Index: bsps/powerpc/beatnik/net/if_em/LICENSE
===================================================================
--- bsps/powerpc/beatnik/net/if_em/LICENSE	(revision 031df3914990db0336a0d386fb53558b05de467e)
+++ bsps/powerpc/beatnik/net/if_em/LICENSE	(revision 031df3914990db0336a0d386fb53558b05de467e)
@@ -0,0 +1,31 @@
+$FreeBSD: /repoman/r/ncvs/src/sys/dev/em/LICENSE,v 1.3 2005/01/06 01:42:38 imp Exp $
+/*-
+Copyright (c) 2001-2003, 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.
+*/
Index: bsps/powerpc/beatnik/net/if_em/README
===================================================================
--- bsps/powerpc/beatnik/net/if_em/README	(revision 031df3914990db0336a0d386fb53558b05de467e)
+++ bsps/powerpc/beatnik/net/if_em/README	(revision 031df3914990db0336a0d386fb53558b05de467e)
@@ -0,0 +1,332 @@
+$FreeBSD: /repoman/r/ncvs/src/sys/dev/em/README,v 1.10 2005/07/11 02:33:25 delphij Exp $
+FreeBSD* Driver for the Intel(R) PRO/1000 Family of Adapters
+============================================================
+
+March 18, 2005
+
+
+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, version 2.1.x, for the Intel(R)
+PRO/1000 Family of Adapters. This driver has been developed for use with
+FreeBSD, version 5.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/adapter/pro100/21397.htm
+
+
+For the latest Intel network drivers for FreeBSD, see:
+
+http://appsr.intel.com/scripts-df/support_intel.asp
+
+
+NOTE: Mobile adapters are not fully supported.
+
+
+Building and Installation
+=========================
+
+NOTE: The driver can be installed as a dynamic loadable kernel module or
+      compiled into the kernel. You must have kernel sources installed in
+      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.i386 file, and add the following lines only if
+   they don't already exist:
+
+        dev/em/if_em.c optional em
+
+        dev/em/if_em_hw.c optional em
+
+   Remove the following lines from the /usr/src/sys/conf/files.i386 file,
+   if they exist:
+
+        dev/em/if_em_fxhw.c optional em
+        dev/em/if_em_phy.c optional em
+
+   Edit the kernel configuration file (i.e., GENERIC or MYKERNEL) in
+   /usr/src/sys/i386/conf, and ensure the following line is present:
+
+        device em
+
+   Compile and install the kernel. The system must be rebooted for the kernel
+   updates to take effect. For additional information on compiling the
+   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.
+
+   1000baseTX      -  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 increase the MTU
+  beyond 1500 bytes.
+
+  NOTES: Only enable Jumbo Frames if your network infrastructure supports
+         them.
+
+         The Jumbo Frames setting on the switch must be set to at least
+         22 bytes larger than that of the MTU.
+
+         The Intel PRO/1000 PM Network Connection does not support jumbo
+         frames.
+
+
+  The Jumbo Frames MTU range for Intel Adapters is 1500 to 16114. The default
+  MTU range is 1500. To modify the setting, enter the following:
+
+        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>
+
+  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 kernels.
+
+        The driver has to be compiled into the kernel for DEVICE POLLING to be
+        enabled in the driver.
+
+  To enable polling in the driver, add the following options to the kernel
+  configuration, and then recompile the kernel:
+
+        options DEVICE_POLLING
+        options HZ=1000
+
+  At runtime use:
+        sysctl kern.polling.enable=1 to turn polling on
+  Use:
+        sysctl kern.polling.enable=0 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
+=================
+
+  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: bsps/powerpc/beatnik/net/if_em/if_em.c
===================================================================
--- bsps/powerpc/beatnik/net/if_em/if_em.c	(revision 031df3914990db0336a0d386fb53558b05de467e)
+++ bsps/powerpc/beatnik/net/if_em/if_em.c	(revision 031df3914990db0336a0d386fb53558b05de467e)
@@ -0,0 +1,3847 @@
+/**************************************************************************
+
+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: /repoman/r/ncvs/src/sys/dev/em/if_em.c,v 1.67 2005/08/03 00:18:29 rwatson Exp $*/
+#ifndef __rtems__
+#include <dev/em/if_em.h>
+#else
+#include <rtems.h>
+#include "rtemscompat_defs.h"
+#include "../porting/rtemscompat.h"
+#include "if_em.h"
+#include "../porting/rtemscompat1.h"
+#include <inttypes.h>
+#endif
+
+/*********************************************************************
+ *  Set this to one to display debug statistics                                                   
+ *********************************************************************/
+int             em_display_debug_stats = 0;
+
+/*********************************************************************
+ *  Linked list of board private structures for all NICs found
+ *********************************************************************/
+
+struct adapter *em_adapter_list = NULL;
+
+
+/*********************************************************************
+ *  Driver version
+ *********************************************************************/
+
+char em_driver_version[] = "2.1.7";
+
+
+/*********************************************************************
+ *  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 }
+ *********************************************************************/
+
+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_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_82573E,              PCI_ANY_ID, PCI_ANY_ID, 0},
+        { 0x8086, E1000_DEV_ID_82573E_IAMT,         PCI_ANY_ID, PCI_ANY_ID, 0},
+
+        /* required last entry */
+        { 0, 0, 0, 0, 0}
+};
+
+/*********************************************************************
+ *  Table of branding strings for all supported NICs.
+ *********************************************************************/
+
+static char *em_strings[] = {
+	"Intel(R) PRO/1000 Network Connection"
+};
+
+/*********************************************************************
+ *  Function prototypes            
+ *********************************************************************/
+static int  em_probe(device_t);
+static int  em_attach(device_t);
+#if !defined(__rtems__) || defined(DEBUG_MODULAR)
+static int  em_detach(device_t);
+#endif
+#ifndef __rtems__
+static int  em_shutdown(device_t);
+#endif
+static void em_intr(void *);
+static void em_start(struct ifnet *);
+#ifndef __rtems__
+static int  em_ioctl(struct ifnet *, u_long, caddr_t);
+#else
+static int  em_ioctl(struct ifnet *, ioctl_command_t, caddr_t);
+#endif
+static void em_watchdog(struct ifnet *);
+static void em_init(void *);
+static void em_init_locked(struct adapter *);
+static void em_stop(void *);
+static void em_media_status(struct ifnet *, struct ifmediareq *);
+#ifndef __rtems__
+static int  em_media_change(struct ifnet *);
+#else
+static int	em_media_change(struct ifnet *ifp, struct rtems_ifmedia *ifm);
+#endif
+static void em_identify_hardware(struct adapter *);
+static int  em_allocate_pci_resources(struct adapter *);
+#ifndef __rtems__
+static void em_free_pci_resources(struct adapter *);
+static void em_local_timer(void *);
+#endif
+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_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_clean_transmit_interrupts(struct adapter *);
+static int  em_allocate_receive_structures(struct adapter *);
+static int  em_allocate_transmit_structures(struct adapter *);
+static void em_process_receive_interrupts(struct adapter *, int);
+#ifndef __rtems__
+static void em_receive_checksum(struct adapter *, 
+				struct em_rx_desc *,
+				struct mbuf *);
+static void em_transmit_checksum_setup(struct adapter *,
+				       struct mbuf *,
+				       u_int32_t *,
+				       u_int32_t *);
+#endif
+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_print_link_status(struct adapter *);
+static int  em_get_buf(int i, struct adapter *,
+		       struct mbuf *);
+#ifndef __rtems__
+static void em_enable_vlans(struct adapter *);
+static void em_disable_vlans(struct adapter *);
+#endif
+static int  em_encap(struct adapter *, struct mbuf **);
+#ifndef __rtems__
+static void em_smartspeed(struct adapter *);
+#endif
+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 *);
+#ifndef __rtems__
+static void em_82547_move_tail(void *arg);
+#endif
+static void em_82547_move_tail_locked(struct adapter *);
+static int  em_dma_malloc(struct adapter *, bus_size_t,
+			  struct em_dma_alloc *, int);
+static void em_dma_free(struct adapter *, struct em_dma_alloc *);
+#ifndef __rtems__
+static void em_print_debug_info(struct adapter *);
+#endif
+static int  em_is_valid_ether_addr(u_int8_t *);
+#ifndef __rtems__
+static int  em_sysctl_stats(SYSCTL_HANDLER_ARGS);
+static int  em_sysctl_debug_info(SYSCTL_HANDLER_ARGS);
+#endif
+static u_int32_t em_fill_descriptors (u_int64_t address, 
+				      u_int32_t length, 
+				      PDESC_ARRAY desc_array);
+#ifndef __rtems__
+static int  em_sysctl_int_delay(SYSCTL_HANDLER_ARGS);
+static void em_add_int_delay_sysctl(struct adapter *, const char *,
+				    const char *, struct em_int_delay_info *,
+				    int, int);
+#endif
+
+/*********************************************************************
+ *  FreeBSD Device Interface Entry Points                    
+ *********************************************************************/
+
+#ifndef __rtems__
+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),
+	{0, 0}
+};
+
+static driver_t em_driver = {
+	"em", em_methods, sizeof(struct adapter ),
+};
+
+static devclass_t em_devclass;
+DRIVER_MODULE(em, pci, em_driver, em_devclass, 0, 0);
+MODULE_DEPEND(em, pci, 1, 1, 1);
+MODULE_DEPEND(em, ether, 1, 1, 1);
+#else
+net_drv_tbl_t METHODS = {
+	n_probe  : em_probe,
+	n_attach : em_attach,
+#ifdef DEBUG_MODULAR
+	n_detach : em_detach,
+#else
+	n_detach:  0,
+#endif
+	n_intr   : em_intr,
+};
+#endif
+
+/*********************************************************************
+ *  Tunable default values.
+ *********************************************************************/
+
+#define E1000_TICKS_TO_USECS(ticks)	((1024 * (ticks) + 500) / 1000)
+#define E1000_USECS_TO_TICKS(usecs)	((1000 * (usecs) + 512) / 1024)
+
+#ifndef __rtems__
+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);
+
+TUNABLE_INT("hw.em.tx_int_delay", &em_tx_int_delay_dflt);
+TUNABLE_INT("hw.em.rx_int_delay", &em_rx_int_delay_dflt);
+TUNABLE_INT("hw.em.tx_abs_int_delay", &em_tx_abs_int_delay_dflt);
+TUNABLE_INT("hw.em.rx_abs_int_delay", &em_rx_abs_int_delay_dflt);
+#endif
+
+/*********************************************************************
+ *  Device identification routine
+ *
+ *  em_probe determines if the driver should be loaded on
+ *  adapter based on PCI vendor/device id of the adapter.
+ *
+ *  return BUS_PROBE_DEFAULT on success, positive on failure
+ *********************************************************************/
+
+static int
+em_probe(device_t dev)
+{
+	em_vendor_info_t *ent;
+
+	u_int16_t       pci_vendor_id = 0;
+	u_int16_t       pci_device_id = 0;
+	u_int16_t       pci_subvendor_id = 0;
+	u_int16_t       pci_subdevice_id = 0;
+	char            adapter_name[60];
+
+	INIT_DEBUGOUT("em_probe: begin");
+
+	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))) {
+			sprintf(adapter_name, "%s, Version - %s", 
+				em_strings[ent->index], 
+				em_driver_version);
+			device_set_desc_copy(dev, adapter_name);
+			return(BUS_PROBE_DEFAULT);
+		}
+		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;
+	int             tsize, rsize;
+	int		error = 0;
+
+	INIT_DEBUGOUT("em_attach: begin");
+
+	/* Allocate, clear, and link in our adapter structure */
+	if (!(adapter = device_get_softc(dev))) {
+		printf("em: adapter structure allocation failed\n");
+		return(ENOMEM);
+	}
+#ifndef __rtems__
+	bzero(adapter, sizeof(struct adapter ));
+#else
+	/* softc structure is maintained outside of this
+	 * and the osdep already contains vital fields (memory address)
+	 */
+#endif
+	adapter->dev = dev;
+	adapter->osdep.dev = dev;
+	adapter->unit = device_get_unit(dev);
+	EM_LOCK_INIT(adapter, device_get_nameunit(dev));
+
+	if (em_adapter_list != NULL)
+		em_adapter_list->prev = adapter;
+	adapter->next = em_adapter_list;
+	em_adapter_list = adapter;
+
+#ifndef __rtems__
+	/* SYSCTL stuff */
+        SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+                        SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+                        OID_AUTO, "debug_info", CTLTYPE_INT|CTLFLAG_RW,
+                        (void *)adapter, 0,
+                        em_sysctl_debug_info, "I", "Debug Information");
+        
+        SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+                        SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+                        OID_AUTO, "stats", CTLTYPE_INT|CTLFLAG_RW,
+                        (void *)adapter, 0,
+                        em_sysctl_stats, "I", "Statistics");
+#endif
+
+	callout_init(&adapter->timer, CALLOUT_MPSAFE);
+	callout_init(&adapter->tx_fifo_timer, CALLOUT_MPSAFE);
+
+	/* Determine hardware revision */
+	em_identify_hardware(adapter);
+
+#ifndef __rtems__
+	/* 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);
+	}
+#endif
+      
+	/* Parameters (to be read from user) */   
+        adapter->num_tx_desc = EM_MAX_TXD;
+        adapter->num_rx_desc = EM_MAX_RXD;
+#ifdef __rtems__
+		if ( dev->d_ifconfig->rbuf_count > 0 ) {
+			adapter->num_rx_desc = dev->d_ifconfig->rbuf_count;
+		}
+		if ( adapter->num_rx_desc < 80 )
+			adapter->num_rx_desc = 80;
+		if ( adapter->num_rx_desc > 256 )
+			adapter->num_rx_desc = 256;
+		if ( dev->d_ifconfig->xbuf_count > 0 ) {
+			adapter->num_tx_desc = dev->d_ifconfig->xbuf_count;
+		}
+		if ( adapter->num_tx_desc < 80 )
+			adapter->num_tx_desc = 80;
+		if ( adapter->num_tx_desc > 256 )
+			adapter->num_tx_desc = 256;
+		adapter->tx_cleanup_threshold = adapter->num_tx_desc/8;
+#endif
+        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;
+                        
+	/*
+         * These parameters control the automatic generation(Tx) and
+         * response(Rx) to Ethernet PAUSE frames.
+         */
+        adapter->hw.fc_high_water = FC_DEFAULT_HI_THRESH;
+        adapter->hw.fc_low_water  = FC_DEFAULT_LO_THRESH;
+        adapter->hw.fc_pause_time = FC_DEFAULT_TX_TIMER;
+        adapter->hw.fc_send_xon   = TRUE;
+        adapter->hw.fc = em_fc_full;
+
+	adapter->hw.phy_init_script = 1;
+	adapter->hw.phy_reset_disable = FALSE;
+
+#ifndef EM_MASTER_SLAVE
+	adapter->hw.master_slave = em_ms_hw_default;
+#else
+	adapter->hw.master_slave = EM_MASTER_SLAVE;
+#endif
+	/* 
+	 * Set the max frame size assuming standard ethernet 
+	 * sized frames 
+	 */   
+	adapter->hw.max_frame_size = 
+		ETHERMTU + ETHER_HDR_LEN + 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.report_tx_early = 1;
+
+
+	if (em_allocate_pci_resources(adapter)) {
+		printf("em%d: Allocation of PCI resources failed\n", 
+		       adapter->unit);
+                error = ENXIO;
+                goto err_pci;
+	}
+  
+	
+	/* Initialize eeprom parameters */
+        em_init_eeprom_params(&adapter->hw);
+
+	tsize = EM_ROUNDUP(adapter->num_tx_desc *
+			   sizeof(struct em_tx_desc), 4096);
+
+	/* Allocate Transmit Descriptor ring */
+        if (em_dma_malloc(adapter, tsize, &adapter->txdma, BUS_DMA_NOWAIT)) {
+                printf("em%d: Unable to allocate tx_desc memory\n",
+                       adapter->unit);
+		error = ENOMEM;
+                goto err_tx_desc;
+        }
+        adapter->tx_desc_base = (struct em_tx_desc *) adapter->txdma.dma_vaddr;
+
+	rsize = EM_ROUNDUP(adapter->num_rx_desc *
+			   sizeof(struct em_rx_desc), 4096);
+
+	/* Allocate Receive Descriptor ring */  
+        if (em_dma_malloc(adapter, rsize, &adapter->rxdma, BUS_DMA_NOWAIT)) {
+                printf("em%d: Unable to allocate rx_desc memory\n",
+                        adapter->unit);
+		error = ENOMEM;
+                goto err_rx_desc;
+        }
+        adapter->rx_desc_base = (struct em_rx_desc *) adapter->rxdma.dma_vaddr;
+
+	/* Initialize the hardware */
+	if (em_hardware_init(adapter)) {
+		printf("em%d: Unable to initialize the hardware\n",
+		       adapter->unit);
+		error = EIO;
+                goto err_hw_init;
+	}
+
+	/* Copy the permanent MAC address out of the EEPROM */
+	if (em_read_mac_addr(&adapter->hw) < 0) {
+		printf("em%d: EEPROM read error while reading mac address\n",
+		       adapter->unit);
+		error = EIO;
+                goto err_mac_addr;
+	}
+
+#ifdef __rtems__
+	/* if the configuration has not set a mac address, copy the permanent
+	 * address from the device to the arpcom struct.
+	 */
+	{
+	int i;
+		for ( i=0; i<ETHER_ADDR_LEN; i++ ) {
+			if ( adapter->arpcom.ac_enaddr[i] )
+				break;
+		}
+		if ( i >= ETHER_ADDR_LEN ) {
+			/* all nulls */
+        	bcopy(adapter->hw.mac_addr, adapter->arpcom.ac_enaddr,
+           	   ETHER_ADDR_LEN);
+		}
+	}
+#endif
+
+	if (!em_is_valid_ether_addr(adapter->hw.mac_addr)) {
+                printf("em%d: Invalid mac address\n", adapter->unit);
+                error = EIO;
+                goto err_mac_addr;
+        }
+
+	/* Setup OS specific network interface */
+	em_setup_interface(dev, adapter);
+
+	/* Initialize statistics */
+	em_clear_hw_cntrs(&adapter->hw);
+	em_update_stats_counters(adapter);
+	adapter->hw.get_link_status = 1;
+#ifndef __rtems__
+	em_check_for_link(&adapter->hw);
+#else
+	/* first check during hw init usually fails - probably we need to wait longer;
+	 * could take a while till the link is up, depends on the partner?
+	 * in any case, rather than waiting here we just proceed...
+	 */
+	em_check_for_link(&adapter->hw);
+	/* em_check_for_link doesn't update 'link_active'
+	 * -- they usually call em_print_link_status() right
+	 * after check_for_link, so let's repeat this
+	 * algorithm here.
+	 */
+	em_print_link_status(adapter);
+#endif
+
+	/* Print the link status */
+	if (adapter->link_active == 1) {
+		em_get_speed_and_duplex(&adapter->hw, &adapter->link_speed, 
+					&adapter->link_duplex);
+		printf("em%d:  Speed:%d Mbps  Duplex:%s\n",
+		       adapter->unit,
+		       adapter->link_speed,
+		       adapter->link_duplex == FULL_DUPLEX ? "Full" : "Half");
+	} else
+		printf("em%d:  Speed:N/A  Duplex:N/A\n", adapter->unit);
+
+	/* 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) {
+                adapter->pcix_82544 = TRUE;
+        }
+        else {
+                adapter->pcix_82544 = FALSE;
+        }
+	INIT_DEBUGOUT("em_attach: end");
+	return(0);
+
+err_mac_addr:
+err_hw_init:
+        em_dma_free(adapter, &adapter->rxdma);
+err_rx_desc:
+        em_dma_free(adapter, &adapter->txdma);
+err_tx_desc:
+err_pci:
+#ifndef __rtems__
+        em_free_pci_resources(adapter);
+#endif
+        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
+ *********************************************************************/
+
+#if !defined(__rtems__) || defined(DEBUG_MODULAR)
+
+static int
+em_detach(device_t dev)
+{
+	struct adapter * adapter = device_get_softc(dev);
+	struct ifnet   *ifp = &adapter->arpcom.ac_if;
+
+	INIT_DEBUGOUT("em_detach: begin");
+
+	EM_LOCK(adapter);
+	adapter->in_detach = 1;
+	em_stop(adapter);
+	em_phy_hw_reset(&adapter->hw);
+	EM_UNLOCK(adapter);
+#ifndef __rtems__
+#if __FreeBSD_version < 500000
+        ether_ifdetach(adapter->ifp, ETHER_BPF_SUPPORTED);
+#else
+        ether_ifdetach(adapter->ifp);
+	if_free(ifp);
+#endif
+	em_free_pci_resources(adapter);
+	bus_generic_detach(dev);
+#else
+        ether_ifdetach(ifp);
+#endif
+
+	/* Free Transmit Descriptor ring */
+        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) {
+                em_dma_free(adapter, &adapter->rxdma);
+                adapter->rx_desc_base = NULL;
+        }
+
+	/* Remove from the adapter list */
+	if (em_adapter_list == adapter)
+		em_adapter_list = adapter->next;
+	if (adapter->next != NULL)
+		adapter->next->prev = adapter->prev;
+	if (adapter->prev != NULL)
+		adapter->prev->next = adapter->next;
+
+	EM_LOCK_DESTROY(adapter);
+
+	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+	ifp->if_timer = 0;
+
+	return(0);
+}
+
+#endif
+
+#ifndef __rtems__
+/*********************************************************************
+ *
+ *  Shutdown entry point
+ *
+ **********************************************************************/ 
+
+static int
+em_shutdown(device_t dev)
+{
+	struct adapter *adapter = device_get_softc(dev);
+	EM_LOCK(adapter);
+	em_stop(adapter);
+	EM_UNLOCK(adapter);
+	return(0);
+}
+#endif
+
+/*********************************************************************
+ *  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_locked(struct ifnet *ifp)
+{
+        struct mbuf    *m_head;
+        struct adapter *adapter = ifp->if_softc;
+
+	mtx_assert(&adapter->mtx, MA_OWNED);
+
+        if (!adapter->link_active)
+                return;
+
+        while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) {
+
+                IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
+                
+                if (m_head == NULL) break;
+
+		/*
+		 * em_encap() can modify our pointer, and or make it NULL on
+		 * failure.  In that event, we can't requeue.
+		 */
+		if (em_encap(adapter, &m_head)) { 
+			if (m_head == NULL)
+				break;
+			ifp->if_flags |= IFF_OACTIVE;
+			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
+			break;
+                }
+
+		/* Send a copy of the frame to the BPF listener */
+#if __FreeBSD_version < 500000 && !defined(__rtems__)
+                if (ifp->if_bpf)
+                        bpf_mtap(ifp, m_head);
+#else
+		BPF_MTAP(ifp, m_head);
+#endif
+        
+                /* Set timeout in case hardware has problems transmitting */
+                ifp->if_timer = EM_TX_TIMEOUT;
+        
+        }
+        return;
+}
+
+static void
+em_start(struct ifnet *ifp)
+{
+	struct adapter *adapter RTEMS_UNUSED = ifp->if_softc;
+
+	EM_LOCK(adapter);
+	em_start_locked(ifp);
+	EM_UNLOCK(adapter);
+	return;
+}
+
+/*********************************************************************
+ *  Ioctl entry point
+ *
+ *  em_ioctl is called when the user wants to configure the
+ *  interface.
+ *
+ *  return 0 on success, positive on failure
+ **********************************************************************/
+
+#ifndef __rtems__
+static int
+em_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
+#else
+static int
+em_ioctl(struct ifnet *ifp, ioctl_command_t command, caddr_t data)
+#endif
+{
+#ifndef __rtems__
+	int             mask, reinit, error = 0;
+#else
+	int             error = 0;
+#endif
+	struct ifreq   *ifr = (struct ifreq *) data;
+	struct adapter * adapter = ifp->if_softc;
+
+	if (adapter->in_detach) return(error);
+
+	switch (command) {
+	case SIOCSIFADDR:
+	case SIOCGIFADDR:
+		IOCTL_DEBUGOUT("ioctl rcv'd: SIOCxIFADDR (Get/Set Interface Addr)");
+		ether_ioctl(ifp, command, data);
+		break;
+	case SIOCSIFMTU:
+		IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFMTU (Set Interface MTU)");
+		if (ifr->ifr_mtu > MAX_JUMBO_FRAME_SIZE - ETHER_HDR_LEN || \
+			/* 82573 does not support jumbo frames */
+			(adapter->hw.mac_type == em_82573 && ifr->ifr_mtu > ETHERMTU) ) {
+			error = EINVAL;
+		} else {
+			EM_LOCK(adapter);
+			ifp->if_mtu = ifr->ifr_mtu;
+			adapter->hw.max_frame_size = 
+			ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN;
+			em_init_locked(adapter);
+			EM_UNLOCK(adapter);
+		}
+		break;
+	case SIOCSIFFLAGS:
+		IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFFLAGS (Set Interface Flags)");
+		EM_LOCK(adapter);
+		if (ifp->if_flags & IFF_UP) {
+			if (!(ifp->if_flags & IFF_RUNNING)) {
+				em_init_locked(adapter);
+			}
+
+			em_disable_promisc(adapter);
+			em_set_promisc(adapter);
+		} else {
+			if (ifp->if_flags & IFF_RUNNING) {
+				em_stop(adapter);
+			}
+		}
+		EM_UNLOCK(adapter);
+		break;
+	case SIOCADDMULTI:
+	case SIOCDELMULTI:
+#ifdef __rtems__
+		if ( (error = ( SIOCADDMULTI == command ?
+							ether_addmulti( ifr, (struct arpcom*)ifp ) :
+							ether_delmulti( ifr, (struct arpcom*)ifp ) ) ) ) {
+			if ( ENETRESET == error )
+				error = 0;
+			else
+				break;
+		}
+#endif
+		IOCTL_DEBUGOUT("ioctl rcv'd: SIOC(ADD|DEL)MULTI");
+		if (ifp->if_flags & IFF_RUNNING) {
+			EM_LOCK(adapter);
+			em_disable_intr(adapter);
+			em_set_multi(adapter);
+			if (adapter->hw.mac_type == em_82542_rev2_0) {
+				em_initialize_receive_unit(adapter);
+			}
+#ifdef DEVICE_POLLING
+                        if (!(ifp->if_flags & IFF_POLLING))
+#endif
+				em_enable_intr(adapter);
+			EM_UNLOCK(adapter);
+		}
+		break;
+#ifndef __rtems__
+	case SIOCSIFMEDIA:
+	case SIOCGIFMEDIA:
+		IOCTL_DEBUGOUT("ioctl rcv'd: SIOCxIFMEDIA (Get/Set Interface Media)");
+		error = ifmedia_ioctl(ifp, ifr, &adapter->media, command);
+	break;
+#else
+	case SIOCSIFMEDIA:
+		{
+		struct rtems_ifmedia mhack;
+			mhack.ifm_media = ifr->ifr_media;
+			error = em_media_change(ifp, &mhack);
+		}
+	break;
+	case SIOCGIFMEDIA:
+		{
+		struct ifmediareq ifmr;
+			em_media_status(ifp, &ifmr);
+			ifr->ifr_media = ifmr.ifm_active;
+			/* add-in rtems flags */
+			if ( adapter->link_active )
+				ifr->ifr_media |= IFM_LINK_OK;
+			if ( !adapter->hw.autoneg )
+				ifr->ifr_media |= IFM_ANEG_DIS;
+			error = 0;
+		}
+	break;
+#endif
+#ifndef __rtems__
+	case SIOCSIFCAP:
+		IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFCAP (Set Capabilities)");
+		reinit = 0;
+		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
+		if (mask & IFCAP_POLLING)
+			ifp->if_capenable ^= IFCAP_POLLING;
+		if (mask & IFCAP_HWCSUM) {
+			ifp->if_capenable ^= IFCAP_HWCSUM;
+			reinit = 1;
+		}
+		if (mask & IFCAP_VLAN_HWTAGGING) {
+			ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
+			reinit = 1;
+		}
+		if (reinit && (ifp->if_flags & IFF_RUNNING))
+			em_init(adapter);
+		break;
+#endif
+
+#ifdef __rtems__
+	case SIO_RTEMS_SHOW_STATS:
+		em_print_hw_stats(adapter);
+		error = 0;
+		break;
+#endif
+
+	default:
+		IOCTL_DEBUGOUT1("ioctl received: UNKNOWN (0x%x)", (int)command);
+		error = EINVAL;
+	}
+
+	return(error);
+}
+
+/*********************************************************************
+ *  Watchdog entry point
+ *
+ *  This routine is called whenever hardware quits transmitting.
+ *
+ **********************************************************************/
+
+static void
+em_watchdog(struct ifnet *ifp)
+{
+	struct adapter * adapter;
+	adapter = ifp->if_softc;
+
+	/* 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) {
+		ifp->if_timer = EM_TX_TIMEOUT;
+		return;
+	}
+
+	if (em_check_for_link(&adapter->hw))
+		printf("em%d: watchdog timeout -- resetting\n", adapter->unit);
+
+	ifp->if_flags &= ~IFF_RUNNING;
+
+	em_init(adapter);
+
+	ifp->if_oerrors++;
+	return;
+}
+
+/*********************************************************************
+ *  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_locked(struct adapter * adapter)
+{
+	struct ifnet   *ifp;
+
+	uint32_t	pba;
+	ifp = &adapter->arpcom.ac_if;
+
+	INIT_DEBUGOUT("em_init: begin");
+
+	mtx_assert(&adapter->mtx, MA_OWNED);
+
+	em_stop(adapter);
+
+	/* Packet Buffer Allocation (PBA)
+	 * Writing PBA sets the receive portion of the buffer
+	 * the remainder is used for the transmit buffer.
+	 *
+	 * Devices before the 82547 had a Packet Buffer of 64K.
+	 *   Default allocation: PBA=48K for Rx, leaving 16K for Tx.
+	 * After the 82547 the buffer was reduced to 40K.
+	 *   Default allocation: PBA=30K for Rx, leaving 10K for Tx.
+	 *   Note: default does not leave enough room for Jumbo Frame >10k.
+	 */
+	if(adapter->hw.mac_type < em_82547) {
+		/* Total FIFO is 64K */
+		if(adapter->rx_buffer_len > EM_RXBUFFER_8192)
+			pba = E1000_PBA_40K; /* 40K for Rx, 24K for Tx */
+		else
+			pba = E1000_PBA_48K; /* 48K for Rx, 16K for Tx */
+	} else {
+		/* Total FIFO is 40K */
+		if(adapter->hw.max_frame_size > EM_RXBUFFER_8192) {
+			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;
+	}
+	INIT_DEBUGOUT1("em_init: pba=%" PRId32 "K",pba);
+	E1000_WRITE_REG(&adapter->hw, PBA, pba);
+	
+	/* Get the latest mac address, User can use a LAA */
+        bcopy(adapter->arpcom.ac_enaddr, adapter->hw.mac_addr,
+              ETHER_ADDR_LEN);
+
+	/* Initialize the hardware */
+	if (em_hardware_init(adapter)) {
+		printf("em%d: Unable to initialize the hardware\n", 
+		       adapter->unit);
+		return;
+	}
+
+#ifndef __rtems__
+	if (ifp->if_capenable & IFCAP_VLAN_HWTAGGING)
+		em_enable_vlans(adapter);
+#endif
+
+	/* Prepare transmit descriptors and buffers */
+	if (em_setup_transmit_structures(adapter)) {
+		printf("em%d: Could not setup transmit structures\n", 
+		       adapter->unit);
+		em_stop(adapter); 
+		return;
+	}
+	em_initialize_transmit_unit(adapter);
+
+	/* Setup Multicast table */
+	em_set_multi(adapter);
+
+	/* Prepare receive descriptors and buffers */
+	if (em_setup_receive_structures(adapter)) {
+		printf("em%d: Could not setup receive structures\n", 
+		       adapter->unit);
+		em_stop(adapter);
+		return;
+	}
+	em_initialize_receive_unit(adapter);
+ 
+	/* Don't loose promiscuous settings */
+	em_set_promisc(adapter);
+
+	ifp->if_flags |= IFF_RUNNING;
+	ifp->if_flags &= ~IFF_OACTIVE;
+
+#ifndef __rtems__
+	if (adapter->hw.mac_type >= em_82543) {
+		if (ifp->if_capenable & IFCAP_TXCSUM)
+			ifp->if_hwassist = EM_CHECKSUM_FEATURES;
+		else
+			ifp->if_hwassist = 0;
+	}
+#endif
+
+	callout_reset(&adapter->timer, hz, em_local_timer, adapter);
+	em_clear_hw_cntrs(&adapter->hw);
+#ifdef DEVICE_POLLING
+        /*
+         * 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 /* DEVICE_POLLING */
+		em_enable_intr(adapter);
+
+	/* Don't reset the phy next time init gets called */
+	adapter->hw.phy_reset_disable = TRUE;
+	
+	return;
+}
+
+static void
+em_init(void *arg)
+{
+	struct adapter * adapter = arg;
+
+	EM_LOCK(adapter);
+	em_init_locked(adapter);
+	EM_UNLOCK(adapter);
+	return;
+}
+
+
+#ifdef DEVICE_POLLING
+static poll_handler_t em_poll;
+        
+static void     
+em_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count)
+{
+        struct adapter *adapter = ifp->if_softc;
+        u_int32_t reg_icr;
+
+	mtx_assert(&adapter->mtx, MA_OWNED);
+
+	if (!(ifp->if_capenable & IFCAP_POLLING)) {
+		ether_poll_deregister(ifp);
+		cmd = POLL_DEREGISTER;
+	}
+        if (cmd == POLL_DEREGISTER) {       /* final call, enable interrupts */
+                em_enable_intr(adapter);
+                return;
+        }
+        if (cmd == POLL_AND_CHECK_STATUS) {
+                reg_icr = E1000_READ_REG(&adapter->hw, 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);
+                        em_print_link_status(adapter);
+			callout_reset(&adapter->timer, hz, em_local_timer, adapter);
+                }
+        }
+        if (ifp->if_flags & IFF_RUNNING) {
+                em_process_receive_interrupts(adapter, count);
+                em_clean_transmit_interrupts(adapter);
+        }
+	
+        if (ifp->if_flags & IFF_RUNNING && !IFQ_DRV_IS_EMPTY(&ifp->if_snd))
+                em_start_locked(ifp);
+}
+        
+static void     
+em_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
+{
+        struct adapter *adapter = ifp->if_softc;
+
+	EM_LOCK(adapter);
+	em_poll_locked(ifp, cmd, count);
+	EM_UNLOCK(adapter);
+}
+#endif /* DEVICE_POLLING */
+
+/*********************************************************************
+ *
+ *  Interrupt Service routine  
+ *
+ **********************************************************************/
+static void
+em_intr(void *arg)
+{
+        u_int32_t       loop_cnt = EM_MAX_INTR;
+        u_int32_t       reg_icr;
+        struct ifnet    *ifp;
+        struct adapter  *adapter = arg;
+
+	EM_LOCK(adapter);
+
+        ifp = &adapter->arpcom.ac_if;  
+
+#ifdef DEVICE_POLLING
+        if (ifp->if_flags & IFF_POLLING) {
+		EM_UNLOCK(adapter);
+                return;
+	}
+
+	if ((ifp->if_capenable & IFCAP_POLLING) &&
+	    ether_poll_register(em_poll, ifp)) {
+                em_disable_intr(adapter);
+                em_poll_locked(ifp, 0, 1);
+		EM_UNLOCK(adapter);
+                return;
+        }
+#endif /* DEVICE_POLLING */
+
+	reg_icr = E1000_READ_REG(&adapter->hw, ICR);
+        if (!reg_icr) {  
+		EM_UNLOCK(adapter);
+                return;
+        }
+
+        /* 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);
+                em_print_link_status(adapter);
+		callout_reset(&adapter->timer, hz, em_local_timer, adapter);
+        }
+
+        while (loop_cnt > 0) { 
+                if (ifp->if_flags & IFF_RUNNING) {
+                        em_process_receive_interrupts(adapter, -1);
+                        em_clean_transmit_interrupts(adapter);
+                }
+                loop_cnt--;
+        }
+                 
+        if (ifp->if_flags & IFF_RUNNING && !IFQ_DRV_IS_EMPTY(&ifp->if_snd))
+                em_start_locked(ifp);
+
+	EM_UNLOCK(adapter);
+        return;
+}
+
+
+
+/*********************************************************************
+ *
+ *  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;
+
+	INIT_DEBUGOUT("em_media_status: begin");
+
+	em_check_for_link(&adapter->hw);
+	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);
+			adapter->link_active = 1;
+		}
+	} else {
+		if (adapter->link_active == 1) {
+			adapter->link_speed = 0;
+			adapter->link_duplex = 0;
+			adapter->link_active = 0;
+		}
+	}
+
+	ifmr->ifm_status = IFM_AVALID;
+	ifmr->ifm_active = IFM_ETHER;
+
+	if (!adapter->link_active)
+		return;
+
+	ifmr->ifm_status |= IFM_ACTIVE;
+
+	if (adapter->hw.media_type == em_media_type_fiber) {
+		ifmr->ifm_active |= IFM_1000_SX | IFM_FDX;
+	} else {
+		switch (adapter->link_speed) {
+		case 10:
+			ifmr->ifm_active |= IFM_10_T;
+			break;
+		case 100:
+			ifmr->ifm_active |= IFM_100_TX;
+			break;
+		case 1000:
+#if __FreeBSD_version < 500000 && !defined(__rtems__)
+			ifmr->ifm_active |= IFM_1000_TX;
+#else
+			ifmr->ifm_active |= IFM_1000_T;
+#endif
+			break;
+		}
+		if (adapter->link_duplex == FULL_DUPLEX)
+			ifmr->ifm_active |= IFM_FDX;
+		else
+			ifmr->ifm_active |= IFM_HDX;
+	}
+	return;
+}
+
+/*********************************************************************
+ *
+ *  Media Ioctl callback
+ *
+ *  This routine is called when the user changes speed/duplex using
+ *  media/mediopt option with ifconfig.
+ *
+ **********************************************************************/
+static int
+#ifndef __rtems__
+em_media_change(struct ifnet *ifp)
+#else
+em_media_change(struct ifnet *ifp, struct rtems_ifmedia *ifm)
+#endif
+{
+	struct adapter * adapter = ifp->if_softc;
+#ifndef __rtems__
+	struct ifmedia  *ifm = &adapter->media;
+#endif
+
+	INIT_DEBUGOUT("em_media_change: begin");
+
+	if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
+		return(EINVAL);
+
+	switch (IFM_SUBTYPE(ifm->ifm_media)) {
+	case IFM_AUTO:
+		adapter->hw.autoneg = DO_AUTO_NEG;
+		adapter->hw.autoneg_advertised = AUTONEG_ADV_DEFAULT;
+		break;
+	case IFM_1000_SX:
+#if __FreeBSD_version < 500000 && !defined(__rtems__)
+	case IFM_1000_TX:
+#else
+	case IFM_1000_T:
+#endif
+		adapter->hw.autoneg = DO_AUTO_NEG;
+		adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL;
+		break;
+	case IFM_100_TX:
+		adapter->hw.autoneg = FALSE;
+		adapter->hw.autoneg_advertised = 0;
+		if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX)
+			adapter->hw.forced_speed_duplex = em_100_full;
+		else
+			adapter->hw.forced_speed_duplex	= em_100_half;
+		break;
+	case IFM_10_T:
+		adapter->hw.autoneg = FALSE;
+		adapter->hw.autoneg_advertised = 0;
+		if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX)
+			adapter->hw.forced_speed_duplex = em_10_full;
+		else
+			adapter->hw.forced_speed_duplex	= em_10_half;
+		break;
+	default:
+		printf("em%d: Unsupported media type\n", adapter->unit);
+	}
+
+	/* As the speed/duplex settings my have changed we need to
+	 * reset the PHY.
+	 */
+	adapter->hw.phy_reset_disable = FALSE;
+
+	em_init(adapter);
+
+	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_headp)
+{
+        u_int32_t       txd_upper;
+        u_int32_t       txd_lower, txd_used = 0, txd_saved = 0;
+        int             i, j, error;
+        u_int64_t       address;
+
+	struct mbuf	*m_head;
+
+	/* For 82544 Workaround */
+	DESC_ARRAY              desc_array;
+	u_int32_t               array_elements;
+	u_int32_t               counter;
+
+#ifndef __rtems__
+#if __FreeBSD_version < 500000
+        struct ifvlan *ifv = NULL;
+#else
+        struct m_tag    *mtag;
+#endif   
+#endif
+	bus_dma_segment_t	segs[EM_MAX_SCATTER];
+#ifndef __rtems__
+	bus_dmamap_t		map;
+#endif
+	int			nsegs;
+        struct em_buffer   *tx_buffer = NULL;
+        struct em_tx_desc *current_tx_desc = NULL;
+#ifndef __rtems__
+        struct ifnet   *ifp = &adapter->arpcom.ac_if;
+#endif
+
+	m_head = *m_headp;
+
+        /*
+         * Force a cleanup if number of TX descriptors
+         * available hits the threshold
+         */
+        if (adapter->num_tx_desc_avail <= EM_TX_CLEANUP_THRESHOLD) {
+                em_clean_transmit_interrupts(adapter);
+                if (adapter->num_tx_desc_avail <= EM_TX_CLEANUP_THRESHOLD) {
+                        adapter->no_tx_desc_avail1++;
+                        return(ENOBUFS);
+                }
+        }
+
+#ifndef __rtems__
+        /*
+         * Map the packet for DMA.
+         */
+        if (bus_dmamap_create(adapter->txtag, BUS_DMA_NOWAIT, &map)) {
+                adapter->no_tx_map_avail++;
+                return (ENOMEM);
+        }
+        error = bus_dmamap_load_mbuf_sg(adapter->txtag, map, m_head, segs,
+					&nsegs, BUS_DMA_NOWAIT);
+        if (error != 0) {
+                adapter->no_tx_dma_setup++;
+                bus_dmamap_destroy(adapter->txtag, map);
+                return (error);
+        }
+#else
+		(void)error;
+		{
+		struct mbuf *m;
+			for ( m=m_head, nsegs=0; m; m=m->m_next, nsegs++ ) {
+				if ( nsegs >= sizeof(segs)/sizeof(segs[0]) ) {
+					break;
+				}
+				segs[nsegs].ds_addr = mtod(m, unsigned);
+				segs[nsegs].ds_len  = m->m_len;
+			}
+		}
+#endif
+        KASSERT(nsegs != 0, ("em_encap: empty packet"));
+
+        if (nsegs > adapter->num_tx_desc_avail) {
+                adapter->no_tx_desc_avail2++;
+                bus_dmamap_destroy(adapter->txtag, map);
+                return (ENOBUFS);
+        }
+
+
+#ifndef __rtems__
+        if (ifp->if_hwassist > 0) {
+                em_transmit_checksum_setup(adapter,  m_head,
+                                           &txd_upper, &txd_lower);
+        } else
+#endif
+                txd_upper = txd_lower = 0;
+
+
+#ifndef __rtems__
+        /* Find out if we are in vlan mode */
+#if __FreeBSD_version < 500000
+        if ((m_head->m_flags & (M_PROTO1|M_PKTHDR)) == (M_PROTO1|M_PKTHDR) &&
+            m_head->m_pkthdr.rcvif != NULL &&
+            m_head->m_pkthdr.rcvif->if_type == IFT_L2VLAN)
+                ifv = m_head->m_pkthdr.rcvif->if_softc;
+#else
+        mtag = VLAN_OUTPUT_TAG(ifp, m_head);
+#endif
+
+	/*
+	 * When operating in promiscuous mode, hardware encapsulation for
+	 * packets is disabled.  This means we have to add the vlan
+	 * encapsulation in the driver, since it will have come down from the
+	 * VLAN layer with a tag instead of a VLAN header.
+	 */
+	if (mtag != NULL && adapter->em_insert_vlan_header) {
+		struct ether_vlan_header *evl;
+		struct ether_header eh;
+
+		m_head = m_pullup(m_head, sizeof(eh));
+		if (m_head == NULL) {
+			*m_headp = NULL;
+                	bus_dmamap_destroy(adapter->txtag, map);
+			return (ENOBUFS);
+		}
+		eh = *mtod(m_head, struct ether_header *);
+		M_PREPEND(m_head, sizeof(*evl), M_DONTWAIT);
+		if (m_head == NULL) {
+			*m_headp = NULL;
+                	bus_dmamap_destroy(adapter->txtag, map);
+			return (ENOBUFS);
+		}
+		m_head = m_pullup(m_head, sizeof(*evl));
+		if (m_head == NULL) {
+			*m_headp = NULL;
+                	bus_dmamap_destroy(adapter->txtag, map);
+			return (ENOBUFS);
+		}
+		evl = mtod(m_head, struct ether_vlan_header *);
+		bcopy(&eh, evl, sizeof(*evl));
+		evl->evl_proto = evl->evl_encap_proto;
+		evl->evl_encap_proto = htons(ETHERTYPE_VLAN);
+		evl->evl_tag = htons(VLAN_TAG_VALUE(mtag));
+		m_tag_delete(m_head, mtag);
+		mtag = NULL;
+		*m_headp = m_head;
+	}
+#endif
+
+        i = adapter->next_avail_tx_desc;
+	if (adapter->pcix_82544) {
+		txd_saved = i;
+		txd_used = 0;
+	}
+        for (j = 0; j < nsegs; j++) {
+		/* If adapter is 82544 and on PCIX bus */
+		if(adapter->pcix_82544) {
+			array_elements = 0;
+			address = htole64(segs[j].ds_addr);
+			/* 
+			 * Check the Address and Length combination and 
+			 * split the data accordingly 
+			 */
+                        array_elements = em_fill_descriptors(address,
+							     htole32(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++;
+					  bus_dmamap_destroy(adapter->txtag, map);
+                                          return (ENOBUFS);
+                                }
+                                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 | 
+					 (u_int16_t)desc_array.descriptor[counter].length));
+                                current_tx_desc->upper.data = htole32((txd_upper));
+                                if (++i == adapter->num_tx_desc)
+                                         i = 0;
+
+                                tx_buffer->m_head = NULL;
+                                txd_used++;
+                        }
+		} else {
+			tx_buffer = &adapter->tx_buffer_area[i];
+			current_tx_desc = &adapter->tx_desc_base[i];
+
+			current_tx_desc->buffer_addr = htole64(segs[j].ds_addr);
+			current_tx_desc->lower.data = htole32(
+				adapter->txd_cmd | txd_lower | segs[j].ds_len);
+			current_tx_desc->upper.data = htole32(txd_upper);
+
+			if (++i == adapter->num_tx_desc)
+				i = 0;
+
+			tx_buffer->m_head = NULL;
+		}
+        }
+
+	adapter->next_avail_tx_desc = i;
+	if (adapter->pcix_82544) {
+		adapter->num_tx_desc_avail -= txd_used;
+	}
+	else {
+		adapter->num_tx_desc_avail -= nsegs;
+	}
+
+#ifndef __rtems__
+#if __FreeBSD_version < 500000
+        if (ifv != NULL) {
+                /* Set the vlan id */
+                current_tx_desc->upper.fields.special = htole16(ifv->ifv_tag);
+#else
+        if (mtag != NULL) {
+                /* Set the vlan id */
+                current_tx_desc->upper.fields.special = htole16(VLAN_TAG_VALUE(mtag));
+#endif
+
+                /* Tell hardware to add tag */
+                current_tx_desc->lower.data |= htole32(E1000_TXD_CMD_VLE);
+        }
+#endif
+
+        tx_buffer->m_head = m_head;
+#ifndef __rtems__
+        tx_buffer->map = map;
+#endif
+        bus_dmamap_sync(adapter->txtag, map, BUS_DMASYNC_PREWRITE);
+
+        /*
+         * Last Descriptor of Packet needs End Of Packet (EOP)
+         */
+        current_tx_desc->lower.data |= htole32(E1000_TXD_CMD_EOP);
+
+        /*
+         * Advance the Transmit Descriptor Tail (Tdt), this tells the E1000
+         * that this frame is available to transmit.
+         */
+        bus_dmamap_sync(adapter->txdma.dma_tag, adapter->txdma.dma_map,
+            BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+        if (adapter->hw.mac_type == em_82547 &&
+            adapter->link_duplex == HALF_DUPLEX) {
+                em_82547_move_tail_locked(adapter);
+        } else {
+                E1000_WRITE_REG(&adapter->hw, TDT, i);
+                if (adapter->hw.mac_type == em_82547) {
+                        em_82547_update_fifo_head(adapter, m_head->m_pkthdr.len);
+                }
+        }
+
+        return(0);
+}
+
+/*********************************************************************
+ *
+ * 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_locked(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;
+
+	EM_LOCK_ASSERT(adapter);
+
+	hw_tdt = E1000_READ_REG(&adapter->hw, TDT);
+	sw_tdt = adapter->next_avail_tx_desc;
+	
+	while (hw_tdt != sw_tdt) {
+		tx_desc = &adapter->tx_desc_base[hw_tdt];
+		length += tx_desc->lower.flags.length;
+		eop = tx_desc->lower.data & E1000_TXD_CMD_EOP;
+		if(++hw_tdt == adapter->num_tx_desc)
+			hw_tdt = 0;
+
+		if(eop) {
+			if (em_82547_fifo_workaround(adapter, length)) {
+				adapter->tx_fifo_wrk_cnt++;
+				callout_reset(&adapter->tx_fifo_timer, 1,
+					em_82547_move_tail, adapter);
+				break;
+			}
+			E1000_WRITE_REG(&adapter->hw, TDT, hw_tdt);
+			em_82547_update_fifo_head(adapter, length);
+			length = 0;
+		}
+	}	
+	return;
+}
+
+#ifndef __rtems__
+static void
+em_82547_move_tail(void *arg)
+{
+        struct adapter *adapter = arg;
+
+        EM_LOCK(adapter);
+        em_82547_move_tail_locked(adapter);
+        EM_UNLOCK(adapter);
+}
+#endif
+
+static int
+em_82547_fifo_workaround(struct adapter *adapter, int len)
+{	
+	int fifo_space, fifo_pkt_len;
+
+	fifo_pkt_len = EM_ROUNDUP(len + EM_FIFO_HDR, EM_FIFO_HDR);
+
+	if (adapter->link_duplex == HALF_DUPLEX) {
+		fifo_space = adapter->tx_fifo_size - adapter->tx_fifo_head;
+
+		if (fifo_pkt_len >= (EM_82547_PKT_THRESH + fifo_space)) {
+			if (em_82547_tx_fifo_reset(adapter)) {
+				return(0);
+			}
+			else {
+				return(1);
+			}
+		}
+	}
+
+	return(0);
+}
+
+static void
+em_82547_update_fifo_head(struct adapter *adapter, int len)
+{
+	int fifo_pkt_len = EM_ROUNDUP(len + EM_FIFO_HDR, EM_FIFO_HDR);
+	
+	/* tx_fifo_head is always 16 byte aligned */
+	adapter->tx_fifo_head += fifo_pkt_len;
+	if (adapter->tx_fifo_head >= adapter->tx_fifo_size) {
+		adapter->tx_fifo_head -= adapter->tx_fifo_size;
+	}
+
+	return;
+}
+
+
+static int
+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)) {
+
+		/* Disable TX unit */
+		tctl = E1000_READ_REG(&adapter->hw, TCTL);
+		E1000_WRITE_REG(&adapter->hw, 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);
+
+		/* Re-enable TX unit */
+		E1000_WRITE_REG(&adapter->hw, TCTL, tctl);
+		E1000_WRITE_FLUSH(&adapter->hw);
+
+		adapter->tx_fifo_head = 0;
+		adapter->tx_fifo_reset_cnt++;
+
+		return(TRUE);
+	}
+	else {
+		return(FALSE);
+	}
+}
+
+static void
+em_set_promisc(struct adapter * adapter)
+{
+
+	u_int32_t       reg_rctl;
+	struct ifnet   *ifp = &adapter->arpcom.ac_if;
+
+	reg_rctl = E1000_READ_REG(&adapter->hw, RCTL);
+
+	if (ifp->if_flags & IFF_PROMISC) {
+		reg_rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE);
+		E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
+#ifndef __rtems__
+		/* Disable VLAN stripping in promiscous mode 
+		 * This enables bridging of vlan tagged frames to occur 
+		 * and also allows vlan tags to be seen in tcpdump
+		 */
+		if (ifp->if_capenable & IFCAP_VLAN_HWTAGGING)
+			em_disable_vlans(adapter);
+		adapter->em_insert_vlan_header = 1;
+#endif
+	} 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);
+#ifndef __rtems__
+		adapter->em_insert_vlan_header = 0;
+	} else
+		adapter->em_insert_vlan_header = 0;
+#else
+	}
+#endif
+
+	return;
+}
+
+static void
+em_disable_promisc(struct adapter * adapter)
+{
+	u_int32_t       reg_rctl;
+#ifndef __rtems__
+	struct ifnet   *ifp = adapter->ifp;
+#endif
+
+	reg_rctl = E1000_READ_REG(&adapter->hw, RCTL);
+
+	reg_rctl &=  (~E1000_RCTL_UPE);
+	reg_rctl &=  (~E1000_RCTL_MPE);
+	E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
+
+#ifndef __rtems__
+	if (ifp->if_capenable & IFCAP_VLAN_HWTAGGING)
+		em_enable_vlans(adapter);
+	adapter->em_insert_vlan_header = 0;
+#endif
+
+	return;
+}
+
+
+/*********************************************************************
+ *  Multicast Update
+ *
+ *  This routine is called whenever multicast address list is updated.
+ *
+ **********************************************************************/
+
+static void
+em_set_multi(struct adapter * adapter)
+{
+        u_int32_t reg_rctl = 0;
+        u_int8_t  mta[MAX_NUM_MULTICAST_ADDRESSES * ETH_LENGTH_OF_ADDRESS];
+#ifndef __rtems__
+        struct ifmultiaddr  *ifma;
+#endif
+        int mcnt = 0;
+        struct ifnet   *ifp = &adapter->arpcom.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);
+                }
+                reg_rctl |= E1000_RCTL_RST;
+                E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
+                msec_delay(5);
+        }
+
+#ifndef __rtems__
+	IF_ADDR_LOCK(ifp);
+#if __FreeBSD_version < 500000
+        LIST_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+#else
+        TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+#endif  
+                if (ifma->ifma_addr->sa_family != AF_LINK)
+                        continue;
+ 
+		if (mcnt == MAX_NUM_MULTICAST_ADDRESSES) break;
+
+                bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
+                      &mta[mcnt*ETH_LENGTH_OF_ADDRESS], ETH_LENGTH_OF_ADDRESS);
+                mcnt++;
+        }
+	IF_ADDR_UNLOCK(ifp);
+#else
+	{
+	/* Don't know how to handle address ranges - we warn and ignore
+	 * for now...
+	 */
+	struct ether_multi     *enm;
+	struct ether_multistep step;
+
+		ETHER_FIRST_MULTI(step, (struct arpcom*)ifp, enm);
+		while ( enm != NULL ) {
+			if ( mcnt == MAX_NUM_MULTICAST_ADDRESSES )
+				break;
+			if ( memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN) ) {
+				printk("if_em: Unable to handle multicast wildcard (not ported yet); skipping/ignoring\n");
+				goto skiptonext;
+			} else {
+				bcopy(enm->enm_addrlo, &mta[mcnt * ETHER_ADDR_LEN], ETHER_ADDR_LEN);
+			}
+			mcnt++;
+skiptonext:
+			ETHER_NEXT_MULTI( step, enm );
+		}
+	}
+#endif
+
+        if (mcnt >= MAX_NUM_MULTICAST_ADDRESSES) {
+                reg_rctl = E1000_READ_REG(&adapter->hw, RCTL);
+                reg_rctl |= E1000_RCTL_MPE;
+                E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
+        } else
+                em_mc_addr_list_update(&adapter->hw, mta, mcnt, 0, 1);
+
+        if (adapter->hw.mac_type == em_82542_rev2_0) {
+                reg_rctl = E1000_READ_REG(&adapter->hw, RCTL);
+                reg_rctl &= ~E1000_RCTL_RST;
+                E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
+                msec_delay(5);
+                if (adapter->hw.pci_cmd_word & CMD_MEM_WRT_INVALIDATE) {
+                        em_pci_set_mwi(&adapter->hw);
+                }
+        }
+
+        return;
+}
+
+#ifndef __rtems__
+/*********************************************************************
+ *  Timer routine
+ *
+ *  This routine checks for link status and updates statistics.
+ *
+ **********************************************************************/
+
+static void
+em_local_timer(void *arg)
+{
+	struct ifnet   *ifp;
+	struct adapter * adapter = arg;
+	ifp = &adapter->arpcom.ac_if;
+
+	EM_LOCK(adapter);
+
+	em_check_for_link(&adapter->hw);
+	em_print_link_status(adapter);
+	em_update_stats_counters(adapter);   
+	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);
+
+	EM_UNLOCK(adapter);
+	return;
+}
+#endif
+
+static void
+em_print_link_status(struct adapter * adapter)
+{
+#ifndef __rtems__
+	struct ifnet *ifp = &adapter->arpcom.ac_if;
+#endif
+
+	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);
+			if (bootverbose)
+				printf("em%d: Link is up %d Mbps %s\n",
+				       adapter->unit,
+				       adapter->link_speed,
+				       ((adapter->link_duplex == FULL_DUPLEX) ?
+					"Full Duplex" : "Half Duplex"));
+			adapter->link_active = 1;
+			adapter->smartspeed = 0;
+#ifndef __rtems__
+			if_link_state_change(ifp, LINK_STATE_UP);
+#endif
+		}
+	} else {
+		if (adapter->link_active == 1) {
+			adapter->link_speed = 0;
+			adapter->link_duplex = 0;
+			if (bootverbose)
+				printf("em%d: Link is Down\n", adapter->unit);
+			adapter->link_active = 0;
+#ifndef __rtems__
+			if_link_state_change(ifp, LINK_STATE_UP);
+			if_link_state_change(ifp, LINK_STATE_DOWN);
+#endif
+		}
+	}
+
+	return;
+}
+
+/*********************************************************************
+ *
+ *  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)
+{
+	struct ifnet   *ifp;
+	struct adapter * adapter = arg;
+	ifp = &adapter->arpcom.ac_if;
+
+	mtx_assert(&adapter->mtx, MA_OWNED);
+
+	INIT_DEBUGOUT("em_stop: begin");
+#ifdef DEVICE_POLLING
+	ether_poll_deregister(ifp);
+#endif
+	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);
+
+	return;
+}
+
+
+/*********************************************************************
+ *
+ *  Determine hardware revision.
+ *
+ **********************************************************************/
+static void
+em_identify_hardware(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))) {
+		printf("em%d: Memory Access and/or Bus Master bits were not set!\n", 
+		       adapter->unit);
+		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_read_config(dev, PCIR_REVID, 1);
+	adapter->hw.subsystem_vendor_id = pci_read_config(dev, PCIR_SUBVEND_0, 2);
+	adapter->hw.subsystem_id = pci_read_config(dev, PCIR_SUBDEV_0, 2);
+
+	/* Identify the MAC */
+        if (em_set_mac_type(&adapter->hw))
+                printf("em%d: Unknown MAC Type\n", adapter->unit);
+	
+	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;
+
+        return;
+}
+
+static int
+em_allocate_pci_resources(struct adapter * adapter)
+{
+	int             i, val, rid;
+	device_t        dev = adapter->dev;
+
+	rid = EM_MMBA;
+
+#ifndef __rtems__
+	adapter->res_memory = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
+						     &rid, RF_ACTIVE);
+	if (!(adapter->res_memory)) {
+		printf("em%d: Unable to allocate bus resource: memory\n", 
+		       adapter->unit);
+		return(ENXIO);
+	}
+	adapter->osdep.mem_bus_space_tag = 
+	rman_get_bustag(adapter->res_memory);
+	adapter->osdep.mem_bus_space_handle = 
+	rman_get_bushandle(adapter->res_memory);
+#endif
+
+	adapter->hw.hw_addr = (uint8_t *)&adapter->osdep.mem_bus_space_handle;
+
+
+	if (adapter->hw.mac_type > em_82543) {
+		/* Figure our where our IO BAR is ? */
+		rid = EM_MMBA;
+		for (i = 0; i < 5; i++) {
+			val = pci_read_config(dev, rid, 4);
+			if (val & 0x00000001) {
+#ifndef __rtems__
+				adapter->io_rid = rid;
+#endif
+				break;
+			}
+			rid += 4;
+		}
+
+#ifndef __rtems__
+		adapter->res_ioport = bus_alloc_resource_any(dev, 
+							     SYS_RES_IOPORT,
+							     &adapter->io_rid,
+							     RF_ACTIVE);
+		if (!(adapter->res_ioport)) {
+			printf("em%d: Unable to allocate bus resource: ioport\n",
+			       adapter->unit);
+			return(ENXIO);  
+		}
+
+		adapter->hw.io_base =
+		rman_get_start(adapter->res_ioport);
+#else
+		adapter->hw.io_base = val & PCI_BASE_ADDRESS_IO_MASK;
+#endif
+	}
+
+#ifndef __rtems__
+	rid = 0x0;
+	adapter->res_interrupt = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+						        RF_SHAREABLE | 
+							RF_ACTIVE);
+	if (!(adapter->res_interrupt)) {
+		printf("em%d: Unable to allocate bus resource: interrupt\n", 
+		       adapter->unit);
+		return(ENXIO);
+	}
+	if (bus_setup_intr(dev, adapter->res_interrupt,
+			   INTR_TYPE_NET | INTR_MPSAFE,
+			   (void (*)(void *)) em_intr, adapter,
+			   &adapter->int_handler_tag)) {
+		printf("em%d: Error registering interrupt handler!\n", 
+		       adapter->unit);
+		return(ENXIO);
+	}
+#endif
+
+	adapter->hw.back = &adapter->osdep;
+
+	return(0);
+}
+
+#ifndef __rtems__
+static void
+em_free_pci_resources(struct adapter * adapter)
+{
+	device_t dev = adapter->dev;
+
+	if (adapter->res_interrupt != NULL) {
+		bus_teardown_intr(dev, adapter->res_interrupt, 
+				  adapter->int_handler_tag);
+		bus_release_resource(dev, SYS_RES_IRQ, 0, 
+				     adapter->res_interrupt);
+	}
+	if (adapter->res_memory != NULL) {
+		bus_release_resource(dev, SYS_RES_MEMORY, EM_MMBA, 
+				     adapter->res_memory);
+	}
+
+	if (adapter->res_ioport != NULL) {
+		bus_release_resource(dev, SYS_RES_IOPORT, adapter->io_rid, 
+				     adapter->res_ioport);
+	}
+	return;
+}
+#endif
+
+/*********************************************************************
+ *
+ *  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)
+{
+        INIT_DEBUGOUT("em_hardware_init: begin");
+	/* Issue a global reset */
+	em_reset_hw(&adapter->hw);
+
+	/* 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) {
+		printf("em%d: The EEPROM Checksum Is Not Valid\n",
+		       adapter->unit);
+		return(EIO);
+	}
+
+	if (em_read_part_num(&adapter->hw, &(adapter->part_num)) < 0) {
+		printf("em%d: EEPROM read error while reading part number\n",
+		       adapter->unit);
+		return(EIO);
+	}
+
+	if (em_init_hw(&adapter->hw) < 0) {
+		printf("em%d: Hardware Initialization Failed",
+		       adapter->unit);
+		return(EIO);
+	}
+
+	em_check_for_link(&adapter->hw);
+	if (E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU)
+		adapter->link_active = 1;
+	else
+		adapter->link_active = 0;
+
+	if (adapter->link_active) {
+		em_get_speed_and_duplex(&adapter->hw, 
+					&adapter->link_speed, 
+					&adapter->link_duplex);
+	} else {
+		adapter->link_speed = 0;
+		adapter->link_duplex = 0;
+	}
+
+	return(0);
+}
+
+/*********************************************************************
+ *
+ *  Setup networking device structure and register an interface.
+ *
+ **********************************************************************/
+static void
+em_setup_interface(device_t dev, struct adapter * adapter)
+{
+	struct ifnet   *ifp = &device_get_softc(dev)->arpcom.ac_if;
+	INIT_DEBUGOUT("em_setup_interface: begin");
+
+	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
+	ifp->if_mtu = ETHERMTU;
+	ifp->if_baudrate = 1000000000;
+	ifp->if_init =  em_init;
+	ifp->if_softc = adapter;
+	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+#ifdef __rtems__
+	ifp->if_output = ether_output;
+#endif
+	ifp->if_ioctl = em_ioctl;
+	ifp->if_start = em_start;
+	ifp->if_watchdog = em_watchdog;
+#ifndef __rtems__
+	IFQ_SET_MAXLEN(&ifp->if_snd, adapter->num_tx_desc - 1);
+	ifp->if_snd.ifq_drv_maxlen = adapter->num_tx_desc - 1;
+	IFQ_SET_READY(&ifp->if_snd);
+#else
+	ifp->if_snd.ifq_maxlen = adapter->num_tx_desc - 1;
+#endif
+
+#ifndef __rtems__
+#if __FreeBSD_version < 500000
+        ether_ifattach(ifp, ETHER_BPF_SUPPORTED);
+#else
+        ether_ifattach(ifp, adapter->hw.mac_addr);
+#endif
+#else
+	if ( !ifp->if_addrlist ) /* reattach hack */
+	{
+		if_attach(ifp);
+		ether_ifattach(ifp);
+	}
+#endif
+
+#ifndef __rtems__
+	ifp->if_capabilities = ifp->if_capenable = 0;
+
+	if (adapter->hw.mac_type >= em_82543) {
+		ifp->if_capabilities |= IFCAP_HWCSUM;
+		ifp->if_capenable |= IFCAP_HWCSUM;
+	}
+
+	/*
+	 * Tell the upper layer(s) we support long frames.
+	 */
+	ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header);
+#if __FreeBSD_version >= 500000
+	ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU;
+	ifp->if_capenable |= IFCAP_VLAN_MTU;
+#endif
+
+#ifdef DEVICE_POLLING
+	ifp->if_capabilities |= IFCAP_POLLING;
+	ifp->if_capenable |= IFCAP_POLLING;
+#endif
+
+	/* 
+	 * 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) {
+		ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_SX | IFM_FDX, 
+			    0, NULL);
+		ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_SX, 
+			    0, NULL);
+	} else {
+		ifmedia_add(&adapter->media, IFM_ETHER | IFM_10_T, 0, NULL);
+		ifmedia_add(&adapter->media, IFM_ETHER | IFM_10_T | IFM_FDX, 
+			    0, NULL);
+		ifmedia_add(&adapter->media, IFM_ETHER | IFM_100_TX, 
+			    0, NULL);
+		ifmedia_add(&adapter->media, IFM_ETHER | IFM_100_TX | IFM_FDX, 
+			    0, NULL);
+#if __FreeBSD_version < 500000 
+		ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_TX | IFM_FDX, 
+			    0, NULL);
+		ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_TX, 0, NULL);
+#else
+		ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_T | IFM_FDX, 
+			    0, NULL);
+		ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_T, 0, NULL);
+#endif
+	}
+	ifmedia_add(&adapter->media, IFM_ETHER | IFM_AUTO, 0, NULL);
+	ifmedia_set(&adapter->media, IFM_ETHER | IFM_AUTO);
+#endif
+
+	return;
+}
+
+#ifndef __rtems__
+/*********************************************************************
+ *
+ *  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))
+		return;
+
+        if(adapter->smartspeed == 0) {
+                /* If Master/Slave config fault is asserted twice,
+                 * we assume back-to-back */
+                em_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);
+                if(phy_tmp & SR_1000T_MS_CONFIG_FAULT) {
+                        em_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);
+                                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);
+                                }
+                        }
+                }
+                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);
+                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);
+                }
+        }
+        /* Restart process after EM_SMARTSPEED_MAX iterations */
+        if(adapter->smartspeed++ == EM_SMARTSPEED_MAX)
+                adapter->smartspeed = 0;
+
+	return;
+}
+
+
+/*
+ * 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;
+        return;
+}
+#endif
+
+static int
+em_dma_malloc(struct adapter *adapter, bus_size_t size,
+        struct em_dma_alloc *dma, int mapflags)
+{
+        int r;
+         
+#ifndef __rtems__
+        r = bus_dma_tag_create(NULL,                    /* parent */
+                               PAGE_SIZE, 0,            /* alignment, bounds */
+                               BUS_SPACE_MAXADDR,       /* lowaddr */
+                               BUS_SPACE_MAXADDR,       /* highaddr */
+                               NULL, NULL,              /* filter, filterarg */
+                               size,                    /* maxsize */
+                               1,                       /* nsegments */
+                               size,                    /* maxsegsize */
+                               BUS_DMA_ALLOCNOW,        /* flags */
+			       NULL,			/* lockfunc */
+			       NULL,			/* lockarg */
+                               &dma->dma_tag);
+        if (r != 0) {
+                printf("em%d: em_dma_malloc: bus_dma_tag_create failed; "
+                        "error %u\n", adapter->unit, r);
+                goto fail_0;
+        }
+
+        r = bus_dmamem_alloc(dma->dma_tag, (void**) &dma->dma_vaddr,
+                             BUS_DMA_NOWAIT, &dma->dma_map);
+#else
+		if ( (dma->malloc_base = malloc( size + PAGE_SIZE, M_DEVBUF, M_NOWAIT )) ) {
+			r = 0; 
+			dma->dma_vaddr = (caddr_t)_DO_ALIGN(dma->malloc_base, PAGE_SIZE);
+		} else {
+			r = -1;
+		}
+#endif
+        if (r != 0) {
+#ifndef __rtems__
+                printf("em%d: em_dma_malloc: bus_dmammem_alloc failed; "
+                        "size %ju, error %d\n", adapter->unit,
+			(uintmax_t)size, r);
+#else
+                printf("em%d: em_dma_malloc: bus_dmammem_alloc failed; "
+                        "size %u, error %d\n", adapter->unit,
+			size, r);
+#endif
+                goto fail_2;
+        }
+
+#ifndef __rtems__
+        r = bus_dmamap_load(dma->dma_tag, dma->dma_map, dma->dma_vaddr,
+                            size,
+                            em_dmamap_cb,
+                            &dma->dma_paddr,
+                            mapflags | BUS_DMA_NOWAIT);
+#else
+		dma->dma_paddr = kvtop(dma->dma_vaddr);
+#endif
+        if (r != 0) {
+                printf("em%d: em_dma_malloc: bus_dmamap_load failed; "
+                        "error %u\n", adapter->unit, r);
+                goto fail_3;
+        }
+
+#ifndef __rtems__
+        dma->dma_size = size;
+#endif
+        return (0);
+
+fail_3:
+        bus_dmamap_unload(dma->dma_tag, dma->dma_map);
+fail_2:
+#ifndef __rtems__
+        bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map);
+#else
+		free(dma->malloc_base, M_DEVBUF);
+		dma->dma_vaddr = dma->malloc_base = 0;
+		dma->dma_paddr = 0;
+#endif
+        bus_dma_tag_destroy(dma->dma_tag);
+#ifndef __rtems__
+fail_0:
+        dma->dma_map = NULL;
+        dma->dma_tag = NULL;
+#endif
+        return (r);
+}
+
+static void
+em_dma_free(struct adapter *adapter, struct em_dma_alloc *dma)
+{
+        bus_dmamap_unload(dma->dma_tag, dma->dma_map);
+#ifndef __rtems__
+        bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map);
+#else
+		free(dma->malloc_base, M_DEVBUF);
+		dma->dma_vaddr = dma->malloc_base = 0;
+		dma->dma_paddr = 0;
+#endif
+        bus_dma_tag_destroy(dma->dma_tag);
+}
+
+
+/*********************************************************************
+ *
+ *  Allocate memory for tx_buffer structures. The tx_buffer stores all 
+ *  the information needed to transmit a packet on the wire. 
+ *
+ **********************************************************************/
+static int
+em_allocate_transmit_structures(struct adapter * adapter)
+{
+	if (!(adapter->tx_buffer_area =
+	      (struct em_buffer *) malloc(sizeof(struct em_buffer) *
+					     adapter->num_tx_desc, M_DEVBUF,
+					     M_NOWAIT))) {
+		printf("em%d: Unable to allocate tx_buffer memory\n", 
+		       adapter->unit);
+		return ENOMEM;
+	}
+
+	bzero(adapter->tx_buffer_area,
+	      sizeof(struct em_buffer) * adapter->num_tx_desc);
+
+	return 0;
+}
+
+/*********************************************************************
+ *
+ *  Allocate and initialize transmit structures. 
+ *
+ **********************************************************************/
+static int
+em_setup_transmit_structures(struct adapter * adapter)
+{
+#ifndef __rtems__
+        /*
+         * Setup DMA descriptor areas.
+         */
+        if (bus_dma_tag_create(NULL,                    /* parent */
+                               1, 0,                    /* alignment, bounds */
+                               BUS_SPACE_MAXADDR,       /* lowaddr */ 
+                               BUS_SPACE_MAXADDR,       /* highaddr */
+                               NULL, NULL,              /* filter, filterarg */
+                               MCLBYTES * 8,            /* maxsize */
+                               EM_MAX_SCATTER,          /* nsegments */
+                               MCLBYTES * 8,            /* maxsegsize */
+                               BUS_DMA_ALLOCNOW,        /* flags */ 
+			       NULL,			/* lockfunc */
+			       NULL,			/* lockarg */
+                               &adapter->txtag)) {
+                printf("em%d: Unable to allocate TX DMA tag\n", adapter->unit);
+                return (ENOMEM);
+        }
+#endif
+
+        if (em_allocate_transmit_structures(adapter))
+                return (ENOMEM);
+
+        bzero((void *) adapter->tx_desc_base,
+              (sizeof(struct em_tx_desc)) * adapter->num_tx_desc);
+
+        adapter->next_avail_tx_desc = 0;
+        adapter->oldest_used_tx_desc = 0;
+
+        /* Set number of descriptors available */
+        adapter->num_tx_desc_avail = adapter->num_tx_desc;
+
+        /* Set checksum context */
+        adapter->active_checksum_context = OFFLOAD_NONE;
+
+        return (0);
+}
+
+/*********************************************************************
+ *
+ *  Enable transmit unit.
+ *
+ **********************************************************************/
+static void
+em_initialize_transmit_unit(struct adapter * adapter)
+{
+	u_int32_t       reg_tctl;
+	u_int32_t       reg_tipg = 0;
+	u_int64_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, TDBAL, (u_int32_t)bus_addr);
+	E1000_WRITE_REG(&adapter->hw, TDBAH, (u_int32_t)(bus_addr >> 32));
+	E1000_WRITE_REG(&adapter->hw, TDLEN, 
+			adapter->num_tx_desc *
+			sizeof(struct em_tx_desc));
+
+	/* Setup the HW Tx Head and Tail descriptor pointers */
+	E1000_WRITE_REG(&adapter->hw, TDH, 0);
+	E1000_WRITE_REG(&adapter->hw, TDT, 0);
+
+
+	HW_DEBUGOUT2("Base = %" PRIx32 ", Length = %" PRIx32 "\n", 
+		     E1000_READ_REG(&adapter->hw, TDBAL),
+		     E1000_READ_REG(&adapter->hw, TDLEN));
+
+	/* 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;
+                break;
+        default:
+                if (adapter->hw.media_type == em_media_type_fiber)
+                        reg_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;
+        }
+
+	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);
+
+	/* 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_82573)
+		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;
+	}
+	E1000_WRITE_REG(&adapter->hw, TCTL, reg_tctl);
+
+	/* Setup Transmit Descriptor Settings for this adapter */   
+	adapter->txd_cmd = E1000_TXD_CMD_IFCS | E1000_TXD_CMD_RS;
+
+	if (adapter->tx_int_delay.value > 0)
+		adapter->txd_cmd |= E1000_TXD_CMD_IDE;
+
+	return;
+}
+
+/*********************************************************************
+ *
+ *  Free all transmit related data structures.
+ *
+ **********************************************************************/
+static void
+em_free_transmit_structures(struct adapter * adapter)
+{
+        struct em_buffer   *tx_buffer;
+        int             i;
+
+        INIT_DEBUGOUT("free_transmit_structures: begin");
+
+        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);
+                                bus_dmamap_destroy(adapter->txtag, tx_buffer->map);
+                                m_freem(tx_buffer->m_head);
+                        }
+                        tx_buffer->m_head = NULL;
+                }
+        }
+        if (adapter->tx_buffer_area != NULL) {
+                free(adapter->tx_buffer_area, M_DEVBUF);
+                adapter->tx_buffer_area = NULL;
+        }
+#ifndef __rtems__
+        if (adapter->txtag != NULL) {
+                bus_dma_tag_destroy(adapter->txtag);
+                adapter->txtag = NULL;
+        }
+#endif
+        return;
+}
+
+#ifndef __rtems__
+/*********************************************************************
+ *
+ *  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.
+ *
+ **********************************************************************/
+static void
+em_transmit_checksum_setup(struct adapter * adapter,
+			   struct mbuf *mp,
+			   u_int32_t *txd_upper,
+			   u_int32_t *txd_lower) 
+{
+	struct em_context_desc *TXD;
+	struct em_buffer *tx_buffer;
+	int 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;
+		}
+	} else {
+		*txd_upper = 0;
+		*txd_lower = 0;
+		return;
+	}
+
+	/* If we reach this point, the checksum offload context
+	 * needs to be reset.
+	 */
+	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];
+
+	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);
+
+	TXD->upper_setup.tcp_fields.tucss = 
+		ETHER_HDR_LEN + sizeof(struct ip);
+	TXD->upper_setup.tcp_fields.tucse = htole16(0);
+
+	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);
+	}
+
+	TXD->tcp_seg_setup.data = htole32(0);
+	TXD->cmd_and_length = htole32(adapter->txd_cmd | E1000_TXD_CMD_DEXT);
+
+	tx_buffer->m_head = NULL;
+
+	if (++curr_txd == adapter->num_tx_desc)
+		curr_txd = 0;
+
+	adapter->num_tx_desc_avail--;
+	adapter->next_avail_tx_desc = curr_txd;
+
+	return;
+}
+#endif
+
+/**********************************************************************
+ *
+ *  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_clean_transmit_interrupts(struct adapter * adapter)
+{
+        int i, num_avail;
+        struct em_buffer *tx_buffer;
+        struct em_tx_desc   *tx_desc;
+	struct ifnet   *ifp = &adapter->arpcom.ac_if;
+
+	mtx_assert(&adapter->mtx, MA_OWNED);
+
+        if (adapter->num_tx_desc_avail == adapter->num_tx_desc)
+                return;
+
+        num_avail = adapter->num_tx_desc_avail;
+        i = adapter->oldest_used_tx_desc;
+
+        tx_buffer = &adapter->tx_buffer_area[i];
+        tx_desc = &adapter->tx_desc_base[i];
+
+        bus_dmamap_sync(adapter->txdma.dma_tag, adapter->txdma.dma_map,
+            BUS_DMASYNC_POSTREAD);
+        while (tx_desc->upper.fields.status & E1000_TXD_STAT_DD) {
+
+                tx_desc->upper.data = 0;
+                num_avail++;
+
+                if (tx_buffer->m_head) {
+			ifp->if_opackets++;
+                        bus_dmamap_unload(adapter->txtag, tx_buffer->map);
+                        bus_dmamap_destroy(adapter->txtag, tx_buffer->map);
+
+                        m_freem(tx_buffer->m_head);
+                        tx_buffer->m_head = NULL;
+                }
+
+                if (++i == adapter->num_tx_desc)
+                        i = 0;
+
+                tx_buffer = &adapter->tx_buffer_area[i];
+                tx_desc = &adapter->tx_desc_base[i];
+        }
+        bus_dmamap_sync(adapter->txdma.dma_tag, adapter->txdma.dma_map,
+            BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+        adapter->oldest_used_tx_desc = i;
+
+        /*
+         * 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)
+                        ifp->if_timer = 0;
+                else if (num_avail == adapter->num_tx_desc_avail)
+                        ifp->if_timer = EM_TX_TIMEOUT;
+        }
+        adapter->num_tx_desc_avail = num_avail;
+        return;
+}
+
+/*********************************************************************
+ *
+ *  Get a buffer from system mbuf buffer pool.
+ *
+ **********************************************************************/
+static int
+em_get_buf(int i, struct adapter *adapter,
+           struct mbuf *nmp)
+{
+        register struct mbuf    *mp = nmp;
+        struct em_buffer *rx_buffer;
+        struct ifnet   *ifp;
+        bus_addr_t paddr;
+#ifndef __rtems__
+        int error;
+#endif
+
+        ifp = &adapter->arpcom.ac_if;
+
+        if (mp == NULL) {
+#ifndef __rtems__
+                mp = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+#else
+				MGETHDR(mp, M_DONTWAIT, MT_DATA);
+				if ( mp ) {
+					MCLGET( mp, M_DONTWAIT );
+					if ( !(mp->m_flags & M_EXT) ) {
+						m_freem(mp);
+						mp = 0;
+					}
+				}
+#endif
+                if (mp == NULL) {
+                        adapter->mbuf_cluster_failed++;
+                        return(ENOBUFS);
+                }
+                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;
+        }
+
+        if (ifp->if_mtu <= ETHERMTU) {
+                m_adj(mp, ETHER_ALIGN);
+        }
+
+        rx_buffer = &adapter->rx_buffer_area[i];
+
+#ifndef __rtems__
+        /*
+         * 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);
+        if (error) {
+                m_free(mp);
+                return(error);
+        }
+#else
+		paddr = kvtop(mtod(mp, void*));
+#endif
+
+        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);
+
+        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)
+{
+        int             i, error;
+#ifndef __rtems__
+        struct em_buffer *rx_buffer;
+#endif
+
+        if (!(adapter->rx_buffer_area =
+              (struct em_buffer *) malloc(sizeof(struct em_buffer) *
+                                          adapter->num_rx_desc, M_DEVBUF,
+                                          M_NOWAIT))) {
+                printf("em%d: Unable to allocate rx_buffer memory\n",
+                       adapter->unit);
+                return(ENOMEM);
+        }
+
+        bzero(adapter->rx_buffer_area,
+              sizeof(struct em_buffer) * adapter->num_rx_desc);
+
+#ifndef __rtems__
+        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 */
+                               BUS_DMA_ALLOCNOW,        /* flags */
+			       NULL,			/* lockfunc */
+			       NULL,			/* lockarg */
+                               &adapter->rxtag);
+        if (error != 0) {
+                printf("em%d: em_allocate_receive_structures: "
+                        "bus_dma_tag_create failed; error %u\n",
+                       adapter->unit, error);
+                goto fail_0;
+        }
+        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,
+                                          &rx_buffer->map);
+                if (error != 0) {
+                        printf("em%d: em_allocate_receive_structures: "
+                                "bus_dmamap_create failed; error %u\n",
+                                adapter->unit, error);
+                        goto fail_1;
+                }
+        }
+
+#else
+		error = 0;
+#endif
+
+        for (i = 0; i < adapter->num_rx_desc; i++) {
+                error = em_get_buf(i, adapter, NULL);
+                if (error != 0) {
+                        adapter->rx_buffer_area[i].m_head = NULL;
+                        adapter->rx_desc_base[i].buffer_addr = 0;
+                        return(error);
+                }
+        }
+        bus_dmamap_sync(adapter->rxdma.dma_tag, adapter->rxdma.dma_map,
+            BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+        return(0);
+
+#ifndef __rtems__
+fail_1:
+        bus_dma_tag_destroy(adapter->rxtag);
+fail_0:
+        adapter->rxtag = NULL;
+#endif
+        free(adapter->rx_buffer_area, M_DEVBUF);
+        adapter->rx_buffer_area = NULL;
+        return (error);
+}
+
+/*********************************************************************
+ *
+ *  Allocate and initialize receive structures.
+ *  
+ **********************************************************************/
+static int
+em_setup_receive_structures(struct adapter * adapter)
+{
+	bzero((void *) adapter->rx_desc_base,
+              (sizeof(struct em_rx_desc)) * adapter->num_rx_desc);
+
+	if (em_allocate_receive_structures(adapter))
+		return ENOMEM;
+
+	/* Setup our descriptor pointers */
+        adapter->next_rx_desc_to_check = 0;
+	return(0);
+}
+
+/*********************************************************************
+ *
+ *  Enable receive unit.
+ *  
+ **********************************************************************/
+static void
+em_initialize_receive_unit(struct adapter * adapter)
+{
+	u_int32_t       reg_rctl;
+#ifndef __rtems__
+	u_int32_t       reg_rxcsum;
+#endif
+	struct ifnet    *ifp;
+	u_int64_t	bus_addr;
+
+        INIT_DEBUGOUT("em_initialize_receive_unit: begin");
+	ifp = &adapter->arpcom.ac_if;
+
+	/* 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);
+
+	if(adapter->hw.mac_type >= em_82540) {
+		E1000_WRITE_REG(&adapter->hw, RADV,
+		    adapter->rx_abs_int_delay.value);
+
+                /* Set the interrupt throttling rate.  Value is calculated
+                 * as DEFAULT_ITR = 1/(MAX_INTS_PER_SEC * 256ns) */
+#define MAX_INTS_PER_SEC        8000
+#define DEFAULT_ITR             1000000000/(MAX_INTS_PER_SEC * 256)
+                E1000_WRITE_REG(&adapter->hw, ITR, DEFAULT_ITR);
+        }       
+
+	/* Setup the Base and Length of the Rx Descriptor Ring */
+	bus_addr = adapter->rxdma.dma_paddr;
+	E1000_WRITE_REG(&adapter->hw, RDBAL, (u_int32_t)bus_addr);
+	E1000_WRITE_REG(&adapter->hw, RDBAH, (u_int32_t)(bus_addr >> 32));
+	E1000_WRITE_REG(&adapter->hw, RDLEN, adapter->num_rx_desc *
+			sizeof(struct em_rx_desc));
+
+	/* 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 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);
+
+	if (adapter->hw.tbi_compatibility_on == TRUE)
+		reg_rctl |= E1000_RCTL_SBP;
+
+
+	switch (adapter->rx_buffer_len) {
+	default:
+	case EM_RXBUFFER_2048:
+		reg_rctl |= E1000_RCTL_SZ_2048;
+		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;
+		break;
+	case EM_RXBUFFER_16384:
+		reg_rctl |= E1000_RCTL_SZ_16384 | E1000_RCTL_BSEX | E1000_RCTL_LPE;
+		break;
+	}
+
+	if (ifp->if_mtu > ETHERMTU)
+		reg_rctl |= E1000_RCTL_LPE;
+
+#ifndef __rtems__
+	/* 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);
+	}
+#endif
+
+	/* Enable Receives */
+	E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
+
+	return;
+}
+
+/*********************************************************************
+ *
+ *  Free receive related data structures.
+ *
+ **********************************************************************/
+static void
+em_free_receive_structures(struct adapter *adapter)
+{
+        struct em_buffer   *rx_buffer;
+        int             i;
+
+        INIT_DEBUGOUT("free_receive_structures: begin");
+
+        if (adapter->rx_buffer_area != NULL) {
+                rx_buffer = adapter->rx_buffer_area;
+                for (i = 0; i < adapter->num_rx_desc; i++, rx_buffer++) {
+#ifndef __rtems__
+                        if (rx_buffer->map != NULL) {
+                                bus_dmamap_unload(adapter->rxtag, rx_buffer->map);
+                                bus_dmamap_destroy(adapter->rxtag, rx_buffer->map);
+                        }
+#endif
+                        if (rx_buffer->m_head != NULL)
+                                m_freem(rx_buffer->m_head);
+                        rx_buffer->m_head = NULL;
+                }
+        }
+        if (adapter->rx_buffer_area != NULL) {
+                free(adapter->rx_buffer_area, M_DEVBUF);
+                adapter->rx_buffer_area = NULL;
+        }
+#ifndef __rtems__
+        if (adapter->rxtag != NULL) {
+                bus_dma_tag_destroy(adapter->rxtag);
+                adapter->rxtag = NULL;
+        }
+#endif
+        return;
+}
+
+/*********************************************************************
+ *
+ *  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_process_receive_interrupts(struct adapter * adapter, int count)
+{
+	struct ifnet        *ifp;
+	struct mbuf         *mp;
+#if __FreeBSD_version < 500000
+        struct ether_header *eh;
+#endif
+	u_int8_t            accept_frame = 0;
+ 	u_int8_t            eop = 0;
+	u_int16_t           len, desc_len, prev_len_adj;
+	int                 i;
+
+	/* Pointer to the receive descriptor being examined. */
+	struct em_rx_desc   *current_desc;
+
+	mtx_assert(&adapter->mtx, MA_OWNED);
+
+	ifp = &adapter->arpcom.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;
+	}
+
+	while ((current_desc->status & E1000_RXD_STAT_DD) && (count != 0)) {
+		
+		mp = adapter->rx_buffer_area[i].m_head;
+		bus_dmamap_sync(adapter->rxtag, adapter->rx_buffer_area[i].map,
+				BUS_DMASYNC_POSTREAD);
+
+		accept_frame = 1;
+		prev_len_adj = 0;
+                desc_len = le16toh(current_desc->length);
+		if (current_desc->status & E1000_RXD_STAT_EOP) {
+			count--;
+			eop = 1;
+			if (desc_len < ETHER_CRC_LEN) {
+                                len = 0;
+                                prev_len_adj = ETHER_CRC_LEN - desc_len;
+                        }
+                        else {
+                                len = desc_len - ETHER_CRC_LEN;
+                        }
+		} else {
+			eop = 0;
+			len = desc_len;
+		}
+
+		if (current_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK) {
+			u_int8_t            last_byte;
+			u_int32_t           pkt_len = desc_len;
+
+			if (adapter->fmp != NULL)
+				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 (len > 0) len--;
+			} 
+			else {
+				accept_frame = 0;
+			}
+		}
+
+		if (accept_frame) {
+
+			if (em_get_buf(i, adapter, NULL) == ENOBUFS) {
+				adapter->dropped_pkts++;
+				em_get_buf(i, adapter, mp);
+				if (adapter->fmp != NULL) 
+					m_freem(adapter->fmp);
+				adapter->fmp = NULL;
+				adapter->lmp = NULL;
+				break;
+			}
+
+			/* Assign correct length to the current fragment */
+			mp->m_len = len;
+
+			if (adapter->fmp == NULL) {
+				mp->m_pkthdr.len = len;
+				adapter->fmp = mp;	 /* Store the first mbuf */
+				adapter->lmp = mp;
+			} else {
+				/* Chain mbuf's together */
+				mp->m_flags &= ~M_PKTHDR;
+				/* 
+                                 * 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->lmp->m_next = mp;
+				adapter->lmp = adapter->lmp->m_next;
+				adapter->fmp->m_pkthdr.len += len;
+			}
+
+                        if (eop) {
+                                adapter->fmp->m_pkthdr.rcvif = ifp;
+                                 ifp->if_ipackets++;
+
+#if __FreeBSD_version < 500000
+                                eh = mtod(adapter->fmp, struct ether_header *);
+                                /* Remove ethernet header from mbuf */
+                                m_adj(adapter->fmp, sizeof(struct ether_header));
+#ifndef __rtems__
+                                em_receive_checksum(adapter, current_desc,
+                                                    adapter->fmp);
+                                if (current_desc->status & E1000_RXD_STAT_VP)
+                                        VLAN_INPUT_TAG(eh, adapter->fmp,
+                                                       (current_desc->special & 
+							E1000_RXD_SPC_VLAN_MASK));
+                                else
+#endif
+                                        ether_input(ifp, eh, adapter->fmp);
+#else
+
+                                em_receive_checksum(adapter, current_desc,
+                                                    adapter->fmp);
+                                if (current_desc->status & E1000_RXD_STAT_VP)
+                                        VLAN_INPUT_TAG(ifp, adapter->fmp,
+                                                       (current_desc->special &
+							E1000_RXD_SPC_VLAN_MASK),
+						       adapter->fmp = NULL);
+ 
+                                if (adapter->fmp != NULL) {
+					EM_UNLOCK(adapter);
+                                        (*ifp->if_input)(ifp, adapter->fmp);
+					EM_LOCK(adapter);
+				}
+#endif
+                                adapter->fmp = NULL;
+                                adapter->lmp = NULL;
+                        }
+		} else {
+			adapter->dropped_pkts++;
+			em_get_buf(i, adapter, mp);
+			if (adapter->fmp != NULL) 
+				m_freem(adapter->fmp);
+			adapter->fmp = NULL;
+			adapter->lmp = NULL;
+		}
+
+		/* Zero out the receive descriptors status  */
+		current_desc->status = 0;
+ 
+		/* Advance the E1000's Receive Queue #0  "Tail Pointer". */
+                E1000_WRITE_REG(&adapter->hw, RDT, i);
+
+                /* Advance our pointers to the next descriptor */
+                if (++i == adapter->num_rx_desc) {
+                        i = 0;
+                        current_desc = adapter->rx_desc_base;
+                } else
+			current_desc++;
+	}
+	bus_dmamap_sync(adapter->rxdma.dma_tag, adapter->rxdma.dma_map,
+	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+	adapter->next_rx_desc_to_check = i;
+	return;
+}
+
+#ifndef __rtems__
+/*********************************************************************
+ *
+ *  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)
+{
+	/* 82543 or newer only */
+	if ((adapter->hw.mac_type < em_82543) ||
+	    /* Ignore Checksum bit is set */
+	    (rx_desc->status & E1000_RXD_STAT_IXSM)) {
+		mp->m_pkthdr.csum_flags = 0;
+		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_TCPCS) {
+		/* Did it pass? */        
+		if (!(rx_desc->errors & E1000_RXD_ERR_TCPE)) {
+			mp->m_pkthdr.csum_flags |= 
+			(CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
+			mp->m_pkthdr.csum_data = htons(0xffff);
+		}
+	}
+
+	return;
+}
+
+
+static void 
+em_enable_vlans(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);
+
+	return;
+}
+
+static void
+em_disable_vlans(struct adapter *adapter)
+{
+	uint32_t ctrl;
+
+	ctrl = E1000_READ_REG(&adapter->hw, CTRL);
+	ctrl &= ~E1000_CTRL_VME;
+	E1000_WRITE_REG(&adapter->hw, CTRL, ctrl);
+
+	return;
+}
+#endif
+
+static void
+em_enable_intr(struct adapter * adapter)
+{
+	E1000_WRITE_REG(&adapter->hw, IMS, (IMS_ENABLE_MASK));
+	return;
+}
+
+static void
+em_disable_intr(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);
+	return;
+}
+
+static int
+em_is_valid_ether_addr(u_int8_t *addr)
+{
+        char zero_addr[6] = { 0, 0, 0, 0, 0, 0 };
+                                
+        if ((addr[0] & 1) || (!bcmp(addr, zero_addr, ETHER_ADDR_LEN))) {
+                return (FALSE);
+        }
+
+        return(TRUE);
+}
+
+void 
+em_write_pci_cfg(struct em_hw *hw,
+		      uint32_t reg,
+		      uint16_t *value)
+{
+	pci_write_config(((struct em_osdep *)hw->back)->dev, reg, 
+			 *value, 2);
+}
+
+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);
+	return;
+}
+
+void
+em_pci_set_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);
+        return;
+}
+
+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);
+        return;
+}
+
+uint32_t 
+em_io_read(struct em_hw *hw, unsigned long port)
+{
+	return(inl(port));
+}
+
+void 
+em_io_write(struct em_hw *hw, unsigned long port, uint32_t value)
+{
+#ifndef __rtems__
+	outl(port, value);
+#else
+	/* everybody else has this the other way round! */
+	outl(value, port);
+#endif
+	return;
+}
+
+/*********************************************************************
+* 82544 Coexistence issue workaround.
+*    There are 2 issues.
+*       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.
+*
+*       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.
+*
+*
+*    WORKAROUND:
+*          Make sure we do not have ending address as 1,2,3,4(Hang) or 9,a,b,c (DAC)
+*
+*** *********************************************************************/
+static u_int32_t
+em_fill_descriptors (u_int64_t address,
+                              u_int32_t length,
+                              PDESC_ARRAY desc_array)
+{
+        /* Since issue is sensitive to length and address.*/
+        /* Let us first check the address...*/
+        u_int32_t safe_terminator;
+        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 = (u_int32_t)((((u_int32_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 > 0xC &&
+        safe_terminator <= 0xF)) {
+                desc_array->descriptor[0].address = address;
+                desc_array->descriptor[0].length = length;
+                desc_array->elements = 1;
+                return desc_array->elements;
+        }
+         
+        desc_array->descriptor[0].address = address;
+        desc_array->descriptor[0].length = length - 4;
+        desc_array->descriptor[1].address = address + (length - 4);
+        desc_array->descriptor[1].length = 4;
+        desc_array->elements = 2;
+        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);
+
+	/* 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.algnerrc += 
+		E1000_READ_REG(&adapter->hw, ALGNERRC);
+		adapter->stats.rxerrc += 
+		E1000_READ_REG(&adapter->hw, RXERRC);
+		adapter->stats.tncrs += 
+		E1000_READ_REG(&adapter->hw, TNCRS);
+		adapter->stats.cexterr += 
+		E1000_READ_REG(&adapter->hw, CEXTERR);
+		adapter->stats.tsctc += 
+		E1000_READ_REG(&adapter->hw, TSCTC);
+		adapter->stats.tsctfc += 
+		E1000_READ_REG(&adapter->hw, TSCTFC);
+	}
+	ifp = &adapter->arpcom.ac_if;
+
+	/* Fill out the OS statistics structure */
+	ifp->if_ibytes = adapter->stats.gorcl;
+	ifp->if_obytes = adapter->stats.gotcl;
+	ifp->if_imcasts = adapter->stats.mprc;
+	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.rlec +
+	adapter->stats.mpc + adapter->stats.cexterr;
+
+	/* Tx Errors */
+	ifp->if_oerrors = adapter->stats.ecol + adapter->stats.latecol;
+
+}
+
+#ifndef __rtems__
+/**********************************************************************
+ *
+ *  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)
+{
+        int unit = adapter->unit;
+	uint8_t *hw_addr = adapter->hw.hw_addr;
+ 
+	printf("em%d: Adapter hardware address = %p \n", unit, hw_addr);
+	printf("em%d:CTRL  = 0x%x\n", unit, 
+		E1000_READ_REG(&adapter->hw, CTRL)); 
+	printf("em%d:RCTL  = 0x%x PS=(0x8402)\n", unit, 
+		E1000_READ_REG(&adapter->hw, RCTL)); 
+	printf("em%d:tx_int_delay = %d, tx_abs_int_delay = %d\n", unit, 
+              E1000_READ_REG(&adapter->hw, TIDV),
+	      E1000_READ_REG(&adapter->hw, TADV));
+	printf("em%d:rx_int_delay = %d, rx_abs_int_delay = %d\n", unit, 
+              E1000_READ_REG(&adapter->hw, RDTR),
+	      E1000_READ_REG(&adapter->hw, RADV));
+        printf("em%d: fifo workaround = %lld, fifo_reset = %lld\n", unit,
+               (long long)adapter->tx_fifo_wrk_cnt, 
+               (long long)adapter->tx_fifo_reset_cnt);
+        printf("em%d: hw tdh = %d, hw tdt = %d\n", unit,
+               E1000_READ_REG(&adapter->hw, TDH),
+               E1000_READ_REG(&adapter->hw, TDT));
+        printf("em%d: Num Tx descriptors avail = %d\n", unit,
+               adapter->num_tx_desc_avail);
+        printf("em%d: Tx Descriptors not avail1 = %ld\n", unit,
+               adapter->no_tx_desc_avail1);
+        printf("em%d: Tx Descriptors not avail2 = %ld\n", unit,
+               adapter->no_tx_desc_avail2);
+        printf("em%d: Std mbuf failed = %ld\n", unit,
+               adapter->mbuf_alloc_failed);
+        printf("em%d: Std mbuf cluster failed = %ld\n", unit,
+               adapter->mbuf_cluster_failed);
+        printf("em%d: Driver dropped packets = %ld\n", unit,
+               adapter->dropped_pkts);
+
+        return;
+}
+#endif
+
+static void
+em_print_hw_stats(struct adapter *adapter)
+{
+        int unit = adapter->unit;
+
+        printf("em%d: Excessive collisions = %lld\n", unit,
+               (long long)adapter->stats.ecol);
+        printf("em%d: Symbol errors = %lld\n", unit,
+               (long long)adapter->stats.symerrs);
+        printf("em%d: Sequence errors = %lld\n", unit,
+               (long long)adapter->stats.sec);
+        printf("em%d: Defer count = %lld\n", unit,
+               (long long)adapter->stats.dc);
+
+        printf("em%d: Missed Packets = %lld\n", unit,
+               (long long)adapter->stats.mpc);
+        printf("em%d: Receive No Buffers = %lld\n", unit,
+               (long long)adapter->stats.rnbc);
+        printf("em%d: Receive length errors = %lld\n", unit,
+               (long long)adapter->stats.rlec);
+        printf("em%d: Receive errors = %lld\n", unit,
+               (long long)adapter->stats.rxerrc);
+        printf("em%d: Crc errors = %lld\n", unit,
+               (long long)adapter->stats.crcerrs);
+        printf("em%d: Alignment errors = %lld\n", unit,
+               (long long)adapter->stats.algnerrc);
+        printf("em%d: Carrier extension errors = %lld\n", unit,
+               (long long)adapter->stats.cexterr);
+
+        printf("em%d: XON Rcvd = %lld\n", unit,
+               (long long)adapter->stats.xonrxc);
+        printf("em%d: XON Xmtd = %lld\n", unit,
+               (long long)adapter->stats.xontxc);
+        printf("em%d: XOFF Rcvd = %lld\n", unit,
+               (long long)adapter->stats.xoffrxc);
+        printf("em%d: XOFF Xmtd = %lld\n", unit,
+               (long long)adapter->stats.xofftxc);
+
+        printf("em%d: Good Packets Rcvd = %lld\n", unit,
+               (long long)adapter->stats.gprc);
+        printf("em%d: Good Packets Xmtd = %lld\n", unit,
+               (long long)adapter->stats.gptc);
+
+        return;
+}
+
+#ifndef __rtems__
+static int
+em_sysctl_debug_info(SYSCTL_HANDLER_ARGS)
+{
+        int error;
+        int result;
+        struct adapter *adapter;
+
+        result = -1;
+        error = sysctl_handle_int(oidp, &result, 0, req);
+
+        if (error || !req->newptr)
+                return (error);
+
+        if (result == 1) {
+                adapter = (struct adapter *)arg1;
+                em_print_debug_info(adapter);
+        }
+
+        return error;
+}
+
+static int
+em_sysctl_stats(SYSCTL_HANDLER_ARGS)
+{
+        int error;
+        int result;
+        struct adapter *adapter;
+
+        result = -1;
+        error = sysctl_handle_int(oidp, &result, 0, req);
+
+        if (error || !req->newptr)
+                return (error);
+
+        if (result == 1) {
+                adapter = (struct adapter *)arg1;
+                em_print_hw_stats(adapter);
+        }
+
+        return error;
+}
+
+static int
+em_sysctl_int_delay(SYSCTL_HANDLER_ARGS)
+{
+	struct em_int_delay_info *info;
+	struct adapter *adapter;
+	u_int32_t regval;
+	int error;
+	int usecs;
+	int ticks;
+	int s;
+
+	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))
+		return EINVAL;
+	info->value = usecs;
+	ticks = E1000_USECS_TO_TICKS(usecs);
+	
+	s = splimp();
+	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
+			adapter->txd_cmd |= E1000_TXD_CMD_IDE;
+		break;
+	}
+	E1000_WRITE_OFFSET(&adapter->hw, info->offset, regval);
+	splx(s);
+	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)
+{
+	info->adapter = adapter;
+	info->offset = offset;
+	info->value = value;
+	SYSCTL_ADD_PROC(device_get_sysctl_ctx(adapter->dev),
+	    SYSCTL_CHILDREN(device_get_sysctl_tree(adapter->dev)),
+	    OID_AUTO, name, CTLTYPE_INT|CTLFLAG_RW,
+	    info, 0, em_sysctl_int_delay, "I", description);
+}
+#endif
+
+#ifdef __rtems__
+/* Initialize bare minimals so we can check the phy link status */
+int
+em_hw_early_init(device_t dev)
+{
+struct adapter *adapter = device_get_softc(dev);
+	adapter->dev = dev;
+	adapter->osdep.dev = dev;
+	em_identify_hardware(adapter);	
+	return em_allocate_pci_resources(adapter);
+}
+#endif
Index: bsps/powerpc/beatnik/net/if_em/if_em.h
===================================================================
--- bsps/powerpc/beatnik/net/if_em/if_em.h	(revision 031df3914990db0336a0d386fb53558b05de467e)
+++ bsps/powerpc/beatnik/net/if_em/if_em.h	(revision 031df3914990db0336a0d386fb53558b05de467e)
@@ -0,0 +1,493 @@
+/**************************************************************************
+
+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: /repoman/r/ncvs/src/sys/dev/em/if_em.h,v 1.31 2005/05/26 23:32:02 tackerman Exp $*/
+
+#ifndef _EM_H_DEFINED_
+#define _EM_H_DEFINED_
+
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#ifndef __rtems__
+#include <sys/module.h>
+#endif
+#include <sys/sockio.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#ifndef __rtems__
+
+#include <net/bpf.h>
+#include <net/if_types.h>
+#include <net/if_vlan_var.h>
+#else
+#include <net/if_types.h>
+#endif
+
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
+
+#ifndef __rtems__
+#include <sys/bus.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <machine/resource.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <machine/clock.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#else
+#include <netinet/if_ether.h>
+#include <bsp/pci.h>
+#endif
+
+#ifndef __rtems__
+#include <sys/endian.h>
+#include <sys/proc.h>
+#include "opt_bdg.h"
+
+
+#include <dev/em/if_em_hw.h>
+#else
+#include "if_em_hw.h"
+#endif
+
+/* Tunables */
+
+/*
+ * EM_MAX_TXD: Maximum number of Transmit Descriptors
+ * Valid Range: 80-256 for 82542 and 82543-based adapters
+ *              80-4096 for others
+ * Default Value: 256
+ *   This value is the number of transmit descriptors allocated by the driver.
+ *   Increasing this value allows the driver to queue more transmits. Each
+ *   descriptor is 16 bytes.
+ */
+#define EM_MAX_TXD                      256
+
+/*
+ * EM_MAX_RXD - Maximum number of receive Descriptors
+ * Valid Range: 80-256 for 82542 and 82543-based adapters
+ *              80-4096 for others
+ * Default Value: 256
+ *   This value is the number of receive descriptors allocated by the driver.
+ *   Increasing this value allows the driver to buffer more incoming packets.
+ *   Each descriptor is 16 bytes.  A receive buffer is also allocated for each
+ *   descriptor. The maximum MTU size is 16110.
+ *
+ */
+#define EM_MAX_RXD                      80
+
+/*
+ * EM_TIDV - Transmit Interrupt Delay Value
+ * Valid Range: 0-65535 (0=off)
+ * Default Value: 64
+ *   This value delays the generation of transmit interrupts in units of
+ *   1.024 microseconds. Transmit interrupt reduction can improve CPU
+ *   efficiency if properly tuned for specific network traffic. If the
+ *   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
+
+/*
+ * EM_TADV - Transmit Absolute Interrupt Delay Value (Not valid for 82542/82543/82544)
+ * Valid Range: 0-65535 (0=off)
+ * Default Value: 64
+ *   This value, in units of 1.024 microseconds, limits the delay in which a
+ *   transmit interrupt is generated. Useful only if EM_TIDV is non-zero,
+ *   this value ensures that an interrupt is generated after the initial
+ *   packet is sent on the wire within the set amount of time.  Proper tuning,
+ *   along with EM_TIDV, may improve traffic throughput in specific
+ *   network conditions.
+ */
+#define EM_TADV                         64
+
+/*
+ * EM_RDTR - Receive Interrupt Delay Timer (Packet Timer)
+ * Valid Range: 0-65535 (0=off)
+ * Default Value: 0
+ *   This value delays the generation of receive interrupts in units of 1.024
+ *   microseconds.  Receive interrupt reduction can improve CPU efficiency if
+ *   properly tuned for specific network traffic. Increasing this value adds
+ *   extra latency to frame reception and can end up decreasing the throughput
+ *   of TCP traffic. If the system is reporting dropped receives, this value
+ *   may be set too high, causing the driver to run out of available receive
+ *   descriptors.
+ *
+ *   CAUTION: When setting EM_RDTR to a value other than 0, adapters
+ *            may hang (stop transmitting) under certain network conditions.
+ *            If this occurs a WATCHDOG message is logged in the system event log.
+ *            In addition, the controller is automatically reset, restoring the
+ *            network connection. To eliminate the potential for the hang
+ *            ensure that EM_RDTR is set to 0.
+ */
+#define EM_RDTR                         0
+
+/*
+ * Receive Interrupt Absolute Delay Timer (Not valid for 82542/82543/82544)
+ * Valid Range: 0-65535 (0=off)
+ * Default Value: 64
+ *   This value, in units of 1.024 microseconds, limits the delay in which a
+ *   receive interrupt is generated. Useful only if EM_RDTR is non-zero,
+ *   this value ensures that an interrupt is generated after the initial
+ *   packet is received within the set amount of time.  Proper tuning,
+ *   along with EM_RDTR, may improve traffic throughput in specific network
+ *   conditions.
+ */
+#define EM_RADV                         64
+
+
+/*
+ * This parameter controls the maximum no of times the driver will loop
+ * in the isr.
+ *           Minimum Value = 1
+ */
+#define EM_MAX_INTR                     3
+
+/*
+ * Inform the stack about transmit checksum offload capabilities.
+ */
+#define EM_CHECKSUM_FEATURES            (CSUM_TCP | CSUM_UDP)
+
+/*
+ * This parameter controls the duration of transmit watchdog timer.
+ */
+#define EM_TX_TIMEOUT                   5    /* set to 5 seconds */
+
+/*
+ * This parameter controls when the driver calls the routine to reclaim
+ * transmit descriptors.
+ */
+#ifndef __rtems__
+#define EM_TX_CLEANUP_THRESHOLD         EM_MAX_TXD / 8
+#else
+#define EM_TX_CLEANUP_THRESHOLD         (adapter->tx_cleanup_threshold)
+#endif
+
+/*
+ * This parameter controls whether or not autonegotation is enabled.
+ *              0 - Disable autonegotiation
+ *              1 - Enable  autonegotiation
+ */
+#define DO_AUTO_NEG                     1
+
+/*
+ * This parameter control whether or not the driver will wait for
+ * autonegotiation to complete.
+ *              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 */
+
+/* Tunables -- End */
+
+#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_MMBA                         0x0010 /* Mem base address */
+#define EM_ROUNDUP(size, unit) (((size) + (unit) - 1) & ~((unit) - 1))
+
+#define EM_JUMBO_PBA                    0x00000028
+#define EM_DEFAULT_PBA                  0x00000030
+#define EM_SMARTSPEED_DOWNSHIFT         3
+#define EM_SMARTSPEED_MAX               15
+
+
+#define MAX_NUM_MULTICAST_ADDRESSES     128
+#define PCI_ANY_ID                      (~0U)
+#define ETHER_ALIGN                     2
+
+/* Defines for printing debug information */
+#define DEBUG_INIT  0
+#define DEBUG_IOCTL 0
+#define DEBUG_HW    0
+
+#define INIT_DEBUGOUT(S)            if (DEBUG_INIT)  printf(S "\n")
+#define INIT_DEBUGOUT1(S, A)        if (DEBUG_INIT)  printf(S "\n", A)
+#define INIT_DEBUGOUT2(S, A, B)     if (DEBUG_INIT)  printf(S "\n", A, B)
+#define IOCTL_DEBUGOUT(S)           if (DEBUG_IOCTL) printf(S "\n")
+#define IOCTL_DEBUGOUT1(S, A)       if (DEBUG_IOCTL) printf(S "\n", A)
+#define IOCTL_DEBUGOUT2(S, A, B)    if (DEBUG_IOCTL) printf(S "\n", A, B)
+#define HW_DEBUGOUT(S)              if (DEBUG_HW) printf(S "\n")
+#define HW_DEBUGOUT1(S, A)          if (DEBUG_HW) printf(S "\n", A)
+#define HW_DEBUGOUT2(S, A, B)       if (DEBUG_HW) printf(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;
+
+
+struct em_buffer {
+        struct mbuf    *m_head;
+#ifndef __rtems__
+        bus_dmamap_t    map;         /* bus_dma map for packet */
+#endif
+};
+
+/*
+ * Bus dma allocation structure used by
+ * em_dma_malloc and em_dma_free.
+ */
+struct em_dma_alloc {
+		bus_addr_t              dma_paddr;	/* 64bit in descriptors */
+#ifndef __rtems__
+        caddr_t                 dma_vaddr;
+        bus_dma_tag_t           dma_tag;
+        bus_dmamap_t            dma_map;
+        bus_dma_segment_t       dma_seg;
+        bus_size_t              dma_size;
+        int                     dma_nseg;
+#else
+		caddr_t		dma_vaddr;
+		caddr_t		malloc_base;
+#endif
+};
+
+typedef enum _XSUM_CONTEXT_T {
+	OFFLOAD_NONE,
+	OFFLOAD_TCP_IP,
+	OFFLOAD_UDP_IP
+} XSUM_CONTEXT_T;
+
+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 */
+};
+
+/* For 82544 PCIX  Workaround */
+typedef struct _ADDRESS_LENGTH_PAIR
+{
+    u_int64_t   address;
+    u_int32_t   length;
+} ADDRESS_LENGTH_PAIR, *PADDRESS_LENGTH_PAIR;
+
+typedef struct _DESCRIPTOR_PAIR
+{
+    ADDRESS_LENGTH_PAIR descriptor[4];
+    u_int32_t   elements;
+} DESC_ARRAY, *PDESC_ARRAY;
+
+/* Our adapter structure */
+struct adapter {
+	struct arpcom   interface_data;
+	struct adapter *next;
+	struct adapter *prev;
+	struct em_hw    hw;
+
+	/* FreeBSD operating-system-specific structures */
+	struct em_osdep osdep;
+#ifndef __rtems__
+	struct device   *dev;
+	struct resource *res_memory;
+	struct resource *res_ioport;
+	struct resource *res_interrupt;
+	void            *int_handler_tag;
+	struct ifmedia  media;
+	struct callout	timer;
+	struct callout	tx_fifo_timer;
+	int             io_rid;
+	struct ifmedia  media;
+#endif
+	u_int8_t        unit;
+#ifndef __rtems__
+	struct mtx	mtx;
+	int		em_insert_vlan_header;
+#else
+	device_t	    dev;
+	unsigned char	irq_no;
+	unsigned char	b,d,f;
+	rtems_id		tid;
+#endif
+
+	/* Info about the board itself */
+#ifndef __rtems__
+	u_int32_t       part_num;
+#else
+	uint32_t       part_num;
+#endif
+	u_int8_t        link_active;
+	u_int16_t       link_speed;
+	u_int16_t       link_duplex;
+	u_int32_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;
+
+	/*
+         * Transmit definitions
+         *
+         * We have an array of num_tx_desc descriptors (handled
+         * by the controller) paired with an array of tx_buffers
+         * (at tx_buffer_area).
+         * The index of the next available descriptor is next_avail_tx_desc.
+         * 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;
+        u_int32_t          next_avail_tx_desc;
+	u_int32_t          oldest_used_tx_desc;
+        volatile u_int16_t num_tx_desc_avail;
+        u_int16_t          num_tx_desc;
+        u_int32_t          txd_cmd;
+        struct em_buffer   *tx_buffer_area;
+#ifndef __rtems__
+	bus_dma_tag_t      txtag;               /* dma tag for tx */
+#endif
+#ifdef __rtems__
+		u_int16_t          tx_cleanup_threshold;        
+#endif
+
+	/* 
+	 * Receive definitions
+         *
+         * we have an array of num_rx_desc rx_desc (handled by the
+         * controller), and paired with an array of rx_buffers
+         * (at rx_buffer_area).
+         * 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;
+        u_int32_t          next_rx_desc_to_check;
+        u_int16_t          num_rx_desc;
+        u_int32_t          rx_buffer_len;
+        struct em_buffer   *rx_buffer_area;
+#ifndef __rtems__
+	bus_dma_tag_t      rxtag;
+#endif
+
+	/* Jumbo frame */
+	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;
+
+	/* 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
+
+	u_int32_t       tx_fifo_size;
+	u_int32_t       tx_fifo_head;
+	u_int32_t       tx_fifo_head_addr;
+	u_int64_t       tx_fifo_reset_cnt;
+	u_int64_t       tx_fifo_wrk_cnt;
+	u_int32_t       tx_head_addr;
+
+        /* For 82544 PCIX Workaround */
+        boolean_t       pcix_82544;
+	boolean_t       in_detach;
+
+	struct em_hw_stats stats;
+};
+
+#define	EM_LOCK_INIT(_sc, _name) \
+	mtx_init(&(_sc)->mtx, _name, MTX_NETWORK_LOCK, MTX_DEF)
+#define	EM_LOCK_DESTROY(_sc)	mtx_destroy(&(_sc)->mtx)
+#define	EM_LOCK(_sc)		mtx_lock(&(_sc)->mtx)
+#define	EM_UNLOCK(_sc)		mtx_unlock(&(_sc)->mtx)
+#define	EM_LOCK_ASSERT(_sc)	mtx_assert(&(_sc)->mtx, MA_OWNED)
+
+#ifdef __rtems__
+/* Initialize bare minimals so we can check the phy link status;
+ * 'rtems_em_pci_setup()' must have been run on the device already!
+ */
+int
+em_hw_early_init(device_t dev);
+#endif
+
+
+#endif                                                  /* _EM_H_DEFINED_ */
Index: bsps/powerpc/beatnik/net/if_em/if_em_hw.c
===================================================================
--- bsps/powerpc/beatnik/net/if_em/if_em_hw.c	(revision 031df3914990db0336a0d386fb53558b05de467e)
+++ bsps/powerpc/beatnik/net/if_em/if_em_hw.c	(revision 031df3914990db0336a0d386fb53558b05de467e)
@@ -0,0 +1,6636 @@
+/*******************************************************************************
+
+  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.
+
+*******************************************************************************/
+
+/* if_em_hw.c
+ * Shared functions for accessing and configuring the MAC
+ */
+
+#include <sys/cdefs.h>
+#ifdef __rtems__
+#include "rtemscompat_defs.h"
+#include "../porting/rtemscompat.h"
+#include "if_em_hw.h"
+#else
+__FBSDID("$FreeBSD: /repoman/r/ncvs/src/sys/dev/em/if_em_hw.c,v 1.16 2005/05/26 23:32:02 tackerman Exp $");
+
+#include <dev/em/if_em_hw.h>
+#endif
+
+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);
+
+/* 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] =
+    { 8, 13, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43,
+      22, 24, 27, 30, 32, 35, 37, 40, 42, 44, 47, 49, 51, 54, 56, 58,
+      32, 35, 38, 41, 44, 47, 50, 53, 55, 58, 61, 63, 66, 69, 71, 74,
+      43, 47, 51, 54, 58, 61, 64, 67, 71, 74, 77, 80, 82, 85, 88, 90,
+      57, 62, 66, 70, 74, 77, 81, 85, 88, 91, 94, 97, 100, 103, 106, 108,
+      73, 78, 82, 87, 91, 95, 98, 102, 105, 109, 112, 114, 117, 119, 122, 124,
+      91, 96, 101, 105, 109, 113, 116, 119, 122, 125, 127, 128, 128, 128, 128, 128,
+      108, 113, 117, 121, 124, 127, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128};
+
+
+/******************************************************************************
+ * Set the phy type member in the hw struct.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+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;
+        }
+        /* 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:
+        hw->mac_type = em_82546_rev_3;
+        break;
+    case E1000_DEV_ID_82541EI:
+    case E1000_DEV_ID_82541ER_LOM:
+    case E1000_DEV_ID_82541EI_MOBILE:
+        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_82573E:
+    case E1000_DEV_ID_82573E_IAMT:
+        hw->mac_type = em_82573;
+        break;
+    default:
+        /* Should never have loaded on this device */
+        return -E1000_ERR_MAC_TYPE;
+    }
+
+    switch(hw->mac_type) {
+    case em_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:
+        hw->media_type = em_media_type_internal_serdes;
+        break;
+    default:
+        if(hw->mac_type >= em_82543) {
+            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;
+            }
+        } else {
+            /* This is an 82542 (fiber only) */
+            hw->media_type = em_media_type_fiber;
+        }
+    }
+}
+
+/******************************************************************************
+ * 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);
+    }
+
+    /* 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:
+#ifndef __arm__
+        case em_82546:
+#endif
+        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;
+        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:
+            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 */
+            ret_val = em_get_auto_rd_done(hw);
+            if(ret_val)
+                /* We don't want to continue accessing MAC registers. */
+                return ret_val;
+            break;
+        default:
+            /* Wait for EEPROM reload (it happens automatically) */
+            msec_delay(5);
+            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);
+    }
+#ifdef __rtems__
+	msec_delay(100);
+#endif
+
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Performs basic configuration of the adapter.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Assumes that the controller has previously been reset and is in a
+ * post-reset uninitialized state. Initializes the receive address registers,
+ * multicast table, and VLAN filter table. Calls routines to setup link
+ * configuration and flow control settings. Clears all on-chip counters. Leaves
+ * the transmit and receive units disabled and uninitialized.
+ *****************************************************************************/
+int32_t
+em_init_hw(struct em_hw *hw)
+{
+    uint32_t ctrl;
+    uint32_t i;
+    int32_t ret_val;
+    uint16_t pcix_cmd_word;
+    uint16_t pcix_stat_hi_word;
+    uint16_t cmd_mmrbc;
+    uint16_t stat_mmrbc;
+    uint32_t mta_size;
+
+    DEBUGFUNC("em_init_hw");
+
+    /* Initialize Identification LED */
+    ret_val = em_id_led_init(hw);
+    if(ret_val) {
+        DEBUGOUT("Error Initializing Identification LED\n");
+        return ret_val;
+    }
+
+    /* Set the media type and TBI compatibility */
+    em_set_media_type(hw);
+
+    /* Disabling VLAN filtering. */
+    DEBUGOUT("Initializing the IEEE VLAN\n");
+    if (hw->mac_type < em_82545_rev_3)
+        E1000_WRITE_REG(hw, VET, 0);
+    em_clear_vfta(hw);
+
+    /* For 82542 (rev 2.0), disable MWI and put the receiver into reset */
+    if(hw->mac_type == em_82542_rev2_0) {
+        DEBUGOUT("Disabling MWI on 82542 rev 2.0\n");
+        em_pci_clear_mwi(hw);
+        E1000_WRITE_REG(hw, RCTL, E1000_RCTL_RST);
+        E1000_WRITE_FLUSH(hw);
+        msec_delay(5);
+    }
+
+    /* Setup the receive address. This involves initializing all of the Receive
+     * Address Registers (RARs 0 - 15).
+     */
+    em_init_rx_addrs(hw);
+
+    /* For 82542 (rev 2.0), take the receiver out of reset and enable MWI */
+    if(hw->mac_type == em_82542_rev2_0) {
+        E1000_WRITE_REG(hw, RCTL, 0);
+        E1000_WRITE_FLUSH(hw);
+        msec_delay(1);
+        if(hw->pci_cmd_word & CMD_MEM_WRT_INVALIDATE)
+            em_pci_set_mwi(hw);
+    }
+
+    /* Zero out the Multicast HASH table */
+    DEBUGOUT("Zeroing the MTA\n");
+    mta_size = E1000_MC_TBL_SIZE;
+    for(i = 0; i < mta_size; i++)
+        E1000_WRITE_REG_ARRAY(hw, MTA, i, 0);
+
+    /* Set the PCI priority bit correctly in the CTRL register.  This
+     * determines if the adapter gives priority to receives, or if it
+     * gives equal priority to transmits and receives.  Valid only on
+     * 82542 and 82543 silicon.
+     */
+    if(hw->dma_fairness && hw->mac_type <= em_82543) {
+        ctrl = E1000_READ_REG(hw, CTRL);
+        E1000_WRITE_REG(hw, CTRL, ctrl | E1000_CTRL_PRIOR);
+    }
+
+    switch(hw->mac_type) {
+    case em_82545_rev_3:
+    case em_82546_rev_3:
+        break;
+    default:
+        /* Workaround for PCI-X problem when BIOS sets MMRBC incorrectly. */
+        if(hw->bus_type == em_bus_type_pcix) {
+            em_read_pci_cfg(hw, PCIX_COMMAND_REGISTER, &pcix_cmd_word);
+            em_read_pci_cfg(hw, PCIX_STATUS_REGISTER_HI,
+                &pcix_stat_hi_word);
+            cmd_mmrbc = (pcix_cmd_word & PCIX_COMMAND_MMRBC_MASK) >>
+                PCIX_COMMAND_MMRBC_SHIFT;
+            stat_mmrbc = (pcix_stat_hi_word & PCIX_STATUS_HI_MMRBC_MASK) >>
+                PCIX_STATUS_HI_MMRBC_SHIFT;
+            if(stat_mmrbc == PCIX_STATUS_HI_MMRBC_4K)
+                stat_mmrbc = PCIX_STATUS_HI_MMRBC_2K;
+            if(cmd_mmrbc > stat_mmrbc) {
+                pcix_cmd_word &= ~PCIX_COMMAND_MMRBC_MASK;
+                pcix_cmd_word |= stat_mmrbc << PCIX_COMMAND_MMRBC_SHIFT;
+                em_write_pci_cfg(hw, PCIX_COMMAND_REGISTER,
+                    &pcix_cmd_word);
+            }
+        }
+        break;
+    }
+
+    /* Call a subroutine to configure the link and setup flow control. */
+    ret_val = em_setup_link(hw);
+
+    /* Set the transmit descriptor write-back policy */
+    if(hw->mac_type > em_82544) {
+        ctrl = E1000_READ_REG(hw, TXDCTL);
+        ctrl = (ctrl & ~E1000_TXDCTL_WTHRESH) | E1000_TXDCTL_FULL_TX_DESC_WB;
+        switch (hw->mac_type) {
+        default:
+            break;
+        case em_82573:
+            ctrl |= E1000_TXDCTL_COUNT_DESC;
+            break;
+        }
+        E1000_WRITE_REG(hw, TXDCTL, ctrl);
+    }
+
+    if (hw->mac_type == em_82573) {
+        em_enable_tx_pkt_filtering(hw); 
+    }
+
+
+    /* Clear all of the statistics registers (clear on read).  It is
+     * important that we do this after we have tried to establish link
+     * because the symbol error count will increment wildly if there
+     * is no link.
+     */
+    em_clear_hw_cntrs(hw);
+
+    return ret_val;
+}
+
+/******************************************************************************
+ * Adjust SERDES output amplitude based on EEPROM setting.
+ *
+ * hw - Struct containing variables accessed by shared code.
+ *****************************************************************************/
+static int32_t
+em_adjust_serdes_amplitude(struct em_hw *hw)
+{
+    uint16_t eeprom_data;
+    int32_t  ret_val;
+
+    DEBUGFUNC("em_adjust_serdes_amplitude");
+
+    if(hw->media_type != em_media_type_internal_serdes)
+        return E1000_SUCCESS;
+
+    switch(hw->mac_type) {
+    case em_82545_rev_3:
+    case em_82546_rev_3:
+        break;
+    default:
+        return E1000_SUCCESS;
+    }
+
+    ret_val = em_read_eeprom(hw, EEPROM_SERDES_AMPLITUDE, 1, &eeprom_data);
+    if (ret_val) {
+        return ret_val;
+    }
+
+    if(eeprom_data != EEPROM_RESERVED_WORD) {
+        /* Adjust SERDES output amplitude only. */
+        eeprom_data &= EEPROM_SERDES_AMPLITUDE_MASK; 
+        ret_val = em_write_phy_reg(hw, M88E1000_PHY_EXT_CTRL, eeprom_data);
+        if(ret_val)
+            return ret_val;
+    }
+
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Configures flow control and link settings.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Determines which flow control settings to use. Calls the apropriate media-
+ * specific link configuration function. Configures the flow control settings.
+ * Assuming the adapter has a valid link partner, a valid link should be
+ * established. Assumes the hardware has previously been reset and the
+ * transmitter and receiver are not enabled.
+ *****************************************************************************/
+int32_t
+em_setup_link(struct em_hw *hw)
+{
+    uint32_t ctrl_ext;
+    int32_t ret_val;
+    uint16_t eeprom_data;
+
+    DEBUGFUNC("em_setup_link");
+
+    /* Read and store word 0x0F of the EEPROM. This word contains bits
+     * that determine the hardware's default PAUSE (flow control) mode,
+     * a bit that determines whether the HW defaults to enabling or
+     * disabling auto-negotiation, and the direction of the
+     * SW defined pins. If there is no SW over-ride of the flow
+     * control setting, then the variable hw->fc will
+     * be initialized based on a value in the EEPROM.
+     */
+    if(em_read_eeprom(hw, EEPROM_INIT_CONTROL2_REG, 1, &eeprom_data)) {
+        DEBUGOUT("EEPROM Read Error\n");
+        return -E1000_ERR_EEPROM;
+    }
+
+    if(hw->fc == em_fc_default) {
+        if((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) == 0)
+            hw->fc = em_fc_none;
+        else if((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) ==
+                EEPROM_WORD0F_ASM_DIR)
+            hw->fc = em_fc_tx_pause;
+        else
+            hw->fc = em_fc_full;
+    }
+
+    /* We want to save off the original Flow Control configuration just
+     * in case we get disconnected and then reconnected into a different
+     * hub or switch with different Flow Control capabilities.
+     */
+    if(hw->mac_type == em_82542_rev2_0)
+        hw->fc &= (~em_fc_tx_pause);
+
+    if((hw->mac_type < em_82543) && (hw->report_tx_early == 1))
+        hw->fc &= (~em_fc_rx_pause);
+
+    hw->original_fc = hw->fc;
+
+    DEBUGOUT1("After fix-ups FlowControl is now = %x\n", hw->fc);
+
+    /* Take the 4 bits from EEPROM word 0x0F that determine the initial
+     * polarity value for the SW controlled pins, and setup the
+     * Extended Device Control reg with that info.
+     * This is needed because one of the SW controlled pins is used for
+     * signal detection.  So this should be done before em_setup_pcs_link()
+     * or em_phy_setup() is called.
+     */
+    if(hw->mac_type == em_82543) {
+        ctrl_ext = ((eeprom_data & EEPROM_WORD0F_SWPDIO_EXT) <<
+                    SWDPIO__EXT_SHIFT);
+        E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+    }
+
+    /* Call the necessary subroutine to configure the link. */
+    ret_val = (hw->media_type == em_media_type_copper) ?
+              em_setup_copper_link(hw) :
+              em_setup_fiber_serdes_link(hw);
+
+    /* Initialize the flow control address, type, and PAUSE timer
+     * registers to their default values.  This is done even if flow
+     * control is disabled, because it does not hurt anything to
+     * initialize these registers.
+     */
+    DEBUGOUT("Initializing the Flow Control address, type and timer regs\n");
+
+    E1000_WRITE_REG(hw, FCAL, FLOW_CONTROL_ADDRESS_LOW);
+    E1000_WRITE_REG(hw, FCAH, FLOW_CONTROL_ADDRESS_HIGH);
+    E1000_WRITE_REG(hw, FCT, FLOW_CONTROL_TYPE);
+
+    E1000_WRITE_REG(hw, FCTTV, hw->fc_pause_time);
+
+    /* Set the flow control receive threshold registers.  Normally,
+     * these registers will be set to a default threshold that may be
+     * adjusted later by the driver's runtime code.  However, if the
+     * ability to transmit pause frames in not enabled, then these
+     * registers will be set to 0.
+     */
+    if(!(hw->fc & em_fc_tx_pause)) {
+        E1000_WRITE_REG(hw, FCRTL, 0);
+        E1000_WRITE_REG(hw, FCRTH, 0);
+    } else {
+        /* We need to set up the Receive Threshold high and low water marks
+         * as well as (optionally) enabling the transmission of XON frames.
+         */
+        if(hw->fc_send_xon) {
+            E1000_WRITE_REG(hw, FCRTL, (hw->fc_low_water | E1000_FCRTL_XONE));
+            E1000_WRITE_REG(hw, FCRTH, hw->fc_high_water);
+        } else {
+            E1000_WRITE_REG(hw, FCRTL, hw->fc_low_water);
+            E1000_WRITE_REG(hw, FCRTH, hw->fc_high_water);
+        }
+    }
+    return ret_val;
+}
+
+/******************************************************************************
+ * Sets up link for a fiber based or serdes based adapter
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Manipulates Physical Coding Sublayer functions in order to configure
+ * link. Assumes the hardware has been previously reset and the transmitter
+ * and receiver are not enabled.
+ *****************************************************************************/
+static int32_t
+em_setup_fiber_serdes_link(struct em_hw *hw)
+{
+    uint32_t ctrl;
+    uint32_t status;
+    uint32_t txcw = 0;
+    uint32_t i;
+    uint32_t signal = 0;
+    int32_t ret_val;
+
+    DEBUGFUNC("em_setup_fiber_serdes_link");
+
+    /* On adapters with a MAC newer than 82544, SW Defineable pin 1 will be
+     * set when the optics detect a signal. On older adapters, it will be
+     * cleared when there is a signal.  This applies to fiber media only.
+     * If we're on serdes media, adjust the output amplitude to value set in
+     * the EEPROM.
+     */
+    ctrl = E1000_READ_REG(hw, CTRL);
+    if(hw->media_type == em_media_type_fiber)
+        signal = (hw->mac_type > em_82544) ? E1000_CTRL_SWDPIN1 : 0;
+
+    ret_val = em_adjust_serdes_amplitude(hw);
+    if(ret_val)
+        return ret_val;
+
+    /* Take the link out of reset */
+    ctrl &= ~(E1000_CTRL_LRST);
+
+    /* Adjust VCO speed to improve BER performance */
+    ret_val = em_set_vco_speed(hw);
+    if(ret_val)
+        return ret_val;
+
+    em_config_collision_dist(hw);
+
+    /* Check for a software override of the flow control settings, and setup
+     * the device accordingly.  If auto-negotiation is enabled, then software
+     * will have to set the "PAUSE" bits to the correct value in the Tranmsit
+     * Config Word Register (TXCW) and re-start auto-negotiation.  However, if
+     * auto-negotiation is disabled, then software will have to manually
+     * configure the two flow control enable bits in the CTRL register.
+     *
+     * The possible values of the "fc" parameter are:
+     *      0:  Flow control is completely disabled
+     *      1:  Rx flow control is enabled (we can receive pause frames, but
+     *          not send pause frames).
+     *      2:  Tx flow control is enabled (we can send pause frames but we do
+     *          not support receiving pause frames).
+     *      3:  Both Rx and TX flow control (symmetric) are enabled.
+     */
+    switch (hw->fc) {
+    case em_fc_none:
+        /* Flow control is completely disabled by a software over-ride. */
+        txcw = (E1000_TXCW_ANE | E1000_TXCW_FD);
+        break;
+    case em_fc_rx_pause:
+        /* RX Flow control is enabled and TX Flow control is disabled by a
+         * software over-ride. Since there really isn't a way to advertise
+         * that we are capable of RX Pause ONLY, we will advertise that we
+         * support both symmetric and asymmetric RX PAUSE. Later, we will
+         *  disable the adapter's ability to send PAUSE frames.
+         */
+        txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
+        break;
+    case em_fc_tx_pause:
+        /* TX Flow control is enabled, and RX Flow control is disabled, by a
+         * software over-ride.
+         */
+        txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_ASM_DIR);
+        break;
+    case em_fc_full:
+        /* Flow control (both RX and TX) is enabled by a software over-ride. */
+        txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
+        break;
+    default:
+        DEBUGOUT("Flow control param set incorrectly\n");
+        return -E1000_ERR_CONFIG;
+        break;
+    }
+
+    /* Since auto-negotiation is enabled, take the link out of reset (the link
+     * will be in reset, because we previously reset the chip). This will
+     * restart auto-negotiation.  If auto-neogtiation is successful then the
+     * link-up status bit will be set and the flow control enable bits (RFCE
+     * and TFCE) will be set according to their negotiated value.
+     */
+    DEBUGOUT("Auto-negotiation enabled\n");
+
+    E1000_WRITE_REG(hw, TXCW, txcw);
+    E1000_WRITE_REG(hw, CTRL, ctrl);
+    E1000_WRITE_FLUSH(hw);
+
+    hw->txcw = txcw;
+    msec_delay(1);
+
+    /* If we have a signal (the cable is plugged in) then poll for a "Link-Up"
+     * indication in the Device Status Register.  Time-out if a link isn't
+     * seen in 500 milliseconds seconds (Auto-negotiation should complete in
+     * less than 500 milliseconds even if the other end is doing it in SW).
+     * For internal serdes, we just assume a signal is present, then poll.
+     */
+    if(hw->media_type == em_media_type_internal_serdes ||
+       (E1000_READ_REG(hw, CTRL) & E1000_CTRL_SWDPIN1) == signal) {
+        DEBUGOUT("Looking for Link\n");
+        for(i = 0; i < (LINK_UP_TIMEOUT / 10); i++) {
+            msec_delay(10);
+            status = E1000_READ_REG(hw, STATUS);
+            if(status & E1000_STATUS_LU) break;
+        }
+        if(i == (LINK_UP_TIMEOUT / 10)) {
+            DEBUGOUT("Never got a valid link from auto-neg!!!\n");
+            hw->autoneg_failed = 1;
+            /* AutoNeg failed to achieve a link, so we'll call
+             * em_check_for_link. This routine will force the link up if
+             * we detect a signal. This will allow us to communicate with
+             * non-autonegotiating link partners.
+             */
+            ret_val = em_check_for_link(hw);
+            if(ret_val) {
+                DEBUGOUT("Error while checking for link\n");
+                return ret_val;
+            }
+            hw->autoneg_failed = 0;
+        } else {
+            hw->autoneg_failed = 0;
+            DEBUGOUT("Valid Link Found\n");
+        }
+    } else {
+        DEBUGOUT("No Signal Detected\n");
+    }
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
+* Make sure we have a valid PHY and change PHY mode before link setup.
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+static int32_t
+em_copper_link_preconfig(struct em_hw *hw)
+{
+    uint32_t ctrl;
+    int32_t ret_val;
+    uint16_t phy_data;
+
+    DEBUGFUNC("em_copper_link_preconfig");
+
+    ctrl = E1000_READ_REG(hw, CTRL);
+    /* With 82543, we need to force speed and duplex on the MAC equal to what
+     * the PHY speed and duplex configuration is. In addition, we need to
+     * perform a hardware reset on the PHY to take it out of reset.
+     */
+    if(hw->mac_type > em_82543) {
+        ctrl |= E1000_CTRL_SLU;
+        ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+        E1000_WRITE_REG(hw, CTRL, ctrl);
+    } else {
+        ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX | E1000_CTRL_SLU);
+        E1000_WRITE_REG(hw, CTRL, ctrl);
+        ret_val = em_phy_hw_reset(hw);
+        if(ret_val)
+            return ret_val;
+    }
+
+    /* Make sure we have a valid PHY */
+    ret_val = em_detect_gig_phy(hw);
+    if(ret_val) {
+        DEBUGOUT("Error, did not detect valid phy.\n");
+        return ret_val;
+    }
+    DEBUGOUT1("Phy ID = %x \n", hw->phy_id);
+
+    /* Set PHY to class A mode (if necessary) */
+    ret_val = em_set_phy_mode(hw);
+    if(ret_val)
+        return ret_val;
+
+    if((hw->mac_type == em_82545_rev_3) ||
+       (hw->mac_type == em_82546_rev_3)) {
+        ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+        phy_data |= 0x00000008;
+        ret_val = em_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+    }
+
+    if(hw->mac_type <= em_82543 ||
+       hw->mac_type == em_82541 || hw->mac_type == em_82547 ||
+       hw->mac_type == em_82541_rev_2 || hw->mac_type == em_82547_rev_2)
+        hw->phy_reset_disable = FALSE;
+
+   return E1000_SUCCESS;
+}
+
+
+/********************************************************************
+* Copper link setup for em_phy_igp series.
+*
+* hw - Struct containing variables accessed by shared code
+*********************************************************************/
+static int32_t
+em_copper_link_igp_setup(struct em_hw *hw)
+{
+    uint32_t led_ctrl;
+    int32_t ret_val;
+    uint16_t phy_data;
+
+    DEBUGFUNC("em_copper_link_igp_setup");
+
+    if (hw->phy_reset_disable)
+        return E1000_SUCCESS;
+    
+    ret_val = em_phy_reset(hw);
+    if (ret_val) {
+        DEBUGOUT("Error Resetting the PHY\n");
+        return ret_val;
+    }
+
+    /* Wait 10ms for MAC to configure PHY from eeprom settings */
+    msec_delay(15);
+
+    /* Configure activity LED after PHY reset */
+    led_ctrl = E1000_READ_REG(hw, LEDCTL);
+    led_ctrl &= IGP_ACTIVITY_LED_MASK;
+    led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
+    E1000_WRITE_REG(hw, LEDCTL, led_ctrl);
+
+    /* disable lplu d3 during driver init */
+    ret_val = em_set_d3_lplu_state(hw, FALSE);
+    if (ret_val) {
+        DEBUGOUT("Error Disabling LPLU D3\n");
+        return ret_val;
+    }
+
+    /* disable lplu d0 during driver init */
+    ret_val = em_set_d0_lplu_state(hw, FALSE);
+    if (ret_val) {
+        DEBUGOUT("Error Disabling LPLU D0\n");
+        return ret_val;
+    }
+    /* Configure mdi-mdix settings */
+    ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data);
+    if (ret_val)
+        return ret_val;
+
+    if ((hw->mac_type == em_82541) || (hw->mac_type == em_82547)) {
+        hw->dsp_config_state = em_dsp_config_disabled;
+        /* Force MDI for earlier revs of the IGP PHY */
+        phy_data &= ~(IGP01E1000_PSCR_AUTO_MDIX | IGP01E1000_PSCR_FORCE_MDI_MDIX);
+        hw->mdix = 1;
+
+    } else {
+        hw->dsp_config_state = em_dsp_config_enabled;
+        phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX;
+
+        switch (hw->mdix) {
+        case 1:
+            phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
+            break;
+        case 2:
+            phy_data |= IGP01E1000_PSCR_FORCE_MDI_MDIX;
+            break;
+        case 0:
+        default:
+            phy_data |= IGP01E1000_PSCR_AUTO_MDIX;
+            break;
+        }
+    }
+    ret_val = em_write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data);
+    if(ret_val)
+        return ret_val;
+
+    /* set auto-master slave resolution settings */
+    if(hw->autoneg) {
+        em_ms_type phy_ms_setting = hw->master_slave;
+
+        if(hw->ffe_config_state == em_ffe_config_active)
+            hw->ffe_config_state = em_ffe_config_enabled;
+
+        if(hw->dsp_config_state == em_dsp_config_activated)
+            hw->dsp_config_state = em_dsp_config_enabled;
+
+        /* when autonegotiation advertisment is only 1000Mbps then we
+          * should disable SmartSpeed and enable Auto MasterSlave
+          * resolution as hardware default. */
+        if(hw->autoneg_advertised == ADVERTISE_1000_FULL) {
+            /* Disable SmartSpeed */
+            ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, &phy_data);
+            if(ret_val)
+                return ret_val;
+            phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+            ret_val = em_write_phy_reg(hw,
+                                                  IGP01E1000_PHY_PORT_CONFIG,
+                                                  phy_data);
+            if(ret_val)
+                return ret_val;
+            /* Set auto Master/Slave resolution process */
+            ret_val = em_read_phy_reg(hw, PHY_1000T_CTRL, &phy_data);
+            if(ret_val)
+                return ret_val;
+            phy_data &= ~CR_1000T_MS_ENABLE;
+            ret_val = em_write_phy_reg(hw, PHY_1000T_CTRL, phy_data);
+            if(ret_val)
+                return ret_val;
+        }
+
+        ret_val = em_read_phy_reg(hw, PHY_1000T_CTRL, &phy_data);
+        if(ret_val)
+            return ret_val;
+
+        /* load defaults for future use */
+        hw->original_master_slave = (phy_data & CR_1000T_MS_ENABLE) ?
+                                        ((phy_data & CR_1000T_MS_VALUE) ?
+                                         em_ms_force_master :
+                                         em_ms_force_slave) :
+                                         em_ms_auto;
+
+        switch (phy_ms_setting) {
+        case em_ms_force_master:
+            phy_data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE);
+            break;
+        case em_ms_force_slave:
+            phy_data |= CR_1000T_MS_ENABLE;
+            phy_data &= ~(CR_1000T_MS_VALUE);
+            break;
+        case em_ms_auto:
+            phy_data &= ~CR_1000T_MS_ENABLE;
+            default:
+            break;
+        }
+        ret_val = em_write_phy_reg(hw, PHY_1000T_CTRL, phy_data);
+        if(ret_val)
+            return ret_val;
+        }
+
+   return E1000_SUCCESS;
+}
+
+
+/********************************************************************
+* Copper link setup for em_phy_m88 series.
+*
+* hw - Struct containing variables accessed by shared code
+*********************************************************************/
+static int32_t
+em_copper_link_mgp_setup(struct em_hw *hw)
+{
+    int32_t ret_val;
+    uint16_t phy_data;
+
+    DEBUGFUNC("em_copper_link_mgp_setup");
+
+    if(hw->phy_reset_disable)
+        return E1000_SUCCESS;
+    
+    /* Enable CRS on TX. This must be set for half-duplex operation. */
+    ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+    if(ret_val)
+        return ret_val;
+
+    phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+
+    /* Options:
+     *   MDI/MDI-X = 0 (default)
+     *   0 - Auto for all speeds
+     *   1 - MDI mode
+     *   2 - MDI-X mode
+     *   3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
+     */
+    phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
+
+    switch (hw->mdix) {
+    case 1:
+        phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE;
+        break;
+    case 2:
+        phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE;
+        break;
+    case 3:
+        phy_data |= M88E1000_PSCR_AUTO_X_1000T;
+        break;
+    case 0:
+    default:
+        phy_data |= M88E1000_PSCR_AUTO_X_MODE;
+        break;
+    }
+
+    /* Options:
+     *   disable_polarity_correction = 0 (default)
+     *       Automatic Correction for Reversed Cable Polarity
+     *   0 - Disabled
+     *   1 - Enabled
+     */
+    phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
+    if(hw->disable_polarity_correction == 1)
+        phy_data |= M88E1000_PSCR_POLARITY_REVERSAL;
+        ret_val = em_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+        if(ret_val)
+            return ret_val;
+
+    /* Force TX_CLK in the Extended PHY Specific Control Register
+     * to 25MHz clock.
+     */
+    ret_val = em_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data);
+    if(ret_val)
+        return ret_val;
+
+    phy_data |= M88E1000_EPSCR_TX_CLK_25;
+
+    if (hw->phy_revision < M88E1011_I_REV_4) {
+        /* Configure Master and Slave downshift values */
+        phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK |
+                              M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK);
+        phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X |
+                             M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X);
+        ret_val = em_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
+        if(ret_val)
+            return ret_val;
+    }
+
+    /* SW Reset the PHY so all changes take effect */
+    ret_val = em_phy_reset(hw);
+    if(ret_val) {
+        DEBUGOUT("Error Resetting the PHY\n");
+        return ret_val;
+    }
+
+   return E1000_SUCCESS;
+}
+
+/********************************************************************
+* Setup auto-negotiation and flow control advertisements,
+* and then perform auto-negotiation.
+*
+* hw - Struct containing variables accessed by shared code
+*********************************************************************/
+static int32_t
+em_copper_link_autoneg(struct em_hw *hw)
+{
+    int32_t ret_val;
+    uint16_t phy_data;
+
+    DEBUGFUNC("em_copper_link_autoneg");
+
+    /* Perform some bounds checking on the hw->autoneg_advertised
+     * parameter.  If this variable is zero, then set it to the default.
+     */
+    hw->autoneg_advertised &= AUTONEG_ADVERTISE_SPEED_DEFAULT;
+
+    /* If autoneg_advertised is zero, we assume it was not defaulted
+     * by the calling code so we set to advertise full capability.
+     */
+    if(hw->autoneg_advertised == 0)
+        hw->autoneg_advertised = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+
+    DEBUGOUT("Reconfiguring auto-neg advertisement params\n");
+    ret_val = em_phy_setup_autoneg(hw);
+    if(ret_val) {
+        DEBUGOUT("Error Setting up Auto-Negotiation\n");
+        return ret_val;
+    }
+    DEBUGOUT("Restarting Auto-Neg\n");
+
+    /* Restart auto-negotiation by setting the Auto Neg Enable bit and
+     * the Auto Neg Restart bit in the PHY control register.
+     */
+    ret_val = em_read_phy_reg(hw, PHY_CTRL, &phy_data);
+    if(ret_val)
+        return ret_val;
+
+    phy_data |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
+    ret_val = em_write_phy_reg(hw, PHY_CTRL, phy_data);
+    if(ret_val)
+        return ret_val;
+
+    /* Does the user want to wait for Auto-Neg to complete here, or
+     * check at a later time (for example, callback routine).
+     */
+    if(hw->wait_autoneg_complete) {
+        ret_val = em_wait_autoneg(hw);
+        if(ret_val) {
+            DEBUGOUT("Error while waiting for autoneg to complete\n");
+            return ret_val;
+        }
+    }
+
+    hw->get_link_status = TRUE;
+
+    return E1000_SUCCESS;
+}
+
+
+/******************************************************************************
+* Config the MAC and the PHY after link is up.
+*   1) Set up the MAC to the current PHY speed/duplex
+*      if we are on 82543.  If we
+*      are on newer silicon, we only need to configure
+*      collision distance in the Transmit Control Register.
+*   2) Set up flow control on the MAC to that established with
+*      the link partner.
+*   3) Config DSP to improve Gigabit link quality for some PHY revisions.    
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+static int32_t
+em_copper_link_postconfig(struct em_hw *hw)
+{
+    int32_t ret_val;
+    DEBUGFUNC("em_copper_link_postconfig");
+    
+    if(hw->mac_type >= em_82544) {
+        em_config_collision_dist(hw);
+    } else {
+        ret_val = em_config_mac_to_phy(hw);
+        if(ret_val) {
+            DEBUGOUT("Error configuring MAC to PHY settings\n");
+            return ret_val;
+        }
+    }
+    ret_val = em_config_fc_after_link_up(hw);
+    if(ret_val) {
+        DEBUGOUT("Error Configuring Flow Control\n");
+        return ret_val;
+    }
+
+    /* Config DSP to improve Giga link quality */
+    if(hw->phy_type == em_phy_igp) {
+        ret_val = em_config_dsp_after_link_change(hw, TRUE);
+        if(ret_val) {
+            DEBUGOUT("Error Configuring DSP after link up\n");
+            return ret_val;
+        }
+    }
+                
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
+* Detects which PHY is present and setup the speed and duplex
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+static int32_t
+em_setup_copper_link(struct em_hw *hw)
+{
+    int32_t ret_val;
+    uint16_t i;
+    uint16_t phy_data;
+
+    DEBUGFUNC("em_setup_copper_link");
+
+    /* Check if it is a valid PHY and set PHY mode if necessary. */
+    ret_val = em_copper_link_preconfig(hw);
+    if(ret_val)
+        return ret_val;
+
+    if (hw->phy_type == em_phy_igp ||
+        hw->phy_type == em_phy_igp_2) {
+        ret_val = em_copper_link_igp_setup(hw);
+        if(ret_val)
+            return ret_val;
+    } else if (hw->phy_type == em_phy_m88) {
+        ret_val = em_copper_link_mgp_setup(hw);
+        if(ret_val)
+            return ret_val;
+    }
+
+    if(hw->autoneg) {
+        /* Setup autoneg and flow control advertisement 
+          * and perform autonegotiation */   
+        ret_val = em_copper_link_autoneg(hw);
+        if(ret_val)
+            return ret_val;           
+    } else {
+        /* PHY will be set to 10H, 10F, 100H,or 100F
+          * depending on value from forced_speed_duplex. */
+        DEBUGOUT("Forcing speed and duplex\n");
+        ret_val = em_phy_force_speed_duplex(hw);
+        if(ret_val) {
+            DEBUGOUT("Error Forcing Speed and Duplex\n");
+            return ret_val;
+        }
+    }
+
+    /* Check link status. Wait up to 100 microseconds for link to become
+     * valid.
+     */
+    for(i = 0; i < 10; i++) {
+        ret_val = em_read_phy_reg(hw, PHY_STATUS, &phy_data);
+        if(ret_val)
+            return ret_val;
+        ret_val = em_read_phy_reg(hw, PHY_STATUS, &phy_data);
+        if(ret_val)
+            return ret_val;
+
+        if(phy_data & MII_SR_LINK_STATUS) {
+            /* Config the MAC and PHY after link is up */
+            ret_val = em_copper_link_postconfig(hw);
+            if(ret_val)
+                return ret_val;
+            
+            DEBUGOUT("Valid link established!!!\n");
+            return E1000_SUCCESS;
+        }
+        usec_delay(10);
+    }
+
+    DEBUGOUT("Unable to establish link!!!\n");
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
+* Configures PHY autoneg and flow control advertisement settings
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+int32_t
+em_phy_setup_autoneg(struct em_hw *hw)
+{
+    int32_t ret_val;
+    uint16_t mii_autoneg_adv_reg;
+    uint16_t mii_1000t_ctrl_reg;
+
+    DEBUGFUNC("em_phy_setup_autoneg");
+
+    /* Read the MII Auto-Neg Advertisement Register (Address 4). */
+    ret_val = em_read_phy_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg);
+    if(ret_val)
+        return ret_val;
+
+        /* Read the MII 1000Base-T Control Register (Address 9). */
+        ret_val = em_read_phy_reg(hw, PHY_1000T_CTRL, &mii_1000t_ctrl_reg);
+        if(ret_val)
+            return ret_val;
+
+    /* Need to parse both autoneg_advertised and fc and set up
+     * the appropriate PHY registers.  First we will parse for
+     * autoneg_advertised software override.  Since we can advertise
+     * a plethora of combinations, we need to check each bit
+     * individually.
+     */
+
+    /* First we clear all the 10/100 mb speed bits in the Auto-Neg
+     * Advertisement Register (Address 4) and the 1000 mb speed bits in
+     * the  1000Base-T Control Register (Address 9).
+     */
+    mii_autoneg_adv_reg &= ~REG4_SPEED_MASK;
+    mii_1000t_ctrl_reg &= ~REG9_SPEED_MASK;
+
+    DEBUGOUT1("autoneg_advertised %x\n", hw->autoneg_advertised);
+
+    /* Do we want to advertise 10 Mb Half Duplex? */
+    if(hw->autoneg_advertised & ADVERTISE_10_HALF) {
+        DEBUGOUT("Advertise 10mb Half duplex\n");
+        mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS;
+    }
+
+    /* Do we want to advertise 10 Mb Full Duplex? */
+    if(hw->autoneg_advertised & ADVERTISE_10_FULL) {
+        DEBUGOUT("Advertise 10mb Full duplex\n");
+        mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS;
+    }
+
+    /* Do we want to advertise 100 Mb Half Duplex? */
+    if(hw->autoneg_advertised & ADVERTISE_100_HALF) {
+        DEBUGOUT("Advertise 100mb Half duplex\n");
+        mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS;
+    }
+
+    /* Do we want to advertise 100 Mb Full Duplex? */
+    if(hw->autoneg_advertised & ADVERTISE_100_FULL) {
+        DEBUGOUT("Advertise 100mb Full duplex\n");
+        mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS;
+    }
+
+    /* We do not allow the Phy to advertise 1000 Mb Half Duplex */
+    if(hw->autoneg_advertised & ADVERTISE_1000_HALF) {
+        DEBUGOUT("Advertise 1000mb Half duplex requested, request denied!\n");
+    }
+
+    /* Do we want to advertise 1000 Mb Full Duplex? */
+    if(hw->autoneg_advertised & ADVERTISE_1000_FULL) {
+        DEBUGOUT("Advertise 1000mb Full duplex\n");
+        mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS;
+    }
+
+    /* Check for a software override of the flow control settings, and
+     * setup the PHY advertisement registers accordingly.  If
+     * auto-negotiation is enabled, then software will have to set the
+     * "PAUSE" bits to the correct value in the Auto-Negotiation
+     * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto-negotiation.
+     *
+     * The possible values of the "fc" parameter are:
+     *      0:  Flow control is completely disabled
+     *      1:  Rx flow control is enabled (we can receive pause frames
+     *          but not send pause frames).
+     *      2:  Tx flow control is enabled (we can send pause frames
+     *          but we do not support receiving pause frames).
+     *      3:  Both Rx and TX flow control (symmetric) are enabled.
+     *  other:  No software override.  The flow control configuration
+     *          in the EEPROM is used.
+     */
+    switch (hw->fc) {
+    case em_fc_none: /* 0 */
+        /* Flow control (RX & TX) is completely disabled by a
+         * software over-ride.
+         */
+        mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+        break;
+    case em_fc_rx_pause: /* 1 */
+        /* RX Flow control is enabled, and TX Flow control is
+         * disabled, by a software over-ride.
+         */
+        /* Since there really isn't a way to advertise that we are
+         * capable of RX Pause ONLY, we will advertise that we
+         * support both symmetric and asymmetric RX PAUSE.  Later
+         * (in em_config_fc_after_link_up) we will disable the
+         *hw's ability to send PAUSE frames.
+         */
+        mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+        break;
+    case em_fc_tx_pause: /* 2 */
+        /* TX Flow control is enabled, and RX Flow control is
+         * disabled, by a software over-ride.
+         */
+        mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR;
+        mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE;
+        break;
+    case em_fc_full: /* 3 */
+        /* Flow control (both RX and TX) is enabled by a software
+         * over-ride.
+         */
+        mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+        break;
+    default:
+        DEBUGOUT("Flow control param set incorrectly\n");
+        return -E1000_ERR_CONFIG;
+    }
+
+    ret_val = em_write_phy_reg(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg);
+    if(ret_val)
+        return ret_val;
+
+    DEBUGOUT1("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
+
+    ret_val = em_write_phy_reg(hw, PHY_1000T_CTRL, mii_1000t_ctrl_reg);    
+    if(ret_val)
+        return ret_val;
+
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
+* Force PHY speed and duplex settings to hw->forced_speed_duplex
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+static int32_t
+em_phy_force_speed_duplex(struct em_hw *hw)
+{
+    uint32_t ctrl;
+    int32_t ret_val;
+    uint16_t mii_ctrl_reg;
+    uint16_t mii_status_reg;
+    uint16_t phy_data;
+    uint16_t i;
+
+    DEBUGFUNC("em_phy_force_speed_duplex");
+
+    /* Turn off Flow control if we are forcing speed and duplex. */
+    hw->fc = em_fc_none;
+
+    DEBUGOUT1("hw->fc = %d\n", hw->fc);
+
+    /* Read the Device Control Register. */
+    ctrl = E1000_READ_REG(hw, CTRL);
+
+    /* Set the bits to Force Speed and Duplex in the Device Ctrl Reg. */
+    ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+    ctrl &= ~(DEVICE_SPEED_MASK);
+
+    /* Clear the Auto Speed Detect Enable bit. */
+    ctrl &= ~E1000_CTRL_ASDE;
+
+    /* Read the MII Control Register. */
+    ret_val = em_read_phy_reg(hw, PHY_CTRL, &mii_ctrl_reg);
+    if(ret_val)
+        return ret_val;
+
+    /* We need to disable autoneg in order to force link and duplex. */
+
+    mii_ctrl_reg &= ~MII_CR_AUTO_NEG_EN;
+
+    /* Are we forcing Full or Half Duplex? */
+    if(hw->forced_speed_duplex == em_100_full ||
+       hw->forced_speed_duplex == em_10_full) {
+        /* We want to force full duplex so we SET the full duplex bits in the
+         * Device and MII Control Registers.
+         */
+        ctrl |= E1000_CTRL_FD;
+        mii_ctrl_reg |= MII_CR_FULL_DUPLEX;
+        DEBUGOUT("Full Duplex\n");
+    } else {
+        /* We want to force half duplex so we CLEAR the full duplex bits in
+         * the Device and MII Control Registers.
+         */
+        ctrl &= ~E1000_CTRL_FD;
+        mii_ctrl_reg &= ~MII_CR_FULL_DUPLEX;
+        DEBUGOUT("Half Duplex\n");
+    }
+
+    /* Are we forcing 100Mbps??? */
+    if(hw->forced_speed_duplex == em_100_full ||
+       hw->forced_speed_duplex == em_100_half) {
+        /* Set the 100Mb bit and turn off the 1000Mb and 10Mb bits. */
+        ctrl |= E1000_CTRL_SPD_100;
+        mii_ctrl_reg |= MII_CR_SPEED_100;
+        mii_ctrl_reg &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_10);
+        DEBUGOUT("Forcing 100mb ");
+    } else {
+        /* Set the 10Mb bit and turn off the 1000Mb and 100Mb bits. */
+        ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
+        mii_ctrl_reg |= MII_CR_SPEED_10;
+        mii_ctrl_reg &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100);
+        DEBUGOUT("Forcing 10mb ");
+    }
+
+    em_config_collision_dist(hw);
+
+    /* Write the configured values back to the Device Control Reg. */
+    E1000_WRITE_REG(hw, CTRL, ctrl);
+
+    if (hw->phy_type == em_phy_m88) {
+        ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+        if(ret_val)
+            return ret_val;
+
+        /* Clear Auto-Crossover to force MDI manually. M88E1000 requires MDI
+         * forced whenever speed are duplex are forced.
+         */
+        phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
+        ret_val = em_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+        if(ret_val)
+            return ret_val;
+
+        DEBUGOUT1("M88E1000 PSCR: %x \n", phy_data);
+
+        /* Need to reset the PHY or these changes will be ignored */
+        mii_ctrl_reg |= MII_CR_RESET;
+    } else {
+        /* Clear Auto-Crossover to force MDI manually.  IGP requires MDI
+         * forced whenever speed or duplex are forced.
+         */
+        ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data);
+        if(ret_val)
+            return ret_val;
+
+        phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX;
+        phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
+
+        ret_val = em_write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data);
+        if(ret_val)
+            return ret_val;
+    }
+
+    /* Write back the modified PHY MII control register. */
+    ret_val = em_write_phy_reg(hw, PHY_CTRL, mii_ctrl_reg);
+    if(ret_val)
+        return ret_val;
+
+    usec_delay(1);
+
+    /* The wait_autoneg_complete flag may be a little misleading here.
+     * Since we are forcing speed and duplex, Auto-Neg is not enabled.
+     * But we do want to delay for a period while forcing only so we
+     * don't generate false No Link messages.  So we will wait here
+     * only if the user has set wait_autoneg_complete to 1, which is
+     * the default.
+     */
+    if(hw->wait_autoneg_complete) {
+        /* We will wait for autoneg to complete. */
+        DEBUGOUT("Waiting for forced speed/duplex link.\n");
+        mii_status_reg = 0;
+
+        /* We will wait for autoneg to complete or 4.5 seconds to expire. */
+        for(i = PHY_FORCE_TIME; i > 0; i--) {
+            /* Read the MII Status Register and wait for Auto-Neg Complete bit
+             * to be set.
+             */
+            ret_val = em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+            if(ret_val)
+                return ret_val;
+
+            ret_val = em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+            if(ret_val)
+                return ret_val;
+
+            if(mii_status_reg & MII_SR_LINK_STATUS) break;
+            msec_delay(100);
+        }
+        if((i == 0) &&
+           (hw->phy_type == em_phy_m88)) {
+            /* We didn't get link.  Reset the DSP and wait again for link. */
+            ret_val = em_phy_reset_dsp(hw);
+            if(ret_val) {
+                DEBUGOUT("Error Resetting PHY DSP\n");
+                return ret_val;
+            }
+        }
+        /* This loop will early-out if the link condition has been met.  */
+        for(i = PHY_FORCE_TIME; i > 0; i--) {
+            if(mii_status_reg & MII_SR_LINK_STATUS) break;
+            msec_delay(100);
+            /* Read the MII Status Register and wait for Auto-Neg Complete bit
+             * to be set.
+             */
+            ret_val = em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+            if(ret_val)
+                return ret_val;
+
+            ret_val = em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+            if(ret_val)
+                return ret_val;
+        }
+    }
+
+    if (hw->phy_type == em_phy_m88) {
+        /* Because we reset the PHY above, we need to re-force TX_CLK in the
+         * Extended PHY Specific Control Register to 25MHz clock.  This value
+         * defaults back to a 2.5MHz clock when the PHY is reset.
+         */
+        ret_val = em_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data);
+        if(ret_val)
+            return ret_val;
+
+        phy_data |= M88E1000_EPSCR_TX_CLK_25;
+        ret_val = em_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
+        if(ret_val)
+            return ret_val;
+
+        /* In addition, because of the s/w reset above, we need to enable CRS on
+         * TX.  This must be set for both full and half duplex operation.
+         */
+        ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+        if(ret_val)
+            return ret_val;
+
+        phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+        ret_val = em_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+        if(ret_val)
+            return ret_val;
+
+        if((hw->mac_type == em_82544 || hw->mac_type == em_82543) &&
+           (!hw->autoneg) &&
+           (hw->forced_speed_duplex == em_10_full ||
+            hw->forced_speed_duplex == em_10_half)) {
+            ret_val = em_polarity_reversal_workaround(hw);
+            if(ret_val)
+                return ret_val;
+        }
+    }
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
+* Sets the collision distance in the Transmit Control register
+*
+* hw - Struct containing variables accessed by shared code
+*
+* Link should have been established previously. Reads the speed and duplex
+* information from the Device Status register.
+******************************************************************************/
+void
+em_config_collision_dist(struct em_hw *hw)
+{
+    uint32_t tctl;
+
+    DEBUGFUNC("em_config_collision_dist");
+
+    tctl = E1000_READ_REG(hw, TCTL);
+
+    tctl &= ~E1000_TCTL_COLD;
+    tctl |= E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT;
+
+    E1000_WRITE_REG(hw, TCTL, tctl);
+    E1000_WRITE_FLUSH(hw);
+}
+
+/******************************************************************************
+* Sets MAC speed and duplex settings to reflect the those in the PHY
+*
+* hw - Struct containing variables accessed by shared code
+* mii_reg - data to write to the MII control register
+*
+* The contents of the PHY register containing the needed information need to
+* be passed in.
+******************************************************************************/
+static int32_t
+em_config_mac_to_phy(struct em_hw *hw)
+{
+    uint32_t ctrl;
+    int32_t ret_val;
+    uint16_t phy_data;
+
+    DEBUGFUNC("em_config_mac_to_phy");
+
+    /* 82544 or newer MAC, Auto Speed Detection takes care of 
+    * MAC speed/duplex configuration.*/
+    if (hw->mac_type >= em_82544)
+        return E1000_SUCCESS;
+
+    /* Read the Device Control Register and set the bits to Force Speed
+     * and Duplex.
+     */
+    ctrl = E1000_READ_REG(hw, CTRL);
+    ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+    ctrl &= ~(E1000_CTRL_SPD_SEL | E1000_CTRL_ILOS);
+
+    /* Set up duplex in the Device Control and Transmit Control
+     * registers depending on negotiated values.
+     */
+    ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
+    if(ret_val)
+        return ret_val;
+
+    if(phy_data & M88E1000_PSSR_DPLX) 
+        ctrl |= E1000_CTRL_FD;
+    else 
+        ctrl &= ~E1000_CTRL_FD;
+
+    em_config_collision_dist(hw);
+
+    /* Set up speed in the Device Control register depending on
+     * negotiated values.
+     */
+    if((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS)
+        ctrl |= E1000_CTRL_SPD_1000;
+    else if((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_100MBS)
+        ctrl |= E1000_CTRL_SPD_100;
+
+    /* Write the configured values back to the Device Control Reg. */
+    E1000_WRITE_REG(hw, CTRL, ctrl);
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Forces the MAC's flow control settings.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Sets the TFCE and RFCE bits in the device control register to reflect
+ * the adapter settings. TFCE and RFCE need to be explicitly set by
+ * software when a Copper PHY is used because autonegotiation is managed
+ * by the PHY rather than the MAC. Software must also configure these
+ * bits when link is forced on a fiber connection.
+ *****************************************************************************/
+int32_t
+em_force_mac_fc(struct em_hw *hw)
+{
+    uint32_t ctrl;
+
+    DEBUGFUNC("em_force_mac_fc");
+
+    /* Get the current configuration of the Device Control Register */
+    ctrl = E1000_READ_REG(hw, CTRL);
+
+    /* Because we didn't get link via the internal auto-negotiation
+     * mechanism (we either forced link or we got link via PHY
+     * auto-neg), we have to manually enable/disable transmit an
+     * receive flow control.
+     *
+     * The "Case" statement below enables/disable flow control
+     * according to the "hw->fc" parameter.
+     *
+     * The possible values of the "fc" parameter are:
+     *      0:  Flow control is completely disabled
+     *      1:  Rx flow control is enabled (we can receive pause
+     *          frames but not send pause frames).
+     *      2:  Tx flow control is enabled (we can send pause frames
+     *          frames but we do not receive pause frames).
+     *      3:  Both Rx and TX flow control (symmetric) is enabled.
+     *  other:  No other values should be possible at this point.
+     */
+
+    switch (hw->fc) {
+    case em_fc_none:
+        ctrl &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE));
+        break;
+    case em_fc_rx_pause:
+        ctrl &= (~E1000_CTRL_TFCE);
+        ctrl |= E1000_CTRL_RFCE;
+        break;
+    case em_fc_tx_pause:
+        ctrl &= (~E1000_CTRL_RFCE);
+        ctrl |= E1000_CTRL_TFCE;
+        break;
+    case em_fc_full:
+        ctrl |= (E1000_CTRL_TFCE | E1000_CTRL_RFCE);
+        break;
+    default:
+        DEBUGOUT("Flow control param set incorrectly\n");
+        return -E1000_ERR_CONFIG;
+    }
+
+    /* Disable TX Flow Control for 82542 (rev 2.0) */
+    if(hw->mac_type == em_82542_rev2_0)
+        ctrl &= (~E1000_CTRL_TFCE);
+
+    E1000_WRITE_REG(hw, CTRL, ctrl);
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Configures flow control settings after link is established
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Should be called immediately after a valid link has been established.
+ * Forces MAC flow control settings if link was forced. When in MII/GMII mode
+ * and autonegotiation is enabled, the MAC flow control settings will be set
+ * based on the flow control negotiated by the PHY. In TBI mode, the TFCE
+ * and RFCE bits will be automaticaly set to the negotiated flow control mode.
+ *****************************************************************************/
+int32_t
+em_config_fc_after_link_up(struct em_hw *hw)
+{
+    int32_t ret_val;
+    uint16_t mii_status_reg;
+    uint16_t mii_nway_adv_reg;
+    uint16_t mii_nway_lp_ability_reg;
+    uint16_t speed;
+    uint16_t duplex;
+
+    DEBUGFUNC("em_config_fc_after_link_up");
+
+    /* Check for the case where we have fiber media and auto-neg failed
+     * so we had to force link.  In this case, we need to force the
+     * configuration of the MAC to match the "fc" parameter.
+     */
+    if(((hw->media_type == em_media_type_fiber) && (hw->autoneg_failed)) ||
+       ((hw->media_type == em_media_type_internal_serdes) && (hw->autoneg_failed)) ||
+       ((hw->media_type == em_media_type_copper) && (!hw->autoneg))) {
+        ret_val = em_force_mac_fc(hw);
+        if(ret_val) {
+            DEBUGOUT("Error forcing flow control settings\n");
+            return ret_val;
+        }
+    }
+
+    /* Check for the case where we have copper media and auto-neg is
+     * enabled.  In this case, we need to check and see if Auto-Neg
+     * has completed, and if so, how the PHY and link partner has
+     * flow control configured.
+     */
+    if((hw->media_type == em_media_type_copper) && hw->autoneg) {
+        /* Read the MII Status Register and check to see if AutoNeg
+         * has completed.  We read this twice because this reg has
+         * some "sticky" (latched) bits.
+         */
+        ret_val = em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+        if(ret_val)
+            return ret_val;
+        ret_val = em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+        if(ret_val)
+            return ret_val;
+
+        if(mii_status_reg & MII_SR_AUTONEG_COMPLETE) {
+            /* The AutoNeg process has completed, so we now need to
+             * read both the Auto Negotiation Advertisement Register
+             * (Address 4) and the Auto_Negotiation Base Page Ability
+             * Register (Address 5) to determine how flow control was
+             * negotiated.
+             */
+            ret_val = em_read_phy_reg(hw, PHY_AUTONEG_ADV,
+                                         &mii_nway_adv_reg);
+            if(ret_val)
+                return ret_val;
+            ret_val = em_read_phy_reg(hw, PHY_LP_ABILITY,
+                                         &mii_nway_lp_ability_reg);
+            if(ret_val)
+                return ret_val;
+
+            /* Two bits in the Auto Negotiation Advertisement Register
+             * (Address 4) and two bits in the Auto Negotiation Base
+             * Page Ability Register (Address 5) determine flow control
+             * for both the PHY and the link partner.  The following
+             * table, taken out of the IEEE 802.3ab/D6.0 dated March 25,
+             * 1999, describes these PAUSE resolution bits and how flow
+             * control is determined based upon these settings.
+             * NOTE:  DC = Don't Care
+             *
+             *   LOCAL DEVICE  |   LINK PARTNER
+             * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution
+             *-------|---------|-------|---------|--------------------
+             *   0   |    0    |  DC   |   DC    | em_fc_none
+             *   0   |    1    |   0   |   DC    | em_fc_none
+             *   0   |    1    |   1   |    0    | em_fc_none
+             *   0   |    1    |   1   |    1    | em_fc_tx_pause
+             *   1   |    0    |   0   |   DC    | em_fc_none
+             *   1   |   DC    |   1   |   DC    | em_fc_full
+             *   1   |    1    |   0   |    0    | em_fc_none
+             *   1   |    1    |   0   |    1    | em_fc_rx_pause
+             *
+             */
+            /* Are both PAUSE bits set to 1?  If so, this implies
+             * Symmetric Flow Control is enabled at both ends.  The
+             * ASM_DIR bits are irrelevant per the spec.
+             *
+             * For Symmetric Flow Control:
+             *
+             *   LOCAL DEVICE  |   LINK PARTNER
+             * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+             *-------|---------|-------|---------|--------------------
+             *   1   |   DC    |   1   |   DC    | em_fc_full
+             *
+             */
+            if((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+               (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) {
+                /* Now we need to check if the user selected RX ONLY
+                 * of pause frames.  In this case, we had to advertise
+                 * FULL flow control because we could not advertise RX
+                 * ONLY. Hence, we must now check to see if we need to
+                 * turn OFF  the TRANSMISSION of PAUSE frames.
+                 */
+                if(hw->original_fc == em_fc_full) {
+                    hw->fc = em_fc_full;
+                    DEBUGOUT("Flow Control = FULL.\r\n");
+                } else {
+                    hw->fc = em_fc_rx_pause;
+                    DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n");
+                }
+            }
+            /* For receiving PAUSE frames ONLY.
+             *
+             *   LOCAL DEVICE  |   LINK PARTNER
+             * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+             *-------|---------|-------|---------|--------------------
+             *   0   |    1    |   1   |    1    | em_fc_tx_pause
+             *
+             */
+            else if(!(mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+                    (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
+                    (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
+                    (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
+                hw->fc = em_fc_tx_pause;
+                DEBUGOUT("Flow Control = TX PAUSE frames only.\r\n");
+            }
+            /* For transmitting PAUSE frames ONLY.
+             *
+             *   LOCAL DEVICE  |   LINK PARTNER
+             * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+             *-------|---------|-------|---------|--------------------
+             *   1   |    1    |   0   |    1    | em_fc_rx_pause
+             *
+             */
+            else if((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+                    (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
+                    !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
+                    (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
+                hw->fc = em_fc_rx_pause;
+                DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n");
+            }
+            /* Per the IEEE spec, at this point flow control should be
+             * disabled.  However, we want to consider that we could
+             * be connected to a legacy switch that doesn't advertise
+             * desired flow control, but can be forced on the link
+             * partner.  So if we advertised no flow control, that is
+             * what we will resolve to.  If we advertised some kind of
+             * receive capability (Rx Pause Only or Full Flow Control)
+             * and the link partner advertised none, we will configure
+             * ourselves to enable Rx Flow Control only.  We can do
+             * this safely for two reasons:  If the link partner really
+             * didn't want flow control enabled, and we enable Rx, no
+             * harm done since we won't be receiving any PAUSE frames
+             * anyway.  If the intent on the link partner was to have
+             * flow control enabled, then by us enabling RX only, we
+             * can at least receive pause frames and process them.
+             * This is a good idea because in most cases, since we are
+             * predominantly a server NIC, more times than not we will
+             * be asked to delay transmission of packets than asking
+             * our link partner to pause transmission of frames.
+             */
+            else if((hw->original_fc == em_fc_none ||
+                     hw->original_fc == em_fc_tx_pause) ||
+                    hw->fc_strict_ieee) {
+                hw->fc = em_fc_none;
+                DEBUGOUT("Flow Control = NONE.\r\n");
+            } else {
+                hw->fc = em_fc_rx_pause;
+                DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n");
+            }
+
+            /* Now we need to do one last check...  If we auto-
+             * negotiated to HALF DUPLEX, flow control should not be
+             * enabled per IEEE 802.3 spec.
+             */
+            ret_val = em_get_speed_and_duplex(hw, &speed, &duplex);
+            if(ret_val) {
+                DEBUGOUT("Error getting link speed and duplex\n");
+                return ret_val;
+            }
+
+            if(duplex == HALF_DUPLEX)
+                hw->fc = em_fc_none;
+
+            /* Now we call a subroutine to actually force the MAC
+             * controller to use the correct flow control settings.
+             */
+            ret_val = em_force_mac_fc(hw);
+            if(ret_val) {
+                DEBUGOUT("Error forcing flow control settings\n");
+                return ret_val;
+            }
+        } else {
+            DEBUGOUT("Copper PHY and Auto Neg has not completed.\r\n");
+        }
+    }
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Checks to see if the link status of the hardware has changed.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Called by any function that needs to check the link status of the adapter.
+ *****************************************************************************/
+int32_t
+em_check_for_link(struct em_hw *hw)
+{
+    uint32_t rxcw = 0;
+    uint32_t ctrl;
+    uint32_t status;
+    uint32_t rctl;
+    uint32_t icr;
+    uint32_t signal = 0;
+    int32_t ret_val;
+    uint16_t phy_data;
+
+    DEBUGFUNC("em_check_for_link");
+
+    ctrl = E1000_READ_REG(hw, CTRL);
+    status = E1000_READ_REG(hw, STATUS);
+
+    /* On adapters with a MAC newer than 82544, SW Defineable pin 1 will be
+     * set when the optics detect a signal. On older adapters, it will be
+     * cleared when there is a signal.  This applies to fiber media only.
+     */
+    if((hw->media_type == em_media_type_fiber) ||
+       (hw->media_type == em_media_type_internal_serdes)) {
+        rxcw = E1000_READ_REG(hw, RXCW);
+
+        if(hw->media_type == em_media_type_fiber) {
+            signal = (hw->mac_type > em_82544) ? E1000_CTRL_SWDPIN1 : 0;
+            if(status & E1000_STATUS_LU)
+                hw->get_link_status = FALSE;
+        }
+    }
+
+    /* If we have a copper PHY then we only want to go out to the PHY
+     * registers to see if Auto-Neg has completed and/or if our link
+     * status has changed.  The get_link_status flag will be set if we
+     * receive a Link Status Change interrupt or we have Rx Sequence
+     * Errors.
+     */
+    if((hw->media_type == em_media_type_copper) && hw->get_link_status) {
+        /* First we want to see if the MII Status Register reports
+         * link.  If so, then we want to get the current speed/duplex
+         * of the PHY.
+         * Read the register twice since the link bit is sticky.
+         */
+        ret_val = em_read_phy_reg(hw, PHY_STATUS, &phy_data);
+        if(ret_val)
+            return ret_val;
+        ret_val = em_read_phy_reg(hw, PHY_STATUS, &phy_data);
+        if(ret_val)
+            return ret_val;
+
+        if(phy_data & MII_SR_LINK_STATUS) {
+            hw->get_link_status = FALSE;
+            /* Check if there was DownShift, must be checked immediately after
+             * link-up */
+            em_check_downshift(hw);
+
+            /* If we are on 82544 or 82543 silicon and speed/duplex
+             * are forced to 10H or 10F, then we will implement the polarity
+             * reversal workaround.  We disable interrupts first, and upon
+             * returning, place the devices interrupt state to its previous
+             * value except for the link status change interrupt which will
+             * happen due to the execution of this workaround.
+             */
+
+            if((hw->mac_type == em_82544 || hw->mac_type == em_82543) &&
+               (!hw->autoneg) &&
+               (hw->forced_speed_duplex == em_10_full ||
+                hw->forced_speed_duplex == em_10_half)) {
+                E1000_WRITE_REG(hw, IMC, 0xffffffff);
+                ret_val = em_polarity_reversal_workaround(hw);
+                icr = E1000_READ_REG(hw, ICR);
+                E1000_WRITE_REG(hw, ICS, (icr & ~E1000_ICS_LSC));
+                E1000_WRITE_REG(hw, IMS, IMS_ENABLE_MASK);
+            }
+
+        } else {
+            /* No link detected */
+            em_config_dsp_after_link_change(hw, FALSE);
+            return 0;
+        }
+
+        /* If we are forcing speed/duplex, then we simply return since
+         * we have already determined whether we have link or not.
+         */
+        if(!hw->autoneg) return -E1000_ERR_CONFIG;
+
+        /* optimize the dsp settings for the igp phy */
+        em_config_dsp_after_link_change(hw, TRUE);
+
+        /* We have a M88E1000 PHY and Auto-Neg is enabled.  If we
+         * have Si on board that is 82544 or newer, Auto
+         * Speed Detection takes care of MAC speed/duplex
+         * configuration.  So we only need to configure Collision
+         * Distance in the MAC.  Otherwise, we need to force
+         * speed/duplex on the MAC to the current PHY speed/duplex
+         * settings.
+         */
+        if(hw->mac_type >= em_82544)
+            em_config_collision_dist(hw);
+        else {
+            ret_val = em_config_mac_to_phy(hw);
+            if(ret_val) {
+                DEBUGOUT("Error configuring MAC to PHY settings\n");
+                return ret_val;
+            }
+        }
+
+        /* Configure Flow Control now that Auto-Neg has completed. First, we
+         * need to restore the desired flow control settings because we may
+         * have had to re-autoneg with a different link partner.
+         */
+        ret_val = em_config_fc_after_link_up(hw);
+        if(ret_val) {
+            DEBUGOUT("Error configuring flow control\n");
+            return ret_val;
+        }
+
+        /* At this point we know that we are on copper and we have
+         * auto-negotiated link.  These are conditions for checking the link
+         * partner capability register.  We use the link speed to determine if
+         * TBI compatibility needs to be turned on or off.  If the link is not
+         * at gigabit speed, then TBI compatibility is not needed.  If we are
+         * at gigabit speed, we turn on TBI compatibility.
+         */
+        if(hw->tbi_compatibility_en) {
+            uint16_t speed, duplex;
+            em_get_speed_and_duplex(hw, &speed, &duplex);
+            if(speed != SPEED_1000) {
+                /* If link speed is not set to gigabit speed, we do not need
+                 * to enable TBI compatibility.
+                 */
+                if(hw->tbi_compatibility_on) {
+                    /* If we previously were in the mode, turn it off. */
+                    rctl = E1000_READ_REG(hw, RCTL);
+                    rctl &= ~E1000_RCTL_SBP;
+                    E1000_WRITE_REG(hw, RCTL, rctl);
+                    hw->tbi_compatibility_on = FALSE;
+                }
+            } else {
+                /* If TBI compatibility is was previously off, turn it on. For
+                 * compatibility with a TBI link partner, we will store bad
+                 * packets. Some frames have an additional byte on the end and
+                 * will look like CRC errors to to the hardware.
+                 */
+                if(!hw->tbi_compatibility_on) {
+                    hw->tbi_compatibility_on = TRUE;
+                    rctl = E1000_READ_REG(hw, RCTL);
+                    rctl |= E1000_RCTL_SBP;
+                    E1000_WRITE_REG(hw, RCTL, rctl);
+                }
+            }
+        }
+    }
+    /* If we don't have link (auto-negotiation failed or link partner cannot
+     * auto-negotiate), the cable is plugged in (we have signal), and our
+     * link partner is not trying to auto-negotiate with us (we are receiving
+     * idles or data), we need to force link up. We also need to give
+     * auto-negotiation time to complete, in case the cable was just plugged
+     * in. The autoneg_failed flag does this.
+     */
+    else if((((hw->media_type == em_media_type_fiber) &&
+              ((ctrl & E1000_CTRL_SWDPIN1) == signal)) ||
+             (hw->media_type == em_media_type_internal_serdes)) &&
+            (!(status & E1000_STATUS_LU)) &&
+            (!(rxcw & E1000_RXCW_C))) {
+        if(hw->autoneg_failed == 0) {
+            hw->autoneg_failed = 1;
+            return 0;
+        }
+        DEBUGOUT("NOT RXing /C/, disable AutoNeg and force link.\r\n");
+
+        /* Disable auto-negotiation in the TXCW register */
+        E1000_WRITE_REG(hw, TXCW, (hw->txcw & ~E1000_TXCW_ANE));
+
+        /* Force link-up and also force full-duplex. */
+        ctrl = E1000_READ_REG(hw, CTRL);
+        ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD);
+        E1000_WRITE_REG(hw, CTRL, ctrl);
+
+        /* Configure Flow Control after forcing link up. */
+        ret_val = em_config_fc_after_link_up(hw);
+        if(ret_val) {
+            DEBUGOUT("Error configuring flow control\n");
+            return ret_val;
+        }
+    }
+    /* If we are forcing link and we are receiving /C/ ordered sets, re-enable
+     * auto-negotiation in the TXCW register and disable forced link in the
+     * Device Control register in an attempt to auto-negotiate with our link
+     * partner.
+     */
+    else if(((hw->media_type == em_media_type_fiber) ||
+             (hw->media_type == em_media_type_internal_serdes)) &&
+            (ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) {
+        DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\r\n");
+        E1000_WRITE_REG(hw, TXCW, hw->txcw);
+        E1000_WRITE_REG(hw, CTRL, (ctrl & ~E1000_CTRL_SLU));
+
+        hw->serdes_link_down = FALSE;
+    }
+    /* If we force link for non-auto-negotiation switch, check link status
+     * based on MAC synchronization for internal serdes media type.
+     */
+    else if((hw->media_type == em_media_type_internal_serdes) &&
+            !(E1000_TXCW_ANE & E1000_READ_REG(hw, TXCW))) {
+        /* SYNCH bit and IV bit are sticky. */
+        usec_delay(10);
+        if(E1000_RXCW_SYNCH & E1000_READ_REG(hw, RXCW)) {
+            if(!(rxcw & E1000_RXCW_IV)) {
+                hw->serdes_link_down = FALSE;
+                DEBUGOUT("SERDES: Link is up.\n");
+            }
+        } else {
+            hw->serdes_link_down = TRUE;
+            DEBUGOUT("SERDES: Link is down.\n");
+        }
+    }
+    if((hw->media_type == em_media_type_internal_serdes) &&
+       (E1000_TXCW_ANE & E1000_READ_REG(hw, TXCW))) {
+        hw->serdes_link_down = !(E1000_STATUS_LU & E1000_READ_REG(hw, STATUS));
+    }
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Detects the current speed and duplex settings of the hardware.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * speed - Speed of the connection
+ * duplex - Duplex setting of the connection
+ *****************************************************************************/
+int32_t
+em_get_speed_and_duplex(struct em_hw *hw,
+                           uint16_t *speed,
+                           uint16_t *duplex)
+{
+    uint32_t status;
+    int32_t ret_val;
+    uint16_t phy_data;
+
+    DEBUGFUNC("em_get_speed_and_duplex");
+
+    if(hw->mac_type >= em_82543) {
+        status = E1000_READ_REG(hw, STATUS);
+        if(status & E1000_STATUS_SPEED_1000) {
+            *speed = SPEED_1000;
+            DEBUGOUT("1000 Mbs, ");
+        } else if(status & E1000_STATUS_SPEED_100) {
+            *speed = SPEED_100;
+            DEBUGOUT("100 Mbs, ");
+        } else {
+            *speed = SPEED_10;
+            DEBUGOUT("10 Mbs, ");
+        }
+
+        if(status & E1000_STATUS_FD) {
+            *duplex = FULL_DUPLEX;
+            DEBUGOUT("Full Duplex\r\n");
+        } else {
+            *duplex = HALF_DUPLEX;
+            DEBUGOUT(" Half Duplex\r\n");
+        }
+    } else {
+        DEBUGOUT("1000 Mbs, Full Duplex\r\n");
+        *speed = SPEED_1000;
+        *duplex = FULL_DUPLEX;
+    }
+
+    /* IGP01 PHY may advertise full duplex operation after speed downgrade even
+     * if it is operating at half duplex.  Here we set the duplex settings to
+     * match the duplex in the link partner's capabilities.
+     */
+    if(hw->phy_type == em_phy_igp && hw->speed_downgraded) {
+        ret_val = em_read_phy_reg(hw, PHY_AUTONEG_EXP, &phy_data);
+        if(ret_val)
+            return ret_val;
+
+        if(!(phy_data & NWAY_ER_LP_NWAY_CAPS))
+            *duplex = HALF_DUPLEX;
+        else {
+            ret_val = em_read_phy_reg(hw, PHY_LP_ABILITY, &phy_data);
+            if(ret_val)
+                return ret_val;
+            if((*speed == SPEED_100 && !(phy_data & NWAY_LPAR_100TX_FD_CAPS)) ||
+               (*speed == SPEED_10 && !(phy_data & NWAY_LPAR_10T_FD_CAPS)))
+                *duplex = HALF_DUPLEX;
+        }
+    }
+
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
+* Blocks until autoneg completes or times out (~4.5 seconds)
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+int32_t
+em_wait_autoneg(struct em_hw *hw)
+{
+    int32_t ret_val;
+    uint16_t i;
+    uint16_t phy_data;
+
+    DEBUGFUNC("em_wait_autoneg");
+    DEBUGOUT("Waiting for Auto-Neg to complete.\n");
+
+    /* We will wait for autoneg to complete or 4.5 seconds to expire. */
+    for(i = PHY_AUTO_NEG_TIME; i > 0; i--) {
+        /* Read the MII Status Register and wait for Auto-Neg
+         * Complete bit to be set.
+         */
+        ret_val = em_read_phy_reg(hw, PHY_STATUS, &phy_data);
+        if(ret_val)
+            return ret_val;
+        ret_val = em_read_phy_reg(hw, PHY_STATUS, &phy_data);
+        if(ret_val)
+            return ret_val;
+        if(phy_data & MII_SR_AUTONEG_COMPLETE) {
+            return E1000_SUCCESS;
+        }
+        msec_delay(100);
+    }
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
+* Raises the Management Data Clock
+*
+* hw - Struct containing variables accessed by shared code
+* ctrl - Device control register's current value
+******************************************************************************/
+static void
+em_raise_mdi_clk(struct em_hw *hw,
+                    uint32_t *ctrl)
+{
+    /* Raise the clock input to the Management Data Clock (by setting the MDC
+     * bit), and then delay 10 microseconds.
+     */
+    E1000_WRITE_REG(hw, CTRL, (*ctrl | E1000_CTRL_MDC));
+    E1000_WRITE_FLUSH(hw);
+    usec_delay(10);
+}
+
+/******************************************************************************
+* Lowers the Management Data Clock
+*
+* hw - Struct containing variables accessed by shared code
+* ctrl - Device control register's current value
+******************************************************************************/
+static void
+em_lower_mdi_clk(struct em_hw *hw,
+                    uint32_t *ctrl)
+{
+    /* Lower the clock input to the Management Data Clock (by clearing the MDC
+     * bit), and then delay 10 microseconds.
+     */
+    E1000_WRITE_REG(hw, CTRL, (*ctrl & ~E1000_CTRL_MDC));
+    E1000_WRITE_FLUSH(hw);
+    usec_delay(10);
+}
+
+/******************************************************************************
+* Shifts data bits out to the PHY
+*
+* hw - Struct containing variables accessed by shared code
+* data - Data to send out to the PHY
+* count - Number of bits to shift out
+*
+* Bits are shifted out in MSB to LSB order.
+******************************************************************************/
+static void
+em_shift_out_mdi_bits(struct em_hw *hw,
+                         uint32_t data,
+                         uint16_t count)
+{
+    uint32_t ctrl;
+    uint32_t mask;
+
+    /* We need to shift "count" number of bits out to the PHY. So, the value
+     * in the "data" parameter will be shifted out to the PHY one bit at a
+     * time. In order to do this, "data" must be broken down into bits.
+     */
+    mask = 0x01;
+    mask <<= (count - 1);
+
+    ctrl = E1000_READ_REG(hw, CTRL);
+
+    /* Set MDIO_DIR and MDC_DIR direction bits to be used as output pins. */
+    ctrl |= (E1000_CTRL_MDIO_DIR | E1000_CTRL_MDC_DIR);
+
+    while(mask) {
+        /* A "1" is shifted out to the PHY by setting the MDIO bit to "1" and
+         * then raising and lowering the Management Data Clock. A "0" is
+         * shifted out to the PHY by setting the MDIO bit to "0" and then
+         * raising and lowering the clock.
+         */
+        if(data & mask) ctrl |= E1000_CTRL_MDIO;
+        else ctrl &= ~E1000_CTRL_MDIO;
+
+        E1000_WRITE_REG(hw, CTRL, ctrl);
+        E1000_WRITE_FLUSH(hw);
+
+        usec_delay(10);
+
+        em_raise_mdi_clk(hw, &ctrl);
+        em_lower_mdi_clk(hw, &ctrl);
+
+        mask = mask >> 1;
+    }
+}
+
+/******************************************************************************
+* Shifts data bits in from the PHY
+*
+* hw - Struct containing variables accessed by shared code
+*
+* Bits are shifted in in MSB to LSB order.
+******************************************************************************/
+static uint16_t
+em_shift_in_mdi_bits(struct em_hw *hw)
+{
+    uint32_t ctrl;
+    uint16_t data = 0;
+    uint8_t i;
+
+    /* In order to read a register from the PHY, we need to shift in a total
+     * of 18 bits from the PHY. The first two bit (turnaround) times are used
+     * to avoid contention on the MDIO pin when a read operation is performed.
+     * These two bits are ignored by us and thrown away. Bits are "shifted in"
+     * by raising the input to the Management Data Clock (setting the MDC bit),
+     * and then reading the value of the MDIO bit.
+     */
+    ctrl = E1000_READ_REG(hw, CTRL);
+
+    /* Clear MDIO_DIR (SWDPIO1) to indicate this bit is to be used as input. */
+    ctrl &= ~E1000_CTRL_MDIO_DIR;
+    ctrl &= ~E1000_CTRL_MDIO;
+
+    E1000_WRITE_REG(hw, CTRL, ctrl);
+    E1000_WRITE_FLUSH(hw);
+
+    /* Raise and Lower the clock before reading in the data. This accounts for
+     * the turnaround bits. The first clock occurred when we clocked out the
+     * last bit of the Register Address.
+     */
+    em_raise_mdi_clk(hw, &ctrl);
+    em_lower_mdi_clk(hw, &ctrl);
+
+    for(data = 0, i = 0; i < 16; i++) {
+        data = data << 1;
+        em_raise_mdi_clk(hw, &ctrl);
+        ctrl = E1000_READ_REG(hw, CTRL);
+        /* Check to see if we shifted in a "1". */
+        if(ctrl & E1000_CTRL_MDIO) data |= 1;
+        em_lower_mdi_clk(hw, &ctrl);
+    }
+
+    em_raise_mdi_clk(hw, &ctrl);
+    em_lower_mdi_clk(hw, &ctrl);
+
+    return data;
+}
+
+/*****************************************************************************
+* Reads the value from a PHY register, if the value is on a specific non zero
+* page, sets the page first.
+* hw - Struct containing variables accessed by shared code
+* reg_addr - address of the PHY register to read
+******************************************************************************/
+int32_t
+em_read_phy_reg(struct em_hw *hw,
+                   uint32_t reg_addr,
+                   uint16_t *phy_data)
+{
+    uint32_t ret_val;
+
+    DEBUGFUNC("em_read_phy_reg");
+
+    if((hw->phy_type == em_phy_igp || 
+        hw->phy_type == em_phy_igp_2) &&
+       (reg_addr > MAX_PHY_MULTI_PAGE_REG)) {
+        ret_val = em_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT,
+                                         (uint16_t)reg_addr);
+        if(ret_val) {
+            return ret_val;
+        }
+    }
+
+    ret_val = em_read_phy_reg_ex(hw, MAX_PHY_REG_ADDRESS & reg_addr,
+                                    phy_data);
+
+    return ret_val;
+}
+
+int32_t
+em_read_phy_reg_ex(struct em_hw *hw,
+                      uint32_t reg_addr,
+                      uint16_t *phy_data)
+{
+    uint32_t i;
+    uint32_t mdic = 0;
+    const uint32_t phy_addr = 1;
+
+    DEBUGFUNC("em_read_phy_reg_ex");
+
+    if(reg_addr > MAX_PHY_REG_ADDRESS) {
+        DEBUGOUT1("PHY Address %d is out of range\n", reg_addr);
+        return -E1000_ERR_PARAM;
+    }
+
+    if(hw->mac_type > em_82543) {
+        /* Set up Op-code, Phy Address, and register address in the MDI
+         * Control register.  The MAC will take care of interfacing with the
+         * PHY to retrieve the desired data.
+         */
+        mdic = ((reg_addr << E1000_MDIC_REG_SHIFT) |
+                (phy_addr << E1000_MDIC_PHY_SHIFT) |
+                (E1000_MDIC_OP_READ));
+
+        E1000_WRITE_REG(hw, MDIC, mdic);
+
+        /* Poll the ready bit to see if the MDI read completed */
+        for(i = 0; i < 64; i++) {
+            usec_delay(50);
+            mdic = E1000_READ_REG(hw, MDIC);
+            if(mdic & E1000_MDIC_READY) break;
+        }
+        if(!(mdic & E1000_MDIC_READY)) {
+            DEBUGOUT("MDI Read did not complete\n");
+            return -E1000_ERR_PHY;
+        }
+        if(mdic & E1000_MDIC_ERROR) {
+            DEBUGOUT("MDI Error\n");
+            return -E1000_ERR_PHY;
+        }
+        *phy_data = (uint16_t) mdic;
+    } else {
+        /* We must first send a preamble through the MDIO pin to signal the
+         * beginning of an MII instruction.  This is done by sending 32
+         * consecutive "1" bits.
+         */
+        em_shift_out_mdi_bits(hw, PHY_PREAMBLE, PHY_PREAMBLE_SIZE);
+
+        /* Now combine the next few fields that are required for a read
+         * operation.  We use this method instead of calling the
+         * em_shift_out_mdi_bits routine five different times. The format of
+         * a MII read instruction consists of a shift out of 14 bits and is
+         * defined as follows:
+         *    <Preamble><SOF><Op Code><Phy Addr><Reg Addr>
+         * followed by a shift in of 18 bits.  This first two bits shifted in
+         * are TurnAround bits used to avoid contention on the MDIO pin when a
+         * READ operation is performed.  These two bits are thrown away
+         * followed by a shift in of 16 bits which contains the desired data.
+         */
+        mdic = ((reg_addr) | (phy_addr << 5) |
+                (PHY_OP_READ << 10) | (PHY_SOF << 12));
+
+        em_shift_out_mdi_bits(hw, mdic, 14);
+
+        /* Now that we've shifted out the read command to the MII, we need to
+         * "shift in" the 16-bit value (18 total bits) of the requested PHY
+         * register address.
+         */
+        *phy_data = em_shift_in_mdi_bits(hw);
+    }
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
+* Writes a value to a PHY register
+*
+* hw - Struct containing variables accessed by shared code
+* reg_addr - address of the PHY register to write
+* data - data to write to the PHY
+******************************************************************************/
+int32_t
+em_write_phy_reg(struct em_hw *hw,
+                    uint32_t reg_addr,
+                    uint16_t phy_data)
+{
+    uint32_t ret_val;
+
+    DEBUGFUNC("em_write_phy_reg");
+
+    if((hw->phy_type == em_phy_igp || 
+        hw->phy_type == em_phy_igp_2) &&
+       (reg_addr > MAX_PHY_MULTI_PAGE_REG)) {
+        ret_val = em_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT,
+                                         (uint16_t)reg_addr);
+        if(ret_val) {
+            return ret_val;
+        }
+    }
+
+    ret_val = em_write_phy_reg_ex(hw, MAX_PHY_REG_ADDRESS & reg_addr,
+                                     phy_data);
+
+    return ret_val;
+}
+
+int32_t
+em_write_phy_reg_ex(struct em_hw *hw,
+                    uint32_t reg_addr,
+                    uint16_t phy_data)
+{
+    uint32_t i;
+    uint32_t mdic = 0;
+    const uint32_t phy_addr = 1;
+
+    DEBUGFUNC("em_write_phy_reg_ex");
+
+    if(reg_addr > MAX_PHY_REG_ADDRESS) {
+        DEBUGOUT1("PHY Address %d is out of range\n", reg_addr);
+        return -E1000_ERR_PARAM;
+    }
+
+    if(hw->mac_type > em_82543) {
+        /* Set up Op-code, Phy Address, register address, and data intended
+         * for the PHY register in the MDI Control register.  The MAC will take
+         * care of interfacing with the PHY to send the desired data.
+         */
+        mdic = (((uint32_t) phy_data) |
+                (reg_addr << E1000_MDIC_REG_SHIFT) |
+                (phy_addr << E1000_MDIC_PHY_SHIFT) |
+                (E1000_MDIC_OP_WRITE));
+
+        E1000_WRITE_REG(hw, MDIC, mdic);
+
+        /* Poll the ready bit to see if the MDI read completed */
+        for(i = 0; i < 640; i++) {
+            usec_delay(5);
+            mdic = E1000_READ_REG(hw, MDIC);
+            if(mdic & E1000_MDIC_READY) break;
+        }
+        if(!(mdic & E1000_MDIC_READY)) {
+            DEBUGOUT("MDI Write did not complete\n");
+            return -E1000_ERR_PHY;
+        }
+    } else {
+        /* We'll need to use the SW defined pins to shift the write command
+         * out to the PHY. We first send a preamble to the PHY to signal the
+         * beginning of the MII instruction.  This is done by sending 32
+         * consecutive "1" bits.
+         */
+        em_shift_out_mdi_bits(hw, PHY_PREAMBLE, PHY_PREAMBLE_SIZE);
+
+        /* Now combine the remaining required fields that will indicate a
+         * write operation. We use this method instead of calling the
+         * em_shift_out_mdi_bits routine for each field in the command. The
+         * format of a MII write instruction is as follows:
+         * <Preamble><SOF><Op Code><Phy Addr><Reg Addr><Turnaround><Data>.
+         */
+        mdic = ((PHY_TURNAROUND) | (reg_addr << 2) | (phy_addr << 7) |
+                (PHY_OP_WRITE << 12) | (PHY_SOF << 14));
+        mdic <<= 16;
+        mdic |= (uint32_t) phy_data;
+
+        em_shift_out_mdi_bits(hw, mdic, 32);
+    }
+
+    return E1000_SUCCESS;
+}
+
+
+/******************************************************************************
+* Returns the PHY to the power-on reset state
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+int32_t
+em_phy_hw_reset(struct em_hw *hw)
+{
+    uint32_t ctrl, ctrl_ext;
+    uint32_t led_ctrl;
+    int32_t ret_val;
+
+    DEBUGFUNC("em_phy_hw_reset");
+
+    /* In the case of the phy reset being blocked, it's not an error, we
+     * simply return success without performing the reset. */
+    ret_val = em_check_phy_reset_block(hw);
+    if (ret_val)
+        return E1000_SUCCESS;
+
+    DEBUGOUT("Resetting Phy...\n");
+
+    if(hw->mac_type > em_82543) {
+        /* Read the device control register and assert the E1000_CTRL_PHY_RST
+         * bit. Then, take it out of reset.
+         */
+        ctrl = E1000_READ_REG(hw, CTRL);
+        E1000_WRITE_REG(hw, CTRL, ctrl | E1000_CTRL_PHY_RST);
+        E1000_WRITE_FLUSH(hw);
+        msec_delay(10);
+        E1000_WRITE_REG(hw, CTRL, ctrl);
+        E1000_WRITE_FLUSH(hw);
+    } else {
+        /* Read the Extended Device Control Register, assert the PHY_RESET_DIR
+         * bit to put the PHY into reset. Then, take it out of reset.
+         */
+        ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
+        ctrl_ext |= E1000_CTRL_EXT_SDP4_DIR;
+        ctrl_ext &= ~E1000_CTRL_EXT_SDP4_DATA;
+        E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+        E1000_WRITE_FLUSH(hw);
+        msec_delay(10);
+        ctrl_ext |= E1000_CTRL_EXT_SDP4_DATA;
+        E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+        E1000_WRITE_FLUSH(hw);
+    }
+    usec_delay(150);
+
+    if((hw->mac_type == em_82541) || (hw->mac_type == em_82547)) {
+        /* Configure activity LED after PHY reset */
+        led_ctrl = E1000_READ_REG(hw, LEDCTL);
+        led_ctrl &= IGP_ACTIVITY_LED_MASK;
+        led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
+        E1000_WRITE_REG(hw, LEDCTL, led_ctrl);
+    }
+
+    /* Wait for FW to finish PHY configuration. */
+    ret_val = em_get_phy_cfg_done(hw);
+
+    return ret_val;
+}
+
+/******************************************************************************
+* Resets the PHY
+*
+* hw - Struct containing variables accessed by shared code
+*
+* Sets bit 15 of the MII Control regiser
+******************************************************************************/
+int32_t
+em_phy_reset(struct em_hw *hw)
+{
+    int32_t ret_val;
+    uint16_t phy_data;
+
+    DEBUGFUNC("em_phy_reset");
+
+    /* In the case of the phy reset being blocked, it's not an error, we
+     * simply return success without performing the reset. */
+    ret_val = em_check_phy_reset_block(hw);
+    if (ret_val)
+        return E1000_SUCCESS;
+
+    switch (hw->mac_type) {
+    case em_82541_rev_2:
+        ret_val = em_phy_hw_reset(hw);
+        if(ret_val)
+            return ret_val;
+        break;
+    default:
+        ret_val = em_read_phy_reg(hw, PHY_CTRL, &phy_data);
+        if(ret_val)
+            return ret_val;
+
+        phy_data |= MII_CR_RESET;
+        ret_val = em_write_phy_reg(hw, PHY_CTRL, phy_data);
+        if(ret_val)
+            return ret_val;
+
+        usec_delay(1);
+        break;
+    }
+
+    if(hw->phy_type == em_phy_igp || hw->phy_type == em_phy_igp_2)
+        em_phy_init_script(hw);
+
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
+* Probes the expected PHY address for known PHY IDs
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+int32_t
+em_detect_gig_phy(struct em_hw *hw)
+{
+    int32_t phy_init_status, ret_val;
+    uint16_t phy_id_high, phy_id_low;
+    boolean_t match = FALSE;
+
+    DEBUGFUNC("em_detect_gig_phy");
+
+    /* Read the PHY ID Registers to identify which PHY is onboard. */
+    ret_val = em_read_phy_reg(hw, PHY_ID1, &phy_id_high);
+    if(ret_val)
+        return ret_val;
+
+    hw->phy_id = (uint32_t) (phy_id_high << 16);
+    usec_delay(20);
+    ret_val = em_read_phy_reg(hw, PHY_ID2, &phy_id_low);
+    if(ret_val)
+        return ret_val;
+
+    hw->phy_id |= (uint32_t) (phy_id_low & PHY_REVISION_MASK);
+    hw->phy_revision = (uint32_t) phy_id_low & ~PHY_REVISION_MASK;
+
+    switch(hw->mac_type) {
+    case em_82543:
+        if(hw->phy_id == M88E1000_E_PHY_ID) match = TRUE;
+        break;
+    case em_82544:
+        if(hw->phy_id == M88E1000_I_PHY_ID) match = TRUE;
+        break;
+    case em_82540:
+    case em_82545:
+    case em_82545_rev_3:
+    case em_82546:
+    case em_82546_rev_3:
+        if(hw->phy_id == M88E1011_I_PHY_ID) match = TRUE;
+        break;
+    case em_82541:
+    case em_82541_rev_2:
+    case em_82547:
+    case em_82547_rev_2:
+        if(hw->phy_id == IGP01E1000_I_PHY_ID) match = TRUE;
+        break;
+    case em_82573:
+        if(hw->phy_id == M88E1111_I_PHY_ID) match = TRUE;
+        break;
+    default:
+        DEBUGOUT1("Invalid MAC type %d\n", hw->mac_type);
+        return -E1000_ERR_CONFIG;
+    }
+    phy_init_status = em_set_phy_type(hw);
+
+    if ((match) && (phy_init_status == E1000_SUCCESS)) {
+        DEBUGOUT1("PHY ID 0x%X detected\n", hw->phy_id);
+        return E1000_SUCCESS;
+    }
+    DEBUGOUT1("Invalid PHY ID 0x%X\n", hw->phy_id);
+    return -E1000_ERR_PHY;
+}
+
+/******************************************************************************
+* Resets the PHY's DSP
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+static int32_t
+em_phy_reset_dsp(struct em_hw *hw)
+{
+    int32_t ret_val;
+    DEBUGFUNC("em_phy_reset_dsp");
+
+    do {
+        ret_val = em_write_phy_reg(hw, 29, 0x001d);
+        if(ret_val) break;
+        ret_val = em_write_phy_reg(hw, 30, 0x00c1);
+        if(ret_val) break;
+        ret_val = em_write_phy_reg(hw, 30, 0x0000);
+        if(ret_val) break;
+        ret_val = E1000_SUCCESS;
+    } while(0);
+
+    return ret_val;
+}
+
+/******************************************************************************
+* Get PHY information from various PHY registers for igp PHY only.
+*
+* hw - Struct containing variables accessed by shared code
+* phy_info - PHY information structure
+******************************************************************************/
+int32_t
+em_phy_igp_get_info(struct em_hw *hw,
+                       struct em_phy_info *phy_info)
+{
+    int32_t ret_val;
+    uint16_t phy_data, polarity, min_length, max_length, average;
+
+    DEBUGFUNC("em_phy_igp_get_info");
+
+    /* The downshift status is checked only once, after link is established,
+     * and it stored in the hw->speed_downgraded parameter. */
+    phy_info->downshift = (em_downshift)hw->speed_downgraded;
+
+    /* IGP01E1000 does not need to support it. */
+    phy_info->extended_10bt_distance = em_10bt_ext_dist_enable_normal;
+
+    /* IGP01E1000 always correct polarity reversal */
+    phy_info->polarity_correction = em_polarity_reversal_enabled;
+
+    /* Check polarity status */
+    ret_val = em_check_polarity(hw, &polarity);
+    if(ret_val)
+        return ret_val;
+
+    phy_info->cable_polarity = polarity;
+
+    ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS, &phy_data);
+    if(ret_val)
+        return ret_val;
+
+    phy_info->mdix_mode = (phy_data & IGP01E1000_PSSR_MDIX) >>
+                          IGP01E1000_PSSR_MDIX_SHIFT;
+
+    if((phy_data & IGP01E1000_PSSR_SPEED_MASK) ==
+       IGP01E1000_PSSR_SPEED_1000MBPS) {
+        /* Local/Remote Receiver Information are only valid at 1000 Mbps */
+        ret_val = em_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data);
+        if(ret_val)
+            return ret_val;
+
+        phy_info->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS) >>
+                             SR_1000T_LOCAL_RX_STATUS_SHIFT;
+        phy_info->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS) >>
+                              SR_1000T_REMOTE_RX_STATUS_SHIFT;
+
+        /* Get cable length */
+        ret_val = em_get_cable_length(hw, &min_length, &max_length);
+        if(ret_val)
+            return ret_val;
+
+        /* Translate to old method */
+        average = (max_length + min_length) / 2;
+
+        if(average <= em_igp_cable_length_50)
+            phy_info->cable_length = em_cable_length_50;
+        else if(average <= em_igp_cable_length_80)
+            phy_info->cable_length = em_cable_length_50_80;
+        else if(average <= em_igp_cable_length_110)
+            phy_info->cable_length = em_cable_length_80_110;
+        else if(average <= em_igp_cable_length_140)
+            phy_info->cable_length = em_cable_length_110_140;
+        else
+            phy_info->cable_length = em_cable_length_140;
+    }
+
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
+* Get PHY information from various PHY registers fot m88 PHY only.
+*
+* hw - Struct containing variables accessed by shared code
+* phy_info - PHY information structure
+******************************************************************************/
+int32_t
+em_phy_m88_get_info(struct em_hw *hw,
+                       struct em_phy_info *phy_info)
+{
+    int32_t ret_val;
+    uint16_t phy_data, polarity;
+
+    DEBUGFUNC("em_phy_m88_get_info");
+
+    /* The downshift status is checked only once, after link is established,
+     * and it stored in the hw->speed_downgraded parameter. */
+    phy_info->downshift = (em_downshift)hw->speed_downgraded;
+
+    ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+    if(ret_val)
+        return ret_val;
+
+    phy_info->extended_10bt_distance =
+        (phy_data & M88E1000_PSCR_10BT_EXT_DIST_ENABLE) >>
+        M88E1000_PSCR_10BT_EXT_DIST_ENABLE_SHIFT;
+    phy_info->polarity_correction =
+        (phy_data & M88E1000_PSCR_POLARITY_REVERSAL) >>
+        M88E1000_PSCR_POLARITY_REVERSAL_SHIFT;
+
+    /* Check polarity status */
+    ret_val = em_check_polarity(hw, &polarity);
+    if(ret_val)
+        return ret_val; 
+    phy_info->cable_polarity = polarity;
+
+    ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
+    if(ret_val)
+        return ret_val;
+
+    phy_info->mdix_mode = (phy_data & M88E1000_PSSR_MDIX) >>
+                          M88E1000_PSSR_MDIX_SHIFT;
+
+    if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) {
+        /* Cable Length Estimation and Local/Remote Receiver Information
+         * are only valid at 1000 Mbps.
+         */
+        phy_info->cable_length = ((phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
+                                  M88E1000_PSSR_CABLE_LENGTH_SHIFT);
+
+        ret_val = em_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data);
+        if(ret_val)
+            return ret_val;
+
+        phy_info->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS) >>
+                             SR_1000T_LOCAL_RX_STATUS_SHIFT;
+
+        phy_info->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS) >>
+                              SR_1000T_REMOTE_RX_STATUS_SHIFT;
+    }
+
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
+* Get PHY information from various PHY registers
+*
+* hw - Struct containing variables accessed by shared code
+* phy_info - PHY information structure
+******************************************************************************/
+int32_t
+em_phy_get_info(struct em_hw *hw,
+                   struct em_phy_info *phy_info)
+{
+    int32_t ret_val;
+    uint16_t phy_data;
+
+    DEBUGFUNC("em_phy_get_info");
+
+    phy_info->cable_length = em_cable_length_undefined;
+    phy_info->extended_10bt_distance = em_10bt_ext_dist_enable_undefined;
+    phy_info->cable_polarity = em_rev_polarity_undefined;
+    phy_info->downshift = em_downshift_undefined;
+    phy_info->polarity_correction = em_polarity_reversal_undefined;
+    phy_info->mdix_mode = em_auto_x_mode_undefined;
+    phy_info->local_rx = em_1000t_rx_status_undefined;
+    phy_info->remote_rx = em_1000t_rx_status_undefined;
+
+    if(hw->media_type != em_media_type_copper) {
+        DEBUGOUT("PHY info is only valid for copper media\n");
+        return -E1000_ERR_CONFIG;
+    }
+
+    ret_val = em_read_phy_reg(hw, PHY_STATUS, &phy_data);
+    if(ret_val)
+        return ret_val;
+
+    ret_val = em_read_phy_reg(hw, PHY_STATUS, &phy_data);
+    if(ret_val)
+        return ret_val;
+
+    if((phy_data & MII_SR_LINK_STATUS) != MII_SR_LINK_STATUS) {
+        DEBUGOUT("PHY info is only valid if link is up\n");
+        return -E1000_ERR_CONFIG;
+    }
+
+    if(hw->phy_type == em_phy_igp ||
+        hw->phy_type == em_phy_igp_2)
+        return em_phy_igp_get_info(hw, phy_info);
+    else
+        return em_phy_m88_get_info(hw, phy_info);
+}
+
+int32_t
+em_validate_mdi_setting(struct em_hw *hw)
+{
+    DEBUGFUNC("em_validate_mdi_settings");
+
+    if(!hw->autoneg && (hw->mdix == 0 || hw->mdix == 3)) {
+        DEBUGOUT("Invalid MDI setting detected\n");
+        hw->mdix = 1;
+        return -E1000_ERR_CONFIG;
+    }
+    return E1000_SUCCESS;
+}
+
+
+/******************************************************************************
+ * Sets up eeprom variables in the hw struct.  Must be called after mac_type
+ * is configured.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+em_init_eeprom_params(struct em_hw *hw)
+{
+    struct em_eeprom_info *eeprom = &hw->eeprom;
+    uint32_t eecd = E1000_READ_REG(hw, EECD);
+    int32_t ret_val = E1000_SUCCESS;
+    uint16_t eeprom_size;
+
+    DEBUGFUNC("em_init_eeprom_params");
+
+    switch (hw->mac_type) {
+    case em_82542_rev2_0:
+    case em_82542_rev2_1:
+    case em_82543:
+    case em_82544:
+        eeprom->type = em_eeprom_microwire;
+        eeprom->word_size = 64;
+        eeprom->opcode_bits = 3;
+        eeprom->address_bits = 6;
+        eeprom->delay_usec = 50;
+        eeprom->use_eerd = FALSE;
+        eeprom->use_eewr = FALSE;
+        break;
+    case em_82540:
+    case em_82545:
+    case em_82545_rev_3:
+    case em_82546:
+    case em_82546_rev_3:
+        eeprom->type = em_eeprom_microwire;
+        eeprom->opcode_bits = 3;
+        eeprom->delay_usec = 50;
+        if(eecd & E1000_EECD_SIZE) {
+            eeprom->word_size = 256;
+            eeprom->address_bits = 8;
+        } else {
+            eeprom->word_size = 64;
+            eeprom->address_bits = 6;
+        }
+        eeprom->use_eerd = FALSE;
+        eeprom->use_eewr = FALSE;
+        break;
+    case em_82541:
+    case em_82541_rev_2:
+    case em_82547:
+    case em_82547_rev_2:
+        if (eecd & E1000_EECD_TYPE) {
+            eeprom->type = em_eeprom_spi;
+            eeprom->opcode_bits = 8;
+            eeprom->delay_usec = 1;
+            if (eecd & E1000_EECD_ADDR_BITS) {
+                eeprom->page_size = 32;
+                eeprom->address_bits = 16;
+            } else {
+                eeprom->page_size = 8;
+                eeprom->address_bits = 8;
+            }
+        } else {
+            eeprom->type = em_eeprom_microwire;
+            eeprom->opcode_bits = 3;
+            eeprom->delay_usec = 50;
+            if (eecd & E1000_EECD_ADDR_BITS) {
+                eeprom->word_size = 256;
+                eeprom->address_bits = 8;
+            } else {
+                eeprom->word_size = 64;
+                eeprom->address_bits = 6;
+            }
+        }
+        eeprom->use_eerd = FALSE;
+        eeprom->use_eewr = FALSE;
+        break;
+    case em_82573:
+        eeprom->type = em_eeprom_spi;
+        eeprom->opcode_bits = 8;
+        eeprom->delay_usec = 1;
+        if (eecd & E1000_EECD_ADDR_BITS) {
+            eeprom->page_size = 32;
+            eeprom->address_bits = 16;
+        } else {
+            eeprom->page_size = 8;
+            eeprom->address_bits = 8;
+        }
+        eeprom->use_eerd = TRUE;
+        eeprom->use_eewr = TRUE;
+        if(em_is_onboard_nvm_eeprom(hw) == FALSE) {
+            eeprom->type = em_eeprom_flash;
+            eeprom->word_size = 2048;
+
+            /* Ensure that the Autonomous FLASH update bit is cleared due to
+             * Flash update issue on parts which use a FLASH for NVM. */
+            eecd &= ~E1000_EECD_AUPDEN;
+            E1000_WRITE_REG(hw, EECD, eecd);
+        }
+        break;
+    default:
+        break;
+    }
+
+    if (eeprom->type == em_eeprom_spi) {
+        /* eeprom_size will be an enum [0..8] that maps to eeprom sizes 128B to
+         * 32KB (incremented by powers of 2).
+         */
+        if(hw->mac_type <= em_82547_rev_2) {
+            /* Set to default value for initial eeprom read. */
+            eeprom->word_size = 64;
+            ret_val = em_read_eeprom(hw, EEPROM_CFG, 1, &eeprom_size);
+            if(ret_val)
+                return ret_val;
+            eeprom_size = (eeprom_size & EEPROM_SIZE_MASK) >> EEPROM_SIZE_SHIFT;
+            /* 256B eeprom size was not supported in earlier hardware, so we
+             * bump eeprom_size up one to ensure that "1" (which maps to 256B)
+             * is never the result used in the shifting logic below. */
+            if(eeprom_size)
+                eeprom_size++;
+        } else {
+            eeprom_size = (uint16_t)((eecd & E1000_EECD_SIZE_EX_MASK) >>
+                          E1000_EECD_SIZE_EX_SHIFT);
+        }
+
+        eeprom->word_size = 1 << (eeprom_size + EEPROM_WORD_SIZE_SHIFT);
+    }
+    return ret_val;
+}
+
+/******************************************************************************
+ * Raises the EEPROM's clock input.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * eecd - EECD's current value
+ *****************************************************************************/
+static void
+em_raise_ee_clk(struct em_hw *hw,
+                   uint32_t *eecd)
+{
+    /* Raise the clock input to the EEPROM (by setting the SK bit), and then
+     * wait <delay> microseconds.
+     */
+    *eecd = *eecd | E1000_EECD_SK;
+    E1000_WRITE_REG(hw, EECD, *eecd);
+    E1000_WRITE_FLUSH(hw);
+    usec_delay(hw->eeprom.delay_usec);
+}
+
+/******************************************************************************
+ * Lowers the EEPROM's clock input.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * eecd - EECD's current value
+ *****************************************************************************/
+static void
+em_lower_ee_clk(struct em_hw *hw,
+                   uint32_t *eecd)
+{
+    /* Lower the clock input to the EEPROM (by clearing the SK bit), and then
+     * wait 50 microseconds.
+     */
+    *eecd = *eecd & ~E1000_EECD_SK;
+    E1000_WRITE_REG(hw, EECD, *eecd);
+    E1000_WRITE_FLUSH(hw);
+    usec_delay(hw->eeprom.delay_usec);
+}
+
+/******************************************************************************
+ * Shift data bits out to the EEPROM.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * data - data to send to the EEPROM
+ * count - number of bits to shift out
+ *****************************************************************************/
+static void
+em_shift_out_ee_bits(struct em_hw *hw,
+                        uint16_t data,
+                        uint16_t count)
+{
+    struct em_eeprom_info *eeprom = &hw->eeprom;
+    uint32_t eecd;
+    uint32_t mask;
+
+    /* We need to shift "count" bits out to the EEPROM. So, value in the
+     * "data" parameter will be shifted out to the EEPROM one bit at a time.
+     * In order to do this, "data" must be broken down into bits.
+     */
+    mask = 0x01 << (count - 1);
+    eecd = E1000_READ_REG(hw, EECD);
+    if (eeprom->type == em_eeprom_microwire) {
+        eecd &= ~E1000_EECD_DO;
+    } else if (eeprom->type == em_eeprom_spi) {
+        eecd |= E1000_EECD_DO;
+    }
+    do {
+        /* A "1" is shifted out to the EEPROM by setting bit "DI" to a "1",
+         * and then raising and then lowering the clock (the SK bit controls
+         * the clock input to the EEPROM).  A "0" is shifted out to the EEPROM
+         * by setting "DI" to "0" and then raising and then lowering the clock.
+         */
+        eecd &= ~E1000_EECD_DI;
+
+        if(data & mask)
+            eecd |= E1000_EECD_DI;
+
+        E1000_WRITE_REG(hw, EECD, eecd);
+        E1000_WRITE_FLUSH(hw);
+
+        usec_delay(eeprom->delay_usec);
+
+        em_raise_ee_clk(hw, &eecd);
+        em_lower_ee_clk(hw, &eecd);
+
+        mask = mask >> 1;
+
+    } while(mask);
+
+    /* We leave the "DI" bit set to "0" when we leave this routine. */
+    eecd &= ~E1000_EECD_DI;
+    E1000_WRITE_REG(hw, EECD, eecd);
+}
+
+/******************************************************************************
+ * Shift data bits in from the EEPROM
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static uint16_t
+em_shift_in_ee_bits(struct em_hw *hw,
+                       uint16_t count)
+{
+    uint32_t eecd;
+    uint32_t i;
+    uint16_t data;
+
+    /* In order to read a register from the EEPROM, we need to shift 'count'
+     * bits in from the EEPROM. Bits are "shifted in" by raising the clock
+     * input to the EEPROM (setting the SK bit), and then reading the value of
+     * the "DO" bit.  During this "shifting in" process the "DI" bit should
+     * always be clear.
+     */
+
+    eecd = E1000_READ_REG(hw, EECD);
+
+    eecd &= ~(E1000_EECD_DO | E1000_EECD_DI);
+    data = 0;
+
+    for(i = 0; i < count; i++) {
+        data = data << 1;
+        em_raise_ee_clk(hw, &eecd);
+
+        eecd = E1000_READ_REG(hw, EECD);
+
+        eecd &= ~(E1000_EECD_DI);
+        if(eecd & E1000_EECD_DO)
+            data |= 1;
+
+        em_lower_ee_clk(hw, &eecd);
+    }
+
+    return data;
+}
+
+/******************************************************************************
+ * Prepares EEPROM for access
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Lowers EEPROM clock. Clears input pin. Sets the chip select pin. This
+ * function should be called before issuing a command to the EEPROM.
+ *****************************************************************************/
+static int32_t
+em_acquire_eeprom(struct em_hw *hw)
+{
+    struct em_eeprom_info *eeprom = &hw->eeprom;
+    uint32_t eecd, i=0;
+
+    DEBUGFUNC("em_acquire_eeprom");
+
+    if(em_get_hw_eeprom_semaphore(hw))
+        return -E1000_ERR_EEPROM;
+
+    eecd = E1000_READ_REG(hw, EECD);
+
+    if (hw->mac_type != em_82573) {
+    /* Request EEPROM Access */
+    if(hw->mac_type > em_82544) {
+        eecd |= E1000_EECD_REQ;
+        E1000_WRITE_REG(hw, EECD, eecd);
+        eecd = E1000_READ_REG(hw, EECD);
+        while((!(eecd & E1000_EECD_GNT)) &&
+              (i < E1000_EEPROM_GRANT_ATTEMPTS)) {
+            i++;
+            usec_delay(5);
+            eecd = E1000_READ_REG(hw, EECD);
+        }
+        if(!(eecd & E1000_EECD_GNT)) {
+            eecd &= ~E1000_EECD_REQ;
+            E1000_WRITE_REG(hw, EECD, eecd);
+            DEBUGOUT("Could not acquire EEPROM grant\n");
+            return -E1000_ERR_EEPROM;
+        }
+    }
+    }
+
+    /* Setup EEPROM for Read/Write */
+
+    if (eeprom->type == em_eeprom_microwire) {
+        /* Clear SK and DI */
+        eecd &= ~(E1000_EECD_DI | E1000_EECD_SK);
+        E1000_WRITE_REG(hw, EECD, eecd);
+
+        /* Set CS */
+        eecd |= E1000_EECD_CS;
+        E1000_WRITE_REG(hw, EECD, eecd);
+    } else if (eeprom->type == em_eeprom_spi) {
+        /* Clear SK and CS */
+        eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
+        E1000_WRITE_REG(hw, EECD, eecd);
+        usec_delay(1);
+    }
+
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Returns EEPROM to a "standby" state
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static void
+em_standby_eeprom(struct em_hw *hw)
+{
+    struct em_eeprom_info *eeprom = &hw->eeprom;
+    uint32_t eecd;
+
+    eecd = E1000_READ_REG(hw, EECD);
+
+    if(eeprom->type == em_eeprom_microwire) {
+        eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
+        E1000_WRITE_REG(hw, EECD, eecd);
+        E1000_WRITE_FLUSH(hw);
+        usec_delay(eeprom->delay_usec);
+
+        /* Clock high */
+        eecd |= E1000_EECD_SK;
+        E1000_WRITE_REG(hw, EECD, eecd);
+        E1000_WRITE_FLUSH(hw);
+        usec_delay(eeprom->delay_usec);
+
+        /* Select EEPROM */
+        eecd |= E1000_EECD_CS;
+        E1000_WRITE_REG(hw, EECD, eecd);
+        E1000_WRITE_FLUSH(hw);
+        usec_delay(eeprom->delay_usec);
+
+        /* Clock low */
+        eecd &= ~E1000_EECD_SK;
+        E1000_WRITE_REG(hw, EECD, eecd);
+        E1000_WRITE_FLUSH(hw);
+        usec_delay(eeprom->delay_usec);
+    } else if(eeprom->type == em_eeprom_spi) {
+        /* Toggle CS to flush commands */
+        eecd |= E1000_EECD_CS;
+        E1000_WRITE_REG(hw, EECD, eecd);
+        E1000_WRITE_FLUSH(hw);
+        usec_delay(eeprom->delay_usec);
+        eecd &= ~E1000_EECD_CS;
+        E1000_WRITE_REG(hw, EECD, eecd);
+        E1000_WRITE_FLUSH(hw);
+        usec_delay(eeprom->delay_usec);
+    }
+}
+
+/******************************************************************************
+ * Terminates a command by inverting the EEPROM's chip select pin
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static void
+em_release_eeprom(struct em_hw *hw)
+{
+    uint32_t eecd;
+
+    DEBUGFUNC("em_release_eeprom");
+
+    eecd = E1000_READ_REG(hw, EECD);
+
+    if (hw->eeprom.type == em_eeprom_spi) {
+        eecd |= E1000_EECD_CS;  /* Pull CS high */
+        eecd &= ~E1000_EECD_SK; /* Lower SCK */
+
+        E1000_WRITE_REG(hw, EECD, eecd);
+
+        usec_delay(hw->eeprom.delay_usec);
+    } else if(hw->eeprom.type == em_eeprom_microwire) {
+        /* cleanup eeprom */
+
+        /* CS on Microwire is active-high */
+        eecd &= ~(E1000_EECD_CS | E1000_EECD_DI);
+
+        E1000_WRITE_REG(hw, EECD, eecd);
+
+        /* Rising edge of clock */
+        eecd |= E1000_EECD_SK;
+        E1000_WRITE_REG(hw, EECD, eecd);
+        E1000_WRITE_FLUSH(hw);
+        usec_delay(hw->eeprom.delay_usec);
+
+        /* Falling edge of clock */
+        eecd &= ~E1000_EECD_SK;
+        E1000_WRITE_REG(hw, EECD, eecd);
+        E1000_WRITE_FLUSH(hw);
+        usec_delay(hw->eeprom.delay_usec);
+    }
+
+    /* Stop requesting EEPROM access */
+    if(hw->mac_type > em_82544) {
+        eecd &= ~E1000_EECD_REQ;
+        E1000_WRITE_REG(hw, EECD, eecd);
+    }
+
+    em_put_hw_eeprom_semaphore(hw);
+}
+
+/******************************************************************************
+ * Reads a 16 bit word from the EEPROM.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+em_spi_eeprom_ready(struct em_hw *hw)
+{
+    uint16_t retry_count = 0;
+    uint8_t spi_stat_reg;
+
+    DEBUGFUNC("em_spi_eeprom_ready");
+
+    /* Read "Status Register" repeatedly until the LSB is cleared.  The
+     * EEPROM will signal that the command has been completed by clearing
+     * bit 0 of the internal status register.  If it's not cleared within
+     * 5 milliseconds, then error out.
+     */
+    retry_count = 0;
+    do {
+        em_shift_out_ee_bits(hw, EEPROM_RDSR_OPCODE_SPI,
+                                hw->eeprom.opcode_bits);
+        spi_stat_reg = (uint8_t)em_shift_in_ee_bits(hw, 8);
+        if (!(spi_stat_reg & EEPROM_STATUS_RDY_SPI))
+            break;
+
+        usec_delay(5);
+        retry_count += 5;
+
+        em_standby_eeprom(hw);
+    } while(retry_count < EEPROM_MAX_RETRY_SPI);
+
+    /* ATMEL SPI write time could vary from 0-20mSec on 3.3V devices (and
+     * only 0-5mSec on 5V devices)
+     */
+    if(retry_count >= EEPROM_MAX_RETRY_SPI) {
+        DEBUGOUT("SPI EEPROM Status error\n");
+        return -E1000_ERR_EEPROM;
+    }
+
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Reads a 16 bit word from the EEPROM.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset of  word in the EEPROM to read
+ * data - word read from the EEPROM
+ * words - number of words to read
+ *****************************************************************************/
+int32_t
+em_read_eeprom(struct em_hw *hw,
+                  uint16_t offset,
+                  uint16_t words,
+                  uint16_t *data)
+{
+    struct em_eeprom_info *eeprom = &hw->eeprom;
+    uint32_t i = 0;
+    int32_t ret_val;
+
+    DEBUGFUNC("em_read_eeprom");
+
+    /* A check for invalid values:  offset too large, too many words, and not
+     * enough words.
+     */
+    if((offset >= eeprom->word_size) || (words > eeprom->word_size - offset) ||
+       (words == 0)) {
+        DEBUGOUT("\"words\" parameter out of bounds\n");
+        return -E1000_ERR_EEPROM;
+    }
+
+    /* FLASH reads without acquiring the semaphore are safe in 82573-based
+     * controllers.
+     */
+    if ((em_is_onboard_nvm_eeprom(hw) == TRUE) ||
+        (hw->mac_type != em_82573)) {
+        /* Prepare the EEPROM for reading  */
+        if(em_acquire_eeprom(hw) != E1000_SUCCESS)
+            return -E1000_ERR_EEPROM;
+    }
+
+    if(eeprom->use_eerd == TRUE) {
+        ret_val = em_read_eeprom_eerd(hw, offset, words, data);
+        if ((em_is_onboard_nvm_eeprom(hw) == TRUE) ||
+            (hw->mac_type != em_82573))
+            em_release_eeprom(hw);
+        return ret_val;
+    }
+
+    if(eeprom->type == em_eeprom_spi) {
+        uint16_t word_in;
+        uint8_t read_opcode = EEPROM_READ_OPCODE_SPI;
+
+        if(em_spi_eeprom_ready(hw)) {
+            em_release_eeprom(hw);
+            return -E1000_ERR_EEPROM;
+        }
+
+        em_standby_eeprom(hw);
+
+        /* Some SPI eeproms use the 8th address bit embedded in the opcode */
+        if((eeprom->address_bits == 8) && (offset >= 128))
+            read_opcode |= EEPROM_A8_OPCODE_SPI;
+
+        /* Send the READ command (opcode + addr)  */
+        em_shift_out_ee_bits(hw, read_opcode, eeprom->opcode_bits);
+        em_shift_out_ee_bits(hw, (uint16_t)(offset*2), eeprom->address_bits);
+
+        /* Read the data.  The address of the eeprom internally increments with
+         * each byte (spi) being read, saving on the overhead of eeprom setup
+         * and tear-down.  The address counter will roll over if reading beyond
+         * the size of the eeprom, thus allowing the entire memory to be read
+         * starting from any offset. */
+        for (i = 0; i < words; i++) {
+            word_in = em_shift_in_ee_bits(hw, 16);
+            data[i] = (word_in >> 8) | (word_in << 8);
+        }
+    } else if(eeprom->type == em_eeprom_microwire) {
+        for (i = 0; i < words; i++) {
+            /* Send the READ command (opcode + addr)  */
+            em_shift_out_ee_bits(hw, EEPROM_READ_OPCODE_MICROWIRE,
+                                    eeprom->opcode_bits);
+            em_shift_out_ee_bits(hw, (uint16_t)(offset + i),
+                                    eeprom->address_bits);
+
+            /* Read the data.  For microwire, each word requires the overhead
+             * of eeprom setup and tear-down. */
+            data[i] = em_shift_in_ee_bits(hw, 16);
+            em_standby_eeprom(hw);
+        }
+    }
+
+    /* End this read operation */
+    em_release_eeprom(hw);
+
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Reads a 16 bit word from the EEPROM using the EERD register.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset of  word in the EEPROM to read
+ * data - word read from the EEPROM
+ * words - number of words to read
+ *****************************************************************************/
+int32_t
+em_read_eeprom_eerd(struct em_hw *hw,
+                  uint16_t offset,
+                  uint16_t words,
+                  uint16_t *data)
+{
+    uint32_t i, eerd = 0;
+    int32_t error = 0;
+
+    for (i = 0; i < words; i++) {
+        eerd = ((offset+i) << E1000_EEPROM_RW_ADDR_SHIFT) +
+                         E1000_EEPROM_RW_REG_START;
+
+        E1000_WRITE_REG(hw, EERD, eerd);
+        error = em_poll_eerd_eewr_done(hw, E1000_EEPROM_POLL_READ);
+        
+        if(error) {
+            break;
+        }
+        data[i] = (E1000_READ_REG(hw, EERD) >> E1000_EEPROM_RW_REG_DATA);
+      
+    }
+    
+    return error;
+}
+
+/******************************************************************************
+ * Writes a 16 bit word from the EEPROM using the EEWR register.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset of  word in the EEPROM to read
+ * data - word read from the EEPROM
+ * words - number of words to read
+ *****************************************************************************/
+int32_t
+em_write_eeprom_eewr(struct em_hw *hw,
+                   uint16_t offset,
+                   uint16_t words,
+                   uint16_t *data)
+{
+    uint32_t    register_value = 0;
+    uint32_t    i              = 0;
+    int32_t     error          = 0;
+
+    for (i = 0; i < words; i++) {
+        register_value = (data[i] << E1000_EEPROM_RW_REG_DATA) | 
+                         ((offset+i) << E1000_EEPROM_RW_ADDR_SHIFT) | 
+                         E1000_EEPROM_RW_REG_START;
+
+        error = em_poll_eerd_eewr_done(hw, E1000_EEPROM_POLL_WRITE);
+        if(error) {
+            break;
+        }       
+
+        E1000_WRITE_REG(hw, EEWR, register_value);
+        
+        error = em_poll_eerd_eewr_done(hw, E1000_EEPROM_POLL_WRITE);
+        
+        if(error) {
+            break;
+        }       
+    }
+    
+    return error;
+}
+
+/******************************************************************************
+ * Polls the status bit (bit 1) of the EERD to determine when the read is done.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+em_poll_eerd_eewr_done(struct em_hw *hw, int eerd)
+{
+    uint32_t attempts = 100000;
+    uint32_t i, reg = 0;
+    int32_t done = E1000_ERR_EEPROM;
+
+    for(i = 0; i < attempts; i++) {
+        if(eerd == E1000_EEPROM_POLL_READ)
+            reg = E1000_READ_REG(hw, EERD);
+        else 
+            reg = E1000_READ_REG(hw, EEWR);
+
+        if(reg & E1000_EEPROM_RW_REG_DONE) {
+            done = E1000_SUCCESS;
+            break;
+        }
+        usec_delay(5);
+    }
+
+    return done;
+}
+
+/***************************************************************************
+* Description:     Determines if the onboard NVM is FLASH or EEPROM.
+*
+* hw - Struct containing variables accessed by shared code
+****************************************************************************/
+boolean_t
+em_is_onboard_nvm_eeprom(struct em_hw *hw)
+{
+    uint32_t eecd = 0;
+
+    if(hw->mac_type == em_82573) {
+        eecd = E1000_READ_REG(hw, EECD);
+
+        /* Isolate bits 15 & 16 */
+        eecd = ((eecd >> 15) & 0x03);
+
+        /* If both bits are set, device is Flash type */
+        if(eecd == 0x03) {
+            return FALSE;
+        }
+    }
+    return TRUE;
+}
+
+/******************************************************************************
+ * Verifies that the EEPROM has a valid checksum
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Reads the first 64 16 bit words of the EEPROM and sums the values read.
+ * If the the sum of the 64 16 bit words is 0xBABA, the EEPROM's checksum is
+ * valid.
+ *****************************************************************************/
+int32_t
+em_validate_eeprom_checksum(struct em_hw *hw)
+{
+    uint16_t checksum = 0;
+    uint16_t i, eeprom_data;
+
+    DEBUGFUNC("em_validate_eeprom_checksum");
+
+    if ((hw->mac_type == em_82573) &&
+        (em_is_onboard_nvm_eeprom(hw) == FALSE)) {
+        /* Check bit 4 of word 10h.  If it is 0, firmware is done updating
+         * 10h-12h.  Checksum may need to be fixed. */
+        em_read_eeprom(hw, 0x10, 1, &eeprom_data);
+        if ((eeprom_data & 0x10) == 0) {
+            /* Read 0x23 and check bit 15.  This bit is a 1 when the checksum
+             * has already been fixed.  If the checksum is still wrong and this
+             * bit is a 1, we need to return bad checksum.  Otherwise, we need
+             * to set this bit to a 1 and update the checksum. */
+            em_read_eeprom(hw, 0x23, 1, &eeprom_data);
+            if ((eeprom_data & 0x8000) == 0) {
+                eeprom_data |= 0x8000;
+                em_write_eeprom(hw, 0x23, 1, &eeprom_data);
+                em_update_eeprom_checksum(hw);
+            }
+        }
+    }
+
+    for(i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) {
+        if(em_read_eeprom(hw, i, 1, &eeprom_data) < 0) {
+            DEBUGOUT("EEPROM Read Error\n");
+            return -E1000_ERR_EEPROM;
+        }
+        checksum += eeprom_data;
+    }
+
+    if(checksum == (uint16_t) EEPROM_SUM)
+        return E1000_SUCCESS;
+    else {
+        DEBUGOUT("EEPROM Checksum Invalid\n");
+        return -E1000_ERR_EEPROM;
+    }
+}
+
+/******************************************************************************
+ * Calculates the EEPROM checksum and writes it to the EEPROM
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Sums the first 63 16 bit words of the EEPROM. Subtracts the sum from 0xBABA.
+ * Writes the difference to word offset 63 of the EEPROM.
+ *****************************************************************************/
+int32_t
+em_update_eeprom_checksum(struct em_hw *hw)
+{
+    uint16_t checksum = 0;
+    uint16_t i, eeprom_data;
+
+    DEBUGFUNC("em_update_eeprom_checksum");
+
+    for(i = 0; i < EEPROM_CHECKSUM_REG; i++) {
+        if(em_read_eeprom(hw, i, 1, &eeprom_data) < 0) {
+            DEBUGOUT("EEPROM Read Error\n");
+            return -E1000_ERR_EEPROM;
+        }
+        checksum += eeprom_data;
+    }
+    checksum = (uint16_t) EEPROM_SUM - checksum;
+    if(em_write_eeprom(hw, EEPROM_CHECKSUM_REG, 1, &checksum) < 0) {
+        DEBUGOUT("EEPROM Write Error\n");
+        return -E1000_ERR_EEPROM;
+    } else if (hw->eeprom.type == em_eeprom_flash) {
+        em_commit_shadow_ram(hw);
+    }
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Parent function for writing words to the different EEPROM types.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset within the EEPROM to be written to
+ * words - number of words to write
+ * data - 16 bit word to be written to the EEPROM
+ *
+ * If em_update_eeprom_checksum is not called after this function, the
+ * EEPROM will most likely contain an invalid checksum.
+ *****************************************************************************/
+int32_t
+em_write_eeprom(struct em_hw *hw,
+                   uint16_t offset,
+                   uint16_t words,
+                   uint16_t *data)
+{
+    struct em_eeprom_info *eeprom = &hw->eeprom;
+    int32_t status = 0;
+
+    DEBUGFUNC("em_write_eeprom");
+
+    /* A check for invalid values:  offset too large, too many words, and not
+     * enough words.
+     */
+    if((offset >= eeprom->word_size) || (words > eeprom->word_size - offset) ||
+       (words == 0)) {
+        DEBUGOUT("\"words\" parameter out of bounds\n");
+        return -E1000_ERR_EEPROM;
+    }
+
+    /* 82573 reads only through eerd */
+    if(eeprom->use_eewr == TRUE)
+        return em_write_eeprom_eewr(hw, offset, words, data);
+
+    /* Prepare the EEPROM for writing  */
+    if (em_acquire_eeprom(hw) != E1000_SUCCESS)
+        return -E1000_ERR_EEPROM;
+
+    if(eeprom->type == em_eeprom_microwire) {
+        status = em_write_eeprom_microwire(hw, offset, words, data);
+    } else {
+        status = em_write_eeprom_spi(hw, offset, words, data);
+        msec_delay(10);
+    }
+
+    /* Done with writing */
+    em_release_eeprom(hw);
+
+    return status;
+}
+
+/******************************************************************************
+ * Writes a 16 bit word to a given offset in an SPI EEPROM.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset within the EEPROM to be written to
+ * words - number of words to write
+ * data - pointer to array of 8 bit words to be written to the EEPROM
+ *
+ *****************************************************************************/
+int32_t
+em_write_eeprom_spi(struct em_hw *hw,
+                       uint16_t offset,
+                       uint16_t words,
+                       uint16_t *data)
+{
+    struct em_eeprom_info *eeprom = &hw->eeprom;
+    uint16_t widx = 0;
+
+    DEBUGFUNC("em_write_eeprom_spi");
+
+    while (widx < words) {
+        uint8_t write_opcode = EEPROM_WRITE_OPCODE_SPI;
+
+        if(em_spi_eeprom_ready(hw)) return -E1000_ERR_EEPROM;
+
+        em_standby_eeprom(hw);
+
+        /*  Send the WRITE ENABLE command (8 bit opcode )  */
+        em_shift_out_ee_bits(hw, EEPROM_WREN_OPCODE_SPI,
+                                    eeprom->opcode_bits);
+
+        em_standby_eeprom(hw);
+
+        /* Some SPI eeproms use the 8th address bit embedded in the opcode */
+        if((eeprom->address_bits == 8) && (offset >= 128))
+            write_opcode |= EEPROM_A8_OPCODE_SPI;
+
+        /* Send the Write command (8-bit opcode + addr) */
+        em_shift_out_ee_bits(hw, write_opcode, eeprom->opcode_bits);
+
+        em_shift_out_ee_bits(hw, (uint16_t)((offset + widx)*2),
+                                eeprom->address_bits);
+
+        /* Send the data */
+
+        /* Loop to allow for up to whole page write (32 bytes) of eeprom */
+        while (widx < words) {
+            uint16_t word_out = data[widx];
+            word_out = (word_out >> 8) | (word_out << 8);
+            em_shift_out_ee_bits(hw, word_out, 16);
+            widx++;
+
+            /* Some larger eeprom sizes are capable of a 32-byte PAGE WRITE
+             * operation, while the smaller eeproms are capable of an 8-byte
+             * PAGE WRITE operation.  Break the inner loop to pass new address
+             */
+            if((((offset + widx)*2) % eeprom->page_size) == 0) {
+                em_standby_eeprom(hw);
+                break;
+            }
+        }
+    }
+
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Writes a 16 bit word to a given offset in a Microwire EEPROM.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset within the EEPROM to be written to
+ * words - number of words to write
+ * data - pointer to array of 16 bit words to be written to the EEPROM
+ *
+ *****************************************************************************/
+int32_t
+em_write_eeprom_microwire(struct em_hw *hw,
+                             uint16_t offset,
+                             uint16_t words,
+                             uint16_t *data)
+{
+    struct em_eeprom_info *eeprom = &hw->eeprom;
+    uint32_t eecd;
+    uint16_t words_written = 0;
+    uint16_t i = 0;
+
+    DEBUGFUNC("em_write_eeprom_microwire");
+
+    /* Send the write enable command to the EEPROM (3-bit opcode plus
+     * 6/8-bit dummy address beginning with 11).  It's less work to include
+     * the 11 of the dummy address as part of the opcode than it is to shift
+     * it over the correct number of bits for the address.  This puts the
+     * EEPROM into write/erase mode.
+     */
+    em_shift_out_ee_bits(hw, EEPROM_EWEN_OPCODE_MICROWIRE,
+                            (uint16_t)(eeprom->opcode_bits + 2));
+
+    em_shift_out_ee_bits(hw, 0, (uint16_t)(eeprom->address_bits - 2));
+
+    /* Prepare the EEPROM */
+    em_standby_eeprom(hw);
+
+    while (words_written < words) {
+        /* Send the Write command (3-bit opcode + addr) */
+        em_shift_out_ee_bits(hw, EEPROM_WRITE_OPCODE_MICROWIRE,
+                                eeprom->opcode_bits);
+
+        em_shift_out_ee_bits(hw, (uint16_t)(offset + words_written),
+                                eeprom->address_bits);
+
+        /* Send the data */
+        em_shift_out_ee_bits(hw, data[words_written], 16);
+
+        /* Toggle the CS line.  This in effect tells the EEPROM to execute
+         * the previous command.
+         */
+        em_standby_eeprom(hw);
+
+        /* Read DO repeatedly until it is high (equal to '1').  The EEPROM will
+         * signal that the command has been completed by raising the DO signal.
+         * If DO does not go high in 10 milliseconds, then error out.
+         */
+        for(i = 0; i < 200; i++) {
+            eecd = E1000_READ_REG(hw, EECD);
+            if(eecd & E1000_EECD_DO) break;
+            usec_delay(50);
+        }
+        if(i == 200) {
+            DEBUGOUT("EEPROM Write did not complete\n");
+            return -E1000_ERR_EEPROM;
+        }
+
+        /* Recover from write */
+        em_standby_eeprom(hw);
+
+        words_written++;
+    }
+
+    /* Send the write disable command to the EEPROM (3-bit opcode plus
+     * 6/8-bit dummy address beginning with 10).  It's less work to include
+     * the 10 of the dummy address as part of the opcode than it is to shift
+     * it over the correct number of bits for the address.  This takes the
+     * EEPROM out of write/erase mode.
+     */
+    em_shift_out_ee_bits(hw, EEPROM_EWDS_OPCODE_MICROWIRE,
+                            (uint16_t)(eeprom->opcode_bits + 2));
+
+    em_shift_out_ee_bits(hw, 0, (uint16_t)(eeprom->address_bits - 2));
+
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Flushes the cached eeprom to NVM. This is done by saving the modified values
+ * in the eeprom cache and the non modified values in the currently active bank
+ * to the new bank.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset of  word in the EEPROM to read
+ * data - word read from the EEPROM
+ * words - number of words to read
+ *****************************************************************************/
+int32_t
+em_commit_shadow_ram(struct em_hw *hw)
+{
+    uint32_t attempts = 100000;
+    uint32_t eecd = 0;
+    uint32_t flop = 0;
+    uint32_t i = 0;
+    int32_t error = E1000_SUCCESS;
+
+    /* The flop register will be used to determine if flash type is STM */
+    flop = E1000_READ_REG(hw, FLOP);
+
+    if (hw->mac_type == em_82573) {
+        for (i=0; i < attempts; i++) {
+            eecd = E1000_READ_REG(hw, EECD);
+            if ((eecd & E1000_EECD_FLUPD) == 0) {
+                break;
+            }
+            usec_delay(5);
+        }
+
+        if (i == attempts) {
+            return -E1000_ERR_EEPROM;
+        }
+
+	/* If STM opcode located in bits 15:8 of flop, reset firmware */
+        if ((flop & 0xFF00) == E1000_STM_OPCODE) {
+            E1000_WRITE_REG(hw, HICR, E1000_HICR_FW_RESET);
+        }
+
+        /* Perform the flash update */
+        E1000_WRITE_REG(hw, EECD, eecd | E1000_EECD_FLUPD);
+
+	for (i=0; i < attempts; i++) {
+            eecd = E1000_READ_REG(hw, EECD);
+            if ((eecd & E1000_EECD_FLUPD) == 0) {
+                break;
+            }
+            usec_delay(5);
+        }
+
+        if (i == attempts) {
+            return -E1000_ERR_EEPROM;
+        }
+    }
+
+    return error;
+}
+
+/******************************************************************************
+ * Reads the adapter's part number from the EEPROM
+ *
+ * hw - Struct containing variables accessed by shared code
+ * part_num - Adapter's part number
+ *****************************************************************************/
+int32_t
+em_read_part_num(struct em_hw *hw,
+                    uint32_t *part_num)
+{
+    uint16_t offset = EEPROM_PBA_BYTE_1;
+    uint16_t eeprom_data;
+
+    DEBUGFUNC("em_read_part_num");
+
+    /* Get word 0 from EEPROM */
+    if(em_read_eeprom(hw, offset, 1, &eeprom_data) < 0) {
+        DEBUGOUT("EEPROM Read Error\n");
+        return -E1000_ERR_EEPROM;
+    }
+    /* Save word 0 in upper half of part_num */
+    *part_num = (uint32_t) (eeprom_data << 16);
+
+    /* Get word 1 from EEPROM */
+    if(em_read_eeprom(hw, ++offset, 1, &eeprom_data) < 0) {
+        DEBUGOUT("EEPROM Read Error\n");
+        return -E1000_ERR_EEPROM;
+    }
+    /* Save word 1 in lower half of part_num */
+    *part_num |= eeprom_data;
+
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Reads the adapter's MAC address from the EEPROM and inverts the LSB for the
+ * second function of dual function devices
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+em_read_mac_addr(struct em_hw * hw)
+{
+    uint16_t offset;
+    uint16_t eeprom_data, i;
+
+    DEBUGFUNC("em_read_mac_addr");
+
+    for(i = 0; i < NODE_ADDRESS_SIZE; i += 2) {
+        offset = i >> 1;
+        if(em_read_eeprom(hw, offset, 1, &eeprom_data) < 0) {
+            DEBUGOUT("EEPROM Read Error\n");
+            return -E1000_ERR_EEPROM;
+        }
+        hw->perm_mac_addr[i] = (uint8_t) (eeprom_data & 0x00FF);
+        hw->perm_mac_addr[i+1] = (uint8_t) (eeprom_data >> 8);
+    }
+    if(((hw->mac_type == em_82546) || (hw->mac_type == em_82546_rev_3)) &&
+       (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1))
+            hw->perm_mac_addr[5] ^= 0x01;
+
+    for(i = 0; i < NODE_ADDRESS_SIZE; i++)
+        hw->mac_addr[i] = hw->perm_mac_addr[i];
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Initializes receive address filters.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Places the MAC address in receive address register 0 and clears the rest
+ * of the receive addresss registers. Clears the multicast table. Assumes
+ * the receiver is in reset when the routine is called.
+ *****************************************************************************/
+void
+em_init_rx_addrs(struct em_hw *hw)
+{
+    uint32_t i;
+    uint32_t rar_num;
+
+    DEBUGFUNC("em_init_rx_addrs");
+
+    /* Setup the receive address. */
+    DEBUGOUT("Programming MAC Address into RAR[0]\n");
+
+    em_rar_set(hw, hw->mac_addr, 0);
+
+    rar_num = E1000_RAR_ENTRIES;
+    /* Zero out the other 15 receive addresses. */
+    DEBUGOUT("Clearing RAR[1-15]\n");
+    for(i = 1; i < rar_num; i++) {
+        E1000_WRITE_REG_ARRAY(hw, RA, (i << 1), 0);
+        E1000_WRITE_REG_ARRAY(hw, RA, ((i << 1) + 1), 0);
+    }
+}
+
+/******************************************************************************
+ * Updates the MAC's list of multicast addresses.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * mc_addr_list - the list of new multicast addresses
+ * mc_addr_count - number of addresses
+ * pad - number of bytes between addresses in the list
+ * rar_used_count - offset where to start adding mc addresses into the RAR's
+ *
+ * The given list replaces any existing list. Clears the last 15 receive
+ * address registers and the multicast table. Uses receive address registers
+ * for the first 15 multicast addresses, and hashes the rest into the
+ * multicast table.
+ *****************************************************************************/
+void
+em_mc_addr_list_update(struct em_hw *hw,
+                          uint8_t *mc_addr_list,
+                          uint32_t mc_addr_count,
+                          uint32_t pad,
+                          uint32_t rar_used_count)
+{
+    uint32_t hash_value;
+    uint32_t i;
+    uint32_t num_rar_entry;
+    uint32_t num_mta_entry;
+    
+    DEBUGFUNC("em_mc_addr_list_update");
+
+    /* Set the new number of MC addresses that we are being requested to use. */
+    hw->num_mc_addrs = mc_addr_count;
+
+    /* Clear RAR[1-15] */
+    DEBUGOUT(" Clearing RAR[1-15]\n");
+    num_rar_entry = E1000_RAR_ENTRIES;
+    for(i = rar_used_count; i < num_rar_entry; i++) {
+        E1000_WRITE_REG_ARRAY(hw, RA, (i << 1), 0);
+        E1000_WRITE_REG_ARRAY(hw, RA, ((i << 1) + 1), 0);
+    }
+
+    /* Clear the MTA */
+    DEBUGOUT(" Clearing MTA\n");
+    num_mta_entry = E1000_NUM_MTA_REGISTERS;
+    for(i = 0; i < num_mta_entry; i++) {
+        E1000_WRITE_REG_ARRAY(hw, MTA, i, 0);
+    }
+
+    /* Add the new addresses */
+    for(i = 0; i < mc_addr_count; i++) {
+        DEBUGOUT(" Adding the multicast addresses:\n");
+        DEBUGOUT7(" MC Addr #%d =%.2X %.2X %.2X %.2X %.2X %.2X\n", i,
+                  mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad)],
+                  mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 1],
+                  mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 2],
+                  mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 3],
+                  mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 4],
+                  mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 5]);
+
+        hash_value = em_hash_mc_addr(hw,
+                                        mc_addr_list +
+                                        (i * (ETH_LENGTH_OF_ADDRESS + pad)));
+
+        DEBUGOUT1(" Hash value = 0x%03X\n", hash_value);
+
+        /* Place this multicast address in the RAR if there is room, *
+         * else put it in the MTA
+         */
+        if (rar_used_count < num_rar_entry) {
+            em_rar_set(hw,
+                          mc_addr_list + (i * (ETH_LENGTH_OF_ADDRESS + pad)),
+                          rar_used_count);
+            rar_used_count++;
+        } else {
+            em_mta_set(hw, hash_value);
+        }
+    }
+    DEBUGOUT("MC Update Complete\n");
+}
+
+/******************************************************************************
+ * Hashes an address to determine its location in the multicast table
+ *
+ * hw - Struct containing variables accessed by shared code
+ * mc_addr - the multicast address to hash
+ *****************************************************************************/
+uint32_t
+em_hash_mc_addr(struct em_hw *hw,
+                   uint8_t *mc_addr)
+{
+    uint32_t hash_value = 0;
+
+    /* The portion of the address that is used for the hash table is
+     * determined by the mc_filter_type setting.
+     */
+    switch (hw->mc_filter_type) {
+    /* [0] [1] [2] [3] [4] [5]
+     * 01  AA  00  12  34  56
+     * LSB                 MSB
+     */
+    case 0:
+        /* [47:36] i.e. 0x563 for above example address */
+        hash_value = ((mc_addr[4] >> 4) | (((uint16_t) mc_addr[5]) << 4));
+        break;
+    case 1:
+        /* [46:35] i.e. 0xAC6 for above example address */
+        hash_value = ((mc_addr[4] >> 3) | (((uint16_t) mc_addr[5]) << 5));
+        break;
+    case 2:
+        /* [45:34] i.e. 0x5D8 for above example address */
+        hash_value = ((mc_addr[4] >> 2) | (((uint16_t) mc_addr[5]) << 6));
+        break;
+    case 3:
+        /* [43:32] i.e. 0x634 for above example address */
+        hash_value = ((mc_addr[4]) | (((uint16_t) mc_addr[5]) << 8));
+        break;
+    }
+
+    hash_value &= 0xFFF;
+
+    return hash_value;
+}
+
+/******************************************************************************
+ * Sets the bit in the multicast table corresponding to the hash value.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * hash_value - Multicast address hash value
+ *****************************************************************************/
+void
+em_mta_set(struct em_hw *hw,
+              uint32_t hash_value)
+{
+    uint32_t hash_bit, hash_reg;
+    uint32_t mta;
+    uint32_t temp;
+
+    /* The MTA is a register array of 128 32-bit registers.
+     * It is treated like an array of 4096 bits.  We want to set
+     * bit BitArray[hash_value]. So we figure out what register
+     * the bit is in, read it, OR in the new bit, then write
+     * back the new value.  The register is determined by the
+     * upper 7 bits of the hash value and the bit within that
+     * register are determined by the lower 5 bits of the value.
+     */
+    hash_reg = (hash_value >> 5) & 0x7F;
+    hash_bit = hash_value & 0x1F;
+
+    mta = E1000_READ_REG_ARRAY(hw, MTA, hash_reg);
+
+    mta |= (1 << hash_bit);
+
+    /* If we are on an 82544 and we are trying to write an odd offset
+     * in the MTA, save off the previous entry before writing and
+     * restore the old value after writing.
+     */
+    if((hw->mac_type == em_82544) && ((hash_reg & 0x1) == 1)) {
+        temp = E1000_READ_REG_ARRAY(hw, MTA, (hash_reg - 1));
+        E1000_WRITE_REG_ARRAY(hw, MTA, hash_reg, mta);
+        E1000_WRITE_REG_ARRAY(hw, MTA, (hash_reg - 1), temp);
+    } else {
+        E1000_WRITE_REG_ARRAY(hw, MTA, hash_reg, mta);
+    }
+}
+
+/******************************************************************************
+ * Puts an ethernet address into a receive address register.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * addr - Address to put into receive address register
+ * index - Receive address register to write
+ *****************************************************************************/
+void
+em_rar_set(struct em_hw *hw,
+              uint8_t *addr,
+              uint32_t index)
+{
+    uint32_t rar_low, rar_high;
+
+    /* HW expects these in little endian so we reverse the byte order
+     * from network order (big endian) to little endian
+     */
+    rar_low = ((uint32_t) addr[0] |
+               ((uint32_t) addr[1] << 8) |
+               ((uint32_t) addr[2] << 16) | ((uint32_t) addr[3] << 24));
+
+    rar_high = ((uint32_t) addr[4] | ((uint32_t) addr[5] << 8) | E1000_RAH_AV);
+
+    E1000_WRITE_REG_ARRAY(hw, RA, (index << 1), rar_low);
+    E1000_WRITE_REG_ARRAY(hw, RA, ((index << 1) + 1), rar_high);
+}
+
+/******************************************************************************
+ * Writes a value to the specified offset in the VLAN filter table.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - Offset in VLAN filer table to write
+ * value - Value to write into VLAN filter table
+ *****************************************************************************/
+void
+em_write_vfta(struct em_hw *hw,
+                 uint32_t offset,
+                 uint32_t value)
+{
+    uint32_t temp;
+
+    if((hw->mac_type == em_82544) && ((offset & 0x1) == 1)) {
+        temp = E1000_READ_REG_ARRAY(hw, VFTA, (offset - 1));
+        E1000_WRITE_REG_ARRAY(hw, VFTA, offset, value);
+        E1000_WRITE_REG_ARRAY(hw, VFTA, (offset - 1), temp);
+    } else {
+        E1000_WRITE_REG_ARRAY(hw, VFTA, offset, value);
+    }
+}
+
+/******************************************************************************
+ * Clears the VLAN filer table
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+void
+em_clear_vfta(struct em_hw *hw)
+{
+    uint32_t offset;
+    uint32_t vfta_value = 0;
+    uint32_t vfta_offset = 0;
+    uint32_t vfta_bit_in_reg = 0;
+
+    if (hw->mac_type == em_82573) {
+        if (hw->mng_cookie.vlan_id != 0) {
+            /* The VFTA is a 4096b bit-field, each identifying a single VLAN
+             * ID.  The following operations determine which 32b entry
+             * (i.e. offset) into the array we want to set the VLAN ID
+             * (i.e. bit) of the manageability unit. */
+            vfta_offset = (hw->mng_cookie.vlan_id >>
+                           E1000_VFTA_ENTRY_SHIFT) &
+                          E1000_VFTA_ENTRY_MASK;
+            vfta_bit_in_reg = 1 << (hw->mng_cookie.vlan_id &
+                                    E1000_VFTA_ENTRY_BIT_SHIFT_MASK);
+        }
+    }
+    for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) {
+        /* If the offset we want to clear is the same offset of the
+         * manageability VLAN ID, then clear all bits except that of the
+         * manageability unit */
+        vfta_value = (offset == vfta_offset) ? vfta_bit_in_reg : 0;
+        E1000_WRITE_REG_ARRAY(hw, VFTA, offset, vfta_value);
+    }
+}
+
+int32_t
+em_id_led_init(struct em_hw * hw)
+{
+    uint32_t ledctl;
+    const uint32_t ledctl_mask = 0x000000FF;
+    const uint32_t ledctl_on = E1000_LEDCTL_MODE_LED_ON;
+    const uint32_t ledctl_off = E1000_LEDCTL_MODE_LED_OFF;
+    uint16_t eeprom_data, i, temp;
+    const uint16_t led_mask = 0x0F;
+
+    DEBUGFUNC("em_id_led_init");
+
+    if(hw->mac_type < em_82540) {
+        /* Nothing to do */
+        return E1000_SUCCESS;
+    }
+
+    ledctl = E1000_READ_REG(hw, LEDCTL);
+    hw->ledctl_default = ledctl;
+    hw->ledctl_mode1 = hw->ledctl_default;
+    hw->ledctl_mode2 = hw->ledctl_default;
+
+    if(em_read_eeprom(hw, EEPROM_ID_LED_SETTINGS, 1, &eeprom_data) < 0) {
+        DEBUGOUT("EEPROM Read Error\n");
+        return -E1000_ERR_EEPROM;
+    }
+    if((eeprom_data== ID_LED_RESERVED_0000) ||
+       (eeprom_data == ID_LED_RESERVED_FFFF)) eeprom_data = ID_LED_DEFAULT;
+    for(i = 0; i < 4; i++) {
+        temp = (eeprom_data >> (i << 2)) & led_mask;
+        switch(temp) {
+        case ID_LED_ON1_DEF2:
+        case ID_LED_ON1_ON2:
+        case ID_LED_ON1_OFF2:
+            hw->ledctl_mode1 &= ~(ledctl_mask << (i << 3));
+            hw->ledctl_mode1 |= ledctl_on << (i << 3);
+            break;
+        case ID_LED_OFF1_DEF2:
+        case ID_LED_OFF1_ON2:
+        case ID_LED_OFF1_OFF2:
+            hw->ledctl_mode1 &= ~(ledctl_mask << (i << 3));
+            hw->ledctl_mode1 |= ledctl_off << (i << 3);
+            break;
+        default:
+            /* Do nothing */
+            break;
+        }
+        switch(temp) {
+        case ID_LED_DEF1_ON2:
+        case ID_LED_ON1_ON2:
+        case ID_LED_OFF1_ON2:
+            hw->ledctl_mode2 &= ~(ledctl_mask << (i << 3));
+            hw->ledctl_mode2 |= ledctl_on << (i << 3);
+            break;
+        case ID_LED_DEF1_OFF2:
+        case ID_LED_ON1_OFF2:
+        case ID_LED_OFF1_OFF2:
+            hw->ledctl_mode2 &= ~(ledctl_mask << (i << 3));
+            hw->ledctl_mode2 |= ledctl_off << (i << 3);
+            break;
+        default:
+            /* Do nothing */
+            break;
+        }
+    }
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Prepares SW controlable LED for use and saves the current state of the LED.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+em_setup_led(struct em_hw *hw)
+{
+    uint32_t ledctl;
+    int32_t ret_val = E1000_SUCCESS;
+
+    DEBUGFUNC("em_setup_led");
+
+    switch(hw->mac_type) {
+    case em_82542_rev2_0:
+    case em_82542_rev2_1:
+    case em_82543:
+    case em_82544:
+        /* No setup necessary */
+        break;
+    case em_82541:
+    case em_82547:
+    case em_82541_rev_2:
+    case em_82547_rev_2:
+        /* Turn off PHY Smart Power Down (if enabled) */
+        ret_val = em_read_phy_reg(hw, IGP01E1000_GMII_FIFO,
+                                     &hw->phy_spd_default);
+        if(ret_val)
+            return ret_val;
+        ret_val = em_write_phy_reg(hw, IGP01E1000_GMII_FIFO,
+                                      (uint16_t)(hw->phy_spd_default &
+                                      ~IGP01E1000_GMII_SPD));
+        if(ret_val)
+            return ret_val;
+        /* Fall Through */
+    default:
+        if(hw->media_type == em_media_type_fiber) {
+            ledctl = E1000_READ_REG(hw, LEDCTL);
+            /* Save current LEDCTL settings */
+            hw->ledctl_default = ledctl;
+            /* Turn off LED0 */
+            ledctl &= ~(E1000_LEDCTL_LED0_IVRT |
+                        E1000_LEDCTL_LED0_BLINK |
+                        E1000_LEDCTL_LED0_MODE_MASK);
+            ledctl |= (E1000_LEDCTL_MODE_LED_OFF <<
+                       E1000_LEDCTL_LED0_MODE_SHIFT);
+            E1000_WRITE_REG(hw, LEDCTL, ledctl);
+        } else if(hw->media_type == em_media_type_copper)
+            E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode1);
+        break;
+    }
+
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Restores the saved state of the SW controlable LED.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+em_cleanup_led(struct em_hw *hw)
+{
+    int32_t ret_val = E1000_SUCCESS;
+
+    DEBUGFUNC("em_cleanup_led");
+
+    switch(hw->mac_type) {
+    case em_82542_rev2_0:
+    case em_82542_rev2_1:
+    case em_82543:
+    case em_82544:
+        /* No cleanup necessary */
+        break;
+    case em_82541:
+    case em_82547:
+    case em_82541_rev_2:
+    case em_82547_rev_2:
+        /* Turn on PHY Smart Power Down (if previously enabled) */
+        ret_val = em_write_phy_reg(hw, IGP01E1000_GMII_FIFO,
+                                      hw->phy_spd_default);
+        if(ret_val)
+            return ret_val;
+        /* Fall Through */
+    default:
+        /* Restore LEDCTL settings */
+        E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_default);
+        break;
+    }
+
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Turns on the software controllable LED
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+em_led_on(struct em_hw *hw)
+{
+    uint32_t ctrl = E1000_READ_REG(hw, CTRL);
+
+    DEBUGFUNC("em_led_on");
+
+    switch(hw->mac_type) {
+    case em_82542_rev2_0:
+    case em_82542_rev2_1:
+    case em_82543:
+        /* Set SW Defineable Pin 0 to turn on the LED */
+        ctrl |= E1000_CTRL_SWDPIN0;
+        ctrl |= E1000_CTRL_SWDPIO0;
+        break;
+    case em_82544:
+        if(hw->media_type == em_media_type_fiber) {
+            /* Set SW Defineable Pin 0 to turn on the LED */
+            ctrl |= E1000_CTRL_SWDPIN0;
+            ctrl |= E1000_CTRL_SWDPIO0;
+        } else {
+            /* Clear SW Defineable Pin 0 to turn on the LED */
+            ctrl &= ~E1000_CTRL_SWDPIN0;
+            ctrl |= E1000_CTRL_SWDPIO0;
+        }
+        break;
+    default:
+        if(hw->media_type == em_media_type_fiber) {
+            /* Clear SW Defineable Pin 0 to turn on the LED */
+            ctrl &= ~E1000_CTRL_SWDPIN0;
+            ctrl |= E1000_CTRL_SWDPIO0;
+        } else if(hw->media_type == em_media_type_copper) {
+            E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode2);
+            return E1000_SUCCESS;
+        }
+        break;
+    }
+
+    E1000_WRITE_REG(hw, CTRL, ctrl);
+
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Turns off the software controllable LED
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+em_led_off(struct em_hw *hw)
+{
+    uint32_t ctrl = E1000_READ_REG(hw, CTRL);
+
+    DEBUGFUNC("em_led_off");
+
+    switch(hw->mac_type) {
+    case em_82542_rev2_0:
+    case em_82542_rev2_1:
+    case em_82543:
+        /* Clear SW Defineable Pin 0 to turn off the LED */
+        ctrl &= ~E1000_CTRL_SWDPIN0;
+        ctrl |= E1000_CTRL_SWDPIO0;
+        break;
+    case em_82544:
+        if(hw->media_type == em_media_type_fiber) {
+            /* Clear SW Defineable Pin 0 to turn off the LED */
+            ctrl &= ~E1000_CTRL_SWDPIN0;
+            ctrl |= E1000_CTRL_SWDPIO0;
+        } else {
+            /* Set SW Defineable Pin 0 to turn off the LED */
+            ctrl |= E1000_CTRL_SWDPIN0;
+            ctrl |= E1000_CTRL_SWDPIO0;
+        }
+        break;
+    default:
+        if(hw->media_type == em_media_type_fiber) {
+            /* Set SW Defineable Pin 0 to turn off the LED */
+            ctrl |= E1000_CTRL_SWDPIN0;
+            ctrl |= E1000_CTRL_SWDPIO0;
+        } else if(hw->media_type == em_media_type_copper) {
+            E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode1);
+            return E1000_SUCCESS;
+        }
+        break;
+    }
+
+    E1000_WRITE_REG(hw, CTRL, ctrl);
+
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Clears all hardware statistics counters.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+void
+em_clear_hw_cntrs(struct em_hw *hw)
+{
+    volatile uint32_t temp;
+
+    temp = E1000_READ_REG(hw, CRCERRS);
+    temp = E1000_READ_REG(hw, SYMERRS);
+    temp = E1000_READ_REG(hw, MPC);
+    temp = E1000_READ_REG(hw, SCC);
+    temp = E1000_READ_REG(hw, ECOL);
+    temp = E1000_READ_REG(hw, MCC);
+    temp = E1000_READ_REG(hw, LATECOL);
+    temp = E1000_READ_REG(hw, COLC);
+    temp = E1000_READ_REG(hw, DC);
+    temp = E1000_READ_REG(hw, SEC);
+    temp = E1000_READ_REG(hw, RLEC);
+    temp = E1000_READ_REG(hw, XONRXC);
+    temp = E1000_READ_REG(hw, XONTXC);
+    temp = E1000_READ_REG(hw, XOFFRXC);
+    temp = E1000_READ_REG(hw, XOFFTXC);
+    temp = E1000_READ_REG(hw, FCRUC);
+    temp = E1000_READ_REG(hw, PRC64);
+    temp = E1000_READ_REG(hw, PRC127);
+    temp = E1000_READ_REG(hw, PRC255);
+    temp = E1000_READ_REG(hw, PRC511);
+    temp = E1000_READ_REG(hw, PRC1023);
+    temp = E1000_READ_REG(hw, PRC1522);
+    temp = E1000_READ_REG(hw, GPRC);
+    temp = E1000_READ_REG(hw, BPRC);
+    temp = E1000_READ_REG(hw, MPRC);
+    temp = E1000_READ_REG(hw, GPTC);
+    temp = E1000_READ_REG(hw, GORCL);
+    temp = E1000_READ_REG(hw, GORCH);
+    temp = E1000_READ_REG(hw, GOTCL);
+    temp = E1000_READ_REG(hw, GOTCH);
+    temp = E1000_READ_REG(hw, RNBC);
+    temp = E1000_READ_REG(hw, RUC);
+    temp = E1000_READ_REG(hw, RFC);
+    temp = E1000_READ_REG(hw, ROC);
+    temp = E1000_READ_REG(hw, RJC);
+    temp = E1000_READ_REG(hw, TORL);
+    temp = E1000_READ_REG(hw, TORH);
+    temp = E1000_READ_REG(hw, TOTL);
+    temp = E1000_READ_REG(hw, TOTH);
+    temp = E1000_READ_REG(hw, TPR);
+    temp = E1000_READ_REG(hw, TPT);
+    temp = E1000_READ_REG(hw, PTC64);
+    temp = E1000_READ_REG(hw, PTC127);
+    temp = E1000_READ_REG(hw, PTC255);
+    temp = E1000_READ_REG(hw, PTC511);
+    temp = E1000_READ_REG(hw, PTC1023);
+    temp = E1000_READ_REG(hw, PTC1522);
+    temp = E1000_READ_REG(hw, MPTC);
+    temp = E1000_READ_REG(hw, BPTC);
+
+    if(hw->mac_type < em_82543) return;
+
+    temp = E1000_READ_REG(hw, ALGNERRC);
+    temp = E1000_READ_REG(hw, RXERRC);
+    temp = E1000_READ_REG(hw, TNCRS);
+    temp = E1000_READ_REG(hw, CEXTERR);
+    temp = E1000_READ_REG(hw, TSCTC);
+    temp = E1000_READ_REG(hw, TSCTFC);
+
+    if(hw->mac_type <= em_82544) return;
+
+    temp = E1000_READ_REG(hw, MGTPRC);
+    temp = E1000_READ_REG(hw, MGTPDC);
+    temp = E1000_READ_REG(hw, MGTPTC);
+
+    if(hw->mac_type <= em_82547_rev_2) return;
+
+    temp = E1000_READ_REG(hw, IAC);
+    temp = E1000_READ_REG(hw, ICRXOC);
+    temp = E1000_READ_REG(hw, ICRXPTC);
+    temp = E1000_READ_REG(hw, ICRXATC);
+    temp = E1000_READ_REG(hw, ICTXPTC);
+    temp = E1000_READ_REG(hw, ICTXATC);
+    temp = E1000_READ_REG(hw, ICTXQEC);
+    temp = E1000_READ_REG(hw, ICTXQMTC);
+    temp = E1000_READ_REG(hw, ICRXDMTC);
+
+}
+
+/******************************************************************************
+ * Resets Adaptive IFS to its default state.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Call this after em_init_hw. You may override the IFS defaults by setting
+ * hw->ifs_params_forced to TRUE. However, you must initialize hw->
+ * current_ifs_val, ifs_min_val, ifs_max_val, ifs_step_size, and ifs_ratio
+ * before calling this function.
+ *****************************************************************************/
+void
+em_reset_adaptive(struct em_hw *hw)
+{
+    DEBUGFUNC("em_reset_adaptive");
+
+    if(hw->adaptive_ifs) {
+        if(!hw->ifs_params_forced) {
+            hw->current_ifs_val = 0;
+            hw->ifs_min_val = IFS_MIN;
+            hw->ifs_max_val = IFS_MAX;
+            hw->ifs_step_size = IFS_STEP;
+            hw->ifs_ratio = IFS_RATIO;
+        }
+        hw->in_ifs_mode = FALSE;
+        E1000_WRITE_REG(hw, AIT, 0);
+    } else {
+        DEBUGOUT("Not in Adaptive IFS mode!\n");
+    }
+}
+
+/******************************************************************************
+ * Called during the callback/watchdog routine to update IFS value based on
+ * the ratio of transmits to collisions.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * tx_packets - Number of transmits since last callback
+ * total_collisions - Number of collisions since last callback
+ *****************************************************************************/
+void
+em_update_adaptive(struct em_hw *hw)
+{
+    DEBUGFUNC("em_update_adaptive");
+
+    if(hw->adaptive_ifs) {
+        if((hw->collision_delta * hw->ifs_ratio) > hw->tx_packet_delta) {
+            if(hw->tx_packet_delta > MIN_NUM_XMITS) {
+                hw->in_ifs_mode = TRUE;
+                if(hw->current_ifs_val < hw->ifs_max_val) {
+                    if(hw->current_ifs_val == 0)
+                        hw->current_ifs_val = hw->ifs_min_val;
+                    else
+                        hw->current_ifs_val += hw->ifs_step_size;
+                    E1000_WRITE_REG(hw, AIT, hw->current_ifs_val);
+                }
+            }
+        } else {
+            if(hw->in_ifs_mode && (hw->tx_packet_delta <= MIN_NUM_XMITS)) {
+                hw->current_ifs_val = 0;
+                hw->in_ifs_mode = FALSE;
+                E1000_WRITE_REG(hw, AIT, 0);
+            }
+        }
+    } else {
+        DEBUGOUT("Not in Adaptive IFS mode!\n");
+    }
+}
+
+/******************************************************************************
+ * Adjusts the statistic counters when a frame is accepted by TBI_ACCEPT
+ *
+ * hw - Struct containing variables accessed by shared code
+ * frame_len - The length of the frame in question
+ * mac_addr - The Ethernet destination address of the frame in question
+ *****************************************************************************/
+void
+em_tbi_adjust_stats(struct em_hw *hw,
+                       struct em_hw_stats *stats,
+                       uint32_t frame_len,
+                       uint8_t *mac_addr)
+{
+    uint64_t carry_bit;
+
+    /* First adjust the frame length. */
+    frame_len--;
+    /* We need to adjust the statistics counters, since the hardware
+     * counters overcount this packet as a CRC error and undercount
+     * the packet as a good packet
+     */
+    /* This packet should not be counted as a CRC error.    */
+    stats->crcerrs--;
+    /* This packet does count as a Good Packet Received.    */
+    stats->gprc++;
+
+    /* Adjust the Good Octets received counters             */
+    carry_bit = 0x80000000 & stats->gorcl;
+    stats->gorcl += frame_len;
+    /* If the high bit of Gorcl (the low 32 bits of the Good Octets
+     * Received Count) was one before the addition,
+     * AND it is zero after, then we lost the carry out,
+     * need to add one to Gorch (Good Octets Received Count High).
+     * This could be simplified if all environments supported
+     * 64-bit integers.
+     */
+    if(carry_bit && ((stats->gorcl & 0x80000000) == 0))
+        stats->gorch++;
+    /* Is this a broadcast or multicast?  Check broadcast first,
+     * since the test for a multicast frame will test positive on
+     * a broadcast frame.
+     */
+    if((mac_addr[0] == (uint8_t) 0xff) && (mac_addr[1] == (uint8_t) 0xff))
+        /* Broadcast packet */
+        stats->bprc++;
+    else if(*mac_addr & 0x01)
+        /* Multicast packet */
+        stats->mprc++;
+
+    if(frame_len == hw->max_frame_size) {
+        /* In this case, the hardware has overcounted the number of
+         * oversize frames.
+         */
+        if(stats->roc > 0)
+            stats->roc--;
+    }
+
+    /* Adjust the bin counters when the extra byte put the frame in the
+     * wrong bin. Remember that the frame_len was adjusted above.
+     */
+    if(frame_len == 64) {
+        stats->prc64++;
+        stats->prc127--;
+    } else if(frame_len == 127) {
+        stats->prc127++;
+        stats->prc255--;
+    } else if(frame_len == 255) {
+        stats->prc255++;
+        stats->prc511--;
+    } else if(frame_len == 511) {
+        stats->prc511++;
+        stats->prc1023--;
+    } else if(frame_len == 1023) {
+        stats->prc1023++;
+        stats->prc1522--;
+    } else if(frame_len == 1522) {
+        stats->prc1522++;
+    }
+}
+
+/******************************************************************************
+ * Gets the current PCI bus type, speed, and width of the hardware
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+void
+em_get_bus_info(struct em_hw *hw)
+{
+    uint32_t status;
+
+    switch (hw->mac_type) {
+    case em_82542_rev2_0:
+    case em_82542_rev2_1:
+        hw->bus_type = em_bus_type_unknown;
+        hw->bus_speed = em_bus_speed_unknown;
+        hw->bus_width = em_bus_width_unknown;
+        break;
+    case em_82573:
+        hw->bus_type = em_bus_type_pci_express;
+        hw->bus_speed = em_bus_speed_2500;
+        hw->bus_width = em_bus_width_pciex_4;
+        break;
+    default:
+        status = E1000_READ_REG(hw, STATUS);
+        hw->bus_type = (status & E1000_STATUS_PCIX_MODE) ?
+                       em_bus_type_pcix : em_bus_type_pci;
+
+        if(hw->device_id == E1000_DEV_ID_82546EB_QUAD_COPPER) {
+            hw->bus_speed = (hw->bus_type == em_bus_type_pci) ?
+                            em_bus_speed_66 : em_bus_speed_120;
+        } else if(hw->bus_type == em_bus_type_pci) {
+            hw->bus_speed = (status & E1000_STATUS_PCI66) ?
+                            em_bus_speed_66 : em_bus_speed_33;
+        } else {
+            switch (status & E1000_STATUS_PCIX_SPEED) {
+            case E1000_STATUS_PCIX_SPEED_66:
+                hw->bus_speed = em_bus_speed_66;
+                break;
+            case E1000_STATUS_PCIX_SPEED_100:
+                hw->bus_speed = em_bus_speed_100;
+                break;
+            case E1000_STATUS_PCIX_SPEED_133:
+                hw->bus_speed = em_bus_speed_133;
+                break;
+            default:
+                hw->bus_speed = em_bus_speed_reserved;
+                break;
+            }
+        }
+        hw->bus_width = (status & E1000_STATUS_BUS64) ?
+                        em_bus_width_64 : em_bus_width_32;
+        break;
+    }
+}
+/******************************************************************************
+ * Reads a value from one of the devices registers using port I/O (as opposed
+ * memory mapped I/O). Only 82544 and newer devices support port I/O.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset to read from
+ *****************************************************************************/
+uint32_t
+em_read_reg_io(struct em_hw *hw,
+                  uint32_t offset)
+{
+    unsigned long io_addr = hw->io_base;
+    unsigned long io_data = hw->io_base + 4;
+
+    em_io_write(hw, io_addr, offset);
+    return em_io_read(hw, io_data);
+}
+
+/******************************************************************************
+ * Writes a value to one of the devices registers using port I/O (as opposed to
+ * memory mapped I/O). Only 82544 and newer devices support port I/O.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset to write to
+ * value - value to write
+ *****************************************************************************/
+void
+em_write_reg_io(struct em_hw *hw,
+                   uint32_t offset,
+                   uint32_t value)
+{
+    unsigned long io_addr = hw->io_base;
+    unsigned long io_data = hw->io_base + 4;
+
+    em_io_write(hw, io_addr, offset);
+    em_io_write(hw, io_data, value);
+}
+
+
+/******************************************************************************
+ * Estimates the cable length.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * min_length - The estimated minimum length
+ * max_length - The estimated maximum length
+ *
+ * returns: - E1000_ERR_XXX
+ *            E1000_SUCCESS
+ *
+ * This function always returns a ranged length (minimum & maximum).
+ * So for M88 phy's, this function interprets the one value returned from the
+ * register to the minimum and maximum range.
+ * For IGP phy's, the function calculates the range by the AGC registers.
+ *****************************************************************************/
+int32_t
+em_get_cable_length(struct em_hw *hw,
+                       uint16_t *min_length,
+                       uint16_t *max_length)
+{
+    int32_t ret_val;
+    uint16_t agc_value = 0;
+    uint16_t cur_agc, min_agc = IGP01E1000_AGC_LENGTH_TABLE_SIZE;
+    uint16_t i, phy_data;
+    uint16_t cable_length;
+
+    DEBUGFUNC("em_get_cable_length");
+
+    *min_length = *max_length = 0;
+
+    /* Use old method for Phy older than IGP */
+    if(hw->phy_type == em_phy_m88) {
+
+        ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS,
+                                     &phy_data);
+        if(ret_val)
+            return ret_val;
+        cable_length = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
+                       M88E1000_PSSR_CABLE_LENGTH_SHIFT;
+
+        /* Convert the enum value to ranged values */
+        switch (cable_length) {
+        case em_cable_length_50:
+            *min_length = 0;
+            *max_length = em_igp_cable_length_50;
+            break;
+        case em_cable_length_50_80:
+            *min_length = em_igp_cable_length_50;
+            *max_length = em_igp_cable_length_80;
+            break;
+        case em_cable_length_80_110:
+            *min_length = em_igp_cable_length_80;
+            *max_length = em_igp_cable_length_110;
+            break;
+        case em_cable_length_110_140:
+            *min_length = em_igp_cable_length_110;
+            *max_length = em_igp_cable_length_140;
+            break;
+        case em_cable_length_140:
+            *min_length = em_igp_cable_length_140;
+            *max_length = em_igp_cable_length_170;
+            break;
+        default:
+            return -E1000_ERR_PHY;
+            break;
+        }
+    } else if(hw->phy_type == em_phy_igp) { /* For IGP PHY */
+        uint16_t agc_reg_array[IGP01E1000_PHY_CHANNEL_NUM] =
+                                                         {IGP01E1000_PHY_AGC_A,
+                                                          IGP01E1000_PHY_AGC_B,
+                                                          IGP01E1000_PHY_AGC_C,
+                                                          IGP01E1000_PHY_AGC_D};
+        /* Read the AGC registers for all channels */
+        for(i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
+
+            ret_val = em_read_phy_reg(hw, agc_reg_array[i], &phy_data);
+            if(ret_val)
+                return ret_val;
+
+            cur_agc = phy_data >> IGP01E1000_AGC_LENGTH_SHIFT;
+
+            /* Array bound check. */
+            if((cur_agc >= IGP01E1000_AGC_LENGTH_TABLE_SIZE - 1) ||
+               (cur_agc == 0))
+                return -E1000_ERR_PHY;
+
+            agc_value += cur_agc;
+
+            /* Update minimal AGC value. */
+            if(min_agc > cur_agc)
+                min_agc = cur_agc;
+        }
+
+        /* Remove the minimal AGC result for length < 50m */
+        if(agc_value < IGP01E1000_PHY_CHANNEL_NUM * em_igp_cable_length_50) {
+            agc_value -= min_agc;
+
+            /* Get the average length of the remaining 3 channels */
+            agc_value /= (IGP01E1000_PHY_CHANNEL_NUM - 1);
+        } else {
+            /* Get the average length of all the 4 channels. */
+            agc_value /= IGP01E1000_PHY_CHANNEL_NUM;
+        }
+
+        /* Set the range of the calculated length. */
+        *min_length = ((em_igp_cable_length_table[agc_value] -
+                       IGP01E1000_AGC_RANGE) > 0) ?
+                       (em_igp_cable_length_table[agc_value] -
+                       IGP01E1000_AGC_RANGE) : 0;
+        *max_length = em_igp_cable_length_table[agc_value] +
+                      IGP01E1000_AGC_RANGE;
+    }
+
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Check the cable polarity
+ *
+ * hw - Struct containing variables accessed by shared code
+ * polarity - output parameter : 0 - Polarity is not reversed
+ *                               1 - Polarity is reversed.
+ *
+ * returns: - E1000_ERR_XXX
+ *            E1000_SUCCESS
+ *
+ * For phy's older then IGP, this function simply reads the polarity bit in the
+ * Phy Status register.  For IGP phy's, this bit is valid only if link speed is
+ * 10 Mbps.  If the link speed is 100 Mbps there is no polarity so this bit will
+ * return 0.  If the link speed is 1000 Mbps the polarity status is in the
+ * IGP01E1000_PHY_PCS_INIT_REG.
+ *****************************************************************************/
+int32_t
+em_check_polarity(struct em_hw *hw,
+                     uint16_t *polarity)
+{
+    int32_t ret_val;
+    uint16_t phy_data;
+#ifdef __rtems__
+	*polarity = 0; /* keep compiler happy */
+#endif
+
+    DEBUGFUNC("em_check_polarity");
+
+    if(hw->phy_type == em_phy_m88) {
+        /* return the Polarity bit in the Status register. */
+        ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS,
+                                     &phy_data);
+        if(ret_val)
+            return ret_val;
+        *polarity = (phy_data & M88E1000_PSSR_REV_POLARITY) >>
+                    M88E1000_PSSR_REV_POLARITY_SHIFT;
+    } else if(hw->phy_type == em_phy_igp ||
+              hw->phy_type == em_phy_igp_2) {
+        /* Read the Status register to check the speed */
+        ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS,
+                                     &phy_data);
+        if(ret_val)
+            return ret_val;
+
+        /* If speed is 1000 Mbps, must read the IGP01E1000_PHY_PCS_INIT_REG to
+         * find the polarity status */
+        if((phy_data & IGP01E1000_PSSR_SPEED_MASK) ==
+           IGP01E1000_PSSR_SPEED_1000MBPS) {
+
+            /* Read the GIG initialization PCS register (0x00B4) */
+            ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PCS_INIT_REG,
+                                         &phy_data);
+            if(ret_val)
+                return ret_val;
+
+            /* Check the polarity bits */
+            *polarity = (phy_data & IGP01E1000_PHY_POLARITY_MASK) ? 1 : 0;
+        } else {
+            /* For 10 Mbps, read the polarity bit in the status register. (for
+             * 100 Mbps this bit is always 0) */
+            *polarity = phy_data & IGP01E1000_PSSR_POLARITY_REVERSED;
+        }
+    }
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Check if Downshift occured
+ *
+ * hw - Struct containing variables accessed by shared code
+ * downshift - output parameter : 0 - No Downshift ocured.
+ *                                1 - Downshift ocured.
+ *
+ * returns: - E1000_ERR_XXX
+ *            E1000_SUCCESS 
+ *
+ * For phy's older then IGP, this function reads the Downshift bit in the Phy
+ * Specific Status register.  For IGP phy's, it reads the Downgrade bit in the
+ * Link Health register.  In IGP this bit is latched high, so the driver must
+ * read it immediately after link is established.
+ *****************************************************************************/
+int32_t
+em_check_downshift(struct em_hw *hw)
+{
+    int32_t ret_val;
+    uint16_t phy_data;
+
+    DEBUGFUNC("em_check_downshift");
+
+    if(hw->phy_type == em_phy_igp || 
+        hw->phy_type == em_phy_igp_2) {
+        ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_LINK_HEALTH,
+                                     &phy_data);
+        if(ret_val)
+            return ret_val;
+
+        hw->speed_downgraded = (phy_data & IGP01E1000_PLHR_SS_DOWNGRADE) ? 1 : 0;
+    } else if(hw->phy_type == em_phy_m88) {
+        ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS,
+                                     &phy_data);
+        if(ret_val)
+            return ret_val;
+
+        hw->speed_downgraded = (phy_data & M88E1000_PSSR_DOWNSHIFT) >>
+                               M88E1000_PSSR_DOWNSHIFT_SHIFT;
+    }
+
+    return E1000_SUCCESS;
+}
+
+/*****************************************************************************
+ *
+ * 82541_rev_2 & 82547_rev_2 have the capability to configure the DSP when a
+ * gigabit link is achieved to improve link quality.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - E1000_ERR_PHY if fail to read/write the PHY
+ *            E1000_SUCCESS at any other case.
+ *
+ ****************************************************************************/
+
+int32_t
+em_config_dsp_after_link_change(struct em_hw *hw,
+                                   boolean_t link_up)
+{
+    int32_t ret_val;
+    uint16_t phy_data, phy_saved_data, speed, duplex, i;
+    uint16_t dsp_reg_array[IGP01E1000_PHY_CHANNEL_NUM] =
+                                        {IGP01E1000_PHY_AGC_PARAM_A,
+                                        IGP01E1000_PHY_AGC_PARAM_B,
+                                        IGP01E1000_PHY_AGC_PARAM_C,
+                                        IGP01E1000_PHY_AGC_PARAM_D};
+    uint16_t min_length, max_length;
+
+    DEBUGFUNC("em_config_dsp_after_link_change");
+
+    if(hw->phy_type != em_phy_igp)
+        return E1000_SUCCESS;
+
+    if(link_up) {
+        ret_val = em_get_speed_and_duplex(hw, &speed, &duplex);
+        if(ret_val) {
+            DEBUGOUT("Error getting link speed and duplex\n");
+            return ret_val;
+        }
+
+        if(speed == SPEED_1000) {
+
+            em_get_cable_length(hw, &min_length, &max_length);
+
+            if((hw->dsp_config_state == em_dsp_config_enabled) &&
+                min_length >= em_igp_cable_length_50) {
+
+                for(i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
+                    ret_val = em_read_phy_reg(hw, dsp_reg_array[i],
+                                                 &phy_data);
+                    if(ret_val)
+                        return ret_val;
+
+                    phy_data &= ~IGP01E1000_PHY_EDAC_MU_INDEX;
+
+                    ret_val = em_write_phy_reg(hw, dsp_reg_array[i],
+                                                  phy_data);
+                    if(ret_val)
+                        return ret_val;
+                }
+                hw->dsp_config_state = em_dsp_config_activated;
+            }
+
+            if((hw->ffe_config_state == em_ffe_config_enabled) &&
+               (min_length < em_igp_cable_length_50)) {
+
+                uint16_t ffe_idle_err_timeout = FFE_IDLE_ERR_COUNT_TIMEOUT_20;
+                uint32_t idle_errs = 0;
+
+                /* clear previous idle error counts */
+                ret_val = em_read_phy_reg(hw, PHY_1000T_STATUS,
+                                             &phy_data);
+                if(ret_val)
+                    return ret_val;
+
+                for(i = 0; i < ffe_idle_err_timeout; i++) {
+                    usec_delay(1000);
+                    ret_val = em_read_phy_reg(hw, PHY_1000T_STATUS,
+                                                 &phy_data);
+                    if(ret_val)
+                        return ret_val;
+
+                    idle_errs += (phy_data & SR_1000T_IDLE_ERROR_CNT);
+                    if(idle_errs > SR_1000T_PHY_EXCESSIVE_IDLE_ERR_COUNT) {
+                        hw->ffe_config_state = em_ffe_config_active;
+
+                        ret_val = em_write_phy_reg(hw,
+                                    IGP01E1000_PHY_DSP_FFE,
+                                    IGP01E1000_PHY_DSP_FFE_CM_CP);
+                        if(ret_val)
+                            return ret_val;
+                        break;
+                    }
+
+                    if(idle_errs)
+                        ffe_idle_err_timeout = FFE_IDLE_ERR_COUNT_TIMEOUT_100;
+                }
+            }
+        }
+    } else {
+        if(hw->dsp_config_state == em_dsp_config_activated) {
+            /* Save off the current value of register 0x2F5B to be restored at
+             * the end of the routines. */
+            ret_val = em_read_phy_reg(hw, 0x2F5B, &phy_saved_data);
+
+            if(ret_val)
+                return ret_val;
+
+            /* Disable the PHY transmitter */
+            ret_val = em_write_phy_reg(hw, 0x2F5B, 0x0003);
+
+            if(ret_val)
+                return ret_val;
+
+            msec_delay_irq(20);
+
+            ret_val = em_write_phy_reg(hw, 0x0000,
+                                          IGP01E1000_IEEE_FORCE_GIGA);
+            if(ret_val)
+                return ret_val;
+            for(i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
+                ret_val = em_read_phy_reg(hw, dsp_reg_array[i], &phy_data);
+                if(ret_val)
+                    return ret_val;
+
+                phy_data &= ~IGP01E1000_PHY_EDAC_MU_INDEX;
+                phy_data |=  IGP01E1000_PHY_EDAC_SIGN_EXT_9_BITS;
+
+                ret_val = em_write_phy_reg(hw,dsp_reg_array[i], phy_data);
+                if(ret_val)
+                    return ret_val;
+            }
+
+            ret_val = em_write_phy_reg(hw, 0x0000,
+                                          IGP01E1000_IEEE_RESTART_AUTONEG);
+            if(ret_val)
+                return ret_val;
+
+            msec_delay_irq(20);
+
+            /* Now enable the transmitter */
+            ret_val = em_write_phy_reg(hw, 0x2F5B, phy_saved_data);
+
+            if(ret_val)
+                return ret_val;
+
+            hw->dsp_config_state = em_dsp_config_enabled;
+        }
+
+        if(hw->ffe_config_state == em_ffe_config_active) {
+            /* Save off the current value of register 0x2F5B to be restored at
+             * the end of the routines. */
+            ret_val = em_read_phy_reg(hw, 0x2F5B, &phy_saved_data);
+
+            if(ret_val)
+                return ret_val;
+
+            /* Disable the PHY transmitter */
+            ret_val = em_write_phy_reg(hw, 0x2F5B, 0x0003);
+
+            if(ret_val)
+                return ret_val;
+
+            msec_delay_irq(20);
+
+            ret_val = em_write_phy_reg(hw, 0x0000,
+                                          IGP01E1000_IEEE_FORCE_GIGA);
+            if(ret_val)
+                return ret_val;
+            ret_val = em_write_phy_reg(hw, IGP01E1000_PHY_DSP_FFE,
+                                          IGP01E1000_PHY_DSP_FFE_DEFAULT);
+            if(ret_val)
+                return ret_val;
+
+            ret_val = em_write_phy_reg(hw, 0x0000,
+                                          IGP01E1000_IEEE_RESTART_AUTONEG);
+            if(ret_val)
+                return ret_val;
+
+            msec_delay_irq(20);
+
+            /* Now enable the transmitter */
+            ret_val = em_write_phy_reg(hw, 0x2F5B, phy_saved_data);
+
+            if(ret_val)
+                return ret_val;
+
+            hw->ffe_config_state = em_ffe_config_enabled;
+        }
+    }
+    return E1000_SUCCESS;
+}
+
+/*****************************************************************************
+ * Set PHY to class A mode
+ * Assumes the following operations will follow to enable the new class mode.
+ *  1. Do a PHY soft reset
+ *  2. Restart auto-negotiation or force link.
+ *
+ * hw - Struct containing variables accessed by shared code
+ ****************************************************************************/
+static int32_t
+em_set_phy_mode(struct em_hw *hw)
+{
+    int32_t ret_val;
+    uint16_t eeprom_data;
+
+    DEBUGFUNC("em_set_phy_mode");
+
+    if((hw->mac_type == em_82545_rev_3) &&
+       (hw->media_type == em_media_type_copper)) {
+        ret_val = em_read_eeprom(hw, EEPROM_PHY_CLASS_WORD, 1, &eeprom_data);
+        if(ret_val) {
+            return ret_val;
+        }
+
+        if((eeprom_data != EEPROM_RESERVED_WORD) &&
+           (eeprom_data & EEPROM_PHY_CLASS_A)) {
+            ret_val = em_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x000B);
+            if(ret_val)
+                return ret_val;
+            ret_val = em_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0x8104);
+            if(ret_val)
+                return ret_val;
+
+            hw->phy_reset_disable = FALSE;
+        }
+    }
+
+    return E1000_SUCCESS;
+}
+
+/*****************************************************************************
+ *
+ * This function sets the lplu state according to the active flag.  When
+ * activating lplu this function also disables smart speed and vise versa.
+ * lplu will not be activated unless the device autonegotiation advertisment
+ * meets standards of either 10 or 10/100 or 10/100/1000 at all duplexes.
+ * hw: Struct containing variables accessed by shared code
+ * active - true to enable lplu false to disable lplu.
+ *
+ * returns: - E1000_ERR_PHY if fail to read/write the PHY
+ *            E1000_SUCCESS at any other case.
+ *
+ ****************************************************************************/
+
+int32_t
+em_set_d3_lplu_state(struct em_hw *hw,
+                        boolean_t active)
+{
+    int32_t ret_val;
+    uint16_t phy_data;
+    DEBUGFUNC("em_set_d3_lplu_state");
+
+    if(hw->phy_type != em_phy_igp && hw->phy_type != em_phy_igp_2)
+        return E1000_SUCCESS;
+
+    /* During driver activity LPLU should not be used or it will attain link
+     * from the lowest speeds starting from 10Mbps. The capability is used for
+     * Dx transitions and states */
+    if(hw->mac_type == em_82541_rev_2 || hw->mac_type == em_82547_rev_2) {
+        ret_val = em_read_phy_reg(hw, IGP01E1000_GMII_FIFO, &phy_data);
+        if(ret_val)
+            return ret_val;
+    } else {
+        ret_val = em_read_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, &phy_data);
+        if(ret_val)
+            return ret_val;
+    }
+
+    if(!active) {
+        if(hw->mac_type == em_82541_rev_2 ||
+           hw->mac_type == em_82547_rev_2) {
+            phy_data &= ~IGP01E1000_GMII_FLEX_SPD;
+            ret_val = em_write_phy_reg(hw, IGP01E1000_GMII_FIFO, phy_data);
+            if(ret_val)
+                return ret_val;
+        } else {
+                phy_data &= ~IGP02E1000_PM_D3_LPLU;
+                ret_val = em_write_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT,
+                                              phy_data);
+                if (ret_val)
+                    return ret_val;
+        }
+
+        /* LPLU and SmartSpeed are mutually exclusive.  LPLU is used during
+         * Dx states where the power conservation is most important.  During
+         * driver activity we should enable SmartSpeed, so performance is
+         * maintained. */
+        if (hw->smart_speed == em_smart_speed_on) {
+            ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+                                         &phy_data);
+            if(ret_val)
+                return ret_val;
+
+            phy_data |= IGP01E1000_PSCFR_SMART_SPEED;
+            ret_val = em_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+                                          phy_data);
+            if(ret_val)
+                return ret_val;
+        } else if (hw->smart_speed == em_smart_speed_off) {
+            ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+                                         &phy_data);
+	    if (ret_val)
+                return ret_val;
+
+            phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+            ret_val = em_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+                                          phy_data);
+            if(ret_val)
+                return ret_val;
+        }
+
+    } else if((hw->autoneg_advertised == AUTONEG_ADVERTISE_SPEED_DEFAULT) ||
+              (hw->autoneg_advertised == AUTONEG_ADVERTISE_10_ALL ) ||
+              (hw->autoneg_advertised == AUTONEG_ADVERTISE_10_100_ALL)) {
+
+        if(hw->mac_type == em_82541_rev_2 ||
+           hw->mac_type == em_82547_rev_2) {
+            phy_data |= IGP01E1000_GMII_FLEX_SPD;
+            ret_val = em_write_phy_reg(hw, IGP01E1000_GMII_FIFO, phy_data);
+            if(ret_val)
+                return ret_val;
+        } else {
+                phy_data |= IGP02E1000_PM_D3_LPLU;
+                ret_val = em_write_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT,
+                                              phy_data);
+                if (ret_val)
+                    return ret_val;
+        }
+
+        /* When LPLU is enabled we should disable SmartSpeed */
+        ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, &phy_data);
+        if(ret_val)
+            return ret_val;
+
+        phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+        ret_val = em_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, phy_data);
+        if(ret_val)
+            return ret_val;
+
+    }
+    return E1000_SUCCESS;
+}
+
+/*****************************************************************************
+ *
+ * This function sets the lplu d0 state according to the active flag.  When
+ * activating lplu this function also disables smart speed and vise versa.
+ * lplu will not be activated unless the device autonegotiation advertisment
+ * meets standards of either 10 or 10/100 or 10/100/1000 at all duplexes.
+ * hw: Struct containing variables accessed by shared code
+ * active - true to enable lplu false to disable lplu.
+ *
+ * returns: - E1000_ERR_PHY if fail to read/write the PHY
+ *            E1000_SUCCESS at any other case.
+ *
+ ****************************************************************************/
+
+int32_t
+em_set_d0_lplu_state(struct em_hw *hw,
+                        boolean_t active)
+{
+    int32_t ret_val;
+    uint16_t phy_data;
+    DEBUGFUNC("em_set_d0_lplu_state");
+
+    if(hw->mac_type <= em_82547_rev_2)
+        return E1000_SUCCESS;
+
+        ret_val = em_read_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, &phy_data);
+        if(ret_val)
+            return ret_val;
+
+    if (!active) {
+            phy_data &= ~IGP02E1000_PM_D0_LPLU;
+            ret_val = em_write_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, phy_data);
+            if (ret_val)
+                return ret_val;
+
+        /* LPLU and SmartSpeed are mutually exclusive.  LPLU is used during
+         * Dx states where the power conservation is most important.  During
+         * driver activity we should enable SmartSpeed, so performance is
+         * maintained. */
+        if (hw->smart_speed == em_smart_speed_on) {
+            ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+                                         &phy_data);
+            if(ret_val)
+                return ret_val;
+
+            phy_data |= IGP01E1000_PSCFR_SMART_SPEED;
+            ret_val = em_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+                                          phy_data);
+            if(ret_val)
+                return ret_val;
+        } else if (hw->smart_speed == em_smart_speed_off) {
+            ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+                                         &phy_data);
+	    if (ret_val)
+                return ret_val;
+
+            phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+            ret_val = em_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+                                          phy_data);
+            if(ret_val)
+                return ret_val;
+        }
+
+
+    } else {
+ 
+            phy_data |= IGP02E1000_PM_D0_LPLU;   
+            ret_val = em_write_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, phy_data);
+            if (ret_val)
+                return ret_val;
+
+        /* When LPLU is enabled we should disable SmartSpeed */
+        ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, &phy_data);
+        if(ret_val)
+            return ret_val;
+
+        phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+        ret_val = em_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, phy_data);
+        if(ret_val)
+            return ret_val;
+
+    }
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Change VCO speed register to improve Bit Error Rate performance of SERDES.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static int32_t
+em_set_vco_speed(struct em_hw *hw)
+{
+    int32_t  ret_val;
+    uint16_t default_page = 0;
+    uint16_t phy_data;
+
+    DEBUGFUNC("em_set_vco_speed");
+
+    switch(hw->mac_type) {
+    case em_82545_rev_3:
+    case em_82546_rev_3:
+       break;
+    default:
+        return E1000_SUCCESS;
+    }
+
+    /* Set PHY register 30, page 5, bit 8 to 0 */
+
+    ret_val = em_read_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, &default_page);
+    if(ret_val)
+        return ret_val;
+
+    ret_val = em_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0005);
+    if(ret_val)
+        return ret_val;
+
+    ret_val = em_read_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, &phy_data);
+    if(ret_val)
+        return ret_val;
+
+    phy_data &= ~M88E1000_PHY_VCO_REG_BIT8;
+    ret_val = em_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, phy_data);
+    if(ret_val)
+        return ret_val;
+
+    /* Set PHY register 30, page 4, bit 11 to 1 */
+
+    ret_val = em_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0004);
+    if(ret_val)
+        return ret_val;
+
+    ret_val = em_read_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, &phy_data);
+    if(ret_val)
+        return ret_val;
+
+    phy_data |= M88E1000_PHY_VCO_REG_BIT11;
+    ret_val = em_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, phy_data);
+    if(ret_val)
+        return ret_val;
+
+    ret_val = em_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, default_page);
+    if(ret_val)
+        return ret_val;
+
+    return E1000_SUCCESS;
+}
+
+
+/*****************************************************************************
+ * This function reads the cookie from ARC ram.
+ *
+ * returns: - E1000_SUCCESS .
+ ****************************************************************************/
+int32_t
+em_host_if_read_cookie(struct em_hw * hw, uint8_t *buffer)
+{
+    uint8_t i;
+    uint32_t offset = E1000_MNG_DHCP_COOKIE_OFFSET; 
+    uint8_t length = E1000_MNG_DHCP_COOKIE_LENGTH;
+
+    length = (length >> 2);
+    offset = (offset >> 2);
+
+    for (i = 0; i < length; i++) {
+        *((uint32_t *) buffer + i) =
+            E1000_READ_REG_ARRAY_DWORD(hw, HOST_IF, offset + i);
+    }
+    return E1000_SUCCESS;
+}
+
+
+/*****************************************************************************
+ * This function checks whether the HOST IF is enabled for command operaton
+ * and also checks whether the previous command is completed.
+ * It busy waits in case of previous command is not completed.
+ *
+ * returns: - E1000_ERR_HOST_INTERFACE_COMMAND in case if is not ready or 
+ *            timeout
+ *          - E1000_SUCCESS for success.
+ ****************************************************************************/
+int32_t
+em_mng_enable_host_if(struct em_hw * hw)
+{
+    uint32_t hicr;
+    uint8_t i;
+
+    /* Check that the host interface is enabled. */
+    hicr = E1000_READ_REG(hw, HICR);
+    if ((hicr & E1000_HICR_EN) == 0) {
+        DEBUGOUT("E1000_HOST_EN bit disabled.\n");
+        return -E1000_ERR_HOST_INTERFACE_COMMAND;
+    }
+    /* check the previous command is completed */
+    for (i = 0; i < E1000_MNG_DHCP_COMMAND_TIMEOUT; i++) {
+        hicr = E1000_READ_REG(hw, HICR);
+        if (!(hicr & E1000_HICR_C))
+            break;
+        msec_delay_irq(1);
+    }
+
+    if (i == E1000_MNG_DHCP_COMMAND_TIMEOUT) { 
+        DEBUGOUT("Previous command timeout failed .\n");
+        return -E1000_ERR_HOST_INTERFACE_COMMAND;
+    }
+    return E1000_SUCCESS;
+}
+
+/*****************************************************************************
+ * This function writes the buffer content at the offset given on the host if.
+ * It also does alignment considerations to do the writes in most efficient way.
+ * Also fills up the sum of the buffer in *buffer parameter.
+ *
+ * returns  - E1000_SUCCESS for success.
+ ****************************************************************************/
+int32_t
+em_mng_host_if_write(struct em_hw * hw, uint8_t *buffer,
+                        uint16_t length, uint16_t offset, uint8_t *sum)
+{
+    uint8_t *tmp;
+    uint8_t *bufptr = buffer;
+    uint32_t data;
+    uint16_t remaining, i, j, prev_bytes;
+
+    /* sum = only sum of the data and it is not checksum */
+
+    if (length == 0 || offset + length > E1000_HI_MAX_MNG_DATA_LENGTH) {
+        return -E1000_ERR_PARAM;
+    }
+
+    tmp = (uint8_t *)&data;
+    prev_bytes = offset & 0x3;
+    offset &= 0xFFFC;
+    offset >>= 2;
+
+    if (prev_bytes) {
+        data = E1000_READ_REG_ARRAY_DWORD(hw, HOST_IF, offset);
+        for (j = prev_bytes; j < sizeof(uint32_t); j++) {
+            *(tmp + j) = *bufptr++;
+            *sum += *(tmp + j);
+        }
+        E1000_WRITE_REG_ARRAY_DWORD(hw, HOST_IF, offset, data);
+        length -= j - prev_bytes;
+        offset++;
+    }
+
+    remaining = length & 0x3;
+    length -= remaining;
+
+    /* Calculate length in DWORDs */
+    length >>= 2;
+
+    /* The device driver writes the relevant command block into the
+     * ram area. */
+    for (i = 0; i < length; i++) {
+        for (j = 0; j < sizeof(uint32_t); j++) {
+            *(tmp + j) = *bufptr++;
+            *sum += *(tmp + j);
+        }
+
+        E1000_WRITE_REG_ARRAY_DWORD(hw, HOST_IF, offset + i, data);
+    }
+    if (remaining) {
+        for (j = 0; j < sizeof(uint32_t); j++) {
+            if (j < remaining)
+                *(tmp + j) = *bufptr++;
+            else
+                *(tmp + j) = 0;
+
+            *sum += *(tmp + j);
+        }
+        E1000_WRITE_REG_ARRAY_DWORD(hw, HOST_IF, offset + i, data);
+    }
+
+    return E1000_SUCCESS;
+}
+
+
+/*****************************************************************************
+ * This function writes the command header after does the checksum calculation.
+ *
+ * returns  - E1000_SUCCESS for success.
+ ****************************************************************************/
+int32_t
+em_mng_write_cmd_header(struct em_hw * hw,
+                           struct em_host_mng_command_header * hdr)
+{
+    uint16_t i;
+    uint8_t sum;
+    uint8_t *buffer;
+
+    /* Write the whole command header structure which includes sum of
+     * the buffer */
+
+    uint16_t length = sizeof(struct em_host_mng_command_header);
+
+    sum = hdr->checksum;
+    hdr->checksum = 0;
+
+    buffer = (uint8_t *) hdr;
+    i = length;
+    while(i--)
+        sum += buffer[i];
+
+    hdr->checksum = 0 - sum;
+
+    length >>= 2;
+    /* The device driver writes the relevant command block into the ram area. */
+    for (i = 0; i < length; i++)
+        E1000_WRITE_REG_ARRAY_DWORD(hw, HOST_IF, i, *((uint32_t *) hdr + i));
+
+    return E1000_SUCCESS;
+}
+
+
+/*****************************************************************************
+ * This function indicates to ARC that a new command is pending which completes
+ * one write operation by the driver.
+ *
+ * returns  - E1000_SUCCESS for success.
+ ****************************************************************************/
+int32_t
+em_mng_write_commit(
+    struct em_hw * hw)
+{
+    uint32_t hicr;
+
+    hicr = E1000_READ_REG(hw, HICR);
+    /* Setting this bit tells the ARC that a new command is pending. */
+    E1000_WRITE_REG(hw, HICR, hicr | E1000_HICR_C);
+
+    return E1000_SUCCESS;
+}
+
+
+/*****************************************************************************
+ * This function checks the mode of the firmware.
+ *
+ * returns  - TRUE when the mode is IAMT or FALSE.
+ ****************************************************************************/
+boolean_t
+em_check_mng_mode(
+    struct em_hw *hw)
+{
+    uint32_t fwsm;
+
+    fwsm = E1000_READ_REG(hw, FWSM);
+
+    if((fwsm & E1000_FWSM_MODE_MASK) ==
+        (E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT))
+        return TRUE;
+
+    return FALSE;
+}
+
+
+/*****************************************************************************
+ * This function writes the dhcp info .
+ ****************************************************************************/
+int32_t
+em_mng_write_dhcp_info(struct em_hw * hw, uint8_t *buffer,
+			  uint16_t length)
+{
+    int32_t ret_val;
+    struct em_host_mng_command_header hdr;
+
+    hdr.command_id = E1000_MNG_DHCP_TX_PAYLOAD_CMD;
+    hdr.command_length = length;
+    hdr.reserved1 = 0;
+    hdr.reserved2 = 0;
+    hdr.checksum = 0;
+
+    ret_val = em_mng_enable_host_if(hw);
+    if (ret_val == E1000_SUCCESS) {
+        ret_val = em_mng_host_if_write(hw, buffer, length, sizeof(hdr),
+                                          &(hdr.checksum));
+        if (ret_val == E1000_SUCCESS) {
+            ret_val = em_mng_write_cmd_header(hw, &hdr);
+            if (ret_val == E1000_SUCCESS)
+                ret_val = em_mng_write_commit(hw);
+        }
+    }
+    return ret_val;
+}
+
+
+/*****************************************************************************
+ * This function calculates the checksum.
+ *
+ * returns  - checksum of buffer contents.
+ ****************************************************************************/
+uint8_t
+em_calculate_mng_checksum(char *buffer, uint32_t length)
+{
+    uint8_t sum = 0;
+    uint32_t i;
+
+    if (!buffer)
+        return 0;
+
+    for (i=0; i < length; i++)
+        sum += buffer[i];
+
+    return (uint8_t) (0 - sum);
+}
+
+/*****************************************************************************
+ * This function checks whether tx pkt filtering needs to be enabled or not.
+ *
+ * returns  - TRUE for packet filtering or FALSE.
+ ****************************************************************************/
+boolean_t
+em_enable_tx_pkt_filtering(struct em_hw *hw)
+{
+    /* called in init as well as watchdog timer functions */
+
+    int32_t ret_val, checksum;
+    boolean_t tx_filter = FALSE;
+    struct em_host_mng_dhcp_cookie *hdr = &(hw->mng_cookie);
+    uint8_t *buffer = (uint8_t *) &(hw->mng_cookie);
+
+    if (em_check_mng_mode(hw)) {
+        ret_val = em_mng_enable_host_if(hw);
+        if (ret_val == E1000_SUCCESS) {
+            ret_val = em_host_if_read_cookie(hw, buffer);
+            if (ret_val == E1000_SUCCESS) {
+                checksum = hdr->checksum;
+                hdr->checksum = 0;
+                if ((hdr->signature == E1000_IAMT_SIGNATURE) &&
+                    checksum == em_calculate_mng_checksum((char *)buffer,
+                                               E1000_MNG_DHCP_COOKIE_LENGTH)) {
+                    if (hdr->status &
+                        E1000_MNG_DHCP_COOKIE_STATUS_PARSING_SUPPORT)
+                        tx_filter = TRUE;
+                } else
+                    tx_filter = TRUE;
+            } else
+                tx_filter = TRUE;
+        }
+    }
+
+    hw->tx_pkt_filtering = tx_filter;
+    return tx_filter;
+}
+
+/******************************************************************************
+ * Verifies the hardware needs to allow ARPs to be processed by the host
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * returns: - TRUE/FALSE
+ *
+ *****************************************************************************/
+uint32_t
+em_enable_mng_pass_thru(struct em_hw *hw)
+{
+    uint32_t manc;
+    uint32_t fwsm, factps;
+
+    if (hw->asf_firmware_present) {
+        manc = E1000_READ_REG(hw, MANC);
+
+        if (!(manc & E1000_MANC_RCV_TCO_EN) ||
+            !(manc & E1000_MANC_EN_MAC_ADDR_FILTER))
+            return FALSE;
+        if (em_arc_subsystem_valid(hw) == TRUE) {
+            fwsm = E1000_READ_REG(hw, FWSM);
+            factps = E1000_READ_REG(hw, FACTPS);
+
+            if (((fwsm & E1000_FWSM_MODE_MASK) ==
+                (em_mng_mode_pt << E1000_FWSM_MODE_SHIFT)) &&
+                (factps & E1000_FACTPS_MNGCG))
+                return TRUE;
+        } else
+            if ((manc & E1000_MANC_SMBUS_EN) && !(manc & E1000_MANC_ASF_EN))
+                return TRUE;
+    }
+    return FALSE;
+}
+
+static int32_t
+em_polarity_reversal_workaround(struct em_hw *hw)
+{
+    int32_t ret_val;
+    uint16_t mii_status_reg;
+    uint16_t i;
+
+    /* Polarity reversal workaround for forced 10F/10H links. */
+
+    /* Disable the transmitter on the PHY */
+
+    ret_val = em_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0019);
+    if(ret_val)
+        return ret_val;
+    ret_val = em_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xFFFF);
+    if(ret_val)
+        return ret_val;
+
+    ret_val = em_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0000);
+    if(ret_val)
+        return ret_val;
+
+    /* This loop will early-out if the NO link condition has been met. */
+    for(i = PHY_FORCE_TIME; i > 0; i--) {
+        /* Read the MII Status Register and wait for Link Status bit
+         * to be clear.
+         */
+
+        ret_val = em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+        if(ret_val)
+            return ret_val;
+
+        ret_val = em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+        if(ret_val)
+            return ret_val;
+
+        if((mii_status_reg & ~MII_SR_LINK_STATUS) == 0) break;
+        msec_delay_irq(100);
+    }
+
+    /* Recommended delay time after link has been lost */
+    msec_delay_irq(1000);
+
+    /* Now we will re-enable th transmitter on the PHY */
+
+    ret_val = em_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0019);
+    if(ret_val)
+        return ret_val;
+    msec_delay_irq(50);
+    ret_val = em_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xFFF0);
+    if(ret_val)
+        return ret_val;
+    msec_delay_irq(50);
+    ret_val = em_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xFF00);
+    if(ret_val)
+        return ret_val;
+    msec_delay_irq(50);
+    ret_val = em_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0x0000);
+    if(ret_val)
+        return ret_val;
+
+    ret_val = em_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0000);
+    if(ret_val)
+        return ret_val;
+
+    /* This loop will early-out if the link condition has been met. */
+    for(i = PHY_FORCE_TIME; i > 0; i--) {
+        /* Read the MII Status Register and wait for Link Status bit
+         * to be set.
+         */
+
+        ret_val = em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+        if(ret_val)
+            return ret_val;
+
+        ret_val = em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+        if(ret_val)
+            return ret_val;
+
+        if(mii_status_reg & MII_SR_LINK_STATUS) break;
+        msec_delay_irq(100);
+    }
+    return E1000_SUCCESS;
+}
+
+/***************************************************************************
+ *
+ * Disables PCI-Express master access.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - none.
+ *
+ ***************************************************************************/
+void
+em_set_pci_express_master_disable(struct em_hw *hw)
+{
+    uint32_t ctrl;
+
+    DEBUGFUNC("em_set_pci_express_master_disable");
+
+    if (hw->bus_type != em_bus_type_pci_express)
+        return;
+
+    ctrl = E1000_READ_REG(hw, CTRL);
+    ctrl |= E1000_CTRL_GIO_MASTER_DISABLE;
+    E1000_WRITE_REG(hw, CTRL, ctrl);
+}
+
+/***************************************************************************
+ *
+ * Enables PCI-Express master access.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - none.
+ *
+ ***************************************************************************/
+void
+em_enable_pciex_master(struct em_hw *hw)
+{
+    uint32_t ctrl;
+
+    DEBUGFUNC("em_enable_pciex_master");
+
+    if (hw->bus_type != em_bus_type_pci_express)
+        return;
+
+    ctrl = E1000_READ_REG(hw, CTRL);
+    ctrl &= ~E1000_CTRL_GIO_MASTER_DISABLE;
+    E1000_WRITE_REG(hw, CTRL, ctrl);
+}
+
+/*******************************************************************************
+ *
+ * Disables PCI-Express master access and verifies there are no pending requests
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - E1000_ERR_MASTER_REQUESTS_PENDING if master disable bit hasn't
+ *            caused the master requests to be disabled.
+ *            E1000_SUCCESS master requests disabled.
+ *
+ ******************************************************************************/
+int32_t
+em_disable_pciex_master(struct em_hw *hw)
+{
+    int32_t timeout = MASTER_DISABLE_TIMEOUT;   /* 80ms */
+
+    DEBUGFUNC("em_disable_pciex_master");
+
+    if (hw->bus_type != em_bus_type_pci_express)
+        return E1000_SUCCESS;
+
+    em_set_pci_express_master_disable(hw);
+
+    while(timeout) {
+        if(!(E1000_READ_REG(hw, STATUS) & E1000_STATUS_GIO_MASTER_ENABLE))
+            break;
+        else
+            usec_delay(100);
+        timeout--;
+    }
+
+    if(!timeout) {
+        DEBUGOUT("Master requests are pending.\n");
+        return -E1000_ERR_MASTER_REQUESTS_PENDING;
+    }
+
+    return E1000_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Check for EEPROM Auto Read bit done.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - E1000_ERR_RESET if fail to reset MAC
+ *            E1000_SUCCESS at any other case.
+ *
+ ******************************************************************************/
+int32_t
+em_get_auto_rd_done(struct em_hw *hw)
+{
+    int32_t timeout = AUTO_READ_DONE_TIMEOUT;
+
+    DEBUGFUNC("em_get_auto_rd_done");
+
+    switch (hw->mac_type) {
+    default:
+        msec_delay(5);
+        break;
+    case em_82573:
+        while(timeout) {
+            if (E1000_READ_REG(hw, EECD) & E1000_EECD_AUTO_RD) break;
+            else msec_delay(1);
+            timeout--;
+        }
+
+        if(!timeout) {
+            DEBUGOUT("Auto read by HW from EEPROM has not completed.\n");
+            return -E1000_ERR_RESET;
+        }
+        break;
+    }
+
+    return E1000_SUCCESS;
+}
+
+/***************************************************************************
+ * Checks if the PHY configuration is done
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - E1000_ERR_RESET if fail to reset MAC
+ *            E1000_SUCCESS at any other case.
+ *
+ ***************************************************************************/
+int32_t
+em_get_phy_cfg_done(struct em_hw *hw)
+{
+    DEBUGFUNC("em_get_phy_cfg_done");
+
+    /* Simply wait for 10ms */
+    msec_delay(10);
+
+    return E1000_SUCCESS;
+}
+
+/***************************************************************************
+ *
+ * Using the combination of SMBI and SWESMBI semaphore bits when resetting
+ * adapter or Eeprom access.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - E1000_ERR_EEPROM if fail to access EEPROM.
+ *            E1000_SUCCESS at any other case.
+ *
+ ***************************************************************************/
+int32_t
+em_get_hw_eeprom_semaphore(struct em_hw *hw)
+{
+    int32_t timeout;
+    uint32_t swsm;
+
+    DEBUGFUNC("em_get_hw_eeprom_semaphore");
+
+    if(!hw->eeprom_semaphore_present)
+        return E1000_SUCCESS;
+
+
+    /* Get the FW semaphore. */
+    timeout = hw->eeprom.word_size + 1;
+    while(timeout) {
+        swsm = E1000_READ_REG(hw, SWSM);
+        swsm |= E1000_SWSM_SWESMBI;
+        E1000_WRITE_REG(hw, SWSM, swsm);
+        /* if we managed to set the bit we got the semaphore. */
+        swsm = E1000_READ_REG(hw, SWSM);
+        if(swsm & E1000_SWSM_SWESMBI)
+            break;
+
+        usec_delay(50);
+        timeout--;
+    }
+
+    if(!timeout) {
+        /* Release semaphores */
+        em_put_hw_eeprom_semaphore(hw);
+        DEBUGOUT("Driver can't access the Eeprom - SWESMBI bit is set.\n");
+        return -E1000_ERR_EEPROM;
+    }
+
+    return E1000_SUCCESS;
+}
+
+/***************************************************************************
+ * This function clears HW semaphore bits.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - None.
+ *
+ ***************************************************************************/
+void
+em_put_hw_eeprom_semaphore(struct em_hw *hw)
+{
+    uint32_t swsm;
+
+    DEBUGFUNC("em_put_hw_eeprom_semaphore");
+
+    if(!hw->eeprom_semaphore_present)
+        return;
+
+    swsm = E1000_READ_REG(hw, SWSM);
+    /* Release both semaphores. */
+    swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI);
+    E1000_WRITE_REG(hw, SWSM, swsm);
+}
+
+/******************************************************************************
+ * Checks if PHY reset is blocked due to SOL/IDER session, for example.
+ * Returning E1000_BLK_PHY_RESET isn't necessarily an error.  But it's up to
+ * the caller to figure out how to deal with it.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * returns: - E1000_BLK_PHY_RESET
+ *            E1000_SUCCESS
+ *
+ *****************************************************************************/
+int32_t
+em_check_phy_reset_block(struct em_hw *hw)
+{
+    uint32_t manc = 0;
+    if(hw->mac_type > em_82547_rev_2)
+        manc = E1000_READ_REG(hw, MANC);
+    return (manc & E1000_MANC_BLK_PHY_RST_ON_IDE) ?
+	    E1000_BLK_PHY_RESET : E1000_SUCCESS;
+}
+
+uint8_t
+em_arc_subsystem_valid(struct em_hw *hw)
+{
+    uint32_t fwsm;
+
+    /* On 8257x silicon, registers in the range of 0x8800 - 0x8FFC
+     * may not be provided a DMA clock when no manageability features are
+     * enabled.  We do not want to perform any reads/writes to these registers
+     * if this is the case.  We read FWSM to determine the manageability mode.
+     */
+    switch (hw->mac_type) {
+    case em_82573:
+        fwsm = E1000_READ_REG(hw, FWSM);
+        if((fwsm & E1000_FWSM_MODE_MASK) != 0)
+            return TRUE;
+        break;
+    default:
+        break;
+    }
+    return FALSE;
+}
+
+
+
Index: bsps/powerpc/beatnik/net/if_em/if_em_hw.h
===================================================================
--- bsps/powerpc/beatnik/net/if_em/if_em_hw.h	(revision 031df3914990db0336a0d386fb53558b05de467e)
+++ bsps/powerpc/beatnik/net/if_em/if_em_hw.h	(revision 031df3914990db0336a0d386fb53558b05de467e)
@@ -0,0 +1,2678 @@
+/*******************************************************************************
+
+  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: /repoman/r/ncvs/src/sys/dev/em/if_em_hw.h,v 1.15 2005/05/26 23:32:02 tackerman Exp $*/
+/* if_em_hw.h
+ * Structures, enums, and macros for the MAC
+ */
+
+#ifndef _EM_HW_H_
+#define _EM_HW_H_
+
+#ifndef __rtems__
+#include <dev/em/if_em_osdep.h>
+#else
+#include "if_em_osdep.h"
+#endif
+
+
+/* Forward declarations of structures used by the shared code */
+struct em_hw;
+struct em_hw_stats;
+
+/* Enumerated types specific to the e1000 hardware */
+/* Media Access Controlers */
+typedef enum {
+    em_undefined = 0,
+    em_82542_rev2_0,
+    em_82542_rev2_1,
+    em_82543,
+    em_82544,
+    em_82540,
+    em_82545,
+    em_82545_rev_3,
+    em_82546,
+    em_82546_rev_3,
+    em_82541,
+    em_82541_rev_2,
+    em_82547,
+    em_82547_rev_2,
+    em_82573,
+    em_num_macs
+} em_mac_type;
+
+typedef enum {
+    em_eeprom_uninitialized = 0,
+    em_eeprom_spi,
+    em_eeprom_microwire,
+    em_eeprom_flash,
+    em_num_eeprom_types
+} em_eeprom_type;
+
+/* Media Types */
+typedef enum {
+    em_media_type_copper = 0,
+    em_media_type_fiber = 1,
+    em_media_type_internal_serdes = 2,
+    em_num_media_types
+} em_media_type;
+
+typedef enum {
+    em_10_half = 0,
+    em_10_full = 1,
+    em_100_half = 2,
+    em_100_full = 3
+} em_speed_duplex_type;
+
+/* Flow Control Settings */
+typedef enum {
+    em_fc_none = 0,
+    em_fc_rx_pause = 1,
+    em_fc_tx_pause = 2,
+    em_fc_full = 3,
+    em_fc_default = 0xFF
+} em_fc_type;
+
+/* PCI bus types */
+typedef enum {
+    em_bus_type_unknown = 0,
+    em_bus_type_pci,
+    em_bus_type_pcix,
+    em_bus_type_pci_express,
+    em_bus_type_reserved
+} em_bus_type;
+
+/* PCI bus speeds */
+typedef enum {
+    em_bus_speed_unknown = 0,
+    em_bus_speed_33,
+    em_bus_speed_66,
+    em_bus_speed_100,
+    em_bus_speed_120,
+    em_bus_speed_133,
+    em_bus_speed_2500,
+    em_bus_speed_reserved
+} em_bus_speed;
+
+/* PCI bus widths */
+typedef enum {
+    em_bus_width_unknown = 0,
+    em_bus_width_32,
+    em_bus_width_64,
+    em_bus_width_pciex_1,
+    em_bus_width_pciex_4,
+    em_bus_width_reserved
+} em_bus_width;
+
+/* PHY status info structure and supporting enums */
+typedef enum {
+    em_cable_length_50 = 0,
+    em_cable_length_50_80,
+    em_cable_length_80_110,
+    em_cable_length_110_140,
+    em_cable_length_140,
+    em_cable_length_undefined = 0xFF
+} em_cable_length;
+
+typedef enum {
+    em_igp_cable_length_10  = 10,
+    em_igp_cable_length_20  = 20,
+    em_igp_cable_length_30  = 30,
+    em_igp_cable_length_40  = 40,
+    em_igp_cable_length_50  = 50,
+    em_igp_cable_length_60  = 60,
+    em_igp_cable_length_70  = 70,
+    em_igp_cable_length_80  = 80,
+    em_igp_cable_length_90  = 90,
+    em_igp_cable_length_100 = 100,
+    em_igp_cable_length_110 = 110,
+    em_igp_cable_length_120 = 120,
+    em_igp_cable_length_130 = 130,
+    em_igp_cable_length_140 = 140,
+    em_igp_cable_length_150 = 150,
+    em_igp_cable_length_160 = 160,
+    em_igp_cable_length_170 = 170,
+    em_igp_cable_length_180 = 180
+} em_igp_cable_length;
+
+typedef enum {
+    em_10bt_ext_dist_enable_normal = 0,
+    em_10bt_ext_dist_enable_lower,
+    em_10bt_ext_dist_enable_undefined = 0xFF
+} em_10bt_ext_dist_enable;
+
+typedef enum {
+    em_rev_polarity_normal = 0,
+    em_rev_polarity_reversed,
+    em_rev_polarity_undefined = 0xFF
+} em_rev_polarity;
+
+typedef enum {
+    em_downshift_normal = 0,
+    em_downshift_activated,
+    em_downshift_undefined = 0xFF
+} em_downshift;
+
+typedef enum {
+    em_smart_speed_default = 0,
+    em_smart_speed_on,
+    em_smart_speed_off
+} em_smart_speed;
+
+typedef enum {
+    em_polarity_reversal_enabled = 0,
+    em_polarity_reversal_disabled,
+    em_polarity_reversal_undefined = 0xFF
+} em_polarity_reversal;
+
+typedef enum {
+    em_auto_x_mode_manual_mdi = 0,
+    em_auto_x_mode_manual_mdix,
+    em_auto_x_mode_auto1,
+    em_auto_x_mode_auto2,
+    em_auto_x_mode_undefined = 0xFF
+} em_auto_x_mode;
+
+typedef enum {
+    em_1000t_rx_status_not_ok = 0,
+    em_1000t_rx_status_ok,
+    em_1000t_rx_status_undefined = 0xFF
+} em_1000t_rx_status;
+
+typedef enum {
+    em_phy_m88 = 0,
+    em_phy_igp,
+    em_phy_igp_2,
+    em_phy_undefined = 0xFF
+} em_phy_type;
+
+typedef enum {
+    em_ms_hw_default = 0,
+    em_ms_force_master,
+    em_ms_force_slave,
+    em_ms_auto
+} em_ms_type;
+
+typedef enum {
+    em_ffe_config_enabled = 0,
+    em_ffe_config_active,
+    em_ffe_config_blocked
+} em_ffe_config;
+
+typedef enum {
+    em_dsp_config_disabled = 0,
+    em_dsp_config_enabled,
+    em_dsp_config_activated,
+    em_dsp_config_undefined = 0xFF
+} em_dsp_config;
+
+struct em_phy_info {
+    em_cable_length cable_length;
+    em_10bt_ext_dist_enable extended_10bt_distance;
+    em_rev_polarity cable_polarity;
+    em_downshift downshift;
+    em_polarity_reversal polarity_correction;
+    em_auto_x_mode mdix_mode;
+    em_1000t_rx_status local_rx;
+    em_1000t_rx_status remote_rx;
+};
+
+struct em_phy_stats {
+    uint32_t idle_errors;
+    uint32_t receive_errors;
+};
+
+struct em_eeprom_info {
+    em_eeprom_type type;
+    uint16_t word_size;
+    uint16_t opcode_bits;
+    uint16_t address_bits;
+    uint16_t delay_usec;
+    uint16_t page_size;
+    boolean_t use_eerd;
+    boolean_t use_eewr;
+};
+
+/* Flex ASF Information */
+#define E1000_HOST_IF_MAX_SIZE  2048
+
+typedef enum {
+    em_byte_align = 0,
+    em_word_align = 1,
+    em_dword_align = 2
+} em_align_type;
+
+
+
+/* Error Codes */
+#define E1000_SUCCESS      0
+#define E1000_ERR_EEPROM   1
+#define E1000_ERR_PHY      2
+#define E1000_ERR_CONFIG   3
+#define E1000_ERR_PARAM    4
+#define E1000_ERR_MAC_TYPE 5
+#define E1000_ERR_PHY_TYPE 6
+#define E1000_ERR_RESET   9
+#define E1000_ERR_MASTER_REQUESTS_PENDING 10
+#define E1000_ERR_HOST_INTERFACE_COMMAND 11
+#define E1000_BLK_PHY_RESET   12
+
+/* Function prototypes */
+/* Initialization */
+int32_t em_reset_hw(struct em_hw *hw);
+int32_t em_init_hw(struct em_hw *hw);
+int32_t em_id_led_init(struct em_hw * hw);
+int32_t em_set_mac_type(struct em_hw *hw);
+void em_set_media_type(struct em_hw *hw);
+
+/* Link Configuration */
+int32_t em_setup_link(struct em_hw *hw);
+int32_t em_phy_setup_autoneg(struct em_hw *hw);
+void em_config_collision_dist(struct em_hw *hw);
+int32_t em_config_fc_after_link_up(struct em_hw *hw);
+int32_t em_check_for_link(struct em_hw *hw);
+int32_t em_get_speed_and_duplex(struct em_hw *hw, uint16_t * speed, uint16_t * duplex);
+int32_t em_wait_autoneg(struct em_hw *hw);
+int32_t em_force_mac_fc(struct em_hw *hw);
+
+/* PHY */
+int32_t em_read_phy_reg(struct em_hw *hw, uint32_t reg_addr, uint16_t *phy_data);
+int32_t em_write_phy_reg(struct em_hw *hw, uint32_t reg_addr, uint16_t data);
+int32_t em_phy_hw_reset(struct em_hw *hw);
+int32_t em_phy_reset(struct em_hw *hw);
+int32_t em_detect_gig_phy(struct em_hw *hw);
+int32_t em_phy_get_info(struct em_hw *hw, struct em_phy_info *phy_info);
+int32_t em_phy_m88_get_info(struct em_hw *hw, struct em_phy_info *phy_info);
+int32_t em_phy_igp_get_info(struct em_hw *hw, struct em_phy_info *phy_info);
+int32_t em_get_cable_length(struct em_hw *hw, uint16_t *min_length, uint16_t *max_length);
+int32_t em_check_polarity(struct em_hw *hw, uint16_t *polarity);
+int32_t em_check_downshift(struct em_hw *hw);
+int32_t em_validate_mdi_setting(struct em_hw *hw);
+
+/* EEPROM Functions */
+int32_t em_init_eeprom_params(struct em_hw *hw);
+boolean_t em_is_onboard_nvm_eeprom(struct em_hw *hw);
+int32_t em_read_eeprom_eerd(struct em_hw *hw, uint16_t offset, uint16_t words, uint16_t *data);
+int32_t em_write_eeprom_eewr(struct em_hw *hw, uint16_t offset, uint16_t words, uint16_t *data);
+int32_t em_poll_eerd_eewr_done(struct em_hw *hw, int eerd);
+
+/* MNG HOST IF functions */
+uint32_t em_enable_mng_pass_thru(struct em_hw *hw);
+
+#define E1000_MNG_DHCP_TX_PAYLOAD_CMD   64
+#define E1000_HI_MAX_MNG_DATA_LENGTH    0x6F8   /* Host Interface data length */
+
+#define E1000_MNG_DHCP_COMMAND_TIMEOUT  10      /* Time in ms to process MNG command */
+#define E1000_MNG_DHCP_COOKIE_OFFSET	0x6F0   /* Cookie offset */
+#define E1000_MNG_DHCP_COOKIE_LENGTH	0x10    /* Cookie length */
+#define E1000_MNG_IAMT_MODE		0x3
+#define E1000_IAMT_SIGNATURE            0x544D4149 /* Intel(R) Active Management Technology signature */
+
+#define E1000_MNG_DHCP_COOKIE_STATUS_PARSING_SUPPORT 0x1 /* DHCP parsing enabled */
+#define E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT    0x2 /* DHCP parsing enabled */
+#define E1000_VFTA_ENTRY_SHIFT                       0x5
+#define E1000_VFTA_ENTRY_MASK                        0x7F
+#define E1000_VFTA_ENTRY_BIT_SHIFT_MASK              0x1F
+
+struct em_host_mng_command_header {
+    uint8_t command_id;
+    uint8_t checksum;
+    uint16_t reserved1;
+    uint16_t reserved2;
+    uint16_t command_length;
+};
+
+struct em_host_mng_command_info {
+    struct em_host_mng_command_header command_header;  /* Command Head/Command Result Head has 4 bytes */
+    uint8_t command_data[E1000_HI_MAX_MNG_DATA_LENGTH];   /* Command data can length 0..0x658*/
+};
+#ifdef __BIG_ENDIAN
+struct em_host_mng_dhcp_cookie{
+    uint32_t signature;
+    uint16_t vlan_id;
+    uint8_t reserved0;
+    uint8_t status;
+    uint32_t reserved1;
+    uint8_t checksum;
+    uint8_t reserved3;
+    uint16_t reserved2;
+};
+#else
+struct em_host_mng_dhcp_cookie{
+    uint32_t signature;
+    uint8_t status;
+    uint8_t reserved0;
+    uint16_t vlan_id;
+    uint32_t reserved1;
+    uint16_t reserved2;
+    uint8_t reserved3;
+    uint8_t checksum;
+};
+#endif
+
+int32_t em_mng_write_dhcp_info(struct em_hw *hw, uint8_t *buffer, 
+							uint16_t length);
+boolean_t em_check_mng_mode(struct em_hw *hw);
+boolean_t em_enable_tx_pkt_filtering(struct em_hw *hw);
+int32_t em_mng_enable_host_if(struct em_hw *hw);
+int32_t em_mng_host_if_write(struct em_hw *hw, uint8_t *buffer,
+                            uint16_t length, uint16_t offset, uint8_t *sum);
+int32_t em_mng_write_cmd_header(struct em_hw* hw, 
+                                   struct em_host_mng_command_header* hdr);
+
+int32_t em_mng_write_commit(struct em_hw *hw);
+
+int32_t em_read_eeprom(struct em_hw *hw, uint16_t reg, uint16_t words, uint16_t *data);
+int32_t em_validate_eeprom_checksum(struct em_hw *hw);
+int32_t em_update_eeprom_checksum(struct em_hw *hw);
+int32_t em_write_eeprom(struct em_hw *hw, uint16_t reg, uint16_t words, uint16_t *data);
+int32_t em_read_part_num(struct em_hw *hw, uint32_t * part_num);
+int32_t em_read_mac_addr(struct em_hw * hw);
+int32_t em_swfw_sync_acquire(struct em_hw *hw, uint16_t mask);
+void em_swfw_sync_release(struct em_hw *hw, uint16_t mask);
+
+/* Filters (multicast, vlan, receive) */
+void em_init_rx_addrs(struct em_hw *hw);
+void em_mc_addr_list_update(struct em_hw *hw, uint8_t * mc_addr_list, uint32_t mc_addr_count, uint32_t pad, uint32_t rar_used_count);
+uint32_t em_hash_mc_addr(struct em_hw *hw, uint8_t * mc_addr);
+void em_mta_set(struct em_hw *hw, uint32_t hash_value);
+void em_rar_set(struct em_hw *hw, uint8_t * mc_addr, uint32_t rar_index);
+void em_write_vfta(struct em_hw *hw, uint32_t offset, uint32_t value);
+void em_clear_vfta(struct em_hw *hw);
+
+/* LED functions */
+int32_t em_setup_led(struct em_hw *hw);
+int32_t em_cleanup_led(struct em_hw *hw);
+int32_t em_led_on(struct em_hw *hw);
+int32_t em_led_off(struct em_hw *hw);
+
+/* Adaptive IFS Functions */
+
+/* Everything else */
+void em_clear_hw_cntrs(struct em_hw *hw);
+void em_reset_adaptive(struct em_hw *hw);
+void em_update_adaptive(struct em_hw *hw);
+void em_tbi_adjust_stats(struct em_hw *hw, struct em_hw_stats *stats, uint32_t frame_len, uint8_t * mac_addr);
+void em_get_bus_info(struct em_hw *hw);
+void em_pci_set_mwi(struct em_hw *hw);
+void em_pci_clear_mwi(struct em_hw *hw);
+void em_read_pci_cfg(struct em_hw *hw, uint32_t reg, uint16_t * value);
+void em_write_pci_cfg(struct em_hw *hw, uint32_t reg, uint16_t * value);
+/* Port I/O is only supported on 82544 and newer */
+uint32_t em_io_read(struct em_hw *hw, unsigned long port);
+uint32_t em_read_reg_io(struct em_hw *hw, uint32_t offset);
+void em_io_write(struct em_hw *hw, unsigned long port, uint32_t value);
+void em_write_reg_io(struct em_hw *hw, uint32_t offset, uint32_t value);
+int32_t em_config_dsp_after_link_change(struct em_hw *hw, boolean_t link_up);
+int32_t em_set_d3_lplu_state(struct em_hw *hw, boolean_t active);
+int32_t em_set_d0_lplu_state(struct em_hw *hw, boolean_t active);
+void em_set_pci_express_master_disable(struct em_hw *hw);
+void em_enable_pciex_master(struct em_hw *hw);
+int32_t em_disable_pciex_master(struct em_hw *hw);
+int32_t em_get_auto_rd_done(struct em_hw *hw);
+int32_t em_get_phy_cfg_done(struct em_hw *hw);
+int32_t em_get_software_semaphore(struct em_hw *hw);
+void em_release_software_semaphore(struct em_hw *hw);
+int32_t em_check_phy_reset_block(struct em_hw *hw);
+int32_t em_get_hw_eeprom_semaphore(struct em_hw *hw);
+void em_put_hw_eeprom_semaphore(struct em_hw *hw);
+int32_t em_commit_shadow_ram(struct em_hw *hw);
+uint8_t em_arc_subsystem_valid(struct em_hw *hw);
+
+#define E1000_READ_REG_IO(a, reg) \
+    em_read_reg_io((a), E1000_##reg)
+#define E1000_WRITE_REG_IO(a, reg, val) \
+    em_write_reg_io((a), E1000_##reg, val)
+
+/* PCI Device IDs */
+#define E1000_DEV_ID_82542               0x1000
+#define E1000_DEV_ID_82543GC_FIBER       0x1001
+#define E1000_DEV_ID_82543GC_COPPER      0x1004
+#define E1000_DEV_ID_82544EI_COPPER      0x1008
+#define E1000_DEV_ID_82544EI_FIBER       0x1009
+#define E1000_DEV_ID_82544GC_COPPER      0x100C
+#define E1000_DEV_ID_82544GC_LOM         0x100D
+#define E1000_DEV_ID_82540EM             0x100E
+#define E1000_DEV_ID_82541ER_LOM         0x1014
+#define E1000_DEV_ID_82540EM_LOM         0x1015
+#define E1000_DEV_ID_82540EP_LOM         0x1016
+#define E1000_DEV_ID_82540EP             0x1017
+#define E1000_DEV_ID_82540EP_LP          0x101E
+#define E1000_DEV_ID_82545EM_COPPER      0x100F
+#define E1000_DEV_ID_82545EM_FIBER       0x1011
+#define E1000_DEV_ID_82545GM_COPPER      0x1026
+#define E1000_DEV_ID_82545GM_FIBER       0x1027
+#define E1000_DEV_ID_82545GM_SERDES      0x1028
+#define E1000_DEV_ID_82546EB_COPPER      0x1010
+#define E1000_DEV_ID_82546EB_FIBER       0x1012
+#define E1000_DEV_ID_82546EB_QUAD_COPPER 0x101D
+#define E1000_DEV_ID_82541EI             0x1013
+#define E1000_DEV_ID_82541EI_MOBILE      0x1018
+#define E1000_DEV_ID_82541ER             0x1078
+#define E1000_DEV_ID_82547GI             0x1075
+#define E1000_DEV_ID_82541GI             0x1076
+#define E1000_DEV_ID_82541GI_MOBILE      0x1077
+#define E1000_DEV_ID_82541GI_LF          0x107C
+#define E1000_DEV_ID_82546GB_COPPER      0x1079
+#define E1000_DEV_ID_82546GB_FIBER       0x107A
+#define E1000_DEV_ID_82546GB_SERDES      0x107B
+#define E1000_DEV_ID_82546GB_PCIE        0x108A
+#define E1000_DEV_ID_82547EI             0x1019
+#define E1000_DEV_ID_82547EI_MOBILE      0x101A
+#define E1000_DEV_ID_82573E              0x108B
+#define E1000_DEV_ID_82573E_IAMT         0x108C
+
+#define E1000_DEV_ID_82546GB_QUAD_COPPER 0x1099
+
+#define NODE_ADDRESS_SIZE 6
+#define ETH_LENGTH_OF_ADDRESS 6
+
+/* MAC decode size is 128K - This is the size of BAR0 */
+#define MAC_DECODE_SIZE (128 * 1024)
+
+#define E1000_82542_2_0_REV_ID 2
+#define E1000_82542_2_1_REV_ID 3
+#define E1000_REVISION_0       0
+#define E1000_REVISION_1       1
+#define E1000_REVISION_2       2
+#define E1000_REVISION_3       3
+
+#define SPEED_10    10
+#define SPEED_100   100
+#define SPEED_1000  1000
+#define HALF_DUPLEX 1
+#define FULL_DUPLEX 2
+
+/* The sizes (in bytes) of a ethernet packet */
+#define ENET_HEADER_SIZE             14
+#define MAXIMUM_ETHERNET_FRAME_SIZE  1518 /* With FCS */
+#define MINIMUM_ETHERNET_FRAME_SIZE  64   /* With FCS */
+#define ETHERNET_FCS_SIZE            4
+#define MAXIMUM_ETHERNET_PACKET_SIZE \
+    (MAXIMUM_ETHERNET_FRAME_SIZE - ETHERNET_FCS_SIZE)
+#define MINIMUM_ETHERNET_PACKET_SIZE \
+    (MINIMUM_ETHERNET_FRAME_SIZE - ETHERNET_FCS_SIZE)
+#define CRC_LENGTH                   ETHERNET_FCS_SIZE
+#define MAX_JUMBO_FRAME_SIZE         0x3F00
+
+
+/* 802.1q VLAN Packet Sizes */
+#define VLAN_TAG_SIZE                     4     /* 802.3ac tag (not DMAed) */
+
+/* Ethertype field values */
+#define ETHERNET_IEEE_VLAN_TYPE 0x8100  /* 802.3ac packet */
+#define ETHERNET_IP_TYPE        0x0800  /* IP packets */
+#define ETHERNET_ARP_TYPE       0x0806  /* Address Resolution Protocol (ARP) */
+
+/* Packet Header defines */
+#define IP_PROTOCOL_TCP    6
+#define IP_PROTOCOL_UDP    0x11
+
+/* This defines the bits that are set in the Interrupt Mask
+ * Set/Read Register.  Each bit is documented below:
+ *   o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0)
+ *   o RXSEQ  = Receive Sequence Error
+ */
+#define POLL_IMS_ENABLE_MASK ( \
+    E1000_IMS_RXDMT0 |         \
+    E1000_IMS_RXSEQ)
+
+/* This defines the bits that are set in the Interrupt Mask
+ * Set/Read Register.  Each bit is documented below:
+ *   o RXT0   = Receiver Timer Interrupt (ring 0)
+ *   o TXDW   = Transmit Descriptor Written Back
+ *   o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0)
+ *   o RXSEQ  = Receive Sequence Error
+ *   o LSC    = Link Status Change
+ */
+#define IMS_ENABLE_MASK ( \
+    E1000_IMS_RXT0   |    \
+    E1000_IMS_TXDW   |    \
+    E1000_IMS_RXDMT0 |    \
+    E1000_IMS_RXSEQ  |    \
+    E1000_IMS_LSC)
+
+
+/* Number of high/low register pairs in the RAR. The RAR (Receive Address
+ * Registers) holds the directed and multicast addresses that we monitor. We
+ * reserve one of these spots for our directed address, allowing us room for
+ * E1000_RAR_ENTRIES - 1 multicast addresses.
+ */
+#define E1000_RAR_ENTRIES 15
+
+#define MIN_NUMBER_OF_DESCRIPTORS 8
+#define MAX_NUMBER_OF_DESCRIPTORS 0xFFF8
+
+/* Receive Descriptor */
+struct em_rx_desc {
+    uint64_t buffer_addr; /* Address of the descriptor's data buffer */
+    uint16_t length;     /* Length of data DMAed into data buffer */
+    uint16_t csum;       /* Packet checksum */
+    uint8_t status;      /* Descriptor status */
+    uint8_t errors;      /* Descriptor Errors */
+    uint16_t special;
+};
+
+/* Receive Descriptor - Extended */
+union em_rx_desc_extended {
+    struct {
+        uint64_t buffer_addr;
+        uint64_t reserved;
+    } read;
+    struct {
+        struct {
+            uint32_t mrq;              /* Multiple Rx Queues */
+            union {
+                uint32_t rss;          /* RSS Hash */
+                struct {
+                    uint16_t ip_id;    /* IP id */
+                    uint16_t csum;     /* Packet Checksum */
+                } csum_ip;
+            } hi_dword;
+        } lower;
+        struct {
+            uint32_t status_error;     /* ext status/error */
+            uint16_t length;
+            uint16_t vlan;             /* VLAN tag */
+        } upper;
+    } wb;  /* writeback */
+};
+
+#define MAX_PS_BUFFERS 4
+/* Receive Descriptor - Packet Split */
+union em_rx_desc_packet_split {
+    struct {
+        /* one buffer for protocol header(s), three data buffers */
+        uint64_t buffer_addr[MAX_PS_BUFFERS];
+    } read;
+    struct {
+        struct {
+            uint32_t mrq;              /* Multiple Rx Queues */
+            union {
+                uint32_t rss;          /* RSS Hash */
+                struct {
+                    uint16_t ip_id;    /* IP id */
+                    uint16_t csum;     /* Packet Checksum */
+                } csum_ip;
+            } hi_dword;
+        } lower;
+        struct {
+            uint32_t status_error;     /* ext status/error */
+            uint16_t length0;          /* length of buffer 0 */
+            uint16_t vlan;             /* VLAN tag */
+        } middle;
+        struct {
+            uint16_t header_status;
+            uint16_t length[3];        /* length of buffers 1-3 */
+        } upper;
+        uint64_t reserved;
+    } wb; /* writeback */
+};
+
+/* Receive Decriptor bit definitions */
+#define E1000_RXD_STAT_DD       0x01    /* Descriptor Done */
+#define E1000_RXD_STAT_EOP      0x02    /* End of Packet */
+#define E1000_RXD_STAT_IXSM     0x04    /* Ignore checksum */
+#define E1000_RXD_STAT_VP       0x08    /* IEEE VLAN Packet */
+#define E1000_RXD_STAT_UDPCS    0x10    /* UDP xsum caculated */
+#define E1000_RXD_STAT_TCPCS    0x20    /* TCP xsum calculated */
+#define E1000_RXD_STAT_IPCS     0x40    /* IP xsum calculated */
+#define E1000_RXD_STAT_PIF      0x80    /* passed in-exact filter */
+#define E1000_RXD_STAT_IPIDV    0x200   /* IP identification valid */
+#define E1000_RXD_STAT_UDPV     0x400   /* Valid UDP checksum */
+#define E1000_RXD_STAT_ACK      0x8000  /* ACK Packet indication */
+#define E1000_RXD_ERR_CE        0x01    /* CRC Error */
+#define E1000_RXD_ERR_SE        0x02    /* Symbol Error */
+#define E1000_RXD_ERR_SEQ       0x04    /* Sequence Error */
+#define E1000_RXD_ERR_CXE       0x10    /* Carrier Extension Error */
+#define E1000_RXD_ERR_TCPE      0x20    /* TCP/UDP Checksum Error */
+#define E1000_RXD_ERR_IPE       0x40    /* IP Checksum Error */
+#define E1000_RXD_ERR_RXE       0x80    /* Rx Data Error */
+#define E1000_RXD_SPC_VLAN_MASK 0x0FFF  /* VLAN ID is in lower 12 bits */
+#define E1000_RXD_SPC_PRI_MASK  0xE000  /* Priority is in upper 3 bits */
+#define E1000_RXD_SPC_PRI_SHIFT 13
+#define E1000_RXD_SPC_CFI_MASK  0x1000  /* CFI is bit 12 */
+#define E1000_RXD_SPC_CFI_SHIFT 12
+
+#define E1000_RXDEXT_STATERR_CE    0x01000000
+#define E1000_RXDEXT_STATERR_SE    0x02000000
+#define E1000_RXDEXT_STATERR_SEQ   0x04000000
+#define E1000_RXDEXT_STATERR_CXE   0x10000000
+#define E1000_RXDEXT_STATERR_TCPE  0x20000000
+#define E1000_RXDEXT_STATERR_IPE   0x40000000
+#define E1000_RXDEXT_STATERR_RXE   0x80000000
+
+#define E1000_RXDPS_HDRSTAT_HDRSP        0x00008000
+#define E1000_RXDPS_HDRSTAT_HDRLEN_MASK  0x000003FF
+
+/* mask to determine if packets should be dropped due to frame errors */
+#define E1000_RXD_ERR_FRAME_ERR_MASK ( \
+    E1000_RXD_ERR_CE  |                \
+    E1000_RXD_ERR_SE  |                \
+    E1000_RXD_ERR_SEQ |                \
+    E1000_RXD_ERR_CXE |                \
+    E1000_RXD_ERR_RXE)
+
+
+/* Same mask, but for extended and packet split descriptors */
+#define E1000_RXDEXT_ERR_FRAME_ERR_MASK ( \
+    E1000_RXDEXT_STATERR_CE  |            \
+    E1000_RXDEXT_STATERR_SE  |            \
+    E1000_RXDEXT_STATERR_SEQ |            \
+    E1000_RXDEXT_STATERR_CXE |            \
+    E1000_RXDEXT_STATERR_RXE)
+
+/* Transmit Descriptor */
+struct em_tx_desc {
+    uint64_t buffer_addr;       /* Address of the descriptor's data buffer */
+    union {
+        uint32_t data;
+        struct {
+            uint16_t length;    /* Data buffer length */
+            uint8_t cso;        /* Checksum offset */
+            uint8_t cmd;        /* Descriptor control */
+        } flags;
+    } lower;
+    union {
+        uint32_t data;
+        struct {
+            uint8_t status;     /* Descriptor status */
+            uint8_t css;        /* Checksum start */
+            uint16_t special;
+        } fields;
+    } upper;
+};
+
+/* Transmit Descriptor bit definitions */
+#define E1000_TXD_DTYP_D     0x00100000 /* Data Descriptor */
+#define E1000_TXD_DTYP_C     0x00000000 /* Context Descriptor */
+#define E1000_TXD_POPTS_IXSM 0x01       /* Insert IP checksum */
+#define E1000_TXD_POPTS_TXSM 0x02       /* Insert TCP/UDP checksum */
+#define E1000_TXD_CMD_EOP    0x01000000 /* End of Packet */
+#define E1000_TXD_CMD_IFCS   0x02000000 /* Insert FCS (Ethernet CRC) */
+#define E1000_TXD_CMD_IC     0x04000000 /* Insert Checksum */
+#define E1000_TXD_CMD_RS     0x08000000 /* Report Status */
+#define E1000_TXD_CMD_RPS    0x10000000 /* Report Packet Sent */
+#define E1000_TXD_CMD_DEXT   0x20000000 /* Descriptor extension (0 = legacy) */
+#define E1000_TXD_CMD_VLE    0x40000000 /* Add VLAN tag */
+#define E1000_TXD_CMD_IDE    0x80000000 /* Enable Tidv register */
+#define E1000_TXD_STAT_DD    0x00000001 /* Descriptor Done */
+#define E1000_TXD_STAT_EC    0x00000002 /* Excess Collisions */
+#define E1000_TXD_STAT_LC    0x00000004 /* Late Collisions */
+#define E1000_TXD_STAT_TU    0x00000008 /* Transmit underrun */
+#define E1000_TXD_CMD_TCP    0x01000000 /* TCP packet */
+#define E1000_TXD_CMD_IP     0x02000000 /* IP packet */
+#define E1000_TXD_CMD_TSE    0x04000000 /* TCP Seg enable */
+#define E1000_TXD_STAT_TC    0x00000004 /* Tx Underrun */
+
+/* Offload Context Descriptor */
+struct em_context_desc {
+    union {
+        uint32_t ip_config;
+        struct {
+            uint8_t ipcss;      /* IP checksum start */
+            uint8_t ipcso;      /* IP checksum offset */
+            uint16_t ipcse;     /* IP checksum end */
+        } ip_fields;
+    } lower_setup;
+    union {
+        uint32_t tcp_config;
+        struct {
+            uint8_t tucss;      /* TCP checksum start */
+            uint8_t tucso;      /* TCP checksum offset */
+            uint16_t tucse;     /* TCP checksum end */
+        } tcp_fields;
+    } upper_setup;
+    uint32_t cmd_and_length;    /* */
+    union {
+        uint32_t data;
+        struct {
+            uint8_t status;     /* Descriptor status */
+            uint8_t hdr_len;    /* Header length */
+            uint16_t mss;       /* Maximum segment size */
+        } fields;
+    } tcp_seg_setup;
+};
+
+/* Offload data descriptor */
+struct em_data_desc {
+    uint64_t buffer_addr;       /* Address of the descriptor's buffer address */
+    union {
+        uint32_t data;
+        struct {
+            uint16_t length;    /* Data buffer length */
+            uint8_t typ_len_ext;        /* */
+            uint8_t cmd;        /* */
+        } flags;
+    } lower;
+    union {
+        uint32_t data;
+        struct {
+            uint8_t status;     /* Descriptor status */
+            uint8_t popts;      /* Packet Options */
+            uint16_t special;   /* */
+        } fields;
+    } upper;
+};
+
+/* Filters */
+#define E1000_NUM_UNICAST          16   /* Unicast filter entries */
+#define E1000_MC_TBL_SIZE          128  /* Multicast Filter Table (4096 bits) */
+#define E1000_VLAN_FILTER_TBL_SIZE 128  /* VLAN Filter Table (4096 bits) */
+
+
+/* Receive Address Register */
+struct em_rar {
+    volatile uint32_t low;      /* receive address low */
+    volatile uint32_t high;     /* receive address high */
+};
+
+/* Number of entries in the Multicast Table Array (MTA). */
+#define E1000_NUM_MTA_REGISTERS 128
+
+/* IPv4 Address Table Entry */
+struct em_ipv4_at_entry {
+    volatile uint32_t ipv4_addr;        /* IP Address (RW) */
+    volatile uint32_t reserved;
+};
+
+/* Four wakeup IP addresses are supported */
+#define E1000_WAKEUP_IP_ADDRESS_COUNT_MAX 4
+#define E1000_IP4AT_SIZE                  E1000_WAKEUP_IP_ADDRESS_COUNT_MAX
+#define E1000_IP6AT_SIZE                  1
+
+/* IPv6 Address Table Entry */
+struct em_ipv6_at_entry {
+    volatile uint8_t ipv6_addr[16];
+};
+
+/* Flexible Filter Length Table Entry */
+struct em_fflt_entry {
+    volatile uint32_t length;   /* Flexible Filter Length (RW) */
+    volatile uint32_t reserved;
+};
+
+/* Flexible Filter Mask Table Entry */
+struct em_ffmt_entry {
+    volatile uint32_t mask;     /* Flexible Filter Mask (RW) */
+    volatile uint32_t reserved;
+};
+
+/* Flexible Filter Value Table Entry */
+struct em_ffvt_entry {
+    volatile uint32_t value;    /* Flexible Filter Value (RW) */
+    volatile uint32_t reserved;
+};
+
+/* Four Flexible Filters are supported */
+#define E1000_FLEXIBLE_FILTER_COUNT_MAX 4
+
+/* Each Flexible Filter is at most 128 (0x80) bytes in length */
+#define E1000_FLEXIBLE_FILTER_SIZE_MAX  128
+
+#define E1000_FFLT_SIZE E1000_FLEXIBLE_FILTER_COUNT_MAX
+#define E1000_FFMT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX
+#define E1000_FFVT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX
+
+/* Register Set. (82543, 82544)
+ *
+ * Registers are defined to be 32 bits and  should be accessed as 32 bit values.
+ * These registers are physically located on the NIC, but are mapped into the
+ * host memory address space.
+ *
+ * RW - register is both readable and writable
+ * RO - register is read only
+ * WO - register is write only
+ * R/clr - register is read only and is cleared when read
+ * A - register array
+ */
+#define E1000_CTRL     0x00000  /* Device Control - RW */
+#define E1000_CTRL_DUP 0x00004  /* Device Control Duplicate (Shadow) - RW */
+#define E1000_STATUS   0x00008  /* Device Status - RO */
+#define E1000_EECD     0x00010  /* EEPROM/Flash Control - RW */
+#define E1000_EERD     0x00014  /* EEPROM Read - RW */
+#define E1000_CTRL_EXT 0x00018  /* Extended Device Control - RW */
+#define E1000_FLA      0x0001C  /* Flash Access - RW */
+#define E1000_MDIC     0x00020  /* MDI Control - RW */
+#define E1000_FCAL     0x00028  /* Flow Control Address Low - RW */
+#define E1000_FCAH     0x0002C  /* Flow Control Address High -RW */
+#define E1000_FCT      0x00030  /* Flow Control Type - RW */
+#define E1000_VET      0x00038  /* VLAN Ether Type - RW */
+#define E1000_ICR      0x000C0  /* Interrupt Cause Read - R/clr */
+#define E1000_ITR      0x000C4  /* Interrupt Throttling Rate - RW */
+#define E1000_ICS      0x000C8  /* Interrupt Cause Set - WO */
+#define E1000_IMS      0x000D0  /* Interrupt Mask Set - RW */
+#define E1000_IMC      0x000D8  /* Interrupt Mask Clear - WO */
+#define E1000_IAM      0x000E0  /* Interrupt Acknowledge Auto Mask */
+#define E1000_RCTL     0x00100  /* RX Control - RW */
+#define E1000_FCTTV    0x00170  /* Flow Control Transmit Timer Value - RW */
+#define E1000_TXCW     0x00178  /* TX Configuration Word - RW */
+#define E1000_RXCW     0x00180  /* RX Configuration Word - RO */
+#define E1000_TCTL     0x00400  /* TX Control - RW */
+#define E1000_TIPG     0x00410  /* TX Inter-packet gap -RW */
+#define E1000_TBT      0x00448  /* TX Burst Timer - RW */
+#define E1000_AIT      0x00458  /* Adaptive Interframe Spacing Throttle - RW */
+#define E1000_LEDCTL   0x00E00  /* LED Control - RW */
+#define E1000_EXTCNF_CTRL  0x00F00  /* Extended Configuration Control */
+#define E1000_EXTCNF_SIZE  0x00F08  /* Extended Configuration Size */
+#define E1000_PBA      0x01000  /* Packet Buffer Allocation - RW */
+#define E1000_PBS      0x01008  /* Packet Buffer Size */
+#define E1000_EEMNGCTL 0x01010  /* MNG EEprom Control */
+#define E1000_FLASH_UPDATES 1000
+#define E1000_EEARBC   0x01024  /* EEPROM Auto Read Bus Control */
+#define E1000_FLASHT   0x01028  /* FLASH Timer Register */
+#define E1000_EEWR     0x0102C  /* EEPROM Write Register - RW */
+#define E1000_FLSWCTL  0x01030  /* FLASH control register */
+#define E1000_FLSWDATA 0x01034  /* FLASH data register */
+#define E1000_FLSWCNT  0x01038  /* FLASH Access Counter */
+#define E1000_FLOP     0x0103C  /* FLASH Opcode Register */
+#define E1000_ERT      0x02008  /* Early Rx Threshold - RW */
+#define E1000_FCRTL    0x02160  /* Flow Control Receive Threshold Low - RW */
+#define E1000_FCRTH    0x02168  /* Flow Control Receive Threshold High - RW */
+#define E1000_PSRCTL   0x02170  /* Packet Split Receive Control - RW */
+#define E1000_RDBAL    0x02800  /* RX Descriptor Base Address Low - RW */
+#define E1000_RDBAH    0x02804  /* RX Descriptor Base Address High - RW */
+#define E1000_RDLEN    0x02808  /* RX Descriptor Length - RW */
+#define E1000_RDH      0x02810  /* RX Descriptor Head - RW */
+#define E1000_RDT      0x02818  /* RX Descriptor Tail - RW */
+#define E1000_RDTR     0x02820  /* RX Delay Timer - RW */
+#define E1000_RXDCTL   0x02828  /* RX Descriptor Control - RW */
+#define E1000_RADV     0x0282C  /* RX Interrupt Absolute Delay Timer - RW */
+#define E1000_RSRPD    0x02C00  /* RX Small Packet Detect - RW */
+#define E1000_RAID     0x02C08  /* Receive Ack Interrupt Delay - RW */
+#define E1000_TXDMAC   0x03000  /* TX DMA Control - RW */
+#define E1000_TDFH     0x03410  /* TX Data FIFO Head - RW */
+#define E1000_TDFT     0x03418  /* TX Data FIFO Tail - RW */
+#define E1000_TDFHS    0x03420  /* TX Data FIFO Head Saved - RW */
+#define E1000_TDFTS    0x03428  /* TX Data FIFO Tail Saved - RW */
+#define E1000_TDFPC    0x03430  /* TX Data FIFO Packet Count - RW */
+#define E1000_TDBAL    0x03800  /* TX Descriptor Base Address Low - RW */
+#define E1000_TDBAH    0x03804  /* TX Descriptor Base Address High - RW */
+#define E1000_TDLEN    0x03808  /* TX Descriptor Length - RW */
+#define E1000_TDH      0x03810  /* TX Descriptor Head - RW */
+#define E1000_TDT      0x03818  /* TX Descripotr Tail - RW */
+#define E1000_TIDV     0x03820  /* TX Interrupt Delay Value - RW */
+#define E1000_TXDCTL   0x03828  /* TX Descriptor Control - RW */
+#define E1000_TADV     0x0382C  /* TX Interrupt Absolute Delay Val - RW */
+#define E1000_TSPMT    0x03830  /* TCP Segmentation PAD & Min Threshold - RW */
+#define E1000_TARC0    0x03840 /* TX Arbitration Count (0) */
+#define E1000_TDBAL1   0x03900 /* TX Desc Base Address Low (1) - RW */
+#define E1000_TDBAH1   0x03904 /* TX Desc Base Address High (1) - RW */
+#define E1000_TDLEN1   0x03908 /* TX Desc Length (1) - RW */
+#define E1000_TDH1     0x03910 /* TX Desc Head (1) - RW */
+#define E1000_TDT1     0x03918 /* TX Desc Tail (1) - RW */
+#define E1000_TXDCTL1  0x03928 /* TX Descriptor Control (1) - RW */
+#define E1000_TARC1    0x03940 /* TX Arbitration Count (1) */
+#define E1000_CRCERRS  0x04000  /* CRC Error Count - R/clr */
+#define E1000_ALGNERRC 0x04004  /* Alignment Error Count - R/clr */
+#define E1000_SYMERRS  0x04008  /* Symbol Error Count - R/clr */
+#define E1000_RXERRC   0x0400C  /* Receive Error Count - R/clr */
+#define E1000_MPC      0x04010  /* Missed Packet Count - R/clr */
+#define E1000_SCC      0x04014  /* Single Collision Count - R/clr */
+#define E1000_ECOL     0x04018  /* Excessive Collision Count - R/clr */
+#define E1000_MCC      0x0401C  /* Multiple Collision Count - R/clr */
+#define E1000_LATECOL  0x04020  /* Late Collision Count - R/clr */
+#define E1000_COLC     0x04028  /* Collision Count - R/clr */
+#define E1000_DC       0x04030  /* Defer Count - R/clr */
+#define E1000_TNCRS    0x04034  /* TX-No CRS - R/clr */
+#define E1000_SEC      0x04038  /* Sequence Error Count - R/clr */
+#define E1000_CEXTERR  0x0403C  /* Carrier Extension Error Count - R/clr */
+#define E1000_RLEC     0x04040  /* Receive Length Error Count - R/clr */
+#define E1000_XONRXC   0x04048  /* XON RX Count - R/clr */
+#define E1000_XONTXC   0x0404C  /* XON TX Count - R/clr */
+#define E1000_XOFFRXC  0x04050  /* XOFF RX Count - R/clr */
+#define E1000_XOFFTXC  0x04054  /* XOFF TX Count - R/clr */
+#define E1000_FCRUC    0x04058  /* Flow Control RX Unsupported Count- R/clr */
+#define E1000_PRC64    0x0405C  /* Packets RX (64 bytes) - R/clr */
+#define E1000_PRC127   0x04060  /* Packets RX (65-127 bytes) - R/clr */
+#define E1000_PRC255   0x04064  /* Packets RX (128-255 bytes) - R/clr */
+#define E1000_PRC511   0x04068  /* Packets RX (255-511 bytes) - R/clr */
+#define E1000_PRC1023  0x0406C  /* Packets RX (512-1023 bytes) - R/clr */
+#define E1000_PRC1522  0x04070  /* Packets RX (1024-1522 bytes) - R/clr */
+#define E1000_GPRC     0x04074  /* Good Packets RX Count - R/clr */
+#define E1000_BPRC     0x04078  /* Broadcast Packets RX Count - R/clr */
+#define E1000_MPRC     0x0407C  /* Multicast Packets RX Count - R/clr */
+#define E1000_GPTC     0x04080  /* Good Packets TX Count - R/clr */
+#define E1000_GORCL    0x04088  /* Good Octets RX Count Low - R/clr */
+#define E1000_GORCH    0x0408C  /* Good Octets RX Count High - R/clr */
+#define E1000_GOTCL    0x04090  /* Good Octets TX Count Low - R/clr */
+#define E1000_GOTCH    0x04094  /* Good Octets TX Count High - R/clr */
+#define E1000_RNBC     0x040A0  /* RX No Buffers Count - R/clr */
+#define E1000_RUC      0x040A4  /* RX Undersize Count - R/clr */
+#define E1000_RFC      0x040A8  /* RX Fragment Count - R/clr */
+#define E1000_ROC      0x040AC  /* RX Oversize Count - R/clr */
+#define E1000_RJC      0x040B0  /* RX Jabber Count - R/clr */
+#define E1000_MGTPRC   0x040B4  /* Management Packets RX Count - R/clr */
+#define E1000_MGTPDC   0x040B8  /* Management Packets Dropped Count - R/clr */
+#define E1000_MGTPTC   0x040BC  /* Management Packets TX Count - R/clr */
+#define E1000_TORL     0x040C0  /* Total Octets RX Low - R/clr */
+#define E1000_TORH     0x040C4  /* Total Octets RX High - R/clr */
+#define E1000_TOTL     0x040C8  /* Total Octets TX Low - R/clr */
+#define E1000_TOTH     0x040CC  /* Total Octets TX High - R/clr */
+#define E1000_TPR      0x040D0  /* Total Packets RX - R/clr */
+#define E1000_TPT      0x040D4  /* Total Packets TX - R/clr */
+#define E1000_PTC64    0x040D8  /* Packets TX (64 bytes) - R/clr */
+#define E1000_PTC127   0x040DC  /* Packets TX (65-127 bytes) - R/clr */
+#define E1000_PTC255   0x040E0  /* Packets TX (128-255 bytes) - R/clr */
+#define E1000_PTC511   0x040E4  /* Packets TX (256-511 bytes) - R/clr */
+#define E1000_PTC1023  0x040E8  /* Packets TX (512-1023 bytes) - R/clr */
+#define E1000_PTC1522  0x040EC  /* Packets TX (1024-1522 Bytes) - R/clr */
+#define E1000_MPTC     0x040F0  /* Multicast Packets TX Count - R/clr */
+#define E1000_BPTC     0x040F4  /* Broadcast Packets TX Count - R/clr */
+#define E1000_TSCTC    0x040F8  /* TCP Segmentation Context TX - R/clr */
+#define E1000_TSCTFC   0x040FC  /* TCP Segmentation Context TX Fail - R/clr */
+#define E1000_IAC       0x4100  /* Interrupt Assertion Count */
+#define E1000_ICRXPTC   0x4104  /* Interrupt Cause Rx Packet Timer Expire Count */
+#define E1000_ICRXATC   0x4108  /* Interrupt Cause Rx Absolute Timer Expire Count */
+#define E1000_ICTXPTC   0x410C  /* Interrupt Cause Tx Packet Timer Expire Count */
+#define E1000_ICTXATC   0x4110  /* Interrupt Cause Tx Absolute Timer Expire Count */
+#define E1000_ICTXQEC   0x4118  /* Interrupt Cause Tx Queue Empty Count */
+#define E1000_ICTXQMTC  0x411C  /* Interrupt Cause Tx Queue Minimum Threshold Count */
+#define E1000_ICRXDMTC  0x4120  /* Interrupt Cause Rx Descriptor Minimum Threshold Count */
+#define E1000_ICRXOC    0x4124  /* Interrupt Cause Receiver Overrun Count */
+#define E1000_RXCSUM   0x05000  /* RX Checksum Control - RW */
+#define E1000_RFCTL    0x05008  /* Receive Filter Control*/
+#define E1000_MTA      0x05200  /* Multicast Table Array - RW Array */
+#define E1000_RA       0x05400  /* Receive Address - RW Array */
+#define E1000_VFTA     0x05600  /* VLAN Filter Table Array - RW Array */
+#define E1000_WUC      0x05800  /* Wakeup Control - RW */
+#define E1000_WUFC     0x05808  /* Wakeup Filter Control - RW */
+#define E1000_WUS      0x05810  /* Wakeup Status - RO */
+#define E1000_MANC     0x05820  /* Management Control - RW */
+#define E1000_IPAV     0x05838  /* IP Address Valid - RW */
+#define E1000_IP4AT    0x05840  /* IPv4 Address Table - RW Array */
+#define E1000_IP6AT    0x05880  /* IPv6 Address Table - RW Array */
+#define E1000_WUPL     0x05900  /* Wakeup Packet Length - RW */
+#define E1000_WUPM     0x05A00  /* Wakeup Packet Memory - RO A */
+#define E1000_FFLT     0x05F00  /* Flexible Filter Length Table - RW Array */
+#define E1000_HOST_IF  0x08800  /* Host Interface */
+#define E1000_FFMT     0x09000  /* Flexible Filter Mask Table - RW Array */
+#define E1000_FFVT     0x09800  /* Flexible Filter Value Table - RW Array */
+
+#define E1000_GCR       0x05B00 /* PCI-Ex Control */
+#define E1000_GSCL_1    0x05B10 /* PCI-Ex Statistic Control #1 */
+#define E1000_GSCL_2    0x05B14 /* PCI-Ex Statistic Control #2 */
+#define E1000_GSCL_3    0x05B18 /* PCI-Ex Statistic Control #3 */
+#define E1000_GSCL_4    0x05B1C /* PCI-Ex Statistic Control #4 */
+#define E1000_FACTPS    0x05B30 /* Function Active and Power State to MNG */
+#define E1000_SWSM      0x05B50 /* SW Semaphore */
+#define E1000_FWSM      0x05B54 /* FW Semaphore */
+#define E1000_FFLT_DBG  0x05F04 /* Debug Register */
+#define E1000_HICR      0x08F00 /* Host Inteface Control */
+/* Register Set (82542)
+ *
+ * Some of the 82542 registers are located at different offsets than they are
+ * in more current versions of the 8254x. Despite the difference in location,
+ * the registers function in the same manner.
+ */
+#define E1000_82542_CTRL     E1000_CTRL
+#define E1000_82542_CTRL_DUP E1000_CTRL_DUP
+#define E1000_82542_STATUS   E1000_STATUS
+#define E1000_82542_EECD     E1000_EECD
+#define E1000_82542_EERD     E1000_EERD
+#define E1000_82542_CTRL_EXT E1000_CTRL_EXT
+#define E1000_82542_FLA      E1000_FLA
+#define E1000_82542_MDIC     E1000_MDIC
+#define E1000_82542_FCAL     E1000_FCAL
+#define E1000_82542_FCAH     E1000_FCAH
+#define E1000_82542_FCT      E1000_FCT
+#define E1000_82542_VET      E1000_VET
+#define E1000_82542_RA       0x00040
+#define E1000_82542_ICR      E1000_ICR
+#define E1000_82542_ITR      E1000_ITR
+#define E1000_82542_ICS      E1000_ICS
+#define E1000_82542_IMS      E1000_IMS
+#define E1000_82542_IMC      E1000_IMC
+#define E1000_82542_RCTL     E1000_RCTL
+#define E1000_82542_RDTR     0x00108
+#define E1000_82542_RDBAL    0x00110
+#define E1000_82542_RDBAH    0x00114
+#define E1000_82542_RDLEN    0x00118
+#define E1000_82542_RDH      0x00120
+#define E1000_82542_RDT      0x00128
+#define E1000_82542_FCRTH    0x00160
+#define E1000_82542_FCRTL    0x00168
+#define E1000_82542_FCTTV    E1000_FCTTV
+#define E1000_82542_TXCW     E1000_TXCW
+#define E1000_82542_RXCW     E1000_RXCW
+#define E1000_82542_MTA      0x00200
+#define E1000_82542_TCTL     E1000_TCTL
+#define E1000_82542_TIPG     E1000_TIPG
+#define E1000_82542_TDBAL    0x00420
+#define E1000_82542_TDBAH    0x00424
+#define E1000_82542_TDLEN    0x00428
+#define E1000_82542_TDH      0x00430
+#define E1000_82542_TDT      0x00438
+#define E1000_82542_TIDV     0x00440
+#define E1000_82542_TBT      E1000_TBT
+#define E1000_82542_AIT      E1000_AIT
+#define E1000_82542_VFTA     0x00600
+#define E1000_82542_LEDCTL   E1000_LEDCTL
+#define E1000_82542_PBA      E1000_PBA
+#define E1000_82542_PBS      E1000_PBS
+#define E1000_82542_EEMNGCTL E1000_EEMNGCTL
+#define E1000_82542_EEARBC   E1000_EEARBC
+#define E1000_82542_FLASHT   E1000_FLASHT
+#define E1000_82542_EEWR     E1000_EEWR
+#define E1000_82542_FLSWCTL  E1000_FLSWCTL
+#define E1000_82542_FLSWDATA E1000_FLSWDATA
+#define E1000_82542_FLSWCNT  E1000_FLSWCNT
+#define E1000_82542_FLOP     E1000_FLOP
+#define E1000_82542_EXTCNF_CTRL  E1000_EXTCNF_CTRL
+#define E1000_82542_EXTCNF_SIZE  E1000_EXTCNF_SIZE
+#define E1000_82542_ERT      E1000_ERT
+#define E1000_82542_RXDCTL   E1000_RXDCTL
+#define E1000_82542_RADV     E1000_RADV
+#define E1000_82542_RSRPD    E1000_RSRPD
+#define E1000_82542_TXDMAC   E1000_TXDMAC
+#define E1000_82542_TDFHS    E1000_TDFHS
+#define E1000_82542_TDFTS    E1000_TDFTS
+#define E1000_82542_TDFPC    E1000_TDFPC
+#define E1000_82542_TXDCTL   E1000_TXDCTL
+#define E1000_82542_TADV     E1000_TADV
+#define E1000_82542_TSPMT    E1000_TSPMT
+#define E1000_82542_CRCERRS  E1000_CRCERRS
+#define E1000_82542_ALGNERRC E1000_ALGNERRC
+#define E1000_82542_SYMERRS  E1000_SYMERRS
+#define E1000_82542_RXERRC   E1000_RXERRC
+#define E1000_82542_MPC      E1000_MPC
+#define E1000_82542_SCC      E1000_SCC
+#define E1000_82542_ECOL     E1000_ECOL
+#define E1000_82542_MCC      E1000_MCC
+#define E1000_82542_LATECOL  E1000_LATECOL
+#define E1000_82542_COLC     E1000_COLC
+#define E1000_82542_DC       E1000_DC
+#define E1000_82542_TNCRS    E1000_TNCRS
+#define E1000_82542_SEC      E1000_SEC
+#define E1000_82542_CEXTERR  E1000_CEXTERR
+#define E1000_82542_RLEC     E1000_RLEC
+#define E1000_82542_XONRXC   E1000_XONRXC
+#define E1000_82542_XONTXC   E1000_XONTXC
+#define E1000_82542_XOFFRXC  E1000_XOFFRXC
+#define E1000_82542_XOFFTXC  E1000_XOFFTXC
+#define E1000_82542_FCRUC    E1000_FCRUC
+#define E1000_82542_PRC64    E1000_PRC64
+#define E1000_82542_PRC127   E1000_PRC127
+#define E1000_82542_PRC255   E1000_PRC255
+#define E1000_82542_PRC511   E1000_PRC511
+#define E1000_82542_PRC1023  E1000_PRC1023
+#define E1000_82542_PRC1522  E1000_PRC1522
+#define E1000_82542_GPRC     E1000_GPRC
+#define E1000_82542_BPRC     E1000_BPRC
+#define E1000_82542_MPRC     E1000_MPRC
+#define E1000_82542_GPTC     E1000_GPTC
+#define E1000_82542_GORCL    E1000_GORCL
+#define E1000_82542_GORCH    E1000_GORCH
+#define E1000_82542_GOTCL    E1000_GOTCL
+#define E1000_82542_GOTCH    E1000_GOTCH
+#define E1000_82542_RNBC     E1000_RNBC
+#define E1000_82542_RUC      E1000_RUC
+#define E1000_82542_RFC      E1000_RFC
+#define E1000_82542_ROC      E1000_ROC
+#define E1000_82542_RJC      E1000_RJC
+#define E1000_82542_MGTPRC   E1000_MGTPRC
+#define E1000_82542_MGTPDC   E1000_MGTPDC
+#define E1000_82542_MGTPTC   E1000_MGTPTC
+#define E1000_82542_TORL     E1000_TORL
+#define E1000_82542_TORH     E1000_TORH
+#define E1000_82542_TOTL     E1000_TOTL
+#define E1000_82542_TOTH     E1000_TOTH
+#define E1000_82542_TPR      E1000_TPR
+#define E1000_82542_TPT      E1000_TPT
+#define E1000_82542_PTC64    E1000_PTC64
+#define E1000_82542_PTC127   E1000_PTC127
+#define E1000_82542_PTC255   E1000_PTC255
+#define E1000_82542_PTC511   E1000_PTC511
+#define E1000_82542_PTC1023  E1000_PTC1023
+#define E1000_82542_PTC1522  E1000_PTC1522
+#define E1000_82542_MPTC     E1000_MPTC
+#define E1000_82542_BPTC     E1000_BPTC
+#define E1000_82542_TSCTC    E1000_TSCTC
+#define E1000_82542_TSCTFC   E1000_TSCTFC
+#define E1000_82542_RXCSUM   E1000_RXCSUM
+#define E1000_82542_WUC      E1000_WUC
+#define E1000_82542_WUFC     E1000_WUFC
+#define E1000_82542_WUS      E1000_WUS
+#define E1000_82542_MANC     E1000_MANC
+#define E1000_82542_IPAV     E1000_IPAV
+#define E1000_82542_IP4AT    E1000_IP4AT
+#define E1000_82542_IP6AT    E1000_IP6AT
+#define E1000_82542_WUPL     E1000_WUPL
+#define E1000_82542_WUPM     E1000_WUPM
+#define E1000_82542_FFLT     E1000_FFLT
+#define E1000_82542_TDFH     0x08010
+#define E1000_82542_TDFT     0x08018
+#define E1000_82542_FFMT     E1000_FFMT
+#define E1000_82542_FFVT     E1000_FFVT
+#define E1000_82542_HOST_IF  E1000_HOST_IF
+#define E1000_82542_IAM         E1000_IAM
+#define E1000_82542_EEMNGCTL    E1000_EEMNGCTL
+#define E1000_82542_PSRCTL      E1000_PSRCTL
+#define E1000_82542_RAID        E1000_RAID
+#define E1000_82542_TARC0       E1000_TARC0
+#define E1000_82542_TDBAL1      E1000_TDBAL1
+#define E1000_82542_TDBAH1      E1000_TDBAH1
+#define E1000_82542_TDLEN1      E1000_TDLEN1
+#define E1000_82542_TDH1        E1000_TDH1
+#define E1000_82542_TDT1        E1000_TDT1
+#define E1000_82542_TXDCTL1     E1000_TXDCTL1
+#define E1000_82542_TARC1       E1000_TARC1
+#define E1000_82542_RFCTL       E1000_RFCTL
+#define E1000_82542_GCR         E1000_GCR
+#define E1000_82542_GSCL_1      E1000_GSCL_1
+#define E1000_82542_GSCL_2      E1000_GSCL_2
+#define E1000_82542_GSCL_3      E1000_GSCL_3
+#define E1000_82542_GSCL_4      E1000_GSCL_4
+#define E1000_82542_FACTPS      E1000_FACTPS
+#define E1000_82542_SWSM        E1000_SWSM
+#define E1000_82542_FWSM        E1000_FWSM
+#define E1000_82542_FFLT_DBG    E1000_FFLT_DBG
+#define E1000_82542_IAC         E1000_IAC
+#define E1000_82542_ICRXPTC     E1000_ICRXPTC
+#define E1000_82542_ICRXATC     E1000_ICRXATC
+#define E1000_82542_ICTXPTC     E1000_ICTXPTC
+#define E1000_82542_ICTXATC     E1000_ICTXATC
+#define E1000_82542_ICTXQEC     E1000_ICTXQEC
+#define E1000_82542_ICTXQMTC    E1000_ICTXQMTC
+#define E1000_82542_ICRXDMTC    E1000_ICRXDMTC
+#define E1000_82542_ICRXOC      E1000_ICRXOC
+#define E1000_82542_HICR        E1000_HICR
+
+/* Statistics counters collected by the MAC */
+struct em_hw_stats {
+    uint64_t crcerrs;
+    uint64_t algnerrc;
+    uint64_t symerrs;
+    uint64_t rxerrc;
+    uint64_t mpc;
+    uint64_t scc;
+    uint64_t ecol;
+    uint64_t mcc;
+    uint64_t latecol;
+    uint64_t colc;
+    uint64_t dc;
+    uint64_t tncrs;
+    uint64_t sec;
+    uint64_t cexterr;
+    uint64_t rlec;
+    uint64_t xonrxc;
+    uint64_t xontxc;
+    uint64_t xoffrxc;
+    uint64_t xofftxc;
+    uint64_t fcruc;
+    uint64_t prc64;
+    uint64_t prc127;
+    uint64_t prc255;
+    uint64_t prc511;
+    uint64_t prc1023;
+    uint64_t prc1522;
+    uint64_t gprc;
+    uint64_t bprc;
+    uint64_t mprc;
+    uint64_t gptc;
+    uint64_t gorcl;
+    uint64_t gorch;
+    uint64_t gotcl;
+    uint64_t gotch;
+    uint64_t rnbc;
+    uint64_t ruc;
+    uint64_t rfc;
+    uint64_t roc;
+    uint64_t rjc;
+    uint64_t mgprc;
+    uint64_t mgpdc;
+    uint64_t mgptc;
+    uint64_t torl;
+    uint64_t torh;
+    uint64_t totl;
+    uint64_t toth;
+    uint64_t tpr;
+    uint64_t tpt;
+    uint64_t ptc64;
+    uint64_t ptc127;
+    uint64_t ptc255;
+    uint64_t ptc511;
+    uint64_t ptc1023;
+    uint64_t ptc1522;
+    uint64_t mptc;
+    uint64_t bptc;
+    uint64_t tsctc;
+    uint64_t tsctfc;
+    uint64_t iac;
+    uint64_t icrxptc;
+    uint64_t icrxatc;
+    uint64_t ictxptc;
+    uint64_t ictxatc;
+    uint64_t ictxqec;
+    uint64_t ictxqmtc;
+    uint64_t icrxdmtc;
+    uint64_t icrxoc;
+};
+
+/* Structure containing variables used by the shared code (em_hw.c) */
+struct em_hw {
+    uint8_t *hw_addr;
+    uint8_t *flash_address;
+    em_mac_type mac_type;
+    em_phy_type phy_type;
+    uint32_t phy_init_script;
+    em_media_type media_type;
+    void *back;
+    em_fc_type fc;
+    em_bus_speed bus_speed;
+    em_bus_width bus_width;
+    em_bus_type bus_type;
+    struct em_eeprom_info eeprom;
+    em_ms_type master_slave;
+    em_ms_type original_master_slave;
+    em_ffe_config ffe_config_state;
+    uint32_t asf_firmware_present;
+    uint32_t eeprom_semaphore_present;
+    unsigned long io_base;
+    uint32_t phy_id;
+    uint32_t phy_revision;
+    uint32_t phy_addr;
+    uint32_t original_fc;
+    uint32_t txcw;
+    uint32_t autoneg_failed;
+    uint32_t max_frame_size;
+    uint32_t min_frame_size;
+    uint32_t mc_filter_type;
+    uint32_t num_mc_addrs;
+    uint32_t collision_delta;
+    uint32_t tx_packet_delta;
+    uint32_t ledctl_default;
+    uint32_t ledctl_mode1;
+    uint32_t ledctl_mode2;
+    boolean_t tx_pkt_filtering;
+    struct em_host_mng_dhcp_cookie mng_cookie;
+    uint16_t phy_spd_default;
+    uint16_t autoneg_advertised;
+    uint16_t pci_cmd_word;
+    uint16_t fc_high_water;
+    uint16_t fc_low_water;
+    uint16_t fc_pause_time;
+    uint16_t current_ifs_val;
+    uint16_t ifs_min_val;
+    uint16_t ifs_max_val;
+    uint16_t ifs_step_size;
+    uint16_t ifs_ratio;
+    uint16_t device_id;
+    uint16_t vendor_id;
+    uint16_t subsystem_id;
+    uint16_t subsystem_vendor_id;
+    uint8_t revision_id;
+    uint8_t autoneg;
+    uint8_t mdix;
+    uint8_t forced_speed_duplex;
+    uint8_t wait_autoneg_complete;
+    uint8_t dma_fairness;
+    uint8_t mac_addr[NODE_ADDRESS_SIZE];
+    uint8_t perm_mac_addr[NODE_ADDRESS_SIZE];
+    boolean_t disable_polarity_correction;
+    boolean_t speed_downgraded;
+    em_smart_speed smart_speed;
+    em_dsp_config dsp_config_state;
+    boolean_t get_link_status;
+    boolean_t serdes_link_down;
+    boolean_t tbi_compatibility_en;
+    boolean_t tbi_compatibility_on;
+    boolean_t phy_reset_disable;
+    boolean_t fc_send_xon;
+    boolean_t fc_strict_ieee;
+    boolean_t report_tx_early;
+    boolean_t adaptive_ifs;
+    boolean_t ifs_params_forced;
+    boolean_t in_ifs_mode;
+    boolean_t mng_reg_access_disabled;
+};
+
+
+#define E1000_EEPROM_SWDPIN0   0x0001   /* SWDPIN 0 EEPROM Value */
+#define E1000_EEPROM_LED_LOGIC 0x0020   /* Led Logic Word */
+#define E1000_EEPROM_RW_REG_DATA   16   /* Offset to data in EEPROM read/write registers */
+#define E1000_EEPROM_RW_REG_DONE   2    /* Offset to READ/WRITE done bit */
+#define E1000_EEPROM_RW_REG_START  1    /* First bit for telling part to start operation */
+#define E1000_EEPROM_RW_ADDR_SHIFT 2    /* Shift to the address bits */
+#define E1000_EEPROM_POLL_WRITE    1    /* Flag for polling for write complete */
+#define E1000_EEPROM_POLL_READ     0    /* Flag for polling for read complete */
+/* Register Bit Masks */
+/* Device Control */
+#define E1000_CTRL_FD       0x00000001  /* Full duplex.0=half; 1=full */
+#define E1000_CTRL_BEM      0x00000002  /* Endian Mode.0=little,1=big */
+#define E1000_CTRL_PRIOR    0x00000004  /* Priority on PCI. 0=rx,1=fair */
+#define E1000_CTRL_GIO_MASTER_DISABLE 0x00000004 /*Blocks new Master requests */
+#define E1000_CTRL_LRST     0x00000008  /* Link reset. 0=normal,1=reset */
+#define E1000_CTRL_TME      0x00000010  /* Test mode. 0=normal,1=test */
+#define E1000_CTRL_SLE      0x00000020  /* Serial Link on 0=dis,1=en */
+#define E1000_CTRL_ASDE     0x00000020  /* Auto-speed detect enable */
+#define E1000_CTRL_SLU      0x00000040  /* Set link up (Force Link) */
+#define E1000_CTRL_ILOS     0x00000080  /* Invert Loss-Of Signal */
+#define E1000_CTRL_SPD_SEL  0x00000300  /* Speed Select Mask */
+#define E1000_CTRL_SPD_10   0x00000000  /* Force 10Mb */
+#define E1000_CTRL_SPD_100  0x00000100  /* Force 100Mb */
+#define E1000_CTRL_SPD_1000 0x00000200  /* Force 1Gb */
+#define E1000_CTRL_BEM32    0x00000400  /* Big Endian 32 mode */
+#define E1000_CTRL_FRCSPD   0x00000800  /* Force Speed */
+#define E1000_CTRL_FRCDPX   0x00001000  /* Force Duplex */
+#define E1000_CTRL_D_UD_POLARITY 0x00004000 /* Defined polarity of Dock/Undock indication in SDP[0] */
+#define E1000_CTRL_SWDPIN0  0x00040000  /* SWDPIN 0 value */
+#define E1000_CTRL_SWDPIN1  0x00080000  /* SWDPIN 1 value */
+#define E1000_CTRL_SWDPIN2  0x00100000  /* SWDPIN 2 value */
+#define E1000_CTRL_SWDPIN3  0x00200000  /* SWDPIN 3 value */
+#define E1000_CTRL_SWDPIO0  0x00400000  /* SWDPIN 0 Input or output */
+#define E1000_CTRL_SWDPIO1  0x00800000  /* SWDPIN 1 input or output */
+#define E1000_CTRL_SWDPIO2  0x01000000  /* SWDPIN 2 input or output */
+#define E1000_CTRL_SWDPIO3  0x02000000  /* SWDPIN 3 input or output */
+#define E1000_CTRL_RST      0x04000000  /* Global reset */
+#define E1000_CTRL_RFCE     0x08000000  /* Receive Flow Control enable */
+#define E1000_CTRL_TFCE     0x10000000  /* Transmit flow control enable */
+#define E1000_CTRL_RTE      0x20000000  /* Routing tag enable */
+#define E1000_CTRL_VME      0x40000000  /* IEEE VLAN mode enable */
+#define E1000_CTRL_PHY_RST  0x80000000  /* PHY Reset */
+
+/* Device Status */
+#define E1000_STATUS_FD         0x00000001      /* Full duplex.0=half,1=full */
+#define E1000_STATUS_LU         0x00000002      /* Link up.0=no,1=link */
+#define E1000_STATUS_FUNC_MASK  0x0000000C      /* PCI Function Mask */
+#define E1000_STATUS_FUNC_SHIFT 2
+#define E1000_STATUS_FUNC_0     0x00000000      /* Function 0 */
+#define E1000_STATUS_FUNC_1     0x00000004      /* Function 1 */
+#define E1000_STATUS_TXOFF      0x00000010      /* transmission paused */
+#define E1000_STATUS_TBIMODE    0x00000020      /* TBI mode */
+#define E1000_STATUS_SPEED_MASK 0x000000C0
+#define E1000_STATUS_SPEED_10   0x00000000      /* Speed 10Mb/s */
+#define E1000_STATUS_SPEED_100  0x00000040      /* Speed 100Mb/s */
+#define E1000_STATUS_SPEED_1000 0x00000080      /* Speed 1000Mb/s */
+#define E1000_STATUS_ASDV       0x00000300      /* Auto speed detect value */
+#define E1000_STATUS_DOCK_CI    0x00000800      /* Change in Dock/Undock state. Clear on write '0'. */
+#define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000 /* Status of Master requests. */
+#define E1000_STATUS_MTXCKOK    0x00000400      /* MTX clock running OK */
+#define E1000_STATUS_PCI66      0x00000800      /* In 66Mhz slot */
+#define E1000_STATUS_BUS64      0x00001000      /* In 64 bit slot */
+#define E1000_STATUS_PCIX_MODE  0x00002000      /* PCI-X mode */
+#define E1000_STATUS_PCIX_SPEED 0x0000C000      /* PCI-X bus speed */
+
+/* Constants used to intrepret the masked PCI-X bus speed. */
+#define E1000_STATUS_PCIX_SPEED_66  0x00000000 /* PCI-X bus speed  50-66 MHz */
+#define E1000_STATUS_PCIX_SPEED_100 0x00004000 /* PCI-X bus speed  66-100 MHz */
+#define E1000_STATUS_PCIX_SPEED_133 0x00008000 /* PCI-X bus speed 100-133 MHz */
+
+/* EEPROM/Flash Control */
+#define E1000_EECD_SK        0x00000001 /* EEPROM Clock */
+#define E1000_EECD_CS        0x00000002 /* EEPROM Chip Select */
+#define E1000_EECD_DI        0x00000004 /* EEPROM Data In */
+#define E1000_EECD_DO        0x00000008 /* EEPROM Data Out */
+#define E1000_EECD_FWE_MASK  0x00000030
+#define E1000_EECD_FWE_DIS   0x00000010 /* Disable FLASH writes */
+#define E1000_EECD_FWE_EN    0x00000020 /* Enable FLASH writes */
+#define E1000_EECD_FWE_SHIFT 4
+#define E1000_EECD_REQ       0x00000040 /* EEPROM Access Request */
+#define E1000_EECD_GNT       0x00000080 /* EEPROM Access Grant */
+#define E1000_EECD_PRES      0x00000100 /* EEPROM Present */
+#define E1000_EECD_SIZE      0x00000200 /* EEPROM Size (0=64 word 1=256 word) */
+#define E1000_EECD_ADDR_BITS 0x00000400 /* EEPROM Addressing bits based on type
+                                         * (0-small, 1-large) */
+#define E1000_EECD_TYPE      0x00002000 /* EEPROM Type (1-SPI, 0-Microwire) */
+#ifndef E1000_EEPROM_GRANT_ATTEMPTS
+#define E1000_EEPROM_GRANT_ATTEMPTS 1000 /* EEPROM # attempts to gain grant */
+#endif
+#define E1000_EECD_AUTO_RD          0x00000200  /* EEPROM Auto Read done */
+#define E1000_EECD_SIZE_EX_MASK     0x00007800  /* EEprom Size */
+#define E1000_EECD_SIZE_EX_SHIFT    11
+#define E1000_EECD_NVADDS    0x00018000 /* NVM Address Size */
+#define E1000_EECD_SELSHAD   0x00020000 /* Select Shadow RAM */
+#define E1000_EECD_INITSRAM  0x00040000 /* Initialize Shadow RAM */
+#define E1000_EECD_FLUPD     0x00080000 /* Update FLASH */
+#define E1000_EECD_AUPDEN    0x00100000 /* Enable Autonomous FLASH update */
+#define E1000_EECD_SHADV     0x00200000 /* Shadow RAM Data Valid */
+#define E1000_EECD_SEC1VAL   0x00400000 /* Sector One Valid */
+#define E1000_STM_OPCODE     0xDB00
+#define E1000_HICR_FW_RESET  0xC0
+
+/* EEPROM Read */
+#define E1000_EERD_START      0x00000001 /* Start Read */
+#define E1000_EERD_DONE       0x00000010 /* Read Done */
+#define E1000_EERD_ADDR_SHIFT 8
+#define E1000_EERD_ADDR_MASK  0x0000FF00 /* Read Address */
+#define E1000_EERD_DATA_SHIFT 16
+#define E1000_EERD_DATA_MASK  0xFFFF0000 /* Read Data */
+
+/* SPI EEPROM Status Register */
+#define EEPROM_STATUS_RDY_SPI  0x01
+#define EEPROM_STATUS_WEN_SPI  0x02
+#define EEPROM_STATUS_BP0_SPI  0x04
+#define EEPROM_STATUS_BP1_SPI  0x08
+#define EEPROM_STATUS_WPEN_SPI 0x80
+
+/* Extended Device Control */
+#define E1000_CTRL_EXT_GPI0_EN   0x00000001 /* Maps SDP4 to GPI0 */
+#define E1000_CTRL_EXT_GPI1_EN   0x00000002 /* Maps SDP5 to GPI1 */
+#define E1000_CTRL_EXT_PHYINT_EN E1000_CTRL_EXT_GPI1_EN
+#define E1000_CTRL_EXT_GPI2_EN   0x00000004 /* Maps SDP6 to GPI2 */
+#define E1000_CTRL_EXT_GPI3_EN   0x00000008 /* Maps SDP7 to GPI3 */
+#define E1000_CTRL_EXT_SDP4_DATA 0x00000010 /* Value of SW Defineable Pin 4 */
+#define E1000_CTRL_EXT_SDP5_DATA 0x00000020 /* Value of SW Defineable Pin 5 */
+#define E1000_CTRL_EXT_PHY_INT   E1000_CTRL_EXT_SDP5_DATA
+#define E1000_CTRL_EXT_SDP6_DATA 0x00000040 /* Value of SW Defineable Pin 6 */
+#define E1000_CTRL_EXT_SDP7_DATA 0x00000080 /* Value of SW Defineable Pin 7 */
+#define E1000_CTRL_EXT_SDP4_DIR  0x00000100 /* Direction of SDP4 0=in 1=out */
+#define E1000_CTRL_EXT_SDP5_DIR  0x00000200 /* Direction of SDP5 0=in 1=out */
+#define E1000_CTRL_EXT_SDP6_DIR  0x00000400 /* Direction of SDP6 0=in 1=out */
+#define E1000_CTRL_EXT_SDP7_DIR  0x00000800 /* Direction of SDP7 0=in 1=out */
+#define E1000_CTRL_EXT_ASDCHK    0x00001000 /* Initiate an ASD sequence */
+#define E1000_CTRL_EXT_EE_RST    0x00002000 /* Reinitialize from EEPROM */
+#define E1000_CTRL_EXT_IPS       0x00004000 /* Invert Power State */
+#define E1000_CTRL_EXT_SPD_BYPS  0x00008000 /* Speed Select Bypass */
+#define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000
+#define E1000_CTRL_EXT_LINK_MODE_GMII 0x00000000
+#define E1000_CTRL_EXT_LINK_MODE_TBI  0x00C00000
+#define E1000_CTRL_EXT_WR_WMARK_MASK  0x03000000
+#define E1000_CTRL_EXT_WR_WMARK_256   0x00000000
+#define E1000_CTRL_EXT_WR_WMARK_320   0x01000000
+#define E1000_CTRL_EXT_WR_WMARK_384   0x02000000
+#define E1000_CTRL_EXT_WR_WMARK_448   0x03000000
+#define E1000_CTRL_EXT_IAME           0x08000000  /* Interrupt acknowledge Auto-mask */
+#define E1000_CTRL_EXT_INT_TIMER_CLR  0x20000000  /* Clear Interrupt timers after IMS clear */
+
+/* MDI Control */
+#define E1000_MDIC_DATA_MASK 0x0000FFFF
+#define E1000_MDIC_REG_MASK  0x001F0000
+#define E1000_MDIC_REG_SHIFT 16
+#define E1000_MDIC_PHY_MASK  0x03E00000
+#define E1000_MDIC_PHY_SHIFT 21
+#define E1000_MDIC_OP_WRITE  0x04000000
+#define E1000_MDIC_OP_READ   0x08000000
+#define E1000_MDIC_READY     0x10000000
+#define E1000_MDIC_INT_EN    0x20000000
+#define E1000_MDIC_ERROR     0x40000000
+
+/* LED Control */
+#define E1000_LEDCTL_LED0_MODE_MASK       0x0000000F
+#define E1000_LEDCTL_LED0_MODE_SHIFT      0
+#define E1000_LEDCTL_LED0_BLINK_RATE      0x0000020
+#define E1000_LEDCTL_LED0_IVRT            0x00000040
+#define E1000_LEDCTL_LED0_BLINK           0x00000080
+#define E1000_LEDCTL_LED1_MODE_MASK       0x00000F00
+#define E1000_LEDCTL_LED1_MODE_SHIFT      8
+#define E1000_LEDCTL_LED1_BLINK_RATE      0x0002000
+#define E1000_LEDCTL_LED1_IVRT            0x00004000
+#define E1000_LEDCTL_LED1_BLINK           0x00008000
+#define E1000_LEDCTL_LED2_MODE_MASK       0x000F0000
+#define E1000_LEDCTL_LED2_MODE_SHIFT      16
+#define E1000_LEDCTL_LED2_BLINK_RATE      0x00200000
+#define E1000_LEDCTL_LED2_IVRT            0x00400000
+#define E1000_LEDCTL_LED2_BLINK           0x00800000
+#define E1000_LEDCTL_LED3_MODE_MASK       0x0F000000
+#define E1000_LEDCTL_LED3_MODE_SHIFT      24
+#define E1000_LEDCTL_LED3_IVRT            0x40000000
+#define E1000_LEDCTL_LED3_BLINK           0x80000000
+
+#define E1000_LEDCTL_MODE_LINK_10_1000  0x0
+#define E1000_LEDCTL_MODE_LINK_100_1000 0x1
+#define E1000_LEDCTL_MODE_LINK_UP       0x2
+#define E1000_LEDCTL_MODE_ACTIVITY      0x3
+#define E1000_LEDCTL_MODE_LINK_ACTIVITY 0x4
+#define E1000_LEDCTL_MODE_LINK_10       0x5
+#define E1000_LEDCTL_MODE_LINK_100      0x6
+#define E1000_LEDCTL_MODE_LINK_1000     0x7
+#define E1000_LEDCTL_MODE_PCIX_MODE     0x8
+#define E1000_LEDCTL_MODE_FULL_DUPLEX   0x9
+#define E1000_LEDCTL_MODE_COLLISION     0xA
+#define E1000_LEDCTL_MODE_BUS_SPEED     0xB
+#define E1000_LEDCTL_MODE_BUS_SIZE      0xC
+#define E1000_LEDCTL_MODE_PAUSED        0xD
+#define E1000_LEDCTL_MODE_LED_ON        0xE
+#define E1000_LEDCTL_MODE_LED_OFF       0xF
+
+/* Receive Address */
+#define E1000_RAH_AV  0x80000000        /* Receive descriptor valid */
+
+/* Interrupt Cause Read */
+#define E1000_ICR_TXDW          0x00000001 /* Transmit desc written back */
+#define E1000_ICR_TXQE          0x00000002 /* Transmit Queue empty */
+#define E1000_ICR_LSC           0x00000004 /* Link Status Change */
+#define E1000_ICR_RXSEQ         0x00000008 /* rx sequence error */
+#define E1000_ICR_RXDMT0        0x00000010 /* rx desc min. threshold (0) */
+#define E1000_ICR_RXO           0x00000040 /* rx overrun */
+#define E1000_ICR_RXT0          0x00000080 /* rx timer intr (ring 0) */
+#define E1000_ICR_MDAC          0x00000200 /* MDIO access complete */
+#define E1000_ICR_RXCFG         0x00000400 /* RX /c/ ordered set */
+#define E1000_ICR_GPI_EN0       0x00000800 /* GP Int 0 */
+#define E1000_ICR_GPI_EN1       0x00001000 /* GP Int 1 */
+#define E1000_ICR_GPI_EN2       0x00002000 /* GP Int 2 */
+#define E1000_ICR_GPI_EN3       0x00004000 /* GP Int 3 */
+#define E1000_ICR_TXD_LOW       0x00008000
+#define E1000_ICR_SRPD          0x00010000
+#define E1000_ICR_ACK           0x00020000 /* Receive Ack frame */
+#define E1000_ICR_MNG           0x00040000 /* Manageability event */
+#define E1000_ICR_DOCK          0x00080000 /* Dock/Undock */
+#define E1000_ICR_INT_ASSERTED  0x80000000 /* If this bit asserted, the driver should claim the interrupt */
+
+/* Interrupt Cause Set */
+#define E1000_ICS_TXDW      E1000_ICR_TXDW      /* Transmit desc written back */
+#define E1000_ICS_TXQE      E1000_ICR_TXQE      /* Transmit Queue empty */
+#define E1000_ICS_LSC       E1000_ICR_LSC       /* Link Status Change */
+#define E1000_ICS_RXSEQ     E1000_ICR_RXSEQ     /* rx sequence error */
+#define E1000_ICS_RXDMT0    E1000_ICR_RXDMT0    /* rx desc min. threshold */
+#define E1000_ICS_RXO       E1000_ICR_RXO       /* rx overrun */
+#define E1000_ICS_RXT0      E1000_ICR_RXT0      /* rx timer intr */
+#define E1000_ICS_MDAC      E1000_ICR_MDAC      /* MDIO access complete */
+#define E1000_ICS_RXCFG     E1000_ICR_RXCFG     /* RX /c/ ordered set */
+#define E1000_ICS_GPI_EN0   E1000_ICR_GPI_EN0   /* GP Int 0 */
+#define E1000_ICS_GPI_EN1   E1000_ICR_GPI_EN1   /* GP Int 1 */
+#define E1000_ICS_GPI_EN2   E1000_ICR_GPI_EN2   /* GP Int 2 */
+#define E1000_ICS_GPI_EN3   E1000_ICR_GPI_EN3   /* GP Int 3 */
+#define E1000_ICS_TXD_LOW   E1000_ICR_TXD_LOW
+#define E1000_ICS_SRPD      E1000_ICR_SRPD
+#define E1000_ICS_ACK       E1000_ICR_ACK       /* Receive Ack frame */
+#define E1000_ICS_MNG       E1000_ICR_MNG       /* Manageability event */
+#define E1000_ICS_DOCK      E1000_ICR_DOCK      /* Dock/Undock */
+
+/* Interrupt Mask Set */
+#define E1000_IMS_TXDW      E1000_ICR_TXDW      /* Transmit desc written back */
+#define E1000_IMS_TXQE      E1000_ICR_TXQE      /* Transmit Queue empty */
+#define E1000_IMS_LSC       E1000_ICR_LSC       /* Link Status Change */
+#define E1000_IMS_RXSEQ     E1000_ICR_RXSEQ     /* rx sequence error */
+#define E1000_IMS_RXDMT0    E1000_ICR_RXDMT0    /* rx desc min. threshold */
+#define E1000_IMS_RXO       E1000_ICR_RXO       /* rx overrun */
+#define E1000_IMS_RXT0      E1000_ICR_RXT0      /* rx timer intr */
+#define E1000_IMS_MDAC      E1000_ICR_MDAC      /* MDIO access complete */
+#define E1000_IMS_RXCFG     E1000_ICR_RXCFG     /* RX /c/ ordered set */
+#define E1000_IMS_GPI_EN0   E1000_ICR_GPI_EN0   /* GP Int 0 */
+#define E1000_IMS_GPI_EN1   E1000_ICR_GPI_EN1   /* GP Int 1 */
+#define E1000_IMS_GPI_EN2   E1000_ICR_GPI_EN2   /* GP Int 2 */
+#define E1000_IMS_GPI_EN3   E1000_ICR_GPI_EN3   /* GP Int 3 */
+#define E1000_IMS_TXD_LOW   E1000_ICR_TXD_LOW
+#define E1000_IMS_SRPD      E1000_ICR_SRPD
+#define E1000_IMS_ACK       E1000_ICR_ACK       /* Receive Ack frame */
+#define E1000_IMS_MNG       E1000_ICR_MNG       /* Manageability event */
+#define E1000_IMS_DOCK      E1000_ICR_DOCK      /* Dock/Undock */
+
+/* Interrupt Mask Clear */
+#define E1000_IMC_TXDW      E1000_ICR_TXDW      /* Transmit desc written back */
+#define E1000_IMC_TXQE      E1000_ICR_TXQE      /* Transmit Queue empty */
+#define E1000_IMC_LSC       E1000_ICR_LSC       /* Link Status Change */
+#define E1000_IMC_RXSEQ     E1000_ICR_RXSEQ     /* rx sequence error */
+#define E1000_IMC_RXDMT0    E1000_ICR_RXDMT0    /* rx desc min. threshold */
+#define E1000_IMC_RXO       E1000_ICR_RXO       /* rx overrun */
+#define E1000_IMC_RXT0      E1000_ICR_RXT0      /* rx timer intr */
+#define E1000_IMC_MDAC      E1000_ICR_MDAC      /* MDIO access complete */
+#define E1000_IMC_RXCFG     E1000_ICR_RXCFG     /* RX /c/ ordered set */
+#define E1000_IMC_GPI_EN0   E1000_ICR_GPI_EN0   /* GP Int 0 */
+#define E1000_IMC_GPI_EN1   E1000_ICR_GPI_EN1   /* GP Int 1 */
+#define E1000_IMC_GPI_EN2   E1000_ICR_GPI_EN2   /* GP Int 2 */
+#define E1000_IMC_GPI_EN3   E1000_ICR_GPI_EN3   /* GP Int 3 */
+#define E1000_IMC_TXD_LOW   E1000_ICR_TXD_LOW
+#define E1000_IMC_SRPD      E1000_ICR_SRPD
+#define E1000_IMC_ACK       E1000_ICR_ACK       /* Receive Ack frame */
+#define E1000_IMC_MNG       E1000_ICR_MNG       /* Manageability event */
+#define E1000_IMC_DOCK      E1000_ICR_DOCK      /* Dock/Undock */
+
+/* Receive Control */
+#define E1000_RCTL_RST            0x00000001    /* Software reset */
+#define E1000_RCTL_EN             0x00000002    /* enable */
+#define E1000_RCTL_SBP            0x00000004    /* store bad packet */
+#define E1000_RCTL_UPE            0x00000008    /* unicast promiscuous enable */
+#define E1000_RCTL_MPE            0x00000010    /* multicast promiscuous enab */
+#define E1000_RCTL_LPE            0x00000020    /* long packet enable */
+#define E1000_RCTL_LBM_NO         0x00000000    /* no loopback mode */
+#define E1000_RCTL_LBM_MAC        0x00000040    /* MAC loopback mode */
+#define E1000_RCTL_LBM_SLP        0x00000080    /* serial link loopback mode */
+#define E1000_RCTL_LBM_TCVR       0x000000C0    /* tcvr loopback mode */
+#define E1000_RCTL_DTYP_MASK      0x00000C00    /* Descriptor type mask */
+#define E1000_RCTL_DTYP_PS        0x00000400    /* Packet Split descriptor */
+#define E1000_RCTL_RDMTS_HALF     0x00000000    /* rx desc min threshold size */
+#define E1000_RCTL_RDMTS_QUAT     0x00000100    /* rx desc min threshold size */
+#define E1000_RCTL_RDMTS_EIGTH    0x00000200    /* rx desc min threshold size */
+#define E1000_RCTL_MO_SHIFT       12            /* multicast offset shift */
+#define E1000_RCTL_MO_0           0x00000000    /* multicast offset 11:0 */
+#define E1000_RCTL_MO_1           0x00001000    /* multicast offset 12:1 */
+#define E1000_RCTL_MO_2           0x00002000    /* multicast offset 13:2 */
+#define E1000_RCTL_MO_3           0x00003000    /* multicast offset 15:4 */
+#define E1000_RCTL_MDR            0x00004000    /* multicast desc ring 0 */
+#define E1000_RCTL_BAM            0x00008000    /* broadcast enable */
+/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */
+#define E1000_RCTL_SZ_2048        0x00000000    /* rx buffer size 2048 */
+#define E1000_RCTL_SZ_1024        0x00010000    /* rx buffer size 1024 */
+#define E1000_RCTL_SZ_512         0x00020000    /* rx buffer size 512 */
+#define E1000_RCTL_SZ_256         0x00030000    /* rx buffer size 256 */
+/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */
+#define E1000_RCTL_SZ_16384       0x00010000    /* rx buffer size 16384 */
+#define E1000_RCTL_SZ_8192        0x00020000    /* rx buffer size 8192 */
+#define E1000_RCTL_SZ_4096        0x00030000    /* rx buffer size 4096 */
+#define E1000_RCTL_VFE            0x00040000    /* vlan filter enable */
+#define E1000_RCTL_CFIEN          0x00080000    /* canonical form enable */
+#define E1000_RCTL_CFI            0x00100000    /* canonical form indicator */
+#define E1000_RCTL_DPF            0x00400000    /* discard pause frames */
+#define E1000_RCTL_PMCF           0x00800000    /* pass MAC control frames */
+#define E1000_RCTL_BSEX           0x02000000    /* Buffer size extension */
+#define E1000_RCTL_SECRC          0x04000000    /* Strip Ethernet CRC */
+#define E1000_RCTL_FLXBUF_MASK    0x78000000    /* Flexible buffer size */
+#define E1000_RCTL_FLXBUF_SHIFT   27            /* Flexible buffer shift */
+
+/* Use byte values for the following shift parameters
+ * Usage:
+ *     psrctl |= (((ROUNDUP(value0, 128) >> E1000_PSRCTL_BSIZE0_SHIFT) &
+ *                  E1000_PSRCTL_BSIZE0_MASK) |
+ *                ((ROUNDUP(value1, 1024) >> E1000_PSRCTL_BSIZE1_SHIFT) &
+ *                  E1000_PSRCTL_BSIZE1_MASK) |
+ *                ((ROUNDUP(value2, 1024) << E1000_PSRCTL_BSIZE2_SHIFT) &
+ *                  E1000_PSRCTL_BSIZE2_MASK) |
+ *                ((ROUNDUP(value3, 1024) << E1000_PSRCTL_BSIZE3_SHIFT) |;
+ *                  E1000_PSRCTL_BSIZE3_MASK))
+ * where value0 = [128..16256],  default=256
+ *       value1 = [1024..64512], default=4096
+ *       value2 = [0..64512],    default=4096
+ *       value3 = [0..64512],    default=0
+ */
+    
+#define E1000_PSRCTL_BSIZE0_MASK   0x0000007F
+#define E1000_PSRCTL_BSIZE1_MASK   0x00003F00
+#define E1000_PSRCTL_BSIZE2_MASK   0x003F0000
+#define E1000_PSRCTL_BSIZE3_MASK   0x3F000000
+
+#define E1000_PSRCTL_BSIZE0_SHIFT  7            /* Shift _right_ 7 */
+#define E1000_PSRCTL_BSIZE1_SHIFT  2            /* Shift _right_ 2 */
+#define E1000_PSRCTL_BSIZE2_SHIFT  6            /* Shift _left_ 6 */
+#define E1000_PSRCTL_BSIZE3_SHIFT 14            /* Shift _left_ 14 */
+
+/* Receive Descriptor */
+#define E1000_RDT_DELAY 0x0000ffff      /* Delay timer (1=1024us) */
+#define E1000_RDT_FPDB  0x80000000      /* Flush descriptor block */
+#define E1000_RDLEN_LEN 0x0007ff80      /* descriptor length */
+#define E1000_RDH_RDH   0x0000ffff      /* receive descriptor head */
+#define E1000_RDT_RDT   0x0000ffff      /* receive descriptor tail */
+
+/* Flow Control */
+#define E1000_FCRTH_RTH  0x0000FFF8     /* Mask Bits[15:3] for RTH */
+#define E1000_FCRTH_XFCE 0x80000000     /* External Flow Control Enable */
+#define E1000_FCRTL_RTL  0x0000FFF8     /* Mask Bits[15:3] for RTL */
+#define E1000_FCRTL_XONE 0x80000000     /* Enable XON frame transmission */
+
+/* Header split receive */
+#define E1000_RFCTL_ISCSI_DIS           0x00000001
+#define E1000_RFCTL_ISCSI_DWC_MASK      0x0000003E
+#define E1000_RFCTL_ISCSI_DWC_SHIFT     1
+#define E1000_RFCTL_NFSW_DIS            0x00000040
+#define E1000_RFCTL_NFSR_DIS            0x00000080
+#define E1000_RFCTL_NFS_VER_MASK        0x00000300
+#define E1000_RFCTL_NFS_VER_SHIFT       8
+#define E1000_RFCTL_IPV6_DIS            0x00000400
+#define E1000_RFCTL_IPV6_XSUM_DIS       0x00000800
+#define E1000_RFCTL_ACK_DIS             0x00001000
+#define E1000_RFCTL_ACKD_DIS            0x00002000
+#define E1000_RFCTL_IPFRSP_DIS          0x00004000
+#define E1000_RFCTL_EXTEN               0x00008000
+#define E1000_RFCTL_IPV6_EX_DIS         0x00010000
+#define E1000_RFCTL_NEW_IPV6_EXT_DIS    0x00020000
+
+/* Receive Descriptor Control */
+#define E1000_RXDCTL_PTHRESH 0x0000003F /* RXDCTL Prefetch Threshold */
+#define E1000_RXDCTL_HTHRESH 0x00003F00 /* RXDCTL Host Threshold */
+#define E1000_RXDCTL_WTHRESH 0x003F0000 /* RXDCTL Writeback Threshold */
+#define E1000_RXDCTL_GRAN    0x01000000 /* RXDCTL Granularity */
+
+/* Transmit Descriptor Control */
+#define E1000_TXDCTL_PTHRESH 0x000000FF /* TXDCTL Prefetch Threshold */
+#define E1000_TXDCTL_HTHRESH 0x0000FF00 /* TXDCTL Host Threshold */
+#define E1000_TXDCTL_WTHRESH 0x00FF0000 /* TXDCTL Writeback Threshold */
+#define E1000_TXDCTL_GRAN    0x01000000 /* TXDCTL Granularity */
+#define E1000_TXDCTL_LWTHRESH 0xFE000000 /* TXDCTL Low Threshold */
+#define E1000_TXDCTL_FULL_TX_DESC_WB 0x01010000 /* GRAN=1, WTHRESH=1 */
+#define E1000_TXDCTL_COUNT_DESC 0x00400000 /* Enable the counting of desc.
+                                              still to be processed. */
+
+/* Transmit Configuration Word */
+#define E1000_TXCW_FD         0x00000020        /* TXCW full duplex */
+#define E1000_TXCW_HD         0x00000040        /* TXCW half duplex */
+#define E1000_TXCW_PAUSE      0x00000080        /* TXCW sym pause request */
+#define E1000_TXCW_ASM_DIR    0x00000100        /* TXCW astm pause direction */
+#define E1000_TXCW_PAUSE_MASK 0x00000180        /* TXCW pause request mask */
+#define E1000_TXCW_RF         0x00003000        /* TXCW remote fault */
+#define E1000_TXCW_NP         0x00008000        /* TXCW next page */
+#define E1000_TXCW_CW         0x0000ffff        /* TxConfigWord mask */
+#define E1000_TXCW_TXC        0x40000000        /* Transmit Config control */
+#define E1000_TXCW_ANE        0x80000000        /* Auto-neg enable */
+
+/* Receive Configuration Word */
+#define E1000_RXCW_CW    0x0000ffff     /* RxConfigWord mask */
+#define E1000_RXCW_NC    0x04000000     /* Receive config no carrier */
+#define E1000_RXCW_IV    0x08000000     /* Receive config invalid */
+#define E1000_RXCW_CC    0x10000000     /* Receive config change */
+#define E1000_RXCW_C     0x20000000     /* Receive config */
+#define E1000_RXCW_SYNCH 0x40000000     /* Receive config synch */
+#define E1000_RXCW_ANC   0x80000000     /* Auto-neg complete */
+
+/* Transmit Control */
+#define E1000_TCTL_RST    0x00000001    /* software reset */
+#define E1000_TCTL_EN     0x00000002    /* enable tx */
+#define E1000_TCTL_BCE    0x00000004    /* busy check enable */
+#define E1000_TCTL_PSP    0x00000008    /* pad short packets */
+#define E1000_TCTL_CT     0x00000ff0    /* collision threshold */
+#define E1000_TCTL_COLD   0x003ff000    /* collision distance */
+#define E1000_TCTL_SWXOFF 0x00400000    /* SW Xoff transmission */
+#define E1000_TCTL_PBE    0x00800000    /* Packet Burst Enable */
+#define E1000_TCTL_RTLC   0x01000000    /* Re-transmit on late collision */
+#define E1000_TCTL_NRTU   0x02000000    /* No Re-transmit on underrun */
+#define E1000_TCTL_MULR   0x10000000    /* Multiple request support */
+
+/* Receive Checksum Control */
+#define E1000_RXCSUM_PCSS_MASK 0x000000FF   /* Packet Checksum Start */
+#define E1000_RXCSUM_IPOFL     0x00000100   /* IPv4 checksum offload */
+#define E1000_RXCSUM_TUOFL     0x00000200   /* TCP / UDP checksum offload */
+#define E1000_RXCSUM_IPV6OFL   0x00000400   /* IPv6 checksum offload */
+#define E1000_RXCSUM_IPPCSE    0x00001000   /* IP payload checksum enable */
+#define E1000_RXCSUM_PCSD      0x00002000   /* packet checksum disabled */
+
+
+/* Definitions for power management and wakeup registers */
+/* Wake Up Control */
+#define E1000_WUC_APME       0x00000001 /* APM Enable */
+#define E1000_WUC_PME_EN     0x00000002 /* PME Enable */
+#define E1000_WUC_PME_STATUS 0x00000004 /* PME Status */
+#define E1000_WUC_APMPME     0x00000008 /* Assert PME on APM Wakeup */
+#define E1000_WUC_SPM        0x80000000 /* Enable SPM */
+
+/* Wake Up Filter Control */
+#define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */
+#define E1000_WUFC_MAG  0x00000002 /* Magic Packet Wakeup Enable */
+#define E1000_WUFC_EX   0x00000004 /* Directed Exact Wakeup Enable */
+#define E1000_WUFC_MC   0x00000008 /* Directed Multicast Wakeup Enable */
+#define E1000_WUFC_BC   0x00000010 /* Broadcast Wakeup Enable */
+#define E1000_WUFC_ARP  0x00000020 /* ARP Request Packet Wakeup Enable */
+#define E1000_WUFC_IPV4 0x00000040 /* Directed IPv4 Packet Wakeup Enable */
+#define E1000_WUFC_IPV6 0x00000080 /* Directed IPv6 Packet Wakeup Enable */
+#define E1000_WUFC_IGNORE_TCO      0x00008000 /* Ignore WakeOn TCO packets */
+#define E1000_WUFC_FLX0 0x00010000 /* Flexible Filter 0 Enable */
+#define E1000_WUFC_FLX1 0x00020000 /* Flexible Filter 1 Enable */
+#define E1000_WUFC_FLX2 0x00040000 /* Flexible Filter 2 Enable */
+#define E1000_WUFC_FLX3 0x00080000 /* Flexible Filter 3 Enable */
+#define E1000_WUFC_ALL_FILTERS 0x000F00FF /* Mask for all wakeup filters */
+#define E1000_WUFC_FLX_OFFSET 16       /* Offset to the Flexible Filters bits */
+#define E1000_WUFC_FLX_FILTERS 0x000F0000 /* Mask for the 4 flexible filters */
+
+/* Wake Up Status */
+#define E1000_WUS_LNKC 0x00000001 /* Link Status Changed */
+#define E1000_WUS_MAG  0x00000002 /* Magic Packet Received */
+#define E1000_WUS_EX   0x00000004 /* Directed Exact Received */
+#define E1000_WUS_MC   0x00000008 /* Directed Multicast Received */
+#define E1000_WUS_BC   0x00000010 /* Broadcast Received */
+#define E1000_WUS_ARP  0x00000020 /* ARP Request Packet Received */
+#define E1000_WUS_IPV4 0x00000040 /* Directed IPv4 Packet Wakeup Received */
+#define E1000_WUS_IPV6 0x00000080 /* Directed IPv6 Packet Wakeup Received */
+#define E1000_WUS_FLX0 0x00010000 /* Flexible Filter 0 Match */
+#define E1000_WUS_FLX1 0x00020000 /* Flexible Filter 1 Match */
+#define E1000_WUS_FLX2 0x00040000 /* Flexible Filter 2 Match */
+#define E1000_WUS_FLX3 0x00080000 /* Flexible Filter 3 Match */
+#define E1000_WUS_FLX_FILTERS 0x000F0000 /* Mask for the 4 flexible filters */
+
+/* Management Control */
+#define E1000_MANC_SMBUS_EN      0x00000001 /* SMBus Enabled - RO */
+#define E1000_MANC_ASF_EN        0x00000002 /* ASF Enabled - RO */
+#define E1000_MANC_R_ON_FORCE    0x00000004 /* Reset on Force TCO - RO */
+#define E1000_MANC_RMCP_EN       0x00000100 /* Enable RCMP 026Fh Filtering */
+#define E1000_MANC_0298_EN       0x00000200 /* Enable RCMP 0298h Filtering */
+#define E1000_MANC_IPV4_EN       0x00000400 /* Enable IPv4 */
+#define E1000_MANC_IPV6_EN       0x00000800 /* Enable IPv6 */
+#define E1000_MANC_SNAP_EN       0x00001000 /* Accept LLC/SNAP */
+#define E1000_MANC_ARP_EN        0x00002000 /* Enable ARP Request Filtering */
+#define E1000_MANC_NEIGHBOR_EN   0x00004000 /* Enable Neighbor Discovery
+                                             * Filtering */
+#define E1000_MANC_ARP_RES_EN    0x00008000 /* Enable ARP response Filtering */
+#define E1000_MANC_TCO_RESET     0x00010000 /* TCO Reset Occurred */
+#define E1000_MANC_RCV_TCO_EN    0x00020000 /* Receive TCO Packets Enabled */
+#define E1000_MANC_REPORT_STATUS 0x00040000 /* Status Reporting Enabled */
+#define E1000_MANC_BLK_PHY_RST_ON_IDE   0x00040000 /* Block phy resets */
+#define E1000_MANC_EN_MAC_ADDR_FILTER   0x00100000 /* Enable MAC address
+                                                    * filtering */
+#define E1000_MANC_EN_MNG2HOST   0x00200000 /* Enable MNG packets to host
+                                             * memory */
+#define E1000_MANC_EN_IP_ADDR_FILTER    0x00400000 /* Enable IP address
+                                                    * filtering */
+#define E1000_MANC_EN_XSUM_FILTER   0x00800000 /* Enable checksum filtering */
+#define E1000_MANC_BR_EN            0x01000000 /* Enable broadcast filtering */
+#define E1000_MANC_SMB_REQ       0x01000000 /* SMBus Request */
+#define E1000_MANC_SMB_GNT       0x02000000 /* SMBus Grant */
+#define E1000_MANC_SMB_CLK_IN    0x04000000 /* SMBus Clock In */
+#define E1000_MANC_SMB_DATA_IN   0x08000000 /* SMBus Data In */
+#define E1000_MANC_SMB_DATA_OUT  0x10000000 /* SMBus Data Out */
+#define E1000_MANC_SMB_CLK_OUT   0x20000000 /* SMBus Clock Out */
+
+#define E1000_MANC_SMB_DATA_OUT_SHIFT  28 /* SMBus Data Out Shift */
+#define E1000_MANC_SMB_CLK_OUT_SHIFT   29 /* SMBus Clock Out Shift */
+
+/* SW Semaphore Register */
+#define E1000_SWSM_SMBI         0x00000001 /* Driver Semaphore bit */
+#define E1000_SWSM_SWESMBI      0x00000002 /* FW Semaphore bit */
+#define E1000_SWSM_WMNG         0x00000004 /* Wake MNG Clock */
+#define E1000_SWSM_DRV_LOAD     0x00000008 /* Driver Loaded Bit */
+
+/* FW Semaphore Register */
+#define E1000_FWSM_MODE_MASK    0x0000000E /* FW mode */
+#define E1000_FWSM_MODE_SHIFT            1
+#define E1000_FWSM_FW_VALID     0x00008000 /* FW established a valid mode */
+
+/* FFLT Debug Register */
+#define E1000_FFLT_DBG_INVC     0x00100000 /* Invalid /C/ code handling */
+
+typedef enum {
+    em_mng_mode_none     = 0,
+    em_mng_mode_asf,
+    em_mng_mode_pt,
+    em_mng_mode_ipmi,
+    em_mng_mode_host_interface_only
+} em_mng_mode;
+
+/* Host Inteface Control Register */
+#define E1000_HICR_EN           0x00000001  /* Enable Bit - RO */
+#define E1000_HICR_C            0x00000002  /* Driver sets this bit when done
+                                             * to put command in RAM */
+#define E1000_HICR_SV           0x00000004  /* Status Validity */
+#define E1000_HICR_FWR          0x00000080  /* FW reset. Set by the Host */
+
+/* Host Interface Command Interface - Address range 0x8800-0x8EFF */
+#define E1000_HI_MAX_DATA_LENGTH         252 /* Host Interface data length */
+#define E1000_HI_MAX_BLOCK_BYTE_LENGTH  1792 /* Number of bytes in range */
+#define E1000_HI_MAX_BLOCK_DWORD_LENGTH  448 /* Number of dwords in range */
+#define E1000_HI_COMMAND_TIMEOUT         500 /* Time in ms to process HI command */
+
+struct em_host_command_header {
+    uint8_t command_id;
+    uint8_t command_length;
+    uint8_t command_options;   /* I/F bits for command, status for return */
+    uint8_t checksum;
+};
+struct em_host_command_info {
+    struct em_host_command_header command_header;  /* Command Head/Command Result Head has 4 bytes */
+    uint8_t command_data[E1000_HI_MAX_DATA_LENGTH];   /* Command data can length 0..252 */
+};
+
+/* Host SMB register #0 */
+#define E1000_HSMC0R_CLKIN      0x00000001  /* SMB Clock in */
+#define E1000_HSMC0R_DATAIN     0x00000002  /* SMB Data in */
+#define E1000_HSMC0R_DATAOUT    0x00000004  /* SMB Data out */
+#define E1000_HSMC0R_CLKOUT     0x00000008  /* SMB Clock out */
+
+/* Host SMB register #1 */
+#define E1000_HSMC1R_CLKIN      E1000_HSMC0R_CLKIN
+#define E1000_HSMC1R_DATAIN     E1000_HSMC0R_DATAIN
+#define E1000_HSMC1R_DATAOUT    E1000_HSMC0R_DATAOUT
+#define E1000_HSMC1R_CLKOUT     E1000_HSMC0R_CLKOUT
+
+/* FW Status Register */
+#define E1000_FWSTS_FWS_MASK    0x000000FF  /* FW Status */
+
+/* Wake Up Packet Length */
+#define E1000_WUPL_LENGTH_MASK 0x0FFF   /* Only the lower 12 bits are valid */
+
+#define E1000_MDALIGN          4096
+
+#define E1000_GCR_BEM32                 0x00400000
+/* Function Active and Power State to MNG */
+#define E1000_FACTPS_FUNC0_POWER_STATE_MASK         0x00000003
+#define E1000_FACTPS_LAN0_VALID                     0x00000004
+#define E1000_FACTPS_FUNC0_AUX_EN                   0x00000008
+#define E1000_FACTPS_FUNC1_POWER_STATE_MASK         0x000000C0
+#define E1000_FACTPS_FUNC1_POWER_STATE_SHIFT        6
+#define E1000_FACTPS_LAN1_VALID                     0x00000100
+#define E1000_FACTPS_FUNC1_AUX_EN                   0x00000200
+#define E1000_FACTPS_FUNC2_POWER_STATE_MASK         0x00003000
+#define E1000_FACTPS_FUNC2_POWER_STATE_SHIFT        12
+#define E1000_FACTPS_IDE_ENABLE                     0x00004000
+#define E1000_FACTPS_FUNC2_AUX_EN                   0x00008000
+#define E1000_FACTPS_FUNC3_POWER_STATE_MASK         0x000C0000
+#define E1000_FACTPS_FUNC3_POWER_STATE_SHIFT        18
+#define E1000_FACTPS_SP_ENABLE                      0x00100000
+#define E1000_FACTPS_FUNC3_AUX_EN                   0x00200000
+#define E1000_FACTPS_FUNC4_POWER_STATE_MASK         0x03000000
+#define E1000_FACTPS_FUNC4_POWER_STATE_SHIFT        24
+#define E1000_FACTPS_IPMI_ENABLE                    0x04000000
+#define E1000_FACTPS_FUNC4_AUX_EN                   0x08000000
+#define E1000_FACTPS_MNGCG                          0x20000000
+#define E1000_FACTPS_LAN_FUNC_SEL                   0x40000000
+#define E1000_FACTPS_PM_STATE_CHANGED               0x80000000
+
+/* EEPROM Commands - Microwire */
+#define EEPROM_READ_OPCODE_MICROWIRE  0x6  /* EEPROM read opcode */
+#define EEPROM_WRITE_OPCODE_MICROWIRE 0x5  /* EEPROM write opcode */
+#define EEPROM_ERASE_OPCODE_MICROWIRE 0x7  /* EEPROM erase opcode */
+#define EEPROM_EWEN_OPCODE_MICROWIRE  0x13 /* EEPROM erase/write enable */
+#define EEPROM_EWDS_OPCODE_MICROWIRE  0x10 /* EEPROM erast/write disable */
+
+/* EEPROM Commands - SPI */
+#define EEPROM_MAX_RETRY_SPI    5000 /* Max wait of 5ms, for RDY signal */
+#define EEPROM_READ_OPCODE_SPI      0x03  /* EEPROM read opcode */
+#define EEPROM_WRITE_OPCODE_SPI     0x02  /* EEPROM write opcode */
+#define EEPROM_A8_OPCODE_SPI        0x08  /* opcode bit-3 = address bit-8 */
+#define EEPROM_WREN_OPCODE_SPI      0x06  /* EEPROM set Write Enable latch */
+#define EEPROM_WRDI_OPCODE_SPI      0x04  /* EEPROM reset Write Enable latch */
+#define EEPROM_RDSR_OPCODE_SPI      0x05  /* EEPROM read Status register */
+#define EEPROM_WRSR_OPCODE_SPI      0x01  /* EEPROM write Status register */
+#define EEPROM_ERASE4K_OPCODE_SPI   0x20  /* EEPROM ERASE 4KB */
+#define EEPROM_ERASE64K_OPCODE_SPI  0xD8  /* EEPROM ERASE 64KB */
+#define EEPROM_ERASE256_OPCODE_SPI  0xDB  /* EEPROM ERASE 256B */
+
+/* EEPROM Size definitions */
+#define EEPROM_WORD_SIZE_SHIFT  6
+#define EEPROM_SIZE_SHIFT       10
+#define EEPROM_SIZE_MASK        0x1C00
+
+/* EEPROM Word Offsets */
+#define EEPROM_COMPAT                 0x0003
+#define EEPROM_ID_LED_SETTINGS        0x0004
+#define EEPROM_SERDES_AMPLITUDE       0x0006 /* For SERDES output amplitude adjustment. */
+#define EEPROM_PHY_CLASS_WORD         0x0007
+#define EEPROM_INIT_CONTROL1_REG      0x000A
+#define EEPROM_INIT_CONTROL2_REG      0x000F
+#define EEPROM_INIT_CONTROL3_PORT_B   0x0014
+#define EEPROM_INIT_CONTROL3_PORT_A   0x0024
+#define EEPROM_CFG                    0x0012
+#define EEPROM_FLASH_VERSION          0x0032
+#define EEPROM_CHECKSUM_REG           0x003F
+
+/* Word definitions for ID LED Settings */
+#define ID_LED_RESERVED_0000 0x0000
+#define ID_LED_RESERVED_FFFF 0xFFFF
+#define ID_LED_DEFAULT       ((ID_LED_OFF1_ON2 << 12) | \
+                              (ID_LED_OFF1_OFF2 << 8) | \
+                              (ID_LED_DEF1_DEF2 << 4) | \
+                              (ID_LED_DEF1_DEF2))
+#define ID_LED_DEF1_DEF2     0x1
+#define ID_LED_DEF1_ON2      0x2
+#define ID_LED_DEF1_OFF2     0x3
+#define ID_LED_ON1_DEF2      0x4
+#define ID_LED_ON1_ON2       0x5
+#define ID_LED_ON1_OFF2      0x6
+#define ID_LED_OFF1_DEF2     0x7
+#define ID_LED_OFF1_ON2      0x8
+#define ID_LED_OFF1_OFF2     0x9
+
+#define IGP_ACTIVITY_LED_MASK   0xFFFFF0FF
+#define IGP_ACTIVITY_LED_ENABLE 0x0300
+#define IGP_LED3_MODE           0x07000000
+
+
+/* Mask bits for SERDES amplitude adjustment in Word 6 of the EEPROM */
+#define EEPROM_SERDES_AMPLITUDE_MASK  0x000F
+
+/* Mask bit for PHY class in Word 7 of the EEPROM */
+#define EEPROM_PHY_CLASS_A   0x8000
+
+/* Mask bits for fields in Word 0x0a of the EEPROM */
+#define EEPROM_WORD0A_ILOS   0x0010
+#define EEPROM_WORD0A_SWDPIO 0x01E0
+#define EEPROM_WORD0A_LRST   0x0200
+#define EEPROM_WORD0A_FD     0x0400
+#define EEPROM_WORD0A_66MHZ  0x0800
+
+/* Mask bits for fields in Word 0x0f of the EEPROM */
+#define EEPROM_WORD0F_PAUSE_MASK 0x3000
+#define EEPROM_WORD0F_PAUSE      0x1000
+#define EEPROM_WORD0F_ASM_DIR    0x2000
+#define EEPROM_WORD0F_ANE        0x0800
+#define EEPROM_WORD0F_SWPDIO_EXT 0x00F0
+
+/* For checksumming, the sum of all words in the EEPROM should equal 0xBABA. */
+#define EEPROM_SUM 0xBABA
+
+/* EEPROM Map defines (WORD OFFSETS)*/
+#define EEPROM_NODE_ADDRESS_BYTE_0 0
+#define EEPROM_PBA_BYTE_1          8
+
+#define EEPROM_RESERVED_WORD          0xFFFF
+
+/* EEPROM Map Sizes (Byte Counts) */
+#define PBA_SIZE 4
+
+/* Collision related configuration parameters */
+#define E1000_COLLISION_THRESHOLD       15
+#define E1000_CT_SHIFT                  4
+#define E1000_COLLISION_DISTANCE        64
+#define E1000_FDX_COLLISION_DISTANCE    E1000_COLLISION_DISTANCE
+#define E1000_HDX_COLLISION_DISTANCE    E1000_COLLISION_DISTANCE
+#define E1000_COLD_SHIFT                12
+
+/* Number of Transmit and Receive Descriptors must be a multiple of 8 */
+#define REQ_TX_DESCRIPTOR_MULTIPLE  8
+#define REQ_RX_DESCRIPTOR_MULTIPLE  8
+
+/* Default values for the transmit IPG register */
+#define DEFAULT_82542_TIPG_IPGT        10
+#define DEFAULT_82543_TIPG_IPGT_FIBER  9
+#define DEFAULT_82543_TIPG_IPGT_COPPER 8
+
+#define E1000_TIPG_IPGT_MASK  0x000003FF
+#define E1000_TIPG_IPGR1_MASK 0x000FFC00
+#define E1000_TIPG_IPGR2_MASK 0x3FF00000
+
+#define DEFAULT_82542_TIPG_IPGR1 2
+#define DEFAULT_82543_TIPG_IPGR1 8
+#define E1000_TIPG_IPGR1_SHIFT  10
+
+#define DEFAULT_82542_TIPG_IPGR2 10
+#define DEFAULT_82543_TIPG_IPGR2 6
+#define E1000_TIPG_IPGR2_SHIFT  20
+
+#define E1000_TXDMAC_DPP 0x00000001
+
+/* Adaptive IFS defines */
+#define TX_THRESHOLD_START     8
+#define TX_THRESHOLD_INCREMENT 10
+#define TX_THRESHOLD_DECREMENT 1
+#define TX_THRESHOLD_STOP      190
+#define TX_THRESHOLD_DISABLE   0
+#define TX_THRESHOLD_TIMER_MS  10000
+#define MIN_NUM_XMITS          1000
+#define IFS_MAX                80
+#define IFS_STEP               10
+#define IFS_MIN                40
+#define IFS_RATIO              4
+
+/* Extended Configuration Control and Size */
+#define E1000_EXTCNF_CTRL_PCIE_WRITE_ENABLE 0x00000001
+#define E1000_EXTCNF_CTRL_PHY_WRITE_ENABLE  0x00000002
+#define E1000_EXTCNF_CTRL_D_UD_ENABLE       0x00000004
+#define E1000_EXTCNF_CTRL_D_UD_LATENCY      0x00000008
+#define E1000_EXTCNF_CTRL_D_UD_OWNER        0x00000010
+#define E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP 0x00000020
+#define E1000_EXTCNF_CTRL_MDIO_HW_OWNERSHIP 0x00000040
+#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER   0x1FFF0000
+
+#define E1000_EXTCNF_SIZE_EXT_PHY_LENGTH    0x000000FF
+#define E1000_EXTCNF_SIZE_EXT_DOCK_LENGTH   0x0000FF00
+#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH   0x00FF0000
+
+/* PBA constants */
+#define E1000_PBA_12K 0x000C    /* 12KB, default Rx allocation */
+#define E1000_PBA_16K 0x0010    /* 16KB, default TX allocation */
+#define E1000_PBA_22K 0x0016
+#define E1000_PBA_24K 0x0018
+#define E1000_PBA_30K 0x001E
+#define E1000_PBA_40K 0x0028
+#define E1000_PBA_48K 0x0030    /* 48KB, default RX allocation */
+
+/* Flow Control Constants */
+#define FLOW_CONTROL_ADDRESS_LOW  0x00C28001
+#define FLOW_CONTROL_ADDRESS_HIGH 0x00000100
+#define FLOW_CONTROL_TYPE         0x8808
+
+/* The historical defaults for the flow control values are given below. */
+#define FC_DEFAULT_HI_THRESH        (0x8000)    /* 32KB */
+#define FC_DEFAULT_LO_THRESH        (0x4000)    /* 16KB */
+#define FC_DEFAULT_TX_TIMER         (0x100)     /* ~130 us */
+
+/* PCIX Config space */
+#define PCIX_COMMAND_REGISTER    0xE6
+#define PCIX_STATUS_REGISTER_LO  0xE8
+#define PCIX_STATUS_REGISTER_HI  0xEA
+
+#define PCIX_COMMAND_MMRBC_MASK      0x000C
+#define PCIX_COMMAND_MMRBC_SHIFT     0x2
+#define PCIX_STATUS_HI_MMRBC_MASK    0x0060
+#define PCIX_STATUS_HI_MMRBC_SHIFT   0x5
+#define PCIX_STATUS_HI_MMRBC_4K      0x3
+#define PCIX_STATUS_HI_MMRBC_2K      0x2
+
+
+/* Number of bits required to shift right the "pause" bits from the
+ * EEPROM (bits 13:12) to the "pause" (bits 8:7) field in the TXCW register.
+ */
+#define PAUSE_SHIFT 5
+
+/* Number of bits required to shift left the "SWDPIO" bits from the
+ * EEPROM (bits 8:5) to the "SWDPIO" (bits 25:22) field in the CTRL register.
+ */
+#define SWDPIO_SHIFT 17
+
+/* Number of bits required to shift left the "SWDPIO_EXT" bits from the
+ * EEPROM word F (bits 7:4) to the bits 11:8 of The Extended CTRL register.
+ */
+#define SWDPIO__EXT_SHIFT 4
+
+/* Number of bits required to shift left the "ILOS" bit from the EEPROM
+ * (bit 4) to the "ILOS" (bit 7) field in the CTRL register.
+ */
+#define ILOS_SHIFT  3
+
+
+#define RECEIVE_BUFFER_ALIGN_SIZE  (256)
+
+/* Number of milliseconds we wait for auto-negotiation to complete */
+#define LINK_UP_TIMEOUT             500
+
+/* Number of 100 microseconds we wait for PCI Express master disable */
+#define MASTER_DISABLE_TIMEOUT      800
+/* Number of milliseconds we wait for Eeprom auto read bit done after MAC reset */
+#define AUTO_READ_DONE_TIMEOUT      10
+/* Number of milliseconds we wait for PHY configuration done after MAC reset */
+#define PHY_CFG_TIMEOUT             40
+
+#define E1000_TX_BUFFER_SIZE ((uint32_t)1514)
+
+/* The carrier extension symbol, as received by the NIC. */
+#define CARRIER_EXTENSION   0x0F
+
+/* TBI_ACCEPT macro definition:
+ *
+ * This macro requires:
+ *      adapter = a pointer to struct em_hw
+ *      status = the 8 bit status field of the RX descriptor with EOP set
+ *      error = the 8 bit error field of the RX descriptor with EOP set
+ *      length = the sum of all the length fields of the RX descriptors that
+ *               make up the current frame
+ *      last_byte = the last byte of the frame DMAed by the hardware
+ *      max_frame_length = the maximum frame length we want to accept.
+ *      min_frame_length = the minimum frame length we want to accept.
+ *
+ * This macro is a conditional that should be used in the interrupt
+ * handler's Rx processing routine when RxErrors have been detected.
+ *
+ * Typical use:
+ *  ...
+ *  if (TBI_ACCEPT) {
+ *      accept_frame = TRUE;
+ *      em_tbi_adjust_stats(adapter, MacAddress);
+ *      frame_length--;
+ *  } else {
+ *      accept_frame = FALSE;
+ *  }
+ *  ...
+ */
+
+#define TBI_ACCEPT(adapter, status, errors, length, last_byte) \
+    ((adapter)->tbi_compatibility_on && \
+     (((errors) & E1000_RXD_ERR_FRAME_ERR_MASK) == E1000_RXD_ERR_CE) && \
+     ((last_byte) == CARRIER_EXTENSION) && \
+     (((status) & E1000_RXD_STAT_VP) ? \
+          (((length) > ((adapter)->min_frame_size - VLAN_TAG_SIZE)) && \
+           ((length) <= ((adapter)->max_frame_size + 1))) : \
+          (((length) > (adapter)->min_frame_size) && \
+           ((length) <= ((adapter)->max_frame_size + VLAN_TAG_SIZE + 1)))))
+
+
+/* Structures, enums, and macros for the PHY */
+
+/* Bit definitions for the Management Data IO (MDIO) and Management Data
+ * Clock (MDC) pins in the Device Control Register.
+ */
+#define E1000_CTRL_PHY_RESET_DIR  E1000_CTRL_SWDPIO0
+#define E1000_CTRL_PHY_RESET      E1000_CTRL_SWDPIN0
+#define E1000_CTRL_MDIO_DIR       E1000_CTRL_SWDPIO2
+#define E1000_CTRL_MDIO           E1000_CTRL_SWDPIN2
+#define E1000_CTRL_MDC_DIR        E1000_CTRL_SWDPIO3
+#define E1000_CTRL_MDC            E1000_CTRL_SWDPIN3
+#define E1000_CTRL_PHY_RESET_DIR4 E1000_CTRL_EXT_SDP4_DIR
+#define E1000_CTRL_PHY_RESET4     E1000_CTRL_EXT_SDP4_DATA
+
+/* PHY 1000 MII Register/Bit Definitions */
+/* PHY Registers defined by IEEE */
+#define PHY_CTRL         0x00 /* Control Register */
+#define PHY_STATUS       0x01 /* Status Regiser */
+#define PHY_ID1          0x02 /* Phy Id Reg (word 1) */
+#define PHY_ID2          0x03 /* Phy Id Reg (word 2) */
+#define PHY_AUTONEG_ADV  0x04 /* Autoneg Advertisement */
+#define PHY_LP_ABILITY   0x05 /* Link Partner Ability (Base Page) */
+#define PHY_AUTONEG_EXP  0x06 /* Autoneg Expansion Reg */
+#define PHY_NEXT_PAGE_TX 0x07 /* Next Page TX */
+#define PHY_LP_NEXT_PAGE 0x08 /* Link Partner Next Page */
+#define PHY_1000T_CTRL   0x09 /* 1000Base-T Control Reg */
+#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */
+#define PHY_EXT_STATUS   0x0F /* Extended Status Reg */
+
+/* M88E1000 Specific Registers */
+#define M88E1000_PHY_SPEC_CTRL     0x10  /* PHY Specific Control Register */
+#define M88E1000_PHY_SPEC_STATUS   0x11  /* PHY Specific Status Register */
+#define M88E1000_INT_ENABLE        0x12  /* Interrupt Enable Register */
+#define M88E1000_INT_STATUS        0x13  /* Interrupt Status Register */
+#define M88E1000_EXT_PHY_SPEC_CTRL 0x14  /* Extended PHY Specific Control */
+#define M88E1000_RX_ERR_CNTR       0x15  /* Receive Error Counter */
+
+#define M88E1000_PHY_EXT_CTRL      0x1A  /* PHY extend control register */
+#define M88E1000_PHY_PAGE_SELECT   0x1D  /* Reg 29 for page number setting */
+#define M88E1000_PHY_GEN_CONTROL   0x1E  /* Its meaning depends on reg 29 */
+#define M88E1000_PHY_VCO_REG_BIT8  0x100 /* Bits 8 & 11 are adjusted for */
+#define M88E1000_PHY_VCO_REG_BIT11 0x800    /* improved BER performance */
+
+#define IGP01E1000_IEEE_REGS_PAGE  0x0000
+#define IGP01E1000_IEEE_RESTART_AUTONEG 0x3300
+#define IGP01E1000_IEEE_FORCE_GIGA      0x0140
+
+/* IGP01E1000 Specific Registers */
+#define IGP01E1000_PHY_PORT_CONFIG 0x10 /* PHY Specific Port Config Register */
+#define IGP01E1000_PHY_PORT_STATUS 0x11 /* PHY Specific Status Register */
+#define IGP01E1000_PHY_PORT_CTRL   0x12 /* PHY Specific Control Register */
+#define IGP01E1000_PHY_LINK_HEALTH 0x13 /* PHY Link Health Register */
+#define IGP01E1000_GMII_FIFO       0x14 /* GMII FIFO Register */
+#define IGP01E1000_PHY_CHANNEL_QUALITY 0x15 /* PHY Channel Quality Register */
+#define IGP02E1000_PHY_POWER_MGMT      0x19
+#define IGP01E1000_PHY_PAGE_SELECT     0x1F /* PHY Page Select Core Register */
+
+/* IGP01E1000 AGC Registers - stores the cable length values*/
+#define IGP01E1000_PHY_AGC_A        0x1172
+#define IGP01E1000_PHY_AGC_B        0x1272
+#define IGP01E1000_PHY_AGC_C        0x1472
+#define IGP01E1000_PHY_AGC_D        0x1872
+
+/* IGP02E1000 AGC Registers for cable length values */
+#define IGP02E1000_PHY_AGC_A        0x11B1
+#define IGP02E1000_PHY_AGC_B        0x12B1
+#define IGP02E1000_PHY_AGC_C        0x14B1
+#define IGP02E1000_PHY_AGC_D        0x18B1
+
+/* IGP01E1000 DSP Reset Register */
+#define IGP01E1000_PHY_DSP_RESET   0x1F33
+#define IGP01E1000_PHY_DSP_SET     0x1F71
+#define IGP01E1000_PHY_DSP_FFE     0x1F35
+
+#define IGP01E1000_PHY_CHANNEL_NUM    4
+#define IGP02E1000_PHY_CHANNEL_NUM    4
+
+#define IGP01E1000_PHY_AGC_PARAM_A    0x1171
+#define IGP01E1000_PHY_AGC_PARAM_B    0x1271
+#define IGP01E1000_PHY_AGC_PARAM_C    0x1471
+#define IGP01E1000_PHY_AGC_PARAM_D    0x1871
+
+#define IGP01E1000_PHY_EDAC_MU_INDEX        0xC000
+#define IGP01E1000_PHY_EDAC_SIGN_EXT_9_BITS 0x8000
+
+#define IGP01E1000_PHY_ANALOG_TX_STATE      0x2890
+#define IGP01E1000_PHY_ANALOG_CLASS_A       0x2000
+#define IGP01E1000_PHY_FORCE_ANALOG_ENABLE  0x0004
+#define IGP01E1000_PHY_DSP_FFE_CM_CP        0x0069
+
+#define IGP01E1000_PHY_DSP_FFE_DEFAULT      0x002A
+/* IGP01E1000 PCS Initialization register - stores the polarity status when
+ * speed = 1000 Mbps. */
+#define IGP01E1000_PHY_PCS_INIT_REG  0x00B4
+#define IGP01E1000_PHY_PCS_CTRL_REG  0x00B5
+
+#define IGP01E1000_ANALOG_REGS_PAGE  0x20C0
+
+#define MAX_PHY_REG_ADDRESS 0x1F        /* 5 bit address bus (0-0x1F) */
+#define MAX_PHY_MULTI_PAGE_REG  0xF     /*Registers that are equal on all pages*/
+/* PHY Control Register */
+#define MII_CR_SPEED_SELECT_MSB 0x0040  /* bits 6,13: 10=1000, 01=100, 00=10 */
+#define MII_CR_COLL_TEST_ENABLE 0x0080  /* Collision test enable */
+#define MII_CR_FULL_DUPLEX      0x0100  /* FDX =1, half duplex =0 */
+#define MII_CR_RESTART_AUTO_NEG 0x0200  /* Restart auto negotiation */
+#define MII_CR_ISOLATE          0x0400  /* Isolate PHY from MII */
+#define MII_CR_POWER_DOWN       0x0800  /* Power down */
+#define MII_CR_AUTO_NEG_EN      0x1000  /* Auto Neg Enable */
+#define MII_CR_SPEED_SELECT_LSB 0x2000  /* bits 6,13: 10=1000, 01=100, 00=10 */
+#define MII_CR_LOOPBACK         0x4000  /* 0 = normal, 1 = loopback */
+#define MII_CR_RESET            0x8000  /* 0 = normal, 1 = PHY reset */
+
+/* PHY Status Register */
+#define MII_SR_EXTENDED_CAPS     0x0001 /* Extended register capabilities */
+#define MII_SR_JABBER_DETECT     0x0002 /* Jabber Detected */
+#define MII_SR_LINK_STATUS       0x0004 /* Link Status 1 = link */
+#define MII_SR_AUTONEG_CAPS      0x0008 /* Auto Neg Capable */
+#define MII_SR_REMOTE_FAULT      0x0010 /* Remote Fault Detect */
+#define MII_SR_AUTONEG_COMPLETE  0x0020 /* Auto Neg Complete */
+#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */
+#define MII_SR_EXTENDED_STATUS   0x0100 /* Ext. status info in Reg 0x0F */
+#define MII_SR_100T2_HD_CAPS     0x0200 /* 100T2 Half Duplex Capable */
+#define MII_SR_100T2_FD_CAPS     0x0400 /* 100T2 Full Duplex Capable */
+#define MII_SR_10T_HD_CAPS       0x0800 /* 10T   Half Duplex Capable */
+#define MII_SR_10T_FD_CAPS       0x1000 /* 10T   Full Duplex Capable */
+#define MII_SR_100X_HD_CAPS      0x2000 /* 100X  Half Duplex Capable */
+#define MII_SR_100X_FD_CAPS      0x4000 /* 100X  Full Duplex Capable */
+#define MII_SR_100T4_CAPS        0x8000 /* 100T4 Capable */
+
+/* Autoneg Advertisement Register */
+#define NWAY_AR_SELECTOR_FIELD 0x0001   /* indicates IEEE 802.3 CSMA/CD */
+#define NWAY_AR_10T_HD_CAPS    0x0020   /* 10T   Half Duplex Capable */
+#define NWAY_AR_10T_FD_CAPS    0x0040   /* 10T   Full Duplex Capable */
+#define NWAY_AR_100TX_HD_CAPS  0x0080   /* 100TX Half Duplex Capable */
+#define NWAY_AR_100TX_FD_CAPS  0x0100   /* 100TX Full Duplex Capable */
+#define NWAY_AR_100T4_CAPS     0x0200   /* 100T4 Capable */
+#define NWAY_AR_PAUSE          0x0400   /* Pause operation desired */
+#define NWAY_AR_ASM_DIR        0x0800   /* Asymmetric Pause Direction bit */
+#define NWAY_AR_REMOTE_FAULT   0x2000   /* Remote Fault detected */
+#define NWAY_AR_NEXT_PAGE      0x8000   /* Next Page ability supported */
+
+/* Link Partner Ability Register (Base Page) */
+#define NWAY_LPAR_SELECTOR_FIELD 0x0000 /* LP protocol selector field */
+#define NWAY_LPAR_10T_HD_CAPS    0x0020 /* LP is 10T   Half Duplex Capable */
+#define NWAY_LPAR_10T_FD_CAPS    0x0040 /* LP is 10T   Full Duplex Capable */
+#define NWAY_LPAR_100TX_HD_CAPS  0x0080 /* LP is 100TX Half Duplex Capable */
+#define NWAY_LPAR_100TX_FD_CAPS  0x0100 /* LP is 100TX Full Duplex Capable */
+#define NWAY_LPAR_100T4_CAPS     0x0200 /* LP is 100T4 Capable */
+#define NWAY_LPAR_PAUSE          0x0400 /* LP Pause operation desired */
+#define NWAY_LPAR_ASM_DIR        0x0800 /* LP Asymmetric Pause Direction bit */
+#define NWAY_LPAR_REMOTE_FAULT   0x2000 /* LP has detected Remote Fault */
+#define NWAY_LPAR_ACKNOWLEDGE    0x4000 /* LP has rx'd link code word */
+#define NWAY_LPAR_NEXT_PAGE      0x8000 /* Next Page ability supported */
+
+/* Autoneg Expansion Register */
+#define NWAY_ER_LP_NWAY_CAPS      0x0001 /* LP has Auto Neg Capability */
+#define NWAY_ER_PAGE_RXD          0x0002 /* LP is 10T   Half Duplex Capable */
+#define NWAY_ER_NEXT_PAGE_CAPS    0x0004 /* LP is 10T   Full Duplex Capable */
+#define NWAY_ER_LP_NEXT_PAGE_CAPS 0x0008 /* LP is 100TX Half Duplex Capable */
+#define NWAY_ER_PAR_DETECT_FAULT  0x0010 /* LP is 100TX Full Duplex Capable */
+
+/* Next Page TX Register */
+#define NPTX_MSG_CODE_FIELD 0x0001 /* NP msg code or unformatted data */
+#define NPTX_TOGGLE         0x0800 /* Toggles between exchanges
+                                    * of different NP
+                                    */
+#define NPTX_ACKNOWLDGE2    0x1000 /* 1 = will comply with msg
+                                    * 0 = cannot comply with msg
+                                    */
+#define NPTX_MSG_PAGE       0x2000 /* formatted(1)/unformatted(0) pg */
+#define NPTX_NEXT_PAGE      0x8000 /* 1 = addition NP will follow
+                                    * 0 = sending last NP
+                                    */
+
+/* Link Partner Next Page Register */
+#define LP_RNPR_MSG_CODE_FIELD 0x0001 /* NP msg code or unformatted data */
+#define LP_RNPR_TOGGLE         0x0800 /* Toggles between exchanges
+                                       * of different NP
+                                       */
+#define LP_RNPR_ACKNOWLDGE2    0x1000 /* 1 = will comply with msg
+                                       * 0 = cannot comply with msg
+                                       */
+#define LP_RNPR_MSG_PAGE       0x2000  /* formatted(1)/unformatted(0) pg */
+#define LP_RNPR_ACKNOWLDGE     0x4000  /* 1 = ACK / 0 = NO ACK */
+#define LP_RNPR_NEXT_PAGE      0x8000  /* 1 = addition NP will follow
+                                        * 0 = sending last NP
+                                        */
+
+/* 1000BASE-T Control Register */
+#define CR_1000T_ASYM_PAUSE      0x0080 /* Advertise asymmetric pause bit */
+#define CR_1000T_HD_CAPS         0x0100 /* Advertise 1000T HD capability */
+#define CR_1000T_FD_CAPS         0x0200 /* Advertise 1000T FD capability  */
+#define CR_1000T_REPEATER_DTE    0x0400 /* 1=Repeater/switch device port */
+                                        /* 0=DTE device */
+#define CR_1000T_MS_VALUE        0x0800 /* 1=Configure PHY as Master */
+                                        /* 0=Configure PHY as Slave */
+#define CR_1000T_MS_ENABLE       0x1000 /* 1=Master/Slave manual config value */
+                                        /* 0=Automatic Master/Slave config */
+#define CR_1000T_TEST_MODE_NORMAL 0x0000 /* Normal Operation */
+#define CR_1000T_TEST_MODE_1     0x2000 /* Transmit Waveform test */
+#define CR_1000T_TEST_MODE_2     0x4000 /* Master Transmit Jitter test */
+#define CR_1000T_TEST_MODE_3     0x6000 /* Slave Transmit Jitter test */
+#define CR_1000T_TEST_MODE_4     0x8000 /* Transmitter Distortion test */
+
+/* 1000BASE-T Status Register */
+#define SR_1000T_IDLE_ERROR_CNT   0x00FF /* Num idle errors since last read */
+#define SR_1000T_ASYM_PAUSE_DIR   0x0100 /* LP asymmetric pause direction bit */
+#define SR_1000T_LP_HD_CAPS       0x0400 /* LP is 1000T HD capable */
+#define SR_1000T_LP_FD_CAPS       0x0800 /* LP is 1000T FD capable */
+#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */
+#define SR_1000T_LOCAL_RX_STATUS  0x2000 /* Local receiver OK */
+#define SR_1000T_MS_CONFIG_RES    0x4000 /* 1=Local TX is Master, 0=Slave */
+#define SR_1000T_MS_CONFIG_FAULT  0x8000 /* Master/Slave config fault */
+#define SR_1000T_REMOTE_RX_STATUS_SHIFT          12
+#define SR_1000T_LOCAL_RX_STATUS_SHIFT           13
+#define SR_1000T_PHY_EXCESSIVE_IDLE_ERR_COUNT    5
+#define FFE_IDLE_ERR_COUNT_TIMEOUT_20            20
+#define FFE_IDLE_ERR_COUNT_TIMEOUT_100           100
+
+/* Extended Status Register */
+#define IEEE_ESR_1000T_HD_CAPS 0x1000 /* 1000T HD capable */
+#define IEEE_ESR_1000T_FD_CAPS 0x2000 /* 1000T FD capable */
+#define IEEE_ESR_1000X_HD_CAPS 0x4000 /* 1000X HD capable */
+#define IEEE_ESR_1000X_FD_CAPS 0x8000 /* 1000X FD capable */
+
+#define PHY_TX_POLARITY_MASK   0x0100 /* register 10h bit 8 (polarity bit) */
+#define PHY_TX_NORMAL_POLARITY 0      /* register 10h bit 8 (normal polarity) */
+
+#define AUTO_POLARITY_DISABLE  0x0010 /* register 11h bit 4 */
+                                      /* (0=enable, 1=disable) */
+
+/* M88E1000 PHY Specific Control Register */
+#define M88E1000_PSCR_JABBER_DISABLE    0x0001 /* 1=Jabber Function disabled */
+#define M88E1000_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reversal enabled */
+#define M88E1000_PSCR_SQE_TEST          0x0004 /* 1=SQE Test enabled */
+#define M88E1000_PSCR_CLK125_DISABLE    0x0010 /* 1=CLK125 low,
+                                                * 0=CLK125 toggling
+                                                */
+#define M88E1000_PSCR_MDI_MANUAL_MODE  0x0000  /* MDI Crossover Mode bits 6:5 */
+                                               /* Manual MDI configuration */
+#define M88E1000_PSCR_MDIX_MANUAL_MODE 0x0020  /* Manual MDIX configuration */
+#define M88E1000_PSCR_AUTO_X_1000T     0x0040  /* 1000BASE-T: Auto crossover,
+                                                *  100BASE-TX/10BASE-T:
+                                                *  MDI Mode
+                                                */
+#define M88E1000_PSCR_AUTO_X_MODE      0x0060  /* Auto crossover enabled
+                                                * all speeds.
+                                                */
+#define M88E1000_PSCR_10BT_EXT_DIST_ENABLE 0x0080
+                                        /* 1=Enable Extended 10BASE-T distance
+                                         * (Lower 10BASE-T RX Threshold)
+                                         * 0=Normal 10BASE-T RX Threshold */
+#define M88E1000_PSCR_MII_5BIT_ENABLE      0x0100
+                                        /* 1=5-Bit interface in 100BASE-TX
+                                         * 0=MII interface in 100BASE-TX */
+#define M88E1000_PSCR_SCRAMBLER_DISABLE    0x0200 /* 1=Scrambler disable */
+#define M88E1000_PSCR_FORCE_LINK_GOOD      0x0400 /* 1=Force link good */
+#define M88E1000_PSCR_ASSERT_CRS_ON_TX     0x0800 /* 1=Assert CRS on Transmit */
+
+#define M88E1000_PSCR_POLARITY_REVERSAL_SHIFT    1
+#define M88E1000_PSCR_AUTO_X_MODE_SHIFT          5
+#define M88E1000_PSCR_10BT_EXT_DIST_ENABLE_SHIFT 7
+
+/* M88E1000 PHY Specific Status Register */
+#define M88E1000_PSSR_JABBER             0x0001 /* 1=Jabber */
+#define M88E1000_PSSR_REV_POLARITY       0x0002 /* 1=Polarity reversed */
+#define M88E1000_PSSR_DOWNSHIFT          0x0020 /* 1=Downshifted */
+#define M88E1000_PSSR_MDIX               0x0040 /* 1=MDIX; 0=MDI */
+#define M88E1000_PSSR_CABLE_LENGTH       0x0380 /* 0=<50M;1=50-80M;2=80-110M;
+                                            * 3=110-140M;4=>140M */
+#define M88E1000_PSSR_LINK               0x0400 /* 1=Link up, 0=Link down */
+#define M88E1000_PSSR_SPD_DPLX_RESOLVED  0x0800 /* 1=Speed & Duplex resolved */
+#define M88E1000_PSSR_PAGE_RCVD          0x1000 /* 1=Page received */
+#define M88E1000_PSSR_DPLX               0x2000 /* 1=Duplex 0=Half Duplex */
+#define M88E1000_PSSR_SPEED              0xC000 /* Speed, bits 14:15 */
+#define M88E1000_PSSR_10MBS              0x0000 /* 00=10Mbs */
+#define M88E1000_PSSR_100MBS             0x4000 /* 01=100Mbs */
+#define M88E1000_PSSR_1000MBS            0x8000 /* 10=1000Mbs */
+
+#define M88E1000_PSSR_REV_POLARITY_SHIFT 1
+#define M88E1000_PSSR_DOWNSHIFT_SHIFT    5
+#define M88E1000_PSSR_MDIX_SHIFT         6
+#define M88E1000_PSSR_CABLE_LENGTH_SHIFT 7
+
+/* M88E1000 Extended PHY Specific Control Register */
+#define M88E1000_EPSCR_FIBER_LOOPBACK 0x4000 /* 1=Fiber loopback */
+#define M88E1000_EPSCR_DOWN_NO_IDLE   0x8000 /* 1=Lost lock detect enabled.
+                                              * Will assert lost lock and bring
+                                              * link down if idle not seen
+                                              * within 1ms in 1000BASE-T
+                                              */
+/* Number of times we will attempt to autonegotiate before downshifting if we
+ * are the master */
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK 0x0C00
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_1X   0x0000
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_2X   0x0400
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_3X   0x0800
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_4X   0x0C00
+/* Number of times we will attempt to autonegotiate before downshifting if we
+ * are the slave */
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK  0x0300
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_DIS   0x0000
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X    0x0100
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_2X    0x0200
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_3X    0x0300
+#define M88E1000_EPSCR_TX_CLK_2_5     0x0060 /* 2.5 MHz TX_CLK */
+#define M88E1000_EPSCR_TX_CLK_25      0x0070 /* 25  MHz TX_CLK */
+#define M88E1000_EPSCR_TX_CLK_0       0x0000 /* NO  TX_CLK */
+
+/* IGP01E1000 Specific Port Config Register - R/W */
+#define IGP01E1000_PSCFR_AUTO_MDIX_PAR_DETECT  0x0010
+#define IGP01E1000_PSCFR_PRE_EN                0x0020
+#define IGP01E1000_PSCFR_SMART_SPEED           0x0080
+#define IGP01E1000_PSCFR_DISABLE_TPLOOPBACK    0x0100
+#define IGP01E1000_PSCFR_DISABLE_JABBER        0x0400
+#define IGP01E1000_PSCFR_DISABLE_TRANSMIT      0x2000
+
+/* IGP01E1000 Specific Port Status Register - R/O */
+#define IGP01E1000_PSSR_AUTONEG_FAILED         0x0001 /* RO LH SC */
+#define IGP01E1000_PSSR_POLARITY_REVERSED      0x0002
+#define IGP01E1000_PSSR_CABLE_LENGTH           0x007C
+#define IGP01E1000_PSSR_FULL_DUPLEX            0x0200
+#define IGP01E1000_PSSR_LINK_UP                0x0400
+#define IGP01E1000_PSSR_MDIX                   0x0800
+#define IGP01E1000_PSSR_SPEED_MASK             0xC000 /* speed bits mask */
+#define IGP01E1000_PSSR_SPEED_10MBPS           0x4000
+#define IGP01E1000_PSSR_SPEED_100MBPS          0x8000
+#define IGP01E1000_PSSR_SPEED_1000MBPS         0xC000
+#define IGP01E1000_PSSR_CABLE_LENGTH_SHIFT     0x0002 /* shift right 2 */
+#define IGP01E1000_PSSR_MDIX_SHIFT             0x000B /* shift right 11 */
+
+/* IGP01E1000 Specific Port Control Register - R/W */
+#define IGP01E1000_PSCR_TP_LOOPBACK            0x0010
+#define IGP01E1000_PSCR_CORRECT_NC_SCMBLR      0x0200
+#define IGP01E1000_PSCR_TEN_CRS_SELECT         0x0400
+#define IGP01E1000_PSCR_FLIP_CHIP              0x0800
+#define IGP01E1000_PSCR_AUTO_MDIX              0x1000
+#define IGP01E1000_PSCR_FORCE_MDI_MDIX         0x2000 /* 0-MDI, 1-MDIX */
+
+/* IGP01E1000 Specific Port Link Health Register */
+#define IGP01E1000_PLHR_SS_DOWNGRADE           0x8000
+#define IGP01E1000_PLHR_GIG_SCRAMBLER_ERROR    0x4000
+#define IGP01E1000_PLHR_MASTER_FAULT           0x2000
+#define IGP01E1000_PLHR_MASTER_RESOLUTION      0x1000
+#define IGP01E1000_PLHR_GIG_REM_RCVR_NOK       0x0800 /* LH */
+#define IGP01E1000_PLHR_IDLE_ERROR_CNT_OFLOW   0x0400 /* LH */
+#define IGP01E1000_PLHR_DATA_ERR_1             0x0200 /* LH */
+#define IGP01E1000_PLHR_DATA_ERR_0             0x0100
+#define IGP01E1000_PLHR_AUTONEG_FAULT          0x0040
+#define IGP01E1000_PLHR_AUTONEG_ACTIVE         0x0010
+#define IGP01E1000_PLHR_VALID_CHANNEL_D        0x0008
+#define IGP01E1000_PLHR_VALID_CHANNEL_C        0x0004
+#define IGP01E1000_PLHR_VALID_CHANNEL_B        0x0002
+#define IGP01E1000_PLHR_VALID_CHANNEL_A        0x0001
+
+/* IGP01E1000 Channel Quality Register */
+#define IGP01E1000_MSE_CHANNEL_D        0x000F
+#define IGP01E1000_MSE_CHANNEL_C        0x00F0
+#define IGP01E1000_MSE_CHANNEL_B        0x0F00
+#define IGP01E1000_MSE_CHANNEL_A        0xF000
+
+#define IGP02E1000_PM_SPD                         0x0001  /* Smart Power Down */
+#define IGP02E1000_PM_D3_LPLU                     0x0004  /* Enable LPLU in non-D0a modes */
+#define IGP02E1000_PM_D0_LPLU                     0x0002  /* Enable LPLU in D0a mode */
+
+/* IGP01E1000 DSP reset macros */
+#define DSP_RESET_ENABLE     0x0
+#define DSP_RESET_DISABLE    0x2
+#define E1000_MAX_DSP_RESETS 10
+
+/* IGP01E1000 & IGP02E1000 AGC Registers */
+
+#define IGP01E1000_AGC_LENGTH_SHIFT 7         /* Coarse - 13:11, Fine - 10:7 */
+#define IGP02E1000_AGC_LENGTH_SHIFT 9         /* Coarse - 15:13, Fine - 12:9 */
+
+/* IGP02E1000 AGC Register Length 9-bit mask */
+#define IGP02E1000_AGC_LENGTH_MASK  0x7F
+
+/* 7 bits (3 Coarse + 4 Fine) --> 128 optional values */
+#define IGP01E1000_AGC_LENGTH_TABLE_SIZE 128
+#define IGP02E1000_AGC_LENGTH_TABLE_SIZE 128
+
+/* The precision error of the cable length is +/- 10 meters */
+#define IGP01E1000_AGC_RANGE    10
+#define IGP02E1000_AGC_RANGE    10
+
+/* IGP01E1000 PCS Initialization register */
+/* bits 3:6 in the PCS registers stores the channels polarity */
+#define IGP01E1000_PHY_POLARITY_MASK    0x0078
+
+/* IGP01E1000 GMII FIFO Register */
+#define IGP01E1000_GMII_FLEX_SPD               0x10 /* Enable flexible speed
+                                                     * on Link-Up */
+#define IGP01E1000_GMII_SPD                    0x20 /* Enable SPD */
+
+/* IGP01E1000 Analog Register */
+#define IGP01E1000_ANALOG_SPARE_FUSE_STATUS       0x20D1
+#define IGP01E1000_ANALOG_FUSE_STATUS             0x20D0
+#define IGP01E1000_ANALOG_FUSE_CONTROL            0x20DC
+#define IGP01E1000_ANALOG_FUSE_BYPASS             0x20DE
+
+#define IGP01E1000_ANALOG_FUSE_POLY_MASK            0xF000
+#define IGP01E1000_ANALOG_FUSE_FINE_MASK            0x0F80
+#define IGP01E1000_ANALOG_FUSE_COARSE_MASK          0x0070
+#define IGP01E1000_ANALOG_SPARE_FUSE_ENABLED        0x0100
+#define IGP01E1000_ANALOG_FUSE_ENABLE_SW_CONTROL    0x0002
+
+#define IGP01E1000_ANALOG_FUSE_COARSE_THRESH        0x0040
+#define IGP01E1000_ANALOG_FUSE_COARSE_10            0x0010
+#define IGP01E1000_ANALOG_FUSE_FINE_1               0x0080
+#define IGP01E1000_ANALOG_FUSE_FINE_10              0x0500
+
+
+/* Bit definitions for valid PHY IDs. */
+/* I = Integrated
+ * E = External
+ */
+#define M88E1000_E_PHY_ID  0x01410C50
+#define M88E1000_I_PHY_ID  0x01410C30
+#define M88E1011_I_PHY_ID  0x01410C20
+#define IGP01E1000_I_PHY_ID  0x02A80380
+#define M88E1000_12_PHY_ID M88E1000_E_PHY_ID
+#define M88E1000_14_PHY_ID M88E1000_E_PHY_ID
+#define M88E1011_I_REV_4   0x04
+#define M88E1111_I_PHY_ID  0x01410CC0
+#define L1LXT971A_PHY_ID   0x001378E0
+
+/* Miscellaneous PHY bit definitions. */
+#define PHY_PREAMBLE        0xFFFFFFFF
+#define PHY_SOF             0x01
+#define PHY_OP_READ         0x02
+#define PHY_OP_WRITE        0x01
+#define PHY_TURNAROUND      0x02
+#define PHY_PREAMBLE_SIZE   32
+#define MII_CR_SPEED_1000   0x0040
+#define MII_CR_SPEED_100    0x2000
+#define MII_CR_SPEED_10     0x0000
+#define E1000_PHY_ADDRESS   0x01
+#define PHY_AUTO_NEG_TIME   45  /* 4.5 Seconds */
+#define PHY_FORCE_TIME      20  /* 2.0 Seconds */
+#define PHY_REVISION_MASK   0xFFFFFFF0
+#define DEVICE_SPEED_MASK   0x00000300  /* Device Ctrl Reg Speed Mask */
+#define REG4_SPEED_MASK     0x01E0
+#define REG9_SPEED_MASK     0x0300
+#define ADVERTISE_10_HALF   0x0001
+#define ADVERTISE_10_FULL   0x0002
+#define ADVERTISE_100_HALF  0x0004
+#define ADVERTISE_100_FULL  0x0008
+#define ADVERTISE_1000_HALF 0x0010
+#define ADVERTISE_1000_FULL 0x0020
+#define AUTONEG_ADVERTISE_SPEED_DEFAULT 0x002F  /* Everything but 1000-Half */
+#define AUTONEG_ADVERTISE_10_100_ALL    0x000F /* All 10/100 speeds*/
+#define AUTONEG_ADVERTISE_10_ALL        0x0003 /* 10Mbps Full & Half speeds*/
+
+#endif /* _EM_HW_H_ */
Index: bsps/powerpc/beatnik/net/if_em/if_em_osdep.h
===================================================================
--- bsps/powerpc/beatnik/net/if_em/if_em_osdep.h	(revision 031df3914990db0336a0d386fb53558b05de467e)
+++ bsps/powerpc/beatnik/net/if_em/if_em_osdep.h	(revision 031df3914990db0336a0d386fb53558b05de467e)
@@ -0,0 +1,146 @@
+/**************************************************************************
+
+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: /repoman/r/ncvs/src/sys/dev/em/if_em_osdep.h,v 1.14 2005/05/26 23:32:02 tackerman Exp $*/
+
+#ifndef _RTEMS_OS_H_
+#define _RTEMS_OS_H_
+
+#include <rtems.h>
+#include "../porting/rtemscompat.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <bsp/pci.h>
+
+/* Eventually, we should include this
+#include <rtems/rtems-mii-ioctl.h>
+*/
+#define IFM_LINK_OK     IFM_FLAG0
+#define IFM_ANEG_DIS    IFM_FLAG1
+
+#define ASSERT(x) if(!(x)) panic("EM: x")
+
+/* The happy-fun DELAY macro is defined in /usr/src/sys/i386/include/clock.h */
+#define usec_delay(x) DELAY(x)
+#define msec_delay(x) DELAY(1000*(x))
+/* TODO: Should we be paranoid about delaying in interrupt context? */
+#define msec_delay_irq(x) DELAY(1000*(x))
+
+#define MSGOUT(S, A, B)     printf(S "\n", A, B)
+#define DEBUGFUNC(F)        DEBUGOUT(F);
+#if DBG
+	#define DEBUGOUT(S)         printf(S "\n")
+	#define DEBUGOUT1(S,A)      printf(S "\n",A)
+	#define DEBUGOUT2(S,A,B)    printf(S "\n",A,B)
+	#define DEBUGOUT3(S,A,B,C)  printf(S "\n",A,B,C)
+	#define bootverbose	(1)
+	#define DEBUGOUT7(S,A,B,C,D,E,F,G)  printf(S "\n",A,B,C,D,E,F,G)
+#else
+	#define DEBUGOUT(S)
+	#define DEBUGOUT1(S,A)
+	#define DEBUGOUT2(S,A,B)
+	#define DEBUGOUT3(S,A,B,C)
+	#define bootverbose	(0)
+	#define DEBUGOUT7(S,A,B,C,D,E,F,G)
+#endif
+
+#define CMD_MEM_WRT_INVALIDATE          0x0010  /* BIT_4 */
+#define PCI_COMMAND_REGISTER            PCIR_COMMAND
+
+struct em_osdep
+{
+	unsigned           mem_bus_space_handle;
+	device_t           dev;
+};
+
+struct rtems_ifmedia {
+	int	ifm_media;
+};
+
+#define E1000_WRITE_FLUSH(hw) E1000_READ_REG(hw, STATUS)
+
+/* Read from an absolute offset in the adapter's memory space */
+#define E1000_READ_OFFSET(hw, offset) \
+    bus_space_read_4( ((struct em_osdep *)(hw)->back)->mem_bus_space_tag, \
+                      ((struct em_osdep *)(hw)->back)->mem_bus_space_handle, \
+                      offset)
+
+/* Write to an absolute offset in the adapter's memory space */
+#define E1000_WRITE_OFFSET(hw, offset, value) \
+    bus_space_write_4( ((struct em_osdep *)(hw)->back)->mem_bus_space_tag, \
+                       ((struct em_osdep *)(hw)->back)->mem_bus_space_handle, \
+                       offset, \
+                       value)
+
+/* Convert a register name to its offset in the adapter's memory space */
+#define E1000_REG_OFFSET(hw, reg) \
+    ((hw)->mac_type >= em_82543 ? E1000_##reg : E1000_82542_##reg)
+
+#define E1000_READ_REG(hw, reg) \
+    E1000_READ_OFFSET(hw, E1000_REG_OFFSET(hw, reg))
+
+#define E1000_WRITE_REG(hw, reg, value) \
+    E1000_WRITE_OFFSET(hw, E1000_REG_OFFSET(hw, reg), value)
+
+#define E1000_READ_REG_ARRAY(hw, reg, index) \
+    E1000_READ_OFFSET(hw, E1000_REG_OFFSET(hw, reg) + ((index) << 2))
+
+#define E1000_READ_REG_ARRAY_DWORD E1000_READ_REG_ARRAY
+
+#define E1000_WRITE_REG_ARRAY(hw, reg, index, value) \
+    E1000_WRITE_OFFSET(hw, E1000_REG_OFFSET(hw, reg) + ((index) << 2), value)
+
+#define E1000_WRITE_REG_ARRAY_BYTE(hw, reg, index, value) \
+    bus_space_write_1( ((struct em_osdep *)(hw)->back)->mem_bus_space_tag, \
+                       ((struct em_osdep *)(hw)->back)->mem_bus_space_handle, \
+                       E1000_REG_OFFSET(hw, reg) + (index), \
+                       value)
+
+#define E1000_WRITE_REG_ARRAY_WORD(hw, reg, index, value) \
+    bus_space_write_2( ((struct em_osdep *)(hw)->back)->mem_bus_space_tag, \
+                       ((struct em_osdep *)(hw)->back)->mem_bus_space_handle, \
+                       E1000_REG_OFFSET(hw, reg) + (index), \
+                       value)
+
+#define E1000_WRITE_REG_ARRAY_DWORD(hw, reg, index, value) \
+    E1000_WRITE_OFFSET(hw, E1000_REG_OFFSET(hw, reg) + ((index) << 2), value)
+
+#endif  /* _FREEBSD_OS_H_ */
+
Index: bsps/powerpc/beatnik/net/if_em/if_em_rtems.c
===================================================================
--- bsps/powerpc/beatnik/net/if_em/if_em_rtems.c	(revision 031df3914990db0336a0d386fb53558b05de467e)
+++ bsps/powerpc/beatnik/net/if_em/if_em_rtems.c	(revision 031df3914990db0336a0d386fb53558b05de467e)
@@ -0,0 +1,106 @@
+#include "rtemscompat_defs.h"
+#include "../porting/if_xxx_rtems.c"
+#include <bsp/early_enet_link_status.h>
+#include <bsp/if_em_pub.h>
+
+/* Provide a routine to check link status early,
+ * i.e., before the network is really running.
+ * In case someone wants to decide whether to use/configure
+ * this interface at all :-)
+ *
+ * NOTE: this routine tries to enable autonegotiation!
+ *
+ * unit: unit number starting with 1 (usual BSDNET convention)
+ *
+ * RETURNS: Phy status register contents (1<<2 means link up).
+ *          or -1 on error.
+ */
+
+/* 
+ * Authorship
+ * ----------
+ * This software ('beatnik' RTEMS BSP for MVME6100 and MVME5500) was
+ *     created by Till Straumann <strauman@slac.stanford.edu>, 2005-2007,
+ * 	   Stanford Linear Accelerator Center, Stanford University.
+ * 
+ * Acknowledgement of sponsorship
+ * ------------------------------
+ * The 'beatnik' BSP was produced by
+ *     the Stanford Linear Accelerator Center, Stanford University,
+ * 	   under Contract DE-AC03-76SFO0515 with the Department of Energy.
+ * 
+ * Government disclaimer of liability
+ * ----------------------------------
+ * Neither the United States nor the United States Department of Energy,
+ * nor any of their employees, makes any warranty, express or implied, or
+ * assumes any legal liability or responsibility for the accuracy,
+ * completeness, or usefulness of any data, apparatus, product, or process
+ * disclosed, or represents that its use would not infringe privately owned
+ * rights.
+ * 
+ * Stanford disclaimer of liability
+ * --------------------------------
+ * Stanford University makes no representations or warranties, express or
+ * implied, nor assumes any liability for the use of this software.
+ * 
+ * Stanford disclaimer of copyright
+ * --------------------------------
+ * Stanford University, owner of the copyright, hereby disclaims its
+ * copyright and all other rights in this software.  Hence, anyone may
+ * freely use it for any purpose without restriction.  
+ * 
+ * Maintenance of notices
+ * ----------------------
+ * In the interest of clarity regarding the origin and status of this
+ * SLAC software, this and all the preceding Stanford University notices
+ * are to remain affixed to any copy or derivative of this software made
+ * or distributed by the recipient and are to be affixed to any copy of
+ * software made or distributed by the recipient that contains a copy or
+ * derivative of this software.
+ * 
+ * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
+ */ 
+
+static int
+em_early_init(int idx)
+{
+	if ( idx < 0 || idx >= NETDRIVER_SLOTS )
+		return -1;
+	return em_hw_early_init(&the_em_devs[idx]);
+}
+
+static int
+em_early_read_phy(int idx, unsigned reg)
+{
+unsigned short data;
+	if ( idx < 0 || idx >= NETDRIVER_SLOTS )
+		return -1;
+	/* Bizarre - I always have to read PHY_STATUS twice until a good link
+	 * status is read
+	 */	
+	if ( em_read_phy_reg(&the_em_devs[idx].d_softc.hw, reg, &data) )
+		return -1;
+	if ( PHY_STATUS == reg ) {
+		/* read again */
+		if ( em_read_phy_reg(&the_em_devs[idx].d_softc.hw, PHY_STATUS, &data) )
+			return -1;
+	}
+	return data;
+}
+
+static int
+em_early_write_phy(int idx, unsigned reg, unsigned val)
+{
+	if ( idx < 0 || idx >= NETDRIVER_SLOTS )
+		return -1;
+	return em_write_phy_reg(&the_em_devs[idx].d_softc.hw, reg, val);
+}
+
+rtems_bsdnet_early_link_check_ops
+rtems_em_early_link_check_ops = {
+	init:		em_early_init,
+	read_phy:	em_early_read_phy,
+	write_phy:	em_early_write_phy,
+	name:		NETDRIVER,
+	num_slots:	NETDRIVER_SLOTS
+};
Index: bsps/powerpc/beatnik/net/if_em/rtemscompat_defs.h
===================================================================
--- bsps/powerpc/beatnik/net/if_em/rtemscompat_defs.h	(revision 031df3914990db0336a0d386fb53558b05de467e)
+++ bsps/powerpc/beatnik/net/if_em/rtemscompat_defs.h	(revision 031df3914990db0336a0d386fb53558b05de467e)
@@ -0,0 +1,198 @@
+#ifndef RTEMS_COMPAT_DEFS_H
+#define RTEMS_COMPAT_DEFS_H
+
+/* Number of device instances the driver should support
+ * - may be limited to 1 depending on IRQ API
+ * (braindamaged PC586 and powerpc)
+ */
+#define NETDRIVER_SLOTS 1
+
+/* String name to print with error messages */
+#define NETDRIVER       "em"
+/* Name snippet used to make global symbols unique to this driver */
+#define NETDRIVER_PREFIX em
+
+#define adapter			em_softc
+#define interface_data	arpcom
+
+/* Define according to endianness of the *ethernet*chip*
+ * (not the CPU - most probably are LE)
+ * This must be either NET_CHIP_LE or NET_CHIP_BE
+ */
+
+#define NET_CHIP_LE
+#undef  NET_CHIP_BE
+
+/* Define either NET_CHIP_MEM_IO or NET_CHIP_PORT_IO,
+ * depending whether the CPU sees it in memory address space
+ * or (e.g. x86) uses special I/O instructions.
+ */
+#define NET_CHIP_MEM_IO
+#undef  NET_CHIP_PORT_IO
+
+/* The name of the hijacked 'bus handle' field in the softc
+ * structure. We use this field to store the chip's base address.
+ */
+#define NET_SOFTC_BHANDLE_FIELD osdep.mem_bus_space_handle
+
+/* define the names of the 'if_XXXreg.h' and 'if_XXXvar.h' headers
+ * (only if present, i.e., if the BSDNET driver has no respective
+ * header, leave this undefined).
+ *
+ */
+#define  IF_REG_HEADER "../if_em/if_em.h"
+#undef  IF_VAR_HEADER
+
+/* define if a pci device */
+#define NETDRIVER_PCI <bsp/pci.h>
+
+/* Macros to disable and enable interrupts, respectively.
+ * The 'disable' macro is expanded in the ISR, the 'enable'
+ * macro is expanded in the driver task.
+ * The global network semaphore usually provides mutex
+ * protection of the device registers.
+ * Special care must be taken when coding the 'disable' macro,
+ * however to MAKE SURE THERE ARE NO OTHER SIDE EFFECTS such
+ * as:
+ *    - macro must not clear any status flags
+ *    - macro must save/restore any context information
+ *      (e.g., a address register pointer or a bank switch register)
+ *
+ * ARGUMENT: the macro arg is a pointer to the driver's 'softc' structure
+ */
+
+#define NET_ENABLE_IRQS(sc)	do { \
+		E1000_WRITE_REG(&sc->hw, IMS, (IMS_ENABLE_MASK)); \
+		} while (0)
+
+#define NET_DISABLE_IRQS(sc)	do { \
+		E1000_WRITE_REG(&sc->hw, IMC, 0xffffffff);	\
+		} while (0)
+		
+#define KASSERT(a...) do {} while (0)
+
+/* dmamap stuff; these are defined just to work with the current version
+ * of this driver and the implementation must be carefully checked if
+ * a newer version is merged.!
+ *
+ * The more cumbersome routines have been commented in the source, the
+ * simpler ones are defined to be NOOPs here so the source gets less
+ * cluttered...
+ *
+ * ASSUMPTIONS:
+ *
+ *	  -> dmamap_sync cannot sync caches; assume we have HW snooping
+ *
+ */
+
+typedef unsigned bus_size_t;
+typedef unsigned bus_addr_t;
+
+typedef struct {
+	unsigned	ds_addr;
+	unsigned	ds_len;
+} bus_dma_segment_t;
+
+#define bus_dma_tag_destroy(args...) do {} while(0)
+
+#define bus_dmamap_destroy(args...) do {} while(0)
+
+#define bus_dmamap_unload(args...) do {} while (0)
+
+#ifdef __PPC__
+#define bus_dmamap_sync(args...) do { __asm__ volatile("sync":::"memory"); } while (0)
+#else
+#define bus_dmamap_sync(args...) do {} while (0)
+#endif
+
+#define BUS_DMA_NOWAIT		0xdeadbeef	/* unused */
+
+#define em_adapter_list _bsd_em_adapter_list
+#define em_arc_subsystem_valid _bsd_em_arc_subsystem_valid
+#define em_check_downshift _bsd_em_check_downshift
+#define em_check_for_link _bsd_em_check_for_link
+#define em_check_mng_mode _bsd_em_check_mng_mode
+#define em_check_phy_reset_block _bsd_em_check_phy_reset_block
+#define em_check_polarity _bsd_em_check_polarity
+#define em_cleanup_led _bsd_em_cleanup_led
+#define em_clear_hw_cntrs _bsd_em_clear_hw_cntrs
+#define em_clear_vfta _bsd_em_clear_vfta
+#define em_commit_shadow_ram _bsd_em_commit_shadow_ram
+#define em_config_collision_dist _bsd_em_config_collision_dist
+#define em_config_dsp_after_link_change _bsd_em_config_dsp_after_link_change
+#define em_config_fc_after_link_up _bsd_em_config_fc_after_link_up
+#define em_dbg_config _bsd_em_dbg_config
+#define em_detect_gig_phy _bsd_em_detect_gig_phy
+#define em_disable_pciex_master _bsd_em_disable_pciex_master
+#define em_display_debug_stats _bsd_em_display_debug_stats
+#define em_driver_version _bsd_em_driver_version
+#define em_enable_mng_pass_thru _bsd_em_enable_mng_pass_thru
+#define em_enable_pciex_master _bsd_em_enable_pciex_master
+#define em_enable_tx_pkt_filtering _bsd_em_enable_tx_pkt_filtering
+#define em_force_mac_fc _bsd_em_force_mac_fc
+#define em_get_auto_rd_done _bsd_em_get_auto_rd_done
+#define em_get_bus_info _bsd_em_get_bus_info
+#define em_get_cable_length _bsd_em_get_cable_length
+#define em_get_hw_eeprom_semaphore _bsd_em_get_hw_eeprom_semaphore
+#define em_get_phy_cfg_done _bsd_em_get_phy_cfg_done
+#define em_get_speed_and_duplex _bsd_em_get_speed_and_duplex
+#define em_hash_mc_addr _bsd_em_hash_mc_addr
+#define em_hw_early_init _bsd_em_hw_early_init
+#define em_id_led_init _bsd_em_id_led_init
+#define em_init_eeprom_params _bsd_em_init_eeprom_params
+#define em_init_hw _bsd_em_init_hw
+#define em_init_rx_addrs _bsd_em_init_rx_addrs
+#define em_io_read _bsd_em_io_read
+#define em_io_write _bsd_em_io_write
+#define em_is_onboard_nvm_eeprom _bsd_em_is_onboard_nvm_eeprom
+#define em_led_off _bsd_em_led_off
+#define em_led_on _bsd_em_led_on
+#define em_mc_addr_list_update _bsd_em_mc_addr_list_update
+#define em_mng_enable_host_if _bsd_em_mng_enable_host_if
+#define em_mng_host_if_write _bsd_em_mng_host_if_write
+#define em_mng_write_cmd_header _bsd_em_mng_write_cmd_header
+#define em_mng_write_commit _bsd_em_mng_write_commit
+#define em_mng_write_dhcp_info _bsd_em_mng_write_dhcp_info
+#define em_mta_set _bsd_em_mta_set
+#define em_pci_clear_mwi _bsd_em_pci_clear_mwi
+#define em_pci_set_mwi _bsd_em_pci_set_mwi
+#define em_phy_get_info _bsd_em_phy_get_info
+#define em_phy_hw_reset _bsd_em_phy_hw_reset
+#define em_phy_igp_get_info _bsd_em_phy_igp_get_info
+#define em_phy_m88_get_info _bsd_em_phy_m88_get_info
+#define em_phy_reset _bsd_em_phy_reset
+#define em_phy_setup_autoneg _bsd_em_phy_setup_autoneg
+#define em_poll_eerd_eewr_done _bsd_em_poll_eerd_eewr_done
+#define em_put_hw_eeprom_semaphore _bsd_em_put_hw_eeprom_semaphore
+#define em_rar_set _bsd_em_rar_set
+#define em_read_eeprom _bsd_em_read_eeprom
+#define em_read_eeprom_eerd _bsd_em_read_eeprom_eerd
+#define em_read_mac_addr _bsd_em_read_mac_addr
+#define em_read_part_num _bsd_em_read_part_num
+#define em_read_pci_cfg _bsd_em_read_pci_cfg
+#define em_read_phy_reg _bsd_em_read_phy_reg
+#define em_read_reg_io _bsd_em_read_reg_io
+#define em_reset_adaptive _bsd_em_reset_adaptive
+#define em_reset_hw _bsd_em_reset_hw
+#define em_set_d0_lplu_state _bsd_em_set_d0_lplu_state
+#define em_set_d3_lplu_state _bsd_em_set_d3_lplu_state
+#define em_set_mac_type _bsd_em_set_mac_type
+#define em_set_media_type _bsd_em_set_media_type
+#define em_set_pci_express_master_disable _bsd_em_set_pci_express_master_disable
+#define em_setup_led _bsd_em_setup_led
+#define em_setup_link _bsd_em_setup_link
+#define em_tbi_adjust_stats _bsd_em_tbi_adjust_stats
+#define em_update_adaptive _bsd_em_update_adaptive
+#define em_update_eeprom_checksum _bsd_em_update_eeprom_checksum
+#define em_validate_eeprom_checksum _bsd_em_validate_eeprom_checksum
+#define em_validate_mdi_setting _bsd_em_validate_mdi_setting
+#define em_wait_autoneg _bsd_em_wait_autoneg
+#define em_write_eeprom _bsd_em_write_eeprom
+#define em_write_eeprom_eewr _bsd_em_write_eeprom_eewr
+#define em_write_pci_cfg _bsd_em_write_pci_cfg
+#define em_write_phy_reg _bsd_em_write_phy_reg
+#define em_write_reg_io _bsd_em_write_reg_io
+#define em_write_vfta _bsd_em_write_vfta
+#define the_em_devs _bsd_the_em_devs
+
+#endif
Index: bsps/powerpc/beatnik/net/if_gfe/gtethreg.h
===================================================================
--- bsps/powerpc/beatnik/net/if_gfe/gtethreg.h	(revision 031df3914990db0336a0d386fb53558b05de467e)
+++ bsps/powerpc/beatnik/net/if_gfe/gtethreg.h	(revision 031df3914990db0336a0d386fb53558b05de467e)
@@ -0,0 +1,854 @@
+/*	$NetBSD: gtethreg.h,v 1.2.10.1 2005/04/29 11:28:55 kent Exp $	*/
+
+/*
+ * Copyright (c) 2002 Allegro Networks, Inc., Wasabi Systems, Inc.
+ * 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. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed for the NetBSD Project by
+ *      Allegro Networks, Inc., and Wasabi Systems, Inc.
+ * 4. The name of Allegro Networks, Inc. may not be used to endorse
+ *    or promote products derived from this software without specific prior
+ *    written permission.
+ * 5. The name of Wasabi Systems, Inc. may not be used to endorse
+ *    or promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ALLEGRO NETWORKS, INC. AND
+ * WASABI SYSTEMS, INC. ``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 EITHER ALLEGRO NETWORKS, INC. OR WASABI SYSTEMS, INC.
+ * 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 _DEV_GTETHREG_H_
+#define	_DEV_GTETHREG_H_
+
+#define ETH__BIT(bit)			(1U << (bit))
+#define ETH__LLBIT(bit)			(1LLU << (bit))
+#define ETH__MASK(bit)			(ETH__BIT(bit) - 1)
+#define ETH__LLMASK(bit)		(ETH__LLBIT(bit) - 1)
+#define ETH__GEN(n, off)		(0x2400+((n) << 10)+(ETH__ ## off))
+#define	ETH__EXT(data, bit, len)	(((data) >> (bit)) & ETH__MASK(len))
+#define	ETH__LLEXT(data, bit, len)	(((data) >> (bit)) & ETH__LLMASK(len))
+#define	ETH__CLR(data, bit, len)	((data) &= ~(ETH__MASK(len) << (bit)))
+#define	ETH__INS(new, bit)		((new) << (bit))
+#define	ETH__LLINS(new, bit)		((uint64_t)(new) << (bit))
+
+/*
+ * Descriptors used for both receive & transmit data.  Note that the descriptor
+ * must start on a 4LW boundary.  Since the GT accesses the descriptor as
+ * two 64-bit quantities, we must present them 32bit quantities in the right
+ * order based on endianess.
+ */
+
+struct gt_eth_desc {
+#if defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN
+	u_int32_t ed_lencnt;	/* length is hi 16 bits; count (rx) is lo 16 */
+	u_int32_t ed_cmdsts;	/* command (hi16)/status (lo16) bits */
+	u_int32_t ed_nxtptr;	/* next descriptor (must be 4LW aligned) */
+	u_int32_t ed_bufptr;	/* pointer to packet buffer */
+#endif
+#if defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN
+	u_int32_t ed_cmdsts;	/* command (hi16)/status (lo16) bits */
+	u_int32_t ed_lencnt;	/* length is hi 16 bits; count (rx) is lo 16 */
+	u_int32_t ed_bufptr;	/* pointer to packet buffer */
+	u_int32_t ed_nxtptr;	/* next descriptor (must be 4LW aligned) */
+#endif
+};
+
+/* Table 578: Ethernet TX Descriptor - Command/Status word
+ * All bits except F, EI, AM, O are only valid if TX_CMD_L is also set,
+ * otherwise should be 0 (tx).
+ */
+#define	TX_STS_LC	ETH__BIT(5)	/* Late Collision */
+#define	TX_STS_UR	ETH__BIT(6)	/* Underrun error */
+#define	TX_STS_RL	ETH__BIT(8)	/* Retransmit Limit (excession coll) */
+#define	TX_STS_COL	ETH__BIT(9)	/* Collision Occurred */
+#define	TX_STS_RC(v)	ETH__GETBITS(v, 10, 4)	/* Retransmit Count */
+#define	TX_STS_ES	ETH__BIT(15)	/* Error Summary (LC|UR|RL) */
+#define	TX_CMD_L	ETH__BIT(16)	/* Last - End Of Packet */
+#define	TX_CMD_F	ETH__BIT(17)	/* First - Start Of Packet */
+#define	TX_CMD_P	ETH__BIT(18)	/* Pad Packet */
+#define	TX_CMD_GC	ETH__BIT(22)	/* Generate CRC */
+#define	TX_CMD_EI	ETH__BIT(23)	/* Enable Interrupt */
+#define	TX_CMD_AM	ETH__BIT(30)	/* Auto Mode */
+#define	TX_CMD_O	ETH__BIT(31)	/* Ownership (1=GT 0=CPU) */
+
+#define	TX_CMD_FIRST	(TX_CMD_F|TX_CMD_O)
+#define	TX_CMD_LAST	(TX_CMD_L|TX_CMD_GC|TX_CMD_P|TX_CMD_O)
+
+/* Table 582: Ethernet RX Descriptor - Command/Status Word
+ * All bits except F, EI, AM, O are only valid if RX_CMD_L is also set,
+ * otherwise should be ignored (rx).
+ */
+#define	RX_STS_CE	ETH__BIT(0)	/* CRC Error */
+#define	RX_STS_COL	ETH__BIT(1)	/* Collision sensed during reception */
+#define	RX_STS_LC	ETH__BIT(5)	/* Late Collision (Reserved) */
+#define	RX_STS_OR	ETH__BIT(6)	/* Overrun Error */
+#define	RX_STS_MFL	ETH__BIT(7)	/* Max Frame Len Error */
+#define	RX_STS_SF	ETH__BIT(8)	/* Short Frame Error (< 64 bytes) */
+#define	RX_STS_FT	ETH__BIT(11)	/* Frame Type (1 = 802.3) */
+#define	RX_STS_M	ETH__BIT(12)	/* Missed Frame */
+#define	RX_STS_HE	ETH__BIT(13)	/* Hash Expired (manual match) */
+#define	RX_STS_IGMP	ETH__BIT(14)	/* IGMP Packet */
+#define	RX_STS_ES	ETH__BIT(15)	/* Error Summary (CE|COL|LC|OR|MFL|SF) */
+#define	RX_CMD_L	ETH__BIT(16)	/* Last - End Of Packet */
+#define	RX_CMD_F	ETH__BIT(17)	/* First - Start Of Packet */
+#define	RX_CMD_EI	ETH__BIT(23)	/* Enable Interrupt */
+#define	RX_CMD_AM	ETH__BIT(30)	/* Auto Mode */
+#define	RX_CMD_O	ETH__BIT(31)	/* Ownership (1=GT 0=CPU) */
+
+/* Table 586: Hash Table Entry Fields
+ */
+#define HSH_V		ETH__LLBIT(0)	/* Entry is valid */
+#define HSH_S		ETH__LLBIT(1)	/* Skip this entry */
+#define HSH_RD		ETH__LLBIT(2)	/* Receive(1) / Discard (0) */
+#define HSH_R		ETH__LLBIT(2)	/* Receive(1) */
+#define	HSH_PRIO_GET(v)	ETH__LLEXT(v, 51, 2)
+#define	HSH_PRIO_INS(v)	ETH__LLINS(v, 51)
+#define	HSH_ADDR_MASK	0x7fffff8LLU
+#define	HSH_LIMIT	12
+
+
+#define	ETH_EPAR	0x2000		/* PHY Address Register */
+#define	ETH_ESMIR	0x2010		/* SMI Register */
+
+#define	ETH_BASE_ETH0	0x2400		/* Ethernet0 Register Base */
+#define	ETH_BASE_ETH1	0x2800		/* Ethernet1 Register Base */
+#define	ETH_BASE_ETH2	0x2c00		/* Ethernet2 Register Base */
+#define	ETH_SIZE	0x0400		/* Register Space */
+
+#define	ETH__EBASE	0x0000		/* Base of Registers */
+#define	ETH__EPCR	0x0000		/* Port Config. Register */
+#define	ETH__EPCXR	0x0008		/* Port Config. Extend Reg */
+#define	ETH__EPCMR	0x0010		/* Port Command Register */
+#define	ETH__EPSR	0x0018		/* Port Status Register */
+#define	ETH__ESPR	0x0020		/* Port Serial Parameters Reg */
+#define	ETH__EHTPR	0x0028		/* Port Hash Table Pointer Reg*/
+#define	ETH__EFCSAL	0x0030		/* Flow Control Src Addr Low */
+#define	ETH__EFCSAH	0x0038		/* Flow Control Src Addr High */
+#define	ETH__ESDCR	0x0040		/* SDMA Configuration Reg */
+#define	ETH__ESDCMR	0x0048		/* SDMA Command Register */
+#define	ETH__EICR	0x0050		/* Interrupt Cause Register */
+#define	ETH__EIMR	0x0058		/* Interrupt Mask Register */
+#define	ETH__EFRDP0	0x0080		/* First Rx Desc Pointer 0 */
+#define	ETH__EFRDP1	0x0084		/* First Rx Desc Pointer 1 */
+#define	ETH__EFRDP2	0x0088		/* First Rx Desc Pointer 2 */
+#define	ETH__EFRDP3	0x008c		/* First Rx Desc Pointer 3 */
+#define	ETH__ECRDP0	0x00a0		/* Current Rx Desc Pointer 0 */
+#define	ETH__ECRDP1	0x00a4		/* Current Rx Desc Pointer 1 */
+#define	ETH__ECRDP2	0x00a8		/* Current Rx Desc Pointer 2 */
+#define	ETH__ECRDP3	0x00ac		/* Current Rx Desc Pointer 3 */
+#define	ETH__ECTDP0	0x00e0		/* Current Tx Desc Pointer 0 */
+#define	ETH__ECTDP1	0x00e4		/* Current Tx Desc Pointer 1 */
+#define	ETH__EDSCP2P0L	0x0060		/* IP Differentiated Services
+					   CodePoint to Priority0 low */
+#define	ETH__EDSCP2P0H	0x0064		/* IP Differentiated Services
+					   CodePoint to Priority0 high*/
+#define	ETH__EDSCP2P1L	0x0068		/* IP Differentiated Services
+					   CodePoint to Priority1 low */
+#define	ETH__EDSCP2P1H	0x006c		/* IP Differentiated Services
+					   CodePoint to Priority1 high*/
+#define	ETH__EVPT2P	0x0068		/* VLAN Prio. Tag to Priority */
+#define	ETH__EMIBCTRS	0x0100		/* MIB Counters */
+
+#define	ETH_BASE(n)	ETH__GEN(n, EBASE)
+#define	ETH_EPCR(n)	ETH__GEN(n, EPCR)	/* Port Config. Register */
+#define	ETH_EPCXR(n)	ETH__GEN(n, EPCXR)	/* Port Config. Extend Reg */
+#define	ETH_EPCMR(n)	ETH__GEN(n, EPCMR)	/* Port Command Register */
+#define	ETH_EPSR(n)	ETH__GEN(n, EPSR)	/* Port Status Register */
+#define	ETH_ESPR(n)	ETH__GEN(n, ESPR)	/* Port Serial Parameters Reg */
+#define	ETH_EHTPR(n)	ETH__GEN(n, EHPTR)	/* Port Hash Table Pointer Reg*/
+#define	ETH_EFCSAL(n)	ETH__GEN(n, EFCSAL)	/* Flow Control Src Addr Low */
+#define	ETH_EFCSAH(n)	ETH__GEN(n, EFCSAH)	/* Flow Control Src Addr High */
+#define	ETH_ESDCR(n)	ETH__GEN(n, ESDCR)	/* SDMA Configuration Reg */
+#define	ETH_ESDCMR(n)	ETH__GEN(n, ESDCMR)	/* SDMA Command Register */
+#define	ETH_EICR(n)	ETH__GEN(n, EICR)	/* Interrupt Cause Register */
+#define	ETH_EIMR(n)	ETH__GEN(n, EIMR)	/* Interrupt Mask Register */
+#define	ETH_EFRDP0(n)	ETH__GEN(n, EFRDP0)	/* First Rx Desc Pointer 0 */
+#define	ETH_EFRDP1(n)	ETH__GEN(n, EFRDP1)	/* First Rx Desc Pointer 1 */
+#define	ETH_EFRDP2(n)	ETH__GEN(n, EFRDP2)	/* First Rx Desc Pointer 2 */
+#define	ETH_EFRDP3(n)	ETH__GEN(n, EFRDP3)	/* First Rx Desc Pointer 3 */
+#define	ETH_ECRDP0(n)	ETH__GEN(n, ECRDP0)	/* Current Rx Desc Pointer 0 */
+#define	ETH_ECRDP1(n)	ETH__GEN(n, ECRDP1)	/* Current Rx Desc Pointer 1 */
+#define	ETH_ECRDP2(n)	ETH__GEN(n, ECRDP2)	/* Current Rx Desc Pointer 2 */
+#define	ETH_ECRDP3(n)	ETH__GEN(n, ECRDP3)	/* Current Rx Desc Pointer 3 */
+#define	ETH_ECTDP0(n)	ETH__GEN(n, ECTDP0)	/* Current Tx Desc Pointer 0 */
+#define	ETH_ECTDP1(n)	ETH__GEN(n, ECTDP1)	/* Current Tx Desc Pointer 1 */
+#define	ETH_EDSCP2P0L(n) ETH__GEN(n, EDSCP2P0L)	/* IP Differentiated Services
+						   CodePoint to Priority0 low */
+#define	ETH_EDSCP2P0H(n) ETH__GEN(n, EDSCP2P0H)	/* IP Differentiated Services
+						   CodePoint to Priority0 high*/
+#define	ETH_EDSCP2P1L(n) ETH__GEN(n, EDSCP2P1L)	/* IP Differentiated Services
+						   CodePoint to Priority1 low */
+#define	ETH_EDSCP2P1H(n) ETH__GEN(n, EDSCP1P1H)	/* IP Differentiated Services
+						   CodePoint to Priority1 high*/
+#define	ETH_EVPT2P(n)	ETH__GEN(n, EVPT2P)	/* VLAN Prio. Tag to Priority */
+#define	ETH_EMIBCTRS(n) ETH__GEN(n, EMIBCTRS)	/* MIB Counters */
+
+#define	ETH_EPAR_PhyAD_GET(v, n)	(((v) >> ((n) * 5)) & 0x1f)
+
+#define ETH_ESMIR_READ(phy, reg)	(ETH__INS(phy, 16)|\
+					 ETH__INS(reg, 21)|\
+					 ETH_ESMIR_ReadOpcode)
+#define ETH_ESMIR_WRITE(phy, reg, val)	(ETH__INS(phy, 16)|\
+					 ETH__INS(reg, 21)|\
+					 ETH__INS(val,  0)|\
+					 ETH_ESMIR_WriteOpcode)
+#define ETH_ESMIR_Value_GET(v)		ETH__EXT(v, 0, 16)
+#define	ETH_ESMIR_WriteOpcode		0
+#define	ETH_ESMIR_ReadOpcode		ETH__BIT(26)
+#define	ETH_ESMIR_ReadValid		ETH__BIT(27)
+#define	ETH_ESMIR_Busy			ETH__BIT(28)
+
+/*
+ * Table 597: Port Configuration Register (PCR)
+ * 00:00 PM			Promiscuous mode
+ *				0: Normal mode (Frames are only received if the
+ *				   destination address is found in the hash
+ *				   table)
+ *				1: Promiscuous mode (Frames are received
+ *				   regardless of their destination address.
+ *				   Errored frames are discarded unless the Port
+ *				   Configuration register's PBF bit is set)
+ * 01:01 RBM			Reject Broadcast Mode
+ *				0: Receive broadcast address
+ *				1: Reject frames with broadcast address
+ *				Overridden by the promiscuous mode.
+ * 02:02 PBF			Pass Bad Frames
+ *				(0: Normal mode, 1: Pass bad Frames)
+ *				The Ethernet receiver passes to the CPU errored
+ *				frames (like fragments and collided packets)
+ *				that are normally rejected.
+ *				NOTE: Frames are only passed if they
+ *				      successfully pass address filtering.
+ * 06:03 Reserved
+ * 07:07 EN			Enable (0: Disabled, 1: Enable)
+ *				When enabled, the ethernet port is ready to
+ *				transmit/receive.
+ * 09:08 LPBK			Loop Back Mode
+ *				00: Normal mode
+ *				01: Internal loop back mode (TX data is looped
+ *				    back to the RX lines. No transition is seen
+ *				    on the interface pins)
+ *				10: External loop back mode (TX data is looped
+ *				    back to the RX lines and also transmitted
+ *				    out to the MII interface pins)
+ *				11: Reserved
+ * 10:10 FC			Force Collision
+ *				0: Normal mode.
+ *				1: Force Collision on any TX frame.
+ *				   For RXM test (in Loopback mode).
+ * 11:11 Reserved.
+ * 12:12 HS			Hash Size
+ *				0: 8K address filtering
+ *				   (256KB of memory space required).
+ *				1: 512 address filtering
+ *				   ( 16KB of memory space required).
+ * 13:13 HM			Hash Mode (0: Hash Func. 0; 1: Hash Func. 1)
+ * 14:14 HDM			Hash Default Mode
+ *				0: Discard addresses not found in address table
+ *				1: Pass addresses not found in address table
+ * 15:15 HD			Duplex Mode (0: Half Duplex, 1: Full Duplex)
+ *				NOTE: Valid only when auto-negotiation for
+ *				      duplex mode is disabled.
+ * 30:16 Reserved
+ * 31:31 ACCS			Accelerate Slot Time
+ *				(0: Normal mode, 1: Reserved)
+ */
+#define	ETH_EPCR_PM		ETH__BIT(0)
+#define	ETH_EPCR_RBM		ETH__BIT(1)
+#define	ETH_EPCR_PBF		ETH__BIT(2)
+#define	ETH_EPCR_EN		ETH__BIT(7)
+#define	ETH_EPCR_LPBK_GET(v)	ETH__BIT(v, 8, 2)
+#define	ETH_EPCR_LPBK_Normal	0
+#define	ETH_EPCR_LPBK_Internal	1
+#define	ETH_EPCR_LPBK_External	2
+#define	ETH_EPCR_FC		ETH__BIT(10)
+
+#define	ETH_EPCR_HS		ETH__BIT(12)
+#define	ETH_EPCR_HS_8K		0
+#define	ETH_EPCR_HS_512		ETH_EPCR_HS
+
+#define	ETH_EPCR_HM		ETH__BIT(13)
+#define	ETH_EPCR_HM_0		0
+#define	ETH_EPCR_HM_1		ETH_EPCR_HM
+
+#define	ETH_EPCR_HDM		ETH__BIT(14)
+#define	ETH_EPCR_HDM_Discard	0
+#define	ETH_EPCR_HDM_Pass	ETH_EPCR_HDM
+
+#define	ETH_EPCR_HD_Half	0
+#define	ETH_EPCR_HD_Full	ETH_EPCR_HD_Full
+
+#define	ETH_EPCR_ACCS		ETH__BIT(31)
+
+
+
+/*
+ * Table 598: Port Configuration Extend Register (PCXR)
+ * 00:00 IGMP			IGMP Packets Capture Enable
+ *				0: IGMP packets are treated as normal Multicast
+ *				   packets.
+ *				1: IGMP packets on IPv4/Ipv6 over Ethernet/802.3
+ *				   are trapped and sent to high priority RX
+ *				   queue.
+ * 01:01 SPAN			Spanning Tree Packets Capture Enable
+ *				0: BPDU (Bridge Protocol Data Unit) packets are
+ *				   treated as normal Multicast packets.
+ *				1: BPDU packets are trapped and sent to high
+ *				   priority RX queue.
+ * 02:02 PAR			Partition Enable (0: Normal, 1: Partition)
+ *				When more than 61 collisions occur while
+ *				transmitting, the port enters Partition mode.
+ *				It waits for the first good packet from the
+ *				wire and then goes back to Normal mode.  Under
+ *				Partition mode it continues transmitting, but
+ *				it does not receive.
+ * 05:03 PRIOtx			Priority weight in the round-robin between high
+ *				and low priority TX queues.
+ *				000: 1 pkt from HIGH, 1 pkt from LOW.
+ *				001: 2 pkt from HIGH, 1 pkt from LOW.
+ *				010: 4 pkt from HIGH, 1 pkt from LOW.
+ *				011: 6 pkt from HIGH, 1 pkt from LOW.
+ *				100: 8 pkt from HIGH, 1 pkt from LOW.
+ *				101: 10 pkt from HIGH, 1 pkt from LOW.
+ *				110: 12 pkt from HIGH, 1 pkt from LOW.
+ *				111: All pkt from HIGH, 0 pkt from LOW. LOW is
+ *				     served only if HIGH is empty.
+ *				NOTE: If the HIGH queue is emptied before
+ *				      finishing the count, the count is reset
+ *				      until the next first HIGH comes in.
+ * 07:06 PRIOrx			Default Priority for Packets Received on this
+ *				Port (00: Lowest priority, 11: Highest priority)
+ * 08:08 PRIOrx_Override	Override Priority for Packets Received on this
+ *				Port (0: Do not override, 1: Override with
+ *				<PRIOrx> field)
+ * 09:09 DPLXen			Enable Auto-negotiation for Duplex Mode
+ *				(0: Enable, 1: Disable)
+ * 11:10 FCTLen			Enable Auto-negotiation for 802.3x Flow-control
+ *				0: Enable; When enabled, 1 is written (through
+ *				   SMI access) to the PHY's register 4 bit 10
+ *				   to advertise flow-control capability.
+ *				1: Disable; Only enables flow control after the
+ *				   PHY address is set by the CPU. When changing
+ *				   the PHY address the flow control
+ *				   auto-negotiation must be disabled.
+ * 11:11 FLP			Force Link Pass
+ *				(0: Force Link Pass, 1: Do NOT Force Link pass)
+ * 12:12 FCTL			802.3x Flow-Control Mode (0: Enable, 1: Disable)
+ *				NOTE: Only valid when auto negotiation for flow
+ *				      control is disabled.
+ * 13:13 Reserved
+ * 15:14 MFL			Max Frame Length
+ *				Maximum packet allowed for reception (including
+ *				CRC):   00: 1518 bytes,   01: 1536 bytes,
+ *					10: 2048 bytes,   11:  64K bytes
+ * 16:16 MIBclrMode		MIB Counters Clear Mode (0: Clear, 1: No effect)
+ * 17:17 MIBctrMode		Reserved. (MBZ)
+ * 18:18 Speed			Port Speed (0: 10Mbit/Sec, 1: 100Mbit/Sec)
+ *				NOTE: Only valid if SpeedEn bit is set.
+ * 19:19 SpeedEn		Enable Auto-negotiation for Speed
+ *				(0: Enable, 1: Disable)
+ * 20:20 RMIIen			RMII enable
+ *				0: Port functions as MII port
+ *				1: Port functions as RMII port
+ * 21:21 DSCPen			DSCP enable
+ *				0: IP DSCP field decoding is disabled.
+ *				1: IP DSCP field decoding is enabled.
+ * 31:22 Reserved
+ */
+#define	ETH_EPCXR_IGMP			ETH__BIT(0)
+#define	ETH_EPCXR_SPAN			ETH__BIT(1)
+#define	ETH_EPCXR_PAR			ETH__BIT(2)
+#define	ETH_EPCXR_PRIOtx_GET(v)		ETH__EXT(v, 3, 3)
+#define	ETH_EPCXR_PRIOrx_GET(v)		ETH__EXT(v, 3, 3)
+#define	ETH_EPCXR_PRIOrx_Override	ETH__BIT(8)
+#define	ETH_EPCXR_DLPXen		ETH__BIT(9)
+#define	ETH_EPCXR_FCTLen		ETH__BIT(10)
+#define	ETH_EPCXR_FLP			ETH__BIT(11)
+#define	ETH_EPCXR_FCTL			ETH__BIT(12)
+#define	ETH_EPCXR_MFL_GET(v)		ETH__EXT(v, 14, 2)
+#define	ETH_EPCXR_MFL_1518		0
+#define	ETH_EPCXR_MFL_1536		1
+#define	ETH_EPCXR_MFL_2084		2
+#define	ETH_EPCXR_MFL_64K		3
+#define	ETH_EPCXR_MIBclrMode		ETH__BIT(16)
+#define	ETH_EPCXR_MIBctrMode		ETH__BIT(17)
+#define	ETH_EPCXR_Speed			ETH__BIT(18)
+#define	ETH_EPCXR_SpeedEn		ETH__BIT(19)
+#define	ETH_EPCXR_RMIIEn		ETH__BIT(20)
+#define	ETH_EPCXR_DSCPEn		ETH__BIT(21)
+
+
+
+/*
+ * Table 599: Port Command Register (PCMR)
+ * 14:00 Reserved
+ * 15:15 FJ			Force Jam / Flow Control
+ *				When in half-duplex mode, the CPU uses this bit
+ *				to force collisions on the Ethernet segment.
+ *				When the CPU recognizes that it is going to run
+ *				out of receive buffers, it can force the
+ *				transmitter to send jam frames, forcing
+ *				collisions on the wire.  To allow transmission
+ *				on the Ethernet segment, the CPU must clear the
+ *				FJ bit when more resources are available.  When
+ *				in full-duplex and flow-control is enabled, this
+ *				bit causes the port's transmitter to send
+ *				flow-control PAUSE packets. The CPU must reset
+ *				this bit when more resources are available.
+ * 31:16 Reserved
+ */
+
+#define	ETH_EPCMR_FJ		ETH__BIT(15)
+
+
+/*
+ * Table 600: Port Status Register (PSR) -- Read Only
+ * 00:00 Speed			Indicates Port Speed (0: 10Mbs, 1: 100Mbs)
+ * 01:01 Duplex			Indicates Port Duplex Mode (0: Half, 1: Full)
+ * 02:02 Fctl			Indicates Flow-control Mode
+ *				(0: enabled, 1: disabled)
+ * 03:03 Link			Indicates Link Status (0: down, 1: up)
+ * 04:04 Pause			Indicates that the port is in flow-control
+ *				disabled state.  This bit is set when an IEEE
+ *				802.3x flow-control PAUSE (XOFF) packet is
+ *				received (assuming that flow-control is
+ *				enabled and the port is in full-duplex mode).
+ *				Reset when XON is received, or when the XOFF
+ *				timer has expired.
+ * 05:05 TxLow			Tx Low Priority Status
+ *				Indicates the status of the low priority
+ *				transmit queue: (0: Stopped, 1: Running)
+ * 06:06 TxHigh			Tx High Priority Status
+ *				Indicates the status of the high priority
+ *				transmit queue: (0: Stopped, 1: Running)
+ * 07:07 TXinProg		TX in Progress
+ *				Indicates that the port's transmitter is in an
+ *				active transmission state.
+ * 31:08 Reserved
+ */
+#define	ETH_EPSR_Speed		ETH__BIT(0)
+#define	ETH_EPSR_Duplex		ETH__BIT(1)
+#define	ETH_EPSR_Fctl		ETH__BIT(2)
+#define	ETH_EPSR_Link		ETH__BIT(3)
+#define	ETH_EPSR_Pause		ETH__BIT(4)
+#define	ETH_EPSR_TxLow		ETH__BIT(5)
+#define	ETH_EPSR_TxHigh		ETH__BIT(6)
+#define	ETH_EPSR_TXinProg	ETH__BIT(7)
+
+
+/*
+ * Table 601: Serial Parameters Register (SPR)
+ * 01:00 JAM_LENGTH		Two bits to determine the JAM Length
+ *				(in Backpressure) as follows:
+ *					00 = 12K bit-times
+ *					01 = 24K bit-times
+ *					10 = 32K bit-times
+ *					11 = 48K bit-times
+ * 06:02 JAM_IPG		Five bits to determine the JAM IPG.
+ *				The step is four bit-times. The value may vary
+ *				between 4 bit time to 124.
+ * 11:07 IPG_JAM_TO_DATA	Five bits to determine the IPG JAM to DATA.
+ *				The step is four bit-times. The value may vary
+ *				between 4 bit time to 124.
+ * 16:12 IPG_DATA		Inter-Packet Gap (IPG)
+ *				The step is four bit-times. The value may vary
+ *				between 12 bit time to 124.
+ *				NOTE: These bits may be changed only when the
+ *				      Ethernet ports is disabled.
+ * 21:17 Data_Blind		Data Blinder
+ *				The number of nibbles from the beginning of the
+ *				IPG, in which the IPG counter is restarted when
+ *				detecting a carrier activity.  Following this
+ *				value, the port enters the Data Blinder zone and
+ *				does not reset the IPG counter. This ensures
+ *				fair access to the medium.
+ *				The default is 10 hex (64 bit times - 2/3 of the
+ *				default IPG).  The step is 4 bit-times. Valid
+ *				range is 3 to 1F hex nibbles.
+ *				NOTE: These bits may be only changed when the
+ *				      Ethernet port is disabled.
+ * 22:22 Limit4			The number of consecutive packet collisions that
+ *				occur before the collision counter is reset.
+ *				  0: The port resets its collision counter after
+ *				     16 consecutive retransmit trials and
+ *				     restarts the Backoff algorithm.
+ *				  1: The port resets its collision counter and
+ *				     restarts the Backoff algorithm after 4
+ *				     consecutive transmit trials.
+ * 31:23 Reserved
+ */
+#define	ETH_ESPR_JAM_LENGTH_GET(v)	ETH__EXT(v, 0, 2)
+#define	ETH_ESPR_JAM_IPG_GET(v)		ETH__EXT(v, 2, 5)
+#define	ETH_ESPR_IPG_JAM_TO_DATA_GET(v)	ETH__EXT(v, 7, 5)
+#define	ETH_ESPR_IPG_DATA_GET(v)	ETH__EXT(v, 12, 5)
+#define	ETH_ESPR_Data_Bilnd_GET(v)	ETH__EXT(v, 17, 5)
+#define	ETH_ESPR_Limit4(v)		ETH__BIT(22)
+
+/*
+ * Table 602: Hash Table Pointer Register (HTPR)
+ * 31:00 HTP			32-bit pointer to the address table.
+ *				Bits [2:0] must be set to zero.
+ */
+
+/*
+ * Table 603: Flow Control Source Address Low (FCSAL)
+ * 15:0 SA[15:0]		Source Address
+ *				The least significant bits of the source
+ *				address for the port.  This address is used for
+ *				Flow Control.
+ * 31:16 Reserved
+ */
+
+/*
+ * Table 604: Flow Control Source Address High (FCSAH)
+ * 31:0 SA[47:16]		Source Address
+ *				The most significant bits of the source address
+ *				for the port.  This address is used for Flow
+ *				Control.
+ */
+
+
+/*
+ * Table 605: SDMA Configuration Register (SDCR)
+ * 01:00 Reserved
+ * 05:02 RC			Retransmit Count
+ *				Sets the maximum number of retransmits per
+ *				packet.  After executing retransmit for RC
+ *				times, the TX SDMA closes the descriptor with a
+ *				Retransmit Limit error indication and processes
+ *				the next packet.  When RC is set to 0, the
+ *				number of retransmits is unlimited. In this
+ *				case, the retransmit process is only terminated
+ *				if CPU issues an Abort command.
+ * 06:06 BLMR			Big/Little Endian Receive Mode
+ *				The DMA supports Big or Little Endian
+ *				configurations on a per channel basis. The BLMR
+ *				bit only affects data transfer to memory.
+ *					0: Big Endian
+ *					1: Little Endian
+ * 07:07 BLMT			Big/Little Endian Transmit Mode
+ *				The DMA supports Big or Little Endian
+ *				configurations on a per channel basis. The BLMT
+ *				bit only affects data transfer from memory.
+ *					0: Big Endian
+ *					1: Little Endian
+ * 08:08 POVR			PCI Override
+ *				When set, causes the SDMA to direct all its
+ *				accesses in PCI_0 direction and overrides
+ *				normal address decoding process.
+ * 09:09 RIFB			Receive Interrupt on Frame Boundaries
+ *				When set, the SDMA Rx generates interrupts only
+ *				on frame boundaries (i.e. after writing the
+ *				frame status to the descriptor).
+ * 11:10 Reserved
+ * 13:12 BSZ			Burst Size
+ *				Sets the maximum burst size for SDMA
+ *				transactions:
+ *					00: Burst is limited to 1 64bit words.
+ *					01: Burst is limited to 2 64bit words.
+ *					10: Burst is limited to 4 64bit words.
+ *					11: Burst is limited to 8 64bit words.
+ * 31:14 Reserved
+ */
+#define	ETH_ESDCR_RC_GET(v)		ETH__EXT(v, 2, 4)
+#define	ETH_ESDCR_BLMR			ETH__BIT(6)
+#define	ETH_ESDCR_BLMT			ETH__BIT(7)
+#define	ETH_ESDCR_POVR			ETH__BIT(8)
+#define	ETH_ESDCR_RIFB			ETH__BIT(9)
+#define	ETH_ESDCR_BSZ_GET(v)		ETH__EXT(v, 12, 2)
+#define	ETH_ESDCR_BSZ_SET(v, n)		(ETH__CLR(v, 12, 2),\
+					 (v) |= ETH__INS(n, 12))
+#define	ETH_ESDCR_BSZ_1			0
+#define	ETH_ESDCR_BSZ_2			1
+#define	ETH_ESDCR_BSZ_4			2
+#define	ETH_ESDCR_BSZ_8			3
+
+#define	ETH_ESDCR_BSZ_Strings		{ "1 64-bit word", "2 64-bit words", \
+					  "4 64-bit words", "8 64-bit words" }
+
+/*
+ * Table 606: SDMA Command Register (SDCMR)
+ * 06:00 Reserved
+ * 07:07 ERD			Enable RX DMA.
+ *				Set to 1 by the CPU to cause the SDMA to start
+ *				a receive process.  Cleared when the CPU issues
+ *				an Abort Receive command.
+ * 14:08 Reserved
+ * 15:15 AR			Abort Receive
+ *				Set to 1 by the CPU to abort a receive SDMA
+ *				operation.  When the AR bit is set, the SDMA
+ *				aborts its current operation and moves to IDLE.
+ *				No descriptor is closed.  The AR bit is cleared
+ *				upon entering IDLE.  After setting the AR bit,
+ *				the CPU must poll the bit to verify that the
+ *				abort sequence is completed.
+ * 16:16 STDH			Stop TX High
+ *				Set to 1 by the CPU to stop the transmission
+ *				process from the high priority queue at the end
+ *				of the current frame. An interrupt is generated
+ *				when the stop command has been executed.
+ *				  Writing 1 to STDH resets TXDH bit.
+ *				  Writing 0 to this bit has no effect.
+ * 17:17 STDL			Stop TX Low
+ *				Set to 1 by the CPU to stop the transmission
+ *				process from the low priority queue at the end
+ *				of the current frame. An interrupt is generated
+ *				when the stop command has been executed.
+ *				  Writing 1 to STDL resets TXDL bit.
+ *				  Writing 0 to this bit has no effect.
+ * 22:18 Reserved
+ * 23:23 TXDH			Start Tx High
+ *				Set to 1 by the CPU to cause the SDMA to fetch
+ *				the first descriptor and start a transmit
+ *				process from the high priority Tx queue.
+ *				  Writing 1 to TXDH resets STDH bit.
+ *				  Writing 0 to this bit has no effect.
+ * 24:24 TXDL			Start Tx Low
+ *				Set to 1 by the CPU to cause the SDMA to fetch
+ *				the first descriptor and start a transmit
+ *				process from the low priority Tx queue.
+ *				  Writing 1 to TXDL resets STDL bit.
+ *				  Writing 0 to this bit has no effect.
+ * 30:25 Reserved
+ * 31:31 AT			Abort Transmit
+ *				Set to 1 by the CPU to abort a transmit DMA
+ *				operation.  When the AT bit is set, the SDMA
+ *				aborts its current operation and moves to IDLE.
+ *				No descriptor is closed.  Cleared upon entering
+ *				IDLE.  After setting AT bit, the CPU must poll
+ *				it in order to verify that the abort sequence
+ *				is completed.
+ */
+#define	ETH_ESDCMR_ERD			ETH__BIT(7)
+#define	ETH_ESDCMR_AR			ETH__BIT(15)
+#define	ETH_ESDCMR_STDH			ETH__BIT(16)
+#define	ETH_ESDCMR_STDL			ETH__BIT(17)
+#define	ETH_ESDCMR_TXDH			ETH__BIT(23)
+#define	ETH_ESDCMR_TXDL			ETH__BIT(24)
+#define	ETH_ESDCMR_AT			ETH__BIT(31)
+
+/*
+ * Table 607: Interrupt Cause Register (ICR)
+ * 00:00 RxBuffer		Rx Buffer Return
+ *				Indicates an Rx buffer returned to CPU ownership
+ *				or that the port finished reception of a Rx
+ *				frame in either priority queues.
+ *				NOTE: In order to get a Rx Buffer return per
+ *				      priority queue, use bit 19:16. This bit is
+ *				      set upon closing any Rx descriptor which
+ *				      has its EI bit set. To limit the
+ *				      interrupts to frame (rather than buffer)
+ *				      boundaries, the user must set SDMA
+ *				      Configuration register's RIFB bit. When
+ *				      the RIFB bit is set, an interrupt
+ *				      generates only upon closing the first
+ *				      descriptor of a received packet, if this
+ *				      descriptor has it EI bit set.
+ * 01:01 Reserved
+ * 02:02 TxBufferHigh		Tx Buffer for High priority Queue
+ *				Indicates a Tx buffer returned to CPU ownership
+ *				or that the port finished transmission of a Tx
+ *				frame.
+ *				NOTE: This bit is set upon closing any Tx
+ *				      descriptor which has its EI bit set. To
+ *				      limit the interrupts to frame (rather than
+ *				      buffer) boundaries, the user must set EI
+ *				      only in the last descriptor.
+ * 03:03 TxBufferLow		Tx Buffer for Low Priority Queue
+ *				Indicates a Tx buffer returned to CPU ownership
+ *				or that the port finished transmission of a Tx
+ *				frame.
+ *				NOTE: This bit is set upon closing any Tx
+ *				      descriptor which has its EI bit set. To
+ *				      limit the interrupts to frame (rather than
+ *				      buffer) boundaries, the user must set EI
+ *				      only in the last descriptor.
+ * 05:04 Reserved
+ * 06:06 TxEndHigh		Tx End for High Priority Queue
+ *				Indicates that the Tx DMA stopped processing the
+ *				high priority queue after stop command, or that
+ *				it reached the end of the high priority
+ *				descriptor chain.
+ * 07:07 TxEndLow		Tx End for Low Priority Queue
+ *				Indicates that the Tx DMA stopped processing the
+ *				low priority queue after stop command, or that
+ *				it reached the end of the low priority
+ *				descriptor chain.
+ * 08:08 RxError		Rx Resource Error
+ *				Indicates a Rx resource error event in one of
+ *				the priority queues.
+ *				NOTE: To get a Rx Resource Error Indication per
+ *				      priority queue, use bit 23:20.
+ * 09:09 Reserved
+ * 10:10 TxErrorHigh		Tx Resource Error for High Priority Queue
+ *				Indicates a Tx resource error event during
+ *				packet transmission from the high priority queue
+ * 11:11 TxErrorLow		Tx Resource Error for Low Priority Queue
+ *				Indicates a Tx resource error event during
+ *				packet transmission from the low priority queue
+ * 12:12 RxOVR			Rx Overrun
+ *				Indicates an overrun event that occurred during
+ *				reception of a packet.
+ * 13:13 TxUdr			Tx Underrun
+ *				Indicates an underrun event that occurred during
+ *				transmission of packet from either queue.
+ * 15:14 Reserved
+ * 16:16 RxBuffer-Queue[0]	Rx Buffer Return in Priority Queue[0]
+ *				Indicates a Rx buffer returned to CPU ownership
+ *				or that the port completed reception of a Rx
+ *				frame in a receive priority queue[0]
+ * 17:17 RxBuffer-Queue[1]	Rx Buffer Return in Priority Queue[1]
+ *				Indicates a Rx buffer returned to CPU ownership
+ *				or that the port completed reception of a Rx
+ *				frame in a receive priority queue[1].
+ * 18:18 RxBuffer-Queue[2]	Rx Buffer Return in Priority Queue[2]
+ *				Indicates a Rx buffer returned to CPU ownership
+ *				or that the port completed reception of a Rx
+ *				frame in a receive priority queue[2].
+ * 19:19 RxBuffer-Queue[3]	Rx Buffer Return in Priority Queue[3]
+ *				Indicates a Rx buffer returned to CPU ownership
+ *				or that the port completed reception of a Rx
+ *				frame in a receive priority queue[3].
+ * 20:20 RxError-Queue[0]	Rx Resource Error in Priority Queue[0]
+ *				Indicates a Rx resource error event in receive
+ *				priority queue[0].
+ * 21:21 RxError-Queue[1]	Rx Resource Error in Priority Queue[1]
+ *				Indicates a Rx resource error event in receive
+ *				priority queue[1].
+ * 22:22 RxError-Queue[2]	Rx Resource Error in Priority Queue[2]
+ *				Indicates a Rx resource error event in receive
+ *				priority queue[2].
+ * 23:23 RxError-Queue[3]	Rx Resource Error in Priority Queue[3]
+ *				Indicates a Rx resource error event in receive
+ *				priority queue[3].
+ * 27:24 Reserved
+ * 28:29 MIIPhySTC		MII PHY Status Change
+ *				Indicates a status change reported by the PHY
+ *				connected to this port.  Set when the MII
+ *				management interface block identifies a change
+ *				in PHY's register 1.
+ * 29:29 SMIdone		SMI Command Done
+ *				Indicates that the SMI completed a MII
+ *				management command (either read or write) that
+ *				was initiated by the CPU writing to the SMI
+ *				register.
+ * 30:30 Reserved
+ * 31:31 EtherIntSum		Ethernet Interrupt Summary
+ *				This bit is a logical OR of the (unmasked) bits
+ *				[30:04] in the Interrupt Cause register.
+ */
+
+#define	ETH_IR_RxBuffer		ETH__BIT(0)
+#define	ETH_IR_TxBufferHigh	ETH__BIT(2)
+#define	ETH_IR_TxBufferLow	ETH__BIT(3)
+#define	ETH_IR_TxEndHigh	ETH__BIT(6)
+#define	ETH_IR_TxEndLow		ETH__BIT(7)
+#define	ETH_IR_RxError		ETH__BIT(8)
+#define	ETH_IR_TxErrorHigh	ETH__BIT(10)
+#define	ETH_IR_TxErrorLow	ETH__BIT(11)
+#define	ETH_IR_RxOVR		ETH__BIT(12)
+#define	ETH_IR_TxUdr		ETH__BIT(13)
+#define	ETH_IR_RxBuffer_0	ETH__BIT(16)
+#define	ETH_IR_RxBuffer_1	ETH__BIT(17)
+#define	ETH_IR_RxBuffer_2	ETH__BIT(18)
+#define	ETH_IR_RxBuffer_3	ETH__BIT(19)
+#define	ETH_IR_RxBuffer_GET(v)	ETH__EXT(v, 16, 4)
+#define	ETH_IR_RxError_0	ETH__BIT(20)
+#define	ETH_IR_RxError_1	ETH__BIT(21)
+#define	ETH_IR_RxError_2	ETH__BIT(22)
+#define	ETH_IR_RxError_3	ETH__BIT(23)
+#define	ETH_IR_RxError_GET(v)	ETH__EXT(v, 20, 4)
+#define	ETH_IR_RxBits		(ETH_IR_RxBuffer_0|\
+				 ETH_IR_RxBuffer_1|\
+				 ETH_IR_RxBuffer_2|\
+				 ETH_IR_RxBuffer_3|\
+				 ETH_IR_RxError_0|\
+				 ETH_IR_RxError_1|\
+				 ETH_IR_RxError_2|\
+				 ETH_IR_RxError_3)
+#define	ETH_IR_MIIPhySTC	ETH__BIT(28)
+#define	ETH_IR_SMIdone		ETH__BIT(29)
+#define	ETH_IR_EtherIntSum	ETH__BIT(31)
+#define	ETH_IR_Summary		ETH__BIT(31)
+
+/*
+ * Table 608: Interrupt Mask Register (IMR)
+ * 31:00 Various		Mask bits for the Interrupt Cause register.
+ */
+
+/*
+ * Table 609: IP Differentiated Services CodePoint to Priority0 low (DSCP2P0L),
+ * 31:00 Priority0_low		The LSB priority bits for DSCP[31:0] entries.
+ */
+
+/*
+ * Table 610: IP Differentiated Services CodePoint to Priority0 high (DSCP2P0H)
+ * 31:00 Priority0_high		The LSB priority bits for DSCP[63:32] entries.
+ */
+
+/*
+ * Table 611: IP Differentiated Services CodePoint to Priority1 low (DSCP2P1L)
+ * 31:00 Priority1_low		The MSB priority bits for DSCP[31:0] entries.
+ */
+
+/*
+ * Table 612: IP Differentiated Services CodePoint to Priority1 high (DSCP2P1H)
+ * 31:00 Priority1_high		The MSB priority bit for DSCP[63:32] entries.
+ */
+
+/*
+ * Table 613: VLAN Priority Tag to Priority (VPT2P)
+ * 07:00 Priority0		The LSB priority bits for VLAN Priority[7:0]
+ *				entries.
+ * 15:08 Priority1		The MSB priority bits for VLAN Priority[7:0]
+ *				entries.
+ * 31:16 Reserved
+ */
+
+/* Address control registers -- these are offsets from the GT base
+ * and NOT from the ethernet port base. <tss>
+ */
+#define	ETH_ACTL_0_LO	0xf200
+
+/* Enable hardware cache snooping;
+ * Copyright Shuchen K. Feng <feng1@bnl.gov>, 2004
+ */
+
+/* Ethernet address control (Low) snoop bits */
+#define RxBSnoopEn      ETH__BIT(6)     /* Rx buffer snoop enable,1=enable*/
+#define TxBSnoopEn      ETH__BIT(14)    /* Tx buffer snoop enable */
+#define RxDSnoopEn      ETH__BIT(22)    /* Rx descriptor snoop enable */
+#define TxDSnoopEn      ETH__BIT(30)    /* Tx descriptor snoop enable */
+
+#define	ETH_ACTL_0_HI	0xf204
+/* Ethernet address control (High),  snoop bits */
+#define HashSnoopEn     ETH__BIT(6)     /* Hash Table snoop enable */
+
+
+#define	ETH_ACTL_1_LO	0xf220
+#define	ETH_ACTL_1_HI	0xf224
+#define	ETH_ACTL_2_LO	0xf240
+#define	ETH_ACTL_2_HI	0xf244
+
+
+#endif /* _DEV_GTETHREG_H_ */
Index: bsps/powerpc/beatnik/net/if_gfe/gtvar.h
===================================================================
--- bsps/powerpc/beatnik/net/if_gfe/gtvar.h	(revision 031df3914990db0336a0d386fb53558b05de467e)
+++ bsps/powerpc/beatnik/net/if_gfe/gtvar.h	(revision 031df3914990db0336a0d386fb53558b05de467e)
@@ -0,0 +1,170 @@
+/*	$NetBSD: gtvar.h,v 1.7.4.1 2005/04/29 11:28:56 kent Exp $	*/
+
+/*
+ * Copyright (c) 2002 Allegro Networks, Inc., Wasabi Systems, Inc.
+ * 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. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed for the NetBSD Project by
+ *      Allegro Networks, Inc., and Wasabi Systems, Inc.
+ * 4. The name of Allegro Networks, Inc. may not be used to endorse
+ *    or promote products derived from this software without specific prior
+ *    written permission.
+ * 5. The name of Wasabi Systems, Inc. may not be used to endorse
+ *    or promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ALLEGRO NETWORKS, INC. AND
+ * WASABI SYSTEMS, INC. ``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 EITHER ALLEGRO NETWORKS, INC. OR WASABI SYSTEMS, INC.
+ * 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.
+ */
+
+/*
+ * gtvar.h -- placeholder for GT system controller driver
+ */
+#ifndef _DISCOVERY_DEV_GTVAR_H_
+#define	_DISCOVERY_DEV_GTVAR_H_
+
+#include <sys/systm.h>
+
+struct gt_softc {
+#ifndef __rtems__
+	struct device gt_dev;
+	bus_dma_tag_t gt_dmat;
+	bus_space_tag_t gt_memt;	/* the GT itself */
+	bus_space_tag_t gt_pci0_memt;	/* PCI0 mem space */
+	bus_space_tag_t gt_pci0_iot;	/* PCI0 i/o space */
+	boolean_t gt_pci0_host;		/* We're host on PCI0 if TRUE */
+	bus_space_tag_t gt_pci1_memt;	/* PCI1 mem space */
+	bus_space_tag_t gt_pci1_iot;	/* PCI1 i/o space */
+	boolean_t gt_pci1_host;		/* We're host on PCI1 if TRUE */
+
+	bus_space_handle_t gt_memh;	/* to access the GT registers */
+#else
+	unsigned			gt_memh;
+#endif
+	int gt_childmask;		/* what children are present */
+};
+
+#define	GT_CHILDOK(gt, ga, cd, pos, max) \
+	(((ga)->ga_unit) < (max) &&  \
+	    !((gt)->gt_childmask & (1 << (((ga)->ga_unit) + (pos)))) && \
+	    !strcmp((ga)->ga_name, (cd)->cd_name))
+
+#define	GT_MPSCOK(gt, ga, cd)		GT_CHILDOK((gt), (ga), (cd), 0, 2)
+#define	GT_PCIOK(gt, ga, cd)		GT_CHILDOK((gt), (ga), (cd), 2, 2)
+#define	GT_ETHEROK(gt, ga, cd)		GT_CHILDOK((gt), (ga), (cd), 4, 3)
+#define	GT_OBIOOK(gt, ga, cd)		GT_CHILDOK((gt), (ga), (cd), 7, 5)
+#define	GT_I2COK(gt, ga, cd)		GT_CHILDOK((gt), (ga), (cd), 12, 1)
+
+#define	GT_CHILDFOUND(gt, ga, pos) \
+	((void)(((gt)->gt_childmask |= (1 << (((ga)->ga_unit) + (pos))))))
+
+#define	GT_MPSCFOUND(gt, ga)		GT_CHILDFOUND((gt), (ga), 0)
+#define	GT_PCIFOUND(gt, ga)		GT_CHILDFOUND((gt), (ga), 2)
+#define	GT_ETHERFOUND(gt, ga)		GT_CHILDFOUND((gt), (ga), 4)
+#define	GT_OBIOFOUND(gt, ga)		GT_CHILDFOUND((gt), (ga), 7)
+#define	GT_I2CFOUND(gt, ga)		GT_CHILDFOUND((gt), (ga), 12)
+
+#ifndef __rtems__
+struct gt_attach_args {
+	const char *ga_name;		/* class name of device */
+	bus_dma_tag_t ga_dmat;		/* dma tag */
+	bus_space_tag_t ga_memt;	/* GT bus space tag */
+	bus_space_handle_t ga_memh;	/* GT bus space handle */
+	int ga_unit;			/* instance of ga_name */
+};
+
+struct obio_attach_args {
+	const char *oa_name;		/* call name of device */
+	bus_space_tag_t oa_memt;	/* bus space tag */
+	bus_addr_t oa_offset;		/* offset (absolute) to device */
+	bus_size_t oa_size;		/* size (strided) of device */
+	int oa_irq;			/* irq */
+};
+#endif
+
+#ifdef _KERNEL
+#ifndef __rtems__
+#include "locators.h"
+#endif
+
+#ifdef DEBUG
+extern int gtpci_debug;
+#endif
+
+/*
+ * Locators for GT private devices, as specified to config.
+ */
+#define	GT_UNK_UNIT		GTCF_UNIT_DEFAULT	/* wcarded 'function' */
+
+#define	OBIO_UNK_OFFSET		OBIOCF_OFFSET_DEFAULT	/* wcarded 'offset' */
+
+#define	OBIO_UNK_SIZE		OBIOCF_SIZE_DEFAULT	/* wcarded 'size' */
+
+#define	OBIO_UNK_IRQ		OBIOCF_IRQ_DEFAULT	/* wcarded 'irq' */
+
+void	gt_attach_common(struct gt_softc *);
+uint32_t gt_read_mpp(void);
+int	gt_cfprint(void *, const char *);
+
+#ifndef __rtems__
+/* int     gt_bs_extent_init(struct discovery_bus_space *, char *);  AKB */
+int	gt_mii_read(struct device *, struct device *, int, int);
+void	gt_mii_write(struct device *, struct device *, int, int, int);
+int	gtget_macaddr(struct gt_softc *,int, char *);
+
+void	gt_watchdog_service(void);
+bus_addr_t gt_dma_phys_to_bus_mem(bus_dma_tag_t, bus_addr_t);
+bus_addr_t gt_dma_bus_mem_to_phys(bus_dma_tag_t, bus_addr_t);
+
+#define	gt_read(gt,o) \
+	bus_space_read_4((gt)->gt_memt, (gt)->gt_memh, (o))
+#define	gt_write(gt,o,v) \
+	bus_space_write_4((gt)->gt_memt, (gt)->gt_memh, (o), (v))
+#else
+#endif
+
+#if defined(__powerpc__)
+static __inline volatile int
+atomic_add(volatile int *p, int	v)
+{
+	int	rv;
+	int	rtmp;
+
+	__asm __volatile(
+	"1:	lwarx	%0,0,%3\n"
+	"	add	%1,%4,%0\n"
+	"	stwcx.	%1,0,%3\n"
+	"	bne-	1b\n"
+	"	sync"
+			: "=&r"(rv), "=&r"(rtmp), "=m"(*p)
+			: "r"(p), "r"(v), "m"(*p)
+			: "cc");
+
+	return rv;
+}
+
+#endif /* __powerpc__ */
+
+#endif /* _KERNEL */
+
+#endif /* _DISCOVERY_DEV_GTVAR_H_ */
Index: bsps/powerpc/beatnik/net/if_gfe/if_gfe.c
===================================================================
--- bsps/powerpc/beatnik/net/if_gfe/if_gfe.c	(revision 031df3914990db0336a0d386fb53558b05de467e)
+++ bsps/powerpc/beatnik/net/if_gfe/if_gfe.c	(revision 031df3914990db0336a0d386fb53558b05de467e)
@@ -0,0 +1,2649 @@
+/*	$NetBSD: if_gfe.c,v 1.13.8.1 2005/04/29 11:28:56 kent Exp $	*/
+
+/*
+ * Copyright (c) 2002 Allegro Networks, Inc., Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Copyright 2004: Enable hardware cache snooping. Kate Feng <feng1@bnl.gov>
+ *
+ * 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. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed for the NetBSD Project by
+ *      Allegro Networks, Inc., and Wasabi Systems, Inc.
+ * 4. The name of Allegro Networks, Inc. may not be used to endorse
+ *    or promote products derived from this software without specific prior
+ *    written permission.
+ * 5. The name of Wasabi Systems, Inc. may not be used to endorse
+ *    or promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ALLEGRO NETWORKS, INC. AND
+ * WASABI SYSTEMS, INC. ``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 EITHER ALLEGRO NETWORKS, INC. OR WASABI SYSTEMS, INC.
+ * 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.
+ */
+
+/*
+ * if_gfe.c -- GT ethernet MAC driver
+ */
+
+/* Enable hardware cache snooping;
+ * Copyright Shuchen K. Feng <feng1@bnl.gov>, 2004
+ */
+
+#ifdef __rtems__
+#include "rtemscompat_defs.h"
+#include "../porting/rtemscompat.h"
+#include <string.h>
+#include <stdio.h>
+#include <inttypes.h>
+#endif
+
+#include <sys/cdefs.h>
+#ifndef __rtems__
+__KERNEL_RCSID(0, "$NetBSD: if_gfe.c,v 1.13.8.1 2005/04/29 11:28:56 kent Exp $");
+
+#include "opt_inet.h"
+#include "bpfilter.h"
+#endif
+
+#include <sys/param.h>
+#include <sys/types.h>
+#ifndef __rtems__
+#include <sys/inttypes.h>
+#include <sys/queue.h>
+#endif
+
+#ifndef __rtems__
+#include <uvm/uvm_extern.h>
+
+#include <sys/callout.h>
+#include <sys/device.h>
+#endif
+#include <sys/errno.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+
+#ifndef __rtems__
+#include <machine/bus.h>
+#endif
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#ifndef __rtems__
+#include <net/if_ether.h>
+#else
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <net/ethernet.h>
+#include <rtems/rtems_mii_ioctl.h>
+#endif
+
+#ifdef INET
+#include <netinet/in.h>
+#ifndef __rtems__
+#include <netinet/if_inarp.h>
+#endif
+#endif
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#endif
+
+#ifndef __rtems__
+#include <dev/mii/miivar.h>
+
+#include <dev/marvell/gtintrreg.h>
+#include <dev/marvell/gtethreg.h>
+
+#include <dev/marvell/gtvar.h>
+#include <dev/marvell/if_gfevar.h>
+#else
+#include	<bsp/gtintrreg.h>
+#include	<bsp/gtreg.h>
+#include	"gtethreg.h"
+
+#include	"gtvar.h"
+#include	"if_gfevar.h"
+#include 	"../porting/rtemscompat1.h"
+#define		ether_sprintf ether_sprintf_macro
+#endif
+
+#define	GE_READ(sc, reg) \
+	bus_space_read_4((sc)->sc_gt_memt, (sc)->sc_memh, ETH__ ## reg)
+#define	GE_WRITE(sc, reg, v) \
+	bus_space_write_4((sc)->sc_gt_memt, (sc)->sc_memh, ETH__ ## reg, (v))
+
+#define	GT_READ(sc, reg) \
+	bus_space_read_4((sc)->sc_gt_memt, (sc)->sc_gt_memh, reg)
+#define	GT_WRITE(sc, reg, v) \
+	bus_space_write_4((sc)->sc_gt_memt, (sc)->sc_gt_memh, reg, (v))
+
+#define	GE_DEBUG
+#if 0
+#define	GE_NOHASH
+#define	GE_NORX
+#endif
+
+#ifdef GE_DEBUG
+#define	GE_DPRINTF(sc, a)	do \
+				  if ((sc)->sc_ec.ec_if.if_flags & IFF_DEBUG) \
+				    printf a; \
+				while (0)
+#define	GE_FUNC_ENTER(sc, func)	GE_DPRINTF(sc, ("[" func))
+#define	GE_FUNC_EXIT(sc, str)	GE_DPRINTF(sc, (str "]"))
+#else
+#define	GE_DPRINTF(sc, a)	do { } while (0)
+#define	GE_FUNC_ENTER(sc, func)	do { } while (0)
+#define	GE_FUNC_EXIT(sc, str)	do { } while (0)
+#endif
+enum gfe_whack_op {
+	GE_WHACK_START,		GE_WHACK_RESTART,
+	GE_WHACK_CHANGE,	GE_WHACK_STOP
+};
+
+enum gfe_hash_op {
+	GE_HASH_ADD,		GE_HASH_REMOVE,
+};
+
+
+#if 1
+#define	htogt32(a)		htobe32(a)
+#define	gt32toh(a)		be32toh(a)
+#else
+#define	htogt32(a)		htole32(a)
+#define	gt32toh(a)		le32toh(a)
+#endif
+
+#ifdef __rtems__
+#define htobe32 htonl
+#define be32toh ntohl
+#endif
+
+#define GE_RXDSYNC(sc, rxq, n, ops) \
+	bus_dmamap_sync((sc)->sc_dmat, (rxq)->rxq_desc_mem.gdm_map, \
+	    (n) * sizeof((rxq)->rxq_descs[0]), sizeof((rxq)->rxq_descs[0]), \
+	    (ops))
+#define	GE_RXDPRESYNC(sc, rxq, n) \
+	GE_RXDSYNC(sc, rxq, n, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE)
+#define	GE_RXDPOSTSYNC(sc, rxq, n) \
+	GE_RXDSYNC(sc, rxq, n, BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE)
+
+#define GE_TXDSYNC(sc, txq, n, ops) \
+	bus_dmamap_sync((sc)->sc_dmat, (txq)->txq_desc_mem.gdm_map, \
+	    (n) * sizeof((txq)->txq_descs[0]), sizeof((txq)->txq_descs[0]), \
+	    (ops))
+#define	GE_TXDPRESYNC(sc, txq, n) \
+	GE_TXDSYNC(sc, txq, n, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE)
+#define	GE_TXDPOSTSYNC(sc, txq, n) \
+	GE_TXDSYNC(sc, txq, n, BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE)
+
+#define	STATIC
+
+#ifndef __rtems__
+STATIC int gfe_match (struct device *, struct cfdata *, void *);
+STATIC void gfe_attach (struct device *, struct device *, void *);
+#else
+STATIC int gfe_probe (device_t);
+STATIC int gfe_attach (device_t);
+STATIC void gfe_init (void*);
+#endif
+
+STATIC int gfe_dmamem_alloc(struct gfe_softc *, struct gfe_dmamem *, int,
+	size_t, int);
+STATIC void gfe_dmamem_free(struct gfe_softc *, struct gfe_dmamem *);
+
+#ifndef __rtems__
+STATIC int gfe_ifioctl (struct ifnet *, u_long, caddr_t);
+#else
+STATIC int gfe_ifioctl (struct ifnet *, ioctl_command_t, caddr_t);
+#endif
+STATIC void gfe_ifstart (struct ifnet *);
+STATIC void gfe_ifwatchdog (struct ifnet *);
+
+#ifndef __rtems__
+STATIC int gfe_mii_mediachange (struct ifnet *);
+STATIC void gfe_mii_mediastatus (struct ifnet *, struct ifmediareq *);
+STATIC int gfe_mii_read (struct device *, int, int);
+STATIC void gfe_mii_write (struct device *, int, int, int);
+STATIC void gfe_mii_statchg (struct device *);
+#endif
+
+STATIC void gfe_tick(void *arg);
+
+STATIC void gfe_tx_restart(void *);
+STATIC int gfe_tx_enqueue(struct gfe_softc *, enum gfe_txprio);
+STATIC uint32_t gfe_tx_done(struct gfe_softc *, enum gfe_txprio, uint32_t);
+STATIC void gfe_tx_cleanup(struct gfe_softc *, enum gfe_txprio, int);
+STATIC int gfe_tx_txqalloc(struct gfe_softc *, enum gfe_txprio);
+STATIC int gfe_tx_start(struct gfe_softc *, enum gfe_txprio);
+STATIC void gfe_tx_stop(struct gfe_softc *, enum gfe_whack_op);
+
+STATIC void gfe_rx_cleanup(struct gfe_softc *, enum gfe_rxprio);
+STATIC void gfe_rx_get(struct gfe_softc *, enum gfe_rxprio);
+STATIC int gfe_rx_prime(struct gfe_softc *);
+STATIC uint32_t gfe_rx_process(struct gfe_softc *, uint32_t, uint32_t);
+STATIC int gfe_rx_rxqalloc(struct gfe_softc *, enum gfe_rxprio);
+STATIC int gfe_rx_rxqinit(struct gfe_softc *, enum gfe_rxprio);
+STATIC void gfe_rx_stop(struct gfe_softc *, enum gfe_whack_op);
+
+STATIC int gfe_intr(void *);
+
+STATIC int gfe_whack(struct gfe_softc *, enum gfe_whack_op);
+
+STATIC int gfe_hash_compute(struct gfe_softc *, const uint8_t [ETHER_ADDR_LEN]);
+STATIC int gfe_hash_entry_op(struct gfe_softc *, enum gfe_hash_op,
+	enum gfe_rxprio, const uint8_t [ETHER_ADDR_LEN]);
+#ifndef __rtems__
+STATIC int gfe_hash_multichg(struct ethercom *, const struct ether_multi *,
+	u_long);
+#endif
+STATIC int gfe_hash_fill(struct gfe_softc *);
+STATIC int gfe_hash_alloc(struct gfe_softc *);
+
+#ifndef __rtems__
+/* Linkup to the rest of the kernel */
+CFATTACH_DECL(gfe, sizeof(struct gfe_softc),
+    gfe_match, gfe_attach, NULL, NULL);
+#else
+net_drv_tbl_t METHODS = {
+    n_probe  : gfe_probe,
+    n_attach : gfe_attach,
+    n_detach : 0,
+    n_intr   : (void (*)(void*))gfe_intr,
+};
+
+int
+gfe_mii_read(int phy, void *arg, unsigned reg, uint32_t *pval);
+int
+gfe_mii_write(int phy, void *arg, unsigned reg, uint32_t val);
+
+struct rtems_mdio_info
+gfe_mdio_access = {
+	mdio_r:	gfe_mii_read,
+	mdio_w:	gfe_mii_write,
+	has_gmii: 0
+};
+
+#endif
+
+extern struct cfdriver gfe_cd;
+
+#ifndef __rtems__
+int
+gfe_match(struct device *parent, struct cfdata *cf, void *aux)
+{
+	struct gt_softc *gt = (struct gt_softc *) parent;
+	struct gt_attach_args *ga = aux;
+	uint8_t enaddr[6];
+
+	if (!GT_ETHEROK(gt, ga, &gfe_cd))
+		return 0;
+
+	if (gtget_macaddr(gt, ga->ga_unit, enaddr) < 0)
+		return 0;
+
+	if (enaddr[0] == 0 && enaddr[1] == 0 && enaddr[2] == 0 &&
+	    enaddr[3] == 0 && enaddr[4] == 0 && enaddr[5] == 0)
+		return 0;
+
+	return 1;
+}
+#else
+int
+gfe_probe(device_t dev)
+{
+	switch ( BSP_getDiscoveryVersion(0) ) {
+		case GT_64260_A:
+		case GT_64260_B:
+			return 0;
+		default:
+			break;
+	}
+	return -1;
+}
+
+void
+gfe_init(void *arg)
+{
+struct gfe_softc *sc = arg;
+	if ( sc->sc_ec.ec_if.if_flags & IFF_RUNNING )
+		gfe_whack(sc, GE_WHACK_RESTART);
+	else
+		gfe_whack(sc, GE_WHACK_START);
+}
+#endif
+
+/*
+ * Attach this instance, and then all the sub-devices
+ */
+#ifndef __rtems__
+void
+gfe_attach(struct device *parent, struct device *self, void *aux)
+#else
+int
+gfe_attach(device_t dev)
+#endif
+{
+#ifndef __rtems__
+	struct gt_attach_args * const ga = aux;
+	struct gt_softc * const gt = (struct gt_softc *) parent;
+	struct gfe_softc * const sc = (struct gfe_softc *) self;
+#else
+	struct gfe_softc * const sc = device_get_softc(dev);
+#endif
+	struct ifnet * const ifp = &sc->sc_ec.ec_if;
+	uint32_t data;
+	uint8_t enaddr[6];
+	int phyaddr;
+	uint32_t sdcr;
+	int error;
+#ifdef __rtems__
+	SPRINTFVARDECL;
+#endif
+
+#ifndef __rtems__
+	GT_ETHERFOUND(gt, ga);
+
+	sc->sc_gt_memt = ga->ga_memt;
+	sc->sc_gt_memh = ga->ga_memh;
+	sc->sc_dmat = ga->ga_dmat;
+	sc->sc_macno = ga->ga_unit;
+
+	if (bus_space_subregion(sc->sc_gt_memt, sc->sc_gt_memh,
+		    ETH_BASE(sc->sc_macno), ETH_SIZE, &sc->sc_memh)) {
+		aprint_error(": failed to map registers\n");
+	}
+	
+	callout_init(&sc->sc_co);
+#else
+	/* sc_macno, irq_no and sc_gt_memh must be filled in by 'setup' */
+
+	/* make ring sizes even numbers so that we have always multiple
+	 * cache lines (paranoia)
+	 */
+	if ( (sc->num_rxdesc = dev->d_ifconfig->rbuf_count) & 1 )
+		sc->num_rxdesc++;
+	if ( 0 == sc->num_rxdesc )
+		sc->num_rxdesc = 64;
+
+	if ( (sc->num_txdesc = dev->d_ifconfig->xbuf_count) & 1 )
+		sc->num_txdesc++;
+	if ( 0 == sc->num_txdesc )
+		sc->num_txdesc = 256;
+
+	/* Enable hardware cache snooping;
+         * Copyright Shuchen K. Feng <feng1@bnl.gov>, 2004
+         */
+	/* regs are eth0: 0xf200/0xf204, eth1 0xf220/0xf224, eth2: 0xf240/0xf244 */
+	{
+	uint32_t v;
+	v = GT_READ(sc, ETH_ACTL_0_LO + (sc->sc_macno<<5));
+	v |= RxBSnoopEn|TxBSnoopEn|RxDSnoopEn|TxDSnoopEn;
+	GT_WRITE(sc, ETH_ACTL_0_LO + (sc->sc_macno<<5), v);
+
+	v = GT_READ(sc, ETH_ACTL_0_HI + (sc->sc_macno<<5));
+	v |= HashSnoopEn;
+	GT_WRITE(sc, ETH_ACTL_0_HI + (sc->sc_macno<<5), v);
+	}
+
+#endif
+
+	data = bus_space_read_4(sc->sc_gt_memt, sc->sc_gt_memh, ETH_EPAR);
+#ifdef __rtems__
+	sc->sc_phyaddr =
+#endif
+	phyaddr = ETH_EPAR_PhyAD_GET(data, sc->sc_macno);
+
+#ifndef __rtems__
+	gtget_macaddr(gt, sc->sc_macno, enaddr);
+#else
+	memset( enaddr, 0, ETHER_ADDR_LEN );
+	if ( !memcmp(enaddr, sc->arpcom.ac_enaddr, ETHER_ADDR_LEN) ) {
+		aprint_error(": MAC address not set (pass to rtems_gfe_setup())\n");
+		return -1;
+	}
+	/* mac address needs to be provided by 'setup' */
+	memcpy(enaddr, sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
+#endif
+
+	sc->sc_pcr = GE_READ(sc, EPCR);
+	sc->sc_pcxr = GE_READ(sc, EPCXR);
+	sc->sc_intrmask = GE_READ(sc, EIMR) | ETH_IR_MIIPhySTC;
+
+	aprint_normal(": address %s", ether_sprintf(enaddr));
+
+#if defined(DEBUG)
+	aprint_normal(", pcr %#x, pcxr %#x", sc->sc_pcr, sc->sc_pcxr);
+#endif
+
+	sc->sc_pcxr &= ~ETH_EPCXR_PRIOrx_Override;
+#ifndef __rtems__
+	if (sc->sc_dev.dv_cfdata->cf_flags & 1) {
+		aprint_normal(", phy %d (rmii)", phyaddr);
+		sc->sc_pcxr |= ETH_EPCXR_RMIIEn;
+	} else
+#endif
+	{
+		aprint_normal(", phy %d (mii)", phyaddr);
+		sc->sc_pcxr &= ~ETH_EPCXR_RMIIEn;
+	}
+#ifndef __rtems__
+	if (sc->sc_dev.dv_cfdata->cf_flags & 2)
+		sc->sc_flags |= GE_NOFREE;
+#endif
+	sc->sc_pcxr &= ~(3 << 14);
+	sc->sc_pcxr |= (ETH_EPCXR_MFL_1536 << 14);
+
+	if (sc->sc_pcr & ETH_EPCR_EN) {
+		int tries = 1000;
+		/*
+		 * Abort transmitter and receiver and wait for them to quiese
+		 */
+		GE_WRITE(sc, ESDCMR, ETH_ESDCMR_AR|ETH_ESDCMR_AT);
+		do {
+			delay(100);
+		} while (tries-- > 0 && (GE_READ(sc, ESDCMR) & (ETH_ESDCMR_AR|ETH_ESDCMR_AT)));
+	}
+
+	sc->sc_pcr &= ~(ETH_EPCR_EN | ETH_EPCR_RBM | ETH_EPCR_PM | ETH_EPCR_PBF);
+
+#if defined(DEBUG)
+	aprint_normal(", pcr %#x, pcxr %#x", sc->sc_pcr, sc->sc_pcxr);
+#endif
+
+	/*
+	 * Now turn off the GT.  If it didn't quiese, too ***ing bad.
+	 */
+	GE_WRITE(sc, EPCR, sc->sc_pcr);
+#ifndef __rtems__
+	GE_WRITE(sc, EIMR, sc->sc_intrmask);
+#else
+	GE_WRITE(sc, EICR, 0);
+	GE_WRITE(sc, EIMR, 0);
+#endif
+	sdcr = GE_READ(sc, ESDCR);
+	ETH_ESDCR_BSZ_SET(sdcr, ETH_ESDCR_BSZ_4);
+	sdcr |= ETH_ESDCR_RIFB;
+	GE_WRITE(sc, ESDCR, sdcr);
+	sc->sc_max_frame_length = 1536;
+
+	aprint_normal("\n");
+#ifndef __rtems__
+	sc->sc_mii.mii_ifp = ifp;
+	sc->sc_mii.mii_readreg = gfe_mii_read;
+	sc->sc_mii.mii_writereg = gfe_mii_write;
+	sc->sc_mii.mii_statchg = gfe_mii_statchg;
+
+	ifmedia_init(&sc->sc_mii.mii_media, 0, gfe_mii_mediachange,
+		gfe_mii_mediastatus);
+
+	mii_attach(&sc->sc_dev, &sc->sc_mii, 0xffffffff, phyaddr,
+		MII_OFFSET_ANY, MIIF_NOISOLATE);
+	if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) {
+		ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER|IFM_NONE, 0, NULL);
+		ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_NONE);
+	} else {
+		ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_AUTO);
+	}
+
+	strcpy(ifp->if_xname, sc->sc_dev.dv_xname);
+#else
+	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
+	ifp->if_mtu   = ETHERMTU;
+	ifp->if_output = ether_output;
+	ifp->if_init   = gfe_init;
+	ifp->if_snd.ifq_maxlen = GE_TXDESC_MAX - 1;
+	ifp->if_baudrate = 10000000;
+#endif
+	ifp->if_softc = sc;
+	/* ifp->if_mowner = &sc->sc_mowner; */
+	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+#if 0
+	ifp->if_flags |= IFF_DEBUG;
+#endif
+	ifp->if_ioctl = gfe_ifioctl;
+	ifp->if_start = gfe_ifstart;
+	ifp->if_watchdog = gfe_ifwatchdog;
+
+	if (sc->sc_flags & GE_NOFREE) {
+		error = gfe_rx_rxqalloc(sc, GE_RXPRIO_HI);
+		if (!error)
+			error = gfe_rx_rxqalloc(sc, GE_RXPRIO_MEDHI);
+		if (!error)
+			error = gfe_rx_rxqalloc(sc, GE_RXPRIO_MEDLO);
+		if (!error)
+			error = gfe_rx_rxqalloc(sc, GE_RXPRIO_LO);
+		if (!error)
+			error = gfe_tx_txqalloc(sc, GE_TXPRIO_HI);
+		if (!error)
+			error = gfe_hash_alloc(sc);
+		if (error)
+			aprint_error(
+			    "%s: failed to allocate resources: %d\n",
+			    ifp->if_xname, error);
+	}
+
+	if_attach(ifp);
+#ifndef __rtems__
+	ether_ifattach(ifp, enaddr);
+#else
+	ether_ifattach(ifp);
+#endif
+#if NBPFILTER > 0
+	bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));
+#endif
+#if NRND > 0
+	rnd_attach_source(&sc->sc_rnd_source, self->dv_xname, RND_TYPE_NET, 0);
+#endif
+#ifndef __rtems__
+	intr_establish(IRQ_ETH0 + sc->sc_macno, IST_LEVEL, IPL_NET,
+	    gfe_intr, sc);
+#else
+	return 0;
+#endif
+}
+
+int
+gfe_dmamem_alloc(struct gfe_softc *sc, struct gfe_dmamem *gdm, int maxsegs,
+	size_t size, int flags)
+{
+	int error = 0;
+	GE_FUNC_ENTER(sc, "gfe_dmamem_alloc");
+
+	KASSERT(gdm->gdm_kva == NULL);
+	gdm->gdm_size = size;
+	gdm->gdm_maxsegs = maxsegs;
+
+#ifndef __rtems__
+	error = bus_dmamem_alloc(sc->sc_dmat, gdm->gdm_size, PAGE_SIZE,
+	    gdm->gdm_size, gdm->gdm_segs, gdm->gdm_maxsegs, &gdm->gdm_nsegs,
+	    BUS_DMA_NOWAIT);
+	if (error)
+		goto fail;
+
+	error = bus_dmamem_map(sc->sc_dmat, gdm->gdm_segs, gdm->gdm_nsegs,
+	    gdm->gdm_size, &gdm->gdm_kva, flags | BUS_DMA_NOWAIT);
+	if (error)
+		goto fail;
+
+	error = bus_dmamap_create(sc->sc_dmat, gdm->gdm_size, gdm->gdm_nsegs,
+	    gdm->gdm_size, 0, BUS_DMA_ALLOCNOW|BUS_DMA_NOWAIT, &gdm->gdm_map);
+	if (error)
+		goto fail;
+
+	error = bus_dmamap_load(sc->sc_dmat, gdm->gdm_map, gdm->gdm_kva,
+	    gdm->gdm_size, NULL, BUS_DMA_NOWAIT);
+	if (error)
+		goto fail;
+#else
+	gdm->gdm_segs[0].ds_len   = size;
+
+	/* FIXME: probably we can relax the alignment */
+	if ( ! ( gdm->gdm_unaligned_buf = malloc( size + PAGE_SIZE - 1, M_DEVBUF, M_NOWAIT ) ) )
+		goto fail;
+
+	gdm->gdm_map   = gdm;
+	gdm->gdm_nsegs = 1;
+	gdm->gdm_kva   = (caddr_t)(gdm->gdm_segs[0].ds_addr = _DO_ALIGN(gdm->gdm_unaligned_buf, PAGE_SIZE));
+#endif
+
+	/* invalidate from cache */
+	bus_dmamap_sync(sc->sc_dmat, gdm->gdm_map, 0, gdm->gdm_size,
+	    BUS_DMASYNC_PREREAD);
+fail:
+	if (error) {
+		gfe_dmamem_free(sc, gdm);
+		GE_DPRINTF(sc, (":err=%d", error));
+	}
+	GE_DPRINTF(sc, (":kva=%p/%#x,map=%p,nsegs=%d,pa=%" PRIx32 "/%" PRIx32,
+	    gdm->gdm_kva, gdm->gdm_size, gdm->gdm_map, gdm->gdm_map->dm_nsegs,
+	    gdm->gdm_map->dm_segs->ds_addr, gdm->gdm_map->dm_segs->ds_len));
+	GE_FUNC_EXIT(sc, "");
+	return error;
+}
+
+void
+gfe_dmamem_free(struct gfe_softc *sc, struct gfe_dmamem *gdm)
+{
+	GE_FUNC_ENTER(sc, "gfe_dmamem_free");
+#ifndef __rtems__
+	if (gdm->gdm_map)
+		bus_dmamap_destroy(sc->sc_dmat, gdm->gdm_map);
+	if (gdm->gdm_kva)
+		bus_dmamem_unmap(sc->sc_dmat, gdm->gdm_kva, gdm->gdm_size);
+	if (gdm->gdm_nsegs > 0)
+		bus_dmamem_free(sc->sc_dmat, gdm->gdm_segs, gdm->gdm_nsegs);
+#else
+	if (gdm->gdm_nsegs > 0)
+		free(gdm->gdm_unaligned_buf, M_DEVBUF);
+#endif
+	gdm->gdm_map = NULL;
+	gdm->gdm_kva = NULL;
+	gdm->gdm_nsegs = 0;
+	GE_FUNC_EXIT(sc, "");
+}
+
+#ifndef __rtems__
+int
+gfe_ifioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
+#else
+int
+gfe_ifioctl(struct ifnet *ifp, ioctl_command_t cmd, caddr_t data)
+#endif
+{
+	struct gfe_softc * const sc = ifp->if_softc;
+	struct ifreq *ifr = (struct ifreq *) data;
+#ifndef __rtems__
+	struct ifaddr *ifa = (struct ifaddr *) data;
+#endif
+	int s, error = 0;
+
+	GE_FUNC_ENTER(sc, "gfe_ifioctl");
+	s = splnet();
+
+	switch (cmd) {
+#ifndef __rtems__
+	case SIOCSIFADDR:
+		ifp->if_flags |= IFF_UP;
+		switch (ifa->ifa_addr->sa_family) {
+#ifdef INET
+		case AF_INET:
+			error = gfe_whack(sc, GE_WHACK_START);
+			if (error == 0)
+				arp_ifinit(ifp, ifa);
+			break;
+#endif
+		default:
+			error = gfe_whack(sc, GE_WHACK_START);
+			break;
+		}
+		break;
+#endif
+
+	case SIOCSIFFLAGS:
+		if ((sc->sc_ec.ec_if.if_flags & IFF_PROMISC) == 0)
+			sc->sc_pcr &= ~ETH_EPCR_PM;
+		else
+			sc->sc_pcr |=  ETH_EPCR_PM;
+		switch (ifp->if_flags & (IFF_UP|IFF_RUNNING)) {
+		case IFF_UP|IFF_RUNNING:/* active->active, update */
+			error = gfe_whack(sc, GE_WHACK_CHANGE);
+			break;
+		case IFF_RUNNING:	/* not up, so we stop */
+			error = gfe_whack(sc, GE_WHACK_STOP);
+			break;
+		case IFF_UP:		/* not running, so we start */
+			error = gfe_whack(sc, GE_WHACK_START);
+			break;
+		case 0:			/* idle->idle: do nothing */
+			break;
+		}
+		break;
+
+	case SIOCADDMULTI:
+	case SIOCDELMULTI:
+		error = (cmd == SIOCADDMULTI)
+		    ? ether_addmulti(ifr, &sc->sc_ec)
+		    : ether_delmulti(ifr, &sc->sc_ec);
+		if (error == ENETRESET) {
+			if (ifp->if_flags & IFF_RUNNING)
+#if !defined(__rtems__)
+				error = gfe_whack(sc, GE_WHACK_CHANGE);
+#else
+			/* doing GE_WHACK_CHANGE seems wrong - that
+			 * doesn't do anything to the hash table.
+			 * Therefore we perform a stop/start sequence.
+			 */
+			{
+				error = gfe_whack(sc, GE_WHACK_STOP);
+				if ( error )
+					break;
+				error = gfe_whack(sc, GE_WHACK_START);
+			}
+#endif
+			else
+				error = 0;
+		}
+		break;
+
+	case SIOCSIFMTU:
+		if (ifr->ifr_mtu > ETHERMTU || ifr->ifr_mtu < ETHERMIN) {
+			error = EINVAL;
+			break;
+		}
+		ifp->if_mtu = ifr->ifr_mtu;
+		break;
+
+	case SIOCSIFMEDIA:
+	case SIOCGIFMEDIA:
+#ifndef __rtems__
+		error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, cmd);
+#else
+		error = rtems_mii_ioctl(&gfe_mdio_access, sc, cmd, &ifr->ifr_media);
+#endif
+		break;
+
+	default:
+#ifndef __rtems__
+	error = EINVAL;
+#else
+	error = ether_ioctl(ifp, cmd, data);
+#endif
+		break;
+	}
+	splx(s);
+	GE_FUNC_EXIT(sc, "");
+	return error;
+}
+
+void
+gfe_ifstart(struct ifnet *ifp)
+{
+	struct gfe_softc * const sc = ifp->if_softc;
+	struct mbuf *m;
+
+	GE_FUNC_ENTER(sc, "gfe_ifstart");
+
+	if ((ifp->if_flags & IFF_RUNNING) == 0) {
+		GE_FUNC_EXIT(sc, "$");
+		return;
+	}
+
+	for (;;) {
+		IF_DEQUEUE(&ifp->if_snd, m);
+		if (m == NULL) {
+			ifp->if_flags &= ~IFF_OACTIVE;
+			GE_FUNC_EXIT(sc, "");
+			return;
+		}
+
+		/*
+		 * No space in the pending queue?  try later.
+		 */
+		if (IF_QFULL(&sc->sc_txq[GE_TXPRIO_HI].txq_pendq))
+			break;
+
+		/*
+		 * Try to enqueue a mbuf to the device. If that fails, we
+		 * can always try to map the next mbuf.
+		 */
+		IF_ENQUEUE(&sc->sc_txq[GE_TXPRIO_HI].txq_pendq, m);
+		GE_DPRINTF(sc, (">"));
+#ifndef GE_NOTX
+		(void) gfe_tx_enqueue(sc, GE_TXPRIO_HI);
+#endif
+	}
+
+	/*
+	 * Attempt to queue the mbuf for send failed.
+	 */
+	IF_PREPEND(&ifp->if_snd, m);
+	ifp->if_flags |= IFF_OACTIVE;
+	GE_FUNC_EXIT(sc, "%%");
+}
+
+void
+gfe_ifwatchdog(struct ifnet *ifp)
+{
+	struct gfe_softc * const sc = ifp->if_softc;
+	struct gfe_txqueue * const txq = &sc->sc_txq[GE_TXPRIO_HI];
+
+	GE_FUNC_ENTER(sc, "gfe_ifwatchdog");
+	printf("%s: device timeout", sc->sc_dev.dv_xname);
+	if (ifp->if_flags & IFF_RUNNING) {
+		uint32_t curtxdnum = (bus_space_read_4(sc->sc_gt_memt, sc->sc_gt_memh, txq->txq_ectdp) - txq->txq_desc_busaddr) / sizeof(txq->txq_descs[0]);
+		GE_TXDPOSTSYNC(sc, txq, txq->txq_fi);
+		GE_TXDPOSTSYNC(sc, txq, curtxdnum);
+		printf(" (fi=%d(%#" PRIx32 "),lo=%d,cur=%" PRIx32 "(%#" PRIx32 "),icm=%#" PRIx32 ") ",
+		    txq->txq_fi, txq->txq_descs[txq->txq_fi].ed_cmdsts,
+		    txq->txq_lo, curtxdnum, txq->txq_descs[curtxdnum].ed_cmdsts,
+		    GE_READ(sc, EICR));
+		GE_TXDPRESYNC(sc, txq, txq->txq_fi);
+		GE_TXDPRESYNC(sc, txq, curtxdnum);
+	}
+	printf("\n");
+	ifp->if_oerrors++;
+	(void) gfe_whack(sc, GE_WHACK_RESTART);
+	GE_FUNC_EXIT(sc, "");
+}
+
+
+#ifdef __rtems__
+static struct mbuf *
+gfe_newbuf(struct mbuf *m)
+{
+	if ( !m ) {
+		MGETHDR(m, M_DONTWAIT, MT_DATA);
+		if ( !m )
+			return 0;
+		MCLGET(m, M_DONTWAIT);
+		if ( !(M_EXT & m->m_flags) ) {
+			m_freem(m);
+			return 0;
+		}
+	} else {
+		m->m_data = m->m_ext.ext_buf;
+	}
+	m->m_len = m->m_pkthdr.len = MCLBYTES;
+#if 0
+	m_adj(m, 2); /* so payload is 16-byte aligned */
+#endif
+	return m;
+}
+#endif
+
+int
+gfe_rx_rxqalloc(struct gfe_softc *sc, enum gfe_rxprio rxprio)
+{
+	struct gfe_rxqueue * const rxq = &sc->sc_rxq[rxprio];
+	int error;
+
+	GE_FUNC_ENTER(sc, "gfe_rx_rxqalloc");
+	GE_DPRINTF(sc, ("(%d)", rxprio));
+
+	error = gfe_dmamem_alloc(sc, &rxq->rxq_desc_mem, 1,
+	    GE_RXDESC_MEMSIZE, BUS_DMA_NOCACHE);
+	if (error) {
+		GE_FUNC_EXIT(sc, "!!");
+		return error;
+	}
+
+#ifndef __rtems__
+	error = gfe_dmamem_alloc(sc, &rxq->rxq_buf_mem, GE_RXBUF_NSEGS,
+	    GE_RXBUF_MEMSIZE, 0);
+#else
+	if ( ! (rxq->rxq_bufs = malloc( sizeof(*rxq->rxq_bufs) * GE_RXDESC_MAX, M_DEVBUF, M_NOWAIT ) ) ) {
+		error = -1;
+	} else {
+		int i;
+		for ( i = 0; i<GE_RXDESC_MAX; i++ ) {
+			if ( !(rxq->rxq_bufs[i] = gfe_newbuf(0)) ) {
+				fprintf(stderr,"gfe: Not enough mbuf clusters to initialize RX ring!\n");
+				while (--i >=0 ) {
+					m_freem(rxq->rxq_bufs[i]);
+				}
+				free(rxq->rxq_bufs, M_DEVBUF);
+				rxq->rxq_bufs = 0;
+				error = -1;
+				break;
+			}
+		}
+	}
+#endif
+	if (error) {
+		GE_FUNC_EXIT(sc, "!!!");
+		return error;
+	}
+	GE_FUNC_EXIT(sc, "");
+	return error;
+}
+
+int
+gfe_rx_rxqinit(struct gfe_softc *sc, enum gfe_rxprio rxprio)
+{
+	struct gfe_rxqueue * const rxq = &sc->sc_rxq[rxprio];
+	volatile struct gt_eth_desc *rxd;
+#ifndef __rtems__
+	const bus_dma_segment_t *ds;
+#endif
+	int idx;
+	bus_addr_t nxtaddr;
+#ifndef __rtems__
+	bus_size_t boff;
+#endif
+
+	GE_FUNC_ENTER(sc, "gfe_rx_rxqinit");
+	GE_DPRINTF(sc, ("(%d)", rxprio));
+
+	if ((sc->sc_flags & GE_NOFREE) == 0) {
+		int error = gfe_rx_rxqalloc(sc, rxprio);
+		if (error) {
+			GE_FUNC_EXIT(sc, "!");
+			return error;
+		}
+	} else {
+		KASSERT(rxq->rxq_desc_mem.gdm_kva != NULL);
+#ifndef __rtems__
+		KASSERT(rxq->rxq_buf_mem.gdm_kva != NULL);
+#else
+		KASSERT(rxq->rxq_bufs != NULL);
+#endif
+	}
+
+	memset(rxq->rxq_desc_mem.gdm_kva, 0, GE_RXDESC_MEMSIZE);
+
+	rxq->rxq_descs =
+	    (volatile struct gt_eth_desc *) rxq->rxq_desc_mem.gdm_kva;
+	rxq->rxq_desc_busaddr = rxq->rxq_desc_mem.gdm_map->dm_segs[0].ds_addr;
+#ifndef __rtems__
+	rxq->rxq_bufs = (struct gfe_rxbuf *) rxq->rxq_buf_mem.gdm_kva;
+#endif
+	rxq->rxq_fi = 0;
+	rxq->rxq_active = GE_RXDESC_MAX;
+	for (idx = 0, rxd = rxq->rxq_descs,
+#ifndef __rtems__
+		boff = 0, ds = rxq->rxq_buf_mem.gdm_map->dm_segs,
+#endif
+		nxtaddr = rxq->rxq_desc_busaddr + sizeof(*rxd);
+	     idx < GE_RXDESC_MAX;
+	     idx++, rxd++, nxtaddr += sizeof(*rxd)) {
+#ifndef __rtems__
+		rxd->ed_lencnt = htogt32(GE_RXBUF_SIZE << 16);
+#else
+		rxd->ed_lencnt = htogt32(MCLBYTES << 16);
+#endif
+		rxd->ed_cmdsts = htogt32(RX_CMD_F|RX_CMD_L|RX_CMD_O|RX_CMD_EI);
+#ifndef __rtems__
+		rxd->ed_bufptr = htogt32(ds->ds_addr + boff);
+#else
+		rxd->ed_bufptr = htogt32(mtod(rxq->rxq_bufs[idx], uint32_t));
+#endif
+		/*
+		 * update the nxtptr to point to the next txd.
+		 */
+		if (idx == GE_RXDESC_MAX - 1)
+			nxtaddr = rxq->rxq_desc_busaddr;
+		rxd->ed_nxtptr = htogt32(nxtaddr);
+#ifndef __rtems__
+		boff += GE_RXBUF_SIZE;
+		if (boff == ds->ds_len) {
+			ds++;
+			boff = 0;
+		}
+#endif
+	}
+	bus_dmamap_sync(sc->sc_dmat, rxq->rxq_desc_mem.gdm_map, 0,
+			rxq->rxq_desc_mem.gdm_map->dm_mapsize,
+			BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+#ifndef __rtems__
+	bus_dmamap_sync(sc->sc_dmat, rxq->rxq_buf_mem.gdm_map, 0,
+			rxq->rxq_buf_mem.gdm_map->dm_mapsize,
+			BUS_DMASYNC_PREREAD);
+#else
+	/* FIXME: we leave this call in here so compilation fails
+	 *        if bus_dmamap_sync() is ever fleshed-out to implement
+	 *        software cache coherency...
+	 */
+	bus_dmamap_sync(sc->sc_dmat, rxq->rxq_buf_mem.gdm_map, 0,
+			rxq->rxq_buf_mem.gdm_map->dm_mapsize,
+			BUS_DMASYNC_PREREAD);
+#endif
+
+	rxq->rxq_intrbits = ETH_IR_RxBuffer|ETH_IR_RxError;
+	switch (rxprio) {
+	case GE_RXPRIO_HI:
+		rxq->rxq_intrbits |= ETH_IR_RxBuffer_3|ETH_IR_RxError_3;
+		rxq->rxq_efrdp = ETH_EFRDP3(sc->sc_macno);
+		rxq->rxq_ecrdp = ETH_ECRDP3(sc->sc_macno);
+		break;
+	case GE_RXPRIO_MEDHI:
+		rxq->rxq_intrbits |= ETH_IR_RxBuffer_2|ETH_IR_RxError_2;
+		rxq->rxq_efrdp = ETH_EFRDP2(sc->sc_macno);
+		rxq->rxq_ecrdp = ETH_ECRDP2(sc->sc_macno);
+		break;
+	case GE_RXPRIO_MEDLO:
+		rxq->rxq_intrbits |= ETH_IR_RxBuffer_1|ETH_IR_RxError_1;
+		rxq->rxq_efrdp = ETH_EFRDP1(sc->sc_macno);
+		rxq->rxq_ecrdp = ETH_ECRDP1(sc->sc_macno);
+		break;
+	case GE_RXPRIO_LO:
+		rxq->rxq_intrbits |= ETH_IR_RxBuffer_0|ETH_IR_RxError_0;
+		rxq->rxq_efrdp = ETH_EFRDP0(sc->sc_macno);
+		rxq->rxq_ecrdp = ETH_ECRDP0(sc->sc_macno);
+		break;
+	}
+	GE_FUNC_EXIT(sc, "");
+	return 0;
+}
+
+void
+gfe_rx_get(struct gfe_softc *sc, enum gfe_rxprio rxprio)
+{
+	struct ifnet * const ifp = &sc->sc_ec.ec_if;
+	struct gfe_rxqueue * const rxq = &sc->sc_rxq[rxprio];
+#ifndef __rtems__
+	struct mbuf *m = rxq->rxq_curpkt;
+#else
+	struct mbuf *m;
+#endif
+
+	GE_FUNC_ENTER(sc, "gfe_rx_get");
+	GE_DPRINTF(sc, ("(%d)", rxprio));
+
+	while (rxq->rxq_active > 0) {
+		volatile struct gt_eth_desc *rxd = &rxq->rxq_descs[rxq->rxq_fi];
+#ifndef __rtems__
+		struct gfe_rxbuf *rxb = &rxq->rxq_bufs[rxq->rxq_fi];
+#else
+		struct mbuf		**rxb = &rxq->rxq_bufs[rxq->rxq_fi];
+#endif
+		const struct ether_header *eh;
+		unsigned int cmdsts;
+		size_t buflen;
+
+		GE_RXDPOSTSYNC(sc, rxq, rxq->rxq_fi);
+		cmdsts = gt32toh(rxd->ed_cmdsts);
+		GE_DPRINTF(sc, (":%d=%#x", rxq->rxq_fi, cmdsts));
+		rxq->rxq_cmdsts = cmdsts;
+		/*
+		 * Sometimes the GE "forgets" to reset the ownership bit.
+		 * But if the length has been rewritten, the packet is ours
+		 * so pretend the O bit is set.
+		 */
+		buflen = gt32toh(rxd->ed_lencnt) & 0xffff;
+		if ((cmdsts & RX_CMD_O) && buflen == 0) {
+			GE_RXDPRESYNC(sc, rxq, rxq->rxq_fi);
+			break;
+		}
+
+		/*
+		 * If this is not a single buffer packet with no errors
+		 * or for some reason it's bigger than our frame size,
+		 * ignore it and go to the next packet.
+		 */
+		if ((cmdsts & (RX_CMD_F|RX_CMD_L|RX_STS_ES)) !=
+			    (RX_CMD_F|RX_CMD_L) ||
+		    buflen > sc->sc_max_frame_length) {
+			GE_DPRINTF(sc, ("!"));
+			--rxq->rxq_active;
+			ifp->if_ipackets++;
+			ifp->if_ierrors++;
+			
+			*rxb = gfe_newbuf(*rxb);
+			goto give_it_back;
+		}
+
+		/* CRC is included with the packet; trim it off. */
+		buflen -= ETHER_CRC_LEN;
+
+#ifndef __rtems__
+		if (m == NULL) {
+			MGETHDR(m, M_DONTWAIT, MT_DATA);
+			if (m == NULL) {
+				GE_DPRINTF(sc, ("?"));
+				break;
+			}
+		}
+		if ((m->m_flags & M_EXT) == 0 && buflen > MHLEN - 2) {
+			MCLGET(m, M_DONTWAIT);
+			if ((m->m_flags & M_EXT) == 0) {
+				GE_DPRINTF(sc, ("?"));
+				break;
+			}
+		}
+		m->m_data += 2;
+		m->m_len = 0;
+		m->m_pkthdr.len = 0;
+		m->m_pkthdr.rcvif = ifp;
+#else
+		if ( ! (m=gfe_newbuf(0)) ) {
+			/* recycle old buffer */
+			*rxb = gfe_newbuf(*rxb);
+			goto give_it_back;
+		}
+		/* swap mbufs */
+		{
+		struct mbuf *tmp = *rxb;
+		*rxb = m;
+		m    = tmp;
+		rxd->ed_bufptr = htogt32(mtod(*rxb, uint32_t));
+		}
+#endif
+		rxq->rxq_cmdsts = cmdsts;
+		--rxq->rxq_active;
+
+#ifdef __rtems__
+		/* FIXME: we leave this call in here so compilation fails
+		 *        if bus_dmamap_sync() is ever fleshed-out to implement
+		 *        software cache coherency...
+		 */
+		bus_dmamap_sync(sc->sc_dmat, rxq->rxq_buf_mem.gdm_map,
+		    rxq->rxq_fi * sizeof(*rxb), buflen, BUS_DMASYNC_POSTREAD);
+#else
+		bus_dmamap_sync(sc->sc_dmat, rxq->rxq_buf_mem.gdm_map,
+		    rxq->rxq_fi * sizeof(*rxb), buflen, BUS_DMASYNC_POSTREAD);
+
+		KASSERT(m->m_len == 0 && m->m_pkthdr.len == 0);
+		memcpy(m->m_data + m->m_len, rxb->rb_data, buflen);
+#endif
+
+		m->m_len = buflen;
+		m->m_pkthdr.len = buflen;
+
+		ifp->if_ipackets++;
+#if NBPFILTER > 0
+		if (ifp->if_bpf != NULL)
+			bpf_mtap(ifp->if_bpf, m);
+#endif
+
+		eh = (const struct ether_header *) m->m_data;
+		if ((ifp->if_flags & IFF_PROMISC) ||
+		    (rxq->rxq_cmdsts & RX_STS_M) == 0 ||
+		    (rxq->rxq_cmdsts & RX_STS_HE) ||
+		    (eh->ether_dhost[0] & 1) != 0 ||
+		    memcmp(eh->ether_dhost,
+#ifndef __rtems__
+				LLADDR(ifp->if_sadl),
+#else
+				sc->sc_ec.ac_enaddr,
+#endif
+			ETHER_ADDR_LEN) == 0) {
+#ifndef __rtems__
+			(*ifp->if_input)(ifp, m);
+			m = NULL;
+#else
+			DO_ETHER_INPUT_SKIPPING_ETHER_HEADER(ifp,m);
+#endif
+			GE_DPRINTF(sc, (">"));
+		} else {
+#ifndef __rtems__
+			m->m_len = 0;
+			m->m_pkthdr.len = 0;
+#else
+			m_freem(m);
+#endif
+			GE_DPRINTF(sc, ("+"));
+		}
+		rxq->rxq_cmdsts = 0;
+
+	   give_it_back:
+		rxd->ed_lencnt &= ~0xffff;	/* zero out length */
+		rxd->ed_cmdsts = htogt32(RX_CMD_F|RX_CMD_L|RX_CMD_O|RX_CMD_EI);
+#if 0
+		GE_DPRINTF(sc, ("([%d]->%08lx.%08lx.%08lx.%08lx)",
+		    rxq->rxq_fi,
+		    ((unsigned long *)rxd)[0], ((unsigned long *)rxd)[1],
+		    ((unsigned long *)rxd)[2], ((unsigned long *)rxd)[3]));
+#endif
+		GE_RXDPRESYNC(sc, rxq, rxq->rxq_fi);
+		if (++rxq->rxq_fi == GE_RXDESC_MAX)
+			rxq->rxq_fi = 0;
+		rxq->rxq_active++;
+	}
+#ifndef __rtems__
+	rxq->rxq_curpkt = m;
+#endif
+	GE_FUNC_EXIT(sc, "");
+}
+
+uint32_t
+gfe_rx_process(struct gfe_softc *sc, uint32_t cause, uint32_t intrmask)
+{
+	struct ifnet * const ifp = &sc->sc_ec.ec_if;
+	struct gfe_rxqueue *rxq;
+	uint32_t rxbits;
+#define	RXPRIO_DECODER	0xffffaa50
+	GE_FUNC_ENTER(sc, "gfe_rx_process");
+
+	rxbits = ETH_IR_RxBuffer_GET(cause);
+	while (rxbits) {
+		enum gfe_rxprio rxprio = (RXPRIO_DECODER >> (rxbits * 2)) & 3;
+		GE_DPRINTF(sc, ("%1" PRIx32, rxbits));
+		rxbits &= ~(1 << rxprio);
+		gfe_rx_get(sc, rxprio);
+	}
+
+	rxbits = ETH_IR_RxError_GET(cause);
+	while (rxbits) {
+		enum gfe_rxprio rxprio = (RXPRIO_DECODER >> (rxbits * 2)) & 3;
+		uint32_t masks[(GE_RXDESC_MAX + 31) / 32];
+		int idx;
+		rxbits &= ~(1 << rxprio);
+		rxq = &sc->sc_rxq[rxprio];
+		sc->sc_idlemask |= (rxq->rxq_intrbits & ETH_IR_RxBits);
+		intrmask &= ~(rxq->rxq_intrbits & ETH_IR_RxBits);
+		if ((sc->sc_tickflags & GE_TICK_RX_RESTART) == 0) {
+			sc->sc_tickflags |= GE_TICK_RX_RESTART;
+			callout_reset(&sc->sc_co, 1, gfe_tick, sc);
+		}
+		ifp->if_ierrors++;
+		GE_DPRINTF(sc, ("%s: rx queue %d filled at %u\n",
+		    sc->sc_dev.dv_xname, rxprio, rxq->rxq_fi));
+		memset(masks, 0, sizeof(masks));
+		bus_dmamap_sync(sc->sc_dmat, rxq->rxq_desc_mem.gdm_map,
+		    0, rxq->rxq_desc_mem.gdm_size,
+		    BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
+		for (idx = 0; idx < GE_RXDESC_MAX; idx++) {
+			volatile struct gt_eth_desc *rxd = &rxq->rxq_descs[idx];
+
+			if (RX_CMD_O & gt32toh(rxd->ed_cmdsts))
+				masks[idx/32] |= 1 << (idx & 31);
+		}
+		bus_dmamap_sync(sc->sc_dmat, rxq->rxq_desc_mem.gdm_map,
+		    0, rxq->rxq_desc_mem.gdm_size,
+		    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+#if defined(DEBUG)
+		printf("%s: rx queue %d filled at %u=%#x(%#x/%#x)\n",
+		    sc->sc_dev.dv_xname, rxprio, rxq->rxq_fi,
+		    rxq->rxq_cmdsts, masks[0], masks[1]);
+#endif
+	}
+	if ((intrmask & ETH_IR_RxBits) == 0)
+		intrmask &= ~(ETH_IR_RxBuffer|ETH_IR_RxError);
+
+	GE_FUNC_EXIT(sc, "");
+	return intrmask;
+}
+
+int
+gfe_rx_prime(struct gfe_softc *sc)
+{
+	struct gfe_rxqueue *rxq;
+	int error;
+
+	GE_FUNC_ENTER(sc, "gfe_rx_prime");
+
+	error = gfe_rx_rxqinit(sc, GE_RXPRIO_HI);
+	if (error)
+		goto bail;
+	rxq = &sc->sc_rxq[GE_RXPRIO_HI];
+	if ((sc->sc_flags & GE_RXACTIVE) == 0) {
+		GE_WRITE(sc, EFRDP3, rxq->rxq_desc_busaddr);
+		GE_WRITE(sc, ECRDP3, rxq->rxq_desc_busaddr);
+	}
+	sc->sc_intrmask |= rxq->rxq_intrbits;
+
+	error = gfe_rx_rxqinit(sc, GE_RXPRIO_MEDHI);
+	if (error)
+		goto bail;
+	if ((sc->sc_flags & GE_RXACTIVE) == 0) {
+		rxq = &sc->sc_rxq[GE_RXPRIO_MEDHI];
+		GE_WRITE(sc, EFRDP2, rxq->rxq_desc_busaddr);
+		GE_WRITE(sc, ECRDP2, rxq->rxq_desc_busaddr);
+		sc->sc_intrmask |= rxq->rxq_intrbits;
+	}
+
+	error = gfe_rx_rxqinit(sc, GE_RXPRIO_MEDLO);
+	if (error)
+		goto bail;
+	if ((sc->sc_flags & GE_RXACTIVE) == 0) {
+		rxq = &sc->sc_rxq[GE_RXPRIO_MEDLO];
+		GE_WRITE(sc, EFRDP1, rxq->rxq_desc_busaddr);
+		GE_WRITE(sc, ECRDP1, rxq->rxq_desc_busaddr);
+		sc->sc_intrmask |= rxq->rxq_intrbits;
+	}
+
+	error = gfe_rx_rxqinit(sc, GE_RXPRIO_LO);
+	if (error)
+		goto bail;
+	if ((sc->sc_flags & GE_RXACTIVE) == 0) {
+		rxq = &sc->sc_rxq[GE_RXPRIO_LO];
+		GE_WRITE(sc, EFRDP0, rxq->rxq_desc_busaddr);
+		GE_WRITE(sc, ECRDP0, rxq->rxq_desc_busaddr);
+		sc->sc_intrmask |= rxq->rxq_intrbits;
+	}
+
+  bail:
+	GE_FUNC_EXIT(sc, "");
+	return error;
+}
+
+void
+gfe_rx_cleanup(struct gfe_softc *sc, enum gfe_rxprio rxprio)
+{
+	struct gfe_rxqueue *rxq = &sc->sc_rxq[rxprio];
+	GE_FUNC_ENTER(sc, "gfe_rx_cleanup");
+	if (rxq == NULL) {
+		GE_FUNC_EXIT(sc, "");
+		return;
+	}
+
+#ifndef __rtems__
+	if (rxq->rxq_curpkt)
+		m_freem(rxq->rxq_curpkt);
+#endif
+	if ((sc->sc_flags & GE_NOFREE) == 0) {
+		gfe_dmamem_free(sc, &rxq->rxq_desc_mem);
+#ifndef __rtems__
+		gfe_dmamem_free(sc, &rxq->rxq_buf_mem);
+#else
+		if ( rxq->rxq_bufs ) {
+			int i;
+			for ( i=0; i<GE_RXDESC_MAX; i++ ) {
+				if ( rxq->rxq_bufs[i] ) {
+					m_freem(rxq->rxq_bufs[i]);
+				}
+			}
+			free(rxq->rxq_bufs, M_DEVBUF);
+		}
+#endif
+	}
+	GE_FUNC_EXIT(sc, "");
+}
+
+void
+gfe_rx_stop(struct gfe_softc *sc, enum gfe_whack_op op)
+{
+	GE_FUNC_ENTER(sc, "gfe_rx_stop");
+	sc->sc_flags &= ~GE_RXACTIVE;
+	sc->sc_idlemask &= ~(ETH_IR_RxBits|ETH_IR_RxBuffer|ETH_IR_RxError);
+	sc->sc_intrmask &= ~(ETH_IR_RxBits|ETH_IR_RxBuffer|ETH_IR_RxError);
+	GE_WRITE(sc, EIMR, sc->sc_intrmask);
+	GE_WRITE(sc, ESDCMR, ETH_ESDCMR_AR);
+	do {
+		delay(10);
+	} while (GE_READ(sc, ESDCMR) & ETH_ESDCMR_AR);
+	gfe_rx_cleanup(sc, GE_RXPRIO_HI);
+	gfe_rx_cleanup(sc, GE_RXPRIO_MEDHI);
+	gfe_rx_cleanup(sc, GE_RXPRIO_MEDLO);
+	gfe_rx_cleanup(sc, GE_RXPRIO_LO);
+	GE_FUNC_EXIT(sc, "");
+}
+
+
+void
+gfe_tick(void *arg)
+{
+	struct gfe_softc * const sc = arg;
+	uint32_t intrmask;
+	unsigned int tickflags;
+	int s;
+
+	GE_FUNC_ENTER(sc, "gfe_tick");
+
+	s = splnet();
+
+	tickflags = sc->sc_tickflags;
+	sc->sc_tickflags = 0;
+	intrmask = sc->sc_intrmask;
+	if (tickflags & GE_TICK_TX_IFSTART)
+		gfe_ifstart(&sc->sc_ec.ec_if);
+	if (tickflags & GE_TICK_RX_RESTART) {
+		intrmask |= sc->sc_idlemask;
+		if (sc->sc_idlemask & (ETH_IR_RxBuffer_3|ETH_IR_RxError_3)) {
+			struct gfe_rxqueue *rxq = &sc->sc_rxq[GE_RXPRIO_HI];
+			rxq->rxq_fi = 0;
+			GE_WRITE(sc, EFRDP3, rxq->rxq_desc_busaddr);
+			GE_WRITE(sc, ECRDP3, rxq->rxq_desc_busaddr);
+		}
+		if (sc->sc_idlemask & (ETH_IR_RxBuffer_2|ETH_IR_RxError_2)) {
+			struct gfe_rxqueue *rxq = &sc->sc_rxq[GE_RXPRIO_MEDHI];
+			rxq->rxq_fi = 0;
+			GE_WRITE(sc, EFRDP2, rxq->rxq_desc_busaddr);
+			GE_WRITE(sc, ECRDP2, rxq->rxq_desc_busaddr);
+		}
+		if (sc->sc_idlemask & (ETH_IR_RxBuffer_1|ETH_IR_RxError_1)) {
+			struct gfe_rxqueue *rxq = &sc->sc_rxq[GE_RXPRIO_MEDLO];
+			rxq->rxq_fi = 0;
+			GE_WRITE(sc, EFRDP1, rxq->rxq_desc_busaddr);
+			GE_WRITE(sc, ECRDP1, rxq->rxq_desc_busaddr);
+		}
+		if (sc->sc_idlemask & (ETH_IR_RxBuffer_0|ETH_IR_RxError_0)) {
+			struct gfe_rxqueue *rxq = &sc->sc_rxq[GE_RXPRIO_LO];
+			rxq->rxq_fi = 0;
+			GE_WRITE(sc, EFRDP0, rxq->rxq_desc_busaddr);
+			GE_WRITE(sc, ECRDP0, rxq->rxq_desc_busaddr);
+		}
+		sc->sc_idlemask = 0;
+	}
+	if (intrmask != sc->sc_intrmask) {
+		sc->sc_intrmask = intrmask;
+		GE_WRITE(sc, EIMR, sc->sc_intrmask);
+	}
+	gfe_intr(sc);
+	splx(s);
+
+	GE_FUNC_EXIT(sc, "");
+}
+
+static int
+gfe_free_slots(struct gfe_softc *sc, struct gfe_txqueue *const txq)
+{
+	struct ifnet * const ifp = &sc->sc_ec.ec_if;
+#ifndef	__rtems__
+	const int dcache_line_size = curcpu()->ci_ci.dcache_line_size;
+#endif
+	int							 got = 0;
+	int							  fi = txq->txq_fi;
+	volatile struct gt_eth_desc *txd = &txq->txq_descs[fi];
+	uint32_t cmdsts;
+#ifndef __rtems__
+	size_t pktlen;
+#endif
+
+	GE_FUNC_ENTER(sc, "gfe_free_slots");
+
+#ifdef __rtems__
+	do {
+#endif
+		GE_TXDPOSTSYNC(sc, txq, fi);
+		if ((cmdsts = gt32toh(txd->ed_cmdsts)) & TX_CMD_O) {
+			int nextin;
+
+			if (txq->txq_nactive == 1) {
+				GE_TXDPRESYNC(sc, txq, fi);
+				GE_FUNC_EXIT(sc, "");
+				return -1;
+			}
+			/*
+			 * Sometimes the Discovery forgets to update the
+			 * ownership bit in the descriptor.  See if we own the
+			 * descriptor after it (since we know we've turned
+			 * that to the Discovery and if we own it now then the
+			 * Discovery gave it back).  If we do, we know the
+			 * Discovery gave back this one but forgot to mark it
+			 * as ours.
+			 */
+			nextin = fi + 1;
+			if (nextin == GE_TXDESC_MAX)
+				nextin = 0;
+			GE_TXDPOSTSYNC(sc, txq, nextin);
+			if (gt32toh(txq->txq_descs[nextin].ed_cmdsts) & TX_CMD_O) {
+				GE_TXDPRESYNC(sc, txq, fi);
+				GE_TXDPRESYNC(sc, txq, nextin);
+				GE_FUNC_EXIT(sc, "");
+				return -1;
+			}
+#ifdef DEBUG
+			printf("%s: gfe_free_slots: transmitter resynced at %d\n",
+					sc->sc_dev.dv_xname, fi);
+#endif
+		}
+		got++;
+#ifdef __rtems__
+		txd++;
+		fi++;
+	} while ( ! ( TX_CMD_LAST & cmdsts ) );
+
+	{ struct mbuf *m;
+		IF_DEQUEUE(&txq->txq_sentq, m);
+		m_freem(m);
+	}
+#endif
+#if 0
+	GE_DPRINTF(sc, ("([%d]<-%08lx.%08lx.%08lx.%08lx)",
+				txq->txq_lo,
+				((unsigned long *)txd)[0], ((unsigned long *)txd)[1],
+				((unsigned long *)txd)[2], ((unsigned long *)txd)[3]));
+#endif
+	GE_DPRINTF(sc, ("(%d)", fi));
+	txq->txq_fi = fi;
+	if ( txq->txq_fi >= GE_TXDESC_MAX)
+		txq->txq_fi -= GE_TXDESC_MAX;
+#ifndef __rtems__
+	txq->txq_inptr = gt32toh(txd->ed_bufptr) - txq->txq_buf_busaddr;
+	pktlen = (gt32toh(txd->ed_lencnt) >> 16) & 0xffff;
+	bus_dmamap_sync(sc->sc_dmat, txq->txq_buf_mem.gdm_map,
+			txq->txq_inptr, pktlen, BUS_DMASYNC_POSTWRITE);
+	txq->txq_inptr += roundup(pktlen, dcache_line_size);
+#endif
+
+	/* statistics */
+	ifp->if_opackets++;
+#ifdef __rtems__
+	/* FIXME: should we check errors on every fragment? */
+#endif
+	if (cmdsts & TX_STS_ES)
+		ifp->if_oerrors++;
+
+	/* txd->ed_bufptr = 0; */
+
+	txq->txq_nactive -= got;
+
+	GE_FUNC_EXIT(sc, "");
+
+	return got;
+}
+
+#ifndef __rtems__
+int
+gfe_tx_enqueue(struct gfe_softc *sc, enum gfe_txprio txprio)
+{
+#ifndef	__rtems__
+	const int dcache_line_size = curcpu()->ci_ci.dcache_line_size;
+#else
+#ifndef PPC_CACHE_ALIGNMENT
+#error	"Unknown cache alignment for your CPU"
+#endif
+	const int dcache_line_size = PPC_CACHE_ALIGNMENT;
+#endif
+	struct ifnet * const ifp = &sc->sc_ec.ec_if;
+	struct gfe_txqueue * const txq = &sc->sc_txq[txprio];
+	volatile struct gt_eth_desc * const txd = &txq->txq_descs[txq->txq_lo];
+	uint32_t intrmask = sc->sc_intrmask;
+	size_t buflen;
+	struct mbuf *m;
+
+	GE_FUNC_ENTER(sc, "gfe_tx_enqueue");
+
+	/*
+	 * Anything in the pending queue to enqueue?  if not, punt. Likewise
+	 * if the txq is not yet created.
+	 * otherwise grab its dmamap.
+	 */
+	if (txq == NULL || (m = txq->txq_pendq.ifq_head) == NULL) {
+		GE_FUNC_EXIT(sc, "-");
+		return 0;
+	}
+
+	/*
+	 * Have we [over]consumed our limit of descriptors?
+	 * Do we have enough free descriptors?
+	 */
+	if (GE_TXDESC_MAX == txq->txq_nactive + 2) {
+		if ( gfe_free_slots(sc, txq) <= 0 )
+			return 0;
+	}
+
+	buflen = roundup(m->m_pkthdr.len, dcache_line_size);
+
+	/*
+	 * If this packet would wrap around the end of the buffer, reset back
+	 * to the beginning.
+	 */
+	if (txq->txq_outptr + buflen > GE_TXBUF_SIZE) {
+		txq->txq_ei_gapcount += GE_TXBUF_SIZE - txq->txq_outptr;
+		txq->txq_outptr = 0;
+	}
+
+	/*
+	 * Make sure the output packet doesn't run over the beginning of
+	 * what we've already given the GT.
+	 */
+	if (txq->txq_nactive > 0 && txq->txq_outptr <= txq->txq_inptr &&
+	    txq->txq_outptr + buflen > txq->txq_inptr) {
+		intrmask |= txq->txq_intrbits &
+		    (ETH_IR_TxBufferHigh|ETH_IR_TxBufferLow);
+		if (sc->sc_intrmask != intrmask) {
+			sc->sc_intrmask = intrmask;
+			GE_WRITE(sc, EIMR, sc->sc_intrmask);
+		}
+		GE_FUNC_EXIT(sc, "#");
+		return 0;
+	}
+
+	/*
+	 * The end-of-list descriptor we put on last time is the starting point
+	 * for this packet.  The GT is supposed to terminate list processing on
+	 * a NULL nxtptr but that currently is broken so a CPU-owned descriptor
+	 * must terminate the list.
+	 */
+	intrmask = sc->sc_intrmask;
+
+	m_copydata(m, 0, m->m_pkthdr.len,
+	    txq->txq_buf_mem.gdm_kva + txq->txq_outptr);
+	bus_dmamap_sync(sc->sc_dmat, txq->txq_buf_mem.gdm_map,
+	    txq->txq_outptr, buflen, BUS_DMASYNC_PREWRITE);
+	txd->ed_bufptr = htogt32(txq->txq_buf_busaddr + txq->txq_outptr);
+	txd->ed_lencnt = htogt32(m->m_pkthdr.len << 16);
+	GE_TXDPRESYNC(sc, txq, txq->txq_lo);
+
+	/*
+	 * Request a buffer interrupt every 2/3 of the way thru the transmit
+	 * buffer.
+	 */
+	txq->txq_ei_gapcount += buflen;
+	if (txq->txq_ei_gapcount > 2 * GE_TXBUF_SIZE / 3) {
+		txd->ed_cmdsts = htogt32(TX_CMD_FIRST|TX_CMD_LAST|TX_CMD_EI);
+		txq->txq_ei_gapcount = 0;
+	} else {
+		txd->ed_cmdsts = htogt32(TX_CMD_FIRST|TX_CMD_LAST);
+	}
+#if 0
+	GE_DPRINTF(sc, ("([%d]->%08lx.%08lx.%08lx.%08lx)", txq->txq_lo,
+	    ((unsigned long *)txd)[0], ((unsigned long *)txd)[1],
+	    ((unsigned long *)txd)[2], ((unsigned long *)txd)[3]));
+#endif
+	GE_TXDPRESYNC(sc, txq, txq->txq_lo);
+
+	txq->txq_outptr += buflen;
+	/*
+	 * Tell the SDMA engine to "Fetch!"
+	 */
+	GE_WRITE(sc, ESDCMR,
+		 txq->txq_esdcmrbits & (ETH_ESDCMR_TXDH|ETH_ESDCMR_TXDL));
+
+	GE_DPRINTF(sc, ("(%d)", txq->txq_lo));
+
+	/*
+	 * Update the last out appropriately.
+	 */
+	txq->txq_nactive++;
+	if (++txq->txq_lo == GE_TXDESC_MAX)
+		txq->txq_lo = 0;
+
+	/*
+	 * Move mbuf from the pending queue to the snd queue.
+	 */
+	IF_DEQUEUE(&txq->txq_pendq, m);
+#if NBPFILTER > 0
+	if (ifp->if_bpf != NULL)
+		bpf_mtap(ifp->if_bpf, m);
+#endif
+	m_freem(m);
+	ifp->if_flags &= ~IFF_OACTIVE;
+
+	/*
+	 * Since we have put an item into the packet queue, we now want
+	 * an interrupt when the transmit queue finishes processing the
+	 * list.  But only update the mask if needs changing.
+	 */
+	intrmask |= txq->txq_intrbits & (ETH_IR_TxEndHigh|ETH_IR_TxEndLow);
+	if (sc->sc_intrmask != intrmask) {
+		sc->sc_intrmask = intrmask;
+		GE_WRITE(sc, EIMR, sc->sc_intrmask);
+	}
+	if (ifp->if_timer == 0)
+		ifp->if_timer = 5;
+	GE_FUNC_EXIT(sc, "*");
+	return 1;
+}
+
+#else
+
+#ifdef __PPC__
+static inline void membarrier(void)
+{
+	asm volatile("sync":::"memory");
+}
+#else
+#error "memory synchronization for your CPU not implemented"
+#endif
+
+
+void
+gfe_assign_desc(volatile struct gt_eth_desc *const d, struct mbuf *m, uint32_t flags)
+{
+	d->ed_cmdsts = htogt32(flags | TX_CMD_GC | TX_CMD_P);
+	d->ed_bufptr = htogt32(mtod(m, uint32_t));
+	d->ed_lencnt = htogt32(m->m_len << 16);
+}
+
+int
+gfe_tx_enqueue(struct gfe_softc *sc, enum gfe_txprio txprio)
+{
+	struct ifnet * const ifp = &sc->sc_ec.ec_if;
+	struct gfe_txqueue * const txq = &sc->sc_txq[txprio];
+	volatile struct gt_eth_desc * const txd = &txq->txq_descs[txq->txq_lo];
+#define NEXT_TXD(d)	((d)+1 < &txq->txq_descs[GE_TXDESC_MAX] ? (d)+1 : txq->txq_descs)
+	volatile struct gt_eth_desc *l,*d;
+	uint32_t intrmask = sc->sc_intrmask;
+	struct mbuf *m_head,*m,*m1;
+	int									avail, used;
+
+	GE_FUNC_ENTER(sc, "gfe_tx_enqueue");
+
+	/*
+	 * Anything in the pending queue to enqueue?  if not, punt. Likewise
+	 * if the txq is not yet created.
+	 * otherwise grab its dmamap.
+	 */
+	if (txq == NULL || (m_head = txq->txq_pendq.ifq_head) == NULL) {
+		GE_FUNC_EXIT(sc, "-");
+		return 0;
+	}
+
+	/* find 1st mbuf with actual data; m_head is not NULL at this point */
+	for ( m1=m_head; 0 == m1->m_len; ) {
+		if ( ! (m1=m1->m_next) ) {
+			/* nothing to send */
+			IF_DEQUEUE(&txq->txq_pendq, m_head);
+			m_freem(m_head);
+			return 0;
+		}
+	}
+
+	avail = GE_TXDESC_MAX - 1 - txq->txq_nactive;
+
+	if ( avail < 1 && (avail += gfe_free_slots(sc, txq)) < 1 )
+		return 0;
+
+	avail--;
+
+	l = txd;
+	d = NEXT_TXD(txd);
+
+	for ( m=m1->m_next, used = 1; m; m=m->m_next ) {
+		if ( 0 == m->m_len )
+			continue; /* skip empty mbufs */
+
+		if ( avail < 1 && (avail += gfe_free_slots(sc, txq)) < 1 ) {
+			/* not enough descriptors; cleanup */
+			for ( l = NEXT_TXD(txd); l!=d; l = NEXT_TXD(l) ) {
+				l->ed_cmdsts = 0;
+				avail++;
+			}
+			avail++;
+			if ( used >= GE_TXDESC_MAX-1 )
+				panic("mbuf chain (#%i) longer than TX ring (#%i); configuration error!",
+					used, GE_TXDESC_MAX-1);
+			return 0;
+		}
+		used++;
+		avail--;
+
+		/* fill this slot */
+		gfe_assign_desc(d, m, TX_CMD_O);
+
+		bus_dmamap_sync(sc->sc_dmat, /* TODO */,
+	   		 mtod(m, uint32_t), m->m_len, BUS_DMASYNC_PREWRITE);
+
+		l = d;
+		d = NEXT_TXD(d);
+
+		GE_TXDPRESYNC(sc, txq, l - txq->txq_descs);
+	}
+
+	/* fill first slot */
+	gfe_assign_desc(txd, m1, TX_CMD_F);
+
+	bus_dmamap_sync(sc->sc_dmat, /* TODO */,
+	   		 mtod(m1, uint32_t), m1->m_len, BUS_DMASYNC_PREWRITE);
+	
+	/* tag last slot; this covers where 1st = last */
+	l->ed_cmdsts	|= htonl(TX_CMD_L | TX_CMD_EI);
+
+	GE_TXDPRESYNC(sc, txq, l - txq->txq_descs);
+
+	/*
+	 * The end-of-list descriptor we put on last time is the starting point
+	 * for this packet.  The GT is supposed to terminate list processing on
+	 * a NULL nxtptr but that currently is broken so a CPU-owned descriptor
+	 * must terminate the list.
+	 */
+	d = NEXT_TXD(l);
+
+	out_be32((uint32_t*)&d->ed_cmdsts,0);
+
+	GE_TXDPRESYNC(sc, txq, d - txq->txq_descs);
+
+	membarrier();
+
+	/* turn over the whole chain by flipping the ownership of the first desc */
+	txd->ed_cmdsts |= htonl(TX_CMD_O);
+
+	GE_TXDPRESYNC(sc, txq, txq->txq_lo);
+
+
+	intrmask = sc->sc_intrmask;
+
+#if 0
+	GE_DPRINTF(sc, ("([%d]->%08lx.%08lx.%08lx.%08lx)", txq->txq_lo,
+	    ((unsigned long *)txd)[0], ((unsigned long *)txd)[1],
+	    ((unsigned long *)txd)[2], ((unsigned long *)txd)[3]));
+#endif
+
+	membarrier();
+
+	/*
+	 * Tell the SDMA engine to "Fetch!"
+	 */
+	GE_WRITE(sc, ESDCMR,
+		 txq->txq_esdcmrbits & (ETH_ESDCMR_TXDH|ETH_ESDCMR_TXDL));
+
+	GE_DPRINTF(sc, ("(%d)", txq->txq_lo));
+
+	/*
+	 * Update the last out appropriately.
+	 */
+	txq->txq_nactive += used;
+	txq->txq_lo      += used;
+	if ( txq->txq_lo >= GE_TXDESC_MAX )
+		txq->txq_lo -= GE_TXDESC_MAX;
+
+	/*
+	 * Move mbuf from the pending queue to the snd queue.
+	 */
+	IF_DEQUEUE(&txq->txq_pendq, m_head);
+
+	IF_ENQUEUE(&txq->txq_sentq, m_head);
+
+#if NBPFILTER > 0
+	if (ifp->if_bpf != NULL)
+		bpf_mtap(ifp->if_bpf, m_head);
+#endif
+	ifp->if_flags &= ~IFF_OACTIVE;
+
+	/*
+	 * Since we have put an item into the packet queue, we now want
+	 * an interrupt when the transmit queue finishes processing the
+	 * list.  But only update the mask if needs changing.
+	 */
+	intrmask |= txq->txq_intrbits & (ETH_IR_TxEndHigh|ETH_IR_TxEndLow);
+	if (sc->sc_intrmask != intrmask) {
+		sc->sc_intrmask = intrmask;
+		GE_WRITE(sc, EIMR, sc->sc_intrmask);
+	}
+	if (ifp->if_timer == 0)
+		ifp->if_timer = 5;
+	GE_FUNC_EXIT(sc, "*");
+	return 1;
+}
+#endif
+
+uint32_t
+gfe_tx_done(struct gfe_softc *sc, enum gfe_txprio txprio, uint32_t intrmask)
+{
+	struct gfe_txqueue * const txq = &sc->sc_txq[txprio];
+	struct ifnet * const ifp = &sc->sc_ec.ec_if;
+
+	GE_FUNC_ENTER(sc, "gfe_tx_done");
+
+	if (txq == NULL) {
+		GE_FUNC_EXIT(sc, "");
+		return intrmask;
+	}
+
+	while (txq->txq_nactive > 0) {
+		if ( gfe_free_slots(sc, txq) < 0 )
+			return intrmask;
+		ifp->if_timer = 5;
+	}
+	if (txq->txq_nactive != 0)
+		panic("%s: transmit fifo%d empty but active count (%d) not 0!",
+		    sc->sc_dev.dv_xname, txprio, txq->txq_nactive);
+	ifp->if_timer = 0;
+	intrmask &= ~(txq->txq_intrbits & (ETH_IR_TxEndHigh|ETH_IR_TxEndLow));
+	intrmask &= ~(txq->txq_intrbits & (ETH_IR_TxBufferHigh|ETH_IR_TxBufferLow));
+	GE_FUNC_EXIT(sc, "");
+	return intrmask;
+}
+
+int
+gfe_tx_txqalloc(struct gfe_softc *sc, enum gfe_txprio txprio)
+{
+	struct gfe_txqueue * const txq = &sc->sc_txq[txprio];
+	int error;
+
+	GE_FUNC_ENTER(sc, "gfe_tx_txqalloc");
+
+	error = gfe_dmamem_alloc(sc, &txq->txq_desc_mem, 1,
+	    GE_TXDESC_MEMSIZE, BUS_DMA_NOCACHE);
+	if (error) {
+		GE_FUNC_EXIT(sc, "");
+		return error;
+	}
+#ifndef __rtems__
+	error = gfe_dmamem_alloc(sc, &txq->txq_buf_mem, 1, GE_TXBUF_SIZE, 0);
+	if (error) {
+		gfe_dmamem_free(sc, &txq->txq_desc_mem);
+		GE_FUNC_EXIT(sc, "");
+		return error;
+	}
+#endif
+	GE_FUNC_EXIT(sc, "");
+	return 0;
+}
+
+int
+gfe_tx_start(struct gfe_softc *sc, enum gfe_txprio txprio)
+{
+	struct gfe_txqueue * const txq = &sc->sc_txq[txprio];
+	volatile struct gt_eth_desc *txd;
+	unsigned int i;
+	bus_addr_t addr;
+
+	GE_FUNC_ENTER(sc, "gfe_tx_start");
+
+	sc->sc_intrmask &= ~(ETH_IR_TxEndHigh|ETH_IR_TxBufferHigh|
+			     ETH_IR_TxEndLow |ETH_IR_TxBufferLow);
+
+	if (sc->sc_flags & GE_NOFREE) {
+		KASSERT(txq->txq_desc_mem.gdm_kva != NULL);
+#ifndef __rtems__
+		KASSERT(txq->txq_buf_mem.gdm_kva != NULL);
+#endif
+	} else {
+		int error = gfe_tx_txqalloc(sc, txprio);
+		if (error) {
+			GE_FUNC_EXIT(sc, "!");
+			return error;
+		}
+	}
+
+	txq->txq_descs =
+	    (volatile struct gt_eth_desc *) txq->txq_desc_mem.gdm_kva;
+	txq->txq_desc_busaddr = txq->txq_desc_mem.gdm_map->dm_segs[0].ds_addr;
+#ifndef __rtems__
+	txq->txq_buf_busaddr = txq->txq_buf_mem.gdm_map->dm_segs[0].ds_addr;
+#else
+	/* never used */
+	memset(&txq->txq_pendq,0,sizeof(txq->txq_pendq));
+	memset(&txq->txq_sentq,0,sizeof(txq->txq_sentq));
+	txq->txq_sentq.ifq_maxlen = 100000;
+#endif
+
+	txq->txq_pendq.ifq_maxlen = 10;
+#ifndef __rtems__
+	txq->txq_ei_gapcount = 0;
+#endif
+	txq->txq_nactive = 0;
+	txq->txq_fi = 0;
+	txq->txq_lo = 0;
+#ifndef __rtems__
+	txq->txq_ei_gapcount = 0;
+	txq->txq_inptr = GE_TXBUF_SIZE;
+	txq->txq_outptr = 0;
+#endif
+	for (i = 0, txd = txq->txq_descs,
+	     addr = txq->txq_desc_busaddr + sizeof(*txd);
+			i < GE_TXDESC_MAX - 1;
+			i++, txd++, addr += sizeof(*txd)) {
+		/*
+		 * update the nxtptr to point to the next txd.
+		 */
+		txd->ed_cmdsts = 0;
+		txd->ed_nxtptr = htogt32(addr);
+	}
+	txq->txq_descs[GE_TXDESC_MAX-1].ed_nxtptr =
+	    htogt32(txq->txq_desc_busaddr);
+	bus_dmamap_sync(sc->sc_dmat, txq->txq_desc_mem.gdm_map, 0,
+	    GE_TXDESC_MEMSIZE, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+
+	switch (txprio) {
+	case GE_TXPRIO_HI:
+		txq->txq_intrbits = ETH_IR_TxEndHigh|ETH_IR_TxBufferHigh;
+		txq->txq_esdcmrbits = ETH_ESDCMR_TXDH;
+		txq->txq_epsrbits = ETH_EPSR_TxHigh;
+		txq->txq_ectdp = ETH_ECTDP1(sc->sc_macno);
+		GE_WRITE(sc, ECTDP1, txq->txq_desc_busaddr);
+		break;
+
+	case GE_TXPRIO_LO:
+		txq->txq_intrbits = ETH_IR_TxEndLow|ETH_IR_TxBufferLow;
+		txq->txq_esdcmrbits = ETH_ESDCMR_TXDL;
+		txq->txq_epsrbits = ETH_EPSR_TxLow;
+		txq->txq_ectdp = ETH_ECTDP0(sc->sc_macno);
+		GE_WRITE(sc, ECTDP0, txq->txq_desc_busaddr);
+		break;
+
+	case GE_TXPRIO_NONE:
+		break;
+	}
+#if 0
+	GE_DPRINTF(sc, ("(ectdp=%#x", txq->txq_ectdp));
+	gt_write(sc->sc_dev.dv_parent, txq->txq_ectdp, txq->txq_desc_busaddr);
+	GE_DPRINTF(sc, (")"));
+#endif
+
+	/*
+	 * If we are restarting, there may be packets in the pending queue
+	 * waiting to be enqueued.  Try enqueuing packets from both priority
+	 * queues until the pending queue is empty or there no room for them
+	 * on the device.
+	 */
+	while (gfe_tx_enqueue(sc, txprio))
+		continue;
+
+	GE_FUNC_EXIT(sc, "");
+	return 0;
+}
+
+void
+gfe_tx_cleanup(struct gfe_softc *sc, enum gfe_txprio txprio, int flush)
+{
+	struct gfe_txqueue * const txq = &sc->sc_txq[txprio];
+
+	GE_FUNC_ENTER(sc, "gfe_tx_cleanup");
+	if (txq == NULL) {
+		GE_FUNC_EXIT(sc, "");
+		return;
+	}
+
+	if (!flush) {
+		GE_FUNC_EXIT(sc, "");
+		return;
+	}
+
+#ifdef __rtems__
+	/* reclaim mbufs that were never sent */
+	{
+	struct mbuf *m;
+		while ( txq->txq_sentq.ifq_head ) {
+			IF_DEQUEUE(&txq->txq_sentq, m);
+			m_freem(m);
+		}
+	}
+#endif
+
+	if ((sc->sc_flags & GE_NOFREE) == 0) {
+		gfe_dmamem_free(sc, &txq->txq_desc_mem);
+#ifndef __rtems__
+		gfe_dmamem_free(sc, &txq->txq_buf_mem);
+#endif
+	}
+	GE_FUNC_EXIT(sc, "-F");
+}
+
+void
+gfe_tx_stop(struct gfe_softc *sc, enum gfe_whack_op op)
+{
+	GE_FUNC_ENTER(sc, "gfe_tx_stop");
+
+	GE_WRITE(sc, ESDCMR, ETH_ESDCMR_STDH|ETH_ESDCMR_STDL);
+
+	sc->sc_intrmask = gfe_tx_done(sc, GE_TXPRIO_HI, sc->sc_intrmask);
+	sc->sc_intrmask = gfe_tx_done(sc, GE_TXPRIO_LO, sc->sc_intrmask);
+	sc->sc_intrmask &= ~(ETH_IR_TxEndHigh|ETH_IR_TxBufferHigh|
+			     ETH_IR_TxEndLow |ETH_IR_TxBufferLow);
+
+	gfe_tx_cleanup(sc, GE_TXPRIO_HI, op == GE_WHACK_STOP);
+	gfe_tx_cleanup(sc, GE_TXPRIO_LO, op == GE_WHACK_STOP);
+
+	sc->sc_ec.ec_if.if_timer = 0;
+	GE_FUNC_EXIT(sc, "");
+}
+
+
+int
+gfe_intr(void *arg)
+{
+	struct gfe_softc * const sc = arg;
+	uint32_t cause;
+	uint32_t intrmask = sc->sc_intrmask;
+	int claim = 0;
+	int cnt;
+
+	GE_FUNC_ENTER(sc, "gfe_intr");
+
+	for (cnt = 0; cnt < 4; cnt++) {
+		if (sc->sc_intrmask != intrmask) {
+			sc->sc_intrmask = intrmask;
+			GE_WRITE(sc, EIMR, sc->sc_intrmask);
+		}
+		cause = GE_READ(sc, EICR);
+		cause &= sc->sc_intrmask;
+		GE_DPRINTF(sc, (".%#" PRIx32, cause));
+		if (cause == 0)
+			break;
+
+		claim = 1;
+
+		GE_WRITE(sc, EICR, ~cause);
+#ifndef GE_NORX
+		if (cause & (ETH_IR_RxBuffer|ETH_IR_RxError))
+			intrmask = gfe_rx_process(sc, cause, intrmask);
+#endif
+
+#ifndef GE_NOTX
+		if (cause & (ETH_IR_TxBufferHigh|ETH_IR_TxEndHigh))
+			intrmask = gfe_tx_done(sc, GE_TXPRIO_HI, intrmask);
+		if (cause & (ETH_IR_TxBufferLow|ETH_IR_TxEndLow))
+			intrmask = gfe_tx_done(sc, GE_TXPRIO_LO, intrmask);
+#endif
+		if (cause & ETH_IR_MIIPhySTC) {
+			sc->sc_flags |= GE_PHYSTSCHG;
+			/* intrmask &= ~ETH_IR_MIIPhySTC; */
+		}
+	}
+
+	while (gfe_tx_enqueue(sc, GE_TXPRIO_HI))
+		continue;
+	while (gfe_tx_enqueue(sc, GE_TXPRIO_LO))
+		continue;
+
+	GE_FUNC_EXIT(sc, "");
+	return claim;
+}
+
+
+#ifndef __rtems__
+int
+gfe_mii_mediachange (struct ifnet *ifp)
+{
+	struct gfe_softc *sc = ifp->if_softc;
+
+	if (ifp->if_flags & IFF_UP)
+		mii_mediachg(&sc->sc_mii);
+
+	return (0);
+}
+void
+gfe_mii_mediastatus (struct ifnet *ifp, struct ifmediareq *ifmr)
+{
+	struct gfe_softc *sc = ifp->if_softc;
+
+	if (sc->sc_flags & GE_PHYSTSCHG) {
+		sc->sc_flags &= ~GE_PHYSTSCHG;
+		mii_pollstat(&sc->sc_mii);
+	}
+	ifmr->ifm_status = sc->sc_mii.mii_media_status;
+	ifmr->ifm_active = sc->sc_mii.mii_media_active;
+}
+
+int
+gfe_mii_read (struct device *self, int phy, int reg)
+{
+	return gt_mii_read(self, self->dv_parent, phy, reg);
+}
+
+void
+gfe_mii_write (struct device *self, int phy, int reg, int value)
+{
+	gt_mii_write(self, self->dv_parent, phy, reg, value);
+}
+
+void
+gfe_mii_statchg (struct device *self)
+{
+	/* struct gfe_softc *sc = (struct gfe_softc *) self; */
+	/* do nothing? */
+}
+
+
+#else
+int
+gfe_mii_read(int phy, void *arg, unsigned reg, uint32_t *pval)
+{
+	struct gfe_softc *sc = arg;
+	uint32_t data;
+	int count = 10000;
+
+	if ( 0 != phy )
+		return -1; /* invalid index */
+
+	phy = sc->sc_phyaddr;
+
+	do {
+		DELAY(10);
+		data = GT_READ(sc, ETH_ESMIR);
+	} while ((data & ETH_ESMIR_Busy) && count-- > 0);
+
+	if (count == 0) {
+		fprintf(stderr,"%s: mii read for phy %d reg %d busied out\n",
+			sc->sc_dev.dv_xname, phy, reg);
+		*pval = ETH_ESMIR_Value_GET(data);
+		return -1;
+	}
+
+	GT_WRITE(sc, ETH_ESMIR, ETH_ESMIR_READ(phy, reg));
+
+	count = 10000;
+	do {
+		DELAY(10);
+		data = GT_READ(sc, ETH_ESMIR);
+	} while ((data & ETH_ESMIR_ReadValid) == 0 && count-- > 0);
+
+	if (count == 0)
+		printf("%s: mii read for phy %d reg %d timed out\n",
+			sc->sc_dev.dv_xname, phy, reg);
+#if defined(GTMIIDEBUG)
+	printf("%s: mii_read(%d, %d): %#x data %#x\n",
+		sc->sc_dev.dv_xname, phy, reg, 
+		data, ETH_ESMIR_Value_GET(data));
+#endif
+	*pval = ETH_ESMIR_Value_GET(data);
+	return 0;
+}
+
+int
+gfe_mii_write(int phy, void *arg, unsigned reg, uint32_t value)
+{
+	struct gfe_softc *sc = arg;
+	uint32_t data;
+	int count = 10000;
+
+	if ( 0 != phy )
+		return -1; /* invalid index */
+
+	phy = sc->sc_phyaddr;
+
+	do {
+		DELAY(10);
+		data = GT_READ(sc, ETH_ESMIR);
+	} while ((data & ETH_ESMIR_Busy) && count-- > 0);
+
+	if (count == 0) {
+		fprintf(stderr, "%s: mii write for phy %d reg %d busied out (busy)\n",
+			sc->sc_dev.dv_xname, phy, reg);
+		return -1;
+	}
+
+	GT_WRITE(sc, ETH_ESMIR,
+		 ETH_ESMIR_WRITE(phy, reg, value));
+
+	count = 10000;
+	do {
+		DELAY(10);
+		data = GT_READ(sc, ETH_ESMIR);
+	} while ((data & ETH_ESMIR_Busy) && count-- > 0);
+
+	if (count == 0)
+		printf("%s: mii write for phy %d reg %d timed out\n",
+			sc->sc_dev.dv_xname, phy, reg);
+#if defined(GTMIIDEBUG)
+	printf("%s: mii_write(%d, %d, %#x)\n", 
+		sc->sc_dev.dv_xname, phy, reg, value);
+#endif
+	return 0;
+}
+
+
+#endif
+int
+gfe_whack(struct gfe_softc *sc, enum gfe_whack_op op)
+{
+	int error = 0;
+	GE_FUNC_ENTER(sc, "gfe_whack");
+
+	switch (op) {
+	case GE_WHACK_RESTART:
+#ifndef GE_NOTX
+		gfe_tx_stop(sc, op);
+#endif
+		/* sc->sc_ec.ec_if.if_flags &= ~IFF_RUNNING; */
+		/* FALLTHROUGH */
+	case GE_WHACK_START:
+#ifndef GE_NOHASH
+		if (error == 0 && sc->sc_hashtable == NULL) {
+			error = gfe_hash_alloc(sc);
+			if (error)
+				break;
+		}
+		if (op != GE_WHACK_RESTART)
+			gfe_hash_fill(sc);
+#endif
+#ifndef GE_NORX
+		if (op != GE_WHACK_RESTART) {
+			error = gfe_rx_prime(sc);
+			if (error)
+				break;
+		}
+#endif
+#ifndef GE_NOTX
+		error = gfe_tx_start(sc, GE_TXPRIO_HI);
+		if (error)
+			break;
+#endif
+		sc->sc_ec.ec_if.if_flags |= IFF_RUNNING;
+		GE_WRITE(sc, EPCR, sc->sc_pcr | ETH_EPCR_EN);
+		GE_WRITE(sc, EPCXR, sc->sc_pcxr);
+		GE_WRITE(sc, EICR, 0);
+		GE_WRITE(sc, EIMR, sc->sc_intrmask);
+#ifndef GE_NOHASH
+		GE_WRITE(sc, EHTPR, sc->sc_hash_mem.gdm_map->dm_segs->ds_addr);
+#endif
+#ifndef GE_NORX
+		GE_WRITE(sc, ESDCMR, ETH_ESDCMR_ERD);
+		sc->sc_flags |= GE_RXACTIVE;
+#endif
+		/* FALLTHROUGH */
+	case GE_WHACK_CHANGE:
+		GE_DPRINTF(sc, ("(pcr=%#" PRIx32 ",imr=%#" PRIx32 ")",
+		    GE_READ(sc, EPCR), GE_READ(sc, EIMR)));
+		GE_WRITE(sc, EPCR, sc->sc_pcr | ETH_EPCR_EN);
+		GE_WRITE(sc, EIMR, sc->sc_intrmask);
+		gfe_ifstart(&sc->sc_ec.ec_if);
+		GE_DPRINTF(sc, ("(ectdp0=%#" PRIx32 ", ectdp1=%#" PRIx32 ")",
+		    GE_READ(sc, ECTDP0), GE_READ(sc, ECTDP1)));
+		GE_FUNC_EXIT(sc, "");
+		return error;
+	case GE_WHACK_STOP:
+		break;
+	}
+
+#ifdef GE_DEBUG
+	if (error)
+		GE_DPRINTF(sc, (" failed: %d\n", error));
+#endif
+	GE_WRITE(sc, EPCR, sc->sc_pcr);
+	GE_WRITE(sc, EIMR, 0);
+	sc->sc_ec.ec_if.if_flags &= ~IFF_RUNNING;
+#ifndef GE_NOTX
+	gfe_tx_stop(sc, GE_WHACK_STOP);
+#endif
+#ifndef GE_NORX
+	gfe_rx_stop(sc, GE_WHACK_STOP);
+#endif
+#ifndef GE_NOHASH
+	if ((sc->sc_flags & GE_NOFREE) == 0) {
+		gfe_dmamem_free(sc, &sc->sc_hash_mem);
+		sc->sc_hashtable = NULL;
+	}
+#endif
+
+	GE_FUNC_EXIT(sc, "");
+	return error;
+}
+
+
+int
+gfe_hash_compute(struct gfe_softc *sc, const uint8_t eaddr[ETHER_ADDR_LEN])
+{
+	uint32_t w0, add0, add1;
+	uint32_t result;
+#ifdef __rtems__
+	SPRINTFVARDECL;
+#endif
+
+	GE_FUNC_ENTER(sc, "gfe_hash_compute");
+	add0 = ((uint32_t) eaddr[5] <<  0) |
+	       ((uint32_t) eaddr[4] <<  8) |
+	       ((uint32_t) eaddr[3] << 16);
+
+	add0 = ((add0 & 0x00f0f0f0) >> 4) | ((add0 & 0x000f0f0f) << 4);
+	add0 = ((add0 & 0x00cccccc) >> 2) | ((add0 & 0x00333333) << 2);
+	add0 = ((add0 & 0x00aaaaaa) >> 1) | ((add0 & 0x00555555) << 1);
+
+	add1 = ((uint32_t) eaddr[2] <<  0) |
+	       ((uint32_t) eaddr[1] <<  8) |
+	       ((uint32_t) eaddr[0] << 16);
+
+	add1 = ((add1 & 0x00f0f0f0) >> 4) | ((add1 & 0x000f0f0f) << 4);
+	add1 = ((add1 & 0x00cccccc) >> 2) | ((add1 & 0x00333333) << 2);
+	add1 = ((add1 & 0x00aaaaaa) >> 1) | ((add1 & 0x00555555) << 1);
+
+	GE_DPRINTF(sc, ("%s=", ether_sprintf(eaddr)));
+	/*
+	 * hashResult is the 15 bits Hash entry address.
+	 * ethernetADD is a 48 bit number, which is derived from the Ethernet
+	 *	MAC address, by nibble swapping in every byte (i.e MAC address
+	 *	of 0x123456789abc translates to ethernetADD of 0x21436587a9cb).
+	 */
+
+	if ((sc->sc_pcr & ETH_EPCR_HM) == 0) {
+		/*
+		 * hashResult[14:0] = hashFunc0(ethernetADD[47:0])
+		 *
+		 * hashFunc0 calculates the hashResult in the following manner:
+		 *   hashResult[ 8:0] = ethernetADD[14:8,1,0]
+		 *		XOR ethernetADD[23:15] XOR ethernetADD[32:24]
+		 */
+		result = (add0 & 3) | ((add0 >> 6) & ~3);
+		result ^= (add0 >> 15) ^ (add1 >>  0);
+		result &= 0x1ff;
+		/*
+		 *   hashResult[14:9] = ethernetADD[7:2]
+		 */
+		result |= (add0 & ~3) << 7;	/* excess bits will be masked */
+		GE_DPRINTF(sc, ("0(%#"PRIx32")", result & 0x7fff));
+	} else {
+#define	TRIBITFLIP	073516240	/* yes its in octal */
+		/*
+		 * hashResult[14:0] = hashFunc1(ethernetADD[47:0])
+		 *
+		 * hashFunc1 calculates the hashResult in the following manner:
+		 *   hashResult[08:00] = ethernetADD[06:14]
+		 *		XOR ethernetADD[15:23] XOR ethernetADD[24:32]
+		 */
+		w0 = ((add0 >> 6) ^ (add0 >> 15) ^ (add1)) & 0x1ff;
+		/*
+		 * Now bitswap those 9 bits
+		 */
+		result = 0;
+		result |= ((TRIBITFLIP >> (((w0 >> 0) & 7) * 3)) & 7) << 6;
+		result |= ((TRIBITFLIP >> (((w0 >> 3) & 7) * 3)) & 7) << 3;
+		result |= ((TRIBITFLIP >> (((w0 >> 6) & 7) * 3)) & 7) << 0;
+
+		/*
+		 *   hashResult[14:09] = ethernetADD[00:05]
+		 */
+		result |= ((TRIBITFLIP >> (((add0 >> 0) & 7) * 3)) & 7) << 12;
+		result |= ((TRIBITFLIP >> (((add0 >> 3) & 7) * 3)) & 7) << 9;
+		GE_DPRINTF(sc, ("1(%#"PRIx32")", result));
+	}
+	GE_FUNC_EXIT(sc, "");
+	return result & ((sc->sc_pcr & ETH_EPCR_HS_512) ? 0x7ff : 0x7fff);
+}
+
+int
+gfe_hash_entry_op(struct gfe_softc *sc, enum gfe_hash_op op,
+	enum gfe_rxprio prio, const uint8_t eaddr[ETHER_ADDR_LEN])
+{
+	uint64_t he;
+	uint64_t *maybe_he_p = NULL;
+	int limit;
+	int hash;
+	int maybe_hash = 0;
+
+	GE_FUNC_ENTER(sc, "gfe_hash_entry_op");
+
+	hash = gfe_hash_compute(sc, eaddr);
+
+	if (sc->sc_hashtable == NULL) {
+		panic("%s:%d: hashtable == NULL!", sc->sc_dev.dv_xname,
+			__LINE__);
+	}
+
+	/*
+	 * Assume we are going to insert so create the hash entry we
+	 * are going to insert.  We also use it to match entries we
+	 * will be removing.
+	 */
+	he = ((uint64_t) eaddr[5] << 43) |
+	     ((uint64_t) eaddr[4] << 35) |
+	     ((uint64_t) eaddr[3] << 27) |
+	     ((uint64_t) eaddr[2] << 19) |
+	     ((uint64_t) eaddr[1] << 11) |
+	     ((uint64_t) eaddr[0] <<  3) |
+	     HSH_PRIO_INS(prio) | HSH_V | HSH_R;
+
+	/*
+	 * The GT will search upto 12 entries for a hit, so we must mimic that.
+	 */
+	hash &= sc->sc_hashmask / sizeof(he);
+	for (limit = HSH_LIMIT; limit > 0 ; --limit) {
+		/*
+		 * Does the GT wrap at the end, stop at the, or overrun the
+		 * end?  Assume it wraps for now.  Stash a copy of the
+		 * current hash entry.
+		 */
+		uint64_t *he_p = &sc->sc_hashtable[hash];
+		uint64_t thishe = *he_p;
+
+		/*
+		 * If the hash entry isn't valid, that break the chain.  And
+		 * this entry a good candidate for reuse.
+		 */
+		if ((thishe & HSH_V) == 0) {
+			maybe_he_p = he_p;
+			break;
+		}
+
+		/*
+		 * If the hash entry has the same address we are looking for
+		 * then ...  if we are removing and the skip bit is set, its
+		 * already been removed.  if are adding and the skip bit is
+		 * clear, then its already added.  In either return EBUSY
+		 * indicating the op has already been done.  Otherwise flip
+		 * the skip bit and return 0.
+		 */
+		if (((he ^ thishe) & HSH_ADDR_MASK) == 0) {
+			if (((op == GE_HASH_REMOVE) && (thishe & HSH_S)) ||
+			    ((op == GE_HASH_ADD) && (thishe & HSH_S) == 0))
+				return EBUSY;
+			*he_p = thishe ^ HSH_S;
+			bus_dmamap_sync(sc->sc_dmat, sc->sc_hash_mem.gdm_map,
+			    hash * sizeof(he), sizeof(he),
+			    BUS_DMASYNC_PREWRITE);
+			GE_FUNC_EXIT(sc, "^");
+			return 0;
+		}
+
+		/*
+		 * If we haven't found a slot for the entry and this entry
+		 * is currently being skipped, return this entry.
+		 */
+		if (maybe_he_p == NULL && (thishe & HSH_S)) {
+			maybe_he_p = he_p;
+			maybe_hash = hash;
+		}
+
+		hash = (hash + 1) & (sc->sc_hashmask / sizeof(he));
+	}
+
+	/*
+	 * If we got here, then there was no entry to remove.
+	 */
+	if (op == GE_HASH_REMOVE) {
+		GE_FUNC_EXIT(sc, "?");
+		return ENOENT;
+	}
+
+	/*
+	 * If we couldn't find a slot, return an error.
+	 */
+	if (maybe_he_p == NULL) {
+		GE_FUNC_EXIT(sc, "!");
+		return ENOSPC;
+	}
+
+	/* Update the entry.
+	 */
+	*maybe_he_p = he;
+	bus_dmamap_sync(sc->sc_dmat, sc->sc_hash_mem.gdm_map,
+	    maybe_hash * sizeof(he), sizeof(he), BUS_DMASYNC_PREWRITE);
+	GE_FUNC_EXIT(sc, "+");
+	return 0;
+}
+
+#ifndef __rtems__
+int
+gfe_hash_multichg(struct ethercom *ec, const struct ether_multi *enm, u_long cmd)
+{
+	struct gfe_softc * const sc = ec->ec_if.if_softc;
+	int error;
+	enum gfe_hash_op op;
+	enum gfe_rxprio prio;
+#ifdef __rtems__
+	SPRINTFVARDECL;
+#endif
+
+	GE_FUNC_ENTER(sc, "hash_multichg");
+	/*
+	 * Is this a wildcard entry?  If so and its being removed, recompute.
+	 */
+	if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN) != 0) {
+		if (cmd == SIOCDELMULTI) {
+			GE_FUNC_EXIT(sc, "");
+			return ENETRESET;
+		}
+
+		/*
+		 * Switch in
+		 */
+		sc->sc_flags |= GE_ALLMULTI;
+		if ((sc->sc_pcr & ETH_EPCR_PM) == 0) {
+			sc->sc_pcr |= ETH_EPCR_PM;
+			GE_WRITE(sc, EPCR, sc->sc_pcr);
+			GE_FUNC_EXIT(sc, "");
+			return 0;
+		}
+		GE_FUNC_EXIT(sc, "");
+		return ENETRESET;
+	}
+
+	prio = GE_RXPRIO_MEDLO;
+	op = (cmd == SIOCDELMULTI ? GE_HASH_REMOVE : GE_HASH_ADD);
+
+	if (sc->sc_hashtable == NULL) {
+		GE_FUNC_EXIT(sc, "");
+		return 0;
+	}
+
+	error = gfe_hash_entry_op(sc, op, prio, enm->enm_addrlo);
+	if (error == EBUSY) {
+		printf("%s: multichg: tried to %s %s again\n",
+		       sc->sc_dev.dv_xname,
+		       cmd == SIOCDELMULTI ? "remove" : "add",
+		       ether_sprintf(enm->enm_addrlo));
+		GE_FUNC_EXIT(sc, "");
+		return 0;
+	}
+
+	if (error == ENOENT) {
+		printf("%s: multichg: failed to remove %s: not in table\n",
+		       sc->sc_dev.dv_xname,
+		       ether_sprintf(enm->enm_addrlo));
+		GE_FUNC_EXIT(sc, "");
+		return 0;
+	}
+
+	if (error == ENOSPC) {
+		printf("%s: multichg: failed to add %s: no space; regenerating table\n",
+		       sc->sc_dev.dv_xname,
+		       ether_sprintf(enm->enm_addrlo));
+		GE_FUNC_EXIT(sc, "");
+		return ENETRESET;
+	}
+	GE_DPRINTF(sc, ("%s: multichg: %s: %s succeeded\n",
+	       sc->sc_dev.dv_xname,
+	       cmd == SIOCDELMULTI ? "remove" : "add",
+	       ether_sprintf(enm->enm_addrlo)));
+	GE_FUNC_EXIT(sc, "");
+	return 0;
+}
+#endif
+
+int
+gfe_hash_fill(struct gfe_softc *sc)
+{
+	struct ether_multistep step;
+	struct ether_multi *enm;
+	int error;
+
+	GE_FUNC_ENTER(sc, "gfe_hash_fill");
+
+#ifndef __rtems__
+	error = gfe_hash_entry_op(sc, GE_HASH_ADD, GE_RXPRIO_HI,
+	    LLADDR(sc->sc_ec.ec_if.if_sadl));
+#else
+	error = gfe_hash_entry_op(sc, GE_HASH_ADD, GE_RXPRIO_HI, sc->sc_ec.ac_enaddr);
+#endif
+	if (error) {
+		GE_FUNC_EXIT(sc, "!");
+		return error;
+	}
+
+	sc->sc_flags &= ~GE_ALLMULTI;
+	if ((sc->sc_ec.ec_if.if_flags & IFF_PROMISC) == 0)
+		sc->sc_pcr &= ~ETH_EPCR_PM;
+	else
+		sc->sc_pcr |=  ETH_EPCR_PM;
+	ETHER_FIRST_MULTI(step, &sc->sc_ec, enm);
+	while (enm != NULL) {
+		if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) {
+			sc->sc_flags |= GE_ALLMULTI;
+			sc->sc_pcr |= ETH_EPCR_PM;
+		} else {
+			error = gfe_hash_entry_op(sc, GE_HASH_ADD,
+			    GE_RXPRIO_MEDLO, enm->enm_addrlo);
+			if (error == ENOSPC)
+				break;
+		}
+		ETHER_NEXT_MULTI(step, enm);
+	}
+
+	GE_FUNC_EXIT(sc, "");
+	return error;
+}
+
+int
+gfe_hash_alloc(struct gfe_softc *sc)
+{
+	int error;
+	GE_FUNC_ENTER(sc, "gfe_hash_alloc");
+	sc->sc_hashmask = (sc->sc_pcr & ETH_EPCR_HS_512 ? 16 : 256)*1024 - 1;
+	error = gfe_dmamem_alloc(sc, &sc->sc_hash_mem, 1, sc->sc_hashmask + 1,
+	    BUS_DMA_NOCACHE);
+	if (error) {
+		printf("%s: failed to allocate %d bytes for hash table: %d\n",
+		    sc->sc_dev.dv_xname, sc->sc_hashmask + 1, error);
+		GE_FUNC_EXIT(sc, "");
+		return error;
+	}
+	sc->sc_hashtable = (uint64_t *) sc->sc_hash_mem.gdm_kva;
+	memset(sc->sc_hashtable, 0, sc->sc_hashmask + 1);
+	bus_dmamap_sync(sc->sc_dmat, sc->sc_hash_mem.gdm_map,
+	    0, sc->sc_hashmask + 1, BUS_DMASYNC_PREWRITE);
+	GE_FUNC_EXIT(sc, "");
+	return 0;
+}
Index: bsps/powerpc/beatnik/net/if_gfe/if_gfe_rtems.c
===================================================================
--- bsps/powerpc/beatnik/net/if_gfe/if_gfe_rtems.c	(revision 031df3914990db0336a0d386fb53558b05de467e)
+++ bsps/powerpc/beatnik/net/if_gfe/if_gfe_rtems.c	(revision 031df3914990db0336a0d386fb53558b05de467e)
@@ -0,0 +1,129 @@
+/* Author: T. Straumann <strauman@slac.stanford.edu>; see ../../LICENSE */
+#include "rtemscompat_defs.h"
+#include "../porting/rtemscompat.h"
+#include "gtethreg.h"
+
+#include <bsp/early_enet_link_status.h>
+#include <bsp/if_gfe_pub.h>
+#include <bsp/irq.h>
+
+/* from if_gfe.c */
+#define	GE_READ(sc, reg) \
+	bus_space_read_4((sc)->sc_gt_memt, (sc)->sc_memh, ETH__ ## reg)
+#define	GE_WRITE(sc, reg, v) \
+	bus_space_write_4((sc)->sc_gt_memt, (sc)->sc_memh, ETH__ ## reg, (v))
+
+#define	GT_READ(sc, reg) \
+	bus_space_read_4((sc)->sc_gt_memt, (sc)->sc_gt_memh, reg)
+#define	GT_WRITE(sc, reg, v) \
+	bus_space_write_4((sc)->sc_gt_memt, (sc)->sc_gt_memh, reg, (v))
+
+#include "../porting/if_xxx_rtems.c"
+
+#include <bsp.h>
+#include <libcpu/io.h>
+
+int
+NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_setup)(
+	int					unit,
+	char 				*ea,
+	uint32_t			base_addr)
+{
+struct NET_SOFTC *sc;
+
+	if ( !ea ) {
+		fprintf(stderr,"Station address argument missing\n");
+		return 0;
+	}
+
+	if ( !(sc=net_drv_check_unit(unit)) ) {
+		fprintf(stderr,"Bad unit number -- (not enought driver slots?)\n");
+		return 0;
+	}
+
+	unit--;
+
+#ifdef DEBUG_MODULAR
+	if ( !METHODSPTR ) {
+		fprintf(stderr,"Methods not set -- module not loaded?\n");
+		return 0;
+	}
+#endif
+
+	if ( !base_addr ) {
+#ifdef BSP_MV64x60_BASE
+		base_addr = BSP_MV64x60_BASE;
+#else
+		fprintf(stderr,"Missing GT64260 base address\n");
+		return 0;
+#endif
+	}
+	sc->sc_gt_memh = base_addr;
+	/* must set this as well to indicate that the device is set up */
+	sc->NET_SOFTC_BHANDLE_FIELD = base_addr + 0x2400 + (unit<<10);
+	sc->sc_macno   = unit;
+	memcpy( sc->arpcom.ac_enaddr, ea, ETHER_ADDR_LEN);
+
+	if ( 0 == METHODSPTR->n_probe(&THEDEVS[unit]) ) {
+		printf(NETDRIVER": Unit %i set up\n", unit + 1);
+		sc->irq_no = BSP_IRQ_ETH0 + unit;
+		return 1;
+	}
+	return 0;
+}
+
+static int
+gfe_early_init(int idx)
+{
+struct gfe_softc	*sc;
+uint32_t			d;
+
+	if ( idx < 0 || idx >= NETDRIVER_SLOTS )
+		return -1;
+
+	sc = device_get_softc(&the_gfe_devs[idx]);
+	d  = bus_space_read_4(sc->sc_gt_memt, sc->sc_gt_memh, ETH_EPAR);
+
+	sc->sc_phyaddr      = ETH_EPAR_PhyAD_GET(d, sc->sc_macno);
+	sc->sc_dev.dv_xname = NETDRIVER;
+	return 0;
+}
+
+static int
+gfe_early_read_phy(int idx, unsigned reg)
+{
+uint32_t rval;
+struct gfe_softc	*sc;
+
+	if ( idx < 0 || idx >= NETDRIVER_SLOTS )
+		return -1;
+
+	sc = device_get_softc(&the_gfe_devs[idx]);
+
+	if ( gfe_mii_read( 0, sc, reg, &rval) )
+		return -1;
+	return rval & 0xffff;
+}
+
+
+static int
+gfe_early_write_phy(int idx, unsigned reg, unsigned val)
+{
+struct gfe_softc	*sc;
+
+	if ( idx < 0 || idx >= NETDRIVER_SLOTS )
+		return -1;
+
+	sc = device_get_softc(&the_gfe_devs[idx]);
+
+	return gfe_mii_write( 0, sc, reg, val);
+}
+
+rtems_bsdnet_early_link_check_ops
+rtems_gfe_early_link_check_ops = {
+	init:		gfe_early_init,
+	read_phy:	gfe_early_read_phy,
+	write_phy:	gfe_early_write_phy,
+	name:		NETDRIVER,
+	num_slots:	NETDRIVER_SLOTS
+};
Index: bsps/powerpc/beatnik/net/if_gfe/if_gfevar.h
===================================================================
--- bsps/powerpc/beatnik/net/if_gfe/if_gfevar.h	(revision 031df3914990db0336a0d386fb53558b05de467e)
+++ bsps/powerpc/beatnik/net/if_gfe/if_gfevar.h	(revision 031df3914990db0336a0d386fb53558b05de467e)
@@ -0,0 +1,225 @@
+#ifndef IF_GFEVAR_H
+#define IF_GFEVAR_H
+/*	$NetBSD: if_gfevar.h,v 1.4.10.1 2005/04/29 11:28:56 kent Exp $	*/
+
+/*
+ * Copyright (c) 2002 Allegro Networks, Inc., Wasabi Systems, Inc.
+ * 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. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed for the NetBSD Project by
+ *      Allegro Networks, Inc., and Wasabi Systems, Inc.
+ * 4. The name of Allegro Networks, Inc. may not be used to endorse
+ *    or promote products derived from this software without specific prior
+ *    written permission.
+ * 5. The name of Wasabi Systems, Inc. may not be used to endorse
+ *    or promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ALLEGRO NETWORKS, INC. AND
+ * WASABI SYSTEMS, INC. ``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 EITHER ALLEGRO NETWORKS, INC. OR WASABI SYSTEMS, INC.
+ * 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.
+ */
+
+/* NOTE: GE_RXDESC_MAX * 16 <= GE_RXDESC_MEMSIZE */
+/* NOTE: the driver needs 4*GE_RXDESC_MAX mbuf clusters (4 queues) */
+#ifndef __rtems__
+#define	GE_RXDESC_MEMSIZE		(1 * PAGE_SIZE)
+#define	GE_RXDESC_MAX			64
+#define	GE_RXBUF_SIZE			2048
+#define	GE_RXBUF_MEMSIZE		(GE_RXDESC_MAX*GE_RXBUF_SIZE)
+#else
+#define GE_RXDESC_MEMSIZE		(GE_RXDESC_MAX * sizeof(struct gt_eth_desc))
+#define GE_RXDESC_MAX			(sc->num_rxdesc)
+#define GE_RXBUF_MEMSIZE		0
+#endif
+
+#define	GE_RXBUF_NSEGS			((GE_RXBUF_MEMSIZE/PAGE_SIZE)+1)
+#define	GE_DMSEG_MAX			(GE_RXBUF_NSEGS)
+
+struct gfe_dmamem {
+	bus_dmamap_t gdm_map;		/* dmamem'ed memory */
+#ifdef __rtems__
+	void		*gdm_unaligned_buf;
+#endif
+	caddr_t gdm_kva;		/* kva of tx memory */
+	int gdm_nsegs;			/* # of segment in gdm_segs */
+	int gdm_maxsegs;		/* maximum # of segments allowed */
+	size_t gdm_size;		/* size of memory region */
+	bus_dma_segment_t gdm_segs[GE_DMSEG_MAX]; /* dma segment of tx memory */
+};
+
+/* With a 4096 page size, we get 256 descriptors per page.
+ */
+#ifndef __rtems__
+#define	GE_TXDESC_MEMSIZE		(1 * PAGE_SIZE)
+#define	GE_TXDESC_MAX			(GE_TXDESC_MEMSIZE / 16)
+#define	GE_TXBUF_SIZE			(4 * PAGE_SIZE)
+#else
+#define	GE_TXDESC_MEMSIZE		(sc->num_txdesc * sizeof(struct gt_eth_desc))
+#define GE_TXDESC_MAX			(sc->num_txdesc)
+#endif
+
+struct gfe_txqueue {
+	struct ifqueue txq_pendq;	/* these are ready to go to the GT */
+	struct ifqueue txq_sentq;
+	struct gfe_dmamem txq_desc_mem;	/* transmit descriptor memory */
+#ifndef __rtems__
+	struct gfe_dmamem txq_buf_mem;	/* transmit buffer memory */
+#endif
+	unsigned int txq_lo;		/* next to be given to GT */
+	unsigned int txq_fi; 		/* next to be returned to CPU */
+#ifndef __rtems__
+	unsigned int txq_ei_gapcount;	/* counter until next EI */
+#endif
+	unsigned int txq_nactive;	/* number of active descriptors */
+#ifndef __rtems__
+	unsigned int txq_outptr;	/* where to put next transmit packet */
+	unsigned int txq_inptr;		/* start of 1st queued tx packet */
+#endif
+	uint32_t txq_intrbits;		/* bits to write to EIMR */
+	uint32_t txq_esdcmrbits;	/* bits to write to ESDCMR */
+	uint32_t txq_epsrbits;		/* bits to test with EPSR */
+	volatile struct gt_eth_desc *txq_descs; /* ptr to tx descriptors */
+	bus_addr_t txq_ectdp;		/* offset to cur. tx desc ptr reg */
+	bus_addr_t txq_desc_busaddr;	/* bus addr of tx descriptors */
+#ifndef __rtems__
+	bus_addr_t txq_buf_busaddr;	/* bus addr of tx buffers */
+#endif
+};
+
+/* With a 4096 page size, we get 256 descriptors per page.  We want 1024
+ * which will give us about 8ms of 64 byte packets (2ms for each priority
+ * queue).
+ */
+
+#ifndef __rtems__
+struct gfe_rxbuf {
+	uint8_t	rb_data[GE_RXBUF_SIZE];
+};
+#endif
+
+struct gfe_rxqueue {
+	struct gfe_dmamem rxq_desc_mem;	/* receive descriptor memory */
+#ifndef __rtems__
+	struct gfe_dmamem rxq_buf_mem;	/* receive buffer memory */
+	struct mbuf *rxq_curpkt;	/* mbuf for current packet */
+#endif
+	volatile struct gt_eth_desc *rxq_descs;
+#ifndef __rtems__
+	struct gfe_rxbuf *rxq_bufs;
+#else
+	struct mbuf **rxq_bufs;
+#endif
+	unsigned int rxq_fi; 		/* next to be returned to CPU */
+	unsigned int rxq_active;	/* # of descriptors given to GT */
+	uint32_t rxq_intrbits;		/* bits to write to EIMR */
+	bus_addr_t rxq_desc_busaddr;	/* bus addr of rx descriptors */
+	uint32_t rxq_cmdsts;		/* save cmdsts from first descriptor */
+	bus_size_t rxq_efrdp;
+	bus_size_t rxq_ecrdp;
+};
+
+enum gfe_txprio {
+	GE_TXPRIO_HI=1,
+	GE_TXPRIO_LO=0,
+	GE_TXPRIO_NONE=2
+};
+enum gfe_rxprio {
+	GE_RXPRIO_HI=3,
+	GE_RXPRIO_MEDHI=2,
+	GE_RXPRIO_MEDLO=1,
+	GE_RXPRIO_LO=0
+};
+
+#ifdef __rtems__
+#define	sc_ec		arpcom
+#define ec_if		ac_if
+#define sc_dev  	arpcom
+#define dv_xname	ac_if.if_name
+#endif
+
+struct gfe_softc {
+#ifndef __rtems__
+	struct device sc_dev;		/* must be first */
+	struct ethercom sc_ec;		/* common ethernet glue */
+	struct callout sc_co;		/* resource recovery */
+	mii_data_t sc_mii;		/* mii interface */
+
+	/*
+	 *
+	 */
+	bus_space_tag_t sc_gt_memt;
+	bus_space_handle_t sc_gt_memh;
+	bus_space_handle_t sc_memh;	/* subregion for ethernet */
+	bus_dma_tag_t sc_dmat;
+#else
+	struct arpcom	sc_ec;
+	unsigned		sc_gt_memh;
+	unsigned		sc_memh;
+	unsigned char	irq_no;
+	rtems_id		tid;
+	int				sc_phyaddr;
+	int				num_rxdesc, num_txdesc;
+#endif
+	int sc_macno;			/* which mac? 0, 1, or 2 */
+
+	unsigned int sc_tickflags;
+#define	GE_TICK_TX_IFSTART	0x0001
+#define	GE_TICK_RX_RESTART	0x0002
+	unsigned int sc_flags;
+#define	GE_ALLMULTI	0x0001
+#define	GE_PHYSTSCHG	0x0002
+#define	GE_RXACTIVE	0x0004
+#define	GE_NOFREE	0x0008		/* Don't free on disable */
+	uint32_t sc_pcr;		/* current EPCR value */
+	uint32_t sc_pcxr;		/* current EPCXR value */
+	uint32_t sc_intrmask;		/* current EIMR value */
+	uint32_t sc_idlemask;		/* suspended EIMR bits */
+	size_t sc_max_frame_length;	/* maximum frame length */
+
+	/*
+	 * Hash table related members
+	 */
+	struct gfe_dmamem sc_hash_mem;	/* dma'ble hash table */
+	uint64_t *sc_hashtable;
+	unsigned int sc_hashmask;	/* 0x1ff or 0x1fff */
+
+	/*
+	 * Transmit related members
+	 */
+	struct gfe_txqueue sc_txq[2];	/* High & Low transmit queues */
+
+	/*
+	 * Receive related members
+	 */
+	struct gfe_rxqueue sc_rxq[4];	/* Hi/MedHi/MedLo/Lo receive queues */
+};
+
+#ifdef __rtems__
+int
+gfe_mii_read(int phy, void *arg, unsigned reg, uint32_t *pval);
+
+int
+gfe_mii_write(int phy, void *arg, unsigned reg, uint32_t value);
+#endif
+
+#endif
Index: bsps/powerpc/beatnik/net/if_gfe/rtemscompat_defs.h
===================================================================
--- bsps/powerpc/beatnik/net/if_gfe/rtemscompat_defs.h	(revision 031df3914990db0336a0d386fb53558b05de467e)
+++ bsps/powerpc/beatnik/net/if_gfe/rtemscompat_defs.h	(revision 031df3914990db0336a0d386fb53558b05de467e)
@@ -0,0 +1,161 @@
+#ifndef RTEMS_COMPAT_DEFS_H
+#define RTEMS_COMPAT_DEFS_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+/* Number of device instances the driver should support
+ * - may be limited to 1 depending on IRQ API
+ * (braindamaged PC586 and powerpc)
+ */
+#define NETDRIVER_SLOTS 1
+/* String name to print with error messages */
+#define NETDRIVER       "gfe"
+/* Name snippet used to make global symbols unique to this driver */
+#define NETDRIVER_PREFIX gfe
+
+/* Define according to endianness of the *ethernet*chip*
+ * (not the CPU - most probably are LE)
+ * This must be either NET_CHIP_LE or NET_CHIP_BE
+ */
+
+#define NET_CHIP_LE
+#undef  NET_CHIP_BE
+
+/* Define either NET_CHIP_MEM_IO or NET_CHIP_PORT_IO,
+ * depending whether the CPU sees it in memory address space
+ * or (e.g. x86) uses special I/O instructions.
+ */
+#define NET_CHIP_MEM_IO
+#undef  NET_CHIP_PORT_IO
+
+/* The name of the hijacked 'bus handle' field in the softc
+ * structure. We use this field to store the chip's base address.
+ */
+#define NET_SOFTC_BHANDLE_FIELD sc_memh
+
+/* define the names of the 'if_XXXreg.h' and 'if_XXXvar.h' headers
+ * (only if present, i.e., if the BSDNET driver has no respective
+ * header, leave this undefined).
+ *
+ */
+#undef  IF_REG_HEADER
+#define  IF_VAR_HEADER "../if_gfe/if_gfevar.h"
+
+/* define if a pci device */
+/*
+#define NETDRIVER_PCI <bsp/pci.h>
+*/
+#undef NETDRIVER_PCI
+
+/* Macros to disable and enable interrupts, respectively.
+ * The 'disable' macro is expanded in the ISR, the 'enable'
+ * macro is expanded in the driver task.
+ * The global network semaphore usually provides mutex
+ * protection of the device registers.
+ * Special care must be taken when coding the 'disable' macro,
+ * however to MAKE SURE THERE ARE NO OTHER SIDE EFFECTS such
+ * as:
+ *    - macro must not clear any status flags
+ *    - macro must save/restore any context information
+ *      (e.g., a address register pointer or a bank switch register)
+ *
+ * ARGUMENT: the macro arg is a pointer to the driver's 'softc' structure
+ */
+
+#define NET_DISABLE_IRQS(sc)	GE_WRITE(sc, EIMR, 0)
+#define NET_ENABLE_IRQS(sc)		GE_WRITE(sc, EIMR, sc->sc_intrmask)
+
+/* Driver may provide a macro/function to copy the hardware address
+ * from the device into 'softc.arpcom'.
+ * If this is undefined, the driver must to the copy itself.
+ * Preferrably, it should check soft.arpcom.ac_enaddr for all
+ * zeros and leave it alone if it is nonzero, i.e., write it
+ * to the hardware.
+#define NET_READ_MAC_ADDR(sc)
+ */
+
+typedef struct {
+	uint32_t	ds_addr;
+	uint32_t	ds_len;
+} bus_dma_segment_t;
+
+#define dm_segs		gdm_segs
+#define dm_nsegs	gdm_nsegs
+typedef struct gfe_dmamem *bus_dmamap_t;
+
+typedef uint32_t bus_addr_t;
+typedef uint32_t bus_size_t;
+
+typedef struct device blah;
+
+#define BUS_DMA_NOCACHE	0xdeadbeef
+
+#ifdef __PPC__
+#define bus_dmamap_sync(args...) do { __asm__ volatile("sync":::"memory"); } while(0)
+#else
+#error "Dont' know how to sync memory on your CPU"
+#endif
+
+int	ether_sprintf_r(const unsigned char *enaddr, char *buf, int len);
+
+/* we have it although we're not ansi */
+int snprintf(char *, size_t, const char *,...);
+
+#include <string.h>
+
+/* declare in every routine using ether_sprintf */
+#define SPRINTFVARDECL	char rtems_sprintf_local_buf[3*6]	/* ethernet string */
+
+#define ether_sprintf_macro(a)					\
+	(snprintf(rtems_sprintf_local_buf,			\
+			sizeof(rtems_sprintf_local_buf),	\
+			"%02X:%02X:%02X:%02X:%02X:%02X",	\
+			a[0],a[1],a[2],a[3],a[4],a[5]) ? 	\
+			rtems_sprintf_local_buf : 0		\
+	)
+
+
+#define aprint_normal(args...)	printf(args)
+#define aprint_error(args...)	fprintf(stderr,args)
+
+#define delay(arg)	DELAY(arg)
+
+#define KASSERT(a...) do {} while (0)
+
+#define gfe_assign_desc _bsd_gfe_assign_desc
+#define gfe_attach _bsd_gfe_attach
+#define gfe_dbg_config _bsd_gfe_dbg_config
+#define gfe_dmamem_alloc _bsd_gfe_dmamem_alloc
+#define gfe_dmamem_free _bsd_gfe_dmamem_free
+#define gfe_hash_alloc _bsd_gfe_hash_alloc
+#define gfe_hash_compute _bsd_gfe_hash_compute
+#define gfe_hash_entry_op _bsd_gfe_hash_entry_op
+#define gfe_hash_fill _bsd_gfe_hash_fill
+#define gfe_ifioctl _bsd_gfe_ifioctl
+#define gfe_ifstart _bsd_gfe_ifstart
+#define gfe_ifwatchdog _bsd_gfe_ifwatchdog
+#define gfe_init _bsd_gfe_init
+#define gfe_intr _bsd_gfe_intr
+#define gfe_mdio_access _bsd_gfe_mdio_access
+#define gfe_mii_read _bsd_gfe_mii_read
+#define gfe_mii_write _bsd_gfe_mii_write
+#define gfe_probe _bsd_gfe_probe
+#define gfe_rx_cleanup _bsd_gfe_rx_cleanup
+#define gfe_rx_get _bsd_gfe_rx_get
+#define gfe_rx_prime _bsd_gfe_rx_prime
+#define gfe_rx_process _bsd_gfe_rx_process
+#define gfe_rx_rxqalloc _bsd_gfe_rx_rxqalloc
+#define gfe_rx_rxqinit _bsd_gfe_rx_rxqinit
+#define gfe_rx_stop _bsd_gfe_rx_stop
+#define gfe_tick _bsd_gfe_tick
+#define gfe_tx_cleanup _bsd_gfe_tx_cleanup
+#define gfe_tx_done _bsd_gfe_tx_done
+#define gfe_tx_enqueue _bsd_gfe_tx_enqueue
+#define gfe_tx_start _bsd_gfe_tx_start
+#define gfe_tx_stop _bsd_gfe_tx_stop
+#define gfe_tx_txqalloc _bsd_gfe_tx_txqalloc
+#define gfe_whack _bsd_gfe_whack
+#define the_gfe_devs _bsd_the_gfe_devs
+
+#endif
Index: bsps/powerpc/beatnik/net/if_mve/mv643xx_eth.c
===================================================================
--- bsps/powerpc/beatnik/net/if_mve/mv643xx_eth.c	(revision 031df3914990db0336a0d386fb53558b05de467e)
+++ bsps/powerpc/beatnik/net/if_mve/mv643xx_eth.c	(revision 031df3914990db0336a0d386fb53558b05de467e)
@@ -0,0 +1,3318 @@
+/* RTEMS driver for the mv643xx gigabit ethernet chip */
+
+/* Acknowledgement:
+ *
+ * Valuable information for developing this driver was obtained
+ * from the linux open-source driver mv643xx_eth.c which was written
+ * by the following people and organizations:
+ *
+ * Matthew Dharm <mdharm@momenco.com>
+ * rabeeh@galileo.co.il
+ * PMC-Sierra, Inc., Manish Lachwani
+ * Ralf Baechle <ralf@linux-mips.org>
+ * MontaVista Software, Inc., Dale Farnsworth <dale@farnsworth.org>
+ * Steven J. Hill <sjhill1@rockwellcollins.com>/<sjhill@realitydiluted.com>
+ *
+ * Note however, that in spite of the identical name of this file
+ * (and some of the symbols used herein) this file provides a
+ * new implementation and is the original work by the author.
+ */
+
+/* 
+ * Authorship
+ * ----------
+ * This software (mv643xx ethernet driver for RTEMS) was
+ *     created by Till Straumann <strauman@slac.stanford.edu>, 2005-2007,
+ * 	   Stanford Linear Accelerator Center, Stanford University.
+ * 
+ * Acknowledgement of sponsorship
+ * ------------------------------
+ * The 'mv643xx ethernet driver for RTEMS' was produced by
+ *     the Stanford Linear Accelerator Center, Stanford University,
+ * 	   under Contract DE-AC03-76SFO0515 with the Department of Energy.
+ * 
+ * Government disclaimer of liability
+ * ----------------------------------
+ * Neither the United States nor the United States Department of Energy,
+ * nor any of their employees, makes any warranty, express or implied, or
+ * assumes any legal liability or responsibility for the accuracy,
+ * completeness, or usefulness of any data, apparatus, product, or process
+ * disclosed, or represents that its use would not infringe privately owned
+ * rights.
+ * 
+ * Stanford disclaimer of liability
+ * --------------------------------
+ * Stanford University makes no representations or warranties, express or
+ * implied, nor assumes any liability for the use of this software.
+ * 
+ * Stanford disclaimer of copyright
+ * --------------------------------
+ * Stanford University, owner of the copyright, hereby disclaims its
+ * copyright and all other rights in this software.  Hence, anyone may
+ * freely use it for any purpose without restriction.  
+ * 
+ * Maintenance of notices
+ * ----------------------
+ * In the interest of clarity regarding the origin and status of this
+ * SLAC software, this and all the preceding Stanford University notices
+ * are to remain affixed to any copy or derivative of this software made
+ * or distributed by the recipient and are to be affixed to any copy of
+ * software made or distributed by the recipient that contains a copy or
+ * derivative of this software.
+ * 
+ * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
+ */ 
+
+/*
+ * NOTE: Some register (e.g., the SMI register) are SHARED among the
+ *       three devices. Concurrent access protection is provided by
+ *       the global networking semaphore.
+ *       If other drivers are running on a subset of IFs then proper
+ *       locking of all shared registers must be implemented!
+ *
+ *       Some things I learned about this hardware can be found
+ *       further down...
+ */
+
+#ifndef KERNEL
+#define KERNEL
+#endif
+#ifndef _KERNEL
+#define _KERNEL
+#endif
+
+#include <rtems.h>
+#include <rtems/bspIo.h>
+#include <rtems/error.h>
+#include <bsp.h>
+#include <bsp/irq.h>
+#include <bsp/gtreg.h>
+#include <libcpu/byteorder.h>
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <dev/mii/mii.h>
+#include <net/if_var.h>
+#include <net/if_media.h>
+
+/* Not so nice; would be more elegant not to depend on C library but the
+ * RTEMS-specific ioctl for dumping statistics needs stdio anyways.
+ */
+
+/*#define NDEBUG effectively removes all assertions
+ * If defining NDEBUG, MAKE SURE assert() EXPRESSION HAVE NO SIDE_EFFECTS!!
+ * This driver DOES have side-effects, so DONT DEFINE NDEBUG
+ * Performance-critical assertions are removed by undefining MVETH_TESTING.
+ */
+
+#undef NDEBUG
+#include <assert.h>
+#include <stdio.h>
+#include <errno.h>
+#include <inttypes.h>
+
+#include <rtems/rtems_bsdnet.h>
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+#include <rtems/rtems_mii_ioctl.h>
+#include <bsp/early_enet_link_status.h>
+#include <bsp/if_mve_pub.h>
+
+/* CONFIGURABLE PARAMETERS */
+
+/* Enable Hardware Snooping; if this is disabled (undefined),
+ * cache coherency is maintained by software.
+ */
+#undef  ENABLE_HW_SNOOPING
+
+/* Compile-time debugging features */
+
+/* Enable paranoia assertions and checks; reduce # of descriptors to minimum for stressing   */
+#undef  MVETH_TESTING
+
+/* Enable debugging messages and some support routines  (dump rings etc.)                    */      
+#undef  MVETH_DEBUG
+
+/* Hack for driver development; rtems bsdnet doesn't implement detaching an interface :-(
+ * but this hack allows us to unload/reload the driver module which makes development
+ * a lot less painful.
+ */
+#undef MVETH_DETACH_HACK
+
+/* Ring sizes */
+
+#ifdef MVETH_TESTING
+
+/* hard and small defaults */
+#undef  MV643XX_RX_RING_SIZE
+#define MV643XX_RX_RING_SIZE	2
+#undef  MV643XX_TX_RING_SIZE
+#define MV643XX_TX_RING_SIZE	4
+
+#else /* MVETH_TESTING */
+
+/* Define default ring sizes, allow override from bsp.h, Makefile,... and from ifcfg->rbuf_count/xbuf_count */
+
+#ifndef MV643XX_RX_RING_SIZE
+#define MV643XX_RX_RING_SIZE	40	/* attached buffers are always 2k clusters, i.e., this
+									 * driver - with a configured ring size of 40 - constantly
+									 * locks 80k of cluster memory - your app config better
+									 * provides enough space!
+									 */
+#endif
+
+#ifndef MV643XX_TX_RING_SIZE
+/* NOTE: tx ring size MUST be > max. # of fragments / mbufs in a chain;
+ *       in 'TESTING' mode, special code is compiled in to repackage
+ *		 chains that are longer than the ring size. Normally, this is
+ *		 disabled for sake of speed.
+ *		 I observed chains of >17 entries regularly!
+ *
+ *       Also, TX_NUM_TAG_SLOTS (1) must be left empty as a marker, hence
+ *       the ring size must be > max. #frags + 1.
+ */
+#define MV643XX_TX_RING_SIZE	200	/* these are smaller fragments and not occupied when
+									 * the driver is idle.
+									 */
+#endif
+
+#endif /* MVETH_TESTING */
+
+/* How many instances to we support (bsp.h could override) */
+#ifndef MV643XXETH_NUM_DRIVER_SLOTS
+#define MV643XXETH_NUM_DRIVER_SLOTS	2
+#endif
+
+#define TX_NUM_TAG_SLOTS			1 /* leave room for tag; must not be 0 */
+
+/* This is REAL; chip reads from 64-bit down-aligned buffer
+ * if the buffer size is < 8 !!! for buffer sizes 8 and upwards
+ * alignment is not an issue. This was verified using the
+ * 'mve_smallbuf_test.c'
+ */
+#define ENABLE_TX_WORKAROUND_8_BYTE_PROBLEM
+
+/* Chip register configuration values */
+#define	MVETH_PORT_CONFIG_VAL			(0				\
+			| MV643XX_ETH_DFLT_RX_Q(0)					\
+			| MV643XX_ETH_DFLT_RX_ARP_Q(0)				\
+			| MV643XX_ETH_DFLT_RX_TCP_Q(0)				\
+			| MV643XX_ETH_DFLT_RX_UDP_Q(0)				\
+			| MV643XX_ETH_DFLT_RX_BPDU_Q(0)				\
+			)
+
+
+#define	MVETH_PORT_XTEND_CONFIG_VAL		0
+
+#ifdef OLDCONFIGVAL
+#define	MVETH_SERIAL_CTRL_CONFIG_VAL	(0				\
+			 | MV643XX_ETH_FORCE_LINK_PASS 				\
+			 | MV643XX_ETH_DISABLE_AUTO_NEG_FOR_FLOWCTL	\
+			 | MV643XX_ETH_ADVERTISE_SYMMETRIC_FLOWCTL	\
+			 | MV643XX_ETH_BIT9_UNKNOWN					\
+			 | MV643XX_ETH_FORCE_LINK_FAIL_DISABLE		\
+			 | MV643XX_ETH_SC_MAX_RX_1552				\
+			 | MV643XX_ETH_SET_FULL_DUPLEX				\
+			 | MV643XX_ETH_ENBL_FLOWCTL_TX_RX_IN_FD		\
+			 )
+#endif
+/* If we enable autoneg (duplex, speed, ...) then it seems
+ * that the chip automatically updates link settings
+ * (correct link settings are reflected in PORT_STATUS_R).
+ * However, when we disable aneg in the PHY then things
+ * can get messed up and the port doesn't work anymore.
+ * => we follow the linux driver in disabling all aneg
+ * in the serial config reg. and manually updating the
+ * speed & duplex bits when the phy link status changes.
+ * FIXME: don't know what to do about pause/flow-ctrl.
+ * It is best to just use ANEG anyways!!!
+ */
+#define	MVETH_SERIAL_CTRL_CONFIG_VAL	(0				\
+			 | MV643XX_ETH_DISABLE_AUTO_NEG_FOR_DUPLEX	\
+			 | MV643XX_ETH_DISABLE_AUTO_NEG_FOR_FLOWCTL	\
+			 | MV643XX_ETH_ADVERTISE_SYMMETRIC_FLOWCTL	\
+			 | MV643XX_ETH_BIT9_UNKNOWN					\
+			 | MV643XX_ETH_FORCE_LINK_FAIL_DISABLE		\
+			 | MV643XX_ETH_DISABLE_AUTO_NEG_SPEED_GMII	\
+			 | MV643XX_ETH_SC_MAX_RX_1552				\
+			 )
+
+#define	MVETH_SERIAL_CTRL_CONFIG_MSK	(0				\
+			 | MV643XX_ETH_SERIAL_PORT_ENBL				\
+			 | MV643XX_ETH_FORCE_LINK_PASS				\
+			 | MV643XX_ETH_SC_MAX_RX_MASK				\
+			 )
+
+
+#ifdef __PPC__
+#define MVETH_SDMA_CONFIG_VAL			(0				\
+			| MV643XX_ETH_RX_BURST_SZ_4_64BIT			\
+			| MV643XX_ETH_TX_BURST_SZ_4_64BIT			\
+			)
+#else
+#define MVETH_SDMA_CONFIG_VAL			(0				\
+			| MV643XX_ETH_RX_BURST_SZ_16_64BIT			\
+			| MV643XX_ETH_TX_BURST_SZ_16_64BIT			\
+			)
+#endif
+
+/* minimal frame size we accept */
+#define MVETH_MIN_FRAMSZ_CONFIG_VAL	40
+
+/* END OF CONFIGURABLE SECTION */
+
+/*
+ * Here's stuff I learned about this chip:
+ *
+ *
+ * RX interrupt flags:
+ *
+ * broadcast packet RX: 0x00000005
+ *           last buf:  0x00000c05
+ *           overrun:   0x00000c00           
+ * unicast   packet RX: 0x00000005
+ * bad CRC received:    0x00000005
+ *
+ * clearing 0x00000004 -> clears 0x00000001
+ * clearing 0x00000400 -> clears 0x00000800
+ *
+ * --> 0x0801 are probably some sort of summary bits.
+ *
+ * TX interrupt flags:
+ *
+ * broadcast packet in 1 buf: xcause: 0x00000001 (cause 0x00080000)
+ *        into disconn. link:             "                 "
+ *
+ * in some cases, I observed  xcause: 0x00000101 (reason for 0x100 unknown
+ * but the linux driver accepts it also).
+ *
+ *
+ * Here a few more ugly things about this piece of hardware I learned
+ * (painfully, painfully; spending many many hours & nights :-()
+ *
+ * a) Especially in the case of 'chained' descriptors, the DMA keeps
+ *    clobbering 'cmd_sts' long after it cleared the OWNership flag!!!
+ *    Only after the whole chain is processed (OWN cleared on the
+ *    last descriptor) it is safe to change cmd_sts.
+ *    However, in the case of hardware snooping I found that the
+ *    last descriptor in chain has its cmd_sts still clobbered *after*
+ *    checking ownership!, I.e.,
+ *        if ( ! OWN & cmd_sts ) {
+ *            cmd_sts = 0;
+ *        }
+ *    --> sometimes, cmd_sts is STILL != 0 here
+ *
+ * b) Sometimes, the OWNership flag is *not cleared*.  
+ * 
+ * c) Weird things happen if the chip finds a descriptor with 'OWN'
+ *    still set (i.e., not properly loaded), i.e., corrupted packets
+ *    are sent [with OK checksum since the chip calculates it]. 
+ *
+ * Combine a+b+c and we end up with a real mess.
+ *
+ * The fact that the chip doesn't reliably reset OWN and that OTOH,
+ * it can't be reliably reset by the driver and still, the chip needs
+ * it for proper communication doesn't make things easy...
+ *
+ * Here the basic workarounds:
+ *
+ *     - In addition to check OWN, the scavenger compares the "currently
+ *       served desc" register to the descriptor it tries to recover and
+ *       ignores OWN if they do not match. Hope this is OK.
+ *       Otherwise, we could scan the list of used descriptors and proceed
+ *       recycling descriptors if we find a !OWNed one behind the target...
+ *
+ *     - Always keep an empty slot around to mark the end of the list of
+ *       jobs. The driver clears the descriptor ahead when enqueueing a new
+ *       packet.
+ */
+
+#define DRVNAME			"mve"
+#define MAX_NUM_SLOTS	3
+
+#if MV643XXETH_NUM_DRIVER_SLOTS > MAX_NUM_SLOTS
+#error "mv643xxeth: only MAX_NUM_SLOTS supported"
+#endif
+
+#ifdef NDEBUG
+#error "Driver uses assert() statements with side-effects; MUST NOT define NDEBUG"
+#endif
+
+#ifdef MVETH_DEBUG
+#define STATIC
+#else
+#define STATIC static
+#endif
+
+#define TX_AVAILABLE_RING_SIZE(mp)		((mp)->xbuf_count - (TX_NUM_TAG_SLOTS))
+
+/* macros for ring alignment; proper alignment is a hardware req; . */
+
+#ifdef ENABLE_HW_SNOOPING
+
+#define RING_ALIGNMENT				16
+/* rx buffers must be 64-bit aligned (chip requirement) */
+#define RX_BUF_ALIGNMENT			8
+
+#else /* ENABLE_HW_SNOOPING */
+
+/* Software cache management */
+
+#ifndef __PPC__
+#error	"Dont' know how to deal with cache on this CPU architecture"
+#endif
+
+/* Ring entries are 32 bytes; coherency-critical chunks are 16 -> software coherency
+ * management works for cache line sizes of 16 and 32 bytes only. If the line size
+ * is bigger, the descriptors could be padded...
+ */
+#if	PPC_CACHE_ALIGMENT != 16 && PPC_CACHE_ALIGNMENT != 32
+#error "Cache line size must be 16 or 32"
+#else
+#define RING_ALIGNMENT				PPC_CACHE_ALIGNMENT
+#define RX_BUF_ALIGNMENT			PPC_CACHE_ALIGNMENT
+#endif
+
+#endif /* ENABLE_HW_SNOOPING */
+
+
+/* HELPER MACROS */
+
+/* Align base to alignment 'a' */
+#define MV643XX_ALIGN(b, a)	((((uint32_t)(b)) + (a)-1) & (~((a)-1)))
+
+#define NOOP()			do {} while(0)
+
+/* Function like macros */
+#define MV_READ(off) \
+		ld_le32((volatile uint32_t *)(BSP_MV64x60_BASE + (off)))
+#define MV_WRITE(off, data)		\
+		st_le32((volatile uint32_t *)(BSP_MV64x60_BASE + (off)), ((unsigned)data))
+
+
+/* ENET window mapped 1:1 to CPU addresses by our BSP/MotLoad
+ * -- if this is changed, we should think about caching the 'next' and 'buf' pointers.
+ */
+#define CPUADDR2ENET(a) ((Dma_addr_t)(a))
+#define ENET2CPUADDR(a) (a)
+
+#if 1	/* Whether to automatically try to reclaim descriptors when enqueueing new packets */
+#define MVETH_CLEAN_ON_SEND(mp) (BSP_mve_swipe_tx(mp))
+#else
+#define MVETH_CLEAN_ON_SEND(mp) (-1)
+#endif
+
+#define NEXT_TXD(d)	(d)->next
+#define NEXT_RXD(d)	(d)->next
+
+/* REGISTER AND DESCRIPTOR OFFSET AND BIT DEFINITIONS */
+
+/* Descriptor Definitions */
+/* Rx descriptor */
+#define RDESC_ERROR									(1<< 0)	/* Error summary    */
+
+/* Error code (bit 1&2) is only valid if summary bit is set */
+#define RDESC_CRC_ERROR								(    1)
+#define RDESC_OVERRUN_ERROR							(    3)
+#define RDESC_MAX_FRAMELENGTH_ERROR					(    5)
+#define RDESC_RESOURCE_ERROR						(    7)
+
+#define RDESC_LAST									(1<<26)	/* Last Descriptor   */
+#define RDESC_FRST									(1<<27)	/* First Descriptor  */
+#define RDESC_INT_ENA								(1<<29) /* Enable Interrupts */
+#define RDESC_DMA_OWNED								(1<<31)
+
+/* Tx descriptor */
+#define TDESC_ERROR									(1<< 0) /* Error summary     */
+#define TDESC_ZERO_PAD								(1<<19)
+#define TDESC_LAST									(1<<20)	/* Last Descriptor   */
+#define TDESC_FRST									(1<<21)	/* First Descriptor  */
+#define TDESC_GEN_CRC								(1<<22)
+#define TDESC_INT_ENA								(1<<23) /* Enable Interrupts */
+#define TDESC_DMA_OWNED								(1<<31)
+
+
+
+/* Register Definitions */
+#define MV643XX_ETH_PHY_ADDR_R						(0x2000)
+#define MV643XX_ETH_SMI_R							(0x2004)
+#define MV643XX_ETH_SMI_BUSY						(1<<28)
+#define MV643XX_ETH_SMI_VALID						(1<<27)
+#define MV643XX_ETH_SMI_OP_WR						(0<<26)
+#define MV643XX_ETH_SMI_OP_RD						(1<<26)
+
+#define MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_R(port)	(0x2448 + ((port)<<10))
+#define MV643XX_ETH_TX_START(queue)					(0x0001<<(queue))
+#define MV643XX_ETH_TX_STOP(queue)					(0x0100<<(queue))
+#define MV643XX_ETH_TX_START_M(queues)				((queues)&0xff)
+#define MV643XX_ETH_TX_STOP_M(queues)				(((queues)&0xff)<<8)
+#define MV643XX_ETH_TX_STOP_ALL						(0xff00)
+#define MV643XX_ETH_TX_ANY_RUNNING					(0x00ff)
+
+#define MV643XX_ETH_RECEIVE_QUEUE_COMMAND_R(port)	(0x2680 + ((port)<<10))
+#define MV643XX_ETH_RX_START(queue)					(0x0001<<(queue))
+#define MV643XX_ETH_RX_STOP(queue)					(0x0100<<(queue))
+#define MV643XX_ETH_RX_STOP_ALL						(0xff00)
+#define MV643XX_ETH_RX_ANY_RUNNING					(0x00ff)
+
+#define MV643XX_ETH_CURRENT_SERVED_TX_DESC(port)	(0x2684 + ((port)<<10))
+
+/* The chip puts the ethernet header at offset 2 into the buffer so
+ * that the payload is aligned
+ */
+#define ETH_RX_OFFSET								2
+#define ETH_CRC_LEN									4	/* strip FCS at end of packet */
+
+
+#define MV643XX_ETH_INTERRUPT_CAUSE_R(port)			(0x2460 + ((port)<<10))
+/* not fully understood; RX seems to raise 0x0005 or 0x0c05 if last buffer is filled and 0x0c00
+ * if there are no buffers
+ */
+#define MV643XX_ETH_ALL_IRQS						(0x0007ffff)
+#define MV643XX_ETH_KNOWN_IRQS						(0x00000c05)
+#define MV643XX_ETH_IRQ_EXT_ENA						(1<<1)
+#define MV643XX_ETH_IRQ_RX_DONE						(1<<2)
+#define MV643XX_ETH_IRQ_RX_NO_DESC					(1<<10)
+
+#define MV643XX_ETH_INTERRUPT_EXTEND_CAUSE_R(port)	(0x2464 + ((port)<<10))
+/* not fully understood; TX seems to raise 0x0001 and link change is 0x00010000
+ * if there are no buffers
+ */
+#define MV643XX_ETH_ALL_EXT_IRQS					(0x0011ffff)
+#define MV643XX_ETH_KNOWN_EXT_IRQS					(0x00010101)
+#define MV643XX_ETH_EXT_IRQ_TX_DONE					(1<<0)
+#define MV643XX_ETH_EXT_IRQ_LINK_CHG				(1<<16)
+#define MV643XX_ETH_INTERRUPT_ENBL_R(port)			(0x2468 + ((port)<<10))
+#define MV643XX_ETH_INTERRUPT_EXTEND_ENBL_R(port)	(0x246c + ((port)<<10))
+
+/* port configuration */
+#define MV643XX_ETH_PORT_CONFIG_R(port)				(0x2400 + ((port)<<10))
+#define	MV643XX_ETH_UNICAST_PROMISC_MODE			(1<<0)
+#define	MV643XX_ETH_DFLT_RX_Q(q)					((q)<<1)
+#define	MV643XX_ETH_DFLT_RX_ARP_Q(q)				((q)<<4)
+#define MV643XX_ETH_REJ_BCAST_IF_NOT_IP_OR_ARP		(1<<7)
+#define MV643XX_ETH_REJ_BCAST_IF_IP					(1<<8)
+#define MV643XX_ETH_REJ_BCAST_IF_ARP				(1<<9)
+#define MV643XX_ETH_TX_AM_NO_UPDATE_ERR_SUMMARY		(1<<12)
+#define MV643XX_ETH_CAPTURE_TCP_FRAMES_ENBL			(1<<14)
+#define MV643XX_ETH_CAPTURE_UDP_FRAMES_ENBL			(1<<15)
+#define	MV643XX_ETH_DFLT_RX_TCP_Q(q)				((q)<<16)
+#define	MV643XX_ETH_DFLT_RX_UDP_Q(q)				((q)<<19)
+#define	MV643XX_ETH_DFLT_RX_BPDU_Q(q)				((q)<<22)
+
+
+
+#define MV643XX_ETH_PORT_CONFIG_XTEND_R(port)		(0x2404 + ((port)<<10))
+#define MV643XX_ETH_CLASSIFY_ENBL					(1<<0)
+#define MV643XX_ETH_SPAN_BPDU_PACKETS_AS_NORMAL		(0<<1)
+#define MV643XX_ETH_SPAN_BPDU_PACKETS_2_Q7			(1<<1)
+#define MV643XX_ETH_PARTITION_DISBL					(0<<2)
+#define MV643XX_ETH_PARTITION_ENBL					(1<<2)
+
+#define MV643XX_ETH_SDMA_CONFIG_R(port)				(0x241c + ((port)<<10))
+#define MV643XX_ETH_SDMA_RIFB						(1<<0)
+#define MV643XX_ETH_RX_BURST_SZ_1_64BIT				(0<<1)
+#define MV643XX_ETH_RX_BURST_SZ_2_64BIT				(1<<1)
+#define MV643XX_ETH_RX_BURST_SZ_4_64BIT				(2<<1)
+#define MV643XX_ETH_RX_BURST_SZ_8_64BIT				(3<<1)
+#define MV643XX_ETH_RX_BURST_SZ_16_64BIT			(4<<1)
+#define MV643XX_ETH_SMDA_BLM_RX_NO_SWAP				(1<<4)
+#define MV643XX_ETH_SMDA_BLM_TX_NO_SWAP				(1<<5)
+#define MV643XX_ETH_SMDA_DESC_BYTE_SWAP				(1<<6)
+#define MV643XX_ETH_TX_BURST_SZ_1_64BIT				(0<<22)
+#define MV643XX_ETH_TX_BURST_SZ_2_64BIT				(1<<22)
+#define MV643XX_ETH_TX_BURST_SZ_4_64BIT				(2<<22)
+#define MV643XX_ETH_TX_BURST_SZ_8_64BIT				(3<<22)
+#define MV643XX_ETH_TX_BURST_SZ_16_64BIT			(4<<22)
+
+#define	MV643XX_ETH_RX_MIN_FRAME_SIZE_R(port)		(0x247c + ((port)<<10))
+
+
+#define MV643XX_ETH_SERIAL_CONTROL_R(port)			(0x243c + ((port)<<10))
+#define MV643XX_ETH_SERIAL_PORT_ENBL				(1<<0)	/* Enable serial port */
+#define MV643XX_ETH_FORCE_LINK_PASS					(1<<1)
+#define MV643XX_ETH_DISABLE_AUTO_NEG_FOR_DUPLEX		(1<<2)
+#define MV643XX_ETH_DISABLE_AUTO_NEG_FOR_FLOWCTL	(1<<3)
+#define MV643XX_ETH_ADVERTISE_SYMMETRIC_FLOWCTL		(1<<4)
+#define MV643XX_ETH_FORCE_FC_MODE_TX_PAUSE_DIS		(1<<5)
+#define MV643XX_ETH_FORCE_BP_MODE_JAM_TX			(1<<7)
+#define MV643XX_ETH_FORCE_BP_MODE_JAM_TX_ON_RX_ERR	(1<<8)
+#define MV643XX_ETH_BIT9_UNKNOWN					(1<<9)	/* unknown purpose; linux sets this */
+#define MV643XX_ETH_FORCE_LINK_FAIL_DISABLE			(1<<10)
+#define MV643XX_ETH_RETRANSMIT_FOREVER				(1<<11) /* limit to 16 attempts if clear    */
+#define MV643XX_ETH_DISABLE_AUTO_NEG_SPEED_GMII		(1<<13)
+#define MV643XX_ETH_DTE_ADV_1						(1<<14)
+#define MV643XX_ETH_AUTO_NEG_BYPASS_ENBL			(1<<15)
+#define MV643XX_ETH_RESTART_AUTO_NEG				(1<<16)
+#define MV643XX_ETH_SC_MAX_RX_1518					(0<<17)	/* Limit RX packet size */
+#define MV643XX_ETH_SC_MAX_RX_1522					(1<<17)	/* Limit RX packet size */
+#define MV643XX_ETH_SC_MAX_RX_1552					(2<<17)	/* Limit RX packet size */
+#define MV643XX_ETH_SC_MAX_RX_9022					(3<<17)	/* Limit RX packet size */
+#define MV643XX_ETH_SC_MAX_RX_9192					(4<<17)	/* Limit RX packet size */
+#define MV643XX_ETH_SC_MAX_RX_9700					(5<<17)	/* Limit RX packet size */
+#define MV643XX_ETH_SC_MAX_RX_MASK					(7<<17)	/* bitmask */
+#define MV643XX_ETH_SET_EXT_LOOPBACK				(1<<20)
+#define MV643XX_ETH_SET_FULL_DUPLEX					(1<<21)
+#define MV643XX_ETH_ENBL_FLOWCTL_TX_RX_IN_FD		(1<<22)	/* enable flow ctrl on rx and tx in full-duplex */
+#define MV643XX_ETH_SET_GMII_SPEED_1000				(1<<23)	/* 10/100 if clear */
+#define MV643XX_ETH_SET_MII_SPEED_100				(1<<24)	/* 10 if clear     */
+
+#define MV643XX_ETH_PORT_STATUS_R(port)				(0x2444 + ((port)<<10))
+
+#define MV643XX_ETH_PORT_STATUS_MODE_10_BIT			(1<<0)
+#define MV643XX_ETH_PORT_STATUS_LINK_UP				(1<<1)
+#define MV643XX_ETH_PORT_STATUS_FDX					(1<<2)
+#define MV643XX_ETH_PORT_STATUS_FC					(1<<3)
+#define MV643XX_ETH_PORT_STATUS_1000				(1<<4)
+#define MV643XX_ETH_PORT_STATUS_100					(1<<5)
+/* PSR bit 6 unknown */
+#define MV643XX_ETH_PORT_STATUS_TX_IN_PROGRESS		(1<<7)
+#define MV643XX_ETH_PORT_STATUS_ANEG_BYPASSED		(1<<8)
+#define MV643XX_ETH_PORT_STATUS_PARTITION			(1<<9)
+#define MV643XX_ETH_PORT_STATUS_TX_FIFO_EMPTY		(1<<10)
+
+#define MV643XX_ETH_MIB_COUNTERS(port)				(0x3000 + ((port)<<7))
+#define MV643XX_ETH_NUM_MIB_COUNTERS				32
+
+#define MV643XX_ETH_MIB_GOOD_OCTS_RCVD_LO			(0)
+#define MV643XX_ETH_MIB_GOOD_OCTS_RCVD_HI			(1<<2)
+#define MV643XX_ETH_MIB_BAD_OCTS_RCVD				(2<<2)
+#define MV643XX_ETH_MIB_INTERNAL_MAC_TX_ERR			(3<<2)
+#define MV643XX_ETH_MIB_GOOD_FRAMES_RCVD			(4<<2)
+#define MV643XX_ETH_MIB_BAD_FRAMES_RCVD				(5<<2)
+#define MV643XX_ETH_MIB_BCAST_FRAMES_RCVD			(6<<2)
+#define MV643XX_ETH_MIB_MCAST_FRAMES_RCVD			(7<<2)
+#define MV643XX_ETH_MIB_FRAMES_64_OCTS				(8<<2)
+#define MV643XX_ETH_MIB_FRAMES_65_127_OCTS			(9<<2)
+#define MV643XX_ETH_MIB_FRAMES_128_255_OCTS			(10<<2)
+#define MV643XX_ETH_MIB_FRAMES_256_511_OCTS			(11<<2)
+#define MV643XX_ETH_MIB_FRAMES_512_1023_OCTS		(12<<2)
+#define MV643XX_ETH_MIB_FRAMES_1024_MAX_OCTS		(13<<2)
+#define MV643XX_ETH_MIB_GOOD_OCTS_SENT_LO			(14<<2)
+#define MV643XX_ETH_MIB_GOOD_OCTS_SENT_HI			(15<<2)
+#define MV643XX_ETH_MIB_GOOD_FRAMES_SENT			(16<<2)
+#define MV643XX_ETH_MIB_EXCESSIVE_COLL				(17<<2)
+#define MV643XX_ETH_MIB_MCAST_FRAMES_SENT			(18<<2)
+#define MV643XX_ETH_MIB_BCAST_FRAMES_SENT			(19<<2)
+#define MV643XX_ETH_MIB_UNREC_MAC_CTRL_RCVD			(20<<2)
+#define MV643XX_ETH_MIB_FC_SENT						(21<<2)
+#define MV643XX_ETH_MIB_GOOD_FC_RCVD				(22<<2)
+#define MV643XX_ETH_MIB_BAD_FC_RCVD					(23<<2)
+#define MV643XX_ETH_MIB_UNDERSIZE_RCVD				(24<<2)
+#define MV643XX_ETH_MIB_FRAGMENTS_RCVD				(25<<2)
+#define MV643XX_ETH_MIB_OVERSIZE_RCVD				(26<<2)
+#define MV643XX_ETH_MIB_JABBER_RCVD					(27<<2)
+#define MV643XX_ETH_MIB_MAC_RX_ERR					(28<<2)
+#define MV643XX_ETH_MIB_BAD_CRC_EVENT				(29<<2)
+#define MV643XX_ETH_MIB_COLL						(30<<2)
+#define MV643XX_ETH_MIB_LATE_COLL					(31<<2)
+
+#define MV643XX_ETH_DA_FILTER_SPECL_MCAST_TBL(port) (0x3400+((port)<<10))
+#define MV643XX_ETH_DA_FILTER_OTHER_MCAST_TBL(port) (0x3500+((port)<<10))
+#define MV643XX_ETH_DA_FILTER_UNICAST_TBL(port)		(0x3600+((port)<<10))
+#define MV643XX_ETH_NUM_MCAST_ENTRIES				64
+#define MV643XX_ETH_NUM_UNICAST_ENTRIES				4
+
+#define MV643XX_ETH_BAR_0							(0x2200)
+#define MV643XX_ETH_SIZE_R_0						(0x2204)
+#define MV643XX_ETH_BAR_1							(0x2208)
+#define MV643XX_ETH_SIZE_R_1						(0x220c)
+#define MV643XX_ETH_BAR_2							(0x2210)
+#define MV643XX_ETH_SIZE_R_2						(0x2214)
+#define MV643XX_ETH_BAR_3							(0x2218)
+#define MV643XX_ETH_SIZE_R_3						(0x221c)
+#define MV643XX_ETH_BAR_4							(0x2220)
+#define MV643XX_ETH_SIZE_R_4						(0x2224)
+#define MV643XX_ETH_BAR_5							(0x2228)
+#define MV643XX_ETH_SIZE_R_5						(0x222c)
+#define MV643XX_ETH_NUM_BARS						6
+
+/* Bits in the BAR reg to program cache snooping */
+#define MV64360_ENET2MEM_SNOOP_NONE 0x0000
+#define MV64360_ENET2MEM_SNOOP_WT	0x1000
+#define MV64360_ENET2MEM_SNOOP_WB	0x2000
+#define MV64360_ENET2MEM_SNOOP_MSK	0x3000
+
+
+#define MV643XX_ETH_BAR_ENBL_R						(0x2290)
+#define MV643XX_ETH_BAR_DISABLE(bar)				(1<<(bar))
+#define MV643XX_ETH_BAR_DISBL_ALL					0x3f
+
+#define MV643XX_ETH_RX_Q0_CURRENT_DESC_PTR(port)	(0x260c+((port)<<10))
+#define MV643XX_ETH_RX_Q1_CURRENT_DESC_PTR(port)	(0x261c+((port)<<10))
+#define MV643XX_ETH_RX_Q2_CURRENT_DESC_PTR(port)	(0x262c+((port)<<10))
+#define MV643XX_ETH_RX_Q3_CURRENT_DESC_PTR(port)	(0x263c+((port)<<10))
+#define MV643XX_ETH_RX_Q4_CURRENT_DESC_PTR(port)	(0x264c+((port)<<10))
+#define MV643XX_ETH_RX_Q5_CURRENT_DESC_PTR(port)	(0x265c+((port)<<10))
+#define MV643XX_ETH_RX_Q6_CURRENT_DESC_PTR(port)	(0x266c+((port)<<10))
+#define MV643XX_ETH_RX_Q7_CURRENT_DESC_PTR(port)	(0x267c+((port)<<10))
+
+#define MV643XX_ETH_TX_Q0_CURRENT_DESC_PTR(port)	(0x26c0+((port)<<10))
+#define MV643XX_ETH_TX_Q1_CURRENT_DESC_PTR(port)	(0x26c4+((port)<<10))
+#define MV643XX_ETH_TX_Q2_CURRENT_DESC_PTR(port)	(0x26c8+((port)<<10))
+#define MV643XX_ETH_TX_Q3_CURRENT_DESC_PTR(port)	(0x26cc+((port)<<10))
+#define MV643XX_ETH_TX_Q4_CURRENT_DESC_PTR(port)	(0x26d0+((port)<<10))
+#define MV643XX_ETH_TX_Q5_CURRENT_DESC_PTR(port)	(0x26d4+((port)<<10))
+#define MV643XX_ETH_TX_Q6_CURRENT_DESC_PTR(port)	(0x26d8+((port)<<10))
+#define MV643XX_ETH_TX_Q7_CURRENT_DESC_PTR(port)	(0x26dc+((port)<<10))
+
+#define MV643XX_ETH_MAC_ADDR_LO(port)				(0x2414+((port)<<10))
+#define MV643XX_ETH_MAC_ADDR_HI(port)				(0x2418+((port)<<10))
+
+/* TYPE DEFINITIONS */
+
+/* just to make the purpose explicit; vars of this
+ * type may need CPU-dependent address translation,
+ * endian conversion etc.
+ */
+typedef uint32_t Dma_addr_t;
+
+typedef volatile struct mveth_rx_desc {
+#ifndef __BIG_ENDIAN__
+#error	"descriptor declaration not implemented for little endian machines"
+#endif
+	uint16_t	byte_cnt;
+	uint16_t	buf_size;
+	uint32_t	cmd_sts;					/* control and status */
+	Dma_addr_t	next_desc_ptr;				/* next descriptor (as seen from DMA) */
+	Dma_addr_t	buf_ptr;
+	/* fields below here are not used by the chip */
+	void		*u_buf;						/* user buffer */
+	volatile struct mveth_rx_desc *next;	/* next descriptor (CPU address; next_desc_ptr is a DMA address) */
+	uint32_t	pad[2];
+} __attribute__(( aligned(RING_ALIGNMENT) )) MvEthRxDescRec, *MvEthRxDesc;
+
+typedef volatile struct mveth_tx_desc {
+#ifndef __BIG_ENDIAN__
+#error	"descriptor declaration not implemented for little endian machines"
+#endif
+	uint16_t	byte_cnt;
+	uint16_t	l4i_chk;
+	uint32_t	cmd_sts;					/* control and status */
+	Dma_addr_t	next_desc_ptr;				/* next descriptor (as seen from DMA) */
+	Dma_addr_t	buf_ptr;
+	/* fields below here are not used by the chip */
+	uint32_t	workaround[2];				/* use this space to work around the 8byte problem (is this real?) */
+	void		*u_buf;						/* user buffer */
+	volatile struct mveth_tx_desc *next;	/* next descriptor (CPU address; next_desc_ptr is a DMA address)   */
+} __attribute__(( aligned(RING_ALIGNMENT) )) MvEthTxDescRec, *MvEthTxDesc;
+
+/* Assume there are never more then 64k aliasing entries */
+typedef uint16_t Mc_Refcnt[MV643XX_ETH_NUM_MCAST_ENTRIES*4];
+
+/* driver private data and bsdnet interface structure */
+struct mveth_private {
+	MvEthRxDesc		rx_ring;					/* pointers to aligned ring area             */
+	MvEthTxDesc		tx_ring;					/* pointers to aligned ring area             */
+	MvEthRxDesc		ring_area;					/* allocated ring area                       */
+	int				rbuf_count, xbuf_count;		/* saved ring sizes from ifconfig            */
+	int				port_num;
+	int				phy;
+	MvEthRxDesc		d_rx_t;						/* tail of the RX ring; next received packet */
+	MvEthTxDesc		d_tx_t, d_tx_h;				
+	uint32_t		rx_desc_dma, tx_desc_dma; 	/* ring address as seen by DMA;	(1:1 on this BSP) */
+	int				avail;
+	void            (*isr)(void*);
+	void            *isr_arg;
+	/* Callbacks to handle buffers */
+	void			(*cleanup_txbuf)(void*, void*, int);	/* callback to cleanup TX buffer */
+	void			*cleanup_txbuf_arg;
+	void			*(*alloc_rxbuf)(int *psize, uintptr_t *paddr);	/* allocate RX buffer  */
+	void			(*consume_rxbuf)(void*, void*,  int);	/* callback to consume RX buffer */
+	void			*consume_rxbuf_arg;
+	rtems_id        tid;
+	uint32_t		irq_mask;					/* IRQs we use                              */
+	uint32_t		xirq_mask;
+    int             promisc;
+	struct		{
+		unsigned		irqs;
+		unsigned		maxchain;
+		unsigned		repack;
+		unsigned		packet;
+		unsigned		odrops;					/* no counter in core code                   */
+		struct {
+			uint64_t	good_octs_rcvd;         /* 64-bit */
+			uint32_t	bad_octs_rcvd;
+			uint32_t	internal_mac_tx_err;
+			uint32_t	good_frames_rcvd;
+			uint32_t	bad_frames_rcvd;
+			uint32_t	bcast_frames_rcvd;
+			uint32_t	mcast_frames_rcvd;
+			uint32_t	frames_64_octs;
+			uint32_t	frames_65_127_octs;
+			uint32_t	frames_128_255_octs;
+			uint32_t	frames_256_511_octs;
+			uint32_t	frames_512_1023_octs;
+			uint32_t	frames_1024_max_octs;
+			uint64_t	good_octs_sent;         /* 64-bit */
+			uint32_t	good_frames_sent;
+			uint32_t	excessive_coll;
+			uint32_t	mcast_frames_sent;
+			uint32_t	bcast_frames_sent;
+			uint32_t	unrec_mac_ctrl_rcvd;
+			uint32_t	fc_sent;
+			uint32_t	good_fc_rcvd;
+			uint32_t	bad_fc_rcvd;
+			uint32_t	undersize_rcvd;
+			uint32_t	fragments_rcvd;
+			uint32_t	oversize_rcvd;
+			uint32_t	jabber_rcvd;
+			uint32_t	mac_rx_err;
+			uint32_t	bad_crc_event;
+			uint32_t	coll;
+			uint32_t	late_coll;
+		} mib;
+	}			stats;
+	struct {
+		Mc_Refcnt	specl, other;
+	}           mc_refcnt;
+};
+
+/* stuff needed for bsdnet support */
+struct mveth_bsdsupp {
+	int				oif_flags;					/* old / cached if_flags */
+};
+
+struct mveth_softc {
+	struct arpcom			arpcom;
+	struct mveth_bsdsupp	bsd;
+	struct mveth_private	pvt;
+};
+
+/* GLOBAL VARIABLES */
+#ifdef MVETH_DEBUG_TX_DUMP
+int mveth_tx_dump = 0;
+#endif
+
+/* THE array of driver/bsdnet structs */
+
+/* If detaching/module unloading is enabled, the main driver data
+ * structure must remain in memory; hence it must reside in its own
+ * 'dummy' module...
+ */
+#ifdef  MVETH_DETACH_HACK
+extern
+#else
+STATIC
+#endif
+struct mveth_softc theMvEths[MV643XXETH_NUM_DRIVER_SLOTS]
+#ifndef MVETH_DETACH_HACK
+= {{{{0}},}}
+#endif
+;
+
+/* daemon task id */
+STATIC rtems_id	mveth_tid = 0;
+/* register access protection mutex */
+STATIC rtems_id mveth_mtx = 0;
+#define REGLOCK()	do { \
+		if ( RTEMS_SUCCESSFUL != rtems_semaphore_obtain(mveth_mtx, RTEMS_WAIT, RTEMS_NO_TIMEOUT) ) \
+			rtems_panic(DRVNAME": unable to lock register protection mutex"); \
+		} while (0)
+#define REGUNLOCK()	rtems_semaphore_release(mveth_mtx)
+
+/* Format strings for statistics messages */
+static const char *mibfmt[] = {
+	"  GOOD_OCTS_RCVD:      %"PRIu64"\n",
+	0,
+	"  BAD_OCTS_RCVD:       %"PRIu32"\n",
+	"  INTERNAL_MAC_TX_ERR: %"PRIu32"\n",
+	"  GOOD_FRAMES_RCVD:    %"PRIu32"\n",
+	"  BAD_FRAMES_RCVD:     %"PRIu32"\n",
+	"  BCAST_FRAMES_RCVD:   %"PRIu32"\n",
+	"  MCAST_FRAMES_RCVD:   %"PRIu32"\n",
+	"  FRAMES_64_OCTS:      %"PRIu32"\n",
+	"  FRAMES_65_127_OCTS:  %"PRIu32"\n",
+	"  FRAMES_128_255_OCTS: %"PRIu32"\n",
+	"  FRAMES_256_511_OCTS: %"PRIu32"\n",
+	"  FRAMES_512_1023_OCTS:%"PRIu32"\n",
+	"  FRAMES_1024_MAX_OCTS:%"PRIu32"\n",
+	"  GOOD_OCTS_SENT:      %"PRIu64"\n",
+	0,
+	"  GOOD_FRAMES_SENT:    %"PRIu32"\n",
+	"  EXCESSIVE_COLL:      %"PRIu32"\n",
+	"  MCAST_FRAMES_SENT:   %"PRIu32"\n",
+	"  BCAST_FRAMES_SENT:   %"PRIu32"\n",
+	"  UNREC_MAC_CTRL_RCVD: %"PRIu32"\n",
+	"  FC_SENT:             %"PRIu32"\n",
+	"  GOOD_FC_RCVD:        %"PRIu32"\n",
+	"  BAD_FC_RCVD:         %"PRIu32"\n",
+	"  UNDERSIZE_RCVD:      %"PRIu32"\n",
+	"  FRAGMENTS_RCVD:      %"PRIu32"\n",
+	"  OVERSIZE_RCVD:       %"PRIu32"\n",
+	"  JABBER_RCVD:         %"PRIu32"\n",
+	"  MAC_RX_ERR:          %"PRIu32"\n",
+	"  BAD_CRC_EVENT:       %"PRIu32"\n",
+	"  COLL:                %"PRIu32"\n",
+	"  LATE_COLL:           %"PRIu32"\n",
+};
+
+/* Interrupt Handler Connection */
+
+/* forward decls + implementation for IRQ API funcs */
+
+static void mveth_isr(rtems_irq_hdl_param unit);
+static void mveth_isr_1(rtems_irq_hdl_param unit);
+static void noop(const rtems_irq_connect_data *unused)  {}
+static int  noop1(const rtems_irq_connect_data *unused) { return 0; }
+
+static rtems_irq_connect_data irq_data[MAX_NUM_SLOTS] = {
+	{
+		BSP_IRQ_ETH0,
+		0,
+		(rtems_irq_hdl_param)0,
+		noop,
+		noop,
+		noop1
+	},
+	{
+		BSP_IRQ_ETH1,
+		0,
+		(rtems_irq_hdl_param)1,
+		noop,
+		noop,
+		noop1
+	},
+	{
+		BSP_IRQ_ETH2,
+		0,
+		(rtems_irq_hdl_param)2,
+		noop,
+		noop,
+		noop1
+	},
+};
+
+/* MII Ioctl Interface */
+
+STATIC unsigned
+mveth_mii_read(struct mveth_private *mp, unsigned addr);
+
+STATIC unsigned
+mveth_mii_write(struct mveth_private *mp, unsigned addr, unsigned v);
+
+
+/* mdio / mii interface wrappers for rtems_mii_ioctl API */
+
+static int mveth_mdio_r(int phy, void *uarg, unsigned reg, uint32_t *pval)
+{
+	if ( phy > 1 )
+		return -1;
+
+	*pval = mveth_mii_read(uarg, reg);
+	return 0;
+}
+
+static int mveth_mdio_w(int phy, void *uarg, unsigned reg, uint32_t val)
+{
+	if ( phy > 1 )
+		return -1;
+	mveth_mii_write(uarg, reg, val);
+	return 0;
+}
+
+static struct rtems_mdio_info mveth_mdio = {
+	mdio_r:	  mveth_mdio_r,
+	mdio_w:	  mveth_mdio_w,
+	has_gmii: 1,
+};
+
+/* LOW LEVEL SUPPORT ROUTINES */
+
+/* Software Cache Coherency */
+#ifndef ENABLE_HW_SNOOPING
+#ifndef __PPC__
+#error "Software cache coherency maintenance is not implemented for your CPU architecture"
+#endif
+
+static inline unsigned INVAL_DESC(volatile void *d)
+{
+typedef const char cache_line[PPC_CACHE_ALIGNMENT];
+	asm volatile("dcbi 0, %1":"=m"(*(cache_line*)d):"r"(d));
+	return (unsigned)d;	/* so this can be used in comma expression */
+}
+
+static inline void FLUSH_DESC(volatile void *d)
+{
+typedef const char cache_line[PPC_CACHE_ALIGNMENT];
+	asm volatile("dcbf 0, %0"::"r"(d),"m"(*(cache_line*)d));
+}
+
+static inline void FLUSH_BARRIER(void)
+{
+	asm volatile("eieio");
+}
+
+/* RX buffers are always cache-line aligned
+ * ASSUMPTIONS:
+ *   - 'addr' is cache aligned
+ *   -  len   is a multiple >0 of cache lines
+ */
+static inline void INVAL_BUF(register uintptr_t addr, register int len)
+{
+typedef char maxbuf[2048]; /* more than an ethernet packet */
+	do {
+		len -= RX_BUF_ALIGNMENT;
+		asm volatile("dcbi %0, %1"::"b"(addr),"r"(len));
+	} while (len > 0);
+	asm volatile("":"=m"(*(maxbuf*)addr));
+}
+
+/* Flushing TX buffers is a little bit trickier; we don't really know their
+ * alignment but *assume* adjacent addresses are covering 'ordinary' memory
+ * so that flushing them does no harm!
+ */
+static inline void FLUSH_BUF(register uintptr_t addr, register int len)
+{
+	asm volatile("":::"memory");
+	len = MV643XX_ALIGN(len, RX_BUF_ALIGNMENT);
+	do { 
+		asm volatile("dcbf %0, %1"::"b"(addr),"r"(len));
+		len -= RX_BUF_ALIGNMENT;
+	} while ( len >= 0 );
+}
+
+#else /* hardware snooping enabled */
+
+/* inline this to silence compiler warnings */
+static inline int INVAL_DESC(volatile void *d)
+{ return 0; }
+
+#define FLUSH_DESC(d)	NOOP()
+#define INVAL_BUF(b,l)	NOOP()
+#define FLUSH_BUF(b,l)	NOOP()
+#define FLUSH_BARRIER()	NOOP()
+
+#endif	/* cache coherency support */
+
+/* Synchronize memory access */
+#ifdef __PPC__
+static inline void membarrier(void)
+{
+	asm volatile("sync":::"memory");
+}
+#else
+#error "memory barrier instruction not defined (yet) for this CPU"
+#endif
+
+/* Enable and disable interrupts at the device */
+static inline void
+mveth_enable_irqs(struct mveth_private *mp, uint32_t mask)
+{
+rtems_interrupt_level l;
+uint32_t val;
+	rtems_interrupt_disable(l);
+
+	val  = MV_READ(MV643XX_ETH_INTERRUPT_ENBL_R(mp->port_num));
+	val  = (val | mask | MV643XX_ETH_IRQ_EXT_ENA) & mp->irq_mask;
+
+	MV_WRITE(MV643XX_ETH_INTERRUPT_ENBL_R(mp->port_num),        val);
+
+	val  = MV_READ(MV643XX_ETH_INTERRUPT_EXTEND_ENBL_R(mp->port_num));
+	val  = (val | mask) & mp->xirq_mask;
+	MV_WRITE(MV643XX_ETH_INTERRUPT_EXTEND_ENBL_R(mp->port_num), val);
+
+	rtems_interrupt_enable(l);
+}
+
+static inline uint32_t
+mveth_disable_irqs(struct mveth_private *mp, uint32_t mask)
+{
+rtems_interrupt_level l;
+uint32_t val,xval,tmp;
+	rtems_interrupt_disable(l);
+
+	val  = MV_READ(MV643XX_ETH_INTERRUPT_ENBL_R(mp->port_num));
+	tmp  = ( (val & ~mask) | MV643XX_ETH_IRQ_EXT_ENA ) & mp->irq_mask;
+	MV_WRITE(MV643XX_ETH_INTERRUPT_ENBL_R(mp->port_num),        tmp);
+
+	xval = MV_READ(MV643XX_ETH_INTERRUPT_EXTEND_ENBL_R(mp->port_num));
+	tmp  = (xval & ~mask) & mp->xirq_mask;
+	MV_WRITE(MV643XX_ETH_INTERRUPT_EXTEND_ENBL_R(mp->port_num), tmp);
+
+	rtems_interrupt_enable(l);
+
+	return (val | xval);
+}
+
+/* This should be safe even w/o turning off interrupts if multiple
+ * threads ack different bits in the cause register (and ignore
+ * other ones) since writing 'ones' into the cause register doesn't
+ * 'stick'.
+ */
+
+static inline uint32_t
+mveth_ack_irqs(struct mveth_private *mp, uint32_t mask)
+{
+register uint32_t x,xe,p;
+
+		p  = mp->port_num;
+		/* Get cause */
+		x  = MV_READ(MV643XX_ETH_INTERRUPT_CAUSE_R(p));
+
+		/* Ack interrupts filtering the ones we're interested in */
+
+		/* Note: EXT_IRQ bit clears by itself if EXT interrupts are cleared */
+		MV_WRITE(MV643XX_ETH_INTERRUPT_CAUSE_R(p), ~ (x & mp->irq_mask & mask));
+
+				/* linux driver tests 1<<1 as a summary bit for extended interrupts;
+				 * the mv64360 seems to use 1<<19 for that purpose; for the moment,
+				 * I just check both.
+				 * Update: link status irq (1<<16 in xe) doesn't set (1<<19) in x!
+				 */
+		if ( 1 /* x & 2 */ )
+		{
+			xe = MV_READ(MV643XX_ETH_INTERRUPT_EXTEND_CAUSE_R(p));
+
+			MV_WRITE(MV643XX_ETH_INTERRUPT_EXTEND_CAUSE_R(p), ~ (xe & mp->xirq_mask & mask));
+		} else {
+			xe = 0;
+		}
+#ifdef MVETH_TESTING
+		if (    ((x & MV643XX_ETH_ALL_IRQS) & ~MV643XX_ETH_KNOWN_IRQS)
+			 || ((xe & MV643XX_ETH_ALL_EXT_IRQS) & ~MV643XX_ETH_KNOWN_EXT_IRQS) ) {
+			fprintf(stderr, "Unknown IRQs detected; leaving all disabled for debugging:\n");
+			fprintf(stderr, "Cause reg was 0x%08x, ext cause 0x%08x\n", x, xe);
+			mp->irq_mask  = 0;
+			mp->xirq_mask = 0;
+		}
+#endif
+		/* luckily, the extended and 'normal' interrupts we use don't overlap so
+		 * we can just OR them into a single word
+		 */
+		return  (xe & mp->xirq_mask) | (x & mp->irq_mask);
+}
+
+static void mveth_isr(rtems_irq_hdl_param arg)
+{
+unsigned unit = (unsigned)arg;
+	mveth_disable_irqs(&theMvEths[unit].pvt, -1);
+	theMvEths[unit].pvt.stats.irqs++;
+	rtems_bsdnet_event_send( theMvEths[unit].pvt.tid, 1<<unit );
+}
+
+static void mveth_isr_1(rtems_irq_hdl_param arg)
+{
+unsigned              unit = (unsigned)arg;
+struct mveth_private *mp   = &theMvEths[unit].pvt;
+
+	mp->stats.irqs++;
+	mp->isr(mp->isr_arg);
+}
+
+static void
+mveth_clear_mib_counters(struct mveth_private *mp)
+{
+register int		i;
+register uint32_t	b;
+	/* reading the counters resets them */
+	b = MV643XX_ETH_MIB_COUNTERS(mp->port_num);
+	for (i=0; i< MV643XX_ETH_NUM_MIB_COUNTERS; i++, b+=4)
+		(void)MV_READ(b);
+}
+
+/* Reading a MIB register also clears it. Hence we read the lo
+ * register first, then the hi one. Correct reading is guaranteed since
+ * the 'lo' register cannot overflow after it is read since it had
+ * been reset to 0.
+ */
+static unsigned long long
+read_long_mib_counter(int port_num, int idx)
+{
+unsigned long lo;
+unsigned long long hi;
+	lo = MV_READ(MV643XX_ETH_MIB_COUNTERS(port_num)+(idx<<2));
+	idx++;
+	hi = MV_READ(MV643XX_ETH_MIB_COUNTERS(port_num)+(idx<<2));
+	return (hi<<32) | lo;
+}
+
+static inline unsigned long
+read_mib_counter(int port_num, int idx)
+{
+	return MV_READ(MV643XX_ETH_MIB_COUNTERS(port_num)+(idx<<2));
+}
+
+
+/* write ethernet address from buffer to hardware (need to change unicast filter after this) */
+static void
+mveth_write_eaddr(struct mveth_private *mp, unsigned char *eaddr)
+{
+int			i;
+uint32_t	x;
+
+	/* build hi word */
+ 	for (i=4,x=0; i; i--, eaddr++) {
+		x = (x<<8) | *eaddr;
+	}
+	MV_WRITE(MV643XX_ETH_MAC_ADDR_HI(mp->port_num), x);
+
+	/* build lo word */
+ 	for (i=2,x=0; i; i--, eaddr++) {
+		x = (x<<8) | *eaddr;
+	}
+	MV_WRITE(MV643XX_ETH_MAC_ADDR_LO(mp->port_num), x);
+}
+
+/* PHY/MII Interface
+ *
+ * Read/write a PHY register;
+ * 
+ * NOTE: The SMI register is shared among the three devices.
+ *       Protection is provided by the global networking semaphore.
+ *       If non-bsd drivers are running on a subset of IFs proper
+ *       locking of all shared registers must be implemented!
+ */
+STATIC unsigned
+mveth_mii_read(struct mveth_private *mp, unsigned addr)
+{
+unsigned v;
+unsigned wc = 0;
+
+	addr  &= 0x1f;
+
+	/* wait until not busy */
+	do {
+		v = MV_READ(MV643XX_ETH_SMI_R);
+		wc++;
+	} while ( MV643XX_ETH_SMI_BUSY & v );
+
+	MV_WRITE(MV643XX_ETH_SMI_R, (addr <<21 ) | (mp->phy<<16) | MV643XX_ETH_SMI_OP_RD );
+
+	do {
+		v = MV_READ(MV643XX_ETH_SMI_R);
+		wc++;
+	} while ( MV643XX_ETH_SMI_BUSY & v );
+
+	if (wc>0xffff)
+		wc = 0xffff;
+	return (wc<<16) | (v & 0xffff);
+}
+
+STATIC unsigned
+mveth_mii_write(struct mveth_private *mp, unsigned addr, unsigned v)
+{
+unsigned wc = 0;
+
+	addr  &= 0x1f;
+	v     &= 0xffff;
+
+	/* busywait is ugly but not preventing ISRs or high priority tasks from
+	 * preempting us
+	 */
+
+	/* wait until not busy */
+	while ( MV643XX_ETH_SMI_BUSY & MV_READ(MV643XX_ETH_SMI_R) )
+		wc++ /* wait */;
+
+	MV_WRITE(MV643XX_ETH_SMI_R, (addr <<21 ) | (mp->phy<<16) | MV643XX_ETH_SMI_OP_WR | v );
+
+	return wc;
+}
+
+/* MID-LAYER SUPPORT ROUTINES */
+
+/* Start TX if descriptors are exhausted */
+static __inline__ void
+mveth_start_tx(struct mveth_private *mp)
+{
+uint32_t running;
+	if ( mp->avail <= 0 ) {
+		running = MV_READ(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_R(mp->port_num));
+		if ( ! (running & MV643XX_ETH_TX_START(0)) ) {
+			MV_WRITE(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_R(mp->port_num), MV643XX_ETH_TX_START(0));
+		}
+	}
+}
+
+/* Stop TX and wait for the command queues to stop and the fifo to drain */
+static uint32_t
+mveth_stop_tx(int port)
+{
+uint32_t active_q;
+
+	active_q = (MV_READ(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_R(port)) & MV643XX_ETH_TX_ANY_RUNNING);
+
+	if ( active_q ) {
+		/* Halt TX and wait for activity to stop */
+		MV_WRITE(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_R(port), MV643XX_ETH_TX_STOP_ALL);
+		while ( MV643XX_ETH_TX_ANY_RUNNING & MV_READ(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_R(port)) )
+			/* poll-wait */;
+		/* Wait for Tx FIFO to drain */
+		while ( ! (MV643XX_ETH_PORT_STATUS_R(port) & MV643XX_ETH_PORT_STATUS_TX_FIFO_EMPTY) )
+			/* poll-wait */;
+	}
+
+	return active_q;
+}
+
+/* update serial port settings from current link status */
+static void
+mveth_update_serial_port(struct mveth_private *mp, int media)
+{
+int port = mp->port_num;
+uint32_t old, new;
+
+	new = old = MV_READ(MV643XX_ETH_SERIAL_CONTROL_R(port));
+
+	/* mask speed and duplex settings */
+	new &= ~(  MV643XX_ETH_SET_GMII_SPEED_1000
+			 | MV643XX_ETH_SET_MII_SPEED_100
+			 | MV643XX_ETH_SET_FULL_DUPLEX );
+
+	if ( IFM_FDX & media )
+		new |= MV643XX_ETH_SET_FULL_DUPLEX;
+
+	switch ( IFM_SUBTYPE(media) ) {
+		default: /* treat as 10 */
+			break;
+		case IFM_100_TX:
+			new |= MV643XX_ETH_SET_MII_SPEED_100;
+			break;
+		case IFM_1000_T:
+			new |= MV643XX_ETH_SET_GMII_SPEED_1000;
+			break;
+	}
+
+	if ( new != old ) {
+		if ( ! (MV643XX_ETH_SERIAL_PORT_ENBL & new) ) {
+			/* just write */
+			MV_WRITE(MV643XX_ETH_SERIAL_CONTROL_R(port), new);
+		} else {
+			uint32_t were_running;
+
+			were_running = mveth_stop_tx(port);
+
+			old &= ~MV643XX_ETH_SERIAL_PORT_ENBL;
+			MV_WRITE(MV643XX_ETH_SERIAL_CONTROL_R(port), old);
+			MV_WRITE(MV643XX_ETH_SERIAL_CONTROL_R(port), new);
+			/* linux driver writes twice... */
+			MV_WRITE(MV643XX_ETH_SERIAL_CONTROL_R(port), new);
+
+			if ( were_running ) {
+				MV_WRITE(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_R(mp->port_num), MV643XX_ETH_TX_START(0));
+			}
+		}
+	}
+}
+
+/* Clear multicast filters                        */
+void
+BSP_mve_mcast_filter_clear(struct mveth_private *mp)
+{
+int                 i;
+register uint32_t 	s,o;
+uint32_t            v = mp->promisc ? 0x01010101 : 0x00000000;
+	s = MV643XX_ETH_DA_FILTER_SPECL_MCAST_TBL(mp->port_num);
+	o = MV643XX_ETH_DA_FILTER_OTHER_MCAST_TBL(mp->port_num);
+	for (i=0; i<MV643XX_ETH_NUM_MCAST_ENTRIES; i++) {
+		MV_WRITE(s,v);
+		MV_WRITE(o,v);
+		s+=4;
+		o+=4;
+	}
+	for (i=0; i<sizeof(mp->mc_refcnt.specl)/sizeof(mp->mc_refcnt.specl[0]); i++) {
+		mp->mc_refcnt.specl[i] = 0;
+		mp->mc_refcnt.other[i] = 0;
+	}
+}
+
+void
+BSP_mve_mcast_filter_accept_all(struct mveth_private *mp)
+{
+int                 i;
+register uint32_t 	s,o;
+	s = MV643XX_ETH_DA_FILTER_SPECL_MCAST_TBL(mp->port_num);
+	o = MV643XX_ETH_DA_FILTER_OTHER_MCAST_TBL(mp->port_num);
+	for (i=0; i<MV643XX_ETH_NUM_MCAST_ENTRIES; i++) {
+		MV_WRITE(s,0x01010101);
+		MV_WRITE(o,0x01010101);
+		s+=4;
+		o+=4;
+		/* Not clear what we should do with the reference count.
+		 * For now just increment it.
+		 */
+		for (i=0; i<sizeof(mp->mc_refcnt.specl)/sizeof(mp->mc_refcnt.specl[0]); i++) {
+			mp->mc_refcnt.specl[i]++;
+			mp->mc_refcnt.other[i]++;
+		}
+	}
+}
+
+static void add_entry(uint32_t off, uint8_t hash, Mc_Refcnt *refcnt)
+{
+uint32_t val;
+uint32_t slot = hash & 0xfc;
+
+	if ( 0 == (*refcnt)[hash]++ ) {
+		val = MV_READ(off+slot) | ( 1 << ((hash&3)<<3) );
+		MV_WRITE(off+slot, val);
+	}
+}
+
+static void del_entry(uint32_t off, uint8_t hash, Mc_Refcnt *refcnt)
+{
+uint32_t val;
+uint32_t slot = hash & 0xfc;
+
+	if ( (*refcnt)[hash] > 0 && 0 == --(*refcnt)[hash] ) {
+		val = MV_READ(off+slot) & ~( 1 << ((hash&3)<<3) );
+		MV_WRITE(off+slot, val);
+	}
+}
+
+void
+BSP_mve_mcast_filter_accept_add(struct mveth_private *mp, unsigned char *enaddr)
+{
+uint32_t   hash;
+static const char spec[]={0x01,0x00,0x5e,0x00,0x00};
+static const char bcst[]={0xff,0xff,0xff,0xff,0xff,0xff};
+uint32_t   tabl;
+Mc_Refcnt  *refcnt;
+
+	if ( ! (0x01 & enaddr[0]) ) {
+		/* not a multicast address; ignore */
+		return;
+	}
+
+	if ( 0 == memcmp(enaddr, bcst, sizeof(bcst)) ) {
+		/* broadcast address; ignore */
+		return;
+	}
+
+	if ( 0 == memcmp(enaddr, spec, sizeof(spec)) ) {
+		hash   = enaddr[5];
+		tabl   = MV643XX_ETH_DA_FILTER_SPECL_MCAST_TBL(mp->port_num);
+		refcnt = &mp->mc_refcnt.specl;
+	} else {
+		uint32_t test, mask;
+		int      i;
+		/* algorithm used by linux driver */
+		for ( hash=0, i=0; i<6; i++ ) {
+			hash = (hash ^ enaddr[i]) << 8;
+			for ( test=0x8000, mask=0x8380; test>0x0080; test>>=1, mask>>=1 ) {
+				if ( hash & test )
+					hash ^= mask;
+			}
+		}
+		tabl   = MV643XX_ETH_DA_FILTER_OTHER_MCAST_TBL(mp->port_num);
+		refcnt = &mp->mc_refcnt.other;
+	}
+	add_entry(tabl, hash, refcnt);
+}
+
+void
+BSP_mve_mcast_filter_accept_del(struct mveth_private *mp, unsigned char *enaddr)
+{
+uint32_t   hash;
+static const char spec[]={0x01,0x00,0x5e,0x00,0x00};
+static const char bcst[]={0xff,0xff,0xff,0xff,0xff,0xff};
+uint32_t   tabl;
+Mc_Refcnt  *refcnt;
+
+	if ( ! (0x01 & enaddr[0]) ) {
+		/* not a multicast address; ignore */
+		return;
+	}
+
+	if ( 0 == memcmp(enaddr, bcst, sizeof(bcst)) ) {
+		/* broadcast address; ignore */
+		return;
+	}
+
+	if ( 0 == memcmp(enaddr, spec, sizeof(spec)) ) {
+		hash   = enaddr[5];
+		tabl   = MV643XX_ETH_DA_FILTER_SPECL_MCAST_TBL(mp->port_num);
+		refcnt = &mp->mc_refcnt.specl;
+	} else {
+		uint32_t test, mask;
+		int      i;
+		/* algorithm used by linux driver */
+		for ( hash=0, i=0; i<6; i++ ) {
+			hash = (hash ^ enaddr[i]) << 8;
+			for ( test=0x8000, mask=0x8380; test>0x0080; test>>=1, mask>>=1 ) {
+				if ( hash & test )
+					hash ^= mask;
+			}
+		}
+		tabl   = MV643XX_ETH_DA_FILTER_OTHER_MCAST_TBL(mp->port_num);
+		refcnt = &mp->mc_refcnt.other;
+	}
+	del_entry(tabl, hash, refcnt);
+}
+
+/* Clear all address filters (multi- and unicast) */
+static void
+mveth_clear_addr_filters(struct mveth_private *mp)
+{
+register int      i;
+register uint32_t u;
+	u = MV643XX_ETH_DA_FILTER_UNICAST_TBL(mp->port_num);
+	for (i=0; i<MV643XX_ETH_NUM_UNICAST_ENTRIES; i++) {
+		MV_WRITE(u,0);
+		u+=4;
+	}
+	BSP_mve_mcast_filter_clear(mp);
+}
+
+/* Setup unicast filter for a given MAC address (least significant nibble) */
+static void
+mveth_ucfilter(struct mveth_private *mp, unsigned char mac_lsbyte, int accept)
+{
+unsigned nib, slot, bit;
+uint32_t	val;
+	/* compute slot in table */
+	nib  = mac_lsbyte & 0xf;	/* strip nibble     */
+	slot = nib & ~3;			/* (nibble/4)*4     */
+	bit  = (nib &  3)<<3;		/*  8*(nibble % 4)  */
+	val = MV_READ(MV643XX_ETH_DA_FILTER_UNICAST_TBL(mp->port_num) + slot);
+	if ( accept ) {
+		val |= 0x01 << bit;
+	} else {
+		val &= 0x0e << bit;
+	}
+	MV_WRITE(MV643XX_ETH_DA_FILTER_UNICAST_TBL(mp->port_num) + slot, val);
+}
+
+#if defined( ENABLE_TX_WORKAROUND_8_BYTE_PROBLEM ) && 0
+/* Currently unused; small unaligned buffers seem to be rare
+ * so we just use memcpy()...
+ */
+
+/* memcpy for 0..7 bytes; arranged so that gcc
+ * optimizes for powerpc...
+ */
+
+static inline void memcpy8(void *to, void *fr, unsigned x)
+{
+register uint8_t *d = to, *s = fro;
+
+	d+=l; s+=l;
+	if ( l & 1 ) {
+		*--d=*--s;
+	}
+	if ( l & 2 ) {
+		/* pre-decrementing causes gcc to use auto-decrementing
+		 * PPC instructions (lhzu rx, -2(ry))
+		 */
+		d-=2; s-=2;
+		/* use memcpy; don't cast to short -- accessing
+		 * misaligned data as short is not portable
+		 * (but it works on PPC).
+		 */
+		__builtin_memcpy(d,s,2);
+	}
+	if ( l & 4 ) {
+		d-=4; s-=4;
+		/* see above */
+		__builtin_memcpy(d,s,4);
+	}
+}
+#endif
+
+/* Assign values (buffer + user data) to a tx descriptor slot */
+static int
+mveth_assign_desc(MvEthTxDesc d, struct mbuf *m, unsigned long extra)
+{
+int rval = (d->byte_cnt = m->m_len);
+
+#ifdef MVETH_TESTING
+	assert( !d->mb      );
+	assert(  m->m_len   );
+#endif
+
+	/* set CRC on all descriptors; seems to be necessary */
+	d->cmd_sts  = extra | (TDESC_GEN_CRC | TDESC_ZERO_PAD);
+
+#ifdef ENABLE_TX_WORKAROUND_8_BYTE_PROBLEM
+	/* The buffer must be 64bit aligned if the payload is <8 (??) */
+	if ( rval < 8 && ((mtod(m, uintptr_t)) & 7) ) {
+		d->buf_ptr = CPUADDR2ENET( d->workaround );
+		memcpy((void*)d->workaround, mtod(m, void*), rval);
+	} else
+#endif
+	{
+		d->buf_ptr  = CPUADDR2ENET( mtod(m, unsigned long) );
+	}
+	d->l4i_chk  = 0;
+	return rval;
+}
+
+static int
+mveth_assign_desc_raw(MvEthTxDesc d, void *buf, int len, unsigned long extra)
+{
+int rval = (d->byte_cnt = len);
+
+#ifdef MVETH_TESTING
+	assert( !d->u_buf );
+	assert(  len   );
+#endif
+
+	/* set CRC on all descriptors; seems to be necessary */
+	d->cmd_sts  = extra | (TDESC_GEN_CRC | TDESC_ZERO_PAD);
+
+#ifdef ENABLE_TX_WORKAROUND_8_BYTE_PROBLEM
+	/* The buffer must be 64bit aligned if the payload is <8 (??) */
+	if ( rval < 8 && ( ((uintptr_t)buf) & 7) ) {
+		d->buf_ptr = CPUADDR2ENET( d->workaround );
+		memcpy((void*)d->workaround, buf, rval);
+	} else
+#endif
+	{
+		d->buf_ptr  = CPUADDR2ENET( (unsigned long)buf );
+	}
+	d->l4i_chk  = 0;
+	return rval;
+}
+
+/*
+ * Ring Initialization
+ *
+ * ENDIAN ASSUMPTION: DMA engine matches CPU endianness (???)
+ *
+ * Linux driver discriminates __LITTLE and __BIG endian for re-arranging
+ * the u16 fields in the descriptor structs. However, no endian conversion
+ * is done on the individual fields (SDMA byte swapping is disabled on LE).
+ */
+
+STATIC int
+mveth_init_rx_desc_ring(struct mveth_private *mp)
+{
+int i,sz;
+MvEthRxDesc	d;
+uintptr_t baddr;
+
+	memset((void*)mp->rx_ring, 0, sizeof(*mp->rx_ring)*mp->rbuf_count);
+
+	mp->rx_desc_dma = CPUADDR2ENET(mp->rx_ring);
+
+	for ( i=0, d = mp->rx_ring; i<mp->rbuf_count; i++, d++ ) {
+		d->u_buf = mp->alloc_rxbuf(&sz, &baddr);
+		assert( d->u_buf );
+
+#ifndef ENABLE_HW_SNOOPING
+		/* could reduce the area to max. ethernet packet size */
+		INVAL_BUF(baddr, sz);
+#endif
+
+		d->buf_size = sz;
+		d->byte_cnt = 0;
+		d->cmd_sts  = RDESC_DMA_OWNED | RDESC_INT_ENA;
+		d->next		= mp->rx_ring + (i+1) % mp->rbuf_count;
+
+		d->buf_ptr  = CPUADDR2ENET( baddr );
+		d->next_desc_ptr = CPUADDR2ENET(d->next);
+		FLUSH_DESC(d);
+	}
+	FLUSH_BARRIER();
+
+	mp->d_rx_t = mp->rx_ring;
+
+	/* point the chip to the start of the ring */
+	MV_WRITE(MV643XX_ETH_RX_Q0_CURRENT_DESC_PTR(mp->port_num),mp->rx_desc_dma);
+
+
+	return i;
+}
+
+STATIC int
+mveth_init_tx_desc_ring(struct mveth_private *mp)
+{
+int i;
+MvEthTxDesc d;
+
+	memset((void*)mp->tx_ring, 0, sizeof(*mp->tx_ring)*mp->xbuf_count);
+
+	/* DMA and CPU live in the same address space (rtems) */
+	mp->tx_desc_dma = CPUADDR2ENET(mp->tx_ring);
+	mp->avail       = TX_AVAILABLE_RING_SIZE(mp);
+
+	for ( i=0, d=mp->tx_ring; i<mp->xbuf_count; i++,d++ ) {
+		d->l4i_chk  = 0;
+		d->byte_cnt = 0;
+		d->cmd_sts  = 0;
+		d->buf_ptr  = 0;
+
+		d->next     = mp->tx_ring + (i+1) % mp->xbuf_count;
+		d->next_desc_ptr = CPUADDR2ENET(d->next);
+		FLUSH_DESC(d);
+	}
+	FLUSH_BARRIER();
+
+	mp->d_tx_h = mp->d_tx_t = mp->tx_ring;
+
+	/* point the chip to the start of the ring */
+	MV_WRITE(MV643XX_ETH_TX_Q0_CURRENT_DESC_PTR(mp->port_num),mp->tx_desc_dma);
+
+	return i;
+}
+
+/* PUBLIC LOW-LEVEL DRIVER ACCESS */
+
+static struct mveth_private *
+mve_setup_internal(
+	int		 unit,
+	rtems_id tid,
+	void     (*isr)(void*isr_arg),
+	void     *isr_arg,
+	void (*cleanup_txbuf)(void *user_buf, void *closure, int error_on_tx_occurred), 
+	void *cleanup_txbuf_arg,
+	void *(*alloc_rxbuf)(int *p_size, uintptr_t *p_data_addr),
+	void (*consume_rxbuf)(void *user_buf, void *closure, int len),
+	void *consume_rxbuf_arg,
+	int		rx_ring_size,
+	int		tx_ring_size,
+	int		irq_mask
+)
+
+{
+struct mveth_private *mp;
+struct ifnet         *ifp;
+int                  InstallISRSuccessful;
+
+	if ( unit <= 0 || unit > MV643XXETH_NUM_DRIVER_SLOTS ) {
+		printk(DRVNAME": Bad unit number %i; must be 1..%i\n", unit, MV643XXETH_NUM_DRIVER_SLOTS);
+		return 0;
+	}
+	ifp = &theMvEths[unit-1].arpcom.ac_if;
+	if ( ifp->if_init ) {
+		if ( ifp->if_init ) {
+			printk(DRVNAME": instance %i already attached.\n", unit);
+			return 0;
+		}
+	}
+
+	if ( rx_ring_size < 0 && tx_ring_size < 0 )
+		return 0;
+
+	if ( MV_64360 != BSP_getDiscoveryVersion(0) ) {
+		printk(DRVNAME": not mv64360 chip\n");
+		return 0;
+	}
+
+	/* lazy init of mutex (non thread-safe! - we assume 1st initialization is single-threaded) */
+	if ( ! mveth_mtx ) {
+		rtems_status_code sc;
+		sc = rtems_semaphore_create(
+				rtems_build_name('m','v','e','X'),
+				1,
+				RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_INHERIT_PRIORITY | RTEMS_DEFAULT_ATTRIBUTES,
+				0,
+				&mveth_mtx);
+		if ( RTEMS_SUCCESSFUL != sc ) {
+			rtems_error(sc,DRVNAME": creating mutex\n");
+			rtems_panic("unable to proceed\n");
+		}
+	}
+
+	mp = &theMvEths[unit-1].pvt;
+
+	memset(mp, 0, sizeof(*mp));
+
+	mp->port_num          = unit-1;
+	mp->phy               = (MV_READ(MV643XX_ETH_PHY_ADDR_R) >> (5*mp->port_num)) & 0x1f;
+
+	mp->tid               = tid;
+	mp->isr               = isr;
+	mp->isr_arg           = isr_arg;
+
+	mp->cleanup_txbuf     = cleanup_txbuf;
+	mp->cleanup_txbuf_arg = cleanup_txbuf_arg;
+	mp->alloc_rxbuf       = alloc_rxbuf;
+	mp->consume_rxbuf     = consume_rxbuf;
+	mp->consume_rxbuf_arg = consume_rxbuf_arg;
+
+	mp->rbuf_count = rx_ring_size ? rx_ring_size : MV643XX_RX_RING_SIZE;
+	mp->xbuf_count = tx_ring_size ? tx_ring_size : MV643XX_TX_RING_SIZE;
+
+	if ( mp->xbuf_count > 0 )
+		mp->xbuf_count += TX_NUM_TAG_SLOTS;
+
+	if ( mp->rbuf_count < 0 )
+		mp->rbuf_count = 0;
+	if ( mp->xbuf_count < 0 )
+		mp->xbuf_count = 0;
+
+	/* allocate ring area; add 1 entry -- room for alignment */
+	assert( !mp->ring_area );
+	mp->ring_area = malloc(
+							sizeof(*mp->ring_area) *
+								(mp->rbuf_count + mp->xbuf_count + 1),
+							M_DEVBUF,
+							M_WAIT );
+	assert( mp->ring_area );
+
+	BSP_mve_stop_hw(mp);
+
+	if ( irq_mask ) {
+		irq_data[mp->port_num].hdl = tid ? mveth_isr : mveth_isr_1;	
+		InstallISRSuccessful = BSP_install_rtems_irq_handler( &irq_data[mp->port_num] );
+		assert( InstallISRSuccessful );
+	}
+
+	/* mark as used */
+	ifp->if_init = (void*)(-1);
+
+	if ( rx_ring_size < 0 )
+		irq_mask &= ~ MV643XX_ETH_IRQ_RX_DONE;
+	if ( tx_ring_size < 0 )
+		irq_mask &= ~ MV643XX_ETH_EXT_IRQ_TX_DONE;
+
+	mp->irq_mask = (irq_mask & MV643XX_ETH_IRQ_RX_DONE);
+	if ( (irq_mask &= (MV643XX_ETH_EXT_IRQ_TX_DONE | MV643XX_ETH_EXT_IRQ_LINK_CHG)) ) {
+		mp->irq_mask |= MV643XX_ETH_IRQ_EXT_ENA;
+		mp->xirq_mask = irq_mask;
+	} else {
+		mp->xirq_mask = 0;
+	}
+
+	return mp;
+}
+
+struct mveth_private *
+BSP_mve_setup(
+	int		 unit,
+	rtems_id tid,
+	void (*cleanup_txbuf)(void *user_buf, void *closure, int error_on_tx_occurred), 
+	void *cleanup_txbuf_arg,
+	void *(*alloc_rxbuf)(int *p_size, uintptr_t *p_data_addr),
+	void (*consume_rxbuf)(void *user_buf, void *closure, int len),
+	void *consume_rxbuf_arg,
+	int		rx_ring_size,
+	int		tx_ring_size,
+	int		irq_mask
+)
+{
+	if ( irq_mask && 0 == tid ) {
+		printk(DRVNAME": must supply a TID if irq_msk not zero\n");
+		return 0;	
+	}
+
+	return mve_setup_internal(
+				unit,
+				tid,
+				0, 0,
+				cleanup_txbuf, cleanup_txbuf_arg,
+				alloc_rxbuf,
+				consume_rxbuf, consume_rxbuf_arg,
+				rx_ring_size, tx_ring_size,
+				irq_mask);
+}
+
+struct mveth_private *
+BSP_mve_setup_1(
+	int		 unit,
+	void     (*isr)(void *isr_arg),
+	void     *isr_arg,
+	void (*cleanup_txbuf)(void *user_buf, void *closure, int error_on_tx_occurred), 
+	void *cleanup_txbuf_arg,
+	void *(*alloc_rxbuf)(int *p_size, uintptr_t *p_data_addr),
+	void (*consume_rxbuf)(void *user_buf, void *closure, int len),
+	void *consume_rxbuf_arg,
+	int		rx_ring_size,
+	int		tx_ring_size,
+	int		irq_mask
+)
+{
+	if ( irq_mask && 0 == isr ) {
+		printk(DRVNAME": must supply an ISR if irq_msk not zero\n");
+		return 0;	
+	}
+
+	return mve_setup_internal(
+				unit,
+				0,
+				isr, isr_arg,
+				cleanup_txbuf, cleanup_txbuf_arg,
+				alloc_rxbuf,
+				consume_rxbuf, consume_rxbuf_arg,
+				rx_ring_size, tx_ring_size,
+				irq_mask);
+}
+
+rtems_id
+BSP_mve_get_tid(struct mveth_private *mp)
+{
+    return mp->tid;
+}
+
+int
+BSP_mve_detach(struct mveth_private *mp)
+{
+int unit = mp->port_num;
+	BSP_mve_stop_hw(mp);
+	if ( mp->irq_mask || mp->xirq_mask ) {
+		if ( !BSP_remove_rtems_irq_handler( &irq_data[mp->port_num] ) )
+			return -1;
+	}
+	free( (void*)mp->ring_area, M_DEVBUF );
+	memset(mp, 0, sizeof(*mp));
+	__asm__ __volatile__("":::"memory");
+	/* mark as unused */
+	theMvEths[unit].arpcom.ac_if.if_init = 0;
+	return 0;
+}
+
+/* MAIN RX-TX ROUTINES
+ *
+ * BSP_mve_swipe_tx():  descriptor scavenger; releases mbufs
+ * BSP_mve_send_buf():  xfer mbufs from IF to chip
+ * BSP_mve_swipe_rx():  enqueue received mbufs to interface
+ *                    allocate new ones and yield them to the
+ *                    chip.
+ */
+
+/* clean up the TX ring freeing up buffers */
+int
+BSP_mve_swipe_tx(struct mveth_private *mp)
+{
+int						rval = 0;
+register MvEthTxDesc	d;
+
+	for ( d = mp->d_tx_t; d->buf_ptr; d = NEXT_TXD(d) ) {
+
+		INVAL_DESC(d);
+
+		if (	(TDESC_DMA_OWNED & d->cmd_sts)
+			 &&	(uint32_t)d == MV_READ(MV643XX_ETH_CURRENT_SERVED_TX_DESC(mp->port_num)) )
+			break;
+
+		/* d->u_buf is only set on the last descriptor in a chain;
+		 * we only count errors in the last descriptor;
+		 */
+		if ( d->u_buf ) {
+			mp->cleanup_txbuf(d->u_buf, mp->cleanup_txbuf_arg, (d->cmd_sts & TDESC_ERROR) ? 1 : 0);
+			d->u_buf = 0;
+		}
+
+		d->buf_ptr = 0;
+
+		rval++;
+	}
+	mp->d_tx_t = d;
+	mp->avail += rval;
+
+	return rval;
+}
+
+/* allocate a new cluster and copy an existing chain there;
+ * old chain is released...
+ */
+static struct mbuf *
+repackage_chain(struct mbuf *m_head)
+{
+struct mbuf *m;
+	MGETHDR(m, M_DONTWAIT, MT_DATA);
+
+	if ( !m ) {
+		goto bail;
+	}
+
+	MCLGET(m, M_DONTWAIT);
+
+	if ( !(M_EXT & m->m_flags) ) {
+		m_freem(m);
+		m = 0;
+		goto bail;
+	}
+
+	m_copydata(m_head, 0, MCLBYTES, mtod(m, caddr_t));
+	m->m_pkthdr.len = m->m_len = m_head->m_pkthdr.len;
+
+bail:
+	m_freem(m_head);
+	return m;
+}
+
+/* Enqueue a mbuf chain or a raw data buffer for transmission;
+ * RETURN: #bytes sent or -1 if there are not enough descriptors
+ *
+ * If 'len' is <=0 then 'm_head' is assumed to point to a mbuf chain.
+ * OTOH, a raw data packet may be send (non-BSD driver) by pointing
+ * m_head to the start of the data and passing 'len' > 0.
+ *
+ * Comments: software cache-flushing incurs a penalty if the
+ *           packet cannot be queued since it is flushed anyways.
+ *           The algorithm is slightly more efficient in the normal
+ *			 case, though.
+ */
+int
+BSP_mve_send_buf(struct mveth_private *mp, void *m_head, void *data_p, int len)
+{
+int						rval;
+register MvEthTxDesc	l,d,h;
+register struct mbuf	*m1;
+int						nmbs;
+int						ismbuf = (len <= 0);
+
+/* Only way to get here is when we discover that the mbuf chain
+ * is too long for the tx ring
+ */
+startover:
+
+	rval = 0;
+
+#ifdef MVETH_TESTING 
+	assert(m_head);
+#endif
+
+	/* if no descriptor is available; try to wipe the queue */
+	if ( (mp->avail < 1) && MVETH_CLEAN_ON_SEND(mp)<=0 ) {
+		/* Maybe TX is stalled and needs to be restarted */
+		mveth_start_tx(mp);
+		return -1;
+	}
+
+	h = mp->d_tx_h;
+
+#ifdef MVETH_TESTING 
+	assert( !h->buf_ptr );
+	assert( !h->mb      );
+#endif
+
+	if ( ! (m1 = m_head) )
+		return 0;
+
+	if ( ismbuf ) {
+		/* find first mbuf with actual data */
+		while ( 0 == m1->m_len ) {
+			if ( ! (m1 = m1->m_next) ) {
+				/* end reached and still no data to send ?? */
+				m_freem(m_head);
+				return 0;
+			}
+		}
+	}
+
+	/* Don't use the first descriptor yet because BSP_mve_swipe_tx()
+	 * needs mp->d_tx_h->buf_ptr == NULL as a marker. Hence, we
+	 * start with the second mbuf and fill the first descriptor
+	 * last.
+	 */
+
+	l = h;
+	d = NEXT_TXD(h);
+
+	mp->avail--;
+
+	nmbs = 1;
+	if ( ismbuf ) {
+			register struct mbuf *m;
+			for ( m=m1->m_next; m; m=m->m_next ) {
+					if ( 0 == m->m_len )
+							continue;	/* skip empty mbufs */
+
+					nmbs++;
+
+					if ( mp->avail < 1 && MVETH_CLEAN_ON_SEND(mp)<=0 ) {
+							/* Maybe TX was stalled - try to restart */
+							mveth_start_tx(mp);
+
+							/* not enough descriptors; cleanup...
+							 * the first slot was never used, so we start
+							 * at mp->d_tx_h->next;
+							 */
+							for ( l = NEXT_TXD(h); l!=d; l=NEXT_TXD(l) ) {
+#ifdef MVETH_TESTING
+									assert( l->mb == 0 );
+#endif
+									l->buf_ptr  = 0;
+									l->cmd_sts  = 0;
+									mp->avail++;
+							}
+							mp->avail++;
+							if ( nmbs > TX_AVAILABLE_RING_SIZE(mp) ) {
+									/* this chain will never fit into the ring */
+									if ( nmbs > mp->stats.maxchain )
+											mp->stats.maxchain = nmbs;
+									mp->stats.repack++;
+									if ( ! (m_head = repackage_chain(m_head)) ) {
+											/* no cluster available */
+											mp->stats.odrops++;
+											return 0;
+									}
+									goto startover;
+							}
+							return -1;
+					}
+
+					mp->avail--;
+
+#ifdef MVETH_TESTING
+					assert( d != h      );
+					assert( !d->buf_ptr );
+#endif
+
+					/* fill this slot */
+					rval += mveth_assign_desc(d, m, TDESC_DMA_OWNED);
+
+					FLUSH_BUF(mtod(m, uint32_t), m->m_len);
+
+					l = d;
+					d = NEXT_TXD(d);
+
+					FLUSH_DESC(l);
+			}
+
+		/* fill first slot - don't release to DMA yet */
+		rval += mveth_assign_desc(h, m1, TDESC_FRST);
+
+
+		FLUSH_BUF(mtod(m1, uint32_t), m1->m_len);
+
+	} else {
+		/* fill first slot with raw buffer - don't release to DMA yet */
+		rval += mveth_assign_desc_raw(h, data_p, len, TDESC_FRST);
+
+		FLUSH_BUF( (uint32_t)data_p, len);
+	}
+
+	/* tag last slot; this covers the case where 1st==last */
+	l->cmd_sts      |= TDESC_LAST | TDESC_INT_ENA;
+	/* mbuf goes into last desc */
+	l->u_buf         = m_head;
+
+
+	FLUSH_DESC(l);
+
+	/* Tag end; make sure chip doesn't try to read ahead of here! */
+	l->next->cmd_sts = 0;
+	FLUSH_DESC(l->next);
+
+#ifdef MVETH_DEBUG_TX_DUMP
+	if ( (mveth_tx_dump & (1<<mp->port_num)) ) {
+		int ll,kk;
+		if ( ismbuf ) {
+			struct mbuf *m;
+			for ( kk=0, m=m_head; m; m=m->m_next) {
+				for ( ll=0; ll<m->m_len; ll++ ) {
+					printf("%02X ",*(mtod(m,char*) + ll));
+					if ( ((++kk)&0xf) == 0 )
+						printf("\n");
+				}
+			}
+		} else {
+			for ( ll=0; ll<len; ) {
+				printf("%02X ",*((char*)data_p + ll));
+				if ( ((++ll)&0xf) == 0 )
+					printf("\n");
+			}	
+		}
+		printf("\n");
+	}
+#endif
+
+	membarrier();
+
+	/* turn over the whole chain by flipping ownership of the first desc */
+	h->cmd_sts |= TDESC_DMA_OWNED;
+
+	FLUSH_DESC(h);
+
+	membarrier();
+
+	/* notify the device */
+	MV_WRITE(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_R(mp->port_num), MV643XX_ETH_TX_START(0));
+
+	/* Update softc */
+	mp->stats.packet++;
+	if ( nmbs > mp->stats.maxchain )
+		mp->stats.maxchain = nmbs;
+
+	/* remember new head */
+	mp->d_tx_h = d;
+
+	return rval; /* #bytes sent */
+}
+
+int
+BSP_mve_send_buf_raw(
+	struct mveth_private *mp,
+	void                 *head_p,
+	int                   h_len,
+	void                 *data_p,
+    int                   d_len)
+{
+int						rval;
+register MvEthTxDesc	l,d,h;
+int						needed;
+void                    *frst_buf;
+int                     frst_len;
+
+	rval = 0;
+
+#ifdef MVETH_TESTING 
+	assert(header || data);
+#endif
+
+	needed = head_p && data_p ? 2 : 1;
+
+	/* if no descriptor is available; try to wipe the queue */
+	if (   ( mp->avail < needed )
+        && ( MVETH_CLEAN_ON_SEND(mp) <= 0 || mp->avail < needed ) ) {
+		/* Maybe TX was stalled and needs a restart */
+		mveth_start_tx(mp);
+		return -1;
+	}
+
+	h = mp->d_tx_h;
+
+#ifdef MVETH_TESTING 
+	assert( !h->buf_ptr );
+	assert( !h->mb      );
+#endif
+
+	/* find the 'first' user buffer */
+	if ( (frst_buf = head_p) ) {
+		frst_len = h_len;
+	} else {
+		frst_buf = data_p;
+		frst_len = d_len;
+	}
+
+	/* Don't use the first descriptor yet because BSP_mve_swipe_tx()
+	 * needs mp->d_tx_h->buf_ptr == NULL as a marker. Hence, we
+	 * start with the second (optional) slot and fill the first
+     * descriptor last.
+	 */
+
+	l = h;
+	d = NEXT_TXD(h);
+
+	mp->avail--;
+
+	if ( needed > 1 ) {
+		mp->avail--;
+#ifdef MVETH_TESTING
+		assert( d != h      );
+		assert( !d->buf_ptr );
+#endif
+		rval += mveth_assign_desc_raw(d, data_p, d_len, TDESC_DMA_OWNED);
+		FLUSH_BUF( (uint32_t)data_p, d_len );
+		d->u_buf = data_p;
+
+		l = d;
+		d = NEXT_TXD(d);
+
+		FLUSH_DESC(l);
+	}
+
+	/* fill first slot with raw buffer - don't release to DMA yet */
+	rval       += mveth_assign_desc_raw(h, frst_buf, frst_len, TDESC_FRST);
+
+	FLUSH_BUF( (uint32_t)frst_buf, frst_len);
+
+	/* tag last slot; this covers the case where 1st==last */
+	l->cmd_sts |= TDESC_LAST | TDESC_INT_ENA;
+
+	/* first buffer of 'chain' goes into last desc */
+	l->u_buf    = frst_buf;
+
+	FLUSH_DESC(l);
+
+	/* Tag end; make sure chip doesn't try to read ahead of here! */
+	l->next->cmd_sts = 0;
+	FLUSH_DESC(l->next);
+
+	membarrier();
+
+	/* turn over the whole chain by flipping ownership of the first desc */
+	h->cmd_sts |= TDESC_DMA_OWNED;
+
+	FLUSH_DESC(h);
+
+	membarrier();
+
+	/* notify the device */
+	MV_WRITE(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_R(mp->port_num), MV643XX_ETH_TX_START(0));
+
+	/* Update softc */
+	mp->stats.packet++;
+	if ( needed > mp->stats.maxchain )
+		mp->stats.maxchain = needed;
+
+	/* remember new head */
+	mp->d_tx_h = d;
+
+	return rval; /* #bytes sent */
+}
+
+/* send received buffers upwards and replace them
+ * with freshly allocated ones;
+ * ASSUMPTION:	buffer length NEVER changes and is set
+ *				when the ring is initialized.
+ * TS 20060727: not sure if this assumption is still necessary - I believe it isn't.
+ */
+
+int
+BSP_mve_swipe_rx(struct mveth_private *mp)
+{
+int						rval = 0, err;
+register MvEthRxDesc	d;
+void					*newbuf;
+int						sz;
+uintptr_t 				baddr;
+
+	for ( d = mp->d_rx_t; ! (INVAL_DESC(d), (RDESC_DMA_OWNED & d->cmd_sts)); d=NEXT_RXD(d) ) {
+
+#ifdef MVETH_TESTING 
+		assert(d->u_buf);
+#endif
+
+		err = (RDESC_ERROR & d->cmd_sts);
+
+		if ( err || !(newbuf = mp->alloc_rxbuf(&sz, &baddr)) ) {
+			/* drop packet and recycle buffer */
+			newbuf = d->u_buf;
+			mp->consume_rxbuf(0, mp->consume_rxbuf_arg, err ? -1 : 0);
+		} else {
+#ifdef MVETH_TESTING
+			assert( d->byte_cnt > 0 );
+#endif
+			mp->consume_rxbuf(d->u_buf, mp->consume_rxbuf_arg, d->byte_cnt);
+
+#ifndef ENABLE_HW_SNOOPING
+			/* could reduce the area to max. ethernet packet size */
+			INVAL_BUF(baddr, sz);
+#endif
+			d->u_buf    = newbuf;
+			d->buf_ptr  = CPUADDR2ENET(baddr);
+			d->buf_size = sz;
+			FLUSH_DESC(d);
+		}
+
+		membarrier();
+
+		d->cmd_sts = RDESC_DMA_OWNED | RDESC_INT_ENA;
+
+		FLUSH_DESC(d);
+
+		rval++;
+	}
+	MV_WRITE(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_R(mp->port_num), MV643XX_ETH_RX_START(0));
+	mp->d_rx_t = d;
+	return rval;
+}
+
+/* Stop hardware and clean out the rings */
+void
+BSP_mve_stop_hw(struct mveth_private *mp)
+{
+MvEthTxDesc	d;
+MvEthRxDesc	r;
+int			i;
+
+	mveth_disable_irqs(mp, -1);
+
+	mveth_stop_tx(mp->port_num);
+
+	/* cleanup TX rings */
+	if (mp->d_tx_t) { /* maybe ring isn't initialized yet */
+		for ( i=0, d=mp->tx_ring; i<mp->xbuf_count; i++, d++ ) {
+			/* should be safe to clear ownership */
+			d->cmd_sts &= ~TDESC_DMA_OWNED;
+			FLUSH_DESC(d);
+		}
+		FLUSH_BARRIER();
+
+		BSP_mve_swipe_tx(mp);
+
+#ifdef MVETH_TESTING 
+		assert( mp->d_tx_h == mp->d_tx_t );
+		for ( i=0, d=mp->tx_ring; i<mp->xbuf_count; i++, d++ ) {
+			assert( !d->buf_ptr );
+		}
+#endif
+	}
+
+	MV_WRITE(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_R(mp->port_num), MV643XX_ETH_RX_STOP_ALL);
+	while ( MV643XX_ETH_RX_ANY_RUNNING & MV_READ(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_R(mp->port_num)) )
+		/* poll-wait */;
+
+	/* stop serial port */
+	MV_WRITE(MV643XX_ETH_SERIAL_CONTROL_R(mp->port_num),
+		MV_READ(MV643XX_ETH_SERIAL_CONTROL_R(mp->port_num))
+		& ~( MV643XX_ETH_SERIAL_PORT_ENBL | MV643XX_ETH_FORCE_LINK_FAIL_DISABLE | MV643XX_ETH_FORCE_LINK_PASS)
+		);
+
+	/* clear pending interrupts */
+	MV_WRITE(MV643XX_ETH_INTERRUPT_CAUSE_R(mp->port_num), 0);
+	MV_WRITE(MV643XX_ETH_INTERRUPT_EXTEND_CAUSE_R(mp->port_num), 0);
+
+	/* cleanup RX rings */
+	if ( mp->rx_ring ) {
+		for ( i=0, r=mp->rx_ring; i<mp->rbuf_count; i++, r++ ) {
+			/* should be OK to clear ownership flag */
+			r->cmd_sts = 0;
+			FLUSH_DESC(r);
+			mp->consume_rxbuf(r->u_buf, mp->consume_rxbuf_arg, 0);
+			r->u_buf = 0;
+		}
+		FLUSH_BARRIER();
+	}
+
+
+}
+
+uint32_t mveth_serial_ctrl_config_val = MVETH_SERIAL_CTRL_CONFIG_VAL;
+
+/* Fire up the low-level driver
+ *
+ * - make sure hardware is halted
+ * - enable cache snooping
+ * - clear address filters
+ * - clear mib counters
+ * - reset phy
+ * - initialize (or reinitialize) descriptor rings
+ * - check that the firmware has set up a reasonable mac address.
+ * - generate unicast filter entry for our mac address
+ * - write register config values to the chip
+ * - start hardware (serial port and SDMA)
+ */
+
+void
+BSP_mve_init_hw(struct mveth_private *mp, int promisc, unsigned char *enaddr)
+{
+int					i;
+uint32_t			v;
+static int			inited = 0;
+
+#ifdef MVETH_DEBUG
+	printk(DRVNAME"%i: Entering BSP_mve_init_hw()\n", mp->port_num+1);
+#endif
+
+	/* since enable/disable IRQ routine only operate on select bitsets
+	 * we must make sure everything is masked initially.
+	 */
+	MV_WRITE(MV643XX_ETH_INTERRUPT_ENBL_R(mp->port_num),        0);
+	MV_WRITE(MV643XX_ETH_INTERRUPT_EXTEND_ENBL_R(mp->port_num), 0);
+
+	BSP_mve_stop_hw(mp);
+
+	memset(&mp->stats, 0, sizeof(mp->stats));
+
+	mp->promisc = promisc;
+
+	/* MotLoad has cache snooping disabled on the ENET2MEM windows.
+	 * Some comments in (linux) indicate that there are errata
+	 * which cause problems which would be a real bummer.
+	 * We try it anyways...
+	 */
+	if ( !inited ) {
+	unsigned long disbl, bar;
+		inited = 1;	/* FIXME: non-thread safe lazy init */
+		disbl = MV_READ(MV643XX_ETH_BAR_ENBL_R);
+			/* disable all 6 windows */
+			MV_WRITE(MV643XX_ETH_BAR_ENBL_R, MV643XX_ETH_BAR_DISBL_ALL);
+			/* set WB snooping on enabled bars */
+			for ( i=0; i<MV643XX_ETH_NUM_BARS*8; i+=8 ) {
+				if ( (bar = MV_READ(MV643XX_ETH_BAR_0 + i)) && MV_READ(MV643XX_ETH_SIZE_R_0 + i) ) {
+#ifdef ENABLE_HW_SNOOPING
+					MV_WRITE(MV643XX_ETH_BAR_0 + i, bar | MV64360_ENET2MEM_SNOOP_WB);
+#else
+					MV_WRITE(MV643XX_ETH_BAR_0 + i, bar & ~MV64360_ENET2MEM_SNOOP_MSK);
+#endif
+					/* read back to flush fifo [linux comment] */
+					(void)MV_READ(MV643XX_ETH_BAR_0 + i);
+				}
+			}
+			/* restore/re-enable */
+		MV_WRITE(MV643XX_ETH_BAR_ENBL_R, disbl);
+	}
+
+	mveth_clear_mib_counters(mp);
+	mveth_clear_addr_filters(mp);
+
+/*	Just leave it alone...
+	reset_phy();
+*/
+
+	if ( mp->rbuf_count > 0 ) {
+		mp->rx_ring = (MvEthRxDesc)MV643XX_ALIGN(mp->ring_area, RING_ALIGNMENT);
+		mveth_init_rx_desc_ring(mp);
+	}
+
+	if ( mp->xbuf_count > 0 ) {
+		mp->tx_ring = (MvEthTxDesc)mp->rx_ring + mp->rbuf_count;
+		mveth_init_tx_desc_ring(mp);
+	}
+
+	if ( enaddr ) {
+		/* set ethernet address from arpcom struct */
+#ifdef MVETH_DEBUG
+		printk(DRVNAME"%i: Writing MAC addr ", mp->port_num+1);
+		for (i=5; i>=0; i--) {
+			printk("%02X%c", enaddr[i], i?':':'\n');
+		}
+#endif
+		mveth_write_eaddr(mp, enaddr);
+	}
+
+	/* set mac address and unicast filter */
+
+	{
+	uint32_t machi, maclo;
+		maclo = MV_READ(MV643XX_ETH_MAC_ADDR_LO(mp->port_num));
+		machi = MV_READ(MV643XX_ETH_MAC_ADDR_HI(mp->port_num));
+		/* ASSUME: firmware has set the mac address for us
+		 *         - if assertion fails, we have to do more work...
+		 */
+		assert( maclo && machi && maclo != 0xffffffff && machi != 0xffffffff );
+		mveth_ucfilter(mp, maclo&0xff, 1/* accept */);
+	}
+	
+	/* port, serial and sdma configuration */
+	v = MVETH_PORT_CONFIG_VAL;
+	if ( promisc ) {
+		/* multicast filters were already set up to
+		 * accept everything (mveth_clear_addr_filters())
+		 */
+		v |= MV643XX_ETH_UNICAST_PROMISC_MODE;
+	} else {
+		v &= ~MV643XX_ETH_UNICAST_PROMISC_MODE;
+	}
+	MV_WRITE(MV643XX_ETH_PORT_CONFIG_R(mp->port_num),
+				v);
+	MV_WRITE(MV643XX_ETH_PORT_CONFIG_XTEND_R(mp->port_num),
+				MVETH_PORT_XTEND_CONFIG_VAL);
+
+	v  = MV_READ(MV643XX_ETH_SERIAL_CONTROL_R(mp->port_num));
+	v &= ~(MVETH_SERIAL_CTRL_CONFIG_MSK);
+	v |= mveth_serial_ctrl_config_val;
+	MV_WRITE(MV643XX_ETH_SERIAL_CONTROL_R(mp->port_num), v);
+
+	i = IFM_MAKEWORD(0, 0, 0, 0);
+	if ( 0 == BSP_mve_media_ioctl(mp, SIOCGIFMEDIA, &i) ) {
+	    if ( (IFM_LINK_OK & i) ) {
+			mveth_update_serial_port(mp, i);
+		}
+	}
+
+	/* enable serial port */
+	v  = MV_READ(MV643XX_ETH_SERIAL_CONTROL_R(mp->port_num));
+	MV_WRITE(MV643XX_ETH_SERIAL_CONTROL_R(mp->port_num),
+				v | MV643XX_ETH_SERIAL_PORT_ENBL);
+
+#ifndef __BIG_ENDIAN__
+#error	"byte swapping needs to be disabled for little endian machines"
+#endif
+	MV_WRITE(MV643XX_ETH_SDMA_CONFIG_R(mp->port_num), MVETH_SDMA_CONFIG_VAL);
+
+	/* allow short frames */
+	MV_WRITE(MV643XX_ETH_RX_MIN_FRAME_SIZE_R(mp->port_num), MVETH_MIN_FRAMSZ_CONFIG_VAL);
+
+	MV_WRITE(MV643XX_ETH_INTERRUPT_CAUSE_R(mp->port_num), 0);
+	MV_WRITE(MV643XX_ETH_INTERRUPT_EXTEND_CAUSE_R(mp->port_num), 0);
+	/* TODO: set irq coalescing */
+
+	/* enable Rx */
+	if ( mp->rbuf_count > 0 ) {
+		MV_WRITE(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_R(mp->port_num), MV643XX_ETH_RX_START(0));
+	}
+
+	mveth_enable_irqs(mp, -1);
+
+#ifdef MVETH_DEBUG
+	printk(DRVNAME"%i: Leaving BSP_mve_init_hw()\n", mp->port_num+1);
+#endif
+}
+
+/* read ethernet address from hw to buffer */
+void
+BSP_mve_read_eaddr(struct mveth_private *mp, unsigned char *oeaddr)
+{
+int				i;
+uint32_t		x;
+unsigned char	buf[6], *eaddr;
+
+	eaddr = oeaddr ? oeaddr : buf;
+
+	eaddr += 5;
+	x = MV_READ(MV643XX_ETH_MAC_ADDR_LO(mp->port_num));
+
+	/* lo word */
+ 	for (i=2; i; i--, eaddr--) {
+		*eaddr = (unsigned char)(x & 0xff);
+		x>>=8;
+	}
+
+	x = MV_READ(MV643XX_ETH_MAC_ADDR_HI(mp->port_num));
+	/* hi word */
+ 	for (i=4; i; i--, eaddr--) {
+		*eaddr = (unsigned char)(x & 0xff);
+		x>>=8;
+	}
+
+	if ( !oeaddr ) {
+		printf("%02X",buf[0]);
+		for (i=1; i<sizeof(buf); i++)
+			printf(":%02X",buf[i]);
+		printf("\n");
+	}
+}
+
+int
+BSP_mve_media_ioctl(struct mveth_private *mp, int cmd, int *parg)
+{
+int rval;
+	/* alias cmd == 0,1 */
+	switch ( cmd ) {
+		case 0: cmd = SIOCGIFMEDIA;
+			break;
+		case 1: cmd = SIOCSIFMEDIA;
+		case SIOCGIFMEDIA:
+		case SIOCSIFMEDIA:
+			break;
+		default: return -1;
+	}
+	REGLOCK();
+	rval = rtems_mii_ioctl(&mveth_mdio, mp, cmd, parg);
+	REGUNLOCK();
+	return rval;
+}
+
+void
+BSP_mve_enable_irqs(struct mveth_private *mp)
+{
+	mveth_enable_irqs(mp, -1);
+}
+
+void
+BSP_mve_disable_irqs(struct mveth_private *mp)
+{
+	mveth_disable_irqs(mp, -1);
+}
+
+uint32_t
+BSP_mve_ack_irqs(struct mveth_private *mp)
+{
+	return mveth_ack_irqs(mp, -1);
+}
+
+
+void
+BSP_mve_enable_irq_mask(struct mveth_private *mp, uint32_t mask)
+{
+	mveth_enable_irqs(mp, mask);
+}
+
+uint32_t
+BSP_mve_disable_irq_mask(struct mveth_private *mp, uint32_t mask)
+{
+	return mveth_disable_irqs(mp, mask);
+}
+
+uint32_t
+BSP_mve_ack_irq_mask(struct mveth_private *mp, uint32_t mask)
+{
+	return mveth_ack_irqs(mp, mask);
+}
+
+int
+BSP_mve_ack_link_chg(struct mveth_private *mp, int *pmedia)
+{
+int media = IFM_MAKEWORD(0,0,0,0);
+
+	if ( 0 == BSP_mve_media_ioctl(mp, SIOCGIFMEDIA, &media)) {
+		if ( IFM_LINK_OK & media ) {
+			mveth_update_serial_port(mp, media);
+			/* If TX stalled because there was no buffer then whack it */
+			mveth_start_tx(mp);
+		}
+		if ( pmedia )
+			*pmedia = media;
+		return 0;
+	}
+	return -1;
+}
+
+/* BSDNET SUPPORT/GLUE ROUTINES */
+
+static void
+mveth_set_filters(struct ifnet *ifp);
+
+STATIC void
+mveth_stop(struct mveth_softc *sc)
+{
+	BSP_mve_stop_hw(&sc->pvt);
+	sc->arpcom.ac_if.if_timer = 0;
+}
+
+/* allocate a mbuf for RX with a properly aligned data buffer
+ * RETURNS 0 if allocation fails
+ */
+static void *
+alloc_mbuf_rx(int *psz, uintptr_t *paddr)
+{
+struct mbuf		*m;
+unsigned long	l,o;
+
+	MGETHDR(m, M_DONTWAIT, MT_DATA);
+	if ( !m )
+		return 0;
+	MCLGET(m, M_DONTWAIT);
+	if ( ! (m->m_flags & M_EXT) ) {
+		m_freem(m);
+		return 0;
+	}
+
+	o = mtod(m, unsigned long);
+	l = MV643XX_ALIGN(o, RX_BUF_ALIGNMENT) - o;
+
+	/* align start of buffer */
+	m->m_data += l;
+
+	/* reduced length */
+	l = MCLBYTES - l;
+
+	m->m_len   = m->m_pkthdr.len = l;
+	*psz       = m->m_len;
+	*paddr     = mtod(m, uintptr_t); 
+
+	return (void*) m;
+}
+
+static void consume_rx_mbuf(void *buf, void *arg, int len)
+{
+struct ifnet *ifp = arg;
+struct mbuf    *m = buf;
+
+	if ( len <= 0 ) {
+		ifp->if_iqdrops++;
+		if ( len < 0 ) {
+			ifp->if_ierrors++;
+		}
+		if ( m )
+			m_freem(m);
+	} else {
+		struct ether_header *eh;
+
+			eh			= (struct ether_header *)(mtod(m, unsigned long) + ETH_RX_OFFSET);
+			m->m_len	= m->m_pkthdr.len = len - sizeof(struct ether_header) - ETH_RX_OFFSET - ETH_CRC_LEN;
+			m->m_data  += sizeof(struct ether_header) + ETH_RX_OFFSET;
+			m->m_pkthdr.rcvif = ifp;
+
+			ifp->if_ipackets++;
+			ifp->if_ibytes  += m->m_pkthdr.len;
+			
+			if (0) {
+				/* Low-level debugging */
+				int i;
+				for (i=0; i<13; i++) {
+					printf("%02X:",((char*)eh)[i]);
+				}
+				printf("%02X\n",((char*)eh)[i]);
+				for (i=0; i<m->m_len; i++) {
+					if ( !(i&15) )
+						printf("\n");
+					printf("0x%02x ",mtod(m,char*)[i]);
+				}
+				printf("\n");
+			}
+
+			if (0) {
+				/* Low-level debugging/testing without bsd stack */
+				m_freem(m);
+			} else {
+				/* send buffer upwards */
+				ether_input(ifp, eh, m);
+			}
+	}
+}
+
+static void release_tx_mbuf(void *buf, void *arg, int err)
+{
+struct ifnet *ifp = arg;
+struct mbuf  *mb  = buf;
+
+	if ( err ) {
+		ifp->if_oerrors++;
+	} else {
+		ifp->if_opackets++;
+	}
+	ifp->if_obytes += mb->m_pkthdr.len;
+	m_freem(mb);
+}
+
+static void
+dump_update_stats(struct mveth_private *mp, FILE *f)
+{
+int      p = mp->port_num;
+int      idx;
+uint32_t v;
+
+	if ( !f )
+		f = stdout;
+
+	fprintf(f, DRVNAME"%i Statistics:\n",        mp->port_num + 1);
+	fprintf(f, "  # IRQS:                 %i\n", mp->stats.irqs);
+	fprintf(f, "  Max. mbuf chain length: %i\n", mp->stats.maxchain);
+	fprintf(f, "  # repacketed:           %i\n", mp->stats.repack);
+	fprintf(f, "  # packets:              %i\n", mp->stats.packet);
+	fprintf(f, "MIB Counters:\n");
+	for ( idx = MV643XX_ETH_MIB_GOOD_OCTS_RCVD_LO>>2;
+			idx < MV643XX_ETH_NUM_MIB_COUNTERS;
+			idx++ ) {
+		switch ( idx ) {
+			case MV643XX_ETH_MIB_GOOD_OCTS_RCVD_LO>>2:
+				mp->stats.mib.good_octs_rcvd += read_long_mib_counter(p, idx);
+				fprintf(f, mibfmt[idx], mp->stats.mib.good_octs_rcvd);
+				idx++;
+				break;
+
+			case MV643XX_ETH_MIB_GOOD_OCTS_SENT_LO>>2:
+				mp->stats.mib.good_octs_sent += read_long_mib_counter(p, idx);
+				fprintf(f, mibfmt[idx], mp->stats.mib.good_octs_sent);
+				idx++;
+				break;
+
+			default:
+				v = ((uint32_t*)&mp->stats.mib)[idx] += read_mib_counter(p, idx);
+				fprintf(f, mibfmt[idx], v);
+				break;
+		}
+	}
+	fprintf(f, "\n");
+}
+
+void
+BSP_mve_dump_stats(struct mveth_private *mp, FILE *f)
+{
+	dump_update_stats(mp, f);
+}
+
+/* BSDNET DRIVER CALLBACKS */
+
+static void
+mveth_init(void *arg)
+{
+struct mveth_softc	*sc  = arg;
+struct ifnet		*ifp = &sc->arpcom.ac_if;
+int                 media;
+
+	BSP_mve_init_hw(&sc->pvt, ifp->if_flags & IFF_PROMISC, sc->arpcom.ac_enaddr);
+
+	media = IFM_MAKEWORD(0, 0, 0, 0);
+	if ( 0 == BSP_mve_media_ioctl(&sc->pvt, SIOCGIFMEDIA, &media) ) {
+	    if ( (IFM_LINK_OK & media) ) {
+			ifp->if_flags &= ~IFF_OACTIVE;
+		} else {
+			ifp->if_flags |= IFF_OACTIVE;
+		}
+	}
+
+	/* if promiscuous then there is no need to change */
+	if ( ! (ifp->if_flags & IFF_PROMISC) )
+		mveth_set_filters(ifp);
+
+	ifp->if_flags |= IFF_RUNNING;
+	sc->arpcom.ac_if.if_timer = 0;
+}
+
+/* bsdnet driver entry to start transmission */
+static void
+mveth_start(struct ifnet *ifp)
+{
+struct mveth_softc	*sc = ifp->if_softc;
+struct mbuf			*m  = 0;
+
+	while ( ifp->if_snd.ifq_head ) {
+		IF_DEQUEUE( &ifp->if_snd, m );
+		if ( BSP_mve_send_buf(&sc->pvt, m, 0, 0) < 0 ) {
+			IF_PREPEND( &ifp->if_snd, m);
+			ifp->if_flags |= IFF_OACTIVE;
+			break;
+		}
+		/* need to do this really only once
+		 * but it's cheaper this way.
+		 */
+		ifp->if_timer = 2*IFNET_SLOWHZ;
+	}
+}
+
+/* bsdnet driver entry; */
+static void
+mveth_watchdog(struct ifnet *ifp)
+{
+struct mveth_softc	*sc = ifp->if_softc;
+
+	ifp->if_oerrors++;
+	printk(DRVNAME"%i: watchdog timeout; resetting\n", ifp->if_unit);
+
+	mveth_init(sc);
+	mveth_start(ifp);
+}
+
+static void
+mveth_set_filters(struct ifnet *ifp)
+{
+struct mveth_softc  *sc = ifp->if_softc;
+uint32_t              v;
+
+	v = MV_READ(MV643XX_ETH_PORT_CONFIG_R(sc->pvt.port_num));
+	if ( ifp->if_flags & IFF_PROMISC )
+		v |= MV643XX_ETH_UNICAST_PROMISC_MODE;
+	else
+		v &= ~MV643XX_ETH_UNICAST_PROMISC_MODE;
+	MV_WRITE(MV643XX_ETH_PORT_CONFIG_R(sc->pvt.port_num), v);
+
+	if ( ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI) ) {
+		BSP_mve_mcast_filter_accept_all(&sc->pvt);
+	} else {
+		struct ether_multi     *enm;
+		struct ether_multistep step;
+
+		BSP_mve_mcast_filter_clear( &sc->pvt );
+		
+		ETHER_FIRST_MULTI(step, (struct arpcom *)ifp, enm);
+
+		while ( enm ) {
+			if ( memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN) )
+				assert( !"Should never get here; IFF_ALLMULTI should be set!" );
+
+			BSP_mve_mcast_filter_accept_add(&sc->pvt, enm->enm_addrlo);
+
+			ETHER_NEXT_MULTI(step, enm);
+		}
+	}
+}
+
+/* bsdnet driver ioctl entry */
+static int
+mveth_ioctl(struct ifnet *ifp, ioctl_command_t cmd, caddr_t data)
+{
+struct mveth_softc	*sc   = ifp->if_softc;
+struct ifreq		*ifr  = (struct ifreq *)data;
+int					error = 0;
+int					f;
+
+	switch ( cmd ) {
+  		case SIOCSIFFLAGS:
+			f = ifp->if_flags;
+			if ( f & IFF_UP ) {
+				if ( ! ( f & IFF_RUNNING ) ) {
+					mveth_init(sc);
+				} else {
+					if ( (f & IFF_PROMISC) != (sc->bsd.oif_flags & IFF_PROMISC) ) {
+						/* Note: in all other scenarios the 'promisc' flag
+						 * in the low-level driver [which affects the way
+						 * the multicast filter is setup: accept none vs.
+						 * accept all in promisc mode] is eventually
+						 * set when the IF is brought up...
+						 */
+						sc->pvt.promisc = (f & IFF_PROMISC);
+
+						mveth_set_filters(ifp);
+					}
+					/* FIXME: other flag changes are ignored/unimplemented */
+				}
+			} else {
+				if ( f & IFF_RUNNING ) {
+					mveth_stop(sc);
+					ifp->if_flags  &= ~(IFF_RUNNING | IFF_OACTIVE);
+				}
+			}
+			sc->bsd.oif_flags = ifp->if_flags;
+		break;
+
+  		case SIOCGIFMEDIA:
+  		case SIOCSIFMEDIA:
+			error = BSP_mve_media_ioctl(&sc->pvt, cmd, &ifr->ifr_media);
+		break;
+ 
+		case SIOCADDMULTI:
+		case SIOCDELMULTI:
+			error = (cmd == SIOCADDMULTI)
+		    		? ether_addmulti(ifr, &sc->arpcom)
+				    : ether_delmulti(ifr, &sc->arpcom);
+
+			if (error == ENETRESET) {
+				if (ifp->if_flags & IFF_RUNNING) {
+					mveth_set_filters(ifp);
+				}
+				error = 0;
+			}
+		break;
+
+
+		break;
+
+ 		case SIO_RTEMS_SHOW_STATS:
+			dump_update_stats(&sc->pvt, stdout);
+		break;
+
+		default:
+			error = ether_ioctl(ifp, cmd, data);
+		break;
+	}
+
+	return error;
+}
+
+/* DRIVER TASK */
+
+/* Daemon task does all the 'interrupt' work */
+static void mveth_daemon(void *arg)
+{
+struct mveth_softc	*sc;
+struct ifnet		*ifp;
+rtems_event_set		evs;
+	for (;;) {
+		rtems_bsdnet_event_receive( 7, RTEMS_WAIT | RTEMS_EVENT_ANY, RTEMS_NO_TIMEOUT, &evs );
+		evs &= 7;
+		for ( sc = theMvEths; evs; evs>>=1, sc++ ) {
+			if ( (evs & 1) ) {
+				register uint32_t x;
+
+				ifp = &sc->arpcom.ac_if;
+
+				if ( !(ifp->if_flags & IFF_UP) ) {
+					mveth_stop(sc);
+					ifp->if_flags &= ~(IFF_UP|IFF_RUNNING);
+					continue;
+				}
+
+				if ( !(ifp->if_flags & IFF_RUNNING) ) {
+					/* event could have been pending at the time hw was stopped;
+					 * just ignore...
+					 */
+					continue;
+				}
+
+				x = mveth_ack_irqs(&sc->pvt, -1);
+
+				if ( MV643XX_ETH_EXT_IRQ_LINK_CHG & x ) {
+					/* phy status changed */
+					int media;
+
+					if ( 0 == BSP_mve_ack_link_chg(&sc->pvt, &media) ) {
+						if ( IFM_LINK_OK & media ) {
+							ifp->if_flags &= ~IFF_OACTIVE;
+							mveth_start(ifp);
+						} else {
+							/* stop sending */
+							ifp->if_flags |= IFF_OACTIVE;
+						}
+					}
+				}
+				/* free tx chain */
+				if ( (MV643XX_ETH_EXT_IRQ_TX_DONE & x) && BSP_mve_swipe_tx(&sc->pvt) ) {
+					ifp->if_flags &= ~IFF_OACTIVE;
+					if ( TX_AVAILABLE_RING_SIZE(&sc->pvt) == sc->pvt.avail )
+						ifp->if_timer = 0;
+					mveth_start(ifp);
+				}
+				if ( (MV643XX_ETH_IRQ_RX_DONE & x) )
+					BSP_mve_swipe_rx(&sc->pvt);
+
+				mveth_enable_irqs(&sc->pvt, -1);
+			}
+		}
+	}
+}
+
+#ifdef  MVETH_DETACH_HACK
+static int mveth_detach(struct mveth_softc *sc);
+#endif
+
+
+/* PUBLIC RTEMS BSDNET ATTACH FUNCTION */
+int
+rtems_mve_attach(struct rtems_bsdnet_ifconfig *ifcfg, int attaching)
+{
+char				*unitName;
+int					unit,i,cfgUnits;
+struct	mveth_softc *sc;
+struct	ifnet		*ifp;
+
+	unit = rtems_bsdnet_parse_driver_name(ifcfg, &unitName);
+	if ( unit <= 0 || unit > MV643XXETH_NUM_DRIVER_SLOTS ) {
+		printk(DRVNAME": Bad unit number %i; must be 1..%i\n", unit, MV643XXETH_NUM_DRIVER_SLOTS);
+		return 1;
+	}
+
+	sc  = &theMvEths[unit-1];
+	ifp = &sc->arpcom.ac_if;
+	sc->pvt.port_num = unit-1;
+	sc->pvt.phy      = (MV_READ(MV643XX_ETH_PHY_ADDR_R) >> (5*sc->pvt.port_num)) & 0x1f;
+
+	if ( attaching ) {
+		if ( ifp->if_init ) {
+			printk(DRVNAME": instance %i already attached.\n", unit);
+			return -1;
+		}
+
+		for ( i=cfgUnits = 0; i<MV643XXETH_NUM_DRIVER_SLOTS; i++ ) {
+			if ( theMvEths[i].arpcom.ac_if.if_init )
+				cfgUnits++;
+		}
+		cfgUnits++; /* this new one */
+
+		/* lazy init of TID should still be thread-safe because we are protected
+		 * by the global networking semaphore..
+		 */
+		if ( !mveth_tid ) {
+			/* newproc uses the 1st 4 chars of name string to build an rtems name */
+			mveth_tid = rtems_bsdnet_newproc("MVEd", 4096, mveth_daemon, 0);
+		}
+
+		if ( !BSP_mve_setup( unit,
+						     mveth_tid,
+						     release_tx_mbuf, ifp,
+						     alloc_mbuf_rx,
+						     consume_rx_mbuf, ifp,
+						     ifcfg->rbuf_count,
+						     ifcfg->xbuf_count,
+			                 BSP_MVE_IRQ_TX | BSP_MVE_IRQ_RX | BSP_MVE_IRQ_LINK) ) {
+			return -1;
+		}
+
+		if ( nmbclusters < sc->pvt.rbuf_count * cfgUnits + 60 /* arbitrary */ )  {
+			printk(DRVNAME"%i: (mv643xx ethernet) Your application has not enough mbuf clusters\n", unit);
+			printk(     "                         configured for this driver.\n");
+			return -1;
+		}
+
+		if ( ifcfg->hardware_address ) {
+			memcpy(sc->arpcom.ac_enaddr, ifcfg->hardware_address, ETHER_ADDR_LEN);
+		} else {
+			/* read back from hardware assuming that MotLoad already had set it up */
+			BSP_mve_read_eaddr(&sc->pvt, sc->arpcom.ac_enaddr);
+		}
+
+		ifp->if_softc			= sc;
+		ifp->if_unit			= unit;
+		ifp->if_name			= unitName;
+
+		ifp->if_mtu				= ifcfg->mtu ? ifcfg->mtu : ETHERMTU;
+
+		ifp->if_init			= mveth_init;
+		ifp->if_ioctl			= mveth_ioctl;
+		ifp->if_start			= mveth_start;
+		ifp->if_output			= ether_output;
+		/*
+		 * While nonzero, the 'if->if_timer' is decremented
+		 * (by the networking code) at a rate of IFNET_SLOWHZ (1hz) and 'if_watchdog'
+		 * is called when it expires. 
+		 * If either of those fields is 0 the feature is disabled.
+		 */
+		ifp->if_watchdog		= mveth_watchdog;
+		ifp->if_timer			= 0;
+
+		sc->bsd.oif_flags		= /* ... */
+		ifp->if_flags			= IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX;
+
+		/*
+		 * if unset, this set to 10Mbps by ether_ifattach; seems to be unused by bsdnet stack;
+		 * could be updated along with phy speed, though...
+		ifp->if_baudrate		= 10000000;
+		*/
+
+		/* NOTE: ether_output drops packets if ifq_len >= ifq_maxlen
+		 *       but this is the packet count, not the fragment count!
+		ifp->if_snd.ifq_maxlen	= sc->pvt.xbuf_count;
+		*/
+		ifp->if_snd.ifq_maxlen	= ifqmaxlen;
+
+#ifdef  MVETH_DETACH_HACK
+		if ( !ifp->if_addrlist ) /* do only the first time [reattach hack] */
+#endif
+		{
+			if_attach(ifp);
+			ether_ifattach(ifp);
+		}
+
+	} else {
+#ifdef  MVETH_DETACH_HACK
+		if ( !ifp->if_init ) {
+			printk(DRVNAME": instance %i not attached.\n", unit);
+			return -1;
+		}
+		return mveth_detach(sc);
+#else
+		printk(DRVNAME": interface detaching not implemented\n");
+		return -1;
+#endif
+	}
+
+	return 0;
+}
+
+/* EARLY PHY ACCESS */
+static int
+mveth_early_init(int idx)
+{
+	if ( idx < 0 || idx >= MV643XXETH_NUM_DRIVER_SLOTS )
+		return -1;
+
+	/* determine the phy */
+	theMvEths[idx].pvt.phy = (MV_READ(MV643XX_ETH_PHY_ADDR_R) >> (5*idx)) & 0x1f;
+	return 0;
+}
+
+static int
+mveth_early_read_phy(int idx, unsigned reg)
+{
+int rval;
+
+	if ( idx < 0 || idx >= MV643XXETH_NUM_DRIVER_SLOTS )
+		return -1;
+
+	rval = mveth_mii_read(&theMvEths[idx].pvt, reg);
+	return rval < 0 ? rval : rval & 0xffff;
+}
+
+static int
+mveth_early_write_phy(int idx, unsigned reg, unsigned val)
+{
+	if ( idx < 0 || idx >= MV643XXETH_NUM_DRIVER_SLOTS )
+		return -1;
+
+	mveth_mii_write(&theMvEths[idx].pvt, reg, val);
+	return 0;
+}
+
+rtems_bsdnet_early_link_check_ops
+rtems_mve_early_link_check_ops = {
+	init:		mveth_early_init,
+	read_phy:	mveth_early_read_phy,
+	write_phy:	mveth_early_write_phy,
+	name:		DRVNAME,
+	num_slots:	MAX_NUM_SLOTS
+};
+
+/* DEBUGGING */
+
+#ifdef MVETH_DEBUG
+/* Display/dump descriptor rings */
+
+int
+mveth_dring(struct mveth_softc *sc)
+{
+int i;
+if (1) {
+MvEthRxDesc pr;
+printf("RX:\n");
+
+	for (i=0, pr=sc->pvt.rx_ring; i<sc->pvt.rbuf_count; i++, pr++) {
+#ifndef ENABLE_HW_SNOOPING
+		/* can't just invalidate the descriptor - if it contains
+		 * data that hasn't been flushed yet, we create an inconsistency...
+		 */
+		rtems_bsdnet_semaphore_obtain();
+		INVAL_DESC(pr);
+#endif
+		printf("cnt: 0x%04x, size: 0x%04x, stat: 0x%08x, next: 0x%08x, buf: 0x%08x\n",
+			pr->byte_cnt, pr->buf_size, pr->cmd_sts, (uint32_t)pr->next_desc_ptr, pr->buf_ptr);
+
+#ifndef ENABLE_HW_SNOOPING
+		rtems_bsdnet_semaphore_release();
+#endif
+	}
+}
+if (1) {
+MvEthTxDesc pt;
+printf("TX:\n");
+	for (i=0, pt=sc->pvt.tx_ring; i<sc->pvt.xbuf_count; i++, pt++) {
+#ifndef ENABLE_HW_SNOOPING
+		rtems_bsdnet_semaphore_obtain();
+		INVAL_DESC(pt);
+#endif
+		printf("cnt: 0x%04x, stat: 0x%08x, next: 0x%08x, buf: 0x%08x, mb: 0x%08x\n",
+			pt->byte_cnt, pt->cmd_sts, (uint32_t)pt->next_desc_ptr, pt->buf_ptr,
+			(uint32_t)pt->mb);
+
+#ifndef ENABLE_HW_SNOOPING
+		rtems_bsdnet_semaphore_release();
+#endif
+	}
+}
+	return 0;
+}
+
+#endif
+
+/* DETACH HACK DETAILS */
+
+#ifdef  MVETH_DETACH_HACK
+int
+_cexpModuleFinalize(void *mh)
+{
+int i;
+	for ( i=0; i<MV643XXETH_NUM_DRIVER_SLOTS; i++ ) {
+		if ( theMvEths[i].arpcom.ac_if.if_init ) {
+			printf("Interface %i still attached; refuse to unload\n", i+1);
+			return -1;
+		}
+	}
+	/* delete task; since there are no attached interfaces, it should block
+	 * for events and hence not hold the semaphore or other resources...
+	 */
+	rtems_task_delete(mveth_tid);
+	return 0;
+}
+
+/* ugly hack to allow unloading/reloading the driver core.
+ * needed because rtems' bsdnet release doesn't implement
+ * if_detach(). Therefore, we bring the interface down but
+ * keep the device record alive...
+ */
+static void
+ether_ifdetach_pvt(struct ifnet *ifp)
+{
+        ifp->if_flags = 0;
+        ifp->if_ioctl = 0;
+        ifp->if_start = 0;
+        ifp->if_watchdog = 0;
+        ifp->if_init  = 0;
+}
+
+static int
+mveth_detach(struct mveth_softc *sc)
+{
+struct ifnet	*ifp = &sc->arpcom.ac_if;
+	if ( ifp->if_init ) {
+		if ( ifp->if_flags & (IFF_UP | IFF_RUNNING) ) {
+			printf(DRVNAME"%i: refuse to detach; interface still up\n",sc->pvt.port_num+1);
+			return -1;
+		}
+		mveth_stop(sc);
+/* not implemented in BSDnet/RTEMS (yet) but declared in header */
+#define ether_ifdetach ether_ifdetach_pvt
+		ether_ifdetach(ifp);
+	}
+	free( (void*)sc->pvt.ring_area, M_DEVBUF );
+	sc->pvt.ring_area = 0;
+	sc->pvt.tx_ring   = 0;
+	sc->pvt.rx_ring   = 0;
+	sc->pvt.d_tx_t    = sc->pvt.d_tx_h   = 0;
+	sc->pvt.d_rx_t    = 0;
+	sc->pvt.avail     = 0;
+	/* may fail if ISR was not installed yet */
+	BSP_remove_rtems_irq_handler( &irq_data[sc->pvt.port_num] );
+	return 0;
+}
+
+#ifdef MVETH_DEBUG
+struct rtems_bsdnet_ifconfig mveth_dbg_config = {
+	name:				DRVNAME"1",
+	attach:				rtems_mve_attach,
+	ip_address:			"192.168.2.10",		/* not used by rtems_bsdnet_attach */
+	ip_netmask:			"255.255.255.0",	/* not used by rtems_bsdnet_attach */
+	hardware_address:	0, /* (void *) */
+	ignore_broadcast:	0,					/* TODO driver should honour this  */
+	mtu:				0,
+	rbuf_count:			0,					/* TODO driver should honour this  */
+	xbuf_count:			0,					/* TODO driver should honour this  */
+};
+#endif
+#endif
Index: bsps/powerpc/beatnik/net/if_mve/mve_smallbuf_tst.c
===================================================================
--- bsps/powerpc/beatnik/net/if_mve/mve_smallbuf_tst.c	(revision 031df3914990db0336a0d386fb53558b05de467e)
+++ bsps/powerpc/beatnik/net/if_mve/mve_smallbuf_tst.c	(revision 031df3914990db0336a0d386fb53558b05de467e)
@@ -0,0 +1,145 @@
+#include <rtems.h>
+#include <bsp.h>
+#include <bsp/if_mve_pub.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+/* Demo for the mv64360 ethernet quirk:
+ *
+ * $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
+ * $$ buffer segments < 8 bytes must be aligned $$
+ * $$ to 8 bytes but larger segments are not    $$
+ * $$ sensitive to alignment.                   $$
+ * $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
+ *
+ * How to use:
+ *
+ *   Init MVE driver on (unused) unit 2:
+ *
+ *    mve = mvtst_init(2)
+ *
+ *    data = { 1,2,3,4,5,6,7,8,9,0xa,0xb, ... }
+ *
+ *   Alloc 2-element mbuf chain (1st holds an
+ *   ethernet header which is > 8bytes so we can't
+ *   test this with only 1 mbuf. The 2nd mbuf holds
+ *   a small fragment of data).
+ *
+ *     mb  = mvtst_getbuf(mve)
+ *
+ *   Copy data into aligned area inside 2nd mbuf,
+ *   (so that you can see if the chip starts using
+ *   the aligned area rather than the unaligned
+ *   buffer pointer). Point mbuf's data pointer
+ *   at 'off'set from the aligned area:
+ *
+ *     mvtst_putbuf(mb, data, len, offset)
+ *
+ *   Send chain off:
+ *
+ *    BSP_mve_send_buf(mve, mb, 0, 0)
+ *
+ *   Watch raw data:
+ *
+ *    tcpdump -XX -vv -s0 ether host <my-ether-addr>
+ *
+ *   E.g, if offset = 1, len = 2 then we would like
+ *   to see 
+ *  
+ *   GOOD:
+ *           < 14 header bytes > 0x02, 0x03
+
+ *   but if the chip starts DMA at aligned address
+ *   we see instead
+ *   BAD:
+ *           < 14 header bytes > 0x01, 0x02
+ */
+
+static inline void *rmalloc(size_t l) { return malloc(l); }
+static inline void  rfree(void *p) { return free(p); }
+
+#define _KERNEL
+#include <sys/param.h>
+#include <sys/mbuf.h>
+
+static void
+cleanup_buf(void *u_b, void *closure, int error)
+{
+rtems_bsdnet_semaphore_obtain();
+	m_freem((struct mbuf*)u_b);
+rtems_bsdnet_semaphore_release();
+}
+
+struct mbuf *mvtst_getbuf(struct mveth_private *mp)
+{
+struct mbuf *m,*n;
+
+	if ( !mp ) {
+		printf("need driver ptr arg\n");
+		return 0;
+	}
+rtems_bsdnet_semaphore_obtain();
+	MGETHDR(m, M_DONTWAIT, MT_DATA);
+	MGET(n, M_DONTWAIT, MT_DATA);
+	m->m_next = n;
+rtems_bsdnet_semaphore_release();
+	/* Ethernet header */
+	memset( mtod(m, unsigned char*), 0xff, 6);
+	BSP_mve_read_eaddr(mp, mtod(m, unsigned char*) + 6);
+	/* Arbitrary; setting to IP but we don't bother
+	 * to setup a real IP header. We just watch the
+	 * raw packet contents...
+	 */
+	mtod(m, unsigned char*)[12] = 0x08;
+	mtod(m, unsigned char*)[13] = 0x00;
+	m->m_pkthdr.len = m->m_len = 14;
+	n->m_len = 0;
+	return m;
+}
+
+int
+mvtst_putbuf(struct mbuf *m, void *data, int len, int off)
+{
+int i;
+	if ( m ) {
+		m->m_pkthdr.len += len;
+	if ( ( m= m->m_next ) ) {
+		m->m_len = len;
+		memcpy(mtod(m, void*), data, 32);
+		m->m_data += off;
+		printf("m.dat: 0x%08x, m.data: 0x%08x\n", m->m_dat, m->m_data);
+		for ( i=0; i< 16; i++ ) {
+			printf(" %02x,",mtod(m, unsigned char*)[i]);
+		}
+		printf("\n");
+	}
+	}
+	
+	return 0;
+}
+
+static void *alloc_rxbuf(int *p_size, unsigned long *paddr)
+{
+	return *(void**)paddr = rmalloc((*p_size = 1800));
+}
+
+static void consume_buf(void *buf, void *closure, int len)
+{
+	rfree(buf);
+}
+
+void *
+mvtst_init(int unit)
+{
+struct mveth_private *mp;
+	mp = BSP_mve_setup(
+		unit, 0,
+		cleanup_buf, 0,
+		alloc_rxbuf,
+		consume_buf, 0,
+		10, 10,
+		0);
+	if ( mp )
+		BSP_mve_init_hw(mp, 0, 0);
+	return mp;
+}
Index: bsps/powerpc/beatnik/net/if_mve/testing.c
===================================================================
--- bsps/powerpc/beatnik/net/if_mve/testing.c	(revision 031df3914990db0336a0d386fb53558b05de467e)
+++ bsps/powerpc/beatnik/net/if_mve/testing.c	(revision 031df3914990db0336a0d386fb53558b05de467e)
@@ -0,0 +1,324 @@
+#ifndef KERNEL
+#define KERNEL
+#endif
+
+#include <rtems.h>
+#include <rtems/rtems_bsdnet_internal.h>
+#include <bsp.h>
+#include <sys/param.h>
+#include <sys/mbuf.h>
+
+#include "mv64340_eth_ll.h"
+
+#include <string.h>
+#include <assert.h>
+
+#include <netinet/in.h>
+#include <stdio.h>
+
+#define RX_SPACING 1
+#define TX_SPACING 1
+
+#define RX_RING_SIZE (MV64340_RX_QUEUE_SIZE*RX_SPACING)
+#define TX_RING_SIZE (MV64340_TX_QUEUE_SIZE*TX_SPACING)
+
+
+struct eth_rx_desc rx_ring[RX_RING_SIZE] __attribute__((aligned(32)));
+struct eth_rx_desc rx_ring[RX_RING_SIZE] = {{0},};
+
+struct eth_tx_desc tx_ring[TX_RING_SIZE] __attribute__((aligned(32)));
+struct eth_tx_desc tx_ring[TX_RING_SIZE] = {{0},};
+
+/* packet buffers */
+char rx_buf[MV64340_RX_QUEUE_SIZE][2048] __attribute__((aligned(8)));
+char rx_buf[MV64340_RX_QUEUE_SIZE][2048];
+
+char tx_buf[MV64340_RX_QUEUE_SIZE][2048] __attribute__((aligned(8)));
+char tx_buf[MV64340_RX_QUEUE_SIZE][2048];
+
+char BcHeader[22] = {
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* dst */
+	0x00, 0x01, 0xaf, 0x13, 0xb5, 0x3e, /* src */
+	00, 00, /* len */
+	0xAA,	/* dsap */
+	0xAA,	/* ssap */
+	0x03,	/* ctrl */
+	0x08, 0x00, 0x56,	/* snap_org [stanford] */
+	0x80, 0x5b,			/* snap_type (stanford kernel) */
+};
+
+struct mv64340_private mveth = {
+	port_num: 0,
+	port_mac_addr: {0x00,0x01,0xAF,0x13,0xB5,0x3C},
+	/* port_config .. tx_resource_err are set by port_init */
+	0
+};
+
+struct pkt_info p0,p1;
+
+static inline void rx_stopq(int port)
+{
+	MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(port), 0x0000ff00);
+}
+
+static inline void tx_stopq(int port)
+{
+	MV_WRITE(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(port), 0x0000ff00);
+}
+
+#define MV64360_ENET2MEM_SNOOP_NONE 0x0000
+#define MV64360_ENET2MEM_SNOOP_WT	0x1000
+#define MV64360_ENET2MEM_SNOOP_WB	0x2000
+
+#if 0
+int
+mveth_init(struct mv64340_private *mp)
+{
+int i;
+	mp->p_rx_desc_area = rx_ring;
+	mp->p_tx_desc_area = tx_ring;
+
+	rx_stopq(mp->port_num);
+	tx_stopq(mp->port_num);
+
+	/* MotLoad has cache snooping disabled on the ENET2MEM windows.
+	 * Some comments in (linux) indicate that there are errata
+	 * which cause problems which is a real bummer.
+	 * We try it anyways...
+	 */
+	{
+	unsigned long disbl, bar;
+	disbl = MV_READ(MV64340_ETH_BASE_ADDR_ENABLE_REG);
+	/* disable all 6 windows */
+	MV_WRITE(MV64340_ETH_BASE_ADDR_ENABLE_REG, 0x3f);
+	/* set WB snooping */
+	for ( i=0; i<6*8; i+=8 ) {
+		if ( (bar = MV_READ(MV64340_ETH_BAR_0 + i)) && MV_READ(MV64340_ETH_SIZE_REG_0 + i) ) {
+			MV_WRITE(MV64340_ETH_BAR_0 + i, bar | MV64360_ENET2MEM_SNOOP_WB);
+			/* read back to flush fifo [linux comment] */
+			(void)MV_READ(MV64340_ETH_BAR_0 + i);
+		}
+	}
+	/* restore/re-enable */
+	MV_WRITE(MV64340_ETH_BASE_ADDR_ENABLE_REG, disbl);
+	}
+
+	eth_port_init(mp);
+
+	sleep(1);
+
+	mveth_init_tx_desc_ring(mp);
+	mveth_init_rx_desc_ring(mp);
+#if 0
+	for ( i = 0; i<MV64340_RX_QUEUE_SIZE; i++ ) {
+		p0.byte_cnt 	= sizeof(rx_buf[0]);
+		p0.buf_ptr  	= (dma_addr_t)rx_buf[i];
+		p0.return_info  = (void*)i;
+		/* other fields are not used by ll driver */
+		assert ( ETH_OK == eth_rx_return_buff(mp,&p0) );
+	}
+	memset(&p0, 0, sizeof(p0));
+#endif
+
+	return eth_port_start(mp);
+}
+#endif
+
+void
+mveth_stop(struct mv64340_private *mp)
+{
+extern void mveth_stop_hw();
+	rtems_bsdnet_semaphore_obtain();
+		mveth_stop_hw(mp);
+	rtems_bsdnet_semaphore_release();
+}
+
+extern int mveth_send_mbuf();
+extern int mveth_swipe_tx();
+
+int
+mveth_tx(struct mv64340_private *mp, char *data, int len, int nbufs)
+{
+int rval = -1,l;
+char        *p;
+struct mbuf *m;
+char 	*emsg = 0;
+
+	rtems_bsdnet_semaphore_obtain();
+	MGETHDR(m, M_WAIT, MT_DATA);
+	if ( !m ) {
+		emsg="Unable to allocate header\n";
+		goto bail;
+	}
+	MCLGET(m, M_WAIT);
+	if ( !(m->m_flags & M_EXT) ) {
+		m_freem(m);
+		emsg="Unable to allocate cluster\n";
+		goto bail;
+	}
+	p = mtod(m, char *);
+	l = 0;
+	switch (nbufs) {
+		case 3:
+		default:
+			emsg="nbufs arg must be 1..3\n";
+			goto bail;
+
+		case 1:
+			l += sizeof(BcHeader);
+			memcpy(p, &BcHeader, sizeof(BcHeader));
+			p += sizeof(BcHeader);
+
+		case 2:
+			memcpy(p,data,len);
+			l += len;
+			m->m_len = m->m_pkthdr.len = l;
+			if ( 2 == nbufs ) {
+    			M_PREPEND(m, sizeof (BcHeader), M_WAIT);
+				if (!m) {
+					emsg = "Unable to prepend\n";
+					goto bail;
+				}
+				p = mtod(m, char*);
+				memcpy(p,&BcHeader,sizeof(BcHeader));
+				l += sizeof(BcHeader);
+			}
+		break;
+	}
+	*(short*)(mtod(m, char*) + 12) = htons(l-14);
+	rval = mveth_send_mbuf(mp,m);
+
+bail:
+	rtems_bsdnet_semaphore_release();
+	if (emsg)
+		printf(emsg);
+
+#if 0
+    /*
+     * Add local net header.  If no space in first mbuf,
+     * allocate another.
+     */
+    M_PREPEND(m, sizeof (struct ether_header), M_DONTWAIT);
+    if (m == 0)
+        senderr(ENOBUFS);
+    eh = mtod(m, struct ether_header *);
+    (void)memcpy(&eh->ether_type, &type,
+        sizeof(eh->ether_type));
+    (void)memcpy(eh->ether_dhost, edst, sizeof (edst));
+    (void)memcpy(eh->ether_shost, ac->ac_enaddr,
+        sizeof(eh->ether_shost));
+#endif
+	return rval;
+}
+
+int
+mveth_protected(int (*p)(struct mv64340_private*), struct mv64340_private *mp)
+{
+int rval;
+	rtems_bsdnet_semaphore_obtain();
+		rval = p(mp);
+	rtems_bsdnet_semaphore_release();
+	return rval;
+}
+
+int
+mveth_rx(struct mv64340_private *mp)
+{
+extern int mveth_swipe_rx();
+	return mveth_protected(mveth_swipe_rx,mp);
+}
+
+int
+mveth_reclaim(struct mv64340_private *mp)
+{
+extern int mveth_swipe_tx();
+	return mveth_protected(mveth_swipe_tx,mp);
+}
+
+
+int preth(FILE *f, char *p)
+{
+int i;
+	for (i=0; i<4; i++)
+		fprintf(f,"%02X:",p[i]);
+	fprintf(f,"%02X",p[i]);
+	return 6;
+}
+
+char *errcode2str(st)
+{
+char *rval;
+	switch(st) {
+		case ETH_OK:
+			rval = "OK";
+		break;
+		case ETH_ERROR:
+			rval = "Fundamental error.";
+		break;
+		case ETH_RETRY:
+			rval = "Could not process request. Try later.";
+		break;
+		case ETH_END_OF_JOB:
+			rval = "Ring has nothing to process.";
+		break;
+		case ETH_QUEUE_FULL:
+			rval = "Ring resource error.";
+		break;
+		case ETH_QUEUE_LAST_RESOURCE:
+			rval = "Ring resources about to exhaust.";
+		break;
+		default:
+			rval = "UNKNOWN"; break;
+	}
+	return rval;
+}
+
+
+#if 0
+int
+mveth_rx(struct mv64340_private *mp)
+{
+int st;
+struct pkt_info p;
+	if ( ETH_OK != (st=eth_port_receive(mp, &p)) ) {
+		fprintf(stderr,"receive: %s\n", errcode2str(st));
+		return -1;
+	}
+	printf("%i bytes received from ", p.byte_cnt);
+	preth(stdout,(char*)p.buf_ptr+6);
+	printf(" (desc. stat: 0x%08x)\n", p.cmd_sts);
+		
+	p.byte_cnt = sizeof(rx_buf[0]);
+	p.buf_ptr -= RX_BUF_OFFSET;
+	if ( ETH_OK != (st=eth_rx_return_buff(mp,&p) ) ) {
+		fprintf(stderr,"returning buffer: %s\n", errcode2str(st));
+		return -1;
+	}
+	return 0;
+}
+#endif
+
+int
+dring()
+{
+int i;
+if (1) {
+struct eth_rx_desc *pr;
+printf("RX:\n");
+	for (i=0, pr=rx_ring; i<RX_RING_SIZE; i+=RX_SPACING, pr+=RX_SPACING) {
+		dcbi(pr);
+		printf("cnt: 0x%04x, size: 0x%04x, stat: 0x%08x, next: 0x%08x, buf: 0x%08x\n",
+			pr->byte_cnt, pr->buf_size, pr->cmd_sts, pr->next_desc_ptr, pr->buf_ptr);
+	}
+}
+if (1) {
+struct eth_tx_desc *pt;
+printf("TX:\n");
+	for (i=0, pt=tx_ring; i<TX_RING_SIZE; i+=TX_SPACING, pt+=TX_SPACING) {
+		dcbi(pt);
+		printf("cnt: 0x%04x, stat: 0x%08x, next: 0x%08x, buf: 0x%08x\n",
+			pt->byte_cnt, pt->cmd_sts, pt->next_desc_ptr, pt->buf_ptr);
+	}
+}
+	return 0;
+}
Index: bsps/powerpc/beatnik/net/porting/LICENSE
===================================================================
--- bsps/powerpc/beatnik/net/porting/LICENSE	(revision 031df3914990db0336a0d386fb53558b05de467e)
+++ bsps/powerpc/beatnik/net/porting/LICENSE	(revision 031df3914990db0336a0d386fb53558b05de467e)
@@ -0,0 +1,51 @@
+/* NOTE: The terms described in this LICENSE file apply only to the
+ *       files created by the author (see below). Consult individual
+ *       file headers for more details. Some files were ported from
+ *       netbsd and/or freebsd and are covered by the respective 
+ *       file header copyright notices.
+ */
+
+/* 
+ * Authorship
+ * ----------
+ * This software ('RTEMS-portability wrappers for BSD network drivers') was
+ *     created by Till Straumann <strauman@slac.stanford.edu>, 2005-2007,
+ * 	   Stanford Linear Accelerator Center, Stanford University.
+ * 
+ * Acknowledgement of sponsorship
+ * ------------------------------
+ * The 'RTEMS-portability wrappers for BSD network drivers' software was produced by
+ *     the Stanford Linear Accelerator Center, Stanford University,
+ * 	   under Contract DE-AC03-76SFO0515 with the Department of Energy.
+ * 
+ * Government disclaimer of liability
+ * ----------------------------------
+ * Neither the United States nor the United States Department of Energy,
+ * nor any of their employees, makes any warranty, express or implied, or
+ * assumes any legal liability or responsibility for the accuracy,
+ * completeness, or usefulness of any data, apparatus, product, or process
+ * disclosed, or represents that its use would not infringe privately owned
+ * rights.
+ * 
+ * Stanford disclaimer of liability
+ * --------------------------------
+ * Stanford University makes no representations or warranties, express or
+ * implied, nor assumes any liability for the use of this software.
+ * 
+ * Stanford disclaimer of copyright
+ * --------------------------------
+ * Stanford University, owner of the copyright, hereby disclaims its
+ * copyright and all other rights in this software.  Hence, anyone may
+ * freely use it for any purpose without restriction.  
+ * 
+ * Maintenance of notices
+ * ----------------------
+ * In the interest of clarity regarding the origin and status of this
+ * SLAC software, this and all the preceding Stanford University notices
+ * are to remain affixed to any copy or derivative of this software made
+ * or distributed by the recipient and are to be affixed to any copy of
+ * software made or distributed by the recipient that contains a copy or
+ * derivative of this software.
+ * 
+ * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
+ */ 
Index: bsps/powerpc/beatnik/net/porting/Makefile.template
===================================================================
--- bsps/powerpc/beatnik/net/porting/Makefile.template	(revision 031df3914990db0336a0d386fb53558b05de467e)
+++ bsps/powerpc/beatnik/net/porting/Makefile.template	(revision 031df3914990db0336a0d386fb53558b05de467e)
@@ -0,0 +1,84 @@
+#
+#  Makefile.lib,v 1.5 2000/06/12 15:00:14 joel Exp
+#
+# Copyright: Till Straumann <strauman@slac.stanford.edu>, 2005;
+# License:   see LICENSE file.
+#
+# Templates/Makefile.lib
+#       Template library Makefile
+#
+
+LIBNAME=libif_XXX.a        # XXX- your library names goes here
+LIB=${ARCH}/${LIBNAME}
+
+# C and C++ source names, if any, go here -- minus the .c or .cc
+C_PIECES=if_XXX if_XXX_rtems
+C_FILES=$(C_PIECES:%=%.c)
+C_O_FILES=$(C_PIECES:%=${ARCH}/%.o)
+
+CC_PIECES=
+CC_FILES=$(CC_PIECES:%=%.cc)
+CC_O_FILES=$(CC_PIECES:%=${ARCH}/%.o)
+
+H_FILES=
+
+# Assembly source names, if any, go here -- minus the .S
+S_PIECES=
+S_FILES=$(S_PIECES:%=%.S)
+S_O_FILES=$(S_FILES:%.S=${ARCH}/%.o)
+
+SRCS=$(C_FILES) $(CC_FILES) $(H_FILES) $(S_FILES)
+OBJS=$(C_O_FILES) $(CC_O_FILES) $(S_O_FILES)
+
+include $(RTEMS_MAKEFILE_PATH)/Makefile.inc
+
+include $(RTEMS_CUSTOM)
+include $(RTEMS_ROOT)/make/lib.cfg
+
+#
+# Add local stuff here using +=
+#
+
+#DEFINES  += -DHAVE_LIBBSPEXT -DDEBUG_MODULAR
+CPPFLAGS += -I. -Ilibchip -Iporting
+# bsdnet newproc generated daemon is non-FP;
+# prevent optimizer from generating FP instructions
+CFLAGS   += -Wno-unused-variable -msoft-float
+
+#
+# Add your list of files to delete here.  The config files
+#  already know how to delete some stuff, so you may want
+#  to just run 'make clean' first to see what gets missed.
+#  'make clobber' already includes 'make clean'
+#
+
+CLEAN_ADDITIONS += 
+CLOBBER_ADDITIONS +=
+
+all:	${ARCH} $(SRCS) $(LIB)
+
+$(LIB): ${OBJS}
+	$(make-library)
+
+ifndef RTEMS_SITE_INSTALLDIR
+RTEMS_SITE_INSTALLDIR = $(PROJECT_RELEASE)
+endif
+
+${RTEMS_SITE_INSTALLDIR}/include \
+${RTEMS_SITE_INSTALLDIR}/lib \
+${RTEMS_SITE_INSTALLDIR}/bin \
+${RTEMS_SITE_INSTALLDIR}/$(RTEMS_BSP)/include \
+${RTEMS_SITE_INSTALLDIR}/$(RTEMS_BSP)/lib \
+${RTEMS_SITE_INSTALLDIR}/$(RTEMS_BSP)/bin :
+	test -d $@ || mkdir -p $@
+
+# Install the library, appending _g or _p as appropriate.
+# for include files, just use $(INSTALL_CHANGE)
+#
+# NOTES:
+#  - BSP specific libraries, headers etc. should be installed to 
+#          $RTEMS_SITE_INSTALLDIR)/$(RTEMS_BSP)/lib
+#
+
+install:  all $(RTEMS_SITE_INSTALLDIR)/lib
+	$(INSTALL_VARIANT) -m 644 ${LIB} ${RTEMS_SITE_INSTALLDIR}/lib
Index: bsps/powerpc/beatnik/net/porting/README
===================================================================
--- bsps/powerpc/beatnik/net/porting/README	(revision 031df3914990db0336a0d386fb53558b05de467e)
+++ bsps/powerpc/beatnik/net/porting/README	(revision 031df3914990db0336a0d386fb53558b05de467e)
@@ -0,0 +1,104 @@
+Templates to help porting freebsd networking drivers
+to rtems (focus on i386 and powerpc) using a 'quick and dirty'
+approach.
+This is not an elegant piece of software -- be warned.
+
+/* Copyright: Till Straumann <strauman@slac.stanford.edu>, 2005;
+ * License:   see LICENSE file.
+ */
+
+Usage:
+
+  A obtain the freebsd driver source. It usually is made
+    up of a
+     if_XXX.c       --  core driver
+     if_XXXreg.h    --  core header
+     if_XXXvar.h    --  some have it, some don't
+     if_XXX_<bus>.c --  glue to integrate the core
+                        driver with different environments
+                        (such as pccard, pci, ...). There
+                        are several of these.
+
+	Note that you might have to get an older version
+	as some structures and interfaces may have undergone
+	significant changes since the bsd/networking version that
+	was ported to rtems.
+
+  B Copy the Makefile and rtemscompat_defs.h templates to the
+    driver source dir and edit them.
+
+  C Edit if_XXXreg.h and comment all unneeded fields from the
+    'softc' structure declaration with
+
+    #ifndef __rtems__
+    #endif
+
+    In particular, the bushandle field (as defined in rtemscompat_defs.h)
+    above, see comments in the template) must be re-declared:
+
+    #ifndef __rtems__
+	bus_space_handle_t  XXX_bhandle;
+	#else
+	unsigned			XXX_bhandle;
+	unsigned char		irq_no;
+	unsigned char		b,d,f;  /* PCI tuple; needed for PCI only */
+	rtems_id			tid;	/* driver task id */
+	#endif
+
+    Later, the compilation attempts will help identifying
+    fields that need to be removed.
+
+	I like the #ifdef __rtems__  construct as it minimizes changes
+    to the source thus making merging updated driver versions easier.
+
+  D Edit if_XXX.c; at the very top, include the lines
+
+    #ifdef __rtems__
+    #include <rtemscompat.h>
+	#endif
+
+	use the #ifndef __rtems__ #endif construct to comment 
+    unneeded / unsupported inclusion of headers and code pieces.
+
+    - inclusion of net/if_media.h must usually be mapped to 
+                   libchip/if_media.h
+   
+    comment all vm, machine, bus, mii etc. related headers.
+
+    - replace inclusion of if_XXXreg.h by
+
+     #include "if_XXXreg.h" 
+     #include <rtemscompat1.h>
+
+    - work through the if_XXX.c and if_XXXreg.h files commenting
+    stuff until if_XXX.c compiles. This might involve hacking
+    the helper headers.
+
+    - pay attention to endian issues; things may need to be fixed!
+
+    - at the top where the freebsd 'methods' and the like are
+    commented, add a definition of the driver methods for RTEMS:
+
+    #ifdef __rtems__
+	net_drv_tbl_t METHODS = {
+		n_probe  : XXX_probe,
+		n_attach : XXX_attach,
+		n_detach : XXX_detach,  /* optional; */
+		n_intr   : XXX_intr,	/* freebsd ISR; executed from daemon under RTEMS */
+	};
+    #endif
+
+	- make sure all the if_xxx methods are set; in particular,
+      set
+		sc->if_output = ether_output;
+
+	- on input:
+		you can use DO_ETHER_INPUT_SKIPPING_ETHER_HEADER() macro
+		-- if you don't MAKE SURE THE RECEIVING INTERFACE IS SET
+		in the mbuf packet header!!!
+
+  E create 'rtems_<chip>_setup()' to probe for devices and
+    set the softc struct's base address, interrupt line and
+    bus/dev/fun triple (PCI only).
+    For PCI devices, a generic setup routine already comes with
+    porting/if_xxx_rtems.c -> nothing needs to be written!
Index: bsps/powerpc/beatnik/net/porting/if_xxx.modini.c
===================================================================
--- bsps/powerpc/beatnik/net/porting/if_xxx.modini.c	(revision 031df3914990db0336a0d386fb53558b05de467e)
+++ bsps/powerpc/beatnik/net/porting/if_xxx.modini.c	(revision 031df3914990db0336a0d386fb53558b05de467e)
@@ -0,0 +1,34 @@
+#include <rtems.h>
+#include <porting/rtemscompat.h>
+
+/* CEXP module initialization/finalization */
+
+/* Copyright: Till Straumann <strauman@slac.stanford.edu>, 2005;
+ * License:   see LICENSE file.
+ */
+
+void
+_cexpModuleInitialize(void *unused)
+{
+extern void NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_bringup)(char *);
+	METHODSPTR = &METHODS;
+/*
+#ifdef DEBUG
+	NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_bringup)("192.168.2.13/255.255.255.0");
+#endif
+*/
+}
+
+int
+_cexpModuleFinalize(void *unused)
+{
+#ifdef DEBUG
+extern int NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_bringdown)();
+	if (NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_bringdown)())
+		return -1;
+	METHODSPTR = 0;
+	return 0;
+#else
+	return -1;
+#endif
+}
Index: bsps/powerpc/beatnik/net/porting/if_xxx_rtems.c
===================================================================
--- bsps/powerpc/beatnik/net/porting/if_xxx_rtems.c	(revision 031df3914990db0336a0d386fb53558b05de467e)
+++ bsps/powerpc/beatnik/net/porting/if_xxx_rtems.c	(revision 031df3914990db0336a0d386fb53558b05de467e)
@@ -0,0 +1,500 @@
+#include "rtemscompat.h"
+
+/* Template for driver task, setup and attach routines. To be instantiated
+ * by defining the relevant symbols in header files.
+ */
+
+/* Copyright: Till Straumann <strauman@slac.stanford.edu>, 2005;
+ * License:   see LICENSE file.
+ */
+
+#include <rtems/irq.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+
+#include <net/if.h>
+#include <net/if_arp.h>
+
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+#include <net/if_media.h>
+
+#ifdef IF_REG_HEADER
+#include IF_REG_HEADER
+#endif
+#ifdef IF_VAR_HEADER
+#include IF_VAR_HEADER
+#endif
+
+#include "rtemscompat1.h"
+
+#define EX_EVENT RTEMS_EVENT_1
+#undef  IRQ_AT_8259
+
+NETDEV_DECL = { /*[0]:*/{ /* softc: */ { /* arpcom: */{ /* ac_if: */ { 0 }}}}};
+
+static void net_daemon(void *arg);
+
+#ifdef HAVE_LIBBSPEXT
+#include <bsp/bspExt.h>
+static void the_net_isr(void *);
+#else
+static void noop(const rtems_irq_connect_data *unused) {}
+static int  noop1(const rtems_irq_connect_data *unused) { return 0;}
+#if ISMINVERSION(4,6,99)
+static void the_net_isr(rtems_irq_hdl_param);
+#else
+static void the_net_isr();
+#if NETDRIVER_SLOTS > 1
+#error only one instance supported (stupid IRQ API)
+#else
+static struct NET_SOFTC *thesc;
+#endif
+#endif
+#endif
+
+#if defined(NETDRIVER_PCI)
+/* Public setup routine for PCI devices;
+ * TODO: currently doesn't work for subsystem vendor/id , i.e. 
+ *       devices behind a standard PCI interface...
+ */
+int
+NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_pci_setup)(int inst);
+#endif
+
+static unsigned
+NET_EMBEMB(,NETDRIVER_PREFIX,_net_driver_ticks_per_sec) = 0;
+
+/* other drivers may already have this created */
+extern unsigned net_driver_ticks_per_sec
+__attribute__((weak, alias(NET_STRSTR(NETDRIVER_PREFIX)"_net_driver_ticks_per_sec") ));
+
+#ifdef DEBUG_MODULAR
+net_drv_tbl_t * volatile METHODSPTR = 0;
+#endif
+
+
+int
+NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_attach)
+	(struct rtems_bsdnet_ifconfig *config, int attaching)
+{
+	int error     = 0;
+	device_t dev = net_dev_get(config);
+	struct	NET_SOFTC *sc;
+	struct  ifnet     *ifp;
+#ifndef HAVE_LIBBSPEXT
+	rtems_irq_connect_data irq_data = {
+				0,
+				the_net_isr,
+#if ISMINVERSION(4,6,99)
+				0,
+#endif
+				noop,
+				noop,
+				noop1 };
+#endif
+
+	if ( !dev )
+		return 1;
+
+	if ( !dev->d_softc.NET_SOFTC_BHANDLE_FIELD ) {
+#if defined(NETDRIVER_PCI)
+		device_printf(dev,NETDRIVER" unit not configured; executing setup...");
+		/* setup should really be performed prior to attaching.
+		 * Wipe the device; setup and re-obtain the device...
+		 */
+		memset(dev,0,sizeof(*dev));
+		error = NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_pci_setup)(-1);
+		/* re-obtain the device */
+		dev   = net_dev_get(config);
+		if ( !dev ) {
+			printk("Unable to re-assign device structure???\n");
+			return 1;
+		}
+		if (error <= 0) {
+			device_printf(dev,NETDRIVER" FAILED; unable to attach interface, sorry\n");
+			return 1;
+		}
+		device_printf(dev,"success\n");
+#else
+		device_printf(dev,NETDRIVER" unit not configured; use 'rtems_"NETDRIVER"_setup()'\n");
+		return 1;
+#endif
+	}
+
+	if ( !net_driver_ticks_per_sec )
+		net_driver_ticks_per_sec = rtems_clock_get_ticks_per_second();
+
+	sc  = device_get_softc( dev );
+	ifp = &sc->arpcom.ac_if;
+
+#ifdef DEBUG_MODULAR
+	if (!METHODSPTR) {
+		device_printf(dev,NETDRIVER": method pointer not set\n");
+		return -1;
+	}
+#endif
+
+	if ( attaching ) {
+		if ( ifp->if_init ) {
+			device_printf(dev,NETDRIVER" Driver already attached.\n");
+			return -1;
+		}
+		if ( config->hardware_address ) {
+			/* use configured MAC address */
+			memcpy(sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
+		} else {
+#ifdef NET_READ_MAC_ADDR
+			NET_READ_MAC_ADDR(sc);
+#endif
+		}
+		if ( METHODSPTR->n_attach(dev) ) {
+			device_printf(dev,NETDRIVER"_attach() failed\n");
+			return -1;
+		}
+	} else {
+		if ( !ifp->if_init ) {
+			device_printf(dev,NETDRIVER" Driver not attached.\n");
+			return -1;
+		}
+		if ( METHODSPTR->n_detach ) {
+			if ( METHODSPTR->n_detach(dev) ) {
+				device_printf(dev,NETDRIVER"_detach() failed\n");
+				return -1;
+			}
+		} else {
+			device_printf(dev,NETDRIVER"_detach() not implemented\n");
+			return -1;
+		}
+	}
+
+
+	if ( !sc->tid )
+		sc->tid = rtems_bsdnet_newproc(NETDRIVER"d", 4096, net_daemon, sc);
+
+	if (attaching) {
+#ifdef DEBUG
+		printf("Installing IRQ # %i\n",sc->irq_no);
+#endif
+#ifdef HAVE_LIBBSPEXT
+		if ( bspExtInstallSharedISR(sc->irq_no, the_net_isr, sc, 0) )
+#else
+		/* BSP dependent :-( */
+		irq_data.name   = sc->irq_no;
+#if ISMINVERSION(4,6,99)
+		irq_data.handle = (rtems_irq_hdl_param)sc;
+#else
+		thesc = sc;
+#endif
+		if ( ! BSP_install_rtems_irq_handler( &irq_data ) )
+#endif
+		{
+			fprintf(stderr,NETDRIVER": unable to install ISR\n");
+			error = -1;
+		}
+	} else {
+		if ( sc->irq_no ) {
+#ifdef DEBUG
+		printf("Removing IRQ # %i\n",sc->irq_no);
+#endif
+#ifdef HAVE_LIBBSPEXT
+		if (bspExtRemoveSharedISR(sc->irq_no, the_net_isr, sc))
+#else
+		/* BSP dependent :-( */
+		irq_data.name   = sc->irq_no;
+#if ISMINVERSION(4,6,99)
+		irq_data.handle = (rtems_irq_hdl_param)sc;
+#endif
+		if ( ! BSP_remove_rtems_irq_handler( &irq_data ) )
+#endif
+		{
+			fprintf(stderr,NETDRIVER": unable to uninstall ISR\n");
+			error = -1;
+		}
+		}
+	}
+	return error;
+}
+
+static void
+the_net_isr(
+#ifdef HAVE_LIBBSPEXT
+void *thesc
+#elif ISMINVERSION(4,6,99)
+rtems_irq_hdl_param thesc
+#endif
+)
+{
+struct NET_SOFTC *sc = thesc;
+
+	/* disable interrupts */
+	NET_DISABLE_IRQS(sc);
+
+	rtems_bsdnet_event_send( sc->tid, EX_EVENT );
+}
+
+static void net_daemon(void *arg)
+{
+struct NET_SOFTC *sc = arg;
+rtems_event_set evs;
+
+	for (;;) {
+		rtems_bsdnet_event_receive(
+				EX_EVENT,
+				RTEMS_WAIT | RTEMS_EVENT_ANY,
+				RTEMS_NO_TIMEOUT,
+				&evs);
+
+		METHODSPTR->n_intr(sc);
+
+		/* re-enable interrupts */
+		NET_ENABLE_IRQS(sc);
+	}
+}
+
+static struct NET_SOFTC *
+net_drv_check_unit(int unit)
+{
+	unit--;
+	if ( unit < 0 || unit >= NETDRIVER_SLOTS ) {
+		fprintf(stderr,"Invalid unit # %i (not in %i..%i)\n", unit+1, 1, NETDRIVER_SLOTS);
+		return 0;
+	}
+
+	if ( THEDEVS[unit].d_name ) {
+		fprintf(stderr,"Unit %i already set up\n", unit+1);
+		return 0;
+	}
+
+	memset( &THEDEVS[unit], 0, sizeof(THEDEVS[0]) );
+
+	return &THEDEVS[unit].d_softc;
+}
+
+struct rtems_bsdnet_ifconfig NET_EMBEMB(NETDRIVER_PREFIX,_dbg,_config) = {
+	NETDRIVER"1",
+	NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_attach),
+	0
+};
+
+#ifdef DEBUG
+void
+NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_bringup)(char *ipaddr)
+{
+short flags;
+struct sockaddr_in addr;
+char *mask;
+
+
+	if (!ipaddr) {
+		printf("Need an ip[/mask] argument (dot notation)\n");
+		return;
+	}
+
+	ipaddr = strdup(ipaddr);
+
+	if ( (mask = strchr(ipaddr,'/')) ) {
+		*mask++=0;
+	} else {
+		mask = "255.255.255.0";
+	}
+
+#if defined(NETDRIVER_PCI)
+	/* this fails if already setup */
+	NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_pci_setup)(-1);
+#endif
+	rtems_bsdnet_attach(&NET_EMBEMB(NETDRIVER_PREFIX,_dbg,_config));
+
+	flags = IFF_UP /*| IFF_PROMISC*/;
+	if ( rtems_bsdnet_ifconfig(NETDRIVER"1",SIOCSIFFLAGS,&flags) < 0 ) {
+		printf("Can't bring '"NETDRIVER"1' up\n");
+		goto cleanup;
+	}
+	memset(&addr,0,sizeof(addr));
+	addr.sin_len = sizeof(addr);
+	addr.sin_family = AF_INET;
+	addr.sin_addr.s_addr = inet_addr(mask);
+	if ( rtems_bsdnet_ifconfig(NETDRIVER"1",SIOCSIFNETMASK,&addr) < 0 ) {
+		printf("Unable to set netmask on '"NETDRIVER"1'\n");
+		goto cleanup;
+	}
+	addr.sin_addr.s_addr = inet_addr(ipaddr);
+	if ( rtems_bsdnet_ifconfig(NETDRIVER"1",SIOCSIFADDR,&addr) < 0 ) {
+		printf("Unable to set address on '"NETDRIVER"1'\n");
+		goto cleanup;
+	}
+cleanup:
+	the_real_free (ipaddr);
+}
+
+int
+NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_bringdown)()
+{
+short flags;
+	flags = 0;
+	if ( rtems_bsdnet_ifconfig(NETDRIVER"1",SIOCSIFFLAGS,&flags) < 0 ) {
+		printf("Can't bring '"NETDRIVER"1' down\n");
+		return -1;
+	}
+	
+	rtems_bsdnet_detach(&NET_EMBEMB(NETDRIVER_PREFIX,_dbg,_config));
+	return 0;
+}
+#endif
+
+
+#if defined(NETDRIVER_PCI) && !defined(NETDRIVER_OWN_SETUP)
+/* Public setup routine for PCI devices;
+ * TODO: currently doesn't work for subsystem vendor/id , i.e. 
+ *       devices behind a standard PCI interface...
+ * passing 'inst' > only sets-up the 'inst'th card; passing
+ * 'inst' == 0 sets-up all matching cards.
+ */
+int
+NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_pci_setup)(int inst)
+{
+unsigned b,d,f,i,isio,unit;
+rtemscompat_32_t base;
+unsigned short cmd,id;
+unsigned char  h;
+struct NET_SOFTC *sc;
+unsigned try[] = { PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_1, 0 };
+
+#ifdef DEBUG_MODULAR
+	if ( !METHODSPTR ) {
+		fprintf(stderr,NETDRIVER": Methods pointer not set\n");
+		return -1;
+	}
+#endif
+
+	/* 0 can be reached when looking for the desired instance */
+	if ( 0 == inst )
+		inst = -1;
+
+#ifdef HAVE_LIBBSPEXT
+	/* make sure it's initialized */
+	bspExtInit();
+#endif
+
+	/* scan PCI for supported devices */
+	for ( b=0, sc=0, unit=0; b<pci_bus_count(); b++ ) {
+		for ( d=0; d<PCI_MAX_DEVICES; d++ ) {
+			pci_read_config_word(b,d,0,PCI_VENDOR_ID,&id);
+			if ( 0xffff == id )
+					continue; /* empty slot */
+
+			pci_read_config_byte(b,d,0,PCI_HEADER_TYPE,&h);
+			h = h&0x80 ? PCI_MAX_FUNCTIONS : 1; /* multifunction device ? */
+
+			for ( f=0;  f<h; f++ ) {
+				if ( !sc && !(sc=net_drv_check_unit(unit+1))) {
+					fprintf(stderr,"Not enough driver slots; stop looking for more devices...\n");
+					return unit;
+				}
+				pci_read_config_word(b,d,f,PCI_VENDOR_ID,&id);
+				if ( 0xffff == id )
+					continue; /* empty slot */
+
+				pci_read_config_word(b,d,f,PCI_CLASS_DEVICE,&id);
+				if ( PCI_CLASS_NETWORK_ETHERNET != id )
+					continue; /* only look at ethernet devices */
+				
+				sc->b = b;
+				sc->d = d;
+				sc->f = f;
+
+				for ( i=0, base=0, isio=0; try[i]; i++ ) {
+					pci_read_config_dword(b,d,f,try[i],&base);
+					if ( base ) {
+						if ( (isio = (PCI_BASE_ADDRESS_SPACE_IO == (base & PCI_BASE_ADDRESS_SPACE )) ) ) {
+#ifdef NET_CHIP_PORT_IO
+							base &= PCI_BASE_ADDRESS_IO_MASK;
+							sc->NET_SOFTC_BHANDLE_FIELD = PCI_IO_2LOCAL(base,b);
+#ifdef DEBUG
+							printf("Found PCI I/O Base 0x%08x\n", (unsigned)base);
+#endif
+#else
+							base = 0;
+							continue;
+#endif
+						} else {
+#ifdef NET_CHIP_MEM_IO
+							base &= PCI_BASE_ADDRESS_MEM_MASK;
+							sc->NET_SOFTC_BHANDLE_FIELD = PCI2LOCAL(base,b);
+#ifdef DEBUG
+							printf("Found PCI MEM Base 0x%08x\n", (unsigned)base);
+#endif
+#else
+							base = 0;
+							continue;
+#endif
+						}
+					break;
+					}
+				}
+				if ( !base ) {
+#ifdef DEBUG
+					fprintf(stderr, NETDRIVER": (warning) Neither PCI base address 0 nor 1 are configured; skipping bus %i, slot %i, fn %i...\n",b,d,f);	
+#endif
+					continue;
+				}
+
+				if ( 0 == METHODSPTR->n_probe(&THEDEVS[unit]) && (inst < 0 || !--inst) ) {
+					pci_read_config_word(b,d,f,PCI_COMMAND,&cmd);
+					pci_write_config_word(b,d,f,PCI_COMMAND,
+						cmd | (isio ? PCI_COMMAND_IO : PCI_COMMAND_MEMORY) | PCI_COMMAND_MASTER );
+					pci_read_config_byte(b,d,f,PCI_INTERRUPT_LINE,&sc->irq_no);
+					printf(NETDRIVER": card found @PCI[%s] 0x%08x (local 0x%08x), IRQ %i\n",
+						(isio ? "io" : "mem"), (unsigned)base, sc->NET_SOFTC_BHANDLE_FIELD, sc->irq_no);
+
+					sc = 0; /* need to allocate a new slot */
+					unit++;
+
+					if ( 0 == inst ) {
+						/* found desired instance */
+						goto terminated;
+					}
+				}
+			}
+		}
+	}
+
+terminated:
+	return unit;
+}
+#else
+
+/* simple skeleton
+int
+NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_setup)(
+	int		unit,
+	void	*base_addr,
+	int		irq_no)
+{
+struct NET_SOFTC *sc;
+	if ( !(sc=net_drv_check_unit(unit)) ) {
+		fprintf(stderr,"Bad unit number -- (not enought driver slots?)\n");
+		return 0;
+	}
+	sc->NET_SOFTC_BHANDLE_FIELD = base_addr;
+	if ( 0 == METHODSPTR->n_probe(&THEDEVS[unit-1]) ) {
+		sc->irq_no					= irq_no;
+		printf(NETDRIVER": Unit %i set up\n", unit);
+		return unit;
+	}
+	return 0;
+}
+*/
+
+#endif
Index: bsps/powerpc/beatnik/net/porting/pcireg.h
===================================================================
--- bsps/powerpc/beatnik/net/porting/pcireg.h	(revision 031df3914990db0336a0d386fb53558b05de467e)
+++ bsps/powerpc/beatnik/net/porting/pcireg.h	(revision 031df3914990db0336a0d386fb53558b05de467e)
@@ -0,0 +1,405 @@
+/*-
+ * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
+ * 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 unmodified, 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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: /repoman/r/ncvs/src/sys/dev/pci/pcireg.h,v 1.39.4.3 2005/04/02 05:03:34 jmg Exp $
+ *
+ */
+
+/*
+ * PCIM_xxx: mask to locate subfield in register
+ * PCIR_xxx: config register offset
+ * PCIC_xxx: device class
+ * PCIS_xxx: device subclass
+ * PCIP_xxx: device programming interface
+ * PCIV_xxx: PCI vendor ID (only required to fixup ancient devices)
+ * PCID_xxx: device ID
+ * PCIY_xxx: capability identification number
+ */
+
+/* some PCI bus constants */
+
+#define PCI_BUSMAX	255
+#define PCI_SLOTMAX	31
+#define PCI_FUNCMAX	7
+#define PCI_REGMAX	255
+#define PCI_MAXHDRTYPE	2
+
+/* PCI config header registers for all devices */
+
+#define PCIR_DEVVENDOR	0x00
+#define PCIR_VENDOR	0x00
+#define PCIR_DEVICE	0x02
+#define PCIR_COMMAND	0x04
+#define PCIM_CMD_PORTEN		0x0001
+#define PCIM_CMD_MEMEN		0x0002
+#define PCIM_CMD_BUSMASTEREN	0x0004
+#define PCIM_CMD_SPECIALEN	0x0008
+#define PCIM_CMD_MWRICEN	0x0010
+#define PCIM_CMD_PERRESPEN	0x0040
+#define PCIM_CMD_SERRESPEN	0x0100
+#define PCIM_CMD_BACKTOBACK	0x0200
+#define PCIR_STATUS	0x06
+#define PCIM_STATUS_CAPPRESENT	0x0010
+#define PCIM_STATUS_66CAPABLE	0x0020
+#define PCIM_STATUS_BACKTOBACK	0x0080
+#define PCIM_STATUS_PERRREPORT	0x0100
+#define PCIM_STATUS_SEL_FAST	0x0000
+#define PCIM_STATUS_SEL_MEDIMUM	0x0200
+#define PCIM_STATUS_SEL_SLOW	0x0400
+#define PCIM_STATUS_SEL_MASK	0x0600
+#define PCIM_STATUS_STABORT	0x0800
+#define PCIM_STATUS_RTABORT	0x1000
+#define PCIM_STATUS_RMABORT	0x2000
+#define PCIM_STATUS_SERR	0x4000
+#define PCIM_STATUS_PERR	0x8000
+#define PCIR_REVID	0x08
+#define PCIR_PROGIF	0x09
+#define PCIR_SUBCLASS	0x0a
+#define PCIR_CLASS	0x0b
+#define PCIR_CACHELNSZ	0x0c
+#define PCIR_LATTIMER	0x0d
+#define PCIR_HDRTYPE	0x0e
+#ifndef BURN_BRIDGES
+#define	PCIR_HEADERTYPE	PCIR_HDRTYPE
+#endif
+#define PCIM_HDRTYPE		0x7f
+#define PCIM_HDRTYPE_NORMAL	0x00
+#define PCIM_HDRTYPE_BRIDGE	0x01
+#define PCIM_HDRTYPE_CARDBUS	0x02
+#define PCIM_MFDEV		0x80
+#define PCIR_BIST	0x0f
+
+/* Capability Identification Numbers */
+
+#define PCIY_PMG	0x01	/* PCI Power Management */
+#define PCIY_AGP	0x02	/* AGP */
+#define PCIY_VPD	0x03	/* Vital Product Data */
+#define PCIY_SLOTID	0x04	/* Slot Identification */
+#define PCIY_MSI	0x05	/* Message Signaled Interrupts */
+#define PCIY_CHSWP	0x06	/* CompactPCI Hot Swap */
+#define PCIY_PCIX	0x07	/* PCI-X */
+#define PCIY_HT		0x08	/* HyperTransport */
+#define PCIY_VENDOR	0x09	/* Vendor Unique */
+#define PCIY_DEBUG	0x0a	/* Debug port */
+#define PCIY_CRES	0x0b	/* CompactPCI central resource control */
+#define PCIY_HOTPLUG	0x0c	/* PCI Hot-Plug */
+#define PCIY_AGP8X	0x0e	/* AGP 8x */
+#define PCIY_SECDEV	0x0f	/* Secure Device */
+#define PCIY_EXPRESS	0x10	/* PCI Express */
+#define PCIY_MSIX	0x11	/* MSI-X */
+
+/* config registers for header type 0 devices */
+
+#define PCIR_BARS	0x10
+#define	PCIR_BAR(x)	(PCIR_BARS + (x) * 4)
+#ifndef BURN_BRIDGES
+#define	PCIR_MAPS	PCIR_BARS
+#endif
+#define PCIR_CARDBUSCIS	0x28
+#define PCIR_SUBVEND_0	0x2c
+#define PCIR_SUBDEV_0	0x2e
+#define PCIR_BIOS	0x30
+#define PCIM_BIOS_ENABLE	0x01
+#define	PCIR_CAP_PTR	0x34
+#define PCIR_INTLINE	0x3c
+#define PCIR_INTPIN	0x3d
+#define PCIR_MINGNT	0x3e
+#define PCIR_MAXLAT	0x3f
+
+/* config registers for header type 1 (PCI-to-PCI bridge) devices */
+
+#define PCIR_SECSTAT_1	0x1e
+
+#define PCIR_PRIBUS_1	0x18
+#define PCIR_SECBUS_1	0x19
+#define PCIR_SUBBUS_1	0x1a
+#define PCIR_SECLAT_1	0x1b
+
+#define PCIR_IOBASEL_1	0x1c
+#define PCIR_IOLIMITL_1	0x1d
+#define PCIR_IOBASEH_1	0x30
+#define PCIR_IOLIMITH_1	0x32
+#define PCIM_BRIO_16		0x0
+#define PCIM_BRIO_32		0x1
+#define PCIM_BRIO_MASK		0xf
+
+#define PCIR_MEMBASE_1	0x20
+#define PCIR_MEMLIMIT_1	0x22
+
+#define PCIR_PMBASEL_1	0x24
+#define PCIR_PMLIMITL_1	0x26
+#define PCIR_PMBASEH_1	0x28
+#define PCIR_PMLIMITH_1	0x2c
+
+#define PCIR_BRIDGECTL_1 0x3e
+
+#define PCIR_SUBVEND_1	0x34
+#define PCIR_SUBDEV_1	0x36
+
+/* config registers for header type 2 (CardBus) devices */
+
+#define PCIR_SECSTAT_2	0x16
+
+#define PCIR_PRIBUS_2	0x18
+#define PCIR_SECBUS_2	0x19
+#define PCIR_SUBBUS_2	0x1a
+#define PCIR_SECLAT_2	0x1b
+
+#define PCIR_MEMBASE0_2	0x1c
+#define PCIR_MEMLIMIT0_2 0x20
+#define PCIR_MEMBASE1_2	0x24
+#define PCIR_MEMLIMIT1_2 0x28
+#define PCIR_IOBASE0_2	0x2c
+#define PCIR_IOLIMIT0_2	0x30
+#define PCIR_IOBASE1_2	0x34
+#define PCIR_IOLIMIT1_2	0x38
+
+#define PCIR_BRIDGECTL_2 0x3e
+
+#define PCIR_SUBVEND_2	0x40
+#define PCIR_SUBDEV_2	0x42
+
+#define PCIR_PCCARDIF_2	0x44
+
+/* PCI device class, subclass and programming interface definitions */
+
+#define PCIC_OLD	0x00
+#define PCIS_OLD_NONVGA		0x00
+#define PCIS_OLD_VGA		0x01
+
+#define PCIC_STORAGE	0x01
+#define PCIS_STORAGE_SCSI	0x00
+#define PCIS_STORAGE_IDE	0x01
+#define PCIP_STORAGE_IDE_MODEPRIM	0x01
+#define PCIP_STORAGE_IDE_PROGINDPRIM	0x02
+#define PCIP_STORAGE_IDE_MODESEC	0x04
+#define PCIP_STORAGE_IDE_PROGINDSEC	0x08
+#define PCIP_STORAGE_IDE_MASTERDEV	0x80
+#define PCIS_STORAGE_FLOPPY	0x02
+#define PCIS_STORAGE_IPI	0x03
+#define PCIS_STORAGE_RAID	0x04
+#define PCIS_STORAGE_OTHER	0x80
+
+#define PCIC_NETWORK	0x02
+#define PCIS_NETWORK_ETHERNET	0x00
+#define PCIS_NETWORK_TOKENRING	0x01
+#define PCIS_NETWORK_FDDI	0x02
+#define PCIS_NETWORK_ATM	0x03
+#define PCIS_NETWORK_ISDN	0x04
+#define PCIS_NETWORK_OTHER	0x80
+
+#define PCIC_DISPLAY	0x03
+#define PCIS_DISPLAY_VGA	0x00
+#define PCIS_DISPLAY_XGA	0x01
+#define PCIS_DISPLAY_3D		0x02
+#define PCIS_DISPLAY_OTHER	0x80
+
+#define PCIC_MULTIMEDIA	0x04
+#define PCIS_MULTIMEDIA_VIDEO	0x00
+#define PCIS_MULTIMEDIA_AUDIO	0x01
+#define PCIS_MULTIMEDIA_TELE	0x02
+#define PCIS_MULTIMEDIA_OTHER	0x80
+
+#define PCIC_MEMORY	0x05
+#define PCIS_MEMORY_RAM		0x00
+#define PCIS_MEMORY_FLASH	0x01
+#define PCIS_MEMORY_OTHER	0x80
+
+#define PCIC_BRIDGE	0x06
+#define PCIS_BRIDGE_HOST	0x00
+#define PCIS_BRIDGE_ISA		0x01
+#define PCIS_BRIDGE_EISA	0x02
+#define PCIS_BRIDGE_MCA		0x03
+#define PCIS_BRIDGE_PCI		0x04
+#define PCIS_BRIDGE_PCMCIA	0x05
+#define PCIS_BRIDGE_NUBUS	0x06
+#define PCIS_BRIDGE_CARDBUS	0x07
+#define PCIS_BRIDGE_RACEWAY	0x08
+#define PCIS_BRIDGE_OTHER	0x80
+
+#define PCIC_SIMPLECOMM	0x07
+#define PCIS_SIMPLECOMM_UART	0x00
+#define PCIP_SIMPLECOMM_UART_16550A	0x02
+#define PCIS_SIMPLECOMM_PAR	0x01
+#define PCIS_SIMPLECOMM_MULSER	0x02
+#define PCIS_SIMPLECOMM_MODEM	0x03
+#define PCIS_SIMPLECOMM_OTHER	0x80
+
+#define PCIC_BASEPERIPH	0x08
+#define PCIS_BASEPERIPH_PIC	0x00
+#define PCIS_BASEPERIPH_DMA	0x01
+#define PCIS_BASEPERIPH_TIMER	0x02
+#define PCIS_BASEPERIPH_RTC	0x03
+#define PCIS_BASEPERIPH_PCIHOT	0x04
+#define PCIS_BASEPERIPH_OTHER	0x80
+
+#define PCIC_INPUTDEV	0x09
+#define PCIS_INPUTDEV_KEYBOARD	0x00
+#define PCIS_INPUTDEV_DIGITIZER	0x01
+#define PCIS_INPUTDEV_MOUSE	0x02
+#define PCIS_INPUTDEV_SCANNER	0x03
+#define PCIS_INPUTDEV_GAMEPORT	0x04
+#define PCIS_INPUTDEV_OTHER	0x80
+
+#define PCIC_DOCKING	0x0a
+#define PCIS_DOCKING_GENERIC	0x00
+#define PCIS_DOCKING_OTHER	0x80
+
+#define PCIC_PROCESSOR	0x0b
+#define PCIS_PROCESSOR_386	0x00
+#define PCIS_PROCESSOR_486	0x01
+#define PCIS_PROCESSOR_PENTIUM	0x02
+#define PCIS_PROCESSOR_ALPHA	0x10
+#define PCIS_PROCESSOR_POWERPC	0x20
+#define PCIS_PROCESSOR_MIPS	0x30
+#define PCIS_PROCESSOR_COPROC	0x40
+
+#define PCIC_SERIALBUS	0x0c
+#define PCIS_SERIALBUS_FW	0x00
+#define PCIS_SERIALBUS_ACCESS	0x01
+#define PCIS_SERIALBUS_SSA	0x02
+#define PCIS_SERIALBUS_USB	0x03
+#define PCIP_SERIALBUS_USB_UHCI	0x00
+#define PCIP_SERIALBUS_USB_OHCI	0x10
+#define PCIP_SERIALBUS_USB_EHCI	0x20
+#define PCIS_SERIALBUS_FC	0x04
+#define PCIS_SERIALBUS_SMBUS	0x05
+
+#define PCIC_WIRELESS	0x0d
+#define PCIS_WIRELESS_IRDA	0x00
+#define PCIS_WIRELESS_IR	0x01
+#define PCIS_WIRELESS_RF	0x10
+#define PCIS_WIRELESS_OTHER	0x80
+
+#define PCIC_INTELLIIO	0x0e
+#define PCIS_INTELLIIO_I2O	0x00
+
+#define PCIC_SATCOM	0x0f
+#define PCIS_SATCOM_TV		0x01
+#define PCIS_SATCOM_AUDIO	0x02
+#define PCIS_SATCOM_VOICE	0x03
+#define PCIS_SATCOM_DATA	0x04
+
+#define PCIC_CRYPTO	0x10
+#define PCIS_CRYPTO_NETCOMP	0x00
+#define PCIS_CRYPTO_ENTERTAIN	0x10
+#define PCIS_CRYPTO_OTHER	0x80
+
+#define PCIC_DASP	0x11
+#define PCIS_DASP_DPIO	0x00
+#define PCIS_DASP_OTHER	0x80
+
+#define PCIC_OTHER	0xff
+
+/* PCI power manangement */
+
+#define PCIR_POWER_CAP		0x2
+#define PCIM_PCAP_SPEC			0x0007
+#define PCIM_PCAP_PMEREQCLK		0x0008
+#define PCIM_PCAP_PMEREQPWR		0x0010
+#define PCIM_PCAP_DEVSPECINIT		0x0020
+#define PCIM_PCAP_DYNCLOCK		0x0040
+#define PCIM_PCAP_SECCLOCK		0x00c0
+#define PCIM_PCAP_CLOCKMASK		0x00c0
+#define PCIM_PCAP_REQFULLCLOCK		0x0100
+#define PCIM_PCAP_D1SUPP		0x0200
+#define PCIM_PCAP_D2SUPP		0x0400
+#define PCIM_PCAP_D0PME			0x1000
+#define PCIM_PCAP_D1PME			0x2000
+#define PCIM_PCAP_D2PME			0x4000
+
+#define PCIR_POWER_STATUS	0x4
+#define PCIM_PSTAT_D0			0x0000
+#define PCIM_PSTAT_D1			0x0001
+#define PCIM_PSTAT_D2			0x0002
+#define PCIM_PSTAT_D3			0x0003
+#define PCIM_PSTAT_DMASK		0x0003
+#define PCIM_PSTAT_REPENABLE		0x0010
+#define PCIM_PSTAT_PMEENABLE		0x0100
+#define PCIM_PSTAT_D0POWER		0x0000
+#define PCIM_PSTAT_D1POWER		0x0200
+#define PCIM_PSTAT_D2POWER		0x0400
+#define PCIM_PSTAT_D3POWER		0x0600
+#define PCIM_PSTAT_D0HEAT		0x0800
+#define PCIM_PSTAT_D1HEAT		0x1000
+#define PCIM_PSTAT_D2HEAT		0x1200
+#define PCIM_PSTAT_D3HEAT		0x1400
+#define PCIM_PSTAT_DATAUNKN		0x0000
+#define PCIM_PSTAT_DATADIV10		0x2000
+#define PCIM_PSTAT_DATADIV100		0x4000
+#define PCIM_PSTAT_DATADIV1000		0x6000
+#define PCIM_PSTAT_DATADIVMASK		0x6000
+#define PCIM_PSTAT_PME			0x8000
+
+#define PCIR_POWER_PMCSR	0x6
+#define PCIM_PMCSR_DCLOCK		0x10
+#define PCIM_PMCSR_B2SUPP		0x20
+#define PCIM_BMCSR_B3SUPP		0x40
+#define PCIM_BMCSR_BPCE			0x80
+
+#define PCIR_POWER_DATA		0x7
+
+/* PCI Message Signalled Interrupts (MSI) */
+#define PCIR_MSI_CTRL		0x2
+#define PCIM_MSICTRL_VECTOR		0x0100
+#define PCIM_MSICTRL_64BIT		0x0080
+#define PCIM_MSICTRL_MME_MASK		0x0070
+#define PCIM_MSICTRL_MME_1		0x0000
+#define PCIM_MSICTRL_MME_2		0x0010
+#define PCIM_MSICTRL_MME_4		0x0020
+#define PCIM_MSICTRL_MME_8		0x0030
+#define PCIM_MSICTRL_MME_16		0x0040
+#define PCIM_MSICTRL_MME_32		0x0050
+#define PCIM_MSICTRL_MMC_MASK		0x000E
+#define PCIM_MSICTRL_MMC_1		0x0000
+#define PCIM_MSICTRL_MMC_2		0x0002
+#define PCIM_MSICTRL_MMC_4		0x0004
+#define PCIM_MSICTRL_MMC_8		0x0006
+#define PCIM_MSICTRL_MMC_16		0x0008
+#define PCIM_MSICTRL_MMC_32		0x000A
+#define PCIM_MSICTRL_MSI_ENABLE		0x0001
+#define PCIR_MSI_ADDR		0x4
+#define PCIR_MSI_ADDR_HIGH	0x8
+#define PCIR_MSI_DATA		0x8
+#define PCIR_MSI_DATA_64BIT	0xc
+#define PCIR_MSI_MASK		0x10
+#define PCIR_MSI_PENDING	0x14
+
+/* PCI-X definitions */
+#define PCIXR_COMMAND	0x96
+#define PCIXR_DEVADDR	0x98
+#define PCIXM_DEVADDR_FNUM	0x0003	/* Function Number */
+#define PCIXM_DEVADDR_DNUM	0x00F8	/* Device Number */
+#define PCIXM_DEVADDR_BNUM	0xFF00	/* Bus Number */
+#define PCIXR_STATUS	0x9A
+#define PCIXM_STATUS_64BIT	0x0001	/* Active 64bit connection to device. */
+#define PCIXM_STATUS_133CAP	0x0002	/* Device is 133MHz capable */
+#define PCIXM_STATUS_SCDISC	0x0004	/* Split Completion Discarded */
+#define PCIXM_STATUS_UNEXPSC	0x0008	/* Unexpected Split Completion */
+#define PCIXM_STATUS_CMPLEXDEV	0x0010	/* Device Complexity (set == bridge) */
+#define PCIXM_STATUS_MAXMRDBC	0x0060	/* Maximum Burst Read Count */
+#define PCIXM_STATUS_MAXSPLITS	0x0380	/* Maximum Split Transactions */
+#define PCIXM_STATUS_MAXCRDS	0x1C00	/* Maximum Cumulative Read Size */
+#define PCIXM_STATUS_RCVDSCEM	0x2000	/* Received a Split Comp w/Error msg */
Index: bsps/powerpc/beatnik/net/porting/rtemscompat.h
===================================================================
--- bsps/powerpc/beatnik/net/porting/rtemscompat.h	(revision 031df3914990db0336a0d386fb53558b05de467e)
+++ bsps/powerpc/beatnik/net/porting/rtemscompat.h	(revision 031df3914990db0336a0d386fb53558b05de467e)
@@ -0,0 +1,456 @@
+#ifndef RTEMS_COMPAT_BSD_NET_H
+#define RTEMS_COMPAT_BSD_NET_H
+
+/* BSD -> rtems wrappers; stuff that must be defined
+ *        prior to including most BSD headers
+ */
+
+/* Copyright: Till Straumann <strauman@slac.stanford.edu>, 2005;
+ * License:   see LICENSE file.
+ */
+
+#include <rtems.h>
+#include <sys/errno.h>
+#include <sys/types.h>
+
+#include <stdlib.h>
+
+/* Check for RTEMS version; true if >= ma.mi.re */
+#define ISMINVERSION(ma,mi,re) \
+	(    __RTEMS_MAJOR__  > (ma)	\
+	 || (__RTEMS_MAJOR__ == (ma) && __RTEMS_MINOR__  > (mi))	\
+	 || (__RTEMS_MAJOR__ == (ma) && __RTEMS_MINOR__ == (mi) && __RTEMS_REVISION__ >= (re)) \
+    )
+
+/* 'align' ARG is evaluated more than once */
+#define _DO_ALIGN(addr, align) (((uint32_t)(addr) + (align) - 1) & ~((align)-1))
+
+
+/* malloc/free are redefined :-( */
+static inline void *the_real_malloc(size_t n)
+{
+	return malloc(n);
+}
+
+static inline void  the_real_free(void *p)
+{
+	return free(p);
+}
+
+#define __INSIDE_RTEMS_BSD_TCPIP_STACK__
+#include <rtems/rtems_bsdnet.h>
+#include <rtems/rtems_bsdnet_internal.h>
+#ifdef __i386__
+#include <libcpu/cpu.h>
+#elif defined(__PPC__)
+#include <libcpu/io.h>
+#else
+#error "dunno what IO ops to use on this architecture"
+#endif
+#include <rtems/bspIo.h>
+
+#define NET_EMB(x,y,z) x ## y ## z
+#define NET_EMBEMB(x,y,z) NET_EMB(x,y,z)
+
+#define NET_STR(arg)	#arg
+#define NET_STRSTR(arg)	NET_STR(arg)
+
+#define NET_SOFTC 	NET_EMBEMB(,NETDRIVER_PREFIX,_softc)
+
+#define METHODS     NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_methods)
+extern struct _net_drv_tbl METHODS;
+
+#ifdef DEBUG_MODULAR
+#define METHODSPTR  NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_methods_p)
+extern struct _net_drv_tbl *volatile METHODSPTR;
+#else
+#define METHODSPTR  (&METHODS)
+#endif
+
+#if defined(__LITTLE_ENDIAN__) || (__i386__)
+static inline uint16_t  htole16(uint16_t  v) { return v; }
+static inline uint32_t  htole32(uint32_t  v) { return v; }
+static inline uint64_t  htole64(uint64_t  v) { return v; }
+static inline uint16_t  le16toh(uint16_t  v) { return v; }
+static inline uint32_t  le32toh(uint32_t  v) { return v; }
+static inline uint64_t  le64toh(uint64_t  v) { return v; }
+#elif defined(__BIG_ENDIAN__)
+#ifdef __PPC__
+#include <libcpu/byteorder.h>
+
+/* Different RTEMS versions use different types
+ * for 32-bit (unsigned vs. unsigned long which
+ * always cause gcc warnings and possible alias
+ * violations, sigh).
+ */
+
+#if ISMINVERSION(4,8,0)
+typedef uint32_t rtemscompat_32_t;
+#else
+typedef unsigned rtemscompat_32_t;
+#endif
+
+static inline uint16_t
+htole16(uint16_t v)
+{
+uint16_t rval;
+	st_le16(&rval,v);
+	return rval;
+}
+
+static inline uint16_t
+le16toh(uint16_t v)
+{
+	return ld_le16((unsigned short*)&v);
+}
+
+static inline uint32_t
+htole32(uint32_t v)
+{
+rtemscompat_32_t rval;
+	st_le32(&rval,v);
+	return rval;
+}
+
+static inline uint32_t
+le32toh(uint32_t v)
+{
+rtemscompat_32_t vv = v;
+	return ld_le32(&vv);
+}
+
+/* Compiler generated floating point instructions for this
+ * and rtems_bsdnet_newproc()-generated tasks are non-FP
+ * :-(
+ */
+static inline uint64_t
+htole64(uint64_t  v) 
+{
+union {
+	rtemscompat_32_t tmp[2];
+	uint64_t          rval;
+} u;
+
+	st_le32( &u.tmp[0], (unsigned)(v&0xffffffff) );
+	st_le32( &u.tmp[1], (unsigned)((v>>32)&0xffffffff) );
+
+	return u.rval;
+}
+
+#else
+#error "need htoleXX() implementation for this CPU arch"
+#endif
+
+#else
+#error "Unknown CPU endianness"
+#endif
+
+
+
+#ifdef __PPC__
+#define _out_byte(a,v) out_8((volatile uint8_t*)(a),(v))
+#define _inp_byte(a)   in_8((volatile uint8_t*)(a))
+#ifdef NET_CHIP_LE
+#define _out_word(a,v) out_le16((volatile uint16_t*)(a),(v))
+#define _out_long(a,v) out_le32((volatile uint32_t *)(a),(v))
+#define _inp_word(a)   in_le16((volatile uint16_t*)(a))
+#define _inp_long(a)   in_le32((volatile uint32_t *)(a))
+#elif defined(NET_CHIP_BE)
+#define _out_word(a,v) out_be16((volatile uint16_t*)(a),(v))
+#define _out_long(a,v) out_be32((volatile uint32_t *)(a),(v))
+#define _inp_word(a)   in_be16((volatile uint16_t*)(a))
+#define _inp_long(a)   in_be32((volatile uint32_t *)(a))
+#else
+#error rtemscompat_defs.h must define either NET_CHIP_LE or NET_CHIP_BE
+#endif
+static inline void wrle32(unsigned *a, unsigned v)
+{
+	asm volatile("stwbrx %1,0,%2":"=m"(*a):"r"(v),"r"(a));
+}
+static inline unsigned rdle32(unsigned *a)
+{
+	asm volatile("lwbrx %0,0,%0":"=r"(a):"0"(a),"m"(*a));
+	return (unsigned)a;
+}
+static inline void orle32(unsigned *a,unsigned v) { wrle32(a, rdle32(a) | v); }
+static inline void anle32(unsigned *a,unsigned v) { wrle32(a, rdle32(a) & v); }
+
+static inline void wrle16(unsigned short *a, unsigned short v)
+{
+	asm volatile("sthbrx %1,0,%2":"=m"(*a):"r"(v),"r"(a));
+}
+static inline unsigned short rdle16(unsigned short *a)
+{
+	asm volatile("lhbrx %0,0,%0":"=r"(a):"0"(a),"m"(*a));
+	return (unsigned short)(unsigned)a;
+}
+static inline void orle16(unsigned short *a,unsigned short v) { wrle16(a, rdle16(a) | v); }
+static inline void anle16(unsigned short *a,unsigned short v) { wrle16(a, rdle16(a) & v); }
+#endif
+
+#ifdef __i386__
+#ifdef NET_CHIP_BE
+#error dunno how to output BE data
+#endif
+
+static inline void wrle32(volatile unsigned *p, unsigned v) { *p  = v; }
+static inline void orle32(volatile unsigned *p, unsigned v) { *p |= v; }
+static inline void anle32(volatile unsigned *p, unsigned v) { *p &= v; }
+static inline unsigned rdle32(volatile unsigned *p) { return *p; }
+
+static inline void wrle16(volatile unsigned short *p, unsigned short v) { *p  = v; }
+static inline void orle16(volatile unsigned short *p, unsigned short v) { *p |= v; }
+static inline void anle16(volatile unsigned short *p, unsigned short v) { *p &= v; }
+static inline unsigned short rdle16(volatile unsigned short *p) { return *p; }
+
+#ifdef NET_CHIP_MEM_IO
+
+#ifdef __i386__
+static inline void           _out_byte(unsigned a, unsigned char v)  {        *(volatile unsigned char*)a = v; }
+static inline unsigned char  _inp_byte(unsigned a)                   { return *(volatile unsigned char*)a;     }
+#ifdef NET_CHIP_LE
+static inline void           _out_word(unsigned a, unsigned short v) {        *(volatile unsigned short*)a = v; }
+static inline unsigned short _inp_word(unsigned a)                   { return *(volatile unsigned short*)a;     }
+static inline void           _out_long(unsigned a, unsigned v)       {        *(volatile unsigned      *)a = v; }
+static inline unsigned       _inp_long(unsigned a)                   { return *(volatile unsigned      *)a; }
+#elif defined(NET_CHIP_BE)
+#error "BE memory IO not implemented for i386 yet"
+#else
+#error rtemscompat_defs.h must define either NET_CHIP_LE or NET_CHIP_BE
+#endif
+#else
+
+#error "Memory IO not implemented for this CPU architecture yet"
+
+#endif
+#elif defined(NET_CHIP_PORT_IO)
+#define _out_byte(addr,val) outport_byte((addr),(val))
+#define _out_word(addr,val) outport_word((addr),(val))
+#define _out_long(addr,val) outport_long((addr),(val))
+
+static inline u_int8_t _inp_byte(volatile unsigned char *a)
+{
+register u_int8_t rval;
+	inport_byte((unsigned short)(unsigned)a,rval);
+	return rval;
+}
+static inline u_int16_t _inp_word(volatile unsigned short *a)
+{
+register u_int16_t rval;
+	inport_word((unsigned short)(unsigned)a,rval);
+	return rval;
+}
+static inline u_int32_t _inp_long(volatile unsigned *a)
+{
+register u_int32_t rval;
+	inport_long((unsigned short)(unsigned)a,rval);
+	return rval;
+}
+#else
+#error either NET_CHIP_MEM_IO or NET_CHIP_PORT_IO must be defined
+#endif
+#endif
+
+#ifndef __FBSDID
+#define __FBSDID(arg)
+#endif
+
+#define _KERNEL
+
+#define device_printf(device,format,args...) printk(format,## args)
+
+static inline u_int8_t bus_space_do_read_1(u_long handle, unsigned reg)
+{
+	return _inp_byte((volatile unsigned char*)((handle)+(reg)));
+}
+
+static inline u_int16_t bus_space_do_read_2(u_long handle, unsigned reg)
+{
+	return _inp_word((volatile unsigned short*)((handle)+(reg)));
+}
+
+static inline u_int32_t bus_space_do_read_4(u_long handle, unsigned reg)
+{
+	return _inp_long((volatile unsigned *)((handle)+(reg)));
+}
+
+#define bus_space_read_1(tag,handle,reg) bus_space_do_read_1((handle),(reg))
+#define bus_space_read_2(tag,handle,reg) bus_space_do_read_2((handle),(reg))
+#define bus_space_read_4(tag,handle,reg) bus_space_do_read_4((handle),(reg))
+
+static inline void bus_space_do_write_multi_1(u_long handle, unsigned reg, unsigned char *addr, int cnt)
+{
+	int i; for (i=0; i<cnt; i++) _out_byte( (handle) + (reg), (addr)[i]);
+}
+
+static inline void bus_space_do_write_multi_2(u_long handle, unsigned reg, unsigned short *addr, int cnt)
+{
+	int i; for (i=0; i<cnt; i++) _out_word( (handle) + (reg), (addr)[i]);
+}
+
+static inline void bus_space_do_write_multi_4(u_long handle, unsigned reg, unsigned long *addr, int cnt)
+{
+	int i; for (i=0; i<cnt; i++) _out_long( (handle) + (reg), (addr)[i]);
+}
+
+
+#define bus_space_write_multi_1(tag, handle, reg, addr, cnt) \
+		bus_space_do_write_multi_1(handle, reg, addr, cnt)
+#define bus_space_write_multi_2(tag, handle, reg, addr, cnt) \
+		bus_space_do_write_multi_2(handle, reg, addr, cnt)
+#define bus_space_write_multi_4(tag, handle, reg, addr, cnt) \
+		bus_space_do_write_multi_4(handle, reg, addr, cnt)
+
+static inline void bus_space_do_read_multi_1(u_long handle, unsigned reg, unsigned char *addr, int cnt)
+{
+	int i; for (i=0; i<cnt; i++)
+				(addr)[i] = _inp_byte((volatile unsigned char*)((handle)+(reg)));
+}
+
+static inline void bus_space_do_read_multi_2(u_long handle, unsigned reg, unsigned short *addr, int cnt)
+{
+	int i; for (i=0; i<cnt; i++)
+				(addr)[i] = _inp_word((volatile unsigned short*)((handle)+(reg)));
+}
+
+static inline void bus_space_do_read_multi_4(u_long handle, unsigned reg, unsigned long *addr, int cnt)
+{
+	int i; for (i=0; i<cnt; i++)
+				(addr)[i] = _inp_long((volatile unsigned *)((handle)+(reg)));
+}
+
+#define bus_space_read_multi_1(tag, handle, reg, addr, cnt) \
+		bus_space_do_read_multi_1(handle, reg, addr, cnt)
+#define bus_space_read_multi_2(tag, handle, reg, addr, cnt) \
+		bus_space_do_read_multi_2(handle, reg, addr, cnt)
+#define bus_space_read_multi_4(tag, handle, reg, addr, cnt) \
+		bus_space_do_read_multi_4(handle, reg, addr, cnt)
+
+
+
+#define bus_space_write_1(tag, handle, reg, val) \
+	do { _out_byte( (handle) + (reg), (val)); } while (0)
+
+#define bus_space_write_2(tag, handle, reg, val) \
+	do { _out_word( (handle) + (reg), (val)); } while (0)
+
+#define bus_space_write_4(tag, handle, reg, val) \
+	do { _out_long( (handle) + (reg), (val)); } while (0)
+
+#define BPF_MTAP(a,b)	do { } while (0)
+
+extern unsigned net_driver_ticks_per_sec;
+
+#ifdef __PPC__
+/* PPC has a timebase - based delay */
+#define DELAY(n) do {		\
+	if ( (n) > 10000 )		\
+		rtems_task_wake_after((((n)*net_driver_ticks_per_sec)/1000000) + 1);	\
+	else					\
+		rtems_bsp_delay(n);	\
+	} while (0)
+#else
+#warning "Have no good usec delay implementation"
+#define DELAY(n) do {		\
+		rtems_task_wake_after((((n)*net_driver_ticks_per_sec)/1000000) + 1);	\
+	} while (0)
+#endif
+
+
+#define IRQ_LOCKED(code) \
+	do { unsigned long _xtre_irq_flags; \
+		rtems_interrupt_disable(_xtre_irq_flags); \
+			do { code } while(0); 	\
+		rtems_interrupt_enable(_xtre_irq_flags); \
+	} while (0)
+
+typedef void (driver_intr_t)(void *);
+
+#define if_xname if_name
+
+/* need to replace those with LOCAL2PCI() and make sure the bus handle is initialized
+ * (on most BSPs we get away with PCI_DRAM_OFFSET [no bus handle needed at all]
+ */
+#ifndef PCI_DRAM_OFFSET
+#define PCI_DRAM_OFFSET 0
+#endif
+
+#ifndef PCI_MEM_BASE
+#define PCI_MEM_BASE    0
+#endif
+
+#define kvtop(a)			((unsigned long)(a) + PCI_DRAM_OFFSET)
+#define vtophys(a)			((unsigned long)(a) + PCI_DRAM_OFFSET)
+
+#define PCI2LOCAL(a,bus)	((unsigned long)(a) + PCI_MEM_BASE)
+
+#ifdef PCI0_IO_BASE /* special mvme5500 hack :-( */
+#define PCI_IO_2LOCAL(a,bus) ((unsigned long)(a) + PCI0_IO_BASE)
+#elif defined(PCI_IO_BASE)
+#define PCI_IO_2LOCAL(a,bus) ((unsigned long)(a) + PCI_IO_BASE)
+#elif defined(_IO_BASE)
+#define PCI_IO_2LOCAL(a,bus) ((unsigned long)(a) + _IO_BASE)
+#else
+#warning "Unable to determine base address of PCI IO space; using ZERO"
+#define PCI_IO_2LOCAL(a,bus) ((unsigned long)(a))
+#endif
+
+#define if_printf(if,fmt,args...)  printf("%s:"fmt,(if)->if_name,args)
+
+#ifndef BUS_PROBE_DEFAULT
+#define BUS_PROBE_DEFAULT 0
+#endif
+
+static inline void *
+contigmalloc(
+	unsigned long size,
+	int type,
+	int flags,
+	unsigned long lo,
+	unsigned long hi,
+	unsigned long align,
+	unsigned long bound)
+{
+void *ptr  = rtems_bsdnet_malloc(size + sizeof(ptr) + align-1, type, flags);
+char *rval = 0;
+	if ( ptr ) {
+		unsigned tmp = (unsigned)ptr + align - 1;
+		tmp -= tmp % align;
+		rval = (char*)tmp;
+		/* save backlink */
+		*(void**)(rval+size) =  ptr;
+	}
+	return rval;
+}
+
+static inline void
+contigfree(void *ptr, size_t size, int type)
+{
+	rtems_bsdnet_free( *(void**)((unsigned)ptr + size), type);
+}
+
+/* callout stuff */
+#define callout_init(args...) do {} while (0);
+#define callout_reset(args...) do {} while (0);
+#define callout_stop(args...) do {} while (0);
+
+#define IFQ_DRV_IS_EMPTY(q) (0 == (q)->ifq_head)
+#define IFQ_DRV_DEQUEUE(q,m) IF_DEQUEUE((q),(m))
+#define IFQ_DRV_PREPEND(q,m) IF_PREPEND((q),(m))
+
+#define DO_ETHER_INPUT_SKIPPING_ETHER_HEADER(ifp,m)				\
+		{	struct ether_header *eh;							\
+			eh				  = mtod(m, struct ether_header*);	\
+       		m->m_data        += sizeof(struct ether_header);	\
+        	m->m_len         -= sizeof(struct ether_header);	\
+        	m->m_pkthdr.len  -= sizeof(struct ether_header);	\
+			m->m_pkthdr.rcvif = ifp;							\
+    		ether_input(ifp, eh, m);							\
+		} while (0)
+
+
+#ifndef __KERNEL_RCSID
+#define __KERNEL_RCSID(arg...) 
+#endif
+
+#endif
Index: bsps/powerpc/beatnik/net/porting/rtemscompat1.h
===================================================================
--- bsps/powerpc/beatnik/net/porting/rtemscompat1.h	(revision 031df3914990db0336a0d386fb53558b05de467e)
+++ bsps/powerpc/beatnik/net/porting/rtemscompat1.h	(revision 031df3914990db0336a0d386fb53558b05de467e)
@@ -0,0 +1,219 @@
+#ifndef RTEMS_COMPAT1_BSD_NET_H
+#define RTEMS_COMPAT1_BSD_NET_H
+
+/* BSD -> RTEMS conversion wrappers; stuff that must be defined
+ *        after most BSD headers are included.
+ */
+
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+/* Copyright: Till Straumann <strauman@slac.stanford.edu>, 2005;
+ * License:   see LICENSE file.
+ */
+
+typedef struct device {
+	struct NET_SOFTC d_softc;	/* MUST BE FIRST FIELD */
+	char			 *d_name;
+	char			 *d_desc;
+	int              d_unit;
+	int				 flags;
+	/* pointer to ifconfig only valid during excution of
+	 * the n_attach/n_detach methods (see below)
+	 */
+	struct rtems_bsdnet_ifconfig *d_ifconfig;
+} netdev_t;
+
+#define THEDEVS	NET_EMBEMB(the_,NETDRIVER_PREFIX,_devs)
+#define NETDEV_DECL netdev_t THEDEVS[NETDRIVER_SLOTS]
+
+extern NETDEV_DECL;
+
+typedef struct _net_drv_tbl {
+	int (*n_probe)(device_t);
+	int (*n_attach)(device_t);
+	int (*n_detach)(device_t);
+	void (*n_intr)(void *);
+} net_drv_tbl_t;
+
+static inline netdev_t *
+net_dev_get(struct rtems_bsdnet_ifconfig *config)
+{
+	int     unitNo;
+	char *unitName;
+
+	unitNo = rtems_bsdnet_parse_driver_name(config, &unitName);
+	if ( unitNo < 0 )
+		return 0;
+
+	if ( unitNo <=0 || unitNo > NETDRIVER_SLOTS ) {
+		device_printf(dev, "Bad "NETDRIVER" unit number.\n");
+		return 0;
+	}
+
+	if ( THEDEVS[unitNo-1].d_unit && THEDEVS[unitNo-1].d_unit != unitNo ) {
+		device_printf(dev, "Unit # mismatch !!??\n");
+		return 0;
+	}
+
+	THEDEVS[unitNo-1].d_unit = unitNo;
+	THEDEVS[unitNo-1].d_name = unitName;
+	THEDEVS[unitNo-1].d_ifconfig = config;
+	
+	return &THEDEVS[unitNo - 1];
+}
+
+/* kludge; that's why softc needs to be first */
+static inline netdev_t *
+softc_get_device(struct NET_SOFTC *sc)
+{
+	return (netdev_t *)sc;
+}
+
+static inline struct NET_SOFTC *
+device_get_softc(netdev_t *dev)
+{ return &dev->d_softc; }
+
+static inline int
+device_get_unit(netdev_t *dev)
+{ return dev->d_unit; }
+
+static inline char *
+device_get_name(netdev_t *dev)
+{ return dev->d_name; }
+
+static inline void
+if_initname(struct ifnet *ifp, char *name, int unit)
+{
+	ifp->if_name = name;
+	ifp->if_unit = unit;
+}
+
+static inline void
+device_set_desc(netdev_t *dev, char *str)
+{
+	dev->d_desc = str;
+}
+
+static inline void
+device_set_desc_copy(netdev_t *dev, char *str)
+{
+	dev->d_desc = strdup(str);
+}
+
+
+static inline int
+device_is_attached(netdev_t *dev)
+{
+	return dev->d_softc.arpcom.ac_if.if_addrlist && dev->d_softc.arpcom.ac_if.if_init;
+}
+
+#ifdef NETDRIVER_PCI
+#include NETDRIVER_PCI
+#include "pcireg.h"
+
+static inline unsigned
+pci_read_config(device_t dev, unsigned addr, unsigned width)
+{
+rtemscompat_32_t d;
+unsigned short   s;
+unsigned char    b;
+struct NET_SOFTC *sc = device_get_softc(dev);
+	switch (width) {
+		case 1:	pci_read_config_byte(sc->b, sc->d, sc->f, addr, &b);
+				return b;
+		case 2:	pci_read_config_word(sc->b, sc->d, sc->f, addr, &s);
+				return s;
+		case 4:	pci_read_config_dword(sc->b, sc->d, sc->f, addr, &d);
+				return d;
+		default:
+				break;
+	}
+	return 0xdeadbeef;
+}
+
+static inline void
+pci_write_config(device_t dev, unsigned addr, unsigned width, unsigned val)
+{
+struct NET_SOFTC *sc = device_get_softc(dev);
+	switch (width) {
+		case 1:	pci_write_config_byte(sc->b, sc->d, sc->f, addr, val);
+				return ;
+		case 2:	pci_write_config_word(sc->b, sc->d, sc->f, addr, val);
+				return ;
+		case 4:	pci_write_config_dword(sc->b, sc->d, sc->f, addr, val);
+				return ;
+		default:
+				break;
+	}
+}
+
+
+static inline unsigned short
+pci_get_vendor(device_t dev)
+{
+	return pci_read_config(dev, PCIR_VENDOR, 2);
+}
+
+static inline unsigned short
+pci_get_device(device_t dev)
+{
+	return pci_read_config(dev, PCIR_DEVICE, 2);
+}
+
+static inline unsigned short
+pci_get_subvendor(device_t dev)
+{
+	return pci_read_config(dev, PCIR_SUBVEND_0, 2);
+}
+
+static inline unsigned short
+pci_get_subdevice(device_t dev)
+{
+	return pci_read_config(dev, PCIR_SUBDEV_0, 2);
+}
+
+
+static inline void
+pci_enable_busmaster(device_t dev)
+{
+	pci_write_config(
+		dev,
+		PCIR_COMMAND,
+		2,
+		pci_read_config(dev, PCIR_COMMAND, 2)
+		| PCIM_CMD_BUSMASTEREN);
+}
+
+#define mtx_init(a,b,c,d) 	do {} while(0)
+#define mtx_initialized(ma) (1)
+#define mtx_destroy(ma)   	do {} while(0)
+#define mtx_lock(a) 		do {} while(0)
+#define mtx_unlock(a) 		do {} while(0)
+#define mtx_assert(a,b)		do {} while(0)
+
+#define callout_handle_init(x) do {} while (0)
+#define untimeout(a...) do {} while (0)
+
+#if !ISMINVERSION(4,6,99)
+#define pci_bus_count BusCountPCI
+#endif
+
+#endif
+
+/* Ugly hack to allow unloading/reloading the driver core.
+ * Needed because rtems' bsdnet release doesn't implement
+ * if_detach(). Therefore, we bring the interface down but
+ * keep the device record alive...
+ */
+static inline void
+__ether_ifdetach(struct ifnet *ifp)
+{
+		ifp->if_flags = 0;
+		ifp->if_ioctl = 0;
+		ifp->if_start = 0;
+		ifp->if_watchdog = 0;
+		ifp->if_init  = 0;
+}
+
+#endif
Index: bsps/powerpc/beatnik/net/porting/rtemscompat_defs.h.template
===================================================================
--- bsps/powerpc/beatnik/net/porting/rtemscompat_defs.h.template	(revision 031df3914990db0336a0d386fb53558b05de467e)
+++ bsps/powerpc/beatnik/net/porting/rtemscompat_defs.h.template	(revision 031df3914990db0336a0d386fb53558b05de467e)
@@ -0,0 +1,97 @@
+#ifndef RTEMS_COMPAT_DEFS_H
+#define RTEMS_COMPAT_DEFS_H
+
+/* Symbol definitions for a particular driver */
+
+/* Copyright: Till Straumann <strauman@slac.stanford.edu>, 2005;
+ * License:   see LICENSE file.
+ */
+
+/* Number of device instances the driver should support
+ * - may be limited to 1 depending on IRQ API
+ * (braindamaged PC586 and powerpc)
+ */
+#define NETDRIVER_SLOTS 1
+/* String name to print with error messages */
+#define NETDRIVER       "PCN"
+/* Name snippet used to make global symbols unique to this driver */
+#define NETDRIVER_PREFIX pcn
+
+/* Define according to endianness of the *ethernet*chip*
+ * (not the CPU - most probably are LE)
+ * This must be either NET_CHIP_LE or NET_CHIP_BE
+ */
+
+#define NET_CHIP_LE
+#undef  NET_CHIP_BE
+
+/* Define either NET_CHIP_MEM_IO or NET_CHIP_PORT_IO,
+ * depending whether the CPU sees it in memory address space
+ * or (e.g. x86) uses special I/O instructions.
+ */
+#define NET_CHIP_MEM_IO
+#undef  NET_CHIP_PORT_IO
+
+/* The name of the hijacked 'bus handle' field in the softc
+ * structure. We use this field to store the chip's base address.
+ */
+#define NET_SOFTC_BHANDLE_FIELD pcn_bhandle
+
+/* define the names of the 'if_XXXreg.h' and 'if_XXXvar.h' headers
+ * (only if present, i.e., if the BSDNET driver has no respective
+ * header, leave this undefined).
+ *
+ */
+#undef  IF_REG_HEADER <if_XXXreg.h>
+#undef  IF_VAR_HEADER <if_XXXvar.h>
+
+/* define if a pci device */
+#define NETDRIVER_PCI <bsp/pci.h>
+
+/* Macros to disable and enable interrupts, respectively.
+ * The 'disable' macro is expanded in the ISR, the 'enable'
+ * macro is expanded in the driver task.
+ * The global network semaphore usually provides mutex
+ * protection of the device registers.
+ * Special care must be taken when coding the 'disable' macro,
+ * however to MAKE SURE THERE ARE NO OTHER SIDE EFFECTS such
+ * as:
+ *    - macro must not clear any status flags
+ *    - macro must save/restore any context information
+ *      (e.g., a address register pointer or a bank switch register)
+ *
+ * ARGUMENT: the macro arg is a pointer to the driver's 'softc' structure
+ */
+
+/* Here EXAMPLES for the pcnet chip which addresses registers indirectly
+ * through a 'address-pointer' (RAP) and 'data-port' (RDP) register pair:
+#define NET_DISABLE_IRQS(sc)		do { \
+		unsigned rap = CSR_READ_4((sc),PCN_IO32_RAP); \
+		unsigned val; \
+		CSR_WRITE_4((sc),PCN_IO32_RAP,PCN_CSR_CSR); \
+		val = CSR_READ_4((sc),PCN_IO32_RDP); \
+		CSR_WRITE_4((sc), PCN_IO32_RDP,  val & ~(CSR0_INT_STATUS_MASK | PCN_CSR_INTEN)); \
+		CSR_WRITE_4((sc), PCN_IO32_RAP, rap); \
+		} while (0)
+
+#define NET_ENABLE_IRQS(sc)	do { \
+		unsigned flags,val;	\
+		rtems_interrupt_disable(flags); \
+		CSR_WRITE_4((sc),PCN_IO32_RAP,PCN_CSR_CSR); \
+		val = CSR_READ_4((sc),PCN_IO32_RDP); \
+		CSR_WRITE_4((sc), PCN_IO32_RDP,  (val & ~CSR0_INT_STATUS_MASK) | PCN_CSR_INTEN); \
+		rtems_interrupt_enable(flags); \
+		} while (0)
+*/
+
+/* Driver may provide a macro/function to copy the hardware address
+ * from the device into 'softc.arpcom'.
+ * If this is undefined, the driver must to the copy itself.
+ * Preferrably, it should check soft.arpcom.ac_enaddr for all
+ * zeros and leave it alone if it is nonzero, i.e., write it
+ * to the hardware.
+#define NET_READ_MAC_ADDR(sc)
+ */
+		
+#define KASSERT(a...) do {} while (0)
+#endif
Index: bsps/powerpc/beatnik/net/support/bsp_attach.c
===================================================================
--- bsps/powerpc/beatnik/net/support/bsp_attach.c	(revision 031df3914990db0336a0d386fb53558b05de467e)
+++ bsps/powerpc/beatnik/net/support/bsp_attach.c	(revision 031df3914990db0336a0d386fb53558b05de467e)
@@ -0,0 +1,468 @@
+/* BSP specific wrapper for rtems_bsdnet_attach(). This wrapper
+ * dispatches to the correct driver attach routine depending on
+ * the board type, boot parameters, link status etc.
+ *
+ * Also, it performs board-specific setup of driver parameters
+ * (such as ethernet address, base addresses and the like)
+ */
+
+/* 
+ * Authorship
+ * ----------
+ * This software ('beatnik' RTEMS BSP for MVME6100 and MVME5500) was
+ *     created by Till Straumann <strauman@slac.stanford.edu>, 2005-2007,
+ * 	   Stanford Linear Accelerator Center, Stanford University.
+ * 
+ * Acknowledgement of sponsorship
+ * ------------------------------
+ * The 'beatnik' BSP was produced by
+ *     the Stanford Linear Accelerator Center, Stanford University,
+ * 	   under Contract DE-AC03-76SFO0515 with the Department of Energy.
+ * 
+ * Government disclaimer of liability
+ * ----------------------------------
+ * Neither the United States nor the United States Department of Energy,
+ * nor any of their employees, makes any warranty, express or implied, or
+ * assumes any legal liability or responsibility for the accuracy,
+ * completeness, or usefulness of any data, apparatus, product, or process
+ * disclosed, or represents that its use would not infringe privately owned
+ * rights.
+ * 
+ * Stanford disclaimer of liability
+ * --------------------------------
+ * Stanford University makes no representations or warranties, express or
+ * implied, nor assumes any liability for the use of this software.
+ * 
+ * Stanford disclaimer of copyright
+ * --------------------------------
+ * Stanford University, owner of the copyright, hereby disclaims its
+ * copyright and all other rights in this software.  Hence, anyone may
+ * freely use it for any purpose without restriction.  
+ * 
+ * Maintenance of notices
+ * ----------------------
+ * In the interest of clarity regarding the origin and status of this
+ * SLAC software, this and all the preceding Stanford University notices
+ * are to remain affixed to any copy or derivative of this software made
+ * or distributed by the recipient and are to be affixed to any copy of
+ * software made or distributed by the recipient that contains a copy or
+ * derivative of this software.
+ * 
+ * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
+ */ 
+
+#include <unistd.h>
+
+#include <rtems.h>
+#include <rtems/rtems_bsdnet.h>
+
+#include <bsp.h>
+#include <bsp/irq.h>
+#include <bsp/pci.h>
+
+#include <bsp/early_enet_link_status.h>
+
+#include <bsp/if_mve_pub.h>
+#include <bsp/if_gfe_pub.h>
+#include <bsp/if_em_pub.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#define IS_6100()		(MVME6100 == BSP_getBoardType())
+#define IS_5500()		(MVME5500 == BSP_getBoardType())
+
+static int bsp_gfe_attach(struct rtems_bsdnet_ifconfig *, int);
+static int mvme5500_em_attach (struct rtems_bsdnet_ifconfig *, int);
+static int mvme5500_em_find_onboard_unit(void);
+
+char BSP_auto_network_driver_name[20] = {0,};
+
+static BSP_NetIFDescRec mvme6100_netifs[] = {
+	{
+		name:			"mve1",
+		description:	"MV64360 built-in 10/100/1000 Ethernet 1",
+		attach_fn:		rtems_mve_attach
+	},
+	{
+		name:			"mve2",
+		description:	"MV64360 built-in 10/100/1000 Ethernet 2",
+		attach_fn:		rtems_mve_attach
+	},
+	{
+		name:			0,
+	}
+};
+
+static BSP_NetIFDescRec mvme5500_netifs[] = {
+	{
+		name:			"em1",
+		description:	"Intel 82544 on-board 10/100/1000 Ethernet (port 1)",
+		attach_fn:		mvme5500_em_attach,
+	},
+	{
+		name:			"gfe1",
+		description:	"GT64260 built-in 10/100 Ethernet (port 2)",
+		attach_fn:		bsp_gfe_attach,
+	},
+	{
+		name:			0,
+	}
+};
+
+
+/* wrap the 'gfe' and 'em' attach functions.
+ * RATIONALE: 'rtems_gfe_attach()' and 'rtems_em_attach()' are
+ *            *chip* specific functions. However, they require
+ *            some *board* specific parameter setup prior to
+ *            being attached which is what these wrappers do...
+ */
+
+static unsigned em_info[];
+
+static int scan4irqLine(int bus, int dev, int fn, void *uarg)
+{
+unsigned char  byte;
+unsigned short word;
+int            i;
+
+	/* count the number of 82544 we find */
+	pci_read_config_word(bus, dev, fn, PCI_VENDOR_ID, &word);
+	if ( 0x8086 != word )
+		return 0;
+
+	pci_read_config_word(bus, dev, fn, PCI_DEVICE_ID, &word);
+	for ( i = 0; em_info[i]; i++ ) {
+		if ( em_info[i] == word )
+			break;
+	}
+
+	if ( !em_info[i] )
+		return 0;
+
+	/* found a candidate; bump unit number */
+	(*(int *)uarg)++;
+
+	pci_read_config_byte(bus, dev, fn, PCI_INTERRUPT_LINE, &byte);
+
+	/* On the mvme5500 the 82544 is hooked to GPP IRQ 20 */
+
+	return ( BSP_IRQ_GPP_0 + 20 == byte ) ? 1 : 0;
+}
+
+/* Setup only once */
+static void
+onboard_em_setup_once(void)
+{
+static char done = 0;
+
+	/* If scanning didn't do anything, passing 0 will setup all interfaces  */
+	if (   !done
+		&& rtems_em_pci_setup( mvme5500_em_find_onboard_unit() > 0 ) ) {
+		done=1;
+	}
+}
+
+static void
+onboard_gfe_setup_once(void)
+{
+static char done = 0;
+
+	/* must setup HW address -- note that the label on the
+	 * board indicates that the gfe is the second interface
+	 * but motLoad etc. interprets the order actually
+	 * the other way round...
+	 */
+	if (   !done
+		&& rtems_gfe_setup( 1, BSP_enetAddr0, BSP_MV64x60_BASE ) > 0 ) {
+		done=1;
+	}
+}
+
+
+/* Find the unit number of the on-board 82544 (even if there is another one
+ * plugged into PMC...
+ *
+ * RETURNS: unit #  (>0) or zero if nothing at all was found. (New board rev.
+ *          with the 82544 hooked to a different IRQ line, new PCI device ID,
+ *          ...)
+ */
+static int
+mvme5500_em_find_onboard_unit(void)
+{
+int unit = 0;
+void *h;
+	/* Determine the on-board 'em' adapter; we know it's interrupt line :-) */
+	for ( h=0; (h=BSP_pciScan(h, scan4irqLine, &unit)); )
+		/* nothing else to do */;
+	return h ? unit : 0;
+}
+
+static int
+mvme5500_em_attach(struct rtems_bsdnet_ifconfig *ifcfg, int attaching)
+{
+	if ( attaching ) {
+		onboard_em_setup_once();
+
+		/* Make sure there is no conflict in MAC address -- see below
+		 * why we 'swap' the addresses. (We actually don't but swap the
+		 * order of the interfaces so they match the label.)
+		 */
+		if ( !ifcfg->hardware_address )
+			ifcfg->hardware_address = BSP_enetAddr1;
+	}
+
+	return rtems_em_attach(ifcfg, attaching);
+}
+
+static int
+bsp_gfe_attach(struct rtems_bsdnet_ifconfig *ifcfg, int attaching)
+{
+	if ( attaching ) {
+		onboard_gfe_setup_once();
+	}
+	return rtems_gfe_attach(ifcfg, attaching);
+}
+
+BSP_NetIFDesc
+BSP_availableNetIFs(void)
+{
+	if ( IS_6100() )
+		return mvme6100_netifs;
+	if ( IS_5500() )
+		return mvme5500_netifs;
+
+	fprintf(stderr,"BSP_availableNetIFs() -- productIdent not set? unable to identify board type\n");
+
+	return 0;
+}
+
+typedef int (*read_op_t)(int,unsigned);
+typedef int (*write_op_t)(int,unsigned,unsigned);
+
+struct poll_job {
+	read_op_t	rdop;
+	write_op_t	wrop;
+	int			unit;
+};
+
+static int
+check_phys(struct poll_job *job)
+{
+struct poll_job *j;
+int             rval = -2;
+	for ( j=job; j->rdop; j++ ) {
+		unsigned w;
+		w = j->rdop(j->unit, 1/*status*/);
+		if ( 0x04 & w )	   /* active link */
+			return j-job;
+		if ( !(0x20 & w) ) /* aneg not done   */
+			rval = -1;	
+	}
+	return rval;
+}
+
+/* check a number of phys
+ * RETURNS: -1 if at least one is still busy
+ *          -2 if all are terminated but no link is found
+ *         >=0 index of first IF with a live link
+ */
+static int
+poll_phys(struct poll_job *job)
+{
+int				rval;
+struct poll_job *j   = job;
+int             retry = 4;
+
+	/* see if we already have a link */
+	if ( (rval=check_phys(job)) < 0 ) {
+		/* no - start negotiation */
+		for ( j = job; j->rdop; j++ ) {
+			j->wrop(j->unit, 0/* ctrl */, 0x1200 /* start aneg */);
+		}
+
+		do {
+			sleep(1);
+		} while ( -1 == (rval = check_phys(job)) && retry-- ); 
+	}
+
+	return rval;
+}
+
+
+/* note that detaching is not supported by the current version of the BSD stack */
+int
+BSP_auto_enet_attach(struct rtems_bsdnet_ifconfig *ifcfg, int attaching)
+{
+int             i = -1;
+BSP_NetIFDesc   d = BSP_availableNetIFs();
+struct poll_job	job[3];
+
+	if ( !d )
+		return -1;
+
+	/* If they pass a name, find the attach fn */
+	if ( ifcfg->name  && RTEMS_BSP_NETWORK_DRIVER_NAME != ifcfg->name && attaching ) {
+		for (i = 0; d[i].name; i++ ) {
+			if ( !strcmp(d[i].name, ifcfg->name) ) {
+				ifcfg->attach = d[i].attach_fn;
+				break;
+			}
+		}
+		if ( !d[i].name ) {
+			fprintf(stderr,"WARNING: have no '%s' interface - using default\n", ifcfg->name);
+			ifcfg->name = 0;
+		}
+	}
+
+	if ( !ifcfg->name || ifcfg->name == RTEMS_BSP_NETWORK_DRIVER_NAME ) {
+		/* automatically choose and attach an interface */
+		if ( RTEMS_BSP_NETWORK_DRIVER_NAME[0] ) {
+			fprintf(stderr,
+					"Configuration error: 'auto' network if already chosen (%s)\n",
+					RTEMS_BSP_NETWORK_DRIVER_NAME);
+			return -1;
+		}
+		if ( IS_6100() ) {
+#define ops rtems_mve_early_link_check_ops
+			assert(ops.num_slots >= 2);
+			ops.init(0);
+			ops.init(1);
+			job[0].rdop = ops.read_phy;
+			job[0].wrop = ops.write_phy;
+			job[0].unit = 0;
+			job[1].rdop = ops.read_phy;
+			job[1].wrop = ops.write_phy;
+			job[1].unit = 1;
+#undef ops
+		} else if ( IS_5500() ) {
+#define opsgfe rtems_gfe_early_link_check_ops
+#define opsem  rtems_em_early_link_check_ops
+			assert(opsgfe.num_slots >= 1);
+			onboard_gfe_setup_once();
+			opsgfe.init(0);
+			assert(opsem.num_slots >= 1);
+			onboard_em_setup_once();
+			opsem.init(0);
+			job[0].rdop = opsem.read_phy;
+			job[0].wrop = opsem.write_phy;
+			job[0].unit = 0;
+			job[1].rdop = opsgfe.read_phy;
+			job[1].wrop = opsgfe.write_phy;
+			job[1].unit = 0;
+#undef opsgfe
+#undef opsem
+		}
+		job[2].rdop = 0; /* tag end */
+		i = poll_phys(job);
+		if ( i >= 0 ) {
+			printf("L");
+		} else {
+			i = 0;
+			printf("No l");
+		}
+		printf("ink detected; attaching %s\n",d[i].name);
+
+		/* set attach function and IF name */
+		ifcfg->attach = d[i].attach_fn;
+		ifcfg->name   = RTEMS_BSP_NETWORK_DRIVER_NAME;
+		strcpy(RTEMS_BSP_NETWORK_DRIVER_NAME, d[i].name);
+	}
+	return ifcfg->attach(ifcfg, attaching);
+}
+
+/* from 'em' */
+
+/* PCI Device IDs */
+#define E1000_DEV_ID_82542               0x1000
+#define E1000_DEV_ID_82543GC_FIBER       0x1001
+#define E1000_DEV_ID_82543GC_COPPER      0x1004
+#define E1000_DEV_ID_82544EI_COPPER      0x1008
+#define E1000_DEV_ID_82544EI_FIBER       0x1009
+#define E1000_DEV_ID_82544GC_COPPER      0x100C
+#define E1000_DEV_ID_82544GC_LOM         0x100D
+#define E1000_DEV_ID_82540EM             0x100E
+#define E1000_DEV_ID_82541ER_LOM         0x1014
+#define E1000_DEV_ID_82540EM_LOM         0x1015
+#define E1000_DEV_ID_82540EP_LOM         0x1016
+#define E1000_DEV_ID_82540EP             0x1017
+#define E1000_DEV_ID_82540EP_LP          0x101E
+#define E1000_DEV_ID_82545EM_COPPER      0x100F
+#define E1000_DEV_ID_82545EM_FIBER       0x1011
+#define E1000_DEV_ID_82545GM_COPPER      0x1026
+#define E1000_DEV_ID_82545GM_FIBER       0x1027
+#define E1000_DEV_ID_82545GM_SERDES      0x1028
+#define E1000_DEV_ID_82546EB_COPPER      0x1010
+#define E1000_DEV_ID_82546EB_FIBER       0x1012
+#define E1000_DEV_ID_82546EB_QUAD_COPPER 0x101D
+#define E1000_DEV_ID_82541EI             0x1013
+#define E1000_DEV_ID_82541EI_MOBILE      0x1018
+#define E1000_DEV_ID_82541ER             0x1078
+#define E1000_DEV_ID_82547GI             0x1075
+#define E1000_DEV_ID_82541GI             0x1076
+#define E1000_DEV_ID_82541GI_MOBILE      0x1077
+#define E1000_DEV_ID_82541GI_LF          0x107C
+#define E1000_DEV_ID_82546GB_COPPER      0x1079
+#define E1000_DEV_ID_82546GB_FIBER       0x107A
+#define E1000_DEV_ID_82546GB_SERDES      0x107B
+#define E1000_DEV_ID_82546GB_PCIE        0x108A
+#define E1000_DEV_ID_82547EI             0x1019
+#define E1000_DEV_ID_82547EI_MOBILE      0x101A
+#define E1000_DEV_ID_82573E              0x108B
+#define E1000_DEV_ID_82573E_IAMT         0x108C
+
+#define E1000_DEV_ID_82546GB_QUAD_COPPER 0x1099
+
+static unsigned em_info[] =
+{
+        /* Intel(R) PRO/1000 Network Connection */
+        E1000_DEV_ID_82540EM,
+        E1000_DEV_ID_82540EM_LOM,
+        E1000_DEV_ID_82540EP,
+        E1000_DEV_ID_82540EP_LOM,
+        E1000_DEV_ID_82540EP_LP,
+
+        E1000_DEV_ID_82541EI,
+        E1000_DEV_ID_82541ER,
+        E1000_DEV_ID_82541ER_LOM,
+        E1000_DEV_ID_82541EI_MOBILE,
+        E1000_DEV_ID_82541GI,
+        E1000_DEV_ID_82541GI_LF,
+        E1000_DEV_ID_82541GI_MOBILE,
+
+        E1000_DEV_ID_82542,
+
+        E1000_DEV_ID_82543GC_FIBER,
+        E1000_DEV_ID_82543GC_COPPER,
+
+        E1000_DEV_ID_82544EI_COPPER,
+        E1000_DEV_ID_82544EI_FIBER,
+        E1000_DEV_ID_82544GC_COPPER,
+        E1000_DEV_ID_82544GC_LOM,
+
+        E1000_DEV_ID_82545EM_COPPER,
+        E1000_DEV_ID_82545EM_FIBER,
+        E1000_DEV_ID_82545GM_COPPER,
+        E1000_DEV_ID_82545GM_FIBER,
+        E1000_DEV_ID_82545GM_SERDES,
+
+        E1000_DEV_ID_82546EB_COPPER,
+        E1000_DEV_ID_82546EB_FIBER,
+        E1000_DEV_ID_82546EB_QUAD_COPPER,
+        E1000_DEV_ID_82546GB_COPPER,
+        E1000_DEV_ID_82546GB_FIBER,
+        E1000_DEV_ID_82546GB_SERDES,
+        E1000_DEV_ID_82546GB_PCIE,
+        E1000_DEV_ID_82546GB_QUAD_COPPER,
+
+        E1000_DEV_ID_82547EI,
+        E1000_DEV_ID_82547EI_MOBILE,
+        E1000_DEV_ID_82547GI,
+
+        E1000_DEV_ID_82573E,
+        E1000_DEV_ID_82573E_IAMT,
+
+        /* required last entry */
+        0,
+};
Index: bsps/powerpc/beatnik/net/support/early_link_status.c
===================================================================
--- bsps/powerpc/beatnik/net/support/early_link_status.c	(revision 031df3914990db0336a0d386fb53558b05de467e)
+++ bsps/powerpc/beatnik/net/support/early_link_status.c	(revision 031df3914990db0336a0d386fb53558b05de467e)
@@ -0,0 +1,40 @@
+#include <rtems.h>
+#include <bsp/early_enet_link_status.h>
+#include <rtems/bspIo.h>
+
+/* T. Straumann, 2005; see ../../LICENSE */
+
+static const char *ename = ": rtems_em_early_check_link_status() - ";
+
+int
+BSP_early_check_link_status(int unit, rtems_bsdnet_early_link_check_ops *ops)
+{
+int status;
+
+	unit--;
+	if ( unit < 0 || unit >= ops->num_slots ) {
+		printk("%s%sinvalid unit # %i (not in %i..%i)\n",
+				ops->name, ename, unit+1, 1, ops->num_slots);
+		return -1;
+	}
+
+	if ( !ops->initialized ) {
+		if ( ops->init(unit) ) {
+			printk("%s%sFAILURE to init hardware\n",ops->name, ename);
+			return -1;
+		}
+		/* Start autoneg */
+		if ( ops->write_phy(unit, 0, 0x1200) ) {
+			printk("%s%sFAILURE to start autonegotiation\n",ops->name, ename);
+			return -1;
+		}
+		/* Dont wait here; the caller can do this on various interfaces
+		 * and wait herself.
+	 	 */
+		ops->initialized = 1;
+	}
+	if ( (status = ops->read_phy(unit, 1)) < 0 ) {
+		printk("%s%sFAILURE to read phy status\n", ops->name, ename);
+	}
+	return status;
+}
