diff -urN linux-2.2.25.orig/Documentation/Configure.help linux-2.2.25/Documentation/Configure.help --- linux-2.2.25.orig/Documentation/Configure.help Tue Apr 8 16:14:11 2003 +++ linux-2.2.25/Documentation/Configure.help Mon Aug 11 15:43:38 2003 @@ -7663,6 +7663,13 @@ module, say M here and read Documentation/modules.txt as well as Documentation/networking/net-modules.txt. +EtherExpress PRO/100 support (Intel driver) +CONFIG_E100 + This is an alternative driver to the EtherExpress Pro/100 above. + Some newer cards are known to work only with this version. + This driver comes with a special license, please read + drivers/net/LICENSE.e100 + EtherExpress support CONFIG_EEXPRESS If you have an EtherExpress16 network (Ethernet) card, say Y and diff -urN linux-2.2.25.orig/drivers/net/Config.in linux-2.2.25/drivers/net/Config.in --- linux-2.2.25.orig/drivers/net/Config.in Tue Apr 8 16:14:11 2003 +++ linux-2.2.25/drivers/net/Config.in Mon Aug 11 15:43:38 2003 @@ -154,6 +154,7 @@ fi tristate 'Digi Intl. RightSwitch SE-X support' CONFIG_DGRS tristate 'EtherExpressPro/100 support' CONFIG_EEXPRESS_PRO100 + tristate 'EtherExpressPro/100 support (Intel driver)' CONFIG_E100 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate 'Mylex EISA LNE390A/B support (EXPERIMENTAL)' CONFIG_LNE390 tristate 'Novell/Eagle/Microdyne NE3210 EISA support (EXPERIMENTAL)' CONFIG_NE3210 diff -urN linux-2.2.25.orig/drivers/net/Makefile linux-2.2.25/drivers/net/Makefile --- linux-2.2.25.orig/drivers/net/Makefile Tue Apr 8 16:14:11 2003 +++ linux-2.2.25/drivers/net/Makefile Mon Aug 11 15:43:38 2003 @@ -585,6 +585,14 @@ endif endif +ifeq ($(CONFIG_E100),y) +L_OBJS += e100.o +else + ifeq ($(CONFIG_E100),m) + M_OBJS += e100.o + endif +endif + ifeq ($(CONFIG_RTL8139),y) L_OBJS += rtl8139.o else diff -urN linux-2.2.25.orig/drivers/net/Space.c linux-2.2.25/drivers/net/Space.c --- linux-2.2.25.orig/drivers/net/Space.c Tue Apr 8 16:14:09 2003 +++ linux-2.2.25/drivers/net/Space.c Mon Aug 11 15:43:38 2003 @@ -56,6 +56,7 @@ extern int express_probe(struct device *); extern int eepro_probe(struct device *); extern int eepro100_probe(struct device *); +extern int e100_probe(struct device *); extern int el3_probe(struct device *); extern int at1500_probe(struct device *); extern int bond_init(struct device *); @@ -239,6 +240,9 @@ #ifdef CONFIG_EEXPRESS_PRO100 /* Intel EtherExpress Pro/100 */ {eepro100_probe, 0}, #endif +#ifdef CONFIG_E100 /* Intel EtherExpress Pro/100 */ + {e100_probe, 0}, +#endif #ifdef CONFIG_LANMEDIA /* Lanmedia must be before Tulip */ {lmc_probe_fake, 0}, #endif diff -urN linux-2.2.25.orig/drivers/net/e100.LICENSE linux-2.2.25/drivers/net/e100.LICENSE --- linux-2.2.25.orig/drivers/net/e100.LICENSE Thu Jan 1 08:00:00 1970 +++ linux-2.2.25/drivers/net/e100.LICENSE Mon Aug 11 15:43:38 2003 @@ -0,0 +1,29 @@ +Copyright (c) 1999-2001, Intel Corporation + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of Intel Corporation nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + diff -urN linux-2.2.25.orig/drivers/net/e100.c linux-2.2.25/drivers/net/e100.c --- linux-2.2.25.orig/drivers/net/e100.c Thu Jan 1 08:00:00 1970 +++ linux-2.2.25/drivers/net/e100.c Mon Aug 11 15:43:38 2003 @@ -0,0 +1,7383 @@ +/***************************************************************************** + ***************************************************************************** + Copyright (c) 1999-2001, Intel Corporation + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of Intel Corporation nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + ***************************************************************************** +****************************************************************************/ + +/********************************************************************** +* * +* 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.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. * +* * +**********************************************************************/ + +/* set the debug level */ +#define DEBUG_STATS 0 +#define DEBUG 0 +#define E100_DEBUG 0 +#define DEBUG_TX 0 +#define DEBUG_RX 0 +#define DEBUG_LINK 0 +#define DEBUG_SKB 0 + +#define COND_FREE(X) if (X) kfree(X) +#define ALLOC_SKBS(bddp, nskb) \ + for (; (bddp)->skb_req > 0; (bddp)->skb_req--) { \ + (nskb) = e100_alloc_skb(bddp);\ + if ((nskb) == NULL) break;\ + e100_add_skb_to_end( (bddp), (nskb) );\ + } + +#ifdef __ia64__ +#define CSUM_IA64 +#endif /* __ia64 __ */ + +#define VLAN_SIZE 2 +#define CSUM_559_SIZE 2 + +/* includes */ +#undef __NO_VERSION__ + +#include "e100.h" + +/**************************************************************************** + * Parameter checking for compile time variables + */ +char *e100_ifname = IFNAME; +int e100_adaptive_ifs = ADAPTIVE_IFS; +uint8_t e100_cfg_parm6 = CFG_BYTE_PARM6; +uint8_t e100_rx_fifo_lmt = (RX_FIFO_LMT < 0) ? DEFAULT_RX_FIFO_LIMIT : ((RX_FIFO_LMT > 15) ? DEFAULT_RX_FIFO_LIMIT : RX_FIFO_LMT); +uint8_t e100_tx_fifo_lmt = (TX_FIFO_LMT < 0) ? DEFAULT_TX_FIFO_LIMIT : ((TX_FIFO_LMT > 7) ? DEFAULT_TX_FIFO_LIMIT : TX_FIFO_LMT); +uint8_t e100_rx_dma_cnt = (RX_DMA_CNT < 0) ? CB_557_CFIG_DEFAULT_PARM4 : ((RX_DMA_CNT > 63) ? CB_557_CFIG_DEFAULT_PARM4 : RX_DMA_CNT); +uint8_t e100_tx_dma_cnt = (TX_DMA_CNT < 0) ? CB_557_CFIG_DEFAULT_PARM5 : ((TX_DMA_CNT > 63) ? CB_557_CFIG_DEFAULT_PARM5 : TX_DMA_CNT); +uint8_t e100_urun_retry = (TX_UR_RETRY < 0) ? CB_557_CFIG_DEFAULT_PARM5 : ((TX_UR_RETRY > 3) ? CB_557_CFIG_DEFAULT_PARM5 : TX_UR_RETRY); +uint8_t e100_tx_thld = (TX_THRSHLD < 0) ? DEFAULT_TRANSMIT_THRESHOLD : ((TX_THRSHLD > 200) ? DEFAULT_TRANSMIT_THRESHOLD : TX_THRSHLD); + +/* Microcode tunable for number of receive interrupts */ +uint16_t e100_cpu_saver = (CPU_CYCLE_SAVER < 0) ? 0x0600 : ((CPU_CYCLE_SAVER > 0xc000) ? 0x0600 : CPU_CYCLE_SAVER); + +/* Microcode tunable for maximum number of frames that will be bundled */ +uint16_t e100_cpusaver_bundle_max = (CPUSAVER_BUNDLE_MAX < 1) ? 0x0006 : ((CPUSAVER_BUNDLE_MAX > 0xffff) ? 0x0006 : CPUSAVER_BUNDLE_MAX); + +/* Congestion enable flag for National Phy */ +uint_t e100_cong_enbl = TX_CONG_DFLT; + +/* + * Auto-polarity enable/disable + * e100_autopolarity = 0 => disable auto-polarity + * e100_autopolarity = 1 => enable auto-polarity + * e100_autopolarity = 2 => let software determine + */ + +int e100_autopolarity = 2; + +/* + * Number of consecutive transmit frames without the CU getting suspended or + * going idle before generating an interrupt + */ + +unsigned int e100_batch_tx_frames = TX_FRAME_CNT; + +/* + * ################### 82558 and 82559 feature set ########################## + * + * These should be enabled only for 82558 or later based (PRO/100+) boards . + * These should be changed only by someone with an intimate knowledge + * of the hardware of the system that the driver is loaded. + */ + +/* e100_enhanced_tx_enable + * + * Enable/Disable 82558 enhanced transmit features. + * 0 - Disable + * 1 - Enable + */ +int e100_enhanced_tx_enable = 1; + +/* e100_MWI_enable + * + * Enable/Disable use of Memory Write and Invalidate + * 0 - Disable + * 1 - Enable + * + * Note: This should be enabled only for an 82558 based adapter (PRO/100+) + * and only on systems in which the PCI bus supports MWI. If enabled on a + * system that does not support MWI, performance might be affected. + */ + +int e100_MWI_enable = 1; + +/* + * e100_read_align_enable + * + * Enable/Disable use of Cache Line Read/Write Termination + * 0 - Disable + * 1 - Enable + * + * Note: This should be enabled only for an 82558 based adapter (PRO/100+) + * and only on cache line oriented systems. If enabled on a + * system that is not cache line oriented, performance might be affected. + */ +int e100_read_align_enable = 0; + +/* + * e100_flow_control_enable + * + * Enable/Disable Full Duplex Flow Control + * 0 - Disable + * 1 - Enable + * + * Note: This should be enabled only for an 82558 based adapter (PRO/100+) + * and only if the Link Partner (hub/switch) supports Full Duplex Flow + * Control. + */ + +int e100_flow_control_enable = 0; + +/* + * e100_cna_backoff_enable + * + * Enable/Disable delaying of CNA (Control Unit Not Active) Interrupts + * 0 - Disable + * 1 - Enable + * + * Note: This should be enabled only for an 82558 based adapter (PRO/100+). + * If enabled, then the value of e100_current_CNA_backoff should be set to + * a value between 0 and 31. + */ + +int e100_cna_backoff_enable = 0; + +/* e100_current_cna_backoff + * + * Delay in assertion of CNA (Control Unit Not Active) Interrupts + * + * Permitted values - 0 through 31 + * + * Note: This should be enabled only for an 82558 based adapter (PRO/100+). + * Larger values increase the delay in assertion of CNA interrupts and + * possibly improve performance. + * If this is set to any value other than 0, make sure that + * e100_cna_backoff_enable is set to 1. + */ + +int e100_current_cna_backoff = 0; /* 0-31 only */ + +/* e100_max_rx + * number of packets that are recieved in single isr */ + +int e100_max_rx = 24; +/* + * ################## End of 82558 and 82559 feature set ################### + */ + +/* Global Data structures and variables */ +char e100id_string[128] = "e100 - Intel(R) PRO/100 Fast Ethernet Adapter, "; +char e100_copyright[] = "Copyright (c) 2001 Intel Corporation"; + + +static const char *e100_version = "1.5.5"; +static const char *e100_full_driver_name = "Intel(R) PRO/100 Fast Ethernet Adapter - Loadable driver, ver 1.5.5"; +static const char *e100_short_driver_name = "e100"; + + +//PCI Vendor ID,PCI Device ID,PCI Sub Vendor ID,PCI Sub system ID,PCI Rev,Branding String, +e100_vendor_info_t e100_vendor_info_array[] = { + { 0x8086,0x1229,0x8086,0x0001,1,"Intel(R) PRO/100B PCI Adapter (TX)"}, + { 0x8086,0x1229,0x8086,0x0002,1,"Intel(R) PRO/100B PCI Adapter (T4)"}, + { 0x8086,0x1229,0x8086,0x0003,1,"Intel(R) PRO/10+ PCI Adapter"}, + { 0x8086,0x1229,0x8086,0x0004,1,"Intel(R) PRO/100 WfM PCI Adapter"}, + { 0x8086,0x1229,0x8086,0x0005,1,"Intel 82557-based Integrated Ethernet PCI (10/100)"}, + { 0x8086,0x1229,0x8086,0x0006,1,"Intel 82557-based Integrated Ethernet with Wake on LAN*"}, + { 0x8086,0x1229,0x8086,0x0002,2,"Intel(R) PRO/100B PCI Adapter (T4)"}, + { 0x8086,0x1229,0x8086,0x0003,2,"Intel(R) PRO/10+ PCI Adapter"}, + { 0x8086,0x1229,0x8086,0x0004,2,"Intel(R) PRO/100 WfM PCI Adapter"}, + { 0x8086,0x1229,0x8086,0x0005,2,"Intel 82557-based Integrated Ethernet PCI (10/100)"}, + { 0x8086,0x1229,0x8086,0x0006,2,"Intel 82557-based Integrated Ethernet with Wake on LAN*"}, + { 0x8086,0x1229,0x8086,0x0007,4,"Intel 82558-based Integrated Ethernet"}, + { 0x8086,0x1229,0x8086,0x0008,4,"Intel 82558-based Integrated Ethernet with Wake on LAN*"}, + { 0x8086,0x1229,0x8086,0x0009,5,"Intel(R) PRO/100+ PCI Adapter"}, + { 0x8086,0x1229,0x8086,0x000A,5,"Intel(R) PRO/100+ Management Adapter"}, + { 0x8086,0x1229,0x8086,0x000A,5,"Intel(R) PRO/100+ Management Adapter"}, + { 0x8086,0x1229,0x8086,0x000B,8,"Intel(R) PRO/100+ Adapter"}, + { 0x8086,0x1229,0x8086,0x000C,8,"Intel(R) PRO/100+ Management Adapter"}, + { 0x8086,0x1229,0x8086,0x000D,8,"Intel(R) PRO/100+ Alert on LAN* 2 Management Adapter"}, + { 0x8086,0x1229,0x8086,0x000E,8,"Intel(R) PRO/100+ Alert on LAN* Management Adapter"}, + { 0x8086,0x1229,0x8086,0x0010,9,"Intel(R) PRO/100 S Management Adapter"}, + { 0x8086,0x1229,0x8086,0x0011,9,"Intel(R) PRO/100 S Management Adapter"}, + { 0x8086,0x1229,0x8086,0x0012,9,"Intel(R) PRO/100 S Advanced Management Adapter"}, + { 0x8086,0x1229,0x8086,0x0013,9,"Intel(R) PRO/100 S Advanced Management Adapter"}, + { 0x8086,0x1229,0x8086,0x0030,8,"Intel(R) PRO/100+ Management Adapter with Alert On LAN* GC"}, + { 0x8086,0x1229,0x8086,0x0040,0xC,"Intel(R) PRO/100 S Desktop Adapter"}, + { 0x8086,0x1229,0x8086,0x0041,0xC,"Intel(R) PRO/100 S Desktop Adapter"}, + { 0x8086,0x1229,0x8086,0x0042,0xC,"Intel(R) PRO/100 Desktop Adapter"}, + { 0x8086,0x1229,0x8086,0x0050,0xD,"Intel(R) PRO/100 S Desktop Adapter"}, + { 0x8086,0x1229,0x8086,0x1009,4,"Intel(R) PRO/100+ Server Adapter"}, + { 0x8086,0x1229,0x8086,0x1009,5,"Intel(R) PRO/100+ Server Adapter"}, + { 0x8086,0x1229,0x8086,0x100C,8,"Intel(R) PRO/100+ Server Adapter (PILA8470B)"}, + { 0x8086,0x1229,0x8086,0x1012,9,"Intel(R) PRO/100 S Server Adapter"}, + { 0x8086,0x1229,0x8086,0x1013,9,"Intel(R) PRO/100 S Server Adapter"}, + { 0x8086,0x1229,0x8086,0x1014,0xD,"Intel(R) PRO/100 Dual Port Server Adapter"}, + { 0x8086,0x1229,0x8086,0x1015,0xD,"Intel(R) PRO/100 S Dual Port Server Adapter"}, + { 0x8086,0x1229,0x8086,0x1016,0xD,"Intel(R) PRO/100 S Dual Port Server Adapter"}, + { 0x8086,0x1229,0x8086,0x1017,8,"Intel(R) PRO/100+ Dual Port Server Adapter"}, + { 0x8086,0x1229,0x8086,0x1030,8,"Intel(R) PRO/100+ Management Adapter with Alert On LAN* G Server"}, + { 0x8086,0x1229,0x8086,0x1040,0xC,"Intel(R) PRO/100 S Server Adapter"}, + { 0x8086,0x1229,0x8086,0x1041,0xC,"Intel(R) PRO/100 S Server Adapter"}, + { 0x8086,0x1229,0x8086,0x1042,0xC,"Intel(R) PRO/100 Server Adapter"}, + { 0x8086,0x1229,0x8086,0x1050,0xD,"Intel(R) PRO/100 S Server Adapter"}, + { 0x8086,0x1229,0x8086,0x10F0,4,"Intel(R) PRO/100+ Dual Port Server Adapter "}, + { 0x8086,0x1229,0x8086,0x10F0,5,"Intel(R) PRO/100+ Dual Port Server Adapter "}, + { 0x8086,0x1229,0x8086,0x2009,0xC,"Intel(R) PRO/100 S Mobile Adapter"}, + { 0x8086,0x1229,0x8086,0x200D,8,"Intel(R) PRO/100 CardBus II"}, + { 0x8086,0x1229,0x8086,0x200D,8,"Intel(R) PRO/100 CardBus II"}, + { 0x8086,0x1229,0x8086,0x200E,8,"Intel(R) PRO/100 LAN+Modem56 CardBus II"}, + { 0x8086,0x1229,0x8086,0x200E,8,"Intel(R) PRO/100 LAN+Modem56 CardBus II"}, + { 0x8086,0x1229,0x8086,0x200F,0xC,"Intel(R) PRO/100 SR Mobile Adapter"}, + { 0x8086,0x1229,0x8086,0x2010,0xC,"Intel(R) PRO/100 S Mobile Combo Adapter"}, + { 0x8086,0x1229,0x8086,0x2013,0xC,"Intel(R) PRO/100 SR Mobile Combo Adapter"}, + { 0x8086,0x1229,0x8086,0x2016,0xD,"Intel(R) PRO/100 S Mobile Adapter"}, + { 0x8086,0x1229,0x8086,0x2017,0xD,"Intel(R) PRO/100 S Combo Mobile Adapter"}, + { 0x8086,0x1229,0x8086,0x2018,0xD,"Intel(R) PRO/100 SR Mobile Adapter"}, + { 0x8086,0x1229,0x8086,0x2019,0xD,"Intel(R) PRO/100 SR Combo Mobile Adapter"}, + { 0x8086,0x1229,0x8086,0x2101,0xC,"Intel(R) PRO/100 P Mobile Adapter"}, + { 0x8086,0x1229,0x8086,0x2102,0xC,"Intel(R) PRO/100 SP Mobile Adapter"}, + { 0x8086,0x1229,0x8086,0x2103,0xC,"Intel(R) PRO/100 SP Mobile Adapter"}, + { 0x8086,0x1229,0x8086,0x2104,0xC,"Intel(R) PRO/100 SP Mobile Adapter"}, + { 0x8086,0x1229,0x8086,0x2105,0xC,"Intel PRO/100 SP Mobile Adapter"}, + { 0x8086,0x1229,0x8086,0x2106,0xA,"Intel PRO/100 P Mobile Adapter"}, + { 0x8086,0x1229,0x8086,0x2107,0xA,"Intel (R) PRO/100 Network Connection"}, + { 0x8086,0x1229,0x8086,0x2108,0xC,"Intel (R) PRO/100 Network Connection"}, + { 0x8086,0x1229,0x8086,0x2200,0xC,"Intel(R) PRO/100 P Mobile Combo Adapter"}, + { 0x8086,0x1229,0x8086,0x2201,0xC,"Intel(R) PRO/100 P Mobile Combo Adapter"}, + { 0x8086,0x1229,0x8086,0x2202,0xC,"Intel(R) PRO/100 SP Mobile Combo Adapter"}, + { 0x8086,0x1229,0x8086,0x2203,CATCHALL,"Intel(R) PRO/100+ Mini PCI"}, + { 0x8086,0x1229,0x8086,0x2204,CATCHALL,"Intel(R) PRO/100+ Mini PCI"}, + { 0x8086,0x1229,0x8086,0x2205,0xC,"Intel(R) PRO/100 SP Mobile Combo Adapter"}, + { 0x8086,0x1229,0x8086,0x2206,0xC,"Intel(R) PRO/100 SP Mobile Combo Adapter"}, + { 0x8086,0x1229,0x8086,0x2207,0xC,"Intel(R) PRO/100 SP Mobile Combo Adapter"}, + { 0x8086,0x1229,0x8086,0x2208,0xC,"Intel(R) PRO/100 P Mobile Combo Adapter"}, + { 0x8086,0x1229,0x8086,0x2408,9,"Intel(R) PRO/100+ Mini PCI"}, + { 0x8086,0x1229,0x8086,0x240F,9,"Intel(R) PRO/100+ Mini PCI"}, + { 0x8086,0x1229,0x8086,0x2411,9,"Intel(R) PRO/100+ Mini PCI"}, + { 0x8086,0x1229,0x8086,0x3000,8,"Intel(R) 82559 Fast Ethernet LAN on Motherboard"}, + { 0x8086,0x1229,0x8086,0x3001,8,"Intel(R) 82559 Fast Ethernet LOM with Alert on LAN*"}, + { 0x8086,0x1229,0x8086,0x3002,8,"Intel(R) 82559 Fast Ethernet LOM with Alert on LAN* 2"}, + { 0x8086,0x1229,0x8086,0x3006,0xC,"Intel(R) PRO/100 S Network Connection"}, + { 0x8086,0x1229,0x8086,0x3007,0xC,"Intel(R) PRO/100 S Network Connection"}, + { 0x8086,0x1229,0x8086,0x3008,0xC,"Intel(R) PRO/100 Network Connection"}, + { 0x8086,0x1229,0x8086,0x3010,CATCHALL,"Intel(R) PRO/100 S Network Connection"}, + { 0x8086,0x1229,0x8086,0x3011,CATCHALL,"Intel(R) PRO/100 S Network Connection"}, + { 0x8086,0x1229,0x8086,0x3012,CATCHALL,"Intel(R) PRO/100 Network Connection"}, + { 0x8086,0x1229,0x1014,0x005C,CATCHALL,"IBM Mobile, Desktop & Server Adapters"}, + { 0x8086,0x1229,0x1014,0x305C,CATCHALL,"IBM Mobile, Desktop & Server Adapters"}, + { 0x8086,0x1229,0x1014,0x405C,CATCHALL,"IBM Mobile, Desktop & Server Adapters"}, + { 0x8086,0x1229,0x1014,0x605C,CATCHALL,"IBM Mobile, Desktop & Server Adapters"}, + { 0x8086,0x1229,0x1014,0x505C,CATCHALL,"IBM Mobile, Desktop & Server Adapters"}, + { 0x8086,0x1229,0x1014,0x105C,CATCHALL,"IBM Mobile, Desktop & Server Adapters"}, + { 0x8086,0x1229,0x1014,0x805C,CATCHALL,"IBM Mobile, Desktop & Server Adapters"}, + { 0x8086,0x1229,0x1014,0x705C,CATCHALL,"IBM Mobile, Desktop & Server Adapters"}, + { 0x8086,0x1229,0x1014,0x01F1,CATCHALL,"IBM Mobile, Desktop & Server Adapters"}, + { 0x8086,0x1229,0x1014,0x0232,CATCHALL,"IBM Mobile, Desktop & Server Adapters"}, + { 0x8086,0x1229,0x1014,0x0207,CATCHALL,"Intel(R) PRO/100 Network Connection"}, + { 0x8086,0x1229,0x1014,0x01BC,CATCHALL,"Intel(R) PRO/100 Network Connection"}, + { 0x8086,0x1229,0x1014,0x01CE,CATCHALL,"Intel(R) PRO/100 Network Connection"}, + { 0x8086,0x1229,0x1014,0x01DC,CATCHALL,"Intel(R) PRO/100 Network Connection"}, + { 0x8086,0x1229,0x1014,0x01EB,CATCHALL,"Intel(R) PRO/100 Network Connection"}, + { 0x8086,0x1229,0x1014,0x01EC,CATCHALL,"Intel(R) PRO/100 Network Connection"}, + { 0x8086,0x1229,0x1014,0x0202,CATCHALL,"Intel(R) PRO/100 Network Connection"}, + { 0x8086,0x1229,0x1014,0x0205,CATCHALL,"Intel(R) PRO/100 Network Connection"}, + { 0x8086,0x1229,0x1014,0x0217,CATCHALL,"Intel(R) PRO/100 Network Connection"}, + { 0x8086,0x1229,0x0E11,0xB01E,CATCHALL,"Compaq Fast Ethernet Server Adapter"}, + { 0x8086,0x1229,0x0E11,0xB01F,CATCHALL,"Compaq Fast Ethernet Server Adapter"}, + { 0x8086,0x1229,0x0E11,0xB02F,CATCHALL,"Compaq Fast Ethernet Server Adapter"}, + { 0x8086,0x1229,0x0E11,0xB04A,CATCHALL,"Compaq Fast Ethernet Server Adapter"}, + { 0x8086,0x1229,0x0E11,0xB0C6,CATCHALL,"Compaq Fast Ethernet Server Adapter"}, + { 0x8086,0x1229,0x0E11,0xB0C7,CATCHALL,"Compaq Fast Ethernet Server Adapter"}, + { 0x8086,0x1229,0x0E11,0xB0D7,CATCHALL,"Compaq Fast Ethernet Server Adapter"}, + { 0x8086,0x1229,0x0E11,0xB0DD,CATCHALL,"Compaq Fast Ethernet Server Adapter"}, + { 0x8086,0x1229,0x0E11,0xB0DE,CATCHALL,"Compaq Fast Ethernet Server Adapter"}, + { 0x8086,0x1229,0x0E11,0xB0E1,CATCHALL,"Compaq Fast Ethernet Server Adapter"}, + { 0x8086,0x1229,0x0E11,0xB134,CATCHALL,"Compaq Fast Ethernet Server Adapter"}, + { 0x8086,0x1229,0x0E11,0xB13C,CATCHALL,"Compaq Fast Ethernet Server Adapter"}, + { 0x8086,0x1229,0x0E11,0xB144,CATCHALL,"Compaq Fast Ethernet Server Adapter"}, + { 0x8086,0x1229,0x0E11,0xB163,CATCHALL,"Compaq Fast Ethernet Server Adapter"}, + { 0x8086,0x1229,0x0E11,0xB164,CATCHALL,"Compaq Fast Ethernet Server Adapter"}, + { 0x8086,0x2449,0x8086,0x3010,1,"Intel(R) PRO/100 VE Desktop Adapter"}, + { 0x8086,0x2449,0x8086,0x3010,3,"Intel(R) PRO/100 VE Desktop Adapter"}, + { 0x8086,0x2449,0x8086,0x3011,1,"Intel(R) PRO/100 VM Desktop Adapter"}, + { 0x8086,0x2449,0x8086,0x3011,3,"Intel(R) PRO/100 VM Desktop Adapter"}, + { 0x8086,0x2449,0x8086,0x3012,1,"82562EH based Phoneline Network Connection"}, + { 0x8086,0x2449,0x8086,0x3012,3,"82562EH based Phoneline Network Connection"}, + { 0x8086,0x2449,0x8086,0x3013,1,"Intel(R) PRO/100 VE Network ConnectionPLC LOM"}, + { 0x8086,0x2449,0x8086,0x3013,3,"Intel(R) PRO/100 VE Network Connection"}, + { 0x8086,0x2449,0x8086,0x3014,1,"Intel(R) PRO/100 VM Network Connection"}, + { 0x8086,0x2449,0x8086,0x3014,3,"Intel(R) PRO/100 VM Network Connection"}, + { 0x8086,0x2449,0x8086,0x3015,1,"82562EH based Phoneline Network Connection"}, + { 0x8086,0x2449,0x8086,0x3015,3,"82562EH based Phoneline Network Connection"}, + { 0x8086,0x2449,0x8086,0x3016,1,"Intel(R) PRO/100 P Mobile Combo Adapter"}, + { 0x8086,0x2449,0x8086,0x3016,3,"Intel(R) PRO/100 P Mobile Combo Adapter"}, + { 0x8086,0x2449,0x8086,0x3017,1,"Intel(R) PRO/100 P Mobile Adapter"}, + { 0x8086,0x2449,0x8086,0x3017,3,"Intel(R) PRO/100 P Mobile Adapter"}, + { 0x8086,0x2449,0x8086,0x3018,1,"Intel (R) PRO/100 Network Connection"}, + { 0x8086,0x2449,0x8086,0x3018,3,"Intel (R) PRO/100 Network Connection"}, + { 0x8086,0x1031,CATCHALL,CATCHALL,CATCHALL,"Intel(R) PRO/100 VE Network Connection"}, + { 0x8086,0x1032,CATCHALL,CATCHALL,CATCHALL,"Intel(R) PRO/100 VE Network Connection"}, + { 0x8086,0x1033,CATCHALL,CATCHALL,CATCHALL,"Intel(R) PRO/100 VM Network Connection"}, + { 0x8086,0x1034,CATCHALL,CATCHALL,CATCHALL,"Intel(R) PRO/100 VM Network Connection"}, + { 0x8086,0x1035,CATCHALL,CATCHALL,CATCHALL,"82562EH based Phoneline Network Connection"}, + { 0x8086,0x1036,CATCHALL,CATCHALL,CATCHALL,"82562EH based Phoneline Network Connection"}, + { 0x8086,0x1037,CATCHALL,CATCHALL,CATCHALL,"82562EH based Phoneline Network Connection"}, + { 0x8086,0x1038,CATCHALL,CATCHALL,CATCHALL,"Intel(R) PRO/100 VM Network Connection"}, + {CATCHALL, CATCHALL, CATCHALL, CATCHALL, CATCHALL, "Intel(R) 8255x-based Ethernet Adapter"}, + {0x0, 0x0, 0x0, 0x0, 0x0, NULL} // This has to be the last entry +}; + + +bd_config_t *e100_first = NULL; +int e100nics = 0; +#define MAX_NIC 16 + + +/* Start Command Line Options */ +/* + * Set the line speed and duplex mode of the controller. + * 0 indicates autodetection for both speed and duplex mode + * 1 indicates a speed of 10Mbps and a duplex mode of half + * 2 indicates a speed of 10Mbps and a duplex mode of full + * 3 indicates a speed of 100Mbps and a duplex mode of half + * 4 indicates a speed of 100Mbps and a duplex mode of full + * + * NOTE: The PRO/10+ can't autodetect so if the setting is left at + * 0 the driver will force it to 10/HALF. If full duplex is desired + * a setting of 2 is required. Setting 3 and 4 are invalid for the + * PRO/10+ hardware. + * + * We support up to 16 nics with this structure. If you need more, + * add new members to the structure. + */ +int e100_speed_duplex[MAX_NIC] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +int RxDescriptors[MAX_NIC] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; +int TxDescriptors[MAX_NIC] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; +int XsumRX[MAX_NIC] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; +uint16_t PhoneLinePower[MAX_NIC] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +uint16_t PhoneLineSpeed[MAX_NIC] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; +int ucode[MAX_NIC] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; +uint ber[MAX_NIC] = { ZLOCK_MAX_ERRORS, ZLOCK_MAX_ERRORS, + ZLOCK_MAX_ERRORS, ZLOCK_MAX_ERRORS, + ZLOCK_MAX_ERRORS, ZLOCK_MAX_ERRORS, + ZLOCK_MAX_ERRORS, ZLOCK_MAX_ERRORS, + ZLOCK_MAX_ERRORS, ZLOCK_MAX_ERRORS, + ZLOCK_MAX_ERRORS, ZLOCK_MAX_ERRORS, + ZLOCK_MAX_ERRORS, ZLOCK_MAX_ERRORS, + ZLOCK_MAX_ERRORS, ZLOCK_MAX_ERRORS }; + +#ifdef CONFIG_PROC_FS +struct proc_dir_entry *adapters_proc_dir = NULL; +#endif + +/* ====================================================================== */ + +void e100_D102_check_checksum(bd_config_t *, struct sk_buff *); +static int e100_ioctl(device_t *dev, struct ifreq *ifr, int cmd); +static void e100_free_rfd_pool(bd_config_t *bddp); +static void e100_free_tbds(bd_config_t *bdp); + +static int create_e100_proc_subdir(bd_config_t *bdp); +static void remove_e100_proc_subdir(device_t *dev); + +#ifdef MODULE +static int init_module (void), + cleanup_module (void); +#else /* NOT MODULE */ +int e100_probe (void); +#endif /* MODULE */ + +static int e100_open (device_t *), + e100_close (device_t *), + e100_xmit_frame (struct sk_buff *, device_t *), + e100init (bd_config_t *), e100_set_mac (device_t *, void *); + +static struct net_device_stats *e100_get_stats (device_t *); + +static void e100intr (int, void *, struct pt_regs *), + e100_print_brd_conf (bd_config_t *), + e100_set_multi (device_t *), drv_usecwait (uint_t); + +static char *e100_GetBrandingMesg (bd_config_t *); + +static void e100_get_pci_info (pci_dev_t *, bd_config_t *); +static boolean_t e100_sw_init (bd_config_t *); + +static bd_config_t *e100_alloc_space (pci_dev_t *); +static int e100_alloc_tcbs(bd_config_t *); + +static void e100_dealloc_space (bd_config_t *), + e100_setup_tcb_pool (ptcb_t, uint_t, bd_config_t *); + +static sk_buff_t *e100_alloc_rfd_pool (bdd_t *); + + +/* EEPROM access functions */ +static void e100_rd_eaddr (bd_config_t *), + e100_rd_pwa_no(bd_config_t *bdp), + e100_ShiftOutBits (bd_config_t *, uint16_t, uint16_t), + e100_RaiseClock (bd_config_t *, uint16_t *), + e100_LowerClock (bd_config_t *, uint16_t *), + e100_EEpromCleanup (bd_config_t *); + +static uint16_t e100_ReadEEprom (bd_config_t *, uint16_t), + e100_ShiftInBits (bd_config_t *), + e100_GetEEpromSize (bd_config_t *), + e100_EEpromAddressSize (uint16_t); + +/* Functions for accessing the adapter hardware */ +static boolean_t e100_clr_cntrs (bd_config_t *), + e100_exec_poll_cmd (bd_config_t *), + e100_load_microcode (bd_config_t *, uint8_t), + e100_selftest (bd_config_t *), + e100_hw_init (bd_config_t *, uint32_t), + e100_configure (bd_config_t *), + e100_setup_iaaddr (bd_config_t *, e100_eaddr_t *), + e100_wait_scb (bd_config_t *); + +static void e100_start_ru (bd_config_t *), + e100_ru_abort (bd_config_t *), + e100_sw_reset (bd_config_t *, uint32_t), + e100_dis_intr (bd_config_t *), + e100_enbl_intr (bd_config_t *), + e100_trigger_SWI(bd_config_t *bdp), + e100_dump_stats_cntrs (bd_config_t *); + + +void e100_check_options(int board); + +/* all inline func must be declared with body, here they're */ + +/* + * Procedure: e100_alloc_skb + * + * Description: allocates skb with enough room for rfd, ans and data, + * and reserve non-data space + * + * Arguments: + * bddp - Ptr to this card's e100_bdconfig structure + * + * Returns: + * sk_buff_t * - the new sk_buff or NULL if we failed to allocate one. + */ +inline sk_buff_t * +e100_alloc_skb(bdd_t *bddp) +{ + sk_buff_t *new_skb; + + new_skb = (sk_buff_t *) dev_alloc_skb(sizeof(rfd_t) + CSUM_559_SIZE + VLAN_SIZE); + if (new_skb) { + +#if (defined __ia64__) + /* 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); +#endif /* __ia64__ */ + + + skb_reserve(new_skb, bddp->rfd_size); + return new_skb; + } + +#if DEBUG_RX + printk(KERN_DEBUG "e100_alloc_skb, b[%d]: skb_alloc failed!!!\n", bddp->bdp->bd_number ); +#endif + return NULL; +} + + +/* + * Procedure: e100_add_skb_to_end + * + * Description: Adds an skb to the end of our rfd list. + * + * Arguments: + * bddp - Ptr to this card's e100_bdconfig structure + * skb_buff_t *new_skb - Ptr to the new skb + * + * Returns: + * NONE + */ + +inline void +e100_add_skb_to_end(bdd_t *bddp, sk_buff_t *new_skb) +{ + rfd_t *rfdn; /* The new rfd */ + rfd_t *rfdp; /* The old rfd */ + bd_config_t *bdp = bddp->bdp; + + /* set who this is from */ + new_skb->dev = bdp->device; + + rfdn = RFD_POINTER(new_skb, bddp); + + /* init all fields in rfd */ + rfdn->rfd_header.cb_status = 0; + rfdn->rfd_header.cb_cmd = RFD_EL_BIT; + rfdn->rfd_rbd_ptr = E100_NULL; /* not really necessary */ + rfdn->rfd_act_cnt = 0; + + rfdn->rfd_sz = sizeof(eth_rx_buffer_t) + CSUM_559_SIZE + VLAN_SIZE; + + /* append new_skb to the end of the rx skb queue */ + rfdn->prev = bddp->rfd_tail; + rfdn->next = NULL; + + rfdn->dma_addr = pci_map_single(bdp->ppci_dev,rfdn, + sizeof(rfd_t),PCI_DMA_FROMDEVICE); + pci_dma_sync_single(bdp->ppci_dev,rfdn->dma_addr,bddp->rfd_size,PCI_DMA_TODEVICE); + if (bddp->rfd_tail != NULL) { + rfdp = RFD_POINTER(bddp->rfd_tail, bddp); + pci_dma_sync_single(bdp->ppci_dev,rfdp->dma_addr,bddp->rfd_size,PCI_DMA_FROMDEVICE); + + rfdp->next = new_skb; + rfdp->rfd_header.cb_lnk_ptr = cpu_to_le32(rfdn->dma_addr); + /* Clear the EL bit on the previous rfd */ + rfdp->rfd_header.cb_cmd &= ~RFD_EL_BIT; + pci_dma_sync_single(bdp->ppci_dev,rfdp->dma_addr,bddp->rfd_size,PCI_DMA_TODEVICE); + } + bddp->rfd_tail = new_skb; /* reset the tail pointer */ + if (bddp->rfd_head == NULL) + bddp->rfd_head = new_skb; + + +#if DEBUG_SKB > 0 + printk(KERN_DEBUG "add_to_end, board_num = 0x%x\n", bddp->bdp->bd_number ); + printk(KERN_DEBUG " rfd_head = 0x%x, rfd_tail = 0x%x\n", + bddp->rfd_head, bddp->rfd_tail ); + printk(KERN_DEBUG " rfdn->next = 0x%x, rfdn->prev = 0x%x\n", + rfdn->next, rfdn->prev ); + printk(KERN_DEBUG " rfdp->next = 0x%x, rfdp->prev = 0x%x\n", + rfdp->next, rfdp->prev ); +#endif /* DEBUG_SKB */ + + return; +} + + +/* + * Procedure: e100_exec_cmd + * + * Description: This general routine will issue a command to the e100. + * + * Arguments: + * bdp - Ptr to this card's e100_bdconfig structure + * scb_cmd_low - The command that is to be issued. + */ +#define e100_exec_cmd(bdp, cmd_low) (bdp)->bddp->scbp->scb_cmd_low = (uint8_t) (cmd_low) + + +/* + * Procedure: e100_wait_exec_cmd + * + * Description: This general routine will issue a command to the e100. + * bdp - Ptr to this card's e100_bdconfig structure + * scb_cmd_low - The command that is to be issued. + * + * Returns: + * B_TRUE if the command was issued to the chip successfully + * B_FALSE if the command was not issued to the chip + */ +inline boolean_t +e100_wait_exec_cmd(bd_config_t *bdp, uint8_t scb_cmd_low) +{ + bdd_t *bddp; /* stores all adapter specific info */ + bddp = (pbdd_t) bdp->bddp; /* get the bddp for this board */ + + if (DEBUG) + printk(KERN_DEBUG "e100_wait_exec_cmd: Called with cmd=0x%x\n", scb_cmd_low); + + if (e100_wait_scb(bdp) != B_TRUE) { + printk(KERN_ERR "e100_wait_exec_cmd: Wait failed. scb cmd=0x%x\n", + bddp->scbp->scb_cmd_low); + return (B_FALSE); + } + + e100_exec_cmd(bdp, scb_cmd_low); + return (B_TRUE); +} + + +void e100_tx_srv (bd_config_t *); +void e100_rx_srv (bd_config_t *); +void e100_watchdog (device_t *); +void e100_refresh_txthld (bd_config_t *); +void e100_adjust_cid (bd_config_t *); +void e100_cu_start (bd_config_t *, tcb_t *); + +static ptcb_t e100_prepare_xmit_buff (bd_config_t *, sk_buff_t *), + e100_prepare_ext_xmit_buff (bd_config_t *, sk_buff_t *); + +/* Functions for accessing the physical layer (PHY) hardware */ +static boolean_t e100_SetupPhy (bd_config_t *), + e100_PhyLinkState (bd_config_t *), e100_GetPhyLinkState(bd_config_t *), + e100_phydetect (bd_config_t *); + +void e100_FindPhySpeedAndDpx (bd_config_t *, uint_t); +void e100_ForceSpeedAndDuplex (bd_config_t *); +void e100_auto_neg (bd_config_t *); +void e100_fix_polarity (bd_config_t *bdp); +void e100_ResetPhy (bd_config_t *); +void e100_MdiWrite (bd_config_t *, uint32_t, uint32_t, uint16_t); +void e100_MdiRead (bd_config_t *, uint32_t, uint32_t, uint16_t *); +void e100_phy_check (bd_config_t *); +void e100_ResetPhy(bd_config_t *); + +/* 82562E (Gilad) Function Prototypes */ +void Phy82562EHNoiseFloorWrite(bdd_t *adapter, uint8_t Value); +void Phy82562EHNoiseCounterClear(bdd_t *adapter); +uint8_t Phy82562EHNoiseEventsRead(bdd_t *adapter); +void Phy82562EHDelayMilliseconds(int time); +uint8_t Phy82562EHNoiseEventsWithDelayCount(bdd_t *adapter, uint8_t NoiseFloor, int32_t Delay); +uint8_t Phy82562EHMedianFind(bdd_t *adapter); +void Phy82562EHAddressSpaceSwitch(bdd_t *adapter, int32_t Page); +void Phy82562EHRegisterInit(bdd_t *adapter); +void Phy82562EHNoiseFloorCalculate(bdd_t *adapter); +void Phy82562EHSpeedPowerSetup(bdd_t *bddp); +void PhyProcessing82562EHInit(bdd_t *bddp); + +static void e100_handle_zero_lock_state(bd_config_t *bdp); + + +/***************************************************************************/ +/***************************************************************************/ +/* Module Install/Uninstall Stuff */ +/***************************************************************************/ + +/**************************************************************************** + * Name: e100_init + * + * Description: This routine is called when the dynamic driver module + * "e100" is loaded using the command "insmod". + * It calls the initialization routine e100init. + * + * This is a Linux required routine. + * + * Born on Date: 07/11/99 + * + * Arguments: dev * + * + * Returns: number of boards + * + * Modification log: + * Date Who Description + * -------- --- -------------------------------------------------------- + * + ****************************************************************************/ +static int +e100_init(void) +{ + device_t *dev; + bd_config_t *bdp; + bdd_t *bddp; + pci_dev_t *pcid = NULL; + int first_time = 0; + static int e100_ohio_flag = 0; /* will be set if ohio found */ + + if (DEBUG) printk(KERN_DEBUG "e100_init\n"); + + if (!pci_present()) return 0; + + /* loop through all of the ethernet PCI devices looking for ours. + * if we encounter device that we can't "pick up" we pass to the next, + * while after memory error we stop looking further for NICs */ + while ((pcid = pci_find_class(PCI_CLASS_NETWORK_ETHERNET << 8, pcid))) { + dev = NULL; + + if (E100_DEBUG) + printk(KERN_DEBUG "e100_init: vendor = 0x%x, device = 0x%x \n", + pcid->vendor, pcid->device); + + if ((pcid->vendor != 0x8086) || + ((pcid->device != 0x1229) && + (pcid->device != 0x1029) && + (pcid->device != 0x1209) && + (pcid->device != 0x2449) && + !((pcid->device > 0x1030) && (pcid->device < 0x1039)))) { + continue; + } + + dev = init_etherdev(dev, 0); + if (dev == NULL) { + printk(KERN_ERR "Not able to alloc etherdev struct\n"); + return e100nics; + } + + if (!first_time) { + /* print out the version */ + first_time = 1; + printk(KERN_NOTICE "%s\n", e100_full_driver_name); + printk(KERN_NOTICE "%s\n", e100_copyright); + } + + /* Allocate all the memory that the driver will need */ + /* Tx and Rx descriptors will be allocated later in this function */ + if (!(bdp = e100_alloc_space(pcid))) { + printk(KERN_ERR "%s - Failed to allocate memory\n", e100_short_driver_name); + e100_dealloc_space(bdp); + unregister_netdev(dev); + return e100nics; + } + bdp->flags = 0; + bddp = bdp->bddp; + bdp->ppci_dev = pcid; + bddp->ven_id = pcid->vendor; + bddp->dev_id = pcid->device; + bddp->pci_dev = pcid; + bdp->vendor = pcid->vendor; + + /* Obtain the PCI specific information about the driver. */ + + e100_get_pci_info(pcid, bdp); + if (check_region(bdp->io_start, 32)) { /* card is catched by someone else */ + e100_dealloc_space(bdp); + unregister_netdev(dev); + continue; + } + + request_region(bdp->io_start, 32, e100_short_driver_name); + + /* Decide whether to load or not based on the * sub-device ID file. + * This also sets the id string. */ + if (!e100_GetBrandingMesg(bdp)) { + release_region(bdp->io_start, 32); + e100_dealloc_space(bdp); + unregister_netdev(dev); + continue; + } + + if (E100_DEBUG) + printk(KERN_DEBUG "ven_id = 0x%x\n", bddp->ven_id); + + /* init the timer */ + bdp->timer_val = -1; + + /* save off the needed information */ + bdp->device = dev; + dev->priv = bdp; + dev->base_addr = bdp->mem_start; /* set in e100_get_pci_info */ + dev->irq = pcid->irq; + bdp->irq_level = pcid->irq; + + if ((bddp->dev_id > 0x1030) && (bddp->dev_id < 0x1039)) { + bddp->rev_id = 0xff; /* workaround for ICH3 */ + } + /* set up other board info based on PCI info */ + if (bddp->rev_id == 0xff) + bddp->rev_id = 1; /* If rev_id is invalid, treat this as a 82557 */ + if ((uint8_t) bddp->rev_id >= D101A4_REV_ID) + bddp->flags |= IS_BACHELOR; + if((uint8_t) bddp->rev_id >= D102_REV_ID) { + bddp->flags |= USE_IPCB; + bddp->rfd_size = 32; + } else { + bddp->rfd_size = 16; + } + if ( (bddp->dev_id == 0x2449) || + ((bddp->dev_id > 0x1030) && (bddp->dev_id < 0x1039)) ) + bddp->flags |= IS_ICH; + + /* Identify Ohio's Port number */ + if (bddp->sub_dev_id == PCI_OHIO_BOARD) { + /* identify Port 1 or Port 2 based on static ohio flag */ + if (!e100_ohio_flag) { + strcat(e100id_string, " (Port 1)"); + e100_ohio_flag = 1; /* so that the next port shows as port 2 */ + } else { + strcat(e100id_string, " (Port 2)"); + e100_ohio_flag = 0; /* in case there is > 1 ohio board */ + bddp->port_num = 2; + } + } + + e100_check_options(e100nics); + + /* init all the data structure and find the rest of the pci info */ + if (!e100init(bdp)) { + printk(KERN_ERR "Failed to initialize e100, instance #%d\n", e100nics); + release_region(bdp->io_start, 32); + e100_dealloc_space(bdp); + unregister_netdev(dev); + continue; + } + +#ifdef CONFIG_PROC_FS + if (create_e100_proc_subdir(bdp) < 0) { + remove_e100_proc_subdir(dev); + release_region(bdp->io_start, 32); + e100_dealloc_space(bdp); + unregister_netdev(dev); + continue; + } +#endif + /* Printout the board configuration */ + e100_print_brd_conf(bdp); + + /* assign driver methods */ + dev->open = &e100_open; + dev->hard_start_xmit = &e100_xmit_frame; + dev->stop = &e100_close; + 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; + e100nics++; + + if (E100_DEBUG) { + printk(KERN_DEBUG "dev = 0x%p ", dev); + printk(KERN_DEBUG " priv = 0x%p\n", dev->priv); + printk(KERN_DEBUG " irq = 0x%x ", dev->irq); + printk(KERN_DEBUG " next = 0x%p ", dev->next); + printk(KERN_DEBUG " flags = 0x%x\n", dev->flags); + printk(KERN_DEBUG " bdp = 0x%p\n", bdp); + printk(KERN_DEBUG " irq_level = 0x%x\n", bdp->irq_level); + } + if (e100nics == MAX_NIC) { + printk(KERN_NOTICE "e100: found %d NICs, stop searching further\n", MAX_NIC); + break; + } + + } /* end of pci_find_class while loop */ + + return e100nics; +} + +/* Set some of the modules specific things here */ +#ifdef MODULE + +MODULE_AUTHOR("Intel Corporation, "); +MODULE_DESCRIPTION(__MODULE_STRING(e100id_string)); +MODULE_PARM(TxDescriptors, "1-" __MODULE_STRING(MAX_NIC) "i"); +MODULE_PARM(RxDescriptors, "1-" __MODULE_STRING(MAX_NIC) "i"); +MODULE_PARM(XsumRX, "1-" __MODULE_STRING(MAX_NIC) "i"); +MODULE_PARM(e100_speed_duplex, "1-" __MODULE_STRING(MAX_NIC) "i"); +MODULE_PARM(PhoneLinePower, "1-" __MODULE_STRING(MAX_NIC) "i"); +MODULE_PARM(PhoneLineSpeed, "1-" __MODULE_STRING(MAX_NIC) "i"); +MODULE_PARM(ucode, "1-" __MODULE_STRING(MAX_NIC) "i"); +MODULE_PARM(ber, "1-" __MODULE_STRING(MAX_NIC) "i"); + + +/**************************************************************************** + * Name: init_module + * + * Description: This routine is an entry point into the driver. + * + * This is a Linux required routine. + * + * Born on Date: 07/11/99 + * + * Arguments: + * NONE + * + * Returns: + * It returns 0 if at least 1 nic was found and initialized + * else it returns -ENODEV. + * + * Modification log: + * Date Who Description + * -------- --- -------------------------------------------------------- + * + ****************************************************************************/ +int +init_module(void) +{ +#ifdef CONFIG_PROC_FS + 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 -ENODEV; +#endif + return e100_init() ? 0 : -ENODEV; +} + + +/**************************************************************************** + * Name: cleanup_module + * + * Description: This routine is an entry point into the driver. + * + * This is a Linux required routine. + * + * Born on Date: 07/11/99 + * + * Arguments: + * NONE + * + * Returns: + * It returns 0 and can not fail + * + * Modification log: + * Date Who Description + * -------- --- -------------------------------------------------------- + * + ****************************************************************************/ +int +cleanup_module(void) +{ + bd_config_t *bdp, *next_bdp; + device_t *dev, *next_dev; + bdd_t *bddp; + + if (E100_DEBUG) + printk(KERN_DEBUG "cleanup_module: SOR, dev = 0x%p\n", dev); + + /* start looking at the first device */ + if (!e100_first) return 0; + + dev = e100_first->device; + while (dev) { +#ifdef CONFIG_PROC_FS + remove_e100_proc_subdir(dev); +#endif + bdp = (bd_config_t *) dev->priv; + bddp = bdp->bddp; + next_bdp = bdp->bd_next; + next_dev = (next_bdp) ? next_bdp->device : NULL; + + e100_ResetPhy(bdp); + e100_sw_reset(bdp, PORT_SELECTIVE_RESET); + + unregister_netdev(dev); + iounmap(bddp->scbp); + release_region(bdp->io_start, 32); + e100_dealloc_space(bdp); + + dev = next_dev; + } +#ifdef CONFIG_PROC_FS + { + struct proc_dir_entry *de; + + /* check if the subdir list is empty before removing adapters_proc_dir */ + for (de = adapters_proc_dir->subdir; de; de = de->next) { + /* ignore . and .. */ + if (*(de->name) == '.') continue; + break; + } + if (de) return 0; + remove_proc_entry(ADAPTERS_PROC_DIR, proc_net); + } +#endif + return 0; +} + +#else /* NOT MODULE */ + +int +e100_probe(void) +{ +#ifdef CONFIG_PROC_FS + 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 -ENODEV; +#endif + return e100_init() ? 0 : -ENODEV; +} + +#ifdef __ia64__ +/* the probe routine will only be called if this is here */ +module_init(e100_probe); +#endif /* __ia64__ */ + +#endif /* MODULE */ + + +/**************************************************************************** + * Name: e100_check_options + * + * Description: This routine does range checking on command-line options + * + * Born on Data: 05/02/2000 + * + * Arguments: int board + * + * Returns: void (cannot fail) + * + ***************************************************************************/ +void +e100_check_options(int board) +{ + /* Transmit Descriptor Count */ + if (TxDescriptors[board] == -1) { + TxDescriptors[board] = E100_DEFAULT_TCB; + } else if (TxDescriptors[board] > E100_MAX_TCB){ + printk(KERN_NOTICE "Invalid TxDescriptor count specified (%i)," + " using maximum value of %i\n",TxDescriptors[board],E100_MAX_TCB); + TxDescriptors[board] = E100_MAX_TCB; + }else if (TxDescriptors[board] < E100_MIN_TCB) { + printk(KERN_NOTICE "Invalid TxDescriptor count specified (%i)," + " using minimum value of %i\n", TxDescriptors[board], E100_MIN_TCB); + TxDescriptors[board] = E100_MIN_TCB; + } else { + printk(KERN_NOTICE "Using specified value of %i TxDescriptors\n", + TxDescriptors[board]); + } + + /* Receive Descriptor Count */ + if (RxDescriptors[board] == -1) { + RxDescriptors[board] = E100_DEFAULT_RFD; + } else if ((RxDescriptors[board] > E100_MAX_RFD) || + (RxDescriptors[board] < E100_MIN_RFD)) { + printk(KERN_NOTICE "Invalid RxDescriptor count specified (%i)," + " using default of %i\n", RxDescriptors[board], E100_DEFAULT_RFD); + RxDescriptors[board] = E100_DEFAULT_RFD; + } else { + printk(KERN_NOTICE "Using specified value of %i RxDescriptors\n", + RxDescriptors[board]); + } + + /* XsumRX (initialy set to TRUE) */ + if ((XsumRX[board] != TRUE) && (XsumRX[board] != FALSE)) { + printk(KERN_NOTICE "Invalid XsumRX value specified (%i)," + " using default of %i\n", XsumRX[board], E100_DEFAULT_XSUM); + XsumRX[board] = E100_DEFAULT_XSUM; + } + + if (ber[board] > ZLOCK_MAX_ERRORS) { + ber[board] = ZLOCK_MAX_ERRORS; + printk(KERN_NOTICE "Invalid Bit Error Rate count specified (%i)," + " using default of %i\n", ber[board], ZLOCK_MAX_ERRORS); + } else if (ber[board] != ZLOCK_MAX_ERRORS) { + printk(KERN_NOTICE "Using specified BER value of %i \n",ber[board]); + } +} + + +/***************************************************************************/ +/***************************************************************************/ +/* Driver Methods (i.e. procvars at device_t */ +/***************************************************************************/ + +/**************************************************************************** + * Name: e100_open + * + * Description: This routine is the open call for the interface. + * + * This is a Linux required routine. + * + * Born on Date: 07/11/99 + * + * Arguments: dev * + * + * Returns: + * It returns 0 on success + * -EAGAIN on failure + * + * Modification log: + * Date Who Description + * -------- --- -------------------------------------------------------- + * + ****************************************************************************/ +static int +e100_open(device_t * dev) +{ + bd_config_t *bdp; + bdd_t *bddp; + pbuf_pool_t ptcb_pool; + + bdp = dev->priv; + bddp = bdp->bddp; + + if (E100_DEBUG) + printk(KERN_DEBUG "open: SOR, bdp = 0x%p\n", bdp); + + if (bdp->flags & DF_OPENED) { + if (E100_DEBUG) + printk(KERN_DEBUG "open: Device is already open. " + "Undo any changes you have made\n"); + return -EBUSY; + } + + if (request_irq(dev->irq, &e100intr, SA_SHIRQ, e100_short_driver_name, dev)) { + if (E100_DEBUG) printk(KERN_DEBUG "open: request_irq failed\n"); + return -EAGAIN; + } + + /* setup the tcb pool */ + if (!e100_alloc_tcbs(bdp)) { + if (E100_DEBUG) + printk(KERN_DEBUG "%s - Failed to allocate descriptors\n", + e100_short_driver_name); + + e100_free_tbds(bdp); + free_irq(dev->irq, dev); + return -ENOMEM; + } + + ptcb_pool = &bddp->tcb_pool; + ptcb_pool->head = 0; + ptcb_pool->tail = 0; + ptcb_pool->count = TxDescriptors[bdp->bd_number]; + e100_setup_tcb_pool((ptcb_t) ptcb_pool->data, + TxDescriptors[bdp->bd_number], bdp); + + /* Arrange dynamic RFD's in a circular queue & setup buffer pool */ + if (e100_alloc_rfd_pool(bddp) == NULL) { + + e100_free_rfd_pool(bdp); + e100_free_tbds(bdp ); + free_irq(dev->irq, dev); + return -ENOMEM; + } + + /* We have to reload CU and RU base because they could have been + corrupted from a TCO packet */ + /* Load the CU BASE (set to 0, because we use linear mode) */ + bddp->prev_cu_cmd = SCB_CUC_LOAD_BASE; + bddp->scbp->scb_gen_ptr = 0; + e100_exec_cmd(bdp, SCB_CUC_LOAD_BASE); + + /* Wait for the SCB command word to clear before we set the * general + * pointer */ + if (e100_wait_scb(bdp) != B_TRUE){ + + e100_free_rfd_pool(bdp); + e100_free_tbds(bdp); + free_irq(dev->irq, dev); + return -EAGAIN; + } + + /* Load the RU BASE (set to 0, because we use linear mode) */ + bddp->scbp->scb_gen_ptr = 0; + bddp->prev_cu_cmd = SCB_RUC_LOAD_BASE; + e100_exec_cmd(bdp, SCB_RUC_LOAD_BASE); + + /* up the mod use count used by the system */ + MOD_INC_USE_COUNT; + + /* launch the watchdog timer */ + init_timer(&bdp->timer_id); + bdp->timer_id.expires = bdp->timer_val = jiffies + (2 * HZ); + bdp->timer_id.data = (ulong_t) dev; + bdp->timer_id.function = (void *) &e100_watchdog; + add_timer(&bdp->timer_id); + + netif_start_queue(dev); + + e100_start_ru(bdp); + e100_enbl_intr(bdp); + + bdp->flags |= DF_OPENED; + return 0; +} + +/**************************************************************************** + * Name: e100_close + * + * Description: This routine is an entry point into the driver. + * + * This is a Linux required routine. + * + * Born on Date: 07/11/99 + * + * Arguments: + * device_t pointer + * + * Returns: + * It returns 0 and can not fail. + * + * Modification log: + * Date Who Description + * -------- --- -------------------------------------------------------- + * + ****************************************************************************/ +static int +e100_close(device_t * dev) +{ + bd_config_t *bdp; + bdd_t *bddp; + + bdp = dev->priv; + bddp = bdp->bddp; + + /* set the device to not started */ + netif_stop_queue(dev); + + /* stop the hardware */ + e100_ru_abort(bdp); + + /* Disable all possible interrupts including the sequence error interrupts. */ + e100_dis_intr(bdp); + free_irq(dev->irq, dev); + + /* kill the timer */ + del_timer(&bdp->timer_id); + + /* free tx and rx memory structures */ + e100_free_tbds(bdp); + e100_free_rfd_pool(bdp); + + /* reset the phy */ + e100_ResetPhy(bdp); + + /* lets reset the chip */ + e100_sw_reset(bdp, PORT_SELECTIVE_RESET); + + MOD_DEC_USE_COUNT; + + bdp->flags &= ~DF_OPENED; + + return (0); +} + +/**************************************************************************** + * Name: e100_xmit_frame + * + * Description: This routine is called to transmit a frame. + * + * + * Born on Date: 07/11/99 + * + * Arguments: + * sb_buff pointer + * device_t pointer + * + * Returns: + * 1 on failure + * 0 on success + * + * Modification log: + * Date Who Description + * -------- --- -------------------------------------------------------- + * + ****************************************************************************/ +static int +e100_xmit_frame(sk_buff_t * skb, device_t * dev) +{ + bd_config_t *bdp = dev->priv; + bdd_t *bddp = bdp->bddp; + int lock_flag; + net_device_stats_t *stats = &(bddp->net_stats); + + /* get the tx lock */ + spin_lock_irqsave(&bddp->bd_tx_lock, lock_flag); + + /* if there are no tcbs, tell stack to stop sending frames to us for now */ + if (!TCBS_AVAIL(&(bddp->tcb_pool))) { + if (DEBUG_TX) printk(KERN_DEBUG "e100_tx_frame no TCBs left\n"); + netif_stop_queue(dev); + spin_unlock_irqrestore(&bddp->bd_tx_lock, lock_flag); + return 1; + } + + if (bddp->flags & USE_IPCB) + e100_prepare_xmit_buff(bdp, skb); + else if ((bddp->flags & IS_BACHELOR) && (e100_enhanced_tx_enable)) + e100_prepare_ext_xmit_buff(bdp, skb); + else + e100_prepare_xmit_buff(bdp, skb); + stats->tx_bytes += skb->len; + + dev->trans_start = jiffies; + spin_unlock_irqrestore(&bddp->bd_tx_lock, lock_flag); + + return 0; +} + + +/**************************************************************************** + * Name: e100_get_stats + * + * Description: This routine is called when the OS wants the nic stats returned + * + * Arguments: + * device_t dev - the device stucture to return stats on + * + * Returns: + * the address of the net_device_stats stucture for the device + * + * Modification log: + * Date Who Description + * -------- --- -------------------------------------------------------- + * + ****************************************************************************/ +static struct net_device_stats * +e100_get_stats(device_t * dev) +{ + bd_config_t *bdp = dev->priv; + bdd_t *bddp = bdp->bddp; + err_stats_t *bd_stats = bddp->perr_stats; + + struct net_device_stats *stats = &(bddp->net_stats); + + /* copy over from out stats struct into the Linux one */ + /* rx_bytes is updated in e100_rx_srv */ + stats->rx_packets = bd_stats->gd_recvs; + /* tx_bytes is updated in e100_xmit_frame */ + stats->tx_packets = bd_stats->gd_xmits; + /* add up all the bad recv counters for total number of recv errors */ + stats->rx_errors = bd_stats->rcv_crc_err + bd_stats->rcv_align_err + + bd_stats->rcv_runts + bd_stats->rcv_cdt_frames; + + /* add up all the tx errors for the total number of tx frames dropped */ + stats->tx_errors = bd_stats->tx_lost_csrs + bd_stats->tx_abrt_xs_col; + stats->rx_dropped = bd_stats->rcv_rsrc_err; + stats->collisions = bd_stats->tx_tot_retries; + stats->rx_length_errors = bd_stats->rcv_runts; + stats->rx_over_errors = bd_stats->rcv_rsrc_err; + stats->rx_crc_errors = bd_stats->rcv_crc_err; + stats->rx_frame_errors = bd_stats->rcv_align_err; + stats->rx_fifo_errors = bd_stats->rcv_dma_orun; + stats->tx_aborted_errors = bd_stats->tx_abrt_xs_col; + stats->tx_carrier_errors = bd_stats->tx_lost_csrs; + stats->tx_fifo_errors = bd_stats->tx_dma_urun; + + return (stats); +} + + +/**************************************************************************** + * Name: e100_set_mac + * + * Description: This routine sets the ethernet address of the board + * + * Born on Date: 07/11/99 + * + * Arguments: + * dev - Ptr to the dev structure for this card + * addr - Ptr to the new ethernet address + * + * Returns: + * 0 - If successful + * -1 - If not successful + * + * Modification log: + * Date Who Description + * -------- --- -------------------------------------------------------- + * + ****************************************************************************/ +static int +e100_set_mac(device_t * dev, void *addr) +{ + bd_config_t *bdp; + bdd_t *bddp; + e100_eaddr_t *eaddrp; + struct sockaddr *p_sockaddr = (struct sockaddr *) addr; + + if (DEBUG) + printk(KERN_DEBUG "e100_set_mac()\n"); + + bdp = dev->priv; + bddp = bdp->bddp; + eaddrp = (e100_eaddr_t *) p_sockaddr->sa_data; + + /* copy over the new mac address */ + memcpy(&(bdp->eaddr), eaddrp, ETHERNET_ADDRESS_LENGTH); + + /* copy the new address into our dev structure */ + memcpy(&(dev->dev_addr), eaddrp, ETHERNET_ADDRESS_LENGTH); + + /* Now call setup_iaaddr to set the mac address on the hardware */ + return ((e100_setup_iaaddr(bdp, eaddrp) == B_TRUE ) ? 0 : -1); +} + + +/***************************************************************************** + * Name: e100_set_multi + * + * Description: this routine is called to add multicast addresses + * + * Born on Date: 1/5/00 + * + * Arguments: + * dev - device structure + * + * Returns: + * (none) + * + * Modification log: + * Date Who Description + * -------- --- -------------------------------------------------------- + * + *****************************************************************************/ +static void +e100_set_multi(device_t * dev) +{ + bd_config_t *bdp = dev->priv; + bdd_t *bddp = bdp->bddp; + mltcst_cb_t *mcast_buff; + cb_header_t *cb_hdr; + uint_t i; + struct dev_mc_list *mc_list; + int lock_flag, e100_retry; + uint8_t rx_mode; + + bddp->promisc = (dev->flags & IFF_PROMISC); + bddp->mulcst_enbl = ((dev->flags & IFF_ALLMULTI) + || (dev->mc_count > MAX_MULTICAST_ADDRS)); + + if (bddp->promisc) rx_mode = 3; + else if (bddp->mulcst_enbl) rx_mode = 1; + else rx_mode = 0; + + /* if rx mode has changed - reconfigure the chip */ + if (bddp->prev_rx_mode != rx_mode) { + bddp->prev_rx_mode = rx_mode; + spin_lock_irqsave(&bddp->bd_lock, lock_flag); + e100_configure(bdp); + spin_unlock_irqrestore(&bddp->bd_lock, lock_flag); + } + + if (rx_mode) return; /* no need for Multicast Cmd */ + + /* get the multicast CB */ + spin_lock_irqsave(&bddp->bd_lock, lock_flag); + mcast_buff = &(bddp->pntcb->ntcb.multicast); + cb_hdr = &(bddp->pntcb->ntcb.multicast.mc_cbhdr); + + /* initialize the multi cast command */ + cb_hdr->cb_status = 0; + cb_hdr->cb_cmd = CB_MULTICAST; + cb_hdr->cb_lnk_ptr = 0; + + /* now fill in the rest of the multicast command */ + *(uint16_t *)(&(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 * ETHERNET_ADDRESS_LENGTH]), + (uint8_t *) & (mc_list->dmi_addr), ETHERNET_ADDRESS_LENGTH); + } + + /* Wait for the SCB command word to clear before we set the * general + * pointer */ + if (e100_wait_scb(bdp) != B_TRUE) { + spin_unlock_irqrestore(&bddp->bd_lock, lock_flag); + printk(KERN_WARNING "Multicast setup failed\n"); + return; + } + + /* If we have issued any transmits, then the CU will either be active, * + * or in the suspended state. If the CU is active, then we wait for * + * it to be suspended. */ + if ((bddp->prev_cu_cmd == CB_TRANSMIT) || + (bddp->prev_cu_cmd == CB_TRANSMIT_FIRST)) { + /* Wait for suspended state */ + e100_retry = E100_CMD_WAIT; + while (((bddp->scbp->scb_status & SCB_CUS_MASK) == SCB_CUS_ACTIVE) + && (e100_retry)) { + mdelay(20); + e100_retry--; + } + } + + /* Update the command list pointer. */ + bddp->scbp->scb_gen_ptr = bddp->nontx_paddr; + /* store the command */ + bddp->prev_cu_cmd = CB_MULTICAST; + /* Submit the Multicast Cmd to the chip, and wait for it to complete. */ + if (!e100_exec_poll_cmd(bdp)) { + printk(KERN_WARNING "Multicast setup failed\n"); + } + spin_unlock_irqrestore(&bddp->bd_lock, lock_flag); + return; +} + + +/**************************************************************************** + * Name: e100_ioctl + * + * Description: Driver's ioctl method + * + * Arguments: + * + * Returns: 0 - on success, negative value on failure + ****************************************************************************/ +static int +e100_ioctl(device_t *dev, struct ifreq *ifr, int cmd) +{ + /* switch on the command */ + switch(cmd) { + default: + return -EOPNOTSUPP; + } + return 0; +} + + +/***************************************************************************/ +/***************************************************************************/ +/* Initialization Routines */ +/***************************************************************************/ + +/**************************************************************************** + * Name: e100init + * + * Description: This routine is called when this driver is loaded. This is + * the initialization routine which allocates memory + * configures the adapter & determines the system + * resources. + * + * Arguments: bd_config_t *bdp + * + * Returns: + * NONE + * + * Modification log: + * Date Who Description + * -------- --- -------------------------------------------------------- + * + ****************************************************************************/ +int +e100init(bd_config_t *bdp) +{ + device_t *dev = bdp->device; + bdd_t *bddp = bdp->bddp; + + if (DEBUG) printk(KERN_DEBUG "e100init()\n"); + + /* init private vars: never fails */ + e100_sw_init(bdp); + + /* Do a self test of the adapter */ + if (!e100_selftest(bdp)) { + printk(KERN_ERR "selftest failed\n"); + return 0; + } + + /* read the MAC address from the eprom */ + e100_rd_eaddr(bdp); + /* read NIC's part number */ + e100_rd_pwa_no(bdp); + + /* Do the adapter initialization */ + if (!e100_hw_init(bdp, PORT_SOFTWARE_RESET)) { + printk(KERN_ERR "hw init failed\n"); + return 0; + } + /* Disable interrupts on the PRO/100 card */ + e100_dis_intr(bdp); + + dev->base_addr = bdp->io_start; + dev->mem_start = (ulong_t) bddp->scbp; + dev->mem_end = (ulong_t) (bddp->scbp + sizeof(scb_t)); + + if (E100_DEBUG) printk(KERN_DEBUG "e100_init: end\n"); + + return 1; +} + + +/**************************************************************************** + * Procedure : e100_sw_init + * + * Description : 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. + * + * Input : + * bdp - + * + * Returns : + * B_TRUE - if successfully initialized + * B_FALSE - if S/W initialization failed + */ +boolean_t +e100_sw_init(bd_config_t *bdp) +{ + bdd_t *bddp = bdp->bddp; /* stores all adapter specific info */ + + if (DEBUG) + printk(KERN_DEBUG "e100_sw_init: [brd %d] begin.\n", bdp->bd_number); + + bddp->bd_number = bdp->bd_number; + bddp->prev_cu_cmd = CB_NULL; + bddp->old_xmits = 0; + bddp->brdcst_dsbl = 0; + bddp->promisc = 0; + bddp->prev_rx_mode = 0; + bddp->mulcst_enbl = 0; + + /* Change for 82558 enhancement set num interrupts to 0 */ + bddp->num_cna_interrupts = + ((e100_current_cna_backoff >= 0) && (e100_current_cna_backoff <= 0x1f)) + ? e100_current_cna_backoff : 0; + + /* + * Set the value for # of good xmits per underrun. the value assigned + * here is an intelligent suggested default. Nothing magical about it. + */ + bddp->tx_per_underrun = DEFAULT_TX_PER_UNDERRUN; + + /* Initialize the checksum flag. If it is supported by the hardware It + * will be truned on in the configure command. */ + bddp->checksum_offload_enabled = 0; + + /* get the default transmit threshold value */ + bddp->tx_thld = e100_tx_thld; + + /* get the EPROM size */ + bddp->EEpromSize = e100_GetEEpromSize(bdp); + + /* Initialize our spinlocks */ + spin_lock_init(&(bddp->bd_lock)); + spin_lock_init(&(bddp->bd_intr_lock)); + spin_lock_init(&(bddp->bd_tx_lock)); + spin_lock_init(&(bddp->bd_rx_lock)); + spin_lock_init(&(bddp->bd_srv_lock)); + + /* Initialize the phone line phy values */ + bddp->Phy82562EHSampleCount = 8; + bddp->Phy82562EHSampleDelay = 35; + bddp->Phy82562EHSampleFilter = 1; + + bdp->ZeroLockState = ZLOCK_INITIAL; + + return 1; +} + + +/***************************************************************************** + * Procedure: e100_hw_init + * + * Description: 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. + * + * Arguments: + * bdp - Ptr to this card's e100_bdconfig structure + * reset_cmd - s/w reset or selective reset. + * + * Returns: + * B_TRUE - If the adapter was initialized + * B_FALSE - If the adapter failed initialization + */ +boolean_t +e100_hw_init(bd_config_t *bdp, uint32_t reset_cmd) +{ + bdd_t *bddp = (bdd_t *) bdp->bddp; + + if (DEBUG) + printk(KERN_DEBUG "e100_hw_init: begin\n"); + + /* Detect the serial component, and set up the Phy if necessary */ + if (!e100_phydetect(bdp)) + return (B_FALSE); + + e100_fix_polarity(bdp); + + /* 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) */ + bddp->prev_cu_cmd = SCB_CUC_LOAD_BASE; + bddp->scbp->scb_gen_ptr = 0; + e100_exec_cmd(bdp, SCB_CUC_LOAD_BASE); + + /* Wait for the SCB command word to clear before we set the * general + * pointer */ + if (e100_wait_scb(bdp) != B_TRUE) + return (B_FALSE); + + /* Load the RU BASE (set to 0, because we use linear mode) */ + bddp->scbp->scb_gen_ptr = 0; + bddp->prev_cu_cmd = SCB_RUC_LOAD_BASE; + e100_exec_cmd(bdp, SCB_RUC_LOAD_BASE); + + /* Configure the adapter in non promiscious mode */ + if (!e100_configure(bdp)) + return (B_FALSE); + + /* Load interrupt microcode */ + if (e100_load_microcode(bdp, bddp->rev_id) == B_TRUE) { + bdp->flags |= DF_UCODE_LOADED; + mdelay(1000); + } + + if (!e100_setup_iaaddr(bdp, &bdp->eaddr)) + return (B_FALSE); + + /* Clear the internal counters */ + if (!e100_clr_cntrs(bdp)) + return (B_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 ((bddp->flags & IS_BACHELOR) && (e100_flow_control_enable)) { + bddp->scbp->scb_ext.d101_scb.scb_fc_thld = DFLT_FC_THLD; + bddp->scbp->scb_ext.d101_scb.scb_fc_xon_xoff = DFLT_FC_CMD; + } + + return (B_TRUE); +} + + +/**************************************************************************** + * Procedure : e100_setup_tcb_pool + * + * Description : This routine arranges the contigiously allocated TCB's + * in a circular list . Also does the one time initialization of the + * TCBs. + * + * Input : + * head - Pointer to head of the allocated TCBs'. + * qlen - Number of elements in the queue. + * bdp - Ptr to this card's e100_bdconfig structure + * + * Returns : + * NONE + */ +static void +e100_setup_tcb_pool(ptcb_t head, uint_t qlen, bd_config_t *bdp) +{ + int ele_no; + ptcb_t pcurr_tcb; /* point to current tcb */ + ptcb_t pnext_tcb; /* point to next tcb */ + uint32_t next_paddr; /* the next phys addr */ + bdd_t *bddp = bdp->bddp; + + pcurr_tcb = head; + pnext_tcb = head; + + for (ele_no = 0, next_paddr = cpu_to_le32( bddp->tcb_paddr); + ele_no < qlen; ele_no++, pcurr_tcb++) { + + /* set the phys addr for this TCB, next_paddr has not incr. yet */ + pcurr_tcb->tcb_paddr = next_paddr; + + pnext_tcb++; /* point to next tcb */ + + next_paddr += sizeof(tcb_t); + + /* set the link to next tcb */ + if (ele_no == (qlen - 1)) + pcurr_tcb->tcb_hdr.cb_lnk_ptr = cpu_to_le32( bddp->tcb_paddr); + else + pcurr_tcb->tcb_hdr.cb_lnk_ptr = next_paddr; + + /* initialize TCB status to zero */ + pcurr_tcb->tcb_hdr.cb_status = 0; + + /* initialize TCB skb pointer to NULL */ + pcurr_tcb->tcb_skb = NULL; + + /* initialize TCB command */ + pcurr_tcb->tcb_hdr.cb_cmd =cpu_to_le32( CB_EL_BIT | /* Last in CBL */ + CB_TRANSMIT | /* Xmit cmd */ + CB_TX_SF_BIT); /* set flexible mod */ + + /* initialize the early xmit threshold */ + pcurr_tcb->tcb_thrshld = bddp->tx_thld; + } + + return; +} + + +/***************************************************************************/ +/***************************************************************************/ +/* Memory Management Routines */ +/***************************************************************************/ + +/**************************************************************************** + * Name: e100_alloc_space + * + * Description : This routine allocates memory for + * the driver. Memory allocated is for the following structures + * - bdp, bddp + * - error count structure for adapter statistics + * + * Arguments: + * pcid: ptr to pci device kernel struct + * + * Returns: bd_config_t * + * + * Modification log: + * Date Who Description + * -------- --- -------------------------------------------------------- + * + ****************************************************************************/ +bd_config_t * +e100_alloc_space(pci_dev_t *pcid) +{ + bd_config_t *bdp, *temp_bd; + bdd_t *bddp; + + if (E100_DEBUG) + printk(KERN_DEBUG "e100_alloc_space: begin\n"); + + /* allocate space for the private structures */ + if (!(bdp = (bd_config_t *) kmalloc(sizeof(bd_config_t), GFP_ATOMIC))) + return NULL; + memset(bdp, 0x00, sizeof(*bdp)); + + /* link the bdp's, if needed */ + if (!e100_first) { /* do we have at least 1 already alloc'd? */ + e100_first = bdp; + bdp->bd_number = 0; + bdp->bd_next = NULL; + bdp->bd_prev = NULL; + } else { + /* No, so find last in list and link the new one in */ + temp_bd = e100_first; + bdp->bd_number = 1; /* it is at least 1 */ + while (temp_bd->bd_next != NULL) { + temp_bd = (bd_config_t *) temp_bd->bd_next; + bdp->bd_number++; /* set the board number */ + } + temp_bd->bd_next = bdp; + bdp->bd_next = NULL; + bdp->bd_prev = temp_bd; + } + + /* Allocate the bdd_t structure */ + if (!(bddp = (bdd_t *) kmalloc(sizeof(bdd_t), GFP_ATOMIC))) + return NULL; + memset(bddp, 0x00, sizeof(bdd_t)); + bdp->bddp = bddp; /* Hang it of the bdp */ + bddp->bdp = bdp; /* point back to the bdp */ + + /* allocate space for selt test results */ + if (!(bddp->pselftest = + pci_alloc_consistent(pcid,sizeof(self_test_t),&(bddp->selftest_paddr) ))) + return NULL; + + /* allocate space for 82557 register dump area */ + if (!(bddp->pdump_area = + pci_alloc_consistent(pcid,sizeof(dump_area_t),&bddp->dump_paddr))) + return NULL; + + /* allocate space for 82557 adapter statistics area */ + if (!(bddp->pstats_counters = + pci_alloc_consistent(pcid,sizeof(err_cntr_t),&bddp->stat_cnt_paddr))) + return NULL; + + + /* allocate space for non transmit cb commands */ + if (!(bddp->pntcb = + pci_alloc_consistent(pcid,sizeof(nxmit_cb_t),&bddp->nontx_paddr))) + return NULL; + + /* allocate space for stats results */ + if (!(bddp->perr_stats = + pci_alloc_consistent(pcid,sizeof(err_stats_t),&bddp->estat_paddr))) + return NULL; + + memset(bddp->perr_stats, 0, sizeof(err_stats_t)); + if (DEBUG) printk(KERN_DEBUG "e100_alloc_space: end\n"); + + return (bdp); +} + + +/**************************************************************************** + * Name: e100_alloc_tcbs + * + * Description: This routine allocates memory for the transmit + * descriptors. + * + * Arguments: bd_config_t * + * + * Returns: + * 0 - Allocation has failed. + * 1 - Otherwise. + * + * Modification log: + * Date Who Description + * -------- --- -------------------------------------------------------- + * + ****************************************************************************/ +#define stcb sizeof(tcb_t) * TxDescriptors[bdp->bd_number] +#define stbd sizeof(tbd_t) * TxDescriptors[bdp->bd_number] + +int +e100_alloc_tcbs(bd_config_t *bdp) +{ + bdd_t *bddp = bdp->bddp; + + /* allocate space for the TCBs */ + if (!(bddp->tcb_pool.data = + pci_alloc_consistent(bdp->ppci_dev,stcb,&bddp->tcb_paddr))) + return 0; + + memset(bddp->tcb_pool.data, 0x00, stcb); + + /* there is ALWAYS only going to 1 phys frag */ + /* tbd_paddr is a phys_addr but stored as an unsigned long */ + if (!(bddp->tbd_pool.data = + pci_alloc_consistent(bdp->ppci_dev,stbd,&(bddp->tbd_paddr)))) + return 0; + + memset(bddp->tbd_pool.data, 0x00, stbd); + + return 1; +} + +void +e100_free_tbds(bd_config_t *bdp) +{ + bdd_t *bddp = bdp->bddp; + + pci_free_consistent(bdp->ppci_dev,stcb, + bddp->tcb_pool.data,bddp->tcb_paddr); + pci_free_consistent(bdp->ppci_dev,stbd, + bddp->tbd_pool.data,bddp->tbd_paddr); +} + + +/**************************************************************************** + * Name: e100_dealloc_space + * + * Description: This routine frees all the memory allocated by "alloc_space". + * and e100_alloc_tbds. + * + * Born on Date: 7/17/97 + * + * Arguments: bd_config_t * + * + * Returns: none + * + * Modification log: + * Date Who Description + * -------- --- -------------------------------------------------------- + * + ****************************************************************************/ +static void +e100_dealloc_space(bd_config_t *bdp) +{ + bdd_t *bddp = bdp->bddp; + + if (DEBUG) printk(KERN_DEBUG "e100_dealloc_space, bdp = 0x%p\n", bdp); + + /* do we have valid board structure? */ + if (!bdp) return; + + /* is bddp valid? */ + if (bdp->bddp) { + pci_free_consistent(bdp->ppci_dev,sizeof(self_test_t), + bddp->pselftest,bddp->selftest_paddr); + pci_free_consistent(bdp->ppci_dev,sizeof(dump_area_t), + bddp->pdump_area,bddp->dump_paddr); + pci_free_consistent(bdp->ppci_dev,sizeof(err_cntr_t), + bddp->pstats_counters,bddp->stat_cnt_paddr); + pci_free_consistent(bdp->ppci_dev,sizeof(nxmit_cb_t), + bddp->pntcb,bddp->nontx_paddr); + pci_free_consistent(bdp->ppci_dev,sizeof(err_stats_t), + bddp->perr_stats,bddp->estat_paddr); + + bddp->tcb_paddr = 0; + bddp->tbd_paddr = 0; + bddp->selftest_paddr = 0; + bddp->dump_paddr = 0; + bddp->stat_cnt_paddr = 0; + bddp->nontx_paddr = 0; + bddp->estat_paddr = 0; + + kfree(bdp->bddp); + } + + /* un-link the bdp from the linked list */ + if (bdp == e100_first) { + e100_first = (bd_config_t *) bdp->bd_next; + if (bdp->bd_next) + ((bd_config_t *) bdp->bd_next)->bd_prev = NULL; + } else { + if (bdp->bd_next) + ((bd_config_t *) bdp->bd_next)->bd_prev = bdp->bd_prev; + if (bdp->bd_prev) + ((bd_config_t *) bdp->bd_prev)->bd_next = bdp->bd_next; + } + + kfree(bdp); + +} + +void +e100_free_rfd_pool(bd_config_t *bdp) +{ + sk_buff_t *skb, *nskb; + bdd_t *bddp = bdp->bddp; + + while (bddp->rfd_head != NULL) { + skb = bddp->rfd_head; + nskb = (sk_buff_t *) RFD_POINTER(skb,bddp)->next; + pci_unmap_single(bdp->ppci_dev,GET_SKB_DMA_ADDR(skb,bddp), + sizeof(rfd_t),PCI_DMA_TODEVICE); + dev_kfree_skb_irq(skb); + bddp->rfd_head = nskb; + } + + bddp->rfd_head = NULL; + bddp->rfd_tail = NULL; + +} + + +/* + * Procedure : e100_alloc_rfd_pool + * + * Description : allocates initial pool of skb which holds both rfd and data + * Input : + * bddp - pointer to board specific data + * + * Returns : + * pointer to head of list + */ + +static sk_buff_t * +e100_alloc_rfd_pool(bdd_t *bddp) +{ + sk_buff_t *nskb; + + bddp->rfd_tail = NULL; + bddp->rfd_head = NULL; + bddp->skb_req = RxDescriptors[bddp->bd_number]; + + ALLOC_SKBS(bddp, nskb); + return bddp->rfd_head; +} + + +/*****************************************************************************/ +/*****************************************************************************/ +/* Run Time Functions */ +/*****************************************************************************/ + +/***************************************************************************** + * Name: e100_watchdog + * + * Description: This routine updates our statitics and refreshs the txthld + * value. + * + * Born on Date: 1/5/00 + * + * Arguments: dev - device structure + * + * Returns: (none) + * + * Modification log: + * Date Who Description + * -------- --- -------------------------------------------------------- + * + *****************************************************************************/ +void +e100_watchdog(device_t *dev) +{ + bd_config_t *bdp = dev->priv; + bdd_t *bddp = bdp->bddp; + + /* Update the statistics needed by the upper interface */ + e100_dump_stats_cntrs(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 ((bddp->rev_id < D101A4_REV_ID) && (!(bddp->flags & IS_ICH))) { + /* if we haven't received any frames then issue the multicast + * command */ + if (bddp->pstats_counters->rcv_gd_frames == 0) { + e100_set_multi(dev); + } + } + + e100_phy_check(bdp); + e100_handle_zero_lock_state(bdp); + + /* relaunch watchdog timer in 2 sec */ + init_timer(&bdp->timer_id); + bdp->timer_id.expires = bdp->timer_val = jiffies + (2 * HZ); + bdp->timer_id.data = (ulong_t) dev; + bdp->timer_id.function = (void *) &e100_watchdog; + add_timer(&bdp->timer_id); + + if (bddp->rfd_head == NULL) + e100_trigger_SWI(bdp); + + return; + +} + + +/* + * Procedure: e100intr + * + * Description: 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. + * + * Returns: + * NONE + */ +void +e100intr(int irq, void *dev_inst, struct pt_regs *regs) +{ + + device_t *dev; + bd_config_t *bdp; + bdd_t *bddp; + uint16_t intr_status; + + dev = (device_t *) dev_inst; + bdp = dev->priv; + bddp = bdp->bddp; + + intr_status = bddp->scbp->scb_status & SCB_STATUS_ACK_MASK; + if (!intr_status) return; /* not our intr - return */ + bddp->scbp->scb_status = intr_status; /* ack intrs */ + e100_dis_intr(bdp); /* prevent intr from happen on another CPU */ + + /* increment intr counter for CNA delay adjustment (82558/9 only) */ + if ((bddp->flags & IS_BACHELOR) && (intr_status & SCB_STATUS_ACK_CNA)) + bddp->num_cna_interrupts++; + + /* SWI intr (triggered by watchdog) is signal to allocate new skb buffers */ + if (intr_status & SCB_STATUS_ACK_SWI) { + sk_buff_t *nskb; + ALLOC_SKBS(bddp, nskb); + } + /* do recv work if any */ + if (intr_status & (SCB_STATUS_ACK_FR | SCB_STATUS_ACK_RNR | SCB_STATUS_ACK_SWI)) { + e100_rx_srv(bdp); + /* restart the RU if it has stopped */ + if ((bddp->scbp->scb_status & SCB_RUS_MASK) != SCB_RUS_READY) + e100_start_ru(bdp); + } + + /* 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); + } + + e100_enbl_intr(bdp); + + return; +} + +/* + * Procedure: e100_tx_skb_free + * + * Description: routine to free resources of TX skbs. + * + * Arguments: + * bdp - Ptr to this card's e100_bdconfig structure. + * tcbp- Ptr to the associated tcb of the freed skb. + * + * Returns: + * NONE + */ +static void inline e100_tx_skb_free(bd_config_t *bdp,tcb_t *tcbp) +{ + if (tcbp->tcb_skb) { + pci_unmap_single(bdp->ppci_dev,tcbp->dma_data_addr,tcbp->tcb_skb->len,PCI_DMA_TODEVICE); + dev_kfree_skb_irq(tcbp->tcb_skb); + tcbp->tcb_skb = NULL; + } +} + + +/* + * Procedure: e100_tx_srv + * + * Description: 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. + * + * Arguments: + * bdp - Ptr to this card's e100_bdconfig structure + * + * Returns: + * NONE + */ +void +e100_tx_srv(bd_config_t *bdp) +{ + bdd_t *bddp = bdp->bddp; + device_t *dev = bdp->device; + buf_pool_t *tcb_poolp; + uint_t tcb_head = 0; + tcb_t *tcbp; + int loop_cnt = 0; + + boolean_t last_tcb_served = 0; + + /* designed to run from isr !! */ + spin_lock(&bddp->bd_tx_lock); + tcb_poolp = &bddp->tcb_pool; + tcb_head = tcb_poolp->head; + tcbp = tcb_poolp->data; + tcbp += tcb_head; + + while ((tcbp->tcb_hdr.cb_status & CB_STATUS_COMPLETE) && + (loop_cnt < TxDescriptors[bdp->bd_number])) { + + if (IS_IT_GAP(tcb_poolp)) { + e100_tx_skb_free(bdp,tcbp); + /* move head to next buffer & service it */ + if ((tcb_head + 1) >= TxDescriptors[bdp->bd_number]) + tcbp = tcb_poolp->data; + else + tcbp++; + + if (tcbp->tcb_hdr.cb_status & CB_STATUS_COMPLETE) { + last_tcb_served = 1; + e100_tx_skb_free(bdp,tcbp); + } + /* Make sure to clear the out of resource condition */ + if (netif_queue_stopped(dev)) { + netif_wake_queue(dev); + } + + break; + } + + /* update statistics & free this msg */ + /* xmits is a counter for update CID. */ + bddp->xmits++; + e100_tx_skb_free(bdp,tcbp); + tcbp->tcb_hdr.cb_status = 0; + + if (bddp->flags & USE_IPCB) { + /* clean out the ipcb fields */ + (tcbp->tcbu).ipcb.scheduling = 0; + (tcbp->tcbu).ipcb.ip_activation = IPCB_IP_ACTIVATION_DEFAULT; + (tcbp->tcbu).ipcb.vlan = 0; + (tcbp->tcbu).ipcb.ip_header_offset = 0; + (tcbp->tcbu).ipcb.tcp_header_offset = 0; + (tcbp->tcbu).ipcb.tbd_sec_addr.tbd_zero_address = 0; + (tcbp->tcbu).ipcb.tbd_sec_size.tbd_zero_size = 0; + (tcbp->tcbu).ipcb.total_tcp_payload = 0; + } + + /* + * If 82558/9 and if enhanced_tx_enabled, clean up the extended + * TCB fields + */ + else if ((bddp->flags & IS_BACHELOR) && (e100_enhanced_tx_enable)) { + /* Note: the tbd0 and tbd1 buf_addrs are physical addresses + * stored * in an unsigned long. */ + (tcbp->tcbu).tcb_ext.tbd0_buf_addr = 0; + (tcbp->tcbu).tcb_ext.tbd0_buf_cnt = 0; + (tcbp->tcbu).tcb_ext.tbd1_buf_addr = 0; + (tcbp->tcbu).tcb_ext.tbd1_buf_cnt = 0; + } + + /* clear the out of resource condition */ + if (netif_queue_stopped(dev)) { + netif_wake_queue(dev); + } + + /* move head to next buffer & service it */ + tcb_head++; + /* check for wrap condition */ + if (tcb_head >= TxDescriptors[bdp->bd_number]) { + tcb_head = 0; + tcbp = tcb_poolp->data; + } else + tcbp++; + tcb_poolp->head = tcb_head; + tcb_poolp->count++; + + loop_cnt++; + + + tcb_poolp->head = tcb_head; + + } /* end of while */ + + + tcb_poolp->head = tcb_head; + if ((tcb_head != tcb_poolp->tail) && !last_tcb_served ) { + if ((bddp->scbp->scb_status & SCB_CUS_MASK) == SCB_CUS_IDLE) { + printk(KERN_WARNING "CU idle while %d tcbs to tx\n", + tcb_poolp->head-tcb_poolp->tail); + } + } + + spin_unlock(&bddp->bd_tx_lock); + +#if (DEBUG_TX) + printk(KERN_DEBUG "e100_tx_srv: exiting\n"); +#endif + return; +} + + +/* + * Procedure: e100_rx_srv + * + * Description: 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, & sends the old msg upstream. + * The new RFD is then put at the end of the free list of RFD's. + * + * Arguments: + * bdp - Ptr to this card's e100_bdconfig structure + * + * Returns: + * NONE + */ +void +e100_rx_srv(bd_config_t *bdp) +{ + bdd_t *bddp = bdp->bddp; + rfd_t *rfdp; /* new rfd, received rfd */ + int i; + uint16_t rfd_status; + sk_buff_t *skb, *nskb; + device_t *dev; + net_device_stats_t *stats; + ip_v4_header *IPPacket; + int HeaderOffset = 0; + unsigned int data_sz; + + dev = bdp->device; + stats = &(bddp->net_stats); + +#if (DEBUG) + printk(KERN_DEBUG "e100_rx_srv - B. b %d scb_status=0x%x\n", + bdp->bd_number, bddp->scbp->scb_status); + printk(KERN_DEBUG " rfd_head = 0x%p\n", bddp->rfd_head); +#endif + + /* 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 < RxDescriptors[bdp->bd_number] ; i++ ) + { + skb = bddp->rfd_head; + if (skb == NULL) /* no buffers left - exit and watchdog take care later */ + return; + + rfdp = RFD_POINTER(skb, bddp); /* locate RFD within skb */ + pci_dma_sync_single(bdp->ppci_dev,rfdp->dma_addr,bddp->rfd_size,PCI_DMA_FROMDEVICE); + rfd_status = rfdp->rfd_header.cb_status; /* get RFD's status */ + if (!(rfd_status & RFD_STATUS_COMPLETE)) /* does not contains data yet - exit */ + return; + + /* to allow manipulation with current skb we need to advance rfd head */ + bddp->rfd_head = rfdp->next; + + data_sz = le16_to_cpu(rfdp->rfd_act_cnt & 0x3fff); + pci_dma_sync_single(bdp->ppci_dev,rfdp->dma_addr, + E100_MIN(data_sz+bddp->rfd_size,sizeof(rfd_t)), + PCI_DMA_FROMDEVICE); + pci_unmap_single(bdp->ppci_dev,rfdp->dma_addr,sizeof(rfd_t),PCI_DMA_TODEVICE); + /* do not free badly recieved packet - move it to the end of skb list for reuse */ + if (!(rfd_status & RFD_STATUS_OK)) { + e100_add_skb_to_end(bddp, skb); + continue; + } + /* end of dma access to rfd */ + + bddp->skb_req++; /* incr number of requested skbs */ + ALLOC_SKBS(bddp, nskb); /* and get them */ + + /* set packet size, excluding checksum (2 last bytes) if it is present */ + if (bddp->checksum_offload_enabled && (bddp->rev_id < D102_REV_ID)) + skb_put(skb, data_sz - 2); + else + skb_put(skb, data_sz); + + /* set the checksum info */ + skb->ip_summed = CHECKSUM_NONE; + if(bddp->checksum_offload_enabled) { + if(bddp->rev_id >= D102_REV_ID) { + e100_D102_check_checksum(bdp, skb); + } +#ifndef CSUM_IA64 + else if ((IPPacket = e100_check_for_ip(&HeaderOffset, skb))) { + e100_calculate_checksum(IPPacket, HeaderOffset, skb, + rfdp->rfd_act_cnt & 0x3FFF); + } +#endif /* CSUM_IA64 */ + } + + /* set the protocol */ + skb->protocol = eth_type_trans(skb, dev); + + stats->rx_bytes += skb->len; + netif_rx(skb); + + } /* end of rfd loop */ + + return; +} + + +/* + * Procedure: e100_refresh_txthld + * + * Arguments: + * bdp - Ptr to this card's e100_bdconfig structure + * + * Returns: + * NONE + */ +void +e100_refresh_txthld(bd_config_t *bdp) +{ + bdd_t *bddp = bdp->bddp; + + /* 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 (bddp->tx_per_underrun) { + /* We are going to last values dumped from the dump statistics + * command */ + if (bddp->pstats_counters->xmt_gd_frames) { + if (bddp->pstats_counters->xmt_uruns) { + /* + * if we have had more than one underrun per "DEFAULT # + * OF XMITS ALLOWED PER UNDERRUN" good xmits, raise the + * THRESHOLD. + */ + if ((bddp->pstats_counters->xmt_gd_frames / + bddp->pstats_counters->xmt_uruns) < + bddp->tx_per_underrun) { + bddp->tx_thld += 3; + if (DEBUG_TX) + printk(KERN_DEBUG "e100_refresh_txthld: B %d THOLD + %d\n", + bdp->bd_number, bddp->tx_thld); + } + } + + /* + * 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 (bddp->pstats_counters->xmt_gd_frames > + bddp->tx_per_underrun) { + bddp->tx_thld--; + + if (bddp->tx_thld < 6) + bddp->tx_thld = 6; + + if (DEBUG_TX) + printk(KERN_DEBUG "e100_refresh_txthld: b %d THOLD -- %d\n", + bdp->bd_number, bddp->tx_thld); + + } + } + + /* 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 (bddp->tx_thld >= 190) { + bddp->tx_per_underrun = 0; + bddp->tx_thld = 189; + if (DEBUG_TX) + printk(KERN_DEBUG "e100_refresh_txthld: b %d stop at 189\n", + bdp->bd_number); + } + } /* end underrun check */ + return; +} + + +/* + * Procedure: e100_prepare_xmit_buff + * + * Description: 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 & sets up the corresponding + * TBD's. If number of fragments are more the the # of TBD/TCB + * it copies all the fragments in a coalesce buffer. + * + * Arguments: + * bdp - Ptr to this card's e100_bdconfig structure + * ksb - Ptr to the skb to send + * + * Returns: + * ptcb - Ptr to the prepared TCB + */ +static ptcb_t +e100_prepare_xmit_buff(bd_config_t *bdp, sk_buff_t *skb) +{ + bdd_t *bddp = bdp->bddp; + buf_pool_t *tcb_poolp; + buf_pool_t *tbd_poolp; + tcb_t *tcbp, *prev_tcbp; + tbd_t *tbdp; + uint16_t txcommand; + + tcb_poolp = &(bddp->tcb_pool); + tbd_poolp = &(bddp->tbd_pool); + tcbp = tcb_poolp->data; + tbdp = tbd_poolp->data; + + /* get the TCB & the TBD we may be using for this MSG */ + tcbp += TCB_TO_USE(tcb_poolp); + tbdp += (TCB_TO_USE(tcb_poolp)); + + if (bddp->flags & USE_IPCB) { + (tcbp->tcbu).ipcb.ip_activation = IPCB_IP_ACTIVATION_DEFAULT; + txcommand = CB_IPCB_TRANSMIT | CB_S_BIT | CB_TX_SF_BIT; + } + else + txcommand = CB_TRANSMIT | CB_S_BIT | CB_TX_SF_BIT; + + tcbp->tcb_cnt = 0; + tcbp->tcb_tbd_num = 1; + tcbp->tcb_thrshld = bddp->tx_thld; + tcbp->tcb_tbd_ptr = bddp->tbd_paddr + + (TCB_TO_USE(tcb_poolp) * sizeof(tbd_t)); + tcbp->tcb_hdr.cb_cmd = txcommand; + + /* set the I bit on the modulo tcbs, so we will get an interrupt * to + * clean things up */ + if (!(++bdp->tx_count % e100_batch_tx_frames)) { + tcbp->tcb_hdr.cb_cmd |= CB_I_BIT; + } + + /* save a pointer to the skb to free it later */ + tcbp->tcb_skb = skb; + + /* set the data size of the SKB */ + tcbp->tcb_msgsz = skb->len; + tcbp->dma_data_addr = cpu_to_le32(pci_map_single(bdp->ppci_dev,skb->data,skb->len,PCI_DMA_TODEVICE)); + if (bddp->flags & USE_IPCB) { + /* setup the ipcb fields */ + (tcbp->tcbu).ipcb.tbd_sec_addr.tbd_zero_address = tcbp->dma_data_addr; + + (tcbp->tcbu).ipcb.tbd_sec_size.tbd_zero_size = skb->len; + } else { + /* copy the phys addrs and len to the tbds */ + tbdp->tbd_buf_addr = tcbp->dma_data_addr; + + tbdp->tbd_buf_cnt = skb->len; + } + + /* Clear the S-Bit of the Previous Command */ + prev_tcbp = tcb_poolp->data; + prev_tcbp += PREV_TCB_USED(tcb_poolp); + prev_tcbp->tcb_hdr.cb_cmd &= ~CB_S_BIT; + + /* update the tail */ + tcb_poolp->tail = NEXT_TCB_TOUSE(tcb_poolp->tail); + +#if (DEBUG_TX) + { + int i; + printk(KERN_DEBUG "prepare_xmit_buff: Frame Data:\n"); + for (i = 0; i < skb->len; i++) + printk(KERN_DEBUG " 0x%x", skb->data[i]); + printk(KERN_DEBUG "\n"); + } +#endif + + /* start the CU if needed */ + e100_cu_start(bdp, tcbp); + + if (tcb_poolp->count) + tcb_poolp->count--; + + return (tcbp); +} + + +/* + * Procedure: e100_prepare_ext_xmit_buff + * + * Description: This is a 82558/9 specific routine. + * This sets up the extended TCBs and dynamically chains TBDs. + * 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 & sets up the corresponding + * TBD's. If number of fragments are more the the # of TBD/TCB + * it copies all the fragments in a coalesce buffer. + * + * Arguments: + * bdp - Ptr to this card's e100_bdconfig structure + * skb - skb to send. + * + * Returns: + * ptcb - Ptr to the prepared TCB + */ +static ptcb_t +e100_prepare_ext_xmit_buff(bd_config_t *bdp, sk_buff_t *skb) +{ + bdd_t *bddp; + buf_pool_t *tcb_poolp; + tcb_t *tcbp; + tcb_t *prev_tcbp; + + bddp = (bdd_t *) bdp->bddp; + tcb_poolp = &bddp->tcb_pool; + tcbp = tcb_poolp->data; + + /* get the TCB & the TBD we may be using for this MSG */ + /* since Linux only use 1 physical address the number of tdbs use is 1 * + * which will fit into the extended tcb */ + tcbp += TCB_TO_USE(tcb_poolp); + +#if (DEBUG_TX) + printk(KERN_DEBUG "e100_prepare_ext_xmit_buff: num tcbs avail = 0x%x\n", + tcb_poolp->count); + printk(KERN_DEBUG " - B. b %d tcb[h=0x%x t=0x%x c=0x%x ] scb_status 0x%x\n", + bdp->bd_number, + tcb_poolp->head, tcb_poolp->tail, tcb_poolp->count, + bddp->scbp->scb_status); + printk(KERN_DEBUG " - TCB_TO_USE = 0x%x\n", TCB_TO_USE(tcb_poolp)); +#endif + + tcbp->tcb_hdr.cb_status = 0; + tcbp->tcb_cnt = 0; + tcbp->tcb_tbd_num = 0xff; + tcbp->tcb_thrshld = bddp->tx_thld; + tcbp->tcb_tbd_ptr = bddp->tbd_paddr + + (TCB_TO_USE(tcb_poolp) * sizeof(tbd_t)); + tcbp->tcb_hdr.cb_cmd = CB_S_BIT | CB_TRANSMIT | CB_TX_SF_BIT; + +#if (DEBUG_TX) + printk(KERN_DEBUG " tcbp = 0x%x, skb = 0x%x\n", tcbp, skb); + printk(KERN_DEBUG " skb_data = 0x%x, skb_len = 0x%x\n", skb->data, skb->len); +#endif + + /* set the I bit on the modulo tcbs, so we will get an interrupt * to + * clean things up */ + if (!(++bdp->tx_count % e100_batch_tx_frames)) { + tcbp->tcb_hdr.cb_cmd |= CB_I_BIT; +#if (DEBUG_TX) + printk(KERN_DEBUG " setting the I_bit\n"); +#endif + } + + /* set the CNA backoff */ + tcbp->tcb_hdr.cb_cmd |= bddp->current_cna_backoff << 8; + + (tcbp->tcbu).tcb_ext.tbd0_buf_cnt = 0 | CB_EL_BIT; + (tcbp->tcbu).tcb_ext.tbd1_buf_cnt = 0 | CB_EL_BIT; + (tcbp->tcbu).tcb_ext.tbd0_buf_addr = 0; + (tcbp->tcbu).tcb_ext.tbd1_buf_addr = 0; + + /* save a pointer to the skb to free it later */ + tcbp->tcb_skb = skb; + + /* set the data size of the SKB */ + tcbp->tcb_msgsz = skb->len; + + tcbp->dma_data_addr = cpu_to_le32(pci_map_single(bdp->ppci_dev,skb->data,skb->len,PCI_DMA_TODEVICE)); + /* set the ext tbd to the skb */ + (tcbp->tcbu).tcb_ext.tbd0_buf_addr = tcbp->dma_data_addr; + + (tcbp->tcbu).tcb_ext.tbd0_buf_cnt = skb->len; + +#if (DEBUG_TX) + { + int i; + printk(KERN_DEBUG "Data: cmd = 0x%x\n", tcbp->tcb_hdr.cb_cmd); + for (i = 0; i < skb->len; i++) + printk(KERN_DEBUG " 0x%x", skb->data[i]); + printk(KERN_DEBUG "\n"); + } +#endif + + /* set the 2nd tbd to end the chain */ + (tcbp->tcbu).tcb_ext.tbd1_buf_addr = 0xFFFFFFFF; + (tcbp->tcbu).tcb_ext.tbd1_buf_cnt = 0 | CB_EL_BIT; + +#if (DEBUG_TX) + { + int i, *temp_val; + printk(KERN_DEBUG " status = 0x%x, tcb_cnt = 0x%x, tcb_tbd_num = 0x%x\n", + tcbp->tcb_hdr.cb_status, tcbp->tcb_cnt, tcbp->tcb_tbd_num); + printk(KERN_DEBUG " tcb_thrshld = 0x%x, tcb_tbd_ptr = 0x%x, cb_cmd= 0x%x\n", + tcbp->tcb_thrshld, tcbp->tcb_tbd_ptr, tcbp->tcb_hdr.cb_cmd); + printk(KERN_DEBUG " tbd0_buf_addr = 0x%x, tbd0_buf_cnt = 0x%x\n", + (tcbp->tcbu).tcb_ext.tbd0_buf_addr, + (tcbp->tcbu).tcb_ext.tbd0_buf_cnt); + printk(KERN_DEBUG " tbd1_buf_addr = 0x%x, tbd1_buf_cnt = 0x%x\n", + (tcbp->tcbu).tcb_ext.tbd1_buf_addr, + (tcbp->tcbu).tcb_ext.tbd1_buf_cnt); + printk(KERN_DEBUG " - PREV_TCB_USED = 0x%x\n", PREV_TCB_USED(tcb_poolp)); + printk(KERN_DEBUG " - tcb_paddr = 0x%x\n", tcbp->tcb_paddr); + + printk(KERN_DEBUG "TCB:\n"); + for ( i = 0, temp_val = (unsigned int *) tcbp; + i < (sizeof(tcb_t) / 4); i++) + printk(KERN_DEBUG " 0x%x", temp_val[i]); + printk(KERN_DEBUG "\n"); + } +#endif + + /* clear the S-BIT on the previous tcb */ + prev_tcbp = tcb_poolp->data; + prev_tcbp += PREV_TCB_USED(tcb_poolp); + prev_tcbp->tcb_hdr.cb_cmd &= ~CB_S_BIT; + + /* start the CU if needed */ + e100_cu_start(bdp, tcbp); + + /* update the tail */ + tcb_poolp->tail = NEXT_TCB_TOUSE(tcb_poolp->tail); + + if (tcb_poolp->count) + tcb_poolp->count--; + +#if (DEBUG_TX) + printk(KERN_DEBUG " tail = 0x%x\n", tcb_poolp->tail); +#endif + return (tcbp); +} + + +/* Changed for 82558 enhancement */ +/* + * Procedure: e100_cu_start + * + * Description: 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. + * + * Arguments: + * bdp - Ptr to this card's e100_bdconfig structure + * tcbp - Ptr to the TCB to be transmitted + * + */ +void +e100_cu_start(bd_config_t *bdp, tcb_t *tcbp) +{ + bdd_t *bddp = (bdd_t *) bdp->bddp; + int loop_cnt, lock_flag; + + spin_lock_irqsave(&bddp->bd_lock, lock_flag); + + /* If CU is suspended, do a resume */ + if ((bddp->prev_cu_cmd == CB_TRANSMIT) || + (bddp->prev_cu_cmd == CB_TRANSMIT_FIRST) || + (bddp->prev_cu_cmd == CB_DUMP_RST_STAT)) { + + + if (DEBUG_TX) /* E100_DEBUG */ + printk(KERN_DEBUG "cu_start: doing RESUME\n"); + + + /* On ICH2 at 10/H we must issue a NOOP before each CU_RESUME */ + if ((bddp->flags & IS_ICH) && + (bddp->cur_line_speed == 10) && + (bddp->cur_dplx_mode == HALF_DUPLEX)) { + e100_wait_exec_cmd(bdp, SCB_CUC_NOOP); + drv_usecwait(1); + } + e100_wait_exec_cmd(bdp, SCB_CUC_RESUME); + + bddp->prev_cu_cmd = CB_TRANSMIT; + spin_unlock_irqrestore(&bddp->bd_lock, lock_flag); + return; + } + + /* If it is idle, do a start */ + if ((bddp->scbp->scb_status & SCB_CUS_MASK) == SCB_CUS_IDLE) { + bddp->scbp->scb_gen_ptr = tcbp->tcb_paddr; + e100_exec_cmd(bdp, SCB_CUC_START); + bddp->prev_cu_cmd = CB_TRANSMIT_FIRST; +#if (DEBUG_TX) + /* E100_DEBUG */ + printk(KERN_DEBUG "cu_start: did START, cmd = 0x%x\n", SCB_CUC_START); + printk(KERN_DEBUG " tcb_paddr = 0x%x\n", tcbp->tcb_paddr); + printk(KERN_DEBUG " bddp = 0x%x\n", bddp); + printk(KERN_DEBUG " scbp = 0x%x\n", bddp->scbp); + printk(KERN_DEBUG " scb_gen_ptr = 0x%x\n", bddp->scbp->scb_gen_ptr); +#endif + spin_unlock_irqrestore(&bddp->bd_lock, lock_flag); + return; + } + + /* If it is active, but if the previous command was not a transmit * then + * wait for the command to finish, and then do a start */ + loop_cnt = 0; + while (((bddp->scbp->scb_status & SCB_CUS_MASK) != SCB_CUS_IDLE) && + (loop_cnt < 5)) { + loop_cnt++; + drv_usecwait(5); + } + + bddp->scbp->scb_gen_ptr = tcbp->tcb_paddr; + e100_exec_cmd(bdp, SCB_CUC_START); + bddp->prev_cu_cmd = CB_TRANSMIT_FIRST; +#if (DEBUG_TX) + /* E100_DEBUG */ + printk(KERN_DEBUG "cu_start: did START 2, cmd = 0x%x\n", SCB_CUC_START); + printk(KERN_DEBUG " tcb_paddr = 0x%x\n", tcbp->tcb_paddr); + printk(KERN_DEBUG " scb_gen_ptr = 0x%x\n", bddp->scbp->scb_gen_ptr); +#endif + spin_unlock_irqrestore(&bddp->bd_lock, lock_flag); + return; +} + + +/* Change for 82558 enhancement */ +/* + * Procedure: e100_adjust_cid + * + * Description: This routine adjusts the CNA Interrupt Delay for 82558/9. + * The routine adjusts the value of bddp->current_cna_backoff based + * on the number of good transmits per interrupt. This adjusted value + * of current_cna_backoff will be used while setting up TCBs in the + * e100_prepare_ext_xmit_buff routine. + * + * + * Arguments: + * bdp - Ptr to this card's e100_bdconfig structure + * + * Returns: + * NONE + */ +void +e100_adjust_cid(bd_config_t *bdp) +{ + bdd_t *bddp = (bdd_t *) bdp->bddp; + uint32_t good_xmits; + + /* How many good xmits happened since the last time we got here? */ + good_xmits = bddp->xmits - bddp->old_xmits; + + /* Increase CID if the number of good xmits is less than or equal to * + * the num of xmit interrupts. This will reduce the num of xmit intrs. */ + if ((bddp->num_cna_interrupts) && (good_xmits >= 10)) { + if ((good_xmits * XMITS_PER_INTR / bddp->num_cna_interrupts) <= + XMITS_PER_INTR) { + if ((bddp->current_cna_backoff + 4) <= 0x1f) + bddp->current_cna_backoff += 4; + } + } else { + if ((e100_current_cna_backoff >= 0) + && (e100_current_cna_backoff <= 0x1f)) + bddp->current_cna_backoff = e100_current_cna_backoff; + else + bddp->current_cna_backoff = 0; + } + + bddp->old_xmits = bddp->xmits; + bddp->num_cna_interrupts = 0; + + return; + +} + + +/* ====================================================================== */ +/* hw */ +/* ====================================================================== */ + +/* + * Procedure: SelfTestHardware + * + * Description: 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. + * + * Arguments: + * bdp - Ptr to this card's e100_bdconfig structure + * + * Returns: + * B_TRUE if adapter passes self_test + * B_FALSE if adapter fails self_test + */ +boolean_t +e100_selftest(bd_config_t *bdp) +{ + + bdd_t *bddp = bdp->bddp; /* stores all adapter specific info */ + uint32_t SelfTestCommandCode; + +#if (DEBUG) + printk(KERN_DEBUG "e100_selftest: begin, selftest_paddr = 0x%x\n", + bddp->selftest_paddr); +#endif + /* Setup the address of the self_test area */ + SelfTestCommandCode = cpu_to_le32( bddp->selftest_paddr); + + /* Setup SELF TEST Command Code in D3 - D0 */ + SelfTestCommandCode |= PORT_SELFTEST; + + /* Initialize the self-test signature and results DWORDS */ + bddp->pselftest->st_sign = 0; + bddp->pselftest->st_result = 0xffffffff; + +#if (DEBUG) + printk(KERN_DEBUG "Port Cmd 0x%x ST_Sign 0x%x ST_Result 0x%x\n", + SelfTestCommandCode, bddp->pselftest->st_sign, + bddp->pselftest->st_result); +#endif + /* Do the port command */ + bddp->scbp->scb_port = SelfTestCommandCode; + + /* Wait 5 milliseconds for the self-test to complete */ + mdelay(50); + + /* 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 ((bddp->pselftest->st_sign == 0) + || (bddp->pselftest->st_result != 0)) { +#if (DEBUG) + printk (KERN_DEBUG "e100: Selftest failed Sig = 0x%x Result = 0x%x brd_number=%d\n", + bddp->pselftest->st_sign, bddp->pselftest->st_result, + bdp->bd_number); +#endif + return B_TRUE; + } + + +#if (DEBUG) + printk(KERN_DEBUG "e100self_test: end. ST_Sign 0x%x ST_Result 0x%x\n", + bddp->pselftest->st_sign, bddp->pselftest->st_result); +#endif + return B_TRUE; +} + +/* + * Procedure: e100_configure + * + * Description: 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. The configuration parameters + * that are user configurable will have been set in "e100.c". + * + * Arguments: + * bdp - Ptr to this card's e100_bdconfig structure + * + * Returns: + * B_TRUE - If the configure command was successfully issued and completed + * B_FALSE - If the configure command failed to complete properly + */ +boolean_t +e100_configure(bd_config_t *bdp) +{ + bdd_t *bddp = bdp->bddp; /* stores all adapter specific info */ + pcb_header_t pntcb_hdr; + int e100_retry; + + pntcb_hdr = (pcb_header_t) bddp->pntcb; /* get hdr of non tcb cmd */ + + /* Setup the non-transmit command block header for the configure command. */ + pntcb_hdr->cb_status = 0; + pntcb_hdr->cb_cmd = CB_CONFIGURE; + /* Note: cb_lnk_ptr is a physical address stored in an unsigned long */ + pntcb_hdr->cb_lnk_ptr = 0; + + /* Fill in the configure command data. */ + + /* First fill in the static (end user can't change) config bytes */ + bddp->pntcb->ntcb.config.cfg_byte[0] = CB_557_CFIG_DEFAULT_PARM0; + bddp->pntcb->ntcb.config.cfg_byte[2] = CB_557_CFIG_DEFAULT_PARM2; + bddp->pntcb->ntcb.config.cfg_byte[3] = CB_557_CFIG_DEFAULT_PARM3; + /* Commented out byte 6 for CNA intr fix. */ + /* bddp->pntcb->ntcb.config.cfg_byte[6] = CB_557_CFIG_DEFAULT_PARM6; */ + bddp->pntcb->ntcb.config.cfg_byte[9] = CB_557_CFIG_DEFAULT_PARM9; + bddp->pntcb->ntcb.config.cfg_byte[10] = CB_557_CFIG_DEFAULT_PARM10; + bddp->pntcb->ntcb.config.cfg_byte[11] = CB_557_CFIG_DEFAULT_PARM11; + bddp->pntcb->ntcb.config.cfg_byte[12] = CB_557_CFIG_DEFAULT_PARM12; + bddp->pntcb->ntcb.config.cfg_byte[13] = CB_557_CFIG_DEFAULT_PARM13; + bddp->pntcb->ntcb.config.cfg_byte[14] = CB_557_CFIG_DEFAULT_PARM14; + bddp->pntcb->ntcb.config.cfg_byte[18] = CB_557_CFIG_DEFAULT_PARM18; + bddp->pntcb->ntcb.config.cfg_byte[20] = CB_557_CFIG_DEFAULT_PARM20; + bddp->pntcb->ntcb.config.cfg_byte[21] = CB_557_CFIG_DEFAULT_PARM21; + + /* Now fill in the rest of the configuration bytes (the bytes that * + * contain user configurable parameters). */ + + /* Change for 82558 enhancement */ + /* Set the Tx and Rx Fifo limits */ + if ((bddp->flags & IS_BACHELOR) && (e100_tx_fifo_lmt < 8)) + e100_tx_fifo_lmt = 8; /* set 8 as the minimum */ + + bddp->pntcb->ntcb.config.cfg_byte[1] = (uint8_t) + (BIT_7 | (e100_tx_fifo_lmt << 4) | e100_rx_fifo_lmt); + + /* added for min. support of IFS */ + if (bddp->cur_line_speed == 100) /* if running at 100Mbps use this */ + bddp->pntcb->ntcb.config.cfg_byte[2] = (uint8_t) e100_adaptive_ifs; + else /* we are at 10Mbps so use a greater value */ + bddp->pntcb->ntcb.config.cfg_byte[2] = (uint8_t) (5 * e100_adaptive_ifs); + + /* Change for 82558 enhancement */ + /* MWI enable. This should be turned on only if enabled in * e100.c and + * if the adapter is a 82558/9 and if the PCI command reg. * has enabled + * the MWI bit. */ + if ((bddp->flags & IS_BACHELOR) && (e100_MWI_enable)) + bddp->pntcb->ntcb.config.cfg_byte[3] |= CB_CFIG_MWI_EN; + + /* Read Align/Write Terminate on cache line. This should be * turned on + * only if enabled in e100.c and if the adapter is a 82558/9 * and if the + * system is cache line oriented. */ + if ((bddp->flags & IS_BACHELOR) && (e100_read_align_enable)) + bddp->pntcb->ntcb.config.cfg_byte[3] |= CB_CFIG_READAL_EN | + CB_CFIG_TERMCL_EN; + + /* Set the Tx and Rx DMA maximum byte count fields. */ + bddp->pntcb->ntcb.config.cfg_byte[4] = e100_rx_dma_cnt; + bddp->pntcb->ntcb.config.cfg_byte[5] = e100_tx_dma_cnt; + if ((e100_rx_dma_cnt) || (e100_tx_dma_cnt)) { + bddp->pntcb->ntcb.config.cfg_byte[5] |= CB_CFIG_DMBC_EN; + } + + /* Change for 82558 enhancement */ + /* Extended TCB. Should be turned on only if enabled * in e100.c and if + * the adapter is a 82558/9. */ + if ((e100_cfg_parm6 == 0x32) || (e100_cfg_parm6 == 0x3a)) + bddp->pntcb->ntcb.config.cfg_byte[6] = e100_cfg_parm6; + else + bddp->pntcb->ntcb.config.cfg_byte[6] = CB_557_CFIG_DEFAULT_PARM6; + + if ((bddp->flags & IS_BACHELOR) && (e100_enhanced_tx_enable)) + bddp->pntcb->ntcb.config.cfg_byte[6] &= ~CB_CFIG_EXT_TCB_DIS; + + /* Set up number of retries after under run */ + bddp->pntcb->ntcb.config.cfg_byte[7] = + ((CB_557_CFIG_DEFAULT_PARM7 & (~CB_CFIG_URUN_RETRY)) | + (e100_urun_retry << 1)); + + /* Change for 82558 enhancement */ + /* Dynamic TBD. Should be turned on only if enabled in e100.c and if + * the adapter is a 82558/9. */ + if ((bddp->flags & IS_BACHELOR) && (e100_enhanced_tx_enable)) + bddp->pntcb->ntcb.config.cfg_byte[7] |= CB_CFIG_DYNTBD_EN; + + /* Setup for MII or 503 operation. The CRS+CDT bit should only be set */ + /* when operating in 503 mode. */ + if (bddp->phy_addr == 32) { + bddp->pntcb->ntcb.config.cfg_byte[8] = (CB_557_CFIG_DEFAULT_PARM8 & + (~CB_CFIG_503_MII)); + bddp->pntcb->ntcb.config.cfg_byte[15] = + (CB_557_CFIG_DEFAULT_PARM15 | CB_CFIG_CRS_OR_CDT); + } else { + bddp->pntcb->ntcb.config.cfg_byte[8] = (CB_557_CFIG_DEFAULT_PARM8 | + CB_CFIG_503_MII); + bddp->pntcb->ntcb.config.cfg_byte[15] = + (CB_557_CFIG_DEFAULT_PARM15 & (~CB_CFIG_CRS_OR_CDT)); + } + + /* Change for 82558 enhancement */ + /* enable flowcontrol only if 82558/9 */ + if ((bddp->flags & IS_BACHELOR) && (e100_flow_control_enable)) { + bddp->pntcb->ntcb.config.cfg_byte[16] = DFLT_FC_DELAY_LSB; + bddp->pntcb->ntcb.config.cfg_byte[17] = DFLT_FC_DELAY_MSB; + /* Removed CB_CFIG_TX_FC_EN frm line below. This bit has to be * 0 to + * enable flow control. */ + bddp->pntcb->ntcb.config.cfg_byte[19] = + (CB_557_CFIG_DEFAULT_PARM19 | CB_CFIG_FC_RESTOP | + CB_CFIG_FC_RESTART | CB_CFIG_REJECT_FC); + } else { + bddp->pntcb->ntcb.config.cfg_byte[16] = CB_557_CFIG_DEFAULT_PARM16; + bddp->pntcb->ntcb.config.cfg_byte[17] = CB_557_CFIG_DEFAULT_PARM17; + /* Bit 2 has to be 'OR'd to disable flow control. */ + bddp->pntcb->ntcb.config.cfg_byte[19] = + CB_557_CFIG_DEFAULT_PARM19 | CB_CFIG_TX_FC_DIS; + } + + /* 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 (( bddp->phy_addr == 0 ) && ( + * bddp->cur_dplx_mode == 2 )) */ + if ((e100_speed_duplex[bdp->bd_number] == 2) || + (e100_speed_duplex[bdp->bd_number] == 4) + || (bddp->cur_dplx_mode == FULL_DUPLEX)) { + bddp->pntcb->ntcb.config.cfg_byte[19] |= CB_CFIG_FORCE_FDX; + } + + /* The rest of the fix is in the PhyDetect code. */ + if ((bddp->phy_addr == 32) && (bddp->cur_dplx_mode == FULL_DUPLEX)) { + bddp->pntcb->ntcb.config.cfg_byte[19] |= CB_CFIG_FORCE_FDX; + } + + /* if in promiscious mode, save bad frames */ + if (bddp->promisc) { + bddp->pntcb->ntcb.config.cfg_byte[6] |= CB_CFIG_SAVE_BAD_FRAMES; + bddp->pntcb->ntcb.config.cfg_byte[7] &= (uint8_t) (~BIT_0); + bddp->pntcb->ntcb.config.cfg_byte[15] |= CB_CFIG_PROMISCUOUS; + } + + /* disable broadcast if so desired */ + if (bddp->brdcst_dsbl) { + bddp->pntcb->ntcb.config.cfg_byte[15] |= CB_CFIG_BROADCAST_DIS; + } + + /* this flag is used to enable receiving all multicast packet */ + if (bddp->mulcst_enbl) { + bddp->pntcb->ntcb.config.cfg_byte[21] |= CB_CFIG_MULTICAST_ALL; + } + + /* Enable checksum offloading if we are on a supported adapter. */ + if ((bddp->rev_id >= D101MA_REV_ID) && (bddp->rev_id < D102_REV_ID) && + (XsumRX[bddp->bd_number] == TRUE) && (bddp->dev_id != 0x1209)) + { +#ifndef __ia64__ + bddp->checksum_offload_enabled = 1; + bddp->pntcb->ntcb.config.cfg_byte[9] |= 1; +#endif /* __ia64__ */ + } + else if(bddp->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. */ + bddp->pntcb->ntcb.config.cfg_byte[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. */ + bddp->pntcb->ntcb.config.cfg_byte[7] = CB_CFIG_EXTENDED_RFD; + + /* put the chip into D102 receive mode. This is neccessary + for any parsing and offloading features. */ + bddp->pntcb->ntcb.config.cfg_byte[22] = CB_CFIG_RECEIVE_GAMLA_MODE; + + /* set the flag if checksum offloading was enabled */ + if(XsumRX[bddp->bd_number] == TRUE) + { + bddp->checksum_offload_enabled = 1; + } + } + + /* Wait for the SCB command word to clear before we set the * general + * pointer */ + if (e100_wait_scb(bdp) != B_TRUE) + return (B_FALSE); + +#if (DEBUG) + { + int i; + + printk(KERN_DEBUG "Configure: paddr = 0x%x\n", bddp->nontx_paddr); + for (i = 0; i < 21; i++) { + printk(KERN_DEBUG " 0x%x", bddp->pntcb->ntcb.config.cfg_byte[i]); + } + printk(KERN_DEBUG "\n"); + } +#endif + + /* If we have issued any transmits, then the CU will either be active, * + * or in the suspended state. If the CU is active, then we wait for * + * it to be suspended. */ + if ((bddp->prev_cu_cmd == CB_TRANSMIT) || + (bddp->prev_cu_cmd == CB_TRANSMIT_FIRST)) { + /* Wait for suspended state */ + e100_retry = E100_CMD_WAIT; + while (((bddp->scbp->scb_status & SCB_CUS_MASK) == SCB_CUS_ACTIVE) + && (e100_retry)) { + mdelay(20); + e100_retry--; + } + } + + /* write the config buffer in the scb gen pointer */ + bddp->scbp->scb_gen_ptr = bddp->nontx_paddr; + + /* store the command */ + bddp->prev_cu_cmd = CB_CONFIGURE; + + /* Submit the configure command to the chip, and wait for it to complete. + */ + if (!e100_exec_poll_cmd(bdp)) + return (B_FALSE); + else + return (B_TRUE); + +} + + +/* + * Procedure: e100_setup_iaaddr + * + * Description: 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. + * + * Arguments: + * bdp - Ptr to this card's e100_bdconfig structure + * peaddr - Ptr to the new ethernet address + * + * Returns: + * B_TRUE - If the IA setup command was successfully issued and completed + * B_FALSE - If the IA setup command failed to complete properly + */ +boolean_t +e100_setup_iaaddr(bd_config_t *bdp, e100_eaddr_t *peaddr) +{ + uint_t i; + bdd_t *bddp = bdp->bddp; /* stores all adapter specific info */ + pcb_header_t pntcb_hdr; + int lock_flag; + + /* We lock before we start using the non tcb cmd */ + spin_lock_irqsave(&bddp->bd_lock, lock_flag); + + pntcb_hdr = (pcb_header_t) bddp->pntcb; /* get hdr of non tcb cmd */ + + /* Setup the non-transmit command block header for the configure command. + */ + pntcb_hdr->cb_status = 0; + pntcb_hdr->cb_cmd = CB_IA_ADDRESS; + /* Note: cb_lnk_ptr is a physical address stored in an unsigned long */ + pntcb_hdr->cb_lnk_ptr = 0; + + /* Copy in the station's individual address */ + for (i = 0; i < ETHERNET_ADDRESS_LENGTH; i++) { + bddp->pntcb->ntcb.setup.ia_addr[i] = peaddr->bytes[i]; + } + + /* Wait for the SCB command word to clear before we set the * general + * pointer */ + if (e100_wait_scb(bdp) != B_TRUE) { + spin_unlock_irqrestore(&bddp->bd_lock, lock_flag); + return (B_FALSE); + } + + /* If we have issued any transmits, then the CU will either be active, * + * or in the suspended state. If the CU is active, then we wait for * + * it to be suspended. */ + if ((bddp->prev_cu_cmd == CB_TRANSMIT) || + (bddp->prev_cu_cmd == CB_TRANSMIT_FIRST)) { + /* Wait for suspended state */ + /* Set timeout to 100 ms */ + i = 0; + while (((bddp->scbp->scb_status & SCB_CUS_MASK) == SCB_CUS_ACTIVE) + && (i < 5)) { + mdelay(20); + i++; + } + } + + /* Update the command list pointer. */ + bddp->scbp->scb_gen_ptr = bddp->nontx_paddr; + + /* store the command */ + bddp->prev_cu_cmd = CB_IA_ADDRESS; + + /* Submit the IA configure command to the chip, and wait for it * to + * complete. */ + + if (!e100_exec_poll_cmd(bdp)) { + printk(KERN_WARNING "IA setup failed\n"); + spin_unlock_irqrestore(&bddp->bd_lock, lock_flag); + return (B_FALSE); + } + spin_unlock_irqrestore(&bddp->bd_lock, lock_flag); + return (B_TRUE); +} + + +/* + * Procedure: e100_start_ru + * + * Description: 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. + * + * Arguments: + * bdp - Ptr to this card's e100_bdconfig structure + * + * Returns: + * NONE + */ +void +e100_start_ru(bd_config_t *bdp) +{ + bdd_t *bddp = bdp->bddp; /* get the bddp for this board */ + sk_buff_t *skb; + + /* If the receiver is ready, then don't try to restart. */ + if ((bddp->scbp->scb_status & SCB_RUS_MASK) == SCB_RUS_READY) { + return; + } + for(skb = bddp->rfd_head; skb != NULL; skb = NEXT_SKB(skb,bddp)){ + pci_dma_sync_single(bdp->ppci_dev,GET_SKB_DMA_ADDR(skb,bddp), + bddp->rfd_size,PCI_DMA_FROMDEVICE); + if (!((SKB_RFD_COMPLETE(skb,bddp) & RFD_STATUS_COMPLETE))){ + break; + } + } + + /* No available buffers */ + if(skb == NULL){ + return; + } + spin_lock(&bddp->bd_lock); + + e100_wait_scb(bdp); + bddp->scbp->scb_gen_ptr = cpu_to_le32(GET_SKB_DMA_ADDR(skb,bddp)); + e100_exec_cmd(bdp, SCB_RUC_START); + + spin_unlock(&bddp->bd_lock); +} + + +/* + * Procedure: e100_ru_abort + * + * Description: This routine issues a RU_ABORT to the receive unit(RU), + * The RU will go to IDLE. + * + * Arguments: + * bdp - Ptr to this card's e100_bdconfig structure + * lock - whether or not we should lock the board when doing this + * + * Returns: + * NONE + */ +void +e100_ru_abort(bd_config_t *bdp) +{ + bdd_t *bddp = bdp->bddp; + uint32_t lock_flag; + + spin_lock_irqsave(&bddp->bd_lock, lock_flag); + e100_wait_scb(bdp); + e100_exec_cmd(bdp, SCB_RUC_ABORT); + spin_unlock_irqrestore(&bddp->bd_lock, lock_flag); +} + +/* + * Procedure: e100_clr_cntrs + * + * Description: This routine will clear the adapter error statistic + * counters. + * + * Arguments: + * bdp - Ptr to this card's e100_bdconfig structure + * + * Returns: + * B_TRUE - If successfully cleared stat counters + * B_FALSE - If command failed to complete properly + */ +static boolean_t +e100_clr_cntrs(bd_config_t *bdp) +{ + bdd_t *bddp = bdp->bddp; /* stores all adapter specific info */ + int e100_retry; + + /* Load the dump counters pointer. Since this command is generated only + * * after the IA setup has complete, we don't need to wait for the SCB * + * command word to clear */ + bddp->scbp->scb_gen_ptr = bddp->stat_cnt_paddr; + + /* Issue the load dump counters address command */ + bddp->prev_cu_cmd = SCB_CUC_DUMP_ADDR; + e100_exec_cmd(bdp, SCB_CUC_DUMP_ADDR); + + /* wait 10 microseconds for the command to complete */ + drv_usecwait(10); + + /* Now dump and reset all of the statistics */ + bddp->prev_cu_cmd = SCB_CUC_DUMP_RST_STAT; + e100_exec_cmd(bdp, SCB_CUC_DUMP_RST_STAT); + + /* Now wait for the dump/reset to complete */ + e100_retry = E100_CMD_WAIT; + while (((uint16_t) bddp->pstats_counters->cmd_complete != 0xA007) + && (e100_retry)) { + mdelay(20); + e100_retry--; + } + + return (B_TRUE); +} + + +/* + * Procedure: e100_dump_stat_cntrs + * + * Description: This routine will dump the board error counters & then reset + * them. + * + * Arguments: + * bdp - Ptr to this card's e100_bdconfig structure + * + * Returns: + * NONE + */ +void +e100_dump_stats_cntrs(bd_config_t *bdp) +{ + bdd_t *bddp = bdp->bddp; /* stores all adapter specific info */ + int delay_cnt = 10; + int retry, lock_flag_tx, lock_flag_bd; + + /* If the CU seems to be hung, get outta here. */ + if (bddp->flags & CU_ACTIVE_TOOLONG) + return; + + /* clear the dump counter complete word */ + bddp->pstats_counters->cmd_complete = 0; + + spin_lock_irqsave(&bddp->bd_tx_lock, lock_flag_tx); + spin_lock_irqsave(&bddp->bd_lock, lock_flag_bd); + + retry = DUMP_STATS_TIMEOUT; + + while (((bddp->scbp->scb_status & SCB_CUS_MASK) == SCB_CUS_ACTIVE) + && (retry)) { + mdelay(20); + retry--; + } + if (!retry) { + /* Mark board to indicate that the CU is hung. This flag * will be + * cleared by the intr routine. This is to fix the OS * hang that was + * encounterd when there was a speed mismatch * between the board and + * the switch. */ + if (DEBUG) + printk(KERN_DEBUG "e100_dump_stats_counters: CU active too long\n"); + bddp->flags |= CU_ACTIVE_TOOLONG; + + if (DEBUG) + printk(KERN_DEBUG "e100: Board[%d] has been disabled\n", bdp->bd_number); + spin_unlock_irqrestore(&bddp->bd_lock, lock_flag_bd); + spin_unlock_irqrestore(&bddp->bd_tx_lock, lock_flag_tx); + return; + } + + /* + * we need to do a wait before issuing the next send, so set previous + * command to CB_DUMP_RST_STAT + */ + bddp->prev_cu_cmd = CB_DUMP_RST_STAT; + + /* dump h/w stats counters */ + e100_exec_cmd(bdp, SCB_CUC_DUMP_RST_STAT); + + /* check the status of the CU, */ + if ((bddp->scbp->scb_status & SCB_CUS_MASK) == 0) /* is idle */ + bddp->prev_cu_cmd = CB_NULL; + spin_unlock_irqrestore(&bddp->bd_lock, lock_flag_bd); + spin_unlock_irqrestore(&bddp->bd_tx_lock, lock_flag_tx); + /* now await command completion */ + while (((uint16_t) bddp->pstats_counters->cmd_complete != 0xA007) && + delay_cnt) { + delay_cnt--; + drv_usecwait(25); + } + + /* increment the staticitcs */ + bddp->perr_stats->gd_xmits += bddp->pstats_counters->xmt_gd_frames; + bddp->perr_stats->gd_recvs += bddp->pstats_counters->rcv_gd_frames; + bddp->perr_stats->tx_abrt_xs_col += + bddp->pstats_counters->xmt_max_coll; + bddp->perr_stats->tx_late_col += bddp->pstats_counters->xmt_late_coll; + bddp->perr_stats->tx_dma_urun += bddp->pstats_counters->xmt_uruns; + bddp->perr_stats->tx_lost_csrs += bddp->pstats_counters->xmt_lost_crs; + bddp->perr_stats->tx_ok_defrd += bddp->pstats_counters->xmt_deferred; + bddp->perr_stats->tx_one_retry += bddp->pstats_counters->xmt_sngl_coll; + bddp->perr_stats->tx_mt_one_retry += + bddp->pstats_counters->xmt_mlt_coll; + bddp->perr_stats->tx_tot_retries += + bddp->pstats_counters->xmt_ttl_coll; + bddp->perr_stats->rcv_crc_err += bddp->pstats_counters->rcv_crc_errs; + bddp->perr_stats->rcv_align_err += + bddp->pstats_counters->rcv_algn_errs; + bddp->perr_stats->rcv_rsrc_err += bddp->pstats_counters->rcv_rsrc_err; + bddp->perr_stats->rcv_dma_orun += bddp->pstats_counters->rcv_oruns; + bddp->perr_stats->rcv_cdt_frames += + bddp->pstats_counters->rcv_err_coll; + bddp->perr_stats->rcv_runts += bddp->pstats_counters->rcv_shrt_frames; + + return; +} + + +/* + * Procedure: e100_exec_poll_cmd + * + * Description: This routine will submit a command block to be executed, & + * then it will wait for that command block to be executed. + * + * Arguments: + * bdp - Ptr to this card's e100_bdconfig structure + * + * Returns: + * B_TRUE - If we successfully submitted and completed the command. + * B_FALSE - If we didn't successfully submit and complete the command. + */ +static boolean_t +e100_exec_poll_cmd(bd_config_t *bdp) +{ + uint_t delay; + boolean_t status = 0; + bdd_t *bddp; /* stores all adapter specific info */ + + pcb_header_t pntcb_hdr; + + bddp = (pbdd_t) bdp->bddp; /* get bddp of this board */ + pntcb_hdr = (pcb_header_t) bddp->pntcb; /* get hdr of non tcb cmd */ + + /* Set the Command Block to be the last command block */ + pntcb_hdr->cb_cmd |= CB_EL_BIT; + + /* Clear the status of the command block */ + pntcb_hdr->cb_status = 0; + + /* Start the command unit. */ + e100_exec_cmd(bdp, SCB_CUC_START); + + /* Wait for the SCB to clear, indicating the completion of the command. */ + if (e100_wait_scb(bdp) != B_TRUE) { + return (B_FALSE); + } + + /* Wait 100ms for some status */ + for (delay = 0; delay < 100; delay++) { + mdelay(1); + + /* need to check the pmc_buff status in case it's from the * + * set_multicast cmd */ + if ((pntcb_hdr->cb_status & CB_STATUS_COMPLETE)) { + status = TRUE; + break; + } else { + status = FALSE; + } + } + + if (delay == 100) { + return (B_FALSE); + } + + return (status); +} + + +/* + * Procedure: e100_wait_scb + * + * Description: 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 30 milliseconds for command acceptance. + * + * Arguments: + * bdp - Ptr to this card's e100_bdconfig structure + * + * Returns: + * B_TRUE if the SCB cleared within 300 milliseconds. + * B_FALSE if it didn't clear within 300 milliseconds + */ +boolean_t +e100_wait_scb(bd_config_t *bdp) +{ + int wait_count = 300000; + bdd_t *bddp = bdp->bddp; /* stores all adapter specific info */ + + do { + if (!bddp->scbp->scb_cmd_low) + return B_TRUE; + drv_usecwait(1); + } + while (wait_count--); + + return B_FALSE; +} + + +/* + * Procedure: e100_sw_reset + * + * Description: This routine will issue a software reset to the adapter. + * + * Arguments: + * bdp - Ptr to this card's e100_bdconfig structure + * reset_cmd - s/w reset or selective reset. + * + * Returns: + */ +void +e100_sw_reset(bd_config_t *bdp, uint32_t reset_cmd) +{ + bdd_t *bddp = bdp->bddp; /* stores all adapter specific info */ + +#if (DEBUG) + printk(KERN_DEBUG "e100_sw_reset, cmd = 0x%x\n", reset_cmd); +#endif + /* Issue a PORT command with a data word of 0 */ + bddp->scbp->scb_port = reset_cmd; + + /* wait 5 milliseconds for the reset to take effect */ + mdelay(5); + + /* Mask off our interrupt line -- its unmasked after reset */ + e100_dis_intr(bdp); + + return; +} + + +/* + * Procedure: e100_load_microcode + * + * Description: This routine downloads microcode on to the controller. This + * microcode is available for the 82558/9. The microcode + * reduces the number of receive interrupts by "bundling" them. The amount + * of reduction in interrupts is configurable thru a e100.c parameter + * called CPU_CYCLE_SAVER. + * + * Arguments: + * bdp - Pointer to this device's board config. + * rev_id - Revision ID of the board. + * + * Returns: + * B_TRUE - Success + * B_FALSE - Failure + */ +static boolean_t +e100_load_microcode(bd_config_t *bdp, uint8_t rev_id) +{ + uint_t i, microcode_length; + bdd_t *bddp = bdp->bddp; /* stores all adapter specific info */ + pcb_header_t pntcb_hdr; + + static uint32_t d101a_ucode[] = D101_A_RCVBUNDLE_UCODE; + static uint32_t d101b0_ucode[] = D101_B0_RCVBUNDLE_UCODE; + static uint32_t d101ma_ucode[] = D101M_B_RCVBUNDLE_UCODE; + static uint32_t d101s_ucode[] = D101S_RCVBUNDLE_UCODE; + static uint32_t d102_ucode[] = D102_B_RCVBUNDLE_UCODE; + static uint32_t d102c_ucode[] = D102_C_RCVBUNDLE_UCODE; + + uint32_t *mlong; + uint16_t *mshort; + int cpusaver_dword; + uint32_t cpusaver_dword_val; + + if (DEBUG) + printk(KERN_DEBUG "e100_load_microcode: rev_id=%d\n", rev_id); + + /* user turned ucode loading off */ + if (!ucode[bdp->bd_number]) + return B_FALSE; + /* this chips do not need ucode */ + if ((bddp->flags & IS_ICH) || (bddp->rev_id < D101A4_REV_ID)) { + return B_FALSE; + } + + pntcb_hdr = (pcb_header_t) bddp->pntcb; /* get hdr of non tcb cmd */ + + /* Decide which ucode to use by looking at the board's rev_id */ + if (rev_id == D101A4_REV_ID) { + mlong = d101a_ucode; + mshort = (uint16_t *) d101a_ucode; + microcode_length = D101_NUM_MICROCODE_DWORDS; + cpusaver_dword = D101_CPUSAVER_DWORD; + cpusaver_dword_val = 0x00080600; + } else if (rev_id == D101B0_REV_ID) { + mlong = d101b0_ucode; + mshort = (uint16_t *) d101b0_ucode; + microcode_length = D101_NUM_MICROCODE_DWORDS; + cpusaver_dword = D101_CPUSAVER_DWORD; + cpusaver_dword_val = 0x00080600; + } else if (rev_id == D101MA_REV_ID) { + mlong = d101ma_ucode; + mshort = (uint16_t *) d101ma_ucode; + microcode_length = D101M_NUM_MICROCODE_DWORDS; + cpusaver_dword = D101M_CPUSAVER_DWORD; + cpusaver_dword_val = 0x00080800; + } + /* Added microcode support for 82559S */ + else if (rev_id == D101S_REV_ID) { + mlong = d101s_ucode; + mshort = (uint16_t *) d101s_ucode; + microcode_length = D101S_NUM_MICROCODE_DWORDS; + cpusaver_dword = D101S_CPUSAVER_DWORD; + cpusaver_dword_val = 0x00080600; + } else if(rev_id == D102_REV_ID) { + mlong = d102_ucode; + mshort = (uint16_t *) d102_ucode; + microcode_length = D102_NUM_MICROCODE_DWORDS; + cpusaver_dword = D102_B_CPUSAVER_DWORD; + cpusaver_dword_val = 0x00080600; + } else if(rev_id == D102C_REV_ID) { + mlong = d102c_ucode; + mshort = (uint16_t *) d102c_ucode; + microcode_length = D102C_NUM_MICROCODE_DWORDS; + cpusaver_dword = D102_C_CPUSAVER_DWORD; + cpusaver_dword_val = 0x00080600; + } else { + return B_FALSE; /* we don't have ucode for this board */ + } + + /* Get the tunable value from e100.c and stick in in the right spot */ + if (!e100_cpu_saver) + return B_FALSE; /* User has disabled it */ + else + mshort[cpusaver_dword * 2] = (uint16_t) e100_cpu_saver; + + /* Get tunable parameter for maximum number of * frames that will be + * bundled. Only applicable for 559's. */ + if (rev_id == D101MA_REV_ID) + mshort[D101M_CPUSAVER_BUNDLE_MAX_DWORD * 2] = + (uint16_t) e100_cpusaver_bundle_max; + else if (rev_id == D101S_REV_ID) + mshort[D101S_CPUSAVER_BUNDLE_MAX_DWORD * 2] = + (uint16_t) e100_cpusaver_bundle_max; + + /* Setup the non-transmit command block header for the command. */ + pntcb_hdr->cb_status = 0; + pntcb_hdr->cb_cmd = CB_LOAD_MICROCODE; + /* Note: cb_lnk_ptr is a physical address stored in an unsigned long */ + pntcb_hdr->cb_lnk_ptr = 0; + + /* Copy in the microcode */ + for (i = 0; i < microcode_length; i++) + bddp->pntcb->ntcb.load_ucode.ucode_dword[i] = mlong[i]; + + /* Wait for the SCB command word to clear before we set the * general + * pointer */ + if (e100_wait_scb(bdp) != B_TRUE) + return (B_FALSE); + + + /* If we have issued any transmits, then the CU will either be active, * + * or in the suspended state. If the CU is active, then we wait for * + * it to be suspended. */ + if ((bddp->prev_cu_cmd == CB_TRANSMIT) || + (bddp->prev_cu_cmd == CB_TRANSMIT_FIRST)) { + /* Wait for suspended state */ + /* Set timeout to 100 ms */ + i = 0; + while (((bddp->scbp->scb_status & SCB_CUS_MASK) == SCB_CUS_ACTIVE) + && (i < 5)) { + mdelay(20); + i++; + } + if (i == 5) { + return (B_FALSE); + } + } + + /* Update the command list pointer. */ + bddp->scbp->scb_gen_ptr = bddp->nontx_paddr; + + /* store the command */ + bddp->prev_cu_cmd = CB_LOAD_MICROCODE; + + /* Submit the Load microcode command to the chip, and wait for it * to + * complete. */ + if (!e100_exec_poll_cmd(bdp)) + return (B_FALSE); + else + return (B_TRUE); +} + +/***************************************************************************/ +/***************************************************************************/ +/* EEPROM Functions */ +/***************************************************************************/ + +/* + * Procedure: e100_rd_pwa_no + * + * Description: read pwa (printed wired assembly) number + */ +void +e100_rd_pwa_no(bd_config_t *bdp) +{ + bdd_t *bddp = (bdd_t *) bdp->bddp; + + bddp->pwa_no = e100_ReadEEprom(bdp, EEPROM_PWA_NO); + bddp->pwa_no <<= 16; + bddp->pwa_no |= e100_ReadEEprom(bdp, EEPROM_PWA_NO+1); +} + + +/* + * Procedure: e100_rd_eaddr + * + * Description: Reads the permanent ethernet address from the eprom. + * + * Arguments: + * bdp - Ptr to this card's e100_bdconfig structure + * + * Returns: (none) + */ +void +e100_rd_eaddr(bd_config_t *bdp) +{ + int i; + uint16_t EepromWordValue; + bdd_t *bddp = (bdd_t *) bdp->bddp; + uint8_t data = 0; + + if (DEBUG) + printk(KERN_DEBUG "e100_rd_eaddr: begin\n"); + + /* Read SCB reg General Control 2 */ + data = bddp->scbp->scb_ext.d102_scb.scb_gen_ctrl2; + + if(bddp->rev_id >= D102_REV_ID) + { + while(!(data & SCB_GCR2_EEPROM_ACCESS_SEMAPHORE)) + { + + /* or in the apropriate bit. After we write this if it is still clear + that means that the hardware is accessing the eeprom. In this case + we will just loop until we get it. */ + + data |= SCB_GCR2_EEPROM_ACCESS_SEMAPHORE; + bddp->scbp->scb_ext.d102_scb.scb_gen_ctrl2 = data; + data = bddp->scbp->scb_ext.d102_scb.scb_gen_ctrl2; + + } + } + + for (i = 0; i < 6; i += 2) { + EepromWordValue = + e100_ReadEEprom(bdp, EEPROM_NODE_ADDRESS_BYTE_0 + (i / 2)); + + /* added code to set the perm_address in bddp */ + bdp->eaddr.bytes[i] = + bddp->perm_node_address[i] = (uint8_t) EepromWordValue; + bdp->eaddr.bytes[i + 1] = + bddp->perm_node_address[i + 1] = + (uint8_t) (EepromWordValue >> 8); + } + + /* Now reset the eeprom semaphore bit */ + /* Read SCB reg General Control 2 */ + if(bddp->rev_id >= D102_REV_ID) + { + data = bddp->scbp->scb_ext.d102_scb.scb_gen_ctrl2; + data &= ~SCB_GCR2_EEPROM_ACCESS_SEMAPHORE; + bddp->scbp->scb_ext.d102_scb.scb_gen_ctrl2 = data; + } + + /* fill in the device structure... */ + memcpy(&bdp->device->dev_addr[0], &bddp->perm_node_address[0], + ETHERNET_ADDRESS_LENGTH); + + if (E100_DEBUG) { + printk(KERN_DEBUG "Node addr is: %x:%x:%x:%x:%x:%x\n", + bddp->perm_node_address[0], + bddp->perm_node_address[1], + bddp->perm_node_address[2], + bddp->perm_node_address[3], + bddp->perm_node_address[4], + bddp->perm_node_address[5]); + } + + return; +} + +/* + * Procedure: e100_ReadEEprom + * + * Description: This routine serially reads one word out of the EEPROM. + * + * Arguments: + * bdp - Ptr to this card's e100_bdconfig structure + * Reg - EEPROM word to read. + * + * Modified for 82559 extended eeprom. + * + * Returns: + * Contents of EEPROM word (Reg). + */ +static uint16_t +e100_ReadEEprom(bd_config_t *bdp, uint16_t Reg) +{ + uint16_t Data; + bdd_t *bddp = (bdd_t *) bdp->bddp; + uint16_t bits; + + bits = e100_EEpromAddressSize(bddp->EEpromSize); + + E100_WRITE_REG(EEPROM_CTRL, EECS); + + /* write the read opcode and register number in that order */ + /* The opcode is 3bits in length, reg is 'bits' bits long */ + e100_ShiftOutBits(bdp, EEPROM_READ_OPCODE, 3); + e100_ShiftOutBits(bdp, Reg, bits); + + /* Now read the data (16 bits) in from the selected EEPROM word */ + Data = e100_ShiftInBits(bdp); + + e100_EEpromCleanup(bdp); + + return Data; +} + +/* + * Procedure: e100_ShiftOutBits + * + * Description: This routine shifts data bits out to the EEPROM. + * + * Arguments: + * bdp - Ptr to this card's e100_bdconfig structure + * data - data to send to the EEPROM. + * count - number of data bits to shift out. + * + * Returns: (none) + */ +static void +e100_ShiftOutBits(bd_config_t *bdp, uint16_t data, uint16_t count) +{ + bdd_t *bddp = (bdd_t *) bdp->bddp; + uint16_t x, mask; + + mask = 0x01 << (count - 1); + x = E100_READ_REG(EEPROM_CTRL); + x &= ~(EEDO | EEDI); + + do { + x &= ~EEDI; + if (data & mask) + x |= EEDI; + + E100_WRITE_REG(EEPROM_CTRL, x); + + drv_usecwait(100); + + e100_RaiseClock(bdp, &x); + e100_LowerClock(bdp, &x); + mask = mask >> 1; + } + while (mask); + + x &= ~EEDI; + E100_WRITE_REG(EEPROM_CTRL, x); + + return; +} + + +/* + * Procedure: e100_RaiseClock + * + * Description: This routine raises the EEPOM's clock input (EESK) + * + * Arguments: + * bdp - Ptr to this card's e100_bdconfig structure + * x - Ptr to the EEPROM control register's current value + * + * Returns: (none) + */ +static void +e100_RaiseClock(bd_config_t *bdp, uint16_t *x) +{ + bdd_t *bddp = (bdd_t *) bdp->bddp; + + *x = *x | EESK; + E100_WRITE_REG(EEPROM_CTRL, *x); + drv_usecwait(100); + + return; +} + + +/* + * Procedure: e100_LowerClock + * + * Description: This routine lower's the EEPOM's clock input (EESK) + * + * Arguments: + * bdp - Ptr to this card's e100_bdconfig structure + * x - Ptr to the EEPROM control register's current value + * + * Returns: (none) + */ +static void +e100_LowerClock(bd_config_t *bdp, uint16_t *x) +{ + bdd_t *bddp = (bdd_t *) bdp->bddp; + + *x = *x & ~EESK; + E100_WRITE_REG(EEPROM_CTRL, *x); + + drv_usecwait(100); + + return; +} + + +/* + * Procedure: e100_ShiftInBits + * + * Description: This routine shifts data bits in from the EEPROM. + * + * Arguments: + * bdp - Ptr to this card's e100_bdconfig structure + * + * Returns: + * The contents of that particular EEPROM word + */ +static uint16_t +e100_ShiftInBits(bd_config_t *bdp) +{ + bdd_t *bddp = (bdd_t *) bdp->bddp; + uint16_t x, data, i; + + x = E100_READ_REG(EEPROM_CTRL); + x &= ~(EEDO | EEDI); + data = 0; + + for (i = 0; i < 16; i++) { + data = data << 1; + e100_RaiseClock(bdp, &x); + + x = E100_READ_REG(EEPROM_CTRL); + + x &= ~(EEDI); + if (x & EEDO) + data |= 1; + + e100_LowerClock(bdp, &x); + } + + return data; +} + + +/* + * Procedure: e100_EEpromCleanup + * + * Description: This routine returns the EEPROM to an idle state + * + * Arguments: + * bdp - Ptr to this card's e100_bdconfig structure + * + * Returns: (none) + */ +static void +e100_EEpromCleanup(bd_config_t *bdp) +{ + bdd_t *bddp = (bdd_t *) bdp->bddp; + uint16_t x; + + x = E100_READ_REG(EEPROM_CTRL); + + x &= ~(EECS | EEDI); + E100_WRITE_REG(EEPROM_CTRL, x); + + e100_RaiseClock(bdp, &x); + e100_LowerClock(bdp, &x); + + return; +} + + +/* + * Procedure: e100_GetEEpromSize + * + * Description: Returns the size of the EEPROM + * + * Arguments: + * bdp - Ptr to this card's e100_bdconfig structure + * + * Returns: size of EEPROM + */ +uint16_t +e100_GetEEpromSize(bd_config_t *bdp) +{ + bdd_t *bddp = (bdd_t *) bdp->bddp; + uint16_t x, + size = 1; /* must be one to accumulate a product */ + uint16_t data; + + /* enable the eeprom by setting EECS. */ + x = E100_READ_REG(EEPROM_CTRL); + x &= ~(EEDI | EEDO | EESK); + x |= EECS; + E100_WRITE_REG(EEPROM_CTRL, x); + + /* write the read opcode */ + e100_ShiftOutBits(bdp, 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 = E100_READ_REG(EEPROM_CTRL); + 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 */ + + E100_WRITE_REG(EEPROM_CTRL, x); + drv_usecwait(100); + e100_RaiseClock(bdp, &x); + e100_LowerClock(bdp, &x); + + /* check for "dummy zero" */ + x = E100_READ_REG(EEPROM_CTRL); + + if (size > 256) { + size = 0; + break; + } + } + while (x & EEDO); + + /* read in the value requested */ + data = e100_ShiftInBits(bdp); + e100_EEpromCleanup(bdp); + + return size; +} + +/* + * Procedure: e100_EEpromAddressSize + * + * Description: Returns the number of address bits required + * + * Arguments: + * size - size of eeprom + * + * Returns: number of address bits + */ +static uint16_t +e100_EEpromAddressSize(uint16_t size) +{ + uint16_t address_size = 0; + + switch (size) { + case 64: + return 6; + case 128: + return 7; + case 256: + return 8; + } + + /* Added catchall and return statement. */ + while (size >>= 1) + address_size++; + return address_size; +} + + +/***************************************************************************/ +/***************************************************************************/ +/* PHY Functions */ +/***************************************************************************/ + +/* + * Procedure: PhyDetect + * + * Description: This routine will detect what phy we are using, set the line + * speed, FDX or HDX, and configure the phy if necessary. + * + * The following combinations are supported: + * - TX or T4 PHY alone at PHY address 1 + * - T4 or TX PHY at address 1 and MII PHY at address 0 + * - 82503 alone (10Base-T mode, no full duplex support) + * - 82503 and MII PHY (TX or T4) at address 0 + * + * The sequence / priority of detection is as follows: + * - PHY 1 with cable termination + * - PHY 0 with cable termination + * - PHY 1 (if found) without cable termination + * - 503 interface + * + * Additionally auto-negotiation capable (NWAY) and parallel + * detection PHYs are supported. The flow-chart is described + */ +boolean_t +e100_phydetect(bd_config_t *bdp) +{ + uint_t CurrPhy; + uint_t Phy1; + uint16_t MdiControlReg, MdiStatusReg; + uint8_t ReNegotiateTime = 35; + bdd_t *bddp; + int old_speed_duplex; + int board_speed_duplex; + + board_speed_duplex = e100_speed_duplex[bdp->bd_number]; + + bddp = (pbdd_t) bdp->bddp; /* get the bddp for this board */ + Phy1 = 0; + +#ifdef PHY_DEBUG + printk(KERN_DEBUG "e100_phydetect: \n"); +#endif + + /* Check for a phy from address 1 - 31 */ + for (CurrPhy = 1; CurrPhy <= MAX_PHY_ADDR; CurrPhy++) { + /* Read the MDI control register at CurrPhy. */ + e100_MdiRead(bdp, MDI_CONTROL_REG, CurrPhy, &MdiControlReg); + + /* Read the status register at phy 1 */ + e100_MdiRead(bdp, MDI_STATUS_REG, CurrPhy, &MdiStatusReg); + +#ifdef PHY_DEBUG + printk(KERN_DEBUG "(%d, 0x%x, 0x%x) \n", + CurrPhy, MdiControlReg, MdiStatusReg); +#endif + + /* check if we found a valid phy */ + if (!((MdiControlReg == 0xffff) || + ((MdiStatusReg == 0) && (MdiControlReg == 0)))) { + /* we have a valid phy1 */ +#ifdef PHY_DEBUG + printk(KERN_DEBUG "Found Phy 1 at address %d CReg 0x%x SReg 0x%x\n", + CurrPhy, MdiControlReg, MdiStatusReg); +#endif + + Phy1 = CurrPhy; + + /* Read the status register again because of sticky bits */ + e100_MdiRead(bdp, MDI_STATUS_REG, CurrPhy, &MdiStatusReg); + + /* If there is a valid link then use this Phy. */ + if (MdiStatusReg & MDI_SR_LINK_STATUS) { + /* Mark link up */ + bdp->flags |= DF_LINK_UP; + +#ifdef PHY_DEBUG + printk(KERN_DEBUG "Setup Phy 1 at address %d with link\n", + CurrPhy); +#endif + + bddp->phy_addr = Phy1; + + return (e100_SetupPhy(bdp)); + } +#ifdef PHY_DEBUG + printk(KERN_DEBUG "Phy 1 at address %d WITHOUT link\n", CurrPhy); +#endif + + /* found a valid phy without a link, so break */ + break; + } + } + + /* + * Next try to detect a PHY at address 0x00 because there was no Phy 1, + * or Phy 1 didn't have link + */ + + /* Read the MDI control register at phy 0 */ + e100_MdiRead(bdp, MDI_CONTROL_REG, 0, &MdiControlReg); + + /* Read the status register at phy 0 */ + e100_MdiRead(bdp, MDI_STATUS_REG, 0, &MdiStatusReg); + + /* check if we found a valid phy 0 */ + if ((MdiControlReg == 0xffff) || + ((MdiStatusReg == 0) && (MdiControlReg == 0))) { + /* we don't have a valid phy at address 0 */ + + if (Phy1) { + /* no phy 0, so use phy 1 */ + bddp->phy_addr = Phy1; + +#ifdef PHY_DEBUG + printk(KERN_DEBUG "Using Phy1 without link -- Phy 0 not found\n"); +#endif + + /* no phy 0, but there is a phy 1, so use phy 1 */ + return (e100_SetupPhy(bdp)); + } else { + /* didn't find phy 0 or phy 1, so assume a 503 interface */ + bddp->phy_addr = 32; + + /* + * This fix is for the board which has the 503 interface + * and need to have the speed and duplex mode set here. The only + * way for a user to get a FULL duplex setting is to have it forced + * in the e100.c file. + * + * The second test is for an invalid setting for the hardware. + */ + /* The adapter can't autoneg. so set to 10/HALF */ + if (board_speed_duplex == 0) { + old_speed_duplex = board_speed_duplex; + board_speed_duplex = e100_speed_duplex[bdp->bd_number] = 1; + e100_ForceSpeedAndDuplex(bdp); + /* Restore speed_duplex value. */ + board_speed_duplex = e100_speed_duplex[bdp->bd_number] = + old_speed_duplex; + } + else if ((board_speed_duplex == 1) + || (board_speed_duplex == 2)) { + e100_ForceSpeedAndDuplex(bdp); + } else if (board_speed_duplex > 2) { + 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 (B_FALSE); + } +#ifdef PHY_DEBUG + printk(KERN_DEBUG "503 serial component detected and " + "set speed and duplex mode\n"); +#endif + return (B_TRUE); + } + } else { + /* We have a valid phy at address 0. If phy 0 has a link then * we + * use phy 0. If Phy 0 doesn't have a link then we use Phy 1 * ( + * which also doesn't have a link ) if phy 1 is present, else use * + * phy 0 if phy 1 is not present */ + +#ifdef PHY_DEBUG + printk(KERN_DEBUG "Phy 0 detected\n"); +#endif + + /* If phy 1 was present, then we must isolate phy 1 before we * + * enable phy 0 to see if Phy 0 has a link. */ + if (Phy1) { + /* isolate phy 1 */ + e100_MdiWrite(bdp, MDI_CONTROL_REG, Phy1, MDI_CR_ISOLATE); + + /* wait 100 milliseconds for the phy to isolate. */ + mdelay(100); + } + + /* Since this Phy is at address 0, we must enable it. So clear */ + /* the isolate bit, and set the auto-speed select bit */ + e100_MdiWrite(bdp, MDI_CONTROL_REG, 0, MDI_CR_AUTO_SELECT); + + /* wait 100 milliseconds for the phy to be enabled. */ + mdelay(100); + + /* restart the auto-negotion process */ + e100_MdiWrite(bdp, MDI_CONTROL_REG, 0, + MDI_CR_RESTART_AUTO_NEG | MDI_CR_AUTO_SELECT); + + /* wait no more than 3.5 seconds for auto-negotiation to complete */ + while (ReNegotiateTime) { + /* Read the status register twice because of sticky bits */ + e100_MdiRead(bdp, MDI_STATUS_REG, 0, &MdiStatusReg); + e100_MdiRead(bdp, MDI_STATUS_REG, 0, &MdiStatusReg); + + if (MdiStatusReg & MDI_SR_AUTO_NEG_COMPLETE) + break; + + mdelay(10); + ReNegotiateTime--; + } + + /* Read the status register again because of sticky bits */ + e100_MdiRead(bdp, MDI_STATUS_REG, 0, &MdiStatusReg); + + /* Mark link up */ + if (MdiStatusReg & MDI_SR_LINK_STATUS) + { + bdp->flags |= DF_LINK_UP; + } + + /* If the link was not set */ + if (!(MdiStatusReg & MDI_SR_LINK_STATUS)) { + /* the link wasn't set, so use phy 1 if phy 1 was present */ + if (Phy1) { +#ifdef PHY_DEBUG + printk(KERN_DEBUG "Using Phy1 without link -- Phy 0 has no link\n"); +#endif + + /* isolate phy 0 */ + e100_MdiWrite(bdp, MDI_CONTROL_REG, 0, MDI_CR_ISOLATE); + + /* wait 100 milliseconds for the phy to isolate. */ + mdelay(100); + + /* Now re-enable PHY 1 */ + e100_MdiWrite(bdp, MDI_CONTROL_REG, Phy1, + MDI_CR_AUTO_SELECT); + + /* wait 100 milliseconds for the phy to be enabled. */ + mdelay(100); + + /* restart the auto-negotion process */ + e100_MdiWrite(bdp, MDI_CONTROL_REG, bddp->phy_addr, + MDI_CR_RESTART_AUTO_NEG | + MDI_CR_AUTO_SELECT); + + bddp->phy_addr = Phy1; + + /* Don't wait for it 2 complete (no link from earlier) */ + return (e100_SetupPhy(bdp)); + } + + } + + /* Definitely using Phy 0 */ + bddp->phy_addr = 0; + + return (e100_SetupPhy(bdp)); + } +} + + +/* + * Procedure: e100_SetupPhy + * + * Description: This routine will setup phy 1 or phy 0 so that it is configured + * to match line speed. This driver assumes assume the adapter + * is automatically setting the line speed, and the duplex mode. + * At the end of this routine, any truly Phy specific code will + * be executed (each Phy has its own quirks, and some require + * that certain special bits are set). + * + * NOTE: The driver assumes that SPEED and FORCEFDX are specified at the + * same time. If FORCEDPX is set without speed being set, the driver + * will encouter a fatal error. + * + * Arguments: + * bdp - Ptr to this card's e100_bdconfig structure + * + * Result: + * Returns: + * B_TRUE - If the phy could be configured correctly + * B_FALSE - If the phy couldn't be configured correctly, because an + * + */ +static boolean_t +e100_SetupPhy(bd_config_t *bdp) +{ + uint16_t MdiIdLowReg, MdiIdHighReg; + uint16_t MdiMiscReg; + uint_t PhyId; + bdd_t *bddp; + int board_speed_duplex; + + board_speed_duplex = e100_speed_duplex[bdp->bd_number]; + + bddp = (pbdd_t) bdp->bddp; /* get the bddp for this board */ + +#ifdef PHY_DEBUG + printk(KERN_DEBUG "e100_SetupPhy Phy %d\n", bddp->phy_addr); +#endif + + /* Find out specifically what Phy this is. We do this because for * + * certain phys there are specific bits that must be set so that the * + * phy and the 82557 work together properly. */ + + e100_MdiRead(bdp, PHY_ID_REG_1, bddp->phy_addr, &MdiIdLowReg); + e100_MdiRead(bdp, PHY_ID_REG_2, bddp->phy_addr, &MdiIdHighReg); + + PhyId = ((uint_t) MdiIdLowReg | ((uint_t) MdiIdHighReg << 16)); + + bddp->PhyState = 0; + bddp->PhyDelay = 0; + + /* get the revsion field of the Phy ID so that we'll be able to detect */ + /* future revs of the same Phy. */ + PhyId &= PHY_MODEL_REV_ID_MASK; +#ifdef PHY_DEBUG + printk(KERN_DEBUG "Phy ID is 0x%x \n", PhyId); +#endif + + bddp->PhyId = PhyId; + + if(PhyId == PHY_82562EH) + { + bddp->flags |= IS_82562EH; + PhyProcessing82562EHInit(bddp); + } + + /* If Intel Phy, set flag to indicate this */ + if (PhyId == PHY_82555_TX) { + bdp->flags |= DF_PHY_82555; + } + + /* Handle the National TX */ + if (PhyId == PHY_NSC_TX) { + e100_MdiRead(bdp, NSC_CONG_CONTROL_REG, bddp->phy_addr, + &MdiMiscReg); + + MdiMiscReg |= NSC_TX_CONG_TXREADY; + + /* If we are configured to do congestion control, then enable the */ + /* congestion control bit in the National Phy */ + if (e100_cong_enbl) + MdiMiscReg |= NSC_TX_CONG_ENABLE; + else + MdiMiscReg &= ~NSC_TX_CONG_ENABLE; + + e100_MdiWrite(bdp, NSC_CONG_CONTROL_REG, bddp->phy_addr, + MdiMiscReg); + } + + if ((board_speed_duplex >= 1) && (board_speed_duplex <= 4)) + e100_ForceSpeedAndDuplex(bdp); + + /* Set bddp values for speed and duplex modes only if autonegotiation * + * happened. If it was forced, the bddp values would have been set by * + * the ForceSpeedAndUplex routine. If it isn't then we need to check * to + * see if autoneg has completed and if we need to restart it. */ + if (!((board_speed_duplex >= 1) && (board_speed_duplex <= 4))) { + e100_auto_neg(bdp); + e100_FindPhySpeedAndDpx(bdp, PhyId); + } +#ifdef PHY_DEBUG + printk(KERN_DEBUG "Current speed=%d, Current Duplex=%d\n", + bddp->cur_line_speed, bddp->cur_dplx_mode); +#endif + + return (B_TRUE); +} + + +/* + * 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 + */ +void +e100_fix_polarity (bd_config_t *bdp) +{ + bdd_t *bddp = (bdd_t *) bdp->bddp; + unsigned long PhyAdd; + unsigned short Status; + unsigned short errors; + int speed; + + if (DEBUG) printk(KERN_DEBUG "e100_set_polarity: begin\n"); + + PhyAdd = bddp->phy_addr; + + /* 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 */ + if (!(bddp->flags & IS_BACHELOR)) { + if (e100_autopolarity == 0) { + e100_MdiWrite(bdp, PHY_82555_SPECIAL_CONTROL, + PhyAdd, DISABLE_AUTO_POLARITY); + } else if (e100_autopolarity >= 2) { + /* we do this only if we have an 82555 and if link is up */ + if ((bdp->flags & DF_PHY_82555) && (bdp->flags & DF_LINK_UP)) { + +#ifdef DEBUG + printk(KERN_DEBUG "messing with autopolarity\n"); +#endif + e100_MdiRead(bdp, PHY_82555_CSR, PhyAdd, &Status); + speed = (Status & PHY_82555_SPEED_BIT) ? 100 : 10; + + /* we need to do this only if speed is 10 */ + if (speed == 10) { + /* see if we have any end of frame errors */ + e100_MdiRead(bdp, PHY_82555_EOF_COUNTER, PhyAdd, &errors); + + /* if non-zero, wait for 100 ms before reading again */ + if (errors) { + mdelay(100); + e100_MdiRead(bdp, PHY_82555_EOF_COUNTER, PhyAdd, &errors); + + /* if non-zero again, we disable polarity */ + if (errors) { + e100_MdiWrite(bdp, PHY_82555_SPECIAL_CONTROL, + PhyAdd, DISABLE_AUTO_POLARITY); + } + } else { + /* it is safe to read the polarity now */ + e100_MdiRead(bdp, PHY_82555_CSR, PhyAdd, &Status); + + /* if polarity is normal, disable polarity */ + if (!(Status & PHY_82555_POLARITY_BIT)) { + e100_MdiWrite(bdp, PHY_82555_SPECIAL_CONTROL, + PhyAdd, DISABLE_AUTO_POLARITY); + } + } + } /* end if speed == 10 */ + } /* end if PHY 82555 */ + } /* end of polarity fix */ + } + + +} + + +/* + * Procedure: e100_auto_neg + * + * Description: This routine will start autonegotiation and wait + * for it to complete + * + * Arguments: + * bdp - Ptr to this card's e100_bdconfig structure + * + * Returns: + * NOTHING + */ +void +e100_auto_neg(bd_config_t *bdp) +{ + uint16_t mdi_status_reg; + bdd_t *bddp = bdp->bddp; + uint_t i; + + /* If we are on 82562EH then no need */ + if(bddp->flags & IS_82562EH) + { + return; + } + + /* first we need to check to see if autoneg has already completed. Sticky + * so read twice */ + e100_MdiRead(bdp, MDI_STATUS_REG, bddp->phy_addr, &(mdi_status_reg)); + e100_MdiRead(bdp, MDI_STATUS_REG, bddp->phy_addr, &(mdi_status_reg)); + /* if it is finished then leave */ + if (mdi_status_reg & MDI_SR_AUTO_NEG_COMPLETE) { + return; + } + + /* if we are capable of performing autoneg then we restart */ + if (mdi_status_reg & MDI_SR_AUTO_SELECT_CAPABLE) { + e100_MdiWrite(bdp, MDI_CONTROL_REG, bddp->phy_addr, + MDI_CR_AUTO_SELECT | MDI_CR_RESTART_AUTO_NEG); + + /* now wait for autoneg to complete this could be up to 3 seconds + * which is 300 times 10 milliseconds */ + for (i = 0; (!(mdi_status_reg & MDI_SR_AUTO_NEG_COMPLETE)) && + (i < 300); i++) { + /* delay 10 milliseconds */ + mdelay(10); + + /* now re-read the value. Sticky so read twice */ + e100_MdiRead(bdp, MDI_STATUS_REG, bddp->phy_addr, + &(mdi_status_reg)); + e100_MdiRead(bdp, MDI_STATUS_REG, bddp->phy_addr, + &(mdi_status_reg)); + } + if (i == 300) + bddp->flags |= INVALID_SPEED_DPLX; + } + return; +} + + +/* + * Procedure: e100_FindPhySpeedAndDpx + * + * 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 + * PhyId - The ID of the PHY in question. + * + * Returns: + * NOTHING + */ +void +e100_FindPhySpeedAndDpx(bd_config_t *bdp, uint_t PhyId) +{ + uint16_t MdiStatusReg; + uint16_t MdiMiscReg; + uint16_t MdiOwnAdReg; + uint16_t MdiLinkPartnerAdReg; + bdd_t *bddp = bdp->bddp; + + /* First check if we are on 82562EH */ + /* If we are then we are always 1Mpbs half duplex */ + if(bddp->flags & IS_82562EH) + { + bddp->cur_line_speed = 1; + bddp->cur_dplx_mode = HALF_DUPLEX; + return; + } + + /* First we should check to see if we have link */ + /* If we don't have link no reason to print a speed and duplex */ + if ((bddp->rev_id >= 8) || (bddp->flags & IS_ICH)) { + if (!(bddp->scbp->scb_ext.d101m_scb.scb_gen_stat & BIT_0)) { + bddp->cur_line_speed = 0; + bddp->cur_dplx_mode = NO_DUPLEX; + return; + } + } else { + /* No GSR so lets get it from the MDI status reg */ + /* have to read it twice because it is a sticky bit */ + e100_MdiRead(bdp, MDI_STATUS_REG, bddp->phy_addr, &(MdiStatusReg)); + e100_MdiRead(bdp, MDI_STATUS_REG, bddp->phy_addr, &(MdiStatusReg)); + if (!(MdiStatusReg & BIT_2)) { + bddp->cur_line_speed = 0; + bddp->cur_dplx_mode = NO_DUPLEX; + return; + } + } + + /* On the 82559 and later controllers, speed/duplex is part of the * + * SCB. So, we save an MdiRead and get these from the SCB. * */ + if ((bddp->rev_id >= 8) || (bddp->flags & IS_ICH)) { + /* Read speed */ + if (bddp->scbp->scb_ext.d101m_scb.scb_gen_stat & BIT_1) + bddp->cur_line_speed = 100; + else + bddp->cur_line_speed = 10; + + /* Read duplex */ + if (bddp->scbp->scb_ext.d101m_scb.scb_gen_stat & BIT_2) + bddp->cur_dplx_mode = FULL_DUPLEX; + else + bddp->cur_dplx_mode = HALF_DUPLEX; + } + + /* 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_MdiRead(bdp, EXTENDED_REG_0, bddp->phy_addr, &MdiMiscReg); + + /* Get current speed setting */ + if (MdiMiscReg & PHY_100_ER0_SPEED_INDIC) + bddp->cur_line_speed = 100; + else + bddp->cur_line_speed = 10; + + /* Get current duplex setting -- if bit is set then FDX is enabled */ + if (MdiMiscReg & PHY_100_ER0_FDX_INDIC) + bddp->cur_dplx_mode = FULL_DUPLEX; + else + bddp->cur_dplx_mode = HALF_DUPLEX; + +#ifdef PHY_DEBUG + printk(KERN_DEBUG "Detecting Speed/Dpx from PHY_100 REG_0 0x%x\n", + MdiMiscReg); +#endif + + return; + } + + /* See if link partner was capable of Auto-Negotiation (bit 0, reg 6) */ + e100_MdiRead(bdp, AUTO_NEG_EXPANSION_REG, bddp->phy_addr, &MdiMiscReg); + + /* See if Auto-Negotiation was complete (bit 5, reg 1) */ + e100_MdiRead(bdp, MDI_STATUS_REG, bddp->phy_addr, &MdiStatusReg); + +#ifdef PHY_DEBUG + printk(KERN_DEBUG "Auto_neg_expn_reg 0x%x Mdi_status_reg 0x%x\n", + MdiMiscReg, MdiStatusReg); +#endif + + /* 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 ((MdiMiscReg & NWAY_EX_LP_NWAY) && + (MdiStatusReg & MDI_SR_AUTO_NEG_COMPLETE)) { +#ifdef PHY_DEBUG + printk(KERN_DEBUG "Detecting Speed/Dpx from NWAY connection\n"); +#endif + + /* Read our advertisement register */ + e100_MdiRead(bdp, AUTO_NEG_ADVERTISE_REG, bddp->phy_addr, + &MdiOwnAdReg); + + /* Read our link partner's advertisement register */ + e100_MdiRead(bdp, AUTO_NEG_LINK_PARTNER_REG, bddp->phy_addr, + &MdiLinkPartnerAdReg); + +#ifdef PHY_DEBUG + printk(KERN_DEBUG "Auto_neg_ad_reg 0x%x Auto_neg_link_partner 0x%x\n", + MdiOwnAdReg, MdiLinkPartnerAdReg); +#endif + + /* AND the two advertisement registers together, and get rid of any + * * extraneous bits. */ + MdiOwnAdReg &= (MdiLinkPartnerAdReg & NWAY_LP_ABILITY); + + /* Get speed setting */ + if (MdiOwnAdReg & + (NWAY_AD_TX_HALF_DPX | NWAY_AD_TX_FULL_DPX | + NWAY_AD_T4_CAPABLE)) bddp->cur_line_speed = 100; + else + bddp->cur_line_speed = 10; + + /* Get duplex setting -- use priority resolution algorithm */ + if (MdiOwnAdReg & (NWAY_AD_T4_CAPABLE)) { + bddp->cur_dplx_mode = HALF_DUPLEX; + return; + } else if (MdiOwnAdReg & (NWAY_AD_TX_FULL_DPX)) { + bddp->cur_dplx_mode = FULL_DUPLEX; + return; + } else if (MdiOwnAdReg & (NWAY_AD_TX_HALF_DPX)) { + bddp->cur_dplx_mode = HALF_DUPLEX; + return; + } else if (MdiOwnAdReg & (NWAY_AD_10T_FULL_DPX)) { + bddp->cur_dplx_mode = FULL_DUPLEX; + return; + } else { + bddp->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. + */ + + bddp->cur_dplx_mode = HALF_DUPLEX; + + if (PhyId == PHY_NSC_TX) { + /* Read register 25 to get the SPEED_10 bit */ + e100_MdiRead(bdp, NSC_SPEED_IND_REG, bddp->phy_addr, &MdiMiscReg); + + /* If bit 6 was set then we're at 10Mbps */ + if (MdiMiscReg & NSC_TX_SPD_INDC_SPEED) + bddp->cur_line_speed = 10; + else + bddp->cur_line_speed = 100; + + if (DEBUG) + printk(KERN_DEBUG "Detecting Speed/Dpx from non-NWAY NSC NSC_SPEED 0x%x\n", + MdiMiscReg); + } else { + /* If we don't know what line speed we are set at, then we'll default + * to 10Mbps */ +#ifdef PHY_DEBUG + printk(KERN_DEBUG "Line speed unknown set at 10Mbps\n"); +#endif + bddp->cur_line_speed = 10; + } +} + + +/* + * Procedure: e100_ForceSpeedAndDuplex + * + * 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 bd_config_t structure for the board + * + * Returns: void + * + */ +void +e100_ForceSpeedAndDuplex(bd_config_t *bdp) +{ + bdd_t *bddp = (bdd_t *) bdp->bddp; + uint16_t control; + int board_speed_duplex; + + /* If we are on 82562EH this doesn't apply */ + if(bddp->flags & IS_82562EH) + { + return; + } + + board_speed_duplex = e100_speed_duplex[bdp->bd_number]; + + bdp->flags |= DF_SPEED_FORCED; + e100_MdiRead(bdp, MDI_CONTROL_REG, bddp->phy_addr, &control); + control &= ~MDI_CR_AUTO_SELECT; + + /* Check e100.c values */ + switch (board_speed_duplex) { + /* 10 half */ + case 1: + control &= ~MDI_CR_10_100; + control &= ~MDI_CR_FULL_HALF; + bddp->cur_line_speed = 10; + bddp->cur_dplx_mode = HALF_DUPLEX; + break; + + /* 10 full */ + case 2: + control &= ~MDI_CR_10_100; + control |= MDI_CR_FULL_HALF; + bddp->cur_line_speed = 10; + bddp->cur_dplx_mode = FULL_DUPLEX; + break; + + /* 100 half */ + case 3: + control |= MDI_CR_10_100; + control &= ~MDI_CR_FULL_HALF; + bddp->cur_line_speed = 100; + bddp->cur_dplx_mode = HALF_DUPLEX; + break; + + /* 100 full */ + case 4: + control |= MDI_CR_10_100; + control |= MDI_CR_FULL_HALF; + bddp->cur_line_speed = 100; + bddp->cur_dplx_mode = FULL_DUPLEX; + break; + } + + e100_MdiWrite(bdp, MDI_CONTROL_REG, bddp->phy_addr, control); + + mdelay(2000); +} + + +/* + * Procedure: e100_phy_check + * + * Arguments: bdp - Pointer to the bd_config_t structure for the board + * + * Returns: void + */ +void +e100_phy_check(bd_config_t *bdp) +{ + bdd_t *bddp = (bdd_t *) bdp->bddp; + int32_t LinkState; + + if (bddp->flags & PRINT_SPEED_DPLX) { + e100_FindPhySpeedAndDpx(bdp, bddp->PhyId); + bddp->flags &= ~PRINT_SPEED_DPLX; + + if (bddp->cur_dplx_mode == HALF_DUPLEX) + printk(KERN_ERR "e100: %s NIC Link is Up %d Mbps Half duplex\n", + bdp->device->name, bddp->cur_line_speed); + else + printk(KERN_ERR "e100: %s NIC Link is Up %d Mbps Full duplex\n", + bdp->device->name, bddp->cur_line_speed); + } + + LinkState = e100_PhyLinkState(bdp); + if (LinkState && (bddp->flags & INVALID_SPEED_DPLX)) { + bddp->flags &= ~INVALID_SPEED_DPLX; + bddp->flags |= PRINT_SPEED_DPLX; + } + + if ((!(bdp->flags & DF_PHY_82555)) || (bdp->flags & DF_SPEED_FORCED)) + return; + + if (LinkState) { + switch (bddp->PhyState) { + case 0: + break; + case 1: + e100_MdiWrite(bdp, PHY_82555_SPECIAL_CONTROL, bddp->phy_addr, 0x0000); + break; + case 2: + e100_MdiWrite(bdp, PHY_82555_MDI_EQUALIZER_CSR, bddp->phy_addr, 0x3000); + break; + } + bddp->PhyState = 0; + bddp->PhyDelay = 0; + } else if (!bddp->PhyDelay--) { + switch (bddp->PhyState) { + case 0: + e100_MdiWrite(bdp, PHY_82555_SPECIAL_CONTROL, bddp->phy_addr, + EXTENDED_SQUELCH_BIT); + bddp->PhyState = 1; + break; + case 1: + e100_MdiWrite(bdp, PHY_82555_SPECIAL_CONTROL, bddp->phy_addr, + 0x0000); + e100_MdiWrite(bdp, PHY_82555_MDI_EQUALIZER_CSR, bddp->phy_addr, 0x2010); + bddp->PhyState = 2; + break; + case 2: + e100_MdiWrite(bdp, PHY_82555_MDI_EQUALIZER_CSR, bddp->phy_addr, 0x3000); + bddp->PhyState = 0; + break; + } + + e100_MdiWrite(bdp, MDI_CONTROL_REG, bddp->phy_addr, + MDI_CR_AUTO_SELECT | MDI_CR_RESTART_AUTO_NEG); + bddp->PhyDelay = 3; + } +} + + +void e100_ResetPhy(bd_config_t *bdp) +{ + uint16_t mdi_control_reg; + bdd_t *bddp = bdp->bddp; + + + mdi_control_reg = (MDI_CR_AUTO_SELECT | MDI_CR_RESTART_AUTO_NEG | + MDI_CR_RESET); + + e100_MdiWrite(bdp, MDI_CONTROL_REG, bddp->phy_addr, mdi_control_reg); + + udelay(100); +} + + +/* + * Procedure: e100_PhyLinkState + * + * Description: This routine updates the link status of the adapter + * + * Arguments: bdp - Pointer to the bd_config_t structure for the board + * + * Returns: + * B_TRUE - If a link is found + * B_FALSE - If there is no link + */ +boolean_t +e100_PhyLinkState(bd_config_t *bdp) +{ + bdd_t *bddp = (bdd_t *) bdp->bddp; + + /* Check link status */ + if (e100_GetPhyLinkState(bdp) == B_TRUE) + { + /* Link is up */ + if (!(bdp->flags & DF_LINK_UP)) + { + bdp->flags |= DF_LINK_UP; + } + return (B_TRUE); + } + /* Link is down */ + if (bdp->flags & DF_LINK_UP) + { + bdp->flags &= ~DF_LINK_UP; + + /* Invalidate the speed and duplex values */ + bddp->flags |= INVALID_SPEED_DPLX; + + /* reset the zerol lock state */ + bdp->ZeroLockState = ZLOCK_INITIAL; + + // set auto lock for phy auto-negotiation on link up + e100_MdiWrite(bdp, PHY_82555_MDI_EQUALIZER_CSR, bddp->phy_addr, 0); + + printk(KERN_ERR "e100: %s NIC Link is Down\n", bdp->device->name); + } + + return (B_FALSE); +} + +/* + * Procedure: e100_GetPhyLinkState + * + * Description: This routine checks the link status of the adapter + * + * Arguments: bdp - Pointer to the bd_config_t structure for the board + * + * Returns: + * B_TRUE - If a link is found + * B_FALSE - If there is no link + */ +boolean_t +e100_GetPhyLinkState(bd_config_t *bdp) +{ + bdd_t *bddp = (bdd_t *) bdp->bddp; + uint16_t Status; + + /* Check link status */ + /* If the controller is a 82559 or later one, link status is available + * from the CSR. This avoids the MdiRead. */ + if ((bddp->rev_id >= 8) || (bddp->flags & IS_ICH)) { + if (bddp->scbp->scb_ext.d101m_scb.scb_gen_stat & BIT_0) { + /* Link is up */ + return (B_TRUE); + } else + /* Link is down */ + return (B_FALSE); + } + else { + /* Read the status register */ + e100_MdiRead(bdp, MDI_STATUS_REG, bddp->phy_addr, &Status); + + /* Read the status register again because of sticky bits */ + e100_MdiRead(bdp, MDI_STATUS_REG, bddp->phy_addr, &Status); + + if (Status & MDI_SR_LINK_STATUS) { + return (B_TRUE); + } else { + return (B_FALSE); + } + } +} + +/* + * Procedure: e100_MdiWrite + * + * 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 + * RegAddress - The MII register that we are writing to + * PhyAddress - The MDI address of the Phy component. + * DataValue - The value that we are writing to the MII register. + * + * Returns: + * NOTHING + */ +void +e100_MdiWrite(bd_config_t *bdp, + uint32_t RegAddress, uint32_t PhyAddress, uint16_t DataValue) +{ + bdd_t *bddp; + int e100_retry; + uint32_t temp_val; + + bddp = (pbdd_t) bdp->bddp; /* get the bddp for this board */ + + temp_val = (((uint32_t) DataValue) | + (RegAddress << 16) | (PhyAddress << 21) | (MDI_WRITE << + 26)); + bddp->scbp->scb_mdi_cntrl = temp_val; + + /* wait 20usec before checking status */ + drv_usecwait(20); /* Removed mstous. */ + + /* poll for the mdi write to complete */ + e100_retry = E100_CMD_WAIT; + while ((!(bddp->scbp->scb_mdi_cntrl & MDI_PHY_READY)) && (e100_retry)) { + drv_usecwait(20); /* Removed mstous. */ + e100_retry--; + } +} + + +/* + * Procedure: e100_MdiRead + * + * 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 + * RegAddress - The MII register that we are reading from + * PhyAddress - The MDI address of the Phy component. + * + * Results: + * DataValue - The value that we read from the MII register. + * + * Returns: + * NOTHING + */ +void +e100_MdiRead(bd_config_t *bdp, + uint32_t RegAddress, uint32_t PhyAddress, uint16_t *DataValue) +{ + bdd_t *bddp; + int e100_retry; + uint32_t temp_val; + + bddp = (pbdd_t) bdp->bddp; /* get the bddp for this board */ + + /* Issue the read command to the MDI control register. */ + temp_val = + ((RegAddress << 16) | (PhyAddress << 21) | (MDI_READ << 26)); + bddp->scbp->scb_mdi_cntrl = temp_val; + + /* wait 20usec before checking status */ + drv_usecwait(20); /* Removed mstous. */ + + /* poll for the mdi read to complete */ + e100_retry = E100_CMD_WAIT; + while ((!(bddp->scbp->scb_mdi_cntrl & MDI_PHY_READY)) && (e100_retry)) { + drv_usecwait(20); + e100_retry--; + } + + /* return 0 blindly as datavalue if we have timed out * and hope that + * someone above smells a rat */ + + if (!e100_retry) + *DataValue = 0; + + *DataValue = (uint16_t) bddp->scbp->scb_mdi_cntrl; +} + + +/***************************************************************************/ +/***************************************************************************/ +/* Checksum Functions */ +/***************************************************************************/ + +/* + * Procedure: e100_check_for_ip + * + * Description: Looks for an TCP/IP or UDP/IP packet. + * + * Arguments: int *HeaderOffset. Where does the ethernet header stop. + * struct sk_buff *. Pointer to the packet data + * + * Returns: IP Packet if we can checksum this packet. + * NULL if we can not checksum this packet. + */ +ip_v4_header * +e100_check_for_ip(int *HeaderOffset, struct sk_buff *skb) +{ + ip_v4_header *IPPacket = NULL; + ethernet_snap_header *snapHeader; + ethernet_ii_header *eIIHeader; + + snapHeader = (ethernet_snap_header *) skb->data; + eIIHeader = (ethernet_ii_header *) skb->data; + + /* Check for Ethernet_II IP encapsulation */ + if (eIIHeader->TypeLength == IP_PROTOCOL) { + /* We need to point the IPPacket past the Ethernet_II header. */ + IPPacket = + (ip_v4_header *) ((uint8_t *) eIIHeader + + sizeof(ethernet_ii_header)); + + if (IPPacket->ProtocolCarried == TCP_PROTOCOL) { + *HeaderOffset = sizeof(ethernet_ii_header); + return IPPacket; + } + + if (IPPacket->ProtocolCarried == UDP_PROTOCOL) { + *HeaderOffset = sizeof(ethernet_ii_header); + return IPPacket; + } + } + /* To qualify for IP encapsulated SNAP the type/length field must contain + * a length value i.e. less than 1500 */ + else if (snapHeader->TypeLength <= MAX_PKT_LEN_FIELD) { + /* Check for SNAP IP encapsulation */ + if ((snapHeader->DSAP == 0xAA) && (snapHeader->SSAP == 0xAA) && + (snapHeader->Ctrl == 0x03)) { + if (*(uint16_t *) & snapHeader->ProtocolId == IP_PROTOCOL) { + IPPacket = + (ip_v4_header *) ((uint8_t *) snapHeader + + sizeof(ethernet_snap_header)); + + if (IPPacket->ProtocolCarried == UDP_PROTOCOL) { + *HeaderOffset = sizeof(ethernet_snap_header); + return IPPacket; + } + + if (IPPacket->ProtocolCarried == TCP_PROTOCOL) { + *HeaderOffset = sizeof(ethernet_snap_header); + return IPPacket; + } + } + } + } + + /* If we didn't find IP encapsulation */ + return NULL; +} + + +/* + * Procedure: e100_calculate_checksum + * + * Description: Calculates the checksum value from the hardware value. + * + * Arguments: uint32_t *HeaderOffset. Where does the ethernet header stop. + * struct sk_buff *skb. Pointer to the packet data + * + * Returns: + * B_TRUE == Valid Checksum + * B_FALSE == Invalid Checksum + */ +boolean_t +e100_calculate_checksum(ip_v4_header *IPPacket, uint32_t HeaderOffset, + struct sk_buff *skb, uint32_t packetSize) +{ + + uint16_t hwCheckSum; + uint8_t *dataFragment; + uint32_t adjustValue = 0; + uint16_t IPTotalLength = 0; + uint32_t i; + uint16_t totalPacketLength; + uint32_t addLength; + udp_header *udpPacket; + union { + uint8_t byteValue[2]; + uint16_t wordValue; + } protocolCarriedSwapped = { { + 0 } }; + union { + uint8_t byteValue[2]; + uint16_t wordValue; + } padWord = { { + 0 } }; + + if (skb->len <= MINIMUM_ETHERNET_PACKET_SIZE) { + skb->ip_summed = CHECKSUM_NONE; + return B_TRUE; + } + + /* Initialize the total packet length. This could include the CRC if we + * are DMAing CRC's. */ + totalPacketLength = packetSize; + + /* Initialize the dataFragment pointer to point at the begining of the + * data area. */ + dataFragment = (uint8_t *) skb->data; + + /* If we have a UDP packet we are now pointing to it. */ + udpPacket = + (udp_header *) ((uint8_t *) IPPacket + (IPPacket->HdrLength * 4)); + + /* If we have a UDP packet with a zero checksum, do not perform checksum + * validation and return ZERO */ + if ((IPPacket->ProtocolCarried == UDP_PROTOCOL) + && (udpPacket->Checksum == 0)) { + return 0; + } + /* Add up the IP Header and whats left of a SNAP header if it is a SNAP + * frame. Have to convert HeaderOffset to words from bytes */ + addLength = (IPPacket->HdrLength * 2) + ((HeaderOffset - + HARDWARE_CHECKSUM_START_OFFSET) + / 2); + for (i = 0; i < addLength; i++) { + adjustValue += *((uint16_t *) IPPacket + i); + } + + /* Now add back in the pseudo header parts. */ + adjustValue -= IPPacket->SrcAddr.Fields.SrcAddrLo; + adjustValue -= IPPacket->SrcAddr.Fields.SrcAddrHi; + adjustValue -= IPPacket->DestAddr.Fields.DestAddrLo; + adjustValue -= IPPacket->DestAddr.Fields.DestAddrHi; + + /* Now take out the protocolID field */ + protocolCarriedSwapped.byteValue[0] = 0; + protocolCarriedSwapped.byteValue[1] = IPPacket->ProtocolCarried; + adjustValue -= protocolCarriedSwapped.wordValue; + + IPTotalLength = BYTE_SWAP_WORD(IPPacket->Length); + + /******************************************************************* + * Layer4Length is part of TCP or UDP checksum + *****************************************************************/ + adjustValue -= BYTE_SWAP_WORD(IPTotalLength - (IPPacket->HdrLength * + sizeof(uint32_t))); + + /* adjustValue = BYTE_SWAP_WORD((uint16_t)adjustValue); */ + + /* This is to take out any padding bytes. If we are posting CRC's this + * code will need to change. */ + if ((totalPacketLength - CHKSUM_SIZE - HeaderOffset) != IPTotalLength) { + padWord.byteValue[1] = + *(uint8_t *) (dataFragment + totalPacketLength - CHKSUM_SIZE - + 1); + + padWord.byteValue[0] = 0; + + adjustValue += padWord.wordValue; + } + + adjustValue = CHECK_FOR_CARRY(adjustValue); + + /* Get the Checksum value from the end of the packet */ + hwCheckSum = + *(uint16_t *) (dataFragment + (totalPacketLength - CHKSUM_SIZE)); + + if ((((adjustValue + ~hwCheckSum) & 0x0000FFFF) == 0xFFFF) || + (adjustValue + ~hwCheckSum == 0)) { + + /**************************************************************** + * Set the appropriate status bit to indicate that we performed + * the transport layer protocol checksum and it is valid. + **************************************************************/ + + skb->ip_summed = CHECKSUM_HW; + skb->csum = hwCheckSum; + return B_TRUE; + } else { + /**************************************************************** + * Set the appropriate status bit to indicate that we performed + * the transport layer protocol checksum and it is NOT valid. + **************************************************************/ + skb->ip_summed = CHECKSUM_NONE; + return B_FALSE; + } +} + + +/* + * Procedure: e100_D102_check_checksum + * + * Description: Checks the D102 RFD flags to see if the checksum passed + * + * Arguments: struct sk_buff *skb. Pointer to the packet data + */ +void +e100_D102_check_checksum(bd_config_t *bdp, struct sk_buff *skb) +{ + rfd_t *rfd = RFD_POINTER(skb, bdp->bddp); + uint32_t status = rfd->rfd_header.cb_status; + + if (/* frame parsing succeed */ + (status & RFD_PARSE_BIT) + /* frame recognized as a TCP or UDP frame */ + && (((rfd->rcvparserstatus & CHECKSUM_PROTOCOL_MASK) == RFD_TCP_PACKET) || + ((rfd->rcvparserstatus & CHECKSUM_PROTOCOL_MASK) == RFD_UDP_PACKET)) + /* checksum was calculated */ + && (rfd->checksumstatus & TCPUDP_CHECKSUM_BIT_VALID) + /* and it happens to be valid */ + && (rfd->checksumstatus & TCPUDP_CHECKSUM_VALID)) + + skb->ip_summed = CHECKSUM_UNNECESSARY; + +} + + +/***************************************************************************/ +/***************************************************************************/ +/* /proc File System Interaface Support Functions */ +/***************************************************************************/ + +#ifdef CONFIG_PROC_FS +struct proc_dir_entry *adapters_proc_dir; + +static int generic_read(char *page, char **start, off_t off, int count, int *eof) +{ + int len; + + len = strlen(page); + page[len++] = '\n'; + + if (len <= off + count) + *eof = 1; + *start = page + off; + len -= off; + if (len > count) + len = count; + if (len < 0) + len = 0; + return len; +} + +static int read_ulong(char *page, char **start, off_t off, + int count, int *eof, unsigned long l) +{ + sprintf(page, "%lu", l); + + return generic_read(page, start, off, count, eof); +} + +static int read_ulong_hex(char *page, char **start, off_t off, + int count, int *eof, unsigned long l) +{ + sprintf(page, "0x%04lx", l); + + return generic_read(page, start, off, count, eof); +} + +static int read_hwaddr(char *page, char **start, off_t off, + int count, int *eof, unsigned char *hwaddr) +{ + sprintf(page, "%02X:%02X:%02X:%02X:%02X:%02X", + hwaddr[0], hwaddr[1], hwaddr[2], + hwaddr[3], hwaddr[4], hwaddr[5]); + + return generic_read(page, start, off, count, eof); +} + +/* need to check page boundaries !!! */ +static int read_info(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + bd_config_t *bdp = (bd_config_t *) data; + struct net_device_stats *stats; + unsigned char *hwaddr; + char *pagep = page; + char *msg; + + msg=e100_GetBrandingMesg(bdp); + page += sprintf(page, "%-25s %s\n", DESCRIPTION_TAG, msg); + + page += sprintf(page, "%-25s %s\n", DRVR_NAME_TAG, e100_short_driver_name); + + page += sprintf(page, "%-25s %s\n", DRVR_VERSION_TAG, e100_version); + + page += sprintf(page, "%-25s 0x%04lx\n", + PCI_VENDOR_TAG, (unsigned long) bdp->bddp->ven_id); + page += sprintf(page, "%-25s 0x%04lx\n", + PCI_DEVICE_ID_TAG, (unsigned long) bdp->bddp->dev_id); + page += sprintf(page, "%-25s 0x%04lx\n", + PCI_SUBSYSTEM_VENDOR_TAG, + (unsigned long) bdp->bddp->sub_ven_id); + page += sprintf(page, "%-25s 0x%04lx\n", + PCI_SUBSYSTEM_ID_TAG, + (unsigned long) bdp->bddp->sub_dev_id); + page += sprintf(page, "%-25s 0x%02lx\n", + PCI_REVISION_ID_TAG, + (unsigned long) bdp->bddp->rev_id); + page += sprintf(page, "%-25s %lu\n", + PCI_BUS_TAG, + (unsigned long) (bdp->bddp->pci_dev->bus->number)); + page += sprintf(page, "%-25s %lu\n", + PCI_SLOT_TAG, + (unsigned long)(PCI_SLOT((bdp->bddp->pci_dev->devfn)))); + page += sprintf(page, "%-25s %lu\n", + IRQ_TAG, + (unsigned long)(bdp->irq_level)); + page += sprintf(page, "%-25s %s\n", + SYSTEM_DEVICE_NAME_TAG, bdp->device->name); + + hwaddr = bdp->device->dev_addr; + page += sprintf(page, "%-25s %02X:%02X:%02X:%02X:%02X:%02X\n", + CURRENT_HWADDR_TAG, + hwaddr[0], hwaddr[1], hwaddr[2], + hwaddr[3], hwaddr[4], hwaddr[5]); + + hwaddr = bdp->bddp->perm_node_address; + page += sprintf(page, "%-25s %02X:%02X:%02X:%02X:%02X:%02X\n", + PERMANENT_HWADDR_TAG, + hwaddr[0], hwaddr[1], hwaddr[2], + hwaddr[3], hwaddr[4], hwaddr[5]); + page += sprintf(page, "%-25s %06lx-%03x\n", + PART_NUMBER_TAG, + (ulong_t)(bdp->bddp->pwa_no >>8), + bdp->bddp->pwa_no & 0xFF); + + page += sprintf(page, "\n"); + + e100_phy_check(bdp); + if (bdp->flags & DF_LINK_UP) msg = "up"; + else msg = "down"; + page += sprintf(page, "%-25s %s\n", LINK_TAG, msg); + + e100_FindPhySpeedAndDpx(bdp, bdp->bddp->PhyId); + if (bdp->bddp->cur_line_speed) + page += sprintf(page, "%-25s %lu\n", + SPEED_TAG, + (unsigned long)(bdp->bddp->cur_line_speed)); + else + page += sprintf(page, "%-25s %s\n", SPEED_TAG, "N/A"); + + msg = bdp->bddp->cur_dplx_mode == FULL_DUPLEX ? "full" : + ((bdp->bddp->cur_dplx_mode == NO_DUPLEX) ? "N/A" : "half"); + page += sprintf(page, "%-25s %s\n", DUPLEX_TAG, msg); + + if (bdp->device->flags & IFF_UP) msg = "up"; + else msg = "down"; + page += sprintf(page, "%-25s %s\n", STATE_TAG, msg); + + page += sprintf(page, "\n"); + + stats = e100_get_stats(bdp->device); + page += sprintf(page, "%-25s %lu\n", + RX_PACKETS_TAG, + (unsigned long) stats->rx_packets); + page += sprintf(page, "%-25s %lu\n", + TX_PACKETS_TAG, + (unsigned long) stats->tx_packets); + page += sprintf(page, "%-25s %lu\n", + RX_BYTES_TAG, + (unsigned long) stats->rx_bytes); + page += sprintf(page, "%-25s %lu\n", + TX_BYTES_TAG, + (unsigned long) stats->tx_bytes); + page += sprintf(page, "%-25s %lu\n", + RX_ERRORS_TAG, + (unsigned long) stats->rx_errors); + page += sprintf(page, "%-25s %lu\n", + TX_ERRORS_TAG, + (unsigned long) stats->tx_errors); + page += sprintf(page, "%-25s %lu\n", + RX_DROPPED_TAG, + (unsigned long) stats->rx_dropped); + page += sprintf(page, "%-25s %lu\n", + TX_DROPPED_TAG, + (unsigned long) stats->tx_dropped); + page += sprintf(page, "%-25s %lu\n", + MULTICAST_TAG, + (unsigned long) stats->multicast); + page += sprintf(page, "%-25s %lu\n", + COLLISIONS_TAG, + (unsigned long) stats->collisions); + page += sprintf(page, "%-25s %lu\n", + RX_LENGTH_ERRORS_TAG, + (unsigned long) stats->rx_length_errors); + page += sprintf(page, "%-25s %lu\n", + RX_OVER_ERRORS_TAG, + (unsigned long) stats->rx_over_errors); + page += sprintf(page, "%-25s %lu\n", + RX_CRC_ERRORS_TAG, + (unsigned long) stats->rx_crc_errors); + page += sprintf(page, "%-25s %lu\n", + RX_FRAME_ERRORS_TAG, + (unsigned long) stats->rx_frame_errors); + page += sprintf(page, "%-25s %lu\n", + RX_FIFO_ERRORS_TAG, + (unsigned long) stats->rx_fifo_errors); + page += sprintf(page, "%-25s %lu\n", + RX_MISSED_ERRORS_TAG, + (unsigned long) stats->rx_missed_errors); + page += sprintf(page, "%-25s %lu\n", + TX_ABORTED_ERRORS_TAG, + (unsigned long) stats->tx_aborted_errors); + page += sprintf(page, "%-25s %lu\n", + TX_CARRIER_ERRORS_TAG, + (unsigned long) stats->tx_carrier_errors); + page += sprintf(page, "%-25s %lu\n", + TX_FIFO_ERRORS_TAG, + (unsigned long) stats->tx_fifo_errors); + page += sprintf(page, "%-25s %lu\n", + TX_HEARTBEAT_ERRORS_TAG, + (unsigned long)0); /* !!! */ + page += sprintf(page, "%-25s %lu\n", + TX_WINDOW_ERRORS_TAG, + (unsigned long)0); /* !!! */ + + page += sprintf(page, "\n"); + + page += sprintf(page, "%-25s %lu\n", + RX_TCP_CHECKSUM_GOOD_TAG, + (unsigned long)0); /* !!! */ + page += sprintf(page, "%-25s %lu\n", + RX_TCP_CHECKSUM_BAD_TAG, + (unsigned long)0); /* !!! */ + page += sprintf(page, "%-25s %lu\n", + TX_TCP_CHECKSUM_GOOD_TAG, + (unsigned long)0); /* !!! */ + page += sprintf(page, "%-25s %lu\n", + TX_TCP_CHECKSUM_BAD_TAG, + (unsigned long)0); /* !!! */ + + page += sprintf(page, "\n"); + page += sprintf(page, "%-25s %lu\n", + TX_ABORT_LATE_COLL_TAG, + (unsigned long)bdp->bddp->perr_stats->tx_late_col); + page += sprintf(page, "%-25s %lu\n", + TX_DEFERRED_OK_TAG, + (unsigned long)bdp->bddp->perr_stats->tx_ok_defrd); + page += sprintf(page, "%-25s %lu\n", + TX_SINGLE_COLL_OK_TAG, + (unsigned long)bdp->bddp->perr_stats->tx_one_retry); + page += sprintf(page, "%-25s %lu\n", + TX_MULTI_COLL_OK_TAG, + (unsigned long)bdp->bddp->perr_stats->tx_mt_one_retry); + page += sprintf(page, "%-25s %lu\n", + RX_LONG_LENGTH_ERRORS_TAG, + (unsigned long)0); + page += sprintf(page, "%-25s %lu\n", + RX_ALIGN_ERRORS_TAG, + (unsigned long)bdp->bddp->perr_stats->rcv_align_err); + + *page = 0; + return generic_read(pagep, start, off, count, eof); +} + +static int read_descr(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + bd_config_t *bdp = (bd_config_t *) data; + char *msg; + + msg=e100_GetBrandingMesg(bdp); + strncpy(page, msg, PAGE_SIZE); + + return generic_read(page, start, off, count, eof); +} + +static int read_drvr_name(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + strncpy(page, e100_short_driver_name, PAGE_SIZE); + + return generic_read(page, start, off, count, eof); +} + +static int read_drvr_ver(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + strncpy(page, e100_version, PAGE_SIZE); + + return generic_read(page, start, off, count, eof); +} + +static int read_pci_vendor(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + bd_config_t *bdp = (bd_config_t *) data; + + return read_ulong_hex(page, start, off, count, eof, + (unsigned long) bdp->bddp->ven_id); +} + +static int read_pci_device(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + bd_config_t *bdp = (bd_config_t *) data; + + return read_ulong_hex(page, start, off, count, eof, + (unsigned long) bdp->bddp->dev_id); +} + +static int read_pci_sub_vendor(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + bd_config_t *bdp = (bd_config_t *) data; + + return read_ulong_hex(page, start, off, count, eof, + (unsigned long) bdp->bddp->sub_ven_id); +} + +static int read_pci_sub_device(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + bd_config_t *bdp = (bd_config_t *) data; + + return read_ulong_hex(page, start, off, count, eof, + (unsigned long) bdp->bddp->sub_dev_id); +} + +static int read_pci_revision(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + bd_config_t *bdp = (bd_config_t *) data; + + return read_ulong_hex(page, start, off, count, eof, + (unsigned long) bdp->bddp->rev_id); +} + +static int read_dev_name(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + bd_config_t *bdp = (bd_config_t *) data; + + strncpy(page, bdp->device->name, PAGE_SIZE); + + return generic_read(page, start, off, count, eof); +} + +static int read_pci_bus(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + bd_config_t *bdp = (bd_config_t *) data; + + return read_ulong(page, start, off, count, eof, + (unsigned long) (bdp->bddp->pci_dev->bus->number)); +} + +static int read_pci_slot(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + bd_config_t *bdp = (bd_config_t *) data; + + return read_ulong(page, start, off, count, eof, + (unsigned long)(PCI_SLOT((bdp->bddp->pci_dev->devfn)))); +} + +static int read_irq(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + bd_config_t *bdp = (bd_config_t *) data; + + return read_ulong(page, start, off, count, eof, + (unsigned long)(bdp->irq_level)); +} + +static int read_current_hwaddr(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + bd_config_t *bdp = (bd_config_t *) data; + unsigned char *hwaddr = bdp->device->dev_addr; + + return read_hwaddr(page, start, off, count, eof, hwaddr); +} + +static int read_permanent_hwaddr(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + bd_config_t *bdp = (bd_config_t *) data; + unsigned char *hwaddr = bdp->bddp->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) +{ + bd_config_t *bdp = (bd_config_t *) data; + sprintf(page, "%06lx-%03x\n", + (ulong_t)(bdp->bddp->pwa_no >>8), + bdp->bddp->pwa_no & 0xFF); + return generic_read(page, start, off, count, eof); +} + +static int read_link_status(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + bd_config_t *bdp = (bd_config_t *) data; + + e100_phy_check(bdp); + if (bdp->flags & DF_LINK_UP) + strncpy(page, "up", PAGE_SIZE); + else + strncpy(page, "down", PAGE_SIZE); + + return generic_read(page, start, off, count, eof); +} + +static int read_speed(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + bd_config_t *bdp = (bd_config_t *) data; + + e100_FindPhySpeedAndDpx(bdp, bdp->bddp->PhyId); + if (bdp->bddp->cur_line_speed) + return read_ulong(page, start, off, count, eof, + (unsigned long) (bdp->bddp->cur_line_speed)); + strncpy(page, "N/A", PAGE_SIZE); + return generic_read(page, start, off, count, eof); +} + +static int read_dplx_mode(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + bd_config_t *bdp = (bd_config_t *) data; + char *dplx_mode; + + e100_FindPhySpeedAndDpx(bdp, bdp->bddp->PhyId); + dplx_mode = bdp->bddp->cur_dplx_mode == FULL_DUPLEX ? "full" : + ((bdp->bddp->cur_dplx_mode == NO_DUPLEX) ? "N/A" : "half"); + strncpy(page, dplx_mode, PAGE_SIZE); + + return generic_read(page, start, off, count, eof); +} + +static int read_state(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + bd_config_t *bdp = (bd_config_t *) data; + + if (bdp->device->flags & IFF_UP) + strncpy(page, "up", PAGE_SIZE); + else + strncpy(page, "down", PAGE_SIZE); + + return generic_read(page, start, off, count, eof); +} + +static int read_rx_packets(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + bd_config_t *bdp = (bd_config_t *) data; + + return read_ulong(page, start, off, count, eof, + (unsigned long) bdp->bddp->perr_stats->gd_recvs); +} + +static int read_tx_packets(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + bd_config_t *bdp = (bd_config_t *) data; + + return read_ulong(page, start, off, count, eof, + (unsigned long) bdp->bddp->perr_stats->gd_xmits); +} + +static int read_rx_bytes(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + bd_config_t *bdp = (bd_config_t *) data; + + return read_ulong(page, start, off, count, eof, + (unsigned long) bdp->bddp->net_stats.rx_bytes); +} + +static int read_tx_bytes(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + bd_config_t *bdp = (bd_config_t *) data; + + return read_ulong(page, start, off, count, eof, + (unsigned long) bdp->bddp->net_stats.tx_bytes); +} + +static int read_rx_errors(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + bd_config_t *bdp = (bd_config_t *) data; + + e100_get_stats(bdp->device); + return read_ulong(page, start, off, count, eof, + (unsigned long) bdp->bddp->net_stats.rx_errors); +} + +static int read_tx_errors(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + bd_config_t *bdp = (bd_config_t *) data; + + e100_get_stats(bdp->device); + return read_ulong(page, start, off, count, eof, + (unsigned long) bdp->bddp->net_stats.tx_errors); +} + +static int read_rx_dropped(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + bd_config_t *bdp = (bd_config_t *) data; + + return read_ulong(page, start, off, count, eof, + (unsigned long) bdp->bddp->perr_stats->rcv_rsrc_err); +} + +static int read_tx_dropped(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + bd_config_t *bdp = (bd_config_t *) data; + + return read_ulong(page, start, off, count, eof, + (unsigned long) bdp->bddp->net_stats.tx_dropped); +} + +static int read_rx_multicast_packets(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + bd_config_t *bdp = (bd_config_t *) data; + + return read_ulong(page, start, off, count, eof, + (unsigned long) bdp->bddp->net_stats.multicast); +} + +static int read_collisions(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + bd_config_t *bdp = (bd_config_t *) data; + + return read_ulong(page, start, off, count, eof, + (unsigned long)bdp->bddp->perr_stats->tx_tot_retries); +} + +static int read_rx_length_errors(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + bd_config_t *bdp = (bd_config_t *) data; + + return read_ulong(page, start, off, count, eof, + (unsigned long) bdp->bddp->perr_stats->rcv_runts); +} + +static int read_rx_over_errors(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + bd_config_t *bdp = (bd_config_t *) data; + + return read_ulong(page, start, off, count, eof, + (unsigned long) bdp->bddp->perr_stats->rcv_rsrc_err); +} + +static int read_rx_crc_errors(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + bd_config_t *bdp = (bd_config_t *) data; + + return read_ulong(page, start, off, count, eof, + (unsigned long) bdp->bddp->perr_stats->rcv_crc_err); +} + +static int read_rx_frame_errors(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + bd_config_t *bdp = (bd_config_t *) data; + + return read_ulong(page, start, off, count, eof, + (unsigned long)bdp->bddp->perr_stats->rcv_align_err); +} + +static int read_rx_fifo_errors(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + bd_config_t *bdp = (bd_config_t *) data; + + return read_ulong(page, start, off, count, eof, + (unsigned long)bdp->bddp->perr_stats->rcv_dma_orun); +} + +static int read_rx_missed_errors(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + bd_config_t *bdp = (bd_config_t *) data; + + return read_ulong(page, start, off, count, eof, + (unsigned long)bdp->bddp->net_stats.rx_missed_errors); +} + +static int read_tx_aborted_errors(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + bd_config_t *bdp = (bd_config_t *) data; + + return read_ulong(page, start, off, count, eof, + (unsigned long)bdp->bddp->perr_stats->tx_abrt_xs_col); +} + +static int read_tx_carrier_errors(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + bd_config_t *bdp = (bd_config_t *) data; + + return read_ulong(page, start, off, count, eof, + (unsigned long)bdp->bddp->perr_stats->tx_lost_csrs); +} + +static int read_tx_fifo_errors(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + bd_config_t *bdp = (bd_config_t *) data; + + return read_ulong(page, start, off, count, eof, + (unsigned long)bdp->bddp->perr_stats->tx_dma_urun); +} + +static int read_tx_heartbeat_errors(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + return read_ulong(page, start, off, count, eof, + (unsigned long)0); +} + +static int read_tx_window_errors(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + return read_ulong(page, start, off, count, eof, + (unsigned long)0); +} + +static int read_rx_tcp_checksum_good(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + return read_ulong(page, start, off, count, eof, + (unsigned long)0); +} + +static int read_rx_tcp_checksum_bad(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + return read_ulong(page, start, off, count, eof, + (unsigned long)0); +} + +static int read_tx_tcp_checksum_good(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + return read_ulong(page, start, off, count, eof, + (unsigned long)0); +} + +static int read_tx_tcp_checksum_bad(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + return read_ulong(page, start, off, count, eof, + (unsigned long)0); +} + + +static int read_tx_abort_late_coll(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + bd_config_t *bdp = (bd_config_t *) data; + + return read_ulong(page, start, off, count, eof, + (unsigned long)bdp->bddp->perr_stats->tx_late_col); +} + +static int read_tx_deferred_ok(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + bd_config_t *bdp = (bd_config_t *) data; + + return read_ulong(page, start, off, count, eof, + (unsigned long)bdp->bddp->perr_stats->tx_ok_defrd); +} + +static int read_tx_single_coll_ok(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + bd_config_t *bdp = (bd_config_t *) data; + + return read_ulong(page, start, off, count, eof, + (unsigned long)bdp->bddp->perr_stats->tx_one_retry); +} + +static int read_tx_multi_coll_ok(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + bd_config_t *bdp = (bd_config_t *) data; + + return read_ulong(page, start, off, count, eof, + (unsigned long)bdp->bddp->perr_stats->tx_mt_one_retry); +} + + +static int read_rx_allign_errors(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + bd_config_t *bdp = (bd_config_t *) data; + + return read_ulong(page, start, off, count, eof, + (unsigned long)bdp->bddp->perr_stats->rcv_align_err); +} + + +static int read_rx_long_length_errors(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + return read_ulong(page, start, off, count, eof, + (unsigned long)0); +} + +#if (DEBUG_LINK > 0) +static int read_link_errors(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + bd_config_t *bdp = (bd_config_t *) data; + + return read_ulong(page, start, off, count, eof, + (unsigned long) bdp->ErrorCounter); +} +#endif + +static struct proc_dir_entry *create_proc_read(char *name, + bd_config_t *bdp, + struct proc_dir_entry *parent, + read_proc_t *read_proc) +{ + struct proc_dir_entry *pdep; + + if (!(pdep = create_proc_entry(name, S_IFREG, parent))) + return NULL; + pdep->read_proc = read_proc; + pdep->data = bdp; + return pdep; +} + +static int create_e100_proc_subdir(bd_config_t *bdp) +{ + struct proc_dir_entry *dev_dir; + char info[256]; + int len; + + dev_dir = create_proc_entry(bdp->device->name, S_IFDIR, adapters_proc_dir); + + strncpy(info, bdp->device->name, sizeof(info)); + len = strlen(info); + strncat(info + len, ".info", sizeof(info) - len); + + /* info */ + if (!(create_proc_read(info, bdp, adapters_proc_dir, read_info))) + return -1; + + /* description */ + if (!(create_proc_read(DESCRIPTION_TAG, bdp, dev_dir, read_descr))) + return -1; + /* driver name */ + if (!(create_proc_read(DRVR_NAME_TAG, bdp, dev_dir, read_drvr_name))) + return -1; + /* driver version */ + if (!(create_proc_read(DRVR_VERSION_TAG, bdp, dev_dir, + read_drvr_ver))) + return -1; + /* pci vendor */ + if (!(create_proc_read(PCI_VENDOR_TAG, bdp, dev_dir, + read_pci_vendor))) + return -1; + /* pci device id */ + if (!(create_proc_read(PCI_DEVICE_ID_TAG, bdp, dev_dir, + read_pci_device))) + return -1; + /* pci sub vendor */ + if (!(create_proc_read(PCI_SUBSYSTEM_VENDOR_TAG, bdp, dev_dir, + read_pci_sub_vendor))) + return -1; + /* pci sub device id */ + if (!(create_proc_read(PCI_SUBSYSTEM_ID_TAG, bdp, dev_dir, + read_pci_sub_device))) + return -1; + /* pci revision id */ + if (!(create_proc_read(PCI_REVISION_ID_TAG, bdp, dev_dir, + read_pci_revision))) + return -1; + /* device name */ + if (!(create_proc_read(SYSTEM_DEVICE_NAME_TAG, bdp, dev_dir, + read_dev_name))) + return -1; + /* pci bus */ + if (!(create_proc_read(PCI_BUS_TAG, bdp, dev_dir, read_pci_bus))) + return -1; + /* pci slot */ + if (!(create_proc_read(PCI_SLOT_TAG, bdp, + dev_dir, read_pci_slot))) + return -1; + /* irq */ + if (!(create_proc_read(IRQ_TAG, bdp, dev_dir, read_irq))) + return -1; + /* current hwaddr */ + if (!(create_proc_read(CURRENT_HWADDR_TAG, bdp, dev_dir, + read_current_hwaddr))) + return -1; + /* permanent hwaddr */ + if (!(create_proc_read(PERMANENT_HWADDR_TAG, bdp, dev_dir, + read_permanent_hwaddr))) + return -1; + /* part number */ + if (!(create_proc_read(PART_NUMBER_TAG, bdp, dev_dir, + read_part_number))) + return -1; + + /* link status */ + if (!(create_proc_read(LINK_TAG, bdp, dev_dir, read_link_status))) + return -1; + /* speed */ + if (!(create_proc_read(SPEED_TAG, bdp, dev_dir, read_speed))) + return -1; + /* duplex mode */ + if (!(create_proc_read(DUPLEX_TAG, bdp, dev_dir, read_dplx_mode))) + return -1; + /* state */ + if (!(create_proc_read(STATE_TAG, bdp, dev_dir, read_state))) + return 1; + + /* rx packets */ + if (!(create_proc_read(RX_PACKETS_TAG, bdp, dev_dir, read_rx_packets))) + return 1; + /* tx packets */ + if (!(create_proc_read(TX_PACKETS_TAG, bdp, dev_dir, read_tx_packets))) + return 1; + /* rx bytes */ + if (!(create_proc_read(RX_BYTES_TAG, bdp, dev_dir, read_rx_bytes))) + return 1; + /* tx bytes */ + if (!(create_proc_read(TX_BYTES_TAG, bdp, dev_dir, read_tx_bytes))) + return 1; + /* rx errors */ + if (!(create_proc_read(RX_ERRORS_TAG, bdp, dev_dir, read_rx_errors))) + return 1; + /* tx errors */ + if (!(create_proc_read(TX_ERRORS_TAG, bdp, dev_dir, read_tx_errors))) + return 1; + /* rx dropped */ + if (!(create_proc_read(RX_DROPPED_TAG, bdp, dev_dir, read_rx_dropped))) + return 1; + /* tx dropped */ + if (!(create_proc_read(TX_DROPPED_TAG, bdp, dev_dir, read_tx_dropped))) + return 1; + /* multicast packets */ + if (!(create_proc_read(MULTICAST_TAG, bdp, dev_dir, + read_rx_multicast_packets))) + return 1; + /* collisions */ + if (!(create_proc_read(COLLISIONS_TAG, bdp, dev_dir, read_collisions))) + return 1; + /* rx length errors */ + if (!(create_proc_read(RX_LENGTH_ERRORS_TAG, bdp, dev_dir, + read_rx_length_errors))) + return 1; + /* rx over errors */ + if (!(create_proc_read(RX_OVER_ERRORS_TAG, bdp, dev_dir, + read_rx_over_errors))) + return 1; + /* rx crc errors */ + if (!(create_proc_read(RX_CRC_ERRORS_TAG, bdp, dev_dir, + read_rx_crc_errors))) + return 1; + /* rx frame errors */ + if (!(create_proc_read(RX_FRAME_ERRORS_TAG, bdp, dev_dir, + read_rx_frame_errors))) + return 1; + /* rx fifo errors */ + if (!(create_proc_read(RX_FIFO_ERRORS_TAG, bdp, dev_dir, + read_rx_fifo_errors))) + return 1; + /* rx missed errors */ + if (!(create_proc_read(RX_MISSED_ERRORS_TAG, bdp, dev_dir, + read_rx_missed_errors))) + return 1; + /* tx aborted errors */ + if (!(create_proc_read(TX_ABORTED_ERRORS_TAG, bdp, dev_dir, + read_tx_aborted_errors))) + return 1; + /* tx carrier errors */ + if (!(create_proc_read(TX_CARRIER_ERRORS_TAG, bdp, dev_dir, + read_tx_carrier_errors))) + return 1; + /* tx fifo errors */ + if (!(create_proc_read(TX_FIFO_ERRORS_TAG, bdp, dev_dir, + read_tx_fifo_errors))) + return 1; + /* tx heartbeat errors */ + if (!(create_proc_read(TX_HEARTBEAT_ERRORS_TAG, bdp, dev_dir, + read_tx_heartbeat_errors))) + return 1; + /* tx window errors */ + if (!(create_proc_read(TX_WINDOW_ERRORS_TAG, bdp, dev_dir, + read_tx_window_errors))) + return 1; + + /* rx tcp checksum good */ + if (!(create_proc_read(RX_TCP_CHECKSUM_GOOD_TAG, bdp, dev_dir, + read_rx_tcp_checksum_good))) + return 1; + /* rx tcp checksum bad */ + if (!(create_proc_read(RX_TCP_CHECKSUM_BAD_TAG, bdp, dev_dir, + read_rx_tcp_checksum_bad))) + return 1; + /* tx tcp checksum good */ + if (!(create_proc_read(TX_TCP_CHECKSUM_GOOD_TAG, bdp, dev_dir, + read_tx_tcp_checksum_good))) + return 1; + /* tx tcp checksum bad */ + if (!(create_proc_read(TX_TCP_CHECKSUM_BAD_TAG, bdp, dev_dir, + read_tx_tcp_checksum_bad))) + return 1; + + /* */ + if (!(create_proc_read(TX_ABORT_LATE_COLL_TAG, bdp, dev_dir, + read_tx_abort_late_coll))) + return 1; + /* */ + if (!(create_proc_read(TX_DEFERRED_OK_TAG, bdp, dev_dir, + read_tx_deferred_ok))) + return 1; + /* */ + if (!(create_proc_read(TX_SINGLE_COLL_OK_TAG, bdp, dev_dir, + read_tx_single_coll_ok))) + return 1; + /* */ + if (!(create_proc_read(TX_MULTI_COLL_OK_TAG, bdp, dev_dir, + read_tx_multi_coll_ok))) + return 1; + /* */ + if (!(create_proc_read(RX_LONG_LENGTH_ERRORS_TAG, bdp, dev_dir, + read_rx_long_length_errors))) + return 1; + /* */ + if (!(create_proc_read(RX_ALIGN_ERRORS_TAG, bdp, dev_dir, + read_rx_allign_errors))) + return 1; + /* */ +#if (DEBUG_LINK > 0) + if (!(create_proc_read("Link_Errors", bdp, dev_dir, + read_link_errors))) + return 1; +#endif + + return 0; +} + +static void remove_e100_proc_subdir(device_t *dev) +{ + struct proc_dir_entry *de; + char info[256]; + int len; + + len = strlen(dev->name); + strncpy(info, dev->name, sizeof(info)); + strncat(info + len, ".info", sizeof(info) - len); + + for (de = adapters_proc_dir->subdir; de; de = de->next) { + if ((de->namelen == len) && (!memcmp(de->name, dev->name, len))) + break; + } + + if (de) { + remove_proc_entry(DESCRIPTION_TAG, de); + remove_proc_entry(DRVR_NAME_TAG, de); + remove_proc_entry(DRVR_VERSION_TAG, de); + remove_proc_entry(PCI_VENDOR_TAG, de); + remove_proc_entry(PCI_DEVICE_ID_TAG, de); + remove_proc_entry(PCI_SUBSYSTEM_VENDOR_TAG, de); + remove_proc_entry(PCI_SUBSYSTEM_ID_TAG, de); + remove_proc_entry(PCI_REVISION_ID_TAG, de); + remove_proc_entry(SYSTEM_DEVICE_NAME_TAG, de); + remove_proc_entry(PCI_BUS_TAG, de); + remove_proc_entry(PCI_SLOT_TAG, de); + remove_proc_entry(IRQ_TAG, de); + remove_proc_entry(CURRENT_HWADDR_TAG, de); + remove_proc_entry(PERMANENT_HWADDR_TAG, de); + remove_proc_entry(PART_NUMBER_TAG, de); + + remove_proc_entry(LINK_TAG, de); + remove_proc_entry(SPEED_TAG, de); + remove_proc_entry(DUPLEX_TAG, de); + remove_proc_entry(STATE_TAG, de); + + remove_proc_entry(RX_PACKETS_TAG, de); + remove_proc_entry(TX_PACKETS_TAG, de); + remove_proc_entry(RX_BYTES_TAG, de); + remove_proc_entry(TX_BYTES_TAG, de); + remove_proc_entry(RX_ERRORS_TAG, de); + remove_proc_entry(TX_ERRORS_TAG, de); + remove_proc_entry(RX_DROPPED_TAG, de); + remove_proc_entry(TX_DROPPED_TAG, de); + remove_proc_entry(MULTICAST_TAG, de); + remove_proc_entry(COLLISIONS_TAG, de); + remove_proc_entry(RX_LENGTH_ERRORS_TAG, de); + remove_proc_entry(RX_OVER_ERRORS_TAG, de); + remove_proc_entry(RX_CRC_ERRORS_TAG, de); + remove_proc_entry(RX_FRAME_ERRORS_TAG, de); + remove_proc_entry(RX_FIFO_ERRORS_TAG, de); + remove_proc_entry(RX_MISSED_ERRORS_TAG, de); + remove_proc_entry(TX_ABORTED_ERRORS_TAG, de); + remove_proc_entry(TX_CARRIER_ERRORS_TAG, de); + remove_proc_entry(TX_FIFO_ERRORS_TAG, de); + remove_proc_entry(TX_HEARTBEAT_ERRORS_TAG, de); + remove_proc_entry(TX_WINDOW_ERRORS_TAG, de); + + remove_proc_entry(RX_TCP_CHECKSUM_GOOD_TAG, de); + remove_proc_entry(RX_TCP_CHECKSUM_BAD_TAG, de); + remove_proc_entry(TX_TCP_CHECKSUM_GOOD_TAG, de); + remove_proc_entry(TX_TCP_CHECKSUM_BAD_TAG, de); + + remove_proc_entry(TX_ABORT_LATE_COLL_TAG, de); + remove_proc_entry(TX_DEFERRED_OK_TAG, de); + remove_proc_entry(TX_SINGLE_COLL_OK_TAG, de); + remove_proc_entry(TX_MULTI_COLL_OK_TAG, de); + remove_proc_entry(RX_LONG_LENGTH_ERRORS_TAG,de); + remove_proc_entry(RX_ALIGN_ERRORS_TAG,de); +#if (DEBUG_LINK > 0) + remove_proc_entry("Link_Errors",de); +#endif + + } + remove_proc_entry(info, adapters_proc_dir); + remove_proc_entry(dev->name, adapters_proc_dir); +} +#endif + + +/***************************************************************************/ +/***************************************************************************/ +/* Functions for the 82562EH Home Phoneline Network Connection */ +/***************************************************************************/ + +/**************************************************************************** + * Name: Phy82562EHNoiseFloorWrite + * + * Description: Writes input parameter values to 82562EH's NSE_FLOOR/ + * CEILING register. + * + * Arguments: + * bddp - pointer to the bddp object. + * Value - the value to be written. + * + * Returns: Nothing + ***************************************************************************/ +void +Phy82562EHNoiseFloorWrite(bdd_t *bddp, uint8_t Value) +{ + e100_MdiWrite(bddp->bdp, PHY_82562EH_NSE_FLOOR_CEILING_REG, + bddp->phy_addr, (uint16_t)(Value | 0xd000)); +} + + +/**************************************************************************** + * Name: Phy82562EHNoiseCounterClear + * + * Description: Clears NSE_EVENTS bit of CONTROL register. + * + * Arguments: bddp - pointer to the bddp object. + * + * Returns: Nothing + ***************************************************************************/ +void +Phy82562EHNoiseCounterClear(bdd_t *bddp) +{ + uint16_t RegVal; + + e100_MdiRead(bddp->bdp, PHY_82562EH_CONTROL_REG, bddp->phy_addr, &RegVal); + RegVal |= 0x0040; + e100_MdiWrite(bddp->bdp, PHY_82562EH_CONTROL_REG, bddp->phy_addr, RegVal); +} + +/**************************************************************************** + * Name: Phy82562EHNoiseEventsRead + * + * Description: This routine will read 82562EH NSE_ATTACK/EVENT register. + * + * Arguments: bddp - pointer to the bddp object. + * + * Returns: uint8_t value from NSE_ATTACK/EVENT register + ***************************************************************************/ +uint8_t +Phy82562EHNoiseEventsRead(bdd_t *bddp) +{ + uint16_t RegVal; + + e100_MdiRead(bddp->bdp, PHY_82562EH_NSE_ATTACK_EVENT_REG, + bddp->phy_addr, &RegVal); + return (uint8_t)(RegVal >> 8); +} + + +/**************************************************************************** + * Name: Phy82562EHDelayMilliseconds + * + * Description: Stalls execution for a specified number of milliseconds. + * + * Arguments: Time - milliseconds to delay + * + * Returns: Nothing + ***************************************************************************/ +void +Phy82562EHDelayMilliseconds(int Time) +{ + udelay(Time); +} + + +/**************************************************************************** + * Name: Phy82562EHNoiseEventsWithDelayCount + * + * Description: + * + * Arguments: + * bddp - pointer to the bddp object. + * NoiseFloor - + * Delay - + * + * Returns: Nothing + ***************************************************************************/ +uint8_t +Phy82562EHNoiseEventsWithDelayCount(bdd_t *bddp, uint8_t NoiseFloor, int32_t Delay) +{ + Phy82562EHNoiseFloorWrite(bddp, NoiseFloor); + Phy82562EHNoiseCounterClear(bddp); + Phy82562EHDelayMilliseconds(Delay); + return Phy82562EHNoiseEventsRead(bddp); +} + + +/**************************************************************************** + * Name: Phy82562EHMedianFind + * + * Description: + * + * Arguments: bddp - pointer to the bddp object. + * + * Returns: uint8_t value of + ***************************************************************************/ +uint8_t +Phy82562EHMedianFind(bdd_t *bddp) +{ + + if(Phy82562EHNoiseEventsWithDelayCount(bddp, 0x10, 90) > 0) { + if(Phy82562EHNoiseEventsWithDelayCount(bddp, 0x18, 60) > 0) { + if(Phy82562EHNoiseEventsWithDelayCount(bddp, 0x1c, 30) > 0) { + return 0x1d; + } else { + return 0x19; + } + } else { + if(Phy82562EHNoiseEventsWithDelayCount(bddp, 0x14, 30) > 0) { + return 0x15; + } else { + return 0x11; + } + } + } else { + if(Phy82562EHNoiseEventsWithDelayCount(bddp, 0x08, 60) > 0) { + if(Phy82562EHNoiseEventsWithDelayCount(bddp, 0x0c, 30) > 0) { + return 0x0d; + } else { + return 0x09; + } + } else { + if(Phy82562EHNoiseEventsWithDelayCount(bddp, 0x04, 30) > 0) { + return 0x05; + } else { + return 0x02; + } + } + } +} + + +/**************************************************************************** + * Name: Phy82562EHAddressSpaceSwitch + * + * Description: Switches 82562EH address space page 1/0 based on Page parameter. + * + * Arguments: bddp - pointer to the bddp object. + * + * Returns: Nothing + ***************************************************************************/ +void +Phy82562EHAddressSpaceSwitch(bdd_t *bddp, int32_t Page) +{ + uint16_t RegVal; + + /* Switch to 82562EH address space page 1/0 by writing to RAP bit (Bit 0 ) + * in Control register (Address 10 Hex) 1/0. */ + e100_MdiRead(bddp->bdp, PHY_82562EH_CONTROL_REG, bddp->phy_addr, &RegVal); + RegVal = (Page ? (RegVal | PHY_82562EH_CR_RAP) : (RegVal & ~(PHY_82562EH_CR_RAP))); + e100_MdiWrite(bddp->bdp, PHY_82562EH_CONTROL_REG, bddp->phy_addr, RegVal); +} + + +/**************************************************************************** + * Name: Phy82562EHRegisterInit + * + * Description: Performs 82562EH PHY register initialization. + * + * Arguments: bddp - pointer to the bddp object. + * + * Returns: Nothing + ***************************************************************************/ +void +Phy82562EHRegisterInit(bdd_t *bddp) +{ + /* 82562EH CSR initialization value. + * + * This are the csrs value recommended for 82562EH regardless the W/A. + * + * A0 value A1 value + * 0 0x1B - RX_CONTROL 0x0009 0x0008 + * 0 0x11 - STATUS_AND_MODE not set 0x0100 + * 0 0x19 - NSE_FLOOR/CEILING 0xD010 not set + * 1 0x12 - AFE_CONTROL1 0xA6A0 0x6600 + * 1 0x13 - AFE_CONTROL2 0x0100 0x0100 + */ + + Phy82562EHAddressSpaceSwitch(bddp, PHY_82562EH_ADDR_SPACE_PAGE_0) ; + e100_MdiWrite(bddp->bdp, PHY_82562EH_STATUS_MODE_REG, bddp->phy_addr, 0x0100); + e100_MdiWrite(bddp->bdp, PHY_82562EH_RX_CONTROL_REG, bddp->phy_addr, 0x0008); + + Phy82562EHAddressSpaceSwitch(bddp, PHY_82562EH_ADDR_SPACE_PAGE_1) ; + e100_MdiWrite(bddp->bdp, PHY_82562EH_AFE_CONTROL1_REG, bddp->phy_addr, 0x6600); + e100_MdiWrite(bddp->bdp, PHY_82562EH_AFE_CONTROL2_REG, bddp->phy_addr, 0x0100); +} + + +/**************************************************************************** + * Name: Phy82562EHNoiseFloorCalculate + * + * Description: Performs 82562EH PHY noise calculations + * + * Arguments: bddp - pointer to the bddp object. + * + * Returns: Nothing + ***************************************************************************/ +void +Phy82562EHNoiseFloorCalculate(bdd_t *bddp) +{ + uint16_t Samples[PHY_82562EH_MAX_TABLE]; + uint16_t RegVal; + uint16_t MaxVal; + uint8_t NoiseFloor; + boolean_t Stable; + int Index; + + /* + 1. Set the mode for initialization: + a. Move to page 1 by setting RAP bit (bit 0) in the Control Register + (address 10H) to value of 1. + b. Write AFE_CONTROL1 register (address 12H) to value A600 + c. Write AFE_CONTROL2 register (address 13H) to value 0900 + d. Move to page 0 by resetting RAP bit (bit 0) in the Control Register + (address 10H) to value of 0 + e. Write RX_CONTROL register (address 1BH) to value 0008 + f. Write STATUS_MODE register (address 11H) to value 0100 + g. Write NSE_EVENTS/ATTACK register (address 0x1A) to value 0022 + h. Write NOISE/PEACK register (address 0x18) to value 7F00 + */ + + Phy82562EHAddressSpaceSwitch(bddp, PHY_82562EH_ADDR_SPACE_PAGE_1); + + e100_MdiWrite(bddp->bdp, PHY_82562EH_AFE_CONTROL1_REG, bddp->phy_addr, + PHY_82562EH_AFE_CR1_WA_INIT); + e100_MdiWrite(bddp->bdp, PHY_82562EH_AFE_CONTROL2_REG, bddp->phy_addr, + PHY_82562EH_AFE_CR2_WA_INIT); + + Phy82562EHAddressSpaceSwitch(bddp, PHY_82562EH_ADDR_SPACE_PAGE_0); + + e100_MdiWrite(bddp->bdp, PHY_82562EH_RX_CONTROL_REG, bddp->phy_addr, + PHY_82562EH_RX_CR_WA_INIT); + e100_MdiWrite(bddp->bdp, PHY_82562EH_STATUS_MODE_REG, bddp->phy_addr, + PHY_82562EH_STATUS_MODE_WA_INIT); + e100_MdiWrite(bddp->bdp, PHY_82562EH_NSE_ATTACK_EVENT_REG, bddp->phy_addr, + PHY_82562EH_NSE_ATTACK_EVENT_WA_INIT); + e100_MdiWrite(bddp->bdp, PHY_82562EH_NOISE_PEAK_LVL_REG, bddp->phy_addr, + PHY_82562EH_NOISE_PEAK_LVL_WA_INIT); + + Phy82562EHDelayMilliseconds(1); + + /* Find and write an appropriate noise floor value */ + NoiseFloor = Phy82562EHMedianFind(bddp); + Phy82562EHNoiseFloorWrite(bddp, NoiseFloor); + + /* Perform X readings of noise register with Y msec delay between */ + for(Index=0; Index < bddp->Phy82562EHSampleCount; Index++) { + e100_MdiRead(bddp->bdp, PHY_82562EH_NOISE_PEAK_LVL_REG, bddp->phy_addr, &Samples[Index]); + Phy82562EHDelayMilliseconds(bddp->Phy82562EHSampleDelay); + } + + /* Find maximum and check for stability */ + MaxVal = 0; + Stable = TRUE; + for(Index=0; Index < bddp->Phy82562EHSampleCount; Index++) { + if(Samples[Index] > MaxVal) { + MaxVal = Samples[Index]; + } + if(Samples[Index] != Samples[0]) { + Stable = FALSE; + } + } + + RegVal = MaxVal; + + if( !Stable || (NoiseFloor == 0x02) ) { + RegVal += bddp->Phy82562EHSampleFilter; + } + + /* Set the normal operation mode: + * + * a. Write NSE_EVENTS/ATTACK register (address 0x1A) to value FFF4 + * b. Move to page 1 by setting RAP bit (bit 0) in the CONTROL register + * (address 10H). + * c. Write AFE_CONTROL1 register (address 12H) to value 6600 + * d. Write AFE_CONTROL2 register (address 13H) to value 0100 + * e. Move to page 0 by resetting RAP bit (bit 0) in the CONTROL register + * (address 10H) to value of 0 + */ + + /* Write final noise floor */ + NoiseFloor = (uint8_t)(RegVal & 0x00FF); + Phy82562EHNoiseFloorWrite(bddp, NoiseFloor); + + /* Restore to normal working values */ + e100_MdiWrite(bddp->bdp, PHY_82562EH_NSE_ATTACK_EVENT_REG, bddp->phy_addr, + PHY_82562EH_NSE_ATTACK_WORK_VALUE); + + Phy82562EHAddressSpaceSwitch(bddp, PHY_82562EH_ADDR_SPACE_PAGE_1); + + e100_MdiWrite(bddp->bdp, PHY_82562EH_AFE_CONTROL1_REG, bddp->phy_addr, + PHY_82562EH_AFE_CR1_WORK_VALUE); + e100_MdiWrite(bddp->bdp, PHY_82562EH_AFE_CONTROL2_REG, bddp->phy_addr, + PHY_82562EH_AFE_CR2_WORK_VALUE); + + Phy82562EHAddressSpaceSwitch(bddp, PHY_82562EH_ADDR_SPACE_PAGE_0); +} + + +/**************************************************************************** + * Name: PhyProcessing82562EHInit + * + * Description: This routine will do all of initializatioin necessary for + * the 82562EH phy. + * + * Arguments: bddp - ptr to bddp object instance + * + * Returns: Nothing + ***************************************************************************/ +void +PhyProcessing82562EHInit( bdd_t *bddp ) +{ + Phy82562EHSpeedPowerSetup(bddp); + Phy82562EHRegisterInit(bddp); + + if(bddp->Phy82562EHSampleCount > PHY_82562EH_MAX_TABLE) { + bddp->Phy82562EHSampleCount = PHY_82562EH_MAX_TABLE; + } + + Phy82562EHNoiseFloorCalculate(bddp); +} + + +/**************************************************************************** + * Name: Phy82562EHSpeedPowerSetup + * + * Description: This routine will setup correct speed/power for 82562EH PHY. + * + * Arguments: bddp - ptr to bddp object instance + * + * Returns: Nothing + ***************************************************************************/ +void +Phy82562EHSpeedPowerSetup(bdd_t *bddp) +{ + uint16_t MdiControlReg, controlReg; + + MdiControlReg = MDI_CR_RESET; + + /* Write the MDI control register with our new Phy configuration */ + e100_MdiWrite(bddp->bdp, MDI_CONTROL_REG, bddp->phy_addr, MdiControlReg); + + /* Setting up right 82562EH power/speed. */ + e100_MdiRead(bddp->bdp, PHY_82562EH_CONTROL_REG, bddp->phy_addr, + &controlReg); + + /* Check if any user override. Default value after reset is low power. */ + if (PhoneLinePower[bddp->bd_number]) + controlReg |= PHY_82562EH_CR_HP; + else + controlReg &= ~ (PHY_82562EH_CR_HP); + + /* Check if any user override. Default value after reset is high speed. */ + if (PhoneLineSpeed[bddp->bd_number]) + controlReg |= PHY_82562EH_CR_HS; + else + controlReg &= ~(PHY_82562EH_CR_HS); + + /* Ignore incoming command from master HomeRun node. */ + controlReg &= ~(PHY_82562EH_CR_IRC); + + e100_MdiWrite(bddp->bdp, PHY_82562EH_CONTROL_REG, bddp->phy_addr, + controlReg); +} + + +/***************************************************************************/ +/***************************************************************************/ +/* Auxilary Functions */ +/***************************************************************************/ + +/* + * Procedure: e100_print_brd_conf + * + * Description: This routine printd the board configuration. + * + * Arguments: + * bdp - Ptr to this card's e100_bdconfig structure + * + * Returns: + * NONE + */ +void +e100_print_brd_conf(bd_config_t *bdp) +{ + bdd_t *bddp = (bdd_t *) bdp->bddp; + int offset; + + printk(KERN_NOTICE "%s: %s\n", bdp->device->name, e100id_string); + + offset = bdp->io_end - bdp->io_start; + + printk(KERN_NOTICE " Mem:0x%p IRQ:%d Speed:%d Mbps Dx:%s\n", + (void*)bdp->mem_start, + bdp->irq_level, bddp->cur_line_speed, + bddp->cur_dplx_mode == FULL_DUPLEX ? "Full" : + ((bddp->cur_dplx_mode == NO_DUPLEX) ? "N/A" : "Half")); + if (bddp->flags & INVALID_SPEED_DPLX) { + /* 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 (bddp->checksum_offload_enabled) + 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 " Ucode was not loaded\n"); +} + + +/* New routine for checking sub-dev & sub-ven IDs. */ + +/* + * Procedure: e100_GetBrandingMesg + * + * Description: This routine checks if the sub_ven and sub_dev found + * on the board is a valid one for the driver to load. If it is, the + * routine determines the right string to be printed. The routine knows + * what IDs to load on by scanning a predefined array. + * + * Arguments: + * sub_ven - Subsystem vendor ID on the board + * sub_dev - Subsystem device ID on the board + * + * Returns: + * 1 - if it is valid to load on this board + * 0 - if it is not valid to load on this board + */ +static char * +e100_GetBrandingMesg(bd_config_t *bdp) +{ + uint16_t sub_ven, sub_dev; + char *mesg = NULL; + int i = 0; + + sub_ven = bdp->bddp->sub_ven_id; + sub_dev = bdp->bddp->sub_dev_id; + + /* Go through the list of all valid device, vendor and subsystem IDs */ + while (e100_vendor_info_array[i].idstr != NULL) { + /* Look for a match on device id */ + if ((e100_vendor_info_array[i].dev_id == bdp->bddp->pci_dev->device) + || (e100_vendor_info_array[i].dev_id == CATCHALL)) { + /* Look for a match on sub_ven */ + if ((e100_vendor_info_array[i].sub_ven == sub_ven) + /* Is this driver to load on all adapters from this vendor? */ + || (e100_vendor_info_array[i].sub_ven == CATCHALL)) { + /* Look for a match on sub_dev */ + if ((e100_vendor_info_array[i].sub_dev == sub_dev) + /* Is this driver to load on all adapters with this subsytem dev id? */ + || (e100_vendor_info_array[i].sub_dev == CATCHALL)) { + mesg = e100_vendor_info_array[i].idstr; + break; + } + } + } + i++; + } + + if (mesg) strcpy(e100id_string, mesg); + else printk(KERN_WARNING "e100: Vendor ID Mismatch\n"); + return mesg; +} + + +/* + * Procedure: e100_dis_intr + * + * Description: This routine disables interrupts at the hardware, by setting + * the M (mask) bit in the adapter's CSR SCB command word. + * + * Arguments: + * bdp - Ptr to this card's e100_bdconfig structure + * + * Returns: + * NOTHING + */ +void +e100_dis_intr(bd_config_t *bdp) +{ + bdd_t *bddp; /* stores all adapter specific info */ + + if (DEBUG) + printk(KERN_DEBUG "e100_dis_intr\n"); + + bddp = (pbdd_t) bdp->bddp; /* get the bddp for this board */ + + /* Disable interrupts on our PCI board by setting the mask bit */ + bddp->scbp->scb_cmd_hi = (uint8_t) SCB_INT_MASK; +} + + +/* + * Procedure: e100_enbl_intr + * + * Description: This routine enables interrupts at the hardware, by resetting + * the M (mask) bit in the adapter's CSR SCB command word + * + * Arguments: + * bdp - Ptr to this card's e100_bdconfig structure + * + * Returns: + * NOTHING + */ +void +e100_enbl_intr(bd_config_t *bdp) +{ + bdd_t *bddp; /* stores all adapter specific info */ + + if (DEBUG) + printk(KERN_DEBUG "e100_enbl_intr\n"); + + bddp = (pbdd_t) bdp->bddp; /* get the bddp for this board */ + + /* Enable interrupts on our PCI board by clearing the mask bit */ + bddp->scbp->scb_cmd_hi = (uint8_t) 0; +} + + +void +e100_trigger_SWI(bd_config_t *bdp) +{ + bdd_t *bddp; /* stores all adapter specific info */ + + bddp = (pbdd_t) bdp->bddp; + /* Trigger interrupt on our PCI board by asserting SWI bit */ + bddp->scbp->scb_cmd_hi = (uint8_t) SCB_SOFT_INT; +} + + +/***************************************************************************** + * Name: drv_usecwait + * + * Description: This routine causes a delay for the number of useconds + * that it is passed. + * + * Arguments: + * MsecDelay - How many useconds to delay for. + * + * Returns: + * (none) + * + * Modification log: + * Date Who Description + * -------- --- -------------------------------------------------------- + * + *****************************************************************************/ +void +drv_usecwait(uint_t MsecDelay) +{ + udelay(MsecDelay); +} + +/***************************************************************************** + * Name: e100_get_pci_info + * + * Description: This routine finds all PCI adapters that have the given Device + * ID and Vendor ID. It will store the IRQ, I/O, mem address, + * amd node address for each adapter in the + * CardsFound structure. This routine will also enable the bus + * master bit on any of our adapters (some BIOS don't do this). + * + * + * Arguments: + * vendor_id - Vendor ID of our adapter. + * device_id - Device ID of our adapter. + * + * Returns: + * B_TRUE - if found pci devices successfully + * B_FALSE - if no pci devices found + * + * Modification log: + * Date Who Description + * -------- --- -------------------------------------------------------- + * + *****************************************************************************/ +static void +e100_get_pci_info(pci_dev_t *pcid, bd_config_t *bdp) +{ + bdd_t *bddp = bdp->bddp; + uint32_t tmp_base_addr; + uint16_t pci_cmd = 0; + + if (DEBUG) + printk(KERN_DEBUG "e100_get_pci_info\n"); + + /* dev and ven ID have already been check so it is our device */ + pci_read_config_byte(pcid, PCI_REVISION_ID, (uint8_t *) & (bddp->rev_id)); + pci_read_config_word(pcid, PCI_SUBSYSTEM_ID, (uint16_t *) & (bddp->sub_dev_id)); + pci_read_config_word(pcid, PCI_SUBSYSTEM_VENDOR_ID, (uint16_t *) & (bddp->sub_ven_id)); + pci_read_config_word(pcid, PCI_COMMAND, (uint16_t *) & (pci_cmd)); + + /* if Bus Mastering is off, turn it on! */ + pci_set_master(pcid); + + /* address #0 is a memory mapping */ + tmp_base_addr = (uint32_t)pci_resource_start(pcid, 0); + bddp->scbp = (pscb_t) ioremap((tmp_base_addr & ~0xf), sizeof(scb_t)); + bddp->mem_size = sizeof(scb_t); + bdp->mem_start = tmp_base_addr; + + /* address #1 is a IO region */ + tmp_base_addr = (uint32_t)pci_resource_start(pcid, 1); + bdp->io_start = (tmp_base_addr & ~0x3UL); + +#if (E100_DEBUG) + printk(KERN_DEBUG "RevID = 0x%x\n", (uint8_t) bddp->rev_id); + printk(KERN_DEBUG "SUBSYSTEM_ID = 0x%x\n", bddp->sub_dev_id); + printk(KERN_DEBUG "SUBSYSTEM_VENDOR_ID = 0x%x\n", bddp->sub_ven_id); + printk(KERN_DEBUG "DeviceNum = 0x%x\n", bddp->dev_num); + printk(KERN_DEBUG "mem_start = 0x%x\n", bdp->mem_start); + printk(KERN_DEBUG "io_start = 0x%x\n", bdp->io_start); + printk(KERN_DEBUG "pci_cmd = 0x%x\n", pci_cmd); +#endif + + bddp->dev_num = pcid->devfn; +} + + +/***************************************************************************** + * Name: e100_pci_write_config + * + * Description: This routine allows writing individual bytes/words/dwords + * from the PCI Configuration Space of a specific device. + * + * + * Arguments: + * pci_dev_t - Device number of the write target + * reg_num - Register Number to write (0-0xFF) + * val - value to write + * wr_type - whether byte, word or dword + * + * Returns: + * + * Modification log: + * Date Who Description + * -------- --- -------------------------------------------------------- + * + *****************************************************************************/ +void +e100_pci_write_config(pci_dev_t *pcid, + uint8_t reg_num, uint32_t val, int wr_type) +{ + switch (wr_type) { + case PCI_BYTE: + pci_write_config_byte(pcid, reg_num, (uint8_t) val); + break; + + case PCI_WORD: + pci_write_config_word(pcid, reg_num, (uint16_t) val); + break; + + case PCI_DWORD: + pci_write_config_dword(pcid, reg_num, val); + break; + } + return; +} + +/**************************************************************************\ + ** + ** PROC NAME: e100_handle_zero_lock_state + ** 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->ZeroLockState, 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): + ** ZeroLockState - current state of the algorithm + ** ZeroLockReadCounter - counts number of reads (up to 100) + ** ZeroLockReadData[i] - counts number of times 'Zero' read was i, 0 <= i <= 15 + ** ZeroLockSleepCounter - 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() + ** + \**************************************************************************/ +static void e100_handle_zero_lock_state(bd_config_t *bdp) +{ + uint16_t ArrayPosition; + uint16_t EqRegValue; + uint8_t MostPopularZero; + uint16_t ErrorCounter; + bdd_t *bddp = (bdd_t *)bdp->bddp; + + switch (bdp->ZeroLockState) + { + case ZLOCK_INITIAL: + +#if (DEBUG_LINK > 0) + printk(KERN_DEBUG "ZeroLockState: INITIAL\n"); +#endif + if ( ((uint8_t)bddp->rev_id <= D102_REV_ID) || + !(bddp->cur_line_speed == 100) || + !(bdp->flags & DF_LINK_UP) ) + { + break; + } + + //initialize hw and sw and start reading + + e100_MdiWrite(bdp, PHY_82555_MDI_EQUALIZER_CSR, bddp->phy_addr, 0); + // reset read counters: + bdp->ZeroLockReadCounter = 0; + for (ArrayPosition=0; ArrayPosition < 16; ArrayPosition++) + bdp->ZeroLockReadData[ArrayPosition] = 0; + // start reading in the next call back: + bdp->ZeroLockState = 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_MdiRead(bdp, PHY_82555_MDI_EQUALIZER_CSR, bddp->phy_addr, &EqRegValue); + + ArrayPosition = (EqRegValue & ZLOCK_ZERO_MASK) >> 4; + + bdp->ZeroLockReadData[ArrayPosition]++; + bdp->ZeroLockReadCounter++; + +#if (DEBUG_LINK > 1) + printk(KERN_DEBUG "ZeroLockState: Reading %d 'Zero' %04X\n",bdp->ZeroLockReadCounter, + (EqRegValue & ZLOCK_ZERO_MASK)); +#endif + + if (bdp->ZeroLockReadCounter == ZLOCK_MAX_READS) + { + // check if we have read a 'Zero' value of 0xB or greater: + if ((bdp->ZeroLockReadData[0xB]) || (bdp->ZeroLockReadData[0xC]) || + (bdp->ZeroLockReadData[0xD]) || (bdp->ZeroLockReadData[0xE]) || + (bdp->ZeroLockReadData[0xF])) + { + // we have read a 'Zero' value of 0xB or greater, find the most popular 'Zero' + // value and lock it: + MostPopularZero = 0; + // this loop finds the most popular 'Zero': + for (ArrayPosition = 1; ArrayPosition < 16; ArrayPosition++) + { + if (bdp->ZeroLockReadData[ArrayPosition] > bdp->ZeroLockReadData[MostPopularZero]) + MostPopularZero = ArrayPosition; + } + // now lock the most popular 'Zero': + EqRegValue = (ZLOCK_SET_ZERO | MostPopularZero); + e100_MdiWrite(bdp, PHY_82555_MDI_EQUALIZER_CSR, bddp->phy_addr, EqRegValue); + +#if (DEBUG_LINK > 0) + printk(KERN_DEBUG "ZeroLockState: Wrote most popular 'Zero' - %d. Going to sleep\n", + MostPopularZero); +#endif + + // sleep for 5 minutes: + bdp->ZeroLockSleepCounter = jiffies; + bdp->ZeroLockState = 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 just read them: + + e100_MdiRead(bdp, PHY_82555_SYMBOL_ERR, bddp->phy_addr, &ErrorCounter); + } + else + { + // we did not read a 'Zero' value of 0xB or above. go back to the start: + bdp->ZeroLockState = ZLOCK_INITIAL; + } + + } + break; + + case ZLOCK_SLEEPING: + // state: sleeping for 5 minutes + // prev states: ZLOCK_READING + // next states: ZLOCK_READING, ZLOCK_SLEEPING + +#if (DEBUG_LINK > 1) + printk(KERN_DEBUG "ZeroLockState: SLEEPING %d SEC \n", + ( jiffies - bdp->ZeroLockSleepCounter )/HZ); +#endif + + // if 5 minutes have passed: + if (( jiffies - bdp->ZeroLockSleepCounter ) >= ZLOCK_MAX_SLEEP) + { + // read and sum up the number of errors: + e100_MdiRead(bdp, PHY_82555_SYMBOL_ERR, bddp->phy_addr, &ErrorCounter); + +#if (DEBUG_LINK > 0) + + printk(KERN_DEBUG "ZeroLockState: Sleep Time expired. Error counter %d\n", + ErrorCounter); + bdp->ErrorCounter = ErrorCounter; + +#endif + + // if we have 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 (ErrorCounter > ber[bdp->bd_number]) + { + // start again in the next callback: + bdp->ZeroLockState = ZLOCK_INITIAL; + } + else + { + // we don't have more errors than allowed, sleep for another 5 minutes: + bdp->ZeroLockSleepCounter = jiffies; + } + } + break; + } // switch +} // e100_handle_zero_lock_state + diff -urN linux-2.2.25.orig/drivers/net/e100.h linux-2.2.25/drivers/net/e100.h --- linux-2.2.25.orig/drivers/net/e100.h Thu Jan 1 08:00:00 1970 +++ linux-2.2.25/drivers/net/e100.h Mon Aug 11 15:44:24 2003 @@ -0,0 +1,2924 @@ +/***************************************************************************** + ***************************************************************************** + Copyright (c) 1999-2001, Intel Corporation + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of Intel Corporation nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + ***************************************************************************** +****************************************************************************/ + +#ifndef _E100_INC_ +#define _E100_INC_ + +#include +#include +#ifdef MODVERSIONS +#include +#endif /* MODVERSIONS */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* /proc definitions */ +#define ADAPTERS_PROC_DIR "PRO_LAN_Adapters" + +#define DESCRIPTION_TAG "Description" +#define DRVR_NAME_TAG "Driver_Name" +#define DRVR_VERSION_TAG "Driver_Version" +#define PCI_VENDOR_TAG "PCI_Vendor" +#define PCI_DEVICE_ID_TAG "PCI_Device_ID" +#define PCI_SUBSYSTEM_VENDOR_TAG "PCI_Subsystem_Vendor" +#define PCI_SUBSYSTEM_ID_TAG "PCI_Subsystem_ID" +#define PCI_REVISION_ID_TAG "PCI_Revision_ID" +#define PCI_BUS_TAG "PCI_Bus" +#define PCI_SLOT_TAG "PCI_Slot" +#define IRQ_TAG "IRQ" +#define SYSTEM_DEVICE_NAME_TAG "System_Device_Name" +#define CURRENT_HWADDR_TAG "Current_HWaddr" +#define PERMANENT_HWADDR_TAG "Permanent_HWaddr" +#define PART_NUMBER_TAG "Part_Number" + +#define LINK_TAG "Link" +#define SPEED_TAG "Speed" +#define DUPLEX_TAG "Duplex" +#define STATE_TAG "State" + +#define RX_PACKETS_TAG "Rx_Packets" +#define TX_PACKETS_TAG "Tx_Packets" +#define RX_BYTES_TAG "Rx_Bytes" +#define TX_BYTES_TAG "Tx_Bytes" +#define RX_ERRORS_TAG "Rx_Errors" +#define TX_ERRORS_TAG "Tx_Errors" +#define RX_DROPPED_TAG "Rx_Dropped" +#define TX_DROPPED_TAG "Tx_Dropped" +#define MULTICAST_TAG "Multicast" +#define COLLISIONS_TAG "Collisions" +#define RX_LENGTH_ERRORS_TAG "Rx_Length_Errors" +#define RX_OVER_ERRORS_TAG "Rx_Over_Errors" +#define RX_CRC_ERRORS_TAG "Rx_CRC_Errors" +#define RX_FRAME_ERRORS_TAG "Rx_Frame_Errors" +#define RX_FIFO_ERRORS_TAG "Rx_FIFO_Errors" +#define RX_MISSED_ERRORS_TAG "Rx_Missed_Errors" +#define TX_ABORTED_ERRORS_TAG "Tx_Aborted_Errors" +#define TX_CARRIER_ERRORS_TAG "Tx_Carrier_Errors" +#define TX_FIFO_ERRORS_TAG "Tx_FIFO_Errors" +#define TX_HEARTBEAT_ERRORS_TAG "Tx_Heartbeat_Errors" +#define TX_WINDOW_ERRORS_TAG "Tx_Window_Errors" + +#define RX_TCP_CHECKSUM_GOOD_TAG "Rx_TCP_Checksum_Good" +#define RX_TCP_CHECKSUM_BAD_TAG "Rx_TCP_Checksum_Bad" +#define TX_TCP_CHECKSUM_GOOD_TAG "Tx_TCP_Checksum_Good" +#define TX_TCP_CHECKSUM_BAD_TAG "Tx_TCP_Checksum_Bad" + +#define TX_ABORT_LATE_COLL_TAG "Tx_Abort_Late_Coll" +#define TX_DEFERRED_OK_TAG "Tx_Deferred_Ok" +#define TX_SINGLE_COLL_OK_TAG "Tx_Single_Coll_Ok" +#define TX_MULTI_COLL_OK_TAG "Tx_Multi_Coll_Ok" +#define RX_ALIGN_ERRORS_TAG "Rx_Align_Errors" +#define RX_LONG_LENGTH_ERRORS_TAG "Rx_Long_Length_Errors" + +/* E100 compile time configurable parameters */ + +#define IFNAME "e100" + +/* + * 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 7 /* 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 TX_CONG_DFLT 0 /* congestion enable flag for National TX Phy */ +#define TX_FIFO_LMT 0 +#define RX_FIFO_LMT 8 +#define TX_DMA_CNT 0 +#define RX_DMA_CNT 0 +#define TX_UR_RETRY 3 +#define TX_THRSHLD 8 + +/* These are special #defs and are NOT TO BE TOUCHED! */ +#define DEFAULT_TX_FIFO_LIMIT 0x00 +#define DEFAULT_RX_FIFO_LIMIT 0x08 +#define CB_557_CFIG_DEFAULT_PARM4 0x00 +#define CB_557_CFIG_DEFAULT_PARM5 0x00 +#define DEFAULT_TRANSMIT_THRESHOLD 12 /* 12 -> 96 bytes */ +#define ADAPTIVE_IFS 0 + +/* Note: The 2 parameters below might affect NFS performance. If there are + * problems with NFS, set CPU_CYCLE_SAVER to 0x0 and CFG_BYTE_PARM6 to 0x32. + */ + +/* CPU_CYCLE_SAVER: Used for receive interrupt bundling microcode. + * Valid values are from 0 to 0xc000. Setting it to 0 disables the feature. + */ +#define CPU_CYCLE_SAVER 0x0 + +/* CFG_BYTE_PARM6: Determines whether the card generates CNA interrupts + * or not. + * 0x32 configures the card to generate CNA interrupts + * 0x3a configures the card not to generate CNA interrupts + */ +#define CFG_BYTE_PARM6 0x32 + +/* 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 CPUSAVER_BUNDLE_MAX 0x0006 + +/* end of configurables */ + + +/***************************************************************************** + * Linux Kernel compatibility + ****************************************************************************/ + +/* Macros to make drivers compatible with 2.2.0 - 2.3.51 Linux kernels */ + +/* + * In order to make a single network driver work with all 2.2-2.4 kernels + * these compatibility macros can be used. + * They are backwards compatible implementations of the latest APIs. + * The idea is that these macros will let you use the newest driver with old + * kernels, but can be removed when working with the latest and greatest. + */ + +#include + +/***************************************************************************** + ** + ** PCI bus changes + ** + *****************************************************************************/ + +/* Accessing the BAR registers from the PCI device structure + * Changed from base_address[bar] to resource[bar].start in 2.3.13 + * The pci_resource_start inline function was introduced in 2.3.43 + */ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,3,13) ) +#define pci_resource_start(dev, bar) ((dev)->base_address[(bar)]) +#elif ( LINUX_VERSION_CODE < KERNEL_VERSION(2,3,43) ) +#define pci_resource_start(dev, bar) ((dev)->resource[(bar)].start) +#endif + +/* Starting with 2.3.23 drivers are supposed to call pci_enable_device + * to make sure I/O and memory regions have been mapped and potentially + * bring the device out of a low power state + */ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,3,23) ) +#define pci_enable_device(dev) do{} while(0) +#endif + +/* Dynamic DMA maping + * Instead of using virt_to_bus, bus mastering PCI drivers should use the DMA + * mapping API to get bus addresses. This lets some platforms use dynamic + * mapping to use PCI devices that do not support DAC in a 64-bit address space + */ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,3,41) ) +#ifdef MODVERSIONS +#include +#endif +#include +#include +#include +#include + + +#if (( LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18) ) || \ + ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) ) ) +typedef unsigned long dma_addr_t; +#endif + +#define PCI_DMA_TODEVICE 1 +#define PCI_DMA_FROMDEVICE 2 + +extern inline void *pci_alloc_consistent (struct pci_dev *dev, + size_t size, + dma_addr_t *dma_handle) { + void *vaddr = kmalloc(size, GFP_ATOMIC); + if(vaddr != NULL) { + *dma_handle = virt_to_bus(vaddr); + } + return vaddr; +} +#define pci_dma_sync_single(dev,dma_handle,size,direction) do{} while(0) +#define pci_dma_supported(dev, addr_mask) (1) +#define pci_free_consistent(dev, size, cpu_addr, dma_handle) kfree(cpu_addr) +#define pci_map_single(dev, addr, size, direction) virt_to_bus(addr) +#define pci_unmap_single(dev, dma_handle, size, direction) do{} while(0) + +#define pci_resource_len(a,b) (128 * 1024) +#endif + +/***************************************************************************** + ** + ** Network Device API changes + ** + *****************************************************************************/ + +/* In 2.3.14 the device structure was renamed to net_device */ +#ifndef _DEVICE_T +#define _DEVICE_T +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,3,14) ) +typedef struct device device_t; +#else +typedef struct net_device device_t; +#endif +#endif + +/* 'Softnet' network stack changes merged in 2.3.43 + * these are 2.2 compatible defines for the new network interface API + * 2.3.47 added some more inline functions for softnet to remove explicit + * bit tests in drivers + */ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,3,43) ) +#define netif_start_queue(dev) ( clear_bit(0, &(dev)->tbusy)) +#define netif_stop_queue(dev) ( set_bit(0, &(dev)->tbusy)) +#define netif_wake_queue(dev) { clear_bit(0, &(dev)->tbusy); \ + mark_bh(NET_BH); } +#define netif_running(dev) ( test_bit(0, &(dev)->start)) +#define netif_queue_stopped(dev) ( test_bit(0, &(dev)->tbusy)) +#elif ( LINUX_VERSION_CODE < KERNEL_VERSION(2,3,47) ) +#define netif_running(dev) (test_bit(LINK_STATE_START, &(dev)->state)) +#define netif_queue_stopped(dev) (test_bit(LINK_STATE_XOFF, &(dev)->state)) +#endif + +/* Softnet changes also affected how SKBs are handled + * Special calls need to be made now while in an interrupt handler + */ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,3,43) ) +#define dev_kfree_skb_irq(skb) dev_kfree_skb(skb) +#endif + + + +/* ====================================================================== */ +/* hw */ +/* ====================================================================== */ + +#ifndef NULL +#define NULL 0 +#endif + +/* watchdog invocation intervals */ +#define E100_SRV_BUSY 40 +#define E100_SRV_LAZY 1000 +#define RX_SRV_COUNT RxDescriptors + +/* timeout for command completion */ +#define E100_CMD_WAIT 100 /* iterations */ + +/* Unix Typedefs */ +typedef unsigned char uchar_t; +typedef unsigned int uint_t; +typedef unsigned short ushort_t; +typedef unsigned long ulong_t; +typedef unsigned long paddr_t; +typedef unsigned char boolean_t; + +/* this is where we store the results of the DUMP & RESET statitics cmd */ +typedef struct _err_stats_t +{ + uint32_t gd_xmits; + uint32_t gd_recvs; + uint32_t tx_abrt_xs_col; + uint32_t tx_late_col; + uint32_t tx_dma_urun; + uint32_t tx_lost_csrs; + uint32_t tx_ok_defrd; + uint32_t tx_one_retry; + uint32_t tx_mt_one_retry; + uint32_t tx_tot_retries; + uint32_t rcv_crc_err; + uint32_t rcv_align_err; + uint32_t rcv_rsrc_err; + uint32_t rcv_dma_orun; + uint32_t rcv_cdt_frames; + uint32_t rcv_runts; + uint32_t num_gd_xmts; /* # of last good tx frames since the last + adjustment of the TX THRESHOLD */ +} err_stats_t, *perr_stats_t; + +#define STATIC static + +#define B_TRUE 1 +#define B_FALSE 0 +#define TRUE 1 +#define FALSE 0 + +typedef struct pci_dev pci_dev_t; +typedef struct sk_buff sk_buff_t; +typedef struct net_device_stats net_device_stats_t; + +/* Flags for hardware identification and status */ +#define USE_IPCB 0x20 /* set if using ipcb for transmits */ +#define IS_BACHELOR 0x40 /* set if 82558 or newer board */ +#define CU_ACTIVE_TOOLONG 0x80 +#define INVALID_SPEED_DPLX 0x100 +#define PRINT_SPEED_DPLX 0x200 +#define BOARD_IN_SERVICE 0x400 +#define IS_ICH 0x800 +#define IS_82562EH 0x1000 + +/* Changed for 82558 and 82559 enhancements */ +/* defines for 82558/9 flow control configure paramters */ +#define DFLT_FC_DELAY_LSB 0x1f /* Delay for outgoing Pause frames */ +#define DFLT_FC_DELAY_MSB 0x01 /* Delay for outgoing Pause frames */ + +/* 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 + +/*- Miscellaneous Equates */ +#define CR 0x0D /* Carriage Return */ +#define LF 0x0A /* Line Feed */ + +#define TX_OK 1 +#define E100_NULL ((uint32_t)0xffffffff) + +/* OEM Message Tags */ +#define stringTag 0xFEFA /* Length Byte After String */ +#define lStringTag 0xFEFB /* Length Byte Before String */ +#define zStringTag 0xFEFC /* Zero-Terminated String Tag */ +#define nStringTag 0xFEFD /* No Length Byte Or 0-Term */ + + +/* Phy related constants */ +#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 PHY_MODEL_REV_ID_MASK 0xFFF0FFFF +#define PARALLEL_DETECT 0 +#define N_WAY 1 + +/* Transmit Threshold related constants */ +#define DEFAULT_TX_PER_UNDERRUN 20000 + +/* Ethernet Frame Sizes */ +#define ETHERNET_ADDRESS_LENGTH 6 +#define ETHERNET_HEADER_SIZE 14 +#define MINIMUM_ETHERNET_PACKET_SIZE 60 +#define MAXIMUM_ETHERNET_PACKET_SIZE 1514 +#define SIZEOF_COALESCE_BUFF 1536 + +#define MAX_MULTICAST_ADDRS 64 +#define TCB_BUFFER_SIZE 64 + +#define RCB_BUFFER_SIZE MAXIMUM_ETHERNET_PACKET_SIZE + +/*- Area reserved for all Non Transmit command blocks */ +#define MAX_NON_TX_CB_AREA 512 + +/* driver constants */ +#define MAX_PHYS_DESC 16 + +#define DUMP_STATS_TIMEOUT 500 +#define FULL_DUPLEX 2 +#define HALF_DUPLEX 1 +#define NO_DUPLEX 0 +/* + * 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 + + +/* CSR field definitions -- Offsets from CSR base*/ +#define SCB_STATUS_LOW_BYTE 0x0 +#define SCB_STATUS_HIGH_BYTE 0x1 +#define SCB_COMMAND_LOW_BYTE 0x2 +#define SCB_COMMAND_HIGH_BYTE 0x3 +#define SCB_GENERAL_POINTER 0x4 +#define CSR_PORT_LOW_WORD 0x8 +#define CSR_PORT_HIGH_WORD 0x0a +#define CSR_FLASH_CONTROL_REG 0x0c +#define CSR_EEPROM_CONTROL_REG 0x0e +#define CSR_MDI_CONTROL_LOW_WORD 0x10 +#define CSR_MDI_CONTROL_HIGH_WORD 0x12 +/* Changed for 82558 enhancements */ +/* define 82558/9 fields */ +#define CSR_RX_DMA_BYTE_COUNT 0x14 +#define CSR_EARLY_RX_INT 0x18 +#define CSR_FC_THRESHOLD 0x19 +#define CSR_FC_XON_XOFF 0x1a +#define CSR_POWER_MGMT_REG 0x1b + + +/* 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_SUBSYSTEM_ID_WORD 0x0b +#define EEPROM_SUBSYSTEM_VENDOR_WORD 0x0c + +#define E100_WRITE_REG(reg, value) {bddp->scbp->reg = value; } +#define E100_READ_REG(reg) bddp->scbp->reg + +#define EEPROM_CTRL scb_eprm_cntrl +#define EEPROM_CHECKSUM_REG 0x3f +#define EEPROM_SUM 0xbaba + + +/* MDI Control register bit definitions */ +#define MDI_DATA_MASK BIT_0_15 /* MDI Data port */ +#define MDI_REG_ADDR BIT_16_20 /* which MDI register to read/write */ +#define MDI_PHY_ADDR BIT_21_25 /* which PHY to read/write */ +#define MDI_PHY_OPCODE BIT_26_27 /* which PHY to read/write */ +#define MDI_PHY_READY BIT_28 /* PHY is ready for next MDI cycle */ +#define MDI_PHY_INT_ENABLE BIT_29 /* Assert INT at MDI cycle compltion */ + + +/* MDI Control register opcode definitions */ +#define MDI_WRITE 1 /* Phy Writ */ +#define MDI_READ 2 /* Phy read */ + +// 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_NOP 0 +#define CB_IA_ADDRESS 1 +#define CB_CONFIGURE 2 +#define CB_MULTICAST 3 +#define CB_TRANSMIT 4 +#define CB_LOAD_MICROCODE 5 +#define CB_DUMP 6 +#define CB_DIAGNOSE 7 +/* the following are dummy commands to maintain the CU state */ +#define CB_NULL 8 +#define CB_TRANSMIT_FIRST 9 +#define CB_DUMP_RST_STAT 10 + +#define CB_IPCB_TRANSMIT 9 + + +/* 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_2 /* CB 3-bit CMD Mask */ + +/*- 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 CB Parameter Fields*/ +#define CB_CFIG_BYTE_COUNT 22 /* 22 config bytes */ +#define CB_CFIG_D102_BYTE_COUNT 10 + +/* 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_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_URUN_RETRY BIT_1_2 /* Underrun Retry Count */ +#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*/ + +/* 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 */ + +/* 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*/ + +/* byte 17 bit definitions -- pre-defined 0x40*/ + +/* 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_CFIG_TX_MAGPAK_WAKE BIT_1 /* Magic Packet Wakeup */ +/* 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_REJECT_FC BIT_5 /* Rx Flow Control Restart */ +/* 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 */ + + + +/* 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 */ + + +#define DUMP_BUFFER_SIZE 600 /* size of the dump buffer */ + + + +/* 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) + + +/*------------------------------------------------------------------------- + * Driver Configuration Default Parameters for the 557 + * Note: If the driver uses any defaults that are different from the chip's + * defaults, it will be noted below + *------------------------------------------------------------------------- + */ +/* Byte 0 (byte count) default*/ +#define CB_557_CFIG_DEFAULT_PARM0 CB_CFIG_BYTE_COUNT + +/* Byte 1 (fifo limits) default ( bit 7 is always set ) */ +#define CB_557_CFIG_DEFAULT_PARM1 0x88 + +/* Byte 2 (adaptive IFS) default*/ +#define CB_557_CFIG_DEFAULT_PARM2 0x00 + +/* Byte 3 (reserved) default*/ +#define CB_557_CFIG_DEFAULT_PARM3 0x00 + +/* Byte 4 (Rx DMA min count) default*/ +#define CB_557_CFIG_DEFAULT_PARM4 0x00 + +/* Byte 5 (Tx DMA min count, DMA min count enable) default*/ +#define CB_557_CFIG_DEFAULT_PARM5 0x00 + +/* Byte 6 (No Late SCB, CNA int) default*/ +#define CB_557_CFIG_DEFAULT_PARM6 0x32 + +/* Byte 7 (Discard short frames, underrun retry) default*/ +/* note: disc short frames will be enabled*/ +#define DEFAULT_UNDERRUN_RETRY 0x01 +#define CB_557_CFIG_DEFAULT_PARM7 0x03 + +/* Byte 8 (MII or 503) default*/ +/* note: MII will be the default*/ +#define CB_557_CFIG_DEFAULT_PARM8 0x01 + +/* Byte 9 (reserved) default*/ +#define CB_557_CFIG_DEFAULT_PARM9 0x00 + +/* Byte 10 (scr addr insertion, preamble, loopback) default*/ +#define CB_557_CFIG_DEFAULT_PARM10 0x2e + +/* Byte 11 (linear priority) default*/ +#define CB_557_CFIG_DEFAULT_PARM11 0x00 + +/* Byte 12 (IFS,linear priority mode) default*/ +#define CB_557_CFIG_DEFAULT_PARM12 0x60 + +/* Byte 13 (reserved) default*/ +#define CB_557_CFIG_DEFAULT_PARM13 0x00 + +/* Byte 14 (reserved) default*/ +#define CB_557_CFIG_DEFAULT_PARM14 0xf2 + +/* Byte 15 (broadcast, CRS/CDT) default*/ +#define CB_557_CFIG_DEFAULT_PARM15 0xc8 + +/* Byte 16 (reserved) default*/ +#define CB_557_CFIG_DEFAULT_PARM16 0x00 + +/* Byte 17 (reserved) default*/ +#define CB_557_CFIG_DEFAULT_PARM17 0x40 + +/* Byte 18 (Stripping, padding, Rcv CRC in mem) default*/ +/* note: padding is enabled with 0xf2, disabled if 0xf0 */ +#define CB_557_CFIG_DEFAULT_PARM18 0xf2 + +/* Byte 19 (reserved) default*/ +/* note: full duplex is enabled if FDX# pin is 0*/ +#define CB_557_CFIG_DEFAULT_PARM19 0x80 + +/* Byte 20 (multi-IA) default*/ +#define CB_557_CFIG_DEFAULT_PARM20 0x3f + +/* Byte 21 (multicast all) default*/ +#define CB_557_CFIG_DEFAULT_PARM21 0x05 + + +/* 82557 PCI Register Definitions */ +/* Refer To The PCI Specification For Detailed Explanations*/ + +/*- Register Offsets*/ +#define PCI_VENDOR_ID_REGISTER 0x00 /* PCI Vendor ID Register */ +#define PCI_DEVICE_ID_REGISTER 0x02 /* PCI Device ID Register */ +#define PCI_CONFIG_ID_REGISTER 0x00 /* PCI Configuration ID Register */ +#define PCI_COMMAND_REGISTER 0x04 /* PCI Command Register */ +#define PCI_STATUS_REGISTER 0x06 /* PCI Status Register */ +#define PCI_REV_ID_REGISTER 0x08 /* PCI Revision ID Register */ +#define PCI_CLASS_CODE_REGISTER 0x09 /* PCI Class Code Register */ +#define PCI_CACHE_LINE_REGISTER 0x0C /* PCI Cache Line Register */ +#define PCI_BIST_REGISTER 0x0F /* PCI Built-In SelfTest Register */ +#define PCI_BAR_0_REGISTER 0x10 /* PCI Base Address Register 0 */ +#define PCI_BAR_1_REGISTER 0x14 /* PCI Base Address Register 1 */ +#define PCI_BAR_2_REGISTER 0x18 /* PCI Base Address Register 2 */ +#define PCI_BAR_3_REGISTER 0x1C /* PCI Base Address Register 3 */ +#define PCI_BAR_4_REGISTER 0x20 /* PCI Base Address Register 4 */ +#define PCI_BAR_5_REGISTER 0x24 /* PCI Base Address Register 5 */ +#define PCI_EXPANSION_ROM 0x30 /* PCI Expansion ROM Base Register */ +#define PCI_MIN_GNT_REGISTER 0x3E /* PCI Min-Gnt Register */ +#define PCI_MAX_LAT_REGISTER 0x3F /* PCI Max_Lat Register */ +#define PCI_NODE_ADDR_REGISTER 0x40 /* PCI Node Address Register */ + +/* PCI access methods */ +#define P_CONF_T1 1 +#define P_CONF_T2 2 + +/* max number of pci buses */ +#define MAX_PCI_BUSES 0xFF + +/* number of PCI config bytes to access */ +#define PCI_BYTE 1 +#define PCI_WORD 2 +#define PCI_DWORD 4 + +/* adapter vendor & device ids */ +#define PCI_OHIO_BOARD 0x10f0 /* subdevice ID, Ohio dual port nic */ + +/* PCI related constants */ +#define CMD_IO_ENBL BIT_0 +#define CMD_MEM_ENBL BIT_1 +#define CMD_BUS_MASTER BIT_2 +#define P_TEST_PATN 0xCDEF +#define PO_DEV_NO 11 +#define PO_BUS_NO 16 +#define PO_FUN_NO 8 +#define P_CSPACE 0x80000000 + +/* PCI addresses */ +#define PCI_SPACE_ENABLE 0xCF8 +#define CF1_CONFIG_ADDR_REGISTER 0x0CF8 +#define CF1_CONFIG_DATA_REGISTER 0x0CFC +#define CF2_FORWARD_REGISTER 0x0CFA +#define CF2_BASE_ADDRESS 0xC000 + +/* PCI Device ID - for internal use */ +#define PCI_DEV_NO 0x00FF +#define PCI_BUS_NO 0xFF00 + +/* PCI configuration space definitions */ +#define PCI_CMD_OFFSET 0x4 /* command register offset */ +#define PCI_IO_ENABLE 0x00000001 /* I/O space access */ +#define PCI_MEM_ENABLE 0x00000002 /* memory space access */ +#define PCI_MASTER 0x00000004 /* bus master enabled */ +#define PCI_IO_ADDR 0x00000001 /* BAR is an I/O space */ + +/* 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 */ +/* Added 82559S rev ID */ +#define D101S_REV_ID 9 /* 82559S A-step */ +#define D102_REV_ID 12 +#define D102C_REV_ID 13 /* 82550 step C */ + +/* PHY 100 MDI Register/Bit Definitions*/ + +/* MDI register set*/ +#define MDI_CONTROL_REG 0x00 /* MDI control register */ +#define MDI_STATUS_REG 0x01 /* MDI Status regiser */ +#define PHY_ID_REG_1 0x02 /* Phy indentification reg (word 1) */ +#define PHY_ID_REG_2 0x03 /* Phy indentification reg (word 2) */ +#define AUTO_NEG_ADVERTISE_REG 0x04 /* Auto-negotiation advertisement */ +#define AUTO_NEG_LINK_PARTNER_REG 0x05 /* Auto-negotiation link partner + * ability */ +#define AUTO_NEG_EXPANSION_REG 0x06 /* Auto-negotiation expansion */ +#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##################### */ + +/* MDI Control register bit definitions*/ +#define MDI_CR_COLL_TEST_ENABLE BIT_7 /* Collision test enable */ +#define MDI_CR_FULL_HALF BIT_8 /* FDX =1, half duplex =0 */ +#define MDI_CR_RESTART_AUTO_NEG BIT_9 /* Restart auto negotiation */ +#define MDI_CR_ISOLATE BIT_10 /* Isolate PHY from MII */ +#define MDI_CR_POWER_DOWN BIT_11 /* Power down */ +#define MDI_CR_AUTO_SELECT BIT_12 /* Auto speed select enable */ +#define MDI_CR_10_100 BIT_13 /* 0 = 10Mbs, 1 = 100Mbs */ +#define MDI_CR_LOOPBACK BIT_14 /* 0 = normal, 1 = loopback */ +#define MDI_CR_RESET BIT_15 /* 0 = normal, 1 = PHY reset */ + +/* MDI Status register bit definitions*/ +#define MDI_SR_EXT_REG_CAPABLE BIT_0 /* Extended register capabilities */ +#define MDI_SR_JABBER_DETECT BIT_1 /* Jabber detected */ +#define MDI_SR_LINK_STATUS BIT_2 /* Link Status -- 1 = link */ +#define MDI_SR_AUTO_SELECT_CAPABLE BIT_3 /* Auto speed select capable */ +#define MDI_SR_REMOTE_FAULT_DETECT BIT_4 /* Remote fault detect */ +#define MDI_SR_AUTO_NEG_COMPLETE BIT_5 /* Auto negotiation complete */ +#define MDI_SR_10T_HALF_DPX BIT_11 /* 10BaseT Half Duplex capable */ +#define MDI_SR_10T_FULL_DPX BIT_12 /* 10BaseT full duplex capable */ +#define MDI_SR_TX_HALF_DPX BIT_13 /* TX Half Duplex capable */ +#define MDI_SR_TX_FULL_DPX BIT_14 /* TX full duplex capable */ +#define MDI_SR_T4_CAPABLE BIT_15 /* T4 capable */ + +/* Auto-Negotiation advertisement register bit definitions*/ +#define NWAY_AD_SELCTOR_FIELD BIT_0_4 /* identifies supported protocol */ +#define NWAY_AD_ABILITY BIT_5_12 /* technologies supported */ +#define NWAY_AD_10T_HALF_DPX BIT_5 /* 10BaseT Half Duplex capable */ +#define NWAY_AD_10T_FULL_DPX BIT_6 /* 10BaseT full duplex capable */ +#define NWAY_AD_TX_HALF_DPX BIT_7 /* TX Half Duplex capable */ +#define NWAY_AD_TX_FULL_DPX BIT_8 /* TX full duplex capable */ +#define NWAY_AD_T4_CAPABLE BIT_9 /* T4 capable */ +#define NWAY_AD_REMOTE_FAULT BIT_13 /* indicates local remote fault */ +#define NWAY_AD_RESERVED BIT_14 /* reserved */ +#define NWAY_AD_NEXT_PAGE BIT_15 /* Next page (not supported) */ + +/* Auto-Negotiation link partner ability register bit definitions*/ +#define NWAY_LP_SELCTOR_FIELD BIT_0_4 /* identifies supported protocol */ +#define NWAY_LP_ABILITY BIT_5_12 /* technologies supported */ +#define NWAY_LP_REMOTE_FAULT BIT_13 /* indic8 partner remote fault */ +#define NWAY_LP_ACKNOWLEDGE BIT_14 /* acknowledge */ +#define NWAY_LP_NEXT_PAGE BIT_15 /* Next page (not supported) */ + +/* Auto-Negotiation expansion register bit definitions*/ +#define NWAY_EX_LP_NWAY BIT_0 /* link partner is NWAY */ +#define NWAY_EX_PAGE_RECEIVED BIT_1 /* link code word received */ +#define NWAY_EX_NEXT_PAGE_ABLE BIT_2 /* local is next page able */ +#define NWAY_EX_LP_NEXT_PAGE_ABLE BIT_3 /* partner is next page able */ +#define NWAY_EX_PARALLEL_DET_FLT BIT_4 /* parallel detection fault */ +#define NWAY_EX_RESERVED BIT_5_15 /* reserved */ + + +/* 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 */ +#define PHY_100_ER0_WAKE_UP BIT_2 /* Wake up DAC */ +#define PHY_100_ER0_RESERVED BIT_3_4 /* Reserved */ +#define PHY_100_ER0_REV_CNTRL BIT_5_7 /* Revsion control (A step = 000) */ +#define PHY_100_ER0_FORCE_FAIL BIT_8 /* Force Fail is enabled */ +#define PHY_100_ER0_TEST BIT_9_13 /* Revsion control (A step = 000) */ +#define PHY_100_ER0_LINKDIS BIT_14 /* Link integrity test disabled */ +#define PHY_100_ER0_JABDIS BIT_15 /* Jabber function is disabled */ + + +/* PHY 100 Extended Register 1 bit definitions*/ +#define PHY_100_ER1_RESERVED BIT_0_8 /* Reserved */ +#define PHY_100_ER1_CH2_DET_ERR BIT_9 /* Channel 2 EOF detection error */ +#define PHY_100_ER1_MANCH_CODE_ERR BIT_10 /* Manchester code error */ +#define PHY_100_ER1_EOP_ERR BIT_11 /* EOP error */ +#define PHY_100_ER1_BAD_CODE_ERR BIT_12 /* bad code error */ +#define PHY_100_ER1_INV_CODE_ERR BIT_13 /* invalid code error */ +#define PHY_100_ER1_DC_BAL_ERR BIT_14 /* DC balance error */ +#define PHY_100_ER1_PAIR_SKEW_ERR BIT_15 /* Pair skew error */ + +/* 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 */ + +/* Return status for xmit bufs */ +#define E_NOBUFS 0x10 /* no more buffers */ +#define E_NOCBUFS 0x20 /* no more coalesce buffers */ + +#define XMITS_PER_INTR 4 + +/* Size of loadable micro code image for each supported chip. */ +#ifndef D100_NUM_MICROCODE_DWORDS +#define D100_NUM_MICROCODE_DWORDS 66 +#endif +#ifndef D101_NUM_MICROCODE_DWORDS +#define D101_NUM_MICROCODE_DWORDS 102 +#endif +#ifndef D101M_NUM_MICROCODE_DWORDS +#define D101M_NUM_MICROCODE_DWORDS 134 +#endif +#ifndef D101S_NUM_MICROCODE_DWORDS +#define D101S_NUM_MICROCODE_DWORDS 134 +#endif +#ifndef D102_NUM_MICROCODE_DWORDS +#define D102_NUM_MICROCODE_DWORDS 134 +#endif +#ifndef D102C_NUM_MICROCODE_DWORDS +#define D102C_NUM_MICROCODE_DWORDS 134 +#endif + +/* ====================================================================== */ +/* checksumming */ +/* ====================================================================== */ + +/* Note: we support TCP and UDP, not IPv4 checksums. IPv4 checksums must be + * done in software + */ +#define HDR_LEN_MSK 0x0F +#define PROTOCOL_TYPE_MASK 0x00FF +#define PROTOCOL_VERSION_MASK 0x00FF +#define TCP_PROTOCOL 6 +#define UDP_PROTOCOL 17 +#define NUMBER_OF_BOARDS 4 +#define IP_8022_DSAPSSAP 0x5E5E +#define IP_8022_DOD_DSAPSSAP 0x0606 +#define IPv4_NIBBLE 4 +#define MAX_PKT_LEN_FIELD 1500 +#define MIN_IP_PKT_SIZE 50 /* 14 for the MAC Header */ +#define PROTOCOL_ID_LEN 5 +#define ADDRESS_LEN 6 +#define FRAG_OFFSET_MASK 0xFF1F +#define HARDWARE_CHECKSUM_START_OFFSET 14 +#define CRC_LENGTH 4 +#define IP_PROTOCOL 0x0008 /* Network Byte order */ +#define CHKSUM_SIZE 2 + +#define IP_HEADER_NO_OPTIONS_SIZE 20 + +#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 + +/* Macro to adjust for carry in our adjust value */ +#define CHECK_FOR_CARRY(_XSUM) (((_XSUM << 16) | (_XSUM >> 16)) + _XSUM) >> 16; + +/* byte swap a 2 byte value */ +#ifndef BYTE_SWAP_WORD +#define BYTE_SWAP_WORD(value) ( (((uint16_t)(value) & 0x00ff) << 8) | (((uint16_t)(value) & 0xff00) >> 8) ) +#endif + +/* Word swap a 4 byte value */ +#define WORD_SWAP_DWORD(value) ( (((uint32_t)(value) & 0x0000FFFF) << 16) | (((uint32_t)(value) & 0xFFFF0000) >> 16) ) + + +typedef struct _ethernet_ii_header_ +{ + uint8_t DestAddr[ADDRESS_LEN]; + uint8_t SourceAddr[ADDRESS_LEN]; + uint16_t TypeLength; + +} ethernet_ii_header, *pethernet_ii_header; + +/********************************************************************** */ +/* Ethernet SNAP Header Definition */ +/********************************************************************** */ + +typedef struct _ethernet_snap_header_ +{ + uint8_t DestAddr[ADDRESS_LEN]; + uint8_t SourceAddr[ADDRESS_LEN]; + uint16_t TypeLength; + uint8_t DSAP; + uint8_t SSAP; + uint8_t Ctrl; + uint8_t ProtocolId[PROTOCOL_ID_LEN]; + +} ethernet_snap_header, *pethernet_snap_header; + +/********************************************************************** */ +/* Internet Protocol Version 4 (IPV4) Header Definition */ +/********************************************************************** */ + +typedef struct _ip_v4_header_ { + uint32_t HdrLength:4, /* Network Byte order */ + HdrVersion:4, /* Network Byte order */ + TOS:8, /* Network Byte order */ + Length:16; /* Network Byte order */ + + union { + uint32_t IdThruOffset; + + struct { + uint32_t DatagramId:16, FragOffset1:5, /* Network Byte order */ + MoreFragments:1, NoFragment:1, Reserved2:1, FragOffset:8; + } Bits; + + struct { + uint32_t DatagramId:16, FragsNFlags:16; /* Network Byte order */ + } Fields; + + } FragmentArea; + + uint8_t TimeToLive; + uint8_t ProtocolCarried; + uint16_t Checksum; + + union { + uint32_t SourceIPAddress; + + struct { + uint32_t SrcAddrLo:16, /* Network Byte order */ + SrcAddrHi:16; + } Fields; + + struct { + uint32_t OctA:8, OctB:8, OctC:8, OctD:8; + } SFields; + + } SrcAddr; + + union { + uint32_t TargetIPAddress; + + struct { + uint32_t DestAddrLo:16, /* Network Byte order */ + DestAddrHi:16; + } Fields; + + struct { + uint32_t OctA:8, OctB:8, OctC:8, OctD:8; + } DFields; + + } DestAddr; + + + uint16_t IpOptions[20]; /* Maximum of 40 bytes (20 words) of IP options */ + +} ip_v4_header; + + +/********************************************************************** */ +/* Ethernet II IP Packet Definition */ +/********************************************************************** */ + +typedef struct _ethernet_ii_ipv4_packet_ +{ + ethernet_ii_header Ethernet; /* Ethernet II Header */ + + ip_v4_header IpHeader; /* IP Header (No Options) */ + +} ethernet_ii_ipv4_packet, *pethernet_ii_ipv4_packet; + +/********************************************************************** */ +/* Ethernet SNAP IP Packet Definition */ +/********************************************************************** */ + +typedef struct _ethernet__snap_ipv4_packet_ +{ + ethernet_snap_header Ethernet; /* Ethernet SNAP Header */ + + ip_v4_header IpHeader; /* IP Header (No Options) */ + +} ethernet_snap_ipv4_packet, *pethernet_snap_ipv4_packet; + +/********************************************************************** */ +/* TCP Header Definition */ +/********************************************************************** */ + +typedef struct _tcp_header_ +{ + uint16_t SourcePort; + uint16_t TargetPort; + uint32_t SourceSeqNum; + uint32_t AckSeqNum; + uint8_t HeaderLen_Rsvd; + uint8_t SessionBits; + uint16_t WindowSize; + uint16_t Checksum; + uint16_t UrgentDataPointer; + +} tcp_header, *ptcp_header; + +/********************************************************************** */ +/* UDP Header Definition */ +/********************************************************************** */ + +typedef struct _udp_header_ +{ + uint16_t SourcePort; + uint16_t TargetPort; + uint16_t Length; + uint16_t Checksum; + +} udp_header, *pudp_header; + +/* checksumming function prototypes */ +static boolean_t e100_calculate_checksum (ip_v4_header * IPPacket, + uint32_t HeaderOffset, + struct sk_buff *skb, + uint32_t packetSize); +ip_v4_header *e100_check_for_ip (int *HeaderOffset, struct sk_buff *skb); + + +#define E100_NAME "e100" + +/* Bits for bdp->flags */ +#define BOARD_PRESENT 0x0001 +#define BOARD_DISABLED 0x0002 +#define DF_OPENED 0x0004 +#define DF_UCODE_LOADED 0x0008 +#define DF_PHY_82555 0x2000 +#define DF_SPEED_FORCED 0x4000 /* set if speed is forced */ +#define DF_LINK_UP 0x8000 /* set if link is up */ + +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:TxDescriptors[bdp->bd_number]-1) +#define NEXT_TCB_TOUSE(X) ((((X)+1) >= TxDescriptors[bdp->bd_number] )? 0:(X)+1) +#define TCB_TO_USE(X) ((X)->tail) +#define TCBS_AVAIL(X) (NEXT_TCB_TOUSE( NEXT_TCB_TOUSE((X)->tail)) != (X)->head) + +/* leave a gap of 2 TCB's in e100_tx_srv */ +#define IS_IT_GAP(X) (NEXT_TCB_TOUSE(NEXT_TCB_TOUSE((X)->head))==(X)->tail) + +/* Macro to see if address is a Multicast address. Jun 22, 1999 */ +#define IS_VALID_MULTICAST(x) ((x)->bytes[0] & 0x1 ) + + + +/* Device ID macros */ +#define get_pci_dev(X) ((X)&PCI_DEV_NO) +#define get_pci_bus(X) ((X)>>8) +#define mk_pci_dev_id(X,Y) (((X)<<8)|((Y)&PCI_DEV_NO)) + +#define E100_MIN(X,Y) ( (X) < (Y)? (X):(Y) ) +#define RFD_POINTER(X,Y) ((rfd_t *) (((unsigned char *)((X)->data))-((Y)->rfd_size))) +#define SKB_RFD_COMPLETE(X,Y) ((RFD_POINTER((X),(Y)))->rfd_header.cb_status) +#define NEXT_SKB(X,Y) ((RFD_POINTER((X),(Y)))->next) +#define GET_SKB_DMA_ADDR(skb,bddp) ((RFD_POINTER(skb,bddp))->dma_addr) +/* ====================================================================== */ +/* 82557 */ +/* ====================================================================== */ + + +#define D102_RFD_EXTRA_SIZE 16 + + +typedef union +{ + uint8_t bytes[ETHERNET_ADDRESS_LENGTH]; + uint16_t words[ETHERNET_ADDRESS_LENGTH / 2]; +} e100_eaddr_t; + + + +typedef struct +{ + uint32_t etherAlignErrors; /* Frame alignment errors */ + uint32_t etherCRCerrors; /* CRC erros */ + uint32_t etherMissedPkts; /* Packet overflow or missed inter */ + uint32_t etherOverrunErrors; /* Overrun errors */ + uint32_t etherUnderrunErrors; /* Underrun errors */ + uint32_t etherCollisions; /* Total collisions */ + uint32_t etherAbortErrors; /* Transmits aborted at interface */ + uint32_t etherCarrierLost; /* Carrier sense signal lost */ + uint32_t etherReadqFull; /* STREAMS read queue full */ + uint32_t etherRcvResources; /* Receive resource alloc faliure */ + uint32_t etherDependent1; /* Device dependent statistic */ + uint32_t etherDependent2; /* Device dependent statistic */ + uint32_t etherDependent3; /* Device dependent statistic */ + uint32_t etherDependent4; /* Device dependent statistic */ + uint32_t etherDependent5; /* Device dependent statistic */ +} e100_etherstat_t; + +/* Ethernet Frame Structure */ +/*- Ethernet 6-byte Address */ +typedef struct _eth_address_t +{ + uint8_t eth_node_addr[ETHERNET_ADDRESS_LENGTH]; +} eth_address_t, *peth_address_t; + + +/*- Ethernet 14-byte Header */ +typedef struct _eth_header_t +{ + uint8_t eth_dest[ETHERNET_ADDRESS_LENGTH]; + uint8_t eth_src[ETHERNET_ADDRESS_LENGTH]; + uint16_t eth_typelen; +} eth_header_t, *peth_header_t __attribute__ ((__packed__)); + + +/*- Ethernet Buffer (Including Ethernet Header) for Transmits */ +typedef struct _eth_tx_buffer_t +{ + eth_header_t tx_mac_hdr; + uint8_t tx_buff_data[(TCB_BUFFER_SIZE - sizeof (eth_header_t))]; +} eth_tx_buffer_t, *peth_tx_buffer_t __attribute__ ((__packed__)); + +typedef struct _eth_rx_buffer_t +{ + eth_header_t rx_mac_hdr; + uint8_t rx_buff_data[(RCB_BUFFER_SIZE - sizeof (eth_header_t)) + + CHKSUM_SIZE]; +} eth_rx_buffer_t, *peth_rx_buffer_t __attribute__ ((__packed__)); + +/* Changed for 82558 enhancement */ +typedef struct _d101_scb_ext_t +{ + volatile uint32_t scb_rx_dma_cnt; /* Rx DMA byte count */ + volatile uint8_t scb_early_rx_int; /* Early Rx DMA byte count */ + volatile uint8_t scb_fc_thld; /* Flow Control threshold */ + volatile uint8_t scb_fc_xon_xoff; /* Flow Control XON/XOFF values */ + volatile uint8_t scb_pmdr; /* Power Mgmt. Driver Reg */ +} d101_scb_ext __attribute__ ((__packed__)); + +/* Changed for 82559 enhancement */ +typedef struct _d101m_scb_ext_t +{ + volatile uint32_t scb_rx_dma_cnt; /* Rx DMA byte count */ + volatile uint8_t scb_early_rx_int; /* Early Rx DMA byte count */ + volatile uint8_t scb_fc_thld; /* Flow Control threshold */ + volatile uint8_t scb_fc_xon_xoff; /* Flow Control XON/XOFF values */ + volatile uint8_t scb_pmdr; /* Power Mgmt. Driver Reg */ + volatile uint8_t scb_gen_ctrl; /* General Control */ + volatile uint8_t scb_gen_stat; /* General Status */ + volatile uint16_t scb_reserved; /* Reserved */ + volatile uint32_t scb_function_event; /* Cardbus Function Event */ + volatile uint32_t scb_function_event_mask; /* Cardbus Function Mask */ + volatile uint32_t scb_function_present_state; /* Cardbus Function state */ + volatile uint32_t scb_force_event; /* Cardbus Force Event */ +} d101m_scb_ext __attribute__ ((__packed__)); + +/* Changed for 82550 enhancement */ +typedef struct _d102_scb_ext_t +{ + volatile uint32_t scb_rx_dma_cnt; /* Rx DMA byte count */ + volatile uint8_t scb_early_rx_int; /* Early Rx DMA byte count */ + volatile uint8_t scb_fc_thld; /* Flow Control threshold */ + volatile uint8_t scb_fc_xon_xoff; /* Flow Control XON/XOFF values */ + volatile uint8_t scb_pmdr; /* Power Mgmt. Driver Reg */ + volatile uint8_t scb_gen_ctrl; /* General Control */ + volatile uint8_t scb_gen_stat; /* General Status */ + volatile uint8_t scb_gen_ctrl2; + volatile uint8_t scb_reserved; /* Reserved */ + volatile uint32_t scb_scheduling_reg; + volatile uint32_t scb_reserved2; + volatile uint32_t scb_function_event; /* Cardbus Function Event */ + volatile uint32_t scb_function_event_mask; /* Cardbus Function Mask */ + volatile uint32_t scb_function_present_state; /* Cardbus Function state */ + volatile uint32_t 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 bdd, which hangs of the bdp. This is the brain of it. + */ +typedef struct _scb_t +{ + volatile uint16_t scb_status; /* SCB Status register */ + volatile uint8_t scb_cmd_low; /* SCB Command register (low byte) */ + volatile uint8_t scb_cmd_hi; /* SCB Command register (high byte) */ + volatile uint32_t scb_gen_ptr; /* SCB General pointer */ + volatile uint32_t scb_port; /* PORT register */ + volatile uint16_t scb_flsh_cntrl; /* Flash Control register */ + volatile uint16_t scb_eprm_cntrl; /* EEPROM control register */ + volatile uint32_t scb_mdi_cntrl; /* MDI Control Register */ + /* Changed for 82558 enhancement */ + union { + volatile uint32_t scb_rx_dma_cnt; /* Rx DMA byte count */ + volatile d101_scb_ext d101_scb; /* 82558/9 specific fields */ + volatile d101m_scb_ext d101m_scb; /* 82559 specific fields */ + volatile d102_scb_ext d102_scb; + } scb_ext; +} scb_t, *pscb_t __attribute__ ((__packed__)); + +/* Self test + * This is used to dump results of the self test + */ +typedef struct _self_test_t +{ + uint32_t st_sign; /* Self Test Signature */ + uint32_t st_result; /* Self Test Results */ +} self_test_t, *pself_test_t __attribute__ ((__packed__)); + + + +/* Error Counters */ +typedef struct _err_cntr_t +{ + uint32_t xmt_gd_frames; /* Good frames transmitted */ + uint32_t xmt_max_coll; /* Fatal frames -- had max collisions */ + uint32_t xmt_late_coll; /* Fatal frames -- had a late coll. */ + uint32_t xmt_uruns; /* Xmit underruns (fatal or re-transmit) */ + uint32_t xmt_lost_crs; /* Frames transmitted without CRS */ + uint32_t xmt_deferred; /* Deferred transmits */ + uint32_t xmt_sngl_coll; /* Transmits that had 1 and only 1 coll. */ + uint32_t xmt_mlt_coll; /* Transmits that had multiple coll. */ + uint32_t xmt_ttl_coll; /* Transmits that had 1+ collisions. */ + uint32_t rcv_gd_frames; /* Good frames received */ + uint32_t rcv_crc_errs; /* Aligned frames that had a CRC error */ + uint32_t rcv_algn_errs; /* Receives that had alignment errors */ + uint32_t rcv_rsrc_err; /* Good frame dropped cuz no resources */ + uint32_t rcv_oruns; /* Overrun errors - bus was busy */ + uint32_t rcv_err_coll; /* Received frms. that encountered coll. */ + uint32_t rcv_shrt_frames; /* Received frames that were to short */ + uint32_t cmd_complete; /* A005h indicates cmd completion */ +} err_cntr_t, *perr_cntr_t; + + +/* Command Block (CB) Generic Header Structure*/ +typedef struct _cb_header_t +{ + uint16_t cb_status; /* Command Block Status */ + uint16_t cb_cmd; /* Command Block Command */ + uint32_t cb_lnk_ptr; /* Link To Next CB */ +} cb_header_t, *pcb_header_t __attribute__ ((__packed__)); + + +/* NOP Command Block (NOP_CB) */ +typedef struct _nop_cb_t +{ + cb_header_t nop_cb_hdr; +} nop_cb_struc, *pnop_cb_struc __attribute__ ((__packed__)); + + +/* Individual Address Command Block (IA_CB)*/ +typedef struct _ia_cb_t +{ + cb_header_t ia_cb_hdr; + uint8_t ia_addr[ETHERNET_ADDRESS_LENGTH]; +} ia_cb_t, *pia_cb_t __attribute__ ((__packed__)); + + +/* Configure Command Block (CONFIG_CB)*/ +typedef struct _config_cb_t +{ + cb_header_t cfg_cbhdr; + uint8_t cfg_byte[CB_CFIG_BYTE_COUNT]; +} config_cb_t, *pconfig_cb_t __attribute__ ((__packed__)); + + +/* MultiCast Command Block (MULTICAST_CB)*/ +typedef struct _multicast_cb_t +{ + cb_header_t mc_cbhdr; + uint16_t mc_count; /* Number of multicast addresses */ + uint8_t mc_addr[(ETHERNET_ADDRESS_LENGTH * MAX_MULTICAST_ADDRS)]; +} mltcst_cb_t, *pmltcst_cb_t __attribute__ ((__packed__)); + + +/* Dump Command Block (DUMP_CB)*/ +typedef struct _dump_cb_t +{ + cb_header_t DumpCBHeader; + uint32_t DumpAreaAddress; /* Dump Buffer Area Address */ +} dump_cb_t, *pdump_cb_t __attribute__ ((__packed__)); + + +/* Dump Area structure definition*/ +typedef struct _dump_area_t +{ + uint8_t DumpBuffer[DUMP_BUFFER_SIZE]; +} dump_area_t, *pdump_area_t; + + +/* Diagnose Command Block (DIAGNOSE_CB)*/ +typedef struct _diagnose_cb_t +{ + cb_header_t DiagCBHeader; +} diagnose_cb_t, *pdiagnose_cb_t __attribute__ ((__packed__)); + +/* Load Microcode Command Block (LOAD_UCODE_CB)*/ +typedef struct _load_ucode_cb_t +{ + cb_header_t load_ucode_cbhdr; + uint32_t ucode_dword[D102_NUM_MICROCODE_DWORDS]; +} load_ucode_cb_t, *pload_ucode_cb_t __attribute__ ((__packed__)); + +/* NON_TRANSMIT_CB -- Generic Non-Transmit Command Block , doesnot include + * MultiCast as the addresses need to be saved + */ +typedef struct _nxmit_cb_t +{ + union { + config_cb_t config; + ia_cb_t setup; + dump_cb_t dump; + load_ucode_cb_t load_ucode; + mltcst_cb_t multicast; + } ntcb; +} nxmit_cb_t, *pnxmit_cb_t __attribute__ ((__packed__)); + + +/* 82558 specific Extended TCB fields */ +typedef struct _tcb_ext_t +{ + uint32_t tbd0_buf_addr; /* Physical Transmit Buffer Address */ + uint32_t tbd0_buf_cnt; /* Actual Count Of Bytes */ + uint32_t tbd1_buf_addr; /* Physical Transmit Buffer Address */ + uint32_t tbd1_buf_cnt; /* Actual Count Of Bytes */ + eth_tx_buffer_t tcb_data; /* Data buffer in TCB */ +} tcb_ext_t __attribute__ ((__packed__)); + + + + +/* some defines for the ipcb */ +#define IPCB_HARDWAREPARSING_ENABLE 0x010 +#define IPCB_IP_ACTIVATION_DEFAULT IPCB_HARDWAREPARSING_ENABLE + +/* d102 specific fields */ +typedef struct _tcb_ipcb_t +{ + uint scheduling:20; + uint ip_activation:12; + uint16_t vlan; + uint8_t ip_header_offset; + uint8_t tcp_header_offset; + union { + uint32_t sec_rec_phys_addr; + uint32_t tbd_zero_address; + } tbd_sec_addr; + union { + uint16_t sec_rec_size; + uint16_t tbd_zero_size; + } tbd_sec_size; + uint16_t total_tcp_payload; + eth_tx_buffer_t tcb_data; +} tcb_ipcb_t __attribute__ ((__packed__)); + +/* Generic 82557 TCB fields */ +typedef struct _tcb_gen_t +{ + eth_tx_buffer_t tcb_data; /* Data buffer in TCB */ + uint32_t pad0; /* filler */ + uint32_t pad1; /* filler */ + uint32_t pad2; /* filler */ + uint32_t pad3; /* filler */ +} tcb_gen_t __attribute__ ((__packed__)); + +/* Transmit Command Block (TCB)*/ +struct _tcb_t +{ + cb_header_t tcb_hdr; + uint32_t tcb_tbd_ptr; /* TBD address */ + uint16_t tcb_cnt; /* Data Bytes In TCB past header */ + uint8_t tcb_thrshld; /* TX Threshold for FIFO Extender */ + uint8_t tcb_tbd_num; + + union { + tcb_ipcb_t ipcb; /* d102 ipcb fields */ + tcb_ext_t tcb_ext; /* 82558 extended TCB fields */ + tcb_gen_t tcb_gen; /* Generic 82557 fields */ + } 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 ). + */ + sk_buff_t *tcb_skb; /* the associated socket buffer */ + int tcb_cbflag; /* set if using the coalesce buffer */ + int tcb_msgsz; + uint32_t dma_data_addr; + uint32_t tcb_paddr; /* phys addr of the TCB */ +} __attribute__ ((__packed__)); + + +#ifndef _TCB_T_ +#define _TCB_T_ +typedef struct _tcb_t tcb_t, *ptcb_t; +#endif + + +/* Transmit Buffer Descriptor (TBD)*/ +typedef struct _tbd_t +{ + uint32_t tbd_buf_addr; /* Physical Transmit Buffer Address */ + uint32_t tbd_buf_cnt; /* Actual Count Of Bytes */ +} tbd_t, *ptbd_t __attribute__ ((__packed__)); + + +/* Receive Frame Descriptor (RFD) - will be using the simple model*/ +struct _rfd_t +{ + /* 8255x */ + cb_header_t rfd_header; + uint32_t rfd_rbd_ptr; /* Receive Buffer Descriptor Addr */ + uint16_t rfd_act_cnt; /* Number Of Bytes Received */ + uint16_t rfd_sz; /* Number Of Bytes In RFD */ + /* D102 aka Gamla */ + uint16_t vlanid; + uint8_t rcvparserstatus; + uint8_t reserved; + uint16_t securitystatus; + uint8_t checksumstatus; + uint8_t zerocopystatus; + + uint8_t fill[8]; + + eth_rx_buffer_t rfd_buf; /* Data buffer in RFD */ + sk_buff_t *prev; /* skb containing previous RFD */ + sk_buff_t *next; /* skb containing next RFD */ + device_t *dev; /* identify which dev this RFD belongs to */ + dma_addr_t dma_addr; +} __attribute__ ((__packed__)); + +#ifndef _RFD_T_ +#define _RFD_T_ +typedef struct _rfd_t rfd_t, *prfd_t; +#endif + + + +/* Receive Buffer Descriptor (RBD)*/ +typedef struct _rbd_t +{ + uint16_t rbd_act_cnt; /* Number Of Bytes Received */ + uint16_t rbd_filler; + uint32_t rbd_lnk_addr; /* Link To Next RBD */ + uint32_t rbd_rcb_addr; /* Receive Buffer Address */ + uint16_t rbd_sz; /* Receive Buffer Size */ + uint16_t rbd_filler1; +} rbd_t, *prbd_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 +{ + uint_t head; /* index to first used resource */ + uint_t tail; /* index to last used resource */ + uint_t count; /* not used for tx pool */ + void *data; /* points to resource pool */ +} buf_pool_t, *pbuf_pool_t; + +typedef struct _bdd_t +{ + uint_t bd_number; /* Board Number */ + uint_t phy_addr; /* address of PHY component */ + uint32_t flags; + uint32_t io_base; /* IO base address */ + size_t mem_size; /* Memory size from devmem_size */ + pscb_t scbp; /* memory mapped ptr to 82557 scb */ + pself_test_t pselftest; /* pointer to self test area */ + dma_addr_t selftest_paddr; /* phys addr of selftest */ + perr_cntr_t pstats_counters; /* pointer to stats table */ + dma_addr_t stat_cnt_paddr; /* phys addr of stat counter area */ + pdump_area_t pdump_area; /* pointer to 82557 reg. dump area */ + dma_addr_t dump_paddr; /* phys addr of dump area */ + pnxmit_cb_t pntcb; /* pointer to non xmit tcb */ + dma_addr_t nontx_paddr; /* phys addr of non-tx tcb */ + perr_stats_t perr_stats; /* ptr to error statictics results */ + dma_addr_t estat_paddr; /* phys addr of err stat results */ + buf_pool_t tcb_pool; + dma_addr_t tcb_paddr; /* phys addr of start of TCBs */ + void *tcb_pool_base; + buf_pool_t tbd_pool; + dma_addr_t tbd_paddr; /* phys addr of start of TBDs */ + sk_buff_t *rfd_head; + sk_buff_t *rfd_tail; + int skb_req; + uint32_t tx_per_underrun; + uint16_t cur_line_speed; + uint16_t cur_dplx_mode; + ulong_t cur_link_status; + ulong_t ans_line_speed; + ulong_t ans_dplx_mode; + uint8_t perm_node_address[ETHERNET_ADDRESS_LENGTH]; + uint32_t pwa_no; /* PWA: xxxxxx-0xx */ + uint8_t tx_thld; /* stores transmit threshold */ + uint8_t prev_cu_cmd; /* determines CU state - idle/susp */ + uint8_t prev_scb_cmd; /* last actual cmd */ + int brdcst_dsbl; /* if set, disables broadcast */ + int mulcst_enbl; /* if set, enables all multicast */ + int promisc; + int prev_rx_mode; + + /* Changed for 82558 and 82559 enhancements */ + uint32_t old_xmits; /* number of good xmits */ + uint32_t num_cna_interrupts; /* number of interrupts */ + uint_t current_cna_backoff; /* CNA Intr. Delay */ + uint32_t xmits; /* num of xmits for e100_adjust_cid() */ + uint_t PhyState; + uint_t PhyDelay; + uint_t PhyId; + uint16_t EEpromSize; + + /* PCI info */ + uint16_t ven_id; + uint16_t dev_id; + uint16_t sub_ven_id; + uint16_t sub_dev_id; + uint16_t pci_cmd_word; + uint8_t rev_id; + uint8_t dev_num; + + /* stuff out of the system dev structure */ + pci_dev_t *pci_dev; /* pci device struct pointer */ + + uint8_t port_num; /* For Ohio */ + uint8_t ucode_loaded; /* For rcv. inter ucode */ + + /* flag to indicate Checksum offloading is enabled */ + uint8_t checksum_offload_enabled; + + struct bdconfig *bdp; /* pointer back to the bd_config */ + /* Lock defintions for the driver */ + spinlock_t bd_lock; /* board lock */ + spinlock_t bd_intr_lock; /* Interrupt lock */ + spinlock_t bd_tx_lock; /* Transmit lock */ + spinlock_t bd_rx_lock; /* Receive lock */ + spinlock_t bd_srv_lock; /* Service routine lock */ + + /* Linux statistics */ + struct net_device_stats net_stats; + + /* 82562EH variables */ + uint16_t Phy82562EHSampleCount; + uint16_t Phy82562EHSampleDelay; + uint16_t Phy82562EHSampleFilter; + + uint16_t rfd_size; +} bdd_t, *pbdd_t; + +enum zero_lock_state_e { ZLOCK_INITIAL, ZLOCK_READING, ZLOCK_SLEEPING }; + +struct bdconfig +{ + struct bdconfig *bd_next; /* pointer to next bd in chain */ + struct bdconfig *bd_prev; /* pointer to prev bd in chain */ + uint unit; /* from mdi_get_unit */ + uint32_t io_start; /* start of I/O base address */ + uint32_t io_end; /* end of I/O base address */ + paddr_t mem_start; /* start of base mem address */ + paddr_t mem_end; /* start of base mem address */ + int irq_level; /* interrupt request level */ + int bd_number; /* board number in multi-board setup */ + int flags; /* board management flags */ + int tx_flags; /* tx management flags */ + int rx_flags; /* rx management flags */ + struct tq_struct bh_task; /* the way to run bh */ + struct timer_list timer_id; /* watchdog timer ID */ + int timer_val; /* watchdog timer value */ + int multicast_cnt; /* count of multicast address sets */ + e100_eaddr_t eaddr; /* Ethernet address storage */ + int Bound; /* flag for MAC_BIND_REQ */ + bdd_t *bddp; + caddr_t rx_srv_count; + caddr_t pci_dev_id; + caddr_t irq_link; + uint_t tx_count; + + /* these are linux only */ + struct sk_buff *last_mp_fail; + device_t *device; + pci_dev_t *ppci_dev; + uint8_t pci_bus; + uint8_t pci_dev_fun; + uint16_t vendor; + int tx_out_res; + + + enum zero_lock_state_e ZeroLockState; + uint8_t ZeroLockReadData[16]; + uint16_t ZeroLockReadCounter; + ulong ZeroLockSleepCounter; +#if (DEBUG_LINK > 0) + uint16_t ErrorCounter; +#endif + +}; + +#ifndef _BD_CONFIG_T_ +#define _BD_CONFIG_T_ +typedef struct bdconfig bd_config_t; +#endif + +/* ====================================================================== */ +/* externs */ +/* ====================================================================== */ + +/* 82562EH PHY Specific Registers */ +#define PHY_82562EH_CONTROL_REG 0x10 +/* 82562EH control register bit definitions. */ +#define PHY_82562EH_CR_RAP BIT_0 +#define PHY_82562EH_CR_HP BIT_1 /* High power 1=HIGH 0=LOW */ +#define PHY_82562EH_CR_HS BIT_2 /* High speed 1=HIGH 0=LOW */ +#define PHY_82562EH_CR_IRC BIT_15 /* Ignore Remote Commands */ + +/* 82562EH PHY address space constant define. */ +#define PHY_82562EH_ADDR_SPACE_PAGE_0 0 +#define PHY_82562EH_ADDR_SPACE_PAGE_1 1 + +/* 82562EH PHY Registers, Page 0 */ +#define PHY_82562EH_STATUS_MODE_REG 0x11 +#define PHY_82562EH_NOISE_PEAK_LVL_REG 0x18 +#define PHY_82562EH_NSE_FLOOR_CEILING_REG 0x19 +#define PHY_82562EH_NSE_ATTACK_EVENT_REG 0x1A +#define PHY_82562EH_RX_CONTROL_REG 0x1B + +/* 82562EH PHY Registers, Page 1 */ +#define PHY_82562EH_AFE_CONTROL1_REG 0x12 +#define PHY_82562EH_AFE_CONTROL2_REG 0x13 + +/* 82562EH PHY Registers Initial Values, Page 0 */ +#define PHY_82562EH_STATUS_MODE_INIT_VALUE 0x0100 /* Reg 0x11 */ +#define PHY_82562EH_RX_CR_INIT_VALUE 0x0008 /* Reg 0x1B */ + +/* 82562EH PHY Registers Initial Values, Page 1 */ +#define PHY_82562EH_AFE_CR1_INIT_VALUE 0x6600 /* Reg 0x12 */ +#define PHY_82562EH_AFE_CR2_INIT_VALUE 0x0100 /* Reg 0x11 */ + +/* 82562EH PHY S/W Init Values */ +#define PHY_82562EH_AFE_CR1_WA_INIT 0xA600 /* Page 1 Reg 0x12 */ +#define PHY_82562EH_AFE_CR2_WA_INIT 0x0900 /* Page 1 Reg 0x11 */ +#define PHY_82562EH_RX_CR_WA_INIT 0x0008 /* Page 0 Reg 0x1B */ +#define PHY_82562EH_STATUS_MODE_WA_INIT 0x0100 /* Page 0 Reg 0x11 */ +#define PHY_82562EH_NSE_ATTACK_EVENT_WA_INIT 0x0022 /* Page 0 Reg 0x1A */ +#define PHY_82562EH_NOISE_PEAK_LVL_WA_INIT 0x7F00 /* Page 0 Reg 0x19 */ + +/* 82562EH PHY Working Mode Value */ +#define PHY_82562EH_NSE_ATTACK_WORK_VALUE 0xFFF4 /* Reg 0x1A */ +#define PHY_82562EH_AFE_CR1_WORK_VALUE 0x6600 /* Reg 0x12 */ +#define PHY_82562EH_AFE_CR2_WORK_VALUE 0x0100 /* Reg 0x11 */ + +#define MILLISECOND 1000 +#define PHY_82562EH_MAX_TABLE 20 + + +/* ====================================================================== */ +/* vendor_info */ +/* ====================================================================== */ + +/* + * vendor_info_array + * + * This array contains the list of Subsystem IDs on which the driver + * should load. + * + * The format of each entry of the array is as follows: + * { VENDOR_ID, DEVICE_ID, SUBSYSTEM_VENDOR, SUBSYSTEM_DEV, REVISION, BRANDING_STRING } + * + * If there is a CATCHALL in the SUBSYSTEM_DEV field, the driver will + * load on all subsystem device IDs of that vendor. + * If there is a CATCHALL in the SUBSYSTEM_VENDOR field, the driver will + * load on all cards, irrespective of the vendor. + * + * The last entry of the array must be: + * { 0, 0, 0, 0, 0, null } + */ + +#define CATCHALL 0xffff + +typedef struct _e100_vendor_info_t +{ + uint16_t ven_id; + uint16_t dev_id; + uint16_t sub_ven; + uint16_t sub_dev; + uint16_t rev_id; + char *idstr; // String to be printed for these IDs +} e100_vendor_info_t; + +extern e100_vendor_info_t e100_vendor_info_array[]; + + +/*************************************************************************/ +/* Receive Interrupt Bundling Microcode (CPUsaver) */ +/*************************************************************************/ + + +/************************************************************************* +* 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. +*************************************************************************/ + + + +/********************************************************/ +/* 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_DWORD 72 + + +#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, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +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, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +} + + +/********************************************************/ +/* CPUSaver micro code for the D101M (B-step only) */ +/********************************************************/ + +/* Version 2.10 */ + +/* Parameter values for the D101M B-step */ +#define D101M_CPUSAVER_DWORD 78 +#define D101M_CPUSAVER_BUNDLE_MAX_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, \ +0x003806A8, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +} + + +/********************************************************/ +/* CPUSaver micro code for the D101S */ +/********************************************************/ + +/* Version 1.20 */ + +/* Parameter values for the D101S */ +#define D101S_CPUSAVER_DWORD 78 +#define D101S_CPUSAVER_BUNDLE_MAX_DWORD 67 +#define D101S_CPUSAVER_MIN_SIZE_DWORD 129 + + +#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, \ +0x00260FF8, \ +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, \ +0x00000000, \ +0x00130831, \ +0x0010090B, \ +0x00124813, \ +0x000CFF80, \ +0x00260703, \ +0x00041000, \ +0x00380700, \ +0x00000000, \ +} + + +/********************************************************/ +/* CPUSaver micro code for the D102 B-step */ +/********************************************************/ + +/* Version 1.00 */ + +/* Parameter values for the D102 B-step */ +#define D102_B_CPUSAVER_DWORD 78 +#define D102_B_CPUSAVER_BUNDLE_MAX_DWORD 67 +#define D102_B_CPUSAVER_MIN_SIZE_DWORD 116 + + +#define D102_B_RCVBUNDLE_UCODE \ +{\ +0x006f0276, \ +0xffff04d2, \ +0xffffffff, \ +0x0ed4ffff, \ +0xffffffff, \ +0x0d20ffff, \ +0x00300001, \ +0x0140D871, \ +0x00300008, \ +0x00E00277, \ +0x01406C59, \ +0x00804073, \ +0x008700FA, \ +0x00E00070, \ +0x01406C59, \ +0x00905F8B, \ +0x00001000, \ +0x01496F50, \ +0x00E004D3, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00C08000, \ +0x01600CA2, \ +0x01600ADA, \ +0x00380408, \ +0x014D6FDA, \ +0x00300002, \ +0x0140DA72, \ +0x00C08000, \ +0x01700C0B, \ +0x01600ADA, \ +0x00380408, \ +0x01406FDA, \ +0x0030003E, \ +0x00845FA1, \ +0x00300002, \ +0x0140DA72, \ +0x00E01F90, \ +0x00200000, \ +0x0140DA6F, \ +0x00E01F90, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x01406C51, \ +0x0080DFF0, \ +0x01406C52, \ +0x00815FF0, \ +0x01406C59, \ +0x00905FC8, \ +0x014C6FD9, \ +0x00300001, \ +0x0140D972, \ +0x00941FEB, \ +0x00102000, \ +0x00048002, \ +0x014C6FD8, \ +0x00300006, \ +0x00840ED5, \ +0x014F71D8, \ +0x0140D872, \ +0x00E00ED5, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00200600, \ +0x0140D76F, \ +0x00148002, \ +0x01406FD8, \ +0x0140D96F, \ +0x00E01FB6, \ +0x00000000, \ +0x00000000, \ +0x00822D2B, \ +0x01406C51, \ +0x0080CD21, \ +0x01406C52, \ +0x00814D21, \ +0x01406C59, \ +0x00904D21, \ +0x014C6FD7, \ +0x00300000, \ +0x00841FE0, \ +0x00300001, \ +0x0140D772, \ +0x00E0129A, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00048002, \ +0x00102000, \ +0x00971FE5, \ +0x00101000, \ +0x00050200, \ +0x00E804D2, \ +0x014C6FD8, \ +0x00300001, \ +0x00840D21, \ +0x0140D872, \ +0x00E00D21, \ +0x014C6F91, \ +0x0150710B, \ +0x01496F72, \ +0x0030FF80, \ +0x00940ED8, \ +0x00102000, \ +0x00E00ED5, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +} + + +/********************************************************/ +/* Micro code for the D102 C-step */ +/********************************************************/ + +/* Parameter values for the D102 C-step */ +#define D102_C_CPUSAVER_DWORD 46 +#define D102_C_CPUSAVER_BUNDLE_MAX_DWORD 54 +#define D102_C_CPUSAVER_MIN_SIZE_DWORD 133 /* not implemented */ + +#define D102_C_RCVBUNDLE_UCODE \ +{\ +0x00700279, \ +0x0e6604e2, \ +0x02bf0cae, \ +0x1519150c, \ +0xFFFFFFFF, \ +0xffffFFFF, \ +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, \ +0x00300006, \ +0x00E0151A, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +0x00000000, \ +} +#endif diff -urN linux-2.2.25.orig/include/config/e100.h linux-2.2.25/include/config/e100.h --- linux-2.2.25.orig/include/config/e100.h Thu Jan 1 08:00:00 1970 +++ linux-2.2.25/include/config/e100.h Mon Aug 11 15:43:38 2003 @@ -0,0 +1 @@ +#define CONFIG_E100 1