]> git.hungrycats.org Git - linux/commitdiff
Merge Intel EtherExpress PRO/100 net driver "e100" from Intel,
authorJeff Garzik <jgarzik@mandrakesoft.com>
Wed, 6 Mar 2002 22:48:44 +0000 (17:48 -0500)
committerJeff Garzik <jgarzik@mandrakesoft.com>
Wed, 6 Mar 2002 22:48:44 +0000 (17:48 -0500)
version 2.0.19, plus boolean cleanups.
Bump version to 2.0.20-pre1.

Contributors: Eli Kupermann @ Intel, Amir Noam @ Intel

13 files changed:
drivers/net/Config.in
drivers/net/Makefile
drivers/net/e100/Makefile [new file with mode: 0644]
drivers/net/e100/e100.h [new file with mode: 0644]
drivers/net/e100/e100_config.c [new file with mode: 0644]
drivers/net/e100/e100_config.h [new file with mode: 0644]
drivers/net/e100/e100_eeprom.c [new file with mode: 0644]
drivers/net/e100/e100_main.c [new file with mode: 0644]
drivers/net/e100/e100_phy.c [new file with mode: 0644]
drivers/net/e100/e100_phy.h [new file with mode: 0644]
drivers/net/e100/e100_proc.c [new file with mode: 0644]
drivers/net/e100/e100_ucode.h [new file with mode: 0644]
drivers/net/e100/e100_vendor.h [new file with mode: 0644]

index cf3fa56ad91ef9dfc7177161baac203e6ed45c29..48878dcb331a8bd2fbc6b2e588a26f2260cf2c87 100644 (file)
@@ -166,7 +166,8 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
          tristate '    Digi Intl. RightSwitch SE-X support' CONFIG_DGRS
       fi
       dep_tristate '    Davicom DM910x/DM980x support' CONFIG_DM9102 $CONFIG_PCI
-      dep_tristate '    EtherExpressPro/100 support' CONFIG_EEPRO100 $CONFIG_PCI
+      dep_tristate '    EtherExpressPro/100 support (eepro100, original Becker driver)' CONFIG_EEPRO100 $CONFIG_PCI
+      dep_tristate '    EtherExpressPro/100 support (e100, Alternate Intel driver)' CONFIG_E100 $CONFIG_PCI
       dep_tristate '    Mylex EISA LNE390A/B support (EXPERIMENTAL)' CONFIG_LNE390 $CONFIG_EISA $CONFIG_EXPERIMENTAL
       dep_tristate '    Myson MTD-8xx PCI Ethernet support' CONFIG_FEALNX $CONFIG_PCI
       dep_tristate '    National Semiconductor DP8381x series PCI Ethernet support' CONFIG_NATSEMI $CONFIG_PCI
index 17d3039b9755356da422db85f094b8c836710480..17839b158877bcece92856ac21338e83989a362e 100644 (file)
@@ -25,6 +25,9 @@ ifeq ($(CONFIG_TULIP),y)
   obj-y += tulip/tulip.o
 endif
 
+ifeq ($(CONFIG_E100),y)
+  obj-y += e1000/e100.o
+endif
 ifeq ($(CONFIG_E1000),y)
   obj-y += e1000/e1000.o
 endif
@@ -36,6 +39,7 @@ endif
 subdir-$(CONFIG_NET_PCMCIA) += pcmcia
 subdir-$(CONFIG_NET_WIRELESS) += wireless
 subdir-$(CONFIG_TULIP) += tulip
+subdir-$(CONFIG_E100) += e100
 subdir-$(CONFIG_E1000) += e1000
 subdir-$(CONFIG_IRDA) += irda
 subdir-$(CONFIG_TR) += tokenring
diff --git a/drivers/net/e100/Makefile b/drivers/net/e100/Makefile
new file mode 100644 (file)
index 0000000..587a0f1
--- /dev/null
@@ -0,0 +1,16 @@
+#
+# Makefile for the Intel's E100 ethernet driver
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+O_TARGET := e100.o
+
+obj-y   := e100_main.o e100_config.o e100_proc.o e100_phy.o \
+          e100_eeprom.o
+obj-m   := $(O_TARGET)
+
+include $(TOPDIR)/Rules.make
diff --git a/drivers/net/e100/e100.h b/drivers/net/e100/e100.h
new file mode 100644 (file)
index 0000000..77e1fb5
--- /dev/null
@@ -0,0 +1,1033 @@
+/*******************************************************************************
+
+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/100 Family of Adapters (e100) (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.
+*******************************************************************************/
+
+#ifndef _E100_INC_
+#define _E100_INC_
+
+#include <linux/module.h>
+#include <linux/types.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/version.h>
+#include <linux/string.h>
+#include <linux/wait.h>
+#include <asm/io.h>
+#include <asm/unaligned.h>
+#include <asm/processor.h>
+#ifdef SIOCETHTOOL
+#include <linux/ethtool.h>
+#include <linux/inetdevice.h>
+#endif
+
+#include <linux/if.h>
+#include <asm/uaccess.h>
+#include <linux/proc_fs.h>
+#include <linux/ip.h>
+
+/*
+ *  Configure parameters for buffers per controller.
+ *  If the machine this is being used on is a faster machine (i.e. > 150MHz)
+ *  and running on a 10MBS network then more queueing of data occurs. This
+ *  may indicate the some of the numbers below should be adjusted.  Here are
+ *  some typical numbers:
+ *                             MAX_TCB 64
+ *                             MAX_RFD 64
+ *  The default numbers give work well on most systems tests so no real
+ *  adjustments really need to take place.  Also, if the machine is connected
+ *  to a 100MBS network the numbers described above can be lowered from the
+ *  defaults as considerably less data will be queued.
+ */
+
+#define MAX_TCB        64      /* number of transmit control blocks */
+#define MAX_TBD        MAX_TCB
+#define TX_FRAME_CNT   8       /* consecutive transmit frames per interrupt */
+/* TX_FRAME_CNT must be less than MAX_TCB    */
+#define MAX_RFD      64
+
+#define E100_DEFAULT_TCB   MAX_TCB
+#define E100_MIN_TCB       2*TX_FRAME_CNT + 3  /* make room for at least 2 interrupts */
+
+#ifdef __ia64__
+ /* We can't use too many DMAble buffers on IA64 machines with >4 GB mem */
+#define E100_MAX_TCB       64
+#else
+#define E100_MAX_TCB       1024
+#endif /*  __ia64__ */
+
+#define E100_DEFAULT_RFD   MAX_RFD
+#define E100_MIN_RFD       8
+
+#ifdef __ia64__
+ /* We can't use too many DMAble buffers on IA64 machines with >4 GB mem */
+#define E100_MAX_RFD       64
+#else
+#define E100_MAX_RFD       1024
+#endif /*  __ia64__ */
+
+#define E100_DEFAULT_XSUM         true
+#define E100_DEFAULT_BER          ZLOCK_MAX_ERRORS
+#define E100_DEFAULT_SPEED_DUPLEX 0
+#define E100_DEFAULT_FC           0
+#define E100_DEFAULT_IFS          true
+#define E100_DEFAULT_UCODE        true
+
+#define TX_THRSHLD     8
+
+/* sleep time is at least 50 ms, in jiffies */
+#define SLEEP_TIME ((HZ / 20) + 1)
+#define CUS_TIMEOUT 1000
+
+/* IFS parameters */
+#define MIN_NUMBER_OF_TRANSMITS_100 1000
+#define MIN_NUMBER_OF_TRANSMITS_10  100
+
+#define E100_MAX_NIC 16
+
+#define E100_MAX_BUSY_WAIT 50  /*Max udelays in wait_scb and wait_cus_idle */
+
+/* CPUSAVER_BUNDLE_MAX: Sets the maximum number of frames that will be bundled.
+ * In some situations, such as the TCP windowing algorithm, it may be
+ * better to limit the growth of the bundle size than let it go as
+ * high as it can, because that could cause too much added latency.
+ * The default is six, because this is the number of packets in the
+ * default TCP window size.  A value of 1 would make CPUSaver indicate
+ * an interrupt for every frame received.  If you do not want to put
+ * a limit on the bundle size, set this value to xFFFF.
+ */
+#define E100_DEFAULT_CPUSAVER_BUNDLE_MAX       6
+#define E100_DEFAULT_CPUSAVER_INTERRUPT_DELAY  0x600
+#define E100_DEFAULT_BUNDLE_SMALL_FR           false
+#define E100_DEFAULT_RX_CONGESTION_CONTROL     true
+
+/* end of configurables */
+
+/* ====================================================================== */
+/*                                hw                                      */
+/* ====================================================================== */
+
+/* timeout for command completion */
+#define E100_CMD_WAIT   100    /* iterations */
+
+struct driver_stats {
+       struct net_device_stats net_stats;
+
+       unsigned long tx_late_col;
+       unsigned long tx_ok_defrd;
+       unsigned long tx_one_retry;
+       unsigned long tx_mt_one_retry;
+       unsigned long rcv_cdt_frames;
+       unsigned long xmt_fc_pkts;
+       unsigned long rcv_fc_pkts;
+       unsigned long rcv_fc_unsupported;
+       unsigned long xmt_tco_pkts;
+       unsigned long rcv_tco_pkts;
+       unsigned long rx_intr_pkts;
+       unsigned long rx_tasklet_pkts;
+       unsigned long poll_intr_switch;
+};
+
+/* TODO: kill me when we can do C99 */
+#define false          (0)
+#define true           (1)
+
+/* Changed for 82558 and 82559 enhancements */
+/* defines for 82558/9 flow control CSR values */
+#define DFLT_FC_THLD       0x00        /* Rx FIFO threshold of 0.5KB free  */
+#define DFLT_FC_CMD        0x00        /* FC Command in CSR */
+
+/* ====================================================================== */
+/*                              equates                                   */
+/* ====================================================================== */
+
+/*
+ * These are general purpose defines 
+ */
+
+/* Bit Mask definitions */
+#define BIT_0       0x0001
+#define BIT_1       0x0002
+#define BIT_2       0x0004
+#define BIT_3       0x0008
+#define BIT_4       0x0010
+#define BIT_5       0x0020
+#define BIT_6       0x0040
+#define BIT_7       0x0080
+#define BIT_8       0x0100
+#define BIT_9       0x0200
+#define BIT_10      0x0400
+#define BIT_11      0x0800
+#define BIT_12      0x1000
+#define BIT_13      0x2000
+#define BIT_14      0x4000
+#define BIT_15      0x8000
+#define BIT_28      0x10000000
+
+#define BIT_0_2     0x0007
+#define BIT_0_3     0x000F
+#define BIT_0_4     0x001F
+#define BIT_0_5     0x003F
+#define BIT_0_6     0x007F
+#define BIT_0_7     0x00FF
+#define BIT_0_8     0x01FF
+#define BIT_0_13    0x3FFF
+#define BIT_0_15    0xFFFF
+#define BIT_1_2     0x0006
+#define BIT_1_3     0x000E
+#define BIT_2_5     0x003C
+#define BIT_3_4     0x0018
+#define BIT_4_5     0x0030
+#define BIT_4_6     0x0070
+#define BIT_4_7     0x00F0
+#define BIT_5_7     0x00E0
+#define BIT_5_12    0x1FE0
+#define BIT_5_15    0xFFE0
+#define BIT_6_7     0x00c0
+#define BIT_7_11    0x0F80
+#define BIT_8_10    0x0700
+#define BIT_9_13    0x3E00
+#define BIT_12_15   0xF000
+#define BIT_8_15    0xFF00
+
+#define BIT_16_20   0x001F0000
+#define BIT_21_25   0x03E00000
+#define BIT_26_27   0x0C000000
+
+/* Transmit Threshold related constants */
+#define DEFAULT_TX_PER_UNDERRUN         20000
+
+#define MAX_MULTICAST_ADDRS             64
+#define MAX_FILTER                      16
+
+#define FULL_DUPLEX      2
+#define HALF_DUPLEX      1
+
+/*
+ * These defines are specific to the 82557 
+ */
+
+/* E100 PORT functions -- lower 4 bits */
+#define PORT_SOFTWARE_RESET         0
+#define PORT_SELFTEST               1
+#define PORT_SELECTIVE_RESET        2
+#define PORT_DUMP                   3
+
+/* SCB Status Word bit definitions */
+/* Interrupt status/ack fields */
+/* ER and FCP interrupts for 82558 masks  */
+#define SCB_STATUS_ACK_MASK        BIT_8_15    /* Status Mask */
+#define SCB_STATUS_ACK_CX          BIT_15      /* CU Completed Action Cmd */
+#define SCB_STATUS_ACK_FR          BIT_14      /* RU Received A Frame */
+#define SCB_STATUS_ACK_CNA         BIT_13      /* CU Became Inactive (IDLE) */
+#define SCB_STATUS_ACK_RNR         BIT_12      /* RU Became Not Ready */
+#define SCB_STATUS_ACK_MDI         BIT_11      /* MDI read or write done */
+#define SCB_STATUS_ACK_SWI         BIT_10      /* S/W generated interrupt */
+#define SCB_STATUS_ACK_ER          BIT_9       /* Early Receive */
+#define SCB_STATUS_ACK_FCP         BIT_8       /* Flow Control Pause */
+
+/*- CUS Fields */
+#define SCB_CUS_MASK            (BIT_6 | BIT_7)        /* CUS 2-bit Mask */
+#define SCB_CUS_IDLE            0      /* CU Idle */
+#define SCB_CUS_SUSPEND         BIT_6  /* CU Suspended */
+#define SCB_CUS_ACTIVE          BIT_7  /* CU Active */
+
+/*- RUS Fields */
+#define SCB_RUS_IDLE            0      /* RU Idle */
+#define SCB_RUS_MASK            BIT_2_5        /* RUS 3-bit Mask */
+#define SCB_RUS_SUSPEND         BIT_2  /* RU Suspended */
+#define SCB_RUS_NO_RESOURCES    BIT_3  /* RU Out Of Resources */
+#define SCB_RUS_READY           BIT_4  /* RU Ready */
+#define SCB_RUS_SUSP_NO_RBDS    (BIT_2 | BIT_5)        /* RU No More RBDs */
+#define SCB_RUS_NO_RBDS         (BIT_3 | BIT_5)        /* RU No More RBDs */
+#define SCB_RUS_READY_NO_RBDS   (BIT_4 | BIT_5)        /* RU Ready, No RBDs */
+
+/* SCB Command Word bit definitions */
+/*- CUC fields */
+/* Changing mask to 4 bits */
+#define SCB_CUC_MASK            BIT_4_7        /* CUC 4-bit Mask */
+#define SCB_CUC_NOOP            0
+#define SCB_CUC_START           BIT_4  /* CU Start */
+#define SCB_CUC_RESUME          BIT_5  /* CU Resume */
+/* Changed for 82558 enhancements */
+#define SCB_CUC_STATIC_RESUME   (BIT_5 | BIT_7)        /* 82558/9 Static Resume */
+#define SCB_CUC_DUMP_ADDR       BIT_6  /* CU Dump Counters Address */
+#define SCB_CUC_DUMP_STAT       (BIT_4 | BIT_6)        /* CU Dump stat. counters */
+#define SCB_CUC_LOAD_BASE       (BIT_5 | BIT_6)        /* Load the CU base */
+/* Below was defined as BIT_4_7 */
+#define SCB_CUC_DUMP_RST_STAT   BIT_4_6        /* CU Dump & reset statistics cntrs */
+
+/*- RUC fields */
+#define SCB_RUC_MASK            BIT_0_2        /* RUC 3-bit Mask */
+#define SCB_RUC_START           BIT_0  /* RU Start */
+#define SCB_RUC_RESUME          BIT_1  /* RU Resume */
+#define SCB_RUC_ABORT           BIT_2  /* RU Abort */
+#define SCB_RUC_LOAD_HDS        (BIT_0 | BIT_2)        /* Load RFD Header Data Size */
+#define SCB_RUC_LOAD_BASE       (BIT_1 | BIT_2)        /* Load the RU base */
+#define SCB_RUC_RBD_RESUME      BIT_0_2        /* RBD resume */
+
+/* Interrupt fields (assuming byte addressing) */
+#define SCB_INT_MASK            BIT_0  /* Mask interrupts */
+#define SCB_SOFT_INT            BIT_1  /* Generate a S/W interrupt */
+/*  Specific Interrupt Mask Bits (upper byte of SCB Command word) */
+#define SCB_FCP_INT_MASK        BIT_2  /* Flow Control Pause */
+#define SCB_ER_INT_MASK         BIT_3  /* Early Receive */
+#define SCB_RNR_INT_MASK        BIT_4  /* RU Not Ready */
+#define SCB_CNA_INT_MASK        BIT_5  /* CU Not Active */
+#define SCB_FR_INT_MASK         BIT_6  /* Frame Received */
+#define SCB_CX_INT_MASK         BIT_7  /* CU eXecution w/ I-bit done */
+#define SCB_BACHELOR_INT_MASK   BIT_2_7        /* 82558 interrupt mask bits */
+
+#define SCB_GCR2_EEPROM_ACCESS_SEMAPHORE BIT_7
+
+/* EEPROM bit definitions */
+/*- EEPROM control register bits */
+#define EN_TRNF          0x10  /* Enable turnoff */
+#define EEDO             0x08  /* EEPROM data out */
+#define EEDI             0x04  /* EEPROM data in (set for writing data) */
+#define EECS             0x02  /* EEPROM chip select (1=hi, 0=lo) */
+#define EESK             0x01  /* EEPROM shift clock (1=hi, 0=lo) */
+
+/*- EEPROM opcodes */
+#define EEPROM_READ_OPCODE          06
+#define EEPROM_WRITE_OPCODE         05
+#define EEPROM_ERASE_OPCODE         07
+#define EEPROM_EWEN_OPCODE          19 /* Erase/write enable */
+#define EEPROM_EWDS_OPCODE          16 /* Erase/write disable */
+
+/*- EEPROM data locations */
+#define EEPROM_NODE_ADDRESS_BYTE_0      0
+#define EEPROM_COMPATIBILITY_WORD       3
+#define EEPROM_PWA_NO                   8
+#define EEPROM_ID_WORD                 0x0A
+
+#define EEPROM_SUM                      0xbaba
+
+// Zero Locking Algorithm definitions:
+#define ZLOCK_ZERO_MASK                0x00F0
+#define ZLOCK_MAX_READS                50      
+#define ZLOCK_SET_ZERO         0x2010
+#define ZLOCK_MAX_SLEEP                300 * HZ        
+#define ZLOCK_MAX_ERRORS       300
+
+/* E100 Action Commands */
+#define CB_IA_ADDRESS           1
+#define CB_CONFIGURE            2
+#define CB_MULTICAST            3
+#define CB_TRANSMIT             4
+#define CB_LOAD_MICROCODE       5
+#define CB_LOAD_FILTER         8
+#define CB_MAX_NONTX_CMD        9
+#define CB_IPCB_TRANSMIT        9
+
+/* Pre-defined Filter Bits */
+#define CB_FILTER_EL            0x80000000
+#define CB_FILTER_FIX           0x40000000
+#define CB_FILTER_ARP           0x08000000
+#define CB_FILTER_IA_MATCH      0x02000000
+
+/* Command Block (CB) Field Definitions */
+/*- CB Command Word */
+#define CB_EL_BIT           BIT_15     /* CB EL Bit */
+#define CB_S_BIT            BIT_14     /* CB Suspend Bit */
+#define CB_I_BIT            BIT_13     /* CB Interrupt Bit */
+#define CB_TX_SF_BIT        BIT_3      /* TX CB Flexible Mode */
+#define CB_CMD_MASK         BIT_0_3    /* CB 4-bit CMD Mask */
+#define CB_CID_DEFAULT      (0x1f << 8)        /* CB 5-bit CID (max value) */
+
+/*- CB Status Word */
+#define CB_STATUS_MASK          BIT_12_15      /* CB Status Mask (4-bits) */
+#define CB_STATUS_COMPLETE      BIT_15 /* CB Complete Bit */
+#define CB_STATUS_OK            BIT_13 /* CB OK Bit */
+#define CB_STATUS_UNDERRUN      BIT_12 /* CB A Bit */
+#define CB_STATUS_FAIL          BIT_11 /* CB Fail (F) Bit */
+
+/*misc command bits */
+#define CB_TX_EOF_BIT           BIT_15 /* TX CB/TBD EOF Bit */
+
+/* Config params */
+#define CB_CFIG_BYTE_COUNT          22 /* 22 config bytes */
+#define CB_CFIG_D102_BYTE_COUNT    10
+
+/* Receive Frame Descriptor Fields */
+
+/*- RFD Status Bits */
+#define RFD_RECEIVE_COLLISION   BIT_0  /* Collision detected on Receive */
+#define RFD_IA_MATCH            BIT_1  /* Indv Address Match Bit */
+#define RFD_RX_ERR              BIT_4  /* RX_ERR pin on Phy was set */
+#define RFD_FRAME_TOO_SHORT     BIT_7  /* Receive Frame Short */
+#define RFD_DMA_OVERRUN         BIT_8  /* Receive DMA Overrun */
+#define RFD_NO_RESOURCES        BIT_9  /* No Buffer Space */
+#define RFD_ALIGNMENT_ERROR     BIT_10 /* Alignment Error */
+#define RFD_CRC_ERROR           BIT_11 /* CRC Error */
+#define RFD_STATUS_OK           BIT_13 /* RFD OK Bit */
+#define RFD_STATUS_COMPLETE     BIT_15 /* RFD Complete Bit */
+
+/*- RFD Command Bits*/
+#define RFD_EL_BIT      BIT_15 /* RFD EL Bit */
+#define RFD_S_BIT       BIT_14 /* RFD Suspend Bit */
+#define RFD_H_BIT       BIT_4  /* Header RFD Bit */
+#define RFD_SF_BIT      BIT_3  /* RFD Flexible Mode */
+
+/*- RFD misc bits*/
+#define RFD_EOF_BIT         BIT_15     /* RFD End-Of-Frame Bit */
+#define RFD_F_BIT           BIT_14     /* RFD Buffer Fetch Bit */
+#define RFD_ACT_COUNT_MASK  BIT_0_13   /* RFD Actual Count Mask */
+
+/* Receive Buffer Descriptor Fields*/
+#define RBD_EOF_BIT             BIT_15 /* RBD End-Of-Frame Bit */
+#define RBD_F_BIT               BIT_14 /* RBD Buffer Fetch Bit */
+#define RBD_ACT_COUNT_MASK      BIT_0_13       /* RBD Actual Count Mask */
+
+#define SIZE_FIELD_MASK     BIT_0_13   /* Size of the associated buffer */
+#define RBD_EL_BIT          BIT_15     /* RBD EL Bit */
+
+/* Self Test Results*/
+#define CB_SELFTEST_FAIL_BIT        BIT_12
+#define CB_SELFTEST_DIAG_BIT        BIT_5
+#define CB_SELFTEST_REGISTER_BIT    BIT_3
+#define CB_SELFTEST_ROM_BIT         BIT_2
+
+#define CB_SELFTEST_ERROR_MASK ( \
+                CB_SELFTEST_FAIL_BIT | CB_SELFTEST_DIAG_BIT | \
+                CB_SELFTEST_REGISTER_BIT | CB_SELFTEST_ROM_BIT)
+
+/* adapter vendor & device ids */
+#define PCI_OHIO_BOARD   0x10f0        /* subdevice ID, Ohio dual port nic */
+
+/* Values for PCI_REV_ID_REGISTER values */
+#define D101A4_REV_ID      4   /* 82558 A4 stepping */
+#define D101B0_REV_ID      5   /* 82558 B0 stepping */
+#define D101MA_REV_ID      8   /* 82559 A0 stepping */
+#define D101S_REV_ID      9    /* 82559S A-step */
+#define D102_REV_ID      12
+#define D102C_REV_ID     13    /* 82550 step C */
+#define D102E_REV_ID     15
+
+/* ############Start of 82555 specific defines################## */
+
+#define PHY_82555_LED_SWITCH_CONTROL           0x1b    /* 82555 led switch control register */
+
+/* 82555 led switch control reg. opcodes */
+#define PHY_82555_LED_NORMAL_CONTROL    0      // control back to the 8255X
+#define PHY_82555_LED_DRIVER_CONTROL    BIT_2  // the driver is in control
+#define PHY_82555_LED_OFF               BIT_2  // activity LED is off
+#define PHY_82555_LED_ON_559           (BIT_0 | BIT_2) // activity LED is on for 559 and later
+#define PHY_82555_LED_ON_PRE_559       (BIT_0 | BIT_1 | BIT_2) // activity LED is on for 558 and before
+
+// Describe the state of the phy led.
+// needed for the function : 'e100_blink_timer'
+enum led_state_e {
+       LED_OFF = 0,
+       LED_ON,
+};
+
+/* ############End of 82555 specific defines##################### */
+
+#define RFD_PARSE_BIT                  BIT_3
+#define RFD_TCP_PACKET                 0x00
+#define RFD_UDP_PACKET                 0x01
+#define TCPUDP_CHECKSUM_BIT_VALID      BIT_4
+#define TCPUDP_CHECKSUM_VALID          BIT_5
+#define CHECKSUM_PROTOCOL_MASK         0x03
+
+#define VLAN_SIZE   4
+#define CHKSUM_SIZE 2
+#define RFD_DATA_SIZE (ETH_FRAME_LEN + CHKSUM_SIZE + VLAN_SIZE)
+
+/* Bits for bdp->flags */
+#define DF_LINK_FC_CAP     0x00000001  /* Link is flow control capable */
+#define DF_CSUM_OFFLOAD    0x00000002
+#define DF_UCODE_LOADED    0x00000004
+#define USE_IPCB           0x00000008  /* set if using ipcb for transmits */
+#define IS_BACHELOR        0x00000010  /* set if 82558 or newer board */
+#define IS_ICH             0x00000020
+#define DF_SPEED_FORCED    0x00000040  /* set if speed is forced */
+
+typedef struct net_device_stats net_dev_stats_t;
+
+/* needed macros */
+/* These macros use the bdp pointer. If you use them it better be defined */
+#define PREV_TCB_USED(X)  ((X).tail ? (X).tail - 1 : bdp->params.TxDescriptors - 1)
+#define NEXT_TCB_TOUSE(X) ((((X) + 1) >= bdp->params.TxDescriptors) ? 0 : (X) + 1)
+#define TCB_TO_USE(X)     ((X).tail)
+#define TCBS_AVAIL(X)     (NEXT_TCB_TOUSE( NEXT_TCB_TOUSE((X).tail)) != (X).head)
+
+#define RFD_POINTER(skb,bdp)      ((rfd_t *) (((unsigned char *)((skb)->data))-((bdp)->rfd_size)))
+#define SKB_RFD_STATUS(skb,bdp)   ((RFD_POINTER((skb),(bdp)))->rfd_header.cb_status)
+#define GET_SKB_DMA_ADDR(skb)          ( *(dma_addr_t *)( (skb)->cb) )
+#define SET_SKB_DMA_ADDR(skb,dma_addr) ( *(dma_addr_t *)( (skb)->cb) = (dma_addr) )
+
+/* ====================================================================== */
+/*                              82557                                     */
+/* ====================================================================== */
+
+/* Changed for 82558 enhancement */
+typedef struct _d101_scb_ext_t {
+       u32 scb_rx_dma_cnt;     /* Rx DMA byte count */
+       u8 scb_early_rx_int;    /* Early Rx DMA byte count */
+       u8 scb_fc_thld; /* Flow Control threshold */
+       u8 scb_fc_xon_xoff;     /* Flow Control XON/XOFF values */
+       u8 scb_pmdr;    /* Power Mgmt. Driver Reg */
+} d101_scb_ext __attribute__ ((__packed__));
+
+/* Changed for 82559 enhancement */
+typedef struct _d101m_scb_ext_t {
+       u32 scb_rx_dma_cnt;     /* Rx DMA byte count */
+       u8 scb_early_rx_int;    /* Early Rx DMA byte count */
+       u8 scb_fc_thld; /* Flow Control threshold */
+       u8 scb_fc_xon_xoff;     /* Flow Control XON/XOFF values */
+       u8 scb_pmdr;    /* Power Mgmt. Driver Reg */
+       u8 scb_gen_ctrl;        /* General Control */
+       u8 scb_gen_stat;        /* General Status */
+       u16 scb_reserved;       /* Reserved */
+       u32 scb_function_event; /* Cardbus Function Event */
+       u32 scb_function_event_mask;    /* Cardbus Function Mask */
+       u32 scb_function_present_state; /* Cardbus Function state */
+       u32 scb_force_event;    /* Cardbus Force Event */
+} d101m_scb_ext __attribute__ ((__packed__));
+
+/* Changed for 82550 enhancement */
+typedef struct _d102_scb_ext_t {
+       u32 scb_rx_dma_cnt;     /* Rx DMA byte count */
+       u8 scb_early_rx_int;    /* Early Rx DMA byte count */
+       u8 scb_fc_thld; /* Flow Control threshold */
+       u8 scb_fc_xon_xoff;     /* Flow Control XON/XOFF values */
+       u8 scb_pmdr;    /* Power Mgmt. Driver Reg */
+       u8 scb_gen_ctrl;        /* General Control */
+       u8 scb_gen_stat;        /* General Status */
+       u8 scb_gen_ctrl2;
+       u8 scb_reserved;        /* Reserved */
+       u32 scb_scheduling_reg;
+       u32 scb_reserved2;
+       u32 scb_function_event; /* Cardbus Function Event */
+       u32 scb_function_event_mask;    /* Cardbus Function Mask */
+       u32 scb_function_present_state; /* Cardbus Function state */
+       u32 scb_force_event;    /* Cardbus Force Event */
+} d102_scb_ext __attribute__ ((__packed__));
+
+/*
+ * 82557 status control block. this will be memory mapped & will hang of the
+ * the bdp, which hangs of the bdp. This is the brain of it.
+ */
+typedef struct _scb_t {
+       u16 scb_status; /* SCB Status register */
+       u8 scb_cmd_low; /* SCB Command register (low byte) */
+       u8 scb_cmd_hi;  /* SCB Command register (high byte) */
+       u32 scb_gen_ptr;        /* SCB General pointer */
+       u32 scb_port;   /* PORT register */
+       u16 scb_flsh_cntrl;     /* Flash Control register */
+       u16 scb_eprm_cntrl;     /* EEPROM control register */
+       u32 scb_mdi_cntrl;      /* MDI Control Register */
+       /* Changed for 82558 enhancement */
+       union {
+               u32 scb_rx_dma_cnt;     /* Rx DMA byte count */
+               d101_scb_ext d101_scb;  /* 82558/9 specific fields */
+               d101m_scb_ext d101m_scb;        /* 82559 specific fields */
+               d102_scb_ext d102_scb;
+       } scb_ext;
+} scb_t __attribute__ ((__packed__));
+
+/* Self test
+ * This is used to dump results of the self test 
+ */
+typedef struct _self_test_t {
+       u32 st_sign;    /* Self Test Signature */
+       u32 st_result;  /* Self Test Results */
+} self_test_t __attribute__ ((__packed__));
+
+/* 
+ *  Statistical Counters 
+ */
+/* 82557 counters */
+typedef struct _basic_cntr_t {
+       u32 xmt_gd_frames;      /* Good frames transmitted */
+       u32 xmt_max_coll;       /* Fatal frames -- had max collisions */
+       u32 xmt_late_coll;      /* Fatal frames -- had a late coll. */
+       u32 xmt_uruns;  /* Xmit underruns (fatal or re-transmit) */
+       u32 xmt_lost_crs;       /* Frames transmitted without CRS */
+       u32 xmt_deferred;       /* Deferred transmits */
+       u32 xmt_sngl_coll;      /* Transmits that had 1 and only 1 coll. */
+       u32 xmt_mlt_coll;       /* Transmits that had multiple coll. */
+       u32 xmt_ttl_coll;       /* Transmits that had 1+ collisions. */
+       u32 rcv_gd_frames;      /* Good frames received */
+       u32 rcv_crc_errs;       /* Aligned frames that had a CRC error */
+       u32 rcv_algn_errs;      /* Receives that had alignment errors */
+       u32 rcv_rsrc_err;       /* Good frame dropped cuz no resources */
+       u32 rcv_oruns;  /* Overrun errors - bus was busy */
+       u32 rcv_err_coll;       /* Received frms. that encountered coll. */
+       u32 rcv_shrt_frames;    /* Received frames that were to short */
+} basic_cntr_t;
+
+/* 82558 extended statistic counters */
+typedef struct _ext_cntr_t {
+       u32 xmt_fc_frames;
+       u32 rcv_fc_frames;
+       u32 rcv_fc_unsupported;
+} ext_cntr_t;
+
+/* 82559 TCO statistic counters */
+typedef struct _tco_cntr_t {
+       u16 xmt_tco_frames;
+       u16 rcv_tco_frames;
+} tco_cntr_t;
+
+/* Structures to access thet physical dump area */
+/* Use one of these types, according to the statisitcal counters mode,
+   to cast the pointer to the physical dump area and access the cmd_complete
+   DWORD. */
+
+/* 557-mode : only basic counters + cmd_complete */
+typedef struct _err_cntr_557_t {
+       basic_cntr_t basic_stats;
+       u32 cmd_complete;
+} err_cntr_557_t;
+
+/* 558-mode : basic + extended counters + cmd_complete */
+typedef struct _err_cntr_558_t {
+       basic_cntr_t basic_stats;
+       ext_cntr_t extended_stats;
+       u32 cmd_complete;
+} err_cntr_558_t;
+
+/* 559-mode : basic + extended + TCO counters + cmd_complete */
+typedef struct _err_cntr_559_t {
+       basic_cntr_t basic_stats;
+       ext_cntr_t extended_stats;
+       tco_cntr_t tco_stats;
+       u32 cmd_complete;
+} err_cntr_559_t;
+
+/* This typedef defines the struct needed to hold the largest number of counters */
+typedef err_cntr_559_t max_counters_t;
+
+/* Different statistical-counters mode the controller may be in */
+typedef enum _stat_mode_t {
+       E100_BASIC_STATS = 0,   /* 82557 stats : 16 counters / 16 dw */
+       E100_EXTENDED_STATS,    /* 82558 stats : 19 counters / 19 dw */
+       E100_TCO_STATS          /* 82559 stats : 21 counters / 20 dw */
+} stat_mode_t;
+
+/* dump statistical counters complete codes */
+#define DUMP_STAT_COMPLETED    0xA005
+#define DUMP_RST_STAT_COMPLETED        0xA007
+
+/* Command Block (CB) Generic Header Structure*/
+typedef struct _cb_header_t {
+       u16 cb_status;  /* Command Block Status */
+       u16 cb_cmd;     /* Command Block Command */
+       u32 cb_lnk_ptr; /* Link To Next CB */
+} cb_header_t __attribute__ ((__packed__));
+
+//* Individual Address Command Block (IA_CB)*/
+typedef struct _ia_cb_t {
+       cb_header_t ia_cb_hdr;
+       u8 ia_addr[ETH_ALEN];
+} ia_cb_t __attribute__ ((__packed__));
+
+/* Configure Command Block (CONFIG_CB)*/
+typedef struct _config_cb_t {
+       cb_header_t cfg_cbhdr;
+       u8 cfg_byte[CB_CFIG_BYTE_COUNT + CB_CFIG_D102_BYTE_COUNT];
+} config_cb_t __attribute__ ((__packed__));
+
+/* MultiCast Command Block (MULTICAST_CB)*/
+typedef struct _multicast_cb_t {
+       cb_header_t mc_cbhdr;
+       u16 mc_count;   /* Number of multicast addresses */
+       u8 mc_addr[(ETH_ALEN * MAX_MULTICAST_ADDRS)];
+} mltcst_cb_t __attribute__ ((__packed__));
+
+#define UCODE_MAX_DWORDS       134
+/* Load Microcode Command Block (LOAD_UCODE_CB)*/
+typedef struct _load_ucode_cb_t {
+       cb_header_t load_ucode_cbhdr;
+       u32 ucode_dword[UCODE_MAX_DWORDS];
+} load_ucode_cb_t __attribute__ ((__packed__));
+
+/* Load Programmable Filter Data*/
+typedef struct _filter_cb_t {
+       cb_header_t filter_cb_hdr;
+       u32 filter_data[MAX_FILTER];
+} filter_cb_t __attribute__ ((__packed__));
+
+/* NON_TRANSMIT_CB -- Generic Non-Transmit Command Block 
+ */
+typedef struct _nxmit_cb_t {
+       union {
+               config_cb_t config;
+               ia_cb_t setup;
+               load_ucode_cb_t load_ucode;
+               mltcst_cb_t multicast;
+               filter_cb_t filter;
+       } ntcb;
+} nxmit_cb_t __attribute__ ((__packed__));
+
+/*Block for queuing for postponed execution of the non-transmit commands*/
+typedef struct _nxmit_cb_entry_t {
+       struct list_head list_elem;
+       nxmit_cb_t *non_tx_cmd;
+       dma_addr_t dma_addr;
+       unsigned long expiration_time;
+} nxmit_cb_entry_t;
+
+/* States for postponed non tx commands execution */
+typedef enum _non_tx_cmd_state_t {
+       E100_NON_TX_IDLE = 0,   /* No queued NON-TX commands */
+       E100_WAIT_TX_FINISH,    /* Wait for completion of the TX activities */
+       E100_WAIT_NON_TX_FINISH /* Wait for completion of the non TX command */
+} non_tx_cmd_state_t;
+
+/* some defines for the ipcb */
+#define IPCB_IP_CHECKSUM_ENABLE        BIT_4
+#define IPCB_TCPUDP_CHECKSUM_ENABLE    BIT_5
+#define IPCB_TCP_PACKET                BIT_6
+#define IPCB_LARGESEND_ENABLE          BIT_7
+#define IPCB_HARDWAREPARSING_ENABLE    BIT_0
+#define IPCB_INSERTVLAN_ENABLE                 BIT_1
+#define IPCB_IP_ACTIVATION_DEFAULT      IPCB_HARDWAREPARSING_ENABLE
+
+/* Transmit Buffer Descriptor (TBD)*/
+typedef struct _tbd_t {
+       u32 tbd_buf_addr;       /* Physical Transmit Buffer Address */
+       u16 tbd_buf_cnt;        /* Actual Count Of Bytes */
+       u16 padd;
+} tbd_t __attribute__ ((__packed__));
+
+/* d102 specific fields */
+typedef struct _tcb_ipcb_t {
+       u16 schedule_low;
+       u8 ip_schedule;
+       u8 ip_activation_high;
+       u16 vlan;
+       u8 ip_header_offset;
+       u8 tcp_header_offset;
+       union {
+               u32 sec_rec_phys_addr;
+               u32 tbd_zero_address;
+       } tbd_sec_addr;
+       union {
+               u16 sec_rec_size;
+               u16 tbd_zero_size;
+       } tbd_sec_size;
+       u16 total_tcp_payload;
+} tcb_ipcb_t __attribute__ ((__packed__));
+
+#ifdef MAX_SKB_FRAGS
+#define E100_ZEROCOPY
+#endif
+
+#ifdef E100_ZEROCOPY
+#define E100_TBD_ARRAY_SIZE (2+MAX_SKB_FRAGS)
+#else
+#define E100_TBD_ARRAY_SIZE 2
+#endif /*E100_ZEROCOPY */
+
+/* Transmit Command Block (TCB)*/
+struct _tcb_t {
+       cb_header_t tcb_hdr;
+       u32 tcb_tbd_ptr;        /* TBD address */
+       u16 tcb_cnt;    /* Data Bytes In TCB past header */
+       u8 tcb_thrshld; /* TX Threshold for FIFO Extender */
+       u8 tcb_tbd_num;
+
+       union {
+               tcb_ipcb_t ipcb;        /* d102 ipcb fields */
+               tbd_t tbd_array[E100_TBD_ARRAY_SIZE];
+       } tcbu;
+
+       /* From here onward we can dump anything we want as long as the
+        * size of the total structure is a multiple of a paragraph
+        * boundary ( i.e. -16 bit aligned ).
+        */
+       tbd_t *tbd_ptr;
+
+#ifdef E100_ZEROCOPY
+       u32 tcb_tbd_dflt_ptr;   /* TBD address for non-segmented packet */
+       u32 tcb_tbd_expand_ptr; /* TBD address for segmented packet */
+#endif                         /*E100_ZEROCOPY */
+
+       struct sk_buff *tcb_skb;        /* the associated socket buffer */
+       dma_addr_t tcb_phys;    /* phys addr of the TCB */
+} __attribute__ ((__packed__));
+
+#ifndef _TCB_T_
+#define _TCB_T_
+typedef struct _tcb_t tcb_t;
+#endif
+
+/* Receive Frame Descriptor (RFD) - will be using the simple model*/
+struct _rfd_t {
+       /* 8255x */
+       cb_header_t rfd_header;
+       u32 rfd_rbd_ptr;        /* Receive Buffer Descriptor Addr */
+       u16 rfd_act_cnt;        /* Number Of Bytes Received */
+       u16 rfd_sz;     /* Number Of Bytes In RFD */
+       /* D102 aka Gamla */
+       u16 vlanid;
+       u8 rcvparserstatus;
+       u8 reserved;
+       u16 securitystatus;
+       u8 checksumstatus;
+       u8 zerocopystatus;
+       u8 pad[8];      /* data should be 16 byte aligned */
+       u8 data[RFD_DATA_SIZE];
+
+} __attribute__ ((__packed__));
+
+#ifndef _RFD_T_
+#define _RFD_T_
+typedef struct _rfd_t rfd_t;
+#endif
+
+/* Receive Buffer Descriptor (RBD)*/
+typedef struct _rbd_t {
+       u16 rbd_act_cnt;        /* Number Of Bytes Received */
+       u16 rbd_filler;
+       u32 rbd_lnk_addr;       /* Link To Next RBD */
+       u32 rbd_rcb_addr;       /* Receive Buffer Address */
+       u16 rbd_sz;     /* Receive Buffer Size */
+       u16 rbd_filler1;
+} rbd_t __attribute__ ((__packed__));
+
+/*
+ * This structure is used to maintain a FIFO access to a resource that is 
+ * maintained as a circular queue. The resource to be maintained is pointed
+ * to by the "data" field in the structure below. In this driver the TCBs', 
+ * TBDs' & RFDs' are maintained  as a circular queue & are managed thru this
+ * structure.
+ */
+typedef struct _buf_pool_t {
+       unsigned int head;      /* index to first used resource */
+       unsigned int tail;      /* index to last used resource */
+       void *data;             /* points to resource pool */
+} buf_pool_t;
+
+/*Rx skb holding structure*/
+struct rx_list_elem {
+       struct list_head list_elem;
+       dma_addr_t dma_addr;
+       struct sk_buff *skb;
+};
+
+enum next_cu_cmd_e { RESUME_NO_WAIT = 0, RESUME_WAIT, START_WAIT };
+enum zlock_state_e { ZLOCK_INITIAL, ZLOCK_READING, ZLOCK_SLEEPING };
+enum tx_queue_stop_type { LONG_STOP = 0, SHORT_STOP };
+
+/* 64 bit aligned size */
+#define E100_SIZE_64A(X) ((sizeof(X) + 7) & ~0x7)
+
+typedef struct _bd_dma_able_t {
+       char selftest[E100_SIZE_64A(self_test_t)];
+       char stats_counters[E100_SIZE_64A(max_counters_t)];
+} bd_dma_able_t;
+
+/* bit masks for bool parameters */
+#define PRM_XSUMRX       0x00000001
+#define PRM_UCODE        0x00000002
+#define PRM_FC           0x00000004
+#define PRM_IFS          0x00000008
+#define PRM_BUNDLE_SMALL 0x00000010
+#define PRM_RX_CONG      0x00000020
+
+struct cfg_params {
+       int e100_speed_duplex;
+       int RxDescriptors;
+       int TxDescriptors;
+       int IntDelay;
+       int BundleMax;
+       int ber;
+       int PollingMaxWork;
+       u32 b_params;
+};
+
+struct e100_private {
+       u32 flags;              /* board management flags */
+       u32 tx_per_underrun;    /* number of good tx frames per underrun */
+       unsigned int tx_count;  /* count of tx frames, so we can request an interrupt */
+       u8 tx_thld;             /* stores transmit threshold */
+       u16 eeprom_size;
+       u32 pwa_no;             /* PWA: xxxxxx-0xx */
+       u8 perm_node_address[ETH_ALEN];
+       struct list_head active_rx_list;        /* list of rx buffers */
+       struct list_head rx_struct_pool;        /* pool of rx buffer struct headers */
+       u16 rfd_size;                   /* size of the adapter's RFD struct */
+       int skb_req;                    /* number of skbs neede by the adapter */
+       u8 intr_mask;                   /* mask for interrupt status */
+
+       void *dma_able;                 /* dma allocated structs */
+       dma_addr_t dma_able_phys;
+       self_test_t *selftest;          /* pointer to self test area */
+       dma_addr_t selftest_phys;       /* phys addr of selftest */
+       max_counters_t *stats_counters; /* pointer to stats table */
+       dma_addr_t stat_cnt_phys;       /* phys addr of stat counter area */
+
+       stat_mode_t stat_mode;  /* statistics mode: extended, TCO, basic */
+       scb_t *scb;             /* memory mapped ptr to 82557 scb */
+
+       tcb_t *last_tcb;        /* pointer to last tcb sent */
+       buf_pool_t tcb_pool;    /* adapter's TCB array */
+       dma_addr_t tcb_phys;    /* phys addr of start of TCBs */
+
+       u16 cur_line_speed;
+       u16 cur_dplx_mode;
+
+       struct net_device *device;
+       struct pci_dev *pdev;
+       struct driver_stats drv_stats;
+
+       u8 rev_id;              /* adapter PCI revision ID */
+       unsigned long device_type;      /* device type from e100_vendor.h */
+
+       unsigned int phy_addr;  /* address of PHY component */
+       unsigned int PhyId;     /* ID of PHY component */
+       unsigned int PhyState;  /* state for the fix squelch algorithm */
+       unsigned int PhyDelay;  /* delay for the fix squelch algorithm */
+
+       /* Lock defintions for the driver */
+       spinlock_t bd_lock;             /* board lock */
+       spinlock_t bd_non_tx_lock;      /* Non transmit command lock  */
+       spinlock_t config_lock;         /* config block lock */
+       spinlock_t mdi_access_lock;     /* mdi lock */
+
+       struct timer_list watchdog_timer;       /* watchdog timer id */
+
+       /* non-tx commands parameters */
+       struct timer_list nontx_timer_id;       /* non-tx timer id */
+       struct list_head non_tx_cmd_list;
+       non_tx_cmd_state_t non_tx_command_state;
+       nxmit_cb_entry_t *same_cmd_entry[CB_MAX_NONTX_CMD];
+
+       enum next_cu_cmd_e next_cu_cmd;
+
+       /* Zero Locking Algorithm data members */
+       enum zlock_state_e zlock_state;
+       u8 zlock_read_data[16]; /* number of times each value 0-15 was read */
+       u16 zlock_read_cnt;     /* counts number of reads */
+       ulong zlock_sleep_cnt;  /* keeps track of "sleep" time */
+
+       u8 config[CB_CFIG_BYTE_COUNT + CB_CFIG_D102_BYTE_COUNT];
+
+       /* IFS params */
+       u8 ifs_state;
+       u8 ifs_value;
+
+       struct cfg_params params;       /* adapter's command line parameters */
+
+       struct proc_dir_entry *proc_parent;
+
+       rwlock_t isolate_lock;
+       int driver_isolated;
+
+       u32 speed_duplex_caps;  /* adapter's speed/duplex capabilities */
+
+       struct tasklet_struct polling_tasklet;
+
+#ifdef ETHTOOL_GWOL
+       /* WOL params for ethtool */
+       u32 wolsupported;
+       u32 wolopts;
+       u16 ip_lbytes;
+#endif
+};
+
+#define E100_AUTONEG        0
+#define E100_SPEED_10_HALF  1
+#define E100_SPEED_10_FULL  2
+#define E100_SPEED_100_HALF 3
+#define E100_SPEED_100_FULL 4
+
+/********* function prototypes *************/
+extern void e100_isolate_driver(struct e100_private *bdp);
+extern void e100_sw_reset(struct e100_private *bdp, u32 reset_cmd);
+extern void e100_start_cu(struct e100_private *bdp, tcb_t *tcb);
+extern void e100_free_non_tx_cmd(struct e100_private *bdp,
+                                nxmit_cb_entry_t *non_tx_cmd);
+extern nxmit_cb_entry_t *e100_alloc_non_tx_cmd(struct e100_private *bdp);
+extern unsigned char e100_exec_non_cu_cmd(struct e100_private *bdp,
+                                         nxmit_cb_entry_t *cmd);
+extern unsigned char e100_selftest(struct e100_private *bdp, u32 *st_timeout,
+                                  u32 *st_result);
+extern unsigned char e100_get_link_state(struct e100_private *bdp);
+extern unsigned char e100_wait_scb(struct e100_private *bdp);
+
+#endif
diff --git a/drivers/net/e100/e100_config.c b/drivers/net/e100/e100_config.c
new file mode 100644 (file)
index 0000000..fe8f3a9
--- /dev/null
@@ -0,0 +1,596 @@
+/*******************************************************************************
+
+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/100 Family of Adapters (e100) (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.
+*******************************************************************************/
+
+/**********************************************************************
+*                                                                     *
+* INTEL CORPORATION                                                   *
+*                                                                     *
+* This software is supplied under the terms of the license included   *
+* above.  All use of this driver must be in accordance with the terms *
+* of that license.                                                    *
+*                                                                     *
+* Module Name:  e100_config.c                                         *
+*                                                                     *
+* Abstract:     Functions for configuring the network adapter.        *
+*                                                                     *
+* Environment:  This file is intended to be specific to the Linux     *
+*               operating system.                                     *
+*                                                                     *
+**********************************************************************/
+#ifdef SIOCETHTOOL
+#include <linux/ethtool.h>
+#endif
+
+#include "e100_config.h"
+
+static void e100_config_long_rx(struct e100_private *bdp, unsigned char enable);
+
+static const u8 def_config[] = {
+       CB_CFIG_BYTE_COUNT,
+       0x08, 0x00, 0x00, 0x00, 0x00, 0x32, 0x07, 0x01,
+       0x00, 0x2e, 0x00, 0x60, 0x00, 0xf2, 0xc8, 0x00,
+       0x40, 0xf2, 0x80, 0x3f, 0x05
+};
+
+/**
+ * e100_config_init_82557 - config the 82557 adapter
+ * @bdp: atapter's private data struct
+ *
+ * This routine will initialize the 82557 configure block.
+ * All other init functions will only set values that are
+ * different from the 82557 default.
+ */
+static void __devinit
+e100_config_init_82557(struct e100_private *bdp)
+{
+       /* initialize config block */
+       memcpy(bdp->config, def_config, sizeof (def_config));
+       bdp->config[0] = CB_CFIG_BYTE_COUNT;    /* just in case */
+
+       e100_config_ifs(bdp);
+
+       /*
+        * Enable extended statistical counters (82558 and up) and TCO counters
+        * (82559 and up) and set the statistical counters' mode in bdp 
+        *  
+        *  stat. mode      |    TCO stat. bit (2)  |  Extended stat. bit (5)
+        * ------------------------------------------------------------------
+        *  Basic (557)     |       0               |         1
+        * ------------------------------------------------------------------
+        *  Extended (558)  |       0               |         0
+        * ------------------------------------------------------------------
+        *  TCO (559)       |       1               |         1
+        * ------------------------------------------------------------------
+        *  Reserved        |       1               |         0
+        * ------------------------------------------------------------------
+        */
+       bdp->config[6] &= ~CB_CFIG_TCO_STAT;
+       bdp->config[6] |= CB_CFIG_EXT_STAT_DIS;
+       bdp->stat_mode = E100_BASIC_STATS;
+
+       /* Setup for MII or 503 operation.  The CRS+CDT bit should only be set */
+       /* when operating in 503 mode. */
+       if (bdp->phy_addr == 32) {
+               bdp->config[8] &= ~CB_CFIG_503_MII;
+               bdp->config[15] |= CB_CFIG_CRS_OR_CDT;
+       } else {
+               bdp->config[8] |= CB_CFIG_503_MII;
+               bdp->config[15] &= ~CB_CFIG_CRS_OR_CDT;
+       }
+
+       e100_config_fc(bdp);
+       e100_config_force_dplx(bdp);
+       e100_config_promisc(bdp, false);
+       e100_config_mulcast_enbl(bdp, false);
+}
+
+static void __devinit
+e100_config_init_82558(struct e100_private *bdp)
+{
+       /* MWI enable. This should be turned on only if the adapter is a 82558/9
+        * and if the PCI command reg. has enabled the MWI bit. */
+       bdp->config[3] |= CB_CFIG_MWI_EN;
+
+       bdp->config[6] &= ~CB_CFIG_EXT_TCB_DIS;
+
+       if (bdp->rev_id >= D101MA_REV_ID) {
+               /* this is 82559 and up - enable TCO counters */
+               bdp->config[6] |= CB_CFIG_TCO_STAT;
+               bdp->config[6] |= CB_CFIG_EXT_STAT_DIS;
+               bdp->stat_mode = E100_TCO_STATS;
+
+               if ((bdp->rev_id < D102_REV_ID) &&
+                   (bdp->params.b_params & PRM_XSUMRX) &&
+                   (bdp->pdev->device != 0x1209)) {
+
+                       bdp->flags |= DF_CSUM_OFFLOAD;
+                       bdp->config[9] |= 1;
+               }
+       } else {
+               /* this is 82558 */
+               bdp->config[6] &= ~CB_CFIG_TCO_STAT;
+               bdp->config[6] &= ~CB_CFIG_EXT_STAT_DIS;
+               bdp->stat_mode = E100_EXTENDED_STATS;
+       }
+
+       e100_config_long_rx(bdp, true);
+}
+
+static void __devinit
+e100_config_init_82550(struct e100_private *bdp)
+{
+       /* The D102 chip allows for 32 config bytes.  This value is
+        * supposed to be in Byte 0.  Just add the extra bytes to
+        * what was already setup in the block. */
+       bdp->config[0] += CB_CFIG_D102_BYTE_COUNT;
+
+       /* now we need to enable the extended RFD.  When this is
+        * enabled, the immediated receive data buffer starts at offset
+        * 32 from the RFD base address, instead of at offset 16. */
+       bdp->config[7] |= CB_CFIG_EXTENDED_RFD;
+
+       /* put the chip into D102 receive mode.  This is neccessary
+        * for any parsing and offloading features. */
+       bdp->config[22] = CB_CFIG_RECEIVE_GAMLA_MODE;
+
+       /* set the flag if checksum offloading was enabled */
+       if (bdp->params.b_params & PRM_XSUMRX) {
+               bdp->flags |= DF_CSUM_OFFLOAD;
+       }
+}
+
+/* Initialize the adapter's configure block */
+void __devinit
+e100_config_init(struct e100_private *bdp)
+{
+       e100_config_init_82557(bdp);
+
+       if (bdp->flags & IS_BACHELOR)
+               e100_config_init_82558(bdp);
+
+       if (bdp->rev_id >= D102_REV_ID)
+               e100_config_init_82550(bdp);
+}
+
+/**
+ * e100_force_config - force a configure command
+ * @bdp: atapter's private data struct
+ *
+ * This routine will force a configure command to the adapter.
+ * The command will be executed in polled mode as interrupts
+ * are _disabled_ at this time.
+ *
+ * Returns:
+ *      true: if the configure command was successfully issued and completed
+ *      false: otherwise
+ */
+unsigned char
+e100_force_config(struct e100_private *bdp)
+{
+       spin_lock_bh(&(bdp->config_lock));
+
+       bdp->config[0] = CB_CFIG_BYTE_COUNT;
+       if (bdp->rev_id >= D102_REV_ID) {
+               /* The D102 chip allows for 32 config bytes.  This value is
+                  supposed to be in Byte 0.  Just add the extra bytes to
+                  what was already setup in the block. */
+               bdp->config[0] += CB_CFIG_D102_BYTE_COUNT;
+       }
+
+       spin_unlock_bh(&(bdp->config_lock));
+
+       // although we call config outside the lock, there is no
+       // race condition because config byte count has maximum value
+       return e100_config(bdp);
+}
+
+/**
+ * e100_config - issue a configure command
+ * @bdp: atapter's private data struct
+ *
+ * This routine will issue a configure command to the 82557.
+ * This command will be executed in polled mode as interrupts
+ * are _disabled_ at this time.
+ *
+ * Returns:
+ *      true: if the configure command was successfully issued and completed
+ *      false: otherwise
+ */
+unsigned char
+e100_config(struct e100_private *bdp)
+{
+       cb_header_t *pntcb_hdr;
+       unsigned char res = true;
+       nxmit_cb_entry_t *cmd;
+
+       if (bdp->config[0] == 0) {
+               goto exit;
+       }
+
+       if ((cmd = e100_alloc_non_tx_cmd(bdp)) == NULL) {
+               res = false;
+               goto exit;
+       }
+
+       pntcb_hdr = (cb_header_t *) cmd->non_tx_cmd;
+       pntcb_hdr->cb_cmd = __constant_cpu_to_le16(CB_CONFIGURE);
+
+       spin_lock_bh(&bdp->config_lock);
+
+       if (bdp->config[0] < CB_CFIG_MIN_PARAMS) {
+               bdp->config[0] = CB_CFIG_MIN_PARAMS;
+       }
+
+       /* Copy the device's config block to the device's memory */
+       memcpy(cmd->non_tx_cmd->ntcb.config.cfg_byte, bdp->config,
+              bdp->config[0]);
+       /* reset number of bytes to config next time */
+       bdp->config[0] = 0;
+
+       spin_unlock_bh(&bdp->config_lock);
+
+       res = e100_exec_non_cu_cmd(bdp, cmd);
+
+exit:
+       if (netif_running(bdp->device))
+               netif_wake_queue(bdp->device);
+       return res;
+}
+
+/**
+ * e100_config_fc - config flow-control state
+ * @bdp: atapter's private data struct
+ *
+ * This routine will enable or disable flow control support in the adapter's
+ * config block. Flow control will be enable only if requested using the command
+ * line option, and if the link is flow-contorl capable (both us and the link
+ * partner).
+ *
+ * Returns:
+ *      true: if then option was indeed changed
+ *      false: if no change was needed
+ */
+unsigned char
+e100_config_fc(struct e100_private *bdp)
+{
+       unsigned char enable = false;
+       unsigned char changed = false;
+
+       /* 82557 doesn't support fc. Don't touch this option */
+       if (!(bdp->flags & IS_BACHELOR))
+               return false;
+
+       /* Enable fc if requested and if the link supports it */
+       if ((bdp->params.b_params & PRM_FC) && (bdp->flags & DF_LINK_FC_CAP)) {
+               enable = true;
+       }
+
+       spin_lock_bh(&(bdp->config_lock));
+
+       if (enable) {
+
+               if (bdp->config[16] != DFLT_FC_DELAY_LSB) {
+                       bdp->config[16] = DFLT_FC_DELAY_LSB;
+                       E100_CONFIG(bdp, 16);
+                       changed = true;
+               }
+
+               if (bdp->config[17] != DFLT_FC_DELAY_LSB) {
+                       bdp->config[17] = DFLT_FC_DELAY_MSB;
+                       E100_CONFIG(bdp, 17);
+                       changed = true;
+               }
+
+               /* check if *all* fc config options were already set */
+               if (((bdp->config[19] & CB_CFIG_FC_OPTS) != CB_CFIG_FC_OPTS) ||
+                   (bdp->config[19] & CB_CFIG_TX_FC_DIS)) {
+
+                       bdp->config[19] |= CB_CFIG_FC_OPTS;
+                       bdp->config[19] &= ~CB_CFIG_TX_FC_DIS;
+                       E100_CONFIG(bdp, 19);
+                       changed = true;
+               }
+
+       } else {
+               if (bdp->config[16] != DFLT_NO_FC_DELAY_LSB) {
+                       bdp->config[16] = DFLT_NO_FC_DELAY_LSB;
+                       E100_CONFIG(bdp, 16);
+                       changed = true;
+               }
+
+               if (bdp->config[17] != DFLT_NO_FC_DELAY_MSB) {
+                       bdp->config[17] = DFLT_NO_FC_DELAY_MSB;
+                       E100_CONFIG(bdp, 17);
+                       changed = true;
+               }
+
+               /* check if *any* fc config options was already set */
+               if ((bdp->config[19] & CB_CFIG_FC_OPTS) ||
+                   !(bdp->config[19] & CB_CFIG_TX_FC_DIS)) {
+
+                       bdp->config[19] &= ~CB_CFIG_FC_OPTS;
+                       bdp->config[19] |= CB_CFIG_TX_FC_DIS;
+                       E100_CONFIG(bdp, 19);
+                       changed = true;
+               }
+       }
+
+       spin_unlock_bh(&(bdp->config_lock));
+
+       return changed;
+}
+
+/**
+ * e100_config_promisc - configure promiscuous mode
+ * @bdp: atapter's private data struct
+ * @enable: should we enable this option or not
+ *
+ * This routine will enable or disable promiscuous mode
+ * in the adapter's config block.
+ */
+void
+e100_config_promisc(struct e100_private *bdp, unsigned char enable)
+{
+       spin_lock_bh(&(bdp->config_lock));
+
+       /* if in promiscuous mode, save bad frames */
+       if (enable) {
+
+               if (!(bdp->config[6] & CB_CFIG_SAVE_BAD_FRAMES)) {
+                       bdp->config[6] |= CB_CFIG_SAVE_BAD_FRAMES;
+                       E100_CONFIG(bdp, 6);
+               }
+
+               if (bdp->config[7] & (u8) BIT_0) {
+                       bdp->config[7] &= (u8) (~BIT_0);
+                       E100_CONFIG(bdp, 7);
+               }
+
+               if (!(bdp->config[15] & CB_CFIG_PROMISCUOUS)) {
+                       bdp->config[15] |= CB_CFIG_PROMISCUOUS;
+                       E100_CONFIG(bdp, 15);
+               }
+
+       } else {                /* not in promiscuous mode */
+
+               if (bdp->config[6] & CB_CFIG_SAVE_BAD_FRAMES) {
+                       bdp->config[6] &= ~CB_CFIG_SAVE_BAD_FRAMES;
+                       E100_CONFIG(bdp, 6);
+               }
+
+               if (!(bdp->config[7] & (u8) BIT_0)) {
+                       bdp->config[7] |= (u8) (BIT_0);
+                       E100_CONFIG(bdp, 7);
+               }
+
+               if (bdp->config[15] & CB_CFIG_PROMISCUOUS) {
+                       bdp->config[15] &= ~CB_CFIG_PROMISCUOUS;
+                       E100_CONFIG(bdp, 15);
+               }
+       }
+
+       spin_unlock_bh(&(bdp->config_lock));
+}
+
+/**
+ * e100_config_mulcast_enbl - configure allmulti mode
+ * @bdp: atapter's private data struct
+ * @enable: should we enable this option or not
+ *
+ * This routine will enable or disable reception of all multicast packets
+ * in the adapter's config block.
+ */
+void
+e100_config_mulcast_enbl(struct e100_private *bdp, unsigned char enable)
+{
+       spin_lock_bh(&(bdp->config_lock));
+
+       /* this flag is used to enable receiving all multicast packet */
+       if (enable) {
+               if (!(bdp->config[21] & CB_CFIG_MULTICAST_ALL)) {
+                       bdp->config[21] |= CB_CFIG_MULTICAST_ALL;
+                       E100_CONFIG(bdp, 21);
+               }
+
+       } else {
+               if (bdp->config[21] & CB_CFIG_MULTICAST_ALL) {
+                       bdp->config[21] &= ~CB_CFIG_MULTICAST_ALL;
+                       E100_CONFIG(bdp, 21);
+               }
+       }
+
+       spin_unlock_bh(&(bdp->config_lock));
+}
+
+/**
+ * e100_config_ifs - configure the IFS parameter
+ * @bdp: atapter's private data struct
+ *
+ * This routine will configure the adaptive IFS value
+ * in the adapter's config block. IFS values are only
+ * relevant in half duplex, so set to 0 in full duplex.
+ */
+void
+e100_config_ifs(struct e100_private *bdp)
+{
+       u8 value = 0;
+
+       spin_lock_bh(&(bdp->config_lock));
+
+       /* IFS value is only needed to be specified at half-duplex mode */
+       if (bdp->cur_dplx_mode == HALF_DUPLEX) {
+               value = (u8) bdp->ifs_value;
+       }
+
+       if (bdp->config[2] != value) {
+               bdp->config[2] = value;
+               E100_CONFIG(bdp, 2);
+       }
+
+       spin_unlock_bh(&(bdp->config_lock));
+}
+
+/**
+ * e100_config_force_dplx - configure the forced full duplex mode
+ * @bdp: atapter's private data struct
+ *
+ * This routine will enable or disable force full duplex
+ * in the adapter's config block. If the PHY is 503, and
+ * the duplex is full, consider the adapter forced.
+ */
+void
+e100_config_force_dplx(struct e100_private *bdp)
+{
+       spin_lock_bh(&(bdp->config_lock));
+
+       /* We must force full duplex on if we are using PHY 0, and we are */
+       /* supposed to run in FDX mode. We do this because the e100 has only */
+       /* one FDX# input pin, and that pin will be connected to PHY 1. */
+       /* Changed the 'if' condition below to fix performance problem * at 10
+        * full. The Phy was getting forced to full duplex while the MAC * was
+        * not, because the cur_dplx_mode was not being set to 2 by SetupPhy. *
+        * This is how the condition was, initially. * This has been changed so
+        * that the MAC gets forced to full duplex * simply if the user has
+        * forced full duplex. * * if (( bdp->phy_addr == 0 ) && (
+        * bdp->cur_dplx_mode == 2 )) */
+       /* The rest of the fix is in the PhyDetect code. */
+       if ((bdp->params.e100_speed_duplex == E100_SPEED_10_FULL) ||
+           (bdp->params.e100_speed_duplex == E100_SPEED_100_FULL) ||
+           ((bdp->phy_addr == 32) && (bdp->cur_dplx_mode == FULL_DUPLEX))) {
+               if (!(bdp->config[19] & (u8) CB_CFIG_FORCE_FDX)) {
+                       bdp->config[19] |= (u8) CB_CFIG_FORCE_FDX;
+                       E100_CONFIG(bdp, 19);
+               }
+
+       } else {
+               if (bdp->config[19] & (u8) CB_CFIG_FORCE_FDX) {
+                       bdp->config[19] &= (u8) (~CB_CFIG_FORCE_FDX);
+                       E100_CONFIG(bdp, 19);
+               }
+       }
+
+       spin_unlock_bh(&(bdp->config_lock));
+}
+
+/**
+ * e100_config_long_rx
+ * @bdp: atapter's private data struct
+ * @enable: should we enable this option or not
+ *
+ * This routine will enable or disable reception of larger packets.
+ * This is needed by VLAN implementations.
+ */
+static void
+e100_config_long_rx(struct e100_private *bdp, unsigned char enable)
+{
+       if (enable) {
+               if (!(bdp->config[18] & CB_CFIG_LONG_RX_OK)) {
+                       bdp->config[18] |= CB_CFIG_LONG_RX_OK;
+                       E100_CONFIG(bdp, 18);
+               }
+
+       } else {
+               if ((bdp->config[18] & CB_CFIG_LONG_RX_OK)) {
+                       bdp->config[18] &= ~CB_CFIG_LONG_RX_OK;
+                       E100_CONFIG(bdp, 18);
+               }
+       }
+}
+
+#ifdef ETHTOOL_GWOL
+/**
+ * e100_config_wol
+ * @bdp: atapter's private data struct
+ *
+ * This sets configuration options for Wake On LAN functionality (WOL) in the
+ * config record. WOL options are retrieved from wolinfo_wolopts in @bdp
+ */
+void
+e100_config_wol(struct e100_private *bdp)
+{
+       spin_lock_bh(&(bdp->config_lock));
+
+       if (bdp->wolopts & WAKE_PHY) {
+               bdp->config[9] |= CB_LINK_STATUS_WOL;
+               E100_CONFIG(bdp, 9);
+       }
+
+       if (!(bdp->wolopts & WAKE_MAGIC)) {
+               bdp->config[19] |= CB_DISABLE_MAGPAK_WAKE;
+               E100_CONFIG(bdp, 19);
+       }
+
+       spin_unlock_bh(&(bdp->config_lock));
+}
+#endif
+
diff --git a/drivers/net/e100/e100_config.h b/drivers/net/e100/e100_config.h
new file mode 100644 (file)
index 0000000..71618e3
--- /dev/null
@@ -0,0 +1,206 @@
+/*******************************************************************************
+
+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/100 Family of Adapters (e100) (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.
+*******************************************************************************/
+
+#ifndef _E100_CONFIG_INC_
+#define _E100_CONFIG_INC_
+
+#include "e100.h"
+
+#define E100_CONFIG(bdp, X) ((bdp)->config[0] = max_t(u8, (bdp)->config[0], (X)+1))
+
+#define CB_CFIG_MIN_PARAMS         8
+
+/* byte 0 bit definitions*/
+#define CB_CFIG_BYTE_COUNT_MASK     BIT_0_5    /* Byte count occupies bit 5-0 */
+
+/* byte 1 bit definitions*/
+#define CB_CFIG_RXFIFO_LIMIT_MASK   BIT_0_4    /* RxFifo limit mask */
+#define CB_CFIG_TXFIFO_LIMIT_MASK   BIT_4_7    /* TxFifo limit mask */
+
+/* byte 2 bit definitions -- ADAPTIVE_IFS*/
+
+/* word 3 bit definitions -- RESERVED*/
+/* Changed for 82558 enhancements */
+/* byte 3 bit definitions */
+#define CB_CFIG_MWI_EN      BIT_0      /* Enable MWI on PCI bus */
+#define CB_CFIG_TYPE_EN     BIT_1      /* Type Enable */
+#define CB_CFIG_READAL_EN   BIT_2      /* Enable Read Align */
+#define CB_CFIG_TERMCL_EN   BIT_3      /* Cache line write  */
+
+/* byte 4 bit definitions*/
+#define CB_CFIG_RX_MIN_DMA_MASK     BIT_0_6    /* Rx minimum DMA count mask */
+
+/* byte 5 bit definitions*/
+#define CB_CFIG_TX_MIN_DMA_MASK BIT_0_6        /* Tx minimum DMA count mask */
+#define CB_CFIG_DMBC_EN         BIT_7  /* Enable Tx/Rx min. DMA counts */
+
+/* Changed for 82558 enhancements */
+/* byte 6 bit definitions*/
+#define CB_CFIG_LATE_SCB           BIT_0       /* Update SCB After New Tx Start */
+#define CB_CFIG_DIRECT_DMA_DIS     BIT_1       /* Direct DMA mode */
+#define CB_CFIG_TNO_INT            BIT_2       /* Tx Not OK Interrupt */
+#define CB_CFIG_TCO_STAT           BIT_2       /* TCO statistics in 559 and above */
+#define CB_CFIG_CI_INT             BIT_3       /* Command Complete Interrupt */
+#define CB_CFIG_EXT_TCB_DIS        BIT_4       /* Extended TCB */
+#define CB_CFIG_EXT_STAT_DIS       BIT_5       /* Extended Stats */
+#define CB_CFIG_SAVE_BAD_FRAMES    BIT_7       /* Save Bad Frames Enabled */
+
+/* byte 7 bit definitions*/
+#define CB_CFIG_DISC_SHORT_FRAMES   BIT_0      /* Discard Short Frames */
+#define CB_CFIG_DYNTBD_EN           BIT_7      /* Enable dynamic TBD */
+/* Enable extended RFD's on D102 */
+#define CB_CFIG_EXTENDED_RFD        BIT_5
+
+/* byte 8 bit definitions*/
+#define CB_CFIG_503_MII             BIT_0      /* 503 vs. MII mode */
+
+/* byte 9 bit definitions -- pre-defined all zeros*/
+#define CB_LINK_STATUS_WOL     BIT_5
+
+/* byte 10 bit definitions*/
+#define CB_CFIG_NO_SRCADR       BIT_3  /* No Source Address Insertion */
+#define CB_CFIG_PREAMBLE_LEN    BIT_4_5        /* Preamble Length */
+#define CB_CFIG_LOOPBACK_MODE   BIT_6_7        /* Loopback Mode */
+#define CB_CFIG_LOOPBACK_NORMAL 0
+#define CB_CFIG_LOOPBACK_INTERNAL BIT_6
+#define CB_CFIG_LOOPBACK_EXTERNAL BIT_6_7
+
+/* byte 11 bit definitions*/
+#define CB_CFIG_LINEAR_PRIORITY     BIT_0_2    /* Linear Priority */
+
+/* byte 12 bit definitions*/
+#define CB_CFIG_LINEAR_PRI_MODE     BIT_0      /* Linear Priority mode */
+#define CB_CFIG_IFS_MASK            BIT_4_7    /* Interframe Spacing mask */
+
+/* byte 13 bit definitions -- pre-defined all zeros*/
+
+/* byte 14 bit definitions -- pre-defined 0xf2*/
+
+/* byte 15 bit definitions*/
+#define CB_CFIG_PROMISCUOUS         BIT_0      /* Promiscuous Mode Enable */
+#define CB_CFIG_BROADCAST_DIS       BIT_1      /* Broadcast Mode Disable */
+#define CB_CFIG_CRS_OR_CDT          BIT_7      /* CRS Or CDT */
+
+/* byte 16 bit definitions -- pre-defined all zeros*/
+#define DFLT_FC_DELAY_LSB  0x1f        /* Delay for outgoing Pause frames */
+#define DFLT_NO_FC_DELAY_LSB  0x00     /* no flow control default value */
+
+/* byte 17 bit definitions -- pre-defined 0x40*/
+#define DFLT_FC_DELAY_MSB  0x01        /* Delay for outgoing Pause frames */
+#define DFLT_NO_FC_DELAY_MSB  0x40     /* no flow control default value */
+
+/* byte 18 bit definitions*/
+#define CB_CFIG_STRIPPING           BIT_0      /* Padding Disabled */
+#define CB_CFIG_PADDING             BIT_1      /* Padding Disabled */
+#define CB_CFIG_CRC_IN_MEM          BIT_2      /* Transfer CRC To Memory */
+
+/* byte 19 bit definitions*/
+#define CB_CFIG_TX_ADDR_WAKE        BIT_0      /* Address Wakeup */
+#define CB_DISABLE_MAGPAK_WAKE      BIT_1      /* Magic Packet Wakeup disable */
+/* Changed TX_FC_EN to TX_FC_DIS because 0 enables, 1 disables. Jul 8, 1999 */
+#define CB_CFIG_TX_FC_DIS           BIT_2      /* Tx Flow Control Disable */
+#define CB_CFIG_FC_RESTOP           BIT_3      /* Rx Flow Control Restop */
+#define CB_CFIG_FC_RESTART          BIT_4      /* Rx Flow Control Restart */
+#define CB_CFIG_FC_REJECT           BIT_5      /* Rx Flow Control Restart */
+#define CB_CFIG_FC_OPTS (CB_CFIG_FC_RESTOP | CB_CFIG_FC_RESTART | CB_CFIG_FC_REJECT)
+
+/* end 82558/9 specifics */
+
+#define CB_CFIG_FORCE_FDX           BIT_6      /* Force Full Duplex */
+#define CB_CFIG_FDX_ENABLE          BIT_7      /* Full Duplex Enabled */
+
+/* byte 20 bit definitions*/
+#define CB_CFIG_MULTI_IA            BIT_6      /* Multiple IA Addr */
+
+/* byte 21 bit definitions*/
+#define CB_CFIG_MULTICAST_ALL       BIT_3      /* Multicast All */
+
+/* byte 22 bit defines */
+#define CB_CFIG_RECEIVE_GAMLA_MODE  BIT_0      /* D102 receive mode */
+#define CB_CFIG_VLAN_DROP_ENABLE    BIT_1      /* vlan stripping */
+
+#define CB_CFIG_LONG_RX_OK         BIT_3
+
+/* function prototypes */
+extern void e100_config_init(struct e100_private *bdp);
+extern unsigned char e100_force_config(struct e100_private *bdp);
+extern unsigned char e100_config(struct e100_private *bdp);
+extern unsigned char e100_config_fc(struct e100_private *bdp);
+extern void e100_config_promisc(struct e100_private *bdp, unsigned char enable);
+extern void e100_config_brdcast_dsbl(struct e100_private *bdp);
+extern void e100_config_mulcast_enbl(struct e100_private *bdp,
+                                    unsigned char enable);
+extern void e100_config_ifs(struct e100_private *bdp);
+extern void e100_config_force_dplx(struct e100_private *bdp);
+
+#endif /* _E100_CONFIG_INC_ */
diff --git a/drivers/net/e100/e100_eeprom.c b/drivers/net/e100/e100_eeprom.c
new file mode 100644 (file)
index 0000000..df9daeb
--- /dev/null
@@ -0,0 +1,614 @@
+/*******************************************************************************
+
+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/100 Family of Adapters (e100) (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.
+*******************************************************************************/
+
+/**********************************************************************
+*                                                                     *
+* INTEL CORPORATION                                                   *
+*                                                                     *
+* This software is supplied under the terms of the license included   *
+* above.  All use of this driver must be in accordance with the terms *
+* of that license.                                                    *
+*                                                                     *
+* Module Name:  e100_eeprom.c                                         *
+*                                                                     *
+* Abstract:     This module contains routines to read and write to a  *
+*               serial EEPROM                                         *
+*                                                                     *
+* Environment:  This file is intended to be specific to the Linux     *
+*               operating system.                                     *
+*                                                                     *
+**********************************************************************/
+#include "e100.h"
+
+#define CSR_EEPROM_CONTROL_FIELD(bdp) ((bdp)->scb->scb_eprm_cntrl)
+
+#define CSR_GENERAL_CONTROL2_FIELD(bdp) \
+                  ((bdp)->scb->scb_ext.d102_scb.scb_gen_ctrl2)
+
+#define EEPROM_STALL_TIME      4
+#define EEPROM_CHECKSUM                ((u16) 0xBABA)
+#define EEPROM_MAX_WORD_SIZE   256
+
+void e100_eeprom_cleanup(struct e100_private *adapter);
+u16 e100_eeprom_calculate_chksum(struct e100_private *adapter);
+static void e100_eeprom_write_word(struct e100_private *adapter, u16 reg,
+                                  u16 data);
+void e100_eeprom_write_block(struct e100_private *adapter, u16 start, u16 *data,
+                            u16 size);
+u16 e100_eeprom_size(struct e100_private *adapter);
+u16 e100_eeprom_read(struct e100_private *adapter, u16 reg);
+
+static void shift_out_bits(struct e100_private *adapter, u16 data, u16 count);
+static u16 shift_in_bits(struct e100_private *adapter);
+static void raise_clock(struct e100_private *adapter, u16 *x);
+static void lower_clock(struct e100_private *adapter, u16 *x);
+static u16 eeprom_wait_cmd_done(struct e100_private *adapter);
+static void eeprom_stand_by(struct e100_private *adapter);
+
+//----------------------------------------------------------------------------------------
+// Procedure:   eeprom_set_semaphore
+//
+// Description: This function set (write 1) Gamla EEPROM semaphore bit (bit 23 word 0x1C in the CSR).
+//
+// Arguments:
+//      Adapter                 - Adapter context
+//
+// Returns:  true if success
+//           else return false 
+//
+//----------------------------------------------------------------------------------------
+
+inline u8
+eeprom_set_semaphore(struct e100_private *adapter)
+{
+       u16 data = 0;
+       unsigned long expiration_time = jiffies + HZ / 100 + 1;
+
+       while (time_before(jiffies, expiration_time)) {
+               // Get current value of General Control 2
+               data = readb(&CSR_GENERAL_CONTROL2_FIELD(adapter));
+
+               // Set bit 23 word 0x1C in the CSR.
+               data |= SCB_GCR2_EEPROM_ACCESS_SEMAPHORE;
+               writeb(data, &CSR_GENERAL_CONTROL2_FIELD(adapter));
+
+               barrier();
+
+               // Check to see if this bit set or not.
+               data = readb(&CSR_GENERAL_CONTROL2_FIELD(adapter));
+
+               if (data & SCB_GCR2_EEPROM_ACCESS_SEMAPHORE) {
+                       return true;
+               }
+
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               schedule_timeout(1);
+       }
+       return false;
+}
+
+//----------------------------------------------------------------------------------------
+// Procedure:   eeprom_reset_semaphore
+//
+// Description: This function reset (write 0) Gamla EEPROM semaphore bit 
+//              (bit 23 word 0x1C in the CSR).
+//
+// Arguments:  struct e100_private * adapter - Adapter context
+//----------------------------------------------------------------------------------------
+
+inline void
+eeprom_reset_semaphore(struct e100_private *adapter)
+{
+       u16 data = 0;
+
+       data = readb(&CSR_GENERAL_CONTROL2_FIELD(adapter));
+       data &= ~(SCB_GCR2_EEPROM_ACCESS_SEMAPHORE);
+       writeb(data, &CSR_GENERAL_CONTROL2_FIELD(adapter));
+}
+
+//----------------------------------------------------------------------------------------
+// Procedure:   e100_eeprom_size
+//
+// Description: This routine determines the size of the EEPROM.  This value should be
+//              checked for validity - ie. is it too big or too small.  The size returned
+//              is then passed to the read/write functions.
+//
+// Returns:
+//      Size of the eeprom, or zero if an error occured
+//----------------------------------------------------------------------------------------
+u16
+e100_eeprom_size(struct e100_private *adapter)
+{
+       u16 x, size = 1;        // must be one to accumulate a product
+
+       // if we've already stored this data, read from memory
+       if (adapter->eeprom_size) {
+               return adapter->eeprom_size;
+       }
+       // otherwise, read from the eeprom
+       // Set EEPROM semaphore.
+       if (adapter->rev_id >= D102_REV_ID) {
+               if (!eeprom_set_semaphore(adapter))
+                       return 0;
+       }
+       // enable the eeprom by setting EECS.
+       x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter));
+       x &= ~(EEDI | EEDO | EESK);
+       x |= EECS;
+       writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter));
+
+       // write the read opcode
+       shift_out_bits(adapter, EEPROM_READ_OPCODE, 3);
+
+       // experiment to discover the size of the eeprom.  request register zero
+       // and wait for the eeprom to tell us it has accepted the entire address.
+       x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter));
+       do {
+               size *= 2;      // each bit of address doubles eeprom size
+               x |= EEDO;      // set bit to detect "dummy zero"
+               x &= ~EEDI;     // address consists of all zeros
+
+               writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter));
+               udelay(EEPROM_STALL_TIME);
+               raise_clock(adapter, &x);
+               lower_clock(adapter, &x);
+
+               // check for "dummy zero"
+               x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter));
+               if (size > EEPROM_MAX_WORD_SIZE) {
+                       size = 0;
+                       break;
+               }
+       } while (x & EEDO);
+
+       // read in the value requested
+       (void) shift_in_bits(adapter);
+       e100_eeprom_cleanup(adapter);
+
+       // Clear EEPROM Semaphore.
+       if (adapter->rev_id >= D102_REV_ID) {
+               eeprom_reset_semaphore(adapter);
+       }
+
+       return size;
+}
+
+//----------------------------------------------------------------------------------------
+// Procedure:   eeprom_address_size
+//
+// Description: determines the number of bits in an address for the eeprom acceptable
+//              values are 64, 128, and 256
+// Arguments: size of the eeprom
+// Returns: bits in an address for that size eeprom
+//----------------------------------------------------------------------------------------
+
+static u16
+eeprom_address_size(u16 size)
+{
+       switch (size) {
+       case 64:
+               return 6;
+       case 128:
+               return 7;
+       case 256:
+               return 8;
+       }
+
+       return 0;               //fix compiler warning or error!
+}
+
+//----------------------------------------------------------------------------------------
+// Procedure:   e100_eeprom_read
+//
+// Description: This routine serially reads one word out of the EEPROM.
+//
+// Arguments:
+//      adapter - our adapter context
+//      reg - EEPROM word to read.
+//
+// Returns:
+//      Contents of EEPROM word (reg).
+//----------------------------------------------------------------------------------------
+
+u16
+e100_eeprom_read(struct e100_private *adapter, u16 reg)
+{
+       u16 x, data, bits;
+
+       // Set EEPROM semaphore.
+       if (adapter->rev_id >= D102_REV_ID) {
+               if (!eeprom_set_semaphore(adapter))
+                       return 0;
+       }
+       // eeprom size is initialized to zero
+       if (!adapter->eeprom_size)
+               adapter->eeprom_size = e100_eeprom_size(adapter);
+
+       bits = eeprom_address_size(adapter->eeprom_size);
+
+       // select EEPROM, reset bits, set EECS
+       x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter));
+
+       x &= ~(EEDI | EEDO | EESK);
+       x |= EECS;
+       writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter));
+
+       // write the read opcode and register number in that order
+       // The opcode is 3bits in length, reg is 'bits' bits long
+       shift_out_bits(adapter, EEPROM_READ_OPCODE, 3);
+       shift_out_bits(adapter, reg, bits);
+
+       // Now read the data (16 bits) in from the selected EEPROM word
+       data = shift_in_bits(adapter);
+
+       e100_eeprom_cleanup(adapter);
+
+       // Clear EEPROM Semaphore.
+       if (adapter->rev_id >= D102_REV_ID) {
+               eeprom_reset_semaphore(adapter);
+       }
+
+       return data;
+}
+
+//----------------------------------------------------------------------------------------
+// Procedure:   shift_out_bits
+//
+// Description: This routine shifts data bits out to the EEPROM.
+//
+// Arguments:
+//      data - data to send to the EEPROM.
+//      count - number of data bits to shift out.
+//
+// Returns: (none)
+//----------------------------------------------------------------------------------------
+
+static void
+shift_out_bits(struct e100_private *adapter, u16 data, u16 count)
+{
+       u16 x, mask;
+
+       mask = 1 << (count - 1);
+       x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter));
+       x &= ~(EEDO | EEDI);
+
+       do {
+               x &= ~EEDI;
+               if (data & mask)
+                       x |= EEDI;
+
+               writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter));
+               udelay(EEPROM_STALL_TIME);
+               raise_clock(adapter, &x);
+               lower_clock(adapter, &x);
+               mask = mask >> 1;
+       } while (mask);
+
+       x &= ~EEDI;
+       writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter));
+}
+
+//----------------------------------------------------------------------------------------
+// Procedure:   raise_clock
+//
+// Description: This routine raises the EEPROM's clock input (EESK)
+//
+// Arguments:
+//      x - Ptr to the EEPROM control register's current value
+//
+// Returns: (none)
+//----------------------------------------------------------------------------------------
+
+void
+raise_clock(struct e100_private *adapter, u16 *x)
+{
+       *x = *x | EESK;
+       writew(*x, &CSR_EEPROM_CONTROL_FIELD(adapter));
+       udelay(EEPROM_STALL_TIME);
+}
+
+//----------------------------------------------------------------------------------------
+// Procedure:   lower_clock
+//
+// Description: This routine lower's the EEPROM's clock input (EESK)
+//
+// Arguments:
+//      x - Ptr to the EEPROM control register's current value
+//
+// Returns: (none)
+//----------------------------------------------------------------------------------------
+
+void
+lower_clock(struct e100_private *adapter, u16 *x)
+{
+       *x = *x & ~EESK;
+       writew(*x, &CSR_EEPROM_CONTROL_FIELD(adapter));
+       udelay(EEPROM_STALL_TIME);
+}
+
+//----------------------------------------------------------------------------------------
+// Procedure:   shift_in_bits
+//
+// Description: This routine shifts data bits in from the EEPROM.
+//
+// Arguments:
+//
+// Returns:
+//      The contents of that particular EEPROM word
+//----------------------------------------------------------------------------------------
+
+static u16
+shift_in_bits(struct e100_private *adapter)
+{
+       u16 x, d, i;
+
+       x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter));
+       x &= ~(EEDO | EEDI);
+       d = 0;
+
+       for (i = 0; i < 16; i++) {
+               d <<= 1;
+               raise_clock(adapter, &x);
+
+               x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter));
+
+               x &= ~EEDI;
+               if (x & EEDO)
+                       d |= 1;
+
+               lower_clock(adapter, &x);
+       }
+
+       return d;
+}
+
+//----------------------------------------------------------------------------------------
+// Procedure:   e100_eeprom_cleanup
+//
+// Description: This routine returns the EEPROM to an idle state
+//----------------------------------------------------------------------------------------
+
+void
+e100_eeprom_cleanup(struct e100_private *adapter)
+{
+       u16 x;
+
+       x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter));
+
+       x &= ~(EECS | EEDI);
+       writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter));
+
+       raise_clock(adapter, &x);
+       lower_clock(adapter, &x);
+}
+
+//**********************************************************************************
+// Procedure:   e100_eeprom_update_chksum
+//
+// Description: Calculates the checksum and writes it to the EEProm. 
+//              It calculates the checksum accroding to the formula: 
+//                              Checksum = 0xBABA - (sum of first 63 words).
+//
+//-----------------------------------------------------------------------------------
+u16
+e100_eeprom_calculate_chksum(struct e100_private *adapter)
+{
+       u16 idx, xsum_index, checksum = 0;
+
+       // eeprom size is initialized to zero
+       if (!adapter->eeprom_size)
+               adapter->eeprom_size = e100_eeprom_size(adapter);
+
+       xsum_index = adapter->eeprom_size - 1;
+       for (idx = 0; idx < xsum_index; idx++)
+               checksum += e100_eeprom_read(adapter, idx);
+
+       checksum = EEPROM_CHECKSUM - checksum;
+       return checksum;
+}
+
+//----------------------------------------------------------------------------------------
+// Procedure:   e100_eeprom_write_word
+//
+// Description: This routine writes a word to a specific EEPROM location without.
+//              taking EEPROM semaphore and updating checksum. 
+//              Use e100_eeprom_write_block for the EEPROM update
+// Arguments: reg - The EEPROM word that we are going to write to.
+//            data - The data (word) that we are going to write to the EEPROM.
+//----------------------------------------------------------------------------------------
+static void
+e100_eeprom_write_word(struct e100_private *adapter, u16 reg, u16 data)
+{
+       u16 x;
+       u16 bits;
+
+       bits = eeprom_address_size(adapter->eeprom_size);
+
+       /* select EEPROM, mask off ASIC and reset bits, set EECS */
+       x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter));
+       x &= ~(EEDI | EEDO | EESK);
+       writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter));
+       wmb();
+       udelay(EEPROM_STALL_TIME);
+       x |= EECS;
+       writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter));
+
+       shift_out_bits(adapter, EEPROM_EWEN_OPCODE, 5);
+       shift_out_bits(adapter, reg, (u16) (bits - 2));
+       if (!eeprom_wait_cmd_done(adapter))
+               return;
+
+       /* write the new word to the EEPROM & send the write opcode the EEPORM */
+       shift_out_bits(adapter, EEPROM_WRITE_OPCODE, 3);
+
+       /* select which word in the EEPROM that we are writing to */
+       shift_out_bits(adapter, reg, bits);
+
+       /* write the data to the selected EEPROM word */
+       shift_out_bits(adapter, data, 16);
+       if (!eeprom_wait_cmd_done(adapter))
+               return;
+
+       shift_out_bits(adapter, EEPROM_EWDS_OPCODE, 5);
+       shift_out_bits(adapter, reg, (u16) (bits - 2));
+       if (!eeprom_wait_cmd_done(adapter))
+               return;
+
+       e100_eeprom_cleanup(adapter);
+}
+
+//----------------------------------------------------------------------------------------
+// Procedure:   e100_eeprom_write_block
+//
+// Description: This routine writes a block of words starting from specified EEPROM 
+//              location and updates checksum
+// Arguments: reg - The EEPROM word that we are going to write to.
+//            data - The data (word) that we are going to write to the EEPROM.
+//----------------------------------------------------------------------------------------
+void
+e100_eeprom_write_block(struct e100_private *adapter, u16 start, u16 *data,
+                       u16 size)
+{
+       u16 checksum;
+       u16 i;
+
+       if (!adapter->eeprom_size)
+               adapter->eeprom_size = e100_eeprom_size(adapter);
+
+       // Set EEPROM semaphore.
+       if (adapter->rev_id >= D102_REV_ID) {
+               if (!eeprom_set_semaphore(adapter))
+                       return;
+       }
+
+       for (i = 0; i < size; i++) {
+               e100_eeprom_write_word(adapter, start + i, data[i]);
+       }
+       //Update checksum
+       checksum = e100_eeprom_calculate_chksum(adapter);
+       e100_eeprom_write_word(adapter, (adapter->eeprom_size - 1), checksum);
+
+       // Clear EEPROM Semaphore.
+       if (adapter->rev_id >= D102_REV_ID) {
+               eeprom_reset_semaphore(adapter);
+       }
+}
+
+//----------------------------------------------------------------------------------------
+// Procedure:   eeprom_wait_cmd_done
+//
+// Description: This routine waits for the the EEPROM to finish its command.  
+//                              Specifically, it waits for EEDO (data out) to go high.
+// Returns:     true - If the command finished
+//              false - If the command never finished (EEDO stayed low)
+//----------------------------------------------------------------------------------------
+static u16
+eeprom_wait_cmd_done(struct e100_private *adapter)
+{
+       u16 x;
+       unsigned long expiration_time = jiffies + HZ / 100 + 1;
+
+       eeprom_stand_by(adapter);
+
+       while (time_before(jiffies, expiration_time)) {
+               rmb();
+               x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter));
+               if (x & EEDO)
+                       return true;
+
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               schedule_timeout(1);
+       }
+
+       return false;
+}
+
+//----------------------------------------------------------------------------------------
+// Procedure:   eeprom_stand_by
+//
+// Description: This routine lowers the EEPROM chip select (EECS) for a few microseconds.
+//----------------------------------------------------------------------------------------
+static void
+eeprom_stand_by(struct e100_private *adapter)
+{
+       u16 x;
+
+       x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter));
+       x &= ~(EECS | EESK);
+       writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter));
+       wmb();
+       udelay(EEPROM_STALL_TIME);
+       x |= EECS;
+       writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter));
+       udelay(EEPROM_STALL_TIME);
+}
diff --git a/drivers/net/e100/e100_main.c b/drivers/net/e100/e100_main.c
new file mode 100644 (file)
index 0000000..20358a9
--- /dev/null
@@ -0,0 +1,3797 @@
+/*******************************************************************************
+
+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/100 Family of Adapters (e100) (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.
+*******************************************************************************/
+
+/**********************************************************************
+*                                                                     *
+* INTEL CORPORATION                                                   *
+*                                                                     *
+* This software is supplied under the terms of the license included   *
+* above.  All use of this driver must be in accordance with the terms *
+* of that license.                                                    *
+*                                                                     *
+* Module Name:  e100_main.c                                           *
+*                                                                     *
+* Abstract:     Functions for the driver entry points like load,      *
+*               unload, open and close. All board specific calls made *
+*               by the network interface section of the driver.       *
+*                                                                     *
+* Environment:  This file is intended to be specific to the Linux     *
+*               operating system.                                     *
+*                                                                     *
+**********************************************************************/
+
+#undef __NO_VERSION__
+
+#include <linux/config.h>
+#include <net/checksum.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include "e100.h"
+#include "e100_ucode.h"
+#include "e100_config.h"
+#include "e100_phy.h"
+#include "e100_vendor.h"
+
+#ifndef CONFIG_PROC_FS
+#undef E100_CONFIG_PROC_FS
+#endif
+
+#ifdef E100_CONFIG_PROC_FS
+extern int e100_create_proc_subdir(struct e100_private *);
+extern void e100_remove_proc_subdir(struct e100_private *);
+#else
+#define e100_create_proc_subdir(X) 0
+#define e100_remove_proc_subdir(X) do {} while(0)
+#endif
+
+#ifdef SIOCETHTOOL
+#define E100_ETHTOOL_IOCTL
+#endif
+#ifdef E100_ETHTOOL_IOCTL
+static int e100_do_ethtool_ioctl(struct net_device *, struct ifreq *);
+static void e100_get_speed_duplex_caps(struct e100_private *);
+static int e100_ethtool_get_settings(struct net_device *, struct ifreq *);
+static int e100_ethtool_set_settings(struct net_device *, struct ifreq *);
+static void e100_set_speed_duplex(struct e100_private *);
+
+#ifdef ETHTOOL_GDRVINFO
+static int e100_ethtool_get_drvinfo(struct net_device *, struct ifreq *);
+#endif
+#ifdef ETHTOOL_GEEPROM
+static int e100_ethtool_eeprom(struct net_device *, struct ifreq *);
+
+#define E100_EEPROM_MAGIC 0x1234
+#endif
+#ifdef ETHTOOL_GLINK
+static int e100_ethtool_glink(struct net_device *, struct ifreq *);
+#endif
+#ifdef ETHTOOL_NWAY_RST
+static int e100_ethtool_nway_rst(struct net_device *, struct ifreq *);
+#endif
+#ifdef ETHTOOL_GWOL
+static int e100_ethtool_wol(struct net_device *, struct ifreq *);
+static unsigned char e100_setup_filter(struct e100_private *bdp);
+static void e100_do_wol(struct pci_dev *pcid, struct e100_private *bdp);
+static u16 e100_get_ip_lbytes(struct net_device *dev);
+extern void e100_config_wol(struct e100_private *bdp);
+#endif
+#endif /*E100_ETHTOOL_IOCTL */
+
+#ifdef SIOCGMIIPHY
+#define E100_MII_IOCTL
+#endif
+#ifdef E100_MII_IOCTL
+#include <linux/mii.h>
+static int e100_mii_ioctl(struct net_device *, struct ifreq *, int);
+#endif /*E100_MII_IOCTL */
+
+static unsigned char e100_delayed_exec_non_cu_cmd(struct e100_private *,
+                                                 nxmit_cb_entry_t *);
+static void e100_free_nontx_list(struct e100_private *);
+static void e100_non_tx_background(unsigned long);
+
+/* Global Data structures and variables */
+char e100_copyright[] __devinitdata = "Copyright (c) 2002 Intel Corporation";
+
+#define E100_VERSION  "2.0.20-pre1"
+#define E100_FULL_DRIVER_NAME  "Intel(R) PRO/100 Fast Ethernet Adapter - Loadable driver, ver "
+
+const char *e100_version = E100_VERSION;
+const char *e100_full_driver_name = E100_FULL_DRIVER_NAME E100_VERSION;
+char *e100_short_driver_name = "e100";
+static int e100nics = 0;
+
+/*********************************************************************/
+/*! 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 E100_PARAM_INIT { [0 ... E100_MAX_NIC-1] = -1 }
+
+/* All parameters are treated the same, as an integer array of values.
+ * This macro just reduces the need to repeat the same declaration code
+ * over and over (plus this helps to avoid typo bugs).
+ */
+#define E100_PARAM(X, S)                                        \
+        static const int X[E100_MAX_NIC + 1] = E100_PARAM_INIT; \
+        MODULE_PARM(X, "1-" __MODULE_STRING(E100_MAX_NIC) "i"); \
+        MODULE_PARM_DESC(X, S);
+
+/* ====================================================================== */
+static u8 e100_D101M_checksum(struct e100_private *, struct sk_buff *);
+static u8 e100_D102_check_checksum(rfd_t *);
+static int e100_ioctl(struct net_device *, struct ifreq *, int);
+static int e100_open(struct net_device *);
+static int e100_close(struct net_device *);
+static int e100_change_mtu(struct net_device *, int);
+static int e100_xmit_frame(struct sk_buff *, struct net_device *);
+static unsigned char e100_init(struct e100_private *);
+static int e100_set_mac(struct net_device *, void *);
+struct net_device_stats *e100_get_stats(struct net_device *);
+
+static void e100intr(int, void *, struct pt_regs *);
+static void e100_print_brd_conf(struct e100_private *);
+static void e100_set_multi(struct net_device *);
+
+char *e100_get_brand_msg(struct e100_private *);
+static u8 e100_pci_setup(struct pci_dev *, struct e100_private *);
+static u8 e100_sw_init(struct e100_private *);
+static unsigned char e100_alloc_space(struct e100_private *);
+static void e100_dealloc_space(struct e100_private *);
+static int e100_alloc_tcb_pool(struct e100_private *);
+static void e100_setup_tcb_pool(tcb_t *, unsigned int, struct e100_private *);
+static void e100_free_tcb_pool(struct e100_private *);
+static int e100_alloc_rfd_pool(struct e100_private *);
+static void e100_free_rfd_pool(struct e100_private *);
+
+static void e100_rd_eaddr(struct e100_private *);
+static void e100_rd_pwa_no(struct e100_private *);
+extern u16 e100_eeprom_read(struct e100_private *, u16);
+extern void e100_eeprom_write_block(struct e100_private *, u16, u16 *, u16);
+extern u16 e100_eeprom_size(struct e100_private *);
+
+static unsigned char e100_clr_cntrs(struct e100_private *);
+static unsigned char e100_load_microcode(struct e100_private *);
+static unsigned char e100_hw_init(struct e100_private *, u32);
+static unsigned char e100_setup_iaaddr(struct e100_private *, u8 *);
+static unsigned char e100_update_stats(struct e100_private *bdp);
+
+static void e100_start_ru(struct e100_private *);
+static void e100_dump_stats_cntrs(struct e100_private *);
+
+static void e100_check_options(int board, struct e100_private *bdp);
+static void e100_set_int_option(int *, int, int, int, int, char *);
+static void e100_set_bool_option(struct e100_private *bdp, int, u32, int,
+                                char *);
+unsigned char e100_wait_exec_cmplx(struct e100_private *, u32, u8);
+void e100_exec_cmplx(struct e100_private *, u32, u8);
+
+/**
+ * e100_get_rx_struct - retrieve cell to hold skb buff from the pool
+ * @bdp: atapter's private data struct
+ *
+ * Returns the new cell to hold sk_buff or %NULL.
+ */
+static inline struct rx_list_elem *
+e100_get_rx_struct(struct e100_private *bdp)
+{
+       struct rx_list_elem *rx_struct = NULL;
+
+       if (!list_empty(&(bdp->rx_struct_pool))) {
+               rx_struct = list_entry(bdp->rx_struct_pool.next,
+                                      struct rx_list_elem, list_elem);
+               list_del(&(rx_struct->list_elem));
+       }
+
+       return rx_struct;
+}
+
+/**
+ * e100_alloc_skb - allocate an skb for the adapter
+ * @bdp: atapter's private data struct
+ *
+ * Allocates skb with enough room for rfd, and data, and reserve non-data space.
+ * Returns the new cell with sk_buff or %NULL.
+ */
+static inline struct rx_list_elem *
+e100_alloc_skb(struct e100_private *bdp)
+{
+       struct sk_buff *new_skb;
+       u32 skb_size = sizeof (rfd_t);
+       struct rx_list_elem *rx_struct;
+
+       new_skb = (struct sk_buff *) dev_alloc_skb(skb_size);
+       if (new_skb) {
+               /* The IP data should be 
+                  DWORD aligned. since the ethernet header is 14 bytes long, 
+                  we need to reserve 2 extra bytes so that the TCP/IP headers
+                  will be DWORD aligned. */
+               skb_reserve(new_skb, 2);
+               if ((rx_struct = e100_get_rx_struct(bdp)) == NULL)
+                       goto err;
+               rx_struct->skb = new_skb;
+               rx_struct->dma_addr = pci_map_single(bdp->pdev, new_skb->data,
+                                                    sizeof (rfd_t),
+                                                    PCI_DMA_FROMDEVICE);
+               if (!rx_struct->dma_addr)
+                       goto err;
+               skb_reserve(new_skb, bdp->rfd_size);
+               return rx_struct;
+       } else {
+               return NULL;
+       }
+
+err:
+       dev_kfree_skb_irq(new_skb);
+       return NULL;
+}
+
+/**
+ * e100_add_skb_to_end - add an skb to the end of our rfd list
+ * @bdp: atapter's private data struct
+ * @rx_struct: rx_list_elem with the new skb
+ *
+ * Adds a newly allocated skb to the end of our rfd list.
+ */
+inline void
+e100_add_skb_to_end(struct e100_private *bdp, struct rx_list_elem *rx_struct)
+{
+       rfd_t *rfdn;            /* The new rfd */
+       rfd_t *rfd;             /* The old rfd */
+       struct rx_list_elem *rx_struct_last;
+
+       (rx_struct->skb)->dev = bdp->device;
+       rfdn = RFD_POINTER(rx_struct->skb, bdp);
+       rfdn->rfd_header.cb_status = 0;
+       rfdn->rfd_header.cb_cmd = __constant_cpu_to_le16(RFD_EL_BIT);
+       rfdn->rfd_act_cnt = 0;
+       rfdn->rfd_sz = __constant_cpu_to_le16(RFD_DATA_SIZE);
+
+       pci_dma_sync_single(bdp->pdev, rx_struct->dma_addr, bdp->rfd_size,
+                           PCI_DMA_TODEVICE);
+
+       if (!list_empty(&(bdp->active_rx_list))) {
+               rx_struct_last = list_entry(bdp->active_rx_list.prev,
+                                           struct rx_list_elem, list_elem);
+               rfd = RFD_POINTER(rx_struct_last->skb, bdp);
+               pci_dma_sync_single(bdp->pdev, rx_struct_last->dma_addr,
+                                   4, PCI_DMA_FROMDEVICE);
+               put_unaligned(cpu_to_le32(rx_struct->dma_addr),
+                             ((u32 *) (&(rfd->rfd_header.cb_lnk_ptr))));
+
+               pci_dma_sync_single(bdp->pdev, rx_struct_last->dma_addr,
+                                   8, PCI_DMA_TODEVICE);
+               rfd->rfd_header.cb_cmd &=
+                       __constant_cpu_to_le16((u16) ~RFD_EL_BIT);
+
+               pci_dma_sync_single(bdp->pdev, rx_struct_last->dma_addr,
+                                   4, PCI_DMA_TODEVICE);
+       }
+
+       list_add_tail(&(rx_struct->list_elem), &(bdp->active_rx_list));
+}
+
+static inline void
+e100_alloc_skbs(struct e100_private *bdp)
+{
+       for (; bdp->skb_req > 0; bdp->skb_req--) {
+               struct rx_list_elem *rx_struct;
+
+               if ((rx_struct = e100_alloc_skb(bdp)) == NULL)
+                       return;
+
+               e100_add_skb_to_end(bdp, rx_struct);
+       }
+}
+
+void e100_tx_srv(struct e100_private *);
+u32 e100_rx_srv(struct e100_private *, u32, int *);
+
+void e100_polling_tasklet(unsigned long);
+
+void e100_watchdog(struct net_device *);
+void e100_refresh_txthld(struct e100_private *);
+void e100_manage_adaptive_ifs(struct e100_private *);
+void e100_clear_pools(struct e100_private *);
+static void e100_clear_structs(struct net_device *);
+static inline tcb_t *e100_prepare_xmit_buff(struct e100_private *,
+                                           struct sk_buff *);
+static void e100_set_multi_exec(struct net_device *dev);
+
+MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
+MODULE_DESCRIPTION(E100_FULL_DRIVER_NAME E100_VERSION);
+MODULE_LICENSE("Dual BSD/GPL");
+
+E100_PARAM(TxDescriptors, "Number of transmit descriptors");
+E100_PARAM(RxDescriptors, "Number of receive descriptors");
+E100_PARAM(XsumRX, "Disable or enable Receive Checksum offload");
+E100_PARAM(e100_speed_duplex, "Speed and Duplex settings");
+E100_PARAM(ucode, "Disable or enable microcode loading");
+E100_PARAM(ber, "Value for the BER correction algorithm");
+E100_PARAM(flow_control, "Disable or enable Ethernet PAUSE frames processing");
+E100_PARAM(IntDelay, "Value for CPU saver's interrupt delay");
+E100_PARAM(BundleSmallFr, "Disable or enable interrupt bundling of small frames");
+E100_PARAM(BundleMax, "Maximum number for CPU saver's packet bundling");
+E100_PARAM(IFS, "Disable or enable the adaptive IFS algorithm");
+E100_PARAM(RxCongestionControl, "Disable or enable switch to polling mode");
+E100_PARAM(PollingMaxWork, "Max number of receive packets processed on single "
+          "polling call");
+
+/**
+ * e100_exec_cmd - issue a comand
+ * @bdp: atapter's private data struct
+ * @scb_cmd_low: the command that is to be issued
+ *
+ * This general routine will issue a command to the e100.
+ */
+static inline void
+e100_exec_cmd(struct e100_private *bdp, u8 cmd_low)
+{
+       writeb(cmd_low, &(bdp->scb->scb_cmd_low));
+}
+
+/**
+ * e100_wait_scb - wait for SCB to clear
+ * @bdp: atapter's private data struct
+ *
+ * This routine checks to see if the e100 has accepted a command.
+ * It does so by checking the command field in the SCB, which will
+ * be zeroed by the e100 upon accepting a command.  The loop waits
+ * for up to 1 millisecond for command acceptance.
+ *
+ * Returns:
+ *      true if the SCB cleared within 1 millisecond.
+ *      false if it didn't clear within 1 millisecond
+ */
+unsigned char
+e100_wait_scb(struct e100_private *bdp)
+{
+       int i;
+
+       /* loop on the scb for a few times */
+       for (i = 0; i < 100; i++) {
+               if (!readb(&bdp->scb->scb_cmd_low))
+                       return true;
+               cpu_relax();
+       }
+
+       /* it didn't work. do it the slow way using udelay()s */
+       for (i = 0; i < E100_MAX_BUSY_WAIT; i++) {
+               if (!readb(&bdp->scb->scb_cmd_low))
+                       return true;
+               cpu_relax();
+               udelay(1);
+       }
+
+       return false;
+}
+
+/**
+ * e100_wait_exec_simple - issue a command
+ * @bdp: atapter's private data struct
+ * @scb_cmd_low: the command that is to be issued
+ *
+ * This general routine will issue a command to the e100 after waiting for
+ * the previous command to finish.
+ *
+ * Returns:
+ *      true if the command was issued to the chip successfully
+ *      false if the command was not issued to the chip
+ */
+inline unsigned char
+e100_wait_exec_simple(struct e100_private *bdp, u8 scb_cmd_low)
+{
+       if (!e100_wait_scb(bdp)) {
+               printk(KERN_ERR "%s e100_wait_exec_simple: Wait failed\n",
+                      bdp->device->name);
+               return false;
+       }
+       e100_exec_cmd(bdp, scb_cmd_low);
+       return true;
+}
+
+void
+e100_exec_cmplx(struct e100_private *bdp, u32 phys_addr, u8 cmd)
+{
+       writel(phys_addr, &(bdp->scb->scb_gen_ptr));
+       readw(&(bdp->scb->scb_status)); /* flashes last write, read-safe */
+       e100_exec_cmd(bdp, cmd);
+}
+
+unsigned char
+e100_wait_exec_cmplx(struct e100_private *bdp, u32 phys_addr, u8 cmd)
+{
+       if (!e100_wait_scb(bdp)) {
+               return false;
+       }
+       e100_exec_cmplx(bdp, phys_addr, cmd);
+       return true;
+}
+
+inline u8
+e100_wait_cus_idle(struct e100_private *bdp)
+{
+       int i;
+
+       /* loop on the scb for a few times */
+       for (i = 0; i < 100; i++) {
+               if (((readw(&(bdp->scb->scb_status)) & SCB_CUS_MASK) !=
+                    SCB_CUS_ACTIVE)) {
+                       return true;
+               }
+               cpu_relax();
+       }
+
+       for (i = 0; i < E100_MAX_BUSY_WAIT; i++) {
+               if (((readw(&(bdp->scb->scb_status)) & SCB_CUS_MASK) !=
+                    SCB_CUS_ACTIVE)) {
+                       return true;
+               }
+               cpu_relax();
+               udelay(1);
+       }
+
+       return false;
+}
+
+/**
+ * e100_dis_intr - disable interrupts
+ * @bdp: atapter's private data struct
+ *
+ * This routine disables interrupts at the hardware, by setting
+ * the M (mask) bit in the adapter's CSR SCB command word.
+ */
+static inline void
+e100_dis_intr(struct e100_private *bdp)
+{
+       /* Disable interrupts on our PCI board by setting the mask bit */
+       writeb(SCB_INT_MASK, &bdp->scb->scb_cmd_hi);
+}
+
+/**
+ * e100_set_intr_mask - set interrupts
+ * @bdp: atapter's private data struct
+ *
+ * This routine sets interrupts at the hardware, by resetting
+ * the M (mask) bit in the adapter's CSR SCB command word
+ */
+static inline void
+e100_set_intr_mask(struct e100_private *bdp)
+{
+       writeb(bdp->intr_mask, &bdp->scb->scb_cmd_hi);
+}
+
+static inline void
+e100_trigger_SWI(struct e100_private *bdp)
+{
+       /* Trigger interrupt on our PCI board by asserting SWI bit */
+       writeb(SCB_SOFT_INT, &bdp->scb->scb_cmd_hi);
+}
+
+static int __devinit
+e100_found1(struct pci_dev *pcid, const struct pci_device_id *ent)
+{
+       static int first_time = true;
+       struct net_device *dev = NULL;
+       struct e100_private *bdp = NULL;
+       int rc = 0;
+
+       dev = alloc_etherdev(sizeof (struct e100_private));
+       if (dev == NULL) {
+               printk(KERN_ERR "Not able to alloc etherdev struct\n");
+               rc = -ENODEV;
+               goto out;
+       }
+
+       SET_MODULE_OWNER(dev);
+
+       if (first_time) {
+               first_time = false;
+               printk(KERN_NOTICE "%s\n", e100_full_driver_name);
+               printk(KERN_NOTICE "%s\n", e100_copyright);
+               printk(KERN_NOTICE "\n");
+       }
+
+       bdp = dev->priv;
+       bdp->pdev = pcid;
+       bdp->device = dev;
+
+       pci_set_drvdata(pcid, dev);
+
+       if ((rc = e100_alloc_space(bdp)) != 0) {
+               goto err_dev;
+       }
+
+       bdp->flags = 0;
+       bdp->ifs_state = 0;
+       bdp->ifs_value = 0;
+       bdp->scb = 0;
+
+       init_timer(&bdp->nontx_timer_id);
+       bdp->nontx_timer_id.data = (unsigned long) bdp;
+       bdp->nontx_timer_id.function = (void *) &e100_non_tx_background;
+       INIT_LIST_HEAD(&(bdp->non_tx_cmd_list));
+       bdp->non_tx_command_state = E100_NON_TX_IDLE;
+
+       init_timer(&bdp->watchdog_timer);
+       bdp->watchdog_timer.data = (unsigned long) dev;
+       bdp->watchdog_timer.function = (void *) &e100_watchdog;
+
+       if ((rc = e100_pci_setup(pcid, bdp)) != 0) {
+               goto err_dealloc;
+       }
+
+       if (((bdp->pdev->device > 0x1030)
+            && (bdp->pdev->device < 0x103F))
+           || (bdp->pdev->device == 0x2449)
+           || (bdp->pdev->device == 0x2459)
+           || (bdp->pdev->device == 0x245D)) {
+               bdp->rev_id = D101MA_REV_ID;    /* workaround for ICH3 */
+               bdp->flags |= IS_ICH;
+       }
+
+       if (bdp->rev_id == 0xff)
+               bdp->rev_id = 1;
+
+       if ((u8) bdp->rev_id >= D101A4_REV_ID)
+               bdp->flags |= IS_BACHELOR;
+
+       if ((u8) bdp->rev_id >= D102_REV_ID) {
+               bdp->flags |= USE_IPCB;
+               bdp->rfd_size = 32;
+       } else {
+               bdp->rfd_size = 16;
+       }
+
+       e100_check_options(e100nics, bdp);
+
+       if (!e100_init(bdp)) {
+               printk(KERN_ERR "Failed to initialize e100, instance #%d\n",
+                      e100nics);
+               rc = -ENODEV;
+               goto err_pci;
+       }
+
+       dev->irq = pcid->irq;
+       dev->open = &e100_open;
+       dev->hard_start_xmit = &e100_xmit_frame;
+       dev->stop = &e100_close;
+       dev->change_mtu = &e100_change_mtu;
+       dev->get_stats = &e100_get_stats;
+       dev->set_multicast_list = &e100_set_multi;
+       dev->set_mac_address = &e100_set_mac;
+       dev->do_ioctl = &e100_ioctl;
+#ifdef E100_ZEROCOPY
+       if (bdp->flags & USE_IPCB) {
+               dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
+       }
+#endif
+       e100nics++;
+
+#ifdef E100_ETHTOOL_IOCTL
+       e100_get_speed_duplex_caps(bdp);
+#endif /*E100_ETHTOOL_IOCTL */
+
+       if ((rc = register_netdev(dev)) != 0) {
+               goto err_pci;
+       }
+
+       bdp->device_type = ent->driver_data;
+       printk(KERN_NOTICE
+              "%s: %s\n", bdp->device->name, e100_get_brand_msg(bdp));
+       e100_print_brd_conf(bdp);
+
+       if (e100_create_proc_subdir(bdp) < 0) {
+               printk(KERN_ERR "Failed to create proc directory for %s\n",
+                      bdp->device->name);
+       }
+
+#ifdef ETHTOOL_GWOL
+       /* Disabling all WOLs as initialization */
+       bdp->wolsupported = bdp->wolopts = 0;
+       if (bdp->rev_id >= D101MA_REV_ID) {
+               bdp->wolsupported =
+                       WAKE_PHY | WAKE_UCAST | WAKE_ARP | WAKE_MAGIC;
+               bdp->wolopts = WAKE_MAGIC;
+       }
+#endif
+
+       printk(KERN_NOTICE "\n");
+
+       goto out;
+
+err_pci:
+       iounmap(bdp->scb);
+       pci_release_regions(pcid);
+       pci_disable_device(pcid);
+err_dealloc:
+       e100_dealloc_space(bdp);
+err_dev:
+       pci_set_drvdata(pcid, NULL);
+       kfree(dev);
+out:
+       return rc;
+}
+
+/**
+ * e100_clear_structs - free resources
+ * @dev: adapter's net_device struct
+ *
+ * Free all device specific structs, unmap i/o address, etc.
+ */
+static void __devexit
+e100_clear_structs(struct net_device *dev)
+{
+       struct e100_private *bdp = dev->priv;
+
+       iounmap(bdp->scb);
+       pci_release_regions(bdp->pdev);
+       pci_disable_device(bdp->pdev);
+
+       e100_dealloc_space(bdp);
+       pci_set_drvdata(bdp->pdev, NULL);
+       kfree(dev);
+}
+
+static void __devexit
+e100_remove1(struct pci_dev *pcid)
+{
+       struct net_device *dev;
+       struct e100_private *bdp;
+
+       if (!(dev = (struct net_device *) pci_get_drvdata(pcid)))
+               return;
+
+       bdp = dev->priv;
+
+       unregister_netdev(dev);
+
+       e100_remove_proc_subdir(bdp);
+
+       e100_sw_reset(bdp, PORT_SELECTIVE_RESET);
+
+       if (bdp->non_tx_command_state != E100_NON_TX_IDLE) {
+               del_timer_sync(&bdp->nontx_timer_id);
+               e100_free_nontx_list(bdp);
+               bdp->non_tx_command_state = E100_NON_TX_IDLE;
+       }
+
+#ifdef ETHTOOL_GWOL
+       /* Set up wol options and enable PME */
+       e100_do_wol(pcid, bdp);
+#endif
+
+       e100_clear_structs(dev);
+
+       --e100nics;
+}
+
+MODULE_DEVICE_TABLE(pci, e100_id_table);
+
+static struct pci_driver e100_driver = {
+       name:           "e100",
+       id_table:       e100_id_table,
+       probe:          e100_found1,
+       remove:         __devexit_p(e100_remove1),
+       suspend:        NULL,
+       resume:         NULL,
+};
+
+static int __init
+e100_init_module(void)
+{
+       return pci_module_init(&e100_driver);
+
+}
+
+static void __exit
+e100_cleanup_module(void)
+{
+       pci_unregister_driver(&e100_driver);
+}
+
+module_init(e100_init_module);
+module_exit(e100_cleanup_module);
+
+/**
+ * e100_check_options - check command line options
+ * @board: board number
+ * @bdp: atapter's private data struct
+ *
+ * This routine does range checking on command-line options
+ */
+void __devinit
+e100_check_options(int board, struct e100_private *bdp)
+{
+       int val;
+
+       if (board >= E100_MAX_NIC) {
+               printk(KERN_NOTICE "No configuration available for board #%d\n",
+                      board);
+               printk(KERN_NOTICE "Using defaults for all values\n");
+       }
+
+       val = (board < E100_MAX_NIC) ? TxDescriptors[board] : -1;
+       e100_set_int_option(&(bdp->params.TxDescriptors), val, E100_MIN_TCB,
+                           E100_MAX_TCB, E100_DEFAULT_TCB,
+                           "TxDescriptor count");
+
+       val = (board < E100_MAX_NIC) ? RxDescriptors[board] : -1;
+       e100_set_int_option(&(bdp->params.RxDescriptors), val, E100_MIN_RFD,
+                           E100_MAX_RFD, E100_DEFAULT_RFD,
+                           "RxDescriptor count");
+
+       val = (board < E100_MAX_NIC) ? e100_speed_duplex[board] : -1;
+       e100_set_int_option(&(bdp->params.e100_speed_duplex), val, 0, 4,
+                           E100_DEFAULT_SPEED_DUPLEX, "speed/duplex mode");
+
+       val = (board < E100_MAX_NIC) ? ber[board] : -1;
+       e100_set_int_option(&(bdp->params.ber), val, 0, ZLOCK_MAX_ERRORS,
+                           E100_DEFAULT_BER, "Bit Error Rate count");
+
+       val = (board < E100_MAX_NIC) ? XsumRX[board] : -1;
+       e100_set_bool_option(bdp, val, PRM_XSUMRX, E100_DEFAULT_XSUM,
+                            "XsumRX value");
+
+       /* Default ucode value depended on controller revision */
+       val = (board < E100_MAX_NIC) ? ucode[board] : -1;
+       if (bdp->rev_id >= D101MA_REV_ID) {
+               e100_set_bool_option(bdp, val, PRM_UCODE, E100_DEFAULT_UCODE,
+                                    "ucode value");
+       } else {
+               e100_set_bool_option(bdp, val, PRM_UCODE, false, "ucode value");
+       }
+
+       val = (board < E100_MAX_NIC) ? flow_control[board] : -1;
+       e100_set_bool_option(bdp, val, PRM_FC, E100_DEFAULT_FC,
+                            "flow control value");
+
+       val = (board < E100_MAX_NIC) ? IFS[board] : -1;
+       e100_set_bool_option(bdp, val, PRM_IFS, E100_DEFAULT_IFS, "IFS value");
+
+       val = (board < E100_MAX_NIC) ? BundleSmallFr[board] : -1;
+       e100_set_bool_option(bdp, val, PRM_BUNDLE_SMALL,
+                            E100_DEFAULT_BUNDLE_SMALL_FR,
+                            "CPU saver bundle small frames value");
+
+       val = (board < E100_MAX_NIC) ? IntDelay[board] : -1;
+       e100_set_int_option(&(bdp->params.IntDelay), val, 0x0, 0xFFFF,
+                           E100_DEFAULT_CPUSAVER_INTERRUPT_DELAY,
+                           "CPU saver interrupt delay value");
+
+       val = (board < E100_MAX_NIC) ? BundleMax[board] : -1;
+       e100_set_int_option(&(bdp->params.BundleMax), val, 0x1, 0xFFFF,
+                           E100_DEFAULT_CPUSAVER_BUNDLE_MAX,
+                           "CPU saver bundle max value");
+
+       val = (board < E100_MAX_NIC) ? RxCongestionControl[board] : -1;
+       e100_set_bool_option(bdp, val, PRM_RX_CONG,
+                            E100_DEFAULT_RX_CONGESTION_CONTROL,
+                            "Rx Congestion Control value");
+
+       val = (board < E100_MAX_NIC) ? PollingMaxWork[board] : -1;
+       e100_set_int_option(&(bdp->params.PollingMaxWork), val, 1, E100_MAX_RFD,
+                           RxDescriptors[board], "Polling Max Work value");
+
+       if (val <= 0) {
+               bdp->params.b_params &= ~PRM_RX_CONG;
+       }
+}
+
+/**
+ * e100_set_int_option - check and set an integer option
+ * @option: a pointer to the relevant option field
+ * @val: the value specified
+ * @min: the minimum valid value
+ * @max: the maximum valid value
+ * @default_val: the default value
+ * @name: the name of the option
+ *
+ * This routine does range checking on a command-line option.
+ * If the option's value is '-1' use the specified default.
+ * Otherwise, if the value is invalid, change it to the default.
+ */
+void __devinit
+e100_set_int_option(int *option, int val, int min, int max, int default_val,
+                   char *name)
+{
+       if (val == -1) {        /* no value specified. use default */
+               *option = default_val;
+
+       } else if ((val < min) || (val > max)) {
+               printk(KERN_NOTICE
+                      "Invalid %s specified (%i). Valid range is %i-%i\n",
+                      name, val, min, max);
+               printk(KERN_NOTICE "Using default %s of %i\n", name,
+                      default_val);
+               *option = default_val;
+       } else {
+               printk(KERN_INFO "Using specified %s of %i\n", name, val);
+               *option = val;
+       }
+}
+
+/**
+ * e100_set_bool_option - check and set a boolean option
+ * @bdp: atapter's private data struct
+ * @val: the value specified
+ * @mask: the mask for the relevant option
+ * @default_val: the default value
+ * @name: the name of the option
+ *
+ * This routine checks a boolean command-line option.
+ * If the option's value is '-1' use the specified default.
+ * Otherwise, if the value is invalid (not 0 or 1), 
+ * change it to the default.
+ */
+void __devinit
+e100_set_bool_option(struct e100_private *bdp, int val, u32 mask,
+                    int default_val, char *name)
+{
+       if (val == -1) {
+               if (default_val)
+                       bdp->params.b_params |= mask;
+
+       } else if ((val != true) && (val != false)) {
+               printk(KERN_NOTICE
+                      "Invalid %s specified (%i). Valid values are %i/%i\n",
+                      name, val, false, true);
+               printk(KERN_NOTICE "Using default %s of %i\n", name,
+                      default_val);
+
+               if (default_val)
+                       bdp->params.b_params |= mask;
+       } else {
+               printk(KERN_INFO "Using specified %s of %i\n", name, val);
+               if (val)
+                       bdp->params.b_params |= mask;
+       }
+}
+
+static int
+e100_open(struct net_device *dev)
+{
+       struct e100_private *bdp;
+       int rc = 0;
+
+       bdp = dev->priv;
+
+       read_lock(&(bdp->isolate_lock));
+
+       if (bdp->driver_isolated) {
+               rc = -EBUSY;
+               goto exit;
+       }
+
+       /* setup the tcb pool */
+       if (!e100_alloc_tcb_pool(bdp)) {
+               rc = -ENOMEM;
+               goto err_exit;
+       }
+       bdp->last_tcb = NULL;
+
+       bdp->tcb_pool.head = 0;
+       bdp->tcb_pool.tail = 1; 
+
+       e100_setup_tcb_pool((tcb_t *) bdp->tcb_pool.data,
+                           bdp->params.TxDescriptors, bdp);
+
+       if (!e100_alloc_rfd_pool(bdp)) {
+               rc = -ENOMEM;
+               goto err_exit;
+       }
+
+       if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE)) {
+               rc = -EAGAIN;
+               goto err_exit;
+       }
+
+       if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE)) {
+               rc = -EAGAIN;
+               goto err_exit;
+       }
+
+       mod_timer(&(bdp->watchdog_timer), jiffies + (2 * HZ));
+
+       netif_start_queue(dev);
+
+       e100_start_ru(bdp);
+       if ((rc = request_irq(dev->irq, &e100intr, SA_SHIRQ,
+                             e100_short_driver_name, dev)) != 0) {
+               del_timer_sync(&bdp->watchdog_timer);
+               goto err_exit;
+       }
+       if (bdp->params.b_params & PRM_RX_CONG) {
+               DECLARE_TASKLET(polling_tasklet,
+                               e100_polling_tasklet, (unsigned long) bdp);
+               bdp->polling_tasklet = polling_tasklet;
+       }
+       bdp->intr_mask = 0;
+       e100_set_intr_mask(bdp);
+
+       e100_force_config(bdp);
+
+       goto exit;
+
+err_exit:
+       e100_clear_pools(bdp);
+exit:
+       read_unlock(&(bdp->isolate_lock));
+       return rc;
+}
+
+static int
+e100_close(struct net_device *dev)
+{
+       struct e100_private *bdp = dev->priv;
+
+       bdp->intr_mask = SCB_INT_MASK;
+       e100_isolate_driver(bdp);
+
+#ifdef ETHTOOL_GWOL
+       bdp->ip_lbytes = e100_get_ip_lbytes(dev);
+#endif
+       free_irq(dev->irq, dev);
+       e100_clear_pools(bdp);
+
+       if (bdp->params.b_params & PRM_RX_CONG) {
+               tasklet_kill(&(bdp->polling_tasklet));
+       }
+
+       /* set the isolate flag to false, so e100_open can be called */
+       bdp->driver_isolated = false;
+
+       return 0;
+}
+
+static int
+e100_change_mtu(struct net_device *dev, int new_mtu)
+{
+       if ((new_mtu < 68) || (new_mtu > (ETH_DATA_LEN + VLAN_SIZE)))
+               return -EINVAL;
+
+       dev->mtu = new_mtu;
+       return 0;
+}
+
+static int
+e100_xmit_frame(struct sk_buff *skb, struct net_device *dev)
+{
+       int rc = 0;
+       int notify_stop = false;
+       struct e100_private *bdp = dev->priv;
+
+       read_lock(&(bdp->isolate_lock));
+
+       if (bdp->driver_isolated) {
+               rc = -EBUSY;
+               goto exit2;
+       }
+
+       if (!spin_trylock(&bdp->bd_non_tx_lock)) {
+               notify_stop = true;
+               rc = 1;
+               goto exit2;
+       }
+
+       if (!TCBS_AVAIL(bdp->tcb_pool) ||
+           (bdp->non_tx_command_state != E100_NON_TX_IDLE)) {
+               notify_stop = true;
+               rc = 1;
+               goto exit1;
+       }
+
+       e100_prepare_xmit_buff(bdp, skb);
+
+       bdp->drv_stats.net_stats.tx_bytes += skb->len;
+
+       dev->trans_start = jiffies;
+
+exit1:
+       spin_unlock(&bdp->bd_non_tx_lock);
+exit2:
+       read_unlock(&(bdp->isolate_lock));
+       if (notify_stop) {
+               netif_stop_queue(dev);
+       }
+
+       return rc;
+}
+
+/**
+ * e100_get_stats - get driver statistics
+ * @dev: adapter's net_device struct
+ *
+ * This routine is called when the OS wants the adapter's stats returned.
+ * It returns the address of the net_device_stats stucture for the device.
+ * If the statistics are currently being updated, then they might be incorrect
+ * for a short while. However, since this cannot actually cause damage, no
+ * locking is used.
+ */
+struct net_device_stats *
+e100_get_stats(struct net_device *dev)
+{
+       struct e100_private *bdp = dev->priv;
+
+       bdp->drv_stats.net_stats.tx_errors =
+               bdp->drv_stats.net_stats.tx_carrier_errors +
+               bdp->drv_stats.net_stats.tx_aborted_errors;
+
+       bdp->drv_stats.net_stats.rx_errors =
+               bdp->drv_stats.net_stats.rx_crc_errors +
+               bdp->drv_stats.net_stats.rx_frame_errors +
+               bdp->drv_stats.net_stats.rx_length_errors +
+               bdp->drv_stats.rcv_cdt_frames;
+
+       return &(bdp->drv_stats.net_stats);
+}
+
+/**
+ * e100_set_mac - set the MAC address
+ * @dev: adapter's net_device struct
+ * @addr: the new address
+ *
+ * This routine sets the ethernet address of the board
+ * Returns:
+ * 0  - if successful
+ * -1 - otherwise
+ */
+static int
+e100_set_mac(struct net_device *dev, void *addr)
+{
+       struct e100_private *bdp;
+       int rc = -1;
+       struct sockaddr *p_sockaddr = (struct sockaddr *) addr;
+
+       bdp = dev->priv;
+
+       read_lock(&(bdp->isolate_lock));
+
+       if (bdp->driver_isolated) {
+               goto exit;
+       }
+       if (e100_setup_iaaddr(bdp, (u8 *) (p_sockaddr->sa_data))) {
+               memcpy(&(dev->dev_addr[0]), p_sockaddr->sa_data, ETH_ALEN);
+               rc = 0;
+       }
+
+exit:
+       read_unlock(&(bdp->isolate_lock));
+       return rc;
+}
+
+static void
+e100_set_multi_exec(struct net_device *dev)
+{
+       struct e100_private *bdp = dev->priv;
+       mltcst_cb_t *mcast_buff;
+       cb_header_t *cb_hdr;
+       struct dev_mc_list *mc_list;
+       unsigned int i;
+       nxmit_cb_entry_t *cmd = e100_alloc_non_tx_cmd(bdp);
+
+       if (cmd != NULL) {
+               mcast_buff = &((cmd->non_tx_cmd)->ntcb.multicast);
+               cb_hdr = &((cmd->non_tx_cmd)->ntcb.multicast.mc_cbhdr);
+       } else {
+               return;
+       }
+
+       /* initialize the multi cast command */
+       cb_hdr->cb_cmd = __constant_cpu_to_le16(CB_MULTICAST);
+
+       /* now fill in the rest of the multicast command */
+       *(u16 *) (&(mcast_buff->mc_count)) = cpu_to_le16(dev->mc_count * 6);
+       for (i = 0, mc_list = dev->mc_list;
+            (i < dev->mc_count) && (i < MAX_MULTICAST_ADDRS);
+            i++, mc_list = mc_list->next) {
+               /* copy into the command */
+               memcpy(&(mcast_buff->mc_addr[i * ETH_ALEN]),
+                      (u8 *) &(mc_list->dmi_addr), ETH_ALEN);
+       }
+
+       if (!e100_exec_non_cu_cmd(bdp, cmd)) {
+               printk(KERN_WARNING "%s: Multicast setup failed\n", dev->name);
+       }
+}
+
+/**
+ * e100_set_multi - set multicast status
+ * @dev: adapter's net_device struct
+ *
+ * This routine is called to add or remove multicast addresses, and/or to
+ * change the adapter's promiscuous state.
+ */
+static void
+e100_set_multi(struct net_device *dev)
+{
+       struct e100_private *bdp = dev->priv;
+       unsigned char promisc_enbl;
+       unsigned char mulcast_enbl;
+
+       read_lock(&(bdp->isolate_lock));
+       if (bdp->driver_isolated) {
+               goto exit;
+       }
+       promisc_enbl = (dev->flags & IFF_PROMISC);
+       mulcast_enbl = ((dev->flags & IFF_ALLMULTI) ||
+                       (dev->mc_count > MAX_MULTICAST_ADDRS));
+
+       e100_config_promisc(bdp, promisc_enbl);
+       e100_config_mulcast_enbl(bdp, mulcast_enbl);
+
+       /* reconfigure the chip if something has changed in its config space */
+       e100_config(bdp);
+
+       if ((promisc_enbl) || (mulcast_enbl)) {
+               goto exit;      /* no need for Multicast Cmd */
+       }
+
+       /* get the multicast CB */
+       e100_set_multi_exec(dev);
+
+exit:
+       read_unlock(&(bdp->isolate_lock));
+}
+
+static int
+e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+
+       switch (cmd) {
+
+#ifdef E100_ETHTOOL_IOCTL
+       case SIOCETHTOOL:
+               return e100_do_ethtool_ioctl(dev, ifr);
+               break;
+#endif /*E100_ETHTOOL_IOCTL */
+
+#ifdef E100_MII_IOCTL
+       case SIOCGMIIPHY:       /* Get address of MII PHY in use. */
+       case SIOCGMIIREG:       /* Read MII PHY register. */
+       case SIOCSMIIREG:       /* Write to MII PHY register. */
+               return e100_mii_ioctl(dev, ifr, cmd);
+               break;
+#endif /*E100_MII_IOCTL */
+
+       default:
+               return -EOPNOTSUPP;
+       }
+       return 0;
+
+}
+
+/**
+ * e100init - initialize the adapter
+ * @bdp: atapter's private data struct
+ *
+ * This routine is called when this driver is loaded. This is the initialization
+ * routine which allocates memory, configures the adapter and determines the
+ * system resources.
+ *
+ * Returns:
+ *      true: if successful
+ *      false: otherwise
+ */
+static unsigned char __devinit
+e100_init(struct e100_private *bdp)
+{
+       e100_sw_init(bdp);
+
+       if (!e100_selftest(bdp, NULL, NULL)) {
+               printk(KERN_ERR "selftest failed\n");
+               return false;
+       }
+
+       /* read the MAC address from the eprom */
+       e100_rd_eaddr(bdp);
+       /* read NIC's part number */
+       e100_rd_pwa_no(bdp);
+
+       if (!e100_hw_init(bdp, PORT_SOFTWARE_RESET)) {
+               printk(KERN_ERR "hw init failed\n");
+               return false;
+       }
+       e100_dis_intr(bdp);
+
+       return true;
+}
+
+/**
+ * e100_sw_init - initialize software structs
+ * @bdp: atapter's private data struct
+ * 
+ * This routine initializes all software structures. Sets up the
+ * circular structures for the RFD's & TCB's. Allocates the per board
+ * structure for storing adapter information. The CSR is also memory 
+ * mapped in this routine.
+ *
+ * Returns :
+ *      true: if S/W was successfully initialized
+ *      false: otherwise
+ */
+static unsigned char __devinit
+e100_sw_init(struct e100_private *bdp)
+{
+       bdp->next_cu_cmd = START_WAIT;  // init the next cu state
+
+       /* 
+        * Set the value for # of good xmits per underrun. the value assigned
+        * here is an intelligent  suggested default. Nothing magical about it.
+        */
+       bdp->tx_per_underrun = DEFAULT_TX_PER_UNDERRUN;
+
+       /* get the default transmit threshold value */
+       bdp->tx_thld = TX_THRSHLD;
+
+       /* get the EPROM size */
+       bdp->eeprom_size = e100_eeprom_size(bdp);
+
+       /* Initialize our spinlocks */
+       spin_lock_init(&(bdp->bd_lock));
+       spin_lock_init(&(bdp->bd_non_tx_lock));
+       spin_lock_init(&(bdp->config_lock));
+       spin_lock_init(&(bdp->mdi_access_lock));
+       bdp->isolate_lock = RW_LOCK_UNLOCKED;
+       bdp->driver_isolated = false;
+
+       return 1;
+}
+
+/**
+ * e100_hw_init - initialized tthe hardware
+ * @bdp: atapter's private data struct
+ * @reset_cmd: s/w reset or selective reset
+ *
+ * This routine performs a reset on the adapter, and configures the adapter.
+ * This includes configuring the 82557 LAN controller, validating and setting
+ * the node address, detecting and configuring the Phy chip on the adapter,
+ * and initializing all of the on chip counters.
+ *
+ * Returns:
+ *      true - If the adapter was initialized
+ *      false - If the adapter failed initialization
+ */
+unsigned char __devinit
+e100_hw_init(struct e100_private *bdp, u32 reset_cmd)
+{
+       if (!e100_phy_init(bdp))
+               return false;
+
+       /* Issue a software reset to the e100 */
+       e100_sw_reset(bdp, reset_cmd);
+
+       /* Load the CU BASE (set to 0, because we use linear mode) */
+       if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE))
+               return false;
+
+       if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE))
+               return false;
+
+       /* Load interrupt microcode  */
+       if (e100_load_microcode(bdp)) {
+               bdp->flags |= DF_UCODE_LOADED;
+       }
+
+       e100_config_init(bdp);
+       if (!e100_config(bdp)) {
+               return false;
+       }
+
+       if (!e100_setup_iaaddr(bdp, bdp->device->dev_addr))
+               return false;
+
+       /* Clear the internal counters */
+       if (!e100_clr_cntrs(bdp))
+               return false;
+
+       /* Change for 82558 enhancement */
+       /* If 82558/9 and if the user has enabled flow control, set up the
+        * Flow Control Reg. in the CSR */
+       if ((bdp->flags & IS_BACHELOR)
+           && (bdp->params.b_params & PRM_FC)) {
+               writeb(DFLT_FC_THLD, &bdp->scb->scb_ext.d101_scb.scb_fc_thld);
+               writeb(DFLT_FC_CMD,
+                      &bdp->scb->scb_ext.d101_scb.scb_fc_xon_xoff);
+       }
+
+       return true;
+}
+
+/**
+ * e100_setup_tcb_pool - setup TCB circular list
+ * @head: Pointer to head of the allocated TCBs
+ * @qlen: Number of elements in the queue
+ * @bdp: atapter's private data struct
+ * 
+ * This routine arranges the contigiously allocated TCB's in a circular list.
+ * Also does the one time initialization of the TCBs.
+ */
+static void
+e100_setup_tcb_pool(tcb_t *head, unsigned int qlen, struct e100_private *bdp)
+{
+       int ele_no;
+       tcb_t *pcurr_tcb;       /* point to current tcb */
+       u32 next_phys;          /* the next phys addr */
+       u16 txcommand = CB_S_BIT | CB_TX_SF_BIT;
+
+       if (bdp->flags & USE_IPCB) {
+               txcommand |= CB_IPCB_TRANSMIT | CB_CID_DEFAULT;
+       } else if (bdp->flags & IS_BACHELOR) {
+               txcommand |= CB_TRANSMIT | CB_CID_DEFAULT;
+       } else {
+               txcommand |= CB_TRANSMIT;
+       }
+
+       for (ele_no = 0, next_phys = bdp->tcb_phys, pcurr_tcb = head;
+            ele_no < qlen; ele_no++, pcurr_tcb++) {
+
+               /* set the phys addr for this TCB, next_phys has not incr. yet */
+               pcurr_tcb->tcb_phys = next_phys;
+               next_phys += sizeof (tcb_t);
+
+               /* set the link to next tcb */
+               if (ele_no == (qlen - 1))
+                       pcurr_tcb->tcb_hdr.cb_lnk_ptr =
+                               cpu_to_le32(bdp->tcb_phys);
+               else
+                       pcurr_tcb->tcb_hdr.cb_lnk_ptr = cpu_to_le32(next_phys);
+
+               pcurr_tcb->tcb_hdr.cb_status = 0;
+               pcurr_tcb->tcb_hdr.cb_cmd = cpu_to_le16(txcommand);
+               pcurr_tcb->tcb_cnt = 0; 
+               pcurr_tcb->tcb_thrshld = bdp->tx_thld;  
+               if (ele_no < 2) {
+                       pcurr_tcb->tcb_hdr.cb_status =
+                               cpu_to_le16(CB_STATUS_COMPLETE);
+               }
+               pcurr_tcb->tcb_tbd_num = 1;
+
+               if (bdp->flags & IS_BACHELOR) {
+                       pcurr_tcb->tcb_tbd_ptr =
+                               __constant_cpu_to_le32(0xFFFFFFFF);
+               } else {
+                       pcurr_tcb->tcb_tbd_ptr =
+                               cpu_to_le32(pcurr_tcb->tcb_phys + 0x10);
+               }
+
+#ifdef E100_ZEROCOPY
+               if (bdp->flags & IS_BACHELOR) {
+                       pcurr_tcb->tcb_tbd_expand_ptr =
+                               cpu_to_le32(pcurr_tcb->tcb_phys + 0x20);
+               } else {
+                       pcurr_tcb->tcb_tbd_expand_ptr =
+                               cpu_to_le32(pcurr_tcb->tcb_phys + 0x10);
+               }
+               pcurr_tcb->tcb_tbd_dflt_ptr = pcurr_tcb->tcb_tbd_ptr;
+#endif
+
+               if (bdp->flags & USE_IPCB) {
+                       pcurr_tcb->tbd_ptr = &(pcurr_tcb->tcbu.tbd_array[1]);
+                       pcurr_tcb->tcbu.ipcb.ip_activation_high =
+                               IPCB_IP_ACTIVATION_DEFAULT;
+                       pcurr_tcb->tcbu.ipcb.vlan = 0;
+               } else {
+                       pcurr_tcb->tbd_ptr = &(pcurr_tcb->tcbu.tbd_array[0]);
+               }
+
+               pcurr_tcb->tcb_skb = NULL;
+       }
+
+       wmb();
+}
+
+/***************************************************************************/
+/***************************************************************************/
+/*       Memory Management Routines                                        */
+/***************************************************************************/
+
+/**
+ * e100_alloc_space - allocate private driver data
+ * @bdp: atapter's private data struct
+ *
+ * This routine allocates memory for the driver. Memory allocated is for the
+ * selftest and statistics structures.
+ *
+ * Returns:
+ *      0: if the operation was successful
+ *      %-ENOMEM: if memory allocation failed
+ */
+unsigned char __devinit
+e100_alloc_space(struct e100_private *bdp)
+{
+       unsigned long off;
+
+       /* allocate all the dma-able structures in one call:
+        * selftest results, adapter stats, and non-tx cb commands */
+       if (!(bdp->dma_able =
+             pci_alloc_consistent(bdp->pdev, sizeof (bd_dma_able_t),
+                                  &(bdp->dma_able_phys)))) {
+               goto err;
+       }
+
+       /* now assign the various pointers into the struct we've just allocated */
+       off = offsetof(bd_dma_able_t, selftest);
+
+       bdp->selftest = (self_test_t *) (bdp->dma_able + off);
+       bdp->selftest_phys = bdp->dma_able_phys + off;
+
+       off = offsetof(bd_dma_able_t, stats_counters);
+
+       bdp->stats_counters = (max_counters_t *) (bdp->dma_able + off);
+       bdp->stat_cnt_phys = bdp->dma_able_phys + off;
+
+       return 0;
+
+err:
+       printk(KERN_ERR
+              "%s - Failed to allocate memory\n", e100_short_driver_name);
+       return -ENOMEM;
+}
+
+/**
+ * e100_alloc_tcb_pool - allocate TCB circular list
+ * @bdp: atapter's private data struct
+ *
+ * This routine allocates memory for the circular list of transmit descriptors.
+ *
+ * Returns:
+ *       0: if allocation has failed.
+ *       1: Otherwise. 
+ */
+int
+e100_alloc_tcb_pool(struct e100_private *bdp)
+{
+       int stcb = sizeof (tcb_t) * bdp->params.TxDescriptors;
+
+       /* allocate space for the TCBs */
+       if (!(bdp->tcb_pool.data =
+             pci_alloc_consistent(bdp->pdev, stcb, &bdp->tcb_phys)))
+               return 0;
+
+       memset(bdp->tcb_pool.data, 0x00, stcb);
+
+       return 1;
+}
+
+void
+e100_free_tcb_pool(struct e100_private *bdp)
+{
+       pci_free_consistent(bdp->pdev,
+                           sizeof (tcb_t) * bdp->params.TxDescriptors,
+                           bdp->tcb_pool.data, bdp->tcb_phys);
+       bdp->tcb_phys = 0;
+}
+
+static void
+e100_dealloc_space(struct e100_private *bdp)
+{
+       if (bdp->dma_able) {
+               pci_free_consistent(bdp->pdev, sizeof (bd_dma_able_t),
+                                   bdp->dma_able, bdp->dma_able_phys);
+       }
+
+       bdp->selftest_phys = 0;
+       bdp->stat_cnt_phys = 0;
+       bdp->dma_able_phys = 0;
+       bdp->dma_able = 0;
+}
+
+static void
+e100_free_rfd_pool(struct e100_private *bdp)
+{
+       struct rx_list_elem *rx_struct;
+
+       while (!list_empty(&(bdp->active_rx_list))) {
+
+               rx_struct = list_entry(bdp->active_rx_list.next,
+                                      struct rx_list_elem, list_elem);
+               list_del(&(rx_struct->list_elem));
+               pci_unmap_single(bdp->pdev, rx_struct->dma_addr,
+                                sizeof (rfd_t), PCI_DMA_TODEVICE);
+               dev_kfree_skb(rx_struct->skb);
+               kfree(rx_struct);
+       }
+
+       while (!list_empty(&(bdp->rx_struct_pool))) {
+               rx_struct = list_entry(bdp->rx_struct_pool.next,
+                                      struct rx_list_elem, list_elem);
+               list_del(&(rx_struct->list_elem));
+               kfree(rx_struct);
+       }
+}
+
+/**
+ * e100_alloc_rfd_pool - allocate RFDs
+ * @bdp: atapter's private data struct
+ *
+ * Allocates initial pool of skb which holds both rfd and data,
+ * and return a pointer to the head of the list
+ */
+static int
+e100_alloc_rfd_pool(struct e100_private *bdp)
+{
+       struct rx_list_elem *rx_struct;
+       int i;
+
+       INIT_LIST_HEAD(&(bdp->active_rx_list));
+       INIT_LIST_HEAD(&(bdp->rx_struct_pool));
+       bdp->skb_req = bdp->params.RxDescriptors;
+       for (i = 0; i < bdp->skb_req; i++) {
+               rx_struct = kmalloc(sizeof (struct rx_list_elem), GFP_ATOMIC);
+               list_add(&(rx_struct->list_elem), &(bdp->rx_struct_pool));
+       }
+       e100_alloc_skbs(bdp);
+       return !list_empty(&(bdp->active_rx_list));
+
+}
+
+void
+e100_clear_pools(struct e100_private *bdp)
+{
+       bdp->last_tcb = NULL;
+       e100_free_rfd_pool(bdp);
+       e100_free_tcb_pool(bdp);
+}
+
+/*****************************************************************************/
+/*****************************************************************************/
+/*      Run Time Functions                                                   */
+/*****************************************************************************/
+
+/**
+ * e100_watchdog
+ * @dev: adapter's net_device struct
+ *
+ * This routine runs every 2 seconds and updates our statitics and link state,
+ * and refreshs txthld value.
+ */
+void
+e100_watchdog(struct net_device *dev)
+{
+       struct e100_private *bdp = dev->priv;
+
+       read_lock(&(bdp->isolate_lock));
+       if (bdp->driver_isolated) {
+               goto exit;
+       }
+       if (!netif_running(dev)) {
+               goto exit;
+       }
+       spin_lock_bh(&(bdp->mdi_access_lock));
+
+       /* check if link state has changed */
+       if (e100_phy_check(bdp)) {
+               if (netif_carrier_ok(dev)) {
+                       printk(KERN_ERR
+                              "e100: %s NIC Link is Up %d Mbps %s duplex\n",
+                              bdp->device->name, bdp->cur_line_speed,
+                              (bdp->cur_dplx_mode == HALF_DUPLEX) ?
+                              "Half" : "Full");
+
+                       e100_config_fc(bdp);
+                       e100_config(bdp);       
+
+               } else {
+                       printk(KERN_ERR "e100: %s NIC Link is Down\n",
+                              bdp->device->name);
+               }
+       }
+
+       // toggle the tx queue according to link status
+       // this also resolves a race condition between tx & non-cu cmd flows
+       if (netif_carrier_ok(dev)) {
+               if (netif_running(dev))
+                       netif_wake_queue(dev);
+       } else {
+               netif_stop_queue(dev);
+       }
+
+       rmb();
+
+       if (e100_update_stats(bdp)) {
+
+               /* Check if a change in the IFS parameter is needed,
+                  and configure the device accordingly */
+               if (bdp->params.b_params & PRM_IFS)
+                       e100_manage_adaptive_ifs(bdp);
+
+               /* Now adjust our dynamic tx threshold value */
+               e100_refresh_txthld(bdp);
+
+               /* Now if we are on a 557 and we havn't received any frames then we
+                * should issue a multicast command to reset the RU */
+               if (bdp->rev_id < D101A4_REV_ID) {
+                       if (!(bdp->stats_counters->basic_stats.rcv_gd_frames)) {
+                               e100_set_multi(dev);
+                       }
+               }
+
+               /* Update the statistics needed by the upper interface */
+               /* This should be the last statistic related command
+                * as it's async. now */
+               e100_dump_stats_cntrs(bdp);
+       }
+
+       wmb();
+
+       spin_unlock_bh(&(bdp->mdi_access_lock));
+
+       /* relaunch watchdog timer in 2 sec */
+       mod_timer(&(bdp->watchdog_timer), jiffies + (2 * HZ));
+
+       if (list_empty(&bdp->active_rx_list))
+               e100_trigger_SWI(bdp);
+
+exit:
+       read_unlock(&(bdp->isolate_lock));
+}
+
+/**
+ * e100_manage_adaptive_ifs
+ * @bdp: atapter's private data struct
+ *
+ * This routine manages the adaptive Inter-Frame Spacing algorithm
+ * using a state machine.
+ */
+void
+e100_manage_adaptive_ifs(struct e100_private *bdp)
+{
+       static u16 state_table[9][4] = {        // rows are states
+               {2, 0, 0, 0},   // state0   // column0: next state if increasing
+               {2, 0, 5, 30},  // state1   // column1: next state if decreasing
+               {5, 1, 5, 30},  // state2   // column2: IFS value for 100 mbit
+               {5, 3, 0, 0},   // state3   // column3: IFS value for 10 mbit
+               {5, 3, 10, 60}, // state4
+               {8, 4, 10, 60}, // state5
+               {8, 6, 0, 0},   // state6
+               {8, 6, 20, 60}, // state7
+               {8, 7, 20, 60}  // state8
+       };
+
+       u32 transmits =
+               le32_to_cpu(bdp->stats_counters->basic_stats.xmt_gd_frames);
+       u32 collisions =
+               le32_to_cpu(bdp->stats_counters->basic_stats.xmt_ttl_coll);
+       u32 state = bdp->ifs_state;
+       u32 old_value = bdp->ifs_value;
+       int next_col;
+       u32 min_transmits;
+
+       if (bdp->cur_dplx_mode == FULL_DUPLEX) {
+               bdp->ifs_state = 0;
+               bdp->ifs_value = 0;
+
+       } else {                /* Half Duplex */
+               /* Set speed specific parameters */
+               if (bdp->cur_line_speed == 100) {
+                       next_col = 2;
+                       min_transmits = MIN_NUMBER_OF_TRANSMITS_100;
+
+               } else {        /* 10 Mbps */
+                       next_col = 3;
+                       min_transmits = MIN_NUMBER_OF_TRANSMITS_10;
+               }
+
+               if ((transmits / 32 < collisions)
+                   && (transmits > min_transmits)) {
+                       state = state_table[state][0];  /* increment */
+
+               } else if (transmits < min_transmits) {
+                       state = state_table[state][1];  /* decrement */
+               }
+
+               bdp->ifs_value = state_table[state][next_col];
+               bdp->ifs_state = state;
+       }
+
+       /* If the IFS value has changed, configure the device */
+       if (bdp->ifs_value != old_value) {
+               e100_config_ifs(bdp);
+               e100_config(bdp);
+       }
+}
+
+void
+e100_polling_tasklet(unsigned long ptr)
+{
+       struct e100_private *bdp = (struct e100_private *) ptr;
+       unsigned int rx_congestion = 0;
+       u32 skb_cnt;
+
+       /* the device is closed, don't continue or else bad things may happen. */
+       if (!netif_running(bdp->device)) {
+               return;
+       }
+
+       read_lock(&(bdp->isolate_lock));
+       if (bdp->driver_isolated) {
+               tasklet_schedule(&(bdp->polling_tasklet));
+               goto exit;
+       }
+
+       e100_alloc_skbs(bdp);
+
+       skb_cnt = e100_rx_srv(bdp, bdp->params.PollingMaxWork, &rx_congestion);
+
+       bdp->drv_stats.rx_tasklet_pkts += skb_cnt;
+
+       if (rx_congestion || skb_cnt) {
+               tasklet_schedule(&(bdp->polling_tasklet));
+       } else {
+               bdp->intr_mask &= ~SCB_INT_MASK;
+
+               bdp->drv_stats.poll_intr_switch++;
+       }
+
+       bdp->tx_count = 0;      /* restart tx interrupt batch count */
+       e100_tx_srv(bdp);
+
+       e100_set_intr_mask(bdp);
+
+exit:
+       read_unlock(&(bdp->isolate_lock));
+}
+
+/**
+ * e100intr - interrupt handler
+ * @irq: the IRQ number
+ * @dev_inst: the net_device struct
+ * @regs: registers (unused)
+ *
+ * This routine is the ISR for the e100 board. It services
+ * the RX & TX queues & starts the RU if it has stopped due
+ * to no resources.
+ */
+void
+e100intr(int irq, void *dev_inst, struct pt_regs *regs)
+{
+       struct net_device *dev;
+       struct e100_private *bdp;
+       u16 intr_status;
+
+       dev = dev_inst;
+       bdp = dev->priv;
+
+       intr_status = readw(&bdp->scb->scb_status);
+       if (!intr_status || (intr_status == 0xffff)) {
+               return;
+       }
+
+       /* disable intr before we ack & after identifying the intr as ours */
+       e100_dis_intr(bdp);
+
+       writew(intr_status, &bdp->scb->scb_status);     /* ack intrs */
+
+       /* the device is closed, don't continue or else bad things may happen. */
+       if (!netif_running(dev)) {
+               e100_set_intr_mask(bdp);
+               return;
+       }
+
+       read_lock(&(bdp->isolate_lock));
+       if (bdp->driver_isolated) {
+               goto exit;
+       }
+
+       /* SWI intr (triggered by watchdog) is signal to allocate new skb buffers */
+       if (intr_status & SCB_STATUS_ACK_SWI) {
+               e100_alloc_skbs(bdp);
+       }
+
+       /* do recv work if any */
+       if (intr_status &
+           (SCB_STATUS_ACK_FR | SCB_STATUS_ACK_RNR | SCB_STATUS_ACK_SWI)) {
+               int rx_congestion;
+
+               bdp->drv_stats.rx_intr_pkts +=
+                       e100_rx_srv(bdp, 0, &rx_congestion);
+               if ((bdp->params.b_params & PRM_RX_CONG) && rx_congestion) {
+                       bdp->intr_mask |= SCB_INT_MASK;
+                       tasklet_schedule(&(bdp->polling_tasklet));
+
+                       bdp->drv_stats.poll_intr_switch++;
+               }
+       }
+
+       /* clean up after tx'ed packets */
+       if (intr_status & (SCB_STATUS_ACK_CNA | SCB_STATUS_ACK_CX)) {
+               bdp->tx_count = 0;      /* restart tx interrupt batch count */
+               e100_tx_srv(bdp);
+       }
+
+exit:
+       e100_set_intr_mask(bdp);
+       read_unlock(&(bdp->isolate_lock));
+}
+
+/**
+ * e100_tx_skb_free - free TX skbs resources
+ * @bdp: atapter's private data struct
+ * @tcb: associated tcb of the freed skb
+ *
+ * This routine frees resources of TX skbs.
+ */
+static void inline
+e100_tx_skb_free(struct e100_private *bdp, tcb_t *tcb)
+{
+       if (tcb->tcb_skb) {
+#ifdef E100_ZEROCOPY
+               int i;
+               tbd_t *tbd_arr = tcb->tbd_ptr;
+               int frags = skb_shinfo(tcb->tcb_skb)->nr_frags;
+
+               for (i = 0; i <= frags; i++, tbd_arr++) {
+                       pci_unmap_single(bdp->pdev,
+                                        le32_to_cpu(tbd_arr->tbd_buf_addr),
+                                        le16_to_cpu(tbd_arr->tbd_buf_cnt),
+                                        PCI_DMA_TODEVICE);
+               }
+#else
+               pci_unmap_single(bdp->pdev,
+                                le32_to_cpu((tcb->tbd_ptr)->tbd_buf_addr),
+                                tcb->tcb_skb->len, PCI_DMA_TODEVICE);
+#endif
+               dev_kfree_skb_irq(tcb->tcb_skb);
+               tcb->tcb_skb = NULL;
+       }
+}
+
+/**
+ * e100_tx_srv - service TX queues
+ * @bdp: atapter's private data struct
+ *
+ * This routine services the TX queues. It reclaims the TCB's & TBD's & other
+ * resources used during the transmit of this buffer. It is called from the ISR.
+ * We don't need a tx_lock since we always access buffers which were already
+ * prepared.
+ */
+void
+e100_tx_srv(struct e100_private *bdp)
+{
+       tcb_t *tcb;
+       int i;
+
+       /* go over at most TxDescriptors buffers */
+       for (i = 0; i < bdp->params.TxDescriptors; i++) {
+               tcb = bdp->tcb_pool.data;
+               tcb += bdp->tcb_pool.head;
+
+               rmb();
+
+               /* if the buffer at 'head' is not complete, break */
+               if (!(tcb->tcb_hdr.cb_status &
+                     __constant_cpu_to_le16(CB_STATUS_COMPLETE)))
+                       break;
+
+               /* service next buffer, clear the out of resource condition */
+               e100_tx_skb_free(bdp, tcb);
+
+               if (netif_running(bdp->device))
+                       netif_wake_queue(bdp->device);
+
+               /* if we've caught up with 'tail', break */
+               if (NEXT_TCB_TOUSE(bdp->tcb_pool.head) == bdp->tcb_pool.tail) {
+                       break;
+               }
+
+               bdp->tcb_pool.head = NEXT_TCB_TOUSE(bdp->tcb_pool.head);
+       }
+}
+
+/**
+ * e100_rx_srv - service RX queue
+ * @bdp: atapter's private data struct
+ * @max_number_of_rfds: max number of RFDs to process
+ * @rx_congestion: flag pointer, to inform the calling function of congestion.
+ *
+ * This routine processes the RX interrupt & services the RX queues.
+ * For each successful RFD, it allocates a new msg block, links that
+ * into the RFD list, and sends the old msg upstream.
+ * The new RFD is then put at the end of the free list of RFD's.
+ * It returns the number of serviced RFDs.
+ */
+u32
+e100_rx_srv(struct e100_private *bdp, u32 max_number_of_rfds,
+           int *rx_congestion)
+{
+       rfd_t *rfd;             /* new rfd, received rfd */
+       int i;
+       u16 rfd_status;
+       struct sk_buff *skb;
+       struct net_device *dev;
+       unsigned int data_sz;
+       struct rx_list_elem *rx_struct;
+       u32 rfd_cnt = 0;
+
+       if (rx_congestion) {
+               *rx_congestion = 0;
+       }
+
+       dev = bdp->device;
+
+       /* current design of rx is as following:
+        * 1. socket buffer (skb) used to pass network packet to upper layer
+        * 2. all HW host memory structures (like RFDs, RBDs and data buffers)
+        *    are placed in a skb's data room
+        * 3. when rx process is complete, we change skb internal pointers to exclude
+        *    from data area all unrelated things (RFD, RDB) and to leave
+        *    just rx'ed packet netto
+        * 4. for each skb passed to upper layer, new one is allocated instead.
+        * 5. if no skb left, in 2 sec another atempt to allocate skbs will be made
+        *    (watchdog trigger SWI intr and isr should allocate new skbs)
+        */
+       for (i = 0; i < bdp->params.RxDescriptors; i++) {
+               if (max_number_of_rfds && (rfd_cnt >= max_number_of_rfds)) {
+                       break;
+               }
+               if (list_empty(&(bdp->active_rx_list)))
+                       break;
+
+               rx_struct = list_entry(bdp->active_rx_list.next,
+                                      struct rx_list_elem, list_elem);
+               skb = rx_struct->skb;
+
+               rfd = RFD_POINTER(skb, bdp);    /* locate RFD within skb */
+
+               // sync only the RFD header
+               pci_dma_sync_single(bdp->pdev, rx_struct->dma_addr,
+                                   bdp->rfd_size, PCI_DMA_FROMDEVICE);
+               rfd_status = le16_to_cpu(rfd->rfd_header.cb_status);    /* get RFD's status */
+               if (!(rfd_status & RFD_STATUS_COMPLETE))        /* does not contains data yet - exit */
+                       break;
+
+               /* to allow manipulation with current skb we need to unlink it */
+               list_del(&(rx_struct->list_elem));
+
+               /* do not free & unmap badly recieved packet.
+                * move it to the end of skb list for reuse */
+               if (!(rfd_status & RFD_STATUS_OK)) {
+                       e100_add_skb_to_end(bdp, rx_struct);
+                       continue;
+               }
+
+               data_sz = min_t(u16, (le16_to_cpu(rfd->rfd_act_cnt) & 0x3fff),
+                               (sizeof (rfd_t) - bdp->rfd_size));
+
+               /* now sync all the data */
+               pci_dma_sync_single(bdp->pdev, rx_struct->dma_addr,
+                                   (data_sz + bdp->rfd_size),
+                                   PCI_DMA_FROMDEVICE);
+
+               // we unmap using DMA_TODEVICE to avoid another memcpy from the 
+               // bounce buffer
+               pci_unmap_single(bdp->pdev, rx_struct->dma_addr,
+                                sizeof (rfd_t), PCI_DMA_TODEVICE);
+
+               list_add(&(rx_struct->list_elem), &(bdp->rx_struct_pool));
+
+               /* end of dma access to rfd */
+               bdp->skb_req++; /* incr number of requested skbs */
+               e100_alloc_skbs(bdp);   /* and get them */
+
+               /* set packet size, excluding checksum (2 last bytes) if it is present */
+               if ((bdp->flags & DF_CSUM_OFFLOAD)
+                   && (bdp->rev_id < D102_REV_ID))
+                       skb_put(skb, (int) data_sz - 2);
+               else
+                       skb_put(skb, (int) data_sz);
+
+               /* set the protocol */
+               skb->protocol = eth_type_trans(skb, dev);
+
+               /* set the checksum info */
+               if (bdp->flags & DF_CSUM_OFFLOAD) {
+                       if (bdp->rev_id >= D102_REV_ID) {
+                               skb->ip_summed = e100_D102_check_checksum(rfd);
+                       } else {
+                               skb->ip_summed = e100_D101M_checksum(bdp, skb);
+                       }
+               } else {
+                       skb->ip_summed = CHECKSUM_NONE;
+               }
+
+               switch (netif_rx(skb)) {
+               case NET_RX_BAD:
+                       break;
+
+               case NET_RX_DROP:
+               case NET_RX_CN_MOD:
+               case NET_RX_CN_HIGH:
+                       if (bdp->params.b_params & PRM_RX_CONG) {
+                               if (rx_congestion) {
+                                       *rx_congestion = 1;
+                               }
+                       }
+                       /* FALL THROUGH TO STATISTICS UPDATE */
+               default:
+                       bdp->drv_stats.net_stats.rx_bytes += skb->len;
+                       break;
+               }
+
+               rfd_cnt++;
+       }                       /* end of rfd loop */
+
+       /* restart the RU if it has stopped */
+       if ((readw(&bdp->scb->scb_status) & SCB_RUS_MASK) != SCB_RUS_READY) {
+               e100_start_ru(bdp);
+       }
+
+       return rfd_cnt;
+}
+
+void
+e100_refresh_txthld(struct e100_private *bdp)
+{
+       basic_cntr_t *pstat = &(bdp->stats_counters->basic_stats);
+
+       /* as long as tx_per_underrun is not 0, we can go about dynamically *
+        * adjusting the xmit threshold. we stop doing that & resort to defaults
+        * * once the adjustments become meaningless. the value is adjusted by *
+        * dumping the error counters & checking the # of xmit underrun errors *
+        * we've had. */
+       if (bdp->tx_per_underrun) {
+               /* We are going to last values dumped from the dump statistics
+                * command */
+               if (le32_to_cpu(pstat->xmt_gd_frames)) {
+                       if (le32_to_cpu(pstat->xmt_uruns)) {
+                               /* 
+                                * if we have had more than one underrun per "DEFAULT #
+                                * OF XMITS ALLOWED PER UNDERRUN" good xmits, raise the
+                                * THRESHOLD.
+                                */
+                               if ((le32_to_cpu(pstat->xmt_gd_frames) /
+                                    le32_to_cpu(pstat->xmt_uruns)) <
+                                   bdp->tx_per_underrun) {
+                                       bdp->tx_thld += 3;
+                               }
+                       }
+
+                       /* 
+                        * if we've had less than one underrun per the DEFAULT number of
+                        * of good xmits allowed, lower the THOLD but not less than 0 
+                        */
+                       if (le32_to_cpu(pstat->xmt_gd_frames) >
+                           bdp->tx_per_underrun) {
+                               bdp->tx_thld--;
+
+                               if (bdp->tx_thld < 6)
+                                       bdp->tx_thld = 6;
+
+                       }
+               }
+
+               /* end good xmits */
+               /* 
+                * * if our adjustments are becoming unresonable, stop adjusting &
+                * resort * to defaults & pray. A THOLD value > 190 means that the
+                * adapter will * wait for 190*8=1520 bytes in TX FIFO before it
+                * starts xmit. Since * MTU is 1514, it doesn't make any sense for
+                * further increase. */
+               if (bdp->tx_thld >= 190) {
+                       bdp->tx_per_underrun = 0;
+                       bdp->tx_thld = 189;
+               }
+       }                       /* end underrun check */
+}
+
+/**
+ * e100_prepare_xmit_buff - prepare a buffer for transmission
+ * @bdp: atapter's private data struct
+ * @skb: skb to send
+ *
+ * This routine prepare a buffer for transmission. It checks
+ * the message length for the appropiate size. It picks up a
+ * free tcb from the TCB pool and sets up the corresponding
+ * TBD's. If the number of fragments are more than the number
+ * of TBD/TCB it copies all the fragments in a coalesce buffer.
+ * It returns a pointer to the prepared TCB.
+ */
+static inline tcb_t *
+e100_prepare_xmit_buff(struct e100_private *bdp, struct sk_buff *skb)
+{
+       tcb_t *tcb, *prev_tcb;
+
+       tcb = bdp->tcb_pool.data;
+       tcb += TCB_TO_USE(bdp->tcb_pool);
+
+       tcb->tcb_hdr.cb_status = 0;
+       tcb->tcb_thrshld = bdp->tx_thld;
+       tcb->tcb_hdr.cb_cmd |= __constant_cpu_to_le16(CB_S_BIT);
+
+       /* set the I bit on the modulo tcbs, so we will get an interrupt * to
+        * clean things up */
+       if (!(++bdp->tx_count % TX_FRAME_CNT)) {
+               tcb->tcb_hdr.cb_cmd |= __constant_cpu_to_le16(CB_I_BIT);
+       }
+
+       tcb->tcb_skb = skb;
+
+#ifdef E100_ZEROCOPY
+       if (skb->ip_summed == CHECKSUM_HW) {
+               const struct iphdr *ip = skb->nh.iph;
+
+               if ((ip->protocol == IPPROTO_TCP) ||
+                   (ip->protocol == IPPROTO_UDP)) {
+                       u16 *chksum;
+
+                       tcb->tcbu.ipcb.ip_activation_high =
+                               IPCB_HARDWAREPARSING_ENABLE;
+                       tcb->tcbu.ipcb.ip_schedule |=
+                               IPCB_TCPUDP_CHECKSUM_ENABLE;
+
+                       if (ip->protocol == IPPROTO_TCP) {
+                               struct tcphdr *tcp;
+
+                               tcp = (struct tcphdr *) ((u32 *) ip + ip->ihl);
+                               chksum = &(tcp->check);
+                               tcb->tcbu.ipcb.ip_schedule |= IPCB_TCP_PACKET;
+                       } else {
+                               struct udphdr *udp;
+
+                               udp = (struct udphdr *) ((u32 *) ip + ip->ihl);
+                               chksum = &(udp->check);
+                       }
+
+                       *chksum = csum_tcpudp_magic(ip->daddr, ip->saddr,
+                                                   sizeof (struct tcphdr),
+                                                   ip->protocol, 0);
+               }
+       } else {
+               if (bdp->flags & USE_IPCB) {
+                       tcb->tcbu.ipcb.ip_activation_high =
+                               IPCB_IP_ACTIVATION_DEFAULT;
+                       tcb->tcbu.ipcb.ip_schedule &= ~IPCB_TCP_PACKET;
+                       tcb->tcbu.ipcb.ip_schedule &=
+                               ~IPCB_TCPUDP_CHECKSUM_ENABLE;
+               }
+       }
+
+       if (!skb_shinfo(skb)->nr_frags) {
+               (tcb->tbd_ptr)->tbd_buf_addr =
+                       cpu_to_le32(pci_map_single(bdp->pdev, skb->data,
+                                                  skb->len, PCI_DMA_TODEVICE));
+               (tcb->tbd_ptr)->tbd_buf_cnt = cpu_to_le16(skb->len);
+               tcb->tcb_tbd_num = 1;
+               tcb->tcb_tbd_ptr = tcb->tcb_tbd_dflt_ptr;
+       } else {
+               int i;
+               void *addr;
+               tbd_t *tbd_arr_ptr = &(tcb->tbd_ptr[1]);
+               skb_frag_t *frag = &skb_shinfo(skb)->frags[0];
+
+               (tcb->tbd_ptr)->tbd_buf_addr =
+                       cpu_to_le32(pci_map_single(bdp->pdev, skb->data,
+                                                  (skb->len - skb->data_len),
+                                                  PCI_DMA_TODEVICE));
+               (tcb->tbd_ptr)->tbd_buf_cnt =
+                       cpu_to_le16(skb->len - skb->data_len);
+
+               for (i = 0; i < skb_shinfo(skb)->nr_frags;
+                    i++, tbd_arr_ptr++, frag++) {
+
+                       addr = ((void *) page_address(frag->page) +
+                               frag->page_offset);
+
+                       tbd_arr_ptr->tbd_buf_addr =
+                               cpu_to_le32(pci_map_single(bdp->pdev,
+                                                          addr, frag->size,
+                                                          PCI_DMA_TODEVICE));
+                       tbd_arr_ptr->tbd_buf_cnt = cpu_to_le16(frag->size);
+               }
+               tcb->tcb_tbd_num = skb_shinfo(skb)->nr_frags + 1;
+               tcb->tcb_tbd_ptr = tcb->tcb_tbd_expand_ptr;
+       }
+#else
+       (tcb->tbd_ptr)->tbd_buf_addr =
+               cpu_to_le32(pci_map_single(bdp->pdev, skb->data,
+                                          skb->len, PCI_DMA_TODEVICE));
+       (tcb->tbd_ptr)->tbd_buf_cnt = cpu_to_le16(skb->len);
+#endif
+
+       /* clear the S-BIT on the previous tcb */
+       prev_tcb = bdp->tcb_pool.data;
+       prev_tcb += PREV_TCB_USED(bdp->tcb_pool);
+       prev_tcb->tcb_hdr.cb_cmd &= __constant_cpu_to_le16((u16) ~CB_S_BIT);
+
+       bdp->tcb_pool.tail = NEXT_TCB_TOUSE(bdp->tcb_pool.tail);
+
+       wmb();
+
+       e100_start_cu(bdp, tcb);
+
+       return tcb;
+}
+
+/* Changed for 82558 enhancement */
+/**
+ * e100_start_cu - start the adapter's CU
+ * @bdp: atapter's private data struct
+ * @tcb: TCB to be transmitted
+ *
+ * This routine issues a CU Start or CU Resume command to the 82558/9.
+ * This routine was added because the prepare_ext_xmit_buff takes advantage
+ * of the 82558/9's Dynamic TBD chaining feature and has to start the CU as
+ * soon as the first TBD is ready. 
+ *
+ * e100_start_cu must be called while holding the tx_lock ! 
+ */
+void
+e100_start_cu(struct e100_private *bdp, tcb_t *tcb)
+{
+       unsigned long lock_flag;
+
+       spin_lock_irqsave(&(bdp->bd_lock), lock_flag);
+       switch (bdp->next_cu_cmd) {
+       case RESUME_NO_WAIT:
+               /*last cu command was a CU_RESMUE if this is a 558 or newer we dont need to
+                * wait for command word to clear, we reach here only if we are bachlor
+                */
+               e100_exec_cmd(bdp, SCB_CUC_RESUME);
+               break;
+
+       case RESUME_WAIT:
+               if ((bdp->flags & IS_ICH) &&
+                   (bdp->cur_line_speed == 10) &&
+                   (bdp->cur_dplx_mode == HALF_DUPLEX)) {
+                       e100_wait_exec_simple(bdp, SCB_CUC_NOOP);
+                       udelay(1);
+               }
+               if ((e100_wait_exec_simple(bdp, SCB_CUC_RESUME)) &&
+                   (bdp->flags & IS_BACHELOR) && (!(bdp->flags & IS_ICH))) {
+                       bdp->next_cu_cmd = RESUME_NO_WAIT;
+               }
+               break;
+
+       case START_WAIT:
+               // The last command was a non_tx CU command
+               if (!e100_wait_cus_idle(bdp))
+                       printk("%s cu_start: timeout waiting for cu\n",
+                              bdp->device->name);
+
+               if (!e100_wait_exec_cmplx(bdp, (u32) (tcb->tcb_phys),
+                                        SCB_CUC_START)) {
+                       printk("%s cu_start: timeout waiting for scb\n",
+                              bdp->device->name);
+                       e100_exec_cmplx(bdp, (u32) (tcb->tcb_phys),
+                                       SCB_CUC_START);
+               }
+
+               bdp->next_cu_cmd = RESUME_WAIT;
+
+               break;
+       }
+
+       /* save the last tcb */
+       bdp->last_tcb = tcb;
+
+       spin_unlock_irqrestore(&(bdp->bd_lock), lock_flag);
+}
+
+/* ====================================================================== */
+/* hw                                                                     */
+/* ====================================================================== */
+
+/**
+ * e100_selftest - perform H/W self test
+ * @bdp: atapter's private data struct
+ * @st_timeout: address to return timeout value, if fails
+ * @st_result: address to return selftest result, if fails
+ *
+ * This routine will issue PORT Self-test command to test the e100.
+ * The self-test will fail if the adapter's master-enable bit is not
+ * set in the PCI Command Register, or if the adapter is not seated
+ * in a PCI master-enabled slot. we also disable interrupts when the
+ * command is completed.
+ *
+ * Returns:
+ *      true: if adapter passes self_test
+ *      false: otherwise
+ */
+unsigned char
+e100_selftest(struct e100_private *bdp, u32 *st_timeout, u32 *st_result)
+{
+       u32 selftest_cmd;
+
+       /* initialize the nic state before running test */
+       e100_sw_reset(bdp, PORT_SOFTWARE_RESET);
+       /* Setup the address of the self_test area */
+       selftest_cmd = bdp->selftest_phys;
+
+       /* Setup SELF TEST Command Code in D3 - D0 */
+       selftest_cmd |= PORT_SELFTEST;
+
+       /* Initialize the self-test signature and results DWORDS */
+       bdp->selftest->st_sign = 0;
+       bdp->selftest->st_result = 0xffffffff;
+
+       /* Do the port command */
+       writel(selftest_cmd, &bdp->scb->scb_port);
+
+       /* Wait at least 10 milliseconds for the self-test to complete */
+       set_current_state(TASK_UNINTERRUPTIBLE);
+       schedule_timeout(HZ / 100 + 1);
+
+       /* disable interrupts since the're now enabled */
+       e100_dis_intr(bdp);
+
+       rmb();
+
+       /* if The First Self Test DWORD Still Zero, We've timed out. If the
+        * second DWORD is not zero then we have an error. */
+       if ((bdp->selftest->st_sign == 0) || (bdp->selftest->st_result != 0)) {
+
+               if (st_timeout)
+                       *st_timeout = !(le32_to_cpu(bdp->selftest->st_sign));
+
+               if (st_result)
+                       *st_result = le32_to_cpu(bdp->selftest->st_result);
+
+               return false;
+       }
+
+       return true;
+}
+
+/**
+ * e100_setup_iaaddr - issue IA setup sommand
+ * @bdp: atapter's private data struct
+ * @eaddr: new ethernet address
+ *
+ * This routine will issue the IA setup command. This command
+ * will notify the 82557 (e100) of what its individual (node)
+ * address is. This command will be executed in polled mode.
+ *
+ * Returns:
+ *      true: if the IA setup command was successfully issued and completed
+ *      false: otherwise
+ */
+unsigned char
+e100_setup_iaaddr(struct e100_private *bdp, u8 *eaddr)
+{
+       unsigned int i;
+       cb_header_t *ntcb_hdr;
+       unsigned char res;
+       nxmit_cb_entry_t *cmd;
+
+       if ((cmd = e100_alloc_non_tx_cmd(bdp)) == NULL) {
+               res = false;
+               goto exit;
+       }
+
+       ntcb_hdr = (cb_header_t *) cmd->non_tx_cmd;
+       ntcb_hdr->cb_cmd = __constant_cpu_to_le16(CB_IA_ADDRESS);
+
+       for (i = 0; i < ETH_ALEN; i++) {
+               (cmd->non_tx_cmd)->ntcb.setup.ia_addr[i] = eaddr[i];
+       }
+
+       res = e100_exec_non_cu_cmd(bdp, cmd);
+       if (!res)
+               printk(KERN_WARNING "%s IA setup failed\n", bdp->device->name);
+
+exit:
+       return res;
+}
+
+/**
+ * e100_start_ru - start the RU if needed
+ * @bdp: atapter's private data struct
+ *
+ * This routine checks the status of the 82557's receive unit(RU),
+ * and starts the RU if it was not already active.  However,
+ * before restarting the RU, the driver gives the RU the buffers
+ * it freed up during the servicing of the ISR. If there are
+ * no free buffers to give to the RU, (i.e. we have reached a
+ * no resource condition) the RU will not be started till the
+ * next ISR.
+ */
+void
+e100_start_ru(struct e100_private *bdp)
+{
+       struct rx_list_elem *rx_struct = NULL;
+       int buffer_found = 0;
+       struct list_head *entry_ptr;
+
+       list_for_each(entry_ptr, &(bdp->active_rx_list)) {
+               rx_struct =
+                       list_entry(entry_ptr, struct rx_list_elem, list_elem);
+               pci_dma_sync_single(bdp->pdev, rx_struct->dma_addr,
+                                   bdp->rfd_size, PCI_DMA_FROMDEVICE);
+               if (!((SKB_RFD_STATUS(rx_struct->skb, bdp) &
+                      __constant_cpu_to_le16(RFD_STATUS_COMPLETE)))) {
+                       buffer_found = 1;
+                       break;
+               }
+       }
+
+       /* No available buffers */
+       if (!buffer_found) {
+               return;
+       }
+
+       spin_lock(&bdp->bd_lock);
+
+       if (!e100_wait_exec_cmplx(bdp, rx_struct->dma_addr, SCB_RUC_START)) {
+               printk("%s start_ru: wait_scb failed\n", bdp->device->name);
+               e100_exec_cmplx(bdp, rx_struct->dma_addr, SCB_RUC_START);
+       }
+       if (bdp->next_cu_cmd == RESUME_NO_WAIT) {
+               bdp->next_cu_cmd = RESUME_WAIT;
+       }
+       spin_unlock(&bdp->bd_lock);
+}
+
+/**
+ * e100_cmd_complete_location
+ * @bdp: atapter's private data struct
+ *
+ * This routine returns a pointer to the location of the command-complete
+ * DWord in the dump statistical counters area, according to the statistical
+ * counters mode (557 - basic, 558 - extended, or 559 - TCO mode).
+ * See e100_config_init() for the setting of the statistical counters mode.
+ */
+static u32 *
+e100_cmd_complete_location(struct e100_private *bdp)
+{
+       u32 *cmd_complete;
+       max_counters_t *stats = bdp->stats_counters;
+
+       switch (bdp->stat_mode) {
+       case E100_EXTENDED_STATS:
+               cmd_complete =
+                       (u32 *) &(((err_cntr_558_t *) (stats))->cmd_complete);
+               break;
+
+       case E100_TCO_STATS:
+               cmd_complete =
+                       (u32 *) &(((err_cntr_559_t *) (stats))->cmd_complete);
+               break;
+
+       case E100_BASIC_STATS:
+       default:                
+               cmd_complete =
+                       (u32 *) &(((err_cntr_557_t *) (stats))->cmd_complete);
+               break;
+       }
+
+       return cmd_complete;
+}
+
+/**
+ * e100_clr_cntrs - clear statistics counters
+ * @bdp: atapter's private data struct
+ *
+ * This routine will clear the adapter error statistic counters.
+ *
+ * Returns:
+ *      true: if successfully cleared stat counters
+ *      false: otherwise
+ */
+static unsigned char __devinit
+e100_clr_cntrs(struct e100_private *bdp)
+{
+       volatile u32 *pcmd_complete;
+
+       /* clear the dump counter complete word */
+       pcmd_complete = e100_cmd_complete_location(bdp);
+       *pcmd_complete = 0;
+       wmb();
+
+       if (!e100_wait_exec_cmplx(bdp, bdp->stat_cnt_phys, SCB_CUC_DUMP_ADDR))
+               return false;
+
+       /* wait 10 microseconds for the command to complete */
+       udelay(10);
+
+       if (!e100_wait_exec_simple(bdp, SCB_CUC_DUMP_RST_STAT))
+               return false;
+
+       if (bdp->next_cu_cmd == RESUME_NO_WAIT) {
+               bdp->next_cu_cmd = RESUME_WAIT;
+       }
+
+       return true;
+}
+
+static unsigned char
+e100_update_stats(struct e100_private *bdp)
+{
+       u32 *pcmd_complete;
+       basic_cntr_t *pstat = &(bdp->stats_counters->basic_stats);
+
+       // check if last dump command completed
+       pcmd_complete = e100_cmd_complete_location(bdp);
+       if (*pcmd_complete != le32_to_cpu(DUMP_RST_STAT_COMPLETED) &&
+           *pcmd_complete != le32_to_cpu(DUMP_STAT_COMPLETED)) {
+               return false;
+       }
+
+       /* increment the statistics */
+       bdp->drv_stats.net_stats.rx_packets +=
+               le32_to_cpu(pstat->rcv_gd_frames);
+       bdp->drv_stats.net_stats.tx_packets +=
+               le32_to_cpu(pstat->xmt_gd_frames);
+       bdp->drv_stats.net_stats.rx_dropped += le32_to_cpu(pstat->rcv_rsrc_err);
+       bdp->drv_stats.net_stats.collisions += le32_to_cpu(pstat->xmt_ttl_coll);
+       bdp->drv_stats.net_stats.rx_length_errors +=
+               le32_to_cpu(pstat->rcv_shrt_frames);
+       bdp->drv_stats.net_stats.rx_over_errors +=
+               le32_to_cpu(pstat->rcv_rsrc_err);
+       bdp->drv_stats.net_stats.rx_crc_errors +=
+               le32_to_cpu(pstat->rcv_crc_errs);
+       bdp->drv_stats.net_stats.rx_frame_errors +=
+               le32_to_cpu(pstat->rcv_algn_errs);
+       bdp->drv_stats.net_stats.rx_fifo_errors +=
+               le32_to_cpu(pstat->rcv_oruns);
+       bdp->drv_stats.net_stats.tx_aborted_errors +=
+               le32_to_cpu(pstat->xmt_max_coll);
+       bdp->drv_stats.net_stats.tx_carrier_errors +=
+               le32_to_cpu(pstat->xmt_lost_crs);
+       bdp->drv_stats.net_stats.tx_fifo_errors +=
+               le32_to_cpu(pstat->xmt_uruns);
+
+       bdp->drv_stats.tx_late_col += le32_to_cpu(pstat->xmt_late_coll);
+       bdp->drv_stats.tx_ok_defrd += le32_to_cpu(pstat->xmt_deferred);
+       bdp->drv_stats.tx_one_retry += le32_to_cpu(pstat->xmt_sngl_coll);
+       bdp->drv_stats.tx_mt_one_retry += le32_to_cpu(pstat->xmt_mlt_coll);
+       bdp->drv_stats.rcv_cdt_frames += le32_to_cpu(pstat->rcv_err_coll);
+
+       if (bdp->stat_mode != E100_BASIC_STATS) {
+               ext_cntr_t *pex_stat = &bdp->stats_counters->extended_stats;
+
+               bdp->drv_stats.xmt_fc_pkts +=
+                       le32_to_cpu(pex_stat->xmt_fc_frames);
+               bdp->drv_stats.rcv_fc_pkts +=
+                       le32_to_cpu(pex_stat->rcv_fc_frames);
+               bdp->drv_stats.rcv_fc_unsupported +=
+                       le32_to_cpu(pex_stat->rcv_fc_unsupported);
+       }
+
+       if (bdp->stat_mode == E100_TCO_STATS) {
+               tco_cntr_t *ptco_stat = &bdp->stats_counters->tco_stats;
+
+               bdp->drv_stats.xmt_tco_pkts +=
+                       le16_to_cpu(ptco_stat->xmt_tco_frames);
+               bdp->drv_stats.rcv_tco_pkts +=
+                       le16_to_cpu(ptco_stat->rcv_tco_frames);
+       }
+
+       *pcmd_complete = 0;
+       return true;
+}
+
+/**
+ * e100_dump_stat_cntrs
+ * @bdp: atapter's private data struct
+ *
+ * This routine will dump the board statistical counters without waiting
+ * for stat_dump to complete. Any access to this stats should verify the completion
+ * of the command
+ */
+void
+e100_dump_stats_cntrs(struct e100_private *bdp)
+{
+       unsigned long lock_flag_bd;
+
+       spin_lock_irqsave(&(bdp->bd_lock), lock_flag_bd);
+
+       /* dump h/w stats counters */
+       if (e100_wait_exec_simple(bdp, SCB_CUC_DUMP_RST_STAT)) {
+               if (bdp->next_cu_cmd == RESUME_NO_WAIT) {
+                       bdp->next_cu_cmd = RESUME_WAIT;
+               }
+       }
+
+       spin_unlock_irqrestore(&(bdp->bd_lock), lock_flag_bd);
+}
+
+/**
+ * e100_exec_non_cu_cmd
+ * @bdp: atapter's private data struct
+ * @command: the non-cu command to execute
+ *
+ * This routine will submit a command block to be executed,
+ */
+unsigned char
+e100_exec_non_cu_cmd(struct e100_private *bdp, nxmit_cb_entry_t *command)
+{
+       cb_header_t *ntcb_hdr;
+       unsigned long lock_flag;
+       unsigned long expiration_time;
+       unsigned char rc = false;
+
+       ntcb_hdr = (cb_header_t *) command->non_tx_cmd; /* get hdr of non tcb cmd */
+
+       /* Set the Command Block to be the last command block */
+       ntcb_hdr->cb_cmd |= __constant_cpu_to_le16(CB_EL_BIT);
+       ntcb_hdr->cb_status = 0;
+       ntcb_hdr->cb_lnk_ptr = 0;
+
+       wmb();
+
+       if (in_interrupt())
+               return e100_delayed_exec_non_cu_cmd(bdp, command);
+
+       spin_lock_bh(&(bdp->bd_non_tx_lock));
+
+       if (bdp->non_tx_command_state != E100_NON_TX_IDLE) {
+               goto delayed_exec;
+       }
+
+       if (bdp->last_tcb) {
+               rmb();
+               if ((bdp->last_tcb->tcb_hdr.cb_status &
+                    __constant_cpu_to_le16(CB_STATUS_COMPLETE)) == 0)
+                       goto delayed_exec;
+       }
+
+       if ((readw(&bdp->scb->scb_status) & SCB_CUS_MASK) == SCB_CUS_ACTIVE) {
+               goto delayed_exec;
+       }
+
+       spin_lock_irqsave(&bdp->bd_lock, lock_flag);
+
+       if (!e100_wait_exec_cmplx(bdp, command->dma_addr, SCB_CUC_START)) {
+               spin_unlock_irqrestore(&(bdp->bd_lock), lock_flag);
+               goto exit;
+       }
+
+       bdp->next_cu_cmd = START_WAIT;
+       spin_unlock_irqrestore(&(bdp->bd_lock), lock_flag);
+
+       /* now wait for completion of non-cu CB up to 20 msec*/
+       expiration_time = jiffies + HZ / 50 + 1;
+       while (time_before(jiffies, expiration_time)) {
+               rmb();
+               if ((ntcb_hdr->cb_status &
+                    __constant_cpu_to_le16(CB_STATUS_COMPLETE))) {
+                       rc = true;
+                       goto exit;
+               }
+               spin_unlock_bh(&(bdp->bd_non_tx_lock));
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               schedule_timeout(1);
+               spin_lock_bh(&(bdp->bd_non_tx_lock));
+       }
+
+       /* didn't get a C bit assume command failed */
+exit:
+       e100_free_non_tx_cmd(bdp, command);
+
+       if (netif_running(bdp->device))
+               netif_wake_queue(bdp->device);
+
+       spin_unlock_bh(&(bdp->bd_non_tx_lock));
+       return rc;
+
+delayed_exec:
+       spin_unlock_bh(&(bdp->bd_non_tx_lock));
+       return e100_delayed_exec_non_cu_cmd(bdp, command);
+}
+
+/**
+ * e100_sw_reset
+ * @bdp: atapter's private data struct
+ * @reset_cmd: s/w reset or selective reset
+ *
+ * This routine will issue a software reset to the adapter. It 
+ * will also disable interrupts, as the are enabled after reset.
+ */
+void
+e100_sw_reset(struct e100_private *bdp, u32 reset_cmd)
+{
+       /* Do  a selective reset first to avoid a potential PCI hang */
+       writel(PORT_SELECTIVE_RESET, &bdp->scb->scb_port);
+
+       /* wait for the reset to take effect */
+       udelay(20);
+       if (reset_cmd == PORT_SOFTWARE_RESET) {
+               writel(PORT_SOFTWARE_RESET, &bdp->scb->scb_port);
+
+               /* wait 20 micro seconds for the reset to take effect */
+               udelay(20);
+       }
+
+       /* Mask off our interrupt line -- its unmasked after reset */
+       e100_dis_intr(bdp);
+}
+
+/**
+ * e100_load_microcode - Download microsocde to controller.
+ * @bdp: atapter's private data struct
+ *
+ * This routine downloads microcode on to the controller. This
+ * microcode is available for the 82558/9, 82550. Currently the
+ * microcode handles interrupt bundling and TCO workaround.
+ *
+ * Returns:
+ *      true: if successfull
+ *      false: otherwise
+ */
+static unsigned char
+e100_load_microcode(struct e100_private *bdp)
+{
+       static struct {
+               u8 rev_id;
+               u32 ucode[UCODE_MAX_DWORDS + 1];
+               int timer_dword;
+               int bundle_dword;
+               int min_size_dword;
+       } ucode_opts[] = {
+               { D101A4_REV_ID,
+                 D101_A_RCVBUNDLE_UCODE,
+                 D101_CPUSAVER_TIMER_DWORD,
+                 D101_CPUSAVER_BUNDLE_DWORD,
+                 D101_CPUSAVER_MIN_SIZE_DWORD },
+               { D101B0_REV_ID,
+                 D101_B0_RCVBUNDLE_UCODE,
+                 D101_CPUSAVER_TIMER_DWORD,
+                 D101_CPUSAVER_BUNDLE_DWORD,
+                 D101_CPUSAVER_MIN_SIZE_DWORD },
+               { D101MA_REV_ID,
+                 D101M_B_RCVBUNDLE_UCODE,
+                 D101M_CPUSAVER_TIMER_DWORD,
+                 D101M_CPUSAVER_BUNDLE_DWORD,
+                 D101M_CPUSAVER_MIN_SIZE_DWORD },
+               { D101S_REV_ID,
+                 D101S_RCVBUNDLE_UCODE,
+                 D101S_CPUSAVER_TIMER_DWORD,
+                 D101S_CPUSAVER_BUNDLE_DWORD,
+                 D101S_CPUSAVER_MIN_SIZE_DWORD },
+               { D102_REV_ID,
+                 D102_B_RCVBUNDLE_UCODE,
+                 D102_B_CPUSAVER_TIMER_DWORD,
+                 D102_B_CPUSAVER_BUNDLE_DWORD,
+                 D102_B_CPUSAVER_MIN_SIZE_DWORD },
+               { D102C_REV_ID,
+                 D102_C_RCVBUNDLE_UCODE,
+                 D102_C_CPUSAVER_TIMER_DWORD,
+                 D102_C_CPUSAVER_BUNDLE_DWORD,
+                 D102_C_CPUSAVER_MIN_SIZE_DWORD },
+               { D102E_REV_ID,
+                 D102_E_RCVBUNDLE_UCODE,
+                 D102_E_CPUSAVER_TIMER_DWORD,
+                 D102_E_CPUSAVER_BUNDLE_DWORD,
+                 D102_E_CPUSAVER_MIN_SIZE_DWORD },
+               { 0, {0}, 0, 0, 0}
+       }, *opts;
+
+       opts = ucode_opts;
+
+       /* User turned ucode loading off */
+       if (!(bdp->params.b_params & PRM_UCODE))
+               return false;
+
+       /* These controllers do not need ucode */
+       if (bdp->flags & IS_ICH)
+               return false;
+
+       /* Search for ucode match against h/w rev_id */
+       while (opts->rev_id) {
+               if (bdp->rev_id == opts->rev_id) {
+                       int i;
+                       u32 *ucode_dword;
+                       load_ucode_cb_t *ucode_cmd_ptr;
+                       nxmit_cb_entry_t *cmd = e100_alloc_non_tx_cmd(bdp);
+
+                       if (cmd != NULL) {
+                               ucode_cmd_ptr =
+                                       (load_ucode_cb_t *) cmd->non_tx_cmd;
+                               ucode_dword = ucode_cmd_ptr->ucode_dword;
+                       } else {
+                               return false;
+                       }
+
+                       memcpy(ucode_dword, opts->ucode, sizeof (opts->ucode));
+
+                       /* Insert user-tunable settings */
+                       ucode_dword[opts->timer_dword] &= 0xFFFF0000;
+                       ucode_dword[opts->timer_dword] |=
+                               (u16) bdp->params.IntDelay;
+                       ucode_dword[opts->bundle_dword] &= 0xFFFF0000;
+                       ucode_dword[opts->bundle_dword] |=
+                               (u16) bdp->params.BundleMax;
+                       ucode_dword[opts->min_size_dword] &= 0xFFFF0000;
+                       ucode_dword[opts->min_size_dword] |=
+                               (bdp->params.b_params & PRM_BUNDLE_SMALL) ?
+                               0xFFFF : 0xFF80;
+
+                       for (i = 0; i < UCODE_MAX_DWORDS; i++)
+                               cpu_to_le32s(&(ucode_dword[i]));
+
+                       ucode_cmd_ptr->load_ucode_cbhdr.cb_cmd =
+                               __constant_cpu_to_le16(CB_LOAD_MICROCODE);
+
+                       return e100_exec_non_cu_cmd(bdp, cmd);
+               }
+               opts++;
+       }
+
+       return false;
+}
+
+/***************************************************************************/
+/***************************************************************************/
+/*       EEPROM  Functions                                                 */
+/***************************************************************************/
+
+/* Read PWA (printed wired assembly) number */
+void __devinit
+e100_rd_pwa_no(struct e100_private *bdp)
+{
+       bdp->pwa_no = e100_eeprom_read(bdp, EEPROM_PWA_NO);
+       bdp->pwa_no <<= 16;
+       bdp->pwa_no |= e100_eeprom_read(bdp, EEPROM_PWA_NO + 1);
+}
+
+/* Read the permanent ethernet address from the eprom. */
+void __devinit
+e100_rd_eaddr(struct e100_private *bdp)
+{
+       int i;
+       u16 eeprom_word;
+
+       for (i = 0; i < 6; i += 2) {
+               eeprom_word =
+                       e100_eeprom_read(bdp,
+                                        EEPROM_NODE_ADDRESS_BYTE_0 + (i / 2));
+
+               bdp->device->dev_addr[i] =
+                       bdp->perm_node_address[i] = (u8) eeprom_word;
+               bdp->device->dev_addr[i + 1] =
+                       bdp->perm_node_address[i + 1] = (u8) (eeprom_word >> 8);
+       }
+}
+
+/* Check the D102 RFD flags to see if the checksum passed */
+static unsigned char
+e100_D102_check_checksum(rfd_t *rfd)
+{
+       if (((le16_to_cpu(rfd->rfd_header.cb_status)) & RFD_PARSE_BIT)
+           && (((rfd->rcvparserstatus & CHECKSUM_PROTOCOL_MASK) ==
+                RFD_TCP_PACKET)
+               || ((rfd->rcvparserstatus & CHECKSUM_PROTOCOL_MASK) ==
+                   RFD_UDP_PACKET))
+           && (rfd->checksumstatus & TCPUDP_CHECKSUM_BIT_VALID)
+           && (rfd->checksumstatus & TCPUDP_CHECKSUM_VALID)) {
+               return CHECKSUM_UNNECESSARY;
+       }
+       return CHECKSUM_NONE;
+}
+
+/**
+ * e100_D101M_checksum
+ * @bdp: atapter's private data struct
+ * @skb: skb received
+ *
+ * Sets the skb->csum value from D101 csum found at the end of the Rx frame. The
+ * D101M sums all words in frame excluding the ethernet II header (14 bytes) so
+ * in case the packet is ethernet II and the protocol is IP, all is need is to
+ * assign this value to skb->csum.
+ */
+static unsigned char
+e100_D101M_checksum(struct e100_private *bdp, struct sk_buff *skb)
+{
+       unsigned short proto = (skb->protocol);
+
+       if (proto == __constant_htons(ETH_P_IP)) {
+
+               skb->csum = get_unaligned((u16 *) (skb->tail));
+               return CHECKSUM_HW;
+       }
+       return CHECKSUM_NONE;
+}
+
+/***************************************************************************/
+/***************************************************************************/
+/***************************************************************************/
+/***************************************************************************/
+/*       Auxilary Functions                                                */
+/***************************************************************************/
+
+/* Print the board's configuration */
+void __devinit
+e100_print_brd_conf(struct e100_private *bdp)
+{
+       if (netif_carrier_ok(bdp->device)) {
+               printk(KERN_NOTICE
+                      "  Mem:0x%08lx  IRQ:%d  Speed:%d Mbps  Dx:%s\n",
+                      (unsigned long) bdp->device->mem_start,
+                      bdp->device->irq, bdp->cur_line_speed,
+                      (bdp->cur_dplx_mode == FULL_DUPLEX) ? "Full" : "Half");
+       } else {
+               printk(KERN_NOTICE
+                      "  Mem:0x%08lx  IRQ:%d  Speed:%d Mbps  Dx:%s\n",
+                      (unsigned long) bdp->device->mem_start,
+                      bdp->device->irq, 0, "N/A");
+
+               /* Auto negotiation failed so we should display an error */
+               printk(KERN_NOTICE "  Failed to detect cable link\n");
+               printk(KERN_NOTICE "  Speed and duplex will be determined "
+                      "at time of connection\n");
+       }
+
+       /* Print the string if checksum Offloading was enabled */
+       if (bdp->flags & DF_CSUM_OFFLOAD)
+               printk(KERN_NOTICE "  Hardware receive checksums enabled\n");
+       else
+               printk(KERN_NOTICE "  Hardware receive checksums disabled\n");
+
+       if ((bdp->flags & DF_UCODE_LOADED))
+               printk(KERN_NOTICE "  cpu cycle saver enabled\n");
+}
+
+/**
+ * e100_get_brand_msg
+ * @bdp: atapter's private data struct
+ *
+ * This routine checks if there is specified branding message for a given board
+ * type and returns a pointer to the string containing the branding message.
+ */
+char *
+e100_get_brand_msg(struct e100_private *bdp)
+{
+       int i;
+
+       for (i = 0; e100_vendor_info_array[i].idstr != NULL; i++) {
+               if (e100_vendor_info_array[i].device_type == bdp->device_type) {
+                       return e100_vendor_info_array[i].idstr;
+               }
+       }
+
+       return e100_vendor_info_array[E100_ALL_BOARDS].idstr;
+}
+
+/**
+ * e100_pci_setup - setup the adapter's PCI information
+ * @pcid: adapter's pci_dev struct
+ * @bdp: atapter's private data struct
+ *
+ * This routine sets up all PCI information for the adapter. It enables the bus
+ * master bit (some BIOS don't do this), requests memory ans I/O regions, and
+ * calls ioremap() on the adapter's memory region.
+ *
+ * Returns:
+ *      true: if successfull
+ *      false: otherwise
+ */
+static unsigned char __devinit
+e100_pci_setup(struct pci_dev *pcid, struct e100_private *bdp)
+{
+       struct net_device *dev = bdp->device;
+       int rc = 0;
+
+       if ((rc = pci_enable_device(pcid)) != 0) {
+               goto err;
+       }
+
+       /* dev and ven ID have already been checked so it is our device */
+       pci_read_config_byte(pcid, PCI_REVISION_ID, (u8 *) &(bdp->rev_id));
+
+       /* address #0 is a memory region */
+       dev->mem_start = pci_resource_start(pcid, 0);
+       dev->mem_end = dev->mem_start + sizeof (scb_t);
+
+       /* address #1 is a IO region */
+       dev->base_addr = pci_resource_start(pcid, 1);
+
+       if ((rc = pci_request_regions(pcid, e100_short_driver_name)) != 0) {
+               goto err_disable;
+       }
+
+       pci_enable_wake(pcid, 0, 0);
+
+       /* if Bus Mastering is off, turn it on! */
+       pci_set_master(pcid);
+
+       /* address #0 is a memory mapping */
+       bdp->scb = (scb_t *) ioremap_nocache(dev->mem_start, sizeof (scb_t));
+
+       if (!bdp->scb) {
+               printk(KERN_ERR "%s - %s: Failed to map PCI address 0x%lX\n",
+                      e100_short_driver_name, dev->name,
+                      pci_resource_start(pcid, 0));
+               rc = -ENOMEM;
+               goto err_region;
+       }
+
+       return 0;
+
+err_region:
+       pci_release_regions(pcid);
+err_disable:
+       pci_disable_device(pcid);
+err:
+       return rc;
+}
+
+void
+e100_isolate_driver(struct e100_private *bdp)
+{
+       write_lock_irq(&(bdp->isolate_lock));
+       bdp->driver_isolated = true;
+       write_unlock_irq(&(bdp->isolate_lock));
+
+       del_timer_sync(&bdp->watchdog_timer);
+
+       netif_stop_queue(bdp->device);
+
+       bdp->last_tcb = NULL;
+
+       e100_sw_reset(bdp, PORT_SELECTIVE_RESET);
+}
+
+#ifdef E100_ETHTOOL_IOCTL
+static int
+e100_do_ethtool_ioctl(struct net_device *dev, struct ifreq *ifr)
+{
+       struct ethtool_cmd ecmd;
+       int rc = -EOPNOTSUPP;
+
+       if (copy_from_user(&ecmd, ifr->ifr_data, sizeof (ecmd.cmd)))
+               return -EFAULT;
+
+       switch (ecmd.cmd) {
+       case ETHTOOL_GSET:
+               rc = e100_ethtool_get_settings(dev, ifr);
+               break;
+       case ETHTOOL_SSET:
+               rc = e100_ethtool_set_settings(dev, ifr);
+               break;
+#ifdef ETHTOOL_GDRVINFO
+       case ETHTOOL_GDRVINFO:
+               rc = e100_ethtool_get_drvinfo(dev, ifr);
+               break;
+#endif
+#ifdef ETHTOOL_NWAY_RST
+       case ETHTOOL_NWAY_RST:
+               rc = e100_ethtool_nway_rst(dev, ifr);
+               break;
+#endif
+#ifdef ETHTOOL_GLINK
+       case ETHTOOL_GLINK:
+               rc = e100_ethtool_glink(dev, ifr);
+               break;
+#endif
+#ifdef ETHTOOL_GEEPROM
+       case ETHTOOL_GEEPROM:
+       case ETHTOOL_SEEPROM:
+               rc = e100_ethtool_eeprom(dev, ifr);
+               break;
+#endif
+#ifdef ETHTOOL_GWOL
+       case ETHTOOL_GWOL:
+       case ETHTOOL_SWOL:
+               rc = e100_ethtool_wol(dev, ifr);
+               break;
+#endif
+       default:
+               break;
+       }                       //switch
+       return rc;
+}
+
+static int
+e100_ethtool_get_settings(struct net_device *dev, struct ifreq *ifr)
+{
+       struct e100_private *bdp;
+       struct ethtool_cmd ecmd;
+       u16 advert = 0;
+
+       memset((void *) &ecmd, 0, sizeof (ecmd));
+
+       bdp = dev->priv;
+
+       ecmd.supported = bdp->speed_duplex_caps;
+
+       ecmd.port =
+               (bdp->speed_duplex_caps & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE;
+       ecmd.transceiver = XCVR_INTERNAL;
+       ecmd.phy_address = bdp->phy_addr;
+
+       ecmd.speed = bdp->cur_line_speed;
+       ecmd.duplex =
+               (bdp->cur_dplx_mode == HALF_DUPLEX) ? DUPLEX_HALF : DUPLEX_FULL;
+
+       ecmd.advertising = ADVERTISED_TP;
+
+       if (bdp->params.e100_speed_duplex == E100_AUTONEG) {
+               ecmd.autoneg = AUTONEG_ENABLE;
+               ecmd.advertising |= ADVERTISED_Autoneg;
+       } else {
+               ecmd.autoneg = AUTONEG_DISABLE;
+       }
+
+       if (bdp->speed_duplex_caps & SUPPORTED_MII) {
+               spin_lock_bh(&(bdp->mdi_access_lock));
+               e100_mdi_read(bdp, MII_ADVERTISE, bdp->phy_addr, &advert);
+               spin_unlock_bh(&(bdp->mdi_access_lock));
+
+               if (advert & ADVERTISE_10HALF)
+                       ecmd.advertising |= ADVERTISED_10baseT_Half;
+               if (advert & ADVERTISE_10FULL)
+                       ecmd.advertising |= ADVERTISED_10baseT_Full;
+               if (advert & ADVERTISE_100HALF)
+                       ecmd.advertising |= ADVERTISED_100baseT_Half;
+               if (advert & ADVERTISE_100FULL)
+                       ecmd.advertising |= ADVERTISED_100baseT_Full;
+       } else {
+               ecmd.autoneg = AUTONEG_DISABLE;
+               ecmd.advertising &= ~ADVERTISED_Autoneg;
+       }
+
+       if (copy_to_user(ifr->ifr_data, &ecmd, sizeof (ecmd)))
+               return -EFAULT;
+
+       return 0;
+}
+
+static int
+e100_ethtool_set_settings(struct net_device *dev, struct ifreq *ifr)
+{
+       struct e100_private *bdp;
+       int current_duplex;
+       int e100_new_speed_duplex;
+       int ethtool_new_speed_duplex;
+       int speed_duplex_change_required;
+       struct ethtool_cmd ecmd;
+
+       if (!capable(CAP_NET_ADMIN)) {
+               return -EPERM;
+       }
+
+       bdp = dev->priv;
+       if (netif_running(dev)) {
+               return -EBUSY;
+       }
+       if (copy_from_user(&ecmd, ifr->ifr_data, sizeof (ecmd))) {
+               return -EFAULT;
+       }
+       current_duplex =
+               (bdp->cur_dplx_mode == HALF_DUPLEX) ? DUPLEX_HALF : DUPLEX_FULL;
+       speed_duplex_change_required = (ecmd.speed != bdp->cur_line_speed)
+               || (ecmd.duplex != current_duplex);
+
+       if ((ecmd.autoneg == AUTONEG_ENABLE) && speed_duplex_change_required) {
+               return -EINVAL;
+       }
+
+       if ((ecmd.autoneg == AUTONEG_ENABLE)
+           && (bdp->speed_duplex_caps & SUPPORTED_Autoneg)) {
+               bdp->params.e100_speed_duplex = E100_AUTONEG;
+               e100_set_speed_duplex(bdp);
+       } else {
+               if (speed_duplex_change_required) {
+                       if (ecmd.speed == SPEED_10) {
+                               if (ecmd.duplex == DUPLEX_HALF) {
+                                       e100_new_speed_duplex =
+                                               E100_SPEED_10_HALF;
+                                       ethtool_new_speed_duplex =
+                                               SUPPORTED_10baseT_Half;
+
+                               } else {
+                                       e100_new_speed_duplex =
+                                               E100_SPEED_10_FULL;
+                                       ethtool_new_speed_duplex =
+                                               SUPPORTED_10baseT_Full;
+                               }
+
+                       } else {
+                               if (ecmd.duplex == DUPLEX_HALF) {
+                                       e100_new_speed_duplex =
+                                               E100_SPEED_100_HALF;
+                                       ethtool_new_speed_duplex =
+                                               SUPPORTED_100baseT_Half;
+
+                               } else {
+                                       e100_new_speed_duplex =
+                                               E100_SPEED_100_FULL;
+                                       ethtool_new_speed_duplex =
+                                               SUPPORTED_100baseT_Full;
+                               }
+                       }
+
+                       if (bdp->speed_duplex_caps & ethtool_new_speed_duplex) {
+                               bdp->params.e100_speed_duplex =
+                                       e100_new_speed_duplex;
+                               e100_set_speed_duplex(bdp);
+                       } else {
+                               return -EOPNOTSUPP;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+#ifdef ETHTOOL_GLINK
+static int
+e100_ethtool_glink(struct net_device *dev, struct ifreq *ifr)
+{
+       struct e100_private *bdp;
+       struct ethtool_value info;
+
+       memset((void *) &info, 0, sizeof (info));
+
+       bdp = dev->priv;
+       info.cmd = ETHTOOL_GLINK;
+
+       spin_lock_bh(&(bdp->mdi_access_lock));
+       info.data = e100_get_link_state(bdp);
+       spin_unlock_bh(&(bdp->mdi_access_lock));
+
+       if (copy_to_user(ifr->ifr_data, &info, sizeof (info)))
+               return -EFAULT;
+
+       return 0;
+}
+#endif
+
+#ifdef ETHTOOL_NWAY_RST
+static int
+e100_ethtool_nway_rst(struct net_device *dev, struct ifreq *ifr)
+{
+       struct e100_private *bdp;
+
+       if (!capable(CAP_NET_ADMIN))
+               return -EPERM;
+
+       bdp = dev->priv;
+
+       if ((bdp->speed_duplex_caps & SUPPORTED_Autoneg) &&
+           (bdp->params.e100_speed_duplex == E100_AUTONEG)) {
+               e100_set_speed_duplex(bdp);
+       } else {
+               return -EFAULT;
+       }
+       return 0;
+}
+#endif
+
+#ifdef ETHTOOL_GDRVINFO
+static int
+e100_ethtool_get_drvinfo(struct net_device *dev, struct ifreq *ifr)
+{
+       struct e100_private *bdp;
+       struct ethtool_drvinfo info;
+
+       memset((void *) &info, 0, sizeof (info));
+
+       bdp = dev->priv;
+
+       strncpy(info.driver, e100_short_driver_name, sizeof (info.driver) - 1);
+       strncpy(info.version, e100_version, sizeof (info.version) - 1);
+       strncpy(info.fw_version, e100_get_brand_msg(bdp),
+               sizeof (info.fw_version) - 1);
+       strncpy(info.bus_info, bdp->pdev->slot_name,
+               sizeof (info.bus_info) - 1);
+#ifdef ETHTOOL_GEEPROM
+       info.eedump_len = (bdp->eeprom_size << 1);      
+#endif
+
+       if (copy_to_user(ifr->ifr_data, &info, sizeof (info)))
+               return -EFAULT;
+
+       return 0;
+}
+#endif //ETHTOOL_GDRVINFO
+
+#ifdef ETHTOOL_GEEPROM
+static int
+e100_ethtool_eeprom(struct net_device *dev, struct ifreq *ifr)
+{
+       struct e100_private *bdp;
+       struct ethtool_eeprom ecmd;
+       u16 eeprom_data[256];
+       u16 *usr_eeprom_ptr;
+       u16 word_length, word_offset;
+       int i;
+
+       if (!capable(CAP_NET_ADMIN))
+               return -EPERM;
+
+       bdp = dev->priv;
+
+       if (copy_from_user(&ecmd, ifr->ifr_data, sizeof (ecmd)))
+               return -EFAULT;
+
+       usr_eeprom_ptr =
+               (u16 *) (ifr->ifr_data + offsetof(struct ethtool_eeprom, data));
+
+       word_offset = (ecmd.offset >> 1);
+       if (word_offset >= bdp->eeprom_size)
+               return -EFAULT;
+
+       word_length =
+               min_t(u32, (ecmd.len >> 1), (bdp->eeprom_size - word_offset));
+
+       if (ecmd.cmd == ETHTOOL_GEEPROM) {
+               for (i = word_offset; i < (word_length + word_offset); i++)
+                       eeprom_data[i] = e100_eeprom_read(bdp, i);
+
+               ecmd.len = (word_length << 1);
+               ecmd.magic = E100_EEPROM_MAGIC;
+
+               if (copy_to_user(ifr->ifr_data, &ecmd, sizeof (ecmd)))
+                       return -EFAULT;
+
+               if (copy_to_user(usr_eeprom_ptr, &(eeprom_data[word_offset]),
+                                (ecmd.len << 1)))
+                       return -EFAULT;
+       } else {
+               if (ecmd.magic != E100_EEPROM_MAGIC)
+                       return -EFAULT;
+
+               if (copy_from_user(&(eeprom_data[word_offset]), usr_eeprom_ptr,
+                                  (ecmd.len << 1)))
+                       return -EFAULT;
+
+               e100_eeprom_write_block(bdp, word_offset,
+                                       &(eeprom_data[word_offset]),
+                                       word_length);
+
+               ecmd.len = (word_length << 1);
+
+               if (copy_to_user(ifr->ifr_data, &ecmd, sizeof (ecmd)))
+                       return -EFAULT;
+       }
+       return 0;
+}
+#endif
+
+static inline int __devinit
+e100_10BaseT_adapter(struct e100_private *bdp)
+{
+       return ((bdp->pdev->device == 0x1229) &&
+               (bdp->pdev->subsystem_vendor == 0x8086) &&
+               (bdp->pdev->subsystem_device == 0x0003));
+}
+
+static void __devinit
+e100_get_speed_duplex_caps(struct e100_private *bdp)
+{
+       u16 status;
+
+       e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &status);
+
+       bdp->speed_duplex_caps = 0;
+
+       bdp->speed_duplex_caps |=
+               (status & BMSR_ANEGCAPABLE) ? SUPPORTED_Autoneg : 0;
+
+       bdp->speed_duplex_caps |=
+               (status & BMSR_10HALF) ? SUPPORTED_10baseT_Half : 0;
+
+       bdp->speed_duplex_caps |=
+               (status & BMSR_10FULL) ? SUPPORTED_10baseT_Full : 0;
+
+       bdp->speed_duplex_caps |=
+               (status & BMSR_100HALF) ? SUPPORTED_100baseT_Half : 0;
+
+       bdp->speed_duplex_caps |=
+               (status & BMSR_100FULL) ? SUPPORTED_100baseT_Full : 0;
+
+       if (IS_NC3133(bdp))
+               bdp->speed_duplex_caps =
+                       (SUPPORTED_FIBRE | SUPPORTED_100baseT_Full);
+       else
+               bdp->speed_duplex_caps |= SUPPORTED_TP;
+
+       if ((status == 0xFFFF) && e100_10BaseT_adapter(bdp)) {
+               bdp->speed_duplex_caps =
+                       (SUPPORTED_10baseT_Half | SUPPORTED_TP);
+       } else {
+               bdp->speed_duplex_caps |= SUPPORTED_MII;
+       }
+
+}
+
+static void
+e100_set_speed_duplex(struct e100_private *bdp)
+{
+       e100_phy_set_speed_duplex(bdp, true);
+       e100_config_fc(bdp);    /* re-config flow-control if necessary */
+       e100_config(bdp);       
+}
+
+#ifdef ETHTOOL_GWOL
+static unsigned char
+e100_setup_filter(struct e100_private *bdp)
+{
+       cb_header_t *ntcb_hdr;
+       unsigned char res = false;
+       nxmit_cb_entry_t *cmd;
+
+       if ((cmd = e100_alloc_non_tx_cmd(bdp)) == NULL) {
+               goto exit;
+       }
+
+       ntcb_hdr = (cb_header_t *) cmd->non_tx_cmd;
+       ntcb_hdr->cb_cmd = __constant_cpu_to_le16(CB_LOAD_FILTER);
+
+       /* Set EL and FIX bit */
+       (cmd->non_tx_cmd)->ntcb.filter.filter_data[0] =
+               __constant_cpu_to_le32(CB_FILTER_EL | CB_FILTER_FIX);
+
+       if (bdp->wolopts & WAKE_UCAST) {
+               (cmd->non_tx_cmd)->ntcb.filter.filter_data[0] |=
+                       __constant_cpu_to_le32(CB_FILTER_IA_MATCH);
+       }
+
+       if (bdp->wolopts & WAKE_ARP) {
+               /* Setup ARP bit and lower IP parts */
+               /* bdp->ip_lbytes contains 2 lower bytes of IP address in network byte order */
+               (cmd->non_tx_cmd)->ntcb.filter.filter_data[0] |=
+                       cpu_to_le32(CB_FILTER_ARP | bdp->ip_lbytes);
+       }
+
+       res = e100_exec_non_cu_cmd(bdp, cmd);
+       if (!res)
+               printk(KERN_WARNING "%s Filter setup failed\n",
+                      bdp->device->name);
+
+exit:
+       return res;
+
+}
+
+static void
+e100_do_wol(struct pci_dev *pcid, struct e100_private *bdp)
+{
+       int enable = 0;
+       u32 state = 0;
+
+       if (bdp->wolopts) {
+               e100_config_wol(bdp);
+
+               if (!e100_config(bdp)) {
+                       printk("e100_config WOL options failed\n");
+                       goto exit;
+               }
+
+               if (bdp->wolopts & (WAKE_UCAST | WAKE_ARP)) {
+                       if (!e100_setup_filter(bdp)) {
+                               printk("e100_config WOL options failed\n");
+                               goto exit;
+                       }
+                       state = 1;
+                       pci_set_power_state(pcid, state);
+               }
+               enable = 1;
+       }
+exit:
+        pci_enable_wake(pcid, state, enable);
+}
+
+static u16 
+e100_get_ip_lbytes(struct net_device *dev)
+{
+       struct in_ifaddr *ifa;
+       struct in_device *in_dev;
+       u32 res = 0;
+
+       in_dev = (struct in_device *) dev->ip_ptr;
+       /* Check if any in_device bound to interface */
+       if (in_dev) {
+               /* Check if any IP address is bound to interface */
+               if ((ifa = in_dev->ifa_list) != NULL) {
+                       res = __constant_ntohl(ifa->ifa_address);
+                       res = __constant_htons(res & 0x0000ffff);
+               }
+       }
+       return res;
+}
+
+static int
+e100_ethtool_wol(struct net_device *dev, struct ifreq *ifr)
+{
+       struct e100_private *bdp;
+       struct ethtool_wolinfo wolinfo;
+       int res = 0;
+
+       if (!capable(CAP_NET_ADMIN))
+               return -EPERM;
+
+       bdp = dev->priv;
+
+       if (copy_from_user(&wolinfo, ifr->ifr_data, sizeof (wolinfo))) {
+               return -EFAULT;
+       }
+
+       switch (wolinfo.cmd) {
+       case ETHTOOL_GWOL:
+               wolinfo.supported = bdp->wolsupported;
+               wolinfo.wolopts = bdp->wolopts;
+               if (copy_to_user(ifr->ifr_data, &wolinfo, sizeof (wolinfo)))
+                       res = -EFAULT;
+               break;
+
+       case ETHTOOL_SWOL:
+               /* If ALL requests are supported or request is DISABLE wol */
+               if (((wolinfo.wolopts & bdp->wolsupported) == wolinfo.wolopts)
+                   || (wolinfo.wolopts == 0)) {
+                       bdp->wolopts = wolinfo.wolopts;
+               } else {
+                       res = -EOPNOTSUPP;
+               }
+               break;
+       default:
+               break;
+       }
+       return res;
+}
+
+#endif
+#endif /*E100_ETHTOOL_IOCTL */
+
+#ifdef E100_MII_IOCTL
+static int
+e100_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+       struct e100_private *bdp;
+       struct mii_ioctl_data *data_ptr =
+               (struct mii_ioctl_data *) &(ifr->ifr_data);
+
+       bdp = dev->priv;
+
+       switch (cmd) {
+       case SIOCGMIIPHY:
+               data_ptr->phy_id = bdp->phy_addr & 0x1f;
+               break;
+
+       case SIOCGMIIREG:
+               if (!capable(CAP_NET_ADMIN))
+                       return -EPERM;
+               spin_lock_bh(&(bdp->mdi_access_lock));
+               e100_mdi_read(bdp, data_ptr->reg_num & 0x1f, bdp->phy_addr,
+                             &(data_ptr->val_out));
+               spin_unlock_bh(&(bdp->mdi_access_lock));
+               break;
+
+       case SIOCSMIIREG:
+               if (!capable(CAP_NET_ADMIN))
+                       return -EPERM;
+               if (netif_running(dev)) {
+                       return -EBUSY;
+               }
+               spin_lock_bh(&(bdp->mdi_access_lock));
+               e100_mdi_write(bdp, data_ptr->reg_num & 0x1f, bdp->phy_addr,
+                              data_ptr->val_in);
+               spin_unlock_bh(&(bdp->mdi_access_lock));
+               break;
+
+       default:
+               return -EOPNOTSUPP;
+       }
+       return 0;
+}
+#endif //E100_MII_IOCTL
+
+nxmit_cb_entry_t *
+e100_alloc_non_tx_cmd(struct e100_private *bdp)
+{
+       nxmit_cb_entry_t *non_tx_cmd_elem;
+
+       if (!(non_tx_cmd_elem = (nxmit_cb_entry_t *)
+             kmalloc(sizeof (nxmit_cb_entry_t), GFP_ATOMIC))) {
+               return NULL;
+       }
+       non_tx_cmd_elem->non_tx_cmd =
+               pci_alloc_consistent(bdp->pdev, sizeof (nxmit_cb_t),
+                                    &(non_tx_cmd_elem->dma_addr));
+       if (non_tx_cmd_elem->non_tx_cmd == NULL) {
+               kfree(non_tx_cmd_elem);
+               return NULL;
+       }
+       return non_tx_cmd_elem;
+}
+
+void
+e100_free_non_tx_cmd(struct e100_private *bdp,
+                    nxmit_cb_entry_t *non_tx_cmd_elem)
+{
+       pci_free_consistent(bdp->pdev, sizeof (nxmit_cb_t),
+                           non_tx_cmd_elem->non_tx_cmd,
+                           non_tx_cmd_elem->dma_addr);
+       kfree(non_tx_cmd_elem);
+}
+
+static void
+e100_free_nontx_list(struct e100_private *bdp)
+{
+       nxmit_cb_entry_t *command;
+       int i;
+
+       while (!list_empty(&bdp->non_tx_cmd_list)) {
+               command = list_entry(bdp->non_tx_cmd_list.next,
+                                    nxmit_cb_entry_t, list_elem);
+               list_del(&(command->list_elem));
+               e100_free_non_tx_cmd(bdp, command);
+       }
+
+       for (i = 0; i < CB_MAX_NONTX_CMD; i++) {
+               bdp->same_cmd_entry[i] = NULL;
+       }
+}
+
+static unsigned char
+e100_delayed_exec_non_cu_cmd(struct e100_private *bdp,
+                            nxmit_cb_entry_t *command)
+{
+       nxmit_cb_entry_t *same_command;
+       cb_header_t *ntcb_hdr;
+       u16 cmd;
+
+       ntcb_hdr = (cb_header_t *) command->non_tx_cmd;
+
+       cmd = CB_CMD_MASK & le16_to_cpu(ntcb_hdr->cb_cmd);
+
+       spin_lock_bh(&(bdp->bd_non_tx_lock));
+
+       same_command = bdp->same_cmd_entry[cmd];
+
+       if (same_command != NULL) {
+               memcpy((void *) (same_command->non_tx_cmd),
+                      (void *) (command->non_tx_cmd), sizeof (nxmit_cb_t));
+               e100_free_non_tx_cmd(bdp, command);
+       } else {
+               list_add_tail(&(command->list_elem), &(bdp->non_tx_cmd_list));
+               bdp->same_cmd_entry[cmd] = command;
+       }
+
+       if (bdp->non_tx_command_state == E100_NON_TX_IDLE) {
+               bdp->non_tx_command_state = E100_WAIT_TX_FINISH;
+               mod_timer(&(bdp->nontx_timer_id), jiffies + 1);
+       }
+
+       spin_unlock_bh(&(bdp->bd_non_tx_lock));
+       return true;
+}
+
+static void
+e100_non_tx_background(unsigned long ptr)
+{
+       struct e100_private *bdp = (struct e100_private *) ptr;
+       nxmit_cb_entry_t *active_command;
+       int restart = true;
+
+       spin_lock_bh(&(bdp->bd_non_tx_lock));
+
+       switch (bdp->non_tx_command_state) {
+       case E100_WAIT_TX_FINISH:
+               if (bdp->last_tcb != NULL) {
+                       rmb();
+                       if ((bdp->last_tcb->tcb_hdr.cb_status &
+                            __constant_cpu_to_le16(CB_STATUS_COMPLETE)) == 0)
+                               goto exit;
+               }
+               if ((readw(&bdp->scb->scb_status) & SCB_CUS_MASK) ==
+                   SCB_CUS_ACTIVE) {
+                       goto exit;
+               }
+               break;
+
+       case E100_WAIT_NON_TX_FINISH:
+               active_command = list_entry(bdp->non_tx_cmd_list.next,
+                                           nxmit_cb_entry_t, list_elem);
+               rmb();
+
+               if (((((cb_header_t *) (active_command->non_tx_cmd))->cb_status
+                     & __constant_cpu_to_le16(CB_STATUS_COMPLETE)) == 0)
+                   && time_before(jiffies, active_command->expiration_time)) {
+                       goto exit;
+               } else {
+                       list_del(&(active_command->list_elem));
+                       e100_free_non_tx_cmd(bdp, active_command);
+               }
+               break;
+
+       default:
+               break;
+       }                       //switch
+
+       if (list_empty(&bdp->non_tx_cmd_list)) {
+               bdp->non_tx_command_state = E100_NON_TX_IDLE;
+               spin_lock_irq(&(bdp->bd_lock));
+               bdp->next_cu_cmd = START_WAIT;
+               spin_unlock_irq(&(bdp->bd_lock));
+               restart = false;
+               goto exit;
+       } else {
+               u16 cmd_type;
+
+               bdp->non_tx_command_state = E100_WAIT_NON_TX_FINISH;
+               active_command = list_entry(bdp->non_tx_cmd_list.next,
+                                           nxmit_cb_entry_t, list_elem);
+               spin_lock_irq(&(bdp->bd_lock));
+               e100_wait_exec_cmplx(bdp, active_command->dma_addr,
+                                    SCB_CUC_START);
+               spin_unlock_irq(&(bdp->bd_lock));
+               active_command->expiration_time = jiffies + HZ;
+               cmd_type = CB_CMD_MASK &
+                       le16_to_cpu(((cb_header_t *)
+                                    (active_command->non_tx_cmd))->cb_cmd);
+               bdp->same_cmd_entry[cmd_type] = NULL;
+       }
+
+exit:
+       if (restart) {
+               mod_timer(&(bdp->nontx_timer_id), jiffies + 1);
+       } else {
+               if (netif_running(bdp->device))
+                       netif_wake_queue(bdp->device);
+       }
+       spin_unlock_bh(&(bdp->bd_non_tx_lock));
+}
diff --git a/drivers/net/e100/e100_phy.c b/drivers/net/e100/e100_phy.c
new file mode 100644 (file)
index 0000000..0631bfe
--- /dev/null
@@ -0,0 +1,1133 @@
+/*******************************************************************************
+
+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/100 Family of Adapters (e100) (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.
+*******************************************************************************/
+
+#include "e100_phy.h"
+
+void e100_handle_zlock(struct e100_private *bdp);
+
+/* 
+ * Procedure:  e100_mdi_write
+ *
+ * Description: This routine will write a value to the specified MII register
+ *             of an external MDI compliant device (e.g. PHY 100).  The
+ *             command will execute in polled mode.
+ *
+ * Arguments:
+ *     bdp - Ptr to this card's e100_bdconfig structure
+ *     reg_addr - The MII register that we are writing to
+ *     phy_addr - The MDI address of the Phy component.
+ *     data - The value that we are writing to the MII register.
+ *
+ * Returns:
+ *     NOTHING
+ */
+void
+e100_mdi_write(struct e100_private *bdp, u32 reg_addr, u32 phy_addr, u16 data)
+{
+       int e100_retry;
+       u32 temp_val;
+
+       temp_val = (((u32) data) | (reg_addr << 16) |
+                   (phy_addr << 21) | (MDI_WRITE << 26));
+       writel(temp_val, &bdp->scb->scb_mdi_cntrl);
+
+       /* wait 20usec before checking status */
+       udelay(20);
+
+       /* poll for the mdi write to complete */
+       e100_retry = E100_CMD_WAIT;
+       while ((!(readl(&bdp->scb->scb_mdi_cntrl) & MDI_PHY_READY)) &&
+              (e100_retry)) {
+
+               udelay(20);
+               e100_retry--;
+       }
+}
+
+/* 
+ * Procedure:  e100_mdi_read
+ *
+ * Description: This routine will read a value from the specified MII register
+ *             of an external MDI compliant device (e.g. PHY 100), and return
+ *             it to the calling routine.  The command will execute in polled
+ *             mode.
+ *
+ * Arguments:
+ *     bdp - Ptr to this card's e100_bdconfig structure
+ *     reg_addr - The MII register that we are reading from
+ *     phy_addr - The MDI address of the Phy component.
+ *
+ * Results:
+ *     data - The value that we read from the MII register.
+ *
+ * Returns:
+ *     NOTHING
+ */
+void
+e100_mdi_read(struct e100_private *bdp, u32 reg_addr, u32 phy_addr, u16 *data)
+{
+       int e100_retry;
+       u32 temp_val;
+
+       /* Issue the read command to the MDI control register. */
+       temp_val = ((reg_addr << 16) | (phy_addr << 21) | (MDI_READ << 26));
+       writel(temp_val, &bdp->scb->scb_mdi_cntrl);
+
+       /* wait 20usec before checking status */
+       udelay(20);
+
+       /* poll for the mdi read to complete */
+       e100_retry = E100_CMD_WAIT;
+       while ((!(readl(&bdp->scb->scb_mdi_cntrl) & MDI_PHY_READY)) &&
+              (e100_retry)) {
+
+               udelay(20);
+               e100_retry--;
+       }
+
+       // return the lower word
+       *data = (u16) readl(&bdp->scb->scb_mdi_cntrl);
+}
+
+static unsigned char __devinit
+e100_phy_valid(struct e100_private *bdp, unsigned int phy_address)
+{
+       u16 ctrl_reg, stat_reg;
+
+       /* Read the MDI control register */
+       e100_mdi_read(bdp, MII_BMCR, phy_address, &ctrl_reg);
+
+       /* Read the status register twice, bacause of sticky bits */
+       e100_mdi_read(bdp, MII_BMSR, phy_address, &stat_reg);
+       e100_mdi_read(bdp, MII_BMSR, phy_address, &stat_reg);
+
+       if ((ctrl_reg == 0xffff) || ((stat_reg == 0) && (ctrl_reg == 0)))
+               return false;
+
+       return true;
+}
+
+static void __devinit
+e100_phy_address_detect(struct e100_private *bdp)
+{
+       unsigned int addr;
+       unsigned char valid_phy_found = false;
+
+       if (IS_NC3133(bdp)) {
+               bdp->phy_addr = 0;
+               return;
+       }
+
+       if (e100_phy_valid(bdp, PHY_DEFAULT_ADDRESS)) {
+               bdp->phy_addr = PHY_DEFAULT_ADDRESS;
+               valid_phy_found = true;
+
+       } else {
+               for (addr = MIN_PHY_ADDR; addr <= MAX_PHY_ADDR; addr++) {
+                       if (e100_phy_valid(bdp, addr)) {
+                               bdp->phy_addr = addr;
+                               valid_phy_found = true;
+                               break;
+                       }
+               }
+       }
+
+       if (!valid_phy_found) {
+               bdp->phy_addr = PHY_ADDRESS_503;
+       }
+}
+
+static void __devinit
+e100_phy_id_detect(struct e100_private *bdp)
+{
+       u16 low_id_reg, high_id_reg;
+
+       if (bdp->phy_addr == PHY_ADDRESS_503) {
+               bdp->PhyId = PHY_503;
+               return;
+       }
+       if (!(bdp->flags & IS_ICH)) {
+               if (bdp->rev_id >= D102_REV_ID) {
+                       bdp->PhyId = PHY_82562ET;
+                       return;
+               }
+       }
+
+       /* Read phy id from the MII register */
+       e100_mdi_read(bdp, MII_PHYSID1, bdp->phy_addr, &low_id_reg);
+       e100_mdi_read(bdp, MII_PHYSID2, bdp->phy_addr, &high_id_reg);
+
+       bdp->PhyId = ((unsigned int) low_id_reg |
+                     ((unsigned int) high_id_reg << 16));
+}
+
+static void __devinit
+e100_phy_isolate(struct e100_private *bdp)
+{
+       unsigned int phy_address;
+       u16 ctrl_reg;
+
+       /* Go over all phy addresses. Deisolate the selected one, and isolate
+        * all the rest */
+       for (phy_address = 0; phy_address <= MAX_PHY_ADDR; phy_address++) {
+               if (phy_address != bdp->phy_addr) {
+                       e100_mdi_write(bdp, MII_BMCR, phy_address,
+                                      BMCR_ISOLATE);
+
+               } else {
+                       e100_mdi_read(bdp, MII_BMCR, bdp->phy_addr, &ctrl_reg);
+                       ctrl_reg &= ~BMCR_ISOLATE;
+                       e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, ctrl_reg);
+               }
+
+               udelay(100);
+       }
+}
+
+static unsigned char __devinit
+e100_phy_specific_setup(struct e100_private *bdp)
+{
+       u16 misc_reg;
+
+       if (bdp->phy_addr == PHY_ADDRESS_503) {
+               switch (bdp->params.e100_speed_duplex) {
+               case E100_AUTONEG:
+                       /* The adapter can't autoneg. so set to 10/HALF */
+                       printk(KERN_INFO
+                              "503 serial component detected which "
+                              "cannot autonegotiate\n");
+                       printk(KERN_INFO
+                              "speed/duplex forced to 10Mbps / Half duplex\n");
+                       bdp->params.e100_speed_duplex = E100_SPEED_10_HALF;
+                       break;
+
+               case E100_SPEED_100_HALF:
+               case E100_SPEED_100_FULL:
+                       printk(KERN_ERR
+                              "503 serial component detected which does not "
+                              "support 100Mbps\n");
+                       printk(KERN_ERR
+                              "Change the forced speed/duplex to a supported "
+                              "setting\n");
+                       return false;
+               }
+
+               return true;
+       }
+
+       if (IS_NC3133(bdp)) {
+               u16 int_reg;
+
+               /* enable 100BASE fiber interface */
+               e100_mdi_write(bdp, MDI_NC3133_CONFIG_REG, bdp->phy_addr,
+                              MDI_NC3133_100FX_ENABLE);
+
+               if ((bdp->params.e100_speed_duplex != E100_AUTONEG) &&
+                   (bdp->params.e100_speed_duplex != E100_SPEED_100_FULL)) {
+                       /* just inform user about 100 full */
+                       printk(KERN_ERR "NC3133 NIC can only run "
+                              "at 100Mbps full duplex\n");
+               }
+
+               bdp->params.e100_speed_duplex = E100_SPEED_100_FULL;
+
+               /* enable interrupts */
+               e100_mdi_read(bdp, MDI_NC3133_INT_ENABLE_REG,
+                             bdp->phy_addr, &int_reg);
+               int_reg |= MDI_NC3133_INT_ENABLE;
+               e100_mdi_write(bdp, MDI_NC3133_INT_ENABLE_REG,
+                              bdp->phy_addr, int_reg);
+       }
+
+       /* Handle the National TX */
+       if ((bdp->PhyId & PHY_MODEL_REV_ID_MASK) == PHY_NSC_TX) {
+               e100_mdi_read(bdp, NSC_CONG_CONTROL_REG,
+                             bdp->phy_addr, &misc_reg);
+
+               misc_reg |= NSC_TX_CONG_TXREADY;
+
+               /* disable the congestion control bit in the National Phy */
+               misc_reg &= ~NSC_TX_CONG_ENABLE;
+
+               e100_mdi_write(bdp, NSC_CONG_CONTROL_REG,
+                              bdp->phy_addr, misc_reg);
+       }
+
+       return true;
+}
+
+/* 
+ * Procedure:  e100_phy_fix_squelch
+ *
+ * Description:
+ *     Help find link on certain rare scenarios.
+ *     NOTE: This routine must be called once per watchdog,
+ *           and *after* setting the current link state.
+ *
+ * Arguments:
+ *     bdp - Ptr to this card's e100_bdconfig structure
+ *
+ * Returns:
+ *     NOTHING
+ */
+static void
+e100_phy_fix_squelch(struct e100_private *bdp)
+{
+       if ((bdp->PhyId != PHY_82555_TX) || (bdp->flags & DF_SPEED_FORCED))
+               return;
+
+       if (netif_carrier_ok(bdp->device)) {
+               switch (bdp->PhyState) {
+               case 0:
+                       break;
+               case 1:
+                       e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL,
+                                      bdp->phy_addr, 0x0000);
+                       break;
+               case 2:
+                       e100_mdi_write(bdp, PHY_82555_MDI_EQUALIZER_CSR,
+                                      bdp->phy_addr, 0x3000);
+                       break;
+               }
+               bdp->PhyState = 0;
+               bdp->PhyDelay = 0;
+
+       } else if (!bdp->PhyDelay--) {
+               switch (bdp->PhyState) {
+               case 0:
+                       e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL,
+                                      bdp->phy_addr, EXTENDED_SQUELCH_BIT);
+                       bdp->PhyState = 1;
+                       break;
+               case 1:
+                       e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL,
+                                      bdp->phy_addr, 0x0000);
+                       e100_mdi_write(bdp, PHY_82555_MDI_EQUALIZER_CSR,
+                                      bdp->phy_addr, 0x2010);
+                       bdp->PhyState = 2;
+                       break;
+               case 2:
+                       e100_mdi_write(bdp, PHY_82555_MDI_EQUALIZER_CSR,
+                                      bdp->phy_addr, 0x3000);
+                       bdp->PhyState = 0;
+                       break;
+               }
+
+               e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr,
+                              BMCR_ANENABLE | BMCR_ANRESTART);
+               bdp->PhyDelay = 3;
+       }
+}
+
+/* 
+ * Procedure:  e100_fix_polarity
+ *
+ * Description:
+ *     Fix for 82555 auto-polarity toggle problem. With a short cable 
+ *     connecting an 82555 with an 840A link partner, if the medium is noisy,
+ *     the 82555 sometime thinks that the polarity might be wrong and so 
+ *     toggles polarity. This happens repeatedly and results in a high bit 
+ *     error rate.
+ *     NOTE: This happens only at 10 Mbps
+ *
+ * Arguments:
+ *     bdp - Ptr to this card's e100_bdconfig structure
+ *
+ * Returns:
+ *     NOTHING
+ */
+static void __devinit
+e100_fix_polarity(struct e100_private *bdp)
+{
+       u16 status;
+       u16 errors;
+       u16 misc_reg;
+       int speed;
+
+       if ((bdp->PhyId != PHY_82555_TX) && (bdp->PhyId != PHY_82562ET) &&
+           (bdp->PhyId != PHY_82562EM))
+               return;
+
+       /* If the user wants auto-polarity disabled, do only that and nothing *
+        * else. * e100_autopolarity == 0 means disable --- we do just the
+        * disabling * e100_autopolarity == 1 means enable  --- we do nothing at
+        * all * e100_autopolarity >= 2 means we do the workaround code. */
+       /* Change for 82558 enhancement */
+       switch (E100_AUTOPOLARITY) {
+       case 0:
+               e100_mdi_read(bdp, PHY_82555_SPECIAL_CONTROL,
+                             bdp->phy_addr, &misc_reg);
+               e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL, bdp->phy_addr,
+                              (u16) (misc_reg | DISABLE_AUTO_POLARITY));
+               break;
+
+       case 1:
+               e100_mdi_read(bdp, PHY_82555_SPECIAL_CONTROL,
+                             bdp->phy_addr, &misc_reg);
+               e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL, bdp->phy_addr,
+                              (u16) (misc_reg & ~DISABLE_AUTO_POLARITY));
+               break;
+
+       case 2:
+               /* we do this only if link is up */
+               if (!netif_carrier_ok(bdp->device)) {
+                       break;
+               }
+
+               e100_mdi_read(bdp, PHY_82555_CSR, bdp->phy_addr, &status);
+               speed = (status & PHY_82555_SPEED_BIT) ? 100 : 10;
+
+               /* we need to do this only if speed is 10 */
+               if (speed != 10) {
+                       break;
+               }
+
+               /* see if we have any end of frame errors */
+               e100_mdi_read(bdp, PHY_82555_EOF_COUNTER,
+                             bdp->phy_addr, &errors);
+
+               /* if non-zero, wait for 100 ms before reading again */
+               if (errors) {
+                       udelay(200);
+                       e100_mdi_read(bdp, PHY_82555_EOF_COUNTER,
+                                     bdp->phy_addr, &errors);
+
+                       /* if non-zero again, we disable polarity */
+                       if (errors) {
+                               e100_mdi_read(bdp, PHY_82555_SPECIAL_CONTROL,
+                                             bdp->phy_addr, &misc_reg);
+                               e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL,
+                                              bdp->phy_addr,
+                                              (u16) (misc_reg |
+                                                     DISABLE_AUTO_POLARITY));
+                       }
+               }
+
+               if (!errors) {
+                       /* it is safe to read the polarity now */
+                       e100_mdi_read(bdp, PHY_82555_CSR,
+                                     bdp->phy_addr, &status);
+
+                       /* if polarity is normal, disable polarity */
+                       if (!(status & PHY_82555_POLARITY_BIT)) {
+                               e100_mdi_read(bdp, PHY_82555_SPECIAL_CONTROL,
+                                             bdp->phy_addr, &misc_reg);
+                               e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL,
+                                              bdp->phy_addr,
+                                              (u16) (misc_reg |
+                                                     DISABLE_AUTO_POLARITY));
+                       }
+               }
+               break;
+
+       default:
+               break;
+       }
+}
+
+/* 
+ * Procedure:  e100_find_speed_duplex
+ *
+ * Description: This routine will figure out what line speed and duplex mode
+ *             the PHY is currently using.
+ *
+ * Arguments:
+ *     bdp - Ptr to this card's e100_bdconfig structure
+ *
+ * Returns:
+ *     NOTHING
+ */
+static void
+e100_find_speed_duplex(struct e100_private *bdp)
+{
+       unsigned int PhyId;
+       u16 stat_reg, misc_reg;
+       u16 ad_reg, lp_ad_reg;
+
+       PhyId = bdp->PhyId & PHY_MODEL_REV_ID_MASK;
+
+       /* First we should check to see if we have link */
+       /* If we don't have a link no reason to print a speed and duplex */
+       if (!e100_update_link_state(bdp)) {
+               return;
+       }
+
+       if (bdp->flags & DF_SPEED_FORCED) {
+               return;
+       }
+
+       /* On the 82559 and later controllers, speed/duplex is part of the *
+        * SCB. So, we save an mdi_read and get these from the SCB. * */
+       if (bdp->rev_id >= D101MA_REV_ID) {
+               /* Read speed */
+               if (readb(&bdp->scb->scb_ext.d101m_scb.scb_gen_stat) & BIT_1)
+                       bdp->cur_line_speed = 100;
+               else
+                       bdp->cur_line_speed = 10;
+
+               /* Read duplex */
+               if (readb(&bdp->scb->scb_ext.d101m_scb.scb_gen_stat) & BIT_2)
+                       bdp->cur_dplx_mode = FULL_DUPLEX;
+               else
+                       bdp->cur_dplx_mode = HALF_DUPLEX;
+
+               return;
+       }
+
+       /* If this is a Phy 100, then read bits 1 and 0 of extended register 0,
+        * to get the current speed and duplex settings. */
+       if ((PhyId == PHY_100_A) || (PhyId == PHY_100_C) ||
+           (PhyId == PHY_82555_TX)) {
+
+               /* Read Phy 100 extended register 0 */
+               e100_mdi_read(bdp, EXTENDED_REG_0, bdp->phy_addr, &misc_reg);
+
+               /* Get current speed setting */
+               if (misc_reg & PHY_100_ER0_SPEED_INDIC)
+                       bdp->cur_line_speed = 100;
+               else
+                       bdp->cur_line_speed = 10;
+
+               /* Get current duplex setting -- FDX enabled if bit is set */
+               if (misc_reg & PHY_100_ER0_FDX_INDIC)
+                       bdp->cur_dplx_mode = FULL_DUPLEX;
+               else
+                       bdp->cur_dplx_mode = HALF_DUPLEX;
+
+               return;
+       }
+
+       /* See if link partner is capable of Auto-Negotiation (bit 0, reg 6) */
+       e100_mdi_read(bdp, MII_EXPANSION, bdp->phy_addr, &misc_reg);
+
+       /* See if Auto-Negotiation was complete (bit 5, reg 1) */
+       e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &stat_reg);
+
+       /* If a True NWAY connection was made, then we can detect speed/dplx
+        * by ANDing our adapter's advertised abilities with our link partner's
+        * advertised ablilities, and then assuming that the highest common
+        * denominator was chosed by NWAY. */
+       if ((misc_reg & EXPANSION_NWAY) && (stat_reg & BMSR_ANEGCOMPLETE)) {
+
+               /* Read our advertisement register */
+               e100_mdi_read(bdp, MII_ADVERTISE, bdp->phy_addr, &ad_reg);
+
+               /* Read our link partner's advertisement register */
+               e100_mdi_read(bdp, MII_LPA, bdp->phy_addr, &lp_ad_reg);
+
+               /* AND the two advertisement registers together, and get rid
+                * of any extraneous bits. */
+               ad_reg &= (lp_ad_reg & NWAY_LP_ABILITY);
+
+               /* Get speed setting */
+               if (ad_reg &
+                   (ADVERTISE_100HALF | ADVERTISE_100FULL |
+                    ADVERTISE_100BASE4))
+
+                       bdp->cur_line_speed = 100;
+               else
+                       bdp->cur_line_speed = 10;
+
+               /* Get duplex setting -- use priority resolution algorithm */
+               if (ad_reg & ADVERTISE_100BASE4) {
+                       bdp->cur_dplx_mode = HALF_DUPLEX;
+               } else if (ad_reg & ADVERTISE_100FULL) {
+                       bdp->cur_dplx_mode = FULL_DUPLEX;
+               } else if (ad_reg & ADVERTISE_100HALF) {
+                       bdp->cur_dplx_mode = HALF_DUPLEX;
+               } else if (ad_reg & ADVERTISE_10FULL) {
+                       bdp->cur_dplx_mode = FULL_DUPLEX;
+               } else {
+                       bdp->cur_dplx_mode = HALF_DUPLEX;
+               }
+
+               return;
+       }
+
+       /* If we are connected to a dumb (non-NWAY) repeater or hub, and the
+        * line speed was determined automatically by parallel detection, then
+        * we have no way of knowing exactly what speed the PHY is set to
+        * unless that PHY has a propietary register which indicates speed in
+        * this situation. The NSC TX PHY does have such a register. Also,
+        * since NWAY didn't establish the connection, the duplex setting
+        * should HALF duplex. */
+       bdp->cur_dplx_mode = HALF_DUPLEX;
+
+       if (PhyId == PHY_NSC_TX) {
+               /* Read register 25 to get the SPEED_10 bit */
+               e100_mdi_read(bdp, NSC_SPEED_IND_REG, bdp->phy_addr, &misc_reg);
+
+               /* If bit 6 was set then we're at 10Mbps */
+               if (misc_reg & NSC_TX_SPD_INDC_SPEED)
+                       bdp->cur_line_speed = 10;
+               else
+                       bdp->cur_line_speed = 100;
+
+       } else {
+               /* If we don't know the line speed, default to 10Mbps */
+               bdp->cur_line_speed = 10;
+       }
+}
+
+/* 
+ * Procedure: e100_force_speed_duplex
+ *
+ * Description: This routine forces line speed and duplex mode of the
+ * adapter based on the values the user has set in e100.c.
+ *
+ * Arguments:  bdp - Pointer to the e100_private structure for the board
+ *
+ * Returns: void
+ *
+ */
+static void
+e100_force_speed_duplex(struct e100_private *bdp)
+{
+       u16 control;
+       int neg_timeout = 2 * HZ;       //2 sec in jiffies
+
+       bdp->flags |= DF_SPEED_FORCED;
+
+       spin_lock_bh(&(bdp->mdi_access_lock));
+
+       e100_mdi_read(bdp, MII_BMCR, bdp->phy_addr, &control);
+       control &= ~BMCR_ANENABLE;
+
+       /* Check e100.c values */
+       switch (bdp->params.e100_speed_duplex) {
+       case E100_SPEED_10_HALF:
+               control &= ~BMCR_SPEED100;
+               control &= ~BMCR_FULLDPLX;
+               bdp->cur_line_speed = 10;
+               bdp->cur_dplx_mode = HALF_DUPLEX;
+               break;
+
+       case E100_SPEED_10_FULL:
+               control &= ~BMCR_SPEED100;
+               control |= BMCR_FULLDPLX;
+               bdp->cur_line_speed = 10;
+               bdp->cur_dplx_mode = FULL_DUPLEX;
+               break;
+
+       case E100_SPEED_100_HALF:
+               control |= BMCR_SPEED100;
+               control &= ~BMCR_FULLDPLX;
+               bdp->cur_line_speed = 100;
+               bdp->cur_dplx_mode = HALF_DUPLEX;
+               break;
+
+       case E100_SPEED_100_FULL:
+               control |= BMCR_SPEED100;
+               control |= BMCR_FULLDPLX;
+               bdp->cur_line_speed = 100;
+               bdp->cur_dplx_mode = FULL_DUPLEX;
+               break;
+       }
+
+       e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, control);
+
+       /* loop must run at least once */
+       do {
+               spin_unlock_bh(&(bdp->mdi_access_lock));
+
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               schedule_timeout(SLEEP_TIME);
+
+               spin_lock_bh(&(bdp->mdi_access_lock));
+
+               if (e100_update_link_state(bdp)) {
+                       break;
+               }
+               neg_timeout -= SLEEP_TIME;
+
+       } while (neg_timeout > 0);
+
+       spin_unlock_bh(&(bdp->mdi_access_lock));
+}
+
+/* 
+ * Procedure: e100_set_fc
+ *
+ * Description: Checks the link's capability for flow control.
+ * 
+ * Arguments:  bdp - Pointer to the e100_private structure for the board
+ *                 
+ * Returns: void
+ *
+ */
+static void
+e100_set_fc(struct e100_private *bdp)
+{
+       u16 ad_reg;
+       u16 lp_ad_reg;
+       u16 exp_reg;
+
+       /* no flow control for 82557, forced links or half duplex */
+       if (!netif_carrier_ok(bdp->device) || (bdp->flags & DF_SPEED_FORCED) ||
+           (bdp->cur_dplx_mode == HALF_DUPLEX) ||
+           !(bdp->flags & IS_BACHELOR)) {
+
+               bdp->flags &= ~DF_LINK_FC_CAP;
+               return;
+       }
+
+       /* See if link partner is capable of Auto-Negotiation (bit 0, reg 6) */
+       e100_mdi_read(bdp, MII_EXPANSION, bdp->phy_addr, &exp_reg);
+
+       if (exp_reg & EXPANSION_NWAY) {
+               /* Read our advertisement register */
+               e100_mdi_read(bdp, MII_ADVERTISE, bdp->phy_addr, &ad_reg);
+
+               /* Read our link partner's advertisement register */
+               e100_mdi_read(bdp, MII_LPA, bdp->phy_addr, &lp_ad_reg);
+
+               ad_reg &= lp_ad_reg;    /* AND the 2 ad registers */
+
+               if (ad_reg & NWAY_AD_FC_SUPPORTED)
+                       bdp->flags |= DF_LINK_FC_CAP;
+               else
+                       bdp->flags &= ~DF_LINK_FC_CAP;
+
+       } else {
+               bdp->flags &= ~DF_LINK_FC_CAP;
+       }
+}
+
+/* 
+ * Procedure: e100_phy_check
+ * 
+ * Arguments:  bdp - Pointer to the e100_private structure for the board
+ *
+ * Returns: true if link state was changed
+ *         B_FLASE otherwise
+ *
+ */
+unsigned char
+e100_phy_check(struct e100_private *bdp)
+{
+       unsigned char old_link;
+       unsigned char changed = false;
+
+       old_link = netif_carrier_ok(bdp->device) ? 1 : 0;
+       e100_find_speed_duplex(bdp);
+
+       if (!old_link && netif_carrier_ok(bdp->device)) {
+               e100_set_fc(bdp);
+               changed = true;
+       }
+
+       if (old_link && !netif_carrier_ok(bdp->device)) {
+               /* reset the zero lock state */
+               bdp->zlock_state = ZLOCK_INITIAL;
+
+               // set auto lock for phy auto-negotiation on link up
+               if ((bdp->PhyId & PHY_MODEL_REV_ID_MASK) == PHY_82555_TX)
+                       e100_mdi_write(bdp, PHY_82555_MDI_EQUALIZER_CSR,
+                                      bdp->phy_addr, 0);
+               changed = true;
+       }
+
+       e100_phy_fix_squelch(bdp);
+       e100_handle_zlock(bdp);
+
+       return changed;
+}
+
+/* 
+ * Procedure:  e100_auto_neg
+ *
+ * Description: This routine will start autonegotiation and wait
+ *                  for it to complete
+ *
+ * Arguments:
+ *     bdp             - pointer to this card's e100_bdconfig structure
+ *     force_restart   - defines if autoneg should be restarted even if it
+ *                     has been completed before
+ * Returns:
+ *     NOTHING
+ */
+static void
+e100_auto_neg(struct e100_private *bdp, unsigned char force_restart)
+{
+       u16 stat_reg;
+       unsigned int i;
+
+       bdp->flags &= ~DF_SPEED_FORCED;
+
+       spin_lock_bh(&(bdp->mdi_access_lock));
+
+       e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &stat_reg);
+       e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &stat_reg);
+
+       /* if we are capable of performing autoneg then we restart if needed */
+       if ((stat_reg != 0xFFFF) && (stat_reg & BMSR_ANEGCAPABLE)) {
+
+               if ((!force_restart) &&
+                   (stat_reg & BMSR_ANEGCOMPLETE)) {
+                       goto exit;
+               }
+
+               e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr,
+                              BMCR_ANENABLE | BMCR_ANRESTART);
+
+               /* wait for autoneg to complete (up to 3 seconds) */
+               for (i = 0; i < 60; i++) {
+                       /* now re-read the value. Sticky so read twice */
+                       e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &stat_reg);
+                       e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &stat_reg);
+
+                       if (stat_reg & BMSR_ANEGCOMPLETE)
+                               goto exit;
+
+                       spin_unlock_bh(&(bdp->mdi_access_lock));
+
+                       set_current_state(TASK_UNINTERRUPTIBLE);
+                       schedule_timeout(SLEEP_TIME);
+
+                       spin_lock_bh(&(bdp->mdi_access_lock));
+
+               }
+       }
+
+exit:
+       e100_find_speed_duplex(bdp);
+       spin_unlock_bh(&(bdp->mdi_access_lock));
+}
+
+void
+e100_phy_set_speed_duplex(struct e100_private *bdp, unsigned char force_restart)
+{
+       if (bdp->params.e100_speed_duplex == E100_AUTONEG) {
+               e100_auto_neg(bdp, force_restart);
+
+       } else {
+               e100_force_speed_duplex(bdp);
+       }
+
+       e100_set_fc(bdp);
+}
+
+void __devexit
+e100_phy_reset(struct e100_private *bdp)
+{
+       u16 ctrl_reg;
+
+       ctrl_reg = BMCR_ANENABLE | BMCR_ANRESTART | BMCR_RESET;
+
+       e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, ctrl_reg);
+
+       udelay(100);
+}
+
+unsigned char __devinit
+e100_phy_init(struct e100_private *bdp)
+{
+       e100_phy_address_detect(bdp);
+       e100_phy_isolate(bdp);
+       e100_phy_id_detect(bdp);
+
+       if (!e100_phy_specific_setup(bdp))
+               return false;
+
+       bdp->PhyState = 0;
+       bdp->PhyDelay = 0;
+       bdp->zlock_state = ZLOCK_INITIAL;
+
+       e100_phy_set_speed_duplex(bdp, false);
+       e100_fix_polarity(bdp);
+
+       return true;
+}
+
+/* 
+ * Procedure: e100_get_link_state
+ * 
+ * Description: This routine checks the link status of the adapter
+ *
+ * Arguments:  bdp - Pointer to the e100_private structure for the board
+ *                 
+ *
+ * Returns: true - If a link is found
+ *             false - If there is no link
+ *
+ */
+unsigned char
+e100_get_link_state(struct e100_private *bdp)
+{
+       unsigned char link = false;
+       u16 status;
+
+       /* Check link status */
+       /* If the controller is a 82559 or later one, link status is available
+        * from the CSR. This avoids the mdi_read. */
+       if (bdp->rev_id >= D101MA_REV_ID) {
+               if (readb(&bdp->scb->scb_ext.d101m_scb.scb_gen_stat) & BIT_0) {
+                       link = true;
+               } else {
+                       link = false;
+               }
+
+       } else {
+               /* Read the status register twice because of sticky bits */
+               e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &status);
+               e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &status);
+
+               if (status & BMSR_LSTATUS) {
+                       link = true;
+               } else {
+                       link = false;
+               }
+       }
+
+       return link;
+}
+
+/* 
+ * Procedure: e100_update_link_state
+ * 
+ * Description: This routine updates the link status of the adapter
+ *
+ * Arguments:  bdp - Pointer to the e100_private structure for the board
+ *                 
+ *
+ * Returns: true - If a link is found
+ *             false - If there is no link
+ *
+ */
+unsigned char
+e100_update_link_state(struct e100_private *bdp)
+{
+       unsigned char link;
+
+       link = e100_get_link_state(bdp);
+
+       if (link) {
+               if (!netif_carrier_ok(bdp->device))
+                       netif_carrier_on(bdp->device);
+       } else {
+               if (netif_carrier_ok(bdp->device))
+                       netif_carrier_off(bdp->device);
+       }
+
+       return link;
+}
+
+/**************************************************************************\
+ **
+ ** PROC NAME:     e100_handle_zlock
+ **    This function manages a state machine that controls
+ **    the driver's zero locking algorithm.
+ **    This function is called by e100_watchdog() every ~2 second.
+ ** States:
+ **    The current link handling state is stored in 
+ **    bdp->zlock_state, and is one of:
+ **    ZLOCK_INITIAL, ZLOCK_READING, ZLOCK_SLEEPING
+ **    Detailed description of the states and the transitions
+ **    between states is found below.
+ **    Note that any time the link is down / there is a reset
+ **    state will be changed outside this function to ZLOCK_INITIAL
+ ** Algorithm:
+ **    1. If link is up & 100 Mbps continue else stay in #1:
+ **    2. Set 'auto lock'
+ **    3. Read & Store 100 times 'Zero' locked in 1 sec interval
+ **    4. If max zero read >= 0xB continue else goto 1
+ **    5. Set most popular 'Zero' read in #3
+ **    6. Sleep 5 minutes
+ **    7. Read number of errors, if it is > 300 goto 2 else goto 6
+ ** Data Structures (in DRIVER_DATA):
+ **    zlock_state           - current state of the algorithm
+ **    zlock_read_cnt        - counts number of reads (up to 100)
+ **    zlock_read_data[i]    - counts number of times 'Zero' read was i, 0 <= i <= 15
+ **    zlock_sleep_cnt       - keeps track of "sleep" time (up to 300 secs = 5 minutes)
+ **                                
+ ** Parameters:    DRIVER_DATA    *bdp
+ **
+ **                bdp  - Pointer to HSM's adapter data space
+ **
+ ** Return Value:  NONE
+ **
+ ** See Also:      e100_watchdog()
+ **
+ \**************************************************************************/
+void
+e100_handle_zlock(struct e100_private *bdp)
+{
+       u16 pos;
+       u16 eq_reg;
+       u16 err_cnt;
+       u8 mpz;                 /* Most Popular Zero */
+
+       switch (bdp->zlock_state) {
+       case ZLOCK_INITIAL:
+
+               if (((u8) bdp->rev_id <= D102_REV_ID) ||
+                   !(bdp->cur_line_speed == 100) ||
+                   !netif_carrier_ok(bdp->device)) {
+                       break;
+               }
+
+               /* initialize hw and sw and start reading */
+               e100_mdi_write(bdp, PHY_82555_MDI_EQUALIZER_CSR,
+                              bdp->phy_addr, 0);
+               /* reset read counters: */
+               bdp->zlock_read_cnt = 0;
+               for (pos = 0; pos < 16; pos++)
+                       bdp->zlock_read_data[pos] = 0;
+               /* start reading in the next call back: */
+               bdp->zlock_state = ZLOCK_READING;
+
+               /* FALL THROUGH !! */
+
+       case ZLOCK_READING:
+               /* state: reading (100 times) zero locked in 1 sec interval
+                * prev states: ZLOCK_INITIAL
+                * next states: ZLOCK_INITIAL, ZLOCK_SLEEPING */
+
+               e100_mdi_read(bdp, PHY_82555_MDI_EQUALIZER_CSR,
+                             bdp->phy_addr, &eq_reg);
+               pos = (eq_reg & ZLOCK_ZERO_MASK) >> 4;
+               bdp->zlock_read_data[pos]++;
+               bdp->zlock_read_cnt++;
+
+               if (bdp->zlock_read_cnt == ZLOCK_MAX_READS) {
+                       /* check if we read a 'Zero' value of 0xB or greater */
+                       if ((bdp->zlock_read_data[0xB]) ||
+                           (bdp->zlock_read_data[0xC]) ||
+                           (bdp->zlock_read_data[0xD]) ||
+                           (bdp->zlock_read_data[0xE]) ||
+                           (bdp->zlock_read_data[0xF])) {
+
+                               /* we've read 'Zero' value of 0xB or greater,
+                                * find most popular 'Zero' value and lock it */
+                               mpz = 0;
+                               /* this loop finds the most popular 'Zero': */
+                               for (pos = 1; pos < 16; pos++) {
+                                       if (bdp->zlock_read_data[pos] >
+                                           bdp->zlock_read_data[mpz])
+
+                                               mpz = pos;
+                               }
+                               /* now lock the most popular 'Zero': */
+                               eq_reg = (ZLOCK_SET_ZERO | mpz);
+                               e100_mdi_write(bdp,
+                                              PHY_82555_MDI_EQUALIZER_CSR,
+                                              bdp->phy_addr, eq_reg);
+
+                               /* sleep for 5 minutes: */
+                               bdp->zlock_sleep_cnt = jiffies;
+                               bdp->zlock_state = ZLOCK_SLEEPING;
+                               /* we will be reading the # of errors after 5
+                                * minutes, so we need to reset the error
+                                * counters - these registers are self clearing
+                                * on read, so read them */
+                               e100_mdi_read(bdp, PHY_82555_SYMBOL_ERR,
+                                             bdp->phy_addr, &err_cnt);
+
+                       } else {
+                               /* we did not read a 'Zero' value of 0xB or
+                                * above. go back to the start */
+                               bdp->zlock_state = ZLOCK_INITIAL;
+                       }
+
+               }
+               break;
+
+       case ZLOCK_SLEEPING:
+               /* state: sleeping for 5 minutes
+                * prev states: ZLOCK_READING
+                * next states: ZLOCK_READING, ZLOCK_SLEEPING */
+
+               /* if 5 minutes have passed: */
+               if ((jiffies - bdp->zlock_sleep_cnt) >= ZLOCK_MAX_SLEEP) {
+                       /* read and sum up the number of errors:  */
+                       e100_mdi_read(bdp, PHY_82555_SYMBOL_ERR,
+                                     bdp->phy_addr, &err_cnt);
+                       /* if we've more than 300 errors (this number was
+                        * calculated according to the spec max allowed errors
+                        * (80 errors per 1 million frames) for 5 minutes in
+                        * 100 Mbps (or the user specified max BER number) */
+                       if (err_cnt > bdp->params.ber) {
+                               /* start again in the next callback: */
+                               bdp->zlock_state = ZLOCK_INITIAL;
+                       } else {
+                               /* we don't have more errors than allowed,
+                                * sleep for 5 minutes */
+                               bdp->zlock_sleep_cnt = jiffies;
+                       }
+               }
+               break;
+
+       default:
+               break;
+       }
+}
diff --git a/drivers/net/e100/e100_phy.h b/drivers/net/e100/e100_phy.h
new file mode 100644 (file)
index 0000000..ab819fc
--- /dev/null
@@ -0,0 +1,183 @@
+/*******************************************************************************
+
+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/100 Family of Adapters (e100) (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.
+*******************************************************************************/
+
+#ifndef _E100_PHY_INC_
+#define _E100_PHY_INC_
+
+#include "e100.h"
+
+#include <linux/mii.h>
+
+/*
+ * Auto-polarity enable/disable
+ * e100_autopolarity = 0 => disable auto-polarity
+ * e100_autopolarity = 1 => enable auto-polarity
+ * e100_autopolarity = 2 => let software determine
+ */
+#define E100_AUTOPOLARITY 2
+
+#define IS_NC3133(bdp) (((bdp)->pdev->subsystem_vendor == 0x0E11) && \
+                        ((bdp)->pdev->subsystem_device == 0xB0E1))
+
+#define PHY_503                 0
+#define PHY_100_A               0x000003E0
+#define PHY_100_C               0x035002A8
+#define PHY_NSC_TX              0x5c002000
+#define PHY_82562ET             0x033002A8
+#define PHY_82562EM             0x032002A8
+#define PHY_82562EH             0x017002A8
+#define PHY_82555_TX            0x015002a8     /* added this for 82555 */
+#define PHY_OTHER               0xFFFF
+#define MAX_PHY_ADDR            31
+#define MIN_PHY_ADDR            0
+
+#define PHY_MODEL_REV_ID_MASK   0xFFF0FFFF
+
+#define PHY_DEFAULT_ADDRESS 1
+#define PHY_ADDRESS_503 32
+
+/* MDI Control register bit definitions */
+#define MDI_PHY_READY      BIT_28      /* PHY is ready for next MDI cycle */
+
+#define MDI_NC3133_CONFIG_REG           0x19
+#define MDI_NC3133_100FX_ENABLE         BIT_2
+#define MDI_NC3133_INT_ENABLE_REG       0x17
+#define MDI_NC3133_INT_ENABLE           BIT_1
+
+/* MDI Control register opcode definitions */
+#define MDI_WRITE 1            /* Phy Write */
+#define MDI_READ  2            /* Phy read */
+
+/* MDI register set*/
+#define AUTO_NEG_NEXT_PAGE_REG     0x07        /* Auto-negotiation next page xmit */
+#define EXTENDED_REG_0             0x10        /* Extended reg 0 (Phy 100 modes) */
+#define EXTENDED_REG_1             0x14        /* Extended reg 1 (Phy 100 error indications) */
+#define NSC_CONG_CONTROL_REG       0x17        /* National (TX) congestion control */
+#define NSC_SPEED_IND_REG          0x19        /* National (TX) speed indication */
+
+/* ############Start of 82555 specific defines################## */
+
+/* Intel 82555 specific registers */
+#define PHY_82555_CSR              0x10        /* 82555 CSR */
+#define PHY_82555_SPECIAL_CONTROL   0x11       /* 82555 special control register */
+
+#define PHY_82555_RCV_ERR          0x15        /* 82555 100BaseTx Receive Error
+                                                * Frame Counter */
+#define PHY_82555_SYMBOL_ERR       0x16        /* 82555 RCV Symbol Error Counter */
+#define PHY_82555_PREM_EOF_ERR     0x17        /* 82555 100BaseTx RCV Premature End
+                                                * of Frame Error Counter */
+#define PHY_82555_EOF_COUNTER      0x18        /* 82555 end of frame error counter */
+#define PHY_82555_MDI_EQUALIZER_CSR 0x1a       /* 82555 specific equalizer reg. */
+
+/* 82555 CSR bits */
+#define PHY_82555_SPEED_BIT    BIT_1
+#define PHY_82555_POLARITY_BIT BIT_8
+
+/* 82555 equalizer reg. opcodes */
+#define ENABLE_ZERO_FORCING  0x2010    /* write to ASD conf. reg. 0 */
+#define DISABLE_ZERO_FORCING 0x2000    /* write to ASD conf. reg. 0 */
+
+/* 82555 special control reg. opcodes */
+#define DISABLE_AUTO_POLARITY 0x0010
+#define EXTENDED_SQUELCH_BIT  BIT_2
+
+/* ############End of 82555 specific defines##################### */
+
+/* Auto-Negotiation advertisement register bit definitions*/
+#define NWAY_AD_FC_SUPPORTED    0x0400 /* Flow Control supported */
+
+/* Auto-Negotiation link partner ability register bit definitions*/
+#define NWAY_LP_ABILITY                0x07e0  /* technologies supported */
+
+/* PHY 100 Extended Register 0 bit definitions*/
+#define PHY_100_ER0_FDX_INDIC  BIT_0   /* 1 = FDX, 0 = half duplex */
+#define PHY_100_ER0_SPEED_INDIC BIT_1  /* 1 = 100Mbps, 0= 10Mbps */
+
+/* National Semiconductor TX phy congestion control register bit definitions*/
+#define NSC_TX_CONG_TXREADY  BIT_10    /* Makes TxReady an input */
+#define NSC_TX_CONG_ENABLE   BIT_8     /* Enables congestion control */
+
+/* National Semiconductor TX phy speed indication register bit definitions*/
+#define NSC_TX_SPD_INDC_SPEED BIT_6    /* 0 = 100Mbps, 1=10Mbps */
+
+/************* function prototypes ************/
+extern unsigned char e100_phy_init(struct e100_private *bdp);
+extern unsigned char e100_update_link_state(struct e100_private *bdp);
+extern unsigned char e100_phy_check(struct e100_private *bdp);
+extern void e100_phy_set_speed_duplex(struct e100_private *bdp,
+                                     unsigned char force_restart);
+extern void e100_phy_reset(struct e100_private *bdp);
+extern void e100_mdi_write(struct e100_private *, u32, u32, u16);
+extern void e100_mdi_read(struct e100_private *, u32, u32, u16 *);
+
+#endif
diff --git a/drivers/net/e100/e100_proc.c b/drivers/net/e100/e100_proc.c
new file mode 100644 (file)
index 0000000..72d10d6
--- /dev/null
@@ -0,0 +1,925 @@
+/*******************************************************************************
+
+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/100 Family of Adapters (e100) (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.
+*******************************************************************************/
+
+/**********************************************************************
+*                                                                       *
+* INTEL CORPORATION                                                     *
+*                                                                       *
+* This software is supplied under the terms of the license included     *
+* above.  All use of this driver must be in accordance with the terms   *
+* of that license.                                                      *
+*                                                                       *
+* Module Name:  e100_proc.c                                             *
+*                                                                       *
+* Abstract:     Functions to handle the proc file system.               *
+*               Create the proc directories and files and run read and  *
+*               write requests from the user                            *
+*                                                                       *
+* Environment:  This file is intended to be specific to the Linux       *
+*               operating system.                                       *
+*                                                                       *
+**********************************************************************/
+
+#include <linux/config.h>
+
+#ifndef CONFIG_PROC_FS
+#undef E100_CONFIG_PROC_FS
+#endif
+
+#ifdef E100_CONFIG_PROC_FS
+#include "e100.h"
+
+/***************************************************************************/
+/*       /proc File System Interaface Support Functions                    */
+/***************************************************************************/
+
+static struct proc_dir_entry *adapters_proc_dir = 0;
+
+/* externs from e100_main.c */
+extern const char *e100_short_driver_name;
+extern const char *e100_version;
+extern struct net_device_stats *e100_get_stats(struct net_device *dev);
+extern char *e100_get_brand_msg(struct e100_private *bdp);
+extern void e100_mdi_write(struct e100_private *, u32, u32, u16);
+
+static void e100_proc_cleanup(void);
+static unsigned char e100_init_proc_dir(void);
+
+#define E100_EOU
+
+#define ADAPTERS_PROC_DIR "PRO_LAN_Adapters"
+#define WRITE_BUF_MAX_LEN 20   
+#define READ_BUF_MAX_LEN  256
+#define E100_PE_LEN       25
+
+#define bdp_drv_off(off) (unsigned long)(offsetof(struct e100_private, drv_stats.off))
+#define bdp_prm_off(off) (unsigned long)(offsetof(struct e100_private, params.off))
+
+typedef struct _e100_proc_entry {
+       char *name;
+       read_proc_t *read_proc;
+       write_proc_t *write_proc;
+       unsigned long offset;   /* offset into bdp. ~0 means no value, pass NULL. */
+} e100_proc_entry;
+
+static int
+generic_read(char *page, char **start, off_t off, int count, int *eof, int len)
+{
+       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
+read_ulong(char *page, char **start, off_t off,
+          int count, int *eof, unsigned long l)
+{
+       int len;
+
+       len = sprintf(page, "%lu\n", l);
+
+       return generic_read(page, start, off, count, eof, len);
+}
+
+static int
+read_gen_ulong(char *page, char **start, off_t off,
+              int count, int *eof, void *data)
+{
+       unsigned long val = 0;
+
+       if (data)
+               val = *((unsigned long *) data);
+
+       return read_ulong(page, start, off, count, eof, val);
+}
+
+static int
+read_hwaddr(char *page, char **start, off_t off,
+           int count, int *eof, unsigned char *hwaddr)
+{
+       int len;
+
+       len = sprintf(page, "%02X:%02X:%02X:%02X:%02X:%02X\n",
+                     hwaddr[0], hwaddr[1], hwaddr[2],
+                     hwaddr[3], hwaddr[4], hwaddr[5]);
+
+       return generic_read(page, start, off, count, eof, len);
+}
+
+static int
+read_descr(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+       struct e100_private *bdp = data;
+       int len;
+
+       len = sprintf(page, "%s\n", e100_get_brand_msg(bdp));
+
+       return generic_read(page, start, off, count, eof, len);
+}
+
+static int
+read_permanent_hwaddr(char *page, char **start, off_t off,
+                     int count, int *eof, void *data)
+{
+       struct e100_private *bdp = data;
+       unsigned char *hwaddr = bdp->perm_node_address;
+
+       return read_hwaddr(page, start, off, count, eof, hwaddr);
+}
+
+static int
+read_part_number(char *page, char **start, off_t off,
+                int count, int *eof, void *data)
+{
+       struct e100_private *bdp = data;
+       int len;
+
+       len = sprintf(page, "%06lx-%03x\n",
+                     (unsigned long) (bdp->pwa_no >> 8),
+                     (unsigned int) (bdp->pwa_no & 0xFF));
+
+       return generic_read(page, start, off, count, eof, len);
+}
+
+static void
+set_led(struct e100_private *bdp, u16 led_mdi_op)
+{
+       spin_lock_bh(&bdp->mdi_access_lock);
+
+       e100_mdi_write(bdp, PHY_82555_LED_SWITCH_CONTROL,
+                      bdp->phy_addr, led_mdi_op);
+
+       spin_unlock_bh(&bdp->mdi_access_lock);
+
+       set_current_state(TASK_UNINTERRUPTIBLE);
+       schedule_timeout(SLEEP_TIME);
+
+       spin_lock_bh(&bdp->mdi_access_lock);
+
+       /* turn led ownership to the chip */
+       e100_mdi_write(bdp, PHY_82555_LED_SWITCH_CONTROL,
+                      bdp->phy_addr, PHY_82555_LED_NORMAL_CONTROL);
+
+       spin_unlock_bh(&bdp->mdi_access_lock);
+}
+
+static int
+write_blink_led_timer(struct file *file, const char *buffer,
+                     unsigned long count, void *data)
+{
+       struct e100_private *bdp = data;
+       char s_blink_op[WRITE_BUF_MAX_LEN + 1];
+       char *res;
+       unsigned long i_blink_op;
+
+       if (!buffer)
+               return -EINVAL;
+
+       if (count > WRITE_BUF_MAX_LEN) {
+               count = WRITE_BUF_MAX_LEN;
+       }
+       copy_from_user(s_blink_op, buffer, count);
+       s_blink_op[count] = '\0';
+       i_blink_op = simple_strtoul(s_blink_op, &res, 0);
+       if (res == s_blink_op) {
+               return -EINVAL;
+       }
+
+       switch (i_blink_op) {
+
+       case LED_OFF:
+               set_led(bdp, PHY_82555_LED_OFF);
+               break;
+       case LED_ON:
+               if (bdp->rev_id >= D101MA_REV_ID)
+                       set_led(bdp, PHY_82555_LED_ON_559);
+               else
+                       set_led(bdp, PHY_82555_LED_ON_PRE_559);
+
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return count;
+}
+
+static e100_proc_entry e100_proc_list[] = {
+       {"Description",           read_descr,            0, 0},
+       {"Permanent_HWaddr",      read_permanent_hwaddr, 0, 0},
+       {"Part_Number",           read_part_number,      0, 0},
+       {"\n",},
+       {"Rx_TCP_Checksum_Good",  read_gen_ulong, 0, ~0},
+       {"Rx_TCP_Checksum_Bad",   read_gen_ulong, 0, ~0},
+       {"Tx_TCP_Checksum_Good",  read_gen_ulong, 0, ~0},
+       {"Tx_TCP_Checksum_Bad",   read_gen_ulong, 0, ~0},
+       {"\n",},
+       {"Tx_Abort_Late_Coll",    read_gen_ulong, 0, bdp_drv_off(tx_late_col)},
+       {"Tx_Deferred_Ok",        read_gen_ulong, 0, bdp_drv_off(tx_ok_defrd)},
+       {"Tx_Single_Coll_Ok",     read_gen_ulong, 0, bdp_drv_off(tx_one_retry)},
+       {"Tx_Multi_Coll_Ok",      read_gen_ulong, 0, bdp_drv_off(tx_mt_one_retry)},
+       {"Rx_Long_Length_Errors", read_gen_ulong, 0, ~0},
+       {"\n",},
+       {"Tx_Flow_Control_Pause", read_gen_ulong, 0, bdp_drv_off(xmt_fc_pkts)},
+       {"Rx_Flow_Control_Pause", read_gen_ulong, 0, bdp_drv_off(rcv_fc_pkts)},
+       {"Rx_Flow_Control_Unsup", read_gen_ulong, 0, bdp_drv_off(rcv_fc_unsupported)},
+       {"\n",},
+       {"Tx_TCO_Packets",        read_gen_ulong, 0, bdp_drv_off(xmt_tco_pkts)},
+       {"Rx_TCO_Packets",        read_gen_ulong, 0, bdp_drv_off(rcv_tco_pkts)},
+       {"\n",},
+       {"Rx_Interrupt_Packets",  read_gen_ulong, 0, bdp_drv_off(rx_intr_pkts)},
+       {"Rx_Polling_Packets",    read_gen_ulong, 0, bdp_drv_off(rx_tasklet_pkts)},
+       {"Polling_Interrupt_Switch", read_gen_ulong, 0, bdp_drv_off(poll_intr_switch)},
+       {"Identify_Adapter", 0, write_blink_led_timer, 0},
+       {"", 0, 0, 0}
+};
+
+static int
+read_info(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+       struct e100_private *bdp = data;
+       e100_proc_entry *pe;
+       int tmp;
+       void *val;
+       int len = 0;
+
+       for (pe = e100_proc_list; pe->name[0]; pe++) {
+               if (pe->name[0] == '\n') {
+                       len += sprintf(page + len, "\n");
+                       continue;
+               }
+
+               if (pe->read_proc) {
+                       if ((len + READ_BUF_MAX_LEN + E100_PE_LEN + 1) >=
+                           PAGE_SIZE)
+                               break;
+
+                       if (pe->offset != ~0)
+                               val = ((char *) bdp) + pe->offset;
+                       else
+                               val = NULL;
+
+                       len += sprintf(page + len, "%-"
+                                      __MODULE_STRING(E100_PE_LEN)
+                                      "s ", pe->name);
+                       len += pe->read_proc(page + len, start, 0,
+                                            READ_BUF_MAX_LEN + 1, &tmp, val);
+               }
+       }
+
+       return generic_read(page, start, off, count, eof, len);
+}
+
+#ifdef E100_EOU
+/**********************
+ *  parameter entries
+ **********************/
+static int
+read_int_param(char *page, char *name, char *desc, int def, int min, int max)
+{
+       int len;
+
+       len = sprintf(page, "Name: %s\n", name);
+       len += sprintf(page + len, "Description: %s\n", desc);
+       len += sprintf(page + len, "Default_Value: %d\n", def);
+       len += sprintf(page + len, "Type: Range\n");
+       len += sprintf(page + len, "Min: %d\n", min);
+       len += sprintf(page + len, "Max: %d\n", max);
+       len += sprintf(page + len, "Step:1\n");
+       len += sprintf(page + len, "Radix: dec\n");
+
+       return len;
+}
+
+static int
+read_bool_param(char *page, char *name, char *desc, int def)
+{
+       int len;
+
+       len = sprintf(page, "Name: %s\n", name);
+       len += sprintf(page + len, "Description: %s\n", desc);
+       len += sprintf(page + len, "Default_Value: %d\n", def);
+       len += sprintf(page + len, "Type: Enum\n");
+       len += sprintf(page + len, "0: Off\n");
+       len += sprintf(page + len, "1: On\n");
+
+       return len;
+}
+
+static int
+read_speed_duplex_def(char *page, char **start, off_t off,
+                     int count, int *eof, void *data)
+{
+       int len;
+
+       len = sprintf(page, "Name: Speed and Duplex\n");
+       len += sprintf(page + len, "Description: Sets the adapter's "
+                      "speed and duplex mode\n");
+       len += sprintf(page + len, "Default_Value: 0\n");
+       len += sprintf(page + len, "Type: Enum\n");
+       len += sprintf(page + len, "0: Auto-Negotiate\n");
+       len += sprintf(page + len, "1: 10 Mbps / Half Duplex\n");
+       len += sprintf(page + len, "2: 10 Mbps / Full Duplex\n");
+       len += sprintf(page + len, "3: 100 Mbps / Half Duplex\n");
+       len += sprintf(page + len, "4: 100 Mbps / Full Duplex\n");
+
+       return generic_read(page, start, off, count, eof, len);
+}
+
+static int
+read_tx_desc_def(char *page, char **start, off_t off,
+                int count, int *eof, void *data)
+{
+       int len;
+
+       len = read_int_param(page, "Transmit Descriptors",
+                            "Sets the number of Tx descriptors "
+                            "available for the adapter",
+                            E100_DEFAULT_TCB, E100_MIN_TCB, E100_MAX_TCB);
+       return generic_read(page, start, off, count, eof, len);
+}
+
+static int
+read_rx_desc_def(char *page, char **start, off_t off,
+                int count, int *eof, void *data)
+{
+       int len;
+
+       len = read_int_param(page, "Receive Descriptors",
+                            "Sets the number of Rx descriptors "
+                            "available for the adapter",
+                            E100_DEFAULT_RFD, E100_MIN_RFD, E100_MAX_RFD);
+       return generic_read(page, start, off, count, eof, len);
+}
+
+static int
+read_ber_def(char *page, char **start, off_t off,
+            int count, int *eof, void *data)
+{
+       int len;
+
+       len = read_int_param(page, "Bit Error Rate",
+                            "Sets the value for the BER correction algorithm",
+                            E100_DEFAULT_BER, 0, ZLOCK_MAX_ERRORS);
+
+       return generic_read(page, start, off, count, eof, len);
+}
+
+static int
+read_xsum_rx_def(char *page, char **start, off_t off,
+                int count, int *eof, void *data)
+{
+       int len;
+
+       len = read_bool_param(page, "RX Checksum",
+                             "Setting this value to \"On\" enables "
+                             "receive checksum", E100_DEFAULT_XSUM);
+
+       return generic_read(page, start, off, count, eof, len);
+}
+
+static int
+read_ucode_def(char *page, char **start, off_t off,
+              int count, int *eof, void *data)
+{
+       int len;
+
+       len = read_bool_param(page, "Microcode",
+                             "Setting this value to \"On\" enables "
+                             "the adapter's microcode", E100_DEFAULT_UCODE);
+
+       return generic_read(page, start, off, count, eof, len);
+}
+
+static int
+read_bundle_small_def(char *page, char **start, off_t off,
+                     int count, int *eof, void *data)
+{
+       int len;
+
+       len = read_bool_param(page, "Bundle Small Frames",
+                             "Setting this value to \"On\" enables "
+                             "interrupt bundling of small frames",
+                             E100_DEFAULT_BUNDLE_SMALL_FR);
+
+       return generic_read(page, start, off, count, eof, len);
+}
+
+static int
+read_fc_def(char *page, char **start, off_t off,
+           int count, int *eof, void *data)
+{
+       int len;
+
+       len = read_bool_param(page, "Flow Control",
+                             "Setting this value to \"On\" enables processing "
+                             "flow-control packets", E100_DEFAULT_FC);
+
+       return generic_read(page, start, off, count, eof, len);
+}
+
+static int
+read_rcv_cong_def(char *page, char **start, off_t off,
+                 int count, int *eof, void *data)
+{
+       int len;
+
+       len = read_bool_param(page, "Receive Congestion Control",
+                             "Setting this value to \"On\" enables switching "
+                             "to polling mode on receive",
+                             E100_DEFAULT_RX_CONGESTION_CONTROL);
+
+       return generic_read(page, start, off, count, eof, len);
+}
+
+static int
+read_poll_max_def(char *page, char **start, off_t off,
+                 int count, int *eof, void *data)
+{
+       struct e100_private *bdp = data;
+
+       int len;
+
+       len = read_int_param(page, "Maximum Polling Work",
+                            "Sets the max number of RX packets processed"
+                            " by single polling function call",
+                            bdp->params.RxDescriptors, 1, E100_MAX_RFD);
+
+       return generic_read(page, start, off, count, eof, len);
+}
+
+static int
+read_int_delay_def(char *page, char **start, off_t off,
+                  int count, int *eof, void *data)
+{
+       int len;
+
+       len = read_int_param(page, "CPU Saver Interrupt Delay",
+                            "Sets the value for CPU saver's interrupt delay",
+                            E100_DEFAULT_CPUSAVER_INTERRUPT_DELAY, 0x0,
+                            0xFFFF);
+
+       return generic_read(page, start, off, count, eof, len);
+}
+
+static int
+read_bundle_max_def(char *page, char **start, off_t off,
+                   int count, int *eof, void *data)
+{
+       int len;
+
+       len = read_int_param(page, "CPU Saver Maximum Bundle",
+                            "Sets the value for CPU saver's maximum value",
+                            E100_DEFAULT_CPUSAVER_BUNDLE_MAX, 0x1, 0xFFFF);
+
+       return generic_read(page, start, off, count, eof, len);
+}
+
+static int
+read_ifs_def(char *page, char **start, off_t off,
+            int count, int *eof, void *data)
+{
+       int len;
+
+       len = read_bool_param(page, "IFS",
+                             "Setting this value to \"On\" enables "
+                             "the adaptive IFS algorithm", E100_DEFAULT_IFS);
+
+       return generic_read(page, start, off, count, eof, len);
+}
+
+static int
+read_xsum_rx_val(char *page, char **start, off_t off,
+                int count, int *eof, void *data)
+{
+       struct e100_private *bdp = data;
+       unsigned long val;
+
+       val = (bdp->params.b_params & PRM_XSUMRX) ? 1 : 0;
+       return read_ulong(page, start, off, count, eof, val);
+}
+
+static int
+read_ucode_val(char *page, char **start, off_t off,
+              int count, int *eof, void *data)
+{
+       struct e100_private *bdp = data;
+       unsigned long val;
+
+       val = (bdp->params.b_params & PRM_UCODE) ? 1 : 0;
+       return read_ulong(page, start, off, count, eof, val);
+}
+
+static int
+read_fc_val(char *page, char **start, off_t off,
+           int count, int *eof, void *data)
+{
+       struct e100_private *bdp = data;
+       unsigned long val;
+
+       val = (bdp->params.b_params & PRM_FC) ? 1 : 0;
+       return read_ulong(page, start, off, count, eof, val);
+}
+
+static int
+read_ifs_val(char *page, char **start, off_t off,
+            int count, int *eof, void *data)
+{
+       struct e100_private *bdp = data;
+       unsigned long val;
+
+       val = (bdp->params.b_params & PRM_IFS) ? 1 : 0;
+       return read_ulong(page, start, off, count, eof, val);
+}
+
+static int
+read_bundle_small_val(char *page, char **start, off_t off,
+                     int count, int *eof, void *data)
+{
+       struct e100_private *bdp = data;
+       unsigned long val;
+
+       val = (bdp->params.b_params & PRM_BUNDLE_SMALL) ? 1 : 0;
+       return read_ulong(page, start, off, count, eof, val);
+}
+
+static int
+read_rcv_cong_val(char *page, char **start, off_t off,
+                 int count, int *eof, void *data)
+{
+       struct e100_private *bdp = data;
+       unsigned long val;
+
+       val = (bdp->params.b_params & PRM_RX_CONG) ? 1 : 0;
+       return read_ulong(page, start, off, count, eof, val);
+}
+
+static int
+read_gen_prm(char *page, char **start, off_t off,
+            int count, int *eof, void *data)
+{
+       int val = 0;
+
+       if (data)
+               val = *((int *) data);
+
+       return read_ulong(page, start, off, count, eof, (unsigned long) val);
+}
+
+static e100_proc_entry e100_proc_params[] = { 
+       /* definitions */
+       {"e100_speed_duplex.def", read_speed_duplex_def, 0, 0},
+       {"RxDescriptors.def",     read_rx_desc_def,      0, 0},
+       {"TxDescriptors.def",     read_tx_desc_def,      0, 0},
+       {"XsumRX.def",            read_xsum_rx_def,      0, 0},
+       {"ucode.def",             read_ucode_def,        0, 0},
+       {"BundleSmallFr.def",     read_bundle_small_def, 0, 0},
+       {"IntDelay.def",          read_int_delay_def,    0, 0},
+       {"BundleMax.def",         read_bundle_max_def,   0, 0},
+       {"ber.def",               read_ber_def,          0, 0},
+       {"flow_control.def",      read_fc_def,           0, 0},
+       {"IFS.def",               read_ifs_def,          0, 0},
+       {"RxCongestionControl.def", read_rcv_cong_def,   0, 0},
+       {"PollingMaxWork.def",      read_poll_max_def,   0, 0},
+       /* values */
+       {"e100_speed_duplex.val", read_gen_prm, 0, bdp_prm_off(e100_speed_duplex)},
+       {"RxDescriptors.val",     read_gen_prm, 0, bdp_prm_off(RxDescriptors)},
+       {"TxDescriptors.val",     read_gen_prm, 0, bdp_prm_off(TxDescriptors)},
+       {"XsumRX.val",            read_xsum_rx_val,      0, 0},
+       {"ucode.val",             read_ucode_val,        0, 0},
+       {"BundleSmallFr.val",     read_bundle_small_val, 0, 0},
+       {"IntDelay.val",          read_gen_prm, 0, bdp_prm_off(IntDelay)},
+       {"BundleMax.val",         read_gen_prm, 0, bdp_prm_off(BundleMax)},
+       {"ber.val",               read_gen_prm, 0, bdp_prm_off(ber)},
+       {"flow_control.val",      read_fc_val,           0, 0},
+       {"IFS.val",               read_ifs_val,          0, 0},
+       {"RxCongestionControl.val", read_rcv_cong_val,   0, 0},
+       {"PollingMaxWork.val",      read_gen_prm, 0, bdp_prm_off(PollingMaxWork)},
+       {"", 0, 0, 0}
+};
+#endif /* E100_EOU */
+
+static struct proc_dir_entry * __devinit
+create_proc_rw(char *name, void *data, struct proc_dir_entry *parent,
+              read_proc_t * read_proc, write_proc_t * write_proc)
+{
+       struct proc_dir_entry *pdep;
+       mode_t mode = S_IFREG;
+
+       if (write_proc) {
+               mode |= S_IWUSR;
+               if (read_proc) {
+                       mode |= S_IRUSR;
+               }
+
+       } else if (read_proc) {
+               mode |= S_IRUGO;
+       }
+
+       if (!(pdep = create_proc_entry(name, mode, parent)))
+               return NULL;
+
+       pdep->read_proc = read_proc;
+       pdep->write_proc = write_proc;
+       pdep->data = data;
+       return pdep;
+}
+
+#ifdef E100_EOU
+static int __devinit
+create_proc_param_subdir(struct e100_private *bdp,
+                        struct proc_dir_entry *dev_dir)
+{
+       struct proc_dir_entry *param_dir;
+       e100_proc_entry *pe;
+       void *data;
+
+       param_dir = create_proc_entry("LoadParameters", S_IFDIR, dev_dir);
+       if (!param_dir)
+               return -ENOMEM;
+
+       for (pe = e100_proc_params; pe->name[0]; pe++) {
+
+               data = ((char *) bdp) + pe->offset;
+
+               if (!(create_proc_rw(pe->name, data, param_dir,
+                                    pe->read_proc, pe->write_proc))) {
+                       return -ENOMEM;
+               }
+       }
+
+       return 0;
+}
+
+static void
+remove_proc_param_subdir(struct proc_dir_entry *parent)
+{
+       struct proc_dir_entry *de;
+       e100_proc_entry *pe;
+       int len;
+
+       len = strlen("LoadParameters");
+
+       for (de = parent->subdir; de; de = de->next) {
+               if ((de->namelen == len) &&
+                   (!memcmp(de->name, "LoadParameters", len)))
+                       break;
+       }
+
+       if (!de)
+               return;
+
+       for (pe = e100_proc_params; pe->name[0]; pe++) {
+               remove_proc_entry(pe->name, de);
+       }
+
+       remove_proc_entry("LoadParameters", parent);
+}
+#endif /* E100_EOU */
+
+void
+e100_remove_proc_subdir(struct e100_private *bdp)
+{
+       e100_proc_entry *pe;
+       char info[256];
+       int len;
+
+       /* If our root /proc dir was not created, there is nothing to remove */
+       if (adapters_proc_dir == NULL) {
+               return;
+       }
+
+       len = strlen(bdp->device->name);
+       strncpy(info, bdp->device->name, sizeof (info));
+       strncat(info + len, ".info", sizeof (info) - len);
+
+       if (bdp->proc_parent) {
+               for (pe = e100_proc_list; pe->name[0]; pe++) {
+                       if (pe->name[0] == '\n')
+                               continue;
+
+                       remove_proc_entry(pe->name, bdp->proc_parent);
+               }
+
+#ifdef E100_EOU
+               remove_proc_param_subdir(bdp->proc_parent);
+#endif
+               remove_proc_entry(bdp->device->name, adapters_proc_dir);
+               bdp->proc_parent = NULL;
+       }
+
+       remove_proc_entry(info, adapters_proc_dir);
+
+       /* try to remove the main /proc dir, if it's empty */
+       e100_proc_cleanup();
+}
+
+int __devinit
+e100_create_proc_subdir(struct e100_private *bdp)
+{
+       struct proc_dir_entry *dev_dir;
+       e100_proc_entry *pe;
+       char info[256];
+       int len;
+       void *data;
+
+       /* create the main /proc dir if needed */
+       if (!adapters_proc_dir) {
+               if (!e100_init_proc_dir())
+                       return -ENOMEM;
+       }
+
+       strncpy(info, bdp->device->name, sizeof (info));
+       len = strlen(info);
+       strncat(info + len, ".info", sizeof (info) - len);
+
+       /* info */
+       if (!(create_proc_rw(info, bdp, adapters_proc_dir, read_info, 0))) {
+               e100_proc_cleanup();
+               return -ENOMEM;
+       }
+
+       dev_dir = create_proc_entry(bdp->device->name, S_IFDIR,
+                                   adapters_proc_dir);
+       bdp->proc_parent = dev_dir;
+
+       if (!dev_dir) {
+               e100_remove_proc_subdir(bdp);
+               return -ENOMEM;
+       }
+
+       for (pe = e100_proc_list; pe->name[0]; pe++) {
+               if (pe->name[0] == '\n')
+                       continue;
+
+               if (pe->offset != ~0)
+                       data = ((char *) bdp) + pe->offset;
+               else
+                       data = NULL;
+
+               if (!(create_proc_rw(pe->name, data, dev_dir,
+                                    pe->read_proc, pe->write_proc))) {
+                       e100_remove_proc_subdir(bdp);
+                       return -ENOMEM;
+               }
+       }
+
+#ifdef E100_EOU
+       if (create_proc_param_subdir(bdp, dev_dir)) {
+               e100_remove_proc_subdir(bdp);
+               return -ENOMEM;
+       }
+#endif
+
+       return 0;
+}
+
+/****************************************************************************
+ * Name:          e100_init_proc_dir
+ *
+ * Description:   This routine creates the top-level /proc directory for the
+ *                driver in /proc/net
+ *
+ * Arguments:     none
+ *
+ * Returns:       true on success, false on fail
+ *
+ ***************************************************************************/
+static unsigned char
+e100_init_proc_dir(void)
+{
+       int len;
+
+       /* first check if adapters_proc_dir already exists */
+       len = strlen(ADAPTERS_PROC_DIR);
+       for (adapters_proc_dir = proc_net->subdir;
+            adapters_proc_dir; adapters_proc_dir = adapters_proc_dir->next) {
+
+               if ((adapters_proc_dir->namelen == len) &&
+                   (!memcmp(adapters_proc_dir->name, ADAPTERS_PROC_DIR, len)))
+                       break;
+       }
+
+       if (!adapters_proc_dir)
+               adapters_proc_dir =
+                       create_proc_entry(ADAPTERS_PROC_DIR, S_IFDIR, proc_net);
+
+       if (!adapters_proc_dir)
+               return false;
+
+       return true;
+}
+
+/****************************************************************************
+ * Name:          e100_proc_cleanup
+ *
+ * Description:   This routine clears the top-level /proc directory, if empty.
+ *
+ * Arguments:     none
+ *
+ * Returns:       none
+ *
+ ***************************************************************************/
+static void
+e100_proc_cleanup(void)
+{
+       struct proc_dir_entry *de;
+
+       if (adapters_proc_dir == NULL) {
+               return;
+       }
+
+       /* check if subdir list is empty before removing adapters_proc_dir */
+       for (de = adapters_proc_dir->subdir; de; de = de->next) {
+               /* ignore . and .. */
+               if (*(de->name) != '.')
+                       break;
+       }
+
+       if (de)
+               return;
+
+       remove_proc_entry(ADAPTERS_PROC_DIR, proc_net);
+       adapters_proc_dir = NULL;
+}
+
+#endif /* CONFIG_PROC_FS */
diff --git a/drivers/net/e100/e100_ucode.h b/drivers/net/e100/e100_ucode.h
new file mode 100644 (file)
index 0000000..b318ff7
--- /dev/null
@@ -0,0 +1,411 @@
+/*******************************************************************************
+
+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/100 Family of Adapters (e100) (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.
+*******************************************************************************/
+
+#ifndef _E100_UCODE_H_
+#define _E100_UCODE_H_
+
+/*
+e100_ucode.h
+
+This file contains the loadable micro code arrays to implement receive 
+bundling on the D101 A-step, D101 B-step, D101M (B-step only), D101S, 
+D102 B-step, D102 B-step with TCO work around and D102 C-step.
+
+Each controller has its own specific micro code array.  The array for one 
+controller is totally incompatible with any other controller, and if used 
+will most likely cause the controller to lock up and stop responding to 
+the driver.  Each micro code array has its own parameter offsets (described 
+below), and they each have their own version number.
+*/
+
+/*************************************************************************
+*  CPUSaver parameters
+*
+*  All CPUSaver parameters are 16-bit literals that are part of a
+*  "move immediate value" instruction.  By changing the value of
+*  the literal in the instruction before the code is loaded, the
+*  driver can change algorithm.
+*
+*  CPUSAVER_DWORD - This is the location of the instruction that loads
+*    the dead-man timer with its inital value.  By writing a 16-bit
+*    value to the low word of this instruction, the driver can change
+*    the timer value.  The current default is either x600 or x800;
+*    experiments show that the value probably should stay within the
+*    range of x200 - x1000.
+*
+*  CPUSAVER_BUNDLE_MAX_DWORD - This is the location of the instruction
+*    that sets the maximum number of frames that will be bundled.  In
+*    some situations, such as the TCP windowing algorithm, it may be
+*    better to limit the growth of the bundle size than let it go as
+*    high as it can, because that could cause too much added latency.
+*    The default is six, because this is the number of packets in the
+*    default TCP window size.  A value of 1 would make CPUSaver indicate
+*    an interrupt for every frame received.  If you do not want to put
+*    a limit on the bundle size, set this value to xFFFF.
+*
+*  CPUSAVER_MIN_SIZE_DWORD - This is the location of the instruction
+*    that contains a bit-mask describing the minimum size frame that
+*    will be bundled.  The default masks the lower 7 bits, which means
+*    that any frame less than 128 bytes in length will not be bundled,
+*    but will instead immediately generate an interrupt.  This does
+*    not affect the current bundle in any way.  Any frame that is 128
+*    bytes or large will be bundled normally.  This feature is meant
+*    to provide immediate indication of ACK frames in a TCP environment.
+*    Customers were seeing poor performance when a machine with CPUSaver
+*    enabled was sending but not receiving.  The delay introduced when
+*    the ACKs were received was enough to reduce total throughput, because
+*    the sender would sit idle until the ACK was finally seen.
+*
+*    The current default is 0xFF80, which masks out the lower 7 bits.
+*    This means that any frame which is x7F (127) bytes or smaller
+*    will cause an immediate interrupt.  Because this value must be a 
+*    bit mask, there are only a few valid values that can be used.  To
+*    turn this feature off, the driver can write the value xFFFF to the
+*    lower word of this instruction (in the same way that the other
+*    parameters are used).  Likewise, a value of 0xF800 (2047) would
+*    cause an interrupt to be generated for every frame, because all
+*    standard Ethernet frames are <= 2047 bytes in length.
+*************************************************************************/
+
+#ifndef UCODE_MAX_DWORDS
+#define UCODE_MAX_DWORDS       134
+#endif
+
+/********************************************************/
+/*  CPUSaver micro code for the D101A                   */
+/********************************************************/
+
+/*  Version 2.0  */
+
+/*  This value is the same for both A and B step of 558.  */
+
+#define D101_CPUSAVER_TIMER_DWORD              72
+#define D101_CPUSAVER_BUNDLE_DWORD             UCODE_MAX_DWORDS
+#define D101_CPUSAVER_MIN_SIZE_DWORD           UCODE_MAX_DWORDS
+
+#define     D101_A_RCVBUNDLE_UCODE \
+{\
+0x03B301BB, 0x0046FFFF, 0xFFFFFFFF, 0x051DFFFF, 0xFFFFFFFF, 0xFFFFFFFF, \
+0x000C0001, 0x00101212, 0x000C0008, 0x003801BC, \
+0x00000000, 0x00124818, 0x000C1000, 0x00220809, \
+0x00010200, 0x00124818, 0x000CFFFC, 0x003803B5, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x0010009C, 0x0024B81D, 0x00130836, 0x000C0001, \
+0x0026081C, 0x0020C81B, 0x00130824, 0x00222819, \
+0x00101213, 0x00041000, 0x003A03B3, 0x00010200, \
+0x00101B13, 0x00238081, 0x00213049, 0x0038003B, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x0010009C, 0x0024B83E, 0x00130826, 0x000C0001, \
+0x0026083B, 0x00010200, 0x00134824, 0x000C0001, \
+0x00101213, 0x00041000, 0x0038051E, 0x00101313, \
+0x00010400, 0x00380521, 0x00050600, 0x00100824, \
+0x00101310, 0x00041000, 0x00080600, 0x00101B10, \
+0x0038051E, 0x00000000, 0x00000000, 0x00000000  \
+}
+
+/********************************************************/
+/*  CPUSaver micro code for the D101B                   */
+/********************************************************/
+
+/*  Version 2.0  */
+
+#define     D101_B0_RCVBUNDLE_UCODE \
+{\
+0x03B401BC, 0x0047FFFF, 0xFFFFFFFF, 0x051EFFFF, 0xFFFFFFFF, 0xFFFFFFFF, \
+0x000C0001, 0x00101B92, 0x000C0008, 0x003801BD, \
+0x00000000, 0x00124818, 0x000C1000, 0x00220809, \
+0x00010200, 0x00124818, 0x000CFFFC, 0x003803B6, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x0010009C, 0x0024B81D, 0x0013082F, 0x000C0001, \
+0x0026081C, 0x0020C81B, 0x00130837, 0x00222819, \
+0x00101B93, 0x00041000, 0x003A03B4, 0x00010200, \
+0x00101793, 0x00238082, 0x0021304A, 0x0038003C, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x0010009C, 0x0024B83E, 0x00130826, 0x000C0001, \
+0x0026083B, 0x00010200, 0x00134837, 0x000C0001, \
+0x00101B93, 0x00041000, 0x0038051F, 0x00101313, \
+0x00010400, 0x00380522, 0x00050600, 0x00100837, \
+0x00101310, 0x00041000, 0x00080600, 0x00101790, \
+0x0038051F, 0x00000000, 0x00000000, 0x00000000  \
+}
+
+/********************************************************/
+/*  CPUSaver micro code for the D101M (B-step only)     */
+/********************************************************/
+
+/*  Version 2.10.1  */
+
+/*  Parameter values for the D101M B-step  */
+#define D101M_CPUSAVER_TIMER_DWORD             78
+#define D101M_CPUSAVER_BUNDLE_DWORD            65
+#define D101M_CPUSAVER_MIN_SIZE_DWORD          126
+
+#define D101M_B_RCVBUNDLE_UCODE \
+{\
+0x00550215, 0xFFFF0437, 0xFFFFFFFF, 0x06A70789, 0xFFFFFFFF, 0x0558FFFF, \
+0x000C0001, 0x00101312, 0x000C0008, 0x00380216, \
+0x0010009C, 0x00204056, 0x002380CC, 0x00380056, \
+0x0010009C, 0x00244C0B, 0x00000800, 0x00124818, \
+0x00380438, 0x00000000, 0x00140000, 0x00380555, \
+0x00308000, 0x00100662, 0x00100561, 0x000E0408, \
+0x00134861, 0x000C0002, 0x00103093, 0x00308000, \
+0x00100624, 0x00100561, 0x000E0408, 0x00100861, \
+0x000C007E, 0x00222C21, 0x000C0002, 0x00103093, \
+0x00380C7A, 0x00080000, 0x00103090, 0x00380C7A, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x0010009C, 0x00244C2D, 0x00010004, 0x00041000, \
+0x003A0437, 0x00044010, 0x0038078A, 0x00000000, \
+0x00100099, 0x00206C7A, 0x0010009C, 0x00244C48, \
+0x00130824, 0x000C0001, 0x00101213, 0x00260C75, \
+0x00041000, 0x00010004, 0x00130826, 0x000C0006, \
+0x002206A8, 0x0013C926, 0x00101313, 0x003806A8, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00080600, 0x00101B10, 0x00050004, 0x00100826, \
+0x00101210, 0x00380C34, 0x00000000, 0x00000000, \
+0x0021155B, 0x00100099, 0x00206559, 0x0010009C, \
+0x00244559, 0x00130836, 0x000C0000, 0x00220C62, \
+0x000C0001, 0x00101B13, 0x00229C0E, 0x00210C0E, \
+0x00226C0E, 0x00216C0E, 0x0022FC0E, 0x00215C0E, \
+0x00214C0E, 0x00380555, 0x00010004, 0x00041000, \
+0x00278C67, 0x00040800, 0x00018100, 0x003A0437, \
+0x00130826, 0x000C0001, 0x00220559, 0x00101313, \
+0x00380559, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00130831, 0x0010090B, 0x00124813, \
+0x000CFF80, 0x002606AB, 0x00041000, 0x00010004, \
+0x003806A8, 0x00000000, 0x00000000, 0x00000000, \
+}
+
+/********************************************************/
+/*  CPUSaver micro code for the D101S                   */
+/********************************************************/
+
+/*  Version 1.20.1  */
+
+/*  Parameter values for the D101S  */
+#define D101S_CPUSAVER_TIMER_DWORD             78
+#define D101S_CPUSAVER_BUNDLE_DWORD            67
+#define D101S_CPUSAVER_MIN_SIZE_DWORD          128
+
+#define D101S_RCVBUNDLE_UCODE \
+{\
+0x00550242, 0xFFFF047E, 0xFFFFFFFF, 0x06FF0818, 0xFFFFFFFF, 0x05A6FFFF, \
+0x000C0001, 0x00101312, 0x000C0008, 0x00380243, \
+0x0010009C, 0x00204056, 0x002380D0, 0x00380056, \
+0x0010009C, 0x00244F8B, 0x00000800, 0x00124818, \
+0x0038047F, 0x00000000, 0x00140000, 0x003805A3, \
+0x00308000, 0x00100610, 0x00100561, 0x000E0408, \
+0x00134861, 0x000C0002, 0x00103093, 0x00308000, \
+0x00100624, 0x00100561, 0x000E0408, 0x00100861, \
+0x000C007E, 0x00222FA1, 0x000C0002, 0x00103093, \
+0x00380F90, 0x00080000, 0x00103090, 0x00380F90, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x0010009C, 0x00244FAD, 0x00010004, 0x00041000, \
+0x003A047E, 0x00044010, 0x00380819, 0x00000000, \
+0x00100099, 0x00206FFD, 0x0010009A, 0x0020AFFD, \
+0x0010009C, 0x00244FC8, 0x00130824, 0x000C0001, \
+0x00101213, 0x00260FF7, 0x00041000, 0x00010004, \
+0x00130826, 0x000C0006, 0x00220700, 0x0013C926, \
+0x00101313, 0x00380700, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00080600, 0x00101B10, 0x00050004, 0x00100826, \
+0x00101210, 0x00380FB6, 0x00000000, 0x00000000, \
+0x002115A9, 0x00100099, 0x002065A7, 0x0010009A, \
+0x0020A5A7, 0x0010009C, 0x002445A7, 0x00130836, \
+0x000C0000, 0x00220FE4, 0x000C0001, 0x00101B13, \
+0x00229F8E, 0x00210F8E, 0x00226F8E, 0x00216F8E, \
+0x0022FF8E, 0x00215F8E, 0x00214F8E, 0x003805A3, \
+0x00010004, 0x00041000, 0x00278FE9, 0x00040800, \
+0x00018100, 0x003A047E, 0x00130826, 0x000C0001, \
+0x002205A7, 0x00101313, 0x003805A7, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00130831, \
+0x0010090B, 0x00124813, 0x000CFF80, 0x00260703, \
+0x00041000, 0x00010004, 0x00380700  \
+}
+
+/********************************************************/
+/*  CPUSaver micro code for the D102 B-step             */
+/********************************************************/
+
+/*  Version 2.0  */
+/*  Parameter values for the D102 B-step  */
+#define D102_B_CPUSAVER_TIMER_DWORD            82
+#define D102_B_CPUSAVER_BUNDLE_DWORD           106
+#define D102_B_CPUSAVER_MIN_SIZE_DWORD         70
+
+#define     D102_B_RCVBUNDLE_UCODE \
+{\
+0x006F0276, 0x0EF71FFF, 0x0ED30F86, 0x0D250ED9, 0x1FFF1FFF, 0x1FFF04D2, \
+0x00300001, 0x0140D871, 0x00300008, 0x00E00277, \
+0x01406C57, 0x00816073, 0x008700FA, 0x00E00070, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x01406CBA, 0x00807F9A, 0x00901F9A, 0x0024FFFF, \
+0x014B6F6F, 0x0030FFFE, 0x01407172, 0x01496FBA, \
+0x014B6F72, 0x00308000, 0x01406C52, 0x00912EFC, \
+0x00E00EF8, 0x00000000, 0x00000000, 0x00000000, \
+0x00906F8C, 0x00900F8C, 0x00E00F87, 0x00000000, \
+0x00906ED8, 0x01406C55, 0x00E00ED4, 0x00000000, \
+0x01406C51, 0x0080DFC2, 0x01406C52, 0x00815FC2, \
+0x01406C57, 0x00917FCC, 0x00E01FDD, 0x00000000, \
+0x00822D30, 0x01406C51, 0x0080CD26, 0x01406C52, \
+0x00814D26, 0x01406C57, 0x00916D26, 0x014C6FD7, \
+0x00300000, 0x00841FD2, 0x00300001, 0x0140D772, \
+0x00E012B3, 0x014C6F91, 0x0150710B, 0x01496F72, \
+0x0030FF80, 0x00940EDD, 0x00102000, 0x00038400, \
+0x00E00EDA, 0x00000000, 0x00000000, 0x00000000, \
+0x01406C57, 0x00917FE9, 0x00001000, 0x00E01FE9, \
+0x00200600, 0x0140D76F, 0x00138400, 0x01406FD8, \
+0x0140D96F, 0x00E01FDD, 0x00038400, 0x00102000, \
+0x00971FD7, 0x00101000, 0x00050200, 0x00E804D2, \
+0x014C6FD8, 0x00300001, 0x00840D26, 0x0140D872, \
+0x00E00D26, 0x014C6FD9, 0x00300001, 0x0140D972, \
+0x00941FBD, 0x00102000, 0x00038400, 0x014C6FD8, \
+0x00300006, 0x00840EDA, 0x014F71D8, 0x0140D872, \
+0x00E00EDA, 0x01496F50, 0x00E004D3, 0x00000000, \
+}
+
+/********************************************************/
+/*  Micro code for the D102 C-step                      */
+/********************************************************/
+
+/*  Parameter values for the D102 C-step  */
+#define D102_C_CPUSAVER_TIMER_DWORD            46
+#define D102_C_CPUSAVER_BUNDLE_DWORD           74
+#define D102_C_CPUSAVER_MIN_SIZE_DWORD         54
+
+#define     D102_C_RCVBUNDLE_UCODE \
+{ \
+0x00700279, 0x0E6604E2, 0x02BF0CAE, 0x1508150C, 0x15190E5B, 0x0E840F13, \
+0x00E014D8, 0x00000000, 0x00000000, 0x00000000, \
+0x00E014DC, 0x00000000, 0x00000000, 0x00000000, \
+0x00E014F4, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00E014E0, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00E014E7, 0x00000000, 0x00000000, 0x00000000, \
+0x00141000, 0x015D6F0D, 0x00E002C0, 0x00000000, \
+0x00200600, 0x00E0150D, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x0030FF80, 0x00940E6A, 0x00038200, 0x00102000, \
+0x00E00E67, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00906E65, 0x00800E60, 0x00E00E5D, 0x00000000, \
+0x00300006, 0x00E0151A, 0x00000000, 0x00000000, \
+0x00906F19, 0x00900F19, 0x00E00F14, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x01406CBA, 0x00807FDA, 0x00901FDA, 0x0024FFFF, \
+0x014B6F6F, 0x0030FFFE, 0x01407172, 0x01496FBA, \
+0x014B6F72, 0x00308000, 0x01406C52, 0x00912E89, \
+0x00E00E85, 0x00000000, 0x00000000, 0x00000000  \
+}
+
+/********************************************************/
+/*  Micro code for the D102 E-step                      */
+/********************************************************/
+
+/*  Parameter values for the D102 E-step  */
+#define D102_E_CPUSAVER_TIMER_DWORD            42
+#define D102_E_CPUSAVER_BUNDLE_DWORD           54
+#define D102_E_CPUSAVER_MIN_SIZE_DWORD         46
+
+#define     D102_E_RCVBUNDLE_UCODE \
+{\
+0x007D028F, 0x0E4204F9, 0x14ED0C85, 0x14FA14E9, 0x1FFF1FFF, 0x1FFF1FFF, \
+0x00E014B9, 0x00000000, 0x00000000, 0x00000000, \
+0x00E014BD, 0x00000000, 0x00000000, 0x00000000, \
+0x00E014D5, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00E014C1, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00E014C8, 0x00000000, 0x00000000, 0x00000000, \
+0x00200600, 0x00E014EE, 0x00000000, 0x00000000, \
+0x0030FF80, 0x00940E46, 0x00038200, 0x00102000, \
+0x00E00E43, 0x00000000, 0x00000000, 0x00000000, \
+0x00300006, 0x00E014FB, 0x00000000, 0x00000000  \
+}
+
+#endif /* _E100_UCODE_H_ */
diff --git a/drivers/net/e100/e100_vendor.h b/drivers/net/e100/e100_vendor.h
new file mode 100644 (file)
index 0000000..15f7820
--- /dev/null
@@ -0,0 +1,348 @@
+/*******************************************************************************
+
+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/100 Family of Adapters (e100) (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.
+*******************************************************************************/
+
+#ifndef E100_VENDOR_ID_INFO
+#define E100_VENDOR_ID_INFO
+/* ====================================================================== */
+/*                              vendor_info                               */
+/* ====================================================================== */
+
+struct e100_vendor_info {
+       unsigned long device_type;
+       char *idstr;
+};
+
+enum e100_device_type {
+       E100_BRD_100TX = 1,
+       E100_BRD_100T4,
+       E100_BRD_10T,
+       E100_BRD_100WFM,
+       E100_BRD_82557,
+       E100_BRD_82557_WOL,
+       E100_BRD_82558,
+       E100_BRD_82558_WOL,
+       E100_BRD_100,
+       E100_BRD_100M,
+       E100_BRD_AOL2,
+       E100_BRD_AOL,
+       E100_PROS_M,
+       E100_PROS_AM,
+       E100_PROS_AM_AOL,
+       E100_PROS_DT,
+       E100_PRO_DT,
+       E100_PROM_DT,
+       E100_PRO_SRV,
+       E100_PRO_SRVP,
+       E100_PROS_SRV,
+       E100_PRO_DUAL,
+       E100_PROS_DUAL,
+       E100_PROP_DUAL,
+       E100_PROP_WOL,
+       E100_PROS_MOB,
+       E100_PRO_CB,
+       E100_PRO_CB_M,
+       E100_PROSR_MOB,
+       E100_PROS_MC,
+       E100_PROSR_MC,
+       E100_PROP_MC,
+       E100_PROSP_MC,
+       E100_PROP_MOB,
+       E100_PROSP_MOB,
+       E100_PRO_MINI,
+       E100_PRO_NET,
+       E100_PROS_NET,
+       E100_PROVM_NET,
+       E100_PROVE_D,
+       E100_82559_LOM,
+       E100_82559_LOM_AOL,
+       E100_82559_LOM_AOL2,
+       E100_IBM_MDS,
+       E100_CMPQ_S,
+       E100_PROVE_DA,
+       E100_PROVM_DA,
+       E100_PROVE_LOM,
+       E100_PROVE_NET,
+       E100_82562,
+       E100_ALL_BOARDS,
+};
+
+struct e100_vendor_info e100_vendor_info_array[] = {
+       { E100_BRD_100TX, "Intel(R) PRO/100B PCI Adapter (TX)"},
+       { E100_BRD_100T4, "Intel(R) PRO/100B PCI Adapter (T4)"},
+       { E100_BRD_10T, "Intel(R) PRO/10+ PCI Adapter"},
+       { E100_BRD_100WFM, "Intel(R) PRO/100 WfM PCI Adapter"},
+       { E100_BRD_82557, "Intel(R) 82557-based Integrated Ethernet PCI (10/100)"},
+       { E100_BRD_82557_WOL, "Intel(R) 82557-based Integrated Ethernet with Wake on LAN*"},
+       { E100_BRD_82558, "Intel(R) 82558-based Integrated Ethernet"},
+       { E100_BRD_82558_WOL, "Intel(R) 82558-based Integrated Ethernet with Wake on LAN*"},
+       { E100_BRD_100, "Intel(R) PRO/100+ PCI Adapter"},
+       { E100_BRD_100M, "Intel(R) PRO/100+ Management Adapter"},
+       { E100_BRD_AOL2, "Intel(R) PRO/100+ Alert on LAN* 2 Management Adapter"},
+       { E100_BRD_AOL, "Intel(R) PRO/100+ Alert on LAN* Management Adapter"},
+       { E100_PROS_M, "Intel(R) PRO/100 S Management Adapter"},
+       { E100_PROS_AM, "Intel(R) PRO/100 S Advanced Management Adapter"},
+       { E100_PROS_AM_AOL, "Intel(R) PRO/100+ Management Adapter with Alert On LAN* GC"},
+       { E100_PROS_DT, "Intel(R) PRO/100 S Desktop Adapter"},
+       { E100_PRO_DT, "Intel(R) PRO/100 Desktop Adapter"},
+       { E100_PROM_DT, "Intel(R) PRO/100 M Desktop Adapter"},
+       { E100_PRO_SRV, "Intel(R) PRO/100+ Server Adapter"},
+       { E100_PRO_SRVP, "Intel(R) PRO/100+ Server Adapter (PILA8470B)"},
+       { E100_PROS_SRV, "Intel(R) PRO/100 S Server Adapter"},
+       { E100_PRO_DUAL, "Intel(R) PRO/100 Dual Port Server Adapter"},
+       { E100_PROS_DUAL, "Intel(R) PRO/100 S Dual Port Server Adapter"},
+       { E100_PROP_DUAL, "Intel(R) PRO/100+ Dual Port Server Adapter"},
+       { E100_PROP_WOL, "Intel(R) PRO/100+ Management Adapter with Alert On LAN* G Server"},
+       { E100_PROS_MOB, "Intel(R) PRO/100 S Mobile Adapter"},
+       { E100_PRO_CB, "Intel(R) PRO/100 CardBus II"},
+       { E100_PRO_CB_M, "Intel(R) PRO/100 LAN+Modem56 CardBus II"},
+       { E100_PROSR_MOB, "Intel(R) PRO/100 SR Mobile Adapter"},
+       { E100_PROS_MC, "Intel(R) PRO/100 S Mobile Combo Adapter"},
+       { E100_PROSR_MC, "Intel(R) PRO/100 SR Mobile Combo Adapter"},
+       { E100_PROP_MC, "Intel(R) PRO/100 P Mobile Combo Adapter"},
+       { E100_PROSP_MC, "Intel(R) PRO/100 SP Mobile Combo Adapter"},
+       { E100_PROP_MOB, "Intel(R) PRO/100 P Mobile Adapter"},
+       { E100_PROSP_MOB, "Intel(R) PRO/100 SP Mobile Adapter"},
+       { E100_PRO_MINI, "Intel(R) PRO/100+ Mini PCI"},
+       { E100_PRO_NET, "Intel(R) PRO/100 Network Connection" },
+       { E100_PROS_NET, "Intel(R) PRO/100 S Network Connection" },
+       { E100_PROVM_NET, "Intel(R) PRO/100 VM Network Connection"},
+       { E100_PROVE_D, "Intel(R) PRO/100 VE Desktop Connection"},
+       { E100_82559_LOM, "Intel(R) 82559 Fast Ethernet LAN on Motherboard"},
+       { E100_82559_LOM_AOL, "Intel(R) 82559 Fast Ethernet LOM with Alert on LAN*" },
+       { E100_82559_LOM_AOL2, "Intel(R) 82559 Fast Ethernet LOM with Alert on LAN* 2" },
+       { E100_IBM_MDS, "IBM Mobile, Desktop & Server Adapters"},
+       { E100_CMPQ_S, "Compaq Fast Ethernet Server Adapter" },
+       { E100_PROVE_DA, "Intel(R) PRO/100 VE Desktop Adapter"},
+       { E100_PROVM_DA, "Intel(R) PRO/100 VM Desktop Adapter"},
+       { E100_PROVE_LOM, "Intel(R) PRO/100 VE Network ConnectionPLC LOM" },
+       { E100_PROVE_NET, "Intel(R) PRO/100 VE Network Connection"},
+       { E100_82562, "Intel(R)82562 based Fast Ethernet Connection"},
+       { E100_ALL_BOARDS, "Intel(R) 8255x-based Ethernet Adapter"},
+       {0,NULL}
+};
+
+static struct pci_device_id e100_id_table[] __devinitdata = {
+       {0x8086, 0x1229, 0x8086, 0x0001, 0, 0, E100_BRD_100TX},
+       {0x8086, 0x1229, 0x8086, 0x0002, 0, 0, E100_BRD_100T4},
+       {0x8086, 0x1229, 0x8086, 0x0003, 0, 0, E100_BRD_10T},
+       {0x8086, 0x1229, 0x8086, 0x0004, 0, 0, E100_BRD_100WFM},
+       {0x8086, 0x1229, 0x8086, 0x0005, 0, 0, E100_BRD_82557},
+       {0x8086, 0x1229, 0x8086, 0x0006, 0, 0, E100_BRD_82557_WOL},
+       {0x8086, 0x1229, 0x8086, 0x0002, 0, 0, E100_BRD_100T4},
+       {0x8086, 0x1229, 0x8086, 0x0003, 0, 0, E100_BRD_10T},
+       {0x8086, 0x1229, 0x8086, 0x0004, 0, 0, E100_BRD_100WFM},
+       {0x8086, 0x1229, 0x8086, 0x0005, 0, 0, E100_BRD_82557},
+       {0x8086, 0x1229, 0x8086, 0x0006, 0, 0, E100_BRD_82557_WOL},
+       {0x8086, 0x1229, 0x8086, 0x0007, 0, 0, E100_BRD_82558},
+       {0x8086, 0x1229, 0x8086, 0x0008, 0, 0, E100_BRD_82558_WOL},
+       {0x8086, 0x1229, 0x8086, 0x0009, 0, 0, E100_BRD_100},
+       {0x8086, 0x1229, 0x8086, 0x000A, 0, 0, E100_BRD_100M},
+       {0x8086, 0x1229, 0x8086, 0x000B, 0, 0, E100_BRD_100},
+       {0x8086, 0x1229, 0x8086, 0x000C, 0, 0, E100_BRD_100M},
+       {0x8086, 0x1229, 0x8086, 0x000D, 0, 0, E100_BRD_AOL2},
+       {0x8086, 0x1229, 0x8086, 0x000E, 0, 0, E100_BRD_AOL},
+       {0x8086, 0x1229, 0x8086, 0x0010, 0, 0, E100_PROS_M},
+       {0x8086, 0x1229, 0x8086, 0x0011, 0, 0, E100_PROS_M},
+       {0x8086, 0x1229, 0x8086, 0x0012, 0, 0, E100_PROS_AM},
+       {0x8086, 0x1229, 0x8086, 0x0013, 0, 0, E100_PROS_AM},
+       {0x8086, 0x1229, 0x8086, 0x0030, 0, 0, E100_PROS_AM_AOL},
+       {0x8086, 0x1229, 0x8086, 0x0040, 0, 0, E100_PROS_DT},
+       {0x8086, 0x1229, 0x8086, 0x0041, 0, 0, E100_PROS_DT},
+       {0x8086, 0x1229, 0x8086, 0x0042, 0, 0, E100_PRO_DT},
+       {0x8086, 0x1229, 0x8086, 0x0050, 0, 0, E100_PROS_DT},
+       {0x8086, 0x1229, 0x8086, 0x0070, 0, 0, E100_PROM_DT},
+       {0x8086, 0x1229, 0x8086, 0x1009, 0, 0, E100_PRO_SRV},
+       {0x8086, 0x1229, 0x8086, 0x100C, 0, 0, E100_PRO_SRVP},
+       {0x8086, 0x1229, 0x8086, 0x1012, 0, 0, E100_PROS_SRV},
+       {0x8086, 0x1229, 0x8086, 0x1013, 0, 0, E100_PROS_SRV},
+       {0x8086, 0x1229, 0x8086, 0x1014, 0, 0, E100_PRO_DUAL},
+       {0x8086, 0x1229, 0x8086, 0x1015, 0, 0, E100_PROS_DUAL},
+       {0x8086, 0x1229, 0x8086, 0x1016, 0, 0, E100_PROS_DUAL},
+       {0x8086, 0x1229, 0x8086, 0x1017, 0, 0, E100_PROP_DUAL},
+       {0x8086, 0x1229, 0x8086, 0x1030, 0, 0, E100_PROP_WOL},
+       {0x8086, 0x1229, 0x8086, 0x1040, 0, 0, E100_PROS_SRV},
+       {0x8086, 0x1229, 0x8086, 0x1041, 0, 0, E100_PROS_SRV},
+       {0x8086, 0x1229, 0x8086, 0x1042, 0, 0, E100_PRO_SRV},
+       {0x8086, 0x1229, 0x8086, 0x1050, 0, 0, E100_PROS_SRV},
+       {0x8086, 0x1229, 0x8086, 0x10F0, 0, 0, E100_PROP_DUAL}, 
+       {0x8086, 0x1229, 0x8086, 0x10F0, 0, 0, E100_PROP_DUAL}, 
+       {0x8086, 0x1229, 0x8086, 0x2009, 0, 0, E100_PROS_MOB},
+       {0x8086, 0x1229, 0x8086, 0x200D, 0, 0, E100_PRO_CB},
+       {0x8086, 0x1229, 0x8086, 0x200E, 0, 0, E100_PRO_CB_M},
+       {0x8086, 0x1229, 0x8086, 0x200F, 0, 0, E100_PROSR_MOB},
+       {0x8086, 0x1229, 0x8086, 0x2010, 0, 0, E100_PROS_MC},
+       {0x8086, 0x1229, 0x8086, 0x2013, 0, 0, E100_PROSR_MC},
+       {0x8086, 0x1229, 0x8086, 0x2016, 0, 0, E100_PROS_MOB},
+       {0x8086, 0x1229, 0x8086, 0x2017, 0, 0, E100_PROS_MC},
+       {0x8086, 0x1229, 0x8086, 0x2018, 0, 0, E100_PROSR_MOB},
+       {0x8086, 0x1229, 0x8086, 0x2019, 0, 0, E100_PROSR_MC},
+       {0x8086, 0x1229, 0x8086, 0x2101, 0, 0, E100_PROP_MOB},
+       {0x8086, 0x1229, 0x8086, 0x2102, 0, 0, E100_PROSP_MOB},
+       {0x8086, 0x1229, 0x8086, 0x2103, 0, 0, E100_PROSP_MOB},
+       {0x8086, 0x1229, 0x8086, 0x2104, 0, 0, E100_PROSP_MOB},
+       {0x8086, 0x1229, 0x8086, 0x2105, 0, 0, E100_PROSP_MOB},
+       {0x8086, 0x1229, 0x8086, 0x2106, 0, 0, E100_PROP_MOB},
+       {0x8086, 0x1229, 0x8086, 0x2107, 0, 0, E100_PRO_NET},
+       {0x8086, 0x1229, 0x8086, 0x2108, 0, 0, E100_PRO_NET},
+       {0x8086, 0x1229, 0x8086, 0x2200, 0, 0, E100_PROP_MC},
+       {0x8086, 0x1229, 0x8086, 0x2201, 0, 0, E100_PROP_MC},
+       {0x8086, 0x1229, 0x8086, 0x2202, 0, 0, E100_PROSP_MC},
+       {0x8086, 0x1229, 0x8086, 0x2203, 0, 0, E100_PRO_MINI},
+       {0x8086, 0x1229, 0x8086, 0x2204, 0, 0, E100_PRO_MINI},
+       {0x8086, 0x1229, 0x8086, 0x2205, 0, 0, E100_PROSP_MC},
+       {0x8086, 0x1229, 0x8086, 0x2206, 0, 0, E100_PROSP_MC},
+       {0x8086, 0x1229, 0x8086, 0x2207, 0, 0, E100_PROSP_MC},
+       {0x8086, 0x1229, 0x8086, 0x2208, 0, 0, E100_PROP_MC},
+       {0x8086, 0x1229, 0x8086, 0x2408, 0, 0, E100_PRO_MINI},
+       {0x8086, 0x1229, 0x8086, 0x240F, 0, 0, E100_PRO_MINI},
+       {0x8086, 0x1229, 0x8086, 0x2411, 0, 0, E100_PRO_MINI},
+       {0x8086, 0x1229, 0x8086, 0x3400, 0, 0, E100_82559_LOM},
+       {0x8086, 0x1229, 0x8086, 0x3000, 0, 0, E100_82559_LOM},
+       {0x8086, 0x1229, 0x8086, 0x3001, 0, 0, E100_82559_LOM_AOL},
+       {0x8086, 0x1229, 0x8086, 0x3002, 0, 0, E100_82559_LOM_AOL2},
+       {0x8086, 0x1229, 0x8086, 0x3006, 0, 0, E100_PROS_NET},
+       {0x8086, 0x1229, 0x8086, 0x3007, 0, 0, E100_PROS_NET},
+       {0x8086, 0x1229, 0x8086, 0x3008, 0, 0, E100_PRO_NET},
+       {0x8086, 0x1229, 0x8086, 0x3010, 0, 0, E100_PROS_NET},
+       {0x8086, 0x1229, 0x8086, 0x3011, 0, 0, E100_PROS_NET},
+       {0x8086, 0x1229, 0x8086, 0x3012, 0, 0, E100_PRO_NET},
+       {0x8086, 0x1229, 0x1014, 0x005C, 0, 0, E100_IBM_MDS},   
+       {0x8086, 0x1229, 0x1014, 0x305C, 0, 0, E100_IBM_MDS},   
+       {0x8086, 0x1229, 0x1014, 0x405C, 0, 0, E100_IBM_MDS},   
+       {0x8086, 0x1229, 0x1014, 0x605C, 0, 0, E100_IBM_MDS},   
+       {0x8086, 0x1229, 0x1014, 0x505C, 0, 0, E100_IBM_MDS},   
+       {0x8086, 0x1229, 0x1014, 0x105C, 0, 0, E100_IBM_MDS},   
+       {0x8086, 0x1229, 0x1014, 0x805C, 0, 0, E100_IBM_MDS},   
+       {0x8086, 0x1229, 0x1014, 0x705C, 0, 0, E100_IBM_MDS},   
+       {0x8086, 0x1229, 0x1014, 0x01F1, 0, 0, E100_IBM_MDS},   
+       {0x8086, 0x1229, 0x1014, 0x0232, 0, 0, E100_IBM_MDS},   
+       {0x8086, 0x1229, 0x1014, 0x0207, 0, 0, E100_PRO_NET},     
+       {0x8086, 0x1229, 0x1014, 0x023F, 0, 0, E100_PRO_NET},   
+       {0x8086, 0x1229, 0x1014, 0x01BC, 0, 0, E100_PRO_NET},     
+       {0x8086, 0x1229, 0x1014, 0x01CE, 0, 0, E100_PRO_NET},     
+       {0x8086, 0x1229, 0x1014, 0x01DC, 0, 0, E100_PRO_NET},     
+       {0x8086, 0x1229, 0x1014, 0x01EB, 0, 0, E100_PRO_NET},     
+       {0x8086, 0x1229, 0x1014, 0x01EC, 0, 0, E100_PRO_NET},     
+       {0x8086, 0x1229, 0x1014, 0x0202, 0, 0, E100_PRO_NET},     
+       {0x8086, 0x1229, 0x1014, 0x0205, 0, 0, E100_PRO_NET},     
+       {0x8086, 0x1229, 0x1014, 0x0217, 0, 0, E100_PRO_NET},     
+       {0x8086, 0x1229, 0x0E11, 0xB01E, 0, 0, E100_CMPQ_S},         
+       {0x8086, 0x1229, 0x0E11, 0xB02F, 0, 0, E100_CMPQ_S},     
+       {0x8086, 0x1229, 0x0E11, 0xB04A, 0, 0, E100_CMPQ_S},     
+       {0x8086, 0x1229, 0x0E11, 0xB0C6, 0, 0, E100_CMPQ_S},     
+       {0x8086, 0x1229, 0x0E11, 0xB0C7, 0, 0, E100_CMPQ_S},     
+       {0x8086, 0x1229, 0x0E11, 0xB0D7, 0, 0, E100_CMPQ_S},     
+       {0x8086, 0x1229, 0x0E11, 0xB0DD, 0, 0, E100_CMPQ_S},     
+       {0x8086, 0x1229, 0x0E11, 0xB0DE, 0, 0, E100_CMPQ_S},     
+       {0x8086, 0x1229, 0x0E11, 0xB0E1, 0, 0, E100_CMPQ_S},     
+       {0x8086, 0x1229, 0x0E11, 0xB134, 0, 0, E100_CMPQ_S},     
+       {0x8086, 0x1229, 0x0E11, 0xB13C, 0, 0, E100_CMPQ_S},     
+       {0x8086, 0x1229, 0x0E11, 0xB144, 0, 0, E100_CMPQ_S},     
+       {0x8086, 0x1229, 0x0E11, 0xB163, 0, 0, E100_CMPQ_S},     
+       {0x8086, 0x1229, 0x0E11, 0xB164, 0, 0, E100_CMPQ_S},
+       {0x8086, 0x1229, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_ALL_BOARDS},
+
+       {0x8086, 0x2449, 0x1014, 0x0265, 0, 0, E100_PROVE_D},
+       {0x8086, 0x2449, 0x1014, 0x0267, 0, 0, E100_PROVE_D},
+       {0x8086, 0x2449, 0x1014, 0x026A, 0, 0, E100_PROVE_D},
+       {0x8086, 0x2449, 0x8086, 0x3010, 0, 0, E100_PROVE_DA},
+       {0x8086, 0x2449, 0x8086, 0x3011, 0, 0, E100_PROVM_DA},
+       {0x8086, 0x2449, 0x8086, 0x3013, 0, 0, E100_PROVE_NET},
+       {0x8086, 0x2449, 0x8086, 0x3014, 0, 0, E100_PROVM_NET},
+       {0x8086, 0x2449, 0x8086, 0x3016, 0, 0, E100_PROP_MC},
+       {0x8086, 0x2449, 0x8086, 0x3017, 0, 0, E100_PROP_MOB},
+       {0x8086, 0x2449, 0x8086, 0x3018, 0, 0, E100_PRO_NET},
+       {0x8086, 0x2449, 0x0E11, PCI_ANY_ID, 0, 0, E100_PROVM_NET},
+       {0x8086, 0x2449, 0x1014, PCI_ANY_ID, 0, 0, E100_PROVE_D},       
+       {0x8086, 0x2449, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_ALL_BOARDS},
+
+       {0x8086, 0x1209, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_ALL_BOARDS},
+       {0x8086, 0x1029, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_ALL_BOARDS},
+       {0x8086, 0x1030, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_ALL_BOARDS},        
+       {0x8086, 0x1031, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVE_NET}, 
+       {0x8086, 0x1032, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVE_NET},
+       {0x8086, 0x1033, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVM_NET}, 
+       {0x8086, 0x1034, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVM_NET}, 
+       {0x8086, 0x1038, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVM_NET},
+       {0x8086, 0x1039, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVE_NET},
+       {0x8086, 0x103A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVE_NET},
+       {0x8086, 0x103B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVM_NET},
+       {0x8086, 0x103C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVM_NET},
+       {0x8086, 0x103D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVE_NET},
+       {0x8086, 0x103E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVM_NET},
+       {0x8086, 0x2459, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_82562},
+       {0x8086, 0x245D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_82562},
+       {0,} /* This has to be the last entry*/
+};
+
+#endif /* E100_VENDOR_ID_INFO */