Whamcloud - gitweb
Adding patches necessary for intel kernels into sourceforge.
authorthantry <thantry>
Fri, 3 Jan 2003 00:53:19 +0000 (00:53 +0000)
committerthantry <thantry>
Fri, 3 Jan 2003 00:53:19 +0000 (00:53 +0000)
The rh-8.0-intel series captures, in addition to all the lustre
specific patches the remaining two patches necessary(or of interest)
to the Intel cluster.

lustre/kernel_patches/patches/e1000.patch [new file with mode: 0644]
lustre/kernel_patches/patches/tcp_zero.patch [new file with mode: 0644]
lustre/kernel_patches/pc/e1000.pc [new file with mode: 0644]
lustre/kernel_patches/pc/tcp_zero.pc [new file with mode: 0644]
lustre/kernel_patches/series/rh-8.0-intel [new file with mode: 0644]
lustre/kernel_patches/txt/e1000.txt [new file with mode: 0644]
lustre/kernel_patches/txt/tcp_zero.txt [new file with mode: 0644]

diff --git a/lustre/kernel_patches/patches/e1000.patch b/lustre/kernel_patches/patches/e1000.patch
new file mode 100644 (file)
index 0000000..ed63058
--- /dev/null
@@ -0,0 +1,11535 @@
+
+This patch creates the necessary drivers
+for the e1000 card that are not included with
+the standard RH distribution. This is used for the
+GigE e1000 cards.
+
+
+ 0 files changed
+
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ linux-2.4.18-14-root/drivers/e1000/e1000.h 2003-01-02 16:22:31.000000000 -0800
+@@ -0,0 +1,362 @@
++/*******************************************************************************
++
++  This software program is available to you under a choice of one of two 
++  licenses. You may choose to be licensed under either the GNU General Public 
++  License (GPL) Version 2, June 1991, available at 
++  http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the 
++  text of which follows:
++  
++  Recipient has requested a license and Intel Corporation ("Intel") is willing
++  to grant a license for the software entitled Linux Base Driver for the 
++  Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided
++  by Intel Corporation. The following definitions apply to this license:
++  
++  "Licensed Patents" means patent claims licensable by Intel Corporation which 
++  are necessarily infringed by the use of sale of the Software alone or when 
++  combined with the operating system referred to below.
++  
++  "Recipient" means the party to whom Intel delivers this Software.
++  
++  "Licensee" means Recipient and those third parties that receive a license to 
++  any operating system available under the GNU Public License version 2.0 or 
++  later.
++  
++  Copyright (c) 1999 - 2002 Intel Corporation.
++  All rights reserved.
++  
++  The license is provided to Recipient and Recipient's Licensees under the 
++  following terms.
++  
++  Redistribution and use in source and binary forms of the Software, with or 
++  without modification, are permitted provided that the following conditions 
++  are met:
++  
++  Redistributions of source code of the Software may retain the above 
++  copyright notice, this list of conditions and the following disclaimer.
++  
++  Redistributions in binary form of the Software may reproduce the above 
++  copyright notice, this list of conditions and the following disclaimer in 
++  the documentation and/or materials provided with the distribution.
++  
++  Neither the name of Intel Corporation nor the names of its contributors 
++  shall be used to endorse or promote products derived from this Software 
++  without specific prior written permission.
++  
++  Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, 
++  royalty-free patent license under Licensed Patents to make, use, sell, offer 
++  to sell, import and otherwise transfer the Software, if any, in source code 
++  and object code form. This license shall include changes to the Software 
++  that are error corrections or other minor changes to the Software that do 
++  not add functionality or features when the Software is incorporated in any 
++  version of an operating system that has been distributed under the GNU 
++  General Public License 2.0 or later. This patent license shall apply to the 
++  combination of the Software and any operating system licensed under the GNU 
++  Public License version 2.0 or later if, at the time Intel provides the 
++  Software to Recipient, such addition of the Software to the then publicly 
++  available versions of such operating systems available under the GNU Public 
++  License version 2.0 or later (whether in gold, beta or alpha form) causes 
++  such combination to be covered by the Licensed Patents. The patent license 
++  shall not apply to any other combinations which include the Software. NO 
++  hardware per se is licensed hereunder.
++  
++  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 MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
++  ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY 
++  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
++  (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
++  ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) 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.
++
++*******************************************************************************/
++
++
++/* Linux PRO/1000 Ethernet Driver main header file */
++
++#ifndef _E1000_H_
++#define _E1000_H_
++
++#ifndef __E1000_MAIN__
++#define __NO_VERSION__
++#endif
++
++#include <linux/stddef.h>
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/types.h>
++#include <asm/byteorder.h>
++#include <linux/init.h>
++#include <linux/mm.h>
++#include <linux/errno.h>
++#include <linux/ioport.h>
++#include <linux/pci.h>
++#include <linux/kernel.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/skbuff.h>
++#include <linux/delay.h>
++#include <linux/timer.h>
++#include <linux/slab.h>
++#include <linux/interrupt.h>
++#include <linux/string.h>
++#include <linux/pagemap.h>
++#include <asm/bitops.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <linux/capability.h>
++#include <linux/in.h>
++#include <linux/ip.h>
++#include <linux/tcp.h>
++#include <linux/udp.h>
++#include <net/pkt_sched.h>
++
++/* ethtool support */
++#ifdef SIOCETHTOOL
++#include <linux/ethtool.h>
++#include <asm/uaccess.h>
++#define  E1000_ETHTOOL_COPPER_INTERFACE_SUPPORTS (SUPPORTED_10baseT_Half | \
++                    SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half | \
++                    SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Full | \
++                    SUPPORTED_Autoneg | SUPPORTED_MII)
++#define  E1000_ETHTOOL_COPPER_INTERFACE_ADVERTISE (ADVERTISED_10baseT_Half | \
++                    ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Half | \
++                    ADVERTISED_100baseT_Full | ADVERTISED_1000baseT_Full | \
++                    ADVERTISED_Autoneg | ADVERTISED_MII)
++#define E1000_ETHTOOL_FIBER_INTERFACE_SUPPORTS (SUPPORTED_Autoneg | \
++                    SUPPORTED_FIBRE)
++#define E1000_ETHTOOL_FIBER_INTERFACE_ADVERTISE (ADVERTISED_Autoneg | \
++                    ADVERTISED_FIBRE)
++#endif /* SIOCETHTOOL */
++
++
++
++struct e1000_adapter;
++
++#include "e1000_mac.h"
++#include "e1000_phy.h"
++
++#ifdef IANS
++#include "base_comm.h"
++#include "ans_driver.h"
++#include "ans.h"
++#endif
++
++#ifdef IDIAG
++#include "idiag_pro.h"
++#include "idiag_e1000.h"
++#endif
++
++#define BAR_0 0
++
++/* 8254x can use Dual Address Cycles for 64-bit addressing */
++
++/* Advertise that we can DMA from any address location */
++#define E1000_DMA_MASK (~0x0UL)
++#define E1000_DBG(args...)
++// #define E1000_DBG(args...) printk("e1000: " args)
++#define E1000_ERR(args...) printk(KERN_ERR "e1000: " args)
++#ifdef CONFIG_PPC
++#define E1000_MAX_INTR 1
++#else
++#define E1000_MAX_INTR 10
++#endif
++#define MAX_NUM_MULTICAST_ADDRESSES 128
++
++/* command line options defaults */
++#define DEFAULT_TXD                  256
++#define MAX_TXD                      256
++#define MIN_TXD                       80
++#define MAX_82544_TXD               4096
++#define DEFAULT_RXD                  256
++#define MAX_RXD                      256
++#define MIN_RXD                       80
++#define MAX_82544_RXD               4096
++#define DEFAULT_TIDV                  64
++#define MAX_TIDV                  0xFFFF
++#define MIN_TIDV                       0
++#define DEFAULT_RIDV                  64
++#define MAX_RIDV                  0xFFFF
++#define MIN_RIDV                       0
++#define DEFAULT_MDIX                   0
++#define MAX_MDIX                       3
++#define MIN_MDIX                       0
++
++#define OPTION_UNSET    -1
++#define OPTION_DISABLED 0
++#define OPTION_ENABLED  1
++#define XSUMRX_DEFAULT       OPTION_ENABLED
++#define WAITFORLINK_DEFAULT  OPTION_ENABLED
++#define AUTONEG_ADV_DEFAULT  0x2F
++#define AUTONEG_ADV_MASK     0x2F
++#define FLOW_CONTROL_DEFAULT FLOW_CONTROL_FULL
++
++#define E1000_REPORT_TX_EARLY  2
++
++/* Supported RX Buffer Sizes */
++#define E1000_RXBUFFER_2048  2048
++#define E1000_RXBUFFER_4096  4096
++#define E1000_RXBUFFER_8192  8192
++#define E1000_RXBUFFER_16384 16384
++
++#define E1000_JUMBO_PBA      0x00000028
++#define E1000_DEFAULT_PBA    0x00000030
++
++/* Round size up to the next multiple of unit */
++#define E1000_ROUNDUP(size, unit) ((((size) + (unit) - 1) / (unit)) * (unit))
++
++/* This is better, but only works for unit sizes that are powers of 2 */
++#define E1000_ROUNDUP2(size, unit) (((size) + (unit) - 1) & ~((unit) - 1))
++
++/* wrapper around a pointer to a socket buffer,
++ * so a DMA handle can be stored along with the buffer */
++struct e1000_buffer {
++    struct sk_buff *skb;
++    uint64_t dma;
++    unsigned long length;
++};
++
++/* Adapter->flags definitions */
++#define E1000_BOARD_OPEN 0
++#define E1000_RX_REFILL 1
++#define E1000_DIAG_OPEN 2
++#define E1000_LINK_STATUS_CHANGED 3
++
++typedef enum _XSUM_CONTEXT_T {
++    OFFLOAD_NONE,
++    OFFLOAD_TCP_IP,
++    OFFLOAD_UDP_IP
++} XSUM_CONTEXT_T;
++
++struct e1000_desc_ring {
++    void *desc;                 /* pointer to the descriptor ring memory      */
++    dma_addr_t dma;             /* physical address of the descriptor ring    */
++    unsigned int size;          /* length of descriptor ring in bytes         */
++    unsigned int count;         /* number of descriptors in the ring          */
++    atomic_t unused;            /* number of descriptors with no buffer       */
++    unsigned int next_to_use;   /* next descriptor to associate a buffer with */
++    unsigned int next_to_clean; /* next descriptor to check for DD status bit */
++    struct e1000_buffer *buffer_info; /* array of buffer information structs  */
++};
++
++#define E1000_RX_DESC(ring, i) \
++    (&(((struct e1000_rx_desc *)(ring.desc))[i]))
++
++#define E1000_TX_DESC(ring, i) \
++    (&(((struct e1000_tx_desc *)(ring.desc))[i]))
++
++#define E1000_CONTEXT_DESC(ring, i) \
++    (&(((struct e1000_context_desc *)(ring.desc))[i]))
++
++/* board specific private data structure */
++
++struct e1000_adapter {
++    struct e1000_adapter *next;
++    struct e1000_adapter *prev;
++
++    struct e1000_shared_adapter shared;
++
++#ifdef IANS
++    void *iANSReserved;
++    piANSsupport_t iANSdata;
++    uint32_t ans_link;
++    uint32_t ans_speed;
++    uint32_t ans_duplex;
++    uint32_t ans_suspend;
++    IANS_BD_TAGGING_MODE tag_mode;
++#endif
++
++    spinlock_t stats_lock;
++    spinlock_t rx_fill_lock;
++
++    unsigned long flags;
++    uint32_t bd_number;
++    struct timer_list timer_id;
++
++    /* Ethernet Node Address */
++    uint8_t perm_net_addr[ETH_LENGTH_OF_ADDRESS];
++
++    /* Status Flags */
++    boolean_t link_active;
++    uint16_t link_speed;
++    uint16_t link_duplex;
++    uint32_t rx_buffer_len;
++
++    /* PCI Device Info */
++    uint16_t vendor_id;
++    uint16_t device_id;
++    uint8_t rev_id;
++    uint16_t subven_id;
++    uint16_t subsys_id;
++
++    uint32_t part_num;
++
++    uint32_t int_mask;
++
++    /* driver specific */
++    struct tasklet_struct rx_fill_tasklet;
++
++    struct e1000_desc_ring tx_ring;
++    uint32_t tx_int_delay;
++    uint32_t TxdCmd;
++    atomic_t tx_timeout;
++
++    struct e1000_desc_ring rx_ring;
++    uint32_t rx_int_delay;
++
++    uint64_t XsumRXGood;
++    uint64_t XsumRXError;
++
++    /* Linux driver specific */
++    struct net_device *netdev;
++    struct pci_dev *pdev;
++    struct net_device_stats net_stats;
++    char *id_string;
++    boolean_t RxChecksum;
++    XSUM_CONTEXT_T ActiveChecksumContext;
++
++    struct e1000_phy_info phy_info;
++    struct e1000_shared_stats stats;
++
++    /* PHY Statistics */
++    struct e1000_phy_stats phy_stats;
++};
++
++/* Prototypes */
++
++/* e1000_main.c */
++extern int e1000_init_module(void);
++extern int e1000_probe_all(void);
++extern void e1000_exit_module(void);
++extern int e1000_probe(struct pci_dev *pdev,
++                       const struct pci_device_id *ent);
++extern void e1000_remove(struct pci_dev *pdev);
++extern void e1000_delete(struct e1000_adapter *Adapter);
++extern int e1000_open(struct net_device *netdev);
++extern int e1000_close(struct net_device *netdev);
++extern void e1000_set_multi(struct net_device *netdev);
++extern int e1000_xmit_frame(struct sk_buff *skb,
++                            struct net_device *netdev);
++extern struct net_device_stats *e1000_get_stats(struct net_device *netdev);
++extern int e1000_change_mtu(struct net_device *netdev,
++                            int new_mtu);
++extern int e1000_set_mac(struct net_device *netdev,
++                         void *p);
++extern void e1000_intr(int irq,
++                       void *data,
++                       struct pt_regs *regs);
++extern int e1000_ioctl(struct net_device *netdev,
++                       struct ifreq *ifr,
++                       int cmd);
++extern void e1000_watchdog(unsigned long data);
++extern void e1000_diag_ioctl(struct net_device *netdev,
++                             struct ifreq *ifr);
++
++#ifdef CONFIG_PROC_FS
++#include "e1000_proc.h"
++#endif
++#ifdef IDIAG
++#include "e1000_idiag.h"
++#endif
++#endif /* _E1000_H_ */
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ linux-2.4.18-14-root/drivers/e1000/e1000_mac.c     2003-01-02 16:22:31.000000000 -0800
+@@ -0,0 +1,2093 @@
++/*******************************************************************************
++
++  This software program is available to you under a choice of one of two 
++  licenses. You may choose to be licensed under either the GNU General Public 
++  License (GPL) Version 2, June 1991, available at 
++  http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the 
++  text of which follows:
++  
++  Recipient has requested a license and Intel Corporation ("Intel") is willing
++  to grant a license for the software entitled Linux Base Driver for the 
++  Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided
++  by Intel Corporation. The following definitions apply to this license:
++  
++  "Licensed Patents" means patent claims licensable by Intel Corporation which 
++  are necessarily infringed by the use of sale of the Software alone or when 
++  combined with the operating system referred to below.
++  
++  "Recipient" means the party to whom Intel delivers this Software.
++  
++  "Licensee" means Recipient and those third parties that receive a license to 
++  any operating system available under the GNU Public License version 2.0 or 
++  later.
++  
++  Copyright (c) 1999 - 2002 Intel Corporation.
++  All rights reserved.
++  
++  The license is provided to Recipient and Recipient's Licensees under the 
++  following terms.
++  
++  Redistribution and use in source and binary forms of the Software, with or 
++  without modification, are permitted provided that the following conditions 
++  are met:
++  
++  Redistributions of source code of the Software may retain the above 
++  copyright notice, this list of conditions and the following disclaimer.
++  
++  Redistributions in binary form of the Software may reproduce the above 
++  copyright notice, this list of conditions and the following disclaimer in 
++  the documentation and/or materials provided with the distribution.
++  
++  Neither the name of Intel Corporation nor the names of its contributors 
++  shall be used to endorse or promote products derived from this Software 
++  without specific prior written permission.
++  
++  Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, 
++  royalty-free patent license under Licensed Patents to make, use, sell, offer 
++  to sell, import and otherwise transfer the Software, if any, in source code 
++  and object code form. This license shall include changes to the Software 
++  that are error corrections or other minor changes to the Software that do 
++  not add functionality or features when the Software is incorporated in any 
++  version of an operating system that has been distributed under the GNU 
++  General Public License 2.0 or later. This patent license shall apply to the 
++  combination of the Software and any operating system licensed under the GNU 
++  Public License version 2.0 or later if, at the time Intel provides the 
++  Software to Recipient, such addition of the Software to the then publicly 
++  available versions of such operating systems available under the GNU Public 
++  License version 2.0 or later (whether in gold, beta or alpha form) causes 
++  such combination to be covered by the Licensed Patents. The patent license 
++  shall not apply to any other combinations which include the Software. NO 
++  hardware per se is licensed hereunder.
++  
++  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 MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
++  ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY 
++  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
++  (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
++  ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) 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.
++
++*******************************************************************************/
++
++/* e1000_mac.c
++ * Shared functions for accessing and configuring the MAC
++ */
++
++#include "e1000_mac.h"
++#include "e1000_phy.h"
++
++/******************************************************************************
++ * Raises the EEPROM's clock input.
++ *
++ * shared - Struct containing variables accessed by shared code
++ * eecd_reg - EECD's current value
++ *****************************************************************************/
++static void
++e1000_raise_clock(struct e1000_shared_adapter *shared,
++                  uint32_t *eecd_reg)
++{
++    /* Raise the clock input to the EEPROM (by setting the SK bit), and then
++     * wait 50 microseconds.
++     */
++    *eecd_reg = *eecd_reg | E1000_EECD_SK;
++    E1000_WRITE_REG(shared, EECD, *eecd_reg);
++    usec_delay(50);
++    return;
++}
++
++/******************************************************************************
++ * Lowers the EEPROM's clock input.
++ *
++ * shared - Struct containing variables accessed by shared code 
++ * eecd_reg - EECD's current value
++ *****************************************************************************/
++static void
++e1000_lower_clock(struct e1000_shared_adapter *shared,
++                  uint32_t *eecd_reg)
++{
++    /* Lower the clock input to the EEPROM (by clearing the SK bit), and then 
++     * wait 50 microseconds. 
++     */
++    *eecd_reg = *eecd_reg & ~E1000_EECD_SK;
++    E1000_WRITE_REG(shared, EECD, *eecd_reg);
++    usec_delay(50);
++    return;
++}
++
++/******************************************************************************
++ * Shift data bits out to the EEPROM.
++ *
++ * shared - Struct containing variables accessed by shared code
++ * data - data to send to the EEPROM
++ * count - number of bits to shift out
++ *****************************************************************************/
++static void
++e1000_shift_out_bits(struct e1000_shared_adapter *shared,
++                     uint16_t data,
++                     uint16_t count)
++{
++    uint32_t eecd_reg;
++    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_reg = E1000_READ_REG(shared, EECD);
++    eecd_reg &= ~(E1000_EECD_DO | E1000_EECD_DI);
++    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_reg &= ~E1000_EECD_DI;
++
++        if(data & mask)
++            eecd_reg |= E1000_EECD_DI;
++
++        E1000_WRITE_REG(shared, EECD, eecd_reg);
++
++        usec_delay(50);
++
++        e1000_raise_clock(shared, &eecd_reg);
++        e1000_lower_clock(shared, &eecd_reg);
++
++        mask = mask >> 1;
++
++    } while(mask);
++
++    /* We leave the "DI" bit set to "0" when we leave this routine. */
++    eecd_reg &= ~E1000_EECD_DI;
++    E1000_WRITE_REG(shared, EECD, eecd_reg);
++    return;
++}
++
++/******************************************************************************
++ * Shift data bits in from the EEPROM
++ *
++ * shared - Struct containing variables accessed by shared code
++ *****************************************************************************/
++static uint16_t
++e1000_shift_in_bits(struct e1000_shared_adapter *shared)
++{
++    uint32_t eecd_reg;
++    uint32_t i;
++    uint16_t data;
++
++    /* In order to read a register from the EEPROM, we need to shift 16 bits 
++     * in from the EEPROM. Bits are "shifted in" by raising the clock input to
++     * the EEPROM (setting the SK bit), and then reading the value of the "DO"
++     * bit.  During this "shifting in" process the "DI" bit should always be 
++     * clear..
++     */
++
++    eecd_reg = E1000_READ_REG(shared, EECD);
++
++    eecd_reg &= ~(E1000_EECD_DO | E1000_EECD_DI);
++    data = 0;
++
++    for(i = 0; i < 16; i++) {
++        data = data << 1;
++        e1000_raise_clock(shared, &eecd_reg);
++
++        eecd_reg = E1000_READ_REG(shared, EECD);
++
++        eecd_reg &= ~(E1000_EECD_DI);
++        if(eecd_reg & E1000_EECD_DO)
++            data |= 1;
++
++        e1000_lower_clock(shared, &eecd_reg);
++    }
++
++    return data;
++}
++
++/******************************************************************************
++ * Prepares EEPROM for access
++ *
++ * shared - Struct containing variables accessed by shared code
++ *
++ * Lowers EEPROM clock. Clears input pin. Sets the chip select pin. This 
++ * function should be called before issuing a command to the EEPROM.
++ *****************************************************************************/
++static void
++e1000_setup_eeprom(struct e1000_shared_adapter *shared)
++{
++    uint32_t eecd_reg;
++
++    eecd_reg = E1000_READ_REG(shared, EECD);
++
++    /* Clear SK and DI */
++    eecd_reg &= ~(E1000_EECD_SK | E1000_EECD_DI);
++    E1000_WRITE_REG(shared, EECD, eecd_reg);
++
++    /* Set CS */
++    eecd_reg |= E1000_EECD_CS;
++    E1000_WRITE_REG(shared, EECD, eecd_reg);
++    return;
++}
++
++/******************************************************************************
++ * Returns EEPROM to a "standby" state
++ * 
++ * shared - Struct containing variables accessed by shared code
++ *****************************************************************************/
++static void
++e1000_standby_eeprom(struct e1000_shared_adapter *shared)
++{
++    uint32_t eecd_reg;
++
++    eecd_reg = E1000_READ_REG(shared, EECD);
++
++    /* Deselct EEPROM */
++    eecd_reg &= ~(E1000_EECD_CS | E1000_EECD_SK);
++    E1000_WRITE_REG(shared, EECD, eecd_reg);
++    usec_delay(50);
++
++    /* Clock high */
++    eecd_reg |= E1000_EECD_SK;
++    E1000_WRITE_REG(shared, EECD, eecd_reg);
++    usec_delay(50);
++
++    /* Select EEPROM */
++    eecd_reg |= E1000_EECD_CS;
++    E1000_WRITE_REG(shared, EECD, eecd_reg);
++    usec_delay(50);
++
++    /* Clock low */
++    eecd_reg &= ~E1000_EECD_SK;
++    E1000_WRITE_REG(shared, EECD, eecd_reg);
++    usec_delay(50);
++    return;
++}
++
++/******************************************************************************
++ * Raises then lowers the EEPROM's clock pin
++ *
++ * shared - Struct containing variables accessed by shared code
++ *****************************************************************************/
++static void
++e1000_clock_eeprom(struct e1000_shared_adapter *shared)
++{
++    uint32_t eecd_reg;
++
++    eecd_reg = E1000_READ_REG(shared, EECD);
++
++    /* Rising edge of clock */
++    eecd_reg |= E1000_EECD_SK;
++    E1000_WRITE_REG(shared, EECD, eecd_reg);
++    usec_delay(50);
++
++    /* Falling edge of clock */
++    eecd_reg &= ~E1000_EECD_SK;
++    E1000_WRITE_REG(shared, EECD, eecd_reg);
++    usec_delay(50);
++    return;
++}
++
++/******************************************************************************
++ * Terminates a command by lowering the EEPROM's chip select pin
++ *
++ * shared - Struct containing variables accessed by shared code
++ *****************************************************************************/
++static void
++e1000_cleanup_eeprom(struct e1000_shared_adapter *shared)
++{
++    uint32_t eecd_reg;
++
++    eecd_reg = E1000_READ_REG(shared, EECD);
++
++    eecd_reg &= ~(E1000_EECD_CS | E1000_EECD_DI);
++
++    E1000_WRITE_REG(shared, EECD, eecd_reg);
++
++    e1000_clock_eeprom(shared);
++    return;
++}
++
++/******************************************************************************
++ * Waits for the EEPROM to finish the current command.
++ *
++ * shared - Struct containing variables accessed by shared code
++ *
++ * The command is done when the EEPROM's data out pin goes high.
++ *****************************************************************************/
++static uint16_t
++e1000_wait_eeprom_command(struct e1000_shared_adapter *shared)
++{
++    uint32_t eecd_reg;
++    uint32_t i;
++
++
++    /* Toggle the CS line.  This in effect tells to EEPROM to actually execute 
++     * the command in question.
++     */
++    e1000_standby_eeprom(shared);
++
++    /* Now read DO repeatedly until is high (equal to '1').  The EEEPROM 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_reg = E1000_READ_REG(shared, EECD);
++
++        if(eecd_reg & E1000_EECD_DO)
++            return (TRUE);
++
++        usec_delay(50);
++    }
++    ASSERT(0);
++    return (FALSE);
++}
++
++/******************************************************************************
++ * Forces the MAC's flow control settings.
++ * 
++ * shared - 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.
++ *****************************************************************************/
++static void
++e1000_force_mac_fc(struct e1000_shared_adapter *shared)
++{
++    uint32_t ctrl_reg;
++
++    DEBUGFUNC("e1000_force_mac_fc");
++
++    /* Get the current configuration of the Device Control Register */
++    ctrl_reg = E1000_READ_REG(shared, 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 "shared->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 (shared->fc) {
++    case e1000_fc_none:
++        ctrl_reg &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE));
++        break;
++    case e1000_fc_rx_pause:
++        ctrl_reg &= (~E1000_CTRL_TFCE);
++        ctrl_reg |= E1000_CTRL_RFCE;
++        break;
++    case e1000_fc_tx_pause:
++        ctrl_reg &= (~E1000_CTRL_RFCE);
++        ctrl_reg |= E1000_CTRL_TFCE;
++        break;
++    case e1000_fc_full:
++        ctrl_reg |= (E1000_CTRL_TFCE | E1000_CTRL_RFCE);
++        break;
++    default:
++        DEBUGOUT("Flow control param set incorrectly\n");
++        ASSERT(0);
++        break;
++    }
++
++    /* Disable TX Flow Control for 82542 (rev 2.0) */
++    if(shared->mac_type == e1000_82542_rev2_0)
++        ctrl_reg &= (~E1000_CTRL_TFCE);
++
++
++    E1000_WRITE_REG(shared, CTRL, ctrl_reg);
++    return;
++}
++
++/******************************************************************************
++ * Reset the transmit and receive units; mask and clear all interrupts.
++ *
++ * shared - Struct containing variables accessed by shared code
++ *****************************************************************************/
++void
++e1000_adapter_stop(struct e1000_shared_adapter *shared)
++{
++#if DBG
++    uint32_t ctrl_reg;
++#endif
++    uint32_t ctrl_ext_reg;
++    uint32_t icr_reg;
++    uint16_t pci_cmd_word;
++
++    DEBUGFUNC("e1000_shared_adapter_stop");
++
++    /* If we are stopped or resetting exit gracefully and wait to be
++     * started again before accessing the hardware.
++     */
++    if(shared->adapter_stopped) {
++        DEBUGOUT("Exiting because the adapter is already stopped!!!\n");
++        return;
++    }
++
++    /* Set the Adapter Stopped flag so other driver functions stop
++     * touching the Hardware.
++     */
++    shared->adapter_stopped = TRUE;
++
++    /* For 82542 (rev 2.0), disable MWI before issuing a device reset */
++    if(shared->mac_type == e1000_82542_rev2_0) {
++        if(shared->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) {
++            DEBUGOUT("Disabling MWI on 82542 rev 2.0\n");
++
++            pci_cmd_word = shared->pci_cmd_word & ~CMD_MEM_WRT_INVALIDATE;
++
++            e1000_write_pci_cfg(shared, PCI_COMMAND_REGISTER, &pci_cmd_word);
++        }
++    }
++
++    /* Clear interrupt mask to stop board from generating interrupts */
++    DEBUGOUT("Masking off all interrupts\n");
++    E1000_WRITE_REG(shared, 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(shared, RCTL, 0);
++    E1000_WRITE_REG(shared, TCTL, E1000_TCTL_PSP);
++
++    /* The tbi_compatibility_on Flag must be cleared when Rctl is cleared. */
++    shared->tbi_compatibility_on = FALSE;
++
++    msec_delay(10);
++
++    /* Issue a global reset to the MAC.  This will reset the chip's
++     * transmit, receive, DMA, and link units.  It will not effect
++     * the current PCI configuration.  The global reset bit is self-
++     * clearing, and should clear within a microsecond.
++     */
++    DEBUGOUT("Issuing a global reset to MAC\n");
++    E1000_WRITE_REG(shared, CTRL, E1000_CTRL_RST);
++
++    /* Delay a few ms just to allow the reset to complete */
++    msec_delay(10);
++
++#if DBG
++    /* Make sure the self-clearing global reset bit did self clear */
++    ctrl_reg = E1000_READ_REG(shared, CTRL);
++
++    ASSERT(!(ctrl_reg & E1000_CTRL_RST));
++#endif
++
++    /* Force a reload from the EEPROM */
++    ctrl_ext_reg = E1000_READ_REG(shared, CTRL_EXT);
++    ctrl_ext_reg |= E1000_CTRL_EXT_EE_RST;
++    E1000_WRITE_REG(shared, CTRL_EXT, ctrl_ext_reg);
++    msec_delay(2);
++    
++    /* Clear interrupt mask to stop board from generating interrupts */
++    DEBUGOUT("Masking off all interrupts\n");
++    E1000_WRITE_REG(shared, IMC, 0xffffffff);
++
++    /* Clear any pending interrupt events. */
++    icr_reg = E1000_READ_REG(shared, ICR);
++
++    /* If MWI was previously enabled, reenable it. */
++    if(shared->mac_type == e1000_82542_rev2_0) {
++        if(shared->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) {
++            e1000_write_pci_cfg(shared,
++                                PCI_COMMAND_REGISTER, &shared->pci_cmd_word);
++        }
++    }
++    return;
++}
++
++/******************************************************************************
++ * Performs basic configuration of the adapter.
++ *
++ * shared - 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.
++ *****************************************************************************/
++boolean_t
++e1000_init_hw(struct e1000_shared_adapter *shared)
++{
++    uint32_t status_reg;
++    uint32_t i;
++    uint16_t pci_cmd_word;
++    boolean_t status;
++
++    DEBUGFUNC("e1000_init_hw");
++
++    /* Set the Media Type and exit with error if it is not valid. */
++    if(shared->mac_type != e1000_82543) {
++        /* tbi_compatibility is only valid on 82543 */
++        shared->tbi_compatibility_en = FALSE;
++    }
++
++    if(shared->mac_type >= e1000_82543) {
++        status_reg = E1000_READ_REG(shared, STATUS);
++        if(status_reg & E1000_STATUS_TBIMODE) {
++            shared->media_type = e1000_media_type_fiber;
++            /* tbi_compatibility not valid on fiber */
++            shared->tbi_compatibility_en = FALSE;
++        } else {
++            shared->media_type = e1000_media_type_copper;
++        }
++    } else {
++        /* This is an 82542 (fiber only) */
++        shared->media_type = e1000_media_type_fiber;
++    }
++
++    /* Disabling VLAN filtering. */
++    DEBUGOUT("Initializing the IEEE VLAN\n");
++    E1000_WRITE_REG(shared, VET, 0);
++
++    e1000_clear_vfta(shared);
++
++    /* For 82542 (rev 2.0), disable MWI and put the receiver into reset */
++    if(shared->mac_type == e1000_82542_rev2_0) {
++        if(shared->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) {
++            DEBUGOUT("Disabling MWI on 82542 rev 2.0\n");
++            pci_cmd_word = shared->pci_cmd_word & ~CMD_MEM_WRT_INVALIDATE;
++            e1000_write_pci_cfg(shared, PCI_COMMAND_REGISTER, &pci_cmd_word);
++        }
++        E1000_WRITE_REG(shared, RCTL, E1000_RCTL_RST);
++
++        msec_delay(5);
++    }
++
++    /* Setup the receive address. This involves initializing all of the Receive
++     * Address Registers (RARs 0 - 15).
++     */
++    e1000_init_rx_addrs(shared);
++
++    /* For 82542 (rev 2.0), take the receiver out of reset and enable MWI */
++    if(shared->mac_type == e1000_82542_rev2_0) {
++        E1000_WRITE_REG(shared, RCTL, 0);
++
++        msec_delay(1);
++
++        if(shared->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) {
++            e1000_write_pci_cfg(shared,
++                                PCI_COMMAND_REGISTER, &shared->pci_cmd_word);
++        }
++    }
++
++    /* Zero out the Multicast HASH table */
++    DEBUGOUT("Zeroing the MTA\n");
++    for(i = 0; i < E1000_MC_TBL_SIZE; i++)
++        E1000_WRITE_REG_ARRAY(shared, MTA, i, 0);
++
++    /* Call a subroutine to configure the link and setup flow control. */
++    status = e1000_setup_fc_and_link(shared);
++
++    /* Clear all of the statistics registers (clear on read).  It is
++     * important that we do this after we have tried to establish link
++     * because the symbol error count will increment wildly if there
++     * is no link.
++     */
++    e1000_clear_hw_cntrs(shared);
++
++    shared->low_profile = FALSE;
++    if(shared->mac_type == e1000_82544) {
++        if(e1000_read_eeprom(shared, E1000_EEPROM_LED_LOGIC) & 
++           E1000_EEPROM_SWDPIN0)
++            shared->low_profile = TRUE;
++    }
++
++    return (status);
++}
++
++/******************************************************************************
++ * Initializes receive address filters.
++ *
++ * shared - 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
++e1000_init_rx_addrs(struct e1000_shared_adapter *shared)
++{
++    uint32_t i;
++    uint32_t addr_low;
++    uint32_t addr_high;
++
++    DEBUGFUNC("e1000_init_rx_addrs");
++
++    /* Setup the receive address. */
++    DEBUGOUT("Programming MAC Address into RAR[0]\n");
++    addr_low = (shared->mac_addr[0] |
++                (shared->mac_addr[1] << 8) |
++                (shared->mac_addr[2] << 16) | (shared->mac_addr[3] << 24));
++
++    addr_high = (shared->mac_addr[4] |
++                 (shared->mac_addr[5] << 8) | E1000_RAH_AV);
++
++    E1000_WRITE_REG_ARRAY(shared, RA, 0, addr_low);
++    E1000_WRITE_REG_ARRAY(shared, RA, 1, addr_high);
++
++    /* Zero out the other 15 receive addresses. */
++    DEBUGOUT("Clearing RAR[1-15]\n");
++    for(i = 1; i < E1000_RAR_ENTRIES; i++) {
++        E1000_WRITE_REG_ARRAY(shared, RA, (i << 1), 0);
++        E1000_WRITE_REG_ARRAY(shared, RA, ((i << 1) + 1), 0);
++    }
++
++    return;
++}
++
++/******************************************************************************
++ * Updates the MAC's list of multicast addresses.
++ *
++ * shared - 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
++ *
++ * 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
++e1000_mc_addr_list_update(struct e1000_shared_adapter *shared,
++                          uint8_t *mc_addr_list,
++                          uint32_t mc_addr_count,
++                          uint32_t pad)
++{
++    uint32_t hash_value;
++    uint32_t i;
++    uint32_t rar_used_count = 1;        /* RAR[0] is used for our MAC address */
++
++    DEBUGFUNC("e1000_mc_addr_list_update");
++
++    /* Set the new number of MC addresses that we are being requested to use. */
++    shared->num_mc_addrs = mc_addr_count;
++
++    /* Clear RAR[1-15] */
++    DEBUGOUT(" Clearing RAR[1-15]\n");
++    for(i = rar_used_count; i < E1000_RAR_ENTRIES; i++) {
++        E1000_WRITE_REG_ARRAY(shared, RA, (i << 1), 0);
++        E1000_WRITE_REG_ARRAY(shared, RA, ((i << 1) + 1), 0);
++    }
++
++    /* Clear the MTA */
++    DEBUGOUT(" Clearing MTA\n");
++    for(i = 0; i < E1000_NUM_MTA_REGISTERS; i++) {
++        E1000_WRITE_REG_ARRAY(shared, 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 = e1000_hash_mc_addr(shared,
++                                        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 < E1000_RAR_ENTRIES) {
++            e1000_rar_set(shared,
++                          mc_addr_list + (i * (ETH_LENGTH_OF_ADDRESS + pad)),
++                          rar_used_count);
++            rar_used_count++;
++        } else {
++            e1000_mta_set(shared, hash_value);
++        }
++    }
++
++    DEBUGOUT("MC Update Complete\n");
++    return;
++}
++
++/******************************************************************************
++ * Hashes an address to determine its location in the multicast table
++ *
++ * shared - Struct containing variables accessed by shared code
++ * mc_addr - the multicast address to hash 
++ *****************************************************************************/
++uint32_t
++e1000_hash_mc_addr(struct e1000_shared_adapter *shared,
++                   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 (shared->mc_filter_type) {
++        /* [0] [1] [2] [3] [4] [5]
++            * 01  AA  00  12  34  56
++            * LSB                 MSB - According to H/W docs */
++    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.
++ *
++ * shared - Struct containing variables accessed by shared code
++ * hash_value - Multicast address hash value
++ *****************************************************************************/
++void
++e1000_mta_set(struct e1000_shared_adapter *shared,
++              uint32_t hash_value)
++{
++    uint32_t hash_bit, hash_reg;
++    uint32_t mta_reg;
++    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_reg = E1000_READ_REG_ARRAY(shared, MTA, hash_reg);
++
++    mta_reg |= (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((shared->mac_type == e1000_82544) && ((hash_reg & 0x1) == 1)) {
++        temp = E1000_READ_REG_ARRAY(shared, MTA, (hash_reg - 1));
++        E1000_WRITE_REG_ARRAY(shared, MTA, hash_reg, mta_reg);
++        E1000_WRITE_REG_ARRAY(shared, MTA, (hash_reg - 1), temp);
++    } else {
++        E1000_WRITE_REG_ARRAY(shared, MTA, hash_reg, mta_reg);
++    }
++    return;
++}
++
++/******************************************************************************
++ * Puts an ethernet address into a receive address register.
++ *
++ * shared - Struct containing variables accessed by shared code
++ * addr - Address to put into receive address register
++ * index - Receive address register to write
++ *****************************************************************************/
++void
++e1000_rar_set(struct e1000_shared_adapter *shared,
++              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(shared, RA, (index << 1), rar_low);
++    E1000_WRITE_REG_ARRAY(shared, RA, ((index << 1) + 1), rar_high);
++    return;
++}
++
++/******************************************************************************
++ * Writes a value to the specified offset in the VLAN filter table.
++ *
++ * shared - Struct containing variables accessed by shared code
++ * offset - Offset in VLAN filer table to write
++ * value - Value to write into VLAN filter table
++ *****************************************************************************/
++void
++e1000_write_vfta(struct e1000_shared_adapter *shared,
++                 uint32_t offset,
++                 uint32_t value)
++{
++    uint32_t temp;
++
++    if((shared->mac_type == e1000_82544) && ((offset & 0x1) == 1)) {
++        temp = E1000_READ_REG_ARRAY(shared, VFTA, (offset - 1));
++        E1000_WRITE_REG_ARRAY(shared, VFTA, offset, value);
++        E1000_WRITE_REG_ARRAY(shared, VFTA, (offset - 1), temp);
++    } else {
++        E1000_WRITE_REG_ARRAY(shared, VFTA, offset, value);
++    }
++    return;
++}
++
++/******************************************************************************
++ * Clears the VLAN filer table
++ *
++ * shared - Struct containing variables accessed by shared code
++ *****************************************************************************/
++void
++e1000_clear_vfta(struct e1000_shared_adapter *shared)
++{
++    uint32_t offset;
++
++    for(offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++)
++        E1000_WRITE_REG_ARRAY(shared, VFTA, offset, 0);
++    return;
++}
++
++/******************************************************************************
++ * Configures flow control and link settings.
++ * 
++ * shared - 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.
++ *****************************************************************************/
++boolean_t
++e1000_setup_fc_and_link(struct e1000_shared_adapter *shared)
++{
++    uint32_t ctrl_reg;
++    uint32_t eecd_reg;
++    uint32_t ctrl_ext_reg;
++    boolean_t status = TRUE;
++
++    DEBUGFUNC("e1000_setup_fc_and_link");
++
++    /* Read the SWDPIO bits and the ILOS bit out of word 0x0A in the
++     * EEPROM.  Store these bits in a variable that we will later write
++     * to the Device Control Register (CTRL).
++     */
++    eecd_reg = e1000_read_eeprom(shared, EEPROM_INIT_CONTROL1_REG);
++
++    ctrl_reg =
++        (((eecd_reg & EEPROM_WORD0A_SWDPIO) << SWDPIO_SHIFT) |
++         ((eecd_reg & EEPROM_WORD0A_ILOS) << ILOS_SHIFT));
++
++    /* 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.
++     */
++    if(shared->dma_fairness)
++        ctrl_reg |= E1000_CTRL_PRIOR;
++
++    /* 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 shared->fc will
++     * be initialized based on a value in the EEPROM.
++     */
++    eecd_reg = e1000_read_eeprom(shared, EEPROM_INIT_CONTROL2_REG);
++
++    if(shared->fc > e1000_fc_full) {
++        if((eecd_reg & EEPROM_WORD0F_PAUSE_MASK) == 0)
++            shared->fc = e1000_fc_none;
++        else if((eecd_reg & EEPROM_WORD0F_PAUSE_MASK) == EEPROM_WORD0F_ASM_DIR)
++            shared->fc = e1000_fc_tx_pause;
++        else
++            shared->fc = e1000_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.
++     */
++    shared->original_fc = shared->fc;
++
++    if(shared->mac_type == e1000_82542_rev2_0)
++        shared->fc &= (~e1000_fc_tx_pause);
++
++    if((shared->mac_type < e1000_82543) && (shared->report_tx_early == 1))
++        shared->fc &= (~e1000_fc_rx_pause);
++
++    DEBUGOUT1("After fix-ups FlowControl is now = %x\n", shared->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 e1000_setup_pcs_link()
++     * or e1000_phy_setup() is called.
++     */
++    if(shared->mac_type == e1000_82543) {
++        ctrl_ext_reg = ((eecd_reg & EEPROM_WORD0F_SWPDIO_EXT)
++                        << SWDPIO__EXT_SHIFT);
++        E1000_WRITE_REG(shared, CTRL_EXT, ctrl_ext_reg);
++    }
++
++    /* Call the necessary subroutine to configure the link. */
++    if(shared->media_type == e1000_media_type_fiber)
++        status = e1000_setup_pcs_link(shared, ctrl_reg);
++    else
++        status = e1000_phy_setup(shared, ctrl_reg);
++
++    /* 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(shared, FCAL, FLOW_CONTROL_ADDRESS_LOW);
++    E1000_WRITE_REG(shared, FCAH, FLOW_CONTROL_ADDRESS_HIGH);
++    E1000_WRITE_REG(shared, FCT, FLOW_CONTROL_TYPE);
++    E1000_WRITE_REG(shared, FCTTV, shared->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(!(shared->fc & e1000_fc_tx_pause)) {
++        E1000_WRITE_REG(shared, FCRTL, 0);
++        E1000_WRITE_REG(shared, 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(shared->fc_send_xon) {
++            E1000_WRITE_REG(shared, FCRTL,
++                            (shared->fc_low_water | E1000_FCRTL_XONE));
++            E1000_WRITE_REG(shared, FCRTH, shared->fc_high_water);
++        } else {
++            E1000_WRITE_REG(shared, FCRTL, shared->fc_low_water);
++            E1000_WRITE_REG(shared, FCRTH, shared->fc_high_water);
++        }
++    }
++    return (status);
++}
++
++/******************************************************************************
++ * Sets up link for a fiber based adapter
++ *
++ * shared - Struct containing variables accessed by shared code
++ * ctrl_reg - Current value of the device control register
++ *
++ * 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.
++ *****************************************************************************/
++boolean_t
++e1000_setup_pcs_link(struct e1000_shared_adapter *shared,
++                     uint32_t ctrl_reg)
++{
++    uint32_t status_reg;
++    uint32_t tctl_reg;
++    uint32_t txcw_reg = 0;
++    uint32_t i;
++
++    DEBUGFUNC("e1000_setup_pcs_link");
++
++    /* Setup the collsion distance.  Since this is configuring the
++     * TBI it is assumed that we are in Full Duplex.
++     */
++    tctl_reg = E1000_READ_REG(shared, TCTL);
++    i = E1000_FDX_COLLISION_DISTANCE;
++    i <<= E1000_COLD_SHIFT;
++    tctl_reg |= i;
++    E1000_WRITE_REG(shared, TCTL, tctl_reg);
++
++    /* 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.
++     *  other:  No software override.  The flow control configuration
++     *          in the EEPROM is used.
++     */
++    switch (shared->fc) {
++    case e1000_fc_none:        /* 0 */
++        /* Flow control (RX & TX) is completely disabled by a
++         * software over-ride.
++         */
++        txcw_reg = (E1000_TXCW_ANE | E1000_TXCW_FD);
++        break;
++    case e1000_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
++         * we will disable the adapter's ability to send PAUSE
++         * frames.
++         */
++        txcw_reg = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
++        break;
++    case e1000_fc_tx_pause:    /* 2 */
++        /* TX Flow control is enabled, and RX Flow control is
++         * disabled, by a software over-ride.
++         */
++        txcw_reg = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_ASM_DIR);
++        break;
++    case e1000_fc_full:        /* 3 */
++        /* Flow control (both RX and TX) is enabled by a software
++         * over-ride.
++         */
++        txcw_reg = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
++        break;
++    default:
++        /* We should never get here.  The value should be 0-3. */
++        DEBUGOUT("Flow control param set incorrectly\n");
++        ASSERT(0);
++        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(shared, TXCW, txcw_reg);
++    E1000_WRITE_REG(shared, CTRL, ctrl_reg);
++
++    shared->txcw_reg = txcw_reg;
++    msec_delay(1);
++
++    /* If we have a signal 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).
++     */
++    if(!(E1000_READ_REG(shared, CTRL) & E1000_CTRL_SWDPIN1)) {
++
++        DEBUGOUT("Looking for Link\n");
++        for(i = 0; i < (LINK_UP_TIMEOUT / 10); i++) {
++            msec_delay(10);
++            status_reg = E1000_READ_REG(shared, STATUS);
++            if(status_reg & E1000_STATUS_LU)
++                break;
++        }
++
++        if(i == (LINK_UP_TIMEOUT / 10)) {
++            /* AutoNeg failed to achieve a link, so we'll call the
++             * "CheckForLink" routine.  This routine will force the link
++             * up if we have "signal-detect".  This will allow us to
++             * communicate with non-autonegotiating link partners.
++             */
++            DEBUGOUT("Never got a valid link from auto-neg!!!\n");
++
++            shared->autoneg_failed = 1;
++            e1000_check_for_link(shared);
++            shared->autoneg_failed = 0;
++        } else {
++            shared->autoneg_failed = 0;
++            DEBUGOUT("Valid Link Found\n");
++        }
++    } else {
++        DEBUGOUT("No Signal Detected\n");
++    }
++
++    return (TRUE);
++}
++
++/******************************************************************************
++ * Configures flow control settings after link is established
++ * 
++ * shared - 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.
++ *****************************************************************************/
++void
++e1000_config_fc_after_link_up(struct e1000_shared_adapter *shared)
++{
++    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("e1000_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(((shared->media_type == e1000_media_type_fiber)
++        && (shared->autoneg_failed))
++       || ((shared->media_type == e1000_media_type_copper)
++           && (!shared->autoneg))) {
++        e1000_force_mac_fc(shared);
++    }
++
++    /* 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((shared->media_type == e1000_media_type_copper) && shared->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.
++         */
++        mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
++        mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
++
++        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.
++             */
++            mii_nway_adv_reg = e1000_read_phy_reg(shared,
++                                                  PHY_AUTONEG_ADV);
++            mii_nway_lp_ability_reg = e1000_read_phy_reg(shared,
++                                                         PHY_LP_ABILITY);
++
++            /* 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    | e1000_fc_none
++             *   0   |    1    |   0   |   DC    | e1000_fc_none
++             *   0   |    1    |   1   |    0    | e1000_fc_none
++             *   0   |    1    |   1   |    1    | e1000_fc_tx_pause
++             *   1   |    0    |   0   |   DC    | e1000_fc_none
++             *   1   |   DC    |   1   |   DC    | e1000_fc_full
++             *   1   |    1    |   0   |    0    | e1000_fc_none
++             *   1   |    1    |   0   |    1    | e1000_fc_rx_pause
++             *
++             */
++            /* Are both PAUSE bits set to 1?  If so, this implies
++             * 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    | e1000_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(shared->original_fc == e1000_fc_full) {
++                    shared->fc = e1000_fc_full;
++                    DEBUGOUT("Flow Control = FULL.\r\n");
++                } else {
++                    shared->fc = e1000_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    | e1000_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)) {
++                shared->fc = e1000_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    | e1000_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)) {
++                shared->fc = e1000_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(shared->original_fc == e1000_fc_none ||
++                    shared->original_fc == e1000_fc_tx_pause) {
++                shared->fc = e1000_fc_none;
++                DEBUGOUT("Flow Control = NONE.\r\n");
++            } else {
++                shared->fc = e1000_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.
++             */
++            e1000_get_speed_and_duplex(shared, &speed, &duplex);
++
++            if(duplex == HALF_DUPLEX)
++                shared->fc = e1000_fc_none;
++
++            /* Now we call a subroutine to actually force the MAC
++             * controller to use the correct flow control settings.
++             */
++            e1000_force_mac_fc(shared);
++        } else {
++            DEBUGOUT("Copper PHY and Auto Neg has not completed.\r\n");
++        }
++    }
++    return;  
++}
++
++/******************************************************************************
++ * Checks to see if the link status of the hardware has changed.
++ *
++ * shared - Struct containing variables accessed by shared code
++ *
++ * Called by any function that needs to check the link status of the adapter.
++ *****************************************************************************/
++void
++e1000_check_for_link(struct e1000_shared_adapter *shared)
++{
++    uint32_t rxcw_reg;
++    uint32_t ctrl_reg;
++    uint32_t status_reg;
++    uint32_t rctl_reg;
++    uint16_t phy_data;
++    uint16_t lp_capability;
++
++    DEBUGFUNC("e1000_check_for_link");
++
++    ctrl_reg = E1000_READ_REG(shared, CTRL);
++    status_reg = E1000_READ_REG(shared, STATUS);
++    rxcw_reg = E1000_READ_REG(shared, RXCW);
++
++    /* 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(shared->media_type == e1000_media_type_copper
++       && shared->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.
++         */
++        phy_data = e1000_read_phy_reg(shared, PHY_STATUS);
++        phy_data = e1000_read_phy_reg(shared, PHY_STATUS);
++
++        if(phy_data & MII_SR_LINK_STATUS) {
++            shared->get_link_status = FALSE;
++        } else {
++            DEBUGOUT("**** CFL - No link detected. ****\r\n");
++            return;
++        }
++
++        /* If we are forcing speed/duplex, then we simply return since
++         * we have already determined whether we have link or not.
++         */
++        if(!shared->autoneg) {
++            return;
++        }
++
++        switch (shared->phy_id) {
++        case M88E1000_12_PHY_ID:
++        case M88E1000_14_PHY_ID:
++        case M88E1000_I_PHY_ID:
++        case M88E1011_I_PHY_ID:
++            /* 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(shared->mac_type >= e1000_82544) {
++                DEBUGOUT("CFL - Auto-Neg complete.");
++                DEBUGOUT("Configuring Collision Distance.");
++                e1000_config_collision_dist(shared);
++            } else {
++                /* Read the Phy Specific Status register to get the
++                 * resolved speed/duplex settings.  Then call
++                 * e1000_config_mac_to_phy which will retrieve
++                 * PHY register information and configure the MAC to
++                 * equal the negotiated speed/duplex.
++                 */
++                phy_data = e1000_read_phy_reg(shared, 
++                                              M88E1000_PHY_SPEC_STATUS);
++
++                DEBUGOUT1("CFL - Auto-Neg complete.  phy_data = %x\r\n",
++                          phy_data);
++                e1000_config_mac_to_phy(shared, phy_data);
++            }
++
++            /* Configure Flow Control now that Auto-Neg has completed.
++             * We need to first restore the users desired Flow
++             * Control setting since we may have had to re-autoneg
++             * with a different link partner.
++             */
++            e1000_config_fc_after_link_up(shared);
++            break;
++
++        default:
++            DEBUGOUT("CFL - Invalid PHY detected.\r\n");
++
++        } /* end switch statement */
++
++        /* At this point we know that we are on copper, link is up, 
++         * and we are auto-neg'd.  These are pre-conditions for checking
++         * the link parter capabilities register.  We use the link partner
++         * capabilities to determine if TBI Compatibility needs to be turned on
++         * or turned off.  If the link partner advertises any speed in addition
++         * to Gigabit, then we assume that they are GMII-based and TBI 
++         * compatibility is not needed.
++         * If no other speeds are advertised, then we assume the link partner
++         * is TBI-based and we turn on TBI Compatibility.
++         */
++        if(shared->tbi_compatibility_en) {
++            lp_capability = e1000_read_phy_reg(shared, PHY_LP_ABILITY);
++            if(lp_capability & (NWAY_LPAR_10T_HD_CAPS |
++                                NWAY_LPAR_10T_FD_CAPS |
++                                NWAY_LPAR_100TX_HD_CAPS |
++                                NWAY_LPAR_100TX_FD_CAPS |
++                                NWAY_LPAR_100T4_CAPS)) {
++                /* If our link partner advertises below Gig, then they do not
++                 * need the special Tbi Compatibility mode. 
++                 */
++                if(shared->tbi_compatibility_on) {
++                    /* If we previously were in the mode, turn it off, now. */
++                    rctl_reg = E1000_READ_REG(shared, RCTL);
++                    rctl_reg &= ~E1000_RCTL_SBP;
++                    E1000_WRITE_REG(shared, RCTL, rctl_reg);
++                    shared->tbi_compatibility_on = FALSE;
++                }
++            } else {
++                /* If the mode is was previously off, turn it on. 
++                 * For compatibility with a suspected Tbi link partners, 
++                 * we will store bad packets.
++                 * (Certain frames have an additional byte on the end and will 
++                 * look like CRC errors to to the hardware).
++                 */
++                if(!shared->tbi_compatibility_on) {
++                    shared->tbi_compatibility_on = TRUE;
++                    rctl_reg = E1000_READ_REG(shared, RCTL);
++                    rctl_reg |= E1000_RCTL_SBP;
++                    E1000_WRITE_REG(shared, RCTL, rctl_reg);
++                }
++            }
++        }
++    } /* end if e1000_media_type_copper statement */
++    /* If we don't have link (auto-negotiation failed or link partner
++     * cannot auto-negotiate) and the cable is plugged in since we don't
++     * have Loss-Of-Signal (we HAVE a signal) and our link partner is
++     * not trying to AutoNeg with us (we are receiving idles/data
++     * then we need to force our link to connect to a non
++     * auto-negotiating link partner.  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((shared->media_type == e1000_media_type_fiber) &&  /* Fiber PHY */
++            (!(status_reg & E1000_STATUS_LU)) &&        /* no link and    */
++            (!(ctrl_reg & E1000_CTRL_SWDPIN1)) &&       /* we have signal */
++            (!(rxcw_reg & E1000_RXCW_C))) {     /* and rxing idle/data */
++        if(shared->autoneg_failed == 0) {      /* given AutoNeg time */
++            shared->autoneg_failed = 1;
++            return;
++        }
++
++        DEBUGOUT("NOT RXing /C/, disable AutoNeg and force link.\r\n");
++
++        /* Disable auto-negotiation in the TXCW register */
++        E1000_WRITE_REG(shared, TXCW, (shared->txcw_reg & ~E1000_TXCW_ANE));
++
++        /* Force link-up and also force full-duplex. */
++        ctrl_reg = E1000_READ_REG(shared, CTRL);
++        ctrl_reg |= (E1000_CTRL_SLU | E1000_CTRL_FD);
++        E1000_WRITE_REG(shared, CTRL, ctrl_reg);
++
++        /* Configure Flow Control after forcing link up. */
++        e1000_config_fc_after_link_up(shared);
++
++    } else if((shared->media_type == e1000_media_type_fiber) && /* Fiber */
++              (ctrl_reg & E1000_CTRL_SLU) &&    /* we have forced link */
++              (rxcw_reg & E1000_RXCW_C)) {      /* and Rxing /C/ ordered sets */
++        /* If we are forcing link and we are receiving /C/ ordered sets,
++         * then re-enable auto-negotiation in the RXCW register and
++         * disable forced link in the Device Control register in an attempt
++         * to AutoNeg with our link partner.
++         */
++        DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\r\n");
++
++        /* Enable auto-negotiation in the TXCW register and stop
++         * forcing link.
++         */
++        E1000_WRITE_REG(shared, TXCW, shared->txcw_reg);
++
++        E1000_WRITE_REG(shared, CTRL, (ctrl_reg & ~E1000_CTRL_SLU));
++    }
++
++    return;
++}
++
++/******************************************************************************
++ * Clears all hardware statistics counters. 
++ *
++ * shared - Struct containing variables accessed by shared code
++ *****************************************************************************/
++void
++e1000_clear_hw_cntrs(struct e1000_shared_adapter *shared)
++{
++    volatile uint32_t temp_reg;
++
++    DEBUGFUNC("e1000_clear_hw_cntrs");
++
++    /* if we are stopped or resetting exit gracefully */
++    if(shared->adapter_stopped) {
++        DEBUGOUT("Exiting because the adapter is stopped!!!\n");
++        return;
++    }
++
++    temp_reg = E1000_READ_REG(shared, CRCERRS);
++    temp_reg = E1000_READ_REG(shared, SYMERRS);
++    temp_reg = E1000_READ_REG(shared, MPC);
++    temp_reg = E1000_READ_REG(shared, SCC);
++    temp_reg = E1000_READ_REG(shared, ECOL);
++    temp_reg = E1000_READ_REG(shared, MCC);
++    temp_reg = E1000_READ_REG(shared, LATECOL);
++    temp_reg = E1000_READ_REG(shared, COLC);
++    temp_reg = E1000_READ_REG(shared, DC);
++    temp_reg = E1000_READ_REG(shared, SEC);
++    temp_reg = E1000_READ_REG(shared, RLEC);
++    temp_reg = E1000_READ_REG(shared, XONRXC);
++    temp_reg = E1000_READ_REG(shared, XONTXC);
++    temp_reg = E1000_READ_REG(shared, XOFFRXC);
++    temp_reg = E1000_READ_REG(shared, XOFFTXC);
++    temp_reg = E1000_READ_REG(shared, FCRUC);
++    temp_reg = E1000_READ_REG(shared, PRC64);
++    temp_reg = E1000_READ_REG(shared, PRC127);
++    temp_reg = E1000_READ_REG(shared, PRC255);
++    temp_reg = E1000_READ_REG(shared, PRC511);
++    temp_reg = E1000_READ_REG(shared, PRC1023);
++    temp_reg = E1000_READ_REG(shared, PRC1522);
++    temp_reg = E1000_READ_REG(shared, GPRC);
++    temp_reg = E1000_READ_REG(shared, BPRC);
++    temp_reg = E1000_READ_REG(shared, MPRC);
++    temp_reg = E1000_READ_REG(shared, GPTC);
++    temp_reg = E1000_READ_REG(shared, GORCL);
++    temp_reg = E1000_READ_REG(shared, GORCH);
++    temp_reg = E1000_READ_REG(shared, GOTCL);
++    temp_reg = E1000_READ_REG(shared, GOTCH);
++    temp_reg = E1000_READ_REG(shared, RNBC);
++    temp_reg = E1000_READ_REG(shared, RUC);
++    temp_reg = E1000_READ_REG(shared, RFC);
++    temp_reg = E1000_READ_REG(shared, ROC);
++    temp_reg = E1000_READ_REG(shared, RJC);
++    temp_reg = E1000_READ_REG(shared, TORL);
++    temp_reg = E1000_READ_REG(shared, TORH);
++    temp_reg = E1000_READ_REG(shared, TOTL);
++    temp_reg = E1000_READ_REG(shared, TOTH);
++    temp_reg = E1000_READ_REG(shared, TPR);
++    temp_reg = E1000_READ_REG(shared, TPT);
++    temp_reg = E1000_READ_REG(shared, PTC64);
++    temp_reg = E1000_READ_REG(shared, PTC127);
++    temp_reg = E1000_READ_REG(shared, PTC255);
++    temp_reg = E1000_READ_REG(shared, PTC511);
++    temp_reg = E1000_READ_REG(shared, PTC1023);
++    temp_reg = E1000_READ_REG(shared, PTC1522);
++    temp_reg = E1000_READ_REG(shared, MPTC);
++    temp_reg = E1000_READ_REG(shared, BPTC);
++
++    if(shared->mac_type < e1000_82543)
++        return;
++
++    temp_reg = E1000_READ_REG(shared, ALGNERRC);
++    temp_reg = E1000_READ_REG(shared, RXERRC);
++    temp_reg = E1000_READ_REG(shared, TNCRS);
++    temp_reg = E1000_READ_REG(shared, CEXTERR);
++    temp_reg = E1000_READ_REG(shared, TSCTC);
++    temp_reg = E1000_READ_REG(shared, TSCTFC);
++    return;
++}
++
++/******************************************************************************
++ * Detects the current speed and duplex settings of the hardware.
++ *
++ * shared - Struct containing variables accessed by shared code
++ * speed - Speed of the connection
++ * duplex - Duplex setting of the connection
++ *****************************************************************************/
++void
++e1000_get_speed_and_duplex(struct e1000_shared_adapter *shared,
++                           uint16_t *speed,
++                           uint16_t *duplex)
++{
++    uint32_t status_reg;
++#if DBG
++    uint16_t phy_data;
++#endif
++
++    DEBUGFUNC("e1000_get_speed_and_duplex");
++
++    /* If the adapter is stopped we don't have a speed or duplex */
++    if(shared->adapter_stopped) {
++        *speed = 0;
++        *duplex = 0;
++        return;
++    }
++
++    if(shared->mac_type >= e1000_82543) {
++        status_reg = E1000_READ_REG(shared, STATUS);
++        if(status_reg & E1000_STATUS_SPEED_1000) {
++            *speed = SPEED_1000;
++            DEBUGOUT("1000 Mbs, ");
++        } else if(status_reg & E1000_STATUS_SPEED_100) {
++            *speed = SPEED_100;
++            DEBUGOUT("100 Mbs, ");
++        } else {
++            *speed = SPEED_10;
++            DEBUGOUT("10 Mbs, ");
++        }
++
++        if(status_reg & 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;
++    }
++
++#if DBG
++    if(shared->phy_id == M88E1000_12_PHY_ID ||
++       shared->phy_id == M88E1000_14_PHY_ID ||
++       shared->phy_id == M88E1000_I_PHY_ID  ||
++       shared->phy_id == M88E1011_I_PHY_ID) {
++        /* read the phy specific status register */
++        phy_data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_STATUS);
++        DEBUGOUT1("M88E1000 Phy Specific Status Reg contents = %x\n", phy_data);
++        phy_data = e1000_read_phy_reg(shared, PHY_STATUS);
++        DEBUGOUT1("Phy MII Status Reg contents = %x\n", phy_data);
++        DEBUGOUT1("Device Status Reg contents = %x\n", 
++                  E1000_READ_REG(shared, STATUS));
++    }
++#endif
++    return;
++}
++
++/******************************************************************************
++ * Reads a 16 bit word from the EEPROM.
++ *
++ * shared - Struct containing variables accessed by shared code
++ * offset - offset of 16 bit word in the EEPROM to read
++ *****************************************************************************/
++uint16_t
++e1000_read_eeprom(struct e1000_shared_adapter *shared,
++                  uint16_t offset)
++{
++    boolean_t large_eeprom = FALSE;
++    uint16_t data;
++    uint32_t eecd_reg;
++    uint32_t tmp = 0;
++
++    if((shared->mac_type > e1000_82544) &&
++       (E1000_READ_REG(shared, EECD) & E1000_EECD_SIZE)) large_eeprom = TRUE;
++    
++    /* Request EEPROM Access */
++    if(shared->mac_type > e1000_82544) {
++        E1000_WRITE_REG(shared, EECD, (uint32_t) E1000_EECD_REQ);
++        eecd_reg = E1000_READ_REG(shared, EECD);
++        while((!(eecd_reg & E1000_EECD_GNT)) && (tmp < 100)) {
++            tmp++;
++            usec_delay(5);
++            eecd_reg = E1000_READ_REG(shared, EECD);
++        }
++        if(!(eecd_reg & E1000_EECD_GNT)) return(FALSE);
++    }
++
++    /*  Prepare the EEPROM for reading  */
++    e1000_setup_eeprom(shared);
++
++    /*  Send the READ command (opcode + addr)  */
++    e1000_shift_out_bits(shared, EEPROM_READ_OPCODE, 3);
++    /* If we have a 256 word EEPROM, there are 8 address bits
++     * if we have a 64 word EEPROM, there are 6 address bits
++     */
++    if(large_eeprom) 
++        e1000_shift_out_bits(shared, offset, 8);
++    else
++        e1000_shift_out_bits(shared, offset, 6);
++
++    /* Read the data */
++    data = e1000_shift_in_bits(shared);
++
++    /* End this read operation */
++    e1000_standby_eeprom(shared);
++
++    /* Stop requestiong EEPROM access */
++    if(shared->mac_type > e1000_82544)
++        E1000_WRITE_REG(shared, EECD, (uint32_t) 0);
++
++    return (data);
++}
++
++/******************************************************************************
++ * Verifies that the EEPROM has a valid checksum
++ * 
++ * shared - 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.
++ *****************************************************************************/
++boolean_t
++e1000_validate_eeprom_checksum(struct e1000_shared_adapter *shared)
++{
++    uint16_t checksum = 0;
++    uint16_t i;
++
++    for(i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++)
++        checksum += e1000_read_eeprom(shared, i);
++
++    if(checksum == (uint16_t) EEPROM_SUM)
++        return (TRUE);
++    else
++        return (FALSE);
++}
++
++/******************************************************************************
++ * Calculates the EEPROM checksum and writes it to the EEPROM
++ *
++ * shared - 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.
++ *****************************************************************************/
++void
++e1000_update_eeprom_checksum(struct e1000_shared_adapter *shared)
++{
++    uint16_t checksum = 0;
++    uint16_t i;
++
++    for(i = 0; i < EEPROM_CHECKSUM_REG; i++)
++        checksum += e1000_read_eeprom(shared, i);
++
++    checksum = (uint16_t) EEPROM_SUM - checksum;
++
++    e1000_write_eeprom(shared, EEPROM_CHECKSUM_REG, checksum);
++    return;
++}
++
++/******************************************************************************
++ * Writes a 16 bit word to a given offset in the EEPROM.
++ *
++ * shared - Struct containing variables accessed by shared code
++ * offset - offset within the EEPROM to be written to
++ * data - 16 bit word to be writen to the EEPROM
++ *
++ * If e1000_update_eeprom_checksum is not called after this function, the 
++ * EEPROM will most likely contain an invalid checksum.
++ *****************************************************************************/
++boolean_t
++e1000_write_eeprom(struct e1000_shared_adapter *shared,
++                   uint16_t offset,
++                   uint16_t data)
++{
++    boolean_t large_eeprom = FALSE;
++    uint32_t eecd_reg;
++    uint32_t tmp = 0;
++
++    if((shared->mac_type > e1000_82544) &&
++       (E1000_READ_REG(shared, EECD) & E1000_EECD_SIZE)) large_eeprom = TRUE;
++    
++    /* Request EEPROM Access */
++    if(shared->mac_type > e1000_82544) {
++        E1000_WRITE_REG(shared, EECD, (uint32_t) E1000_EECD_REQ);
++        eecd_reg = E1000_READ_REG(shared, EECD);
++        while((!(eecd_reg & E1000_EECD_GNT)) && (tmp < 100)) {
++            tmp++;
++            usec_delay(5);
++            eecd_reg = E1000_READ_REG(shared, EECD);
++        }
++        if(!(eecd_reg & E1000_EECD_GNT)) return(FALSE);
++    }
++
++    /* Prepare the EEPROM for writing  */
++    e1000_setup_eeprom(shared);
++
++    /* Send the 9-bit (or 11-bit on large EEPROM) EWEN (write enable) 
++     * command to the EEPROM (5-bit opcode plus 4/6-bit dummy).
++     * This puts the EEPROM into write/erase mode. 
++     */
++    e1000_shift_out_bits(shared, EEPROM_EWEN_OPCODE, 5);
++    if(large_eeprom) 
++        e1000_shift_out_bits(shared, 0, 6);
++    else
++        e1000_shift_out_bits(shared, 0, 4);
++
++    /* Prepare the EEPROM */
++    e1000_standby_eeprom(shared);
++
++    /* Send the Write command (3-bit opcode + addr) */
++    e1000_shift_out_bits(shared, EEPROM_WRITE_OPCODE, 3);
++    /* If we have a 256 word EEPROM, there are 8 address bits
++     * if we have a 64 word EEPROM, there are 6 address bits
++     */
++    if(large_eeprom) 
++        e1000_shift_out_bits(shared, offset, 8);
++    else
++        e1000_shift_out_bits(shared, offset, 6);
++
++    /* Send the data */
++    e1000_shift_out_bits(shared, data, 16);
++    e1000_wait_eeprom_command(shared);
++
++    /* Recover from write */
++    e1000_standby_eeprom(shared);
++
++    /* Send the 9-bit  (or 11-bit on large EEPROM) EWDS (write disable) 
++     * command to the EEPROM (5-bit opcode plus 4/6-bit dummy).
++     * This takes the EEPROM out of write/erase mode.
++     */
++    e1000_shift_out_bits(shared, EEPROM_EWDS_OPCODE, 5);
++    if(large_eeprom) 
++        e1000_shift_out_bits(shared, 0, 6);
++    else
++        e1000_shift_out_bits(shared, 0, 4);
++
++    /* Done with writing */
++    e1000_cleanup_eeprom(shared);
++
++    /* Stop requestiong EEPROM access */
++    if(shared->mac_type > e1000_82544)
++        E1000_WRITE_REG(shared, EECD, (uint32_t) 0);
++
++    return (TRUE);
++}
++
++/******************************************************************************
++ * Reads the adapter's part number from the EEPROM
++ *
++ * shared - Struct containing variables accessed by shared code
++ * part_num - Adapter's part number
++ *****************************************************************************/
++boolean_t
++e1000_read_part_num(struct e1000_shared_adapter *shared,
++                    uint32_t *part_num)
++{
++    uint16_t eeprom_word;
++
++    DEBUGFUNC("e1000_read_part_num");
++
++    /* Don't read the EEPROM if we are stopped */
++    if(shared->adapter_stopped) {
++        *part_num = 0;
++        return (FALSE);
++    }
++
++    /* Get word 0 from EEPROM */
++    eeprom_word = e1000_read_eeprom(shared, (uint16_t) (EEPROM_PBA_BYTE_1));
++
++    DEBUGOUT("Read first part number word\n");
++
++    /* Save word 0 in upper half is PartNumber */
++    *part_num = (uint32_t) eeprom_word;
++    *part_num = *part_num << 16;
++
++    /* Get word 1 from EEPROM */
++    eeprom_word =
++        e1000_read_eeprom(shared, (uint16_t) (EEPROM_PBA_BYTE_1 + 1));
++
++    DEBUGOUT("Read second part number word\n");
++
++    /* Save word 1 in lower half of PartNumber */
++    *part_num |= eeprom_word;
++
++    /* read a valid part number */
++    return (TRUE);
++}
++
++/******************************************************************************
++ * Turns on the software controllable LED
++ *
++ * shared - Struct containing variables accessed by shared code
++ *****************************************************************************/
++void
++e1000_led_on(struct e1000_shared_adapter *shared)
++{
++    uint32_t ctrl_reg;
++
++    /* if we're stopped don't touch the hardware */
++    if(shared->adapter_stopped)
++        return;
++
++    /* Read the content of the device control reg */
++    ctrl_reg = E1000_READ_REG(shared, CTRL);
++
++    /* Set the LED control pin to an output */
++    ctrl_reg |= E1000_CTRL_SWDPIO0;
++
++    /* Drive it high on normal boards, low on low profile boards */
++    if(shared->low_profile)
++        ctrl_reg &= ~E1000_CTRL_SWDPIN0;
++    else
++        ctrl_reg |= E1000_CTRL_SWDPIN0;
++
++    E1000_WRITE_REG(shared, CTRL, ctrl_reg);
++    return;
++}
++
++/******************************************************************************
++ * Turns off the software controllable LED
++ *
++ * shared - Struct containing variables accessed by shared code
++ *****************************************************************************/
++void
++e1000_led_off(struct e1000_shared_adapter *shared)
++{
++    uint32_t ctrl_reg;
++
++    /* if we're stopped don't touch the hardware */
++    if(shared->adapter_stopped)
++        return;
++
++    /* Read the content of the device control reg */
++    ctrl_reg = E1000_READ_REG(shared, CTRL);
++
++    /* Set the LED control pin to an output */
++    ctrl_reg |= E1000_CTRL_SWDPIO0;
++
++    /* Drive it low on normal boards, high on low profile boards */
++    if(shared->low_profile)
++        ctrl_reg |= E1000_CTRL_SWDPIN0;
++    else
++        ctrl_reg &= ~E1000_CTRL_SWDPIN0;
++
++    /* Write the device control reg. back  */
++    E1000_WRITE_REG(shared, CTRL, ctrl_reg);
++    return;
++}
++
++/******************************************************************************
++ * Adjusts the statistic counters when a frame is accepted by TBI_ACCEPT
++ * 
++ * shared - 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
++ *****************************************************************************/
++uint32_t
++e1000_tbi_adjust_stats(struct e1000_shared_adapter *shared,
++                       struct e1000_shared_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 == shared->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++;
++    }
++    return frame_len;
++}
++
++/******************************************************************************
++ * Gets the current PCI bus type, speed, and width of the hardware
++ *
++ * shared - Struct containing variables accessed by shared code
++ *****************************************************************************/
++void
++e1000_get_bus_info(struct e1000_shared_adapter *shared)
++{
++    uint32_t status_reg;
++
++    if(shared->mac_type < e1000_82543) {
++        shared->bus_type = e1000_bus_type_unknown;
++        shared->bus_speed = e1000_bus_speed_unknown;
++        shared->bus_width = e1000_bus_width_unknown;
++        return;
++    }
++
++    status_reg = E1000_READ_REG(shared, STATUS);
++
++    shared->bus_type = (status_reg & E1000_STATUS_PCIX_MODE) ?
++        e1000_bus_type_pcix : e1000_bus_type_pci;
++
++    if(shared->bus_type == e1000_bus_type_pci) {
++        shared->bus_speed = (status_reg & E1000_STATUS_PCI66) ?
++            e1000_bus_speed_66 : e1000_bus_speed_33;
++    } else {
++        switch (status_reg & E1000_STATUS_PCIX_SPEED) {
++        case E1000_STATUS_PCIX_SPEED_66:
++            shared->bus_speed = e1000_bus_speed_66;
++            break;
++        case E1000_STATUS_PCIX_SPEED_100:
++            shared->bus_speed = e1000_bus_speed_100;
++            break;
++        case E1000_STATUS_PCIX_SPEED_133:
++            shared->bus_speed = e1000_bus_speed_133;
++            break;
++        default:
++            shared->bus_speed = e1000_bus_speed_reserved;
++            break;
++        }
++    }
++
++    shared->bus_width = (status_reg & E1000_STATUS_BUS64) ?
++        e1000_bus_width_64 : e1000_bus_width_32;
++
++    return;
++}
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ linux-2.4.18-14-root/drivers/e1000/e1000_mac.h     2003-01-02 16:22:31.000000000 -0800
+@@ -0,0 +1,1381 @@
++/*******************************************************************************
++
++  This software program is available to you under a choice of one of two 
++  licenses. You may choose to be licensed under either the GNU General Public 
++  License (GPL) Version 2, June 1991, available at 
++  http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the 
++  text of which follows:
++  
++  Recipient has requested a license and Intel Corporation ("Intel") is willing
++  to grant a license for the software entitled Linux Base Driver for the 
++  Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided
++  by Intel Corporation. The following definitions apply to this license:
++  
++  "Licensed Patents" means patent claims licensable by Intel Corporation which 
++  are necessarily infringed by the use of sale of the Software alone or when 
++  combined with the operating system referred to below.
++  
++  "Recipient" means the party to whom Intel delivers this Software.
++  
++  "Licensee" means Recipient and those third parties that receive a license to 
++  any operating system available under the GNU Public License version 2.0 or 
++  later.
++  
++  Copyright (c) 1999 - 2002 Intel Corporation.
++  All rights reserved.
++  
++  The license is provided to Recipient and Recipient's Licensees under the 
++  following terms.
++  
++  Redistribution and use in source and binary forms of the Software, with or 
++  without modification, are permitted provided that the following conditions 
++  are met:
++  
++  Redistributions of source code of the Software may retain the above 
++  copyright notice, this list of conditions and the following disclaimer.
++  
++  Redistributions in binary form of the Software may reproduce the above 
++  copyright notice, this list of conditions and the following disclaimer in 
++  the documentation and/or materials provided with the distribution.
++  
++  Neither the name of Intel Corporation nor the names of its contributors 
++  shall be used to endorse or promote products derived from this Software 
++  without specific prior written permission.
++  
++  Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, 
++  royalty-free patent license under Licensed Patents to make, use, sell, offer 
++  to sell, import and otherwise transfer the Software, if any, in source code 
++  and object code form. This license shall include changes to the Software 
++  that are error corrections or other minor changes to the Software that do 
++  not add functionality or features when the Software is incorporated in any 
++  version of an operating system that has been distributed under the GNU 
++  General Public License 2.0 or later. This patent license shall apply to the 
++  combination of the Software and any operating system licensed under the GNU 
++  Public License version 2.0 or later if, at the time Intel provides the 
++  Software to Recipient, such addition of the Software to the then publicly 
++  available versions of such operating systems available under the GNU Public 
++  License version 2.0 or later (whether in gold, beta or alpha form) causes 
++  such combination to be covered by the Licensed Patents. The patent license 
++  shall not apply to any other combinations which include the Software. NO 
++  hardware per se is licensed hereunder.
++  
++  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 MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
++  ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY 
++  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
++  (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
++  ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) 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.
++
++*******************************************************************************/
++
++/* e1000_mac.h
++ * Structures, enums, and macros for the MAC
++ */
++
++#ifndef _E1000_MAC_H_
++#define _E1000_MAC_H_
++
++#include "e1000_osdep.h"
++
++/* Forward declarations of structures used by the shared code */
++struct e1000_shared_adapter;
++struct e1000_shared_stats;
++
++/* Enumerated types specific to the e1000 hardware */
++/* Media Access Controlers */
++typedef enum {
++    e1000_82542_rev2_0 = 0,
++    e1000_82542_rev2_1,
++    e1000_82543,
++    e1000_82544,
++    e1000_82540,
++    e1000_num_macs
++} e1000_mac_type;
++
++/* Media Types */
++typedef enum {
++    e1000_media_type_copper = 0,
++    e1000_media_type_fiber = 1,
++    e1000_num_media_types
++} e1000_media_type;
++
++typedef enum {
++    e1000_10_half = 0,
++    e1000_10_full = 1,
++    e1000_100_half = 2,
++    e1000_100_full = 3
++} e1000_speed_duplex_type;
++
++/* Flow Control Settings */
++typedef enum {
++    e1000_fc_none = 0,
++    e1000_fc_rx_pause = 1,
++    e1000_fc_tx_pause = 2,
++    e1000_fc_full = 3,
++    e1000_fc_default = 0xFF
++} e1000_fc_type;
++
++/* PCI bus types */
++typedef enum {
++    e1000_bus_type_unknown = 0,
++    e1000_bus_type_pci,
++    e1000_bus_type_pcix
++} e1000_bus_type;
++
++/* PCI bus speeds */
++typedef enum {
++    e1000_bus_speed_unknown = 0,
++    e1000_bus_speed_33,
++    e1000_bus_speed_66,
++    e1000_bus_speed_100,
++    e1000_bus_speed_133,
++    e1000_bus_speed_reserved
++} e1000_bus_speed;
++
++/* PCI bus widths */
++typedef enum {
++    e1000_bus_width_unknown = 0,
++    e1000_bus_width_32,
++    e1000_bus_width_64
++} e1000_bus_width;
++
++
++
++/* Function prototypes */
++/* Setup */
++void e1000_adapter_stop(struct e1000_shared_adapter *shared);
++boolean_t e1000_init_hw(struct e1000_shared_adapter *shared);
++void e1000_init_rx_addrs(struct e1000_shared_adapter *shared);
++
++/* Filters (multicast, vlan, receive) */
++void e1000_mc_addr_list_update(struct e1000_shared_adapter *shared, uint8_t * mc_addr_list, uint32_t mc_addr_count, uint32_t pad);
++uint32_t e1000_hash_mc_addr(struct e1000_shared_adapter *shared, uint8_t * mc_addr);
++void e1000_mta_set(struct e1000_shared_adapter *shared, uint32_t hash_value);
++void e1000_rar_set(struct e1000_shared_adapter *shared, uint8_t * mc_addr, uint32_t rar_index);
++void e1000_write_vfta(struct e1000_shared_adapter *shared, uint32_t offset, uint32_t value);
++void e1000_clear_vfta(struct e1000_shared_adapter *shared);
++
++/* Link layer setup functions */
++boolean_t e1000_setup_fc_and_link(struct e1000_shared_adapter *shared);
++boolean_t e1000_setup_pcs_link(struct e1000_shared_adapter *shared, uint32_t dev_ctrl_reg);
++void e1000_config_fc_after_link_up(struct e1000_shared_adapter *shared);
++void e1000_check_for_link(struct e1000_shared_adapter *shared);
++void e1000_get_speed_and_duplex(struct e1000_shared_adapter *shared, uint16_t * speed, uint16_t * duplex);
++
++/* EEPROM Functions */
++uint16_t e1000_read_eeprom(struct e1000_shared_adapter *shared, uint16_t reg);
++boolean_t e1000_validate_eeprom_checksum(struct e1000_shared_adapter *shared);
++void e1000_update_eeprom_checksum(struct e1000_shared_adapter *shared);
++boolean_t e1000_write_eeprom(struct e1000_shared_adapter *shared, uint16_t reg, uint16_t data);
++
++/* Everything else */
++void e1000_clear_hw_cntrs(struct e1000_shared_adapter *shared);
++boolean_t e1000_read_part_num(struct e1000_shared_adapter *shared, uint32_t * part_num);
++void e1000_led_on(struct e1000_shared_adapter *shared);
++void e1000_led_off(struct e1000_shared_adapter *shared);
++void e1000_get_bus_info(struct e1000_shared_adapter *shared);
++uint32_t e1000_tbi_adjust_stats(struct e1000_shared_adapter *shared, struct e1000_shared_stats *stats, uint32_t frame_len, uint8_t * mac_addr);
++void e1000_write_pci_cfg(struct e1000_shared_adapter *shared, uint32_t reg, uint16_t * value);
++
++/* 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 NUM_DEV_IDS 8
++
++#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 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_PACKET_SIZE 1514 /* Without FCS */
++#define MINIMUM_ETHERNET_PACKET_SIZE 60   /* Without FCS */
++#define CRC_LENGTH                   4
++#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)
++
++/* The 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 16
++
++#define MIN_NUMBER_OF_DESCRIPTORS 8
++#define MAX_NUMBER_OF_DESCRIPTORS 0xFFF8
++
++/* Receive Descriptor */
++struct e1000_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 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_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_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 0x000D  /* Priority is in upper 3 of 16 */
++#define E1000_RXD_SPC_CFI_MASK  0x1000  /* CFI is bit 12 */
++#define E1000_RXD_SPC_CFI_SHIFT 0x000C  /* CFI is bit 12 */
++
++/* 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)
++
++/* Transmit Descriptor */
++struct e1000_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 e1000_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 e1000_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 e1000_rar {
++    volatile uint32_t low;      /* receive address low */
++    volatile uint32_t high;     /* receive address high */
++};
++
++/* The number of entries in the Multicast Table Array (MTA). */
++#define E1000_NUM_MTA_REGISTERS 128
++
++/* IPv4 Address Table Entry */
++struct e1000_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 e1000_ipv6_at_entry {
++    volatile uint8_t ipv6_addr[16];
++};
++
++/* Flexible Filter Length Table Entry */
++struct e1000_fflt_entry {
++    volatile uint32_t length;   /* Flexible Filter Length (RW) */
++    volatile uint32_t reserved;
++};
++
++/* Flexible Filter Mask Table Entry */
++struct e1000_ffmt_entry {
++    volatile uint32_t mask;     /* Flexible Filter Mask (RW) */
++    volatile uint32_t reserved;
++};
++
++/* Flexible Filter Value Table Entry */
++struct e1000_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_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_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_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_LEDCTL   0x00E00  /* LED Control - RW */
++#define E1000_PBA      0x01000  /* Packet Buffer Allocation - RW */
++#define E1000_FCRTL    0x02160  /* Flow Control Receive Threshold Low - RW */
++#define E1000_FCRTH    0x02168  /* Flow Control Receive Threshold High - 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_TXDMAC   0x03000  /* TX DMA Control - 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_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_RXCSUM   0x05000  /* RX Checksum Control - RW */
++#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_FFMT     0x09000  /* Flexible Filter Mask Table - RW Array */
++#define E1000_FFVT     0x09800  /* Flexible Filter Value Table - RW Array */
++
++/* 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_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_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_VFTA     0x00600
++#define E1000_82542_LEDCTL   E1000_LEDCTL
++#define E1000_82542_PBA      E1000_PBA
++#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_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_FFMT     E1000_FFMT
++#define E1000_82542_FFVT     E1000_FFVT
++
++/* Statistics counters collected by the MAC */
++struct e1000_shared_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;
++};
++
++/* Structure containing variables used by the shared code (e1000_mac.c and 
++ * e1000_phy.c)
++ */
++struct e1000_shared_adapter {
++    uint8_t *hw_addr;
++    e1000_mac_type mac_type;
++    e1000_media_type media_type;
++    void *back;
++    e1000_fc_type fc;
++    e1000_bus_speed bus_speed;
++    e1000_bus_width bus_width;
++    e1000_bus_type bus_type;
++    uint32_t phy_id;
++    uint32_t phy_addr;
++    uint32_t original_fc;
++    uint32_t txcw_reg;
++    uint32_t autoneg_failed;
++    uint32_t max_frame_size;
++    uint32_t min_frame_size;
++    uint32_t mc_filter_type;
++    uint32_t num_mc_addrs;
++    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 device_id;
++    uint16_t vendor_id;
++    uint16_t subsystem_id;
++    uint16_t subsystem_vendor_id;
++    uint8_t revision_id;
++    boolean_t disable_polarity_correction;
++    boolean_t get_link_status;
++    boolean_t tbi_compatibility_en;
++    boolean_t tbi_compatibility_on;
++    boolean_t adapter_stopped;
++    boolean_t fc_send_xon;
++    boolean_t report_tx_early;
++    boolean_t low_profile;
++    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];
++};
++
++
++#define E1000_EEPROM_SWDPIN0   0x0001   /* SWDPIN 0 EEPROM Value */
++#define E1000_EEPROM_LED_LOGIC 0x0020   /* Led Logic Word */
++
++/* 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_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_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_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_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_SIZE      0x00000200 /* EEPROM Size (0=64 word 1=256 word) */
++#define E1000_EECD_REQ       0x00000040 /* EEPROM Access Request */
++#define E1000_EECD_GNT       0x00000080 /* EEPROM Access Grant */
++#define E1000_EECD_PRES      0x00000100 /* EEPROM Present */
++
++/* 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 */
++
++/* 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
++
++/* 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_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_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_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
++
++/* 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
++
++/* 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
++
++/* 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
++
++/* 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_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 */
++
++/* 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 */
++
++/* 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 */
++
++/* 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 */
++
++/* 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 */
++
++/* 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 */
++
++/* 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_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_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_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 */
++
++/* Wake Up Packet Length */
++#define E1000_WUPL_LENGTH_MASK 0x0FFF   /* Only the lower 12 bits are valid */
++
++#define E1000_MDALIGN          4096
++
++/* EEPROM Commands */
++#define EEPROM_READ_OPCODE  0x6  /* EERPOM read opcode */
++#define EEPROM_WRITE_OPCODE 0x5  /* EERPOM write opcode */
++#define EEPROM_ERASE_OPCODE 0x7  /* EERPOM erase opcode */
++#define EEPROM_EWEN_OPCODE  0x13 /* EERPOM erase/write enable */
++#define EEPROM_EWDS_OPCODE  0x10 /* EERPOM erast/write disable */
++
++/* EEPROM Word Offsets */
++#define EEPROM_INIT_CONTROL1_REG 0x000A
++#define EEPROM_INIT_CONTROL2_REG 0x000F
++#define EEPROM_FLASH_VERSION     0x0032
++#define EEPROM_CHECKSUM_REG      0x003F
++
++/* 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
++
++/* EEPROM Map Sizes (Byte Counts) */
++#define PBA_SIZE 4
++
++/* Collision related configuration parameters */
++#define E1000_COLLISION_THRESHOLD       16
++#define E1000_CT_SHIFT                  4
++#define E1000_FDX_COLLISION_DISTANCE    64
++#define E1000_HDX_COLLISION_DISTANCE    64
++#define E1000_GB_HDX_COLLISION_DISTANCE 512
++#define E1000_COLD_SHIFT                12
++
++/* The 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
++
++/* PBA constants */
++#define E1000_PBA_16K 0x0010    /* 16KB, default TX allocation */
++#define E1000_PBA_24K 0x0018
++#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 */
++
++
++/* The number of bits that we need to shift right to move the "pause"
++ * bits from the EEPROM (bits 13:12) to the "pause" (bits 8:7) field
++ * in the TXCW register 
++ */
++#define PAUSE_SHIFT 5
++
++/* The number of bits that we need to shift left to move the "SWDPIO"
++ * bits from the EEPROM (bits 8:5) to the "SWDPIO" (bits 25:22) field
++ * in the CTRL register 
++ */
++#define SWDPIO_SHIFT 17
++
++/* The number of bits that we need to shift left to move the "SWDPIO_EXT"
++ * bits from the EEPROM word F (bits 7:4) to the bits 11:8 of The
++ * Extended CTRL register.
++ * in the CTRL register 
++ */
++#define SWDPIO__EXT_SHIFT 4
++
++/* The number of bits that we need to shift left to move 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)
++
++/* The number of milliseconds we wait for auto-negotiation to complete */
++#define LINK_UP_TIMEOUT             500
++
++#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 e1000_shared_adapter 
++ *      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;
++ *      e1000_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)))))
++
++
++#endif /* _E1000_MAC_H_ */
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ linux-2.4.18-14-root/drivers/e1000/e1000_main.c    2003-01-02 16:22:31.000000000 -0800
+@@ -0,0 +1,3780 @@
++/*******************************************************************************
++
++  This software program is available to you under a choice of one of two 
++  licenses. You may choose to be licensed under either the GNU General Public 
++  License (GPL) Version 2, June 1991, available at 
++  http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the 
++  text of which follows:
++  
++  Recipient has requested a license and Intel Corporation ("Intel") is willing
++  to grant a license for the software entitled Linux Base Driver for the 
++  Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided
++  by Intel Corporation. The following definitions apply to this license:
++  
++  "Licensed Patents" means patent claims licensable by Intel Corporation which 
++  are necessarily infringed by the use of sale of the Software alone or when 
++  combined with the operating system referred to below.
++  
++  "Recipient" means the party to whom Intel delivers this Software.
++  
++  "Licensee" means Recipient and those third parties that receive a license to 
++  any operating system available under the GNU Public License version 2.0 or 
++  later.
++  
++  Copyright (c) 1999 - 2002 Intel Corporation.
++  All rights reserved.
++  
++  The license is provided to Recipient and Recipient's Licensees under the 
++  following terms.
++  
++  Redistribution and use in source and binary forms of the Software, with or 
++  without modification, are permitted provided that the following conditions 
++  are met:
++  
++  Redistributions of source code of the Software may retain the above 
++  copyright notice, this list of conditions and the following disclaimer.
++  
++  Redistributions in binary form of the Software may reproduce the above 
++  copyright notice, this list of conditions and the following disclaimer in 
++  the documentation and/or materials provided with the distribution.
++  
++  Neither the name of Intel Corporation nor the names of its contributors 
++  shall be used to endorse or promote products derived from this Software 
++  without specific prior written permission.
++  
++  Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, 
++  royalty-free patent license under Licensed Patents to make, use, sell, offer 
++  to sell, import and otherwise transfer the Software, if any, in source code 
++  and object code form. This license shall include changes to the Software 
++  that are error corrections or other minor changes to the Software that do 
++  not add functionality or features when the Software is incorporated in any 
++  version of an operating system that has been distributed under the GNU 
++  General Public License 2.0 or later. This patent license shall apply to the 
++  combination of the Software and any operating system licensed under the GNU 
++  Public License version 2.0 or later if, at the time Intel provides the 
++  Software to Recipient, such addition of the Software to the then publicly 
++  available versions of such operating systems available under the GNU Public 
++  License version 2.0 or later (whether in gold, beta or alpha form) causes 
++  such combination to be covered by the Licensed Patents. The patent license 
++  shall not apply to any other combinations which include the Software. NO 
++  hardware per se is licensed hereunder.
++  
++  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 MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
++  ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY 
++  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
++  (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
++  ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) 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.
++
++*******************************************************************************/
++
++
++#define __E1000_MAIN__
++#ifdef IANS
++#define _IANS_MAIN_MODULE_C_
++#endif
++#include "e1000.h"
++
++/* Driver name string */
++char e1000_driver_name[] = "e1000";
++
++/* Driver ID string, displayed when loading */
++char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver";
++
++/* Driver version */
++char e1000_driver_version[] = "4.1.7";
++
++/* Copyright string, displayed when loading */
++char e1000_copyright[] = "Copyright (c) 1999-2002 Intel Corporation.";
++
++/* Linked list of board private structures for all NICs found */
++struct e1000_adapter *e1000_adapter_list = NULL;
++
++/* e1000_strings - PCI Device ID Table
++ *
++ * for selecting devices to load on
++ * private driver_data field (last one) stores an index
++ * into e1000_strings
++ * Wildcard entries (PCI_ANY_ID) should come last
++ * Last entry must be all 0s
++ *
++ * { Vendor ID, Device ID, SubVendor ID, SubDevice ID,
++ *   Class, Class Mask, String Index }
++ */
++static struct pci_device_id e1000_pci_table[] = {
++    /* Intel(R) PRO/1000 Network Connection */
++    {0x8086, 0x1000, 0x8086, 0x1000, 0, 0, 0},
++    {0x8086, 0x1001, 0x8086, 0x1003, 0, 0, 0},
++    {0x8086, 0x1004, 0x8086, 0x1004, 0, 0, 0},
++    {0x8086, 0x1008, 0x8086, 0x1107, 0, 0, 0},
++    {0x8086, 0x1009, 0x8086, 0x1109, 0, 0, 0},
++    {0x8086, 0x100C, 0x8086, 0x1112, 0, 0, 0},
++    {0x8086, 0x100E, 0x8086, 0x001E, 0, 0, 0},
++    /* Compaq Gigabit Ethernet Server Adapter */
++    {0x8086, 0x1000, 0x0E11, PCI_ANY_ID, 0, 0, 1},
++    {0x8086, 0x1001, 0x0E11, PCI_ANY_ID, 0, 0, 1},
++    {0x8086, 0x1004, 0x0E11, PCI_ANY_ID, 0, 0, 1},
++    /* IBM Mobile, Desktop & Server Adapters */
++    {0x8086, 0x1000, 0x1014, PCI_ANY_ID, 0, 0, 2},
++    {0x8086, 0x1001, 0x1014, PCI_ANY_ID, 0, 0, 2},
++    {0x8086, 0x1004, 0x1014, PCI_ANY_ID, 0, 0, 2},
++    /* Generic */
++    {0x8086, 0x1000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
++    {0x8086, 0x1001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
++    {0x8086, 0x1004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
++    {0x8086, 0x1008, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
++    {0x8086, 0x1009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
++    {0x8086, 0x100C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
++    {0x8086, 0x100D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
++    {0x8086, 0x100E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
++    /* required last entry */
++    {0,}
++};
++
++MODULE_DEVICE_TABLE(pci, e1000_pci_table);
++
++/* e1000_pci_table - Table of branding strings for all supported NICs. */
++
++static char *e1000_strings[] = {
++    "Intel(R) PRO/1000 Network Connection",
++    "Compaq Gigabit Ethernet Server Adapter",
++    "IBM Mobile, Desktop & Server Adapters"
++};
++
++/* PCI driver information (Linux 2.4 driver API) */
++static struct pci_driver e1000_driver = {
++    name:     e1000_driver_name,
++    id_table: e1000_pci_table,
++    probe:    e1000_probe,
++    remove:   e1000_remove,
++    /* Power Managment Hooks */
++    suspend:  NULL,
++    resume:   NULL
++};
++
++/* Module Parameters are always initialized to -1, so that the driver
++ * can tell the difference between no user specified value or the
++ * user asking for the default value.
++ * The true default values are loaded in when e1000_check_options is called.
++ */
++
++/* This is the only thing that needs to be changed to adjust the
++ * maximum number of ports that the driver can manage.
++ */
++
++#define E1000_MAX_NIC 8
++
++/* This is a GCC extension to ANSI C.
++ * See the item "Labeled Elements in Initializers" in the section
++ * "Extensions to the C Language Family" of the GCC documentation.
++ */
++
++#define E1000_OPTION_INIT { [0 ... E1000_MAX_NIC] = OPTION_UNSET }
++
++/* Transmit Descriptor Count
++ *
++ * Valid Range: 80-256 for 82542 and 82543 gigabit ethernet controllers
++ * Valid Range: 80-4096 for 82544
++ *
++ * Default Value: 256
++ */
++
++static int TxDescriptors[E1000_MAX_NIC + 1] = E1000_OPTION_INIT;
++
++/* Receive Descriptor Count
++ *
++ * Valid Range: 80-256 for 82542 and 82543 gigabit ethernet controllers
++ * Valid Range: 80-4096 for 82544
++ *
++ * Default Value: 256
++ */
++
++static int RxDescriptors[E1000_MAX_NIC + 1] = E1000_OPTION_INIT;
++
++/* User Specified Speed Override
++ *
++ * Valid Range: 0, 10, 100, 1000
++ *  - 0    - auto-negotiate at all supported speeds
++ *  - 10   - only link at 10 Mbps
++ *  - 100  - only link at 100 Mbps
++ *  - 1000 - only link at 1000 Mbps
++ *
++ * Default Value: 0
++ */
++
++static int Speed[E1000_MAX_NIC + 1] = E1000_OPTION_INIT;
++
++/* User Specified Duplex Override
++ *
++ * Valid Range: 0-2
++ *  - 0 - auto-negotiate for duplex
++ *  - 1 - only link at half duplex
++ *  - 2 - only link at full duplex
++ *
++ * Default Value: 0
++ */
++
++static int Duplex[E1000_MAX_NIC + 1] = E1000_OPTION_INIT;
++
++/* Auto-negotiation Advertisement Override
++ *
++ * Valid Range: 0x00-0x0F, 0x20-0x2F
++ *
++ * The AutoNeg value is a bit mask describing which speed and duplex
++ * combinations should be advertised during auto-negotiation.
++ * The supported speed and duplex modes are listed below
++ *
++ * Bit           7     6     5      4      3     2     1      0
++ * Speed (Mbps)  N/A   N/A   1000   N/A    100   100   10     10
++ * Duplex                    Full          Full  Half  Full   Half
++ *
++ * Default Value: 0x2F
++ */
++
++static int AutoNeg[E1000_MAX_NIC + 1] = E1000_OPTION_INIT;
++
++/* User Specified Flow Control Override
++ *
++ * Valid Range: 0-3
++ *  - 0 - No Flow Control
++ *  - 1 - Rx only, respond to PAUSE frames but do not generate them
++ *  - 2 - Tx only, generate PAUSE frames but ignore them on receive
++ *  - 3 - Full Flow Control Support
++ *
++ * Default Value: Read flow control settings from the EEPROM
++ */
++
++static int FlowControl[E1000_MAX_NIC + 1] = E1000_OPTION_INIT;
++
++/* XsumRX - Receive Checksum Offload Enable/Disable
++ *
++ * Valid Range: 0, 1
++ *  - 0 - disables all checksum offload
++ *  - 1 - enables receive IP/TCP/UDP checksum offload
++ *        on 82543 based NICs
++ *
++ * Default Value: 1
++ */
++
++static int XsumRX[E1000_MAX_NIC + 1] = E1000_OPTION_INIT;
++
++/* Transmit Interrupt Delay in units of 1.024 microseconds
++ *
++ * Valid Range: 0-65535
++ *
++ * Default Value: 64
++ */
++
++static int TxIntDelay[E1000_MAX_NIC + 1] = E1000_OPTION_INIT;
++
++/* Receive Interrupt Delay in units of 1.024 microseconds
++ *
++ * Valid Range: 0-65535
++ *
++ * Default Value: 64
++ */
++
++static int RxIntDelay[E1000_MAX_NIC + 1] = E1000_OPTION_INIT;
++
++/* MDI-X Support Enable/Disable - Applies only to Copper PHY
++ *
++ * Valid Range: 0, 3
++ *  - 0 - Auto in all modes
++ *  - 1 - MDI
++ *  - 2 - MDI-X
++ *  - 3 - Auto in 1000 Base-T mode (MDI in 10 Base-T and 100 Base-T)
++ *
++ * Default Value: 0 (Auto)
++ */
++
++static int MdiX[E1000_MAX_NIC + 1] = E1000_OPTION_INIT;
++
++/* Automatic Correction of Reversed Cable Polarity Enable/Disable
++ * This setting applies only to Copper PHY
++ *
++ * Valid Range: 0, 1
++ *  - 0 - Disabled
++ *  - 1 - Enabled
++ *
++ * Default Value: 1 (Enabled)
++ */
++
++static int DisablePolarityCorrection[E1000_MAX_NIC + 1] = E1000_OPTION_INIT;
++
++#ifdef MODULE
++
++MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
++MODULE_DESCRIPTION("Intel(R) PRO/1000 Network Driver");
++
++#if defined(MODULE_LICENSE)
++MODULE_LICENSE("BSD with patent grant");
++#endif
++
++MODULE_PARM(TxDescriptors, "1-" __MODULE_STRING(E1000_MAX_NIC) "i");
++MODULE_PARM(RxDescriptors, "1-" __MODULE_STRING(E1000_MAX_NIC) "i");
++MODULE_PARM(Speed,         "1-" __MODULE_STRING(E1000_MAX_NIC) "i");
++MODULE_PARM(Duplex,        "1-" __MODULE_STRING(E1000_MAX_NIC) "i");
++MODULE_PARM(AutoNeg,       "1-" __MODULE_STRING(E1000_MAX_NIC) "i");
++MODULE_PARM(XsumRX,        "1-" __MODULE_STRING(E1000_MAX_NIC) "i");
++MODULE_PARM(FlowControl,   "1-" __MODULE_STRING(E1000_MAX_NIC) "i");
++MODULE_PARM(TxIntDelay,    "1-" __MODULE_STRING(E1000_MAX_NIC) "i");
++MODULE_PARM(RxIntDelay,    "1-" __MODULE_STRING(E1000_MAX_NIC) "i");
++MODULE_PARM(MdiX,          "1-" __MODULE_STRING(E1000_MAX_NIC) "i");
++MODULE_PARM(DisablePolarityCorrection, "1-" __MODULE_STRING(E1000_MAX_NIC) "i");
++
++MODULE_PARM_DESC(TxDescriptors, "Number of transmit descriptors");
++MODULE_PARM_DESC(RxDescriptors, "Number of receive descriptors");
++MODULE_PARM_DESC(Speed,         "Speed setting");
++MODULE_PARM_DESC(Duplex,        "Duplex setting");
++MODULE_PARM_DESC(AutoNeg,       "Advertised auto-negotiation setting");
++MODULE_PARM_DESC(XsumRX,        "Disable or enable Receive Checksum offload");
++MODULE_PARM_DESC(FlowControl,   "Flow Control setting");
++MODULE_PARM_DESC(TxIntDelay,    "Transmit Interrupt Delay");
++MODULE_PARM_DESC(RxIntDelay,    "Receive Interrupt Delay");
++MODULE_PARM_DESC(MdiX,          "Set MDI/MDI-X Mode");
++MODULE_PARM_DESC(DisablePolarityCorrection,
++                 "Disable or enable Automatic Correction for Reversed Cable Polarity");
++
++#ifdef EXPORT_SYMTAB
++/*EXPORT_SYMBOL(e1000_init_module);
++EXPORT_SYMBOL(e1000_exit_module);
++EXPORT_SYMBOL(e1000_probe);
++EXPORT_SYMBOL(e1000_remove);
++EXPORT_SYMBOL(e1000_open);
++EXPORT_SYMBOL(e1000_close);
++EXPORT_SYMBOL(e1000_xmit_frame);
++EXPORT_SYMBOL(e1000_intr);
++EXPORT_SYMBOL(e1000_set_multi);
++EXPORT_SYMBOL(e1000_change_mtu);
++EXPORT_SYMBOL(e1000_set_mac);
++EXPORT_SYMBOL(e1000_get_stats);
++EXPORT_SYMBOL(e1000_watchdog);
++EXPORT_SYMBOL(e1000_ioctl);
++EXPORT_SYMBOL(e1000_adapter_list);*/
++#endif
++
++#endif
++
++/* Local Function Prototypes */
++
++static void e1000_check_options(struct e1000_adapter *adapter);
++static void e1000_check_fiber_options(struct e1000_adapter *adapter);
++static void e1000_check_copper_options(struct e1000_adapter *adapter);
++static int e1000_sw_init(struct e1000_adapter *adapter);
++static int e1000_hw_init(struct e1000_adapter *adapter);
++static void e1000_read_address(struct e1000_adapter *adapter,
++                               uint8_t *addr);
++static int e1000_setup_tx_resources(struct e1000_adapter *adapter);
++static int e1000_setup_rx_resources(struct e1000_adapter *adapter);
++static void e1000_setup_rctl(struct e1000_adapter *adapter);
++static void e1000_configure_rx(struct e1000_adapter *adapter);
++static void e1000_configure_tx(struct e1000_adapter *adapter);
++static void e1000_free_tx_resources(struct e1000_adapter *adapter);
++static void e1000_free_rx_resources(struct e1000_adapter *adapter);
++static void e1000_update_stats(struct e1000_adapter *adapter);
++static inline void e1000_irq_disable(struct e1000_adapter *adapter);
++static inline void e1000_irq_enable(struct e1000_adapter *adapter);
++static void e1000_clean_tx_irq(struct e1000_adapter *adapter);
++static void e1000_clean_rx_irq(struct e1000_adapter *adapter);
++static inline void e1000_rx_checksum(struct e1000_adapter *adapter,
++                                     struct e1000_rx_desc *rx_desc,
++                                     struct sk_buff *skb);
++static void e1000_alloc_rx_buffers(unsigned long data);
++static void e1000_clean_tx_ring(struct e1000_adapter *adapter);
++static void e1000_clean_rx_ring(struct e1000_adapter *adapter);
++void e1000_hibernate_adapter(struct net_device *netdev);
++void e1000_wakeup_adapter(struct net_device *netdev);
++static void e1000_enable_WOL(struct e1000_adapter *adapter);
++
++#ifdef SIOCETHTOOL
++static int e1000_ethtool_ioctl(struct net_device *netdev,
++                               struct ifreq *ifr);
++#endif
++#ifdef IDIAG
++static int e1000_check_lbtest_frame(struct sk_buff *skb,
++                                    unsigned int frame_size);
++#endif
++
++/**
++ * e1000_init_module - Driver Registration Routine
++ *
++ * e1000_init_module is the first routine called when the driver is
++ * loaded. All it does is register with the PCI subsystem.
++ **/
++
++int
++e1000_init_module()
++{
++    E1000_DBG("e1000_init_module\n");
++
++    /* Print the driver ID string and copyright notice */
++
++    printk("%s - version %s\n%s\n", e1000_driver_string, e1000_driver_version,
++           e1000_copyright);
++
++    /* register the driver with the PCI subsystem */
++
++    return pci_module_init(&e1000_driver);
++}
++
++/* this macro creates a special symbol in the object file that
++ * identifies the driver initialization routine
++ */
++module_init(e1000_init_module);
++
++/**
++ * e1000_exit_module - Driver Exit Cleanup Routine
++ *
++ * e1000_exit_module is called just before the driver is removed
++ * from memory.
++ **/
++
++void
++e1000_exit_module()
++{
++#ifdef CONFIG_PROC_FS
++    struct proc_dir_entry *de;
++#endif
++
++    E1000_DBG("e1000_exit_module\n");
++
++    pci_unregister_driver(&e1000_driver);
++
++#ifdef CONFIG_PROC_FS
++    /* if there is no e1000_proc_dir (proc creation failure on load)
++     * then we're done
++     */
++    if(e1000_proc_dir == NULL)
++        return;
++
++    /* If ADAPTERS_PROC_DIR (/proc/net/PRO_LAN_Adapters) is empty
++     * it can be removed now (might still be in use by e100)
++     */
++    for(de = e1000_proc_dir->subdir; de; de = de->next) {
++
++        /* ignore . and .. */
++
++        if(*(de->name) == '.')
++            continue;
++        break;
++    }
++    if(de)
++        return;
++    remove_proc_entry(ADAPTERS_PROC_DIR, proc_net);
++#endif
++
++    return;
++}
++
++/* this macro creates a special symbol in the object file that
++ * identifies the driver cleanup routine
++ */
++module_exit(e1000_exit_module);
++
++/**
++ * e1000_probe - Device Initialization Routine
++ * @pdev: PCI device information struct
++ * @ent: entry in e1000_pci_table
++ *
++ * Returns 0 on success, negative on failure
++ *
++ * e1000_probe initializes an adapter identified by a pci_dev
++ * structure.  The OS initialization is handled here, and
++ * e1000_sw_init and e1000_hw_init are called to handle the driver
++ * specific software structures and hardware initialization
++ * respectively.
++ **/
++
++int
++e1000_probe(struct pci_dev *pdev,
++            const struct pci_device_id *ent)
++{
++    struct net_device *netdev = NULL;
++    struct e1000_adapter *adapter;
++    static int cards_found = 0;
++
++#ifdef CONFIG_PROC_FS
++    int len;
++#endif
++
++    E1000_DBG("e1000_probe\n");
++
++    /* Make sure the PCI device has the proper resources available */
++
++    if(pci_enable_device(pdev) != 0) {
++        E1000_ERR("pci_enable_device failed\n");
++        return -ENODEV;
++    }
++
++    /* Make sure we are enabled as a bus mastering device */
++
++    pci_set_master(pdev);
++
++    /* Check to see if our PCI addressing needs are supported */
++    if(pci_set_dma_mask(pdev, E1000_DMA_MASK) < 0) {
++        E1000_ERR("PCI DMA not supported by the system\n");
++        return -ENODEV;
++    }
++
++    /* Allocate private data structure (struct e1000_adapter)
++     */
++    netdev = alloc_etherdev(sizeof(struct e1000_adapter));
++
++    if(netdev == NULL) {
++        E1000_ERR("Unable to allocate net_device struct\n");
++        return -ENOMEM;
++    }
++
++    /* Calling alloc_etherdev with sizeof(struct e1000_adapter) allocates
++     * a single buffer of size net_device + struct e1000_adapter +
++     * alignment. If this is not done then the struct e1000_adapter needs
++     * to be allocated and freed separately.
++     */
++    adapter = (struct e1000_adapter *) netdev->priv;
++    memset(adapter, 0, sizeof(struct e1000_adapter));
++    adapter->netdev = netdev;
++    adapter->pdev = pdev;
++
++    /* link the struct e1000_adapter into the list */
++
++    if(e1000_adapter_list != NULL)
++        e1000_adapter_list->prev = adapter;
++    adapter->next = e1000_adapter_list;
++    e1000_adapter_list = adapter;
++    adapter->shared.back = (void *) adapter;
++
++    /* reserve the MMIO region as ours */
++
++    if(!request_mem_region
++       (pci_resource_start(pdev, BAR_0), pci_resource_len(pdev, BAR_0),
++        e1000_driver_name)) {
++        E1000_ERR("request_mem_region failed\n");
++        e1000_remove(pdev);
++        return -ENODEV;
++    }
++
++    /* map the MMIO region into the kernel virtual address space */
++
++    adapter->shared.hw_addr =
++        ioremap(pci_resource_start(pdev, BAR_0), pci_resource_len(pdev, BAR_0));
++
++    if(adapter->shared.hw_addr == NULL) {
++        E1000_ERR("ioremap failed\n");
++        release_mem_region(pci_resource_start(pdev, BAR_0),
++                           pci_resource_len(pdev, BAR_0));
++        e1000_remove(pdev);
++        return -ENOMEM;
++    }
++
++    /* don't actually register the interrupt handler until e1000_open */
++
++    netdev->irq = pdev->irq;
++
++    /* Set the MMIO base address for the NIC */
++
++#ifdef IANS
++    netdev->base_addr = pci_resource_start(pdev, BAR_0);
++#endif
++    netdev->mem_start = pci_resource_start(pdev, BAR_0);
++    netdev->mem_end = netdev->mem_start + pci_resource_len(pdev, BAR_0);
++
++    /* set up function pointers to driver entry points */
++
++    netdev->open = &e1000_open;
++    netdev->stop = &e1000_close;
++    netdev->hard_start_xmit = &e1000_xmit_frame;
++    netdev->get_stats = &e1000_get_stats;
++    netdev->set_multicast_list = &e1000_set_multi;
++    netdev->set_mac_address = &e1000_set_mac;
++    netdev->change_mtu = &e1000_change_mtu;
++    netdev->do_ioctl = &e1000_ioctl;
++
++    /* set up the struct e1000_adapter */
++
++    adapter->bd_number = cards_found;
++    adapter->id_string = e1000_strings[ent->driver_data];
++    printk("\n%s\n", adapter->id_string);
++
++    /* Order is important here.  e1000_sw_init also identifies the
++     * hardware, so that e1000_check_options can treat command line parameters
++     * differently depending on the hardware.
++     */
++    e1000_sw_init(adapter);
++    e1000_check_options(adapter);
++
++#ifdef MAX_SKB_FRAGS
++    if(adapter->shared.mac_type >= e1000_82543) {
++        netdev->features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_HIGHDMA;
++    } else {
++        netdev->features = NETIF_F_SG | NETIF_F_HIGHDMA;
++    }
++#endif
++
++#ifdef IANS
++    adapter->iANSdata = kmalloc(sizeof(iANSsupport_t), GFP_KERNEL);
++    if(adapter->iANSdata == NULL) {
++        e1000_remove(pdev);
++        return -ENOMEM;
++    }
++    memset(adapter->iANSdata, 0, sizeof(iANSsupport_t));
++    bd_ans_drv_InitANS(adapter, adapter->iANSdata);
++#endif
++
++    /* finally, we get around to setting up the hardware */
++
++    if(e1000_hw_init(adapter) < 0) {
++        e1000_remove(pdev);
++        return -ENODEV;
++    }
++    cards_found++;
++
++    /* reset stats */
++
++    e1000_clear_hw_cntrs(&adapter->shared);
++    e1000_phy_get_info(&adapter->shared, &adapter->phy_info);
++
++    /* Then register the net device once everything initializes
++     */
++    register_netdev(netdev);
++
++#ifdef CONFIG_PROC_FS
++    /* set up the proc fs entry */
++
++    len = strlen(ADAPTERS_PROC_DIR);
++
++    for(e1000_proc_dir = proc_net->subdir; e1000_proc_dir;
++        e1000_proc_dir = e1000_proc_dir->next) {
++        if((e1000_proc_dir->namelen == len) &&
++           (memcmp(e1000_proc_dir->name, ADAPTERS_PROC_DIR, len) == 0))
++            break;
++    }
++
++    if(e1000_proc_dir == NULL)
++        e1000_proc_dir =
++            create_proc_entry(ADAPTERS_PROC_DIR, S_IFDIR, proc_net);
++
++    if(e1000_proc_dir != NULL)
++        if(e1000_create_proc_dev(adapter) < 0) {
++            e1000_remove_proc_dev(adapter->netdev);
++        }
++#endif
++
++    /* print the link status */
++
++    if(adapter->link_active == 1)
++        printk("%s:  Mem:0x%p  IRQ:%d  Speed:%d Mbps  Duplex:%s\n",
++               netdev->name, (void *) netdev->mem_start, netdev->irq,
++               adapter->link_speed,
++               adapter->link_duplex == FULL_DUPLEX ? "Full" : "Half");
++    else
++        printk("%s:  Mem:0x%p  IRQ:%d  Speed:N/A  Duplex:N/A\n", netdev->name,
++               (void *) netdev->mem_start, netdev->irq);
++
++    return 0;
++}
++
++/**
++ * e1000_remove - Device Removal Routine
++ * @pdev: PCI device information struct
++ *
++ * e1000_remove is called by the PCI subsystem to alert the driver
++ * that it should release a PCI device.  The could be caused by a
++ * Hot-Plug event, or because the driver is going to be removed from
++ * memory.
++ *
++ * This routine is also called to clean up from a failure in
++ * e1000_probe.  The Adapter struct and netdev will always exist,
++ * all other pointers must be checked for NULL before freeing.
++ **/
++
++void
++e1000_remove(struct pci_dev *pdev)
++{
++    struct net_device *netdev;
++    struct e1000_adapter *adapter;
++
++    /* find the Adapter struct that matches this PCI device */
++
++    for(adapter = e1000_adapter_list; adapter != NULL; adapter = adapter->next) {
++        if(adapter->pdev == pdev)
++            break;
++    }
++    if(adapter == NULL)
++        return;
++
++    netdev = adapter->netdev;
++
++    /* this must be called before freeing anything,
++     * otherwise there is a case where the open entry point can be
++     * running at the same time as remove. Calling unregister_netdev on an
++     * open interface results in a call to dev_close, which locks
++     * properly against the other netdev entry points, so this takes
++     * care of the hotplug issue of removing an active interface as well.
++     */
++    unregister_netdev(netdev);
++
++    e1000_phy_hw_reset(&adapter->shared);
++
++#ifdef CONFIG_PROC_FS
++    /* remove the proc nodes */
++
++    if(e1000_proc_dir != NULL)
++        e1000_remove_proc_dev(adapter->netdev);
++#endif
++
++    /* remove from the adapter list */
++
++    if(e1000_adapter_list == adapter)
++        e1000_adapter_list = adapter->next;
++    if(adapter->next != NULL)
++        adapter->next->prev = adapter->prev;
++    if(adapter->prev != NULL)
++        adapter->prev->next = adapter->next;
++
++    /* free system resources */
++
++#ifdef IANS
++    if(adapter->iANSdata != NULL)
++        kfree(adapter->iANSdata);
++#endif
++
++    if(adapter->shared.hw_addr != NULL) {
++        iounmap((void *) adapter->shared.hw_addr);
++        release_mem_region(pci_resource_start(pdev, BAR_0),
++                           pci_resource_len(pdev, BAR_0));
++    }
++
++    /* free the net_device _and_ struct e1000_adapter memory */
++
++    kfree(netdev);
++
++    return;
++}
++
++/**
++ * e1000_check_options - Range Checking for Command Line Parameters
++ * @adapter: board private structure
++ *
++ * This routine checks all command line paramters for valid user
++ * input.  If an invalid value is given, or if no user specified
++ * value exists, a default value is used.  The final value is stored
++ * in a variable in the Adapter structure.
++ **/
++
++static void
++e1000_check_options(struct e1000_adapter *adapter)
++{
++    int board = adapter->bd_number;
++
++    if(board >= E1000_MAX_NIC) {
++        printk("Warning: no configuration for board #%i\n", board);
++        printk("Using defaults for all values\n");
++        board = E1000_MAX_NIC;
++    }
++
++    E1000_DBG("e1000_check_options\n");
++
++    /* Transmit Descriptor Count */
++
++    if(TxDescriptors[board] == OPTION_UNSET) {
++        adapter->tx_ring.count = DEFAULT_TXD;
++        TxDescriptors[board] = DEFAULT_TXD;
++    } else
++        if(((TxDescriptors[board] > MAX_TXD) ||
++            (TxDescriptors[board] < MIN_TXD)) &&
++           (adapter->shared.mac_type <= e1000_82543)) {
++        printk("Invalid TxDescriptors specified (%i), using default %i\n",
++               TxDescriptors[board], DEFAULT_TXD);
++        adapter->tx_ring.count = DEFAULT_TXD;
++    } else
++        if(((TxDescriptors[board] > MAX_82544_TXD) ||
++            (TxDescriptors[board] < MIN_TXD)) &&
++           (adapter->shared.mac_type > e1000_82543)) {
++        printk("Invalid TxDescriptors specified (%i), using default %i\n",
++               TxDescriptors[board], DEFAULT_TXD);
++        adapter->tx_ring.count = DEFAULT_TXD;
++    } else {
++        printk("Using specified value of %i TxDescriptors\n",
++               TxDescriptors[board]);
++        adapter->tx_ring.count = TxDescriptors[board];
++    }
++
++    /* tx_ring.count must be a multiple of 8 */
++
++    adapter->tx_ring.count = E1000_ROUNDUP2(adapter->tx_ring.count,
++                                            REQ_TX_DESCRIPTOR_MULTIPLE);
++
++    /* Receive Descriptor Count */
++
++    if(RxDescriptors[board] == OPTION_UNSET) {
++        adapter->rx_ring.count = DEFAULT_RXD;
++        RxDescriptors[board] = DEFAULT_RXD;
++    } else
++        if(((RxDescriptors[board] > MAX_RXD) ||
++            (RxDescriptors[board] < MIN_RXD)) &&
++           (adapter->shared.mac_type <= e1000_82543)) {
++        printk("Invalid RxDescriptors specified (%i), using default %i\n",
++               RxDescriptors[board], DEFAULT_RXD);
++        adapter->rx_ring.count = DEFAULT_RXD;
++    } else
++        if(((RxDescriptors[board] > MAX_82544_RXD) ||
++            (RxDescriptors[board] < MIN_RXD)) &&
++           (adapter->shared.mac_type > e1000_82543)) {
++        printk("Invalid RxDescriptors specified (%i), using default %i\n",
++               RxDescriptors[board], DEFAULT_RXD);
++        adapter->rx_ring.count = DEFAULT_RXD;
++    } else {
++        printk("Using specified value of %i RxDescriptors\n",
++               RxDescriptors[board]);
++        adapter->rx_ring.count = RxDescriptors[board];
++    }
++
++    /* rx_ring.count must be a multiple of 8 */
++
++    adapter->rx_ring.count =
++        E1000_ROUNDUP2(adapter->rx_ring.count, REQ_RX_DESCRIPTOR_MULTIPLE);
++
++    /* Receive Checksum Offload Enable */
++
++    if(XsumRX[board] == OPTION_UNSET) {
++        adapter->RxChecksum = XSUMRX_DEFAULT;
++        XsumRX[board] = XSUMRX_DEFAULT;
++    } else if((XsumRX[board] != OPTION_ENABLED) &&
++              (XsumRX[board] != OPTION_DISABLED)) {
++        printk("Invalid XsumRX specified (%i), using default of %i\n",
++               XsumRX[board], XSUMRX_DEFAULT);
++        adapter->RxChecksum = XSUMRX_DEFAULT;
++    } else {
++        printk("Receive Checksum Offload %s\n",
++               XsumRX[board] == OPTION_ENABLED ? "Enabled" : "Disabled");
++        adapter->RxChecksum = XsumRX[board];
++    }
++
++    /* Flow Control */
++
++    if(FlowControl[board] == OPTION_UNSET) {
++        adapter->shared.fc = e1000_fc_default;
++        FlowControl[board] = e1000_fc_default;
++    } else if((FlowControl[board] > e1000_fc_full) ||
++              (FlowControl[board] < e1000_fc_none)) {
++        printk("Invalid FlowControl specified (%i), "
++               "reading default settings from the EEPROM\n",
++               FlowControl[board]);
++        adapter->shared.fc = e1000_fc_default;
++    } else {
++        adapter->shared.fc = FlowControl[board];
++        switch (adapter->shared.fc) {
++        case e1000_fc_none:
++            printk("Flow Control Disabled\n");
++            break;
++        case e1000_fc_rx_pause:
++            printk("Flow Control Receive Only\n");
++            break;
++        case e1000_fc_tx_pause:
++            printk("Flow Control Transmit Only\n");
++            break;
++        case e1000_fc_full:
++            printk("Flow Control Enabled\n");
++        case e1000_fc_default:
++            printk("Flow Control Hardware Default\n");
++        }
++    }
++
++    /* Transmit Interrupt Delay */
++
++    if(TxIntDelay[board] == OPTION_UNSET) {
++        adapter->tx_int_delay = DEFAULT_TIDV;
++        TxIntDelay[board] = DEFAULT_TIDV;
++    } else if((TxIntDelay[board] > MAX_TIDV) || (TxIntDelay[board] < MIN_TIDV)) {
++        printk("Invalid TxIntDelay specified (%i), using default %i\n",
++               TxIntDelay[board], DEFAULT_TIDV);
++        adapter->tx_int_delay = DEFAULT_TIDV;
++    } else {
++        printk("Using specified TxIntDelay of %i\n", TxIntDelay[board]);
++        adapter->tx_int_delay = TxIntDelay[board];
++    }
++
++    /* Receive Interrupt Delay */
++
++    if(RxIntDelay[board] == OPTION_UNSET) {
++        adapter->rx_int_delay = DEFAULT_RIDV;
++        RxIntDelay[board] = DEFAULT_RIDV;
++    } else if((RxIntDelay[board] > MAX_RIDV) || (RxIntDelay[board] < MIN_RIDV)) {
++        printk("Invalid RxIntDelay specified (%i), using default %i\n",
++               RxIntDelay[board], DEFAULT_RIDV);
++        adapter->rx_int_delay = DEFAULT_RIDV;
++    } else {
++        printk("Using specified RxIntDelay of %i\n", RxIntDelay[board]);
++        adapter->rx_int_delay = RxIntDelay[board];
++    }
++
++    if(adapter->shared.media_type == e1000_media_type_copper) {
++        /* MDI/MDI-X Support */
++
++        if(MdiX[board] == OPTION_UNSET) {
++            adapter->shared.mdix = DEFAULT_MDIX;
++            MdiX[board] = DEFAULT_MDIX;
++        } else if((MdiX[board] > MAX_MDIX) || (MdiX[board] < MIN_MDIX)) {
++            printk("Invalid MDI/MDI-X specified (%i), using default %i\n",
++                   MdiX[board], DEFAULT_MDIX);
++            adapter->shared.mdix = DEFAULT_MDIX;
++        } else {
++            printk("Using specified MDI/MDI-X of %i\n", MdiX[board]);
++            adapter->shared.mdix = MdiX[board];
++        }
++
++        /* Automatic Correction for Reverse Cable Polarity */
++
++        if(DisablePolarityCorrection[board] == OPTION_UNSET) {
++            adapter->shared.disable_polarity_correction = OPTION_DISABLED;
++            DisablePolarityCorrection[board] = OPTION_DISABLED;
++        } else if((DisablePolarityCorrection[board] != OPTION_ENABLED) &&
++                  (DisablePolarityCorrection[board] != OPTION_DISABLED)) {
++            printk("Invalid polarity correction specified (%i),"
++                   "    using default %i\n", DisablePolarityCorrection[board],
++                   OPTION_DISABLED);
++            adapter->shared.disable_polarity_correction = OPTION_DISABLED;
++        } else {
++            printk("Using specified polarity correction of %i\n",
++                   DisablePolarityCorrection[board]);
++            adapter->shared.disable_polarity_correction =
++                DisablePolarityCorrection[board];
++        }
++    }
++
++    /* Speed, Duplex, and AutoNeg */
++
++    switch (adapter->shared.media_type) {
++
++    case e1000_media_type_fiber:
++        e1000_check_fiber_options(adapter);
++        break;
++
++    case e1000_media_type_copper:
++        e1000_check_copper_options(adapter);
++        break;
++
++    default:
++        printk("Unknown Media Type\n");
++        break;
++    }
++
++    return;
++}
++
++/**
++ * e1000_check_fiber_options - Range Checking for Link Options, Fiber Version
++ * @adapter: board private structure
++ *
++ * Handles speed and duplex options on fiber based adapters
++ **/
++
++static void
++e1000_check_fiber_options(struct e1000_adapter *adapter)
++{
++    int board =
++        adapter->bd_number > E1000_MAX_NIC ? E1000_MAX_NIC : adapter->bd_number;
++
++    E1000_DBG("CheckSpeedDuplexFiber\n");
++
++    /* Speed, Duplex, and AutoNeg are not valid on fiber NICs */
++
++    if((Speed[board] != OPTION_UNSET)) {
++        Speed[board] = 0;
++        printk("Warning: Speed not valid for fiber adapters\n");
++        printk("Speed Parameter Ignored\n");
++    }
++    if((Duplex[board] != OPTION_UNSET)) {
++        Duplex[board] = 0;
++        printk("Warning: Duplex not valid for fiber adapters\n");
++        printk("Duplex Parameter Ignored\n");
++    }
++    if((AutoNeg[board] != OPTION_UNSET)) {
++        AutoNeg[board] = AUTONEG_ADV_DEFAULT;
++        printk("Warning: AutoNeg not valid for fiber adapters\n");
++        printk("AutoNeg Parameter Ignored\n");
++    }
++
++    return;
++}
++
++/**
++ * e1000_check_copper_options - Range Checking for Link Options, Copper Version
++ * @adapter: board private structure
++ *
++ * Handles speed and duplex options on copper based adapters
++ **/
++
++static void
++e1000_check_copper_options(struct e1000_adapter *adapter)
++{
++    int board =
++        adapter->bd_number > E1000_MAX_NIC ? E1000_MAX_NIC : adapter->bd_number;
++    int speed, duplex;
++    boolean_t all_default = TRUE;
++
++    E1000_DBG("CheckSpeedDuplexCopper\n");
++
++    /* User Specified Auto-negotiation Settings */
++
++    if(AutoNeg[board] == OPTION_UNSET) {
++
++        adapter->shared.autoneg_advertised = AUTONEG_ADV_DEFAULT;
++        AutoNeg[board] = AUTONEG_ADV_DEFAULT;
++
++    } else if((Speed[board] != 0 && Speed[board] != OPTION_UNSET) ||
++              (Duplex[board] != 0 && Duplex[board] != OPTION_UNSET)) {
++
++        printk("Warning: AutoNeg specified along with Speed or Duplex\n");
++        printk("AutoNeg Parameter Ignored\n");
++
++        adapter->shared.autoneg_advertised = AUTONEG_ADV_DEFAULT;
++
++    } else {
++
++        if(AutoNeg[board] & ~AUTONEG_ADV_MASK) {
++
++            printk("Invalid AutoNeg Specified (0x%X), Parameter Ignored\n",
++                   AutoNeg[board]);
++
++            adapter->shared.autoneg_advertised = AUTONEG_ADV_DEFAULT;
++
++        } else {
++
++            adapter->shared.autoneg_advertised = AutoNeg[board];
++        }
++
++        printk("AutoNeg Advertising ");
++        if(adapter->shared.autoneg_advertised & ADVERTISE_1000_FULL) {
++            printk("1000/FD");
++            if(adapter->shared.autoneg_advertised & (ADVERTISE_1000_FULL - 1))
++                printk(", ");
++        }
++        if(adapter->shared.autoneg_advertised & ADVERTISE_1000_HALF) {
++            printk("1000/HD");
++            if(adapter->shared.autoneg_advertised & (ADVERTISE_1000_HALF - 1))
++                printk(", ");
++        }
++        if(adapter->shared.autoneg_advertised & ADVERTISE_100_FULL) {
++            printk("100/FD");
++            if(adapter->shared.autoneg_advertised & (ADVERTISE_100_FULL - 1))
++                printk(", ");
++        }
++        if(adapter->shared.autoneg_advertised & ADVERTISE_100_HALF) {
++            printk("100/HD");
++            if(adapter->shared.autoneg_advertised & (ADVERTISE_100_HALF - 1))
++                printk(", ");
++        }
++        if(adapter->shared.autoneg_advertised & ADVERTISE_10_FULL) {
++            printk("10/FD");
++            if(adapter->shared.autoneg_advertised & (ADVERTISE_10_FULL - 1))
++                printk(", ");
++        }
++        if(adapter->shared.autoneg_advertised & ADVERTISE_10_HALF)
++            printk("10/HD");
++        printk("\n");
++    }
++
++    /* Forced Speed and Duplex */
++
++    switch (Speed[board]) {
++    default:
++        printk("Invalid Speed Specified (%i), Parameter Ignored\n",
++               Speed[board]);
++        all_default = FALSE;
++    case OPTION_UNSET:
++        speed = 0;
++        Speed[board] = 0;
++        break;
++    case 0:
++    case 10:
++    case 100:
++    case 1000:
++        speed = Speed[board];
++        all_default = FALSE;
++        break;
++    }
++
++    switch (Duplex[board]) {
++    default:
++        printk("Invalid Duplex Specified (%i), Parameter Ignored\n",
++               Duplex[board]);
++        all_default = FALSE;
++    case OPTION_UNSET:
++        duplex = 0;
++        Duplex[board] = 0;
++        break;
++    case 0:
++    case 1:
++    case 2:
++        duplex = Duplex[board];
++        all_default = FALSE;
++        break;
++    }
++
++    switch (speed + duplex) {
++    case 0:
++        if(all_default == FALSE)
++            printk("Speed and Duplex Auto-negotiation Enabled\n");
++        adapter->shared.autoneg = 1;
++        break;
++    case 1:
++        printk("Warning: Half Duplex specified without Speed\n");
++        printk("Using Auto-negotiation at Half Duplex only\n");
++        adapter->shared.autoneg = 1;
++        adapter->shared.autoneg_advertised =
++            ADVERTISE_10_HALF | ADVERTISE_100_HALF;
++        break;
++    case 2:
++        printk("Warning: Full Duplex specified without Speed\n");
++        printk("Using Auto-negotiation at Full Duplex only\n");
++        adapter->shared.autoneg = 1;
++        adapter->shared.autoneg_advertised =
++            ADVERTISE_10_FULL | ADVERTISE_100_FULL | ADVERTISE_1000_FULL;
++        break;
++    case 10:
++        printk("Warning: 10 Mbps Speed specified without Duplex\n");
++        printk("Using Auto-negotiation at 10 Mbps only\n");
++        adapter->shared.autoneg = 1;
++        adapter->shared.autoneg_advertised =
++            ADVERTISE_10_HALF | ADVERTISE_10_FULL;
++        break;
++    case 11:
++        printk("Forcing to 10 Mbps Half Duplex\n");
++        adapter->shared.autoneg = 0;
++        adapter->shared.forced_speed_duplex = e1000_10_half;
++        adapter->shared.autoneg_advertised = 0;
++        break;
++    case 12:
++        printk("Forcing to 10 Mbps Full Duplex\n");
++        adapter->shared.autoneg = 0;
++        adapter->shared.forced_speed_duplex = e1000_10_full;
++        adapter->shared.autoneg_advertised = 0;
++        break;
++    case 100:
++        printk("Warning: 100 Mbps Speed specified without Duplex\n");
++        printk("Using Auto-negotiation at 100 Mbps only\n");
++        adapter->shared.autoneg = 1;
++        adapter->shared.autoneg_advertised =
++            ADVERTISE_100_HALF | ADVERTISE_100_FULL;
++        break;
++    case 101:
++        printk("Forcing to 100 Mbps Half Duplex\n");
++        adapter->shared.autoneg = 0;
++        adapter->shared.forced_speed_duplex = e1000_100_half;
++        adapter->shared.autoneg_advertised = 0;
++        break;
++    case 102:
++        printk("Forcing to 100 Mbps Full Duplex\n");
++        adapter->shared.autoneg = 0;
++        adapter->shared.forced_speed_duplex = e1000_100_full;
++        adapter->shared.autoneg_advertised = 0;
++        break;
++    case 1000:
++        printk("Warning: 1000 Mbps Speed specified without Duplex\n");
++        printk("Using Auto-negotiation at 1000 Mbps Full Duplex only\n");
++        adapter->shared.autoneg = 1;
++        adapter->shared.autoneg_advertised = ADVERTISE_1000_FULL;
++        break;
++    case 1001:
++        printk("Warning: Half Duplex is not supported at 1000 Mbps\n");
++        printk("Using Auto-negotiation at 1000 Mbps Full Duplex only\n");
++        adapter->shared.autoneg = 1;
++        adapter->shared.autoneg_advertised = ADVERTISE_1000_FULL;
++        break;
++    case 1002:
++        printk("Using Auto-negotiation at 1000 Mbps Full Duplex only\n");
++        adapter->shared.autoneg = 1;
++        adapter->shared.autoneg_advertised = ADVERTISE_1000_FULL;
++        break;
++    default:
++        panic("something is wrong in e1000_check_copper_options");
++    }
++
++    /* Speed, AutoNeg and MDI/MDI-X */
++    if (!e1000_validate_mdi_setting(&(adapter->shared))) {
++        printk ("Speed, AutoNeg and MDI-X specifications are incompatible."
++                " Setting MDI-X to a compatible value.\n");
++    }
++
++    return;
++}
++
++/**
++ * e1000_sw_init - Initialize general software structures (struct e1000_adapter)
++ * @adapter: board private structure to initialize
++ *
++ * Returns 0 on success, negative on failure
++ *
++ * e1000_sw_init initializes the Adapter private data structure.
++ * Fields are initialized based on PCI device information and
++ * OS network device settings (MTU size).
++ **/
++
++static int
++e1000_sw_init(struct e1000_adapter *adapter)
++{
++    struct net_device *netdev = adapter->netdev;
++    struct pci_dev *pdev = adapter->pdev;
++    uint32_t status;
++
++    E1000_DBG("e1000_sw_init\n");
++
++    /* PCI config space info */
++
++    pci_read_config_word(pdev, PCI_VENDOR_ID, &adapter->vendor_id);
++    pci_read_config_word(pdev, PCI_DEVICE_ID, &adapter->device_id);
++    pci_read_config_byte(pdev, PCI_REVISION_ID, &adapter->rev_id);
++    pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &adapter->subven_id);
++    pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &adapter->subsys_id);
++    pci_read_config_word(pdev, PCI_COMMAND, &adapter->shared.pci_cmd_word);
++    adapter->shared.vendor_id = adapter->vendor_id;
++    adapter->shared.device_id = adapter->device_id;
++    adapter->shared.revision_id = adapter->rev_id;
++    adapter->shared.subsystem_vendor_id = adapter->subven_id;
++    adapter->shared.subsystem_id = adapter->subsys_id;
++
++    /* Initial Receive Buffer Length */
++
++    if((netdev->mtu + ENET_HEADER_SIZE + CRC_LENGTH) < E1000_RXBUFFER_2048)
++        adapter->rx_buffer_len = E1000_RXBUFFER_2048;
++    else if((netdev->mtu + ENET_HEADER_SIZE + CRC_LENGTH) < E1000_RXBUFFER_4096)
++        adapter->rx_buffer_len = E1000_RXBUFFER_4096;
++    else if((netdev->mtu + ENET_HEADER_SIZE + CRC_LENGTH) < E1000_RXBUFFER_8192)
++        adapter->rx_buffer_len = E1000_RXBUFFER_8192;
++    else
++        adapter->rx_buffer_len = E1000_RXBUFFER_16384;
++
++    adapter->shared.max_frame_size =
++        netdev->mtu + ENET_HEADER_SIZE + CRC_LENGTH;
++    adapter->shared.min_frame_size = MINIMUM_ETHERNET_PACKET_SIZE + CRC_LENGTH;
++
++    /* MAC and Phy settings */
++
++    switch (adapter->device_id) {
++    case E1000_DEV_ID_82542:
++        switch (adapter->rev_id) {
++        case E1000_82542_2_0_REV_ID:
++            adapter->shared.mac_type = e1000_82542_rev2_0;
++            break;
++        case E1000_82542_2_1_REV_ID:
++            adapter->shared.mac_type = e1000_82542_rev2_1;
++            break;
++        default:
++            adapter->shared.mac_type = e1000_82542_rev2_0;
++            E1000_ERR("Could not identify 82542 revision\n");
++        }
++        break;
++    case E1000_DEV_ID_82543GC_FIBER:
++    case E1000_DEV_ID_82543GC_COPPER:
++        adapter->shared.mac_type = e1000_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:
++        adapter->shared.mac_type = e1000_82544;
++        break;
++    case E1000_DEV_ID_82540EM:
++        adapter->shared.mac_type = e1000_82540;
++        break;
++    default:
++        E1000_ERR("Could not identify hardware\n");
++        return -ENODEV;
++    }
++
++    adapter->shared.fc_high_water = FC_DEFAULT_HI_THRESH;
++    adapter->shared.fc_low_water = FC_DEFAULT_LO_THRESH;
++    adapter->shared.fc_pause_time = FC_DEFAULT_TX_TIMER;
++    adapter->shared.fc_send_xon = 1;
++
++    /* Identify the Hardware - this is done by the gigabit shared code
++     * in e1000_init_hw, but it would help to identify the NIC
++     * before bringing the hardware online for use in e1000_check_options.
++     */
++    if(adapter->shared.mac_type >= e1000_82543) {
++        status = E1000_READ_REG(&adapter->shared, STATUS);
++        if(status & E1000_STATUS_TBIMODE) {
++            adapter->shared.media_type = e1000_media_type_fiber;
++        } else {
++            adapter->shared.media_type = e1000_media_type_copper;
++        }
++    } else {
++        adapter->shared.media_type = e1000_media_type_fiber;
++    }
++
++    if((E1000_REPORT_TX_EARLY == 0) || (E1000_REPORT_TX_EARLY == 1)) {
++        adapter->shared.report_tx_early = E1000_REPORT_TX_EARLY;
++    } else {
++        if(adapter->shared.mac_type < e1000_82543) {
++
++            adapter->shared.report_tx_early = 0;
++        } else {
++            adapter->shared.report_tx_early = 1;
++        }
++    }
++
++    adapter->shared.wait_autoneg_complete = WAITFORLINK_DEFAULT;
++
++    adapter->shared.tbi_compatibility_en = 1;
++
++    atomic_set(&adapter->tx_timeout, 0);
++
++    spin_lock_init(&adapter->stats_lock);
++    spin_lock_init(&adapter->rx_fill_lock);
++
++    return 0;
++}
++
++/**
++ * e1000_hw_init - prepare the hardware
++ * @adapter: board private struct containing configuration
++ *
++ * Returns 0 on success, negative on failure
++ *
++ * Initialize the hardware to a configuration as specified by the
++ * Adapter structure.  The controler is reset, the EEPROM is
++ * verified, the MAC address is set, then the shared initilization
++ * routines are called.
++ **/
++
++static int
++e1000_hw_init(struct e1000_adapter *adapter)
++{
++    struct net_device *netdev = adapter->netdev;
++
++    E1000_DBG("e1000_hw_init\n");
++
++    /* Repartition Pba for greater than 9k mtu
++     * To take effect Ctrl_Rst is required.
++     */
++    if(adapter->rx_buffer_len > E1000_RXBUFFER_8192)
++        E1000_WRITE_REG(&adapter->shared, PBA, E1000_JUMBO_PBA);
++    else
++        E1000_WRITE_REG(&adapter->shared, PBA, E1000_DEFAULT_PBA);
++
++    /* Issue a global reset */
++
++    adapter->shared.adapter_stopped = 0;
++    e1000_adapter_stop(&adapter->shared);
++    adapter->shared.adapter_stopped = 0;
++
++    /* make sure the EEPROM is good */
++
++    if(!e1000_validate_eeprom_checksum(&adapter->shared)) {
++        E1000_ERR("The EEPROM Checksum Is Not Valid\n");
++        return -1;
++    }
++
++    /* copy the MAC address out of the EEPROM */
++
++    e1000_read_address(adapter, adapter->perm_net_addr);
++    memcpy(netdev->dev_addr, adapter->perm_net_addr, netdev->addr_len);
++    memcpy(adapter->shared.mac_addr, netdev->dev_addr, netdev->addr_len);
++
++    e1000_read_part_num(&adapter->shared, &(adapter->part_num));
++
++    if(!e1000_init_hw(&adapter->shared)) {
++        E1000_ERR("Hardware Initialization Failed\n");
++        return -1;
++    }
++
++    e1000_enable_WOL(adapter);
++
++    adapter->shared.get_link_status = 1;
++    e1000_check_for_link(&adapter->shared);
++
++    if(E1000_READ_REG(&adapter->shared, STATUS) & E1000_STATUS_LU)
++        adapter->link_active = TRUE;
++    else
++        adapter->link_active = FALSE;
++
++    if(adapter->link_active == TRUE) {
++        e1000_get_speed_and_duplex(&adapter->shared, &adapter->link_speed,
++                                   &adapter->link_duplex);
++    } else {
++        adapter->link_speed = 0;
++        adapter->link_duplex = 0;
++    }
++
++    e1000_get_bus_info(&adapter->shared);
++
++    return 0;
++}
++
++/**
++ * e1000_read_address - Reads the MAC address from the EEPROM
++ * @adapter: board private structure
++ * @addr: pointer to an array of bytes
++ **/
++
++static void
++e1000_read_address(struct e1000_adapter *adapter,
++                   uint8_t *addr)
++{
++    uint16_t eeprom_word;
++    int i;
++
++    E1000_DBG("e1000_read_address\n");
++
++    for(i = 0; i < NODE_ADDRESS_SIZE; i += 2) {
++        eeprom_word =
++            e1000_read_eeprom(&adapter->shared,
++                              EEPROM_NODE_ADDRESS_BYTE_0 + (i / 2));
++        addr[i] = (uint8_t) (eeprom_word & 0x00FF);
++        addr[i + 1] = (uint8_t) (eeprom_word >> 8);
++    }
++
++    return;
++}
++
++/**
++ * e1000_open - Called when a network interface is made active
++ * @netdev: network interface device structure
++ *
++ * Returns 0 on success, negative value on failure
++ *
++ * The open entry point is called when a network interface is made
++ * active by the system (IFF_UP).  At this point all resources needed
++ * for transmit and receive operations are allocated, the interrupt
++ * handler is registered with the OS, the watchdog timer is started,
++ * and the stack is notified that the interface is ready.
++ **/
++
++int
++e1000_open(struct net_device *netdev)
++{
++    struct e1000_adapter *adapter = netdev->priv;
++
++    E1000_DBG("e1000_open\n");
++
++    /* prevent multiple opens when dealing with iANS */
++
++    if(test_and_set_bit(E1000_BOARD_OPEN, &adapter->flags)) {
++        return -EBUSY;
++    }
++
++    adapter->shared.fc = adapter->shared.original_fc;
++
++    /* e1000_close issues a global reset (e1000_adapter_stop)
++     * so e1000_hw_init must be called again or the hardware
++     * will resume in it's default state
++     */
++    if(e1000_hw_init(adapter) < 0) {
++        clear_bit(E1000_BOARD_OPEN, &adapter->flags);
++        return -EBUSY;
++    }
++#ifdef IANS
++    /* restore VLAN settings */
++    if((IANS_BD_TAGGING_MODE) (ANS_PRIVATE_DATA_FIELD(adapter)->tag_mode) !=
++       IANS_BD_TAGGING_NONE)
++        bd_ans_hw_EnableVLAN(adapter);
++#endif
++
++    adapter->shared.adapter_stopped = 0;
++
++    /* allocate transmit descriptors */
++
++    if(e1000_setup_tx_resources(adapter) != 0) {
++        e1000_adapter_stop(&adapter->shared);
++        clear_bit(E1000_BOARD_OPEN, &adapter->flags);
++        return -ENOMEM;
++    }
++    e1000_configure_tx(adapter);
++
++    /* allocate receive descriptors and buffers */
++
++    if(e1000_setup_rx_resources(adapter) != 0) {
++        e1000_adapter_stop(&adapter->shared);
++        e1000_free_tx_resources(adapter);
++        clear_bit(E1000_BOARD_OPEN, &adapter->flags);
++        return -ENOMEM;
++    }
++    e1000_setup_rctl(adapter);
++    e1000_configure_rx(adapter);
++
++    /* hook the interrupt */
++
++    if(request_irq(netdev->irq, &e1000_intr,
++                   SA_SHIRQ, e1000_driver_name, netdev) != 0) {
++        clear_bit(E1000_BOARD_OPEN, &adapter->flags);
++        e1000_adapter_stop(&adapter->shared);
++        e1000_free_tx_resources(adapter);
++        e1000_free_rx_resources(adapter);
++        clear_bit(E1000_BOARD_OPEN, &adapter->flags);
++        return -EBUSY;
++    }
++
++    /* fill Rx ring with sk_buffs */
++
++    tasklet_init(&adapter->rx_fill_tasklet, e1000_alloc_rx_buffers,
++                 (unsigned long) adapter);
++
++    tasklet_schedule(&adapter->rx_fill_tasklet);
++
++    /* Set the watchdog timer for 2 seconds */
++
++    init_timer(&adapter->timer_id);
++    adapter->timer_id.function = &e1000_watchdog;
++    adapter->timer_id.data = (unsigned long) netdev;
++    mod_timer(&adapter->timer_id, (jiffies + 2 * HZ));
++
++    /* stats accumulated while down are dropped
++     * this does not clear the running total
++     */
++
++    e1000_clear_hw_cntrs(&adapter->shared);
++
++    adapter->int_mask = IMS_ENABLE_MASK;
++    e1000_irq_enable(adapter);
++    netif_start_queue(netdev);
++
++#ifdef MODULE
++
++    /* Incrementing the module use count prevents a driver from being
++     * unloaded while an active network interface is using it.
++     */
++    MOD_INC_USE_COUNT;
++
++#endif
++
++    return 0;
++}
++
++/**
++ * e1000_close - Disables a network interface
++ * @netdev: network interface device structure
++ *
++ * Returns 0, this is not allowed to fail
++ *
++ * The close entry point is called when an interface is de-activated
++ * by the OS.  The hardware is still under the drivers control, but
++ * needs to be disabled.  A global MAC reset is issued to stop the
++ * hardware, and all transmit and receive resources are freed.
++ **/
++
++int
++e1000_close(struct net_device *netdev)
++{
++    struct e1000_adapter *adapter = netdev->priv;
++
++    E1000_DBG("e1000_close\n");
++
++    if(!test_bit(E1000_BOARD_OPEN, &adapter->flags))
++        return 0;
++
++    /* Issue a global reset */
++
++    e1000_adapter_stop((&adapter->shared));
++
++    /* Enable receiver unit after Global reset
++     * for WOL, so that receiver can still recive
++     * wake up packet and will not drop it.
++     */
++    if(adapter->shared.mac_type > e1000_82543)
++        E1000_WRITE_REG(&adapter->shared, RCTL, E1000_RCTL_EN);
++
++    /* free OS resources */
++
++    netif_stop_queue(netdev);
++    free_irq(netdev->irq, netdev);
++    del_timer_sync(&adapter->timer_id);
++
++    /* Make sure the tasklet won't be left after ifconfig down */
++
++    /*
++     * Assumption: tasklet is ALREADY enabled, ie, t->count == 0.
++     * Otherwise, tasklet is still left in the tasklet list, and,
++     * tasklet_kill will not be able to return (hang).
++     */
++    tasklet_kill(&adapter->rx_fill_tasklet);
++
++    /* free software resources */
++
++    e1000_free_tx_resources(adapter);
++    e1000_free_rx_resources(adapter);
++
++#ifdef MODULE
++
++    /* decrement the module usage count
++     * so that the driver can be unloaded
++     */
++    MOD_DEC_USE_COUNT;
++
++#endif
++
++    clear_bit(E1000_BOARD_OPEN, &adapter->flags);
++    return 0;
++}
++
++/**
++ * e1000_setup_tx_resources - allocate Tx resources (Descriptors)
++ * @adapter: board private structure
++ *
++ * Return 0 on success, negative on failure
++ *
++ * e1000_setup_tx_resources allocates all software transmit resources
++ * and enabled the Tx unit of the MAC.
++ **/
++
++static int
++e1000_setup_tx_resources(struct e1000_adapter *adapter)
++{
++    struct pci_dev *pdev = adapter->pdev;
++    int size;
++
++    E1000_DBG("e1000_setup_tx_resources\n");
++
++    size = sizeof(struct e1000_buffer) * adapter->tx_ring.count;
++    adapter->tx_ring.buffer_info = kmalloc(size, GFP_KERNEL);
++    if(adapter->tx_ring.buffer_info == NULL) {
++        return -ENOMEM;
++    }
++    memset(adapter->tx_ring.buffer_info, 0, size);
++
++    /* round up to nearest 4K */
++
++    adapter->tx_ring.size = E1000_ROUNDUP2(adapter->tx_ring.count *
++                                           sizeof(struct e1000_tx_desc),
++                                           4096);
++
++    adapter->tx_ring.desc = pci_alloc_consistent(pdev, adapter->tx_ring.size,
++                                                 &adapter->tx_ring.dma);
++    if(adapter->tx_ring.desc == NULL) {
++        kfree(adapter->tx_ring.buffer_info);
++        return -ENOMEM;
++    }
++    memset(adapter->tx_ring.desc, 0, adapter->tx_ring.size);
++
++    atomic_set(&adapter->tx_ring.unused, adapter->tx_ring.count);
++    adapter->tx_ring.next_to_use = 0;
++    adapter->tx_ring.next_to_clean = 0;
++
++    return 0;
++}
++
++/**
++ * e1000_configure_tx - Configure 8254x Transmit Unit after Reset
++ * @adapter: board private structure
++ *
++ * Configure the Tx unit of the MAC after a reset.
++ **/
++
++static void
++e1000_configure_tx(struct e1000_adapter *adapter)
++{
++    uint32_t tctl, tipg;
++
++    /* Setup the Base and Length of the Rx Descriptor Ring */
++    /* tx_ring.dma can be either a 32 or 64 bit value */
++
++#if (BITS_PER_LONG == 32)
++    E1000_WRITE_REG(&adapter->shared, TDBAL, adapter->tx_ring.dma);
++    E1000_WRITE_REG(&adapter->shared, TDBAH, 0);
++#elif ( BITS_PER_LONG == 64)
++    E1000_WRITE_REG(&adapter->shared, TDBAL,
++                    (uint32_t) (adapter->tx_ring.dma & 0x00000000FFFFFFFF));
++    E1000_WRITE_REG(&adapter->shared, TDBAH,
++                    (uint32_t) (adapter->tx_ring.dma >> 32));
++#else
++#error "Unsupported System - does not use 32 or 64 bit pointers!"
++#endif
++
++    E1000_WRITE_REG(&adapter->shared, TDLEN,
++                    adapter->tx_ring.count * sizeof(struct e1000_tx_desc));
++
++    /* Setup the HW Tx Head and Tail descriptor pointers */
++
++    E1000_WRITE_REG(&adapter->shared, TDH, 0);
++    E1000_WRITE_REG(&adapter->shared, TDT, 0);
++
++    /* Set the default values for the Tx Inter Packet Gap timer */
++
++    switch (adapter->shared.mac_type) {
++    case e1000_82543:
++    case e1000_82544:
++    case e1000_82540:
++        if(adapter->shared.media_type == e1000_media_type_fiber)
++            tipg = DEFAULT_82543_TIPG_IPGT_FIBER;
++        else
++            tipg = DEFAULT_82543_TIPG_IPGT_COPPER;
++        tipg |= DEFAULT_82543_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT;
++        tipg |= DEFAULT_82543_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT;
++        break;
++    case e1000_82542_rev2_0:
++    case e1000_82542_rev2_1:
++    default:
++        tipg = DEFAULT_82542_TIPG_IPGT;
++        tipg |= DEFAULT_82542_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT;
++        tipg |= DEFAULT_82542_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT;
++        break;
++    }
++    E1000_WRITE_REG(&adapter->shared, TIPG, tipg);
++
++    /* Set the Tx Interrupt Delay register */
++
++    E1000_WRITE_REG(&adapter->shared, TIDV, adapter->tx_int_delay);
++
++    /* Program the Transmit Control Register */
++
++    tctl =
++        E1000_TCTL_PSP | E1000_TCTL_EN | (E1000_COLLISION_THRESHOLD <<
++                                          E1000_CT_SHIFT);
++    if(adapter->link_duplex == FULL_DUPLEX) {
++        tctl |= E1000_FDX_COLLISION_DISTANCE << E1000_COLD_SHIFT;
++    } else {
++        tctl |= E1000_HDX_COLLISION_DISTANCE << E1000_COLD_SHIFT;
++    }
++    E1000_WRITE_REG(&adapter->shared, TCTL, tctl);
++
++#ifdef CONFIG_PPC
++    if(adapter->shared.mac_type >= e1000_82543) {
++        E1000_WRITE_REG(&adapter->shared, TXDCTL, 0x00020000);
++    }
++#endif
++
++    /* Setup Transmit Descriptor Settings for this adapter */
++    adapter->TxdCmd = E1000_TXD_CMD_IFCS;
++
++    if(adapter->tx_int_delay > 0)
++        adapter->TxdCmd |= E1000_TXD_CMD_IDE;
++    if(adapter->shared.report_tx_early == 1)
++        adapter->TxdCmd |= E1000_TXD_CMD_RS;
++    else
++        adapter->TxdCmd |= E1000_TXD_CMD_RPS;
++
++    adapter->ActiveChecksumContext = OFFLOAD_NONE;
++
++    return;
++}
++
++/**
++ * e1000_setup_rx_resources - allocate Rx resources (Descriptors, receive SKBs)
++ * @adapter: board private structure
++ * 
++ * Returns 0 on success, negative on failure
++ *
++ * e1000_setup_rx_resources allocates all software receive resources
++ * and network buffers, and enables the Rx unit of the MAC.
++ **/
++
++static int
++e1000_setup_rx_resources(struct e1000_adapter *adapter)
++{
++    struct pci_dev *pdev = adapter->pdev;
++    int size;
++
++    E1000_DBG("e1000_setup_rx_resources\n");
++
++    size = sizeof(struct e1000_buffer) * adapter->rx_ring.count;
++    adapter->rx_ring.buffer_info = kmalloc(size, GFP_KERNEL);
++    if(adapter->rx_ring.buffer_info == NULL) {
++        return -ENOMEM;
++    }
++    memset(adapter->rx_ring.buffer_info, 0, size);
++
++    /* Round up to nearest 4K */
++
++    adapter->rx_ring.size = E1000_ROUNDUP2(adapter->rx_ring.count *
++                                           sizeof(struct e1000_rx_desc),
++                                           4096);
++
++    adapter->rx_ring.desc = pci_alloc_consistent(pdev, adapter->rx_ring.size, 
++                                                 &adapter->rx_ring.dma);
++
++    if(adapter->rx_ring.desc == NULL) {
++        kfree(adapter->rx_ring.buffer_info);
++        return -ENOMEM;
++    }
++    memset(adapter->rx_ring.desc, 0, adapter->rx_ring.size);
++
++    adapter->rx_ring.next_to_clean = 0;
++    atomic_set(&adapter->rx_ring.unused, adapter->rx_ring.count);
++
++    adapter->rx_ring.next_to_use = 0;
++
++    return 0;
++}
++
++/**
++ * e1000_setup_rctl - configure the receive control register
++ * @adapter: Board private structure
++ **/
++
++static void
++e1000_setup_rctl(struct e1000_adapter *adapter)
++{
++    uint32_t rctl;
++
++    /* Setup the Receive Control Register */
++    rctl =
++        E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_LBM_NO |
++        E1000_RCTL_RDMTS_HALF | (adapter->shared.
++                                 mc_filter_type << E1000_RCTL_MO_SHIFT);
++
++    if(adapter->shared.tbi_compatibility_on == 1)
++        rctl |= E1000_RCTL_SBP;
++
++    switch (adapter->rx_buffer_len) {
++    case E1000_RXBUFFER_2048:
++    default:
++        rctl |= E1000_RCTL_SZ_2048;
++        break;
++    case E1000_RXBUFFER_4096:
++        rctl |= E1000_RCTL_SZ_4096 | E1000_RCTL_BSEX | E1000_RCTL_LPE;
++        break;
++    case E1000_RXBUFFER_8192:
++        rctl |= E1000_RCTL_SZ_8192 | E1000_RCTL_BSEX | E1000_RCTL_LPE;
++        break;
++    case E1000_RXBUFFER_16384:
++        rctl |= E1000_RCTL_SZ_16384 | E1000_RCTL_BSEX | E1000_RCTL_LPE;
++        break;
++    }
++
++    E1000_WRITE_REG(&adapter->shared, RCTL, rctl);
++}
++
++/**
++ * e1000_configure_rx - Configure 8254x Receive Unit after Reset
++ * @adapter: board private structure
++ *
++ * Configure the Rx unit of the MAC after a reset.
++ **/
++
++static void
++e1000_configure_rx(struct e1000_adapter *adapter)
++{
++    uint32_t rctl;
++    uint32_t rxcsum;
++
++    /* make sure receives are disabled while setting up the descriptor ring */
++    rctl = E1000_READ_REG(&adapter->shared, RCTL);
++    E1000_WRITE_REG(&adapter->shared, RCTL, rctl & ~E1000_RCTL_EN);
++
++    /* set the Receive Delay Timer Register */
++    E1000_WRITE_REG(&adapter->shared, RDTR,
++                    adapter->rx_int_delay | E1000_RDT_FPDB);
++
++    /* Setup the Base and Length of the Rx Descriptor Ring */
++    /* rx_ring.dma can be either a 32 or 64 bit value */
++
++#if (BITS_PER_LONG == 32)
++    E1000_WRITE_REG(&adapter->shared, RDBAL, adapter->rx_ring.dma);
++    E1000_WRITE_REG(&adapter->shared, RDBAH, 0);
++#elif ( BITS_PER_LONG == 64)
++    E1000_WRITE_REG(&adapter->shared, RDBAL,
++                    (uint32_t) (adapter->rx_ring.dma & 0x00000000FFFFFFFF));
++    E1000_WRITE_REG(&adapter->shared, RDBAH,
++                    (uint32_t) (adapter->rx_ring.dma >> 32));
++#else
++#error "Unsupported System - does not use 32 or 64 bit pointers!"
++#endif
++
++    E1000_WRITE_REG(&adapter->shared, RDLEN,
++                    adapter->rx_ring.count * sizeof(struct e1000_rx_desc));
++
++    /* Setup the HW Rx Head and Tail Descriptor Pointers */
++    E1000_WRITE_REG(&adapter->shared, RDH, 0);
++    E1000_WRITE_REG(&adapter->shared, RDT, 0);
++
++    /* Enable 82543 Receive Checksum Offload for TCP and UDP */
++    if((adapter->shared.mac_type >= e1000_82543) &&
++       (adapter->RxChecksum == TRUE)) {
++        rxcsum = E1000_READ_REG(&adapter->shared, RXCSUM);
++        rxcsum |= E1000_RXCSUM_TUOFL;
++        E1000_WRITE_REG(&adapter->shared, RXCSUM, rxcsum);
++    }
++#ifdef CONFIG_PPC
++    if(adapter->shared.mac_type >= e1000_82543) {
++        E1000_WRITE_REG(&adapter->shared, RXDCTL, 0x00020000);
++    }
++#endif
++
++    /* Enable Receives */
++    E1000_WRITE_REG(&adapter->shared, RCTL, rctl);
++
++    return;
++}
++
++/**
++ * e1000_free_tx_resources - Free Tx Resources
++ * @adapter: board private structure
++ *
++ * Free all transmit software resources
++ **/
++
++static void
++e1000_free_tx_resources(struct e1000_adapter *adapter)
++{
++    struct pci_dev *pdev = adapter->pdev;
++
++    E1000_DBG("e1000_free_tx_resources\n");
++
++    e1000_clean_tx_ring(adapter);
++
++    kfree(adapter->tx_ring.buffer_info);
++    adapter->tx_ring.buffer_info = NULL;
++
++    pci_free_consistent(pdev, adapter->tx_ring.size, adapter->tx_ring.desc,
++                        adapter->tx_ring.dma);
++
++    adapter->tx_ring.desc = NULL;
++
++    return;
++}
++
++/**
++ * e1000_clean_tx_ring - Free Tx Buffers
++ * @adapter: board private structure
++ **/
++
++static void
++e1000_clean_tx_ring(struct e1000_adapter *adapter)
++{
++    struct pci_dev *pdev = adapter->pdev;
++    unsigned long size;
++    int i;
++
++    /* Free all the Tx ring sk_buffs */
++
++    for(i = 0; i < adapter->tx_ring.count; i++) {
++        if(adapter->tx_ring.buffer_info[i].skb != NULL) {
++
++            pci_unmap_page(pdev, adapter->tx_ring.buffer_info[i].dma,
++                           adapter->tx_ring.buffer_info[i].length,
++                           PCI_DMA_TODEVICE);
++
++            dev_kfree_skb(adapter->tx_ring.buffer_info[i].skb);
++
++            adapter->tx_ring.buffer_info[i].skb = NULL;
++        }
++    }
++
++    size = sizeof(struct e1000_buffer) * adapter->tx_ring.count;
++    memset(adapter->tx_ring.buffer_info, 0, size);
++
++    /* Zero out the descriptor ring */
++
++    memset(adapter->tx_ring.desc, 0, adapter->tx_ring.size);
++
++    atomic_set(&adapter->tx_ring.unused, adapter->tx_ring.count);
++    adapter->tx_ring.next_to_use = 0;
++    adapter->tx_ring.next_to_clean = 0;
++
++    return;
++}
++
++/**
++ * e1000_free_rx_resources - Free Rx Resources
++ * @adapter: board private structure
++ *
++ * Free all receive software resources
++ **/
++
++static void
++e1000_free_rx_resources(struct e1000_adapter *adapter)
++{
++    struct pci_dev *pdev = adapter->pdev;
++
++    E1000_DBG("e1000_free_rx_resources\n");
++
++    tasklet_disable(&adapter->rx_fill_tasklet);
++
++    e1000_clean_rx_ring(adapter);
++
++    kfree(adapter->rx_ring.buffer_info);
++    adapter->rx_ring.buffer_info = NULL;
++
++    pci_free_consistent(pdev, adapter->rx_ring.size, adapter->rx_ring.desc,
++                        adapter->rx_ring.dma);
++
++    adapter->rx_ring.desc = NULL;
++
++    return;
++}
++
++/**
++ * e1000_clean_rx_ring - Free Rx Buffers
++ * @adapter: board private structure
++ **/
++
++static void
++e1000_clean_rx_ring(struct e1000_adapter *adapter)
++{
++    struct pci_dev *pdev = adapter->pdev;
++    unsigned long size;
++    int i;
++
++    /* Free all the Rx ring sk_buffs */
++
++    for(i = 0; i < adapter->rx_ring.count; i++) {
++        if(adapter->rx_ring.buffer_info[i].skb != NULL) {
++
++            pci_unmap_single(pdev, adapter->rx_ring.buffer_info[i].dma,
++                             adapter->rx_ring.buffer_info[i].length,
++                             PCI_DMA_FROMDEVICE);
++
++            dev_kfree_skb(adapter->rx_ring.buffer_info[i].skb);
++
++            adapter->rx_ring.buffer_info[i].skb = NULL;
++        }
++    }
++
++    size = sizeof(struct e1000_buffer) * adapter->rx_ring.count;
++    memset(adapter->rx_ring.buffer_info, 0, size);
++
++    /* Zero out the descriptor ring */
++
++    memset(adapter->rx_ring.desc, 0, adapter->rx_ring.size);
++
++    atomic_set(&adapter->rx_ring.unused, adapter->rx_ring.count);
++    adapter->rx_ring.next_to_clean = 0;
++    adapter->rx_ring.next_to_use = 0;
++
++    return;
++}
++
++/**
++ * e1000_set_multi - Multicast and Promiscuous mode set
++ * @netdev: network interface device structure
++ *
++ * The set_multi entry point is called whenever the multicast address
++ * list or the network interface flags are updated.  This routine is
++ * resposible for configuring the hardware for proper multicast,
++ * promiscuous mode, and all-multi behavior.
++ **/
++
++void
++e1000_set_multi(struct net_device *netdev)
++{
++    struct e1000_adapter *adapter = netdev->priv;
++    struct pci_dev *pdev = adapter->pdev;
++    uint32_t rctl;
++    uint8_t mta[MAX_NUM_MULTICAST_ADDRESSES * ETH_LENGTH_OF_ADDRESS];
++    uint16_t pci_command_word;
++    struct dev_mc_list *mc_ptr;
++    int i;
++
++    E1000_DBG("e1000_set_multi\n");
++
++    rctl = E1000_READ_REG(&adapter->shared, RCTL);
++
++    if(adapter->shared.mac_type == e1000_82542_rev2_0) {
++        if(adapter->shared.pci_cmd_word & PCI_COMMAND_INVALIDATE) {
++            pci_command_word =
++                adapter->shared.pci_cmd_word & ~PCI_COMMAND_INVALIDATE;
++            pci_write_config_word(pdev, PCI_COMMAND, pci_command_word);
++        }
++        rctl |= E1000_RCTL_RST;
++        E1000_WRITE_REG(&adapter->shared, RCTL, rctl);
++        mdelay(5);
++        if(test_bit(E1000_BOARD_OPEN, &adapter->flags)) {
++            tasklet_disable(&adapter->rx_fill_tasklet);
++            e1000_clean_rx_ring(adapter);
++        }
++    }
++
++    /* Check for Promiscuous and All Multicast modes */
++
++    if(netdev->flags & IFF_PROMISC) {
++        rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE);
++    } else if(netdev->flags & IFF_ALLMULTI) {
++        rctl |= E1000_RCTL_MPE;
++        rctl &= ~E1000_RCTL_UPE;
++    } else {
++        rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE);
++    }
++
++    if(netdev->mc_count > MAX_NUM_MULTICAST_ADDRESSES) {
++        rctl |= E1000_RCTL_MPE;
++        E1000_WRITE_REG(&adapter->shared, RCTL, rctl);
++    } else {
++        E1000_WRITE_REG(&adapter->shared, RCTL, rctl);
++        for(i = 0, mc_ptr = netdev->mc_list; mc_ptr; i++, mc_ptr = mc_ptr->next)
++            memcpy(&mta[i * ETH_LENGTH_OF_ADDRESS], mc_ptr->dmi_addr,
++                   ETH_LENGTH_OF_ADDRESS);
++        e1000_mc_addr_list_update(&adapter->shared, mta, netdev->mc_count, 0);
++    }
++
++    if(adapter->shared.mac_type == e1000_82542_rev2_0) {
++        rctl = E1000_READ_REG(&adapter->shared, RCTL);
++        rctl &= ~E1000_RCTL_RST;
++        E1000_WRITE_REG(&adapter->shared, RCTL, rctl);
++        mdelay(5);
++        if(adapter->shared.pci_cmd_word & PCI_COMMAND_INVALIDATE) {
++            pci_write_config_word(pdev, PCI_COMMAND,
++                                  adapter->shared.pci_cmd_word);
++        }
++        if(test_bit(E1000_BOARD_OPEN, &adapter->flags)) {
++            e1000_configure_rx(adapter);
++            tasklet_enable(&adapter->rx_fill_tasklet);
++        }
++    }
++
++    return;
++}
++
++#ifdef IANS
++
++/* flush Tx queue without link */
++static void
++e1000_tx_flush(struct e1000_adapter *adapter)
++{
++    uint32_t ctrl, txcw, icr;
++
++    adapter->int_mask = 0;
++    e1000_irq_disable(adapter);
++    synchronize_irq();
++
++    if(adapter->shared.mac_type < e1000_82543) {
++        /* Transmit Unit Reset */
++        E1000_WRITE_REG(&adapter->shared, TCTL, E1000_TCTL_RST);
++        E1000_WRITE_REG(&adapter->shared, TCTL, 0);
++        e1000_clean_tx_ring(adapter);
++        e1000_configure_tx(adapter);
++    } else {
++        /* turn off autoneg, set link up, and invert loss of signal */
++        txcw = E1000_READ_REG(&adapter->shared, TXCW);
++        ctrl = E1000_READ_REG(&adapter->shared, CTRL);
++        E1000_WRITE_REG(&adapter->shared, TXCW, txcw & ~E1000_TXCW_ANE);
++        E1000_WRITE_REG(&adapter->shared, CTRL,
++                        (ctrl | E1000_CTRL_SLU | E1000_CTRL_ILOS));
++        /* delay to flush queue, then clean up */
++        mdelay(20);
++        e1000_clean_tx_irq(adapter);
++        E1000_WRITE_REG(&adapter->shared, CTRL, ctrl);
++        E1000_WRITE_REG(&adapter->shared, TXCW, txcw);
++        /* clear the link status change interrupts this caused */
++        icr = E1000_READ_REG(&adapter->shared, ICR);
++    }
++
++    adapter->int_mask = IMS_ENABLE_MASK;
++    e1000_irq_enable(adapter);
++    return;
++}
++#endif
++
++/**
++ * e1000_watchdog - Timer Call-back
++ * @data: pointer to netdev cast into an unsigned long
++ **/
++
++void
++e1000_watchdog(unsigned long data)
++{
++    struct net_device *netdev = (struct net_device *) data;
++    struct e1000_adapter *adapter = netdev->priv;
++
++#ifdef IANS
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0))
++    int flags;
++#endif
++#endif
++
++    e1000_check_for_link(&adapter->shared);
++
++    if (test_and_clear_bit(E1000_LINK_STATUS_CHANGED, &adapter->flags))
++        e1000_phy_get_info(&adapter->shared, &adapter->phy_info);
++
++    if(E1000_READ_REG(&adapter->shared, STATUS) & E1000_STATUS_LU) {
++        if(adapter->link_active != TRUE) {
++
++#ifdef IANS
++            if((adapter->iANSdata->iANS_status == IANS_COMMUNICATION_UP) &&
++               (adapter->iANSdata->reporting_mode == IANS_STATUS_REPORTING_ON))
++                if(ans_notify)
++                    ans_notify(netdev, IANS_IND_XMIT_QUEUE_READY);
++#endif
++            netif_wake_queue(netdev);
++
++            e1000_get_speed_and_duplex(&adapter->shared, &adapter->link_speed,
++                                       &adapter->link_duplex);
++            printk(KERN_ERR "e1000: %s NIC Link is Up %d Mbps %s\n",
++                   netdev->name, adapter->link_speed,
++                   adapter->link_duplex ==
++                   FULL_DUPLEX ? "Full Duplex" : "Half Duplex");
++
++            adapter->link_active = TRUE;
++            set_bit(E1000_LINK_STATUS_CHANGED, &adapter->flags);
++        }
++    } else {
++        if(adapter->link_active != FALSE) {
++            adapter->link_speed = 0;
++            adapter->link_duplex = 0;
++            printk(KERN_ERR "e1000: %s NIC Link is Down\n", netdev->name);
++            adapter->link_active = FALSE;
++            atomic_set(&adapter->tx_timeout, 0);
++        }
++    }
++
++    e1000_update_stats(adapter);
++
++    if(atomic_read(&adapter->tx_timeout) > 1)
++        atomic_dec(&adapter->tx_timeout);
++
++    if((adapter->link_active == TRUE) && 
++       (atomic_read(&adapter->tx_timeout) == 1)) {
++
++        if(E1000_READ_REG(&adapter->shared, STATUS) & E1000_STATUS_TXOFF) {
++            atomic_set(&adapter->tx_timeout, 3);
++        } else {
++
++            e1000_hibernate_adapter(netdev);
++
++#ifdef IANS
++        if((adapter->iANSdata->iANS_status == IANS_COMMUNICATION_UP) &&
++           (adapter->iANSdata->reporting_mode == IANS_STATUS_REPORTING_ON)) {
++                adapter->link_active = FALSE;
++                bd_ans_os_Watchdog(netdev, adapter);
++                adapter->link_active = TRUE;
++            }
++#endif
++            atomic_set(&adapter->tx_timeout, 0);
++            e1000_wakeup_adapter(netdev);
++        }
++    }
++#ifdef IANS
++    if(adapter->iANSdata->iANS_status == IANS_COMMUNICATION_UP) {
++
++        if(adapter->iANSdata->reporting_mode == IANS_STATUS_REPORTING_ON)
++            bd_ans_os_Watchdog(netdev, adapter);
++
++        if(adapter->link_active == FALSE) {
++            /* don't sit on SKBs while link is down */
++
++            if(atomic_read(&adapter->tx_ring.unused) < adapter->tx_ring.count) {
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0))
++                spin_lock_irqsave(&netdev->xmit_lock, flags);
++                e1000_tx_flush(adapter);
++                spin_unlock_irqrestore(&netdev->xmit_lock, flags);
++#else
++                e1000_tx_flush(adapter);
++#endif
++            }
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0))
++            spin_lock_irqsave(&netdev->queue_lock, flags);
++            qdisc_reset(netdev->qdisc);
++            spin_unlock_irqrestore(&netdev->queue_lock, flags);
++#else
++            qdisc_reset(netdev->qdisc);
++#endif
++        }
++    }
++#endif
++
++    if(test_bit(E1000_RX_REFILL, &adapter->flags)) {
++        tasklet_schedule(&adapter->rx_fill_tasklet);
++    }
++
++    /* Reset the timer */
++    mod_timer(&adapter->timer_id, jiffies + 2 * HZ);
++
++    return;
++}
++
++/**
++ * e1000_tx_checksum_setup
++ * @adapter:
++ * @skb:
++ * @txd_upper:
++ * @txd_lower:
++ **/
++
++static inline void
++e1000_tx_checksum_setup(struct e1000_adapter *adapter,
++                        struct sk_buff *skb,
++                        uint32_t *txd_upper,
++                        uint32_t *txd_lower)
++{
++
++    struct e1000_context_desc *desc;
++    int i;
++
++    if(skb->protocol != __constant_htons(ETH_P_IP)) {
++        *txd_upper = 0;
++        *txd_lower = adapter->TxdCmd;
++        return;
++    }
++
++    switch (skb->nh.iph->protocol) {
++    case IPPROTO_TCP:
++        /* Offload TCP checksum */
++        *txd_upper = E1000_TXD_POPTS_TXSM << 8;
++        *txd_lower = adapter->TxdCmd | E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D;
++        if(adapter->ActiveChecksumContext == OFFLOAD_TCP_IP)
++            return;
++        else
++            adapter->ActiveChecksumContext = OFFLOAD_TCP_IP;
++        break;
++    case IPPROTO_UDP:
++        /* Offload UDP checksum */
++        *txd_upper = E1000_TXD_POPTS_TXSM << 8;
++        *txd_lower = adapter->TxdCmd | E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D;
++        if(adapter->ActiveChecksumContext == OFFLOAD_UDP_IP)
++            return;
++        else
++            adapter->ActiveChecksumContext = OFFLOAD_UDP_IP;
++        break;
++    default:
++        /* no checksum to offload */
++        *txd_upper = 0;
++        *txd_lower = adapter->TxdCmd;
++        return;
++    }
++
++    /* If we reach this point, the checksum offload context
++     * needs to be reset
++     */
++
++    i = adapter->tx_ring.next_to_use;
++    desc = E1000_CONTEXT_DESC(adapter->tx_ring, i);
++
++    desc->lower_setup.ip_fields.ipcss = skb->nh.raw - skb->data;
++    desc->lower_setup.ip_fields.ipcso =
++        ((skb->nh.raw + offsetof(struct iphdr, check)) - skb->data);
++    desc->lower_setup.ip_fields.ipcse = cpu_to_le16(skb->h.raw - skb->data - 1);
++
++    desc->upper_setup.tcp_fields.tucss = (skb->h.raw - skb->data);
++    desc->upper_setup.tcp_fields.tucso = ((skb->h.raw + skb->csum) - skb->data);
++    desc->upper_setup.tcp_fields.tucse = 0;
++
++    desc->tcp_seg_setup.data = 0;
++    desc->cmd_and_length = cpu_to_le32(E1000_TXD_CMD_DEXT) | adapter->TxdCmd;
++
++    i = (i + 1) % adapter->tx_ring.count;
++    atomic_dec(&adapter->tx_ring.unused);
++    adapter->tx_ring.next_to_use = i;
++    E1000_WRITE_REG(&adapter->shared, TDT, adapter->tx_ring.next_to_use);
++    return;
++}
++
++/**
++ * e1000_xmit_frame - Transmit entry point
++ * @skb: buffer with frame data to transmit
++ * @netdev: network interface device structure
++ *
++ * Returns 0 on success, negative on error
++ *
++ * e1000_xmit_frame is called by the stack to initiate a transmit.
++ * The out of resource condition is checked after each successful Tx
++ * so that the stack can be notified, preventing the driver from
++ * ever needing to drop a frame.  The atomic operations on
++ * tx_ring.unused are used to syncronize with the transmit
++ * interrupt processing code without the need for a spinlock.
++ **/
++
++int
++e1000_xmit_frame(struct sk_buff *skb,
++                 struct net_device *netdev)
++{
++    struct e1000_adapter *adapter = netdev->priv;
++    struct pci_dev *pdev = adapter->pdev;
++    struct e1000_tx_desc *tx_desc;
++    int i, len, offset, txd_needed;
++    uint32_t txd_upper, txd_lower;
++
++#define TXD_USE_COUNT(x) (((x) >> 12) + ((x) & 0x0fff ? 1 : 0))
++
++#ifdef MAX_SKB_FRAGS
++    int f;
++    skb_frag_t *frag;
++#endif
++
++    E1000_DBG("e1000_xmit_frame\n");
++
++    if(adapter->link_active == FALSE) {
++#ifdef IANS
++        if((adapter->iANSdata->iANS_status == IANS_COMMUNICATION_UP) &&
++           (adapter->iANSdata->reporting_mode == IANS_STATUS_REPORTING_ON))
++            if(ans_notify)
++                ans_notify(netdev, IANS_IND_XMIT_QUEUE_FULL);
++#endif
++        netif_stop_queue(netdev);
++        return 1;
++    }
++
++#ifdef MAX_SKB_FRAGS
++    txd_needed = TXD_USE_COUNT(skb->len - skb->data_len);
++    for(f = 0; f < skb_shinfo(skb)->nr_frags; f++) {
++        frag = &skb_shinfo(skb)->frags[f];
++        txd_needed += TXD_USE_COUNT(frag->size);
++    }
++#else
++    txd_needed = TXD_USE_COUNT(skb->len);
++#endif
++
++    /* make sure there are enough Tx descriptors available in the ring */
++    if(atomic_read(&adapter->tx_ring.unused) <= (txd_needed + 1)) {
++        adapter->net_stats.tx_dropped++;
++#ifdef IANS
++        if((adapter->iANSdata->iANS_status == IANS_COMMUNICATION_UP) &&
++           (adapter->iANSdata->reporting_mode == IANS_STATUS_REPORTING_ON))
++            if(ans_notify)
++                ans_notify(netdev, IANS_IND_XMIT_QUEUE_FULL);
++#endif
++        netif_stop_queue(netdev);
++
++        return 1;
++    }
++
++    if(skb->ip_summed == CHECKSUM_HW) {
++        e1000_tx_checksum_setup(adapter, skb, &txd_upper, &txd_lower);
++    } else {
++        txd_upper = 0;
++        txd_lower = adapter->TxdCmd;
++    }
++
++    i = adapter->tx_ring.next_to_use;
++    tx_desc = E1000_TX_DESC(adapter->tx_ring, i);
++
++#ifdef IANS
++    if(adapter->iANSdata->iANS_status == IANS_COMMUNICATION_UP) {
++        tx_desc->lower.data = cpu_to_le32(txd_lower);
++        tx_desc->upper.data = cpu_to_le32(txd_upper);
++        if(bd_ans_os_Transmit(adapter, tx_desc, &skb) == BD_ANS_FAILURE) {
++            return 1;
++        }
++        txd_lower = le32_to_cpu(tx_desc->lower.data);
++        txd_upper = le32_to_cpu(tx_desc->upper.data);
++    }
++#endif
++
++#ifdef MAX_SKB_FRAGS
++    len = skb->len - skb->data_len;
++#else
++    len = skb->len;
++#endif
++    offset = 0;
++
++    while(len > 4096) {
++        adapter->tx_ring.buffer_info[i].length = 4096;
++        adapter->tx_ring.buffer_info[i].dma =
++            pci_map_page(pdev, virt_to_page(skb->data + offset),
++                         (unsigned long) (skb->data + offset) & ~PAGE_MASK,
++                         4096, PCI_DMA_TODEVICE);
++
++        tx_desc->buffer_addr = cpu_to_le64(adapter->tx_ring.buffer_info[i].dma);
++        tx_desc->lower.data = cpu_to_le32(txd_lower | 4096);
++        tx_desc->upper.data = cpu_to_le32(txd_upper);
++
++        len -= 4096;
++        offset += 4096;
++        i = (i + 1) % adapter->tx_ring.count;
++        atomic_dec(&adapter->tx_ring.unused);
++        tx_desc = E1000_TX_DESC(adapter->tx_ring, i);
++    }
++    adapter->tx_ring.buffer_info[i].length = len;
++    adapter->tx_ring.buffer_info[i].dma =
++        pci_map_page(pdev, virt_to_page(skb->data + offset),
++                     (unsigned long) (skb->data + offset) & ~PAGE_MASK, len,
++                     PCI_DMA_TODEVICE);
++
++    tx_desc->buffer_addr = cpu_to_le64(adapter->tx_ring.buffer_info[i].dma);
++    tx_desc->lower.data = cpu_to_le32(txd_lower | len);
++    tx_desc->upper.data = cpu_to_le32(txd_upper);
++
++#ifdef MAX_SKB_FRAGS
++    for(f = 0; f < skb_shinfo(skb)->nr_frags; f++) {
++        frag = &skb_shinfo(skb)->frags[f];
++        i = (i + 1) % adapter->tx_ring.count;
++        atomic_dec(&adapter->tx_ring.unused);
++        tx_desc = E1000_TX_DESC(adapter->tx_ring, i);
++
++        len = frag->size;
++        offset = 0;
++
++        while(len > 4096) {
++            adapter->tx_ring.buffer_info[i].length = 4096;
++            adapter->tx_ring.buffer_info[i].dma =
++                pci_map_page(pdev, frag->page, frag->page_offset + offset,
++                             4096, PCI_DMA_TODEVICE);
++
++            tx_desc->buffer_addr =
++                cpu_to_le64(adapter->tx_ring.buffer_info[i].dma);
++            tx_desc->lower.data = cpu_to_le32(txd_lower | 4096);
++            tx_desc->upper.data = cpu_to_le32(txd_upper);
++
++            len -= 4096;
++            offset += 4096;
++            i = (i + 1) % adapter->tx_ring.count;
++            atomic_dec(&adapter->tx_ring.unused);
++            tx_desc = E1000_TX_DESC(adapter->tx_ring, i);
++        }
++        adapter->tx_ring.buffer_info[i].length = len;
++        adapter->tx_ring.buffer_info[i].dma =
++            pci_map_page(pdev, frag->page, frag->page_offset + offset, len,
++                         PCI_DMA_TODEVICE);
++        tx_desc->buffer_addr =
++            cpu_to_le64(adapter->tx_ring.buffer_info[i].dma);
++
++        tx_desc->lower.data = cpu_to_le32(txd_lower | len);
++        tx_desc->upper.data = cpu_to_le32(txd_upper);
++    }
++#endif
++    
++    /* EOP and SKB pointer go with the last fragment */
++    tx_desc->lower.data |= cpu_to_le32(E1000_TXD_CMD_EOP);
++    adapter->tx_ring.buffer_info[i].skb = skb;
++
++    i = (i + 1) % adapter->tx_ring.count;
++    atomic_dec(&adapter->tx_ring.unused);
++
++    /* Move the HW Tx Tail Pointer */
++    adapter->tx_ring.next_to_use = i;
++
++    E1000_WRITE_REG(&adapter->shared, TDT, adapter->tx_ring.next_to_use);
++
++    if(atomic_read(&adapter->tx_timeout) == 0)
++        atomic_set(&adapter->tx_timeout, 3);
++
++    netdev->trans_start = jiffies;
++
++    return 0;
++}
++
++/**
++ * e1000_get_stats - Get System Network Statistics
++ * @netdev: network interface device structure
++ *
++ * Returns the address of the device statistics structure.
++ * The statistics are actually updated from the timer callback.
++ **/
++
++struct net_device_stats *
++e1000_get_stats(struct net_device *netdev)
++{
++    struct e1000_adapter *adapter = netdev->priv;
++
++    E1000_DBG("e1000_get_stats\n");
++
++    return &adapter->net_stats;
++}
++
++/**
++ * e1000_change_mtu - Change the Maximum Transfer Unit
++ * @netdev: network interface device structure
++ * @new_mtu: new value for maximum frame size
++ *
++ * Returns 0 on success, negative on failure
++ **/
++
++int
++e1000_change_mtu(struct net_device *netdev,
++                 int new_mtu)
++{
++    struct e1000_adapter *adapter = netdev->priv;
++    uint32_t old_mtu = adapter->rx_buffer_len;
++
++    E1000_DBG("e1000_change_mtu\n");
++    if((new_mtu < MINIMUM_ETHERNET_PACKET_SIZE - ENET_HEADER_SIZE) ||
++       (new_mtu > MAX_JUMBO_FRAME_SIZE - ENET_HEADER_SIZE)) {
++        E1000_ERR("Invalid MTU setting\n");
++        return -EINVAL;
++    }
++
++    if(new_mtu <= MAXIMUM_ETHERNET_PACKET_SIZE - ENET_HEADER_SIZE) {
++        /* 2k buffers */
++        adapter->rx_buffer_len = E1000_RXBUFFER_2048;
++
++    } else if(adapter->shared.mac_type < e1000_82543) {
++        E1000_ERR("Jumbo Frames not supported on 82542\n");
++        return -EINVAL;
++
++    } else if(new_mtu <= E1000_RXBUFFER_4096 - ENET_HEADER_SIZE - CRC_LENGTH) {
++        /* 4k buffers */
++        adapter->rx_buffer_len = E1000_RXBUFFER_4096;
++
++    } else if(new_mtu <= E1000_RXBUFFER_8192 - ENET_HEADER_SIZE - CRC_LENGTH) {
++        /* 8k buffers */
++        adapter->rx_buffer_len = E1000_RXBUFFER_8192;
++
++    } else {
++        /* 16k buffers */
++        adapter->rx_buffer_len = E1000_RXBUFFER_16384;
++    }
++
++    if(old_mtu != adapter->rx_buffer_len &&
++       test_bit(E1000_BOARD_OPEN, &adapter->flags)) {
++
++        /* stop */
++        tasklet_disable(&adapter->rx_fill_tasklet);
++        netif_stop_queue(netdev);
++        adapter->shared.adapter_stopped = 0;
++        e1000_adapter_stop(&adapter->shared);
++
++        /* clean out old buffers */
++        e1000_clean_rx_ring(adapter);
++        e1000_clean_tx_ring(adapter);
++
++        /* reset hardware */
++        adapter->shared.adapter_stopped = 0;
++        e1000_hw_init(adapter);
++
++        /* go */
++        e1000_setup_rctl(adapter);
++        e1000_configure_rx(adapter);
++        e1000_configure_tx(adapter);
++#ifdef IANS
++        /* restore VLAN settings */
++        if((IANS_BD_TAGGING_MODE) (ANS_PRIVATE_DATA_FIELD(adapter)->tag_mode)
++           != IANS_BD_TAGGING_NONE)
++            bd_ans_hw_EnableVLAN(adapter);
++#endif
++        tasklet_enable(&adapter->rx_fill_tasklet);
++        tasklet_schedule(&adapter->rx_fill_tasklet);
++        e1000_irq_enable(adapter);
++        netif_start_queue(netdev);
++    }
++
++    netdev->mtu = new_mtu;
++    adapter->shared.max_frame_size = new_mtu + ENET_HEADER_SIZE + CRC_LENGTH;
++
++    return 0;
++}
++
++/**
++ * e1000_set_mac - Change the Ethernet Address of the NIC
++ * @netdev: network interface device structure
++ * @p: pointer to an address structure
++ * 
++ * Returns 0 on success, negative on failure
++ **/
++
++int
++e1000_set_mac(struct net_device *netdev,
++              void *p)
++{
++    struct e1000_adapter *adapter = netdev->priv;
++    struct pci_dev *pdev = adapter->pdev;
++    struct sockaddr *addr = (struct sockaddr *) p;
++    uint32_t pci_command;
++    uint32_t rctl;
++
++    E1000_DBG("e1000_set_mac\n");
++
++    rctl = E1000_READ_REG(&adapter->shared, RCTL);
++
++    if(adapter->shared.mac_type == e1000_82542_rev2_0) {
++        if(adapter->shared.pci_cmd_word & PCI_COMMAND_INVALIDATE) {
++            pci_command =
++                adapter->shared.pci_cmd_word & ~PCI_COMMAND_INVALIDATE;
++            pci_write_config_word(pdev, PCI_COMMAND, pci_command);
++        }
++        E1000_WRITE_REG(&adapter->shared, RCTL, rctl | E1000_RCTL_RST);
++        mdelay(5);
++        if(test_bit(E1000_BOARD_OPEN, &adapter->flags)) {
++            tasklet_disable(&adapter->rx_fill_tasklet);
++            e1000_clean_rx_ring(adapter);
++        }
++    }
++
++    memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
++    memcpy(adapter->shared.mac_addr, addr->sa_data, netdev->addr_len);
++
++    e1000_rar_set(&adapter->shared, adapter->shared.mac_addr, 0);
++
++    if(adapter->shared.mac_type == e1000_82542_rev2_0) {
++        E1000_WRITE_REG(&adapter->shared, RCTL, rctl);
++        mdelay(5);
++        if(adapter->shared.pci_cmd_word & PCI_COMMAND_INVALIDATE) {
++            pci_write_config_word(pdev, PCI_COMMAND,
++                                  adapter->shared.pci_cmd_word);
++        }
++        if(test_bit(E1000_BOARD_OPEN, &adapter->flags)) {
++            e1000_configure_rx(adapter);
++            tasklet_enable(&adapter->rx_fill_tasklet);
++        }
++    }
++
++    return 0;
++}
++
++/**
++ * e1000_update_stats - Update the board statistics counters
++ * @adapter: board private structure
++ **/
++
++static void
++e1000_update_stats(struct e1000_adapter *adapter)
++{
++    unsigned long flags;
++
++#define PHY_IDLE_ERROR_COUNT_MASK 0x00FF
++
++    spin_lock_irqsave(&adapter->stats_lock, flags);
++
++    adapter->stats.crcerrs += E1000_READ_REG(&adapter->shared, CRCERRS);
++    adapter->stats.symerrs += E1000_READ_REG(&adapter->shared, SYMERRS);
++    adapter->stats.mpc += E1000_READ_REG(&adapter->shared, MPC);
++    adapter->stats.scc += E1000_READ_REG(&adapter->shared, SCC);
++    adapter->stats.ecol += E1000_READ_REG(&adapter->shared, ECOL);
++    adapter->stats.mcc += E1000_READ_REG(&adapter->shared, MCC);
++    adapter->stats.latecol += E1000_READ_REG(&adapter->shared, LATECOL);
++    adapter->stats.colc += E1000_READ_REG(&adapter->shared, COLC);
++    adapter->stats.dc += E1000_READ_REG(&adapter->shared, DC);
++    adapter->stats.sec += E1000_READ_REG(&adapter->shared, SEC);
++    adapter->stats.rlec += E1000_READ_REG(&adapter->shared, RLEC);
++    adapter->stats.xonrxc += E1000_READ_REG(&adapter->shared, XONRXC);
++    adapter->stats.xontxc += E1000_READ_REG(&adapter->shared, XONTXC);
++    adapter->stats.xoffrxc += E1000_READ_REG(&adapter->shared, XOFFRXC);
++    adapter->stats.xofftxc += E1000_READ_REG(&adapter->shared, XOFFTXC);
++    adapter->stats.fcruc += E1000_READ_REG(&adapter->shared, FCRUC);
++    adapter->stats.prc64 += E1000_READ_REG(&adapter->shared, PRC64);
++    adapter->stats.prc127 += E1000_READ_REG(&adapter->shared, PRC127);
++    adapter->stats.prc255 += E1000_READ_REG(&adapter->shared, PRC255);
++    adapter->stats.prc511 += E1000_READ_REG(&adapter->shared, PRC511);
++    adapter->stats.prc1023 += E1000_READ_REG(&adapter->shared, PRC1023);
++    adapter->stats.prc1522 += E1000_READ_REG(&adapter->shared, PRC1522);
++    adapter->stats.gprc += E1000_READ_REG(&adapter->shared, GPRC);
++    adapter->stats.bprc += E1000_READ_REG(&adapter->shared, BPRC);
++    adapter->stats.mprc += E1000_READ_REG(&adapter->shared, MPRC);
++    adapter->stats.gptc += E1000_READ_REG(&adapter->shared, 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->shared, GORCL);
++    adapter->stats.gorch += E1000_READ_REG(&adapter->shared, GORCH);
++    adapter->stats.gotcl += E1000_READ_REG(&adapter->shared, GOTCL);
++    adapter->stats.gotch += E1000_READ_REG(&adapter->shared, GOTCH);
++
++    adapter->stats.rnbc += E1000_READ_REG(&adapter->shared, RNBC);
++    adapter->stats.ruc += E1000_READ_REG(&adapter->shared, RUC);
++    adapter->stats.rfc += E1000_READ_REG(&adapter->shared, RFC);
++    adapter->stats.roc += E1000_READ_REG(&adapter->shared, ROC);
++    adapter->stats.rjc += E1000_READ_REG(&adapter->shared, RJC);
++
++    adapter->stats.torl += E1000_READ_REG(&adapter->shared, TORL);
++    adapter->stats.torh += E1000_READ_REG(&adapter->shared, TORH);
++    adapter->stats.totl += E1000_READ_REG(&adapter->shared, TOTL);
++    adapter->stats.toth += E1000_READ_REG(&adapter->shared, TOTH);
++
++    adapter->stats.tpr += E1000_READ_REG(&adapter->shared, TPR);
++    adapter->stats.tpt += E1000_READ_REG(&adapter->shared, TPT);
++    adapter->stats.ptc64 += E1000_READ_REG(&adapter->shared, PTC64);
++    adapter->stats.ptc127 += E1000_READ_REG(&adapter->shared, PTC127);
++    adapter->stats.ptc255 += E1000_READ_REG(&adapter->shared, PTC255);
++    adapter->stats.ptc511 += E1000_READ_REG(&adapter->shared, PTC511);
++    adapter->stats.ptc1023 += E1000_READ_REG(&adapter->shared, PTC1023);
++    adapter->stats.ptc1522 += E1000_READ_REG(&adapter->shared, PTC1522);
++    adapter->stats.mptc += E1000_READ_REG(&adapter->shared, MPTC);
++    adapter->stats.bptc += E1000_READ_REG(&adapter->shared, BPTC);
++
++    if(adapter->shared.mac_type >= e1000_82543) {
++        adapter->stats.algnerrc += E1000_READ_REG(&adapter->shared, ALGNERRC);
++        adapter->stats.rxerrc += E1000_READ_REG(&adapter->shared, RXERRC);
++        adapter->stats.tncrs += E1000_READ_REG(&adapter->shared, TNCRS);
++        adapter->stats.cexterr += E1000_READ_REG(&adapter->shared, CEXTERR);
++        adapter->stats.tsctc += E1000_READ_REG(&adapter->shared, TSCTC);
++        adapter->stats.tsctfc += E1000_READ_REG(&adapter->shared, TSCTFC);
++    }
++
++    /* Fill out the OS statistics structure */
++
++    adapter->net_stats.rx_packets = adapter->stats.gprc;
++    adapter->net_stats.tx_packets = adapter->stats.gptc;
++    adapter->net_stats.rx_bytes = adapter->stats.gorcl;
++    adapter->net_stats.tx_bytes = adapter->stats.gotcl;
++    adapter->net_stats.multicast = adapter->stats.mprc;
++    adapter->net_stats.collisions = adapter->stats.colc;
++
++    /* Rx Errors */
++
++    adapter->net_stats.rx_errors =
++        adapter->stats.rxerrc + adapter->stats.crcerrs +
++        adapter->stats.algnerrc + adapter->stats.rlec + adapter->stats.rnbc +
++        adapter->stats.mpc + adapter->stats.cexterr;
++    adapter->net_stats.rx_dropped = adapter->stats.rnbc;
++    adapter->net_stats.rx_length_errors = adapter->stats.rlec;
++    adapter->net_stats.rx_crc_errors = adapter->stats.crcerrs;
++    adapter->net_stats.rx_frame_errors = adapter->stats.algnerrc;
++    adapter->net_stats.rx_fifo_errors = adapter->stats.mpc;
++    adapter->net_stats.rx_missed_errors = adapter->stats.mpc;
++
++    /* Tx Errors */
++
++    adapter->net_stats.tx_errors = adapter->stats.ecol + adapter->stats.latecol;
++    adapter->net_stats.tx_aborted_errors = adapter->stats.ecol;
++    adapter->net_stats.tx_window_errors = adapter->stats.latecol;
++
++    /* Tx Dropped needs to be maintained elsewhere */
++
++    if(adapter->shared.media_type == e1000_media_type_copper) {
++        adapter->phy_stats.idle_errors +=
++            (e1000_read_phy_reg(&adapter->shared, PHY_1000T_STATUS)
++             & PHY_IDLE_ERROR_COUNT_MASK);
++        adapter->phy_stats.receive_errors +=
++            e1000_read_phy_reg(&adapter->shared, M88E1000_RX_ERR_CNTR);
++    }
++
++    spin_unlock_irqrestore(&adapter->stats_lock, flags);
++    return;
++}
++
++/**
++ * e1000_irq_disable - Mask off interrupt generation on the NIC
++ * @adapter: board private structure
++ **/
++
++static inline void
++e1000_irq_disable(struct e1000_adapter *adapter)
++{
++    E1000_DBG("e1000_irq_disable\n");
++
++    /* Mask off all interrupts */
++
++    E1000_WRITE_REG(&adapter->shared, IMC, ~0);
++    return;
++}
++
++/**
++ * e1000_irq_enable - Enable default interrupt generation settings
++ * @adapter: board private structure
++ **/
++
++static inline void
++e1000_irq_enable(struct e1000_adapter *adapter)
++{
++    E1000_DBG("e1000_irq_enable\n");
++
++    E1000_WRITE_REG(&adapter->shared, IMS, adapter->int_mask);
++    return;
++}
++
++/**
++ * e1000_intr - Interrupt Handler
++ * @irq: interrupt number
++ * @data: pointer to a network interface device structure
++ * @pt_regs: CPU registers structure
++ **/
++
++void
++e1000_intr(int irq,
++           void *data,
++           struct pt_regs *regs)
++{
++    struct net_device *netdev = (struct net_device *) data;
++    struct e1000_adapter *adapter = netdev->priv;
++    uint32_t icr;
++    uint loop_count = E1000_MAX_INTR;
++
++    E1000_DBG("e1000_intr\n");
++
++    e1000_irq_disable(adapter);
++
++    while(loop_count > 0 && (icr = E1000_READ_REG(&adapter->shared, ICR)) != 0) {
++
++        if(icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
++            adapter->shared.get_link_status = 1;
++            set_bit(E1000_LINK_STATUS_CHANGED, &adapter->flags);
++            /* run the watchdog ASAP */
++            mod_timer(&adapter->timer_id, jiffies);
++        }
++
++        e1000_clean_rx_irq(adapter);
++        e1000_clean_tx_irq(adapter);
++        loop_count--;
++    }
++
++    e1000_irq_enable(adapter);
++
++    return;
++}
++
++/**
++ * e1000_clean_tx_irq - Reclaim resources after transmit completes
++ * @adapter: board private structure
++ **/
++
++static void
++e1000_clean_tx_irq(struct e1000_adapter *adapter)
++{
++    struct pci_dev *pdev = adapter->pdev;
++    int i;
++
++    struct e1000_tx_desc *tx_desc;
++    struct net_device *netdev = adapter->netdev;
++
++    E1000_DBG("e1000_clean_tx_irq\n");
++
++    i = adapter->tx_ring.next_to_clean;
++    tx_desc = E1000_TX_DESC(adapter->tx_ring, i);
++
++    while(tx_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) {
++
++        if(adapter->tx_ring.buffer_info[i].dma != 0) {
++            pci_unmap_page(pdev, adapter->tx_ring.buffer_info[i].dma,
++                           adapter->tx_ring.buffer_info[i].length,
++                           PCI_DMA_TODEVICE);
++            adapter->tx_ring.buffer_info[i].dma = 0;
++        }
++
++        if(adapter->tx_ring.buffer_info[i].skb != NULL) {
++            dev_kfree_skb_irq(adapter->tx_ring.buffer_info[i].skb);
++            adapter->tx_ring.buffer_info[i].skb = NULL;
++        }
++
++        atomic_inc(&adapter->tx_ring.unused);
++        i = (i + 1) % adapter->tx_ring.count;
++
++        tx_desc->upper.data = 0;
++        tx_desc = E1000_TX_DESC(adapter->tx_ring, i);
++    }
++
++    adapter->tx_ring.next_to_clean = i;
++
++    if(adapter->tx_ring.next_to_clean == adapter->tx_ring.next_to_use)
++        atomic_set(&adapter->tx_timeout, 0);
++    else
++        atomic_set(&adapter->tx_timeout, 3);
++
++    if(netif_queue_stopped(netdev) &&
++       (atomic_read(&adapter->tx_ring.unused) >
++        (adapter->tx_ring.count * 3 / 4))) {
++
++#ifdef IANS
++        if((adapter->iANSdata->iANS_status == IANS_COMMUNICATION_UP) &&
++           (adapter->iANSdata->reporting_mode == IANS_STATUS_REPORTING_ON))
++            if(ans_notify)
++                ans_notify(netdev, IANS_IND_XMIT_QUEUE_READY);
++#endif
++        netif_wake_queue(netdev);
++    }
++
++    return;
++}
++
++/**
++ * e1000_clean_rx_irq - Send received data up the network stack,
++ * @adapter: board private structure
++ **/
++
++static void
++e1000_clean_rx_irq(struct e1000_adapter *adapter)
++{
++    struct net_device *netdev = adapter->netdev;
++    struct pci_dev *pdev = adapter->pdev;
++    struct e1000_rx_desc *rx_desc;
++    int i;
++    uint32_t length;
++    struct sk_buff *skb;
++    uint8_t last_byte;
++    unsigned long flags;
++
++    E1000_DBG("e1000_clean_rx_irq\n");
++
++    i = adapter->rx_ring.next_to_clean;
++    rx_desc = E1000_RX_DESC(adapter->rx_ring, i);
++
++    while(rx_desc->status & E1000_RXD_STAT_DD) {
++        pci_unmap_single(pdev, adapter->rx_ring.buffer_info[i].dma,
++                         adapter->rx_ring.buffer_info[i].length,
++                         PCI_DMA_FROMDEVICE);
++
++        skb = adapter->rx_ring.buffer_info[i].skb;
++        length = le16_to_cpu(rx_desc->length);
++
++        if(!(rx_desc->status & E1000_RXD_STAT_EOP)) {
++
++            /* All receives must fit into a single buffer */
++
++            E1000_DBG("Receive packet consumed multiple buffers\n");
++
++            dev_kfree_skb_irq(skb);
++            memset(rx_desc, 0, 16);
++            mb();
++            adapter->rx_ring.buffer_info[i].skb = NULL;
++
++            atomic_inc(&adapter->rx_ring.unused);
++
++            i = (i + 1) % adapter->rx_ring.count;
++
++            rx_desc = E1000_RX_DESC(adapter->rx_ring, i);
++            continue;
++        }
++
++        if(rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK) {
++
++            last_byte = *(skb->data + length - 1);
++
++            if(TBI_ACCEPT
++               (&adapter->shared, rx_desc->status, rx_desc->errors, length,
++                last_byte)) {
++                spin_lock_irqsave(&adapter->stats_lock, flags);
++                e1000_tbi_adjust_stats(&adapter->shared, &adapter->stats,
++                                       length, skb->data);
++                spin_unlock_irqrestore(&adapter->stats_lock, flags);
++                length--;
++            } else {
++
++                E1000_DBG("Receive Errors Reported by Hardware\n");
++
++                dev_kfree_skb_irq(skb);
++                memset(rx_desc, 0, 16);
++                mb();
++                adapter->rx_ring.buffer_info[i].skb = NULL;
++
++                atomic_inc(&adapter->rx_ring.unused);
++                i = (i + 1) % adapter->rx_ring.count;
++
++                rx_desc = E1000_RX_DESC(adapter->rx_ring, i);
++                continue;
++            }
++        }
++
++        /* Good Receive */
++        skb_put(skb, length - CRC_LENGTH);
++
++        /* Adjust socket buffer accounting to only cover the ethernet frame
++         * Not what the stack intends, but there exist TCP problems that
++         * break NFS for network interfaces that need 2k receive buffers
++         */
++        skb->truesize = skb->len;
++
++        /* Receive Checksum Offload */
++        e1000_rx_checksum(adapter, rx_desc, skb);
++
++#ifdef IANS
++        if(adapter->iANSdata->iANS_status == IANS_COMMUNICATION_UP) {
++            if(bd_ans_os_Receive(adapter, rx_desc, skb) == BD_ANS_FAILURE)
++                dev_kfree_skb_irq(skb);
++            else
++                netif_rx(skb);
++        } else {
++            skb->protocol = eth_type_trans(skb, netdev);
++            netif_rx(skb);
++        }
++#else
++        skb->protocol = eth_type_trans(skb, netdev);
++        netif_rx(skb);
++#endif
++        memset(rx_desc, 0, 16);
++        mb();
++        adapter->rx_ring.buffer_info[i].skb = NULL;
++
++        atomic_inc(&adapter->rx_ring.unused);
++
++        i = (i + 1) % adapter->rx_ring.count;
++
++        rx_desc = E1000_RX_DESC(adapter->rx_ring, i);
++    }
++
++    /* if the Rx ring is less than 3/4 full, allocate more sk_buffs */
++
++    if(atomic_read(&adapter->rx_ring.unused) > (adapter->rx_ring.count / 4)) {
++        tasklet_schedule(&adapter->rx_fill_tasklet);
++    }
++    adapter->rx_ring.next_to_clean = i;
++
++    return;
++}
++
++/**
++ * e1000_alloc_rx_buffers - Replace used receive buffers
++ * @data: address of board private structure
++ **/
++
++static void
++e1000_alloc_rx_buffers(unsigned long data)
++{
++    struct e1000_adapter *adapter = (struct e1000_adapter *) data;
++    struct net_device *netdev = adapter->netdev;
++    struct pci_dev *pdev = adapter->pdev;
++    struct e1000_rx_desc *rx_desc;
++    struct sk_buff *skb;
++    int i;
++    int reserve_len;
++
++    E1000_DBG("e1000_alloc_rx_buffers\n");
++
++    /* kernel 2.4.7 seems to be broken with respect to tasklet locking */
++    if(!spin_trylock(&adapter->rx_fill_lock))
++        return;
++
++    if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) {
++        spin_unlock(&adapter->rx_fill_lock);
++        return;
++    }
++
++#ifdef IANS
++    reserve_len = E1000_ROUNDUP2(BD_ANS_INFO_SIZE, 16) + 2;
++#else
++    reserve_len = 2;
++#endif
++
++    i = adapter->rx_ring.next_to_use;
++
++    while(adapter->rx_ring.buffer_info[i].skb == NULL) {
++        rx_desc = E1000_RX_DESC(adapter->rx_ring, i);
++
++        skb = alloc_skb(adapter->rx_buffer_len + reserve_len, GFP_ATOMIC);
++
++        if(skb == NULL) {
++            /* Alloc Failed; If we could not allocate a
++             *  skb during this schedule. Wait for a while before
++             *  tasklet to allocate skb is called again.
++             */
++            set_bit(E1000_RX_REFILL, &adapter->flags);
++            break;
++        }
++
++        /* Make buffer alignment 2 beyond a 16 byte boundary
++         * this will result in a 16 byte aligned IP header after
++         * the 14 byte MAC header is removed
++         */
++        skb_reserve(skb, reserve_len);
++
++        skb->dev = netdev;
++
++        adapter->rx_ring.buffer_info[i].skb = skb;
++        adapter->rx_ring.buffer_info[i].length = adapter->rx_buffer_len;
++        adapter->rx_ring.buffer_info[i].dma =
++            pci_map_single(pdev, skb->data, adapter->rx_buffer_len,
++                           PCI_DMA_FROMDEVICE);
++
++        rx_desc->buffer_addr = cpu_to_le64(adapter->rx_ring.buffer_info[i].dma);
++
++        /* move tail */
++        E1000_WRITE_REG(&adapter->shared, RDT, i);
++
++        atomic_dec(&adapter->rx_ring.unused);
++
++        i = (i + 1) % adapter->rx_ring.count;
++
++        if(test_and_clear_bit(E1000_RX_REFILL, &adapter->flags)) {
++            /* Trigger Soft Interrupt */
++            E1000_WRITE_REG(&adapter->shared, ICS, E1000_ICS_RXT0);
++        }
++    }
++
++    adapter->rx_ring.next_to_use = i;
++
++    spin_unlock(&adapter->rx_fill_lock);
++    return;
++}
++
++/**
++ * e1000_ioctl - 
++ * @netdev:
++ * @ifreq:
++ * @cmd:
++ **/
++
++int
++e1000_ioctl(struct net_device *netdev,
++            struct ifreq *ifr,
++            int cmd)
++{
++#ifdef IANS
++    IANS_BD_PARAM_HEADER *header;
++#endif
++
++    E1000_DBG("e1000_do_ioctl\n");
++
++    switch (cmd) {
++
++#ifdef IANS
++    case IANS_BASE_SIOC:
++        header = (IANS_BD_PARAM_HEADER *) ifr->ifr_data;
++        if((header->Opcode != IANS_OP_EXT_GET_STATUS) &&
++           (!capable(CAP_NET_ADMIN)))
++            return -EPERM;
++        return bd_ans_os_Ioctl(netdev, ifr, cmd);
++        break;
++#endif
++
++#ifdef IDIAG
++    case IDIAG_PRO_BASE_SIOC:
++        if(!capable(CAP_NET_ADMIN))
++            return -EPERM;
++
++#ifdef DIAG_DEBUG
++        printk("Entering diagnostics\n");
++#endif
++        e1000_diag_ioctl(netdev, ifr);
++        break;
++#endif /* IDIAG */
++
++#ifdef SIOCETHTOOL
++    case SIOCETHTOOL:
++
++        return e1000_ethtool_ioctl(netdev, ifr);
++
++        break;
++#endif
++
++    default:
++        return -EOPNOTSUPP;
++    }
++
++    return 0;
++}
++
++/**
++ * e1000_rx_checksum - Receive Checksum Offload for 82543
++ * @adapter: board private structure
++ * @rx_desc: receive descriptor
++ * @sk_buff: socket buffer with received data
++ **/
++
++static inline void
++e1000_rx_checksum(struct e1000_adapter *adapter,
++                  struct e1000_rx_desc *rx_desc,
++                  struct sk_buff *skb)
++{
++    /* 82543 or newer only */
++    if((adapter->shared.mac_type < e1000_82543) ||
++       /* Ignore Checksum bit is set */
++       (rx_desc->status & E1000_RXD_STAT_IXSM) ||
++       /* TCP Checksum has not been calculated */
++       (!(rx_desc->status & E1000_RXD_STAT_TCPCS))) {
++
++        skb->ip_summed = CHECKSUM_NONE;
++        return;
++    }
++
++    /* At this point we know the hardware did the TCP checksum */
++    /* now look at the TCP checksum error bit */
++    if(rx_desc->errors & E1000_RXD_ERR_TCPE) {
++        /* let the stack verify checksum errors */
++        skb->ip_summed = CHECKSUM_NONE;
++        adapter->XsumRXError++;
++    } else {
++        /* TCP checksum is good */
++        skb->ip_summed = CHECKSUM_UNNECESSARY;
++        adapter->XsumRXGood++;
++    }
++
++    return;
++}
++
++void
++e1000_hibernate_adapter(struct net_device *netdev)
++{
++    uint32_t icr;
++    struct e1000_adapter *adapter = netdev->priv;
++
++    e1000_irq_disable(adapter);
++    netif_stop_queue(netdev);
++    adapter->shared.adapter_stopped = 0;
++    e1000_adapter_stop(&adapter->shared);
++
++    if(test_bit(E1000_BOARD_OPEN, &adapter->flags)) {
++
++        /* Disable tasklet only when interface is opened. */
++        tasklet_disable(&adapter->rx_fill_tasklet);
++
++        /* clean out old buffers */
++        e1000_clean_rx_ring(adapter);
++        e1000_clean_tx_ring(adapter);
++
++        /* Delete watchdog timer */
++        del_timer(&adapter->timer_id);
++
++        /* Unhook irq */
++        e1000_irq_disable(adapter);
++        icr = E1000_READ_REG(&adapter->shared, ICR);
++        free_irq(netdev->irq, netdev);
++    }
++}
++
++void
++e1000_wakeup_adapter(struct net_device *netdev)
++{
++    uint32_t icr;
++    struct e1000_adapter *adapter = netdev->priv;
++
++    adapter->shared.adapter_stopped = 0;
++    e1000_adapter_stop(&adapter->shared);
++    adapter->shared.adapter_stopped = 0;
++    adapter->shared.fc = adapter->shared.original_fc;
++
++    if(!e1000_init_hw(&adapter->shared))
++        printk("Hardware Init Failed at wakeup\n");
++
++    if(test_bit(E1000_BOARD_OPEN, &adapter->flags)) {
++
++        /* Setup Rctl */
++        e1000_setup_rctl(adapter);
++        e1000_configure_rx(adapter);
++        e1000_alloc_rx_buffers((unsigned long) adapter);
++        e1000_set_multi(netdev);
++        e1000_configure_tx(adapter);
++
++#ifdef IANS
++        if((IANS_BD_TAGGING_MODE) (ANS_PRIVATE_DATA_FIELD(adapter)->tag_mode)
++           != IANS_BD_TAGGING_NONE)
++            bd_ans_hw_EnableVLAN(adapter);
++#endif
++
++        /* Set the watchdog timer for 2 seconds */
++        init_timer(&adapter->timer_id);
++        adapter->timer_id.function = &e1000_watchdog;
++        adapter->timer_id.data = (unsigned long) netdev;
++        mod_timer(&adapter->timer_id, (jiffies + 2 * HZ));
++
++        tasklet_enable(&adapter->rx_fill_tasklet);
++
++        /* Hook irq */
++        e1000_irq_disable(adapter);
++        icr = E1000_READ_REG(&adapter->shared, ICR);
++        if(request_irq
++           (netdev->irq, &e1000_intr, SA_SHIRQ, e1000_driver_name, netdev) != 0)
++            printk(KERN_ERR "e1000: Unable to hook irq.\n");
++
++        e1000_irq_enable(adapter);
++        netif_start_queue(netdev);
++    }
++}
++
++#ifdef IDIAG
++int
++e1000_xmit_lbtest_frame(struct sk_buff *skb,
++                        struct e1000_adapter *adapter)
++{
++    /*struct e1000_adapter *adapter = netdev->priv; */
++    struct pci_dev *pdev = adapter->pdev;
++    struct e1000_tx_desc *tx_desc;
++    int i;
++
++    i = adapter->tx_ring.next_to_use;
++    tx_desc = E1000_TX_DESC(adapter->tx_ring, i);
++
++    adapter->tx_ring.buffer_info[i].skb = skb;
++    adapter->tx_ring.buffer_info[i].length = skb->len;
++    adapter->tx_ring.buffer_info[i].dma =
++        pci_map_page(pdev, virt_to_page(skb->data),
++                     (unsigned long) skb->data & ~PAGE_MASK, skb->len,
++                     PCI_DMA_TODEVICE);
++
++    tx_desc->buffer_addr = cpu_to_le64(adapter->tx_ring.buffer_info[i].dma);
++    tx_desc->lower.data = cpu_to_le32(skb->len);
++
++    /* zero out the status field in the descriptor */
++
++    tx_desc->upper.data = 0;
++
++    tx_desc->lower.data |= E1000_TXD_CMD_EOP;
++    tx_desc->lower.data |= E1000_TXD_CMD_IFCS;
++    tx_desc->lower.data |= E1000_TXD_CMD_IDE;
++
++    if(adapter->shared.report_tx_early == 1)
++        tx_desc->lower.data |= E1000_TXD_CMD_RS;
++    else
++        tx_desc->lower.data |= E1000_TXD_CMD_RPS;
++
++    /* Move the HW Tx Tail Pointer */
++
++    adapter->tx_ring.next_to_use++;
++    adapter->tx_ring.next_to_use %= adapter->tx_ring.count;
++
++    E1000_WRITE_REG(&adapter->shared, TDT, adapter->tx_ring.next_to_use);
++    mdelay(10);
++
++    atomic_dec(&adapter->tx_ring.unused);
++
++    if(atomic_read(&adapter->tx_ring.unused) <= 1) {
++
++        /* this driver never actually drops transmits,
++         * so use tx_dropped count to indicate the number of times
++         * netif_stop_queue is called due to no available descriptors
++         */
++
++        adapter->net_stats.tx_dropped++;
++        return (0);
++    }
++    return (1);
++}
++
++int
++e1000_rcv_lbtest_frame(struct e1000_adapter *adapter,
++                       unsigned int frame_size)
++{
++    struct pci_dev *pdev = adapter->pdev;
++    struct e1000_rx_desc *rx_desc;
++    int i, j = 0, rcved_pkt = 0;
++    uint32_t Length;
++    struct sk_buff *skb;
++
++    mdelay(500);
++    i = adapter->rx_ring.next_to_clean;
++    rx_desc = E1000_RX_DESC(adapter->rx_ring, i);
++
++    while(rx_desc->status & E1000_RXD_STAT_DD) {
++        Length = le16_to_cpu(rx_desc->length) - CRC_LENGTH;
++        skb = adapter->rx_ring.buffer_info[i].skb;
++
++        /* Snoop the packet for pattern */
++        rcved_pkt = e1000_check_lbtest_frame(skb, frame_size);
++
++        pci_unmap_single(pdev, adapter->rx_ring.buffer_info[i].dma,
++                         adapter->rx_ring.buffer_info[i].length,
++                         PCI_DMA_FROMDEVICE);
++
++        dev_kfree_skb_irq(skb);
++        adapter->rx_ring.buffer_info[i].skb = NULL;
++
++        rx_desc->status = 0;
++        atomic_inc(&adapter->rx_ring.unused);
++
++        i++;
++        i %= adapter->rx_ring.count;
++        rx_desc = E1000_RX_DESC(adapter->rx_ring, i);
++
++        if(rcved_pkt)
++            break;
++
++        /* waited enough */
++        if(j++ >= adapter->rx_ring.count)
++            return 0;
++
++        mdelay(5);
++
++    }
++
++    adapter->rx_ring.next_to_clean = i;
++
++    return (rcved_pkt);
++
++}
++
++void
++e1000_selective_wakeup_adapter(struct net_device *netdev)
++{
++    struct e1000_adapter *adapter = netdev->priv;
++    uint32_t ctrl, txcw;
++
++    e1000_init_hw(&adapter->shared);
++
++    if((adapter->link_active == FALSE) &&
++       (adapter->shared.mac_type == e1000_82543)) {
++
++        txcw = E1000_READ_REG(&adapter->shared, TXCW);
++        ctrl = E1000_READ_REG(&adapter->shared, CTRL);
++        E1000_WRITE_REG(&adapter->shared, TXCW, txcw & ~E1000_TXCW_ANE);
++        E1000_WRITE_REG(&adapter->shared, CTRL,
++                        (ctrl | E1000_CTRL_SLU | E1000_CTRL_ILOS |
++                         E1000_CTRL_FD));
++        mdelay(20);
++    }
++
++    if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) {
++        set_bit(E1000_BOARD_OPEN, &adapter->flags);
++        set_bit(E1000_DIAG_OPEN, &adapter->flags);
++        e1000_setup_tx_resources(adapter);
++        e1000_setup_rx_resources(adapter);
++    }
++    e1000_setup_rctl(adapter);
++    e1000_configure_rx(adapter);
++    e1000_alloc_rx_buffers((unsigned long) adapter);
++    e1000_configure_tx(adapter);
++}
++
++void
++e1000_selective_hibernate_adapter(struct net_device *netdev)
++{
++    struct e1000_adapter *adapter = netdev->priv;
++    uint32_t ctrl, txcw;
++
++    if((adapter->link_active == FALSE) &&
++       (adapter->shared.mac_type == e1000_82543)) {
++
++        txcw = E1000_READ_REG(&adapter->shared, TXCW);
++        ctrl = E1000_READ_REG(&adapter->shared, CTRL);
++        ctrl &= ~E1000_CTRL_SLU & ~E1000_CTRL_ILOS;
++        E1000_WRITE_REG(&adapter->shared, TXCW, txcw | E1000_TXCW_ANE);
++        E1000_WRITE_REG(&adapter->shared, CTRL, ctrl);
++        mdelay(20);
++    }
++    /* clean out old buffers */
++    e1000_clean_rx_ring(adapter);
++    e1000_clean_tx_ring(adapter);
++    if(test_and_clear_bit(E1000_DIAG_OPEN, &adapter->flags)) {
++        e1000_free_tx_resources(adapter);
++        e1000_free_rx_resources(adapter);
++        clear_bit(E1000_BOARD_OPEN, &adapter->flags);
++    }
++}
++
++static int
++e1000_check_lbtest_frame(struct sk_buff *skb,
++                         unsigned int frame_size)
++{
++    frame_size = (frame_size % 2) ? (frame_size - 1) : frame_size;
++    if(*(skb->data + 3) == 0xFF) {
++        if((*(skb->data + frame_size / 2 + 10) == 0xBE) &&
++           (*(skb->data + frame_size / 2 + 12) == 0xAF)) {
++            return 1;
++        }
++    }
++    return 0;
++}
++#endif /* IDIAG */
++
++#ifdef SIOCETHTOOL
++/**
++ * e1000_ethtool_ioctl - Ethtool Ioctl Support 
++ * @netdev: net device structure 
++ * @ifr: interface request structure 
++ **/
++
++static int
++e1000_ethtool_ioctl(struct net_device *netdev,
++                    struct ifreq *ifr)
++{
++    struct ethtool_cmd eth_cmd;
++    struct e1000_adapter *adapter = netdev->priv;
++    boolean_t re_initiate = FALSE;
++
++#ifdef ETHTOOL_GLINK
++    struct ethtool_value eth_e1000_linkinfo;
++#endif
++#ifdef ETHTOOL_GDRVINFO
++    struct ethtool_drvinfo eth_e1000_info;
++#endif
++#ifdef ETHTOOL_GWOL
++    struct ethtool_wolinfo eth_e1000_wolinfo;
++#endif
++
++    /* Get the data structure */
++    if(copy_from_user(&eth_cmd, ifr->ifr_data, sizeof(eth_cmd)))
++        return -EFAULT;
++
++    switch (eth_cmd.cmd) {
++        /* Get the information */
++    case ETHTOOL_GSET:
++        if(adapter->shared.media_type == e1000_media_type_copper) {
++            eth_cmd.supported = E1000_ETHTOOL_COPPER_INTERFACE_SUPPORTS;
++            eth_cmd.advertising = E1000_ETHTOOL_COPPER_INTERFACE_ADVERTISE;
++            eth_cmd.port = PORT_MII;
++            eth_cmd.phy_address = adapter->shared.phy_addr;
++            eth_cmd.transceiver =
++                (adapter->shared.mac_type >
++                 e1000_82543) ? XCVR_INTERNAL : XCVR_EXTERNAL;
++        } else {
++            eth_cmd.supported = E1000_ETHTOOL_FIBER_INTERFACE_SUPPORTS;
++            eth_cmd.advertising = E1000_ETHTOOL_FIBER_INTERFACE_ADVERTISE;
++            eth_cmd.port = PORT_FIBRE;
++        }
++
++        if(adapter->link_active == TRUE) {
++            e1000_get_speed_and_duplex(&adapter->shared, &adapter->link_speed,
++                                       &adapter->link_duplex);
++            eth_cmd.speed = adapter->link_speed;
++            eth_cmd.duplex =
++                (adapter->link_duplex ==
++                 FULL_DUPLEX) ? DUPLEX_FULL : DUPLEX_HALF;
++        } else {
++            eth_cmd.speed = 0;
++            eth_cmd.duplex = 0;
++        }
++
++        if(adapter->shared.autoneg)
++            eth_cmd.autoneg = AUTONEG_ENABLE;
++        else
++            eth_cmd.autoneg = AUTONEG_DISABLE;
++
++        if(copy_to_user(ifr->ifr_data, &eth_cmd, sizeof(eth_cmd)))
++            return -EFAULT;
++
++        break;
++
++        /* set information */
++    case ETHTOOL_SSET:
++        /* need proper permission to do set */
++        if(!capable(CAP_NET_ADMIN))
++            return -EPERM;
++
++        /* Cannot Force speed/duplex and at the same time autoneg.
++         * Autoneg will override forcing. 
++         * For example to force speed/duplex pass in 
++         *  'speed 100 duplex half autoneg off'
++         * pass in 'autoneg on' to start autoneg.
++         */
++        printk("e1000: Requested link to be forced to %d Speed, %s Duplex "
++               "%s\n", eth_cmd.speed, (eth_cmd.duplex ? "Full" : "Half"),
++               (eth_cmd.autoneg ? "and Autonegotiate" : "."));
++
++        if(eth_cmd.autoneg && eth_cmd.speed)
++            printk("e1000: Autoneg request will over-ride speed forcing\n");
++
++        /* if not in autoneg mode and have been asked to enable autoneg */
++        if(eth_cmd.autoneg) {
++            if(adapter->shared.autoneg &&
++               adapter->shared.autoneg_advertised == AUTONEG_ADV_DEFAULT)
++                /* If already in Autoneg */
++                return 0;
++            else {
++                adapter->shared.autoneg = 1;
++                adapter->shared.autoneg_advertised = AUTONEG_ADV_DEFAULT;
++                re_initiate = TRUE;
++            }
++        }
++        /* Force link to whatever speed and duplex */
++        /* Also turning off Autoneg in case of non-gig speeds */
++        else if(eth_cmd.speed) {
++            /* Check for invalid request */
++            if(((eth_cmd.speed != SPEED_10) && (eth_cmd.speed != SPEED_100) &&
++                (eth_cmd.speed != SPEED_1000)) ||
++               ((eth_cmd.duplex != DUPLEX_HALF) &&
++                (eth_cmd.duplex != DUPLEX_FULL)) ||
++               (adapter->shared.media_type == e1000_media_type_fiber))
++                return -EINVAL;
++
++            e1000_get_speed_and_duplex(&adapter->shared, &adapter->link_speed,
++                                       &adapter->link_duplex);
++            /* If we are already forced to requested speed and duplex
++             * Donot do anything, just return
++             */
++            if(!adapter->shared.autoneg &&
++               (adapter->link_speed == eth_cmd.speed) &&
++               (adapter->link_duplex == (eth_cmd.duplex + 1)))
++
++                return 0;
++
++            adapter->shared.autoneg = 0;
++            adapter->shared.autoneg_advertised = 0;
++            re_initiate = TRUE;
++            switch (eth_cmd.speed + eth_cmd.duplex) {
++            case (SPEED_10 + DUPLEX_HALF):
++                adapter->shared.forced_speed_duplex = e1000_10_half;
++                break;
++            case (SPEED_100 + DUPLEX_HALF):
++                adapter->shared.forced_speed_duplex = e1000_100_half;
++                break;
++            case (SPEED_10 + DUPLEX_FULL):
++                adapter->shared.forced_speed_duplex = e1000_10_full;
++                break;
++            case (SPEED_100 + DUPLEX_FULL):
++                adapter->shared.forced_speed_duplex = e1000_100_full;
++                break;
++            case (SPEED_1000 + DUPLEX_HALF):
++                printk("Half Duplex is not supported at 1000 Mbps\n");
++            case (SPEED_1000 + DUPLEX_FULL):
++                printk("Using Auto-neg at 1000 Mbps Full Duplex\n");
++            default:
++                adapter->shared.autoneg = 1;
++                adapter->shared.autoneg_advertised = ADVERTISE_1000_FULL;
++                break;
++            }
++        }
++
++        /* End of force */
++        /* Put the adapter to new settings */
++        if(re_initiate == TRUE) {
++            e1000_hibernate_adapter(netdev);
++            e1000_wakeup_adapter(netdev);
++        } else if(!eth_cmd.autoneg && !eth_cmd.speed) {
++            printk("Cannot turn off autoneg without "
++                   "knowing what speed to force the link\n");
++            printk("Speed specified was %dMbps\n", eth_cmd.speed);
++            return -EINVAL;
++        }
++        /* We donot support setting of 
++         * whatever else that was requested */
++        else
++            return -EOPNOTSUPP;
++
++        break;
++
++#ifdef ETHTOOL_NWAY_RST
++    case ETHTOOL_NWAY_RST:
++        /* need proper permission to restart auto-negotiation */
++        if(!capable(CAP_NET_ADMIN))
++            return -EPERM;
++
++        adapter->shared.autoneg = 1;
++        adapter->shared.autoneg_advertised = AUTONEG_ADV_DEFAULT;
++        e1000_hibernate_adapter(netdev);
++        e1000_wakeup_adapter(netdev);
++
++        break;
++#endif
++
++#ifdef ETHTOOL_GLINK
++    case ETHTOOL_GLINK:
++        eth_e1000_linkinfo.data = adapter->link_active;
++        if(copy_to_user(ifr->ifr_data, &eth_e1000_linkinfo, sizeof(eth_e1000_linkinfo)))
++            return -EFAULT;
++        break;
++#endif
++
++#ifdef ETHTOOL_GDRVINFO
++    case ETHTOOL_GDRVINFO:
++        strcpy(eth_e1000_info.driver, e1000_driver_name);
++        strcpy(eth_e1000_info.version, e1000_driver_version);
++        strcpy(eth_e1000_info.fw_version, "None");
++        strcpy(eth_e1000_info.bus_info, adapter->pdev->slot_name);
++        if(copy_to_user(ifr->ifr_data, &eth_e1000_info, sizeof(eth_e1000_info)))
++            return -EFAULT;
++        break;
++#endif
++
++#ifdef ETHTOOL_GWOL
++    case ETHTOOL_GWOL:
++        eth_e1000_wolinfo.supported = eth_e1000_wolinfo.wolopts = WAKE_MAGIC;
++        if(copy_to_user
++           (ifr->ifr_data, &eth_e1000_wolinfo, sizeof(eth_e1000_wolinfo)))
++            return -EFAULT;
++        break;
++#endif
++
++    default:
++        return -EOPNOTSUPP;
++    }
++
++    return 0;
++
++}
++#endif /* SIOCETHTOOL */
++
++/**
++ * e1000_enable_WOL - Wake On Lan Support (Magic Pkt)
++ * @adapter: Adapter structure 
++ **/
++
++static void
++e1000_enable_WOL(struct e1000_adapter *adapter)
++{
++    uint32_t wuc_val;
++
++    if(adapter->shared.mac_type <= e1000_82543)
++        return;
++
++    /* Set up Wake-Up Ctrl reg */
++    wuc_val = E1000_READ_REG(&adapter->shared, WUC);
++    wuc_val &= ~(E1000_WUC_APME | E1000_WUC_APMPME);
++    wuc_val |= (E1000_WUC_PME_STATUS | E1000_WUC_PME_EN);
++
++    E1000_WRITE_REG(&adapter->shared, WUC, wuc_val);
++
++    /* Set up Wake-up Filter */
++    E1000_WRITE_REG(&adapter->shared, WUFC, E1000_WUFC_MAG);
++
++    return;
++}
++
++/**
++ * e1000_write_pci_cg -
++ * @shared:
++ * @reg:
++ * @value:
++ **/
++
++void
++e1000_write_pci_cfg(struct e1000_shared_adapter *shared,
++                    uint32_t reg,
++                    uint16_t *value)
++{
++    struct e1000_adapter *adapter = (struct e1000_adapter *) shared->back;
++
++    pci_write_config_word(adapter->pdev, reg, *value);
++    return;
++}
++
++/* e1000_main.c */
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ linux-2.4.18-14-root/drivers/e1000/e1000_osdep.h   2003-01-02 16:22:31.000000000 -0800
+@@ -0,0 +1,138 @@
++/*******************************************************************************
++
++  This software program is available to you under a choice of one of two 
++  licenses. You may choose to be licensed under either the GNU General Public 
++  License (GPL) Version 2, June 1991, available at 
++  http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the 
++  text of which follows:
++  
++  Recipient has requested a license and Intel Corporation ("Intel") is willing
++  to grant a license for the software entitled Linux Base Driver for the 
++  Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided
++  by Intel Corporation. The following definitions apply to this license:
++  
++  "Licensed Patents" means patent claims licensable by Intel Corporation which 
++  are necessarily infringed by the use of sale of the Software alone or when 
++  combined with the operating system referred to below.
++  
++  "Recipient" means the party to whom Intel delivers this Software.
++  
++  "Licensee" means Recipient and those third parties that receive a license to 
++  any operating system available under the GNU Public License version 2.0 or 
++  later.
++  
++  Copyright (c) 1999 - 2002 Intel Corporation.
++  All rights reserved.
++  
++  The license is provided to Recipient and Recipient's Licensees under the 
++  following terms.
++  
++  Redistribution and use in source and binary forms of the Software, with or 
++  without modification, are permitted provided that the following conditions 
++  are met:
++  
++  Redistributions of source code of the Software may retain the above 
++  copyright notice, this list of conditions and the following disclaimer.
++  
++  Redistributions in binary form of the Software may reproduce the above 
++  copyright notice, this list of conditions and the following disclaimer in 
++  the documentation and/or materials provided with the distribution.
++  
++  Neither the name of Intel Corporation nor the names of its contributors 
++  shall be used to endorse or promote products derived from this Software 
++  without specific prior written permission.
++  
++  Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, 
++  royalty-free patent license under Licensed Patents to make, use, sell, offer 
++  to sell, import and otherwise transfer the Software, if any, in source code 
++  and object code form. This license shall include changes to the Software 
++  that are error corrections or other minor changes to the Software that do 
++  not add functionality or features when the Software is incorporated in any 
++  version of an operating system that has been distributed under the GNU 
++  General Public License 2.0 or later. This patent license shall apply to the 
++  combination of the Software and any operating system licensed under the GNU 
++  Public License version 2.0 or later if, at the time Intel provides the 
++  Software to Recipient, such addition of the Software to the then publicly 
++  available versions of such operating systems available under the GNU Public 
++  License version 2.0 or later (whether in gold, beta or alpha form) causes 
++  such combination to be covered by the Licensed Patents. The patent license 
++  shall not apply to any other combinations which include the Software. NO 
++  hardware per se is licensed hereunder.
++  
++  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 MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
++  ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY 
++  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
++  (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
++  ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) 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.
++
++*******************************************************************************/
++
++
++/* glue for the OS independant part of e1000 
++ * includes register access macros
++ */
++
++#ifndef _E1000_OSDEP_H_
++#define _E1000_OSDEP_H_
++
++#include <linux/types.h>
++#include <linux/pci.h>
++#include <linux/delay.h>
++#include <asm/io.h>
++
++#define usec_delay(x) udelay(x)
++#define msec_delay(x) mdelay(x)
++
++#define PCI_COMMAND_REGISTER   PCI_COMMAND
++#define CMD_MEM_WRT_INVALIDATE PCI_COMMAND_INVALIDATE
++
++typedef enum {
++    FALSE = 0,
++    TRUE = 1
++} boolean_t;
++
++#if DBG
++#define ASSERT(x) if(!(x)) panic("E1000: x")
++#define DEBUGOUT(S)         printk(S "\n")
++#define DEBUGOUT1(S,A)      printk(S "\n",A)
++#define DEBUGOUT2(S,A,B)    printk(S "\n",A,B)
++#define DEBUGOUT3(S,A,B,C)  printk(S "\n",A,B,C)
++#define DEBUGOUT7(S,A,B,C,D,E,F,G)  printk(S "\n",A,B,C,D,E,F,G)
++#else
++#define ASSERT(x)
++#define DEBUGOUT(S)
++#define DEBUGOUT1(S,A)
++#define DEBUGOUT2(S,A,B)
++#define DEBUGOUT3(S,A,B,C)
++#define DEBUGOUT7(S,A,B,C,D,E,F,G)
++#endif
++
++#define MSGOUT(S, A, B)     printk(S "\n", A, B)
++#define DEBUGFUNC(F)        DEBUGOUT(F)
++
++#define E1000_WRITE_REG(a, reg, value) ( \
++    ((a)->mac_type >= e1000_82543) ? \
++        (writel((value), ((a)->hw_addr + E1000_##reg))) : \
++        (writel((value), ((a)->hw_addr + E1000_82542_##reg))))
++
++#define E1000_READ_REG(a, reg) ( \
++    ((a)->mac_type >= e1000_82543) ? \
++        readl((a)->hw_addr + E1000_##reg) : \
++        readl((a)->hw_addr + E1000_82542_##reg))
++
++#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) ( \
++    ((a)->mac_type >= e1000_82543) ? \
++        writel((value), ((a)->hw_addr + E1000_##reg + ((offset) << 2))) : \
++        writel((value), ((a)->hw_addr + E1000_82542_##reg + ((offset) << 2))))
++
++#define E1000_READ_REG_ARRAY(a, reg, offset) ( \
++    ((a)->mac_type >= e1000_82543) ? \
++        readl((a)->hw_addr + E1000_##reg + ((offset) << 2)) : \
++        readl((a)->hw_addr + E1000_82542_##reg + ((offset) << 2)))
++
++#endif /* _E1000_OSDEP_H_ */
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ linux-2.4.18-14-root/drivers/e1000/e1000_phy.c     2003-01-02 16:22:31.000000000 -0800
+@@ -0,0 +1,1576 @@
++/*******************************************************************************
++
++  This software program is available to you under a choice of one of two 
++  licenses. You may choose to be licensed under either the GNU General Public 
++  License (GPL) Version 2, June 1991, available at 
++  http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the 
++  text of which follows:
++  
++  Recipient has requested a license and Intel Corporation ("Intel") is willing
++  to grant a license for the software entitled Linux Base Driver for the 
++  Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided
++  by Intel Corporation. The following definitions apply to this license:
++  
++  "Licensed Patents" means patent claims licensable by Intel Corporation which 
++  are necessarily infringed by the use of sale of the Software alone or when 
++  combined with the operating system referred to below.
++  
++  "Recipient" means the party to whom Intel delivers this Software.
++  
++  "Licensee" means Recipient and those third parties that receive a license to 
++  any operating system available under the GNU Public License version 2.0 or 
++  later.
++  
++  Copyright (c) 1999 - 2002 Intel Corporation.
++  All rights reserved.
++  
++  The license is provided to Recipient and Recipient's Licensees under the 
++  following terms.
++  
++  Redistribution and use in source and binary forms of the Software, with or 
++  without modification, are permitted provided that the following conditions 
++  are met:
++  
++  Redistributions of source code of the Software may retain the above 
++  copyright notice, this list of conditions and the following disclaimer.
++  
++  Redistributions in binary form of the Software may reproduce the above 
++  copyright notice, this list of conditions and the following disclaimer in 
++  the documentation and/or materials provided with the distribution.
++  
++  Neither the name of Intel Corporation nor the names of its contributors 
++  shall be used to endorse or promote products derived from this Software 
++  without specific prior written permission.
++  
++  Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, 
++  royalty-free patent license under Licensed Patents to make, use, sell, offer 
++  to sell, import and otherwise transfer the Software, if any, in source code 
++  and object code form. This license shall include changes to the Software 
++  that are error corrections or other minor changes to the Software that do 
++  not add functionality or features when the Software is incorporated in any 
++  version of an operating system that has been distributed under the GNU 
++  General Public License 2.0 or later. This patent license shall apply to the 
++  combination of the Software and any operating system licensed under the GNU 
++  Public License version 2.0 or later if, at the time Intel provides the 
++  Software to Recipient, such addition of the Software to the then publicly 
++  available versions of such operating systems available under the GNU Public 
++  License version 2.0 or later (whether in gold, beta or alpha form) causes 
++  such combination to be covered by the Licensed Patents. The patent license 
++  shall not apply to any other combinations which include the Software. NO 
++  hardware per se is licensed hereunder.
++  
++  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 MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
++  ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY 
++  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
++  (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
++  ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) 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.
++
++*******************************************************************************/
++
++/* e1000_phy.c
++ * Shared functions for accessing and configuring the PHY
++ */
++
++#include "e1000_mac.h"
++#include "e1000_phy.h"
++
++/******************************************************************************
++* Raises the Management Data Clock
++*
++* shared - Struct containing variables accessed by shared code
++* ctrl_reg - Device control register's current value
++******************************************************************************/
++static void
++e1000_raise_mdc(struct e1000_shared_adapter *shared,
++                uint32_t *ctrl_reg)
++{
++    /* Raise the clock input to the Management Data Clock (by setting
++     * the MDC bit), and then delay 2 microseconds.
++     */
++    E1000_WRITE_REG(shared, CTRL, (*ctrl_reg | E1000_CTRL_MDC));
++    usec_delay(2);
++    return;
++}
++
++/******************************************************************************
++* Lowers the Management Data Clock
++*
++* shared - Struct containing variables accessed by shared code
++* ctrl_reg - Device control register's current value
++******************************************************************************/
++static void
++e1000_lower_mdc(struct e1000_shared_adapter *shared,
++                uint32_t *ctrl_reg)
++{
++    /* Lower the clock input to the Management Data Clock (by clearing
++     * the MDC bit), and then delay 2 microseconds.
++     */
++    E1000_WRITE_REG(shared, CTRL, (*ctrl_reg & ~E1000_CTRL_MDC));
++    usec_delay(2);
++    return;
++}
++
++/******************************************************************************
++* Shifts data bits out to the PHY
++*
++* shared - 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
++e1000_phy_shift_out(struct e1000_shared_adapter *shared,
++                    uint32_t data,
++                    uint16_t count)
++{
++    uint32_t ctrl_reg;
++    uint32_t mask;
++
++    ASSERT(count <= 32);
++
++    /* 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, which is what the "while" logic does below.
++     */
++    mask = 0x01;
++    mask <<= (count - 1);
++
++    ctrl_reg = E1000_READ_REG(shared, CTRL);
++
++    /* Set MDIO_DIR (SWDPIO1) and MDC_DIR (SWDPIO2) direction bits to
++     * be used as output pins.
++     */
++    ctrl_reg |= (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
++         * (MDC).  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_reg |= E1000_CTRL_MDIO;
++        else
++            ctrl_reg &= ~E1000_CTRL_MDIO;
++
++        E1000_WRITE_REG(shared, CTRL, ctrl_reg);
++
++        usec_delay(2);
++
++        e1000_raise_mdc(shared, &ctrl_reg);
++        e1000_lower_mdc(shared, &ctrl_reg);
++
++        mask = mask >> 1;
++    }
++
++    /* Clear the data bit just before leaving this routine. */
++    ctrl_reg &= ~E1000_CTRL_MDIO;
++    return;
++}
++
++/******************************************************************************
++* Shifts data bits in from the PHY
++*
++* shared - Struct containing variables accessed by shared code
++*
++* Bits are shifted in in MSB to LSB order. 
++******************************************************************************/
++static uint16_t
++e1000_phy_shift_in(struct e1000_shared_adapter *shared)
++{
++    uint32_t ctrl_reg;
++    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 clock input
++     * to the Management Data Clock (setting the MDC bit), and then
++     * reading the value of the MDIO bit.
++     */ 
++    ctrl_reg = E1000_READ_REG(shared, CTRL);
++
++    /* Clear MDIO_DIR (SWDPIO1) to indicate this bit is to be used as
++     * input.
++     */ 
++    ctrl_reg &= ~E1000_CTRL_MDIO_DIR;
++    ctrl_reg &= ~E1000_CTRL_MDIO;
++
++    E1000_WRITE_REG(shared, CTRL, ctrl_reg);
++
++    /* 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.
++     */
++    e1000_raise_mdc(shared, &ctrl_reg);
++    e1000_lower_mdc(shared, &ctrl_reg);
++
++    for(data = 0, i = 0; i < 16; i++) {
++        data = data << 1;
++        e1000_raise_mdc(shared, &ctrl_reg);
++
++        ctrl_reg = E1000_READ_REG(shared, CTRL);
++
++        /* Check to see if we shifted in a "1". */
++        if(ctrl_reg & E1000_CTRL_MDIO)
++            data |= 1;
++
++        e1000_lower_mdc(shared, &ctrl_reg);
++    }
++
++    e1000_raise_mdc(shared, &ctrl_reg);
++    e1000_lower_mdc(shared, &ctrl_reg);
++
++    /* Clear the MDIO bit just before leaving this routine. */
++    ctrl_reg &= ~E1000_CTRL_MDIO;
++
++    return (data);
++}
++
++/******************************************************************************
++* Force PHY speed and duplex settings to shared->forced_speed_duplex
++*
++* shared - Struct containing variables accessed by shared code
++******************************************************************************/
++static void
++e1000_phy_force_speed_duplex(struct e1000_shared_adapter *shared)
++{
++    uint32_t tctl_reg;
++    uint32_t ctrl_reg;
++    uint32_t shift;
++    uint16_t mii_ctrl_reg;
++    uint16_t mii_status_reg;
++    uint16_t phy_data;
++    uint16_t i;
++
++    DEBUGFUNC("e1000_phy_force_speed_duplex");
++
++    /* Turn off Flow control if we are forcing speed and duplex. */
++    shared->fc = e1000_fc_none;
++
++    DEBUGOUT1("shared->fc = %d\n", shared->fc);
++
++    /* Read the Device Control Register. */
++    ctrl_reg = E1000_READ_REG(shared, CTRL);
++
++    /* Set the bits to Force Speed and Duplex in the Device Ctrl Reg. */
++    ctrl_reg |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
++    ctrl_reg &= ~(DEVICE_SPEED_MASK);
++
++    /* Clear the Auto Speed Detect Enable bit. */
++    ctrl_reg &= ~E1000_CTRL_ASDE;
++
++    /* Read the MII Control Register. */
++    mii_ctrl_reg = e1000_read_phy_reg(shared, PHY_CTRL);
++
++    /* 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(shared->forced_speed_duplex == e1000_100_full ||
++       shared->forced_speed_duplex == e1000_10_full) {
++
++        /* We want to force full duplex so we SET the full duplex bits
++         * in the Device and MII Control Registers.
++         */
++        ctrl_reg |= 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_reg &= ~E1000_CTRL_FD;
++        mii_ctrl_reg &= ~MII_CR_FULL_DUPLEX;    /* Do this implies HALF */
++
++        DEBUGOUT("Half Duplex\n");
++    }
++
++    /* Are we forcing 100Mbps??? */
++    if(shared->forced_speed_duplex == e1000_100_full ||
++       shared->forced_speed_duplex == e1000_100_half) {
++
++        /* Set the 100Mb bit and turn off the 1000Mb and 10Mb bits. */
++        ctrl_reg |= 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 {                    /* Force 10MB Full or Half */
++
++        /* Set the 10Mb bit and turn off the 1000Mb and 100Mb bits. */
++        ctrl_reg &= ~(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 ");
++    }
++
++    /* Now we need to configure the Collision Distance.  We need to read
++     * the Transmit Control Register to do this.
++     * Note: This must be done for both Half or Full Duplex.
++     */
++    tctl_reg = E1000_READ_REG(shared, TCTL);
++    DEBUGOUT1("tctl_reg = %x\n", tctl_reg);
++
++    if(!(mii_ctrl_reg & MII_CR_FULL_DUPLEX)) {
++
++       /* We are in Half Duplex mode so we need to set up our collision
++        * distance for 10/100.
++        */
++        tctl_reg &= ~E1000_TCTL_COLD;
++        shift = E1000_HDX_COLLISION_DISTANCE;
++        shift <<= E1000_COLD_SHIFT;
++        tctl_reg |= shift;
++    } else {
++        /* We are in Full Duplex mode.  We have the same collision
++         * distance regardless of speed.
++         */
++        tctl_reg &= ~E1000_TCTL_COLD;
++        shift = E1000_FDX_COLLISION_DISTANCE;
++        shift <<= E1000_COLD_SHIFT;
++        tctl_reg |= shift;
++    }
++
++    /* Write the configured values back to the Transmit Control Reg. */
++    E1000_WRITE_REG(shared, TCTL, tctl_reg);
++
++    /* Write the configured values back to the Device Control Reg. */
++    E1000_WRITE_REG(shared, CTRL, ctrl_reg);
++
++    /* Write the MII Control Register with the new PHY configuration. */
++    phy_data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL);
++
++    /* Clear Auto-Crossover to force MDI manually.
++     * M88E1000 requires MDI forced whenever speed/duplex is forced
++     */
++    phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
++
++    e1000_write_phy_reg(shared, M88E1000_PHY_SPEC_CTRL, phy_data);
++
++    DEBUGOUT1("M88E1000 PSCR: %x \n", phy_data);
++
++    /* Need to reset the PHY or these bits will get ignored. */
++    mii_ctrl_reg |= MII_CR_RESET;
++
++    e1000_write_phy_reg(shared, PHY_CTRL, mii_ctrl_reg);
++
++    /* 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(shared->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.
++             */
++            mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
++            mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
++
++            if(mii_status_reg & MII_SR_LINK_STATUS)
++                break;
++
++            msec_delay(100);
++        }                       /* end for loop */
++
++        if(i == 0) {            /* We didn't get link   */
++
++            /* Reset the DSP and wait again for link.   */
++            e1000_phy_reset_dsp(shared);
++        }
++
++        /* 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.
++             */
++            mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
++            mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
++
++        }                       /* end for loop */
++    }    /* end if wait_autoneg_complete */
++    /*
++     * 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.
++     */
++    phy_data = e1000_read_phy_reg(shared, M88E1000_EXT_PHY_SPEC_CTRL);
++
++    phy_data |= M88E1000_EPSCR_TX_CLK_25;
++
++    e1000_write_phy_reg(shared, M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
++
++    /* 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.
++     */
++    phy_data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL);
++
++    phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
++
++    e1000_write_phy_reg(shared, M88E1000_PHY_SPEC_CTRL, phy_data);
++    DEBUGOUT1("M88E1000 Phy Specific Ctrl Reg = %4x\r\n", phy_data);
++
++    return;
++}
++
++/*****************************************************************************
++* Reads the value from a PHY register
++*
++* shared - Struct containing variables accessed by shared code
++* reg_addr - address of the PHY register to read
++******************************************************************************/
++uint16_t
++e1000_read_phy_reg(struct e1000_shared_adapter *shared,
++                   uint32_t reg_addr)
++{
++    uint32_t i;
++    uint32_t data = 0;
++    uint32_t command = 0;
++
++    ASSERT(reg_addr <= MAX_PHY_REG_ADDRESS);
++
++    if(shared->mac_type > e1000_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.
++         */
++        command = ((reg_addr << E1000_MDIC_REG_SHIFT) |
++                   (shared->phy_addr << E1000_MDIC_PHY_SHIFT) | 
++                   (E1000_MDIC_OP_READ));
++
++        E1000_WRITE_REG(shared, MDIC, command);
++
++        /* Check every 10 usec to see if the read completed.  The read
++         * may take as long as 64 usecs (we'll wait 100 usecs max)
++         * from the CPU Write to the Ready bit assertion.
++         */
++        for(i = 0; i < 64; i++) {
++            usec_delay(10);
++
++            data = E1000_READ_REG(shared, MDIC);
++
++            if(data & E1000_MDIC_READY)
++                break;
++        }
++    } 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.
++         */
++        e1000_phy_shift_out(shared, 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
++         * e1000_phy_shift_out 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.
++         */
++        command = ((reg_addr) |
++                   (shared->phy_addr << 5) |
++                   (PHY_OP_READ << 10) | (PHY_SOF << 12));
++
++        e1000_phy_shift_out(shared, command, 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.
++         */
++        data = (uint32_t) e1000_phy_shift_in(shared);
++    }
++
++    ASSERT(!(data & E1000_MDIC_ERROR));
++
++    return ((uint16_t) data);
++}
++
++/******************************************************************************
++* Writes a value to a PHY register
++*
++* shared - Struct containing variables accessed by shared code
++* reg_addr - address of the PHY register to write
++* data - data to write to the PHY
++******************************************************************************/
++void
++e1000_write_phy_reg(struct e1000_shared_adapter *shared,
++                    uint32_t reg_addr,
++                    uint16_t data)
++{
++    uint32_t i;
++    uint32_t command = 0;
++    uint32_t mdic_reg;
++
++    ASSERT(reg_addr <= MAX_PHY_REG_ADDRESS);
++
++    if(shared->mac_type > e1000_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.
++         */
++        command = (((uint32_t) data) |
++                   (reg_addr << E1000_MDIC_REG_SHIFT) |
++                   (shared->phy_addr << E1000_MDIC_PHY_SHIFT) | 
++                   (E1000_MDIC_OP_WRITE));
++
++        E1000_WRITE_REG(shared, MDIC, command);
++
++        /* Check every 10 usec to see if the read completed.  The read
++         * may take as long as 64 usecs (we'll wait 100 usecs max)
++         * from the CPU Write to the Ready bit assertion.
++         */
++        for(i = 0; i < 10; i++) {
++            usec_delay(10);
++
++            mdic_reg = E1000_READ_REG(shared, MDIC);
++
++            if(mdic_reg & E1000_MDIC_READY)
++                break;
++        }
++    } 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.
++         */
++        e1000_phy_shift_out(shared, 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
++         * e1000_phy_shift_out 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>.
++         */
++        command = ((PHY_TURNAROUND) |
++                   (reg_addr << 2) |
++                   (shared->phy_addr << 7) |
++                   (PHY_OP_WRITE << 12) | (PHY_SOF << 14));
++        command <<= 16;
++        command |= ((uint32_t) data);
++
++        e1000_phy_shift_out(shared, command, 32);
++    }
++    return;
++}
++
++/******************************************************************************
++* Returns the PHY to the power-on reset state
++*
++* shared - Struct containing variables accessed by shared code
++******************************************************************************/
++void
++e1000_phy_hw_reset(struct e1000_shared_adapter *shared)
++{
++    uint32_t ctrl_reg;
++    uint32_t ctrl_ext_reg;
++
++    DEBUGFUNC("e1000_phy_hw_reset");
++
++    DEBUGOUT("Resetting Phy...\n");
++
++    if(shared->mac_type > e1000_82543) {
++        /* Read the device control register and assert the
++         * E1000_CTRL_PHY_RST bit.  Hold for 20ms and then take it out
++         * of reset.
++         */
++        ctrl_reg = E1000_READ_REG(shared, CTRL);
++
++        ctrl_reg |= E1000_CTRL_PHY_RST;
++
++        E1000_WRITE_REG(shared, CTRL, ctrl_reg);
++
++        msec_delay(20);
++
++        ctrl_reg &= ~E1000_CTRL_PHY_RST;
++
++        E1000_WRITE_REG(shared, CTRL, ctrl_reg);
++
++        msec_delay(20);
++    } else {
++        /* Read the Extended Device Control Register, assert the
++         * PHY_RESET_DIR bit.  Then clock it out to the PHY.
++         */
++        ctrl_ext_reg = E1000_READ_REG(shared, CTRL_EXT);
++
++        ctrl_ext_reg |= E1000_CTRL_PHY_RESET_DIR4;
++
++        E1000_WRITE_REG(shared, CTRL_EXT, ctrl_ext_reg);
++
++        msec_delay(20);
++
++        /* Set the reset bit in the device control register and clock
++         * it out to the PHY.
++         */
++        ctrl_ext_reg = E1000_READ_REG(shared, CTRL_EXT);
++
++        ctrl_ext_reg &= ~E1000_CTRL_PHY_RESET4;
++
++        E1000_WRITE_REG(shared, CTRL_EXT, ctrl_ext_reg);
++
++        msec_delay(20);
++
++        ctrl_ext_reg = E1000_READ_REG(shared, CTRL_EXT);
++
++        ctrl_ext_reg |= E1000_CTRL_PHY_RESET4;
++
++        E1000_WRITE_REG(shared, CTRL_EXT, ctrl_ext_reg);
++
++        msec_delay(20);
++    }
++    return;
++}
++
++/******************************************************************************
++* Resets the PHY
++*
++* shared - Struct containing variables accessed by shared code
++*
++* Sets bit 15 of the MII Control regiser
++******************************************************************************/
++boolean_t
++e1000_phy_reset(struct e1000_shared_adapter *shared)
++{
++    uint16_t reg_data;
++    uint16_t i;
++
++    DEBUGFUNC("e1000_phy_reset");
++
++    /* Read the MII control register, set the reset bit and write the
++     * value back by clocking it out to the PHY.
++     */
++    reg_data = e1000_read_phy_reg(shared, PHY_CTRL);
++
++    reg_data |= MII_CR_RESET;
++
++    e1000_write_phy_reg(shared, PHY_CTRL, reg_data);
++
++    /* Wait for bit 15 of the MII Control Register to be cleared
++     * indicating the PHY has been reset.
++     */
++    i = 0;
++    while((reg_data & MII_CR_RESET) && i++ < 500) {
++        reg_data = e1000_read_phy_reg(shared, PHY_CTRL);
++        usec_delay(1);
++    }
++
++    if(i >= 500) {
++        DEBUGOUT("Timeout waiting for PHY to reset.\n");
++        return FALSE;
++    }
++    return TRUE;
++}
++
++/******************************************************************************
++* Detects which PHY is present and the speed and duplex
++*
++* shared - Struct containing variables accessed by shared code
++* ctrl_reg - current value of the device control register
++******************************************************************************/
++boolean_t
++e1000_phy_setup(struct e1000_shared_adapter *shared,
++                uint32_t ctrl_reg)
++{
++    uint16_t mii_ctrl_reg;
++    uint16_t mii_status_reg;
++    uint16_t phy_specific_ctrl_reg;
++    uint16_t mii_autoneg_adv_reg;
++    uint16_t mii_1000t_ctrl_reg;
++    uint16_t i;
++    uint16_t data;
++    uint16_t autoneg_hw_setting;
++    uint16_t autoneg_fc_setting;
++    boolean_t restart_autoneg = FALSE;
++    boolean_t force_autoneg_restart = FALSE;
++
++    DEBUGFUNC("e1000_phy_setup");
++
++    /* We want to enable the Auto-Speed Detection bit in the Device
++     * Control Register.  When set to 1, the MAC automatically detects
++     * the resolved speed of the link and self-configures appropriately.
++     * The Set Link Up bit must also be set for this behavior work
++     * properly.
++     */
++    /* Nothing but 82543 and newer */
++    ASSERT(shared->mac_type >= e1000_82543);
++
++    /* With 82543, we need to force speed/duplex
++     * on the MAC equal to what the PHY speed/duplex configuration is.
++     * In addition, on 82543, we need to perform a hardware reset
++     * on the PHY to take it out of reset.
++     */
++    if(shared->mac_type >= e1000_82544) {
++        ctrl_reg |= E1000_CTRL_SLU;
++        E1000_WRITE_REG(shared, CTRL, ctrl_reg);
++    } else {
++        ctrl_reg |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX | E1000_CTRL_SLU);
++        E1000_WRITE_REG(shared, CTRL, ctrl_reg);
++
++        if(shared->mac_type == e1000_82543)
++            e1000_phy_hw_reset(shared);
++    }
++
++    if(!e1000_detect_gig_phy(shared)) {
++        /* No PHY detected, return FALSE */
++        DEBUGOUT("PhySetup failure, did not detect valid phy.\n");
++        return (FALSE);
++    }
++
++    DEBUGOUT1("Phy ID = %x \n", shared->phy_id);
++
++    /* Read the MII Control Register. */
++    mii_ctrl_reg = e1000_read_phy_reg(shared, PHY_CTRL);
++
++    DEBUGOUT1("MII Ctrl Reg contents = %x\n", mii_ctrl_reg);
++
++    /* Check to see if the Auto Neg Enable bit is set in the MII Control
++     * Register.  If not, we could be in a situation where a driver was
++     * loaded previously and was forcing speed and duplex.  Then the
++     * driver was unloaded but a e1000_phy_hw_reset was not performed, so
++     * link was still being forced and link was still achieved.  Then
++     * the driver was reloaded with the intention to auto-negotiate, but
++     * since link is already established we end up not restarting
++     * auto-neg.  So if the auto-neg bit is not enabled and the driver
++     * is being loaded with the desire to auto-neg, we set this flag to
++     * to ensure the restart of the auto-neg engine later in the logic.
++     */
++    if(!(mii_ctrl_reg & MII_CR_AUTO_NEG_EN))
++        force_autoneg_restart = TRUE;
++
++    /* Clear the isolate bit for normal operation and write it back to
++     * the MII Control Reg.  Although the spec says this doesn't need
++     * to be done when the PHY address is not equal to zero, we do it
++     * anyway just to be safe.
++     */
++    mii_ctrl_reg &= ~(MII_CR_ISOLATE);
++
++    e1000_write_phy_reg(shared, PHY_CTRL, mii_ctrl_reg);
++
++    data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL);
++
++    /* Enable CRS on TX.  This must be set for half-duplex operation. */
++    data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
++
++    DEBUGOUT1("M88E1000 PSCR: %x \n", data);
++
++    e1000_write_phy_reg(shared, M88E1000_PHY_SPEC_CTRL, data);
++
++    data = e1000_read_phy_reg(shared, M88E1000_EXT_PHY_SPEC_CTRL);
++
++    /* Force TX_CLK in the Extended PHY Specific Control Register
++     * to 25MHz clock.
++     */
++    data |= M88E1000_EPSCR_TX_CLK_25;
++
++    e1000_write_phy_reg(shared, M88E1000_EXT_PHY_SPEC_CTRL, data);
++
++    /* Certain PHYs will set the default of MII register 4 differently.
++     * We need to check this against our fc value.  If it is
++     * different, we need to setup up register 4 correctly and restart
++     * autonegotiation.
++     */
++    /* Read the MII Auto-Neg Advertisement Register (Address 4). */
++    mii_autoneg_adv_reg = e1000_read_phy_reg(shared, PHY_AUTONEG_ADV);
++
++    /* Shift right to put 10T-Half bit in bit 0
++     * Isolate the four bits for 100/10 Full/Half.
++     */ 
++    autoneg_hw_setting = (mii_autoneg_adv_reg >> 5) & 0xF;
++
++    /* Get the 1000T settings. */
++    mii_1000t_ctrl_reg = e1000_read_phy_reg(shared, PHY_1000T_CTRL);
++
++    /* Isolate and OR in the 1000T settings. */
++    autoneg_hw_setting |= ((mii_1000t_ctrl_reg & 0x0300) >> 4);
++
++    /* mask all bits in the MII Auto-Neg Advertisement Register
++     * except for ASM_DIR and PAUSE and shift.  This value
++     * will be used later to see if we need to restart Auto-Negotiation.
++     */
++    autoneg_fc_setting = ((mii_autoneg_adv_reg & 0x0C00) >> 10);
++
++    /* Perform some bounds checking on the shared->autoneg_advertised
++     * parameter.  If this variable is zero, then set it to the default.
++     */
++    shared->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(shared->autoneg_advertised == 0)
++        shared->autoneg_advertised = AUTONEG_ADVERTISE_SPEED_DEFAULT;
++
++    /* We could be in the situation where Auto-Neg has already completed
++     * and the user has not indicated any overrides.  In this case we
++     * simply need to call e1000_get_speed_and_duplex to obtain the Auto-
++     * Negotiated speed and duplex, then return.
++     */
++    if(!force_autoneg_restart && shared->autoneg &&
++       (shared->autoneg_advertised == autoneg_hw_setting) &&
++       (shared->fc == autoneg_fc_setting)) {
++
++        DEBUGOUT("No overrides - Reading MII Status Reg..\n");
++
++        /* Read the MII Status Register.  We read this twice because
++         * certain bits are "sticky" and need to be read twice.
++         */
++        mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
++        mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
++
++        DEBUGOUT1("MII Status Reg contents = %x\n", mii_status_reg);
++
++        /* Do we have link now? (if so, auto-neg has completed) */
++        if(mii_status_reg & MII_SR_LINK_STATUS) {
++            data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_STATUS);
++            DEBUGOUT1("M88E1000 Phy Specific Status Reg contents = %x\n", data);
++
++            /* We have link, so we need to finish the config process:
++             *   1) Set up the MAC to the current PHY speed/duplex
++             *      if we are on 82543.  If we
++             *      are on newer silicon, we only need to configure
++             *      collision distance in the Transmit Control Register.
++             *   2) Set up flow control on the MAC to that established
++             *      with the link partner.
++             */
++            if(shared->mac_type >= e1000_82544)
++                e1000_config_collision_dist(shared);
++            else
++                e1000_config_mac_to_phy(shared, data);
++
++            e1000_config_fc_after_link_up(shared);
++
++            return (TRUE);
++        }
++    }
++
++    /* 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_specific_ctrl_reg = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL);
++
++    phy_specific_ctrl_reg &= ~M88E1000_PSCR_AUTO_X_MODE;
++
++    switch (shared->mdix) {
++    case 1:
++        phy_specific_ctrl_reg |= M88E1000_PSCR_MDI_MANUAL_MODE;
++        break;
++    case 2:
++        phy_specific_ctrl_reg |= M88E1000_PSCR_MDIX_MANUAL_MODE;
++        break;
++    case 3:
++        phy_specific_ctrl_reg |= M88E1000_PSCR_AUTO_X_1000T;
++        break;
++    case 0:
++    default:
++        phy_specific_ctrl_reg |= M88E1000_PSCR_AUTO_X_MODE;
++        break;
++    }
++
++    e1000_write_phy_reg(shared, M88E1000_PHY_SPEC_CTRL, phy_specific_ctrl_reg);
++
++    /* Options:
++     *   disable_polarity_correction = 0 (default)
++     *       Automatic Correction for Reversed Cable Polarity
++     *   0 - Disabled
++     *   1 - Enabled
++     */
++    phy_specific_ctrl_reg = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL);
++
++    phy_specific_ctrl_reg &= ~M88E1000_PSCR_POLARITY_REVERSAL;
++
++    if(shared->disable_polarity_correction == 1)
++        phy_specific_ctrl_reg |= M88E1000_PSCR_POLARITY_REVERSAL;
++
++    e1000_write_phy_reg(shared, M88E1000_PHY_SPEC_CTRL, phy_specific_ctrl_reg);
++
++    /* Options:
++     *   autoneg = 1 (default)
++     *      PHY will advertise value(s) parsed from
++     *      autoneg_advertised and fc
++     *   autoneg = 0
++     *      PHY will be set to 10H, 10F, 100H, or 100F
++     *      depending on value parsed from forced_speed_duplex.
++     */
++
++    /* Is autoneg enabled?  This is enabled by default or by software override.
++     * If so, call e1000_phy_setup_autoneg routine to parse the
++     * autoneg_advertised and fc options. If autoneg is NOT enabled, then the
++     * user should have provided a speed/duplex override.  If so, then call
++     * e1000_phy_force_speed_duplex to parse and set this up.  Otherwise,
++     * we are in an error situation and need to bail.
++     */
++    if(shared->autoneg) {
++        DEBUGOUT("Reconfiguring auto-neg advertisement params\n");
++        restart_autoneg = e1000_phy_setup_autoneg(shared);
++    } else {
++        DEBUGOUT("Forcing speed and duplex\n");
++        e1000_phy_force_speed_duplex(shared);
++    }
++
++    /* Based on information parsed above, check the flag to indicate
++     * whether we need to restart Auto-Neg.
++     */
++    if(restart_autoneg) {
++        DEBUGOUT("Restarting Auto-Neg\n");
++
++        /* Read the MII Control Register. */
++        mii_ctrl_reg = e1000_read_phy_reg(shared, PHY_CTRL);
++
++        /* Restart auto-negotiation by setting the Auto Neg Enable bit and
++         * the Auto Neg Restart bit.
++         */
++        mii_ctrl_reg |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
++
++        e1000_write_phy_reg(shared, PHY_CTRL, mii_ctrl_reg);
++
++        /* Does the user want to wait for Auto-Neg to complete here, or
++         * check at a later time (for example, callback routine).
++         */
++        if(shared->wait_autoneg_complete)
++            e1000_wait_autoneg(shared);
++    } /* end if restart_autoneg */
++
++    /* Read the MII Status Register. */
++    mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
++    mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
++
++    DEBUGOUT1("Checking for link status - MII Status Reg contents = %x\n",
++              mii_status_reg);
++
++    /* Check link status.  Wait up to 100 microseconds for link to
++     * become valid.
++     */
++    for(i = 0; i < 10; i++) {
++        if(mii_status_reg & MII_SR_LINK_STATUS)
++            break;
++        usec_delay(10);
++        DEBUGOUT(". ");
++
++        mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
++        mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
++    }
++
++    if(mii_status_reg & MII_SR_LINK_STATUS) {
++        /* Yes, so configure MAC to PHY settings as well as flow control
++         * registers.
++         */
++        data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_STATUS);
++
++        DEBUGOUT1("M88E1000 Phy Specific Status Reg contents = %x\n", data);
++
++        /* We have link, so we need to finish the config process:
++         *   1) Set up the MAC to the current PHY speed/duplex
++         *      if we are on 82543.  If we
++         *      are on newer silicon, we only need to configure
++         *      collision distance in the Transmit Control Register.
++         *   2) Set up flow control on the MAC to that established with
++         *      the link partner.
++         */
++        if(shared->mac_type >= e1000_82544)
++            e1000_config_collision_dist(shared);
++        else
++            e1000_config_mac_to_phy(shared, data);
++
++        e1000_config_fc_after_link_up(shared);
++
++        DEBUGOUT("Valid link established!!!\n");
++    } else {
++        DEBUGOUT("Unable to establish link!!!\n");
++    }
++
++    return (TRUE);
++}
++
++/******************************************************************************
++* Configures PHY autoneg and flow control advertisement settings
++*
++* shared - Struct containing variables accessed by shared code
++******************************************************************************/
++boolean_t
++e1000_phy_setup_autoneg(struct e1000_shared_adapter *shared)
++{
++    uint16_t mii_autoneg_adv_reg;
++    uint16_t mii_1000t_ctrl_reg;
++
++    DEBUGFUNC("e1000_phy_setup_autoneg");
++
++    /* Read the MII Auto-Neg Advertisement Register (Address 4). */
++    mii_autoneg_adv_reg = e1000_read_phy_reg(shared, PHY_AUTONEG_ADV);
++
++    /* Read the MII 1000Base-T Control Register (Address 9). */
++    mii_1000t_ctrl_reg = e1000_read_phy_reg(shared, PHY_1000T_CTRL);
++
++    /* 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", shared->autoneg_advertised);
++
++    /* Do we want to advertise 10 Mb Half Duplex? */
++    if(shared->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(shared->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(shared->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(shared->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(shared->autoneg_advertised & ADVERTISE_1000_HALF) {
++        DEBUGOUT("Advertise 1000mb Half duplex requested, request denied!\n");
++    }
++
++    /* Do we want to advertise 1000 Mb Full Duplex? */
++    if(shared->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 (shared->fc) {
++    case e1000_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 e1000_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 e1000_config_fc_after_link_up) we will disable the
++             *shared's ability to send PAUSE frames.
++             */
++        mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
++        break;
++    case e1000_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 e1000_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:
++            /* We should never get here.  The value should be 0-3. */
++        DEBUGOUT("Flow control param set incorrectly\n");
++        ASSERT(0);
++        break;
++    }
++
++    /* Write the MII Auto-Neg Advertisement Register (Address 4). */
++    e1000_write_phy_reg(shared, PHY_AUTONEG_ADV, mii_autoneg_adv_reg);
++
++    DEBUGOUT1("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
++
++    /* Write the MII 1000Base-T Control Register (Address 9). */
++    e1000_write_phy_reg(shared, PHY_1000T_CTRL, mii_1000t_ctrl_reg);
++    return (TRUE);
++}
++
++/******************************************************************************
++* Sets MAC speed and duplex settings to reflect the those in the PHY
++*
++* shared - 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.
++******************************************************************************/
++void
++e1000_config_mac_to_phy(struct e1000_shared_adapter *shared,
++                        uint16_t mii_reg)
++{
++    uint32_t ctrl_reg;
++    uint32_t tctl_reg;
++    uint32_t shift;
++
++    DEBUGFUNC("e1000_config_mac_to_phy");
++
++    /* We need to read the Transmit Control register to configure the
++     * collision distance.
++     * Note: This must be done for both Half or Full Duplex.
++     */
++    tctl_reg = E1000_READ_REG(shared, TCTL);
++    DEBUGOUT1("tctl_reg = %x\n", tctl_reg);
++
++    /* Read the Device Control Register and set the bits to Force Speed
++     * and Duplex.
++     */
++    ctrl_reg = E1000_READ_REG(shared, CTRL);
++
++    ctrl_reg |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
++    ctrl_reg &= ~(DEVICE_SPEED_MASK);
++
++    DEBUGOUT1("MII Register Data = %x\r\n", mii_reg);
++
++    /* Clear the ILOS bit. */
++    ctrl_reg &= ~E1000_CTRL_ILOS;
++
++    /* Set up duplex in the Device Control and Transmit Control
++     * registers depending on negotiated values.
++     */
++    if(mii_reg & M88E1000_PSSR_DPLX) {
++        ctrl_reg |= E1000_CTRL_FD;
++
++        /* We are in Full Duplex mode.  We have the same collision
++         * distance regardless of speed.
++         */
++        tctl_reg &= ~E1000_TCTL_COLD;
++        shift = E1000_FDX_COLLISION_DISTANCE;
++        shift <<= E1000_COLD_SHIFT;
++        tctl_reg |= shift;
++    } else {
++        ctrl_reg &= ~E1000_CTRL_FD;
++
++        /* We are in Half Duplex mode.  Our Half Duplex collision
++         * distance is different for Gigabit than for 10/100 so we will
++         * set accordingly.
++         */
++        if((mii_reg & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) { 
++            /* 1000Mbs HDX */
++            tctl_reg &= ~E1000_TCTL_COLD;
++            shift = E1000_GB_HDX_COLLISION_DISTANCE;
++            shift <<= E1000_COLD_SHIFT;
++            tctl_reg |= shift;
++            tctl_reg |= E1000_TCTL_PBE; /* Enable Packet Bursting */
++        } else {
++            /* 10/100Mbs HDX */
++            tctl_reg &= ~E1000_TCTL_COLD;
++            shift = E1000_HDX_COLLISION_DISTANCE;
++            shift <<= E1000_COLD_SHIFT;
++            tctl_reg |= shift;
++        }
++    }
++
++    /* Set up speed in the Device Control register depending on
++     * negotiated values.
++     */
++    if((mii_reg & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS)
++        ctrl_reg |= E1000_CTRL_SPD_1000;
++    else if((mii_reg & M88E1000_PSSR_SPEED) == M88E1000_PSSR_100MBS)
++        ctrl_reg |= E1000_CTRL_SPD_100;
++    else
++        ctrl_reg &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
++
++    /* Write the configured values back to the Transmit Control Reg. */
++    E1000_WRITE_REG(shared, TCTL, tctl_reg);
++
++    /* Write the configured values back to the Device Control Reg. */
++    E1000_WRITE_REG(shared, CTRL, ctrl_reg);
++
++    return;
++}
++
++/******************************************************************************
++* Sets the collision distance in the Transmit Control register
++*
++* shared - 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
++e1000_config_collision_dist(struct e1000_shared_adapter *shared)
++{
++    uint32_t tctl_reg;
++    uint16_t speed;
++    uint16_t duplex;
++    uint32_t shift;
++
++    DEBUGFUNC("e1000_config_collision_dist");
++
++    /* Get our current speed and duplex from the Device Status Register. */
++    e1000_get_speed_and_duplex(shared, &speed, &duplex);
++
++    /* We need to configure the Collision Distance for both Full or
++     * Half Duplex.
++     */
++    tctl_reg = E1000_READ_REG(shared, TCTL);
++    DEBUGOUT1("tctl_reg = %x\n", tctl_reg);
++
++    /* mask the Collision Distance bits in the Transmit Control Reg. */
++    tctl_reg &= ~E1000_TCTL_COLD;
++
++    if(duplex == FULL_DUPLEX) {
++        /* We are in Full Duplex mode.  Therefore, the collision distance
++         * is the same regardless of speed.
++         */
++        shift = E1000_FDX_COLLISION_DISTANCE;
++        shift <<= E1000_COLD_SHIFT;
++        tctl_reg |= shift;
++    } else {
++        /* We are in Half Duplex mode.  Half Duplex collision distance is
++         * different for Gigabit vs. 10/100, so we will set accordingly.
++         */
++        if(speed == SPEED_1000) {       /* 1000Mbs HDX */
++            shift = E1000_GB_HDX_COLLISION_DISTANCE;
++            shift <<= E1000_COLD_SHIFT;
++            tctl_reg |= shift;
++            tctl_reg |= E1000_TCTL_PBE; /* Enable Packet Bursting */
++        } else {                /* 10/100Mbs HDX */
++            shift = E1000_HDX_COLLISION_DISTANCE;
++            shift <<= E1000_COLD_SHIFT;
++            tctl_reg |= shift;
++        }
++    }
++
++    /* Write the configured values back to the Transmit Control Reg. */
++    E1000_WRITE_REG(shared, TCTL, tctl_reg);
++
++    return;
++}
++
++#if DBG
++/******************************************************************************
++* Displays the contents of all of the MII registers
++*
++* shared - Struct containing variables accessed by shared code
++*
++* For debugging.
++******************************************************************************/
++void
++e1000_display_mii(struct e1000_shared_adapter *shared)
++{
++    uint16_t data;
++    uint16_t phy_id_high;
++    uint16_t phy_id_low;
++    uint32_t phy_id;
++
++    DEBUGFUNC("e1000_display_mii");
++
++    DEBUGOUT1("adapter Base Address = %x\n", shared->hw_addr);
++
++    /* This will read each PHY Reg address and display its contents. */
++
++    data = e1000_read_phy_reg(shared, PHY_CTRL);
++    DEBUGOUT1("MII Ctrl Reg contents = %x\n", data);
++
++    data = e1000_read_phy_reg(shared, PHY_STATUS);
++    data = e1000_read_phy_reg(shared, PHY_STATUS);
++    DEBUGOUT1("MII Status Reg contents = %x\n", data);
++
++    phy_id_high = e1000_read_phy_reg(shared, PHY_ID1);
++    usec_delay(2);
++    phy_id_low = e1000_read_phy_reg(shared, PHY_ID2);
++    phy_id = (phy_id_low | (phy_id_high << 16)) & PHY_REVISION_MASK;
++    DEBUGOUT1("Phy ID = %x \n", phy_id);
++
++    data = e1000_read_phy_reg(shared, PHY_AUTONEG_ADV);
++    DEBUGOUT1("Reg 4 contents = %x\n", data);
++
++    data = e1000_read_phy_reg(shared, PHY_LP_ABILITY);
++    DEBUGOUT1("Reg 5 contents = %x\n", data);
++
++    data = e1000_read_phy_reg(shared, PHY_AUTONEG_EXP);
++    DEBUGOUT1("Reg 6 contents = %x\n", data);
++
++    data = e1000_read_phy_reg(shared, PHY_NEXT_PAGE_TX);
++    DEBUGOUT1("Reg 7 contents = %x\n", data);
++
++    data = e1000_read_phy_reg(shared, PHY_LP_NEXT_PAGE);
++    DEBUGOUT1("Reg 8 contents = %x\n", data);
++
++    data = e1000_read_phy_reg(shared, PHY_1000T_CTRL);
++    DEBUGOUT1("Reg 9 contents = %x\n", data);
++
++    data = e1000_read_phy_reg(shared, PHY_1000T_STATUS);
++    DEBUGOUT1("Reg A contents = %x\n", data);
++
++    data = e1000_read_phy_reg(shared, PHY_EXT_STATUS);
++    DEBUGOUT1("Reg F contents = %x\n", data);
++
++    data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL);
++    DEBUGOUT1("M88E1000 Specific Control Reg (0x10) = %x\n", data);
++
++    data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_STATUS);
++    DEBUGOUT1("M88E1000 Specific Status Reg (0x11) = %x\n", data);
++
++    /*
++     * data = e1000_read_phy_reg(shared, M88E1000_INT_ENABLE_REG);
++     * DEBUGOUT1("M88E1000 Interrupt Enable Reg (0x12) = %x\n", data);
++     */
++
++    /*
++     * data = e1000_read_phy_reg(shared, M88E1000_INT_STATUS_REG);
++     * DEBUGOUT1("M88E1000 Interrupt Status Reg (0x13) = %x\n", data);
++     */
++     
++    data = e1000_read_phy_reg(shared, M88E1000_EXT_PHY_SPEC_CTRL);
++    DEBUGOUT1("M88E1000 Ext. Phy Specific Control (0x14) = %x\n", data);
++
++    data = e1000_read_phy_reg(shared, M88E1000_RX_ERR_CNTR);
++    DEBUGOUT1("M88E1000 Receive Error Counter (0x15) = %x\n", data);
++
++    /*
++     * data = e1000_read_phy_reg(shared, M88E1000_LED_CTRL_REG);
++     * DEBUGOUT1("M88E1000 LED control reg (0x18) = %x\n", data);
++     */
++
++    return;
++}
++#endif // DBG
++
++/******************************************************************************
++* Probes the expected PHY address for known PHY IDs
++*
++* shared - Struct containing variables accessed by shared code
++******************************************************************************/
++boolean_t
++e1000_detect_gig_phy(struct e1000_shared_adapter *shared)
++{
++    uint32_t phy_id_high;
++    uint16_t phy_id_low;
++
++    DEBUGFUNC("e1000_detect_gig_phy");
++
++    /* Read the PHY ID Registers to identify which PHY is onboard. */
++    shared->phy_addr = 1;
++
++    phy_id_high = e1000_read_phy_reg(shared, PHY_ID1);
++
++    usec_delay(2);
++
++    phy_id_low = e1000_read_phy_reg(shared, PHY_ID2);
++
++    shared->phy_id = (phy_id_low | (phy_id_high << 16)) & PHY_REVISION_MASK;
++
++    if(shared->phy_id == M88E1000_12_PHY_ID ||
++       shared->phy_id == M88E1000_14_PHY_ID ||
++       shared->phy_id == M88E1000_I_PHY_ID  ||
++       shared->phy_id == M88E1011_I_PHY_ID) {
++
++        DEBUGOUT2("phy_id 0x%x detected at address 0x%x\n",
++                  shared->phy_id, shared->phy_addr);
++        return (TRUE);
++    } else {
++        DEBUGOUT("Could not auto-detect Phy!\n");
++        return (FALSE);
++    }
++}
++
++/******************************************************************************
++* Resets the PHY's DSP
++*
++* shared - Struct containing variables accessed by shared code
++******************************************************************************/
++void
++e1000_phy_reset_dsp(struct e1000_shared_adapter *shared)
++{
++    e1000_write_phy_reg(shared, 29, 0x1d);
++    e1000_write_phy_reg(shared, 30, 0xc1);
++    e1000_write_phy_reg(shared, 30, 0x00);
++    return;
++}
++
++/******************************************************************************
++* Blocks until autoneg completes or times out (~4.5 seconds)
++*
++* shared - Struct containing variables accessed by shared code
++******************************************************************************/
++boolean_t
++e1000_wait_autoneg(struct e1000_shared_adapter *shared)
++{
++    uint16_t i;
++    uint16_t mii_status_reg;
++    boolean_t autoneg_complete = FALSE;
++
++    DEBUGFUNC("e1000_wait_autoneg");
++
++    /* We will wait for autoneg to complete. */
++    DEBUGOUT("Waiting for Auto-Neg to complete.\n");
++    mii_status_reg = 0;
++
++    /* 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.
++         */
++        mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
++        mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
++
++        if(mii_status_reg & MII_SR_AUTONEG_COMPLETE) {
++            autoneg_complete = TRUE;
++            break;
++        }
++
++        msec_delay(100);
++    }
++
++    return (autoneg_complete);
++}
++
++/******************************************************************************
++* Get PHY information from various PHY registers
++*
++* shared - Struct containing variables accessed by shared code
++* phy_status_info - PHY information structure
++******************************************************************************/
++boolean_t
++e1000_phy_get_info(struct e1000_shared_adapter *shared,
++                   struct e1000_phy_info *phy_status_info)
++{
++    uint16_t phy_mii_status_reg;
++    uint16_t phy_specific_ctrl_reg;
++    uint16_t phy_specific_status_reg;
++    uint16_t phy_specific_ext_ctrl_reg;
++    uint16_t phy_1000t_stat_reg;
++
++    phy_status_info->cable_length = e1000_cable_length_undefined;
++    phy_status_info->extended_10bt_distance =
++        e1000_10bt_ext_dist_enable_undefined;
++    phy_status_info->cable_polarity = e1000_rev_polarity_undefined;
++    phy_status_info->polarity_correction = e1000_polarity_reversal_undefined;
++    phy_status_info->link_reset = e1000_down_no_idle_undefined;
++    phy_status_info->mdix_mode = e1000_auto_x_mode_undefined;
++    phy_status_info->local_rx = e1000_1000t_rx_status_undefined;
++    phy_status_info->remote_rx = e1000_1000t_rx_status_undefined;
++
++    /* PHY info only valid for copper media. */
++    if(shared == NULL || shared->media_type != e1000_media_type_copper)
++        return FALSE;
++
++    /* PHY info only valid for LINK UP.  Read MII status reg 
++     * back-to-back to get link status.
++     */
++    phy_mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
++    phy_mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
++    if((phy_mii_status_reg & MII_SR_LINK_STATUS) != MII_SR_LINK_STATUS)
++        return FALSE;
++
++    /* Read various PHY registers to get the PHY info. */
++    phy_specific_ctrl_reg = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL);
++    phy_specific_status_reg =
++        e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_STATUS);
++    phy_specific_ext_ctrl_reg =
++        e1000_read_phy_reg(shared, M88E1000_EXT_PHY_SPEC_CTRL);
++    phy_1000t_stat_reg = e1000_read_phy_reg(shared, PHY_1000T_STATUS);
++
++    phy_status_info->cable_length =
++        ((phy_specific_status_reg & M88E1000_PSSR_CABLE_LENGTH) >>
++         M88E1000_PSSR_CABLE_LENGTH_SHIFT);
++
++    phy_status_info->extended_10bt_distance =
++        (phy_specific_ctrl_reg & M88E1000_PSCR_10BT_EXT_DIST_ENABLE) >>
++        M88E1000_PSCR_10BT_EXT_DIST_ENABLE_SHIFT;
++
++    phy_status_info->cable_polarity =
++        (phy_specific_status_reg & M88E1000_PSSR_REV_POLARITY) >>
++        M88E1000_PSSR_REV_POLARITY_SHIFT;
++
++    phy_status_info->polarity_correction =
++        (phy_specific_ctrl_reg & M88E1000_PSCR_POLARITY_REVERSAL) >>
++        M88E1000_PSCR_POLARITY_REVERSAL_SHIFT;
++
++    phy_status_info->link_reset =
++        (phy_specific_ext_ctrl_reg & M88E1000_EPSCR_DOWN_NO_IDLE) >>
++        M88E1000_EPSCR_DOWN_NO_IDLE_SHIFT;
++
++    phy_status_info->mdix_mode =
++        (phy_specific_status_reg & M88E1000_PSSR_MDIX) >>
++        M88E1000_PSSR_MDIX_SHIFT;
++
++    phy_status_info->local_rx =
++        (phy_1000t_stat_reg & SR_1000T_LOCAL_RX_STATUS) >>
++        SR_1000T_LOCAL_RX_STATUS_SHIFT;
++
++    phy_status_info->remote_rx =
++        (phy_1000t_stat_reg & SR_1000T_REMOTE_RX_STATUS) >>
++        SR_1000T_REMOTE_RX_STATUS_SHIFT;
++
++    return TRUE;
++}
++
++boolean_t
++e1000_validate_mdi_setting(struct e1000_shared_adapter *shared)
++{
++    if(!shared->autoneg && (shared->mdix == 0 || shared->mdix == 3)) {
++        shared->mdix = 1;
++        return FALSE;
++    }
++    return TRUE;
++}
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ linux-2.4.18-14-root/drivers/e1000/e1000_phy.h     2003-01-02 16:22:31.000000000 -0800
+@@ -0,0 +1,424 @@
++/*******************************************************************************
++
++  This software program is available to you under a choice of one of two 
++  licenses. You may choose to be licensed under either the GNU General Public 
++  License (GPL) Version 2, June 1991, available at 
++  http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the 
++  text of which follows:
++  
++  Recipient has requested a license and Intel Corporation ("Intel") is willing
++  to grant a license for the software entitled Linux Base Driver for the 
++  Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided
++  by Intel Corporation. The following definitions apply to this license:
++  
++  "Licensed Patents" means patent claims licensable by Intel Corporation which 
++  are necessarily infringed by the use of sale of the Software alone or when 
++  combined with the operating system referred to below.
++  
++  "Recipient" means the party to whom Intel delivers this Software.
++  
++  "Licensee" means Recipient and those third parties that receive a license to 
++  any operating system available under the GNU Public License version 2.0 or 
++  later.
++  
++  Copyright (c) 1999 - 2002 Intel Corporation.
++  All rights reserved.
++  
++  The license is provided to Recipient and Recipient's Licensees under the 
++  following terms.
++  
++  Redistribution and use in source and binary forms of the Software, with or 
++  without modification, are permitted provided that the following conditions 
++  are met:
++  
++  Redistributions of source code of the Software may retain the above 
++  copyright notice, this list of conditions and the following disclaimer.
++  
++  Redistributions in binary form of the Software may reproduce the above 
++  copyright notice, this list of conditions and the following disclaimer in 
++  the documentation and/or materials provided with the distribution.
++  
++  Neither the name of Intel Corporation nor the names of its contributors 
++  shall be used to endorse or promote products derived from this Software 
++  without specific prior written permission.
++  
++  Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, 
++  royalty-free patent license under Licensed Patents to make, use, sell, offer 
++  to sell, import and otherwise transfer the Software, if any, in source code 
++  and object code form. This license shall include changes to the Software 
++  that are error corrections or other minor changes to the Software that do 
++  not add functionality or features when the Software is incorporated in any 
++  version of an operating system that has been distributed under the GNU 
++  General Public License 2.0 or later. This patent license shall apply to the 
++  combination of the Software and any operating system licensed under the GNU 
++  Public License version 2.0 or later if, at the time Intel provides the 
++  Software to Recipient, such addition of the Software to the then publicly 
++  available versions of such operating systems available under the GNU Public 
++  License version 2.0 or later (whether in gold, beta or alpha form) causes 
++  such combination to be covered by the Licensed Patents. The patent license 
++  shall not apply to any other combinations which include the Software. NO 
++  hardware per se is licensed hereunder.
++  
++  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 MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
++  ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY 
++  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
++  (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
++  ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) 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.
++
++*******************************************************************************/
++
++/* e1000_phy.h
++ * Structures, enums, and macros for the PHY
++ */
++
++#ifndef _E1000_PHY_H_
++#define _E1000_PHY_H_
++
++#include "e1000_osdep.h"
++
++/* PHY status info structure and supporting enums */
++typedef enum {
++    e1000_cable_length_50 = 0,
++    e1000_cable_length_50_80,
++    e1000_cable_length_80_110,
++    e1000_cable_length_110_140,
++    e1000_cable_length_140,
++    e1000_cable_length_undefined = 0xFF
++} e1000_cable_length;
++
++typedef enum {
++    e1000_10bt_ext_dist_enable_normal = 0,
++    e1000_10bt_ext_dist_enable_lower,
++    e1000_10bt_ext_dist_enable_undefined = 0xFF
++} e1000_10bt_ext_dist_enable;
++
++typedef enum {
++    e1000_rev_polarity_normal = 0,
++    e1000_rev_polarity_reversed,
++    e1000_rev_polarity_undefined = 0xFF
++} e1000_rev_polarity;
++
++typedef enum {
++    e1000_polarity_reversal_enabled = 0,
++    e1000_polarity_reversal_disabled,
++    e1000_polarity_reversal_undefined = 0xFF
++} e1000_polarity_reversal;
++
++typedef enum {
++    e1000_down_no_idle_no_detect = 0,
++    e1000_down_no_idle_detect,
++    e1000_down_no_idle_undefined = 0xFF
++} e1000_down_no_idle;
++
++typedef enum {
++    e1000_auto_x_mode_manual_mdi = 0,
++    e1000_auto_x_mode_manual_mdix,
++    e1000_auto_x_mode_auto1,
++    e1000_auto_x_mode_auto2,
++    e1000_auto_x_mode_undefined = 0xFF
++} e1000_auto_x_mode;
++
++typedef enum {
++    e1000_1000t_rx_status_not_ok = 0,
++    e1000_1000t_rx_status_ok,
++    e1000_1000t_rx_status_undefined = 0xFF
++} e1000_1000t_rx_status;
++
++struct e1000_phy_info {
++    e1000_cable_length cable_length;
++    e1000_10bt_ext_dist_enable extended_10bt_distance;
++    e1000_rev_polarity cable_polarity;
++    e1000_polarity_reversal polarity_correction;
++    e1000_down_no_idle link_reset;
++    e1000_auto_x_mode mdix_mode;
++    e1000_1000t_rx_status local_rx;
++    e1000_1000t_rx_status remote_rx;
++};
++
++struct e1000_phy_stats {
++    uint32_t idle_errors;
++    uint32_t receive_errors;
++};
++
++/* Function Prototypes */
++uint16_t e1000_read_phy_reg(struct e1000_shared_adapter *shared, uint32_t reg_addr);
++void e1000_write_phy_reg(struct e1000_shared_adapter *shared, uint32_t reg_addr, uint16_t data);
++void e1000_phy_hw_reset(struct e1000_shared_adapter *shared);
++boolean_t e1000_phy_reset(struct e1000_shared_adapter *shared);
++boolean_t e1000_phy_setup(struct e1000_shared_adapter *shared, uint32_t ctrl_reg);
++boolean_t e1000_phy_setup_autoneg(struct e1000_shared_adapter *shared);
++void e1000_config_mac_to_phy(struct e1000_shared_adapter *shared, uint16_t mii_reg);
++void e1000_config_collision_dist(struct e1000_shared_adapter *shared);
++void e1000_display_mii(struct e1000_shared_adapter *shared);
++boolean_t e1000_detect_gig_phy(struct e1000_shared_adapter *shared);
++void e1000_phy_reset_dsp(struct e1000_shared_adapter *shared);
++boolean_t e1000_wait_autoneg(struct e1000_shared_adapter *shared);
++boolean_t e1000_phy_get_info(struct e1000_shared_adapter *shared, struct e1000_phy_info *phy_status_info);
++boolean_t e1000_validate_mdi_setting(struct e1000_shared_adapter *shared);
++
++/* 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 MAX_PHY_REG_ADDRESS 0x1F        /* 5 bit address bus (0-0x1F) */
++
++/* 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  0x0100 /* 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
++
++/* 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_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_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 
++                                              */
++#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 */
++
++#define M88E1000_EPSCR_DOWN_NO_IDLE_SHIFT 15
++
++/* Bit definitions for valid PHY IDs. */
++#define M88E1000_12_PHY_ID 0x01410C50
++#define M88E1000_14_PHY_ID 0x01410C40
++#define M88E1000_I_PHY_ID  0x01410C30
++#define M88E1011_I_PHY_ID  0x01410C20
++
++/* 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 */
++
++#endif /* _E1000_PHY_H_ */
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ linux-2.4.18-14-root/drivers/e1000/e1000_proc.c    2003-01-02 16:22:31.000000000 -0800
+@@ -0,0 +1,1437 @@
++/*******************************************************************************
++
++  This software program is available to you under a choice of one of two 
++  licenses. You may choose to be licensed under either the GNU General Public 
++  License (GPL) Version 2, June 1991, available at 
++  http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the 
++  text of which follows:
++  
++  Recipient has requested a license and Intel Corporation ("Intel") is willing
++  to grant a license for the software entitled Linux Base Driver for the 
++  Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided
++  by Intel Corporation. The following definitions apply to this license:
++  
++  "Licensed Patents" means patent claims licensable by Intel Corporation which 
++  are necessarily infringed by the use of sale of the Software alone or when 
++  combined with the operating system referred to below.
++  
++  "Recipient" means the party to whom Intel delivers this Software.
++  
++  "Licensee" means Recipient and those third parties that receive a license to 
++  any operating system available under the GNU Public License version 2.0 or 
++  later.
++  
++  Copyright (c) 1999 - 2002 Intel Corporation.
++  All rights reserved.
++  
++  The license is provided to Recipient and Recipient's Licensees under the 
++  following terms.
++  
++  Redistribution and use in source and binary forms of the Software, with or 
++  without modification, are permitted provided that the following conditions 
++  are met:
++  
++  Redistributions of source code of the Software may retain the above 
++  copyright notice, this list of conditions and the following disclaimer.
++  
++  Redistributions in binary form of the Software may reproduce the above 
++  copyright notice, this list of conditions and the following disclaimer in 
++  the documentation and/or materials provided with the distribution.
++  
++  Neither the name of Intel Corporation nor the names of its contributors 
++  shall be used to endorse or promote products derived from this Software 
++  without specific prior written permission.
++  
++  Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, 
++  royalty-free patent license under Licensed Patents to make, use, sell, offer 
++  to sell, import and otherwise transfer the Software, if any, in source code 
++  and object code form. This license shall include changes to the Software 
++  that are error corrections or other minor changes to the Software that do 
++  not add functionality or features when the Software is incorporated in any 
++  version of an operating system that has been distributed under the GNU 
++  General Public License 2.0 or later. This patent license shall apply to the 
++  combination of the Software and any operating system licensed under the GNU 
++  Public License version 2.0 or later if, at the time Intel provides the 
++  Software to Recipient, such addition of the Software to the then publicly 
++  available versions of such operating systems available under the GNU Public 
++  License version 2.0 or later (whether in gold, beta or alpha form) causes 
++  such combination to be covered by the Licensed Patents. The patent license 
++  shall not apply to any other combinations which include the Software. NO 
++  hardware per se is licensed hereunder.
++  
++  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 MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
++  ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY 
++  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
++  (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
++  ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) 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.
++
++*******************************************************************************/
++
++/***************************************************************************/
++/*       /proc File System Interaface Support Functions                    */
++/***************************************************************************/
++
++#include "e1000.h"
++extern char e1000_driver_name[];
++extern char e1000_driver_version[];
++#include "e1000_proc.h"
++#include <linux/proc_fs.h>
++
++struct proc_dir_entry *e1000_proc_dir;
++
++#define CABLE_LENGTH_TO_STRING() \
++   msg = \
++   (adapter->phy_info.cable_length == e1000_cable_length_50)      ? "0-50 Meters (+/- 20 Meters)"  : \
++   (adapter->phy_info.cable_length == e1000_cable_length_50_80)   ? "50-80 Meters (+/- 20 Meters)"  : \
++   (adapter->phy_info.cable_length == e1000_cable_length_80_110)  ? "80-110 Meters (+/- 20 Meters)" : \
++   (adapter->phy_info.cable_length == e1000_cable_length_110_140) ? "110-140 Meters (+/- 20 Meters)" : \
++   (adapter->phy_info.cable_length == e1000_cable_length_140)     ? "> 140 Meters (+/- 20 Meters)" : \
++   "Unknown";
++
++#define EXTENDED_10BASE_T_DISTANCE_TO_STRING() \
++    msg = \
++    (adapter->phy_info.extended_10bt_distance == \
++            e1000_10bt_ext_dist_enable_normal) ? "Disabled" : \
++    (adapter->phy_info.extended_10bt_distance == \
++                    e1000_10bt_ext_dist_enable_lower) ? "Enabled" : "Unknown"; 
++
++#define CABLE_POLARITY_TO_STRING() \
++    msg = \
++    (adapter->phy_info.cable_polarity == e1000_rev_polarity_normal) ? "Normal" : \
++    (adapter->phy_info.cable_polarity == e1000_rev_polarity_reversed) ? \
++                                        "Reversed" : "Unknown";
++
++#define POLARITY_CORRECTION_TO_STRING() \
++    msg = \
++    (adapter->phy_info.polarity_correction == \
++                    e1000_polarity_reversal_enabled) ? "Disabled" : \
++    (adapter->phy_info.polarity_correction == \
++                    e1000_polarity_reversal_disabled) ? "Enabled" : "Undefined";
++
++#define LINK_RESET_TO_STRING() \
++    msg = \
++    (adapter->phy_info.link_reset == e1000_down_no_idle_no_detect) ? "Disabled" : \
++    (adapter->phy_info.link_reset == e1000_down_no_idle_detect) ? "Enabled" : \
++    "Unknown"; 
++
++#define MDI_X_MODE_TO_STRING() \
++    msg = (adapter->phy_info.mdix_mode == 0) ? "MDI" :  "MDI-X";
++
++#define LOCAL_RECEIVER_STATUS_TO_STRING() \
++    msg = \
++    (adapter->phy_info.local_rx == e1000_1000t_rx_status_not_ok) ? "NOT_OK" : \
++    (adapter->phy_info.local_rx == e1000_1000t_rx_status_ok) ? "OK" : \
++    "Unknown";
++
++#define REMOTE_RECEIVER_STATUS_TO_STRING() \
++    msg = \
++    (adapter->phy_info.remote_rx == e1000_1000t_rx_status_not_ok) ? "NOT_OK" : \
++    (adapter->phy_info.remote_rx == e1000_1000t_rx_status_ok) ? "OK" : \
++    "Unknown";
++
++static void e1000_link_update(struct e1000_adapter * adapter) {
++
++    e1000_check_for_link(&adapter->shared);
++    if(E1000_READ_REG(&adapter->shared, STATUS) & E1000_STATUS_LU)
++        adapter->link_active = 1;
++    else
++        adapter->link_active = 0;
++
++    if (adapter->link_active) {
++        e1000_get_speed_and_duplex(&adapter->shared, &adapter->link_speed, &adapter->link_duplex);
++    } else {
++        adapter->link_speed = 0;
++        adapter->link_duplex = 0;
++    }
++    return;
++}
++
++static int e1000_generic_read(char *page, char **start, off_t off,
++                              int count, int *eof)
++{
++    int len;
++
++    len = strlen(page);
++    page[len++] = '\n';
++
++    if (len <= off + count)
++        *eof = 1;
++    *start = page + off;
++    len -= off;
++    if (len > count)
++        len = count;
++    if (len < 0)
++        len = 0;
++    return len;
++}
++
++static int e1000_read_ulong(char *page, char **start, off_t off,
++               int count, int *eof, unsigned long l)
++{
++    sprintf(page, "%lu", l);
++
++    return e1000_generic_read(page, start, off, count, eof);
++}
++
++static int e1000_read_ulong_hex(char *page, char **start, off_t off,
++                   int count, int *eof, unsigned long l)
++{
++    sprintf(page, "0x%04lx", l);
++
++    return e1000_generic_read(page, start, off, count, eof);
++}
++
++static int e1000_read_ullong(char *page, char **start, off_t off,
++               int count, int *eof, unsigned long long l)
++{
++    sprintf(page, "%Lu", l);
++
++    return e1000_generic_read(page, start, off, count, eof);
++}
++
++static int e1000_read_hwaddr(char *page, char **start, off_t off,
++                int count, int *eof, unsigned char *hwaddr)
++{
++    sprintf(page, "%02X:%02X:%02X:%02X:%02X:%02X",
++            hwaddr[0], hwaddr[1], hwaddr[2],
++            hwaddr[3], hwaddr[4], hwaddr[5]);
++
++    return e1000_generic_read(page, start, off, count, eof);
++}
++
++/* need to check page boundaries !!! */
++static int e1000_read_info(char *page, char **start, off_t off,
++              int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++    struct net_device_stats *stats = &adapter->net_stats;
++    unsigned char *hwaddr;
++    char *pagep = page;
++    char *msg;
++
++    page += sprintf(page, "%-32s %s\n", DESCRIPTION_TAG, adapter->id_string);
++    page += sprintf(page, "%-32s %06lx-%03x\n",
++                    PART_NUMBER_TAG, 
++                    (unsigned long )adapter->part_num >> 8, 
++                    adapter->part_num & 0x000000FF);
++
++    page += sprintf(page, "%-32s %s\n", DRVR_NAME_TAG, e1000_driver_name);
++
++    page += sprintf(page, "%-32s %s\n", DRVR_VERSION_TAG, e1000_driver_version);
++
++    page += sprintf(page, "%-32s 0x%04lx\n",
++                    PCI_VENDOR_TAG, (unsigned long) adapter->vendor_id);
++    page += sprintf(page, "%-32s 0x%04lx\n",
++                    PCI_DEVICE_ID_TAG, (unsigned long) adapter->device_id);
++    page += sprintf(page, "%-32s 0x%04lx\n",
++                    PCI_SUBSYSTEM_VENDOR_TAG,
++                    (unsigned long) adapter->subven_id);
++    page += sprintf(page, "%-32s 0x%04lx\n",
++                    PCI_SUBSYSTEM_ID_TAG,
++                    (unsigned long) adapter->subsys_id);
++    page += sprintf(page, "%-32s 0x%02lx\n",
++                    PCI_REVISION_ID_TAG,
++                    (unsigned long) adapter->rev_id);
++    
++    page += sprintf(page, "%-32s %lu\n",
++                    PCI_BUS_TAG,
++                    (unsigned long) (adapter->pdev->bus->number));
++    page += sprintf(page, "%-32s %lu\n",
++                    PCI_SLOT_TAG,
++                    (unsigned
++                     long) (PCI_SLOT((adapter->pdev->devfn))));
++       
++    if(adapter->shared.mac_type >= e1000_82543) {
++        page += sprintf(page, "%-32s %s\n",
++                PCI_BUS_TYPE_TAG,
++                (adapter->shared.bus_type == e1000_bus_type_pci)  ? "PCI"   :
++                (adapter->shared.bus_type == e1000_bus_type_pcix) ? "PCI-X" :
++                "UNKNOWN");
++    
++        page += sprintf(page, "%-32s %s\n",
++            PCI_BUS_SPEED_TAG,
++            (adapter->shared.bus_speed == e1000_bus_speed_33)  ? "33MHz"  :
++            (adapter->shared.bus_speed == e1000_bus_speed_66)  ? "66MHz"  :
++            (adapter->shared.bus_speed == e1000_bus_speed_100) ? "100MHz" :
++            (adapter->shared.bus_speed == e1000_bus_speed_133) ? "133MHz" :
++                "UNKNOWN");
++    
++        page += sprintf(page, "%-32s %s\n",
++                PCI_BUS_WIDTH_TAG,
++                (adapter->shared.bus_width == e1000_bus_width_32) ? "32-bit" :
++                (adapter->shared.bus_width == e1000_bus_width_64) ? "64-bit" :
++                "UNKNOWN");
++    }
++    
++    page +=
++        sprintf(page, "%-32s %lu\n", IRQ_TAG,
++                (unsigned long) (adapter->pdev->irq));
++    page +=
++        sprintf(page, "%-32s %s\n", SYSTEM_DEVICE_NAME_TAG,
++                adapter->netdev->name);
++
++    hwaddr = adapter->netdev->dev_addr;
++    page += sprintf(page, "%-32s %02X:%02X:%02X:%02X:%02X:%02X\n",
++                    CURRENT_HWADDR_TAG,
++                    hwaddr[0], hwaddr[1], hwaddr[2],
++                    hwaddr[3], hwaddr[4], hwaddr[5]);
++
++    hwaddr = adapter->perm_net_addr;
++    page += sprintf(page, "%-32s %02X:%02X:%02X:%02X:%02X:%02X\n",
++                    PERMANENT_HWADDR_TAG,
++                    hwaddr[0], hwaddr[1], hwaddr[2],
++                    hwaddr[3], hwaddr[4], hwaddr[5]);
++
++    page += sprintf(page, "\n");
++    
++    /* If board is not open yet, */
++    if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) 
++        e1000_link_update(adapter);
++
++    if (adapter->link_active == 1)
++        msg = "up";
++    else
++        msg = "down";
++    page += sprintf(page, "%-32s %s\n", LINK_TAG, msg);
++
++    if (adapter->link_speed)
++        page += sprintf(page, "%-32s %lu\n",
++                        SPEED_TAG,
++                        (unsigned long) (adapter->link_speed));
++    else
++        page += sprintf(page, "%-32s %s\n", SPEED_TAG, "N/A");
++
++    msg = adapter->link_duplex == FULL_DUPLEX ? "full" :
++        ((adapter->link_duplex == 0) ? "N/A" : "half");
++    page += sprintf(page, "%-32s %s\n", DUPLEX_TAG, msg);
++
++    if (adapter->netdev->flags & IFF_UP)
++        msg = "up";
++    else
++        msg = "down";
++    page += sprintf(page, "%-32s %s\n", STATE_TAG, msg);
++
++    page += sprintf(page, "\n");
++
++    page += sprintf(page, "%-32s %lu\n",
++                    RX_PACKETS_TAG, (unsigned long) stats->rx_packets);
++    page += sprintf(page, "%-32s %lu\n",
++                    TX_PACKETS_TAG, (unsigned long) stats->tx_packets);
++    page += sprintf(page, "%-32s %lu\n",
++                    RX_BYTES_TAG, (unsigned long) stats->rx_bytes);
++    page += sprintf(page, "%-32s %lu\n",
++                    TX_BYTES_TAG, (unsigned long) stats->tx_bytes);
++    page += sprintf(page, "%-32s %lu\n",
++                    RX_ERRORS_TAG, (unsigned long) stats->rx_errors);
++    page += sprintf(page, "%-32s %lu\n",
++                    TX_ERRORS_TAG, (unsigned long) stats->tx_errors);
++    page += sprintf(page, "%-32s %lu\n",
++                    RX_DROPPED_TAG, (unsigned long) stats->rx_dropped);
++    page += sprintf(page, "%-32s %lu\n",
++                    TX_DROPPED_TAG, (unsigned long) stats->tx_dropped);
++    page += sprintf(page, "%-32s %lu\n",
++                    MULTICAST_TAG, (unsigned long) stats->multicast);
++    page += sprintf(page, "%-32s %lu\n",
++                    COLLISIONS_TAG, (unsigned long) stats->collisions);
++    page += sprintf(page, "%-32s %lu\n",
++                    RX_LENGTH_ERRORS_TAG,
++                    (unsigned long) stats->rx_length_errors);
++    page += sprintf(page, "%-32s %lu\n",
++                    RX_OVER_ERRORS_TAG,
++                    (unsigned long) stats->rx_over_errors);
++    page += sprintf(page, "%-32s %lu\n",
++                    RX_CRC_ERRORS_TAG,
++                    (unsigned long) stats->rx_crc_errors);
++    page += sprintf(page, "%-32s %lu\n",
++                    RX_FRAME_ERRORS_TAG,
++                    (unsigned long) stats->rx_frame_errors);
++    page += sprintf(page, "%-32s %lu\n",
++                    RX_FIFO_ERRORS_TAG,
++                    (unsigned long) stats->rx_fifo_errors);
++    page += sprintf(page, "%-32s %lu\n",
++                    RX_MISSED_ERRORS_TAG,
++                    (unsigned long) stats->rx_missed_errors);
++    page += sprintf(page, "%-32s %lu\n",
++                    TX_ABORTED_ERRORS_TAG,
++                    (unsigned long) stats->tx_aborted_errors);
++    page += sprintf(page, "%-32s %lu\n",
++                    TX_CARRIER_ERRORS_TAG,
++                    (unsigned long) stats->tx_carrier_errors);
++    page += sprintf(page, "%-32s %lu\n",
++                    TX_FIFO_ERRORS_TAG,
++                    (unsigned long) stats->tx_fifo_errors);
++    page += sprintf(page, "%-32s %lu\n",
++                    TX_HEARTBEAT_ERRORS_TAG,
++                    (unsigned long) stats->tx_heartbeat_errors);
++    page += sprintf(page, "%-32s %lu\n",
++                    TX_WINDOW_ERRORS_TAG,
++                    (unsigned long) stats->tx_window_errors);
++
++    page += sprintf(page, "\n");
++
++    /* 8254x specific stats */
++    page += sprintf(page, "%-32s %Lu\n",
++                    TX_LATE_COLL_TAG,
++                    (unsigned long long)adapter->stats.latecol);
++    page += sprintf(page, "%-32s %Lu\n",
++                    TX_DEFERRED_TAG,
++                    (unsigned long long)adapter->stats.dc);
++    page += sprintf(page, "%-32s %Lu\n",
++                    TX_SINGLE_COLL_TAG,
++                    (unsigned long long)adapter->stats.scc);
++    page += sprintf(page, "%-32s %Lu\n",
++                    TX_MULTI_COLL_TAG,
++                    (unsigned long long)adapter->stats.mcc);
++    page += sprintf(page, "%-32s %Lu\n",
++                    RX_LONG_ERRORS_TAG,
++                    (unsigned long long)adapter->stats.roc);
++    page += sprintf(page, "%-32s %Lu\n",
++                    RX_SHORT_ERRORS_TAG,
++                    (unsigned long long)adapter->stats.ruc);
++    /* The 82542 does not have an alignment error count register */
++    /* ALGNERRC is only valid in MII mode at 10 or 100 Mbps */
++    if(adapter->shared.mac_type >= e1000_82543)
++        page += sprintf(page, "%-32s %Lu\n",
++                        RX_ALIGN_ERRORS_TAG,
++                        (unsigned long long)adapter->stats.algnerrc);
++    page += sprintf(page, "%-32s %Lu\n",
++                    RX_XON_TAG,
++                    (unsigned long long)adapter->stats.xonrxc);
++    page += sprintf(page, "%-32s %Lu\n",
++                    RX_XOFF_TAG,
++                    (unsigned long long)adapter->stats.xoffrxc);
++    page += sprintf(page, "%-32s %Lu\n",
++                    TX_XON_TAG,
++                    (unsigned long long)adapter->stats.xontxc);
++    page += sprintf(page, "%-32s %Lu\n",
++                    TX_XOFF_TAG,
++                    (unsigned long long)adapter->stats.xofftxc);
++    page += sprintf(page, "%-32s %Lu\n",
++                    RX_CSUM_GOOD_TAG,
++                    (unsigned long long)adapter->XsumRXGood);
++    page += sprintf(page, "%-32s %Lu\n",
++                    RX_CSUM_ERROR_TAG,
++                    (unsigned long long)adapter->XsumRXError);
++
++    if (adapter->shared.media_type == e1000_media_type_copper)
++        msg = "Copper";
++    else
++        msg = "Fiber";
++    page += sprintf(page, "\n%-32s %s\n", MEDIA_TYPE_TAG, msg);
++    
++    if (adapter->shared.media_type == e1000_media_type_copper) {
++       CABLE_LENGTH_TO_STRING();
++       page += sprintf(page, "%-32s %s\n", CABLE_LENGTH_TAG, msg);
++
++       EXTENDED_10BASE_T_DISTANCE_TO_STRING();
++       page += sprintf(page, "%-32s %s\n", EXTENDED_10BASE_T_DISTANCE_TAG, msg);
++ 
++       CABLE_POLARITY_TO_STRING();
++       page += sprintf(page, "%-32s %s\n", CABLE_POLARITY_TAG, msg);
++
++       POLARITY_CORRECTION_TO_STRING();
++       page += sprintf(page, "%-32s %s\n",  CABLE_POLARITY_CORRECTION_TAG, msg);
++
++       page += sprintf(page, "%-32s %lu\n", IDLE_ERRORS_TAG, (unsigned long)adapter->phy_stats.idle_errors );
++
++       LINK_RESET_TO_STRING();
++       page += sprintf(page, "%-32s %s\n", LINK_RESET_ENABLED_TAG, msg);
++
++       page += sprintf(page, "%-32s %lu\n", RECEIVE_ERRORS_TAG, (unsigned long)adapter->phy_stats.receive_errors);
++
++       MDI_X_MODE_TO_STRING();
++       page += sprintf(page, "%-32s %s\n", MDI_X_ENABLED_TAG, msg);
++
++       LOCAL_RECEIVER_STATUS_TO_STRING();
++       page += sprintf(page, "%-32s %s\n", LOCAL_RECEIVER_STATUS_TAG, msg);
++
++       REMOTE_RECEIVER_STATUS_TO_STRING();
++       page += sprintf(page, "%-32s %s\n", REMOTE_RECEIVER_STATUS_TAG, msg);
++    }
++
++    *page = 0;
++    return e1000_generic_read(pagep, start, off, count, eof);
++}
++
++static int e1000_read_descr(char *page, char **start, off_t off,
++               int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++    
++    strncpy(page, adapter->id_string, PAGE_SIZE);
++    return e1000_generic_read(page, start, off, count, eof);
++}
++
++static int e1000_read_partnum(char *page, char **start, off_t off,
++                          int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++    sprintf(page, "%06lx-%03x",
++            (unsigned long)adapter->part_num >> 8,
++            adapter->part_num & 0x000000FF);
++
++    return e1000_generic_read(page, start, off, count, eof);
++}
++
++static int e1000_read_drvr_name(char *page, char **start, off_t off,
++                   int count, int *eof, void *data)
++{
++    strncpy(page, e1000_driver_name, PAGE_SIZE);
++
++    return e1000_generic_read(page, start, off, count, eof);
++}
++
++static int e1000_read_drvr_ver(char *page, char **start, off_t off,
++                  int count, int *eof, void *data)
++{
++    strncpy(page, e1000_driver_version, PAGE_SIZE);
++
++    return e1000_generic_read(page, start, off, count, eof);
++}
++
++static int e1000_read_pci_vendor(char *page, char **start, off_t off,
++                    int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++
++    return e1000_read_ulong_hex(page, start, off, count, eof,
++                          (unsigned long) adapter->vendor_id);
++}
++
++static int e1000_read_pci_device(char *page, char **start, off_t off,
++                    int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++
++    return e1000_read_ulong_hex(page, start, off, count, eof,
++                          (unsigned long) adapter->device_id);
++}
++
++static int e1000_read_pci_sub_vendor(char *page, char **start, off_t off,
++                        int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++
++    return e1000_read_ulong_hex(page, start, off, count, eof,
++                          (unsigned long) adapter->subven_id);
++}
++
++static int e1000_read_pci_sub_device(char *page, char **start, off_t off,
++                        int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++
++    return e1000_read_ulong_hex(page, start, off, count, eof,
++                          (unsigned long) adapter->subsys_id);
++}
++
++static int e1000_read_pci_revision(char *page, char **start, off_t off,
++                      int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++
++    return e1000_read_ulong_hex(page, start, off, count, eof,
++                          (unsigned long) adapter->rev_id);
++}
++
++static int e1000_read_dev_name(char *page, char **start, off_t off,
++                  int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++
++    strncpy(page, adapter->netdev->name, PAGE_SIZE);
++
++    return e1000_generic_read(page, start, off, count, eof);
++}
++
++static int e1000_read_pci_bus(char *page, char **start, off_t off,
++                 int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++
++    return e1000_read_ulong(page, start, off, count, eof,
++                      (unsigned long) (adapter->pdev->bus->number));
++}
++
++static int e1000_read_pci_slot(char *page, char **start, off_t off,
++                  int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++
++    return e1000_read_ulong(page, start, off, count, eof,
++                      (unsigned
++                       long) (PCI_SLOT((adapter->pdev->devfn))));
++}
++
++static int e1000_read_pci_bus_type(char *page, char **start, off_t off,
++               int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++
++    strncpy(page,
++        (adapter->shared.bus_type == e1000_bus_type_pci)  ? "PCI"   :
++        (adapter->shared.bus_type == e1000_bus_type_pcix) ? "PCI-X" :
++        "UNKNOWN", PAGE_SIZE);
++
++    return e1000_generic_read(page, start, off, count, eof);
++}
++
++static int e1000_read_pci_bus_speed(char *page, char **start, off_t off,
++               int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++
++    strncpy(page, 
++        (adapter->shared.bus_speed == e1000_bus_speed_33)  ? "33MHz"  :
++        (adapter->shared.bus_speed == e1000_bus_speed_66)  ? "66MHz"  :
++        (adapter->shared.bus_speed == e1000_bus_speed_100) ? "100MHz" :
++        (adapter->shared.bus_speed == e1000_bus_speed_133) ? "133MHz" :
++        "UNKNOWN", PAGE_SIZE);
++
++    return e1000_generic_read(page, start, off, count, eof);
++}
++
++static int e1000_read_pci_bus_width(char *page, char **start, off_t off,
++               int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++
++    strncpy(page, 
++        (adapter->shared.bus_width == e1000_bus_width_32) ? "32-bit" :
++        (adapter->shared.bus_width == e1000_bus_width_64) ? "64-bit" :
++        "UNKNOWN", PAGE_SIZE);
++
++    return e1000_generic_read(page, start, off, count, eof);
++}
++
++static int e1000_read_irq(char *page, char **start, off_t off,
++             int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++
++    return e1000_read_ulong(page, start, off, count, eof,
++                      (unsigned long) (adapter->pdev->irq));
++}
++
++static int e1000_read_current_hwaddr(char *page, char **start, off_t off,
++                        int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++    unsigned char *hwaddr = adapter->netdev->dev_addr;
++
++    return e1000_read_hwaddr(page, start, off, count, eof, hwaddr);
++}
++
++static int e1000_read_permanent_hwaddr(char *page, char **start, off_t off,
++                          int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++    unsigned char *hwaddr = adapter->perm_net_addr;
++
++    return e1000_read_hwaddr(page, start, off, count, eof, hwaddr);
++}
++
++static int e1000_read_link_status(char *page, char **start, off_t off,
++                     int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++
++    /* If board is not open yet, */
++    if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) 
++        e1000_link_update(adapter);
++
++    if (adapter->link_active == 1)
++        strncpy(page, "up", PAGE_SIZE);
++    else
++        strncpy(page, "down", PAGE_SIZE);
++
++    return e1000_generic_read(page, start, off, count, eof);
++}
++
++static int e1000_read_speed(char *page, char **start, off_t off,
++               int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++
++    /* If board is not open yet, */
++    if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) 
++        e1000_link_update(adapter);
++
++    if (adapter->link_speed)
++        return e1000_read_ulong(page, start, off, count, eof,
++                          (unsigned long) (adapter->link_speed));
++    strncpy(page, "N/A", PAGE_SIZE);
++    return e1000_generic_read(page, start, off, count, eof);
++}
++
++static int e1000_read_dplx_mode(char *page, char **start, off_t off,
++                   int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++    char *dplx_mode;
++
++    /* If board is not open yet, */
++    if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) 
++        e1000_link_update(adapter);
++
++    dplx_mode = adapter->link_duplex == FULL_DUPLEX ? "full" :
++        ((adapter->link_duplex == 0) ? "N/A" : "half");
++    strncpy(page, dplx_mode, PAGE_SIZE);
++
++    return e1000_generic_read(page, start, off, count, eof);
++}
++
++static int e1000_read_state(char *page, char **start, off_t off,
++               int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++
++    if (adapter->netdev->flags & IFF_UP)
++        strncpy(page, "up", PAGE_SIZE);
++    else
++        strncpy(page, "down", PAGE_SIZE);
++
++    return e1000_generic_read(page, start, off, count, eof);
++}
++
++static int e1000_read_rx_packets(char *page, char **start, off_t off,
++                    int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++
++    return e1000_read_ulong(page, start, off, count, eof,
++                      (unsigned long) adapter->net_stats.rx_packets);
++}
++
++static int e1000_read_tx_packets(char *page, char **start, off_t off,
++                    int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++
++    return e1000_read_ulong(page, start, off, count, eof,
++                      (unsigned long) adapter->net_stats.tx_packets);
++}
++
++static int e1000_read_rx_bytes(char *page, char **start, off_t off,
++                  int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++
++    return e1000_read_ulong(page, start, off, count, eof,
++                      (unsigned long) adapter->net_stats.rx_bytes);
++}
++
++static int e1000_read_tx_bytes(char *page, char **start, off_t off,
++                  int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++
++    return e1000_read_ulong(page, start, off, count, eof,
++                      (unsigned long) adapter->net_stats.tx_bytes);
++}
++
++static int e1000_read_rx_errors(char *page, char **start, off_t off,
++                   int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++
++    return e1000_read_ulong(page, start, off, count, eof,
++                      (unsigned long) adapter->net_stats.rx_errors);
++}
++
++static int e1000_read_tx_errors(char *page, char **start, off_t off,
++                   int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++
++    return e1000_read_ulong(page, start, off, count, eof,
++                      (unsigned long) adapter->net_stats.tx_errors);
++}
++
++static int e1000_read_rx_dropped(char *page, char **start, off_t off,
++                    int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++
++    return e1000_read_ulong(page, start, off, count, eof,
++                      (unsigned long) adapter->net_stats.rx_dropped);
++}
++
++static int e1000_read_tx_dropped(char *page, char **start, off_t off,
++                    int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++
++    return e1000_read_ulong(page, start, off, count, eof,
++                      (unsigned long) adapter->net_stats.tx_dropped);
++}
++
++static int e1000_read_rx_multicast_packets(char *page, char **start, off_t off,
++                              int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++
++    return e1000_read_ulong(page, start, off, count, eof,
++                      (unsigned long) adapter->net_stats.multicast);
++}
++
++static int e1000_read_collisions(char *page, char **start, off_t off,
++                    int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++
++    return e1000_read_ulong(page, start, off, count, eof,
++                      (unsigned long) adapter->net_stats.collisions);
++}
++
++static int e1000_read_rx_length_errors(char *page, char **start, off_t off,
++                          int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++
++    return e1000_read_ulong(page, start, off, count, eof,
++                      (unsigned long) adapter->net_stats.rx_length_errors);
++}
++
++static int e1000_read_rx_over_errors(char *page, char **start, off_t off,
++                        int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++
++    return e1000_read_ulong(page, start, off, count, eof,
++                      (unsigned long) adapter->net_stats.rx_over_errors);
++}
++
++static int e1000_read_rx_crc_errors(char *page, char **start, off_t off,
++                       int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++
++    return e1000_read_ulong(page, start, off, count, eof,
++                      (unsigned long) adapter->net_stats.rx_crc_errors);
++}
++
++static int e1000_read_rx_frame_errors(char *page, char **start, off_t off,
++                         int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++
++    return e1000_read_ulong(page, start, off, count, eof,
++                      (unsigned long) adapter->net_stats.rx_frame_errors);
++}
++
++static int e1000_read_rx_fifo_errors(char *page, char **start, off_t off,
++                        int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++
++    return e1000_read_ulong(page, start, off, count, eof,
++                      (unsigned long) adapter->net_stats.rx_fifo_errors);
++}
++
++static int e1000_read_rx_missed_errors(char *page, char **start, off_t off,
++                          int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++
++    return e1000_read_ulong(page, start, off, count, eof,
++                      (unsigned long) adapter->net_stats.rx_missed_errors);
++}
++
++static int e1000_read_tx_aborted_errors(char *page, char **start, off_t off,
++                           int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++
++    return e1000_read_ulong(page, start, off, count, eof,
++                      (unsigned long) adapter->net_stats.tx_aborted_errors);
++}
++
++static int e1000_read_tx_carrier_errors(char *page, char **start, off_t off,
++                           int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++
++    return e1000_read_ulong(page, start, off, count, eof,
++                      (unsigned long) adapter->net_stats.tx_carrier_errors);
++}
++
++static int e1000_read_tx_fifo_errors(char *page, char **start, off_t off,
++                        int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++
++    return e1000_read_ulong(page, start, off, count, eof,
++                      (unsigned long) adapter->net_stats.tx_fifo_errors);
++}
++
++static int e1000_read_tx_heartbeat_errors(char *page, char **start, off_t off,
++                             int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++
++    return e1000_read_ulong(page, start, off, count, eof,
++                      (unsigned long) adapter->net_stats.tx_heartbeat_errors);
++}
++
++static int e1000_read_tx_window_errors(char *page, char **start, off_t off,
++                          int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++
++    return e1000_read_ulong(page, start, off, count, eof,
++                      (unsigned long) adapter->net_stats.tx_window_errors);
++}
++
++/* 8254x specific stats */
++static int e1000_read_tx_late_coll(char *page, char **start, off_t off,
++                             int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++    return e1000_read_ullong(page, start, off, count, eof, adapter->stats.latecol);
++}
++
++static int e1000_read_tx_defer_events(char *page, char **start, off_t off,
++                             int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++    return e1000_read_ullong(page, start, off, count, eof, adapter->stats.dc);
++}
++static int e1000_read_tx_single_coll(char *page, char **start, off_t off,
++                             int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++    return e1000_read_ullong(page, start, off, count, eof, adapter->stats.scc);
++}
++static int e1000_read_tx_multi_coll(char *page, char **start, off_t off,
++                             int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++    return e1000_read_ullong(page, start, off, count, eof, adapter->stats.mcc);
++}
++static int e1000_read_rx_oversize(char *page, char **start, off_t off,
++                             int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++    return e1000_read_ullong(page, start, off, count, eof, adapter->stats.roc);
++}
++static int e1000_read_rx_undersize(char *page, char **start, off_t off,
++                             int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++    return e1000_read_ullong(page, start, off, count, eof, adapter->stats.ruc);
++}
++static int e1000_read_rx_align_err(char *page, char **start, off_t off,
++                             int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++    return e1000_read_ullong(page, start, off, count, eof, adapter->stats.algnerrc);
++}
++static int e1000_read_rx_xon(char *page, char **start, off_t off,
++                             int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++    return e1000_read_ullong(page, start, off, count, eof, adapter->stats.xonrxc);
++}
++static int e1000_read_rx_xoff(char *page, char **start, off_t off,
++                             int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++    return e1000_read_ullong(page, start, off, count, eof, adapter->stats.xoffrxc);
++}
++static int e1000_read_tx_xon(char *page, char **start, off_t off,
++                             int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++    return e1000_read_ullong(page, start, off, count, eof, adapter->stats.xontxc);
++}
++static int e1000_read_tx_xoff(char *page, char **start, off_t off,
++                             int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++    return e1000_read_ullong(page, start, off, count, eof, adapter->stats.xofftxc);
++}
++
++static struct proc_dir_entry *e1000_create_proc_read(char *name,
++    struct e1000_adapter * adapter,
++    struct proc_dir_entry *parent,
++    read_proc_t * read_proc)
++{
++    struct proc_dir_entry *pdep;
++
++    if (!(pdep = create_proc_entry(name, S_IFREG, parent)))
++        return NULL;
++    pdep->read_proc = read_proc;
++    pdep->data = adapter;
++    return pdep;
++}
++
++static int e1000_read_cable_length (char *page, char **start, 
++                off_t off, int count, int *eof, void *data)
++{
++    char *msg;
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++
++    /* If board is not open yet, */
++    if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) 
++        e1000_link_update(adapter);
++
++    CABLE_LENGTH_TO_STRING();
++    strncpy (page, msg, PAGE_SIZE);
++    return e1000_generic_read(page, start, off, count, eof);
++}
++
++static int e1000_read_media_type (char *page, char **start,
++                   off_t off, int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++
++    /* If board is not open yet, */
++    if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) 
++        e1000_link_update(adapter);
++
++    switch (adapter->shared.media_type) {
++        case e1000_media_type_copper: strncpy(page,"Copper", PAGE_SIZE); break;
++        case e1000_media_type_fiber: strncpy(page, "Fiber", PAGE_SIZE); break;
++        default: strncpy(page, "Unknown", PAGE_SIZE);    
++    }
++    return e1000_generic_read(page, start, off, count, eof);
++}
++
++static int e1000_read_extended_10base_t_distance (char *page, char **start, 
++                off_t off, int count, int *eof, void *data)
++{
++    char *msg;
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++
++    /* If board is not open yet, */
++    if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) 
++        e1000_link_update(adapter);
++
++    EXTENDED_10BASE_T_DISTANCE_TO_STRING();
++    strncpy (page, msg, PAGE_SIZE);
++    return e1000_generic_read(page, start, off, count, eof);
++}
++
++static int e1000_read_cable_polarity (char *page, char **start, 
++                off_t off, int count, int *eof, void *data)
++{
++    char *msg;
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++
++    /* If board is not open yet, */
++    if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) 
++        e1000_link_update(adapter);
++
++    CABLE_POLARITY_TO_STRING();
++    strncpy (page, msg, PAGE_SIZE);
++    return e1000_generic_read(page, start, off, count, eof);
++}
++
++static int e1000_read_cable_polarity_correction (char *page, char **start, 
++                off_t off, int count, int *eof, void *data)
++{
++    char *msg;
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++
++    /* If board is not open yet, */
++    if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) 
++        e1000_link_update(adapter);
++
++    POLARITY_CORRECTION_TO_STRING();
++    strncpy (page, msg, PAGE_SIZE);
++    return e1000_generic_read(page, start, off, count, eof);
++}
++
++static int e1000_read_idle_errors (char *page, char **start, 
++                off_t off, int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++
++    /* If board is not open yet, */
++    if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) 
++        e1000_link_update(adapter);
++
++    return e1000_read_ulong(page, start, off, count, eof, adapter->phy_stats.idle_errors);
++}
++
++static int e1000_read_link_reset_enabled (char *page, char **start, 
++                off_t off, int count, int *eof, void *data)
++{
++    char *msg;
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++
++    /* If board is not open yet, */
++    if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) 
++        e1000_link_update(adapter);
++
++    LINK_RESET_TO_STRING();
++    strncpy (page, msg, PAGE_SIZE);
++    return e1000_generic_read(page, start, off, count, eof);
++}
++
++static int e1000_read_receive_errors (char *page, char **start, 
++                off_t off, int count, int *eof, void *data)
++{
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++
++    /* If board is not open yet, */
++    if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) 
++        e1000_link_update(adapter);
++
++    return e1000_read_ulong(page, start, off, count, eof, adapter->phy_stats.receive_errors);
++}
++
++static int e1000_read_mdi_x_enabled (char *page, char **start, 
++                off_t off, int count, int *eof, void *data)
++{
++    char *msg;
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++
++    /* If board is not open yet, */
++    if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) 
++        e1000_link_update(adapter);
++
++    MDI_X_MODE_TO_STRING();
++    strncpy (page, msg, PAGE_SIZE);
++    return e1000_generic_read(page, start, off, count, eof);
++}
++
++static int e1000_read_local_receiver_status (char *page, char **start, 
++                off_t off, int count, int *eof, void *data)
++{
++    char *msg;
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++
++    /* If board is not open yet, */
++    if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) 
++        e1000_link_update(adapter);
++
++    LOCAL_RECEIVER_STATUS_TO_STRING();
++    strncpy (page, msg, PAGE_SIZE);
++    return e1000_generic_read(page, start, off, count, eof);
++}
++
++static int e1000_read_remote_receiver_status (char *page, char **start, 
++                off_t off, int count, int *eof, void *data)
++{
++    char *msg;
++    struct e1000_adapter * adapter = (struct e1000_adapter *) data;
++
++    /* If board is not open yet, */
++    if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) 
++        e1000_link_update(adapter);
++    
++    REMOTE_RECEIVER_STATUS_TO_STRING();
++    strncpy (page, msg, PAGE_SIZE);
++    return e1000_generic_read(page, start, off, count, eof);
++}
++
++int e1000_create_proc_dev(struct e1000_adapter * adapter)
++{
++    struct proc_dir_entry *dev_dir;
++    char info[256];
++    int len;
++
++    dev_dir = create_proc_entry(adapter->netdev->name, S_IFDIR, e1000_proc_dir);
++
++    strncpy(info, adapter->netdev->name, sizeof(info));
++    len = strlen(info);
++    strncat(info + len, ".info", sizeof(info) - len);
++
++    /* info */
++    if (!(e1000_create_proc_read(info, adapter, e1000_proc_dir, e1000_read_info)))
++        return -1;
++
++    /* description */
++    if (!(e1000_create_proc_read(DESCRIPTION_TAG, adapter, dev_dir, e1000_read_descr)))
++        return -1;
++    /* part number */
++    if (!(e1000_create_proc_read(PART_NUMBER_TAG, adapter, dev_dir, e1000_read_partnum)))
++        return -1;
++    /* driver name */
++    if (!(e1000_create_proc_read(DRVR_NAME_TAG, adapter, dev_dir, e1000_read_drvr_name)))
++        return -1;
++    /* driver version */
++    if (!(e1000_create_proc_read(DRVR_VERSION_TAG, adapter, dev_dir, e1000_read_drvr_ver)))
++        return -1;
++    /* pci vendor */
++    if (!(e1000_create_proc_read(PCI_VENDOR_TAG, adapter, dev_dir, e1000_read_pci_vendor)))
++        return -1;
++    /* pci device id */
++    if (!(e1000_create_proc_read(PCI_DEVICE_ID_TAG, adapter, dev_dir,
++                           e1000_read_pci_device))) return -1;
++    /* pci sub vendor */
++    if (!(e1000_create_proc_read(PCI_SUBSYSTEM_VENDOR_TAG, adapter, dev_dir,
++                           e1000_read_pci_sub_vendor))) return -1;
++    /* pci sub device id */
++    if (!(e1000_create_proc_read(PCI_SUBSYSTEM_ID_TAG, adapter, dev_dir,
++                           e1000_read_pci_sub_device))) return -1;
++    /* pci revision id */
++    if (!(e1000_create_proc_read(PCI_REVISION_ID_TAG, adapter, dev_dir,
++                           e1000_read_pci_revision))) return -1;
++    /* device name */
++    if (!(e1000_create_proc_read(SYSTEM_DEVICE_NAME_TAG, adapter, dev_dir,
++                           e1000_read_dev_name))) return -1;
++    /* pci bus */
++    if (!(e1000_create_proc_read(PCI_BUS_TAG, adapter, dev_dir, e1000_read_pci_bus)))
++        return -1;
++    /* pci slot */
++    if (!(e1000_create_proc_read(PCI_SLOT_TAG, adapter, dev_dir, e1000_read_pci_slot)))
++        return -1;
++    /* pci bus type */
++    if (!(e1000_create_proc_read(PCI_BUS_TYPE_TAG, adapter, dev_dir, 
++                               e1000_read_pci_bus_type))) return -1;
++    /* pci bus speed */
++    if (!(e1000_create_proc_read(PCI_BUS_SPEED_TAG, adapter, dev_dir, 
++                               e1000_read_pci_bus_speed))) return -1;
++    /* pci bus width */
++    if (!(e1000_create_proc_read(PCI_BUS_WIDTH_TAG, adapter, dev_dir, 
++                               e1000_read_pci_bus_width))) return -1;
++    /* irq */
++    if (!(e1000_create_proc_read(IRQ_TAG, adapter, dev_dir, e1000_read_irq)))
++        return -1;
++    /* current hwaddr */
++    if (!(e1000_create_proc_read(CURRENT_HWADDR_TAG, adapter, dev_dir,
++                           e1000_read_current_hwaddr))) return -1;
++    /* permanent hwaddr */
++    if (!(e1000_create_proc_read(PERMANENT_HWADDR_TAG, adapter, dev_dir,
++                           e1000_read_permanent_hwaddr))) return -1;
++
++    /* link status */
++    if (!(e1000_create_proc_read(LINK_TAG, adapter, dev_dir, e1000_read_link_status)))
++        return -1;
++    /* speed */
++    if (!(e1000_create_proc_read(SPEED_TAG, adapter, dev_dir, e1000_read_speed)))
++        return -1;
++    /* duplex mode */
++    if (!(e1000_create_proc_read(DUPLEX_TAG, adapter, dev_dir, e1000_read_dplx_mode)))
++        return -1;
++    /* state */
++    if (!(e1000_create_proc_read(STATE_TAG, adapter, dev_dir, e1000_read_state)))
++        return -1;
++    /* rx packets */
++    if (!(e1000_create_proc_read(RX_PACKETS_TAG, adapter, dev_dir, e1000_read_rx_packets)))
++        return -1;
++    /* tx packets */
++    if (!(e1000_create_proc_read(TX_PACKETS_TAG, adapter, dev_dir, e1000_read_tx_packets)))
++        return -1;
++    /* rx bytes */
++    if (!(e1000_create_proc_read(RX_BYTES_TAG, adapter, dev_dir, e1000_read_rx_bytes)))
++        return -1;
++    /* tx bytes */
++    if (!(e1000_create_proc_read(TX_BYTES_TAG, adapter, dev_dir, e1000_read_tx_bytes)))
++        return -1;
++    /* rx errors */
++    if (!(e1000_create_proc_read(RX_ERRORS_TAG, adapter, dev_dir, e1000_read_rx_errors)))
++        return -1;
++    /* tx errors */
++    if (!(e1000_create_proc_read(TX_ERRORS_TAG, adapter, dev_dir, e1000_read_tx_errors)))
++        return -1;
++    /* rx dropped */
++    if (!(e1000_create_proc_read(RX_DROPPED_TAG, adapter, dev_dir, e1000_read_rx_dropped)))
++        return -1;
++    /* tx dropped */
++    if (!(e1000_create_proc_read(TX_DROPPED_TAG, adapter, dev_dir, e1000_read_tx_dropped)))
++        return -1;
++    /* multicast packets */
++    if (!(e1000_create_proc_read(MULTICAST_TAG, adapter, dev_dir, 
++                                    e1000_read_rx_multicast_packets)))
++        return -1;
++
++    /* collisions */
++    if (!(e1000_create_proc_read (COLLISIONS_TAG, adapter, dev_dir, e1000_read_collisions))) 
++        return -1;
++             
++    /* rx length errors */
++    if (!(e1000_create_proc_read(RX_LENGTH_ERRORS_TAG, adapter, dev_dir,
++                           e1000_read_rx_length_errors))) return -1;
++    /* rx over errors */
++    if (!(e1000_create_proc_read(RX_OVER_ERRORS_TAG, adapter, dev_dir,
++                               e1000_read_rx_over_errors))) return -1;
++    /* rx crc errors */
++    if (!(e1000_create_proc_read(RX_CRC_ERRORS_TAG, adapter, dev_dir,
++                           e1000_read_rx_crc_errors))) return -1;
++    /* rx frame errors */
++    if (!(e1000_create_proc_read(RX_FRAME_ERRORS_TAG, adapter, dev_dir,
++                           e1000_read_rx_frame_errors))) return -1;
++    /* rx fifo errors */
++    if (!(e1000_create_proc_read(RX_FIFO_ERRORS_TAG, adapter, dev_dir,
++                           e1000_read_rx_fifo_errors))) return -1;
++    /* rx missed errors */
++    if (!(e1000_create_proc_read(RX_MISSED_ERRORS_TAG, adapter, dev_dir,
++                           e1000_read_rx_missed_errors))) return -1;
++    /* tx aborted errors */
++    if (!(e1000_create_proc_read(TX_ABORTED_ERRORS_TAG, adapter, dev_dir,
++                           e1000_read_tx_aborted_errors))) return -1;
++    /* tx carrier errors */
++    if (!(e1000_create_proc_read(TX_CARRIER_ERRORS_TAG, adapter, dev_dir,
++                           e1000_read_tx_carrier_errors))) return -1;
++    /* tx fifo errors */
++    if (!(e1000_create_proc_read(TX_FIFO_ERRORS_TAG, adapter, dev_dir,
++                           e1000_read_tx_fifo_errors))) return -1;
++    /* tx heartbeat errors */
++    if (!(e1000_create_proc_read(TX_HEARTBEAT_ERRORS_TAG, adapter, dev_dir,
++                           e1000_read_tx_heartbeat_errors))) return -1;
++    /* tx window errors */
++    if (!(e1000_create_proc_read(TX_WINDOW_ERRORS_TAG, adapter, dev_dir,
++                           e1000_read_tx_window_errors))) return -1;
++
++    if (!(e1000_create_proc_read(TX_LATE_COLL_TAG, adapter, dev_dir,
++                           e1000_read_tx_late_coll))) return -1;
++    if (!(e1000_create_proc_read(TX_DEFERRED_TAG, adapter, dev_dir,
++                           e1000_read_tx_defer_events))) return -1;
++    if (!(e1000_create_proc_read(TX_SINGLE_COLL_TAG, adapter, dev_dir,
++                           e1000_read_tx_single_coll))) return -1;
++    if (!(e1000_create_proc_read(TX_MULTI_COLL_TAG, adapter, dev_dir,
++                           e1000_read_tx_multi_coll))) return -1;
++    if (!(e1000_create_proc_read(RX_LONG_ERRORS_TAG, adapter, dev_dir,
++                           e1000_read_rx_oversize))) return -1;
++    if (!(e1000_create_proc_read(RX_SHORT_ERRORS_TAG, adapter, dev_dir,
++                           e1000_read_rx_undersize))) return -1;
++    if(adapter->shared.mac_type >= e1000_82543)
++        if (!(e1000_create_proc_read(RX_ALIGN_ERRORS_TAG, adapter, dev_dir,
++                               e1000_read_rx_align_err))) return -1;
++    if (!(e1000_create_proc_read(RX_XON_TAG, adapter, dev_dir,
++                           e1000_read_rx_xon))) return -1;
++    if (!(e1000_create_proc_read(RX_XOFF_TAG, adapter, dev_dir,
++                           e1000_read_rx_xoff))) return -1;
++    if (!(e1000_create_proc_read(TX_XON_TAG, adapter, dev_dir,
++                           e1000_read_tx_xon))) return -1;
++    if (!(e1000_create_proc_read(TX_XOFF_TAG, adapter, dev_dir,
++                           e1000_read_tx_xoff))) return -1;
++
++    if (!(e1000_create_proc_read(MEDIA_TYPE_TAG, adapter, dev_dir,
++                    e1000_read_media_type))) return -1;
++    
++    if (adapter->shared.media_type == e1000_media_type_copper) {
++       if (!(e1000_create_proc_read(CABLE_LENGTH_TAG, adapter, dev_dir,
++                    e1000_read_cable_length))) return -1;
++   
++       if (!(e1000_create_proc_read(EXTENDED_10BASE_T_DISTANCE_TAG, 
++                   adapter, dev_dir,
++                   e1000_read_extended_10base_t_distance))) return -1;
++        
++       if (!(e1000_create_proc_read(CABLE_POLARITY_TAG, adapter, dev_dir,
++                    e1000_read_cable_polarity))) return -1;
++   
++       if (!(e1000_create_proc_read(CABLE_POLARITY_CORRECTION_TAG, adapter, dev_dir,
++                   e1000_read_cable_polarity_correction))) return -1;
++   
++       if (!(e1000_create_proc_read(IDLE_ERRORS_TAG, adapter, dev_dir,
++                    e1000_read_idle_errors))) return -1;
++   
++       if (!(e1000_create_proc_read(LINK_RESET_ENABLED_TAG, adapter, dev_dir,
++                   e1000_read_link_reset_enabled))) return -1;
++   
++       if (!(e1000_create_proc_read(RECEIVE_ERRORS_TAG, adapter, dev_dir,
++                    e1000_read_receive_errors))) return -1;
++   
++       if (!(e1000_create_proc_read(MDI_X_ENABLED_TAG, adapter, dev_dir,
++                   e1000_read_mdi_x_enabled))) return -1;
++  
++       if (!(e1000_create_proc_read(LOCAL_RECEIVER_STATUS_TAG, adapter, dev_dir,
++                   e1000_read_local_receiver_status))) return -1;
++   
++       if (!(e1000_create_proc_read(REMOTE_RECEIVER_STATUS_TAG, adapter, dev_dir,
++                   e1000_read_remote_receiver_status))) return -1;
++    }
++    
++    return 0;
++}
++
++void e1000_remove_proc_dev(struct net_device *dev)
++{
++    struct proc_dir_entry *de;
++    struct e1000_adapter * adapter = dev->priv;
++    char info[256];
++    int len;
++
++    len = strlen(dev->name);
++    strncpy(info, dev->name, sizeof(info));
++    strncat(info + len, ".info", sizeof(info) - len);
++
++    for (de = e1000_proc_dir->subdir; de; de = de->next) {
++        if ((de->namelen == len) && (!memcmp(de->name, dev->name, len)))
++            break;
++    }
++    if (de) {
++        remove_proc_entry(DESCRIPTION_TAG, de);
++        remove_proc_entry(PART_NUMBER_TAG, de);
++        remove_proc_entry(DRVR_NAME_TAG, de);
++        remove_proc_entry(DRVR_VERSION_TAG, de);
++        remove_proc_entry(PCI_VENDOR_TAG, de);
++        remove_proc_entry(PCI_DEVICE_ID_TAG, de);
++        remove_proc_entry(PCI_SUBSYSTEM_VENDOR_TAG, de);
++        remove_proc_entry(PCI_SUBSYSTEM_ID_TAG, de);
++        remove_proc_entry(PCI_REVISION_ID_TAG, de);
++        remove_proc_entry(SYSTEM_DEVICE_NAME_TAG, de);
++        remove_proc_entry(PCI_BUS_TAG, de);
++        remove_proc_entry(PCI_SLOT_TAG, de);
++        remove_proc_entry(PCI_BUS_TYPE_TAG, de);
++        remove_proc_entry(PCI_BUS_SPEED_TAG, de);
++        remove_proc_entry(PCI_BUS_WIDTH_TAG, de);
++        remove_proc_entry(IRQ_TAG, de);
++        remove_proc_entry(CURRENT_HWADDR_TAG, de);
++        remove_proc_entry(PERMANENT_HWADDR_TAG, de);
++
++        remove_proc_entry(LINK_TAG, de);
++        remove_proc_entry(SPEED_TAG, de);
++        remove_proc_entry(DUPLEX_TAG, de);
++        remove_proc_entry(STATE_TAG, de);
++
++        remove_proc_entry(RX_PACKETS_TAG, de);
++        remove_proc_entry(TX_PACKETS_TAG, de);
++        remove_proc_entry(RX_BYTES_TAG, de);
++        remove_proc_entry(TX_BYTES_TAG, de);
++        remove_proc_entry(RX_ERRORS_TAG, de);
++        remove_proc_entry(TX_ERRORS_TAG, de);
++        remove_proc_entry(RX_DROPPED_TAG, de);
++        remove_proc_entry(TX_DROPPED_TAG, de);
++        remove_proc_entry(MULTICAST_TAG, de);
++        remove_proc_entry(COLLISIONS_TAG, de);
++        remove_proc_entry(RX_LENGTH_ERRORS_TAG, de);
++        remove_proc_entry(RX_OVER_ERRORS_TAG, de);
++        remove_proc_entry(RX_CRC_ERRORS_TAG, de);
++        remove_proc_entry(RX_FRAME_ERRORS_TAG, de);
++        remove_proc_entry(RX_FIFO_ERRORS_TAG, de);
++        remove_proc_entry(RX_MISSED_ERRORS_TAG, de);
++        remove_proc_entry(TX_ABORTED_ERRORS_TAG, de);
++        remove_proc_entry(TX_CARRIER_ERRORS_TAG, de);
++        remove_proc_entry(TX_FIFO_ERRORS_TAG, de);
++        remove_proc_entry(TX_HEARTBEAT_ERRORS_TAG, de);
++        remove_proc_entry(TX_WINDOW_ERRORS_TAG, de);
++        remove_proc_entry(TX_LATE_COLL_TAG, de);
++        remove_proc_entry(TX_DEFERRED_TAG, de);
++        remove_proc_entry(TX_SINGLE_COLL_TAG, de);
++        remove_proc_entry(TX_MULTI_COLL_TAG, de);
++        remove_proc_entry(RX_LONG_ERRORS_TAG, de);
++        remove_proc_entry(RX_SHORT_ERRORS_TAG, de);
++        remove_proc_entry(RX_XON_TAG, de);
++        remove_proc_entry(RX_XOFF_TAG, de);
++        remove_proc_entry(TX_XON_TAG, de);
++        remove_proc_entry(TX_XOFF_TAG, de);
++
++        remove_proc_entry(MEDIA_TYPE_TAG, de);
++        if (adapter->shared.media_type == e1000_media_type_copper) {
++           remove_proc_entry(CABLE_LENGTH_TAG, de);
++           remove_proc_entry(EXTENDED_10BASE_T_DISTANCE_TAG, de);
++           remove_proc_entry(CABLE_POLARITY_TAG, de);
++           remove_proc_entry(CABLE_POLARITY_CORRECTION_TAG, de);
++           remove_proc_entry(IDLE_ERRORS_TAG, de);
++           remove_proc_entry(LINK_RESET_ENABLED_TAG, de);
++           remove_proc_entry(RECEIVE_ERRORS_TAG, de);
++           remove_proc_entry(MDI_X_ENABLED_TAG, de);
++           remove_proc_entry(LOCAL_RECEIVER_STATUS_TAG, de);
++           remove_proc_entry(REMOTE_RECEIVER_STATUS_TAG, de);
++        }
++    }
++
++    remove_proc_entry(info, e1000_proc_dir);
++    remove_proc_entry(dev->name, e1000_proc_dir);
++}
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ linux-2.4.18-14-root/drivers/e1000/e1000_proc.h    2003-01-02 16:22:31.000000000 -0800
+@@ -0,0 +1,181 @@
++/*******************************************************************************
++
++  This software program is available to you under a choice of one of two 
++  licenses. You may choose to be licensed under either the GNU General Public 
++  License (GPL) Version 2, June 1991, available at 
++  http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the 
++  text of which follows:
++  
++  Recipient has requested a license and Intel Corporation ("Intel") is willing
++  to grant a license for the software entitled Linux Base Driver for the 
++  Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided
++  by Intel Corporation. The following definitions apply to this license:
++  
++  "Licensed Patents" means patent claims licensable by Intel Corporation which 
++  are necessarily infringed by the use of sale of the Software alone or when 
++  combined with the operating system referred to below.
++  
++  "Recipient" means the party to whom Intel delivers this Software.
++  
++  "Licensee" means Recipient and those third parties that receive a license to 
++  any operating system available under the GNU Public License version 2.0 or 
++  later.
++  
++  Copyright (c) 1999 - 2002 Intel Corporation.
++  All rights reserved.
++  
++  The license is provided to Recipient and Recipient's Licensees under the 
++  following terms.
++  
++  Redistribution and use in source and binary forms of the Software, with or 
++  without modification, are permitted provided that the following conditions 
++  are met:
++  
++  Redistributions of source code of the Software may retain the above 
++  copyright notice, this list of conditions and the following disclaimer.
++  
++  Redistributions in binary form of the Software may reproduce the above 
++  copyright notice, this list of conditions and the following disclaimer in 
++  the documentation and/or materials provided with the distribution.
++  
++  Neither the name of Intel Corporation nor the names of its contributors 
++  shall be used to endorse or promote products derived from this Software 
++  without specific prior written permission.
++  
++  Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, 
++  royalty-free patent license under Licensed Patents to make, use, sell, offer 
++  to sell, import and otherwise transfer the Software, if any, in source code 
++  and object code form. This license shall include changes to the Software 
++  that are error corrections or other minor changes to the Software that do 
++  not add functionality or features when the Software is incorporated in any 
++  version of an operating system that has been distributed under the GNU 
++  General Public License 2.0 or later. This patent license shall apply to the 
++  combination of the Software and any operating system licensed under the GNU 
++  Public License version 2.0 or later if, at the time Intel provides the 
++  Software to Recipient, such addition of the Software to the then publicly 
++  available versions of such operating systems available under the GNU Public 
++  License version 2.0 or later (whether in gold, beta or alpha form) causes 
++  such combination to be covered by the Licensed Patents. The patent license 
++  shall not apply to any other combinations which include the Software. NO 
++  hardware per se is licensed hereunder.
++  
++  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 MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
++  ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY 
++  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
++  (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
++  ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) 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.
++
++*******************************************************************************/
++
++/* /proc definitions */
++#include <linux/proc_fs.h>
++
++#define ADAPTERS_PROC_DIR           "PRO_LAN_Adapters"
++
++#define DESCRIPTION_TAG             "Description"
++#define PART_NUMBER_TAG             "Part_Number"
++#define DRVR_NAME_TAG               "Driver_Name"
++#define DRVR_VERSION_TAG            "Driver_Version"
++#define PCI_VENDOR_TAG              "PCI_Vendor"
++#define PCI_DEVICE_ID_TAG           "PCI_Device_ID"
++#define PCI_SUBSYSTEM_VENDOR_TAG    "PCI_Subsystem_Vendor"
++#define PCI_SUBSYSTEM_ID_TAG        "PCI_Subsystem_ID"
++#define PCI_REVISION_ID_TAG         "PCI_Revision_ID"
++#define PCI_BUS_TAG                 "PCI_Bus"
++#define PCI_SLOT_TAG                "PCI_Slot"
++#define PCI_BUS_TYPE_TAG            "PCI_Bus_Type"
++#define PCI_BUS_SPEED_TAG           "PCI_Bus_Speed"
++#define PCI_BUS_WIDTH_TAG           "PCI_Bus_Width"
++#define IRQ_TAG                     "IRQ"
++#define SYSTEM_DEVICE_NAME_TAG      "System_Device_Name"
++#define CURRENT_HWADDR_TAG          "Current_HWaddr"
++#define PERMANENT_HWADDR_TAG        "Permanent_HWaddr"
++
++#define LINK_TAG                    "Link"
++#define SPEED_TAG                   "Speed"
++#define DUPLEX_TAG                  "Duplex"
++#define STATE_TAG                   "State"
++
++#define RX_PACKETS_TAG              "Rx_Packets"
++#define TX_PACKETS_TAG              "Tx_Packets"
++#define RX_BYTES_TAG                "Rx_Bytes"
++#define TX_BYTES_TAG                "Tx_Bytes"
++#define RX_ERRORS_TAG               "Rx_Errors"
++#define TX_ERRORS_TAG               "Tx_Errors"
++#define RX_DROPPED_TAG              "Rx_Dropped"
++#define TX_DROPPED_TAG              "Tx_Dropped"
++#define MULTICAST_TAG               "Multicast"
++#define COLLISIONS_TAG              "Collisions"
++#define RX_LENGTH_ERRORS_TAG        "Rx_Length_Errors"
++#define RX_OVER_ERRORS_TAG          "Rx_Over_Errors"
++#define RX_CRC_ERRORS_TAG           "Rx_CRC_Errors"
++#define RX_FRAME_ERRORS_TAG         "Rx_Frame_Errors"
++#define RX_FIFO_ERRORS_TAG          "Rx_FIFO_Errors"
++#define RX_MISSED_ERRORS_TAG        "Rx_Missed_Errors"
++#define TX_ABORTED_ERRORS_TAG       "Tx_Aborted_Errors"
++#define TX_CARRIER_ERRORS_TAG       "Tx_Carrier_Errors"
++#define TX_FIFO_ERRORS_TAG          "Tx_FIFO_Errors"
++#define TX_HEARTBEAT_ERRORS_TAG     "Tx_Heartbeat_Errors"
++#define TX_WINDOW_ERRORS_TAG        "Tx_Window_Errors"
++
++#define RX_TCP_CHECKSUM_GOOD_TAG    "Rx_TCP_Checksum_Good"
++#define RX_TCP_CHECKSUM_BAD_TAG     "Rx_TCP_Checksum_Bad"
++#define TX_TCP_CHECKSUM_GOOD_TAG    "Tx_TCP_Checksum_Good"
++#define TX_TCP_CHECKSUM_BAD_TAG     "Tx_TCP_Checksum_Bad"
++
++#define TX_LATE_COLL_TAG            "Tx_Abort_Late_Coll"
++#define TX_DEFERRED_TAG             "Tx_Deferred_Ok"
++#define TX_SINGLE_COLL_TAG          "Tx_Single_Coll_Ok"
++#define TX_MULTI_COLL_TAG           "Tx_Multi_Coll_Ok"
++#define RX_LONG_ERRORS_TAG          "Rx_Long_Length_Errors"
++#define RX_SHORT_ERRORS_TAG         "Rx_Short_Length_Errors"
++#define RX_ALIGN_ERRORS_TAG         "Rx_Align_Errors"
++#define RX_XON_TAG                  "Rx_Flow_Control_XON"
++#define RX_XOFF_TAG                 "Rx_Flow_Control_XOFF"
++#define TX_XON_TAG                  "Tx_Flow_Control_XON"
++#define TX_XOFF_TAG                 "Tx_Flow_Control_XOFF"
++#define RX_CSUM_GOOD_TAG            "Rx_Csum_Offload_Good"
++#define RX_CSUM_ERROR_TAG           "Rx_Csum_Offload_Errors"
++
++/* what is the cable length (only for 100/1000 modes)? - 50, 50-80, 80-110, 110-140 and > 140 meters */
++#define CABLE_LENGTH_TAG                 "PHY_Cable_Length"
++
++/* Media Type Copper/Fiber */
++#define MEDIA_TYPE_TAG                   "PHY_Media_Type"
++
++/* Is extended 10 Base-T distance feature enabled? This is done by lowering the receive threshold - enabled/disabled */
++#define EXTENDED_10BASE_T_DISTANCE_TAG   "PHY_Extended_10Base_T_Distance"
++
++/* Cable polarity Normal/Reversed */
++#define CABLE_POLARITY_TAG               "PHY_Cable_Polarity"
++
++/* Is Polarity reversal enabled? Enabled/Disabled */
++#define CABLE_POLARITY_CORRECTION_TAG    "PHY_Disable_Polarity_Correction"
++
++/* Number of IDLE Errors */
++#define IDLE_ERRORS_TAG                  "PHY_Idle_Errors"
++
++/* Should the link be brought down if an IDLE is not seen within 1 msec while in 1000mbps mode? Enabled/Disabled */
++#define LINK_RESET_ENABLED_TAG           "PHY_Link_Reset_Enabled"
++
++/* Number of receive errors */
++#define RECEIVE_ERRORS_TAG               "PHY_Receive_Errors"
++
++/* MDI-X Support Enabled? Auto, Manual(MDI) or Manual(MDI-X) */
++#define MDI_X_ENABLED_TAG                "PHY_MDI_X_Enabled"
++
++/* Local Receiver OK? OK/NOT_OK */
++#define LOCAL_RECEIVER_STATUS_TAG        "PHY_Local_Receiver_Status"
++
++/* Remote Receiver OK? OK/NOT_OK */
++#define REMOTE_RECEIVER_STATUS_TAG       "PHY_Remote_Receiver_Status"
++
++/* symbols exported to e1000_main */
++extern struct proc_dir_entry *e1000_proc_dir;
++extern int e1000_create_proc_dev(struct e1000_adapter * Adapter);
++extern void e1000_remove_proc_dev(struct net_device *dev);
+--- /dev/null  2002-08-30 16:31:37.000000000 -0700
++++ linux-2.4.18-14-root/drivers/e1000/Makefile        2003-01-02 16:22:31.000000000 -0800
+@@ -0,0 +1,92 @@
++################################################################################
++#
++# This software program is available to you under a choice of one of two 
++# licenses. You may choose to be licensed under either the GNU General Public 
++# License (GPL) Version 2, June 1991, available at 
++# http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the 
++# text of which follows:
++# 
++# Recipient has requested a license and Intel Corporation ("Intel") is willing
++# to grant a license for the software entitled Linux Base Driver for the 
++# Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided
++# by Intel Corporation. The following definitions apply to this license:
++# 
++# "Licensed Patents" means patent claims licensable by Intel Corporation which 
++# are necessarily infringed by the use of sale of the Software alone or when 
++# combined with the operating system referred to below.
++# 
++# "Recipient" means the party to whom Intel delivers this Software.
++# 
++# "Licensee" means Recipient and those third parties that receive a license to 
++# any operating system available under the GNU Public License version 2.0 or 
++# later.
++# 
++# Copyright (c) 1999 - 2002 Intel Corporation.
++# All rights reserved.
++# 
++# The license is provided to Recipient and Recipient's Licensees under the 
++# following terms.
++# 
++# Redistribution and use in source and binary forms of the Software, with or 
++# without modification, are permitted provided that the following conditions 
++# are met:
++# 
++# Redistributions of source code of the Software may retain the above 
++# copyright notice, this list of conditions and the following disclaimer.
++# 
++# Redistributions in binary form of the Software may reproduce the above 
++# copyright notice, this list of conditions and the following disclaimer in 
++# the documentation and/or materials provided with the distribution.
++# 
++# Neither the name of Intel Corporation nor the names of its contributors 
++# shall be used to endorse or promote products derived from this Software 
++# without specific prior written permission.
++# 
++# Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, 
++# royalty-free patent license under Licensed Patents to make, use, sell, offer 
++# to sell, import and otherwise transfer the Software, if any, in source code 
++# and object code form. This license shall include changes to the Software 
++# that are error corrections or other minor changes to the Software that do 
++# not add functionality or features when the Software is incorporated in any 
++# version of an operating system that has been distributed under the GNU 
++# General Public License 2.0 or later. This patent license shall apply to the 
++# combination of the Software and any operating system licensed under the GNU 
++# Public License version 2.0 or later if, at the time Intel provides the 
++# Software to Recipient, such addition of the Software to the then publicly 
++# available versions of such operating systems available under the GNU Public 
++# License version 2.0 or later (whether in gold, beta or alpha form) causes 
++# such combination to be covered by the Licensed Patents. The patent license 
++# shall not apply to any other combinations which include the Software. NO 
++# hardware per se is licensed hereunder.
++# 
++# 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 MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
++# ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY 
++# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
++# (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
++# ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) 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.
++#
++################################################################################
++
++###########################################################################
++# Configuration Section
++
++# Optional features - set to 'y' for on, anything else for off
++# Intel(R) Advanced Network Services
++IANS := n
++# Intel(R) PRO Diagnostics
++IDIAG := n
++
++###########################################################################
++# Driver files
++
++# core driver files
++O_TARGET := e1000.o
++obj-y          := e1000_main.o e1000_mac.o e1000_phy.o e1000_proc.o
++obj-m  := $(O_TARGET)
++
++include $(TOPDIR)/Rules.make
+--- linux-2.4.18-14/drivers/Makefile~e1000     2003-01-02 16:20:41.000000000 -0800
++++ linux-2.4.18-14-root/drivers/Makefile      2003-01-02 16:22:31.000000000 -0800
+@@ -6,14 +6,15 @@
+ #
+-mod-subdirs :=        addon dio mtd sbus video macintosh usb input telephony sgi ide \
++mod-subdirs :=        e1000 addon dio mtd sbus video macintosh usb input telephony sgi ide \
+               message/i2o message/fusion scsi md ieee1394 pnp isdn atm \
+               fc4 net/hamradio i2c acpi bluetooth sensors
+-subdir-y :=   addon parport char block net sound misc media cdrom hotplug
++subdir-y :=   e1000 addon parport char block net sound misc media cdrom hotplug
+ subdir-m :=   $(subdir-y)
++subdir-$(CONFIG_E1000)                += e1000
+ subdir-$(CONFIG_DIO)          += dio
+ subdir-$(CONFIG_PCI)          += pci
+ subdir-$(CONFIG_PCMCIA)               += pcmcia
+--- linux-2.4.18-14/Makefile~e1000     2003-01-02 16:20:51.000000000 -0800
++++ linux-2.4.18-14-root/Makefile      2003-01-02 16:22:31.000000000 -0800
+@@ -178,6 +178,7 @@ DRIVERS-$(CONFIG_PCMCIA) += drivers/pcmc
+ DRIVERS-$(CONFIG_NET_PCMCIA) += drivers/net/pcmcia/pcmcia_net.o
+ DRIVERS-$(CONFIG_NET_WIRELESS) += drivers/net/wireless/wireless_net.o
+ DRIVERS-$(CONFIG_PCMCIA_CHRDEV) += drivers/char/pcmcia/pcmcia_char.o
++DRIVERS-$(CONFIG_E1000) += drivers/e1000/e1000.o
+ DRIVERS-$(CONFIG_DIO) += drivers/dio/dio.a
+ DRIVERS-$(CONFIG_SBUS) += drivers/sbus/sbus_all.o
+ DRIVERS-$(CONFIG_ZORRO) += drivers/zorro/driver.o
+
+_
diff --git a/lustre/kernel_patches/patches/tcp_zero.patch b/lustre/kernel_patches/patches/tcp_zero.patch
new file mode 100644 (file)
index 0000000..27b2ab7
--- /dev/null
@@ -0,0 +1,468 @@
+
+Zero-copy tcp patch. An initial implementation
+we use for performance analysis. May render tree unstable.
+Use at your own risk.
+
+
+ 0 files changed
+
+--- linux-2.4.18-14/include/linux/skbuff.h~tcp_zero    2003-01-02 16:33:52.000000000 -0800
++++ linux-2.4.18-14-root/include/linux/skbuff.h        2003-01-02 16:36:14.000000000 -0800
+@@ -116,6 +116,30 @@ struct skb_frag_struct
+       __u16 size;
+ };
++/* Support for callback when skb data has been released */
++typedef struct zccd                           /* Zero Copy Callback Descriptor */
++{                                             /* (embed as first member of custom struct) */
++      atomic_t        zccd_count;             /* reference count */
++      void           (*zccd_destructor)(struct zccd *); /* callback when refcount reaches zero */
++} zccd_t;
++
++static inline void zccd_init (zccd_t *d, void (*callback)(zccd_t *))
++{
++      atomic_set (&d->zccd_count, 1);
++      d->zccd_destructor = callback;
++}
++
++static inline void zccd_get (zccd_t *d)               /* take a reference */
++{
++      atomic_inc (&d->zccd_count);
++}
++
++static inline void zccd_put (zccd_t *d)               /* release a reference */
++{
++      if (atomic_dec_and_test (&d->zccd_count))
++              (d->zccd_destructor)(d);
++}
++
+ /* This data is invariant across clones and lives at
+  * the end of the header data, ie. at skb->end.
+  */
+@@ -123,6 +147,12 @@ struct skb_shared_info {
+       atomic_t        dataref;
+       unsigned int    nr_frags;
+       struct sk_buff  *frag_list;
++      zccd_t          *zccd;                  /* zero copy descriptor */
++      zccd_t          *zccd2;                 /* 2nd zero copy descriptor */
++      /* NB we expect zero-copy data to be at least 1 packet, so
++       * having 2 zccds means we don't unneccessarily split the packet
++       * where consecutive zero-copy sends abutt.
++       */
+       skb_frag_t      frags[MAX_SKB_FRAGS];
+ };
+--- linux-2.4.18-14/include/net/tcp.h~tcp_zero 2003-01-02 16:34:14.000000000 -0800
++++ linux-2.4.18-14-root/include/net/tcp.h     2003-01-02 16:36:14.000000000 -0800
+@@ -639,6 +639,8 @@ extern int                 tcp_v4_tw_remember_stam
+ extern int                    tcp_sendmsg(struct sock *sk, struct msghdr *msg, int size);
+ extern ssize_t                        tcp_sendpage(struct socket *sock, struct page *page, int offset, size_t size, int flags);
++extern ssize_t                        tcp_sendpage_zccd(struct socket *sock, struct page *page, int offset, size_t size, 
++                                                int flags, zccd_t *zccd);
+ extern int                    tcp_ioctl(struct sock *sk, 
+                                         int cmd, 
+@@ -732,6 +734,9 @@ extern int                 tcp_recvmsg(struct sock *sk
+                                           struct msghdr *msg,
+                                           int len, int nonblock, 
+                                           int flags, int *addr_len);
++extern int                    tcp_recvpackets(struct sock *sk, 
++                                              struct sk_buff_head *packets,
++                                              int len, int nonblock);
+ extern int                    tcp_listen_start(struct sock *sk);
+--- linux-2.4.18-14/net/netsyms.c~tcp_zero     2003-01-02 16:34:39.000000000 -0800
++++ linux-2.4.18-14-root/net/netsyms.c 2003-01-02 16:36:14.000000000 -0800
+@@ -395,6 +395,8 @@ EXPORT_SYMBOL(sysctl_tcp_wmem);
+ EXPORT_SYMBOL(sysctl_tcp_ecn);
+ EXPORT_SYMBOL(tcp_cwnd_application_limited);
+ EXPORT_SYMBOL(tcp_sendpage);
++EXPORT_SYMBOL(tcp_sendpage_zccd);
++EXPORT_SYMBOL(tcp_recvpackets);
+ EXPORT_SYMBOL(tcp_write_xmit);
+@@ -415,6 +417,7 @@ EXPORT_SYMBOL(secure_ipv6_id);
+ #endif
+ EXPORT_SYMBOL(tcp_read_sock);
++EXPORT_SYMBOL(tcp_sendpage_zccd);
+ EXPORT_SYMBOL(netlink_set_err);
+ EXPORT_SYMBOL(netlink_broadcast);
+--- linux-2.4.18-14/net/core/skbuff.c~tcp_zero 2003-01-02 16:34:50.000000000 -0800
++++ linux-2.4.18-14-root/net/core/skbuff.c     2003-01-02 16:36:14.000000000 -0800
+@@ -208,6 +208,8 @@ struct sk_buff *alloc_skb(unsigned int s
+       atomic_set(&(skb_shinfo(skb)->dataref), 1);
+       skb_shinfo(skb)->nr_frags = 0;
+       skb_shinfo(skb)->frag_list = NULL;
++      skb_shinfo(skb)->zccd = NULL;           /* skbuffs kick off with NO user zero copy descriptors */
++      skb_shinfo(skb)->zccd2 = NULL;
+       return skb;
+ nodata:
+@@ -276,6 +278,10 @@ static void skb_release_data(struct sk_b
+ {
+       if (!skb->cloned ||
+           atomic_dec_and_test(&(skb_shinfo(skb)->dataref))) {
++              if (skb_shinfo(skb)->zccd != NULL) /* zero copy callback descriptor? */
++                      zccd_put (skb_shinfo(skb)->zccd); /* release hold */
++              if (skb_shinfo(skb)->zccd2 != NULL) /* 2nd zero copy callback descriptor? */
++                      zccd_put (skb_shinfo(skb)->zccd2); /* release hold */
+               if (skb_shinfo(skb)->nr_frags) {
+                       int i;
+                       for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
+@@ -532,6 +538,8 @@ int skb_linearize(struct sk_buff *skb, i
+       atomic_set(&(skb_shinfo(skb)->dataref), 1);
+       skb_shinfo(skb)->nr_frags = 0;
+       skb_shinfo(skb)->frag_list = NULL;
++      skb_shinfo(skb)->zccd = NULL;           /* copied data => no user zero copy descriptor */
++      skb_shinfo(skb)->zccd2 = NULL;
+       /* We are no longer a clone, even if we were. */
+       skb->cloned = 0;
+@@ -577,6 +585,14 @@ struct sk_buff *pskb_copy(struct sk_buff
+       n->data_len = skb->data_len;
+       n->len = skb->len;
++      
++      if (skb_shinfo(skb)->zccd != NULL)      /* user zero copy descriptor? */
++              zccd_get (skb_shinfo(skb)->zccd); /* 1 more ref (pages are shared) */
++      skb_shinfo(n)->zccd = skb_shinfo(skb)->zccd;
++
++      if (skb_shinfo(skb)->zccd2 != NULL)     /* 2nd user zero copy descriptor? */
++              zccd_get (skb_shinfo(skb)->zccd2); /* 1 more ref (pages are shared) */
++      skb_shinfo(n)->zccd2 = skb_shinfo(skb)->zccd2;
+       if (skb_shinfo(skb)->nr_frags) {
+               int i;
+@@ -620,6 +636,8 @@ int pskb_expand_head(struct sk_buff *skb
+       u8 *data;
+       int size = nhead + (skb->end - skb->head) + ntail;
+       long off;
++      zccd_t *zccd = skb_shinfo(skb)->zccd;   /* stash user zero copy descriptor */
++      zccd_t *zccd2 = skb_shinfo(skb)->zccd2; /* stash 2nd user zero copy descriptor */
+       if (skb_shared(skb))
+               BUG();
+@@ -641,6 +659,11 @@ int pskb_expand_head(struct sk_buff *skb
+       if (skb_shinfo(skb)->frag_list)
+               skb_clone_fraglist(skb);
++      if (zccd != NULL)                       /* user zero copy descriptor? */
++              zccd_get (zccd);                /* extra ref (pages are shared) */
++      if (zccd2 != NULL)                      /* 2nd user zero copy descriptor? */
++              zccd_get (zccd2);               /* extra ref (pages are shared) */
++      
+       skb_release_data(skb);
+       off = (data+nhead) - skb->head;
+@@ -655,6 +678,8 @@ int pskb_expand_head(struct sk_buff *skb
+       skb->nh.raw += off;
+       skb->cloned = 0;
+       atomic_set(&skb_shinfo(skb)->dataref, 1);
++      skb_shinfo(skb)->zccd = zccd;
++      skb_shinfo(skb)->zccd2 = zccd2;
+       return 0;
+ nodata:
+--- linux-2.4.18-14/net/ipv4/tcp.c~tcp_zero    2003-01-02 16:35:02.000000000 -0800
++++ linux-2.4.18-14-root/net/ipv4/tcp.c        2003-01-02 16:36:14.000000000 -0800
+@@ -745,7 +745,7 @@ do_interrupted:
+       goto out;
+ }
+-ssize_t do_tcp_sendpages(struct sock *sk, struct page **pages, int poffset, size_t psize, int flags);
++ssize_t do_tcp_sendpages(struct sock *sk, struct page **pages, int poffset, size_t psize, int flags, zccd_t *zccd);
+ static inline int
+ can_coalesce(struct sk_buff *skb, int i, struct page *page, int off)
+@@ -824,7 +824,8 @@ static int tcp_error(struct sock *sk, in
+       return err;
+ }
+-ssize_t do_tcp_sendpages(struct sock *sk, struct page **pages, int poffset, size_t psize, int flags)
++/* Extra parameter: user zero copy descriptor (or NULL if not doing that) */
++ssize_t do_tcp_sendpages(struct sock *sk, struct page **pages, int poffset, size_t psize, int flags, zccd_t *zccd)
+ {
+       struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+       int mss_now;
+@@ -872,6 +873,17 @@ new_segment:
+                       copy = size;
+               i = skb_shinfo(skb)->nr_frags;
++              
++              if (zccd != NULL &&             /* this is a zcc I/O */
++                  skb_shinfo(skb)->zccd != NULL && /* skb is part of a zcc I/O */
++                  skb_shinfo(skb)->zccd2 != NULL &&
++                  skb_shinfo(skb)->zccd != zccd && /* not the same one */
++                  skb_shinfo(skb)->zccd2 != zccd)
++              {
++                      tcp_mark_push (tp, skb);
++                      goto new_segment;
++              }
++              
+               if (can_coalesce(skb, i, page, offset)) {
+                       skb_shinfo(skb)->frags[i-1].size += copy;
+               } else if (i < MAX_SKB_FRAGS) {
+@@ -881,6 +893,20 @@ new_segment:
+                       tcp_mark_push(tp, skb);
+                       goto new_segment;
+               }
++              
++              if (zccd != NULL &&     /* this is a zcc I/O */
++                  skb_shinfo(skb)->zccd != zccd && /* not already referencing this zccd */
++                  skb_shinfo(skb)->zccd2 != zccd)
++              {
++                      zccd_get (zccd);        /* bump ref count */
++
++                      BUG_TRAP (skb_shinfo(skb)->zccd2 == NULL);
++
++                      if (skb_shinfo(skb)->zccd == NULL) /* reference this zccd */
++                              skb_shinfo(skb)->zccd = zccd;
++                      else 
++                              skb_shinfo(skb)->zccd2 = zccd;
++              }
+               skb->len += copy;
+               skb->data_len += copy;
+@@ -945,7 +971,31 @@ ssize_t tcp_sendpage(struct socket *sock
+       lock_sock(sk);
+       TCP_CHECK_TIMER(sk);
+-      res = do_tcp_sendpages(sk, &page, offset, size, flags);
++      res = do_tcp_sendpages(sk, &page, offset, size, flags, NULL);
++      TCP_CHECK_TIMER(sk);
++      release_sock(sk);
++      return res;
++}
++
++ssize_t tcp_sendpage_zccd(struct socket *sock, struct page *page, int offset, size_t size, 
++                        int flags, zccd_t *zccd)
++{
++      ssize_t res;
++      struct sock *sk = sock->sk;
++
++#define TCP_ZC_CSUM_FLAGS (NETIF_F_IP_CSUM|NETIF_F_NO_CSUM|NETIF_F_HW_CSUM)
++
++      if (!(sk->route_caps & NETIF_F_SG) ||   /* caller shouldn't waste her time */
++          !(sk->route_caps & TCP_ZC_CSUM_FLAGS)) /* on double mapping */
++              BUG ();
++
++#undef TCP_ZC_CSUM_FLAGS
++
++      lock_sock(sk);
++      TCP_CHECK_TIMER(sk);
++
++      res = do_tcp_sendpages(sk, &page, offset, size, flags, zccd);
++      
+       TCP_CHECK_TIMER(sk);
+       release_sock(sk);
+       return res;
+@@ -1769,6 +1819,202 @@ recv_urg:
+       goto out;
+ }
++int tcp_recvpackets (struct sock *sk, struct sk_buff_head *packets, 
++                   int len, int nonblock)
++{
++      struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
++      int copied;
++      long timeo;
++
++      BUG_TRAP (len > 0);
++//    BUG_TRAP ((flags & (MSG_OOB | MSG_PEEK | MSG_TRUNC)) == 0);
++      
++      lock_sock(sk);
++
++      TCP_CHECK_TIMER(sk);
++
++      copied = -ENOTCONN;
++      if (sk->state == TCP_LISTEN)
++              goto out;
++
++      copied = 0;
++      timeo = sock_rcvtimeo(sk, nonblock);
++
++      do {
++              struct sk_buff * skb;
++              u32 offset;
++              unsigned long used;
++              int exhausted;
++              int eaten;
++
++              /* Are we at urgent data? Stop if we have read anything. */
++              if (copied && tp->urg_data && tp->urg_seq == tp->copied_seq)
++                      break;
++
++              /* We need to check signals first, to get correct SIGURG
++               * handling. FIXME: Need to check this doesnt impact 1003.1g
++               * and move it down to the bottom of the loop
++               */
++              if (signal_pending(current)) {
++                      if (copied)
++                              break;
++                      copied = timeo ? sock_intr_errno(timeo) : -EAGAIN;
++                      break;
++              }
++
++              /* Next get a buffer. */
++
++              skb = skb_peek(&sk->receive_queue);
++
++              if (skb == NULL)                /* nothing ready */
++              {
++                      if (copied) {
++                              if (sk->err ||
++                                  sk->state == TCP_CLOSE ||
++                                  (sk->shutdown & RCV_SHUTDOWN) ||
++                                  !timeo ||
++                                  (0))
++                                      break;
++                      } else {
++                              if (sk->done)
++                                      break;
++
++                              if (sk->err) {
++                                      copied = sock_error(sk);
++                                      break;
++                              }
++
++                              if (sk->shutdown & RCV_SHUTDOWN)
++                                      break;
++
++                              if (sk->state == TCP_CLOSE) {
++                                      if (!sk->done) {
++                                              /* This occurs when user tries to read
++                                               * from never connected socket.
++                                               */
++                                              copied = -ENOTCONN;
++                                              break;
++                                      }
++                                      break;
++                              }
++
++                              if (!timeo) {
++                                      copied = -EAGAIN;
++                                      break;
++                              }
++                      }
++                      
++                      cleanup_rbuf(sk, copied);
++                      timeo = tcp_data_wait(sk, timeo);
++                      continue;
++              }
++              
++              BUG_TRAP (atomic_read (&skb->users) == 1);
++
++              exhausted = eaten = 0;
++
++              offset = tp->copied_seq - TCP_SKB_CB(skb)->seq;
++              if (skb->h.th->syn)
++                      offset--;
++
++              used = skb->len - offset;
++
++              if (tp->urg_data) {
++                      u32 urg_offset = tp->urg_seq - tp->copied_seq;
++                      if (urg_offset < used) {
++                              if (!urg_offset) { /* at urgent date */
++                                      if (!sk->urginline) {
++                                              tp->copied_seq++; /* discard the single byte of urgent data */
++                                              offset++;
++                                              used--;
++                                      }
++                              } else          /* truncate read */
++                                      used = urg_offset;
++                      }
++              }
++              
++              BUG_TRAP (used >= 0);
++              if (len < used)
++                      used = len;
++
++              if (used == 0)
++                      exhausted = 1;
++              else
++              {
++                      if (skb_is_nonlinear (skb))
++                      {
++                              int   rc = skb_linearize (skb, GFP_KERNEL);
++                              
++                              printk ("tcp_recvpackets(): linearising: %d\n", rc);
++
++                              if (rc)
++                              {
++                                      if (!copied)
++                                              copied = rc;
++                                      break;
++                              }
++                      }
++                      
++                      if ((offset + used) == skb->len) /* consuming the whole packet */
++                      {
++                              __skb_unlink (skb, &sk->receive_queue);
++                              dst_release (skb->dst);
++                              skb_orphan (skb);
++                              __skb_pull (skb, offset);
++                              __skb_queue_tail (packets, skb);
++                              exhausted = eaten = 1;
++                      } 
++                      else                    /* consuming only part of the packet */
++                      {
++                              struct sk_buff *skb2 = skb_clone (skb, GFP_KERNEL);
++
++                              if (skb2 == NULL)
++                              {
++                                      if (!copied)
++                                              copied = -ENOMEM;
++                                      break;
++                              }
++                              
++                              dst_release (skb2->dst);
++                              __skb_pull (skb2, offset);
++                              __skb_trim (skb2, used);
++                              __skb_queue_tail (packets, skb2);
++                      }
++                      
++                      tp->copied_seq += used;
++                      copied += used;
++                      len -= used;
++              }
++              
++              if (tp->urg_data && after(tp->copied_seq,tp->urg_seq)) {
++                      tp->urg_data = 0;
++                      tcp_fast_path_check(sk, tp);
++              }
++
++              if (!exhausted)
++                      continue;
++              
++              if (skb->h.th->fin)
++              {
++                      tp->copied_seq++;
++                      if (!eaten)
++                              tcp_eat_skb (sk, skb);
++                      break;
++              }
++              
++              if (!eaten)
++                      tcp_eat_skb (sk, skb);
++
++      } while (len > 0);
++
++ out:
++      /* Clean up data we have read: This will do ACK frames. */
++      cleanup_rbuf(sk, copied);
++      TCP_CHECK_TIMER(sk);
++      release_sock(sk);
++      return copied;
++}
++
+ /*
+  *    State processing on a close. This implements the state shift for
+  *    sending our FIN frame. Note that we only send a FIN for some
+
+_
diff --git a/lustre/kernel_patches/pc/e1000.pc b/lustre/kernel_patches/pc/e1000.pc
new file mode 100644 (file)
index 0000000..8d804d9
--- /dev/null
@@ -0,0 +1,12 @@
+drivers/e1000/e1000.h
+drivers/e1000/e1000_mac.c
+drivers/e1000/e1000_mac.h
+drivers/e1000/e1000_main.c
+drivers/e1000/e1000_osdep.h
+drivers/e1000/e1000_phy.c
+drivers/e1000/e1000_phy.h
+drivers/e1000/e1000_proc.c
+drivers/e1000/e1000_proc.h
+drivers/e1000/Makefile
+drivers/Makefile
+Makefile
diff --git a/lustre/kernel_patches/pc/tcp_zero.pc b/lustre/kernel_patches/pc/tcp_zero.pc
new file mode 100644 (file)
index 0000000..02877c0
--- /dev/null
@@ -0,0 +1,5 @@
+include/linux/skbuff.h
+include/net/tcp.h
+net/netsyms.c
+net/core/skbuff.c
+net/ipv4/tcp.c
diff --git a/lustre/kernel_patches/series/rh-8.0-intel b/lustre/kernel_patches/series/rh-8.0-intel
new file mode 100644 (file)
index 0000000..4fceef5
--- /dev/null
@@ -0,0 +1,10 @@
+dev_read_only.patch
+exports.patch
+kmem_cache_validate.patch
+lustre_version.patch
+uml_check_get_page.patch
+uml_no_panic.patch
+vfs_intent.patch
+uml_compile_fixes.patch
+e1000.patch
+tcp_zero.patch
diff --git a/lustre/kernel_patches/txt/e1000.txt b/lustre/kernel_patches/txt/e1000.txt
new file mode 100644 (file)
index 0000000..c0c1d89
--- /dev/null
@@ -0,0 +1,4 @@
+This patch creates the necessary drivers
+for the e1000 card that are not included with
+the standard RH distribution. This is used for the
+GigE e1000 cards.
diff --git a/lustre/kernel_patches/txt/tcp_zero.txt b/lustre/kernel_patches/txt/tcp_zero.txt
new file mode 100644 (file)
index 0000000..abc85b5
--- /dev/null
@@ -0,0 +1,3 @@
+Zero-copy tcp patch. An initial implementation
+we use for performance analysis. May render tree unstable.
+Use at your own risk.