summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuillem Jover <guillem@debian.org>2006-02-02 03:44:49 +0000
committerGuillem Jover <guillem@debian.org>2006-02-02 03:44:49 +0000
commit14d7bdd2f00afa1fe1f46218f8bb6d0aa4339510 (patch)
tree4804e7c56557b7ad5d467c7eca4712dd2c3e9c11
parent05e48aded83f979767e259a9e9ddfec394a634d2 (diff)
* New upstream CVS snapshot.
- debian/patches/11_nic_update.patch: Removed, integrated upstream. - debian/patches/17_net_gcc_4.0.patch: Likewise. - debian/patches/20_ide_disable_irqs.patch: Likewise. - debian/patches/31_tls_ldt.patch: Likewise. - debian/patches/00_build_make_beta.patch: Sync. - debian/patches/12_sis900.patch: Likewise. - debian/patches/13_ide_dma.patch: Likewise. - debian/patches/15_mem_obj_proxy.patch: Likewise. - debian/patches/41_io_unlock_ioremove.patch: Likewise. - debian/patches/42_disable_ioperm.patch: Likewise. - debian/patches/45_io_per_task.patch: Likewise. - debian/patches/90_autoconf_autogen.patch: Likewise.
-rw-r--r--debian/changelog22
-rw-r--r--debian/patches/00_build_make_beta.patch13
-rw-r--r--debian/patches/11_nic_update.patch36970
-rw-r--r--debian/patches/12_sis900.patch86
-rw-r--r--debian/patches/13_ide_dma.patch2
-rw-r--r--debian/patches/15_mem_obj_proxy.patch9
-rw-r--r--debian/patches/17_net_gcc_4.0.patch37
-rw-r--r--debian/patches/20_ide_disable_irqs.patch95
-rw-r--r--debian/patches/31_tls_ldt.patch53
-rw-r--r--debian/patches/41_io_unlock_ioremove.patch2
-rw-r--r--debian/patches/42_disable_ioperm.patch4
-rw-r--r--debian/patches/45_io_per_task.patch16
-rw-r--r--debian/patches/90_autoconf_autogen.patch677
13 files changed, 90 insertions, 37896 deletions
diff --git a/debian/changelog b/debian/changelog
index 7ed4750..8d44f5f 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,4 +1,22 @@
-gnumach (1:20050801-4) UNRELEASED; urgency=low
+gnumach (1:20060201-1) UNRELEASED; urgency=low
+
+ * New upstream CVS snapshot.
+ - debian/patches/11_nic_update.patch: Removed, integrated upstream.
+ - debian/patches/17_net_gcc_4.0.patch: Likewise.
+ - debian/patches/20_ide_disable_irqs.patch: Likewise.
+ - debian/patches/31_tls_ldt.patch: Likewise.
+ - debian/patches/00_build_make_beta.patch: Sync.
+ - debian/patches/12_sis900.patch: Likewise.
+ - debian/patches/13_ide_dma.patch: Likewise.
+ - debian/patches/15_mem_obj_proxy.patch: Likewise.
+ - debian/patches/41_io_unlock_ioremove.patch: Likewise.
+ - debian/patches/42_disable_ioperm.patch: Likewise.
+ - debian/patches/45_io_per_task.patch: Likewise.
+ - debian/patches/90_autoconf_autogen.patch: Likewise.
+
+ -- Guillem Jover <guillem@debian.org> Wed, 1 Feb 2006 23:21:59 +0200
+
+gnumach (1:20050801-4) unstable; urgency=low
* Actually enable the io access disabling patch.
- debian/patches/42_disable_ioperm.disabled: Rename to ...
@@ -13,7 +31,7 @@ gnumach (1:20050801-4) UNRELEASED; urgency=low
Thanks to Samuel Thibault <samuel.thibault@ens-lyon.org>.
* Build-Depend on the new POSIX compliant make.
- -- Guillem Jover <guillem@debian.org> Sun, 15 Jan 2006 00:05:27 +0200
+ -- Guillem Jover <guillem@debian.org> Mon, 16 Jan 2006 05:40:33 +0200
gnumach (1:20050801-3) unstable; urgency=low
diff --git a/debian/patches/00_build_make_beta.patch b/debian/patches/00_build_make_beta.patch
index df0ad07..75c9838 100644
--- a/debian/patches/00_build_make_beta.patch
+++ b/debian/patches/00_build_make_beta.patch
@@ -2,21 +2,21 @@
2006-01-11 Alfred M. Szmidt <ams@gnu.org>
- * Makefile.in (migs_d_SCRIPT): New variable.
+ * Makerules.in (migs_d_SCRIPT): New variable.
(%.migs_d): Use it.
(migu_d_SCRIPT): New variable.
%.migu_d): Use it.
---- Makefile.in 2005-07-25 06:48:20.000000000 +0300
-+++ Makefile.in 2006-01-11 23:52:38.000000000 +0200
-@@ -467,13 +467,17 @@
+--- Makerules.in.orig 2006-01-31 11:21:04.000000000 +0200
++++ Makerules.in 2006-02-01 23:28:54.000000000 +0200
+@@ -118,13 +118,17 @@
# Here is how to make those dependency files
+migs_d_SCRIPT = 'set -e; $(CPP) $(MIGFLAGS) -M -MG -x c $< | \
+ sed -e \'s/[^:]*:/$(@:.migs_d=_server.c) $@:/\' > $@)'
+
- %.migs_d: %.srv $(before-compile)
+ %.migs_d: %.srv
- (set -e; $(CPP) $(MIGFLAGS) -M -MG -x c $< | \
- sed -e 's/[^:]*:/$(@:.migs_d=_server.c) $@:/' > $@)
+ $(migs_d_SCRIPT)
@@ -24,11 +24,10 @@
+migu_d_SCRIPT = 'set -e; $(CPP) $(MIGFLAGS) -M -MG -x c $< | \
+ sed -e \'s/[^:]*:/$(@:.migu_d=_user.c) $@:/\' > $@)'
- %.migu_d: %.cli $(before-compile)
+ %.migu_d: %.cli
- (set -e; $(CPP) $(MIGFLAGS) -M -MG -x c $< | \
- sed -e 's/[^:]*:/$(@:.migu_d=_user.c) $@:/' > $@)
+ $(migu_d_SCRIPT)
%.migsh_d: %.migs_d
sed -e 's/_server\.c /_interface.h /' -e 's/migs_d/migsh_d/' < $< > $@
-
diff --git a/debian/patches/11_nic_update.patch b/debian/patches/11_nic_update.patch
deleted file mode 100644
index 8cc4e03..0000000
--- a/debian/patches/11_nic_update.patch
+++ /dev/null
@@ -1,36970 +0,0 @@
-#DPATCHLEVEL=0
-
-2005-11-10 Guillem Jover <guillem@hadrons.org>
-
- * i386/linux/configure.ac: Renamed winbond-840 driver to winbond_840.
- Do not include "pci-skeleton.c" in the "net" AC_DRIVER_CLASS.
- Enable the starfire, intel_gige and natsemi network drivers. Remove
- "CONFIG_" from cb_chim, starfire, sundance, winbond840, hamachi,
- natsemi, myson803 and ns820 driver declarations. Replace INTER_GIGE
- with INTEL_GIGE.
- * linux/src/include/asm-i386/cache.h: New file from linux 2.2.26.
- * linux/dev/include/linux/malloc.h: Include <asm/cache.h>.
- * linux/src/drivers/net/ns820.c (netsami_drv_id): Renamed to ...
- (ns820_drv_id): ... this. Fix all callers.
- * linux/src/drivers/net/intel-gige.c
- (skel_netdev_probe): Renamed to ...
- (igige_probe): ... this.
- * linux/dev/drivers/net/Space.c: Add conditional probes for natsemi,
- ns820, winbond840, hamachi, sundance, starfire, myson803 and
- intel-gige drivers.
- * linux/dev/drivers/net/eepro100.c: Remove obsoleted file.
- * linux/src/drivers/net/eepro100.c (pci_id_tbl): Add PCI ID's from
- linux-2.6.14-rc4.
-
-2004-02-29 Alfred M. Szmidt <ams@kemisten.nu>
-
- * i386/linux/Makefile.in (linux-net-files): Added `cb_shim.c',
- `hamachi.c', `intel-gige.c', `myson803.c', `natsemi.c', `ns820.c',
- `pci-scan.c', `pci-serial.c', `pci-skeleton.c', `starfire.c',
- `sundance.c' and `winbond-840.c.
- * i386/linux/Drivers.in (ns820, myson803, sundance,
- winbond-840, hamachi): New drivers. Added `pci-scan' and
- `pci-skeleton.o' to the network driver class.
- * linux/dev/include/linux/modversions.h: New file.
-
- * linux/src/drivers/net/3c59x.c, linux/src/drivers/net/eepro100.c,
- linux/src/drivers/net/epic100.c, linux/src/drivers/net/ne2k-pci.c,
- linux/src/drivers/net/rtl8139.c, linux/src/drivers/net/tulip.c,
- linux/src/drivers/net/via-rhine.c,
- linux/src/drivers/net/yellowfin.c: Updated files from netdrivers
- 3.5 (http://www.scyld.com/network).
- * linux/src/drivers/net/winbond-840.c,
- linux/src/drivers/net/starfire.c,
- linux/src/drivers/net/sundance.c, linux/src/drivers/net/ns820.c,
- linux/src/drivers/net/pci-scan.c,
- linux/src/drivers/net/pci-scan.h,
- linux/src/drivers/net/pci-serial.c,
- linux/src/drivers/net/pci-skeleton.c,
- linux/src/drivers/net/hamachi.c,
- linux/src/drivers/net/intel-gige.c,
- linux/src/drivers/net/kern_compat.h,
- linux/src/drivers/net/myson803.c, linux/src/drivers/net/natsemi.c,
- linux/src/drivers/net/cb_shim.c: New files from netdrivers 3.5
- package (http://www.scyld.com/network).
-
-
---- i386/linux/configure.ac
-+++ i386/linux/configure.ac
-@@ -108,7 +108,7 @@
- sd_ioctl.o sr.o sr_ioctl.o])
-
- AC_DRIVER_CLASS([net], [CONFIG_INET], [ \
-- auto_irq.o net.o Space.o dev.o net_init.o])
-+ auto_irq.o net.o Space.o dev.o net_init.o pci-scan.o])
-
- dnl Strictly speaking, we could have a `linux' option too, but it's
- dnl not possible to built a useful kernel without at least one Linux
-@@ -170,6 +170,20 @@
-
- dnl Ethernet controllers
-
-+dnl FIXME: Can't be enabled since it is a pcmcia driver, and we don't
-+dnl have that kind of fluff.
-+dnl
-+dnl linux_DRIVER([cb_shim], [CB_SHIM], [cb_shim], [net])
-+
-+linux_DRIVER([starfire], [STARFIRE], [starfire], [net])
-+linux_DRIVER([sundance], [SUNDANCE], [sundance], [net])
-+linux_DRIVER([winbond_840], [WINBOND840], [winbond-840], [net])
-+linux_DRIVER([hamachi], [HAMACHI], [hamachi], [net])
-+linux_DRIVER([intel_gige], [INTEL_GIGE], [intel-gige], [net])
-+linux_DRIVER([natsemi], [NATSEMI], [natsemi], [net])
-+linux_DRIVER([myson803], [MYSON803], [myson803], [net])
-+linux_DRIVER([ns820], [NS820], [ns820], [net])
-+
- AC_DRIVER([ne2000], [CONFIG_NE2000], [ne.o 8390.o], [net])
- AC_DRIVER([el2], [CONFIG_EL2], [3c503.o 8390.o], [net])
- linux_DRIVER([el3], [EL3], [3c509], [net])
-Index: i386/linux/Makefile.in
-===================================================================
-RCS file: /cvsroot/hurd/gnumach/i386/linux/Attic/Makefile.in,v
-retrieving revision 1.4
-diff -u -r1.4 Makefile.in
---- i386/linux/Makefile.in 27 May 2001 12:44:22 -0000 1.4
-+++ i386/linux/Makefile.in 20 Aug 2004 10:32:51 -0000
-@@ -1,5 +1,5 @@
- # Makefile for Linux device drivers and the glue codes.
--# Copyright 1998, 1999 Free Software Foundation, Inc.
-+# Copyright 1998, 1999, 2004 Free Software Foundation, Inc.
- #
- # Permission to use, copy, modify and distribute this software and its
- # documentation is hereby granted, provided that both the copyright
-@@ -62,13 +62,18 @@
- vpath %.c $(linuxsrcdir)/dev/drivers/block
- vpath %.c $(linuxsrcdir)/src/drivers/block
-
--linux-net-files = auto_irq.c 3c501.c 3c503.c 3c505.c 3c507.c 3c509.c \
-- 3c59x.c 3c515.c 8390.c Space.c ac3200.c apricot.c at1700.c atp.c \
-- de4x5.c de600.c de620.c depca.c dev.c e2100.c eepro.c eepro100.c \
-- eexpress.c epic100.c eth16i.c ewrk3.c fmv18x.c hp-plus.c hp.c hp100.c \
-- lance.c ne.c ne2k-pci.c net_init.c ni52.c ni65.c pcnet32.c rtl8139.c \
-- seeq8005.c sk_g16.c smc-ultra.c smc-ultra32.c tlan.c tulip.c \
-- via-rhine.c wavelan.c wd.c yellowfin.c znet.c net.c
-+linux-net-files = auto_irq.c 3c501.c 3c503.c 3c505.c 3c507.c 3c509.c \
-+ 3c59x.c 3c515.c 8390.c Space.c ac3200.c apricot.c at1700.c \
-+ atp.c de4x5.c de600.c de620.c depca.c dev.c e2100.c eepro.c \
-+ eepro100.c eexpress.c epic100.c eth16i.c ewrk3.c fmv18x.c \
-+ hp-plus.c hp.c hp100.c lance.c ne.c ne2k-pci.c net_init.c \
-+ ni52.c ni65.c pcnet32.c rtl8139.c seeq8005.c sk_g16.c \
-+ smc-ultra.c smc-ultra32.c tlan.c tulip.c via-rhine.c wavelan.c \
-+ wd.c yellowfin.c znet.c net.c net.c cb_shim.c hamachi.c \
-+ intel-gige.c myson803.c natsemi.c ns820.c pci-scan.c \
-+ pci-serial.c pci-skeleton.c starfire.c sundance.c \
-+ winbond-840.c
-+
- vpath %.c $(linuxsrcdir)/dev/drivers/net
- vpath %.c $(linuxsrcdir)/dev/net/core
- vpath %.c $(linuxsrcdir)/src/drivers/net
-Index: linux/dev/drivers/net/eepro100.c
-===================================================================
-RCS file: linux/dev/drivers/net/eepro100.c
-diff -N linux/dev/drivers/net/eepro100.c
---- linux/dev/drivers/net/eepro100.c 17 Aug 2001 23:33:35 -0000 1.1
-+++ /dev/null 1 Jan 1970 00:00:00 -0000
-@@ -1,2284 +0,0 @@
--/* drivers/net/eepro100.c: An Intel i82557-559 Ethernet driver for Linux. */
--/*
-- NOTICE: this version of the driver is supposed to work with 2.2 kernels.
-- Written 1996-1999 by Donald Becker.
--
-- This software may be used and distributed according to the terms
-- of the GNU Public License, incorporated herein by reference.
--
-- This driver is for the Intel EtherExpress Pro100 (Speedo3) design.
-- It should work with all i82557/558/559 boards.
--
-- To use as a module, use the compile-command at the end of the file.
--
-- The author may be reached as becker@CESDIS.usra.edu, or C/O
-- Center of Excellence in Space Data and Information Sciences
-- Code 930.5, NASA Goddard Space Flight Center, Greenbelt MD 20771
-- For updates see
-- http://cesdis.gsfc.nasa.gov/linux/drivers/eepro100.html
-- For installation instructions
-- http://cesdis.gsfc.nasa.gov/linux/misc/modules.html
-- There is a Majordomo mailing list based at
-- linux-eepro100@cesdis.gsfc.nasa.gov
--
-- The driver also contains updates by different kernel developers.
-- This driver clone is maintained by Andrey V. Savochkin <saw@saw.sw.com.sg>.
-- Please use this email address and linux-kernel mailing list for bug reports.
--
-- Modification history:
-- 2000 Mar 24 Dragan Stancevic <visitor@valinux.com>
-- Disabled FC and ER, to avoid lockups when when we get FCP interrupts.
-- 2000 May 27 Andrey Moruga <moruga@sw.com.sg>
-- Code duplication for 82559ER support was removed.
-- Accurate handling of all supported chips was implemented.
-- Some fixes in 2.3 clone of the driver were ported.
-- 2000 May 30 Dragan Stancevic <visitor@valinux.com> and
-- Andrey Moruga <moruga@sw.com.sg>
-- Honor PortReset timing specification.
-- 2000 Jul 25 Dragan Stancevic <visitor@valinux.com>
-- Changed to MMIO, resized FIFOs, resized rings, changed ISR timeout
-- Problem reported by:
-- Marc MERLIN <merlin@valinux.com>
-- 2000 Nov 15 Dragan Stancevic <visitor@valinux.com>
-- Changed command completion time and added debug info as to which
-- CMD timed out. Problem reported by:
-- "Ulrich Windl" <Ulrich.Windl@rz.uni-regensburg.de>
--*/
--
--#define USE_IO
--static const char *version =
--"eepro100.c:v1.09j-t 9/29/99 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/eepro100.html\n"
--"eepro100.c: $Revision: 1.1 $ 2000/05/31 Modified by Andrey V. Savochkin <saw@saw.sw.com.sg> and others\n"
--"eepro100.c: VA Linux custom, Dragan Stancevic <visitor@valinux.com> 2000/11/15\n";
--
--/* A few user-configurable values that apply to all boards.
-- First set is undocumented and spelled per Intel recommendations. */
--
--static int congenb = 0; /* Enable congestion control in the DP83840. */
--static int txfifo = 0; /* Tx FIFO threshold in 4 byte units, 0-15 */
--static int rxfifo = 0xF; /* Rx FIFO threshold, default 32 bytes. */
--/* Tx/Rx DMA burst length, 0-127, 0 == no preemption, tx==128 -> disabled. */
--static int txdmacount = 128;
--static int rxdmacount = 0;
--
--/* Set the copy breakpoint for the copy-only-tiny-buffer Rx method.
-- Lower values use more memory, but are faster. */
--#if defined(__alpha__) || defined(__sparc__)
--/* force copying of all packets to avoid unaligned accesses on Alpha */
--static int rx_copybreak = 1518;
--#else
--static int rx_copybreak = 200;
--#endif
--
--/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
--static int max_interrupt_work = 200;
--
--/* Maximum number of multicast addresses to filter (vs. rx-all-multicast) */
--static int multicast_filter_limit = 64;
--
--/* 'options' is used to pass a transceiver override or full-duplex flag
-- e.g. "options=16" for FD, "options=32" for 100mbps-only. */
--static int full_duplex[] = {-1, -1, -1, -1, -1, -1, -1, -1};
--static int options[] = {-1, -1, -1, -1, -1, -1, -1, -1};
--#ifdef MODULE
--static int debug = -1; /* The debug level */
--#endif
--
--/* A few values that may be tweaked. */
--/* The ring sizes should be a power of two for efficiency. */
--#define TX_RING_SIZE 64
--#define RX_RING_SIZE 64
--/* How much slots multicast filter setup may take.
-- Do not descrease without changing set_rx_mode() implementaion. */
--#define TX_MULTICAST_SIZE 2
--#define TX_MULTICAST_RESERV (TX_MULTICAST_SIZE*2)
--/* Actual number of TX packets queued, must be
-- <= TX_RING_SIZE-TX_MULTICAST_RESERV. */
--#define TX_QUEUE_LIMIT (TX_RING_SIZE-TX_MULTICAST_RESERV)
--/* Hysteresis marking queue as no longer full. */
--#define TX_QUEUE_UNFULL (TX_QUEUE_LIMIT-4)
--
--/* Operational parameters that usually are not changed. */
--
--/* Time in jiffies before concluding the transmitter is hung. */
--#define TX_TIMEOUT (2*HZ)
--/* Size of an pre-allocated Rx buffer: <Ethernet MTU> + slack.*/
--#define PKT_BUF_SZ 1536
--
--#if !defined(__OPTIMIZE__) || !defined(__KERNEL__)
--#warning You must compile this file with the correct options!
--#warning See the last lines of the source file.
--#error You must compile this driver with "-O".
--#endif
--
--#include <linux/version.h>
--#include <linux/module.h>
--#if defined(MODVERSIONS)
--#include <linux/modversions.h>
--#endif
--
--#include <linux/kernel.h>
--#include <linux/string.h>
--#include <linux/timer.h>
--#include <linux/errno.h>
--#include <linux/ioport.h>
--#include <linux/malloc.h>
--#include <linux/interrupt.h>
--#include <linux/pci.h>
--#include <linux/compatmac.h>
--#include <asm/spinlock.h>
--#include <asm/processor.h>
--#include <asm/bitops.h>
--#include <asm/io.h>
--/* #include <asm/unaligned.h> */
--/* #include <asm/byteorder.h> */
--#define __LITTLE_ENDIAN
--#include <asm/hardirq.h>
--
--#include <linux/netdevice.h>
--#include <linux/etherdevice.h>
--#include <linux/skbuff.h>
--#include <linux/delay.h>
--
--#if defined(MODULE) && (LINUX_VERSION_CODE > 0x20115)
--MODULE_AUTHOR("Maintainer: Andrey V. Savochkin <saw@saw.sw.com.sg>");
--MODULE_DESCRIPTION("Intel i82557/i82558 PCI EtherExpressPro driver");
--MODULE_PARM(debug, "i");
--MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
--MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
--MODULE_PARM(congenb, "i");
--MODULE_PARM(txfifo, "i");
--MODULE_PARM(rxfifo, "i");
--MODULE_PARM(txdmacount, "i");
--MODULE_PARM(rxdmacount, "i");
--MODULE_PARM(rx_copybreak, "i");
--MODULE_PARM(max_interrupt_work, "i");
--MODULE_PARM(multicast_filter_limit, "i");
--#endif
--
--#if (LINUX_VERSION_CODE >= 0x20100)
--static char kernel_version[] = UTS_RELEASE;
--#endif
--
--#if LINUX_VERSION_CODE < 0x20123
--#define hard_smp_processor_id() smp_processor_id()
--#define test_and_set_bit(val, addr) set_bit(val, addr)
--#define le16_to_cpu(val) (val)
--#define le32_to_cpu(val) (val)
--#define cpu_to_le32(val) (val)
--#define cpu_to_le16(val) (val)
--#endif
--#if LINUX_VERSION_CODE <= 0x20139
--#define net_device_stats enet_statistics
--#else
--#define NETSTATS_VER2
--#endif
--#if LINUX_VERSION_CODE < 0x20155
--/* Grrrr, the PCI code changed, but did not consider CardBus... */
--#include <linux/bios32.h>
--#define PCI_SUPPORT_VER1
--#else
--#define PCI_SUPPORT_VER2
--#endif
--#if LINUX_VERSION_CODE < 0x20159
--#define dev_free_skb(skb) dev_kfree_skb(skb, FREE_WRITE);
--#else
--#define dev_free_skb(skb) dev_kfree_skb(skb);
--#endif
--#if ! defined(CAP_NET_ADMIN)
--#define capable(CAP_XXX) (suser())
--#endif
--
--#define RUN_AT(x) (jiffies + (x))
--/* Condensed bus+endian portability operations. */
--#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr))
--#define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr))
--
--#define net_device device
--#define pci_base_address(p, n) (p)->base_address[n]
--
--#define netif_wake_queue(dev) do { \
-- clear_bit(0, (void*)&dev->tbusy); \
-- mark_bh(NET_BH); \
-- } while(0)
--#define netif_start_queue(dev) clear_bit(0, (void*)&dev->tbusy)
--#define netif_stop_queue(dev) set_bit(0, (void*)&dev->tbusy)
--#ifndef PCI_DEVICE_ID_INTEL_82559ER
--#define PCI_DEVICE_ID_INTEL_82559ER 0x1209
--#endif
--#ifndef PCI_DEVICE_ID_INTEL_ID1029
--#define PCI_DEVICE_ID_INTEL_ID1029 0x1029
--#endif
--#ifndef PCI_DEVICE_ID_INTEL_ID1030
--#define PCI_DEVICE_ID_INTEL_ID1030 0x1030
--#endif
--#ifndef PCI_DEVICE_ID_INTEL_ID2449
--#define PCI_DEVICE_ID_INTEL_ID2449 0x2449
--#endif
--
--/* The total I/O port extent of the board.
-- The registers beyond 0x18 only exist on the i82558. */
--#define SPEEDO3_TOTAL_SIZE 0x20
--
--int speedo_debug = 1;
--
--/*
-- Theory of Operation
--
--I. Board Compatibility
--
--This device driver is designed for the Intel i82557 "Speedo3" chip, Intel's
--single-chip fast Ethernet controller for PCI, as used on the Intel
--EtherExpress Pro 100 adapter.
--
--II. Board-specific settings
--
--PCI bus devices are configured by the system at boot time, so no jumpers
--need to be set on the board. The system BIOS should be set to assign the
--PCI INTA signal to an otherwise unused system IRQ line. While it's
--possible to share PCI interrupt lines, it negatively impacts performance and
--only recent kernels support it.
--
--III. Driver operation
--
--IIIA. General
--The Speedo3 is very similar to other Intel network chips, that is to say
--"apparently designed on a different planet". This chips retains the complex
--Rx and Tx descriptors and multiple buffers pointers as previous chips, but
--also has simplified Tx and Rx buffer modes. This driver uses the "flexible"
--Tx mode, but in a simplified lower-overhead manner: it associates only a
--single buffer descriptor with each frame descriptor.
--
--Despite the extra space overhead in each receive skbuff, the driver must use
--the simplified Rx buffer mode to assure that only a single data buffer is
--associated with each RxFD. The driver implements this by reserving space
--for the Rx descriptor at the head of each Rx skbuff.
--
--The Speedo-3 has receive and command unit base addresses that are added to
--almost all descriptor pointers. The driver sets these to zero, so that all
--pointer fields are absolute addresses.
--
--The System Control Block (SCB) of some previous Intel chips exists on the
--chip in both PCI I/O and memory space. This driver uses the I/O space
--registers, but might switch to memory mapped mode to better support non-x86
--processors.
--
--IIIB. Transmit structure
--
--The driver must use the complex Tx command+descriptor mode in order to
--have a indirect pointer to the skbuff data section. Each Tx command block
--(TxCB) is associated with two immediately appended Tx Buffer Descriptor
--(TxBD). A fixed ring of these TxCB+TxBD pairs are kept as part of the
--speedo_private data structure for each adapter instance.
--
--The newer i82558 explicitly supports this structure, and can read the two
--TxBDs in the same PCI burst as the TxCB.
--
--This ring structure is used for all normal transmit packets, but the
--transmit packet descriptors aren't long enough for most non-Tx commands such
--as CmdConfigure. This is complicated by the possibility that the chip has
--already loaded the link address in the previous descriptor. So for these
--commands we convert the next free descriptor on the ring to a NoOp, and point
--that descriptor's link to the complex command.
--
--An additional complexity of these non-transmit commands are that they may be
--added asynchronous to the normal transmit queue, so we disable interrupts
--whenever the Tx descriptor ring is manipulated.
--
--A notable aspect of these special configure commands is that they do
--work with the normal Tx ring entry scavenge method. The Tx ring scavenge
--is done at interrupt time using the 'dirty_tx' index, and checking for the
--command-complete bit. While the setup frames may have the NoOp command on the
--Tx ring marked as complete, but not have completed the setup command, this
--is not a problem. The tx_ring entry can be still safely reused, as the
--tx_skbuff[] entry is always empty for config_cmd and mc_setup frames.
--
--Commands may have bits set e.g. CmdSuspend in the command word to either
--suspend or stop the transmit/command unit. This driver always flags the last
--command with CmdSuspend, erases the CmdSuspend in the previous command, and
--then issues a CU_RESUME.
--Note: Watch out for the potential race condition here: imagine
-- erasing the previous suspend
-- the chip processes the previous command
-- the chip processes the final command, and suspends
-- doing the CU_RESUME
-- the chip processes the next-yet-valid post-final-command.
--So blindly sending a CU_RESUME is only safe if we do it immediately after
--after erasing the previous CmdSuspend, without the possibility of an
--intervening delay. Thus the resume command is always within the
--interrupts-disabled region. This is a timing dependence, but handling this
--condition in a timing-independent way would considerably complicate the code.
--
--Note: In previous generation Intel chips, restarting the command unit was a
--notoriously slow process. This is presumably no longer true.
--
--IIIC. Receive structure
--
--Because of the bus-master support on the Speedo3 this driver uses the new
--SKBUFF_RX_COPYBREAK scheme, rather than a fixed intermediate receive buffer.
--This scheme allocates full-sized skbuffs as receive buffers. The value
--SKBUFF_RX_COPYBREAK is used as the copying breakpoint: it is chosen to
--trade-off the memory wasted by passing the full-sized skbuff to the queue
--layer for all frames vs. the copying cost of copying a frame to a
--correctly-sized skbuff.
--
--For small frames the copying cost is negligible (esp. considering that we
--are pre-loading the cache with immediately useful header information), so we
--allocate a new, minimally-sized skbuff. For large frames the copying cost
--is non-trivial, and the larger copy might flush the cache of useful data, so
--we pass up the skbuff the packet was received into.
--
--IV. Notes
--
--Thanks to Steve Williams of Intel for arranging the non-disclosure agreement
--that stated that I could disclose the information. But I still resent
--having to sign an Intel NDA when I'm helping Intel sell their own product!
--
--*/
--
--/* This table drives the PCI probe routines. */
--static struct net_device *speedo_found1(struct pci_dev *pdev, int pci_bus,
-- int pci_devfn, long ioaddr,
-- int chip_idx, int card_idx);
--
--#ifdef USE_IO
--#define SPEEDO_IOTYPE PCI_USES_MASTER|PCI_USES_IO|PCI_ADDR1
--#define SPEEDO_SIZE 32
--#else
--#define SPEEDO_IOTYPE PCI_USES_MASTER|PCI_USES_MEM|PCI_ADDR0
--#define SPEEDO_SIZE 0x1000
--#endif
--
--enum pci_flags_bit {
-- PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
-- PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
--};
--struct pci_id_info {
-- const char *name;
-- u16 vendor_id, device_id;
-- int pci_index;
--} static pci_tbl[] = {
-- { "Intel PCI EtherExpress Pro100 82557",
-- PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82557,
-- 0
-- },
-- { "Intel PCI EtherExpress Pro100 82559ER",
-- PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82559ER,
-- 0
-- },
-- { "Intel PCI EtherExpress Pro100 ID1029",
-- PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ID1029,
-- 0
-- },
-- { "Intel Corporation 82559 InBusiness 10/100",
-- PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ID1030,
-- 0
-- },
-- { "Intel PCI EtherExpress Pro100 82562EM",
-- PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ID2449,
-- 0
-- },
-- {0,} /* 0 terminated list. */
--};
--
--static inline unsigned int io_inw(unsigned long port)
--{
-- return inw(port);
--}
--static inline void io_outw(unsigned int val, unsigned long port)
--{
-- outw(val, port);
--}
--
--#ifndef USE_IO
--#undef inb
--#undef inw
--#undef inl
--#undef outb
--#undef outw
--#undef outl
--#define inb readb
--#define inw readw
--#define inl readl
--#define outb writeb
--#define outw writew
--#define outl writel
--#endif
--
--/* How to wait for the command unit to accept a command.
-- Typically this takes 0 ticks. */
--static inline void wait_for_cmd_done(long cmd_ioaddr)
--{
-- int wait = 20000;
-- char cmd_reg1, cmd_reg2;
-- do ;
-- while((cmd_reg1 = inb(cmd_ioaddr)) && (--wait >= 0));
--
-- /* Last chance to change your mind --Dragan*/
-- if (wait < 0){
-- cmd_reg2 = inb(cmd_ioaddr);
-- if(cmd_reg2){
-- printk(KERN_ALERT "eepro100: cmd_wait for(%#2.2x) timedout with(%#2.2x)!\n",
-- cmd_reg1, cmd_reg2);
--
-- }
-- }
--
--}
--
--/* Offsets to the various registers.
-- All accesses need not be longword aligned. */
--enum speedo_offsets {
-- SCBStatus = 0, SCBCmd = 2, /* Rx/Command Unit command and status. */
-- SCBPointer = 4, /* General purpose pointer. */
-- SCBPort = 8, /* Misc. commands and operands. */
-- SCBflash = 12, SCBeeprom = 14, /* EEPROM and flash memory control. */
-- SCBCtrlMDI = 16, /* MDI interface control. */
-- SCBEarlyRx = 20, /* Early receive byte count. */
--};
--/* Commands that can be put in a command list entry. */
--enum commands {
-- CmdNOp = 0, CmdIASetup = 0x10000, CmdConfigure = 0x20000,
-- CmdMulticastList = 0x30000, CmdTx = 0x40000, CmdTDR = 0x50000,
-- CmdDump = 0x60000, CmdDiagnose = 0x70000,
-- CmdSuspend = 0x40000000, /* Suspend after completion. */
-- CmdIntr = 0x20000000, /* Interrupt after completion. */
-- CmdTxFlex = 0x00080000, /* Use "Flexible mode" for CmdTx command. */
--};
--/* Clear CmdSuspend (1<<30) avoiding interference with the card access to the
-- status bits. Previous driver versions used separate 16 bit fields for
-- commands and statuses. --SAW
-- */
--#if defined(__LITTLE_ENDIAN)
--#define clear_suspend(cmd) ((__u16 *)&(cmd)->cmd_status)[1] &= ~0x4000
--#elif defined(__BIG_ENDIAN)
--#define clear_suspend(cmd) ((__u16 *)&(cmd)->cmd_status)[1] &= ~0x0040
--#else
--#error Unsupported byteorder
--#endif
--
--enum SCBCmdBits {
-- SCBMaskCmdDone=0x8000, SCBMaskRxDone=0x4000, SCBMaskCmdIdle=0x2000,
-- SCBMaskRxSuspend=0x1000, SCBMaskEarlyRx=0x0800, SCBMaskFlowCtl=0x0400,
-- SCBTriggerIntr=0x0200, SCBMaskAll=0x0100,
-- /* The rest are Rx and Tx commands. */
-- CUStart=0x0010, CUResume=0x0020, CUStatsAddr=0x0040, CUShowStats=0x0050,
-- CUCmdBase=0x0060, /* CU Base address (set to zero) . */
-- CUDumpStats=0x0070, /* Dump then reset stats counters. */
-- RxStart=0x0001, RxResume=0x0002, RxAbort=0x0004, RxAddrLoad=0x0006,
-- RxResumeNoResources=0x0007,
--};
--
--enum SCBPort_cmds {
-- PortReset=0, PortSelfTest=1, PortPartialReset=2, PortDump=3,
--};
--
--/* The Speedo3 Rx and Tx frame/buffer descriptors. */
--struct descriptor { /* A generic descriptor. */
-- s32 cmd_status; /* All command and status fields. */
-- u32 link; /* struct descriptor * */
-- unsigned char params[0];
--};
--
--/* The Speedo3 Rx and Tx buffer descriptors. */
--struct RxFD { /* Receive frame descriptor. */
-- s32 status;
-- u32 link; /* struct RxFD * */
-- u32 rx_buf_addr; /* void * */
-- u32 count;
--};
--
--/* Selected elements of the Tx/RxFD.status word. */
--enum RxFD_bits {
-- RxComplete=0x8000, RxOK=0x2000,
-- RxErrCRC=0x0800, RxErrAlign=0x0400, RxErrTooBig=0x0200, RxErrSymbol=0x0010,
-- RxEth2Type=0x0020, RxNoMatch=0x0004, RxNoIAMatch=0x0002,
-- TxUnderrun=0x1000, StatusComplete=0x8000,
--};
--
--struct TxFD { /* Transmit frame descriptor set. */
-- s32 status;
-- u32 link; /* void * */
-- u32 tx_desc_addr; /* Always points to the tx_buf_addr element. */
-- s32 count; /* # of TBD (=1), Tx start thresh., etc. */
-- /* This constitutes two "TBD" entries -- we only use one. */
-- u32 tx_buf_addr0; /* void *, frame to be transmitted. */
-- s32 tx_buf_size0; /* Length of Tx frame. */
-- u32 tx_buf_addr1; /* void *, frame to be transmitted. */
-- s32 tx_buf_size1; /* Length of Tx frame. */
--};
--
--/* Multicast filter setting block. --SAW */
--struct speedo_mc_block {
-- struct speedo_mc_block *next;
-- unsigned int tx;
-- struct descriptor frame __attribute__ ((__aligned__(16)));
--};
--
--/* Elements of the dump_statistics block. This block must be lword aligned. */
--struct speedo_stats {
-- u32 tx_good_frames;
-- u32 tx_coll16_errs;
-- u32 tx_late_colls;
-- u32 tx_underruns;
-- u32 tx_lost_carrier;
-- u32 tx_deferred;
-- u32 tx_one_colls;
-- u32 tx_multi_colls;
-- u32 tx_total_colls;
-- u32 rx_good_frames;
-- u32 rx_crc_errs;
-- u32 rx_align_errs;
-- u32 rx_resource_errs;
-- u32 rx_overrun_errs;
-- u32 rx_colls_errs;
-- u32 rx_runt_errs;
-- u32 done_marker;
--};
--
--enum Rx_ring_state_bits {
-- RrNoMem=1, RrPostponed=2, RrNoResources=4, RrOOMReported=8,
--};
--
--/* Do not change the position (alignment) of the first few elements!
-- The later elements are grouped for cache locality. */
--struct speedo_private {
-- struct TxFD tx_ring[TX_RING_SIZE]; /* Commands (usually CmdTxPacket). */
-- struct RxFD *rx_ringp[RX_RING_SIZE]; /* Rx descriptor, used as ring. */
-- /* The addresses of a Tx/Rx-in-place packets/buffers. */
-- struct sk_buff* tx_skbuff[TX_RING_SIZE];
-- struct sk_buff* rx_skbuff[RX_RING_SIZE];
-- struct descriptor *last_cmd; /* Last command sent. */
-- unsigned int cur_tx, dirty_tx; /* The ring entries to be free()ed. */
-- spinlock_t lock; /* Group with Tx control cache line. */
-- u32 tx_threshold; /* The value for txdesc.count. */
-- struct RxFD *last_rxf; /* Last command sent. */
-- unsigned int cur_rx, dirty_rx; /* The next free ring entry */
-- long last_rx_time; /* Last Rx, in jiffies, to handle Rx hang. */
-- const char *product_name;
-- struct net_device *next_module;
-- void *priv_addr; /* Unaligned address for kfree */
-- struct enet_statistics stats;
-- struct speedo_stats lstats;
-- int chip_id;
-- unsigned char pci_bus, pci_devfn, acpi_pwr;
-- struct timer_list timer; /* Media selection timer. */
-- struct speedo_mc_block *mc_setup_head;/* Multicast setup frame list head. */
-- struct speedo_mc_block *mc_setup_tail;/* Multicast setup frame list tail. */
-- int in_interrupt; /* Word-aligned dev->interrupt */
-- char rx_mode; /* Current PROMISC/ALLMULTI setting. */
-- unsigned int tx_full:1; /* The Tx queue is full. */
-- unsigned int full_duplex:1; /* Full-duplex operation requested. */
-- unsigned int flow_ctrl:1; /* Use 802.3x flow control. */
-- unsigned int rx_bug:1; /* Work around receiver hang errata. */
-- unsigned int rx_bug10:1; /* Receiver might hang at 10mbps. */
-- unsigned int rx_bug100:1; /* Receiver might hang at 100mbps. */
-- unsigned char default_port:8; /* Last dev->if_port value. */
-- unsigned char rx_ring_state; /* RX ring status flags. */
-- unsigned short phy[2]; /* PHY media interfaces available. */
-- unsigned short advertising; /* Current PHY advertised caps. */
-- unsigned short partner; /* Link partner caps. */
--};
--
--/* The parameters for a CmdConfigure operation.
-- There are so many options that it would be difficult to document each bit.
-- We mostly use the default or recommended settings. */
--const char i82557_config_cmd[22] = {
-- 22, 0x08, 0, 0, 0, 0, 0x32, 0x03, 1, /* 1=Use MII 0=Use AUI */
-- 0, 0x2E, 0, 0x60, 0,
-- 0xf2, 0x48, 0, 0x40, 0xf2, 0x80, /* 0x40=Force full-duplex */
-- 0x3f, 0x05, };
--const char i82558_config_cmd[22] = {
-- 22, 0x08, 0, 1, 0, 0, 0x22, 0x03, 1, /* 1=Use MII 0=Use AUI */
-- 0, 0x2E, 0, 0x60, 0x08, 0x88,
-- 0x68, 0, 0x40, 0xf2, 0x84, /* Disable FC */
-- 0x31, 0x05, };
--
--/* PHY media interface chips. */
--static const char *phys[] = {
-- "None", "i82553-A/B", "i82553-C", "i82503",
-- "DP83840", "80c240", "80c24", "i82555",
-- "unknown-8", "unknown-9", "DP83840A", "unknown-11",
-- "unknown-12", "unknown-13", "unknown-14", "unknown-15", };
--enum phy_chips { NonSuchPhy=0, I82553AB, I82553C, I82503, DP83840, S80C240,
-- S80C24, I82555, DP83840A=10, };
--static const char is_mii[] = { 0, 1, 1, 0, 1, 1, 0, 1 };
--#define EE_READ_CMD (6)
--
--static int do_eeprom_cmd(long ioaddr, int cmd, int cmd_len);
--static int mdio_read(long ioaddr, int phy_id, int location);
--static int mdio_write(long ioaddr, int phy_id, int location, int value);
--static int speedo_open(struct net_device *dev);
--static void speedo_resume(struct net_device *dev);
--static void speedo_timer(unsigned long data);
--static void speedo_init_rx_ring(struct net_device *dev);
--static void speedo_tx_timeout(struct net_device *dev);
--static int speedo_start_xmit(struct sk_buff *skb, struct net_device *dev);
--static void speedo_refill_rx_buffers(struct net_device *dev, int force);
--static int speedo_rx(struct net_device *dev);
--static void speedo_tx_buffer_gc(struct net_device *dev);
--static void speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
--static int speedo_close(struct net_device *dev);
--static struct enet_statistics *speedo_get_stats(struct net_device *dev);
--static int speedo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
--static void set_rx_mode(struct net_device *dev);
--static void speedo_show_state(struct net_device *dev);
--
--
--
--#ifdef honor_default_port
--/* Optional driver feature to allow forcing the transceiver setting.
-- Not recommended. */
--static int mii_ctrl[8] = { 0x3300, 0x3100, 0x0000, 0x0100,
-- 0x2000, 0x2100, 0x0400, 0x3100};
--#endif
--
--/* A list of all installed Speedo devices, for removing the driver module. */
--static struct net_device *root_speedo_dev = NULL;
--
--int eepro100_init(void)
--{
-- int cards_found = 0;
-- int chip_idx;
-- struct pci_dev *pdev;
-- struct pci_dev rdev; pdev = &rdev;
--
-- if (! pcibios_present())
-- return cards_found;
--
-- for (chip_idx = 0; pci_tbl[chip_idx].name; chip_idx++) {
-- for (; pci_tbl[chip_idx].pci_index < 8; pci_tbl[chip_idx].pci_index++) {
-- unsigned char pci_bus, pci_device_fn, pci_latency;
-- unsigned long pciaddr;
-- long ioaddr;
-- int irq;
--
-- u16 pci_command, new_command;
--
-- if (pcibios_find_device(pci_tbl[chip_idx].vendor_id,
-- pci_tbl[chip_idx].device_id,
-- pci_tbl[chip_idx].pci_index, &pci_bus,
-- &pci_device_fn))
-- break;
-- {
--#if defined(PCI_SUPPORT_VER2)
-- pdev = pci_find_slot(pci_bus, pci_device_fn);
--#ifdef USE_IO
-- pciaddr = pci_base_address(pdev, 1); /* Use [0] to mem-map */
--#else
-- pciaddr = pci_base_address(pdev, 0);
--#endif
-- irq = pdev->irq;
--#else
-- u32 pci_ioaddr;
-- u8 pci_irq_line;
--#ifdef USE_IO
-- pcibios_read_config_dword(pci_bus, pci_device_fn,
-- PCI_BASE_ADDRESS_1, &pci_ioaddr);
--#else
-- pcibios_read_config_dword(pci_bus, pci_device_fn,
-- PCI_BASE_ADDRESS_0, &pci_ioaddr);
--#endif
-- pcibios_read_config_byte(pci_bus, pci_device_fn,
-- PCI_INTERRUPT_LINE, &pci_irq_line);
-- pciaddr = pci_ioaddr;
-- irq = pci_irq_line;
-- pdev->irq = irq;
--#endif
-- }
-- /* Remove I/O space marker in bit 0. */
-- if (pciaddr & 1) {
-- ioaddr = pciaddr & ~3UL;
-- if (check_region(ioaddr, 32))
-- continue;
-- } else {
--#ifdef __sparc__
-- /* ioremap is hosed in 2.2.x on Sparc. */
-- ioaddr = pciaddr & ~0xfUL;
--#else
-- if ((ioaddr = (long)ioremap(pciaddr & ~0xfUL, 0x1000)) == 0) {
-- printk(KERN_INFO "Failed to map PCI address %#lx.\n",
-- pciaddr);
-- continue;
-- }
--#endif
-- }
-- if (speedo_debug > 2)
-- printk("Found Intel i82557 PCI Speedo at I/O %#lx, IRQ %d.\n",
-- ioaddr, irq);
--
-- /* Get and check the bus-master and latency values. */
-- pcibios_read_config_word(pci_bus, pci_device_fn,
-- PCI_COMMAND, &pci_command);
-- new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
-- if (pci_command != new_command) {
-- printk(KERN_INFO " The PCI BIOS has not enabled this"
-- " device! Updating PCI command %4.4x->%4.4x.\n",
-- pci_command, new_command);
-- pcibios_write_config_word(pci_bus, pci_device_fn,
-- PCI_COMMAND, new_command);
-- }
-- pcibios_read_config_byte(pci_bus, pci_device_fn,
-- PCI_LATENCY_TIMER, &pci_latency);
-- if (pci_latency < 32) {
-- printk(" PCI latency timer (CFLT) is unreasonably low at %d."
-- " Setting to 32 clocks.\n", pci_latency);
-- pcibios_write_config_byte(pci_bus, pci_device_fn,
-- PCI_LATENCY_TIMER, 32);
-- } else if (speedo_debug > 1)
-- printk(" PCI latency timer (CFLT) is %#x.\n", pci_latency);
--
-- if (speedo_found1(pdev, pci_bus, pci_device_fn, ioaddr, chip_idx, cards_found))
-- cards_found++;
-- }
-- }
--
-- return cards_found;
--}
--
--static struct net_device *speedo_found1(struct pci_dev *pdev, int pci_bus,
-- int pci_devfn, long ioaddr,
-- int chip_idx, int card_idx)
--{
-- struct net_device *dev;
-- struct speedo_private *sp;
-- const char *product;
-- int i, option;
-- u16 eeprom[0x100];
-- int acpi_idle_state = 0;
--#ifndef MODULE
-- static int did_version = 0; /* Already printed version info. */
-- if (speedo_debug > 0 && did_version++ == 0)
-- printk(version);
--#endif
--
-- dev = init_etherdev(NULL, sizeof(struct speedo_private));
--
-- if (dev->mem_start > 0)
-- option = dev->mem_start;
-- else if (card_idx >= 0 && options[card_idx] >= 0)
-- option = options[card_idx];
-- else
-- option = 0;
--
-- /* Read the station address EEPROM before doing the reset.
-- Nominally his should even be done before accepting the device, but
-- then we wouldn't have a device name with which to report the error.
-- The size test is for 6 bit vs. 8 bit address serial EEPROMs.
-- */
-- {
-- unsigned long iobase;
-- int read_cmd, ee_size;
-- u16 sum;
-- int j;
--
-- /* Use IO only to avoid postponed writes and satisfy EEPROM timing
-- requirements. */
--#if defined(PCI_SUPPORT_VER2)
-- iobase = pci_base_address(pdev, 1) & ~3UL;
--#else
-- {
-- u32 pci_ioaddr;
-- pcibios_read_config_dword(pci_bus, pci_devfn,
-- PCI_BASE_ADDRESS_1, &pci_ioaddr);
-- iobase = pci_ioaddr & ~3UL;
-- }
--#endif
-- if ((do_eeprom_cmd(iobase, EE_READ_CMD << 24, 27) & 0xffe0000)
-- == 0xffe0000) {
-- ee_size = 0x100;
-- read_cmd = EE_READ_CMD << 24;
-- } else {
-- ee_size = 0x40;
-- read_cmd = EE_READ_CMD << 22;
-- }
--
-- for (j = 0, i = 0, sum = 0; i < ee_size; i++) {
-- u16 value = do_eeprom_cmd(iobase, read_cmd | (i << 16), 27);
-- eeprom[i] = value;
-- sum += value;
-- if (i < 3) {
-- dev->dev_addr[j++] = value;
-- dev->dev_addr[j++] = value >> 8;
-- }
-- }
-- if (sum != 0xBABA)
-- printk(KERN_WARNING "%s: Invalid EEPROM checksum %#4.4x, "
-- "check settings before activating this device!\n",
-- dev->name, sum);
-- /* Don't unregister_netdev(dev); as the EEPro may actually be
-- usable, especially if the MAC address is set later.
-- On the other hand, it may be unusable if MDI data is corrupted. */
-- }
--
-- /* Reset the chip: stop Tx and Rx processes and clear counters.
-- This takes less than 10usec and will easily finish before the next
-- action. */
-- outl(PortReset, ioaddr + SCBPort);
-- inl(ioaddr + SCBPort);
-- /* Honor PortReset timing. */
-- udelay(10);
--
-- if (eeprom[3] & 0x0100)
-- product = "OEM i82557/i82558 10/100 Ethernet";
-- else
-- product = pci_tbl[chip_idx].name;
--
-- printk(KERN_INFO "%s: %s, ", dev->name, product);
--
-- for (i = 0; i < 5; i++)
-- printk("%2.2X:", dev->dev_addr[i]);
-- printk("%2.2X, ", dev->dev_addr[i]);
--#ifdef USE_IO
-- printk("I/O at %#3lx, ", ioaddr);
--#endif
-- printk("IRQ %d.\n", pdev->irq);
--
--#if 1 || defined(kernel_bloat)
-- /* OK, this is pure kernel bloat. I don't like it when other drivers
-- waste non-pageable kernel space to emit similar messages, but I need
-- them for bug reports. */
-- {
-- const char *connectors[] = {" RJ45", " BNC", " AUI", " MII"};
-- /* The self-test results must be paragraph aligned. */
-- s32 str[6], *volatile self_test_results;
-- int boguscnt = 16000; /* Timeout for set-test. */
-- if ((eeprom[3] & 0x03) != 0x03)
-- printk(KERN_INFO " Receiver lock-up bug exists -- enabling"
-- " work-around.\n");
-- printk(KERN_INFO " Board assembly %4.4x%2.2x-%3.3d, Physical"
-- " connectors present:",
-- eeprom[8], eeprom[9]>>8, eeprom[9] & 0xff);
-- for (i = 0; i < 4; i++)
-- if (eeprom[5] & (1<<i))
-- printk(connectors[i]);
-- printk("\n"KERN_INFO" Primary interface chip %s PHY #%d.\n",
-- phys[(eeprom[6]>>8)&15], eeprom[6] & 0x1f);
-- if (eeprom[7] & 0x0700)
-- printk(KERN_INFO " Secondary interface chip %s.\n",
-- phys[(eeprom[7]>>8)&7]);
-- if (((eeprom[6]>>8) & 0x3f) == DP83840
-- || ((eeprom[6]>>8) & 0x3f) == DP83840A) {
-- int mdi_reg23 = mdio_read(ioaddr, eeprom[6] & 0x1f, 23) | 0x0422;
-- if (congenb)
-- mdi_reg23 |= 0x0100;
-- printk(KERN_INFO" DP83840 specific setup, setting register 23 to %4.4x.\n",
-- mdi_reg23);
-- mdio_write(ioaddr, eeprom[6] & 0x1f, 23, mdi_reg23);
-- }
-- if ((option >= 0) && (option & 0x70)) {
-- printk(KERN_INFO " Forcing %dMbs %s-duplex operation.\n",
-- (option & 0x20 ? 100 : 10),
-- (option & 0x10 ? "full" : "half"));
-- mdio_write(ioaddr, eeprom[6] & 0x1f, 0,
-- ((option & 0x20) ? 0x2000 : 0) | /* 100mbps? */
-- ((option & 0x10) ? 0x0100 : 0)); /* Full duplex? */
-- }
--
-- /* Perform a system self-test. */
-- self_test_results = (s32*) ((((long) str) + 15) & ~0xf);
-- self_test_results[0] = 0;
-- self_test_results[1] = -1;
-- outl(virt_to_bus(self_test_results) | PortSelfTest, ioaddr + SCBPort);
-- do {
-- udelay(10);
-- } while (self_test_results[1] == -1 && --boguscnt >= 0);
--
-- if (boguscnt < 0) { /* Test optimized out. */
-- printk(KERN_ERR "Self test failed, status %8.8x:\n"
-- KERN_ERR " Failure to initialize the i82557.\n"
-- KERN_ERR " Verify that the card is a bus-master"
-- " capable slot.\n",
-- self_test_results[1]);
-- } else
-- printk(KERN_INFO " General self-test: %s.\n"
-- KERN_INFO " Serial sub-system self-test: %s.\n"
-- KERN_INFO " Internal registers self-test: %s.\n"
-- KERN_INFO " ROM checksum self-test: %s (%#8.8x).\n",
-- self_test_results[1] & 0x1000 ? "failed" : "passed",
-- self_test_results[1] & 0x0020 ? "failed" : "passed",
-- self_test_results[1] & 0x0008 ? "failed" : "passed",
-- self_test_results[1] & 0x0004 ? "failed" : "passed",
-- self_test_results[0]);
-- }
--#endif /* kernel_bloat */
--
-- outl(PortReset, ioaddr + SCBPort);
-- inl(ioaddr + SCBPort);
-- /* Honor PortReset timing. */
-- udelay(10);
--
-- /* We do a request_region() only to register /proc/ioports info. */
-- request_region(ioaddr, SPEEDO3_TOTAL_SIZE, "Intel Speedo3 Ethernet");
--
-- dev->base_addr = ioaddr;
-- dev->irq = pdev->irq;
--
-- sp = dev->priv;
-- if (dev->priv == NULL) {
-- void *mem = kmalloc(sizeof(*sp), GFP_KERNEL);
-- dev->priv = sp = mem; /* Cache align here if kmalloc does not. */
-- sp->priv_addr = mem;
-- }
-- memset(sp, 0, sizeof(*sp));
-- sp->next_module = root_speedo_dev;
-- root_speedo_dev = dev;
--
-- sp->pci_bus = pci_bus;
-- sp->pci_devfn = pci_devfn;
-- sp->chip_id = chip_idx;
-- sp->acpi_pwr = acpi_idle_state;
--
-- sp->full_duplex = option >= 0 && (option & 0x10) ? 1 : 0;
-- if (card_idx >= 0) {
-- if (full_duplex[card_idx] >= 0)
-- sp->full_duplex = full_duplex[card_idx];
-- }
-- sp->default_port = option >= 0 ? (option & 0x0f) : 0;
--
-- sp->phy[0] = eeprom[6];
-- sp->phy[1] = eeprom[7];
-- sp->rx_bug = (eeprom[3] & 0x03) == 3 ? 0 : 1;
--
-- if (sp->rx_bug)
-- printk(KERN_INFO " Receiver lock-up workaround activated.\n");
--
-- /* The Speedo-specific entries in the device structure. */
-- dev->open = &speedo_open;
-- dev->hard_start_xmit = &speedo_start_xmit;
--#if defined(HAS_NETIF_QUEUE)
-- dev->tx_timeout = &speedo_tx_timeout;
-- dev->watchdog_timeo = TX_TIMEOUT;
--#endif
-- dev->stop = &speedo_close;
-- dev->get_stats = &speedo_get_stats;
-- dev->set_multicast_list = &set_rx_mode;
-- dev->do_ioctl = &speedo_ioctl;
--
-- return dev;
--}
--
--/* Serial EEPROM section.
-- A "bit" grungy, but we work our way through bit-by-bit :->. */
--/* EEPROM_Ctrl bits. */
--#define EE_SHIFT_CLK 0x01 /* EEPROM shift clock. */
--#define EE_CS 0x02 /* EEPROM chip select. */
--#define EE_DATA_WRITE 0x04 /* EEPROM chip data in. */
--#define EE_DATA_READ 0x08 /* EEPROM chip data out. */
--#define EE_ENB (0x4800 | EE_CS)
--#define EE_WRITE_0 0x4802
--#define EE_WRITE_1 0x4806
--#define EE_OFFSET SCBeeprom
--
--/* The fixes for the code were kindly provided by Dragan Stancevic
-- <visitor@valinux.com> to strictly follow Intel specifications of EEPROM
-- access timing.
-- The publicly available sheet 64486302 (sec. 3.1) specifies 1us access
-- interval for serial EEPROM. However, it looks like that there is an
-- additional requirement dictating larger udelay's in the code below.
-- 2000/05/24 SAW */
--static int do_eeprom_cmd(long ioaddr, int cmd, int cmd_len)
--{
-- unsigned retval = 0;
-- long ee_addr = ioaddr + SCBeeprom;
--
-- io_outw(EE_ENB, ee_addr); udelay(2);
-- io_outw(EE_ENB | EE_SHIFT_CLK, ee_addr); udelay(2);
--
-- /* Shift the command bits out. */
-- do {
-- short dataval = (cmd & (1 << cmd_len)) ? EE_WRITE_1 : EE_WRITE_0;
-- io_outw(dataval, ee_addr); udelay(2);
-- io_outw(dataval | EE_SHIFT_CLK, ee_addr); udelay(2);
-- retval = (retval << 1) | ((io_inw(ee_addr) & EE_DATA_READ) ? 1 : 0);
-- } while (--cmd_len >= 0);
-- io_outw(EE_ENB, ee_addr); udelay(2);
--
-- /* Terminate the EEPROM access. */
-- io_outw(EE_ENB & ~EE_CS, ee_addr);
-- return retval;
--}
--
--static int mdio_read(long ioaddr, int phy_id, int location)
--{
-- int val, boguscnt = 64*10; /* <64 usec. to complete, typ 27 ticks */
-- outl(0x08000000 | (location<<16) | (phy_id<<21), ioaddr + SCBCtrlMDI);
-- do {
-- val = inl(ioaddr + SCBCtrlMDI);
-- if (--boguscnt < 0) {
-- printk(KERN_ERR " mdio_read() timed out with val = %8.8x.\n", val);
-- break;
-- }
-- } while (! (val & 0x10000000));
-- return val & 0xffff;
--}
--
--static int mdio_write(long ioaddr, int phy_id, int location, int value)
--{
-- int val, boguscnt = 64*10; /* <64 usec. to complete, typ 27 ticks */
-- outl(0x04000000 | (location<<16) | (phy_id<<21) | value,
-- ioaddr + SCBCtrlMDI);
-- do {
-- val = inl(ioaddr + SCBCtrlMDI);
-- if (--boguscnt < 0) {
-- printk(KERN_ERR" mdio_write() timed out with val = %8.8x.\n", val);
-- break;
-- }
-- } while (! (val & 0x10000000));
-- return val & 0xffff;
--}
--
--
--static int
--speedo_open(struct net_device *dev)
--{
-- struct speedo_private *sp = (struct speedo_private *)dev->priv;
-- long ioaddr = dev->base_addr;
--
-- if (speedo_debug > 1)
-- printk(KERN_DEBUG "%s: speedo_open() irq %d.\n", dev->name, dev->irq);
--
-- MOD_INC_USE_COUNT;
--
-- /* Set up the Tx queue early.. */
-- sp->cur_tx = 0;
-- sp->dirty_tx = 0;
-- sp->last_cmd = 0;
-- sp->tx_full = 0;
-- sp->lock = (spinlock_t) SPIN_LOCK_UNLOCKED;
-- sp->in_interrupt = 0;
--
-- /* .. we can safely take handler calls during init. */
-- if (request_irq(dev->irq, &speedo_interrupt, SA_SHIRQ, dev->name, dev)) {
-- MOD_DEC_USE_COUNT;
-- return -EAGAIN;
-- }
--
-- dev->if_port = sp->default_port;
--
--#ifdef oh_no_you_dont_unless_you_honour_the_options_passed_in_to_us
-- /* Retrigger negotiation to reset previous errors. */
-- if ((sp->phy[0] & 0x8000) == 0) {
-- int phy_addr = sp->phy[0] & 0x1f ;
-- /* Use 0x3300 for restarting NWay, other values to force xcvr:
-- 0x0000 10-HD
-- 0x0100 10-FD
-- 0x2000 100-HD
-- 0x2100 100-FD
-- */
--#ifdef honor_default_port
-- mdio_write(ioaddr, phy_addr, 0, mii_ctrl[dev->default_port & 7]);
--#else
-- mdio_write(ioaddr, phy_addr, 0, 0x3300);
--#endif
-- }
--#endif
--
-- speedo_init_rx_ring(dev);
--
-- /* Fire up the hardware. */
-- outw(SCBMaskAll, ioaddr + SCBCmd);
-- speedo_resume(dev);
--
-- dev->interrupt = 0;
-- dev->start = 1;
-- netif_start_queue(dev);
--
-- /* Setup the chip and configure the multicast list. */
-- sp->mc_setup_head = NULL;
-- sp->mc_setup_tail = NULL;
-- sp->flow_ctrl = sp->partner = 0;
-- sp->rx_mode = -1; /* Invalid -> always reset the mode. */
-- set_rx_mode(dev);
-- if ((sp->phy[0] & 0x8000) == 0)
-- sp->advertising = mdio_read(ioaddr, sp->phy[0] & 0x1f, 4);
--
-- if (speedo_debug > 2) {
-- printk(KERN_DEBUG "%s: Done speedo_open(), status %8.8x.\n",
-- dev->name, inw(ioaddr + SCBStatus));
-- }
--
-- /* Set the timer. The timer serves a dual purpose:
-- 1) to monitor the media interface (e.g. link beat) and perhaps switch
-- to an alternate media type
-- 2) to monitor Rx activity, and restart the Rx process if the receiver
-- hangs. */
-- init_timer(&sp->timer);
-- sp->timer.expires = RUN_AT((24*HZ)/10); /* 2.4 sec. */
-- sp->timer.data = (unsigned long)dev;
-- sp->timer.function = &speedo_timer; /* timer handler */
-- add_timer(&sp->timer);
--
-- /* No need to wait for the command unit to accept here. */
-- if ((sp->phy[0] & 0x8000) == 0)
-- mdio_read(ioaddr, sp->phy[0] & 0x1f, 0);
--
-- return 0;
--}
--
--/* Start the chip hardware after a full reset. */
--static void speedo_resume(struct net_device *dev)
--{
-- struct speedo_private *sp = (struct speedo_private *)dev->priv;
-- long ioaddr = dev->base_addr;
--
-- /* Start with a Tx threshold of 256 (0x..20.... 8 byte units). */
-- sp->tx_threshold = 0x01208000;
--
-- /* Set the segment registers to '0'. */
-- wait_for_cmd_done(ioaddr + SCBCmd);
-- outl(0, ioaddr + SCBPointer);
-- /* impose a delay to avoid a bug */
-- inl(ioaddr + SCBPointer);
-- udelay(10);
-- outb(RxAddrLoad, ioaddr + SCBCmd);
-- wait_for_cmd_done(ioaddr + SCBCmd);
-- outb(CUCmdBase, ioaddr + SCBCmd);
-- wait_for_cmd_done(ioaddr + SCBCmd);
--
-- /* Load the statistics block and rx ring addresses. */
-- outl(virt_to_bus(&sp->lstats), ioaddr + SCBPointer);
-- outb(CUStatsAddr, ioaddr + SCBCmd);
-- sp->lstats.done_marker = 0;
-- wait_for_cmd_done(ioaddr + SCBCmd);
--
-- if (sp->rx_ringp[sp->cur_rx % RX_RING_SIZE] == NULL) {
-- if (speedo_debug > 2)
-- printk(KERN_DEBUG "%s: NULL cur_rx in speedo_resume().\n",
-- dev->name);
-- } else {
-- outl(virt_to_bus(sp->rx_ringp[sp->cur_rx % RX_RING_SIZE]),
-- ioaddr + SCBPointer);
-- outb(RxStart, ioaddr + SCBCmd);
-- wait_for_cmd_done(ioaddr + SCBCmd);
-- }
--
-- outb(CUDumpStats, ioaddr + SCBCmd);
--
-- /* Fill the first command with our physical address. */
-- {
-- struct descriptor *ias_cmd;
--
-- ias_cmd =
-- (struct descriptor *)&sp->tx_ring[sp->cur_tx++ % TX_RING_SIZE];
-- /* Avoid a bug(?!) here by marking the command already completed. */
-- ias_cmd->cmd_status = cpu_to_le32((CmdSuspend | CmdIASetup) | 0xa000);
-- ias_cmd->link =
-- virt_to_le32desc(&sp->tx_ring[sp->cur_tx % TX_RING_SIZE]);
-- memcpy(ias_cmd->params, dev->dev_addr, 6);
-- sp->last_cmd = ias_cmd;
-- }
--
-- /* Start the chip's Tx process and unmask interrupts. */
-- wait_for_cmd_done(ioaddr + SCBCmd);
-- outl(virt_to_bus(&sp->tx_ring[sp->dirty_tx % TX_RING_SIZE]),
-- ioaddr + SCBPointer);
-- /* We are not ACK-ing FCP and ER in the interrupt handler yet so they should
-- remain masked --Dragan */
-- outw(CUStart | SCBMaskEarlyRx | SCBMaskFlowCtl, ioaddr + SCBCmd);
--}
--
--/* Media monitoring and control. */
--static void speedo_timer(unsigned long data)
--{
-- struct net_device *dev = (struct net_device *)data;
-- struct speedo_private *sp = (struct speedo_private *)dev->priv;
-- long ioaddr = dev->base_addr;
-- int phy_num = sp->phy[0] & 0x1f;
--
-- /* We have MII and lost link beat. */
-- if ((sp->phy[0] & 0x8000) == 0) {
-- int partner = mdio_read(ioaddr, phy_num, 5);
-- if (partner != sp->partner) {
-- int flow_ctrl = sp->advertising & partner & 0x0400 ? 1 : 0;
-- if (speedo_debug > 2) {
-- printk(KERN_DEBUG "%s: Link status change.\n", dev->name);
-- printk(KERN_DEBUG "%s: Old partner %x, new %x, adv %x.\n",
-- dev->name, sp->partner, partner, sp->advertising);
-- }
-- sp->partner = partner;
-- if (flow_ctrl != sp->flow_ctrl) {
-- sp->flow_ctrl = flow_ctrl;
-- sp->rx_mode = -1; /* Trigger a reload. */
-- }
-- /* Clear sticky bit. */
-- mdio_read(ioaddr, phy_num, 1);
-- /* If link beat has returned... */
-- if (mdio_read(ioaddr, phy_num, 1) & 0x0004)
-- dev->flags |= IFF_RUNNING;
-- else
-- dev->flags &= ~IFF_RUNNING;
-- }
-- }
-- if (speedo_debug > 3) {
-- printk(KERN_DEBUG "%s: Media control tick, status %4.4x.\n",
-- dev->name, inw(ioaddr + SCBStatus));
-- }
-- if (sp->rx_mode < 0 ||
-- (sp->rx_bug && jiffies - sp->last_rx_time > 2*HZ)) {
-- /* We haven't received a packet in a Long Time. We might have been
-- bitten by the receiver hang bug. This can be cleared by sending
-- a set multicast list command. */
-- if (speedo_debug > 2)
-- printk(KERN_DEBUG "%s: Sending a multicast list set command"
-- " from a timer routine.\n", dev->name);
-- set_rx_mode(dev);
-- }
-- /* We must continue to monitor the media. */
-- sp->timer.expires = RUN_AT(2*HZ); /* 2.0 sec. */
-- add_timer(&sp->timer);
--}
--
--static void speedo_show_state(struct net_device *dev)
--{
-- struct speedo_private *sp = (struct speedo_private *)dev->priv;
--#if 0
-- long ioaddr = dev->base_addr;
-- int phy_num = sp->phy[0] & 0x1f;
--#endif
-- int i;
--
-- /* Print a few items for debugging. */
-- if (speedo_debug > 0) {
-- int i;
-- printk(KERN_DEBUG "%s: Tx ring dump, Tx queue %u / %u:\n", dev->name,
-- sp->cur_tx, sp->dirty_tx);
-- for (i = 0; i < TX_RING_SIZE; i++)
-- printk(KERN_DEBUG "%s: %c%c%2d %8.8x.\n", dev->name,
-- i == sp->dirty_tx % TX_RING_SIZE ? '*' : ' ',
-- i == sp->cur_tx % TX_RING_SIZE ? '=' : ' ',
-- i, sp->tx_ring[i].status);
-- }
-- printk(KERN_DEBUG "%s: Printing Rx ring"
-- " (next to receive into %u, dirty index %u).\n",
-- dev->name, sp->cur_rx, sp->dirty_rx);
--
-- for (i = 0; i < RX_RING_SIZE; i++)
-- printk(KERN_DEBUG "%s: %c%c%c%2d %8.8x.\n", dev->name,
-- sp->rx_ringp[i] == sp->last_rxf ? 'l' : ' ',
-- i == sp->dirty_rx % RX_RING_SIZE ? '*' : ' ',
-- i == sp->cur_rx % RX_RING_SIZE ? '=' : ' ',
-- i, (sp->rx_ringp[i] != NULL) ?
-- (unsigned)sp->rx_ringp[i]->status : 0);
--
--#if 0
-- for (i = 0; i < 16; i++) {
-- /* FIXME: what does it mean? --SAW */
-- if (i == 6) i = 21;
-- printk(KERN_DEBUG "%s: PHY index %d register %d is %4.4x.\n",
-- dev->name, phy_num, i, mdio_read(ioaddr, phy_num, i));
-- }
--#endif
--
--}
--
--/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
--static void
--speedo_init_rx_ring(struct net_device *dev)
--{
-- struct speedo_private *sp = (struct speedo_private *)dev->priv;
-- struct RxFD *rxf, *last_rxf = NULL;
-- int i;
--
-- sp->cur_rx = 0;
--
-- for (i = 0; i < RX_RING_SIZE; i++) {
-- struct sk_buff *skb;
-- skb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD));
-- sp->rx_skbuff[i] = skb;
-- if (skb == NULL)
-- break; /* OK. Just initially short of Rx bufs. */
-- skb->dev = dev; /* Mark as being used by this device. */
-- rxf = (struct RxFD *)skb->tail;
-- sp->rx_ringp[i] = rxf;
-- skb_reserve(skb, sizeof(struct RxFD));
-- if (last_rxf)
-- last_rxf->link = virt_to_le32desc(rxf);
-- last_rxf = rxf;
-- rxf->status = cpu_to_le32(0x00000001); /* '1' is flag value only. */
-- rxf->link = 0; /* None yet. */
-- /* This field unused by i82557. */
-- rxf->rx_buf_addr = 0xffffffff;
-- rxf->count = cpu_to_le32(PKT_BUF_SZ << 16);
-- }
-- sp->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
-- /* Mark the last entry as end-of-list. */
-- last_rxf->status = cpu_to_le32(0xC0000002); /* '2' is flag value only. */
-- sp->last_rxf = last_rxf;
--}
--
--static void speedo_purge_tx(struct net_device *dev)
--{
-- struct speedo_private *sp = (struct speedo_private *)dev->priv;
-- int entry;
--
-- while ((int)(sp->cur_tx - sp->dirty_tx) > 0) {
-- entry = sp->dirty_tx % TX_RING_SIZE;
-- if (sp->tx_skbuff[entry]) {
-- sp->stats.tx_errors++;
-- dev_free_skb(sp->tx_skbuff[entry]);
-- sp->tx_skbuff[entry] = 0;
-- }
-- sp->dirty_tx++;
-- }
-- while (sp->mc_setup_head != NULL) {
-- struct speedo_mc_block *t;
-- if (speedo_debug > 1)
-- printk(KERN_DEBUG "%s: freeing mc frame.\n", dev->name);
-- t = sp->mc_setup_head->next;
-- kfree(sp->mc_setup_head);
-- sp->mc_setup_head = t;
-- }
-- sp->mc_setup_tail = NULL;
-- sp->tx_full = 0;
-- netif_wake_queue(dev);
--}
--
--static void reset_mii(struct net_device *dev)
--{
-- struct speedo_private *sp = (struct speedo_private *)dev->priv;
-- long ioaddr = dev->base_addr;
-- /* Reset the MII transceiver, suggested by Fred Young @ scalable.com. */
-- if ((sp->phy[0] & 0x8000) == 0) {
-- int phy_addr = sp->phy[0] & 0x1f;
-- int advertising = mdio_read(ioaddr, phy_addr, 4);
-- int mii_bmcr = mdio_read(ioaddr, phy_addr, 0);
-- mdio_write(ioaddr, phy_addr, 0, 0x0400);
-- mdio_write(ioaddr, phy_addr, 1, 0x0000);
-- mdio_write(ioaddr, phy_addr, 4, 0x0000);
-- mdio_write(ioaddr, phy_addr, 0, 0x8000);
--#ifdef honor_default_port
-- mdio_write(ioaddr, phy_addr, 0, mii_ctrl[dev->default_port & 7]);
--#else
-- mdio_read(ioaddr, phy_addr, 0);
-- mdio_write(ioaddr, phy_addr, 0, mii_bmcr);
-- mdio_write(ioaddr, phy_addr, 4, advertising);
--#endif
-- }
--}
--
--static void speedo_tx_timeout(struct net_device *dev)
--{
-- struct speedo_private *sp = (struct speedo_private *)dev->priv;
-- long ioaddr = dev->base_addr;
-- int status = inw(ioaddr + SCBStatus);
-- unsigned long flags;
--
-- printk(KERN_WARNING "%s: Transmit timed out: status %4.4x "
-- " %4.4x at %d/%d command %8.8x.\n",
-- dev->name, status, inw(ioaddr + SCBCmd),
-- sp->dirty_tx, sp->cur_tx,
-- sp->tx_ring[sp->dirty_tx % TX_RING_SIZE].status);
--
-- /* Trigger a stats dump to give time before the reset. */
-- speedo_get_stats(dev);
--
-- speedo_show_state(dev);
--#if 0
-- if ((status & 0x00C0) != 0x0080
-- && (status & 0x003C) == 0x0010) {
-- /* Only the command unit has stopped. */
-- printk(KERN_WARNING "%s: Trying to restart the transmitter...\n",
-- dev->name);
-- outl(virt_to_bus(&sp->tx_ring[sp->dirty_tx % TX_RING_SIZE]),
-- ioaddr + SCBPointer);
-- outw(CUStart, ioaddr + SCBCmd);
-- reset_mii(dev);
-- } else {
--#else
-- {
--#endif
-- start_bh_atomic();
-- /* Ensure that timer routine doesn't run! */
-- del_timer(&sp->timer);
-- end_bh_atomic();
-- /* Reset the Tx and Rx units. */
-- outl(PortReset, ioaddr + SCBPort);
-- /* We may get spurious interrupts here. But I don't think that they
-- may do much harm. 1999/12/09 SAW */
-- udelay(10);
-- /* Disable interrupts. */
-- outw(SCBMaskAll, ioaddr + SCBCmd);
-- synchronize_irq();
-- speedo_tx_buffer_gc(dev);
-- /* Free as much as possible.
-- It helps to recover from a hang because of out-of-memory.
-- It also simplifies speedo_resume() in case TX ring is full or
-- close-to-be full. */
-- speedo_purge_tx(dev);
-- speedo_refill_rx_buffers(dev, 1);
-- spin_lock_irqsave(&sp->lock, flags);
-- speedo_resume(dev);
-- sp->rx_mode = -1;
-- dev->trans_start = jiffies;
-- spin_unlock_irqrestore(&sp->lock, flags);
-- set_rx_mode(dev); /* it takes the spinlock itself --SAW */
-- /* Reset MII transceiver. Do it before starting the timer to serialize
-- mdio_xxx operations. Yes, it's a paranoya :-) 2000/05/09 SAW */
-- reset_mii(dev);
-- sp->timer.expires = RUN_AT(2*HZ);
-- add_timer(&sp->timer);
-- }
-- return;
--}
--
--static int
--speedo_start_xmit(struct sk_buff *skb, struct net_device *dev)
--{
-- struct speedo_private *sp = (struct speedo_private *)dev->priv;
-- long ioaddr = dev->base_addr;
-- int entry;
--
--#if ! defined(HAS_NETIF_QUEUE)
-- if (test_bit(0, (void*)&dev->tbusy) != 0) {
-- int tickssofar = jiffies - dev->trans_start;
-- if (tickssofar < TX_TIMEOUT - 2)
-- return 1;
-- if (tickssofar < TX_TIMEOUT) {
-- /* Reap sent packets from the full Tx queue. */
-- unsigned long flags;
-- /* Take a spinlock to make wait_for_cmd_done and sending the
-- command atomic. --SAW */
-- spin_lock_irqsave(&sp->lock, flags);
-- wait_for_cmd_done(ioaddr + SCBCmd);
-- outw(SCBTriggerIntr, ioaddr + SCBCmd);
-- spin_unlock_irqrestore(&sp->lock, flags);
-- return 1;
-- }
-- speedo_tx_timeout(dev);
-- return 1;
-- }
--#endif
--
-- { /* Prevent interrupts from changing the Tx ring from underneath us. */
-- unsigned long flags;
--
-- spin_lock_irqsave(&sp->lock, flags);
--
-- /* Check if there are enough space. */
-- if ((int)(sp->cur_tx - sp->dirty_tx) >= TX_QUEUE_LIMIT) {
-- printk(KERN_ERR "%s: incorrect tbusy state, fixed.\n", dev->name);
-- netif_stop_queue(dev);
-- sp->tx_full = 1;
-- spin_unlock_irqrestore(&sp->lock, flags);
-- return 1;
-- }
--
-- /* Calculate the Tx descriptor entry. */
-- entry = sp->cur_tx++ % TX_RING_SIZE;
--
-- sp->tx_skbuff[entry] = skb;
-- sp->tx_ring[entry].status =
-- cpu_to_le32(CmdSuspend | CmdTx | CmdTxFlex);
-- if (!(entry & ((TX_RING_SIZE>>2)-1)))
-- sp->tx_ring[entry].status |= cpu_to_le32(CmdIntr);
-- sp->tx_ring[entry].link =
-- virt_to_le32desc(&sp->tx_ring[sp->cur_tx % TX_RING_SIZE]);
-- sp->tx_ring[entry].tx_desc_addr =
-- virt_to_le32desc(&sp->tx_ring[entry].tx_buf_addr0);
-- /* The data region is always in one buffer descriptor. */
-- sp->tx_ring[entry].count = cpu_to_le32(sp->tx_threshold);
-- sp->tx_ring[entry].tx_buf_addr0 = virt_to_le32desc(skb->data);
-- sp->tx_ring[entry].tx_buf_size0 = cpu_to_le32(skb->len);
-- /* Trigger the command unit resume. */
-- wait_for_cmd_done(ioaddr + SCBCmd);
-- clear_suspend(sp->last_cmd);
-- /* We want the time window between clearing suspend flag on the previous
-- command and resuming CU to be as small as possible.
-- Interrupts in between are very undesired. --SAW */
-- outb(CUResume, ioaddr + SCBCmd);
-- sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry];
--
-- /* Leave room for set_rx_mode(). If there is no more space than reserved
-- for multicast filter mark the ring as full. */
-- if ((int)(sp->cur_tx - sp->dirty_tx) >= TX_QUEUE_LIMIT) {
-- netif_stop_queue(dev);
-- sp->tx_full = 1;
-- }
--
-- spin_unlock_irqrestore(&sp->lock, flags);
-- }
--
-- dev->trans_start = jiffies;
--
-- return 0;
--}
--
--static void speedo_tx_buffer_gc(struct net_device *dev)
--{
-- unsigned int dirty_tx;
-- struct speedo_private *sp = (struct speedo_private *)dev->priv;
--
-- dirty_tx = sp->dirty_tx;
-- while ((int)(sp->cur_tx - dirty_tx) > 0) {
-- int entry = dirty_tx % TX_RING_SIZE;
-- int status = le32_to_cpu(sp->tx_ring[entry].status);
--
-- if (speedo_debug > 5)
-- printk(KERN_DEBUG " scavenge candidate %d status %4.4x.\n",
-- entry, status);
-- if ((status & StatusComplete) == 0)
-- break; /* It still hasn't been processed. */
-- if (status & TxUnderrun)
-- if (sp->tx_threshold < 0x01e08000) {
-- if (speedo_debug > 2)
-- printk(KERN_DEBUG "%s: TX underrun, threshold adjusted.\n",
-- dev->name);
-- sp->tx_threshold += 0x00040000;
-- }
-- /* Free the original skb. */
-- if (sp->tx_skbuff[entry]) {
-- sp->stats.tx_packets++; /* Count only user packets. */
-- /* sp->stats.tx_bytes += sp->tx_skbuff[entry]->len; */
-- dev_free_skb(sp->tx_skbuff[entry]);
-- sp->tx_skbuff[entry] = 0;
-- }
-- dirty_tx++;
-- }
--
-- if (speedo_debug && (int)(sp->cur_tx - dirty_tx) > TX_RING_SIZE) {
-- printk(KERN_ERR "out-of-sync dirty pointer, %d vs. %d,"
-- " full=%d.\n",
-- dirty_tx, sp->cur_tx, sp->tx_full);
-- dirty_tx += TX_RING_SIZE;
-- }
--
-- while (sp->mc_setup_head != NULL
-- && (int)(dirty_tx - sp->mc_setup_head->tx - 1) > 0) {
-- struct speedo_mc_block *t;
-- if (speedo_debug > 1)
-- printk(KERN_DEBUG "%s: freeing mc frame.\n", dev->name);
-- t = sp->mc_setup_head->next;
-- kfree(sp->mc_setup_head);
-- sp->mc_setup_head = t;
-- }
-- if (sp->mc_setup_head == NULL)
-- sp->mc_setup_tail = NULL;
--
-- sp->dirty_tx = dirty_tx;
--}
--
--/* The interrupt handler does all of the Rx thread work and cleans up
-- after the Tx thread. */
--static void speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
--{
-- struct net_device *dev = (struct net_device *)dev_instance;
-- struct speedo_private *sp;
-- long ioaddr, boguscnt = max_interrupt_work;
-- unsigned short status;
--
--#ifndef final_version
-- if (dev == NULL) {
-- printk(KERN_ERR "speedo_interrupt(): irq %d for unknown device.\n", irq);
-- return;
-- }
--#endif
--
-- ioaddr = dev->base_addr;
-- sp = (struct speedo_private *)dev->priv;
--
--#ifndef final_version
-- /* A lock to prevent simultaneous entry on SMP machines. */
-- if (test_and_set_bit(0, (void*)&sp->in_interrupt)) {
-- printk(KERN_ERR"%s: SMP simultaneous entry of an interrupt handler.\n",
-- dev->name);
-- sp->in_interrupt = 0; /* Avoid halting machine. */
-- return;
-- }
-- dev->interrupt = 1;
--#endif
--
-- do {
-- status = inw(ioaddr + SCBStatus);
-- /* Acknowledge all of the current interrupt sources ASAP. */
-- /* Will change from 0xfc00 to 0xff00 when we start handling
-- FCP and ER interrupts --Dragan */
-- outw(status & 0xfc00, ioaddr + SCBStatus);
--
-- if (speedo_debug > 3)
-- printk(KERN_DEBUG "%s: interrupt status=%#4.4x.\n",
-- dev->name, status);
--
-- if ((status & 0xfc00) == 0)
-- break;
--
-- /* Always check if all rx buffers are allocated. --SAW */
-- speedo_refill_rx_buffers(dev, 0);
--
-- if ((status & 0x5000) || /* Packet received, or Rx error. */
-- (sp->rx_ring_state&(RrNoMem|RrPostponed)) == RrPostponed)
-- /* Need to gather the postponed packet. */
-- speedo_rx(dev);
--
-- if (status & 0x1000) {
-- spin_lock(&sp->lock);
-- if ((status & 0x003c) == 0x0028) { /* No more Rx buffers. */
-- struct RxFD *rxf;
-- printk(KERN_WARNING "%s: card reports no RX buffers.\n",
-- dev->name);
-- rxf = sp->rx_ringp[sp->cur_rx % RX_RING_SIZE];
-- if (rxf == NULL) {
-- if (speedo_debug > 2)
-- printk(KERN_DEBUG
-- "%s: NULL cur_rx in speedo_interrupt().\n",
-- dev->name);
-- sp->rx_ring_state |= RrNoMem|RrNoResources;
-- } else if (rxf == sp->last_rxf) {
-- if (speedo_debug > 2)
-- printk(KERN_DEBUG
-- "%s: cur_rx is last in speedo_interrupt().\n",
-- dev->name);
-- sp->rx_ring_state |= RrNoMem|RrNoResources;
-- } else
-- outb(RxResumeNoResources, ioaddr + SCBCmd);
-- } else if ((status & 0x003c) == 0x0008) { /* No resources. */
-- struct RxFD *rxf;
-- printk(KERN_WARNING "%s: card reports no resources.\n",
-- dev->name);
-- rxf = sp->rx_ringp[sp->cur_rx % RX_RING_SIZE];
-- if (rxf == NULL) {
-- if (speedo_debug > 2)
-- printk(KERN_DEBUG
-- "%s: NULL cur_rx in speedo_interrupt().\n",
-- dev->name);
-- sp->rx_ring_state |= RrNoMem|RrNoResources;
-- } else if (rxf == sp->last_rxf) {
-- if (speedo_debug > 2)
-- printk(KERN_DEBUG
-- "%s: cur_rx is last in speedo_interrupt().\n",
-- dev->name);
-- sp->rx_ring_state |= RrNoMem|RrNoResources;
-- } else {
-- /* Restart the receiver. */
-- outl(virt_to_bus(sp->rx_ringp[sp->cur_rx % RX_RING_SIZE]),
-- ioaddr + SCBPointer);
-- outb(RxStart, ioaddr + SCBCmd);
-- }
-- }
-- sp->stats.rx_errors++;
-- spin_unlock(&sp->lock);
-- }
--
-- if ((sp->rx_ring_state&(RrNoMem|RrNoResources)) == RrNoResources) {
-- printk(KERN_WARNING
-- "%s: restart the receiver after a possible hang.\n",
-- dev->name);
-- spin_lock(&sp->lock);
-- /* Restart the receiver.
-- I'm not sure if it's always right to restart the receiver
-- here but I don't know another way to prevent receiver hangs.
-- 1999/12/25 SAW */
-- outl(virt_to_bus(sp->rx_ringp[sp->cur_rx % RX_RING_SIZE]),
-- ioaddr + SCBPointer);
-- outb(RxStart, ioaddr + SCBCmd);
-- sp->rx_ring_state &= ~RrNoResources;
-- spin_unlock(&sp->lock);
-- }
--
-- /* User interrupt, Command/Tx unit interrupt or CU not active. */
-- if (status & 0xA400) {
-- spin_lock(&sp->lock);
-- speedo_tx_buffer_gc(dev);
-- if (sp->tx_full
-- && (int)(sp->cur_tx - sp->dirty_tx) < TX_QUEUE_UNFULL) {
-- /* The ring is no longer full. */
-- sp->tx_full = 0;
-- netif_wake_queue(dev); /* Attention: under a spinlock. --SAW */
-- }
-- spin_unlock(&sp->lock);
-- }
--
-- if (--boguscnt < 0) {
-- printk(KERN_ERR "%s: Too much work at interrupt, status=0x%4.4x.\n",
-- dev->name, status);
-- /* Clear all interrupt sources. */
-- /* Will change from 0xfc00 to 0xff00 when we start handling
-- FCP and ER interrupts --Dragan */
-- outl(0xfc00, ioaddr + SCBStatus);
-- break;
-- }
-- } while (1);
--
-- if (speedo_debug > 3)
-- printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
-- dev->name, inw(ioaddr + SCBStatus));
--
-- dev->interrupt = 0;
-- clear_bit(0, (void*)&sp->in_interrupt);
-- return;
--}
--
--static inline struct RxFD *speedo_rx_alloc(struct net_device *dev, int entry)
--{
-- struct speedo_private *sp = (struct speedo_private *)dev->priv;
-- struct RxFD *rxf;
-- struct sk_buff *skb;
-- /* Get a fresh skbuff to replace the consumed one. */
-- skb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD));
-- sp->rx_skbuff[entry] = skb;
-- if (skb == NULL) {
-- sp->rx_ringp[entry] = NULL;
-- return NULL;
-- }
-- rxf = sp->rx_ringp[entry] = (struct RxFD *)skb->tail;
-- skb->dev = dev;
-- skb_reserve(skb, sizeof(struct RxFD));
-- rxf->rx_buf_addr = virt_to_bus(skb->tail);
-- return rxf;
--}
--
--static inline void speedo_rx_link(struct net_device *dev, int entry,
-- struct RxFD *rxf)
--{
-- struct speedo_private *sp = (struct speedo_private *)dev->priv;
-- rxf->status = cpu_to_le32(0xC0000001); /* '1' for driver use only. */
-- rxf->link = 0; /* None yet. */
-- rxf->count = cpu_to_le32(PKT_BUF_SZ << 16);
-- sp->last_rxf->link = virt_to_le32desc(rxf);
-- sp->last_rxf->status &= cpu_to_le32(~0xC0000000);
-- sp->last_rxf = rxf;
--}
--
--static int speedo_refill_rx_buf(struct net_device *dev, int force)
--{
-- struct speedo_private *sp = (struct speedo_private *)dev->priv;
-- int entry;
-- struct RxFD *rxf;
--
-- entry = sp->dirty_rx % RX_RING_SIZE;
-- if (sp->rx_skbuff[entry] == NULL) {
-- rxf = speedo_rx_alloc(dev, entry);
-- if (rxf == NULL) {
-- unsigned int forw;
-- int forw_entry;
-- if (speedo_debug > 2 || !(sp->rx_ring_state & RrOOMReported)) {
-- printk(KERN_WARNING "%s: can't fill rx buffer (force %d)!\n",
-- dev->name, force);
-- speedo_show_state(dev);
-- sp->rx_ring_state |= RrOOMReported;
-- }
-- if (!force)
-- return -1; /* Better luck next time! */
-- /* Borrow an skb from one of next entries. */
-- for (forw = sp->dirty_rx + 1; forw != sp->cur_rx; forw++)
-- if (sp->rx_skbuff[forw % RX_RING_SIZE] != NULL)
-- break;
-- if (forw == sp->cur_rx)
-- return -1;
-- forw_entry = forw % RX_RING_SIZE;
-- sp->rx_skbuff[entry] = sp->rx_skbuff[forw_entry];
-- sp->rx_skbuff[forw_entry] = NULL;
-- rxf = sp->rx_ringp[forw_entry];
-- sp->rx_ringp[forw_entry] = NULL;
-- sp->rx_ringp[entry] = rxf;
-- }
-- } else {
-- rxf = sp->rx_ringp[entry];
-- }
-- speedo_rx_link(dev, entry, rxf);
-- sp->dirty_rx++;
-- sp->rx_ring_state &= ~(RrNoMem|RrOOMReported); /* Mark the progress. */
-- return 0;
--}
--
--static void speedo_refill_rx_buffers(struct net_device *dev, int force)
--{
-- struct speedo_private *sp = (struct speedo_private *)dev->priv;
--
-- /* Refill the RX ring. */
-- while ((int)(sp->cur_rx - sp->dirty_rx) > 0 &&
-- speedo_refill_rx_buf(dev, force) != -1);
--}
--
--static int
--speedo_rx(struct net_device *dev)
--{
-- struct speedo_private *sp = (struct speedo_private *)dev->priv;
-- int entry = sp->cur_rx % RX_RING_SIZE;
-- int status;
-- int rx_work_limit = sp->dirty_rx + RX_RING_SIZE - sp->cur_rx;
-- int alloc_ok = 1;
--
-- if (speedo_debug > 4)
-- printk(KERN_DEBUG " In speedo_rx().\n");
-- /* If we own the next entry, it's a new packet. Send it up. */
-- while (sp->rx_ringp[entry] != NULL &&
-- (status = le32_to_cpu(sp->rx_ringp[entry]->status)) & RxComplete) {
-- int pkt_len = le32_to_cpu(sp->rx_ringp[entry]->count) & 0x3fff;
--
-- if (--rx_work_limit < 0)
-- break;
--
-- /* Check for a rare out-of-memory case: the current buffer is
-- the last buffer allocated in the RX ring. --SAW */
-- if (sp->last_rxf == sp->rx_ringp[entry]) {
-- /* Postpone the packet. It'll be reaped at an interrupt when this
-- packet is no longer the last packet in the ring. */
-- if (speedo_debug > 2)
-- printk(KERN_DEBUG "%s: RX packet postponed!\n",
-- dev->name);
-- sp->rx_ring_state |= RrPostponed;
-- break;
-- }
--
-- if (speedo_debug > 4)
-- printk(KERN_DEBUG " speedo_rx() status %8.8x len %d.\n", status,
-- pkt_len);
-- if ((status & (RxErrTooBig|RxOK|0x0f90)) != RxOK) {
-- if (status & RxErrTooBig)
-- printk(KERN_ERR "%s: Ethernet frame overran the Rx buffer, "
-- "status %8.8x!\n", dev->name, status);
-- else if (! (status & RxOK)) {
-- /* There was a fatal error. This *should* be impossible. */
-- sp->stats.rx_errors++;
-- printk(KERN_ERR "%s: Anomalous event in speedo_rx(), "
-- "status %8.8x.\n",
-- dev->name, status);
-- }
-- } else {
-- struct sk_buff *skb;
--
-- /* Check if the packet is long enough to just accept without
-- copying to a properly sized skbuff. */
-- if (pkt_len < rx_copybreak
-- && (skb = dev_alloc_skb(pkt_len + 2)) != 0) {
-- skb->dev = dev;
-- skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
-- /* 'skb_put()' points to the start of sk_buff data area. */
--#if !defined(__alpha__)
-- /* Packet is in one chunk -- we can copy + cksum. */
-- eth_copy_and_sum(skb, sp->rx_skbuff[entry]->tail, pkt_len, 0);
-- skb_put(skb, pkt_len);
--#else
-- memcpy(skb_put(skb, pkt_len), sp->rx_skbuff[entry]->tail,
-- pkt_len);
--#endif
-- } else {
-- /* Pass up the already-filled skbuff. */
-- skb = sp->rx_skbuff[entry];
-- if (skb == NULL) {
-- printk(KERN_ERR "%s: Inconsistent Rx descriptor chain.\n",
-- dev->name);
-- break;
-- }
-- sp->rx_skbuff[entry] = NULL;
-- skb_put(skb, pkt_len);
-- sp->rx_ringp[entry] = NULL;
-- }
-- skb->protocol = eth_type_trans(skb, dev);
-- netif_rx(skb);
-- sp->stats.rx_packets++;
-- /* sp->stats.rx_bytes += pkt_len; */
-- }
-- entry = (++sp->cur_rx) % RX_RING_SIZE;
-- sp->rx_ring_state &= ~RrPostponed;
-- /* Refill the recently taken buffers.
-- Do it one-by-one to handle traffic bursts better. */
-- if (alloc_ok && speedo_refill_rx_buf(dev, 0) == -1)
-- alloc_ok = 0;
-- }
--
-- /* Try hard to refill the recently taken buffers. */
-- speedo_refill_rx_buffers(dev, 1);
--
-- sp->last_rx_time = jiffies;
--
-- return 0;
--}
--
--static int
--speedo_close(struct net_device *dev)
--{
-- long ioaddr = dev->base_addr;
-- struct speedo_private *sp = (struct speedo_private *)dev->priv;
-- int i;
--
-- dev->start = 0;
-- netif_stop_queue(dev);
--
-- if (speedo_debug > 1)
-- printk(KERN_DEBUG "%s: Shutting down ethercard, status was %4.4x.\n",
-- dev->name, inw(ioaddr + SCBStatus));
--
-- /* Shut off the media monitoring timer. */
-- start_bh_atomic();
-- del_timer(&sp->timer);
-- end_bh_atomic();
--
-- /* Shutting down the chip nicely fails to disable flow control. So.. */
-- outl(PortPartialReset, ioaddr + SCBPort);
--
-- free_irq(dev->irq, dev);
--
-- /* Print a few items for debugging. */
-- if (speedo_debug > 3)
-- speedo_show_state(dev);
--
-- /* Free all the skbuffs in the Rx and Tx queues. */
-- for (i = 0; i < RX_RING_SIZE; i++) {
-- struct sk_buff *skb = sp->rx_skbuff[i];
-- sp->rx_skbuff[i] = 0;
-- /* Clear the Rx descriptors. */
-- if (skb)
-- dev_free_skb(skb);
-- }
--
-- for (i = 0; i < TX_RING_SIZE; i++) {
-- struct sk_buff *skb = sp->tx_skbuff[i];
-- sp->tx_skbuff[i] = 0;
-- /* Clear the Tx descriptors. */
-- if (skb)
-- dev_free_skb(skb);
-- }
--
-- /* Free multicast setting blocks. */
-- for (i = 0; sp->mc_setup_head != NULL; i++) {
-- struct speedo_mc_block *t;
-- t = sp->mc_setup_head->next;
-- kfree(sp->mc_setup_head);
-- sp->mc_setup_head = t;
-- }
-- sp->mc_setup_tail = NULL;
-- if (speedo_debug > 0)
-- printk(KERN_DEBUG "%s: %d multicast blocks dropped.\n", dev->name, i);
--
-- MOD_DEC_USE_COUNT;
--
-- return 0;
--}
--
--/* The Speedo-3 has an especially awkward and unusable method of getting
-- statistics out of the chip. It takes an unpredictable length of time
-- for the dump-stats command to complete. To avoid a busy-wait loop we
-- update the stats with the previous dump results, and then trigger a
-- new dump.
--
-- These problems are mitigated by the current /proc implementation, which
-- calls this routine first to judge the output length, and then to emit the
-- output.
--
-- Oh, and incoming frames are dropped while executing dump-stats!
-- */
--static struct enet_statistics *
--speedo_get_stats(struct net_device *dev)
--{
-- struct speedo_private *sp = (struct speedo_private *)dev->priv;
-- long ioaddr = dev->base_addr;
--
-- /* Update only if the previous dump finished. */
-- if (sp->lstats.done_marker == le32_to_cpu(0xA007)) {
-- sp->stats.tx_aborted_errors += le32_to_cpu(sp->lstats.tx_coll16_errs);
-- sp->stats.tx_window_errors += le32_to_cpu(sp->lstats.tx_late_colls);
-- sp->stats.tx_fifo_errors += le32_to_cpu(sp->lstats.tx_underruns);
-- sp->stats.tx_fifo_errors += le32_to_cpu(sp->lstats.tx_lost_carrier);
-- /*sp->stats.tx_deferred += le32_to_cpu(sp->lstats.tx_deferred);*/
-- sp->stats.collisions += le32_to_cpu(sp->lstats.tx_total_colls);
-- sp->stats.rx_crc_errors += le32_to_cpu(sp->lstats.rx_crc_errs);
-- sp->stats.rx_frame_errors += le32_to_cpu(sp->lstats.rx_align_errs);
-- sp->stats.rx_over_errors += le32_to_cpu(sp->lstats.rx_resource_errs);
-- sp->stats.rx_fifo_errors += le32_to_cpu(sp->lstats.rx_overrun_errs);
-- sp->stats.rx_length_errors += le32_to_cpu(sp->lstats.rx_runt_errs);
-- sp->lstats.done_marker = 0x0000;
-- if (dev->start) {
-- unsigned long flags;
-- /* Take a spinlock to make wait_for_cmd_done and sending the
-- command atomic. --SAW */
-- spin_lock_irqsave(&sp->lock, flags);
-- wait_for_cmd_done(ioaddr + SCBCmd);
-- outb(CUDumpStats, ioaddr + SCBCmd);
-- spin_unlock_irqrestore(&sp->lock, flags);
-- }
-- }
-- return &sp->stats;
--}
--
--static int speedo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
--{
-- struct speedo_private *sp = (struct speedo_private *)dev->priv;
-- long ioaddr = dev->base_addr;
-- u16 *data = (u16 *)&rq->ifr_data;
-- int phy = sp->phy[0] & 0x1f;
--
-- switch(cmd) {
-- case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */
-- data[0] = phy;
-- case SIOCDEVPRIVATE+1: /* Read the specified MII register. */
-- /* FIXME: these operations need to be serialized with MDIO
-- access from the timeout handler.
-- They are currently serialized only with MDIO access from the
-- timer routine. 2000/05/09 SAW */
-- start_bh_atomic();
-- data[3] = mdio_read(ioaddr, data[0], data[1]);
-- end_bh_atomic();
-- return 0;
-- case SIOCDEVPRIVATE+2: /* Write the specified MII register */
-- if (!capable(CAP_NET_ADMIN))
-- return -EPERM;
-- start_bh_atomic();
-- mdio_write(ioaddr, data[0], data[1], data[2]);
-- end_bh_atomic();
-- return 0;
-- default:
-- return -EOPNOTSUPP;
-- }
--}
--
--/* Set or clear the multicast filter for this adaptor.
-- This is very ugly with Intel chips -- we usually have to execute an
-- entire configuration command, plus process a multicast command.
-- This is complicated. We must put a large configuration command and
-- an arbitrarily-sized multicast command in the transmit list.
-- To minimize the disruption -- the previous command might have already
-- loaded the link -- we convert the current command block, normally a Tx
-- command, into a no-op and link it to the new command.
--*/
--static void set_rx_mode(struct net_device *dev)
--{
-- struct speedo_private *sp = (struct speedo_private *)dev->priv;
-- long ioaddr = dev->base_addr;
-- struct descriptor *last_cmd;
-- char new_rx_mode;
-- unsigned long flags;
-- int entry, i;
--
-- if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
-- new_rx_mode = 3;
-- } else if ((dev->flags & IFF_ALLMULTI) ||
-- dev->mc_count > multicast_filter_limit) {
-- new_rx_mode = 1;
-- } else
-- new_rx_mode = 0;
--
-- if (speedo_debug > 3)
-- printk(KERN_DEBUG "%s: set_rx_mode %d -> %d\n", dev->name,
-- sp->rx_mode, new_rx_mode);
--
-- if ((int)(sp->cur_tx - sp->dirty_tx) > TX_RING_SIZE - TX_MULTICAST_SIZE) {
-- /* The Tx ring is full -- don't add anything! Hope the mode will be
-- * set again later. */
-- sp->rx_mode = -1;
-- return;
-- }
--
-- if (new_rx_mode != sp->rx_mode) {
-- u8 *config_cmd_data;
--
-- spin_lock_irqsave(&sp->lock, flags);
-- entry = sp->cur_tx++ % TX_RING_SIZE;
-- last_cmd = sp->last_cmd;
-- sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry];
--
-- sp->tx_skbuff[entry] = 0; /* Redundant. */
-- sp->tx_ring[entry].status = cpu_to_le32(CmdSuspend | CmdConfigure);
-- sp->tx_ring[entry].link =
-- virt_to_le32desc(&sp->tx_ring[(entry + 1) % TX_RING_SIZE]);
-- config_cmd_data = (void *)&sp->tx_ring[entry].tx_desc_addr;
-- /* Construct a full CmdConfig frame. */
-- memcpy(config_cmd_data, i82558_config_cmd, sizeof(i82558_config_cmd));
-- config_cmd_data[1] = (txfifo << 4) | rxfifo;
-- config_cmd_data[4] = rxdmacount;
-- config_cmd_data[5] = txdmacount + 0x80;
-- config_cmd_data[15] |= (new_rx_mode & 2) ? 1 : 0;
-- /* 0x80 doesn't disable FC 0x84 does.
-- Disable Flow control since we are not ACK-ing any FC interrupts
-- for now. --Dragan */
-- config_cmd_data[19] = 0x84;
-- config_cmd_data[19] |= sp->full_duplex ? 0x40 : 0;
-- config_cmd_data[21] = (new_rx_mode & 1) ? 0x0D : 0x05;
-- if (sp->phy[0] & 0x8000) { /* Use the AUI port instead. */
-- config_cmd_data[15] |= 0x80;
-- config_cmd_data[8] = 0;
-- }
-- /* Trigger the command unit resume. */
-- wait_for_cmd_done(ioaddr + SCBCmd);
-- clear_suspend(last_cmd);
-- outb(CUResume, ioaddr + SCBCmd);
-- if ((int)(sp->cur_tx - sp->dirty_tx) >= TX_QUEUE_LIMIT) {
-- netif_stop_queue(dev);
-- sp->tx_full = 1;
-- }
-- spin_unlock_irqrestore(&sp->lock, flags);
-- }
--
-- if (new_rx_mode == 0 && dev->mc_count < 4) {
-- /* The simple case of 0-3 multicast list entries occurs often, and
-- fits within one tx_ring[] entry. */
-- struct dev_mc_list *mclist;
-- u16 *setup_params, *eaddrs;
--
-- spin_lock_irqsave(&sp->lock, flags);
-- entry = sp->cur_tx++ % TX_RING_SIZE;
-- last_cmd = sp->last_cmd;
-- sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry];
--
-- sp->tx_skbuff[entry] = 0;
-- sp->tx_ring[entry].status = cpu_to_le32(CmdSuspend | CmdMulticastList);
-- sp->tx_ring[entry].link =
-- virt_to_le32desc(&sp->tx_ring[(entry + 1) % TX_RING_SIZE]);
-- sp->tx_ring[entry].tx_desc_addr = 0; /* Really MC list count. */
-- setup_params = (u16 *)&sp->tx_ring[entry].tx_desc_addr;
-- *setup_params++ = cpu_to_le16(dev->mc_count*6);
-- /* Fill in the multicast addresses. */
-- for (i = 0, mclist = dev->mc_list; i < dev->mc_count;
-- i++, mclist = mclist->next) {
-- eaddrs = (u16 *)mclist->dmi_addr;
-- *setup_params++ = *eaddrs++;
-- *setup_params++ = *eaddrs++;
-- *setup_params++ = *eaddrs++;
-- }
--
-- wait_for_cmd_done(ioaddr + SCBCmd);
-- clear_suspend(last_cmd);
-- /* Immediately trigger the command unit resume. */
-- outb(CUResume, ioaddr + SCBCmd);
--
-- if ((int)(sp->cur_tx - sp->dirty_tx) >= TX_QUEUE_LIMIT) {
-- netif_stop_queue(dev);
-- sp->tx_full = 1;
-- }
-- spin_unlock_irqrestore(&sp->lock, flags);
-- } else if (new_rx_mode == 0) {
-- struct dev_mc_list *mclist;
-- u16 *setup_params, *eaddrs;
-- struct speedo_mc_block *mc_blk;
-- struct descriptor *mc_setup_frm;
-- int i;
--
-- mc_blk = kmalloc(sizeof(*mc_blk) + 2 + multicast_filter_limit*6,
-- GFP_ATOMIC);
-- if (mc_blk == NULL) {
-- printk(KERN_ERR "%s: Failed to allocate a setup frame.\n",
-- dev->name);
-- sp->rx_mode = -1; /* We failed, try again. */
-- return;
-- }
-- mc_blk->next = NULL;
-- mc_setup_frm = &mc_blk->frame;
--
-- /* Fill the setup frame. */
-- if (speedo_debug > 1)
-- printk(KERN_DEBUG "%s: Constructing a setup frame at %p.\n",
-- dev->name, mc_setup_frm);
-- mc_setup_frm->cmd_status =
-- cpu_to_le32(CmdSuspend | CmdIntr | CmdMulticastList);
-- /* Link set below. */
-- setup_params = (u16 *)&mc_setup_frm->params;
-- *setup_params++ = cpu_to_le16(dev->mc_count*6);
-- /* Fill in the multicast addresses. */
-- for (i = 0, mclist = dev->mc_list; i < dev->mc_count;
-- i++, mclist = mclist->next) {
-- eaddrs = (u16 *)mclist->dmi_addr;
-- *setup_params++ = *eaddrs++;
-- *setup_params++ = *eaddrs++;
-- *setup_params++ = *eaddrs++;
-- }
--
-- /* Disable interrupts while playing with the Tx Cmd list. */
-- spin_lock_irqsave(&sp->lock, flags);
--
-- if (sp->mc_setup_tail)
-- sp->mc_setup_tail->next = mc_blk;
-- else
-- sp->mc_setup_head = mc_blk;
-- sp->mc_setup_tail = mc_blk;
-- mc_blk->tx = sp->cur_tx;
--
-- entry = sp->cur_tx++ % TX_RING_SIZE;
-- last_cmd = sp->last_cmd;
-- sp->last_cmd = mc_setup_frm;
--
-- /* Change the command to a NoOp, pointing to the CmdMulti command. */
-- sp->tx_skbuff[entry] = 0;
-- sp->tx_ring[entry].status = cpu_to_le32(CmdNOp);
-- sp->tx_ring[entry].link = virt_to_le32desc(mc_setup_frm);
--
-- /* Set the link in the setup frame. */
-- mc_setup_frm->link =
-- virt_to_le32desc(&(sp->tx_ring[(entry+1) % TX_RING_SIZE]));
--
-- wait_for_cmd_done(ioaddr + SCBCmd);
-- clear_suspend(last_cmd);
-- /* Immediately trigger the command unit resume. */
-- outb(CUResume, ioaddr + SCBCmd);
--
-- if ((int)(sp->cur_tx - sp->dirty_tx) >= TX_QUEUE_LIMIT) {
-- netif_stop_queue(dev);
-- sp->tx_full = 1;
-- }
-- spin_unlock_irqrestore(&sp->lock, flags);
--
-- if (speedo_debug > 5)
-- printk(" CmdMCSetup frame length %d in entry %d.\n",
-- dev->mc_count, entry);
-- }
--
-- sp->rx_mode = new_rx_mode;
--}
--
--#ifdef MODULE
--
--int init_module(void)
--{
-- int cards_found;
--
-- if (debug >= 0 && speedo_debug != debug)
-- printk(KERN_INFO "eepro100.c: Debug level is %d.\n", debug);
-- if (debug >= 0)
-- speedo_debug = debug;
-- /* Always emit the version message. */
-- if (speedo_debug)
-- printk(KERN_INFO "%s", version);
--
-- cards_found = eepro100_init();
-- if (cards_found <= 0) {
-- printk(KERN_INFO "eepro100: No cards found, driver not installed.\n");
-- return -ENODEV;
-- }
-- return 0;
--}
--
--void
--cleanup_module(void)
--{
-- struct net_device *next_dev;
--
-- /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
-- while (root_speedo_dev) {
-- struct speedo_private *sp = (void *)root_speedo_dev->priv;
-- unregister_netdev(root_speedo_dev);
-- release_region(root_speedo_dev->base_addr, SPEEDO3_TOTAL_SIZE);
--#ifndef USE_IO
-- iounmap((char *)root_speedo_dev->base_addr);
--#endif
-- next_dev = sp->next_module;
-- if (sp->priv_addr)
-- kfree(sp->priv_addr);
-- kfree(root_speedo_dev);
-- root_speedo_dev = next_dev;
-- }
--}
--
--#else /* not MODULE */
--
--int eepro100_probe(void)
--{
-- int cards_found = 0;
--
-- cards_found = eepro100_init();
--
-- if (speedo_debug > 0 && cards_found)
-- printk(version);
--
-- return cards_found ? 0 : -ENODEV;
--}
--#endif /* MODULE */
--
--/*
-- * Local variables:
-- * compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c eepro100.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
-- * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c eepro100.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
-- * c-indent-level: 4
-- * c-basic-offset: 4
-- * tab-width: 4
-- * End:
-- */
-Index: linux/dev/include/linux/modversions.h
-===================================================================
-RCS file: linux/dev/include/linux/modversions.h
-diff -N linux/dev/include/linux/modversions.h
---- /dev/null 1 Jan 1970 00:00:00 -0000
-+++ linux/dev/include/linux/modversions.h 20 Aug 2004 10:32:52 -0000
-@@ -0,0 +1 @@
-+/* Dummy file. */
-Index: linux/src/drivers/net/3c59x.c
-===================================================================
-RCS file: /cvsroot/hurd/gnumach/linux/src/drivers/net/Attic/3c59x.c,v
-retrieving revision 1.3
-diff -u -r1.3 3c59x.c
---- linux/src/drivers/net/3c59x.c 8 Oct 1999 13:50:16 -0000 1.3
-+++ linux/src/drivers/net/3c59x.c 20 Aug 2004 10:32:53 -0000
-@@ -1,157 +1,181 @@
- /* EtherLinkXL.c: A 3Com EtherLink PCI III/XL ethernet driver for linux. */
- /*
-- Written 1996-1999 by Donald Becker.
-+ Written 1996-2003 by Donald Becker.
-
-- This software may be used and distributed according to the terms
-- of the GNU Public License, incorporated herein by reference.
-+ This software may be used and distributed according to the terms of
-+ the GNU General Public License (GPL), incorporated herein by reference.
-+ Drivers based on or derived from this code fall under the GPL and must
-+ retain the authorship, copyright and license notice. This file is not
-+ a complete program and may only be used when the entire operating
-+ system is licensed under the GPL.
-
- This driver is for the 3Com "Vortex" and "Boomerang" series ethercards.
- Members of the series include Fast EtherLink 3c590/3c592/3c595/3c597
- and the EtherLink XL 3c900 and 3c905 cards.
-
-- The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
-- Center of Excellence in Space Data and Information Sciences
-- Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
-+ The original author may be reached as becker@scyld.com, or C/O
-+ Scyld Computing Corporation
-+ 410 Severn Ave., Suite 210
-+ Annapolis MD 21403
-+
-+ Support information and updates are available at
-+ http://www.scyld.com/network/vortex.html
- */
-
--static char *version =
--"3c59x.c:v0.99L 5/28/99 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n";
-+static const char versionA[] =
-+"3c59x.c:v0.99Za 4/17/2003 Donald Becker, becker@scyld.com\n";
-+static const char versionB[] =
-+" http://www.scyld.com/network/vortex.html\n";
-+
-+/* The user-configurable values.
-+ These may be modified when a driver module is loaded.*/
-+
-+/* Message enable level: 0..31 = no..all messages. See NETIF_MSG docs. */
-+static int debug = 2;
-+
-+/* This driver uses 'options' to pass the media type, full-duplex flag, etc.
-+ See media_tbl[] and the web page for the possible types.
-+ There is no limit on card count, MAX_UNITS limits only module options. */
-+#define MAX_UNITS 8
-+static int options[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1,};
-+static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-+
-+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-+static int max_interrupt_work = 20;
-
--/* "Knobs" that adjust features and parameters. */
- /* Set the copy breakpoint for the copy-only-tiny-frames scheme.
- Setting to > 1512 effectively disables this feature. */
- static const int rx_copybreak = 200;
--/* Allow setting MTU to a larger size, bypassing the normal ethernet setup. */
--static const int mtu = 1500;
--/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
--static int max_interrupt_work = 20;
-
--/* Put out somewhat more debugging messages. (0: no msg, 1 minimal .. 6). */
--#define vortex_debug debug
--#ifdef VORTEX_DEBUG
--static int vortex_debug = VORTEX_DEBUG;
--#else
--static int vortex_debug = 1;
--#endif
-+/* Allow setting MTU to a larger size, bypassing the normal Ethernet setup. */
-+static const int mtu = 1500;
-
--/* Some values here only for performance evaluation and path-coverage
-- debugging. */
--static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0, rx_csumhits;
-+/* Maximum number of multicast addresses to filter (vs. rx-all-multicast).
-+ Cyclones and later have a 64 or 256 element hash table based on the
-+ Ethernet CRC. */
-+static int multicast_filter_limit = 64;
-+
-+/* Operational parameters that are set at compile time. */
-+
-+/* Keep the ring sizes a power of two for compile efficiency.
-+ The compiler will convert <unsigned>'%'<2^N> into a bit mask.
-+ Making the Tx ring too large decreases the effectiveness of channel
-+ bonding and packet priority.
-+ Do not increase the Tx ring beyond 256.
-+ Large receive rings waste memory and confound network buffer limits.
-+ These values have been carefully studied: changing these might mask a
-+ problem, it won't fix it.
-+ */
-+#define TX_RING_SIZE 16
-+#define TX_QUEUE_LEN 10 /* Limit ring entries actually used. */
-+#define RX_RING_SIZE 32
-
--/* A few values that may be tweaked. */
-+/* Operational parameters that usually are not changed. */
- /* Time in jiffies before concluding the transmitter is hung. */
--#define TX_TIMEOUT (2*HZ)
-+#define TX_TIMEOUT (6*HZ)
-
--/* Keep the ring sizes a power of two for efficiency. */
--#define TX_RING_SIZE 16
--#define RX_RING_SIZE 32
--#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/
-+/* Allocation size of Rx buffers with normal sized Ethernet frames.
-+ Do not change this value without good reason. The 1536 value is not
-+ a limit, or directly related to MTU, but rather a way to keep a
-+ consistent allocation size among drivers.
-+ */
-+#define PKT_BUF_SZ 1536
-
--#ifndef __OPTIMIZE__
-+#ifndef __KERNEL__
-+#define __KERNEL__
-+#endif
-+#if !defined(__OPTIMIZE__)
- #warning You must compile this file with the correct options!
- #warning See the last lines of the source file.
- #error You must compile this driver with "-O".
- #endif
-
- #include <linux/config.h>
--#include <linux/version.h>
--#ifdef MODULE
--#ifdef MODVERSIONS
--#include <linux/modversions.h>
-+#if defined(CONFIG_SMP) && ! defined(__SMP__)
-+#define __SMP__
- #endif
-+#if defined(MODULE) && defined(CONFIG_MODVERSIONS) && ! defined(MODVERSIONS)
-+#define MODVERSIONS
-+#endif
-+
-+#include <linux/version.h>
-+#if LINUX_VERSION_CODE < 0x20300 && defined(MODVERSIONS)
- #include <linux/module.h>
-+#include <linux/modversions.h>
- #else
--#define MOD_INC_USE_COUNT
--#define MOD_DEC_USE_COUNT
-+#include <linux/modversions.h>
-+#include <linux/module.h>
- #endif
-
- #include <linux/kernel.h>
--#include <linux/sched.h>
- #include <linux/string.h>
- #include <linux/timer.h>
- #include <linux/errno.h>
--#include <linux/in.h>
- #include <linux/ioport.h>
-+#if LINUX_VERSION_CODE >= 0x20400
-+#include <linux/slab.h>
-+#else
- #include <linux/malloc.h>
-+#endif
- #include <linux/interrupt.h>
- #include <linux/pci.h>
- #include <linux/netdevice.h>
- #include <linux/etherdevice.h>
- #include <linux/skbuff.h>
--#if LINUX_VERSION_CODE < 0x20155
--#include <linux/bios32.h>
--#endif
--#include <asm/irq.h> /* For NR_IRQS only. */
-+#include <asm/irq.h>
-+#include <asm/byteorder.h>
- #include <asm/bitops.h>
- #include <asm/io.h>
-
--/* Kernel compatibility defines, some common to David Hinds' PCMCIA package.
-- This is only in the support-all-kernels source code. */
-+#ifdef INLINE_PCISCAN
-+#include "k_compat.h"
-+#else
-+#include "pci-scan.h"
-+#include "kern_compat.h"
-+#endif
-
--#define RUN_AT(x) (jiffies + (x))
-+/* Condensed operations for readability.
-+ Compatibility defines are now in kern_compat.h */
-
--#include <linux/delay.h>
-+#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr))
-+#define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr))
-
--#if (LINUX_VERSION_CODE >= 0x20100)
-+#if (LINUX_VERSION_CODE >= 0x20100) && defined(MODULE)
- char kernel_version[] = UTS_RELEASE;
--#else
--#ifndef __alpha__
--#define ioremap(a,b) \
-- (((a)<0x100000) ? (void *)((u_long)(a)) : vremap(a,b))
--#define iounmap(v) \
-- do { if ((u_long)(v) > 0x100000) vfree(v); } while (0)
--#endif
--#endif
--#if LINUX_VERSION_CODE <= 0x20139
--#define net_device_stats enet_statistics
--#define NETSTATS_VER2
--#endif
--#if LINUX_VERSION_CODE < 0x20138
--#define test_and_set_bit(val, addr) set_bit(val, addr)
--#define le32_to_cpu(val) (val)
--#define cpu_to_le32(val) (val)
--#endif
--#if LINUX_VERSION_CODE < 0x20155
--#define PCI_SUPPORT_VER1
--#else
--#define PCI_SUPPORT_VER2
--#endif
--#if LINUX_VERSION_CODE < 0x20159
--#define DEV_FREE_SKB(skb) dev_kfree_skb (skb, FREE_WRITE);
--#else /* Grrr, incompatible changes should change the name. */
--#define DEV_FREE_SKB(skb) dev_kfree_skb(skb);
--#endif
--#if ! defined(CAP_NET_ADMIN)
--#define capable(CAP_XXX) (suser())
- #endif
-
--#if defined(MODULE) && LINUX_VERSION_CODE > 0x20115
--MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
--MODULE_DESCRIPTION("3Com 3c590/3c900 series Vortex/Boomerang driver");
-+MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
-+MODULE_DESCRIPTION("3Com EtherLink XL (3c590/3c900 series) driver");
-+MODULE_LICENSE("GPL");
- MODULE_PARM(debug, "i");
--MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
--MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
-+MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
-+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
- MODULE_PARM(rx_copybreak, "i");
- MODULE_PARM(max_interrupt_work, "i");
--MODULE_PARM(compaq_ioaddr, "i");
--MODULE_PARM(compaq_irq, "i");
--MODULE_PARM(compaq_device_id, "i");
-+MODULE_PARM(multicast_filter_limit, "i");
-+#ifdef MODULE_PARM_DESC
-+MODULE_PARM_DESC(debug, "3c59x message level (0-31)");
-+MODULE_PARM_DESC(options, "3c59x force fixed media type");
-+MODULE_PARM_DESC(full_duplex,
-+ "3c59x set to 1 to force full duplex (deprecated)");
-+MODULE_PARM_DESC(rx_copybreak,
-+ "3c59x copy breakpoint for copy-only-tiny-frames");
-+MODULE_PARM_DESC(max_interrupt_work,
-+ "3c59x maximum events handled per interrupt");
-+MODULE_PARM_DESC(multicast_filter_limit,
-+ "Multicast address count before switching to Rx-all-multicast");
- #endif
-
- /* Operational parameter that usually are not changed. */
-
--/* The Vortex size is twice that of the original EtherLinkIII series: the
-- runtime register window, window 1, is now always mapped in.
-- The Boomerang size is twice as large as the Vortex -- it has additional
-- bus master control registers. */
--#define VORTEX_TOTAL_SIZE 0x20
--#define BOOMERANG_TOTAL_SIZE 0x40
--
- /* Set iff a MII transceiver on any interface requires mdio preamble.
- This only set with the original DP83840 on older 3c905 boards, so the extra
- code size of a per-interface flag is not worthwhile. */
- static char mii_preamble_required = 0;
-
-+/* Performance and path-coverage information. */
-+static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0, rx_csumhits;
-+
- /*
- Theory of Operation
-
-@@ -160,11 +184,10 @@
- This device driver is designed for the 3Com FastEtherLink and FastEtherLink
- XL, 3Com's PCI to 10/100baseT adapters. It also works with the 10Mbs
- versions of the FastEtherLink cards. The supported product IDs are
-- 3c590, 3c592, 3c595, 3c597, 3c900, 3c905
-+in the pci_tbl[] list.
-
- The related ISA 3c515 is supported with a separate driver, 3c515.c, included
--with the kernel source or available from
-- cesdis.gsfc.nasa.gov:/pub/linux/drivers/3c515.html
-+with the kernel source.
-
- II. Board-specific settings
-
-@@ -224,83 +247,152 @@
- the EISA version is called "Demon". According to Terry these names come
- from rides at the local amusement park.
-
--The new chips support both ethernet (1.5K) and FDDI (4.5K) packet sizes!
--This driver only supports ethernet packets because of the skbuff allocation
--limit of 4K.
-+The new chips support both ethernet (1.5K) and FDDI (4.5K) packet sizes.
-+This driver only supports ethernet packets on some kernels because of the
-+skbuff allocation limit of 4K.
- */
-
--/* This table drives the PCI probe routines. It's mostly boilerplate in all
-- of the drivers, and will likely be provided by some future kernel.
--*/
--enum pci_flags_bit {
-- PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
-- PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
--};
--struct pci_id_info {
-- const char *name;
-- u16 vendor_id, device_id, device_id_mask, flags;
-- int drv_flags, io_size;
-- struct device *(*probe1)(int pci_bus, int pci_devfn, struct device *dev,
-- long ioaddr, int irq, int chip_idx, int fnd_cnt);
--};
--
--enum { IS_VORTEX=1, IS_BOOMERANG=2, IS_CYCLONE=4,
-- HAS_PWR_CTRL=0x10, HAS_MII=0x20, HAS_NWAY=0x40, HAS_CB_FNS=0x80, };
--static struct device *vortex_probe1(int pci_bus, int pci_devfn,
-- struct device *dev, long ioaddr,
-- int irq, int dev_id, int card_idx);
-+/* The Vortex size is twice that of the original EtherLinkIII series: the
-+ runtime register window, window 1, is now always mapped in.
-+ The Boomerang size is twice as large as the Vortex -- it has additional
-+ bus master control registers. */
-+#define VORTEX_SIZE 0x20
-+#define BOOMERANG_SIZE 0x40
-+#define CYCLONE_SIZE 0x80
-+enum { IS_VORTEX=1, IS_BOOMERANG=2, IS_CYCLONE=0x804, IS_TORNADO=0x08,
-+ HAS_PWR_CTRL=0x10, HAS_MII=0x20, HAS_NWAY=0x40, HAS_CB_FNS=0x80,
-+ EEPROM_8BIT=0x200, INVERT_LED_PWR=0x400, MII_XCVR_PWR=0x4000,
-+ HAS_V2_TX=0x800, WN0_XCVR_PWR=0x1000,
-+};
-+/* Base feature sets for the generations. */
-+#define FEATURE_BOOMERANG (HAS_MII) /* 905 */
-+#define FEATURE_CYCLONE (IS_CYCLONE|HAS_V2_TX) /* 905B */
-+#define FEATURE_TORNADO (IS_TORNADO|HAS_NWAY|HAS_V2_TX) /* 905C */
-+
-+static void *vortex_probe1(struct pci_dev *pdev, void *init_dev,
-+ long ioaddr, int irq, int chip_idx, int find_cnt);
-+static int pwr_event(void *dev_instance, int event);
-+#ifdef USE_MEM_OPS
-+#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR1)
-+#else
-+#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_IO | PCI_ADDR0)
-+#endif
-+
- static struct pci_id_info pci_tbl[] = {
-- {"3c590 Vortex 10Mbps", 0x10B7, 0x5900, 0xffff,
-- PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, vortex_probe1},
-- {"3c595 Vortex 100baseTx", 0x10B7, 0x5950, 0xffff,
-- PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, vortex_probe1},
-- {"3c595 Vortex 100baseT4", 0x10B7, 0x5951, 0xffff,
-- PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, vortex_probe1},
-- {"3c595 Vortex 100base-MII", 0x10B7, 0x5952, 0xffff,
-- PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, vortex_probe1},
-- {"3Com Vortex", 0x10B7, 0x5900, 0xff00,
-- PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, vortex_probe1},
-- {"3c900 Boomerang 10baseT", 0x10B7, 0x9000, 0xffff,
-- PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, vortex_probe1},
-- {"3c900 Boomerang 10Mbps Combo", 0x10B7, 0x9001, 0xffff,
-- PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, vortex_probe1},
-- {"3c900 Cyclone 10Mbps Combo", 0x10B7, 0x9005, 0xffff,
-- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
-- {"3c900B-FL Cyclone 10base-FL", 0x10B7, 0x900A, 0xffff,
-- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
-- {"3c905 Boomerang 100baseTx", 0x10B7, 0x9050, 0xffff,
-- PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1},
-- {"3c905 Boomerang 100baseT4", 0x10B7, 0x9051, 0xffff,
-- PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1},
-- {"3c905B Cyclone 100baseTx", 0x10B7, 0x9055, 0xffff,
-- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, vortex_probe1},
-- {"3c905B Cyclone 10/100/BNC", 0x10B7, 0x9058, 0xffff,
-- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, vortex_probe1},
-- {"3c905B-FX Cyclone 100baseFx", 0x10B7, 0x905A, 0xffff,
-- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
-- {"3c905C Tornado", 0x10B7, 0x9200, 0xffff,
-- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
-- {"3c980 Cyclone", 0x10B7, 0x9800, 0xfff0,
-- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
-- {"3cSOHO100-TX Hurricane", 0x10B7, 0x7646, 0xffff,
-- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
-- {"3c555 Laptop Hurricane", 0x10B7, 0x5055, 0xffff,
-- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
-- {"3c575 Boomerang CardBus", 0x10B7, 0x5057, 0xffff,
-- PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1},
-- {"3CCFE575 Cyclone CardBus", 0x10B7, 0x5157, 0xffff,
-- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS,
-- 128, vortex_probe1},
-- {"3CCFE656 Cyclone CardBus", 0x10B7, 0x6560, 0xffff,
-- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS,
-- 128, vortex_probe1},
-- {"3c575 series CardBus (unknown version)", 0x10B7, 0x5057, 0xf0ff,
-- PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1},
-- {"3Com Boomerang (unknown version)", 0x10B7, 0x9000, 0xff00,
-- PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, vortex_probe1},
-+ {"3c590 Vortex 10Mbps", { 0x590010B7, 0xffffffff },
-+ PCI_IOTYPE, VORTEX_SIZE, IS_VORTEX, },
-+ {"3c595 Vortex 100baseTx", { 0x595010B7, 0xffffffff },
-+ PCI_IOTYPE, VORTEX_SIZE, IS_VORTEX, },
-+ {"3c595 Vortex 100baseT4", { 0x595110B7, 0xffffffff },
-+ PCI_IOTYPE, VORTEX_SIZE, IS_VORTEX, },
-+ {"3c595 Vortex 100base-MII",{ 0x595210B7, 0xffffffff },
-+ PCI_IOTYPE, VORTEX_SIZE, IS_VORTEX, },
-+ /* Change EISA_scan if these move from index 4 and 5. */
-+ {"3c592 EISA Vortex", { 0x592010B7, 0xffffffff },
-+ PCI_IOTYPE, VORTEX_SIZE, IS_VORTEX, },
-+ {"3c597 EISA Vortex", { 0x597010B7, 0xffffffff },
-+ PCI_IOTYPE, VORTEX_SIZE, IS_VORTEX, },
-+ {"Vortex (unknown)", { 0x590010B7, 0xff00ffff },
-+ PCI_IOTYPE, VORTEX_SIZE, IS_VORTEX, },
-+ {"3c900 Boomerang 10baseT", { 0x900010B7, 0xffffffff },
-+ PCI_IOTYPE, BOOMERANG_SIZE, IS_BOOMERANG, },
-+ {"3c900 Boomerang 10Mbps Combo", { 0x900110B7, 0xffffffff },
-+ PCI_IOTYPE,BOOMERANG_SIZE, IS_BOOMERANG, },
-+ {"3c900 Cyclone 10Mbps TPO", { 0x900410B7, 0xffffffff },
-+ PCI_IOTYPE, CYCLONE_SIZE, IS_CYCLONE, },
-+ {"3c900 Cyclone 10Mbps Combo", { 0x900510B7, 0xffffffff },
-+ PCI_IOTYPE, CYCLONE_SIZE, IS_CYCLONE, },
-+ {"3c900 Cyclone 10Mbps TPC", { 0x900610B7, 0xffffffff },
-+ PCI_IOTYPE, CYCLONE_SIZE, IS_CYCLONE, },
-+ {"3c900B-FL Cyclone 10base-FL",{ 0x900A10B7, 0xffffffff },
-+ PCI_IOTYPE, CYCLONE_SIZE, IS_CYCLONE, },
-+ {"3c905 Boomerang 100baseTx",{ 0x905010B7, 0xffffffff },
-+ PCI_IOTYPE,BOOMERANG_SIZE, IS_BOOMERANG|HAS_MII, },
-+ {"3c905 Boomerang 100baseT4",{ 0x905110B7, 0xffffffff },
-+ PCI_IOTYPE,BOOMERANG_SIZE, IS_BOOMERANG|HAS_MII, },
-+ {"3c905B Cyclone 100baseTx",{ 0x905510B7, 0xffffffff },
-+ PCI_IOTYPE, CYCLONE_SIZE, IS_CYCLONE|HAS_NWAY, },
-+ {"3c905B Cyclone 10/100/BNC",{ 0x905810B7, 0xffffffff },
-+ PCI_IOTYPE, CYCLONE_SIZE, IS_CYCLONE|HAS_NWAY, },
-+ {"3c905B-FX Cyclone 100baseFx",{ 0x905A10B7, 0xffffffff },
-+ PCI_IOTYPE, CYCLONE_SIZE, IS_CYCLONE, },
-+ {"3c905C Tornado",{ 0x920010B7, 0xffffffff },
-+ PCI_IOTYPE, CYCLONE_SIZE, FEATURE_TORNADO, },
-+ {"3c920 Tornado",{ 0x920110B7, 0xffffffff },
-+ PCI_IOTYPE, CYCLONE_SIZE, FEATURE_TORNADO, },
-+ {"3c920 series Tornado",{ 0x920010B7, 0xfff0ffff },
-+ PCI_IOTYPE, CYCLONE_SIZE, FEATURE_TORNADO, },
-+ {"3c982 Server Tornado",{ 0x980510B7, 0xffffffff },
-+ PCI_IOTYPE, CYCLONE_SIZE, FEATURE_TORNADO, },
-+ {"3c980 Cyclone",{ 0x980010B7, 0xfff0ffff },
-+ PCI_IOTYPE, CYCLONE_SIZE, FEATURE_CYCLONE|HAS_NWAY, },
-+ {"3cSOHO100-TX Hurricane", { 0x764610B7, 0xffffffff },
-+ PCI_IOTYPE, CYCLONE_SIZE, FEATURE_CYCLONE, },
-+ {"3c555 Laptop Hurricane", { 0x505510B7, 0xffffffff },
-+ PCI_IOTYPE, CYCLONE_SIZE, FEATURE_CYCLONE, },
-+ {"3c556 Laptop Tornado",{ 0x605510B7, 0xffffffff },
-+ PCI_IOTYPE, CYCLONE_SIZE, FEATURE_TORNADO|EEPROM_8BIT, },
-+ {"3c556 series Laptop Tornado",{ 0x605510B7, 0xf0ffffff },
-+ PCI_IOTYPE, CYCLONE_SIZE, FEATURE_TORNADO|EEPROM_8BIT, },
-+ {"3c1556B-5 mini-PCI",{ 0x605610B7, 0xffffffff, 0x655610b7, 0xffffffff, },
-+ PCI_IOTYPE, CYCLONE_SIZE,
-+ FEATURE_TORNADO|EEPROM_8BIT|INVERT_LED_PWR|WN0_XCVR_PWR, },
-+ {"3c1556B mini-PCI",{ 0x605610B7, 0xffffffff },
-+ PCI_IOTYPE, CYCLONE_SIZE,
-+ FEATURE_TORNADO|EEPROM_8BIT|HAS_CB_FNS|INVERT_LED_PWR|MII_XCVR_PWR, },
-+ {"3c1556B series mini-PCI",{ 0x605610B7, 0xf0ffffff },
-+ PCI_IOTYPE, CYCLONE_SIZE,
-+ FEATURE_TORNADO|EEPROM_8BIT|HAS_CB_FNS|INVERT_LED_PWR|MII_XCVR_PWR, },
-+ {"3c575 Boomerang CardBus", { 0x505710B7, 0xffffffff },
-+ PCI_IOTYPE,BOOMERANG_SIZE, IS_BOOMERANG|HAS_MII|EEPROM_8BIT, },
-+ {"3CCFE575BT Cyclone CardBus",{ 0x515710B7, 0xffffffff },
-+ PCI_IOTYPE, CYCLONE_SIZE,
-+ FEATURE_CYCLONE | HAS_CB_FNS | EEPROM_8BIT | INVERT_LED_PWR, },
-+ {"3CCFE575CT Tornado CardBus",{ 0x525710B7, 0xffffffff },
-+ PCI_IOTYPE, CYCLONE_SIZE,
-+ FEATURE_TORNADO|HAS_CB_FNS|EEPROM_8BIT|MII_XCVR_PWR, },
-+ {"3CCFE656 Cyclone CardBus",{ 0x656010B7, 0xffffffff },
-+ PCI_IOTYPE, CYCLONE_SIZE,
-+ IS_CYCLONE|HAS_NWAY|HAS_CB_FNS| INVERT_LED_PWR | MII_XCVR_PWR, },
-+ {"3CCFE656B Cyclone+Winmodem CardBus",{ 0x656210B7, 0xffffffff },
-+ PCI_IOTYPE, CYCLONE_SIZE,
-+ FEATURE_CYCLONE/*|HAS_NWAY*/ |HAS_CB_FNS|EEPROM_8BIT|INVERT_LED_PWR|MII_XCVR_PWR, },
-+ {"3CCFE656C Tornado+Winmodem CardBus",{ 0x656410B7, 0xffffffff },
-+ PCI_IOTYPE, CYCLONE_SIZE,
-+ (FEATURE_TORNADO & ~HAS_NWAY)|HAS_CB_FNS|EEPROM_8BIT | MII_XCVR_PWR, },
-+ {"3c450 HomePNA Tornado",{ 0x450010B7, 0xffffffff },
-+ PCI_IOTYPE, CYCLONE_SIZE, FEATURE_TORNADO, },
-+ {"3c575 series CardBus (unknown version)", {0x505710B7, 0xf0ffffff },
-+ PCI_IOTYPE, BOOMERANG_SIZE, IS_BOOMERANG|HAS_MII, },
-+ {"3Com Boomerang (unknown version)",{ 0x900010B7, 0xff00ffff },
-+ PCI_IOTYPE, BOOMERANG_SIZE, IS_BOOMERANG, },
- {0,}, /* 0 terminated list. */
- };
-
-+struct drv_id_info vortex_drv_id = {
-+ "vortex", PCI_HOTSWAP, PCI_CLASS_NETWORK_ETHERNET<<8, pci_tbl,
-+ vortex_probe1, pwr_event };
-+
-+/* This driver was written to use I/O operations.
-+ However there are performance benefits to using memory operations, so
-+ that mode is now an options.
-+ Compiling for memory ops turns off EISA support.
-+*/
-+#ifdef USE_MEM_OPS
-+#undef inb
-+#undef inw
-+#undef inl
-+#undef outb
-+#undef outw
-+#undef outl
-+#define inb readb
-+#define inw readw
-+#define inl readl
-+#define outb writeb
-+#define outw writew
-+#define outl writel
-+#endif
-+
- /* Operational definitions.
- These are not used by other compilation units and thus are not
- exported in a ".h" file.
-@@ -332,7 +424,9 @@
-
- /* The SetRxFilter command accepts the following classes: */
- enum RxFilter {
-- RxStation = 1, RxMulticast = 2, RxBroadcast = 4, RxProm = 8 };
-+ RxStation = 1, RxMulticast = 2, RxBroadcast = 4, RxProm = 8,
-+ RxMulticastHash = 0x10,
-+};
-
- /* Bits in the general status register. */
- enum vortex_status {
-@@ -356,11 +450,7 @@
- Wn0EepromData = 12, /* Window 0: EEPROM results register. */
- IntrStatus=0x0E, /* Valid in all windows. */
- };
--enum Win0_EEPROM_bits {
-- EEPROM_Read = 0x80, EEPROM_WRITE = 0x40, EEPROM_ERASE = 0xC0,
-- EEPROM_EWENB = 0x30, /* Enable erasing/writing for 10 msec. */
-- EEPROM_EWDIS = 0x00, /* Disable EWENB before 10 msec timeout. */
--};
-+
- /* EEPROM locations. */
- enum eeprom_offset {
- PhysAddr01=0, PhysAddr23=1, PhysAddr45=2, ModelID=3,
-@@ -372,34 +462,35 @@
- Wn2_ResetOptions=12,
- };
- enum Window3 { /* Window 3: MAC/config bits. */
-- Wn3_Config=0, Wn3_MAC_Ctrl=6, Wn3_Options=8,
--};
--union wn3_config {
-- int i;
-- struct w3_config_fields {
-- unsigned int ram_size:3, ram_width:1, ram_speed:2, rom_size:2;
-- int pad8:8;
-- unsigned int ram_split:2, pad18:2, xcvr:4, autoselect:1;
-- int pad24:7;
-- } u;
-+ Wn3_Config=0, Wn3_MaxPktSize=4, Wn3_MAC_Ctrl=6, Wn3_Options=8,
- };
-
- enum Window4 { /* Window 4: Xcvr/media bits. */
- Wn4_FIFODiag = 4, Wn4_NetDiag = 6, Wn4_PhysicalMgmt=8, Wn4_Media = 10,
- };
-+enum Window5 {
-+ Wn5_TxThreshold = 0, Wn5_RxFilter = 8,
-+};
- enum Win4_Media_bits {
- Media_SQE = 0x0008, /* Enable SQE error counting for AUI. */
- Media_10TP = 0x00C0, /* Enable link beat and jabber for 10baseT. */
- Media_Lnk = 0x0080, /* Enable just link beat for 100TX/100FX. */
- Media_LnkBeat = 0x0800,
- };
--enum Window7 { /* Window 7: Bus Master control. */
-+enum Window7 {
-+ /* Bus Master control on Vortex. */
- Wn7_MasterAddr = 0, Wn7_MasterLen = 6, Wn7_MasterStatus = 12,
-+ /* On Cyclone and later, VLAN and PowerMgt control. */
-+ Wn7_VLAN_Mask = 0, Wn7_VLAN_EtherType = 4, Wn7_PwrMgmtEvent = 12,
- };
--/* Boomerang bus master control registers. */
-+
-+/* Boomerang and Cyclone bus master control registers. */
- enum MasterCtrl {
- PktStatus = 0x20, DownListPtr = 0x24, FragAddr = 0x28, FragLen = 0x2c,
-- TxFreeThreshold = 0x2f, UpPktStatus = 0x30, UpListPtr = 0x38,
-+ DownPollRate = 0x2d, TxFreeThreshold = 0x2f,
-+ UpPktStatus = 0x30, UpListPtr = 0x38,
-+ /* Cyclone+. */
-+ TxPktID=0x18, RxPriorityThresh = 0x3c,
- };
-
- /* The Rx and Tx descriptor lists.
-@@ -429,14 +520,16 @@
-
- /* Values for the Tx status entry. */
- enum tx_desc_status {
-- CRCDisable=0x2000, TxDComplete=0x8000,
-+ CRCDisable=0x2000, TxIntrDnComplete=0x8000, TxDownComplete=0x10000,
- AddIPChksum=0x02000000, AddTCPChksum=0x04000000, AddUDPChksum=0x08000000,
-+ TxNoRoundup=0x10000000, /* HAS_V2_TX should not word-pad packet. */
- TxIntrUploaded=0x80000000, /* IRQ when in FIFO, but maybe not sent. */
- };
-
- /* Chip features we care about in vp->capabilities, read from the EEPROM. */
--enum ChipCaps { CapBusMaster=0x20, CapPwrMgmt=0x2000 };
-+enum ChipCaps { CapBusMaster=0x20, CapNoTxLength=0x0200, CapPwrMgmt=0x2000 };
-
-+#define PRIV_ALIGN 15 /* Required alignment mask */
- struct vortex_private {
- /* The Rx and Tx rings should be quad-word-aligned. */
- struct boom_rx_desc rx_ring[RX_RING_SIZE];
-@@ -444,32 +537,46 @@
- /* The addresses of transmit- and receive-in-place skbuffs. */
- struct sk_buff* rx_skbuff[RX_RING_SIZE];
- struct sk_buff* tx_skbuff[TX_RING_SIZE];
-- struct device *next_module;
-+ struct net_device *next_module;
- void *priv_addr;
-- unsigned int cur_rx, cur_tx; /* The next free ring entry */
-- unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */
-- struct net_device_stats stats;
-+ /* Keep the Rx and Tx variables grouped on their own cache lines. */
-+ struct boom_rx_desc *rx_head_desc;
-+ unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */
-+ unsigned int rx_buf_sz; /* Based on MTU+slack. */
-+ int rx_copybreak;
-+
-+ struct boom_tx_desc *tx_desc_tail;
- struct sk_buff *tx_skb; /* Packet being eaten by bus master ctrl. */
-+ unsigned int cur_tx, dirty_tx;
-+ unsigned int tx_full:1, restart_tx:1;
-
-- /* PCI configuration space information. */
-- u8 pci_bus, pci_devfn; /* PCI bus location, for power management. */
-+ long last_reset;
-+ spinlock_t window_lock;
-+ struct net_device_stats stats;
- char *cb_fn_base; /* CardBus function status addr space. */
-- int chip_id;
-+ int msg_level;
-+ int chip_id, drv_flags;
-+ struct pci_dev *pci_dev; /* PCI configuration space information. */
-
- /* The remainder are related to chip state, mostly media selection. */
-- unsigned long in_interrupt;
-+ int multicast_filter_limit;
-+ u32 mc_filter[8];
-+ int max_interrupt_work;
-+ int rx_mode;
- struct timer_list timer; /* Media selection timer. */
- int options; /* User-settable misc. driver options. */
- unsigned int media_override:4, /* Passed-in media type. */
- default_media:4, /* Read from the EEPROM/Wn3_Config. */
-- full_duplex:1, force_fd:1, autoselect:1,
-+ full_duplex:1, medialock:1, autoselect:1,
- bus_master:1, /* Vortex can only do a fragment bus-m. */
- full_bus_master_tx:1, full_bus_master_rx:2, /* Boomerang */
- hw_csums:1, /* Has hardware checksums. */
-- tx_full:1;
-+ restore_intr_mask:1,
-+ polling:1;
- u16 status_enable;
- u16 intr_enable;
- u16 available_media; /* From Wn3_Options. */
-+ u16 wn3_mac_ctrl; /* Current settings. */
- u16 capabilities, info1, info2; /* Various, from EEPROM. */
- u16 advertising; /* NWay media advertisement */
- unsigned char phys[2]; /* MII device addresses. */
-@@ -503,62 +610,60 @@
- { "Default", 0, 0xFF, XCVR_10baseT, 10000},
- };
-
--#ifndef CARDBUS
--static int vortex_scan(struct device *dev, struct pci_id_info pci_tbl[]);
-+#if ! defined(CARDBUS) && ! defined(USE_MEM_OPS)
-+static int eisa_scan(struct net_device *dev);
- #endif
--static int vortex_open(struct device *dev);
-+static int vortex_open(struct net_device *dev);
-+static void set_media_type(struct net_device *dev);
-+static void activate_xcvr(struct net_device *dev);
-+static void start_operation(struct net_device *dev);
-+static void start_operation1(struct net_device *dev);
- static void mdio_sync(long ioaddr, int bits);
- static int mdio_read(long ioaddr, int phy_id, int location);
- static void mdio_write(long ioaddr, int phy_id, int location, int value);
- static void vortex_timer(unsigned long arg);
--static int vortex_start_xmit(struct sk_buff *skb, struct device *dev);
--static int boomerang_start_xmit(struct sk_buff *skb, struct device *dev);
--static int vortex_rx(struct device *dev);
--static int boomerang_rx(struct device *dev);
-+static void vortex_tx_timeout(struct net_device *dev);
-+static int vortex_start_xmit(struct sk_buff *skb, struct net_device *dev);
-+static int boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev);
-+static int vortex_rx(struct net_device *dev);
-+static int boomerang_rx(struct net_device *dev);
- static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs);
--static int vortex_close(struct device *dev);
--static void update_stats(long ioaddr, struct device *dev);
--static struct net_device_stats *vortex_get_stats(struct device *dev);
--static void set_rx_mode(struct device *dev);
--static int vortex_ioctl(struct device *dev, struct ifreq *rq, int cmd);
--static void acpi_wake(int pci_bus, int pci_devfn);
--static void acpi_set_WOL(struct device *dev);
-+static int vortex_close(struct net_device *dev);
-+static void update_stats(long ioaddr, struct net_device *dev);
-+static struct net_device_stats *vortex_get_stats(struct net_device *dev);
-+static void set_rx_mode(struct net_device *dev);
-+static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-+#if defined(NO_PCI)
-+#define acpi_set_WOL(dev) do {} while(0);
-+#define acpi_wake(pci_dev) do {} while(0);
-+#define acpi_set_pwr_state(pci_dev, state) do {} while(0);
-+#else
-+static void acpi_set_WOL(struct net_device *dev);
-+#endif
-
-
--/* This driver uses 'options' to pass the media type, full-duplex flag, etc. */
--/* Option count limit only -- unlimited interfaces are supported. */
--#define MAX_UNITS 8
--static int options[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1,};
--static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
- /* A list of all installed Vortex devices, for removing the driver module. */
--static struct device *root_vortex_dev = NULL;
-+static struct net_device *root_vortex_dev = NULL;
-
--#ifdef MODULE
--#ifndef CARDBUS
--/* Variables to work-around the Compaq PCI BIOS32 problem. */
--static int compaq_ioaddr = 0, compaq_irq = 0, compaq_device_id = 0x5900;
--#endif
-
--#ifdef CARDBUS
-+#if defined(MODULE) && defined(CARDBUS)
-
- #include <pcmcia/driver_ops.h>
-
- static dev_node_t *vortex_attach(dev_locator_t *loc)
- {
-- u16 dev_id, vendor_id;
-- u32 io;
-+ u32 io, pci_id;
- u8 bus, devfn, irq;
-- struct device *dev;
-+ struct net_device *dev;
- int chip_idx;
-
- if (loc->bus != LOC_PCI) return NULL;
- bus = loc->b.pci.bus; devfn = loc->b.pci.devfn;
- pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &io);
- pcibios_read_config_byte(bus, devfn, PCI_INTERRUPT_LINE, &irq);
-- pcibios_read_config_word(bus, devfn, PCI_VENDOR_ID, &vendor_id);
-- pcibios_read_config_word(bus, devfn, PCI_DEVICE_ID, &dev_id);
-- printk(KERN_INFO "vortex_attach(bus %d, function %d, device %4.4x)\n",
-- bus, devfn, dev_id);
-+ pcibios_read_config_dword(bus, devfn, PCI_VENDOR_ID, &pci_id);
-+ printk(KERN_INFO "vortex_attach(bus %d, function %d, device %8.8x)\n",
-+ bus, devfn, pci_id);
- io &= ~3;
- if (io == 0 || irq == 0) {
- printk(KERN_ERR "The 3Com CardBus Ethernet interface was not "
-@@ -566,17 +671,16 @@
- io == 0 ? "I/O address" : "IRQ");
- return NULL;
- }
-- for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++)
-- if (vendor_id == pci_tbl[chip_idx].vendor_id
-- && (dev_id & pci_tbl[chip_idx].device_id_mask) ==
-- pci_tbl[chip_idx].device_id)
-+ for (chip_idx = 0; pci_tbl[chip_idx].id.pci; chip_idx++)
-+ if ((pci_id & pci_tbl[chip_idx].id.pci_mask) ==
-+ pci_tbl[chip_idx].id.pci)
- break;
-- if (pci_tbl[chip_idx].vendor_id == 0) { /* Compiled out! */
-- printk(KERN_INFO "Unable to match chip type %4.4x %4.4x in "
-- "vortex_attach().\n", vendor_id, dev_id);
-+ if (pci_tbl[chip_idx].id.pci == 0) { /* Compiled out! */
-+ printk(KERN_INFO "Unable to match chip type %8.8x in "
-+ "vortex_attach().\n", pci_id);
- return NULL;
- }
-- dev = vortex_probe1(bus, devfn, NULL, io, irq, chip_idx, MAX_UNITS+1);
-+ dev = vortex_probe1(pci_find_slot(bus, devfn), NULL, io, irq, chip_idx, MAX_UNITS+1);
- if (dev) {
- dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL);
- strcpy(node->dev_name, dev->name);
-@@ -590,17 +694,17 @@
-
- static void vortex_detach(dev_node_t *node)
- {
-- struct device **devp, **next;
-- printk(KERN_INFO "vortex_detach(%s)\n", node->dev_name);
-+ struct net_device **devp, **next;
-+ printk(KERN_DEBUG "vortex_detach(%s)\n", node->dev_name);
- for (devp = &root_vortex_dev; *devp; devp = next) {
- next = &((struct vortex_private *)(*devp)->priv)->next_module;
- if (strcmp((*devp)->name, node->dev_name) == 0) break;
- }
- if (*devp) {
-- struct device *dev = *devp;
-+ struct net_device *dev = *devp;
- struct vortex_private *vp = dev->priv;
- if (dev->flags & IFF_UP)
-- vortex_close(dev);
-+ dev_close(dev);
- dev->flags &= ~(IFF_UP|IFF_RUNNING);
- unregister_netdev(dev);
- if (vp->cb_fn_base) iounmap(vp->cb_fn_base);
-@@ -616,143 +720,68 @@
- "3c575_cb", vortex_attach, NULL, NULL, vortex_detach
- };
-
--#endif /* Cardbus support */
-+#endif /* Old-style Cardbus module support */
-+
-+#if defined(MODULE) || (LINUX_VERSION_CODE >= 0x020400)
-
-+#if ! defined(MODULE) /* Must be a 2.4 kernel */
-+module_init(init_module);
-+module_exit(cleanup_module);
-+#endif
-
- int init_module(void)
- {
-- if (vortex_debug)
-- printk(KERN_INFO "%s", version);
-+ printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB);
- #ifdef CARDBUS
- register_driver(&vortex_ops);
- return 0;
- #else
-- return vortex_scan(0, pci_tbl);
-+#ifndef USE_MEM_OPS
-+ /* This is not quite correct, but both EISA and PCI cards is unlikely. */
-+ if (eisa_scan(0) >= 0)
-+ return 0;
-+#if defined(NO_PCI)
-+ return 0;
-+#endif
-+#endif
-+
-+ return pci_drv_register(&vortex_drv_id, NULL);
- #endif
- }
-
- #else
--int tc59x_probe(struct device *dev)
-+int tc59x_probe(struct net_device *dev)
- {
-- static int did_version = -1;
-- if (++did_version <= 0)
-- printk(KERN_INFO "%s", version);
-- return vortex_scan(dev, pci_tbl);
-+ int retval = -ENODEV;
-+
-+ /* Allow an EISA-only driver. */
-+#if ! defined(NO_PCI)
-+ if (pci_drv_register(&vortex_drv_id, dev) >= 0) {
-+ retval = 0;
-+ dev = 0;
-+ }
-+#endif
-+#ifndef USE_MEM_OPS
-+ if (eisa_scan(dev) >= 0)
-+ retval = 0;
-+#endif
-+ if (retval >= 0)
-+ printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB);
-+ return retval;
- }
- #endif /* not MODULE */
-
--#ifndef CARDBUS
--static int vortex_scan(struct device *dev, struct pci_id_info pci_tbl[])
-+#if ! defined(CARDBUS) && ! defined(USE_MEM_OPS)
-+static int eisa_scan(struct net_device *dev)
- {
- int cards_found = 0;
-
-- /* Allow an EISA-only driver. */
--#if defined(CONFIG_PCI) || (defined(MODULE) && !defined(NO_PCI))
-- /* Ideally we would detect all cards in slot order. That would
-- be best done a central PCI probe dispatch, which wouldn't work
-- well with the current structure. So instead we detect 3Com cards
-- in slot order. */
-- if (pcibios_present()) {
-- static int pci_index = 0;
-- unsigned char pci_bus, pci_device_fn;
--
-- for (;pci_index < 0xff; pci_index++) {
-- u16 vendor, device, pci_command, new_command;
-- int chip_idx, irq;
-- long ioaddr;
--
-- if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pci_index,
-- &pci_bus, &pci_device_fn)
-- != PCIBIOS_SUCCESSFUL)
-- break;
-- pcibios_read_config_word(pci_bus, pci_device_fn,
-- PCI_VENDOR_ID, &vendor);
-- pcibios_read_config_word(pci_bus, pci_device_fn,
-- PCI_DEVICE_ID, &device);
-- for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++)
-- if (vendor == pci_tbl[chip_idx].vendor_id
-- && (device & pci_tbl[chip_idx].device_id_mask) ==
-- pci_tbl[chip_idx].device_id)
-- break;
-- if (pci_tbl[chip_idx].vendor_id == 0) /* Compiled out! */
-- continue;
--
-- /* The Cyclone requires config space re-write if powered down. */
-- acpi_wake(pci_bus, pci_device_fn);
--
-- {
--#if LINUX_VERSION_CODE >= 0x20155
-- struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
-- ioaddr = pdev->base_address[0] & ~3;
-- irq = pdev->irq;
--#else
-- u32 pci_ioaddr;
-- u8 pci_irq_line;
-- pcibios_read_config_byte(pci_bus, pci_device_fn,
-- PCI_INTERRUPT_LINE, &pci_irq_line);
-- pcibios_read_config_dword(pci_bus, pci_device_fn,
-- PCI_BASE_ADDRESS_0, &pci_ioaddr);
-- ioaddr = pci_ioaddr & ~3;;
-- irq = pci_irq_line;
--#endif
-- }
--
-- if (ioaddr == 0) {
-- printk(KERN_WARNING " A 3Com network adapter has been found, "
-- "however it has not been assigned an I/O address.\n"
-- " You may need to power-cycle the machine for this "
-- "device to work!\n");
-- continue;
-- }
--
-- if (check_region(ioaddr, pci_tbl[chip_idx].io_size))
-- continue;
--
-- /* Activate the card. */
-- pcibios_read_config_word(pci_bus, pci_device_fn,
-- PCI_COMMAND, &pci_command);
-- new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
-- if (pci_command != new_command) {
-- printk(KERN_INFO " The PCI BIOS has not enabled the device "
-- "at %d/%d. Updating PCI command %4.4x->%4.4x.\n",
-- pci_bus, pci_device_fn, pci_command, new_command);
-- pcibios_write_config_word(pci_bus, pci_device_fn,
-- PCI_COMMAND, new_command);
-- }
--
-- dev = vortex_probe1(pci_bus, pci_device_fn, dev, ioaddr, irq,
-- chip_idx, cards_found);
--
-- if (dev) {
-- /* Get and check the latency values. On the 3c590 series
-- the latency timer must be set to the maximum value to avoid
-- data corruption that occurs when the timer expires during
-- a transfer -- a bug in the Vortex chip only. */
-- u8 pci_latency;
-- u8 new_latency = (device & 0xff00) == 0x5900 ? 248 : 32;
--
-- pcibios_read_config_byte(pci_bus, pci_device_fn,
-- PCI_LATENCY_TIMER, &pci_latency);
-- if (pci_latency < new_latency) {
-- printk(KERN_INFO "%s: Overriding PCI latency"
-- " timer (CFLT) setting of %d, new value is %d.\n",
-- dev->name, pci_latency, new_latency);
-- pcibios_write_config_byte(pci_bus, pci_device_fn,
-- PCI_LATENCY_TIMER, new_latency);
-- }
-- dev = 0;
-- cards_found++;
-- }
-- }
-- }
--#endif /* NO_PCI */
--
-- /* Now check all slots of the EISA bus. */
-+ /* Check the slots of the EISA bus. */
- if (EISA_bus) {
- static long ioaddr = 0x1000;
- for ( ; ioaddr < 0x9000; ioaddr += 0x1000) {
- int device_id;
-- if (check_region(ioaddr, VORTEX_TOTAL_SIZE))
-+ if (check_region(ioaddr, VORTEX_SIZE))
- continue;
- /* Check the standard EISA ID register for an encoded '3Com'. */
- if (inw(ioaddr + 0xC80) != 0x6d50)
-@@ -761,65 +790,100 @@
- device_id = (inb(ioaddr + 0xC82)<<8) + inb(ioaddr + 0xC83);
- if ((device_id & 0xFF00) != 0x5900)
- continue;
-- vortex_probe1(0, 0, dev, ioaddr, inw(ioaddr + 0xC88) >> 12,
-- 4, cards_found);
-+ vortex_probe1(0, dev, ioaddr, inw(ioaddr + 0xC88) >> 12,
-+ (device_id & 0xfff0) == 0x5970 ? 5 : 4, cards_found);
- dev = 0;
- cards_found++;
- }
- }
-
--#ifdef MODULE
-- /* Special code to work-around the Compaq PCI BIOS32 problem. */
-- if (compaq_ioaddr) {
-- vortex_probe1(0, 0, dev, compaq_ioaddr, compaq_irq,
-- compaq_device_id, cards_found++);
-- dev = 0;
-- }
--#endif
--
- return cards_found ? 0 : -ENODEV;
- }
- #endif /* ! Cardbus */
-
--static struct device *vortex_probe1(int pci_bus, int pci_devfn,
-- struct device *dev, long ioaddr,
-- int irq, int chip_idx, int card_idx)
-+static int do_eeprom_op(long ioaddr, int ee_cmd)
- {
-+ int timer;
-+
-+ outw(ee_cmd, ioaddr + Wn0EepromCmd);
-+ /* Wait for the read to take place, worst-case 162 us. */
-+ for (timer = 1620; timer >= 0; timer--) {
-+ if ((inw(ioaddr + Wn0EepromCmd) & 0x8000) == 0)
-+ break;
-+ }
-+ return inw(ioaddr + Wn0EepromData);
-+}
-+
-+static void *vortex_probe1(struct pci_dev *pdev, void *init_dev,
-+ long ioaddr, int irq, int chip_idx, int find_cnt)
-+{
-+ struct net_device *dev;
- struct vortex_private *vp;
-+ void *priv_mem;
- int option;
- unsigned int eeprom[0x40], checksum = 0; /* EEPROM contents */
-+ int ee_read_cmd;
-+ int drv_flags = pci_tbl[chip_idx].drv_flags;
- int i;
-
-- dev = init_etherdev(dev, 0);
-+ dev = init_etherdev(init_dev, 0);
-+ if (!dev)
-+ return NULL;
-+
-+#if ! defined(NO_PCI)
-+ /* Check the PCI latency value. On the 3c590 series the latency timer
-+ must be set to the maximum value to avoid data corruption that occurs
-+ when the timer expires during a transfer. This bug exists the Vortex
-+ chip only. */
-+ if (pdev) {
-+ u8 pci_latency;
-+ u8 new_latency = (drv_flags & IS_VORTEX) ? 248 : 32;
-+
-+ pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency);
-+ if (pci_latency < new_latency) {
-+ printk(KERN_INFO "%s: Overriding PCI latency"
-+ " timer (CFLT) setting of %d, new value is %d.\n",
-+ dev->name, pci_latency, new_latency);
-+ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, new_latency);
-+ }
-+ }
-+#endif
-
- printk(KERN_INFO "%s: 3Com %s at 0x%lx, ",
- dev->name, pci_tbl[chip_idx].name, ioaddr);
-
-+ /* Make certain elements e.g. descriptor lists are aligned. */
-+ priv_mem = kmalloc(sizeof(*vp) + PRIV_ALIGN, GFP_KERNEL);
-+ /* Check for the very unlikely case of no memory. */
-+ if (priv_mem == NULL) {
-+ printk(" INTERFACE MEMORY ALLOCATION FAILURE.\n");
-+ return NULL;
-+ }
-+
- dev->base_addr = ioaddr;
- dev->irq = irq;
- dev->mtu = mtu;
-
-- /* Make certain the descriptor lists are aligned. */
-- {
-- void *mem = kmalloc(sizeof(*vp) + 15, GFP_KERNEL);
-- vp = (void *)(((long)mem + 15) & ~15);
-- vp->priv_addr = mem;
-- }
-+ dev->priv = vp = (void *)(((long)priv_mem + PRIV_ALIGN) & ~PRIV_ALIGN);
- memset(vp, 0, sizeof(*vp));
-- dev->priv = vp;
-+ vp->priv_addr = priv_mem;
-
- vp->next_module = root_vortex_dev;
- root_vortex_dev = dev;
-
- vp->chip_id = chip_idx;
-- vp->pci_bus = pci_bus;
-- vp->pci_devfn = pci_devfn;
-+ vp->pci_dev = pdev;
-+ vp->drv_flags = drv_flags;
-+ vp->msg_level = (1 << debug) - 1;
-+ vp->rx_copybreak = rx_copybreak;
-+ vp->max_interrupt_work = max_interrupt_work;
-+ vp->multicast_filter_limit = multicast_filter_limit;
-
- /* The lower four bits are the media type. */
- if (dev->mem_start)
- option = dev->mem_start;
-- else if (card_idx < MAX_UNITS)
-- option = options[card_idx];
-+ else if (find_cnt < MAX_UNITS)
-+ option = options[find_cnt];
- else
- option = -1;
-
-@@ -832,28 +896,30 @@
- vp->full_duplex = 0;
- vp->bus_master = 0;
- }
-- if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0)
-+ if (find_cnt < MAX_UNITS && full_duplex[find_cnt] > 0)
- vp->full_duplex = 1;
-
-- vp->force_fd = vp->full_duplex;
- vp->options = option;
-
- /* Read the station address from the EEPROM. */
- EL3WINDOW(0);
-+ /* Figure out the size and offset of the EEPROM table.
-+ This is complicated by potential discontiguous address bits. */
-+
-+ /* Locate the opcode bits, 0xC0 or 0x300. */
-+ outw(0x5555, ioaddr + Wn0EepromData);
-+ ee_read_cmd = do_eeprom_op(ioaddr, 0x80) == 0x5555 ? 0x200 : 0x80;
-+ /* Locate the table base for CardBus cards. */
-+ if (do_eeprom_op(ioaddr, ee_read_cmd + 0x37) == 0x6d50)
-+ ee_read_cmd += 0x30;
-+
- for (i = 0; i < 0x40; i++) {
-- int timer;
--#ifdef CARDBUS
-- outw(0x230 + i, ioaddr + Wn0EepromCmd);
--#else
-- outw(EEPROM_Read + i, ioaddr + Wn0EepromCmd);
--#endif
-- /* Pause for at least 162 us. for the read to take place. */
-- for (timer = 10; timer >= 0; timer--) {
-- udelay(162);
-- if ((inw(ioaddr + Wn0EepromCmd) & 0x8000) == 0)
-- break;
-+ int cmd_and_addr = ee_read_cmd + i;
-+ if (ee_read_cmd == 0xB0) { /* Correct for discontinuity. */
-+ int offset = 0x30 + i;
-+ cmd_and_addr = 0x80 + (offset & 0x3f) + ((offset<<2) & 0x0f00);
- }
-- eeprom[i] = inw(ioaddr + Wn0EepromData);
-+ eeprom[i] = do_eeprom_op(ioaddr, cmd_and_addr);
- }
- for (i = 0; i < 0x18; i++)
- checksum ^= eeprom[i];
-@@ -863,7 +929,7 @@
- checksum ^= eeprom[i++];
- checksum = (checksum ^ (checksum >> 8)) & 0xff;
- }
-- if (checksum != 0x00)
-+ if (checksum != 0x00 && !(drv_flags & IS_TORNADO))
- printk(" ***INVALID CHECKSUM %4.4x*** ", checksum);
-
- for (i = 0; i < 3; i++)
-@@ -874,27 +940,22 @@
- for (i = 0; i < 6; i++)
- outb(dev->dev_addr[i], ioaddr + i);
-
--#ifdef __sparc__
-- printk(", IRQ %s\n", __irq_itoa(dev->irq));
--#else
- printk(", IRQ %d\n", dev->irq);
- /* Tell them about an invalid IRQ. */
-- if (vortex_debug && (dev->irq <= 0 || dev->irq >= NR_IRQS))
-+ if (dev->irq <= 0)
- printk(KERN_WARNING " *** Warning: IRQ %d is unlikely to work! ***\n",
- dev->irq);
--#endif
-
-- if (pci_tbl[vp->chip_id].drv_flags & HAS_CB_FNS) {
-+#if ! defined(NO_PCI)
-+ if (drv_flags & HAS_CB_FNS) {
- u32 fn_st_addr; /* Cardbus function status space */
-- pcibios_read_config_dword(pci_bus, pci_devfn, PCI_BASE_ADDRESS_2,
-- &fn_st_addr);
-+ pci_read_config_dword(pdev, PCI_BASE_ADDRESS_2, &fn_st_addr);
- if (fn_st_addr)
- vp->cb_fn_base = ioremap(fn_st_addr & ~3, 128);
-- printk("%s: CardBus functions mapped %8.8x->%p (PCMCIA committee"
-- " brain-damage).\n", dev->name, fn_st_addr, vp->cb_fn_base);
-- EL3WINDOW(2);
-- outw(0x10 | inw(ioaddr + Wn2_ResetOptions), ioaddr + Wn2_ResetOptions);
-+ printk(KERN_INFO "%s: CardBus functions mapped %8.8x->%p.\n",
-+ dev->name, fn_st_addr, vp->cb_fn_base);
- }
-+#endif
-
- /* Extract our information from the EEPROM data. */
- vp->info1 = eeprom[13];
-@@ -903,27 +964,31 @@
-
- if (vp->info1 & 0x8000)
- vp->full_duplex = 1;
-+ if (vp->full_duplex)
-+ vp->medialock = 1;
-+
-+ /* Turn on the transceiver. */
-+ activate_xcvr(dev);
-
- {
- char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
-- union wn3_config config;
-+ int i_cfg;
- EL3WINDOW(3);
- vp->available_media = inw(ioaddr + Wn3_Options);
- if ((vp->available_media & 0xff) == 0) /* Broken 3c916 */
- vp->available_media = 0x40;
-- config.i = inl(ioaddr + Wn3_Config);
-- if (vortex_debug > 1)
-- printk(KERN_DEBUG " Internal config register is %4.4x, "
-- "transceivers %#x.\n", config.i, inw(ioaddr + Wn3_Options));
-- printk(KERN_INFO " %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n",
-- 8 << config.u.ram_size,
-- config.u.ram_width ? "word" : "byte",
-- ram_split[config.u.ram_split],
-- config.u.autoselect ? "autoselect/" : "",
-- config.u.xcvr > XCVR_ExtMII ? "<invalid transceiver>" :
-- media_tbl[config.u.xcvr].name);
-- vp->default_media = config.u.xcvr;
-- vp->autoselect = config.u.autoselect;
-+ i_cfg = inl(ioaddr + Wn3_Config); /* Internal Configuration */
-+ vp->default_media = (i_cfg >> 20) & 15;
-+ if (vp->msg_level & NETIF_MSG_LINK)
-+ printk(KERN_DEBUG " Internal config register is %8.8x, "
-+ "transceivers %#x.\n", i_cfg, inw(ioaddr + Wn3_Options));
-+ printk(KERN_INFO " %dK buffer %s Rx:Tx split, %s%s interface.\n",
-+ 8 << (i_cfg & 7),
-+ ram_split[(i_cfg >> 16) & 3],
-+ i_cfg & 0x01000000 ? "autoselect/" : "",
-+ vp->default_media > XCVR_ExtMII ? "<invalid transceiver>" :
-+ media_tbl[vp->default_media].name);
-+ vp->autoselect = i_cfg & 0x01000000 ? 1 : 0;
- }
-
- if (vp->media_override != 7) {
-@@ -933,16 +998,17 @@
- } else
- dev->if_port = vp->default_media;
-
-- if (dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) {
-+ if ((vp->available_media & 0x41) || (drv_flags & HAS_NWAY) ||
-+ dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) {
- int phy, phy_idx = 0;
- EL3WINDOW(4);
- mii_preamble_required++;
-- mii_preamble_required++;
-+ mdio_sync(ioaddr, 32);
- mdio_read(ioaddr, 24, 1);
- for (phy = 1; phy <= 32 && phy_idx < sizeof(vp->phys); phy++) {
- int mii_status, phyx = phy & 0x1f;
- mii_status = mdio_read(ioaddr, phyx, 1);
-- if (mii_status && mii_status != 0xffff) {
-+ if ((mii_status & 0xf800) && mii_status != 0xffff) {
- vp->phys[phy_idx++] = phyx;
- printk(KERN_INFO " MII transceiver found at address %d,"
- " status %4x.\n", phyx, mii_status);
-@@ -955,6 +1021,12 @@
- printk(KERN_WARNING" ***WARNING*** No MII transceivers found!\n");
- vp->phys[0] = 24;
- } else {
-+ if (mii_preamble_required == 0 &&
-+ mdio_read(ioaddr, vp->phys[0], 1) == 0) {
-+ printk(KERN_INFO "%s: MII transceiver has preamble bug.\n",
-+ dev->name);
-+ mii_preamble_required = 1;
-+ }
- vp->advertising = mdio_read(ioaddr, vp->phys[0], 4);
- if (vp->full_duplex) {
- /* Only advertise the FD media types. */
-@@ -962,14 +1034,14 @@
- mdio_write(ioaddr, vp->phys[0], 4, vp->advertising);
- }
- }
-+ } else {
-+ /* We will emulate MII management. */
-+ vp->phys[0] = 32;
- }
-
-- if (vp->capabilities & CapPwrMgmt)
-- acpi_set_WOL(dev);
--
- if (vp->capabilities & CapBusMaster) {
- vp->full_bus_master_tx = 1;
-- printk(KERN_INFO" Enabling bus-master transmits and %s receives.\n",
-+ printk(KERN_INFO" Using bus-master transmits and %s receives.\n",
- (vp->info2 & 1) ? "early" : "whole-frame" );
- vp->full_bus_master_rx = (vp->info2 & 1) ? 1 : 2;
- }
-@@ -989,29 +1061,27 @@
- }
-
-
--static int
--vortex_open(struct device *dev)
-+static int vortex_open(struct net_device *dev)
- {
-- long ioaddr = dev->base_addr;
- struct vortex_private *vp = (struct vortex_private *)dev->priv;
-- union wn3_config config;
-+ long ioaddr = dev->base_addr;
- int i;
-
-- /* Should be if(HAS_ACPI) */
-- acpi_wake(vp->pci_bus, vp->pci_devfn);
-+ MOD_INC_USE_COUNT;
-
-- /* Before initializing select the active media port. */
-- EL3WINDOW(3);
-- config.i = inl(ioaddr + Wn3_Config);
-+ acpi_wake(vp->pci_dev);
-+ vp->window_lock = SPIN_LOCK_UNLOCKED;
-+ activate_xcvr(dev);
-
-+ /* Before initializing select the active media port. */
- if (vp->media_override != 7) {
-- if (vortex_debug > 1)
-+ if (vp->msg_level & NETIF_MSG_LINK)
- printk(KERN_INFO "%s: Media override to transceiver %d (%s).\n",
- dev->name, vp->media_override,
- media_tbl[vp->media_override].name);
- dev->if_port = vp->media_override;
- } else if (vp->autoselect) {
-- if (pci_tbl[vp->chip_id].drv_flags & HAS_NWAY)
-+ if (vp->drv_flags & HAS_NWAY)
- dev->if_port = XCVR_NWAY;
- else {
- /* Find first available media type, starting with 100baseTx. */
-@@ -1022,88 +1092,39 @@
- } else
- dev->if_port = vp->default_media;
-
-- init_timer(&vp->timer);
-- vp->timer.expires = RUN_AT(media_tbl[dev->if_port].wait);
-- vp->timer.data = (unsigned long)dev;
-- vp->timer.function = &vortex_timer; /* timer handler */
-- add_timer(&vp->timer);
--
-- if (vortex_debug > 1)
-- printk(KERN_DEBUG "%s: Initial media type %s.\n",
-- dev->name, media_tbl[dev->if_port].name);
--
-- vp->full_duplex = vp->force_fd;
-- config.u.xcvr = dev->if_port;
-- if ( ! (pci_tbl[vp->chip_id].drv_flags & HAS_NWAY))
-- outl(config.i, ioaddr + Wn3_Config);
--
-- if (dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) {
-- int mii_reg1, mii_reg5;
-- EL3WINDOW(4);
-- /* Read BMSR (reg1) only to clear old status. */
-- mii_reg1 = mdio_read(ioaddr, vp->phys[0], 1);
-- mii_reg5 = mdio_read(ioaddr, vp->phys[0], 5);
-- if (mii_reg5 == 0xffff || mii_reg5 == 0x0000)
-- ; /* No MII device or no link partner report */
-- else if ((mii_reg5 & 0x0100) != 0 /* 100baseTx-FD */
-- || (mii_reg5 & 0x00C0) == 0x0040) /* 10T-FD, but not 100-HD */
-- vp->full_duplex = 1;
-- if (vortex_debug > 1)
-- printk(KERN_INFO "%s: MII #%d status %4.4x, link partner capability %4.4x,"
-- " setting %s-duplex.\n", dev->name, vp->phys[0],
-- mii_reg1, mii_reg5, vp->full_duplex ? "full" : "half");
-- EL3WINDOW(3);
-- }
--
-- /* Set the full-duplex bit. */
-- outb(((vp->info1 & 0x8000) || vp->full_duplex ? 0x20 : 0) |
-- (dev->mtu > 1500 ? 0x40 : 0), ioaddr + Wn3_MAC_Ctrl);
--
-- if (vortex_debug > 1) {
-- printk(KERN_DEBUG "%s: vortex_open() InternalConfig %8.8x.\n",
-- dev->name, config.i);
-- }
-+ if (! vp->medialock)
-+ vp->full_duplex = 0;
-
-- outw(TxReset, ioaddr + EL3_CMD);
-- for (i = 2000; i >= 0 ; i--)
-- if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
-- break;
-+ vp->status_enable = SetStatusEnb | HostError|IntReq|StatsFull|TxComplete|
-+ (vp->full_bus_master_tx ? DownComplete : TxAvailable) |
-+ (vp->full_bus_master_rx ? UpComplete : RxComplete) |
-+ (vp->bus_master ? DMADone : 0);
-+ vp->intr_enable = SetIntrEnb | IntLatch | TxAvailable | RxComplete |
-+ StatsFull | HostError | TxComplete | IntReq
-+ | (vp->bus_master ? DMADone : 0) | UpComplete | DownComplete;
-
-- outw(RxReset, ioaddr + EL3_CMD);
-- /* Wait a few ticks for the RxReset command to complete. */
-- for (i = 2000; i >= 0 ; i--)
-- if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
-- break;
-+ if (vp->msg_level & NETIF_MSG_LINK)
-+ printk(KERN_DEBUG "%s: Initial media type %s %s-duplex.\n",
-+ dev->name, media_tbl[dev->if_port].name,
-+ vp->full_duplex ? "full":"half");
-
-- outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD);
-+ set_media_type(dev);
-+ start_operation(dev);
-
- /* Use the now-standard shared IRQ implementation. */
- if (request_irq(dev->irq, &vortex_interrupt, SA_SHIRQ, dev->name, dev)) {
-+ MOD_DEC_USE_COUNT;
- return -EAGAIN;
- }
-
-- if (vortex_debug > 1) {
-+ spin_lock(&vp->window_lock);
-+
-+ if (vp->msg_level & NETIF_MSG_IFUP) {
- EL3WINDOW(4);
- printk(KERN_DEBUG "%s: vortex_open() irq %d media status %4.4x.\n",
- dev->name, dev->irq, inw(ioaddr + Wn4_Media));
- }
-
-- /* Set the station address and mask in window 2 each time opened. */
-- EL3WINDOW(2);
-- for (i = 0; i < 6; i++)
-- outb(dev->dev_addr[i], ioaddr + i);
-- for (; i < 12; i+=2)
-- outw(0, ioaddr + i);
--
-- if (dev->if_port == XCVR_10base2)
-- /* Start the thinnet transceiver. We should really wait 50ms...*/
-- outw(StartCoax, ioaddr + EL3_CMD);
-- if (dev->if_port != XCVR_NWAY) {
-- EL3WINDOW(4);
-- outw((inw(ioaddr + Wn4_Media) & ~(Media_10TP|Media_SQE)) |
-- media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media);
-- }
--
- /* Switch to the stats window, and clear all stats by reading. */
- outw(StatsDisable, ioaddr + EL3_CMD);
- EL3WINDOW(6);
-@@ -1119,63 +1140,226 @@
-
- /* Switch to register set 7 for normal use. */
- EL3WINDOW(7);
-+#if defined(CONFIG_VLAN)
-+ /* If this value is set no MTU adjustment is needed for 802.1Q. */
-+ outw(0x8100, ioaddr + Wn7_VLAN_EtherType);
-+#endif
-+ spin_unlock(&vp->window_lock);
-
- if (vp->full_bus_master_rx) { /* Boomerang bus master. */
- vp->cur_rx = vp->dirty_rx = 0;
-+ /* Use 1518/+18 if the CRC is transferred. */
-+ vp->rx_buf_sz = dev->mtu + 14;
-+ if (vp->rx_buf_sz < PKT_BUF_SZ)
-+ vp->rx_buf_sz = PKT_BUF_SZ;
-+
- /* Initialize the RxEarly register as recommended. */
- outw(SetRxThreshold + (1536>>2), ioaddr + EL3_CMD);
- outl(0x0020, ioaddr + PktStatus);
-- if (vortex_debug > 2)
-- printk(KERN_DEBUG "%s: Filling in the Rx ring.\n", dev->name);
- for (i = 0; i < RX_RING_SIZE; i++) {
-- struct sk_buff *skb;
-- vp->rx_ring[i].next = cpu_to_le32(virt_to_bus(&vp->rx_ring[i+1]));
-- vp->rx_ring[i].status = 0; /* Clear complete bit. */
-- vp->rx_ring[i].length = cpu_to_le32(PKT_BUF_SZ | LAST_FRAG);
-- skb = dev_alloc_skb(PKT_BUF_SZ);
-+ vp->rx_ring[i].length = cpu_to_le32(vp->rx_buf_sz | LAST_FRAG);
-+ vp->rx_ring[i].status = 0;
-+ vp->rx_ring[i].next = virt_to_le32desc(&vp->rx_ring[i+1]);
-+ vp->rx_skbuff[i] = 0;
-+ }
-+ /* Wrap the ring. */
-+ vp->rx_head_desc = &vp->rx_ring[0];
-+ vp->rx_ring[i-1].next = virt_to_le32desc(&vp->rx_ring[0]);
-+
-+ for (i = 0; i < RX_RING_SIZE; i++) {
-+ struct sk_buff *skb = dev_alloc_skb(vp->rx_buf_sz);
- vp->rx_skbuff[i] = skb;
- if (skb == NULL)
- break; /* Bad news! */
- skb->dev = dev; /* Mark as being used by this device. */
--#if LINUX_VERSION_CODE >= 0x10300
- skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
-- vp->rx_ring[i].addr = cpu_to_le32(virt_to_bus(skb->tail));
--#else
-- vp->rx_ring[i].addr = virt_to_bus(skb->data);
--#endif
-+ vp->rx_ring[i].addr = virt_to_le32desc(skb->tail);
- }
-- /* Wrap the ring. */
-- vp->rx_ring[i-1].next = cpu_to_le32(virt_to_bus(&vp->rx_ring[0]));
-- outl(virt_to_bus(&vp->rx_ring[0]), ioaddr + UpListPtr);
-+ outl(virt_to_bus(vp->rx_head_desc), ioaddr + UpListPtr);
- }
- if (vp->full_bus_master_tx) { /* Boomerang bus master Tx. */
- dev->hard_start_xmit = &boomerang_start_xmit;
- vp->cur_tx = vp->dirty_tx = 0;
-- outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); /* Room for a packet. */
-+ vp->tx_desc_tail = &vp->tx_ring[TX_RING_SIZE - 1];
-+ if (vp->drv_flags & IS_BOOMERANG) {
-+ /* Room for a packet, to avoid long DownStall delays. */
-+ outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold);
-+ } else if (vp->drv_flags & HAS_V2_TX)
-+ outb(20, ioaddr + DownPollRate);
-+
- /* Clear the Tx ring. */
- for (i = 0; i < TX_RING_SIZE; i++)
- vp->tx_skbuff[i] = 0;
- outl(0, ioaddr + DownListPtr);
-+ vp->tx_full = 0;
-+ vp->restart_tx = 1;
- }
-- /* Set reciever mode: presumably accept b-case and phys addr only. */
-+ /* The multicast filter is an ill-considered, write-only design.
-+ The semantics are not documented, so we assume but do not rely
-+ on the table being cleared with an RxReset.
-+ Here we do an explicit clear of the largest known table.
-+ */
-+ if (vp->drv_flags & HAS_V2_TX)
-+ for (i = 0; i < 0x100; i++)
-+ outw(SetFilterBit | i, ioaddr + EL3_CMD);
-+ memset(vp->mc_filter, 0, sizeof vp->mc_filter);
-+
-+ /* Set receiver mode: presumably accept b-case and phys addr only. */
-+ vp->rx_mode = 0;
- set_rx_mode(dev);
-- outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */
-
-- vp->in_interrupt = 0;
-- dev->tbusy = 0;
-- dev->interrupt = 0;
-- dev->start = 1;
-+ start_operation1(dev);
-+
-+ init_timer(&vp->timer);
-+ vp->timer.expires = jiffies + media_tbl[dev->if_port].wait;
-+ vp->timer.data = (unsigned long)dev;
-+ vp->timer.function = &vortex_timer; /* timer handler */
-+ add_timer(&vp->timer);
-+
-+ return 0;
-+}
-+
-+static void set_media_type(struct net_device *dev)
-+{
-+ struct vortex_private *vp = (struct vortex_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+ int i_cfg;
-+
-+ EL3WINDOW(3);
-+ i_cfg = inl(ioaddr + Wn3_Config);
-+ i_cfg &= ~0x00f00000;
-+ if (vp->drv_flags & HAS_NWAY)
-+ outl(i_cfg | 0x00800000, ioaddr + Wn3_Config);
-+ else
-+ outl(i_cfg | (dev->if_port << 20), ioaddr + Wn3_Config);
-+
-+ if (dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) {
-+ int mii_reg1, mii_reg5;
-+ EL3WINDOW(4);
-+ /* Read BMSR (reg1) only to clear old status. */
-+ mii_reg1 = mdio_read(ioaddr, vp->phys[0], 1);
-+ mii_reg5 = mdio_read(ioaddr, vp->phys[0], 5);
-+ if (mii_reg5 == 0xffff || mii_reg5 == 0x0000)
-+ ; /* No MII device or no link partner report */
-+ else if ((mii_reg5 & 0x0100) != 0 /* 100baseTx-FD */
-+ || (mii_reg5 & 0x00C0) == 0x0040) /* 10T-FD, but not 100-HD */
-+ vp->full_duplex = 1;
-+ if (vp->msg_level & NETIF_MSG_LINK)
-+ printk(KERN_INFO "%s: MII #%d status %4.4x, link partner capability %4.4x,"
-+ " setting %s-duplex.\n", dev->name, vp->phys[0],
-+ mii_reg1, mii_reg5, vp->full_duplex ? "full" : "half");
-+ EL3WINDOW(3);
-+ }
-+ if (dev->if_port == XCVR_10base2)
-+ /* Start the thinnet transceiver. We should really wait 50ms...*/
-+ outw(StartCoax, ioaddr + EL3_CMD);
-+ EL3WINDOW(4);
-+ if (dev->if_port != XCVR_NWAY) {
-+ outw((inw(ioaddr + Wn4_Media) & ~(Media_10TP|Media_SQE)) |
-+ media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media);
-+ }
-+ /* Do we require link beat to transmit? */
-+ if (vp->info1 & 0x4000)
-+ outw(inw(ioaddr + Wn4_Media) & ~Media_Lnk, ioaddr + Wn4_Media);
-+
-+ /* Set the full-duplex and oversized frame bits. */
-+ EL3WINDOW(3);
-+
-+ vp->wn3_mac_ctrl = vp->full_duplex ? 0x0120 : 0;
-+ if (dev->mtu > 1500)
-+ vp->wn3_mac_ctrl |= (dev->mtu == 1504 ? 0x0400 : 0x0040);
-+ outb(vp->wn3_mac_ctrl, ioaddr + Wn3_MAC_Ctrl);
-+
-+ if (vp->drv_flags & HAS_V2_TX)
-+ outw(dev->mtu + 14, ioaddr + Wn3_MaxPktSize);
-+}
-+
-+static void activate_xcvr(struct net_device *dev)
-+{
-+ struct vortex_private *vp = (struct vortex_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+ int reset_opts;
-+
-+ /* Correct some magic bits. */
-+ EL3WINDOW(2);
-+ reset_opts = inw(ioaddr + Wn2_ResetOptions);
-+ if (vp->drv_flags & INVERT_LED_PWR)
-+ reset_opts |= 0x0010;
-+ if (vp->drv_flags & MII_XCVR_PWR)
-+ reset_opts |= 0x4000;
-+ outw(reset_opts, ioaddr + Wn2_ResetOptions);
-+ if (vp->drv_flags & WN0_XCVR_PWR) {
-+ EL3WINDOW(0);
-+ outw(0x0900, ioaddr);
-+ }
-+}
-
-+static void start_operation(struct net_device *dev)
-+{
-+ struct vortex_private *vp = (struct vortex_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+ int i;
-+
-+ outw(TxReset, ioaddr + EL3_CMD);
-+ for (i = 2000; i >= 0 ; i--)
-+ if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
-+ break;
-+
-+ outw(RxReset | 0x04, ioaddr + EL3_CMD);
-+ /* Assume this cleared the filter. */
-+ memset(vp->mc_filter, 0, sizeof vp->mc_filter);
-+
-+ /* Wait a few ticks for the RxReset command to complete. */
-+ for (i = 0; i < 200000; i++)
-+ if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
-+ break;
-+ if (i >= 200 && (vp->msg_level & NETIF_MSG_DRV))
-+ printk(KERN_DEBUG "%s: Rx Reset took an unexpectedly long time"
-+ " to finish, %d ticks.\n",
-+ dev->name, i);
-+
-+ outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD);
-+ /* Handle VLANs and jumbo frames. */
-+ if ((vp->drv_flags & HAS_V2_TX) && dev->mtu > 1500) {
-+ EL3WINDOW(3);
-+ outw(dev->mtu + 14, ioaddr + Wn3_MaxPktSize);
-+ if (dev->mtu > 2033) {
-+ outl(inl(ioaddr + Wn3_Config) | 0x0000C000, ioaddr + Wn3_Config);
-+ outw(SetTxStart + (2000>>2), ioaddr + EL3_CMD);
-+ }
-+ }
-+ /* Reset the station address and mask. */
-+ EL3WINDOW(2);
-+ for (i = 0; i < 6; i++)
-+ outb(dev->dev_addr[i], ioaddr + i);
-+ for (; i < 12; i+=2)
-+ outw(0, ioaddr + i);
-+ if (vp->drv_flags & IS_BOOMERANG) {
-+ /* Room for a packet, to avoid long DownStall delays. */
-+ outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold);
-+ } else if (vp->drv_flags & HAS_V2_TX) {
-+ outb(20, ioaddr + DownPollRate);
-+ vp->restart_tx = 1;
-+ }
-+}
-+
-+static void start_operation1(struct net_device *dev)
-+{
-+ struct vortex_private *vp = (struct vortex_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+
-+ if (vp->full_bus_master_rx) { /* post-Vortex bus master. */
-+ /* Initialize the RxEarly register as recommended. */
-+ outw(SetRxThreshold + (1536>>2), ioaddr + EL3_CMD);
-+ outl(0x0020, ioaddr + PktStatus);
-+ outl(virt_to_bus(&vp->rx_ring[vp->cur_rx % RX_RING_SIZE]),
-+ ioaddr + UpListPtr);
-+ }
-+
-+ outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */
- outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */
- outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */
- /* Allow status bits to be seen. */
-- vp->status_enable = SetStatusEnb | HostError|IntReq|StatsFull|TxComplete|
-- (vp->full_bus_master_tx ? DownComplete : TxAvailable) |
-- (vp->full_bus_master_rx ? UpComplete : RxComplete) |
-- (vp->bus_master ? DMADone : 0);
-- vp->intr_enable = SetIntrEnb | IntLatch | TxAvailable | RxComplete |
-- StatsFull | HostError | TxComplete | IntReq
-- | (vp->bus_master ? DMADone : 0) | UpComplete | DownComplete;
- outw(vp->status_enable, ioaddr + EL3_CMD);
- /* Ack all pending events, and set active indicator mask. */
- outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,
-@@ -1183,24 +1367,47 @@
- outw(vp->intr_enable, ioaddr + EL3_CMD);
- if (vp->cb_fn_base) /* The PCMCIA people are idiots. */
- writel(0x8000, vp->cb_fn_base + 4);
--
-- MOD_INC_USE_COUNT;
--
-- return 0;
-+ netif_start_tx_queue(dev);
- }
-
- static void vortex_timer(unsigned long data)
- {
-- struct device *dev = (struct device *)data;
-+ struct net_device *dev = (struct net_device *)data;
- struct vortex_private *vp = (struct vortex_private *)dev->priv;
- long ioaddr = dev->base_addr;
- int next_tick = 60*HZ;
- int ok = 0;
-- int media_status, mii_status, old_window;
-+ int media_status, old_window;
-
-- if (vortex_debug > 1)
-- printk(KERN_DEBUG "%s: Media selection timer tick happened, %s.\n",
-- dev->name, media_tbl[dev->if_port].name);
-+ if (vp->msg_level & NETIF_MSG_TIMER)
-+ printk(KERN_DEBUG "%s: Media selection timer tick happened, "
-+ "%s %s duplex.\n",
-+ dev->name, media_tbl[dev->if_port].name,
-+ vp->full_duplex ? "full" : "half");
-+
-+ /* This only works with bus-master (non-3c590) chips. */
-+ if (vp->cur_tx - vp->dirty_tx > 1 &&
-+ (jiffies - dev->trans_start) > TX_TIMEOUT) {
-+ /* Check for blocked interrupts. */
-+ if (inw(ioaddr + EL3_STATUS) & IntLatch) {
-+ /* We have a blocked IRQ line. This should never happen, but
-+ we recover as best we can.*/
-+ if ( ! vp->polling) {
-+ if (jiffies - vp->last_reset > 10*HZ) {
-+ printk(KERN_ERR "%s: IRQ %d is physically blocked! "
-+ "Failing back to low-rate polling.\n",
-+ dev->name, dev->irq);
-+ vp->last_reset = jiffies;
-+ }
-+ vp->polling = 1;
-+ }
-+ vortex_interrupt(dev->irq, dev, 0);
-+ next_tick = jiffies + 2;
-+ } else {
-+ vortex_tx_timeout(dev);
-+ vp->last_reset = jiffies;
-+ }
-+ }
-
- disable_irq(dev->irq);
- old_window = inw(ioaddr + EL3_CMD) >> 13;
-@@ -1210,59 +1417,66 @@
- case XCVR_10baseT: case XCVR_100baseTx: case XCVR_100baseFx:
- if (media_status & Media_LnkBeat) {
- ok = 1;
-- if (vortex_debug > 1)
-+ if (vp->msg_level & NETIF_MSG_LINK)
- printk(KERN_DEBUG "%s: Media %s has link beat, %x.\n",
- dev->name, media_tbl[dev->if_port].name, media_status);
-- } else if (vortex_debug > 1)
-+ } else if (vp->msg_level & NETIF_MSG_LINK)
- printk(KERN_DEBUG "%s: Media %s is has no link beat, %x.\n",
- dev->name, media_tbl[dev->if_port].name, media_status);
- break;
-- case XCVR_MII: case XCVR_NWAY:
-- mii_status = mdio_read(ioaddr, vp->phys[0], 1);
-- ok = 1;
-- if (debug > 1)
-- printk(KERN_DEBUG "%s: MII transceiver has status %4.4x.\n",
-- dev->name, mii_status);
-- if (mii_status & 0x0004) {
-- int mii_reg5 = mdio_read(ioaddr, vp->phys[0], 5);
-- if (! vp->force_fd && mii_reg5 != 0xffff) {
-- int duplex = (mii_reg5&0x0100) ||
-- (mii_reg5 & 0x01C0) == 0x0040;
-- if (vp->full_duplex != duplex) {
-- vp->full_duplex = duplex;
-- printk(KERN_INFO "%s: Setting %s-duplex based on MII "
-- "#%d link partner capability of %4.4x.\n",
-- dev->name, vp->full_duplex ? "full" : "half",
-- vp->phys[0], mii_reg5);
-- /* Set the full-duplex bit. */
-- outb((vp->full_duplex ? 0x20 : 0) |
-- (dev->mtu > 1500 ? 0x40 : 0),
-- ioaddr + Wn3_MAC_Ctrl);
-- }
-- next_tick = 60*HZ;
-- }
-- }
-- break;
-- default: /* Other media types handled by Tx timeouts. */
-- if (vortex_debug > 1)
-- printk(KERN_DEBUG "%s: Media %s is has no indication, %x.\n",
-- dev->name, media_tbl[dev->if_port].name, media_status);
-+ case XCVR_MII: case XCVR_NWAY: {
-+ int mii_status = mdio_read(ioaddr, vp->phys[0], 1);
-+ int mii_reg5, negotiated, duplex;
-+ ok = 1;
-+ if (vp->msg_level & NETIF_MSG_LINK)
-+ printk(KERN_DEBUG "%s: MII transceiver has status %4.4x.\n",
-+ dev->name, mii_status);
-+ if (vp->medialock)
-+ break;
-+ if ((mii_status & 0x0004) == 0) {
-+ next_tick = 5*HZ;
-+ break;
-+ }
-+ mii_reg5 = mdio_read(ioaddr, vp->phys[0], 5);
-+ negotiated = mii_reg5 & vp->advertising;
-+ duplex = (negotiated & 0x0100) || (negotiated & 0x03C0) == 0x0040;
-+ if (mii_reg5 == 0xffff || vp->full_duplex == duplex)
-+ break;
-+ if (vp->msg_level & NETIF_MSG_LINK)
-+ printk(KERN_INFO "%s: Setting %s-duplex based on "
-+ "MII #%d link partner capability of %4.4x.\n",
-+ dev->name, vp->full_duplex ? "full" : "half",
-+ vp->phys[0], mii_reg5);
-+ vp->full_duplex = duplex;
-+ /* Set the full-duplex bit. */
-+ EL3WINDOW(3);
-+ if (duplex)
-+ vp->wn3_mac_ctrl |= 0x120;
-+ else
-+ vp->wn3_mac_ctrl &= ~0x120;
-+ outb(vp->wn3_mac_ctrl, ioaddr + Wn3_MAC_Ctrl);
-+ break;
-+ }
-+ default: /* Other media types handled by Tx timeouts. */
-+ if (vp->msg_level & NETIF_MSG_LINK)
-+ printk(KERN_DEBUG "%s: Media %s is has no indication, %x.\n",
-+ dev->name, media_tbl[dev->if_port].name, media_status);
- ok = 1;
- }
- if ( ! ok) {
-- union wn3_config config;
-+ int i_cfg;
-
- do {
- dev->if_port = media_tbl[dev->if_port].next;
- } while ( ! (vp->available_media & media_tbl[dev->if_port].mask));
- if (dev->if_port == XCVR_Default) { /* Go back to default. */
- dev->if_port = vp->default_media;
-- if (vortex_debug > 1)
-+ if (vp->msg_level & NETIF_MSG_LINK)
- printk(KERN_DEBUG "%s: Media selection failing, using default "
- "%s port.\n",
- dev->name, media_tbl[dev->if_port].name);
- } else {
-- if (vortex_debug > 1)
-+ if (vp->msg_level & NETIF_MSG_LINK)
- printk(KERN_DEBUG "%s: Media selection failed, now trying "
- "%s port.\n",
- dev->name, media_tbl[dev->if_port].name);
-@@ -1272,54 +1486,60 @@
- media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media);
-
- EL3WINDOW(3);
-- config.i = inl(ioaddr + Wn3_Config);
-- config.u.xcvr = dev->if_port;
-- outl(config.i, ioaddr + Wn3_Config);
-+ i_cfg = inl(ioaddr + Wn3_Config);
-+ i_cfg &= ~0x00f00000;
-+ i_cfg |= (dev->if_port << 20);
-+ outl(i_cfg, ioaddr + Wn3_Config);
-
- outw(dev->if_port == XCVR_10base2 ? StartCoax : StopCoax,
- ioaddr + EL3_CMD);
- }
- EL3WINDOW(old_window);
- enable_irq(dev->irq);
-+ if (vp->restore_intr_mask)
-+ outw(FakeIntr, ioaddr + EL3_CMD);
-
-- if (vortex_debug > 2)
-+ if (vp->msg_level & NETIF_MSG_TIMER)
- printk(KERN_DEBUG "%s: Media selection timer finished, %s.\n",
- dev->name, media_tbl[dev->if_port].name);
-
-- vp->timer.expires = RUN_AT(next_tick);
-+ vp->timer.expires = jiffies + next_tick;
- add_timer(&vp->timer);
- return;
- }
-
--static void vortex_tx_timeout(struct device *dev)
-+static void vortex_tx_timeout(struct net_device *dev)
- {
- struct vortex_private *vp = (struct vortex_private *)dev->priv;
- long ioaddr = dev->base_addr;
-+ int tx_status = inb(ioaddr + TxStatus);
-+ int intr_status = inw(ioaddr + EL3_STATUS);
- int j;
-
- printk(KERN_ERR "%s: transmit timed out, tx_status %2.2x status %4.4x.\n",
-- dev->name, inb(ioaddr + TxStatus),
-- inw(ioaddr + EL3_STATUS));
-+ dev->name, tx_status, intr_status);
- /* Slight code bloat to be user friendly. */
-- if ((inb(ioaddr + TxStatus) & 0x88) == 0x88)
-+ if ((tx_status & 0x88) == 0x88)
- printk(KERN_ERR "%s: Transmitter encountered 16 collisions --"
- " network cable problem?\n", dev->name);
-- if (inw(ioaddr + EL3_STATUS) & IntLatch) {
-+ if (intr_status & IntLatch) {
- printk(KERN_ERR "%s: Interrupt posted but not delivered --"
- " IRQ blocked by another device?\n", dev->name);
-- /* Bad idea here.. but we might as well handle a few events. */
-+ /* Race condition possible, but we handle a few events. */
- vortex_interrupt(dev->irq, dev, 0);
- }
-
- #if ! defined(final_version) && LINUX_VERSION_CODE >= 0x10300
- if (vp->full_bus_master_tx) {
- int i;
-- printk(KERN_DEBUG " Flags; bus-master %d, full %d; dirty %d "
-- "current %d.\n",
-- vp->full_bus_master_tx, vp->tx_full, vp->dirty_tx, vp->cur_tx);
-- printk(KERN_DEBUG " Transmit list %8.8x vs. %p.\n",
-- inl(ioaddr + DownListPtr),
-- &vp->tx_ring[vp->dirty_tx % TX_RING_SIZE]);
-+ printk(KERN_DEBUG " Flags: bus-master %d full %d dirty %d "
-+ "current %d restart_tx %d.\n",
-+ vp->full_bus_master_tx, vp->tx_full, vp->dirty_tx, vp->cur_tx,
-+ vp->restart_tx);
-+ printk(KERN_DEBUG " Transmit list %8.8x vs. %p, packet ID %2.2x.\n",
-+ (int)inl(ioaddr + DownListPtr),
-+ &vp->tx_ring[vp->dirty_tx % TX_RING_SIZE],
-+ inb(ioaddr + TxPktID));
- for (i = 0; i < TX_RING_SIZE; i++) {
- printk(KERN_DEBUG " %d: @%p length %8.8x status %8.8x\n", i,
- &vp->tx_ring[i],
-@@ -1334,26 +1554,40 @@
- break;
-
- vp->stats.tx_errors++;
-+
- if (vp->full_bus_master_tx) {
-- if (vortex_debug > 0)
-+ if (vp->drv_flags & HAS_V2_TX)
-+ outb(20, ioaddr + DownPollRate);
-+ if (vp->msg_level & NETIF_MSG_TX_ERR)
- printk(KERN_DEBUG "%s: Resetting the Tx ring pointer.\n",
- dev->name);
- if (vp->cur_tx - vp->dirty_tx > 0 && inl(ioaddr + DownListPtr) == 0)
- outl(virt_to_bus(&vp->tx_ring[vp->dirty_tx % TX_RING_SIZE]),
- ioaddr + DownListPtr);
-- if (vp->tx_full && (vp->cur_tx - vp->dirty_tx <= TX_RING_SIZE - 1)) {
-+ else
-+ vp->restart_tx = 1;
-+ if (vp->drv_flags & IS_BOOMERANG) {
-+ /* Room for a packet, to avoid long DownStall delays. */
-+ outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold);
-+ outw(DownUnstall, ioaddr + EL3_CMD);
-+ } else {
-+ if (dev->mtu > 2033)
-+ outw(SetTxStart + (2000>>2), ioaddr + EL3_CMD);
-+ }
-+
-+ if (vp->tx_full && (vp->cur_tx - vp->dirty_tx <= TX_QUEUE_LEN - 1)) {
- vp->tx_full = 0;
-- clear_bit(0, (void*)&dev->tbusy);
-+ netif_unpause_tx_queue(dev);
- }
-- outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold);
-- outw(DownUnstall, ioaddr + EL3_CMD);
-- } else
-+ } else {
-+ netif_unpause_tx_queue(dev);
- vp->stats.tx_dropped++;
--
-+ }
-+
- /* Issue Tx Enable */
- outw(TxEnable, ioaddr + EL3_CMD);
- dev->trans_start = jiffies;
--
-+
- /* Switch to register set 7 for normal use. */
- EL3WINDOW(7);
- }
-@@ -1363,7 +1597,7 @@
- * the cache impact.
- */
- static void
--vortex_error(struct device *dev, int status)
-+vortex_error(struct net_device *dev, int status)
- {
- struct vortex_private *vp = (struct vortex_private *)dev->priv;
- long ioaddr = dev->base_addr;
-@@ -1373,8 +1607,7 @@
- if (status & TxComplete) { /* Really "TxError" for us. */
- unsigned char tx_status = inb(ioaddr + TxStatus);
- /* Presumably a tx-timeout. We must merely re-enable. */
-- if (vortex_debug > 2
-- || (tx_status != 0x88 && vortex_debug > 0))
-+ if (vp->msg_level & NETIF_MSG_TX_ERR)
- printk(KERN_DEBUG"%s: Transmit error, Tx status register %2.2x.\n",
- dev->name, tx_status);
- if (tx_status & 0x14) vp->stats.tx_fifo_errors++;
-@@ -1382,8 +1615,10 @@
- outb(0, ioaddr + TxStatus);
- if (tx_status & 0x30)
- do_tx_reset = 1;
-- else /* Merely re-enable the transmitter. */
-+ else { /* Merely re-enable the transmitter. */
- outw(TxEnable, ioaddr + EL3_CMD);
-+ vp->restart_tx = 1;
-+ }
- }
- if (status & RxEarly) { /* Rx early is unused. */
- vortex_rx(dev);
-@@ -1391,7 +1626,7 @@
- }
- if (status & StatsFull) { /* Empty statistics. */
- static int DoneDidThat = 0;
-- if (vortex_debug > 4)
-+ if (vp->msg_level & NETIF_MSG_MISC)
- printk(KERN_DEBUG "%s: Updating stats.\n", dev->name);
- update_stats(ioaddr, dev);
- /* HACK: Disable statistics as an interrupt source. */
-@@ -1409,31 +1644,47 @@
- if (status & IntReq) { /* Restore all interrupt sources. */
- outw(vp->status_enable, ioaddr + EL3_CMD);
- outw(vp->intr_enable, ioaddr + EL3_CMD);
-+ vp->restore_intr_mask = 0;
- }
- if (status & HostError) {
- u16 fifo_diag;
- EL3WINDOW(4);
- fifo_diag = inw(ioaddr + Wn4_FIFODiag);
-- if (vortex_debug > 0)
-- printk(KERN_ERR "%s: Host error, FIFO diagnostic register %4.4x.\n",
-- dev->name, fifo_diag);
-+ if (vp->msg_level & NETIF_MSG_DRV)
-+ printk(KERN_ERR "%s: Host error, status %x, FIFO diagnostic "
-+ "register %4.4x.\n",
-+ dev->name, status, fifo_diag);
- /* Adapter failure requires Tx/Rx reset and reinit. */
- if (vp->full_bus_master_tx) {
-+ int bus_status = inl(ioaddr + PktStatus);
-+ /* 0x80000000 PCI master abort. */
-+ /* 0x40000000 PCI target abort. */
- outw(TotalReset | 0xff, ioaddr + EL3_CMD);
- for (i = 2000; i >= 0 ; i--)
- if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
- break;
-+ if (vp->msg_level & NETIF_MSG_DRV)
-+ printk(KERN_ERR "%s: PCI bus error, bus status %8.8x, reset "
-+ "had %d tick left.\n",
-+ dev->name, bus_status, i);
- /* Re-enable the receiver. */
- outw(RxEnable, ioaddr + EL3_CMD);
- outw(TxEnable, ioaddr + EL3_CMD);
-+ vp->restart_tx = 1;
- } else if (fifo_diag & 0x0400)
- do_tx_reset = 1;
- if (fifo_diag & 0x3000) {
-- outw(RxReset, ioaddr + EL3_CMD);
-- for (i = 2000; i >= 0 ; i--)
-+ outw(RxReset | 7, ioaddr + EL3_CMD);
-+ for (i = 200000; i >= 0 ; i--)
- if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
- break;
-+ if ((vp->drv_flags & HAS_V2_TX) && dev->mtu > 1500) {
-+ EL3WINDOW(3);
-+ outw(dev->mtu + 14, ioaddr + Wn3_MaxPktSize);
-+ }
- /* Set the Rx filter to the current state. */
-+ memset(vp->mc_filter, 0, sizeof vp->mc_filter);
-+ vp->rx_mode = 0;
- set_rx_mode(dev);
- outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */
- outw(AckIntr | HostError, ioaddr + EL3_CMD);
-@@ -1446,19 +1697,23 @@
- if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
- break;
- outw(TxEnable, ioaddr + EL3_CMD);
-+ vp->restart_tx = 1;
- }
-
- }
-
-
- static int
--vortex_start_xmit(struct sk_buff *skb, struct device *dev)
-+vortex_start_xmit(struct sk_buff *skb, struct net_device *dev)
- {
- struct vortex_private *vp = (struct vortex_private *)dev->priv;
- long ioaddr = dev->base_addr;
-
-- if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
-- if (jiffies - dev->trans_start >= TX_TIMEOUT)
-+ /* Block a timer-based transmit from overlapping. This happens when
-+ packets are presumed lost, and we use this check the Tx status. */
-+ if (netif_pause_tx_queue(dev) != 0) {
-+ /* This watchdog code is redundant with the media monitor timer. */
-+ if (jiffies - dev->trans_start > TX_TIMEOUT)
- vortex_tx_timeout(dev);
- return 1;
- }
-@@ -1471,16 +1726,18 @@
- outw((skb->len + 3) & ~3, ioaddr + Wn7_MasterLen);
- vp->tx_skb = skb;
- outw(StartDMADown, ioaddr + EL3_CMD);
-- /* dev->tbusy will be cleared at the DMADone interrupt. */
-+ netif_stop_tx_queue(dev);
-+ /* Tx busy will be cleared at the DMADone interrupt. */
- } else {
- /* ... and the packet rounded to a doubleword. */
- outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
-- DEV_FREE_SKB(skb);
-- if (inw(ioaddr + TxFree) > 1536) {
-- clear_bit(0, (void*)&dev->tbusy);
-- } else
-+ dev_free_skb(skb);
-+ if (inw(ioaddr + TxFree) <= 1536) {
- /* Interrupt us when the FIFO has room for max-sized packet. */
- outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
-+ netif_stop_tx_queue(dev);
-+ } else
-+ netif_unpause_tx_queue(dev); /* Typical path */
- }
-
- dev->trans_start = jiffies;
-@@ -1492,7 +1749,7 @@
-
- while (--i > 0 && (tx_status = inb(ioaddr + TxStatus)) > 0) {
- if (tx_status & 0x3C) { /* A Tx-disabling error occurred. */
-- if (vortex_debug > 2)
-+ if (vp->msg_level & NETIF_MSG_TX_ERR)
- printk(KERN_DEBUG "%s: Tx error, status %2.2x.\n",
- dev->name, tx_status);
- if (tx_status & 0x04) vp->stats.tx_fifo_errors++;
-@@ -1505,6 +1762,7 @@
- break;
- }
- outw(TxEnable, ioaddr + EL3_CMD);
-+ vp->restart_tx = 1;
- }
- outb(0x00, ioaddr + TxStatus); /* Pop the status stack. */
- }
-@@ -1513,38 +1771,46 @@
- }
-
- static int
--boomerang_start_xmit(struct sk_buff *skb, struct device *dev)
-+boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev)
- {
- struct vortex_private *vp = (struct vortex_private *)dev->priv;
- long ioaddr = dev->base_addr;
-+ int entry;
-+ struct boom_tx_desc *prev_entry;
-+ unsigned long flags;
-+ int i;
-
-- if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
-- if (jiffies - dev->trans_start >= TX_TIMEOUT)
-+ if (netif_pause_tx_queue(dev) != 0) {
-+ /* This watchdog code is redundant with the media monitor timer. */
-+ if (jiffies - dev->trans_start > TX_TIMEOUT)
- vortex_tx_timeout(dev);
- return 1;
-- } else {
-- /* Calculate the next Tx descriptor entry. */
-- int entry = vp->cur_tx % TX_RING_SIZE;
-- struct boom_tx_desc *prev_entry =
-- &vp->tx_ring[(vp->cur_tx-1) % TX_RING_SIZE];
-- unsigned long flags;
-- int i;
-+ }
-
-- if (vortex_debug > 3)
-- printk(KERN_DEBUG "%s: Trying to send a packet, Tx index %d.\n",
-- dev->name, vp->cur_tx);
-- if (vp->tx_full) {
-- if (vortex_debug >0)
-- printk(KERN_WARNING "%s: Tx Ring full, refusing to send buffer.\n",
-- dev->name);
-- return 1;
-- }
-- vp->tx_skbuff[entry] = skb;
-- vp->tx_ring[entry].next = 0;
-- vp->tx_ring[entry].addr = cpu_to_le32(virt_to_bus(skb->data));
-- vp->tx_ring[entry].length = cpu_to_le32(skb->len | LAST_FRAG);
-+ /* Calculate the next Tx descriptor entry. */
-+ entry = vp->cur_tx % TX_RING_SIZE;
-+ prev_entry = &vp->tx_ring[(vp->cur_tx-1) % TX_RING_SIZE];
-+
-+ if (vp->msg_level & NETIF_MSG_TX_QUEUED)
-+ printk(KERN_DEBUG "%s: Queuing Tx packet, index %d.\n",
-+ dev->name, vp->cur_tx);
-+ /* Impossible error. */
-+ if (vp->tx_full) {
-+ printk(KERN_WARNING "%s: Tx Ring full, refusing to send buffer.\n",
-+ dev->name);
-+ return 1;
-+ }
-+ vp->tx_skbuff[entry] = skb;
-+ vp->tx_ring[entry].next = 0;
-+ vp->tx_ring[entry].addr = virt_to_le32desc(skb->data);
-+ vp->tx_ring[entry].length = cpu_to_le32(skb->len | LAST_FRAG);
-+ if (vp->capabilities & CapNoTxLength)
-+ vp->tx_ring[entry].status =
-+ cpu_to_le32(TxNoRoundup | TxIntrUploaded | (entry << 2));
-+ else
- vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded);
-
-+ if (vp->drv_flags & IS_BOOMERANG) {
- save_flags(flags);
- cli();
- outw(DownStall, ioaddr + EL3_CMD);
-@@ -1552,66 +1818,64 @@
- for (i = 600; i >= 0 ; i--)
- if ( (inw(ioaddr + EL3_STATUS) & CmdInProgress) == 0)
- break;
-- prev_entry->next = cpu_to_le32(virt_to_bus(&vp->tx_ring[entry]));
-+ vp->tx_desc_tail->next = virt_to_le32desc(&vp->tx_ring[entry]);
-+ vp->tx_desc_tail = &vp->tx_ring[entry];
- if (inl(ioaddr + DownListPtr) == 0) {
- outl(virt_to_bus(&vp->tx_ring[entry]), ioaddr + DownListPtr);
- queued_packet++;
- }
- outw(DownUnstall, ioaddr + EL3_CMD);
- restore_flags(flags);
--
-- vp->cur_tx++;
-- if (vp->cur_tx - vp->dirty_tx > TX_RING_SIZE - 1)
-- vp->tx_full = 1;
-- else { /* Clear previous interrupt enable. */
-+ } else {
-+ vp->tx_desc_tail->next = virt_to_le32desc(&vp->tx_ring[entry]);
-+ vp->tx_desc_tail = &vp->tx_ring[entry];
-+ if (vp->restart_tx) {
-+ outl(virt_to_bus(vp->tx_desc_tail), ioaddr + DownListPtr);
-+ vp->restart_tx = 0;
-+ queued_packet++;
-+ }
-+ }
-+ vp->cur_tx++;
-+ if (vp->cur_tx - vp->dirty_tx >= TX_QUEUE_LEN) {
-+ vp->tx_full = 1;
-+ /* Check for a just-cleared queue. */
-+ if (vp->cur_tx - (volatile unsigned int)vp->dirty_tx
-+ < TX_QUEUE_LEN - 2) {
-+ vp->tx_full = 0;
-+ netif_unpause_tx_queue(dev);
-+ } else
-+ netif_stop_tx_queue(dev);
-+ } else { /* Clear previous interrupt enable. */
- #if defined(tx_interrupt_mitigation)
-- prev_entry->status &= cpu_to_le32(~TxIntrUploaded);
-+ prev_entry->status &= cpu_to_le32(~TxIntrUploaded);
- #endif
-- clear_bit(0, (void*)&dev->tbusy);
-- }
-- dev->trans_start = jiffies;
-- return 0;
-+ netif_unpause_tx_queue(dev); /* Typical path */
- }
-+ dev->trans_start = jiffies;
-+ return 0;
- }
-
- /* The interrupt handler does all of the Rx thread work and cleans up
- after the Tx thread. */
- static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs)
- {
-- struct device *dev = dev_id;
-+ struct net_device *dev = dev_id;
- struct vortex_private *vp = (struct vortex_private *)dev->priv;
- long ioaddr;
- int latency, status;
-- int work_done = max_interrupt_work;
-+ int work_done = vp->max_interrupt_work;
-
--#if defined(__i386__)
-- /* A lock to prevent simultaneous entry bug on Intel SMP machines. */
-- if (test_and_set_bit(0, (void*)&dev->interrupt)) {
-- printk(KERN_ERR"%s: SMP simultaneous entry of an interrupt handler.\n",
-- dev->name);
-- dev->interrupt = 0; /* Avoid halting machine. */
-- return;
-- }
--#else
-- if (dev->interrupt) {
-- printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name);
-- return;
-- }
-- dev->interrupt = 1;
--#endif
--
-- dev->interrupt = 1;
- ioaddr = dev->base_addr;
- latency = inb(ioaddr + Timer);
- status = inw(ioaddr + EL3_STATUS);
-
- if (status == 0xffff)
- goto handler_exit;
-- if (vortex_debug > 4)
-+ if (vp->msg_level & NETIF_MSG_INTR)
- printk(KERN_DEBUG "%s: interrupt, status %4.4x, latency %d ticks.\n",
- dev->name, status, latency);
- do {
-- if (vortex_debug > 5)
-+ if (vp->msg_level & NETIF_MSG_INTR)
- printk(KERN_DEBUG "%s: In interrupt loop, status %4.4x.\n",
- dev->name, status);
- if (status & RxComplete)
-@@ -1622,12 +1886,11 @@
- }
-
- if (status & TxAvailable) {
-- if (vortex_debug > 5)
-+ if (vp->msg_level & NETIF_MSG_TX_DONE)
- printk(KERN_DEBUG " TX room bit was handled.\n");
- /* There's room in the FIFO for a full-sized packet. */
- outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);
-- clear_bit(0, (void*)&dev->tbusy);
-- mark_bh(NET_BH);
-+ netif_resume_tx_queue(dev);
- }
-
- if (status & DownComplete) {
-@@ -1636,30 +1899,37 @@
- outw(AckIntr | DownComplete, ioaddr + EL3_CMD);
- while (vp->cur_tx - dirty_tx > 0) {
- int entry = dirty_tx % TX_RING_SIZE;
-- if (inl(ioaddr + DownListPtr) ==
-- virt_to_bus(&vp->tx_ring[entry]))
-+ int tx_status = le32_to_cpu(vp->tx_ring[entry].status);
-+ if (vp->capabilities & CapNoTxLength) {
-+ if ( ! (tx_status & TxDownComplete))
-+ break;
-+ } else if (inl(ioaddr + DownListPtr) ==
-+ virt_to_bus(&vp->tx_ring[entry]))
- break; /* It still hasn't been processed. */
-+ if (vp->msg_level & NETIF_MSG_TX_DONE)
-+ printk(KERN_DEBUG "%s: Transmit done, Tx status %8.8x.\n",
-+ dev->name, tx_status);
- if (vp->tx_skbuff[entry]) {
-- DEV_FREE_SKB(vp->tx_skbuff[entry]);
-+ dev_free_skb_irq(vp->tx_skbuff[entry]);
- vp->tx_skbuff[entry] = 0;
- }
- /* vp->stats.tx_packets++; Counted below. */
- dirty_tx++;
- }
- vp->dirty_tx = dirty_tx;
-- if (vp->tx_full && (vp->cur_tx - dirty_tx <= TX_RING_SIZE - 1)) {
-+ /* 4 entry hysteresis before marking the queue non-full. */
-+ if (vp->tx_full && (vp->cur_tx - dirty_tx < TX_QUEUE_LEN - 4)) {
- vp->tx_full = 0;
-- clear_bit(0, (void*)&dev->tbusy);
-- mark_bh(NET_BH);
-+ netif_resume_tx_queue(dev);
- }
- }
- if (status & DMADone) {
- if (inw(ioaddr + Wn7_MasterStatus) & 0x1000) {
- outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */
-- DEV_FREE_SKB(vp->tx_skb); /* Release the transfered buffer */
-+ /* Release the transfered buffer */
-+ dev_free_skb_irq(vp->tx_skb);
- if (inw(ioaddr + TxFree) > 1536) {
-- clear_bit(0, (void*)&dev->tbusy);
-- mark_bh(NET_BH);
-+ netif_resume_tx_queue(dev);
- } else /* Interrupt when FIFO has room for max-sized packet. */
- outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
- }
-@@ -1683,6 +1953,7 @@
- outw(SetStatusEnb | ((~status) & 0x7FE), ioaddr + EL3_CMD);
- outw(AckIntr | 0x7FF, ioaddr + EL3_CMD);
- /* The timer will reenable interrupts. */
-+ vp->restore_intr_mask = 1;
- break;
- }
- }
-@@ -1693,32 +1964,27 @@
-
- } while ((status = inw(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete));
-
-- if (vortex_debug > 4)
-+ if (vp->msg_level & NETIF_MSG_INTR)
- printk(KERN_DEBUG "%s: exiting interrupt, status %4.4x.\n",
- dev->name, status);
- handler_exit:
--#if defined(__i386__)
-- clear_bit(0, (void*)&dev->interrupt);
--#else
-- dev->interrupt = 0;
--#endif
- return;
- }
-
--static int vortex_rx(struct device *dev)
-+static int vortex_rx(struct net_device *dev)
- {
- struct vortex_private *vp = (struct vortex_private *)dev->priv;
- long ioaddr = dev->base_addr;
- int i;
- short rx_status;
-
-- if (vortex_debug > 5)
-+ if (vp->msg_level & NETIF_MSG_RX_STATUS)
- printk(KERN_DEBUG" In rx_packet(), status %4.4x, rx_status %4.4x.\n",
- inw(ioaddr+EL3_STATUS), inw(ioaddr+RxStatus));
- while ((rx_status = inw(ioaddr + RxStatus)) > 0) {
- if (rx_status & 0x4000) { /* Error, update stats. */
- unsigned char rx_error = inb(ioaddr + RxErrors);
-- if (vortex_debug > 2)
-+ if (vp->msg_level & NETIF_MSG_RX_ERR)
- printk(KERN_DEBUG " Rx error: status %2.2x.\n", rx_error);
- vp->stats.rx_errors++;
- if (rx_error & 0x01) vp->stats.rx_over_errors++;
-@@ -1732,7 +1998,7 @@
- struct sk_buff *skb;
-
- skb = dev_alloc_skb(pkt_len + 5);
-- if (vortex_debug > 4)
-+ if (vp->msg_level & NETIF_MSG_RX_STATUS)
- printk(KERN_DEBUG "Receiving packet size %d status %4.4x.\n",
- pkt_len, rx_status);
- if (skb != NULL) {
-@@ -1756,12 +2022,15 @@
- netif_rx(skb);
- dev->last_rx = jiffies;
- vp->stats.rx_packets++;
-+#if LINUX_VERSION_CODE > 0x20127
-+ vp->stats.rx_bytes += pkt_len;
-+#endif
- /* Wait a limited time to go to next packet. */
- for (i = 200; i >= 0; i--)
- if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
- break;
- continue;
-- } else if (vortex_debug)
-+ } else if (vp->msg_level & NETIF_MSG_RX_ERR)
- printk(KERN_NOTICE "%s: No memory to allocate a sk_buff of "
- "size %d.\n", dev->name, pkt_len);
- }
-@@ -1777,7 +2046,7 @@
- }
-
- static int
--boomerang_rx(struct device *dev)
-+boomerang_rx(struct net_device *dev)
- {
- struct vortex_private *vp = (struct vortex_private *)dev->priv;
- int entry = vp->cur_rx % RX_RING_SIZE;
-@@ -1785,42 +2054,51 @@
- int rx_status;
- int rx_work_limit = vp->dirty_rx + RX_RING_SIZE - vp->cur_rx;
-
-- if (vortex_debug > 5)
-+ if (vp->msg_level & NETIF_MSG_RX_STATUS)
- printk(KERN_DEBUG " In boomerang_rx(), status %4.4x, rx_status "
-- "%4.4x.\n",
-- inw(ioaddr+EL3_STATUS), inw(ioaddr+RxStatus));
-+ "%8.8x.\n",
-+ inw(ioaddr+EL3_STATUS), (int)inl(ioaddr+UpPktStatus));
- while ((rx_status = le32_to_cpu(vp->rx_ring[entry].status)) & RxDComplete){
- if (--rx_work_limit < 0)
- break;
- if (rx_status & RxDError) { /* Error, update stats. */
- unsigned char rx_error = rx_status >> 16;
-- if (vortex_debug > 2)
-+ if (vp->msg_level & NETIF_MSG_RX_ERR)
- printk(KERN_DEBUG " Rx error: status %2.2x.\n", rx_error);
- vp->stats.rx_errors++;
-- if (rx_error & 0x01) vp->stats.rx_over_errors++;
- if (rx_error & 0x02) vp->stats.rx_length_errors++;
-+ if (rx_error & 0x10) vp->stats.rx_length_errors++;
- if (rx_error & 0x04) vp->stats.rx_frame_errors++;
- if (rx_error & 0x08) vp->stats.rx_crc_errors++;
-- if (rx_error & 0x10) vp->stats.rx_length_errors++;
-+ if (rx_error & 0x01) {
-+ vp->stats.rx_over_errors++;
-+ if (vp->drv_flags & HAS_V2_TX) {
-+ int cur_rx_thresh = inb(ioaddr + RxPriorityThresh);
-+ if (cur_rx_thresh < 0x20)
-+ outb(cur_rx_thresh + 1, ioaddr + RxPriorityThresh);
-+ else
-+ printk(KERN_WARNING "%s: Excessive PCI latency causing"
-+ " packet corruption.\n", dev->name);
-+ }
-+ }
- } else {
- /* The packet length: up to 4.5K!. */
- int pkt_len = rx_status & 0x1fff;
- struct sk_buff *skb;
-
-- if (vortex_debug > 4)
-+ if (vp->msg_level & NETIF_MSG_RX_STATUS)
- printk(KERN_DEBUG "Receiving packet size %d status %4.4x.\n",
- pkt_len, rx_status);
-
- /* Check if the packet is long enough to just accept without
- copying to a properly sized skbuff. */
-- if (pkt_len < rx_copybreak
-+ if (pkt_len < vp->rx_copybreak
- && (skb = dev_alloc_skb(pkt_len + 2)) != 0) {
- skb->dev = dev;
- skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
- /* 'skb_put()' points to the start of sk_buff data area. */
- memcpy(skb_put(skb, pkt_len),
-- bus_to_virt(le32_to_cpu(vp->rx_ring[entry].addr)),
-- pkt_len);
-+ le32desc_to_virt(vp->rx_ring[entry].addr), pkt_len);
- rx_copy++;
- } else {
- void *temp;
-@@ -1829,7 +2107,7 @@
- vp->rx_skbuff[entry] = NULL;
- temp = skb_put(skb, pkt_len);
- /* Remove this checking code for final release. */
-- if (bus_to_virt(le32_to_cpu(vp->rx_ring[entry].addr)) != temp)
-+ if (le32desc_to_virt(vp->rx_ring[entry].addr) != temp)
- printk(KERN_ERR "%s: Warning -- the skbuff addresses do not match"
- " in boomerang_rx: %p vs. %p.\n", dev->name,
- bus_to_virt(le32_to_cpu(vp->rx_ring[entry].addr)),
-@@ -1849,20 +2127,23 @@
- netif_rx(skb);
- dev->last_rx = jiffies;
- vp->stats.rx_packets++;
-+#if LINUX_VERSION_CODE > 0x20127
-+ vp->stats.rx_bytes += pkt_len;
-+#endif
- }
- entry = (++vp->cur_rx) % RX_RING_SIZE;
- }
- /* Refill the Rx ring buffers. */
-- for (; vp->dirty_rx < vp->cur_rx; vp->dirty_rx++) {
-+ for (; vp->cur_rx - vp->dirty_rx > 0; vp->dirty_rx++) {
- struct sk_buff *skb;
- entry = vp->dirty_rx % RX_RING_SIZE;
- if (vp->rx_skbuff[entry] == NULL) {
-- skb = dev_alloc_skb(PKT_BUF_SZ);
-+ skb = dev_alloc_skb(vp->rx_buf_sz);
- if (skb == NULL)
- break; /* Bad news! */
- skb->dev = dev; /* Mark as being used by this device. */
- skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
-- vp->rx_ring[entry].addr = cpu_to_le32(virt_to_bus(skb->tail));
-+ vp->rx_ring[entry].addr = virt_to_le32desc(skb->tail);
- vp->rx_skbuff[entry] = skb;
- }
- vp->rx_ring[entry].status = 0; /* Clear complete bit. */
-@@ -1871,25 +2152,11 @@
- return 0;
- }
-
--static int
--vortex_close(struct device *dev)
-+static void
-+vortex_down(struct net_device *dev)
- {
- struct vortex_private *vp = (struct vortex_private *)dev->priv;
- long ioaddr = dev->base_addr;
-- int i;
--
-- dev->start = 0;
-- dev->tbusy = 1;
--
-- if (vortex_debug > 1) {
-- printk(KERN_DEBUG"%s: vortex_close() status %4.4x, Tx status %2.2x.\n",
-- dev->name, inw(ioaddr + EL3_STATUS), inb(ioaddr + TxStatus));
-- printk(KERN_DEBUG "%s: vortex close stats: rx_nocopy %d rx_copy %d"
-- " tx_queued %d Rx pre-checksummed %d.\n",
-- dev->name, rx_nocopy, rx_copy, queued_packet, rx_csumhits);
-- }
--
-- del_timer(&vp->timer);
-
- /* Turn off statistics ASAP. We update vp->stats below. */
- outw(StatsDisable, ioaddr + EL3_CMD);
-@@ -1902,44 +2169,66 @@
- /* Turn off thinnet power. Green! */
- outw(StopCoax, ioaddr + EL3_CMD);
-
-- free_irq(dev->irq, dev);
--
- outw(SetIntrEnb | 0x0000, ioaddr + EL3_CMD);
-
- update_stats(ioaddr, dev);
-- if (vp->full_bus_master_rx) { /* Free Boomerang bus master Rx buffers. */
-+ if (vp->full_bus_master_rx)
- outl(0, ioaddr + UpListPtr);
-+ if (vp->full_bus_master_tx)
-+ outl(0, ioaddr + DownListPtr);
-+}
-+
-+static int
-+vortex_close(struct net_device *dev)
-+{
-+ struct vortex_private *vp = (struct vortex_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+ int i;
-+
-+ netif_stop_tx_queue(dev);
-+
-+ if (vp->msg_level & NETIF_MSG_IFDOWN) {
-+ printk(KERN_DEBUG"%s: vortex_close() status %4.4x, Tx status %2.2x.\n",
-+ dev->name, inw(ioaddr + EL3_STATUS), inb(ioaddr + TxStatus));
-+ printk(KERN_DEBUG "%s: vortex close stats: rx_nocopy %d rx_copy %d"
-+ " tx_queued %d Rx pre-checksummed %d.\n",
-+ dev->name, rx_nocopy, rx_copy, queued_packet, rx_csumhits);
-+ }
-+
-+ del_timer(&vp->timer);
-+ vortex_down(dev);
-+ free_irq(dev->irq, dev);
-+ outw(TotalReset | 0x34, ioaddr + EL3_CMD);
-+
-+ if (vp->full_bus_master_rx) { /* Free Boomerang bus master Rx buffers. */
- for (i = 0; i < RX_RING_SIZE; i++)
- if (vp->rx_skbuff[i]) {
- #if LINUX_VERSION_CODE < 0x20100
- vp->rx_skbuff[i]->free = 1;
- #endif
-- DEV_FREE_SKB(vp->rx_skbuff[i]);
-+ dev_free_skb(vp->rx_skbuff[i]);
- vp->rx_skbuff[i] = 0;
- }
- }
- if (vp->full_bus_master_tx) { /* Free Boomerang bus master Tx buffers. */
-- outl(0, ioaddr + DownListPtr);
- for (i = 0; i < TX_RING_SIZE; i++)
- if (vp->tx_skbuff[i]) {
-- DEV_FREE_SKB(vp->tx_skbuff[i]);
-+ dev_free_skb(vp->tx_skbuff[i]);
- vp->tx_skbuff[i] = 0;
- }
- }
-
-- if (vp->capabilities & CapPwrMgmt)
-- acpi_set_WOL(dev);
- MOD_DEC_USE_COUNT;
-
- return 0;
- }
-
--static struct net_device_stats *vortex_get_stats(struct device *dev)
-+static struct net_device_stats *vortex_get_stats(struct net_device *dev)
- {
- struct vortex_private *vp = (struct vortex_private *)dev->priv;
- unsigned long flags;
-
-- if (dev->start) {
-+ if (netif_running(dev)) {
- save_flags(flags);
- cli();
- update_stats(dev->base_addr, dev);
-@@ -1955,7 +2244,7 @@
- table. This is done by checking that the ASM (!) code generated uses
- atomic updates with '+='.
- */
--static void update_stats(long ioaddr, struct device *dev)
-+static void update_stats(long ioaddr, struct net_device *dev)
- {
- struct vortex_private *vp = (struct vortex_private *)dev->priv;
- int old_window = inw(ioaddr + EL3_CMD);
-@@ -1978,8 +2267,8 @@
- /* Don't bother with register 9, an extension of registers 6&7.
- If we do use the 6&7 values the atomic update assumption above
- is invalid. */
-+ /* Rx Bytes is unreliable */ inw(ioaddr + 10);
- #if LINUX_VERSION_CODE > 0x020119
-- vp->stats.rx_bytes += inw(ioaddr + 10);
- vp->stats.tx_bytes += inw(ioaddr + 12);
- #else
- inw(ioaddr + 10);
-@@ -1994,49 +2283,151 @@
- return;
- }
-
--static int vortex_ioctl(struct device *dev, struct ifreq *rq, int cmd)
-+static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
- {
- struct vortex_private *vp = (struct vortex_private *)dev->priv;
- long ioaddr = dev->base_addr;
- u16 *data = (u16 *)&rq->ifr_data;
-- int phy = vp->phys[0] & 0x1f;
-+ u32 *data32 = (void *)&rq->ifr_data;
-+ int phy = vp->phys[0];
-
- switch(cmd) {
-- case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */
-+ case 0x8947: case 0x89F0:
-+ /* SIOCGMIIPHY: Get the address of the PHY in use. */
- data[0] = phy;
-- case SIOCDEVPRIVATE+1: /* Read the specified MII register. */
-+ /* Fall Through */
-+ case 0x8948: case 0x89F1:
-+ /* SIOCGMIIREG: Read the specified MII register. */
-+ if (data[0] == 32) { /* Emulate MII for 3c59*, 3c900. */
-+ data[3] = 0;
-+ switch (data[1]) {
-+ case 0:
-+ if (dev->if_port == XCVR_100baseTx) data[3] |= 0x2000;
-+ if (vp->full_duplex) data[3] |= 0x0100;
-+ break;
-+ case 1:
-+ if (vp->available_media & 0x02) data[3] |= 0x6000;
-+ if (vp->available_media & 0x08) data[3] |= 0x1800;
-+ spin_lock(&vp->window_lock);
-+ EL3WINDOW(4);
-+ if (inw(ioaddr + Wn4_Media) & Media_LnkBeat) data[3] |= 0x0004;
-+ spin_unlock(&vp->window_lock);
-+ break;
-+ case 2: data[3] = 0x0280; break; /* OUI 00:a0:24 */
-+ case 3: data[3] = 0x9000; break;
-+ default: break;
-+ }
-+ return 0;
-+ }
-+ spin_lock(&vp->window_lock);
- EL3WINDOW(4);
- data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f);
-+ spin_unlock(&vp->window_lock);
- return 0;
-- case SIOCDEVPRIVATE+2: /* Write the specified MII register */
-+ case 0x8949: case 0x89F2:
-+ /* SIOCSMIIREG: Write the specified MII register */
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
-+ if (data[0] == vp->phys[0]) {
-+ u16 value = data[2];
-+ if (vp->phys[0] == 32) {
-+ if (data[1] == 0) {
-+ vp->media_override = (value & 0x2000) ?
-+ XCVR_100baseTx : XCVR_10baseT;
-+ vp->full_duplex = (value & 0x0100) ? 1 : 0;
-+ vp->medialock = 1;
-+ }
-+ return 0;
-+ }
-+ switch (data[1]) {
-+ case 0:
-+ /* Check for autonegotiation on or reset. */
-+ vp->medialock = (value & 0x9000) ? 0 : 1;
-+ if (vp->medialock)
-+ vp->full_duplex = (value & 0x0100) ? 1 : 0;
-+ break;
-+ case 4: vp->advertising = value; break;
-+ }
-+ /* Perhaps check_duplex(dev), depending on chip semantics. */
-+ }
-+ spin_lock(&vp->window_lock);
- EL3WINDOW(4);
- mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]);
-+ spin_unlock(&vp->window_lock);
-+ return 0;
-+ case SIOCGPARAMS:
-+ data32[0] = vp->msg_level;
-+ data32[1] = vp->multicast_filter_limit;
-+ data32[2] = vp->max_interrupt_work;
-+ data32[3] = vp->rx_copybreak;
-+ return 0;
-+ case SIOCSPARAMS:
-+ if (!capable(CAP_NET_ADMIN))
-+ return -EPERM;
-+ vp->msg_level = data32[0];
-+ vp->multicast_filter_limit = data32[1];
-+ vp->max_interrupt_work = data32[2];
-+ vp->rx_copybreak = data32[3];
- return 0;
- default:
- return -EOPNOTSUPP;
- }
- }
-
-+static unsigned const ethernet_polynomial = 0x04c11db7U;
-+static inline u32 ether_crc(int length, unsigned char *data)
-+{
-+ int crc = -1;
-+
-+ while(--length >= 0) {
-+ unsigned char current_octet = *data++;
-+ int bit;
-+ for (bit = 0; bit < 8; bit++, current_octet >>= 1)
-+ crc = (crc << 1) ^
-+ ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
-+ }
-+ return crc;
-+}
-+
- /* Pre-Cyclone chips have no documented multicast filter, so the only
-- multicast setting is to receive all multicast frames. At least
-- the chip has a very clean way to set the mode, unlike many others. */
--static void set_rx_mode(struct device *dev)
-+ multicast setting is to receive all multicast frames. Cyclone and later
-+ chips have a write-only table of unknown size.
-+ At least the chip has a very clean way to set the other filter modes. */
-+static void set_rx_mode(struct net_device *dev)
- {
-+ struct vortex_private *vp = (void *)dev->priv;
- long ioaddr = dev->base_addr;
- int new_mode;
-
- if (dev->flags & IFF_PROMISC) {
-- if (vortex_debug > 0)
-- printk(KERN_NOTICE "%s: Setting promiscuous mode.\n", dev->name);
-+ /* Unconditionally log a net tap. */
-+ printk(KERN_NOTICE "%s: Setting promiscuous mode.\n", dev->name);
- new_mode = SetRxFilter|RxStation|RxMulticast|RxBroadcast|RxProm;
-- } else if ((dev->mc_list) || (dev->flags & IFF_ALLMULTI)) {
-+ } else if (dev->flags & IFF_ALLMULTI) {
-+ new_mode = SetRxFilter|RxStation|RxMulticast|RxBroadcast;
-+ } else if ((vp->drv_flags & HAS_V2_TX) &&
-+ dev->mc_count < vp->multicast_filter_limit) {
-+ struct dev_mc_list *mclist;
-+ int i;
-+ for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
-+ i++, mclist = mclist->next) {
-+ int filter_bit = ether_crc(ETH_ALEN, mclist->dmi_addr) & 0xff;
-+ if (test_bit(filter_bit, vp->mc_filter))
-+ continue;
-+ outw(SetFilterBit | 0x0400 | filter_bit, ioaddr + EL3_CMD);
-+ set_bit(filter_bit, vp->mc_filter);
-+ }
-+
-+ new_mode = SetRxFilter|RxStation|RxMulticastHash|RxBroadcast;
-+ } else if (dev->mc_count) {
- new_mode = SetRxFilter|RxStation|RxMulticast|RxBroadcast;
- } else
- new_mode = SetRxFilter | RxStation | RxBroadcast;
-
-- outw(new_mode, ioaddr + EL3_CMD);
-+ if (vp->rx_mode != new_mode) {
-+ vp->rx_mode = new_mode;
-+ outw(new_mode, ioaddr + EL3_CMD);
-+ }
- }
-
-
-@@ -2090,19 +2481,15 @@
- outw(dataval | MDIO_SHIFT_CLK, mdio_addr);
- mdio_delay();
- }
-- /* Read the two transition, 16 data, and wire-idle bits. */
-- for (i = 19; i > 0; i--) {
-+ /* Read the two transition and 16 data bits. */
-+ for (i = 18; i > 0; i--) {
- outw(MDIO_ENB_IN, mdio_addr);
- mdio_delay();
- retval = (retval << 1) | ((inw(mdio_addr) & MDIO_DATA_READ) ? 1 : 0);
- outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
- mdio_delay();
- }
--#if 0
-- return (retval>>1) & 0x1ffff;
--#else
-- return retval & 0x20000 ? 0xffff : retval>>1 & 0xffff;
--#endif
-+ return retval & 0x10000 ? 0xffff : retval & 0xffff;
- }
-
- static void mdio_write(long ioaddr, int phy_id, int location, int value)
-@@ -2123,19 +2510,15 @@
- mdio_delay();
- }
- /* Leave the interface idle. */
-- for (i = 1; i >= 0; i--) {
-- outw(MDIO_ENB_IN, mdio_addr);
-- mdio_delay();
-- outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
-- mdio_delay();
-- }
-+ mdio_sync(ioaddr, 32);
-
- return;
- }
-
-+#if ! defined(NO_PCI)
- /* ACPI: Advanced Configuration and Power Interface. */
- /* Set Wake-On-LAN mode and put the board into D3 (power-down) state. */
--static void acpi_set_WOL(struct device *dev)
-+static void acpi_set_WOL(struct net_device *dev)
- {
- struct vortex_private *vp = (struct vortex_private *)dev->priv;
- long ioaddr = dev->base_addr;
-@@ -2147,57 +2530,105 @@
- outw(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD);
- outw(RxEnable, ioaddr + EL3_CMD);
- /* Change the power state to D3; RxEnable doesn't take effect. */
-- pcibios_write_config_word(vp->pci_bus, vp->pci_devfn, 0xe0, 0x8103);
-+ pci_write_config_word(vp->pci_dev, 0xe0, 0x8103);
- }
--/* Change from D3 (sleep) to D0 (active).
-- Problem: The Cyclone forgets all PCI config info during the transition! */
--static void acpi_wake(int bus, int devfn)
--{
-- u32 base0, base1, romaddr;
-- u16 pci_command, pwr_command;
-- u8 pci_latency, pci_cacheline, irq;
-+#endif
-
-- pcibios_read_config_word(bus, devfn, 0xe0, &pwr_command);
-- if ((pwr_command & 3) == 0)
-- return;
-- pcibios_read_config_word( bus, devfn, PCI_COMMAND, &pci_command);
-- pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &base0);
-- pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_1, &base1);
-- pcibios_read_config_dword(bus, devfn, PCI_ROM_ADDRESS, &romaddr);
-- pcibios_read_config_byte( bus, devfn, PCI_LATENCY_TIMER, &pci_latency);
-- pcibios_read_config_byte( bus, devfn, PCI_CACHE_LINE_SIZE, &pci_cacheline);
-- pcibios_read_config_byte( bus, devfn, PCI_INTERRUPT_LINE, &irq);
--
-- pcibios_write_config_word( bus, devfn, 0xe0, 0x0000);
-- pcibios_write_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, base0);
-- pcibios_write_config_dword(bus, devfn, PCI_BASE_ADDRESS_1, base1);
-- pcibios_write_config_dword(bus, devfn, PCI_ROM_ADDRESS, romaddr);
-- pcibios_write_config_byte( bus, devfn, PCI_INTERRUPT_LINE, irq);
-- pcibios_write_config_byte( bus, devfn, PCI_LATENCY_TIMER, pci_latency);
-- pcibios_write_config_byte( bus, devfn, PCI_CACHE_LINE_SIZE, pci_cacheline);
-- pcibios_write_config_word( bus, devfn, PCI_COMMAND, pci_command | 5);
-+static int pwr_event(void *dev_instance, int event)
-+{
-+ struct net_device *dev = dev_instance;
-+ struct vortex_private *np = (struct vortex_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+
-+ if (np->msg_level & NETIF_MSG_LINK)
-+ printk(KERN_DEBUG "%s: Handling power event %d.\n", dev->name, event);
-+ switch(event) {
-+ case DRV_ATTACH:
-+ MOD_INC_USE_COUNT;
-+ break;
-+ case DRV_SUSPEND:
-+ vortex_down(dev);
-+ netif_stop_tx_queue(dev);
-+ if (np->capabilities & CapPwrMgmt)
-+ acpi_set_WOL(dev);
-+ break;
-+ case DRV_RESUME:
-+ /* This is incomplete: the actions are very chip specific. */
-+ activate_xcvr(dev);
-+ set_media_type(dev);
-+ start_operation(dev);
-+ np->rx_mode = 0;
-+ set_rx_mode(dev);
-+ start_operation1(dev);
-+ break;
-+ case DRV_DETACH: {
-+ struct net_device **devp, **next;
-+ if (dev->flags & IFF_UP) {
-+ dev_close(dev);
-+ dev->flags &= ~(IFF_UP|IFF_RUNNING);
-+ }
-+ unregister_netdev(dev);
-+ release_region(dev->base_addr, pci_tbl[np->chip_id].io_size);
-+#ifndef USE_IO_OPS
-+ iounmap((char *)dev->base_addr);
-+#endif
-+ for (devp = &root_vortex_dev; *devp; devp = next) {
-+ next = &((struct vortex_private *)(*devp)->priv)->next_module;
-+ if (*devp == dev) {
-+ *devp = *next;
-+ break;
-+ }
-+ }
-+ if (np->priv_addr)
-+ kfree(np->priv_addr);
-+ kfree(dev);
-+ MOD_DEC_USE_COUNT;
-+ break;
-+ }
-+ case DRV_PWR_WakeOn:
-+ if ( ! (np->capabilities & CapPwrMgmt))
-+ return -1;
-+ EL3WINDOW(7);
-+ /* Power up on: 1=Downloaded Filter, 2=Magic Packets, 4=Link Status.*/
-+ outw(2, ioaddr + 12);
-+ /* This RxEnable doesn't take effect if we immediately change to D3. */
-+ outw(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD);
-+ outw(RxEnable, ioaddr + EL3_CMD);
-+ acpi_set_pwr_state(np->pci_dev, ACPI_D3);
-+ break;
-+ }
-+ return 0;
- }
-
-
- #ifdef MODULE
- void cleanup_module(void)
- {
-- struct device *next_dev;
-+ struct net_device *next_dev;
-
- #ifdef CARDBUS
- unregister_driver(&vortex_ops);
-+#elif ! defined(NO_PCI)
-+ pci_drv_unregister(&vortex_drv_id);
- #endif
-
- /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
- while (root_vortex_dev) {
- struct vortex_private *vp=(void *)(root_vortex_dev->priv);
-- next_dev = vp->next_module;
- unregister_netdev(root_vortex_dev);
-- outw(TotalReset, root_vortex_dev->base_addr + EL3_CMD);
-+ outw(TotalReset | 0x14, root_vortex_dev->base_addr + EL3_CMD);
-+ if (vp->capabilities & CapPwrMgmt)
-+ acpi_set_WOL(root_vortex_dev);
-+#ifdef USE_MEM_OPS
-+ iounmap((char *)root_vortex_dev->base_addr);
-+#else
- release_region(root_vortex_dev->base_addr,
- pci_tbl[vp->chip_id].io_size);
-+#endif
-+ next_dev = vp->next_module;
-+ if (vp->priv_addr)
-+ kfree(vp->priv_addr);
- kfree(root_vortex_dev);
-- kfree(vp->priv_addr);
- root_vortex_dev = next_dev;
- }
- }
-@@ -2206,9 +2637,10 @@
-
- /*
- * Local variables:
-- * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
-- * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c"
-- * cardbus-compile-command: "gcc -DCARDBUS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c -o 3c575_cb.o -I/usr/src/linux/pcmcia-cs-3.0.9/include/"
-+ * compile-command: "make KERNVER=`uname -r` 3c59x.o"
-+ * compile-cmd: "gcc -DMODULE -Wall -Wstrict-prototypes -O6 -c 3c59x.c"
-+ * cardbus-compile-command: "gcc -DCARDBUS -DMODULE -Wall -Wstrict-prototypes -O6 -c 3c59x.c -o 3c575_cb.o -I/usr/src/pcmcia/include/"
-+ * eisa-only-compile: "gcc -DNO_PCI -DMODULE -O6 -c 3c59x.c -o 3c597.o"
- * c-indent-level: 4
- * c-basic-offset: 4
- * tab-width: 4
-Index: linux/src/drivers/net/cb_shim.c
-===================================================================
-RCS file: linux/src/drivers/net/cb_shim.c
-diff -N linux/src/drivers/net/cb_shim.c
---- /dev/null 1 Jan 1970 00:00:00 -0000
-+++ linux/src/drivers/net/cb_shim.c 20 Aug 2004 10:32:53 -0000
-@@ -0,0 +1,296 @@
-+/* cb_shim.c: Linux CardBus device support code. */
-+/*
-+ Written 1999-2002 by Donald Becker.
-+
-+ This software may be used and distributed according to the terms of
-+ the GNU General Public License (GPL), incorporated herein by
-+ reference. This is not a documented interface. Drivers incorporating
-+ or interacting with these functions are derivative works and thus
-+ are covered the GPL. They must include an explicit GPL notice.
-+
-+ This code provides a shim to allow newer drivers to interact with the
-+ older Cardbus driver activation code. The functions supported are
-+ attach, suspend, power-off, resume and eject.
-+
-+ The author may be reached as becker@scyld.com, or
-+ Donald Becker
-+ Scyld Computing Corporation
-+ 410 Severn Ave., Suite 210
-+ Annapolis MD 21403
-+
-+ Support and updates available at
-+ http://www.scyld.com/network/drivers.html
-+
-+ Other contributers: (none yet)
-+*/
-+
-+static const char version1[] =
-+"cb_shim.c:v1.03 7/12/2002 Donald Becker <becker@scyld.com>\n";
-+static const char version2[] =
-+" http://www.scyld.com/linux/drivers.html\n";
-+
-+/* Module options. */
-+static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */
-+
-+#ifndef __KERNEL__
-+#define __KERNEL__
-+#endif
-+#include <linux/config.h>
-+#if defined(CONFIG_SMP) && ! defined(__SMP__)
-+#define __SMP__
-+#endif
-+#if defined(CONFIG_MODVERSIONS) && ! defined(MODVERSIONS)
-+#define MODVERSIONS
-+#endif
-+
-+#include <linux/version.h>
-+#if defined(MODVERSIONS)
-+#include <linux/modversions.h>
-+#endif
-+#include <linux/module.h>
-+
-+#include <linux/kernel.h>
-+#if LINUX_VERSION_CODE >= 0x20400
-+#include <linux/slab.h>
-+#else
-+#include <linux/malloc.h>
-+#endif
-+#include <linux/netdevice.h>
-+#include <linux/pci.h>
-+#include <asm/io.h>
-+
-+/* These might be awkward to locate. */
-+#include <pcmcia/driver_ops.h>
-+#include "pci-scan.h"
-+#include "kern_compat.h"
-+
-+MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
-+MODULE_DESCRIPTION("Hot-swap-PCI and Cardbus event dispatch");
-+MODULE_LICENSE("GPL");
-+MODULE_PARM(debug, "i");
-+MODULE_PARM_DESC(debug, "Enable additional status messages (0-7)");
-+
-+/* Note: this is used in a slightly sleazy manner: it is passed to routines
-+ that expect and return just dev_node_t. However using the too-simple
-+ dev_node_t complicates devices management -- older drivers had to
-+ look up dev_node_t.name in their private list. */
-+
-+struct registered_pci_device {
-+ struct dev_node_t node;
-+ int magic;
-+ struct registered_pci_device *next;
-+ struct drv_id_info *drv_info;
-+ struct pci_dev *pci_loc;
-+ void *dev_instance;
-+} static *root_pci_devs = 0;
-+
-+struct drv_shim {
-+ struct drv_id_info *did;
-+ struct driver_operations drv_ops;
-+ int magic;
-+ struct drv_shim *next;
-+} static *root_drv_id = 0;
-+
-+static void drv_power_op(struct dev_node_t *node, enum drv_pwr_action action)
-+{
-+ struct registered_pci_device **devp, **next, *rpin = (void *)node, *rp;
-+ if (debug > 1)
-+ printk(KERN_DEBUG "power operation(%s, %d).\n",
-+ rpin->drv_info->name, action);
-+ /* With our wrapper structure we can almost do
-+ rpin->drv_info->pwr_event(rpin->dev_instance, action);
-+ But the detach operation requires us to remove the object from the
-+ list, so we check for uncontrolled "ghost" devices. */
-+ for (devp = &root_pci_devs; *devp; devp = next) {
-+ rp = *devp;
-+ next = &rp->next;
-+ if (rp == rpin) {
-+ if (rp->drv_info->pwr_event)
-+ rp->drv_info->pwr_event((*devp)->dev_instance, action);
-+ else
-+ printk(KERN_ERR "No power event hander for driver %s.\n",
-+ rpin->drv_info->name);
-+ if (action == DRV_DETACH) {
-+ kfree(rp);
-+ *devp = *next;
-+ MOD_DEC_USE_COUNT;
-+ }
-+ return;
-+ }
-+ }
-+ if (debug)
-+ printk(KERN_WARNING "power operation(%s, %d) for a ghost device.\n",
-+ node->dev_name, action);
-+}
-+/* Wrappers / static lambdas. */
-+static void drv_suspend(struct dev_node_t *node)
-+{
-+ drv_power_op(node, DRV_SUSPEND);
-+}
-+static void drv_resume(struct dev_node_t *node)
-+{
-+ drv_power_op(node, DRV_RESUME);
-+}
-+static void drv_detach(struct dev_node_t *node)
-+{
-+ drv_power_op(node, DRV_DETACH);
-+}
-+
-+/* The CardBus interaction does not identify the driver the attach() is
-+ for, thus we must search for the ID in all PCI device tables.
-+ While ugly, we likely only have one driver loaded anyway.
-+*/
-+static dev_node_t *drv_attach(struct dev_locator_t *loc)
-+{
-+ struct drv_shim *dp;
-+ struct drv_id_info *drv_id = NULL;
-+ struct pci_id_info *pci_tbl = NULL;
-+ u32 pci_id, subsys_id, pci_rev, pciaddr;
-+ u8 irq;
-+ int chip_idx = 0, pci_flags, bus, devfn;
-+ long ioaddr;
-+ void *newdev;
-+
-+ if (debug > 1)
-+ printk(KERN_INFO "drv_attach()\n");
-+ if (loc->bus != LOC_PCI) return NULL;
-+ bus = loc->b.pci.bus; devfn = loc->b.pci.devfn;
-+ if (debug > 1)
-+ printk(KERN_DEBUG "drv_attach(bus %d, function %d)\n", bus, devfn);
-+
-+ pcibios_read_config_dword(bus, devfn, PCI_VENDOR_ID, &pci_id);
-+ pcibios_read_config_dword(bus, devfn, PCI_SUBSYSTEM_ID, &subsys_id);
-+ pcibios_read_config_dword(bus, devfn, PCI_REVISION_ID, &pci_rev);
-+ pcibios_read_config_byte(bus, devfn, PCI_INTERRUPT_LINE, &irq);
-+ for (dp = root_drv_id; dp; dp = dp->next) {
-+ drv_id = dp->did;
-+ pci_tbl = drv_id->pci_dev_tbl;
-+ for (chip_idx = 0; pci_tbl[chip_idx].name; chip_idx++) {
-+ struct pci_id_info *chip = &pci_tbl[chip_idx];
-+ if ((pci_id & chip->id.pci_mask) == chip->id.pci
-+ && (subsys_id & chip->id.subsystem_mask) == chip->id.subsystem
-+ && (pci_rev & chip->id.revision_mask) == chip->id.revision)
-+ break;
-+ }
-+ if (pci_tbl[chip_idx].name) /* Compiled out! */
-+ break;
-+ }
-+ if (dp == 0) {
-+ printk(KERN_WARNING "No driver match for device %8.8x at %d/%d.\n",
-+ pci_id, bus, devfn);
-+ return 0;
-+ }
-+ pci_flags = pci_tbl[chip_idx].pci_flags;
-+ pcibios_read_config_dword(bus, devfn, ((pci_flags >> 2) & 0x1C) + 0x10,
-+ &pciaddr);
-+ if ((pciaddr & PCI_BASE_ADDRESS_SPACE_IO)) {
-+ ioaddr = pciaddr & PCI_BASE_ADDRESS_IO_MASK;
-+ } else
-+ ioaddr = (long)ioremap(pciaddr & PCI_BASE_ADDRESS_MEM_MASK,
-+ pci_tbl[chip_idx].io_size);
-+ if (ioaddr == 0 || irq == 0) {
-+ printk(KERN_ERR "The %s at %d/%d was not assigned an %s.\n"
-+ KERN_ERR " It will not be activated.\n",
-+ pci_tbl[chip_idx].name, bus, devfn,
-+ ioaddr == 0 ? "address" : "IRQ");
-+ return NULL;
-+ }
-+ printk(KERN_INFO "Found a %s at %d/%d address 0x%x->0x%lx IRQ %d.\n",
-+ pci_tbl[chip_idx].name, bus, devfn, pciaddr, ioaddr, irq);
-+ {
-+ u16 pci_command;
-+ pcibios_read_config_word(bus, devfn, PCI_COMMAND, &pci_command);
-+ printk(KERN_INFO "%s at %d/%d command 0x%x.\n",
-+ pci_tbl[chip_idx].name, bus, devfn, pci_command);
-+ }
-+
-+ newdev = drv_id->probe1(pci_find_slot(bus, devfn), 0,
-+ ioaddr, irq, chip_idx, 0);
-+ if (newdev) {
-+ struct registered_pci_device *hsdev =
-+ kmalloc(sizeof(struct registered_pci_device), GFP_KERNEL);
-+ if (drv_id->pci_class == PCI_CLASS_NETWORK_ETHERNET<<8)
-+ strcpy(hsdev->node.dev_name, ((struct net_device *)newdev)->name);
-+ hsdev->node.major = hsdev->node.minor = 0;
-+ hsdev->node.next = NULL;
-+ hsdev->drv_info = drv_id;
-+ hsdev->dev_instance = newdev;
-+ hsdev->next = root_pci_devs;
-+ root_pci_devs = hsdev;
-+ drv_id->pwr_event(newdev, DRV_ATTACH);
-+ MOD_INC_USE_COUNT;
-+ return &hsdev->node;
-+ }
-+ return NULL;
-+}
-+
-+/* Add/remove a driver ID structure to our private list of known drivers. */
-+int do_cb_register(struct drv_id_info *did)
-+{
-+ struct driver_operations *dop;
-+ struct drv_shim *dshim = kmalloc(sizeof(*dshim), GFP_KERNEL);
-+ if (dshim == 0)
-+ return 0;
-+ if (debug > 1)
-+ printk(KERN_INFO "Registering driver support for '%s'.\n",
-+ did->name);
-+ MOD_INC_USE_COUNT;
-+ dshim->did = did;
-+ dop = &dshim->drv_ops;
-+ dop->name = (char *)did->name;
-+ dop->attach = drv_attach;
-+ dop->suspend = drv_suspend;
-+ dop->resume = drv_resume;
-+ dop->detach = drv_detach;
-+ dshim->next = root_drv_id;
-+ root_drv_id = dshim;
-+ return register_driver(dop);
-+}
-+
-+void do_cb_unregister(struct drv_id_info *did)
-+{
-+ struct drv_shim **dp;
-+ for (dp = &root_drv_id; *dp; dp = &(*dp)->next)
-+ if ((*dp)->did == did) {
-+ struct drv_shim *dshim = *dp;
-+ unregister_driver(&dshim->drv_ops);
-+ *dp = dshim->next;
-+ kfree(dshim);
-+ MOD_DEC_USE_COUNT;
-+ return;
-+ }
-+}
-+
-+extern int (*register_hotswap_hook)(struct drv_id_info *did);
-+extern void (*unregister_hotswap_hook)(struct drv_id_info *did);
-+
-+int (*old_cb_hook)(struct drv_id_info *did);
-+void (*old_un_cb_hook)(struct drv_id_info *did);
-+
-+int init_module(void)
-+{
-+ if (debug)
-+ printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2);
-+ old_cb_hook = register_hotswap_hook;
-+ old_un_cb_hook = unregister_hotswap_hook;
-+ register_hotswap_hook = do_cb_register;
-+ unregister_hotswap_hook = do_cb_unregister;
-+ return 0;
-+}
-+void cleanup_module(void)
-+{
-+ register_hotswap_hook = old_cb_hook;
-+ unregister_hotswap_hook = old_un_cb_hook;
-+ return;
-+}
-+
-+
-+/*
-+ * Local variables:
-+ * compile-command: "gcc -DMODULE -Wall -Wstrict-prototypes -O6 -c cb_shim.c -I/usr/include/ -I/usr/src/pcmcia/include/"
-+ * c-indent-level: 4
-+ * c-basic-offset: 4
-+ * tab-width: 4
-+ * End:
-+ */
-+
-Index: linux/src/drivers/net/eepro100.c
-===================================================================
-RCS file: /cvsroot/hurd/gnumach/linux/src/drivers/net/Attic/eepro100.c,v
-retrieving revision 1.2
-diff -u -r1.2 eepro100.c
---- linux/src/drivers/net/eepro100.c 18 Aug 2001 00:56:42 -0000 1.2
-+++ linux/src/drivers/net/eepro100.c 10 Nov 2005 00:43:18 -0000
-@@ -1,146 +1,166 @@
- /* drivers/net/eepro100.c: An Intel i82557-559 Ethernet driver for Linux. */
- /*
-- NOTICE: this version of the driver is supposed to work with 2.2 kernels.
-- Written 1996-1999 by Donald Becker.
-+ Written 1998-2003 by Donald Becker.
-
-- This software may be used and distributed according to the terms
-- of the GNU Public License, incorporated herein by reference.
-+ This software may be used and distributed according to the terms of
-+ the GNU General Public License (GPL), incorporated herein by reference.
-+ Drivers based on or derived from this code fall under the GPL and must
-+ retain the authorship, copyright and license notice. This driver is not
-+ a complete program and may only be used when the entire operating
-+ system is licensed under the GPL.
-
- This driver is for the Intel EtherExpress Pro100 (Speedo3) design.
- It should work with all i82557/558/559 boards.
-
- To use as a module, use the compile-command at the end of the file.
-
-- The author may be reached as becker@CESDIS.usra.edu, or C/O
-- Center of Excellence in Space Data and Information Sciences
-- Code 930.5, NASA Goddard Space Flight Center, Greenbelt MD 20771
-+ The author may be reached as becker@scyld.com, or C/O
-+ Scyld Computing Corporation
-+ 914 Bay Ridge Road, Suite 220
-+ Annapolis MD 21403
-+
- For updates see
-- http://cesdis.gsfc.nasa.gov/linux/drivers/eepro100.html
-+ http://www.scyld.com/network/eepro100.html
- For installation instructions
-- http://cesdis.gsfc.nasa.gov/linux/misc/modules.html
-- There is a Majordomo mailing list based at
-- linux-eepro100@cesdis.gsfc.nasa.gov
--
-- The driver also contains updates by different kernel developers.
-- This driver clone is maintained by Andrey V. Savochkin <saw@saw.sw.com.sg>.
-- Please use this email address and linux-kernel mailing list for bug reports.
--
-- Modification history:
-- 2000 Mar 24 Dragan Stancevic <visitor@valinux.com>
-- Disabled FC and ER, to avoid lockups when when we get FCP interrupts.
-- 2000 May 27 Andrey Moruga <moruga@sw.com.sg>
-- Code duplication for 82559ER support was removed.
-- Accurate handling of all supported chips was implemented.
-- Some fixes in 2.3 clone of the driver were ported.
-- 2000 May 30 Dragan Stancevic <visitor@valinux.com> and
-- Andrey Moruga <moruga@sw.com.sg>
-- Honor PortReset timing specification.
-- 2000 Jul 25 Dragan Stancevic <visitor@valinux.com>
-- Changed to MMIO, resized FIFOs, resized rings, changed ISR timeout
-- Problem reported by:
-- Marc MERLIN <merlin@valinux.com>
-- 2000 Nov 15 Dragan Stancevic <visitor@valinux.com>
-- Changed command completion time and added debug info as to which
-- CMD timed out. Problem reported by:
-- "Ulrich Windl" <Ulrich.Windl@rz.uni-regensburg.de>
-+ http://www.scyld.com/network/modules.html
-+ The information and support mailing lists are based at
-+ http://www.scyld.com/mailman/listinfo/
- */
-
--/*#define USE_IO*/
--static const char *version =
--"eepro100.c:v1.09j-t 9/29/99 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/eepro100.html\n"
--"eepro100.c: $Revision: 1.2 $ 2000/05/31 Modified by Andrey V. Savochkin <saw@saw.sw.com.sg> and others\n"
--"eepro100.c: VA Linux custom, Dragan Stancevic <visitor@valinux.com> 2000/11/15\n";
-+/* These identify the driver base version and may not be removed. */
-+static const char version1[] =
-+"eepro100.c:v1.28 7/22/2003 Donald Becker <becker@scyld.com>\n";
-+static const char version2[] =
-+" http://www.scyld.com/network/eepro100.html\n";
-+
-+
-+/* The user-configurable values.
-+ These may be modified when a driver module is loaded.
-+ The first five are undocumented and spelled per Intel recommendations.
-+*/
-
--/* A few user-configurable values that apply to all boards.
-- First set is undocumented and spelled per Intel recommendations. */
-+/* Message enable level: 0..31 = no..all messages. See NETIF_MSG docs. */
-+static int debug = 2;
-
- static int congenb = 0; /* Enable congestion control in the DP83840. */
--static int txfifo = 0; /* Tx FIFO threshold in 4 byte units, 0-15 */
--static int rxfifo = 0xF; /* Rx FIFO threshold, default 32 bytes. */
-+static int txfifo = 8; /* Tx FIFO threshold in 4 byte units, 0-15 */
-+static int rxfifo = 8; /* Rx FIFO threshold, default 32 bytes. */
- /* Tx/Rx DMA burst length, 0-127, 0 == no preemption, tx==128 -> disabled. */
- static int txdmacount = 128;
- static int rxdmacount = 0;
-
--/* Set the copy breakpoint for the copy-only-tiny-buffer Rx method.
-- Lower values use more memory, but are faster. */
--#if defined(__alpha__) || defined(__sparc__)
--/* force copying of all packets to avoid unaligned accesses on Alpha */
--static int rx_copybreak = 1518;
--#else
-+/* Set the copy breakpoint for the copy-only-tiny-frame Rx method.
-+ Lower values use more memory, but are faster.
-+ Setting to > 1518 disables this feature. */
- static int rx_copybreak = 200;
--#endif
-
- /* Maximum events (Rx packets, etc.) to handle at each interrupt. */
--static int max_interrupt_work = 200;
-+static int max_interrupt_work = 20;
-
- /* Maximum number of multicast addresses to filter (vs. rx-all-multicast) */
- static int multicast_filter_limit = 64;
-
--/* 'options' is used to pass a transceiver override or full-duplex flag
-- e.g. "options=16" for FD, "options=32" for 100mbps-only. */
--static int full_duplex[] = {-1, -1, -1, -1, -1, -1, -1, -1};
--static int options[] = {-1, -1, -1, -1, -1, -1, -1, -1};
--#ifdef MODULE
--static int debug = -1; /* The debug level */
--#endif
-+/* Used to pass the media type, etc.
-+ Both 'options[]' and 'full_duplex[]' should exist for driver
-+ interoperability, however setting full_duplex[] is deprecated.
-+ The media type is usually passed in 'options[]'.
-+ Use option values 0x10/0x20 for 10Mbps, 0x100,0x200 for 100Mbps.
-+ Use option values 0x10 and 0x100 for forcing half duplex fixed speed.
-+ Use option values 0x20 and 0x200 for forcing full duplex operation.
-+*/
-+#define MAX_UNITS 8 /* More are supported, limit only on options */
-+static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-+static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-+
-+/* Operational parameters that are set at compile time. */
-
--/* A few values that may be tweaked. */
- /* The ring sizes should be a power of two for efficiency. */
--#define TX_RING_SIZE 64
--#define RX_RING_SIZE 64
--/* How much slots multicast filter setup may take.
-- Do not descrease without changing set_rx_mode() implementaion. */
--#define TX_MULTICAST_SIZE 2
--#define TX_MULTICAST_RESERV (TX_MULTICAST_SIZE*2)
--/* Actual number of TX packets queued, must be
-- <= TX_RING_SIZE-TX_MULTICAST_RESERV. */
--#define TX_QUEUE_LIMIT (TX_RING_SIZE-TX_MULTICAST_RESERV)
--/* Hysteresis marking queue as no longer full. */
--#define TX_QUEUE_UNFULL (TX_QUEUE_LIMIT-4)
-+#define TX_RING_SIZE 32 /* Effectively 2 entries fewer. */
-+#define RX_RING_SIZE 32
-+/* Actual number of TX packets queued, must be <= TX_RING_SIZE-2. */
-+#define TX_QUEUE_LIMIT 12
-+#define TX_QUEUE_UNFULL 8 /* Hysteresis marking queue as no longer full. */
-
- /* Operational parameters that usually are not changed. */
-
- /* Time in jiffies before concluding the transmitter is hung. */
--#define TX_TIMEOUT (2*HZ)
--/* Size of an pre-allocated Rx buffer: <Ethernet MTU> + slack.*/
-+#define TX_TIMEOUT (6*HZ)
-+
-+/* Allocation size of Rx buffers with normal sized Ethernet frames.
-+ Do not change this value without good reason. This is not a limit,
-+ but a way to keep a consistent allocation size among drivers.
-+ */
- #define PKT_BUF_SZ 1536
-
--#if !defined(__OPTIMIZE__) || !defined(__KERNEL__)
-+#ifndef __KERNEL__
-+#define __KERNEL__
-+#endif
-+#if !defined(__OPTIMIZE__)
- #warning You must compile this file with the correct options!
- #warning See the last lines of the source file.
- #error You must compile this driver with "-O".
- #endif
-
-+#include <linux/config.h>
-+#if defined(CONFIG_SMP) && ! defined(__SMP__)
-+#define __SMP__
-+#endif
-+#if defined(MODULE) && defined(CONFIG_MODVERSIONS) && ! defined(MODVERSIONS)
-+#define MODVERSIONS
-+#endif
-+
- #include <linux/version.h>
--#include <linux/module.h>
- #if defined(MODVERSIONS)
- #include <linux/modversions.h>
- #endif
-+#include <linux/module.h>
-
- #include <linux/kernel.h>
- #include <linux/string.h>
- #include <linux/timer.h>
- #include <linux/errno.h>
- #include <linux/ioport.h>
-+#if LINUX_VERSION_CODE >= 0x20400
-+#include <linux/slab.h>
-+#else
- #include <linux/malloc.h>
-+#endif
- #include <linux/interrupt.h>
- #include <linux/pci.h>
--#include <asm/spinlock.h>
--
--#include <asm/bitops.h>
--#include <asm/io.h>
--
- #include <linux/netdevice.h>
- #include <linux/etherdevice.h>
- #include <linux/skbuff.h>
- #include <linux/delay.h>
-+#include <asm/bitops.h>
-+#include <asm/io.h>
-+
-+#if LINUX_VERSION_CODE >= 0x20300
-+#include <linux/spinlock.h>
-+#elif LINUX_VERSION_CODE >= 0x20200
-+#include <asm/spinlock.h>
-+#endif
-+
-+#ifdef INLINE_PCISCAN
-+#include "k_compat.h"
-+#else
-+#include "pci-scan.h"
-+#include "kern_compat.h"
-+#endif
-+
-+/* Condensed bus+endian portability operations. */
-+#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr))
-+#define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr))
-+
-+#if (LINUX_VERSION_CODE >= 0x20100) && defined(MODULE)
-+char kernel_version[] = UTS_RELEASE;
-+#endif
-
--#if defined(MODULE)
--MODULE_AUTHOR("Maintainer: Andrey V. Savochkin <saw@saw.sw.com.sg>");
--MODULE_DESCRIPTION("Intel i82557/i82558 PCI EtherExpressPro driver");
-+MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
-+MODULE_DESCRIPTION("Intel PCI EtherExpressPro 100 driver");
-+MODULE_LICENSE("GPL");
- MODULE_PARM(debug, "i");
--MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
--MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
-+MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
-+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
- MODULE_PARM(congenb, "i");
- MODULE_PARM(txfifo, "i");
- MODULE_PARM(rxfifo, "i");
-@@ -149,42 +169,21 @@
- MODULE_PARM(rx_copybreak, "i");
- MODULE_PARM(max_interrupt_work, "i");
- MODULE_PARM(multicast_filter_limit, "i");
-+#ifdef MODULE_PARM_DESC
-+MODULE_PARM_DESC(debug, "EEPro100 message level (0-31)");
-+MODULE_PARM_DESC(options,
-+ "EEPro100: force fixed speed+duplex 0x10 0x20 0x100 0x200");
-+MODULE_PARM_DESC(max_interrupt_work,
-+ "EEPro100 maximum events handled per interrupt");
-+MODULE_PARM_DESC(full_duplex, "EEPro100 set to forced full duplex when not 0"
-+ " (deprecated)");
-+MODULE_PARM_DESC(rx_copybreak,
-+ "EEPro100 copy breakpoint for copy-only-tiny-frames");
-+MODULE_PARM_DESC(multicast_filter_limit,
-+ "EEPro100 breakpoint for switching to Rx-all-multicast");
-+/* Other settings are undocumented per Intel recommendation. */
- #endif
-
--#define RUN_AT(x) (jiffies + (x))
--/* Condensed bus+endian portability operations. */
--#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr))
--#define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr))
--
--#define net_device device
--#define pci_base_address(p, n) (p)->base_address[n]
--
--#define dev_free_skb(skb) dev_kfree_skb(skb);
--#define netif_wake_queue(dev) do { \
-- clear_bit(0, (void*)&dev->tbusy); \
-- mark_bh(NET_BH); \
-- } while(0)
--#define netif_start_queue(dev) clear_bit(0, (void*)&dev->tbusy)
--#define netif_stop_queue(dev) set_bit(0, (void*)&dev->tbusy)
--#ifndef PCI_DEVICE_ID_INTEL_82559ER
--#define PCI_DEVICE_ID_INTEL_82559ER 0x1209
--#endif
--#ifndef PCI_DEVICE_ID_INTEL_ID1029
--#define PCI_DEVICE_ID_INTEL_ID1029 0x1029
--#endif
--#ifndef PCI_DEVICE_ID_INTEL_ID1030
--#define PCI_DEVICE_ID_INTEL_ID1030 0x1030
--#endif
--#ifndef PCI_DEVICE_ID_INTEL_ID2449
--#define PCI_DEVICE_ID_INTEL_ID2449 0x2449
--#endif
--
--/* The total I/O port extent of the board.
-- The registers beyond 0x18 only exist on the i82558. */
--#define SPEEDO3_TOTAL_SIZE 0x20
--
--int speedo_debug = 1;
--
- /*
- Theory of Operation
-
-@@ -234,7 +233,7 @@
- (TxBD). A fixed ring of these TxCB+TxBD pairs are kept as part of the
- speedo_private data structure for each adapter instance.
-
--The newer i82558 explicitly supports this structure, and can read the two
-+The i82558 and later explicitly supports this structure, and can read the two
- TxBDs in the same PCI burst as the TxCB.
-
- This ring structure is used for all normal transmit packets, but the
-@@ -245,7 +244,7 @@
- that descriptor's link to the complex command.
-
- An additional complexity of these non-transmit commands are that they may be
--added asynchronous to the normal transmit queue, so we disable interrupts
-+added asynchronous to the normal transmit queue, so we set a lock
- whenever the Tx descriptor ring is manipulated.
-
- A notable aspect of these special configure commands is that they do
-@@ -257,27 +256,16 @@
- tx_skbuff[] entry is always empty for config_cmd and mc_setup frames.
-
- Commands may have bits set e.g. CmdSuspend in the command word to either
--suspend or stop the transmit/command unit. This driver always flags the last
--command with CmdSuspend, erases the CmdSuspend in the previous command, and
--then issues a CU_RESUME.
--Note: Watch out for the potential race condition here: imagine
-- erasing the previous suspend
-- the chip processes the previous command
-- the chip processes the final command, and suspends
-- doing the CU_RESUME
-- the chip processes the next-yet-valid post-final-command.
--So blindly sending a CU_RESUME is only safe if we do it immediately after
--after erasing the previous CmdSuspend, without the possibility of an
--intervening delay. Thus the resume command is always within the
--interrupts-disabled region. This is a timing dependence, but handling this
--condition in a timing-independent way would considerably complicate the code.
-+suspend or stop the transmit/command unit. This driver always initializes
-+the current command with CmdSuspend before erasing the CmdSuspend in the
-+previous command, and only then issues a CU_RESUME.
-
- Note: In previous generation Intel chips, restarting the command unit was a
- notoriously slow process. This is presumably no longer true.
-
- IIIC. Receive structure
-
--Because of the bus-master support on the Speedo3 this driver uses the new
-+Because of the bus-master support on the Speedo3 this driver uses the
- SKBUFF_RX_COPYBREAK scheme, rather than a fixed intermediate receive buffer.
- This scheme allocates full-sized skbuffs as receive buffers. The value
- SKBUFF_RX_COPYBREAK is used as the copying breakpoint: it is chosen to
-@@ -291,6 +279,24 @@
- is non-trivial, and the larger copy might flush the cache of useful data, so
- we pass up the skbuff the packet was received into.
-
-+IIID. Synchronization
-+The driver runs as two independent, single-threaded flows of control. One
-+is the send-packet routine, which enforces single-threaded use by the
-+dev->tbusy flag. The other thread is the interrupt handler, which is single
-+threaded by the hardware and other software.
-+
-+The send packet thread has partial control over the Tx ring and 'dev->tbusy'
-+flag. It sets the tbusy flag whenever it's queuing a Tx packet. If the next
-+queue slot is empty, it clears the tbusy flag when finished otherwise it sets
-+the 'sp->tx_full' flag.
-+
-+The interrupt handler has exclusive control over the Rx ring and records stats
-+from the Tx ring. (The Tx-done interrupt can't be selectively turned off, so
-+we can't avoid the interrupt overhead by having the Tx routine reap the Tx
-+stats.) After reaping the stats, it marks the queue entry as empty by setting
-+the 'base' to zero. Iff the 'sp->tx_full' flag is set, it clears both the
-+tx_full and tbusy flags.
-+
- IV. Notes
-
- Thanks to Steve Williams of Intel for arranging the non-disclosure agreement
-@@ -300,11 +306,13 @@
- */
-
- /* This table drives the PCI probe routines. */
--static struct net_device *speedo_found1(struct pci_dev *pdev, int pci_bus,
-- int pci_devfn, long ioaddr,
-- int chip_idx, int card_idx);
-+static void *speedo_found1(struct pci_dev *pdev, void *init_dev,
-+ long ioaddr, int irq, int chip_idx, int fnd_cnt);
-+static int speedo_pwr_event(void *dev_instance, int event);
-+enum chip_capability_flags { ResetMII=1, HasChksum=2};
-
--#ifdef USE_IO
-+/* I/O registers beyond 0x18 do not exist on the i82557. */
-+#ifdef USE_IO_OPS
- #define SPEEDO_IOTYPE PCI_USES_MASTER|PCI_USES_IO|PCI_ADDR1
- #define SPEEDO_SIZE 32
- #else
-@@ -312,48 +320,70 @@
- #define SPEEDO_SIZE 0x1000
- #endif
-
--enum pci_flags_bit {
-- PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
-- PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
--};
--struct pci_id_info {
-- const char *name;
-- u16 vendor_id, device_id;
-- int pci_index;
--} static pci_tbl[] = {
-- { "Intel PCI EtherExpress Pro100 82557",
-- PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82557,
-- 0
-- },
-- { "Intel PCI EtherExpress Pro100 82559ER",
-- PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82559ER,
-- 0
-- },
-- { "Intel PCI EtherExpress Pro100 ID1029",
-- PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ID1029,
-- 0
-- },
-- { "Intel Corporation 82559 InBusiness 10/100",
-- PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ID1030,
-- 0
-- },
-- { "Intel PCI EtherExpress Pro100 82562EM",
-- PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ID2449,
-- 0
-- },
-- {0,} /* 0 terminated list. */
-+struct pci_id_info static pci_id_tbl[] = {
-+ {"Intel PCI EtherExpress Pro100 82865", { 0x12278086, 0xffffffff,},
-+ SPEEDO_IOTYPE, SPEEDO_SIZE, 0, },
-+ {"Intel PCI EtherExpress Pro100 Smart (i960RP/RD)",
-+ { 0x12288086, 0xffffffff,}, SPEEDO_IOTYPE, SPEEDO_SIZE, 0, },
-+ {"Intel i82559 rev 8", { 0x12298086, ~0, 0,0, 8,0xff},
-+ SPEEDO_IOTYPE, SPEEDO_SIZE, HasChksum, },
-+ {"Intel PCI EtherExpress Pro100", { 0x12298086, 0xffffffff,},
-+ SPEEDO_IOTYPE, SPEEDO_SIZE, 0, },
-+ {"Intel EtherExpress Pro/100+ i82559ER", { 0x12098086, 0xffffffff,},
-+ SPEEDO_IOTYPE, SPEEDO_SIZE, ResetMII, },
-+ {"Intel EtherExpress Pro/100 type 1029", { 0x10298086, 0xffffffff,},
-+ SPEEDO_IOTYPE, SPEEDO_SIZE, 0, },
-+ {"Intel EtherExpress Pro/100 type 1030", { 0x10308086, 0xffffffff,},
-+ SPEEDO_IOTYPE, SPEEDO_SIZE, 0, },
-+ {"Intel Pro/100 V Network", { 0x24498086, 0xffffffff,},
-+ SPEEDO_IOTYPE, SPEEDO_SIZE, 0, },
-+ {"Intel PCI LAN0 Controller 82801E", { 0x24598086, 0xffffffff,},
-+ SPEEDO_IOTYPE, SPEEDO_SIZE, 0, },
-+ {"Intel PCI LAN1 Controller 82801E", { 0x245D8086, 0xffffffff,},
-+ SPEEDO_IOTYPE, SPEEDO_SIZE, 0, },
-+ {"Intel Pro/100 VE (type 1031)", { 0x10318086, 0xffffffff,},
-+ SPEEDO_IOTYPE, SPEEDO_SIZE, 0, },
-+ {"Intel Pro/100 VE (type 1032)", { 0x10328086, 0xffffffff,},
-+ SPEEDO_IOTYPE, SPEEDO_SIZE, 0, },
-+ {"Intel Pro/100 VE (type 1033)", { 0x10338086, 0xffffffff,},
-+ SPEEDO_IOTYPE, SPEEDO_SIZE, 0, },
-+ {"Intel Pro/100 VE (type 1034)", { 0x10348086, 0xffffffff,},
-+ SPEEDO_IOTYPE, SPEEDO_SIZE, 0, },
-+ {"Intel Pro/100 VE (type 1035)", { 0x10358086, 0xffffffff,},
-+ SPEEDO_IOTYPE, SPEEDO_SIZE, 0, },
-+ {"Intel Pro/100 VM (type 1038)", { 0x10388086, 0xffffffff,},
-+ SPEEDO_IOTYPE, SPEEDO_SIZE, 0, },
-+ {"Intel Pro/100 VM (type 1039)", { 0x10398086, 0xffffffff,},
-+ SPEEDO_IOTYPE, SPEEDO_SIZE, 0, },
-+ {"Intel Pro/100 VM (type 103a)", { 0x103a8086, 0xffffffff,},
-+ SPEEDO_IOTYPE, SPEEDO_SIZE, 0, },
-+ {"HP/Compaq D510 Intel Pro/100 VM",
-+ { 0x103b8086, 0xffffffff, 0x00120e11, 0xffffffff,},
-+ SPEEDO_IOTYPE, SPEEDO_SIZE, 0, },
-+ {"Intel Pro/100 VM (type 103b)", { 0x103b8086, 0xffffffff,},
-+ SPEEDO_IOTYPE, SPEEDO_SIZE, 0, },
-+ {"Intel Pro/100 VE (type 103D)", { 0x103d8086, 0xffffffff,},
-+ SPEEDO_IOTYPE, SPEEDO_SIZE, 0, },
-+ {"Intel Pro/100 VE (type 103E)", { 0x103e8086, 0xffffffff,},
-+ SPEEDO_IOTYPE, SPEEDO_SIZE, 0, },
-+ {"Intel EtherExpress Pro/100 865G Northbridge type 1051",
-+ { 0x10518086, 0xffffffff,}, SPEEDO_IOTYPE, SPEEDO_SIZE, 0, },
-+ {"Intel PCI to PCI Bridge EtherExpress Pro100 Server Adapter",
-+ { 0x52008086, 0xffffffff,}, SPEEDO_IOTYPE, SPEEDO_SIZE, 0, },
-+ {"Intel PCI EtherExpress Pro100 Server Adapter",
-+ { 0x52018086, 0xffffffff,}, SPEEDO_IOTYPE, SPEEDO_SIZE, 0, },
-+ {"Intel Pro/100 VM (unknown type series 1030)",
-+ { 0x10308086, 0xfff0ffff,}, SPEEDO_IOTYPE, SPEEDO_SIZE, 0, },
-+ {"Intel Pro/100 (unknown type series 1050)",
-+ { 0x10508086, 0xfff0ffff,}, SPEEDO_IOTYPE, SPEEDO_SIZE, 0, },
-+ {0,}, /* 0 terminated list. */
- };
-
--static inline unsigned int io_inw(unsigned long port)
--{
-- return inw(port);
--}
--static inline void io_outw(unsigned int val, unsigned long port)
--{
-- outw(val, port);
--}
-+struct drv_id_info eepro100_drv_id = {
-+ "eepro100", PCI_HOTSWAP, PCI_CLASS_NETWORK_ETHERNET<<8, pci_id_tbl,
-+ speedo_found1, speedo_pwr_event, };
-
--#ifndef USE_IO
-+#ifndef USE_IO_OPS
- #undef inb
- #undef inw
- #undef inl
-@@ -368,27 +398,6 @@
- #define outl writel
- #endif
-
--/* How to wait for the command unit to accept a command.
-- Typically this takes 0 ticks. */
--static inline void wait_for_cmd_done(long cmd_ioaddr)
--{
-- int wait = 20000;
-- char cmd_reg1, cmd_reg2;
-- do ;
-- while((cmd_reg1 = inb(cmd_ioaddr)) && (--wait >= 0));
--
-- /* Last chance to change your mind --Dragan*/
-- if (wait < 0){
-- cmd_reg2 = inb(cmd_ioaddr);
-- if(cmd_reg2){
-- printk(KERN_ALERT "eepro100: cmd_wait for(%#2.2x) timedout with(%#2.2x)!\n",
-- cmd_reg1, cmd_reg2);
--
-- }
-- }
--
--}
--
- /* Offsets to the various registers.
- All accesses need not be longword aligned. */
- enum speedo_offsets {
-@@ -408,28 +417,36 @@
- CmdIntr = 0x20000000, /* Interrupt after completion. */
- CmdTxFlex = 0x00080000, /* Use "Flexible mode" for CmdTx command. */
- };
--/* Clear CmdSuspend (1<<30) avoiding interference with the card access to the
-- status bits. Previous driver versions used separate 16 bit fields for
-- commands and statuses. --SAW
-- */
--#if defined(__LITTLE_ENDIAN)
--#define clear_suspend(cmd) ((__u16 *)&(cmd)->cmd_status)[1] &= ~0x4000
--#elif defined(__BIG_ENDIAN)
--#define clear_suspend(cmd) ((__u16 *)&(cmd)->cmd_status)[1] &= ~0x0040
-+/* Do atomically if possible. */
-+#if defined(__i386__)
-+#define clear_suspend(cmd) ((char *)(&(cmd)->cmd_status))[3] &= ~0x40
-+#elif defined(__alpha__) || defined(__x86_64) || defined(__ia64)
-+#define clear_suspend(cmd) clear_bit(30, &(cmd)->cmd_status)
-+#elif defined(__powerpc__) || defined(__sparc__) || (__BIG_ENDIAN)
-+#define clear_suspend(cmd) clear_bit(6, &(cmd)->cmd_status)
- #else
--#error Unsupported byteorder
-+#warning Undefined architecture.
-+#define clear_suspend(cmd) (cmd)->cmd_status &= cpu_to_le32(~CmdSuspend)
- #endif
-
- enum SCBCmdBits {
-- SCBMaskCmdDone=0x8000, SCBMaskRxDone=0x4000, SCBMaskCmdIdle=0x2000,
-- SCBMaskRxSuspend=0x1000, SCBMaskEarlyRx=0x0800, SCBMaskFlowCtl=0x0400,
-- SCBTriggerIntr=0x0200, SCBMaskAll=0x0100,
-- /* The rest are Rx and Tx commands. */
-- CUStart=0x0010, CUResume=0x0020, CUStatsAddr=0x0040, CUShowStats=0x0050,
-- CUCmdBase=0x0060, /* CU Base address (set to zero) . */
-- CUDumpStats=0x0070, /* Dump then reset stats counters. */
-- RxStart=0x0001, RxResume=0x0002, RxAbort=0x0004, RxAddrLoad=0x0006,
-- RxResumeNoResources=0x0007,
-+ SCBMaskCmdDone=0x8000, SCBMaskRxDone=0x4000, SCBMaskCmdIdle=0x2000,
-+ SCBMaskRxSuspend=0x1000, SCBMaskEarlyRx=0x0800, SCBMaskFlowCtl=0x0400,
-+ SCBTriggerIntr=0x0200, SCBMaskAll=0x0100,
-+ /* The rest are Rx and Tx commands. */
-+ CUStart=0x0010, CUResume=0x0020, CUHiPriStart=0x0030, CUStatsAddr=0x0040,
-+ CUShowStats=0x0050,
-+ CUCmdBase=0x0060, /* CU Base address (set to zero) . */
-+ CUDumpStats=0x0070, /* Dump then reset stats counters. */
-+ CUHiPriResume=0x00b0, /* Resume for the high priority Tx queue. */
-+ RxStart=0x0001, RxResume=0x0002, RxAbort=0x0004, RxAddrLoad=0x0006,
-+ RxResumeNoResources=0x0007,
-+};
-+
-+enum intr_status_bits {
-+ IntrCmdDone=0x8000, IntrRxDone=0x4000, IntrCmdIdle=0x2000,
-+ IntrRxSuspend=0x1000, IntrMIIDone=0x0800, IntrDrvrIntr=0x0400,
-+ IntrAllNormal=0xfc00,
- };
-
- enum SCBPort_cmds {
-@@ -437,9 +454,9 @@
- };
-
- /* The Speedo3 Rx and Tx frame/buffer descriptors. */
--struct descriptor { /* A generic descriptor. */
-- s32 cmd_status; /* All command and status fields. */
-- u32 link; /* struct descriptor * */
-+struct descriptor { /* A generic descriptor. */
-+ s32 cmd_status; /* All command and status fields. */
-+ u32 link; /* struct descriptor * */
- unsigned char params[0];
- };
-
-@@ -464,18 +481,11 @@
- u32 link; /* void * */
- u32 tx_desc_addr; /* Always points to the tx_buf_addr element. */
- s32 count; /* # of TBD (=1), Tx start thresh., etc. */
-- /* This constitutes two "TBD" entries -- we only use one. */
-+ /* This constitutes two "TBD" entries. Non-zero-copy uses only one. */
- u32 tx_buf_addr0; /* void *, frame to be transmitted. */
- s32 tx_buf_size0; /* Length of Tx frame. */
-- u32 tx_buf_addr1; /* void *, frame to be transmitted. */
-- s32 tx_buf_size1; /* Length of Tx frame. */
--};
--
--/* Multicast filter setting block. --SAW */
--struct speedo_mc_block {
-- struct speedo_mc_block *next;
-- unsigned int tx;
-- struct descriptor frame __attribute__ ((__aligned__(16)));
-+ u32 tx_buf_addr1; /* Used only for zero-copy data section. */
-+ s32 tx_buf_size1; /* Length of second data buffer (0). */
- };
-
- /* Elements of the dump_statistics block. This block must be lword aligned. */
-@@ -499,48 +509,70 @@
- u32 done_marker;
- };
-
--enum Rx_ring_state_bits {
-- RrNoMem=1, RrPostponed=2, RrNoResources=4, RrOOMReported=8,
--};
--
- /* Do not change the position (alignment) of the first few elements!
- The later elements are grouped for cache locality. */
- struct speedo_private {
- struct TxFD tx_ring[TX_RING_SIZE]; /* Commands (usually CmdTxPacket). */
- struct RxFD *rx_ringp[RX_RING_SIZE]; /* Rx descriptor, used as ring. */
-+ struct speedo_stats lstats; /* Statistics and self-test region */
-+
- /* The addresses of a Tx/Rx-in-place packets/buffers. */
- struct sk_buff* tx_skbuff[TX_RING_SIZE];
- struct sk_buff* rx_skbuff[RX_RING_SIZE];
-+
-+ /* Transmit and other commands control. */
- struct descriptor *last_cmd; /* Last command sent. */
- unsigned int cur_tx, dirty_tx; /* The ring entries to be free()ed. */
- spinlock_t lock; /* Group with Tx control cache line. */
- u32 tx_threshold; /* The value for txdesc.count. */
-- struct RxFD *last_rxf; /* Last command sent. */
-+ unsigned long last_cmd_time;
-+
-+ /* Rx control, one cache line. */
-+ struct RxFD *last_rxf; /* Most recent Rx frame. */
- unsigned int cur_rx, dirty_rx; /* The next free ring entry */
-+ unsigned int rx_buf_sz; /* Based on MTU+slack. */
- long last_rx_time; /* Last Rx, in jiffies, to handle Rx hang. */
-- const char *product_name;
-+ int rx_copybreak;
-+
-+ int msg_level;
-+ int max_interrupt_work;
- struct net_device *next_module;
- void *priv_addr; /* Unaligned address for kfree */
-- struct enet_statistics stats;
-- struct speedo_stats lstats;
-- int chip_id;
-- unsigned char pci_bus, pci_devfn, acpi_pwr;
-+ struct net_device_stats stats;
-+ int alloc_failures;
-+ int chip_id, drv_flags;
-+ struct pci_dev *pci_dev;
-+ unsigned char acpi_pwr;
- struct timer_list timer; /* Media selection timer. */
-- struct speedo_mc_block *mc_setup_head;/* Multicast setup frame list head. */
-- struct speedo_mc_block *mc_setup_tail;/* Multicast setup frame list tail. */
-+ /* Multicast filter command. */
-+ int mc_setup_frm_len; /* The length of an allocated.. */
-+ struct descriptor *mc_setup_frm; /* ..multicast setup frame. */
-+ int mc_setup_busy; /* Avoid double-use of setup frame. */
-+ int multicast_filter_limit;
-+
- int in_interrupt; /* Word-aligned dev->interrupt */
-- char rx_mode; /* Current PROMISC/ALLMULTI setting. */
-+ int rx_mode; /* Current PROMISC/ALLMULTI setting. */
- unsigned int tx_full:1; /* The Tx queue is full. */
- unsigned int full_duplex:1; /* Full-duplex operation requested. */
- unsigned int flow_ctrl:1; /* Use 802.3x flow control. */
- unsigned int rx_bug:1; /* Work around receiver hang errata. */
- unsigned int rx_bug10:1; /* Receiver might hang at 10mbps. */
- unsigned int rx_bug100:1; /* Receiver might hang at 100mbps. */
-- unsigned char default_port:8; /* Last dev->if_port value. */
-- unsigned char rx_ring_state; /* RX ring status flags. */
-+ unsigned int polling:1; /* Hardware blocked interrupt line. */
-+ unsigned int medialock:1; /* The media speed/duplex is fixed. */
-+ unsigned char default_port; /* Last dev->if_port value. */
- unsigned short phy[2]; /* PHY media interfaces available. */
- unsigned short advertising; /* Current PHY advertised caps. */
- unsigned short partner; /* Link partner caps. */
-+ long last_reset;
-+};
-+
-+/* Our internal RxMode state, not tied to the hardware bits. */
-+enum rx_mode_bits {
-+ AcceptAllMulticast=0x01, AcceptAllPhys=0x02,
-+ AcceptErr=0x80, AcceptRunt=0x10,
-+ AcceptBroadcast=0x08, AcceptMulticast=0x04,
-+ AcceptMyPhys=0x01, RxInvalidMode=0x7f
- };
-
- /* The parameters for a CmdConfigure operation.
-@@ -554,10 +586,10 @@
- const char i82558_config_cmd[22] = {
- 22, 0x08, 0, 1, 0, 0, 0x22, 0x03, 1, /* 1=Use MII 0=Use AUI */
- 0, 0x2E, 0, 0x60, 0x08, 0x88,
-- 0x68, 0, 0x40, 0xf2, 0x84, /* Disable FC */
-+ 0x68, 0, 0x40, 0xf2, 0xBD, /* 0xBD->0xFD=Force full-duplex */
- 0x31, 0x05, };
-
--/* PHY media interface chips. */
-+/* PHY media interface chips, defined by the databook. */
- static const char *phys[] = {
- "None", "i82553-A/B", "i82553-C", "i82503",
- "DP83840", "80c240", "80c24", "i82555",
-@@ -566,10 +598,12 @@
- enum phy_chips { NonSuchPhy=0, I82553AB, I82553C, I82503, DP83840, S80C240,
- S80C24, I82555, DP83840A=10, };
- static const char is_mii[] = { 0, 1, 1, 0, 1, 1, 0, 1 };
-+
-+/* Standard serial configuration EEPROM commands. */
- #define EE_READ_CMD (6)
-
- static int do_eeprom_cmd(long ioaddr, int cmd, int cmd_len);
--static int mdio_read(long ioaddr, int phy_id, int location);
-+static int mdio_read(struct net_device *dev, int phy_id, int location);
- static int mdio_write(long ioaddr, int phy_id, int location, int value);
- static int speedo_open(struct net_device *dev);
- static void speedo_resume(struct net_device *dev);
-@@ -577,15 +611,12 @@
- static void speedo_init_rx_ring(struct net_device *dev);
- static void speedo_tx_timeout(struct net_device *dev);
- static int speedo_start_xmit(struct sk_buff *skb, struct net_device *dev);
--static void speedo_refill_rx_buffers(struct net_device *dev, int force);
- static int speedo_rx(struct net_device *dev);
--static void speedo_tx_buffer_gc(struct net_device *dev);
- static void speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
- static int speedo_close(struct net_device *dev);
--static struct enet_statistics *speedo_get_stats(struct net_device *dev);
-+static struct net_device_stats *speedo_get_stats(struct net_device *dev);
- static int speedo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
- static void set_rx_mode(struct net_device *dev);
--static void speedo_show_state(struct net_device *dev);
-
-
-
-@@ -599,112 +630,28 @@
- /* A list of all installed Speedo devices, for removing the driver module. */
- static struct net_device *root_speedo_dev = NULL;
-
--int eepro100_init(void)
--{
-- int cards_found = 0;
-- int chip_idx;
-- struct pci_dev *pdev;
--
-- if (! pcibios_present())
-- return cards_found;
--
-- for (chip_idx = 0; pci_tbl[chip_idx].name; chip_idx++) {
-- for (; pci_tbl[chip_idx].pci_index < 8; pci_tbl[chip_idx].pci_index++) {
-- unsigned char pci_bus, pci_device_fn, pci_latency;
-- unsigned long pciaddr;
-- long ioaddr;
-- int irq;
--
-- u16 pci_command, new_command;
--
-- if (pcibios_find_device(pci_tbl[chip_idx].vendor_id,
-- pci_tbl[chip_idx].device_id,
-- pci_tbl[chip_idx].pci_index, &pci_bus,
-- &pci_device_fn))
-- break;
-- {
-- pdev = pci_find_slot(pci_bus, pci_device_fn);
--#ifdef USE_IO
-- pciaddr = pci_base_address(pdev, 1); /* Use [0] to mem-map */
--#else
-- pciaddr = pci_base_address(pdev, 0);
--#endif
-- irq = pdev->irq;
-- }
-- /* Remove I/O space marker in bit 0. */
-- if (pciaddr & 1) {
-- ioaddr = pciaddr & ~3UL;
-- if (check_region(ioaddr, 32))
-- continue;
-- } else {
--#ifdef __sparc__
-- /* ioremap is hosed in 2.2.x on Sparc. */
-- ioaddr = pciaddr & ~0xfUL;
--#else
-- if ((ioaddr = (long)ioremap(pciaddr & ~0xfUL, 0x1000)) == 0) {
-- printk(KERN_INFO "Failed to map PCI address %#lx.\n",
-- pciaddr);
-- continue;
-- }
--#endif
-- }
-- if (speedo_debug > 2)
-- printk("Found Intel i82557 PCI Speedo at I/O %#lx, IRQ %d.\n",
-- ioaddr, irq);
--
-- /* Get and check the bus-master and latency values. */
-- pcibios_read_config_word(pci_bus, pci_device_fn,
-- PCI_COMMAND, &pci_command);
-- new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
-- if (pci_command != new_command) {
-- printk(KERN_INFO " The PCI BIOS has not enabled this"
-- " device! Updating PCI command %4.4x->%4.4x.\n",
-- pci_command, new_command);
-- pcibios_write_config_word(pci_bus, pci_device_fn,
-- PCI_COMMAND, new_command);
-- }
-- pcibios_read_config_byte(pci_bus, pci_device_fn,
-- PCI_LATENCY_TIMER, &pci_latency);
-- if (pci_latency < 32) {
-- printk(" PCI latency timer (CFLT) is unreasonably low at %d."
-- " Setting to 32 clocks.\n", pci_latency);
-- pcibios_write_config_byte(pci_bus, pci_device_fn,
-- PCI_LATENCY_TIMER, 32);
-- } else if (speedo_debug > 1)
-- printk(" PCI latency timer (CFLT) is %#x.\n", pci_latency);
--
-- if (speedo_found1(pdev, pci_bus, pci_device_fn, ioaddr, chip_idx, cards_found))
-- cards_found++;
-- }
-- }
--
-- return cards_found;
--}
--
--static struct net_device *speedo_found1(struct pci_dev *pdev, int pci_bus,
-- int pci_devfn, long ioaddr,
-- int chip_idx, int card_idx)
-+static void *speedo_found1(struct pci_dev *pdev, void *init_dev,
-+ long ioaddr, int irq, int chip_idx, int card_idx)
- {
- struct net_device *dev;
- struct speedo_private *sp;
-- const char *product;
-+ void *priv_mem;
- int i, option;
- u16 eeprom[0x100];
- int acpi_idle_state = 0;
--#ifndef MODULE
-- static int did_version = 0; /* Already printed version info. */
-- if (speedo_debug > 0 && did_version++ == 0)
-- printk(version);
--#endif
-
-- dev = init_etherdev(NULL, sizeof(struct speedo_private));
-+ dev = init_etherdev(init_dev, 0);
-+ if (!dev)
-+ return NULL;
-
- if (dev->mem_start > 0)
- option = dev->mem_start;
- else if (card_idx >= 0 && options[card_idx] >= 0)
- option = options[card_idx];
- else
-- option = 0;
-+ option = -1;
-+
-+ acpi_idle_state = acpi_set_pwr_state(pdev, ACPI_D0);
-
- /* Read the station address EEPROM before doing the reset.
- Nominally his should even be done before accepting the device, but
-@@ -712,15 +659,11 @@
- The size test is for 6 bit vs. 8 bit address serial EEPROMs.
- */
- {
-- unsigned long iobase;
-- int read_cmd, ee_size;
-- u16 sum;
-+ u16 sum = 0;
- int j;
-+ int read_cmd, ee_size;
-
-- /* Use IO only to avoid postponed writes and satisfy EEPROM timing
-- requirements. */
-- iobase = pci_base_address(pdev, 1) & ~3UL;
-- if ((do_eeprom_cmd(iobase, EE_READ_CMD << 24, 27) & 0xffe0000)
-+ if ((do_eeprom_cmd(ioaddr, EE_READ_CMD << 24, 27) & 0xffe0000)
- == 0xffe0000) {
- ee_size = 0x100;
- read_cmd = EE_READ_CMD << 24;
-@@ -729,8 +672,8 @@
- read_cmd = EE_READ_CMD << 22;
- }
-
-- for (j = 0, i = 0, sum = 0; i < ee_size; i++) {
-- u16 value = do_eeprom_cmd(iobase, read_cmd | (i << 16), 27);
-+ for (j = 0, i = 0; i < ee_size; i++) {
-+ u16 value = do_eeprom_cmd(ioaddr, read_cmd | (i << 16), 27);
- eeprom[i] = value;
- sum += value;
- if (i < 3) {
-@@ -743,45 +686,41 @@
- "check settings before activating this device!\n",
- dev->name, sum);
- /* Don't unregister_netdev(dev); as the EEPro may actually be
-- usable, especially if the MAC address is set later.
-- On the other hand, it may be unusable if MDI data is corrupted. */
-+ usable, especially if the MAC address is set later. */
- }
-
- /* Reset the chip: stop Tx and Rx processes and clear counters.
- This takes less than 10usec and will easily finish before the next
- action. */
- outl(PortReset, ioaddr + SCBPort);
-- inl(ioaddr + SCBPort);
-- /* Honor PortReset timing. */
-- udelay(10);
-
-- if (eeprom[3] & 0x0100)
-- product = "OEM i82557/i82558 10/100 Ethernet";
-- else
-- product = pci_tbl[chip_idx].name;
--
-- printk(KERN_INFO "%s: %s, ", dev->name, product);
-+ printk(KERN_INFO "%s: %s%s at %#3lx, ", dev->name,
-+ eeprom[3] & 0x0100 ? "OEM " : "", pci_id_tbl[chip_idx].name,
-+ ioaddr);
-
- for (i = 0; i < 5; i++)
- printk("%2.2X:", dev->dev_addr[i]);
-- printk("%2.2X, ", dev->dev_addr[i]);
--#ifdef USE_IO
-- printk("I/O at %#3lx, ", ioaddr);
--#endif
-- printk("IRQ %d.\n", pdev->irq);
-+ printk("%2.2X, IRQ %d.\n", dev->dev_addr[i], irq);
-
--#if 1 || defined(kernel_bloat)
-+ /* We have decided to accept this device. */
-+ /* Allocate cached private storage.
-+ The PCI coherent descriptor rings are allocated at each open. */
-+ sp = priv_mem = kmalloc(sizeof(*sp), GFP_KERNEL);
-+ /* Check for the very unlikely case of no memory. */
-+ if (priv_mem == NULL)
-+ return NULL;
-+ dev->base_addr = ioaddr;
-+ dev->irq = irq;
-+
-+#ifndef kernel_bloat
- /* OK, this is pure kernel bloat. I don't like it when other drivers
- waste non-pageable kernel space to emit similar messages, but I need
- them for bug reports. */
- {
- const char *connectors[] = {" RJ45", " BNC", " AUI", " MII"};
- /* The self-test results must be paragraph aligned. */
-- s32 str[6], *volatile self_test_results;
-+ s32 *volatile self_test_results;
- int boguscnt = 16000; /* Timeout for set-test. */
-- if ((eeprom[3] & 0x03) != 0x03)
-- printk(KERN_INFO " Receiver lock-up bug exists -- enabling"
-- " work-around.\n");
- printk(KERN_INFO " Board assembly %4.4x%2.2x-%3.3d, Physical"
- " connectors present:",
- eeprom[8], eeprom[9]>>8, eeprom[9] & 0xff);
-@@ -795,24 +734,42 @@
- phys[(eeprom[7]>>8)&7]);
- if (((eeprom[6]>>8) & 0x3f) == DP83840
- || ((eeprom[6]>>8) & 0x3f) == DP83840A) {
-- int mdi_reg23 = mdio_read(ioaddr, eeprom[6] & 0x1f, 23) | 0x0422;
-+ int mdi_reg23 = mdio_read(dev, eeprom[6] & 0x1f, 23) | 0x0422;
- if (congenb)
- mdi_reg23 |= 0x0100;
- printk(KERN_INFO" DP83840 specific setup, setting register 23 to %4.4x.\n",
- mdi_reg23);
- mdio_write(ioaddr, eeprom[6] & 0x1f, 23, mdi_reg23);
- }
-- if ((option >= 0) && (option & 0x70)) {
-+ if ((option >= 0) && (option & 0x330)) {
- printk(KERN_INFO " Forcing %dMbs %s-duplex operation.\n",
-- (option & 0x20 ? 100 : 10),
-- (option & 0x10 ? "full" : "half"));
-+ (option & 0x300 ? 100 : 10),
-+ (option & 0x220 ? "full" : "half"));
- mdio_write(ioaddr, eeprom[6] & 0x1f, 0,
-- ((option & 0x20) ? 0x2000 : 0) | /* 100mbps? */
-- ((option & 0x10) ? 0x0100 : 0)); /* Full duplex? */
-- }
-+ ((option & 0x300) ? 0x2000 : 0) | /* 100mbps? */
-+ ((option & 0x220) ? 0x0100 : 0)); /* Full duplex? */
-+ } else {
-+ int mii_bmcrctrl = mdio_read(dev, eeprom[6] & 0x1f, 0);
-+ /* Reset out of a transceiver left in 10baseT-fixed mode. */
-+ if ((mii_bmcrctrl & 0x3100) == 0)
-+ mdio_write(ioaddr, eeprom[6] & 0x1f, 0, 0x8000);
-+ }
-+ if (eeprom[10] & 0x0002)
-+ printk(KERN_INFO "\n" KERN_INFO " ** The configuration "
-+ "EEPROM enables Sleep Mode.\n" KERN_INFO "\n"
-+ " ** This will cause PCI bus errors!\n"
-+ KERN_INFO " ** Update the configuration EEPROM "
-+ "with the eepro100-diag program.\n" );
-+ if (eeprom[6] == 0)
-+ printk(KERN_INFO " ** The configuration EEPROM does not have a "
-+ "transceiver type set.\n" KERN_INFO "\n"
-+ " ** This will cause configuration problems and prevent "
-+ "monitoring the link!\n"
-+ KERN_INFO " ** Update the configuration EEPROM "
-+ "with the eepro100-diag program.\n" );
-
- /* Perform a system self-test. */
-- self_test_results = (s32*) ((((long) str) + 15) & ~0xf);
-+ self_test_results = (s32*)(&sp->lstats);
- self_test_results[0] = 0;
- self_test_results[1] = -1;
- outl(virt_to_bus(self_test_results) | PortSelfTest, ioaddr + SCBPort);
-@@ -840,37 +797,36 @@
- #endif /* kernel_bloat */
-
- outl(PortReset, ioaddr + SCBPort);
-- inl(ioaddr + SCBPort);
-- /* Honor PortReset timing. */
-- udelay(10);
-
-- /* We do a request_region() only to register /proc/ioports info. */
-- request_region(ioaddr, SPEEDO3_TOTAL_SIZE, "Intel Speedo3 Ethernet");
-+ /* Return the chip to its original power state. */
-+ acpi_set_pwr_state(pdev, acpi_idle_state);
-
-- dev->base_addr = ioaddr;
-- dev->irq = pdev->irq;
-+ /* We do a request_region() only to register /proc/ioports info. */
-+ request_region(ioaddr, pci_id_tbl[chip_idx].io_size, dev->name);
-
-- sp = dev->priv;
-- if (dev->priv == NULL) {
-- void *mem = kmalloc(sizeof(*sp), GFP_KERNEL);
-- dev->priv = sp = mem; /* Cache align here if kmalloc does not. */
-- sp->priv_addr = mem;
-- }
-+ dev->priv = sp; /* Allocated above. */
- memset(sp, 0, sizeof(*sp));
- sp->next_module = root_speedo_dev;
- root_speedo_dev = dev;
-
-- sp->pci_bus = pci_bus;
-- sp->pci_devfn = pci_devfn;
-+ sp->priv_addr = priv_mem;
-+ sp->pci_dev = pdev;
- sp->chip_id = chip_idx;
-+ sp->drv_flags = pci_id_tbl[chip_idx].drv_flags;
- sp->acpi_pwr = acpi_idle_state;
-+ sp->msg_level = (1 << debug) - 1;
-+ sp->rx_copybreak = rx_copybreak;
-+ sp->max_interrupt_work = max_interrupt_work;
-+ sp->multicast_filter_limit = multicast_filter_limit;
-
-- sp->full_duplex = option >= 0 && (option & 0x10) ? 1 : 0;
-+ sp->full_duplex = option >= 0 && (option & 0x220) ? 1 : 0;
- if (card_idx >= 0) {
- if (full_duplex[card_idx] >= 0)
- sp->full_duplex = full_duplex[card_idx];
- }
- sp->default_port = option >= 0 ? (option & 0x0f) : 0;
-+ if (sp->full_duplex)
-+ sp->medialock = 1;
-
- sp->phy[0] = eeprom[6];
- sp->phy[1] = eeprom[7];
-@@ -882,10 +838,6 @@
- /* The Speedo-specific entries in the device structure. */
- dev->open = &speedo_open;
- dev->hard_start_xmit = &speedo_start_xmit;
--#if defined(HAS_NETIF_QUEUE)
-- dev->tx_timeout = &speedo_tx_timeout;
-- dev->watchdog_timeo = TX_TIMEOUT;
--#endif
- dev->stop = &speedo_close;
- dev->get_stats = &speedo_get_stats;
- dev->set_multicast_list = &set_rx_mode;
-@@ -893,6 +845,50 @@
-
- return dev;
- }
-+
-+/* How to wait for the command unit to accept a command.
-+ Typically this takes 0 ticks. */
-+
-+static inline void wait_for_cmd_done(struct net_device *dev)
-+{
-+ long cmd_ioaddr = dev->base_addr + SCBCmd;
-+ int wait = 0;
-+ int delayed_cmd;
-+ do
-+ if (inb(cmd_ioaddr) == 0) return;
-+ while(++wait <= 100);
-+ delayed_cmd = inb(cmd_ioaddr);
-+ do
-+ if (inb(cmd_ioaddr) == 0) break;
-+ while(++wait <= 10000);
-+ printk(KERN_ERR "%s: Command %2.2x was not immediately accepted, "
-+ "%d ticks!\n",
-+ dev->name, delayed_cmd, wait);
-+}
-+
-+/* Perform a SCB command known to be slow.
-+ This function checks the status both before and after command execution. */
-+static void do_slow_command(struct net_device *dev, int cmd)
-+{
-+ long cmd_ioaddr = dev->base_addr + SCBCmd;
-+ int wait = 0;
-+ do
-+ if (inb(cmd_ioaddr) == 0) break;
-+ while(++wait <= 200);
-+ if (wait > 100)
-+ printk(KERN_ERR "%s: Command %4.4x was never accepted (%d polls)!\n",
-+ dev->name, inb(cmd_ioaddr), wait);
-+ outb(cmd, cmd_ioaddr);
-+ for (wait = 0; wait <= 100; wait++)
-+ if (inb(cmd_ioaddr) == 0) return;
-+ for (; wait <= 20000; wait++)
-+ if (inb(cmd_ioaddr) == 0) return;
-+ else udelay(1);
-+ printk(KERN_ERR "%s: Command %4.4x was not accepted after %d polls!"
-+ " Current status %8.8x.\n",
-+ dev->name, cmd, wait, (int)inl(dev->base_addr + SCBStatus));
-+}
-+
-
- /* Serial EEPROM section.
- A "bit" grungy, but we work our way through bit-by-bit :->. */
-@@ -906,43 +902,48 @@
- #define EE_WRITE_1 0x4806
- #define EE_OFFSET SCBeeprom
-
--/* The fixes for the code were kindly provided by Dragan Stancevic
-- <visitor@valinux.com> to strictly follow Intel specifications of EEPROM
-- access timing.
-- The publicly available sheet 64486302 (sec. 3.1) specifies 1us access
-- interval for serial EEPROM. However, it looks like that there is an
-- additional requirement dictating larger udelay's in the code below.
-- 2000/05/24 SAW */
-+/* Delay between EEPROM clock transitions.
-+ The code works with no delay on 33Mhz PCI. */
-+#ifndef USE_IO_OPS
-+#define eeprom_delay(ee_addr) writew(readw(ee_addr), ee_addr)
-+#else
-+#define eeprom_delay(ee_addr) inw(ee_addr)
-+#endif
-+
- static int do_eeprom_cmd(long ioaddr, int cmd, int cmd_len)
- {
- unsigned retval = 0;
- long ee_addr = ioaddr + SCBeeprom;
-
-- io_outw(EE_ENB, ee_addr); udelay(2);
-- io_outw(EE_ENB | EE_SHIFT_CLK, ee_addr); udelay(2);
-+ outw(EE_ENB | EE_SHIFT_CLK, ee_addr);
-
- /* Shift the command bits out. */
- do {
- short dataval = (cmd & (1 << cmd_len)) ? EE_WRITE_1 : EE_WRITE_0;
-- io_outw(dataval, ee_addr); udelay(2);
-- io_outw(dataval | EE_SHIFT_CLK, ee_addr); udelay(2);
-- retval = (retval << 1) | ((io_inw(ee_addr) & EE_DATA_READ) ? 1 : 0);
-+ outw(dataval, ee_addr);
-+ eeprom_delay(ee_addr);
-+ outw(dataval | EE_SHIFT_CLK, ee_addr);
-+ eeprom_delay(ee_addr);
-+ retval = (retval << 1) | ((inw(ee_addr) & EE_DATA_READ) ? 1 : 0);
- } while (--cmd_len >= 0);
-- io_outw(EE_ENB, ee_addr); udelay(2);
-+ outw(EE_ENB, ee_addr);
-
- /* Terminate the EEPROM access. */
-- io_outw(EE_ENB & ~EE_CS, ee_addr);
-+ outw(EE_ENB & ~EE_CS, ee_addr);
- return retval;
- }
-
--static int mdio_read(long ioaddr, int phy_id, int location)
-+static int mdio_read(struct net_device *dev, int phy_id, int location)
- {
-+ long ioaddr = dev->base_addr;
- int val, boguscnt = 64*10; /* <64 usec. to complete, typ 27 ticks */
-+
- outl(0x08000000 | (location<<16) | (phy_id<<21), ioaddr + SCBCtrlMDI);
- do {
- val = inl(ioaddr + SCBCtrlMDI);
- if (--boguscnt < 0) {
-- printk(KERN_ERR " mdio_read() timed out with val = %8.8x.\n", val);
-+ printk(KERN_ERR "%s: mdio_read() timed out with val = %8.8x.\n",
-+ dev->name, val);
- break;
- }
- } while (! (val & 0x10000000));
-@@ -971,10 +972,11 @@
- struct speedo_private *sp = (struct speedo_private *)dev->priv;
- long ioaddr = dev->base_addr;
-
-- if (speedo_debug > 1)
-- printk(KERN_DEBUG "%s: speedo_open() irq %d.\n", dev->name, dev->irq);
--
- MOD_INC_USE_COUNT;
-+ acpi_set_pwr_state(sp->pci_dev, ACPI_D0);
-+
-+ if (sp->msg_level & NETIF_MSG_IFUP)
-+ printk(KERN_DEBUG "%s: speedo_open() irq %d.\n", dev->name, dev->irq);
-
- /* Set up the Tx queue early.. */
- sp->cur_tx = 0;
-@@ -982,19 +984,16 @@
- sp->last_cmd = 0;
- sp->tx_full = 0;
- sp->lock = (spinlock_t) SPIN_LOCK_UNLOCKED;
-- sp->in_interrupt = 0;
--
-- /* .. we can safely take handler calls during init. */
-- if (request_irq(dev->irq, &speedo_interrupt, SA_SHIRQ, dev->name, dev)) {
-- MOD_DEC_USE_COUNT;
-- return -EAGAIN;
-- }
-+ sp->polling = sp->in_interrupt = 0;
-
- dev->if_port = sp->default_port;
-
--#ifdef oh_no_you_dont_unless_you_honour_the_options_passed_in_to_us
-- /* Retrigger negotiation to reset previous errors. */
-- if ((sp->phy[0] & 0x8000) == 0) {
-+ if ((sp->phy[0] & 0x8000) == 0)
-+ sp->advertising = mdio_read(dev, sp->phy[0] & 0x1f, 4);
-+ /* With some transceivers we must retrigger negotiation to reset
-+ power-up errors. */
-+ if ((sp->drv_flags & ResetMII) &&
-+ (sp->phy[0] & 0x8000) == 0) {
- int phy_addr = sp->phy[0] & 0x1f ;
- /* Use 0x3300 for restarting NWay, other values to force xcvr:
- 0x0000 10-HD
-@@ -1008,31 +1007,31 @@
- mdio_write(ioaddr, phy_addr, 0, 0x3300);
- #endif
- }
--#endif
-+
-+ /* We can safely take handler calls during init.
-+ Doing this after speedo_init_rx_ring() results in a memory leak. */
-+ if (request_irq(dev->irq, &speedo_interrupt, SA_SHIRQ, dev->name, dev)) {
-+ MOD_DEC_USE_COUNT;
-+ return -EAGAIN;
-+ }
-
- speedo_init_rx_ring(dev);
-
- /* Fire up the hardware. */
-- outw(SCBMaskAll, ioaddr + SCBCmd);
- speedo_resume(dev);
--
-- dev->interrupt = 0;
-- dev->start = 1;
-- netif_start_queue(dev);
-+ netif_start_tx_queue(dev);
-
- /* Setup the chip and configure the multicast list. */
-- sp->mc_setup_head = NULL;
-- sp->mc_setup_tail = NULL;
-+ sp->mc_setup_frm = NULL;
-+ sp->mc_setup_frm_len = 0;
-+ sp->mc_setup_busy = 0;
-+ sp->rx_mode = RxInvalidMode; /* Invalid -> always reset the mode. */
- sp->flow_ctrl = sp->partner = 0;
-- sp->rx_mode = -1; /* Invalid -> always reset the mode. */
- set_rx_mode(dev);
-- if ((sp->phy[0] & 0x8000) == 0)
-- sp->advertising = mdio_read(ioaddr, sp->phy[0] & 0x1f, 4);
-
-- if (speedo_debug > 2) {
-+ if (sp->msg_level & NETIF_MSG_IFUP)
- printk(KERN_DEBUG "%s: Done speedo_open(), status %8.8x.\n",
-- dev->name, inw(ioaddr + SCBStatus));
-- }
-+ dev->name, (int)inw(ioaddr + SCBStatus));
-
- /* Set the timer. The timer serves a dual purpose:
- 1) to monitor the media interface (e.g. link beat) and perhaps switch
-@@ -1040,15 +1039,14 @@
- 2) to monitor Rx activity, and restart the Rx process if the receiver
- hangs. */
- init_timer(&sp->timer);
-- sp->timer.expires = RUN_AT((24*HZ)/10); /* 2.4 sec. */
-+ sp->timer.expires = jiffies + 3*HZ;
- sp->timer.data = (unsigned long)dev;
- sp->timer.function = &speedo_timer; /* timer handler */
- add_timer(&sp->timer);
-
- /* No need to wait for the command unit to accept here. */
- if ((sp->phy[0] & 0x8000) == 0)
-- mdio_read(ioaddr, sp->phy[0] & 0x1f, 0);
--
-+ mdio_read(dev, sp->phy[0] & 0x1f, 0);
- return 0;
- }
-
-@@ -1058,60 +1056,57 @@
- struct speedo_private *sp = (struct speedo_private *)dev->priv;
- long ioaddr = dev->base_addr;
-
-+ outw(SCBMaskAll, ioaddr + SCBCmd);
-+
- /* Start with a Tx threshold of 256 (0x..20.... 8 byte units). */
- sp->tx_threshold = 0x01208000;
-
- /* Set the segment registers to '0'. */
-- wait_for_cmd_done(ioaddr + SCBCmd);
-+ wait_for_cmd_done(dev);
-+ if (inb(ioaddr + SCBCmd)) {
-+ outl(PortPartialReset, ioaddr + SCBPort);
-+ udelay(10);
-+ }
- outl(0, ioaddr + SCBPointer);
-- /* impose a delay to avoid a bug */
-- inl(ioaddr + SCBPointer);
-- udelay(10);
-- outb(RxAddrLoad, ioaddr + SCBCmd);
-- wait_for_cmd_done(ioaddr + SCBCmd);
-- outb(CUCmdBase, ioaddr + SCBCmd);
-- wait_for_cmd_done(ioaddr + SCBCmd);
-+ inl(ioaddr + SCBPointer); /* Flush to PCI. */
-+ udelay(10); /* Bogus, but it avoids the bug. */
-+ /* Note: these next two operations can take a while. */
-+ do_slow_command(dev, RxAddrLoad);
-+ do_slow_command(dev, CUCmdBase);
-
- /* Load the statistics block and rx ring addresses. */
- outl(virt_to_bus(&sp->lstats), ioaddr + SCBPointer);
-+ inl(ioaddr + SCBPointer); /* Flush to PCI. */
- outb(CUStatsAddr, ioaddr + SCBCmd);
- sp->lstats.done_marker = 0;
-- wait_for_cmd_done(ioaddr + SCBCmd);
-+ wait_for_cmd_done(dev);
-
-- if (sp->rx_ringp[sp->cur_rx % RX_RING_SIZE] == NULL) {
-- if (speedo_debug > 2)
-- printk(KERN_DEBUG "%s: NULL cur_rx in speedo_resume().\n",
-- dev->name);
-- } else {
-- outl(virt_to_bus(sp->rx_ringp[sp->cur_rx % RX_RING_SIZE]),
-- ioaddr + SCBPointer);
-- outb(RxStart, ioaddr + SCBCmd);
-- wait_for_cmd_done(ioaddr + SCBCmd);
-- }
--
-- outb(CUDumpStats, ioaddr + SCBCmd);
-+ outl(virt_to_bus(sp->rx_ringp[sp->cur_rx % RX_RING_SIZE]),
-+ ioaddr + SCBPointer);
-+ inl(ioaddr + SCBPointer); /* Flush to PCI. */
-+ /* Note: RxStart should complete instantly. */
-+ do_slow_command(dev, RxStart);
-+ do_slow_command(dev, CUDumpStats);
-
- /* Fill the first command with our physical address. */
- {
-- struct descriptor *ias_cmd;
-+ int entry = sp->cur_tx++ % TX_RING_SIZE;
-+ struct descriptor *cur_cmd = (struct descriptor *)&sp->tx_ring[entry];
-
-- ias_cmd =
-- (struct descriptor *)&sp->tx_ring[sp->cur_tx++ % TX_RING_SIZE];
- /* Avoid a bug(?!) here by marking the command already completed. */
-- ias_cmd->cmd_status = cpu_to_le32((CmdSuspend | CmdIASetup) | 0xa000);
-- ias_cmd->link =
-+ cur_cmd->cmd_status = cpu_to_le32((CmdSuspend | CmdIASetup) | 0xa000);
-+ cur_cmd->link =
- virt_to_le32desc(&sp->tx_ring[sp->cur_tx % TX_RING_SIZE]);
-- memcpy(ias_cmd->params, dev->dev_addr, 6);
-- sp->last_cmd = ias_cmd;
-+ memcpy(cur_cmd->params, dev->dev_addr, 6);
-+ if (sp->last_cmd)
-+ clear_suspend(sp->last_cmd);
-+ sp->last_cmd = cur_cmd;
- }
-
- /* Start the chip's Tx process and unmask interrupts. */
-- wait_for_cmd_done(ioaddr + SCBCmd);
- outl(virt_to_bus(&sp->tx_ring[sp->dirty_tx % TX_RING_SIZE]),
- ioaddr + SCBPointer);
-- /* We are not ACK-ing FCP and ER in the interrupt handler yet so they should
-- remain masked --Dragan */
-- outw(CUStart | SCBMaskEarlyRx | SCBMaskFlowCtl, ioaddr + SCBCmd);
-+ outw(CUStart, ioaddr + SCBCmd);
- }
-
- /* Media monitoring and control. */
-@@ -1121,90 +1116,116 @@
- struct speedo_private *sp = (struct speedo_private *)dev->priv;
- long ioaddr = dev->base_addr;
- int phy_num = sp->phy[0] & 0x1f;
-+ int status = inw(ioaddr + SCBStatus);
-
-+ if (sp->msg_level & NETIF_MSG_TIMER)
-+ printk(KERN_DEBUG "%s: Interface monitor tick, chip status %4.4x.\n",
-+ dev->name, status);
-+
-+ /* Normally we check every two seconds. */
-+ sp->timer.expires = jiffies + 2*HZ;
-+
-+ if (sp->polling) {
-+ /* Continue to be annoying. */
-+ if (status & 0xfc00) {
-+ speedo_interrupt(dev->irq, dev, 0);
-+ if (jiffies - sp->last_reset > 10*HZ) {
-+ printk(KERN_ERR "%s: IRQ %d is still blocked!\n",
-+ dev->name, dev->irq);
-+ sp->last_reset = jiffies;
-+ }
-+ } else if (jiffies - sp->last_reset > 10*HZ)
-+ sp->polling = 0;
-+ sp->timer.expires = jiffies + 2;
-+ }
- /* We have MII and lost link beat. */
- if ((sp->phy[0] & 0x8000) == 0) {
-- int partner = mdio_read(ioaddr, phy_num, 5);
-+ int partner = mdio_read(dev, phy_num, 5);
- if (partner != sp->partner) {
- int flow_ctrl = sp->advertising & partner & 0x0400 ? 1 : 0;
-- if (speedo_debug > 2) {
-- printk(KERN_DEBUG "%s: Link status change.\n", dev->name);
-- printk(KERN_DEBUG "%s: Old partner %x, new %x, adv %x.\n",
-- dev->name, sp->partner, partner, sp->advertising);
-- }
- sp->partner = partner;
- if (flow_ctrl != sp->flow_ctrl) {
- sp->flow_ctrl = flow_ctrl;
-- sp->rx_mode = -1; /* Trigger a reload. */
-+ sp->rx_mode = RxInvalidMode; /* Trigger a reload. */
- }
- /* Clear sticky bit. */
-- mdio_read(ioaddr, phy_num, 1);
-+ mdio_read(dev, phy_num, 1);
- /* If link beat has returned... */
-- if (mdio_read(ioaddr, phy_num, 1) & 0x0004)
-- dev->flags |= IFF_RUNNING;
-+ if (mdio_read(dev, phy_num, 1) & 0x0004)
-+ netif_link_up(dev);
- else
-- dev->flags &= ~IFF_RUNNING;
-+ netif_link_down(dev);
- }
- }
-- if (speedo_debug > 3) {
-- printk(KERN_DEBUG "%s: Media control tick, status %4.4x.\n",
-- dev->name, inw(ioaddr + SCBStatus));
-+
-+ /* This no longer has a false-trigger window. */
-+ if (sp->cur_tx - sp->dirty_tx > 1 &&
-+ (jiffies - dev->trans_start) > TX_TIMEOUT &&
-+ (jiffies - sp->last_cmd_time) > TX_TIMEOUT) {
-+ if (status == 0xffff) {
-+ if (jiffies - sp->last_reset > 10*HZ) {
-+ sp->last_reset = jiffies;
-+ printk(KERN_ERR "%s: The EEPro100 chip is missing!\n",
-+ dev->name);
-+ }
-+ } else if (status & 0xfc00) {
-+ /* We have a blocked IRQ line. This should never happen, but
-+ we recover as best we can.*/
-+ if ( ! sp->polling) {
-+ if (jiffies - sp->last_reset > 10*HZ) {
-+ printk(KERN_ERR "%s: IRQ %d is physically blocked! (%4.4x)"
-+ "Failing back to low-rate polling.\n",
-+ dev->name, dev->irq, status);
-+ sp->last_reset = jiffies;
-+ }
-+ sp->polling = 1;
-+ }
-+ speedo_interrupt(dev->irq, dev, 0);
-+ sp->timer.expires = jiffies + 2; /* Avoid */
-+ } else {
-+ speedo_tx_timeout(dev);
-+ sp->last_reset = jiffies;
-+ }
- }
-- if (sp->rx_mode < 0 ||
-+ if (sp->rx_mode == RxInvalidMode ||
- (sp->rx_bug && jiffies - sp->last_rx_time > 2*HZ)) {
- /* We haven't received a packet in a Long Time. We might have been
- bitten by the receiver hang bug. This can be cleared by sending
- a set multicast list command. */
-- if (speedo_debug > 2)
-- printk(KERN_DEBUG "%s: Sending a multicast list set command"
-- " from a timer routine.\n", dev->name);
- set_rx_mode(dev);
- }
-- /* We must continue to monitor the media. */
-- sp->timer.expires = RUN_AT(2*HZ); /* 2.0 sec. */
- add_timer(&sp->timer);
- }
-
- static void speedo_show_state(struct net_device *dev)
- {
- struct speedo_private *sp = (struct speedo_private *)dev->priv;
--#if 0
-- long ioaddr = dev->base_addr;
- int phy_num = sp->phy[0] & 0x1f;
--#endif
- int i;
-
- /* Print a few items for debugging. */
-- if (speedo_debug > 0) {
-+ if (sp->msg_level & NETIF_MSG_DRV) {
- int i;
-- printk(KERN_DEBUG "%s: Tx ring dump, Tx queue %u / %u:\n", dev->name,
-+ printk(KERN_DEBUG "%s: Tx ring dump, Tx queue %d / %d:\n", dev->name,
- sp->cur_tx, sp->dirty_tx);
- for (i = 0; i < TX_RING_SIZE; i++)
-- printk(KERN_DEBUG "%s: %c%c%2d %8.8x.\n", dev->name,
-+ printk(KERN_DEBUG "%s: %c%c%d %8.8x.\n", dev->name,
- i == sp->dirty_tx % TX_RING_SIZE ? '*' : ' ',
- i == sp->cur_tx % TX_RING_SIZE ? '=' : ' ',
- i, sp->tx_ring[i].status);
- }
-- printk(KERN_DEBUG "%s: Printing Rx ring"
-- " (next to receive into %u, dirty index %u).\n",
-- dev->name, sp->cur_rx, sp->dirty_rx);
-+ printk(KERN_DEBUG "%s:Printing Rx ring (next to receive into %d).\n",
-+ dev->name, sp->cur_rx);
-
- for (i = 0; i < RX_RING_SIZE; i++)
-- printk(KERN_DEBUG "%s: %c%c%c%2d %8.8x.\n", dev->name,
-- sp->rx_ringp[i] == sp->last_rxf ? 'l' : ' ',
-- i == sp->dirty_rx % RX_RING_SIZE ? '*' : ' ',
-- i == sp->cur_rx % RX_RING_SIZE ? '=' : ' ',
-- i, (sp->rx_ringp[i] != NULL) ?
-- (unsigned)sp->rx_ringp[i]->status : 0);
-+ printk(KERN_DEBUG " Rx ring entry %d %8.8x.\n",
-+ i, sp->rx_ringp[i] ? (int)sp->rx_ringp[i]->status : 0);
-
--#if 0
- for (i = 0; i < 16; i++) {
-- /* FIXME: what does it mean? --SAW */
- if (i == 6) i = 21;
-- printk(KERN_DEBUG "%s: PHY index %d register %d is %4.4x.\n",
-- dev->name, phy_num, i, mdio_read(ioaddr, phy_num, i));
-+ printk(KERN_DEBUG " PHY index %d register %d is %4.4x.\n",
-+ phy_num, i, mdio_read(dev, phy_num, i));
- }
--#endif
-
- }
-
-@@ -1217,10 +1238,18 @@
- int i;
-
- sp->cur_rx = 0;
-+#if defined(CONFIG_VLAN)
-+ /* Note that buffer sizing is not a run-time check! */
-+ sp->rx_buf_sz = dev->mtu + 14 + sizeof(struct RxFD) + 4;
-+#else
-+ sp->rx_buf_sz = dev->mtu + 14 + sizeof(struct RxFD);
-+#endif
-+ if (sp->rx_buf_sz < PKT_BUF_SZ)
-+ sp->rx_buf_sz = PKT_BUF_SZ;
-
- for (i = 0; i < RX_RING_SIZE; i++) {
- struct sk_buff *skb;
-- skb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD));
-+ skb = dev_alloc_skb(sp->rx_buf_sz);
- sp->rx_skbuff[i] = skb;
- if (skb == NULL)
- break; /* OK. Just initially short of Rx bufs. */
-@@ -1233,9 +1262,13 @@
- last_rxf = rxf;
- rxf->status = cpu_to_le32(0x00000001); /* '1' is flag value only. */
- rxf->link = 0; /* None yet. */
-- /* This field unused by i82557. */
-+ /* This field unused by i82557, we use it as a consistency check. */
-+#ifdef final_version
- rxf->rx_buf_addr = 0xffffffff;
-- rxf->count = cpu_to_le32(PKT_BUF_SZ << 16);
-+#else
-+ rxf->rx_buf_addr = virt_to_bus(skb->tail);
-+#endif
-+ rxf->count = cpu_to_le32((sp->rx_buf_sz - sizeof(struct RxFD)) << 16);
- }
- sp->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
- /* Mark the last entry as end-of-list. */
-@@ -1243,121 +1276,86 @@
- sp->last_rxf = last_rxf;
- }
-
--static void speedo_purge_tx(struct net_device *dev)
--{
-- struct speedo_private *sp = (struct speedo_private *)dev->priv;
-- int entry;
--
-- while ((int)(sp->cur_tx - sp->dirty_tx) > 0) {
-- entry = sp->dirty_tx % TX_RING_SIZE;
-- if (sp->tx_skbuff[entry]) {
-- sp->stats.tx_errors++;
-- dev_free_skb(sp->tx_skbuff[entry]);
-- sp->tx_skbuff[entry] = 0;
-- }
-- sp->dirty_tx++;
-- }
-- while (sp->mc_setup_head != NULL) {
-- struct speedo_mc_block *t;
-- if (speedo_debug > 1)
-- printk(KERN_DEBUG "%s: freeing mc frame.\n", dev->name);
-- t = sp->mc_setup_head->next;
-- kfree(sp->mc_setup_head);
-- sp->mc_setup_head = t;
-- }
-- sp->mc_setup_tail = NULL;
-- sp->tx_full = 0;
-- netif_wake_queue(dev);
--}
--
--static void reset_mii(struct net_device *dev)
--{
-- struct speedo_private *sp = (struct speedo_private *)dev->priv;
-- long ioaddr = dev->base_addr;
-- /* Reset the MII transceiver, suggested by Fred Young @ scalable.com. */
-- if ((sp->phy[0] & 0x8000) == 0) {
-- int phy_addr = sp->phy[0] & 0x1f;
-- int advertising = mdio_read(ioaddr, phy_addr, 4);
-- int mii_bmcr = mdio_read(ioaddr, phy_addr, 0);
-- mdio_write(ioaddr, phy_addr, 0, 0x0400);
-- mdio_write(ioaddr, phy_addr, 1, 0x0000);
-- mdio_write(ioaddr, phy_addr, 4, 0x0000);
-- mdio_write(ioaddr, phy_addr, 0, 0x8000);
--#ifdef honor_default_port
-- mdio_write(ioaddr, phy_addr, 0, mii_ctrl[dev->default_port & 7]);
--#else
-- mdio_read(ioaddr, phy_addr, 0);
-- mdio_write(ioaddr, phy_addr, 0, mii_bmcr);
-- mdio_write(ioaddr, phy_addr, 4, advertising);
--#endif
-- }
--}
--
- static void speedo_tx_timeout(struct net_device *dev)
- {
- struct speedo_private *sp = (struct speedo_private *)dev->priv;
- long ioaddr = dev->base_addr;
- int status = inw(ioaddr + SCBStatus);
-- unsigned long flags;
-
- printk(KERN_WARNING "%s: Transmit timed out: status %4.4x "
-- " %4.4x at %d/%d command %8.8x.\n",
-- dev->name, status, inw(ioaddr + SCBCmd),
-+ " %4.4x at %d/%d commands %8.8x %8.8x %8.8x.\n",
-+ dev->name, status, (int)inw(ioaddr + SCBCmd),
- sp->dirty_tx, sp->cur_tx,
-- sp->tx_ring[sp->dirty_tx % TX_RING_SIZE].status);
-+ sp->tx_ring[(sp->dirty_tx+0) % TX_RING_SIZE].status,
-+ sp->tx_ring[(sp->dirty_tx+1) % TX_RING_SIZE].status,
-+ sp->tx_ring[(sp->dirty_tx+2) % TX_RING_SIZE].status);
-
- /* Trigger a stats dump to give time before the reset. */
- speedo_get_stats(dev);
-
- speedo_show_state(dev);
--#if 0
- if ((status & 0x00C0) != 0x0080
-- && (status & 0x003C) == 0x0010) {
-+ && (status & 0x003C) == 0x0010 && 0) {
- /* Only the command unit has stopped. */
- printk(KERN_WARNING "%s: Trying to restart the transmitter...\n",
- dev->name);
- outl(virt_to_bus(&sp->tx_ring[sp->dirty_tx % TX_RING_SIZE]),
- ioaddr + SCBPointer);
- outw(CUStart, ioaddr + SCBCmd);
-- reset_mii(dev);
- } else {
--#else
-- {
--#endif
-- start_bh_atomic();
-- /* Ensure that timer routine doesn't run! */
-- del_timer(&sp->timer);
-- end_bh_atomic();
-+ printk(KERN_WARNING "%s: Restarting the chip...\n",
-+ dev->name);
- /* Reset the Tx and Rx units. */
- outl(PortReset, ioaddr + SCBPort);
-- /* We may get spurious interrupts here. But I don't think that they
-- may do much harm. 1999/12/09 SAW */
-+ if (sp->msg_level & NETIF_MSG_TX_ERR)
-+ speedo_show_state(dev);
- udelay(10);
-- /* Disable interrupts. */
-- outw(SCBMaskAll, ioaddr + SCBCmd);
-- synchronize_irq();
-- speedo_tx_buffer_gc(dev);
-- /* Free as much as possible.
-- It helps to recover from a hang because of out-of-memory.
-- It also simplifies speedo_resume() in case TX ring is full or
-- close-to-be full. */
-- speedo_purge_tx(dev);
-- speedo_refill_rx_buffers(dev, 1);
-- spin_lock_irqsave(&sp->lock, flags);
- speedo_resume(dev);
-- sp->rx_mode = -1;
-- dev->trans_start = jiffies;
-- spin_unlock_irqrestore(&sp->lock, flags);
-- set_rx_mode(dev); /* it takes the spinlock itself --SAW */
-- /* Reset MII transceiver. Do it before starting the timer to serialize
-- mdio_xxx operations. Yes, it's a paranoya :-) 2000/05/09 SAW */
-- reset_mii(dev);
-- sp->timer.expires = RUN_AT(2*HZ);
-- add_timer(&sp->timer);
- }
-+ /* Reset the MII transceiver, suggested by Fred Young @ scalable.com. */
-+ if ((sp->phy[0] & 0x8000) == 0) {
-+ int phy_addr = sp->phy[0] & 0x1f;
-+ int advertising = mdio_read(dev, phy_addr, 4);
-+ int mii_bmcr = mdio_read(dev, phy_addr, 0);
-+ mdio_write(ioaddr, phy_addr, 0, 0x0400);
-+ mdio_write(ioaddr, phy_addr, 1, 0x0000);
-+ mdio_write(ioaddr, phy_addr, 4, 0x0000);
-+ mdio_write(ioaddr, phy_addr, 0, 0x8000);
-+#ifdef honor_default_port
-+ mdio_write(ioaddr, phy_addr, 0, mii_ctrl[dev->default_port & 7]);
-+#else
-+ mdio_read(dev, phy_addr, 0);
-+ mdio_write(ioaddr, phy_addr, 0, mii_bmcr);
-+ mdio_write(ioaddr, phy_addr, 4, advertising);
-+#endif
-+ }
-+ sp->stats.tx_errors++;
-+ dev->trans_start = jiffies;
- return;
- }
-
-+/* Handle the interrupt cases when something unexpected happens. */
-+static void speedo_intr_error(struct net_device *dev, int intr_status)
-+{
-+ long ioaddr = dev->base_addr;
-+ struct speedo_private *sp = (struct speedo_private *)dev->priv;
-+
-+ if (intr_status & IntrRxSuspend) {
-+ if ((intr_status & 0x003c) == 0x0028) /* No more Rx buffers. */
-+ outb(RxResumeNoResources, ioaddr + SCBCmd);
-+ else if ((intr_status & 0x003c) == 0x0008) { /* No resources (why?!) */
-+ printk(KERN_DEBUG "%s: Unknown receiver error, status=%#4.4x.\n",
-+ dev->name, intr_status);
-+ /* No idea of what went wrong. Restart the receiver. */
-+ outl(virt_to_bus(sp->rx_ringp[sp->cur_rx % RX_RING_SIZE]),
-+ ioaddr + SCBPointer);
-+ outb(RxStart, ioaddr + SCBCmd);
-+ }
-+ sp->stats.rx_errors++;
-+ }
-+}
-+
-+
- static int
- speedo_start_xmit(struct sk_buff *skb, struct net_device *dev)
- {
-@@ -1365,154 +1363,82 @@
- long ioaddr = dev->base_addr;
- int entry;
-
--#if ! defined(HAS_NETIF_QUEUE)
-- if (test_bit(0, (void*)&dev->tbusy) != 0) {
-+ /* Block a timer-based transmit from overlapping. This could better be
-+ done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
-+ If this ever occurs the queue layer is doing something evil! */
-+ if (netif_pause_tx_queue(dev) != 0) {
- int tickssofar = jiffies - dev->trans_start;
- if (tickssofar < TX_TIMEOUT - 2)
- return 1;
- if (tickssofar < TX_TIMEOUT) {
- /* Reap sent packets from the full Tx queue. */
-- unsigned long flags;
-- /* Take a spinlock to make wait_for_cmd_done and sending the
-- command atomic. --SAW */
-- spin_lock_irqsave(&sp->lock, flags);
-- wait_for_cmd_done(ioaddr + SCBCmd);
- outw(SCBTriggerIntr, ioaddr + SCBCmd);
-- spin_unlock_irqrestore(&sp->lock, flags);
- return 1;
- }
- speedo_tx_timeout(dev);
- return 1;
- }
--#endif
-+
-+ /* Caution: the write order is important here, set the base address
-+ with the "ownership" bits last. */
-
- { /* Prevent interrupts from changing the Tx ring from underneath us. */
- unsigned long flags;
-
- spin_lock_irqsave(&sp->lock, flags);
--
-- /* Check if there are enough space. */
-- if ((int)(sp->cur_tx - sp->dirty_tx) >= TX_QUEUE_LIMIT) {
-- printk(KERN_ERR "%s: incorrect tbusy state, fixed.\n", dev->name);
-- netif_stop_queue(dev);
-- sp->tx_full = 1;
-- spin_unlock_irqrestore(&sp->lock, flags);
-- return 1;
-- }
--
- /* Calculate the Tx descriptor entry. */
-- entry = sp->cur_tx++ % TX_RING_SIZE;
-+ entry = sp->cur_tx % TX_RING_SIZE;
-
- sp->tx_skbuff[entry] = skb;
-+ /* Todo: be a little more clever about setting the interrupt bit. */
- sp->tx_ring[entry].status =
- cpu_to_le32(CmdSuspend | CmdTx | CmdTxFlex);
-- if (!(entry & ((TX_RING_SIZE>>2)-1)))
-- sp->tx_ring[entry].status |= cpu_to_le32(CmdIntr);
-+ sp->cur_tx++;
- sp->tx_ring[entry].link =
- virt_to_le32desc(&sp->tx_ring[sp->cur_tx % TX_RING_SIZE]);
-+ /* We may nominally release the lock here. */
- sp->tx_ring[entry].tx_desc_addr =
- virt_to_le32desc(&sp->tx_ring[entry].tx_buf_addr0);
- /* The data region is always in one buffer descriptor. */
- sp->tx_ring[entry].count = cpu_to_le32(sp->tx_threshold);
- sp->tx_ring[entry].tx_buf_addr0 = virt_to_le32desc(skb->data);
- sp->tx_ring[entry].tx_buf_size0 = cpu_to_le32(skb->len);
-- /* Trigger the command unit resume. */
-- wait_for_cmd_done(ioaddr + SCBCmd);
-- clear_suspend(sp->last_cmd);
-- /* We want the time window between clearing suspend flag on the previous
-- command and resuming CU to be as small as possible.
-- Interrupts in between are very undesired. --SAW */
-- outb(CUResume, ioaddr + SCBCmd);
-- sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry];
--
-- /* Leave room for set_rx_mode(). If there is no more space than reserved
-- for multicast filter mark the ring as full. */
-- if ((int)(sp->cur_tx - sp->dirty_tx) >= TX_QUEUE_LIMIT) {
-- netif_stop_queue(dev);
-- sp->tx_full = 1;
-+ /* Todo: perhaps leave the interrupt bit set if the Tx queue is more
-+ than half full. Argument against: we should be receiving packets
-+ and scavenging the queue. Argument for: if so, it shouldn't
-+ matter. */
-+ {
-+ struct descriptor *last_cmd = sp->last_cmd;
-+ sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry];
-+ clear_suspend(last_cmd);
- }
--
-+ if (sp->cur_tx - sp->dirty_tx >= TX_QUEUE_LIMIT) {
-+ sp->tx_full = 1;
-+ netif_stop_tx_queue(dev);
-+ } else
-+ netif_unpause_tx_queue(dev);
- spin_unlock_irqrestore(&sp->lock, flags);
- }
--
-+ wait_for_cmd_done(dev);
-+ outb(CUResume, ioaddr + SCBCmd);
- dev->trans_start = jiffies;
-
- return 0;
- }
-
--static void speedo_tx_buffer_gc(struct net_device *dev)
--{
-- unsigned int dirty_tx;
-- struct speedo_private *sp = (struct speedo_private *)dev->priv;
--
-- dirty_tx = sp->dirty_tx;
-- while ((int)(sp->cur_tx - dirty_tx) > 0) {
-- int entry = dirty_tx % TX_RING_SIZE;
-- int status = le32_to_cpu(sp->tx_ring[entry].status);
--
-- if (speedo_debug > 5)
-- printk(KERN_DEBUG " scavenge candidate %d status %4.4x.\n",
-- entry, status);
-- if ((status & StatusComplete) == 0)
-- break; /* It still hasn't been processed. */
-- if (status & TxUnderrun)
-- if (sp->tx_threshold < 0x01e08000) {
-- if (speedo_debug > 2)
-- printk(KERN_DEBUG "%s: TX underrun, threshold adjusted.\n",
-- dev->name);
-- sp->tx_threshold += 0x00040000;
-- }
-- /* Free the original skb. */
-- if (sp->tx_skbuff[entry]) {
-- sp->stats.tx_packets++; /* Count only user packets. */
-- sp->stats.tx_bytes += sp->tx_skbuff[entry]->len;
-- dev_free_skb(sp->tx_skbuff[entry]);
-- sp->tx_skbuff[entry] = 0;
-- }
-- dirty_tx++;
-- }
--
-- if (speedo_debug && (int)(sp->cur_tx - dirty_tx) > TX_RING_SIZE) {
-- printk(KERN_ERR "out-of-sync dirty pointer, %d vs. %d,"
-- " full=%d.\n",
-- dirty_tx, sp->cur_tx, sp->tx_full);
-- dirty_tx += TX_RING_SIZE;
-- }
--
-- while (sp->mc_setup_head != NULL
-- && (int)(dirty_tx - sp->mc_setup_head->tx - 1) > 0) {
-- struct speedo_mc_block *t;
-- if (speedo_debug > 1)
-- printk(KERN_DEBUG "%s: freeing mc frame.\n", dev->name);
-- t = sp->mc_setup_head->next;
-- kfree(sp->mc_setup_head);
-- sp->mc_setup_head = t;
-- }
-- if (sp->mc_setup_head == NULL)
-- sp->mc_setup_tail = NULL;
--
-- sp->dirty_tx = dirty_tx;
--}
--
- /* The interrupt handler does all of the Rx thread work and cleans up
- after the Tx thread. */
- static void speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
- {
- struct net_device *dev = (struct net_device *)dev_instance;
- struct speedo_private *sp;
-- long ioaddr, boguscnt = max_interrupt_work;
-- unsigned short status;
--
--#ifndef final_version
-- if (dev == NULL) {
-- printk(KERN_ERR "speedo_interrupt(): irq %d for unknown device.\n", irq);
-- return;
-- }
--#endif
-+ long ioaddr;
-+ int work_limit;
-+ u16 status;
-
- ioaddr = dev->base_addr;
- sp = (struct speedo_private *)dev->priv;
--
-+ work_limit = sp->max_interrupt_work;
- #ifndef final_version
- /* A lock to prevent simultaneous entry on SMP machines. */
- if (test_and_set_bit(0, (void*)&sp->in_interrupt)) {
-@@ -1521,211 +1447,108 @@
- sp->in_interrupt = 0; /* Avoid halting machine. */
- return;
- }
-- dev->interrupt = 1;
- #endif
-
- do {
- status = inw(ioaddr + SCBStatus);
-+
-+ if ((status & IntrAllNormal) == 0 || status == 0xffff)
-+ break;
- /* Acknowledge all of the current interrupt sources ASAP. */
-- /* Will change from 0xfc00 to 0xff00 when we start handling
-- FCP and ER interrupts --Dragan */
-- outw(status & 0xfc00, ioaddr + SCBStatus);
-+ outw(status & IntrAllNormal, ioaddr + SCBStatus);
-
-- if (speedo_debug > 3)
-+ if (sp->msg_level & NETIF_MSG_INTR)
- printk(KERN_DEBUG "%s: interrupt status=%#4.4x.\n",
- dev->name, status);
-
-- if ((status & 0xfc00) == 0)
-- break;
--
-- /* Always check if all rx buffers are allocated. --SAW */
-- speedo_refill_rx_buffers(dev, 0);
--
-- if ((status & 0x5000) || /* Packet received, or Rx error. */
-- (sp->rx_ring_state&(RrNoMem|RrPostponed)) == RrPostponed)
-- /* Need to gather the postponed packet. */
-+ if (status & (IntrRxDone|IntrRxSuspend))
- speedo_rx(dev);
-
-- if (status & 0x1000) {
-+ /* The command unit did something, scavenge finished Tx entries. */
-+ if (status & (IntrCmdDone | IntrCmdIdle | IntrDrvrIntr)) {
-+ unsigned int dirty_tx;
-+ /* We should nominally not need this lock. */
- spin_lock(&sp->lock);
-- if ((status & 0x003c) == 0x0028) { /* No more Rx buffers. */
-- struct RxFD *rxf;
-- printk(KERN_WARNING "%s: card reports no RX buffers.\n",
-- dev->name);
-- rxf = sp->rx_ringp[sp->cur_rx % RX_RING_SIZE];
-- if (rxf == NULL) {
-- if (speedo_debug > 2)
-- printk(KERN_DEBUG
-- "%s: NULL cur_rx in speedo_interrupt().\n",
-- dev->name);
-- sp->rx_ring_state |= RrNoMem|RrNoResources;
-- } else if (rxf == sp->last_rxf) {
-- if (speedo_debug > 2)
-- printk(KERN_DEBUG
-- "%s: cur_rx is last in speedo_interrupt().\n",
-- dev->name);
-- sp->rx_ring_state |= RrNoMem|RrNoResources;
-- } else
-- outb(RxResumeNoResources, ioaddr + SCBCmd);
-- } else if ((status & 0x003c) == 0x0008) { /* No resources. */
-- struct RxFD *rxf;
-- printk(KERN_WARNING "%s: card reports no resources.\n",
-- dev->name);
-- rxf = sp->rx_ringp[sp->cur_rx % RX_RING_SIZE];
-- if (rxf == NULL) {
-- if (speedo_debug > 2)
-- printk(KERN_DEBUG
-- "%s: NULL cur_rx in speedo_interrupt().\n",
-- dev->name);
-- sp->rx_ring_state |= RrNoMem|RrNoResources;
-- } else if (rxf == sp->last_rxf) {
-- if (speedo_debug > 2)
-- printk(KERN_DEBUG
-- "%s: cur_rx is last in speedo_interrupt().\n",
-- dev->name);
-- sp->rx_ring_state |= RrNoMem|RrNoResources;
-- } else {
-- /* Restart the receiver. */
-- outl(virt_to_bus(sp->rx_ringp[sp->cur_rx % RX_RING_SIZE]),
-- ioaddr + SCBPointer);
-- outb(RxStart, ioaddr + SCBCmd);
-+
-+ dirty_tx = sp->dirty_tx;
-+ while (sp->cur_tx - dirty_tx > 0) {
-+ int entry = dirty_tx % TX_RING_SIZE;
-+ int status = le32_to_cpu(sp->tx_ring[entry].status);
-+
-+ if (sp->msg_level & NETIF_MSG_INTR)
-+ printk(KERN_DEBUG " scavenge candidate %d status %4.4x.\n",
-+ entry, status);
-+ if ((status & StatusComplete) == 0) {
-+ /* Special case error check: look for descriptor that the
-+ chip skipped(?). */
-+ if (sp->cur_tx - dirty_tx > 2 &&
-+ (sp->tx_ring[(dirty_tx+1) % TX_RING_SIZE].status
-+ & cpu_to_le32(StatusComplete))) {
-+ printk(KERN_ERR "%s: Command unit failed to mark "
-+ "command %8.8x as complete at %d.\n",
-+ dev->name, status, dirty_tx);
-+ } else
-+ break; /* It still hasn't been processed. */
- }
-+ if ((status & TxUnderrun) &&
-+ (sp->tx_threshold < 0x01e08000)) {
-+ sp->tx_threshold += 0x00040000;
-+ if (sp->msg_level & NETIF_MSG_TX_ERR)
-+ printk(KERN_DEBUG "%s: Tx threshold increased, "
-+ "%#8.8x.\n", dev->name, sp->tx_threshold);
-+ }
-+ /* Free the original skb. */
-+ if (sp->tx_skbuff[entry]) {
-+ sp->stats.tx_packets++; /* Count only user packets. */
-+#if LINUX_VERSION_CODE > 0x20127
-+ sp->stats.tx_bytes += sp->tx_skbuff[entry]->len;
-+#endif
-+ dev_free_skb_irq(sp->tx_skbuff[entry]);
-+ sp->tx_skbuff[entry] = 0;
-+ } else if ((status & 0x70000) == CmdNOp)
-+ sp->mc_setup_busy = 0;
-+ dirty_tx++;
- }
-- sp->stats.rx_errors++;
-- spin_unlock(&sp->lock);
-- }
-
-- if ((sp->rx_ring_state&(RrNoMem|RrNoResources)) == RrNoResources) {
-- printk(KERN_WARNING
-- "%s: restart the receiver after a possible hang.\n",
-- dev->name);
-- spin_lock(&sp->lock);
-- /* Restart the receiver.
-- I'm not sure if it's always right to restart the receiver
-- here but I don't know another way to prevent receiver hangs.
-- 1999/12/25 SAW */
-- outl(virt_to_bus(sp->rx_ringp[sp->cur_rx % RX_RING_SIZE]),
-- ioaddr + SCBPointer);
-- outb(RxStart, ioaddr + SCBCmd);
-- sp->rx_ring_state &= ~RrNoResources;
-- spin_unlock(&sp->lock);
-- }
-+#ifndef final_version
-+ if (sp->cur_tx - dirty_tx > TX_RING_SIZE) {
-+ printk(KERN_ERR "out-of-sync dirty pointer, %d vs. %d,"
-+ " full=%d.\n",
-+ dirty_tx, sp->cur_tx, sp->tx_full);
-+ dirty_tx += TX_RING_SIZE;
-+ }
-+#endif
-
-- /* User interrupt, Command/Tx unit interrupt or CU not active. */
-- if (status & 0xA400) {
-- spin_lock(&sp->lock);
-- speedo_tx_buffer_gc(dev);
-+ sp->dirty_tx = dirty_tx;
- if (sp->tx_full
-- && (int)(sp->cur_tx - sp->dirty_tx) < TX_QUEUE_UNFULL) {
-- /* The ring is no longer full. */
-+ && sp->cur_tx - dirty_tx < TX_QUEUE_UNFULL) {
-+ /* The ring is no longer full, clear tbusy. */
- sp->tx_full = 0;
-- netif_wake_queue(dev); /* Attention: under a spinlock. --SAW */
-+ netif_resume_tx_queue(dev);
- }
- spin_unlock(&sp->lock);
- }
-
-- if (--boguscnt < 0) {
-+ if (status & IntrRxSuspend)
-+ speedo_intr_error(dev, status);
-+
-+ if (--work_limit < 0) {
- printk(KERN_ERR "%s: Too much work at interrupt, status=0x%4.4x.\n",
- dev->name, status);
- /* Clear all interrupt sources. */
-- /* Will change from 0xfc00 to 0xff00 when we start handling
-- FCP and ER interrupts --Dragan */
- outl(0xfc00, ioaddr + SCBStatus);
- break;
- }
- } while (1);
-
-- if (speedo_debug > 3)
-+ if (sp->msg_level & NETIF_MSG_INTR)
- printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
-- dev->name, inw(ioaddr + SCBStatus));
-+ dev->name, (int)inw(ioaddr + SCBStatus));
-
-- dev->interrupt = 0;
- clear_bit(0, (void*)&sp->in_interrupt);
- return;
- }
-
--static inline struct RxFD *speedo_rx_alloc(struct net_device *dev, int entry)
--{
-- struct speedo_private *sp = (struct speedo_private *)dev->priv;
-- struct RxFD *rxf;
-- struct sk_buff *skb;
-- /* Get a fresh skbuff to replace the consumed one. */
-- skb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD));
-- sp->rx_skbuff[entry] = skb;
-- if (skb == NULL) {
-- sp->rx_ringp[entry] = NULL;
-- return NULL;
-- }
-- rxf = sp->rx_ringp[entry] = (struct RxFD *)skb->tail;
-- skb->dev = dev;
-- skb_reserve(skb, sizeof(struct RxFD));
-- rxf->rx_buf_addr = virt_to_bus(skb->tail);
-- return rxf;
--}
--
--static inline void speedo_rx_link(struct net_device *dev, int entry,
-- struct RxFD *rxf)
--{
-- struct speedo_private *sp = (struct speedo_private *)dev->priv;
-- rxf->status = cpu_to_le32(0xC0000001); /* '1' for driver use only. */
-- rxf->link = 0; /* None yet. */
-- rxf->count = cpu_to_le32(PKT_BUF_SZ << 16);
-- sp->last_rxf->link = virt_to_le32desc(rxf);
-- sp->last_rxf->status &= cpu_to_le32(~0xC0000000);
-- sp->last_rxf = rxf;
--}
--
--static int speedo_refill_rx_buf(struct net_device *dev, int force)
--{
-- struct speedo_private *sp = (struct speedo_private *)dev->priv;
-- int entry;
-- struct RxFD *rxf;
--
-- entry = sp->dirty_rx % RX_RING_SIZE;
-- if (sp->rx_skbuff[entry] == NULL) {
-- rxf = speedo_rx_alloc(dev, entry);
-- if (rxf == NULL) {
-- unsigned int forw;
-- int forw_entry;
-- if (speedo_debug > 2 || !(sp->rx_ring_state & RrOOMReported)) {
-- printk(KERN_WARNING "%s: can't fill rx buffer (force %d)!\n",
-- dev->name, force);
-- speedo_show_state(dev);
-- sp->rx_ring_state |= RrOOMReported;
-- }
-- if (!force)
-- return -1; /* Better luck next time! */
-- /* Borrow an skb from one of next entries. */
-- for (forw = sp->dirty_rx + 1; forw != sp->cur_rx; forw++)
-- if (sp->rx_skbuff[forw % RX_RING_SIZE] != NULL)
-- break;
-- if (forw == sp->cur_rx)
-- return -1;
-- forw_entry = forw % RX_RING_SIZE;
-- sp->rx_skbuff[entry] = sp->rx_skbuff[forw_entry];
-- sp->rx_skbuff[forw_entry] = NULL;
-- rxf = sp->rx_ringp[forw_entry];
-- sp->rx_ringp[forw_entry] = NULL;
-- sp->rx_ringp[entry] = rxf;
-- }
-- } else {
-- rxf = sp->rx_ringp[entry];
-- }
-- speedo_rx_link(dev, entry, rxf);
-- sp->dirty_rx++;
-- sp->rx_ring_state &= ~(RrNoMem|RrOOMReported); /* Mark the progress. */
-- return 0;
--}
--
--static void speedo_refill_rx_buffers(struct net_device *dev, int force)
--{
-- struct speedo_private *sp = (struct speedo_private *)dev->priv;
--
-- /* Refill the RX ring. */
-- while ((int)(sp->cur_rx - sp->dirty_rx) > 0 &&
-- speedo_refill_rx_buf(dev, force) != -1);
--}
--
- static int
- speedo_rx(struct net_device *dev)
- {
-@@ -1733,63 +1556,48 @@
- int entry = sp->cur_rx % RX_RING_SIZE;
- int status;
- int rx_work_limit = sp->dirty_rx + RX_RING_SIZE - sp->cur_rx;
-- int alloc_ok = 1;
-
-- if (speedo_debug > 4)
-+ if (sp->msg_level & NETIF_MSG_RX_STATUS)
- printk(KERN_DEBUG " In speedo_rx().\n");
- /* If we own the next entry, it's a new packet. Send it up. */
- while (sp->rx_ringp[entry] != NULL &&
- (status = le32_to_cpu(sp->rx_ringp[entry]->status)) & RxComplete) {
-- int pkt_len = le32_to_cpu(sp->rx_ringp[entry]->count) & 0x3fff;
-+ int desc_count = le32_to_cpu(sp->rx_ringp[entry]->count);
-+ int pkt_len = desc_count & 0x07ff;
-
- if (--rx_work_limit < 0)
- break;
--
-- /* Check for a rare out-of-memory case: the current buffer is
-- the last buffer allocated in the RX ring. --SAW */
-- if (sp->last_rxf == sp->rx_ringp[entry]) {
-- /* Postpone the packet. It'll be reaped at an interrupt when this
-- packet is no longer the last packet in the ring. */
-- if (speedo_debug > 2)
-- printk(KERN_DEBUG "%s: RX packet postponed!\n",
-- dev->name);
-- sp->rx_ring_state |= RrPostponed;
-- break;
-- }
--
-- if (speedo_debug > 4)
-+ if (sp->msg_level & NETIF_MSG_RX_STATUS)
- printk(KERN_DEBUG " speedo_rx() status %8.8x len %d.\n", status,
- pkt_len);
- if ((status & (RxErrTooBig|RxOK|0x0f90)) != RxOK) {
- if (status & RxErrTooBig)
- printk(KERN_ERR "%s: Ethernet frame overran the Rx buffer, "
- "status %8.8x!\n", dev->name, status);
-- else if (! (status & RxOK)) {
-+ else if ( ! (status & RxOK)) {
- /* There was a fatal error. This *should* be impossible. */
- sp->stats.rx_errors++;
- printk(KERN_ERR "%s: Anomalous event in speedo_rx(), "
-- "status %8.8x.\n",
-- dev->name, status);
-+ "status %8.8x.\n", dev->name, status);
- }
- } else {
- struct sk_buff *skb;
-
-+ if (sp->drv_flags & HasChksum)
-+ pkt_len -= 2;
-+
- /* Check if the packet is long enough to just accept without
- copying to a properly sized skbuff. */
-- if (pkt_len < rx_copybreak
-+ if (pkt_len < sp->rx_copybreak
- && (skb = dev_alloc_skb(pkt_len + 2)) != 0) {
- skb->dev = dev;
- skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
- /* 'skb_put()' points to the start of sk_buff data area. */
--#if !defined(__alpha__)
- /* Packet is in one chunk -- we can copy + cksum. */
- eth_copy_and_sum(skb, sp->rx_skbuff[entry]->tail, pkt_len, 0);
- skb_put(skb, pkt_len);
--#else
-- memcpy(skb_put(skb, pkt_len), sp->rx_skbuff[entry]->tail,
-- pkt_len);
--#endif
- } else {
-+ void *temp;
- /* Pass up the already-filled skbuff. */
- skb = sp->rx_skbuff[entry];
- if (skb == NULL) {
-@@ -1798,27 +1606,64 @@
- break;
- }
- sp->rx_skbuff[entry] = NULL;
-- skb_put(skb, pkt_len);
-+ temp = skb_put(skb, pkt_len);
-+#if !defined(final_version) && !defined(__powerpc__)
-+ if (bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr) != temp)
-+ printk(KERN_ERR "%s: Rx consistency error -- the skbuff "
-+ "addresses do not match in speedo_rx: %p vs. %p "
-+ "/ %p.\n", dev->name,
-+ bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr),
-+ skb->head, temp);
-+#endif
- sp->rx_ringp[entry] = NULL;
- }
- skb->protocol = eth_type_trans(skb, dev);
-+ if (sp->drv_flags & HasChksum) {
-+#if 0
-+ u16 csum = get_unaligned((u16*)(skb->head + pkt_len))
-+ if (desc_count & 0x8000)
-+ skb->ip_summed = CHECKSUM_UNNECESSARY;
-+#endif
-+ }
- netif_rx(skb);
- sp->stats.rx_packets++;
-+#if LINUX_VERSION_CODE > 0x20127
- sp->stats.rx_bytes += pkt_len;
-+#endif
- }
- entry = (++sp->cur_rx) % RX_RING_SIZE;
-- sp->rx_ring_state &= ~RrPostponed;
-- /* Refill the recently taken buffers.
-- Do it one-by-one to handle traffic bursts better. */
-- if (alloc_ok && speedo_refill_rx_buf(dev, 0) == -1)
-- alloc_ok = 0;
- }
-
-- /* Try hard to refill the recently taken buffers. */
-- speedo_refill_rx_buffers(dev, 1);
-+ /* Refill the Rx ring buffers. */
-+ for (; sp->cur_rx - sp->dirty_rx > 0; sp->dirty_rx++) {
-+ struct RxFD *rxf;
-+ entry = sp->dirty_rx % RX_RING_SIZE;
-+ if (sp->rx_skbuff[entry] == NULL) {
-+ struct sk_buff *skb;
-+ /* Get a fresh skbuff to replace the consumed one. */
-+ skb = dev_alloc_skb(sp->rx_buf_sz);
-+ sp->rx_skbuff[entry] = skb;
-+ if (skb == NULL) {
-+ sp->rx_ringp[entry] = NULL;
-+ sp->alloc_failures++;
-+ break; /* Better luck next time! */
-+ }
-+ rxf = sp->rx_ringp[entry] = (struct RxFD *)skb->tail;
-+ skb->dev = dev;
-+ skb_reserve(skb, sizeof(struct RxFD));
-+ rxf->rx_buf_addr = virt_to_le32desc(skb->tail);
-+ } else {
-+ rxf = sp->rx_ringp[entry];
-+ }
-+ rxf->status = cpu_to_le32(0xC0000001); /* '1' for driver use only. */
-+ rxf->link = 0; /* None yet. */
-+ rxf->count = cpu_to_le32((sp->rx_buf_sz - sizeof(struct RxFD)) << 16);
-+ sp->last_rxf->link = virt_to_le32desc(rxf);
-+ sp->last_rxf->status &= cpu_to_le32(~0xC0000000);
-+ sp->last_rxf = rxf;
-+ }
-
- sp->last_rx_time = jiffies;
--
- return 0;
- }
-
-@@ -1829,34 +1674,33 @@
- struct speedo_private *sp = (struct speedo_private *)dev->priv;
- int i;
-
-- dev->start = 0;
-- netif_stop_queue(dev);
-+ netif_stop_tx_queue(dev);
-
-- if (speedo_debug > 1)
-- printk(KERN_DEBUG "%s: Shutting down ethercard, status was %4.4x.\n",
-- dev->name, inw(ioaddr + SCBStatus));
-+ if (sp->msg_level & NETIF_MSG_IFDOWN)
-+ printk(KERN_DEBUG "%s: Shutting down ethercard, status was %4.4x.\n"
-+ KERN_DEBUG "%s: Cumlative allocation failures: %d.\n",
-+ dev->name, (int)inw(ioaddr + SCBStatus),
-+ dev->name, sp->alloc_failures);
-
- /* Shut off the media monitoring timer. */
-- start_bh_atomic();
- del_timer(&sp->timer);
-- end_bh_atomic();
-
- /* Shutting down the chip nicely fails to disable flow control. So.. */
- outl(PortPartialReset, ioaddr + SCBPort);
-
- free_irq(dev->irq, dev);
-
-- /* Print a few items for debugging. */
-- if (speedo_debug > 3)
-- speedo_show_state(dev);
--
-- /* Free all the skbuffs in the Rx and Tx queues. */
-+ /* Free all the skbuffs in the Rx and Tx queues. */
- for (i = 0; i < RX_RING_SIZE; i++) {
- struct sk_buff *skb = sp->rx_skbuff[i];
- sp->rx_skbuff[i] = 0;
- /* Clear the Rx descriptors. */
-- if (skb)
-+ if (skb) {
-+#if LINUX_VERSION_CODE < 0x20100
-+ skb->free = 1;
-+#endif
- dev_free_skb(skb);
-+ }
- }
-
- for (i = 0; i < TX_RING_SIZE; i++) {
-@@ -1866,18 +1710,17 @@
- if (skb)
- dev_free_skb(skb);
- }
-+ if (sp->mc_setup_frm) {
-+ kfree(sp->mc_setup_frm);
-+ sp->mc_setup_frm_len = 0;
-+ }
-
-- /* Free multicast setting blocks. */
-- for (i = 0; sp->mc_setup_head != NULL; i++) {
-- struct speedo_mc_block *t;
-- t = sp->mc_setup_head->next;
-- kfree(sp->mc_setup_head);
-- sp->mc_setup_head = t;
-- }
-- sp->mc_setup_tail = NULL;
-- if (speedo_debug > 0)
-- printk(KERN_DEBUG "%s: %d multicast blocks dropped.\n", dev->name, i);
-+ /* Print a few items for debugging. */
-+ if (sp->msg_level & NETIF_MSG_IFDOWN)
-+ speedo_show_state(dev);
-
-+ /* Alt: acpi_set_pwr_state(pdev, sp->acpi_pwr); */
-+ acpi_set_pwr_state(sp->pci_dev, ACPI_D2);
- MOD_DEC_USE_COUNT;
-
- return 0;
-@@ -1895,8 +1738,7 @@
-
- Oh, and incoming frames are dropped while executing dump-stats!
- */
--static struct enet_statistics *
--speedo_get_stats(struct net_device *dev)
-+static struct net_device_stats *speedo_get_stats(struct net_device *dev)
- {
- struct speedo_private *sp = (struct speedo_private *)dev->priv;
- long ioaddr = dev->base_addr;
-@@ -1915,14 +1757,9 @@
- sp->stats.rx_fifo_errors += le32_to_cpu(sp->lstats.rx_overrun_errs);
- sp->stats.rx_length_errors += le32_to_cpu(sp->lstats.rx_runt_errs);
- sp->lstats.done_marker = 0x0000;
-- if (dev->start) {
-- unsigned long flags;
-- /* Take a spinlock to make wait_for_cmd_done and sending the
-- command atomic. --SAW */
-- spin_lock_irqsave(&sp->lock, flags);
-- wait_for_cmd_done(ioaddr + SCBCmd);
-+ if (netif_running(dev)) {
-+ wait_for_cmd_done(dev);
- outb(CUDumpStats, ioaddr + SCBCmd);
-- spin_unlock_irqrestore(&sp->lock, flags);
- }
- }
- return &sp->stats;
-@@ -1933,26 +1770,68 @@
- struct speedo_private *sp = (struct speedo_private *)dev->priv;
- long ioaddr = dev->base_addr;
- u16 *data = (u16 *)&rq->ifr_data;
-+ u32 *data32 = (void *)&rq->ifr_data;
- int phy = sp->phy[0] & 0x1f;
-+ int saved_acpi;
-
-- switch(cmd) {
-- case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */
-+ switch(cmd) {
-+ case 0x8947: case 0x89F0:
-+ /* SIOCGMIIPHY: Get the address of the PHY in use. */
- data[0] = phy;
-- case SIOCDEVPRIVATE+1: /* Read the specified MII register. */
-- /* FIXME: these operations need to be serialized with MDIO
-- access from the timeout handler.
-- They are currently serialized only with MDIO access from the
-- timer routine. 2000/05/09 SAW */
-- start_bh_atomic();
-- data[3] = mdio_read(ioaddr, data[0], data[1]);
-- end_bh_atomic();
-+ /* Fall Through */
-+ case 0x8948: case 0x89F1:
-+ /* SIOCGMIIREG: Read the specified MII register. */
-+ saved_acpi = acpi_set_pwr_state(sp->pci_dev, ACPI_D0);
-+ data[3] = mdio_read(dev, data[0], data[1]);
-+ acpi_set_pwr_state(sp->pci_dev, saved_acpi);
- return 0;
-- case SIOCDEVPRIVATE+2: /* Write the specified MII register */
-+ case 0x8949: case 0x89F2:
-+ /* SIOCSMIIREG: Write the specified MII register */
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
-- start_bh_atomic();
-+ if (data[0] == sp->phy[0]) {
-+ u16 value = data[2];
-+ switch (data[1]) {
-+ case 0:
-+ /* Check for autonegotiation on or reset. */
-+ sp->medialock = (value & 0x9000) ? 0 : 1;
-+ if (sp->medialock) {
-+ sp->full_duplex = (value & 0x0100) ? 1 : 0;
-+ sp->rx_mode = RxInvalidMode;
-+ }
-+ break;
-+ case 4: sp->advertising = value; break;
-+ }
-+ }
-+ saved_acpi = acpi_set_pwr_state(sp->pci_dev, ACPI_D0);
- mdio_write(ioaddr, data[0], data[1], data[2]);
-- end_bh_atomic();
-+ acpi_set_pwr_state(sp->pci_dev, saved_acpi);
-+ return 0;
-+ case SIOCGPARAMS:
-+ data32[0] = sp->msg_level;
-+ data32[1] = sp->multicast_filter_limit;
-+ data32[2] = sp->max_interrupt_work;
-+ data32[3] = sp->rx_copybreak;
-+#if 0
-+ /* No room in the ioctl() to set these. */
-+ data32[4] = txfifo;
-+ data32[5] = rxfifo;
-+#endif
-+ return 0;
-+ case SIOCSPARAMS:
-+ if (!capable(CAP_NET_ADMIN))
-+ return -EPERM;
-+ sp->msg_level = data32[0];
-+ sp->multicast_filter_limit = data32[1];
-+ sp->max_interrupt_work = data32[2];
-+ sp->rx_copybreak = data32[3];
-+#if 0
-+ /* No room in the ioctl() to set these. */
-+ if (data32[4] < 16)
-+ txfifo = data32[4];
-+ if (data32[5] < 16)
-+ rxfifo = data32[5];
-+#endif
- return 0;
- default:
- return -EOPNOTSUPP;
-@@ -1978,21 +1857,18 @@
- int entry, i;
-
- if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
-- new_rx_mode = 3;
-+ new_rx_mode = AcceptAllMulticast | AcceptAllPhys;
- } else if ((dev->flags & IFF_ALLMULTI) ||
-- dev->mc_count > multicast_filter_limit) {
-- new_rx_mode = 1;
-+ dev->mc_count > sp->multicast_filter_limit) {
-+ new_rx_mode = AcceptAllMulticast;
- } else
- new_rx_mode = 0;
-
-- if (speedo_debug > 3)
-- printk(KERN_DEBUG "%s: set_rx_mode %d -> %d\n", dev->name,
-- sp->rx_mode, new_rx_mode);
--
-- if ((int)(sp->cur_tx - sp->dirty_tx) > TX_RING_SIZE - TX_MULTICAST_SIZE) {
-- /* The Tx ring is full -- don't add anything! Hope the mode will be
-- * set again later. */
-- sp->rx_mode = -1;
-+ if (sp->cur_tx - sp->dirty_tx >= TX_RING_SIZE - 1) {
-+ /* The Tx ring is full -- don't add anything! Presumably the new mode
-+ is in config_cmd_data and will be added anyway, otherwise we wait
-+ for a timer tick or the mode to change again. */
-+ sp->rx_mode = RxInvalidMode;
- return;
- }
-
-@@ -2000,40 +1876,41 @@
- u8 *config_cmd_data;
-
- spin_lock_irqsave(&sp->lock, flags);
-- entry = sp->cur_tx++ % TX_RING_SIZE;
-+ entry = sp->cur_tx % TX_RING_SIZE;
- last_cmd = sp->last_cmd;
- sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry];
-
- sp->tx_skbuff[entry] = 0; /* Redundant. */
- sp->tx_ring[entry].status = cpu_to_le32(CmdSuspend | CmdConfigure);
-+ sp->cur_tx++;
- sp->tx_ring[entry].link =
- virt_to_le32desc(&sp->tx_ring[(entry + 1) % TX_RING_SIZE]);
-+ /* We may nominally release the lock here. */
-+
- config_cmd_data = (void *)&sp->tx_ring[entry].tx_desc_addr;
- /* Construct a full CmdConfig frame. */
- memcpy(config_cmd_data, i82558_config_cmd, sizeof(i82558_config_cmd));
- config_cmd_data[1] = (txfifo << 4) | rxfifo;
- config_cmd_data[4] = rxdmacount;
- config_cmd_data[5] = txdmacount + 0x80;
-- config_cmd_data[15] |= (new_rx_mode & 2) ? 1 : 0;
-- /* 0x80 doesn't disable FC 0x84 does.
-- Disable Flow control since we are not ACK-ing any FC interrupts
-- for now. --Dragan */
-- config_cmd_data[19] = 0x84;
-+ config_cmd_data[6] |= (new_rx_mode & AcceptErr) ? 0x80 : 0;
-+ config_cmd_data[7] &= (new_rx_mode & AcceptRunt) ? ~0x01 : ~0;
-+ if (sp->drv_flags & HasChksum)
-+ config_cmd_data[9] |= 1;
-+ config_cmd_data[15] |= (new_rx_mode & AcceptAllPhys) ? 1 : 0;
-+ config_cmd_data[19] = sp->flow_ctrl ? 0xBD : 0x80;
- config_cmd_data[19] |= sp->full_duplex ? 0x40 : 0;
-- config_cmd_data[21] = (new_rx_mode & 1) ? 0x0D : 0x05;
-+ config_cmd_data[21] = (new_rx_mode & AcceptAllMulticast) ? 0x0D : 0x05;
- if (sp->phy[0] & 0x8000) { /* Use the AUI port instead. */
- config_cmd_data[15] |= 0x80;
- config_cmd_data[8] = 0;
- }
- /* Trigger the command unit resume. */
-- wait_for_cmd_done(ioaddr + SCBCmd);
-+ wait_for_cmd_done(dev);
- clear_suspend(last_cmd);
- outb(CUResume, ioaddr + SCBCmd);
-- if ((int)(sp->cur_tx - sp->dirty_tx) >= TX_QUEUE_LIMIT) {
-- netif_stop_queue(dev);
-- sp->tx_full = 1;
-- }
- spin_unlock_irqrestore(&sp->lock, flags);
-+ sp->last_cmd_time = jiffies;
- }
-
- if (new_rx_mode == 0 && dev->mc_count < 4) {
-@@ -2043,14 +1920,16 @@
- u16 *setup_params, *eaddrs;
-
- spin_lock_irqsave(&sp->lock, flags);
-- entry = sp->cur_tx++ % TX_RING_SIZE;
-+ entry = sp->cur_tx % TX_RING_SIZE;
- last_cmd = sp->last_cmd;
- sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry];
-
- sp->tx_skbuff[entry] = 0;
- sp->tx_ring[entry].status = cpu_to_le32(CmdSuspend | CmdMulticastList);
-+ sp->cur_tx++;
- sp->tx_ring[entry].link =
- virt_to_le32desc(&sp->tx_ring[(entry + 1) % TX_RING_SIZE]);
-+ /* We may nominally release the lock here. */
- sp->tx_ring[entry].tx_desc_addr = 0; /* Really MC list count. */
- setup_params = (u16 *)&sp->tx_ring[entry].tx_desc_addr;
- *setup_params++ = cpu_to_le16(dev->mc_count*6);
-@@ -2063,38 +1942,45 @@
- *setup_params++ = *eaddrs++;
- }
-
-- wait_for_cmd_done(ioaddr + SCBCmd);
-+ wait_for_cmd_done(dev);
- clear_suspend(last_cmd);
- /* Immediately trigger the command unit resume. */
- outb(CUResume, ioaddr + SCBCmd);
--
-- if ((int)(sp->cur_tx - sp->dirty_tx) >= TX_QUEUE_LIMIT) {
-- netif_stop_queue(dev);
-- sp->tx_full = 1;
-- }
- spin_unlock_irqrestore(&sp->lock, flags);
-+ sp->last_cmd_time = jiffies;
- } else if (new_rx_mode == 0) {
- struct dev_mc_list *mclist;
- u16 *setup_params, *eaddrs;
-- struct speedo_mc_block *mc_blk;
-- struct descriptor *mc_setup_frm;
-+ struct descriptor *mc_setup_frm = sp->mc_setup_frm;
- int i;
-
-- mc_blk = kmalloc(sizeof(*mc_blk) + 2 + multicast_filter_limit*6,
-- GFP_ATOMIC);
-- if (mc_blk == NULL) {
-- printk(KERN_ERR "%s: Failed to allocate a setup frame.\n",
-- dev->name);
-- sp->rx_mode = -1; /* We failed, try again. */
-+ if (sp->mc_setup_frm_len < 10 + dev->mc_count*6
-+ || sp->mc_setup_frm == NULL) {
-+ /* Allocate a full setup frame, 10bytes + <max addrs>. */
-+ if (sp->mc_setup_frm)
-+ kfree(sp->mc_setup_frm);
-+ sp->mc_setup_busy = 0;
-+ sp->mc_setup_frm_len = 10 + sp->multicast_filter_limit*6;
-+ sp->mc_setup_frm = kmalloc(sp->mc_setup_frm_len, GFP_ATOMIC);
-+ if (sp->mc_setup_frm == NULL) {
-+ printk(KERN_ERR "%s: Failed to allocate a setup frame.\n",
-+ dev->name);
-+ sp->rx_mode = RxInvalidMode; /* We failed, try again. */
-+ return;
-+ }
-+ }
-+ /* If we are busy, someone might be quickly adding to the MC list.
-+ Try again later when the list updates stop. */
-+ if (sp->mc_setup_busy) {
-+ sp->rx_mode = RxInvalidMode;
- return;
- }
-- mc_blk->next = NULL;
-- mc_setup_frm = &mc_blk->frame;
--
-+ mc_setup_frm = sp->mc_setup_frm;
- /* Fill the setup frame. */
-- if (speedo_debug > 1)
-- printk(KERN_DEBUG "%s: Constructing a setup frame at %p.\n",
-- dev->name, mc_setup_frm);
-+ if (sp->msg_level & NETIF_MSG_RXFILTER)
-+ printk(KERN_DEBUG "%s: Constructing a setup frame at %p, "
-+ "%d bytes.\n",
-+ dev->name, sp->mc_setup_frm, sp->mc_setup_frm_len);
- mc_setup_frm->cmd_status =
- cpu_to_le32(CmdSuspend | CmdIntr | CmdMulticastList);
- /* Link set below. */
-@@ -2111,81 +1997,125 @@
-
- /* Disable interrupts while playing with the Tx Cmd list. */
- spin_lock_irqsave(&sp->lock, flags);
--
-- if (sp->mc_setup_tail)
-- sp->mc_setup_tail->next = mc_blk;
-- else
-- sp->mc_setup_head = mc_blk;
-- sp->mc_setup_tail = mc_blk;
-- mc_blk->tx = sp->cur_tx;
--
-- entry = sp->cur_tx++ % TX_RING_SIZE;
-+ entry = sp->cur_tx % TX_RING_SIZE;
- last_cmd = sp->last_cmd;
- sp->last_cmd = mc_setup_frm;
-+ sp->mc_setup_busy++;
-
- /* Change the command to a NoOp, pointing to the CmdMulti command. */
- sp->tx_skbuff[entry] = 0;
- sp->tx_ring[entry].status = cpu_to_le32(CmdNOp);
-+ sp->cur_tx++;
- sp->tx_ring[entry].link = virt_to_le32desc(mc_setup_frm);
-+ /* We may nominally release the lock here. */
-
- /* Set the link in the setup frame. */
- mc_setup_frm->link =
- virt_to_le32desc(&(sp->tx_ring[(entry+1) % TX_RING_SIZE]));
-
-- wait_for_cmd_done(ioaddr + SCBCmd);
-+ wait_for_cmd_done(dev);
- clear_suspend(last_cmd);
- /* Immediately trigger the command unit resume. */
- outb(CUResume, ioaddr + SCBCmd);
--
-- if ((int)(sp->cur_tx - sp->dirty_tx) >= TX_QUEUE_LIMIT) {
-- netif_stop_queue(dev);
-- sp->tx_full = 1;
-- }
- spin_unlock_irqrestore(&sp->lock, flags);
--
-- if (speedo_debug > 5)
-- printk(" CmdMCSetup frame length %d in entry %d.\n",
-+ sp->last_cmd_time = jiffies;
-+ if (sp->msg_level & NETIF_MSG_RXFILTER)
-+ printk(KERN_DEBUG " CmdMCSetup frame length %d in entry %d.\n",
- dev->mc_count, entry);
- }
-
- sp->rx_mode = new_rx_mode;
- }
-+
-+static int speedo_pwr_event(void *dev_instance, int event)
-+{
-+ struct net_device *dev = dev_instance;
-+ struct speedo_private *np = (struct speedo_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+
-+ if (np->msg_level & NETIF_MSG_LINK)
-+ printk(KERN_DEBUG "%s: Handling power event %d.\n", dev->name, event);
-+ switch(event) {
-+ case DRV_ATTACH:
-+ MOD_INC_USE_COUNT;
-+ break;
-+ case DRV_SUSPEND:
-+ outl(PortPartialReset, ioaddr + SCBPort);
-+ break;
-+ case DRV_RESUME:
-+ speedo_resume(dev);
-+ np->rx_mode = RxInvalidMode;
-+ np->flow_ctrl = np->partner = 0;
-+ set_rx_mode(dev);
-+ break;
-+ case DRV_DETACH: {
-+ struct net_device **devp, **next;
-+ if (dev->flags & IFF_UP) {
-+ dev_close(dev);
-+ dev->flags &= ~(IFF_UP|IFF_RUNNING);
-+ }
-+ unregister_netdev(dev);
-+ release_region(dev->base_addr, pci_id_tbl[np->chip_id].io_size);
-+#ifndef USE_IO_OPS
-+ iounmap((char *)dev->base_addr);
-+#endif
-+ for (devp = &root_speedo_dev; *devp; devp = next) {
-+ next = &((struct speedo_private *)(*devp)->priv)->next_module;
-+ if (*devp == dev) {
-+ *devp = *next;
-+ break;
-+ }
-+ }
-+ if (np->priv_addr)
-+ kfree(np->priv_addr);
-+ kfree(dev);
-+ MOD_DEC_USE_COUNT;
-+ break;
-+ }
-+ case DRV_PWR_DOWN:
-+ case DRV_PWR_UP:
-+ acpi_set_pwr_state(np->pci_dev, event==DRV_PWR_DOWN ? ACPI_D3:ACPI_D0);
-+ break;
-+ case DRV_PWR_WakeOn:
-+ default:
-+ return -1;
-+ }
-+
-+ return 0;
-+}
-
--#ifdef MODULE
-+
-+#if defined(MODULE) || (LINUX_VERSION_CODE >= 0x020400)
-
- int init_module(void)
- {
- int cards_found;
-
-- if (debug >= 0 && speedo_debug != debug)
-- printk(KERN_INFO "eepro100.c: Debug level is %d.\n", debug);
-- if (debug >= 0)
-- speedo_debug = debug;
-- /* Always emit the version message. */
-- if (speedo_debug)
-- printk(KERN_INFO "%s", version);
--
-- cards_found = eepro100_init();
-- if (cards_found <= 0) {
-+ /* Emit version even if no cards detected. */
-+ printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2);
-+ cards_found = pci_drv_register(&eepro100_drv_id, NULL);
-+ if (cards_found < 0)
- printk(KERN_INFO "eepro100: No cards found, driver not installed.\n");
-- return -ENODEV;
-- }
-- return 0;
-+ return cards_found;
- }
-
--void
--cleanup_module(void)
-+void cleanup_module(void)
- {
- struct net_device *next_dev;
-
-+ pci_drv_unregister(&eepro100_drv_id);
-+
- /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
- while (root_speedo_dev) {
- struct speedo_private *sp = (void *)root_speedo_dev->priv;
- unregister_netdev(root_speedo_dev);
-- release_region(root_speedo_dev->base_addr, SPEEDO3_TOTAL_SIZE);
--#ifndef USE_IO
-+#ifdef USE_IO_OPS
-+ release_region(root_speedo_dev->base_addr,
-+ pci_id_tbl[sp->chip_id].io_size);
-+#else
- iounmap((char *)root_speedo_dev->base_addr);
- #endif
-+ acpi_set_pwr_state(sp->pci_dev, sp->acpi_pwr);
- next_dev = sp->next_module;
- if (sp->priv_addr)
- kfree(sp->priv_addr);
-@@ -2194,25 +2124,30 @@
- }
- }
-
-+#if (LINUX_VERSION_CODE >= 0x020400) && 0
-+module_init(init_module);
-+module_exit(cleanup_module);
-+#endif
-+
- #else /* not MODULE */
-
--int eepro100_probe(void)
-+int eepro100_probe(struct net_device *dev)
- {
-- int cards_found = 0;
--
-- cards_found = eepro100_init();
-+ int cards_found = pci_drv_register(&eepro100_drv_id, dev);
-
-- if (speedo_debug > 0 && cards_found)
-- printk(version);
-+ /* Only emit the version if the driver is being used. */
-+ if (cards_found >= 0)
-+ printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2);
-
-- return cards_found ? 0 : -ENODEV;
-+ return cards_found;
- }
- #endif /* MODULE */
-
- /*
- * Local variables:
-- * compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c eepro100.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
-- * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c eepro100.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
-+ * compile-command: "make KERNVER=`uname -r` eepro100.o"
-+ * compile-cmd: "gcc -DMODULE -Wall -Wstrict-prototypes -O6 -c eepro100.c"
-+ * simple-compile-command: "gcc -DMODULE -O6 -c eepro100.c"
- * c-indent-level: 4
- * c-basic-offset: 4
- * tab-width: 4
-Index: linux/src/drivers/net/epic100.c
-===================================================================
-RCS file: /cvsroot/hurd/gnumach/linux/src/drivers/net/Attic/epic100.c,v
-retrieving revision 1.1
-diff -u -r1.1 epic100.c
---- linux/src/drivers/net/epic100.c 26 Apr 1999 05:52:10 -0000 1.1
-+++ linux/src/drivers/net/epic100.c 20 Aug 2004 10:32:53 -0000
-@@ -1,135 +1,177 @@
- /* epic100.c: A SMC 83c170 EPIC/100 Fast Ethernet driver for Linux. */
- /*
-- Written 1997-1998 by Donald Becker.
-+ Written/copyright 1997-2002 by Donald Becker.
-
-- This software may be used and distributed according to the terms
-- of the GNU Public License, incorporated herein by reference.
-- All other rights reserved.
-+ This software may be used and distributed according to the terms of
-+ the GNU General Public License (GPL), incorporated herein by reference.
-+ Drivers based on or derived from this code fall under the GPL and must
-+ retain the authorship, copyright and license notice. This file is not
-+ a complete program and may only be used when the entire operating
-+ system is licensed under the GPL.
-
- This driver is for the SMC83c170/175 "EPIC" series, as used on the
- SMC EtherPower II 9432 PCI adapter, and several CardBus cards.
-
-- The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
-- Center of Excellence in Space Data and Information Sciences
-- Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
-+ The author may be reached as becker@scyld.com, or C/O
-+ Scyld Computing Corporation
-+ 914 Bay Ridge Road, Suite 220
-+ Annapolis MD 21403
-
-- Support and updates available at
-- http://cesdis.gsfc.nasa.gov/linux/drivers/epic100.html
-+ Information and updates available at
-+ http://www.scyld.com/network/epic100.html
- */
-
--static const char *version =
--"epic100.c:v1.03 8/7/98 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/epic100.html\n";
-+/* These identify the driver base version and may not be removed. */
-+static const char version[] =
-+"epic100.c:v1.18 7/22/2003 Written by Donald Becker <becker@scyld.com>\n";
-+static const char version2[] =
-+" http://www.scyld.com/network/epic100.html\n";
-
--/* A few user-configurable values. */
-+/* The user-configurable values.
-+ These may be modified when a driver module is loaded.*/
-
--/* Keep the ring sizes a power of two for efficiency.
-- Making the Tx ring too large decreases the effectiveness of channel
-- bonding and packet priority.
-- There are no ill effects from too-large receive rings. */
--#define TX_RING_SIZE 16
--#define RX_RING_SIZE 32
-+/* Message enable level: 0..31 = no..all messages. See NETIF_MSG docs. */
-+static int debug = 2;
-+
-+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-+static int max_interrupt_work = 32;
-+
-+/* Maximum number of multicast addresses to filter (vs. rx-all-multicast).
-+ This chip uses a 64 element hash table based on the Ethernet CRC. */
-+static int multicast_filter_limit = 32;
-+
-+/* Used to set a special media speed or duplex.
-+ Both 'options[]' and 'full_duplex[]' should exist for driver
-+ interoperability.
-+ The media type is usually passed in 'options[]'.
-+ The default is autonegotation for speed and duplex.
-+ This should rarely be overridden.
-+ Use option values 0x10/0x20 for 10Mbps, 0x100,0x200 for 100Mbps.
-+ Use option values 0x10 and 0x100 for forcing half duplex fixed speed.
-+ Use option values 0x20 and 0x200 for forcing full duplex operation.
-+*/
-+#define MAX_UNITS 8 /* More are supported, limit only on options */
-+static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-+static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-
- /* Set the copy breakpoint for the copy-only-tiny-frames scheme.
- Setting to > 1518 effectively disables this feature. */
--static int rx_copybreak = 200;
-+static int rx_copybreak = 0;
-
--/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
--static int max_interrupt_work = 10;
-+/* Operational parameters that are set at compile time. */
-+
-+/* Keep the ring sizes a power of two for operational efficiency.
-+ The compiler will convert <unsigned>'%'<2^N> into a bit mask.
-+ Making the Tx ring too large decreases the effectiveness of channel
-+ bonding and packet priority.
-+ Too-large receive rings only waste memory. */
-+#define TX_RING_SIZE 16
-+#define TX_QUEUE_LEN 10 /* Limit ring entries actually used. */
-+#define RX_RING_SIZE 32
-
- /* Operational parameters that usually are not changed. */
- /* Time in jiffies before concluding the transmitter is hung. */
--#define TX_TIMEOUT ((2000*HZ)/1000)
-+#define TX_TIMEOUT (6*HZ)
-
--#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/
-+/* Allocation size of Rx buffers with normal sized Ethernet frames.
-+ Do not change this value without good reason. This is not a limit,
-+ but a way to keep a consistent allocation size among drivers.
-+ */
-+#define PKT_BUF_SZ 1536
-
- /* Bytes transferred to chip before transmission starts. */
--#define TX_FIFO_THRESH 256 /* Rounded down to 4 byte units. */
-+/* Initial threshold, increased on underflow, rounded down to 4 byte units. */
-+#define TX_FIFO_THRESH 256
- #define RX_FIFO_THRESH 1 /* 0-3, 0==32, 64,96, or 3==128 bytes */
-
-+#ifndef __KERNEL__
-+#define __KERNEL__
-+#endif
-+#if !defined(__OPTIMIZE__)
-+#warning You must compile this file with the correct options!
-+#warning See the last lines of the source file.
-+#error You must compile this driver with "-O".
-+#endif
-+
- #include <linux/config.h>
--#include <linux/version.h> /* Evil, but neccessary */
--#ifdef MODULE
--#ifdef MODVERSIONS
-+#if defined(CONFIG_SMP) && ! defined(__SMP__)
-+#define __SMP__
-+#endif
-+#if defined(MODULE) && defined(CONFIG_MODVERSIONS) && ! defined(MODVERSIONS)
-+#define MODVERSIONS
-+#endif
-+
-+#include <linux/version.h>
-+#if defined(MODVERSIONS)
- #include <linux/modversions.h>
- #endif
- #include <linux/module.h>
--#else
--#define MOD_INC_USE_COUNT
--#define MOD_DEC_USE_COUNT
--#endif
-
- #include <linux/kernel.h>
--#include <linux/sched.h>
- #include <linux/string.h>
- #include <linux/timer.h>
--#include <linux/ptrace.h>
- #include <linux/errno.h>
- #include <linux/ioport.h>
-+#if LINUX_VERSION_CODE >= 0x20400
-+#include <linux/slab.h>
-+#else
- #include <linux/malloc.h>
-+#endif
- #include <linux/interrupt.h>
- #include <linux/pci.h>
--#if LINUX_VERSION_CODE >= 0x20155
--#define PCI_SUPPORT_VER2
--#else
--#include <linux/bios32.h>
--#endif
- #include <linux/delay.h>
--
--#include <asm/processor.h> /* Processor type for cache alignment. */
--#include <asm/bitops.h>
--#include <asm/io.h>
--#include <asm/dma.h>
--
- #include <linux/netdevice.h>
- #include <linux/etherdevice.h>
- #include <linux/skbuff.h>
-+#include <asm/bitops.h>
-+#include <asm/io.h>
-
--/* Kernel compatibility defines, common to David Hind's PCMCIA package.
-- This is only in the support-all-kernels source code. */
-+#if LINUX_VERSION_CODE >= 0x20300
-+#include <linux/spinlock.h>
-+#elif LINUX_VERSION_CODE >= 0x20200
-+#include <asm/spinlock.h>
-+#endif
-
--#if ! defined (LINUX_VERSION_CODE) || LINUX_VERSION_CODE < 0x20000
--#warning This driver version is only for kernel versions 2.0.0 and later.
-+#ifdef INLINE_PCISCAN
-+#include "k_compat.h"
-+#else
-+#include "pci-scan.h"
-+#include "kern_compat.h"
- #endif
-
--#define RUN_AT(x) (jiffies + (x))
-+#if (LINUX_VERSION_CODE >= 0x20100) && defined(MODULE)
-+char kernel_version[] = UTS_RELEASE;
-+#endif
-
--#if defined(MODULE) && (LINUX_VERSION_CODE >= 0x20115)
--MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
-+MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
- MODULE_DESCRIPTION("SMC 83c170 EPIC series Ethernet driver");
-+MODULE_LICENSE("GPL");
- MODULE_PARM(debug, "i");
--MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
--MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
--MODULE_PARM(rx_copybreak, "i");
- MODULE_PARM(max_interrupt_work, "i");
--#endif
--#if LINUX_VERSION_CODE < 0x20123
--#define test_and_set_bit(val, addr) set_bit(val, addr)
--#endif
--#if LINUX_VERSION_CODE <= 0x20139
--#define net_device_stats enet_statistics
--#define NETSTATS_VER2
--#endif
--#if LINUX_VERSION_CODE < 0x20159
--#define DEV_FREE_SKB(skb) dev_kfree_skb(skb, FREE_WRITE);
--#else /* Grrr, unneeded incompatible change. */
--#define DEV_FREE_SKB(skb) dev_kfree_skb(skb);
--#endif
--
--/* The I/O extent. */
--#define EPIC_TOTAL_SIZE 0x100
--
--static int epic_debug = 1;
-+MODULE_PARM(rx_copybreak, "i");
-+MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
-+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
-+MODULE_PARM(multicast_filter_limit, "i");
-+MODULE_PARM_DESC(debug, "Driver message level (0-31)");
-+MODULE_PARM_DESC(options, "Force transceiver type or fixed speed+duplex.\n"
-+"Values are 0x10/0x20/0x100/0x200.");
-+MODULE_PARM_DESC(max_interrupt_work,
-+ "Driver maximum events handled per interrupt");
-+MODULE_PARM_DESC(full_duplex, "Non-zero to set forced full duplex.");
-+MODULE_PARM_DESC(rx_copybreak,
-+ "Breakpoint in bytes for copy-only-tiny-frames");
-+MODULE_PARM_DESC(multicast_filter_limit,
-+ "Multicast addresses before switching to Rx-all-multicast");
-
- /*
- Theory of Operation
-
- I. Board Compatibility
-
--This device driver is designed for the SMC "EPCI/100", the SMC
-+This device driver is designed for the SMC "EPIC/100", the SMC
- single-chip Ethernet controllers for PCI. This chip is used on
- the SMC EtherPower II boards.
-
--
- II. Board-specific settings
-
- PCI bus devices are configured by the system at boot time, so no jumpers
-@@ -144,35 +186,61 @@
-
- IVb. References
-
--http://www.smc.com/components/catalog/smc83c170.html
--http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html
--http://www.national.com/pf/DP/DP83840.html
-+http://www.smsc.com/main/datasheets/83c171.pdf
-+http://www.smsc.com/main/datasheets/83c175.pdf
-+http://scyld.com/expert/NWay.html
-+http://www.national.com/pf/DP/DP83840A.html
-
- IVc. Errata
-
- */
-
--/* The rest of these values should never change. */
-+static void *epic_probe1(struct pci_dev *pdev, void *init_dev,
-+ long ioaddr, int irq, int chip_idx, int find_cnt);
-+static int epic_pwr_event(void *dev_instance, int event);
-
--static struct device *epic_probe1(int pci_bus, int pci_devfn,
-- struct device *dev, int card_idx);
-+enum chip_capability_flags { MII_PWRDWN=1, TYPE2_INTR=2, NO_MII=4 };
-
--enum pci_flags_bit {
-- PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
-- PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
--};
--struct chip_info {
-- const char *name;
-- u16 vendor_id, device_id, device_id_mask, pci_flags;
-- int io_size, min_latency;
-- struct device *(*probe1)(int pci_bus, int pci_devfn, struct device *dev,
-- int chip_idx);
--} chip_tbl[] = {
-- {"SMSC EPIC/100", 0x10B8, 0x0005, 0x7fff,
-- PCI_USES_IO|PCI_USES_MASTER|PCI_ADDR0, EPIC_TOTAL_SIZE, 32, epic_probe1},
-+#define EPIC_TOTAL_SIZE 0x100
-+#ifdef USE_IO_OPS
-+#define EPIC_IOTYPE PCI_USES_MASTER|PCI_USES_IO|PCI_ADDR0
-+#else
-+#define EPIC_IOTYPE PCI_USES_MASTER|PCI_USES_MEM|PCI_ADDR1
-+#endif
-+
-+static struct pci_id_info pci_id_tbl[] = {
-+ {"SMSC EPIC 83c172", {0x000510B8, 0xffffffff, 0,0, 9,0xff},
-+ EPIC_IOTYPE, EPIC_TOTAL_SIZE, TYPE2_INTR | MII_PWRDWN, },
-+ {"SMSC EPIC 83c171", {0x000510B8, 0xffffffff, 0,0, 6,0xff},
-+ EPIC_IOTYPE, EPIC_TOTAL_SIZE, TYPE2_INTR | MII_PWRDWN, },
-+ {"SMSC EPIC/100 83c170", {0x000510B8, 0xffffffff, 0x0ab41092, 0xffffffff},
-+ EPIC_IOTYPE, EPIC_TOTAL_SIZE, TYPE2_INTR | NO_MII | MII_PWRDWN, },
-+ {"SMSC EPIC/100 83c170", {0x000510B8, 0xffffffff},
-+ EPIC_IOTYPE, EPIC_TOTAL_SIZE, TYPE2_INTR, },
-+ {"SMSC EPIC/C 83c175", {0x000610B8, 0xffffffff},
-+ EPIC_IOTYPE, EPIC_TOTAL_SIZE, TYPE2_INTR | MII_PWRDWN, },
- {0,},
- };
-
-+struct drv_id_info epic_drv_id = {
-+ "epic100", PCI_HOTSWAP, PCI_CLASS_NETWORK_ETHERNET<<8, pci_id_tbl,
-+ epic_probe1, epic_pwr_event };
-+
-+#ifndef USE_IO_OPS
-+#undef inb
-+#undef inw
-+#undef inl
-+#undef outb
-+#undef outw
-+#undef outl
-+#define inb readb
-+#define inw readw
-+#define inl readl
-+#define outb writeb
-+#define outw writew
-+#define outl writel
-+#endif
-+
- /* Offsets to registers, using the (ugh) SMC names. */
- enum epic_registers {
- COMMAND=0, INTSTAT=4, INTMASK=8, GENCTL=0x0C, NVCTL=0x10, EECTL=0x14,
-@@ -187,38 +255,40 @@
-
- /* Interrupt register bits, using my own meaningful names. */
- enum IntrStatus {
-- TxIdle=0x40000, RxIdle=0x20000, IntrSummary=0x010000,
-- PCIBusErr170=0x7000, PCIBusErr175=0x1000, PhyEvent175=0x8000,
-- RxStarted=0x0800, RxEarlyWarn=0x0400, CntFull=0x0200, TxUnderrun=0x0100,
-- TxEmpty=0x0080, TxDone=0x0020, RxError=0x0010,
-- RxOverflow=0x0008, RxFull=0x0004, RxHeader=0x0002, RxDone=0x0001,
-+ TxIdle=0x40000, RxIdle=0x20000, IntrSummary=0x010000,
-+ PCIBusErr170=0x7000, PCIBusErr175=0x1000, PhyEvent175=0x8000,
-+ RxStarted=0x0800, RxEarlyWarn=0x0400, CntFull=0x0200, TxUnderrun=0x0100,
-+ TxEmpty=0x0080, TxDone=0x0020, RxError=0x0010,
-+ RxOverflow=0x0008, RxFull=0x0004, RxHeader=0x0002, RxDone=0x0001,
-+};
-+enum CommandBits {
-+ StopRx=1, StartRx=2, TxQueued=4, RxQueued=8,
-+ StopTxDMA=0x20, StopRxDMA=0x40, RestartTx=0x80,
- };
-
- /* The EPIC100 Rx and Tx buffer descriptors. */
-
- struct epic_tx_desc {
-- s16 status;
-- u16 txlength;
-+ u32 txstatus;
- u32 bufaddr;
-- u16 buflength;
-- u16 control;
-+ u32 buflength;
- u32 next;
- };
-
- struct epic_rx_desc {
-- s16 status;
-- u16 rxlength;
-+ u32 rxstatus;
- u32 bufaddr;
- u32 buflength;
- u32 next;
- };
-
--struct epic_private {
-- char devname[8]; /* Used only for kernel debugging. */
-- const char *product_name;
-- struct device *next_module;
-+enum desc_status_bits {
-+ DescOwn=0x8000,
-+};
-
-- /* Rx and Rx rings here so that they remain paragraph aligned. */
-+#define PRIV_ALIGN 15 /* Required alignment mask */
-+struct epic_private {
-+ /* Tx and Rx rings first so that they remain paragraph aligned. */
- struct epic_rx_desc rx_ring[RX_RING_SIZE];
- struct epic_tx_desc tx_ring[TX_RING_SIZE];
- /* The saved address of a sent-in-place packet/buffer, for skfree(). */
-@@ -226,168 +296,80 @@
- /* The addresses of receive-in-place skbuffs. */
- struct sk_buff* rx_skbuff[RX_RING_SIZE];
-
-- /* Ring pointers. */
-- unsigned int cur_rx, cur_tx; /* The next free ring entry */
-- unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */
-+ struct net_device *next_module;
-+ void *priv_addr; /* Unaligned address for kfree */
-
-- u8 pci_bus, pci_dev_fn; /* PCI bus location. */
-- u16 chip_id;
-+ /* Ring pointers. */
-+ spinlock_t lock; /* Group with Tx control cache line. */
-+ unsigned int cur_tx, dirty_tx;
-+ struct descriptor *last_tx_desc;
-+
-+ unsigned int cur_rx, dirty_rx;
-+ unsigned int rx_buf_sz; /* Based on MTU+slack. */
-+ struct descriptor *last_rx_desc;
-+ long last_rx_time; /* Last Rx, in jiffies. */
-+ int rx_copybreak;
-+
-+ int msg_level;
-+ int max_interrupt_work;
-+ struct pci_dev *pci_dev; /* PCI bus location. */
-+ int chip_id, chip_flags;
-
- struct net_device_stats stats;
- struct timer_list timer; /* Media selection timer. */
-+ int tx_threshold;
-+ int genctl; /* Including Rx threshold. */
-+ u32 cur_rx_mode;
- unsigned char mc_filter[8];
-+ int multicast_filter_limit;
-+
- signed char phys[4]; /* MII device addresses. */
-+ u16 mii_bmcr; /* MII control register */
-+ u16 advertising; /* NWay media advertisement */
-+ int mii_phy_cnt;
- unsigned int tx_full:1; /* The Tx queue is full. */
- unsigned int full_duplex:1; /* Current duplex setting. */
-- unsigned int force_fd:1; /* Full-duplex operation requested. */
-- unsigned int default_port:4; /* Last dev->if_port value. */
-+ unsigned int duplex_lock:1; /* Duplex forced by the user. */
-+ unsigned int default_port; /* Last dev->if_port value. */
- unsigned int media2:4; /* Secondary monitored media port. */
- unsigned int medialock:1; /* Don't sense media type. */
- unsigned int mediasense:1; /* Media sensing in progress. */
-- int pad0, pad1; /* Used for 8-byte alignment */
- };
-
--/* Used to pass the full-duplex flag, etc. */
--#define MAX_UNITS 8
--static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
--static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
--
--static int epic_open(struct device *dev);
-+static int epic_open(struct net_device *dev);
- static int read_eeprom(long ioaddr, int location);
--static int mdio_read(long ioaddr, int phy_id, int location);
--static void mdio_write(long ioaddr, int phy_id, int location, int value);
--static void epic_restart(struct device *dev);
-+static int mdio_read(struct net_device *dev, int phy_id, int location);
-+static void mdio_write(struct net_device *dev, int phy_id, int loc, int val);
-+static void epic_start(struct net_device *dev, int restart);
-+static void check_media(struct net_device *dev);
- static void epic_timer(unsigned long data);
--static void epic_tx_timeout(struct device *dev);
--static void epic_init_ring(struct device *dev);
--static int epic_start_xmit(struct sk_buff *skb, struct device *dev);
--static int epic_rx(struct device *dev);
-+static void epic_tx_timeout(struct net_device *dev);
-+static void epic_init_ring(struct net_device *dev);
-+static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev);
-+static int epic_rx(struct net_device *dev);
- static void epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
--static int mii_ioctl(struct device *dev, struct ifreq *rq, int cmd);
--static int epic_close(struct device *dev);
--static struct net_device_stats *epic_get_stats(struct device *dev);
--static void set_rx_mode(struct device *dev);
-+static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-+static int epic_close(struct net_device *dev);
-+static struct net_device_stats *epic_get_stats(struct net_device *dev);
-+static void set_rx_mode(struct net_device *dev);
-
-
- /* A list of all installed EPIC devices, for removing the driver module. */
--static struct device *root_epic_dev = NULL;
-+static struct net_device *root_epic_dev = NULL;
-
--#ifndef CARDBUS
--int epic100_probe(struct device *dev)
-+static void *epic_probe1(struct pci_dev *pdev, void *init_dev,
-+ long ioaddr, int irq, int chip_idx, int card_idx)
- {
-- int cards_found = 0;
-- int chip_idx;
-- u16 pci_command, new_command;
-- unsigned char pci_bus, pci_device_fn;
--
--#ifdef PCI_SUPPORT_VER2
-- struct pci_dev *pcidev = NULL;
-- while ((pcidev = pci_find_class(PCI_CLASS_NETWORK_ETHERNET << 8, pcidev))
-- != NULL) {
-- long pci_ioaddr = pcidev->base_address[0] & ~3;
-- int vendor = pcidev->vendor;
-- int device = pcidev->device;
--
-- for (chip_idx = 0; chip_tbl[chip_idx].vendor_id; chip_idx++)
-- if (vendor == chip_tbl[chip_idx].vendor_id
-- && (device & chip_tbl[chip_idx].device_id_mask) ==
-- chip_tbl[chip_idx].device_id)
-- break;
-- if (chip_tbl[chip_idx].vendor_id == 0 /* Compiled out! */
-- || check_region(pci_ioaddr, chip_tbl[chip_idx].io_size))
-- continue;
-- pci_bus = pcidev->bus->number;
-- pci_device_fn = pcidev->devfn;
--#else
-- int pci_index;
--
-- if ( ! pcibios_present())
-- return -ENODEV;
--
-- for (pci_index = 0; pci_index < 0xff; pci_index++) {
-- u16 vendor, device;
-- u32 pci_ioaddr;
--
-- if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8,
-- pci_index, &pci_bus, &pci_device_fn)
-- != PCIBIOS_SUCCESSFUL)
-- break;
-- pcibios_read_config_word(pci_bus, pci_device_fn,
-- PCI_VENDOR_ID, &vendor);
-- pcibios_read_config_word(pci_bus, pci_device_fn,
-- PCI_DEVICE_ID, &device);
--
-- for (chip_idx = 0; chip_tbl[chip_idx].vendor_id; chip_idx++)
-- if (vendor == chip_tbl[chip_idx].vendor_id
-- && (device & chip_tbl[chip_idx].device_id_mask) ==
-- chip_tbl[chip_idx].device_id)
-- break;
-- if (chip_tbl[chip_idx].vendor_id == 0) /* Compiled out! */
-- continue;
--
-- pcibios_read_config_dword(pci_bus, pci_device_fn,
-- PCI_BASE_ADDRESS_0, &pci_ioaddr);
-- /* Remove I/O space marker in bit 0. */
-- pci_ioaddr &= ~3;
--
-- if (check_region(pci_ioaddr, chip_tbl[chip_idx].io_size))
-- continue;
--#endif
--
-- /* EPIC-specific code: Soft-reset the chip ere setting as master. */
-- outl(0x0001, pci_ioaddr + GENCTL);
--
-- /* Activate the card: fix for brain-damaged Win98 BIOSes. */
-- pcibios_read_config_word(pci_bus, pci_device_fn,
-- PCI_COMMAND, &pci_command);
-- new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
-- if (pci_command != new_command) {
-- printk(KERN_INFO " The PCI BIOS has not enabled Ethernet"
-- " device %4.4x-%4.4x."
-- " Updating PCI command %4.4x->%4.4x.\n",
-- vendor, device, pci_command, new_command);
-- pcibios_write_config_word(pci_bus, pci_device_fn,
-- PCI_COMMAND, new_command);
-- }
--
-- dev = chip_tbl[chip_idx].probe1(pci_bus, pci_device_fn,
-- dev, cards_found);
--
-- /* Check the latency timer. */
-- if (dev) {
-- u8 pci_latency;
-- pcibios_read_config_byte(pci_bus, pci_device_fn,
-- PCI_LATENCY_TIMER, &pci_latency);
-- if (pci_latency < chip_tbl[chip_idx].min_latency) {
-- printk(KERN_INFO " PCI latency timer (CFLT) value of %d is "
-- "unreasonably low, setting to %d.\n", pci_latency,
-- chip_tbl[chip_idx].min_latency);
-- pcibios_write_config_byte(pci_bus, pci_device_fn,
-- PCI_LATENCY_TIMER,
-- chip_tbl[chip_idx].min_latency);
-- }
-- dev = 0;
-- cards_found++;
-- }
-- }
--
-- return cards_found ? 0 : -ENODEV;
--}
--#endif /* not CARDBUS */
--
--static struct device *epic_probe1(int bus, int devfn, struct device *dev,
-- int card_idx)
--{
-- static int did_version = 0; /* Already printed version info. */
-+ struct net_device *dev;
- struct epic_private *ep;
-+ void *priv_mem;
- int i, option = 0, duplex = 0;
-- u16 chip_id;
-- u32 ioaddr;
-
-- if (epic_debug > 0 && did_version++ == 0)
-- printk(KERN_INFO "%s", version);
-+ dev = init_etherdev(init_dev, 0);
-+ if (!dev)
-+ return NULL;
-
-- if (dev && dev->mem_start) {
-+ if (dev->mem_start) {
- option = dev->mem_start;
- duplex = (dev->mem_start & 16) ? 1 : 0;
- } else if (card_idx >= 0 && card_idx < MAX_UNITS) {
-@@ -397,108 +379,125 @@
- duplex = full_duplex[card_idx];
- }
-
-- dev = init_etherdev(dev, 0);
--
-- { /* Grrrr, badly consider interface change. */
--#if defined(PCI_SUPPORT_VER2)
-- struct pci_dev *pdev = pci_find_slot(bus, devfn);
-- ioaddr = pdev->base_address[0] & ~3;
-- dev->irq = pdev->irq;
-- chip_id = pdev->device;
--#else
-- u8 irq;
-- u32 ioaddr0;
-- pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &ioaddr0);
-- pcibios_read_config_byte(bus, devfn, PCI_INTERRUPT_LINE, &irq);
-- pcibios_read_config_word(bus, devfn, PCI_DEVICE_ID, &chip_id);
-- ioaddr = ioaddr0 & ~3;
-- dev->irq = irq;
--#endif
-- }
--
- dev->base_addr = ioaddr;
-- printk(KERN_INFO "%s: SMC EPIC/100 (chip ID %4.4x) at %#3x, IRQ %d, ",
-- dev->name, chip_id, ioaddr, dev->irq);
-+ dev->irq = irq;
-+ printk(KERN_INFO "%s: %s at %#lx, %2.2x:%2.2x IRQ %d, ",
-+ dev->name, pci_id_tbl[chip_idx].name, ioaddr,
-+ pci_bus_number(pdev), pci_devfn(pdev)>>3, dev->irq);
-
- /* Bring the chip out of low-power mode. */
- outl(0x4200, ioaddr + GENCTL);
-- /* Magic?! If we don't set this bit the MII interface won't work. */
-+ /* Magic from SMSC app note 7.15 */
- outl(0x0008, ioaddr + TEST1);
-
- /* Turn on the MII transceiver. */
- outl(0x12, ioaddr + MIICfg);
-- if (chip_id == 6)
-+ if (pci_id_tbl[chip_idx].drv_flags & NO_MII)
- outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);
- outl(0x0200, ioaddr + GENCTL);
-
-- /* This could also be read from the EEPROM. */
-+ if (((1 << debug) - 1) & NETIF_MSG_MISC) {
-+ printk(KERN_DEBUG "%s: EEPROM contents\n", dev->name);
-+ for (i = 0; i < 64; i++)
-+ printk(" %4.4x%s", read_eeprom(ioaddr, i),
-+ i % 16 == 15 ? "\n" : "");
-+ }
-+
-+ /* Note: the '175 does not have a serial EEPROM. */
- for (i = 0; i < 3; i++)
-- ((u16 *)dev->dev_addr)[i] = inw(ioaddr + LAN0 + i*4);
-+ ((u16 *)dev->dev_addr)[i] = le16_to_cpu(inw(ioaddr + LAN0 + i*4));
-
- for (i = 0; i < 5; i++)
- printk("%2.2x:", dev->dev_addr[i]);
- printk("%2.2x.\n", dev->dev_addr[i]);
-
-- if (epic_debug > 1) {
-- printk(KERN_DEBUG "%s: EEPROM contents\n", dev->name);
-- for (i = 0; i < 64; i++)
-- printk(" %4.4x%s", read_eeprom(ioaddr, i),
-- i % 16 == 15 ? "\n" : "");
-- }
-+ /* Make certain elements e.g. descriptor lists are aligned. */
-+ priv_mem = kmalloc(sizeof(*ep) + PRIV_ALIGN, GFP_KERNEL);
-+ /* Check for the very unlikely case of no memory. */
-+ if (priv_mem == NULL)
-+ return NULL;
-
- /* We do a request_region() to register /proc/ioports info. */
-- request_region(ioaddr, EPIC_TOTAL_SIZE, "SMC EPIC/100");
-+ request_region(ioaddr, pci_id_tbl[chip_idx].io_size, dev->name);
-
-- /* The data structures must be quadword aligned. */
-- ep = kmalloc(sizeof(*ep), GFP_KERNEL | GFP_DMA);
-+ dev->priv = ep = (void *)(((long)priv_mem + PRIV_ALIGN) & ~PRIV_ALIGN);
- memset(ep, 0, sizeof(*ep));
-- dev->priv = ep;
-+ ep->priv_addr = priv_mem;
-
- ep->next_module = root_epic_dev;
- root_epic_dev = dev;
-
-- ep->pci_bus = bus;
-- ep->pci_dev_fn = devfn;
-- ep->chip_id = chip_id;
-+ ep->pci_dev = pdev;
-+ ep->chip_id = chip_idx;
-+ ep->chip_flags = pci_id_tbl[chip_idx].drv_flags;
-+ ep->msg_level = (1 << debug) - 1;
-+ ep->rx_copybreak = rx_copybreak;
-+ ep->max_interrupt_work = max_interrupt_work;
-+ ep->multicast_filter_limit = multicast_filter_limit;
-+
-+ /* The lower four bits are non-TP media types. */
-+ if (option > 0) {
-+ if (option & 0x220)
-+ ep->duplex_lock = ep->full_duplex = 1;
-+ ep->default_port = option & 0xFFFF;
-+ ep->medialock = 1;
-+ }
-+ if (duplex) {
-+ ep->duplex_lock = ep->full_duplex = 1;
-+ printk(KERN_INFO "%s: Forced full duplex operation requested.\n",
-+ dev->name);
-+ }
-+ dev->if_port = ep->default_port;
-
- /* Find the connected MII xcvrs.
- Doing this in open() would allow detecting external xcvrs later, but
-- takes too much time. */
-+ takes much time and no cards have external MII. */
- {
-- int phy, phy_idx;
-- for (phy = 1, phy_idx = 0; phy < 32 && phy_idx < sizeof(ep->phys);
-- phy++) {
-- int mii_status = mdio_read(ioaddr, phy, 1);
-- if (mii_status != 0xffff && mii_status != 0x0000) {
-+ int phy, phy_idx = 0;
-+ for (phy = 1; phy < 32 && phy_idx < sizeof(ep->phys); phy++) {
-+ int mii_status = mdio_read(dev, phy, 1);
-+ if (mii_status != 0xffff && mii_status != 0x0000) {
- ep->phys[phy_idx++] = phy;
-- printk(KERN_INFO "%s: MII transceiver #%d control "
-- "%4.4x status %4.4x.\n"
-- KERN_INFO "%s: Autonegotiation advertising %4.4x "
-- "link partner %4.4x.\n",
-- dev->name, phy, mdio_read(ioaddr, phy, 0), mii_status,
-- dev->name, mdio_read(ioaddr, phy, 4),
-- mdio_read(ioaddr, phy, 5));
-+ printk(KERN_INFO "%s: Located MII transceiver #%d control "
-+ "%4.4x status %4.4x.\n",
-+ dev->name, phy, mdio_read(dev, phy, 0), mii_status);
- }
- }
-- if (phy_idx == 0) {
-- printk(KERN_WARNING "%s: ***WARNING***: No MII transceiver found!\n",
-- dev->name);
-- /* Use the known PHY address of the EPII. */
-- ep->phys[0] = 3;
-+ ep->mii_phy_cnt = phy_idx;
-+ }
-+ if (ep->mii_phy_cnt == 0 && ! (ep->chip_flags & NO_MII)) {
-+ printk(KERN_WARNING "%s: ***WARNING***: No MII transceiver found!\n",
-+ dev->name);
-+ /* Use the known PHY address of the EPII. */
-+ ep->phys[0] = 3;
-+ }
-+
-+ if (ep->mii_phy_cnt) {
-+ int phy = ep->phys[0];
-+ int xcvr = ep->default_port & 0x330;
-+ if (xcvr) {
-+ printk(KERN_INFO " Forcing %dMbs %s-duplex operation.\n",
-+ (xcvr & 0x300 ? 100 : 10),
-+ (xcvr & 0x220 ? "full" : "half"));
-+ ep->mii_bmcr = xcvr & 0x300 ? 0x2000 : 0; /* 10/100mbps? */
-+ ep->mii_bmcr |= xcvr & 0x220 ? 0x0100 : 0; /* duplex */
-+ mdio_write(dev, phy, 0, ep->mii_bmcr);
-+ } else {
-+ ep->mii_bmcr = 0x3000;
-+ ep->advertising = mdio_read(dev, phy, 4);
-+ printk(KERN_INFO "%s: Autonegotiation advertising %4.4x link "
-+ "partner %4.4x.\n",
-+ dev->name, ep->advertising, mdio_read(dev, phy, 5));
- }
- }
-
-+#if EPIC_POWER_SAVE
- /* Turn off the MII xcvr (175 only!), leave the chip in low-power mode. */
-- if (ep->chip_id == 6)
-+ if (ep->chip_flags & MII_PWRDWN)
- outl(inl(ioaddr + NVCTL) & ~0x483C, ioaddr + NVCTL);
-+#endif
- outl(0x0008, ioaddr + GENCTL);
-
-- /* The lower four bits are the media type. */
-- ep->force_fd = duplex;
-- ep->default_port = option;
-- if (ep->default_port)
-- ep->medialock = 1;
--
- /* The Epic-specific entries in the device structure. */
- dev->open = &epic_open;
- dev->hard_start_xmit = &epic_start_xmit;
-@@ -522,14 +521,10 @@
- #define EE_ENB (0x0001 | EE_CS)
-
- /* Delay between EEPROM clock transitions.
-- No extra delay is needed with 33Mhz PCI, but 66Mhz is untested.
-+ This serves to flush the operation to the PCI bus.
- */
-
--#ifdef _LINUX_DELAY_H
--#define eeprom_delay(nanosec) udelay(1)
--#else
--#define eeprom_delay(nanosec) do { ; } while (0)
--#endif
-+#define eeprom_delay() inl(ee_addr)
-
- /* The EEPROM commands include the alway-set leading bit. */
- #define EE_WRITE_CMD (5 << 6)
-@@ -543,9 +538,8 @@
- int retval = 0;
- long ee_addr = ioaddr + EECTL;
- int read_cmd = location |
-- (inl(ee_addr) & 0x40) ? EE_READ64_CMD : EE_READ256_CMD;
-+ (inl(ee_addr) & 0x40 ? EE_READ64_CMD : EE_READ256_CMD);
-
-- printk("EEctrl is %x.\n", inl(ee_addr));
- outl(EE_ENB & ~EE_CS, ee_addr);
- outl(EE_ENB, ee_addr);
-
-@@ -553,18 +547,18 @@
- for (i = 12; i >= 0; i--) {
- short dataval = (read_cmd & (1 << i)) ? EE_WRITE_1 : EE_WRITE_0;
- outl(EE_ENB | dataval, ee_addr);
-- eeprom_delay(100);
-+ eeprom_delay();
- outl(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
-- eeprom_delay(150);
-+ eeprom_delay();
- }
- outl(EE_ENB, ee_addr);
-
- for (i = 16; i > 0; i--) {
- outl(EE_ENB | EE_SHIFT_CLK, ee_addr);
-- eeprom_delay(100);
-+ eeprom_delay();
- retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0);
- outl(EE_ENB, ee_addr);
-- eeprom_delay(100);
-+ eeprom_delay();
- }
-
- /* Terminate the EEPROM access. */
-@@ -574,24 +568,34 @@
-
- #define MII_READOP 1
- #define MII_WRITEOP 2
--static int mdio_read(long ioaddr, int phy_id, int location)
-+static int mdio_read(struct net_device *dev, int phy_id, int location)
- {
-+ long ioaddr = dev->base_addr;
-+ int read_cmd = (phy_id << 9) | (location << 4) | MII_READOP;
- int i;
-
-- outl((phy_id << 9) | (location << 4) | MII_READOP, ioaddr + MIICtrl);
-- /* Typical operation takes < 50 ticks. */
-- for (i = 4000; i > 0; i--)
-- if ((inl(ioaddr + MIICtrl) & MII_READOP) == 0)
-+ outl(read_cmd, ioaddr + MIICtrl);
-+ /* Typical operation takes 25 loops. */
-+ for (i = 400; i > 0; i--)
-+ if ((inl(ioaddr + MIICtrl) & MII_READOP) == 0) {
-+ /* Work around read failure bug. */
-+ if (phy_id == 1 && location < 6
-+ && inw(ioaddr + MIIData) == 0xffff) {
-+ outl(read_cmd, ioaddr + MIICtrl);
-+ continue;
-+ }
- return inw(ioaddr + MIIData);
-+ }
- return 0xffff;
- }
-
--static void mdio_write(long ioaddr, int phy_id, int location, int value)
-+static void mdio_write(struct net_device *dev, int phy_id, int loc, int value)
- {
-+ long ioaddr = dev->base_addr;
- int i;
-
- outw(value, ioaddr + MIIData);
-- outl((phy_id << 9) | (location << 4) | MII_WRITEOP, ioaddr + MIICtrl);
-+ outl((phy_id << 9) | (loc << 4) | MII_WRITEOP, ioaddr + MIICtrl);
- for (i = 10000; i > 0; i--) {
- if ((inl(ioaddr + MIICtrl) & MII_WRITEOP) == 0)
- break;
-@@ -600,89 +604,25 @@
- }
-
-
--static int
--epic_open(struct device *dev)
-+static int epic_open(struct net_device *dev)
- {
- struct epic_private *ep = (struct epic_private *)dev->priv;
-- long ioaddr = dev->base_addr;
-- int i;
-- int mii_reg5;
-- ep->full_duplex = ep->force_fd;
--
-- /* Soft reset the chip. */
-- outl(0x4001, ioaddr + GENCTL);
--
-- if (request_irq(dev->irq, &epic_interrupt, SA_SHIRQ, "SMC EPIC/100", dev))
-- return -EAGAIN;
-
- MOD_INC_USE_COUNT;
-
-- epic_init_ring(dev);
--
-- outl(0x4000, ioaddr + GENCTL);
-- /* This next magic! line by Ken Yamaguchi.. ?? */
-- outl(0x0008, ioaddr + TEST1);
--
-- /* Pull the chip out of low-power mode, enable interrupts, and set for
-- PCI read multiple. The MIIcfg setting and strange write order are
-- required by the details of which bits are reset and the transceiver
-- wiring on the Ositech CardBus card.
-- */
-- outl(0x12, ioaddr + MIICfg);
-- if (ep->chip_id == 6)
-- outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);
--
--#if defined(__powerpc__) || defined(__sparc__) /* Big endian */
-- outl(0x0432 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL);
--#else
-- outl(0x0412 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL);
--#endif
--
-- for (i = 0; i < 3; i++)
-- outl(((u16*)dev->dev_addr)[i], ioaddr + LAN0 + i*4);
--
-- outl(TX_FIFO_THRESH, ioaddr + TxThresh);
--
-- mii_reg5 = mdio_read(ioaddr, ep->phys[0], 5);
-- if (mii_reg5 != 0xffff) {
-- if ((mii_reg5 & 0x0100) || (mii_reg5 & 0x01C0) == 0x0040)
-- ep->full_duplex = 1;
-- else if (! (mii_reg5 & 0x4000))
-- mdio_write(ioaddr, ep->phys[0], 0, 0x1200);
-- if (epic_debug > 1)
-- printk(KERN_INFO "%s: Setting %s-duplex based on MII xcvr %d"
-- " register read of %4.4x.\n", dev->name,
-- ep->full_duplex ? "full" : "half", ep->phys[0], mii_reg5);
-+ if (request_irq(dev->irq, &epic_interrupt, SA_SHIRQ, dev->name, dev)) {
-+ MOD_DEC_USE_COUNT;
-+ return -EAGAIN;
- }
-
-- outl(ep->full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl);
-- outl(virt_to_bus(ep->rx_ring), ioaddr + PRxCDAR);
-- outl(virt_to_bus(ep->tx_ring), ioaddr + PTxCDAR);
--
-- /* Start the chip's Rx process. */
-- set_rx_mode(dev);
-- outl(0x000A, ioaddr + COMMAND);
--
-- dev->tbusy = 0;
-- dev->interrupt = 0;
-- dev->start = 1;
--
-- /* Enable interrupts by setting the interrupt mask. */
-- outl((ep->chip_id == 6 ? PCIBusErr175 : PCIBusErr170)
-- | CntFull | TxUnderrun | TxDone
-- | RxError | RxOverflow | RxFull | RxHeader | RxDone,
-- ioaddr + INTMASK);
--
-- if (epic_debug > 1)
-- printk(KERN_DEBUG "%s: epic_open() ioaddr %lx IRQ %d status %4.4x "
-- "%s-duplex.\n",
-- dev->name, ioaddr, dev->irq, inl(ioaddr + GENCTL),
-- ep->full_duplex ? "full" : "half");
-+ epic_init_ring(dev);
-+ check_media(dev);
-+ epic_start(dev, 0);
-
- /* Set the timer to switch to check for link beat and perhaps switch
- to an alternate media type. */
- init_timer(&ep->timer);
-- ep->timer.expires = RUN_AT((24*HZ)/10); /* 2.4 sec. */
-+ ep->timer.expires = jiffies + 3*HZ;
- ep->timer.data = (unsigned long)dev;
- ep->timer.function = &epic_timer; /* timer handler */
- add_timer(&ep->timer);
-@@ -692,7 +632,7 @@
-
- /* Reset the chip to recover from a PCI transaction error.
- This may occur at interrupt time. */
--static void epic_pause(struct device *dev)
-+static void epic_pause(struct net_device *dev)
- {
- long ioaddr = dev->base_addr;
- struct epic_private *ep = (struct epic_private *)dev->priv;
-@@ -700,7 +640,7 @@
- /* Disable interrupts by clearing the interrupt mask. */
- outl(0x00000000, ioaddr + INTMASK);
- /* Stop the chip's Tx and Rx DMA processes. */
-- outw(0x0061, ioaddr + COMMAND);
-+ outw(StopRx | StopTxDMA | StopRxDMA, ioaddr + COMMAND);
-
- /* Update the error counts. */
- if (inw(ioaddr + COMMAND) != 0xffff) {
-@@ -713,214 +653,268 @@
- epic_rx(dev);
- }
-
--static void epic_restart(struct device *dev)
-+static void epic_start(struct net_device *dev, int restart)
- {
- long ioaddr = dev->base_addr;
- struct epic_private *ep = (struct epic_private *)dev->priv;
- int i;
-
-- printk(KERN_DEBUG "%s: Restarting the EPIC chip, Rx %d/%d Tx %d/%d.\n",
-- dev->name, ep->cur_rx, ep->dirty_rx, ep->dirty_tx, ep->cur_tx);
-- /* Soft reset the chip. */
-- outl(0x0001, ioaddr + GENCTL);
--
-- udelay(1);
-- /* Duplicate code from epic_open(). */
-- outl(0x0008, ioaddr + TEST1);
--
--#if defined(__powerpc__) /* Big endian */
-- outl(0x0432 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL);
-+ if (restart) {
-+ /* Soft reset the chip. */
-+ outl(0x4001, ioaddr + GENCTL);
-+ printk(KERN_DEBUG "%s: Restarting the EPIC chip, Rx %d/%d Tx %d/%d.\n",
-+ dev->name, ep->cur_rx, ep->dirty_rx, ep->dirty_tx, ep->cur_tx);
-+ udelay(1);
-+
-+ /* This magic is documented in SMSC app note 7.15 */
-+ for (i = 16; i > 0; i--)
-+ outl(0x0008, ioaddr + TEST1);
-+ }
-+
-+#if defined(__powerpc__) || defined(__sparc__) || defined(__BIG_ENDIAN)
-+ ep->genctl = 0x0432 | (RX_FIFO_THRESH<<8);
-+#elif defined(__LITTLE_ENDIAN) || defined(__i386__)
-+ ep->genctl = 0x0412 | (RX_FIFO_THRESH<<8);
- #else
-- outl(0x0412 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL);
-+#error The byte order of this architecture is not defined.
- #endif
-- outl(0x12, ioaddr + MIICfg);
-- if (ep->chip_id == 6)
-+
-+ /* Power and reset the PHY. */
-+ if (ep->chip_flags & MII_PWRDWN)
- outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);
-+ if (restart) {
-+ outl(ep->genctl | 0x4000, ioaddr + GENCTL);
-+ inl(ioaddr + GENCTL);
-+ }
-+ outl(ep->genctl, ioaddr + GENCTL);
-+
-+ if (dev->if_port == 2 || dev->if_port == 5) { /* 10base2 or AUI */
-+ outl(0x13, ioaddr + MIICfg);
-+ printk(KERN_INFO "%s: Disabling MII PHY to use 10base2/AUI.\n",
-+ dev->name);
-+ mdio_write(dev, ep->phys[0], 0, 0x0C00);
-+ } else {
-+ outl(0x12, ioaddr + MIICfg);
-+ mdio_write(dev, ep->phys[0], 0, ep->advertising);
-+ mdio_write(dev, ep->phys[0], 0, ep->mii_bmcr);
-+ check_media(dev);
-+ }
-
- for (i = 0; i < 3; i++)
-- outl(((u16*)dev->dev_addr)[i], ioaddr + LAN0 + i*4);
-+ outl(cpu_to_le16(((u16*)dev->dev_addr)[i]), ioaddr + LAN0 + i*4);
-
-- outl(TX_FIFO_THRESH, ioaddr + TxThresh);
-+ ep->tx_threshold = TX_FIFO_THRESH;
-+ outl(ep->tx_threshold, ioaddr + TxThresh);
- outl(ep->full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl);
-- outl(virt_to_bus(&ep->rx_ring[ep->cur_rx%RX_RING_SIZE]), ioaddr + PRxCDAR);
-- outl(virt_to_bus(&ep->tx_ring[ep->dirty_tx%TX_RING_SIZE]),
-+ outl(virt_to_bus(&ep->rx_ring[ep->cur_rx % RX_RING_SIZE]),
-+ ioaddr + PRxCDAR);
-+ outl(virt_to_bus(&ep->tx_ring[ep->dirty_tx % TX_RING_SIZE]),
- ioaddr + PTxCDAR);
-
- /* Start the chip's Rx process. */
- set_rx_mode(dev);
-- outl(0x000A, ioaddr + COMMAND);
-+ outl(StartRx | RxQueued, ioaddr + COMMAND);
-+
-+ if ( ! restart)
-+ netif_start_tx_queue(dev);
-
- /* Enable interrupts by setting the interrupt mask. */
-- outl((ep->chip_id == 6 ? PCIBusErr175 : PCIBusErr170)
-- | CntFull | TxUnderrun | TxDone
-+ outl((ep->chip_flags & TYPE2_INTR ? PCIBusErr175 : PCIBusErr170)
-+ | CntFull | TxUnderrun | TxDone | TxEmpty
- | RxError | RxOverflow | RxFull | RxHeader | RxDone,
- ioaddr + INTMASK);
-- printk(KERN_DEBUG "%s: epic_restart() done, cmd status %4.4x, ctl %4.4x"
-- " interrupt %4.4x.\n",
-- dev->name, inl(ioaddr + COMMAND), inl(ioaddr + GENCTL),
-- inl(ioaddr + INTSTAT));
-+ if (ep->msg_level & NETIF_MSG_IFUP)
-+ printk(KERN_DEBUG "%s: epic_start() done, cmd status %4.4x, "
-+ "ctl %4.4x interrupt %4.4x.\n",
-+ dev->name, (int)inl(ioaddr + COMMAND),
-+ (int)inl(ioaddr + GENCTL), (int)inl(ioaddr + INTSTAT));
- return;
- }
-
-+static void check_media(struct net_device *dev)
-+{
-+ struct epic_private *ep = (struct epic_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+ int mii_reg5 = ep->mii_phy_cnt ? mdio_read(dev, ep->phys[0], 5) : 0;
-+ int negotiated = mii_reg5 & ep->advertising;
-+ int duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;
-+
-+ if (ep->duplex_lock)
-+ return;
-+ if (mii_reg5 == 0xffff) /* Bogus read */
-+ return;
-+ if (ep->full_duplex != duplex) {
-+ ep->full_duplex = duplex;
-+ printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d link"
-+ " partner capability of %4.4x.\n", dev->name,
-+ ep->full_duplex ? "full" : "half", ep->phys[0], mii_reg5);
-+ outl(ep->full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl);
-+ }
-+}
-+
- static void epic_timer(unsigned long data)
- {
-- struct device *dev = (struct device *)data;
-+ struct net_device *dev = (struct net_device *)data;
- struct epic_private *ep = (struct epic_private *)dev->priv;
- long ioaddr = dev->base_addr;
-- int next_tick = 0;
-- int mii_reg5 = mdio_read(ioaddr, ep->phys[0], 5);
-+ int next_tick = 5*HZ;
-
-- if (epic_debug > 3) {
-- printk(KERN_DEBUG "%s: Media selection tick, Tx status %8.8x.\n",
-- dev->name, inl(ioaddr + TxSTAT));
-+ if (ep->msg_level & NETIF_MSG_TIMER) {
-+ printk(KERN_DEBUG "%s: Media monitor tick, Tx status %8.8x.\n",
-+ dev->name, (int)inl(ioaddr + TxSTAT));
- printk(KERN_DEBUG "%s: Other registers are IntMask %4.4x "
- "IntStatus %4.4x RxStatus %4.4x.\n",
-- dev->name, inl(ioaddr + INTMASK), inl(ioaddr + INTSTAT),
-- inl(ioaddr + RxSTAT));
-- }
-- if (! ep->force_fd && mii_reg5 != 0xffff) {
-- int duplex = (mii_reg5&0x0100) || (mii_reg5 & 0x01C0) == 0x0040;
-- if (ep->full_duplex != duplex) {
-- ep->full_duplex = duplex;
-- printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d link"
-- " partner capability of %4.4x.\n", dev->name,
-- ep->full_duplex ? "full" : "half", ep->phys[0], mii_reg5);
-- outl(ep->full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl);
-- }
-- next_tick = 60*HZ;
-+ dev->name, (int)inl(ioaddr + INTMASK),
-+ (int)inl(ioaddr + INTSTAT), (int)inl(ioaddr + RxSTAT));
- }
-
-- if (next_tick) {
-- ep->timer.expires = RUN_AT(next_tick);
-- add_timer(&ep->timer);
-+ if (ep->cur_tx - ep->dirty_tx > 1 &&
-+ jiffies - dev->trans_start > TX_TIMEOUT) {
-+ printk(KERN_WARNING "%s: Tx hung, %d vs. %d.\n",
-+ dev->name, ep->cur_tx, ep->dirty_tx);
-+ epic_tx_timeout(dev);
- }
-+
-+ check_media(dev);
-+
-+ ep->timer.expires = jiffies + next_tick;
-+ add_timer(&ep->timer);
- }
-
--static void epic_tx_timeout(struct device *dev)
-+static void epic_tx_timeout(struct net_device *dev)
- {
- struct epic_private *ep = (struct epic_private *)dev->priv;
- long ioaddr = dev->base_addr;
-+ int tx_status = inw(ioaddr + TxSTAT);
-
-- if (epic_debug > 0) {
-- printk(KERN_WARNING "%s: Transmit timeout using MII device, "
-- "Tx status %4.4x.\n",
-- dev->name, inw(ioaddr + TxSTAT));
-- if (epic_debug > 1) {
-- printk(KERN_DEBUG "%s: Tx indices: dirty_tx %d, cur_tx %d.\n",
-- dev->name, ep->dirty_tx, ep->cur_tx);
-- }
-- }
-- if (inw(ioaddr + TxSTAT) & 0x10) { /* Tx FIFO underflow. */
-+ printk(KERN_WARNING "%s: EPIC transmit timeout, Tx status %4.4x.\n",
-+ dev->name, tx_status);
-+ if (ep->msg_level & NETIF_MSG_TX_ERR)
-+ printk(KERN_DEBUG "%s: Tx indices: dirty_tx %d, cur_tx %d.\n",
-+ dev->name, ep->dirty_tx, ep->cur_tx);
-+ if (tx_status & 0x10) { /* Tx FIFO underflow. */
- ep->stats.tx_fifo_errors++;
-- /* Restart the transmit process. */
-- outl(0x0080, ioaddr + COMMAND);
-+ outl(RestartTx, ioaddr + COMMAND);
-+ } else {
-+ epic_start(dev, 1);
-+ outl(TxQueued, dev->base_addr + COMMAND);
- }
-
-- /* Perhaps stop and restart the chip's Tx processes . */
-- /* Trigger a transmit demand. */
-- outl(0x0004, dev->base_addr + COMMAND);
--
- dev->trans_start = jiffies;
- ep->stats.tx_errors++;
- return;
- }
-
- /* Initialize the Rx and Tx rings, along with various 'dev' bits. */
--static void
--epic_init_ring(struct device *dev)
-+static void epic_init_ring(struct net_device *dev)
- {
- struct epic_private *ep = (struct epic_private *)dev->priv;
- int i;
-
- ep->tx_full = 0;
-- ep->cur_rx = ep->cur_tx = 0;
-- ep->dirty_rx = ep->dirty_tx = 0;
-+ ep->lock = (spinlock_t) SPIN_LOCK_UNLOCKED;
-+ ep->dirty_tx = ep->cur_tx = 0;
-+ ep->cur_rx = ep->dirty_rx = 0;
-+ ep->last_rx_time = jiffies;
-+ ep->rx_buf_sz = (dev->mtu <= 1522 ? PKT_BUF_SZ : dev->mtu + 14);
-
-+ /* Initialize all Rx descriptors. */
- for (i = 0; i < RX_RING_SIZE; i++) {
-- ep->rx_ring[i].status = 0x8000; /* Owned by Epic chip */
-- ep->rx_ring[i].buflength = PKT_BUF_SZ;
-- {
-- /* Note the receive buffer must be longword aligned.
-- dev_alloc_skb() provides 16 byte alignment. But do *not*
-- use skb_reserve() to align the IP header! */
-- struct sk_buff *skb;
-- skb = dev_alloc_skb(PKT_BUF_SZ);
-- ep->rx_skbuff[i] = skb;
-- if (skb == NULL)
-- break; /* Bad news! */
-- skb->dev = dev; /* Mark as being used by this device. */
-- skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
-- ep->rx_ring[i].bufaddr = virt_to_bus(skb->tail);
-- }
-+ ep->rx_ring[i].rxstatus = 0;
-+ ep->rx_ring[i].buflength = ep->rx_buf_sz;
- ep->rx_ring[i].next = virt_to_bus(&ep->rx_ring[i+1]);
-+ ep->rx_skbuff[i] = 0;
- }
- /* Mark the last entry as wrapping the ring. */
- ep->rx_ring[i-1].next = virt_to_bus(&ep->rx_ring[0]);
-
-+ /* Fill in the Rx buffers. Handle allocation failure gracefully. */
-+ for (i = 0; i < RX_RING_SIZE; i++) {
-+ struct sk_buff *skb = dev_alloc_skb(ep->rx_buf_sz);
-+ ep->rx_skbuff[i] = skb;
-+ if (skb == NULL)
-+ break;
-+ skb->dev = dev; /* Mark as being used by this device. */
-+ skb_reserve(skb, 2); /* 16 byte align the IP header. */
-+ ep->rx_ring[i].bufaddr = virt_to_bus(skb->tail);
-+ ep->rx_ring[i].rxstatus = DescOwn;
-+ }
-+ ep->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
-+
- /* The Tx buffer descriptor is filled in as needed, but we
- do need to clear the ownership bit. */
- for (i = 0; i < TX_RING_SIZE; i++) {
- ep->tx_skbuff[i] = 0;
-- ep->tx_ring[i].status = 0x0000;
-+ ep->tx_ring[i].txstatus = 0x0000;
- ep->tx_ring[i].next = virt_to_bus(&ep->tx_ring[i+1]);
- }
- ep->tx_ring[i-1].next = virt_to_bus(&ep->tx_ring[0]);
-+ return;
- }
-
--static int
--epic_start_xmit(struct sk_buff *skb, struct device *dev)
-+static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev)
- {
- struct epic_private *ep = (struct epic_private *)dev->priv;
-- int entry;
-- u32 flag;
--
-- /* Block a timer-based transmit from overlapping. This could better be
-- done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
-- if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
-- if (jiffies - dev->trans_start < TX_TIMEOUT)
-- return 1;
-- epic_tx_timeout(dev);
-+ int entry, free_count;
-+ u32 ctrl_word;
-+ unsigned long flags;
-+
-+ /* Block a timer-based transmit from overlapping. */
-+ if (netif_pause_tx_queue(dev) != 0) {
-+ /* This watchdog code is redundant with the media monitor timer. */
-+ if (jiffies - dev->trans_start > TX_TIMEOUT)
-+ epic_tx_timeout(dev);
- return 1;
- }
-
-- /* Caution: the write order is important here, set the base address
-- with the "ownership" bits last. */
-+ /* Caution: the write order is important here, set the field with the
-+ "ownership" bit last. */
-
- /* Calculate the next Tx descriptor entry. */
-+ spin_lock_irqsave(&ep->lock, flags);
-+ free_count = ep->cur_tx - ep->dirty_tx;
- entry = ep->cur_tx % TX_RING_SIZE;
-
- ep->tx_skbuff[entry] = skb;
-- ep->tx_ring[entry].txlength = (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN);
- ep->tx_ring[entry].bufaddr = virt_to_bus(skb->data);
-- ep->tx_ring[entry].buflength = skb->len;
-
-- if (ep->cur_tx - ep->dirty_tx < TX_RING_SIZE/2) {/* Typical path */
-- flag = 0x10; /* No interrupt */
-- clear_bit(0, (void*)&dev->tbusy);
-- } else if (ep->cur_tx - ep->dirty_tx == TX_RING_SIZE/2) {
-- flag = 0x14; /* Tx-done intr. */
-- clear_bit(0, (void*)&dev->tbusy);
-- } else if (ep->cur_tx - ep->dirty_tx < TX_RING_SIZE - 2) {
-- flag = 0x10; /* No Tx-done intr. */
-- clear_bit(0, (void*)&dev->tbusy);
-+ if (free_count < TX_QUEUE_LEN/2) {/* Typical path */
-+ ctrl_word = 0x100000; /* No interrupt */
-+ } else if (free_count == TX_QUEUE_LEN/2) {
-+ ctrl_word = 0x140000; /* Tx-done intr. */
-+ } else if (free_count < TX_QUEUE_LEN - 1) {
-+ ctrl_word = 0x100000; /* No Tx-done intr. */
- } else {
-- /* Leave room for two additional entries. */
-- flag = 0x14; /* Tx-done intr. */
-- ep->tx_full = 1;
-- }
-+ /* Leave room for an additional entry. */
-+ ctrl_word = 0x140000; /* Tx-done intr. */
-+ ep->tx_full = 1;
-+ }
-+ ep->tx_ring[entry].buflength = ctrl_word | skb->len;
-+ ep->tx_ring[entry].txstatus =
-+ ((skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN) << 16)
-+ | DescOwn;
-
-- ep->tx_ring[entry].control = flag;
-- ep->tx_ring[entry].status = 0x8000; /* Pass ownership to the chip. */
- ep->cur_tx++;
-+ if (ep->tx_full) {
-+ /* Check for a just-cleared queue. */
-+ if (ep->cur_tx - (volatile int)ep->dirty_tx < TX_QUEUE_LEN - 2) {
-+ netif_unpause_tx_queue(dev);
-+ ep->tx_full = 0;
-+ } else
-+ netif_stop_tx_queue(dev);
-+ } else
-+ netif_unpause_tx_queue(dev);
-+
-+ spin_unlock_irqrestore(&ep->lock, flags);
- /* Trigger an immediate transmit demand. */
-- outl(0x0004, dev->base_addr + COMMAND);
-+ outl(TxQueued, dev->base_addr + COMMAND);
-
- dev->trans_start = jiffies;
-- if (epic_debug > 4)
-+ if (ep->msg_level & NETIF_MSG_TX_QUEUED)
- printk(KERN_DEBUG "%s: Queued Tx packet size %d to slot %d, "
- "flag %2.2x Tx status %8.8x.\n",
-- dev->name, (int)skb->len, entry, flag,
-- inl(dev->base_addr + TxSTAT));
-+ dev->name, (int)skb->len, entry, ctrl_word,
-+ (int)inl(dev->base_addr + TxSTAT));
-
- return 0;
- }
-@@ -929,59 +923,48 @@
- after the Tx thread. */
- static void epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
- {
-- struct device *dev = (struct device *)dev_instance;
-- struct epic_private *ep;
-- int status, ioaddr, boguscnt = max_interrupt_work;
--
-- ioaddr = dev->base_addr;
-- ep = (struct epic_private *)dev->priv;
--
--#if defined(__i386__)
-- /* A lock to prevent simultaneous entry bug on Intel SMP machines. */
-- if (test_and_set_bit(0, (void*)&dev->interrupt)) {
-- printk(KERN_ERR"%s: SMP simultaneous entry of an interrupt handler.\n",
-- dev->name);
-- dev->interrupt = 0; /* Avoid halting machine. */
-- return;
-- }
--#else
-- if (dev->interrupt) {
-- printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name);
-- return;
-- }
-- dev->interrupt = 1;
--#endif
-+ struct net_device *dev = (struct net_device *)dev_instance;
-+ struct epic_private *ep = (struct epic_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+ int status, boguscnt = max_interrupt_work;
-
- do {
- status = inl(ioaddr + INTSTAT);
- /* Acknowledge all of the current interrupt sources ASAP. */
- outl(status & 0x00007fff, ioaddr + INTSTAT);
-
-- if (epic_debug > 4)
-- printk("%s: interrupt interrupt=%#8.8x new intstat=%#8.8x.\n",
-- dev->name, status, inl(ioaddr + INTSTAT));
-+ if (ep->msg_level & NETIF_MSG_INTR)
-+ printk(KERN_DEBUG "%s: Interrupt, status=%#8.8x new "
-+ "intstat=%#8.8x.\n",
-+ dev->name, status, (int)inl(ioaddr + INTSTAT));
-
- if ((status & IntrSummary) == 0)
- break;
-
-- if (status & (RxDone | RxStarted | RxEarlyWarn))
-+ if (status & (RxDone | RxStarted | RxEarlyWarn | RxOverflow))
- epic_rx(dev);
-
- if (status & (TxEmpty | TxDone)) {
-- int dirty_tx;
-+ unsigned int dirty_tx, cur_tx;
-
-- for (dirty_tx = ep->dirty_tx; dirty_tx < ep->cur_tx; dirty_tx++) {
-+ /* Note: if this lock becomes a problem we can narrow the locked
-+ region at the cost of occasionally grabbing the lock more
-+ times. */
-+ spin_lock(&ep->lock);
-+ cur_tx = ep->cur_tx;
-+ dirty_tx = ep->dirty_tx;
-+ for (; cur_tx - dirty_tx > 0; dirty_tx++) {
- int entry = dirty_tx % TX_RING_SIZE;
-- int txstatus = ep->tx_ring[entry].status;
-+ int txstatus = ep->tx_ring[entry].txstatus;
-
-- if (txstatus < 0)
-+ if (txstatus & DescOwn)
- break; /* It still hasn't been Txed */
-
- if ( ! (txstatus & 0x0001)) {
- /* There was an major error, log it. */
- #ifndef final_version
-- if (epic_debug > 1)
-- printk("%s: Transmit error, Tx status %8.8x.\n",
-+ if (ep->msg_level & NETIF_MSG_TX_ERR)
-+ printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",
- dev->name, txstatus);
- #endif
- ep->stats.tx_errors++;
-@@ -993,39 +976,44 @@
- if (txstatus & 0x1000) ep->stats.collisions16++;
- #endif
- } else {
-+ if (ep->msg_level & NETIF_MSG_TX_DONE)
-+ printk(KERN_DEBUG "%s: Transmit done, Tx status "
-+ "%8.8x.\n", dev->name, txstatus);
- #ifdef ETHER_STATS
- if ((txstatus & 0x0002) != 0) ep->stats.tx_deferred++;
- #endif
- ep->stats.collisions += (txstatus >> 8) & 15;
- ep->stats.tx_packets++;
-+#if LINUX_VERSION_CODE > 0x20127
-+ ep->stats.tx_bytes += ep->tx_skbuff[entry]->len;
-+#endif
- }
-
- /* Free the original skb. */
-- DEV_FREE_SKB(ep->tx_skbuff[entry]);
-+ dev_free_skb_irq(ep->tx_skbuff[entry]);
- ep->tx_skbuff[entry] = 0;
- }
-
- #ifndef final_version
-- if (ep->cur_tx - dirty_tx > TX_RING_SIZE) {
-- printk("%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
-- dev->name, dirty_tx, ep->cur_tx, ep->tx_full);
-+ if (cur_tx - dirty_tx > TX_RING_SIZE) {
-+ printk(KERN_WARNING "%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
-+ dev->name, dirty_tx, cur_tx, ep->tx_full);
- dirty_tx += TX_RING_SIZE;
- }
- #endif
--
-- if (ep->tx_full && dev->tbusy
-- && dirty_tx > ep->cur_tx - TX_RING_SIZE + 2) {
-- /* The ring is no longer full, clear tbusy. */
-- ep->tx_full = 0;
-- clear_bit(0, (void*)&dev->tbusy);
-- mark_bh(NET_BH);
-- }
--
- ep->dirty_tx = dirty_tx;
-+ if (ep->tx_full
-+ && cur_tx - dirty_tx < TX_QUEUE_LEN - 4) {
-+ /* The ring is no longer full, allow new TX entries. */
-+ ep->tx_full = 0;
-+ spin_unlock(&ep->lock);
-+ netif_resume_tx_queue(dev);
-+ } else
-+ spin_unlock(&ep->lock);
- }
-
- /* Check uncommon events all at once. */
-- if (status & (CntFull | TxUnderrun | RxOverflow |
-+ if (status & (CntFull | TxUnderrun | RxOverflow | RxFull |
- PCIBusErr170 | PCIBusErr175)) {
- if (status == 0xffffffff) /* Chip failed or removed (CardBus). */
- break;
-@@ -1036,60 +1024,65 @@
-
- if (status & TxUnderrun) { /* Tx FIFO underflow. */
- ep->stats.tx_fifo_errors++;
-- outl(1536, ioaddr + TxThresh);
-+ outl(ep->tx_threshold += 128, ioaddr + TxThresh);
- /* Restart the transmit process. */
-- outl(0x0080, ioaddr + COMMAND);
-+ outl(RestartTx, ioaddr + COMMAND);
- }
- if (status & RxOverflow) { /* Missed a Rx frame. */
- ep->stats.rx_errors++;
- }
-+ if (status & (RxOverflow | RxFull))
-+ outw(RxQueued, ioaddr + COMMAND);
- if (status & PCIBusErr170) {
- printk(KERN_ERR "%s: PCI Bus Error! EPIC status %4.4x.\n",
- dev->name, status);
- epic_pause(dev);
-- epic_restart(dev);
-+ epic_start(dev, 1);
- }
- /* Clear all error sources. */
- outl(status & 0x7f18, ioaddr + INTSTAT);
- }
- if (--boguscnt < 0) {
-- printk(KERN_ERR "%s: Too much work at interrupt, "
-+ printk(KERN_WARNING "%s: Too much work at interrupt, "
- "IntrStatus=0x%8.8x.\n",
- dev->name, status);
- /* Clear all interrupt sources. */
- outl(0x0001ffff, ioaddr + INTSTAT);
-+ /* Ill-advised: Slowly stop emitting this message. */
-+ max_interrupt_work++;
- break;
- }
- } while (1);
-
-- if (epic_debug > 3)
-- printk(KERN_DEBUG "%s: exiting interrupt, intr_status=%#4.4x.\n",
-- dev->name, inl(ioaddr + INTSTAT));
-+ if (ep->msg_level & NETIF_MSG_INTR)
-+ printk(KERN_DEBUG "%s: Exiting interrupt, intr_status=%#4.4x.\n",
-+ dev->name, status);
-
--#if defined(__i386__)
-- clear_bit(0, (void*)&dev->interrupt);
--#else
-- dev->interrupt = 0;
--#endif
- return;
- }
-
--static int epic_rx(struct device *dev)
-+static int epic_rx(struct net_device *dev)
- {
- struct epic_private *ep = (struct epic_private *)dev->priv;
- int entry = ep->cur_rx % RX_RING_SIZE;
-+ int rx_work_limit = ep->dirty_rx + RX_RING_SIZE - ep->cur_rx;
- int work_done = 0;
-
-- if (epic_debug > 4)
-+ if (ep->msg_level & NETIF_MSG_RX_STATUS)
- printk(KERN_DEBUG " In epic_rx(), entry %d %8.8x.\n", entry,
-- ep->rx_ring[entry].status);
-+ ep->rx_ring[entry].rxstatus);
- /* If we own the next entry, it's a new packet. Send it up. */
-- while (ep->rx_ring[entry].status >= 0 && ep->rx_skbuff[entry]) {
-- int status = ep->rx_ring[entry].status;
-+ while ((ep->rx_ring[entry].rxstatus & DescOwn) == 0) {
-+ int status = ep->rx_ring[entry].rxstatus;
-
-- if (epic_debug > 4)
-+ if (ep->msg_level & NETIF_MSG_RX_STATUS)
- printk(KERN_DEBUG " epic_rx() status was %8.8x.\n", status);
-+ if (--rx_work_limit < 0)
-+ break;
- if (status & 0x2006) {
-+ if (ep->msg_level & NETIF_MSG_RX_ERR)
-+ printk(KERN_DEBUG "%s: epic_rx() error status was %8.8x.\n",
-+ dev->name, status);
- if (status & 0x2000) {
- printk(KERN_WARNING "%s: Oversized Ethernet frame spanned "
- "multiple buffers, status %4.4x!\n", dev->name, status);
-@@ -1100,22 +1093,30 @@
- } else {
- /* Malloc up new buffer, compatible with net-2e. */
- /* Omit the four octet CRC from the length. */
-- short pkt_len = ep->rx_ring[entry].rxlength - 4;
-+ short pkt_len = (status >> 16) - 4;
- struct sk_buff *skb;
-
-+ if (pkt_len > PKT_BUF_SZ - 4) {
-+ printk(KERN_ERR "%s: Oversized Ethernet frame, status %x "
-+ "%d bytes.\n",
-+ dev->name, pkt_len, status);
-+ pkt_len = 1514;
-+ }
-+ if (ep->msg_level & NETIF_MSG_RX_STATUS)
-+ printk(KERN_DEBUG " netdev_rx() normal Rx pkt length %d"
-+ ", bogus_cnt %d.\n", pkt_len, rx_work_limit);
- /* Check if the packet is long enough to accept without copying
- to a minimally-sized skbuff. */
- if (pkt_len < rx_copybreak
- && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
- skb->dev = dev;
- skb_reserve(skb, 2); /* 16 byte align the IP header */
--#if 1 /* USE_IP_COPYSUM */
-- eth_copy_and_sum(skb, bus_to_virt(ep->rx_ring[entry].bufaddr),
-- pkt_len, 0);
-+#if 1 /* HAS_IP_COPYSUM */
-+ eth_copy_and_sum(skb, ep->rx_skbuff[entry]->tail, pkt_len, 0);
- skb_put(skb, pkt_len);
- #else
-- memcpy(skb_put(skb, pkt_len),
-- bus_to_virt(ep->rx_ring[entry].bufaddr), pkt_len);
-+ memcpy(skb_put(skb, pkt_len), ep->rx_skbuff[entry]->tail,
-+ pkt_len);
- #endif
- } else {
- skb_put(skb = ep->rx_skbuff[entry], pkt_len);
-@@ -1124,6 +1125,9 @@
- skb->protocol = eth_type_trans(skb, dev);
- netif_rx(skb);
- ep->stats.rx_packets++;
-+#if LINUX_VERSION_CODE > 0x20127
-+ ep->stats.rx_bytes += pkt_len;
-+#endif
- }
- work_done++;
- entry = (++ep->cur_rx) % RX_RING_SIZE;
-@@ -1134,7 +1138,7 @@
- entry = ep->dirty_rx % RX_RING_SIZE;
- if (ep->rx_skbuff[entry] == NULL) {
- struct sk_buff *skb;
-- skb = ep->rx_skbuff[entry] = dev_alloc_skb(PKT_BUF_SZ);
-+ skb = ep->rx_skbuff[entry] = dev_alloc_skb(ep->rx_buf_sz);
- if (skb == NULL)
- break;
- skb->dev = dev; /* Mark as being used by this device. */
-@@ -1142,73 +1146,60 @@
- ep->rx_ring[entry].bufaddr = virt_to_bus(skb->tail);
- work_done++;
- }
-- ep->rx_ring[entry].status = 0x8000;
-+ ep->rx_ring[entry].rxstatus = DescOwn;
- }
- return work_done;
- }
-
--static int epic_close(struct device *dev)
-+static int epic_close(struct net_device *dev)
- {
- long ioaddr = dev->base_addr;
- struct epic_private *ep = (struct epic_private *)dev->priv;
- int i;
-
-- dev->start = 0;
-- dev->tbusy = 1;
--
-- if (epic_debug > 1)
-- printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n",
-- dev->name, inl(ioaddr + INTSTAT));
-+ netif_stop_tx_queue(dev);
-
-- /* Disable interrupts by clearing the interrupt mask. */
-- outl(0x00000000, ioaddr + INTMASK);
-- /* Stop the chip's Tx and Rx DMA processes. */
-- outw(0x0061, ioaddr + COMMAND);
--
-- /* Update the error counts. */
-- ep->stats.rx_missed_errors += inb(ioaddr + MPCNT);
-- ep->stats.rx_frame_errors += inb(ioaddr + ALICNT);
-- ep->stats.rx_crc_errors += inb(ioaddr + CRCCNT);
-+ if (ep->msg_level & NETIF_MSG_IFDOWN)
-+ printk(KERN_DEBUG "%s: Shutting down ethercard, status was %8.8x.\n",
-+ dev->name, (int)inl(ioaddr + INTSTAT));
-
-+ epic_pause(dev);
- del_timer(&ep->timer);
--
- free_irq(dev->irq, dev);
-
- /* Free all the skbuffs in the Rx queue. */
- for (i = 0; i < RX_RING_SIZE; i++) {
- struct sk_buff *skb = ep->rx_skbuff[i];
- ep->rx_skbuff[i] = 0;
-- ep->rx_ring[i].status = 0; /* Not owned by Epic chip. */
-+ ep->rx_ring[i].rxstatus = 0; /* Not owned by Epic chip. */
- ep->rx_ring[i].buflength = 0;
- ep->rx_ring[i].bufaddr = 0xBADF00D0; /* An invalid address. */
- if (skb) {
- #if LINUX_VERSION_CODE < 0x20100
- skb->free = 1;
- #endif
-- DEV_FREE_SKB(skb);
-+ dev_free_skb(skb);
- }
- }
- for (i = 0; i < TX_RING_SIZE; i++) {
- if (ep->tx_skbuff[i])
-- DEV_FREE_SKB(ep->tx_skbuff[i]);
-+ dev_free_skb(ep->tx_skbuff[i]);
- ep->tx_skbuff[i] = 0;
- }
-
--
- /* Green! Leave the chip in low-power mode. */
-- outl(0x0008, ioaddr + GENCTL);
-+ outl(0x440008, ioaddr + GENCTL);
-
- MOD_DEC_USE_COUNT;
--
- return 0;
- }
-
--static struct net_device_stats *epic_get_stats(struct device *dev)
-+static struct net_device_stats *epic_get_stats(struct net_device *dev)
- {
- struct epic_private *ep = (struct epic_private *)dev->priv;
- long ioaddr = dev->base_addr;
-
-- if (dev->start) {
-+ if (netif_running(dev)) {
- /* Update the error counts. */
- ep->stats.rx_missed_errors += inb(ioaddr + MPCNT);
- ep->stats.rx_frame_errors += inb(ioaddr + ALICNT);
-@@ -1244,16 +1235,16 @@
- return crc;
- }
-
--
--static void set_rx_mode(struct device *dev)
-+static void set_rx_mode(struct net_device *dev)
- {
- long ioaddr = dev->base_addr;
- struct epic_private *ep = (struct epic_private *)dev->priv;
- unsigned char mc_filter[8]; /* Multicast hash filter */
-+ u32 new_rx_mode;
- int i;
-
- if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
-- outl(0x002C, ioaddr + RxCtrl);
-+ new_rx_mode = 0x002C;
- /* Unconditionally log net taps. */
- printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name);
- memset(mc_filter, 0xff, sizeof(mc_filter));
-@@ -1262,10 +1253,10 @@
- is never enabled. */
- /* Too many to filter perfectly -- accept all multicasts. */
- memset(mc_filter, 0xff, sizeof(mc_filter));
-- outl(0x000C, ioaddr + RxCtrl);
-+ new_rx_mode = 0x000C;
- } else if (dev->mc_count == 0) {
-- outl(0x0004, ioaddr + RxCtrl);
-- return;
-+ memset(mc_filter, 0, sizeof(mc_filter));
-+ new_rx_mode = 0x0004;
- } else { /* Never executed, for now. */
- struct dev_mc_list *mclist;
-
-@@ -1274,6 +1265,11 @@
- i++, mclist = mclist->next)
- set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x3f,
- mc_filter);
-+ new_rx_mode = 0x000C;
-+ }
-+ if (ep->cur_rx_mode != new_rx_mode) {
-+ ep->cur_rx_mode = new_rx_mode;
-+ outl(new_rx_mode, ioaddr + RxCtrl);
- }
- /* ToDo: perhaps we need to stop the Tx and Rx process here? */
- if (memcmp(mc_filter, ep->mc_filter, sizeof(mc_filter))) {
-@@ -1284,48 +1280,125 @@
- return;
- }
-
--static int mii_ioctl(struct device *dev, struct ifreq *rq, int cmd)
-+static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
- {
-+ struct epic_private *ep = (void *)dev->priv;
- long ioaddr = dev->base_addr;
- u16 *data = (u16 *)&rq->ifr_data;
-+ u32 *data32 = (void *)&rq->ifr_data;
-
- switch(cmd) {
-- case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */
-- data[0] = ((struct epic_private *)dev->priv)->phys[0] & 0x1f;
-+ case 0x8947: case 0x89F0:
-+ /* SIOCGMIIPHY: Get the address of the PHY in use. */
-+ data[0] = ep->phys[0] & 0x1f;
- /* Fall Through */
-- case SIOCDEVPRIVATE+1: /* Read the specified MII register. */
-- if (! dev->start) {
-+ case 0x8948: case 0x89F1:
-+ /* SIOCGMIIREG: Read the specified MII register. */
-+ if (! netif_running(dev)) {
- outl(0x0200, ioaddr + GENCTL);
- outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);
- }
-- data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f);
-- if (! dev->start) {
--#ifdef notdef
-+ data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f);
-+#if defined(PWRDWN_AFTER_IOCTL)
-+ if (! netif_running(dev)) {
- outl(0x0008, ioaddr + GENCTL);
- outl((inl(ioaddr + NVCTL) & ~0x483C) | 0x0000, ioaddr + NVCTL);
--#endif
- }
-+#endif
- return 0;
-- case SIOCDEVPRIVATE+2: /* Write the specified MII register */
-- if (!suser())
-+ case 0x8949: case 0x89F2:
-+ /* SIOCSMIIREG: Write the specified MII register */
-+ if (!capable(CAP_NET_ADMIN))
- return -EPERM;
-- if (! dev->start) {
-+ if (! netif_running(dev)) {
- outl(0x0200, ioaddr + GENCTL);
- outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);
- }
-- mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]);
-- if (! dev->start) {
--#ifdef notdef
-+ if (data[0] == ep->phys[0]) {
-+ u16 value = data[2];
-+ switch (data[1]) {
-+ case 0:
-+ /* Check for autonegotiation on or reset. */
-+ ep->duplex_lock = (value & 0x9000) ? 0 : 1;
-+ if (ep->duplex_lock)
-+ ep->full_duplex = (value & 0x0100) ? 1 : 0;
-+ break;
-+ case 4: ep->advertising = value; break;
-+ }
-+ /* Perhaps check_duplex(dev), depending on chip semantics. */
-+ }
-+ mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]);
-+#if defined(PWRDWN_AFTER_IOCTL)
-+ if (! netif_running(dev)) {
- outl(0x0008, ioaddr + GENCTL);
- outl((inl(ioaddr + NVCTL) & ~0x483C) | 0x0000, ioaddr + NVCTL);
--#endif
- }
-+#endif
-+ return 0;
-+ case SIOCGPARAMS:
-+ data32[0] = ep->msg_level;
-+ data32[1] = ep->multicast_filter_limit;
-+ data32[2] = ep->max_interrupt_work;
-+ data32[3] = ep->rx_copybreak;
-+ return 0;
-+ case SIOCSPARAMS:
-+ if (!capable(CAP_NET_ADMIN))
-+ return -EPERM;
-+ ep->msg_level = data32[0];
-+ ep->multicast_filter_limit = data32[1];
-+ ep->max_interrupt_work = data32[2];
-+ ep->rx_copybreak = data32[3];
- return 0;
- default:
- return -EOPNOTSUPP;
- }
- }
-
-+static int epic_pwr_event(void *dev_instance, int event)
-+{
-+ struct net_device *dev = dev_instance;
-+ struct epic_private *ep = (struct epic_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+ if (ep->msg_level & NETIF_MSG_LINK)
-+ printk(KERN_DEBUG "%s: Handling power event %d.\n", dev->name, event);
-+ switch(event) {
-+ case DRV_SUSPEND:
-+ epic_pause(dev);
-+ /* Put the chip into low-power mode. */
-+ outl(0x0008, ioaddr + GENCTL);
-+ break;
-+ case DRV_RESUME:
-+ epic_start(dev, 1);
-+ break;
-+ case DRV_DETACH: {
-+ struct net_device **devp, **next;
-+ if (dev->flags & IFF_UP) {
-+ dev_close(dev);
-+ dev->flags &= ~(IFF_UP|IFF_RUNNING);
-+ }
-+ unregister_netdev(dev);
-+ release_region(dev->base_addr, pci_id_tbl[ep->chip_id].io_size);
-+#ifndef USE_IO_OPS
-+ iounmap((char *)dev->base_addr);
-+#endif
-+ for (devp = &root_epic_dev; *devp; devp = next) {
-+ next = &((struct epic_private *)(*devp)->priv)->next_module;
-+ if (*devp == dev) {
-+ *devp = *next;
-+ break;
-+ }
-+ }
-+ if (ep->priv_addr)
-+ kfree(ep->priv_addr);
-+ kfree(dev);
-+ /*MOD_DEC_USE_COUNT;*/
-+ break;
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-
- #ifdef CARDBUS
-
-@@ -1333,19 +1406,33 @@
-
- static dev_node_t *epic_attach(dev_locator_t *loc)
- {
-- struct device *dev;
-+ struct net_device *dev;
- u16 dev_id;
-- u32 io;
-+ u32 pciaddr;
- u8 bus, devfn, irq;
-+ long ioaddr;
-
- if (loc->bus != LOC_PCI) return NULL;
- bus = loc->b.pci.bus; devfn = loc->b.pci.devfn;
-- printk(KERN_INFO "epic_attach(bus %d, function %d)\n", bus, devfn);
-- pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &io);
-+ printk(KERN_DEBUG "epic_attach(bus %d, function %d)\n", bus, devfn);
-+#ifdef USE_IO_OPS
-+ pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &pciaddr);
-+ ioaddr = pciaddr & PCI_BASE_ADDRESS_IO_MASK;
-+#else
-+ pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_1, &pciaddr);
-+ ioaddr = (long)ioremap(pciaddr & PCI_BASE_ADDRESS_MEM_MASK,
-+ pci_id_tbl[1].io_size);
-+#endif
- pcibios_read_config_byte(bus, devfn, PCI_INTERRUPT_LINE, &irq);
- pcibios_read_config_word(bus, devfn, PCI_DEVICE_ID, &dev_id);
-- io &= ~3;
-- dev = epic_probe1(bus, devfn, NULL, -1);
-+ if (ioaddr == 0 || irq == 0) {
-+ printk(KERN_ERR "The EPIC/C CardBus Ethernet interface at %d/%d was "
-+ "not assigned an %s.\n"
-+ KERN_ERR " It will not be activated.\n",
-+ bus, devfn, ioaddr == 0 ? "address" : "IRQ");
-+ return NULL;
-+ }
-+ dev = epic_probe1(pci_find_slot(bus, devfn), NULL, ioaddr, irq, 1, 0);
- if (dev) {
- dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL);
- strcpy(node->dev_name, dev->name);
-@@ -1359,7 +1446,7 @@
-
- static void epic_suspend(dev_node_t *node)
- {
-- struct device **devp, **next;
-+ struct net_device **devp, **next;
- printk(KERN_INFO "epic_suspend(%s)\n", node->dev_name);
- for (devp = &root_epic_dev; *devp; devp = next) {
- next = &((struct epic_private *)(*devp)->priv)->next_module;
-@@ -1374,19 +1461,19 @@
- }
- static void epic_resume(dev_node_t *node)
- {
-- struct device **devp, **next;
-+ struct net_device **devp, **next;
- printk(KERN_INFO "epic_resume(%s)\n", node->dev_name);
- for (devp = &root_epic_dev; *devp; devp = next) {
- next = &((struct epic_private *)(*devp)->priv)->next_module;
- if (strcmp((*devp)->name, node->dev_name) == 0) break;
- }
- if (*devp) {
-- epic_restart(*devp);
-+ epic_start(*devp, 1);
- }
- }
- static void epic_detach(dev_node_t *node)
- {
-- struct device **devp, **next;
-+ struct net_device **devp, **next;
- printk(KERN_INFO "epic_detach(%s)\n", node->dev_name);
- for (devp = &root_epic_dev; *devp; devp = next) {
- next = &((struct epic_private *)(*devp)->priv)->next_module;
-@@ -1394,6 +1481,10 @@
- }
- if (*devp) {
- unregister_netdev(*devp);
-+ release_region((*devp)->base_addr, EPIC_TOTAL_SIZE);
-+#ifndef USE_IO_OPS
-+ iounmap((char *)(*devp)->base_addr);
-+#endif
- kfree(*devp);
- *devp = *next;
- kfree(node);
-@@ -1410,48 +1501,58 @@
-
- #ifdef MODULE
-
--/* An additional parameter that may be passed in... */
--static int debug = -1;
--
--int
--init_module(void)
-+int init_module(void)
- {
-- if (debug >= 0)
-- epic_debug = debug;
-+ /* Emit version even if no cards detected. */
-+ printk(KERN_INFO "%s", version);
-
- #ifdef CARDBUS
- register_driver(&epic_ops);
- return 0;
- #else
-- return epic100_probe(0);
-+ return pci_drv_register(&epic_drv_id, NULL);
- #endif
- }
-
--void
--cleanup_module(void)
-+void cleanup_module(void)
- {
-- struct device *next_dev;
-+ struct net_device *next_dev;
-
- #ifdef CARDBUS
- unregister_driver(&epic_ops);
-+#else
-+ pci_drv_unregister(&epic_drv_id);
- #endif
-
- /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
- while (root_epic_dev) {
-- next_dev = ((struct epic_private *)root_epic_dev->priv)->next_module;
-+ struct epic_private *ep = (struct epic_private *)root_epic_dev->priv;
- unregister_netdev(root_epic_dev);
-- release_region(root_epic_dev->base_addr, EPIC_TOTAL_SIZE);
-+ release_region(root_epic_dev->base_addr, pci_id_tbl[ep->chip_id].io_size);
-+#ifndef USE_IO_OPS
-+ iounmap((char *)root_epic_dev->base_addr);
-+#endif
-+ next_dev = ep->next_module;
-+ if (ep->priv_addr)
-+ kfree(ep->priv_addr);
- kfree(root_epic_dev);
- root_epic_dev = next_dev;
- }
- }
--
-+#else
-+int epic100_probe(struct net_device *dev)
-+{
-+ int retval = pci_drv_register(&epic_drv_id, dev);
-+ if (retval >= 0)
-+ printk(KERN_INFO "%s", version);
-+ return retval;
-+}
- #endif /* MODULE */
-
- /*
- * Local variables:
-- * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c epic100.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
-- * cardbus-compile-command: "gcc -DCARDBUS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c epic100.c -o epic_cb.o -I/usr/src/pcmcia-cs-3.0.5/include/"
-+ * compile-command: "gcc -DMODULE -Wall -Wstrict-prototypes -O6 -c epic100.c"
-+ * cardbus-compile-command: "gcc -DCARDBUS -DMODULE -Wall -Wstrict-prototypes -O6 -c epic100.c -o epic_cb.o -I/usr/src/pcmcia/include/"
- * c-indent-level: 4
- * c-basic-offset: 4
- * tab-width: 4
-Index: linux/src/drivers/net/hamachi.c
-===================================================================
-RCS file: linux/src/drivers/net/hamachi.c
-diff -N linux/src/drivers/net/hamachi.c
---- /dev/null 1 Jan 1970 00:00:00 -0000
-+++ linux/src/drivers/net/hamachi.c 20 Aug 2004 10:32:53 -0000
-@@ -0,0 +1,1315 @@
-+/* hamachi.c: A Packet Engines GNIC-II Gigabit Ethernet driver for Linux. */
-+/*
-+ Written 1998-2002 by Donald Becker.
-+
-+ This software may be used and distributed according to the terms of
-+ the GNU General Public License (GPL), incorporated herein by reference.
-+ Drivers based on or derived from this code fall under the GPL and must
-+ retain the authorship, copyright and license notice. This file is not
-+ a complete program and may only be used when the entire operating
-+ system is licensed under the GPL.
-+
-+ The author may be reached as becker@scyld.com, or C/O
-+ Scyld Computing Corporation
-+ 410 Severn Ave., Suite 210
-+ Annapolis MD 21403
-+
-+ This driver is for the Packet Engines GNIC-II PCI Gigabit Ethernet
-+ adapter.
-+
-+ Support and updates available at
-+ http://www.scyld.com/network/hamachi.html
-+*/
-+
-+/* These identify the driver base version and may not be removed. */
-+static const char version1[] =
-+"hamachi.c:v1.04 11/17/2002 Written by Donald Becker <becker@scyld.com>\n";
-+static const char version2[] =
-+" http://www.scyld.com/network/hamachi.html\n";
-+
-+/* Automatically extracted configuration info:
-+probe-func: hamachi_probe
-+config-in: tristate 'Packet Engines "Hamachi" PCI Gigabit Ethernet support' CONFIG_HAMACHI
-+c-help-name: Packet Engines "Hamachi" PCI Gigabit Ethernet support
-+c-help-symbol: CONFIG_HAMACHI
-+c-help: This driver is for the Packet Engines "Hamachi" GNIC-2 Gigabit Ethernet
-+c-help: adapter.
-+c-help: Usage information and updates are available from
-+c-help: http://www.scyld.com/network/hamachi.html
-+*/
-+
-+/* The user-configurable values.
-+ These may be modified when a driver module is loaded.*/
-+
-+/* Message enable level: 0..31 = no..all messages. See NETIF_MSG docs. */
-+static int debug = 2;
-+
-+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-+static int max_interrupt_work = 40;
-+
-+/* Maximum number of multicast addresses to filter (vs. rx-all-multicast).
-+ The Hamachi has a 64 element perfect filter. */
-+static int multicast_filter_limit = 32;
-+
-+/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
-+ Setting to > 1518 effectively disables this feature. */
-+static int rx_copybreak = 0;
-+
-+/* A override for the hardware detection of bus width.
-+ Set to 1 to force 32 bit PCI bus detection. Set to 4 to force 64 bit.
-+ Add 2 to disable parity detection.
-+*/
-+static int force32 = 0;
-+
-+/* Used to pass the media type, etc.
-+ These exist for driver interoperability.
-+ Only 1 Gigabit is supported by the chip.
-+*/
-+#define MAX_UNITS 8 /* More are supported, limit only on options */
-+static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-+static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-+
-+/* Operational parameters that are set at compile time. */
-+
-+/* Keep the ring sizes a power of two for compile efficiency.
-+ The compiler will convert <unsigned>'%'<2^N> into a bit mask.
-+ Making the Tx ring too large decreases the effectiveness of channel
-+ bonding and packet priority.
-+ There are no ill effects from too-large receive rings. */
-+#define TX_RING_SIZE 64
-+#define TX_QUEUE_LEN 60 /* Limit ring entries actually used. */
-+#define RX_RING_SIZE 128
-+
-+/* Operational parameters that usually are not changed. */
-+/* Time in jiffies before concluding the transmitter is hung. */
-+#define TX_TIMEOUT (6*HZ)
-+
-+/* Allocation size of Rx buffers with normal sized Ethernet frames.
-+ Do not change this value without good reason. This is not a limit,
-+ but a way to keep a consistent allocation size among drivers.
-+ */
-+#define PKT_BUF_SZ 1536
-+
-+#ifndef __KERNEL__
-+#define __KERNEL__
-+#endif
-+#if !defined(__OPTIMIZE__)
-+#warning You must compile this file with the correct options!
-+#warning See the last lines of the source file.
-+#error You must compile this driver with "-O".
-+#endif
-+
-+#include <linux/config.h>
-+#if defined(CONFIG_SMP) && ! defined(__SMP__)
-+#define __SMP__
-+#endif
-+#if defined(MODULE) && defined(CONFIG_MODVERSIONS) && ! defined(MODVERSIONS)
-+#define MODVERSIONS
-+#endif
-+
-+#include <linux/version.h>
-+#if defined(MODVERSIONS)
-+#include <linux/modversions.h>
-+#endif
-+#include <linux/module.h>
-+
-+#include <linux/kernel.h>
-+#include <linux/string.h>
-+#include <linux/timer.h>
-+#include <linux/errno.h>
-+#include <linux/ioport.h>
-+#if LINUX_VERSION_CODE >= 0x20400
-+#include <linux/slab.h>
-+#else
-+#include <linux/malloc.h>
-+#endif
-+#include <linux/interrupt.h>
-+#include <linux/pci.h>
-+#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/skbuff.h>
-+#include <asm/processor.h> /* Processor type for cache alignment. */
-+#include <asm/bitops.h>
-+#include <asm/io.h>
-+#include <asm/unaligned.h>
-+
-+#ifdef INLINE_PCISCAN
-+#include "k_compat.h"
-+#else
-+#include "pci-scan.h"
-+#include "kern_compat.h"
-+#endif
-+
-+/* Condensed operations for readability. */
-+#if ADDRLEN == 64
-+#define virt_to_desc(addr) cpu_to_le64(virt_to_bus(addr))
-+#else
-+#define virt_to_desc(addr) cpu_to_le32(virt_to_bus(addr))
-+#define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr))
-+#endif
-+
-+#if (LINUX_VERSION_CODE >= 0x20100) && defined(MODULE)
-+char kernel_version[] = UTS_RELEASE;
-+#endif
-+
-+MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
-+MODULE_DESCRIPTION("Packet Engines 'Hamachi' GNIC-II Gigabit Ethernet driver");
-+MODULE_LICENSE("GPL");
-+MODULE_PARM(debug, "i");
-+MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
-+MODULE_PARM(rx_copybreak, "i");
-+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
-+MODULE_PARM(multicast_filter_limit, "i");
-+MODULE_PARM(max_interrupt_work, "i");
-+MODULE_PARM(force32, "i");
-+MODULE_PARM_DESC(debug, "Driver message level (0-31)");
-+MODULE_PARM_DESC(options, "Force transceiver type or fixed speed+duplex");
-+MODULE_PARM_DESC(max_interrupt_work,
-+ "Driver maximum events handled per interrupt");
-+MODULE_PARM_DESC(full_duplex,
-+ "Non-zero to force full duplex, non-negotiated link "
-+ "(unused, deprecated).");
-+MODULE_PARM_DESC(rx_copybreak,
-+ "Breakpoint in bytes for copy-only-tiny-frames");
-+MODULE_PARM_DESC(multicast_filter_limit,
-+ "Multicast addresses before switching to Rx-all-multicast");
-+MODULE_PARM_DESC(force32, "Set to 1 to force 32 bit PCI bus use.");
-+
-+/*
-+ Theory of Operation
-+
-+I. Board Compatibility
-+
-+This device driver is designed for the Packet Engines "Hamachi"
-+Gigabit Ethernet chip. The only PCA currently supported is the GNIC-II 64-bit
-+66Mhz PCI card.
-+
-+II. Board-specific settings
-+
-+No jumpers exist on the board. The chip supports software correction of
-+various motherboard wiring errors, however this driver does not support
-+that feature.
-+
-+III. Driver operation
-+
-+IIIa. Ring buffers
-+
-+The Hamachi uses a typical descriptor based bus-master architecture.
-+The descriptor list is similar to that used by the Digital Tulip.
-+This driver uses two statically allocated fixed-size descriptor lists
-+formed into rings by a branch from the final descriptor to the beginning of
-+the list. The ring sizes are set at compile time by RX/TX_RING_SIZE.
-+
-+This driver uses a zero-copy receive and transmit scheme similar my other
-+network drivers.
-+The driver allocates full frame size skbuffs for the Rx ring buffers at
-+open() time and passes the skb->data field to the Hamachi as receive data
-+buffers. When an incoming frame is less than RX_COPYBREAK bytes long,
-+a fresh skbuff is allocated and the frame is copied to the new skbuff.
-+When the incoming frame is larger, the skbuff is passed directly up the
-+protocol stack and replaced by a newly allocated skbuff.
-+
-+The RX_COPYBREAK value is chosen to trade-off the memory wasted by
-+using a full-sized skbuff for small frames vs. the copying costs of larger
-+frames. Gigabit cards are typically used on generously configured machines
-+and the underfilled buffers have negligible impact compared to the benefit of
-+a single allocation size, so the default value of zero results in never
-+copying packets.
-+
-+IIIb/c. Transmit/Receive Structure
-+
-+The Rx and Tx descriptor structure are straight-forward, with no historical
-+baggage that must be explained. Unlike the awkward DBDMA structure, there
-+are no unused fields or option bits that had only one allowable setting.
-+
-+Two details should be noted about the descriptors: The chip supports both 32
-+bit and 64 bit address structures, and the length field is overwritten on
-+the receive descriptors. The descriptor length is set in the control word
-+for each channel. The development driver uses 32 bit addresses only, however
-+64 bit addresses may be enabled for 64 bit architectures e.g. the Alpha.
-+
-+IIId. Synchronization
-+
-+This driver is very similar to my other network drivers.
-+The driver runs as two independent, single-threaded flows of control. One
-+is the send-packet routine, which enforces single-threaded use by the
-+dev->tbusy flag. The other thread is the interrupt handler, which is single
-+threaded by the hardware and other software.
-+
-+The send packet thread has partial control over the Tx ring and 'dev->tbusy'
-+flag. It sets the tbusy flag whenever it's queuing a Tx packet. If the next
-+queue slot is empty, it clears the tbusy flag when finished otherwise it sets
-+the 'hmp->tx_full' flag.
-+
-+The interrupt handler has exclusive control over the Rx ring and records stats
-+from the Tx ring. After reaping the stats, it marks the Tx queue entry as
-+empty by incrementing the dirty_tx mark. Iff the 'hmp->tx_full' flag is set, it
-+clears both the tx_full and tbusy flags.
-+
-+IV. Notes
-+
-+Thanks to Kim Stearns of Packet Engines for providing a pair of GNIC-II boards.
-+
-+IVb. References
-+
-+Hamachi Engineering Design Specification, 5/15/97
-+(Note: This version was marked "Confidential".)
-+
-+IVc. Errata
-+
-+None noted.
-+*/
-+
-+
-+/* The table for PCI detection and activation. */
-+
-+static void *hamachi_probe1(struct pci_dev *pdev, void *init_dev,
-+ long ioaddr, int irq, int chip_idx, int find_cnt);
-+enum chip_capability_flags { CanHaveMII=1, };
-+
-+static struct pci_id_info pci_id_tbl[] = {
-+ {"Packet Engines GNIC-II \"Hamachi\"", { 0x09111318, 0xffffffff,},
-+ PCI_USES_MEM | PCI_USES_MASTER | PCI_ADDR0 | PCI_ADDR_64BITS, 0x400, 0, },
-+ { 0,},
-+};
-+
-+struct drv_id_info hamachi_drv_id = {
-+ "hamachi", 0, PCI_CLASS_NETWORK_ETHERNET<<8, pci_id_tbl,
-+ hamachi_probe1, 0,
-+};
-+
-+/* Offsets to the Hamachi registers. Various sizes. */
-+enum hamachi_offsets {
-+ TxDMACtrl=0x00, TxCmd=0x04, TxStatus=0x06, TxPtr=0x08, TxCurPtr=0x10,
-+ RxDMACtrl=0x20, RxCmd=0x24, RxStatus=0x26, RxPtr=0x28, RxCurPtr=0x30,
-+ PCIClkMeas=0x060, MiscStatus=0x066, ChipRev=0x68, ChipReset=0x06B,
-+ LEDCtrl=0x06C, VirtualJumpers=0x06D,
-+ TxChecksum=0x074, RxChecksum=0x076,
-+ TxIntrCtrl=0x078, RxIntrCtrl=0x07C,
-+ InterruptEnable=0x080, InterruptClear=0x084, IntrStatus=0x088,
-+ EventStatus=0x08C,
-+ MACCnfg=0x0A0, FrameGap0=0x0A2, FrameGap1=0x0A4,
-+ /* See enum MII_offsets below. */
-+ MACCnfg2=0x0B0, RxDepth=0x0B8, FlowCtrl=0x0BC, MaxFrameSize=0x0CE,
-+ AddrMode=0x0D0, StationAddr=0x0D2,
-+ /* Gigabit AutoNegotiation. */
-+ ANCtrl=0x0E0, ANStatus=0x0E2, ANXchngCtrl=0x0E4, ANAdvertise=0x0E8,
-+ ANLinkPartnerAbility=0x0EA,
-+ EECmdStatus=0x0F0, EEData=0x0F1, EEAddr=0x0F2,
-+ FIFOcfg=0x0F8,
-+};
-+
-+/* Offsets to the MII-mode registers. */
-+enum MII_offsets {
-+ MII_Cmd=0xA6, MII_Addr=0xA8, MII_Wr_Data=0xAA, MII_Rd_Data=0xAC,
-+ MII_Status=0xAE,
-+};
-+
-+/* Bits in the interrupt status/mask registers. */
-+enum intr_status_bits {
-+ IntrRxDone=0x01, IntrRxPCIFault=0x02, IntrRxPCIErr=0x04,
-+ IntrTxDone=0x100, IntrTxPCIFault=0x200, IntrTxPCIErr=0x400,
-+ LinkChange=0x10000, NegotiationChange=0x20000, StatsMax=0x40000, };
-+
-+/* The Hamachi Rx and Tx buffer descriptors. */
-+struct hamachi_desc {
-+ u32 status_n_length;
-+#if ADDRLEN == 64
-+ u32 pad;
-+ u64 addr;
-+#else
-+ u32 addr;
-+#endif
-+};
-+
-+/* Bits in hamachi_desc.status */
-+enum desc_status_bits {
-+ DescOwn=0x80000000, DescEndPacket=0x40000000, DescEndRing=0x20000000,
-+ DescIntr=0x10000000,
-+};
-+
-+#define PRIV_ALIGN 15 /* Required alignment mask */
-+struct hamachi_private {
-+ /* Descriptor rings first for alignment. Tx requires a second descriptor
-+ for status. */
-+ struct hamachi_desc rx_ring[RX_RING_SIZE];
-+ struct hamachi_desc tx_ring[TX_RING_SIZE];
-+ /* The addresses of receive-in-place skbuffs. */
-+ struct sk_buff* rx_skbuff[RX_RING_SIZE];
-+ /* The saved address of a sent-in-place packet/buffer, for skfree(). */
-+ struct sk_buff* tx_skbuff[TX_RING_SIZE];
-+ struct net_device *next_module;
-+ void *priv_addr; /* Unaligned address for kfree */
-+ struct net_device_stats stats;
-+ struct timer_list timer; /* Media monitoring timer. */
-+ int chip_id, drv_flags;
-+ struct pci_dev *pci_dev;
-+
-+ /* Frequently used and paired value: keep adjacent for cache effect. */
-+ int msg_level;
-+ int max_interrupt_work;
-+ long in_interrupt;
-+
-+ struct hamachi_desc *rx_head_desc;
-+ unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */
-+ unsigned int rx_buf_sz; /* Based on MTU+slack. */
-+ int rx_copybreak;
-+ int multicast_filter_limit;
-+ int rx_mode;
-+
-+ unsigned int cur_tx, dirty_tx;
-+ unsigned int tx_full:1; /* The Tx queue is full. */
-+ unsigned int full_duplex:1; /* Full-duplex operation requested. */
-+ unsigned int duplex_lock:1;
-+ unsigned int medialock:1; /* Do not sense media. */
-+ unsigned int default_port; /* Last dev->if_port value. */
-+ /* MII transceiver section. */
-+ int mii_cnt; /* MII device addresses. */
-+ u16 advertising; /* NWay media advertisement */
-+ unsigned char phys[2]; /* MII device addresses. */
-+};
-+
-+static int read_eeprom(struct net_device *dev, int location);
-+static int mdio_read(long ioaddr, int phy_id, int location);
-+static void mdio_write(long ioaddr, int phy_id, int location, int value);
-+static int hamachi_open(struct net_device *dev);
-+static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-+#ifdef HAVE_CHANGE_MTU
-+static int change_mtu(struct net_device *dev, int new_mtu);
-+#endif
-+static void hamachi_timer(unsigned long data);
-+static void hamachi_tx_timeout(struct net_device *dev);
-+static void hamachi_init_ring(struct net_device *dev);
-+static int hamachi_start_xmit(struct sk_buff *skb, struct net_device *dev);
-+static void hamachi_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
-+static int hamachi_rx(struct net_device *dev);
-+static void hamachi_error(struct net_device *dev, int intr_status);
-+static int hamachi_close(struct net_device *dev);
-+static struct net_device_stats *hamachi_get_stats(struct net_device *dev);
-+static void set_rx_mode(struct net_device *dev);
-+
-+
-+
-+/* A list of our installed devices, for removing the driver module. */
-+static struct net_device *root_hamachi_dev = NULL;
-+
-+#ifndef MODULE
-+int hamachi_probe(struct net_device *dev)
-+{
-+ if (pci_drv_register(&hamachi_drv_id, dev) < 0)
-+ return -ENODEV;
-+ printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2);
-+ return 0;
-+}
-+#endif
-+
-+static void *hamachi_probe1(struct pci_dev *pdev, void *init_dev,
-+ long ioaddr, int irq, int chip_idx, int card_idx)
-+{
-+ struct net_device *dev;
-+ struct hamachi_private *np;
-+ void *priv_mem;
-+ int i, option = card_idx < MAX_UNITS ? options[card_idx] : 0;
-+
-+ dev = init_etherdev(init_dev, 0);
-+ if (!dev)
-+ return NULL;
-+
-+ printk(KERN_INFO "%s: %s type %x at 0x%lx, ",
-+ dev->name, pci_id_tbl[chip_idx].name, (int)readl(ioaddr + ChipRev),
-+ ioaddr);
-+
-+ for (i = 0; i < 6; i++)
-+ dev->dev_addr[i] = read_eeprom(dev, 4 + i);
-+ /* Alternate: readb(ioaddr + StationAddr + i); */
-+ for (i = 0; i < 5; i++)
-+ printk("%2.2x:", dev->dev_addr[i]);
-+ printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);
-+
-+ i = readb(ioaddr + PCIClkMeas);
-+ printk(KERN_INFO "%s: %d-bit %d Mhz PCI bus (%d), Virtual Jumpers "
-+ "%2.2x, LPA %4.4x.\n",
-+ dev->name, readw(ioaddr + MiscStatus) & 1 ? 64 : 32,
-+ i ? 2000/(i&0x7f) : 0, i&0x7f, (int)readb(ioaddr + VirtualJumpers),
-+ (int)readw(ioaddr + ANLinkPartnerAbility));
-+
-+ /* Hmmm, do we really need to reset the chip???. */
-+ writeb(1, ioaddr + ChipReset);
-+
-+ /* If the bus size is misidentified, do the following. */
-+ if (force32)
-+ writeb(force32, ioaddr + VirtualJumpers);
-+
-+ /* Make certain elements e.g. descriptor lists are aligned. */
-+ priv_mem = kmalloc(sizeof(*np) + PRIV_ALIGN, GFP_KERNEL);
-+ /* Check for the very unlikely case of no memory. */
-+ if (priv_mem == NULL)
-+ return NULL;
-+
-+ dev->base_addr = ioaddr;
-+ dev->irq = irq;
-+
-+ dev->priv = np = (void *)(((long)priv_mem + PRIV_ALIGN) & ~PRIV_ALIGN);
-+ memset(np, 0, sizeof(*np));
-+ np->priv_addr = priv_mem;
-+
-+ np->next_module = root_hamachi_dev;
-+ root_hamachi_dev = dev;
-+
-+ np->pci_dev = pdev;
-+ np->chip_id = chip_idx;
-+ np->drv_flags = pci_id_tbl[chip_idx].drv_flags;
-+ np->msg_level = (1 << debug) - 1;
-+ np->rx_copybreak = rx_copybreak;
-+ np->max_interrupt_work = max_interrupt_work;
-+ np->multicast_filter_limit =
-+ multicast_filter_limit < 64 ? multicast_filter_limit : 64;
-+
-+ if (dev->mem_start)
-+ option = dev->mem_start;
-+
-+ /* The lower four bits are the media type. */
-+ if (option > 0) {
-+ if (option & 0x2220)
-+ np->full_duplex = 1;
-+ np->default_port = option & 15;
-+ if (np->default_port & 0x3330)
-+ np->medialock = 1;
-+ }
-+ if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0)
-+ np->full_duplex = 1;
-+
-+ if (np->full_duplex) {
-+ if (np->msg_level & NETIF_MSG_PROBE)
-+ printk(KERN_INFO "%s: Set to forced full duplex, autonegotiation"
-+ " disabled.\n", dev->name);
-+ np->duplex_lock = 1;
-+ }
-+
-+ /* The Hamachi-specific entries in the device structure. */
-+ dev->open = &hamachi_open;
-+ dev->hard_start_xmit = &hamachi_start_xmit;
-+ dev->stop = &hamachi_close;
-+ dev->get_stats = &hamachi_get_stats;
-+ dev->set_multicast_list = &set_rx_mode;
-+ dev->do_ioctl = &mii_ioctl;
-+#ifdef HAVE_CHANGE_MTU
-+ dev->change_mtu = change_mtu;
-+#endif
-+
-+ if (np->drv_flags & CanHaveMII) {
-+ int phy, phy_idx = 0;
-+ for (phy = 0; phy < 32 && phy_idx < 4; phy++) {
-+ int mii_status = mdio_read(ioaddr, phy, 1);
-+ if (mii_status != 0xffff && mii_status != 0x0000) {
-+ np->phys[phy_idx++] = phy;
-+ np->advertising = mdio_read(ioaddr, phy, 4);
-+ printk(KERN_INFO "%s: MII PHY found at address %d, status "
-+ "0x%4.4x advertising %4.4x.\n",
-+ dev->name, phy, mii_status, np->advertising);
-+ }
-+ }
-+ np->mii_cnt = phy_idx;
-+ }
-+#ifdef notyet
-+ /* Disable PCI Parity Error (0x02) or PCI 64 Bit (0x01) for miswired
-+ motherboards. */
-+ if (readb(ioaddr + VirtualJumpers) != 0x30)
-+ writeb(0x33, ioaddr + VirtualJumpers)
-+#endif
-+ /* Configure gigabit autonegotiation. */
-+ writew(0x0400, ioaddr + ANXchngCtrl); /* Enable legacy links. */
-+ writew(0x08e0, ioaddr + ANAdvertise); /* Set our advertise word. */
-+ writew(0x1000, ioaddr + ANCtrl); /* Enable negotiation */
-+
-+ return dev;
-+}
-+
-+static int read_eeprom(struct net_device *dev, int location)
-+{
-+ struct hamachi_private *np = (void *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+ int bogus_cnt = 1000;
-+
-+ writew(location, ioaddr + EEAddr);
-+ writeb(0x02, ioaddr + EECmdStatus);
-+ while ((readb(ioaddr + EECmdStatus) & 0x40) && --bogus_cnt > 0)
-+ ;
-+ if (np->msg_level & NETIF_MSG_MISC)
-+ printk(KERN_DEBUG " EEPROM status is %2.2x after %d ticks.\n",
-+ (int)readb(ioaddr + EECmdStatus), 1000- bogus_cnt);
-+ return readb(ioaddr + EEData);
-+}
-+
-+/* MII Managemen Data I/O accesses.
-+ These routines assume the MDIO controller is idle, and do not exit until
-+ the command is finished. */
-+
-+static int mdio_read(long ioaddr, int phy_id, int location)
-+{
-+ int i;
-+
-+ writew((phy_id<<8) + location, ioaddr + MII_Addr);
-+ writew(1, ioaddr + MII_Cmd);
-+ for (i = 10000; i >= 0; i--)
-+ if ((readw(ioaddr + MII_Status) & 1) == 0)
-+ break;
-+ return readw(ioaddr + MII_Rd_Data);
-+}
-+
-+static void mdio_write(long ioaddr, int phy_id, int location, int value)
-+{
-+ int i;
-+
-+ writew((phy_id<<8) + location, ioaddr + MII_Addr);
-+ writew(value, ioaddr + MII_Wr_Data);
-+
-+ /* Wait for the command to finish. */
-+ for (i = 10000; i >= 0; i--)
-+ if ((readw(ioaddr + MII_Status) & 1) == 0)
-+ break;
-+ return;
-+}
-+
-+
-+static int hamachi_open(struct net_device *dev)
-+{
-+ struct hamachi_private *hmp = (struct hamachi_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+ int i;
-+
-+ /* Do we need to reset the chip??? */
-+
-+ MOD_INC_USE_COUNT;
-+
-+ if (request_irq(dev->irq, &hamachi_interrupt, SA_SHIRQ, dev->name, dev)) {
-+ MOD_DEC_USE_COUNT;
-+ return -EAGAIN;
-+ }
-+
-+ if (hmp->msg_level & NETIF_MSG_IFUP)
-+ printk(KERN_DEBUG "%s: hamachi_open() irq %d.\n",
-+ dev->name, dev->irq);
-+
-+ hamachi_init_ring(dev);
-+
-+#if ADDRLEN == 64
-+ writel(virt_to_bus(hmp->rx_ring), ioaddr + RxPtr);
-+ writel(virt_to_bus(hmp->rx_ring) >> 32, ioaddr + RxPtr + 4);
-+ writel(virt_to_bus(hmp->tx_ring), ioaddr + TxPtr);
-+ writel(virt_to_bus(hmp->tx_ring) >> 32, ioaddr + TxPtr + 4);
-+#else
-+ writel(virt_to_bus(hmp->rx_ring), ioaddr + RxPtr);
-+ writel(virt_to_bus(hmp->tx_ring), ioaddr + TxPtr);
-+#endif
-+
-+ for (i = 0; i < 6; i++)
-+ writeb(dev->dev_addr[i], ioaddr + StationAddr + i);
-+
-+ /* Initialize other registers: with so many this eventually this will
-+ converted to an offset/value list. */
-+ /* Configure the FIFO for 512K external, 16K used for Tx. */
-+ writew(0x0028, ioaddr + FIFOcfg);
-+
-+ if (dev->if_port == 0)
-+ dev->if_port = hmp->default_port;
-+ hmp->in_interrupt = 0;
-+
-+ /* Setting the Rx mode will start the Rx process. */
-+ /* We are always in full-duplex mode with gigabit! */
-+ hmp->full_duplex = 1;
-+ writew(0x0001, ioaddr + RxChecksum); /* Enable Rx IP partial checksum. */
-+ writew(0x8000, ioaddr + MACCnfg); /* Soft reset the MAC */
-+ writew(0x215F, ioaddr + MACCnfg);
-+ writew(0x000C, ioaddr + FrameGap0); /* 0060/4060 for non-MII 10baseT */
-+ writew(0x1018, ioaddr + FrameGap1);
-+ writew(0x2780, ioaddr + MACCnfg2); /* Upper 16 bits control LEDs. */
-+ /* Enable automatic generation of flow control frames, period 0xffff. */
-+ writel(0x0030FFFF, ioaddr + FlowCtrl);
-+ writew(dev->mtu+19, ioaddr + MaxFrameSize); /* hmp->rx_buf_sz ??? */
-+
-+ /* Enable legacy links. */
-+ writew(0x0400, ioaddr + ANXchngCtrl); /* Enable legacy links. */
-+ /* Initial Link LED to blinking red. */
-+ writeb(0x03, ioaddr + LEDCtrl);
-+
-+ /* Configure interrupt mitigation. This has a great effect on
-+ performance, so systems tuning should start here!. */
-+ writel(0x00080000, ioaddr + TxIntrCtrl);
-+ writel(0x00000020, ioaddr + RxIntrCtrl);
-+
-+ hmp->rx_mode = 0; /* Force Rx mode write. */
-+ set_rx_mode(dev);
-+ netif_start_tx_queue(dev);
-+
-+ /* Enable interrupts by setting the interrupt mask. */
-+ writel(0x80878787, ioaddr + InterruptEnable);
-+ writew(0x0000, ioaddr + EventStatus); /* Clear non-interrupting events */
-+
-+ /* Configure and start the DMA channels. */
-+ /* Burst sizes are in the low three bits: size = 4<<(val&7) */
-+#if ADDRLEN == 64
-+ writew(0x0055, ioaddr + RxDMACtrl); /* 128 dword bursts */
-+ writew(0x0055, ioaddr + TxDMACtrl);
-+#else
-+ writew(0x0015, ioaddr + RxDMACtrl);
-+ writew(0x0015, ioaddr + TxDMACtrl);
-+#endif
-+ writew(1, dev->base_addr + RxCmd);
-+
-+ if (hmp->msg_level & NETIF_MSG_IFUP)
-+ printk(KERN_DEBUG "%s: Done hamachi_open(), status: Rx %x Tx %x.\n",
-+ dev->name, (int)readw(ioaddr + RxStatus),
-+ (int)readw(ioaddr + TxStatus));
-+
-+ /* Set the timer to check for link beat. */
-+ init_timer(&hmp->timer);
-+ hmp->timer.expires = jiffies + 3*HZ;
-+ hmp->timer.data = (unsigned long)dev;
-+ hmp->timer.function = &hamachi_timer; /* timer handler */
-+ add_timer(&hmp->timer);
-+
-+ return 0;
-+}
-+
-+static void hamachi_timer(unsigned long data)
-+{
-+ struct net_device *dev = (struct net_device *)data;
-+ struct hamachi_private *hmp = (struct hamachi_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+ int next_tick = 10*HZ;
-+
-+ if (hmp->msg_level & NETIF_MSG_TIMER) {
-+ printk(KERN_INFO "%s: Hamachi Autonegotiation status %4.4x, LPA "
-+ "%4.4x.\n", dev->name, (int)readw(ioaddr + ANStatus),
-+ (int)readw(ioaddr + ANLinkPartnerAbility));
-+ printk(KERN_INFO "%s: Autonegotiation regs %4.4x %4.4x %4.4x "
-+ "%4.4x %4.4x %4.4x.\n", dev->name,
-+ (int)readw(ioaddr + 0x0e0),
-+ (int)readw(ioaddr + 0x0e2),
-+ (int)readw(ioaddr + 0x0e4),
-+ (int)readw(ioaddr + 0x0e6),
-+ (int)readw(ioaddr + 0x0e8),
-+ (int)readw(ioaddr + 0x0eA));
-+ }
-+ /* This has a small false-trigger window. */
-+ if (netif_queue_paused(dev) &&
-+ (jiffies - dev->trans_start) > TX_TIMEOUT
-+ && hmp->cur_tx - hmp->dirty_tx > 1) {
-+ hamachi_tx_timeout(dev);
-+ }
-+ /* We could do something here... nah. */
-+ hmp->timer.expires = jiffies + next_tick;
-+ add_timer(&hmp->timer);
-+}
-+
-+static void hamachi_tx_timeout(struct net_device *dev)
-+{
-+ struct hamachi_private *hmp = (struct hamachi_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+
-+ printk(KERN_WARNING "%s: Hamachi transmit timed out, status %8.8x,"
-+ " resetting...\n", dev->name, (int)readw(ioaddr + TxStatus));
-+
-+ if (hmp->msg_level & NETIF_MSG_TX_ERR) {
-+ int i;
-+ printk(KERN_DEBUG " Rx ring %p: ", hmp->rx_ring);
-+ for (i = 0; i < RX_RING_SIZE; i++)
-+ printk(" %8.8x", (unsigned int)hmp->rx_ring[i].status_n_length);
-+ printk("\n"KERN_DEBUG" Tx ring %p: ", hmp->tx_ring);
-+ for (i = 0; i < TX_RING_SIZE; i++)
-+ printk(" %4.4x", hmp->tx_ring[i].status_n_length);
-+ printk("\n");
-+ }
-+
-+ /* Perhaps we should reinitialize the hardware here. */
-+ dev->if_port = 0;
-+ /* Stop and restart the chip's Tx processes . */
-+
-+ /* Trigger an immediate transmit demand. */
-+ writew(2, dev->base_addr + TxCmd);
-+ writew(1, dev->base_addr + TxCmd);
-+ writew(1, dev->base_addr + RxCmd);
-+
-+ dev->trans_start = jiffies;
-+ hmp->stats.tx_errors++;
-+ return;
-+}
-+
-+
-+/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
-+static void hamachi_init_ring(struct net_device *dev)
-+{
-+ struct hamachi_private *hmp = (struct hamachi_private *)dev->priv;
-+ int i;
-+
-+ hmp->tx_full = 0;
-+ hmp->cur_rx = hmp->cur_tx = 0;
-+ hmp->dirty_rx = hmp->dirty_tx = 0;
-+
-+ /* Size of each temporary Rx buffer. Add 8 if you do Rx checksumming! */
-+ hmp->rx_buf_sz = dev->mtu + 18 + 8;
-+ /* Match other driver's allocation size when possible. */
-+ if (hmp->rx_buf_sz < PKT_BUF_SZ)
-+ hmp->rx_buf_sz = PKT_BUF_SZ;
-+ hmp->rx_head_desc = &hmp->rx_ring[0];
-+
-+ /* Initialize all Rx descriptors. */
-+ for (i = 0; i < RX_RING_SIZE; i++) {
-+ hmp->rx_ring[i].status_n_length = 0;
-+ hmp->rx_skbuff[i] = 0;
-+ }
-+ /* Fill in the Rx buffers. Handle allocation failure gracefully. */
-+ for (i = 0; i < RX_RING_SIZE; i++) {
-+ struct sk_buff *skb = dev_alloc_skb(hmp->rx_buf_sz);
-+ hmp->rx_skbuff[i] = skb;
-+ if (skb == NULL)
-+ break;
-+ skb->dev = dev; /* Mark as being used by this device. */
-+ skb_reserve(skb, 2); /* 16 byte align the IP header. */
-+ hmp->rx_ring[i].addr = virt_to_desc(skb->tail);
-+ hmp->rx_ring[i].status_n_length =
-+ cpu_to_le32(DescOwn | DescEndPacket | DescIntr | hmp->rx_buf_sz);
-+ }
-+ hmp->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
-+ /* Mark the last entry as wrapping the ring. */
-+ hmp->rx_ring[i-1].status_n_length |= cpu_to_le32(DescEndRing);
-+
-+ for (i = 0; i < TX_RING_SIZE; i++) {
-+ hmp->tx_skbuff[i] = 0;
-+ hmp->tx_ring[i].status_n_length = 0;
-+ }
-+ return;
-+}
-+
-+static int hamachi_start_xmit(struct sk_buff *skb, struct net_device *dev)
-+{
-+ struct hamachi_private *hmp = (struct hamachi_private *)dev->priv;
-+ unsigned entry;
-+
-+ /* Block a timer-based transmit from overlapping. This could better be
-+ done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
-+ if (netif_pause_tx_queue(dev) != 0) {
-+ /* This watchdog code is redundant with the media monitor timer. */
-+ if (jiffies - dev->trans_start > TX_TIMEOUT)
-+ hamachi_tx_timeout(dev);
-+ return 1;
-+ }
-+
-+ /* Note: Ordering is important here, set the field with the
-+ "ownership" bit last, and only then increment cur_tx. */
-+
-+ /* Calculate the next Tx descriptor entry. */
-+ entry = hmp->cur_tx % TX_RING_SIZE;
-+
-+ hmp->tx_skbuff[entry] = skb;
-+
-+ hmp->tx_ring[entry].addr = virt_to_desc(skb->data);
-+ if (entry >= TX_RING_SIZE-1) /* Wrap ring */
-+ hmp->tx_ring[entry].status_n_length =
-+ cpu_to_le32(DescOwn|DescEndPacket|DescEndRing|DescIntr | skb->len);
-+ else
-+ hmp->tx_ring[entry].status_n_length =
-+ cpu_to_le32(DescOwn|DescEndPacket | skb->len);
-+ hmp->cur_tx++;
-+
-+ /* Architecture-specific: explicitly flush cache lines here. */
-+
-+ /* Wake the potentially-idle transmit channel. */
-+ writew(1, dev->base_addr + TxCmd);
-+
-+ if (hmp->cur_tx - hmp->dirty_tx >= TX_QUEUE_LEN - 1) {
-+ hmp->tx_full = 1;
-+ if (hmp->cur_tx - hmp->dirty_tx < TX_QUEUE_LEN - 1) {
-+ netif_unpause_tx_queue(dev);
-+ hmp->tx_full = 0;
-+ } else
-+ netif_stop_tx_queue(dev);
-+ } else
-+ netif_unpause_tx_queue(dev); /* Typical path */
-+ dev->trans_start = jiffies;
-+
-+ if (hmp->msg_level & NETIF_MSG_TX_QUEUED) {
-+ printk(KERN_DEBUG "%s: Hamachi transmit frame #%d length %d queued "
-+ "in slot %d.\n", dev->name, hmp->cur_tx, (int)skb->len, entry);
-+ }
-+ return 0;
-+}
-+
-+/* The interrupt handler does all of the Rx thread work and cleans up
-+ after the Tx thread. */
-+static void hamachi_interrupt(int irq, void *dev_instance, struct pt_regs *rgs)
-+{
-+ struct net_device *dev = (struct net_device *)dev_instance;
-+ struct hamachi_private *hmp;
-+ long ioaddr;
-+ int boguscnt = max_interrupt_work;
-+
-+#ifndef final_version /* Can never occur. */
-+ if (dev == NULL) {
-+ printk (KERN_ERR "hamachi_interrupt(): irq %d for unknown device.\n", irq);
-+ return;
-+ }
-+#endif
-+
-+ ioaddr = dev->base_addr;
-+ hmp = (struct hamachi_private *)dev->priv;
-+ if (test_and_set_bit(0, (void*)&hmp->in_interrupt)) {
-+ printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name);
-+ hmp->in_interrupt = 0; /* Avoid future hang on bug */
-+ return;
-+ }
-+
-+ do {
-+ u32 intr_status = readl(ioaddr + InterruptClear);
-+
-+ if (hmp->msg_level & NETIF_MSG_INTR)
-+ printk(KERN_DEBUG "%s: Hamachi interrupt, status %4.4x.\n",
-+ dev->name, intr_status);
-+
-+ if (intr_status == 0)
-+ break;
-+
-+ if (intr_status & IntrRxDone)
-+ hamachi_rx(dev);
-+
-+ for (; hmp->cur_tx - hmp->dirty_tx > 0; hmp->dirty_tx++) {
-+ int entry = hmp->dirty_tx % TX_RING_SIZE;
-+ if (!(hmp->tx_ring[entry].status_n_length & cpu_to_le32(DescOwn)))
-+ break;
-+ if (hmp->msg_level & NETIF_MSG_TX_DONE)
-+ printk(KERN_DEBUG "%s: Transmit done, Tx status %8.8x.\n",
-+ dev->name, hmp->tx_ring[entry].status_n_length);
-+ /* Free the original skb. */
-+ dev_free_skb_irq(hmp->tx_skbuff[entry]);
-+ hmp->tx_skbuff[entry] = 0;
-+ hmp->stats.tx_packets++;
-+ }
-+ if (hmp->tx_full
-+ && hmp->cur_tx - hmp->dirty_tx < TX_QUEUE_LEN - 4) {
-+ /* The ring is no longer full, clear tbusy. */
-+ hmp->tx_full = 0;
-+ netif_resume_tx_queue(dev);
-+ }
-+
-+ /* Abnormal error summary/uncommon events handlers. */
-+ if (intr_status &
-+ (IntrTxPCIFault | IntrTxPCIErr | IntrRxPCIFault | IntrRxPCIErr |
-+ LinkChange | NegotiationChange | StatsMax))
-+ hamachi_error(dev, intr_status);
-+
-+ if (--boguscnt < 0) {
-+ printk(KERN_WARNING "%s: Too much work at interrupt, "
-+ "status=0x%4.4x.\n",
-+ dev->name, intr_status);
-+ break;
-+ }
-+ } while (1);
-+
-+ if (hmp->msg_level & NETIF_MSG_INTR)
-+ printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
-+ dev->name, (int)readl(ioaddr + IntrStatus));
-+ clear_bit(0, (void*)&hmp->in_interrupt);
-+ return;
-+}
-+
-+/* This routine is logically part of the interrupt handler, but separated
-+ for clarity and better register allocation. */
-+static int hamachi_rx(struct net_device *dev)
-+{
-+ struct hamachi_private *hmp = (struct hamachi_private *)dev->priv;
-+ int entry = hmp->cur_rx % RX_RING_SIZE;
-+ int boguscnt = hmp->dirty_rx + RX_RING_SIZE - hmp->cur_rx;
-+
-+ if (hmp->msg_level & NETIF_MSG_RX_STATUS) {
-+ printk(KERN_DEBUG " In hamachi_rx(), entry %d status %4.4x.\n",
-+ entry, hmp->rx_ring[entry].status_n_length);
-+ }
-+
-+ /* If EOP is set on the next entry, it's a new packet. Send it up. */
-+ while ( ! (hmp->rx_head_desc->status_n_length & cpu_to_le32(DescOwn))) {
-+ struct hamachi_desc *desc = hmp->rx_head_desc;
-+ u32 desc_status = le32_to_cpu(desc->status_n_length);
-+ u16 data_size = desc_status; /* Implicit truncate */
-+ u8 *buf_addr = hmp->rx_skbuff[entry]->tail;
-+ s32 frame_status =
-+ le32_to_cpu(get_unaligned((s32*)&(buf_addr[data_size - 12])));
-+
-+ if (hmp->msg_level & NETIF_MSG_RX_STATUS)
-+ printk(KERN_DEBUG " hamachi_rx() status was %8.8x.\n",
-+ frame_status);
-+ if (--boguscnt < 0)
-+ break;
-+ if ( ! (desc_status & DescEndPacket)) {
-+ printk(KERN_WARNING "%s: Oversized Ethernet frame spanned "
-+ "multiple buffers, entry %#x length %d status %4.4x!\n",
-+ dev->name, hmp->cur_rx, data_size, desc_status);
-+ printk(KERN_WARNING "%s: Oversized Ethernet frame %p vs %p.\n",
-+ dev->name, desc, &hmp->rx_ring[hmp->cur_rx % RX_RING_SIZE]);
-+ printk(KERN_WARNING "%s: Oversized Ethernet frame -- next status"
-+ " %x last status %x.\n", dev->name,
-+ hmp->rx_ring[(hmp->cur_rx+1) % RX_RING_SIZE].status_n_length,
-+ hmp->rx_ring[(hmp->cur_rx-1) % RX_RING_SIZE].status_n_length);
-+ hmp->stats.rx_length_errors++;
-+ } /* else Omit for prototype errata??? */
-+ if (frame_status & 0x00380000) {
-+ /* There was a error. */
-+ if (hmp->msg_level & NETIF_MSG_RX_ERR)
-+ printk(KERN_DEBUG " hamachi_rx() Rx error was %8.8x.\n",
-+ frame_status);
-+ hmp->stats.rx_errors++;
-+ if (frame_status & 0x00600000) hmp->stats.rx_length_errors++;
-+ if (frame_status & 0x00080000) hmp->stats.rx_frame_errors++;
-+ if (frame_status & 0x00100000) hmp->stats.rx_crc_errors++;
-+ if (frame_status < 0) hmp->stats.rx_dropped++;
-+ } else {
-+ struct sk_buff *skb;
-+ u16 pkt_len = (frame_status & 0x07ff) - 4; /* Omit CRC */
-+
-+#if ! defined(final_version) && 0
-+ if (hmp->msg_level & NETIF_MSG_RX_STATUS)
-+ printk(KERN_DEBUG " hamachi_rx() normal Rx pkt length %d"
-+ " of %d, bogus_cnt %d.\n",
-+ pkt_len, data_size, boguscnt);
-+ if (hmp->msg_level & NETIF_MSG_PKTDATA)
-+ printk(KERN_DEBUG"%s: rx status %8.8x %8.8x %8.8x %8.8x %8.8x.\n",
-+ dev->name,
-+ *(s32*)&(buf_addr[data_size - 20]),
-+ *(s32*)&(buf_addr[data_size - 16]),
-+ *(s32*)&(buf_addr[data_size - 12]),
-+ *(s32*)&(buf_addr[data_size - 8]),
-+ *(s32*)&(buf_addr[data_size - 4]));
-+#endif
-+ /* Check if the packet is long enough to accept without copying
-+ to a minimally-sized skbuff. */
-+ if (pkt_len < rx_copybreak
-+ && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
-+ skb->dev = dev;
-+ skb_reserve(skb, 2); /* 16 byte align the IP header */
-+ eth_copy_and_sum(skb, hmp->rx_skbuff[entry]->tail, pkt_len, 0);
-+ skb_put(skb, pkt_len);
-+ } else {
-+ char *temp = skb_put(skb = hmp->rx_skbuff[entry], pkt_len);
-+ hmp->rx_skbuff[entry] = NULL;
-+#if ! defined(final_version)
-+ if (bus_to_virt(desc->addr) != temp)
-+ printk(KERN_ERR "%s: Internal fault: The skbuff addresses "
-+ "do not match in hamachi_rx: %p vs. %p / %p.\n",
-+ dev->name, bus_to_virt(desc->addr),
-+ skb->head, temp);
-+#endif
-+ }
-+ skb->protocol = eth_type_trans(skb, dev);
-+ /* Note: checksum -> skb->ip_summed = CHECKSUM_UNNECESSARY; */
-+ netif_rx(skb);
-+ dev->last_rx = jiffies;
-+ hmp->stats.rx_packets++;
-+ }
-+ entry = (++hmp->cur_rx) % RX_RING_SIZE;
-+ hmp->rx_head_desc = &hmp->rx_ring[entry];
-+ }
-+
-+ /* Refill the Rx ring buffers. */
-+ for (; hmp->cur_rx - hmp->dirty_rx > 0; hmp->dirty_rx++) {
-+ struct sk_buff *skb;
-+ entry = hmp->dirty_rx % RX_RING_SIZE;
-+ if (hmp->rx_skbuff[entry] == NULL) {
-+ skb = dev_alloc_skb(hmp->rx_buf_sz);
-+ hmp->rx_skbuff[entry] = skb;
-+ if (skb == NULL)
-+ break; /* Better luck next round. */
-+ skb->dev = dev; /* Mark as being used by this device. */
-+ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
-+ hmp->rx_ring[entry].addr = virt_to_desc(skb->tail);
-+ }
-+ if (entry >= RX_RING_SIZE-1) /* Wrap ring */
-+ hmp->rx_ring[entry].status_n_length =
-+ cpu_to_le32(DescOwn|DescEndPacket|DescEndRing|DescIntr | hmp->rx_buf_sz);
-+ else
-+ hmp->rx_ring[entry].status_n_length =
-+ cpu_to_le32(DescOwn|DescEndPacket|DescIntr | hmp->rx_buf_sz);
-+ }
-+
-+ /* Restart Rx engine if stopped. */
-+ writew(1, dev->base_addr + RxCmd);
-+ return 0;
-+}
-+
-+/* This is more properly named "uncommon interrupt events", as it covers more
-+ than just errors. */
-+static void hamachi_error(struct net_device *dev, int intr_status)
-+{
-+ long ioaddr = dev->base_addr;
-+ struct hamachi_private *hmp = (struct hamachi_private *)dev->priv;
-+
-+ if (intr_status & (LinkChange|NegotiationChange)) {
-+ if (hmp->msg_level & NETIF_MSG_LINK)
-+ printk(KERN_INFO "%s: Link changed: AutoNegotiation Ctrl"
-+ " %4.4x, Status %4.4x %4.4x Intr status %4.4x.\n",
-+ dev->name, (int)readw(ioaddr + 0x0E0),
-+ (int)readw(ioaddr + 0x0E2),
-+ (int)readw(ioaddr + ANLinkPartnerAbility),
-+ (int)readl(ioaddr + IntrStatus));
-+ if (readw(ioaddr + ANStatus) & 0x20) {
-+ writeb(0x01, ioaddr + LEDCtrl);
-+ netif_link_up(dev);
-+ } else {
-+ writeb(0x03, ioaddr + LEDCtrl);
-+ netif_link_down(dev);
-+ }
-+ }
-+ if (intr_status & StatsMax) {
-+ hamachi_get_stats(dev);
-+ /* Read the overflow bits to clear. */
-+ readl(ioaddr + 0x36C);
-+ readl(ioaddr + 0x3F0);
-+ }
-+ if ((intr_status & ~(LinkChange|StatsMax|NegotiationChange))
-+ && (hmp->msg_level & NETIF_MSG_DRV))
-+ printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n",
-+ dev->name, intr_status);
-+ /* Hmmmmm, it's not clear how to recover from PCI faults. */
-+ if (intr_status & (IntrTxPCIErr | IntrTxPCIFault))
-+ hmp->stats.tx_fifo_errors++;
-+ if (intr_status & (IntrRxPCIErr | IntrRxPCIFault))
-+ hmp->stats.rx_fifo_errors++;
-+}
-+
-+static int hamachi_close(struct net_device *dev)
-+{
-+ long ioaddr = dev->base_addr;
-+ struct hamachi_private *hmp = (struct hamachi_private *)dev->priv;
-+ int i;
-+
-+ netif_stop_tx_queue(dev);
-+
-+ if (hmp->msg_level & NETIF_MSG_IFDOWN) {
-+ printk(KERN_DEBUG "%s: Shutting down ethercard, status was Tx %4.4x "
-+ "Rx %4.4x Int %2.2x.\n",
-+ dev->name, (int)readw(ioaddr + TxStatus),
-+ (int)readw(ioaddr + RxStatus), (int)readl(ioaddr + IntrStatus));
-+ printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d, Rx %d / %d.\n",
-+ dev->name, hmp->cur_tx, hmp->dirty_tx, hmp->cur_rx,
-+ hmp->dirty_rx);
-+ }
-+
-+ /* Disable interrupts by clearing the interrupt mask. */
-+ writel(0x0000, ioaddr + InterruptEnable);
-+
-+ /* Stop the chip's Tx and Rx processes. */
-+ writel(2, ioaddr + RxCmd);
-+ writew(2, ioaddr + TxCmd);
-+
-+ del_timer(&hmp->timer);
-+
-+#ifdef __i386__
-+ if (hmp->msg_level & NETIF_MSG_IFDOWN) {
-+ printk("\n"KERN_DEBUG" Tx ring at %8.8x:\n",
-+ (int)virt_to_bus(hmp->tx_ring));
-+ for (i = 0; i < TX_RING_SIZE; i++)
-+ printk(" %c #%d desc. %8.8x %8.8x.\n",
-+ readl(ioaddr + TxCurPtr) == (long)&hmp->tx_ring[i] ? '>' : ' ',
-+ i, hmp->tx_ring[i].status_n_length, hmp->tx_ring[i].addr);
-+ printk("\n"KERN_DEBUG " Rx ring %8.8x:\n",
-+ (int)virt_to_bus(hmp->rx_ring));
-+ for (i = 0; i < RX_RING_SIZE; i++) {
-+ printk(KERN_DEBUG " %c #%d desc. %8.8x %8.8x\n",
-+ readl(ioaddr + RxCurPtr) == (long)&hmp->rx_ring[i] ? '>' : ' ',
-+ i, hmp->rx_ring[i].status_n_length, hmp->rx_ring[i].addr);
-+ if (*(u8*)hmp->rx_ring[i].addr != 0x69) {
-+ int j;
-+ for (j = 0; j < 0x50; j++)
-+ printk(" %4.4x", ((u16*)hmp->rx_ring[i].addr)[j]);
-+ printk("\n");
-+ }
-+ }
-+ }
-+#endif /* __i386__ debugging only */
-+
-+ free_irq(dev->irq, dev);
-+
-+ /* Free all the skbuffs in the Rx queue. */
-+ for (i = 0; i < RX_RING_SIZE; i++) {
-+ hmp->rx_ring[i].status_n_length = 0;
-+ hmp->rx_ring[i].addr = 0xBADF00D0; /* An invalid address. */
-+ if (hmp->rx_skbuff[i]) {
-+#if LINUX_VERSION_CODE < 0x20100
-+ hmp->rx_skbuff[i]->free = 1;
-+#endif
-+ dev_free_skb(hmp->rx_skbuff[i]);
-+ }
-+ hmp->rx_skbuff[i] = 0;
-+ }
-+ for (i = 0; i < TX_RING_SIZE; i++) {
-+ if (hmp->tx_skbuff[i])
-+ dev_free_skb(hmp->tx_skbuff[i]);
-+ hmp->tx_skbuff[i] = 0;
-+ }
-+
-+ writeb(0x00, ioaddr + LEDCtrl);
-+
-+ MOD_DEC_USE_COUNT;
-+
-+ return 0;
-+}
-+
-+static struct net_device_stats *hamachi_get_stats(struct net_device *dev)
-+{
-+ long ioaddr = dev->base_addr;
-+ struct hamachi_private *hmp = (struct hamachi_private *)dev->priv;
-+
-+ /* We should lock this segment of code for SMP eventually, although
-+ the vulnerability window is very small and statistics are
-+ non-critical. */
-+#if LINUX_VERSION_CODE >= 0x20119
-+ hmp->stats.rx_bytes += readl(ioaddr + 0x330); /* Total Uni+Brd+Multi */
-+ hmp->stats.tx_bytes += readl(ioaddr + 0x3B0); /* Total Uni+Brd+Multi */
-+#endif
-+ hmp->stats.multicast += readl(ioaddr + 0x320); /* Multicast Rx */
-+
-+ hmp->stats.rx_length_errors += readl(ioaddr + 0x368); /* Over+Undersized */
-+ hmp->stats.rx_over_errors += readl(ioaddr + 0x35C); /* Jabber */
-+ hmp->stats.rx_crc_errors += readl(ioaddr + 0x360);
-+ hmp->stats.rx_frame_errors += readl(ioaddr + 0x364); /* Symbol Errs */
-+ hmp->stats.rx_missed_errors += readl(ioaddr + 0x36C); /* Dropped */
-+
-+ return &hmp->stats;
-+}
-+
-+static void set_rx_mode(struct net_device *dev)
-+{
-+ struct hamachi_private *np = (void *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+ int new_rx_mode;
-+
-+ if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
-+ /* Unconditionally log net taps. */
-+ printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);
-+ new_rx_mode = 0x000F;
-+ } else if (dev->mc_count > np->multicast_filter_limit ||
-+ (dev->flags & IFF_ALLMULTI)) {
-+ /* Too many to match, or accept all multicasts. */
-+ new_rx_mode = 0x000B;
-+ } else if (dev->mc_count > 0) { /* Must use the CAM filter. */
-+ struct dev_mc_list *mclist;
-+ int i;
-+ for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
-+ i++, mclist = mclist->next) {
-+ writel(*(u32*)(mclist->dmi_addr), ioaddr + 0x100 + i*8);
-+ writel(0x20000 | (*(u16*)&mclist->dmi_addr[4]),
-+ ioaddr + 0x104 + i*8);
-+ }
-+ /* Clear remaining entries. */
-+ for (; i < 64; i++)
-+ writel(0, ioaddr + 0x104 + i*8);
-+ new_rx_mode = 0x0003;
-+ } else { /* Normal, unicast/broadcast-only mode. */
-+ new_rx_mode = 0x0001;
-+ }
-+ if (np->rx_mode != new_rx_mode) {
-+ np->rx_mode = new_rx_mode;
-+ writew(new_rx_mode, ioaddr + AddrMode);
-+ }
-+}
-+
-+static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-+{
-+ struct hamachi_private *np = (void *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+ u16 *data = (u16 *)&rq->ifr_data;
-+ u32 *data32 = (void *)&rq->ifr_data;
-+
-+ switch(cmd) {
-+ case 0x8947: case 0x89F0:
-+ /* SIOCGMIIPHY: Get the address of the PHY in use. */
-+ data[0] = np->phys[0] & 0x1f;
-+ /* Fall Through */
-+ case 0x8948: case 0x89F1:
-+ /* SIOCGMIIREG: Read the specified MII register. */
-+ data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f);
-+ return 0;
-+ case 0x8949: case 0x89F2:
-+ /* SIOCSMIIREG: Write the specified MII register */
-+ if (!capable(CAP_NET_ADMIN))
-+ return -EPERM;
-+ /* We are always full duplex. Skip recording the advertised value. */
-+ mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]);
-+ return 0;
-+ case SIOCGPARAMS:
-+ data32[0] = np->msg_level;
-+ data32[1] = np->multicast_filter_limit;
-+ data32[2] = np->max_interrupt_work;
-+ data32[3] = np->rx_copybreak;
-+ return 0;
-+ case SIOCSPARAMS: {
-+ /* Set rx,tx intr params, from Eric Kasten. */
-+ if (!capable(CAP_NET_ADMIN))
-+ return -EPERM;
-+ np->msg_level = data32[0];
-+ np->max_interrupt_work = data32[2];
-+ writel(data32[1], dev->base_addr + TxIntrCtrl);
-+ writel(data32[3], dev->base_addr + RxIntrCtrl);
-+ printk(KERN_INFO "%s: Set interrupt mitigate paramters tx %08x, "
-+ "rx %08x.\n", dev->name,
-+ (int) readl(dev->base_addr + TxIntrCtrl),
-+ (int) readl(dev->base_addr + RxIntrCtrl));
-+ return 0;
-+ }
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+}
-+
-+#ifdef HAVE_CHANGE_MTU
-+static int change_mtu(struct net_device *dev, int new_mtu)
-+{
-+ if ((new_mtu < 68) || (new_mtu > 1536))
-+ return -EINVAL;
-+ if (netif_running(dev))
-+ return -EBUSY;
-+ printk(KERN_NOTICE "%s: Changing MTU to %d.\n", dev->name, new_mtu);
-+ dev->mtu = new_mtu;
-+ return 0;
-+}
-+#endif
-+
-+
-+#ifdef MODULE
-+int init_module(void)
-+{
-+ if (debug >= NETIF_MSG_DRV) /* Emit version even if no cards detected. */
-+ printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2);
-+ return pci_drv_register(&hamachi_drv_id, NULL);
-+}
-+
-+void cleanup_module(void)
-+{
-+ struct net_device *next_dev;
-+
-+ pci_drv_unregister(&hamachi_drv_id);
-+
-+ /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
-+ while (root_hamachi_dev) {
-+ struct hamachi_private *hmp = (void *)(root_hamachi_dev->priv);
-+ unregister_netdev(root_hamachi_dev);
-+ iounmap((char *)root_hamachi_dev->base_addr);
-+ next_dev = hmp->next_module;
-+ if (hmp->priv_addr)
-+ kfree(hmp->priv_addr);
-+ kfree(root_hamachi_dev);
-+ root_hamachi_dev = next_dev;
-+ }
-+}
-+
-+#endif /* MODULE */
-+
-+/*
-+ * Local variables:
-+ * compile-command: "make KERNVER=`uname -r` hamachi.o"
-+ * compile-cmd: "gcc -DMODULE -Wall -Wstrict-prototypes -O6 -c hamachi.c"
-+ * simple-compile-command: "gcc -DMODULE -O6 -c hamachi.c"
-+ * c-indent-level: 4
-+ * c-basic-offset: 4
-+ * tab-width: 4
-+ * End:
-+ */
-Index: linux/src/drivers/net/intel-gige.c
-===================================================================
-RCS file: linux/src/drivers/net/intel-gige.c
-diff -N linux/src/drivers/net/intel-gige.c
---- /dev/null 1 Jan 1970 00:00:00 -0000
-+++ linux/src/drivers/net/intel-gige.c 10 Nov 2005 00:43:19 -0000
-@@ -0,0 +1,1450 @@
-+/* intel-gige.c: A Linux device driver for Intel Gigabit Ethernet adapters. */
-+/*
-+ Written 2000-2002 by Donald Becker.
-+ Copyright Scyld Computing Corporation.
-+
-+ This software may be used and distributed according to the terms of
-+ the GNU General Public License (GPL), incorporated herein by reference.
-+ You should have received a copy of the GPL with this file.
-+ Drivers based on or derived from this code fall under the GPL and must
-+ retain the authorship, copyright and license notice. This file is not
-+ a complete program and may only be used when the entire operating
-+ system is licensed under the GPL.
-+
-+ The author may be reached as becker@scyld.com, or C/O
-+ Scyld Computing Corporation
-+ 410 Severn Ave., Suite 210
-+ Annapolis MD 21403
-+
-+ Support information and updates available at
-+ http://www.scyld.com/network/ethernet.html
-+*/
-+
-+/* These identify the driver base version and may not be removed. */
-+static const char version1[] =
-+"intel-gige.c:v0.14 11/17/2002 Written by Donald Becker <becker@scyld.com>\n";
-+static const char version2[] =
-+" http://www.scyld.com/network/ethernet.html\n";
-+
-+/* Automatically extracted configuration info:
-+probe-func: igige_probe
-+config-in: tristate 'Intel PCI Gigabit Ethernet support' CONFIG_IGIGE
-+
-+c-help-name: Intel PCI Gigabit Ethernet support
-+c-help-symbol: CONFIG_IGIGE
-+c-help: This driver is for the Intel PCI Gigabit Ethernet
-+c-help: adapter series.
-+c-help: More specific information and updates are available from
-+c-help: http://www.scyld.com/network/drivers.html
-+*/
-+
-+/* The user-configurable values.
-+ These may be modified when a driver module is loaded.*/
-+
-+/* Message enable level: 0..31 = no..all messages. See NETIF_MSG docs. */
-+static int debug = 2;
-+
-+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-+static int max_interrupt_work = 20;
-+
-+/* Maximum number of multicast addresses to filter (vs. rx-all-multicast).
-+ This chip has a 16 element perfect filter, and an unusual 4096 bit
-+ hash filter based directly on address bits, not the Ethernet CRC.
-+ It is costly to recalculate a large, frequently changing table.
-+ However even a large table may useful in some nearly-static environments.
-+*/
-+static int multicast_filter_limit = 15;
-+
-+/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
-+ Setting to > 1518 effectively disables this feature. */
-+static int rx_copybreak = 0;
-+
-+/* Used to pass the media type, etc.
-+ The media type is passed in 'options[]'. The full_duplex[] table only
-+ allows the duplex to be forced on, implicitly disabling autonegotiation.
-+ Setting the entry to zero still allows a link to autonegotiate to full
-+ duplex.
-+*/
-+#define MAX_UNITS 8 /* More are supported, limit only on options */
-+static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-+static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-+
-+/* The delay before announcing a Rx or Tx has completed. */
-+static int rx_intr_holdoff = 0;
-+static int tx_intr_holdoff = 128;
-+
-+/* Operational parameters that are set at compile time. */
-+
-+/* Keep the ring sizes a power of two to avoid divides.
-+ The compiler will convert <unsigned>'%'<2^N> into a bit mask.
-+ Making the Tx ring too large decreases the effectiveness of channel
-+ bonding and packet priority.
-+ There are no ill effects from too-large receive rings. */
-+#if ! defined(final_version) /* Stress the driver. */
-+#define TX_RING_SIZE 8
-+#define TX_QUEUE_LEN 5
-+#define RX_RING_SIZE 4
-+#else
-+#define TX_RING_SIZE 16
-+#define TX_QUEUE_LEN 10 /* Limit ring entries actually used. */
-+#define RX_RING_SIZE 32
-+#endif
-+
-+/* Operational parameters that usually are not changed. */
-+/* Time in jiffies before concluding the transmitter is hung. */
-+#define TX_TIMEOUT (6*HZ)
-+
-+/* Allocation size of Rx buffers with normal sized Ethernet frames.
-+ Do not change this value without good reason. This is not a limit,
-+ but a way to keep a consistent allocation size among drivers.
-+ */
-+#define PKT_BUF_SZ 1536
-+
-+#ifndef __KERNEL__
-+#define __KERNEL__
-+#endif
-+#if !defined(__OPTIMIZE__)
-+#warning You must compile this file with the correct options!
-+#warning See the last lines of the source file.
-+#error You must compile this driver with "-O".
-+#endif
-+
-+/* Include files, designed to support most kernel versions 2.0.0 and later. */
-+#include <linux/config.h>
-+#if defined(CONFIG_SMP) && ! defined(__SMP__)
-+#define __SMP__
-+#endif
-+#if defined(MODULE) && defined(CONFIG_MODVERSIONS) && ! defined(MODVERSIONS)
-+#define MODVERSIONS
-+#endif
-+
-+#include <linux/version.h>
-+#if defined(MODVERSIONS)
-+#include <linux/modversions.h>
-+#endif
-+#include <linux/module.h>
-+
-+#include <linux/kernel.h>
-+#include <linux/string.h>
-+#include <linux/timer.h>
-+#include <linux/errno.h>
-+#include <linux/ioport.h>
-+#if LINUX_VERSION_CODE >= 0x20400
-+#include <linux/slab.h>
-+#else
-+#include <linux/malloc.h>
-+#endif
-+#include <linux/interrupt.h>
-+#include <linux/pci.h>
-+#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/skbuff.h>
-+#include <asm/processor.h> /* Processor type for cache alignment. */
-+#include <asm/bitops.h>
-+#include <asm/io.h>
-+
-+#ifdef INLINE_PCISCAN
-+#include "k_compat.h"
-+#else
-+#include "pci-scan.h"
-+#include "kern_compat.h"
-+#endif
-+
-+/* Condensed operations for readability. */
-+#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr))
-+#define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr))
-+
-+#if (LINUX_VERSION_CODE >= 0x20100) && defined(MODULE)
-+char kernel_version[] = UTS_RELEASE;
-+#endif
-+
-+MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
-+MODULE_DESCRIPTION("Intel Gigabit Ethernet driver");
-+MODULE_LICENSE("GPL");
-+MODULE_PARM(debug, "i");
-+MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
-+MODULE_PARM(rx_copybreak, "i");
-+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
-+MODULE_PARM(multicast_filter_limit, "i");
-+MODULE_PARM(max_interrupt_work, "i");
-+MODULE_PARM_DESC(debug, "Driver message level (0-31)");
-+MODULE_PARM_DESC(options, "Force transceiver type or fixed speed+duplex");
-+MODULE_PARM_DESC(max_interrupt_work,
-+ "Driver maximum events handled per interrupt");
-+MODULE_PARM_DESC(full_duplex,
-+ "Non-zero to set forced full duplex (deprecated).");
-+MODULE_PARM_DESC(rx_copybreak,
-+ "Breakpoint in bytes for copy-only-tiny-frames");
-+MODULE_PARM_DESC(multicast_filter_limit,
-+ "Multicast addresses before switching to Rx-all-multicast");
-+
-+/*
-+ Theory of Operation
-+
-+I. Board Compatibility
-+
-+This driver is for the Intel Gigabit Ethernet adapter.
-+
-+II. Board-specific settings
-+
-+III. Driver operation
-+
-+IIIa. Descriptor Rings
-+
-+This driver uses two statically allocated fixed-size descriptor arrays
-+treated as rings by the hardware. The ring sizes are set at compile time
-+by RX/TX_RING_SIZE.
-+
-+IIIb/c. Transmit/Receive Structure
-+
-+This driver uses a zero-copy receive and transmit scheme.
-+The driver allocates full frame size skbuffs for the Rx ring buffers at
-+open() time and passes the skb->data field to the chip as receive data
-+buffers. When an incoming frame is less than RX_COPYBREAK bytes long,
-+a fresh skbuff is allocated and the frame is copied to the new skbuff.
-+When the incoming frame is larger, the skbuff is passed directly up the
-+protocol stack. Buffers consumed this way are replaced by newly allocated
-+skbuffs in a later phase of receives.
-+
-+The RX_COPYBREAK value is chosen to trade-off the memory wasted by
-+using a full-sized skbuff for small frames vs. the copying costs of larger
-+frames. New boards are typically used in generously configured machines
-+and the underfilled buffers have negligible impact compared to the benefit of
-+a single allocation size, so the default value of zero results in never
-+copying packets. When copying is done, the cost is usually mitigated by using
-+a combined copy/checksum routine. Copying also preloads the cache, which is
-+most useful with small frames.
-+
-+A subtle aspect of the operation is that the IP header at offset 14 in an
-+ethernet frame isn't longword aligned for further processing.
-+When unaligned buffers are permitted by the hardware (and always on copies)
-+frames are put into the skbuff at an offset of "+2", 16-byte aligning
-+the IP header.
-+
-+IIId. Synchronization
-+
-+The driver runs as two independent, single-threaded flows of control.
-+One is the send-packet routine which is single-threaded by the queue
-+layer. The other thread is the interrupt handler, which is single
-+threaded by the hardware and interrupt handling software.
-+
-+The send packet thread has partial control over the Tx ring. At the
-+start of a transmit attempt netif_pause_tx_queue(dev) is called. If the
-+transmit attempt fills the Tx queue controlled by the chip, the driver
-+informs the software queue layer by not calling
-+netif_unpause_tx_queue(dev) on exit.
-+
-+The interrupt handler has exclusive control over the Rx ring and records stats
-+from the Tx ring. After reaping the stats, it marks the Tx queue entry as
-+empty by incrementing the dirty_tx mark. Iff the 'lp->tx_full' flag is set, it
-+clears both the tx_full and tbusy flags.
-+
-+IIId. SMP semantics
-+
-+The following are serialized with respect to each other via the "xmit_lock".
-+ dev->hard_start_xmit() Transmit a packet
-+ dev->tx_timeout() Transmit watchdog for stuck Tx
-+ dev->set_multicast_list() Set the recieve filter.
-+Note: The Tx timeout watchdog code is implemented by the timer routine in
-+kernels up to 2.2.*. In 2.4.* and later the timeout code is part of the
-+driver interface.
-+
-+The following fall under the global kernel lock. The module will not be
-+unloaded during the call, unless a call with a potential reschedule e.g.
-+kmalloc() is called. No other synchronization assertion is made.
-+ dev->open()
-+ dev->do_ioctl()
-+ dev->get_stats()
-+Caution: The lock for dev->open() is commonly broken with request_irq() or
-+kmalloc(). It is best to avoid any lock-breaking call in do_ioctl() and
-+get_stats(), or additional module locking code must be implemented.
-+
-+The following is self-serialized (no simultaneous entry)
-+ An handler registered with request_irq().
-+
-+IV. Notes
-+
-+IVb. References
-+
-+Intel has also released a Linux driver for this product, "e1000".
-+
-+IVc. Errata
-+
-+*/
-+
-+
-+
-+static void *igige_probe1(struct pci_dev *pdev, void *init_dev,
-+ long ioaddr, int irq, int chip_idx, int find_cnt);
-+static int netdev_pwr_event(void *dev_instance, int event);
-+enum chip_capability_flags { CanHaveMII=1, };
-+#define PCI_IOTYPE ()
-+
-+static struct pci_id_info pci_id_tbl[] = {
-+ {"Intel Gigabit Ethernet adapter", {0x10008086, 0xffffffff, },
-+ PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR0, 0x1ffff, 0},
-+ {0,}, /* 0 terminated list. */
-+};
-+
-+struct drv_id_info igige_drv_id = {
-+ "intel-gige", PCI_HOTSWAP, PCI_CLASS_NETWORK_ETHERNET<<8, pci_id_tbl,
-+ igige_probe1, netdev_pwr_event };
-+
-+/* This hardware only has a PCI memory space BAR, not I/O space. */
-+#ifdef USE_IO_OPS
-+#error This driver only works with PCI memory space access.
-+#endif
-+
-+/* Offsets to the device registers.
-+*/
-+enum register_offsets {
-+ ChipCtrl=0x00, ChipStatus=0x08, EECtrl=0x10,
-+ FlowCtrlAddrLo=0x028, FlowCtrlAddrHi=0x02c, FlowCtrlType=0x030,
-+ VLANetherType=0x38,
-+
-+ RxAddrCAM=0x040,
-+ IntrStatus=0x0C0, /* Interrupt, Clear on Read, AKA ICR */
-+ IntrEnable=0x0D0, /* Set enable mask when '1' AKA IMS */
-+ IntrDisable=0x0D8, /* Clear enable mask when '1' */
-+
-+ RxControl=0x100,
-+ RxQ0IntrDelay=0x108, /* Rx list #0 interrupt delay timer. */
-+ RxRingPtr=0x110, /* Rx Desc. list #0 base address, 64bits */
-+ RxRingLen=0x118, /* Num bytes of Rx descriptors in ring. */
-+ RxDescHead=0x120,
-+ RxDescTail=0x128,
-+
-+ RxQ1IntrDelay=0x130, /* Rx list #1 interrupt delay timer. */
-+ RxRing1Ptr=0x138, /* Rx Desc. list #1 base address, 64bits */
-+ RxRing1Len=0x140, /* Num bytes of Rx descriptors in ring. */
-+ RxDesc1Head=0x148,
-+ RxDesc1Tail=0x150,
-+
-+ FlowCtrlTimer=0x170, FlowCtrlThrshHi=0x160, FlowCtrlThrshLo=0x168,
-+ TxConfigReg=0x178,
-+ RxConfigReg=0x180,
-+ MulticastArray=0x200,
-+
-+ TxControl=0x400,
-+ TxQState=0x408, /* 64 bit queue state */
-+ TxIPG=0x410, /* Inter-Packet Gap */
-+ TxRingPtr=0x420, TxRingLen=0x428,
-+ TxDescHead=0x430, TxDescTail=0x438, TxIntrDelay=0x440,
-+
-+ RxCRCErrs=0x4000, RxMissed=0x4010,
-+
-+ TxStatus=0x408,
-+ RxStatus=0x180,
-+};
-+
-+/* Bits in the interrupt status/mask registers. */
-+enum intr_status_bits {
-+ IntrTxDone=0x0001, /* Tx packet queued */
-+ IntrLinkChange=0x0004, /* Link Status Change */
-+ IntrRxSErr=0x0008, /* Rx Symbol/Sequence error */
-+ IntrRxEmpty=0x0010, /* Rx queue 0 Empty */
-+ IntrRxQ1Empty=0x0020, /* Rx queue 1 Empty */
-+ IntrRxDone=0x0080, /* Rx Done, Queue 0*/
-+ IntrRxDoneQ1=0x0100, /* Rx Done, Queue 0*/
-+ IntrPCIErr=0x0200, /* PCI Bus Error */
-+
-+ IntrTxEmpty=0x0002, /* Guess */
-+ StatsMax=0x1000, /* Unknown */
-+};
-+
-+/* Bits in the RxFilterMode register. */
-+enum rx_mode_bits {
-+ RxCtrlReset=0x01, RxCtrlEnable=0x02, RxCtrlAllUnicast=0x08,
-+ RxCtrlAllMulticast=0x10,
-+ RxCtrlLoopback=0xC0, /* We never configure loopback */
-+ RxCtrlAcceptBroadcast=0x8000,
-+ /* Aliased names.*/
-+ AcceptAllPhys=0x08, AcceptAllMulticast=0x10, AcceptBroadcast=0x8000,
-+ AcceptMyPhys=0,
-+ AcceptMulticast=0,
-+};
-+
-+/* The Rx and Tx buffer descriptors. */
-+struct rx_desc {
-+ u32 buf_addr;
-+ u32 buf_addr_hi;
-+ u32 csum_length; /* Checksum and length */
-+ u32 status; /* Errors and status. */
-+};
-+
-+struct tx_desc {
-+ u32 buf_addr;
-+ u32 buf_addr_hi;
-+ u32 cmd_length;
-+ u32 status; /* And errors */
-+};
-+
-+/* Bits in tx_desc.cmd_length */
-+enum tx_cmd_bits {
-+ TxDescEndPacket=0x02000000, TxCmdIntrDelay=0x80000000,
-+ TxCmdAddCRC=0x02000000, TxCmdDoTx=0x13000000,
-+};
-+enum tx_status_bits {
-+ TxDescDone=0x0001, TxDescEndPkt=0x0002,
-+};
-+
-+/* Bits in tx_desc.status */
-+enum rx_status_bits {
-+ RxDescDone=0x0001, RxDescEndPkt=0x0002,
-+};
-+
-+
-+#define PRIV_ALIGN 15 /* Required alignment mask */
-+/* Use __attribute__((aligned (L1_CACHE_BYTES))) to maintain alignment
-+ within the structure. */
-+struct netdev_private {
-+ struct net_device *next_module; /* Link for devices of this type. */
-+ void *priv_addr; /* Unaligned address for kfree */
-+ const char *product_name;
-+ /* The addresses of receive-in-place skbuffs. */
-+ struct sk_buff* rx_skbuff[RX_RING_SIZE];
-+ /* The saved address of a sent-in-place packet/buffer, for later free(). */
-+ struct sk_buff* tx_skbuff[TX_RING_SIZE];
-+ struct net_device_stats stats;
-+ struct timer_list timer; /* Media monitoring timer. */
-+ /* Keep frequently used values adjacent for cache effect. */
-+ int msg_level;
-+ int chip_id, drv_flags;
-+ struct pci_dev *pci_dev;
-+ int max_interrupt_work;
-+ int intr_enable;
-+ long in_interrupt; /* Word-long for SMP locks. */
-+
-+ struct rx_desc *rx_ring;
-+ struct rx_desc *rx_head_desc;
-+ unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */
-+ unsigned int rx_buf_sz; /* Based on MTU+slack. */
-+ int rx_copybreak;
-+
-+ struct tx_desc *tx_ring;
-+ unsigned int cur_tx, dirty_tx;
-+ unsigned int tx_full:1; /* The Tx queue is full. */
-+
-+ unsigned int rx_mode;
-+ unsigned int tx_config;
-+ int multicast_filter_limit;
-+ /* These values track the transceiver/media in use. */
-+ unsigned int full_duplex:1; /* Full-duplex operation requested. */
-+ unsigned int duplex_lock:1;
-+ unsigned int medialock:1; /* Do not sense media. */
-+ unsigned int default_port; /* Last dev->if_port value. */
-+};
-+
-+static int eeprom_read(long ioaddr, int location);
-+static int netdev_open(struct net_device *dev);
-+static int change_mtu(struct net_device *dev, int new_mtu);
-+static void check_duplex(struct net_device *dev);
-+static void netdev_timer(unsigned long data);
-+static void tx_timeout(struct net_device *dev);
-+static void init_ring(struct net_device *dev);
-+static int start_tx(struct sk_buff *skb, struct net_device *dev);
-+static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs);
-+static void netdev_error(struct net_device *dev, int intr_status);
-+static int netdev_rx(struct net_device *dev);
-+static void netdev_error(struct net_device *dev, int intr_status);
-+static void set_rx_mode(struct net_device *dev);
-+static struct net_device_stats *get_stats(struct net_device *dev);
-+static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-+static int netdev_close(struct net_device *dev);
-+
-+
-+
-+/* A list of our installed devices, for removing the driver module. */
-+static struct net_device *root_net_dev = NULL;
-+
-+#ifndef MODULE
-+int igige_probe(struct net_device *dev)
-+{
-+ if (pci_drv_register(&igige_drv_id, dev) < 0)
-+ return -ENODEV;
-+ printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2);
-+ return 0;
-+}
-+#endif
-+
-+static void *igige_probe1(struct pci_dev *pdev, void *init_dev,
-+ long ioaddr, int irq, int chip_idx, int card_idx)
-+{
-+ struct net_device *dev;
-+ struct netdev_private *np;
-+ void *priv_mem;
-+ int i, option = card_idx < MAX_UNITS ? options[card_idx] : 0;
-+
-+ dev = init_etherdev(init_dev, 0);
-+ if (!dev)
-+ return NULL;
-+
-+ printk(KERN_INFO "%s: %s at 0x%lx, ",
-+ dev->name, pci_id_tbl[chip_idx].name, ioaddr);
-+
-+ for (i = 0; i < 3; i++)
-+ ((u16*)dev->dev_addr)[i] = le16_to_cpu(eeprom_read(ioaddr, i));
-+ for (i = 0; i < 5; i++)
-+ printk("%2.2x:", dev->dev_addr[i]);
-+ printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);
-+
-+ /* Make certain elements e.g. descriptor lists are aligned. */
-+ priv_mem = kmalloc(sizeof(*np) + PRIV_ALIGN, GFP_KERNEL);
-+ /* Check for the very unlikely case of no memory. */
-+ if (priv_mem == NULL)
-+ return NULL;
-+
-+ /* Do bogusness checks before this point.
-+ We do a request_region() only to register /proc/ioports info. */
-+ request_region(ioaddr, pci_id_tbl[chip_idx].io_size, dev->name);
-+
-+ /* Reset the chip to erase previous misconfiguration. */
-+ writel(0x04000000, ioaddr + ChipCtrl);
-+
-+ dev->base_addr = ioaddr;
-+ dev->irq = irq;
-+
-+ dev->priv = np = (void *)(((long)priv_mem + PRIV_ALIGN) & ~PRIV_ALIGN);
-+ memset(np, 0, sizeof(*np));
-+ np->priv_addr = priv_mem;
-+
-+ np->next_module = root_net_dev;
-+ root_net_dev = dev;
-+
-+ np->pci_dev = pdev;
-+ np->chip_id = chip_idx;
-+ np->drv_flags = pci_id_tbl[chip_idx].drv_flags;
-+ np->msg_level = (1 << debug) - 1;
-+ np->rx_copybreak = rx_copybreak;
-+ np->max_interrupt_work = max_interrupt_work;
-+ np->multicast_filter_limit = multicast_filter_limit;
-+
-+ if (dev->mem_start)
-+ option = dev->mem_start;
-+
-+ /* The lower four bits are the media type. */
-+ if (option > 0) {
-+ if (option & 0x2220)
-+ np->full_duplex = 1;
-+ np->default_port = option & 0x3330;
-+ if (np->default_port)
-+ np->medialock = 1;
-+ }
-+ if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0)
-+ np->full_duplex = 1;
-+
-+ if (np->full_duplex)
-+ np->duplex_lock = 1;
-+
-+#if ! defined(final_version) /* Dump the EEPROM contents during development. */
-+ if (np->msg_level & NETIF_MSG_MISC) {
-+ int sum = 0;
-+ for (i = 0; i < 0x40; i++) {
-+ int eeval = eeprom_read(ioaddr, i);
-+ printk("%4.4x%s", eeval, i % 16 != 15 ? " " : "\n");
-+ sum += eeval;
-+ }
-+ printk(KERN_DEBUG "%s: EEPROM checksum %4.4X (expected value 0xBABA).\n",
-+ dev->name, sum & 0xffff);
-+ }
-+#endif
-+
-+ /* The chip-specific entries in the device structure. */
-+ dev->open = &netdev_open;
-+ dev->hard_start_xmit = &start_tx;
-+ dev->stop = &netdev_close;
-+ dev->get_stats = &get_stats;
-+ dev->set_multicast_list = &set_rx_mode;
-+ dev->do_ioctl = &mii_ioctl;
-+ dev->change_mtu = &change_mtu;
-+
-+ /* Turn off VLAN and clear the VLAN filter. */
-+ writel(0x04000000, ioaddr + VLANetherType);
-+ for (i = 0x600; i < 0x800; i+=4)
-+ writel(0, ioaddr + i);
-+ np->tx_config = 0x80000020;
-+ writel(np->tx_config, ioaddr + TxConfigReg);
-+ {
-+ int eeword10 = eeprom_read(ioaddr, 10);
-+ writel(((eeword10 & 0x01e0) << 17) | ((eeword10 & 0x0010) << 3),
-+ ioaddr + ChipCtrl);
-+ }
-+
-+ return dev;
-+}
-+
-+
-+/* Read the EEPROM interface with a serial bit streams generated by the
-+ host processor.
-+ The example below is for the common 93c46 EEPROM, 64 16 bit words. */
-+
-+/* Delay between EEPROM clock transitions.
-+ The effectivly flushes the write cache to prevent quick double-writes.
-+*/
-+#define eeprom_delay(ee_addr) readl(ee_addr)
-+
-+enum EEPROM_Ctrl_Bits {
-+ EE_ShiftClk=0x01, EE_ChipSelect=0x02, EE_DataIn=0x08, EE_DataOut=0x04,
-+};
-+#define EE_Write0 (EE_ChipSelect)
-+#define EE_Write1 (EE_ChipSelect | EE_DataOut)
-+
-+/* The EEPROM commands include the alway-set leading bit. */
-+enum EEPROM_Cmds { EE_WriteCmd=5, EE_ReadCmd=6, EE_EraseCmd=7, };
-+
-+static int eeprom_read(long addr, int location)
-+{
-+ int i;
-+ int retval = 0;
-+ long ee_addr = addr + EECtrl;
-+ int read_cmd = ((EE_ReadCmd<<6) | location) << 16 ;
-+ int cmd_len = 2+6+16;
-+ u32 baseval = readl(ee_addr) & ~0x0f;
-+
-+ writel(EE_Write0 | baseval, ee_addr);
-+
-+ /* Shift the read command bits out. */
-+ for (i = cmd_len; i >= 0; i--) {
-+ int dataval = baseval |
-+ ((read_cmd & (1 << i)) ? EE_Write1 : EE_Write0);
-+ writel(dataval, ee_addr);
-+ eeprom_delay(ee_addr);
-+ writel(dataval | EE_ShiftClk, ee_addr);
-+ eeprom_delay(ee_addr);
-+ retval = (retval << 1) | ((readl(ee_addr) & EE_DataIn) ? 1 : 0);
-+ }
-+
-+ /* Terminate the EEPROM access. */
-+ writel(baseval | EE_Write0, ee_addr);
-+ writel(baseval & ~EE_ChipSelect, ee_addr);
-+ return retval;
-+}
-+
-+
-+
-+static int netdev_open(struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+
-+ /* Some chips may need to be reset. */
-+
-+ MOD_INC_USE_COUNT;
-+
-+ if (np->tx_ring == 0)
-+ np->tx_ring = (void *)get_free_page(GFP_KERNEL);
-+ if (np->tx_ring == 0)
-+ return -ENOMEM;
-+ if (np->rx_ring == 0)
-+ np->rx_ring = (void *)get_free_page(GFP_KERNEL);
-+ if (np->tx_ring == 0) {
-+ free_page((long)np->tx_ring);
-+ return -ENOMEM;
-+ }
-+
-+ /* Note that both request_irq() and init_ring() call kmalloc(), which
-+ break the global kernel lock protecting this routine. */
-+ if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev)) {
-+ MOD_DEC_USE_COUNT;
-+ return -EAGAIN;
-+ }
-+
-+ if (np->msg_level & NETIF_MSG_IFUP)
-+ printk(KERN_DEBUG "%s: netdev_open() irq %d.\n",
-+ dev->name, dev->irq);
-+
-+ init_ring(dev);
-+
-+ writel(0, ioaddr + RxControl);
-+ writel(virt_to_bus(np->rx_ring), ioaddr + RxRingPtr);
-+#if ADDRLEN == 64
-+ writel(virt_to_bus(np->rx_ring) >> 32, ioaddr + RxRingPtr + 4);
-+#else
-+ writel(0, ioaddr + RxRingPtr + 4);
-+#endif
-+
-+ writel(RX_RING_SIZE * sizeof(struct rx_desc), ioaddr + RxRingLen);
-+ writel(0x80000000 | rx_intr_holdoff, ioaddr + RxQ0IntrDelay);
-+ writel(0, ioaddr + RxDescHead);
-+ writel(np->dirty_rx + RX_RING_SIZE, ioaddr + RxDescTail);
-+
-+ /* Zero the unused Rx ring #1. */
-+ writel(0, ioaddr + RxQ1IntrDelay);
-+ writel(0, ioaddr + RxRing1Ptr);
-+ writel(0, ioaddr + RxRing1Ptr + 4);
-+ writel(0, ioaddr + RxRing1Len);
-+ writel(0, ioaddr + RxDesc1Head);
-+ writel(0, ioaddr + RxDesc1Tail);
-+
-+ /* Use 0x002000FA for half duplex. */
-+ writel(0x000400FA, ioaddr + TxControl);
-+
-+ writel(virt_to_bus(np->tx_ring), ioaddr + TxRingPtr);
-+#if ADDRLEN == 64
-+ writel(virt_to_bus(np->tx_ring) >> 32, ioaddr + TxRingPtr + 4);
-+#else
-+ writel(0, ioaddr + TxRingPtr + 4);
-+#endif
-+
-+ writel(TX_RING_SIZE * sizeof(struct tx_desc), ioaddr + TxRingLen);
-+ writel(0, ioaddr + TxDescHead);
-+ writel(0, ioaddr + TxDescTail);
-+ writel(0, ioaddr + TxQState);
-+ writel(0, ioaddr + TxQState + 4);
-+
-+ /* Set IPG register with Ethernet standard values. */
-+ writel(0x00A0080A, ioaddr + TxIPG);
-+ /* The delay before announcing a Tx has completed. */
-+ writel(tx_intr_holdoff, ioaddr + TxIntrDelay);
-+
-+ writel(((u32*)dev->dev_addr)[0], ioaddr + RxAddrCAM);
-+ writel(0x80000000 | ((((u32*)dev->dev_addr)[1]) & 0xffff),
-+ ioaddr + RxAddrCAM + 4);
-+
-+ /* Initialize other registers. */
-+ /* Configure the PCI bus bursts and FIFO thresholds. */
-+
-+ if (dev->if_port == 0)
-+ dev->if_port = np->default_port;
-+
-+ np->in_interrupt = 0;
-+
-+ np->rx_mode = RxCtrlEnable;
-+ set_rx_mode(dev);
-+
-+ /* Tx mode */
-+ np->tx_config = 0x80000020;
-+ writel(np->tx_config, ioaddr + TxConfigReg);
-+
-+ /* Flow control */
-+ writel(0x00C28001, ioaddr + FlowCtrlAddrLo);
-+ writel(0x00000100, ioaddr + FlowCtrlAddrHi);
-+ writel(0x8808, ioaddr + FlowCtrlType);
-+ writel(0x0100, ioaddr + FlowCtrlTimer);
-+ writel(0x8000, ioaddr + FlowCtrlThrshHi);
-+ writel(0x4000, ioaddr + FlowCtrlThrshLo);
-+
-+ netif_start_tx_queue(dev);
-+
-+ /* Enable interrupts by setting the interrupt mask. */
-+ writel(IntrTxDone | IntrLinkChange | IntrRxDone | IntrPCIErr
-+ | IntrRxEmpty | IntrRxSErr, ioaddr + IntrEnable);
-+
-+ /* writel(1, dev->base_addr + RxCmd);*/
-+
-+ if (np->msg_level & NETIF_MSG_IFUP)
-+ printk(KERN_DEBUG "%s: Done netdev_open(), status: %x Rx %x Tx %x.\n",
-+ dev->name, (int)readl(ioaddr + ChipStatus),
-+ (int)readl(ioaddr + RxStatus), (int)readl(ioaddr + TxStatus));
-+
-+ /* Set the timer to check for link beat. */
-+ init_timer(&np->timer);
-+ np->timer.expires = jiffies + 3*HZ;
-+ np->timer.data = (unsigned long)dev;
-+ np->timer.function = &netdev_timer; /* timer handler */
-+ add_timer(&np->timer);
-+
-+ return 0;
-+}
-+
-+/* Update for jumbo frames...
-+ Changing the MTU while active is not allowed.
-+ */
-+static int change_mtu(struct net_device *dev, int new_mtu)
-+{
-+ if ((new_mtu < 68) || (new_mtu > 1500))
-+ return -EINVAL;
-+ if (netif_running(dev))
-+ return -EBUSY;
-+ dev->mtu = new_mtu;
-+ return 0;
-+}
-+
-+static void check_duplex(struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+ int chip_ctrl = readl(ioaddr + ChipCtrl);
-+ int rx_cfg = readl(ioaddr + RxConfigReg);
-+ int tx_cfg = readl(ioaddr + TxConfigReg);
-+#if 0
-+ int chip_status = readl(ioaddr + ChipStatus);
-+#endif
-+
-+ if (np->msg_level & NETIF_MSG_LINK)
-+ printk(KERN_DEBUG "%s: Link changed status. Ctrl %x rxcfg %8.8x "
-+ "txcfg %8.8x.\n",
-+ dev->name, chip_ctrl, rx_cfg, tx_cfg);
-+ if (np->medialock) {
-+ if (np->full_duplex)
-+ ;
-+ }
-+ /* writew(new_tx_mode, ioaddr + TxMode); */
-+}
-+
-+static void netdev_timer(unsigned long data)
-+{
-+ struct net_device *dev = (struct net_device *)data;
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+ int next_tick = 10*HZ;
-+
-+ if (np->msg_level & NETIF_MSG_TIMER) {
-+ printk(KERN_DEBUG "%s: Media selection timer tick, status %8.8x, "
-+ "Tx %x Rx %x.\n",
-+ dev->name, (int)readl(ioaddr + ChipStatus),
-+ (int)readl(ioaddr + TxStatus), (int)readl(ioaddr + RxStatus));
-+ }
-+ /* This will either have a small false-trigger window or will not catch
-+ tbusy incorrectly set when the queue is empty. */
-+ if ((jiffies - dev->trans_start) > TX_TIMEOUT &&
-+ (np->cur_tx - np->dirty_tx > 0 ||
-+ netif_queue_paused(dev)) ) {
-+ tx_timeout(dev);
-+ }
-+ check_duplex(dev);
-+ np->timer.expires = jiffies + next_tick;
-+ add_timer(&np->timer);
-+}
-+
-+static void tx_timeout(struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+
-+ printk(KERN_WARNING "%s: Transmit timed out, status %8.8x,"
-+ " resetting...\n", dev->name, (int)readl(ioaddr + ChipStatus));
-+
-+#ifndef __alpha__
-+ if (np->msg_level & NETIF_MSG_TX_ERR) {
-+ int i;
-+ printk(KERN_DEBUG " Tx registers: ");
-+ for (i = 0x400; i < 0x444; i += 8)
-+ printk(" %8.8x", (int)readl(ioaddr + i));
-+ printk("\n"KERN_DEBUG " Rx ring %p: ", np->rx_ring);
-+ for (i = 0; i < RX_RING_SIZE; i++)
-+ printk(" %8.8x", (unsigned int)np->rx_ring[i].status);
-+ printk("\n"KERN_DEBUG" Tx ring %p: ", np->tx_ring);
-+ for (i = 0; i < TX_RING_SIZE; i++)
-+ printk(" %4.4x", np->tx_ring[i].status);
-+ printk("\n");
-+ }
-+#endif
-+
-+ /* Perhaps we should reinitialize the hardware here. */
-+ dev->if_port = 0;
-+ /* Stop and restart the chip's Tx processes . */
-+
-+ /* Trigger an immediate transmit demand. */
-+
-+ dev->trans_start = jiffies;
-+ np->stats.tx_errors++;
-+ return;
-+}
-+
-+
-+/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
-+static void init_ring(struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ int i;
-+
-+ np->tx_full = 0;
-+ np->cur_rx = np->cur_tx = 0;
-+ np->dirty_rx = np->dirty_tx = 0;
-+
-+ np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);
-+ np->rx_head_desc = &np->rx_ring[0];
-+
-+ /* Initialize all Rx descriptors. */
-+ for (i = 0; i < RX_RING_SIZE; i++) {
-+ np->rx_skbuff[i] = 0;
-+ }
-+
-+ /* The number of ring descriptors is set by the ring length register,
-+ thus the chip does not use 'next_desc' chains. */
-+
-+ /* Fill in the Rx buffers. Allocation failures are acceptable. */
-+ for (i = 0; i < RX_RING_SIZE; i++) {
-+ struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz);
-+ np->rx_skbuff[i] = skb;
-+ if (skb == NULL)
-+ break;
-+ skb->dev = dev; /* Mark as being used by this device. */
-+ skb_reserve(skb, 2); /* 16 byte align the IP header. */
-+ np->rx_ring[i].buf_addr = virt_to_le32desc(skb->tail);
-+ np->rx_ring[i].buf_addr_hi = 0;
-+ np->rx_ring[i].status = 0;
-+ }
-+ np->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
-+
-+ for (i = 0; i < TX_RING_SIZE; i++) {
-+ np->tx_skbuff[i] = 0;
-+ np->tx_ring[i].status = 0;
-+ }
-+ return;
-+}
-+
-+static int start_tx(struct sk_buff *skb, struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ unsigned entry;
-+
-+ /* Block a timer-based transmit from overlapping. This happens when
-+ packets are presumed lost, and we use this check the Tx status. */
-+ if (netif_pause_tx_queue(dev) != 0) {
-+ /* This watchdog code is redundant with the media monitor timer. */
-+ if (jiffies - dev->trans_start > TX_TIMEOUT)
-+ tx_timeout(dev);
-+ return 1;
-+ }
-+
-+ /* Calculate the next Tx descriptor entry. */
-+ entry = np->cur_tx % TX_RING_SIZE;
-+
-+ np->tx_skbuff[entry] = skb;
-+
-+ /* Note: Descriptors may be uncached. Write each field only once. */
-+ np->tx_ring[entry].buf_addr = virt_to_le32desc(skb->data);
-+ np->tx_ring[entry].buf_addr_hi = 0;
-+ np->tx_ring[entry].cmd_length = cpu_to_le32(TxCmdDoTx | skb->len);
-+ np->tx_ring[entry].status = 0;
-+
-+ /* Non-CC architectures: explicitly flush descriptor and packet.
-+ cache_flush(np->tx_ring[entry], sizeof np->tx_ring[entry]);
-+ cache_flush(skb->data, skb->len);
-+ */
-+
-+ np->cur_tx++;
-+ if (np->cur_tx - np->dirty_tx >= TX_QUEUE_LEN - 1) {
-+ np->tx_full = 1;
-+ /* Check for a just-cleared queue. */
-+ if (np->cur_tx - (volatile int)np->dirty_tx < TX_QUEUE_LEN - 2) {
-+ netif_unpause_tx_queue(dev);
-+ np->tx_full = 0;
-+ } else
-+ netif_stop_tx_queue(dev);
-+ } else
-+ netif_unpause_tx_queue(dev); /* Typical path */
-+
-+ /* Inform the chip we have another Tx. */
-+ if (np->msg_level & NETIF_MSG_TX_QUEUED)
-+ printk(KERN_DEBUG "%s: Tx queued to slot %d, desc tail now %d "
-+ "writing %d.\n",
-+ dev->name, entry, (int)readl(dev->base_addr + TxDescTail),
-+ np->cur_tx % TX_RING_SIZE);
-+ writel(np->cur_tx % TX_RING_SIZE, dev->base_addr + TxDescTail);
-+
-+ dev->trans_start = jiffies;
-+
-+ if (np->msg_level & NETIF_MSG_TX_QUEUED) {
-+ printk(KERN_DEBUG "%s: Transmit frame #%d (%x) queued in slot %d.\n",
-+ dev->name, np->cur_tx, (int)virt_to_bus(&np->tx_ring[entry]),
-+ entry);
-+ }
-+ return 0;
-+}
-+
-+/* The interrupt handler does all of the Rx thread work and cleans up
-+ after the Tx thread. */
-+static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
-+{
-+ struct net_device *dev = (struct net_device *)dev_instance;
-+ struct netdev_private *np;
-+ long ioaddr;
-+ int work_limit;
-+
-+ ioaddr = dev->base_addr;
-+ np = (struct netdev_private *)dev->priv;
-+ work_limit = np->max_interrupt_work;
-+
-+#if defined(__i386__) && LINUX_VERSION_CODE < 0x020300
-+ /* A lock to prevent simultaneous entry bug on Intel SMP machines. */
-+ if (test_and_set_bit(0, (void*)&dev->interrupt)) {
-+ printk(KERN_ERR"%s: SMP simultaneous entry of an interrupt handler.\n",
-+ dev->name);
-+ dev->interrupt = 0; /* Avoid halting machine. */
-+ return;
-+ }
-+#endif
-+
-+ do {
-+ u32 intr_status = readl(ioaddr + IntrStatus);
-+
-+ if (np->msg_level & NETIF_MSG_INTR)
-+ printk(KERN_DEBUG "%s: Interrupt, status %4.4x.\n",
-+ dev->name, intr_status);
-+
-+ if (intr_status == 0 || intr_status == 0xffffffff)
-+ break;
-+
-+ if (intr_status & IntrRxDone)
-+ netdev_rx(dev);
-+
-+ for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) {
-+ int entry = np->dirty_tx % TX_RING_SIZE;
-+ if (np->tx_ring[entry].status == 0)
-+ break;
-+ if (np->msg_level & NETIF_MSG_TX_DONE)
-+ printk(KERN_DEBUG "%s: Transmit done, Tx status %8.8x.\n",
-+ dev->name, np->tx_ring[entry].status);
-+ np->stats.tx_packets++;
-+#if LINUX_VERSION_CODE > 0x20127
-+ np->stats.tx_bytes += np->tx_skbuff[entry]->len;
-+#endif
-+ /* Free the original skb. */
-+ dev_free_skb_irq(np->tx_skbuff[entry]);
-+ np->tx_skbuff[entry] = 0;
-+ }
-+ /* Note the 4 slot hysteresis to mark the queue non-full. */
-+ if (np->tx_full && np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 4) {
-+ /* The ring is no longer full, allow new TX entries. */
-+ np->tx_full = 0;
-+ netif_resume_tx_queue(dev);
-+ }
-+
-+ /* Abnormal error summary/uncommon events handlers. */
-+ if (intr_status & (IntrPCIErr | IntrLinkChange | StatsMax))
-+ netdev_error(dev, intr_status);
-+
-+ if (--work_limit < 0) {
-+ printk(KERN_WARNING "%s: Too much work at interrupt, "
-+ "status=0x%4.4x.\n",
-+ dev->name, intr_status);
-+ break;
-+ }
-+ } while (1);
-+
-+ if (np->msg_level & NETIF_MSG_INTR)
-+ printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
-+ dev->name, (int)readl(ioaddr + IntrStatus));
-+
-+#if defined(__i386__) && LINUX_VERSION_CODE < 0x020300
-+ clear_bit(0, (void*)&dev->interrupt);
-+#endif
-+ return;
-+}
-+
-+/* This routine is logically part of the interrupt handler, but separated
-+ for clarity and better register allocation. */
-+static int netdev_rx(struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ int entry = np->cur_rx % RX_RING_SIZE;
-+ int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx;
-+
-+ if (np->msg_level & NETIF_MSG_RX_STATUS) {
-+ printk(KERN_DEBUG " In netdev_rx(), entry %d status %4.4x.\n",
-+ entry, np->rx_ring[entry].status);
-+ }
-+
-+ /* If EOP is set on the next entry, it's a new packet. Send it up. */
-+ while (np->rx_head_desc->status & cpu_to_le32(RxDescDone)) {
-+ struct rx_desc *desc = np->rx_head_desc;
-+ u32 desc_status = le32_to_cpu(desc->status);
-+ int data_size = le32_to_cpu(desc->csum_length);
-+
-+ if (np->msg_level & NETIF_MSG_RX_STATUS)
-+ printk(KERN_DEBUG " netdev_rx() status was %8.8x.\n",
-+ desc_status);
-+ if (--boguscnt < 0)
-+ break;
-+ if ( ! (desc_status & RxDescEndPkt)) {
-+ printk(KERN_WARNING "%s: Oversized Ethernet frame spanned "
-+ "multiple buffers, entry %#x length %d status %4.4x!\n",
-+ dev->name, np->cur_rx, data_size, desc_status);
-+ np->stats.rx_length_errors++;
-+ } else {
-+ struct sk_buff *skb;
-+ /* Reported length should omit the CRC. */
-+ int pkt_len = (data_size & 0xffff) - 4;
-+
-+#ifndef final_version
-+ if (np->msg_level & NETIF_MSG_RX_STATUS)
-+ printk(KERN_DEBUG " netdev_rx() normal Rx pkt length %d"
-+ " of %d, bogus_cnt %d.\n",
-+ pkt_len, data_size, boguscnt);
-+#endif
-+ /* Check if the packet is long enough to accept without copying
-+ to a minimally-sized skbuff. */
-+ if (pkt_len < np->rx_copybreak
-+ && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
-+ skb->dev = dev;
-+ skb_reserve(skb, 2); /* 16 byte align the IP header */
-+#if HAS_IP_COPYSUM /* Call copy + cksum if available. */
-+ eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0);
-+ skb_put(skb, pkt_len);
-+#else
-+ memcpy(skb_put(skb, pkt_len), np->rx_skbuff[entry]->tail,
-+ pkt_len);
-+#endif
-+ } else {
-+ char *temp = skb_put(skb = np->rx_skbuff[entry], pkt_len);
-+ np->rx_skbuff[entry] = NULL;
-+#ifndef final_version /* Remove after testing. */
-+ if (le32desc_to_virt(np->rx_ring[entry].buf_addr) != temp)
-+ printk(KERN_ERR "%s: Internal fault: The skbuff addresses "
-+ "do not match in netdev_rx: %p vs. %p / %p.\n",
-+ dev->name,
-+ le32desc_to_virt(np->rx_ring[entry].buf_addr),
-+ skb->head, temp);
-+#endif
-+ }
-+#ifndef final_version /* Remove after testing. */
-+ /* You will want this info for the initial debug. */
-+ if (np->msg_level & NETIF_MSG_PKTDATA)
-+ printk(KERN_DEBUG " Rx data %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:"
-+ "%2.2x %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x %2.2x%2.2x "
-+ "%d.%d.%d.%d.\n",
-+ skb->data[0], skb->data[1], skb->data[2], skb->data[3],
-+ skb->data[4], skb->data[5], skb->data[6], skb->data[7],
-+ skb->data[8], skb->data[9], skb->data[10],
-+ skb->data[11], skb->data[12], skb->data[13],
-+ skb->data[14], skb->data[15], skb->data[16],
-+ skb->data[17]);
-+#endif
-+ skb->protocol = eth_type_trans(skb, dev);
-+ /* Note: checksum -> skb->ip_summed = CHECKSUM_UNNECESSARY; */
-+ netif_rx(skb);
-+ dev->last_rx = jiffies;
-+ np->stats.rx_packets++;
-+#if LINUX_VERSION_CODE > 0x20127
-+ np->stats.rx_bytes += pkt_len;
-+#endif
-+ }
-+ entry = (++np->cur_rx) % RX_RING_SIZE;
-+ np->rx_head_desc = &np->rx_ring[entry];
-+ }
-+
-+ /* Refill the Rx ring buffers. */
-+ for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) {
-+ struct sk_buff *skb;
-+ entry = np->dirty_rx % RX_RING_SIZE;
-+ if (np->rx_skbuff[entry] == NULL) {
-+ skb = dev_alloc_skb(np->rx_buf_sz);
-+ np->rx_skbuff[entry] = skb;
-+ if (skb == NULL)
-+ break; /* Better luck next round. */
-+ skb->dev = dev; /* Mark as being used by this device. */
-+ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
-+ np->rx_ring[entry].buf_addr = virt_to_le32desc(skb->tail);
-+ }
-+ np->rx_ring[entry].status = 0;
-+ }
-+
-+ /* Restart Rx engine if stopped. */
-+ /* writel(1, dev->base_addr + RxCmd); */
-+ return 0;
-+}
-+
-+static void netdev_error(struct net_device *dev, int intr_status)
-+{
-+ long ioaddr = dev->base_addr;
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+
-+ if (intr_status & IntrLinkChange) {
-+ int chip_ctrl = readl(ioaddr + ChipCtrl);
-+ if (np->msg_level & NETIF_MSG_LINK)
-+ printk(KERN_ERR "%s: Link changed: Autonegotiation on-going.\n",
-+ dev->name);
-+ if (chip_ctrl & 1)
-+ netif_link_up(dev);
-+ else
-+ netif_link_down(dev);
-+ check_duplex(dev);
-+ }
-+ if (intr_status & StatsMax) {
-+ get_stats(dev);
-+ }
-+ if ((intr_status & ~(IntrLinkChange|StatsMax))
-+ && (np->msg_level & NETIF_MSG_DRV))
-+ printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n",
-+ dev->name, intr_status);
-+ /* Hmmmmm, it's not clear how to recover from PCI faults. */
-+ if (intr_status & IntrPCIErr)
-+ np->stats.tx_fifo_errors++;
-+}
-+
-+static struct net_device_stats *get_stats(struct net_device *dev)
-+{
-+ long ioaddr = dev->base_addr;
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ int crc_errs = readl(ioaddr + RxCRCErrs);
-+
-+ if (crc_errs != 0xffffffff) {
-+ /* We need not lock this segment of code for SMP.
-+ The non-atomic-add vulnerability is very small
-+ and statistics are non-critical. */
-+ np->stats.rx_crc_errors += readl(ioaddr + RxCRCErrs);
-+ np->stats.rx_missed_errors += readl(ioaddr + RxMissed);
-+ }
-+
-+ return &np->stats;
-+}
-+
-+/* The little-endian AUTODIN II ethernet CRC calculations.
-+ A big-endian version is also available.
-+ This is slow but compact code. Do not use this routine for bulk data,
-+ use a table-based routine instead.
-+ This is common code and should be moved to net/core/crc.c.
-+ Chips may use the upper or lower CRC bits, and may reverse and/or invert
-+ them. Select the endian-ness that results in minimal calculations.
-+*/
-+static unsigned const ethernet_polynomial_le = 0xedb88320U;
-+static inline unsigned ether_crc_le(int length, unsigned char *data)
-+{
-+ unsigned int crc = 0xffffffff; /* Initial value. */
-+ while(--length >= 0) {
-+ unsigned char current_octet = *data++;
-+ int bit;
-+ for (bit = 8; --bit >= 0; current_octet >>= 1) {
-+ if ((crc ^ current_octet) & 1) {
-+ crc >>= 1;
-+ crc ^= ethernet_polynomial_le;
-+ } else
-+ crc >>= 1;
-+ }
-+ }
-+ return crc;
-+}
-+
-+static void set_rx_mode(struct net_device *dev)
-+{
-+ long ioaddr = dev->base_addr;
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ u32 new_mc_filter[128]; /* Multicast filter table */
-+ u32 new_rx_mode = np->rx_mode;
-+
-+ if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
-+ /* Unconditionally log net taps. */
-+ printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);
-+ new_rx_mode |=
-+ RxCtrlAcceptBroadcast | RxCtrlAllMulticast | RxCtrlAllUnicast;
-+ } else if ((dev->mc_count > np->multicast_filter_limit)
-+ || (dev->flags & IFF_ALLMULTI)) {
-+ /* Too many to match, or accept all multicasts. */
-+ new_rx_mode &= ~RxCtrlAllUnicast;
-+ new_rx_mode |= RxCtrlAcceptBroadcast | RxCtrlAllMulticast;
-+ } else {
-+ struct dev_mc_list *mclist;
-+ int i;
-+ memset(new_mc_filter, 0, sizeof(new_mc_filter));
-+ for (i = 0, mclist = dev->mc_list; mclist && i < 15;
-+ i++, mclist = mclist->next) {
-+ writel(((u32*)mclist->dmi_addr)[0], ioaddr + RxAddrCAM + 8 + i*8);
-+ writel((((u32*)mclist->dmi_addr)[1] & 0xffff) | 0x80000000,
-+ ioaddr + RxAddrCAM + 12 + i*8);
-+ }
-+ for (; mclist && i < dev->mc_count; i++, mclist = mclist->next) {
-+ set_bit(((u32*)mclist->dmi_addr)[1] & 0xfff,
-+ new_mc_filter);
-+ }
-+ new_rx_mode &= ~RxCtrlAllUnicast | RxCtrlAllMulticast;
-+ new_rx_mode |= RxCtrlAcceptBroadcast;
-+ if (dev->mc_count > 15)
-+ for (i = 0; i < 128; i++)
-+ writel(new_mc_filter[i], ioaddr + MulticastArray + (i<<2));
-+ }
-+ if (np->rx_mode != new_rx_mode)
-+ writel(np->rx_mode = new_rx_mode, ioaddr + RxControl);
-+}
-+
-+static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ u32 *data32 = (void *)&rq->ifr_data;
-+
-+ switch(cmd) {
-+ case SIOCGPARAMS:
-+ data32[0] = np->msg_level;
-+ data32[1] = np->multicast_filter_limit;
-+ data32[2] = np->max_interrupt_work;
-+ data32[3] = np->rx_copybreak;
-+ return 0;
-+ case SIOCSPARAMS:
-+ if (!capable(CAP_NET_ADMIN))
-+ return -EPERM;
-+ np->msg_level = data32[0];
-+ np->multicast_filter_limit = data32[1];
-+ np->max_interrupt_work = data32[2];
-+ np->rx_copybreak = data32[3];
-+ return 0;
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+}
-+
-+static int netdev_close(struct net_device *dev)
-+{
-+ long ioaddr = dev->base_addr;
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ int i;
-+
-+ netif_stop_tx_queue(dev);
-+
-+ if (np->msg_level & NETIF_MSG_IFDOWN) {
-+ printk(KERN_DEBUG "%s: Shutting down ethercard, status was Tx %4.4x "
-+ "Rx %4.4x Int %2.2x.\n",
-+ dev->name, (int)readl(ioaddr + TxStatus),
-+ (int)readl(ioaddr + RxStatus), (int)readl(ioaddr + IntrStatus));
-+ printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d, Rx %d / %d.\n",
-+ dev->name, np->cur_tx, np->dirty_tx, np->cur_rx, np->dirty_rx);
-+ }
-+
-+ /* Disable interrupts by clearing the interrupt mask. */
-+ writel(~0, ioaddr + IntrDisable);
-+ readl(ioaddr + IntrStatus);
-+
-+ /* Reset everything. */
-+ writel(0x04000000, ioaddr + ChipCtrl);
-+
-+ del_timer(&np->timer);
-+
-+#ifdef __i386__
-+ if (np->msg_level & NETIF_MSG_IFDOWN) {
-+ printk("\n"KERN_DEBUG" Tx ring at %8.8x:\n",
-+ (int)virt_to_bus(np->tx_ring));
-+ for (i = 0; i < TX_RING_SIZE; i++)
-+ printk(" #%d desc. buf %8.8x, length %8.8x, status %8.8x.\n",
-+ i, np->tx_ring[i].buf_addr, np->tx_ring[i].cmd_length,
-+ np->tx_ring[i].status);
-+ printk("\n"KERN_DEBUG " Rx ring %8.8x:\n",
-+ (int)virt_to_bus(np->rx_ring));
-+ for (i = 0; i < RX_RING_SIZE; i++) {
-+ printk(KERN_DEBUG " #%d desc. %4.4x %4.4x %8.8x\n",
-+ i, np->rx_ring[i].csum_length,
-+ np->rx_ring[i].status, np->rx_ring[i].buf_addr);
-+ if (np->rx_ring[i].buf_addr) {
-+ if (*(u8*)np->rx_skbuff[i]->tail != 0x69) {
-+ u16 *pkt_buf = (void *)np->rx_skbuff[i]->tail;
-+ int j;
-+ for (j = 0; j < 0x50; j++)
-+ printk(" %4.4x", pkt_buf[j]);
-+ printk("\n");
-+ }
-+ }
-+ }
-+ }
-+#endif /* __i386__ debugging only */
-+
-+ free_irq(dev->irq, dev);
-+
-+ /* Free all the skbuffs in the Rx queue. */
-+ for (i = 0; i < RX_RING_SIZE; i++) {
-+ np->rx_ring[i].status = 0;
-+ np->rx_ring[i].buf_addr = 0xBADF00D0; /* An invalid address. */
-+ if (np->rx_skbuff[i]) {
-+#if LINUX_VERSION_CODE < 0x20100
-+ np->rx_skbuff[i]->free = 1;
-+#endif
-+ dev_free_skb(np->rx_skbuff[i]);
-+ }
-+ np->rx_skbuff[i] = 0;
-+ }
-+ for (i = 0; i < TX_RING_SIZE; i++) {
-+ if (np->tx_skbuff[i])
-+ dev_free_skb(np->tx_skbuff[i]);
-+ np->tx_skbuff[i] = 0;
-+ }
-+
-+ MOD_DEC_USE_COUNT;
-+
-+ return 0;
-+}
-+
-+static int netdev_pwr_event(void *dev_instance, int event)
-+{
-+ struct net_device *dev = dev_instance;
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+
-+ if (np->msg_level & NETIF_MSG_LINK)
-+ printk(KERN_DEBUG "%s: Handling power event %d.\n", dev->name, event);
-+ switch(event) {
-+ case DRV_ATTACH:
-+ MOD_INC_USE_COUNT;
-+ break;
-+ case DRV_SUSPEND:
-+ /* Disable interrupts, stop Tx and Rx. */
-+ writel(~0, ioaddr + IntrDisable);
-+ /* writel(2, ioaddr + RxCmd); */
-+ /* writew(2, ioaddr + TxCmd); */
-+ break;
-+ case DRV_RESUME:
-+ /* This is incomplete: the actions are very chip specific. */
-+ set_rx_mode(dev);
-+ break;
-+ case DRV_DETACH: {
-+ struct net_device **devp, **next;
-+ if (dev->flags & IFF_UP) {
-+ /* Some, but not all, kernel versions close automatically. */
-+ dev_close(dev);
-+ dev->flags &= ~(IFF_UP|IFF_RUNNING);
-+ }
-+ unregister_netdev(dev);
-+ release_region(dev->base_addr, pci_id_tbl[np->chip_id].io_size);
-+ iounmap((char *)dev->base_addr);
-+ for (devp = &root_net_dev; *devp; devp = next) {
-+ next = &((struct netdev_private *)(*devp)->priv)->next_module;
-+ if (*devp == dev) {
-+ *devp = *next;
-+ break;
-+ }
-+ }
-+ if (np->priv_addr)
-+ kfree(np->priv_addr);
-+ kfree(dev);
-+ MOD_DEC_USE_COUNT;
-+ break;
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+
-+#ifdef MODULE
-+int init_module(void)
-+{
-+ /* Emit version even if no cards detected. */
-+ printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2);
-+ return pci_drv_register(&igige_drv_id, NULL);
-+}
-+
-+void cleanup_module(void)
-+{
-+ struct net_device *next_dev;
-+
-+ pci_drv_unregister(&igige_drv_id);
-+
-+ /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
-+ while (root_net_dev) {
-+ struct netdev_private *np = (void *)(root_net_dev->priv);
-+ unregister_netdev(root_net_dev);
-+ release_region(root_net_dev->base_addr,
-+ pci_id_tbl[np->chip_id].io_size);
-+ iounmap((char *)(root_net_dev->base_addr));
-+ next_dev = np->next_module;
-+ if (np->tx_ring == 0)
-+ free_page((long)np->tx_ring);
-+ if (np->rx_ring == 0)
-+ free_page((long)np->rx_ring);
-+ if (np->priv_addr)
-+ kfree(np->priv_addr);
-+ kfree(root_net_dev);
-+ root_net_dev = next_dev;
-+ }
-+}
-+
-+#endif /* MODULE */
-+
-+/*
-+ * Local variables:
-+ * compile-command: "make KERNVER=`uname -r` intel-gige.o"
-+ * compile-cmd: "gcc -DMODULE -Wall -Wstrict-prototypes -O6 -c intel-gige.c"
-+ * simple-compile-command: "gcc -DMODULE -O6 -c intel-gige.c"
-+ * c-indent-level: 4
-+ * c-basic-offset: 4
-+ * tab-width: 4
-+ * End:
-+ */
-Index: linux/src/drivers/net/kern_compat.h
-===================================================================
-RCS file: linux/src/drivers/net/kern_compat.h
-diff -N linux/src/drivers/net/kern_compat.h
---- /dev/null 1 Jan 1970 00:00:00 -0000
-+++ linux/src/drivers/net/kern_compat.h 20 Aug 2004 10:32:53 -0000
-@@ -0,0 +1,285 @@
-+#ifndef _KERN_COMPAT_H
-+#define _KERN_COMPAT_H
-+/* kern_compat.h: Linux PCI network adapter backward compatibility code. */
-+/*
-+ $Revision: 1.18 $ $Date: 2003/07/22 17:40:21 $
-+
-+ Kernel compatibility defines.
-+ This file provides macros to mask the difference between kernel versions.
-+ It is designed primarily to allow device drivers to be written so that
-+ they work with a range of kernel versions.
-+
-+ Written 1999-2003 Donald Becker, Scyld Computing Corporation
-+ This software may be used and distributed according to the terms
-+ of the GNU General Public License (GPL), incorporated herein by
-+ reference. Drivers interacting with these functions are derivative
-+ works and thus are covered the GPL. They must include an explicit
-+ GPL notice.
-+
-+ This code also provides inline scan and activate functions for PCI network
-+ interfaces. It has an interface identical to pci-scan.c, but is
-+ intended as an include file to simplify using updated drivers with older
-+ kernel versions.
-+ This code version matches pci-scan.c:v0.05 9/16/99
-+
-+ The author may be reached as becker@scyld.com, or
-+ Donald Becker
-+ Penguin Computing Corporation
-+ 914 Bay Ridge Road, Suite 220
-+ Annapolis MD 21403
-+
-+ Other contributers:
-+ <none>
-+*/
-+
-+/* We try to use defined values to decide when an interface has changed or
-+ added features, but we must have the kernel version number for a few. */
-+#if ! defined(LINUX_VERSION_CODE) || (LINUX_VERSION_CODE < 0x10000)
-+#include <linux/version.h>
-+#endif
-+/* Older kernel versions didn't include modversions automatically. */
-+#if LINUX_VERSION_CODE < 0x20300 && defined(MODVERSIONS)
-+#include <linux/modversions.h>
-+#endif
-+
-+/* There was no support for PCI address space mapping in 2.0, but the
-+ Alpha needed it. See the 2.2 documentation. */
-+#if LINUX_VERSION_CODE < 0x20100 && ! defined(__alpha__)
-+#define ioremap(a,b)\
-+ (((unsigned long)(a) >= 0x100000) ? vremap(a,b) : (void*)(a))
-+#define iounmap(v)\
-+ do { if ((unsigned long)(v) >= 0x100000) vfree(v);} while (0)
-+#endif
-+
-+/* Support for adding info about the purpose of and parameters for kernel
-+ modules was added in 2.1. */
-+#if LINUX_VERSION_CODE < 0x20115
-+#define MODULE_AUTHOR(name) extern int nonesuch
-+#define MODULE_DESCRIPTION(string) extern int nonesuch
-+#define MODULE_PARM(varname, typestring) extern int nonesuch
-+#define MODULE_PARM_DESC(var,desc) extern int nonesuch
-+#endif
-+#if !defined(MODULE_LICENSE)
-+#define MODULE_LICENSE(license) \
-+static const char __module_license[] __attribute__((section(".modinfo"))) = \
-+"license=" license
-+#endif
-+#if !defined(MODULE_PARM_DESC)
-+#define MODULE_PARM_DESC(var,desc) \
-+const char __module_parm_desc_##var[] \
-+__attribute__((section(".modinfo"))) = \
-+"parm_desc_" __MODULE_STRING(var) "=" desc
-+#endif
-+
-+/* SMP and better multiarchitecture support were added.
-+ Using an older kernel means we assume a little-endian uniprocessor.
-+*/
-+#if LINUX_VERSION_CODE < 0x20123
-+#define hard_smp_processor_id() smp_processor_id()
-+#define test_and_set_bit(val, addr) set_bit(val, addr)
-+#define cpu_to_le16(val) (val)
-+#define cpu_to_le32(val) (val)
-+#define le16_to_cpu(val) (val)
-+#define le16_to_cpus(val) /* In-place conversion. */
-+#define le32_to_cpu(val) (val)
-+#define cpu_to_be16(val) ((((val) & 0xff) << 8) + (((val) >> 8) & 0xff))
-+#define cpu_to_be32(val) ((cpu_to_be16(val) << 16) + cpu_to_be16((val) >> 16))
-+typedef long spinlock_t;
-+#define SPIN_LOCK_UNLOCKED 0
-+#define spin_lock(lock)
-+#define spin_unlock(lock)
-+#define spin_lock_irqsave(lock, flags) do {save_flags(flags); cli();} while(0)
-+#define spin_unlock_irqrestore(lock, flags) restore_flags(flags)
-+#endif
-+
-+#if LINUX_VERSION_CODE <= 0x20139
-+#define net_device_stats enet_statistics
-+#else
-+#define NETSTATS_VER2
-+#endif
-+
-+/* These are used by the netdrivers to report values from the
-+ MII (Media Indpendent Interface) management registers.
-+*/
-+#ifndef SIOCGMIIPHY
-+#define SIOCGMIIPHY (SIOCDEVPRIVATE) /* Get the PHY in use. */
-+#define SIOCGMIIREG (SIOCDEVPRIVATE+1) /* Read a PHY register. */
-+#define SIOCSMIIREG (SIOCDEVPRIVATE+2) /* Write a PHY register. */
-+#endif
-+#ifndef SIOCGPARAMS
-+#define SIOCGPARAMS (SIOCDEVPRIVATE+3) /* Read operational parameters. */
-+#define SIOCSPARAMS (SIOCDEVPRIVATE+4) /* Set operational parameters. */
-+#endif
-+
-+#if !defined(HAVE_NETIF_MSG)
-+enum {
-+ NETIF_MSG_DRV = 0x0001,
-+ NETIF_MSG_PROBE = 0x0002,
-+ NETIF_MSG_LINK = 0x0004,
-+ NETIF_MSG_TIMER = 0x0008,
-+ NETIF_MSG_IFDOWN = 0x0010,
-+ NETIF_MSG_IFUP = 0x0020,
-+ NETIF_MSG_RX_ERR = 0x0040,
-+ NETIF_MSG_TX_ERR = 0x0080,
-+ NETIF_MSG_TX_QUEUED = 0x0100,
-+ NETIF_MSG_INTR = 0x0200,
-+ NETIF_MSG_TX_DONE = 0x0400,
-+ NETIF_MSG_RX_STATUS = 0x0800,
-+ NETIF_MSG_PKTDATA = 0x1000,
-+ /* 2000 is reserved. */
-+ NETIF_MSG_WOL = 0x4000,
-+ NETIF_MSG_MISC = 0x8000,
-+ NETIF_MSG_RXFILTER = 0x10000,
-+};
-+#define NETIF_MSG_MAX 0x10000
-+#endif
-+
-+#if !defined(NETIF_MSG_MAX) || NETIF_MSG_MAX < 0x8000
-+#define NETIF_MSG_MISC 0x8000
-+#endif
-+#if !defined(NETIF_MSG_MAX) || NETIF_MSG_MAX < 0x10000
-+#define NETIF_MSG_RXFILTER 0x10000
-+#endif
-+
-+#if LINUX_VERSION_CODE < 0x20155
-+#include <linux/bios32.h>
-+#define PCI_SUPPORT_VER1
-+/* A minimal version of the 2.2.* PCI support that handles configuration
-+ space access.
-+ Drivers that actually use pci_dev fields must do explicit compatibility.
-+ Note that the struct pci_dev * "pointer" is actually a byte mapped integer!
-+*/
-+#if LINUX_VERSION_CODE < 0x20014
-+struct pci_dev { int not_used; };
-+#endif
-+
-+#define pci_find_slot(bus, devfn) (struct pci_dev*)((bus<<8) | devfn | 0xf0000)
-+#define bus_number(pci_dev) ((((int)(pci_dev))>>8) & 0xff)
-+#define devfn_number(pci_dev) (((int)(pci_dev)) & 0xff)
-+#define pci_bus_number(pci_dev) ((((int)(pci_dev))>>8) & 0xff)
-+#define pci_devfn(pci_dev) (((int)(pci_dev)) & 0xff)
-+
-+#ifndef CONFIG_PCI
-+extern inline int pci_present(void) { return 0; }
-+#else
-+#define pci_present pcibios_present
-+#endif
-+
-+#define pci_read_config_byte(pdev, where, valp)\
-+ pcibios_read_config_byte(bus_number(pdev), devfn_number(pdev), where, valp)
-+#define pci_read_config_word(pdev, where, valp)\
-+ pcibios_read_config_word(bus_number(pdev), devfn_number(pdev), where, valp)
-+#define pci_read_config_dword(pdev, where, valp)\
-+ pcibios_read_config_dword(bus_number(pdev), devfn_number(pdev), where, valp)
-+#define pci_write_config_byte(pdev, where, val)\
-+ pcibios_write_config_byte(bus_number(pdev), devfn_number(pdev), where, val)
-+#define pci_write_config_word(pdev, where, val)\
-+ pcibios_write_config_word(bus_number(pdev), devfn_number(pdev), where, val)
-+#define pci_write_config_dword(pdev, where, val)\
-+ pcibios_write_config_dword(bus_number(pdev), devfn_number(pdev), where, val)
-+#else
-+#define PCI_SUPPORT_VER2
-+#define pci_bus_number(pci_dev) ((pci_dev)->bus->number)
-+#define pci_devfn(pci_dev) ((pci_dev)->devfn)
-+#endif
-+
-+/* The arg count changed, but function name did not.
-+ We cover that bad choice by defining a new name.
-+*/
-+#if LINUX_VERSION_CODE < 0x20159
-+#define dev_free_skb(skb) dev_kfree_skb(skb, FREE_WRITE)
-+#define dev_free_skb_irq(skb) dev_kfree_skb(skb, FREE_WRITE)
-+#elif LINUX_VERSION_CODE < 0x20400
-+#define dev_free_skb(skb) dev_kfree_skb(skb)
-+#define dev_free_skb_irq(skb) dev_kfree_skb(skb)
-+#else
-+#define dev_free_skb(skb) dev_kfree_skb(skb)
-+#define dev_free_skb_irq(skb) dev_kfree_skb_irq(skb)
-+#endif
-+
-+/* Added at the suggestion of Jes Sorensen. */
-+#if LINUX_VERSION_CODE > 0x20153
-+#include <linux/init.h>
-+#else
-+#define __init
-+#define __initdata
-+#define __initfunc(__arginit) __arginit
-+#endif
-+
-+/* The old 'struct device' used a too-generic name. */
-+#if LINUX_VERSION_CODE < 0x2030d
-+#define net_device device
-+#endif
-+
-+/* More changes for the 2.4 kernel, some in the zillion 2.3.99 releases. */
-+#if LINUX_VERSION_CODE < 0x20363
-+#define DECLARE_MUTEX(name) struct semaphore (name) = MUTEX;
-+#define down_write(semaphore_p) down(semaphore_p)
-+#define down_read(semaphore_p) down(semaphore_p)
-+#define up_write(semaphore_p) up(semaphore_p)
-+#define up_read(semaphore_p) up(semaphore_p)
-+/* Note that the kernel version has a broken time_before()! */
-+#define time_after(a,b) ((long)(b) - (long)(a) < 0)
-+#define time_before(a,b) ((long)(a) - (long)(b) < 0)
-+#else
-+#define get_free_page get_zeroed_page
-+#endif
-+
-+/* The 2.2 kernels added the start of capability-based security for operations
-+ that formerally could only be done by root.
-+*/
-+#if ! defined(CAP_NET_ADMIN)
-+#define capable(CAP_XXX) (suser())
-+#endif
-+
-+#if ! defined(HAVE_NETIF_QUEUE)
-+#define netif_wake_queue(dev) do { clear_bit( 0, (void*)&(dev)->tbusy); mark_bh(NET_BH); } while (0)
-+#define netif_start_tx_queue(dev) do { (dev)->tbusy = 0; dev->start = 1; } while (0)
-+#define netif_stop_tx_queue(dev) do { (dev)->tbusy = 1; dev->start = 0; } while (0)
-+#define netif_queue_paused(dev) ((dev)->tbusy != 0)
-+/* Splitting these lines exposes a bug in some preprocessors. */
-+#define netif_pause_tx_queue(dev) (test_and_set_bit( 0, (void*)&(dev)->tbusy))
-+#define netif_unpause_tx_queue(dev) do { clear_bit( 0, (void*)&(dev)->tbusy); } while (0)
-+#define netif_resume_tx_queue(dev) do { clear_bit( 0, (void*)&(dev)->tbusy); mark_bh(NET_BH); } while (0)
-+
-+#define netif_running(dev) ((dev)->start != 0)
-+#define netif_device_attach(dev) do {; } while (0)
-+#define netif_device_detach(dev) do {; } while (0)
-+#define netif_device_present(dev) (1)
-+#define netif_set_tx_timeout(dev, func, deltajiffs) do {; } while (0)
-+#define netif_link_down(dev) (dev)->flags &= ~IFF_RUNNING
-+#define netif_link_up(dev) (dev)->flags |= IFF_RUNNING
-+
-+#else
-+
-+#define netif_start_tx_queue(dev) netif_start_queue(dev)
-+#define netif_stop_tx_queue(dev) netif_stop_queue(dev)
-+#define netif_queue_paused(dev) netif_queue_stopped(dev)
-+#define netif_resume_tx_queue(dev) netif_wake_queue(dev)
-+/* Only used in transmit path. No function in 2.4. */
-+#define netif_pause_tx_queue(dev) 0
-+#define netif_unpause_tx_queue(dev) do {; } while (0)
-+
-+#ifdef __LINK_STATE_NOCARRIER
-+#define netif_link_down(dev) netif_carrier_off(dev)
-+#define netif_link_up(dev) netif_carrier_on(dev)
-+#else
-+#define netif_link_down(dev) (dev)->flags &= ~IFF_RUNNING
-+#define netif_link_up(dev) (dev)->flags |= IFF_RUNNING
-+#endif
-+
-+#endif
-+#ifndef PCI_DMA_BUS_IS_PHYS
-+#define pci_dma_sync_single(pci_dev, base_addr, extent, tofrom) do {; } while (0)
-+#define pci_map_single(pci_dev, base_addr, extent, dir) virt_to_bus(base_addr)
-+#define pci_unmap_single(pci_dev, base_addr, extent, dir) do {; } while (0)
-+#endif
-+
-+#endif
-+/*
-+ * Local variables:
-+ * c-indent-level: 4
-+ * c-basic-offset: 4
-+ * tab-width: 4
-+ * End:
-+ */
-Index: linux/src/drivers/net/myson803.c
-===================================================================
-RCS file: linux/src/drivers/net/myson803.c
-diff -N linux/src/drivers/net/myson803.c
---- /dev/null 1 Jan 1970 00:00:00 -0000
-+++ linux/src/drivers/net/myson803.c 20 Aug 2004 10:32:53 -0000
-@@ -0,0 +1,1650 @@
-+/* myson803.c: A Linux device driver for the Myson mtd803 Ethernet chip. */
-+/*
-+ Written 1998-2003 by Donald Becker.
-+
-+ This software may be used and distributed according to the terms of
-+ the GNU General Public License (GPL), incorporated herein by reference.
-+ Drivers based on or derived from this code fall under the GPL and must
-+ retain the authorship, copyright and license notice. This file is not
-+ a complete program and may only be used when the entire operating
-+ system is licensed under the GPL.
-+
-+ The author may be reached as becker@scyld.com, or C/O
-+ Scyld Computing Corporation
-+ 410 Severn Ave., Suite 210
-+ Annapolis MD 21403
-+
-+ Support information and updates available at
-+ http://www.scyld.com/network/myson803.html
-+*/
-+
-+/* These identify the driver base version and may not be removed. */
-+static const char version1[] =
-+"myson803.c:v1.05 3/10/2003 Written by Donald Becker <becker@scyld.com>\n";
-+static const char version2[] =
-+" http://www.scyld.com/network/drivers.html\n";
-+
-+/* Automatically extracted configuration info:
-+probe-func: myson803_probe
-+config-in: tristate 'Myson MTD803 series Ethernet support' CONFIG_MYSON_ETHER
-+
-+c-help-name: Myson MTD803 PCI Ethernet support
-+c-help-symbol: CONFIG_MYSON_ETHER
-+c-help: This driver is for the Myson MTD803 Ethernet adapter series.
-+c-help: More specific information and updates are available from
-+c-help: http://www.scyld.com/network/drivers.html
-+*/
-+
-+/* The user-configurable values.
-+ These may be modified when a driver module is loaded.*/
-+
-+/* Message enable level: 0..31 = no..all messages. See NETIF_MSG docs. */
-+static int debug = 2;
-+
-+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-+static int max_interrupt_work = 40;
-+
-+/* Maximum number of multicast addresses to filter (vs. rx-all-multicast).
-+ This chip uses a 64 element hash table based on the Ethernet CRC. */
-+static int multicast_filter_limit = 32;
-+
-+/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
-+ Setting to > 1518 effectively disables this feature. */
-+static int rx_copybreak = 0;
-+
-+/* Used to pass the media type, etc.
-+ Both 'options[]' and 'full_duplex[]' should exist for driver
-+ interoperability.
-+ The media type is usually passed in 'options[]'.
-+ The default is autonegotation for speed and duplex.
-+ This should rarely be overridden.
-+ Use option values 0x10/0x20 for 10Mbps, 0x100,0x200 for 100Mbps.
-+ Use option values 0x10 and 0x100 for forcing half duplex fixed speed.
-+ Use option values 0x20 and 0x200 for forcing full duplex operation.
-+*/
-+#define MAX_UNITS 8 /* More are supported, limit only on options */
-+static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-+static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-+
-+/* Operational parameters that are set at compile time. */
-+
-+/* Keep the ring sizes a power of two for compile efficiency.
-+ The compiler will convert <unsigned>'%'<2^N> into a bit mask.
-+ Making the Tx ring too large decreases the effectiveness of channel
-+ bonding and packet priority.
-+ There are no ill effects from too-large receive rings. */
-+#define TX_RING_SIZE 16
-+#define TX_QUEUE_LEN 10 /* Limit Tx ring entries actually used. */
-+#define RX_RING_SIZE 32
-+
-+/* Operational parameters that usually are not changed. */
-+/* Time in jiffies before concluding the transmitter is hung. */
-+#define TX_TIMEOUT (6*HZ)
-+
-+/* Allocation size of Rx buffers with normal sized Ethernet frames.
-+ Do not change this value without good reason. This is not a limit,
-+ but a way to keep a consistent allocation size among drivers.
-+ */
-+#define PKT_BUF_SZ 1536
-+
-+#ifndef __KERNEL__
-+#define __KERNEL__
-+#endif
-+#if !defined(__OPTIMIZE__)
-+#warning You must compile this file with the correct options!
-+#warning See the last lines of the source file.
-+#error You must compile this driver with "-O".
-+#endif
-+
-+/* Include files, designed to support most kernel versions 2.0.0 and later. */
-+#include <linux/config.h>
-+#if defined(CONFIG_SMP) && ! defined(__SMP__)
-+#define __SMP__
-+#endif
-+#if defined(MODULE) && defined(CONFIG_MODVERSIONS) && ! defined(MODVERSIONS)
-+#define MODVERSIONS
-+#endif
-+
-+#include <linux/version.h>
-+#if defined(MODVERSIONS)
-+#include <linux/modversions.h>
-+#endif
-+#include <linux/module.h>
-+
-+#include <linux/kernel.h>
-+#include <linux/string.h>
-+#include <linux/timer.h>
-+#include <linux/errno.h>
-+#include <linux/ioport.h>
-+#if LINUX_VERSION_CODE >= 0x20400
-+#include <linux/slab.h>
-+#else
-+#include <linux/malloc.h>
-+#endif
-+#include <linux/interrupt.h>
-+#include <linux/pci.h>
-+#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/skbuff.h>
-+#include <linux/delay.h>
-+#include <asm/processor.h> /* Processor type for cache alignment. */
-+#include <asm/bitops.h>
-+#include <asm/io.h>
-+#include <asm/unaligned.h>
-+
-+#ifdef INLINE_PCISCAN
-+#include "k_compat.h"
-+#else
-+#include "pci-scan.h"
-+#include "kern_compat.h"
-+#endif
-+
-+/* Condensed operations for readability. */
-+#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr))
-+#define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr))
-+
-+#if (LINUX_VERSION_CODE >= 0x20100) && defined(MODULE)
-+char kernel_version[] = UTS_RELEASE;
-+#endif
-+
-+/* Kernels before 2.1.0 cannot map the high addrs assigned by some BIOSes. */
-+#if (LINUX_VERSION_CODE < 0x20100) || ! defined(MODULE)
-+#define USE_IO_OPS
-+#endif
-+
-+MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
-+MODULE_DESCRIPTION("Myson mtd803 Ethernet driver");
-+MODULE_LICENSE("GPL");
-+/* List in order of common use. */
-+MODULE_PARM(debug, "i");
-+MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
-+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
-+MODULE_PARM(max_interrupt_work, "i");
-+MODULE_PARM(rx_copybreak, "i");
-+MODULE_PARM(multicast_filter_limit, "i");
-+MODULE_PARM_DESC(debug, "Driver message level (0-31)");
-+MODULE_PARM_DESC(options, "Force transceiver type or fixed speed+duplex");
-+MODULE_PARM_DESC(full_duplex, "Non-zero to force full duplex, "
-+ "non-negotiated link (deprecated).");
-+MODULE_PARM_DESC(max_interrupt_work,
-+ "Maximum events handled per interrupt");
-+MODULE_PARM_DESC(rx_copybreak,
-+ "Breakpoint in bytes for copy-only-tiny-frames");
-+MODULE_PARM_DESC(multicast_filter_limit,
-+ "Multicast addresses before switching to Rx-all-multicast");
-+
-+/*
-+ Theory of Operation
-+
-+I. Board Compatibility
-+
-+This driver is for the Myson mtd803 chip.
-+It should work with other Myson 800 series chips.
-+
-+II. Board-specific settings
-+
-+None.
-+
-+III. Driver operation
-+
-+IIIa. Ring buffers
-+
-+This driver uses two statically allocated fixed-size descriptor lists
-+formed into rings by a branch from the final descriptor to the beginning of
-+the list. The ring sizes are set at compile time by RX/TX_RING_SIZE.
-+Some chips explicitly use only 2^N sized rings, while others use a
-+'next descriptor' pointer that the driver forms into rings.
-+
-+IIIb/c. Transmit/Receive Structure
-+
-+This driver uses a zero-copy receive and transmit scheme.
-+The driver allocates full frame size skbuffs for the Rx ring buffers at
-+open() time and passes the skb->data field to the chip as receive data
-+buffers. When an incoming frame is less than RX_COPYBREAK bytes long,
-+a fresh skbuff is allocated and the frame is copied to the new skbuff.
-+When the incoming frame is larger, the skbuff is passed directly up the
-+protocol stack. Buffers consumed this way are replaced by newly allocated
-+skbuffs in a later phase of receives.
-+
-+The RX_COPYBREAK value is chosen to trade-off the memory wasted by
-+using a full-sized skbuff for small frames vs. the copying costs of larger
-+frames. New boards are typically used in generously configured machines
-+and the underfilled buffers have negligible impact compared to the benefit of
-+a single allocation size, so the default value of zero results in never
-+copying packets. When copying is done, the cost is usually mitigated by using
-+a combined copy/checksum routine. Copying also preloads the cache, which is
-+most useful with small frames.
-+
-+A subtle aspect of the operation is that the IP header at offset 14 in an
-+ethernet frame isn't longword aligned for further processing.
-+When unaligned buffers are permitted by the hardware (and always on copies)
-+frames are put into the skbuff at an offset of "+2", 16-byte aligning
-+the IP header.
-+
-+IIId. Synchronization
-+
-+The driver runs as two independent, single-threaded flows of control. One
-+is the send-packet routine, which enforces single-threaded use by the
-+dev->tbusy flag. The other thread is the interrupt handler, which is single
-+threaded by the hardware and interrupt handling software.
-+
-+The send packet thread has partial control over the Tx ring and 'dev->tbusy'
-+flag. It sets the tbusy flag whenever it's queuing a Tx packet. If the next
-+queue slot is empty, it clears the tbusy flag when finished otherwise it sets
-+the 'lp->tx_full' flag.
-+
-+The interrupt handler has exclusive control over the Rx ring and records stats
-+from the Tx ring. After reaping the stats, it marks the Tx queue entry as
-+empty by incrementing the dirty_tx mark. Iff the 'lp->tx_full' flag is set, it
-+clears both the tx_full and tbusy flags.
-+
-+IIId. SMP semantics
-+
-+The following are serialized with respect to each other via the "xmit_lock".
-+ dev->hard_start_xmit() Transmit a packet
-+ dev->tx_timeout() Transmit watchdog for stuck Tx
-+ dev->set_multicast_list() Set the recieve filter.
-+Note: The Tx timeout watchdog code is implemented by the timer routine in
-+kernels up to 2.2.*. In 2.4.* and later the timeout code is part of the
-+driver interface.
-+
-+The following fall under the global kernel lock. The module will not be
-+unloaded during the call, unless a call with a potential reschedule e.g.
-+kmalloc() is called. No other synchronization assertion is made.
-+ dev->open()
-+ dev->do_ioctl()
-+ dev->get_stats()
-+Caution: The lock for dev->open() is commonly broken with request_irq() or
-+kmalloc(). It is best to avoid any lock-breaking call in do_ioctl() and
-+get_stats(), or additional module locking code must be implemented.
-+
-+The following is self-serialized (no simultaneous entry)
-+ An handler registered with request_irq().
-+
-+IV. Notes
-+
-+IVb. References
-+
-+http://www.scyld.com/expert/100mbps.html
-+http://scyld.com/expert/NWay.html
-+http://www.myson.com.hk/mtd/datasheet/mtd803.pdf
-+ Myson does not require a NDA to read the datasheet.
-+
-+IVc. Errata
-+
-+No undocumented errata.
-+*/
-+
-+
-+
-+/* PCI probe routines. */
-+
-+static void *myson_probe1(struct pci_dev *pdev, void *init_dev,
-+ long ioaddr, int irq, int chip_idx, int find_cnt);
-+static int netdev_pwr_event(void *dev_instance, int event);
-+
-+/* Chips prior to the 803 have an external MII transceiver. */
-+enum chip_capability_flags { HasMIIXcvr=1, HasChipXcvr=2 };
-+
-+#ifdef USE_IO_OPS
-+#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_IO | PCI_ADDR0)
-+#define PCI_IOSIZE 256
-+#else
-+#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR1)
-+#define PCI_IOSIZE 1024
-+#endif
-+
-+static struct pci_id_info pci_id_tbl[] = {
-+ {"Myson mtd803 Fast Ethernet", {0x08031516, 0xffffffff, },
-+ PCI_IOTYPE, PCI_IOSIZE, HasChipXcvr},
-+ {"Myson mtd891 Gigabit Ethernet", {0x08911516, 0xffffffff, },
-+ PCI_IOTYPE, PCI_IOSIZE, HasChipXcvr},
-+ {0,}, /* 0 terminated list. */
-+};
-+
-+struct drv_id_info myson803_drv_id = {
-+ "myson803", 0, PCI_CLASS_NETWORK_ETHERNET<<8, pci_id_tbl, myson_probe1,
-+ netdev_pwr_event };
-+
-+/* This driver was written to use PCI memory space, however x86-oriented
-+ hardware sometimes works only with I/O space accesses. */
-+#ifdef USE_IO_OPS
-+#undef readb
-+#undef readw
-+#undef readl
-+#undef writeb
-+#undef writew
-+#undef writel
-+#define readb inb
-+#define readw inw
-+#define readl inl
-+#define writeb outb
-+#define writew outw
-+#define writel outl
-+#endif
-+
-+/* Offsets to the various registers.
-+ Most accesses must be longword aligned. */
-+enum register_offsets {
-+ StationAddr=0x00, MulticastFilter0=0x08, MulticastFilter1=0x0C,
-+ FlowCtrlAddr=0x10, RxConfig=0x18, TxConfig=0x1a, PCIBusCfg=0x1c,
-+ TxStartDemand=0x20, RxStartDemand=0x24,
-+ RxCurrentPtr=0x28, TxRingPtr=0x2c, RxRingPtr=0x30,
-+ IntrStatus=0x34, IntrEnable=0x38,
-+ FlowCtrlThreshold=0x3c,
-+ MIICtrl=0x40, EECtrl=0x40, RxErrCnts=0x44, TxErrCnts=0x48,
-+ PHYMgmt=0x4c,
-+};
-+
-+/* Bits in the interrupt status/mask registers. */
-+enum intr_status_bits {
-+ IntrRxErr=0x0002, IntrRxDone=0x0004, IntrTxDone=0x0008,
-+ IntrTxEmpty=0x0010, IntrRxEmpty=0x0020, StatsMax=0x0040, RxEarly=0x0080,
-+ TxEarly=0x0100, RxOverflow=0x0200, TxUnderrun=0x0400,
-+ IntrPCIErr=0x2000, NWayDone=0x4000, LinkChange=0x8000,
-+};
-+
-+/* Bits in the RxMode (np->txrx_config) register. */
-+enum rx_mode_bits {
-+ RxEnable=0x01, RxFilter=0xfe,
-+ AcceptErr=0x02, AcceptRunt=0x08, AcceptBroadcast=0x40,
-+ AcceptMulticast=0x20, AcceptAllPhys=0x80, AcceptMyPhys=0x00,
-+ RxFlowCtrl=0x2000,
-+ TxEnable=0x40000, TxModeFDX=0x00100000, TxThreshold=0x00e00000,
-+};
-+
-+/* Misc. bits. */
-+enum misc_bits {
-+ BCR_Reset=1, /* PCIBusCfg */
-+ TxThresholdInc=0x200000,
-+};
-+
-+/* The Rx and Tx buffer descriptors. */
-+/* Note that using only 32 bit fields simplifies conversion to big-endian
-+ architectures. */
-+struct netdev_desc {
-+ u32 status;
-+ u32 ctrl_length;
-+ u32 buf_addr;
-+ u32 next_desc;
-+};
-+
-+/* Bits in network_desc.status */
-+enum desc_status_bits {
-+ DescOwn=0x80000000,
-+ RxDescStartPacket=0x0800, RxDescEndPacket=0x0400, RxDescWholePkt=0x0c00,
-+ RxDescErrSum=0x80, RxErrRunt=0x40, RxErrLong=0x20, RxErrFrame=0x10,
-+ RxErrCRC=0x08, RxErrCode=0x04,
-+ TxErrAbort=0x2000, TxErrCarrier=0x1000, TxErrLate=0x0800,
-+ TxErr16Colls=0x0400, TxErrDefer=0x0200, TxErrHeartbeat=0x0100,
-+ TxColls=0x00ff,
-+};
-+/* Bits in network_desc.ctrl_length */
-+enum ctrl_length_bits {
-+ TxIntrOnDone=0x80000000, TxIntrOnFIFO=0x40000000,
-+ TxDescEndPacket=0x20000000, TxDescStartPacket=0x10000000,
-+ TxAppendCRC=0x08000000, TxPadTo64=0x04000000, TxNormalPkt=0x3C000000,
-+};
-+
-+#define PRIV_ALIGN 15 /* Required alignment mask */
-+/* Use __attribute__((aligned (L1_CACHE_BYTES))) to maintain alignment
-+ within the structure. */
-+struct netdev_private {
-+ /* Descriptor rings first for alignment. */
-+ struct netdev_desc rx_ring[RX_RING_SIZE];
-+ struct netdev_desc tx_ring[TX_RING_SIZE];
-+ struct net_device *next_module; /* Link for devices of this type. */
-+ void *priv_addr; /* Unaligned address for kfree */
-+ /* The addresses of receive-in-place skbuffs. */
-+ struct sk_buff* rx_skbuff[RX_RING_SIZE];
-+ /* The saved address of a sent-in-place packet/buffer, for later free(). */
-+ struct sk_buff* tx_skbuff[TX_RING_SIZE];
-+ struct net_device_stats stats;
-+ struct timer_list timer; /* Media monitoring timer. */
-+ /* Frequently used values: keep some adjacent for cache effect. */
-+ int msg_level;
-+ int max_interrupt_work;
-+ int intr_enable;
-+ int chip_id, drv_flags;
-+ struct pci_dev *pci_dev;
-+
-+ struct netdev_desc *rx_head_desc;
-+ unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */
-+ unsigned int rx_buf_sz; /* Based on MTU+slack. */
-+ int rx_copybreak;
-+
-+ unsigned int cur_tx, dirty_tx;
-+ unsigned int tx_full:1; /* The Tx queue is full. */
-+ unsigned int rx_died:1;
-+ unsigned int txrx_config;
-+
-+ /* These values keep track of the transceiver/media in use. */
-+ unsigned int full_duplex:1; /* Full-duplex operation requested. */
-+ unsigned int duplex_lock:1;
-+ unsigned int medialock:1; /* Do not sense media. */
-+ unsigned int default_port; /* Last dev->if_port value. */
-+
-+ unsigned int mcast_filter[2];
-+ int multicast_filter_limit;
-+
-+ /* MII transceiver section. */
-+ int mii_cnt; /* MII device addresses. */
-+ u16 advertising; /* NWay media advertisement */
-+ unsigned char phys[2]; /* MII device addresses. */
-+};
-+
-+static int eeprom_read(long ioaddr, int location);
-+static int mdio_read(struct net_device *dev, int phy_id,
-+ unsigned int location);
-+static void mdio_write(struct net_device *dev, int phy_id,
-+ unsigned int location, int value);
-+static int netdev_open(struct net_device *dev);
-+static void check_duplex(struct net_device *dev);
-+static void netdev_timer(unsigned long data);
-+static void tx_timeout(struct net_device *dev);
-+static void init_ring(struct net_device *dev);
-+static int start_tx(struct sk_buff *skb, struct net_device *dev);
-+static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs);
-+static void netdev_error(struct net_device *dev, int intr_status);
-+static int netdev_rx(struct net_device *dev);
-+static void netdev_error(struct net_device *dev, int intr_status);
-+static void set_rx_mode(struct net_device *dev);
-+static struct net_device_stats *get_stats(struct net_device *dev);
-+static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-+static int netdev_close(struct net_device *dev);
-+
-+
-+
-+/* A list of our installed devices, for removing the driver module. */
-+static struct net_device *root_net_dev = NULL;
-+
-+#ifndef MODULE
-+int myson803_probe(struct net_device *dev)
-+{
-+ if (pci_drv_register(&myson803_drv_id, dev) < 0)
-+ return -ENODEV;
-+ if (debug >= NETIF_MSG_DRV) /* Emit version even if no cards detected. */
-+ printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2);
-+ return 0;
-+}
-+#endif
-+
-+static void *myson_probe1(struct pci_dev *pdev, void *init_dev,
-+ long ioaddr, int irq, int chip_idx, int card_idx)
-+{
-+ struct net_device *dev;
-+ struct netdev_private *np;
-+ void *priv_mem;
-+ int i, option = card_idx < MAX_UNITS ? options[card_idx] : 0;
-+
-+ dev = init_etherdev(init_dev, 0);
-+ if (!dev)
-+ return NULL;
-+
-+ printk(KERN_INFO "%s: %s at 0x%lx, ",
-+ dev->name, pci_id_tbl[chip_idx].name, ioaddr);
-+
-+ for (i = 0; i < 3; i++)
-+ ((u16 *)dev->dev_addr)[i] = le16_to_cpu(eeprom_read(ioaddr, i + 8));
-+ if (memcmp(dev->dev_addr, "\0\0\0\0\0", 6) == 0) {
-+ /* Fill a temp addr with the "locally administered" bit set. */
-+ memcpy(dev->dev_addr, ">Linux", 6);
-+ }
-+ for (i = 0; i < 5; i++)
-+ printk("%2.2x:", dev->dev_addr[i]);
-+ printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);
-+
-+#if ! defined(final_version) /* Dump the EEPROM contents during development. */
-+ if (debug > 4)
-+ for (i = 0; i < 0x40; i++)
-+ printk("%4.4x%s",
-+ eeprom_read(ioaddr, i), i % 16 != 15 ? " " : "\n");
-+#endif
-+
-+ /* Make certain elements e.g. descriptor lists are aligned. */
-+ priv_mem = kmalloc(sizeof(*np) + PRIV_ALIGN, GFP_KERNEL);
-+ /* Check for the very unlikely case of no memory. */
-+ if (priv_mem == NULL)
-+ return NULL;
-+
-+ /* Do bogusness checks before this point.
-+ We do a request_region() only to register /proc/ioports info. */
-+#ifdef USE_IO_OPS
-+ request_region(ioaddr, pci_id_tbl[chip_idx].io_size, dev->name);
-+#endif
-+
-+ /* Reset the chip to erase previous misconfiguration. */
-+ writel(BCR_Reset, ioaddr + PCIBusCfg);
-+
-+ dev->base_addr = ioaddr;
-+ dev->irq = irq;
-+
-+ dev->priv = np = (void *)(((long)priv_mem + PRIV_ALIGN) & ~PRIV_ALIGN);
-+ memset(np, 0, sizeof(*np));
-+ np->priv_addr = priv_mem;
-+
-+ np->next_module = root_net_dev;
-+ root_net_dev = dev;
-+
-+ np->pci_dev = pdev;
-+ np->chip_id = chip_idx;
-+ np->drv_flags = pci_id_tbl[chip_idx].drv_flags;
-+ np->msg_level = (1 << debug) - 1;
-+ np->rx_copybreak = rx_copybreak;
-+ np->max_interrupt_work = max_interrupt_work;
-+ np->multicast_filter_limit = multicast_filter_limit;
-+
-+ if (dev->mem_start)
-+ option = dev->mem_start;
-+
-+ /* The lower four bits are the media type. */
-+ if (option > 0) {
-+ if (option & 0x220)
-+ np->full_duplex = 1;
-+ np->default_port = option & 0x3ff;
-+ if (np->default_port)
-+ np->medialock = 1;
-+ }
-+ if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0)
-+ np->full_duplex = 1;
-+
-+ if (np->full_duplex) {
-+ if (np->msg_level & NETIF_MSG_PROBE)
-+ printk(KERN_INFO "%s: Set to forced full duplex, autonegotiation"
-+ " disabled.\n", dev->name);
-+ np->duplex_lock = 1;
-+ }
-+
-+ /* The chip-specific entries in the device structure. */
-+ dev->open = &netdev_open;
-+ dev->hard_start_xmit = &start_tx;
-+ dev->stop = &netdev_close;
-+ dev->get_stats = &get_stats;
-+ dev->set_multicast_list = &set_rx_mode;
-+ dev->do_ioctl = &mii_ioctl;
-+
-+ if (np->drv_flags & HasMIIXcvr) {
-+ int phy, phy_idx = 0;
-+ for (phy = 0; phy < 32 && phy_idx < 4; phy++) {
-+ int mii_status = mdio_read(dev, phy, 1);
-+ if (mii_status != 0xffff && mii_status != 0x0000) {
-+ np->phys[phy_idx++] = phy;
-+ np->advertising = mdio_read(dev, phy, 4);
-+ if (np->msg_level & NETIF_MSG_PROBE)
-+ printk(KERN_INFO "%s: MII PHY found at address %d, status "
-+ "0x%4.4x advertising %4.4x.\n",
-+ dev->name, phy, mii_status, np->advertising);
-+ }
-+ }
-+ np->mii_cnt = phy_idx;
-+ }
-+ if (np->drv_flags & HasChipXcvr) {
-+ np->phys[np->mii_cnt++] = 32;
-+ printk(KERN_INFO "%s: Internal PHY status 0x%4.4x"
-+ " advertising %4.4x.\n",
-+ dev->name, mdio_read(dev, 32, 1), mdio_read(dev, 32, 4));
-+ }
-+ /* Allow forcing the media type. */
-+ if (np->default_port & 0x330) {
-+ np->medialock = 1;
-+ if (option & 0x220)
-+ np->full_duplex = 1;
-+ printk(KERN_INFO " Forcing %dMbs %s-duplex operation.\n",
-+ (option & 0x300 ? 100 : 10),
-+ (np->full_duplex ? "full" : "half"));
-+ if (np->mii_cnt)
-+ mdio_write(dev, np->phys[0], 0,
-+ ((option & 0x300) ? 0x2000 : 0) | /* 100mbps? */
-+ (np->full_duplex ? 0x0100 : 0)); /* Full duplex? */
-+ }
-+
-+ return dev;
-+}
-+
-+
-+/* Read the EEPROM and MII Management Data I/O (MDIO) interfaces. These are
-+ often serial bit streams generated by the host processor.
-+ The example below is for the common 93c46 EEPROM, 64 16 bit words. */
-+
-+/* This "delay" forces out buffered PCI writes.
-+ The udelay() is unreliable for timing, but some Myson NICs shipped with
-+ absurdly slow EEPROMs.
-+ */
-+#define eeprom_delay(ee_addr) readl(ee_addr); udelay(2); readl(ee_addr)
-+
-+enum EEPROM_Ctrl_Bits {
-+ EE_ShiftClk=0x04<<16, EE_ChipSelect=0x88<<16,
-+ EE_DataOut=0x02<<16, EE_DataIn=0x01<<16,
-+ EE_Write0=0x88<<16, EE_Write1=0x8a<<16,
-+};
-+
-+/* The EEPROM commands always start with 01.. preamble bits.
-+ Commands are prepended to the variable-length address. */
-+enum EEPROM_Cmds { EE_WriteCmd=5, EE_ReadCmd=6, EE_EraseCmd=7, };
-+
-+static int eeprom_read(long addr, int location)
-+{
-+ int i;
-+ int retval = 0;
-+ long ee_addr = addr + EECtrl;
-+ int read_cmd = location | (EE_ReadCmd<<6);
-+
-+ writel(EE_ChipSelect, ee_addr);
-+
-+ /* Shift the read command bits out. */
-+ for (i = 10; i >= 0; i--) {
-+ int dataval = (read_cmd & (1 << i)) ? EE_Write1 : EE_Write0;
-+ writel(dataval, ee_addr);
-+ eeprom_delay(ee_addr);
-+ writel(dataval | EE_ShiftClk, ee_addr);
-+ eeprom_delay(ee_addr);
-+ }
-+ writel(EE_ChipSelect, ee_addr);
-+ eeprom_delay(ee_addr);
-+
-+ for (i = 16; i > 0; i--) {
-+ writel(EE_ChipSelect | EE_ShiftClk, ee_addr);
-+ eeprom_delay(ee_addr);
-+ retval = (retval << 1) | ((readl(ee_addr) & EE_DataIn) ? 1 : 0);
-+ writel(EE_ChipSelect, ee_addr);
-+ eeprom_delay(ee_addr);
-+ }
-+
-+ /* Terminate the EEPROM access. */
-+ writel(EE_ChipSelect, ee_addr);
-+ writel(0, ee_addr);
-+ return retval;
-+}
-+
-+/* MII transceiver control section.
-+ Read and write the MII registers using software-generated serial
-+ MDIO protocol. See the MII specifications or DP83840A data sheet
-+ for details.
-+
-+ The maximum data clock rate is 2.5 Mhz.
-+ The timing is decoupled from the processor clock by flushing the write
-+ from the CPU write buffer with a following read, and using PCI
-+ transaction timing. */
-+#define mdio_in(mdio_addr) readl(mdio_addr)
-+#define mdio_out(value, mdio_addr) writel(value, mdio_addr)
-+#define mdio_delay(mdio_addr) readl(mdio_addr)
-+
-+/* Set iff a MII transceiver on any interface requires mdio preamble.
-+ This only set with older tranceivers, so the extra
-+ code size of a per-interface flag is not worthwhile. */
-+static char mii_preamble_required = 0;
-+
-+enum mii_reg_bits {
-+ MDIO_ShiftClk=0x0001, MDIO_Data=0x0002, MDIO_EnbOutput=0x0004,
-+};
-+#define MDIO_EnbIn (0)
-+#define MDIO_WRITE0 (MDIO_EnbOutput)
-+#define MDIO_WRITE1 (MDIO_Data | MDIO_EnbOutput)
-+
-+/* Generate the preamble required for initial synchronization and
-+ a few older transceivers. */
-+static void mdio_sync(long mdio_addr)
-+{
-+ int bits = 32;
-+
-+ /* Establish sync by sending at least 32 logic ones. */
-+ while (--bits >= 0) {
-+ mdio_out(MDIO_WRITE1, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ mdio_out(MDIO_WRITE1 | MDIO_ShiftClk, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ }
-+}
-+
-+static int mdio_read(struct net_device *dev, int phy_id, unsigned int location)
-+{
-+ long ioaddr = dev->base_addr;
-+ long mdio_addr = ioaddr + MIICtrl;
-+ int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;
-+ int i, retval = 0;
-+
-+ if (location >= 32)
-+ return 0xffff;
-+ if (phy_id >= 32) {
-+ if (location < 6)
-+ return readw(ioaddr + PHYMgmt + location*2);
-+ else if (location == 16)
-+ return readw(ioaddr + PHYMgmt + 6*2);
-+ else if (location == 17)
-+ return readw(ioaddr + PHYMgmt + 7*2);
-+ else if (location == 18)
-+ return readw(ioaddr + PHYMgmt + 10*2);
-+ else
-+ return 0;
-+ }
-+
-+ if (mii_preamble_required)
-+ mdio_sync(mdio_addr);
-+
-+ /* Shift the read command bits out. */
-+ for (i = 15; i >= 0; i--) {
-+ int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
-+
-+ mdio_out(dataval, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ mdio_out(dataval | MDIO_ShiftClk, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ }
-+ /* Read the two transition, 16 data, and wire-idle bits. */
-+ for (i = 19; i > 0; i--) {
-+ mdio_out(MDIO_EnbIn, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ retval = (retval << 1) | ((mdio_in(mdio_addr) & MDIO_Data) ? 1 : 0);
-+ mdio_out(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ }
-+ return (retval>>1) & 0xffff;
-+}
-+
-+static void mdio_write(struct net_device *dev, int phy_id,
-+ unsigned int location, int value)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+ long mdio_addr = ioaddr + MIICtrl;
-+ int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;
-+ int i;
-+
-+ if (location == 4 && phy_id == np->phys[0])
-+ np->advertising = value;
-+ else if (location >= 32)
-+ return;
-+
-+ if (phy_id == 32) {
-+ if (location < 6)
-+ writew(value, ioaddr + PHYMgmt + location*2);
-+ else if (location == 16)
-+ writew(value, ioaddr + PHYMgmt + 6*2);
-+ else if (location == 17)
-+ writew(value, ioaddr + PHYMgmt + 7*2);
-+ return;
-+ }
-+
-+ if (mii_preamble_required)
-+ mdio_sync(mdio_addr);
-+
-+ /* Shift the command bits out. */
-+ for (i = 31; i >= 0; i--) {
-+ int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
-+
-+ mdio_out(dataval, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ mdio_out(dataval | MDIO_ShiftClk, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ }
-+ /* Clear out extra bits. */
-+ for (i = 2; i > 0; i--) {
-+ mdio_out(MDIO_EnbIn, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ mdio_out(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ }
-+ return;
-+}
-+
-+
-+static int netdev_open(struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+
-+ /* Some chips may need to be reset. */
-+
-+ MOD_INC_USE_COUNT;
-+
-+ writel(~0, ioaddr + IntrStatus);
-+
-+ /* Note that both request_irq() and init_ring() call kmalloc(), which
-+ break the global kernel lock protecting this routine. */
-+ if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev)) {
-+ MOD_DEC_USE_COUNT;
-+ return -EAGAIN;
-+ }
-+
-+ if (np->msg_level & NETIF_MSG_IFUP)
-+ printk(KERN_DEBUG "%s: netdev_open() irq %d.\n",
-+ dev->name, dev->irq);
-+
-+ init_ring(dev);
-+
-+ writel(virt_to_bus(np->rx_ring), ioaddr + RxRingPtr);
-+ writel(virt_to_bus(np->tx_ring), ioaddr + TxRingPtr);
-+
-+ /* Address register must be written as words. */
-+ writel(cpu_to_le32(cpu_to_le32(get_unaligned((u32 *)dev->dev_addr))),
-+ ioaddr + StationAddr);
-+ writel(cpu_to_le16(cpu_to_le16(get_unaligned((u16 *)(dev->dev_addr+4)))),
-+ ioaddr + StationAddr + 4);
-+ /* Set the flow control address, 01:80:c2:00:00:01. */
-+ writel(0x00c28001, ioaddr + FlowCtrlAddr);
-+ writel(0x00000100, ioaddr + FlowCtrlAddr + 4);
-+
-+ /* Initialize other registers. */
-+ /* Configure the PCI bus bursts and FIFO thresholds. */
-+ writel(0x01f8, ioaddr + PCIBusCfg);
-+
-+ if (dev->if_port == 0)
-+ dev->if_port = np->default_port;
-+
-+ np->txrx_config = TxEnable | RxEnable | RxFlowCtrl | 0x00600000;
-+ np->mcast_filter[0] = np->mcast_filter[1] = 0;
-+ np->rx_died = 0;
-+ set_rx_mode(dev);
-+ netif_start_tx_queue(dev);
-+
-+ /* Enable interrupts by setting the interrupt mask. */
-+ np->intr_enable = IntrRxDone | IntrRxErr | IntrRxEmpty | IntrTxDone
-+ | IntrTxEmpty | StatsMax | RxOverflow | TxUnderrun | IntrPCIErr
-+ | NWayDone | LinkChange;
-+ writel(np->intr_enable, ioaddr + IntrEnable);
-+
-+ if (np->msg_level & NETIF_MSG_IFUP)
-+ printk(KERN_DEBUG "%s: Done netdev_open(), PHY status: %x %x.\n",
-+ dev->name, (int)readw(ioaddr + PHYMgmt),
-+ (int)readw(ioaddr + PHYMgmt + 2));
-+
-+ /* Set the timer to check for link beat. */
-+ init_timer(&np->timer);
-+ np->timer.expires = jiffies + 3*HZ;
-+ np->timer.data = (unsigned long)dev;
-+ np->timer.function = &netdev_timer; /* timer handler */
-+ add_timer(&np->timer);
-+
-+ return 0;
-+}
-+
-+static void check_duplex(struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+ int new_tx_mode = np->txrx_config;
-+
-+ if (np->medialock) {
-+ } else {
-+ int mii_reg5 = mdio_read(dev, np->phys[0], 5);
-+ int negotiated = mii_reg5 & np->advertising;
-+ int duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;
-+ if (np->duplex_lock || mii_reg5 == 0xffff)
-+ return;
-+ if (duplex)
-+ new_tx_mode |= TxModeFDX;
-+ if (np->full_duplex != duplex) {
-+ np->full_duplex = duplex;
-+ if (np->msg_level & NETIF_MSG_LINK)
-+ printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d"
-+ " negotiated capability %4.4x.\n", dev->name,
-+ duplex ? "full" : "half", np->phys[0], negotiated);
-+ }
-+ }
-+ if (np->txrx_config != new_tx_mode)
-+ writel(new_tx_mode, ioaddr + RxConfig);
-+}
-+
-+static void netdev_timer(unsigned long data)
-+{
-+ struct net_device *dev = (struct net_device *)data;
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+ int next_tick = 10*HZ;
-+
-+ if (np->msg_level & NETIF_MSG_TIMER) {
-+ printk(KERN_DEBUG "%s: Media selection timer tick, status %8.8x.\n",
-+ dev->name, (int)readw(ioaddr + PHYMgmt + 10));
-+ }
-+ /* This will either have a small false-trigger window or will not catch
-+ tbusy incorrectly set when the queue is empty. */
-+ if (netif_queue_paused(dev) &&
-+ np->cur_tx - np->dirty_tx > 1 &&
-+ (jiffies - dev->trans_start) > TX_TIMEOUT) {
-+ tx_timeout(dev);
-+ }
-+ /* It's dead Jim, no race condition. */
-+ if (np->rx_died)
-+ netdev_rx(dev);
-+ check_duplex(dev);
-+ np->timer.expires = jiffies + next_tick;
-+ add_timer(&np->timer);
-+}
-+
-+static void tx_timeout(struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+
-+ printk(KERN_WARNING "%s: Transmit timed out, status %8.8x,"
-+ " resetting...\n", dev->name, (int)readl(ioaddr + IntrStatus));
-+
-+ if (np->msg_level & NETIF_MSG_TX_ERR) {
-+ int i;
-+ printk(KERN_DEBUG " Rx ring %p: ", np->rx_ring);
-+ for (i = 0; i < RX_RING_SIZE; i++)
-+ printk(" %8.8x", (unsigned int)np->rx_ring[i].status);
-+ printk("\n"KERN_DEBUG" Tx ring %p: ", np->tx_ring);
-+ for (i = 0; i < TX_RING_SIZE; i++)
-+ printk(" %8.8x", np->tx_ring[i].status);
-+ printk("\n");
-+ }
-+
-+ /* Stop and restart the chip's Tx processes . */
-+ writel(np->txrx_config & ~TxEnable, ioaddr + RxConfig);
-+ writel(virt_to_bus(np->tx_ring + (np->dirty_tx%TX_RING_SIZE)),
-+ ioaddr + TxRingPtr);
-+ writel(np->txrx_config, ioaddr + RxConfig);
-+ /* Trigger an immediate transmit demand. */
-+ writel(0, dev->base_addr + TxStartDemand);
-+
-+ dev->trans_start = jiffies;
-+ np->stats.tx_errors++;
-+ return;
-+}
-+
-+
-+/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
-+static void init_ring(struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ int i;
-+
-+ np->tx_full = 0;
-+ np->cur_rx = np->cur_tx = 0;
-+ np->dirty_rx = np->dirty_tx = 0;
-+
-+ np->rx_buf_sz = (dev->mtu <= 1532 ? PKT_BUF_SZ : dev->mtu + 4);
-+ np->rx_head_desc = &np->rx_ring[0];
-+
-+ /* Initialize all Rx descriptors. */
-+ for (i = 0; i < RX_RING_SIZE; i++) {
-+ np->rx_ring[i].ctrl_length = cpu_to_le32(np->rx_buf_sz);
-+ np->rx_ring[i].status = 0;
-+ np->rx_ring[i].next_desc = virt_to_le32desc(&np->rx_ring[i+1]);
-+ np->rx_skbuff[i] = 0;
-+ }
-+ /* Mark the last entry as wrapping the ring. */
-+ np->rx_ring[i-1].next_desc = virt_to_le32desc(&np->rx_ring[0]);
-+
-+ /* Fill in the Rx buffers. Handle allocation failure gracefully. */
-+ for (i = 0; i < RX_RING_SIZE; i++) {
-+ struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz);
-+ np->rx_skbuff[i] = skb;
-+ if (skb == NULL)
-+ break;
-+ skb->dev = dev; /* Mark as being used by this device. */
-+ np->rx_ring[i].buf_addr = virt_to_le32desc(skb->tail);
-+ np->rx_ring[i].status = cpu_to_le32(DescOwn);
-+ }
-+ np->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
-+
-+ for (i = 0; i < TX_RING_SIZE; i++) {
-+ np->tx_skbuff[i] = 0;
-+ np->tx_ring[i].status = 0;
-+ np->tx_ring[i].next_desc = virt_to_le32desc(&np->tx_ring[i+1]);
-+ }
-+ np->tx_ring[i-1].next_desc = virt_to_le32desc(&np->tx_ring[0]);
-+ return;
-+}
-+
-+static int start_tx(struct sk_buff *skb, struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ unsigned entry;
-+
-+ /* Block a timer-based transmit from overlapping. This happens when
-+ packets are presumed lost, and we use this check the Tx status. */
-+ if (netif_pause_tx_queue(dev) != 0) {
-+ /* This watchdog code is redundant with the media monitor timer. */
-+ if (jiffies - dev->trans_start > TX_TIMEOUT)
-+ tx_timeout(dev);
-+ return 1;
-+ }
-+
-+ /* Note: Ordering is important here, set the field with the
-+ "ownership" bit last, and only then increment cur_tx. */
-+
-+ /* Calculate the next Tx descriptor entry. */
-+ entry = np->cur_tx % TX_RING_SIZE;
-+
-+ np->tx_skbuff[entry] = skb;
-+
-+ np->tx_ring[entry].buf_addr = virt_to_le32desc(skb->data);
-+ np->tx_ring[entry].ctrl_length =
-+ cpu_to_le32(TxIntrOnDone | TxNormalPkt | (skb->len << 11) | skb->len);
-+ np->tx_ring[entry].status = cpu_to_le32(DescOwn);
-+ np->cur_tx++;
-+
-+ /* On some architectures: explicitly flushing cache lines here speeds
-+ operation. */
-+
-+ if (np->cur_tx - np->dirty_tx >= TX_QUEUE_LEN - 1) {
-+ np->tx_full = 1;
-+ /* Check for a just-cleared queue. */
-+ if (np->cur_tx - (volatile unsigned int)np->dirty_tx
-+ < TX_QUEUE_LEN - 2) {
-+ np->tx_full = 0;
-+ netif_unpause_tx_queue(dev);
-+ } else
-+ netif_stop_tx_queue(dev);
-+ } else
-+ netif_unpause_tx_queue(dev); /* Typical path */
-+ /* Wake the potentially-idle transmit channel. */
-+ writel(0, dev->base_addr + TxStartDemand);
-+
-+ dev->trans_start = jiffies;
-+
-+ if (np->msg_level & NETIF_MSG_TX_QUEUED) {
-+ printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n",
-+ dev->name, np->cur_tx, entry);
-+ }
-+ return 0;
-+}
-+
-+/* The interrupt handler does all of the Rx thread work and cleans up
-+ after the Tx thread. */
-+static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
-+{
-+ struct net_device *dev = (struct net_device *)dev_instance;
-+ struct netdev_private *np;
-+ long ioaddr;
-+ int boguscnt;
-+
-+#ifndef final_version /* Can never occur. */
-+ if (dev == NULL) {
-+ printk (KERN_ERR "Netdev interrupt handler(): IRQ %d for unknown "
-+ "device.\n", irq);
-+ return;
-+ }
-+#endif
-+
-+ ioaddr = dev->base_addr;
-+ np = (struct netdev_private *)dev->priv;
-+ boguscnt = np->max_interrupt_work;
-+
-+#if defined(__i386__) && LINUX_VERSION_CODE < 0x020300
-+ /* A lock to prevent simultaneous entry bug on Intel SMP machines. */
-+ if (test_and_set_bit(0, (void*)&dev->interrupt)) {
-+ printk(KERN_ERR"%s: SMP simultaneous entry of an interrupt handler.\n",
-+ dev->name);
-+ dev->interrupt = 0; /* Avoid halting machine. */
-+ return;
-+ }
-+#endif
-+
-+ do {
-+ u32 intr_status = readl(ioaddr + IntrStatus);
-+
-+ /* Acknowledge all of the current interrupt sources ASAP. */
-+ writel(intr_status, ioaddr + IntrStatus);
-+
-+ if (np->msg_level & NETIF_MSG_INTR)
-+ printk(KERN_DEBUG "%s: Interrupt, status %4.4x.\n",
-+ dev->name, intr_status);
-+
-+ if (intr_status == 0)
-+ break;
-+
-+ if (intr_status & IntrRxDone)
-+ netdev_rx(dev);
-+
-+ for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) {
-+ int entry = np->dirty_tx % TX_RING_SIZE;
-+ int tx_status = le32_to_cpu(np->tx_ring[entry].status);
-+ if (tx_status & DescOwn)
-+ break;
-+ if (np->msg_level & NETIF_MSG_TX_DONE)
-+ printk(KERN_DEBUG "%s: Transmit done, Tx status %8.8x.\n",
-+ dev->name, tx_status);
-+ if (tx_status & (TxErrAbort | TxErrCarrier | TxErrLate
-+ | TxErr16Colls | TxErrHeartbeat)) {
-+ if (np->msg_level & NETIF_MSG_TX_ERR)
-+ printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",
-+ dev->name, tx_status);
-+ np->stats.tx_errors++;
-+ if (tx_status & TxErrCarrier) np->stats.tx_carrier_errors++;
-+ if (tx_status & TxErrLate) np->stats.tx_window_errors++;
-+ if (tx_status & TxErrHeartbeat) np->stats.tx_heartbeat_errors++;
-+#ifdef ETHER_STATS
-+ if (tx_status & TxErr16Colls) np->stats.collisions16++;
-+ if (tx_status & TxErrAbort) np->stats.tx_aborted_errors++;
-+#else
-+ if (tx_status & (TxErr16Colls|TxErrAbort))
-+ np->stats.tx_aborted_errors++;
-+#endif
-+ } else {
-+ np->stats.tx_packets++;
-+ np->stats.collisions += tx_status & TxColls;
-+#if LINUX_VERSION_CODE > 0x20127
-+ np->stats.tx_bytes += np->tx_skbuff[entry]->len;
-+#endif
-+#ifdef ETHER_STATS
-+ if (tx_status & TxErrDefer) np->stats.tx_deferred++;
-+#endif
-+ }
-+ /* Free the original skb. */
-+ dev_free_skb_irq(np->tx_skbuff[entry]);
-+ np->tx_skbuff[entry] = 0;
-+ }
-+ /* Note the 4 slot hysteresis to mark the queue non-full. */
-+ if (np->tx_full && np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 4) {
-+ /* The ring is no longer full, allow new TX entries. */
-+ np->tx_full = 0;
-+ netif_resume_tx_queue(dev);
-+ }
-+
-+ /* Abnormal error summary/uncommon events handlers. */
-+ if (intr_status & (IntrRxErr | IntrRxEmpty | StatsMax | RxOverflow
-+ | TxUnderrun | IntrPCIErr | NWayDone | LinkChange))
-+ netdev_error(dev, intr_status);
-+
-+ if (--boguscnt < 0) {
-+ printk(KERN_WARNING "%s: Too much work at interrupt, "
-+ "status=0x%4.4x.\n",
-+ dev->name, intr_status);
-+ break;
-+ }
-+ } while (1);
-+
-+ if (np->msg_level & NETIF_MSG_INTR)
-+ printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
-+ dev->name, (int)readl(ioaddr + IntrStatus));
-+
-+#if defined(__i386__) && LINUX_VERSION_CODE < 0x020300
-+ clear_bit(0, (void*)&dev->interrupt);
-+#endif
-+ return;
-+}
-+
-+/* This routine is logically part of the interrupt handler, but separated
-+ for clarity and better register allocation. */
-+static int netdev_rx(struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ int entry = np->cur_rx % RX_RING_SIZE;
-+ int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx;
-+ int refilled = 0;
-+
-+ if (np->msg_level & NETIF_MSG_RX_STATUS) {
-+ printk(KERN_DEBUG " In netdev_rx(), entry %d status %4.4x.\n",
-+ entry, np->rx_ring[entry].status);
-+ }
-+
-+ /* If EOP is set on the next entry, it's a new packet. Send it up. */
-+ while ( ! (np->rx_head_desc->status & cpu_to_le32(DescOwn))) {
-+ struct netdev_desc *desc = np->rx_head_desc;
-+ u32 desc_status = le32_to_cpu(desc->status);
-+
-+ if (np->msg_level & NETIF_MSG_RX_STATUS)
-+ printk(KERN_DEBUG " netdev_rx() status was %8.8x.\n",
-+ desc_status);
-+ if (--boguscnt < 0)
-+ break;
-+ if ((desc_status & RxDescWholePkt) != RxDescWholePkt) {
-+ printk(KERN_WARNING "%s: Oversized Ethernet frame spanned "
-+ "multiple buffers, entry %#x length %d status %4.4x!\n",
-+ dev->name, np->cur_rx, desc_status >> 16, desc_status);
-+ np->stats.rx_length_errors++;
-+ } else if (desc_status & RxDescErrSum) {
-+ /* There was a error. */
-+ if (np->msg_level & NETIF_MSG_RX_ERR)
-+ printk(KERN_DEBUG " netdev_rx() Rx error was %8.8x.\n",
-+ desc_status);
-+ np->stats.rx_errors++;
-+ if (desc_status & (RxErrLong|RxErrRunt))
-+ np->stats.rx_length_errors++;
-+ if (desc_status & (RxErrFrame|RxErrCode))
-+ np->stats.rx_frame_errors++;
-+ if (desc_status & RxErrCRC)
-+ np->stats.rx_crc_errors++;
-+ } else {
-+ struct sk_buff *skb;
-+ /* Reported length should omit the CRC. */
-+ u16 pkt_len = ((desc_status >> 16) & 0xfff) - 4;
-+
-+#ifndef final_version
-+ if (np->msg_level & NETIF_MSG_RX_STATUS)
-+ printk(KERN_DEBUG " netdev_rx() normal Rx pkt length %d"
-+ " of %d, bogus_cnt %d.\n",
-+ pkt_len, pkt_len, boguscnt);
-+#endif
-+ /* Check if the packet is long enough to accept without copying
-+ to a minimally-sized skbuff. */
-+ if (pkt_len < np->rx_copybreak
-+ && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
-+ skb->dev = dev;
-+ skb_reserve(skb, 2); /* 16 byte align the IP header */
-+ eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0);
-+ skb_put(skb, pkt_len);
-+ } else {
-+ skb_put(skb = np->rx_skbuff[entry], pkt_len);
-+ np->rx_skbuff[entry] = NULL;
-+ }
-+#ifndef final_version /* Remove after testing. */
-+ /* You will want this info for the initial debug. */
-+ if (np->msg_level & NETIF_MSG_PKTDATA)
-+ printk(KERN_DEBUG " Rx data %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:"
-+ "%2.2x %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x %2.2x%2.2x "
-+ "%d.%d.%d.%d.\n",
-+ skb->data[0], skb->data[1], skb->data[2], skb->data[3],
-+ skb->data[4], skb->data[5], skb->data[6], skb->data[7],
-+ skb->data[8], skb->data[9], skb->data[10],
-+ skb->data[11], skb->data[12], skb->data[13],
-+ skb->data[14], skb->data[15], skb->data[16],
-+ skb->data[17]);
-+#endif
-+ skb->mac.raw = skb->data;
-+ /* Protocol lookup disabled until verified with all kernels. */
-+ if (0 && ntohs(skb->mac.ethernet->h_proto) >= 0x0800) {
-+ struct ethhdr *eth = skb->mac.ethernet;
-+ skb->protocol = eth->h_proto;
-+ if (desc_status & 0x1000) {
-+ if ((dev->flags & IFF_PROMISC) &&
-+ memcmp(eth->h_dest, dev->dev_addr, ETH_ALEN))
-+ skb->pkt_type = PACKET_OTHERHOST;
-+ } else if (desc_status & 0x2000)
-+ skb->pkt_type = PACKET_BROADCAST;
-+ else if (desc_status & 0x4000)
-+ skb->pkt_type = PACKET_MULTICAST;
-+ } else
-+ skb->protocol = eth_type_trans(skb, dev);
-+ netif_rx(skb);
-+ dev->last_rx = jiffies;
-+ np->stats.rx_packets++;
-+#if LINUX_VERSION_CODE > 0x20127
-+ np->stats.rx_bytes += pkt_len;
-+#endif
-+ }
-+ entry = (++np->cur_rx) % RX_RING_SIZE;
-+ np->rx_head_desc = &np->rx_ring[entry];
-+ }
-+
-+ /* Refill the Rx ring buffers. */
-+ for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) {
-+ struct sk_buff *skb;
-+ entry = np->dirty_rx % RX_RING_SIZE;
-+ if (np->rx_skbuff[entry] == NULL) {
-+ skb = dev_alloc_skb(np->rx_buf_sz);
-+ np->rx_skbuff[entry] = skb;
-+ if (skb == NULL)
-+ break; /* Better luck next round. */
-+ skb->dev = dev; /* Mark as being used by this device. */
-+ np->rx_ring[entry].buf_addr = virt_to_le32desc(skb->tail);
-+ }
-+ np->rx_ring[entry].ctrl_length = cpu_to_le32(np->rx_buf_sz);
-+ np->rx_ring[entry].status = cpu_to_le32(DescOwn);
-+ refilled++;
-+ }
-+
-+ /* Restart Rx engine if stopped. */
-+ if (refilled) { /* Perhaps "&& np->rx_died" */
-+ writel(0, dev->base_addr + RxStartDemand);
-+ np->rx_died = 0;
-+ }
-+ return refilled;
-+}
-+
-+static void netdev_error(struct net_device *dev, int intr_status)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+
-+ if (intr_status & (LinkChange | NWayDone)) {
-+ if (np->msg_level & NETIF_MSG_LINK)
-+ printk(KERN_NOTICE "%s: Link changed: Autonegotiation advertising"
-+ " %4.4x partner %4.4x.\n", dev->name,
-+ mdio_read(dev, np->phys[0], 4),
-+ mdio_read(dev, np->phys[0], 5));
-+ /* Clear sticky bit first. */
-+ readw(ioaddr + PHYMgmt + 2);
-+ if (readw(ioaddr + PHYMgmt + 2) & 0x0004)
-+ netif_link_up(dev);
-+ else
-+ netif_link_down(dev);
-+ check_duplex(dev);
-+ }
-+ if ((intr_status & TxUnderrun)
-+ && (np->txrx_config & TxThreshold) != TxThreshold) {
-+ np->txrx_config += TxThresholdInc;
-+ writel(np->txrx_config, ioaddr + RxConfig);
-+ np->stats.tx_fifo_errors++;
-+ }
-+ if (intr_status & IntrRxEmpty) {
-+ printk(KERN_WARNING "%s: Out of receive buffers: no free memory.\n",
-+ dev->name);
-+ /* Refill Rx descriptors */
-+ np->rx_died = 1;
-+ netdev_rx(dev);
-+ }
-+ if (intr_status & RxOverflow) {
-+ printk(KERN_WARNING "%s: Receiver overflow.\n", dev->name);
-+ np->stats.rx_over_errors++;
-+ netdev_rx(dev); /* Refill Rx descriptors */
-+ get_stats(dev); /* Empty dropped counter. */
-+ }
-+ if (intr_status & StatsMax) {
-+ get_stats(dev);
-+ }
-+ if ((intr_status & ~(LinkChange|NWayDone|StatsMax|TxUnderrun|RxOverflow
-+ |TxEarly|RxEarly|0x001e))
-+ && (np->msg_level & NETIF_MSG_DRV))
-+ printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n",
-+ dev->name, intr_status);
-+ /* Hmmmmm, it's not clear how to recover from PCI faults. */
-+ if (intr_status & IntrPCIErr) {
-+ const char *const pcierr[4] =
-+ { "Parity Error", "Master Abort", "Target Abort", "Unknown Error" };
-+ if (np->msg_level & NETIF_MSG_DRV)
-+ printk(KERN_WARNING "%s: PCI Bus %s, %x.\n",
-+ dev->name, pcierr[(intr_status>>11) & 3], intr_status);
-+ }
-+}
-+
-+/* We do not bother to spinlock statistics.
-+ A window only exists if we have non-atomic adds, the error counts are
-+ typically zero, and statistics are non-critical. */
-+static struct net_device_stats *get_stats(struct net_device *dev)
-+{
-+ long ioaddr = dev->base_addr;
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ unsigned int rxerrs = readl(ioaddr + RxErrCnts);
-+ unsigned int txerrs = readl(ioaddr + TxErrCnts);
-+
-+ /* The chip only need report frames silently dropped. */
-+ np->stats.rx_crc_errors += rxerrs >> 16;
-+ np->stats.rx_missed_errors += rxerrs & 0xffff;
-+
-+ /* These stats are required when the descriptor is closed before Tx. */
-+ np->stats.tx_aborted_errors += txerrs >> 24;
-+ np->stats.tx_window_errors += (txerrs >> 16) & 0xff;
-+ np->stats.collisions += txerrs & 0xffff;
-+
-+ return &np->stats;
-+}
-+
-+/* Big-endian AUTODIN II ethernet CRC calculations.
-+ This is slow but compact code. Do not use this routine for bulk data,
-+ use a table-based routine instead.
-+ This is common code and may be in the kernel with Linux 2.5+.
-+*/
-+static unsigned const ethernet_polynomial = 0x04c11db7U;
-+static inline u32 ether_crc(int length, unsigned char *data)
-+{
-+ u32 crc = ~0;
-+
-+ while(--length >= 0) {
-+ unsigned char current_octet = *data++;
-+ int bit;
-+ for (bit = 0; bit < 8; bit++, current_octet >>= 1)
-+ crc = (crc << 1) ^
-+ ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
-+ }
-+ return crc;
-+}
-+
-+static void set_rx_mode(struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+ u32 mc_filter[2]; /* Multicast hash filter */
-+ u32 rx_mode;
-+
-+ if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
-+ /* Unconditionally log net taps. */
-+ printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);
-+ mc_filter[1] = mc_filter[0] = ~0;
-+ rx_mode = AcceptBroadcast | AcceptMulticast | AcceptAllPhys
-+ | AcceptMyPhys;
-+ } else if ((dev->mc_count > np->multicast_filter_limit)
-+ || (dev->flags & IFF_ALLMULTI)) {
-+ /* Too many to match, or accept all multicasts. */
-+ mc_filter[1] = mc_filter[0] = ~0;
-+ rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
-+ } else {
-+ struct dev_mc_list *mclist;
-+ int i;
-+ mc_filter[1] = mc_filter[0] = 0;
-+ for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
-+ i++, mclist = mclist->next) {
-+ set_bit((ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26) & 0x3f,
-+ mc_filter);
-+ }
-+ rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
-+ }
-+ if (mc_filter[0] != np->mcast_filter[0] ||
-+ mc_filter[1] != np->mcast_filter[1]) {
-+ writel(mc_filter[0], ioaddr + MulticastFilter0);
-+ writel(mc_filter[1], ioaddr + MulticastFilter1);
-+ np->mcast_filter[0] = mc_filter[0];
-+ np->mcast_filter[1] = mc_filter[1];
-+ }
-+ if ((np->txrx_config & RxFilter) != rx_mode) {
-+ np->txrx_config &= ~RxFilter;
-+ np->txrx_config |= rx_mode;
-+ writel(np->txrx_config, ioaddr + RxConfig);
-+ }
-+}
-+
-+/*
-+ Handle user-level ioctl() calls.
-+ We must use two numeric constants as the key because some clueless person
-+ changed the value for the symbolic name.
-+*/
-+static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ u16 *data = (u16 *)&rq->ifr_data;
-+ u32 *data32 = (void *)&rq->ifr_data;
-+
-+ switch(cmd) {
-+ case 0x8947: case 0x89F0:
-+ /* SIOCGMIIPHY: Get the address of the PHY in use. */
-+ data[0] = np->phys[0];
-+ /* Fall Through */
-+ case 0x8948: case 0x89F1:
-+ /* SIOCGMIIREG: Read the specified MII register. */
-+ data[3] = mdio_read(dev, data[0], data[1]);
-+ return 0;
-+ case 0x8949: case 0x89F2:
-+ /* SIOCSMIIREG: Write the specified MII register */
-+ if (!capable(CAP_NET_ADMIN))
-+ return -EPERM;
-+ if (data[0] == np->phys[0]) {
-+ u16 value = data[2];
-+ switch (data[1]) {
-+ case 0:
-+ /* Check for autonegotiation on or reset. */
-+ np->medialock = (value & 0x9000) ? 0 : 1;
-+ if (np->medialock)
-+ np->full_duplex = (value & 0x0100) ? 1 : 0;
-+ break;
-+ case 4: np->advertising = value; break;
-+ }
-+ /* Perhaps check_duplex(dev), depending on chip semantics. */
-+ }
-+ mdio_write(dev, data[0], data[1], data[2]);
-+ return 0;
-+ case SIOCGPARAMS:
-+ data32[0] = np->msg_level;
-+ data32[1] = np->multicast_filter_limit;
-+ data32[2] = np->max_interrupt_work;
-+ data32[3] = np->rx_copybreak;
-+ return 0;
-+ case SIOCSPARAMS:
-+ if (!capable(CAP_NET_ADMIN))
-+ return -EPERM;
-+ np->msg_level = data32[0];
-+ np->multicast_filter_limit = data32[1];
-+ np->max_interrupt_work = data32[2];
-+ np->rx_copybreak = data32[3];
-+ return 0;
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+}
-+
-+static int netdev_close(struct net_device *dev)
-+{
-+ long ioaddr = dev->base_addr;
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ int i;
-+
-+ netif_stop_tx_queue(dev);
-+
-+ if (np->msg_level & NETIF_MSG_IFDOWN) {
-+ printk(KERN_DEBUG "%s: Shutting down ethercard, status was %8.8x.\n",
-+ dev->name, (int)readl(ioaddr + RxConfig));
-+ printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d, Rx %d / %d.\n",
-+ dev->name, np->cur_tx, np->dirty_tx, np->cur_rx, np->dirty_rx);
-+ }
-+
-+ /* Disable interrupts by clearing the interrupt mask. */
-+ writel(0x0000, ioaddr + IntrEnable);
-+
-+ /* Stop the chip's Tx and Rx processes. */
-+ np->txrx_config = 0;
-+ writel(0, ioaddr + RxConfig);
-+
-+ del_timer(&np->timer);
-+
-+#ifdef __i386__
-+ if (np->msg_level & NETIF_MSG_IFDOWN) {
-+ printk("\n"KERN_DEBUG" Tx ring at %8.8x:\n",
-+ (int)virt_to_bus(np->tx_ring));
-+ for (i = 0; i < TX_RING_SIZE; i++)
-+ printk(" #%d desc. %x %x %8.8x.\n",
-+ i, np->tx_ring[i].status, np->tx_ring[i].ctrl_length,
-+ np->tx_ring[i].buf_addr);
-+ printk("\n"KERN_DEBUG " Rx ring %8.8x:\n",
-+ (int)virt_to_bus(np->rx_ring));
-+ for (i = 0; i < RX_RING_SIZE; i++) {
-+ printk(KERN_DEBUG " #%d desc. %4.4x %4.4x %8.8x\n",
-+ i, np->rx_ring[i].status, np->rx_ring[i].ctrl_length,
-+ np->rx_ring[i].buf_addr);
-+ }
-+ }
-+#endif /* __i386__ debugging only */
-+
-+ free_irq(dev->irq, dev);
-+
-+ /* Free all the skbuffs in the Rx queue. */
-+ for (i = 0; i < RX_RING_SIZE; i++) {
-+ np->rx_ring[i].status = 0;
-+ np->rx_ring[i].buf_addr = 0xBADF00D0; /* An invalid address. */
-+ if (np->rx_skbuff[i]) {
-+#if LINUX_VERSION_CODE < 0x20100
-+ np->rx_skbuff[i]->free = 1;
-+#endif
-+ dev_free_skb(np->rx_skbuff[i]);
-+ }
-+ np->rx_skbuff[i] = 0;
-+ }
-+ for (i = 0; i < TX_RING_SIZE; i++) {
-+ if (np->tx_skbuff[i])
-+ dev_free_skb(np->tx_skbuff[i]);
-+ np->tx_skbuff[i] = 0;
-+ }
-+
-+ MOD_DEC_USE_COUNT;
-+
-+ return 0;
-+}
-+
-+static int netdev_pwr_event(void *dev_instance, int event)
-+{
-+ struct net_device *dev = dev_instance;
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+
-+ if (np->msg_level & NETIF_MSG_LINK)
-+ printk(KERN_DEBUG "%s: Handling power event %d.\n", dev->name, event);
-+ switch(event) {
-+ case DRV_ATTACH:
-+ MOD_INC_USE_COUNT;
-+ break;
-+ case DRV_SUSPEND:
-+ /* Disable interrupts, stop Tx and Rx. */
-+ writel(0, ioaddr + IntrEnable);
-+ writel(0, ioaddr + RxConfig);
-+ break;
-+ case DRV_RESUME:
-+ /* This is incomplete: the actions are very chip specific. */
-+ set_rx_mode(dev);
-+ writel(np->intr_enable, ioaddr + IntrEnable);
-+ break;
-+ case DRV_DETACH: {
-+ struct net_device **devp, **next;
-+ if (dev->flags & IFF_UP) {
-+ /* Some, but not all, kernel versions close automatically. */
-+ dev_close(dev);
-+ dev->flags &= ~(IFF_UP|IFF_RUNNING);
-+ }
-+ unregister_netdev(dev);
-+ release_region(dev->base_addr, pci_id_tbl[np->chip_id].io_size);
-+#ifndef USE_IO_OPS
-+ iounmap((char *)dev->base_addr);
-+#endif
-+ for (devp = &root_net_dev; *devp; devp = next) {
-+ next = &((struct netdev_private *)(*devp)->priv)->next_module;
-+ if (*devp == dev) {
-+ *devp = *next;
-+ break;
-+ }
-+ }
-+ if (np->priv_addr)
-+ kfree(np->priv_addr);
-+ kfree(dev);
-+ MOD_DEC_USE_COUNT;
-+ break;
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+
-+#ifdef MODULE
-+int init_module(void)
-+{
-+ if (debug >= NETIF_MSG_DRV) /* Emit version even if no cards detected. */
-+ printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2);
-+ return pci_drv_register(&myson803_drv_id, NULL);
-+}
-+
-+void cleanup_module(void)
-+{
-+ struct net_device *next_dev;
-+
-+ pci_drv_unregister(&myson803_drv_id);
-+
-+ /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
-+ while (root_net_dev) {
-+ struct netdev_private *np = (void *)(root_net_dev->priv);
-+ unregister_netdev(root_net_dev);
-+#ifdef USE_IO_OPS
-+ release_region(root_net_dev->base_addr,
-+ pci_id_tbl[np->chip_id].io_size);
-+#else
-+ iounmap((char *)(root_net_dev->base_addr));
-+#endif
-+ next_dev = np->next_module;
-+ if (np->priv_addr)
-+ kfree(np->priv_addr);
-+ kfree(root_net_dev);
-+ root_net_dev = next_dev;
-+ }
-+}
-+
-+#endif /* MODULE */
-+
-+/*
-+ * Local variables:
-+ * compile-command: "make KERNVER=`uname -r` myson803.o"
-+ * compile-cmd: "gcc -DMODULE -Wall -Wstrict-prototypes -O6 -c myson803.c"
-+ * simple-compile-command: "gcc -DMODULE -O6 -c myson803.c"
-+ * c-indent-level: 4
-+ * c-basic-offset: 4
-+ * tab-width: 4
-+ * End:
-+ */
-Index: linux/src/drivers/net/natsemi.c
-===================================================================
-RCS file: linux/src/drivers/net/natsemi.c
-diff -N linux/src/drivers/net/natsemi.c
---- /dev/null 1 Jan 1970 00:00:00 -0000
-+++ linux/src/drivers/net/natsemi.c 20 Aug 2004 10:32:53 -0000
-@@ -0,0 +1,1448 @@
-+/* natsemi.c: A Linux PCI Ethernet driver for the NatSemi DP83810 series. */
-+/*
-+ Written/copyright 1999-2003 by Donald Becker.
-+
-+ This software may be used and distributed according to the terms of
-+ the GNU General Public License (GPL), incorporated herein by reference.
-+ Drivers based on or derived from this code fall under the GPL and must
-+ retain the authorship, copyright and license notice. This file is not
-+ a complete program and may only be used when the entire operating
-+ system is licensed under the GPL. License for under other terms may be
-+ available. Contact the original author for details.
-+
-+ The original author may be reached as becker@scyld.com, or at
-+ Scyld Computing Corporation
-+ 914 Bay Ridge Road, Suite 220
-+ Annapolis MD 21403
-+
-+ Support information and updates available at
-+ http://www.scyld.com/network/natsemi.html
-+ The information and support mailing lists are based at
-+ http://www.scyld.com/mailman/listinfo/
-+*/
-+
-+/* These identify the driver base version and may not be removed. */
-+static const char version1[] =
-+"natsemi.c:v1.17a 8/09/2003 Written by Donald Becker <becker@scyld.com>\n";
-+static const char version2[] =
-+" http://www.scyld.com/network/natsemi.html\n";
-+/* Updated to recommendations in pci-skeleton v2.11. */
-+
-+/* Automatically extracted configuration info:
-+probe-func: natsemi_probe
-+config-in: tristate 'National Semiconductor DP8381x series PCI Ethernet support' CONFIG_NATSEMI
-+
-+c-help-name: National Semiconductor DP8381x series PCI Ethernet support
-+c-help-symbol: CONFIG_NATSEMI
-+c-help: This driver is for the National Semiconductor DP83810 series,
-+c-help: including the 83815 chip.
-+c-help: Usage information and updates are available from
-+c-help: http://www.scyld.com/network/natsemi.html
-+*/
-+
-+/* The user-configurable values.
-+ These may be modified when a driver module is loaded.*/
-+
-+/* Message enable level: 0..31 = no..all messages. See NETIF_MSG docs. */
-+static int debug = 2;
-+
-+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-+static int max_interrupt_work = 20;
-+
-+/* Maximum number of multicast addresses to filter (vs. rx-all-multicast).
-+ This chip uses a 512 element hash table based on the Ethernet CRC.
-+ Some chip versions are reported to have unreliable multicast filter
-+ circuitry. To work around an observed problem set this value to '0',
-+ which will immediately switch to Rx-all-multicast.
-+*/
-+static int multicast_filter_limit = 100;
-+
-+/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
-+ Setting to > 1518 effectively disables this feature.
-+ This chip can only receive into aligned buffers, so architectures such
-+ as the Alpha AXP might benefit from a copy-align.
-+*/
-+static int rx_copybreak = 0;
-+
-+/* Used to pass the media type, etc.
-+ Both 'options[]' and 'full_duplex[]' should exist for driver
-+ interoperability, however setting full_duplex[] is deprecated.
-+ The media type is usually passed in 'options[]'.
-+ The default is autonegotation for speed and duplex.
-+ This should rarely be overridden.
-+ Use option values 0x10/0x20 for 10Mbps, 0x100,0x200 for 100Mbps.
-+ Use option values 0x10 and 0x100 for forcing half duplex fixed speed.
-+ Use option values 0x20 and 0x200 for forcing full duplex operation.
-+*/
-+#define MAX_UNITS 8 /* More are supported, limit only on options */
-+static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-+static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-+
-+/* Operational parameters that are set at compile time. */
-+
-+/* Keep the ring sizes a power of two for compile efficiency.
-+ Understand the implications before changing these settings!
-+ The compiler will convert <unsigned>'%'<2^N> into a bit mask.
-+ Making the Tx ring too large decreases the effectiveness of channel
-+ bonding and packet priority.
-+ Too-large receive rings waste memory and confound network buffer limits. */
-+#define TX_RING_SIZE 16
-+#define TX_QUEUE_LEN 10 /* Limit ring entries actually used, min 4. */
-+#define RX_RING_SIZE 32
-+
-+/* Operational parameters that usually are not changed. */
-+/* Time in jiffies before concluding the transmitter is hung.
-+ Re-autonegotiation may take up to 3 seconds.
-+ */
-+#define TX_TIMEOUT (6*HZ)
-+
-+/* Allocation size of Rx buffers with normal sized Ethernet frames.
-+ Do not change this value without good reason. This is not a limit,
-+ but a way to keep a consistent allocation size among drivers.
-+ */
-+#define PKT_BUF_SZ 1536
-+
-+#ifndef __KERNEL__
-+#define __KERNEL__
-+#endif
-+#if !defined(__OPTIMIZE__)
-+#warning You must compile this file with the correct options!
-+#warning See the last lines of the source file.
-+#error You must compile this driver with "-O".
-+#endif
-+
-+/* Include files, designed to support most kernel versions 2.0.0 and later. */
-+#include <linux/config.h>
-+#if defined(CONFIG_SMP) && ! defined(__SMP__)
-+#define __SMP__
-+#endif
-+#if defined(MODULE) && defined(CONFIG_MODVERSIONS) && ! defined(MODVERSIONS)
-+#define MODVERSIONS
-+#endif
-+
-+#include <linux/version.h>
-+#if defined(MODVERSIONS)
-+#include <linux/modversions.h>
-+#endif
-+#include <linux/module.h>
-+
-+#include <linux/kernel.h>
-+#include <linux/string.h>
-+#include <linux/timer.h>
-+#include <linux/errno.h>
-+#include <linux/ioport.h>
-+#if LINUX_VERSION_CODE >= 0x20400
-+#include <linux/slab.h>
-+#else
-+#include <linux/malloc.h>
-+#endif
-+#include <linux/interrupt.h>
-+#include <linux/pci.h>
-+#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/skbuff.h>
-+#include <asm/processor.h> /* Processor type for cache alignment. */
-+#include <asm/bitops.h>
-+#include <asm/io.h>
-+
-+#ifdef INLINE_PCISCAN
-+#include "k_compat.h"
-+#else
-+#include "pci-scan.h"
-+#include "kern_compat.h"
-+#endif
-+
-+/* Condensed operations for readability. */
-+#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr))
-+#define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr))
-+
-+#if (LINUX_VERSION_CODE >= 0x20100) && defined(MODULE)
-+char kernel_version[] = UTS_RELEASE;
-+#endif
-+
-+MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
-+MODULE_DESCRIPTION("National Semiconductor DP83810 series PCI Ethernet driver");
-+MODULE_LICENSE("GPL");
-+MODULE_PARM(debug, "i");
-+MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
-+MODULE_PARM(rx_copybreak, "i");
-+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
-+MODULE_PARM(multicast_filter_limit, "i");
-+MODULE_PARM(max_interrupt_work, "i");
-+MODULE_PARM_DESC(debug, "Driver message level (0-31)");
-+MODULE_PARM_DESC(options, "Force transceiver type or fixed speed+duplex");
-+MODULE_PARM_DESC(max_interrupt_work,
-+ "Driver maximum events handled per interrupt");
-+MODULE_PARM_DESC(full_duplex,
-+ "Non-zero to force full duplex, non-negotiated link "
-+ "(deprecated).");
-+MODULE_PARM_DESC(rx_copybreak,
-+ "Breakpoint in bytes for copy-only-tiny-frames");
-+MODULE_PARM_DESC(multicast_filter_limit,
-+ "Multicast addresses before switching to Rx-all-multicast");
-+
-+/*
-+ Theory of Operation
-+
-+I. Board Compatibility
-+
-+This driver is designed for National Semiconductor DP83815 PCI Ethernet NIC.
-+It also works with other chips in in the DP83810 series.
-+The most common board is the Netgear FA311 using the 83815.
-+
-+II. Board-specific settings
-+
-+This driver requires the PCI interrupt line to be valid.
-+It honors the EEPROM-set values.
-+
-+III. Driver operation
-+
-+IIIa. Ring buffers
-+
-+This driver uses two statically allocated fixed-size descriptor lists
-+formed into rings by a branch from the final descriptor to the beginning of
-+the list. The ring sizes are set at compile time by RX/TX_RING_SIZE.
-+The NatSemi design uses a 'next descriptor' pointer that the driver forms
-+into a list, thus rings can be arbitrarily sized. Before changing the
-+ring sizes you should understand the flow and cache effects of the
-+full/available/empty hysteresis.
-+
-+IIIb/c. Transmit/Receive Structure
-+
-+This driver uses a zero-copy receive and transmit scheme.
-+The driver allocates full frame size skbuffs for the Rx ring buffers at
-+open() time and passes the skb->data field to the chip as receive data
-+buffers. When an incoming frame is less than RX_COPYBREAK bytes long,
-+a fresh skbuff is allocated and the frame is copied to the new skbuff.
-+When the incoming frame is larger, the skbuff is passed directly up the
-+protocol stack. Buffers consumed this way are replaced by newly allocated
-+skbuffs in a later phase of receives.
-+
-+The RX_COPYBREAK value is chosen to trade-off the memory wasted by
-+using a full-sized skbuff for small frames vs. the copying costs of larger
-+frames. New boards are typically used in generously configured machines
-+and the underfilled buffers have negligible impact compared to the benefit of
-+a single allocation size, so the default value of zero results in never
-+copying packets. When copying is done, the cost is usually mitigated by using
-+a combined copy/checksum routine. Copying also preloads the cache, which is
-+most useful with small frames.
-+
-+A subtle aspect of the operation is that unaligned buffers are not permitted
-+by the hardware. Thus the IP header at offset 14 in an ethernet frame isn't
-+longword aligned for further processing. On copies frames are put into the
-+skbuff at an offset of "+2", 16-byte aligning the IP header.
-+
-+IIId. Synchronization
-+
-+The driver runs as two independent, single-threaded flows of control. One
-+is the send-packet routine, which enforces single-threaded use by the
-+dev->tbusy flag. The other thread is the interrupt handler, which is single
-+threaded by the hardware and interrupt handling software.
-+
-+The send packet thread has partial control over the Tx ring and 'dev->tbusy'
-+flag. It sets the tbusy flag whenever it's queuing a Tx packet. If the next
-+queue slot is empty, it clears the tbusy flag when finished otherwise it sets
-+the 'lp->tx_full' flag.
-+
-+The interrupt handler has exclusive control over the Rx ring and records stats
-+from the Tx ring. After reaping the stats, it marks the Tx queue entry as
-+empty by incrementing the dirty_tx mark. Iff the 'lp->tx_full' flag is set, it
-+clears both the tx_full and tbusy flags.
-+
-+IV. Notes
-+
-+The older dp83810 chips are so uncommon that support is not relevant.
-+No NatSemi datasheet was publically available at the initial release date,
-+but the dp83815 has now been published.
-+
-+IVb. References
-+
-+http://www.scyld.com/expert/100mbps.html
-+http://www.scyld.com/expert/NWay.html
-+
-+
-+IVc. Errata
-+
-+Qustionable multicast filter implementation.
-+The EEPROM format is obviously the result of a chip bug.
-+*/
-+
-+
-+
-+static void *natsemi_probe1(struct pci_dev *pdev, void *init_dev,
-+ long ioaddr, int irq, int chip_idx, int find_cnt);
-+static int power_event(void *dev_instance, int event);
-+#ifdef USE_IO_OPS
-+#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_IO | PCI_ADDR0)
-+#else
-+#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR1)
-+#endif
-+
-+static struct pci_id_info pci_id_tbl[] = {
-+ {"Netgear FA311 (NatSemi DP83815)",
-+ { 0x0020100B, 0xffffffff, 0xf3111385, 0xffffffff, },
-+ PCI_IOTYPE, 256, 0},
-+ {"NatSemi DP83815", { 0x0020100B, 0xffffffff },
-+ PCI_IOTYPE, 256, 0},
-+ {0,}, /* 0 terminated list. */
-+};
-+
-+struct drv_id_info natsemi_drv_id = {
-+ "natsemi", PCI_HOTSWAP, PCI_CLASS_NETWORK_ETHERNET<<8, pci_id_tbl,
-+ natsemi_probe1, power_event };
-+
-+/* Offsets to the device registers.
-+ Unlike software-only systems, device drivers interact with complex hardware.
-+ It's not useful to define symbolic names for every register bit in the
-+ device. Please do not change these names without good reason.
-+*/
-+enum register_offsets {
-+ ChipCmd=0x00, ChipConfig=0x04, EECtrl=0x08, PCIBusCfg=0x0C,
-+ IntrStatus=0x10, IntrMask=0x14, IntrEnable=0x18,
-+ TxRingPtr=0x20, TxConfig=0x24,
-+ RxRingPtr=0x30, RxConfig=0x34, ClkRunCtrl=0x3C,
-+ WOLCmd=0x40, PauseCmd=0x44, RxFilterAddr=0x48, RxFilterData=0x4C,
-+ BootRomAddr=0x50, BootRomData=0x54, ChipRevReg=0x58,
-+ StatsCtrl=0x5C, StatsData=0x60,
-+ RxPktErrs=0x60, RxMissed=0x68, RxCRCErrs=0x64,
-+ NS_Xcvr_Mgmt = 0x80, NS_MII_BMCR=0x80, NS_MII_BMSR=0x84,
-+ NS_MII_Advert=0x90, NS_MIILinkPartner=0x94,
-+};
-+
-+/* Bits in ChipCmd. */
-+enum ChipCmdBits {
-+ ChipReset=0x100, SoftIntr=0x80, RxReset=0x20, TxReset=0x10,
-+ RxOff=0x08, RxOn=0x04, TxOff=0x02, TxOn=0x01,
-+};
-+
-+/* Bits in ChipConfig. */
-+enum ChipConfigBits {
-+ CfgLinkGood=0x80000000, CfgFDX=0x20000000,
-+};
-+
-+/* Bits in the interrupt status/mask registers. */
-+enum intr_status_bits {
-+ IntrRxDone=0x0001, IntrRxIntr=0x0002, IntrRxErr=0x0004, IntrRxEarly=0x0008,
-+ IntrRxIdle=0x0010, IntrRxOverrun=0x0020,
-+ IntrTxDone=0x0040, IntrTxIntr=0x0080, IntrTxErr=0x0100,
-+ IntrTxIdle=0x0200, IntrTxUnderrun=0x0400,
-+ StatsMax=0x0800, IntrDrv=0x1000, WOLPkt=0x2000, LinkChange=0x4000,
-+ RxStatusOverrun=0x10000,
-+ RxResetDone=0x1000000, TxResetDone=0x2000000,
-+ IntrPCIErr=0x00f00000,
-+ IntrNormalSummary=0x0251, IntrAbnormalSummary=0xED20,
-+};
-+
-+/* Bits in the RxMode register. */
-+enum rx_mode_bits {
-+ AcceptErr=0x20, AcceptRunt=0x10,
-+ AcceptBroadcast=0xC0000000,
-+ AcceptMulticast=0x00200000, AcceptAllMulticast=0x20000000,
-+ AcceptAllPhys=0x10000000, AcceptMyPhys=0x08000000,
-+};
-+
-+/* The Rx and Tx buffer descriptors. */
-+/* Note that using only 32 bit fields simplifies conversion to big-endian
-+ architectures. */
-+struct netdev_desc {
-+ u32 next_desc;
-+ s32 cmd_status;
-+ u32 buf_addr;
-+ u32 software_use;
-+};
-+
-+/* Bits in network_desc.status */
-+enum desc_status_bits {
-+ DescOwn=0x80000000, DescMore=0x40000000, DescIntr=0x20000000,
-+ DescNoCRC=0x10000000,
-+ DescPktOK=0x08000000, RxTooLong=0x00400000,
-+};
-+
-+#define PRIV_ALIGN 15 /* Required alignment mask */
-+struct netdev_private {
-+ /* Descriptor rings first for alignment. */
-+ struct netdev_desc rx_ring[RX_RING_SIZE];
-+ struct netdev_desc tx_ring[TX_RING_SIZE];
-+ struct net_device *next_module; /* Link for devices of this type. */
-+ void *priv_addr; /* Unaligned address for kfree */
-+ const char *product_name;
-+ /* The addresses of receive-in-place skbuffs. */
-+ struct sk_buff* rx_skbuff[RX_RING_SIZE];
-+ /* The saved address of a sent-in-place packet/buffer, for later free(). */
-+ struct sk_buff* tx_skbuff[TX_RING_SIZE];
-+ struct net_device_stats stats;
-+ struct timer_list timer; /* Media monitoring timer. */
-+ /* Frequently used values: keep some adjacent for cache effect. */
-+ int msg_level;
-+ int chip_id, drv_flags;
-+ struct pci_dev *pci_dev;
-+ long in_interrupt; /* Word-long for SMP locks. */
-+ int max_interrupt_work;
-+ int intr_enable;
-+ unsigned int restore_intr_enable:1; /* Set if temporarily masked. */
-+ unsigned int rx_q_empty:1; /* Set out-of-skbuffs. */
-+
-+ struct netdev_desc *rx_head_desc;
-+ unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */
-+ unsigned int rx_buf_sz; /* Based on MTU+slack. */
-+ int rx_copybreak;
-+
-+ unsigned int cur_tx, dirty_tx;
-+ unsigned int tx_full:1; /* The Tx queue is full. */
-+ /* These values keep track of the transceiver/media in use. */
-+ unsigned int full_duplex:1; /* Full-duplex operation requested. */
-+ unsigned int duplex_lock:1;
-+ unsigned int medialock:1; /* Do not sense media. */
-+ unsigned int default_port; /* Last dev->if_port value. */
-+ /* Rx filter. */
-+ u32 cur_rx_mode;
-+ u16 rx_filter[32];
-+ int multicast_filter_limit;
-+ /* FIFO and PCI burst thresholds. */
-+ int tx_config, rx_config;
-+ /* MII transceiver section. */
-+ u16 advertising; /* NWay media advertisement */
-+};
-+
-+static int eeprom_read(long ioaddr, int location);
-+static int mdio_read(struct net_device *dev, int phy_id, int location);
-+static void mdio_write(struct net_device *dev, int phy_id, int location,
-+ int value);
-+static int netdev_open(struct net_device *dev);
-+static void check_duplex(struct net_device *dev);
-+static void netdev_timer(unsigned long data);
-+static void tx_timeout(struct net_device *dev);
-+static int rx_ring_fill(struct net_device *dev);
-+static void init_ring(struct net_device *dev);
-+static int start_tx(struct sk_buff *skb, struct net_device *dev);
-+static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs);
-+static void netdev_error(struct net_device *dev, int intr_status);
-+static int netdev_rx(struct net_device *dev);
-+static void netdev_error(struct net_device *dev, int intr_status);
-+static void set_rx_mode(struct net_device *dev);
-+static struct net_device_stats *get_stats(struct net_device *dev);
-+static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-+static int netdev_close(struct net_device *dev);
-+
-+
-+
-+/* A list of our installed devices, for removing the driver module. */
-+static struct net_device *root_net_dev = NULL;
-+
-+#ifndef MODULE
-+int natsemi_probe(struct net_device *dev)
-+{
-+ if (pci_drv_register(&natsemi_drv_id, dev) < 0)
-+ return -ENODEV;
-+ printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2);
-+ return 0;
-+}
-+#endif
-+
-+static void *natsemi_probe1(struct pci_dev *pdev, void *init_dev,
-+ long ioaddr, int irq, int chip_idx, int card_idx)
-+{
-+ struct net_device *dev;
-+ struct netdev_private *np;
-+ void *priv_mem;
-+ int i, option = card_idx < MAX_UNITS ? options[card_idx] : 0;
-+ int prev_eedata;
-+
-+ dev = init_etherdev(init_dev, 0);
-+ if (!dev)
-+ return NULL;
-+
-+ /* Perhaps NETIF_MSG_PROBE */
-+ printk(KERN_INFO "%s: %s at 0x%lx, ",
-+ dev->name, pci_id_tbl[chip_idx].name, ioaddr);
-+
-+ /* Work around the dropped serial bit. */
-+ prev_eedata = eeprom_read(ioaddr, 6);
-+ for (i = 0; i < 3; i++) {
-+ int eedata = eeprom_read(ioaddr, i + 7);
-+ dev->dev_addr[i*2] = (eedata << 1) + (prev_eedata >> 15);
-+ dev->dev_addr[i*2+1] = eedata >> 7;
-+ prev_eedata = eedata;
-+ }
-+ for (i = 0; i < 5; i++)
-+ printk("%2.2x:", dev->dev_addr[i]);
-+ printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);
-+
-+ /* Reset the chip to erase previous misconfiguration. */
-+ writel(ChipReset, ioaddr + ChipCmd);
-+
-+ /* Make certain elements e.g. descriptor lists are aligned. */
-+ priv_mem = kmalloc(sizeof(*np) + PRIV_ALIGN, GFP_KERNEL);
-+ /* Check for the very unlikely case of no memory. */
-+ if (priv_mem == NULL)
-+ return NULL;
-+
-+ dev->base_addr = ioaddr;
-+ dev->irq = irq;
-+
-+ dev->priv = np = (void *)(((long)priv_mem + PRIV_ALIGN) & ~PRIV_ALIGN);
-+ memset(np, 0, sizeof(*np));
-+ np->priv_addr = priv_mem;
-+
-+ np->next_module = root_net_dev;
-+ root_net_dev = dev;
-+
-+ np->pci_dev = pdev;
-+ np->chip_id = chip_idx;
-+ np->drv_flags = pci_id_tbl[chip_idx].drv_flags;
-+ np->msg_level = (1 << debug) - 1;
-+ np->rx_copybreak = rx_copybreak;
-+ np->max_interrupt_work = max_interrupt_work;
-+ np->multicast_filter_limit = multicast_filter_limit;
-+
-+ if (dev->mem_start)
-+ option = dev->mem_start;
-+
-+ /* 0x10/0x20/0x100/0x200 set forced speed&duplex modes. */
-+ if (option > 0) {
-+ if (option & 0x220)
-+ np->full_duplex = 1;
-+ np->default_port = option & 0x3ff;
-+ if (np->default_port & 0x330) {
-+ np->medialock = 1;
-+ if (np->msg_level & NETIF_MSG_PROBE)
-+ printk(KERN_INFO " Forcing %dMbs %s-duplex operation.\n",
-+ (option & 0x300 ? 100 : 10),
-+ (np->full_duplex ? "full" : "half"));
-+ writew(((option & 0x300) ? 0x2000 : 0) | /* 100mbps? */
-+ (np->full_duplex ? 0x0100 : 0), /* Full duplex? */
-+ ioaddr + NS_MII_BMCR);
-+ }
-+ }
-+ if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0)
-+ np->full_duplex = 1;
-+
-+ if (np->full_duplex) {
-+ if (np->msg_level & NETIF_MSG_PROBE)
-+ printk(KERN_INFO "%s: Set to forced full duplex, autonegotiation"
-+ " disabled.\n", dev->name);
-+ np->duplex_lock = 1;
-+ }
-+
-+ /* The chip-specific entries in the device structure. */
-+ dev->open = &netdev_open;
-+ dev->hard_start_xmit = &start_tx;
-+ dev->stop = &netdev_close;
-+ dev->get_stats = &get_stats;
-+ dev->set_multicast_list = &set_rx_mode;
-+ dev->do_ioctl = &mii_ioctl;
-+
-+ /* Override the PME enable from the EEPROM. */
-+ writel(0x8000, ioaddr + ClkRunCtrl);
-+
-+ if ((readl(ioaddr + ChipConfig) & 0xe000) != 0xe000) {
-+ u32 chip_config = readl(ioaddr + ChipConfig);
-+ if (np->msg_level & NETIF_MSG_PROBE)
-+ printk(KERN_INFO "%s: Transceiver default autonegotiation %s "
-+ "10%s %s duplex.\n",
-+ dev->name, chip_config & 0x2000 ? "enabled, advertise"
-+ : "disabled, force", chip_config & 0x4000 ? "0" : "",
-+ chip_config & 0x8000 ? "full" : "half");
-+ }
-+ if (np->msg_level & NETIF_MSG_PROBE)
-+ printk(KERN_INFO "%s: Transceiver status 0x%4.4x partner %4.4x.\n",
-+ dev->name, (int)readl(ioaddr + NS_MII_BMSR),
-+ (int)readl(ioaddr + NS_MIILinkPartner));
-+
-+ return dev;
-+}
-+
-+
-+/* Read the EEPROM and MII Management Data I/O (MDIO) interfaces.
-+ The EEPROM code is for the common 93c06/46 EEPROMs with 6 bit addresses.
-+ Update to the code in other drivers for 8/10 bit addresses.
-+*/
-+
-+/* Delay between EEPROM clock transitions.
-+ This "delay" forces out buffered PCI writes, which is sufficient to meet
-+ the timing requirements of most EEPROMs.
-+*/
-+#define eeprom_delay(ee_addr) readl(ee_addr)
-+
-+enum EEPROM_Ctrl_Bits {
-+ EE_ShiftClk=0x04, EE_DataIn=0x01, EE_ChipSelect=0x08, EE_DataOut=0x02,
-+};
-+#define EE_Write0 (EE_ChipSelect)
-+#define EE_Write1 (EE_ChipSelect | EE_DataIn)
-+
-+/* The EEPROM commands include the preamble. */
-+enum EEPROM_Cmds {
-+ EE_WriteCmd=(5 << 6), EE_ReadCmd=(6 << 6), EE_EraseCmd=(7 << 6),
-+};
-+
-+static int eeprom_read(long addr, int location)
-+{
-+ int i;
-+ int retval = 0;
-+ long ee_addr = addr + EECtrl;
-+ int read_cmd = location | EE_ReadCmd;
-+ writel(EE_Write0, ee_addr);
-+
-+ /* Shift the read command bits out. */
-+ for (i = 10; i >= 0; i--) {
-+ short dataval = (read_cmd & (1 << i)) ? EE_Write1 : EE_Write0;
-+ writel(dataval, ee_addr);
-+ eeprom_delay(ee_addr);
-+ writel(dataval | EE_ShiftClk, ee_addr);
-+ eeprom_delay(ee_addr);
-+ }
-+ writel(EE_ChipSelect, ee_addr);
-+ eeprom_delay(ee_addr);
-+
-+ for (i = 0; i < 16; i++) {
-+ writel(EE_ChipSelect | EE_ShiftClk, ee_addr);
-+ eeprom_delay(ee_addr);
-+ retval |= (readl(ee_addr) & EE_DataOut) ? 1 << i : 0;
-+ writel(EE_ChipSelect, ee_addr);
-+ eeprom_delay(ee_addr);
-+ }
-+
-+ /* Terminate the EEPROM access. */
-+ writel(EE_Write0, ee_addr);
-+ writel(0, ee_addr);
-+ return retval;
-+}
-+
-+/* MII transceiver control section.
-+ The 83815 series has an internal, directly accessable transceiver.
-+ We present the management registers as if they were MII connected. */
-+
-+static int mdio_read(struct net_device *dev, int phy_id, int location)
-+{
-+ if (phy_id == 1 && location < 32)
-+ return readw(dev->base_addr + NS_Xcvr_Mgmt + (location<<2));
-+ else
-+ return 0xffff;
-+}
-+
-+static void mdio_write(struct net_device *dev, int phy_id, int location,
-+ int value)
-+{
-+ if (phy_id == 1 && location < 32)
-+ writew(value, dev->base_addr + NS_Xcvr_Mgmt + (location<<2));
-+}
-+
-+
-+static int netdev_open(struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+ int i;
-+
-+ /* We do not need to reset the '815 chip. */
-+
-+ MOD_INC_USE_COUNT;
-+
-+ if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev)) {
-+ MOD_DEC_USE_COUNT;
-+ return -EAGAIN;
-+ }
-+
-+ if (np->msg_level & NETIF_MSG_IFUP)
-+ printk(KERN_DEBUG "%s: netdev_open() irq %d.\n",
-+ dev->name, dev->irq);
-+
-+ init_ring(dev);
-+
-+ writel(virt_to_bus(np->rx_ring), ioaddr + RxRingPtr);
-+ writel(virt_to_bus(np->tx_ring), ioaddr + TxRingPtr);
-+
-+ for (i = 0; i < 6; i += 2) {
-+ writel(i, ioaddr + RxFilterAddr);
-+ writel(dev->dev_addr[i] + (dev->dev_addr[i+1] << 8),
-+ ioaddr + RxFilterData);
-+ }
-+
-+ /* Initialize other registers. */
-+ /* See the datasheet for this correction. */
-+ if (readl(ioaddr + ChipRevReg) == 0x0203) {
-+ writew(0x0001, ioaddr + 0xCC);
-+ writew(0x18C9, ioaddr + 0xE4);
-+ writew(0x0000, ioaddr + 0xFC);
-+ writew(0x5040, ioaddr + 0xF4);
-+ writew(0x008C, ioaddr + 0xF8);
-+ }
-+
-+ /* Configure the PCI bus bursts and FIFO thresholds. */
-+ /* Configure for standard, in-spec Ethernet. */
-+
-+ if (readl(ioaddr + ChipConfig) & CfgFDX) { /* Full duplex */
-+ np->tx_config = 0xD0801002;
-+ np->rx_config = 0x10000020;
-+ } else {
-+ np->tx_config = 0x10801002;
-+ np->rx_config = 0x0020;
-+ }
-+ if (dev->mtu > 1500)
-+ np->rx_config |= 0x08000000;
-+ writel(np->tx_config, ioaddr + TxConfig);
-+ writel(np->rx_config, ioaddr + RxConfig);
-+
-+ if (dev->if_port == 0)
-+ dev->if_port = np->default_port;
-+
-+ np->in_interrupt = 0;
-+
-+ check_duplex(dev);
-+ set_rx_mode(dev);
-+ netif_start_tx_queue(dev);
-+
-+ /* Enable interrupts by setting the interrupt mask. */
-+ np->intr_enable = IntrNormalSummary | IntrAbnormalSummary | 0x1f;
-+ writel(np->intr_enable, ioaddr + IntrMask);
-+ writel(1, ioaddr + IntrEnable);
-+
-+ writel(RxOn | TxOn, ioaddr + ChipCmd);
-+ writel(4, ioaddr + StatsCtrl); /* Clear Stats */
-+
-+ if (np->msg_level & NETIF_MSG_IFUP)
-+ printk(KERN_DEBUG "%s: Done netdev_open(), status: %x.\n",
-+ dev->name, (int)readl(ioaddr + ChipCmd));
-+
-+ /* Set the timer to check for link beat. */
-+ init_timer(&np->timer);
-+ np->timer.expires = jiffies + 3*HZ;
-+ np->timer.data = (unsigned long)dev;
-+ np->timer.function = &netdev_timer; /* timer handler */
-+ add_timer(&np->timer);
-+
-+ return 0;
-+}
-+
-+static void check_duplex(struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+ int duplex;
-+
-+ if (np->duplex_lock)
-+ return;
-+ duplex = readl(ioaddr + ChipConfig) & 0x20000000 ? 1 : 0;
-+ if (np->full_duplex != duplex) {
-+ np->full_duplex = duplex;
-+ if (np->msg_level & NETIF_MSG_LINK)
-+ printk(KERN_INFO "%s: Setting %s-duplex based on negotiated link"
-+ " capability.\n", dev->name,
-+ duplex ? "full" : "half");
-+ if (duplex) {
-+ np->rx_config |= 0x10000000;
-+ np->tx_config |= 0xC0000000;
-+ } else {
-+ np->rx_config &= ~0x10000000;
-+ np->tx_config &= ~0xC0000000;
-+ }
-+ writel(np->tx_config, ioaddr + TxConfig);
-+ writel(np->rx_config, ioaddr + RxConfig);
-+ }
-+}
-+
-+static void netdev_timer(unsigned long data)
-+{
-+ struct net_device *dev = (struct net_device *)data;
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+ int next_tick = 10*HZ;
-+
-+ if (np->msg_level & NETIF_MSG_TIMER)
-+ printk(KERN_DEBUG "%s: Driver monitor timer tick, status %8.8x.\n",
-+ dev->name, (int)readl(ioaddr + IntrStatus));
-+ if (np->rx_q_empty) {
-+ /* Trigger an interrupt to refill. */
-+ writel(SoftIntr, ioaddr + ChipCmd);
-+ }
-+ /* This will either have a small false-trigger window or will not catch
-+ tbusy incorrectly set when the queue is empty. */
-+ if (netif_queue_paused(dev) &&
-+ np->cur_tx - np->dirty_tx > 1 &&
-+ (jiffies - dev->trans_start) > TX_TIMEOUT) {
-+ tx_timeout(dev);
-+ }
-+ check_duplex(dev);
-+ np->timer.expires = jiffies + next_tick;
-+ add_timer(&np->timer);
-+}
-+
-+static void tx_timeout(struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+
-+ printk(KERN_WARNING "%s: Transmit timed out, status %8.8x,"
-+ " resetting...\n", dev->name, (int)readl(ioaddr + TxRingPtr));
-+
-+ if (np->msg_level & NETIF_MSG_TX_ERR) {
-+ int i;
-+ printk(KERN_DEBUG " Rx ring %p: ", np->rx_ring);
-+ for (i = 0; i < RX_RING_SIZE; i++)
-+ printk(" %8.8x", (unsigned int)np->rx_ring[i].cmd_status);
-+ printk("\n"KERN_DEBUG" Tx ring %p: ", np->tx_ring);
-+ for (i = 0; i < TX_RING_SIZE; i++)
-+ printk(" %4.4x", np->tx_ring[i].cmd_status);
-+ printk("\n");
-+ }
-+
-+ /* Reinitialize the hardware here. */
-+ /* Stop and restart the chip's Tx processes . */
-+
-+ /* Trigger an immediate transmit demand. */
-+
-+ dev->trans_start = jiffies;
-+ np->stats.tx_errors++;
-+ return;
-+}
-+
-+/* Refill the Rx ring buffers, returning non-zero if not full. */
-+static int rx_ring_fill(struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ unsigned int entry;
-+
-+ for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) {
-+ entry = np->dirty_rx % RX_RING_SIZE;
-+ if (np->rx_skbuff[entry] == NULL) {
-+ struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz);
-+ np->rx_skbuff[entry] = skb;
-+ if (skb == NULL)
-+ return 1; /* Better luck next time. */
-+ skb->dev = dev; /* Mark as being used by this device. */
-+ np->rx_ring[entry].buf_addr = virt_to_le32desc(skb->tail);
-+ }
-+ np->rx_ring[entry].cmd_status = cpu_to_le32(DescIntr | np->rx_buf_sz);
-+ }
-+ return 0;
-+}
-+
-+/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
-+static void init_ring(struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ int i;
-+
-+ np->tx_full = 0;
-+ np->cur_rx = np->cur_tx = 0;
-+ np->dirty_rx = np->dirty_tx = 0;
-+
-+ /* MAX(PKT_BUF_SZ, dev->mtu + 8); */
-+ /* I know you _want_ to change this without understanding it. Don't. */
-+ np->rx_buf_sz = (dev->mtu <= 1532 ? PKT_BUF_SZ : dev->mtu + 8);
-+ np->rx_head_desc = &np->rx_ring[0];
-+
-+ /* Initialize all Rx descriptors. */
-+ for (i = 0; i < RX_RING_SIZE; i++) {
-+ np->rx_ring[i].next_desc = virt_to_le32desc(&np->rx_ring[i+1]);
-+ np->rx_ring[i].cmd_status = cpu_to_le32(DescOwn);
-+ np->rx_skbuff[i] = 0;
-+ }
-+ /* Mark the last entry as wrapping the ring. */
-+ np->rx_ring[i-1].next_desc = virt_to_le32desc(&np->rx_ring[0]);
-+
-+ for (i = 0; i < TX_RING_SIZE; i++) {
-+ np->tx_skbuff[i] = 0;
-+ np->tx_ring[i].next_desc = virt_to_le32desc(&np->tx_ring[i+1]);
-+ np->tx_ring[i].cmd_status = 0;
-+ }
-+ np->tx_ring[i-1].next_desc = virt_to_le32desc(&np->tx_ring[0]);
-+
-+ /* Fill in the Rx buffers.
-+ Allocation failure just leaves a "negative" np->dirty_rx. */
-+ np->dirty_rx = (unsigned int)(0 - RX_RING_SIZE);
-+ rx_ring_fill(dev);
-+
-+ return;
-+}
-+
-+static int start_tx(struct sk_buff *skb, struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ unsigned int entry;
-+
-+ /* Block a timer-based transmit from overlapping. This happens when
-+ packets are presumed lost, and we use this check the Tx status. */
-+ if (netif_pause_tx_queue(dev) != 0) {
-+ /* This watchdog code is redundant with the media monitor timer. */
-+ if (jiffies - dev->trans_start > TX_TIMEOUT)
-+ tx_timeout(dev);
-+ return 1;
-+ }
-+
-+ /* Note: Ordering is important here, set the field with the
-+ "ownership" bit last, and only then increment cur_tx.
-+ No spinlock is needed for either Tx or Rx.
-+ */
-+
-+ /* Calculate the next Tx descriptor entry. */
-+ entry = np->cur_tx % TX_RING_SIZE;
-+
-+ np->tx_skbuff[entry] = skb;
-+
-+ np->tx_ring[entry].buf_addr = virt_to_le32desc(skb->data);
-+ np->tx_ring[entry].cmd_status = cpu_to_le32(DescOwn|DescIntr | skb->len);
-+ np->cur_tx++;
-+
-+ /* For some architectures explicitly flushing np->tx_ring,sizeof(tx_ring)
-+ and skb->data,skb->len improves performance. */
-+
-+ if (np->cur_tx - np->dirty_tx >= TX_QUEUE_LEN - 1) {
-+ np->tx_full = 1;
-+ /* Check for a just-cleared queue. */
-+ if (np->cur_tx - (volatile unsigned int)np->dirty_tx
-+ < TX_QUEUE_LEN - 4) {
-+ np->tx_full = 0;
-+ netif_unpause_tx_queue(dev);
-+ } else
-+ netif_stop_tx_queue(dev);
-+ } else
-+ netif_unpause_tx_queue(dev); /* Typical path */
-+ /* Wake the potentially-idle transmit channel. */
-+ writel(TxOn, dev->base_addr + ChipCmd);
-+
-+ dev->trans_start = jiffies;
-+
-+ if (np->msg_level & NETIF_MSG_TX_QUEUED) {
-+ printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n",
-+ dev->name, np->cur_tx, entry);
-+ }
-+ return 0;
-+}
-+
-+/* The interrupt handler does all of the Rx thread work and cleans up
-+ after the Tx thread. */
-+static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
-+{
-+ struct net_device *dev = (struct net_device *)dev_instance;
-+ struct netdev_private *np;
-+ long ioaddr;
-+ int boguscnt;
-+
-+#ifndef final_version /* Can never occur. */
-+ if (dev == NULL) {
-+ printk (KERN_ERR "Netdev interrupt handler(): IRQ %d for unknown "
-+ "device.\n", irq);
-+ return;
-+ }
-+#endif
-+
-+ ioaddr = dev->base_addr;
-+ np = (struct netdev_private *)dev->priv;
-+ boguscnt = np->max_interrupt_work;
-+
-+ do {
-+ u32 intr_status = readl(ioaddr + IntrStatus);
-+
-+ if (intr_status == 0 || intr_status == 0xffffffff)
-+ break;
-+
-+ /* Acknowledge all of the current interrupt sources ASAP.
-+ Nominally the read above accomplishes this, but... */
-+ writel(intr_status & 0x001ffff, ioaddr + IntrStatus);
-+
-+ if (np->msg_level & NETIF_MSG_INTR)
-+ printk(KERN_DEBUG "%s: Interrupt, status %8.8x.\n",
-+ dev->name, intr_status);
-+
-+ if (intr_status & (IntrRxDone | IntrRxIntr)) {
-+ netdev_rx(dev);
-+ np->rx_q_empty = rx_ring_fill(dev);
-+ }
-+
-+ if (intr_status & (IntrRxIdle | IntrDrv)) {
-+ unsigned int old_dirty_rx = np->dirty_rx;
-+ if (rx_ring_fill(dev) == 0)
-+ np->rx_q_empty = 0;
-+ /* Restart Rx engine iff we did add a buffer. */
-+ if (np->dirty_rx != old_dirty_rx)
-+ writel(RxOn, dev->base_addr + ChipCmd);
-+ }
-+
-+ for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) {
-+ int entry = np->dirty_tx % TX_RING_SIZE;
-+ int tx_status = le32_to_cpu(np->tx_ring[entry].cmd_status);
-+ if (tx_status & DescOwn)
-+ break;
-+ if (np->msg_level & NETIF_MSG_TX_DONE)
-+ printk(KERN_DEBUG "%s: Transmit done, Tx status %8.8x.\n",
-+ dev->name, tx_status);
-+ if (tx_status & 0x08000000) {
-+ np->stats.tx_packets++;
-+#if LINUX_VERSION_CODE > 0x20127
-+ np->stats.tx_bytes += np->tx_skbuff[entry]->len;
-+#endif
-+ } else { /* Various Tx errors */
-+ if (np->msg_level & NETIF_MSG_TX_ERR)
-+ printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",
-+ dev->name, tx_status);
-+ if (tx_status & 0x04010000) np->stats.tx_aborted_errors++;
-+ if (tx_status & 0x02000000) np->stats.tx_fifo_errors++;
-+ if (tx_status & 0x01000000) np->stats.tx_carrier_errors++;
-+ if (tx_status & 0x00200000) np->stats.tx_window_errors++;
-+ np->stats.tx_errors++;
-+ }
-+ /* Free the original skb. */
-+ dev_free_skb_irq(np->tx_skbuff[entry]);
-+ np->tx_skbuff[entry] = 0;
-+ }
-+ /* Note the 4 slot hysteresis to mark the queue non-full. */
-+ if (np->tx_full
-+ && np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 4) {
-+ /* The ring is no longer full, allow new TX entries. */
-+ np->tx_full = 0;
-+ netif_resume_tx_queue(dev);
-+ }
-+
-+ /* Abnormal error summary/uncommon events handlers. */
-+ if (intr_status & IntrAbnormalSummary)
-+ netdev_error(dev, intr_status);
-+
-+ if (--boguscnt < 0) {
-+ printk(KERN_WARNING "%s: Too much work at interrupt, "
-+ "status=0x%4.4x.\n",
-+ dev->name, intr_status);
-+ np->restore_intr_enable = 1;
-+ break;
-+ }
-+ } while (1);
-+
-+ if (np->msg_level & NETIF_MSG_INTR)
-+ printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
-+ dev->name, (int)readl(ioaddr + IntrStatus));
-+
-+ return;
-+}
-+
-+/* This routine is logically part of the interrupt handler, but separated
-+ for clarity and better register allocation. */
-+static int netdev_rx(struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ int entry = np->cur_rx % RX_RING_SIZE;
-+ int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx;
-+ s32 desc_status = le32_to_cpu(np->rx_head_desc->cmd_status);
-+
-+ /* If the driver owns the next entry it's a new packet. Send it up. */
-+ while (desc_status < 0) { /* e.g. & DescOwn */
-+ if (np->msg_level & NETIF_MSG_RX_STATUS)
-+ printk(KERN_DEBUG " In netdev_rx() entry %d status was %8.8x.\n",
-+ entry, desc_status);
-+ if (--boguscnt < 0)
-+ break;
-+ if ((desc_status & (DescMore|DescPktOK|RxTooLong)) != DescPktOK) {
-+ if (desc_status & DescMore) {
-+ printk(KERN_WARNING "%s: Oversized(?) Ethernet frame spanned "
-+ "multiple buffers, entry %#x status %x.\n",
-+ dev->name, np->cur_rx, desc_status);
-+ np->stats.rx_length_errors++;
-+ } else {
-+ /* There was a error. */
-+ if (np->msg_level & NETIF_MSG_RX_ERR)
-+ printk(KERN_DEBUG " netdev_rx() Rx error was %8.8x.\n",
-+ desc_status);
-+ np->stats.rx_errors++;
-+ if (desc_status & 0x06000000) np->stats.rx_over_errors++;
-+ if (desc_status & 0x00600000) np->stats.rx_length_errors++;
-+ if (desc_status & 0x00140000) np->stats.rx_frame_errors++;
-+ if (desc_status & 0x00080000) np->stats.rx_crc_errors++;
-+ }
-+ } else {
-+ struct sk_buff *skb;
-+ int pkt_len = (desc_status & 0x0fff) - 4; /* Omit CRC size. */
-+ /* Check if the packet is long enough to accept without copying
-+ to a minimally-sized skbuff. */
-+ if (pkt_len < np->rx_copybreak
-+ && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
-+ skb->dev = dev;
-+ skb_reserve(skb, 2); /* 16 byte align the IP header */
-+#if defined(HAS_IP_COPYSUM) || (LINUX_VERSION_CODE >= 0x20100)
-+ eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0);
-+ skb_put(skb, pkt_len);
-+#else
-+ memcpy(skb_put(skb, pkt_len), np->rx_skbuff[entry]->tail,
-+ pkt_len);
-+#endif
-+ } else {
-+ skb_put(skb = np->rx_skbuff[entry], pkt_len);
-+ np->rx_skbuff[entry] = NULL;
-+ }
-+ skb->protocol = eth_type_trans(skb, dev);
-+ /* W/ hardware checksum: skb->ip_summed = CHECKSUM_UNNECESSARY; */
-+ netif_rx(skb);
-+ dev->last_rx = jiffies;
-+ np->stats.rx_packets++;
-+#if LINUX_VERSION_CODE > 0x20127
-+ np->stats.rx_bytes += pkt_len;
-+#endif
-+ }
-+ entry = (++np->cur_rx) % RX_RING_SIZE;
-+ np->rx_head_desc = &np->rx_ring[entry];
-+ desc_status = le32_to_cpu(np->rx_head_desc->cmd_status);
-+ }
-+
-+ /* Refill is now done in the main interrupt loop. */
-+ return 0;
-+}
-+
-+static void netdev_error(struct net_device *dev, int intr_status)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+
-+ if (intr_status & LinkChange) {
-+ int chip_config = readl(ioaddr + ChipConfig);
-+ if (np->msg_level & NETIF_MSG_LINK)
-+ printk(KERN_NOTICE "%s: Link changed: Autonegotiation advertising"
-+ " %4.4x partner %4.4x.\n", dev->name,
-+ (int)readw(ioaddr + NS_MII_Advert),
-+ (int)readw(ioaddr + NS_MIILinkPartner));
-+ if (chip_config & CfgLinkGood)
-+ netif_link_up(dev);
-+ else
-+ netif_link_down(dev);
-+ check_duplex(dev);
-+ }
-+ if (intr_status & StatsMax) {
-+ get_stats(dev);
-+ }
-+ if (intr_status & IntrTxUnderrun) {
-+ /* Increase the Tx threshold, 32 byte units. */
-+ if ((np->tx_config & 0x3f) < 62)
-+ np->tx_config += 2; /* +64 bytes */
-+ writel(np->tx_config, ioaddr + TxConfig);
-+ }
-+ if (intr_status & WOLPkt) {
-+ int wol_status = readl(ioaddr + WOLCmd);
-+ printk(KERN_NOTICE "%s: Link wake-up event %8.8x",
-+ dev->name, wol_status);
-+ }
-+ if (intr_status & (RxStatusOverrun | IntrRxOverrun)) {
-+ if (np->msg_level & NETIF_MSG_DRV)
-+ printk(KERN_ERR "%s: Rx overflow! ns815 %8.8x.\n",
-+ dev->name, intr_status);
-+ np->stats.rx_fifo_errors++;
-+ }
-+ if (intr_status & ~(LinkChange|StatsMax|RxResetDone|TxResetDone|
-+ RxStatusOverrun|0xA7ff)) {
-+ if (np->msg_level & NETIF_MSG_DRV)
-+ printk(KERN_ERR "%s: Something Wicked happened! natsemi %8.8x.\n",
-+ dev->name, intr_status);
-+ }
-+ /* Hmmmmm, it's not clear how to recover from PCI faults. */
-+ if (intr_status & IntrPCIErr) {
-+ np->stats.tx_fifo_errors++;
-+ np->stats.rx_fifo_errors++;
-+ }
-+}
-+
-+static struct net_device_stats *get_stats(struct net_device *dev)
-+{
-+ long ioaddr = dev->base_addr;
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ int crc_errs = readl(ioaddr + RxCRCErrs);
-+
-+ if (crc_errs != 0xffffffff) {
-+ /* We need not lock this segment of code for SMP.
-+ There is no atomic-add vulnerability for most CPUs,
-+ and statistics are non-critical. */
-+ /* The chip only need report frame silently dropped. */
-+ np->stats.rx_crc_errors += crc_errs;
-+ np->stats.rx_missed_errors += readl(ioaddr + RxMissed);
-+ }
-+
-+ return &np->stats;
-+}
-+
-+/* The big-endian AUTODIN II ethernet CRC calculations.
-+ See ns820.c for how to fill the table on new chips.
-+ */
-+static unsigned const ethernet_polynomial = 0x04c11db7U;
-+static inline u32 ether_crc(int length, unsigned char *data)
-+{
-+ int crc = -1;
-+
-+ while(--length >= 0) {
-+ unsigned char current_octet = *data++;
-+ int bit;
-+ for (bit = 0; bit < 8; bit++, current_octet >>= 1)
-+ crc = (crc << 1) ^
-+ ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
-+ }
-+ return crc;
-+}
-+
-+static void set_rx_mode(struct net_device *dev)
-+{
-+ long ioaddr = dev->base_addr;
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ u8 mc_filter[64]; /* Multicast hash filter */
-+ u32 rx_mode;
-+
-+ if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
-+ /* Unconditionally log net taps. */
-+ printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);
-+ rx_mode = AcceptBroadcast | AcceptAllMulticast | AcceptAllPhys
-+ | AcceptMyPhys;
-+ } else if ((dev->mc_count > np->multicast_filter_limit)
-+ || (dev->flags & IFF_ALLMULTI)) {
-+ rx_mode = AcceptBroadcast | AcceptAllMulticast | AcceptMyPhys;
-+ } else {
-+ struct dev_mc_list *mclist;
-+ int i;
-+ memset(mc_filter, 0, sizeof(mc_filter));
-+ for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
-+ i++, mclist = mclist->next) {
-+ int filterbit = ether_crc(ETH_ALEN, mclist->dmi_addr);
-+ set_bit(filterbit & 0x1ff, mc_filter);
-+ if (np->msg_level & NETIF_MSG_RXFILTER)
-+ printk(KERN_INFO "%s: Added filter for %2.2x:%2.2x:%2.2x:"
-+ "%2.2x:%2.2x:%2.2x crc %8.8x bit %d.\n", dev->name,
-+ mclist->dmi_addr[0], mclist->dmi_addr[1],
-+ mclist->dmi_addr[2], mclist->dmi_addr[3],
-+ mclist->dmi_addr[4], mclist->dmi_addr[5],
-+ filterbit, filterbit & 0x1ff);
-+ }
-+ rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
-+ for (i = 0; i < 64; i += 2) {
-+ u16 filterword = (mc_filter[i+1]<<8) + mc_filter[i];
-+ if (filterword != np->rx_filter[i>>2]) {
-+ writel(0x200 + i, ioaddr + RxFilterAddr);
-+ writel(filterword, ioaddr + RxFilterData);
-+ np->rx_filter[i>>2] = filterword;
-+ }
-+ }
-+ }
-+ writel(rx_mode, ioaddr + RxFilterAddr);
-+ np->cur_rx_mode = rx_mode;
-+}
-+
-+static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ u16 *data = (u16 *)&rq->ifr_data;
-+ u32 *data32 = (void *)&rq->ifr_data;
-+
-+ switch(cmd) {
-+ case 0x8947: case 0x89F0:
-+ /* SIOCGMIIPHY: Get the address of the PHY in use. */
-+ data[0] = 1;
-+ /* Fall Through */
-+ case 0x8948: case 0x89F1:
-+ /* SIOCGMIIREG: Read the specified MII register. */
-+ data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f);
-+ return 0;
-+ case 0x8949: case 0x89F2:
-+ /* SIOCSMIIREG: Write the specified MII register */
-+ if (!capable(CAP_NET_ADMIN))
-+ return -EPERM;
-+ if (data[0] == 1) {
-+ u16 miireg = data[1] & 0x1f;
-+ u16 value = data[2];
-+ mdio_write(dev, 1, miireg, value);
-+ switch (miireg) {
-+ case 0:
-+ /* Check for autonegotiation on or reset. */
-+ np->duplex_lock = (value & 0x9000) ? 0 : 1;
-+ if (np->duplex_lock)
-+ np->full_duplex = (value & 0x0100) ? 1 : 0;
-+ break;
-+ case 4: np->advertising = value; break;
-+ }
-+ }
-+ return 0;
-+ case SIOCGPARAMS:
-+ data32[0] = np->msg_level;
-+ data32[1] = np->multicast_filter_limit;
-+ data32[2] = np->max_interrupt_work;
-+ data32[3] = np->rx_copybreak;
-+ return 0;
-+ case SIOCSPARAMS:
-+ if (!capable(CAP_NET_ADMIN))
-+ return -EPERM;
-+ np->msg_level = data32[0];
-+ np->multicast_filter_limit = data32[1];
-+ np->max_interrupt_work = data32[2];
-+ np->rx_copybreak = data32[3];
-+ return 0;
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+}
-+
-+static int netdev_close(struct net_device *dev)
-+{
-+ long ioaddr = dev->base_addr;
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ int i;
-+
-+ netif_stop_tx_queue(dev);
-+
-+ if (np->msg_level & NETIF_MSG_IFDOWN) {
-+ printk(KERN_DEBUG "%s: Shutting down ethercard, status was %4.4x "
-+ "Int %2.2x.\n",
-+ dev->name, (int)readl(ioaddr + ChipCmd),
-+ (int)readl(ioaddr + IntrStatus));
-+ printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d, Rx %d / %d.\n",
-+ dev->name, np->cur_tx, np->dirty_tx, np->cur_rx, np->dirty_rx);
-+ }
-+
-+ /* We don't want the timer to re-start anything. */
-+ del_timer(&np->timer);
-+
-+ /* Disable interrupts using the mask. */
-+ writel(0, ioaddr + IntrMask);
-+ writel(0, ioaddr + IntrEnable);
-+ writel(2, ioaddr + StatsCtrl); /* Freeze Stats */
-+
-+ /* Stop the chip's Tx and Rx processes. */
-+ writel(RxOff | TxOff, ioaddr + ChipCmd);
-+
-+ get_stats(dev);
-+
-+#ifdef __i386__
-+ if (np->msg_level & NETIF_MSG_IFDOWN) {
-+ printk("\n"KERN_DEBUG" Tx ring at %8.8x:\n",
-+ (int)virt_to_bus(np->tx_ring));
-+ for (i = 0; i < TX_RING_SIZE; i++)
-+ printk(" #%d desc. %8.8x %8.8x.\n",
-+ i, np->tx_ring[i].cmd_status, (u32)np->tx_ring[i].buf_addr);
-+ printk("\n"KERN_DEBUG " Rx ring %8.8x:\n",
-+ (int)virt_to_bus(np->rx_ring));
-+ for (i = 0; i < RX_RING_SIZE; i++) {
-+ printk(KERN_DEBUG " #%d desc. %8.8x %8.8x\n",
-+ i, np->rx_ring[i].cmd_status, (u32)np->rx_ring[i].buf_addr);
-+ }
-+ }
-+#endif /* __i386__ debugging only */
-+
-+ free_irq(dev->irq, dev);
-+
-+ /* Free all the skbuffs in the Rx queue. */
-+ for (i = 0; i < RX_RING_SIZE; i++) {
-+ np->rx_ring[i].cmd_status = 0;
-+ np->rx_ring[i].buf_addr = 0xBADF00D0; /* An invalid address. */
-+ if (np->rx_skbuff[i]) {
-+#if LINUX_VERSION_CODE < 0x20100
-+ np->rx_skbuff[i]->free = 1;
-+#endif
-+ dev_free_skb(np->rx_skbuff[i]);
-+ }
-+ np->rx_skbuff[i] = 0;
-+ }
-+ for (i = 0; i < TX_RING_SIZE; i++) {
-+ if (np->tx_skbuff[i])
-+ dev_free_skb(np->tx_skbuff[i]);
-+ np->tx_skbuff[i] = 0;
-+ }
-+
-+#if 0
-+ writel(0x0200, ioaddr + ChipConfig); /* Power down Xcvr. */
-+#endif
-+
-+ MOD_DEC_USE_COUNT;
-+
-+ return 0;
-+}
-+
-+static int power_event(void *dev_instance, int event)
-+{
-+ struct net_device *dev = dev_instance;
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+
-+ if (np->msg_level & NETIF_MSG_LINK)
-+ printk(KERN_DEBUG "%s: Handling power event %d.\n", dev->name, event);
-+ switch(event) {
-+ case DRV_ATTACH:
-+ MOD_INC_USE_COUNT;
-+ break;
-+ case DRV_SUSPEND:
-+ /* Disable interrupts, freeze stats, stop Tx and Rx. */
-+ writel(0, ioaddr + IntrEnable);
-+ writel(2, ioaddr + StatsCtrl);
-+ writel(RxOff | TxOff, ioaddr + ChipCmd);
-+ break;
-+ case DRV_RESUME:
-+ /* This is incomplete: the open() actions should be repeated. */
-+ set_rx_mode(dev);
-+ writel(np->intr_enable, ioaddr + IntrEnable);
-+ writel(1, ioaddr + IntrEnable);
-+ writel(RxOn | TxOn, ioaddr + ChipCmd);
-+ break;
-+ case DRV_DETACH: {
-+ struct net_device **devp, **next;
-+ if (dev->flags & IFF_UP) {
-+ /* Some, but not all, kernel versions close automatically. */
-+ dev_close(dev);
-+ dev->flags &= ~(IFF_UP|IFF_RUNNING);
-+ }
-+ unregister_netdev(dev);
-+ release_region(dev->base_addr, pci_id_tbl[np->chip_id].io_size);
-+ for (devp = &root_net_dev; *devp; devp = next) {
-+ next = &((struct netdev_private *)(*devp)->priv)->next_module;
-+ if (*devp == dev) {
-+ *devp = *next;
-+ break;
-+ }
-+ }
-+ if (np->priv_addr)
-+ kfree(np->priv_addr);
-+ kfree(dev);
-+ MOD_DEC_USE_COUNT;
-+ break;
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+
-+#ifdef MODULE
-+int init_module(void)
-+{
-+ if (debug >= NETIF_MSG_DRV) /* Emit version even if no cards detected. */
-+ printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2);
-+#ifdef CARDBUS
-+ register_driver(&etherdev_ops);
-+ return 0;
-+#else
-+ return pci_drv_register(&natsemi_drv_id, NULL);
-+#endif
-+}
-+
-+void cleanup_module(void)
-+{
-+ struct net_device *next_dev;
-+
-+#ifdef CARDBUS
-+ unregister_driver(&etherdev_ops);
-+#else
-+ pci_drv_unregister(&natsemi_drv_id);
-+#endif
-+
-+ /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
-+ while (root_net_dev) {
-+ struct netdev_private *np = (void *)(root_net_dev->priv);
-+ unregister_netdev(root_net_dev);
-+ iounmap((char *)root_net_dev->base_addr);
-+ next_dev = np->next_module;
-+ if (np->priv_addr)
-+ kfree(np->priv_addr);
-+ kfree(root_net_dev);
-+ root_net_dev = next_dev;
-+ }
-+}
-+
-+#endif /* MODULE */
-+
-+/*
-+ * Local variables:
-+ * compile-command: "make KERNVER=`uname -r` natsemi.o"
-+ * compile-cmd: "gcc -DMODULE -Wall -Wstrict-prototypes -O6 -c natsemi.c"
-+ * simple-compile-command: "gcc -DMODULE -O6 -c natsemi.c"
-+ * c-indent-level: 4
-+ * c-basic-offset: 4
-+ * tab-width: 4
-+ * End:
-+ */
-Index: linux/src/drivers/net/ne2k-pci.c
-===================================================================
-RCS file: /cvsroot/hurd/gnumach/linux/src/drivers/net/Attic/ne2k-pci.c,v
-retrieving revision 1.1
-diff -u -r1.1 ne2k-pci.c
---- linux/src/drivers/net/ne2k-pci.c 26 Apr 1999 05:52:27 -0000 1.1
-+++ linux/src/drivers/net/ne2k-pci.c 20 Aug 2004 10:32:53 -0000
-@@ -2,39 +2,81 @@
- /*
- A Linux device driver for PCI NE2000 clones.
-
-- Authorship and other copyrights:
-- 1992-1998 by Donald Becker, NE2000 core and various modifications.
-+ Authors and other copyright holders:
-+ 1992-2002 by Donald Becker, NE2000 core and various modifications.
- 1995-1998 by Paul Gortmaker, core modifications and PCI support.
--
- Copyright 1993 assigned to the United States Government as represented
- by the Director, National Security Agency.
-
-- This software may be used and distributed according to the terms
-- of the GNU Public License, incorporated herein by reference.
--
-- The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
-- Center of Excellence in Space Data and Information Sciences
-- Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
--
-- People are making PCI ne2000 clones! Oh the horror, the horror...
-+ This software may be used and distributed according to the terms of
-+ the GNU General Public License (GPL), incorporated herein by reference.
-+ Drivers based on or derived from this code fall under the GPL and must
-+ retain the authorship, copyright and license notice. This file is not
-+ a complete program and may only be used when the entire operating
-+ system is licensed under the GPL.
-+
-+ The author may be reached as becker@scyld.com, or C/O
-+ Scyld Computing Corporation
-+ 410 Severn Ave., Suite 210
-+ Annapolis MD 21403
-
- Issues remaining:
-- No full-duplex support.
-+ People are making PCI ne2000 clones! Oh the horror, the horror...
-+ Limited full-duplex support.
- */
-
--/* Our copyright info must remain in the binary. */
--static const char *version =
--"ne2k-pci.c:v0.99L 2/7/98 D. Becker/P. Gortmaker http://cesdis.gsfc.nasa.gov/linux/drivers/ne2k-pci.html\n";
-+/* These identify the driver base version and may not be removed. */
-+static const char version1[] =
-+"ne2k-pci.c:v1.05 6/13/2002 D. Becker/P. Gortmaker\n";
-+static const char version2[] =
-+" http://www.scyld.com/network/ne2k-pci.html\n";
-+
-+/* The user-configurable values.
-+ These may be modified when a driver module is loaded.*/
-+
-+static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */
-+
-+#define MAX_UNITS 8 /* More are supported, limit only on options */
-+/* Used to pass the full-duplex flag, etc. */
-+static int full_duplex[MAX_UNITS] = {0, };
-+static int options[MAX_UNITS] = {0, };
-
--#ifdef MODVERSIONS
--#include <linux/modversions.h>
-+/* Force a non std. amount of memory. Units are 256 byte pages. */
-+/* #define PACKETBUF_MEMSIZE 0x40 */
-+
-+#ifndef __KERNEL__
-+#define __KERNEL__
-+#endif
-+#if !defined(__OPTIMIZE__)
-+#warning You must compile this file with the correct options!
-+#warning See the last lines of the source file.
-+#error You must compile this driver with "-O".
-+#endif
-+
-+#include <linux/config.h>
-+#if defined(CONFIG_SMP) && ! defined(__SMP__)
-+#define __SMP__
-+#endif
-+#if defined(MODULE) && defined(CONFIG_MODVERSIONS) && ! defined(MODVERSIONS)
-+#define MODVERSIONS
- #endif
-+
-+#include <linux/version.h>
- #include <linux/module.h>
-+#if LINUX_VERSION_CODE < 0x20300 && defined(MODVERSIONS)
-+#include <linux/modversions.h>
-+#endif
-+
- #include <linux/kernel.h>
--#include <linux/sched.h>
- #include <linux/errno.h>
- #include <linux/pci.h>
--#include <linux/bios32.h>
-+#if LINUX_VERSION_CODE < 0x20200
-+#define lock_8390_module()
-+#define unlock_8390_module()
-+#else
-+#include <linux/init.h>
-+#endif
-+
- #include <asm/system.h>
- #include <asm/io.h>
- #include <asm/irq.h>
-@@ -43,8 +85,18 @@
- #include <linux/etherdevice.h>
- #include "8390.h"
-
--/* Set statically or when loading the driver module. */
--static int debug = 1;
-+#ifdef INLINE_PCISCAN
-+#include "k_compat.h"
-+#else
-+#include "pci-scan.h"
-+#include "kern_compat.h"
-+#endif
-+
-+MODULE_AUTHOR("Donald Becker / Paul Gortmaker");
-+MODULE_DESCRIPTION("PCI NE2000 clone driver");
-+MODULE_PARM(debug, "i");
-+MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
-+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
-
- /* Some defines that people can play with if so inclined. */
-
-@@ -52,27 +104,52 @@
- #ifdef LOAD_8390_BY_KERNELD
- #include <linux/kerneld.h>
- #endif
--/* Use 32 bit data-movement operations instead of 16 bit. */
--#define USE_LONGIO
--
--/* Do we implement the read before write bugfix ? */
--/* #define NE_RW_BUGFIX */
-
--/* Do we have a non std. amount of memory? (in units of 256 byte pages) */
--/* #define PACKETBUF_MEMSIZE 0x40 */
-+static void *ne2k_pci_probe1(struct pci_dev *pdev, void *dev,
-+ long ioaddr, int irq, int chip_idx, int fnd_cnt);
-+/* Flags. We rename an existing ei_status field to store flags! */
-+/* Thus only the low 8 bits are usable for non-init-time flags. */
-+#define ne2k_flags reg0
-+enum {
-+ ONLY_16BIT_IO=8, ONLY_32BIT_IO=4, /* Chip can do only 16/32-bit xfers. */
-+ FORCE_FDX=0x20, /* User override. */
-+ REALTEK_FDX=0x40, HOLTEK_FDX=0x80,
-+ STOP_PG_0x60=0x100,
-+};
-+#define NE_IO_EXTENT 0x20
-+#ifndef USE_MEMORY_OPS
-+#define PCI_IOTYPE (PCI_USES_IO | PCI_ADDR0)
-+#else
-+#warning When using PCI memory mode the 8390 core must be compiled for memory
-+#warning operations as well.
-+#warning Not all PCI NE2000 clones support memory mode access.
-+#define PCI_IOTYPE (PCI_USES_MEM | PCI_ADDR1)
-+#endif
-+
-+static struct pci_id_info pci_id_tbl[] = {
-+ {"RealTek RTL-8029",{ 0x802910ec, 0xffffffff}, PCI_IOTYPE, NE_IO_EXTENT,
-+ REALTEK_FDX },
-+ {"Winbond 89C940", { 0x09401050, 0xffffffff}, PCI_IOTYPE, NE_IO_EXTENT, 0},
-+ {"Winbond w89c940", { 0x5a5a1050, 0xffffffff}, PCI_IOTYPE, NE_IO_EXTENT, 0},
-+ {"KTI ET32P2", { 0x30008e2e, 0xffffffff}, PCI_IOTYPE, NE_IO_EXTENT, 0},
-+ {"NetVin NV5000SC", { 0x50004a14, 0xffffffff}, PCI_IOTYPE, NE_IO_EXTENT, 0},
-+ {"Via 86C926", { 0x09261106, 0xffffffff},
-+ PCI_IOTYPE, NE_IO_EXTENT, ONLY_16BIT_IO},
-+ {"SureCom NE34", { 0x0e3410bd, 0xffffffff}, PCI_IOTYPE, NE_IO_EXTENT, 0},
-+ {"Holtek HT80232", { 0x005812c3, 0xffffffff},
-+ PCI_IOTYPE, NE_IO_EXTENT, ONLY_16BIT_IO | HOLTEK_FDX},
-+ {"Holtek HT80229", { 0x559812c3, 0xffffffff},
-+ PCI_IOTYPE, NE_IO_EXTENT, ONLY_32BIT_IO | HOLTEK_FDX | STOP_PG_0x60},
-+ {"Compex RL2000",
-+ { 0x140111f6, 0xffffffff}, PCI_IOTYPE, NE_IO_EXTENT, 0},
-+ /* A mutant board: Winbond chip with a RTL format EEPROM. */
-+ {"Winbond w89c940 (misprogrammed type 0x1980)", { 0x19808c4a, 0xffffffff},
-+ PCI_IOTYPE, NE_IO_EXTENT, 0},
-+ {0,}, /* 0 terminated list. */
-+};
-
--static struct {
-- unsigned short vendor, dev_id;
-- char *name;
--}
--pci_clone_list[] = {
-- {0x10ec, 0x8029, "RealTek RTL-8029"},
-- {0x1050, 0x0940, "Winbond 89C940"},
-- {0x11f6, 0x1401, "Compex RL2000"},
-- {0x8e2e, 0x3000, "KTI ET32P2"},
-- {0x4a14, 0x5000, "NetVin NV5000SC"},
-- {0x1106, 0x0926, "Via 82C926"},
-- {0,}
-+struct drv_id_info ne2k_pci_drv_id = {
-+ "ne2k-pci", 0, PCI_CLASS_NETWORK_ETHERNET<<8, pci_id_tbl, ne2k_pci_probe1,
- };
-
- /* ---- No user-serviceable parts below ---- */
-@@ -81,41 +158,40 @@
- #define NE_CMD 0x00
- #define NE_DATAPORT 0x10 /* NatSemi-defined port window offset. */
- #define NE_RESET 0x1f /* Issue a read to reset, a write to clear. */
--#define NE_IO_EXTENT 0x20
-
- #define NESM_START_PG 0x40 /* First page of TX buffer */
- #define NESM_STOP_PG 0x80 /* Last page +1 of RX ring */
-
--int ne2k_pci_probe(struct device *dev);
--static struct device *ne2k_pci_probe1(struct device *dev, int ioaddr, int irq);
-+int ne2k_pci_probe(struct net_device *dev);
-
--static int ne_open(struct device *dev);
--static int ne_close(struct device *dev);
-+static int ne2k_pci_open(struct net_device *dev);
-+static int ne2k_pci_close(struct net_device *dev);
-
--static void ne_reset_8390(struct device *dev);
--static void ne_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr,
-+static void ne2k_pci_reset_8390(struct net_device *dev);
-+static void ne2k_pci_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
- int ring_page);
--static void ne_block_input(struct device *dev, int count,
-+static void ne2k_pci_block_input(struct net_device *dev, int count,
- struct sk_buff *skb, int ring_offset);
--static void ne_block_output(struct device *dev, const int count,
-+static void ne2k_pci_block_output(struct net_device *dev, const int count,
- const unsigned char *buf, const int start_page);
-
-
-
--/* No room in the standard 8390 structure for extra info we need. */
-+/* There is no room in the standard 8390 structure for extra info we need,
-+ so we build a meta/outer-wrapper structure.. */
- struct ne2k_pci_card {
- struct ne2k_pci_card *next;
-- struct device *dev;
-- unsigned char pci_bus, pci_device_fn;
-+ struct net_device *dev;
-+ struct pci_dev *pci_dev;
- };
- /* A list of all installed devices, for removing the driver module. */
- static struct ne2k_pci_card *ne2k_card_list = NULL;
-
- #ifdef LOAD_8390_BY_KERNELD
--static int (*Lethdev_init)(struct device *dev);
--static void (*LNS8390_init)(struct device *dev, int startp);
--static int (*Lei_open)(struct device *dev);
--static int (*Lei_close)(struct device *dev);
-+static int (*Lethdev_init)(struct net_device *dev);
-+static void (*LNS8390_init)(struct net_device *dev, int startp);
-+static int (*Lei_open)(struct net_device *dev);
-+static int (*Lei_close)(struct net_device *dev);
- static void (*Lei_interrupt)(int irq, void *dev_id, struct pt_regs *regs);
- #else
- #define Lethdev_init ethdev_init
-@@ -126,23 +202,28 @@
- #endif
-
- #ifdef MODULE
--
--int
--init_module(void)
-+int init_module(void)
- {
-- /* We must emit version information. */
-- if (debug)
-- printk(KERN_INFO "%s", version);
-+ int found_cnt;
-
-- return ne2k_pci_probe(0);
-+ if (debug) /* Emit version even if no cards detected. */
-+ printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2);
-+ found_cnt = pci_drv_register(&ne2k_pci_drv_id, NULL);
-+ if (found_cnt < 0) {
-+ printk(KERN_NOTICE "ne2k-pci.c: No useable cards found, driver NOT installed.\n");
-+ return -ENODEV;
-+ }
-+ lock_8390_module();
-+ return 0;
- }
-
--void
--cleanup_module(void)
-+void cleanup_module(void)
- {
-- struct device *dev;
-+ struct net_device *dev;
- struct ne2k_pci_card *this_card;
-
-+ pci_drv_unregister(&ne2k_pci_drv_id);
-+
- /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
- while (ne2k_card_list) {
- dev = ne2k_card_list->dev;
-@@ -156,131 +237,32 @@
-
- #ifdef LOAD_8390_BY_KERNELD
- release_module("8390", 0);
-+#else
-+ unlock_8390_module();
- #endif
- }
-
--#endif /* MODULE */
--
--/*
-- NEx000-clone boards have a Station Address (SA) PROM (SAPROM) in the packet
-- buffer memory space. By-the-spec NE2000 clones have 0x57,0x57 in bytes
-- 0x0e,0x0f of the SAPROM, while other supposed NE2000 clones must be
-- detected by their SA prefix.
--
-- Reading the SAPROM from a word-wide card with the 8390 set in byte-wide
-- mode results in doubled values, which can be detected and compensated for.
--
-- The probe is also responsible for initializing the card and filling
-- in the 'dev' and 'ei_status' structures.
--*/
--
--#ifdef HAVE_DEVLIST
--struct netdev_entry netcard_drv =
--{"ne2k_pci", ne2k_pci_probe1, NE_IO_EXTENT, 0};
--#endif
-+#else
-
--int ne2k_pci_probe(struct device *dev)
-+int ne2k_pci_probe(struct net_device *dev)
- {
-- static int pci_index = 0; /* Static, for multiple calls. */
-- int cards_found = 0;
-- int i;
--
-- if ( ! pcibios_present())
-- return -ENODEV;
--
-- for (;pci_index < 0xff; pci_index++) {
-- unsigned char pci_bus, pci_device_fn;
-- u8 pci_irq_line;
-- u16 pci_command, new_command, vendor, device;
-- u32 pci_ioaddr;
--
-- if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pci_index,
-- &pci_bus, &pci_device_fn)
-- != PCIBIOS_SUCCESSFUL)
-- break;
-- pcibios_read_config_word(pci_bus, pci_device_fn,
-- PCI_VENDOR_ID, &vendor);
-- pcibios_read_config_word(pci_bus, pci_device_fn,
-- PCI_DEVICE_ID, &device);
--
-- /* Note: some vendor IDs (RealTek) have non-NE2k cards as well. */
-- for (i = 0; pci_clone_list[i].vendor != 0; i++)
-- if (pci_clone_list[i].vendor == vendor
-- && pci_clone_list[i].dev_id == device)
-- break;
-- if (pci_clone_list[i].vendor == 0)
-- continue;
--
--#ifndef MODULE
-- {
-- static unsigned version_printed = 0;
-- if (version_printed++ == 0)
-- printk(KERN_INFO "%s", version);
-- }
--#endif
--
-- pcibios_read_config_dword(pci_bus, pci_device_fn,
-- PCI_BASE_ADDRESS_0, &pci_ioaddr);
-- pcibios_read_config_byte(pci_bus, pci_device_fn,
-- PCI_INTERRUPT_LINE, &pci_irq_line);
-- pcibios_read_config_word(pci_bus, pci_device_fn,
-- PCI_COMMAND, &pci_command);
--
-- /* Remove I/O space marker in bit 0. */
-- pci_ioaddr &= PCI_BASE_ADDRESS_IO_MASK;
--
-- /* Avoid already found cards from previous calls */
-- if (check_region(pci_ioaddr, NE_IO_EXTENT))
-- continue;
--
-- /* Activate the card: fix for brain-damaged Win98 BIOSes. */
-- new_command = pci_command | PCI_COMMAND_IO;
-- if (pci_command != new_command) {
-- printk(KERN_INFO " The PCI BIOS has not enabled this"
-- " NE2k clone! Updating PCI command %4.4x->%4.4x.\n",
-- pci_command, new_command);
-- pcibios_write_config_word(pci_bus, pci_device_fn,
-- PCI_COMMAND, new_command);
-- }
--
-- if (pci_irq_line <= 0 || pci_irq_line >= NR_IRQS)
-- printk(KERN_WARNING " WARNING: The PCI BIOS assigned this PCI NE2k"
-- " card to IRQ %d, which is unlikely to work!.\n"
-- KERN_WARNING " You should use the PCI BIOS setup to assign"
-- " a valid IRQ line.\n", pci_irq_line);
--
-- printk("ne2k-pci.c: PCI NE2000 clone '%s' at I/O %#x, IRQ %d.\n",
-- pci_clone_list[i].name, pci_ioaddr, pci_irq_line);
-- dev = ne2k_pci_probe1(dev, pci_ioaddr, pci_irq_line);
-- if (dev == 0) {
-- /* Should not happen. */
-- printk(KERN_ERR "ne2k-pci: Probe of PCI card at %#x failed.\n",
-- pci_ioaddr);
-- continue;
-- } else {
-- struct ne2k_pci_card *ne2k_card =
-- kmalloc(sizeof(struct ne2k_pci_card), GFP_KERNEL);
-- ne2k_card->next = ne2k_card_list;
-- ne2k_card_list = ne2k_card;
-- ne2k_card->dev = dev;
-- ne2k_card->pci_bus = pci_bus;
-- ne2k_card->pci_device_fn = pci_device_fn;
-- }
-- dev = 0;
--
-- cards_found++;
-- }
--
-- return cards_found ? 0 : -ENODEV;
-+ int found_cnt = pci_drv_register(&ne2k_pci_drv_id, NULL);
-+ if (found_cnt >= 0 && debug)
-+ printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2);
-+ return found_cnt;
- }
-+#endif /* MODULE */
-
--static struct device *ne2k_pci_probe1(struct device *dev, int ioaddr, int irq)
-+static void *ne2k_pci_probe1(struct pci_dev *pdev, void *init_dev,
-+ long ioaddr, int irq, int chip_idx, int fnd_cnt)
- {
-+ struct net_device *dev;
- int i;
- unsigned char SA_prom[32];
-- const char *name = NULL;
- int start_page, stop_page;
- int reg0 = inb(ioaddr);
-+ int flags = pci_id_tbl[chip_idx].drv_flags;
-+ struct ne2k_pci_card *ne2k_card;
-
- if (reg0 == 0xFF)
- return 0;
-@@ -300,7 +282,18 @@
- }
- }
-
-- dev = init_etherdev(dev, 0);
-+ dev = init_etherdev(init_dev, 0);
-+
-+ if (dev == NULL)
-+ return 0;
-+ ne2k_card = kmalloc(sizeof(struct ne2k_pci_card), GFP_KERNEL);
-+ if (ne2k_card == NULL)
-+ return 0;
-+
-+ ne2k_card->next = ne2k_card_list;
-+ ne2k_card_list = ne2k_card;
-+ ne2k_card->dev = dev;
-+ ne2k_card->pci_dev = pdev;
-
- /* Reset card. Who knows what dain-bramaged state it was left in. */
- {
-@@ -363,34 +356,23 @@
-
- }
-
--#ifdef notdef
-- /* Some broken PCI cards don't respect the byte-wide
-- request in program_seq above, and hence don't have doubled up values.
-- */
-- for(i = 0; i < 32 /*sizeof(SA_prom)*/; i+=2) {
-- SA_prom[i] = inb(ioaddr + NE_DATAPORT);
-- SA_prom[i+1] = inb(ioaddr + NE_DATAPORT);
-- if (SA_prom[i] != SA_prom[i+1])
-- sa_prom_doubled = 0;
-- }
-+ /* Note: all PCI cards have at least 16 bit access, so we don't have
-+ to check for 8 bit cards. Most cards permit 32 bit access. */
-
-- if (sa_prom_doubled)
-- for (i = 0; i < 16; i++)
-- SA_prom[i] = SA_prom[i+i];
--#else
-- for(i = 0; i < 32 /*sizeof(SA_prom)*/; i++)
-- SA_prom[i] = inb(ioaddr + NE_DATAPORT);
--
--#endif
-+ if (flags & ONLY_32BIT_IO) {
-+ for (i = 0; i < 8; i++)
-+ ((u32 *)SA_prom)[i] = le32_to_cpu(inl(ioaddr + NE_DATAPORT));
-+ } else
-+ for(i = 0; i < 32 /*sizeof(SA_prom)*/; i++)
-+ SA_prom[i] = inb(ioaddr + NE_DATAPORT);
-
- /* We always set the 8390 registers for word mode. */
- outb(0x49, ioaddr + EN0_DCFG);
- start_page = NESM_START_PG;
-- stop_page = NESM_STOP_PG;
-
-- /* Set up the rest of the parameters. */
-- name = "PCI NE2000";
-+ stop_page = flags & STOP_PG_0x60 ? 0x60 : NESM_STOP_PG;
-
-+ /* Set up the rest of the parameters. */
- dev->irq = irq;
- dev->base_addr = ioaddr;
-
-@@ -402,17 +384,24 @@
-
- request_region(ioaddr, NE_IO_EXTENT, dev->name);
-
-- printk("%s: %s found at %#x, IRQ %d, ",
-- dev->name, name, ioaddr, dev->irq);
-+ printk("%s: %s found at %#lx, IRQ %d, ",
-+ dev->name, pci_id_tbl[chip_idx].name, ioaddr, dev->irq);
- for(i = 0; i < 6; i++) {
- printk("%2.2X%s", SA_prom[i], i == 5 ? ".\n": ":");
- dev->dev_addr[i] = SA_prom[i];
- }
-
-- ei_status.name = name;
-+ ei_status.name = pci_id_tbl[chip_idx].name;
- ei_status.tx_start_page = start_page;
- ei_status.stop_page = stop_page;
- ei_status.word16 = 1;
-+ ei_status.ne2k_flags = flags;
-+ if (fnd_cnt < MAX_UNITS) {
-+ if (full_duplex[fnd_cnt] > 0 || (options[fnd_cnt] & FORCE_FDX)) {
-+ printk("%s: Full duplex set by user option.\n", dev->name);
-+ ei_status.ne2k_flags |= FORCE_FDX;
-+ }
-+ }
-
- ei_status.rx_start_page = start_page + TX_PAGES;
- #ifdef PACKETBUF_MEMSIZE
-@@ -420,28 +409,37 @@
- ei_status.stop_page = ei_status.tx_start_page + PACKETBUF_MEMSIZE;
- #endif
-
-- ei_status.reset_8390 = &ne_reset_8390;
-- ei_status.block_input = &ne_block_input;
-- ei_status.block_output = &ne_block_output;
-- ei_status.get_8390_hdr = &ne_get_8390_hdr;
-- dev->open = &ne_open;
-- dev->stop = &ne_close;
-+ ei_status.reset_8390 = &ne2k_pci_reset_8390;
-+ ei_status.block_input = &ne2k_pci_block_input;
-+ ei_status.block_output = &ne2k_pci_block_output;
-+ ei_status.get_8390_hdr = &ne2k_pci_get_8390_hdr;
-+ dev->open = &ne2k_pci_open;
-+ dev->stop = &ne2k_pci_close;
- LNS8390_init(dev, 0);
- return dev;
- }
-
--static int
--ne_open(struct device *dev)
-+static int ne2k_pci_open(struct net_device *dev)
- {
-- if (request_irq(dev->irq, Lei_interrupt, SA_SHIRQ, dev->name, dev))
-+ MOD_INC_USE_COUNT;
-+ if (request_irq(dev->irq, Lei_interrupt, SA_SHIRQ, dev->name, dev)) {
-+ MOD_DEC_USE_COUNT;
- return -EAGAIN;
-+ }
-+ /* Set full duplex for the chips that we know about. */
-+ if (ei_status.ne2k_flags & FORCE_FDX) {
-+ long ioaddr = dev->base_addr;
-+ if (ei_status.ne2k_flags & REALTEK_FDX) {
-+ outb(0xC0 + E8390_NODMA, ioaddr + NE_CMD); /* Page 3 */
-+ outb(inb(ioaddr + 0x20) | 0x80, ioaddr + 0x20);
-+ } else if (ei_status.ne2k_flags & HOLTEK_FDX)
-+ outb(inb(ioaddr + 0x20) | 0x80, ioaddr + 0x20);
-+ }
- Lei_open(dev);
-- MOD_INC_USE_COUNT;
- return 0;
- }
-
--static int
--ne_close(struct device *dev)
-+static int ne2k_pci_close(struct net_device *dev)
- {
- Lei_close(dev);
- free_irq(dev->irq, dev);
-@@ -451,8 +449,7 @@
-
- /* Hard reset the card. This used to pause for the same period that a
- 8390 reset command required, but that shouldn't be necessary. */
--static void
--ne_reset_8390(struct device *dev)
-+static void ne2k_pci_reset_8390(struct net_device *dev)
- {
- unsigned long reset_start_time = jiffies;
-
-@@ -467,7 +464,7 @@
- /* This check _should_not_ be necessary, omit eventually. */
- while ((inb(NE_BASE+EN0_ISR) & ENISR_RESET) == 0)
- if (jiffies - reset_start_time > 2) {
-- printk("%s: ne_reset_8390() did not complete.\n", dev->name);
-+ printk("%s: ne2k_pci_reset_8390() did not complete.\n", dev->name);
- break;
- }
- outb(ENISR_RESET, NE_BASE + EN0_ISR); /* Ack intr. */
-@@ -477,18 +474,18 @@
- we don't need to be concerned with ring wrap as the header will be at
- the start of a page, so we optimize accordingly. */
-
--static void
--ne_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
-+static void ne2k_pci_get_8390_hdr(struct net_device *dev,
-+ struct e8390_pkt_hdr *hdr, int ring_page)
- {
-
-- int nic_base = dev->base_addr;
-+ long nic_base = dev->base_addr;
-
- /* This *shouldn't* happen. If it does, it's the last thing you'll see */
- if (ei_status.dmaing) {
-- printk("%s: DMAing conflict in ne_get_8390_hdr "
-+ printk("%s: DMAing conflict in ne2k_pci_get_8390_hdr "
- "[DMAstat:%d][irqlock:%d][intr:%d].\n",
- dev->name, ei_status.dmaing, ei_status.irqlock,
-- dev->interrupt);
-+ (int)dev->interrupt);
- return;
- }
-
-@@ -500,11 +497,12 @@
- outb(ring_page, nic_base + EN0_RSARHI);
- outb(E8390_RREAD+E8390_START, nic_base + NE_CMD);
-
--#if defined(USE_LONGIO)
-- *(u32*)hdr = inl(NE_BASE + NE_DATAPORT);
--#else
-- insw(NE_BASE + NE_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr)>>1);
--#endif
-+ if (ei_status.ne2k_flags & ONLY_16BIT_IO) {
-+ insw(NE_BASE + NE_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr)>>1);
-+ } else {
-+ *(u32*)hdr = le32_to_cpu(inl(NE_BASE + NE_DATAPORT));
-+ le16_to_cpus(&hdr->count);
-+ }
-
- outb(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */
- ei_status.dmaing &= ~0x01;
-@@ -515,21 +513,23 @@
- The NEx000 doesn't share the on-board packet memory -- you have to put
- the packet out through the "remote DMA" dataport using outb. */
-
--static void
--ne_block_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset)
-+static void ne2k_pci_block_input(struct net_device *dev, int count,
-+ struct sk_buff *skb, int ring_offset)
- {
-- int nic_base = dev->base_addr;
-+ long nic_base = dev->base_addr;
- char *buf = skb->data;
-
- /* This *shouldn't* happen. If it does, it's the last thing you'll see */
- if (ei_status.dmaing) {
-- printk("%s: DMAing conflict in ne_block_input "
-+ printk("%s: DMAing conflict in ne2k_pci_block_input "
- "[DMAstat:%d][irqlock:%d][intr:%d].\n",
- dev->name, ei_status.dmaing, ei_status.irqlock,
-- dev->interrupt);
-+ (int)dev->interrupt);
- return;
- }
- ei_status.dmaing |= 0x01;
-+ if (ei_status.ne2k_flags & ONLY_32BIT_IO)
-+ count = (count + 3) & 0xFFFC;
- outb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
- outb(count & 0xff, nic_base + EN0_RCNTLO);
- outb(count >> 8, nic_base + EN0_RCNTHI);
-@@ -537,31 +537,28 @@
- outb(ring_offset >> 8, nic_base + EN0_RSARHI);
- outb(E8390_RREAD+E8390_START, nic_base + NE_CMD);
-
--#if defined(USE_LONGIO)
-- insl(NE_BASE + NE_DATAPORT, buf, count>>2);
-- if (count & 3) {
-- buf += count & ~3;
-- if (count & 2)
-- {
-- *buf = *(u16 *) buf + 1;
-- *buf = inw(NE_BASE + NE_DATAPORT);
-- }
-- if (count & 1)
-- *buf = inb(NE_BASE + NE_DATAPORT);
-- }
--#else
-- insw(NE_BASE + NE_DATAPORT,buf,count>>1);
-- if (count & 0x01) {
-- buf[count-1] = inb(NE_BASE + NE_DATAPORT);
-+ if (ei_status.ne2k_flags & ONLY_16BIT_IO) {
-+ insw(NE_BASE + NE_DATAPORT,buf,count>>1);
-+ if (count & 0x01) {
-+ buf[count-1] = inb(NE_BASE + NE_DATAPORT);
-+ }
-+ } else {
-+ insl(NE_BASE + NE_DATAPORT, buf, count>>2);
-+ if (count & 3) {
-+ buf += count & ~3;
-+ if (count & 2)
-+ *((u16*)buf)++ = le16_to_cpu(inw(NE_BASE + NE_DATAPORT));
-+ if (count & 1)
-+ *buf = inb(NE_BASE + NE_DATAPORT);
-+ }
- }
--#endif
-
- outb(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */
- ei_status.dmaing &= ~0x01;
- }
-
- static void
--ne_block_output(struct device *dev, int count,
-+ne2k_pci_block_output(struct net_device *dev, int count,
- const unsigned char *buf, const int start_page)
- {
- int nic_base = NE_BASE;
-@@ -569,15 +566,18 @@
-
- /* On little-endian it's always safe to round the count up for
- word writes. */
-- if (count & 0x01)
-- count++;
-+ if (ei_status.ne2k_flags & ONLY_32BIT_IO)
-+ count = (count + 3) & 0xFFFC;
-+ else
-+ if (count & 0x01)
-+ count++;
-
- /* This *shouldn't* happen. If it does, it's the last thing you'll see */
- if (ei_status.dmaing) {
-- printk("%s: DMAing conflict in ne_block_output."
-+ printk("%s: DMAing conflict in ne2k_pci_block_output."
- "[DMAstat:%d][irqlock:%d][intr:%d]\n",
- dev->name, ei_status.dmaing, ei_status.irqlock,
-- dev->interrupt);
-+ (int)dev->interrupt);
- return;
- }
- ei_status.dmaing |= 0x01;
-@@ -603,24 +603,23 @@
- outb(0x00, nic_base + EN0_RSARLO);
- outb(start_page, nic_base + EN0_RSARHI);
- outb(E8390_RWRITE+E8390_START, nic_base + NE_CMD);
--#if defined(USE_LONGIO)
-- outsl(NE_BASE + NE_DATAPORT, buf, count>>2);
-- if (count & 3) {
-- buf += count & ~3;
-- if (count & 2)
-- outw(*buf++, NE_BASE + NE_DATAPORT);
--
-+ if (ei_status.ne2k_flags & ONLY_16BIT_IO) {
-+ outsw(NE_BASE + NE_DATAPORT, buf, count>>1);
-+ } else {
-+ outsl(NE_BASE + NE_DATAPORT, buf, count>>2);
-+ if (count & 3) {
-+ buf += count & ~3;
-+ if (count & 2)
-+ outw(cpu_to_le16(*((u16*)buf)++), NE_BASE + NE_DATAPORT);
-+ }
- }
--#else
-- outsw(NE_BASE + NE_DATAPORT, buf, count>>1);
--#endif
-
- dma_start = jiffies;
-
- while ((inb(nic_base + EN0_ISR) & ENISR_RDC) == 0)
- if (jiffies - dma_start > 2) { /* Avoid clock roll-over. */
- printk("%s: timeout waiting for Tx RDC.\n", dev->name);
-- ne_reset_8390(dev);
-+ ne2k_pci_reset_8390(dev);
- LNS8390_init(dev,1);
- break;
- }
-@@ -633,8 +632,8 @@
-
- /*
- * Local variables:
-- * compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/ -c ne2k-pci.c"
-- * alt-compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/ -c ne2k-pci.c"
-+ * compile-command: "gcc -DMODULE -Wall -Wstrict-prototypes -O6 -c ne2k-pci.c -I/usr/src/linux/drivers/net/"
-+ * alt-compile-command: "gcc -DMODULE -O6 -c ne2k-pci.c"
- * c-indent-level: 4
- * c-basic-offset: 4
- * tab-width: 4
-Index: linux/src/drivers/net/ns820.c
-===================================================================
-RCS file: linux/src/drivers/net/ns820.c
-diff -N linux/src/drivers/net/ns820.c
---- /dev/null 1 Jan 1970 00:00:00 -0000
-+++ linux/src/drivers/net/ns820.c 10 Nov 2005 00:43:21 -0000
-@@ -0,0 +1,1547 @@
-+/* ns820.c: A Linux Gigabit Ethernet driver for the NatSemi DP83820 series. */
-+/*
-+ Written/copyright 1999-2003 by Donald Becker.
-+ Copyright 2002-2003 by Scyld Computing Corporation.
-+
-+ This software may be used and distributed according to the terms of
-+ the GNU General Public License (GPL), incorporated herein by reference.
-+ Drivers based on or derived from this code fall under the GPL and must
-+ retain the authorship, copyright and license notice. This file is not
-+ a complete program and may only be used when the entire operating
-+ system is licensed under the GPL. License for under other terms may be
-+ available. Contact the original author for details.
-+
-+ The original author may be reached as becker@scyld.com, or at
-+ Scyld Computing Corporation
-+ 914 Bay Ridge Road, Suite 220
-+ Annapolis MD 21403
-+
-+ Support information and updates available at
-+ http://www.scyld.com/network/natsemi.html
-+ The information and support mailing lists are based at
-+ http://www.scyld.com/mailman/listinfo/
-+*/
-+
-+/* These identify the driver base version and may not be removed. */
-+static const char version1[] =
-+"ns820.c:v1.03a 8/09/2003 Written by Donald Becker <becker@scyld.com>\n";
-+static const char version2[] =
-+" http://www.scyld.com/network/natsemi.html\n";
-+/* Updated to recommendations in pci-skeleton v2.13. */
-+
-+/* Automatically extracted configuration info:
-+probe-func: ns820_probe
-+config-in: tristate 'National Semiconductor DP8382x series PCI Ethernet support' CONFIG_NATSEMI820
-+
-+c-help-name: National Semiconductor DP8382x series PCI Ethernet support
-+c-help-symbol: CONFIG_NATSEMI820
-+c-help: This driver is for the National Semiconductor DP83820 Gigabit Ethernet
-+c-help: adapter series.
-+c-help: More specific information and updates are available from
-+c-help: http://www.scyld.com/network/natsemi.html
-+*/
-+
-+/* The user-configurable values.
-+ These may be modified when a driver module is loaded.*/
-+
-+/* Message enable level: 0..31 = no..all messages. See NETIF_MSG docs. */
-+static int debug = 2;
-+
-+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-+static int max_interrupt_work = 20;
-+
-+/* Maximum number of multicast addresses to filter (vs. rx-all-multicast).
-+ This chip uses a 2048 element hash table based on the Ethernet CRC.
-+ Previous natsemi chips had unreliable multicast filter circuitry.
-+ To work around an observed problem set this value to '0',
-+ which will immediately switch to Rx-all-multicast.
-+ */
-+static int multicast_filter_limit = 100;
-+
-+/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
-+ Setting to > 1518 effectively disables this feature.
-+ This chip can only receive into aligned buffers, so architectures such
-+ as the Alpha AXP might benefit from a copy-align.
-+*/
-+static int rx_copybreak = 0;
-+
-+/* Used to pass the media type, etc.
-+ Both 'options[]' and 'full_duplex[]' should exist for driver
-+ interoperability, however setting full_duplex[] is deprecated.
-+ The media type is usually passed in 'options[]'.
-+ The default is autonegotation for speed and duplex.
-+ This should rarely be overridden.
-+ Use option values 0x10/0x20 for 10Mbps, 0x100,0x200 for 100Mbps.
-+ Use option values 0x10 and 0x100 for forcing half duplex fixed speed.
-+ Use option values 0x20 and 0x200 for forcing full duplex operation.
-+ Use 0x1000 or 0x2000 for gigabit.
-+*/
-+#define MAX_UNITS 8 /* More are supported, limit only on options */
-+static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-+static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-+
-+/* Operational parameters that are set at compile time. */
-+
-+/* Keep the ring sizes a power of two for compile efficiency.
-+ Understand the implications before changing these settings!
-+ The compiler will convert <unsigned>'%'<2^N> into a bit mask.
-+ Making the Tx ring too large decreases the effectiveness of channel
-+ bonding and packet priority, confuses the system network buffer limits,
-+ and wastes memory.
-+ Too-large receive rings waste memory and confound network buffer limits.
-+*/
-+#define TX_RING_SIZE 16
-+#define TX_QUEUE_LEN 10 /* Limit ring entries actually used, min 4. */
-+#define RX_RING_SIZE 64
-+
-+/* Operational parameters that usually are not changed. */
-+/* Time in jiffies before concluding the transmitter is hung.
-+ Re-autonegotiation may take up to 3 seconds.
-+ */
-+#define TX_TIMEOUT (6*HZ)
-+
-+/* Allocation size of Rx buffers with normal sized Ethernet frames.
-+ Do not change this value without good reason. This is not a limit,
-+ but a way to keep a consistent allocation size among drivers.
-+ */
-+#define PKT_BUF_SZ 1536
-+
-+#ifndef __KERNEL__
-+#define __KERNEL__
-+#endif
-+#if !defined(__OPTIMIZE__)
-+#warning You must compile this file with the correct options!
-+#warning See the last lines of the source file.
-+#error You must compile this driver with "-O".
-+#endif
-+
-+/* Include files, designed to support most kernel versions 2.0.0 and later. */
-+#include <linux/config.h>
-+#if defined(CONFIG_SMP) && ! defined(__SMP__)
-+#define __SMP__
-+#endif
-+#if defined(MODULE) && defined(CONFIG_MODVERSIONS) && ! defined(MODVERSIONS)
-+#define MODVERSIONS
-+#endif
-+
-+#include <linux/version.h>
-+#if defined(MODVERSIONS)
-+#include <linux/modversions.h>
-+#endif
-+#include <linux/module.h>
-+
-+#include <linux/kernel.h>
-+#include <linux/string.h>
-+#include <linux/timer.h>
-+#include <linux/errno.h>
-+#include <linux/ioport.h>
-+#if LINUX_VERSION_CODE >= 0x20400
-+#include <linux/slab.h>
-+#else
-+#include <linux/malloc.h>
-+#endif
-+#include <linux/interrupt.h>
-+#include <linux/pci.h>
-+#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/skbuff.h>
-+#include <asm/processor.h> /* Processor type for cache alignment. */
-+#include <asm/bitops.h>
-+#include <asm/io.h>
-+
-+#ifdef INLINE_PCISCAN
-+#include "k_compat.h"
-+#else
-+#include "pci-scan.h"
-+#include "kern_compat.h"
-+#endif
-+
-+#if (LINUX_VERSION_CODE >= 0x20100) && defined(MODULE)
-+char kernel_version[] = UTS_RELEASE;
-+#endif
-+
-+MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
-+MODULE_DESCRIPTION("National Semiconductor DP83820 series PCI Ethernet driver");
-+MODULE_LICENSE("GPL");
-+MODULE_PARM(debug, "i");
-+MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
-+MODULE_PARM(max_interrupt_work, "i");
-+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
-+MODULE_PARM(rx_copybreak, "i");
-+MODULE_PARM(multicast_filter_limit, "i");
-+MODULE_PARM_DESC(debug, "Driver message level (0-31)");
-+MODULE_PARM_DESC(options, "Force transceiver type or fixed speed+duplex");
-+MODULE_PARM_DESC(max_interrupt_work,
-+ "Driver maximum events handled per interrupt");
-+MODULE_PARM_DESC(full_duplex,
-+ "Non-zero to force full duplex, non-negotiated link "
-+ "(deprecated).");
-+MODULE_PARM_DESC(rx_copybreak,
-+ "Breakpoint in bytes for copy-only-tiny-frames");
-+MODULE_PARM_DESC(multicast_filter_limit,
-+ "Multicast addresses before switching to Rx-all-multicast");
-+
-+/*
-+ Theory of Operation
-+
-+I. Board Compatibility
-+
-+This driver is designed for National Semiconductor DP83820 10/100/1000
-+Ethernet NIC. It is superficially similar to the 810 series "natsemi.c"
-+driver, however the register layout, descriptor layout and element
-+length of the new chip series is different.
-+
-+II. Board-specific settings
-+
-+This driver requires the PCI interrupt line to be configured.
-+It honors the EEPROM-set values.
-+
-+III. Driver operation
-+
-+IIIa. Ring buffers
-+
-+This driver uses two statically allocated fixed-size descriptor lists
-+formed into rings by a branch from the final descriptor to the beginning of
-+the list. The ring sizes are set at compile time by RX/TX_RING_SIZE.
-+The NatSemi design uses a 'next descriptor' pointer that the driver forms
-+into a list, thus rings can be arbitrarily sized. Before changing the
-+ring sizes you should understand the flow and cache effects of the
-+full/available/empty hysteresis.
-+
-+IIIb/c. Transmit/Receive Structure
-+
-+This driver uses a zero-copy receive and transmit scheme.
-+The driver allocates full frame size skbuffs for the Rx ring buffers at
-+open() time and passes the skb->data field to the chip as receive data
-+buffers. When an incoming frame is less than RX_COPYBREAK bytes long,
-+a fresh skbuff is allocated and the frame is copied to the new skbuff.
-+When the incoming frame is larger, the skbuff is passed directly up the
-+protocol stack. Buffers consumed this way are replaced by newly allocated
-+skbuffs in a later phase of receives.
-+
-+The RX_COPYBREAK value is chosen to trade-off the memory wasted by
-+using a full-sized skbuff for small frames vs. the copying costs of larger
-+frames. New boards are typically used in generously configured machines
-+and the underfilled buffers have negligible impact compared to the benefit of
-+a single allocation size, so the default value of zero results in never
-+copying packets. When copying is done, the cost is usually mitigated by using
-+a combined copy/checksum routine. Copying also preloads the cache, which is
-+most useful with small frames.
-+
-+A subtle aspect of the operation is that unaligned buffers are not permitted
-+by the hardware. Thus the IP header at offset 14 in an ethernet frame isn't
-+longword aligned for further processing. On copies frames are put into the
-+skbuff at an offset of "+2", 16-byte aligning the IP header.
-+
-+IIId. Synchronization
-+
-+The driver runs as two independent, single-threaded flows of control. One
-+is the send-packet routine, which enforces single-threaded use by the
-+dev->tbusy flag. The other thread is the interrupt handler, which is single
-+threaded by the hardware and interrupt handling software.
-+
-+The send packet thread has partial control over the Tx ring and 'dev->tbusy'
-+flag. It sets the tbusy flag whenever it's queuing a Tx packet. If the next
-+queue slot is empty, it clears the tbusy flag when finished otherwise it sets
-+the 'lp->tx_full' flag.
-+
-+The interrupt handler has exclusive control over the Rx ring and records stats
-+from the Tx ring. After reaping the stats, it marks the Tx queue entry as
-+empty by incrementing the dirty_tx mark. Iff the 'lp->tx_full' flag is set, it
-+clears both the tx_full and tbusy flags.
-+
-+IV. Notes
-+
-+The NatSemi 820 series PCI gigabit chips are very common on low-cost NICs.
-+The '821 appears to be the same as '820 chip, only with pins for the upper
-+32 bits marked "N/C".
-+
-+IVb. References
-+
-+http://www.scyld.com/expert/100mbps.html
-+http://www.scyld.com/expert/NWay.html
-+The NatSemi dp83820 datasheet is available: search www.natsemi.com
-+
-+IVc. Errata
-+
-+None characterised.
-+
-+*/
-+
-+
-+
-+static void *ns820_probe1(struct pci_dev *pdev, void *init_dev,
-+ long ioaddr, int irq, int chip_idx, int find_cnt);
-+static int power_event(void *dev_instance, int event);
-+enum chip_capability_flags {FDXActiveLow=1, InvertGbXcvrPwr=2, };
-+#ifdef USE_IO_OPS
-+#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_IO | PCI_ADDR0)
-+#else
-+#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR1)
-+#endif
-+
-+static struct pci_id_info pci_id_tbl[] = {
-+ { "D-Link DGE-500T (DP83820)",
-+ { 0x0022100B, 0xffffffff, 0x49001186, 0xffffffff, },
-+ PCI_IOTYPE, 256, FDXActiveLow},
-+ {"NatSemi DP83820", { 0x0022100B, 0xffffffff },
-+ PCI_IOTYPE, 256, 0},
-+ {0,}, /* 0 terminated list. */
-+};
-+
-+struct drv_id_info ns820_drv_id = {
-+ "ns820", PCI_HOTSWAP, PCI_CLASS_NETWORK_ETHERNET<<8, pci_id_tbl,
-+ ns820_probe1, power_event };
-+
-+/* Offsets to the device registers.
-+ Unlike software-only systems, device drivers interact with complex hardware.
-+ It's not useful to define symbolic names for every register bit in the
-+ device. Please do not change these names without good reason.
-+*/
-+enum register_offsets {
-+ ChipCmd=0x00, ChipConfig=0x04, EECtrl=0x08, PCIBusCfg=0x0C,
-+ IntrStatus=0x10, IntrMask=0x14, IntrEnable=0x18, IntrHoldoff=0x1C,
-+ TxRingPtr=0x20, TxRingPtrHi=0x24, TxConfig=0x28,
-+ RxRingPtr=0x30, RxRingPtrHi=0x34, RxConfig=0x38,
-+ WOLCmd=0x40, PauseCmd=0x44, RxFilterAddr=0x48, RxFilterData=0x4C,
-+ BootRomAddr=0x50, BootRomData=0x54, ChipRevReg=0x58,
-+ StatsCtrl=0x5C, RxPktErrs=0x60, RxMissed=0x68, RxCRCErrs=0x64,
-+};
-+
-+/* Bits in ChipCmd. */
-+enum ChipCmdBits {
-+ ChipReset=0x100, SoftIntr=0x80, RxReset=0x20, TxReset=0x10,
-+ RxOff=0x08, RxOn=0x04, TxOff=0x02, TxOn=0x01,
-+};
-+
-+/* Bits in ChipConfig. */
-+enum ChipConfigBits {
-+ CfgLinkGood=0x80000000, CfgFDX=0x10000000,
-+ CfgXcrReset=0x0400, CfgXcrOff=0x0200,
-+};
-+
-+/* Bits in the interrupt status/mask registers. */
-+enum intr_status_bits {
-+ IntrRxDone=0x0001, IntrRxIntr=0x0002, IntrRxErr=0x0004, IntrRxEarly=0x0008,
-+ IntrRxIdle=0x0010, IntrRxOverrun=0x0020,
-+ IntrTxDone=0x0040, IntrTxIntr=0x0080, IntrTxErr=0x0100,
-+ IntrTxIdle=0x0200, IntrTxUnderrun=0x0400,
-+ StatsMax=0x0800, IntrDrv=0x1000, WOLPkt=0x2000, LinkChange=0x4000,
-+ RxStatusOverrun=0x10000,
-+ RxResetDone=0x00200000, TxResetDone=0x00400000,
-+ IntrPCIErr=0x001E0000,
-+ IntrNormalSummary=0x0251, IntrAbnormalSummary=0xED20,
-+};
-+
-+/* Bits in the RxMode register. */
-+enum rx_mode_bits {
-+ AcceptErr=0x20, AcceptRunt=0x10,
-+ AcceptBroadcast=0xC0000000,
-+ AcceptMulticast=0x00200000, AcceptAllMulticast=0x20000000,
-+ AcceptAllPhys=0x10000000, AcceptMyPhys=0x08000000,
-+};
-+
-+/* The Rx and Tx buffer descriptors. */
-+/* Note that using only 32 bit fields simplifies conversion to big-endian
-+ architectures. */
-+struct netdev_desc {
-+#if ADDRLEN == 64
-+ u64 next_desc;
-+ u64 buf_addr;
-+#endif
-+ u32 next_desc;
-+ u32 buf_addr;
-+ s32 cmd_status;
-+ u32 vlan_status;
-+};
-+
-+/* Bits in network_desc.status */
-+enum desc_status_bits {
-+ DescOwn=0x80000000, DescMore=0x40000000, DescIntr=0x20000000,
-+ DescNoCRC=0x10000000,
-+ DescPktOK=0x08000000, RxTooLong=0x00400000,
-+};
-+
-+#define PRIV_ALIGN 15 /* Required alignment mask */
-+struct netdev_private {
-+ /* Descriptor rings first for alignment. */
-+ struct netdev_desc rx_ring[RX_RING_SIZE];
-+ struct netdev_desc tx_ring[TX_RING_SIZE];
-+ struct net_device *next_module; /* Link for devices of this type. */
-+ void *priv_addr; /* Unaligned address for kfree */
-+ const char *product_name;
-+ /* The addresses of receive-in-place skbuffs. */
-+ struct sk_buff* rx_skbuff[RX_RING_SIZE];
-+ /* The saved address of a sent-in-place packet/buffer, for later free(). */
-+ struct sk_buff* tx_skbuff[TX_RING_SIZE];
-+ struct net_device_stats stats;
-+ struct timer_list timer; /* Media monitoring timer. */
-+ /* Frequently used values: keep some adjacent for cache effect. */
-+ int msg_level;
-+ int chip_id, drv_flags;
-+ struct pci_dev *pci_dev;
-+ long in_interrupt; /* Word-long for SMP locks. */
-+ int max_interrupt_work;
-+ int intr_enable;
-+ unsigned int restore_intr_enable:1; /* Set if temporarily masked. */
-+ unsigned int rx_q_empty:1; /* Set out-of-skbuffs. */
-+
-+ struct netdev_desc *rx_head_desc;
-+ unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */
-+ unsigned int rx_buf_sz; /* Based on MTU+slack. */
-+ int rx_copybreak;
-+
-+ unsigned int cur_tx, dirty_tx;
-+ unsigned int tx_full:1; /* The Tx queue is full. */
-+ /* These values keep track of the transceiver/media in use. */
-+ unsigned int full_duplex:1; /* Full-duplex operation requested. */
-+ unsigned int duplex_lock:1;
-+ unsigned int medialock:1; /* Do not sense media. */
-+ unsigned int default_port; /* Last dev->if_port value. */
-+ /* Rx filter. */
-+ u32 cur_rx_mode;
-+ u32 rx_filter[16];
-+ int multicast_filter_limit;
-+ /* FIFO and PCI burst thresholds. */
-+ int tx_config, rx_config;
-+ /* MII transceiver section. */
-+ u16 advertising; /* NWay media advertisement */
-+};
-+
-+static int eeprom_read(long ioaddr, int location);
-+static void mdio_sync(long mdio_addr);
-+static int mdio_read(struct net_device *dev, int phy_id, int location);
-+static void mdio_write(struct net_device *dev, int phy_id, int location, int value);
-+static int netdev_open(struct net_device *dev);
-+static void check_duplex(struct net_device *dev);
-+static void netdev_timer(unsigned long data);
-+static void tx_timeout(struct net_device *dev);
-+static int rx_ring_fill(struct net_device *dev);
-+static void init_ring(struct net_device *dev);
-+static int start_tx(struct sk_buff *skb, struct net_device *dev);
-+static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs);
-+static void netdev_error(struct net_device *dev, int intr_status);
-+static int netdev_rx(struct net_device *dev);
-+static void netdev_error(struct net_device *dev, int intr_status);
-+static void set_rx_mode(struct net_device *dev);
-+static struct net_device_stats *get_stats(struct net_device *dev);
-+static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-+static int netdev_close(struct net_device *dev);
-+
-+
-+
-+/* A list of our installed devices, for removing the driver module. */
-+static struct net_device *root_net_dev = NULL;
-+
-+#ifndef MODULE
-+int ns820_probe(struct net_device *dev)
-+{
-+ if (pci_drv_register(&ns820_drv_id, dev) < 0)
-+ return -ENODEV;
-+ printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2);
-+ return 0;
-+}
-+#endif
-+
-+static void *ns820_probe1(struct pci_dev *pdev, void *init_dev,
-+ long ioaddr, int irq, int chip_idx, int card_idx)
-+{
-+ struct net_device *dev;
-+ struct netdev_private *np;
-+ void *priv_mem;
-+ int i, option = card_idx < MAX_UNITS ? options[card_idx] : 0;
-+
-+ dev = init_etherdev(init_dev, 0);
-+ if (!dev)
-+ return NULL;
-+
-+ /* Perhaps NETIF_MSG_PROBE */
-+ printk(KERN_INFO "%s: %s at 0x%lx, ",
-+ dev->name, pci_id_tbl[chip_idx].name, ioaddr);
-+
-+ for (i = 0; i < 3; i++)
-+ ((u16 *)dev->dev_addr)[i] = le16_to_cpu(eeprom_read(ioaddr, 12 - i));
-+ for (i = 0; i < 5; i++)
-+ printk("%2.2x:", dev->dev_addr[i]);
-+ printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);
-+
-+ /* Reset the chip to erase previous misconfiguration. */
-+ writel(ChipReset, ioaddr + ChipCmd);
-+ /* Power up Xcvr. */
-+ writel(~CfgXcrOff & readl(ioaddr + ChipConfig), ioaddr + ChipConfig);
-+
-+ /* Make certain elements e.g. descriptor lists are aligned. */
-+ priv_mem = kmalloc(sizeof(*np) + PRIV_ALIGN, GFP_KERNEL);
-+ /* Check for the very unlikely case of no memory. */
-+ if (priv_mem == NULL)
-+ return NULL;
-+
-+ dev->base_addr = ioaddr;
-+ dev->irq = irq;
-+
-+ dev->priv = np = (void *)(((long)priv_mem + PRIV_ALIGN) & ~PRIV_ALIGN);
-+ memset(np, 0, sizeof(*np));
-+ np->priv_addr = priv_mem;
-+
-+ np->next_module = root_net_dev;
-+ root_net_dev = dev;
-+
-+ np->pci_dev = pdev;
-+ np->chip_id = chip_idx;
-+ np->drv_flags = pci_id_tbl[chip_idx].drv_flags;
-+ np->msg_level = (1 << debug) - 1;
-+ np->rx_copybreak = rx_copybreak;
-+ np->max_interrupt_work = max_interrupt_work;
-+ np->multicast_filter_limit = multicast_filter_limit;
-+
-+ if (dev->mem_start)
-+ option = dev->mem_start;
-+
-+ /* The lower four bits are the media type. */
-+ if (option > 0) {
-+ if (option & 0x220)
-+ np->full_duplex = 1;
-+ np->default_port = option & 0x33ff;
-+ if (np->default_port & 0x330)
-+ np->medialock = 1;
-+ }
-+ if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0)
-+ np->full_duplex = 1;
-+
-+ if (np->full_duplex) {
-+ if (np->msg_level & NETIF_MSG_PROBE)
-+ printk(KERN_INFO "%s: Set to forced full duplex, autonegotiation"
-+ " disabled.\n", dev->name);
-+ np->duplex_lock = 1;
-+ }
-+
-+ /* The chip-specific entries in the device structure. */
-+ dev->open = &netdev_open;
-+ dev->hard_start_xmit = &start_tx;
-+ dev->stop = &netdev_close;
-+ dev->get_stats = &get_stats;
-+ dev->set_multicast_list = &set_rx_mode;
-+ dev->do_ioctl = &mii_ioctl;
-+
-+ /* Allow forcing the media type. */
-+ if (option > 0) {
-+ if (option & 0x220)
-+ np->full_duplex = 1;
-+ np->default_port = option & 0x3ff;
-+ if (np->default_port & 0x330) {
-+ np->medialock = 1;
-+ if (np->msg_level & NETIF_MSG_PROBE)
-+ printk(KERN_INFO " Forcing %dMbs %s-duplex operation.\n",
-+ (option & 0x300 ? 100 : 10),
-+ (np->full_duplex ? "full" : "half"));
-+ mdio_write(dev, 1, 0,
-+ ((option & 0x300) ? 0x2000 : 0) | /* 100mbps? */
-+ (np->full_duplex ? 0x0100 : 0)); /* Full duplex? */
-+ }
-+ }
-+
-+ return dev;
-+}
-+
-+
-+/* Read the EEPROM and MII Management Data I/O (MDIO) interfaces.
-+ The EEPROM code is for the common 93c06/46 EEPROMs with 6 bit addresses.
-+ Update to the code in other drivers for 8/10 bit addresses.
-+*/
-+
-+/* Delay between EEPROM clock transitions.
-+ This "delay" forces out buffered PCI writes, which is sufficient to meet
-+ the timing requirements of most EEPROMs.
-+*/
-+#define eeprom_delay(ee_addr) readl(ee_addr)
-+
-+enum EEPROM_Ctrl_Bits {
-+ EE_ShiftClk=0x04, EE_DataIn=0x01, EE_ChipSelect=0x08, EE_DataOut=0x02,
-+};
-+#define EE_Write0 (EE_ChipSelect)
-+#define EE_Write1 (EE_ChipSelect | EE_DataIn)
-+
-+/* The EEPROM commands include the 01 preamble. */
-+enum EEPROM_Cmds {
-+ EE_WriteCmd=5, EE_ReadCmd=6, EE_EraseCmd=7,
-+};
-+
-+static int eeprom_read(long addr, int location)
-+{
-+ long eeprom_addr = addr + EECtrl;
-+ int read_cmd = (EE_ReadCmd << 6) | location;
-+ int retval = 0;
-+ int i;
-+
-+ writel(EE_Write0, eeprom_addr);
-+
-+ /* Shift the read command bits out. */
-+ for (i = 10; i >= 0; i--) {
-+ int dataval = (read_cmd & (1 << i)) ? EE_Write1 : EE_Write0;
-+ writel(dataval, eeprom_addr);
-+ eeprom_delay(eeprom_addr);
-+ writel(dataval | EE_ShiftClk, eeprom_addr);
-+ eeprom_delay(eeprom_addr);
-+ }
-+ writel(EE_ChipSelect, eeprom_addr);
-+ eeprom_delay(eeprom_addr);
-+
-+ for (i = 15; i >= 0; i--) {
-+ writel(EE_ChipSelect | EE_ShiftClk, eeprom_addr);
-+ eeprom_delay(eeprom_addr);
-+ retval |= (readl(eeprom_addr) & EE_DataOut) ? 1 << i : 0;
-+ writel(EE_ChipSelect, eeprom_addr);
-+ eeprom_delay(eeprom_addr);
-+ }
-+
-+ /* Terminate the EEPROM access. */
-+ writel(EE_Write0, eeprom_addr);
-+ writel(0, eeprom_addr);
-+ return retval;
-+}
-+
-+/* MII transceiver control section.
-+ Read and write MII registers using software-generated serial MDIO
-+ protocol. See the MII specifications or DP83840A data sheet for details.
-+
-+ The maximum data clock rate is 2.5 Mhz. To meet minimum timing we
-+ must flush writes to the PCI bus with a PCI read. */
-+#define mdio_delay(mdio_addr) readl(mdio_addr)
-+
-+/* Set iff a MII transceiver on any interface requires mdio preamble.
-+ This only set with older tranceivers, so the extra
-+ code size of a per-interface flag is not worthwhile. */
-+static char mii_preamble_required = 0;
-+
-+enum mii_reg_bits {
-+ MDIO_ShiftClk=0x0040, MDIO_Data=0x0010, MDIO_EnbOutput=0x0020,
-+};
-+#define MDIO_EnbIn (0)
-+#define MDIO_WRITE0 (MDIO_EnbOutput)
-+#define MDIO_WRITE1 (MDIO_Data | MDIO_EnbOutput)
-+
-+/* Generate the preamble required for initial synchronization and
-+ a few older transceivers. */
-+static void mdio_sync(long mdio_addr)
-+{
-+ int bits = 32;
-+
-+ /* Establish sync by sending at least 32 logic ones. */
-+ while (--bits >= 0) {
-+ writel(MDIO_WRITE1, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ writel(MDIO_WRITE1 | MDIO_ShiftClk, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ }
-+}
-+
-+static int mdio_read(struct net_device *dev, int phy_id, int location)
-+{
-+ long mdio_addr = dev->base_addr + EECtrl;
-+ int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;
-+ int i, retval = 0;
-+
-+ if (mii_preamble_required)
-+ mdio_sync(mdio_addr);
-+
-+ /* Shift the read command bits out. */
-+ for (i = 15; i >= 0; i--) {
-+ int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
-+
-+ writel(dataval, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ writel(dataval | MDIO_ShiftClk, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ }
-+ /* Read the two transition, 16 data, and wire-idle bits. */
-+ for (i = 19; i > 0; i--) {
-+ writel(MDIO_EnbIn, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ retval = (retval << 1) | ((readl(mdio_addr) & MDIO_Data) ? 1 : 0);
-+ writel(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ }
-+ return (retval>>1) & 0xffff;
-+}
-+
-+static void mdio_write(struct net_device *dev, int phy_id, int location, int value)
-+{
-+ long mdio_addr = dev->base_addr + EECtrl;
-+ int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;
-+ int i;
-+
-+ if (mii_preamble_required)
-+ mdio_sync(mdio_addr);
-+
-+ /* Shift the command bits out. */
-+ for (i = 31; i >= 0; i--) {
-+ int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
-+
-+ writel(dataval, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ writel(dataval | MDIO_ShiftClk, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ }
-+ /* Clear out extra bits. */
-+ for (i = 2; i > 0; i--) {
-+ writel(MDIO_EnbIn, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ writel(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ }
-+ return;
-+}
-+
-+static int netdev_open(struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+ int i;
-+ u32 intr_status = readl(ioaddr + IntrStatus);
-+
-+ /* We have not yet encountered a case where we need to reset the chip. */
-+
-+ MOD_INC_USE_COUNT;
-+
-+ if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev)) {
-+ MOD_DEC_USE_COUNT;
-+ return -EAGAIN;
-+ }
-+
-+ /* Power up Xcvr. */
-+ writel((~CfgXcrOff & readl(ioaddr + ChipConfig)) | 0x00400000,
-+ ioaddr + ChipConfig);
-+ if (np->msg_level & NETIF_MSG_IFUP)
-+ printk(KERN_DEBUG "%s: netdev_open() irq %d intr_status %8.8x.\n",
-+ dev->name, dev->irq, intr_status);
-+
-+ init_ring(dev);
-+
-+#if defined(ADDR_64BITS) && defined(__alpha__)
-+ writel(virt_to_bus(np->rx_ring) >> 32, ioaddr + RxRingPtrHi);
-+ writel(virt_to_bus(np->tx_ring) >> 32, ioaddr + TxRingPtrHi);
-+#else
-+ writel(0, ioaddr + RxRingPtrHi);
-+ writel(0, ioaddr + TxRingPtrHi);
-+#endif
-+ writel(virt_to_bus(np->rx_ring), ioaddr + RxRingPtr);
-+ writel(virt_to_bus(np->tx_ring), ioaddr + TxRingPtr);
-+
-+ for (i = 0; i < 6; i += 2) {
-+ writel(i, ioaddr + RxFilterAddr);
-+ writel(dev->dev_addr[i] + (dev->dev_addr[i+1] << 8),
-+ ioaddr + RxFilterData);
-+ }
-+
-+ /* Initialize other registers. */
-+ /* Configure the PCI bus bursts and FIFO thresholds. */
-+ /* Configure for standard, in-spec Ethernet. */
-+
-+ if (np->full_duplex ||
-+ ((readl(ioaddr + ChipConfig) & CfgFDX) == 0) ^
-+ ((np->drv_flags & FDXActiveLow) != 0)) {
-+ np->tx_config = 0xD0801002;
-+ np->rx_config = 0x10000020;
-+ } else {
-+ np->tx_config = 0x10801002;
-+ np->rx_config = 0x0020;
-+ }
-+ if (dev->mtu > 1500)
-+ np->rx_config |= 0x08000000;
-+ writel(np->tx_config, ioaddr + TxConfig);
-+ writel(np->rx_config, ioaddr + RxConfig);
-+ if (np->msg_level & NETIF_MSG_IFUP)
-+ printk(KERN_DEBUG "%s: Setting TxConfig to %8.8x.\n",
-+ dev->name, (int)readl(ioaddr + TxConfig));
-+
-+ if (dev->if_port == 0)
-+ dev->if_port = np->default_port;
-+
-+ np->in_interrupt = 0;
-+
-+ check_duplex(dev);
-+ set_rx_mode(dev);
-+ netif_start_tx_queue(dev);
-+
-+ /* Enable interrupts by setting the interrupt mask. */
-+ np->intr_enable = IntrNormalSummary | IntrAbnormalSummary | 0x1f;
-+ writel(np->intr_enable, ioaddr + IntrMask);
-+ writel(1, ioaddr + IntrEnable);
-+
-+ writel(RxOn | TxOn, ioaddr + ChipCmd);
-+ writel(4, ioaddr + StatsCtrl); /* Clear Stats */
-+
-+ if (np->msg_level & NETIF_MSG_IFUP)
-+ printk(KERN_DEBUG "%s: Done netdev_open(), status: %x.\n",
-+ dev->name, (int)readl(ioaddr + ChipCmd));
-+
-+ /* Set the timer to check for link beat. */
-+ init_timer(&np->timer);
-+ np->timer.expires = jiffies + 3*HZ;
-+ np->timer.data = (unsigned long)dev;
-+ np->timer.function = &netdev_timer; /* timer handler */
-+ add_timer(&np->timer);
-+
-+ return 0;
-+}
-+
-+static void check_duplex(struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+ int duplex;
-+
-+ if (np->duplex_lock)
-+ return;
-+ duplex = readl(ioaddr + ChipConfig) & CfgFDX ? 1 : 0;
-+ if (np->full_duplex != duplex) {
-+ np->full_duplex = duplex;
-+ if (np->msg_level & NETIF_MSG_LINK)
-+ printk(KERN_INFO "%s: Setting %s-duplex based on negotiated link"
-+ " capability.\n", dev->name,
-+ duplex ? "full" : "half");
-+ if (duplex) {
-+ np->rx_config |= 0x10000000;
-+ np->tx_config |= 0xC0000000;
-+ } else {
-+ np->rx_config &= ~0x10000000;
-+ np->tx_config &= ~0xC0000000;
-+ }
-+ writel(np->tx_config, ioaddr + TxConfig);
-+ writel(np->rx_config, ioaddr + RxConfig);
-+ if (np->msg_level & NETIF_MSG_LINK)
-+ printk(KERN_DEBUG "%s: Setting TxConfig to %8.8x (%8.8x).\n",
-+ dev->name, np->tx_config, (int)readl(ioaddr + TxConfig));
-+ }
-+}
-+
-+static void netdev_timer(unsigned long data)
-+{
-+ struct net_device *dev = (struct net_device *)data;
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+ int next_tick = 10*HZ;
-+
-+ if (np->msg_level & NETIF_MSG_TIMER)
-+ printk(KERN_DEBUG "%s: Driver monitor timer tick, status %8.8x.\n",
-+ dev->name, (int)readl(ioaddr + ChipConfig));
-+ if (np->rx_q_empty) {
-+ /* Trigger an interrupt to refill. */
-+ writel(SoftIntr, ioaddr + ChipCmd);
-+ }
-+ if (netif_queue_paused(dev) &&
-+ np->cur_tx - np->dirty_tx > 1 &&
-+ (jiffies - dev->trans_start) > TX_TIMEOUT) {
-+ tx_timeout(dev);
-+ }
-+ check_duplex(dev);
-+ np->timer.expires = jiffies + next_tick;
-+ add_timer(&np->timer);
-+}
-+
-+static void tx_timeout(struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+
-+ printk(KERN_WARNING "%s: Transmit timed out, status %8.8x,"
-+ " resetting...\n", dev->name, (int)readl(ioaddr + TxRingPtr));
-+
-+ if (np->msg_level & NETIF_MSG_TX_ERR) {
-+ int i;
-+ printk(KERN_DEBUG " Rx ring %p: ", np->rx_ring);
-+ for (i = 0; i < RX_RING_SIZE; i++)
-+ printk(" %8.8x", (unsigned int)np->rx_ring[i].cmd_status);
-+ printk("\n"KERN_DEBUG" Tx ring %p: ", np->tx_ring);
-+ for (i = 0; i < TX_RING_SIZE; i++)
-+ printk(" %4.4x", np->tx_ring[i].cmd_status);
-+ printk("\n");
-+ }
-+
-+ /* Perhaps we should reinitialize the hardware here. */
-+ dev->if_port = 0;
-+ /* Stop and restart the chip's Tx processes . */
-+
-+ /* Trigger an immediate transmit demand. */
-+
-+ dev->trans_start = jiffies;
-+ np->stats.tx_errors++;
-+ return;
-+}
-+
-+/* Refill the Rx ring buffers, returning non-zero if not full. */
-+static int rx_ring_fill(struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ unsigned int entry;
-+
-+ for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) {
-+ entry = np->dirty_rx % RX_RING_SIZE;
-+ if (np->rx_skbuff[entry] == NULL) {
-+ struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz);
-+ np->rx_skbuff[entry] = skb;
-+ if (skb == NULL)
-+ return 1; /* Better luck next time. */
-+ skb->dev = dev; /* Mark as being used by this device. */
-+ np->rx_ring[entry].buf_addr = virt_to_bus(skb->tail);
-+ }
-+ np->rx_ring[entry].cmd_status = cpu_to_le32(DescIntr | np->rx_buf_sz);
-+ }
-+ return 0;
-+}
-+
-+/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
-+static void init_ring(struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ int i;
-+
-+ np->tx_full = 0;
-+ np->cur_rx = np->cur_tx = 0;
-+ np->dirty_rx = np->dirty_tx = 0;
-+
-+ /* MAX(PKT_BUF_SZ, dev->mtu + 8); */
-+ /* I know you _want_ to change this without understanding it. Don't. */
-+ np->rx_buf_sz = (dev->mtu <= 1532 ? PKT_BUF_SZ : dev->mtu + 8);
-+ np->rx_head_desc = &np->rx_ring[0];
-+
-+ /* Initialize all Rx descriptors. */
-+ for (i = 0; i < RX_RING_SIZE; i++) {
-+ np->rx_ring[i].next_desc = virt_to_bus(&np->rx_ring[i+1]);
-+ np->rx_ring[i].cmd_status = cpu_to_le32(DescOwn);
-+ np->rx_skbuff[i] = 0;
-+ }
-+ /* Mark the last entry as wrapping the ring. */
-+ np->rx_ring[i-1].next_desc = virt_to_bus(&np->rx_ring[0]);
-+
-+ for (i = 0; i < TX_RING_SIZE; i++) {
-+ np->tx_skbuff[i] = 0;
-+ np->tx_ring[i].next_desc = virt_to_bus(&np->tx_ring[i+1]);
-+ np->tx_ring[i].cmd_status = 0;
-+ }
-+ np->tx_ring[i-1].next_desc = virt_to_bus(&np->tx_ring[0]);
-+
-+ /* Fill in the Rx buffers.
-+ Allocation failure just leaves a "negative" np->dirty_rx. */
-+ np->dirty_rx = (unsigned int)(0 - RX_RING_SIZE);
-+ rx_ring_fill(dev);
-+
-+ return;
-+}
-+
-+static int start_tx(struct sk_buff *skb, struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ unsigned int entry;
-+
-+ /* Block a timer-based transmit from overlapping. This happens when
-+ packets are presumed lost, and we use this check the Tx status. */
-+ if (netif_pause_tx_queue(dev) != 0) {
-+ /* This watchdog code is redundant with the media monitor timer. */
-+ if (jiffies - dev->trans_start > TX_TIMEOUT)
-+ tx_timeout(dev);
-+ return 1;
-+ }
-+
-+ /* Note: Ordering is important here, set the field with the
-+ "ownership" bit last, and only then increment cur_tx.
-+ No spinlock is needed for either Tx or Rx.
-+ */
-+
-+ /* Calculate the next Tx descriptor entry. */
-+ entry = np->cur_tx % TX_RING_SIZE;
-+
-+ np->tx_skbuff[entry] = skb;
-+
-+ np->tx_ring[entry].buf_addr = virt_to_bus(skb->data);
-+ np->tx_ring[entry].cmd_status = cpu_to_le32(DescOwn|DescIntr | skb->len);
-+ np->cur_tx++;
-+
-+ /* StrongARM: Explicitly cache flush np->tx_ring and skb->data,skb->len. */
-+
-+ if (np->cur_tx - np->dirty_tx >= TX_QUEUE_LEN - 1) {
-+ np->tx_full = 1;
-+ /* Check for a just-cleared queue. */
-+ if (np->cur_tx - (volatile unsigned int)np->dirty_tx
-+ < TX_QUEUE_LEN - 4) {
-+ np->tx_full = 0;
-+ netif_unpause_tx_queue(dev);
-+ } else
-+ netif_stop_tx_queue(dev);
-+ } else
-+ netif_unpause_tx_queue(dev); /* Typical path */
-+ /* Wake the potentially-idle transmit channel. */
-+ writel(TxOn, dev->base_addr + ChipCmd);
-+
-+ dev->trans_start = jiffies;
-+
-+ if (np->msg_level & NETIF_MSG_TX_QUEUED) {
-+ printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n",
-+ dev->name, np->cur_tx, entry);
-+ }
-+ return 0;
-+}
-+
-+/* The interrupt handler does all of the Rx thread work and cleans up
-+ after the Tx thread. */
-+static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
-+{
-+ struct net_device *dev = (struct net_device *)dev_instance;
-+ struct netdev_private *np;
-+ long ioaddr;
-+ int boguscnt;
-+
-+#ifndef final_version /* Can never occur. */
-+ if (dev == NULL) {
-+ printk (KERN_ERR "Netdev interrupt handler(): IRQ %d for unknown "
-+ "device.\n", irq);
-+ return;
-+ }
-+#endif
-+
-+ ioaddr = dev->base_addr;
-+ np = (struct netdev_private *)dev->priv;
-+ boguscnt = np->max_interrupt_work;
-+
-+#if defined(__i386__) && LINUX_VERSION_CODE < 0x020300
-+ /* A lock to prevent simultaneous entry bug on Intel SMP machines. */
-+ if (test_and_set_bit(0, (void*)&dev->interrupt)) {
-+ printk(KERN_ERR"%s: SMP simultaneous entry of an interrupt handler.\n",
-+ dev->name);
-+ dev->interrupt = 0; /* Avoid halting machine. */
-+ return;
-+ }
-+#endif
-+
-+ do {
-+ u32 intr_status = readl(ioaddr + IntrStatus);
-+
-+ if (np->msg_level & NETIF_MSG_INTR)
-+ printk(KERN_DEBUG "%s: Interrupt, status %8.8x.\n",
-+ dev->name, intr_status);
-+
-+ if (intr_status == 0 || intr_status == 0xffffffff)
-+ break;
-+
-+ /* Acknowledge all of the current interrupt sources ASAP.
-+ Nominally the read above accomplishes this, but... */
-+ writel(intr_status & 0x001ffff, ioaddr + IntrStatus);
-+
-+ if (intr_status & (IntrRxDone | IntrRxIntr)) {
-+ netdev_rx(dev);
-+ np->rx_q_empty = rx_ring_fill(dev);
-+ }
-+
-+ if (intr_status & (IntrRxIdle | IntrDrv)) {
-+ unsigned int old_dirty_rx = np->dirty_rx;
-+ if (rx_ring_fill(dev) == 0)
-+ np->rx_q_empty = 0;
-+ /* Restart Rx engine iff we did add a buffer. */
-+ if (np->dirty_rx != old_dirty_rx)
-+ writel(RxOn, dev->base_addr + ChipCmd);
-+ }
-+
-+ for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) {
-+ int entry = np->dirty_tx % TX_RING_SIZE;
-+ if (np->msg_level & NETIF_MSG_INTR)
-+ printk(KERN_DEBUG "%s: Tx entry %d @%p status %8.8x.\n",
-+ dev->name, entry, &np->tx_ring[entry],
-+ np->tx_ring[entry].cmd_status);
-+ if (np->tx_ring[entry].cmd_status & cpu_to_le32(DescOwn))
-+ break;
-+ if (np->tx_ring[entry].cmd_status & cpu_to_le32(0x08000000)) {
-+ if (np->msg_level & NETIF_MSG_TX_DONE)
-+ printk(KERN_DEBUG "%s: Transmit done, Tx status %8.8x.\n",
-+ dev->name, np->tx_ring[entry].cmd_status);
-+ np->stats.tx_packets++;
-+#if LINUX_VERSION_CODE > 0x20127
-+ np->stats.tx_bytes += np->tx_skbuff[entry]->len;
-+#endif
-+ } else { /* Various Tx errors */
-+ int tx_status = le32_to_cpu(np->tx_ring[entry].cmd_status);
-+ if (tx_status & 0x04010000) np->stats.tx_aborted_errors++;
-+ if (tx_status & 0x02000000) np->stats.tx_fifo_errors++;
-+ if (tx_status & 0x01000000) np->stats.tx_carrier_errors++;
-+ if (tx_status & 0x00200000) np->stats.tx_window_errors++;
-+ if (np->msg_level & NETIF_MSG_TX_ERR)
-+ printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",
-+ dev->name, tx_status);
-+ np->stats.tx_errors++;
-+ }
-+ /* Free the original skb. */
-+ dev_free_skb_irq(np->tx_skbuff[entry]);
-+ np->tx_skbuff[entry] = 0;
-+ }
-+ /* Note the 4 slot hysteresis to mark the queue non-full. */
-+ if (np->tx_full
-+ && np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 4) {
-+ /* The ring is no longer full, allow new TX entries. */
-+ np->tx_full = 0;
-+ netif_resume_tx_queue(dev);
-+ }
-+
-+ /* Abnormal error summary/uncommon events handlers. */
-+ if (intr_status & IntrAbnormalSummary)
-+ netdev_error(dev, intr_status);
-+
-+ if (--boguscnt < 0) {
-+ printk(KERN_WARNING "%s: Too much work at interrupt, "
-+ "status=0x%4.4x.\n",
-+ dev->name, intr_status);
-+ np->restore_intr_enable = 1;
-+ break;
-+ }
-+ } while (1);
-+
-+ if (np->msg_level & NETIF_MSG_INTR)
-+ printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
-+ dev->name, (int)readl(ioaddr + IntrStatus));
-+
-+#if defined(__i386__) && LINUX_VERSION_CODE < 0x020300
-+ clear_bit(0, (void*)&dev->interrupt);
-+#endif
-+ return;
-+}
-+
-+/* This routine is logically part of the interrupt handler, but separated
-+ for clarity and better register allocation. */
-+static int netdev_rx(struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ int entry = np->cur_rx % RX_RING_SIZE;
-+ int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx;
-+ s32 desc_status = le32_to_cpu(np->rx_head_desc->cmd_status);
-+
-+ /* If the driver owns the next entry it's a new packet. Send it up. */
-+ while (desc_status < 0) { /* e.g. & DescOwn */
-+ if (np->msg_level & NETIF_MSG_RX_STATUS)
-+ printk(KERN_DEBUG " In netdev_rx() entry %d status was %8.8x.\n",
-+ entry, desc_status);
-+ if (--boguscnt < 0)
-+ break;
-+ if ((desc_status & (DescMore|DescPktOK|RxTooLong)) != DescPktOK) {
-+ if (desc_status & DescMore) {
-+ printk(KERN_WARNING "%s: Oversized(?) Ethernet frame spanned "
-+ "multiple buffers, entry %#x status %x.\n",
-+ dev->name, np->cur_rx, desc_status);
-+ np->stats.rx_length_errors++;
-+ } else {
-+ /* There was a error. */
-+ if (np->msg_level & NETIF_MSG_RX_ERR)
-+ printk(KERN_DEBUG " netdev_rx() Rx error was %8.8x.\n",
-+ desc_status);
-+ np->stats.rx_errors++;
-+ if (desc_status & 0x06000000) np->stats.rx_over_errors++;
-+ if (desc_status & 0x00600000) np->stats.rx_length_errors++;
-+ if (desc_status & 0x00140000) np->stats.rx_frame_errors++;
-+ if (desc_status & 0x00080000) np->stats.rx_crc_errors++;
-+ }
-+ } else {
-+ struct sk_buff *skb;
-+ int pkt_len = (desc_status & 0x0fff) - 4; /* Omit CRC size. */
-+ /* Check if the packet is long enough to accept without copying
-+ to a minimally-sized skbuff. */
-+ if (pkt_len < np->rx_copybreak
-+ && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
-+ skb->dev = dev;
-+ skb_reserve(skb, 2); /* 16 byte align the IP header */
-+#if HAS_IP_COPYSUM
-+ eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0);
-+ skb_put(skb, pkt_len);
-+#else
-+ memcpy(skb_put(skb, pkt_len), np->rx_skbuff[entry]->tail,
-+ pkt_len);
-+#endif
-+ } else {
-+ skb_put(skb = np->rx_skbuff[entry], pkt_len);
-+ np->rx_skbuff[entry] = NULL;
-+ }
-+#ifndef final_version /* Remove after testing. */
-+ /* You will want this info for the initial debug. */
-+ if (np->msg_level & NETIF_MSG_PKTDATA)
-+ printk(KERN_DEBUG " Rx data %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:"
-+ "%2.2x %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x %2.2x%2.2x "
-+ "%d.%d.%d.%d.\n",
-+ skb->data[0], skb->data[1], skb->data[2], skb->data[3],
-+ skb->data[4], skb->data[5], skb->data[6], skb->data[7],
-+ skb->data[8], skb->data[9], skb->data[10],
-+ skb->data[11], skb->data[12], skb->data[13],
-+ skb->data[14], skb->data[15], skb->data[16],
-+ skb->data[17]);
-+#endif
-+ skb->protocol = eth_type_trans(skb, dev);
-+ /* W/ hardware checksum: skb->ip_summed = CHECKSUM_UNNECESSARY; */
-+ netif_rx(skb);
-+ dev->last_rx = jiffies;
-+ np->stats.rx_packets++;
-+#if LINUX_VERSION_CODE > 0x20127
-+ np->stats.rx_bytes += pkt_len;
-+#endif
-+ }
-+ entry = (++np->cur_rx) % RX_RING_SIZE;
-+ np->rx_head_desc = &np->rx_ring[entry];
-+ desc_status = le32_to_cpu(np->rx_head_desc->cmd_status);
-+ }
-+
-+ /* Refill is now done in the main interrupt loop. */
-+ return 0;
-+}
-+
-+static void netdev_error(struct net_device *dev, int intr_status)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+
-+ if (intr_status & LinkChange) {
-+ int chip_config = readl(ioaddr + ChipConfig);
-+ if (np->msg_level & NETIF_MSG_LINK)
-+ printk(KERN_NOTICE "%s: Link changed: Autonegotiation advertising"
-+ " %4.4x partner %4.4x.\n", dev->name,
-+ (int)readl(ioaddr + 0x90), (int)readl(ioaddr + 0x94));
-+ if (chip_config & CfgLinkGood)
-+ netif_link_up(dev);
-+ else
-+ netif_link_down(dev);
-+ check_duplex(dev);
-+ }
-+ if (intr_status & StatsMax) {
-+ get_stats(dev);
-+ }
-+ if (intr_status & IntrTxUnderrun) {
-+ /* Increase the Tx threshold, 32 byte units. */
-+ if ((np->tx_config & 0x3f) < 62)
-+ np->tx_config += 2; /* +64 bytes */
-+ writel(np->tx_config, ioaddr + TxConfig);
-+ }
-+ if (intr_status & WOLPkt) {
-+ int wol_status = readl(ioaddr + WOLCmd);
-+ printk(KERN_NOTICE "%s: Link wake-up event %8.8x",
-+ dev->name, wol_status);
-+ }
-+ if (intr_status & (RxStatusOverrun | IntrRxOverrun)) {
-+ if (np->msg_level & NETIF_MSG_DRV)
-+ printk(KERN_ERR "%s: Rx overflow! ns820 %8.8x.\n",
-+ dev->name, intr_status);
-+ np->stats.rx_fifo_errors++;
-+ }
-+ if (intr_status & ~(LinkChange|StatsMax|RxResetDone|TxResetDone|
-+ RxStatusOverrun|0xA7ff)) {
-+ if (np->msg_level & NETIF_MSG_DRV)
-+ printk(KERN_ERR "%s: Something Wicked happened! ns820 %8.8x.\n",
-+ dev->name, intr_status);
-+ }
-+ /* Hmmmmm, it's not clear how to recover from PCI faults. */
-+ if (intr_status & IntrPCIErr) {
-+ np->stats.tx_fifo_errors++;
-+ np->stats.rx_fifo_errors++;
-+ }
-+}
-+
-+static struct net_device_stats *get_stats(struct net_device *dev)
-+{
-+ long ioaddr = dev->base_addr;
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ int crc_errs = readl(ioaddr + RxCRCErrs);
-+
-+ if (crc_errs != 0xffffffff) {
-+ /* We need not lock this segment of code for SMP.
-+ There is no atomic-add vulnerability for most CPUs,
-+ and statistics are non-critical. */
-+ /* The chip only need report frame silently dropped. */
-+ np->stats.rx_crc_errors += crc_errs;
-+ np->stats.rx_missed_errors += readl(ioaddr + RxMissed);
-+ }
-+
-+ return &np->stats;
-+}
-+
-+/* The little-endian AUTODIN II ethernet CRC calculations.
-+ A big-endian version is also available.
-+ This is slow but compact code. Do not use this routine for bulk data,
-+ use a table-based routine instead.
-+ This is common code and should be moved to net/core/crc.c.
-+ Chips may use the upper or lower CRC bits, and may reverse and/or invert
-+ them. Select the endian-ness that results in minimal calculations.
-+*/
-+static unsigned const ethernet_polynomial_le = 0xedb88320U;
-+static inline unsigned ether_crc_le(int length, unsigned char *data)
-+{
-+ unsigned int crc = 0xffffffff; /* Initial value. */
-+ while(--length >= 0) {
-+ unsigned char current_octet = *data++;
-+ int bit;
-+ for (bit = 8; --bit >= 0; current_octet >>= 1) {
-+ if ((crc ^ current_octet) & 1) {
-+ crc >>= 1;
-+ crc ^= ethernet_polynomial_le;
-+ } else
-+ crc >>= 1;
-+ }
-+ }
-+ return crc;
-+}
-+
-+static void set_rx_mode(struct net_device *dev)
-+{
-+ long ioaddr = dev->base_addr;
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ u8 mc_filter[64]; /* Multicast hash filter */
-+ u32 rx_mode;
-+
-+ if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
-+ /* Unconditionally log net taps. */
-+ printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);
-+ rx_mode = AcceptBroadcast | AcceptAllMulticast | AcceptAllPhys
-+ | AcceptMyPhys;
-+ } else if ((dev->mc_count > np->multicast_filter_limit)
-+ || (dev->flags & IFF_ALLMULTI)) {
-+ rx_mode = AcceptBroadcast | AcceptAllMulticast | AcceptMyPhys;
-+ } else {
-+ struct dev_mc_list *mclist;
-+ int i;
-+ memset(mc_filter, 0, sizeof(mc_filter));
-+ for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
-+ i++, mclist = mclist->next) {
-+ set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x7ff,
-+ mc_filter);
-+ }
-+ rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
-+ for (i = 0; i < 64; i += 2) {
-+ writel(rx_mode + 0x200 + i, ioaddr + RxFilterAddr);
-+ writel((mc_filter[i+1]<<8) + mc_filter[i], ioaddr + RxFilterData);
-+ }
-+ }
-+ writel(rx_mode, ioaddr + RxFilterAddr);
-+ np->cur_rx_mode = rx_mode;
-+}
-+
-+static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ u16 *data = (u16 *)&rq->ifr_data;
-+ u32 *data32 = (void *)&rq->ifr_data;
-+
-+ switch(cmd) {
-+ case 0x8947: case 0x89F0:
-+ /* SIOCGMIIPHY: Get the address of the PHY in use. */
-+ data[0] = 1;
-+ /* Fall Through */
-+ case 0x8948: case 0x89F1:
-+ /* SIOCGMIIREG: Read the specified MII register. */
-+ data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f);
-+ return 0;
-+ case 0x8949: case 0x89F2:
-+ /* SIOCSMIIREG: Write the specified MII register */
-+ if (!capable(CAP_NET_ADMIN))
-+ return -EPERM;
-+ if (data[0] == 1) {
-+ u16 miireg = data[1] & 0x1f;
-+ u16 value = data[2];
-+ switch (miireg) {
-+ case 0:
-+ /* Check for autonegotiation on or reset. */
-+ np->duplex_lock = (value & 0x9000) ? 0 : 1;
-+ if (np->duplex_lock)
-+ np->full_duplex = (value & 0x0100) ? 1 : 0;
-+ break;
-+ case 4: np->advertising = value; break;
-+ }
-+ }
-+ mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]);
-+ return 0;
-+ case SIOCGPARAMS:
-+ data32[0] = np->msg_level;
-+ data32[1] = np->multicast_filter_limit;
-+ data32[2] = np->max_interrupt_work;
-+ data32[3] = np->rx_copybreak;
-+ return 0;
-+ case SIOCSPARAMS:
-+ if (!capable(CAP_NET_ADMIN))
-+ return -EPERM;
-+ np->msg_level = data32[0];
-+ np->multicast_filter_limit = data32[1];
-+ np->max_interrupt_work = data32[2];
-+ np->rx_copybreak = data32[3];
-+ return 0;
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+}
-+
-+static int netdev_close(struct net_device *dev)
-+{
-+ long ioaddr = dev->base_addr;
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ int i;
-+
-+ netif_stop_tx_queue(dev);
-+
-+ if (np->msg_level & NETIF_MSG_IFDOWN) {
-+ printk(KERN_DEBUG "%s: Shutting down ethercard, status was %4.4x "
-+ "Int %2.2x.\n",
-+ dev->name, (int)readl(ioaddr + ChipCmd),
-+ (int)readl(ioaddr + IntrStatus));
-+ printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d, Rx %d / %d.\n",
-+ dev->name, np->cur_tx, np->dirty_tx, np->cur_rx, np->dirty_rx);
-+ }
-+
-+ /* We don't want the timer to re-start anything. */
-+ del_timer(&np->timer);
-+
-+ /* Disable interrupts using the mask. */
-+ writel(0, ioaddr + IntrMask);
-+ writel(0, ioaddr + IntrEnable);
-+ writel(2, ioaddr + StatsCtrl); /* Freeze Stats */
-+
-+ /* Stop the chip's Tx and Rx processes. */
-+ writel(RxOff | TxOff, ioaddr + ChipCmd);
-+
-+ get_stats(dev);
-+
-+#ifdef __i386__
-+ if (np->msg_level & NETIF_MSG_IFDOWN) {
-+ printk("\n"KERN_DEBUG" Tx ring at %8.8x:\n",
-+ (int)virt_to_bus(np->tx_ring));
-+ for (i = 0; i < TX_RING_SIZE; i++)
-+ printk(" #%d desc. %8.8x %8.8x.\n",
-+ i, np->tx_ring[i].cmd_status, (u32)np->tx_ring[i].buf_addr);
-+ printk("\n"KERN_DEBUG " Rx ring %8.8x:\n",
-+ (int)virt_to_bus(np->rx_ring));
-+ for (i = 0; i < RX_RING_SIZE; i++) {
-+ printk(KERN_DEBUG " #%d desc. %8.8x %8.8x\n",
-+ i, np->rx_ring[i].cmd_status, (u32)np->rx_ring[i].buf_addr);
-+ }
-+ }
-+#endif /* __i386__ debugging only */
-+
-+ free_irq(dev->irq, dev);
-+
-+ /* Free all the skbuffs in the Rx queue. */
-+ for (i = 0; i < RX_RING_SIZE; i++) {
-+ np->rx_ring[i].cmd_status = 0;
-+ np->rx_ring[i].buf_addr = 0xBADF00D0; /* An invalid address. */
-+ if (np->rx_skbuff[i]) {
-+#if LINUX_VERSION_CODE < 0x20100
-+ np->rx_skbuff[i]->free = 1;
-+#endif
-+ dev_free_skb(np->rx_skbuff[i]);
-+ }
-+ np->rx_skbuff[i] = 0;
-+ }
-+ for (i = 0; i < TX_RING_SIZE; i++) {
-+ if (np->tx_skbuff[i])
-+ dev_free_skb(np->tx_skbuff[i]);
-+ np->tx_skbuff[i] = 0;
-+ }
-+
-+ /* Power down Xcvr. */
-+ writel(CfgXcrOff | readl(ioaddr + ChipConfig), ioaddr + ChipConfig);
-+
-+ MOD_DEC_USE_COUNT;
-+
-+ return 0;
-+}
-+
-+static int power_event(void *dev_instance, int event)
-+{
-+ struct net_device *dev = dev_instance;
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+
-+ if (np->msg_level & NETIF_MSG_LINK)
-+ printk(KERN_DEBUG "%s: Handling power event %d.\n", dev->name, event);
-+ switch(event) {
-+ case DRV_ATTACH:
-+ MOD_INC_USE_COUNT;
-+ break;
-+ case DRV_SUSPEND:
-+ /* Disable interrupts, freeze stats, stop Tx and Rx. */
-+ writel(0, ioaddr + IntrEnable);
-+ writel(2, ioaddr + StatsCtrl);
-+ writel(RxOff | TxOff, ioaddr + ChipCmd);
-+ writel(CfgXcrOff | readl(ioaddr + ChipConfig), ioaddr + ChipConfig);
-+ break;
-+ case DRV_RESUME:
-+ /* This is incomplete: the open() actions should be repeated. */
-+ writel(~CfgXcrOff & readl(ioaddr + ChipConfig), ioaddr + ChipConfig);
-+ set_rx_mode(dev);
-+ writel(np->intr_enable, ioaddr + IntrEnable);
-+ writel(1, ioaddr + IntrEnable);
-+ writel(RxOn | TxOn, ioaddr + ChipCmd);
-+ break;
-+ case DRV_DETACH: {
-+ struct net_device **devp, **next;
-+ if (dev->flags & IFF_UP) {
-+ /* Some, but not all, kernel versions close automatically. */
-+ dev_close(dev);
-+ dev->flags &= ~(IFF_UP|IFF_RUNNING);
-+ }
-+ unregister_netdev(dev);
-+ release_region(dev->base_addr, pci_id_tbl[np->chip_id].io_size);
-+ for (devp = &root_net_dev; *devp; devp = next) {
-+ next = &((struct netdev_private *)(*devp)->priv)->next_module;
-+ if (*devp == dev) {
-+ *devp = *next;
-+ break;
-+ }
-+ }
-+ if (np->priv_addr)
-+ kfree(np->priv_addr);
-+ kfree(dev);
-+ MOD_DEC_USE_COUNT;
-+ break;
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+
-+#ifdef MODULE
-+int init_module(void)
-+{
-+ /* Emit version even if no cards detected. */
-+ printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2);
-+#ifdef CARDBUS
-+ register_driver(&etherdev_ops);
-+ return 0;
-+#else
-+ return pci_drv_register(&ns820_drv_id, NULL);
-+#endif
-+}
-+
-+void cleanup_module(void)
-+{
-+ struct net_device *next_dev;
-+
-+#ifdef CARDBUS
-+ unregister_driver(&etherdev_ops);
-+#else
-+ pci_drv_unregister(&ns820_drv_id);
-+#endif
-+
-+ /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
-+ while (root_net_dev) {
-+ struct netdev_private *np = (void *)(root_net_dev->priv);
-+ unregister_netdev(root_net_dev);
-+ iounmap((char *)root_net_dev->base_addr);
-+ next_dev = np->next_module;
-+ if (np->priv_addr)
-+ kfree(np->priv_addr);
-+ kfree(root_net_dev);
-+ root_net_dev = next_dev;
-+ }
-+}
-+
-+#endif /* MODULE */
-+
-+/*
-+ * Local variables:
-+ * compile-command: "make KERNVER=`uname -r` ns820.o"
-+ * compile-cmd: "gcc -DMODULE -Wall -Wstrict-prototypes -O6 -c ns820.c"
-+ * simple-compile-command: "gcc -DMODULE -O6 -c ns820.c"
-+ * c-indent-level: 4
-+ * c-basic-offset: 4
-+ * tab-width: 4
-+ * End:
-+ */
-Index: linux/src/drivers/net/pci-scan.c
-===================================================================
-RCS file: linux/src/drivers/net/pci-scan.c
-diff -N linux/src/drivers/net/pci-scan.c
---- /dev/null 1 Jan 1970 00:00:00 -0000
-+++ linux/src/drivers/net/pci-scan.c 20 Aug 2004 10:32:54 -0000
-@@ -0,0 +1,659 @@
-+/* pci-scan.c: Linux PCI network adapter support code. */
-+/*
-+ Originally written 1999-2003 by Donald Becker.
-+
-+ This software may be used and distributed according to the terms
-+ of the GNU General Public License (GPL), incorporated herein by
-+ reference. Drivers interacting with these functions are derivative
-+ works and thus also must be licensed under the GPL and include an explicit
-+ GPL notice.
-+
-+ This code provides common scan and activate functions for PCI network
-+ interfaces.
-+
-+ The author may be reached as becker@scyld.com, or
-+ Donald Becker
-+ Scyld Computing Corporation
-+ 914 Bay Ridge Road, Suite 220
-+ Annapolis MD 21403
-+
-+ Other contributers:
-+*/
-+static const char version[] =
-+"pci-scan.c:v1.12 7/30/2003 Donald Becker <becker@scyld.com>"
-+" http://www.scyld.com/linux/drivers.html\n";
-+
-+/* A few user-configurable values that may be modified when a module. */
-+
-+static int msg_level = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */
-+static int min_pci_latency = 32;
-+
-+#if ! defined(__KERNEL__)
-+#define __KERNEL__ 1
-+#endif
-+#if !defined(__OPTIMIZE__)
-+#warning You must compile this file with the correct options!
-+#warning See the last lines of the source file.
-+#error You must compile this driver with the proper options, including "-O".
-+#endif
-+
-+#if defined(MODULE) && ! defined(EXPORT_SYMTAB)
-+#define EXPORT_SYMTAB
-+#endif
-+
-+#include <linux/config.h>
-+#if defined(CONFIG_SMP) && ! defined(__SMP__)
-+#define __SMP__
-+#endif
-+#if defined(MODULE) && defined(CONFIG_MODVERSIONS) && ! defined(MODVERSIONS)
-+#define MODVERSIONS
-+#endif
-+
-+#include <linux/version.h>
-+#if defined(MODVERSIONS)
-+#include <linux/modversions.h>
-+#endif
-+#if LINUX_VERSION_CODE < 0x20500 && defined(MODVERSIONS)
-+/* Another interface semantics screw-up. */
-+#include <linux/module.h>
-+#include <linux/modversions.h>
-+#else
-+#include <linux/module.h>
-+#endif
-+
-+#include <linux/kernel.h>
-+#include <linux/mm.h>
-+#include <linux/errno.h>
-+#include <linux/types.h>
-+#include <linux/pci.h>
-+#include <linux/ioport.h>
-+#if LINUX_VERSION_CODE >= 0x20300
-+/* Bogus change in the middle of a "stable" kernel series.
-+ Also, in 2.4.7+ slab must come before interrupt.h to avoid breakage. */
-+#include <linux/slab.h>
-+#else
-+#include <linux/malloc.h>
-+#endif
-+#include <asm/io.h>
-+#include "pci-scan.h"
-+#include "kern_compat.h"
-+#if defined(CONFIG_APM) && LINUX_VERSION_CODE < 0x20400
-+#include <linux/apm_bios.h>
-+#endif
-+#ifdef CONFIG_PM
-+/* New in 2.4 kernels, pointlessly incompatible with earlier APM. */
-+#include <linux/pm.h>
-+#endif
-+
-+#if (LINUX_VERSION_CODE >= 0x20100) && defined(MODULE)
-+char kernel_version[] = UTS_RELEASE;
-+#endif
-+#if (LINUX_VERSION_CODE < 0x20100)
-+#define PCI_CAPABILITY_LIST 0x34 /* Offset of first capability list entry */
-+#define PCI_STATUS_CAP_LIST 0x10 /* Support Capability List */
-+#define PCI_CAP_ID_PM 0x01 /* Power Management */
-+#endif
-+
-+int (*register_hotswap_hook)(struct drv_id_info *did);
-+void (*unregister_hotswap_hook)(struct drv_id_info *did);
-+
-+#if LINUX_VERSION_CODE > 0x20118 && defined(MODULE)
-+MODULE_LICENSE("GPL");
-+MODULE_PARM(msg_level, "i");
-+MODULE_PARM(min_pci_latency, "i");
-+MODULE_PARM_DESC(msg_level, "Enable additional status messages (0-7)");
-+MODULE_PARM_DESC(min_pci_latency,
-+ "Minimum value for the PCI Latency Timer settings");
-+#if defined(EXPORT_SYMTAB)
-+EXPORT_SYMBOL_NOVERS(pci_drv_register);
-+EXPORT_SYMBOL_NOVERS(pci_drv_unregister);
-+EXPORT_SYMBOL_NOVERS(acpi_wake);
-+EXPORT_SYMBOL_NOVERS(acpi_set_pwr_state);
-+EXPORT_SYMBOL_NOVERS(register_hotswap_hook);
-+EXPORT_SYMBOL_NOVERS(unregister_hotswap_hook);
-+#endif
-+#endif
-+
-+/* List of registered drivers. */
-+static struct drv_id_info *drv_list;
-+/* List of detected PCI devices, for APM events. */
-+static struct dev_info {
-+ struct dev_info *next;
-+ void *dev;
-+ struct drv_id_info *drv_id;
-+ int flags;
-+} *dev_list;
-+
-+/*
-+ This code is not intended to support every configuration.
-+ It is intended to minimize duplicated code by providing the functions
-+ needed in almost every PCI driver.
-+
-+ The "no kitchen sink" policy:
-+ Additional features and code will be added to this module only if more
-+ than half of the drivers for common hardware would benefit from the feature.
-+*/
-+
-+/*
-+ Ideally we would detect and number all cards of a type (e.g. network) in
-+ PCI slot order.
-+ But that does not work with hot-swap card, CardBus cards and added drivers.
-+ So instead we detect just the each chip table in slot order.
-+
-+ This routine takes a PCI ID table, scans the PCI bus, and calls the
-+ associated attach/probe1 routine with the hardware already activated and
-+ single I/O or memory address already mapped.
-+
-+ This routine will later be supplemented with CardBus and hot-swap PCI
-+ support using the same table. Thus the pci_chip_tbl[] should not be
-+ marked as __initdata.
-+*/
-+
-+#if LINUX_VERSION_CODE >= 0x20200
-+/* Grrrr.. complex abstaction layers with negative benefit. */
-+int pci_drv_register(struct drv_id_info *drv_id, void *initial_device)
-+{
-+ int chip_idx, cards_found = 0;
-+ struct pci_dev *pdev = NULL;
-+ struct pci_id_info *pci_tbl = drv_id->pci_dev_tbl;
-+ struct drv_id_info *drv;
-+ void *newdev;
-+
-+
-+ /* Ignore a double-register attempt. */
-+ for (drv = drv_list; drv; drv = drv->next)
-+ if (drv == drv_id)
-+ return -EBUSY;
-+
-+ while ((pdev = pci_find_class(drv_id->pci_class, pdev)) != 0) {
-+ u32 pci_id, pci_subsys_id, pci_class_rev;
-+ u16 pci_command, new_command;
-+ int pci_flags;
-+ long pciaddr; /* Bus address. */
-+ long ioaddr; /* Mapped address for this processor. */
-+
-+ pci_read_config_dword(pdev, PCI_VENDOR_ID, &pci_id);
-+ /* Offset 0x2c is PCI_SUBSYSTEM_ID aka PCI_SUBSYSTEM_VENDOR_ID. */
-+ pci_read_config_dword(pdev, 0x2c, &pci_subsys_id);
-+ pci_read_config_dword(pdev, PCI_REVISION_ID, &pci_class_rev);
-+
-+ if (msg_level > 3)
-+ printk(KERN_DEBUG "PCI ID %8.8x subsystem ID is %8.8x.\n",
-+ pci_id, pci_subsys_id);
-+ for (chip_idx = 0; pci_tbl[chip_idx].name; chip_idx++) {
-+ struct pci_id_info *chip = &pci_tbl[chip_idx];
-+ if ((pci_id & chip->id.pci_mask) == chip->id.pci
-+ && (pci_subsys_id&chip->id.subsystem_mask) == chip->id.subsystem
-+ && (pci_class_rev&chip->id.revision_mask) == chip->id.revision)
-+ break;
-+ }
-+ if (pci_tbl[chip_idx].name == 0) /* Compiled out! */
-+ continue;
-+
-+ pci_flags = pci_tbl[chip_idx].pci_flags;
-+#if LINUX_VERSION_CODE >= 0x2030C
-+ /* Wow. A oversized, hard-to-use abstraction. Bogus. */
-+ pciaddr = pdev->resource[(pci_flags >> 4) & 7].start;
-+#else
-+ pciaddr = pdev->base_address[(pci_flags >> 4) & 7];
-+#if defined(__alpha__) /* Really any machine with 64 bit addressing. */
-+ if (pci_flags & PCI_ADDR_64BITS)
-+ pciaddr |= ((long)pdev->base_address[((pci_flags>>4)&7)+ 1]) << 32;
-+#endif
-+#endif
-+ if (msg_level > 2)
-+ printk(KERN_INFO "Found %s at PCI address %#lx, mapped IRQ %d.\n",
-+ pci_tbl[chip_idx].name, pciaddr, pdev->irq);
-+
-+ if ( ! (pci_flags & PCI_UNUSED_IRQ) &&
-+ (pdev->irq == 0 || pdev->irq == 255)) {
-+ if (pdev->bus->number == 32) /* Broken CardBus activation. */
-+ printk(KERN_WARNING "Resources for CardBus device '%s' have"
-+ " not been allocated.\n"
-+ KERN_WARNING "Activation has been delayed.\n",
-+ pci_tbl[chip_idx].name);
-+ else
-+ printk(KERN_WARNING "PCI device '%s' was not assigned an "
-+ "IRQ.\n"
-+ KERN_WARNING "It will not be activated.\n",
-+ pci_tbl[chip_idx].name);
-+ continue;
-+ }
-+ if ((pci_flags & PCI_BASE_ADDRESS_SPACE_IO)) {
-+ ioaddr = pciaddr & PCI_BASE_ADDRESS_IO_MASK;
-+ if (check_region(ioaddr, pci_tbl[chip_idx].io_size))
-+ continue;
-+ } else if ((ioaddr = (long)ioremap(pciaddr & PCI_BASE_ADDRESS_MEM_MASK,
-+ pci_tbl[chip_idx].io_size)) == 0) {
-+ printk(KERN_INFO "Failed to map PCI address %#lx for device "
-+ "'%s'.\n", pciaddr, pci_tbl[chip_idx].name);
-+ continue;
-+ }
-+ if ( ! (pci_flags & PCI_NO_ACPI_WAKE))
-+ acpi_wake(pdev);
-+ pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
-+ new_command = pci_command | (pci_flags & 7);
-+ if (pci_command != new_command) {
-+ printk(KERN_INFO " The PCI BIOS has not enabled the"
-+ " device at %d/%d! Updating PCI command %4.4x->%4.4x.\n",
-+ pdev->bus->number, pdev->devfn, pci_command, new_command);
-+ pci_write_config_word(pdev, PCI_COMMAND, new_command);
-+ }
-+
-+ newdev = drv_id->probe1(pdev, initial_device,
-+ ioaddr, pdev->irq, chip_idx, cards_found);
-+ if (newdev == NULL)
-+ continue;
-+ initial_device = 0;
-+ cards_found++;
-+ if (pci_flags & PCI_COMMAND_MASTER) {
-+ pci_set_master(pdev);
-+ if ( ! (pci_flags & PCI_NO_MIN_LATENCY)) {
-+ u8 pci_latency;
-+ pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency);
-+ if (pci_latency < min_pci_latency) {
-+ printk(KERN_INFO " PCI latency timer (CFLT) is "
-+ "unreasonably low at %d. Setting to %d clocks.\n",
-+ pci_latency, min_pci_latency);
-+ pci_write_config_byte(pdev, PCI_LATENCY_TIMER,
-+ min_pci_latency);
-+ }
-+ }
-+ }
-+ {
-+ struct dev_info *devp =
-+ kmalloc(sizeof(struct dev_info), GFP_KERNEL);
-+ if (devp == 0)
-+ continue;
-+ devp->next = dev_list;
-+ devp->dev = newdev;
-+ devp->drv_id = drv_id;
-+ dev_list = devp;
-+ }
-+ }
-+
-+ if (((drv_id->flags & PCI_HOTSWAP)
-+ && register_hotswap_hook && (*register_hotswap_hook)(drv_id) == 0)
-+ || cards_found) {
-+ MOD_INC_USE_COUNT;
-+ drv_id->next = drv_list;
-+ drv_list = drv_id;
-+ return 0;
-+ } else
-+ return -ENODEV;
-+}
-+#else
-+int pci_drv_register(struct drv_id_info *drv_id, void *initial_device)
-+{
-+ int pci_index, cards_found = 0;
-+ unsigned char pci_bus, pci_device_fn;
-+ struct pci_dev *pdev;
-+ struct pci_id_info *pci_tbl = drv_id->pci_dev_tbl;
-+ void *newdev;
-+
-+ if ( ! pcibios_present())
-+ return -ENODEV;
-+
-+ for (pci_index = 0; pci_index < 0xff; pci_index++) {
-+ u32 pci_id, subsys_id, pci_class_rev;
-+ u16 pci_command, new_command;
-+ int chip_idx, irq, pci_flags;
-+ long pciaddr;
-+ long ioaddr;
-+ u32 pci_busaddr;
-+ u8 pci_irq_line;
-+
-+ if (pcibios_find_class (drv_id->pci_class, pci_index,
-+ &pci_bus, &pci_device_fn)
-+ != PCIBIOS_SUCCESSFUL)
-+ break;
-+ pcibios_read_config_dword(pci_bus, pci_device_fn,
-+ PCI_VENDOR_ID, &pci_id);
-+ /* Offset 0x2c is PCI_SUBSYSTEM_ID aka PCI_SUBSYSTEM_VENDOR_ID. */
-+ pcibios_read_config_dword(pci_bus, pci_device_fn, 0x2c, &subsys_id);
-+ pcibios_read_config_dword(pci_bus, pci_device_fn,
-+ PCI_REVISION_ID, &pci_class_rev);
-+
-+ for (chip_idx = 0; pci_tbl[chip_idx].name; chip_idx++) {
-+ struct pci_id_info *chip = &pci_tbl[chip_idx];
-+ if ((pci_id & chip->id.pci_mask) == chip->id.pci
-+ && (subsys_id & chip->id.subsystem_mask) == chip->id.subsystem
-+ && (pci_class_rev&chip->id.revision_mask) == chip->id.revision)
-+ break;
-+ }
-+ if (pci_tbl[chip_idx].name == 0) /* Compiled out! */
-+ continue;
-+
-+ pci_flags = pci_tbl[chip_idx].pci_flags;
-+ pdev = pci_find_slot(pci_bus, pci_device_fn);
-+ pcibios_read_config_byte(pci_bus, pci_device_fn,
-+ PCI_INTERRUPT_LINE, &pci_irq_line);
-+ irq = pci_irq_line;
-+ pcibios_read_config_dword(pci_bus, pci_device_fn,
-+ ((pci_flags >> 2) & 0x1C) + 0x10,
-+ &pci_busaddr);
-+ pciaddr = pci_busaddr;
-+#if defined(__alpha__)
-+ if (pci_flags & PCI_ADDR_64BITS) {
-+ pcibios_read_config_dword(pci_bus, pci_device_fn,
-+ ((pci_flags >> 2) & 0x1C) + 0x14,
-+ &pci_busaddr);
-+ pciaddr |= ((long)pci_busaddr)<<32;
-+ }
-+#endif
-+
-+ if (msg_level > 2)
-+ printk(KERN_INFO "Found %s at PCI address %#lx, IRQ %d.\n",
-+ pci_tbl[chip_idx].name, pciaddr, irq);
-+
-+ if ( ! (pci_flags & PCI_UNUSED_IRQ) &&
-+ (irq == 0 || irq == 255)) {
-+ if (pci_bus == 32) /* Broken CardBus activation. */
-+ printk(KERN_WARNING "Resources for CardBus device '%s' have"
-+ " not been allocated.\n"
-+ KERN_WARNING "It will not be activated.\n",
-+ pci_tbl[chip_idx].name);
-+ else
-+ printk(KERN_WARNING "PCI device '%s' was not assigned an "
-+ "IRQ.\n"
-+ KERN_WARNING "It will not be activated.\n",
-+ pci_tbl[chip_idx].name);
-+ continue;
-+ }
-+
-+ if ((pciaddr & PCI_BASE_ADDRESS_SPACE_IO)) {
-+ ioaddr = pciaddr & PCI_BASE_ADDRESS_IO_MASK;
-+ if (check_region(ioaddr, pci_tbl[chip_idx].io_size))
-+ continue;
-+ } else if ((ioaddr = (long)ioremap(pciaddr & PCI_BASE_ADDRESS_MEM_MASK,
-+ pci_tbl[chip_idx].io_size)) == 0) {
-+ printk(KERN_INFO "Failed to map PCI address %#lx.\n",
-+ pciaddr);
-+ continue;
-+ }
-+
-+ if ( ! (pci_flags & PCI_NO_ACPI_WAKE))
-+ acpi_wake(pdev);
-+ pcibios_read_config_word(pci_bus, pci_device_fn,
-+ PCI_COMMAND, &pci_command);
-+ new_command = pci_command | (pci_flags & 7);
-+ if (pci_command != new_command) {
-+ printk(KERN_INFO " The PCI BIOS has not enabled the"
-+ " device at %d/%d! Updating PCI command %4.4x->%4.4x.\n",
-+ pci_bus, pci_device_fn, pci_command, new_command);
-+ pcibios_write_config_word(pci_bus, pci_device_fn,
-+ PCI_COMMAND, new_command);
-+ }
-+
-+ newdev = drv_id->probe1(pdev, initial_device,
-+ ioaddr, irq, chip_idx, cards_found);
-+
-+ if (newdev && (pci_flags & PCI_COMMAND_MASTER) &&
-+ ! (pci_flags & PCI_NO_MIN_LATENCY)) {
-+ u8 pci_latency;
-+ pcibios_read_config_byte(pci_bus, pci_device_fn,
-+ PCI_LATENCY_TIMER, &pci_latency);
-+ if (pci_latency < min_pci_latency) {
-+ printk(KERN_INFO " PCI latency timer (CFLT) is "
-+ "unreasonably low at %d. Setting to %d clocks.\n",
-+ pci_latency, min_pci_latency);
-+ pcibios_write_config_byte(pci_bus, pci_device_fn,
-+ PCI_LATENCY_TIMER, min_pci_latency);
-+ }
-+ }
-+ if (newdev) {
-+ struct dev_info *devp =
-+ kmalloc(sizeof(struct dev_info), GFP_KERNEL);
-+ if (devp) {
-+ devp->next = dev_list;
-+ devp->dev = newdev;
-+ devp->drv_id = drv_id;
-+ dev_list = devp;
-+ }
-+ }
-+ initial_device = 0;
-+ cards_found++;
-+ }
-+
-+ if (((drv_id->flags & PCI_HOTSWAP)
-+ && register_hotswap_hook && (*register_hotswap_hook)(drv_id) == 0)
-+ || cards_found) {
-+ MOD_INC_USE_COUNT;
-+ drv_id->next = drv_list;
-+ drv_list = drv_id;
-+ return 0;
-+ } else
-+ return cards_found ? 0 : -ENODEV;
-+}
-+#endif
-+
-+void pci_drv_unregister(struct drv_id_info *drv_id)
-+{
-+ struct drv_id_info **drvp;
-+ struct dev_info **devip = &dev_list;
-+
-+ if (unregister_hotswap_hook)
-+ (*unregister_hotswap_hook)(drv_id);
-+
-+ for (drvp = &drv_list; *drvp; drvp = &(*drvp)->next)
-+ if (*drvp == drv_id) {
-+ *drvp = (*drvp)->next;
-+ MOD_DEC_USE_COUNT;
-+ break;
-+ }
-+ while (*devip) {
-+ struct dev_info *thisdevi = *devip;
-+ if (thisdevi->drv_id == drv_id) {
-+ *devip = thisdevi->next;
-+ kfree(thisdevi);
-+ } else
-+ devip = &(*devip)->next;
-+ }
-+
-+ return;
-+}
-+
-+#if LINUX_VERSION_CODE < 0x20400
-+/*
-+ Search PCI configuration space for the specified capability registers.
-+ Return the index, or 0 on failure.
-+ The 2.4 kernel now includes this function.
-+*/
-+int pci_find_capability(struct pci_dev *pdev, int findtype)
-+{
-+ u16 pci_status, cap_type;
-+ u8 pci_cap_idx;
-+ int cap_idx;
-+
-+ pci_read_config_word(pdev, PCI_STATUS, &pci_status);
-+ if ( ! (pci_status & PCI_STATUS_CAP_LIST))
-+ return 0;
-+ pci_read_config_byte(pdev, PCI_CAPABILITY_LIST, &pci_cap_idx);
-+ cap_idx = pci_cap_idx;
-+ for (cap_idx = pci_cap_idx; cap_idx; cap_idx = (cap_type >> 8) & 0xff) {
-+ pci_read_config_word(pdev, cap_idx, &cap_type);
-+ if ((cap_type & 0xff) == findtype)
-+ return cap_idx;
-+ }
-+ return 0;
-+}
-+#endif
-+
-+/* Change a device from D3 (sleep) to D0 (active).
-+ Return the old power state.
-+ This is more complicated than you might first expect since most cards
-+ forget all PCI config info during the transition! */
-+int acpi_wake(struct pci_dev *pdev)
-+{
-+ u32 base[5], romaddr;
-+ u16 pci_command, pwr_command;
-+ u8 pci_latency, pci_cacheline, irq;
-+ int i, pwr_cmd_idx = pci_find_capability(pdev, PCI_CAP_ID_PM);
-+
-+ if (pwr_cmd_idx == 0)
-+ return 0;
-+ pci_read_config_word(pdev, pwr_cmd_idx + 4, &pwr_command);
-+ if ((pwr_command & 3) == 0)
-+ return 0;
-+ pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
-+ for (i = 0; i < 5; i++)
-+ pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0 + i*4,
-+ &base[i]);
-+ pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &romaddr);
-+ pci_read_config_byte( pdev, PCI_LATENCY_TIMER, &pci_latency);
-+ pci_read_config_byte( pdev, PCI_CACHE_LINE_SIZE, &pci_cacheline);
-+ pci_read_config_byte( pdev, PCI_INTERRUPT_LINE, &irq);
-+
-+ pci_write_config_word(pdev, pwr_cmd_idx + 4, 0x0000);
-+ for (i = 0; i < 5; i++)
-+ if (base[i])
-+ pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0 + i*4,
-+ base[i]);
-+ pci_write_config_dword(pdev, PCI_ROM_ADDRESS, romaddr);
-+ pci_write_config_byte( pdev, PCI_INTERRUPT_LINE, irq);
-+ pci_write_config_byte( pdev, PCI_CACHE_LINE_SIZE, pci_cacheline);
-+ pci_write_config_byte( pdev, PCI_LATENCY_TIMER, pci_latency);
-+ pci_write_config_word( pdev, PCI_COMMAND, pci_command | 5);
-+ return pwr_command & 3;
-+}
-+
-+int acpi_set_pwr_state(struct pci_dev *pdev, enum acpi_pwr_state new_state)
-+{
-+ u16 pwr_command;
-+ int pwr_cmd_idx = pci_find_capability(pdev, PCI_CAP_ID_PM);
-+
-+ if (pwr_cmd_idx == 0)
-+ return 0;
-+ pci_read_config_word(pdev, pwr_cmd_idx + 4, &pwr_command);
-+ if ((pwr_command & 3) == ACPI_D3 && new_state != ACPI_D3)
-+ acpi_wake(pdev); /* The complicated sequence. */
-+ pci_write_config_word(pdev, pwr_cmd_idx + 4,
-+ (pwr_command & ~3) | new_state);
-+ return pwr_command & 3;
-+}
-+
-+#if defined(CONFIG_PM)
-+static int handle_pm_event(struct pm_dev *dev, int event, void *data)
-+{
-+ static int down = 0;
-+ struct dev_info *devi;
-+ int pwr_cmd = -1;
-+
-+ if (msg_level > 1)
-+ printk(KERN_DEBUG "pci-scan: Handling power event %d for driver "
-+ "list %s...\n",
-+ event, drv_list->name);
-+ switch (event) {
-+ case PM_SUSPEND:
-+ if (down) {
-+ printk(KERN_DEBUG "pci-scan: Received extra suspend event\n");
-+ break;
-+ }
-+ down = 1;
-+ for (devi = dev_list; devi; devi = devi->next)
-+ if (devi->drv_id->pwr_event)
-+ devi->drv_id->pwr_event(devi->dev, DRV_SUSPEND);
-+ break;
-+ case PM_RESUME:
-+ if (!down) {
-+ printk(KERN_DEBUG "pci-scan: Received bogus resume event\n");
-+ break;
-+ }
-+ for (devi = dev_list; devi; devi = devi->next) {
-+ if (devi->drv_id->pwr_event) {
-+ if (msg_level > 3)
-+ printk(KERN_DEBUG "pci-scan: Calling resume for %s "
-+ "device.\n", devi->drv_id->name);
-+ devi->drv_id->pwr_event(devi->dev, DRV_RESUME);
-+ }
-+ }
-+ down = 0;
-+ break;
-+ case PM_SET_WAKEUP: pwr_cmd = DRV_PWR_WakeOn; break;
-+ case PM_EJECT: pwr_cmd = DRV_DETACH; break;
-+ default:
-+ printk(KERN_DEBUG "pci-scan: Unknown power management event %d.\n",
-+ event);
-+ }
-+ if (pwr_cmd >= 0)
-+ for (devi = dev_list; devi; devi = devi->next)
-+ if (devi->drv_id->pwr_event)
-+ devi->drv_id->pwr_event(devi->dev, pwr_cmd);
-+
-+ return 0;
-+}
-+
-+#elif defined(CONFIG_APM) && LINUX_VERSION_CODE < 0x20400
-+static int handle_apm_event(apm_event_t event)
-+{
-+ static int down = 0;
-+ struct dev_info *devi;
-+
-+ if (msg_level > 1)
-+ printk(KERN_DEBUG "pci-scan: Handling APM event %d for driver "
-+ "list %s...\n",
-+ event, drv_list->name);
-+ return 0;
-+ switch (event) {
-+ case APM_SYS_SUSPEND:
-+ case APM_USER_SUSPEND:
-+ if (down) {
-+ printk(KERN_DEBUG "pci-scan: Received extra suspend event\n");
-+ break;
-+ }
-+ down = 1;
-+ for (devi = dev_list; devi; devi = devi->next)
-+ if (devi->drv_id->pwr_event)
-+ devi->drv_id->pwr_event(devi->dev, DRV_SUSPEND);
-+ break;
-+ case APM_NORMAL_RESUME:
-+ case APM_CRITICAL_RESUME:
-+ if (!down) {
-+ printk(KERN_DEBUG "pci-scan: Received bogus resume event\n");
-+ break;
-+ }
-+ for (devi = dev_list; devi; devi = devi->next)
-+ if (devi->drv_id->pwr_event)
-+ devi->drv_id->pwr_event(devi->dev, DRV_RESUME);
-+ down = 0;
-+ break;
-+ }
-+ return 0;
-+}
-+#endif /* CONFIG_APM */
-+
-+#ifdef MODULE
-+int init_module(void)
-+{
-+ if (msg_level) /* Emit version even if no cards detected. */
-+ printk(KERN_INFO "%s", version);
-+
-+#if defined(CONFIG_PM)
-+ pm_register(PM_PCI_DEV, 0, &handle_pm_event);
-+#elif defined(CONFIG_APM) && LINUX_VERSION_CODE < 0x20400
-+ apm_register_callback(&handle_apm_event);
-+#endif
-+ return 0;
-+}
-+void cleanup_module(void)
-+{
-+#if defined(CONFIG_PM)
-+ pm_unregister_all(&handle_pm_event);
-+#elif defined(CONFIG_APM) && LINUX_VERSION_CODE < 0x20400
-+ apm_unregister_callback(&handle_apm_event);
-+#endif
-+ if (dev_list != NULL)
-+ printk(KERN_WARNING "pci-scan: Unfreed device references.\n");
-+ return;
-+}
-+#endif
-+
-+
-+/*
-+ * Local variables:
-+ * compile-command: "gcc -DMODULE -D__KERNEL__ -DEXPORT_SYMTAB -Wall -Wstrict-prototypes -O6 -c pci-scan.c"
-+ * c-indent-level: 4
-+ * c-basic-offset: 4
-+ * tab-width: 4
-+ * End:
-+ */
-Index: linux/src/drivers/net/pci-scan.h
-===================================================================
-RCS file: linux/src/drivers/net/pci-scan.h
-diff -N linux/src/drivers/net/pci-scan.h
---- /dev/null 1 Jan 1970 00:00:00 -0000
-+++ linux/src/drivers/net/pci-scan.h 20 Aug 2004 10:32:54 -0000
-@@ -0,0 +1,90 @@
-+#ifndef _PCI_SCAN_H
-+#define _PCI_SCAN_H
-+/*
-+ version 1.02 $Version:$ $Date: 2001/03/18 21:35:59 $
-+ Copyright 1999-2001 Donald Becker / Scyld Computing Corporation
-+ This software is part of the Linux kernel. It may be used and
-+ distributed according to the terms of the GNU Public License,
-+ incorporated herein by reference.
-+*/
-+
-+/*
-+ These are the structures in the table that drives the PCI probe routines.
-+ Note the matching code uses a bitmask: more specific table entries should
-+ be placed before "catch-all" entries.
-+
-+ The table must be zero terminated.
-+*/
-+enum pci_id_flags_bits {
-+ /* Set PCI command register bits before calling probe1(). */
-+ PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
-+ /* Read and map the single following PCI BAR. */
-+ PCI_ADDR0=0<<4, PCI_ADDR1=1<<4, PCI_ADDR2=2<<4, PCI_ADDR3=3<<4,
-+ PCI_ADDR_64BITS=0x100, PCI_NO_ACPI_WAKE=0x200, PCI_NO_MIN_LATENCY=0x400,
-+ PCI_UNUSED_IRQ=0x800,
-+};
-+
-+struct pci_id_info {
-+ const char *name;
-+ struct match_info {
-+ int pci, pci_mask, subsystem, subsystem_mask;
-+ int revision, revision_mask; /* Only 8 bits. */
-+ } id;
-+ enum pci_id_flags_bits pci_flags;
-+ int io_size; /* Needed for I/O region check or ioremap(). */
-+ int drv_flags; /* Driver use, intended as capability flags. */
-+};
-+
-+enum drv_id_flags {
-+ PCI_HOTSWAP=1, /* Leave module loaded for Cardbus-like chips. */
-+};
-+enum drv_pwr_action {
-+ DRV_NOOP, /* No action. */
-+ DRV_ATTACH, /* The driver may expect power ops. */
-+ DRV_SUSPEND, /* Machine suspending, next event RESUME or DETACH. */
-+ DRV_RESUME, /* Resume from previous SUSPEND */
-+ DRV_DETACH, /* Card will-be/is gone. Valid from SUSPEND! */
-+ DRV_PWR_WakeOn, /* Put device in e.g. Wake-On-LAN mode. */
-+ DRV_PWR_DOWN, /* Go to lowest power mode. */
-+ DRV_PWR_UP, /* Go to normal power mode. */
-+};
-+
-+struct drv_id_info {
-+ const char *name; /* Single-word driver name. */
-+ int flags;
-+ int pci_class; /* Typically PCI_CLASS_NETWORK_ETHERNET<<8. */
-+ struct pci_id_info *pci_dev_tbl;
-+ void *(*probe1)(struct pci_dev *pdev, void *dev_ptr,
-+ long ioaddr, int irq, int table_idx, int fnd_cnt);
-+ /* Optional, called for suspend, resume and detach. */
-+ int (*pwr_event)(void *dev, int event);
-+ /* Internal values. */
-+ struct drv_id_info *next;
-+ void *cb_ops;
-+};
-+
-+/* PCI scan and activate.
-+ Scan PCI-like hardware, calling probe1(..,dev,..) on devices that match.
-+ Returns -ENODEV, a negative number, if no cards are found. */
-+
-+extern int pci_drv_register(struct drv_id_info *drv_id, void *initial_device);
-+extern void pci_drv_unregister(struct drv_id_info *drv_id);
-+
-+
-+/* ACPI routines.
-+ Wake (change to ACPI D0 state) or set the ACPI power level of a sleeping
-+ ACPI device. Returns the old power state. */
-+
-+int acpi_wake(struct pci_dev *pdev);
-+enum acpi_pwr_state {ACPI_D0, ACPI_D1, ACPI_D2, ACPI_D3};
-+int acpi_set_pwr_state(struct pci_dev *pdev, enum acpi_pwr_state state);
-+
-+
-+/*
-+ * Local variables:
-+ * c-indent-level: 4
-+ * c-basic-offset: 4
-+ * tab-width: 4
-+ * End:
-+ */
-+#endif
-Index: linux/src/drivers/net/pci-serial.c
-===================================================================
-RCS file: linux/src/drivers/net/pci-serial.c
-diff -N linux/src/drivers/net/pci-serial.c
---- /dev/null 1 Jan 1970 00:00:00 -0000
-+++ linux/src/drivers/net/pci-serial.c 20 Aug 2004 10:32:54 -0000
-@@ -0,0 +1,258 @@
-+/* pci-serial.c: A PCI serial port (e.g. modem) activator for Linux. */
-+/*
-+ This driver is an activator for PCI serial devices.
-+
-+ Written/copyright 1999-2002 by Donald Becker.
-+
-+ This software may be used and distributed according to the terms of
-+ the GNU General Public License (GPL), incorporated herein by reference.
-+ Drivers based on or derived from this code fall under the GPL and must
-+ retain the authorship, copyright and license notice. This file is not
-+ a complete program and may only be used when the entire operating
-+ system is licensed under the GPL.
-+
-+ The author may be reached as becker@scyld.com, or C/O
-+ Scyld Computing Corporation
-+ 410 Severn Ave., Suite 210
-+ Annapolis MD 21403
-+
-+ Support information and updates available at
-+ http://www.scyld.com/network/updates.html
-+*/
-+
-+static const char *version =
-+"pci-serial.c:v1.03 7/30/2002 Donald Becker http://www.scyld.com/index.html\n";
-+
-+/* A few user-configurable values. */
-+
-+/* Message enable level: 0..31 = no..all messages. See NETIF_MSG docs. */
-+static int debug = 1;
-+
-+/* Operational parameters that usually are not changed. */
-+
-+#if !defined(__OPTIMIZE__) || !defined(__KERNEL__)
-+#warning You must compile this file with the correct options!
-+#warning See the last lines of the source file.
-+#error You must compile this driver with "-O".
-+#endif
-+
-+#include <linux/config.h>
-+#if defined(MODULE) && defined(CONFIG_MODVERSIONS) && ! defined(MODVERSIONS)
-+#define MODVERSIONS
-+#endif
-+
-+#include <linux/version.h>
-+#if defined(MODVERSIONS)
-+#include <linux/modversions.h>
-+#endif
-+#include <linux/module.h>
-+
-+#include <linux/kernel.h>
-+#if LINUX_VERSION_CODE >= 0x20400
-+#include <linux/slab.h>
-+#else
-+#include <linux/malloc.h>
-+#endif
-+#include <linux/pci.h>
-+#if LINUX_VERSION_CODE < 0x20155
-+#include <linux/bios32.h>
-+#define PCI_SUPPORT 1
-+#else
-+#define PCI_SUPPORT 2
-+#endif
-+#include <linux/major.h>
-+#include <linux/serial.h>
-+
-+#include <asm/io.h>
-+#include "kern_compat.h"
-+
-+#if ! defined (LINUX_VERSION_CODE) || LINUX_VERSION_CODE < 0x20000
-+#warning This driver version is only for kernel versions 2.0.0 and later.
-+#endif
-+
-+MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
-+MODULE_DESCRIPTION("PCI hot-swap serial port activator");
-+MODULE_LICENSE("GPL");
-+MODULE_PARM(debug, "i");
-+MODULE_PARM_DESC(debug, "Driver message level (0-31)");
-+
-+#if LINUX_VERSION_CODE < 0x20123
-+#define test_and_set_bit(val, addr) set_bit(val, addr)
-+#endif
-+#if LINUX_VERSION_CODE < 0x20155
-+#define PCI_SUPPORT_VER1
-+#define pci_present pcibios_present
-+#endif
-+
-+/*
-+ Theory of Operation
-+
-+I. Board Compatibility
-+
-+This device driver is designed for PCI serial ports.
-+
-+
-+II. Board-specific settings
-+
-+N/A
-+
-+III. Operation
-+
-+IVb. References
-+
-+IVc. Errata
-+
-+*/
-+
-+/* The rest of these values should never change. */
-+
-+static struct cb_serial_info {
-+ struct cb_serial_info *next;
-+ long ioaddr;
-+ int major, minor;
-+ char dev_name[8];
-+ u32 subsystem_id;
-+ u8 pci_bus, pci_devfn, irq;
-+} *cb_serial_list;
-+
-+int serial_attach(int bus, int devfn)
-+{
-+ struct serial_struct serial;
-+ int line;
-+ u16 device_id, vendor_id, pci_cmd;
-+ u32 addr0, subsystem_id, pwr_cmd;
-+ u8 irq;
-+ long ioaddr;
-+
-+ if (debug) {
-+ printk(KERN_INFO "serial_attach(bus %d, function %d).\n",
-+ bus, devfn);
-+ }
-+ pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &addr0);
-+ if ( ! (addr0 & 1))
-+ pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_1, &addr0);
-+ pcibios_read_config_byte(bus, devfn, PCI_INTERRUPT_LINE, &irq);
-+ pcibios_read_config_word(bus, devfn, PCI_VENDOR_ID, &vendor_id);
-+ pcibios_read_config_word(bus, devfn, PCI_DEVICE_ID, &device_id);
-+ pcibios_read_config_dword(bus, devfn, PCI_SUBSYSTEM_ID, &subsystem_id);
-+ pcibios_read_config_dword(bus, devfn, 0x44, &pwr_cmd);
-+ pcibios_write_config_dword(bus, devfn, 0x44, pwr_cmd & ~3);
-+ pcibios_read_config_word(bus, devfn, PCI_COMMAND, &pci_cmd);
-+ ioaddr = addr0 & ~3;
-+ if (ioaddr == 0 || irq == 0) {
-+ printk(KERN_ERR "A CardBus serial port was not assigned an %s.\n",
-+ ioaddr == 0 ? "I/O address" : "IRQ");
-+ return 0;
-+ }
-+ if (debug > 1) {
-+ printk(KERN_INFO " PCI command register was %4.4x.\n", pci_cmd);
-+ printk(KERN_INFO "serial_attach(bus %d, function %d), device %4.4x "
-+ "IRQ %d IO %lx subsystem ID %8.8x.\n", bus, devfn, device_id,
-+ irq, ioaddr, subsystem_id);
-+ }
-+ /* Insert vendor-specific magic here. */
-+ serial.port = ioaddr;
-+ serial.irq = irq;
-+ serial.flags = ASYNC_SHARE_IRQ;
-+ line = register_serial(&serial);
-+
-+ if (debug > 2) {
-+ int i;
-+ printk(KERN_DEBUG "pci-serial: Register dump at %#lx:", ioaddr);
-+ for (i = 0; i < 8; i++)
-+ printk(" %2.2x", inb(ioaddr + i));
-+ printk(".\n");
-+ }
-+
-+ if (line < 0) {
-+ printk(KERN_NOTICE "serial_cb: register_serial() at 0x%04x, "
-+ "irq %d failed, status %d\n", serial.port, serial.irq, line);
-+ } else {
-+ struct cb_serial_info *info =
-+ kmalloc(sizeof(struct cb_serial_info), GFP_KERNEL);
-+ memset(info, 0, sizeof(struct cb_serial_info));
-+ sprintf(info->dev_name, "ttyS%d", line);
-+ info->major = TTY_MAJOR;
-+ info->minor = 0x40 + line;
-+ info->pci_bus = bus;
-+ info->pci_devfn = devfn;
-+ info->ioaddr = ioaddr;
-+ info->subsystem_id = subsystem_id;
-+ info->next = cb_serial_list;
-+ cb_serial_list = info;
-+ MOD_INC_USE_COUNT;
-+ return 1;
-+ }
-+ return 0;
-+}
-+
-+static void serial_detach(void)
-+{
-+ struct cb_serial_info *info, **infop;
-+ if (debug)
-+ printk(KERN_INFO "serial_detach()\n");
-+ for (infop = &cb_serial_list; *infop; *infop = (*infop)->next)
-+ if (1)
-+ break;
-+ info = *infop;
-+ if (info == NULL)
-+ return;
-+#if 0
-+ unregister_serial(node->minor - 0x40);
-+#endif
-+ *infop = info->next;
-+ kfree(info);
-+ MOD_DEC_USE_COUNT;
-+ if (debug)
-+ printk(KERN_INFO "serial_detach() done.\n");
-+}
-+
-+
-+#ifdef MODULE
-+
-+int init_module(void)
-+{
-+ int cards_found = 0;
-+ int pci_index;
-+ unsigned char pci_bus, pci_device_fn;
-+
-+ printk(KERN_INFO "%s", version);
-+
-+ if ( ! pcibios_present())
-+ return -ENODEV;
-+
-+ for (pci_index = 0; pci_index < 0xff; pci_index++) {
-+ if (pcibios_find_class (PCI_CLASS_COMMUNICATION_OTHER << 8, pci_index,
-+ &pci_bus, &pci_device_fn)
-+ != PCIBIOS_SUCCESSFUL)
-+ break;
-+ cards_found++;
-+ serial_attach(pci_bus, pci_device_fn);
-+ }
-+ for (pci_index = 0; pci_index < 0xff; pci_index++) {
-+ if (pcibios_find_class((PCI_CLASS_COMMUNICATION_SERIAL <<8) | 0x02,
-+ pci_index, &pci_bus, &pci_device_fn)
-+ != PCIBIOS_SUCCESSFUL)
-+ break;
-+ cards_found++;
-+ serial_attach(pci_bus, pci_device_fn);
-+ }
-+ return cards_found ? 0 : -ENODEV;
-+}
-+
-+void cleanup_module(void)
-+{
-+ return;
-+}
-+
-+#endif /* MODULE */
-+
-+/*
-+ * Local variables:
-+ * compile-command: "make pci-serial.o"
-+ * alt-compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c pci-serial.c"
-+ * c-indent-level: 4
-+ * c-basic-offset: 4
-+ * tab-width: 4
-+ * End:
-+ */
-Index: linux/src/drivers/net/pci-skeleton.c
-===================================================================
-RCS file: linux/src/drivers/net/pci-skeleton.c
-diff -N linux/src/drivers/net/pci-skeleton.c
---- /dev/null 1 Jan 1970 00:00:00 -0000
-+++ linux/src/drivers/net/pci-skeleton.c 20 Aug 2004 10:32:54 -0000
-@@ -0,0 +1,1694 @@
-+/* pci-skeleton.c: A Linux PCI network adapter skeleton device driver. */
-+/*
-+ Written 1998-2003 by Donald Becker.
-+
-+ This software may be used and distributed according to the terms of
-+ the GNU General Public License (GPL), incorporated herein by reference.
-+ Drivers based on or derived from this code fall under the GPL and must
-+ retain the authorship, copyright and license notice. This file is not
-+ a complete program and may only be used when the entire operating
-+ system is licensed under the GPL.
-+
-+ The author may be reached as becker@scyld.com, or C/O
-+ Scyld Computing Corporation
-+ 914 Bay Ridge Road, Suite 220
-+ Annapolis MD 21403
-+
-+ Support information and updates available at
-+ http://www.scyld.com/network/pci-skeleton.html
-+ The information and support mailing lists are based at
-+ http://www.scyld.com/mailman/listinfo/
-+*/
-+
-+/* These identify the driver base version and may not be removed. */
-+static const char version1[] =
-+"pci-skeleton.c:v2.13a 6/3/2003 Written by Donald Becker <becker@scyld.com>\n";
-+static const char version2[] =
-+" http://www.scyld.com/network/drivers.html\n";
-+
-+/* The user-configurable values.
-+ These may be modified when a driver module is loaded.*/
-+
-+/* Message enable level: 0..31 = no..all messages. See NETIF_MSG docs. */
-+static int debug = 2;
-+
-+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-+static int max_interrupt_work = 20;
-+
-+/* Maximum number of multicast addresses to filter (vs. rx-all-multicast).
-+ Typical is a 64 element hash table based on the Ethernet CRC. */
-+static int multicast_filter_limit = 32;
-+
-+/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
-+ Setting to > 1518 effectively disables this feature. */
-+static int rx_copybreak = 0;
-+
-+/* Used to pass the media type, etc.
-+ Both 'options[]' and 'full_duplex[]' should exist for driver
-+ interoperability, however setting full_duplex[] is deprecated.
-+ The media type is usually passed in 'options[]'.
-+ The default is autonegotation for speed and duplex.
-+ This should rarely be overridden.
-+ Use option values 0x10/0x20 for 10Mbps, 0x100,0x200 for 100Mbps.
-+ Use option values 0x10 and 0x100 for forcing half duplex fixed speed.
-+ Use option values 0x20 and 0x200 for forcing full duplex operation.
-+*/
-+#define MAX_UNITS 8 /* More are supported, limit only on options */
-+static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-+static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-+
-+/* Operational parameters that are set at compile time. */
-+
-+/* Keep the ring sizes a power of two for compile efficiency.
-+ The compiler will convert <unsigned>'%'<2^N> into a bit mask.
-+ Making the Tx ring too large decreases the effectiveness of channel
-+ bonding and packet priority, confuses the system network buffer limits,
-+ and wastes memory.
-+ Larger receive rings merely waste memory.
-+*/
-+#define TX_RING_SIZE 16
-+#define TX_QUEUE_LEN 10 /* Limit ring entries actually used, min 4. */
-+#define RX_RING_SIZE 32
-+
-+/* Operational parameters that usually are not changed. */
-+/* Time in jiffies before concluding the transmitter is hung.
-+ Re-autonegotiation may take up to 3 seconds.
-+ */
-+#define TX_TIMEOUT (6*HZ)
-+
-+/* Allocation size of Rx buffers with normal sized Ethernet frames.
-+ Do not change this value without good reason. This is not a limit,
-+ but a way to keep a consistent allocation size among drivers.
-+ */
-+#define PKT_BUF_SZ 1536
-+
-+/* Set iff a MII transceiver on any interface requires mdio preamble.
-+ This only set with older tranceivers, so the extra
-+ code size of a per-interface flag is not worthwhile. */
-+static char mii_preamble_required = 0;
-+
-+#ifndef __KERNEL__
-+#define __KERNEL__
-+#endif
-+#if !defined(__OPTIMIZE__)
-+#warning You must compile this file with the correct options!
-+#warning See the last lines of the source file.
-+#error You must compile this driver with "-O".
-+#endif
-+
-+/* Include files, designed to support most kernel versions 2.0.0 and later. */
-+#include <linux/config.h>
-+#if defined(CONFIG_SMP) && ! defined(__SMP__)
-+#define __SMP__
-+#endif
-+#if defined(MODULE) && defined(CONFIG_MODVERSIONS) && ! defined(MODVERSIONS)
-+#define MODVERSIONS
-+#endif
-+
-+#include <linux/version.h>
-+#if defined(MODVERSIONS)
-+#include <linux/modversions.h>
-+#endif
-+#include <linux/module.h>
-+
-+#include <linux/kernel.h>
-+#include <linux/string.h>
-+#include <linux/timer.h>
-+#include <linux/errno.h>
-+#include <linux/ioport.h>
-+#if LINUX_VERSION_CODE >= 0x20400
-+/* Bogus change in the middle of a "stable" kernel series.
-+ In 2.4.7+ slab must come before interrupt.h to avoid mystery breakage. */
-+#include <linux/slab.h>
-+#else
-+#include <linux/malloc.h>
-+#endif
-+#include <linux/interrupt.h>
-+#include <linux/pci.h>
-+#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/skbuff.h>
-+#include <asm/processor.h> /* Processor type for cache alignment. */
-+#include <asm/bitops.h>
-+#include <asm/io.h>
-+
-+#if LINUX_VERSION_CODE >= 0x20300
-+#include <linux/spinlock.h>
-+#elif LINUX_VERSION_CODE >= 0x20200
-+#include <asm/spinlock.h>
-+#endif
-+
-+#ifdef INLINE_PCISCAN
-+#include "k_compat.h"
-+#else
-+#include "pci-scan.h"
-+#include "kern_compat.h"
-+#endif
-+
-+/* Condensed operations for readability. */
-+#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr))
-+#define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr))
-+
-+#if (LINUX_VERSION_CODE >= 0x20100) && defined(MODULE)
-+char kernel_version[] = UTS_RELEASE;
-+#endif
-+
-+/* Kernels before 2.1.0 cannot map the high addrs assigned by some BIOSes. */
-+#if (LINUX_VERSION_CODE < 0x20100) || ! defined(MODULE)
-+#define USE_IO_OPS
-+#endif
-+
-+MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
-+MODULE_DESCRIPTION("PCI network skeleton Ethernet driver");
-+MODULE_LICENSE("GPL");
-+MODULE_PARM(debug, "i");
-+MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
-+MODULE_PARM(rx_copybreak, "i");
-+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
-+MODULE_PARM(multicast_filter_limit, "i");
-+MODULE_PARM(max_interrupt_work, "i");
-+MODULE_PARM_DESC(debug, "Driver message level (0-31)");
-+MODULE_PARM_DESC(options, "Force transceiver type or fixed speed+duplex");
-+MODULE_PARM_DESC(max_interrupt_work,
-+ "Driver maximum events handled per interrupt");
-+MODULE_PARM_DESC(full_duplex,
-+ "Non-zero to force full duplex, non-negotiated link "
-+ "(deprecated).");
-+MODULE_PARM_DESC(rx_copybreak,
-+ "Breakpoint in bytes for copy-only-tiny-frames");
-+MODULE_PARM_DESC(multicast_filter_limit,
-+ "Multicast addresses before switching to Rx-all-multicast");
-+
-+/*
-+ Theory of Operation
-+
-+I. Board Compatibility
-+
-+State the chips and boards this driver is known to work with.
-+Note any similar chips or boards that will not work.
-+
-+This driver skeleton demonstrates the driver for an idealized
-+descriptor-based bus-master PCI chip.
-+
-+II. Board-specific settings
-+
-+No jumpers exist on most PCI boards, so this section is usually empty.
-+
-+III. Driver operation
-+
-+IIIa. Ring buffers
-+
-+This driver uses two statically allocated fixed-size descriptor lists
-+formed into rings by a branch from the final descriptor to the beginning of
-+the list. The ring sizes are set at compile time by RX/TX_RING_SIZE.
-+Some chips explicitly use only 2^N sized rings, while others use a
-+'next descriptor' pointer that the driver forms into rings.
-+
-+IIIb/c. Transmit/Receive Structure
-+
-+This driver uses a zero-copy receive and transmit scheme.
-+The driver allocates full frame size skbuffs for the Rx ring buffers at
-+open() time and passes the skb->data field to the chip as receive data
-+buffers. When an incoming frame is less than RX_COPYBREAK bytes long,
-+a fresh skbuff is allocated and the frame is copied to the new skbuff.
-+When the incoming frame is larger, the skbuff is passed directly up the
-+protocol stack. Buffers consumed this way are replaced by newly allocated
-+skbuffs in a later phase of receives.
-+
-+The RX_COPYBREAK value is chosen to trade-off the memory wasted by
-+using a full-sized skbuff for small frames vs. the copying costs of larger
-+frames. New boards are typically used in generously configured machines
-+and the underfilled buffers have negligible impact compared to the benefit of
-+a single allocation size, so the default value of zero results in never
-+copying packets. When copying is done, the cost is usually mitigated by using
-+a combined copy/checksum routine. Copying also preloads the cache, which is
-+most useful with small frames.
-+
-+A subtle aspect of the operation is that the IP header at offset 14 in an
-+ethernet frame isn't longword aligned for further processing.
-+When unaligned buffers are permitted by the hardware (and always on copies)
-+frames are put into the skbuff at an offset of "+2", 16-byte aligning
-+the IP header.
-+
-+IIId. Synchronization
-+
-+The driver runs as two independent, single-threaded flows of control. One
-+is the send-packet routine, which enforces single-threaded use by the
-+dev->tbusy flag. The other thread is the interrupt handler, which is single
-+threaded by the hardware and interrupt handling software.
-+
-+The send packet thread has partial control over the Tx ring and 'dev->tbusy'
-+flag. It sets the tbusy flag whenever it's queuing a Tx packet. If the next
-+queue slot is empty, it clears the tbusy flag when finished otherwise it sets
-+the 'lp->tx_full' flag.
-+
-+The interrupt handler has exclusive control over the Rx ring and records stats
-+from the Tx ring. After reaping the stats, it marks the Tx queue entry as
-+empty by incrementing the dirty_tx mark. Iff the 'lp->tx_full' flag is set, it
-+clears both the tx_full and tbusy flags.
-+
-+IIId. SMP semantics
-+
-+The following are serialized with respect to each other via the "xmit_lock".
-+ dev->hard_start_xmit() Transmit a packet
-+ dev->tx_timeout() Transmit watchdog for stuck Tx
-+ dev->set_multicast_list() Set the recieve filter.
-+Note: The Tx timeout watchdog code is implemented by the timer routine in
-+kernels up to 2.2.*. In 2.4.* and later the timeout code is part of the
-+driver interface.
-+
-+The following fall under the global kernel lock. The module will not be
-+unloaded during the call, unless a call with a potential reschedule e.g.
-+kmalloc() is called. No other synchronization assertion is made.
-+ dev->open()
-+ dev->do_ioctl()
-+ dev->get_stats()
-+Caution: The lock for dev->open() is commonly broken with request_irq() or
-+kmalloc(). It is best to avoid any lock-breaking call in do_ioctl() and
-+get_stats(), or additional module locking code must be implemented.
-+
-+The following is self-serialized (no simultaneous entry)
-+ An handler registered with request_irq().
-+
-+IV. Notes
-+
-+There are few hard rules about writing device drivers, but I have read some
-+amazingly unwise code. Bad code often stems from the mistaken belief that
-+this device driver is the most important code the machine is running.
-+
-+Remember that this is a real OS, not DOS. Never mess with system hardware
-+(the timer chip, DMA channels, IRQ mapping): use the hardware-independent
-+kernel services instead.
-+
-+While there is a udelay() function, use it sparingly and only with tiny
-+delays. It is not for having the kernel wait three seconds while
-+autonegotiation completes! At boot time or module insertion time this rule
-+can be relaxed somewhat, but even then the total delay should be under a
-+timer tick (10msec).
-+
-+All loops should be checked with a 'boguscnt' limit. That includes the
-+interrupt handler, which should limit the work it does with a tunable
-+parameter. Loops that check for hardware completion should have a typical
-+completion count in a comment. An exception is traversing software
-+maintained lists, most of which should be designed to grow arbitrarily long.
-+
-+The device driver source code file should be self-contained, and as compact
-+as readability permits. It should not be spread out over multiple source
-+files, and there should only be a driver.h file in special circumstances.
-+
-+Finally, always support multiple devices. That means few, if any, global
-+variables. All driver variables should be 'static'.
-+
-+IVb. References
-+
-+http://www.scyld.com/expert/100mbps.html
-+http://scyld.com/expert/NWay.html
-+
-+List the documentation used to write the driver. Note any proprietary or
-+trade secret information, and the agreement you have to release the same.
-+
-+IVc. Errata
-+
-+Note any known bugs or limitations.
-+*/
-+
-+
-+
-+/* This table drives the PCI probe routines.
-+ Note the matching code -- the first table entry matches only the 5678 card,
-+ the second all remaining 56** cards.
-+*/
-+
-+static void *netfin_probe1(struct pci_dev *pdev, void *init_dev,
-+ long ioaddr, int irq, int chip_idx, int find_cnt);
-+static int netfin_pwr_event(void *dev_instance, int event);
-+enum chip_capability_flags {CanHaveMII=1, };
-+#ifdef USE_IO_OPS
-+#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_IO | PCI_ADDR0)
-+#else
-+#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR1)
-+#endif
-+
-+static struct pci_id_info pci_id_tbl[] = {
-+ {"NetTechCom 5678 adapter", {0x56781234, 0xffffffff, },
-+ PCI_IOTYPE, 128, CanHaveMII},
-+ {"NetTechCom 5600 series", {0x56001234, 0xff00ffff, },
-+ PCI_IOTYPE, 128, CanHaveMII},
-+ {0,}, /* 0 terminated list. */
-+};
-+
-+struct drv_id_info netfin_drv_id = {
-+ "netfin", PCI_HOTSWAP, PCI_CLASS_NETWORK_ETHERNET<<8, pci_id_tbl,
-+ netfin_probe1, netfin_pwr_event };
-+
-+/* This driver was written to use PCI memory space, however x86-oriented
-+ hardware sometimes works only with I/O space accesses. */
-+#ifdef USE_IO_OPS
-+#undef readb
-+#undef readw
-+#undef readl
-+#undef writeb
-+#undef writew
-+#undef writel
-+#define readb inb
-+#define readw inw
-+#define readl inl
-+#define writeb outb
-+#define writew outw
-+#define writel outl
-+#endif
-+
-+/* Offsets to the device registers.
-+ Unlike software-only systems, device drivers interact with complex hardware.
-+ It's not useful to define symbolic names for every register bit in the
-+ device. The name can only partially document the semantics and make
-+ the driver longer and more difficult to read.
-+ In general, only the important configuration values or bits changed
-+ multiple times should be defined symbolically.
-+*/
-+enum register_offsets {
-+ ChipCmd=0x00, IntrStatus=0x04, IntrEnable=0x08,
-+ TxStatus=0x10, TxCmd=0x14, TxRingPtr=0x18,
-+ RxStatus=0x20, RxCmd=0x24, RxRingPtr=0x28,
-+ EECtrl=0x40, MIICtrl=0x44, LEDCtrl=0x48,
-+ StationAddr=0x50, RxMode=0x58, TxMode=0x5C,
-+ RxMissed=0x60, RxCRCErrs=0x64, MulticastFilter0=0x68,MulticastFilter1=0x6C,
-+ PCIBusCfg=0x70, FIFOCfg=0x74, ChipReset=0x78,
-+};
-+
-+/* Bits in the interrupt status/mask registers. */
-+enum intr_status_bits {
-+ IntrRxDone=0x01, IntrRxEmpty=0x02, IntrRxPCIErr=0x04,
-+ IntrTxDone=0x10, IntrTxEmpty=0x20, IntrTxPCIErr=0x40,
-+ StatsMax=0x0100, LinkChange=0x0200, TxUnderrun=0x0400, RxOverflow=0x0800,
-+ IntrNormalSummary=0x8000, IntrAbnormalSummary=0x4000,
-+};
-+
-+/* Bits in the RxMode register. */
-+enum rx_mode_bits {
-+ AcceptErr=0x20, AcceptRunt=0x10,
-+ AcceptBroadcast=0x08, AcceptMulticast=0x04,
-+ AcceptAllPhys=0x02, AcceptMyPhys=0x01,
-+};
-+
-+/* Misc. bits. Symbolic names so that may be searched for. */
-+enum misc_bits {
-+ ChipResetCmd=1, RxEnable=1, RxPoll=2, RxDisable=4,
-+ TxEnable=1, TxPoll=2, TxDisable=4,
-+ TxModeFDX=1, TxThresholdField=0x0ff0, TxThresholdInc=0x0010,
-+};
-+
-+/* The Rx and Tx buffer descriptors. */
-+/* Note that using only 32 bit fields simplifies conversion to big-endian
-+ architectures. */
-+struct netdev_desc {
-+ u32 status;
-+ u32 length;
-+ u32 addr;
-+ u32 next_desc;
-+};
-+
-+/* Bits in network_desc.status */
-+enum desc_status_bits {
-+ DescOwn=0x80000000, DescEndPacket=0x40000000, DescEndRing=0x20000000,
-+ DescIntr=0x10000000,
-+ RxDescWholePkt=0x60000000,
-+ RxDescErrSum=0x80, RxErrRunt=0x40, RxErrLong=0x20, RxErrFrame=0x10,
-+ RxErrCRC=0x08, RxErrCode=0x04,
-+ TxErrAbort=0x2000, TxErrCarrier=0x1000, TxErrLate=0x0800,
-+ TxErr16Colls=0x0400, TxErrDefer=0x0200, TxErrHeartbeat=0x0100,
-+ TxColls=0x00ff,
-+};
-+
-+#define PRIV_ALIGN 15 /* Required alignment mask */
-+/* Use __attribute__((aligned (L1_CACHE_BYTES))) to maintain alignment
-+ within the structure. */
-+struct netdev_private {
-+ /* Descriptor rings first for alignment. */
-+ struct netdev_desc rx_ring[RX_RING_SIZE];
-+ struct netdev_desc tx_ring[TX_RING_SIZE];
-+ struct net_device *next_module; /* Link for devices of this type. */
-+ void *priv_addr; /* Unaligned address for kfree */
-+ const char *product_name;
-+ /* The addresses of receive-in-place skbuffs. */
-+ struct sk_buff* rx_skbuff[RX_RING_SIZE];
-+ /* The saved address of a sent-in-place packet/buffer, for later free(). */
-+ struct sk_buff* tx_skbuff[TX_RING_SIZE];
-+ struct net_device_stats stats;
-+ struct timer_list timer; /* Media monitoring timer. */
-+ /* Frequently used values: keep some adjacent for cache effect. */
-+ int msg_level;
-+ int chip_id, drv_flags;
-+ struct pci_dev *pci_dev;
-+ long in_interrupt; /* Word-long for SMP locks. */
-+ int max_interrupt_work;
-+ int intr_enable;
-+ unsigned int restore_intr_enable:1; /* Set if temporarily masked. */
-+
-+ struct netdev_desc *rx_head_desc;
-+ unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */
-+ unsigned int rx_buf_sz; /* Based on MTU+slack. */
-+ int rx_copybreak;
-+
-+ unsigned int cur_tx, dirty_tx;
-+ unsigned int tx_config;
-+ unsigned int tx_full:1; /* The Tx queue is full. */
-+
-+ /* These values keep track of the transceiver/media in use. */
-+ unsigned int full_duplex:1; /* Full-duplex operation requested. */
-+ unsigned int duplex_lock:1;
-+ unsigned int medialock:1; /* Do not sense media. */
-+ unsigned int default_port; /* Last dev->if_port value. */
-+ /* Rx filter. */
-+ u32 cur_rx_mode;
-+ u32 rx_filter[2];
-+ int multicast_filter_limit;
-+
-+ /* MII transceiver section. */
-+ int mii_cnt; /* MII device addresses. */
-+ u16 advertising; /* NWay media advertisement */
-+ unsigned char phys[2]; /* MII device addresses. */
-+};
-+
-+/* The station address location in the EEPROM. */
-+#define EEPROM_SA_OFFSET 0x10
-+
-+static int eeprom_read(long ioaddr, int location);
-+static int mdio_read(struct net_device *dev, int phy_id,
-+ unsigned int location);
-+static void mdio_write(struct net_device *dev, int phy_id,
-+ unsigned int location, int value);
-+static int netdev_open(struct net_device *dev);
-+static int change_mtu(struct net_device *dev, int new_mtu);
-+static void check_duplex(struct net_device *dev);
-+static void netdev_timer(unsigned long data);
-+static void tx_timeout(struct net_device *dev);
-+static void init_ring(struct net_device *dev);
-+static int start_tx(struct sk_buff *skb, struct net_device *dev);
-+static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs);
-+static void netdev_error(struct net_device *dev, int intr_status);
-+static int netdev_rx(struct net_device *dev);
-+static void netdev_error(struct net_device *dev, int intr_status);
-+static void set_rx_mode(struct net_device *dev);
-+static struct net_device_stats *get_stats(struct net_device *dev);
-+static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-+static int netdev_close(struct net_device *dev);
-+
-+
-+
-+/* A list of our installed devices, for removing the driver module. */
-+static struct net_device *root_net_dev = NULL;
-+
-+#ifndef MODULE
-+/* You *must* rename this! */
-+int skel_netdev_probe(struct net_device *dev)
-+{
-+ if (pci_drv_register(&netfin_drv_id, dev) < 0)
-+ return -ENODEV;
-+ if (debug >= NETIF_MSG_DRV) /* Emit version even if no cards detected. */
-+ printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2);
-+ return 0;
-+}
-+#endif
-+
-+static void *netfin_probe1(struct pci_dev *pdev, void *init_dev,
-+ long ioaddr, int irq, int chip_idx, int card_idx)
-+{
-+ struct net_device *dev;
-+ struct netdev_private *np;
-+ void *priv_mem;
-+ int i, option = card_idx < MAX_UNITS ? options[card_idx] : 0;
-+
-+ dev = init_etherdev(init_dev, 0);
-+ if (!dev)
-+ return NULL;
-+
-+ /* Perhaps NETIF_MSG_PROBE */
-+ printk(KERN_INFO "%s: %s at 0x%lx, ",
-+ dev->name, pci_id_tbl[chip_idx].name, ioaddr);
-+
-+ for (i = 0; i < 3; i++)
-+ ((u16 *)dev->dev_addr)[i] =
-+ le16_to_cpu(eeprom_read(ioaddr, i + EEPROM_SA_OFFSET));
-+ if (memcmp(dev->dev_addr, "\0\0\0\0\0", 6) == 0) {
-+ printk(" (MISSING EEPROM ADDRESS)");
-+ /* Fill a temp addr with the "locally administered" bit set. */
-+ memcpy(dev->dev_addr, ">Linux", 6);
-+ }
-+ for (i = 0; i < 5; i++)
-+ printk("%2.2x:", dev->dev_addr[i]);
-+ printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);
-+
-+#if ! defined(final_version) /* Dump the EEPROM contents during development. */
-+ if (debug > 4)
-+ for (i = 0; i < 0x40; i++)
-+ printk("%4.4x%s",
-+ eeprom_read(ioaddr, i), i % 16 != 15 ? " " : "\n");
-+#endif
-+
-+ /* Make certain elements e.g. descriptor lists are aligned. */
-+ priv_mem = kmalloc(sizeof(*np) + PRIV_ALIGN, GFP_KERNEL);
-+ /* Check for the very unlikely case of no memory. */
-+ if (priv_mem == NULL)
-+ return NULL;
-+
-+ /* Do bogusness checks before this point.
-+ We do a request_region() only to register /proc/ioports info. */
-+#ifdef USE_IO_OPS
-+ request_region(ioaddr, pci_id_tbl[chip_idx].io_size, dev->name);
-+#endif
-+
-+ /* Reset the chip to erase previous misconfiguration. */
-+ writel(ChipResetCmd, ioaddr + ChipReset);
-+
-+ dev->base_addr = ioaddr;
-+ dev->irq = irq;
-+
-+ dev->priv = np = (void *)(((long)priv_mem + PRIV_ALIGN) & ~PRIV_ALIGN);
-+ memset(np, 0, sizeof(*np));
-+ np->priv_addr = priv_mem;
-+
-+ np->next_module = root_net_dev;
-+ root_net_dev = dev;
-+
-+ np->pci_dev = pdev;
-+ np->chip_id = chip_idx;
-+ np->drv_flags = pci_id_tbl[chip_idx].drv_flags;
-+ np->msg_level = (1 << debug) - 1;
-+ np->rx_copybreak = rx_copybreak;
-+ np->max_interrupt_work = max_interrupt_work;
-+ np->multicast_filter_limit = multicast_filter_limit;
-+
-+ if (dev->mem_start)
-+ option = dev->mem_start;
-+
-+ /* The lower four bits are the media type. */
-+ if (option > 0) {
-+ if (option & 0x220)
-+ np->full_duplex = 1;
-+ np->default_port = option & 0x3ff;
-+ if (np->default_port & 0x330)
-+ np->medialock = 1;
-+ }
-+ if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0)
-+ np->full_duplex = 1;
-+
-+ if (np->full_duplex) {
-+ if (np->msg_level & NETIF_MSG_PROBE)
-+ printk(KERN_INFO "%s: Set to forced full duplex, autonegotiation"
-+ " disabled.\n", dev->name);
-+ np->duplex_lock = 1;
-+ }
-+
-+ /* The chip-specific entries in the device structure. */
-+ dev->open = &netdev_open;
-+ dev->hard_start_xmit = &start_tx;
-+ dev->stop = &netdev_close;
-+ dev->get_stats = &get_stats;
-+ dev->set_multicast_list = &set_rx_mode;
-+ dev->do_ioctl = &mii_ioctl;
-+ dev->change_mtu = &change_mtu;
-+
-+ if (np->drv_flags & CanHaveMII) {
-+ int phy, phy_idx = 0;
-+ mii_preamble_required++;
-+ /* In some cases the search should begin with #0. */
-+ for (phy = 1; phy < 32 && phy_idx < 4; phy++) {
-+ int mii_status = mdio_read(dev, phy, 1);
-+ if (mii_status != 0xffff && mii_status != 0x0000) {
-+ np->phys[phy_idx++] = phy;
-+ np->advertising = mdio_read(dev, phy, 4);
-+ if ((mii_status & 0x0040) == 0)
-+ mii_preamble_required++;
-+ if (np->msg_level & NETIF_MSG_PROBE)
-+ printk(KERN_INFO "%s: MII PHY found at address %d, status "
-+ "0x%4.4x advertising %4.4x.\n",
-+ dev->name, phy, mii_status, np->advertising);
-+ }
-+ }
-+ mii_preamble_required--;
-+ np->mii_cnt = phy_idx;
-+ }
-+
-+ /* Allow forcing the media type. */
-+ if (option > 0) {
-+ if (option & 0x220)
-+ np->full_duplex = 1;
-+ np->default_port = option & 0x3ff;
-+ if (np->default_port & 0x330) {
-+ np->medialock = 1;
-+ if (np->msg_level & NETIF_MSG_PROBE)
-+ printk(KERN_INFO " Forcing %dMbs %s-duplex operation.\n",
-+ (option & 0x300 ? 100 : 10),
-+ (np->full_duplex ? "full" : "half"));
-+ if (np->mii_cnt)
-+ mdio_write(dev, np->phys[0], 0,
-+ ((option & 0x300) ? 0x2000 : 0) | /* 100mbps? */
-+ (np->full_duplex ? 0x0100 : 0)); /* Full duplex? */
-+ }
-+ }
-+
-+ return dev;
-+}
-+
-+
-+/* Read the EEPROM and MII Management Data I/O (MDIO) interfaces.
-+ These are often serial bit streams generated by the host processor.
-+ The example below is for the common 93c46 EEPROM, 64 16 bit words. */
-+
-+/* Delay between EEPROM clock transitions.
-+ This "delay" forces out buffered PCI writes.
-+ Typically no extra delay is needed.
-+ Note that pre-2.0.34 kernels had a cache-alignment bug that made
-+ udelay() unreliable.
-+*/
-+#define eeprom_delay(ee_addr) readl(ee_addr)
-+
-+/* Note carefully if "DataIn" refers to the NIC or EEPROM viewpoint. */
-+enum EEPROM_Ctrl_Bits {
-+ EE_ShiftClk=0x01, EE_DataBit=0x02, EE_ChipSelect=0x04, EE_DataDir=0x08,
-+};
-+#define EE_Write0 (EE_DataDir | EE_ChipSelect)
-+#define EE_Write1 (EE_DataDir | EE_ChipSelect | EE_DataBit)
-+
-+/* The EEPROM commands always start with 01.. preamble bits.
-+ Commands are prepended to the variable-length address. */
-+enum EEPROM_Cmds { EE_WriteCmd=5, EE_ReadCmd=6, EE_EraseCmd=7, };
-+
-+static int eeprom_read(long addr, int location)
-+{
-+ int i;
-+ int retval = 0;
-+ long ee_addr = addr + EECtrl;
-+ int read_cmd = location | (EE_ReadCmd<<6);
-+
-+ writel(EE_DataDir, ee_addr);
-+ /* Shift the read command bits out. */
-+ for (i = 10; i >= 0; i--) {
-+ short dataval = (read_cmd & (1 << i)) ? EE_Write1 : EE_Write0;
-+ writel(dataval, ee_addr);
-+ eeprom_delay(ee_addr);
-+ writel(dataval | EE_ShiftClk, ee_addr);
-+ eeprom_delay(ee_addr);
-+ }
-+ writel(EE_ChipSelect, ee_addr);
-+ eeprom_delay(ee_addr);
-+
-+ for (i = 16; i > 0; i--) {
-+ writel(EE_ChipSelect | EE_ShiftClk, ee_addr);
-+ eeprom_delay(ee_addr);
-+ retval = (retval << 1) | ((readl(ee_addr) & EE_DataBit) ? 1 : 0);
-+ writel(EE_ChipSelect, ee_addr);
-+ eeprom_delay(ee_addr);
-+ }
-+
-+ /* Terminate the EEPROM access. */
-+ writel(EE_DataDir, ee_addr);
-+ writel(0, ee_addr);
-+ return retval;
-+}
-+
-+/* MII transceiver control section.
-+ Read and write the MII registers using software-generated serial
-+ MDIO protocol. See the MII specifications or DP83840A data sheet
-+ for details.
-+
-+ The maximum data clock rate is 2.5 Mhz.
-+ The timing is decoupled from the processor clock by flushing the write
-+ from the CPU write buffer with a following read, and using PCI
-+ transaction time. */
-+#define mdio_in(mdio_addr) readl(mdio_addr)
-+#define mdio_out(value, mdio_addr) writel(value, mdio_addr)
-+#define mdio_delay(mdio_addr) readl(mdio_addr)
-+
-+enum mii_reg_bits {
-+ MDIO_ShiftClk=0x0001, MDIO_Data=0x0002, MDIO_EnbOutput=0x0004,
-+};
-+#define MDIO_EnbIn (0)
-+#define MDIO_WRITE0 (MDIO_EnbOutput)
-+#define MDIO_WRITE1 (MDIO_Data | MDIO_EnbOutput)
-+
-+/* Generate the preamble required for initial synchronization and
-+ a few older transceivers. */
-+static void mdio_sync(long mdio_addr)
-+{
-+ int bits = 32;
-+
-+ /* Establish sync by sending at least 32 logic ones. */
-+ while (--bits >= 0) {
-+ mdio_out(MDIO_WRITE1, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ mdio_out(MDIO_WRITE1 | MDIO_ShiftClk, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ }
-+}
-+
-+static int mdio_read(struct net_device *dev, int phy_id, unsigned int location)
-+{
-+ long mdio_addr = dev->base_addr + MIICtrl;
-+ int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;
-+ int i, retval = 0;
-+
-+ if (mii_preamble_required)
-+ mdio_sync(mdio_addr);
-+
-+ /* Shift the read command bits out. */
-+ for (i = 15; i >= 0; i--) {
-+ int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
-+
-+ mdio_out(dataval, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ mdio_out(dataval | MDIO_ShiftClk, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ }
-+ /* Read the two transition, 16 data, and wire-idle bits. */
-+ for (i = 19; i > 0; i--) {
-+ mdio_out(MDIO_EnbIn, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ retval = (retval << 1) | ((mdio_in(mdio_addr) & MDIO_Data) ? 1 : 0);
-+ mdio_out(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ }
-+ return (retval>>1) & 0xffff;
-+}
-+
-+static void mdio_write(struct net_device *dev, int phy_id,
-+ unsigned int location, int value)
-+{
-+ long mdio_addr = dev->base_addr + MIICtrl;
-+ int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;
-+ int i;
-+
-+ if (mii_preamble_required)
-+ mdio_sync(mdio_addr);
-+
-+ /* Shift the command bits out. */
-+ for (i = 31; i >= 0; i--) {
-+ int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
-+
-+ mdio_out(dataval, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ mdio_out(dataval | MDIO_ShiftClk, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ }
-+ /* Clear out extra bits. */
-+ for (i = 2; i > 0; i--) {
-+ mdio_out(MDIO_EnbIn, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ mdio_out(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ }
-+ return;
-+}
-+
-+
-+static int netdev_open(struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+ int i;
-+
-+ /* Some chips may need to be reset. */
-+
-+ MOD_INC_USE_COUNT;
-+
-+ /* Note that both request_irq() and init_ring() call kmalloc(), which
-+ break the global kernel lock protecting this routine. */
-+ if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev)) {
-+ MOD_DEC_USE_COUNT;
-+ return -EAGAIN;
-+ }
-+
-+ if (np->msg_level & NETIF_MSG_IFUP)
-+ printk(KERN_DEBUG "%s: netdev_open() irq %d.\n",
-+ dev->name, dev->irq);
-+
-+ init_ring(dev);
-+
-+#if ADDRLEN == 64
-+ writel(virt_to_bus(np->rx_ring) >> 32, ioaddr + RxRingPtr + 4);
-+ writel(virt_to_bus(np->tx_ring) >> 32, ioaddr + TxRingPtr + 4);
-+#endif
-+ writel(virt_to_bus(np->rx_ring), ioaddr + RxRingPtr);
-+ writel(virt_to_bus(np->tx_ring), ioaddr + TxRingPtr);
-+
-+ for (i = 0; i < 6; i++)
-+ writeb(dev->dev_addr[i], ioaddr + StationAddr + i);
-+#if 0
-+ /* Or, if Address register must be written as words. */
-+ writel(cpu_to_le32(cpu_to_le32(get_unaligned((u32 *)dev->dev_addr))),
-+ ioaddr + StationAddr);
-+ writel(cpu_to_le16(cpu_to_le16(get_unaligned((u16 *)(dev->dev_addr+4)))),
-+ ioaddr + StationAddr + 4);
-+#endif
-+
-+ /* Initialize other registers. */
-+ /* Configure the PCI bus bursts and FIFO thresholds. */
-+ writel(0x0000, ioaddr + PCIBusCfg);
-+ writel(0x0000, ioaddr + FIFOCfg);
-+
-+ if (dev->if_port == 0)
-+ dev->if_port = np->default_port;
-+
-+ np->in_interrupt = 0;
-+
-+ set_rx_mode(dev);
-+ netif_start_tx_queue(dev);
-+
-+ /* Enable interrupts by setting the interrupt mask. */
-+ np->intr_enable = IntrRxDone | IntrRxEmpty | IntrRxPCIErr |
-+ IntrTxDone | IntrTxEmpty | IntrTxPCIErr | StatsMax | LinkChange;
-+ writel(np->intr_enable, ioaddr + IntrEnable);
-+
-+ writel(RxEnable, dev->base_addr + RxCmd);
-+
-+ if (np->msg_level & NETIF_MSG_IFUP)
-+ printk(KERN_DEBUG "%s: Done netdev_open(), status: Rx %x Tx %x.\n",
-+ dev->name, (int)readl(ioaddr + RxStatus),
-+ (int)readl(ioaddr + TxStatus));
-+
-+ /* Set the timer to check for link beat. */
-+ init_timer(&np->timer);
-+ np->timer.expires = jiffies + 3*HZ;
-+ np->timer.data = (unsigned long)dev;
-+ np->timer.function = &netdev_timer; /* timer handler */
-+ add_timer(&np->timer);
-+
-+ return 0;
-+}
-+
-+/* This is only needed if the chip supports >1500 byte frames.
-+ Changing the MTU while active is usually race prone or impossible, thus
-+ no configuration relies on the capability.
-+ */
-+static int change_mtu(struct net_device *dev, int new_mtu)
-+{
-+ if ((new_mtu < 68) || (new_mtu > 1500))
-+ return -EINVAL;
-+ if (netif_running(dev))
-+ return -EBUSY;
-+ dev->mtu = new_mtu;
-+ return 0;
-+}
-+
-+static void check_duplex(struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+ int old_tx_mode = np->tx_config;
-+
-+ if (np->medialock) {
-+ if (np->full_duplex)
-+ np->tx_config |= 1;
-+ } else {
-+ int mii_reg5 = mdio_read(dev, np->phys[0], 5);
-+ int negotiated = mii_reg5 & np->advertising;
-+ int duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;
-+ if (np->duplex_lock || mii_reg5 == 0xffff)
-+ return;
-+ if (duplex)
-+ np->tx_config |= TxModeFDX;
-+ else
-+ np->tx_config &= ~TxModeFDX;
-+ if (np->full_duplex != duplex) {
-+ np->full_duplex = duplex;
-+ if (np->msg_level & NETIF_MSG_LINK)
-+ printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d"
-+ " negotiated capability %4.4x.\n", dev->name,
-+ duplex ? "full" : "half", np->phys[0], negotiated);
-+ }
-+ }
-+ if (old_tx_mode != np->tx_config)
-+ writew(np->tx_config, ioaddr + TxMode);
-+}
-+
-+static void netdev_timer(unsigned long data)
-+{
-+ struct net_device *dev = (struct net_device *)data;
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+ int next_tick = 10*HZ;
-+
-+ if (np->msg_level & NETIF_MSG_TIMER) {
-+ printk(KERN_DEBUG "%s: Media selection timer tick, status %8.8x, "
-+ "Tx %x Rx %x.\n",
-+ dev->name, (int)readl(ioaddr + IntrStatus),
-+ (int)readl(ioaddr + TxStatus), (int)readl(ioaddr + RxStatus));
-+ }
-+ /* This will either have a small false-trigger window or will not catch
-+ tbusy incorrectly set when the queue is empty. */
-+ if (netif_queue_paused(dev) &&
-+ np->cur_tx - np->dirty_tx > 1 &&
-+ (jiffies - dev->trans_start) > TX_TIMEOUT) {
-+ tx_timeout(dev);
-+ }
-+ check_duplex(dev);
-+ np->timer.expires = jiffies + next_tick;
-+ add_timer(&np->timer);
-+}
-+
-+static void tx_timeout(struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+
-+ printk(KERN_WARNING "%s: Transmit timed out, status %8.8x,"
-+ " resetting...\n", dev->name, (int)readl(ioaddr + TxStatus));
-+
-+#ifndef __alpha__
-+ if (np->msg_level & NETIF_MSG_TX_ERR) {
-+ int i;
-+ printk(KERN_DEBUG " Rx ring %p: ", np->rx_ring);
-+ for (i = 0; i < RX_RING_SIZE; i++)
-+ printk(" %8.8x", (unsigned int)np->rx_ring[i].status);
-+ printk("\n"KERN_DEBUG" Tx ring %p: ", np->tx_ring);
-+ for (i = 0; i < TX_RING_SIZE; i++)
-+ printk(" %8.8x", np->tx_ring[i].status);
-+ printk("\n");
-+ }
-+#endif
-+
-+ /* Perhaps we should reinitialize the hardware here. */
-+ dev->if_port = 0;
-+ /* Stop and restart the chip's Tx processes . */
-+
-+ /* Trigger an immediate transmit demand. */
-+
-+ dev->trans_start = jiffies;
-+ np->stats.tx_errors++;
-+ return;
-+}
-+
-+
-+/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
-+static void init_ring(struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ int i;
-+
-+ np->tx_full = 0;
-+ np->cur_rx = np->cur_tx = 0;
-+ np->dirty_rx = np->dirty_tx = 0;
-+
-+ /* Use 1518/+18 if the CRC is transferred. */
-+ np->rx_buf_sz = (dev->mtu <= 1522 ? PKT_BUF_SZ : dev->mtu + 14);
-+ np->rx_head_desc = &np->rx_ring[0];
-+
-+ /* Initialize all Rx descriptors. */
-+ for (i = 0; i < RX_RING_SIZE; i++) {
-+ np->rx_ring[i].length = cpu_to_le32(np->rx_buf_sz);
-+ np->rx_ring[i].status = 0;
-+ /* np->rx_ring[i].next_desc = virt_to_le32desc(&np->rx_ring[i+1]);*/
-+ np->rx_skbuff[i] = 0;
-+ }
-+ /* Mark the last entry as wrapping the ring. */
-+ np->rx_ring[i-1].status |= cpu_to_le32(DescEndRing);
-+ /* Or np->rx_ring[i-1].next_desc = virt_to_le32desc(&np->rx_ring[0]);*/
-+
-+ /* Fill in the Rx buffers. Handle allocation failure gracefully. */
-+ for (i = 0; i < RX_RING_SIZE; i++) {
-+ struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz);
-+ np->rx_skbuff[i] = skb;
-+ if (skb == NULL)
-+ break;
-+ skb->dev = dev; /* Mark as being used by this device. */
-+ skb_reserve(skb, 2); /* 16 byte align the IP header. */
-+ np->rx_ring[i].addr = virt_to_le32desc(skb->tail);
-+ np->rx_ring[i].status = cpu_to_le32(DescOwn | DescIntr);
-+ }
-+ np->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
-+
-+ for (i = 0; i < TX_RING_SIZE; i++) {
-+ np->tx_skbuff[i] = 0;
-+ np->tx_ring[i].status = 0;
-+ /* Or np->tx_ring[i].next_desc = virt_to_le32desc(&np->tx_ring[i+1]);*/
-+ }
-+ /* Or np->tx_ring[i-1].next_desc = virt_to_le32desc(&np->tx_ring[0]); */
-+ return;
-+}
-+
-+static int start_tx(struct sk_buff *skb, struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ unsigned entry;
-+
-+ /* Block a timer-based transmit from overlapping. This happens when
-+ packets are presumed lost, and we use this check the Tx status. */
-+ if (netif_pause_tx_queue(dev) != 0) {
-+ /* This watchdog code is redundant with the media monitor timer. */
-+ if (jiffies - dev->trans_start > TX_TIMEOUT)
-+ tx_timeout(dev);
-+ return 1;
-+ }
-+
-+ /* Note: Ordering is important here, set the field with the
-+ "ownership" bit last, and only then increment cur_tx. */
-+
-+ /* Calculate the next Tx descriptor entry. */
-+ entry = np->cur_tx % TX_RING_SIZE;
-+
-+ np->tx_skbuff[entry] = skb;
-+
-+ np->tx_ring[entry].addr = virt_to_le32desc(skb->data);
-+ np->tx_ring[entry].length = cpu_to_le32(skb->len);
-+ if (entry >= TX_RING_SIZE-1) /* Wrap ring */
-+ np->tx_ring[entry].status =
-+ cpu_to_le32(DescOwn|DescEndPacket|DescEndRing);
-+ else
-+ np->tx_ring[entry].status = cpu_to_le32(DescOwn|DescEndPacket);
-+ np->cur_tx++;
-+
-+ /* On some architectures: explicitly flush cache lines here. */
-+
-+ if (np->cur_tx - np->dirty_tx >= TX_QUEUE_LEN - 1) {
-+ np->tx_full = 1;
-+ /* Check for a just-cleared queue. */
-+ if (np->cur_tx - (volatile unsigned int)np->dirty_tx
-+ < TX_QUEUE_LEN - 2) {
-+ np->tx_full = 0;
-+ netif_unpause_tx_queue(dev);
-+ } else
-+ netif_stop_tx_queue(dev);
-+ } else
-+ netif_unpause_tx_queue(dev); /* Typical path */
-+ /* Wake the potentially-idle transmit channel. */
-+ writel(TxPoll, dev->base_addr + TxCmd);
-+
-+ dev->trans_start = jiffies;
-+
-+ if (np->msg_level & NETIF_MSG_TX_QUEUED) {
-+ printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n",
-+ dev->name, np->cur_tx, entry);
-+ }
-+ return 0;
-+}
-+
-+/* The interrupt handler does all of the Rx thread work and cleans up
-+ after the Tx thread. */
-+static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
-+{
-+ struct net_device *dev = (struct net_device *)dev_instance;
-+ struct netdev_private *np;
-+ long ioaddr;
-+ int boguscnt;
-+
-+#ifndef final_version /* Can never occur. */
-+ if (dev == NULL) {
-+ printk (KERN_ERR "Netdev interrupt handler(): IRQ %d for unknown "
-+ "device.\n", irq);
-+ return;
-+ }
-+#endif
-+
-+ ioaddr = dev->base_addr;
-+ np = (struct netdev_private *)dev->priv;
-+ boguscnt = np->max_interrupt_work;
-+
-+#if defined(__i386__) && LINUX_VERSION_CODE < 0x020300
-+ /* A lock to prevent simultaneous entry bug on Intel SMP machines. */
-+ if (test_and_set_bit(0, (void*)&dev->interrupt)) {
-+ printk(KERN_ERR"%s: SMP simultaneous entry of an interrupt handler.\n",
-+ dev->name);
-+ dev->interrupt = 0; /* Avoid halting machine. */
-+ return;
-+ }
-+#endif
-+
-+ do {
-+ u32 intr_status = readl(ioaddr + IntrStatus);
-+
-+ /* Acknowledge all of the current interrupt sources ASAP. */
-+ writel(intr_status & 0x0000ffff, ioaddr + IntrStatus);
-+
-+ if (np->msg_level & NETIF_MSG_INTR)
-+ printk(KERN_DEBUG "%s: Interrupt, status %4.4x.\n",
-+ dev->name, intr_status);
-+
-+ if (intr_status == 0 || intr_status == 0xffffffff)
-+ break;
-+
-+ if (intr_status & IntrRxDone)
-+ netdev_rx(dev);
-+
-+ for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) {
-+ int entry = np->dirty_tx % TX_RING_SIZE;
-+ int tx_status = le32_to_cpu(np->tx_ring[entry].status);
-+ if (tx_status & DescOwn)
-+ break;
-+ if (np->msg_level & NETIF_MSG_TX_DONE)
-+ printk(KERN_DEBUG "%s: Transmit done, Tx status %8.8x.\n",
-+ dev->name, tx_status);
-+ if (tx_status & (TxErrAbort | TxErrCarrier | TxErrLate
-+ | TxErr16Colls | TxErrHeartbeat)) {
-+ if (np->msg_level & NETIF_MSG_TX_ERR)
-+ printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",
-+ dev->name, tx_status);
-+ np->stats.tx_errors++;
-+ if (tx_status & TxErrCarrier) np->stats.tx_carrier_errors++;
-+ if (tx_status & TxErrLate) np->stats.tx_window_errors++;
-+ if (tx_status & TxErrHeartbeat) np->stats.tx_heartbeat_errors++;
-+#ifdef ETHER_STATS
-+ if (tx_status & TxErr16Colls) np->stats.collisions16++;
-+ if (tx_status & TxErrAbort) np->stats.tx_aborted_errors++;
-+#else
-+ if (tx_status & (TxErr16Colls|TxErrAbort))
-+ np->stats.tx_aborted_errors++;
-+#endif
-+ } else {
-+ np->stats.tx_packets++;
-+ np->stats.collisions += tx_status & TxColls;
-+#if LINUX_VERSION_CODE > 0x20127
-+ np->stats.tx_bytes += np->tx_skbuff[entry]->len;
-+#endif
-+#ifdef ETHER_STATS
-+ if (tx_status & TxErrDefer) np->stats.tx_deferred++;
-+#endif
-+ }
-+ /* Free the original skb. */
-+ dev_free_skb_irq(np->tx_skbuff[entry]);
-+ np->tx_skbuff[entry] = 0;
-+ }
-+ /* Note the 4 slot hysteresis to mark the queue non-full. */
-+ if (np->tx_full && np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 4) {
-+ /* The ring is no longer full, allow new TX entries. */
-+ np->tx_full = 0;
-+ netif_resume_tx_queue(dev);
-+ }
-+
-+ /* Abnormal error summary/uncommon events handlers. */
-+ if (intr_status & (IntrTxPCIErr | IntrRxPCIErr | LinkChange | StatsMax))
-+ netdev_error(dev, intr_status);
-+
-+ if (--boguscnt < 0) {
-+ printk(KERN_WARNING "%s: Too much work at interrupt, "
-+ "status=0x%4.4x.\n",
-+ dev->name, intr_status);
-+ np->restore_intr_enable = 1;
-+ break;
-+ }
-+ } while (1);
-+
-+ if (np->msg_level & NETIF_MSG_INTR)
-+ printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
-+ dev->name, (int)readl(ioaddr + IntrStatus));
-+
-+#if defined(__i386__) && LINUX_VERSION_CODE < 0x020300
-+ clear_bit(0, (void*)&dev->interrupt);
-+#endif
-+ return;
-+}
-+
-+/* This routine is logically part of the interrupt handler, but separated
-+ for clarity and better register allocation. */
-+static int netdev_rx(struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ int entry = np->cur_rx % RX_RING_SIZE;
-+ int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx;
-+
-+ if (np->msg_level & NETIF_MSG_RX_STATUS) {
-+ printk(KERN_DEBUG " In netdev_rx(), entry %d status %4.4x.\n",
-+ entry, np->rx_ring[entry].status);
-+ }
-+
-+ /* If EOP is set on the next entry, it's a new packet. Send it up. */
-+ while ( ! (np->rx_head_desc->status & cpu_to_le32(DescOwn))) {
-+ struct netdev_desc *desc = np->rx_head_desc;
-+ u32 desc_status = le32_to_cpu(desc->status);
-+ int data_size = le32_to_cpu(desc->length);
-+
-+ if (np->msg_level & NETIF_MSG_RX_STATUS)
-+ printk(KERN_DEBUG " netdev_rx() status was %8.8x.\n",
-+ desc_status);
-+ if (--boguscnt < 0)
-+ break;
-+ if ((desc_status & RxDescWholePkt) != RxDescWholePkt) {
-+ /* Select a message. */
-+ printk(KERN_WARNING "%s: Oversized Ethernet frame spanned "
-+ "multiple buffers, entry %#x length %d status %4.4x!\n",
-+ dev->name, np->cur_rx, data_size, desc_status);
-+ printk(KERN_WARNING "%s: Oversized Ethernet frame %p vs %p.\n",
-+ dev->name, np->rx_head_desc,
-+ &np->rx_ring[np->cur_rx % RX_RING_SIZE]);
-+ printk(KERN_WARNING "%s: Oversized Ethernet frame -- next status %x/%x last status %x.\n",
-+ dev->name,
-+ np->rx_ring[(np->cur_rx+1) % RX_RING_SIZE].status,
-+ np->rx_ring[(np->cur_rx+1) % RX_RING_SIZE].length,
-+ np->rx_ring[(np->cur_rx-1) % RX_RING_SIZE].status);
-+ np->stats.rx_length_errors++;
-+ } else if (desc_status & RxDescErrSum) {
-+ /* There was a error. */
-+ if (np->msg_level & NETIF_MSG_RX_ERR)
-+ printk(KERN_DEBUG " netdev_rx() Rx error was %8.8x.\n",
-+ desc_status);
-+ np->stats.rx_errors++;
-+ if (desc_status & (RxErrLong|RxErrRunt))
-+ np->stats.rx_length_errors++;
-+ if (desc_status & (RxErrFrame|RxErrCode))
-+ np->stats.rx_frame_errors++;
-+ if (desc_status & RxErrCRC)
-+ np->stats.rx_crc_errors++;
-+ } else {
-+ struct sk_buff *skb;
-+ /* Reported length should omit the CRC. */
-+ u16 pkt_len = data_size - 4;
-+
-+#ifndef final_version
-+ if (np->msg_level & NETIF_MSG_RX_STATUS)
-+ printk(KERN_DEBUG " netdev_rx() normal Rx pkt length %d"
-+ " of %d, bogus_cnt %d.\n",
-+ pkt_len, data_size, boguscnt);
-+#endif
-+ /* Check if the packet is long enough to accept without copying
-+ to a minimally-sized skbuff. */
-+ if (pkt_len < np->rx_copybreak
-+ && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
-+ skb->dev = dev;
-+ skb_reserve(skb, 2); /* 16 byte align the IP header */
-+#if (LINUX_VERSION_CODE >= 0x20100)
-+ /* Use combined copy + cksum if available. */
-+ eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0);
-+ skb_put(skb, pkt_len);
-+#else
-+ memcpy(skb_put(skb, pkt_len), np->rx_skbuff[entry]->tail,
-+ pkt_len);
-+#endif
-+ } else {
-+ char *temp = skb_put(skb = np->rx_skbuff[entry], pkt_len);
-+ np->rx_skbuff[entry] = NULL;
-+#ifndef final_version /* Remove after testing. */
-+ if (le32desc_to_virt(np->rx_ring[entry].addr) != temp)
-+ printk(KERN_ERR "%s: Internal fault: The skbuff addresses "
-+ "do not match in netdev_rx: %p vs. %p / %p.\n",
-+ dev->name,
-+ le32desc_to_virt(np->rx_ring[entry].addr),
-+ skb->head, temp);
-+#endif
-+ }
-+#ifndef final_version /* Remove after testing. */
-+ /* You will want this info for the initial debug. */
-+ if (np->msg_level & NETIF_MSG_PKTDATA)
-+ printk(KERN_DEBUG " Rx data %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:"
-+ "%2.2x %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x %2.2x%2.2x "
-+ "%d.%d.%d.%d.\n",
-+ skb->data[0], skb->data[1], skb->data[2], skb->data[3],
-+ skb->data[4], skb->data[5], skb->data[6], skb->data[7],
-+ skb->data[8], skb->data[9], skb->data[10],
-+ skb->data[11], skb->data[12], skb->data[13],
-+ skb->data[14], skb->data[15], skb->data[16],
-+ skb->data[17]);
-+#endif
-+ skb->protocol = eth_type_trans(skb, dev);
-+ /* Note: checksum -> skb->ip_summed = CHECKSUM_UNNECESSARY; */
-+ netif_rx(skb);
-+ dev->last_rx = jiffies;
-+ np->stats.rx_packets++;
-+#if LINUX_VERSION_CODE > 0x20127
-+ np->stats.rx_bytes += pkt_len;
-+#endif
-+ }
-+ entry = (++np->cur_rx) % RX_RING_SIZE;
-+ np->rx_head_desc = &np->rx_ring[entry];
-+ }
-+
-+ /* Refill the Rx ring buffers. */
-+ for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) {
-+ struct sk_buff *skb;
-+ entry = np->dirty_rx % RX_RING_SIZE;
-+ if (np->rx_skbuff[entry] == NULL) {
-+ skb = dev_alloc_skb(np->rx_buf_sz);
-+ np->rx_skbuff[entry] = skb;
-+ if (skb == NULL)
-+ break; /* Better luck next round. */
-+ skb->dev = dev; /* Mark as being used by this device. */
-+ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
-+ np->rx_ring[entry].addr = virt_to_le32desc(skb->tail);
-+ }
-+ np->rx_ring[entry].length = cpu_to_le32(np->rx_buf_sz);
-+ np->rx_ring[entry].status = (entry == RX_RING_SIZE - 1)
-+ ? cpu_to_le32(DescOwn | DescEndPacket | DescEndRing | DescIntr)
-+ : cpu_to_le32(DescOwn | DescEndPacket | DescIntr);
-+ }
-+
-+ /* Restart Rx engine if stopped. */
-+ writel(RxPoll, dev->base_addr + RxCmd);
-+ return 0;
-+}
-+
-+static void netdev_error(struct net_device *dev, int intr_status)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+
-+ if (intr_status & LinkChange) {
-+ int phy_num = np->phys[0];
-+ if (np->msg_level & NETIF_MSG_LINK)
-+ printk(KERN_NOTICE "%s: Link changed: Autonegotiation advertising"
-+ " %4.4x partner %4.4x.\n", dev->name,
-+ mdio_read(dev, phy_num, 4),
-+ mdio_read(dev, phy_num, 5));
-+ /* Clear sticky bit. */
-+ mdio_read(dev, phy_num, 1);
-+ /* If link beat has returned... */
-+ if (mdio_read(dev, phy_num, 1) & 0x0004)
-+ netif_link_up(dev);
-+ else
-+ netif_link_down(dev);
-+ check_duplex(dev);
-+ }
-+ if ((intr_status & TxUnderrun)
-+ && (np->tx_config & TxThresholdField) != TxThresholdField) {
-+ long ioaddr = dev->base_addr;
-+ np->tx_config += TxThresholdInc;
-+ writel(np->tx_config, ioaddr + TxMode);
-+ np->stats.tx_fifo_errors++;
-+ }
-+ if (intr_status & RxOverflow) {
-+ printk(KERN_WARNING "%s: Receiver overflow.\n", dev->name);
-+ np->stats.rx_over_errors++;
-+ netdev_rx(dev); /* Refill */
-+ get_stats(dev); /* Empty dropped counter. */
-+ }
-+ if (intr_status & StatsMax) {
-+ get_stats(dev);
-+ }
-+ if ((intr_status & ~(LinkChange|StatsMax|TxUnderrun|RxOverflow))
-+ && (np->msg_level & NETIF_MSG_DRV))
-+ printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n",
-+ dev->name, intr_status);
-+ /* Hmmmmm, it's not clear how to recover from PCI faults. */
-+ if (intr_status & IntrTxPCIErr)
-+ np->stats.tx_fifo_errors++;
-+ if (intr_status & IntrRxPCIErr)
-+ np->stats.rx_fifo_errors++;
-+}
-+
-+/* We frequently do not bother to spinlock statistics.
-+ A window only exists if we have non-atomic adds, the error counts are
-+ typically zero, and statistics are non-critical. */
-+static struct net_device_stats *get_stats(struct net_device *dev)
-+{
-+ long ioaddr = dev->base_addr;
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+
-+ /* We should lock this segment of code for SMP eventually, although
-+ the vulnerability window is very small and statistics are
-+ non-critical. */
-+ /* The chip only need report frame silently dropped. */
-+ np->stats.rx_crc_errors += readl(ioaddr + RxCRCErrs);
-+ np->stats.rx_missed_errors += readl(ioaddr + RxMissed);
-+
-+ return &np->stats;
-+}
-+
-+/* The little-endian AUTODIN II ethernet CRC calculations.
-+ A big-endian version is also available.
-+ This is slow but compact code. Do not use this routine for bulk data,
-+ use a table-based routine instead.
-+ This is common code and should be moved to net/core/crc.c.
-+ Chips may use the upper or lower CRC bits, and may reverse and/or invert
-+ them. Select the endian-ness that results in minimal calculations.
-+*/
-+static unsigned const ethernet_polynomial_le = 0xedb88320U;
-+static inline unsigned ether_crc_le(int length, unsigned char *data)
-+{
-+ unsigned int crc = ~0; /* Initial value. */
-+ while(--length >= 0) {
-+ unsigned char current_octet = *data++;
-+ int bit;
-+ for (bit = 8; --bit >= 0; current_octet >>= 1) {
-+ if ((crc ^ current_octet) & 1) {
-+ crc >>= 1;
-+ crc ^= ethernet_polynomial_le;
-+ } else
-+ crc >>= 1;
-+ }
-+ }
-+ return crc;
-+}
-+
-+/*
-+ Set the receiver mode, including the multicast filter.
-+ The driver must not sleep here. If it must allocate memory use
-+ GFP_ATOMIC and recover from allocation failure in the timer code.
-+*/
-+static void set_rx_mode(struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+ u32 mc_filter[2]; /* Multicast hash filter */
-+ u32 rx_mode;
-+
-+ if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
-+ /* Unconditionally log net taps. */
-+ printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);
-+ memset(mc_filter, ~0, sizeof(mc_filter));
-+ rx_mode = AcceptBroadcast | AcceptMulticast | AcceptAllPhys
-+ | AcceptMyPhys;
-+ } else if ((dev->mc_count > np->multicast_filter_limit)
-+ || (dev->flags & IFF_ALLMULTI)) {
-+ /* Too many to match, or accept all multicasts. */
-+ memset(mc_filter, 0xff, sizeof(mc_filter));
-+ rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
-+ } else {
-+ struct dev_mc_list *mclist;
-+ int i;
-+ memset(mc_filter, 0, sizeof(mc_filter));
-+ for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
-+ i++, mclist = mclist->next) {
-+ set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x3f,
-+ mc_filter);
-+ }
-+ rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
-+ }
-+ writel(mc_filter[0], ioaddr + MulticastFilter0);
-+ writel(mc_filter[1], ioaddr + MulticastFilter1);
-+ writel(rx_mode, ioaddr + RxMode);
-+}
-+
-+/*
-+ Handle user-level ioctl() calls.
-+ We must use two numeric constants as the key because some clueless person
-+ changed the value for the symbolic name.
-+*/
-+static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ u16 *data = (u16 *)&rq->ifr_data;
-+ u32 *data32 = (void *)&rq->ifr_data;
-+
-+ switch(cmd) {
-+ case 0x8947: case 0x89F0:
-+ /* SIOCGMIIPHY: Get the address of the PHY in use. */
-+ data[0] = np->phys[0] & 0x1f;
-+ /* Fall Through */
-+ case 0x8948: case 0x89F1:
-+ /* SIOCGMIIREG: Read the specified MII register. */
-+ data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f);
-+ return 0;
-+ case 0x8949: case 0x89F2:
-+ /* SIOCSMIIREG: Write the specified MII register */
-+ if (!capable(CAP_NET_ADMIN))
-+ return -EPERM;
-+ if (data[0] == np->phys[0]) {
-+ u16 value = data[2];
-+ switch (data[1]) {
-+ case 0:
-+ /* Check for autonegotiation on or reset. */
-+ np->medialock = (value & 0x9000) ? 0 : 1;
-+ if (np->medialock)
-+ np->full_duplex = (value & 0x0100) ? 1 : 0;
-+ break;
-+ case 4: np->advertising = value; break;
-+ }
-+ /* Perhaps check_duplex(dev), depending on chip semantics. */
-+ }
-+ mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]);
-+ return 0;
-+ case SIOCGPARAMS:
-+ data32[0] = np->msg_level;
-+ data32[1] = np->multicast_filter_limit;
-+ data32[2] = np->max_interrupt_work;
-+ data32[3] = np->rx_copybreak;
-+ return 0;
-+ case SIOCSPARAMS:
-+ if (!capable(CAP_NET_ADMIN))
-+ return -EPERM;
-+ np->msg_level = data32[0];
-+ np->multicast_filter_limit = data32[1];
-+ np->max_interrupt_work = data32[2];
-+ np->rx_copybreak = data32[3];
-+ return 0;
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+}
-+
-+static int netdev_close(struct net_device *dev)
-+{
-+ long ioaddr = dev->base_addr;
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ int i;
-+
-+ netif_stop_tx_queue(dev);
-+
-+ if (np->msg_level & NETIF_MSG_IFDOWN) {
-+ printk(KERN_DEBUG "%s: Shutting down ethercard, status was Tx %4.4x "
-+ "Rx %4.4x Int %2.2x.\n",
-+ dev->name, (int)readl(ioaddr + TxStatus),
-+ (int)readl(ioaddr + RxStatus), (int)readl(ioaddr + IntrStatus));
-+ printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d, Rx %d / %d.\n",
-+ dev->name, np->cur_tx, np->dirty_tx, np->cur_rx, np->dirty_rx);
-+ }
-+
-+ /* Disable interrupts by clearing the interrupt mask. */
-+ writel(0x0000, ioaddr + IntrEnable);
-+
-+ /* Stop the chip's Tx and Rx processes. */
-+ writel(RxDisable, ioaddr + RxCmd);
-+ writew(TxDisable, ioaddr + TxCmd);
-+
-+ del_timer(&np->timer);
-+
-+#ifdef __i386__
-+ if (np->msg_level & NETIF_MSG_IFDOWN) {
-+ printk("\n"KERN_DEBUG" Tx ring at %8.8x:\n",
-+ (int)virt_to_bus(np->tx_ring));
-+ for (i = 0; i < TX_RING_SIZE; i++)
-+ printk(KERN_DEBUG " #%d desc. %4.4x %8.8x %8.8x.\n",
-+ i, np->tx_ring[i].length,
-+ np->tx_ring[i].status, np->tx_ring[i].addr);
-+ printk(KERN_DEBUG "\n" KERN_DEBUG " Rx ring %8.8x:\n",
-+ (int)virt_to_bus(np->rx_ring));
-+ for (i = 0; i < RX_RING_SIZE; i++) {
-+ printk(KERN_DEBUG " #%d desc. %4.4x %4.4x %8.8x\n",
-+ i, np->rx_ring[i].length,
-+ np->rx_ring[i].status, np->rx_ring[i].addr);
-+ }
-+ }
-+#endif /* __i386__ debugging only */
-+
-+ free_irq(dev->irq, dev);
-+
-+ /* Free all the skbuffs in the Rx queue. */
-+ for (i = 0; i < RX_RING_SIZE; i++) {
-+ np->rx_ring[i].status = 0;
-+ np->rx_ring[i].addr = 0xBADF00D0; /* An invalid address. */
-+ if (np->rx_skbuff[i]) {
-+#if LINUX_VERSION_CODE < 0x20100
-+ np->rx_skbuff[i]->free = 1;
-+#endif
-+ dev_free_skb(np->rx_skbuff[i]);
-+ }
-+ np->rx_skbuff[i] = 0;
-+ }
-+ for (i = 0; i < TX_RING_SIZE; i++) {
-+ if (np->tx_skbuff[i])
-+ dev_free_skb(np->tx_skbuff[i]);
-+ np->tx_skbuff[i] = 0;
-+ }
-+
-+ writel(0x00, ioaddr + LEDCtrl);
-+
-+ MOD_DEC_USE_COUNT;
-+
-+ return 0;
-+}
-+
-+static int netfin_pwr_event(void *dev_instance, int event)
-+{
-+ struct net_device *dev = dev_instance;
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+
-+ if (np->msg_level & NETIF_MSG_LINK)
-+ printk(KERN_DEBUG "%s: Handling power event %d.\n", dev->name, event);
-+ switch(event) {
-+ case DRV_ATTACH:
-+ MOD_INC_USE_COUNT;
-+ break;
-+ case DRV_SUSPEND:
-+ /* Disable interrupts, stop Tx and Rx. */
-+ writel(0x0000, ioaddr + IntrEnable);
-+ writel(RxDisable, ioaddr + RxCmd);
-+ writew(TxDisable, ioaddr + TxCmd);
-+ break;
-+ case DRV_RESUME:
-+ /* This is incomplete: the actions are very chip specific. */
-+ set_rx_mode(dev);
-+ writel(np->intr_enable, ioaddr + IntrEnable);
-+ break;
-+ case DRV_DETACH: {
-+ struct net_device **devp, **next;
-+ if (dev->flags & IFF_UP) {
-+ /* Some, but not all, kernel versions close automatically. */
-+ dev_close(dev);
-+ dev->flags &= ~(IFF_UP|IFF_RUNNING);
-+ }
-+ unregister_netdev(dev);
-+ release_region(dev->base_addr, pci_id_tbl[np->chip_id].io_size);
-+#ifndef USE_IO_OPS
-+ iounmap((char *)dev->base_addr);
-+#endif
-+ for (devp = &root_net_dev; *devp; devp = next) {
-+ next = &((struct netdev_private *)(*devp)->priv)->next_module;
-+ if (*devp == dev) {
-+ *devp = *next;
-+ break;
-+ }
-+ }
-+ if (np->priv_addr)
-+ kfree(np->priv_addr);
-+ kfree(dev);
-+ MOD_DEC_USE_COUNT;
-+ break;
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+
-+#ifdef MODULE
-+int init_module(void)
-+{
-+ if (debug >= NETIF_MSG_DRV) /* Emit version even if no cards detected. */
-+ printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2);
-+ return pci_drv_register(&netfin_drv_id, NULL);
-+}
-+
-+void cleanup_module(void)
-+{
-+ struct net_device *next_dev;
-+
-+ pci_drv_unregister(&netfin_drv_id);
-+
-+ /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
-+ while (root_net_dev) {
-+ struct netdev_private *np = (void *)(root_net_dev->priv);
-+ unregister_netdev(root_net_dev);
-+#ifdef USE_IO_OPS
-+ release_region(root_net_dev->base_addr,
-+ pci_id_tbl[np->chip_id].io_size);
-+#else
-+ iounmap((char *)(root_net_dev->base_addr));
-+#endif
-+ next_dev = np->next_module;
-+ if (np->priv_addr)
-+ kfree(np->priv_addr);
-+ kfree(root_net_dev);
-+ root_net_dev = next_dev;
-+ }
-+}
-+
-+#endif /* MODULE */
-+
-+/*
-+ * Local variables:
-+ * compile-command: "make KERNVER=`uname -r` pci-skeleton.o"
-+ * compile-cmd: "gcc -DMODULE -Wall -Wstrict-prototypes -O6 -c pci-skeleton.c"
-+ * simple-compile-command: "gcc -DMODULE -O6 -c pci-skeleton.c"
-+ * c-indent-level: 4
-+ * c-basic-offset: 4
-+ * tab-width: 4
-+ * End:
-+ */
-Index: linux/src/drivers/net/rtl8139.c
-===================================================================
-RCS file: /cvsroot/hurd/gnumach/linux/src/drivers/net/Attic/rtl8139.c,v
-retrieving revision 1.2
-diff -u -r1.2 rtl8139.c
---- linux/src/drivers/net/rtl8139.c 9 Sep 1999 06:30:37 -0000 1.2
-+++ linux/src/drivers/net/rtl8139.c 20 Aug 2004 10:32:54 -0000
-@@ -1,34 +1,62 @@
- /* rtl8139.c: A RealTek RTL8129/8139 Fast Ethernet driver for Linux. */
- /*
-- Written 1997-1998 by Donald Becker.
--
-- This software may be used and distributed according to the terms
-- of the GNU Public License, incorporated herein by reference.
-- All other rights reserved.
-+ Written and Copyright 1997-2003 by Donald Becker.
-+ This software may be used and distributed according to the terms of
-+ the GNU General Public License (GPL), incorporated herein by reference.
-+ Drivers based on or derived from this code fall under the GPL and must
-+ retain the authorship, copyright and license notice. This file is not
-+ a complete program and may only be used when the entire operating
-+ system is licensed under the GPL.
-
- This driver is for boards based on the RTL8129 and RTL8139 PCI ethernet
- chips.
-
-- The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
-- Center of Excellence in Space Data and Information Sciences
-- Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
-+ The author may be reached as becker@scyld.com, or C/O
-+ Scyld Computing Corporation
-+ 410 Severn Ave., Suite 210
-+ Annapolis MD 21403
-
- Support and updates available at
-- http://cesdis.gsfc.nasa.gov/linux/drivers/rtl8139.html
-+ http://www.scyld.com/network/rtl8139.html
-
-- Twister-tuning code contributed by Kinston <shangh@realtek.com.tw>.
-+ Twister-tuning table provided by Kinston <shangh@realtek.com.tw>.
- */
-
--static const char *version =
--"rtl8139.c:v0.99B 4/7/98 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/rtl8139.html\n";
-+/* These identify the driver base version and may not be removed. */
-+static const char versionA[] =
-+"rtl8139.c:v1.23a 8/24/2003 Donald Becker, becker@scyld.com.\n";
-+static const char versionB[] =
-+" http://www.scyld.com/network/rtl8139.html\n";
-+
-+#ifndef USE_MEM_OPS
-+/* Note: Register access width and timing restrictions apply in MMIO mode.
-+ This updated driver should nominally work, but I/O mode is better tested. */
-+#define USE_IO_OPS
-+#endif
-+
-+/* The user-configurable values.
-+ These may be modified when a driver module is loaded.*/
-+/* Message enable level: 0..31 = no..all messages. See NETIF_MSG docs. */
-+static int debug = 2;
-
--/* A few user-configurable values. */
- /* Maximum events (Rx packets, etc.) to handle at each interrupt. */
--static int max_interrupt_work = 10;
-+static int max_interrupt_work = 20;
-+
-+/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
-+ The RTL chips use a 64 element hash table based on the Ethernet CRC. It
-+ is efficient to update the hardware filter, but recalculating the table
-+ for a long filter list is painful. */
-+static int multicast_filter_limit = 32;
-+
-+/* Used to pass the full-duplex flag, etc. */
-+#define MAX_UNITS 8 /* More are supported, limit only on options */
-+static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-+static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-+
-+/* Operational parameters that are set at compile time. */
-
--/* Size of the in-memory receive ring. */
-+/* Maximum size of the in-memory receive ring (smaller if no memory). */
- #define RX_BUF_LEN_IDX 2 /* 0==8K, 1==16K, 2==32K, 3==64K */
--#define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX)
- /* Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). */
- #define TX_BUF_SIZE 1536
-
-@@ -39,68 +67,86 @@
- /* The following settings are log_2(bytes)-4: 0 == 16 bytes .. 6==1024. */
- #define RX_FIFO_THRESH 4 /* Rx buffer level before first PCI xfer. */
- #define RX_DMA_BURST 4 /* Maximum PCI burst, '4' is 256 bytes */
--#define TX_DMA_BURST 4
-+#define TX_DMA_BURST 4 /* Calculate as 16<<val. */
-
- /* Operational parameters that usually are not changed. */
- /* Time in jiffies before concluding the transmitter is hung. */
--#define TX_TIMEOUT ((4000*HZ)/1000)
-+#define TX_TIMEOUT (6*HZ)
-
--#ifdef MODULE
--#ifdef MODVERSIONS
--#include <linux/modversions.h>
-+/* Allocation size of Rx buffers with full-sized Ethernet frames.
-+ This is a cross-driver value that is not a limit,
-+ but a way to keep a consistent allocation size among drivers.
-+ */
-+#define PKT_BUF_SZ 1536
-+
-+
-+#ifndef __KERNEL__
-+#define __KERNEL__
- #endif
--#include <linux/module.h>
-+#if !defined(__OPTIMIZE__)
-+#warning You must compile this file with the correct options!
-+#warning See the last lines of the source file.
-+#error You must compile this driver with "-O".
-+#endif
-+
-+#include <linux/config.h>
-+#if defined(CONFIG_SMP) && ! defined(__SMP__)
-+#define __SMP__
-+#endif
-+#if defined(MODULE) && defined(CONFIG_MODVERSIONS) && ! defined(MODVERSIONS)
-+#define MODVERSIONS
-+#endif
-+
- #include <linux/version.h>
--#else
--#define MOD_INC_USE_COUNT
--#define MOD_DEC_USE_COUNT
-+#if defined(MODVERSIONS)
-+#include <linux/modversions.h>
- #endif
-+#include <linux/module.h>
-
- #include <linux/kernel.h>
--#include <linux/sched.h>
- #include <linux/string.h>
- #include <linux/timer.h>
--#include <linux/ptrace.h>
- #include <linux/errno.h>
- #include <linux/ioport.h>
-+#if LINUX_VERSION_CODE >= 0x20400
-+#include <linux/slab.h>
-+#else
- #include <linux/malloc.h>
-+#endif
- #include <linux/interrupt.h>
- #include <linux/pci.h>
--#include <linux/bios32.h>
--#include <asm/processor.h> /* Processor type for cache alignment. */
--#include <asm/bitops.h>
--#include <asm/io.h>
--#include <asm/dma.h>
--
- #include <linux/netdevice.h>
- #include <linux/etherdevice.h>
- #include <linux/skbuff.h>
-+#include <asm/processor.h> /* Processor type for cache alignment. */
-+#include <asm/bitops.h>
-+#include <asm/io.h>
-
--#define RUN_AT(x) (jiffies + (x))
--
--#include <linux/delay.h>
--
--#if (LINUX_VERSION_CODE < 0x20123)
--#define test_and_set_bit(val, addr) set_bit(val, addr)
-+#if LINUX_VERSION_CODE >= 0x20300
-+#include <linux/spinlock.h>
-+#elif LINUX_VERSION_CODE >= 0x20200
-+#include <asm/spinlock.h>
- #endif
-
--/* The I/O extent. */
--#define RTL8129_TOTAL_SIZE 0x80
--
--#ifdef HAVE_DEVLIST
--struct netdev_entry rtl8139_drv =
--{"RTL8139", rtl8139_probe, RTL8129_TOTAL_SIZE, NULL};
-+#ifdef INLINE_PCISCAN
-+#include "k_compat.h"
-+#else
-+#include "pci-scan.h"
-+#include "kern_compat.h"
- #endif
-
--static int rtl8129_debug = 1;
-+#if (LINUX_VERSION_CODE >= 0x20100) && defined(MODULE)
-+char kernel_version[] = UTS_RELEASE;
-+#endif
-
- /*
- Theory of Operation
-
- I. Board Compatibility
-
--This device driver is designed for the RealTek RTL8129, the RealTek Fast
--Ethernet controllers for PCI. This chip is used on a few clone boards.
-+This device driver is designed for the RealTek RTL8129 series, the RealTek
-+Fast Ethernet controllers for PCI and CardBus. This chip is used on many
-+low-end boards, sometimes with custom chip labels.
-
-
- II. Board-specific settings
-@@ -121,15 +167,17 @@
- skbuffs.
-
- Comment: While it is theoretically possible to process many frames in place,
--any delay in Rx processing would cause us to drop frames. More importantly,
--the Linux protocol stack is not designed to operate in this manner.
-+any delay in Rx processing would block the Rx ring and cause us to drop
-+frames. It would be difficult to design a protocol stack where the data
-+buffer could be recalled by the device driver.
-
- IIIb. Tx operation
-
--The RTL8129 uses a fixed set of four Tx descriptors in register space.
--In a stunningly bad design choice, Tx frames must be 32 bit aligned. Linux
--aligns the IP header on word boundaries, and 14 byte ethernet header means
--that almost all frames will need to be copied to an alignment buffer.
-+The RTL8129 uses a fixed set of four Tx descriptors in register space. Tx
-+frames must be 32 bit aligned. Linux aligns the IP header on word
-+boundaries, and 14 byte ethernet header means that almost all frames will
-+need to be copied to an alignment buffer. The driver statically allocates
-+alignment the four alignment buffers at open() time.
-
- IVb. References
-
-@@ -139,15 +187,74 @@
- IVc. Errata
-
- */
-+
-
--#ifndef PCI_VENDOR_ID_REALTEK
--#define PCI_VENDOR_ID_REALTEK 0x10ec
--#endif
--#ifndef PCI_DEVICE_ID_REALTEK_8129
--#define PCI_DEVICE_ID_REALTEK_8129 0x8129
-+static void *rtl8139_probe1(struct pci_dev *pdev, void *init_dev,
-+ long ioaddr, int irq, int chip_idx, int find_cnt);
-+static int rtl_pwr_event(void *dev_instance, int event);
-+
-+enum chip_capability_flags {HAS_MII_XCVR=0x01, HAS_CHIP_XCVR=0x02,
-+ HAS_LNK_CHNG=0x04, HAS_DESC=0x08};
-+#ifdef USE_IO_OPS
-+#define RTL8139_IOTYPE PCI_USES_MASTER|PCI_USES_IO |PCI_ADDR0
-+#else
-+#define RTL8139_IOTYPE PCI_USES_MASTER|PCI_USES_MEM|PCI_ADDR1
- #endif
--#ifndef PCI_DEVICE_ID_REALTEK_8139
--#define PCI_DEVICE_ID_REALTEK_8139 0x8139
-+#define RTL8129_CAPS HAS_MII_XCVR
-+#define RTL8139_CAPS HAS_CHIP_XCVR|HAS_LNK_CHNG
-+#define RTL8139D_CAPS HAS_CHIP_XCVR|HAS_LNK_CHNG|HAS_DESC
-+
-+/* Note: Update the marked constant in _attach() if the RTL8139B entry moves.*/
-+static struct pci_id_info pci_tbl[] = {
-+ {"RealTek RTL8139C+, 64 bit high performance",
-+ { 0x813910ec, 0xffffffff, 0,0, 0x20, 0xff},
-+ RTL8139_IOTYPE, 0x80, RTL8139D_CAPS, },
-+ {"RealTek RTL8139C Fast Ethernet",
-+ { 0x813910ec, 0xffffffff, 0,0, 0x10, 0xff},
-+ RTL8139_IOTYPE, 0x80, RTL8139_CAPS, },
-+ {"RealTek RTL8129 Fast Ethernet", { 0x812910ec, 0xffffffff,},
-+ RTL8139_IOTYPE, 0x80, RTL8129_CAPS, },
-+ {"RealTek RTL8139 Fast Ethernet", { 0x813910ec, 0xffffffff,},
-+ RTL8139_IOTYPE, 0x80, RTL8139_CAPS, },
-+ {"RealTek RTL8139B PCI/CardBus", { 0x813810ec, 0xffffffff,},
-+ RTL8139_IOTYPE, 0x80, RTL8139_CAPS, },
-+ {"SMC1211TX EZCard 10/100 (RealTek RTL8139)", { 0x12111113, 0xffffffff,},
-+ RTL8139_IOTYPE, 0x80, RTL8139_CAPS, },
-+ {"Accton MPX5030 (RealTek RTL8139)", { 0x12111113, 0xffffffff,},
-+ RTL8139_IOTYPE, 0x80, RTL8139_CAPS, },
-+ {"D-Link DFE-530TX+ (RealTek RTL8139C)",
-+ { 0x13001186, 0xffffffff, 0x13011186, 0xffffffff,},
-+ RTL8139_IOTYPE, 0x100, RTL8139_CAPS, },
-+ {"D-Link DFE-538TX (RealTek RTL8139)", { 0x13001186, 0xffffffff,},
-+ RTL8139_IOTYPE, 0x80, RTL8139_CAPS, },
-+ {"LevelOne FPC-0106Tx (RealTek RTL8139)", { 0x0106018a, 0xffffffff,},
-+ RTL8139_IOTYPE, 0x80, RTL8139_CAPS, },
-+ {"Compaq HNE-300 (RealTek RTL8139c)", { 0x8139021b, 0xffffffff,},
-+ RTL8139_IOTYPE, 0x80, RTL8139_CAPS, },
-+ {"Edimax EP-4103DL CardBus (RealTek RTL8139c)", { 0xab0613d1, 0xffffffff,},
-+ RTL8139_IOTYPE, 0x80, RTL8139_CAPS, },
-+ {"Siemens 1012v2 CardBus (RealTek RTL8139c)", { 0x101202ac, 0xffffffff,},
-+ RTL8139_IOTYPE, 0x80, RTL8139_CAPS, },
-+ {0,}, /* 0 terminated list. */
-+};
-+
-+struct drv_id_info rtl8139_drv_id = {
-+ "realtek", PCI_HOTSWAP, PCI_CLASS_NETWORK_ETHERNET<<8, pci_tbl,
-+ rtl8139_probe1, rtl_pwr_event };
-+
-+#ifndef USE_IO_OPS
-+#undef inb
-+#undef inw
-+#undef inl
-+#undef outb
-+#undef outw
-+#undef outl
-+#define inb readb
-+#define inw readw
-+#define inl readl
-+#define outb writeb
-+#define outw writew
-+#define outl writel
- #endif
-
- /* The rest of these values should never change. */
-@@ -157,7 +264,7 @@
- enum RTL8129_registers {
- MAC0=0, /* Ethernet hardware address. */
- MAR0=8, /* Multicast filter. */
-- TxStat0=0x10, /* Transmit status (Four 32bit registers). */
-+ TxStatus0=0x10, /* Transmit status (Four 32bit registers). */
- TxAddr0=0x20, /* Tx descriptors (also four 32bit). */
- RxBuf=0x30, RxEarlyCnt=0x34, RxEarlyStatus=0x36,
- ChipCmd=0x37, RxBufPtr=0x38, RxBufAddr=0x3A,
-@@ -168,9 +275,10 @@
- Cfg9346=0x50, Config0=0x51, Config1=0x52,
- FlashReg=0x54, GPPinData=0x58, GPPinDir=0x59, MII_SMI=0x5A, HltClk=0x5B,
- MultiIntr=0x5C, TxSummary=0x60,
-- BMCR=0x62, BMSR=0x64, NWayAdvert=0x66, NWayLPAR=0x68, NWayExpansion=0x6A,
-+ MII_BMCR=0x62, MII_BMSR=0x64, NWayAdvert=0x66, NWayLPAR=0x68,
-+ NWayExpansion=0x6A,
- /* Undocumented registers, but required for proper operation. */
-- FIFOTMS=0x70, /* FIFO Test Mode Select */
-+ FIFOTMS=0x70, /* FIFO Control and test. */
- CSCR=0x74, /* Chip Status and Configuration Register. */
- PARA78=0x78, PARA7c=0x7c, /* Magic transceiver parameter register. */
- };
-@@ -194,281 +302,240 @@
- RxBadAlign=0x0002, RxStatusOK=0x0001,
- };
-
-+/* Twister tuning parameters from RealTek.
-+ Completely undocumented, but required to tune bad links. */
- enum CSCRBits {
- CSCR_LinkOKBit=0x0400, CSCR_LinkChangeBit=0x0800,
- CSCR_LinkStatusBits=0x0f000, CSCR_LinkDownOffCmd=0x003c0,
- CSCR_LinkDownCmd=0x0f3c0,
--};
--
--/* Twister tuning parameters from RealTek. Completely undocumented. */
-+};
-+#define PARA78_default 0x78fa8388
-+#define PARA7c_default 0xcb38de43 /* param[0][3] */
-+#define PARA7c_xxx 0xcb38de43
- unsigned long param[4][4]={
-- {0x0cb39de43,0x0cb39ce43,0x0fb38de03,0x0cb38de43},
-- {0x0cb39de43,0x0cb39ce43,0x0cb39ce83,0x0cb39ce83},
-- {0x0cb39de43,0x0cb39ce43,0x0cb39ce83,0x0cb39ce83},
-- {0x0bb39de43,0x0bb39ce43,0x0bb39ce83,0x0bb39ce83}
-+ {0xcb39de43, 0xcb39ce43, 0xfb38de03, 0xcb38de43},
-+ {0xcb39de43, 0xcb39ce43, 0xcb39ce83, 0xcb39ce83},
-+ {0xcb39de43, 0xcb39ce43, 0xcb39ce83, 0xcb39ce83},
-+ {0xbb39de43, 0xbb39ce43, 0xbb39ce83, 0xbb39ce83}
- };
-
-+#define PRIV_ALIGN 15 /* Desired alignment mask */
- struct rtl8129_private {
-- char devname[8]; /* Used only for kernel debugging. */
-- const char *product_name;
-- struct device *next_module;
-- int chip_id;
-- int chip_revision;
--#if LINUX_VERSION_CODE > 0x20139
-+ struct net_device *next_module;
-+ void *priv_addr; /* Unaligned address for kfree */
-+
-+ int chip_id, drv_flags;
-+ struct pci_dev *pci_dev;
- struct net_device_stats stats;
--#else
-- struct enet_statistics stats;
--#endif
- struct timer_list timer; /* Media selection timer. */
-- unsigned int cur_rx, cur_tx; /* The next free and used entries */
-- unsigned int dirty_rx, dirty_tx;
-+ int msg_level;
-+ int max_interrupt_work;
-+
-+ /* Receive state. */
-+ unsigned char *rx_ring;
-+ unsigned int cur_rx; /* Index into the Rx buffer of next Rx pkt. */
-+ unsigned int rx_buf_len; /* Size (8K 16K 32K or 64KB) of the Rx ring */
-+
-+ /* Transmit state. */
-+ unsigned int cur_tx, dirty_tx, tx_flag;
-+ unsigned long tx_full; /* The Tx queue is full. */
- /* The saved address of a sent-in-place packet/buffer, for skfree(). */
- struct sk_buff* tx_skbuff[NUM_TX_DESC];
- unsigned char *tx_buf[NUM_TX_DESC]; /* Tx bounce buffers */
-- unsigned char *rx_ring;
- unsigned char *tx_bufs; /* Tx bounce buffer region. */
-- unsigned char mc_filter[8]; /* Current multicast filter. */
-+
-+ /* Receive filter state. */
-+ unsigned int rx_config;
-+ u32 mc_filter[2]; /* Multicast hash filter */
-+ int cur_rx_mode;
-+ int multicast_filter_limit;
-+
-+ /* Transceiver state. */
- char phys[4]; /* MII device addresses. */
-- int in_interrupt; /* Alpha needs word-wide lock. */
-- unsigned int tx_full:1; /* The Tx queue is full. */
-+ u16 advertising; /* NWay media advertisement */
-+ char twistie, twist_row, twist_col; /* Twister tune state. */
-+ u8 config1;
- unsigned int full_duplex:1; /* Full-duplex operation requested. */
-- unsigned int default_port:4; /* Last dev->if_port value. */
-+ unsigned int duplex_lock:1;
- unsigned int media2:4; /* Secondary monitored media port. */
- unsigned int medialock:1; /* Don't sense media type. */
- unsigned int mediasense:1; /* Media sensing in progress. */
-+ unsigned int default_port; /* Last dev->if_port value. */
- };
-
--#ifdef MODULE
--/* Used to pass the full-duplex flag, etc. */
--static int options[] = {-1, -1, -1, -1, -1, -1, -1, -1};
--static int full_duplex[] = {-1, -1, -1, -1, -1, -1, -1, -1};
--#if LINUX_VERSION_CODE > 0x20118
--MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
-+MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
- MODULE_DESCRIPTION("RealTek RTL8129/8139 Fast Ethernet driver");
--MODULE_PARM(debug, "i");
--MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
--MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
-+MODULE_LICENSE("GPL");
-+MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
-+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
-+MODULE_PARM(multicast_filter_limit, "i");
- MODULE_PARM(max_interrupt_work, "i");
--#endif
--#endif
--
--static struct device *rtl8129_probe1(struct device *dev, int ioaddr, int irq,
-- int chip_id, int options, int card_idx);
--static int rtl8129_open(struct device *dev);
--static int read_eeprom(int ioaddr, int location);
--static int mdio_read(int ioaddr, int phy_id, int location);
-+MODULE_PARM(debug, "i");
-+MODULE_PARM_DESC(debug, "Driver message level (0-31)");
-+MODULE_PARM_DESC(options, "Force transceiver type or fixed speed+duplex");
-+MODULE_PARM_DESC(full_duplex, "Non-zero to set forced full duplex.");
-+MODULE_PARM_DESC(multicast_filter_limit,
-+ "Multicast addresses before switching to Rx-all-multicast");
-+MODULE_PARM_DESC(max_interrupt_work,
-+ "Driver maximum events handled per interrupt");
-+
-+static int rtl8129_open(struct net_device *dev);
-+static void rtl_hw_start(struct net_device *dev);
-+static int read_eeprom(long ioaddr, int location, int addr_len);
-+static int mdio_read(struct net_device *dev, int phy_id, int location);
-+static void mdio_write(struct net_device *dev, int phy_id, int location, int val);
- static void rtl8129_timer(unsigned long data);
--static void rtl8129_tx_timeout(struct device *dev);
--static void rtl8129_init_ring(struct device *dev);
--static int rtl8129_start_xmit(struct sk_buff *skb, struct device *dev);
--static int rtl8129_rx(struct device *dev);
-+static void rtl8129_tx_timeout(struct net_device *dev);
-+static void rtl8129_init_ring(struct net_device *dev);
-+static int rtl8129_start_xmit(struct sk_buff *skb, struct net_device *dev);
-+static int rtl8129_rx(struct net_device *dev);
- static void rtl8129_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
--static int rtl8129_close(struct device *dev);
--static struct enet_statistics *rtl8129_get_stats(struct device *dev);
--static void set_rx_mode(struct device *dev);
-+static void rtl_error(struct net_device *dev, int status, int link_status);
-+static int rtl8129_close(struct net_device *dev);
-+static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-+static struct net_device_stats *rtl8129_get_stats(struct net_device *dev);
-+static inline u32 ether_crc(int length, unsigned char *data);
-+static void set_rx_mode(struct net_device *dev);
-
-
--#ifdef MODULE
- /* A list of all installed RTL8129 devices, for removing the driver module. */
--static struct device *root_rtl8129_dev = NULL;
--#endif
-+static struct net_device *root_rtl8129_dev = NULL;
-
--int rtl8139_probe(struct device *dev)
-+#ifndef MODULE
-+int rtl8139_probe(struct net_device *dev)
- {
-- int cards_found = 0;
-- static int pci_index = 0; /* Static, for multiple probe calls. */
--
-- /* Ideally we would detect all network cards in slot order. That would
-- be best done a central PCI probe dispatch, which wouldn't work
-- well with the current structure. So instead we detect just the
-- Rtl81*9 cards in slot order. */
--
-- if (pcibios_present()) {
-- unsigned char pci_bus, pci_device_fn;
--
-- for (;pci_index < 0xff; pci_index++) {
-- u8 pci_irq_line, pci_latency;
-- u16 pci_command, new_command, vendor, device;
-- u32 pci_ioaddr;
--
-- if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8,
--#ifdef REVERSE_PROBE_ORDER
-- 0xff - pci_index,
--#else
-- pci_index,
--#endif
-- &pci_bus, &pci_device_fn)
-- != PCIBIOS_SUCCESSFUL)
-- break;
-- pcibios_read_config_word(pci_bus, pci_device_fn,
-- PCI_VENDOR_ID, &vendor);
-- if (vendor != PCI_VENDOR_ID_REALTEK)
-- continue;
--
-- pcibios_read_config_word(pci_bus, pci_device_fn,
-- PCI_DEVICE_ID, &device);
-- pcibios_read_config_byte(pci_bus, pci_device_fn,
-- PCI_INTERRUPT_LINE, &pci_irq_line);
-- pcibios_read_config_dword(pci_bus, pci_device_fn,
-- PCI_BASE_ADDRESS_0, &pci_ioaddr);
-- /* Remove I/O space marker in bit 0. */
-- pci_ioaddr &= ~3;
--
-- if (device != PCI_DEVICE_ID_REALTEK_8129
-- && device != PCI_DEVICE_ID_REALTEK_8139) {
-- printk(KERN_NOTICE "Unknown RealTek PCI ethernet chip type "
-- "%4.4x detected: not configured.\n", device);
-- continue;
-- }
-- if (check_region(pci_ioaddr, RTL8129_TOTAL_SIZE))
-- continue;
--
-- /* Activate the card: fix for brain-damaged Win98 BIOSes. */
-- pcibios_read_config_word(pci_bus, pci_device_fn,
-- PCI_COMMAND, &pci_command);
-- new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
-- if (pci_command != new_command) {
-- printk(KERN_INFO " The PCI BIOS has not enabled this"
-- " device! Updating PCI config %4.4x->%4.4x.\n",
-- pci_command, new_command);
-- pcibios_write_config_word(pci_bus, pci_device_fn,
-- PCI_COMMAND, new_command);
-- }
--
--#ifdef MODULE
-- dev = rtl8129_probe1(dev, pci_ioaddr, pci_irq_line, device,
-- options[cards_found], cards_found);
--#else
-- dev = rtl8129_probe1(dev, pci_ioaddr, pci_irq_line, device,
-- dev ? dev->mem_start : 0, -1);
--#endif
--
-- if (dev) {
-- pcibios_read_config_byte(pci_bus, pci_device_fn,
-- PCI_LATENCY_TIMER, &pci_latency);
-- if (pci_latency < 32) {
-- printk(KERN_NOTICE" PCI latency timer (CFLT) is "
-- "unreasonably low at %d. Setting to 64 clocks.\n",
-- pci_latency);
-- pcibios_write_config_byte(pci_bus, pci_device_fn,
-- PCI_LATENCY_TIMER, 64);
-- } else if (rtl8129_debug > 1)
-- printk(KERN_INFO" PCI latency timer (CFLT) is %#x.\n",
-- pci_latency);
-- dev = 0;
-- cards_found++;
-- }
-- }
-- }
-+ static int did_version = 0; /* Already printed version info. */
-
--#if defined (MODULE)
-- return cards_found;
--#else
-- return cards_found ? 0 : -ENODEV;
--#endif
-+ if (debug >= NETIF_MSG_DRV /* Emit version even if no cards detected. */
-+ && did_version++ == 0)
-+ printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB);
-+ return pci_drv_register(&rtl8139_drv_id, dev);
- }
-+#endif
-
--static struct device *rtl8129_probe1(struct device *dev, int ioaddr, int irq,
-- int chip_id, int options, int card_idx)
-+static void *rtl8139_probe1(struct pci_dev *pdev, void *init_dev,
-+ long ioaddr, int irq, int chip_idx, int found_cnt)
- {
-- static int did_version = 0; /* Already printed version info. */
-- struct rtl8129_private *tp;
-- int i;
--
-- if (rtl8129_debug > 0 && did_version++ == 0)
-- printk(KERN_INFO "%s", version);
-+ struct net_device *dev;
-+ struct rtl8129_private *np;
-+ void *priv_mem;
-+ int i, option = found_cnt < MAX_UNITS ? options[found_cnt] : 0;
-+ int config1;
-+
-+ dev = init_etherdev(init_dev, 0);
-+ if (!dev)
-+ return NULL;
-
-- dev = init_etherdev(dev, 0);
--
-- printk(KERN_INFO "%s: RealTek RTL%x at %#3x, IRQ %d, ",
-- dev->name, chip_id, ioaddr, irq);
-+ printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ",
-+ dev->name, pci_tbl[chip_idx].name, ioaddr, irq);
-
- /* Bring the chip out of low-power mode. */
-- outb(0x00, ioaddr + Config1);
--
-- /* Perhaps this should be read from the EEPROM? */
-- for (i = 0; i < 6; i++)
-- dev->dev_addr[i] = inb(ioaddr + MAC0 + i);
-+ config1 = inb(ioaddr + Config1);
-+ if (pci_tbl[chip_idx].drv_flags & HAS_MII_XCVR) /* rtl8129 chip */
-+ outb(config1 & ~0x03, ioaddr + Config1);
-+
-+ {
-+ int addr_len = read_eeprom(ioaddr, 0, 8) == 0x8129 ? 8 : 6;
-+ for (i = 0; i < 3; i++)
-+ ((u16 *)(dev->dev_addr))[i] =
-+ le16_to_cpu(read_eeprom(ioaddr, i+7, addr_len));
-+ }
-
- for (i = 0; i < 5; i++)
- printk("%2.2x:", dev->dev_addr[i]);
- printk("%2.2x.\n", dev->dev_addr[i]);
-
-- if (rtl8129_debug > 1) {
-- printk(KERN_INFO "%s: EEPROM contents\n", dev->name);
-- for (i = 0; i < 64; i++)
-- printk(" %4.4x%s", read_eeprom(ioaddr, i),
-- i%16 == 15 ? "\n"KERN_INFO : "");
-- }
-+ /* Make certain elements e.g. descriptor lists are aligned. */
-+ priv_mem = kmalloc(sizeof(*np) + PRIV_ALIGN, GFP_KERNEL);
-+ /* Check for the very unlikely case of no memory. */
-+ if (priv_mem == NULL)
-+ return NULL;
-
- /* We do a request_region() to register /proc/ioports info. */
-- request_region(ioaddr, RTL8129_TOTAL_SIZE, "RealTek RTL8129/39 Fast Ethernet");
-+ request_region(ioaddr, pci_tbl[chip_idx].io_size, dev->name);
-
- dev->base_addr = ioaddr;
- dev->irq = irq;
-
-- /* Some data structures must be quadword aligned. */
-- tp = kmalloc(sizeof(*tp), GFP_KERNEL | GFP_DMA);
-- memset(tp, 0, sizeof(*tp));
-- dev->priv = tp;
-+ dev->priv = np = (void *)(((long)priv_mem + PRIV_ALIGN) & ~PRIV_ALIGN);
-+ memset(np, 0, sizeof(*np));
-+ np->priv_addr = priv_mem;
-
--#ifdef MODULE
-- tp->next_module = root_rtl8129_dev;
-+ np->next_module = root_rtl8129_dev;
- root_rtl8129_dev = dev;
--#endif
-
-- tp->chip_id = chip_id;
-+ np->pci_dev = pdev;
-+ np->chip_id = chip_idx;
-+ np->drv_flags = pci_tbl[chip_idx].drv_flags;
-+ np->msg_level = (1 << debug) - 1;
-+ np->max_interrupt_work = max_interrupt_work;
-+ np->multicast_filter_limit = multicast_filter_limit;
-+
-+ np->config1 = config1;
-
- /* Find the connected MII xcvrs.
- Doing this in open() would allow detecting external xcvrs later, but
- takes too much time. */
-- if (chip_id == 0x8129) {
-- int phy, phy_idx;
-- for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(tp->phys);
-- phy++) {
-- int mii_status = mdio_read(ioaddr, phy, 1);
--
-- if (mii_status != 0xffff && mii_status != 0x0000) {
-- tp->phys[phy_idx++] = phy;
-- printk(KERN_INFO "%s: MII transceiver found at address %d.\n",
-- dev->name, phy);
-+ if (np->drv_flags & HAS_MII_XCVR) {
-+ int phy, phy_idx = 0;
-+ for (phy = 0; phy < 32 && phy_idx < sizeof(np->phys); phy++) {
-+ int mii_status = mdio_read(dev, phy, 1);
-+ if (mii_status != 0xffff && mii_status != 0x0000) {
-+ np->phys[phy_idx++] = phy;
-+ np->advertising = mdio_read(dev, phy, 4);
-+ printk(KERN_INFO "%s: MII transceiver %d status 0x%4.4x "
-+ "advertising %4.4x.\n",
-+ dev->name, phy, mii_status, np->advertising);
- }
- }
- if (phy_idx == 0) {
- printk(KERN_INFO "%s: No MII transceivers found! Assuming SYM "
- "transceiver.\n",
- dev->name);
-- tp->phys[0] = -1;
-+ np->phys[0] = 32;
- }
-- } else {
-- tp->phys[0] = -1;
-- }
-+ } else
-+ np->phys[0] = 32;
-
- /* Put the chip into low-power mode. */
- outb(0xC0, ioaddr + Cfg9346);
-- outb(0x03, ioaddr + Config1);
-+ if (np->drv_flags & HAS_MII_XCVR) /* rtl8129 chip */
-+ outb(0x03, ioaddr + Config1);
-+
- outb('H', ioaddr + HltClk); /* 'R' would leave the clock running. */
-
- /* The lower four bits are the media type. */
-- if (options > 0) {
-- tp->full_duplex = (options & 16) ? 1 : 0;
-- tp->default_port = options & 15;
-- if (tp->default_port)
-- tp->medialock = 1;
-- }
--#ifdef MODULE
-- if (card_idx >= 0) {
-- if (full_duplex[card_idx] >= 0)
-- tp->full_duplex = full_duplex[card_idx];
-+ if (option > 0) {
-+ np->full_duplex = (option & 0x220) ? 1 : 0;
-+ np->default_port = option & 0x330;
-+ if (np->default_port)
-+ np->medialock = 1;
-+ }
-+
-+ if (found_cnt < MAX_UNITS && full_duplex[found_cnt] > 0)
-+ np->full_duplex = full_duplex[found_cnt];
-+
-+ if (np->full_duplex) {
-+ printk(KERN_INFO "%s: Media type forced to Full Duplex.\n", dev->name);
-+ /* Changing the MII-advertised media might prevent re-connection. */
-+ np->duplex_lock = 1;
-+ }
-+ if (np->default_port) {
-+ printk(KERN_INFO " Forcing %dMbs %s-duplex operation.\n",
-+ (option & 0x300 ? 100 : 10),
-+ (option & 0x220 ? "full" : "half"));
-+ mdio_write(dev, np->phys[0], 0,
-+ ((option & 0x300) ? 0x2000 : 0) | /* 100mbps? */
-+ ((option & 0x220) ? 0x0100 : 0)); /* Full duplex? */
- }
--#endif
-
-- /* The Rtl8129-specific entries in the device structure. */
-+ /* The rtl81x9-specific entries in the device structure. */
- dev->open = &rtl8129_open;
- dev->hard_start_xmit = &rtl8129_start_xmit;
- dev->stop = &rtl8129_close;
- dev->get_stats = &rtl8129_get_stats;
- dev->set_multicast_list = &set_rx_mode;
-+ dev->do_ioctl = &mii_ioctl;
-
- return dev;
- }
-@@ -485,48 +552,43 @@
- #define EE_ENB (0x80 | EE_CS)
-
- /* Delay between EEPROM clock transitions.
-- No extra delay is needed with 33Mhz PCI, but 66Mhz is untested.
-+ No extra delay is needed with 33Mhz PCI, but 66Mhz may change this.
- */
-
--#ifdef _LINUX_DELAY_H
--#define eeprom_delay(nanosec) udelay(1)
--#else
--#define eeprom_delay(nanosec) do { ; } while (0)
--#endif
-+#define eeprom_delay() inl(ee_addr)
-
- /* The EEPROM commands include the alway-set leading bit. */
--#define EE_WRITE_CMD (5 << 6)
--#define EE_READ_CMD (6 << 6)
--#define EE_ERASE_CMD (7 << 6)
-+#define EE_WRITE_CMD (5)
-+#define EE_READ_CMD (6)
-+#define EE_ERASE_CMD (7)
-
--static int read_eeprom(int ioaddr, int location)
-+static int read_eeprom(long ioaddr, int location, int addr_len)
- {
- int i;
- unsigned retval = 0;
-- int ee_addr = ioaddr + Cfg9346;
-- int read_cmd = location | EE_READ_CMD;
-+ long ee_addr = ioaddr + Cfg9346;
-+ int read_cmd = location | (EE_READ_CMD << addr_len);
-
- outb(EE_ENB & ~EE_CS, ee_addr);
- outb(EE_ENB, ee_addr);
-
- /* Shift the read command bits out. */
-- for (i = 10; i >= 0; i--) {
-+ for (i = 4 + addr_len; i >= 0; i--) {
- int dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
- outb(EE_ENB | dataval, ee_addr);
-- eeprom_delay(100);
-+ eeprom_delay();
- outb(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
-- eeprom_delay(150);
-- outb(EE_ENB | dataval, ee_addr); /* Finish EEPROM a clock tick. */
-- eeprom_delay(250);
-+ eeprom_delay();
- }
- outb(EE_ENB, ee_addr);
-+ eeprom_delay();
-
- for (i = 16; i > 0; i--) {
- outb(EE_ENB | EE_SHIFT_CLK, ee_addr);
-- eeprom_delay(100);
-+ eeprom_delay();
- retval = (retval << 1) | ((inb(ee_addr) & EE_DATA_READ) ? 1 : 0);
- outb(EE_ENB, ee_addr);
-- eeprom_delay(100);
-+ eeprom_delay();
- }
-
- /* Terminate the EEPROM access. */
-@@ -544,288 +606,402 @@
- #define MDIO_DATA_OUT 0x04
- #define MDIO_DATA_IN 0x02
- #define MDIO_CLK 0x01
--#ifdef _LINUX_DELAY_H
--#define mdio_delay() udelay(1) /* Really 400ns. */
--#else
--#define mdio_delay() do { ; } while (0)
--#endif
-+#define MDIO_WRITE0 (MDIO_DIR)
-+#define MDIO_WRITE1 (MDIO_DIR | MDIO_DATA_OUT)
-+
-+#define mdio_delay(mdio_addr) inb(mdio_addr)
-+
-+static char mii_2_8139_map[8] = {MII_BMCR, MII_BMSR, 0, 0, NWayAdvert,
-+ NWayLPAR, NWayExpansion, 0 };
-
- /* Syncronize the MII management interface by shifting 32 one bits out. */
--static void mdio_sync(int ioaddr)
-+static void mdio_sync(long mdio_addr)
- {
- int i;
-- int mdio_addr = ioaddr + MII_SMI;
-
- for (i = 32; i >= 0; i--) {
-- outb(MDIO_DIR | MDIO_DATA_OUT, mdio_addr);
-- mdio_delay();
-- outb(MDIO_DIR | MDIO_DATA_OUT | MDIO_CLK, mdio_addr);
-- mdio_delay();
-+ outb(MDIO_WRITE1, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ outb(MDIO_WRITE1 | MDIO_CLK, mdio_addr);
-+ mdio_delay(mdio_addr);
- }
- return;
- }
--static int mdio_read(int ioaddr, int phy_id, int location)
-+static int mdio_read(struct net_device *dev, int phy_id, int location)
- {
-- int i;
-- int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
-+ long mdio_addr = dev->base_addr + MII_SMI;
-+ int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;
- int retval = 0;
-- int mdio_addr = ioaddr + MII_SMI;
-+ int i;
-
-- mdio_sync(ioaddr);
-+ if (phy_id > 31) { /* Really a 8139. Use internal registers. */
-+ return location < 8 && mii_2_8139_map[location] ?
-+ inw(dev->base_addr + mii_2_8139_map[location]) : 0;
-+ }
-+ mdio_sync(mdio_addr);
- /* Shift the read command bits out. */
- for (i = 15; i >= 0; i--) {
-- int dataval =
-- (read_cmd & (1 << i)) ? MDIO_DATA_OUT : 0;
-+ int dataval = (mii_cmd & (1 << i)) ? MDIO_DATA_OUT : 0;
-
- outb(MDIO_DIR | dataval, mdio_addr);
-- mdio_delay();
-+ mdio_delay(mdio_addr);
- outb(MDIO_DIR | dataval | MDIO_CLK, mdio_addr);
-- mdio_delay();
-+ mdio_delay(mdio_addr);
- }
-
- /* Read the two transition, 16 data, and wire-idle bits. */
- for (i = 19; i > 0; i--) {
- outb(0, mdio_addr);
-- mdio_delay();
-+ mdio_delay(mdio_addr);
- retval = (retval << 1) | ((inb(mdio_addr) & MDIO_DATA_IN) ? 1 : 0);
- outb(MDIO_CLK, mdio_addr);
-- mdio_delay();
-+ mdio_delay(mdio_addr);
- }
- return (retval>>1) & 0xffff;
- }
--
--static int
--rtl8129_open(struct device *dev)
-+
-+static void mdio_write(struct net_device *dev, int phy_id, int location,
-+ int value)
- {
-- struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
-- int ioaddr = dev->base_addr;
-+ long mdio_addr = dev->base_addr + MII_SMI;
-+ int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;
- int i;
-- int full_duplex = 0;
-
-- /* Soft reset the chip. */
-- outb(CmdReset, ioaddr + ChipCmd);
-+ if (phy_id > 31) { /* Really a 8139. Use internal registers. */
-+ long ioaddr = dev->base_addr;
-+ if (location == 0) {
-+ outb(0xC0, ioaddr + Cfg9346);
-+ outw(value, ioaddr + MII_BMCR);
-+ outb(0x00, ioaddr + Cfg9346);
-+ } else if (location < 8 && mii_2_8139_map[location])
-+ outw(value, ioaddr + mii_2_8139_map[location]);
-+ return;
-+ }
-+ mdio_sync(mdio_addr);
-+
-+ /* Shift the command bits out. */
-+ for (i = 31; i >= 0; i--) {
-+ int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
-+ outb(dataval, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ outb(dataval | MDIO_CLK, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ }
-+ /* Clear out extra bits. */
-+ for (i = 2; i > 0; i--) {
-+ outb(0, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ outb(MDIO_CLK, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ }
-+ return;
-+}
-+
-+
-+static int rtl8129_open(struct net_device *dev)
-+{
-+ struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+ int rx_buf_len_idx;
-
-+ MOD_INC_USE_COUNT;
- if (request_irq(dev->irq, &rtl8129_interrupt, SA_SHIRQ, dev->name, dev)) {
-+ MOD_DEC_USE_COUNT;
- return -EAGAIN;
- }
-
-- MOD_INC_USE_COUNT;
-+ /* The Rx ring allocation size is 2^N + delta, which is worst-case for
-+ the kernel binary-buddy allocation. We allocate the Tx bounce buffers
-+ at the same time to use some of the otherwise wasted space.
-+ The delta of +16 is required for dribble-over because the receiver does
-+ not wrap when the packet terminates just beyond the end of the ring. */
-+ rx_buf_len_idx = RX_BUF_LEN_IDX;
-+ do {
-+ tp->rx_buf_len = 8192 << rx_buf_len_idx;
-+ tp->rx_ring = kmalloc(tp->rx_buf_len + 16 +
-+ (TX_BUF_SIZE * NUM_TX_DESC), GFP_KERNEL);
-+ } while (tp->rx_ring == NULL && --rx_buf_len_idx >= 0);
-
-- tp->tx_bufs = kmalloc(TX_BUF_SIZE * NUM_TX_DESC, GFP_KERNEL);
-- tp->rx_ring = kmalloc(RX_BUF_LEN + 16, GFP_KERNEL);
-- if (tp->tx_bufs == NULL || tp->rx_ring == NULL) {
-- free_irq (dev->irq, dev);
-- if (tp->tx_bufs)
-- kfree(tp->tx_bufs);
-- if (rtl8129_debug > 0)
-+ if (tp->rx_ring == NULL) {
-+ if (debug > 0)
- printk(KERN_ERR "%s: Couldn't allocate a %d byte receive ring.\n",
-- dev->name, RX_BUF_LEN);
-+ dev->name, tp->rx_buf_len);
-+ MOD_DEC_USE_COUNT;
- return -ENOMEM;
- }
-+ tp->tx_bufs = tp->rx_ring + tp->rx_buf_len + 16;
-+
- rtl8129_init_ring(dev);
-+ tp->full_duplex = tp->duplex_lock;
-+ tp->tx_flag = (TX_FIFO_THRESH<<11) & 0x003f0000;
-+ tp->rx_config =
-+ (RX_FIFO_THRESH << 13) | (rx_buf_len_idx << 11) | (RX_DMA_BURST<<8);
-+
-+ rtl_hw_start(dev);
-+ netif_start_tx_queue(dev);
-+
-+ if (tp->msg_level & NETIF_MSG_IFUP)
-+ printk(KERN_DEBUG"%s: rtl8129_open() ioaddr %#lx IRQ %d"
-+ " GP Pins %2.2x %s-duplex.\n",
-+ dev->name, ioaddr, dev->irq, inb(ioaddr + GPPinData),
-+ tp->full_duplex ? "full" : "half");
-
-+ /* Set the timer to switch to check for link beat and perhaps switch
-+ to an alternate media type. */
-+ init_timer(&tp->timer);
-+ tp->timer.expires = jiffies + 3*HZ;
-+ tp->timer.data = (unsigned long)dev;
-+ tp->timer.function = &rtl8129_timer;
-+ add_timer(&tp->timer);
-+
-+ return 0;
-+}
-+
-+/* Start the hardware at open or resume. */
-+static void rtl_hw_start(struct net_device *dev)
-+{
-+ struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+ int i;
-+
-+ /* Soft reset the chip. */
-+ outb(CmdReset, ioaddr + ChipCmd);
- /* Check that the chip has finished the reset. */
- for (i = 1000; i > 0; i--)
- if ((inb(ioaddr + ChipCmd) & CmdReset) == 0)
- break;
-+ /* Restore our idea of the MAC address. */
-+ outb(0xC0, ioaddr + Cfg9346);
-+ outl(cpu_to_le32(*(u32*)(dev->dev_addr + 0)), ioaddr + MAC0 + 0);
-+ outl(cpu_to_le32(*(u32*)(dev->dev_addr + 4)), ioaddr + MAC0 + 4);
-
-- for (i = 0; i < 6; i++)
-- outb(dev->dev_addr[i], ioaddr + MAC0 + i);
-+ /* Hmmm, do these belong here? */
-+ tp->cur_rx = 0;
-
- /* Must enable Tx/Rx before setting transfer thresholds! */
- outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);
-- outl((RX_FIFO_THRESH << 13) | (RX_BUF_LEN_IDX << 11) | (RX_DMA_BURST<<8),
-- ioaddr + RxConfig);
-- outl((TX_DMA_BURST<<8)|0x03000000, ioaddr + TxConfig);
--
-- full_duplex = tp->full_duplex;
-- if (tp->phys[0] >= 0 || tp->chip_id == 0x8139) {
-- u16 mii_reg5;
-- if (tp->chip_id == 0x8139)
-- mii_reg5 = inw(ioaddr + NWayLPAR);
-- else
-- mii_reg5 = mdio_read(ioaddr, tp->phys[0], 5);
-+ outl(tp->rx_config, ioaddr + RxConfig);
-+ /* Check this value: the documentation contradicts ifself. Is the
-+ IFG correct with bit 28:27 zero, or with |0x03000000 ? */
-+ outl((TX_DMA_BURST<<8), ioaddr + TxConfig);
-+
-+ /* This is check_duplex() */
-+ if (tp->phys[0] >= 0 || (tp->drv_flags & HAS_MII_XCVR)) {
-+ u16 mii_reg5 = mdio_read(dev, tp->phys[0], 5);
- if (mii_reg5 == 0xffff)
- ; /* Not there */
- else if ((mii_reg5 & 0x0100) == 0x0100
- || (mii_reg5 & 0x00C0) == 0x0040)
-- full_duplex = 1;
-- if (rtl8129_debug > 1)
-+ tp->full_duplex = 1;
-+ if (tp->msg_level & NETIF_MSG_LINK)
- printk(KERN_INFO"%s: Setting %s%s-duplex based on"
- " auto-negotiated partner ability %4.4x.\n", dev->name,
- mii_reg5 == 0 ? "" :
- (mii_reg5 & 0x0180) ? "100mbps " : "10mbps ",
-- full_duplex ? "full" : "half", mii_reg5);
-+ tp->full_duplex ? "full" : "half", mii_reg5);
- }
-
-- outb(0xC0, ioaddr + Cfg9346);
-- outb(full_duplex ? 0x60 : 0x20, ioaddr + Config1);
-+ if (tp->drv_flags & HAS_MII_XCVR) /* rtl8129 chip */
-+ outb(tp->full_duplex ? 0x60 : 0x20, ioaddr + Config1);
- outb(0x00, ioaddr + Cfg9346);
-
- outl(virt_to_bus(tp->rx_ring), ioaddr + RxBuf);
--
- /* Start the chip's Tx and Rx process. */
- outl(0, ioaddr + RxMissed);
- set_rx_mode(dev);
--
- outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);
--
-- dev->tbusy = 0;
-- dev->interrupt = 0;
-- dev->start = 1;
--
- /* Enable all known interrupts by setting the interrupt mask. */
- outw(PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver
-- | TxErr | TxOK | RxErr | RxOK, ioaddr + IntrMask);
--
-- if (rtl8129_debug > 1)
-- printk(KERN_DEBUG"%s: rtl8129_open() ioaddr %4.4x IRQ %d"
-- " GP Pins %2.2x %s-duplex.\n",
-- dev->name, ioaddr, dev->irq, inb(ioaddr + GPPinData),
-- full_duplex ? "full" : "half");
--
-- /* Set the timer to switch to check for link beat and perhaps switch
-- to an alternate media type. */
-- init_timer(&tp->timer);
-- tp->timer.expires = RUN_AT((24*HZ)/10); /* 2.4 sec. */
-- tp->timer.data = (unsigned long)dev;
-- tp->timer.function = &rtl8129_timer; /* timer handler */
-- add_timer(&tp->timer);
-+ | TxErr | TxOK | RxErr | RxOK, ioaddr + IntrMask);
-
-- return 0;
- }
-
- static void rtl8129_timer(unsigned long data)
- {
-- struct device *dev = (struct device *)data;
-- struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
-- int ioaddr = dev->base_addr;
-- int next_tick = 0;
--
-- if (tp->chip_id == 0x8139) {
-- u16 mii_reg5 = inw(ioaddr + NWayLPAR);
-- if ((mii_reg5 & 0x0100) == 0x0100
-- || (mii_reg5 & 0x00C0) == 0x0040)
-- if ( ! tp->full_duplex) {
-- tp->full_duplex = 1;
-- if (rtl8129_debug > 0)
-- printk(KERN_INFO "%s: Switching to full-duplex based on "
-- "link partner ability of %4.4x.\n",
-- dev->name, mii_reg5);
-+ struct net_device *dev = (struct net_device *)data;
-+ struct rtl8129_private *np = (struct rtl8129_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+ int next_tick = 60*HZ;
-+ int mii_reg5 = mdio_read(dev, np->phys[0], 5);
-+
-+ if (! np->duplex_lock && mii_reg5 != 0xffff) {
-+ int duplex = (mii_reg5&0x0100) || (mii_reg5 & 0x01C0) == 0x0040;
-+ if (np->full_duplex != duplex) {
-+ np->full_duplex = duplex;
-+ printk(KERN_INFO "%s: Using %s-duplex based on MII #%d link"
-+ " partner ability of %4.4x.\n", dev->name,
-+ np->full_duplex ? "full" : "half", np->phys[0], mii_reg5);
-+ if (np->drv_flags & HAS_MII_XCVR) {
- outb(0xC0, ioaddr + Cfg9346);
-- outb(tp->full_duplex ? 0x60 : 0x20, ioaddr + Config1);
-+ outb(np->full_duplex ? 0x60 : 0x20, ioaddr + Config1);
- outb(0x00, ioaddr + Cfg9346);
- }
-+ }
- }
-- if (rtl8129_debug > 2) {
-- if (tp->chip_id == 0x8129)
-+#if LINUX_VERSION_CODE < 0x20300
-+ /* Check for bogusness. */
-+ if (inw(ioaddr + IntrStatus) & (TxOK | RxOK)) {
-+ int status = inw(ioaddr + IntrStatus); /* Double check */
-+ if (status & (TxOK | RxOK) && ! dev->interrupt) {
-+ printk(KERN_ERR "%s: RTL8139 Interrupt line blocked, status %x.\n",
-+ dev->name, status);
-+ rtl8129_interrupt(dev->irq, dev, 0);
-+ }
-+ }
-+ if (dev->tbusy && jiffies - dev->trans_start >= 2*TX_TIMEOUT)
-+ rtl8129_tx_timeout(dev);
-+#else
-+ if (netif_queue_paused(dev) &&
-+ np->cur_tx - np->dirty_tx > 1 &&
-+ (jiffies - dev->trans_start) > TX_TIMEOUT) {
-+ rtl8129_tx_timeout(dev);
-+ }
-+#endif
-+
-+#if defined(RTL_TUNE_TWISTER)
-+ /* This is a complicated state machine to configure the "twister" for
-+ impedance/echos based on the cable length.
-+ All of this is magic and undocumented.
-+ */
-+ if (np->twistie) switch(np->twistie) {
-+ case 1: {
-+ if (inw(ioaddr + CSCR) & CSCR_LinkOKBit) {
-+ /* We have link beat, let us tune the twister. */
-+ outw(CSCR_LinkDownOffCmd, ioaddr + CSCR);
-+ np->twistie = 2; /* Change to state 2. */
-+ next_tick = HZ/10;
-+ } else {
-+ /* Just put in some reasonable defaults for when beat returns. */
-+ outw(CSCR_LinkDownCmd, ioaddr + CSCR);
-+ outl(0x20,ioaddr + FIFOTMS); /* Turn on cable test mode. */
-+ outl(PARA78_default ,ioaddr + PARA78);
-+ outl(PARA7c_default ,ioaddr + PARA7c);
-+ np->twistie = 0; /* Bail from future actions. */
-+ }
-+ } break;
-+ case 2: {
-+ /* Read how long it took to hear the echo. */
-+ int linkcase = inw(ioaddr + CSCR) & CSCR_LinkStatusBits;
-+ if (linkcase == 0x7000) np->twist_row = 3;
-+ else if (linkcase == 0x3000) np->twist_row = 2;
-+ else if (linkcase == 0x1000) np->twist_row = 1;
-+ else np->twist_row = 0;
-+ np->twist_col = 0;
-+ np->twistie = 3; /* Change to state 2. */
-+ next_tick = HZ/10;
-+ } break;
-+ case 3: {
-+ /* Put out four tuning parameters, one per 100msec. */
-+ if (np->twist_col == 0) outw(0, ioaddr + FIFOTMS);
-+ outl(param[(int)np->twist_row][(int)np->twist_col], ioaddr + PARA7c);
-+ next_tick = HZ/10;
-+ if (++np->twist_col >= 4) {
-+ /* For short cables we are done.
-+ For long cables (row == 3) check for mistune. */
-+ np->twistie = (np->twist_row == 3) ? 4 : 0;
-+ }
-+ } break;
-+ case 4: {
-+ /* Special case for long cables: check for mistune. */
-+ if ((inw(ioaddr + CSCR) & CSCR_LinkStatusBits) == 0x7000) {
-+ np->twistie = 0;
-+ break;
-+ } else {
-+ outl(0xfb38de03, ioaddr + PARA7c);
-+ np->twistie = 5;
-+ next_tick = HZ/10;
-+ }
-+ } break;
-+ case 5: {
-+ /* Retune for shorter cable (column 2). */
-+ outl(0x20,ioaddr + FIFOTMS);
-+ outl(PARA78_default, ioaddr + PARA78);
-+ outl(PARA7c_default, ioaddr + PARA7c);
-+ outl(0x00,ioaddr + FIFOTMS);
-+ np->twist_row = 2;
-+ np->twist_col = 0;
-+ np->twistie = 3;
-+ next_tick = HZ/10;
-+ } break;
-+ }
-+#endif
-+
-+ if (np->msg_level & NETIF_MSG_TIMER) {
-+ if (np->drv_flags & HAS_MII_XCVR)
- printk(KERN_DEBUG"%s: Media selection tick, GP pins %2.2x.\n",
- dev->name, inb(ioaddr + GPPinData));
- else
- printk(KERN_DEBUG"%s: Media selection tick, Link partner %4.4x.\n",
- dev->name, inw(ioaddr + NWayLPAR));
-- printk(KERN_DEBUG"%s: Other registers are IntMask %4.4x IntStatus %4.4x"
-- " RxStatus %4.4x.\n",
-+ printk(KERN_DEBUG"%s: Other registers are IntMask %4.4x "
-+ "IntStatus %4.4x RxStatus %4.4x.\n",
- dev->name, inw(ioaddr + IntrMask), inw(ioaddr + IntrStatus),
-- inl(ioaddr + RxEarlyStatus));
-+ (int)inl(ioaddr + RxEarlyStatus));
- printk(KERN_DEBUG"%s: Chip config %2.2x %2.2x.\n",
- dev->name, inb(ioaddr + Config0), inb(ioaddr + Config1));
- }
-
-- if (next_tick) {
-- tp->timer.expires = RUN_AT(next_tick);
-- add_timer(&tp->timer);
-- }
-+ np->timer.expires = jiffies + next_tick;
-+ add_timer(&np->timer);
- }
-
--static void rtl8129_tx_timeout(struct device *dev)
-+static void rtl8129_tx_timeout(struct net_device *dev)
- {
- struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
-- int ioaddr = dev->base_addr;
-- int i;
-+ long ioaddr = dev->base_addr;
-+ int status = inw(ioaddr + IntrStatus);
-+ int mii_reg, i;
-+
-+ /* Could be wrapped with if (tp->msg_level & NETIF_MSG_TX_ERR) */
-+ printk(KERN_ERR "%s: Transmit timeout, status %2.2x %4.4x "
-+ "media %2.2x.\n",
-+ dev->name, inb(ioaddr + ChipCmd), status, inb(ioaddr + GPPinData));
-+
-+ if (status & (TxOK | RxOK)) {
-+ printk(KERN_ERR "%s: RTL8139 Interrupt line blocked, status %x.\n",
-+ dev->name, status);
-+ }
-
- /* Disable interrupts by clearing the interrupt mask. */
- outw(0x0000, ioaddr + IntrMask);
--
-- if (rtl8129_debug > 0)
-- printk(KERN_WARNING "%s: Transmit timeout, status %2.2x %4.4x.\n",
-- dev->name, inb(ioaddr + ChipCmd), inw(ioaddr + IntrStatus));
- /* Emit info to figure out what went wrong. */
-+ printk(KERN_DEBUG "%s: Tx queue start entry %d dirty entry %d%s.\n",
-+ dev->name, tp->cur_tx, tp->dirty_tx, tp->tx_full ? ", full" : "");
- for (i = 0; i < NUM_TX_DESC; i++)
-- printk(KERN_DEBUG"%s: Tx descriptor %d is %8.8x.%s\n",
-- dev->name, i, inl(ioaddr + TxStat0 + i*4),
-+ printk(KERN_DEBUG "%s: Tx descriptor %d is %8.8x.%s\n",
-+ dev->name, i, (int)inl(ioaddr + TxStatus0 + i*4),
- i == tp->dirty_tx % NUM_TX_DESC ? " (queue head)" : "");
-- if (tp->chip_id == 0x8129) {
-- int mii_reg;
-- printk(KERN_DEBUG"%s: MII #%d registers are:", dev->name, tp->phys[0]);
-- for (mii_reg = 0; mii_reg < 8; mii_reg++)
-- printk(" %4.4x", mdio_read(ioaddr, tp->phys[0], mii_reg));
-- printk(".\n");
-- } else {
-- printk(KERN_DEBUG"%s: MII status register is %4.4x.\n",
-- dev->name, inw(ioaddr + BMSR));
-- }
--
-- /* Soft reset the chip. */
-- outb(CmdReset, ioaddr + ChipCmd);
-- for (i = 0; i < 6; i++)
-- outb(dev->dev_addr[i], ioaddr + MAC0 + i);
--
-- { /* Save the unsent Tx packets. */
-- struct sk_buff *saved_skb[NUM_TX_DESC], *skb;
-- int j = 0;
-- for (; tp->cur_tx - tp->dirty_tx > 0 ; tp->dirty_tx++)
-- saved_skb[j++] = tp->tx_skbuff[tp->dirty_tx % NUM_TX_DESC];
-- tp->dirty_tx = tp->cur_tx = 0;
--
-- for (i = 0; i < j; i++) {
-- skb = tp->tx_skbuff[i] = saved_skb[i];
-- if ((long)skb->data & 3) { /* Must use alignment buffer. */
-- memcpy(tp->tx_buf[i], skb->data, skb->len);
-- outl(virt_to_bus(tp->tx_buf[i]), ioaddr + TxAddr0 + i*4);
-- } else
-- outl(virt_to_bus(skb->data), ioaddr + TxAddr0 + i*4);
-- /* Note: the chip doesn't have auto-pad! */
-- outl(((TX_FIFO_THRESH<<11) & 0x003f0000) |
-- (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN),
-- ioaddr + TxStat0 + i*4);
-- }
-- tp->cur_tx = i;
-- while (i < NUM_TX_DESC)
-+ printk(KERN_DEBUG "%s: MII #%d registers are:", dev->name, tp->phys[0]);
-+ for (mii_reg = 0; mii_reg < 8; mii_reg++)
-+ printk(" %4.4x", mdio_read(dev, tp->phys[0], mii_reg));
-+ printk(".\n");
-+
-+ /* Stop a shared interrupt from scavenging while we are. */
-+ tp->dirty_tx = tp->cur_tx = 0;
-+ /* Dump the unsent Tx packets. */
-+ for (i = 0; i < NUM_TX_DESC; i++) {
-+ if (tp->tx_skbuff[i]) {
-+ dev_free_skb(tp->tx_skbuff[i]);
- tp->tx_skbuff[i] = 0;
-- if (tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) {/* Typical path */
-- dev->tbusy = 0;
-- } else {
-- tp->tx_full = 1;
-+ tp->stats.tx_dropped++;
- }
- }
--
-- /* Must enable Tx/Rx before setting transfer thresholds! */
-- set_rx_mode(dev);
-- outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);
-- outl((RX_FIFO_THRESH << 13) | (RX_BUF_LEN_IDX << 11) | (RX_DMA_BURST<<8),
-- ioaddr + RxConfig);
-- outl((TX_DMA_BURST<<8), ioaddr + TxConfig);
--
-- dev->trans_start = jiffies;
-- tp->stats.tx_errors++;
-- /* Enable all known interrupts by setting the interrupt mask. */
-- outw(PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver
-- | TxErr | TxOK | RxErr | RxOK, ioaddr + IntrMask);
-+ rtl_hw_start(dev);
-+ netif_unpause_tx_queue(dev);
-+ tp->tx_full = 0;
- return;
- }
-
-
- /* Initialize the Rx and Tx rings, along with various 'dev' bits. */
- static void
--rtl8129_init_ring(struct device *dev)
-+rtl8129_init_ring(struct net_device *dev)
- {
- struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
- int i;
-
- tp->tx_full = 0;
-- tp->cur_rx = tp->cur_tx = 0;
-- tp->dirty_rx = tp->dirty_tx = 0;
-+ tp->dirty_tx = tp->cur_tx = 0;
-
- for (i = 0; i < NUM_TX_DESC; i++) {
- tp->tx_skbuff[i] = 0;
-@@ -834,18 +1010,16 @@
- }
-
- static int
--rtl8129_start_xmit(struct sk_buff *skb, struct device *dev)
-+rtl8129_start_xmit(struct sk_buff *skb, struct net_device *dev)
- {
- struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
-- int ioaddr = dev->base_addr;
-+ long ioaddr = dev->base_addr;
- int entry;
-
-- /* Block a timer-based transmit from overlapping. This could better be
-- done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
-- if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
-- if (jiffies - dev->trans_start < TX_TIMEOUT)
-- return 1;
-- rtl8129_tx_timeout(dev);
-+ if (netif_pause_tx_queue(dev) != 0) {
-+ /* This watchdog code is redundant with the media monitor timer. */
-+ if (jiffies - dev->trans_start > TX_TIMEOUT)
-+ rtl8129_tx_timeout(dev);
- return 1;
- }
-
-@@ -859,20 +1033,26 @@
- } else
- outl(virt_to_bus(skb->data), ioaddr + TxAddr0 + entry*4);
- /* Note: the chip doesn't have auto-pad! */
-- outl(((TX_FIFO_THRESH<<11) & 0x003f0000) |
-- (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN),
-- ioaddr + TxStat0 + entry*4);
-+ outl(tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN),
-+ ioaddr + TxStatus0 + entry*4);
-
-- if (++tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) {/* Typical path */
-- dev->tbusy = 0;
-- } else {
-- tp->tx_full = 1;
-- }
-+ /* There is a race condition here -- we might read dirty_tx, take an
-+ interrupt that clears the Tx queue, and only then set tx_full.
-+ So we do this in two phases. */
-+ if (++tp->cur_tx - tp->dirty_tx >= NUM_TX_DESC) {
-+ set_bit(0, &tp->tx_full);
-+ if (tp->cur_tx - (volatile unsigned int)tp->dirty_tx < NUM_TX_DESC) {
-+ clear_bit(0, &tp->tx_full);
-+ netif_unpause_tx_queue(dev);
-+ } else
-+ netif_stop_tx_queue(dev);
-+ } else
-+ netif_unpause_tx_queue(dev);
-
- dev->trans_start = jiffies;
-- if (rtl8129_debug > 4)
-- printk(KERN_DEBUG"%s: Queued Tx packet at %p size %ld to slot %d.\n",
-- dev->name, skb->data, skb->len, entry);
-+ if (tp->msg_level & NETIF_MSG_TX_QUEUED)
-+ printk(KERN_DEBUG"%s: Queued Tx packet at %p size %d to slot %d.\n",
-+ dev->name, skb->data, (int)skb->len, entry);
-
- return 0;
- }
-@@ -881,31 +1061,32 @@
- after the Tx thread. */
- static void rtl8129_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
- {
-- struct device *dev = (struct device *)dev_instance;
-- struct rtl8129_private *tp;
-- int ioaddr, boguscnt = max_interrupt_work;
-- int status;
--
-- if (dev == NULL) {
-- printk (KERN_ERR"rtl8139_interrupt(): IRQ %d for unknown device.\n",
-- irq);
-- return;
-- }
--
-- ioaddr = dev->base_addr;
-- tp = (struct rtl8129_private *)dev->priv;
-- if (test_and_set_bit(0, (void*)&tp->in_interrupt)) {
-- printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name);
-+ struct net_device *dev = (struct net_device *)dev_instance;
-+ struct rtl8129_private *np = (struct rtl8129_private *)dev->priv;
-+ struct rtl8129_private *tp = np;
-+ int boguscnt = np->max_interrupt_work;
-+ long ioaddr = dev->base_addr;
-+ int link_changed = 0; /* Grrr, avoid bogus "uninitialized" warning */
-+
-+#if defined(__i386__) && LINUX_VERSION_CODE < 0x20123
-+ /* A lock to prevent simultaneous entry bug on Intel SMP machines. */
-+ if (test_and_set_bit(0, (void*)&dev->interrupt)) {
-+ printk(KERN_ERR"%s: SMP simultaneous entry of an interrupt handler.\n",
-+ dev->name);
-+ dev->interrupt = 0; /* Avoid halting machine. */
- return;
- }
-- dev->interrupt = 1;
-+#endif
-
- do {
-- status = inw(ioaddr + IntrStatus);
-- /* Acknowledge all of the current interrupt sources ASAP. */
-+ int status = inw(ioaddr + IntrStatus);
-+ /* Acknowledge all of the current interrupt sources ASAP, but
-+ an first get an additional status bit from CSCR. */
-+ if (status & RxUnderrun)
-+ link_changed = inw(ioaddr+CSCR) & CSCR_LinkChangeBit;
- outw(status, ioaddr + IntrStatus);
-
-- if (rtl8129_debug > 4)
-+ if (tp->msg_level & NETIF_MSG_INTR)
- printk(KERN_DEBUG"%s: interrupt status=%#4.4x new intstat=%#4.4x.\n",
- dev->name, status, inw(ioaddr + IntrStatus));
-
-@@ -917,27 +1098,25 @@
- rtl8129_rx(dev);
-
- if (status & (TxOK | TxErr)) {
-- unsigned int dirty_tx;
-+ unsigned int dirty_tx = tp->dirty_tx;
-
-- for (dirty_tx = tp->dirty_tx; dirty_tx < tp->cur_tx; dirty_tx++) {
-+ while (tp->cur_tx - dirty_tx > 0) {
- int entry = dirty_tx % NUM_TX_DESC;
-- int txstatus = inl(ioaddr + TxStat0 + entry*4);
-+ int txstatus = inl(ioaddr + TxStatus0 + entry*4);
-
-- if ( ! (txstatus & TxHostOwns))
-+ if ( ! (txstatus & (TxStatOK | TxUnderrun | TxAborted)))
- break; /* It still hasn't been Txed */
-
- /* Note: TxCarrierLost is always asserted at 100mbps. */
- if (txstatus & (TxOutOfWindow | TxAborted)) {
- /* There was an major error, log it. */
--#ifndef final_version
-- if (rtl8129_debug > 1)
-+ if (tp->msg_level & NETIF_MSG_TX_ERR)
- printk(KERN_NOTICE"%s: Transmit error, Tx status %8.8x.\n",
- dev->name, txstatus);
--#endif
- tp->stats.tx_errors++;
- if (txstatus&TxAborted) {
- tp->stats.tx_aborted_errors++;
-- outl((TX_DMA_BURST<<8)|0x03000001, ioaddr + TxConfig);
-+ outl(TX_DMA_BURST << 8, ioaddr + TxConfig);
- }
- if (txstatus&TxCarrierLost) tp->stats.tx_carrier_errors++;
- if (txstatus&TxOutOfWindow) tp->stats.tx_window_errors++;
-@@ -946,11 +1125,13 @@
- tp->stats.collisions16++;
- #endif
- } else {
--#ifdef ETHER_STATS
-- /* No count for tp->stats.tx_deferred */
--#endif
-+ if (tp->msg_level & NETIF_MSG_TX_DONE)
-+ printk(KERN_DEBUG "%s: Transmit done, Tx status"
-+ " %8.8x.\n", dev->name, txstatus);
- if (txstatus & TxUnderrun) {
-- /* Todo: increase the Tx FIFO threshold. */
-+ /* Add 64 to the Tx FIFO threshold. */
-+ if (tp->tx_flag < 0x00300000)
-+ tp->tx_flag += 0x00020000;
- tp->stats.tx_fifo_errors++;
- }
- tp->stats.collisions += (txstatus >> 24) & 15;
-@@ -961,48 +1142,34 @@
- }
-
- /* Free the original skb. */
-- dev_kfree_skb(tp->tx_skbuff[entry], FREE_WRITE);
-+ dev_free_skb_irq(tp->tx_skbuff[entry]);
- tp->tx_skbuff[entry] = 0;
-+ if (test_bit(0, &tp->tx_full)) {
-+ /* The ring is no longer full, clear tbusy. */
-+ clear_bit(0, &tp->tx_full);
-+ netif_resume_tx_queue(dev);
-+ }
-+ dirty_tx++;
- }
-
- #ifndef final_version
- if (tp->cur_tx - dirty_tx > NUM_TX_DESC) {
- printk(KERN_ERR"%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
-- dev->name, dirty_tx, tp->cur_tx, tp->tx_full);
-+ dev->name, dirty_tx, tp->cur_tx, (int)tp->tx_full);
- dirty_tx += NUM_TX_DESC;
- }
- #endif
--
-- if (tp->tx_full && dev->tbusy
-- && dirty_tx > tp->cur_tx - NUM_TX_DESC) {
-- /* The ring is no longer full, clear tbusy. */
-- tp->tx_full = 0;
-- dev->tbusy = 0;
-- mark_bh(NET_BH);
-- }
--
- tp->dirty_tx = dirty_tx;
- }
-
- /* Check uncommon events with one test. */
- if (status & (PCIErr|PCSTimeout |RxUnderrun|RxOverflow|RxFIFOOver
- |TxErr|RxErr)) {
-- /* Update the error count. */
-- tp->stats.rx_missed_errors += inl(ioaddr + RxMissed);
-- outl(0, ioaddr + RxMissed);
--
-- if (status & (RxUnderrun | RxOverflow | RxErr | RxFIFOOver))
-- tp->stats.rx_errors++;
--
-- if (status & (PCSTimeout)) tp->stats.rx_length_errors++;
-- if (status & (RxUnderrun|RxFIFOOver)) tp->stats.rx_fifo_errors++;
-- if (status & RxOverflow) {
-- tp->stats.rx_over_errors++;
-- tp->cur_rx = inw(ioaddr + RxBufAddr) % RX_BUF_LEN;
-- outw(tp->cur_rx - 16, ioaddr + RxBufPtr);
-- }
-- /* Error sources cleared above. */
-+ if (status == 0xffff) /* Missing chip! */
-+ break;
-+ rtl_error(dev, status, link_changed);
- }
-+
- if (--boguscnt < 0) {
- printk(KERN_WARNING"%s: Too much work at interrupt, "
- "IntrStatus=0x%4.4x.\n",
-@@ -1013,55 +1180,65 @@
- }
- } while (1);
-
-- if (rtl8129_debug > 3)
-+ if (tp->msg_level & NETIF_MSG_INTR)
- printk(KERN_DEBUG"%s: exiting interrupt, intr_status=%#4.4x.\n",
-- dev->name, inl(ioaddr + IntrStatus));
-+ dev->name, inw(ioaddr + IntrStatus));
-
-- dev->interrupt = 0;
-- clear_bit(0, (void*)&tp->in_interrupt);
-+#if defined(__i386__) && LINUX_VERSION_CODE < 0x20123
-+ clear_bit(0, (void*)&dev->interrupt);
-+#endif
- return;
- }
-
- /* The data sheet doesn't describe the Rx ring at all, so I'm guessing at the
- field alignments and semantics. */
--static int
--rtl8129_rx(struct device *dev)
-+static int rtl8129_rx(struct net_device *dev)
- {
- struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
-- int ioaddr = dev->base_addr;
-+ long ioaddr = dev->base_addr;
- unsigned char *rx_ring = tp->rx_ring;
- u16 cur_rx = tp->cur_rx;
-
-- if (rtl8129_debug > 4)
-+ if (tp->msg_level & NETIF_MSG_RX_STATUS)
- printk(KERN_DEBUG"%s: In rtl8129_rx(), current %4.4x BufAddr %4.4x,"
- " free to %4.4x, Cmd %2.2x.\n",
- dev->name, cur_rx, inw(ioaddr + RxBufAddr),
- inw(ioaddr + RxBufPtr), inb(ioaddr + ChipCmd));
-
-- while ((inb(ioaddr + ChipCmd) & 1) == 0) {
-- int ring_offset = cur_rx % RX_BUF_LEN;
-- u32 rx_status = *(u32*)(rx_ring + ring_offset);
-- int rx_size = rx_status >> 16;
-+ while ((inb(ioaddr + ChipCmd) & RxBufEmpty) == 0) {
-+ int ring_offset = cur_rx % tp->rx_buf_len;
-+ u32 rx_status = le32_to_cpu(*(u32*)(rx_ring + ring_offset));
-+ int rx_size = rx_status >> 16; /* Includes the CRC. */
-
-- if (rtl8129_debug > 4) {
-+ if (tp->msg_level & NETIF_MSG_RX_STATUS) {
- int i;
-- printk(KERN_DEBUG"%s: rtl8129_rx() status %4.4x, size %4.4x, cur %4.4x.\n",
-+ printk(KERN_DEBUG"%s: rtl8129_rx() status %4.4x, size %4.4x,"
-+ " cur %4.4x.\n",
- dev->name, rx_status, rx_size, cur_rx);
- printk(KERN_DEBUG"%s: Frame contents ", dev->name);
- for (i = 0; i < 70; i++)
- printk(" %2.2x", rx_ring[ring_offset + i]);
- printk(".\n");
- }
-- if (rx_status & RxTooLong) {
-- if (rtl8129_debug > 0)
-- printk(KERN_NOTICE"%s: Oversized Ethernet frame, status %4.4x!\n",
-- dev->name, rx_status);
-- tp->stats.rx_length_errors++;
-- } else if (rx_status &
-- (RxBadSymbol|RxRunt|RxTooLong|RxCRCErr|RxBadAlign)) {
-- if (rtl8129_debug > 1)
-+ if (rx_status & (RxBadSymbol|RxRunt|RxTooLong|RxCRCErr|RxBadAlign)) {
-+ if (tp->msg_level & NETIF_MSG_RX_ERR)
- printk(KERN_DEBUG"%s: Ethernet frame had errors,"
-- " status %4.4x.\n", dev->name, rx_status);
-+ " status %8.8x.\n", dev->name, rx_status);
-+ if (rx_status == 0xffffffff) {
-+ printk(KERN_NOTICE"%s: Invalid receive status at ring "
-+ "offset %4.4x\n", dev->name, ring_offset);
-+ rx_status = 0;
-+ }
-+ if (rx_status & RxTooLong) {
-+ if (tp->msg_level & NETIF_MSG_DRV)
-+ printk(KERN_NOTICE"%s: Oversized Ethernet frame, status"
-+ " %4.4x!\n",
-+ dev->name, rx_status);
-+ /* A.C.: The chip hangs here.
-+ This should never occur, which means that we are screwed
-+ when it does.
-+ */
-+ }
- tp->stats.rx_errors++;
- if (rx_status & (RxBadSymbol|RxBadAlign))
- tp->stats.rx_frame_errors++;
-@@ -1070,15 +1247,18 @@
- /* Reset the receiver, based on RealTek recommendation. (Bug?) */
- tp->cur_rx = 0;
- outb(CmdTxEnb, ioaddr + ChipCmd);
-+ /* A.C.: Reset the multicast list. */
-+ set_rx_mode(dev);
- outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);
-- outl((RX_FIFO_THRESH << 13) | (RX_BUF_LEN_IDX << 11) |
-- (RX_DMA_BURST<<8), ioaddr + RxConfig);
- } else {
- /* Malloc up new buffer, compatible with net-2e. */
- /* Omit the four octet CRC from the length. */
- struct sk_buff *skb;
-+ int pkt_size = rx_size - 4;
-
-- skb = dev_alloc_skb(rx_size + 2);
-+ /* Allocate a common-sized skbuff if we are close. */
-+ skb = dev_alloc_skb(1400 < pkt_size && pkt_size < PKT_BUF_SZ-2 ?
-+ PKT_BUF_SZ : pkt_size + 2);
- if (skb == NULL) {
- printk(KERN_WARNING"%s: Memory squeeze, deferring packet.\n",
- dev->name);
-@@ -1089,13 +1269,14 @@
- }
- skb->dev = dev;
- skb_reserve(skb, 2); /* 16 byte align the IP fields. */
-- if (ring_offset+rx_size+4 > RX_BUF_LEN) {
-- int semi_count = RX_BUF_LEN - ring_offset - 4;
-+ if (ring_offset + rx_size > tp->rx_buf_len) {
-+ int semi_count = tp->rx_buf_len - ring_offset - 4;
-+ /* This could presumably use two calls to copy_and_sum()? */
- memcpy(skb_put(skb, semi_count), &rx_ring[ring_offset + 4],
- semi_count);
-- memcpy(skb_put(skb, rx_size-semi_count), rx_ring,
-- rx_size-semi_count);
-- if (rtl8129_debug > 4) {
-+ memcpy(skb_put(skb, pkt_size-semi_count), rx_ring,
-+ pkt_size-semi_count);
-+ if (tp->msg_level & NETIF_MSG_PKTDATA) {
- int i;
- printk(KERN_DEBUG"%s: Frame wrap @%d",
- dev->name, semi_count);
-@@ -1104,22 +1285,23 @@
- printk(".\n");
- memset(rx_ring, 0xcc, 16);
- }
-- } else
-- memcpy(skb_put(skb, rx_size), &rx_ring[ring_offset + 4],
-- rx_size);
-+ } else {
-+ eth_copy_and_sum(skb, &rx_ring[ring_offset + 4],
-+ pkt_size, 0);
-+ skb_put(skb, pkt_size);
-+ }
- skb->protocol = eth_type_trans(skb, dev);
- netif_rx(skb);
- #if LINUX_VERSION_CODE > 0x20119
-- tp->stats.rx_bytes += rx_size;
-+ tp->stats.rx_bytes += pkt_size;
- #endif
- tp->stats.rx_packets++;
- }
-
-- cur_rx += rx_size + 4;
-- cur_rx = (cur_rx + 3) & ~3;
-+ cur_rx = (cur_rx + rx_size + 4 + 3) & ~3;
- outw(cur_rx - 16, ioaddr + RxBufPtr);
- }
-- if (rtl8129_debug > 4)
-+ if (tp->msg_level & NETIF_MSG_RX_STATUS)
- printk(KERN_DEBUG"%s: Done rtl8129_rx(), current %4.4x BufAddr %4.4x,"
- " free to %4.4x, Cmd %2.2x.\n",
- dev->name, cur_rx, inw(ioaddr + RxBufAddr),
-@@ -1128,17 +1310,77 @@
- return 0;
- }
-
-+/* Error and abnormal or uncommon events handlers. */
-+static void rtl_error(struct net_device *dev, int status, int link_changed)
-+{
-+ struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+
-+ if (tp->msg_level & NETIF_MSG_LINK)
-+ printk(KERN_NOTICE"%s: Abnormal interrupt, status %8.8x.\n",
-+ dev->name, status);
-+
-+ /* Update the error count. */
-+ tp->stats.rx_missed_errors += inl(ioaddr + RxMissed);
-+ outl(0, ioaddr + RxMissed);
-+
-+ if (status & RxUnderrun){
-+ /* This might actually be a link change event. */
-+ if ((tp->drv_flags & HAS_LNK_CHNG) && link_changed) {
-+ /* Really link-change on new chips. */
-+ int lpar = inw(ioaddr + NWayLPAR);
-+ int duplex = (lpar&0x0100) || (lpar & 0x01C0) == 0x0040
-+ || tp->duplex_lock;
-+ /* Do not use MII_BMSR as that clears sticky bit. */
-+ if (inw(ioaddr + GPPinData) & 0x0004) {
-+ netif_link_down(dev);
-+ } else
-+ netif_link_up(dev);
-+ if (tp->msg_level & NETIF_MSG_LINK)
-+ printk(KERN_DEBUG "%s: Link changed, link partner "
-+ "%4.4x new duplex %d.\n",
-+ dev->name, lpar, duplex);
-+ tp->full_duplex = duplex;
-+ /* Only count as errors with no link change. */
-+ status &= ~RxUnderrun;
-+ } else {
-+ /* If this does not work, we will do rtl_hw_start(dev); */
-+ outb(CmdTxEnb, ioaddr + ChipCmd);
-+ set_rx_mode(dev); /* Reset the multicast list. */
-+ outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);
-+
-+ tp->stats.rx_errors++;
-+ tp->stats.rx_fifo_errors++;
-+ }
-+ }
-+
-+ if (status & (RxOverflow | RxErr | RxFIFOOver)) tp->stats.rx_errors++;
-+ if (status & (PCSTimeout)) tp->stats.rx_length_errors++;
-+ if (status & RxFIFOOver) tp->stats.rx_fifo_errors++;
-+ if (status & RxOverflow) {
-+ tp->stats.rx_over_errors++;
-+ tp->cur_rx = inw(ioaddr + RxBufAddr) % tp->rx_buf_len;
-+ outw(tp->cur_rx - 16, ioaddr + RxBufPtr);
-+ }
-+ if (status & PCIErr) {
-+ u32 pci_cmd_status;
-+ pci_read_config_dword(tp->pci_dev, PCI_COMMAND, &pci_cmd_status);
-+
-+ printk(KERN_ERR "%s: PCI Bus error %4.4x.\n",
-+ dev->name, pci_cmd_status);
-+ }
-+}
-+
- static int
--rtl8129_close(struct device *dev)
-+rtl8129_close(struct net_device *dev)
- {
-- int ioaddr = dev->base_addr;
-+ long ioaddr = dev->base_addr;
- struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
- int i;
-
-- dev->start = 0;
-- dev->tbusy = 1;
-+ netif_stop_tx_queue(dev);
-
-- if (rtl8129_debug > 1)
-+ if (tp->msg_level & NETIF_MSG_IFDOWN)
- printk(KERN_DEBUG"%s: Shutting down ethercard, status was 0x%4.4x.\n",
- dev->name, inw(ioaddr + IntrStatus));
-
-@@ -1158,15 +1400,15 @@
-
- for (i = 0; i < NUM_TX_DESC; i++) {
- if (tp->tx_skbuff[i])
-- dev_kfree_skb(tp->tx_skbuff[i], FREE_WRITE);
-+ dev_free_skb(tp->tx_skbuff[i]);
- tp->tx_skbuff[i] = 0;
- }
- kfree(tp->rx_ring);
-- kfree(tp->tx_bufs);
-+ tp->rx_ring = 0;
-
- /* Green! Put the chip in low-power mode. */
- outb(0xC0, ioaddr + Cfg9346);
-- outb(0x03, ioaddr + Config1);
-+ outb(tp->config1 | 0x03, ioaddr + Config1);
- outb('H', ioaddr + HltClk); /* 'R' would leave the clock running. */
-
- MOD_DEC_USE_COUNT;
-@@ -1174,13 +1416,69 @@
- return 0;
- }
-
--static struct enet_statistics *
--rtl8129_get_stats(struct device *dev)
-+/*
-+ Handle user-level ioctl() calls.
-+ We must use two numeric constants as the key because some clueless person
-+ changed value for the symbolic name.
-+*/
-+static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-+{
-+ struct rtl8129_private *np = (struct rtl8129_private *)dev->priv;
-+ u16 *data = (u16 *)&rq->ifr_data;
-+ u32 *data32 = (void *)&rq->ifr_data;
-+
-+ switch(cmd) {
-+ case 0x8947: case 0x89F0:
-+ /* SIOCGMIIPHY: Get the address of the PHY in use. */
-+ data[0] = np->phys[0] & 0x3f;
-+ /* Fall Through */
-+ case 0x8948: case 0x89F1:
-+ /* SIOCGMIIREG: Read the specified MII register. */
-+ data[3] = mdio_read(dev, data[0], data[1] & 0x1f);
-+ return 0;
-+ case 0x8949: case 0x89F2:
-+ /* SIOCSMIIREG: Write the specified MII register */
-+ if (!capable(CAP_NET_ADMIN))
-+ return -EPERM;
-+ if (data[0] == np->phys[0]) {
-+ u16 value = data[2];
-+ switch (data[1]) {
-+ case 0:
-+ /* Check for autonegotiation on or reset. */
-+ np->medialock = (value & 0x9000) ? 0 : 1;
-+ if (np->medialock)
-+ np->full_duplex = (value & 0x0100) ? 1 : 0;
-+ break;
-+ case 4: np->advertising = value; break;
-+ }
-+ }
-+ mdio_write(dev, data[0], data[1] & 0x1f, data[2]);
-+ return 0;
-+ case SIOCGPARAMS:
-+ data32[0] = np->msg_level;
-+ data32[1] = np->multicast_filter_limit;
-+ data32[2] = np->max_interrupt_work;
-+ data32[3] = 0; /* No rx_copybreak, always copy. */
-+ return 0;
-+ case SIOCSPARAMS:
-+ if (!capable(CAP_NET_ADMIN))
-+ return -EPERM;
-+ np->msg_level = data32[0];
-+ np->multicast_filter_limit = data32[1];
-+ np->max_interrupt_work = data32[2];
-+ return 0;
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+}
-+
-+static struct net_device_stats *
-+rtl8129_get_stats(struct net_device *dev)
- {
- struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
-- int ioaddr = dev->base_addr;
-+ long ioaddr = dev->base_addr;
-
-- if (dev->start) {
-+ if (netif_running(dev)) {
- tp->stats.rx_missed_errors += inl(ioaddr + RxMissed);
- outl(0, ioaddr + RxMissed);
- }
-@@ -1189,100 +1487,236 @@
- }
-
- /* Set or clear the multicast filter for this adaptor.
-- Note that we only use exclusion around actually queueing the
-- new frame, not around filling tp->setup_frame. This is non-deterministic
-- when re-entered but still correct. */
--
--/* The little-endian AUTODIN II ethernet CRC calculation.
-- N.B. Do not use for bulk data, use a table-based routine instead.
-- This is common code and should be moved to net/core/crc.c */
--static unsigned const ethernet_polynomial_le = 0xedb88320U;
--static inline unsigned ether_crc_le(int length, unsigned char *data)
-+ This routine is not state sensitive and need not be SMP locked. */
-+
-+static unsigned const ethernet_polynomial = 0x04c11db7U;
-+static inline u32 ether_crc(int length, unsigned char *data)
- {
-- unsigned int crc = 0xffffffff; /* Initial value. */
-- while(--length >= 0) {
-+ int crc = -1;
-+
-+ while (--length >= 0) {
- unsigned char current_octet = *data++;
- int bit;
-- for (bit = 8; --bit >= 0; current_octet >>= 1) {
-- if ((crc ^ current_octet) & 1) {
-- crc >>= 1;
-- crc ^= ethernet_polynomial_le;
-- } else
-- crc >>= 1;
-- }
-+ for (bit = 0; bit < 8; bit++, current_octet >>= 1)
-+ crc = (crc << 1) ^
-+ ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
- }
- return crc;
- }
-
--static void set_rx_mode(struct device *dev)
-+/* Bits in RxConfig. */
-+enum rx_mode_bits {
-+ AcceptErr=0x20, AcceptRunt=0x10, AcceptBroadcast=0x08,
-+ AcceptMulticast=0x04, AcceptMyPhys=0x02, AcceptAllPhys=0x01,
-+};
-+
-+static void set_rx_mode(struct net_device *dev)
- {
-- int ioaddr = dev->base_addr;
- struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
-- unsigned char mc_filter[8]; /* Multicast hash filter */
-- int i;
-+ long ioaddr = dev->base_addr;
-+ u32 mc_filter[2]; /* Multicast hash filter */
-+ int i, rx_mode;
-
-- if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
-+ if (tp->msg_level & NETIF_MSG_RXFILTER)
-+ printk(KERN_DEBUG"%s: set_rx_mode(%4.4x) done -- Rx config %8.8x.\n",
-+ dev->name, dev->flags, (int)inl(ioaddr + RxConfig));
-+
-+ /* Note: do not reorder, GCC is clever about common statements. */
-+ if (dev->flags & IFF_PROMISC) {
- /* Unconditionally log net taps. */
- printk(KERN_NOTICE"%s: Promiscuous mode enabled.\n", dev->name);
-- memset(mc_filter, 0xff, sizeof(mc_filter));
-- outb(0x0F, ioaddr + RxConfig);
-- } else if ((dev->mc_count > 1000) || (dev->flags & IFF_ALLMULTI)) {
-+ rx_mode = AcceptBroadcast|AcceptMulticast|AcceptMyPhys|AcceptAllPhys;
-+ mc_filter[1] = mc_filter[0] = 0xffffffff;
-+ } else if ((dev->mc_count > tp->multicast_filter_limit)
-+ || (dev->flags & IFF_ALLMULTI)) {
- /* Too many to filter perfectly -- accept all multicasts. */
-- memset(mc_filter, 0xff, sizeof(mc_filter));
-- outb(0x0E, ioaddr + RxConfig);
-- } else if (dev->mc_count == 0) {
-- outb(0x0A, ioaddr + RxConfig);
-- return;
-+ rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
-+ mc_filter[1] = mc_filter[0] = 0xffffffff;
- } else {
- struct dev_mc_list *mclist;
--
-- memset(mc_filter, 0, sizeof(mc_filter));
-+ rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
-+ mc_filter[1] = mc_filter[0] = 0;
- for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
- i++, mclist = mclist->next)
-- set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x3f,
-- mc_filter);
-- }
-- /* ToDo: perhaps we need to stop the Tx and Rx process here? */
-- if (memcmp(mc_filter, tp->mc_filter, sizeof(mc_filter))) {
-- for (i = 0; i < 2; i++)
-- outl(((u32 *)mc_filter)[i], ioaddr + MAR0 + i*4);
-- memcpy(tp->mc_filter, mc_filter, sizeof(mc_filter));
-+ set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26, mc_filter);
- }
-- if (rtl8129_debug > 3)
-- printk(KERN_DEBUG"%s: set_rx_mode(%4.4x) done -- Rx config %8.8x.\n",
-- dev->name, dev->flags, inl(ioaddr + RxConfig));
-+ /* We can safely update without stopping the chip. */
-+ outl(tp->rx_config | rx_mode, ioaddr + RxConfig);
-+ tp->mc_filter[0] = mc_filter[0];
-+ tp->mc_filter[1] = mc_filter[1];
-+ outl(mc_filter[0], ioaddr + MAR0 + 0);
-+ outl(mc_filter[1], ioaddr + MAR0 + 4);
- return;
- }
-
--#ifdef MODULE
-
--/* An additional parameter that may be passed in... */
--static int debug = -1;
-+static int rtl_pwr_event(void *dev_instance, int event)
-+{
-+ struct net_device *dev = dev_instance;
-+ struct rtl8129_private *np = (struct rtl8129_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+
-+ if (np->msg_level & NETIF_MSG_LINK)
-+ printk("%s: Handling power event %d.\n", dev->name, event);
-+ switch(event) {
-+ case DRV_ATTACH:
-+ MOD_INC_USE_COUNT;
-+ break;
-+ case DRV_SUSPEND:
-+ netif_device_detach(dev);
-+ /* Disable interrupts, stop Tx and Rx. */
-+ outw(0x0000, ioaddr + IntrMask);
-+ outb(0x00, ioaddr + ChipCmd);
-+ /* Update the error counts. */
-+ np->stats.rx_missed_errors += inl(ioaddr + RxMissed);
-+ outl(0, ioaddr + RxMissed);
-+ break;
-+ case DRV_RESUME:
-+ netif_device_attach(dev);
-+ rtl_hw_start(dev);
-+ break;
-+ case DRV_DETACH: {
-+ struct net_device **devp, **next;
-+ if (dev->flags & IFF_UP) {
-+ dev_close(dev);
-+ dev->flags &= ~(IFF_UP|IFF_RUNNING);
-+ }
-+ unregister_netdev(dev);
-+ release_region(dev->base_addr, pci_tbl[np->chip_id].io_size);
-+#ifndef USE_IO_OPS
-+ iounmap((char *)dev->base_addr);
-+#endif
-+ for (devp = &root_rtl8129_dev; *devp; devp = next) {
-+ next = &((struct rtl8129_private *)(*devp)->priv)->next_module;
-+ if (*devp == dev) {
-+ *devp = *next;
-+ break;
-+ }
-+ }
-+ if (np->priv_addr)
-+ kfree(np->priv_addr);
-+ kfree(dev);
-+ MOD_DEC_USE_COUNT;
-+ break;
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+#ifdef CARDBUS
-+
-+#include <pcmcia/driver_ops.h>
-
--int
--init_module(void)
-+static dev_node_t *rtl8139_attach(dev_locator_t *loc)
- {
-- int cards_found;
-+ struct net_device *dev;
-+ u16 dev_id;
-+ u32 pciaddr;
-+ u8 bus, devfn, irq;
-+ long hostaddr;
-+ /* Note: the chip index should match the 8139B pci_tbl[] entry. */
-+ int chip_idx = 2;
-+
-+ if (loc->bus != LOC_PCI) return NULL;
-+ bus = loc->b.pci.bus; devfn = loc->b.pci.devfn;
-+ printk(KERN_DEBUG "rtl8139_attach(bus %d, function %d)\n", bus, devfn);
-+#ifdef USE_IO_OPS
-+ pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &pciaddr);
-+ hostaddr = pciaddr & PCI_BASE_ADDRESS_IO_MASK;
-+#else
-+ pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_1, &pciaddr);
-+ hostaddr = (long)ioremap(pciaddr & PCI_BASE_ADDRESS_MEM_MASK,
-+ pci_tbl[chip_idx].io_size);
-+#endif
-+ pcibios_read_config_byte(bus, devfn, PCI_INTERRUPT_LINE, &irq);
-+ pcibios_read_config_word(bus, devfn, PCI_DEVICE_ID, &dev_id);
-+ if (hostaddr == 0 || irq == 0) {
-+ printk(KERN_ERR "The %s interface at %d/%d was not assigned an %s.\n"
-+ KERN_ERR " It will not be activated.\n",
-+ pci_tbl[chip_idx].name, bus, devfn,
-+ hostaddr == 0 ? "address" : "IRQ");
-+ return NULL;
-+ }
-+ dev = rtl8139_probe1(pci_find_slot(bus, devfn), NULL,
-+ hostaddr, irq, chip_idx, 0);
-+ if (dev) {
-+ dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL);
-+ strcpy(node->dev_name, dev->name);
-+ node->major = node->minor = 0;
-+ node->next = NULL;
-+ MOD_INC_USE_COUNT;
-+ return node;
-+ }
-+ return NULL;
-+}
-
-- if (debug >= 0)
-- rtl8129_debug = debug;
-+static void rtl8139_detach(dev_node_t *node)
-+{
-+ struct net_device **devp, **next;
-+ printk(KERN_INFO "rtl8139_detach(%s)\n", node->dev_name);
-+ for (devp = &root_rtl8129_dev; *devp; devp = next) {
-+ next = &((struct rtl8129_private *)(*devp)->priv)->next_module;
-+ if (strcmp((*devp)->name, node->dev_name) == 0) break;
-+ }
-+ if (*devp) {
-+ struct rtl8129_private *np =
-+ (struct rtl8129_private *)(*devp)->priv;
-+ unregister_netdev(*devp);
-+ release_region((*devp)->base_addr, pci_tbl[np->chip_id].io_size);
-+#ifndef USE_IO_OPS
-+ iounmap((char *)(*devp)->base_addr);
-+#endif
-+ kfree(*devp);
-+ if (np->priv_addr)
-+ kfree(np->priv_addr);
-+ *devp = *next;
-+ kfree(node);
-+ MOD_DEC_USE_COUNT;
-+ }
-+}
-
-- root_rtl8129_dev = NULL;
-- cards_found = rtl8139_probe(0);
-+struct driver_operations realtek_ops = {
-+ "realtek_cb",
-+ rtl8139_attach, /*rtl8139_suspend*/0, /*rtl8139_resume*/0, rtl8139_detach
-+};
-
-- return cards_found ? 0 : -ENODEV;
-+#endif /* Cardbus support */
-+
-+#ifdef MODULE
-+int init_module(void)
-+{
-+ if (debug >= NETIF_MSG_DRV) /* Emit version even if no cards detected. */
-+ printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB);
-+#ifdef CARDBUS
-+ register_driver(&realtek_ops);
-+ return 0;
-+#else
-+ return pci_drv_register(&rtl8139_drv_id, NULL);
-+#endif
- }
-
--void
--cleanup_module(void)
-+void cleanup_module(void)
- {
-- struct device *next_dev;
-+ struct net_device *next_dev;
-+
-+#ifdef CARDBUS
-+ unregister_driver(&realtek_ops);
-+#else
-+ pci_drv_unregister(&rtl8139_drv_id);
-+#endif
-
-- /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
- while (root_rtl8129_dev) {
-- next_dev = ((struct rtl8129_private *)root_rtl8129_dev->priv)->next_module;
-+ struct rtl8129_private *np = (void *)(root_rtl8129_dev->priv);
- unregister_netdev(root_rtl8129_dev);
-- release_region(root_rtl8129_dev->base_addr, RTL8129_TOTAL_SIZE);
-+ release_region(root_rtl8129_dev->base_addr,
-+ pci_tbl[np->chip_id].io_size);
-+#ifndef USE_IO_OPS
-+ iounmap((char *)(root_rtl8129_dev->base_addr));
-+#endif
-+ next_dev = np->next_module;
-+ if (np->priv_addr)
-+ kfree(np->priv_addr);
- kfree(root_rtl8129_dev);
- root_rtl8129_dev = next_dev;
- }
-@@ -1292,8 +1726,9 @@
-
- /*
- * Local variables:
-- * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c rtl8139.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
-- * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c rtl8139.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
-+ * compile-command: "make KERNVER=`uname -r` rtl8139.o"
-+ * compile-cmd: "gcc -DMODULE -Wall -Wstrict-prototypes -O6 -c rtl8139.c"
-+ * cardbus-compile-command: "gcc -DCARDBUS -DMODULE -Wall -Wstrict-prototypes -O6 -c rtl8139.c -o realtek_cb.o -I/usr/src/pcmcia/include/"
- * c-indent-level: 4
- * c-basic-offset: 4
- * tab-width: 4
-Index: linux/src/drivers/net/starfire.c
-===================================================================
-RCS file: linux/src/drivers/net/starfire.c
-diff -N linux/src/drivers/net/starfire.c
---- /dev/null 1 Jan 1970 00:00:00 -0000
-+++ linux/src/drivers/net/starfire.c 20 Aug 2004 10:32:54 -0000
-@@ -0,0 +1,1535 @@
-+/* starfire.c: Linux device driver for the Adaptec Starfire network adapter. */
-+/*
-+ Written/Copyright 1998-2003 by Donald Becker.
-+
-+ This software may be used and distributed according to the terms of
-+ the GNU General Public License (GPL), incorporated herein by reference.
-+ Drivers based on or derived from this code fall under the GPL and must
-+ retain the authorship, copyright and license notice. This file is not
-+ a complete program and may only be used when the entire operating
-+ system is licensed under the GPL.
-+
-+ The author may be reached as becker@scyld.com, or C/O
-+ Scyld Computing Corporation
-+ 914 Bay Ridge Road, Suite 220
-+ Annapolis MD 21403
-+
-+ Support information and updates available at
-+ http://www.scyld.com/network/starfire.html
-+*/
-+
-+/* These identify the driver base version and may not be removed. */
-+static const char version1[] =
-+"starfire.c:v1.09 7/22/2003 Copyright by Donald Becker <becker@scyld.com>\n";
-+static const char version2[] =
-+" Updates and info at http://www.scyld.com/network/starfire.html\n";
-+
-+/* The user-configurable values.
-+ These may be modified when a driver module is loaded.*/
-+
-+/* Used for tuning interrupt latency vs. overhead. */
-+static int interrupt_mitigation = 0x0;
-+
-+/* Message enable level: 0..31 = no..all messages. See NETIF_MSG docs. */
-+static int debug = 2;
-+
-+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-+static int max_interrupt_work = 20;
-+
-+/* Maximum number of multicast addresses to filter (vs. rx-all-multicast).
-+ The Starfire has a 512 element hash table based on the Ethernet CRC. */
-+static int multicast_filter_limit = 32;
-+
-+/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
-+ Setting to > 1518 effectively disables this feature. */
-+static int rx_copybreak = 0;
-+
-+/* Used to pass the media type, etc.
-+ Both 'options[]' and 'full_duplex[]' exist for driver interoperability,
-+ however full_duplex[] should never be used in new configurations.
-+ The media type is usually passed in 'options[]'.
-+ The default is autonegotation for speed and duplex.
-+ This should rarely be overridden.
-+ Use option values 0x10/0x20 for 10Mbps, 0x100,0x200 for 100Mbps.
-+ Use option values 0x10 and 0x100 for forcing half duplex fixed speed.
-+ Use option values 0x20 and 0x200 for forcing full duplex operation.
-+*/
-+#define MAX_UNITS 8 /* More are supported, limit only on options */
-+static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-+static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-+
-+/* Automatically extracted configuration info:
-+probe-func: starfire_probe
-+config-in: tristate 'Adaptec DuraLAN ("starfire") series PCI Ethernet support' CONFIG_DURLAN
-+
-+c-help-name: Adaptec DuraLAN ("starfire") series PCI Ethernet support
-+c-help-symbol: CONFIG_DURALAN
-+c-help: This driver is for the Adaptec DuraLAN series, the 6915, 62022
-+c-help: and 62044 boards.
-+c-help: Design information, usage details and updates are available from
-+c-help: http://www.scyld.com/network/starfire.html
-+*/
-+
-+/* Operational parameters that are set at compile time. */
-+
-+/* The "native" ring sizes are either 256 or 2048.
-+ However in some modes a descriptor may be marked to wrap the ring earlier.
-+ The driver allocates a single page for each descriptor ring, constraining
-+ the maximum size in an architecture-dependent way.
-+*/
-+#define RX_RING_SIZE 256
-+#define TX_RING_SIZE 32
-+/* The completion queues are fixed at 1024 entries i.e. 4K or 8KB. */
-+#define DONE_Q_SIZE 1024
-+
-+/* Operational parameters that usually are not changed. */
-+/* Time in jiffies before concluding the transmitter is hung. */
-+#define TX_TIMEOUT (6*HZ)
-+
-+/* Allocation size of Rx buffers with normal sized Ethernet frames.
-+ Do not change this value without good reason. This is not a limit,
-+ but a way to keep a consistent allocation size among drivers.
-+ */
-+#define PKT_BUF_SZ 1536
-+
-+#ifndef __KERNEL__
-+#define __KERNEL__
-+#endif
-+#if !defined(__OPTIMIZE__)
-+#warning You must compile this file with the correct options!
-+#warning See the last lines of the source file.
-+#error You must compile this driver with "-O".
-+#endif
-+
-+/* Include files, designed to support most kernel versions 2.0.0 and later. */
-+#include <linux/config.h>
-+#if defined(CONFIG_SMP) && ! defined(__SMP__)
-+#define __SMP__
-+#endif
-+#if defined(MODULE) && defined(CONFIG_MODVERSIONS) && ! defined(MODVERSIONS)
-+#define MODVERSIONS
-+#endif
-+
-+#include <linux/version.h>
-+#if defined(MODVERSIONS)
-+#include <linux/modversions.h>
-+#endif
-+#include <linux/module.h>
-+
-+#include <linux/kernel.h>
-+#include <linux/string.h>
-+#include <linux/timer.h>
-+#include <linux/errno.h>
-+#include <linux/ioport.h>
-+#if LINUX_VERSION_CODE >= 0x20400
-+#include <linux/slab.h>
-+#else
-+#include <linux/malloc.h>
-+#endif
-+#include <linux/interrupt.h>
-+#include <linux/pci.h>
-+#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/skbuff.h>
-+#include <asm/processor.h> /* Processor type for cache alignment. */
-+#include <asm/bitops.h>
-+#include <asm/io.h>
-+
-+#ifdef INLINE_PCISCAN
-+#include "k_compat.h"
-+#else
-+#include "pci-scan.h"
-+#include "kern_compat.h"
-+#endif
-+
-+/* Condensed operations for readability.
-+ Compatibility defines are in kern_compat.h */
-+
-+#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr))
-+#define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr))
-+
-+#if (LINUX_VERSION_CODE >= 0x20100) && defined(MODULE)
-+char kernel_version[] = UTS_RELEASE;
-+#endif
-+
-+MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
-+MODULE_DESCRIPTION("Adaptec Starfire Ethernet driver");
-+MODULE_LICENSE("GPL");
-+MODULE_PARM(debug, "i");
-+MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
-+MODULE_PARM(rx_copybreak, "i");
-+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
-+MODULE_PARM(multicast_filter_limit, "i");
-+MODULE_PARM(max_interrupt_work, "i");
-+MODULE_PARM_DESC(debug, "Driver message enable level (0-31)");
-+MODULE_PARM_DESC(options, "Force transceiver type or fixed speed+duplex");
-+MODULE_PARM_DESC(max_interrupt_work,
-+ "Driver maximum events handled per interrupt");
-+MODULE_PARM_DESC(full_duplex,
-+ "Non-zero to set forced full duplex (deprecated).");
-+MODULE_PARM_DESC(rx_copybreak,
-+ "Breakpoint in bytes for copy-only-tiny-frames");
-+MODULE_PARM_DESC(multicast_filter_limit,
-+ "Multicast addresses before switching to Rx-all-multicast");
-+
-+/*
-+ Theory of Operation
-+
-+I. Board Compatibility
-+
-+This driver is for the Adaptec 6915 DuraLAN "Starfire" 64 bit PCI Ethernet
-+adapter, and the multiport boards using the same chip.
-+
-+II. Board-specific settings
-+
-+III. Driver operation
-+
-+IIIa. Ring buffers
-+
-+The Starfire hardware uses multiple fixed-size descriptor queues/rings. The
-+ring sizes are set fixed by the hardware, but may optionally be wrapped
-+earlier by the END bit in the descriptor.
-+This driver uses that hardware queue size for the Rx ring, where a large
-+number of entries has no ill effect beyond increases the potential backlog.
-+The Tx ring is wrapped with the END bit, since a large hardware Tx queue
-+disables the queue layer priority ordering and we have no mechanism to
-+utilize the hardware two-level priority queue. When modifying the
-+RX/TX_RING_SIZE pay close attention to page sizes and the ring-empty warning
-+levels.
-+
-+IIIb/c. Transmit/Receive Structure
-+
-+See the Adaptec manual for the many possible structures, and options for
-+each structure. There are far too many to document here.
-+
-+For transmit this driver uses type 1 transmit descriptors, and relies on
-+automatic minimum-length padding. It does not use the completion queue
-+consumer index, but instead checks for non-zero status entries.
-+
-+For receive this driver uses type 0 receive descriptors. The driver
-+allocates full frame size skbuffs for the Rx ring buffers, so all frames
-+should fit in a single descriptor. The driver does not use the completion
-+queue consumer index, but instead checks for non-zero status entries.
-+
-+When an incoming frame is less than RX_COPYBREAK bytes long, a fresh skbuff
-+is allocated and the frame is copied to the new skbuff. When the incoming
-+frame is larger, the skbuff is passed directly up the protocol stack.
-+Buffers consumed this way are replaced by newly allocated skbuffs in a later
-+phase of receive.
-+
-+A notable aspect of operation is that unaligned buffers are not permitted by
-+the Starfire hardware. The IP header at offset 14 in an ethernet frame thus
-+isn't longword aligned, which may cause problems on some machine
-+e.g. Alphas. Copied frames are put into the skbuff at an offset of "+2",
-+16-byte aligning the IP header.
-+
-+IIId. Synchronization
-+
-+The driver runs as two independent, single-threaded flows of control. One
-+is the send-packet routine, which enforces single-threaded use by the
-+dev->tbusy flag. The other thread is the interrupt handler, which is single
-+threaded by the hardware and interrupt handling software.
-+
-+The send packet thread has partial control over the Tx ring and 'dev->tbusy'
-+flag. It sets the tbusy flag whenever it's queuing a Tx packet. If the next
-+queue slot is empty, it clears the tbusy flag when finished otherwise it sets
-+the 'lp->tx_full' flag.
-+
-+The interrupt handler has exclusive control over the Rx ring and records stats
-+from the Tx ring. After reaping the stats, it marks the Tx queue entry as
-+empty by incrementing the dirty_tx mark. Iff the 'lp->tx_full' flag is set, it
-+clears both the tx_full and tbusy flags.
-+
-+IV. Notes
-+
-+IVb. References
-+
-+The Adaptec Starfire manuals, available only from Adaptec.
-+http://www.scyld.com/expert/100mbps.html
-+http://www.scyld.com/expert/NWay.html
-+
-+IVc. Errata
-+
-+*/
-+
-+
-+
-+static void *starfire_probe1(struct pci_dev *pdev, void *init_dev,
-+ long ioaddr, int irq, int chip_idx, int find_cnt);
-+static int starfire_pwr_event(void *dev_instance, int event);
-+enum chip_capability_flags {CanHaveMII=1, };
-+#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR0)
-+/* And maps in 0.5MB(!) -- no I/O mapping here! */
-+#define MEM_ADDR_SZ 0x80000
-+
-+#if 0 && (defined(__x86_64) || defined(__alpha__))
-+/* Enable 64 bit address modes. */
-+#define STARFIRE_ADDR_64BITS 1
-+#endif
-+
-+static struct pci_id_info pci_id_tbl[] = {
-+ {"Adaptec Starfire 6915", { 0x69159004, 0xffffffff, },
-+ PCI_IOTYPE, MEM_ADDR_SZ, CanHaveMII},
-+ {0,}, /* 0 terminated list. */
-+};
-+
-+struct drv_id_info starfire_drv_id = {
-+ "starfire", PCI_HOTSWAP, PCI_CLASS_NETWORK_ETHERNET<<8, pci_id_tbl,
-+ starfire_probe1, starfire_pwr_event };
-+
-+/* Offsets to the device registers.
-+ Unlike software-only systems, device drivers interact with complex hardware.
-+ It's not useful to define symbolic names for every register bit in the
-+ device. The name can only partially document the semantics and make
-+ the driver longer and more difficult to read.
-+ In general, only the important configuration values or bits changed
-+ multiple times should be defined symbolically.
-+*/
-+enum register_offsets {
-+ PCIDeviceConfig=0x50040, GenCtrl=0x50070, IntrTimerCtrl=0x50074,
-+ IntrClear=0x50080, IntrStatus=0x50084, IntrEnable=0x50088,
-+ MIICtrl=0x52000, StationAddr=0x50120, EEPROMCtrl=0x51000,
-+ TxDescCtrl=0x50090,
-+ TxRingPtr=0x50098, HiPriTxRingPtr=0x50094, /* Low and High priority. */
-+ TxRingHiAddr=0x5009C, /* 64 bit address extension. */
-+ TxProducerIdx=0x500A0, TxConsumerIdx=0x500A4,
-+ TxThreshold=0x500B0,
-+ CompletionHiAddr=0x500B4, TxCompletionAddr=0x500B8,
-+ RxCompletionAddr=0x500BC, RxCompletionQ2Addr=0x500C0,
-+ CompletionQConsumerIdx=0x500C4,
-+ RxDescQCtrl=0x500D4, RxDescQHiAddr=0x500DC, RxDescQAddr=0x500E0,
-+ RxDescQIdx=0x500E8, RxDMAStatus=0x500F0, RxFilterMode=0x500F4,
-+ TxMode=0x55000,
-+};
-+
-+/* Bits in the interrupt status/mask registers. */
-+enum intr_status_bits {
-+ IntrNormalSummary=0x8000, IntrAbnormalSummary=0x02000000,
-+ IntrRxDone=0x0300, IntrRxEmpty=0x10040, IntrRxPCIErr=0x80000,
-+ IntrTxDone=0x4000, IntrTxEmpty=0x1000, IntrTxPCIErr=0x80000,
-+ StatsMax=0x08000000, LinkChange=0xf0000000,
-+ IntrTxDataLow=0x00040000,
-+ IntrPCIPin=0x01,
-+};
-+
-+/* Bits in the RxFilterMode register. */
-+enum rx_mode_bits {
-+ AcceptBroadcast=0x04, AcceptAllMulticast=0x02, AcceptAll=0x01,
-+ AcceptMulticast=0x10, AcceptMyPhys=0xE040,
-+};
-+
-+/* Misc. bits. Symbolic names so that may be searched for. */
-+enum misc_bits {
-+ ChipResetCmd=1, /* PCIDeviceConfig */
-+ PCIIntEnb=0x00800000, /* PCIDeviceConfig */
-+ TxEnable=0x0A, RxEnable=0x05, SoftIntr=0x100, /* GenCtrl */
-+};
-+
-+/* The Rx and Tx buffer descriptors. */
-+struct starfire_rx_desc {
-+ u32 rxaddr; /* Optionally 64 bits. */
-+#if defined(STARFIRE_ADDR_64BITS)
-+ u32 rxaddr_hi; /* Optionally 64 bits. */
-+#endif
-+};
-+enum rx_desc_bits {
-+ RxDescValid=1, RxDescEndRing=2,
-+};
-+
-+/* Completion queue entry.
-+ You must update the page allocation, init_ring and the shift count in rx()
-+ if using a larger format. */
-+struct rx_done_desc {
-+ u32 status; /* Low 16 bits is length. */
-+#ifdef full_rx_status
-+ u32 status2;
-+ u16 vlanid;
-+ u16 csum; /* partial checksum */
-+ u32 timestamp;
-+#endif
-+};
-+enum rx_done_bits {
-+ RxOK=0x20000000, RxFIFOErr=0x10000000, RxBufQ2=0x08000000,
-+};
-+
-+/* Type 1 Tx descriptor. */
-+struct starfire_tx_desc {
-+ u32 status; /* Upper bits are status, lower 16 length. */
-+ u32 addr;
-+};
-+enum tx_desc_bits {
-+ TxDescID=0xB1010000, /* Also marks single fragment, add CRC. */
-+ TxDescIntr=0x08000000, TxRingWrap=0x04000000,
-+};
-+struct tx_done_report {
-+ u32 status; /* timestamp, index. */
-+#if 0
-+ u32 intrstatus; /* interrupt status */
-+#endif
-+};
-+
-+#define PRIV_ALIGN 15 /* Required alignment mask */
-+struct netdev_private {
-+ /* Descriptor rings first for alignment. */
-+ struct starfire_rx_desc *rx_ring;
-+ struct starfire_tx_desc *tx_ring;
-+ struct net_device *next_module; /* Link for devices of this type. */
-+ void *priv_addr; /* Unaligned address for kfree */
-+ const char *product_name;
-+ /* The addresses of rx/tx-in-place skbuffs. */
-+ struct sk_buff* rx_skbuff[RX_RING_SIZE];
-+ struct sk_buff* tx_skbuff[TX_RING_SIZE];
-+ u8 pad0[100]; /* Impact padding */
-+ /* Pointers to completion queues (full pages). Cache line pad.. */
-+ struct rx_done_desc *rx_done_q __attribute__((aligned (L1_CACHE_BYTES)));
-+ unsigned int rx_done;
-+ struct tx_done_report *tx_done_q __attribute__((aligned (L1_CACHE_BYTES)));
-+ unsigned int tx_done;
-+
-+ struct net_device_stats stats;
-+ struct timer_list timer; /* Media monitoring timer. */
-+ int msg_level;
-+ int chip_id, drv_flags;
-+ struct pci_dev *pci_dev;
-+ /* Frequently used values: keep some adjacent for cache effect. */
-+ int max_interrupt_work;
-+ int intr_enable;
-+ unsigned int restore_intr_enable:1; /* Set if temporarily masked. */
-+ unsigned int polling:1; /* Erk, IRQ err. */
-+
-+ unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */
-+ unsigned int rx_buf_sz; /* Based on MTU+slack. */
-+ int rx_copybreak;
-+
-+ unsigned int cur_tx, dirty_tx;
-+ unsigned int tx_full:1; /* The Tx queue is full. */
-+ /* These values keep track of the transceiver/media in use. */
-+ unsigned int full_duplex:1, /* Full-duplex operation requested. */
-+ medialock:1, /* Xcvr set to fixed speed/duplex. */
-+ rx_flowctrl:1,
-+ tx_flowctrl:1; /* Use 802.3x flow control. */
-+ unsigned int default_port; /* Last dev->if_port value. */
-+ u32 tx_mode;
-+ u8 tx_threshold;
-+ u32 cur_rx_mode;
-+ u16 mc_filter[32];
-+ int multicast_filter_limit;
-+
-+ /* MII transceiver section. */
-+ int mii_cnt; /* MII device addresses. */
-+ u16 advertising; /* NWay media advertisement */
-+ unsigned char phys[2]; /* MII device addresses. */
-+};
-+
-+static int mdio_read(struct net_device *dev, int phy_id, int location);
-+static void mdio_write(struct net_device *dev, int phy_id, int location,
-+ int value);
-+static int netdev_open(struct net_device *dev);
-+static int change_mtu(struct net_device *dev, int new_mtu);
-+static void check_duplex(struct net_device *dev);
-+static void netdev_timer(unsigned long data);
-+static void tx_timeout(struct net_device *dev);
-+static void init_ring(struct net_device *dev);
-+static int start_tx(struct sk_buff *skb, struct net_device *dev);
-+static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs);
-+static void netdev_error(struct net_device *dev, int intr_status);
-+static int netdev_rx(struct net_device *dev);
-+static void netdev_error(struct net_device *dev, int intr_status);
-+static void set_rx_mode(struct net_device *dev);
-+static struct net_device_stats *get_stats(struct net_device *dev);
-+static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-+static int netdev_close(struct net_device *dev);
-+
-+
-+
-+/* A list of our installed devices, for removing the driver module. */
-+static struct net_device *root_net_dev = NULL;
-+
-+#ifndef MODULE
-+int starfire_probe(struct net_device *dev)
-+{
-+ if (pci_drv_register(&starfire_drv_id, dev) < 0)
-+ return -ENODEV;
-+ printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2);
-+ return 0;
-+}
-+#endif
-+
-+static void *starfire_probe1(struct pci_dev *pdev, void *init_dev,
-+ long ioaddr, int irq, int chip_idx, int card_idx)
-+{
-+ struct net_device *dev;
-+ struct netdev_private *np;
-+ void *priv_mem;
-+ int i, option = card_idx < MAX_UNITS ? options[card_idx] : 0;
-+
-+ dev = init_etherdev(init_dev, 0);
-+ if (!dev)
-+ return NULL;
-+
-+ printk(KERN_INFO "%s: %s at 0x%lx, ",
-+ dev->name, pci_id_tbl[chip_idx].name, ioaddr);
-+
-+ /* Serial EEPROM reads are hidden by the hardware. */
-+ for (i = 0; i < 6; i++)
-+ dev->dev_addr[i] = readb(ioaddr + EEPROMCtrl + 20-i);
-+ for (i = 0; i < 5; i++)
-+ printk("%2.2x:", dev->dev_addr[i]);
-+ printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);
-+
-+ /* Make certain elements e.g. descriptor lists are aligned. */
-+ priv_mem = kmalloc(sizeof(*np) + PRIV_ALIGN, GFP_KERNEL);
-+ /* Check for the very unlikely case of no memory. */
-+ if (priv_mem == NULL)
-+ return NULL;
-+
-+ /* Reset the chip to erase previous misconfiguration. */
-+ writel(ChipResetCmd, ioaddr + PCIDeviceConfig);
-+
-+ dev->base_addr = ioaddr;
-+ dev->irq = irq;
-+
-+ dev->priv = np = (void *)(((long)priv_mem + PRIV_ALIGN) & ~PRIV_ALIGN);
-+ memset(np, 0, sizeof(*np));
-+ np->priv_addr = priv_mem;
-+
-+ np->next_module = root_net_dev;
-+ root_net_dev = dev;
-+
-+ np->pci_dev = pdev;
-+ np->chip_id = chip_idx;
-+ np->drv_flags = pci_id_tbl[chip_idx].drv_flags;
-+ np->msg_level = (1 << debug) - 1;
-+ np->rx_copybreak = rx_copybreak;
-+ np->max_interrupt_work = max_interrupt_work;
-+ np->multicast_filter_limit = multicast_filter_limit;
-+
-+ if (dev->mem_start)
-+ option = dev->mem_start;
-+
-+ if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0)
-+ np->full_duplex = 1;
-+
-+ if (np->full_duplex) {
-+ if (np->msg_level & NETIF_MSG_PROBE)
-+ printk(KERN_INFO "%s: Set to forced full duplex, autonegotiation"
-+ " disabled.\n", dev->name);
-+ np->medialock = 1;
-+ }
-+
-+ /* The chip-specific entries in the device structure. */
-+ dev->open = &netdev_open;
-+ dev->hard_start_xmit = &start_tx;
-+ dev->stop = &netdev_close;
-+ dev->get_stats = &get_stats;
-+ dev->set_multicast_list = &set_rx_mode;
-+ dev->do_ioctl = &mii_ioctl;
-+ dev->change_mtu = &change_mtu;
-+
-+ if (np->drv_flags & CanHaveMII) {
-+ int phy, phy_idx = 0;
-+ for (phy = 0; phy < 32 && phy_idx < 4; phy++) {
-+ int mii_status = mdio_read(dev, phy, 1);
-+ if (mii_status != 0xffff && mii_status != 0x0000) {
-+ np->phys[phy_idx++] = phy;
-+ np->advertising = mdio_read(dev, phy, 4);
-+ if (np->msg_level & NETIF_MSG_PROBE)
-+ printk(KERN_INFO "%s: MII PHY found at address %d, status "
-+ "0x%4.4x advertising %4.4x.\n",
-+ dev->name, phy, mii_status, np->advertising);
-+ }
-+ }
-+ np->mii_cnt = phy_idx;
-+ }
-+
-+ /* Force the media type after detecting the transceiver. */
-+ if (option > 0) {
-+ if (option & 0x220)
-+ np->full_duplex = 1;
-+ np->default_port = option & 0x3ff;
-+ if (np->default_port & 0x330) {
-+ np->medialock = 1;
-+ if (np->msg_level & NETIF_MSG_PROBE)
-+ printk(KERN_INFO " Forcing %dMbs %s-duplex operation.\n",
-+ (option & 0x300 ? 100 : 10),
-+ (np->full_duplex ? "full" : "half"));
-+ mdio_write(dev, np->phys[0], 0,
-+ ((option & 0x300) ? 0x2000 : 0) | /* 100mbps? */
-+ (np->full_duplex ? 0x0100 : 0)); /* Full duplex? */
-+ }
-+ }
-+
-+ return dev;
-+}
-+
-+
-+/* Read the MII Management Data I/O (MDIO) interfaces. */
-+
-+static int mdio_read(struct net_device *dev, int phy_id, int location)
-+{
-+ long mdio_addr = dev->base_addr + MIICtrl + (phy_id<<7) + (location<<2);
-+ int result, boguscnt=1000;
-+ /* ??? Should we add a busy-wait here? */
-+ do
-+ result = readl(mdio_addr);
-+ while ((result & 0xC0000000) != 0x80000000 && --boguscnt >= 0);
-+ return result & 0xffff;
-+}
-+
-+static void mdio_write(struct net_device *dev, int phy_id, int location, int value)
-+{
-+ long mdio_addr = dev->base_addr + MIICtrl + (phy_id<<7) + (location<<2);
-+ writel(value, mdio_addr);
-+ /* The busy-wait will occur before a read. */
-+ return;
-+}
-+
-+
-+static int netdev_open(struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+ int i;
-+
-+ MOD_INC_USE_COUNT;
-+
-+ if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev)) {
-+ MOD_DEC_USE_COUNT;
-+ return -EAGAIN;
-+ }
-+
-+ /* We have no reports that indicate we need to reset the chip.
-+ But to be on the safe side... */
-+ /* Disable the Rx and Tx, and reset the chip. */
-+ writel(0, ioaddr + GenCtrl);
-+ writel(ChipResetCmd, ioaddr + PCIDeviceConfig);
-+ if (np->msg_level & NETIF_MSG_IFUP)
-+ printk(KERN_DEBUG "%s: netdev_open() irq %d.\n",
-+ dev->name, dev->irq);
-+ /* Allocate the various queues, failing gracefully. */
-+ if (np->tx_done_q == 0)
-+ np->tx_done_q = (struct tx_done_report *)get_free_page(GFP_KERNEL);
-+ if (np->rx_done_q == 0)
-+ np->rx_done_q = (struct rx_done_desc *)get_free_page(GFP_KERNEL);
-+ if (np->tx_ring == 0)
-+ np->tx_ring = (struct starfire_tx_desc *)get_free_page(GFP_KERNEL);
-+ if (np->rx_ring == 0)
-+ np->rx_ring = (struct starfire_rx_desc *)get_free_page(GFP_KERNEL);
-+ if (np->tx_done_q == 0 || np->rx_done_q == 0
-+ || np->rx_ring == 0 || np->tx_ring == 0) {
-+ /* Retain the pages to increase our chances next time. */
-+ MOD_DEC_USE_COUNT;
-+ return -ENOMEM;
-+ }
-+
-+ init_ring(dev);
-+ /* Set the size of the Rx buffers. */
-+ writel((np->rx_buf_sz<<16) | 0xA000, ioaddr + RxDescQCtrl);
-+
-+ /* Set Tx descriptor to type 1 and padding to 0 bytes. */
-+ writel(0x02000401, ioaddr + TxDescCtrl);
-+
-+#if defined(STARFIRE_ADDR_64BITS)
-+ writel(virt_to_bus(np->rx_ring) >> 32, ioaddr + RxDescQHiAddr);
-+ writel(virt_to_bus(np->tx_ring) >> 32, ioaddr + TxRingHiAddr);
-+#else
-+ writel(0, ioaddr + RxDescQHiAddr);
-+ writel(0, ioaddr + TxRingHiAddr);
-+ writel(0, ioaddr + CompletionHiAddr);
-+#endif
-+ writel(virt_to_bus(np->rx_ring), ioaddr + RxDescQAddr);
-+ writel(virt_to_bus(np->tx_ring), ioaddr + TxRingPtr);
-+
-+ writel(virt_to_bus(np->tx_done_q), ioaddr + TxCompletionAddr);
-+ writel(virt_to_bus(np->rx_done_q), ioaddr + RxCompletionAddr);
-+
-+ if (np->msg_level & NETIF_MSG_IFUP)
-+ printk(KERN_DEBUG "%s: Filling in the station address.\n", dev->name);
-+
-+ /* Fill both the unused Tx SA register and the Rx perfect filter. */
-+ for (i = 0; i < 6; i++)
-+ writeb(dev->dev_addr[i], ioaddr + StationAddr + 5-i);
-+ for (i = 0; i < 16; i++) {
-+ u16 *eaddrs = (u16 *)dev->dev_addr;
-+ long setup_frm = ioaddr + 0x56000 + i*16;
-+ writew(cpu_to_be16(eaddrs[2]), setup_frm); setup_frm += 4;
-+ writew(cpu_to_be16(eaddrs[1]), setup_frm); setup_frm += 4;
-+ writew(cpu_to_be16(eaddrs[0]), setup_frm); setup_frm += 8;
-+ }
-+
-+ /* Initialize other registers. */
-+ /* Configure the PCI bus bursts and FIFO thresholds. */
-+ np->tx_mode = 0; /* Initialized when TxMode set. */
-+ np->tx_threshold = 4;
-+ writel(np->tx_threshold, ioaddr + TxThreshold);
-+ writel(interrupt_mitigation, ioaddr + IntrTimerCtrl);
-+
-+ if (dev->if_port == 0)
-+ dev->if_port = np->default_port;
-+
-+ if (np->msg_level & NETIF_MSG_IFUP)
-+ printk(KERN_DEBUG "%s: Setting the Rx and Tx modes.\n", dev->name);
-+ set_rx_mode(dev);
-+
-+ np->advertising = mdio_read(dev, np->phys[0], 4);
-+ check_duplex(dev);
-+ netif_start_tx_queue(dev);
-+
-+ /* Set the interrupt mask and enable PCI interrupts. */
-+ np->intr_enable = IntrRxDone | IntrRxEmpty | IntrRxPCIErr |
-+ IntrTxDone | IntrTxEmpty | IntrTxPCIErr |
-+ StatsMax | LinkChange | IntrNormalSummary | IntrAbnormalSummary
-+ | 0x0010;
-+ writel(np->intr_enable, ioaddr + IntrEnable);
-+ writel(PCIIntEnb | readl(ioaddr + PCIDeviceConfig),
-+ ioaddr + PCIDeviceConfig);
-+
-+ /* Enable the Rx and Tx units. */
-+ writel(TxEnable|RxEnable, ioaddr + GenCtrl);
-+
-+ if (np->msg_level & NETIF_MSG_IFUP)
-+ printk(KERN_DEBUG "%s: Done netdev_open().\n",
-+ dev->name);
-+
-+ /* Set the timer to check for link beat. */
-+ init_timer(&np->timer);
-+ np->timer.expires = jiffies + 3*HZ;
-+ np->timer.data = (unsigned long)dev;
-+ np->timer.function = &netdev_timer; /* timer handler */
-+ add_timer(&np->timer);
-+
-+ return 0;
-+}
-+
-+/* The starfire can handle frame sizes up to 64KB, but we arbitrarily
-+ * limit the size.
-+ */
-+static int change_mtu(struct net_device *dev, int new_mtu)
-+{
-+ if ((new_mtu < 68) || (new_mtu > 17268))
-+ return -EINVAL;
-+ if (netif_running(dev))
-+ return -EBUSY;
-+ dev->mtu = new_mtu;
-+ return 0;
-+}
-+
-+static void check_duplex(struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+ int new_tx_mode;
-+
-+ new_tx_mode = 0x0C04 | (np->tx_flowctrl ? 0x0800:0)
-+ | (np->rx_flowctrl ? 0x0400:0);
-+ if (np->medialock) {
-+ if (np->full_duplex)
-+ new_tx_mode |= 2;
-+ } else {
-+ int mii_reg5 = mdio_read(dev, np->phys[0], 5);
-+ int negotiated = mii_reg5 & np->advertising;
-+ int duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;
-+ if (duplex)
-+ new_tx_mode |= 2;
-+ if (np->full_duplex != duplex) {
-+ np->full_duplex = duplex;
-+ if (np->msg_level & NETIF_MSG_LINK)
-+ printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d"
-+ " negotiated capability %4.4x.\n", dev->name,
-+ duplex ? "full" : "half", np->phys[0], negotiated);
-+ }
-+ }
-+ if (new_tx_mode != np->tx_mode) {
-+ np->tx_mode = new_tx_mode;
-+ writel(np->tx_mode | 0x8000, ioaddr + TxMode);
-+ writel(np->tx_mode, ioaddr + TxMode);
-+ }
-+}
-+
-+/* Check for duplex changes, but mostly check for failures. */
-+static void netdev_timer(unsigned long data)
-+{
-+ struct net_device *dev = (struct net_device *)data;
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+ int status = readl(ioaddr + IntrStatus);
-+ static long last_msg = 0;
-+
-+ /* Normally we check only every few seconds. */
-+ np->timer.expires = jiffies + 60*HZ;
-+
-+ if (np->msg_level & NETIF_MSG_TIMER) {
-+ printk(KERN_DEBUG "%s: Media selection timer tick, status %8.8x.\n",
-+ dev->name, status);
-+ }
-+
-+ /* Check for a missing chip or failed interrupt line.
-+ * The latter may be falsely triggered, so we check twice. */
-+ if (status == 0xffffffff) {
-+ if (jiffies - last_msg > 10*HZ) {
-+ last_msg = jiffies;
-+ printk(KERN_ERR "%s: The Starfire chip is missing!\n",
-+ dev->name);
-+ }
-+ } else if (np->polling) {
-+ if (status & IntrPCIPin) {
-+ intr_handler(dev->irq, dev, 0);
-+ if (jiffies - last_msg > 10*HZ) {
-+ printk(KERN_ERR "%s: IRQ %d is still blocked!\n",
-+ dev->name, dev->irq);
-+ last_msg = jiffies;
-+ }
-+ } else if (jiffies - last_msg > 10*HZ)
-+ np->polling = 0;
-+ np->timer.expires = jiffies + 2;
-+ } else if (status & IntrPCIPin) {
-+ int new_status = readl(ioaddr + IntrStatus);
-+ /* Bogus hardware IRQ mapping: Fake an interrupt handler call. */
-+ if (new_status & IntrPCIPin) {
-+ printk(KERN_ERR "%s: IRQ %d is not raising an interrupt! "
-+ "Status %8.8x/%8.8x. \n",
-+ dev->name, dev->irq, status, new_status);
-+ intr_handler(dev->irq, dev, 0);
-+ np->timer.expires = jiffies + 2;
-+ np->polling = 1;
-+ }
-+ } else if (netif_queue_paused(dev) &&
-+ np->cur_tx - np->dirty_tx > 1 &&
-+ (jiffies - dev->trans_start) > TX_TIMEOUT) {
-+ /* This will not catch tbusy incorrectly set when the queue is empty,
-+ * but that state should never occur. */
-+ tx_timeout(dev);
-+ }
-+
-+ check_duplex(dev);
-+
-+ add_timer(&np->timer);
-+}
-+
-+static void tx_timeout(struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+
-+ printk(KERN_WARNING "%s: Transmit timed out, status %8.8x,"
-+ " resetting...\n", dev->name, (int)readl(ioaddr + IntrStatus));
-+
-+#if defined(__i386__)
-+ if (np->msg_level & NETIF_MSG_TX_ERR) {
-+ int i;
-+ printk("\n" KERN_DEBUG " Tx ring %p: ", np->tx_ring);
-+ for (i = 0; i < TX_RING_SIZE; i++)
-+ printk(" %4.4x", np->tx_ring[i].status);
-+ printk("\n" KERN_DEBUG " Rx ring %p: ", np->rx_ring);
-+ for (i = 0; i < RX_RING_SIZE; i++)
-+ printk(" %8.8x", (unsigned int)np->rx_ring[i].rxaddr);
-+ printk("\n");
-+ }
-+#endif
-+
-+ /* If a specific problem is reported, reinitialize the hardware here. */
-+ dev->if_port = 0;
-+ /* Stop and restart the chip's Tx processes . */
-+ writel(0, ioaddr + GenCtrl);
-+ /* Enable the Rx and Tx units. */
-+ writel(TxEnable|RxEnable, ioaddr + GenCtrl);
-+
-+ dev->trans_start = jiffies;
-+ np->stats.tx_errors++;
-+ return;
-+}
-+
-+
-+/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
-+static void init_ring(struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ int i;
-+
-+ np->tx_full = 0;
-+ np->cur_rx = np->cur_tx = 0;
-+ np->dirty_rx = np->rx_done = np->dirty_tx = np->tx_done = 0;
-+
-+ np->rx_buf_sz = (dev->mtu <= 1522 ? PKT_BUF_SZ :
-+ (dev->mtu + 14 + 3) & ~3); /* Round to word. */
-+
-+ /* Fill in the Rx buffers. Handle allocation failure gracefully. */
-+ for (i = 0; i < RX_RING_SIZE; i++) {
-+ struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz);
-+ np->rx_skbuff[i] = skb;
-+ if (skb == NULL)
-+ break;
-+ skb->dev = dev; /* Mark as being used by this device. */
-+ /* Grrr, we cannot offset to correctly align the IP header. */
-+ np->rx_ring[i].rxaddr =
-+ virt_to_le32desc(skb->tail) | cpu_to_le32(RxDescValid);
-+ }
-+ writew(i - 1, dev->base_addr + RxDescQIdx);
-+ np->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
-+
-+ /* Clear the remainder of the Rx buffer ring. */
-+ for ( ; i < RX_RING_SIZE; i++) {
-+ np->rx_ring[i].rxaddr = 0;
-+ np->rx_skbuff[i] = 0;
-+ }
-+ /* Mark the last entry as wrapping the ring. */
-+ np->rx_ring[i-1].rxaddr |= cpu_to_le32(RxDescEndRing);
-+
-+ /* Clear the completion rings. */
-+ for (i = 0; i < DONE_Q_SIZE; i++) {
-+ np->rx_done_q[i].status = 0;
-+ np->tx_done_q[i].status = 0;
-+ }
-+
-+ for (i = 0; i < TX_RING_SIZE; i++) {
-+ np->tx_skbuff[i] = 0;
-+ np->tx_ring[i].status = 0;
-+ }
-+ return;
-+}
-+
-+static int start_tx(struct sk_buff *skb, struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ unsigned entry;
-+
-+ /* Block a timer-based transmit from overlapping. This happens when
-+ packets are presumed lost, and we use this check the Tx status. */
-+ if (netif_pause_tx_queue(dev) != 0) {
-+ /* This watchdog code is redundant with the media monitor timer. */
-+ if (jiffies - dev->trans_start > TX_TIMEOUT)
-+ tx_timeout(dev);
-+ return 1;
-+ }
-+
-+ /* Caution: the write order is important here, set the field
-+ with the "ownership" bits last. */
-+
-+ /* Calculate the next Tx descriptor entry. */
-+ entry = np->cur_tx % TX_RING_SIZE;
-+
-+ np->tx_skbuff[entry] = skb;
-+
-+ np->tx_ring[entry].addr = virt_to_le32desc(skb->data);
-+ /* Add "| TxDescIntr" to generate Tx-done interrupts. */
-+ np->tx_ring[entry].status = cpu_to_le32(skb->len | TxDescID);
-+#if 1
-+ if (entry >= TX_RING_SIZE-1) { /* Wrap ring */
-+ np->tx_ring[entry].status |= cpu_to_le32(TxRingWrap | TxDescIntr);
-+ entry = -1;
-+ }
-+#endif
-+
-+ /* On some architectures better performance results by explicitly
-+ flushing cache lines: pci_flush_virt(skb->data, skb->len); */
-+
-+ np->cur_tx++;
-+ /* Update the producer index. */
-+ writel(++entry, dev->base_addr + TxProducerIdx);
-+
-+ /* cf. using TX_QUEUE_LEN instead of TX_RING_SIZE here. */
-+ if (np->cur_tx - np->dirty_tx >= TX_RING_SIZE - 1) {
-+ np->tx_full = 1;
-+ /* Check for the rare case of a just-cleared queue. */
-+ if (np->cur_tx - (volatile unsigned int)np->dirty_tx
-+ < TX_RING_SIZE - 2) {
-+ np->tx_full = 0;
-+ netif_unpause_tx_queue(dev);
-+ } else
-+ netif_stop_tx_queue(dev);
-+ } else
-+ netif_unpause_tx_queue(dev); /* Typical path */
-+
-+ dev->trans_start = jiffies;
-+
-+ if (np->msg_level & NETIF_MSG_TX_QUEUED) {
-+ printk(KERN_DEBUG "%s: Tx frame #%d slot %d %8.8x %8.8x.\n",
-+ dev->name, np->cur_tx, entry,
-+ np->tx_ring[entry].status, np->tx_ring[entry].addr);
-+ }
-+ return 0;
-+}
-+
-+/* The interrupt handler does all of the Rx thread work and cleans up
-+ after the Tx thread. */
-+static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
-+{
-+ struct net_device *dev = (struct net_device *)dev_instance;
-+ struct netdev_private *np;
-+ long ioaddr;
-+ int boguscnt;
-+
-+#ifndef final_version /* Can never occur. */
-+ if (dev == NULL) {
-+ printk (KERN_ERR "Netdev interrupt handler(): IRQ %d for unknown "
-+ "device.\n", irq);
-+ return;
-+ }
-+#endif
-+
-+ ioaddr = dev->base_addr;
-+ np = (struct netdev_private *)dev->priv;
-+ boguscnt = np->max_interrupt_work;
-+
-+ do {
-+ u32 intr_status = readl(ioaddr + IntrClear);
-+
-+ if (np->msg_level & NETIF_MSG_INTR)
-+ printk(KERN_DEBUG "%s: Interrupt status %4.4x.\n",
-+ dev->name, intr_status);
-+
-+ if (intr_status == 0 || intr_status == 0xffffffff)
-+ break;
-+
-+ if (intr_status & IntrRxDone)
-+ netdev_rx(dev);
-+
-+ /* Scavenge the skbuff list based on the Tx-done queue.
-+ There are redundant checks here that may be cleaned up
-+ after the driver has proven to be reliable. */
-+ {
-+ int consumer = readl(ioaddr + TxConsumerIdx);
-+ int tx_status;
-+ if (np->msg_level & NETIF_MSG_INTR)
-+ printk(KERN_DEBUG "%s: Tx Consumer index is %d.\n",
-+ dev->name, consumer);
-+#if 0
-+ if (np->tx_done >= 250 || np->tx_done == 0)
-+ printk(KERN_DEBUG "%s: Tx completion entry %d is %8.8x, "
-+ "%d is %8.8x.\n", dev->name,
-+ np->tx_done, np->tx_done_q[np->tx_done].status,
-+ (np->tx_done+1) & (DONE_Q_SIZE-1),
-+ np->tx_done_q[(np->tx_done+1)&(DONE_Q_SIZE-1)].status);
-+#endif
-+ while ((tx_status = cpu_to_le32(np->tx_done_q[np->tx_done].status))
-+ != 0) {
-+ if (np->msg_level & NETIF_MSG_TX_DONE)
-+ printk(KERN_DEBUG "%s: Tx completion entry %d is %8.8x.\n",
-+ dev->name, np->tx_done, tx_status);
-+ if ((tx_status & 0xe0000000) == 0xa0000000) {
-+ np->stats.tx_packets++;
-+ } else if ((tx_status & 0xe0000000) == 0x80000000) {
-+ u16 entry = tx_status; /* Implicit truncate */
-+ entry >>= 3;
-+ /* Scavenge the descriptor. */
-+ if (np->tx_skbuff[entry]) {
-+ dev_free_skb_irq(np->tx_skbuff[entry]);
-+ } else
-+ printk(KERN_WARNING "%s: Null skbuff at entry %d!!!\n",
-+ dev->name, entry);
-+ np->tx_skbuff[entry] = 0;
-+ np->dirty_tx++;
-+ }
-+ np->tx_done_q[np->tx_done].status = 0;
-+ np->tx_done = (np->tx_done+1) & (DONE_Q_SIZE-1);
-+ }
-+ writew(np->tx_done, ioaddr + CompletionQConsumerIdx + 2);
-+ }
-+ if (np->tx_full && np->cur_tx - np->dirty_tx < TX_RING_SIZE - 4) {
-+ /* The ring is no longer full, allow new TX entries. */
-+ np->tx_full = 0;
-+ netif_resume_tx_queue(dev);
-+ }
-+
-+ /* Abnormal error summary/uncommon events handlers. */
-+ if (intr_status & IntrAbnormalSummary)
-+ netdev_error(dev, intr_status);
-+
-+ if (--boguscnt < 0) {
-+ printk(KERN_WARNING "%s: Too much work at interrupt, "
-+ "status=0x%4.4x.\n",
-+ dev->name, intr_status);
-+ writel(0x0021, ioaddr + IntrTimerCtrl);
-+ break;
-+ }
-+ } while (1);
-+
-+ if (np->msg_level & NETIF_MSG_INTR)
-+ printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
-+ dev->name, (int)readl(ioaddr + IntrStatus));
-+
-+ return;
-+}
-+
-+/* This routine is logically part of the interrupt handler, but separated
-+ for clarity and better register allocation. */
-+static int netdev_rx(struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx;
-+ u32 desc_status;
-+
-+ if (np->rx_done_q == 0) {
-+ printk(KERN_ERR "%s: rx_done_q is NULL! rx_done is %d. %p.\n",
-+ dev->name, np->rx_done, np->tx_done_q);
-+ return 0;
-+ }
-+
-+ /* If EOP is set on the next entry, it's a new packet. Send it up. */
-+ while ((desc_status = le32_to_cpu(np->rx_done_q[np->rx_done].status)) != 0) {
-+ if (np->msg_level & NETIF_MSG_RX_STATUS)
-+ printk(KERN_DEBUG " netdev_rx() status of %d was %8.8x.\n",
-+ np->rx_done, desc_status);
-+ if (--boguscnt < 0)
-+ break;
-+ if ( ! (desc_status & RxOK)) {
-+ /* There was a error. */
-+ if (np->msg_level & NETIF_MSG_RX_ERR)
-+ printk(KERN_DEBUG " netdev_rx() Rx error was %8.8x.\n",
-+ desc_status);
-+ np->stats.rx_errors++;
-+ if (desc_status & RxFIFOErr)
-+ np->stats.rx_fifo_errors++;
-+ } else {
-+ struct sk_buff *skb;
-+ u16 pkt_len = desc_status; /* Implicitly Truncate */
-+ int entry = (desc_status >> 16) & 0x7ff;
-+
-+#ifndef final_version
-+ if (np->msg_level & NETIF_MSG_RX_STATUS)
-+ printk(KERN_DEBUG " netdev_rx() normal Rx pkt length %d"
-+ ", bogus_cnt %d.\n",
-+ pkt_len, boguscnt);
-+#endif
-+ /* Check if the packet is long enough to accept without copying
-+ to a minimally-sized skbuff. */
-+ if (pkt_len < rx_copybreak
-+ && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
-+ skb->dev = dev;
-+ skb_reserve(skb, 2); /* 16 byte align the IP header */
-+#if HAS_IP_COPYSUM /* Call copy + cksum if available. */
-+ eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0);
-+ skb_put(skb, pkt_len);
-+#else
-+ memcpy(skb_put(skb, pkt_len), np->rx_skbuff[entry]->tail,
-+ pkt_len);
-+#endif
-+ } else {
-+ char *temp = skb_put(skb = np->rx_skbuff[entry], pkt_len);
-+ np->rx_skbuff[entry] = NULL;
-+#ifndef final_version /* Remove after testing. */
-+ if (le32desc_to_virt(np->rx_ring[entry].rxaddr & ~3) != temp)
-+ printk(KERN_ERR "%s: Internal fault: The skbuff addresses "
-+ "do not match in netdev_rx: %p vs. %p / %p.\n",
-+ dev->name,
-+ le32desc_to_virt(np->rx_ring[entry].rxaddr),
-+ skb->head, temp);
-+#endif
-+ }
-+ skb->protocol = eth_type_trans(skb, dev);
-+#ifdef full_rx_status
-+ if (np->rx_done_q[np->rx_done].status2 & cpu_to_le32(0x01000000))
-+ skb->ip_summed = CHECKSUM_UNNECESSARY;
-+#endif
-+ netif_rx(skb);
-+ dev->last_rx = jiffies;
-+ np->stats.rx_packets++;
-+ }
-+ np->cur_rx++;
-+ np->rx_done_q[np->rx_done].status = 0;
-+ np->rx_done = (np->rx_done + 1) & (DONE_Q_SIZE-1);
-+ }
-+ writew(np->rx_done, dev->base_addr + CompletionQConsumerIdx);
-+
-+ /* Refill the Rx ring buffers. */
-+ for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) {
-+ struct sk_buff *skb;
-+ int entry = np->dirty_rx % RX_RING_SIZE;
-+ if (np->rx_skbuff[entry] == NULL) {
-+ skb = dev_alloc_skb(np->rx_buf_sz);
-+ np->rx_skbuff[entry] = skb;
-+ if (skb == NULL)
-+ break; /* Better luck next round. */
-+ skb->dev = dev; /* Mark as being used by this device. */
-+ np->rx_ring[entry].rxaddr =
-+ virt_to_le32desc(skb->tail) | cpu_to_le32(RxDescValid);
-+ }
-+ if (entry == RX_RING_SIZE - 1)
-+ np->rx_ring[entry].rxaddr |= cpu_to_le32(RxDescEndRing);
-+ /* We could defer this until later... */
-+ writew(entry, dev->base_addr + RxDescQIdx);
-+ }
-+
-+ if ((np->msg_level & NETIF_MSG_RX_STATUS)
-+ || memcmp(np->pad0, np->pad0 + 1, sizeof(np->pad0) -1))
-+ printk(KERN_DEBUG " exiting netdev_rx() status of %d was %8.8x %d.\n",
-+ np->rx_done, desc_status,
-+ memcmp(np->pad0, np->pad0 + 1, sizeof(np->pad0) -1));
-+
-+ return 0;
-+}
-+
-+static void netdev_error(struct net_device *dev, int intr_status)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+
-+ if (intr_status & LinkChange) {
-+ int phy_num = np->phys[0];
-+ if (np->msg_level & NETIF_MSG_LINK)
-+ printk(KERN_NOTICE "%s: Link changed: Autonegotiation advertising"
-+ " %4.4x partner %4.4x.\n", dev->name,
-+ mdio_read(dev, phy_num, 4),
-+ mdio_read(dev, phy_num, 5));
-+ /* Clear sticky bit. */
-+ mdio_read(dev, phy_num, 1);
-+ /* If link beat has returned... */
-+ if (mdio_read(dev, phy_num, 1) & 0x0004)
-+ netif_link_up(dev);
-+ else
-+ netif_link_down(dev);
-+ check_duplex(dev);
-+ }
-+ if (intr_status & StatsMax) {
-+ get_stats(dev);
-+ }
-+ /* Came close to underrunning the Tx FIFO, increase threshold. */
-+ if (intr_status & IntrTxDataLow)
-+ writel(++np->tx_threshold, dev->base_addr + TxThreshold);
-+ /* Ingore expected normal events, and handled abnormal events. */
-+ if ((intr_status &
-+ ~(IntrAbnormalSummary|LinkChange|StatsMax|IntrTxDataLow| 0xFF01))
-+ && (np->msg_level & NETIF_MSG_DRV))
-+ printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n",
-+ dev->name, intr_status);
-+ /* Hmmmmm, it's not clear how to recover from PCI faults. */
-+ if (intr_status & IntrTxPCIErr)
-+ np->stats.tx_fifo_errors++;
-+ if (intr_status & IntrRxPCIErr)
-+ np->stats.rx_fifo_errors++;
-+}
-+
-+static struct net_device_stats *get_stats(struct net_device *dev)
-+{
-+ long ioaddr = dev->base_addr;
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+
-+ /* This adapter architecture needs no SMP locks. */
-+#if LINUX_VERSION_CODE > 0x20119
-+ np->stats.tx_bytes = readl(ioaddr + 0x57010);
-+ np->stats.rx_bytes = readl(ioaddr + 0x57044);
-+#endif
-+ np->stats.tx_packets = readl(ioaddr + 0x57000);
-+ np->stats.tx_aborted_errors =
-+ readl(ioaddr + 0x57024) + readl(ioaddr + 0x57028);
-+ np->stats.tx_window_errors = readl(ioaddr + 0x57018);
-+ np->stats.collisions = readl(ioaddr + 0x57004) + readl(ioaddr + 0x57008);
-+
-+ /* The chip only need report frame silently dropped. */
-+ np->stats.rx_dropped += readw(ioaddr + RxDMAStatus);
-+ writew(0, ioaddr + RxDMAStatus);
-+ np->stats.rx_crc_errors = readl(ioaddr + 0x5703C);
-+ np->stats.rx_frame_errors = readl(ioaddr + 0x57040);
-+ np->stats.rx_length_errors = readl(ioaddr + 0x57058);
-+ np->stats.rx_missed_errors = readl(ioaddr + 0x5707C);
-+
-+ return &np->stats;
-+}
-+
-+/* The little-endian AUTODIN II ethernet CRC calculations.
-+ A big-endian version is also available.
-+ This is slow but compact code. Do not use this routine for bulk data,
-+ use a table-based routine instead.
-+ This is common code and should be moved to net/core/crc.c.
-+ Chips may use the upper or lower CRC bits, and may reverse and/or invert
-+ them. Select the endian-ness that results in minimal calculations.
-+*/
-+static unsigned const ethernet_polynomial_le = 0xedb88320U;
-+static inline unsigned ether_crc_le(int length, unsigned char *data)
-+{
-+ unsigned int crc = ~0; /* Initial value. */
-+ while(--length >= 0) {
-+ unsigned char current_octet = *data++;
-+ int bit;
-+ for (bit = 8; --bit >= 0; current_octet >>= 1) {
-+ if ((crc ^ current_octet) & 1) {
-+ crc >>= 1;
-+ crc ^= ethernet_polynomial_le;
-+ } else
-+ crc >>= 1;
-+ }
-+ }
-+ return crc;
-+}
-+
-+static void set_rx_mode(struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+ u32 rx_mode;
-+ struct dev_mc_list *mclist;
-+ int i;
-+
-+ if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
-+ /* Unconditionally log net taps. */
-+ printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);
-+ rx_mode = AcceptBroadcast|AcceptAllMulticast|AcceptAll|AcceptMyPhys;
-+ } else if ((dev->mc_count > np->multicast_filter_limit)
-+ || (dev->flags & IFF_ALLMULTI)) {
-+ /* Too many to match, or accept all multicasts. */
-+ rx_mode = AcceptBroadcast|AcceptAllMulticast|AcceptMyPhys;
-+ } else if (dev->mc_count <= 15) {
-+ /* Use the 16 element perfect filter. */
-+ long filter_addr = ioaddr + 0x56000 + 1*16;
-+ for (i = 1, mclist = dev->mc_list; mclist && i <= dev->mc_count;
-+ i++, mclist = mclist->next) {
-+ u16 *eaddrs = (u16 *)mclist->dmi_addr;
-+ writew(cpu_to_be16(eaddrs[2]), filter_addr); filter_addr += 4;
-+ writew(cpu_to_be16(eaddrs[1]), filter_addr); filter_addr += 4;
-+ writew(cpu_to_be16(eaddrs[0]), filter_addr); filter_addr += 8;
-+ }
-+ while (i++ < 16) {
-+ writew(0xffff, filter_addr); filter_addr += 4;
-+ writew(0xffff, filter_addr); filter_addr += 4;
-+ writew(0xffff, filter_addr); filter_addr += 8;
-+ }
-+ rx_mode = AcceptBroadcast | AcceptMyPhys;
-+ } else {
-+ /* Must use a multicast hash table. */
-+ long filter_addr;
-+ u16 mc_filter[32]; /* Multicast hash filter */
-+
-+ memset(mc_filter, 0, sizeof(mc_filter));
-+ for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
-+ i++, mclist = mclist->next) {
-+ set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) >> 23, mc_filter);
-+ }
-+ /* Clear the perfect filter list. */
-+ filter_addr = ioaddr + 0x56000 + 1*16;
-+ for (i = 1; i < 16; i++) {
-+ writew(0xffff, filter_addr); filter_addr += 4;
-+ writew(0xffff, filter_addr); filter_addr += 4;
-+ writew(0xffff, filter_addr); filter_addr += 8;
-+ }
-+ for (filter_addr=ioaddr + 0x56100, i=0; i < 32; filter_addr+= 16, i++){
-+ np->mc_filter[i] = mc_filter[i];
-+ writew(mc_filter[i], filter_addr);
-+ }
-+ rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
-+ }
-+ writel(rx_mode, ioaddr + RxFilterMode);
-+}
-+
-+/*
-+ Handle user-level ioctl() calls.
-+ We must use two numeric constants as the key because some clueless person
-+ changed the value for the symbolic name.
-+*/
-+static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ u16 *data = (u16 *)&rq->ifr_data;
-+ u32 *data32 = (void *)&rq->ifr_data;
-+
-+ switch(cmd) {
-+ case 0x8947: case 0x89F0:
-+ /* SIOCGMIIPHY: Get the address of the PHY in use. */
-+ data[0] = np->phys[0] & 0x1f;
-+ /* Fall Through */
-+ case 0x8948: case 0x89F1:
-+ /* SIOCGMIIREG: Read the specified MII register. */
-+ data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f);
-+ return 0;
-+ case 0x8949: case 0x89F2:
-+ /* SIOCSMIIREG: Write the specified MII register */
-+ if (!capable(CAP_NET_ADMIN))
-+ return -EPERM;
-+ if (data[0] == np->phys[0]) {
-+ u16 value = data[2];
-+ switch (data[1]) {
-+ case 0:
-+ /* Check for autonegotiation on or reset. */
-+ np->medialock = (value & 0x9000) ? 0 : 1;
-+ if (np->medialock)
-+ np->full_duplex = (value & 0x0100) ? 1 : 0;
-+ break;
-+ case 4: np->advertising = value; break;
-+ }
-+ check_duplex(dev);
-+ }
-+ mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]);
-+ return 0;
-+ case SIOCGPARAMS:
-+ data32[0] = np->msg_level;
-+ data32[1] = np->multicast_filter_limit;
-+ data32[2] = np->max_interrupt_work;
-+ data32[3] = np->rx_copybreak;
-+ return 0;
-+ case SIOCSPARAMS:
-+ if (!capable(CAP_NET_ADMIN))
-+ return -EPERM;
-+ np->msg_level = data32[0];
-+ np->multicast_filter_limit = data32[1];
-+ np->max_interrupt_work = data32[2];
-+ np->rx_copybreak = data32[3];
-+ return 0;
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+}
-+
-+static int netdev_close(struct net_device *dev)
-+{
-+ long ioaddr = dev->base_addr;
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ int i;
-+
-+ netif_stop_tx_queue(dev);
-+
-+ if (np->msg_level & NETIF_MSG_IFDOWN) {
-+ printk(KERN_DEBUG "%s: Shutting down ethercard, Intr status %4.4x.\n",
-+ dev->name, (int)readl(ioaddr + IntrStatus));
-+ printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d, Rx %d / %d.\n",
-+ dev->name, np->cur_tx, np->dirty_tx, np->cur_rx, np->dirty_rx);
-+ }
-+
-+ /* Disable interrupts by clearing the interrupt mask. */
-+ writel(0, ioaddr + IntrEnable);
-+
-+ /* Stop the chip's Tx and Rx processes. */
-+ writel(0, ioaddr + GenCtrl);
-+
-+ del_timer(&np->timer);
-+
-+#ifdef __i386__
-+ if (np->msg_level & NETIF_MSG_IFDOWN) {
-+ printk("\n"KERN_DEBUG" Tx ring at %8.8x:\n",
-+ (int)virt_to_bus(np->tx_ring));
-+ for (i = 0; i < 8 /* TX_RING_SIZE is huge! */; i++)
-+ printk(KERN_DEBUG " #%d desc. %8.8x %8.8x -> %8.8x.\n",
-+ i, np->tx_ring[i].status, np->tx_ring[i].addr,
-+ np->tx_done_q[i].status);
-+ printk(KERN_DEBUG " Rx ring at %8.8x -> %p:\n",
-+ (int)virt_to_bus(np->rx_ring), np->rx_done_q);
-+ if (np->rx_done_q)
-+ for (i = 0; i < 8 /* RX_RING_SIZE */; i++) {
-+ printk(KERN_DEBUG " #%d desc. %8.8x -> %8.8x\n",
-+ i, np->rx_ring[i].rxaddr, np->rx_done_q[i].status);
-+ }
-+ }
-+#endif /* __i386__ debugging only */
-+
-+ free_irq(dev->irq, dev);
-+
-+ /* Free all the skbuffs in the Rx queue. */
-+ for (i = 0; i < RX_RING_SIZE; i++) {
-+ np->rx_ring[i].rxaddr = 0xBADF00D0; /* An invalid address. */
-+ if (np->rx_skbuff[i]) {
-+#if LINUX_VERSION_CODE < 0x20100
-+ np->rx_skbuff[i]->free = 1;
-+#endif
-+ dev_free_skb(np->rx_skbuff[i]);
-+ }
-+ np->rx_skbuff[i] = 0;
-+ }
-+ for (i = 0; i < TX_RING_SIZE; i++) {
-+ if (np->tx_skbuff[i])
-+ dev_free_skb(np->tx_skbuff[i]);
-+ np->tx_skbuff[i] = 0;
-+ }
-+
-+ MOD_DEC_USE_COUNT;
-+
-+ return 0;
-+}
-+
-+
-+static int starfire_pwr_event(void *dev_instance, int event)
-+{
-+ struct net_device *dev = dev_instance;
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+
-+ if (np->msg_level & NETIF_MSG_LINK)
-+ printk(KERN_DEBUG "%s: Handling power event %d.\n", dev->name, event);
-+ switch(event) {
-+ case DRV_ATTACH:
-+ MOD_INC_USE_COUNT;
-+ break;
-+ case DRV_SUSPEND:
-+ /* Disable interrupts, stop Tx and Rx. */
-+ writel(0x0000, ioaddr + IntrEnable);
-+ writel(0, ioaddr + GenCtrl);
-+ break;
-+ case DRV_RESUME:
-+ /* This is incomplete: we must factor start_chip() out of open(). */
-+ writel(np->tx_threshold, ioaddr + TxThreshold);
-+ writel(interrupt_mitigation, ioaddr + IntrTimerCtrl);
-+ set_rx_mode(dev);
-+ writel(np->intr_enable, ioaddr + IntrEnable);
-+ writel(TxEnable|RxEnable, ioaddr + GenCtrl);
-+ break;
-+ case DRV_DETACH: {
-+ struct net_device **devp, **next;
-+ if (dev->flags & IFF_UP) {
-+ /* Some, but not all, kernel versions close automatically. */
-+ dev_close(dev);
-+ dev->flags &= ~(IFF_UP|IFF_RUNNING);
-+ }
-+ unregister_netdev(dev);
-+ release_region(dev->base_addr, pci_id_tbl[np->chip_id].io_size);
-+#ifndef USE_IO_OPS
-+ iounmap((char *)dev->base_addr);
-+#endif
-+ for (devp = &root_net_dev; *devp; devp = next) {
-+ next = &((struct netdev_private *)(*devp)->priv)->next_module;
-+ if (*devp == dev) {
-+ *devp = *next;
-+ break;
-+ }
-+ }
-+ if (np->priv_addr)
-+ kfree(np->priv_addr);
-+ kfree(dev);
-+ MOD_DEC_USE_COUNT;
-+ break;
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+
-+#ifdef MODULE
-+int init_module(void)
-+{
-+ if (debug >= NETIF_MSG_DRV) /* Emit version even if no cards detected. */
-+ printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2);
-+ if (pci_drv_register(&starfire_drv_id, NULL)) {
-+ printk(KERN_INFO " No Starfire adapters detected, driver not loaded.\n");
-+ return -ENODEV;
-+ }
-+ return 0;
-+}
-+
-+void cleanup_module(void)
-+{
-+ struct net_device *next_dev;
-+
-+ pci_drv_unregister(&starfire_drv_id);
-+
-+ /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
-+ while (root_net_dev) {
-+ struct netdev_private *np = (void *)(root_net_dev->priv);
-+ unregister_netdev(root_net_dev);
-+ iounmap((char *)(root_net_dev->base_addr));
-+ next_dev = np->next_module;
-+ if (np->tx_done_q) free_page((long)np->tx_done_q);
-+ if (np->rx_done_q) free_page((long)np->rx_done_q);
-+ if (np->priv_addr) kfree(np->priv_addr);
-+ kfree(root_net_dev);
-+ root_net_dev = next_dev;
-+ }
-+}
-+
-+#endif /* MODULE */
-+
-+/*
-+ * Local variables:
-+ * compile-command: "make KERNVER=`uname -r` starfire.o"
-+ * compile-cmd: "gcc -DMODULE -Wall -Wstrict-prototypes -O6 -c starfire.c"
-+ * simple-compile-command: "gcc -DMODULE -O6 -c starfire.c"
-+ * c-indent-level: 4
-+ * c-basic-offset: 4
-+ * tab-width: 4
-+ * End:
-+ */
-Index: linux/src/drivers/net/sundance.c
-===================================================================
-RCS file: linux/src/drivers/net/sundance.c
-diff -N linux/src/drivers/net/sundance.c
---- /dev/null 1 Jan 1970 00:00:00 -0000
-+++ linux/src/drivers/net/sundance.c 20 Aug 2004 10:32:54 -0000
-@@ -0,0 +1,1556 @@
-+/* sundance.c: A Linux device driver for the Sundance ST201 "Alta". */
-+/*
-+ Written 1999-2003 by Donald Becker.
-+
-+ This software may be used and distributed according to the terms of
-+ the GNU General Public License (GPL), incorporated herein by reference.
-+ Drivers based on or derived from this code fall under the GPL and must
-+ retain the authorship, copyright and license notice. This file is not
-+ a complete program and may only be used when the entire operating
-+ system is licensed under the GPL.
-+
-+ The author may be reached as becker@scyld.com, or C/O
-+ Scyld Computing Corporation
-+ 410 Severn Ave., Suite 210
-+ Annapolis MD 21403
-+
-+ Support information and updates available at
-+ http://www.scyld.com/network/sundance.html
-+*/
-+
-+/* These identify the driver base version and may not be removed. */
-+static const char version1[] =
-+"sundance.c:v1.11 2/4/2003 Written by Donald Becker <becker@scyld.com>\n";
-+static const char version2[] =
-+" http://www.scyld.com/network/sundance.html\n";
-+/* Updated to recommendations in pci-skeleton v2.12. */
-+
-+/* Automatically extracted configuration info:
-+probe-func: sundance_probe
-+config-in: tristate 'Sundance ST201 "Alta" PCI Ethernet support' CONFIG_SUNDANCE
-+c-help-name: Sundance ST201 "Alta" PCI Ethernet support
-+c-help-symbol: CONFIG_SUNDANCE
-+c-help: This driver is for the Sundance ST201 "Alta" and Kendin KS8723, as
-+c-help: used on the D-Link DFE-550 and DFE-580.
-+c-help: Design information, usage details and updates are available from
-+c-help: http://www.scyld.com/network/sundance.html
-+*/
-+
-+/* The user-configurable values.
-+ These may be modified when a driver module is loaded.*/
-+
-+/* Message enable level: 0..31 = no..all messages. See NETIF_MSG docs. */
-+static int debug = 2;
-+
-+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-+static int max_interrupt_work = 20;
-+
-+/* Maximum number of multicast addresses to filter (vs. rx-all-multicast).
-+ The sundance uses a 64 element hash table based on the Ethernet CRC. */
-+static int multicast_filter_limit = 32;
-+
-+/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
-+ Setting to > 1518 effectively disables this feature.
-+ This chip can receive into any byte alignment buffers, so word-oriented
-+ archs do not need a copy-align of the IP header. */
-+static int rx_copybreak = 0;
-+
-+/* Used to pass the media type, etc.
-+ Both 'options[]' and 'full_duplex[]' should exist for driver
-+ interoperability.
-+ The media type is usually passed in 'options[]'.
-+ The default is autonegotation for speed and duplex.
-+ This should rarely be overridden.
-+ Use option values 0x10/0x20 for 10Mbps, 0x100,0x200 for 100Mbps.
-+ Use option values 0x10 and 0x100 for forcing half duplex fixed speed.
-+ Use option values 0x20 and 0x200 for forcing full duplex operation.
-+*/
-+#define MAX_UNITS 8 /* More are supported, limit only on options */
-+static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-+static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-+
-+/* Operational parameters that are set at compile time. */
-+
-+/* Ring sizes are a power of two only for compile efficiency.
-+ The compiler will convert <unsigned>'%'<2^N> into a bit mask.
-+ There must be at least five Tx entries for the tx_full hysteresis, and
-+ more than 31 requires modifying the Tx status handling error recovery.
-+ Leave a inactive gap in the Tx ring for better cache behavior.
-+ Making the Tx ring too large decreases the effectiveness of channel
-+ bonding and packet priority.
-+ Large receive rings waste memory and impact buffer accounting.
-+ The driver need to protect against interrupt latency and the kernel
-+ not reserving enough available memory.
-+*/
-+#define TX_RING_SIZE 16
-+#define TX_QUEUE_LEN 10 /* Limit ring entries actually used. */
-+#define RX_RING_SIZE 32
-+
-+/* Operational parameters that usually are not changed. */
-+/* Time in jiffies before concluding the transmitter is hung. */
-+#define TX_TIMEOUT (6*HZ)
-+
-+/* Allocation size of Rx buffers with normal sized Ethernet frames.
-+ Do not change this value without good reason. This is not a limit,
-+ but a way to keep a consistent allocation size among drivers.
-+ */
-+#define PKT_BUF_SZ 1536
-+
-+/* Set iff a MII transceiver on any interface requires mdio preamble.
-+ This only set with older tranceivers, so the extra
-+ code size of a per-interface flag is not worthwhile. */
-+static char mii_preamble_required = 0;
-+
-+#ifndef __KERNEL__
-+#define __KERNEL__
-+#endif
-+#if !defined(__OPTIMIZE__)
-+#warning You must compile this file with the correct options!
-+#warning See the last lines of the source file.
-+#error You must compile this driver with "-O".
-+#endif
-+
-+/* Include files, designed to support most kernel versions 2.0.0 and later. */
-+#include <linux/config.h>
-+#if defined(CONFIG_SMP) && ! defined(__SMP__)
-+#define __SMP__
-+#endif
-+#if defined(MODULE) && defined(CONFIG_MODVERSIONS) && ! defined(MODVERSIONS)
-+#define MODVERSIONS
-+#endif
-+
-+#include <linux/version.h>
-+#if defined(MODVERSIONS)
-+#include <linux/modversions.h>
-+#endif
-+#include <linux/module.h>
-+
-+#include <linux/kernel.h>
-+#include <linux/string.h>
-+#include <linux/timer.h>
-+#include <linux/errno.h>
-+#include <linux/ioport.h>
-+#if LINUX_VERSION_CODE >= 0x20400
-+#include <linux/slab.h>
-+#else
-+#include <linux/malloc.h>
-+#endif
-+#include <linux/interrupt.h>
-+#include <linux/pci.h>
-+#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/skbuff.h>
-+#include <asm/bitops.h>
-+#include <asm/io.h>
-+
-+#if LINUX_VERSION_CODE >= 0x20300
-+#include <linux/spinlock.h>
-+#elif LINUX_VERSION_CODE >= 0x20200
-+#include <asm/spinlock.h>
-+#endif
-+
-+#ifdef INLINE_PCISCAN
-+#include "k_compat.h"
-+#else
-+#include "pci-scan.h"
-+#include "kern_compat.h"
-+#endif
-+
-+/* Condensed operations for readability. */
-+#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr))
-+#define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr))
-+
-+#if (LINUX_VERSION_CODE >= 0x20100) && defined(MODULE)
-+char kernel_version[] = UTS_RELEASE;
-+#endif
-+
-+MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
-+MODULE_DESCRIPTION("Sundance Alta Ethernet driver");
-+MODULE_LICENSE("GPL");
-+MODULE_PARM(max_interrupt_work, "i");
-+MODULE_PARM(debug, "i");
-+MODULE_PARM(rx_copybreak, "i");
-+MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
-+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
-+MODULE_PARM(multicast_filter_limit, "i");
-+
-+MODULE_PARM_DESC(debug, "Driver message level (0-31)");
-+MODULE_PARM_DESC(options, "Force transceiver type or fixed speed+duplex");
-+MODULE_PARM_DESC(max_interrupt_work,
-+ "Driver maximum events handled per interrupt");
-+MODULE_PARM_DESC(full_duplex,
-+ "Non-zero to set forced full duplex (deprecated).");
-+MODULE_PARM_DESC(rx_copybreak,
-+ "Breakpoint in bytes for copy-only-tiny-frames");
-+MODULE_PARM_DESC(multicast_filter_limit,
-+ "Multicast addresses before switching to Rx-all-multicast");
-+
-+/*
-+ Theory of Operation
-+
-+I. Board Compatibility
-+
-+This driver is designed for the Sundance Technologies "Alta" ST201 chip.
-+The Kendin KS8723 is the same design with an integrated transceiver and
-+new quirks.
-+
-+II. Board-specific settings
-+
-+This is an all-in-one chip, so there are no board-specific settings.
-+
-+III. Driver operation
-+
-+IIIa. Ring buffers
-+
-+This driver uses two statically allocated fixed-size descriptor lists
-+formed into rings by a branch from the final descriptor to the beginning of
-+the list. The ring sizes are set at compile time by RX/TX_RING_SIZE.
-+Some chips explicitly use only 2^N sized rings, while others use a
-+'next descriptor' pointer that the driver forms into rings.
-+
-+IIIb/c. Transmit/Receive Structure
-+
-+This driver uses a zero-copy receive and transmit scheme.
-+The driver allocates full frame size skbuffs for the Rx ring buffers at
-+open() time and passes the skb->data field to the chip as receive data
-+buffers. When an incoming frame is less than RX_COPYBREAK bytes long,
-+a fresh skbuff is allocated and the frame is copied to the new skbuff.
-+When the incoming frame is larger, the skbuff is passed directly up the
-+protocol stack. Buffers consumed this way are replaced by newly allocated
-+skbuffs in a later phase of receives.
-+
-+The RX_COPYBREAK value is chosen to trade-off the memory wasted by
-+using a full-sized skbuff for small frames vs. the copying costs of larger
-+frames. New boards are typically used in generously configured machines
-+and the underfilled buffers have negligible impact compared to the benefit of
-+a single allocation size, so the default value of zero results in never
-+copying packets. When copying is done, the cost is usually mitigated by using
-+a combined copy/checksum routine. Copying also preloads the cache, which is
-+most useful with small frames.
-+
-+A subtle aspect of the operation is that the IP header at offset 14 in an
-+ethernet frame isn't longword aligned for further processing.
-+Unaligned buffers are permitted by the Sundance hardware, so
-+frames are received into the skbuff at an offset of "+2", 16-byte aligning
-+the IP header.
-+
-+IIId. Synchronization
-+
-+The driver runs as two independent, single-threaded flows of control. One
-+is the send-packet routine, which enforces single-threaded use by the
-+dev->tbusy flag. The other thread is the interrupt handler, which is single
-+threaded by the hardware and interrupt handling software.
-+
-+The send packet thread has partial control over the Tx ring and 'dev->tbusy'
-+flag. It sets the tbusy flag whenever it's queuing a Tx packet. If the next
-+queue slot is empty, it clears the tbusy flag when finished otherwise it sets
-+the 'lp->tx_full' flag.
-+
-+The interrupt handler has exclusive control over the Rx ring and records stats
-+from the Tx ring. After reaping the stats, it marks the Tx queue entry as
-+empty by incrementing the dirty_tx mark. Iff the 'lp->tx_full' flag is set, it
-+clears both the tx_full and tbusy flags.
-+
-+IV. Notes
-+
-+IVb. References
-+
-+The Sundance ST201 datasheet, preliminary version.
-+The Kendin KS8723 datasheet, preliminary version.
-+http://www.scyld.com/expert/100mbps.html
-+http://www.scyld.com/expert/NWay.html
-+
-+IVc. Errata
-+
-+*/
-+
-+
-+
-+/* Work-around for Kendin chip bugs. This will be reversed after tracking
-+ down all of the chip access quirks in memory mode. */
-+#ifndef USE_MEM_OPS
-+#define USE_IO_OPS 1
-+#endif
-+
-+static void *sundance_probe1(struct pci_dev *pdev, void *init_dev,
-+ long ioaddr, int irq, int chip_idx, int find_cnt);
-+static int sundance_pwr_event(void *dev_instance, int event);
-+
-+enum chip_capability_flags {CanHaveMII=1, KendinPktDropBug=2, };
-+#ifdef USE_IO_OPS
-+#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_IO | PCI_ADDR0)
-+#else
-+#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR1)
-+#endif
-+
-+static struct pci_id_info pci_id_tbl[] = {
-+ {"D-Link DFE-580TX (Kendin/Sundance ST201 Alta)",
-+ {0x10021186, 0xffffffff, 0x10121186, 0xffffffff, 0x14, 0xff},
-+ PCI_IOTYPE, 128, CanHaveMII|KendinPktDropBug},
-+ {"D-Link DFE-580TX (Sundance ST201)",
-+ {0x10021186, 0xffffffff, 0x10121186, 0xffffffff, },
-+ PCI_IOTYPE, 128, CanHaveMII|KendinPktDropBug},
-+ {"D-Link DFE-550FX 100baseFx (Sundance ST201)",
-+ {0x10031186, 0xffffffff, },
-+ PCI_IOTYPE, 128, CanHaveMII|KendinPktDropBug},
-+ {"OEM Sundance Technology ST201", {0x10021186, 0xffffffff, },
-+ PCI_IOTYPE, 128, CanHaveMII},
-+ {"Sundance Technology Alta", {0x020113F0, 0xffffffff, },
-+ PCI_IOTYPE, 128, CanHaveMII},
-+ {0,}, /* 0 terminated list. */
-+};
-+
-+struct drv_id_info sundance_drv_id = {
-+ "sundance", PCI_HOTSWAP, PCI_CLASS_NETWORK_ETHERNET<<8, pci_id_tbl,
-+ sundance_probe1, sundance_pwr_event };
-+
-+/* This driver was written to use PCI memory space, however x86-oriented
-+ hardware often uses I/O space accesses. */
-+#ifdef USE_IO_OPS
-+#undef readb
-+#undef readw
-+#undef readl
-+#undef writeb
-+#undef writew
-+#undef writel
-+#define readb inb
-+#define readw inw
-+#define readl inl
-+#define writeb outb
-+#define writew outw
-+#define writel outl
-+#endif
-+
-+/* Offsets to the device registers.
-+ Unlike software-only systems, device drivers interact with complex hardware.
-+ It's not useful to define symbolic names for every register bit in the
-+ device. The name can only partially document the semantics and make
-+ the driver longer and more difficult to read.
-+ In general, only the important configuration values or bits changed
-+ multiple times should be defined symbolically.
-+*/
-+enum alta_offsets {
-+ DMACtrl=0x00, TxListPtr=0x04, TxDMACtrl=0x08, TxDescPoll=0x0a,
-+ RxDMAStatus=0x0c, RxListPtr=0x10, RxDMACtrl=0x14, RxDescPoll=0x16,
-+ LEDCtrl=0x1a, ASICCtrl=0x30,
-+ EEData=0x34, EECtrl=0x36, TxThreshold=0x3c,
-+ FlashAddr=0x40, FlashData=0x44, WakeEvent=0x45, TxStatus=0x46,
-+ DownCounter=0x48, IntrClear=0x4a, IntrEnable=0x4c, IntrStatus=0x4e,
-+ MACCtrl0=0x50, MACCtrl1=0x52, StationAddr=0x54,
-+ MaxFrameSize=0x5A, RxMode=0x5c, MIICtrl=0x5e,
-+ MulticastFilter0=0x60, MulticastFilter1=0x64,
-+ RxOctetsLow=0x68, RxOctetsHigh=0x6a, TxOctetsLow=0x6c, TxOctetsHigh=0x6e,
-+ TxFramesOK=0x70, RxFramesOK=0x72, StatsCarrierError=0x74,
-+ StatsLateColl=0x75, StatsMultiColl=0x76, StatsOneColl=0x77,
-+ StatsTxDefer=0x78, RxMissed=0x79, StatsTxXSDefer=0x7a, StatsTxAbort=0x7b,
-+ StatsBcastTx=0x7c, StatsBcastRx=0x7d, StatsMcastTx=0x7e, StatsMcastRx=0x7f,
-+ /* Aliased and bogus values! */
-+ RxStatus=0x0c,
-+};
-+
-+/* Bits in the interrupt status/mask registers. */
-+enum intr_status_bits {
-+ IntrSummary=0x0001, IntrPCIErr=0x0002, IntrMACCtrl=0x0008,
-+ IntrTxDone=0x0004, IntrRxDone=0x0010, IntrRxStart=0x0020,
-+ IntrDrvRqst=0x0040,
-+ StatsMax=0x0080, LinkChange=0x0100,
-+ IntrTxDMADone=0x0200, IntrRxDMADone=0x0400,
-+};
-+
-+/* Bits in the RxMode register. */
-+enum rx_mode_bits {
-+ AcceptAllIPMulti=0x20, AcceptMultiHash=0x10, AcceptAll=0x08,
-+ AcceptBroadcast=0x04, AcceptMulticast=0x02, AcceptMyPhys=0x01,
-+};
-+/* Bits in MACCtrl. */
-+enum mac_ctrl0_bits {
-+ EnbFullDuplex=0x20, EnbRcvLargeFrame=0x40,
-+ EnbFlowCtrl=0x100, EnbPassRxCRC=0x200,
-+};
-+enum mac_ctrl1_bits {
-+ StatsEnable=0x0020, StatsDisable=0x0040, StatsEnabled=0x0080,
-+ TxEnable=0x0100, TxDisable=0x0200, TxEnabled=0x0400,
-+ RxEnable=0x0800, RxDisable=0x1000, RxEnabled=0x2000,
-+};
-+
-+/* The Rx and Tx buffer descriptors.
-+ Using only 32 bit fields simplifies software endian correction.
-+ This structure must be aligned, and should avoid spanning cache lines.
-+*/
-+struct netdev_desc {
-+ u32 next_desc;
-+ u32 status;
-+ struct desc_frag { u32 addr, length; } frag[1];
-+};
-+
-+/* Bits in netdev_desc.status */
-+enum desc_status_bits {
-+ DescOwn=0x8000, DescEndPacket=0x4000, DescEndRing=0x2000,
-+ DescTxDMADone=0x10000,
-+ LastFrag=0x80000000, DescIntrOnTx=0x8000, DescIntrOnDMADone=0x80000000,
-+};
-+
-+#define PRIV_ALIGN 15 /* Required alignment mask */
-+/* Use __attribute__((aligned (L1_CACHE_BYTES))) to maintain alignment
-+ within the structure. */
-+struct netdev_private {
-+ /* Descriptor rings first for alignment. */
-+ struct netdev_desc rx_ring[RX_RING_SIZE];
-+ struct netdev_desc tx_ring[TX_RING_SIZE];
-+ struct net_device *next_module; /* Link for devices of this type. */
-+ void *priv_addr; /* Unaligned address for kfree */
-+ const char *product_name;
-+ /* The addresses of receive-in-place skbuffs. */
-+ struct sk_buff* rx_skbuff[RX_RING_SIZE];
-+ /* The saved address of a sent-in-place packet/buffer, for later free(). */
-+ struct sk_buff* tx_skbuff[TX_RING_SIZE];
-+ struct net_device_stats stats;
-+ struct timer_list timer; /* Media monitoring timer. */
-+ /* Frequently used values: keep some adjacent for cache effect. */
-+ int msg_level;
-+ int chip_id, drv_flags;
-+ struct pci_dev *pci_dev;
-+ int max_interrupt_work;
-+
-+ /* Note: Group variables for cache line effect. */
-+ struct netdev_desc *rx_head_desc;
-+ unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */
-+ unsigned int rx_buf_sz; /* Based on MTU+slack. */
-+ int rx_copybreak;
-+
-+ spinlock_t txlock; /* Group with Tx control cache line. */
-+ struct netdev_desc *last_tx; /* Last Tx descriptor used. */
-+ unsigned int cur_tx, dirty_tx;
-+ unsigned int tx_full:1; /* The Tx queue is full. */
-+
-+ /* These values keep track of the transceiver/media in use. */
-+ unsigned int full_duplex:1; /* Full-duplex operation requested. */
-+ unsigned int duplex_lock:1;
-+ unsigned int medialock:1; /* Do not sense media. */
-+ unsigned int default_port; /* Last dev->if_port value. */
-+ /* Multicast and receive mode. */
-+ spinlock_t mcastlock; /* SMP lock multicast updates. */
-+ u16 mcast_filter[4];
-+ int multicast_filter_limit;
-+
-+ /* MII transceiver section. */
-+ int mii_cnt; /* MII device addresses. */
-+ int link_status;
-+ u16 advertising; /* NWay media advertisement */
-+ unsigned char phys[2]; /* MII device addresses. */
-+};
-+
-+/* The station address location in the EEPROM. */
-+#define EEPROM_SA_OFFSET 0x10
-+
-+static int eeprom_read(long ioaddr, int location);
-+static int mdio_read(struct net_device *dev, int phy_id,
-+ unsigned int location);
-+static void mdio_write(struct net_device *dev, int phy_id,
-+ unsigned int location, int value);
-+static int netdev_open(struct net_device *dev);
-+static void sundance_start(struct net_device *dev);
-+static int change_mtu(struct net_device *dev, int new_mtu);
-+static void check_duplex(struct net_device *dev);
-+static void netdev_timer(unsigned long data);
-+static void tx_timeout(struct net_device *dev);
-+static void init_ring(struct net_device *dev);
-+static int start_tx(struct sk_buff *skb, struct net_device *dev);
-+static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs);
-+static void netdev_error(struct net_device *dev, int intr_status);
-+static int netdev_rx(struct net_device *dev);
-+static void netdev_error(struct net_device *dev, int intr_status);
-+static void set_rx_mode(struct net_device *dev);
-+static struct net_device_stats *get_stats(struct net_device *dev);
-+static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-+static int netdev_close(struct net_device *dev);
-+
-+
-+
-+/* A list of our installed devices, for removing the driver module. */
-+static struct net_device *root_net_dev = NULL;
-+
-+#ifndef MODULE
-+int sundance_probe(struct net_device *dev)
-+{
-+ if (pci_drv_register(&sundance_drv_id, dev) < 0)
-+ return -ENODEV;
-+ if (debug >= NETIF_MSG_DRV) /* Emit version even if no cards detected. */
-+ printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2);
-+ return 0;
-+}
-+#endif
-+
-+static void *sundance_probe1(struct pci_dev *pdev, void *init_dev,
-+ long ioaddr, int irq, int chip_idx, int card_idx)
-+{
-+ struct net_device *dev;
-+ struct netdev_private *np;
-+ void *priv_mem;
-+ int i, option = card_idx < MAX_UNITS ? options[card_idx] : 0;
-+
-+ dev = init_etherdev(init_dev, 0);
-+ if (!dev)
-+ return NULL;
-+
-+ /* Perhaps NETIF_MSG_PROBE */
-+ printk(KERN_INFO "%s: %s at 0x%lx, ",
-+ dev->name, pci_id_tbl[chip_idx].name, ioaddr);
-+
-+ for (i = 0; i < 3; i++)
-+ ((u16 *)dev->dev_addr)[i] =
-+ le16_to_cpu(eeprom_read(ioaddr, i + EEPROM_SA_OFFSET));
-+ for (i = 0; i < 5; i++)
-+ printk("%2.2x:", dev->dev_addr[i]);
-+ printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);
-+
-+ /* Make certain elements e.g. descriptor lists are aligned. */
-+ priv_mem = kmalloc(sizeof(*np) + PRIV_ALIGN, GFP_KERNEL);
-+ /* Check for the very unlikely case of no memory. */
-+ if (priv_mem == NULL)
-+ return NULL;
-+
-+ /* All failure checks before this point.
-+ We do a request_region() only to register /proc/ioports info. */
-+#ifdef USE_IO_OPS
-+ request_region(ioaddr, pci_id_tbl[chip_idx].io_size, dev->name);
-+#endif
-+
-+ dev->base_addr = ioaddr;
-+ dev->irq = irq;
-+
-+ dev->priv = np = (void *)(((long)priv_mem + PRIV_ALIGN) & ~PRIV_ALIGN);
-+ memset(np, 0, sizeof(*np));
-+ np->priv_addr = priv_mem;
-+
-+ np->next_module = root_net_dev;
-+ root_net_dev = dev;
-+
-+ np->pci_dev = pdev;
-+ np->chip_id = chip_idx;
-+ np->drv_flags = pci_id_tbl[chip_idx].drv_flags;
-+ np->msg_level = (1 << debug) - 1;
-+ np->rx_copybreak = rx_copybreak;
-+ np->max_interrupt_work = max_interrupt_work;
-+ np->multicast_filter_limit = multicast_filter_limit;
-+
-+ if (dev->mem_start)
-+ option = dev->mem_start;
-+
-+ if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0)
-+ np->full_duplex = 1;
-+
-+ if (np->full_duplex)
-+ np->medialock = 1;
-+
-+ /* The chip-specific entries in the device structure. */
-+ dev->open = &netdev_open;
-+ dev->hard_start_xmit = &start_tx;
-+ dev->stop = &netdev_close;
-+ dev->get_stats = &get_stats;
-+ dev->set_multicast_list = &set_rx_mode;
-+ dev->do_ioctl = &mii_ioctl;
-+ dev->change_mtu = &change_mtu;
-+
-+ if (1) {
-+ int phy, phy_idx = 0;
-+ np->phys[0] = 1; /* Default setting */
-+ mii_preamble_required++;
-+ for (phy = 1; phy < 32 && phy_idx < 4; phy++) {
-+ int mii_status = mdio_read(dev, phy, 1);
-+ if (mii_status != 0xffff && mii_status != 0x0000) {
-+ np->phys[phy_idx++] = phy;
-+ np->advertising = mdio_read(dev, phy, 4);
-+ if ((mii_status & 0x0040) == 0)
-+ mii_preamble_required++;
-+ if (np->msg_level & NETIF_MSG_PROBE)
-+ printk(KERN_INFO "%s: MII PHY found at address %d, status "
-+ "0x%4.4x advertising %4.4x.\n",
-+ dev->name, phy, mii_status, np->advertising);
-+ }
-+ }
-+ mii_preamble_required--;
-+ np->mii_cnt = phy_idx;
-+ if (phy_idx == 0)
-+ printk(KERN_INFO "%s: No MII transceiver found!, ASIC status %x\n",
-+ dev->name, (int)readl(ioaddr + ASICCtrl));
-+ }
-+
-+ /* Allow forcing the media type. */
-+ if (option > 0) {
-+ if (option & 0x220)
-+ np->full_duplex = 1;
-+ np->default_port = option & 0x3ff;
-+ if (np->default_port & 0x330) {
-+ np->medialock = 1;
-+ if (np->msg_level & NETIF_MSG_PROBE)
-+ printk(KERN_INFO " Forcing %dMbs %s-duplex operation.\n",
-+ (option & 0x300 ? 100 : 10),
-+ (np->full_duplex ? "full" : "half"));
-+ if (np->mii_cnt)
-+ mdio_write(dev, np->phys[0], 0,
-+ ((option & 0x300) ? 0x2000 : 0) | /* 100mbps? */
-+ (np->full_duplex ? 0x0100 : 0)); /* Full duplex? */
-+ }
-+ }
-+
-+ /* Reset the chip to erase previous misconfiguration. */
-+ if (np->msg_level & NETIF_MSG_MISC)
-+ printk("ASIC Control is %x.\n", (int)readl(ioaddr + ASICCtrl));
-+ writel(0x007f0000 | readl(ioaddr + ASICCtrl), ioaddr + ASICCtrl);
-+ if (np->msg_level & NETIF_MSG_MISC)
-+ printk("ASIC Control is now %x.\n", (int)readl(ioaddr + ASICCtrl));
-+
-+ return dev;
-+}
-+
-+
-+
-+static int change_mtu(struct net_device *dev, int new_mtu)
-+{
-+ if ((new_mtu < 68) || (new_mtu > 8191)) /* Limited by RxDMAFrameLen */
-+ return -EINVAL;
-+ if (netif_running(dev))
-+ return -EBUSY;
-+ dev->mtu = new_mtu;
-+ return 0;
-+}
-+
-+/* Read the EEPROM and MII Management Data I/O (MDIO) interfaces. */
-+static int eeprom_read(long ioaddr, int location)
-+{
-+ int boguscnt = 2000; /* Typical 190 ticks. */
-+ writew(0x0200 | (location & 0xff), ioaddr + EECtrl);
-+ do {
-+ if (! (readw(ioaddr + EECtrl) & 0x8000)) {
-+ return readw(ioaddr + EEData);
-+ }
-+ } while (--boguscnt > 0);
-+ return 0;
-+}
-+
-+/* MII transceiver control section.
-+ Read and write the MII registers using software-generated serial
-+ MDIO protocol. See the MII specifications or DP83840A data sheet
-+ for details.
-+
-+ The maximum data clock rate is 2.5 Mhz.
-+ The timing is decoupled from the processor clock by flushing the write
-+ from the CPU write buffer with a following read, and using PCI
-+ transaction time. */
-+#define mdio_in(mdio_addr) readb(mdio_addr)
-+#define mdio_out(value, mdio_addr) writeb(value, mdio_addr)
-+#define mdio_delay(mdio_addr) readb(mdio_addr)
-+
-+enum mii_reg_bits {
-+ MDIO_ShiftClk=0x0001, MDIO_Data=0x0002, MDIO_EnbOutput=0x0004,
-+};
-+#define MDIO_EnbIn (0)
-+#define MDIO_WRITE0 (MDIO_EnbOutput)
-+#define MDIO_WRITE1 (MDIO_Data | MDIO_EnbOutput)
-+
-+/* Generate the preamble required for initial synchronization and
-+ a few older transceivers. */
-+static void mdio_sync(long mdio_addr)
-+{
-+ int bits = 32;
-+
-+ /* Establish sync by sending at least 32 logic ones. */
-+ while (--bits >= 0) {
-+ mdio_out(MDIO_WRITE1, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ mdio_out(MDIO_WRITE1 | MDIO_ShiftClk, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ }
-+}
-+
-+static int mdio_read(struct net_device *dev, int phy_id, unsigned int location)
-+{
-+ long mdio_addr = dev->base_addr + MIICtrl;
-+ int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;
-+ int i, retval = 0;
-+
-+ if (mii_preamble_required)
-+ mdio_sync(mdio_addr);
-+
-+ /* Shift the read command bits out. */
-+ for (i = 15; i >= 0; i--) {
-+ int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
-+
-+ mdio_out(dataval, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ mdio_out(dataval | MDIO_ShiftClk, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ }
-+ /* Read the two transition, 16 data, and wire-idle bits. */
-+ for (i = 19; i > 0; i--) {
-+ mdio_out(MDIO_EnbIn, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ retval = (retval << 1) | ((mdio_in(mdio_addr) & MDIO_Data) ? 1 : 0);
-+ mdio_out(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ }
-+ return (retval>>1) & 0xffff;
-+}
-+
-+static void mdio_write(struct net_device *dev, int phy_id,
-+ unsigned int location, int value)
-+{
-+ long mdio_addr = dev->base_addr + MIICtrl;
-+ int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;
-+ int i;
-+
-+ if (mii_preamble_required)
-+ mdio_sync(mdio_addr);
-+
-+ /* Shift the command bits out. */
-+ for (i = 31; i >= 0; i--) {
-+ int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
-+
-+ mdio_out(dataval, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ mdio_out(dataval | MDIO_ShiftClk, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ }
-+ /* Clear out extra bits. */
-+ for (i = 2; i > 0; i--) {
-+ mdio_out(MDIO_EnbIn, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ mdio_out(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ }
-+ return;
-+}
-+
-+
-+static int netdev_open(struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+
-+ MOD_INC_USE_COUNT;
-+
-+ if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev)) {
-+ MOD_DEC_USE_COUNT;
-+ return -EAGAIN;
-+ }
-+
-+ if (np->msg_level & NETIF_MSG_IFUP)
-+ printk(KERN_DEBUG "%s: netdev_open() irq %d.\n",
-+ dev->name, dev->irq);
-+
-+ init_ring(dev);
-+
-+ if (dev->if_port == 0)
-+ dev->if_port = np->default_port;
-+
-+ np->full_duplex = np->duplex_lock;
-+ np->mcastlock = (spinlock_t) SPIN_LOCK_UNLOCKED;
-+
-+ sundance_start(dev);
-+ netif_start_tx_queue(dev);
-+
-+ if (np->msg_level & NETIF_MSG_IFUP)
-+ printk(KERN_DEBUG "%s: Done netdev_open(), status: Rx %x Tx %x "
-+ "MAC Control %x, %4.4x %4.4x.\n",
-+ dev->name, (int)readl(ioaddr + RxStatus),
-+ (int)readw(ioaddr + TxStatus), (int)readl(ioaddr + MACCtrl0),
-+ (int)readw(ioaddr + MACCtrl1), (int)readw(ioaddr + MACCtrl0));
-+
-+ /* Set the timer to check for link beat. */
-+ init_timer(&np->timer);
-+ np->timer.expires = jiffies + 3*HZ;
-+ np->timer.data = (unsigned long)dev;
-+ np->timer.function = &netdev_timer; /* timer handler */
-+ add_timer(&np->timer);
-+
-+ return 0;
-+}
-+
-+static void sundance_start(struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+ int i;
-+
-+ /* No reports have indicated that we need to reset the chip. */
-+
-+ writel(virt_to_bus(&np->rx_ring[np->cur_rx % RX_RING_SIZE]),
-+ ioaddr + RxListPtr);
-+ /* The Tx list pointer is written as packets are queued. */
-+
-+ /* Station address must be written as 16 bit words with the Kendin chip. */
-+ for (i = 0; i < 6; i += 2)
-+ writew((dev->dev_addr[i + 1] << 8) + dev->dev_addr[i],
-+ ioaddr + StationAddr + i);
-+
-+ np->link_status = readb(ioaddr + MIICtrl) & 0xE0;
-+ writew((np->full_duplex || (np->link_status & 0x20)) ? 0x120 : 0,
-+ ioaddr + MACCtrl0);
-+ writew(dev->mtu + 14, ioaddr + MaxFrameSize);
-+ if (dev->mtu > 2047)
-+ writel(readl(ioaddr + ASICCtrl) | 0x0C, ioaddr + ASICCtrl);
-+
-+ set_rx_mode(dev);
-+ writew(0, ioaddr + DownCounter);
-+ /* Set the chip to poll every N*320nsec. */
-+ writeb(100, ioaddr + RxDescPoll);
-+ writeb(127, ioaddr + TxDescPoll);
-+#if 0
-+ if (np->drv_flags & KendinPktDropBug)
-+ writeb(0x01, ioaddr + DebugCtrl1);
-+#endif
-+
-+ /* Enable interrupts by setting the interrupt mask. */
-+ writew(IntrRxDMADone | IntrPCIErr | IntrDrvRqst | IntrTxDone
-+ | StatsMax | LinkChange, ioaddr + IntrEnable);
-+ writew(StatsEnable | RxEnable | TxEnable, ioaddr + MACCtrl1);
-+}
-+
-+static void check_duplex(struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+ int mii_reg5 = mdio_read(dev, np->phys[0], 5);
-+ int negotiated = mii_reg5 & np->advertising;
-+ int duplex;
-+
-+ if (np->duplex_lock || mii_reg5 == 0xffff)
-+ return;
-+ duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;
-+ if (np->full_duplex != duplex) {
-+ np->full_duplex = duplex;
-+ if (np->msg_level & NETIF_MSG_LINK)
-+ printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d "
-+ "negotiated capability %4.4x.\n", dev->name,
-+ duplex ? "full" : "half", np->phys[0], negotiated);
-+ writew(duplex ? 0x20 : 0, ioaddr + MACCtrl0);
-+ }
-+}
-+
-+static void netdev_timer(unsigned long data)
-+{
-+ struct net_device *dev = (struct net_device *)data;
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+ int next_tick = 10*HZ;
-+
-+ if (np->msg_level & NETIF_MSG_TIMER) {
-+ printk(KERN_DEBUG "%s: Media selection timer tick, intr status %4.4x, "
-+ "Tx %x Rx %x.\n",
-+ dev->name, (int)readw(ioaddr + IntrEnable),
-+ (int)readw(ioaddr + TxStatus), (int)readl(ioaddr + RxStatus));
-+ }
-+ /* Note: This does not catch a 0 or 1 element stuck queue. */
-+ if (netif_queue_paused(dev) &&
-+ np->cur_tx - np->dirty_tx > 1 &&
-+ (jiffies - dev->trans_start) > TX_TIMEOUT) {
-+ tx_timeout(dev);
-+ }
-+ check_duplex(dev);
-+ np->timer.expires = jiffies + next_tick;
-+ add_timer(&np->timer);
-+}
-+
-+static void tx_timeout(struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+
-+ printk(KERN_WARNING "%s: Transmit timed out, status %4.4x,"
-+ " resetting...\n", dev->name, (int)readw(ioaddr + TxStatus));
-+
-+#ifdef __i386__
-+ if (np->msg_level & NETIF_MSG_TX_ERR) {
-+ int i;
-+ printk(KERN_DEBUG " Rx ring %8.8x: ", (int)np->rx_ring);
-+ for (i = 0; i < RX_RING_SIZE; i++)
-+ printk(" %8.8x", (unsigned int)np->rx_ring[i].status);
-+ printk("\n"KERN_DEBUG" Tx ring %8.8x: ", (int)np->tx_ring);
-+ for (i = 0; i < TX_RING_SIZE; i++)
-+ printk(" %8.8x", np->tx_ring[i].status);
-+ printk("\n");
-+ }
-+#endif
-+
-+ /* Perhaps we should reinitialize the hardware here. */
-+ dev->if_port = 0;
-+ /* Stop and restart the chip's Tx processes . */
-+
-+ /* Trigger an immediate transmit demand. */
-+ writew(IntrRxDMADone | IntrPCIErr | IntrDrvRqst | IntrTxDone
-+ | StatsMax | LinkChange, ioaddr + IntrEnable);
-+
-+ dev->trans_start = jiffies;
-+ np->stats.tx_errors++;
-+ return;
-+}
-+
-+
-+/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
-+static void init_ring(struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ int i;
-+
-+ np->tx_full = 0;
-+ np->cur_rx = np->cur_tx = 0;
-+ np->dirty_rx = np->dirty_tx = 0;
-+
-+ np->rx_buf_sz = dev->mtu + 20;
-+ if (np->rx_buf_sz < PKT_BUF_SZ)
-+ np->rx_buf_sz = PKT_BUF_SZ;
-+ np->rx_head_desc = &np->rx_ring[0];
-+
-+ /* Initialize all Rx descriptors. */
-+ for (i = 0; i < RX_RING_SIZE; i++) {
-+ np->rx_ring[i].next_desc = virt_to_le32desc(&np->rx_ring[i+1]);
-+ np->rx_ring[i].status = 0;
-+ np->rx_ring[i].frag[0].length = 0;
-+ np->rx_skbuff[i] = 0;
-+ }
-+ /* Wrap the ring. */
-+ np->rx_ring[i-1].next_desc = virt_to_le32desc(&np->rx_ring[0]);
-+
-+ /* Fill in the Rx buffers. Handle allocation failure gracefully. */
-+ for (i = 0; i < RX_RING_SIZE; i++) {
-+ struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz);
-+ np->rx_skbuff[i] = skb;
-+ if (skb == NULL)
-+ break;
-+ skb->dev = dev; /* Mark as being used by this device. */
-+ skb_reserve(skb, 2); /* 16 byte align the IP header. */
-+ np->rx_ring[i].frag[0].addr = virt_to_le32desc(skb->tail);
-+ np->rx_ring[i].frag[0].length = cpu_to_le32(np->rx_buf_sz | LastFrag);
-+ }
-+ np->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
-+
-+ for (i = 0; i < TX_RING_SIZE; i++) {
-+ np->tx_skbuff[i] = 0;
-+ np->tx_ring[i].status = 0;
-+ }
-+ return;
-+}
-+
-+static int start_tx(struct sk_buff *skb, struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ struct netdev_desc *txdesc;
-+ unsigned entry;
-+
-+ /* Block a timer-based transmit from overlapping. */
-+ if (netif_pause_tx_queue(dev) != 0) {
-+ /* This watchdog code is redundant with the media monitor timer. */
-+ if (jiffies - dev->trans_start > TX_TIMEOUT)
-+ tx_timeout(dev);
-+ return 1;
-+ }
-+
-+ /* Note: Ordering is important here, set the field with the
-+ "ownership" bit last, and only then increment cur_tx. */
-+
-+ /* Calculate the next Tx descriptor entry. */
-+ entry = np->cur_tx % TX_RING_SIZE;
-+ np->tx_skbuff[entry] = skb;
-+ txdesc = &np->tx_ring[entry];
-+
-+ txdesc->next_desc = 0;
-+ /* Note: disable the interrupt generation here before releasing. */
-+ txdesc->status =
-+ cpu_to_le32((entry<<2) | DescIntrOnDMADone | DescIntrOnTx | 1);
-+ txdesc->frag[0].addr = virt_to_le32desc(skb->data);
-+ txdesc->frag[0].length = cpu_to_le32(skb->len | LastFrag);
-+ if (np->last_tx)
-+ np->last_tx->next_desc = virt_to_le32desc(txdesc);
-+ np->last_tx = txdesc;
-+ np->cur_tx++;
-+
-+ /* On some architectures: explicitly flush cache lines here. */
-+
-+ if (np->cur_tx - np->dirty_tx >= TX_QUEUE_LEN - 1) {
-+ np->tx_full = 1;
-+ /* Check for a just-cleared queue. */
-+ if (np->cur_tx - (volatile unsigned int)np->dirty_tx
-+ < TX_QUEUE_LEN - 2) {
-+ np->tx_full = 0;
-+ netif_unpause_tx_queue(dev);
-+ } else
-+ netif_stop_tx_queue(dev);
-+ } else
-+ netif_unpause_tx_queue(dev); /* Typical path */
-+
-+ /* Side effect: The read wakes the potentially-idle transmit channel. */
-+ if (readl(dev->base_addr + TxListPtr) == 0)
-+ writel(virt_to_bus(&np->tx_ring[entry]), dev->base_addr + TxListPtr);
-+
-+ dev->trans_start = jiffies;
-+
-+ if (np->msg_level & NETIF_MSG_TX_QUEUED) {
-+ printk(KERN_DEBUG "%s: Transmit frame #%d len %d queued in slot %d.\n",
-+ dev->name, np->cur_tx, skb->len, entry);
-+ }
-+ return 0;
-+}
-+
-+/* The interrupt handler does all of the Rx thread work and cleans up
-+ after the Tx thread. */
-+static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
-+{
-+ struct net_device *dev = (struct net_device *)dev_instance;
-+ struct netdev_private *np;
-+ long ioaddr;
-+ int boguscnt;
-+
-+ ioaddr = dev->base_addr;
-+ np = (struct netdev_private *)dev->priv;
-+ boguscnt = np->max_interrupt_work;
-+
-+ do {
-+ int intr_status = readw(ioaddr + IntrStatus);
-+ if ((intr_status & ~IntrRxDone) == 0 || intr_status == 0xffff)
-+ break;
-+
-+ writew(intr_status & (IntrRxDMADone | IntrPCIErr |
-+ IntrDrvRqst |IntrTxDone|IntrTxDMADone |
-+ StatsMax | LinkChange),
-+ ioaddr + IntrStatus);
-+
-+ if (np->msg_level & NETIF_MSG_INTR)
-+ printk(KERN_DEBUG "%s: Interrupt, status %4.4x.\n",
-+ dev->name, intr_status);
-+
-+ if (intr_status & IntrRxDMADone)
-+ netdev_rx(dev);
-+
-+ if (intr_status & IntrTxDone) {
-+ int txboguscnt = 32;
-+ int tx_status = readw(ioaddr + TxStatus);
-+ while (tx_status & 0x80) {
-+ if (np->msg_level & NETIF_MSG_TX_DONE)
-+ printk("%s: Transmit status is %4.4x.\n",
-+ dev->name, tx_status);
-+ if (tx_status & 0x1e) {
-+ if (np->msg_level & NETIF_MSG_TX_ERR)
-+ printk("%s: Transmit error status %4.4x.\n",
-+ dev->name, tx_status);
-+ np->stats.tx_errors++;
-+ if (tx_status & 0x10) np->stats.tx_fifo_errors++;
-+#ifdef ETHER_STATS
-+ if (tx_status & 0x08) np->stats.collisions16++;
-+#else
-+ if (tx_status & 0x08) np->stats.collisions++;
-+#endif
-+ if (tx_status & 0x04) np->stats.tx_fifo_errors++;
-+ if (tx_status & 0x02) np->stats.tx_window_errors++;
-+ /* This reset has not been verified!. */
-+ if (tx_status & 0x10) { /* Reset the Tx. */
-+ writel(0x001c0000 | readl(ioaddr + ASICCtrl),
-+ ioaddr + ASICCtrl);
-+#if 0 /* Do we need to reset the Tx pointer here? */
-+ writel(virt_to_bus(&np->tx_ring[np->dirty_tx]),
-+ dev->base_addr + TxListPtr);
-+#endif
-+ }
-+ if (tx_status & 0x1e) /* Restart the Tx. */
-+ writew(TxEnable, ioaddr + MACCtrl1);
-+ }
-+ /* Yup, this is a documentation bug. It cost me *hours*. */
-+ writew(0, ioaddr + TxStatus);
-+ if (--txboguscnt < 0)
-+ break;
-+ tx_status = readw(ioaddr + TxStatus);
-+ }
-+ }
-+ for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) {
-+ int entry = np->dirty_tx % TX_RING_SIZE;
-+ if ( ! (np->tx_ring[entry].status & cpu_to_le32(DescTxDMADone)))
-+ break;
-+ /* Free the original skb. */
-+ dev_free_skb_irq(np->tx_skbuff[entry]);
-+ np->tx_skbuff[entry] = 0;
-+ }
-+ if (np->tx_full && np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 4) {
-+ /* The ring is no longer full, allow new TX entries. */
-+ np->tx_full = 0;
-+ netif_resume_tx_queue(dev);
-+ }
-+
-+ /* Abnormal error summary/uncommon events handlers. */
-+ if (intr_status & (IntrDrvRqst | IntrPCIErr | LinkChange | StatsMax))
-+ netdev_error(dev, intr_status);
-+
-+ if (--boguscnt < 0) {
-+ int intr_clear = readw(ioaddr + IntrClear);
-+ get_stats(dev);
-+ printk(KERN_WARNING "%s: Too much work at interrupt, "
-+ "status=0x%4.4x / 0x%4.4x .. 0x%4.4x.\n",
-+ dev->name, intr_status, intr_clear,
-+ (int)readw(ioaddr + IntrClear));
-+ /* Re-enable us in 3.2msec. */
-+ writew(1000, ioaddr + DownCounter);
-+ writew(IntrDrvRqst, ioaddr + IntrEnable);
-+ break;
-+ }
-+ } while (1);
-+
-+ if (np->msg_level & NETIF_MSG_INTR)
-+ printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
-+ dev->name, (int)readw(ioaddr + IntrStatus));
-+
-+ return;
-+}
-+
-+/* This routine is logically part of the interrupt handler, but separated
-+ for clarity and better register allocation. */
-+static int netdev_rx(struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ int entry = np->cur_rx % RX_RING_SIZE;
-+ int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx;
-+
-+ if (np->msg_level & NETIF_MSG_RX_STATUS) {
-+ printk(KERN_DEBUG " In netdev_rx(), entry %d status %4.4x.\n",
-+ entry, np->rx_ring[entry].status);
-+ }
-+
-+ /* If EOP is set on the next entry, it's a new packet. Send it up. */
-+ while (np->rx_head_desc->status & cpu_to_le32(DescOwn)) {
-+ struct netdev_desc *desc = np->rx_head_desc;
-+ u32 frame_status = le32_to_cpu(desc->status);
-+ int pkt_len = frame_status & 0x1fff; /* Chip omits the CRC. */
-+
-+ if (np->msg_level & NETIF_MSG_RX_STATUS)
-+ printk(KERN_DEBUG " netdev_rx() status was %8.8x.\n",
-+ frame_status);
-+ if (--boguscnt < 0)
-+ break;
-+ if (frame_status & 0x001f4000) {
-+ /* There was a error. */
-+ if (np->msg_level & NETIF_MSG_RX_ERR)
-+ printk(KERN_DEBUG " netdev_rx() Rx error was %8.8x.\n",
-+ frame_status);
-+ np->stats.rx_errors++;
-+ if (frame_status & 0x00100000) np->stats.rx_length_errors++;
-+ if (frame_status & 0x00010000) np->stats.rx_fifo_errors++;
-+ if (frame_status & 0x00060000) np->stats.rx_frame_errors++;
-+ if (frame_status & 0x00080000) np->stats.rx_crc_errors++;
-+ if (frame_status & 0x00100000) {
-+ printk(KERN_WARNING "%s: Oversized Ethernet frame,"
-+ " status %8.8x.\n",
-+ dev->name, frame_status);
-+ }
-+ } else {
-+ struct sk_buff *skb;
-+
-+#ifndef final_version
-+ if (np->msg_level & NETIF_MSG_RX_STATUS)
-+ printk(KERN_DEBUG " netdev_rx() normal Rx pkt length %d"
-+ ", bogus_cnt %d.\n",
-+ pkt_len, boguscnt);
-+#endif
-+ /* Check if the packet is long enough to accept without copying
-+ to a minimally-sized skbuff. */
-+ if (pkt_len < np->rx_copybreak
-+ && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
-+ skb->dev = dev;
-+ skb_reserve(skb, 2); /* 16 byte align the IP header */
-+ eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0);
-+ skb_put(skb, pkt_len);
-+ } else {
-+ skb_put(skb = np->rx_skbuff[entry], pkt_len);
-+ np->rx_skbuff[entry] = NULL;
-+ }
-+ skb->protocol = eth_type_trans(skb, dev);
-+ /* Note: checksum -> skb->ip_summed = CHECKSUM_UNNECESSARY; */
-+ netif_rx(skb);
-+ dev->last_rx = jiffies;
-+ }
-+ entry = (++np->cur_rx) % RX_RING_SIZE;
-+ np->rx_head_desc = &np->rx_ring[entry];
-+ }
-+
-+ /* Refill the Rx ring buffers. */
-+ for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) {
-+ struct sk_buff *skb;
-+ entry = np->dirty_rx % RX_RING_SIZE;
-+ if (np->rx_skbuff[entry] == NULL) {
-+ skb = dev_alloc_skb(np->rx_buf_sz);
-+ np->rx_skbuff[entry] = skb;
-+ if (skb == NULL)
-+ break; /* Better luck next round. */
-+ skb->dev = dev; /* Mark as being used by this device. */
-+ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
-+ np->rx_ring[entry].frag[0].addr = virt_to_le32desc(skb->tail);
-+ }
-+ /* Perhaps we need not reset this field. */
-+ np->rx_ring[entry].frag[0].length =
-+ cpu_to_le32(np->rx_buf_sz | LastFrag);
-+ np->rx_ring[entry].status = 0;
-+ }
-+
-+ /* No need to restart Rx engine, it will poll. */
-+ return 0;
-+}
-+
-+static void netdev_error(struct net_device *dev, int intr_status)
-+{
-+ long ioaddr = dev->base_addr;
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+
-+ if (intr_status & IntrDrvRqst) {
-+ /* Stop the down counter and turn interrupts back on. */
-+ printk(KERN_WARNING "%s: Turning interrupts back on.\n", dev->name);
-+ writew(0, ioaddr + DownCounter);
-+ writew(IntrRxDMADone | IntrPCIErr | IntrDrvRqst |
-+ IntrTxDone | StatsMax | LinkChange, ioaddr + IntrEnable);
-+ }
-+ if (intr_status & LinkChange) {
-+ int new_status = readb(ioaddr + MIICtrl) & 0xE0;
-+ if (np->msg_level & NETIF_MSG_LINK)
-+ printk(KERN_NOTICE "%s: Link changed: Autonegotiation advertising"
-+ " %4.4x partner %4.4x.\n", dev->name,
-+ mdio_read(dev, np->phys[0], 4),
-+ mdio_read(dev, np->phys[0], 5));
-+ if ((np->link_status ^ new_status) & 0x80) {
-+ if (new_status & 0x80)
-+ netif_link_up(dev);
-+ else
-+ netif_link_down(dev);
-+ }
-+ np->link_status = new_status;
-+ check_duplex(dev);
-+ }
-+ if (intr_status & StatsMax) {
-+ get_stats(dev);
-+ }
-+ if (intr_status & IntrPCIErr) {
-+ printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n",
-+ dev->name, intr_status);
-+ /* We must do a global reset of DMA to continue. */
-+ }
-+}
-+
-+static struct net_device_stats *get_stats(struct net_device *dev)
-+{
-+ long ioaddr = dev->base_addr;
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ int i;
-+
-+ if (readw(ioaddr + StationAddr) == 0xffff)
-+ return &np->stats;
-+
-+ /* We do not spinlock statistics.
-+ A window only exists if we have non-atomic adds, the error counts
-+ are typically zero, and statistics are non-critical. */
-+ np->stats.rx_missed_errors += readb(ioaddr + RxMissed);
-+ np->stats.tx_packets += readw(ioaddr + TxFramesOK);
-+ np->stats.rx_packets += readw(ioaddr + RxFramesOK);
-+ np->stats.collisions += readb(ioaddr + StatsLateColl);
-+ np->stats.collisions += readb(ioaddr + StatsMultiColl);
-+ np->stats.collisions += readb(ioaddr + StatsOneColl);
-+ readb(ioaddr + StatsCarrierError);
-+ readb(ioaddr + StatsTxDefer);
-+ for (i = StatsTxXSDefer; i <= StatsMcastRx; i++)
-+ readb(ioaddr + i);
-+#if LINUX_VERSION_CODE > 0x20127
-+ np->stats.tx_bytes += readw(ioaddr + TxOctetsLow);
-+ np->stats.tx_bytes += readw(ioaddr + TxOctetsHigh) << 16;
-+ np->stats.rx_bytes += readw(ioaddr + RxOctetsLow);
-+ np->stats.rx_bytes += readw(ioaddr + RxOctetsHigh) << 16;
-+#else
-+ readw(ioaddr + TxOctetsLow);
-+ readw(ioaddr + TxOctetsHigh);
-+ readw(ioaddr + RxOctetsLow);
-+ readw(ioaddr + RxOctetsHigh);
-+#endif
-+
-+ return &np->stats;
-+}
-+
-+/* The little-endian AUTODIN II ethernet CRC calculations.
-+ A big-endian version is also available.
-+ This is slow but compact code. Do not use this routine for bulk data,
-+ use a table-based routine instead.
-+ This is common code and should be moved to net/core/crc.c.
-+ Chips may use the upper or lower CRC bits, and may reverse and/or invert
-+ them. Select the endian-ness that results in minimal calculations.
-+*/
-+static unsigned const ethernet_polynomial_le = 0xedb88320U;
-+static inline unsigned ether_crc_le(int length, unsigned char *data)
-+{
-+ unsigned int crc = ~0; /* Initial value. */
-+ while(--length >= 0) {
-+ unsigned char current_octet = *data++;
-+ int bit;
-+ for (bit = 8; --bit >= 0; current_octet >>= 1) {
-+ if ((crc ^ current_octet) & 1) {
-+ crc >>= 1;
-+ crc ^= ethernet_polynomial_le;
-+ } else
-+ crc >>= 1;
-+ }
-+ }
-+ return crc;
-+}
-+
-+static void set_rx_mode(struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+ u16 mc_filter[4]; /* Multicast hash filter */
-+ u32 rx_mode;
-+ int i;
-+
-+ if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
-+ /* Unconditionally log net taps. */
-+ printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);
-+ memset(mc_filter, ~0, sizeof(mc_filter));
-+ rx_mode = AcceptBroadcast | AcceptMulticast | AcceptAll | AcceptMyPhys;
-+ } else if ((dev->mc_count > np->multicast_filter_limit)
-+ || (dev->flags & IFF_ALLMULTI)) {
-+ /* Too many to match, or accept all multicasts. */
-+ memset(mc_filter, 0xff, sizeof(mc_filter));
-+ rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
-+ } else if (dev->mc_count) {
-+ struct dev_mc_list *mclist;
-+ memset(mc_filter, 0, sizeof(mc_filter));
-+ for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
-+ i++, mclist = mclist->next) {
-+ set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x3f,
-+ mc_filter);
-+ }
-+ rx_mode = AcceptBroadcast | AcceptMultiHash | AcceptMyPhys;
-+ } else {
-+ writeb(AcceptBroadcast | AcceptMyPhys, ioaddr + RxMode);
-+ return;
-+ }
-+ for (i = 0; i < 4; i++)
-+ writew(mc_filter[i], ioaddr + MulticastFilter0 + i*2);
-+ writeb(rx_mode, ioaddr + RxMode);
-+}
-+
-+static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ u16 *data = (u16 *)&rq->ifr_data;
-+ u32 *data32 = (void *)&rq->ifr_data;
-+
-+ switch(cmd) {
-+ case 0x8947: case 0x89F0:
-+ /* SIOCGMIIPHY: Get the address of the PHY in use. */
-+ data[0] = np->phys[0] & 0x1f;
-+ /* Fall Through */
-+ case 0x8948: case 0x89F1:
-+ /* SIOCGMIIREG: Read the specified MII register. */
-+ data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f);
-+ return 0;
-+ case 0x8949: case 0x89F2:
-+ /* SIOCSMIIREG: Write the specified MII register */
-+ if (!capable(CAP_NET_ADMIN))
-+ return -EPERM;
-+ if (data[0] == np->phys[0]) {
-+ u16 value = data[2];
-+ switch (data[1]) {
-+ case 0:
-+ /* Check for autonegotiation on or reset. */
-+ np->medialock = (value & 0x9000) ? 0 : 1;
-+ if (np->medialock)
-+ np->full_duplex = (value & 0x0100) ? 1 : 0;
-+ break;
-+ case 4: np->advertising = value; break;
-+ }
-+ /* Perhaps check_duplex(dev), depending on chip semantics. */
-+ }
-+ mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]);
-+ return 0;
-+ case SIOCGPARAMS:
-+ data32[0] = np->msg_level;
-+ data32[1] = np->multicast_filter_limit;
-+ data32[2] = np->max_interrupt_work;
-+ data32[3] = np->rx_copybreak;
-+ return 0;
-+ case SIOCSPARAMS:
-+ if (!capable(CAP_NET_ADMIN))
-+ return -EPERM;
-+ np->msg_level = data32[0];
-+ np->multicast_filter_limit = data32[1];
-+ np->max_interrupt_work = data32[2];
-+ np->rx_copybreak = data32[3];
-+ return 0;
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+}
-+
-+static int sundance_pwr_event(void *dev_instance, int event)
-+{
-+ struct net_device *dev = dev_instance;
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+
-+ if (np->msg_level & NETIF_MSG_LINK)
-+ printk(KERN_DEBUG "%s: Handling power event %d.\n", dev->name, event);
-+ switch(event) {
-+ case DRV_ATTACH:
-+ MOD_INC_USE_COUNT;
-+ break;
-+ case DRV_SUSPEND:
-+ /* Disable interrupts, stop Tx and Rx. */
-+ writew(0x0000, ioaddr + IntrEnable);
-+ writew(TxDisable | RxDisable | StatsDisable, ioaddr + MACCtrl1);
-+ break;
-+ case DRV_RESUME:
-+ sundance_start(dev);
-+ break;
-+ case DRV_DETACH: {
-+ struct net_device **devp, **next;
-+ if (dev->flags & IFF_UP) {
-+ /* Some, but not all, kernel versions close automatically. */
-+ dev_close(dev);
-+ dev->flags &= ~(IFF_UP|IFF_RUNNING);
-+ }
-+ unregister_netdev(dev);
-+ release_region(dev->base_addr, pci_id_tbl[np->chip_id].io_size);
-+#ifndef USE_IO_OPS
-+ iounmap((char *)dev->base_addr);
-+#endif
-+ for (devp = &root_net_dev; *devp; devp = next) {
-+ next = &((struct netdev_private *)(*devp)->priv)->next_module;
-+ if (*devp == dev) {
-+ *devp = *next;
-+ break;
-+ }
-+ }
-+ if (np->priv_addr)
-+ kfree(np->priv_addr);
-+ kfree(dev);
-+ MOD_DEC_USE_COUNT;
-+ break;
-+ }
-+ case DRV_PWR_WakeOn:
-+ writeb(readb(ioaddr + WakeEvent) | 2, ioaddr + WakeEvent);
-+ /* Fall through. */
-+ case DRV_PWR_DOWN:
-+ case DRV_PWR_UP:
-+ acpi_set_pwr_state(np->pci_dev, event==DRV_PWR_UP ? ACPI_D0:ACPI_D3);
-+ break;
-+ default:
-+ return -1;
-+ }
-+
-+ return 0;
-+}
-+
-+static int netdev_close(struct net_device *dev)
-+{
-+ long ioaddr = dev->base_addr;
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ int i;
-+
-+ netif_stop_tx_queue(dev);
-+
-+ if (np->msg_level & NETIF_MSG_IFDOWN) {
-+ printk(KERN_DEBUG "%s: Shutting down ethercard, status was Tx %2.2x "
-+ "Rx %4.4x Int %2.2x.\n",
-+ dev->name, (int)readw(ioaddr + TxStatus),
-+ (int)readl(ioaddr + RxStatus), (int)readw(ioaddr + IntrStatus));
-+ printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d, Rx %d / %d.\n",
-+ dev->name, np->cur_tx, np->dirty_tx, np->cur_rx, np->dirty_rx);
-+ }
-+
-+ /* Disable interrupts by clearing the interrupt mask. */
-+ writew(0x0000, ioaddr + IntrEnable);
-+
-+ /* Stop the chip's Tx and Rx processes. */
-+ writew(TxDisable | RxDisable | StatsDisable, ioaddr + MACCtrl1);
-+
-+ del_timer(&np->timer);
-+
-+#ifdef __i386__
-+ if (np->msg_level & NETIF_MSG_IFDOWN) {
-+ printk("\n"KERN_DEBUG" Tx ring at %8.8x:\n",
-+ (int)virt_to_bus(np->tx_ring));
-+ for (i = 0; i < TX_RING_SIZE; i++)
-+ printk(" #%d desc. %4.4x %8.8x %8.8x.\n",
-+ i, np->tx_ring[i].status, np->tx_ring[i].frag[0].addr,
-+ np->tx_ring[i].frag[0].length);
-+ printk("\n"KERN_DEBUG " Rx ring %8.8x:\n",
-+ (int)virt_to_bus(np->rx_ring));
-+ for (i = 0; i < /*RX_RING_SIZE*/4 ; i++) {
-+ printk(KERN_DEBUG " #%d desc. %4.4x %4.4x %8.8x\n",
-+ i, np->rx_ring[i].status, np->rx_ring[i].frag[0].addr,
-+ np->rx_ring[i].frag[0].length);
-+ }
-+ }
-+#endif /* __i386__ debugging only */
-+
-+ free_irq(dev->irq, dev);
-+
-+ /* Free all the skbuffs in the Rx queue. */
-+ for (i = 0; i < RX_RING_SIZE; i++) {
-+ np->rx_ring[i].status = 0;
-+ np->rx_ring[i].frag[0].addr = 0xBADF00D0; /* An invalid address. */
-+ if (np->rx_skbuff[i]) {
-+#if LINUX_VERSION_CODE < 0x20100
-+ np->rx_skbuff[i]->free = 1;
-+#endif
-+ dev_free_skb(np->rx_skbuff[i]);
-+ }
-+ np->rx_skbuff[i] = 0;
-+ }
-+ for (i = 0; i < TX_RING_SIZE; i++) {
-+ if (np->tx_skbuff[i])
-+ dev_free_skb(np->tx_skbuff[i]);
-+ np->tx_skbuff[i] = 0;
-+ }
-+
-+ MOD_DEC_USE_COUNT;
-+
-+ return 0;
-+}
-+
-+
-+#ifdef MODULE
-+int init_module(void)
-+{
-+ if (debug >= NETIF_MSG_DRV) /* Emit version even if no cards detected. */
-+ printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2);
-+ return pci_drv_register(&sundance_drv_id, NULL);
-+}
-+
-+void cleanup_module(void)
-+{
-+ struct net_device *next_dev;
-+
-+ pci_drv_unregister(&sundance_drv_id);
-+
-+ /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
-+ while (root_net_dev) {
-+ struct netdev_private *np = (void *)(root_net_dev->priv);
-+ unregister_netdev(root_net_dev);
-+#ifdef USE_IO_OPS
-+ release_region(root_net_dev->base_addr,
-+ pci_id_tbl[np->chip_id].io_size);
-+#else
-+ iounmap((char *)root_net_dev->base_addr);
-+#endif
-+ next_dev = np->next_module;
-+ if (np->priv_addr)
-+ kfree(np->priv_addr);
-+ kfree(root_net_dev);
-+ root_net_dev = next_dev;
-+ }
-+}
-+
-+#endif /* MODULE */
-+
-+/*
-+ * Local variables:
-+ * compile-command: "make KERNVER=`uname -r` sundance.o"
-+ * compile-cmd1: "gcc -DMODULE -Wall -Wstrict-prototypes -O6 -c sundance.c"
-+ * simple-compile-command: "gcc -DMODULE -O6 -c sundance.c"
-+ * c-indent-level: 4
-+ * c-basic-offset: 4
-+ * tab-width: 4
-+ * End:
-+ */
-Index: linux/src/drivers/net/tulip.c
-===================================================================
-RCS file: /cvsroot/hurd/gnumach/linux/src/drivers/net/Attic/tulip.c,v
-retrieving revision 1.2
-diff -u -r1.2 tulip.c
---- linux/src/drivers/net/tulip.c 26 Nov 2000 03:21:57 -0000 1.2
-+++ linux/src/drivers/net/tulip.c 20 Aug 2004 10:32:54 -0000
-@@ -1,30 +1,39 @@
--/* tulip.c: A DEC 21040-family ethernet driver for Linux. */
-+/* tulip.c: A DEC 21040 family ethernet driver for Linux. */
- /*
-- Written/copyright 1994-1999 by Donald Becker.
-+ Written/copyright 1994-2003 by Donald Becker.
-
-- This software may be used and distributed according to the terms
-- of the GNU Public License, incorporated herein by reference.
-+ This software may be used and distributed according to the terms of
-+ the GNU General Public License (GPL), incorporated herein by reference.
-+ Drivers based on or derived from this code fall under the GPL and must
-+ retain the authorship, copyright and license notice. This file is not
-+ a complete program and may only be used when the entire operating
-+ system is licensed under the GPL.
-
- This driver is for the Digital "Tulip" Ethernet adapter interface.
- It should work with most DEC 21*4*-based chips/ethercards, as well as
- with work-alike chips from Lite-On (PNIC) and Macronix (MXIC) and ASIX.
-
-- The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
-- Center of Excellence in Space Data and Information Sciences
-- Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
-+ The author may be reached as becker@scyld.com, or C/O
-+ Scyld Computing Corporation
-+ 914 Bay Ridge Road, Suite 220
-+ Annapolis MD 21403
-
- Support and updates available at
-- http://cesdis.gsfc.nasa.gov/linux/drivers/tulip.html
--
-- This driver also contains updates by Wolfgang Walter and others.
-- For this specific driver variant please use linux-kernel for
-- bug reports.
-+ http://www.scyld.com/network/tulip.html
- */
-
-+/* These identify the driver base version and may not be removed. */
-+static const char version1[] =
-+"tulip.c:v0.97 7/22/2003 Written by Donald Becker <becker@scyld.com>\n";
-+static const char version2[] =
-+" http://www.scyld.com/network/tulip.html\n";
-+
- #define SMP_CHECK
--static const char version[] = "tulip.c:v0.91g-ppc 7/16/99 becker@cesdis.gsfc.nasa.gov\n";
-
--/* A few user-configurable values. */
-+/* The user-configurable values.
-+ These may be modified when a driver module is loaded.*/
-+
-+static int debug = 2; /* Message enable: 0..31 = no..all messages. */
-
- /* Maximum events (Rx packets, etc.) to handle at each interrupt. */
- static int max_interrupt_work = 25;
-@@ -36,11 +45,14 @@
- static int mtu[MAX_UNITS] = {0, }; /* Jumbo MTU for interfaces. */
-
- /* The possible media types that can be set in options[] are: */
--static const char * const medianame[] = {
-+#define MEDIA_MASK 31
-+static const char * const medianame[32] = {
- "10baseT", "10base2", "AUI", "100baseTx",
-- "10baseT-FD", "100baseTx-FD", "100baseT4", "100baseFx",
-- "100baseFx-FD", "MII 10baseT", "MII 10baseT-FD", "MII",
-- "10baseT(forced)", "MII 100baseTx", "MII 100baseTx-FD", "MII 100baseT4",
-+ "10baseT-FDX", "100baseTx-FDX", "100baseT4", "100baseFx",
-+ "100baseFx-FDX", "MII 10baseT", "MII 10baseT-FDX", "MII",
-+ "10baseT(forced)", "MII 100baseTx", "MII 100baseTx-FDX", "MII 100baseT4",
-+ "MII 100baseFx-HDX", "MII 100baseFx-FDX", "Home-PNA 1Mbps", "Invalid-19",
-+ "","","","", "","","","", "","","","Transceiver reset",
- };
-
- /* Set if the PCI BIOS detects the chips on a multiport board backwards. */
-@@ -50,15 +62,8 @@
- static int reverse_probe = 0;
- #endif
-
--/* Keep the ring sizes a power of two for efficiency.
-- Making the Tx ring too large decreases the effectiveness of channel
-- bonding and packet priority.
-- There are no ill effects from too-large receive rings. */
--#define TX_RING_SIZE 16
--#define RX_RING_SIZE 32
--
- /* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */
--#ifdef __alpha__
-+#ifdef __alpha__ /* Always copy to aligned IP headers. */
- static int rx_copybreak = 1518;
- #else
- static int rx_copybreak = 100;
-@@ -77,50 +82,85 @@
- ToDo: Non-Intel setting could be better.
- */
-
--#if defined(__alpha__)
-+#if defined(__alpha__) || defined(__x86_64) || defined(__ia64)
- static int csr0 = 0x01A00000 | 0xE000;
- #elif defined(__i386__) || defined(__powerpc__) || defined(__sparc__)
-+/* Do *not* rely on hardware endian correction for big-endian machines! */
- static int csr0 = 0x01A00000 | 0x8000;
- #else
- #warning Processor architecture undefined!
- static int csr0 = 0x00A00000 | 0x4800;
- #endif
-
-+/* Maximum number of multicast addresses to filter (vs. rx-all-multicast).
-+ Typical is a 64 element hash table based on the Ethernet CRC.
-+ This value does not apply to the 512 bit table chips.
-+*/
-+static int multicast_filter_limit = 32;
-+
-+/* Operational parameters that are set at compile time. */
-+
-+/* Keep the descriptor ring sizes a power of two for efficiency.
-+ The Tx queue length limits transmit packets to a portion of the available
-+ ring entries. It should be at least one element less to allow multicast
-+ filter setup frames to be queued. It must be at least four for hysteresis.
-+ Making the Tx queue too long decreases the effectiveness of channel
-+ bonding and packet priority.
-+ Large receive rings waste memory and confound network buffer limits.
-+ These values have been carefully studied: changing these might mask a
-+ problem, it won't fix it.
-+*/
-+#define TX_RING_SIZE 16
-+#define TX_QUEUE_LEN 10
-+#define RX_RING_SIZE 32
-+
- /* Operational parameters that usually are not changed. */
- /* Time in jiffies before concluding the transmitter is hung. */
--#define TX_TIMEOUT (4*HZ)
--#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/
-+#define TX_TIMEOUT (6*HZ)
-+/* Preferred skbuff allocation size. */
-+#define PKT_BUF_SZ 1536
- /* This is a mysterious value that can be written to CSR11 in the 21040 (only)
- to support a pre-NWay full-duplex signaling mechanism using short frames.
- No one knows what it should be, but if left at its default value some
- 10base2(!) packets trigger a full-duplex-request interrupt. */
- #define FULL_DUPLEX_MAGIC 0x6969
-
--#if !defined(__OPTIMIZE__) || !defined(__KERNEL__)
-+/* The include file section. We start by doing checks and fix-ups for
-+ missing compile flags. */
-+#ifndef __KERNEL__
-+#define __KERNEL__
-+#endif
-+#if !defined(__OPTIMIZE__)
- #warning You must compile this file with the correct options!
- #warning See the last lines of the source file.
- #error You must compile this driver with "-O".
- #endif
-
- #include <linux/config.h>
-+#if defined(CONFIG_SMP) && ! defined(__SMP__)
-+#define __SMP__
-+#endif
-+#if defined(CONFIG_MODVERSIONS) && defined(MODULE) && ! defined(MODVERSIONS)
-+#define MODVERSIONS
-+#endif
-+
- #include <linux/version.h>
--#ifdef MODULE
--#ifdef MODVERSIONS
-+#if defined(MODVERSIONS)
- #include <linux/modversions.h>
- #endif
- #include <linux/module.h>
--#else
--#define MOD_INC_USE_COUNT
--#define MOD_DEC_USE_COUNT
--#endif
-+
-
- #include <linux/kernel.h>
--#include <linux/sched.h>
- #include <linux/string.h>
- #include <linux/timer.h>
- #include <linux/errno.h>
- #include <linux/ioport.h>
-+#if LINUX_VERSION_CODE >= 0x20400
-+#include <linux/slab.h>
-+#else
- #include <linux/malloc.h>
-+#endif
- #include <linux/interrupt.h>
- #include <linux/pci.h>
- #include <linux/netdevice.h>
-@@ -131,12 +171,23 @@
- #include <asm/io.h>
- #include <asm/unaligned.h>
-
--/* Kernel compatibility defines, some common to David Hind's PCMCIA package.
-- This is only in the support-all-kernels source code. */
-+#ifdef INLINE_PCISCAN
-+#include "k_compat.h"
-+#else
-+#include "pci-scan.h"
-+#include "kern_compat.h"
-+#endif
-+
-+/* Condensed operations for readability. */
-+#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr))
-+
-+#if (LINUX_VERSION_CODE >= 0x20100) && defined(MODULE)
-+char kernel_version[] = UTS_RELEASE;
-+#endif
-
--#if defined(MODULE) && LINUX_VERSION_CODE > 0x20115
--MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
-+MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
- MODULE_DESCRIPTION("Digital 21*4* Tulip ethernet driver");
-+MODULE_LICENSE("GPL");
- MODULE_PARM(debug, "i");
- MODULE_PARM(max_interrupt_work, "i");
- MODULE_PARM(reverse_probe, "i");
-@@ -144,54 +195,42 @@
- MODULE_PARM(csr0, "i");
- MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
- MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
--#endif
--
--#define RUN_AT(x) (jiffies + (x))
--
--#if (LINUX_VERSION_CODE >= 0x20100)
--static char kernel_version[] = UTS_RELEASE;
--#endif
--
--#if LINUX_VERSION_CODE < 0x20123
--#define hard_smp_processor_id() smp_processor_id()
--#define test_and_set_bit(val, addr) set_bit(val, addr)
--#define le16_to_cpu(val) (val)
--#define le32_to_cpu(val) (val)
--#define cpu_to_le32(val) (val)
--#endif
--#if LINUX_VERSION_CODE <= 0x20139
--#define net_device_stats enet_statistics
--#else
--#define NETSTATS_VER2
--#endif
--#if LINUX_VERSION_CODE < 0x20155
--/* Grrrr, the PCI code changed, but did not consider CardBus... */
--#include <linux/bios32.h>
--#define PCI_SUPPORT_VER1
--#else
--#define PCI_SUPPORT_VER2
--#endif
--#if LINUX_VERSION_CODE < 0x20159
--#define dev_free_skb(skb) dev_kfree_skb(skb, FREE_WRITE);
--#else
--#define dev_free_skb(skb) dev_kfree_skb(skb);
--#endif
--#if ! defined(CAP_NET_ADMIN)
--#define capable(CAP_XXX) (suser())
--#endif
--#if ! defined(HAS_NETIF_QUEUE)
--#define netif_wake_queue(dev) mark_bh(NET_BH);
--#endif
--
--/* Condensed operations for readability. */
--#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr))
--#define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr))
--
--#define tulip_debug debug
--#ifdef TULIP_DEBUG
--static int tulip_debug = TULIP_DEBUG;
--#else
--static int tulip_debug = 1;
-+MODULE_PARM(multicast_filter_limit, "i");
-+#ifdef MODULE_PARM_DESC
-+MODULE_PARM_DESC(debug, "Tulip driver message level (0-31)");
-+MODULE_PARM_DESC(options,
-+ "Tulip: force transceiver type or fixed speed+duplex");
-+MODULE_PARM_DESC(max_interrupt_work,
-+ "Tulip driver maximum events handled per interrupt");
-+MODULE_PARM_DESC(full_duplex, "Tulip: non-zero to set forced full duplex.");
-+MODULE_PARM_DESC(rx_copybreak,
-+ "Tulip breakpoint in bytes for copy-only-tiny-frames");
-+MODULE_PARM_DESC(multicast_filter_limit,
-+ "Tulip breakpoint for switching to Rx-all-multicast");
-+MODULE_PARM_DESC(reverse_probe, "Search PCI devices in reverse order to work "
-+ "around misordered multiport NICS.");
-+MODULE_PARM_DESC(csr0, "Special setting for the CSR0 PCI bus parameter "
-+ "register.");
-+#endif
-+
-+/* This driver was originally written to use I/O space access, but now
-+ uses memory space by default. Override this this with -DUSE_IO_OPS. */
-+#if (LINUX_VERSION_CODE < 0x20100) || ! defined(MODULE)
-+#define USE_IO_OPS
-+#endif
-+#ifndef USE_IO_OPS
-+#undef inb
-+#undef inw
-+#undef inl
-+#undef outb
-+#undef outw
-+#undef outl
-+#define inb readb
-+#define inw readw
-+#define inl readl
-+#define outb writeb
-+#define outw writew
-+#define outl writel
- #endif
-
- /*
-@@ -203,7 +242,7 @@
- single-chip ethernet controllers for PCI. Supported members of the family
- are the 21040, 21041, 21140, 21140A, 21142, and 21143. Similar work-alike
- chips from Lite-On, Macronics, ASIX, Compex and other listed below are also
--supported.
-+supported.
-
- These chips are used on at least 140 unique PCI board designs. The great
- number of chips and board designs supported is the reason for the
-@@ -221,7 +260,7 @@
- is usually "autoselect". This should only be overridden when using
- transceiver connections without link beat e.g. 10base2 or AUI, or (rarely!)
- for forcing full-duplex when used with old link partners that do not do
--autonegotiation.
-+autonegotiation.
-
- III. Driver operation
-
-@@ -244,7 +283,7 @@
- information). For large frames the copying cost is non-trivial, and the
- larger copy might flush the cache of useful data. A subtle aspect of this
- choice is that the Tulip only receives into longword aligned buffers, thus
--the IP header at offset 14 isn't longword aligned for further processing.
-+the IP header at offset 14 is not longword aligned for further processing.
- Copied frames are put into the new skbuff at an offset of "+2", thus copying
- has the beneficial effect of aligning the IP header and preloading the
- cache.
-@@ -256,13 +295,13 @@
- threaded by the hardware and other software.
-
- The send packet thread has partial control over the Tx ring and 'dev->tbusy'
--flag. It sets the tbusy flag whenever it's queuing a Tx packet. If the next
-+flag. It sets the tbusy flag whenever it is queuing a Tx packet. If the next
- queue slot is empty, it clears the tbusy flag when finished otherwise it sets
- the 'tp->tx_full' flag.
-
- The interrupt handler has exclusive control over the Rx ring and records stats
--from the Tx ring. (The Tx-done interrupt can't be selectively turned off, so
--we can't avoid the interrupt overhead by having the Tx routine reap the Tx
-+from the Tx ring. (The Tx-done interrupt can not be selectively turned off, so
-+we cannot avoid the interrupt overhead by having the Tx routine reap the Tx
- stats.) After reaping the stats, it marks the queue entry as empty by setting
- the 'base' to zero. Iff the 'tp->tx_full' flag is set, it clears both the
- tx_full and tbusy flags.
-@@ -275,7 +314,7 @@
-
- IVb. References
-
--http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html
-+http://scyld.com/expert/NWay.html
- http://www.digital.com (search for current 21*4* datasheets and "21X4 SROM")
- http://www.national.com/pf/DP/DP83840A.html
- http://www.asix.com.tw/pmac.htm
-@@ -290,73 +329,138 @@
- The DEC SROM format is very badly designed not precisely defined, leading to
- part of the media selection junkheap below. Some boards do not have EEPROM
- media tables and need to be patched up. Worse, other boards use the DEC
--design kit media table when it isn't correct for their board.
-+design kit media table when it is not correct for their design.
-
- We cannot use MII interrupts because there is no defined GPIO pin to attach
- them. The MII transceiver status is polled using an kernel timer.
-
- */
-
--static struct device *
--tulip_probe1(int pci_bus, int pci_devfn, struct device *dev, long ioaddr,
-- int irq, int chip_idx, int board_idx);
--
--/* This table drives the PCI probe routines. It's mostly boilerplate in all
-- of the drivers, and will likely be provided by some future kernel.
-- Note the matching code -- the first table entry matchs all 56** cards but
-- second only the 1234 card.
--*/
--enum pci_flags_bit {
-- PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
-- PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
--};
--#define PCI_ADDR0_IO (PCI_USES_IO|PCI_ADDR0)
-+static void *tulip_probe1(struct pci_dev *pdev, void *init_dev,
-+ long ioaddr, int irq, int chip_idx, int find_cnt);
-+static int tulip_pwr_event(void *dev_instance, int event);
-+
-+#ifdef USE_IO_OPS
-+#define TULIP_IOTYPE PCI_USES_MASTER | PCI_USES_IO | PCI_ADDR0
-+#define TULIP_SIZE 0x80
-+#define TULIP_SIZE1 0x100
-+#else
-+#define TULIP_IOTYPE PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR1
-+#define TULIP_SIZE 0x400 /* New PCI v2.1 recommends 4K min mem size. */
-+#define TULIP_SIZE1 0x400 /* New PCI v2.1 recommends 4K min mem size. */
-+#endif
-
--struct pci_id_info {
-- const char *name;
-- u16 vendor_id, device_id, device_id_mask, flags;
-- int io_size, min_latency;
-- struct device *(*probe1)(int pci_bus, int pci_devfn, struct device *dev,
-- long ioaddr, int irq, int chip_idx, int fnd_cnt);
-+/* This much match tulip_tbl[]! Note 21142 == 21143. */
-+enum tulip_chips {
-+ DC21040=0, DC21041=1, DC21140=2, DC21142=3, DC21143=3,
-+ LC82C168, MX98713, MX98715, MX98725, AX88141, AX88140, PNIC2, COMET,
-+ COMPEX9881, I21145, XIRCOM, CONEXANT,
-+ /* These flags may be added to the chip type. */
-+ HAS_VLAN=0x100,
- };
--#ifndef CARDBUS
--static struct pci_id_info pci_tbl[] = {
-- { "Digital DC21040 Tulip",
-- 0x1011, 0x0002, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 },
-- { "Digital DC21041 Tulip",
-- 0x1011, 0x0014, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 },
-- { "Digital DS21140 Tulip",
-- 0x1011, 0x0009, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 },
-- { "Digital DS21143 Tulip",
-- 0x1011, 0x0019, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 },
-- { "Lite-On 82c168 PNIC",
-- 0x11AD, 0x0002, 0xffff, PCI_ADDR0_IO, 256, 32, tulip_probe1 },
-- { "Macronix 98713 PMAC",
-- 0x10d9, 0x0512, 0xffff, PCI_ADDR0_IO, 256, 32, tulip_probe1 },
-- { "Macronix 98715 PMAC",
-- 0x10d9, 0x0531, 0xffff, PCI_ADDR0_IO, 256, 32, tulip_probe1 },
-- { "Macronix 98725 PMAC",
-- 0x10d9, 0x0531, 0xffff, PCI_ADDR0_IO, 256, 32, tulip_probe1 },
-- { "ASIX AX88140",
-- 0x125B, 0x1400, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 },
-- { "Lite-On LC82C115 PNIC-II",
-- 0x11AD, 0xc115, 0xffff, PCI_ADDR0_IO, 256, 32, tulip_probe1 },
-- { "ADMtek AN981 Comet",
-- 0x1317, 0x0981, 0xffff, PCI_ADDR0_IO, 256, 32, tulip_probe1 },
-- { "Compex RL100-TX",
-- 0x11F6, 0x9881, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 },
-- { "Intel 21145 Tulip",
-- 0x8086, 0x0039, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 },
-- { "Xircom Tulip clone",
-- 0x115d, 0x0003, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 },
-- {0},
-+
-+static struct pci_id_info pci_id_tbl[] = {
-+ { "Digital DC21040 Tulip", { 0x00021011, 0xffffffff },
-+ TULIP_IOTYPE, 0x80, DC21040 },
-+ { "Digital DC21041 Tulip", { 0x00141011, 0xffffffff },
-+ TULIP_IOTYPE, 0x80, DC21041 },
-+ { "Digital DS21140A Tulip", { 0x00091011, 0xffffffff, 0,0, 0x20,0xf0 },
-+ TULIP_IOTYPE, 0x80, DC21140 },
-+ { "Digital DS21140 Tulip", { 0x00091011, 0xffffffff },
-+ TULIP_IOTYPE, 0x80, DC21140 },
-+ { "Digital DS21143-xD Tulip", { 0x00191011, 0xffffffff, 0,0, 0x40,0xf0 },
-+ TULIP_IOTYPE, TULIP_SIZE, DC21142 | HAS_VLAN },
-+ { "Digital DS21143-xC Tulip", { 0x00191011, 0xffffffff, 0,0, 0x30,0xf0 },
-+ TULIP_IOTYPE, TULIP_SIZE, DC21142 },
-+ { "Digital DS21142 Tulip", { 0x00191011, 0xffffffff },
-+ TULIP_IOTYPE, TULIP_SIZE, DC21142 },
-+ { "Kingston KNE110tx (PNIC)",
-+ { 0x000211AD, 0xffffffff, 0xf0022646, 0xffffffff },
-+ TULIP_IOTYPE, 256, LC82C168 },
-+ { "Linksys LNE100TX (82c168 PNIC)", /* w/SYM */
-+ { 0x000211AD, 0xffffffff, 0xffff11ad, 0xffffffff, 17,0xff },
-+ TULIP_IOTYPE, 256, LC82C168 },
-+ { "Linksys LNE100TX (82c169 PNIC)", /* w/ MII */
-+ { 0x000211AD, 0xffffffff, 0xf00311ad, 0xffffffff, 32,0xff },
-+ TULIP_IOTYPE, 256, LC82C168 },
-+ { "Lite-On 82c168 PNIC", { 0x000211AD, 0xffffffff },
-+ TULIP_IOTYPE, 256, LC82C168 },
-+ { "Macronix 98713 PMAC", { 0x051210d9, 0xffffffff },
-+ TULIP_IOTYPE, 256, MX98713 },
-+ { "Macronix 98715 PMAC", { 0x053110d9, 0xffffffff },
-+ TULIP_IOTYPE, 256, MX98715 },
-+ { "Macronix 98725 PMAC", { 0x053110d9, 0xffffffff },
-+ TULIP_IOTYPE, 256, MX98725 },
-+ { "ASIX AX88141", { 0x1400125B, 0xffffffff, 0,0, 0x10, 0xf0 },
-+ TULIP_IOTYPE, 128, AX88141 },
-+ { "ASIX AX88140", { 0x1400125B, 0xffffffff },
-+ TULIP_IOTYPE, 128, AX88140 },
-+ { "Lite-On LC82C115 PNIC-II", { 0xc11511AD, 0xffffffff },
-+ TULIP_IOTYPE, 256, PNIC2 },
-+ { "ADMtek AN981 Comet", { 0x09811317, 0xffffffff },
-+ TULIP_IOTYPE, TULIP_SIZE1, COMET },
-+ { "ADMtek Centaur-P", { 0x09851317, 0xffffffff },
-+ TULIP_IOTYPE, TULIP_SIZE1, COMET },
-+ { "ADMtek Centaur-C", { 0x19851317, 0xffffffff },
-+ TULIP_IOTYPE, TULIP_SIZE1, COMET },
-+ { "D-Link DFE-680TXD v1.0 (ADMtek Centaur-C)", { 0x15411186, 0xffffffff },
-+ TULIP_IOTYPE, TULIP_SIZE1, COMET },
-+ { "ADMtek Centaur-C (Linksys v2)", { 0xab0213d1, 0xffffffff },
-+ TULIP_IOTYPE, TULIP_SIZE1, COMET },
-+ { "ADMtek Centaur-C (Linksys)", { 0xab0313d1, 0xffffffff },
-+ TULIP_IOTYPE, TULIP_SIZE1, COMET },
-+ { "ADMtek Centaur-C (Linksys)", { 0xab0813d1, 0xffffffff },
-+ TULIP_IOTYPE, TULIP_SIZE1, COMET },
-+ { "ADMtek Centaur-C (Linksys PCM200 v3)", { 0xab081737, 0xffffffff },
-+ TULIP_IOTYPE, TULIP_SIZE1, COMET },
-+ { "ADMtek Centaur-C (Linksys PCM200 v3)", { 0xab091737, 0xffffffff },
-+ TULIP_IOTYPE, TULIP_SIZE1, COMET },
-+ { "STMicro STE10/100 Comet", { 0x0981104a, 0xffffffff },
-+ TULIP_IOTYPE, TULIP_SIZE1, COMET },
-+ { "STMicro STE10/100A Comet", { 0x2774104a, 0xffffffff },
-+ TULIP_IOTYPE, TULIP_SIZE1, COMET },
-+ { "ADMtek Comet-II", { 0x95111317, 0xffffffff },
-+ TULIP_IOTYPE, TULIP_SIZE1, COMET },
-+ { "ADMtek Comet-II (9513)", { 0x95131317, 0xffffffff },
-+ TULIP_IOTYPE, TULIP_SIZE1, COMET },
-+ { "SMC1255TX (ADMtek Comet)",
-+ { 0x12161113, 0xffffffff, 0x125510b8, 0xffffffff },
-+ TULIP_IOTYPE, TULIP_SIZE1, COMET },
-+ { "Accton EN1217/EN2242 (ADMtek Comet)", { 0x12161113, 0xffffffff },
-+ TULIP_IOTYPE, TULIP_SIZE1, COMET },
-+ { "SMC1255TX (ADMtek Comet-II)", { 0x125510b8, 0xffffffff },
-+ TULIP_IOTYPE, TULIP_SIZE1, COMET },
-+ { "ADMtek Comet-II (model 1020)", { 0x1020111a, 0xffffffff },
-+ TULIP_IOTYPE, TULIP_SIZE1, COMET },
-+ { "Allied Telesyn A120 (ADMtek Comet)", { 0xa1201259, 0xffffffff },
-+ TULIP_IOTYPE, TULIP_SIZE1, COMET },
-+ { "Compex RL100-TX", { 0x988111F6, 0xffffffff },
-+ TULIP_IOTYPE, 128, COMPEX9881 },
-+ { "Intel 21145 Tulip", { 0x00398086, 0xffffffff },
-+ TULIP_IOTYPE, 128, I21145 },
-+ { "Xircom Tulip clone", { 0x0003115d, 0xffffffff },
-+ TULIP_IOTYPE, 128, XIRCOM },
-+ { "Davicom DM9102", { 0x91021282, 0xffffffff },
-+ TULIP_IOTYPE, 0x80, DC21140 },
-+ { "Davicom DM9100", { 0x91001282, 0xffffffff },
-+ TULIP_IOTYPE, 0x80, DC21140 },
-+ { "Macronix mxic-98715 (EN1217)", { 0x12171113, 0xffffffff },
-+ TULIP_IOTYPE, 256, MX98715 },
-+ { "Conexant LANfinity", { 0x180314f1, 0xffffffff },
-+ TULIP_IOTYPE, TULIP_SIZE1, CONEXANT },
-+ { "3Com 3cSOHO100B-TX (ADMtek Centaur)", { 0x930010b7, 0xffffffff },
-+ TULIP_IOTYPE, TULIP_SIZE1, COMET },
-+ { 0},
- };
--#endif /* !CARD_BUS */
-
--/* This table use during operation for capabilities and media timer. */
-+struct drv_id_info tulip_drv_id = {
-+ "tulip", PCI_HOTSWAP, PCI_CLASS_NETWORK_ETHERNET<<8, pci_id_tbl,
-+ tulip_probe1, tulip_pwr_event };
-+
-+/* This table is used during operation for capabilities and media timer. */
-
- static void tulip_timer(unsigned long data);
--static void t21142_timer(unsigned long data);
-+static void nway_timer(unsigned long data);
- static void mxic_timer(unsigned long data);
- static void pnic_timer(unsigned long data);
- static void comet_timer(unsigned long data);
-@@ -364,23 +468,27 @@
- enum tbl_flag {
- HAS_MII=1, HAS_MEDIA_TABLE=2, CSR12_IN_SROM=4, ALWAYS_CHECK_MII=8,
- HAS_PWRDWN=0x10, MC_HASH_ONLY=0x20, /* Hash-only multicast filter. */
-- HAS_PNICNWAY=0x80, HAS_NWAY143=0x40, /* Uses internal NWay xcvr. */
-- HAS_8023X=0x100,
-+ HAS_PNICNWAY=0x80, HAS_NWAY=0x40, /* Uses internal NWay xcvr. */
-+ HAS_INTR_MITIGATION=0x100, IS_ASIX=0x200, HAS_8023X=0x400,
-+ COMET_MAC_ADDR=0x0800,
- };
-+
-+/* Note: this table must match enum tulip_chips above. */
- static struct tulip_chip_table {
- char *chip_name;
-- int io_size;
-+ int io_size; /* Unused */
- int valid_intrs; /* CSR7 interrupt enable settings */
- int flags;
- void (*media_timer)(unsigned long data);
- } tulip_tbl[] = {
- { "Digital DC21040 Tulip", 128, 0x0001ebef, 0, tulip_timer },
-- { "Digital DC21041 Tulip", 128, 0x0001ebff, HAS_MEDIA_TABLE, tulip_timer },
-+ { "Digital DC21041 Tulip", 128, 0x0001ebff,
-+ HAS_MEDIA_TABLE | HAS_NWAY, tulip_timer },
- { "Digital DS21140 Tulip", 128, 0x0001ebef,
- HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, tulip_timer },
- { "Digital DS21143 Tulip", 128, 0x0801fbff,
-- HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_PWRDWN | HAS_NWAY143,
-- t21142_timer },
-+ HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_PWRDWN | HAS_NWAY
-+ | HAS_INTR_MITIGATION, nway_timer },
- { "Lite-On 82c168 PNIC", 256, 0x0001ebef,
- HAS_MII | HAS_PNICNWAY, pnic_timer },
- { "Macronix 98713 PMAC", 128, 0x0001ebef,
-@@ -390,38 +498,37 @@
- { "Macronix 98725 PMAC", 256, 0x0001ebef,
- HAS_MEDIA_TABLE, mxic_timer },
- { "ASIX AX88140", 128, 0x0001fbff,
-- HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | MC_HASH_ONLY, tulip_timer },
-+ HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | MC_HASH_ONLY | IS_ASIX, tulip_timer },
-+ { "ASIX AX88141", 128, 0x0001fbff,
-+ HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | MC_HASH_ONLY | IS_ASIX, tulip_timer },
- { "Lite-On PNIC-II", 256, 0x0801fbff,
-- HAS_MII | HAS_NWAY143 | HAS_8023X, t21142_timer },
-+ HAS_MII | HAS_NWAY | HAS_8023X, nway_timer },
- { "ADMtek Comet", 256, 0x0001abef,
-- MC_HASH_ONLY, comet_timer },
-+ HAS_MII | MC_HASH_ONLY | COMET_MAC_ADDR, comet_timer },
- { "Compex 9881 PMAC", 128, 0x0001ebef,
- HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer },
- { "Intel DS21145 Tulip", 128, 0x0801fbff,
-- HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_PWRDWN | HAS_NWAY143,
-- t21142_timer },
-+ HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_PWRDWN | HAS_NWAY,
-+ nway_timer },
- { "Xircom tulip work-alike", 128, 0x0801fbff,
-- HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_PWRDWN | HAS_NWAY143,
-- t21142_timer },
-+ HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_PWRDWN | HAS_NWAY,
-+ nway_timer },
-+ { "Conexant LANfinity", 256, 0x0001ebef,
-+ HAS_MII | HAS_PWRDWN, tulip_timer },
- {0},
- };
--/* This matches the table above. Note 21142 == 21143. */
--enum chips {
-- DC21040=0, DC21041=1, DC21140=2, DC21142=3, DC21143=3,
-- LC82C168, MX98713, MX98715, MX98725, AX88140, PNIC2, COMET, COMPEX9881,
-- I21145,
--};
-
- /* A full-duplex map for media types. */
- enum MediaIs {
- MediaIsFD = 1, MediaAlwaysFD=2, MediaIsMII=4, MediaIsFx=8,
- MediaIs100=16};
--static const char media_cap[] =
--{0,0,0,16, 3,19,16,24, 27,4,7,5, 0,20,23,20 };
-+static const char media_cap[32] =
-+{0,0,0,16, 3,19,16,24, 27,4,7,5, 0,20,23,20, 28,31,0,0, };
- static u8 t21040_csr13[] = {2,0x0C,8,4, 4,0,0,0, 0,0,0,0, 4,0,0,0};
-+
- /* 21041 transceiver register settings: 10-T, 10-2, AUI, 10-T, 10T-FD*/
--static u16 t21041_csr13[] = { 0xEF05, 0xEF0D, 0xEF0D, 0xEF05, 0xEF05, };
--static u16 t21041_csr14[] = { 0xFFFF, 0xF7FD, 0xF7FD, 0x7F3F, 0x7F3D, };
-+static u16 t21041_csr13[] = { 0xEF01, 0xEF09, 0xEF09, 0xEF01, 0xEF09, };
-+static u16 t21041_csr14[] = { 0xFFFF, 0xF7FD, 0xF7FD, 0x6F3F, 0x6F3D, };
- static u16 t21041_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, };
-
- static u16 t21142_csr13[] = { 0x0001, 0x0009, 0x0009, 0x0000, 0x0001, };
-@@ -437,12 +544,20 @@
-
- /* The bits in the CSR5 status registers, mostly interrupt sources. */
- enum status_bits {
-- TimerInt=0x800, SytemError=0x2000, TPLnkFail=0x1000, TPLnkPass=0x10,
-- NormalIntr=0x10000, AbnormalIntr=0x8000,
-- RxJabber=0x200, RxDied=0x100, RxNoBuf=0x80, RxIntr=0x40,
-+ TimerInt=0x800, TPLnkFail=0x1000, TPLnkPass=0x10,
-+ NormalIntr=0x10000, AbnormalIntr=0x8000, PCIBusError=0x2000,
-+ RxJabber=0x200, RxStopped=0x100, RxNoBuf=0x80, RxIntr=0x40,
- TxFIFOUnderflow=0x20, TxJabber=0x08, TxNoBuf=0x04, TxDied=0x02, TxIntr=0x01,
- };
-
-+/* The configuration bits in CSR6. */
-+enum csr6_mode_bits {
-+ TxOn=0x2000, RxOn=0x0002, FullDuplex=0x0200,
-+ AcceptBroadcast=0x0100, AcceptAllMulticast=0x0080,
-+ AcceptAllPhys=0x0040, AcceptRunt=0x0008,
-+};
-+
-+
- /* The Tulip Rx and Tx buffer descriptors. */
- struct tulip_rx_desc {
- s32 status;
-@@ -470,7 +585,7 @@
- */
- #define DESC_RING_WRAP 0x02000000
-
--#define EEPROM_SIZE 128 /* 2 << EEPROM_ADDRLEN */
-+#define EEPROM_SIZE 512 /* support 256*16 EEPROMs */
-
- struct medialeaf {
- u8 type;
-@@ -493,239 +608,147 @@
- unsigned char *info;
- };
-
-+#define PRIV_ALIGN 15 /* Required alignment mask */
- struct tulip_private {
-- char devname[8]; /* Used only for kernel debugging. */
-- const char *product_name;
-- struct device *next_module;
- struct tulip_rx_desc rx_ring[RX_RING_SIZE];
- struct tulip_tx_desc tx_ring[TX_RING_SIZE];
-- /* The saved address of a sent-in-place packet/buffer, for skfree(). */
-+ /* The saved addresses of Rx/Tx-in-place packet buffers. */
- struct sk_buff* tx_skbuff[TX_RING_SIZE];
-- /* The addresses of receive-in-place skbuffs. */
- struct sk_buff* rx_skbuff[RX_RING_SIZE];
-- char *rx_buffs; /* Address of temporary Rx buffers. */
-+ struct net_device *next_module;
-+ void *priv_addr; /* Unaligned address of dev->priv for kfree */
-+ /* Multicast filter control. */
- u16 setup_frame[96]; /* Pseudo-Tx frame to init address table. */
-- int chip_id;
-- int revision;
-+ u32 mc_filter[2]; /* Multicast hash filter */
-+ int multicast_filter_limit;
-+ struct pci_dev *pci_dev;
-+ int chip_id, revision;
- int flags;
-+ int max_interrupt_work;
-+ int msg_level;
-+ unsigned int csr0, csr6; /* Current CSR0, CSR6 settings. */
-+ /* Note: cache line pairing and isolation of Rx vs. Tx indicies. */
-+ unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */
-+ unsigned int rx_buf_sz; /* Based on MTU+slack. */
-+ int rx_copybreak;
-+ unsigned int rx_dead:1; /* We have no Rx buffers. */
-+
- struct net_device_stats stats;
-- struct timer_list timer; /* Media selection timer. */
-- int interrupt; /* In-interrupt flag. */
-- unsigned int cur_rx, cur_tx; /* The next free ring entry */
-- unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */
-+ unsigned int cur_tx, dirty_tx;
- unsigned int tx_full:1; /* The Tx queue is full. */
-+
-+ /* Media selection state. */
- unsigned int full_duplex:1; /* Full-duplex operation requested. */
- unsigned int full_duplex_lock:1;
- unsigned int fake_addr:1; /* Multiport board faked address. */
-- unsigned int default_port:4; /* Last dev->if_port value. */
- unsigned int media2:4; /* Secondary monitored media port. */
-- unsigned int medialock:1; /* Don't sense media type. */
-+ unsigned int medialock:1; /* Do not sense media type. */
- unsigned int mediasense:1; /* Media sensing in progress. */
- unsigned int nway:1, nwayset:1; /* 21143 internal NWay. */
-- unsigned int csr0; /* CSR0 setting. */
-- unsigned int csr6; /* Current CSR6 control settings. */
-+ unsigned int default_port; /* Last dev->if_port value. */
- unsigned char eeprom[EEPROM_SIZE]; /* Serial EEPROM contents. */
-- void (*link_change)(struct device *dev, int csr5);
-- u16 to_advertise; /* NWay capabilities advertised. */
-+ struct timer_list timer; /* Media selection timer. */
-+ void (*link_change)(struct net_device *dev, int csr5);
- u16 lpar; /* 21143 Link partner ability. */
-- u16 advertising[4];
-+ u16 sym_advertise, mii_advertise; /* NWay to-advertise. */
-+ u16 advertising[4]; /* MII advertise, from SROM table. */
- signed char phys[4], mii_cnt; /* MII device addresses. */
-+ spinlock_t mii_lock;
- struct mediatable *mtable;
- int cur_index; /* Current media index. */
- int saved_if_port;
-- unsigned char pci_bus, pci_devfn;
-- int ttimer;
-- int susp_rx;
-- unsigned long nir;
-- int pad0, pad1; /* Used for 8-byte alignment */
- };
-
--static void parse_eeprom(struct device *dev);
-+static void start_link(struct net_device *dev);
-+static void parse_eeprom(struct net_device *dev);
- static int read_eeprom(long ioaddr, int location, int addr_len);
--static int mdio_read(struct device *dev, int phy_id, int location);
--static void mdio_write(struct device *dev, int phy_id, int location, int value);
--static void select_media(struct device *dev, int startup);
--static int tulip_open(struct device *dev);
-+static int mdio_read(struct net_device *dev, int phy_id, int location);
-+static void mdio_write(struct net_device *dev, int phy_id, int location, int value);
-+static int tulip_open(struct net_device *dev);
- /* Chip-specific media selection (timer functions prototyped above). */
--static void t21142_lnk_change(struct device *dev, int csr5);
--static void t21142_start_nway(struct device *dev);
--static void pnic_lnk_change(struct device *dev, int csr5);
--static void pnic_do_nway(struct device *dev);
--
--static void tulip_tx_timeout(struct device *dev);
--static void tulip_init_ring(struct device *dev);
--static int tulip_start_xmit(struct sk_buff *skb, struct device *dev);
--static int tulip_refill_rx(struct device *dev);
--static int tulip_rx(struct device *dev);
-+static int check_duplex(struct net_device *dev);
-+static void select_media(struct net_device *dev, int startup);
-+static void init_media(struct net_device *dev);
-+static void nway_lnk_change(struct net_device *dev, int csr5);
-+static void nway_start(struct net_device *dev);
-+static void pnic_lnk_change(struct net_device *dev, int csr5);
-+static void pnic_do_nway(struct net_device *dev);
-+
-+static void tulip_tx_timeout(struct net_device *dev);
-+static void tulip_init_ring(struct net_device *dev);
-+static int tulip_start_xmit(struct sk_buff *skb, struct net_device *dev);
-+static int tulip_rx(struct net_device *dev);
- static void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
--static int tulip_close(struct device *dev);
--static struct net_device_stats *tulip_get_stats(struct device *dev);
-+static int tulip_close(struct net_device *dev);
-+static struct net_device_stats *tulip_get_stats(struct net_device *dev);
- #ifdef HAVE_PRIVATE_IOCTL
--static int private_ioctl(struct device *dev, struct ifreq *rq, int cmd);
-+static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
- #endif
--static void set_rx_mode(struct device *dev);
-+static void set_rx_mode(struct net_device *dev);
-
-
-
- /* A list of all installed Tulip devices. */
--static struct device *root_tulip_dev = NULL;
--
--#ifndef CARDBUS
--int tulip_probe(struct device *dev)
--{
-- int cards_found = 0;
-- int pci_index = 0;
-- unsigned char pci_bus, pci_device_fn;
--
-- if ( ! pcibios_present())
-- return -ENODEV;
--
-- for (;pci_index < 0xff; pci_index++) {
-- u16 vendor, device, pci_command, new_command, subvendor;
-- int chip_idx;
-- int irq;
-- long ioaddr;
--
-- if (pcibios_find_class
-- (PCI_CLASS_NETWORK_ETHERNET << 8,
-- reverse_probe ? 0xfe - pci_index : pci_index,
-- &pci_bus, &pci_device_fn) != PCIBIOS_SUCCESSFUL) {
-- if (reverse_probe)
-- continue;
-- else
-- break;
-- }
-- pcibios_read_config_word(pci_bus, pci_device_fn,
-- PCI_VENDOR_ID, &vendor);
-- pcibios_read_config_word(pci_bus, pci_device_fn,
-- PCI_DEVICE_ID, &device);
-- pcibios_read_config_word(pci_bus, pci_device_fn,
-- PCI_SUBSYSTEM_VENDOR_ID, &subvendor);
--
-- if( subvendor == 0x1376 ){
-- printk("tulip: skipping LMC card.\n");
-- continue;
-- }
--
-- for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++)
-- if (vendor == pci_tbl[chip_idx].vendor_id
-- && (device & pci_tbl[chip_idx].device_id_mask) ==
-- pci_tbl[chip_idx].device_id)
-- break;
-- if (pci_tbl[chip_idx].vendor_id == 0)
-- continue;
--
-- {
--#if defined(PCI_SUPPORT_VER2)
-- struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
-- ioaddr = pdev->base_address[0] & ~3;
-- irq = pdev->irq;
--#else
-- u32 pci_ioaddr;
-- u8 pci_irq_line;
-- pcibios_read_config_dword(pci_bus, pci_device_fn,
-- PCI_BASE_ADDRESS_0, &pci_ioaddr);
-- pcibios_read_config_byte(pci_bus, pci_device_fn,
-- PCI_INTERRUPT_LINE, &pci_irq_line);
-- ioaddr = pci_ioaddr & ~3;
-- irq = pci_irq_line;
--#endif
-- }
--
-- if (debug > 2)
-- printk(KERN_INFO "Found %s at PCI I/O address %#lx.\n",
-- pci_tbl[chip_idx].name, ioaddr);
--
-- if (check_region(ioaddr, pci_tbl[chip_idx].io_size))
-- continue;
--
-- pcibios_read_config_word(pci_bus, pci_device_fn,
-- PCI_COMMAND, &pci_command);
-- new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
-- if (pci_command != new_command) {
-- printk(KERN_INFO " The PCI BIOS has not enabled the"
-- " device at %d/%d! Updating PCI command %4.4x->%4.4x.\n",
-- pci_bus, pci_device_fn, pci_command, new_command);
-- pcibios_write_config_word(pci_bus, pci_device_fn,
-- PCI_COMMAND, new_command);
-- }
--
-- dev = pci_tbl[chip_idx].probe1(pci_bus, pci_device_fn, dev, ioaddr,
-- irq, chip_idx, cards_found);
--
-- /* Get and check the bus-master and latency values. */
-- if (dev) {
-- u8 pci_latency;
-- pcibios_read_config_byte(pci_bus, pci_device_fn,
-- PCI_LATENCY_TIMER, &pci_latency);
-- if (pci_latency < 10) {
-- printk(KERN_INFO " PCI latency timer (CFLT) is "
-- "unreasonably low at %d. Setting to 64 clocks.\n",
-- pci_latency);
-- pcibios_write_config_byte(pci_bus, pci_device_fn,
-- PCI_LATENCY_TIMER, 64);
-- }
-- }
-- dev = 0;
-- cards_found++;
-- }
--
-- return cards_found ? 0 : -ENODEV;
--}
--#endif /* not CARDBUS */
-+static struct net_device *root_tulip_dev = NULL;
-
--static struct device *tulip_probe1(int pci_bus, int pci_devfn,
-- struct device *dev, long ioaddr, int irq,
-- int chip_idx, int board_idx)
-+static void *tulip_probe1(struct pci_dev *pdev, void *init_dev,
-+ long ioaddr, int irq, int pci_tbl_idx, int find_cnt)
- {
-- static int did_version = 0; /* Already printed version info. */
-+ struct net_device *dev;
- struct tulip_private *tp;
-+ void *priv_mem;
- /* See note below on the multiport cards. */
-- static unsigned char last_phys_addr[6] = {0x00, 'L', 'i', 'n', 'u', 'x'};
-+ static unsigned char last_phys_addr[6] = {0x02, 'L', 'i', 'n', 'u', 'x'};
- static int last_irq = 0;
- static int multiport_cnt = 0; /* For four-port boards w/one EEPROM */
- u8 chip_rev;
-- int i;
-+ int i, chip_idx = pci_id_tbl[pci_tbl_idx].drv_flags & 0xff;
- unsigned short sum;
- u8 ee_data[EEPROM_SIZE];
-
-- if (tulip_debug > 0 && did_version++ == 0)
-- printk(KERN_INFO "%s", version);
-+ /* Bring the 21041/21143 out of sleep mode.
-+ Caution: Snooze mode does not work with some boards! */
-+ if (tulip_tbl[chip_idx].flags & HAS_PWRDWN)
-+ pci_write_config_dword(pdev, 0x40, 0x00000000);
-+
-+ if (inl(ioaddr + CSR5) == 0xffffffff) {
-+ printk(KERN_ERR "The Tulip chip at %#lx is not functioning.\n", ioaddr);
-+ return 0;
-+ }
-
-- dev = init_etherdev(dev, 0);
-+ dev = init_etherdev(init_dev, 0);
-+ if (!dev)
-+ return NULL;
-
- /* Make certain the data structures are quadword aligned. */
-- tp = (void *)(((long)kmalloc(sizeof(*tp), GFP_KERNEL | GFP_DMA) + 7) & ~7);
-+ priv_mem = kmalloc(sizeof(*tp) + PRIV_ALIGN, GFP_KERNEL);
-+ /* Check for the very unlikely case of no memory. */
-+ if (priv_mem == NULL)
-+ return NULL;
-+ dev->priv = tp = (void *)(((long)priv_mem + PRIV_ALIGN) & ~PRIV_ALIGN);
- memset(tp, 0, sizeof(*tp));
-- dev->priv = tp;
-+ tp->mii_lock = (spinlock_t) SPIN_LOCK_UNLOCKED;
-+ tp->priv_addr = priv_mem;
-
- tp->next_module = root_tulip_dev;
- root_tulip_dev = dev;
-
-- pcibios_read_config_byte(pci_bus, pci_devfn, PCI_REVISION_ID, &chip_rev);
--
-- /* Bring the 21041/21143 out of sleep mode.
-- Caution: Snooze mode does not work with some boards! */
-- if (tulip_tbl[chip_idx].flags & HAS_PWRDWN)
-- pcibios_write_config_dword(pci_bus, pci_devfn, 0x40, 0x00000000);
-+ pci_read_config_byte(pdev, PCI_REVISION_ID, &chip_rev);
-
- printk(KERN_INFO "%s: %s rev %d at %#3lx,",
-- dev->name, tulip_tbl[chip_idx].chip_name, chip_rev, ioaddr);
-+ dev->name, pci_id_tbl[pci_tbl_idx].name, chip_rev, ioaddr);
-
-- /* Stop the chip's Tx and Rx processes. */
-- outl(inl(ioaddr + CSR6) & ~0x2002, ioaddr + CSR6);
-+ /* Stop the Tx and Rx processes. */
-+ outl(inl(ioaddr + CSR6) & ~TxOn & ~RxOn, ioaddr + CSR6);
- /* Clear the missed-packet counter. */
-- (volatile int)inl(ioaddr + CSR8);
-+ inl(ioaddr + CSR8);
-
- if (chip_idx == DC21041 && inl(ioaddr + CSR9) & 0x8000) {
- printk(" 21040 compatible mode,");
- chip_idx = DC21040;
- }
-
-- /* The station address ROM is read byte serially. The register must
-- be polled, waiting for the value to be read bit serially from the
-- EEPROM.
-- */
-+ /* The SROM/EEPROM interface varies dramatically. */
- sum = 0;
- if (chip_idx == DC21040) {
- outl(0, ioaddr + CSR9); /* Reset the pointer with a dummy write. */
-@@ -749,16 +772,18 @@
- }
- } else if (chip_idx == COMET) {
- /* No need to read the EEPROM. */
-- put_unaligned(inl(ioaddr + 0xA4), (u32 *)dev->dev_addr);
-- put_unaligned(inl(ioaddr + 0xA8), (u16 *)(dev->dev_addr + 4));
-+ put_unaligned(le32_to_cpu(inl(ioaddr + 0xA4)), (u32 *)dev->dev_addr);
-+ put_unaligned(le16_to_cpu(inl(ioaddr + 0xA8)),
-+ (u16 *)(dev->dev_addr + 4));
- for (i = 0; i < 6; i ++)
- sum += dev->dev_addr[i];
- } else {
- /* A serial EEPROM interface, we read now and sort it out later. */
- int sa_offset = 0;
- int ee_addr_size = read_eeprom(ioaddr, 0xff, 8) & 0x40000 ? 8 : 6;
-+ int eeprom_word_cnt = 1 << ee_addr_size;
-
-- for (i = 0; i < sizeof(ee_data)/2; i++)
-+ for (i = 0; i < eeprom_word_cnt; i++)
- ((u16 *)ee_data)[i] =
- le16_to_cpu(read_eeprom(ioaddr, i, ee_addr_size));
-
-@@ -768,7 +793,12 @@
- for (i = 0; i < 8; i ++)
- if (ee_data[i] != ee_data[16+i])
- sa_offset = 20;
-- if (ee_data[0] == 0xff && ee_data[1] == 0xff && ee_data[2] == 0) {
-+ if (chip_idx == CONEXANT) {
-+ /* Check that the tuple type and length is correct. */
-+ if (ee_data[0x198] == 0x04 && ee_data[0x199] == 6)
-+ sa_offset = 0x19A;
-+ } else if (ee_data[0] == 0xff && ee_data[1] == 0xff &&
-+ ee_data[2] == 0) {
- sa_offset = 2; /* Grrr, damn Matrox boards. */
- multiport_cnt = 4;
- }
-@@ -806,27 +836,33 @@
- printk(", IRQ %d.\n", irq);
- last_irq = irq;
-
-- /* We do a request_region() only to register /proc/ioports info. */
-- /* Note that proper size is tulip_tbl[chip_idx].chip_name, but... */
-- request_region(ioaddr, tulip_tbl[chip_idx].io_size, dev->name);
-+#ifdef USE_IO_OPS
-+ /* We do a request_region() to register /proc/ioports info. */
-+ request_region(ioaddr, pci_id_tbl[chip_idx].io_size, dev->name);
-+#endif
-
- dev->base_addr = ioaddr;
- dev->irq = irq;
-
-- tp->pci_bus = pci_bus;
-- tp->pci_devfn = pci_devfn;
-+ tp->pci_dev = pdev;
-+ tp->msg_level = (1 << debug) - 1;
- tp->chip_id = chip_idx;
- tp->revision = chip_rev;
-- tp->flags = tulip_tbl[chip_idx].flags;
-+ tp->flags = tulip_tbl[chip_idx].flags
-+ | (pci_id_tbl[pci_tbl_idx].drv_flags & 0xffffff00);
-+ tp->rx_copybreak = rx_copybreak;
-+ tp->max_interrupt_work = max_interrupt_work;
-+ tp->multicast_filter_limit = multicast_filter_limit;
- tp->csr0 = csr0;
-
- /* BugFixes: The 21143-TD hangs with PCI Write-and-Invalidate cycles.
- And the ASIX must have a burst limit or horrible things happen. */
- if (chip_idx == DC21143 && chip_rev == 65)
- tp->csr0 &= ~0x01000000;
-- else if (chip_idx == AX88140)
-+ else if (tp->flags & IS_ASIX)
- tp->csr0 |= 0x2000;
-
-+ /* We support a zillion ways to set the media type. */
- #ifdef TULIP_FULL_DUPLEX
- tp->full_duplex = 1;
- tp->full_duplex_lock = 1;
-@@ -839,16 +875,19 @@
- #endif
-
- /* The lower four bits are the media type. */
-- if (board_idx >= 0 && board_idx < MAX_UNITS) {
-- tp->default_port = options[board_idx] & 15;
-- if ((options[board_idx] & 0x90) || full_duplex[board_idx] > 0)
-+ if (find_cnt >= 0 && find_cnt < MAX_UNITS) {
-+ if (options[find_cnt] & 0x1f)
-+ tp->default_port = options[find_cnt] & 0x1f;
-+ if ((options[find_cnt] & 0x200) || full_duplex[find_cnt] > 0)
- tp->full_duplex = 1;
-- if (mtu[board_idx] > 0)
-- dev->mtu = mtu[board_idx];
-+ if (mtu[find_cnt] > 0)
-+ dev->mtu = mtu[find_cnt];
- }
- if (dev->mem_start)
-- tp->default_port = dev->mem_start;
-+ tp->default_port = dev->mem_start & 0x1f;
- if (tp->default_port) {
-+ printk(KERN_INFO "%s: Transceiver selection forced to %s.\n",
-+ dev->name, medianame[tp->default_port & MEDIA_MASK]);
- tp->medialock = 1;
- if (media_cap[tp->default_port] & MediaAlwaysFD)
- tp->full_duplex = 1;
-@@ -858,11 +897,9 @@
-
- if (media_cap[tp->default_port] & MediaIsMII) {
- u16 media2advert[] = { 0x20, 0x40, 0x03e0, 0x60, 0x80, 0x100, 0x200 };
-- tp->to_advertise = media2advert[tp->default_port - 9];
-- } else if (tp->flags & HAS_8023X)
-- tp->to_advertise = 0x05e1;
-- else
-- tp->to_advertise = 0x01e1;
-+ tp->mii_advertise = media2advert[tp->default_port - 9];
-+ tp->mii_advertise |= (tp->flags & HAS_8023X); /* Matching bits! */
-+ }
-
- /* This is logically part of probe1(), but too complex to write inline. */
- if (tp->flags & HAS_MEDIA_TABLE) {
-@@ -870,16 +907,49 @@
- parse_eeprom(dev);
- }
-
-+ /* The Tulip-specific entries in the device structure. */
-+ dev->open = &tulip_open;
-+ dev->hard_start_xmit = &tulip_start_xmit;
-+ dev->stop = &tulip_close;
-+ dev->get_stats = &tulip_get_stats;
-+#ifdef HAVE_PRIVATE_IOCTL
-+ dev->do_ioctl = &private_ioctl;
-+#endif
-+#ifdef HAVE_MULTICAST
-+ dev->set_multicast_list = &set_rx_mode;
-+#endif
-+
-+ if (tp->flags & HAS_NWAY)
-+ tp->link_change = nway_lnk_change;
-+ else if (tp->flags & HAS_PNICNWAY)
-+ tp->link_change = pnic_lnk_change;
-+ start_link(dev);
-+ if (chip_idx == COMET) {
-+ /* Set the Comet LED configuration. */
-+ outl(0xf0000000, ioaddr + CSR9);
-+ }
-+
-+ return dev;
-+}
-+
-+/* Start the link, typically called at probe1() time but sometimes later with
-+ multiport cards. */
-+static void start_link(struct net_device *dev)
-+{
-+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+ int i;
-+
- if ((tp->flags & ALWAYS_CHECK_MII) ||
- (tp->mtable && tp->mtable->has_mii) ||
- ( ! tp->mtable && (tp->flags & HAS_MII))) {
-- int phy, phy_idx;
-+ int phyn, phy_idx = 0;
- if (tp->mtable && tp->mtable->has_mii) {
- for (i = 0; i < tp->mtable->leafcount; i++)
- if (tp->mtable->mleaf[i].media == 11) {
- tp->cur_index = i;
- tp->saved_if_port = dev->if_port;
-- select_media(dev, 1);
-+ select_media(dev, 2);
- dev->if_port = tp->saved_if_port;
- break;
- }
-@@ -887,33 +957,38 @@
- /* Find the connected MII xcvrs.
- Doing this in open() would allow detecting external xcvrs later,
- but takes much time. */
-- for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(tp->phys);
-- phy++) {
-+ for (phyn = 1; phyn <= 32 && phy_idx < sizeof(tp->phys); phyn++) {
-+ int phy = phyn & 0x1f;
- int mii_status = mdio_read(dev, phy, 1);
- if ((mii_status & 0x8301) == 0x8001 ||
- ((mii_status & 0x8000) == 0 && (mii_status & 0x7800) != 0)) {
- int mii_reg0 = mdio_read(dev, phy, 0);
- int mii_advert = mdio_read(dev, phy, 4);
-- int reg4 = ((mii_status>>6) & tp->to_advertise) | 1;
-- tp->phys[phy_idx] = phy;
-- tp->advertising[phy_idx++] = reg4;
-+ int to_advert;
-+
-+ if (tp->mii_advertise)
-+ to_advert = tp->mii_advertise;
-+ else if (tp->advertising[phy_idx])
-+ to_advert = tp->advertising[phy_idx];
-+ else /* Leave unchanged. */
-+ tp->mii_advertise = to_advert = mii_advert;
-+
-+ tp->phys[phy_idx++] = phy;
- printk(KERN_INFO "%s: MII transceiver #%d "
- "config %4.4x status %4.4x advertising %4.4x.\n",
- dev->name, phy, mii_reg0, mii_status, mii_advert);
- /* Fixup for DLink with miswired PHY. */
-- if (mii_advert != reg4) {
-+ if (mii_advert != to_advert) {
- printk(KERN_DEBUG "%s: Advertising %4.4x on PHY %d,"
- " previously advertising %4.4x.\n",
-- dev->name, reg4, phy, mii_advert);
-- printk(KERN_DEBUG "%s: Advertising %4.4x (to advertise"
-- " is %4.4x).\n",
-- dev->name, reg4, tp->to_advertise);
-- mdio_write(dev, phy, 4, reg4);
-+ dev->name, to_advert, phy, mii_advert);
-+ mdio_write(dev, phy, 4, to_advert);
- }
- /* Enable autonegotiation: some boards default to off. */
-- mdio_write(dev, phy, 0, mii_reg0 |
-- (tp->full_duplex ? 0x1100 : 0x1000) |
-- (media_cap[tp->default_port]&MediaIs100 ? 0x2000:0));
-+ mdio_write(dev, phy, 0, (mii_reg0 & ~0x3000) |
-+ (tp->full_duplex ? 0x0100 : 0x0000) |
-+ ((media_cap[tp->default_port] & MediaIs100) ?
-+ 0x2000 : 0x1000));
- }
- }
- tp->mii_cnt = phy_idx;
-@@ -924,36 +999,21 @@
- }
- }
-
-- /* The Tulip-specific entries in the device structure. */
-- dev->open = &tulip_open;
-- dev->hard_start_xmit = &tulip_start_xmit;
-- dev->stop = &tulip_close;
-- dev->get_stats = &tulip_get_stats;
--#ifdef HAVE_PRIVATE_IOCTL
-- dev->do_ioctl = &private_ioctl;
--#endif
--#ifdef HAVE_MULTICAST
-- dev->set_multicast_list = &set_rx_mode;
--#endif
--
-- if ((tp->flags & HAS_NWAY143) || tp->chip_id == DC21041)
-- tp->link_change = t21142_lnk_change;
-- else if (tp->flags & HAS_PNICNWAY)
-- tp->link_change = pnic_lnk_change;
--
- /* Reset the xcvr interface and turn on heartbeat. */
-- switch (chip_idx) {
-+ switch (tp->chip_id) {
-+ case DC21040:
-+ outl(0x00000000, ioaddr + CSR13);
-+ outl(0x00000004, ioaddr + CSR13);
-+ break;
- case DC21041:
-- tp->to_advertise = 0x0061;
-+ /* This is nway_start(). */
-+ if (tp->sym_advertise == 0)
-+ tp->sym_advertise = 0x0061;
- outl(0x00000000, ioaddr + CSR13);
- outl(0xFFFFFFFF, ioaddr + CSR14);
- outl(0x00000008, ioaddr + CSR15); /* Listen on AUI also. */
-- outl(inl(ioaddr + CSR6) | 0x0200, ioaddr + CSR6);
-- outl(0x0000EF05, ioaddr + CSR13);
-- break;
-- case DC21040:
-- outl(0x00000000, ioaddr + CSR13);
-- outl(0x00000004, ioaddr + CSR13);
-+ outl(inl(ioaddr + CSR6) | FullDuplex, ioaddr + CSR6);
-+ outl(0x0000EF01, ioaddr + CSR13);
- break;
- case DC21140: default:
- if (tp->mtable)
-@@ -967,7 +1027,7 @@
- outl(0x0000, ioaddr + CSR14);
- outl(0x820E0000, ioaddr + CSR6);
- } else
-- t21142_start_nway(dev);
-+ nway_start(dev);
- break;
- case LC82C168:
- if ( ! tp->mii_cnt) {
-@@ -979,35 +1039,36 @@
- outl(0x0201F078, ioaddr + 0xB8); /* Turn on autonegotiation. */
- }
- break;
-- case MX98713: case COMPEX9881:
-+ case COMPEX9881:
- outl(0x00000000, ioaddr + CSR6);
- outl(0x000711C0, ioaddr + CSR14); /* Turn on NWay. */
- outl(0x00000001, ioaddr + CSR13);
- break;
-- case MX98715: case MX98725:
-+ case MX98713: case MX98715: case MX98725:
- outl(0x01a80000, ioaddr + CSR6);
- outl(0xFFFFFFFF, ioaddr + CSR14);
- outl(0x00001000, ioaddr + CSR12);
- break;
- case COMET:
-- /* No initialization necessary. */
- break;
- }
-
-- if (tulip_tbl[chip_idx].flags & HAS_PWRDWN)
-- pcibios_write_config_dword(pci_bus, pci_devfn, 0x40, 0x40000000);
--
-- return dev;
-+ if (tp->flags & HAS_PWRDWN)
-+ pci_write_config_dword(tp->pci_dev, 0x40, 0x40000000);
- }
-+
-
- /* Serial EEPROM section. */
- /* The main routine to parse the very complicated SROM structure.
- Search www.digital.com for "21X4 SROM" to get details.
- This code is very complex, and will require changes to support
-- additional cards, so I'll be verbose about what is going on.
-+ additional cards, so I will be verbose about what is going on.
- */
-
--/* Known cards that have old-style EEPROMs. */
-+/* Known cards that have old-style EEPROMs.
-+ Writing this table is described at
-+ http://www.scyld.com/network/tulip-media.html
-+*/
- static struct fixups {
- char *name;
- unsigned char addr0, addr1, addr2;
-@@ -1051,14 +1112,15 @@
- #define get_u16(ptr) (((u8*)(ptr))[0] + (((u8*)(ptr))[1]<<8))
- #endif
-
--static void parse_eeprom(struct device *dev)
-+static void parse_eeprom(struct net_device *dev)
- {
- /* The last media info list parsed, for multiport boards. */
- static struct mediatable *last_mediatable = NULL;
- static unsigned char *last_ee_data = NULL;
- static int controller_index = 0;
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
-- unsigned char *ee_data = tp->eeprom;
-+ unsigned char *p, *ee_data = tp->eeprom;
-+ int new_advertise = 0;
- int i;
-
- tp->mtable = 0;
-@@ -1079,59 +1141,76 @@
- } else
- printk(KERN_INFO "%s: Missing EEPROM, this interface may "
- "not work correctly!\n",
-- dev->name);
-+ dev->name);
- return;
- }
-- /* Do a fix-up based on the vendor half of the station address prefix. */
-- for (i = 0; eeprom_fixups[i].name; i++) {
-- if (dev->dev_addr[0] == eeprom_fixups[i].addr0
-- && dev->dev_addr[1] == eeprom_fixups[i].addr1
-- && dev->dev_addr[2] == eeprom_fixups[i].addr2) {
-- if (dev->dev_addr[2] == 0xE8 && ee_data[0x1a] == 0x55)
-- i++; /* An Accton EN1207, not an outlaw Maxtech. */
-- memcpy(ee_data + 26, eeprom_fixups[i].newtable,
-- sizeof(eeprom_fixups[i].newtable));
-- printk(KERN_INFO "%s: Old format EEPROM on '%s' board. Using"
-- " substitute media control info.\n",
-- dev->name, eeprom_fixups[i].name);
-- break;
-+ /* Do a fix-up based on the vendor half of the station address. */
-+ for (i = 0; eeprom_fixups[i].name; i++) {
-+ if (dev->dev_addr[0] == eeprom_fixups[i].addr0
-+ && dev->dev_addr[1] == eeprom_fixups[i].addr1
-+ && dev->dev_addr[2] == eeprom_fixups[i].addr2) {
-+ if (dev->dev_addr[2] == 0xE8 && ee_data[0x1a] == 0x55)
-+ i++; /* An Accton EN1207, not an outlaw Maxtech. */
-+ memcpy(ee_data + 26, eeprom_fixups[i].newtable,
-+ sizeof(eeprom_fixups[i].newtable));
-+ printk(KERN_INFO "%s: Old format EEPROM on '%s' board.\n"
-+ KERN_INFO "%s: Using substitute media control info.\n",
-+ dev->name, eeprom_fixups[i].name, dev->name);
-+ break;
-+ }
-+ }
-+ if (eeprom_fixups[i].name == NULL) { /* No fixup found. */
-+ printk(KERN_INFO "%s: Old style EEPROM with no media selection "
-+ "information.\n",
-+ dev->name);
-+ return;
- }
-- }
-- if (eeprom_fixups[i].name == NULL) { /* No fixup found. */
-- printk(KERN_INFO "%s: Old style EEPROM with no media selection "
-- "information.\n",
-- dev->name);
-- return;
-- }
- }
-
- controller_index = 0;
-- if (ee_data[19] > 1) { /* Multiport board. */
-+ if (ee_data[19] > 1) {
-+ struct net_device *prev_dev;
-+ struct tulip_private *otp;
-+ /* This is a multiport board. The probe order may be "backwards", so
-+ we patch up already found devices. */
- last_ee_data = ee_data;
-+ for (prev_dev = tp->next_module; prev_dev; prev_dev = otp->next_module) {
-+ otp = (struct tulip_private *)prev_dev->priv;
-+ if (otp->eeprom[0] == 0xff && otp->mtable == 0) {
-+ parse_eeprom(prev_dev);
-+ start_link(prev_dev);
-+ } else
-+ break;
-+ }
-+ controller_index = 0;
- }
- subsequent_board:
-
-+ p = (void *)ee_data + ee_data[27 + controller_index*3];
- if (ee_data[27] == 0) { /* No valid media table. */
- } else if (tp->chip_id == DC21041) {
-- unsigned char *p = (void *)ee_data + ee_data[27 + controller_index*3];
- int media = get_u16(p);
- int count = p[2];
- p += 3;
-
- printk(KERN_INFO "%s: 21041 Media table, default media %4.4x (%s).\n",
- dev->name, media,
-- media & 0x0800 ? "Autosense" : medianame[media & 15]);
-+ media & 0x0800 ? "Autosense" : medianame[media & MEDIA_MASK]);
- for (i = 0; i < count; i++) {
-- unsigned char media_code = *p++;
-- if (media_code & 0x40)
-+ unsigned char media_block = *p++;
-+ int media_code = media_block & MEDIA_MASK;
-+ if (media_block & 0x40)
- p += 6;
-+ switch(media_code) {
-+ case 0: new_advertise |= 0x0020; break;
-+ case 4: new_advertise |= 0x0040; break;
-+ }
- printk(KERN_INFO "%s: 21041 media #%d, %s.\n",
-- dev->name, media_code & 15, medianame[media_code & 15]);
-+ dev->name, media_code, medianame[media_code]);
- }
- } else {
-- unsigned char *p = (void *)ee_data + ee_data[27];
- unsigned char csr12dir = 0;
-- int count, new_advertise = 0;
-+ int count;
- struct mediatable *mtable;
- u16 media = get_u16(p);
-
-@@ -1152,7 +1231,7 @@
- mtable->csr15dir = mtable->csr15val = 0;
-
- printk(KERN_INFO "%s: EEPROM default media type %s.\n", dev->name,
-- media & 0x0800 ? "Autosense" : medianame[media & 15]);
-+ media & 0x0800 ? "Autosense" : medianame[media & MEDIA_MASK]);
- for (i = 0; i < count; i++) {
- struct medialeaf *leaf = &mtable->mleaf[i];
-
-@@ -1164,16 +1243,28 @@
- mtable->has_mii = 1;
- p += 4;
- } else {
-- leaf->type = p[1];
-- if (p[1] == 0x05) {
-- mtable->has_reset = i;
-- leaf->media = p[2] & 0x0f;
-- } else if (p[1] & 1) {
-+ switch(leaf->type = p[1]) {
-+ case 5:
-+ mtable->has_reset = i + 1; /* Assure non-zero */
-+ /* Fall through */
-+ case 6:
-+ leaf->media = 31;
-+ break;
-+ case 1: case 3:
- mtable->has_mii = 1;
- leaf->media = 11;
-- } else {
-+ break;
-+ case 2:
-+ if ((p[2] & 0x3f) == 0) {
-+ u32 base15 = (p[2] & 0x40) ? get_u16(p + 7) : 0x0008;
-+ u16 *p1 = (u16 *)(p + (p[2] & 0x40 ? 9 : 3));
-+ mtable->csr15dir = (get_unaligned(p1 + 0)<<16) + base15;
-+ mtable->csr15val = (get_unaligned(p1 + 1)<<16) + base15;
-+ }
-+ /* Fall through. */
-+ case 0: case 4:
- mtable->has_nonmii = 1;
-- leaf->media = p[2] & 0x0f;
-+ leaf->media = p[2] & MEDIA_MASK;
- switch (leaf->media) {
- case 0: new_advertise |= 0x0020; break;
- case 4: new_advertise |= 0x0040; break;
-@@ -1181,36 +1272,30 @@
- case 5: new_advertise |= 0x0100; break;
- case 6: new_advertise |= 0x0200; break;
- }
-- if (p[1] == 2 && leaf->media == 0) {
-- if (p[2] & 0x40) {
-- u32 base15 = get_unaligned((u16*)&p[7]);
-- mtable->csr15dir =
-- (get_unaligned((u16*)&p[9])<<16) + base15;
-- mtable->csr15val =
-- (get_unaligned((u16*)&p[11])<<16) + base15;
-- } else {
-- mtable->csr15dir = get_unaligned((u16*)&p[3])<<16;
-- mtable->csr15val = get_unaligned((u16*)&p[5])<<16;
-- }
-- }
-+ break;
-+ default:
-+ leaf->media = 19;
- }
- leaf->leafdata = p + 2;
- p += (p[0] & 0x3f) + 1;
- }
-- if (tulip_debug > 1 && leaf->media == 11) {
-+ if ((tp->msg_level & NETIF_MSG_LINK) &&
-+ leaf->media == 11) {
- unsigned char *bp = leaf->leafdata;
- printk(KERN_INFO "%s: MII interface PHY %d, setup/reset "
- "sequences %d/%d long, capabilities %2.2x %2.2x.\n",
- dev->name, bp[0], bp[1], bp[2 + bp[1]*2],
- bp[5 + bp[2 + bp[1]*2]*2], bp[4 + bp[2 + bp[1]*2]*2]);
- }
-- printk(KERN_INFO "%s: Index #%d - Media %s (#%d) described "
-- "by a %s (%d) block.\n",
-- dev->name, i, medianame[leaf->media], leaf->media,
-- block_name[leaf->type], leaf->type);
-+ if (tp->msg_level & NETIF_MSG_PROBE)
-+ printk(KERN_INFO "%s: Index #%d - Media %s (#%d) described "
-+ "by a %s (%d) block.\n",
-+ dev->name, i, medianame[leaf->media], leaf->media,
-+ leaf->type < 6 ? block_name[leaf->type] : "UNKNOWN",
-+ leaf->type);
- }
- if (new_advertise)
-- tp->to_advertise = new_advertise;
-+ tp->sym_advertise = new_advertise;
- }
- }
- /* Reading a serial EEPROM is a "bit" grungy, but we work our way through:->.*/
-@@ -1225,7 +1310,7 @@
- #define EE_ENB (0x4800 | EE_CS)
-
- /* Delay between EEPROM clock transitions.
-- Even at 33Mhz current PCI implementations don't overrun the EEPROM clock.
-+ Even at 33Mhz current PCI implementations do not overrun the EEPROM clock.
- We add a bus turn-around to insure that this remains true. */
- #define eeprom_delay() inl(ee_addr)
-
-@@ -1253,6 +1338,7 @@
- retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0);
- }
- outl(EE_ENB, ee_addr);
-+ eeprom_delay();
-
- for (i = 16; i > 0; i--) {
- outl(EE_ENB | EE_SHIFT_CLK, ee_addr);
-@@ -1287,36 +1373,42 @@
- #define MDIO_ENB_IN 0x40000
- #define MDIO_DATA_READ 0x80000
-
--static int mdio_read(struct device *dev, int phy_id, int location)
-+static const unsigned char comet_miireg2offset[32] = {
-+ 0xB4, 0xB8, 0xBC, 0xC0, 0xC4, 0xC8, 0xCC, 0, 0,0,0,0, 0,0,0,0,
-+ 0,0xD0,0,0, 0,0,0,0, 0,0,0,0, 0, 0xD4, 0xD8, 0xDC, };
-+
-+static int mdio_read(struct net_device *dev, int phy_id, int location)
- {
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- int i;
-- int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
-+ int read_cmd = (0xf6 << 10) | ((phy_id & 0x1f) << 5) | location;
- int retval = 0;
- long ioaddr = dev->base_addr;
- long mdio_addr = ioaddr + CSR9;
-+ unsigned long flags;
-+
-+ if (location & ~0x1f)
-+ return 0xffff;
-+
-+ if (tp->chip_id == COMET && phy_id == 30) {
-+ if (comet_miireg2offset[location])
-+ return inl(ioaddr + comet_miireg2offset[location]);
-+ return 0xffff;
-+ }
-
-+ spin_lock_irqsave(&tp->mii_lock, flags);
- if (tp->chip_id == LC82C168) {
- int i = 1000;
- outl(0x60020000 + (phy_id<<23) + (location<<18), ioaddr + 0xA0);
- inl(ioaddr + 0xA0);
- inl(ioaddr + 0xA0);
-+ inl(ioaddr + 0xA0);
-+ inl(ioaddr + 0xA0);
- while (--i > 0)
- if ( ! ((retval = inl(ioaddr + 0xA0)) & 0x80000000))
-- return retval & 0xffff;
-- return 0xffff;
-- }
--
-- if (tp->chip_id == COMET) {
-- if (phy_id == 1) {
-- if (location < 7)
-- return inl(ioaddr + 0xB4 + (location<<2));
-- else if (location == 17)
-- return inl(ioaddr + 0xD0);
-- else if (location >= 29 && location <= 31)
-- return inl(ioaddr + 0xD4 + ((location-29)<<2));
-- }
-- return 0xffff;
-+ break;
-+ spin_unlock_irqrestore(&tp->mii_lock, flags);
-+ return retval & 0xffff;
- }
-
- /* Establish sync by sending at least 32 logic ones. */
-@@ -1343,17 +1435,29 @@
- outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
- mdio_delay();
- }
-+ spin_unlock_irqrestore(&tp->mii_lock, flags);
- return (retval>>1) & 0xffff;
- }
-
--static void mdio_write(struct device *dev, int phy_id, int location, int value)
-+static void mdio_write(struct net_device *dev, int phy_id, int location, int val)
- {
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- int i;
-- int cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;
-+ int cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | (val & 0xffff);
- long ioaddr = dev->base_addr;
- long mdio_addr = ioaddr + CSR9;
-+ unsigned long flags;
-+
-+ if (location & ~0x1f)
-+ return;
-+
-+ if (tp->chip_id == COMET && phy_id == 30) {
-+ if (comet_miireg2offset[location])
-+ outl(val, ioaddr + comet_miireg2offset[location]);
-+ return;
-+ }
-
-+ spin_lock_irqsave(&tp->mii_lock, flags);
- if (tp->chip_id == LC82C168) {
- int i = 1000;
- outl(cmd, ioaddr + 0xA0);
-@@ -1361,18 +1465,7 @@
- if ( ! (inl(ioaddr + 0xA0) & 0x80000000))
- break;
- while (--i > 0);
-- return;
-- }
--
-- if (tp->chip_id == COMET) {
-- if (phy_id != 1)
-- return;
-- if (location < 7)
-- outl(value, ioaddr + 0xB4 + (location<<2));
-- else if (location == 17)
-- outl(value, ioaddr + 0xD0);
-- else if (location >= 29 && location <= 31)
-- outl(value, ioaddr + 0xD4 + ((location-29)<<2));
-+ spin_unlock_irqrestore(&tp->mii_lock, flags);
- return;
- }
-
-@@ -1398,21 +1491,21 @@
- outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
- mdio_delay();
- }
-+ spin_unlock_irqrestore(&tp->mii_lock, flags);
- return;
- }
-
-
- static int
--tulip_open(struct device *dev)
-+tulip_open(struct net_device *dev)
- {
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- long ioaddr = dev->base_addr;
- int next_tick = 3*HZ;
-- int i;
-
- /* Wake the chip from sleep/snooze mode. */
- if (tp->flags & HAS_PWRDWN)
-- pcibios_write_config_dword(tp->pci_bus, tp->pci_devfn, 0x40, 0);
-+ pci_write_config_dword(tp->pci_dev, 0x40, 0);
-
- /* On some chip revs we must set the MII/SYM port before the reset!? */
- if (tp->mii_cnt || (tp->mtable && tp->mtable->has_mii))
-@@ -1421,67 +1514,93 @@
- /* Reset the chip, holding bit 0 set at least 50 PCI cycles. */
- outl(0x00000001, ioaddr + CSR0);
-
-- if (request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ, dev->name, dev))
-- return -EAGAIN;
- MOD_INC_USE_COUNT;
-
-+ /* This would be done after interrupts are initialized, but we do not want
-+ to frob the transceiver only to fail later. */
-+ if (request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ, dev->name, dev)) {
-+ MOD_DEC_USE_COUNT;
-+ return -EAGAIN;
-+ }
-+
- /* Deassert reset.
- Wait the specified 50 PCI cycles after a reset by initializing
- Tx and Rx queues and the address filter list. */
- outl(tp->csr0, ioaddr + CSR0);
-
-- if (tulip_debug > 1)
-+ if (tp->msg_level & NETIF_MSG_IFUP)
- printk(KERN_DEBUG "%s: tulip_open() irq %d.\n", dev->name, dev->irq);
-
- tulip_init_ring(dev);
-
--#if 0
- if (tp->chip_id == PNIC2) {
-- u32 addr_low = cpu_to_le32(get_unaligned((u32 *)dev->dev_addr));
-- u32 addr_high = cpu_to_le16(get_unaligned((u16 *)(dev->dev_addr+4)));
-- addr_high = (dev->dev_addr[4]<<8) + (dev->dev_addr[5]<<0);
-- outl((dev->dev_addr[0]<<8) + dev->dev_addr[1] +
-- (dev->dev_addr[2]<<24) + (dev->dev_addr[3]<<16),
-+ u32 addr_high = (dev->dev_addr[1]<<8) + (dev->dev_addr[0]<<0);
-+ /* This address setting does not appear to impact chip operation?? */
-+ outl((dev->dev_addr[5]<<8) + dev->dev_addr[4] +
-+ (dev->dev_addr[3]<<24) + (dev->dev_addr[2]<<16),
- ioaddr + 0xB0);
- outl(addr_high + (addr_high<<16), ioaddr + 0xB8);
- }
--#endif
- if (tp->flags & MC_HASH_ONLY) {
- u32 addr_low = cpu_to_le32(get_unaligned((u32 *)dev->dev_addr));
-- u32 addr_high = cpu_to_le32(get_unaligned((u16 *)(dev->dev_addr+4)));
-- if (tp->chip_id == AX88140) {
-+ u32 addr_high = cpu_to_le16(get_unaligned((u16 *)(dev->dev_addr+4)));
-+ if (tp->flags & IS_ASIX) {
- outl(0, ioaddr + CSR13);
- outl(addr_low, ioaddr + CSR14);
- outl(1, ioaddr + CSR13);
- outl(addr_high, ioaddr + CSR14);
-- } else if (tp->chip_id == COMET) {
-+ } else if (tp->flags & COMET_MAC_ADDR) {
- outl(addr_low, ioaddr + 0xA4);
- outl(addr_high, ioaddr + 0xA8);
- outl(0, ioaddr + 0xAC);
- outl(0, ioaddr + 0xB0);
- }
-- } else {
-- /* This is set_rx_mode(), but without starting the transmitter. */
-- u16 *eaddrs = (u16 *)dev->dev_addr;
-- u16 *setup_frm = &tp->setup_frame[15*6];
--
-- /* 21140 bug: you must add the broadcast address. */
-- memset(tp->setup_frame, 0xff, sizeof(tp->setup_frame));
-- /* Fill the final entry of the table with our physical address. */
-- *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0];
-- *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1];
-- *setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2];
-- /* Put the setup frame on the Tx list. */
-- tp->tx_ring[0].length = cpu_to_le32(0x08000000 | 192);
-- tp->tx_ring[0].buffer1 = virt_to_le32desc(tp->setup_frame);
-- tp->tx_ring[0].status = cpu_to_le32(DescOwned);
--
-- tp->cur_tx++;
- }
-
- outl(virt_to_bus(tp->rx_ring), ioaddr + CSR3);
- outl(virt_to_bus(tp->tx_ring), ioaddr + CSR4);
-
-+ if ( ! tp->full_duplex_lock)
-+ tp->full_duplex = 0;
-+ init_media(dev);
-+ if (media_cap[dev->if_port] & MediaIsMII)
-+ check_duplex(dev);
-+ set_rx_mode(dev);
-+
-+ /* Start the Tx to process setup frame. */
-+ outl(tp->csr6, ioaddr + CSR6);
-+ outl(tp->csr6 | TxOn, ioaddr + CSR6);
-+
-+ netif_start_tx_queue(dev);
-+
-+ /* Enable interrupts by setting the interrupt mask. */
-+ outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR5);
-+ outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7);
-+ outl(tp->csr6 | TxOn | RxOn, ioaddr + CSR6);
-+ outl(0, ioaddr + CSR2); /* Rx poll demand */
-+
-+ if (tp->msg_level & NETIF_MSG_IFUP)
-+ printk(KERN_DEBUG "%s: Done tulip_open(), CSR0 %8.8x, CSR5 %8.8x CSR6 "
-+ "%8.8x.\n", dev->name, (int)inl(ioaddr + CSR0),
-+ (int)inl(ioaddr + CSR5), (int)inl(ioaddr + CSR6));
-+
-+ /* Set the timer to switch to check for link beat and perhaps switch
-+ to an alternate media type. */
-+ init_timer(&tp->timer);
-+ tp->timer.expires = jiffies + next_tick;
-+ tp->timer.data = (unsigned long)dev;
-+ tp->timer.function = tulip_tbl[tp->chip_id].media_timer;
-+ add_timer(&tp->timer);
-+
-+ return 0;
-+}
-+
-+static void init_media(struct net_device *dev)
-+{
-+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+ int i;
-+
- tp->saved_if_port = dev->if_port;
- if (dev->if_port == 0)
- dev->if_port = tp->default_port;
-@@ -1501,7 +1620,7 @@
- }
- }
- if ((tp->mtable->defaultmedia & 0x0800) == 0) {
-- int looking_for = tp->mtable->defaultmedia & 15;
-+ int looking_for = tp->mtable->defaultmedia & MEDIA_MASK;
- for (i = 0; i < tp->mtable->leafcount; i++)
- if (tp->mtable->mleaf[i].media == looking_for) {
- printk(KERN_INFO "%s: Using EEPROM-set media %s.\n",
-@@ -1518,13 +1637,27 @@
- tp->csr6 = 0;
- tp->cur_index = i;
- tp->nwayset = 0;
-- if (dev->if_port == 0 && tp->chip_id == DC21041) {
-- tp->nway = 1;
-+
-+ if (dev->if_port) {
-+ if (tp->chip_id == DC21143 &&
-+ (media_cap[dev->if_port] & MediaIsMII)) {
-+ /* We must reset the media CSRs when we force-select MII mode. */
-+ outl(0x0000, ioaddr + CSR13);
-+ outl(0x0000, ioaddr + CSR14);
-+ outl(0x0008, ioaddr + CSR15);
-+ }
-+ select_media(dev, 1);
-+ return;
- }
-- if (dev->if_port == 0 && tp->chip_id == DC21142) {
-+ switch(tp->chip_id) {
-+ case DC21041:
-+ /* tp->nway = 1;*/
-+ nway_start(dev);
-+ break;
-+ case DC21142:
- if (tp->mii_cnt) {
- select_media(dev, 1);
-- if (tulip_debug > 1)
-+ if (tp->msg_level & NETIF_MSG_LINK)
- printk(KERN_INFO "%s: Using MII transceiver %d, status "
- "%4.4x.\n",
- dev->name, tp->phys[0], mdio_read(dev, tp->phys[0], 1));
-@@ -1534,13 +1667,15 @@
- outl(0x0000, ioaddr + CSR13);
- outl(0x0000, ioaddr + CSR14);
- } else
-- t21142_start_nway(dev);
-- } else if (tp->chip_id == PNIC2) {
-- t21142_start_nway(dev);
-- } else if (tp->chip_id == LC82C168 && ! tp->medialock) {
-+ nway_start(dev);
-+ break;
-+ case PNIC2:
-+ nway_start(dev);
-+ break;
-+ case LC82C168:
- if (tp->mii_cnt) {
- dev->if_port = 11;
-- tp->csr6 = 0x814C0000 | (tp->full_duplex ? 0x0200 : 0);
-+ tp->csr6 = 0x814C0000 | (tp->full_duplex ? FullDuplex : 0);
- outl(0x0001, ioaddr + CSR15);
- } else if (inl(ioaddr + CSR5) & TPLnkPass)
- pnic_do_nway(dev);
-@@ -1550,65 +1685,39 @@
- tp->csr6 = 0x00420000;
- outl(0x0001B078, ioaddr + 0xB8);
- outl(0x0201B078, ioaddr + 0xB8);
-- next_tick = 1*HZ;
- }
-- } else if ((tp->chip_id == MX98713 || tp->chip_id == COMPEX9881)
-- && ! tp->medialock) {
-+ break;
-+ case MX98713: case COMPEX9881:
- dev->if_port = 0;
-- tp->csr6 = 0x01880000 | (tp->full_duplex ? 0x0200 : 0);
-+ tp->csr6 = 0x01880000 | (tp->full_duplex ? FullDuplex : 0);
- outl(0x0f370000 | inw(ioaddr + 0x80), ioaddr + 0x80);
-- } else if (tp->chip_id == MX98715 || tp->chip_id == MX98725) {
-+ break;
-+ case MX98715: case MX98725:
- /* Provided by BOLO, Macronix - 12/10/1998. */
- dev->if_port = 0;
-- tp->csr6 = 0x01a80200;
-+ tp->csr6 = 0x01a80000 | FullDuplex;
- outl(0x0f370000 | inw(ioaddr + 0x80), ioaddr + 0x80);
- outl(0x11000 | inw(ioaddr + 0xa0), ioaddr + 0xa0);
-- } else if (tp->chip_id == DC21143 &&
-- media_cap[dev->if_port] & MediaIsMII) {
-- /* We must reset the media CSRs when we force-select MII mode. */
-- outl(0x0000, ioaddr + CSR13);
-- outl(0x0000, ioaddr + CSR14);
-- outl(0x0008, ioaddr + CSR15);
-- } else if (tp->chip_id == COMET) {
-- dev->if_port = 0;
-+ break;
-+ case COMET: case CONEXANT:
-+ /* Enable automatic Tx underrun recovery. */
-+ outl(inl(ioaddr + 0x88) | 1, ioaddr + 0x88);
-+ dev->if_port = tp->mii_cnt ? 11 : 0;
- tp->csr6 = 0x00040000;
-- } else if (tp->chip_id == AX88140) {
-+ break;
-+ case AX88140: case AX88141:
- tp->csr6 = tp->mii_cnt ? 0x00040100 : 0x00000100;
-- } else
-+ break;
-+ default:
- select_media(dev, 1);
--
-- /* Start the chip's Tx to process setup frame. */
-- outl(tp->csr6, ioaddr + CSR6);
-- outl(tp->csr6 | 0x2000, ioaddr + CSR6);
--
-- dev->tbusy = 0;
-- tp->interrupt = 0;
-- dev->start = 1;
--
-- /* Enable interrupts by setting the interrupt mask. */
-- outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR5);
-- outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7);
-- outl(tp->csr6 | 0x2002, ioaddr + CSR6);
-- outl(0, ioaddr + CSR2); /* Rx poll demand */
--
-- if (tulip_debug > 2) {
-- printk(KERN_DEBUG "%s: Done tulip_open(), CSR0 %8.8x, CSR5 %8.8x CSR6 %8.8x.\n",
-- dev->name, inl(ioaddr + CSR0), inl(ioaddr + CSR5),
-- inl(ioaddr + CSR6));
- }
-- /* Set the timer to switch to check for link beat and perhaps switch
-- to an alternate media type. */
-- init_timer(&tp->timer);
-- tp->timer.expires = RUN_AT(next_tick);
-- tp->timer.data = (unsigned long)dev;
-- tp->timer.function = tulip_tbl[tp->chip_id].media_timer;
-- add_timer(&tp->timer);
--
-- return 0;
- }
-
--/* Set up the transceiver control registers for the selected media type. */
--static void select_media(struct device *dev, int startup)
-+/* Set up the transceiver control registers for the selected media type.
-+ STARTUP indicates to reset the transceiver. It is set to '2' for
-+ the initial card detection, and '1' during resume or open().
-+*/
-+static void select_media(struct net_device *dev, int startup)
- {
- long ioaddr = dev->base_addr;
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
-@@ -1619,9 +1728,12 @@
- if (mtable) {
- struct medialeaf *mleaf = &mtable->mleaf[tp->cur_index];
- unsigned char *p = mleaf->leafdata;
-+ if (tp->msg_level & NETIF_MSG_LINK)
-+ printk(KERN_DEBUG "%s: Media table type %d.\n",
-+ dev->name, mleaf->type);
- switch (mleaf->type) {
- case 0: /* 21140 non-MII xcvr. */
-- if (tulip_debug > 1)
-+ if (tp->msg_level & NETIF_MSG_LINK)
- printk(KERN_DEBUG "%s: Using a 21140 non-MII transceiver"
- " with control setting %2.2x.\n",
- dev->name, p[1]);
-@@ -1637,20 +1749,20 @@
- for (i = 0; i < 5; i++)
- setup[i] = get_u16(&p[i*2 + 1]);
-
-- dev->if_port = p[0] & 15;
-+ dev->if_port = p[0] & MEDIA_MASK;
- if (media_cap[dev->if_port] & MediaAlwaysFD)
- tp->full_duplex = 1;
-
- if (startup && mtable->has_reset) {
-- struct medialeaf *rleaf = &mtable->mleaf[mtable->has_reset];
-+ struct medialeaf *rleaf = &mtable->mleaf[mtable->has_reset-1];
- unsigned char *rst = rleaf->leafdata;
-- if (tulip_debug > 1)
-+ if (tp->msg_level & NETIF_MSG_LINK)
- printk(KERN_DEBUG "%s: Resetting the transceiver.\n",
- dev->name);
- for (i = 0; i < rst[0]; i++)
- outl(get_u16(rst + 1 + (i<<1)) << 16, ioaddr + CSR15);
- }
-- if (tulip_debug > 1)
-+ if (tp->msg_level & NETIF_MSG_LINK)
- printk(KERN_DEBUG "%s: 21143 non-MII %s transceiver control "
- "%4.4x/%4.4x.\n",
- dev->name, medianame[dev->if_port], setup[0], setup[1]);
-@@ -1666,7 +1778,7 @@
- outl(csr13val, ioaddr + CSR13);
- } else {
- csr13val = 1;
-- csr14val = 0x0003FF7F;
-+ csr14val = 0x0003FFFF;
- csr15dir = (setup[0]<<16) | 0x0008;
- csr15val = (setup[1]<<16) | 0x0008;
- if (dev->if_port <= 4)
-@@ -1679,11 +1791,11 @@
- outl(csr15val, ioaddr + CSR15); /* Data */
- if (startup) outl(csr13val, ioaddr + CSR13);
- }
-- if (tulip_debug > 1)
-+ if (tp->msg_level & NETIF_MSG_LINK)
- printk(KERN_DEBUG "%s: Setting CSR15 to %8.8x/%8.8x.\n",
- dev->name, csr15dir, csr15val);
- if (mleaf->type == 4)
-- new_csr6 = 0x82020000 | ((setup[2] & 0x71) << 18);
-+ new_csr6 = 0x820A0000 | ((setup[2] & 0x71) << 18);
- else
- new_csr6 = 0x82420000;
- break;
-@@ -1692,7 +1804,6 @@
- int phy_num = p[0];
- int init_length = p[1];
- u16 *misc_info;
-- u16 to_advertise;
-
- dev->if_port = 11;
- new_csr6 = 0x020E0000;
-@@ -1719,13 +1830,15 @@
- for (i = 0; i < init_length; i++)
- outl(init_sequence[i], ioaddr + CSR12);
- }
-- to_advertise = (get_u16(&misc_info[1]) & tp->to_advertise) | 1;
-- tp->advertising[phy_num] = to_advertise;
-- if (tulip_debug > 1)
-- printk(KERN_DEBUG "%s: Advertising %4.4x on PHY %d (%d).\n",
-- dev->name, to_advertise, phy_num, tp->phys[phy_num]);
-- /* Bogus: put in by a committee? */
-- mdio_write(dev, tp->phys[phy_num], 4, to_advertise);
-+ tp->advertising[phy_num] = get_u16(&misc_info[1]) | 1;
-+ if (startup < 2) {
-+ if (tp->mii_advertise == 0)
-+ tp->mii_advertise = tp->advertising[phy_num];
-+ if (tp->msg_level & NETIF_MSG_LINK)
-+ printk(KERN_DEBUG "%s: Advertising %4.4x on MII %d.\n",
-+ dev->name, tp->mii_advertise, tp->phys[phy_num]);
-+ mdio_write(dev, tp->phys[phy_num], 4, tp->mii_advertise);
-+ }
- break;
- }
- default:
-@@ -1733,16 +1846,16 @@
- dev->name, mleaf->type);
- new_csr6 = 0x020E0000;
- }
-- if (tulip_debug > 1)
-+ if (tp->msg_level & NETIF_MSG_LINK)
- printk(KERN_DEBUG "%s: Using media type %s, CSR12 is %2.2x.\n",
- dev->name, medianame[dev->if_port],
-- inl(ioaddr + CSR12) & 0xff);
-+ (int)inl(ioaddr + CSR12) & 0xff);
- } else if (tp->chip_id == DC21041) {
- int port = dev->if_port <= 4 ? dev->if_port : 0;
-- if (tulip_debug > 1)
-+ if (tp->msg_level & NETIF_MSG_LINK)
- printk(KERN_DEBUG "%s: 21041 using media %s, CSR12 is %4.4x.\n",
- dev->name, medianame[port == 3 ? 12: port],
-- inl(ioaddr + CSR12));
-+ (int)inl(ioaddr + CSR12));
- outl(0x00000000, ioaddr + CSR13); /* Reset the serial interface */
- outl(t21041_csr14[port], ioaddr + CSR14);
- outl(t21041_csr15[port], ioaddr + CSR15);
-@@ -1751,9 +1864,10 @@
- } else if (tp->chip_id == LC82C168) {
- if (startup && ! tp->medialock)
- dev->if_port = tp->mii_cnt ? 11 : 0;
-- if (tulip_debug > 1)
-+ if (tp->msg_level & NETIF_MSG_LINK)
- printk(KERN_DEBUG "%s: PNIC PHY status is %3.3x, media %s.\n",
-- dev->name, inl(ioaddr + 0xB8), medianame[dev->if_port]);
-+ dev->name, (int)inl(ioaddr + 0xB8),
-+ medianame[dev->if_port]);
- if (tp->mii_cnt) {
- new_csr6 = 0x810C0000;
- outl(0x0001, ioaddr + CSR15);
-@@ -1777,7 +1891,7 @@
- } else if (tp->chip_id == DC21040) { /* 21040 */
- /* Turn on the xcvr interface. */
- int csr12 = inl(ioaddr + CSR12);
-- if (tulip_debug > 1)
-+ if (tp->msg_level & NETIF_MSG_LINK)
- printk(KERN_DEBUG "%s: 21040 media type is %s, CSR12 is %2.2x.\n",
- dev->name, medianame[dev->if_port], csr12);
- if (media_cap[dev->if_port] & MediaAlwaysFD)
-@@ -1800,17 +1914,18 @@
- if (media_cap[dev->if_port] & MediaIsMII) {
- new_csr6 = 0x020E0000;
- } else if (media_cap[dev->if_port] & MediaIsFx) {
-- new_csr6 = 0x028600000;
-+ new_csr6 = 0x02860000;
- } else
-- new_csr6 = 0x038600000;
-- if (tulip_debug > 1)
-+ new_csr6 = 0x038E0000;
-+ if (tp->msg_level & NETIF_MSG_LINK)
- printk(KERN_DEBUG "%s: No media description table, assuming "
- "%s transceiver, CSR12 %2.2x.\n",
- dev->name, medianame[dev->if_port],
-- inl(ioaddr + CSR12));
-+ (int)inl(ioaddr + CSR12));
- }
-
-- tp->csr6 = new_csr6 | (tp->csr6 & 0xfdff) | (tp->full_duplex ? 0x0200 : 0);
-+ tp->csr6 = new_csr6 | (tp->csr6 & 0xfdff) |
-+ (tp->full_duplex ? FullDuplex : 0);
- return;
- }
-
-@@ -1820,7 +1935,7 @@
- Return 0 if everything is OK.
- Return < 0 if the transceiver is missing or has no link beat.
- */
--static int check_duplex(struct device *dev)
-+static int check_duplex(struct net_device *dev)
- {
- long ioaddr = dev->base_addr;
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
-@@ -1828,36 +1943,37 @@
-
- if (tp->full_duplex_lock)
- return 0;
-- mii_reg1 = mdio_read(dev, tp->phys[0], 1);
- mii_reg5 = mdio_read(dev, tp->phys[0], 5);
-- if (tulip_debug > 1)
-- printk(KERN_INFO "%s: MII status %4.4x, Link partner report "
-- "%4.4x.\n", dev->name, mii_reg1, mii_reg5);
-- if (mii_reg1 == 0xffff)
-+ negotiated = mii_reg5 & tp->mii_advertise;
-+
-+ if (tp->msg_level & NETIF_MSG_TIMER)
-+ printk(KERN_INFO "%s: MII link partner %4.4x, negotiated %4.4x.\n",
-+ dev->name, mii_reg5, negotiated);
-+ if (mii_reg5 == 0xffff)
- return -2;
-- if ((mii_reg1 & 0x0004) == 0) {
-+ if ((mii_reg5 & 0x4000) == 0 && /* No negotiation. */
-+ ((mii_reg1 = mdio_read(dev, tp->phys[0], 1)) & 0x0004) == 0) {
- int new_reg1 = mdio_read(dev, tp->phys[0], 1);
- if ((new_reg1 & 0x0004) == 0) {
-- if (tulip_debug > 1)
-+ if (tp->msg_level & NETIF_MSG_TIMER)
- printk(KERN_INFO "%s: No link beat on the MII interface,"
- " status %4.4x.\n", dev->name, new_reg1);
- return -1;
- }
- }
-- negotiated = mii_reg5 & tp->advertising[0];
- duplex = ((negotiated & 0x0300) == 0x0100
- || (negotiated & 0x00C0) == 0x0040);
- /* 100baseTx-FD or 10T-FD, but not 100-HD */
- if (tp->full_duplex != duplex) {
- tp->full_duplex = duplex;
-- if (negotiated & 0x038) /* 100mbps. */
-+ if (negotiated & 0x0380) /* 100mbps. */
- tp->csr6 &= ~0x00400000;
-- if (tp->full_duplex) tp->csr6 |= 0x0200;
-- else tp->csr6 &= ~0x0200;
-- outl(tp->csr6 | 0x0002, ioaddr + CSR6);
-- outl(tp->csr6 | 0x2002, ioaddr + CSR6);
-- if (tulip_debug > 0)
-- printk(KERN_INFO "%s: Setting %s-duplex based on MII"
-+ if (tp->full_duplex) tp->csr6 |= FullDuplex;
-+ else tp->csr6 &= ~FullDuplex;
-+ outl(tp->csr6 | RxOn, ioaddr + CSR6);
-+ outl(tp->csr6 | TxOn | RxOn, ioaddr + CSR6);
-+ if (tp->msg_level & NETIF_MSG_LINK)
-+ printk(KERN_INFO "%s: Setting %s-duplex based on MII "
- "#%d link partner capability of %4.4x.\n",
- dev->name, tp->full_duplex ? "full" : "half",
- tp->phys[0], mii_reg5);
-@@ -1868,31 +1984,32 @@
-
- static void tulip_timer(unsigned long data)
- {
-- struct device *dev = (struct device *)data;
-+ struct net_device *dev = (struct net_device *)data;
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- long ioaddr = dev->base_addr;
- u32 csr12 = inl(ioaddr + CSR12);
- int next_tick = 2*HZ;
-
-- if (tulip_debug > 2) {
-+ if (tp->msg_level & NETIF_MSG_TIMER)
- printk(KERN_DEBUG "%s: Media selection tick, %s, status %8.8x mode"
- " %8.8x SIA %8.8x %8.8x %8.8x %8.8x.\n",
-- dev->name, medianame[dev->if_port], inl(ioaddr + CSR5),
-- inl(ioaddr + CSR6), csr12, inl(ioaddr + CSR13),
-- inl(ioaddr + CSR14), inl(ioaddr + CSR15));
-- }
-+ dev->name, medianame[dev->if_port], (int)inl(ioaddr + CSR5),
-+ (int)inl(ioaddr + CSR6), csr12, (int)inl(ioaddr + CSR13),
-+ (int)inl(ioaddr + CSR14), (int)inl(ioaddr + CSR15));
-+
- switch (tp->chip_id) {
- case DC21040:
-- if (!tp->medialock && csr12 & 0x0002) { /* Network error */
-- printk(KERN_INFO "%s: No link beat found.\n",
-- dev->name);
-+ if (!tp->medialock && (csr12 & 0x0002)) { /* Network error */
-+ if (tp->msg_level & NETIF_MSG_TIMER)
-+ printk(KERN_INFO "%s: No link beat found.\n",
-+ dev->name);
- dev->if_port = (dev->if_port == 2 ? 0 : 2);
- select_media(dev, 0);
- dev->trans_start = jiffies;
- }
- break;
- case DC21041:
-- if (tulip_debug > 2)
-+ if (tp->msg_level & NETIF_MSG_TIMER)
- printk(KERN_DEBUG "%s: 21041 media tick CSR12 %8.8x.\n",
- dev->name, csr12);
- if (tp->medialock) break;
-@@ -1905,8 +2022,10 @@
- dev->if_port = 2;
- else
- dev->if_port = 1;
-- printk(KERN_INFO "%s: No 21041 10baseT link beat, Media switched to %s.\n",
-- dev->name, medianame[dev->if_port]);
-+ if (tp->msg_level & NETIF_MSG_LINK)
-+ printk(KERN_INFO "%s: No 21041 10baseT link beat, Media "
-+ "switched to %s.\n",
-+ dev->name, medianame[dev->if_port]);
- outl(0, ioaddr + CSR13); /* Reset */
- outl(t21041_csr14[dev->if_port], ioaddr + CSR14);
- outl(t21041_csr15[dev->if_port], ioaddr + CSR15);
-@@ -1921,8 +2040,9 @@
- next_tick = (30*HZ); /* 30 sec. */
- tp->mediasense = 0;
- } else if ((csr12 & 0x0004) == 0) {
-- printk(KERN_INFO "%s: 21041 media switched to 10baseT.\n",
-- dev->name);
-+ if (tp->msg_level & NETIF_MSG_LINK)
-+ printk(KERN_INFO "%s: 21041 media switched to 10baseT.\n",
-+ dev->name);
- dev->if_port = 0;
- select_media(dev, 0);
- next_tick = (24*HZ)/10; /* 2.4 sec. */
-@@ -1943,10 +2063,10 @@
- /* Not much that can be done.
- Assume this a generic MII or SYM transceiver. */
- next_tick = 60*HZ;
-- if (tulip_debug > 2)
-+ if (tp->msg_level & NETIF_MSG_TIMER)
- printk(KERN_DEBUG "%s: network media monitor CSR6 %8.8x "
- "CSR12 0x%2.2x.\n",
-- dev->name, inl(ioaddr + CSR6), csr12 & 0xff);
-+ dev->name, (int)inl(ioaddr + CSR6), csr12 & 0xff);
- break;
- }
- mleaf = &tp->mtable->mleaf[tp->cur_index];
-@@ -1957,7 +2077,7 @@
- int offset = mleaf->type == 4 ? 5 : 2;
- s8 bitnum = p[offset];
- if (p[offset+1] & 0x80) {
-- if (tulip_debug > 1)
-+ if (tp->msg_level & NETIF_MSG_TIMER)
- printk(KERN_DEBUG"%s: Transceiver monitor tick "
- "CSR12=%#2.2x, no media sense.\n",
- dev->name, csr12);
-@@ -1967,7 +2087,7 @@
- }
- break;
- }
-- if (tulip_debug > 2)
-+ if (tp->msg_level & NETIF_MSG_TIMER)
- printk(KERN_DEBUG "%s: Transceiver monitor tick: CSR12=%#2.2x"
- " bit %d is %d, expecting %d.\n",
- dev->name, csr12, (bitnum >> 1) & 7,
-@@ -1976,9 +2096,9 @@
- /* Check that the specified bit has the proper value. */
- if ((bitnum < 0) !=
- ((csr12 & (1 << ((bitnum >> 1) & 7))) != 0)) {
-- if (tulip_debug > 1)
-- printk(KERN_DEBUG "%s: Link beat detected for %s.\n", dev->name,
-- medianame[mleaf->media]);
-+ if (tp->msg_level & NETIF_MSG_LINK)
-+ printk(KERN_DEBUG "%s: Link beat detected for %s.\n",
-+ dev->name, medianame[mleaf->media & MEDIA_MASK]);
- if ((p[2] & 0x61) == 0x01) /* Bogus Znyx board. */
- goto actually_mii;
- break;
-@@ -1993,15 +2113,15 @@
- dev->if_port = tp->mtable->mleaf[tp->cur_index].media;
- if (media_cap[dev->if_port] & MediaIsFD)
- goto select_next_media; /* Skip FD entries. */
-- if (tulip_debug > 1)
-+ if (tp->msg_level & NETIF_MSG_LINK)
- printk(KERN_DEBUG "%s: No link beat on media %s,"
- " trying transceiver type %s.\n",
-- dev->name, medianame[mleaf->media & 15],
-+ dev->name, medianame[mleaf->media & MEDIA_MASK],
- medianame[tp->mtable->mleaf[tp->cur_index].media]);
- select_media(dev, 0);
- /* Restart the transmit process. */
-- outl(tp->csr6 | 0x0002, ioaddr + CSR6);
-- outl(tp->csr6 | 0x2002, ioaddr + CSR6);
-+ outl(tp->csr6 | RxOn, ioaddr + CSR6);
-+ outl(tp->csr6 | TxOn | RxOn, ioaddr + CSR6);
- next_tick = (24*HZ)/10;
- break;
- }
-@@ -2017,45 +2137,45 @@
- }
- break;
- }
-- tp->timer.expires = RUN_AT(next_tick);
-+ tp->timer.expires = jiffies + next_tick;
- add_timer(&tp->timer);
- }
-
--/* Handle the 21143 uniquely: do autoselect with NWay, not the EEPROM list
-- of available transceivers. */
--static void t21142_timer(unsigned long data)
-+/* Handle internal NWay transceivers uniquely.
-+ These exist on the 21041, 21143 (in SYM mode) and the PNIC2.
-+ */
-+static void nway_timer(unsigned long data)
- {
-- struct device *dev = (struct device *)data;
-+ struct net_device *dev = (struct net_device *)data;
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- long ioaddr = dev->base_addr;
- int csr12 = inl(ioaddr + CSR12);
- int next_tick = 60*HZ;
- int new_csr6 = 0;
-
-- if (tulip_debug > 2)
-- printk(KERN_INFO"%s: 21143 negotiation status %8.8x, %s.\n",
-+ if (tp->msg_level & NETIF_MSG_TIMER)
-+ printk(KERN_INFO"%s: N-Way autonegotiation status %8.8x, %s.\n",
- dev->name, csr12, medianame[dev->if_port]);
- if (media_cap[dev->if_port] & MediaIsMII) {
- check_duplex(dev);
-- next_tick = 60*HZ;
- } else if (tp->nwayset) {
-- /* Don't screw up a negotiated session! */
-- if (tulip_debug > 1)
-+ /* Do not screw up a negotiated session! */
-+ if (tp->msg_level & NETIF_MSG_TIMER)
- printk(KERN_INFO"%s: Using NWay-set %s media, csr12 %8.8x.\n",
- dev->name, medianame[dev->if_port], csr12);
- } else if (tp->medialock) {
- ;
- } else if (dev->if_port == 3) {
- if (csr12 & 2) { /* No 100mbps link beat, revert to 10mbps. */
-- if (tulip_debug > 1)
-+ if (tp->msg_level & NETIF_MSG_LINK)
- printk(KERN_INFO"%s: No 21143 100baseTx link beat, %8.8x, "
- "trying NWay.\n", dev->name, csr12);
-- t21142_start_nway(dev);
-+ nway_start(dev);
- next_tick = 3*HZ;
- }
- } else if ((csr12 & 0x7000) != 0x5000) {
- /* Negotiation failed. Search media types. */
-- if (tulip_debug > 1)
-+ if (tp->msg_level & NETIF_MSG_LINK)
- printk(KERN_INFO"%s: 21143 negotiation failed, status %8.8x.\n",
- dev->name, csr12);
- if (!(csr12 & 4)) { /* 10mbps link beat good. */
-@@ -2074,15 +2194,15 @@
- outw(8, ioaddr + CSR15);
- outl(1, ioaddr + CSR13);
- }
-- if (tulip_debug > 1)
-+ if (tp->msg_level & NETIF_MSG_LINK)
- printk(KERN_INFO"%s: Testing new 21143 media %s.\n",
- dev->name, medianame[dev->if_port]);
-- if (new_csr6 != (tp->csr6 & ~0x00D5)) {
-- tp->csr6 &= 0x00D5;
-+ if (new_csr6 != (tp->csr6 & ~0x20D7)) {
-+ tp->csr6 &= 0x20D7;
- tp->csr6 |= new_csr6;
- outl(0x0301, ioaddr + CSR12);
-- outl(tp->csr6 | 0x0002, ioaddr + CSR6);
-- outl(tp->csr6 | 0x2002, ioaddr + CSR6);
-+ outl(tp->csr6 | RxOn, ioaddr + CSR6);
-+ outl(tp->csr6 | TxOn | RxOn, ioaddr + CSR6);
- }
- next_tick = 3*HZ;
- }
-@@ -2093,49 +2213,69 @@
- tulip_tx_timeout(dev);
- }
-
-- tp->timer.expires = RUN_AT(next_tick);
-+ tp->timer.expires = jiffies + next_tick;
- add_timer(&tp->timer);
- }
-
--static void t21142_start_nway(struct device *dev)
-+static void nway_start(struct net_device *dev)
- {
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- long ioaddr = dev->base_addr;
-- int csr14 = ((tp->to_advertise & 0x0780) << 9) |
-- ((tp->to_advertise&0x0020)<<1) | 0xffbf;
-+ int csr14 = ((tp->sym_advertise & 0x0780) << 9) |
-+ ((tp->sym_advertise&0x0020)<<1) | 0xffbf;
-
- dev->if_port = 0;
- tp->nway = tp->mediasense = 1;
- tp->nwayset = tp->lpar = 0;
-- if (debug > 1)
-- printk(KERN_DEBUG "%s: Restarting 21143 autonegotiation, %8.8x.\n",
-- dev->name, csr14);
-+ if (tp->chip_id == PNIC2) {
-+ tp->csr6 = 0x01000000 | (tp->sym_advertise & 0x0040 ? FullDuplex : 0);
-+ return;
-+ }
-+ if (tp->msg_level & NETIF_MSG_LINK)
-+ printk(KERN_DEBUG "%s: Restarting internal NWay autonegotiation, "
-+ "%8.8x.\n", dev->name, csr14);
- outl(0x0001, ioaddr + CSR13);
- outl(csr14, ioaddr + CSR14);
-- tp->csr6 = 0x82420000 | (tp->to_advertise & 0x0040 ? 0x0200 : 0);
-+ tp->csr6 = 0x82420000 | (tp->sym_advertise & 0x0040 ? FullDuplex : 0)
-+ | (tp->csr6 & 0x20ff);
- outl(tp->csr6, ioaddr + CSR6);
- if (tp->mtable && tp->mtable->csr15dir) {
- outl(tp->mtable->csr15dir, ioaddr + CSR15);
- outl(tp->mtable->csr15val, ioaddr + CSR15);
-- } else
-+ } else if (tp->chip_id != PNIC2)
- outw(0x0008, ioaddr + CSR15);
-- outl(0x1301, ioaddr + CSR12); /* Trigger NWAY. */
-+ if (tp->chip_id == DC21041) /* Trigger NWAY. */
-+ outl(0xEF01, ioaddr + CSR12);
-+ else
-+ outl(0x1301, ioaddr + CSR12);
- }
-
--static void t21142_lnk_change(struct device *dev, int csr5)
-+static void nway_lnk_change(struct net_device *dev, int csr5)
- {
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- long ioaddr = dev->base_addr;
- int csr12 = inl(ioaddr + CSR12);
-
-- if (tulip_debug > 1)
-+ if (tp->chip_id == PNIC2) {
-+ if (tp->msg_level & NETIF_MSG_LINK)
-+ printk(KERN_INFO"%s: PNIC-2 link status changed, CSR5/12/14 %8.8x"
-+ " %8.8x, %8.8x.\n",
-+ dev->name, csr12, csr5, (int)inl(ioaddr + CSR14));
-+ dev->if_port = 5;
-+ tp->lpar = csr12 >> 16;
-+ tp->nwayset = 1;
-+ tp->csr6 = 0x01000000 | (tp->csr6 & 0xffff);
-+ outl(tp->csr6, ioaddr + CSR6);
-+ return;
-+ }
-+ if (tp->msg_level & NETIF_MSG_LINK)
- printk(KERN_INFO"%s: 21143 link status interrupt %8.8x, CSR5 %x, "
-- "%8.8x.\n", dev->name, csr12, csr5, inl(ioaddr + CSR14));
-+ "%8.8x.\n", dev->name, csr12, csr5, (int)inl(ioaddr + CSR14));
-
- /* If NWay finished and we have a negotiated partner capability. */
- if (tp->nway && !tp->nwayset && (csr12 & 0x7000) == 0x5000) {
- int setup_done = 0;
-- int negotiated = tp->to_advertise & (csr12 >> 16);
-+ int negotiated = tp->sym_advertise & (csr12 >> 16);
- tp->lpar = csr12 >> 16;
- tp->nwayset = 1;
- if (negotiated & 0x0100) dev->if_port = 5;
-@@ -2144,16 +2284,16 @@
- else if (negotiated & 0x0020) dev->if_port = 0;
- else {
- tp->nwayset = 0;
-- if ((csr12 & 2) == 0 && (tp->to_advertise & 0x0180))
-+ if ((csr12 & 2) == 0 && (tp->sym_advertise & 0x0180))
- dev->if_port = 3;
- }
- tp->full_duplex = (media_cap[dev->if_port] & MediaAlwaysFD) ? 1:0;
-
-- if (tulip_debug > 1) {
-+ if (tp->msg_level & NETIF_MSG_LINK) {
- if (tp->nwayset)
- printk(KERN_INFO "%s: Switching to %s based on link "
- "negotiation %4.4x & %4.4x = %4.4x.\n",
-- dev->name, medianame[dev->if_port], tp->to_advertise,
-+ dev->name, medianame[dev->if_port], tp->sym_advertise,
- tp->lpar, negotiated);
- else
- printk(KERN_INFO "%s: Autonegotiation failed, using %s,"
-@@ -2172,86 +2312,86 @@
- }
- }
- if ( ! setup_done) {
-- tp->csr6 = dev->if_port & 1 ? 0x83860000 : 0x82420000;
-+ tp->csr6 = (dev->if_port & 1 ? 0x838E0000 : 0x82420000)
-+ | (tp->csr6 & 0x20ff);
- if (tp->full_duplex)
-- tp->csr6 |= 0x0200;
-+ tp->csr6 |= FullDuplex;
- outl(1, ioaddr + CSR13);
- }
--#if 0 /* Restart shouldn't be needed. */
-+#if 0 /* Restart should not be needed. */
- outl(tp->csr6 | 0x0000, ioaddr + CSR6);
-- if (debug > 2)
-+ if (tp->msg_level & NETIF_MSG_LINK)
- printk(KERN_DEBUG "%s: Restarting Tx and Rx, CSR5 is %8.8x.\n",
- dev->name, inl(ioaddr + CSR5));
- #endif
-- outl(tp->csr6 | 0x2002, ioaddr + CSR6);
-- if (debug > 2)
-+ outl(tp->csr6 | TxOn | RxOn, ioaddr + CSR6);
-+ if (tp->msg_level & NETIF_MSG_LINK)
- printk(KERN_DEBUG "%s: Setting CSR6 %8.8x/%x CSR12 %8.8x.\n",
-- dev->name, tp->csr6, inl(ioaddr + CSR6),
-- inl(ioaddr + CSR12));
-+ dev->name, tp->csr6, (int)inl(ioaddr + CSR6),
-+ (int)inl(ioaddr + CSR12));
- } else if ((tp->nwayset && (csr5 & 0x08000000)
- && (dev->if_port == 3 || dev->if_port == 5)
- && (csr12 & 2) == 2) ||
- (tp->nway && (csr5 & (TPLnkFail)))) {
- /* Link blew? Maybe restart NWay. */
- del_timer(&tp->timer);
-- t21142_start_nway(dev);
-- tp->timer.expires = RUN_AT(3*HZ);
-+ nway_start(dev);
-+ tp->timer.expires = jiffies + 3*HZ;
- add_timer(&tp->timer);
- } else if (dev->if_port == 3 || dev->if_port == 5) {
-- if (tulip_debug > 1)
-+ if (tp->msg_level & NETIF_MSG_LINK) /* TIMER? */
- printk(KERN_INFO"%s: 21143 %s link beat %s.\n",
- dev->name, medianame[dev->if_port],
- (csr12 & 2) ? "failed" : "good");
- if ((csr12 & 2) && ! tp->medialock) {
- del_timer(&tp->timer);
-- t21142_start_nway(dev);
-- tp->timer.expires = RUN_AT(3*HZ);
-+ nway_start(dev);
-+ tp->timer.expires = jiffies + 3*HZ;
- add_timer(&tp->timer);
-- }
-+ } else if (dev->if_port == 5)
-+ outl(inl(ioaddr + CSR14) & ~0x080, ioaddr + CSR14);
- } else if (dev->if_port == 0 || dev->if_port == 4) {
- if ((csr12 & 4) == 0)
- printk(KERN_INFO"%s: 21143 10baseT link beat good.\n",
- dev->name);
- } else if (!(csr12 & 4)) { /* 10mbps link beat good. */
-- if (tulip_debug)
-+ if (tp->msg_level & NETIF_MSG_LINK)
- printk(KERN_INFO"%s: 21143 10mbps sensed media.\n",
- dev->name);
- dev->if_port = 0;
- } else if (tp->nwayset) {
-- if (tulip_debug)
-+ if (tp->msg_level & NETIF_MSG_LINK)
- printk(KERN_INFO"%s: 21143 using NWay-set %s, csr6 %8.8x.\n",
- dev->name, medianame[dev->if_port], tp->csr6);
- } else { /* 100mbps link beat good. */
-- if (tulip_debug)
-+ if (tp->msg_level & NETIF_MSG_LINK)
- printk(KERN_INFO"%s: 21143 100baseTx sensed media.\n",
- dev->name);
- dev->if_port = 3;
-- tp->csr6 = 0x83860000;
-+ tp->csr6 = 0x838E0000 | (tp->csr6 & 0x20ff);
- outl(0x0003FF7F, ioaddr + CSR14);
- outl(0x0301, ioaddr + CSR12);
-- outl(tp->csr6 | 0x0002, ioaddr + CSR6);
-- outl(tp->csr6 | 0x2002, ioaddr + CSR6);
-+ outl(tp->csr6 | RxOn, ioaddr + CSR6);
-+ outl(tp->csr6 | RxOn | TxOn, ioaddr + CSR6);
- }
- }
-
- static void mxic_timer(unsigned long data)
- {
-- struct device *dev = (struct device *)data;
-+ struct net_device *dev = (struct net_device *)data;
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- long ioaddr = dev->base_addr;
- int next_tick = 60*HZ;
-
-- if (tulip_debug > 3) {
-+ if (tp->msg_level & NETIF_MSG_TIMER) {
- printk(KERN_INFO"%s: MXIC negotiation status %8.8x.\n", dev->name,
-- inl(ioaddr + CSR12));
-- }
-- if (next_tick) {
-- tp->timer.expires = RUN_AT(next_tick);
-- add_timer(&tp->timer);
-+ (int)inl(ioaddr + CSR12));
- }
-+ tp->timer.expires = jiffies + next_tick;
-+ add_timer(&tp->timer);
- }
-
--static void pnic_do_nway(struct device *dev)
-+static void pnic_do_nway(struct net_device *dev)
- {
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- long ioaddr = dev->base_addr;
-@@ -2270,26 +2410,27 @@
- outl(0x1F868, ioaddr + 0xB8);
- if (phy_reg & 0x30000000) {
- tp->full_duplex = 1;
-- new_csr6 |= 0x00000200;
-+ new_csr6 |= FullDuplex;
- }
-- if (tulip_debug > 1)
-+ if (tp->msg_level & NETIF_MSG_LINK)
- printk(KERN_DEBUG "%s: PNIC autonegotiated status %8.8x, %s.\n",
- dev->name, phy_reg, medianame[dev->if_port]);
- if (tp->csr6 != new_csr6) {
- tp->csr6 = new_csr6;
-- outl(tp->csr6 | 0x0002, ioaddr + CSR6); /* Restart Tx */
-- outl(tp->csr6 | 0x2002, ioaddr + CSR6);
-+ outl(tp->csr6 | RxOn, ioaddr + CSR6); /* Restart Tx */
-+ outl(tp->csr6 | TxOn | RxOn, ioaddr + CSR6);
- dev->trans_start = jiffies;
- }
- }
- }
--static void pnic_lnk_change(struct device *dev, int csr5)
-+
-+static void pnic_lnk_change(struct net_device *dev, int csr5)
- {
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- long ioaddr = dev->base_addr;
- int phy_reg = inl(ioaddr + 0xB8);
-
-- if (tulip_debug > 1)
-+ if (tp->msg_level & NETIF_MSG_LINK)
- printk(KERN_DEBUG "%s: PNIC link changed state %8.8x, CSR5 %8.8x.\n",
- dev->name, phy_reg, csr5);
- if (inl(ioaddr + CSR5) & TPLnkFail) {
-@@ -2308,7 +2449,7 @@
- }
- static void pnic_timer(unsigned long data)
- {
-- struct device *dev = (struct device *)data;
-+ struct net_device *dev = (struct net_device *)data;
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- long ioaddr = dev->base_addr;
- int next_tick = 60*HZ;
-@@ -2322,7 +2463,7 @@
- int phy_reg = inl(ioaddr + 0xB8);
- int csr5 = inl(ioaddr + CSR5);
-
-- if (tulip_debug > 1)
-+ if (tp->msg_level & NETIF_MSG_TIMER)
- printk(KERN_DEBUG "%s: PNIC timer PHY status %8.8x, %s "
- "CSR5 %8.8x.\n",
- dev->name, phy_reg, medianame[dev->if_port], csr5);
-@@ -2334,11 +2475,11 @@
- pnic_do_nway(dev);
- next_tick = 60*HZ;
- } else if (csr5 & TPLnkFail) { /* 100baseTx link beat */
-- if (tulip_debug > 1)
-+ if (tp->msg_level & NETIF_MSG_LINK)
- printk(KERN_DEBUG "%s: %s link beat failed, CSR12 %4.4x, "
- "CSR5 %8.8x, PHY %3.3x.\n",
- dev->name, medianame[dev->if_port], csr12,
-- inl(ioaddr + CSR5), inl(ioaddr + 0xB8));
-+ (int)inl(ioaddr + CSR5), (int)inl(ioaddr + 0xB8));
- next_tick = 3*HZ;
- if (tp->medialock) {
- } else if (tp->nwayset && (dev->if_port & 1)) {
-@@ -2356,10 +2497,10 @@
- }
- if (tp->csr6 != new_csr6) {
- tp->csr6 = new_csr6;
-- outl(tp->csr6 | 0x0002, ioaddr + CSR6); /* Restart Tx */
-- outl(tp->csr6 | 0x2002, ioaddr + CSR6);
-+ outl(tp->csr6 | RxOn, ioaddr + CSR6); /* Restart Tx */
-+ outl(tp->csr6 | RxOn | TxOn, ioaddr + CSR6);
- dev->trans_start = jiffies;
-- if (tulip_debug > 1)
-+ if (tp->msg_level & NETIF_MSG_LINK)
- printk(KERN_INFO "%s: Changing PNIC configuration to %s "
- "%s-duplex, CSR6 %8.8x.\n",
- dev->name, medianame[dev->if_port],
-@@ -2367,36 +2508,45 @@
- }
- }
- }
-- tp->timer.expires = RUN_AT(next_tick);
-+ tp->timer.expires = jiffies + next_tick;
- add_timer(&tp->timer);
- }
-
- static void comet_timer(unsigned long data)
- {
-- struct device *dev = (struct device *)data;
-+ struct net_device *dev = (struct net_device *)data;
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
-- long ioaddr = dev->base_addr;
- int next_tick = 60*HZ;
-
-- if (tulip_debug > 1)
-+ if (tp->msg_level & NETIF_MSG_TIMER)
- printk(KERN_DEBUG "%s: Comet link status %4.4x partner capability "
- "%4.4x.\n",
-- dev->name, inl(ioaddr + 0xB8), inl(ioaddr + 0xC8));
-- tp->timer.expires = RUN_AT(next_tick);
-+ dev->name, mdio_read(dev, tp->phys[0], 1),
-+ mdio_read(dev, tp->phys[0], 5));
-+ check_duplex(dev);
-+ tp->timer.expires = jiffies + next_tick;
- add_timer(&tp->timer);
- }
-
--static void tulip_tx_timeout(struct device *dev)
-+static void tulip_tx_timeout(struct net_device *dev)
- {
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- long ioaddr = dev->base_addr;
-
- if (media_cap[dev->if_port] & MediaIsMII) {
- /* Do nothing -- the media monitor should handle this. */
-- if (tulip_debug > 1)
-- printk(KERN_WARNING "%s: Transmit timeout using MII device.\n",
-- dev->name);
-- } else if (tp->chip_id == DC21040) {
-+ int mii_bmsr = mdio_read(dev, tp->phys[0], 1);
-+ if (tp->msg_level & NETIF_MSG_LINK)
-+ printk(KERN_WARNING "%s: Transmit timeout using MII device,"
-+ " status %4.4x.\n",
-+ dev->name, mii_bmsr);
-+ if ( ! (mii_bmsr & 0x0004)) { /* No link beat present */
-+ dev->trans_start = jiffies;
-+ netif_link_down(dev);
-+ return;
-+ }
-+ } else switch (tp->chip_id) {
-+ case DC21040:
- if ( !tp->medialock && inl(ioaddr + CSR12) & 0x0002) {
- dev->if_port = (dev->if_port == 2 ? 0 : 2);
- printk(KERN_INFO "%s: transmit timed out, switching to "
-@@ -2405,38 +2555,49 @@
- select_media(dev, 0);
- }
- dev->trans_start = jiffies;
-- return;
-- } else if (tp->chip_id == DC21041) {
-+ return; /* Note: not break! */
-+ case DC21041: {
- int csr12 = inl(ioaddr + CSR12);
-
- printk(KERN_WARNING "%s: 21041 transmit timed out, status %8.8x, "
- "CSR12 %8.8x, CSR13 %8.8x, CSR14 %8.8x, resetting...\n",
-- dev->name, inl(ioaddr + CSR5), csr12,
-- inl(ioaddr + CSR13), inl(ioaddr + CSR14));
-+ dev->name, (int)inl(ioaddr + CSR5), csr12,
-+ (int)inl(ioaddr + CSR13), (int)inl(ioaddr + CSR14));
- tp->mediasense = 1;
- if ( ! tp->medialock) {
- if (dev->if_port == 1 || dev->if_port == 2)
-- if (csr12 & 0x0004) {
-- dev->if_port = 2 - dev->if_port;
-- } else
-- dev->if_port = 0;
-+ dev->if_port = (csr12 & 0x0004) ? 2 - dev->if_port : 0;
- else
- dev->if_port = 1;
- select_media(dev, 0);
- }
-- } else if (tp->chip_id == DC21140 || tp->chip_id == DC21142
-- || tp->chip_id == MX98713 || tp->chip_id == COMPEX9881) {
-- printk(KERN_WARNING "%s: 21140 transmit timed out, status %8.8x, "
-+ break;
-+ }
-+ case DC21142:
-+ if (tp->nwayset) {
-+ printk(KERN_WARNING "%s: Transmit timed out, status %8.8x, "
-+ "SIA %8.8x %8.8x %8.8x %8.8x, restarting NWay .\n",
-+ dev->name, (int)inl(ioaddr + CSR5),
-+ (int)inl(ioaddr + CSR12), (int)inl(ioaddr + CSR13),
-+ (int)inl(ioaddr + CSR14), (int)inl(ioaddr + CSR15));
-+ nway_start(dev);
-+ break;
-+ }
-+ /* Fall through. */
-+ case DC21140: case MX98713: case COMPEX9881:
-+ printk(KERN_WARNING "%s: %s transmit timed out, status %8.8x, "
- "SIA %8.8x %8.8x %8.8x %8.8x, resetting...\n",
-- dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12),
-- inl(ioaddr + CSR13), inl(ioaddr + CSR14), inl(ioaddr + CSR15));
-+ dev->name, tulip_tbl[tp->chip_id].chip_name,
-+ (int)inl(ioaddr + CSR5), (int)inl(ioaddr + CSR12),
-+ (int)inl(ioaddr + CSR13), (int)inl(ioaddr + CSR14),
-+ (int)inl(ioaddr + CSR15));
- if ( ! tp->medialock && tp->mtable) {
- do
- --tp->cur_index;
- while (tp->cur_index >= 0
- && (media_cap[tp->mtable->mleaf[tp->cur_index].media]
- & MediaIsFD));
-- if (--tp->cur_index < 0) {
-+ if (tp->cur_index < 0) {
- /* We start again, but should instead look for default. */
- tp->cur_index = tp->mtable->leafcount - 1;
- }
-@@ -2444,15 +2605,21 @@
- printk(KERN_WARNING "%s: transmit timed out, switching to %s "
- "media.\n", dev->name, medianame[dev->if_port]);
- }
-- } else {
-+ break;
-+ case PNIC2:
-+ printk(KERN_WARNING "%s: PNIC2 transmit timed out, status %8.8x, "
-+ "CSR6/7 %8.8x / %8.8x CSR12 %8.8x, resetting...\n",
-+ dev->name, (int)inl(ioaddr + CSR5), (int)inl(ioaddr + CSR6),
-+ (int)inl(ioaddr + CSR7), (int)inl(ioaddr + CSR12));
-+ break;
-+ default:
- printk(KERN_WARNING "%s: Transmit timed out, status %8.8x, CSR12 "
- "%8.8x, resetting...\n",
-- dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12));
-- dev->if_port = 0;
-+ dev->name, (int)inl(ioaddr + CSR5), (int)inl(ioaddr + CSR12));
- }
-
--#if defined(way_too_many_messages)
-- if (tulip_debug > 3) {
-+#if defined(way_too_many_messages) && defined(__i386__)
-+ if (tp->msg_level & NETIF_MSG_TXERR) {
- int i;
- for (i = 0; i < RX_RING_SIZE; i++) {
- u8 *buf = (u8 *)(tp->rx_ring[i].buffer1);
-@@ -2478,11 +2645,13 @@
- }
- #endif
-
-- /* Stop and restart the chip's Tx processes . */
-- outl(tp->csr6 | 0x0002, ioaddr + CSR6);
-- outl(tp->csr6 | 0x2002, ioaddr + CSR6);
-+ /* Stop and restart the Tx process.
-+ The pwr_event approach of empty/init_rings() may be better... */
-+ outl(tp->csr6 | RxOn, ioaddr + CSR6);
-+ outl(tp->csr6 | RxOn | TxOn, ioaddr + CSR6);
- /* Trigger an immediate transmit demand. */
- outl(0, ioaddr + CSR1);
-+ outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7);
-
- dev->trans_start = jiffies;
- tp->stats.tx_errors++;
-@@ -2491,38 +2660,39 @@
-
-
- /* Initialize the Rx and Tx rings, along with various 'dev' bits. */
--static void tulip_init_ring(struct device *dev)
-+static void tulip_init_ring(struct net_device *dev)
- {
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- int i;
-
-- tp->tx_full = 0;
-+ tp->rx_dead = tp->tx_full = 0;
- tp->cur_rx = tp->cur_tx = 0;
- tp->dirty_rx = tp->dirty_tx = 0;
-- tp->susp_rx = 0;
-- tp->ttimer = 0;
-- tp->nir = 0;
-+
-+ tp->rx_buf_sz = dev->mtu + 18;
-+ if (tp->rx_buf_sz < PKT_BUF_SZ)
-+ tp->rx_buf_sz = PKT_BUF_SZ;
-
- for (i = 0; i < RX_RING_SIZE; i++) {
- tp->rx_ring[i].status = 0x00000000;
-- tp->rx_ring[i].length = cpu_to_le32(PKT_BUF_SZ);
-+ tp->rx_ring[i].length = cpu_to_le32(tp->rx_buf_sz);
- tp->rx_ring[i].buffer2 = virt_to_le32desc(&tp->rx_ring[i+1]);
- tp->rx_skbuff[i] = NULL;
- }
- /* Mark the last entry as wrapping the ring. */
-- tp->rx_ring[i-1].length = cpu_to_le32(PKT_BUF_SZ | DESC_RING_WRAP);
-+ tp->rx_ring[i-1].length |= cpu_to_le32(DESC_RING_WRAP);
- tp->rx_ring[i-1].buffer2 = virt_to_le32desc(&tp->rx_ring[0]);
-
- for (i = 0; i < RX_RING_SIZE; i++) {
- /* Note the receive buffer must be longword aligned.
- dev_alloc_skb() provides 16 byte alignment. But do *not*
- use skb_reserve() to align the IP header! */
-- struct sk_buff *skb = dev_alloc_skb(PKT_BUF_SZ);
-+ struct sk_buff *skb = dev_alloc_skb(tp->rx_buf_sz);
- tp->rx_skbuff[i] = skb;
- if (skb == NULL)
- break;
- skb->dev = dev; /* Mark as being used by this device. */
-- tp->rx_ring[i].status = cpu_to_le32(DescOwned); /* Owned by Tulip chip */
-+ tp->rx_ring[i].status = cpu_to_le32(DescOwned);
- tp->rx_ring[i].buffer1 = virt_to_le32desc(skb->tail);
- }
- tp->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
-@@ -2538,18 +2708,18 @@
- }
-
- static int
--tulip_start_xmit(struct sk_buff *skb, struct device *dev)
-+tulip_start_xmit(struct sk_buff *skb, struct net_device *dev)
- {
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
-- int entry;
-+ int entry, q_used_cnt;
- u32 flag;
-
-- /* Block a timer-based transmit from overlapping. This could better be
-- done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
-- if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
-- if (jiffies - dev->trans_start < TX_TIMEOUT)
-- return 1;
-- tulip_tx_timeout(dev);
-+ /* Block a timer-based transmit from overlapping. This happens when
-+ packets are presumed lost, and we use this check the Tx status. */
-+ if (netif_pause_tx_queue(dev) != 0) {
-+ /* This watchdog code is redundant with the media monitor timer. */
-+ if (jiffies - dev->trans_start > TX_TIMEOUT)
-+ tulip_tx_timeout(dev);
- return 1;
- }
-
-@@ -2558,15 +2728,16 @@
-
- /* Calculate the next Tx descriptor entry. */
- entry = tp->cur_tx % TX_RING_SIZE;
-+ q_used_cnt = tp->cur_tx - tp->dirty_tx;
-
- tp->tx_skbuff[entry] = skb;
- tp->tx_ring[entry].buffer1 = virt_to_le32desc(skb->data);
-
-- if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE/2) {/* Typical path */
-+ if (q_used_cnt < TX_QUEUE_LEN/2) {/* Typical path */
- flag = 0x60000000; /* No interrupt */
-- } else if (tp->cur_tx - tp->dirty_tx == TX_RING_SIZE/2) {
-+ } else if (q_used_cnt == TX_QUEUE_LEN/2) {
- flag = 0xe0000000; /* Tx-done intr. */
-- } else if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE - 2) {
-+ } else if (q_used_cnt < TX_QUEUE_LEN) {
- flag = 0x60000000; /* No Tx-done intr. */
- } else { /* Leave room for set_rx_mode() to fill entries. */
- tp->tx_full = 1;
-@@ -2579,7 +2750,15 @@
- tp->tx_ring[entry].status = cpu_to_le32(DescOwned);
- tp->cur_tx++;
- if ( ! tp->tx_full)
-- clear_bit(0, (void*)&dev->tbusy);
-+ netif_unpause_tx_queue(dev);
-+ else {
-+ netif_stop_tx_queue(dev);
-+ /* Check for a just-cleared queue race.
-+ Note that this code path differs from other drivers because we
-+ set the tx_full flag early. */
-+ if ( ! tp->tx_full)
-+ netif_resume_tx_queue(dev);
-+ }
-
- dev->trans_start = jiffies;
- /* Trigger an immediate transmit demand. */
-@@ -2592,55 +2771,26 @@
- after the Tx thread. */
- static void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
- {
-- struct device *dev = (struct device *)dev_instance;
-+ struct net_device *dev = (struct net_device *)dev_instance;
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- long ioaddr = dev->base_addr;
-- int csr5;
-- int entry;
-- int missed;
-- int rx = 0;
-- int tx = 0;
-- int oi = 0;
-- int maxrx = RX_RING_SIZE;
-- int maxtx = TX_RING_SIZE;
-- int maxoi = TX_RING_SIZE;
--
--#if defined(__i386__) && defined(SMP_CHECK)
-- if (test_and_set_bit(0, (void*)&dev->interrupt)) {
-- printk(KERN_ERR "%s: Duplicate entry of the interrupt handler by "
-- "processor %d.\n",
-- dev->name, hard_smp_processor_id());
-- dev->interrupt = 0;
-- return;
-- }
--#else
-- if (dev->interrupt) {
-- printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name);
-- return;
-- }
-- dev->interrupt = 1;
--#endif
--
-- tp->nir++;
-+ int csr5, work_budget = tp->max_interrupt_work;
-
- do {
- csr5 = inl(ioaddr + CSR5);
-- /* Acknowledge all of the current interrupt sources ASAP. */
-- outl(csr5 & 0x0001ffff, ioaddr + CSR5);
--
-- if (tulip_debug > 4)
-- printk(KERN_DEBUG "%s: interrupt csr5=%#8.8x new csr5=%#8.8x.\n",
-- dev->name, csr5, inl(dev->base_addr + CSR5));
--
- if ((csr5 & (NormalIntr|AbnormalIntr)) == 0)
- break;
-
-- if (csr5 & (RxIntr | RxNoBuf)) {
-- rx += tulip_rx(dev);
-- tulip_refill_rx(dev);
-- }
-+ if (tp->msg_level & NETIF_MSG_INTR)
-+ printk(KERN_DEBUG "%s: interrupt csr5=%#8.8x new csr5=%#8.8x.\n",
-+ dev->name, csr5, (int)inl(dev->base_addr + CSR5));
-+ /* Acknowledge all of the current interrupt sources ASAP. */
-+ outl(csr5 & 0x0001ffff, ioaddr + CSR5);
-+
-+ if (csr5 & (RxIntr | RxNoBuf))
-+ work_budget -= tulip_rx(dev);
-
-- if (csr5 & (TxNoBuf | TxDied | TxIntr | TimerInt)) {
-+ if (csr5 & (TxNoBuf | TxDied | TxIntr)) {
- unsigned int dirty_tx;
-
- for (dirty_tx = tp->dirty_tx; tp->cur_tx - dirty_tx > 0;
-@@ -2653,14 +2803,12 @@
- /* Check for Rx filter setup frames. */
- if (tp->tx_skbuff[entry] == NULL)
- continue;
--
-+
- if (status & 0x8000) {
- /* There was an major error, log it. */
--#ifndef final_version
-- if (tulip_debug > 1)
-+ if (tp->msg_level & NETIF_MSG_TX_ERR)
- printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",
- dev->name, status);
--#endif
- tp->stats.tx_errors++;
- if (status & 0x4104) tp->stats.tx_aborted_errors++;
- if (status & 0x0C00) tp->stats.tx_carrier_errors++;
-@@ -2672,6 +2820,9 @@
- if (status & 0x0100) tp->stats.collisions16++;
- #endif
- } else {
-+ if (tp->msg_level & NETIF_MSG_TX_DONE)
-+ printk(KERN_DEBUG "%s: Transmit complete, status "
-+ "%8.8x.\n", dev->name, status);
- #ifdef ETHER_STATS
- if (status & 0x0001) tp->stats.tx_deferred++;
- #endif
-@@ -2683,9 +2834,8 @@
- }
-
- /* Free the original skb. */
-- dev_free_skb(tp->tx_skbuff[entry]);
-+ dev_free_skb_irq(tp->tx_skbuff[entry]);
- tp->tx_skbuff[entry] = 0;
-- tx++;
- }
-
- #ifndef final_version
-@@ -2696,22 +2846,22 @@
- }
- #endif
-
-- if (tp->tx_full && dev->tbusy
-- && tp->cur_tx - dirty_tx < TX_RING_SIZE - 2) {
-+ if (tp->tx_full && tp->cur_tx - dirty_tx < TX_QUEUE_LEN - 4) {
- /* The ring is no longer full, clear tbusy. */
- tp->tx_full = 0;
-- dev->tbusy = 0;
-- netif_wake_queue(dev);
-+ netif_resume_tx_queue(dev);
- }
-
- tp->dirty_tx = dirty_tx;
-- if (csr5 & TxDied) {
-- if (tulip_debug > 2)
-- printk(KERN_WARNING "%s: The transmitter stopped."
-- " CSR5 is %x, CSR6 %x, new CSR6 %x.\n",
-- dev->name, csr5, inl(ioaddr + CSR6), tp->csr6);
-- outl(tp->csr6 | 0x0002, ioaddr + CSR6);
-- outl(tp->csr6 | 0x2002, ioaddr + CSR6);
-+ }
-+
-+ if (tp->rx_dead) {
-+ tulip_rx(dev);
-+ if (tp->cur_rx - tp->dirty_rx < RX_RING_SIZE - 3) {
-+ printk(KERN_ERR "%s: Restarted Rx at %d / %d.\n",
-+ dev->name, tp->cur_rx, tp->dirty_rx);
-+ outl(0, ioaddr + CSR2); /* Rx poll demand */
-+ tp->rx_dead = 0;
- }
- }
-
-@@ -2720,130 +2870,98 @@
- if (csr5 == 0xffffffff)
- break;
- if (csr5 & TxJabber) tp->stats.tx_errors++;
-+ if (csr5 & PCIBusError) {
-+ printk(KERN_ERR "%s: PCI Fatal Bus Error, %8.8x.\n",
-+ dev->name, csr5);
-+ }
- if (csr5 & TxFIFOUnderflow) {
- if ((tp->csr6 & 0xC000) != 0xC000)
- tp->csr6 += 0x4000; /* Bump up the Tx threshold */
- else
- tp->csr6 |= 0x00200000; /* Store-n-forward. */
-+ if (tp->msg_level & NETIF_MSG_TX_ERR)
-+ printk(KERN_WARNING "%s: Tx threshold increased, "
-+ "new CSR6 %x.\n", dev->name, tp->csr6);
-+ }
-+ if (csr5 & TxDied) {
-+ /* This is normal when changing Tx modes. */
-+ if (tp->msg_level & NETIF_MSG_LINK)
-+ printk(KERN_WARNING "%s: The transmitter stopped."
-+ " CSR5 is %x, CSR6 %x, new CSR6 %x.\n",
-+ dev->name, csr5, (int)inl(ioaddr + CSR6), tp->csr6);
-+ }
-+ if (csr5 & (TxDied | TxFIFOUnderflow | PCIBusError)) {
- /* Restart the transmit process. */
-- outl(tp->csr6 | 0x0002, ioaddr + CSR6);
-- outl(tp->csr6 | 0x2002, ioaddr + CSR6);
-- outl(0, ioaddr + CSR1);
-+ outl(tp->csr6 | RxOn, ioaddr + CSR6);
-+ outl(tp->csr6 | RxOn | TxOn, ioaddr + CSR6);
- }
-- if (csr5 & RxDied) { /* Missed a Rx frame. */
-- tp->stats.rx_errors++;
-+ if (csr5 & (RxStopped | RxNoBuf)) {
-+ /* Missed a Rx frame or mode change. */
- tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
-- outl(tp->csr6 | 0x2002, ioaddr + CSR6);
-+ if (tp->flags & COMET_MAC_ADDR) {
-+ outl(tp->mc_filter[0], ioaddr + 0xAC);
-+ outl(tp->mc_filter[1], ioaddr + 0xB0);
-+ }
-+ tulip_rx(dev);
-+ if (csr5 & RxNoBuf)
-+ tp->rx_dead = 1;
-+ outl(tp->csr6 | RxOn | TxOn, ioaddr + CSR6);
-+ }
-+ if (csr5 & TimerInt) {
-+ if (tp->msg_level & NETIF_MSG_INTR)
-+ printk(KERN_ERR "%s: Re-enabling interrupts, %8.8x.\n",
-+ dev->name, csr5);
-+ outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7);
- }
- if (csr5 & (TPLnkPass | TPLnkFail | 0x08000000)) {
- if (tp->link_change)
- (tp->link_change)(dev, csr5);
- }
-- if (csr5 & SytemError) {
-- printk(KERN_ERR "%s: (%lu) System Error occured\n", dev->name, tp->nir);
-- }
- /* Clear all error sources, included undocumented ones! */
- outl(0x0800f7ba, ioaddr + CSR5);
-- oi++;
- }
-- if (csr5 & TimerInt) {
--#if 0
-- if (tulip_debug > 2)
-- printk(KERN_ERR "%s: Re-enabling interrupts, %8.8x.\n",
-- dev->name, csr5);
-- outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7);
--#endif
-- tp->ttimer = 0;
-- oi++;
-- }
-- if (tx > maxtx || rx > maxrx || oi > maxoi) {
-- if (tulip_debug > 1)
-+ if (--work_budget < 0) {
-+ if (tp->msg_level & NETIF_MSG_DRV)
- printk(KERN_WARNING "%s: Too much work during an interrupt, "
-- "csr5=0x%8.8x. (%lu) (%d,%d,%d)\n", dev->name, csr5, tp->nir, tx, rx, oi);
-+ "csr5=0x%8.8x.\n", dev->name, csr5);
- /* Acknowledge all interrupt sources. */
--#if 0
-- /* Clear all interrupting sources, set timer to re-enable. */
-- outl(((~csr5) & 0x0001ebef) | NormalIntr | AbnormalIntr | TimerInt,
-- ioaddr + CSR7);
-- outl(12, ioaddr + CSR11);
-- tp->ttimer = 1;
--#endif
-+ outl(0x8001ffff, ioaddr + CSR5);
-+ if (tp->flags & HAS_INTR_MITIGATION) {
-+ /* Josip Loncaric at ICASE did extensive experimentation
-+ to develop a good interrupt mitigation setting.*/
-+ outl(0x8b240000, ioaddr + CSR11);
-+ } else {
-+ /* Mask all interrupting sources, set timer to re-enable. */
-+ outl(((~csr5) & 0x0001ebef) | AbnormalIntr | TimerInt,
-+ ioaddr + CSR7);
-+ outl(0x0012, ioaddr + CSR11);
-+ }
- break;
- }
- } while (1);
-
-- tulip_refill_rx(dev);
--
-- /* check if we card is in suspend mode */
-- entry = tp->dirty_rx % RX_RING_SIZE;
-- if (tp->rx_skbuff[entry] == NULL) {
-- if (tulip_debug > 1)
-- printk(KERN_WARNING "%s: in rx suspend mode: (%lu) (tp->cur_rx = %u, ttimer = %d, rx = %d) go/stay in suspend mode\n", dev->name, tp->nir, tp->cur_rx, tp->ttimer, rx);
-- if (tp->ttimer == 0 || (inl(ioaddr + CSR11) & 0xffff) == 0) {
-- if (tulip_debug > 1)
-- printk(KERN_WARNING "%s: in rx suspend mode: (%lu) set timer\n", dev->name, tp->nir);
-- outl(tulip_tbl[tp->chip_id].valid_intrs | TimerInt,
-- ioaddr + CSR7);
-- outl(TimerInt, ioaddr + CSR5);
-- outl(12, ioaddr + CSR11);
-- tp->ttimer = 1;
-- }
-- }
--
-- if ((missed = inl(ioaddr + CSR8) & 0x1ffff)) {
-- tp->stats.rx_dropped += missed & 0x10000 ? 0x10000 : missed;
-- }
--
-- if (tulip_debug > 4)
-+ if (tp->msg_level & NETIF_MSG_INTR)
- printk(KERN_DEBUG "%s: exiting interrupt, csr5=%#4.4x.\n",
-- dev->name, inl(ioaddr + CSR5));
-+ dev->name, (int)inl(ioaddr + CSR5));
-
--#if defined(__i386__)
-- clear_bit(0, (void*)&dev->interrupt);
--#else
-- dev->interrupt = 0;
--#endif
- return;
- }
-
--static int tulip_refill_rx(struct device *dev)
--{
-- struct tulip_private *tp = (struct tulip_private *)dev->priv;
-- int entry;
-- int refilled = 0;
--
-- /* Refill the Rx ring buffers. */
-- for (; tp->cur_rx - tp->dirty_rx > 0; tp->dirty_rx++) {
-- entry = tp->dirty_rx % RX_RING_SIZE;
-- if (tp->rx_skbuff[entry] == NULL) {
-- struct sk_buff *skb;
-- skb = tp->rx_skbuff[entry] = dev_alloc_skb(PKT_BUF_SZ);
-- if (skb == NULL)
-- break;
-- skb->dev = dev; /* Mark as being used by this device. */
-- tp->rx_ring[entry].buffer1 = virt_to_le32desc(skb->tail);
-- refilled++;
-- }
-- tp->rx_ring[entry].status = cpu_to_le32(DescOwned);
-- }
-- return refilled;
--}
--
--static int tulip_rx(struct device *dev)
-+static int tulip_rx(struct net_device *dev)
- {
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- int entry = tp->cur_rx % RX_RING_SIZE;
- int rx_work_limit = tp->dirty_rx + RX_RING_SIZE - tp->cur_rx;
-- int received = 0;
-+ int work_done = 0;
-
-- if (tulip_debug > 4)
-+ if (tp->msg_level & NETIF_MSG_RX_STATUS)
- printk(KERN_DEBUG " In tulip_rx(), entry %d %8.8x.\n", entry,
- tp->rx_ring[entry].status);
- /* If we own the next entry, it is a new packet. Send it up. */
- while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) {
- s32 status = le32_to_cpu(tp->rx_ring[entry].status);
-
-- if (tulip_debug > 5)
-+ if (tp->msg_level & NETIF_MSG_RX_STATUS)
- printk(KERN_DEBUG "%s: In tulip_rx(), entry %d %8.8x.\n",
- dev->name, entry, status);
- if (--rx_work_limit < 0)
-@@ -2852,7 +2970,7 @@
- if ((status & 0x38000300) != 0x0300) {
- /* Ingore earlier buffers. */
- if ((status & 0xffff) != 0x7fff) {
-- if (tulip_debug > 1)
-+ if (tp->msg_level & NETIF_MSG_RX_ERR)
- printk(KERN_WARNING "%s: Oversized Ethernet frame "
- "spanned multiple buffers, status %8.8x!\n",
- dev->name, status);
-@@ -2860,7 +2978,7 @@
- }
- } else if (status & RxDescFatalErr) {
- /* There was a fatal error. */
-- if (tulip_debug > 2)
-+ if (tp->msg_level & NETIF_MSG_RX_ERR)
- printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n",
- dev->name, status);
- tp->stats.rx_errors++; /* end of a packet.*/
-@@ -2884,28 +3002,21 @@
- #endif
- /* Check if the packet is long enough to accept without copying
- to a minimally-sized skbuff. */
-- if (pkt_len < rx_copybreak
-+ if (pkt_len < tp->rx_copybreak
- && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
- skb->dev = dev;
- skb_reserve(skb, 2); /* 16 byte align the IP header */
--#if ! defined(__alpha__)
-+#if (LINUX_VERSION_CODE >= 0x20100)
- eth_copy_and_sum(skb, tp->rx_skbuff[entry]->tail, pkt_len, 0);
- skb_put(skb, pkt_len);
- #else
- memcpy(skb_put(skb, pkt_len), tp->rx_skbuff[entry]->tail,
- pkt_len);
- #endif
-- } else { /* Pass up the skb already on the Rx ring. */
-- char *temp = skb_put(skb = tp->rx_skbuff[entry], pkt_len);
-+ work_done++;
-+ } else { /* Pass up the skb already on the Rx ring. */
-+ skb_put(skb = tp->rx_skbuff[entry], pkt_len);
- tp->rx_skbuff[entry] = NULL;
--#ifndef final_version
-- if (le32desc_to_virt(tp->rx_ring[entry].buffer1) != temp)
-- printk(KERN_ERR "%s: Internal fault: The skbuff addresses "
-- "do not match in tulip_rx: %p vs. %p / %p.\n",
-- dev->name,
-- le32desc_to_virt(tp->rx_ring[entry].buffer1),
-- skb->head, temp);
--#endif
- }
- skb->protocol = eth_type_trans(skb, dev);
- netif_rx(skb);
-@@ -2915,43 +3026,36 @@
- tp->stats.rx_bytes += pkt_len;
- #endif
- }
-- received++;
- entry = (++tp->cur_rx) % RX_RING_SIZE;
- }
-
-- return received;
-+ /* Refill the Rx ring buffers. */
-+ for (; tp->cur_rx - tp->dirty_rx > 0; tp->dirty_rx++) {
-+ entry = tp->dirty_rx % RX_RING_SIZE;
-+ if (tp->rx_skbuff[entry] == NULL) {
-+ struct sk_buff *skb;
-+ skb = tp->rx_skbuff[entry] = dev_alloc_skb(tp->rx_buf_sz);
-+ if (skb == NULL) {
-+ if (tp->cur_rx - tp->dirty_rx == RX_RING_SIZE)
-+ printk(KERN_ERR "%s: No kernel memory to allocate "
-+ "receive buffers.\n", dev->name);
-+ break;
-+ }
-+ skb->dev = dev; /* Mark as being used by this device. */
-+ tp->rx_ring[entry].buffer1 = virt_to_le32desc(skb->tail);
-+ work_done++;
-+ }
-+ tp->rx_ring[entry].status = cpu_to_le32(DescOwned);
-+ }
-+
-+ return work_done;
- }
-
--static int tulip_close(struct device *dev)
-+static void empty_rings(struct net_device *dev)
- {
-- long ioaddr = dev->base_addr;
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- int i;
-
-- dev->start = 0;
-- dev->tbusy = 1;
--
-- if (tulip_debug > 1)
-- printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n",
-- dev->name, inl(ioaddr + CSR5));
--
-- /* Disable interrupts by clearing the interrupt mask. */
-- outl(0x00000000, ioaddr + CSR7);
-- /* Stop the Tx and Rx processes. */
-- outl(inl(ioaddr + CSR6) & ~0x2002, ioaddr + CSR6);
-- /* 21040 -- Leave the card in 10baseT state. */
-- if (tp->chip_id == DC21040)
-- outl(0x00000004, ioaddr + CSR13);
--
-- if (inl(ioaddr + CSR6) != 0xffffffff)
-- tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
--
-- del_timer(&tp->timer);
--
-- free_irq(dev->irq, dev);
--
-- dev->if_port = tp->saved_if_port;
--
- /* Free all the skbuffs in the Rx queue. */
- for (i = 0; i < RX_RING_SIZE; i++) {
- struct sk_buff *skb = tp->rx_skbuff[i];
-@@ -2971,86 +3075,165 @@
- dev_free_skb(tp->tx_skbuff[i]);
- tp->tx_skbuff[i] = 0;
- }
-+}
-+
-+static int tulip_close(struct net_device *dev)
-+{
-+ long ioaddr = dev->base_addr;
-+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
-+
-+ netif_stop_tx_queue(dev);
-+
-+ if (tp->msg_level & NETIF_MSG_IFDOWN)
-+ printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n",
-+ dev->name, (int)inl(ioaddr + CSR5));
-
-+ /* Disable interrupts by clearing the interrupt mask. */
-+ outl(0x00000000, ioaddr + CSR7);
-+ /* Stop the Tx and Rx processes. */
-+ outl(inl(ioaddr + CSR6) & ~TxOn & ~RxOn, ioaddr + CSR6);
-+ /* 21040 -- Leave the card in 10baseT state. */
-+ if (tp->chip_id == DC21040)
-+ outl(0x00000004, ioaddr + CSR13);
-+
-+ if (inl(ioaddr + CSR6) != 0xffffffff)
-+ tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
-+
-+ del_timer(&tp->timer);
-+
-+ free_irq(dev->irq, dev);
-+
-+ dev->if_port = tp->saved_if_port;
-+
-+ empty_rings(dev);
- /* Leave the driver in snooze, not sleep, mode. */
- if (tp->flags & HAS_PWRDWN)
-- pcibios_write_config_dword(tp->pci_bus, tp->pci_devfn, 0x40,
-- 0x40000000);
-+ pci_write_config_dword(tp->pci_dev, 0x40, 0x40000000);
-
- MOD_DEC_USE_COUNT;
-
- return 0;
- }
-
--static struct net_device_stats *tulip_get_stats(struct device *dev)
-+static struct net_device_stats *tulip_get_stats(struct net_device *dev)
- {
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- long ioaddr = dev->base_addr;
-+ int csr8 = inl(ioaddr + CSR8);
-
-- if (dev->start)
-- tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
-+ if (netif_running(dev) && csr8 != 0xffffffff)
-+ tp->stats.rx_missed_errors += (u16)csr8;
-
- return &tp->stats;
- }
-
- #ifdef HAVE_PRIVATE_IOCTL
--/* Provide ioctl() calls to examine the MII xcvr state. */
--static int private_ioctl(struct device *dev, struct ifreq *rq, int cmd)
-+/* Provide ioctl() calls to examine the MII xcvr state.
-+ We emulate a MII management registers for chips without MII.
-+ The two numeric constants are because some clueless person
-+ changed value for the symbolic name.
-+ */
-+static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
- {
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- long ioaddr = dev->base_addr;
- u16 *data = (u16 *)&rq->ifr_data;
-- int phy = tp->phys[0] & 0x1f;
-- long flags;
-+ u32 *data32 = (void *)&rq->ifr_data;
-+ unsigned int phy = tp->phys[0];
-+ unsigned int regnum = data[1];
-
- switch(cmd) {
-- case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */
-+ case 0x8947: case 0x89F0:
-+ /* SIOCGMIIPHY: Get the address of the PHY in use. */
- if (tp->mii_cnt)
- data[0] = phy;
-- else if (tp->flags & HAS_NWAY143)
-+ else if (tp->flags & HAS_NWAY)
- data[0] = 32;
- else if (tp->chip_id == COMET)
- data[0] = 1;
- else
- return -ENODEV;
-- case SIOCDEVPRIVATE+1: /* Read the specified MII register. */
-- if (data[0] == 32 && (tp->flags & HAS_NWAY143)) {
-+ case 0x8948: case 0x89F1:
-+ /* SIOCGMIIREG: Read the specified MII register. */
-+ if (data[0] == 32 && (tp->flags & HAS_NWAY)) {
- int csr12 = inl(ioaddr + CSR12);
- int csr14 = inl(ioaddr + CSR14);
-- switch (data[1]) {
-- case 0: {
-- data[3] = (csr14<<5) & 0x1000;
-- break; }
-+ switch (regnum) {
-+ case 0:
-+ if (((csr14<<5) & 0x1000) ||
-+ (dev->if_port == 5 && tp->nwayset))
-+ data[3] = 0x1000;
-+ else
-+ data[3] = (media_cap[dev->if_port]&MediaIs100 ? 0x2000 : 0)
-+ | (media_cap[dev->if_port]&MediaIsFD ? 0x0100 : 0);
-+ break;
- case 1:
-- data[3] = 0x7848 + ((csr12&0x7000) == 0x5000 ? 0x20 : 0)
-- + (csr12&0x06 ? 0x04 : 0);
-+ data[3] = 0x1848 + ((csr12&0x7000) == 0x5000 ? 0x20 : 0)
-+ + ((csr12&0x06) == 6 ? 0 : 4);
-+ if (tp->chip_id != DC21041)
-+ data[3] |= 0x6048;
- break;
- case 4: {
-- data[3] = ((csr14>>9)&0x07C0) +
-- ((inl(ioaddr + CSR6)>>3)&0x0040) + ((csr14>>1)&0x20) + 1;
-+ /* Advertised value, bogus 10baseTx-FD value from CSR6. */
-+ data[3] = ((inl(ioaddr + CSR6)>>3)&0x0040)+((csr14>>1)&0x20)+1;
-+ if (tp->chip_id != DC21041)
-+ data[3] |= ((csr14>>9)&0x03C0);
- break;
- }
-- case 5: data[3] = csr12 >> 16; break;
-+ case 5: data[3] = tp->lpar; break;
- default: data[3] = 0; break;
- }
- } else {
-- save_flags(flags);
-- cli();
-- data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f);
-- restore_flags(flags);
-+ data[3] = mdio_read(dev, data[0] & 0x1f, regnum);
- }
- return 0;
-- case SIOCDEVPRIVATE+2: /* Write the specified MII register */
-+ case 0x8949: case 0x89F2:
-+ /* SIOCSMIIREG: Write the specified MII register */
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
-- if (data[0] == 32 && (tp->flags & HAS_NWAY143)) {
-- if (data[1] == 5)
-- tp->to_advertise = data[2];
-+ if (regnum & ~0x1f)
-+ return -EINVAL;
-+ if (data[0] == phy) {
-+ u16 value = data[2];
-+ switch (regnum) {
-+ case 0: /* Check for autonegotiation on or reset. */
-+ tp->full_duplex_lock = (value & 0x9000) ? 0 : 1;
-+ if (tp->full_duplex_lock)
-+ tp->full_duplex = (value & 0x0100) ? 1 : 0;
-+ break;
-+ case 4: tp->mii_advertise = data[2]; break;
-+ }
-+ }
-+ if (data[0] == 32 && (tp->flags & HAS_NWAY)) {
-+ u16 value = data[2];
-+ if (regnum == 0) {
-+ if ((value & 0x1200) == 0x1200)
-+ nway_start(dev);
-+ } else if (regnum == 4)
-+ tp->sym_advertise = value;
- } else {
-- save_flags(flags);
-- cli();
-- mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]);
-- restore_flags(flags);
-+ mdio_write(dev, data[0] & 0x1f, regnum, data[2]);
-+ }
-+ return 0;
-+ case SIOCGPARAMS:
-+ data32[0] = tp->msg_level;
-+ data32[1] = tp->multicast_filter_limit;
-+ data32[2] = tp->max_interrupt_work;
-+ data32[3] = tp->rx_copybreak;
-+ data32[4] = inl(ioaddr + CSR11);
-+ return 0;
-+ case SIOCSPARAMS:
-+ if (!capable(CAP_NET_ADMIN))
-+ return -EPERM;
-+ tp->msg_level = data32[0];
-+ tp->multicast_filter_limit = data32[1];
-+ tp->max_interrupt_work = data32[2];
-+ tp->rx_copybreak = data32[3];
-+ if (tp->flags & HAS_INTR_MITIGATION) {
-+ u32 *d = (u32 *)&rq->ifr_data;
-+ outl(data32[4], ioaddr + CSR11);
-+ printk(KERN_NOTICE "%s: Set interrupt mitigate paramters %8.8x.\n",
-+ dev->name, d[0]);
- }
- return 0;
- default:
-@@ -3089,19 +3272,19 @@
- static unsigned const ethernet_polynomial = 0x04c11db7U;
- static inline u32 ether_crc(int length, unsigned char *data)
- {
-- int crc = -1;
-+ int crc = -1;
-
-- while(--length >= 0) {
-+ while(--length >= 0) {
- unsigned char current_octet = *data++;
- int bit;
- for (bit = 0; bit < 8; bit++, current_octet >>= 1)
- crc = (crc << 1) ^
- ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
-- }
-- return crc;
-+ }
-+ return crc;
- }
-
--static void set_rx_mode(struct device *dev)
-+static void set_rx_mode(struct net_device *dev)
- {
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- long ioaddr = dev->base_addr;
-@@ -3109,37 +3292,56 @@
-
- tp->csr6 &= ~0x00D5;
- if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
-- tp->csr6 |= 0x00C0;
-- csr6 |= 0x00C0;
-+ tp->csr6 |= AcceptAllMulticast | AcceptAllPhys;
-+ csr6 |= AcceptAllMulticast | AcceptAllPhys;
- /* Unconditionally log net taps. */
- printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name);
-- } else if ((dev->mc_count > 1000) || (dev->flags & IFF_ALLMULTI)) {
-+ } else if ((dev->mc_count > tp->multicast_filter_limit) ||
-+ (dev->flags & IFF_ALLMULTI)) {
- /* Too many to filter well -- accept all multicasts. */
-- tp->csr6 |= 0x0080;
-- csr6 |= 0x0080;
-+ tp->csr6 |= AcceptAllMulticast;
-+ csr6 |= AcceptAllMulticast;
- } else if (tp->flags & MC_HASH_ONLY) {
- /* Some work-alikes have only a 64-entry hash filter table. */
- /* Should verify correctness on big-endian/__powerpc__ */
- struct dev_mc_list *mclist;
- int i;
-- u32 mc_filter[2]; /* Multicast hash filter */
-- if (dev->mc_count > 64) { /* Arbitrary non-effective limit. */
-- tp->csr6 |= 0x0080;
-- csr6 |= 0x0080;
-+ if (dev->mc_count > tp->multicast_filter_limit) {
-+ tp->csr6 |= AcceptAllMulticast;
-+ csr6 |= AcceptAllMulticast;
- } else {
-- mc_filter[1] = mc_filter[0] = 0;
-+ u32 mc_filter[2] = {0, 0}; /* Multicast hash filter */
-+ int filterbit;
- for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
-- i++, mclist = mclist->next)
-- set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr)>>26, mc_filter);
-- if (tp->chip_id == AX88140) {
-+ i++, mclist = mclist->next) {
-+ if (tp->flags & COMET_MAC_ADDR)
-+ filterbit = ether_crc_le(ETH_ALEN, mclist->dmi_addr);
-+ else
-+ filterbit = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
-+ filterbit &= 0x3f;
-+ set_bit(filterbit, mc_filter);
-+ if (tp->msg_level & NETIF_MSG_RXFILTER)
-+ printk(KERN_INFO "%s: Added filter for %2.2x:%2.2x:%2.2x:"
-+ "%2.2x:%2.2x:%2.2x %8.8x bit %d.\n", dev->name,
-+ mclist->dmi_addr[0], mclist->dmi_addr[1],
-+ mclist->dmi_addr[2], mclist->dmi_addr[3],
-+ mclist->dmi_addr[4], mclist->dmi_addr[5],
-+ ether_crc(ETH_ALEN, mclist->dmi_addr), filterbit);
-+ }
-+ if (mc_filter[0] == tp->mc_filter[0] &&
-+ mc_filter[1] == tp->mc_filter[1])
-+ ; /* No change. */
-+ else if (tp->flags & IS_ASIX) {
- outl(2, ioaddr + CSR13);
- outl(mc_filter[0], ioaddr + CSR14);
- outl(3, ioaddr + CSR13);
- outl(mc_filter[1], ioaddr + CSR14);
-- } else if (tp->chip_id == COMET) { /* Has a simple hash filter. */
-+ } else if (tp->flags & COMET_MAC_ADDR) {
- outl(mc_filter[0], ioaddr + 0xAC);
- outl(mc_filter[1], ioaddr + 0xB0);
- }
-+ tp->mc_filter[0] = mc_filter[0];
-+ tp->mc_filter[1] = mc_filter[1];
- }
- } else {
- u16 *eaddrs, *setup_frm = tp->setup_frame;
-@@ -3153,14 +3355,16 @@
- u16 hash_table[32];
- tx_flags = 0x08400000 | 192; /* Use hash filter. */
- memset(hash_table, 0, sizeof(hash_table));
-- set_bit(255, hash_table); /* Broadcast entry */
-+ set_bit(255, hash_table); /* Broadcast entry */
- /* This should work on big-endian machines as well. */
- for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
- i++, mclist = mclist->next)
- set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x1ff,
- hash_table);
-- for (i = 0; i < 32; i++)
-- *setup_frm++ = *setup_frm++ = hash_table[i];
-+ for (i = 0; i < 32; i++) {
-+ *setup_frm++ = hash_table[i];
-+ *setup_frm++ = hash_table[i];
-+ }
- setup_frm = &tp->setup_frame[13*6];
- } else {
- /* We have <= 14 addresses so we can use the wonderful
-@@ -3168,9 +3372,9 @@
- for (i = 0, mclist = dev->mc_list; i < dev->mc_count;
- i++, mclist = mclist->next) {
- eaddrs = (u16 *)mclist->dmi_addr;
-- *setup_frm++ = *setup_frm++ = *eaddrs++;
-- *setup_frm++ = *setup_frm++ = *eaddrs++;
-- *setup_frm++ = *setup_frm++ = *eaddrs++;
-+ *setup_frm++ = *eaddrs; *setup_frm++ = *eaddrs++;
-+ *setup_frm++ = *eaddrs; *setup_frm++ = *eaddrs++;
-+ *setup_frm++ = *eaddrs; *setup_frm++ = *eaddrs++;
- }
- /* Fill the unused entries with the broadcast address. */
- memset(setup_frm, 0xff, (15-i)*12);
-@@ -3178,9 +3382,9 @@
- }
- /* Fill the final entry with our physical address. */
- eaddrs = (u16 *)dev->dev_addr;
-- *setup_frm++ = *setup_frm++ = eaddrs[0];
-- *setup_frm++ = *setup_frm++ = eaddrs[1];
-- *setup_frm++ = *setup_frm++ = eaddrs[2];
-+ *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0];
-+ *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1];
-+ *setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2];
- /* Now add this frame to the Tx list. */
- if (tp->cur_tx - tp->dirty_tx > TX_RING_SIZE - 2) {
- /* Same setup recently queued, we need not add it. */
-@@ -3188,14 +3392,14 @@
- unsigned long flags;
- unsigned int entry;
-
-- save_flags(flags); cli();
-+ spin_lock_irqsave(&tp->mii_lock, flags);
- entry = tp->cur_tx++ % TX_RING_SIZE;
-
- if (entry != 0) {
- /* Avoid a chip errata by prefixing a dummy entry. */
- tp->tx_skbuff[entry] = 0;
- tp->tx_ring[entry].length =
-- (entry == TX_RING_SIZE-1) ? cpu_to_le32(DESC_RING_WRAP) : 0;
-+ (entry == TX_RING_SIZE-1) ? cpu_to_le32(DESC_RING_WRAP):0;
- tp->tx_ring[entry].buffer1 = 0;
- tp->tx_ring[entry].status = cpu_to_le32(DescOwned);
- entry = tp->cur_tx++ % TX_RING_SIZE;
-@@ -3209,35 +3413,145 @@
- tp->tx_ring[entry].buffer1 = virt_to_le32desc(tp->setup_frame);
- tp->tx_ring[entry].status = cpu_to_le32(DescOwned);
- if (tp->cur_tx - tp->dirty_tx >= TX_RING_SIZE - 2) {
-- set_bit(0, (void*)&dev->tbusy);
-+ netif_stop_tx_queue(dev);
- tp->tx_full = 1;
- }
-- restore_flags(flags);
-+ spin_unlock_irqrestore(&tp->mii_lock, flags);
- /* Trigger an immediate transmit demand. */
- outl(0, ioaddr + CSR1);
- }
- }
-- outl(csr6 | 0x0000, ioaddr + CSR6);
-+ outl(csr6, ioaddr + CSR6);
- }
-
-+
-+static int tulip_pwr_event(void *dev_instance, int event)
-+{
-+ struct net_device *dev = dev_instance;
-+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+ if (tp->msg_level & NETIF_MSG_LINK)
-+ printk("%s: Handling power event %d.\n", dev->name, event);
-+ switch(event) {
-+ case DRV_ATTACH:
-+ MOD_INC_USE_COUNT;
-+ break;
-+ case DRV_SUSPEND: {
-+ int csr6 = inl(ioaddr + CSR6);
-+ /* Disable interrupts, stop the chip, gather stats. */
-+ if (csr6 != 0xffffffff) {
-+ int csr8 = inl(ioaddr + CSR8);
-+ outl(0x00000000, ioaddr + CSR7);
-+ outl(csr6 & ~TxOn & ~RxOn, ioaddr + CSR6);
-+ tp->stats.rx_missed_errors += (unsigned short)csr8;
-+ }
-+ empty_rings(dev);
-+ /* Put the 21143 into sleep mode. */
-+ if (tp->flags & HAS_PWRDWN)
-+ pci_write_config_dword(tp->pci_dev, 0x40,0x80000000);
-+ break;
-+ }
-+ case DRV_RESUME:
-+ if (tp->flags & HAS_PWRDWN)
-+ pci_write_config_dword(tp->pci_dev, 0x40, 0x0000);
-+ outl(tp->csr0, ioaddr + CSR0);
-+ tulip_init_ring(dev);
-+ outl(virt_to_bus(tp->rx_ring), ioaddr + CSR3);
-+ outl(virt_to_bus(tp->tx_ring), ioaddr + CSR4);
-+ if (tp->mii_cnt) {
-+ dev->if_port = 11;
-+ if (tp->mtable && tp->mtable->has_mii)
-+ select_media(dev, 1);
-+ tp->csr6 = 0x820E0000;
-+ dev->if_port = 11;
-+ outl(0x0000, ioaddr + CSR13);
-+ outl(0x0000, ioaddr + CSR14);
-+ } else if (! tp->medialock)
-+ nway_start(dev);
-+ else
-+ select_media(dev, 1);
-+ outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7);
-+ outl(tp->csr6 | TxOn | RxOn, ioaddr + CSR6);
-+ outl(0, ioaddr + CSR2); /* Rx poll demand */
-+ set_rx_mode(dev);
-+ break;
-+ case DRV_DETACH: {
-+ struct net_device **devp, **next;
-+ if (dev->flags & IFF_UP) {
-+ printk(KERN_ERR "%s: Tulip CardBus interface was detached while "
-+ "still active.\n", dev->name);
-+ dev_close(dev);
-+ dev->flags &= ~(IFF_UP|IFF_RUNNING);
-+ }
-+ if (tp->msg_level & NETIF_MSG_DRV)
-+ printk(KERN_DEBUG "%s: Unregistering device.\n", dev->name);
-+ unregister_netdev(dev);
-+#ifdef USE_IO_OPS
-+ release_region(dev->base_addr, pci_id_tbl[tp->chip_id].io_size);
-+#else
-+ iounmap((char *)dev->base_addr);
-+#endif
-+ for (devp = &root_tulip_dev; *devp; devp = next) {
-+ next = &((struct tulip_private *)(*devp)->priv)->next_module;
-+ if (*devp == dev) {
-+ *devp = *next;
-+ break;
-+ }
-+ }
-+ if (tp->priv_addr)
-+ kfree(tp->priv_addr);
-+ kfree(dev);
-+ MOD_DEC_USE_COUNT;
-+ break;
-+ }
-+ default:
-+ break;
-+ }
-+
-+ return 0;
-+}
-+
- #ifdef CARDBUS
-
- #include <pcmcia/driver_ops.h>
-
- static dev_node_t *tulip_attach(dev_locator_t *loc)
- {
-- struct device *dev;
-- u16 dev_id;
-- u32 io;
-+ struct net_device *dev;
-+ long ioaddr;
-+ struct pci_dev *pdev;
- u8 bus, devfn, irq;
-+ u32 dev_id;
-+ u32 pciaddr;
-+ int i, chip_id = 4; /* DC21143 */
-
- if (loc->bus != LOC_PCI) return NULL;
- bus = loc->b.pci.bus; devfn = loc->b.pci.devfn;
- printk(KERN_INFO "tulip_attach(bus %d, function %d)\n", bus, devfn);
-- pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &io);
-- pcibios_read_config_word(bus, devfn, PCI_DEVICE_ID, &dev_id);
-- pcibios_read_config_byte(bus, devfn, PCI_INTERRUPT_LINE, &irq);
-- dev = tulip_probe1(bus, devfn, NULL, io & ~3, irq, DC21142, 0);
-+ pdev = pci_find_slot(bus, devfn);
-+#ifdef USE_IO_OPS
-+ pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &pciaddr);
-+ ioaddr = pciaddr & PCI_BASE_ADDRESS_IO_MASK;
-+#else
-+ pci_read_config_dword(pdev, PCI_BASE_ADDRESS_1, &pciaddr);
-+ ioaddr = (long)ioremap(pciaddr & PCI_BASE_ADDRESS_MEM_MASK,
-+ pci_id_tbl[DC21142].io_size);
-+#endif
-+ pci_read_config_dword(pdev, 0, &dev_id);
-+ pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &irq);
-+ if (ioaddr == 0 || irq == 0) {
-+ printk(KERN_ERR "The Tulip CardBus Ethernet interface at %d/%d was "
-+ "not assigned an %s.\n"
-+ KERN_ERR " It will not be activated.\n",
-+ bus, devfn, ioaddr == 0 ? "address" : "IRQ");
-+ return NULL;
-+ }
-+ for (i = 0; pci_id_tbl[i].id.pci; i++) {
-+ if (pci_id_tbl[i].id.pci == (dev_id & pci_id_tbl[i].id.pci_mask)) {
-+ chip_id = i; break;
-+ }
-+ }
-+ dev = tulip_probe1(pdev, NULL, ioaddr, irq, chip_id, 0);
- if (dev) {
- dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL);
- strcpy(node->dev_name, dev->name);
-@@ -3251,54 +3565,49 @@
-
- static void tulip_suspend(dev_node_t *node)
- {
-- struct device **devp, **next;
-+ struct net_device **devp, **next;
- printk(KERN_INFO "tulip_suspend(%s)\n", node->dev_name);
- for (devp = &root_tulip_dev; *devp; devp = next) {
- next = &((struct tulip_private *)(*devp)->priv)->next_module;
-- if (strcmp((*devp)->name, node->dev_name) == 0) break;
-- }
-- if (*devp) {
-- long ioaddr = (*devp)->base_addr;
-- struct tulip_private *tp = (struct tulip_private *)(*devp)->priv;
-- int csr6 = inl(ioaddr + CSR6);
-- /* Disable interrupts, stop the chip, gather stats. */
-- if (csr6 != 0xffffffff) {
-- outl(0x00000000, ioaddr + CSR7);
-- outl(csr6 & ~0x2002, ioaddr + CSR6);
-- tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
-+ if (strcmp((*devp)->name, node->dev_name) == 0) {
-+ tulip_pwr_event(*devp, DRV_SUSPEND);
-+ break;
- }
-- tulip_close(*devp);
-- /* Put the 21143 into sleep mode. */
-- pcibios_write_config_dword(tp->pci_bus,tp->pci_devfn, 0x40,0x80000000);
- }
- }
-
- static void tulip_resume(dev_node_t *node)
- {
-- struct device **devp, **next;
-+ struct net_device **devp, **next;
- printk(KERN_INFO "tulip_resume(%s)\n", node->dev_name);
- for (devp = &root_tulip_dev; *devp; devp = next) {
- next = &((struct tulip_private *)(*devp)->priv)->next_module;
-- if (strcmp((*devp)->name, node->dev_name) == 0) break;
-- }
-- if (*devp) {
-- struct tulip_private *tp = (struct tulip_private *)(*devp)->priv;
-- pcibios_write_config_dword(tp->pci_bus, tp->pci_devfn, 0x40, 0x0000);
-- tulip_open(*devp);
-+ if (strcmp((*devp)->name, node->dev_name) == 0) {
-+ tulip_pwr_event(*devp, DRV_RESUME);
-+ break;
-+ }
- }
- }
-
- static void tulip_detach(dev_node_t *node)
- {
-- struct device **devp, **next;
-+ struct net_device **devp, **next;
- printk(KERN_INFO "tulip_detach(%s)\n", node->dev_name);
- for (devp = &root_tulip_dev; *devp; devp = next) {
- next = &((struct tulip_private *)(*devp)->priv)->next_module;
- if (strcmp((*devp)->name, node->dev_name) == 0) break;
- }
- if (*devp) {
-+ struct tulip_private *tp = (struct tulip_private *)(*devp)->priv;
- unregister_netdev(*devp);
-+#ifdef USE_IO_OPS
-+ release_region((*devp)->base_addr, pci_id_tbl[DC21142].io_size);
-+#else
-+ iounmap((char *)(*devp)->base_addr);
-+#endif
- kfree(*devp);
-+ if (tp->priv_addr)
-+ kfree(tp->priv_addr);
- *devp = *next;
- kfree(node);
- MOD_DEC_USE_COUNT;
-@@ -3315,42 +3624,60 @@
- #ifdef MODULE
- int init_module(void)
- {
-+ if (debug >= NETIF_MSG_DRV) /* Emit version even if no cards detected. */
-+ printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2);
- #ifdef CARDBUS
-- reverse_probe = 0; /* Not used. */
- register_driver(&tulip_ops);
- return 0;
- #else
-- return tulip_probe(NULL);
-+ return pci_drv_register(&tulip_drv_id, NULL);
- #endif
-+ reverse_probe = 0; /* Not used. */
- }
-
- void cleanup_module(void)
- {
-- struct device *next_dev;
-+ struct net_device *next_dev;
-
- #ifdef CARDBUS
- unregister_driver(&tulip_ops);
-+#else
-+ pci_drv_unregister(&tulip_drv_id);
- #endif
-
- /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
- while (root_tulip_dev) {
-- struct tulip_private *tp = (struct tulip_private *)root_tulip_dev->priv;
-- next_dev = tp->next_module;
-+ struct tulip_private *tp = (struct tulip_private*)root_tulip_dev->priv;
- unregister_netdev(root_tulip_dev);
-+#ifdef USE_IO_OPS
- release_region(root_tulip_dev->base_addr,
-- tulip_tbl[tp->chip_id].io_size);
-+ pci_id_tbl[tp->chip_id].io_size);
-+#else
-+ iounmap((char *)root_tulip_dev->base_addr);
-+#endif
-+ next_dev = tp->next_module;
-+ if (tp->priv_addr)
-+ kfree(tp->priv_addr);
- kfree(root_tulip_dev);
- root_tulip_dev = next_dev;
- }
- }
--
-+#else
-+int tulip_probe(struct net_device *dev)
-+{
-+ if (pci_drv_register(&tulip_drv_id, dev) < 0)
-+ return -ENODEV;
-+ printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2);
-+ return 0;
-+ reverse_probe = 0; /* Not used. */
-+}
- #endif /* MODULE */
-
- /*
- * Local variables:
-- * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c tulip.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
-- * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c tulip.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
-- * cardbus-compile-command: "gcc -DCARDBUS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c tulip.c -o tulip_cb.o -I/usr/src/pcmcia-cs-3.0.9/include/"
-+ * compile-command: "make KERNVER=`uname -r` tulip.o"
-+ * compile-cmd: "gcc -DMODULE -Wall -Wstrict-prototypes -O6 -c tulip.c"
-+ * cardbus-compile-command: "gcc -DCARDBUS -DMODULE -Wall -Wstrict-prototypes -O6 -c tulip.c -o tulip_cb.o -I/usr/src/pcmcia/include/"
- * c-indent-level: 4
- * c-basic-offset: 4
- * tab-width: 4
-Index: linux/src/drivers/net/via-rhine.c
-===================================================================
-RCS file: /cvsroot/hurd/gnumach/linux/src/drivers/net/Attic/via-rhine.c,v
-retrieving revision 1.1
-diff -u -r1.1 via-rhine.c
---- linux/src/drivers/net/via-rhine.c 26 Apr 1999 05:52:45 -0000 1.1
-+++ linux/src/drivers/net/via-rhine.c 20 Aug 2004 10:32:54 -0000
-@@ -1,35 +1,54 @@
- /* via-rhine.c: A Linux Ethernet device driver for VIA Rhine family chips. */
- /*
-- Written 1998 by Donald Becker.
-+ Written 1998-2003 by Donald Becker.
-
-- This software may be used and distributed according to the terms
-- of the GNU Public License (GPL), incorporated herein by reference.
-- Drivers derived from this code also fall under the GPL and must retain
-- this authorship and copyright notice.
-+ This software may be used and distributed according to the terms of
-+ the GNU General Public License (GPL), incorporated herein by reference.
-+ Drivers based on or derived from this code fall under the GPL and must
-+ retain the authorship, copyright and license notice. This file is not
-+ a complete program and may only be used when the entire operating
-+ system is licensed under the GPL.
-
- This driver is designed for the VIA VT86c100A Rhine-II PCI Fast Ethernet
- controller. It also works with the older 3043 Rhine-I chip.
-
-- The author may be reached as becker@cesdis.edu, or
-- Donald Becker
-- 312 Severn Ave. #W302
-+ The author may be reached as becker@scyld.com, or C/O
-+ Scyld Computing Corporation
-+ 914 Bay Ridge Road, Suite 220
- Annapolis MD 21403
-
-- Support and updates available at
-- http://cesdis.gsfc.nasa.gov/linux/drivers/via-rhine.html
-+ Support information and updates available at
-+ http://www.scyld.com/network/via-rhine.html
-+ The information and support mailing lists are based at
-+ http://www.scyld.com/mailman/listinfo/
- */
-
--static const char *versionA =
--"via-rhine.c:v1.00 9/5/98 Written by Donald Becker\n";
--static const char *versionB =
--" http://cesdis.gsfc.nasa.gov/linux/drivers/via-rhine.html\n";
-+/* These identify the driver base version and may not be removed. */
-+static const char version1[] =
-+"via-rhine.c:v1.16 7/22/2003 Written by Donald Becker <becker@scyld.com>\n";
-+static const char version2[] =
-+" http://www.scyld.com/network/via-rhine.html\n";
-+
-+/* Automatically extracted configuration info:
-+probe-func: via_rhine_probe
-+config-in: tristate 'VIA "Rhine" vt86c100, vt3043, and vt3065 series PCI Ethernet support' CONFIG_VIA_RHINE
-+
-+c-help-name: VIA Rhine series PCI Ethernet support
-+c-help-symbol: CONFIG_VIA_RHINE
-+c-help: This driver is for the VIA Rhine (v3043) and Rhine-II
-+c-help: (vt3065 AKA vt86c100) network adapter chip series.
-+c-help: More specific information and updates are available from
-+c-help: http://www.scyld.com/network/via-rhine.html
-+*/
-+
-+/* The user-configurable values.
-+ These may be modified when a driver module is loaded.*/
-
--/* A few user-configurable values. These may be modified when a driver
-- module is loaded.*/
-+/* Message enable level: 0..31 = no..all messages. See NETIF_MSG docs. */
-+static int debug = 2;
-
--static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */
-+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
- static int max_interrupt_work = 20;
--static int min_pci_latency = 64;
-
- /* Set the copy breakpoint for the copy-only-tiny-frames scheme.
- Setting to > 1518 effectively disables this feature. */
-@@ -39,6 +58,11 @@
- Both 'options[]' and 'full_duplex[]' should exist for driver
- interoperability.
- The media type is usually passed in 'options[]'.
-+ The default is autonegotation for speed and duplex.
-+ This should rarely be overridden.
-+ Use option values 0x10/0x20 for 10Mbps, 0x100,0x200 for 100Mbps.
-+ Use option values 0x10 and 0x100 for forcing half duplex fixed speed.
-+ Use option values 0x20 and 0x200 for forcing full duplex operation.
- */
- #define MAX_UNITS 8 /* More are supported, limit only on options */
- static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-@@ -50,39 +74,57 @@
-
- /* Operational parameters that are set at compile time. */
-
--/* Keep the ring sizes a power of two for compile efficiency.
-- The compiler will convert <unsigned>'%'<2^N> into a bit mask.
-- Making the Tx ring too large decreases the effectiveness of channel
-+/* Making the Tx ring too large decreases the effectiveness of channel
- bonding and packet priority.
- There are no ill effects from too-large receive rings. */
--#define TX_RING_SIZE 8
--#define RX_RING_SIZE 16
-+#define TX_RING_SIZE 16
-+#define TX_QUEUE_LEN 10 /* Limit ring entries actually used. */
-+#define RX_RING_SIZE 32
-
- /* Operational parameters that usually are not changed. */
- /* Time in jiffies before concluding the transmitter is hung. */
--#define TX_TIMEOUT (2*HZ)
-+#define TX_TIMEOUT (6*HZ)
-
--#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/
-+/* Allocation size of Rx buffers with normal sized Ethernet frames.
-+ Do not change this value without good reason. This is not a limit,
-+ but a way to keep a consistent allocation size among drivers.
-+ */
-+#define PKT_BUF_SZ 1536
-+
-+#ifndef __KERNEL__
-+#define __KERNEL__
-+#endif
-+#if !defined(__OPTIMIZE__)
-+#warning You must compile this file with the correct options!
-+#warning See the last lines of the source file.
-+#error You must compile this driver with "-O".
-+#endif
-
- /* Include files, designed to support most kernel versions 2.0.0 and later. */
- #include <linux/config.h>
-+#if defined(CONFIG_SMP) && ! defined(__SMP__)
-+#define __SMP__
-+#endif
-+#if defined(MODULE) && defined(CONFIG_MODVERSIONS) && ! defined(MODVERSIONS)
-+#define MODVERSIONS
-+#endif
-+
- #include <linux/version.h>
--#ifdef MODULE
--#ifdef MODVERSIONS
-+#if defined(MODVERSIONS)
- #include <linux/modversions.h>
- #endif
- #include <linux/module.h>
--#else
--#define MOD_INC_USE_COUNT
--#define MOD_DEC_USE_COUNT
--#endif
-
- #include <linux/kernel.h>
- #include <linux/string.h>
- #include <linux/timer.h>
- #include <linux/errno.h>
- #include <linux/ioport.h>
-+#if LINUX_VERSION_CODE >= 0x20400
-+#include <linux/slab.h>
-+#else
- #include <linux/malloc.h>
-+#endif
- #include <linux/interrupt.h>
- #include <linux/pci.h>
- #include <linux/netdevice.h>
-@@ -92,10 +134,24 @@
- #include <asm/bitops.h>
- #include <asm/io.h>
-
--/* This driver was written to use PCI memory space, however some boards
-- only work with I/O space accesses. */
--#define VIA_USE_IO
--#ifdef VIA_USE_IO
-+#ifdef INLINE_PCISCAN
-+#include "k_compat.h"
-+#else
-+#include "pci-scan.h"
-+#include "kern_compat.h"
-+#endif
-+
-+/* Condensed bus+endian portability operations. */
-+#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr))
-+#define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr))
-+
-+/* This driver was written to use PCI memory space, however most versions
-+ of the Rhine only work correctly with I/O space accesses. */
-+#if defined(VIA_USE_MEMORY)
-+#warning Many adapters using the VIA Rhine chip are not configured to work
-+#warning with PCI memory space accesses.
-+#else
-+#define USE_IO_OPS
- #undef readb
- #undef readw
- #undef readl
-@@ -110,50 +166,29 @@
- #define writel outl
- #endif
-
--/* Kernel compatibility defines, some common to David Hind's PCMCIA package.
-- This is only in the support-all-kernels source code. */
--
--#define RUN_AT(x) (jiffies + (x))
--
--#if (LINUX_VERSION_CODE >= 0x20100)
-+#if (LINUX_VERSION_CODE >= 0x20100) && defined(MODULE)
- char kernel_version[] = UTS_RELEASE;
--#else
--#ifndef __alpha__
--#define ioremap vremap
--#define iounmap vfree
--#endif
- #endif
--#if defined(MODULE) && LINUX_VERSION_CODE > 0x20115
--MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
-+
-+MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
- MODULE_DESCRIPTION("VIA Rhine PCI Fast Ethernet driver");
-+MODULE_LICENSE("GPL");
- MODULE_PARM(max_interrupt_work, "i");
--MODULE_PARM(min_pci_latency, "i");
- MODULE_PARM(debug, "i");
- MODULE_PARM(rx_copybreak, "i");
- MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
- MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
--#endif
--#if LINUX_VERSION_CODE < 0x20123
--#define test_and_set_bit(val, addr) set_bit(val, addr)
--#endif
--#if LINUX_VERSION_CODE <= 0x20139
--#define net_device_stats enet_statistics
--#else
--#define NETSTATS_VER2
--#endif
--#if LINUX_VERSION_CODE < 0x20155 || defined(CARDBUS)
--/* Grrrr, the PCI code changed, but did not consider CardBus... */
--#include <linux/bios32.h>
--#define PCI_SUPPORT_VER1
--#else
--#define PCI_SUPPORT_VER2
--#endif
--#if LINUX_VERSION_CODE < 0x20159
--#define dev_free_skb(skb) dev_kfree_skb(skb, FREE_WRITE);
--#else
--#define dev_free_skb(skb) dev_kfree_skb(skb);
--#endif
--
-+MODULE_PARM(multicast_filter_limit, "i");
-+MODULE_PARM_DESC(debug, "Driver message level (0-31)");
-+MODULE_PARM_DESC(options, "Force transceiver type or fixed speed+duplex");
-+MODULE_PARM_DESC(max_interrupt_work,
-+ "Driver maximum events handled per interrupt");
-+MODULE_PARM_DESC(full_duplex, "Non-zero to set forced full duplex "
-+ "(deprecated, use options[] instead).");
-+MODULE_PARM_DESC(rx_copybreak,
-+ "Breakpoint in bytes for copy-only-tiny-frames");
-+MODULE_PARM_DESC(multicast_filter_limit,
-+ "Multicast addresses before switching to Rx-all-multicast");
-
- /*
- Theory of Operation
-@@ -230,63 +265,72 @@
-
- IVb. References
-
--Preliminary VT86C100A manual from http://www.via.com.tw/
--http://cesdis.gsfc.nasa.gov/linux/misc/100mbps.html
--http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html
-+This driver was originally written using a preliminary VT86C100A manual
-+from
-+ http://www.via.com.tw/
-+The usual background material was used:
-+ http://www.scyld.com/expert/100mbps.html
-+ http://scyld.com/expert/NWay.html
-+
-+Additional information is now available, especially for the newer chips.
-+ http://www.via.com.tw/en/Networking/DS6105LOM100.pdf
-
- IVc. Errata
-
- The VT86C100A manual is not reliable information.
--The chip does not handle unaligned transmit or receive buffers, resulting
--in significant performance degradation for bounce buffer copies on transmit
--and unaligned IP headers on receive.
-+The 3043 chip does not handle unaligned transmit or receive buffers,
-+resulting in significant performance degradation for bounce buffer
-+copies on transmit and unaligned IP headers on receive.
- The chip does not pad to minimum transmit length.
-
-+There is a bug with the transmit descriptor pointer handling when the
-+chip encounters a transmit error.
-+
- */
-
-
-
--/* This table drives the PCI probe routines. It's mostly boilerplate in all
-- of the drivers, and will likely be provided by some future kernel.
-- Note the matching code -- the first table entry matchs all 56** cards but
-- second only the 1234 card.
--*/
--enum pci_flags_bit {
-- PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
-- PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
--};
--struct pci_id_info {
-- const char *name;
-- u16 vendor_id, device_id, device_id_mask, flags;
-- int io_size;
-- struct device *(*probe1)(int pci_bus, int pci_devfn, struct device *dev,
-- long ioaddr, int irq, int chip_idx, int fnd_cnt);
-+static void *via_probe1(struct pci_dev *pdev, void *init_dev,
-+ long ioaddr, int irq, int chip_idx, int find_cnt);
-+static int via_pwr_event(void *dev_instance, int event);
-+enum chip_capability_flags {
-+ CanHaveMII=1, HasESIPhy=2, HasDavicomPhy=4, HasV1TxStat=8,
-+ ReqTxAlign=0x10, HasWOL=0x20, HasIPChecksum=0x40, HasVLAN=0x80,
-+
- };
-
--static struct device *via_probe1(int pci_bus, int pci_devfn,
-- struct device *dev, long ioaddr, int irq,
-- int chp_idx, int fnd_cnt);
-+#if defined(VIA_USE_MEMORY)
-+#define RHINE_IOTYPE (PCI_USES_MEM | PCI_USES_MASTER | PCI_ADDR1)
-+#define RHINE_I_IOSIZE 128
-+#define RHINEII_IOSIZE 4096
-+#else
-+#define RHINE_IOTYPE (PCI_USES_IO | PCI_USES_MASTER | PCI_ADDR0)
-+#define RHINE_I_IOSIZE 128
-+#define RHINEII_IOSIZE 256
-+#endif
-
- static struct pci_id_info pci_tbl[] = {
-- { "VIA VT86C100A Rhine-II", 0x1106, 0x6100, 0xffff,
-- PCI_USES_MEM|PCI_USES_IO|PCI_USES_MEM|PCI_USES_MASTER, 128, via_probe1},
-- { "VIA VT3043 Rhine", 0x1106, 0x3043, 0xffff,
-- PCI_USES_IO|PCI_USES_MEM|PCI_USES_MASTER, 128, via_probe1},
-+ { "VIA VT3043 Rhine", { 0x30431106, 0xffffffff,},
-+ RHINE_IOTYPE, RHINE_I_IOSIZE, CanHaveMII | ReqTxAlign | HasV1TxStat },
-+ { "VIA VT86C100A Rhine", { 0x61001106, 0xffffffff,},
-+ RHINE_IOTYPE, RHINE_I_IOSIZE, CanHaveMII | ReqTxAlign | HasV1TxStat },
-+ { "VIA VT6102 Rhine-II", { 0x30651106, 0xffffffff,},
-+ RHINE_IOTYPE, RHINEII_IOSIZE, CanHaveMII | HasWOL },
-+ { "VIA VT6105LOM Rhine-III (3106)", { 0x31061106, 0xffffffff,},
-+ RHINE_IOTYPE, RHINEII_IOSIZE, CanHaveMII | HasWOL },
-+ /* Duplicate entry, with 'M' features enabled. */
-+ { "VIA VT6105M Rhine-III (3106)", { 0x31061106, 0xffffffff,},
-+ RHINE_IOTYPE, RHINEII_IOSIZE, CanHaveMII|HasWOL|HasIPChecksum|HasVLAN},
-+ { "VIA VT6105M Rhine-III (3053 prototype)", { 0x30531106, 0xffffffff,},
-+ RHINE_IOTYPE, RHINEII_IOSIZE, CanHaveMII | HasWOL },
- {0,}, /* 0 terminated list. */
- };
-
--
--/* A chip capabilities table, matching the entries in pci_tbl[] above. */
--enum chip_capability_flags {CanHaveMII=1, };
--struct chip_info {
-- int io_size;
-- int flags;
--} static cap_tbl[] = {
-- {128, CanHaveMII, },
-- {128, CanHaveMII, },
-+struct drv_id_info via_rhine_drv_id = {
-+ "via-rhine", PCI_HOTSWAP, PCI_CLASS_NETWORK_ETHERNET<<8, pci_tbl,
-+ via_probe1, via_pwr_event
- };
-
--
- /* Offsets to the device registers.
- */
- enum register_offsets {
-@@ -294,9 +338,10 @@
- IntrStatus=0x0C, IntrEnable=0x0E,
- MulticastFilter0=0x10, MulticastFilter1=0x14,
- RxRingPtr=0x18, TxRingPtr=0x1C,
-- MIIPhyAddr=0x6C, MIIStatus=0x6D, PCIConfig=0x6E,
-- MIICmd=0x70, MIIRegAddr=0x71, MIIData=0x72,
-- Config=0x78, RxMissed=0x7C, RxCRCErrs=0x7E,
-+ MIIPhyAddr=0x6C, MIIStatus=0x6D, PCIBusConfig=0x6E,
-+ MIICmd=0x70, MIIRegAddr=0x71, MIIData=0x72, MACRegEEcsr=0x74,
-+ Config=0x78, ConfigA=0x7A, RxMissed=0x7C, RxCRCErrs=0x7E,
-+ StickyHW=0x83, WOLcrClr=0xA4, WOLcgClr=0xA7, PwrcsrClr=0xAC,
- };
-
- /* Bits in the interrupt status/mask registers. */
-@@ -308,21 +353,18 @@
- IntrRxOverflow=0x0400, IntrRxDropped=0x0800, IntrRxNoBuf=0x1000,
- IntrTxAborted=0x2000, IntrLinkChange=0x4000,
- IntrRxWakeUp=0x8000,
-- IntrNormalSummary=0x0003, IntrAbnormalSummary=0x8260,
-+ IntrNormalSummary=0x0003, IntrAbnormalSummary=0xC260,
- };
-
--
- /* The Rx and Tx buffer descriptors. */
- struct rx_desc {
-- u16 rx_status;
-- u16 rx_length;
-+ s32 rx_status;
- u32 desc_length;
- u32 addr;
- u32 next_desc;
- };
- struct tx_desc {
-- u16 tx_status;
-- u16 tx_own;
-+ s32 tx_status;
- u32 desc_length;
- u32 addr;
- u32 next_desc;
-@@ -330,9 +372,19 @@
-
- /* Bits in *_desc.status */
- enum rx_status_bits {
-- RxDescOwn=0x80000000, RxOK=0x8000, RxWholePkt=0x0300, RxErr=0x008F};
-+ RxOK=0x8000, RxWholePkt=0x0300, RxErr=0x008F};
- enum desc_status_bits {
-- DescOwn=0x8000, DescEndPacket=0x4000, DescIntr=0x1000,
-+ DescOwn=0x80000000, DescEndPacket=0x4000, DescIntr=0x1000,
-+};
-+
-+/* Bits in rx.desc_length for extended status. */
-+enum rx_info_bits {
-+ RxTypeTag=0x00010000,
-+ RxTypeUDP=0x00020000, RxTypeTCP=0x00040000, RxTypeIP=0x00080000,
-+ RxTypeUTChksumOK=0x00100000, RxTypeIPChksumOK=0x00200000,
-+ /* Summarized. */
-+ RxTypeCsumMask=0x003E0000,
-+ RxTypeUDPSumOK=0x003A0000, RxTypeTCPSumOK=0x003C0000,
- };
-
- /* Bits in ChipCmd. */
-@@ -343,6 +395,9 @@
- CmdNoTxPoll=0x0800, CmdReset=0x8000,
- };
-
-+#define PRIV_ALIGN 15 /* Required alignment mask */
-+/* Use __attribute__((aligned (L1_CACHE_BYTES))) to maintain alignment
-+ within the structure. */
- struct netdev_private {
- /* Descriptor rings first for alignment. */
- struct rx_desc rx_ring[RX_RING_SIZE];
-@@ -353,24 +408,34 @@
- struct sk_buff* tx_skbuff[TX_RING_SIZE];
- unsigned char *tx_buf[TX_RING_SIZE]; /* Tx bounce buffers */
- unsigned char *tx_bufs; /* Tx bounce buffer region. */
-- struct device *next_module; /* Link for devices of this type. */
-+ struct net_device *next_module; /* Link for devices of this type. */
-+ void *priv_addr; /* Unaligned address for kfree */
- struct net_device_stats stats;
- struct timer_list timer; /* Media monitoring timer. */
-- unsigned char pci_bus, pci_devfn;
-+ int msg_level;
-+ int max_interrupt_work;
-+ int intr_enable;
-+ int chip_id, drv_flags;
-+ struct pci_dev *pci_dev;
-+
- /* Frequently used values: keep some adjacent for cache effect. */
-- int chip_id;
-- long in_interrupt; /* Word-long for SMP locks. */
-+
- struct rx_desc *rx_head_desc;
- unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */
-- unsigned int cur_tx, dirty_tx;
- unsigned int rx_buf_sz; /* Based on MTU+slack. */
-+ int rx_copybreak;
-+
-+ unsigned int cur_tx, dirty_tx;
- u16 chip_cmd; /* Current setting for ChipCmd */
-+ int multicast_filter_limit;
-+ u32 mc_filter[2];
-+ int rx_mode;
- unsigned int tx_full:1; /* The Tx queue is full. */
- /* These values are keep track of the transceiver/media in use. */
- unsigned int full_duplex:1; /* Full-duplex operation requested. */
- unsigned int duplex_lock:1;
- unsigned int medialock:1; /* Do not sense media. */
-- unsigned int default_port:4; /* Last dev->if_port value. */
-+ unsigned int default_port; /* Last dev->if_port value. */
- u8 tx_thresh, rx_thresh;
- /* MII transceiver section. */
- int mii_cnt; /* MII device addresses. */
-@@ -378,171 +443,81 @@
- unsigned char phys[2]; /* MII device addresses. */
- };
-
--static int mdio_read(struct device *dev, int phy_id, int location);
--static void mdio_write(struct device *dev, int phy_id, int location, int value);
--static int netdev_open(struct device *dev);
--static void check_duplex(struct device *dev);
-+static int mdio_read(struct net_device *dev, int phy_id, int location);
-+static void mdio_write(struct net_device *dev, int phy_id, int location, int value);
-+static int netdev_open(struct net_device *dev);
-+static void check_duplex(struct net_device *dev);
- static void netdev_timer(unsigned long data);
--static void tx_timeout(struct device *dev);
--static void init_ring(struct device *dev);
--static int start_tx(struct sk_buff *skb, struct device *dev);
-+static void tx_timeout(struct net_device *dev);
-+static void init_ring(struct net_device *dev);
-+static int start_tx(struct sk_buff *skb, struct net_device *dev);
- static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs);
--static int netdev_rx(struct device *dev);
--static void netdev_error(struct device *dev, int intr_status);
--static void set_rx_mode(struct device *dev);
--static struct net_device_stats *get_stats(struct device *dev);
--static int mii_ioctl(struct device *dev, struct ifreq *rq, int cmd);
--static int netdev_close(struct device *dev);
-+static int netdev_rx(struct net_device *dev);
-+static void netdev_error(struct net_device *dev, int intr_status);
-+static void set_rx_mode(struct net_device *dev);
-+static struct net_device_stats *get_stats(struct net_device *dev);
-+static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-+static int netdev_close(struct net_device *dev);
-
-
-
- /* A list of our installed devices, for removing the driver module. */
--static struct device *root_net_dev = NULL;
--
--/* Ideally we would detect all network cards in slot order. That would
-- be best done a central PCI probe dispatch, which wouldn't work
-- well when dynamically adding drivers. So instead we detect just the
-- cards we know about in slot order. */
--
--static int pci_etherdev_probe(struct device *dev, struct pci_id_info pci_tbl[])
--{
-- int cards_found = 0;
-- int pci_index = 0;
-- unsigned char pci_bus, pci_device_fn;
--
-- if ( ! pcibios_present())
-- return -ENODEV;
--
-- for (;pci_index < 0xff; pci_index++) {
-- u16 vendor, device, pci_command, new_command;
-- int chip_idx, irq;
-- long pciaddr;
-- long ioaddr;
--
-- if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pci_index,
-- &pci_bus, &pci_device_fn)
-- != PCIBIOS_SUCCESSFUL)
-- break;
-- pcibios_read_config_word(pci_bus, pci_device_fn,
-- PCI_VENDOR_ID, &vendor);
-- pcibios_read_config_word(pci_bus, pci_device_fn,
-- PCI_DEVICE_ID, &device);
--
-- for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++)
-- if (vendor == pci_tbl[chip_idx].vendor_id
-- && (device & pci_tbl[chip_idx].device_id_mask) ==
-- pci_tbl[chip_idx].device_id)
-- break;
-- if (pci_tbl[chip_idx].vendor_id == 0) /* Compiled out! */
-- continue;
--
-- {
--#if defined(PCI_SUPPORT_VER2)
-- struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
--#ifdef VIA_USE_IO
-- pciaddr = pdev->base_address[0];
--#else
-- pciaddr = pdev->base_address[1];
--#endif
-- irq = pdev->irq;
--#else
-- u32 pci_memaddr;
-- u8 pci_irq_line;
-- pcibios_read_config_byte(pci_bus, pci_device_fn,
-- PCI_INTERRUPT_LINE, &pci_irq_line);
--#ifdef VIA_USE_IO
-- pcibios_read_config_dword(pci_bus, pci_device_fn,
-- PCI_BASE_ADDRESS_0, &pci_memaddr);
-- pciaddr = pci_memaddr;
--#else
-- pcibios_read_config_dword(pci_bus, pci_device_fn,
-- PCI_BASE_ADDRESS_1, &pci_memaddr);
-- pciaddr = pci_memaddr;
--#endif
-- irq = pci_irq_line;
--#endif
-- }
--
-- if (debug > 2)
-- printk(KERN_INFO "Found %s at PCI address %#lx, IRQ %d.\n",
-- pci_tbl[chip_idx].name, pciaddr, irq);
--
-- if (pci_tbl[chip_idx].flags & PCI_USES_IO) {
-- if (check_region(pciaddr, pci_tbl[chip_idx].io_size))
-- continue;
-- ioaddr = pciaddr & ~3;
-- } else if ((ioaddr = (long)ioremap(pciaddr & ~0xf,
-- pci_tbl[chip_idx].io_size)) == 0) {
-- printk(KERN_INFO "Failed to map PCI address %#lx.\n",
-- pciaddr);
-- continue;
-- }
--
-- pcibios_read_config_word(pci_bus, pci_device_fn,
-- PCI_COMMAND, &pci_command);
-- new_command = pci_command | (pci_tbl[chip_idx].flags & 7);
-- if (pci_command != new_command) {
-- printk(KERN_INFO " The PCI BIOS has not enabled the"
-- " device at %d/%d! Updating PCI command %4.4x->%4.4x.\n",
-- pci_bus, pci_device_fn, pci_command, new_command);
-- pcibios_write_config_word(pci_bus, pci_device_fn,
-- PCI_COMMAND, new_command);
-- }
--
-- dev = pci_tbl[chip_idx].probe1(pci_bus, pci_device_fn, dev, ioaddr,
-- irq, chip_idx, cards_found);
--
-- if (dev && (pci_tbl[chip_idx].flags & PCI_COMMAND_MASTER)) {
-- u8 pci_latency;
-- pcibios_read_config_byte(pci_bus, pci_device_fn,
-- PCI_LATENCY_TIMER, &pci_latency);
-- if (pci_latency < min_pci_latency) {
-- printk(KERN_INFO " PCI latency timer (CFLT) is "
-- "unreasonably low at %d. Setting to %d clocks.\n",
-- pci_latency, min_pci_latency);
-- pcibios_write_config_byte(pci_bus, pci_device_fn,
-- PCI_LATENCY_TIMER, min_pci_latency);
-- }
-- }
-- dev = 0;
-- cards_found++;
-- }
--
-- return cards_found ? 0 : -ENODEV;
--}
-+static struct net_device *root_net_dev = NULL;
-
- #ifndef MODULE
--int via_rhine_probe(struct device *dev)
-+int via_rhine_probe(struct net_device *dev)
- {
-- return pci_etherdev_probe(dev, pci_tbl);
-+ printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2);
-+ return pci_drv_register(&via_rhine_drv_id, dev);
- }
- #endif
-
--static struct device *via_probe1(int pci_bus, int pci_devfn,
-- struct device *dev, long ioaddr, int irq,
-- int chip_id, int card_idx)
-+static void *via_probe1(struct pci_dev *pdev, void *init_dev,
-+ long ioaddr, int irq, int chip_idx, int card_idx)
- {
-- static int did_version = 0; /* Already printed version info */
-+ struct net_device *dev;
- struct netdev_private *np;
-+ void *priv_mem;
- int i, option = card_idx < MAX_UNITS ? options[card_idx] : 0;
-
-- if (debug > 0 && did_version++ == 0)
-- printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB);
--
-- dev = init_etherdev(dev, 0);
-+ dev = init_etherdev(init_dev, 0);
-+ if (!dev)
-+ return NULL;
-
- printk(KERN_INFO "%s: %s at 0x%lx, ",
-- dev->name, pci_tbl[chip_id].name, ioaddr);
-+ dev->name, pci_tbl[chip_idx].name, ioaddr);
-
-- /* Ideally we would be read the EEPROM but access may be locked. */
-- for (i = 0; i <6; i++)
-+ /* We would prefer to directly read the EEPROM but access may be locked. */
-+ for (i = 0; i < 6; i++)
- dev->dev_addr[i] = readb(ioaddr + StationAddr + i);
-+ if (memcmp(dev->dev_addr, "\0\0\0\0\0", 6) == 0) {
-+ /* Reload the station address from the EEPROM. */
-+ writeb(0x20, ioaddr + MACRegEEcsr);
-+ /* Typically 2 cycles to reload. */
-+ for (i = 0; i < 150; i++)
-+ if (! (readb(ioaddr + MACRegEEcsr) & 0x20))
-+ break;
-+ for (i = 0; i < 6; i++)
-+ dev->dev_addr[i] = readb(ioaddr + StationAddr + i);
-+ if (memcmp(dev->dev_addr, "\0\0\0\0\0", 6) == 0) {
-+ printk(" (MISSING EEPROM ADDRESS)");
-+ /* Fill a temp addr with the "locally administered" bit set. */
-+ memcpy(dev->dev_addr, ">Linux", 6);
-+ }
-+ }
-+
- for (i = 0; i < 5; i++)
-- printk("%2.2x:", dev->dev_addr[i]);
-+ printk("%2.2x:", dev->dev_addr[i]);
- printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);
-
--#ifdef VIA_USE_IO
-- request_region(ioaddr, pci_tbl[chip_id].io_size, dev->name);
-+ /* Make certain the descriptor lists are cache-aligned. */
-+ priv_mem = kmalloc(sizeof(*np) + PRIV_ALIGN, GFP_KERNEL);
-+ /* Check for the very unlikely case of no memory. */
-+ if (priv_mem == NULL)
-+ return NULL;
-+
-+#ifdef USE_IO_OPS
-+ request_region(ioaddr, pci_tbl[chip_idx].io_size, dev->name);
- #endif
-
- /* Reset the chip to erase previous misconfiguration. */
-@@ -551,24 +526,27 @@
- dev->base_addr = ioaddr;
- dev->irq = irq;
-
-- /* Make certain the descriptor lists are cache-aligned. */
-- np = (void *)(((long)kmalloc(sizeof(*np), GFP_KERNEL) + 31) & ~31);
-+ dev->priv = np = (void *)(((long)priv_mem + PRIV_ALIGN) & ~PRIV_ALIGN);
- memset(np, 0, sizeof(*np));
-- dev->priv = np;
-+ np->priv_addr = priv_mem;
-
- np->next_module = root_net_dev;
- root_net_dev = dev;
-
-- np->pci_bus = pci_bus;
-- np->pci_devfn = pci_devfn;
-- np->chip_id = chip_id;
-+ np->pci_dev = pdev;
-+ np->chip_id = chip_idx;
-+ np->drv_flags = pci_tbl[chip_idx].drv_flags;
-+ np->msg_level = (1 << debug) - 1;
-+ np->rx_copybreak = rx_copybreak;
-+ np->max_interrupt_work = max_interrupt_work;
-+ np->multicast_filter_limit = multicast_filter_limit;
-
- if (dev->mem_start)
- option = dev->mem_start;
-
- /* The lower four bits are the media type. */
- if (option > 0) {
-- if (option & 0x200)
-+ if (option & 0x220)
- np->full_duplex = 1;
- np->default_port = option & 15;
- if (np->default_port)
-@@ -577,8 +555,11 @@
- if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0)
- np->full_duplex = 1;
-
-- if (np->full_duplex)
-+ if (np->full_duplex) {
-+ printk(KERN_INFO "%s: Set to forced full duplex, autonegotiation"
-+ " disabled.\n", dev->name);
- np->duplex_lock = 1;
-+ }
-
- /* The chip-specific entries in the device structure. */
- dev->open = &netdev_open;
-@@ -588,7 +569,7 @@
- dev->set_multicast_list = &set_rx_mode;
- dev->do_ioctl = &mii_ioctl;
-
-- if (cap_tbl[np->chip_id].flags & CanHaveMII) {
-+ if (np->drv_flags & CanHaveMII) {
- int phy, phy_idx = 0;
- np->phys[0] = 1; /* Standard for this chip. */
- for (phy = 1; phy < 32 && phy_idx < 4; phy++) {
-@@ -605,13 +586,30 @@
- np->mii_cnt = phy_idx;
- }
-
-+ /* Allow forcing the media type. */
-+ if (option > 0) {
-+ if (option & 0x220)
-+ np->full_duplex = 1;
-+ np->default_port = option & 0x3ff;
-+ if (np->default_port & 0x330) {
-+ np->medialock = 1;
-+ printk(KERN_INFO " Forcing %dMbs %s-duplex operation.\n",
-+ (option & 0x300 ? 100 : 10),
-+ (np->full_duplex ? "full" : "half"));
-+ if (np->mii_cnt)
-+ mdio_write(dev, np->phys[0], 0,
-+ ((option & 0x300) ? 0x2000 : 0) | /* 100mbps? */
-+ (np->full_duplex ? 0x0100 : 0)); /* Full duplex? */
-+ }
-+ }
-+
- return dev;
- }
-
-
- /* Read and write over the MII Management Data I/O (MDIO) interface. */
-
--static int mdio_read(struct device *dev, int phy_id, int regnum)
-+static int mdio_read(struct net_device *dev, int phy_id, int regnum)
- {
- long ioaddr = dev->base_addr;
- int boguscnt = 1024;
-@@ -629,11 +627,23 @@
- return readw(ioaddr + MIIData);
- }
-
--static void mdio_write(struct device *dev, int phy_id, int regnum, int value)
-+static void mdio_write(struct net_device *dev, int phy_id, int regnum, int value)
- {
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
- long ioaddr = dev->base_addr;
- int boguscnt = 1024;
-
-+ if (phy_id == np->phys[0]) {
-+ switch (regnum) {
-+ case 0: /* Is user forcing speed/duplex? */
-+ if (value & 0x9000) /* Autonegotiation. */
-+ np->duplex_lock = 0;
-+ else
-+ np->full_duplex = (value & 0x0100) ? 1 : 0;
-+ break;
-+ case 4: np->advertising = value; break;
-+ }
-+ }
- /* Wait for a previous command to complete. */
- while ((readb(ioaddr + MIICmd) & 0x60) && --boguscnt > 0)
- ;
-@@ -646,7 +656,7 @@
- }
-
-
--static int netdev_open(struct device *dev)
-+static int netdev_open(struct net_device *dev)
- {
- struct netdev_private *np = (struct netdev_private *)dev->priv;
- long ioaddr = dev->base_addr;
-@@ -655,15 +665,17 @@
- /* Reset the chip. */
- writew(CmdReset, ioaddr + ChipCmd);
-
-- if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev))
-+ MOD_INC_USE_COUNT;
-+
-+ if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev)) {
-+ MOD_DEC_USE_COUNT;
- return -EAGAIN;
-+ }
-
-- if (debug > 1)
-+ if (np->msg_level & NETIF_MSG_IFUP)
- printk(KERN_DEBUG "%s: netdev_open() irq %d.\n",
- dev->name, dev->irq);
-
-- MOD_INC_USE_COUNT;
--
- init_ring(dev);
-
- writel(virt_to_bus(np->rx_ring), ioaddr + RxRingPtr);
-@@ -673,7 +685,7 @@
- writeb(dev->dev_addr[i], ioaddr + StationAddr + i);
-
- /* Initialize other registers. */
-- writew(0x0006, ioaddr + PCIConfig); /* Tune configuration??? */
-+ writew(0x0006, ioaddr + PCIBusConfig); /* Tune configuration??? */
- /* Configure the FIFO thresholds. */
- writeb(0x20, ioaddr + TxConfig); /* Initial threshold 32 bytes */
- np->tx_thresh = 0x20;
-@@ -682,26 +694,29 @@
- if (dev->if_port == 0)
- dev->if_port = np->default_port;
-
-- dev->tbusy = 0;
-- dev->interrupt = 0;
-- np->in_interrupt = 0;
--
- set_rx_mode(dev);
-+ netif_start_tx_queue(dev);
-
-- dev->start = 1;
--
-+ np->intr_enable = IntrRxDone | IntrRxErr | IntrRxEmpty |
-+ IntrRxOverflow| IntrRxDropped| IntrTxDone | IntrTxAbort |
-+ IntrTxUnderrun | IntrPCIErr | IntrStatsMax | IntrLinkChange |
-+ IntrMIIChange;
- /* Enable interrupts by setting the interrupt mask. */
-- writew(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow| IntrRxDropped|
-- IntrTxDone | IntrTxAbort | IntrTxUnderrun |
-- IntrPCIErr | IntrStatsMax | IntrLinkChange | IntrMIIChange,
-- ioaddr + IntrEnable);
-+ writew(np->intr_enable, ioaddr + IntrEnable);
-
- np->chip_cmd = CmdStart|CmdTxOn|CmdRxOn|CmdNoTxPoll;
-+ if (np->duplex_lock)
-+ np->chip_cmd |= CmdFDuplex;
- writew(np->chip_cmd, ioaddr + ChipCmd);
-
- check_duplex(dev);
-+ /* The LED outputs of various MII xcvrs should be configured. */
-+ /* For NS or Mison phys, turn on bit 1 in register 0x17 */
-+ /* For ESI phys, turn on bit 7 in register 0x17. */
-+ mdio_write(dev, np->phys[0], 0x17, mdio_read(dev, np->phys[0], 0x17) |
-+ (np->drv_flags & HasESIPhy) ? 0x0080 : 0x0001);
-
-- if (debug > 2)
-+ if (np->msg_level & NETIF_MSG_IFUP)
- printk(KERN_DEBUG "%s: Done netdev_open(), status %4.4x "
- "MII status: %4.4x.\n",
- dev->name, readw(ioaddr + ChipCmd),
-@@ -709,7 +724,7 @@
-
- /* Set the timer to check for link beat. */
- init_timer(&np->timer);
-- np->timer.expires = RUN_AT(1);
-+ np->timer.expires = jiffies + 2;
- np->timer.data = (unsigned long)dev;
- np->timer.function = &netdev_timer; /* timer handler */
- add_timer(&np->timer);
-@@ -717,19 +732,20 @@
- return 0;
- }
-
--static void check_duplex(struct device *dev)
-+static void check_duplex(struct net_device *dev)
- {
- struct netdev_private *np = (struct netdev_private *)dev->priv;
- long ioaddr = dev->base_addr;
- int mii_reg5 = mdio_read(dev, np->phys[0], 5);
-+ int negotiated = mii_reg5 & np->advertising;
- int duplex;
-
- if (np->duplex_lock || mii_reg5 == 0xffff)
- return;
-- duplex = (mii_reg5 & 0x0100) || (mii_reg5 & 0x01C0) == 0x0040;
-+ duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;
- if (np->full_duplex != duplex) {
- np->full_duplex = duplex;
-- if (debug)
-+ if (np->msg_level & NETIF_MSG_LINK)
- printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d link"
- " partner capability of %4.4x.\n", dev->name,
- duplex ? "full" : "half", np->phys[0], mii_reg5);
-@@ -743,22 +759,27 @@
-
- static void netdev_timer(unsigned long data)
- {
-- struct device *dev = (struct device *)data;
-+ struct net_device *dev = (struct net_device *)data;
- struct netdev_private *np = (struct netdev_private *)dev->priv;
- long ioaddr = dev->base_addr;
- int next_tick = 10*HZ;
-
-- if (debug > 3) {
-+ if (np->msg_level & NETIF_MSG_TIMER) {
- printk(KERN_DEBUG "%s: VIA Rhine monitor tick, status %4.4x.\n",
- dev->name, readw(ioaddr + IntrStatus));
- }
-+ if (netif_queue_paused(dev)
-+ && np->cur_tx - np->dirty_tx > 1
-+ && jiffies - dev->trans_start > TX_TIMEOUT)
-+ tx_timeout(dev);
-+
- check_duplex(dev);
-
-- np->timer.expires = RUN_AT(next_tick);
-+ np->timer.expires = jiffies + next_tick;
- add_timer(&np->timer);
- }
-
--static void tx_timeout(struct device *dev)
-+static void tx_timeout(struct net_device *dev)
- {
- struct netdev_private *np = (struct netdev_private *)dev->priv;
- long ioaddr = dev->base_addr;
-@@ -768,20 +789,23 @@
- dev->name, readw(ioaddr + IntrStatus),
- mdio_read(dev, np->phys[0], 1));
-
-- /* Perhaps we should reinitialize the hardware here. */
-- dev->if_port = 0;
-- /* Stop and restart the chip's Tx processes . */
--
-- /* Trigger an immediate transmit demand. */
--
-- dev->trans_start = jiffies;
-- np->stats.tx_errors++;
-- return;
-+ /* Perhaps we should reinitialize the hardware here. */
-+ dev->if_port = 0;
-+ /* Restart the chip's Tx processes . */
-+ writel(virt_to_bus(np->tx_ring + (np->dirty_tx % TX_RING_SIZE)),
-+ ioaddr + TxRingPtr);
-+ writew(CmdTxDemand | np->chip_cmd, dev->base_addr + ChipCmd);
-+
-+ /* Trigger an immediate transmit demand. */
-+
-+ dev->trans_start = jiffies;
-+ np->stats.tx_errors++;
-+ return;
- }
-
-
- /* Initialize the Rx and Tx rings, along with various 'dev' bits. */
--static void init_ring(struct device *dev)
-+static void init_ring(struct net_device *dev)
- {
- struct netdev_private *np = (struct netdev_private *)dev->priv;
- int i;
-@@ -790,93 +814,105 @@
- np->cur_rx = np->cur_tx = 0;
- np->dirty_rx = np->dirty_tx = 0;
-
-- np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);
-+ /* Use 1518/+18 if the CRC is transferred. */
-+ np->rx_buf_sz = dev->mtu + 14;
-+ if (np->rx_buf_sz < PKT_BUF_SZ)
-+ np->rx_buf_sz = PKT_BUF_SZ;
- np->rx_head_desc = &np->rx_ring[0];
-
- for (i = 0; i < RX_RING_SIZE; i++) {
- np->rx_ring[i].rx_status = 0;
-- np->rx_ring[i].rx_length = 0;
-- np->rx_ring[i].desc_length = np->rx_buf_sz;
-- np->rx_ring[i].next_desc = virt_to_bus(&np->rx_ring[i+1]);
-+ np->rx_ring[i].desc_length = cpu_to_le32(np->rx_buf_sz);
-+ np->rx_ring[i].next_desc = virt_to_le32desc(&np->rx_ring[i+1]);
- np->rx_skbuff[i] = 0;
- }
- /* Mark the last entry as wrapping the ring. */
-- np->rx_ring[i-1].next_desc = virt_to_bus(&np->rx_ring[0]);
-+ np->rx_ring[i-1].next_desc = virt_to_le32desc(&np->rx_ring[0]);
-
-- /* Fill in the Rx buffers. */
-+ /* Fill in the Rx buffers. Handle allocation failure gracefully. */
- for (i = 0; i < RX_RING_SIZE; i++) {
- struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz);
- np->rx_skbuff[i] = skb;
- if (skb == NULL)
- break;
- skb->dev = dev; /* Mark as being used by this device. */
-- np->rx_ring[i].addr = virt_to_bus(skb->tail);
-- np->rx_ring[i].rx_status = 0;
-- np->rx_ring[i].rx_length = DescOwn;
-+ np->rx_ring[i].addr = virt_to_le32desc(skb->tail);
-+ np->rx_ring[i].rx_status = cpu_to_le32(DescOwn);
- }
- np->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
-
- for (i = 0; i < TX_RING_SIZE; i++) {
- np->tx_skbuff[i] = 0;
-- np->tx_ring[i].tx_own = 0;
-- np->tx_ring[i].desc_length = 0x00e08000;
-- np->tx_ring[i].next_desc = virt_to_bus(&np->tx_ring[i+1]);
-- np->tx_buf[i] = kmalloc(PKT_BUF_SZ, GFP_KERNEL);
-+ np->tx_ring[i].tx_status = 0;
-+ np->tx_ring[i].desc_length = cpu_to_le32(0x00e08000);
-+ np->tx_ring[i].next_desc = virt_to_le32desc(&np->tx_ring[i+1]);
-+ np->tx_buf[i] = 0; /* Allocated as/if needed. */
- }
-- np->tx_ring[i-1].next_desc = virt_to_bus(&np->tx_ring[0]);
-+ np->tx_ring[i-1].next_desc = virt_to_le32desc(&np->tx_ring[0]);
-
- return;
- }
-
--static int start_tx(struct sk_buff *skb, struct device *dev)
-+static int start_tx(struct sk_buff *skb, struct net_device *dev)
- {
- struct netdev_private *np = (struct netdev_private *)dev->priv;
- unsigned entry;
-
-- /* Block a timer-based transmit from overlapping. This could better be
-- done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
-- if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
-- if (jiffies - dev->trans_start < TX_TIMEOUT)
-- return 1;
-- tx_timeout(dev);
-+ /* Block a timer-based transmit from overlapping. This happens when
-+ packets are presumed lost, and we use this check the Tx status. */
-+ if (netif_pause_tx_queue(dev) != 0) {
-+ /* This watchdog code is redundant with the media monitor timer. */
-+ if (jiffies - dev->trans_start > TX_TIMEOUT)
-+ tx_timeout(dev);
- return 1;
- }
-
-- /* Caution: the write order is important here, set the field
-- with the "ownership" bits last. */
-+ /* Caution: the write order is important here, set the descriptor word
-+ with the "ownership" bit last. No SMP locking is needed if the
-+ cur_tx is incremented after the descriptor is consistent. */
-
- /* Calculate the next Tx descriptor entry. */
- entry = np->cur_tx % TX_RING_SIZE;
-
- np->tx_skbuff[entry] = skb;
-
-- if ((long)skb->data & 3) { /* Must use alignment buffer. */
-+ if ((np->drv_flags & ReqTxAlign) && ((long)skb->data & 3)) {
-+ /* Must use alignment buffer. */
- if (np->tx_buf[entry] == NULL &&
- (np->tx_buf[entry] = kmalloc(PKT_BUF_SZ, GFP_KERNEL)) == NULL)
- return 1;
- memcpy(np->tx_buf[entry], skb->data, skb->len);
-- np->tx_ring[entry].addr = virt_to_bus(np->tx_buf[entry]);
-+ np->tx_ring[entry].addr = virt_to_le32desc(np->tx_buf[entry]);
- } else
-- np->tx_ring[entry].addr = virt_to_bus(skb->data);
-+ np->tx_ring[entry].addr = virt_to_le32desc(skb->data);
-+ /* Explicitly flush packet data cache lines here. */
-
-- np->tx_ring[entry].desc_length = 0x00E08000 |
-- (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN);
-- np->tx_ring[entry].tx_own = DescOwn;
-+ np->tx_ring[entry].desc_length =
-+ cpu_to_le32(0x00E08000 | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN));
-+ np->tx_ring[entry].tx_status = cpu_to_le32(DescOwn);
-
- np->cur_tx++;
-
-- /* Non-x86 Todo: explicitly flush cache lines here. */
-+ /* Explicitly flush descriptor cache lines here. */
-
- /* Wake the potentially-idle transmit channel. */
- writew(CmdTxDemand | np->chip_cmd, dev->base_addr + ChipCmd);
-
-- if (np->cur_tx - np->dirty_tx < TX_RING_SIZE - 1)
-- clear_bit(0, (void*)&dev->tbusy); /* Typical path */
-- else
-+ if (np->cur_tx - np->dirty_tx >= TX_QUEUE_LEN - 1) {
- np->tx_full = 1;
-+ /* Check for a just-cleared queue. */
-+ if (np->cur_tx - (volatile unsigned int)np->dirty_tx
-+ < TX_QUEUE_LEN - 2) {
-+ np->tx_full = 0;
-+ netif_unpause_tx_queue(dev);
-+ } else
-+ netif_stop_tx_queue(dev);
-+ } else
-+ netif_unpause_tx_queue(dev); /* Typical path */
-+
- dev->trans_start = jiffies;
-
-- if (debug > 4) {
-+ if (np->msg_level & NETIF_MSG_TX_QUEUED) {
- printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n",
- dev->name, np->cur_tx, entry);
- }
-@@ -887,27 +923,10 @@
- after the Tx thread. */
- static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
- {
-- struct device *dev = (struct device *)dev_instance;
-- struct netdev_private *np;
-- long ioaddr, boguscnt = max_interrupt_work;
--
-- ioaddr = dev->base_addr;
-- np = (struct netdev_private *)dev->priv;
--#if defined(__i386__)
-- /* A lock to prevent simultaneous entry bug on Intel SMP machines. */
-- if (test_and_set_bit(0, (void*)&dev->interrupt)) {
-- printk(KERN_ERR"%s: SMP simultaneous entry of an interrupt handler.\n",
-- dev->name);
-- dev->interrupt = 0; /* Avoid halting machine. */
-- return;
-- }
--#else
-- if (dev->interrupt) {
-- printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name);
-- return;
-- }
-- dev->interrupt = 1;
--#endif
-+ struct net_device *dev = (struct net_device *)dev_instance;
-+ struct netdev_private *np = (void *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+ int boguscnt = np->max_interrupt_work;
-
- do {
- u32 intr_status = readw(ioaddr + IntrStatus);
-@@ -915,7 +934,7 @@
- /* Acknowledge all of the current interrupt sources ASAP. */
- writew(intr_status & 0xffff, ioaddr + IntrStatus);
-
-- if (debug > 4)
-+ if (np->msg_level & NETIF_MSG_INTR)
- printk(KERN_DEBUG "%s: Interrupt, status %4.4x.\n",
- dev->name, intr_status);
-
-@@ -928,15 +947,14 @@
-
- for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) {
- int entry = np->dirty_tx % TX_RING_SIZE;
-- int txstatus;
-- if (np->tx_ring[entry].tx_own)
-+ int txstatus = le32_to_cpu(np->tx_ring[entry].tx_status);
-+ if (txstatus & DescOwn)
- break;
-- txstatus = np->tx_ring[entry].tx_status;
-- if (debug > 6)
-- printk(KERN_DEBUG " Tx scavenge %d status %4.4x.\n",
-+ if (np->msg_level & NETIF_MSG_TX_DONE)
-+ printk(KERN_DEBUG " Tx scavenge %d status %4.4x.\n",
- entry, txstatus);
- if (txstatus & 0x8000) {
-- if (debug > 1)
-+ if (np->msg_level & NETIF_MSG_TX_ERR)
- printk(KERN_DEBUG "%s: Transmit error, Tx status %4.4x.\n",
- dev->name, txstatus);
- np->stats.tx_errors++;
-@@ -953,22 +971,24 @@
- #ifdef ETHER_STATS
- if (txstatus & 0x0001) np->stats.tx_deferred++;
- #endif
-- np->stats.collisions += (txstatus >> 3) & 15;
-+ if (np->drv_flags & HasV1TxStat)
-+ np->stats.collisions += (txstatus >> 3) & 15;
-+ else
-+ np->stats.collisions += txstatus & 15;
- #if defined(NETSTATS_VER2)
-- np->stats.tx_bytes += np->tx_ring[entry].desc_length & 0x7ff;
-+ np->stats.tx_bytes += np->tx_skbuff[entry]->len;
- #endif
- np->stats.tx_packets++;
- }
- /* Free the original skb. */
-- dev_free_skb(np->tx_skbuff[entry]);
-+ dev_free_skb_irq(np->tx_skbuff[entry]);
- np->tx_skbuff[entry] = 0;
- }
-- if (np->tx_full && dev->tbusy
-- && np->cur_tx - np->dirty_tx < TX_RING_SIZE - 4) {
-- /* The ring is no longer full, clear tbusy. */
-+ /* Note the 4 slot hysteresis in mark the queue non-full. */
-+ if (np->tx_full && np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 4) {
-+ /* The ring is no longer full, allow new TX entries. */
- np->tx_full = 0;
-- clear_bit(0, (void*)&dev->tbusy);
-- mark_bh(NET_BH);
-+ netif_resume_tx_queue(dev);
- }
-
- /* Abnormal error summary/uncommon events handlers. */
-@@ -984,38 +1004,33 @@
- }
- } while (1);
-
-- if (debug > 3)
-+ if (np->msg_level & NETIF_MSG_INTR)
- printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
-- dev->name, readw(ioaddr + IntrStatus));
-+ dev->name, (int)readw(ioaddr + IntrStatus));
-
--#if defined(__i386__)
-- clear_bit(0, (void*)&dev->interrupt);
--#else
-- dev->interrupt = 0;
--#endif
- return;
- }
-
- /* This routine is logically part of the interrupt handler, but isolated
- for clarity and better register allocation. */
--static int netdev_rx(struct device *dev)
-+static int netdev_rx(struct net_device *dev)
- {
- struct netdev_private *np = (struct netdev_private *)dev->priv;
- int entry = np->cur_rx % RX_RING_SIZE;
- int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx;
-
-- if (debug > 4) {
-- printk(KERN_DEBUG " In netdev_rx(), entry %d status %4.4x.\n",
-- entry, np->rx_head_desc->rx_length);
-+ if (np->msg_level & NETIF_MSG_RX_STATUS) {
-+ printk(KERN_DEBUG " In netdev_rx(), entry %d status %8.8x.\n",
-+ entry, np->rx_head_desc->rx_status);
- }
-
- /* If EOP is set on the next entry, it's a new packet. Send it up. */
-- while ( ! (np->rx_head_desc->rx_length & DescOwn)) {
-+ while ( ! (np->rx_head_desc->rx_status & cpu_to_le32(DescOwn))) {
- struct rx_desc *desc = np->rx_head_desc;
-- int data_size = desc->rx_length;
-- u16 desc_status = desc->rx_status;
-+ u32 desc_status = le32_to_cpu(desc->rx_status);
-+ int data_size = desc_status >> 16;
-
-- if (debug > 4)
-+ if (np->msg_level & NETIF_MSG_RX_STATUS)
- printk(KERN_DEBUG " netdev_rx() status is %4.4x.\n",
- desc_status);
- if (--boguscnt < 0)
-@@ -1031,7 +1046,7 @@
- np->stats.rx_length_errors++;
- } else if (desc_status & RxErr) {
- /* There was a error. */
-- if (debug > 2)
-+ if (np->msg_level & NETIF_MSG_RX_ERR)
- printk(KERN_DEBUG " netdev_rx() Rx error was %8.8x.\n",
- desc_status);
- np->stats.rx_errors++;
-@@ -1043,28 +1058,38 @@
- } else {
- struct sk_buff *skb;
- /* Length should omit the CRC */
-- u16 pkt_len = data_size - 4;
-+ int pkt_len = data_size - 4;
-
- /* Check if the packet is long enough to accept without copying
- to a minimally-sized skbuff. */
-- if (pkt_len < rx_copybreak
-+ if (pkt_len < np->rx_copybreak
- && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
- skb->dev = dev;
- skb_reserve(skb, 2); /* 16 byte align the IP header */
--#if ! defined(__alpha__) || USE_IP_COPYSUM /* Avoid misaligned on Alpha */
-- eth_copy_and_sum(skb, bus_to_virt(desc->addr),
-- pkt_len, 0);
-+#if HAS_IP_COPYSUM /* Call copy + cksum if available. */
-+ eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0);
- skb_put(skb, pkt_len);
- #else
-- memcpy(skb_put(skb,pkt_len), bus_to_virt(desc->addr), pkt_len);
-+ memcpy(skb_put(skb, pkt_len), np->rx_skbuff[entry]->tail,
-+ pkt_len);
- #endif
- } else {
- skb_put(skb = np->rx_skbuff[entry], pkt_len);
- np->rx_skbuff[entry] = NULL;
- }
- skb->protocol = eth_type_trans(skb, dev);
-+ { /* Use hardware checksum info. */
-+ int rxtype = le32_to_cpu(desc->desc_length);
-+ int csum_bits = rxtype & RxTypeCsumMask;
-+ if (csum_bits == RxTypeUDPSumOK ||
-+ csum_bits == RxTypeTCPSumOK)
-+ skb->ip_summed = CHECKSUM_UNNECESSARY;
-+ }
- netif_rx(skb);
- dev->last_rx = jiffies;
-+#if defined(NETSTATS_VER2)
-+ np->stats.rx_bytes += pkt_len;
-+#endif
- np->stats.rx_packets++;
- }
- entry = (++np->cur_rx) % RX_RING_SIZE;
-@@ -1081,10 +1106,9 @@
- if (skb == NULL)
- break; /* Better luck next round. */
- skb->dev = dev; /* Mark as being used by this device. */
-- np->rx_ring[entry].addr = virt_to_bus(skb->tail);
-+ np->rx_ring[entry].addr = virt_to_le32desc(skb->tail);
- }
-- np->rx_ring[entry].rx_status = 0;
-- np->rx_ring[entry].rx_length = DescOwn;
-+ np->rx_ring[entry].rx_status = cpu_to_le32(DescOwn);
- }
-
- /* Pre-emptively restart Rx engine. */
-@@ -1092,18 +1116,22 @@
- return 0;
- }
-
--static void netdev_error(struct device *dev, int intr_status)
-+static void netdev_error(struct net_device *dev, int intr_status)
- {
- struct netdev_private *np = (struct netdev_private *)dev->priv;
- long ioaddr = dev->base_addr;
-
- if (intr_status & (IntrMIIChange | IntrLinkChange)) {
-- if (readb(ioaddr + MIIStatus) & 0x02)
-+ if (readb(ioaddr + MIIStatus) & 0x02) {
- /* Link failed, restart autonegotiation. */
-- mdio_write(dev, np->phys[0], 0, 0x3300);
-- else
-+ if (np->drv_flags & HasDavicomPhy)
-+ mdio_write(dev, np->phys[0], 0, 0x3300);
-+ netif_link_down(dev);
-+ } else {
-+ netif_link_up(dev);
- check_duplex(dev);
-- if (debug)
-+ }
-+ if (np->msg_level & NETIF_MSG_LINK)
- printk(KERN_ERR "%s: MII status changed: Autonegotiation "
- "advertising %4.4x partner %4.4x.\n", dev->name,
- mdio_read(dev, np->phys[0], 4),
-@@ -1112,20 +1140,24 @@
- if (intr_status & IntrStatsMax) {
- np->stats.rx_crc_errors += readw(ioaddr + RxCRCErrs);
- np->stats.rx_missed_errors += readw(ioaddr + RxMissed);
-- writel(0, RxMissed);
-+ writel(0, ioaddr + RxMissed);
- }
- if (intr_status & IntrTxAbort) {
- /* Stats counted in Tx-done handler, just restart Tx. */
-+ writel(virt_to_bus(&np->tx_ring[np->dirty_tx % TX_RING_SIZE]),
-+ ioaddr + TxRingPtr);
- writew(CmdTxDemand | np->chip_cmd, dev->base_addr + ChipCmd);
- }
- if (intr_status & IntrTxUnderrun) {
- if (np->tx_thresh < 0xE0)
- writeb(np->tx_thresh += 0x20, ioaddr + TxConfig);
-- if (debug > 1)
-+ if (np->msg_level & NETIF_MSG_TX_ERR)
- printk(KERN_INFO "%s: Transmitter underrun, increasing Tx "
- "threshold setting to %2.2x.\n", dev->name, np->tx_thresh);
- }
-- if ((intr_status & ~(IntrLinkChange|IntrStatsMax|IntrTxAbort)) && debug) {
-+ if ((intr_status & ~(IntrLinkChange | IntrMIIChange | IntrStatsMax |
-+ IntrTxAbort|IntrTxAborted | IntrNormalSummary))
-+ && (np->msg_level & NETIF_MSG_DRV)) {
- printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n",
- dev->name, intr_status);
- /* Recovery for other fault sources not known. */
-@@ -1133,7 +1165,7 @@
- }
- }
-
--static struct enet_statistics *get_stats(struct device *dev)
-+static struct net_device_stats *get_stats(struct net_device *dev)
- {
- struct netdev_private *np = (struct netdev_private *)dev->priv;
- long ioaddr = dev->base_addr;
-@@ -1143,7 +1175,7 @@
- non-critical. */
- np->stats.rx_crc_errors += readw(ioaddr + RxCRCErrs);
- np->stats.rx_missed_errors += readw(ioaddr + RxMissed);
-- writel(0, RxMissed);
-+ writel(0, ioaddr + RxMissed);
-
- return &np->stats;
- }
-@@ -1154,20 +1186,20 @@
- static unsigned const ethernet_polynomial = 0x04c11db7U;
- static inline u32 ether_crc(int length, unsigned char *data)
- {
-- int crc = -1;
-+ int crc = -1;
-
-- while(--length >= 0) {
-+ while(--length >= 0) {
- unsigned char current_octet = *data++;
- int bit;
- for (bit = 0; bit < 8; bit++, current_octet >>= 1) {
- crc = (crc << 1) ^
- ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
- }
-- }
-- return crc;
-+ }
-+ return crc;
- }
-
--static void set_rx_mode(struct device *dev)
-+static void set_rx_mode(struct net_device *dev)
- {
- struct netdev_private *np = (struct netdev_private *)dev->priv;
- long ioaddr = dev->base_addr;
-@@ -1178,9 +1210,11 @@
- /* Unconditionally log net taps. */
- printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);
- rx_mode = 0x1C;
-- } else if ((dev->mc_count > multicast_filter_limit)
-+ } else if ((dev->mc_count > np->multicast_filter_limit)
- || (dev->flags & IFF_ALLMULTI)) {
- /* Too many to match, or accept all multicasts. */
-+ writel(0xffffffff, ioaddr + MulticastFilter0);
-+ writel(0xffffffff, ioaddr + MulticastFilter1);
- rx_mode = 0x0C;
- } else {
- struct dev_mc_list *mclist;
-@@ -1198,44 +1232,67 @@
- writeb(np->rx_thresh | rx_mode, ioaddr + RxConfig);
- }
-
--static int mii_ioctl(struct device *dev, struct ifreq *rq, int cmd)
-+static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
- {
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
- u16 *data = (u16 *)&rq->ifr_data;
-+ u32 *data32 = (void *)&rq->ifr_data;
-
- switch(cmd) {
-- case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */
-- data[0] = ((struct netdev_private *)dev->priv)->phys[0] & 0x1f;
-+ case 0x8947: case 0x89F0:
-+ /* SIOCGMIIPHY: Get the address of the PHY in use. */
-+ data[0] = np->phys[0] & 0x1f;
- /* Fall Through */
-- case SIOCDEVPRIVATE+1: /* Read the specified MII register. */
-+ case 0x8948: case 0x89F1:
-+ /* SIOCGMIIREG: Read the specified MII register. */
- data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f);
- return 0;
-- case SIOCDEVPRIVATE+2: /* Write the specified MII register */
-- if (!suser())
-+ case 0x8949: case 0x89F2:
-+ /* SIOCSMIIREG: Write the specified MII register */
-+ if (!capable(CAP_NET_ADMIN))
- return -EPERM;
-+ /* Note: forced media tracking is done in mdio_write(). */
- mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]);
- return 0;
-+ case SIOCGPARAMS:
-+ data32[0] = np->msg_level;
-+ data32[1] = np->multicast_filter_limit;
-+ data32[2] = np->max_interrupt_work;
-+ data32[3] = np->rx_copybreak;
-+ return 0;
-+ case SIOCSPARAMS:
-+ if (!capable(CAP_NET_ADMIN))
-+ return -EPERM;
-+ np->msg_level = data32[0];
-+ np->multicast_filter_limit = data32[1];
-+ np->max_interrupt_work = data32[2];
-+ np->rx_copybreak = data32[3];
-+ return 0;
- default:
- return -EOPNOTSUPP;
- }
- }
-
--static int netdev_close(struct device *dev)
-+static int netdev_close(struct net_device *dev)
- {
- long ioaddr = dev->base_addr;
- struct netdev_private *np = (struct netdev_private *)dev->priv;
- int i;
-
-- dev->start = 0;
-- dev->tbusy = 1;
-+ netif_stop_tx_queue(dev);
-
-- if (debug > 1)
-+ if (np->msg_level & NETIF_MSG_IFDOWN)
- printk(KERN_DEBUG "%s: Shutting down ethercard, status was %4.4x.\n",
- dev->name, readw(ioaddr + ChipCmd));
-
-+ /* Switch to loopback mode to avoid hardware races. */
-+ writeb(np->tx_thresh | 0x01, ioaddr + TxConfig);
-+
- /* Disable interrupts by clearing the interrupt mask. */
- writew(0x0000, ioaddr + IntrEnable);
-
- /* Stop the chip's Tx and Rx processes. */
-+ np->chip_cmd = CmdStop;
- writew(CmdStop, ioaddr + ChipCmd);
-
- del_timer(&np->timer);
-@@ -1244,7 +1301,7 @@
-
- /* Free all the skbuffs in the Rx queue. */
- for (i = 0; i < RX_RING_SIZE; i++) {
-- np->rx_ring[i].rx_length = 0;
-+ np->rx_ring[i].rx_status = 0;
- np->rx_ring[i].addr = 0xBADF00D0; /* An invalid address. */
- if (np->rx_skbuff[i]) {
- #if LINUX_VERSION_CODE < 0x20100
-@@ -1258,6 +1315,10 @@
- if (np->tx_skbuff[i])
- dev_free_skb(np->tx_skbuff[i]);
- np->tx_skbuff[i] = 0;
-+ if (np->tx_buf[i]) {
-+ kfree(np->tx_buf[i]);
-+ np->tx_buf[i] = 0;
-+ }
- }
-
- MOD_DEC_USE_COUNT;
-@@ -1265,42 +1326,90 @@
- return 0;
- }
-
-+static int via_pwr_event(void *dev_instance, int event)
-+{
-+ struct net_device *dev = dev_instance;
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+
-+ if (np->msg_level & NETIF_MSG_LINK)
-+ printk(KERN_DEBUG "%s: Handling power event %d.\n", dev->name, event);
-+ switch(event) {
-+ case DRV_ATTACH:
-+ MOD_INC_USE_COUNT;
-+ break;
-+ case DRV_SUSPEND:
-+ /* Disable interrupts, stop Tx and Rx. */
-+ writew(0x0000, ioaddr + IntrEnable);
-+ /* Stop the chip's Tx and Rx processes. */
-+ writew(CmdStop, ioaddr + ChipCmd);
-+ break;
-+ case DRV_RESUME:
-+ /* This is incomplete: the actions are very chip specific. */
-+ set_rx_mode(dev);
-+ netif_start_tx_queue(dev);
-+ writew(np->chip_cmd, ioaddr + ChipCmd);
-+ writew(np->intr_enable, ioaddr + IntrEnable);
-+ break;
-+ case DRV_DETACH: {
-+ struct net_device **devp, **next;
-+ if (dev->flags & IFF_UP) {
-+ /* Some, but not all, kernel versions close automatically. */
-+ dev_close(dev);
-+ dev->flags &= ~(IFF_UP|IFF_RUNNING);
-+ }
-+ unregister_netdev(dev);
-+ release_region(dev->base_addr, pci_tbl[np->chip_id].io_size);
-+#ifndef USE_IO_OPS
-+ iounmap((char *)dev->base_addr);
-+#endif
-+ for (devp = &root_net_dev; *devp; devp = next) {
-+ next = &((struct netdev_private *)(*devp)->priv)->next_module;
-+ if (*devp == dev) {
-+ *devp = *next;
-+ break;
-+ }
-+ }
-+ if (np->priv_addr)
-+ kfree(np->priv_addr);
-+ kfree(dev);
-+ MOD_DEC_USE_COUNT;
-+ break;
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-
- #ifdef MODULE
- int init_module(void)
- {
-- if (debug) /* Emit version even if no cards detected. */
-- printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB);
--#ifdef CARDBUS
-- register_driver(&etherdev_ops);
-- return 0;
--#else
-- return pci_etherdev_probe(NULL, pci_tbl);
--#endif
-+ if (debug >= NETIF_MSG_DRV) /* Emit version even if no cards detected. */
-+ printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2);
-+ return pci_drv_register(&via_rhine_drv_id, NULL);
- }
-
- void cleanup_module(void)
- {
-+ struct net_device *next_dev;
-
--#ifdef CARDBUS
-- unregister_driver(&etherdev_ops);
--#endif
-+ pci_drv_unregister(&via_rhine_drv_id);
-
- /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
- while (root_net_dev) {
-- struct netdev_private *np =
-- (struct netdev_private *)(root_net_dev->priv);
-+ struct netdev_private *np = (void *)(root_net_dev->priv);
- unregister_netdev(root_net_dev);
--#ifdef VIA_USE_IO
-+#ifdef USE_IO_OPS
- release_region(root_net_dev->base_addr, pci_tbl[np->chip_id].io_size);
- #else
- iounmap((char *)(root_net_dev->base_addr));
- #endif
-+ next_dev = np->next_module;
-+ if (np->priv_addr)
-+ kfree(np->priv_addr);
- kfree(root_net_dev);
-- root_net_dev = np->next_module;
--#if 0
-- kfree(np); /* Assumption: no struct realignment. */
--#endif
-+ root_net_dev = next_dev;
- }
- }
-
-@@ -1308,8 +1417,9 @@
-
- /*
- * Local variables:
-- * compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c via-rhine.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
-- * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c via-rhine.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
-+ * compile-command: "make KERNVER=`uname -r` via-rhine.o"
-+ * compile-cmd: "gcc -DMODULE -Wall -Wstrict-prototypes -O6 -c via-rhine.c"
-+ * simple-compile-command: "gcc -DMODULE -O6 -c via-rhine.c"
- * c-indent-level: 4
- * c-basic-offset: 4
- * tab-width: 4
-Index: linux/src/drivers/net/winbond-840.c
-===================================================================
-RCS file: linux/src/drivers/net/winbond-840.c
-diff -N linux/src/drivers/net/winbond-840.c
---- /dev/null 1 Jan 1970 00:00:00 -0000
-+++ linux/src/drivers/net/winbond-840.c 20 Aug 2004 10:32:55 -0000
-@@ -0,0 +1,1558 @@
-+/* winbond-840.c: A Linux network device driver for the Winbond W89c840. */
-+/*
-+ Written 1998-2003 by Donald Becker.
-+
-+ This software may be used and distributed according to the terms of
-+ the GNU General Public License (GPL), incorporated herein by reference.
-+ Drivers based on or derived from this code fall under the GPL and must
-+ retain the authorship, copyright and license notice. This file is not
-+ a complete program and may only be used when the entire operating
-+ system is licensed under the GPL.
-+
-+ The author may be reached as becker@scyld.com, or C/O
-+ Scyld Computing Corporation
-+ 914 Bay Ridge Road, Suite 220
-+ Annapolis MD 21403
-+
-+ Support information and updates available at
-+ http://www.scyld.com/network/drivers.html
-+ The information and support mailing lists are based at
-+ http://www.scyld.com/mailman/listinfo/
-+
-+ Do not remove the copyright infomation.
-+ Do not change the version information unless an improvement has been made.
-+ Merely removing my name, as Compex has done in the past, does not count
-+ as an improvement.
-+*/
-+
-+/* These identify the driver base version and may not be removed. */
-+static const char version1[] =
-+"winbond-840.c:v1.10 7/22/2003 Donald Becker <becker@scyld.com>\n";
-+static const char version2[] =
-+" http://www.scyld.com/network/drivers.html\n";
-+
-+/* Automatically extracted configuration info:
-+probe-func: winbond840_probe
-+config-in: tristate 'Winbond W89c840 Ethernet support' CONFIG_WINBOND_840
-+
-+c-help-name: Winbond W89c840 PCI Ethernet support
-+c-help-symbol: CONFIG_WINBOND_840
-+c-help: The winbond-840.c driver is for the Winbond W89c840 chip.
-+c-help: This chip is named TX9882 on the Compex RL100-ATX board.
-+c-help: More specific information and updates are available from
-+c-help: http://www.scyld.com/network/drivers.html
-+*/
-+
-+/* The user-configurable values.
-+ These may be modified when a driver module is loaded.*/
-+
-+/* Message enable level: 0..31 = no..all messages. See NETIF_MSG docs. */
-+static int debug = 2;
-+
-+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-+static int max_interrupt_work = 20;
-+
-+/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
-+ The '840 uses a 64 element hash table based on the Ethernet CRC. */
-+static int multicast_filter_limit = 32;
-+
-+/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
-+ Setting to > 1518 effectively disables this feature. */
-+static int rx_copybreak = 0;
-+
-+/* Used to pass the media type, etc.
-+ Both 'options[]' and 'full_duplex[]' should exist for driver
-+ interoperability, however setting full_duplex[] is deprecated.
-+ The media type is usually passed in 'options[]'.
-+ The default is autonegotation for speed and duplex.
-+ This should rarely be overridden.
-+ Use option values 0x10/0x20 for 10Mbps, 0x100,0x200 for 100Mbps.
-+ Use option values 0x10 and 0x100 for forcing half duplex fixed speed.
-+ Use option values 0x20 and 0x200 for forcing full duplex operation.
-+*/
-+#define MAX_UNITS 8 /* More are supported, limit only on options */
-+static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-+static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-+
-+/* Operational parameters that are set at compile time. */
-+
-+/* Keep the ring sizes a power of two for compile efficiency.
-+ The compiler will convert <unsigned>'%'<2^N> into a bit mask.
-+ Making the Tx ring too large decreases the effectiveness of channel
-+ bonding and packet priority, confuses the system network buffer limits,
-+ and wastes memory.
-+ Larger receive rings merely waste memory.
-+*/
-+#define TX_RING_SIZE 16
-+#define TX_QUEUE_LEN 10 /* Limit ring entries actually used, min 4. */
-+#define RX_RING_SIZE 32
-+
-+/* The presumed FIFO size for working around the Tx-FIFO-overflow bug.
-+ To avoid overflowing we don't queue again until we have room for a
-+ full-size packet.
-+ */
-+#define TX_FIFO_SIZE (2048)
-+#define TX_BUG_FIFO_LIMIT (TX_FIFO_SIZE-1514-16)
-+
-+/* Operational parameters that usually are not changed. */
-+/* Time in jiffies before concluding the transmitter is hung.
-+ Re-autonegotiation may take up to 3 seconds.
-+ */
-+#define TX_TIMEOUT (6*HZ)
-+
-+/* Allocation size of Rx buffers with normal sized Ethernet frames.
-+ Do not change this value without good reason. This is not a limit,
-+ but a way to keep a consistent allocation size among drivers.
-+ */
-+#define PKT_BUF_SZ 1536
-+
-+#ifndef __KERNEL__
-+#define __KERNEL__
-+#endif
-+#if !defined(__OPTIMIZE__)
-+#warning You must compile this file with the correct options!
-+#warning See the last lines of the source file.
-+#error You must compile this driver with "-O".
-+#endif
-+
-+/* Include files, designed to support most kernel versions 2.0.0 and later. */
-+#include <linux/config.h>
-+#if defined(CONFIG_SMP) && ! defined(__SMP__)
-+#define __SMP__
-+#endif
-+#if defined(MODULE) && defined(CONFIG_MODVERSIONS) && ! defined(MODVERSIONS)
-+#define MODVERSIONS
-+#endif
-+
-+#include <linux/version.h>
-+#if defined(MODVERSIONS)
-+#include <linux/modversions.h>
-+#endif
-+#include <linux/module.h>
-+
-+#include <linux/kernel.h>
-+#include <linux/string.h>
-+#include <linux/timer.h>
-+#include <linux/errno.h>
-+#include <linux/ioport.h>
-+#if LINUX_VERSION_CODE >= 0x20400
-+#include <linux/slab.h>
-+#else
-+#include <linux/malloc.h>
-+#endif
-+#include <linux/interrupt.h>
-+#include <linux/pci.h>
-+#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/skbuff.h>
-+#include <asm/processor.h> /* Processor type for cache alignment. */
-+#include <asm/bitops.h>
-+#include <asm/io.h>
-+
-+#ifdef INLINE_PCISCAN
-+#include "k_compat.h"
-+#else
-+#include "pci-scan.h"
-+#include "kern_compat.h"
-+#endif
-+
-+/* Configure the PCI bus bursts and FIFO thresholds.
-+ 486: Set 8 longword cache alignment, 8 longword burst.
-+ 586: Set 16 longword cache alignment, no burst limit.
-+ Cache alignment bits 15:14 Burst length 13:8
-+ 0000 <not allowed> 0000 align to cache 0800 8 longwords
-+ 4000 8 longwords 0100 1 longword 1000 16 longwords
-+ 8000 16 longwords 0200 2 longwords 2000 32 longwords
-+ C000 32 longwords 0400 4 longwords
-+ Wait the specified 50 PCI cycles after a reset by initializing
-+ Tx and Rx queues and the address filter list. */
-+#define TX_DESC_SIZE 16
-+#if defined(__powerpc__) || defined(__sparc__) /* Big endian */
-+static int csr0 = 0x00100000 | 0xE000 | TX_DESC_SIZE;
-+#elif defined(__alpha__) || defined(__x86_64) || defined(__ia64)
-+static int csr0 = 0xE000 | TX_DESC_SIZE;
-+#elif defined(__i386__)
-+static int csr0 = 0xE000 | TX_DESC_SIZE;
-+#else
-+static int csr0 = 0xE000 | TX_DESC_SIZE;
-+#warning Processor architecture unknown!
-+#endif
-+
-+
-+
-+#if (LINUX_VERSION_CODE >= 0x20100) && defined(MODULE)
-+char kernel_version[] = UTS_RELEASE;
-+#endif
-+
-+MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
-+MODULE_DESCRIPTION("Winbond W89c840 Ethernet driver");
-+MODULE_LICENSE("GPL");
-+MODULE_PARM(max_interrupt_work, "i");
-+MODULE_PARM(debug, "i");
-+MODULE_PARM(rx_copybreak, "i");
-+MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
-+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
-+MODULE_PARM(multicast_filter_limit, "i");
-+MODULE_PARM_DESC(debug, "Driver message level (0-31)");
-+MODULE_PARM_DESC(options, "Force transceiver type or fixed speed+duplex");
-+MODULE_PARM_DESC(max_interrupt_work,
-+ "Driver maximum events handled per interrupt");
-+MODULE_PARM_DESC(full_duplex, "Non-zero to set forced full duplex.");
-+MODULE_PARM_DESC(rx_copybreak,
-+ "Breakpoint in bytes for copy-only-tiny-frames");
-+MODULE_PARM_DESC(multicast_filter_limit,
-+ "Multicast addresses before switching to Rx-all-multicast");
-+
-+/*
-+ Theory of Operation
-+
-+I. Board Compatibility
-+
-+This driver is for the Winbond w89c840 chip.
-+
-+II. Board-specific settings
-+
-+None.
-+
-+III. Driver operation
-+
-+This chip is very similar to the Digital 21*4* "Tulip" family. The first
-+twelve registers and the descriptor format are nearly identical. Read a
-+Tulip manual for operational details.
-+
-+A significant difference is that the multicast filter and station address are
-+stored in registers rather than loaded through a pseudo-transmit packet.
-+
-+Unlike the Tulip, transmit buffers are limited to 1KB. To transmit a
-+full-sized packet we must use both data buffers in a descriptor. Thus the
-+driver uses ring mode where descriptors are implicitly sequential in memory,
-+rather than using the second descriptor address as a chain pointer to
-+subsequent descriptors.
-+
-+IV. Notes
-+
-+If you are going to almost clone a Tulip, why not go all the way and avoid
-+the need for a new driver?
-+
-+IVb. References
-+
-+http://www.scyld.com/expert/100mbps.html
-+http://www.scyld.com/expert/NWay.html
-+http://www.winbond.com.tw/
-+
-+IVc. Errata
-+
-+A horrible bug exists in the transmit FIFO. Apparently the chip doesn't
-+correctly detect a full FIFO, and queuing more than 2048 bytes may result in
-+silent data corruption.
-+
-+*/
-+
-+
-+
-+/*
-+ PCI probe table.
-+*/
-+static void *w840_probe1(struct pci_dev *pdev, void *init_dev,
-+ long ioaddr, int irq, int chip_idx, int find_cnt);
-+static int winbond_pwr_event(void *dev_instance, int event);
-+enum chip_capability_flags {
-+ CanHaveMII=1, HasBrokenTx=2, AlwaysFDX=4, FDXOnNoMII=8,};
-+#ifdef USE_IO_OPS
-+#define W840_FLAGS (PCI_USES_IO | PCI_ADDR0 | PCI_USES_MASTER)
-+#else
-+#define W840_FLAGS (PCI_USES_MEM | PCI_ADDR1 | PCI_USES_MASTER)
-+#endif
-+
-+static struct pci_id_info pci_id_tbl[] = {
-+ {"Winbond W89c840", /* Sometime a Level-One switch card. */
-+ { 0x08401050, 0xffffffff, 0x81530000, 0xffff0000 },
-+ W840_FLAGS, 128, CanHaveMII | HasBrokenTx | FDXOnNoMII},
-+ {"Winbond W89c840", { 0x08401050, 0xffffffff, },
-+ W840_FLAGS, 128, CanHaveMII | HasBrokenTx},
-+ {"Compex RL100-ATX", { 0x201111F6, 0xffffffff,},
-+ W840_FLAGS, 128, CanHaveMII | HasBrokenTx},
-+ {0,}, /* 0 terminated list. */
-+};
-+
-+struct drv_id_info winbond840_drv_id = {
-+ "winbond-840", PCI_HOTSWAP, PCI_CLASS_NETWORK_ETHERNET<<8, pci_id_tbl,
-+ w840_probe1, winbond_pwr_event };
-+
-+/* This driver was written to use PCI memory space, however some x86 systems
-+ work only with I/O space accesses. Pass -DUSE_IO_OPS to use PCI I/O space
-+ accesses instead of memory space. */
-+
-+#ifdef USE_IO_OPS
-+#undef readb
-+#undef readw
-+#undef readl
-+#undef writeb
-+#undef writew
-+#undef writel
-+#define readb inb
-+#define readw inw
-+#define readl inl
-+#define writeb outb
-+#define writew outw
-+#define writel outl
-+#endif
-+
-+/* Offsets to the Command and Status Registers, "CSRs".
-+ While similar to the Tulip, these registers are longword aligned.
-+ Note: It's not useful to define symbolic names for every register bit in
-+ the device. The name can only partially document the semantics and make
-+ the driver longer and more difficult to read.
-+*/
-+enum w840_offsets {
-+ PCIBusCfg=0x00, TxStartDemand=0x04, RxStartDemand=0x08,
-+ RxRingPtr=0x0C, TxRingPtr=0x10,
-+ IntrStatus=0x14, NetworkConfig=0x18, IntrEnable=0x1C,
-+ RxMissed=0x20, EECtrl=0x24, MIICtrl=0x24, BootRom=0x28, GPTimer=0x2C,
-+ CurRxDescAddr=0x30, CurRxBufAddr=0x34, /* Debug use */
-+ MulticastFilter0=0x38, MulticastFilter1=0x3C, StationAddr=0x40,
-+ CurTxDescAddr=0x4C, CurTxBufAddr=0x50,
-+};
-+
-+/* Bits in the interrupt status/enable registers. */
-+/* The bits in the Intr Status/Enable registers, mostly interrupt sources. */
-+enum intr_status_bits {
-+ NormalIntr=0x10000, AbnormalIntr=0x8000,
-+ IntrPCIErr=0x2000, TimerInt=0x800,
-+ IntrRxDied=0x100, RxNoBuf=0x80, IntrRxDone=0x40,
-+ TxFIFOUnderflow=0x20, RxErrIntr=0x10,
-+ TxIdle=0x04, IntrTxStopped=0x02, IntrTxDone=0x01,
-+};
-+
-+/* Bits in the NetworkConfig register. */
-+enum rx_mode_bits {
-+ TxOn=0x2000, RxOn=0x0002, FullDuplex=0x0200,
-+ AcceptErr=0x80, AcceptRunt=0x40, /* Not used */
-+ AcceptBroadcast=0x20, AcceptMulticast=0x10, AcceptAllPhys=0x08,
-+};
-+
-+enum mii_reg_bits {
-+ MDIO_ShiftClk=0x10000, MDIO_DataIn=0x80000, MDIO_DataOut=0x20000,
-+ MDIO_EnbOutput=0x40000, MDIO_EnbIn = 0x00000,
-+};
-+
-+/* The Tulip-like Rx and Tx buffer descriptors. */
-+struct w840_rx_desc {
-+ s32 status;
-+ s32 length;
-+ u32 buffer1;
-+ u32 next_desc;
-+};
-+
-+struct w840_tx_desc {
-+ s32 status;
-+ s32 length;
-+ u32 buffer1, buffer2; /* We use only buffer 1. */
-+ char pad[TX_DESC_SIZE - 16];
-+};
-+
-+/* Bits in network_desc.status */
-+enum desc_status_bits {
-+ DescOwn=0x80000000, DescEndRing=0x02000000, DescUseLink=0x01000000,
-+ DescWholePkt=0x60000000, DescStartPkt=0x20000000, DescEndPkt=0x40000000,
-+ DescIntr=0x80000000,
-+};
-+
-+#define PRIV_ALIGN 15 /* Required alignment mask */
-+struct netdev_private {
-+ /* Descriptor rings first for alignment. */
-+ struct w840_rx_desc rx_ring[RX_RING_SIZE];
-+ struct w840_tx_desc tx_ring[TX_RING_SIZE];
-+ struct net_device *next_module; /* Link for devices of this type. */
-+ void *priv_addr; /* Unaligned address for kfree */
-+ const char *product_name;
-+ /* The addresses of receive-in-place skbuffs. */
-+ struct sk_buff* rx_skbuff[RX_RING_SIZE];
-+ /* The saved address of a sent-in-place packet/buffer, for later free(). */
-+ struct sk_buff* tx_skbuff[TX_RING_SIZE];
-+ struct net_device_stats stats;
-+ struct timer_list timer; /* Media monitoring timer. */
-+ /* Frequently used values: keep some adjacent for cache effect. */
-+ int msg_level;
-+ int chip_id, drv_flags;
-+ struct pci_dev *pci_dev;
-+ int csr0, csr6;
-+ unsigned int polling; /* Switched to polling mode. */
-+ int max_interrupt_work;
-+
-+ struct w840_rx_desc *rx_head_desc;
-+ unsigned int rx_ring_size;
-+ unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */
-+ unsigned int rx_buf_sz; /* Based on MTU+slack. */
-+ int rx_copybreak;
-+
-+ unsigned int tx_ring_size;
-+ unsigned int cur_tx, dirty_tx;
-+ unsigned int tx_q_bytes, tx_unq_bytes;
-+ unsigned int tx_full:1; /* The Tx queue is full. */
-+
-+ /* These values track of the transceiver/media in use. */
-+ unsigned int full_duplex:1; /* Full-duplex operation requested. */
-+ unsigned int duplex_lock:1;
-+ unsigned int medialock:1; /* Do not sense media. */
-+ unsigned int default_port; /* Last dev->if_port value. */
-+ /* Rx filter. */
-+ u32 cur_rx_mode;
-+ u32 rx_filter[2];
-+ int multicast_filter_limit;
-+
-+ /* MII transceiver section. */
-+ int mii_cnt; /* MII device addresses. */
-+ u16 advertising; /* NWay media advertisement */
-+ unsigned char phys[2]; /* MII device addresses. */
-+};
-+
-+static int eeprom_read(long ioaddr, int location);
-+static int mdio_read(struct net_device *dev, int phy_id, int location);
-+static void mdio_write(struct net_device *dev, int phy_id, int location, int value);
-+static int netdev_open(struct net_device *dev);
-+static void check_duplex(struct net_device *dev);
-+static void netdev_timer(unsigned long data);
-+static void tx_timeout(struct net_device *dev);
-+static void init_ring(struct net_device *dev);
-+static int start_tx(struct sk_buff *skb, struct net_device *dev);
-+static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs);
-+static void netdev_error(struct net_device *dev, int intr_status);
-+static int netdev_rx(struct net_device *dev);
-+static void netdev_error(struct net_device *dev, int intr_status);
-+static inline unsigned ether_crc(int length, unsigned char *data);
-+static void set_rx_mode(struct net_device *dev);
-+static struct net_device_stats *get_stats(struct net_device *dev);
-+static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-+static int netdev_close(struct net_device *dev);
-+
-+
-+
-+/* A list of our installed devices, for removing the driver module. */
-+static struct net_device *root_net_dev = NULL;
-+
-+static void *w840_probe1(struct pci_dev *pdev, void *init_dev,
-+ long ioaddr, int irq, int chip_idx, int card_idx)
-+{
-+ struct net_device *dev;
-+ struct netdev_private *np;
-+ void *priv_mem;
-+ int i, option = card_idx < MAX_UNITS ? options[card_idx] : 0;
-+
-+ dev = init_etherdev(init_dev, 0);
-+ if (!dev)
-+ return NULL;
-+
-+#if LINUX_VERSION_CODE < 0x20155
-+ printk(KERN_INFO "%s: %s at 0x%lx, %2.2x:%2.2x",
-+ dev->name, pci_id_tbl[chip_idx].name, ioaddr,
-+ pci_bus_number(pdev), pci_devfn(pdev)>>3);
-+#else
-+ printk(KERN_INFO "%s: %s at 0x%lx, %2.2x:%2.2x",
-+ dev->name, pci_id_tbl[chip_idx].name, ioaddr,
-+ pdev->bus->number, pdev->devfn>>3);
-+#endif
-+
-+ /* Warning: validate for big-endian machines. */
-+ for (i = 0; i < 3; i++)
-+ ((u16 *)dev->dev_addr)[i] = le16_to_cpu(eeprom_read(ioaddr, i));
-+
-+ for (i = 0; i < 5; i++)
-+ printk("%2.2x:", dev->dev_addr[i]);
-+ printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);
-+
-+ priv_mem = kmalloc(sizeof(*np) + PRIV_ALIGN, GFP_KERNEL);
-+ /* Out of memory is very unlikely. */
-+ if (priv_mem == NULL)
-+ return NULL;
-+
-+#ifdef USE_IO_OPS
-+ request_region(ioaddr, pci_id_tbl[chip_idx].io_size, dev->name);
-+#endif
-+
-+ /* Reset the chip to erase previous misconfiguration.
-+ No hold time required! */
-+ writel(0x00000001, ioaddr + PCIBusCfg);
-+
-+ dev->base_addr = ioaddr;
-+ dev->irq = irq;
-+
-+ /* The descriptor lists must be aligned. */
-+ dev->priv = np = (void *)(((long)priv_mem + PRIV_ALIGN) & ~PRIV_ALIGN);
-+ memset(np, 0, sizeof(*np));
-+ np->priv_addr = priv_mem;
-+
-+ np->next_module = root_net_dev;
-+ root_net_dev = dev;
-+
-+ np->pci_dev = pdev;
-+ np->chip_id = chip_idx;
-+ np->drv_flags = pci_id_tbl[chip_idx].drv_flags;
-+ np->msg_level = (1 << debug) - 1;
-+ np->rx_copybreak = rx_copybreak;
-+ np->max_interrupt_work = max_interrupt_work;
-+ np->multicast_filter_limit = multicast_filter_limit;
-+ np->tx_ring_size = TX_RING_SIZE;
-+ np->rx_ring_size = RX_RING_SIZE;
-+
-+ if (dev->mem_start)
-+ option = dev->mem_start;
-+
-+ if ((card_idx < MAX_UNITS && full_duplex[card_idx] > 0)
-+ || (np->drv_flags & AlwaysFDX))
-+ np->full_duplex = 1;
-+
-+ /* The chip-specific entries in the device structure. */
-+ dev->open = &netdev_open;
-+ dev->hard_start_xmit = &start_tx;
-+ dev->stop = &netdev_close;
-+ dev->get_stats = &get_stats;
-+ dev->set_multicast_list = &set_rx_mode;
-+ dev->do_ioctl = &mii_ioctl;
-+
-+ if (np->drv_flags & CanHaveMII) {
-+ int phy, phy_idx = 0;
-+ for (phy = 1; phy < 32 && phy_idx < 4; phy++) {
-+ int mii_status = mdio_read(dev, phy, 1);
-+ if (mii_status != 0xffff && mii_status != 0x0000) {
-+ np->phys[phy_idx++] = phy;
-+ np->advertising = mdio_read(dev, phy, 4);
-+ printk(KERN_INFO "%s: MII PHY found at address %d, status "
-+ "0x%4.4x advertising %4.4x.\n",
-+ dev->name, phy, mii_status, np->advertising);
-+ }
-+ }
-+ np->mii_cnt = phy_idx;
-+ if (phy_idx == 0) {
-+ printk(KERN_WARNING "%s: MII PHY not found -- this device may "
-+ "not operate correctly.\n"
-+ KERN_WARNING "%s: If this is a switch card, explicitly "
-+ "force full duplex on this interface.\n",
-+ dev->name, dev->name);
-+ if (np->drv_flags & FDXOnNoMII) {
-+ printk(KERN_INFO "%s: Assuming a switch card, forcing full "
-+ "duplex.\n", dev->name);
-+ np->full_duplex = np->duplex_lock = 1;
-+ }
-+ }
-+ }
-+ /* Allow forcing the media type. */
-+ if (np->full_duplex) {
-+ printk(KERN_INFO "%s: Set to forced full duplex, autonegotiation"
-+ " disabled.\n", dev->name);
-+ np->duplex_lock = 1;
-+ }
-+ if (option > 0) {
-+ if (option & 0x220)
-+ np->full_duplex = 1;
-+ np->default_port = option & 0x3ff;
-+ if (np->default_port & 0x330) {
-+ np->medialock = 1;
-+ printk(KERN_INFO " Forcing %dMbs %s-duplex operation.\n",
-+ (option & 0x300 ? 100 : 10),
-+ (np->full_duplex ? "full" : "half"));
-+ if (np->mii_cnt)
-+ mdio_write(dev, np->phys[0], 0,
-+ ((option & 0x300) ? 0x2000 : 0) | /* 100mbps? */
-+ (np->full_duplex ? 0x0100 : 0)); /* Full duplex? */
-+ }
-+ }
-+
-+ return dev;
-+}
-+
-+
-+/* Read the EEPROM and MII Management Data I/O (MDIO) interfaces.
-+ The Winbond NIC uses serial bit streams generated by the host processor. */
-+
-+/* Delay between EEPROM clock transitions.
-+ This "delay" is to force out buffered PCI writes. */
-+#define eeprom_delay(ee_addr) readl(ee_addr)
-+
-+enum EEPROM_Ctrl_Bits {
-+ EE_ShiftClk=0x02, EE_Write0=0x801, EE_Write1=0x805,
-+ EE_ChipSelect=0x801, EE_DataIn=0x08,
-+};
-+
-+/* The EEPROM commands always start with 01.. preamble bits.
-+ Commands are prepended to the variable-length address. */
-+enum EEPROM_Cmds {
-+ EE_WriteCmd=(5 << 6), EE_ReadCmd=(6 << 6), EE_EraseCmd=(7 << 6),
-+};
-+
-+static int eeprom_read(long addr, int location)
-+{
-+ int i;
-+ int retval = 0;
-+ long ee_addr = addr + EECtrl;
-+ int read_cmd = location | EE_ReadCmd;
-+
-+ writel(EE_ChipSelect, ee_addr);
-+ /* Shift the read command bits out. */
-+ for (i = 10; i >= 0; i--) {
-+ short dataval = (read_cmd & (1 << i)) ? EE_Write1 : EE_Write0;
-+ writel(dataval, ee_addr);
-+ eeprom_delay(ee_addr);
-+ writel(dataval | EE_ShiftClk, ee_addr);
-+ eeprom_delay(ee_addr);
-+ }
-+ writel(EE_ChipSelect, ee_addr);
-+ eeprom_delay(ee_addr);
-+
-+ for (i = 16; i > 0; i--) {
-+ writel(EE_ChipSelect | EE_ShiftClk, ee_addr);
-+ eeprom_delay(ee_addr);
-+ retval = (retval << 1) | ((readl(ee_addr) & EE_DataIn) ? 1 : 0);
-+ writel(EE_ChipSelect, ee_addr);
-+ eeprom_delay(ee_addr);
-+ }
-+
-+ /* Terminate the EEPROM access. */
-+ writel(0, ee_addr);
-+ return retval;
-+}
-+
-+/* MII transceiver control section.
-+ Read and write the MII registers using software-generated serial
-+ MDIO protocol. See the MII specifications or DP83840A data sheet
-+ for details.
-+
-+ The maximum data clock rate is 2.5 Mhz.
-+ The timing is decoupled from the processor clock by flushing the write
-+ from the CPU write buffer with a following read, and using PCI
-+ transaction time. */
-+#define mdio_in(mdio_addr) readl(mdio_addr)
-+#define mdio_out(value, mdio_addr) writel(value, mdio_addr)
-+#define mdio_delay(mdio_addr) readl(mdio_addr)
-+
-+/* Set iff a MII transceiver on any interface requires mdio preamble.
-+ This only set with older tranceivers, so the extra
-+ code size of a per-interface flag is not worthwhile. */
-+static char mii_preamble_required = 1;
-+
-+#define MDIO_WRITE0 (MDIO_EnbOutput)
-+#define MDIO_WRITE1 (MDIO_DataOut | MDIO_EnbOutput)
-+
-+/* Generate the preamble required for initial synchronization and
-+ a few older transceivers. */
-+static void mdio_sync(long mdio_addr)
-+{
-+ int bits = 32;
-+
-+ /* Establish sync by sending at least 32 logic ones. */
-+ while (--bits >= 0) {
-+ mdio_out(MDIO_WRITE1, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ mdio_out(MDIO_WRITE1 | MDIO_ShiftClk, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ }
-+}
-+
-+static int mdio_read(struct net_device *dev, int phy_id, int location)
-+{
-+ long mdio_addr = dev->base_addr + MIICtrl;
-+ int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;
-+ int i, retval = 0;
-+
-+ if (mii_preamble_required)
-+ mdio_sync(mdio_addr);
-+
-+ /* Shift the read command bits out. */
-+ for (i = 15; i >= 0; i--) {
-+ int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
-+
-+ mdio_out(dataval, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ mdio_out(dataval | MDIO_ShiftClk, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ }
-+ /* Read the two transition, 16 data, and wire-idle bits. */
-+ for (i = 20; i > 0; i--) {
-+ mdio_out(MDIO_EnbIn, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ retval = (retval << 1) | ((mdio_in(mdio_addr) & MDIO_DataIn) ? 1 : 0);
-+ mdio_out(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ }
-+ return (retval>>1) & 0xffff;
-+}
-+
-+static void mdio_write(struct net_device *dev, int phy_id, int reg, int value)
-+{
-+ long mdio_addr = dev->base_addr + MIICtrl;
-+ int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (reg<<18) | value;
-+ int i;
-+
-+ if (mii_preamble_required)
-+ mdio_sync(mdio_addr);
-+
-+ /* Shift the command bits out. */
-+ for (i = 31; i >= 0; i--) {
-+ int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
-+
-+ mdio_out(dataval, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ mdio_out(dataval | MDIO_ShiftClk, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ }
-+ /* Clear out extra bits. */
-+ for (i = 2; i > 0; i--) {
-+ mdio_out(MDIO_EnbIn, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ mdio_out(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);
-+ mdio_delay(mdio_addr);
-+ }
-+ return;
-+}
-+
-+
-+static int netdev_open(struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+ int i;
-+
-+ writel(0x00000001, ioaddr + PCIBusCfg); /* Reset */
-+
-+ MOD_INC_USE_COUNT;
-+
-+ if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev)) {
-+ MOD_DEC_USE_COUNT;
-+ return -EAGAIN;
-+ }
-+
-+ if (np->msg_level & NETIF_MSG_IFUP)
-+ printk(KERN_DEBUG "%s: w89c840_open() irq %d.\n",
-+ dev->name, dev->irq);
-+
-+ init_ring(dev);
-+
-+ writel(virt_to_bus(np->rx_ring), ioaddr + RxRingPtr);
-+ writel(virt_to_bus(np->tx_ring), ioaddr + TxRingPtr);
-+
-+ for (i = 0; i < 6; i++)
-+ writeb(dev->dev_addr[i], ioaddr + StationAddr + i);
-+
-+ /* Initialize other registers. */
-+ np->csr0 = csr0;
-+ writel(np->csr0, ioaddr + PCIBusCfg);
-+
-+ if (dev->if_port == 0)
-+ dev->if_port = np->default_port;
-+
-+ writel(0, ioaddr + RxStartDemand);
-+ np->csr6 = np->full_duplex ? 0x20022202 : 0x20022002;
-+ check_duplex(dev);
-+ set_rx_mode(dev);
-+
-+ netif_start_tx_queue(dev);
-+
-+ /* Clear and Enable interrupts by setting the interrupt mask.
-+ See enum intr_status_bits above for bit guide.
-+ We omit: TimerInt, IntrRxDied, IntrTxStopped
-+ */
-+ writel(0x1A0F5, ioaddr + IntrStatus);
-+ writel(0x1A0F5, ioaddr + IntrEnable);
-+
-+ if (np->msg_level & NETIF_MSG_IFUP)
-+ printk(KERN_DEBUG "%s: Done netdev_open().\n", dev->name);
-+
-+ /* Set the timer to check for link beat. */
-+ init_timer(&np->timer);
-+ np->timer.expires = jiffies + 3*HZ;
-+ np->timer.data = (unsigned long)dev;
-+ np->timer.function = &netdev_timer; /* timer handler */
-+ add_timer(&np->timer);
-+
-+ return 0;
-+}
-+
-+static void check_duplex(struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ int mii_reg5 = mdio_read(dev, np->phys[0], 5);
-+ int negotiated = mii_reg5 & np->advertising;
-+ int duplex;
-+
-+ if (np->duplex_lock || mii_reg5 == 0xffff)
-+ return;
-+ duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;
-+ if (np->full_duplex != duplex) {
-+ np->full_duplex = duplex;
-+ if (np->msg_level & NETIF_MSG_LINK)
-+ printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d "
-+ "negotiated capability %4.4x.\n", dev->name,
-+ duplex ? "full" : "half", np->phys[0], negotiated);
-+ np->csr6 &= ~0x200;
-+ np->csr6 |= duplex ? 0x200 : 0;
-+ }
-+}
-+
-+static void netdev_timer(unsigned long data)
-+{
-+ struct net_device *dev = (struct net_device *)data;
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+ int next_tick = 10*HZ;
-+ int old_csr6 = np->csr6;
-+ u32 intr_status = readl(ioaddr + IntrStatus);
-+
-+ if (np->msg_level & NETIF_MSG_TIMER)
-+ printk(KERN_DEBUG "%s: Media selection timer tick, status %8.8x "
-+ "config %8.8x.\n",
-+ dev->name, intr_status, (int)readl(ioaddr + NetworkConfig));
-+ /* Check for blocked interrupts. */
-+ if (np->polling) {
-+ if (intr_status & 0x1ffff) {
-+ intr_handler(dev->irq, dev, 0);
-+ next_tick = 1;
-+ np->polling = 1;
-+ } else if (++np->polling > 10*HZ)
-+ np->polling = 0;
-+ else
-+ next_tick = 2;
-+ } else if ((intr_status & 0x1ffff)) {
-+ np->polling = 1;
-+ }
-+
-+ if (netif_queue_paused(dev) &&
-+ np->cur_tx - np->dirty_tx > 1 &&
-+ (jiffies - dev->trans_start) > TX_TIMEOUT) {
-+ tx_timeout(dev);
-+ }
-+ check_duplex(dev);
-+ if (np->csr6 != old_csr6) {
-+ writel(np->csr6 & ~0x0002, ioaddr + NetworkConfig);
-+ writel(np->csr6 | 0x2002, ioaddr + NetworkConfig);
-+ }
-+ np->timer.expires = jiffies + next_tick;
-+ add_timer(&np->timer);
-+}
-+
-+static void tx_timeout(struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+
-+ printk(KERN_WARNING "%s: Transmit timed out, status %8.8x,"
-+ " resetting...\n", dev->name, (int)readl(ioaddr + IntrStatus));
-+
-+#ifndef __alpha__
-+ if (np->msg_level & NETIF_MSG_TX_ERR) {
-+ int i;
-+ printk(KERN_DEBUG " Rx ring %p: ", np->rx_ring);
-+ for (i = 0; i < np->rx_ring_size; i++)
-+ printk(" %8.8x", (unsigned int)np->rx_ring[i].status);
-+ printk("\n"KERN_DEBUG" Tx ring %p: ", np->tx_ring);
-+ for (i = 0; i < np->tx_ring_size; i++)
-+ printk(" %8.8x", np->tx_ring[i].status);
-+ printk("\n");
-+ }
-+#endif
-+
-+ /* Perhaps we should reinitialize the hardware here. Just trigger a
-+ Tx demand for now. */
-+ writel(0, ioaddr + TxStartDemand);
-+ dev->if_port = 0;
-+ /* Stop and restart the chip's Tx processes . */
-+
-+ dev->trans_start = jiffies;
-+ np->stats.tx_errors++;
-+ return;
-+}
-+
-+
-+/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
-+static void init_ring(struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ int i;
-+
-+ np->tx_full = 0;
-+ np->cur_tx = np->dirty_tx = 0;
-+ np->tx_q_bytes = np->tx_unq_bytes = 0;
-+
-+ np->cur_rx = np->dirty_rx = 0;
-+ np->rx_buf_sz = (dev->mtu <= 1522 ? PKT_BUF_SZ : dev->mtu + 14);
-+ np->rx_head_desc = &np->rx_ring[0];
-+
-+ /* Initialize all Rx descriptors. */
-+ for (i = 0; i < np->rx_ring_size; i++) {
-+ np->rx_ring[i].length = np->rx_buf_sz;
-+ np->rx_ring[i].status = 0;
-+ np->rx_ring[i].next_desc = virt_to_bus(&np->rx_ring[i+1]);
-+ np->rx_skbuff[i] = 0;
-+ }
-+ /* Mark the last entry as wrapping the ring. */
-+ np->rx_ring[i-1].length |= DescEndRing;
-+ np->rx_ring[i-1].next_desc = virt_to_bus(&np->rx_ring[0]);
-+
-+ /* Fill in the Rx buffers. Handle allocation failure gracefully. */
-+ for (i = 0; i < np->rx_ring_size; i++) {
-+ struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz);
-+ np->rx_skbuff[i] = skb;
-+ if (skb == NULL)
-+ break;
-+ skb->dev = dev; /* Mark as being used by this device. */
-+ np->rx_ring[i].buffer1 = virt_to_bus(skb->tail);
-+ np->rx_ring[i].status = DescOwn | DescIntr;
-+ }
-+ np->dirty_rx = (unsigned int)(i - np->rx_ring_size);
-+
-+ for (i = 0; i < np->tx_ring_size; i++) {
-+ np->tx_skbuff[i] = 0;
-+ np->tx_ring[i].status = 0;
-+ }
-+ return;
-+}
-+
-+static int start_tx(struct sk_buff *skb, struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ unsigned entry;
-+
-+ /* Block a timer-based transmit from overlapping. */
-+ if (netif_pause_tx_queue(dev) != 0) {
-+ /* This watchdog code is redundant with the media monitor timer. */
-+ if (jiffies - dev->trans_start > TX_TIMEOUT)
-+ tx_timeout(dev);
-+ return 1;
-+ }
-+
-+ /* Note: Ordering is important here, set the field with the
-+ "ownership" bit last, and only then increment cur_tx. */
-+
-+ /* Calculate the next Tx descriptor entry. */
-+ entry = np->cur_tx % np->tx_ring_size;
-+
-+ np->tx_skbuff[entry] = skb;
-+ np->tx_ring[entry].buffer1 = virt_to_bus(skb->data);
-+
-+#define one_buffer
-+#define BPT 1022
-+#if defined(one_buffer)
-+ np->tx_ring[entry].length = DescWholePkt | skb->len;
-+ if (entry >= np->tx_ring_size-1) /* Wrap ring */
-+ np->tx_ring[entry].length |= DescIntr | DescEndRing;
-+ np->tx_ring[entry].status = DescOwn;
-+ np->cur_tx++;
-+#elif defined(two_buffer)
-+ if (skb->len > BPT) {
-+ unsigned int entry1 = ++np->cur_tx % np->tx_ring_size;
-+ np->tx_ring[entry].length = DescStartPkt | BPT;
-+ np->tx_ring[entry1].length = DescEndPkt | (skb->len - BPT);
-+ np->tx_ring[entry1].buffer1 = virt_to_bus((skb->data) + BPT);
-+ np->tx_ring[entry1].status = DescOwn;
-+ np->tx_ring[entry].status = DescOwn;
-+ if (entry >= np->tx_ring_size-1)
-+ np->tx_ring[entry].length |= DescIntr|DescEndRing;
-+ else if (entry1 >= np->tx_ring_size-1)
-+ np->tx_ring[entry1].length |= DescIntr|DescEndRing;
-+ np->cur_tx++;
-+ } else {
-+ np->tx_ring[entry].length = DescWholePkt | skb->len;
-+ if (entry >= np->tx_ring_size-1) /* Wrap ring */
-+ np->tx_ring[entry].length |= DescIntr | DescEndRing;
-+ np->tx_ring[entry].status = DescOwn;
-+ np->cur_tx++;
-+ }
-+#elif defined(split_buffer)
-+ {
-+ /* Work around the Tx-FIFO-full bug by splitting our transmit packet
-+ into two pieces, the first which may be loaded without overflowing
-+ the FIFO, and the second which contains the remainder of the
-+ packet. When we get a Tx-done interrupt that frees enough room
-+ in the FIFO we mark the remainder of the packet as loadable.
-+
-+ This has the problem that the Tx descriptors are written both
-+ here and in the interrupt handler.
-+ */
-+
-+ int buf1size = TX_FIFO_SIZE - (np->tx_q_bytes - np->tx_unq_bytes);
-+ int buf2size = skb->len - buf1size;
-+
-+ if (buf2size <= 0) { /* We fit into one descriptor. */
-+ np->tx_ring[entry].length = DescWholePkt | skb->len;
-+ } else { /* We must use two descriptors. */
-+ unsigned int entry2;
-+ np->tx_ring[entry].length = DescIntr | DescStartPkt | buf1size;
-+ if (entry >= np->tx_ring_size-1) { /* Wrap ring */
-+ np->tx_ring[entry].length |= DescEndRing;
-+ entry2 = 0;
-+ } else
-+ entry2 = entry + 1;
-+ np->cur_tx++;
-+ np->tx_ring[entry2].buffer1 =
-+ virt_to_bus(skb->data + buf1size);
-+ np->tx_ring[entry2].length = DescEndPkt | buf2size;
-+ if (entry2 >= np->tx_ring_size-1) /* Wrap ring */
-+ np->tx_ring[entry2].length |= DescEndRing;
-+ }
-+ np->tx_ring[entry].status = DescOwn;
-+ np->cur_tx++;
-+ }
-+#endif
-+ np->tx_q_bytes += skb->len;
-+ writel(0, dev->base_addr + TxStartDemand);
-+
-+ /* Work around horrible bug in the chip by marking the queue as full
-+ when we do not have FIFO room for a maximum sized packet. */
-+ if (np->cur_tx - np->dirty_tx > TX_QUEUE_LEN) {
-+ np->tx_full = 1;
-+ netif_stop_tx_queue(dev);
-+ } else if ((np->drv_flags & HasBrokenTx)
-+ && np->tx_q_bytes - np->tx_unq_bytes > TX_BUG_FIFO_LIMIT) {
-+ np->tx_full = 1;
-+ netif_stop_tx_queue(dev);
-+ } else
-+ netif_unpause_tx_queue(dev); /* Typical path */
-+
-+ dev->trans_start = jiffies;
-+
-+ if (np->msg_level & NETIF_MSG_TX_QUEUED) {
-+ printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n",
-+ dev->name, np->cur_tx, entry);
-+ }
-+ return 0;
-+}
-+
-+/* The interrupt handler does all of the Rx thread work and cleans up
-+ after the Tx thread. */
-+static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
-+{
-+ struct net_device *dev = (struct net_device *)dev_instance;
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+ int work_limit = np->max_interrupt_work;
-+
-+ do {
-+ u32 intr_status = readl(ioaddr + IntrStatus);
-+
-+ /* Acknowledge all of the current interrupt sources ASAP. */
-+ writel(intr_status & 0x0001ffff, ioaddr + IntrStatus);
-+
-+ if (np->msg_level & NETIF_MSG_INTR)
-+ printk(KERN_DEBUG "%s: Interrupt, status %4.4x.\n",
-+ dev->name, intr_status);
-+
-+ if ((intr_status & (NormalIntr|AbnormalIntr)) == 0
-+ || intr_status == 0xffffffff)
-+ break;
-+
-+ if (intr_status & (IntrRxDone | RxNoBuf))
-+ netdev_rx(dev);
-+
-+ for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) {
-+ int entry = np->dirty_tx % np->tx_ring_size;
-+ int tx_status = np->tx_ring[entry].status;
-+
-+ if (tx_status < 0)
-+ break;
-+ if (np->msg_level & NETIF_MSG_TX_DONE)
-+ printk(KERN_DEBUG "%s: Transmit done, Tx status %8.8x.\n",
-+ dev->name, tx_status);
-+ if (tx_status & 0x8000) { /* There was an error, log it. */
-+ if (np->msg_level & NETIF_MSG_TX_ERR)
-+ printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",
-+ dev->name, tx_status);
-+ np->stats.tx_errors++;
-+ if (tx_status & 0x0104) np->stats.tx_aborted_errors++;
-+ if (tx_status & 0x0C80) np->stats.tx_carrier_errors++;
-+ if (tx_status & 0x0200) np->stats.tx_window_errors++;
-+ if (tx_status & 0x0002) np->stats.tx_fifo_errors++;
-+ if ((tx_status & 0x0080) && np->full_duplex == 0)
-+ np->stats.tx_heartbeat_errors++;
-+#ifdef ETHER_STATS
-+ if (tx_status & 0x0100) np->stats.collisions16++;
-+#endif
-+ } else {
-+#ifdef ETHER_STATS
-+ if (tx_status & 0x0001) np->stats.tx_deferred++;
-+#endif
-+#if LINUX_VERSION_CODE > 0x20127
-+ np->stats.tx_bytes += np->tx_skbuff[entry]->len;
-+#endif
-+ np->stats.collisions += (tx_status >> 3) & 15;
-+ np->stats.tx_packets++;
-+ }
-+ /* Free the original skb. */
-+ np->tx_unq_bytes += np->tx_skbuff[entry]->len;
-+ dev_free_skb_irq(np->tx_skbuff[entry]);
-+ np->tx_skbuff[entry] = 0;
-+ }
-+ if (np->tx_full &&
-+ np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 4
-+ && np->tx_q_bytes - np->tx_unq_bytes < TX_BUG_FIFO_LIMIT) {
-+ /* The ring is no longer full, allow new TX entries. */
-+ np->tx_full = 0;
-+ netif_resume_tx_queue(dev);
-+ }
-+
-+ /* Abnormal error summary/uncommon events handlers. */
-+ if (intr_status & (AbnormalIntr | TxFIFOUnderflow | IntrPCIErr |
-+ TimerInt | IntrTxStopped))
-+ netdev_error(dev, intr_status);
-+
-+ if (--work_limit < 0) {
-+ printk(KERN_WARNING "%s: Too much work at interrupt, "
-+ "status=0x%4.4x.\n", dev->name, intr_status);
-+ /* Set the timer to re-enable the other interrupts after
-+ 10*82usec ticks. */
-+ writel(AbnormalIntr | TimerInt, ioaddr + IntrEnable);
-+ writel(10, ioaddr + GPTimer);
-+ break;
-+ }
-+ } while (1);
-+
-+ if (np->msg_level & NETIF_MSG_INTR)
-+ printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
-+ dev->name, (int)readl(ioaddr + IntrStatus));
-+
-+ return;
-+}
-+
-+/* This routine is logically part of the interrupt handler, but separated
-+ for clarity and better register allocation. */
-+static int netdev_rx(struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ int entry = np->cur_rx % np->rx_ring_size;
-+ int work_limit = np->dirty_rx + np->rx_ring_size - np->cur_rx;
-+
-+ if (np->msg_level & NETIF_MSG_RX_STATUS) {
-+ printk(KERN_DEBUG " In netdev_rx(), entry %d status %4.4x.\n",
-+ entry, np->rx_ring[entry].status);
-+ }
-+
-+ /* If EOP is set on the next entry, it's a new packet. Send it up. */
-+ while (--work_limit >= 0) {
-+ struct w840_rx_desc *desc = np->rx_head_desc;
-+ s32 status = desc->status;
-+
-+ if (np->msg_level & NETIF_MSG_RX_STATUS)
-+ printk(KERN_DEBUG " netdev_rx() status was %8.8x.\n",
-+ status);
-+ if (status < 0)
-+ break;
-+ if ((status & 0x38008300) != 0x0300) {
-+ if ((status & 0x38000300) != 0x0300) {
-+ /* Ingore earlier buffers. */
-+ if ((status & 0xffff) != 0x7fff) {
-+ printk(KERN_WARNING "%s: Oversized Ethernet frame spanned "
-+ "multiple buffers, entry %#x status %4.4x!\n",
-+ dev->name, np->cur_rx, status);
-+ np->stats.rx_length_errors++;
-+ }
-+ } else if (status & 0x8000) {
-+ /* There was a fatal error. */
-+ if (np->msg_level & NETIF_MSG_RX_ERR)
-+ printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n",
-+ dev->name, status);
-+ np->stats.rx_errors++; /* end of a packet.*/
-+ if (status & 0x0890) np->stats.rx_length_errors++;
-+ if (status & 0x004C) np->stats.rx_frame_errors++;
-+ if (status & 0x0002) np->stats.rx_crc_errors++;
-+ }
-+ } else {
-+ struct sk_buff *skb;
-+ /* Omit the four octet CRC from the length. */
-+ int pkt_len = ((status >> 16) & 0x7ff) - 4;
-+
-+ if (np->msg_level & NETIF_MSG_RX_STATUS)
-+ printk(KERN_DEBUG " netdev_rx() normal Rx pkt length %d"
-+ " status %x.\n", pkt_len, status);
-+ /* Check if the packet is long enough to accept without copying
-+ to a minimally-sized skbuff. */
-+ if (pkt_len < np->rx_copybreak
-+ && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
-+ skb->dev = dev;
-+ skb_reserve(skb, 2); /* 16 byte align the IP header */
-+ /* Call copy + cksum if available. */
-+#if HAS_IP_COPYSUM
-+ eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0);
-+ skb_put(skb, pkt_len);
-+#else
-+ memcpy(skb_put(skb, pkt_len), np->rx_skbuff[entry]->tail,
-+ pkt_len);
-+#endif
-+ } else {
-+ char *temp = skb_put(skb = np->rx_skbuff[entry], pkt_len);
-+ np->rx_skbuff[entry] = NULL;
-+#ifndef final_version /* Remove after testing. */
-+ if (bus_to_virt(desc->buffer1) != temp)
-+ printk(KERN_ERR "%s: Internal fault: The skbuff addresses "
-+ "do not match in netdev_rx: %p vs. %p / %p.\n",
-+ dev->name, bus_to_virt(desc->buffer1),
-+ skb->head, temp);
-+#endif
-+ }
-+ skb->protocol = eth_type_trans(skb, dev);
-+ netif_rx(skb);
-+ dev->last_rx = jiffies;
-+ np->stats.rx_packets++;
-+#if LINUX_VERSION_CODE > 0x20127
-+ np->stats.rx_bytes += pkt_len;
-+#endif
-+ }
-+ entry = (++np->cur_rx) % np->rx_ring_size;
-+ np->rx_head_desc = &np->rx_ring[entry];
-+ }
-+
-+ /* Refill the Rx ring buffers. */
-+ for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) {
-+ struct sk_buff *skb;
-+ entry = np->dirty_rx % np->rx_ring_size;
-+ if (np->rx_skbuff[entry] == NULL) {
-+ skb = dev_alloc_skb(np->rx_buf_sz);
-+ np->rx_skbuff[entry] = skb;
-+ if (skb == NULL)
-+ break; /* Better luck next round. */
-+ skb->dev = dev; /* Mark as being used by this device. */
-+ np->rx_ring[entry].buffer1 = virt_to_bus(skb->tail);
-+ }
-+ np->rx_ring[entry].status = DescOwn;
-+ }
-+
-+ return 0;
-+}
-+
-+static void netdev_error(struct net_device *dev, int intr_status)
-+{
-+ long ioaddr = dev->base_addr;
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+
-+ if (np->msg_level & NETIF_MSG_MISC)
-+ printk(KERN_DEBUG "%s: Abnormal event, %8.8x.\n",
-+ dev->name, intr_status);
-+ if (intr_status == 0xffffffff)
-+ return;
-+ if (intr_status & TxFIFOUnderflow) {
-+ np->csr6 += 0x4000; /* Bump up the Tx threshold */
-+ if (np->msg_level & NETIF_MSG_TX_ERR)
-+ printk(KERN_DEBUG "%s: Tx underflow, increasing threshold to "
-+ "%8.8x.\n", dev->name, np->csr6);
-+ writel(np->csr6, ioaddr + NetworkConfig);
-+ }
-+ if (intr_status & IntrRxDied) { /* Missed a Rx frame. */
-+ np->stats.rx_errors++;
-+ }
-+ if (intr_status & TimerInt) {
-+ /* Re-enable other interrupts. */
-+ writel(0x1A0F5, ioaddr + IntrEnable);
-+ }
-+ np->stats.rx_missed_errors += readl(ioaddr + RxMissed) & 0xffff;
-+ writel(0, ioaddr + RxStartDemand);
-+}
-+
-+static struct net_device_stats *get_stats(struct net_device *dev)
-+{
-+ long ioaddr = dev->base_addr;
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+
-+ /* The chip only need report frame silently dropped. */
-+ if (netif_running(dev))
-+ np->stats.rx_missed_errors += readl(ioaddr + RxMissed) & 0xffff;
-+
-+ return &np->stats;
-+}
-+
-+static unsigned const ethernet_polynomial = 0x04c11db7U;
-+static inline u32 ether_crc(int length, unsigned char *data)
-+{
-+ int crc = -1;
-+
-+ while(--length >= 0) {
-+ unsigned char current_octet = *data++;
-+ int bit;
-+ for (bit = 0; bit < 8; bit++, current_octet >>= 1) {
-+ crc = (crc << 1) ^
-+ ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
-+ }
-+ }
-+ return crc;
-+}
-+
-+static void set_rx_mode(struct net_device *dev)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+ u32 mc_filter[2]; /* Multicast hash filter */
-+ u32 rx_mode;
-+
-+ if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
-+ /* Unconditionally log net taps. */
-+ printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);
-+ memset(mc_filter, ~0, sizeof(mc_filter));
-+ rx_mode = AcceptBroadcast | AcceptMulticast | AcceptAllPhys;
-+ } else if ((dev->mc_count > np->multicast_filter_limit)
-+ || (dev->flags & IFF_ALLMULTI)) {
-+ /* Too many to match, or accept all multicasts. */
-+ memset(mc_filter, 0xff, sizeof(mc_filter));
-+ rx_mode = AcceptBroadcast | AcceptMulticast;
-+ } else {
-+ struct dev_mc_list *mclist;
-+ int i;
-+ memset(mc_filter, 0, sizeof(mc_filter));
-+ for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
-+ i++, mclist = mclist->next) {
-+ set_bit((ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26) ^ 0x3F,
-+ mc_filter);
-+ }
-+ rx_mode = AcceptBroadcast | AcceptMulticast;
-+ }
-+ writel(mc_filter[0], ioaddr + MulticastFilter0);
-+ writel(mc_filter[1], ioaddr + MulticastFilter1);
-+ np->csr6 &= ~0x00F8;
-+ np->csr6 |= rx_mode;
-+ writel(np->csr6, ioaddr + NetworkConfig);
-+}
-+
-+static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-+{
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ u16 *data = (u16 *)&rq->ifr_data;
-+ u32 *data32 = (void *)&rq->ifr_data;
-+
-+ switch(cmd) {
-+ case 0x8947: case 0x89F0:
-+ /* SIOCGMIIPHY: Get the address of the PHY in use. */
-+ data[0] = np->phys[0] & 0x1f;
-+ /* Fall Through */
-+ case 0x8948: case 0x89F1:
-+ /* SIOCGMIIREG: Read the specified MII register. */
-+ data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f);
-+ return 0;
-+ case 0x8949: case 0x89F2:
-+ /* SIOCSMIIREG: Write the specified MII register */
-+ if (!capable(CAP_NET_ADMIN))
-+ return -EPERM;
-+ if (data[0] == np->phys[0]) {
-+ u16 value = data[2];
-+ switch (data[1]) {
-+ case 0:
-+ /* Check for autonegotiation on or reset. */
-+ np->medialock = (value & 0x9000) ? 0 : 1;
-+ if (np->medialock)
-+ np->full_duplex = (value & 0x0100) ? 1 : 0;
-+ break;
-+ case 4: np->advertising = value; break;
-+ }
-+ /* Perhaps check_duplex(dev), depending on chip semantics. */
-+ }
-+ mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]);
-+ return 0;
-+ case SIOCGPARAMS:
-+ data32[0] = np->msg_level;
-+ data32[1] = np->multicast_filter_limit;
-+ data32[2] = np->max_interrupt_work;
-+ data32[3] = np->rx_copybreak;
-+ return 0;
-+ case SIOCSPARAMS:
-+ if (!capable(CAP_NET_ADMIN))
-+ return -EPERM;
-+ np->msg_level = data32[0];
-+ np->multicast_filter_limit = data32[1];
-+ np->max_interrupt_work = data32[2];
-+ np->rx_copybreak = data32[3];
-+ return 0;
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+}
-+
-+
-+static void empty_rings(struct net_device *dev)
-+{
-+ struct netdev_private *np = (void *)dev->priv;
-+ int i;
-+
-+ /* Free all the skbuffs in the Rx queue. */
-+ for (i = 0; i < np->rx_ring_size; i++) {
-+ np->rx_ring[i].status = 0;
-+ if (np->rx_skbuff[i]) {
-+#if LINUX_VERSION_CODE < 0x20100
-+ np->rx_skbuff[i]->free = 1;
-+#endif
-+ dev_free_skb(np->rx_skbuff[i]);
-+ }
-+ np->rx_skbuff[i] = 0;
-+ }
-+ for (i = 0; i < np->tx_ring_size; i++) {
-+ if (np->tx_skbuff[i])
-+ dev_free_skb(np->tx_skbuff[i]);
-+ np->tx_skbuff[i] = 0;
-+ }
-+}
-+
-+static int netdev_close(struct net_device *dev)
-+{
-+ long ioaddr = dev->base_addr;
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+
-+ netif_stop_tx_queue(dev);
-+
-+ if (np->msg_level & NETIF_MSG_IFDOWN) {
-+ printk(KERN_DEBUG "%s: Shutting down ethercard, status was %8.8x "
-+ "Config %8.8x.\n", dev->name, (int)readl(ioaddr + IntrStatus),
-+ (int)readl(ioaddr + NetworkConfig));
-+ printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d, Rx %d / %d.\n",
-+ dev->name, np->cur_tx, np->dirty_tx, np->cur_rx, np->dirty_rx);
-+ }
-+
-+ /* Disable interrupts by clearing the interrupt mask. */
-+ writel(0x0000, ioaddr + IntrEnable);
-+
-+ /* Stop the chip's Tx and Rx processes. */
-+ writel(np->csr6 &= ~0x20FA, ioaddr + NetworkConfig);
-+
-+ del_timer(&np->timer);
-+ if (readl(ioaddr + NetworkConfig) != 0xffffffff)
-+ np->stats.rx_missed_errors += readl(ioaddr + RxMissed) & 0xffff;
-+
-+#ifdef __i386__
-+ if (np->msg_level & NETIF_MSG_IFDOWN) {
-+ int i;
-+ printk("\n"KERN_DEBUG" Tx ring at %8.8x:\n",
-+ (int)virt_to_bus(np->tx_ring));
-+ for (i = 0; i < np->tx_ring_size; i++)
-+ printk(KERN_DEBUG " #%d desc. %4.4x %8.8x %8.8x.\n",
-+ i, np->tx_ring[i].length,
-+ np->tx_ring[i].status, np->tx_ring[i].buffer1);
-+ printk(KERN_DEBUG "\n" KERN_DEBUG " Rx ring %8.8x:\n",
-+ (int)virt_to_bus(np->rx_ring));
-+ for (i = 0; i < np->rx_ring_size; i++) {
-+ printk(KERN_DEBUG " #%d desc. %4.4x %4.4x %8.8x\n",
-+ i, np->rx_ring[i].length,
-+ np->rx_ring[i].status, np->rx_ring[i].buffer1);
-+ }
-+ }
-+#endif /* __i386__ debugging only */
-+
-+ free_irq(dev->irq, dev);
-+ empty_rings(dev);
-+
-+ MOD_DEC_USE_COUNT;
-+
-+ return 0;
-+}
-+
-+static int winbond_pwr_event(void *dev_instance, int event)
-+{
-+ struct net_device *dev = dev_instance;
-+ struct netdev_private *np = (struct netdev_private *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+
-+ if (np->msg_level & NETIF_MSG_LINK)
-+ printk(KERN_DEBUG "%s: Handling power event %d.\n", dev->name, event);
-+ switch(event) {
-+ case DRV_ATTACH:
-+ MOD_INC_USE_COUNT;
-+ break;
-+ case DRV_SUSPEND: {
-+ int csr6 = readl(ioaddr + NetworkConfig);
-+ /* Disable interrupts, stop the chip, gather stats. */
-+ if (csr6 != 0xffffffff) {
-+ int csr8 = readl(ioaddr + RxMissed);
-+ writel(0x00000000, ioaddr + IntrEnable);
-+ writel(csr6 & ~TxOn & ~RxOn, ioaddr + NetworkConfig);
-+ np->stats.rx_missed_errors += (unsigned short)csr8;
-+ }
-+ empty_rings(dev);
-+ break;
-+ }
-+ case DRV_RESUME:
-+ writel(np->csr0, ioaddr + PCIBusCfg);
-+ init_ring(dev);
-+ writel(virt_to_bus(np->rx_ring), ioaddr + RxRingPtr);
-+ writel(virt_to_bus(np->tx_ring), ioaddr + TxRingPtr);
-+ writel(0x1A0F5, ioaddr + IntrStatus);
-+ writel(0x1A0F5, ioaddr + IntrEnable);
-+ writel(np->csr6 | TxOn | RxOn, ioaddr + NetworkConfig);
-+ writel(0, ioaddr + RxStartDemand); /* Rx poll demand */
-+ set_rx_mode(dev);
-+ break;
-+ case DRV_DETACH: {
-+ struct net_device **devp, **next;
-+ if (dev->flags & IFF_UP) {
-+ printk(KERN_ERR "%s: Winbond-840 NIC removed while still "
-+ "active.\n", dev->name);
-+ dev_close(dev);
-+ dev->flags &= ~(IFF_UP|IFF_RUNNING);
-+ }
-+ unregister_netdev(dev);
-+ release_region(dev->base_addr, pci_id_tbl[np->chip_id].io_size);
-+#ifndef USE_IO_OPS
-+ iounmap((char *)dev->base_addr);
-+#endif
-+ for (devp = &root_net_dev; *devp; devp = next) {
-+ next = &((struct netdev_private *)(*devp)->priv)->next_module;
-+ if (*devp == dev) {
-+ *devp = *next;
-+ break;
-+ }
-+ }
-+ if (np->priv_addr)
-+ kfree(np->priv_addr);
-+ kfree(dev);
-+ MOD_DEC_USE_COUNT;
-+ break;
-+ }
-+ default:
-+ break;
-+ }
-+
-+ return 0;
-+}
-+
-+
-+#ifdef MODULE
-+int init_module(void)
-+{
-+ if (debug >= NETIF_MSG_DRV) /* Emit version even if no cards detected. */
-+ printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2);
-+ return pci_drv_register(&winbond840_drv_id, NULL);
-+}
-+
-+void cleanup_module(void)
-+{
-+ struct net_device *next_dev;
-+
-+ pci_drv_unregister(&winbond840_drv_id);
-+
-+ /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
-+ while (root_net_dev) {
-+ struct netdev_private *np = (void *)(root_net_dev->priv);
-+ unregister_netdev(root_net_dev);
-+#ifdef USE_IO_OPS
-+ release_region(root_net_dev->base_addr,
-+ pci_id_tbl[np->chip_id].io_size);
-+#else
-+ iounmap((char *)(root_net_dev->base_addr));
-+#endif
-+ next_dev = np->next_module;
-+ if (np->priv_addr)
-+ kfree(np->priv_addr);
-+ kfree(root_net_dev);
-+ root_net_dev = next_dev;
-+ }
-+}
-+#else
-+int winbond840_probe(struct net_device *dev)
-+{
-+ if (pci_drv_register(&winbond840_drv_id, dev) < 0)
-+ return -ENODEV;
-+ printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2);
-+ return 0;
-+}
-+#endif /* MODULE */
-+
-+
-+/*
-+ * Local variables:
-+ * compile-command: "make KERNVER=`uname -r` winbond-840.o"
-+ * compile-cmd: "gcc -DMODULE -Wall -Wstrict-prototypes -O6 -c winbond-840.c"
-+ * c-indent-level: 4
-+ * c-basic-offset: 4
-+ * tab-width: 4
-+ * End:
-+ */
-Index: linux/src/drivers/net/yellowfin.c
-===================================================================
-RCS file: /cvsroot/hurd/gnumach/linux/src/drivers/net/Attic/yellowfin.c,v
-retrieving revision 1.2
-diff -u -r1.2 yellowfin.c
---- linux/src/drivers/net/yellowfin.c 7 Sep 1999 07:19:16 -0000 1.2
-+++ linux/src/drivers/net/yellowfin.c 20 Aug 2004 10:32:55 -0000
-@@ -1,28 +1,47 @@
- /* yellowfin.c: A Packet Engines G-NIC ethernet driver for linux. */
- /*
-- Written 1997-1998 by Donald Becker.
-+ Written 1997-2003 by Donald Becker.
-
-- This software may be used and distributed according to the terms
-- of the GNU Public License, incorporated herein by reference.
-+ This software may be used and distributed according to the terms of
-+ the GNU General Public License (GPL), incorporated herein by reference.
-+ Drivers based on or derived from this code fall under the GPL and must
-+ retain the authorship, copyright and license notice. This file is not
-+ a complete program and may only be used when the entire operating
-+ system is licensed under the GPL.
-
- This driver is for the Packet Engines G-NIC PCI Gigabit Ethernet adapter.
- It also supports the Symbios Logic version of the same chip core.
-
-- The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
-- Center of Excellence in Space Data and Information Sciences
-- Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
--
-- Support and updates available at
-- http://cesdis.gsfc.nasa.gov/linux/drivers/yellowfin.html
-+ The author may be reached as becker@scyld.com, or C/O
-+ Scyld Computing Corporation
-+ 914 Bay Ridge Road, Suite 220
-+ Annapolis MD 21403
-+
-+ Support information and updates available at
-+ http://www.scyld.com/network/yellowfin.html
-+ The information and support mailing lists are based at
-+ http://www.scyld.com/mailman/listinfo/
- */
-
--static const char *version = "yellowfin.c:v0.99A 4/7/98 becker@cesdis.gsfc.nasa.gov\n";
-+/* These identify the driver base version and may not be removed. */
-+static const char version1[] =
-+"yellowfin.c:v1.10 7/22/2003 Written by Donald Becker <becker@scyld.com>\n";
-+static const char version2[] =
-+" http://www.scyld.com/network/yellowfin.html\n";
-+
-+/* The user-configurable values.
-+ These may be modified when a driver module is loaded.*/
-
--/* A few user-configurable values. */
-+/* Message enable level: 0..31 = no..all messages. See NETIF_MSG docs. */
-+static int debug = 2;
-
-+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
- static int max_interrupt_work = 20;
--static int min_pci_latency = 64;
--static int mtu = 0;
-+
-+/* Maximum number of multicast addresses to filter (vs. rx-all-multicast).
-+ Typical is a 64 element hash table based on the Ethernet CRC. */
-+static int multicast_filter_limit = 64;
-+
- #ifdef YF_PROTOTYPE /* Support for prototype hardware errata. */
- /* System-wide count of bogus-rx frames. */
- static int bogus_rx = 0;
-@@ -38,109 +57,121 @@
-
- /* Set the copy breakpoint for the copy-only-tiny-frames scheme.
- Setting to > 1518 effectively disables this feature. */
--static const int rx_copybreak = 100;
-+static int rx_copybreak = 0;
-+
-+/* Used to pass the media type, etc.
-+ No media types are currently defined. These options exist only for
-+ compatibility with other drivers.
-+*/
-+#define MAX_UNITS 8 /* More are supported, limit only on options */
-+static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-+static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-+
-+/* Do ugly workaround for GX server chipset errata. */
-+static int gx_fix = 0;
-+
-+/* Operational parameters that are set at compile time. */
-
- /* Keep the ring sizes a power of two for efficiency.
- Making the Tx ring too large decreases the effectiveness of channel
-- bonding and packet priority.
-- There are no ill effects from too-large receive rings. */
-+ bonding and packet priority, confuses the system network buffer limits,
-+ and wastes memory.
-+ Too-large receive rings waste memory and confound network buffer limits.
-+*/
- #define TX_RING_SIZE 16
--#define RX_RING_SIZE 32
-+#define TX_QUEUE_SIZE 12 /* Must be > 4 && <= TX_RING_SIZE */
-+#define RX_RING_SIZE 64
-
- /* Operational parameters that usually are not changed. */
- /* Time in jiffies before concluding the transmitter is hung. */
--#define TX_TIMEOUT ((2000*HZ)/1000)
-+#define TX_TIMEOUT (6*HZ)
-+
-+/* Allocation size of Rx buffers with normal sized Ethernet frames.
-+ Do not change this value without good reason. This is not a limit,
-+ but a way to keep a consistent allocation size among drivers.
-+ */
-+#define PKT_BUF_SZ 1536
-+
-+#ifndef __KERNEL__
-+#define __KERNEL__
-+#endif
-+#if !defined(__OPTIMIZE__)
-+#warning You must compile this file with the correct options!
-+#warning See the last lines of the source file.
-+#error You must compile this driver with "-O".
-+#endif
-
- #include <linux/config.h>
--#ifdef MODULE
--#ifdef MODVERSIONS
--#include <linux/modversions.h>
-+#if defined(CONFIG_SMP) && ! defined(__SMP__)
-+#define __SMP__
- #endif
--#include <linux/module.h>
-+#if defined(MODULE) && defined(CONFIG_MODVERSIONS) && ! defined(MODVERSIONS)
-+#define MODVERSIONS
-+#endif
-+
- #include <linux/version.h>
--#else
--#define MOD_INC_USE_COUNT
--#define MOD_DEC_USE_COUNT
-+#if defined(MODVERSIONS)
-+#include <linux/modversions.h>
- #endif
-+#include <linux/module.h>
-
- #include <linux/kernel.h>
--#include <linux/sched.h>
- #include <linux/string.h>
- #include <linux/timer.h>
--#include <linux/ptrace.h>
- #include <linux/errno.h>
- #include <linux/ioport.h>
-+#if LINUX_VERSION_CODE >= 0x20400
-+#include <linux/slab.h>
-+#else
- #include <linux/malloc.h>
-+#endif
- #include <linux/interrupt.h>
- #include <linux/pci.h>
--#include <linux/bios32.h>
--#include <asm/processor.h> /* Processor type for cache alignment. */
--#include <asm/bitops.h>
--#include <asm/io.h>
--
- #include <linux/netdevice.h>
- #include <linux/etherdevice.h>
- #include <linux/skbuff.h>
-+#include <asm/processor.h> /* Processor type for cache alignment. */
-+#include <asm/unaligned.h>
-+#include <asm/bitops.h>
-+#include <asm/io.h>
-
--/* Kernel compatibility defines, common to David Hind's PCMCIA package.
-- This is only in the support-all-kernels source code. */
--#include <linux/version.h> /* Evil, but neccessary */
--
--#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x10300
--#define RUN_AT(x) (x) /* What to put in timer->expires. */
--#define DEV_ALLOC_SKB(len) alloc_skb(len, GFP_ATOMIC)
--#define virt_to_bus(addr) ((unsigned long)addr)
--#define bus_to_virt(addr) ((void*)addr)
--
--#else /* 1.3.0 and later */
--#define RUN_AT(x) (jiffies + (x))
--#define DEV_ALLOC_SKB(len) dev_alloc_skb(len + 2)
--#endif
--
--#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x10338
--#ifdef MODULE
--#if !defined(CONFIG_MODVERSIONS) && !defined(__NO_VERSION__)
--char kernel_version[] = UTS_RELEASE;
--#endif
-+#ifdef INLINE_PCISCAN
-+#include "k_compat.h"
- #else
--#undef MOD_INC_USE_COUNT
--#define MOD_INC_USE_COUNT
--#undef MOD_DEC_USE_COUNT
--#define MOD_DEC_USE_COUNT
--#endif
--#endif /* 1.3.38 */
--
--#if (LINUX_VERSION_CODE >= 0x10344)
--#define NEW_MULTICAST
--#include <linux/delay.h>
--#endif
--#if (LINUX_VERSION_CODE >= 0x20100)
--char kernel_version[] = UTS_RELEASE;
--#endif
--#ifdef SA_SHIRQ
--#define IRQ(irq, dev_id, pt_regs) (irq, dev_id, pt_regs)
--#else
--#define IRQ(irq, dev_id, pt_regs) (irq, pt_regs)
--#endif
--#if (LINUX_VERSION_CODE < 0x20123)
--#define test_and_set_bit(val, addr) set_bit(val, addr)
-+#include "pci-scan.h"
-+#include "kern_compat.h"
- #endif
-
--static const char *card_name = "Yellowfin G-NIC Gbit Ethernet";
-+/* Condensed operations for readability. */
-+#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr))
-+#define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr))
-
--/* The PCI I/O space extent. */
--#define YELLOWFIN_TOTAL_SIZE 0x100
--
--#ifdef HAVE_DEVLIST
--struct netdev_entry yellowfin_drv =
--{card_name, yellowfin_pci_probe, YELLOWFIN_TOTAL_SIZE, NULL};
-+#if (LINUX_VERSION_CODE >= 0x20100) && defined(MODULE)
-+char kernel_version[] = UTS_RELEASE;
- #endif
-
--#ifdef YELLOWFIN_DEBUG
--int yellowfin_debug = YELLOWFIN_DEBUG;
--#else
--int yellowfin_debug = 1;
--#endif
-+MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
-+MODULE_DESCRIPTION("Packet Engines Yellowfin G-NIC Gigabit Ethernet driver");
-+MODULE_LICENSE("GPL");
-+MODULE_PARM(debug, "i");
-+MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
-+MODULE_PARM(rx_copybreak, "i");
-+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
-+MODULE_PARM(multicast_filter_limit, "i");
-+MODULE_PARM(max_interrupt_work, "i");
-+MODULE_PARM(gx_fix, "i");
-+MODULE_PARM_DESC(debug, "Driver message level enable (0-31)");
-+MODULE_PARM_DESC(options, "Force transceiver type or fixed speed+duplex");
-+MODULE_PARM_DESC(rx_copybreak,
-+ "Breakpoint in bytes for copy-only-tiny-frames");
-+MODULE_PARM_DESC(full_duplex,
-+ "Non-zero to force full duplex, non-negotiated link "
-+ "(deprecated).");
-+MODULE_PARM_DESC(max_interrupt_work,
-+ "Driver maximum events handled per interrupt");
-+MODULE_PARM_DESC(multicast_filter_limit,
-+ "Multicast addresses before switching to Rx-all-multicast");
-+MODULE_PARM_DESC(gx_fix, "Set to work around old GX chipset errata");
-
- /*
- Theory of Operation
-@@ -203,29 +234,50 @@
- IV. Notes
-
- Thanks to Kim Stearns of Packet Engines for providing a pair of G-NIC boards.
-+Thanks to Bruce Faust of Digitalscape for providing both their SYM53C885 board
-+and an AlphaStation to verifty the Alpha port!
-
- IVb. References
-
- Yellowfin Engineering Design Specification, 4/23/97 Preliminary/Confidential
-+Symbios SYM53C885 PCI-SCSI/Fast Ethernet Multifunction Controller Preliminary
-+ Data Manual v3.0
-+http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html
- http://cesdis.gsfc.nasa.gov/linux/misc/100mbps.html
-
- IVc. Errata
-
--See Packet Engines confidential appendix.
--
-+See Packet Engines confidential appendix (prototype chips only).
- */
-+
-
--/* A few values that may be tweaked. */
--#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/
-
--#ifndef PCI_VENDOR_ID_PKT_ENG /* To be defined in linux/pci.h */
--#define PCI_VENDOR_ID_PKT_ENG 0x1000 /* Hmm, likely number.. */
--#define PCI_DEVICE_ID_YELLOWFIN 0x0702
-+static void *yellowfin_probe1(struct pci_dev *pdev, void *init_dev,
-+ long ioaddr, int irq, int chip_idx, int fnd_cnt);
-+enum capability_flags {
-+ HasMII=1, FullTxStatus=2, IsGigabit=4, HasMulticastBug=8, FullRxStatus=16,
-+ HasMACAddrBug=32, /* Only on early revs. */
-+};
-+/* The PCI I/O space extent. */
-+#define YELLOWFIN_SIZE 0x100
-+#ifdef USE_IO_OPS
-+#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_IO | PCI_ADDR0)
-+#else
-+#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR1)
- #endif
-
--/* The rest of these values should never change. */
-+static struct pci_id_info pci_id_tbl[] = {
-+ {"Yellowfin G-NIC Gigabit Ethernet", { 0x07021000, 0xffffffff},
-+ PCI_IOTYPE, YELLOWFIN_SIZE,
-+ FullTxStatus | IsGigabit | HasMulticastBug | HasMACAddrBug},
-+ {"Symbios SYM83C885", { 0x07011000, 0xffffffff},
-+ PCI_IOTYPE, YELLOWFIN_SIZE, HasMII },
-+ {0,},
-+};
-
--static void yellowfin_timer(unsigned long data);
-+struct drv_id_info yellowfin_drv_id = {
-+ "yellowfin", PCI_HOTSWAP, PCI_CLASS_NETWORK_ETHERNET<<8, pci_id_tbl,
-+ yellowfin_probe1, };
-
- /* Offsets to the Yellowfin registers. Various sizes and alignments. */
- enum yellowfin_offsets {
-@@ -234,33 +286,45 @@
- RxCtrl=0x40, RxStatus=0x44, RxPtr=0x4C,
- RxIntrSel=0x50, RxBranchSel=0x54, RxWaitSel=0x58,
- EventStatus=0x80, IntrEnb=0x82, IntrClear=0x84, IntrStatus=0x86,
-- ChipRev=0x8C, DMACtrl=0x90, Cnfg=0xA0, RxDepth=0xB8, FlowCtrl=0xBC,
-+ ChipRev=0x8C, DMACtrl=0x90, TxThreshold=0x94,
-+ Cnfg=0xA0, FrameGap0=0xA2, FrameGap1=0xA4,
-+ MII_Cmd=0xA6, MII_Addr=0xA8, MII_Wr_Data=0xAA, MII_Rd_Data=0xAC,
-+ MII_Status=0xAE,
-+ RxDepth=0xB8, FlowCtrl=0xBC,
- AddrMode=0xD0, StnAddr=0xD2, HashTbl=0xD8, FIFOcfg=0xF8,
-+ EEStatus=0xF0, EECtrl=0xF1, EEAddr=0xF2, EERead=0xF3, EEWrite=0xF4,
-+ EEFeature=0xF5,
- };
-
--/* The Yellowfin Rx and Tx buffer descriptors. */
-+/* The Yellowfin Rx and Tx buffer descriptors.
-+ Elements are written as 32 bit for endian portability. */
- struct yellowfin_desc {
-- u16 request_cnt;
-- u16 cmd;
-+ u32 dbdma_cmd;
- u32 addr;
- u32 branch_addr;
-- u16 result_cnt;
-- u16 status;
-+ u32 result_status;
- };
-
- struct tx_status_words {
-+#if defined(__powerpc__)
-+ u16 tx_errs;
-+ u16 tx_cnt;
-+ u16 paused;
-+ u16 total_tx_cnt;
-+#else /* Little endian chips. */
- u16 tx_cnt;
- u16 tx_errs;
- u16 total_tx_cnt;
- u16 paused;
-+#endif
- };
-
- /* Bits in yellowfin_desc.cmd */
- enum desc_cmd_bits {
-- CMD_TX_PKT=0x1000, CMD_RX_BUF=0x2000, CMD_TXSTATUS=0x3000,
-- CMD_NOP=0x6000, CMD_STOP=0x7000,
-- BRANCH_ALWAYS=0x0C, INTR_ALWAYS=0x30, WAIT_ALWAYS=0x03,
-- BRANCH_IFTRUE=0x04,
-+ CMD_TX_PKT=0x10000000, CMD_RX_BUF=0x20000000, CMD_TXSTATUS=0x30000000,
-+ CMD_NOP=0x60000000, CMD_STOP=0x70000000,
-+ BRANCH_ALWAYS=0x0C0000, INTR_ALWAYS=0x300000, WAIT_ALWAYS=0x030000,
-+ BRANCH_IFTRUE=0x040000,
- };
-
- /* Bits in yellowfin_desc.status */
-@@ -272,227 +336,159 @@
- IntrTxDone=0x10, IntrTxInvalid=0x20, IntrTxPCIFault=0x40,IntrTxPCIErr=0x80,
- IntrEarlyRx=0x100, IntrWakeup=0x200, };
-
-+#define PRIV_ALIGN 31 /* Required alignment mask */
- struct yellowfin_private {
-- /* Descriptor rings first for alignment. Tx requires a second descriptor
-- for status. */
-+ /* Descriptor rings first for alignment.
-+ Tx requires a second descriptor for status. */
- struct yellowfin_desc rx_ring[RX_RING_SIZE];
- struct yellowfin_desc tx_ring[TX_RING_SIZE*2];
-- const char *product_name;
-- struct device *next_module;
-- /* The saved address of a sent-in-place packet/buffer, for skfree(). */
-- struct sk_buff* tx_skbuff[TX_RING_SIZE];
-- struct tx_status_words tx_status[TX_RING_SIZE];
-+ struct net_device *next_module;
-+ void *priv_addr; /* Unaligned address for kfree */
- /* The addresses of receive-in-place skbuffs. */
- struct sk_buff* rx_skbuff[RX_RING_SIZE];
-- int chip_id;
-- struct enet_statistics stats;
-+ /* The saved address of a sent-in-place packet/buffer, for later free(). */
-+ struct sk_buff* tx_skbuff[TX_RING_SIZE];
-+ struct tx_status_words tx_status[TX_RING_SIZE];
- struct timer_list timer; /* Media selection timer. */
-- int in_interrupt;
-- unsigned int cur_rx, cur_tx; /* The next free ring entry */
-- unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */
-+ struct net_device_stats stats;
-+ /* Frequently used and paired value: keep adjacent for cache effect. */
-+ int msg_level;
-+ int chip_id, drv_flags;
-+ struct pci_dev *pci_dev;
-+ long in_interrupt;
-+ int max_interrupt_work;
-+
-+ struct yellowfin_desc *rx_head_desc;
-+ unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */
-+ unsigned int rx_buf_sz; /* Based on MTU+slack. */
-+ int rx_copybreak;
-+
-+ struct tx_status_words *tx_tail_desc;
-+ unsigned int cur_tx, dirty_tx;
-+ int tx_threshold;
- unsigned int tx_full:1; /* The Tx queue is full. */
- unsigned int full_duplex:1; /* Full-duplex operation requested. */
-+ unsigned int duplex_lock:1;
- unsigned int medialock:1; /* Do not sense media. */
-- unsigned int default_port:4; /* Last dev->if_port value. */
-- u32 pad[4]; /* Used for 32-byte alignment */
-+ unsigned int default_port; /* Last dev->if_port value. */
-+ /* MII transceiver section. */
-+ int mii_cnt; /* MII device addresses. */
-+ u16 advertising; /* NWay media advertisement */
-+ unsigned char phys[2]; /* MII device addresses. */
-+ /* Rx multicast filter. */
-+ u16 mc_filter[4];
-+ int rx_mode;
-+ int multicast_filter_limit;
- };
-
--#ifdef MODULE
--/* Used to pass the media type, etc. */
--#define MAX_UNITS 8 /* More are supported, limit only on options */
--static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
--
--#if LINUX_VERSION_CODE > 0x20115
--MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
--MODULE_DESCRIPTION("Packet Engines Yellowfin G-NIC Gigabit Ethernet driver");
--MODULE_PARM(max_interrupt_work, "i");
--MODULE_PARM(min_pci_latency, "i");
--MODULE_PARM(mtu, "i");
--MODULE_PARM(debug, "i");
--MODULE_PARM(rx_copybreak, "i");
--MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
-+static int read_eeprom(long ioaddr, int location);
-+static int mdio_read(long ioaddr, int phy_id, int location);
-+static void mdio_write(long ioaddr, int phy_id, int location, int value);
-+#ifdef HAVE_PRIVATE_IOCTL
-+static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
- #endif
--
--#endif
--
--static struct device *yellowfin_probe1(struct device *dev, int ioaddr, int irq,
-- int chip_id, int options);
--static int yellowfin_open(struct device *dev);
-+static int yellowfin_open(struct net_device *dev);
- static void yellowfin_timer(unsigned long data);
--static void yellowfin_tx_timeout(struct device *dev);
--static void yellowfin_init_ring(struct device *dev);
--static int yellowfin_start_xmit(struct sk_buff *skb, struct device *dev);
--static int yellowfin_rx(struct device *dev);
--static void yellowfin_interrupt IRQ(int irq, void *dev_instance, struct pt_regs *regs);
--static int yellowfin_close(struct device *dev);
--static struct enet_statistics *yellowfin_get_stats(struct device *dev);
--#ifdef NEW_MULTICAST
--static void set_rx_mode(struct device *dev);
--#else
--static void set_rx_mode(struct device *dev, int num_addrs, void *addrs);
--#endif
-+static void yellowfin_tx_timeout(struct net_device *dev);
-+static void yellowfin_init_ring(struct net_device *dev);
-+static int yellowfin_start_xmit(struct sk_buff *skb, struct net_device *dev);
-+static void yellowfin_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
-+static int yellowfin_rx(struct net_device *dev);
-+static void yellowfin_error(struct net_device *dev, int intr_status);
-+static int yellowfin_close(struct net_device *dev);
-+static struct net_device_stats *yellowfin_get_stats(struct net_device *dev);
-+static void set_rx_mode(struct net_device *dev);
-
-
-
--#ifdef MODULE
--/* A list of all installed Yellowfin devices, for removing the driver module. */
--static struct device *root_yellowfin_dev = NULL;
--#endif
-+/* A list of installed Yellowfin devices, for removing the driver module. */
-+static struct net_device *root_yellowfin_dev = NULL;
-
--int yellowfin_probe(struct device *dev)
-+#ifndef MODULE
-+int yellowfin_probe(struct net_device *dev)
- {
-- int cards_found = 0;
-- static int pci_index = 0; /* Static, for multiple probe calls. */
--
-- /* Ideally we would detect all network cards in slot order. That would
-- be best done a central PCI probe dispatch, which wouldn't work
-- well with the current structure. So instead we detect just the
-- Yellowfin cards in slot order. */
--
-- if (pcibios_present()) {
-- unsigned char pci_bus, pci_device_fn;
--
-- for (;pci_index < 0xff; pci_index++) {
-- u8 pci_irq_line, pci_latency;
-- u16 pci_command, vendor, device;
-- u32 pci_ioaddr, chip_idx = 0;
--
--#ifdef REVERSE_PROBE_ORDER
-- if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8,
-- 0xfe - pci_index,
-- &pci_bus, &pci_device_fn)
-- != PCIBIOS_SUCCESSFUL)
-- continue;
--#else
-- if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8,
-- pci_index,
-- &pci_bus, &pci_device_fn)
-- != PCIBIOS_SUCCESSFUL)
-- break;
--#endif
-- pcibios_read_config_word(pci_bus, pci_device_fn,
-- PCI_VENDOR_ID, &vendor);
-- pcibios_read_config_word(pci_bus, pci_device_fn,
-- PCI_DEVICE_ID, &device);
-- pcibios_read_config_byte(pci_bus, pci_device_fn,
-- PCI_INTERRUPT_LINE, &pci_irq_line);
-- pcibios_read_config_dword(pci_bus, pci_device_fn,
-- PCI_BASE_ADDRESS_0, &pci_ioaddr);
-- /* Remove I/O space marker in bit 0. */
-- pci_ioaddr &= ~3;
--
-- if (vendor != PCI_VENDOR_ID_PKT_ENG)
-- continue;
--
-- if (device != PCI_DEVICE_ID_YELLOWFIN)
-- continue;
--
-- if (yellowfin_debug > 2)
-- printk("Found Packet Engines Yellowfin G-NIC at I/O %#x, IRQ %d.\n",
-- pci_ioaddr, pci_irq_line);
--
-- if (check_region(pci_ioaddr, YELLOWFIN_TOTAL_SIZE))
-- continue;
--
--#ifdef MODULE
-- dev = yellowfin_probe1(dev, pci_ioaddr, pci_irq_line, chip_idx,
-- cards_found < MAX_UNITS ? options[cards_found] : 0);
--#else
-- dev = yellowfin_probe1(dev, pci_ioaddr, pci_irq_line, chip_idx,
-- dev ? dev->mem_start : 0);
--#endif
--
-- if (dev) {
-- /* Get and check the bus-master and latency values. */
-- pcibios_read_config_word(pci_bus, pci_device_fn,
-- PCI_COMMAND, &pci_command);
-- if ( ! (pci_command & PCI_COMMAND_MASTER)) {
-- printk(" PCI Master Bit has not been set! Setting...\n");
-- pci_command |= PCI_COMMAND_MASTER;
-- pcibios_write_config_word(pci_bus, pci_device_fn,
-- PCI_COMMAND, pci_command);
-- }
-- pcibios_read_config_byte(pci_bus, pci_device_fn,
-- PCI_LATENCY_TIMER, &pci_latency);
-- if (pci_latency < min_pci_latency) {
-- printk(" PCI latency timer (CFLT) is unreasonably low at %d."
-- " Setting to %d clocks.\n",
-- pci_latency, min_pci_latency);
-- pcibios_write_config_byte(pci_bus, pci_device_fn,
-- PCI_LATENCY_TIMER, min_pci_latency);
-- } else if (yellowfin_debug > 1)
-- printk(" PCI latency timer (CFLT) is %#x.\n", pci_latency);
-- dev = 0;
-- cards_found++;
-- }
-- }
-- }
--
--#if defined (MODULE)
-- return cards_found;
--#else
-- return cards_found ? 0 : -ENODEV;
--#endif
-+ if (pci_drv_register(&yellowfin_drv_id, dev) < 0)
-+ return -ENODEV;
-+ printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2);
-+ return 0;
- }
-+#endif
-
--static struct device *yellowfin_probe1(struct device *dev, int ioaddr, int irq,
-- int chip_id, int options)
-+static void *yellowfin_probe1(struct pci_dev *pdev, void *init_dev,
-+ long ioaddr, int irq, int chip_idx, int find_cnt)
- {
-- static int did_version = 0; /* Already printed version info. */
-- struct yellowfin_private *yp;
-- int i;
--
-- if (yellowfin_debug > 0 && did_version++ == 0)
-- printk(version);
--
-- dev = init_etherdev(dev, sizeof(struct yellowfin_private));
--
-- printk("%s: P-E Yellowfin type %8x at %#3x, ",
-- dev->name, inl(ioaddr + ChipRev), ioaddr);
--
-+ struct net_device *dev;
-+ struct yellowfin_private *np;
-+ void *priv_mem;
-+ int i, option = find_cnt < MAX_UNITS ? options[find_cnt] : 0;
-+ int drv_flags = pci_id_tbl[chip_idx].drv_flags;
-+
-+ dev = init_etherdev(init_dev, 0);
-+ if (!dev)
-+ return NULL;
-+
-+ printk(KERN_INFO "%s: %s type %8x at 0x%lx, ",
-+ dev->name, pci_id_tbl[chip_idx].name, (int)inl(ioaddr + ChipRev),
-+ ioaddr);
-+
-+ if (drv_flags & IsGigabit)
-+ for (i = 0; i < 6; i++)
-+ dev->dev_addr[i] = inb(ioaddr + StnAddr + i);
-+ else {
-+ int ee_offset = (read_eeprom(ioaddr, 6) == 0xff ? 0x100 : 0);
-+ for (i = 0; i < 6; i++)
-+ dev->dev_addr[i] = read_eeprom(ioaddr, ee_offset + i);
-+ }
- for (i = 0; i < 5; i++)
-- printk("%2.2x:", inb(ioaddr + StnAddr + i));
-- printk("%2.2x, IRQ %d.\n", inb(ioaddr + StnAddr + i), irq);
-- for (i = 0; i < 6; i++)
-- dev->dev_addr[i] = inb(ioaddr + StnAddr + i);
-+ printk("%2.2x:", dev->dev_addr[i]);
-+ printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);
-
- /* Reset the chip. */
- outl(0x80000000, ioaddr + DMACtrl);
-
-+ /* Make certain elements e.g. descriptor lists are aligned. */
-+ priv_mem = kmalloc(sizeof(*np) + PRIV_ALIGN, GFP_KERNEL);
-+ /* Check for the very unlikely case of no memory. */
-+ if (priv_mem == NULL)
-+ return NULL;
-
- /* We do a request_region() only to register /proc/ioports info. */
-- request_region(ioaddr, YELLOWFIN_TOTAL_SIZE, card_name);
-+ request_region(ioaddr, pci_id_tbl[chip_idx].io_size, dev->name);
-
- dev->base_addr = ioaddr;
- dev->irq = irq;
-
-- /* Make certain the descriptor lists are aligned. */
-- yp = (void *)(((long)kmalloc(sizeof(*yp), GFP_KERNEL) + 31) & ~31);
-- memset(yp, 0, sizeof(*yp));
-- dev->priv = yp;
-+ dev->priv = np = (void *)(((long)priv_mem + PRIV_ALIGN) & ~PRIV_ALIGN);
-+ memset(np, 0, sizeof(*np));
-+ np->priv_addr = priv_mem;
-
--#ifdef MODULE
-- yp->next_module = root_yellowfin_dev;
-+ np->next_module = root_yellowfin_dev;
- root_yellowfin_dev = dev;
--#endif
-
-- yp->chip_id = chip_id;
-+ np->pci_dev = pdev;
-+ np->chip_id = chip_idx;
-+ np->drv_flags = drv_flags;
-+ np->msg_level = (1 << debug) - 1;
-+ np->rx_copybreak = rx_copybreak;
-+ np->max_interrupt_work = max_interrupt_work;
-+ np->multicast_filter_limit = multicast_filter_limit;
-
-- yp->full_duplex = 1;
--#ifdef YELLOWFIN_DEFAULT_MEDIA
-- yp->default_port = YELLOWFIN_DEFAULT_MEDIA;
--#endif
--#ifdef YELLOWFIN_NO_MEDIA_SWITCH
-- yp->medialock = 1;
--#endif
-+ if (dev->mem_start)
-+ option = dev->mem_start;
-
- /* The lower four bits are the media type. */
-- if (options > 0) {
-- yp->full_duplex = (options & 16) ? 1 : 0;
-- yp->default_port = options & 15;
-- if (yp->default_port)
-- yp->medialock = 1;
-+ if (option > 0) {
-+ if (option & 0x220)
-+ np->full_duplex = 1;
-+ np->default_port = option & 15;
-+ if (np->default_port)
-+ np->medialock = 1;
- }
-+ if (find_cnt < MAX_UNITS && full_duplex[find_cnt] > 0)
-+ np->full_duplex = 1;
-+
-+ if (np->full_duplex)
-+ np->duplex_lock = 1;
-
- /* The Yellowfin-specific entries in the device structure. */
- dev->open = &yellowfin_open;
-@@ -500,48 +496,97 @@
- dev->stop = &yellowfin_close;
- dev->get_stats = &yellowfin_get_stats;
- dev->set_multicast_list = &set_rx_mode;
-- if (mtu)
-- dev->mtu = mtu;
-+ dev->do_ioctl = &mii_ioctl;
-
-- /* todo: Reset the xcvr interface and turn on heartbeat. */
-+ if (np->drv_flags & HasMII) {
-+ int phy, phy_idx = 0;
-+ for (phy = 0; phy < 32 && phy_idx < 4; phy++) {
-+ int mii_status = mdio_read(ioaddr, phy, 1);
-+ if (mii_status != 0xffff && mii_status != 0x0000) {
-+ np->phys[phy_idx++] = phy;
-+ np->advertising = mdio_read(ioaddr, phy, 4);
-+ printk(KERN_INFO "%s: MII PHY found at address %d, status "
-+ "0x%4.4x advertising %4.4x.\n",
-+ dev->name, phy, mii_status, np->advertising);
-+ }
-+ }
-+ np->mii_cnt = phy_idx;
-+ }
-
- return dev;
- }
-
-+static int read_eeprom(long ioaddr, int location)
-+{
-+ int bogus_cnt = 10000; /* Typical 33Mhz: 1050 ticks */
-+
-+ outb(location, ioaddr + EEAddr);
-+ outb(0x30 | ((location >> 8) & 7), ioaddr + EECtrl);
-+ while ((inb(ioaddr + EEStatus) & 0x80) && --bogus_cnt > 0)
-+ ;
-+ return inb(ioaddr + EERead);
-+}
-+
-+/* MII Managemen Data I/O accesses.
-+ These routines assume the MDIO controller is idle, and do not exit until
-+ the command is finished. */
-+
-+static int mdio_read(long ioaddr, int phy_id, int location)
-+{
-+ int i;
-+
-+ outw((phy_id<<8) + location, ioaddr + MII_Addr);
-+ outw(1, ioaddr + MII_Cmd);
-+ for (i = 10000; i >= 0; i--)
-+ if ((inw(ioaddr + MII_Status) & 1) == 0)
-+ break;
-+ return inw(ioaddr + MII_Rd_Data);
-+}
-+
-+static void mdio_write(long ioaddr, int phy_id, int location, int value)
-+{
-+ int i;
-+
-+ outw((phy_id<<8) + location, ioaddr + MII_Addr);
-+ outw(value, ioaddr + MII_Wr_Data);
-+
-+ /* Wait for the command to finish. */
-+ for (i = 10000; i >= 0; i--)
-+ if ((inw(ioaddr + MII_Status) & 1) == 0)
-+ break;
-+ return;
-+}
-+
-
--static int
--yellowfin_open(struct device *dev)
-+static int yellowfin_open(struct net_device *dev)
- {
- struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv;
-- int ioaddr = dev->base_addr;
-+ long ioaddr = dev->base_addr;
-+ int i;
-
- /* Reset the chip. */
- outl(0x80000000, ioaddr + DMACtrl);
-
--#ifdef SA_SHIRQ
-- if (request_irq(dev->irq, &yellowfin_interrupt, SA_SHIRQ,
-- card_name, dev)) {
-- return -EAGAIN;
-- }
--#else
-- if (irq2dev_map[dev->irq] != NULL
-- || (irq2dev_map[dev->irq] = dev) == NULL
-- || dev->irq == 0
-- || request_irq(dev->irq, &yellowfin_interrupt, 0, card_name)) {
-+ MOD_INC_USE_COUNT;
-+
-+ if (request_irq(dev->irq, &yellowfin_interrupt, SA_SHIRQ, dev->name,
-+ dev)) {
-+ MOD_DEC_USE_COUNT;
- return -EAGAIN;
- }
--#endif
-
-- if (yellowfin_debug > 1)
-- printk("%s: yellowfin_open() irq %d.\n", dev->name, dev->irq);
--
-- MOD_INC_USE_COUNT;
-+ if (yp->msg_level & NETIF_MSG_IFUP)
-+ printk(KERN_DEBUG "%s: yellowfin_open() irq %d.\n",
-+ dev->name, dev->irq);
-
- yellowfin_init_ring(dev);
-
- outl(virt_to_bus(yp->rx_ring), ioaddr + RxPtr);
- outl(virt_to_bus(yp->tx_ring), ioaddr + TxPtr);
-
-+ for (i = 0; i < 6; i++)
-+ outb(dev->dev_addr[i], ioaddr + StnAddr + i);
-+
- /* Set up various condition 'select' registers.
- There are no options here. */
- outl(0x00800080, ioaddr + TxIntrSel); /* Interrupt on Tx abort */
-@@ -558,25 +603,27 @@
- /* Enable automatic generation of flow control frames, period 0xffff. */
- outl(0x0030FFFF, ioaddr + FlowCtrl);
-
-+ yp->tx_threshold = 32;
-+ outl(yp->tx_threshold, ioaddr + TxThreshold);
-+
- if (dev->if_port == 0)
- dev->if_port = yp->default_port;
-
-- dev->tbusy = 0;
-- dev->interrupt = 0;
- yp->in_interrupt = 0;
-
-- /* We are always in full-duplex mode with the current chip! */
-- yp->full_duplex = 1;
--
- /* Setting the Rx mode will start the Rx process. */
-- outw(0x01CD | (yp->full_duplex ? 2 : 0), ioaddr + Cnfg);
--#ifdef NEW_MULTICAST
-+ if (yp->drv_flags & IsGigabit) {
-+ /* We are always in full-duplex mode with gigabit! */
-+ yp->full_duplex = 1;
-+ outw(0x01CF, ioaddr + Cnfg);
-+ } else {
-+ outw(0x0018, ioaddr + FrameGap0); /* 0060/4060 for non-MII 10baseT */
-+ outw(0x1018, ioaddr + FrameGap1);
-+ outw(0x101C | (yp->full_duplex ? 2 : 0), ioaddr + Cnfg);
-+ }
-+ yp->rx_mode = 0;
- set_rx_mode(dev);
--#else
-- set_rx_mode(dev, 0, 0);
--#endif
--
-- dev->start = 1;
-+ netif_start_tx_queue(dev);
-
- /* Enable interrupts by setting the interrupt mask. */
- outw(0x81ff, ioaddr + IntrEnb); /* See enum intr_status_bits */
-@@ -584,13 +631,13 @@
- outl(0x80008000, ioaddr + RxCtrl); /* Start Rx and Tx channels. */
- outl(0x80008000, ioaddr + TxCtrl);
-
-- if (yellowfin_debug > 2) {
-- printk("%s: Done yellowfin_open().\n",
-+ if (yp->msg_level & NETIF_MSG_IFUP)
-+ printk(KERN_DEBUG "%s: Done yellowfin_open().\n",
- dev->name);
-- }
-+
- /* Set the timer to check for link beat. */
- init_timer(&yp->timer);
-- yp->timer.expires = RUN_AT((24*HZ)/10); /* 2.4 sec. */
-+ yp->timer.expires = jiffies + 3*HZ;
- yp->timer.data = (unsigned long)dev;
- yp->timer.function = &yellowfin_timer; /* timer handler */
- add_timer(&yp->timer);
-@@ -600,183 +647,240 @@
-
- static void yellowfin_timer(unsigned long data)
- {
-- struct device *dev = (struct device *)data;
-+ struct net_device *dev = (struct net_device *)data;
- struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv;
-- int ioaddr = dev->base_addr;
-- int next_tick = 0;
-+ long ioaddr = dev->base_addr;
-+ int next_tick = 60*HZ;
-+
-+ if (yp->msg_level & NETIF_MSG_TIMER)
-+ printk(KERN_DEBUG "%s: Yellowfin timer tick, status %8.8x.\n",
-+ dev->name, inw(ioaddr + IntrStatus));
-+
-+ if (jiffies - dev->trans_start > TX_TIMEOUT
-+ && yp->cur_tx - yp->dirty_tx > 1
-+ && netif_queue_paused(dev))
-+ yellowfin_tx_timeout(dev);
-
-- if (yellowfin_debug > 3) {
-- printk("%s: Yellowfin timer tick, status %8.8x.\n",
-- dev->name, inl(ioaddr + IntrStatus));
-- }
-- if (next_tick) {
-- yp->timer.expires = RUN_AT(next_tick);
-- add_timer(&yp->timer);
-+ if (yp->mii_cnt) {
-+ int mii_reg1 = mdio_read(ioaddr, yp->phys[0], 1);
-+ int mii_reg5 = mdio_read(ioaddr, yp->phys[0], 5);
-+ int negotiated = mii_reg5 & yp->advertising;
-+ if (yp->msg_level & NETIF_MSG_TIMER)
-+ printk(KERN_DEBUG "%s: MII #%d status register is %4.4x, "
-+ "link partner capability %4.4x.\n",
-+ dev->name, yp->phys[0], mii_reg1, mii_reg5);
-+
-+ if ( ! yp->duplex_lock &&
-+ ((negotiated & 0x0300) == 0x0100
-+ || (negotiated & 0x00C0) == 0x0040)) {
-+ yp->full_duplex = 1;
-+ }
-+ outw(0x101C | (yp->full_duplex ? 2 : 0), ioaddr + Cnfg);
-+
-+ if (mii_reg1 & 0x0004)
-+ next_tick = 60*HZ;
-+ else
-+ next_tick = 3*HZ;
- }
-+
-+ yp->timer.expires = jiffies + next_tick;
-+ add_timer(&yp->timer);
- }
-
--static void yellowfin_tx_timeout(struct device *dev)
-+static void yellowfin_tx_timeout(struct net_device *dev)
- {
- struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv;
-- int ioaddr = dev->base_addr;
-+ long ioaddr = dev->base_addr;
-
-- printk("%s: Yellowfin transmit timed out, status %8.8x, resetting...\n",
-- dev->name, inl(ioaddr));
-+ printk(KERN_WARNING "%s: Yellowfin transmit timed out at %d/%d Tx "
-+ "status %4.4x, Rx status %4.4x, resetting...\n",
-+ dev->name, yp->cur_tx, yp->dirty_tx,
-+ (int)inl(ioaddr + TxStatus), (int)inl(ioaddr + RxStatus));
-
--#ifndef __alpha__
-- {
-+ /* Note: these should be KERN_DEBUG. */
-+ if (yp->msg_level & NETIF_MSG_TX_ERR) {
- int i;
-- printk(" Rx ring %8.8x: ", (int)yp->rx_ring);
-+ printk(KERN_DEBUG " Rx ring %p: ", yp->rx_ring);
- for (i = 0; i < RX_RING_SIZE; i++)
-- printk(" %8.8x", (unsigned int)yp->rx_ring[i].status);
-- printk("\n Tx ring %8.8x: ", (int)yp->tx_ring);
-+ printk(" %8.8x", yp->rx_ring[i].result_status);
-+ printk("\n"KERN_DEBUG" Tx ring %p: ", yp->tx_ring);
- for (i = 0; i < TX_RING_SIZE; i++)
-- printk(" %4.4x /%4.4x", yp->tx_status[i].tx_errs, yp->tx_ring[i].status);
-+ printk(" %4.4x /%8.8x", yp->tx_status[i].tx_errs,
-+ yp->tx_ring[i].result_status);
- printk("\n");
- }
--#endif
-
-- /* Perhaps we should reinitialize the hardware here. */
-- dev->if_port = 0;
-- /* Stop and restart the chip's Tx processes . */
--
-- /* Trigger an immediate transmit demand. */
--
-- dev->trans_start = jiffies;
-- yp->stats.tx_errors++;
-- return;
--}
-+ /* If the hardware is found to hang regularly, we will update the code
-+ to reinitialize the chip here. */
-+ dev->if_port = 0;
-
-+ /* Wake the potentially-idle transmit channel. */
-+ outl(0x10001000, dev->base_addr + TxCtrl);
-+ if (yp->cur_tx - yp->dirty_tx < TX_QUEUE_SIZE)
-+ netif_unpause_tx_queue(dev);
-+
-+ dev->trans_start = jiffies;
-+ yp->stats.tx_errors++;
-+ return;
-+}
-
- /* Initialize the Rx and Tx rings, along with various 'dev' bits. */
--static void
--yellowfin_init_ring(struct device *dev)
-+static void yellowfin_init_ring(struct net_device *dev)
- {
- struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv;
- int i;
-
- yp->tx_full = 0;
- yp->cur_rx = yp->cur_tx = 0;
-- yp->dirty_rx = yp->dirty_tx = 0;
-+ yp->dirty_tx = 0;
-
-- for (i = 0; i < RX_RING_SIZE; i++) {
-- struct sk_buff *skb;
-- int pkt_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);
-+ yp->rx_buf_sz = dev->mtu + 18 + 15;
-+ /* Match other driver's allocation size when possible. */
-+ if (yp->rx_buf_sz < PKT_BUF_SZ)
-+ yp->rx_buf_sz = PKT_BUF_SZ;
-+ yp->rx_head_desc = &yp->rx_ring[0];
-
-- yp->rx_ring[i].request_cnt = pkt_buf_sz;
-- yp->rx_ring[i].cmd = CMD_RX_BUF | INTR_ALWAYS;
-+ for (i = 0; i < RX_RING_SIZE; i++) {
-+ yp->rx_ring[i].dbdma_cmd =
-+ cpu_to_le32(CMD_RX_BUF | INTR_ALWAYS | yp->rx_buf_sz);
-+ yp->rx_ring[i].branch_addr = virt_to_le32desc(&yp->rx_ring[i+1]);
-+ }
-+ /* Mark the last entry as wrapping the ring. */
-+ yp->rx_ring[i-1].branch_addr = virt_to_le32desc(&yp->rx_ring[0]);
-
-- skb = DEV_ALLOC_SKB(pkt_buf_sz);
-- skb_reserve(skb, 2); /* 16 byte align the IP header. */
-+ for (i = 0; i < RX_RING_SIZE; i++) {
-+ struct sk_buff *skb = dev_alloc_skb(yp->rx_buf_sz);
- yp->rx_skbuff[i] = skb;
- if (skb == NULL)
-- break; /* Bad news! */
-+ break;
- skb->dev = dev; /* Mark as being used by this device. */
--#if LINUX_VERSION_CODE > 0x10300
-- yp->rx_ring[i].addr = virt_to_bus(skb->tail);
--#else
-- yp->rx_ring[i].addr = virt_to_bus(skb->data);
--#endif
-- yp->rx_ring[i].branch_addr = virt_to_bus(&yp->rx_ring[i+1]);
-+ skb_reserve(skb, 2); /* 16 byte align the IP header. */
-+ yp->rx_ring[i].addr = virt_to_le32desc(skb->tail);
- }
-- /* Mark the last entry as wrapping the ring. */
-- yp->rx_ring[i-1].cmd = CMD_RX_BUF | INTR_ALWAYS | BRANCH_ALWAYS;
-- yp->rx_ring[i-1].branch_addr = virt_to_bus(&yp->rx_ring[0]);
-+ yp->rx_ring[i-1].dbdma_cmd = cpu_to_le32(CMD_STOP);
-+ yp->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
-
--/*#define NO_TXSTATS*/
-+#define NO_TXSTATS
- #ifdef NO_TXSTATS
- /* In this mode the Tx ring needs only a single descriptor. */
- for (i = 0; i < TX_RING_SIZE; i++) {
- yp->tx_skbuff[i] = 0;
-- yp->tx_ring[i].cmd = CMD_STOP;
-- yp->tx_ring[i].branch_addr = virt_to_bus(&yp->tx_ring[i+1]);
-+ yp->tx_ring[i].dbdma_cmd = cpu_to_le32(CMD_STOP);
-+ yp->tx_ring[i].branch_addr = virt_to_le32desc(&yp->tx_ring[i+1]);
- }
-- yp->tx_ring[--i].cmd = CMD_STOP | BRANCH_ALWAYS; /* Wrap ring */
-- yp->tx_ring[i].branch_addr = virt_to_bus(&yp->tx_ring[0]);
-+ /* Wrap ring */
-+ yp->tx_ring[--i].dbdma_cmd = cpu_to_le32(CMD_STOP | BRANCH_ALWAYS);
-+ yp->tx_ring[i].branch_addr = virt_to_le32desc(&yp->tx_ring[0]);
- #else
- /* Tx ring needs a pair of descriptors, the second for the status. */
- for (i = 0; i < TX_RING_SIZE*2; i++) {
- yp->tx_skbuff[i/2] = 0;
-- yp->tx_ring[i].cmd = CMD_STOP; /* Branch on Tx error. */
-- yp->tx_ring[i].branch_addr = virt_to_bus(&yp->tx_ring[i+1]);
-+ /* Branch on Tx error. */
-+ yp->tx_ring[i].dbdma_cmd = cpu_to_le32(CMD_STOP);
-+ yp->tx_ring[i].branch_addr = virt_to_le32desc(&yp->tx_ring[i+1]);
- i++;
-- yp->tx_ring[i].cmd = CMD_TXSTATUS; /* Interrupt, no wait. */
-- yp->tx_ring[i].request_cnt = sizeof(yp->tx_status[i]);
-- yp->tx_ring[i].addr = virt_to_bus(&yp->tx_status[i/2]);
-- yp->tx_ring[i].branch_addr = virt_to_bus(&yp->tx_ring[i+1]);
-+ if (yp->flags & FullTxStatus) {
-+ yp->tx_ring[i].dbdma_cmd =
-+ cpu_to_le32(CMD_TXSTATUS | sizeof(yp->tx_status[i]));
-+ yp->tx_ring[i].request_cnt = sizeof(yp->tx_status[i]);
-+ yp->tx_ring[i].addr = virt_to_le32desc(&yp->tx_status[i/2]);
-+ } else { /* Symbios chips write only tx_errs word. */
-+ yp->tx_ring[i].dbdma_cmd =
-+ cpu_to_le32(CMD_TXSTATUS | INTR_ALWAYS | 2);
-+ yp->tx_ring[i].request_cnt = 2;
-+ yp->tx_ring[i].addr = virt_to_le32desc(&yp->tx_status[i/2].tx_errs);
-+ }
-+ yp->tx_ring[i].branch_addr = virt_to_le32desc(&yp->tx_ring[i+1]);
- }
- /* Wrap ring */
-- yp->tx_ring[--i].cmd = CMD_TXSTATUS | BRANCH_ALWAYS | INTR_ALWAYS;
-- yp->tx_ring[i].branch_addr = virt_to_bus(&yp->tx_ring[0]);
-+ yp->tx_ring[--i].dbdma_cmd |= cpu_to_le32(BRANCH_ALWAYS | INTR_ALWAYS);
-+ yp->tx_ring[i].branch_addr = virt_to_le32desc(&yp->tx_ring[0]);
- #endif
-+ yp->tx_tail_desc = &yp->tx_status[0];
-+ return;
- }
-
--static int
--yellowfin_start_xmit(struct sk_buff *skb, struct device *dev)
-+static int yellowfin_start_xmit(struct sk_buff *skb, struct net_device *dev)
- {
- struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv;
- unsigned entry;
-
-+#if LINUX_VERSION_CODE < 0x20323
- /* Block a timer-based transmit from overlapping. This could better be
- done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
-- if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
-- if (jiffies - dev->trans_start < TX_TIMEOUT)
-- return 1;
-- yellowfin_tx_timeout(dev);
-+ if (netif_pause_tx_queue(dev) != 0) {
-+ /* This watchdog code is redundant with the media monitor timer. */
-+ if (jiffies - dev->trans_start > TX_TIMEOUT)
-+ yellowfin_tx_timeout(dev);
- return 1;
- }
-+#endif
-
-- /* Caution: the write order is important here, set the base address
-- with the "ownership" bits last. */
-+ /* Note: Ordering is important here, set the field with the
-+ "ownership" bit last, and only then increment cur_tx. */
-
- /* Calculate the next Tx descriptor entry. */
- entry = yp->cur_tx % TX_RING_SIZE;
-
- yp->tx_skbuff[entry] = skb;
-
-+ if (gx_fix) { /* Note: only works for paddable protocols e.g. IP. */
-+ int cacheline_end = (virt_to_bus(skb->data) + skb->len) % 32;
-+ /* Fix GX chipset errata. */
-+ if (cacheline_end > 24 || cacheline_end == 0)
-+ skb->len += 32 - cacheline_end + 1;
-+ }
- #ifdef NO_TXSTATS
-- yp->tx_ring[entry].request_cnt = skb->len;
-- yp->tx_ring[entry].addr = virt_to_bus(skb->data);
-- yp->tx_ring[entry].status = 0;
-+ yp->tx_ring[entry].addr = virt_to_le32desc(skb->data);
-+ yp->tx_ring[entry].result_status = 0;
- if (entry >= TX_RING_SIZE-1) {
-- yp->tx_ring[0].cmd = CMD_STOP; /* New stop command. */
-- yp->tx_ring[TX_RING_SIZE-1].cmd = CMD_TX_PKT | BRANCH_ALWAYS;
-+ /* New stop command. */
-+ yp->tx_ring[0].dbdma_cmd = cpu_to_le32(CMD_STOP);
-+ yp->tx_ring[TX_RING_SIZE-1].dbdma_cmd =
-+ cpu_to_le32(CMD_TX_PKT|BRANCH_ALWAYS | skb->len);
- } else {
-- yp->tx_ring[entry+1].cmd = CMD_STOP; /* New stop command. */
-- yp->tx_ring[entry].cmd = CMD_TX_PKT | BRANCH_IFTRUE;
-+ yp->tx_ring[entry+1].dbdma_cmd = cpu_to_le32(CMD_STOP);
-+ yp->tx_ring[entry].dbdma_cmd =
-+ cpu_to_le32(CMD_TX_PKT | BRANCH_IFTRUE | skb->len);
- }
- yp->cur_tx++;
- #else
- yp->tx_ring[entry<<1].request_cnt = skb->len;
-- yp->tx_ring[entry<<1].addr = virt_to_bus(skb->data);
-+ yp->tx_ring[entry<<1].addr = virt_to_le32desc(skb->data);
- /* The input_last (status-write) command is constant, but we must rewrite
- the subsequent 'stop' command. */
-
- yp->cur_tx++;
- {
- unsigned next_entry = yp->cur_tx % TX_RING_SIZE;
-- yp->tx_ring[next_entry<<1].cmd = CMD_STOP;
-+ yp->tx_ring[next_entry<<1].dbdma_cmd = cpu_to_le32(CMD_STOP);
- }
- /* Final step -- overwrite the old 'stop' command. */
-
-- yp->tx_ring[entry<<1].cmd =
-- (entry % 6) == 0 ? CMD_TX_PKT | INTR_ALWAYS | BRANCH_IFTRUE :
-- CMD_TX_PKT | BRANCH_IFTRUE;
-+ yp->tx_ring[entry<<1].dbdma_cmd =
-+ cpu_to_le32( ((entry % 6) == 0 ? CMD_TX_PKT|INTR_ALWAYS|BRANCH_IFTRUE :
-+ CMD_TX_PKT | BRANCH_IFTRUE) | skb->len);
- #endif
-
-- /* Todo: explicitly flush cache lines here. */
-+ /* Non-x86 Todo: explicitly flush cache lines here. */
-
- /* Wake the potentially-idle transmit channel. */
- outl(0x10001000, dev->base_addr + TxCtrl);
-
-- if (yp->cur_tx - yp->dirty_tx < TX_RING_SIZE - 1)
-- clear_bit(0, (void*)&dev->tbusy); /* Typical path */
-- else
-+ if (yp->cur_tx - yp->dirty_tx >= TX_QUEUE_SIZE) {
-+ netif_stop_tx_queue(dev);
- yp->tx_full = 1;
-+ if (yp->cur_tx - (volatile int)yp->dirty_tx < TX_QUEUE_SIZE) {
-+ netif_unpause_tx_queue(dev);
-+ yp->tx_full = 0;
-+ } else
-+ netif_stop_tx_queue(dev);
-+ } else
-+ netif_unpause_tx_queue(dev); /* Typical path */
- dev->trans_start = jiffies;
-
-- if (yellowfin_debug > 4) {
-- printk("%s: Yellowfin transmit frame #%d queued in slot %d.\n",
-+ if (yp->msg_level & NETIF_MSG_TX_QUEUED) {
-+ printk(KERN_DEBUG "%s: Yellowfin transmit frame #%d queued in slot %d.\n",
- dev->name, yp->cur_tx, entry);
- }
- return 0;
-@@ -784,316 +888,331 @@
-
- /* The interrupt handler does all of the Rx thread work and cleans up
- after the Tx thread. */
--static void yellowfin_interrupt IRQ(int irq, void *dev_instance, struct pt_regs *regs)
-+static void yellowfin_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
- {
--#ifdef SA_SHIRQ /* Use the now-standard shared IRQ implementation. */
-- struct device *dev = (struct device *)dev_instance;
--#else
-- struct device *dev = (struct device *)(irq2dev_map[irq]);
--#endif
--
-- struct yellowfin_private *lp;
-- int ioaddr, boguscnt = max_interrupt_work;
-+ struct net_device *dev = (struct net_device *)dev_instance;
-+ struct yellowfin_private *yp;
-+ long ioaddr;
-+ int boguscnt = max_interrupt_work;
-
-+#ifndef final_version /* Can never occur. */
- if (dev == NULL) {
-- printk ("yellowfin_interrupt(): irq %d for unknown device.\n", irq);
-+ printk (KERN_ERR "yellowfin_interrupt(): irq %d for unknown device.\n", irq);
- return;
- }
-+#endif
-
- ioaddr = dev->base_addr;
-- lp = (struct yellowfin_private *)dev->priv;
-- if (test_and_set_bit(0, (void*)&lp->in_interrupt)) {
-- dev->interrupt = 1;
-+ yp = (struct yellowfin_private *)dev->priv;
-+ if (test_and_set_bit(0, (void*)&yp->in_interrupt)) {
- printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name);
- return;
- }
-
- do {
- u16 intr_status = inw(ioaddr + IntrClear);
-- unsigned dirty_tx = lp->dirty_tx;
-
-- if (yellowfin_debug > 4)
-- printk("%s: Yellowfin interrupt, status %4.4x.\n",
-+ if (yp->msg_level & NETIF_MSG_INTR)
-+ printk(KERN_DEBUG "%s: Yellowfin interrupt, status %4.4x.\n",
- dev->name, intr_status);
-
- if (intr_status == 0)
- break;
-
-- if (intr_status & (IntrRxDone | IntrEarlyRx))
-+ if (intr_status & (IntrRxDone | IntrEarlyRx)) {
- yellowfin_rx(dev);
-+ outl(0x10001000, ioaddr + RxCtrl); /* Wake Rx engine. */
-+ }
-
- #ifdef NO_TXSTATS
-- for (; lp->cur_tx - dirty_tx > 0; dirty_tx++) {
-- int entry = dirty_tx % TX_RING_SIZE;
-- if (lp->tx_ring[entry].status == 0)
-+ for (; yp->cur_tx - yp->dirty_tx > 0; yp->dirty_tx++) {
-+ int entry = yp->dirty_tx % TX_RING_SIZE;
-+ if (yp->tx_ring[entry].result_status == 0)
- break;
-+ yp->stats.tx_packets++;
-+#if LINUX_VERSION_CODE > 0x20127
-+ yp->stats.tx_bytes += yp->tx_skbuff[entry]->len;
-+#endif
- /* Free the original skb. */
-- dev_kfree_skb(lp->tx_skbuff[entry], FREE_WRITE);
-- lp->tx_skbuff[entry] = 0;
-- lp->stats.tx_packets++;
-+ dev_free_skb_irq(yp->tx_skbuff[entry]);
-+ yp->tx_skbuff[entry] = 0;
- }
-- if (lp->tx_full && dev->tbusy
-- && lp->cur_tx - dirty_tx < TX_RING_SIZE - 4) {
-+ if (yp->tx_full
-+ && yp->cur_tx - yp->dirty_tx < TX_QUEUE_SIZE - 4) {
- /* The ring is no longer full, clear tbusy. */
-- lp->tx_full = 0;
-- clear_bit(0, (void*)&dev->tbusy);
-- mark_bh(NET_BH);
-+ yp->tx_full = 0;
-+ netif_resume_tx_queue(dev);
- }
-- lp->dirty_tx = dirty_tx;
- #else
- if (intr_status & IntrTxDone
-- || lp->tx_status[dirty_tx % TX_RING_SIZE].tx_errs) {
-+ || yp->tx_tail_desc->tx_errs) {
-+ unsigned dirty_tx = yp->dirty_tx;
-
-- for (dirty_tx = lp->dirty_tx; lp->cur_tx - dirty_tx > 0;
-+ for (dirty_tx = yp->dirty_tx; yp->cur_tx - dirty_tx > 0;
- dirty_tx++) {
- /* Todo: optimize this. */
- int entry = dirty_tx % TX_RING_SIZE;
-- u16 tx_errs = lp->tx_status[entry].tx_errs;
-+ u16 tx_errs = yp->tx_status[entry].tx_errs;
-
-+#ifndef final_version
-+ if (yp->msg_level & NETIF_MSG_INTR)
-+ printk(KERN_DEBUG "%s: Tx queue %d check, Tx status "
-+ "%4.4x %4.4x %4.4x %4.4x.\n",
-+ dev->name, entry,
-+ yp->tx_status[entry].tx_cnt,
-+ yp->tx_status[entry].tx_errs,
-+ yp->tx_status[entry].total_tx_cnt,
-+ yp->tx_status[entry].paused);
-+#endif
- if (tx_errs == 0)
- break; /* It still hasn't been Txed */
-- if (tx_errs & 0xF8100000) {
-+ if (tx_errs & 0xF810) {
- /* There was an major error, log it. */
- #ifndef final_version
-- if (yellowfin_debug > 1)
-- printk("%s: Transmit error, Tx status %4.4x.\n",
-+ if (yp->msg_level & NETIF_MSG_TX_ERR)
-+ printk(KERN_DEBUG "%s: Transmit error, Tx status %4.4x.\n",
- dev->name, tx_errs);
- #endif
-- lp->stats.tx_errors++;
-- if (tx_errs & 0xF800) lp->stats.tx_aborted_errors++;
-- if (tx_errs & 0x0800) lp->stats.tx_carrier_errors++;
-- if (tx_errs & 0x2000) lp->stats.tx_window_errors++;
-- if (tx_errs & 0x8000) lp->stats.tx_fifo_errors++;
-+ yp->stats.tx_errors++;
-+ if (tx_errs & 0xF800) yp->stats.tx_aborted_errors++;
-+ if (tx_errs & 0x0800) yp->stats.tx_carrier_errors++;
-+ if (tx_errs & 0x2000) yp->stats.tx_window_errors++;
-+ if (tx_errs & 0x8000) yp->stats.tx_fifo_errors++;
- #ifdef ETHER_STATS
-- if (tx_errs & 0x1000) lp->stats.collisions16++;
-+ if (tx_errs & 0x1000) yp->stats.collisions16++;
- #endif
- } else {
-+#ifndef final_version
-+ if (yp->msg_level & NETIF_MSG_TX_DONE)
-+ printk(KERN_DEBUG "%s: Normal transmit, Tx status %4.4x.\n",
-+ dev->name, tx_errs);
-+#endif
- #ifdef ETHER_STATS
-- if (status & 0x0400) lp->stats.tx_deferred++;
-+ if (tx_errs & 0x0400) yp->stats.tx_deferred++;
-+#endif
-+#if LINUX_VERSION_CODE > 0x20127
-+ yp->stats.tx_bytes += yp->tx_skbuff[entry]->len;
- #endif
-- lp->stats.collisions += tx_errs & 15;
-- lp->stats.tx_packets++;
-+ yp->stats.collisions += tx_errs & 15;
-+ yp->stats.tx_packets++;
- }
--
- /* Free the original skb. */
-- dev_kfree_skb(lp->tx_skbuff[entry], FREE_WRITE);
-- lp->tx_skbuff[entry] = 0;
-+ dev_free_skb_irq(yp->tx_skbuff[entry]);
-+ yp->tx_skbuff[entry] = 0;
- /* Mark status as empty. */
-- lp->tx_status[entry].tx_errs = 0;
-+ yp->tx_status[entry].tx_errs = 0;
- }
-
- #ifndef final_version
-- if (lp->cur_tx - dirty_tx > TX_RING_SIZE) {
-- printk("%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
-- dev->name, dirty_tx, lp->cur_tx, lp->tx_full);
-+ if (yp->cur_tx - dirty_tx > TX_RING_SIZE) {
-+ printk(KERN_ERR "%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
-+ dev->name, dirty_tx, yp->cur_tx, yp->tx_full);
- dirty_tx += TX_RING_SIZE;
- }
- #endif
-
-- if (lp->tx_full && dev->tbusy
-- && lp->cur_tx - dirty_tx < TX_RING_SIZE - 2) {
-+ if (yp->tx_full
-+ && yp->cur_tx - dirty_tx < TX_QUEUE_SIZE - 2) {
- /* The ring is no longer full, clear tbusy. */
-- lp->tx_full = 0;
-- clear_bit(0, (void*)&dev->tbusy);
-- mark_bh(NET_BH);
-+ yp->tx_full = 0;
-+ netif_resume_tx_queue(dev);
- }
-
-- lp->dirty_tx = dirty_tx;
-+ yp->dirty_tx = dirty_tx;
-+ yp->tx_tail_desc = &yp->tx_status[dirty_tx % TX_RING_SIZE];
- }
- #endif
-
-- /* Log errors and other events. */
-- if (intr_status & 0x2ee) { /* Abnormal error summary. */
-- printk("%s: Something Wicked happened! %4.4x.\n",
-- dev->name, intr_status);
-- /* Hmmmmm, it's not clear what to do here. */
-- if (intr_status & (IntrTxPCIErr | IntrTxPCIFault))
-- lp->stats.tx_errors++;
-- if (intr_status & (IntrRxPCIErr | IntrRxPCIFault))
-- lp->stats.rx_errors++;
-- }
-+ /* Log errors and other uncommon events. */
-+ if (intr_status & 0x2ee) /* Abnormal error summary. */
-+ yellowfin_error(dev, intr_status);
-+
- if (--boguscnt < 0) {
-- printk("%s: Too much work at interrupt, status=0x%4.4x.\n",
-+ printk(KERN_WARNING "%s: Too much work at interrupt, "
-+ "status=0x%4.4x.\n",
- dev->name, intr_status);
- break;
- }
- } while (1);
-
-- if (yellowfin_debug > 3)
-- printk("%s: exiting interrupt, status=%#4.4x.\n",
-+ if (yp->msg_level & NETIF_MSG_INTR)
-+ printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
- dev->name, inw(ioaddr + IntrStatus));
-
-- /* Code that should never be run! Perhaps remove after testing.. */
-- {
-- static int stopit = 10;
-- if (dev->start == 0 && --stopit < 0) {
-- printk("%s: Emergency stop, looping startup interrupt.\n",
-- dev->name);
--#ifdef SA_SHIRQ
-- free_irq(irq, dev);
--#else
-- free_irq(irq);
--#endif
-- }
-- }
--
-- dev->interrupt = 0;
-- clear_bit(0, (void*)&lp->in_interrupt);
-+ clear_bit(0, (void*)&yp->in_interrupt);
- return;
- }
-
- /* This routine is logically part of the interrupt handler, but separated
- for clarity and better register allocation. */
--static int
--yellowfin_rx(struct device *dev)
-+static int yellowfin_rx(struct net_device *dev)
- {
-- struct yellowfin_private *lp = (struct yellowfin_private *)dev->priv;
- struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv;
-- int entry = lp->cur_rx % RX_RING_SIZE;
-- int boguscnt = 20;
-+ int entry = yp->cur_rx % RX_RING_SIZE;
-+ int boguscnt = yp->dirty_rx + RX_RING_SIZE - yp->cur_rx;
-
-- if (yellowfin_debug > 4) {
-- printk(" In yellowfin_rx(), entry %d status %4.4x.\n", entry,
-- yp->rx_ring[entry].status);
-- printk(" #%d desc. %4.4x %4.4x %8.8x %4.4x %4.4x.\n",
-- entry, yp->rx_ring[entry].cmd,
-- yp->rx_ring[entry].request_cnt, yp->rx_ring[entry].addr,
-- yp->rx_ring[entry].result_cnt, yp->rx_ring[entry].status);
-+ if (yp->msg_level & NETIF_MSG_RX_STATUS) {
-+ printk(KERN_DEBUG " In yellowfin_rx(), entry %d status %8.8x.\n",
-+ entry, yp->rx_ring[entry].result_status);
-+ printk(KERN_DEBUG " #%d desc. %8.8x %8.8x %8.8x.\n",
-+ entry, yp->rx_ring[entry].dbdma_cmd, yp->rx_ring[entry].addr,
-+ yp->rx_ring[entry].result_status);
- }
-
--
- /* If EOP is set on the next entry, it's a new packet. Send it up. */
-- while (yp->rx_ring[entry].status) {
-- /* Todo: optimize this mess. */
-- u16 desc_status = yp->rx_ring[entry].status;
-- struct yellowfin_desc *desc = &lp->rx_ring[entry];
-- int frm_size = desc->request_cnt - desc->result_cnt;
-- u8 *buf_addr = bus_to_virt(lp->rx_ring[entry].addr);
-- s16 frame_status = *(s16*)&(buf_addr[frm_size - 2]);
--
-- if (yellowfin_debug > 4)
-- printk(" yellowfin_rx() status was %4.4x.\n", frame_status);
-+ while (yp->rx_head_desc->result_status) {
-+ struct yellowfin_desc *desc = yp->rx_head_desc;
-+ u16 desc_status = le32_to_cpu(desc->result_status) >> 16;
-+ int data_size =
-+ (le32_to_cpu(desc->dbdma_cmd) - le32_to_cpu(desc->result_status))
-+ & 0xffff;
-+ u8 *buf_addr = le32desc_to_virt(desc->addr);
-+ s16 frame_status = get_unaligned((s16*)&(buf_addr[data_size - 2]));
-+
-+ if (yp->msg_level & NETIF_MSG_RX_STATUS)
-+ printk(KERN_DEBUG " yellowfin_rx() status was %4.4x.\n",
-+ frame_status);
- if (--boguscnt < 0)
- break;
- if ( ! (desc_status & RX_EOP)) {
-- printk("%s: Oversized Ethernet frame spanned multiple buffers,"
-+ printk(KERN_WARNING "%s: Oversized Ethernet frame spanned multiple buffers,"
- " status %4.4x!\n", dev->name, desc_status);
-- lp->stats.rx_length_errors++;
-- } else if (frame_status & 0x0038) {
-+ yp->stats.rx_length_errors++;
-+ } else if ((yp->drv_flags & IsGigabit) && (frame_status & 0x0038)) {
- /* There was a error. */
-- if (yellowfin_debug > 3)
-- printk(" yellowfin_rx() Rx error was %4.4x.\n", frame_status);
-- lp->stats.rx_errors++;
-- if (frame_status & 0x0060) lp->stats.rx_length_errors++;
-- if (frame_status & 0x0008) lp->stats.rx_frame_errors++;
-- if (frame_status & 0x0010) lp->stats.rx_crc_errors++;
-- if (frame_status < 0) lp->stats.rx_dropped++;
-+ if (yp->msg_level & NETIF_MSG_RX_ERR)
-+ printk(KERN_DEBUG " yellowfin_rx() Rx error was %4.4x.\n",
-+ frame_status);
-+ yp->stats.rx_errors++;
-+ if (frame_status & 0x0060) yp->stats.rx_length_errors++;
-+ if (frame_status & 0x0008) yp->stats.rx_frame_errors++;
-+ if (frame_status & 0x0010) yp->stats.rx_crc_errors++;
-+ if (frame_status < 0) yp->stats.rx_dropped++;
-+ } else if ( !(yp->drv_flags & IsGigabit) &&
-+ ((buf_addr[data_size-1] & 0x85) || buf_addr[data_size-2] & 0xC0)) {
-+ u8 status1 = buf_addr[data_size-2];
-+ u8 status2 = buf_addr[data_size-1];
-+ yp->stats.rx_errors++;
-+ if (status1 & 0xC0) yp->stats.rx_length_errors++;
-+ if (status2 & 0x03) yp->stats.rx_frame_errors++;
-+ if (status2 & 0x04) yp->stats.rx_crc_errors++;
-+ if (status2 & 0x80) yp->stats.rx_dropped++;
- #ifdef YF_PROTOTYPE /* Support for prototype hardware errata. */
-- } else if (memcmp(bus_to_virt(lp->rx_ring[entry].addr),
-+ } else if ((yp->flags & HasMACAddrBug) &&
-+ memcmp(le32desc_to_virt(yp->rx_ring[entry].addr),
- dev->dev_addr, 6) != 0
-- && memcmp(bus_to_virt(lp->rx_ring[entry].addr),
-+ && memcmp(le32desc_to_virt(yp->rx_ring[entry].addr),
- "\377\377\377\377\377\377", 6) != 0) {
-- printk("%s: Bad frame to %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n",
-- dev->name,
-- ((char *)bus_to_virt(lp->rx_ring[entry].addr))[0],
-- ((char *)bus_to_virt(lp->rx_ring[entry].addr))[1],
-- ((char *)bus_to_virt(lp->rx_ring[entry].addr))[2],
-- ((char *)bus_to_virt(lp->rx_ring[entry].addr))[3],
-- ((char *)bus_to_virt(lp->rx_ring[entry].addr))[4],
-- ((char *)bus_to_virt(lp->rx_ring[entry].addr))[5]);
-- bogus_rx++;
-+ if (bogus_rx++ == 0)
-+ printk(KERN_WARNING "%s: Bad frame to %2.2x:%2.2x:%2.2x:%2.2x:"
-+ "%2.2x:%2.2x.\n",
-+ dev->name, buf_addr[0], buf_addr[1], buf_addr[2],
-+ buf_addr[3], buf_addr[4], buf_addr[5]);
- #endif
- } else {
-- u8 bogus_cnt = buf_addr[frm_size - 8];
-- int pkt_len = frm_size - 8 - bogus_cnt;
- struct sk_buff *skb;
-- int rx_in_place = 0;
-+ int pkt_len = data_size -
-+ (yp->chip_id ? 7 : 8 + buf_addr[data_size - 8]);
-+ /* To verify: Yellowfin Length should omit the CRC! */
-
-- /* Check if the packet is long enough to just accept without
-- copying to a properly sized skbuff. */
-- if (pkt_len > rx_copybreak) {
-- struct sk_buff *newskb;
-- char *temp;
--
-- /* Get a fresh skbuff to replace the filled one. */
-- newskb = DEV_ALLOC_SKB(dev->mtu <= 1500 ? PKT_BUF_SZ
-- : dev->mtu + 32);
-- if (newskb == NULL) {
-- skb = 0; /* No memory, drop the packet. */
-- goto memory_squeeze;
-- }
-- /* Pass up the skb already on the Rx ring. */
-- skb = lp->rx_skbuff[entry];
-- temp = skb_put(skb, pkt_len);
-- if (bus_to_virt(lp->rx_ring[entry].addr) != temp)
-- printk("%s: Warning -- the skbuff addresses do not match"
-- " in yellowfin_rx: %p vs. %p / %p.\n", dev->name,
-- bus_to_virt(lp->rx_ring[entry].addr),
-+#ifndef final_version
-+ if (yp->msg_level & NETIF_MSG_RX_STATUS)
-+ printk(KERN_DEBUG " yellowfin_rx() normal Rx pkt length %d"
-+ " of %d, bogus_cnt %d.\n",
-+ pkt_len, data_size, boguscnt);
-+#endif
-+ /* Check if the packet is long enough to just pass up the skbuff
-+ without copying to a properly sized skbuff. */
-+ if (pkt_len > yp->rx_copybreak) {
-+ char *temp = skb_put(skb = yp->rx_skbuff[entry], pkt_len);
-+ yp->rx_skbuff[entry] = NULL;
-+#ifndef final_version /* Remove after testing. */
-+ if (le32desc_to_virt(yp->rx_ring[entry].addr) != temp)
-+ printk(KERN_ERR "%s: Internal fault: The skbuff addresses "
-+ "do not match in yellowfin_rx: %p vs. %p / %p.\n",
-+ dev->name,
-+ le32desc_to_virt(yp->rx_ring[entry].addr),
- skb->head, temp);
-- rx_in_place = 1;
-- lp->rx_skbuff[entry] = newskb;
-- newskb->dev = dev;
-- skb_reserve(newskb, 2); /* 16 byte align IP header */
-- lp->rx_ring[entry].addr = virt_to_bus(newskb->tail);
-- } else
-- skb = DEV_ALLOC_SKB(pkt_len + 2);
-- memory_squeeze:
-- if (skb == NULL) {
-- printk("%s: Memory squeeze, deferring packet.\n", dev->name);
-- /* todo: Check that at least two ring entries are free.
-- If not, free one and mark stats->rx_dropped++. */
-- break;
-- }
-- skb->dev = dev;
-- if (! rx_in_place) {
-- skb_reserve(skb, 2); /* 16 byte align the data fields */
-- memcpy(skb_put(skb, pkt_len),
-- bus_to_virt(lp->rx_ring[entry].addr), pkt_len);
-- }
--#if LINUX_VERSION_CODE > 0x10300
-- skb->protocol = eth_type_trans(skb, dev);
-+#endif
-+ } else {
-+ skb = dev_alloc_skb(pkt_len + 2);
-+ if (skb == NULL)
-+ break;
-+ skb->dev = dev;
-+ skb_reserve(skb, 2); /* 16 byte align the IP header */
-+#if HAS_IP_COPYSUM
-+ eth_copy_and_sum(skb, yp->rx_skbuff[entry]->tail, pkt_len, 0);
-+ skb_put(skb, pkt_len);
- #else
-- skb->len = pkt_len;
-+ memcpy(skb_put(skb, pkt_len), yp->rx_skbuff[entry]->tail,
-+ pkt_len);
- #endif
-+ }
-+ skb->protocol = eth_type_trans(skb, dev);
- netif_rx(skb);
-- lp->stats.rx_packets++;
-+ dev->last_rx = jiffies;
-+ yp->stats.rx_packets++;
-+#if LINUX_VERSION_CODE > 0x20127
-+ yp->stats.rx_bytes += pkt_len;
-+#endif
- }
-+ entry = (++yp->cur_rx) % RX_RING_SIZE;
-+ yp->rx_head_desc = &yp->rx_ring[entry];
-+ }
-
-- /* Mark this entry as being the end-of-list, and the prior entry
-- as now valid. */
-- lp->rx_ring[entry].cmd = CMD_STOP;
-- yp->rx_ring[entry].status = 0;
-- {
-- int prev_entry = entry - 1;
-- if (prev_entry < 0)
-- lp->rx_ring[RX_RING_SIZE - 1].cmd =
-- CMD_RX_BUF | INTR_ALWAYS | BRANCH_ALWAYS;
-- else
-- lp->rx_ring[prev_entry].cmd = CMD_RX_BUF | INTR_ALWAYS;
-+ /* Refill the Rx ring buffers. */
-+ for (; yp->cur_rx - yp->dirty_rx > 0; yp->dirty_rx++) {
-+ entry = yp->dirty_rx % RX_RING_SIZE;
-+ if (yp->rx_skbuff[entry] == NULL) {
-+ struct sk_buff *skb = dev_alloc_skb(yp->rx_buf_sz);
-+ yp->rx_skbuff[entry] = skb;
-+ if (skb == NULL)
-+ break; /* Better luck next round. */
-+ skb->dev = dev; /* Mark as being used by this device. */
-+ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
-+ yp->rx_ring[entry].addr = virt_to_le32desc(skb->tail);
- }
-- entry = (++lp->cur_rx) % RX_RING_SIZE;
-+ yp->rx_ring[entry].dbdma_cmd = cpu_to_le32(CMD_STOP);
-+ yp->rx_ring[entry].result_status = 0; /* Clear complete bit. */
-+ if (entry != 0)
-+ yp->rx_ring[entry - 1].dbdma_cmd =
-+ cpu_to_le32(CMD_RX_BUF | INTR_ALWAYS | yp->rx_buf_sz);
-+ else
-+ yp->rx_ring[RX_RING_SIZE - 1].dbdma_cmd =
-+ cpu_to_le32(CMD_RX_BUF | INTR_ALWAYS | BRANCH_ALWAYS
-+ | yp->rx_buf_sz);
- }
-- /* todo: restart Rx engine if stopped. For now we just make the Rx ring
-- large enough to avoid this. */
-
- return 0;
- }
-
--static int
--yellowfin_close(struct device *dev)
-+static void yellowfin_error(struct net_device *dev, int intr_status)
-+{
-+ struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv;
-+
-+ printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n",
-+ dev->name, intr_status);
-+ /* Hmmmmm, it's not clear what to do here. */
-+ if (intr_status & (IntrTxPCIErr | IntrTxPCIFault))
-+ yp->stats.tx_errors++;
-+ if (intr_status & (IntrRxPCIErr | IntrRxPCIFault))
-+ yp->stats.rx_errors++;
-+}
-+
-+static int yellowfin_close(struct net_device *dev)
- {
-- int ioaddr = dev->base_addr;
-+ long ioaddr = dev->base_addr;
- struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv;
- int i;
-
-- dev->start = 0;
-- dev->tbusy = 1;
-+ netif_stop_tx_queue(dev);
-
-- if (yellowfin_debug > 1) {
-- printk("%s: Shutting down ethercard, status was Tx %4.4x Rx %4.4x Int %2.2x.\n",
-+ if (yp->msg_level & NETIF_MSG_IFDOWN) {
-+ printk(KERN_DEBUG "%s: Shutting down ethercard, status was Tx %4.4x "
-+ "Rx %4.4x Int %2.2x.\n",
- dev->name, inw(ioaddr + TxStatus),
-- inw(ioaddr + RxStatus), inl(ioaddr + IntrStatus));
-- printk("%s: Queue pointers were Tx %d / %d, Rx %d / %d.\n",
-+ inw(ioaddr + RxStatus), inw(ioaddr + IntrStatus));
-+ printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d, Rx %d / %d.\n",
- dev->name, yp->cur_tx, yp->dirty_tx, yp->cur_rx, yp->dirty_rx);
- }
-
-@@ -1106,34 +1225,34 @@
-
- del_timer(&yp->timer);
-
--#ifdef __i386__
-- if (yellowfin_debug > 2) {
-- printk("\n Tx ring at %8.8x:\n", (int)virt_to_bus(yp->tx_ring));
-+#if defined(__i386__)
-+ if (yp->msg_level & NETIF_MSG_IFDOWN) {
-+ printk("\n"KERN_DEBUG" Tx ring at %8.8x:\n",
-+ (int)virt_to_bus(yp->tx_ring));
- for (i = 0; i < TX_RING_SIZE*2; i++)
-- printk(" %c #%d desc. %4.4x %4.4x %8.8x %8.8x %4.4x %4.4x.\n",
-+ printk(" %c #%d desc. %8.8x %8.8x %8.8x %8.8x.\n",
- inl(ioaddr + TxPtr) == (long)&yp->tx_ring[i] ? '>' : ' ',
-- i, yp->tx_ring[i].cmd,
-- yp->tx_ring[i].request_cnt, yp->tx_ring[i].addr,
-- yp->tx_ring[i].branch_addr,
-- yp->tx_ring[i].result_cnt, yp->tx_ring[i].status);
-- printk(" Tx status %p:\n", yp->tx_status);
-+ i, yp->tx_ring[i].dbdma_cmd, yp->tx_ring[i].addr,
-+ yp->tx_ring[i].branch_addr, yp->tx_ring[i].result_status);
-+ printk(KERN_DEBUG " Tx status %p:\n", yp->tx_status);
- for (i = 0; i < TX_RING_SIZE; i++)
-- printk(" #%d status %4.4x %4.4x %4.4x %4.4x.\n",
-+ printk(KERN_DEBUG " #%d status %4.4x %4.4x %4.4x %4.4x.\n",
- i, yp->tx_status[i].tx_cnt, yp->tx_status[i].tx_errs,
- yp->tx_status[i].total_tx_cnt, yp->tx_status[i].paused);
-
-- printk("\n Rx ring %8.8x:\n", (int)virt_to_bus(yp->rx_ring));
-+ printk("\n"KERN_DEBUG " Rx ring %8.8x:\n",
-+ (int)virt_to_bus(yp->rx_ring));
- for (i = 0; i < RX_RING_SIZE; i++) {
-- printk(" %c #%d desc. %4.4x %4.4x %8.8x %4.4x %4.4x\n",
-+ printk(KERN_DEBUG " %c #%d desc. %8.8x %8.8x %8.8x\n",
- inl(ioaddr + RxPtr) == (long)&yp->rx_ring[i] ? '>' : ' ',
-- i, yp->rx_ring[i].cmd,
-- yp->rx_ring[i].request_cnt, yp->rx_ring[i].addr,
-- yp->rx_ring[i].result_cnt, yp->rx_ring[i].status);
-- if (yellowfin_debug > 5) {
-- if (*(u8*)yp->rx_ring[i].addr != 0x69) {
-+ i, yp->rx_ring[i].dbdma_cmd, yp->rx_ring[i].addr,
-+ yp->rx_ring[i].result_status);
-+ if (yp->msg_level & NETIF_MSG_PKTDATA) {
-+ if (get_unaligned((u8*)yp->rx_ring[i].addr) != 0x69) {
- int j;
- for (j = 0; j < 0x50; j++)
-- printk(" %4.4x", ((u16*)yp->rx_ring[i].addr)[j]);
-+ printk(" %4.4x",
-+ get_unaligned(((u16*)yp->rx_ring[i].addr) + j));
- printk("\n");
- }
- }
-@@ -1141,34 +1260,29 @@
- }
- #endif /* __i386__ debugging only */
-
--#ifdef SA_SHIRQ
- free_irq(dev->irq, dev);
--#else
-- free_irq(dev->irq);
-- irq2dev_map[dev->irq] = 0;
--#endif
-
- /* Free all the skbuffs in the Rx queue. */
- for (i = 0; i < RX_RING_SIZE; i++) {
-- yp->rx_ring[i].cmd = CMD_STOP;
-+ yp->rx_ring[i].dbdma_cmd = cpu_to_le32(CMD_STOP);
- yp->rx_ring[i].addr = 0xBADF00D0; /* An invalid address. */
- if (yp->rx_skbuff[i]) {
- #if LINUX_VERSION_CODE < 0x20100
- yp->rx_skbuff[i]->free = 1;
- #endif
-- dev_kfree_skb(yp->rx_skbuff[i], FREE_WRITE);
-+ dev_free_skb(yp->rx_skbuff[i]);
- }
- yp->rx_skbuff[i] = 0;
- }
- for (i = 0; i < TX_RING_SIZE; i++) {
- if (yp->tx_skbuff[i])
-- dev_kfree_skb(yp->tx_skbuff[i], FREE_WRITE);
-+ dev_free_skb(yp->tx_skbuff[i]);
- yp->tx_skbuff[i] = 0;
- }
-
- #ifdef YF_PROTOTYPE /* Support for prototype hardware errata. */
-- if (yellowfin_debug > 0) {
-- printk("%s: Received %d frames that we should not have.\n",
-+ if (yp->msg_level & NETIF_MSG_IFDOWN) {
-+ printk(KERN_DEBUG "%s: Received %d frames that we should not have.\n",
- dev->name, bogus_rx);
- }
- #endif
-@@ -1177,8 +1291,7 @@
- return 0;
- }
-
--static struct enet_statistics *
--yellowfin_get_stats(struct device *dev)
-+static struct net_device_stats *yellowfin_get_stats(struct net_device *dev)
- {
- struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv;
- return &yp->stats;
-@@ -1190,6 +1303,7 @@
- N.B. Do not use for bulk data, use a table-based routine instead.
- This is common code and should be moved to net/core/crc.c */
- static unsigned const ethernet_polynomial_le = 0xedb88320U;
-+
- static inline unsigned ether_crc_le(int length, unsigned char *data)
- {
- unsigned int crc = 0xffffffff; /* Initial value. */
-@@ -1208,82 +1322,147 @@
- }
-
-
--#ifdef NEW_MULTICAST
--static void set_rx_mode(struct device *dev)
--#else
--static void set_rx_mode(struct device *dev, int num_addrs, void *addrs);
--#endif
-+static void set_rx_mode(struct net_device *dev)
- {
-- int ioaddr = dev->base_addr;
-- u16 cfg_value = inw(ioaddr + Cnfg);
-+ struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv;
-+ u16 hash_table[4] = {0, 0, 0, 0};
-+ int mc_change = 0;
-+ int new_rx_mode, i;
-
-- /* Stop the Rx process to change any value. */
-- outw(cfg_value & ~0x1000, ioaddr + Cnfg);
- if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
- /* Unconditionally log net taps. */
-- printk("%s: Promiscuous mode enabled.\n", dev->name);
-- outw(0x000F, ioaddr + AddrMode);
-- } else if ((dev->mc_count > 64) || (dev->flags & IFF_ALLMULTI)) {
-+ printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);
-+ new_rx_mode = 0x000F;
-+ } else if (dev->mc_count > yp->multicast_filter_limit
-+ || (dev->flags & IFF_ALLMULTI)) {
- /* Too many to filter well, or accept all multicasts. */
-- outw(0x000B, ioaddr + AddrMode);
-+ new_rx_mode = 0x000B;
- } else if (dev->mc_count > 0) { /* Must use the multicast hash table. */
- struct dev_mc_list *mclist;
-- u16 hash_table[4];
-- int i;
-- memset(hash_table, 0, sizeof(hash_table));
-+
- for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
- i++, mclist = mclist->next) {
- /* Due to a bug in the early chip versions, multiple filter
- slots must be set for each address. */
-- set_bit((ether_crc_le(3, mclist->dmi_addr) >> 3) & 0x3f,
-- hash_table);
-- set_bit((ether_crc_le(4, mclist->dmi_addr) >> 3) & 0x3f,
-- hash_table);
-- set_bit((ether_crc_le(5, mclist->dmi_addr) >> 3) & 0x3f,
-- hash_table);
-+ if (yp->drv_flags & HasMulticastBug) {
-+ set_bit((ether_crc_le(3, mclist->dmi_addr) >> 3) & 0x3f,
-+ hash_table);
-+ set_bit((ether_crc_le(4, mclist->dmi_addr) >> 3) & 0x3f,
-+ hash_table);
-+ set_bit((ether_crc_le(5, mclist->dmi_addr) >> 3) & 0x3f,
-+ hash_table);
-+ }
- set_bit((ether_crc_le(6, mclist->dmi_addr) >> 3) & 0x3f,
- hash_table);
- }
-+ if (memcmp(hash_table, yp->mc_filter, sizeof hash_table) != 0)
-+ mc_change = 1;
-+ new_rx_mode = 0x0003;
-+ } else { /* Normal, unicast/broadcast-only mode. */
-+ new_rx_mode = 0x0001;
-+ }
-+
-+ /* Stop the Rx process to change any value. */
-+ if (yp->rx_mode != new_rx_mode || mc_change) {
-+ long ioaddr = dev->base_addr;
-+ u16 cfg_value = inw(ioaddr + Cnfg);
-+
-+ outw(cfg_value & ~0x1000, ioaddr + Cnfg);
-+
-+ yp->rx_mode = new_rx_mode;
-+ outw(new_rx_mode, ioaddr + AddrMode);
-+ memcpy(yp->mc_filter, hash_table, sizeof hash_table);
- /* Copy the hash table to the chip. */
- for (i = 0; i < 4; i++)
- outw(hash_table[i], ioaddr + HashTbl + i*2);
-- outw(0x0003, ioaddr + AddrMode);
-- } else { /* Normal, unicast/broadcast-only mode. */
-- outw(0x0001, ioaddr + AddrMode);
-+
-+ /* Restart the Rx process. */
-+ outw(cfg_value | 0x1000, ioaddr + Cnfg);
- }
-- /* Restart the Rx process. */
-- outw(cfg_value | 0x1000, ioaddr + Cnfg);
- }
--
--#ifdef MODULE
-
--/* An additional parameter that may be passed in... */
--static int debug = -1;
--
--int
--init_module(void)
-+static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
- {
-- int cards_found;
--
-- if (debug >= 0)
-- yellowfin_debug = debug;
--
-- root_yellowfin_dev = NULL;
-- cards_found = yellowfin_probe(0);
-+ struct yellowfin_private *np = (void *)dev->priv;
-+ long ioaddr = dev->base_addr;
-+ u16 *data = (u16 *)&rq->ifr_data;
-+ u32 *data32 = (void *)&rq->ifr_data;
-+
-+ switch(cmd) {
-+ case 0x8947: case 0x89F0:
-+ /* SIOCGMIIPHY: Get the address of the PHY in use. */
-+ data[0] = np->phys[0] & 0x1f;
-+ /* Fall Through */
-+ case 0x8948: case 0x89F1:
-+ /* SIOCGMIIREG: Read the specified MII register. */
-+ data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f);
-+ return 0;
-+ case 0x8949: case 0x89F2:
-+ /* SIOCSMIIREG: Write the specified MII register */
-+ if (!capable(CAP_NET_ADMIN))
-+ return -EPERM;
-+ if (data[0] == np->phys[0]) {
-+ u16 value = data[2];
-+ switch (data[1]) {
-+ case 0:
-+ /* Check for autonegotiation on or reset. */
-+ np->medialock = (value & 0x9000) ? 0 : 1;
-+ if (np->medialock)
-+ np->full_duplex = (value & 0x0100) ? 1 : 0;
-+ break;
-+ case 4: np->advertising = value; break;
-+ }
-+ /* Perhaps check_duplex(dev), depending on chip semantics. */
-+ }
-+ mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]);
-+ return 0;
-+ case SIOCGPARAMS:
-+ data32[0] = np->msg_level;
-+ data32[1] = np->multicast_filter_limit;
-+ data32[2] = np->max_interrupt_work;
-+ data32[3] = np->rx_copybreak;
-+ return 0;
-+ case SIOCSPARAMS:
-+ if (!capable(CAP_NET_ADMIN))
-+ return -EPERM;
-+ np->msg_level = data32[0];
-+ np->multicast_filter_limit = data32[1];
-+ np->max_interrupt_work = data32[2];
-+ np->rx_copybreak = data32[3];
-+ return 0;
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+}
-
-- return cards_found ? 0 : -ENODEV;
-+
-+#ifdef MODULE
-+int init_module(void)
-+{
-+ /* Emit version even if no cards detected. */
-+ printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2);
-+ return pci_drv_register(&yellowfin_drv_id, NULL);
- }
-
--void
--cleanup_module(void)
-+void cleanup_module(void)
- {
-- struct device *next_dev;
-+ struct net_device *next_dev;
-+
-+ pci_drv_unregister(&yellowfin_drv_id);
-
- /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
- while (root_yellowfin_dev) {
-- next_dev = ((struct yellowfin_private *)root_yellowfin_dev->priv)->next_module;
-+ struct yellowfin_private *np = (void *)(root_yellowfin_dev->priv);
- unregister_netdev(root_yellowfin_dev);
-- release_region(root_yellowfin_dev->base_addr, YELLOWFIN_TOTAL_SIZE);
-+#ifdef USE_IO_OPS
-+ release_region(root_yellowfin_dev->base_addr,
-+ pci_id_tbl[np->chip_id].io_size);
-+#else
-+ iounmap((char *)root_yellowfin_dev->base_addr);
-+#endif
-+ next_dev = np->next_module;
-+ if (np->priv_addr)
-+ kfree(np->priv_addr);
- kfree(root_yellowfin_dev);
- root_yellowfin_dev = next_dev;
- }
-@@ -1293,8 +1472,9 @@
-
- /*
- * Local variables:
-- * compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c yellowfin.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
-- * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c yellowfin.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
-+ * compile-command: "make KERNVER=`uname -r` yellowfin.o"
-+ * compile-cmd: "gcc -DMODULE -Wall -Wstrict-prototypes -O6 -c yellowfin.c"
-+ * simple-compile-command: "gcc -DMODULE -O6 -c yellowfin.c"
- * c-indent-level: 4
- * c-basic-offset: 4
- * tab-width: 4
-diff -Naur linux/dev/drivers/net/Space.c linux/dev/drivers/net/Space.c
---- linux/dev/drivers/net/Space.c 1999-09-07 09:19:06.000000000 +0200
-+++ linux/dev/drivers/net/Space.c 2004-10-25 06:29:49.000000000 +0200
-@@ -62,6 +62,14 @@
- extern int de4x5_probe(struct device *);
- extern int el1_probe(struct device *);
- extern int via_rhine_probe(struct device *);
-+extern int natsemi_probe(struct device *);
-+extern int ns820_probe(struct device *);
-+extern int winbond840_probe(struct device *);
-+extern int hamachi_probe(struct device *);
-+extern int sundance_probe(struct device *);
-+extern int starfire_probe(struct device *);
-+extern int myson803_probe(struct device *);
-+extern int igige_probe(struct device *);
- #if defined(CONFIG_WAVELAN)
- extern int wavelan_probe(struct device *);
- #endif /* defined(CONFIG_WAVELAN) */
-@@ -132,6 +140,30 @@
- #ifdef CONFIG_VIA_RHINE
- && via_rhine_probe(dev)
- #endif
-+#ifdef CONFIG_NATSEMI
-+ && natsemi_probe(dev)
-+#endif
-+#ifdef CONFIG_NS820
-+ && ns820_probe(dev)
-+#endif
-+#ifdef CONFIG_WINBOND840
-+ && winbond840_probe(dev)
-+#endif
-+#ifdef CONFIG_HAMACHI
-+ && hamachi_probe(dev)
-+#endif
-+#ifdef CONFIG_SUNDANCE
-+ && sundance_probe(dev)
-+#endif
-+#ifdef CONFIG_STARFIRE
-+ && starfire_probe(dev)
-+#endif
-+#ifdef CONFIG_MYSON803
-+ && myson803_probe(dev)
-+#endif
-+#ifdef CONFIG_INTEL_GIGE
-+ && igige_probe(dev)
-+#endif
- #if defined(CONFIG_DEC_ELCP)
- && tulip_probe(dev)
- #endif
-diff -Naur linux/src/include/asm-i386/cache.h linux/src/include/asm-i386/cache.h
---- linux/src/include/asm-i386/cache.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux/src/include/asm-i386/cache.h 2004-10-23 15:58:14.000000000 +0200
-@@ -0,0 +1,18 @@
-+/*
-+ * include/asm-i386/cache.h
-+ */
-+#ifndef __ARCH_I386_CACHE_H
-+#define __ARCH_I386_CACHE_H
-+
-+/* bytes per L1 cache line */
-+#if CPU==586 || CPU==686
-+#define L1_CACHE_BYTES 32
-+#else
-+#define L1_CACHE_BYTES 16
-+#endif
-+
-+#define L1_CACHE_ALIGN(x) (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1))
-+
-+#define SMP_CACHE_BYTES L1_CACHE_BYTES
-+
-+#endif
-diff -Naur linux/dev/include/linux/malloc.h linux/dev/include/linux/malloc.h
---- linux/dev/include/linux/malloc.h 2004-10-25 10:14:02.000000000 +0200
-+++ linux/dev/include/linux/malloc.h 2004-10-25 10:13:13.000000000 +0200
-@@ -2,6 +2,7 @@
- #define _LINUX_MALLOC_H
-
- #include <linux/mm.h>
-+#include <asm/cache.h>
-
- #ifndef MACH_INCLUDE
- #define kmalloc linux_kmalloc
diff --git a/debian/patches/12_sis900.patch b/debian/patches/12_sis900.patch
index 0d62b02..f5ea78d 100644
--- a/debian/patches/12_sis900.patch
+++ b/debian/patches/12_sis900.patch
@@ -1,4 +1,4 @@
-#DPATCHLEVEL=1
+#DPATCHLEVEL=0
2005-05-01 Andreas B. Mundt <andi.mundt@web.de>
@@ -12,46 +12,21 @@
* linux/src/drivers/net/sis900.h: Likewise.
-diff -ruN gnumach.orig/doc/mach.texi gnumach.sis900/doc/mach.texi
---- gnumach.orig/doc/mach.texi 2002-03-29 22:01:19.000000000 +0100
-+++ gnumach.sis900/doc/mach.texi 2005-03-26 21:08:35.000000000 +0100
-@@ -854,6 +854,9 @@
-
- @item --enable-viarhine
- Enables the VIA Rhine netword card devices eth%d.
+--- doc/mach.texi 2006-02-01 22:58:07.000000000 +0200
++++ doc/mach.texi 2006-02-01 23:32:52.000000000 +0200
+@@ -878,6 +878,9 @@
+
+ @item --enable-winbond-840
+ Enables the Winbond W89c840 PCI Ethernet devices eth%d.
+
+@item --enable-sis900
+Enables the SiS900 PCI netword card devices eth%d.
@end table
-
-
-diff -ruN gnumach.orig/i386/README-Drivers gnumach.sis900/i386/README-Drivers
---- gnumach.orig/i386/README-Drivers 2001-05-27 14:44:22.000000000 +0200
-+++ gnumach.sis900/i386/README-Drivers 2005-03-26 21:08:35.000000000 +0100
-@@ -371,3 +371,7 @@
-
- VIA Rhine
- --enable-viarhine net/via_rhine.c
-+
-+SiS 900
-+ --enable-sis900 net/sis900.c
-+
-diff -ruN gnumach.orig/i386/linux/Makefile.in gnumach.sis900/i386/linux/Makefile.in
---- gnumach.orig/i386/linux/Makefile.in 2005-03-26 20:38:18.000000000 +0100
-+++ gnumach.sis900/i386/linux/Makefile.in 2005-03-26 21:08:35.000000000 +0100
-@@ -67,7 +67,7 @@
- atp.c de4x5.c de600.c de620.c depca.c dev.c e2100.c eepro.c \
- eepro100.c eexpress.c epic100.c eth16i.c ewrk3.c fmv18x.c \
- hp-plus.c hp.c hp100.c lance.c ne.c ne2k-pci.c net_init.c \
-- ni52.c ni65.c pcnet32.c rtl8139.c seeq8005.c sk_g16.c \
-+ ni52.c ni65.c pcnet32.c rtl8139.c seeq8005.c sis900.c sk_g16.c \
- smc-ultra.c smc-ultra32.c tlan.c tulip.c via-rhine.c wavelan.c \
- wd.c yellowfin.c znet.c net.c net.c cb_shim.c hamachi.c \
- intel-gige.c myson803.c natsemi.c ns820.c pci-scan.c \
-diff -ruN gnumach.orig/i386/linux/configure.ac gnumach.sis900/i386/linux/configure.ac
---- gnumach.orig/i386/linux/configure.ac 2005-03-26 20:38:18.000000000 +0100
-+++ gnumach.sis900/i386/linux/configure.ac 2005-03-26 21:08:35.000000000 +0100
-@@ -213,6 +213,7 @@
+
+
+--- i386/linux/configure.ac 2006-02-01 22:58:08.000000000 +0200
++++ i386/linux/configure.ac 2006-02-01 23:31:33.000000000 +0200
+@@ -207,6 +207,7 @@
linux_DRIVER([elplus], [ELPLUS], [3c505], [net])
linux_DRIVER([de600], [DE600], [de600], [net])
linux_DRIVER([de620], [DE620], [de620], [net])
@@ -59,9 +34,28 @@ diff -ruN gnumach.orig/i386/linux/configure.ac gnumach.sis900/i386/linux/configu
linux_DRIVER([skg16], [SK_G16], [sk_g16], [net])
linux_DRIVER([ni52], [NI52], [ni52], [net])
linux_DRIVER([ni65], [NI65], [ni65], [net])
-diff -ruN gnumach.orig/linux/dev/drivers/net/Space.c gnumach.sis900/linux/dev/drivers/net/Space.c
---- gnumach.orig/linux/dev/drivers/net/Space.c 2005-03-26 20:38:18.000000000 +0100
-+++ gnumach.sis900/linux/dev/drivers/net/Space.c 2005-03-26 21:08:35.000000000 +0100
+--- i386/linux/Makefile.in 2006-02-01 22:58:08.000000000 +0200
++++ i386/linux/Makefile.in 2006-02-01 23:34:05.000000000 +0200
+@@ -90,7 +90,7 @@
+ eexpress.c epic100.c eth16i.c ewrk3.c fmv18x.c hp-plus.c hp.c hp100.c \
+ lance.c ne.c ne2k-pci.c net_init.c ni52.c ni65.c pcnet32.c rtl8139.c \
+ seeq8005.c sk_g16.c smc-ultra.c smc-ultra32.c tlan.c tulip.c \
+- via-rhine.c wavelan.c wd.c yellowfin.c znet.c \
++ via-rhine.c sis900.c wavelan.c wd.c yellowfin.c znet.c \
+ cb_shim.c hamachi.c intel-gige.c myson803.c natsemi.c ns820.c \
+ starfire.c sundance.c winbond-840.c \
+ pci-scan.c \
+--- i386/README-Drivers 2006-02-01 22:58:07.000000000 +0200
++++ i386/README-Drivers 2006-02-01 23:34:52.000000000 +0200
+@@ -395,3 +395,6 @@
+
+ Winbond W89c840 PCI Ethernet
+ --enable-winbond-840 net/winbond-840.c
++
++SiS 900
++ --enable-sis900 net/sis900.c
+--- linux/dev/drivers/net/Space.c 2006-02-01 22:58:10.000000000 +0200
++++ linux/dev/drivers/net/Space.c 2006-02-01 23:31:33.000000000 +0200
@@ -93,6 +93,7 @@
extern int eepro100_probe(struct device *);
extern int epic100_probe(struct device *);
@@ -80,9 +74,8 @@ diff -ruN gnumach.orig/linux/dev/drivers/net/Space.c gnumach.sis900/linux/dev/dr
#ifdef CONFIG_VIA_RHINE
&& via_rhine_probe(dev)
#endif
-diff -ruN gnumach.orig/linux/src/drivers/net/sis900.c gnumach.sis900/linux/src/drivers/net/sis900.c
---- gnumach.orig/linux/src/drivers/net/sis900.c 1970-01-01 01:00:00.000000000 +0100
-+++ gnumach.sis900/linux/src/drivers/net/sis900.c 2005-03-27 20:52:47.000000000 +0200
+--- linux/src/drivers/net/sis900.c 1970-01-01 02:00:00.000000000 +0200
++++ linux/src/drivers/net/sis900.c 2006-02-01 23:31:33.000000000 +0200
@@ -0,0 +1,1803 @@
+/* sis900.c: A SiS 900/7016 PCI Fast Ethernet driver for Linux.
+ Copyright 1999 Silicon Integrated System Corporation
@@ -1887,9 +1880,8 @@ diff -ruN gnumach.orig/linux/src/drivers/net/sis900.c gnumach.sis900/linux/src/d
+}
+
+#endif /* MODULE */
-diff -ruN gnumach.orig/linux/src/drivers/net/sis900.h gnumach.sis900/linux/src/drivers/net/sis900.h
---- gnumach.orig/linux/src/drivers/net/sis900.h 1970-01-01 01:00:00.000000000 +0100
-+++ gnumach.sis900/linux/src/drivers/net/sis900.h 2005-03-26 21:08:35.000000000 +0100
+--- linux/src/drivers/net/sis900.h 1970-01-01 02:00:00.000000000 +0200
++++ linux/src/drivers/net/sis900.h 2006-02-01 23:31:33.000000000 +0200
@@ -0,0 +1,284 @@
+/* sis900.h Definitions for SiS ethernet controllers including 7014/7016 and 900
+ * Copyright 1999 Silicon Integrated System Corporation
@@ -2175,5 +2167,3 @@ diff -ruN gnumach.orig/linux/src/drivers/net/sis900.h gnumach.sis900/linux/src/d
+#define SIOCGMIIPHY (SIOCDEVPRIVATE) /* Get the PHY in use. */
+#define SIOCGMIIREG (SIOCDEVPRIVATE+1) /* Read a PHY register. */
+#define SIOCSMIIREG (SIOCDEVPRIVATE+2) /* Write a PHY register */
-
-
diff --git a/debian/patches/13_ide_dma.patch b/debian/patches/13_ide_dma.patch
index 48479e7..2fae496 100644
--- a/debian/patches/13_ide_dma.patch
+++ b/debian/patches/13_ide_dma.patch
@@ -9,7 +9,7 @@ supporting hardware.
diff -Naur i386.orig/linux/configure.ac i386/linux/configure.ac
--- i386.orig/linux/configure.ac 2004-09-17 01:03:19.000000000 +0200
+++ i386/linux/configure.ac 2004-09-17 01:01:49.000000000 +0200
-@@ -129,6 +129,11 @@
+@@ -123,6 +123,11 @@
AC_DRIVER([ide], [CONFIG_BLK_DEV_IDE], [ \
cmd640.o ide-cd.o ide.o rz1000.o triton.o])
diff --git a/debian/patches/15_mem_obj_proxy.patch b/debian/patches/15_mem_obj_proxy.patch
index a3e272a..b9bd4d8 100644
--- a/debian/patches/15_mem_obj_proxy.patch
+++ b/debian/patches/15_mem_obj_proxy.patch
@@ -20,14 +20,7 @@
diff -rupN gnumach-1/Makefile.in gnumach/Makefile.in
--- gnumach-1/Makefile.in 2005-06-06 21:37:42.000000000 +0200
+++ gnumach/Makefile.in 2005-06-07 04:08:55.000000000 +0200
-@@ -1,5 +1,5 @@
- # Makefile for Mach 4 kernel directory
--# Copyright 1997, 1999, 2004 Free Software Foundation, Inc.
-+# Copyright 1997, 1999, 2004, 2005 Free Software Foundation, Inc.
- #
- # Permission to use, copy, modify and distribute this software and its
- # documentation is hereby granted, provided that both the copyright
-@@ -157,7 +157,7 @@ util-files = $(util-cfiles) config.h cpu
+@@ -158,7 +158,7 @@ util-files = $(util-cfiles) config.h cpu
phys_mem.h ref_count.h
# Virtual memory implementation
diff --git a/debian/patches/17_net_gcc_4.0.patch b/debian/patches/17_net_gcc_4.0.patch
deleted file mode 100644
index 9534738..0000000
--- a/debian/patches/17_net_gcc_4.0.patch
+++ /dev/null
@@ -1,37 +0,0 @@
-#DPATCHLEVEL=0
-
-2005-11-05 Thomas Schwinge <tschwinge@gnu.org>
-
- * linux/src/drivers/net/ne2k-pci.c (ne2k_pci_block_input)
- (ne2k_pci_block_output): Fix invalid lvalue errors with gcc 4.0.
-
-
-diff -Naur linux/src/drivers/net/ne2k-pci.c linux/src/drivers/net/ne2k-pci.c
---- linux/src/drivers/net/ne2k-pci.c 2005-11-28 03:34:08.000000000 +0200
-+++ linux/src/drivers/net/ne2k-pci.c 2005-11-28 03:38:41.000000000 +0200
-@@ -546,8 +546,10 @@
- insl(NE_BASE + NE_DATAPORT, buf, count>>2);
- if (count & 3) {
- buf += count & ~3;
-- if (count & 2)
-- *((u16*)buf)++ = le16_to_cpu(inw(NE_BASE + NE_DATAPORT));
-+ if (count & 2) {
-+ *((u16 *) buf) = le16_to_cpu(inw(NE_BASE + NE_DATAPORT));
-+ buf = (void *) buf + sizeof (u16);
-+ }
- if (count & 1)
- *buf = inb(NE_BASE + NE_DATAPORT);
- }
-@@ -609,8 +611,10 @@
- outsl(NE_BASE + NE_DATAPORT, buf, count>>2);
- if (count & 3) {
- buf += count & ~3;
-- if (count & 2)
-- outw(cpu_to_le16(*((u16*)buf)++), NE_BASE + NE_DATAPORT);
-+ if (count & 2) {
-+ outw(cpu_to_le16(*((u16 *) buf)), NE_BASE + NE_DATAPORT);
-+ buf = (void *) buf + sizeof (u16);
-+ }
- }
- }
-
diff --git a/debian/patches/20_ide_disable_irqs.patch b/debian/patches/20_ide_disable_irqs.patch
deleted file mode 100644
index de1b396..0000000
--- a/debian/patches/20_ide_disable_irqs.patch
+++ /dev/null
@@ -1,95 +0,0 @@
-#DPATCHLEVEL=1
-
-2005-07-30 Samuel Thibault <samuel.thibault@ens-lyon.org>
-
- * irq.c (linux_intr): Disable interrupts when the driver
- requested it through request_irq().
-
-
---- gnumach/linux/dev/arch/i386/kernel/irq.c 1999-04-26 07:40:55.000000000 +0200
-+++ gnumach/linux/dev/arch/i386/kernel/irq.c 2005-07-19 04:37:17.000000000 +0200
-@@ -103,16 +103,23 @@ linux_intr (int irq)
- {
- struct pt_regs regs;
- struct linux_action *action = *(irq_action + irq);
-+ unsigned long flags;
-
- kstat.interrupts[irq]++;
- intr_count++;
-
-+ save_flags (flags);
-+ if (action && (action->flags & SA_INTERRUPT))
-+ cli ();
-+
- while (action)
- {
- action->handler (irq, action->dev_id, &regs);
- action = action->next;
- }
-
-+ restore_flags (flags);
-+
- intr_count--;
-
- /* Not used. by OKUJI Yoshinori. */
-
-
-2005-07-30 Samuel Thibault <samuel.thibault@ens-lyon.org>
-
- * ide.c (read_intr): Set irq handler before issuing order, in
- case the device is really fast (QEMU for instance).
- (write_intr): Likewise.
- (multwrite_intr): Likewise.
-
---- gnumach/linux/dev/drivers/block/ide.c 2001-06-28 10:55:02.000000000 +0200
-+++ gnumach/linux/dev/drivers/block/ide.c 2005-07-19 03:53:36.000000000 +0200
-@@ -1129,6 +1129,9 @@ read_intr (ide_drive_t *drive)
- msect -= nsect;
- } else
- nsect = 1;
-+ i = rq->nr_sectors - nsect;
-+ if (i > 0 && !msect)
-+ ide_set_handler (drive, &read_intr, WAIT_CMD);
- ide_input_data(drive, rq->buffer, nsect * SECTOR_WORDS);
- #ifdef DEBUG
- printk("%s: read: sectors(%ld-%ld), buffer=0x%08lx, remaining=%ld\n",
-@@ -1138,14 +1141,11 @@ read_intr (ide_drive_t *drive)
- rq->sector += nsect;
- rq->buffer += nsect<<9;
- rq->errors = 0;
-- i = (rq->nr_sectors -= nsect);
-+ rq->nr_sectors = i;
- if ((rq->current_nr_sectors -= nsect) <= 0)
- ide_end_request(1, HWGROUP(drive));
-- if (i > 0) {
-- if (msect)
-- goto read_next;
-- ide_set_handler (drive, &read_intr, WAIT_CMD);
-- }
-+ if (i > 0 && msect)
-+ goto read_next;
- }
-
- /*
-@@ -1173,8 +1173,8 @@ write_intr (ide_drive_t *drive)
- if (rq->current_nr_sectors <= 0)
- ide_end_request(1, hwgroup);
- if (i > 0) {
-+ ide_set_handler (drive, &write_intr, WAIT_CMD);
- ide_output_data (drive, rq->buffer, SECTOR_WORDS);
-- ide_set_handler (drive, &write_intr, WAIT_CMD);
- }
- return;
- }
-@@ -1231,8 +1231,8 @@ multwrite_intr (ide_drive_t *drive)
- if (OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) {
- if (stat & DRQ_STAT) {
- if (rq->nr_sectors) {
-+ ide_set_handler (drive, &multwrite_intr, WAIT_CMD);
- ide_multwrite(drive, drive->mult_count);
-- ide_set_handler (drive, &multwrite_intr, WAIT_CMD);
- return;
- }
- } else {
-
-
diff --git a/debian/patches/31_tls_ldt.patch b/debian/patches/31_tls_ldt.patch
deleted file mode 100644
index 5cbc6d2..0000000
--- a/debian/patches/31_tls_ldt.patch
+++ /dev/null
@@ -1,53 +0,0 @@
-#DPATCHLEVEL=0
-
-2005-09-18 Jeroen Dekkers <jeroen@dekkers.cx>
-
- * i386/i386/locore.S (trap_push_segs): Switch fs and gs to kernel
- data segment too.
- (syscall_entry_2): Likewise.
- * i386/i386/user_ldt.c (i386_set_ldt): Always copy the master LDT
- when there is no old user LDT.
-
-
-Index: i386/i386/locore.S
-===================================================================
-RCS file: /cvsroot/hurd/gnumach/i386/i386/locore.S,v
-retrieving revision 1.6.2.1
-diff -u -p -r1.6.2.1 locore.S
---- i386/i386/locore.S 28 Nov 2004 17:29:35 -0000 1.6.2.1
-+++ i386/i386/locore.S 30 Aug 2005 10:34:02 -0000
-@@ -464,6 +464,8 @@ trap_push_segs:
- mov %ss,%ax /* switch to kernel data segment */
- mov %ax,%ds /* (same as kernel stack segment) */
- mov %ax,%es
-+ mov %ax,%fs
-+ mov %ax,%gs
-
- trap_set_segs:
- cld /* clear direction flag */
-@@ -982,6 +984,8 @@ syscall_entry_2:
- mov %ss,%dx /* switch to kernel data segment */
- mov %dx,%ds
- mov %dx,%es
-+ mov %dx,%fs
-+ mov %dx,%gs
-
- /*
- * Shuffle eflags,eip,cs into proper places
-Index: i386/i386/user_ldt.c
-===================================================================
-RCS file: /cvsroot/hurd/gnumach/i386/i386/user_ldt.c,v
-retrieving revision 1.2
-diff -u -p -r1.2 user_ldt.c
---- i386/i386/user_ldt.c 16 Sep 1999 02:17:48 -0000 1.2
-+++ i386/i386/user_ldt.c 30 Aug 2005 10:34:02 -0000
-@@ -225,7 +225,7 @@ i386_set_ldt(thread, first_selector, des
- (char *)&new_ldt->ldt[0],
- old_ldt->desc.limit_low + 1);
- }
-- else if (thread == current_thread()) {
-+ else {
- struct real_descriptor template = {0, 0, 0, ACC_P, 0, 0 ,0};
-
- for (dp = &new_ldt->ldt[0], i = 0; i < first_desc; i++, dp++) {
-
diff --git a/debian/patches/41_io_unlock_ioremove.patch b/debian/patches/41_io_unlock_ioremove.patch
index e71ed41..02dbbe6 100644
--- a/debian/patches/41_io_unlock_ioremove.patch
+++ b/debian/patches/41_io_unlock_ioremove.patch
@@ -13,7 +13,7 @@ retrieving revision 1.1.1.1
diff -u -r1.1.1.1 iopb.c
--- i386/i386/iopb.c 25 Feb 1997 21:27:09 -0000 1.1.1.1
+++ i386/i386/iopb.c 28 Dec 2005 16:18:40 -0000
-@@ -468,6 +468,10 @@
+@@ -469,6 +469,10 @@
/*
* No mapping.
*/
diff --git a/debian/patches/42_disable_ioperm.patch b/debian/patches/42_disable_ioperm.patch
index 2a292ec..1bb6768 100644
--- a/debian/patches/42_disable_ioperm.patch
+++ b/debian/patches/42_disable_ioperm.patch
@@ -12,7 +12,7 @@
--- i386/i386/iopb.c Tue Feb 25 22:27:09 1997
+++ i386/i386/iopb.c Sun Oct 7 05:00:09 2001
-@@ -270,7 +270,7 @@
+@@ -271,7 +271,7 @@
register iopb_tss_t ts;
ts = (iopb_tss_t) kalloc(sizeof (struct iopb_tss));
@@ -21,7 +21,7 @@
return ts;
}
-@@ -357,7 +360,7 @@
+@@ -357,7 +362,7 @@
simple_unlock(&iopb_lock);
new_io_tss = (iopb_tss_t) kalloc(sizeof(struct iopb_tss));
diff --git a/debian/patches/45_io_per_task.patch b/debian/patches/45_io_per_task.patch
index b9290b9..0614848 100644
--- a/debian/patches/45_io_per_task.patch
+++ b/debian/patches/45_io_per_task.patch
@@ -187,7 +187,7 @@ diff -urp gnumach-mine-4-more_ports/i386/i386/iopb.c gnumach-mine-5-io_per_task/
/*
* No mapping.
*/
-@@ -493,7 +501,7 @@ i386_io_port_remove(thread, device)
+@@ -497,7 +505,7 @@ i386_io_port_remove(thread, device)
}
/*
@@ -196,7 +196,7 @@ diff -urp gnumach-mine-4-more_ports/i386/i386/iopb.c gnumach-mine-5-io_per_task/
*/
extern ipc_port_t mach_convert_device_to_port(/* device_t */);
-@@ -503,7 +511,7 @@ i386_io_port_list(thread, list, list_cou
+@@ -507,7 +515,7 @@ i386_io_port_list(thread, list, list_cou
mach_device_t **list;
unsigned int *list_count;
{
@@ -205,7 +205,7 @@ diff -urp gnumach-mine-4-more_ports/i386/i386/iopb.c gnumach-mine-5-io_per_task/
register iopb_tss_t io_tss;
unsigned int count, alloc_count;
mach_device_t *devices;
-@@ -514,7 +522,7 @@ i386_io_port_list(thread, list, list_cou
+@@ -518,7 +526,7 @@ i386_io_port_list(thread, list, list_cou
if (thread == THREAD_NULL)
return KERN_INVALID_ARGUMENT;
@@ -214,7 +214,7 @@ diff -urp gnumach-mine-4-more_ports/i386/i386/iopb.c gnumach-mine-5-io_per_task/
alloc_count = 16; /* a guess */
-@@ -537,8 +545,8 @@ i386_io_port_list(thread, list, list_cou
+@@ -541,8 +549,8 @@ i386_io_port_list(thread, list, list_cou
count = 0;
simple_lock(&iopb_lock);
@@ -225,7 +225,7 @@ diff -urp gnumach-mine-4-more_ports/i386/i386/iopb.c gnumach-mine-5-io_per_task/
if (io_tss != 0) {
register io_use_t iu;
-@@ -550,7 +558,7 @@ i386_io_port_list(thread, list, list_cou
+@@ -554,7 +562,7 @@ i386_io_port_list(thread, list, list_cou
}
}
}
@@ -234,7 +234,7 @@ diff -urp gnumach-mine-4-more_ports/i386/i386/iopb.c gnumach-mine-5-io_per_task/
simple_unlock(&iopb_lock);
} while (count > alloc_count);
-@@ -596,7 +604,7 @@ i386_io_port_list(thread, list, list_cou
+@@ -600,7 +608,7 @@ i386_io_port_list(thread, list, list_cou
}
/*
@@ -243,7 +243,7 @@ diff -urp gnumach-mine-4-more_ports/i386/i386/iopb.c gnumach-mine-5-io_per_task/
* Used to support the 'iopl' device automatic mapping.
*/
boolean_t
-@@ -604,11 +612,11 @@ iopb_check_mapping(thread, device)
+@@ -608,11 +616,11 @@ iopb_check_mapping(thread, device)
thread_t thread;
mach_device_t device;
{
@@ -257,7 +257,7 @@ diff -urp gnumach-mine-4-more_ports/i386/i386/iopb.c gnumach-mine-5-io_per_task/
simple_lock(&iopb_lock);
-@@ -622,15 +630,18 @@ iopb_check_mapping(thread, device)
+@@ -626,15 +634,18 @@ iopb_check_mapping(thread, device)
/* Look up the mapping in the device`s mapping list. */
diff --git a/debian/patches/90_autoconf_autogen.patch b/debian/patches/90_autoconf_autogen.patch
index e5133fc..3fdb1c6 100644
--- a/debian/patches/90_autoconf_autogen.patch
+++ b/debian/patches/90_autoconf_autogen.patch
@@ -1,4 +1,4 @@
-#DPATCHLEVEL=1
+#DPATCHLEVEL=0
This patch is just autogenerated stuff, do not hack directly on it.
Regenerate with:
@@ -7,59 +7,25 @@ Regenerate with:
find -name autom4te.cache | xargs rm -rf
-diff -Naur gnumach-20050801.orig/i386/linux/configure gnumach-20050801/i386/linux/configure
---- gnumach-20050801.orig/i386/linux/configure 2005-07-25 06:48:31.000000000 +0300
-+++ gnumach-20050801/i386/linux/configure 2005-08-01 04:04:31.000000000 +0300
-@@ -853,6 +853,7 @@
+--- i386/linux/configure 2006-02-01 22:58:08.000000000 +0200
++++ i386/linux/configure 2006-02-02 04:55:10.000000000 +0200
+@@ -839,6 +839,7 @@
--enable-epic100 enable driver alias epic100 for epic
--enable-floppy enable driver floppy
--enable-ide enable driver ide
+ --enable-ide-forcedma enable forced use of DMA on IDE
- --enable-advansys enable driver alias advansys for advansys
--enable-advansys enable driver advansys
--enable-BusLogic enable driver alias BusLogic for buslogic
-@@ -910,6 +911,22 @@
- --enable-gdth enable driver alias gdth for gdth
- --enable-gdth enable driver gdth
- --enable-flashpoint enable SCSI flashpoint [default=no]
-+ --enable-starfire enable driver alias starfire for starfire
-+ --enable-starfire enable driver starfire
-+ --enable-sundance enable driver alias sundance for sundance
-+ --enable-sundance enable driver sundance
-+ --enable-winbond-840 enable driver alias winbond-840 for winbond_840
-+ --enable-winbond_840 enable driver winbond_840
-+ --enable-hamachi enable driver alias hamachi for hamachi
-+ --enable-hamachi enable driver hamachi
-+ --enable-intel-gige enable driver alias intel-gige for intel_gige
-+ --enable-intel_gige enable driver intel_gige
-+ --enable-natsemi enable driver alias natsemi for natsemi
-+ --enable-natsemi enable driver natsemi
-+ --enable-myson803 enable driver alias myson803 for myson803
-+ --enable-myson803 enable driver myson803
-+ --enable-ns820 enable driver alias ns820 for ns820
-+ --enable-ns820 enable driver ns820
- --enable-ne2000 enable driver ne2000
- --enable-el2 enable driver el2
- --enable-el3 enable driver el3
-@@ -954,6 +971,8 @@
+ --enable-buslogic enable driver buslogic
+@@ -920,6 +921,7 @@
+ --enable-elplus enable driver elplus
--enable-de600 enable driver de600
- --enable-de620 enable driver alias de620 for de620
--enable-de620 enable driver de620
-+ --enable-sis900 enable driver alias sis900 for sis900
+ --enable-sis900 enable driver sis900
--enable-sk_g16 enable driver alias sk_g16 for skg16
--enable-skg16 enable driver skg16
- --enable-ni52 enable driver alias ni52 for ni52
-@@ -3085,7 +3104,7 @@
-
- driver_class_net_option=CONFIG_INET
- driver_class_net_files=" \
-- auto_irq.o net.o Space.o dev.o net_init.o"
-+ auto_irq.o net.o Space.o dev.o net_init.o pci-scan.o"
-
-
-
-@@ -3142,6 +3161,17 @@
+ --enable-ni52 enable driver ni52
+@@ -2003,6 +2005,17 @@
fi;
@@ -77,298 +43,10 @@ diff -Naur gnumach-20050801.orig/i386/linux/configure gnumach-20050801/i386/linu
-@@ -4111,6 +4141,280 @@
-
-
-
-+
-+
-+# Checking for alias starfire
-+# Check whether --enable-starfire or --disable-starfire was given.
-+if test "${enable_starfire+set}" = set; then
-+ enableval="$enable_starfire"
-+ enable_starfire="$enable_starfire"
-+
-+fi;
-+
-+# Checking for device driver option starfire
-+# Check whether --enable-starfire or --disable-starfire was given.
-+if test "${enable_starfire+set}" = set; then
-+ enableval="$enable_starfire"
-+
-+if test "x$enableval" != xno; then
-+
-+cat >>confdefs.h <<\_ACEOF
-+#define CONFIG_STARFIRE 1
-+_ACEOF
-+
-+device_drivers="$device_drivers starfire.o"
-+if test "${driver_class_net_selected+set}" != set; then
-+ driver_class_net_selected=yes
-+ cat >>confdefs.h <<_ACEOF
-+#define $driver_class_net_option 1
-+_ACEOF
-+
-+ device_drivers="$device_drivers $driver_class_net_files"
-+fi
-+fi
-+
-+fi;
-+
-+
-+
-+# Checking for alias sundance
-+# Check whether --enable-sundance or --disable-sundance was given.
-+if test "${enable_sundance+set}" = set; then
-+ enableval="$enable_sundance"
-+ enable_sundance="$enable_sundance"
-+
-+fi;
-+
-+# Checking for device driver option sundance
-+# Check whether --enable-sundance or --disable-sundance was given.
-+if test "${enable_sundance+set}" = set; then
-+ enableval="$enable_sundance"
-+
-+if test "x$enableval" != xno; then
-+
-+cat >>confdefs.h <<\_ACEOF
-+#define CONFIG_SUNDANCE 1
-+_ACEOF
-+
-+device_drivers="$device_drivers sundance.o"
-+if test "${driver_class_net_selected+set}" != set; then
-+ driver_class_net_selected=yes
-+ cat >>confdefs.h <<_ACEOF
-+#define $driver_class_net_option 1
-+_ACEOF
-+
-+ device_drivers="$device_drivers $driver_class_net_files"
-+fi
-+fi
-+
-+fi;
-+
-+
-+
-+# Checking for alias winbond-840
-+# Check whether --enable-winbond-840 or --disable-winbond-840 was given.
-+if test "${enable_winbond_840+set}" = set; then
-+ enableval="$enable_winbond_840"
-+ enable_winbond_840="$enable_winbond-840"
-+
-+fi;
-+
-+# Checking for device driver option winbond_840
-+# Check whether --enable-winbond_840 or --disable-winbond_840 was given.
-+if test "${enable_winbond_840+set}" = set; then
-+ enableval="$enable_winbond_840"
-+
-+if test "x$enableval" != xno; then
-+
-+cat >>confdefs.h <<\_ACEOF
-+#define CONFIG_WINBOND840 1
-+_ACEOF
-+
-+device_drivers="$device_drivers winbond-840.o"
-+if test "${driver_class_net_selected+set}" != set; then
-+ driver_class_net_selected=yes
-+ cat >>confdefs.h <<_ACEOF
-+#define $driver_class_net_option 1
-+_ACEOF
-+
-+ device_drivers="$device_drivers $driver_class_net_files"
-+fi
-+fi
-+
-+fi;
-+
-+
-+
-+# Checking for alias hamachi
-+# Check whether --enable-hamachi or --disable-hamachi was given.
-+if test "${enable_hamachi+set}" = set; then
-+ enableval="$enable_hamachi"
-+ enable_hamachi="$enable_hamachi"
-+
-+fi;
-+
-+# Checking for device driver option hamachi
-+# Check whether --enable-hamachi or --disable-hamachi was given.
-+if test "${enable_hamachi+set}" = set; then
-+ enableval="$enable_hamachi"
-+
-+if test "x$enableval" != xno; then
-+
-+cat >>confdefs.h <<\_ACEOF
-+#define CONFIG_HAMACHI 1
-+_ACEOF
-+
-+device_drivers="$device_drivers hamachi.o"
-+if test "${driver_class_net_selected+set}" != set; then
-+ driver_class_net_selected=yes
-+ cat >>confdefs.h <<_ACEOF
-+#define $driver_class_net_option 1
-+_ACEOF
-+
-+ device_drivers="$device_drivers $driver_class_net_files"
-+fi
-+fi
-+
-+fi;
-+
-+
-+
-+# Checking for alias intel-gige
-+# Check whether --enable-intel-gige or --disable-intel-gige was given.
-+if test "${enable_intel_gige+set}" = set; then
-+ enableval="$enable_intel_gige"
-+ enable_intel_gige="$enable_intel-gige"
-+
-+fi;
-+
-+# Checking for device driver option intel_gige
-+# Check whether --enable-intel_gige or --disable-intel_gige was given.
-+if test "${enable_intel_gige+set}" = set; then
-+ enableval="$enable_intel_gige"
-+
-+if test "x$enableval" != xno; then
-+
-+cat >>confdefs.h <<\_ACEOF
-+#define CONFIG_INTEL_GIGE 1
-+_ACEOF
-+
-+device_drivers="$device_drivers intel-gige.o"
-+if test "${driver_class_net_selected+set}" != set; then
-+ driver_class_net_selected=yes
-+ cat >>confdefs.h <<_ACEOF
-+#define $driver_class_net_option 1
-+_ACEOF
-+
-+ device_drivers="$device_drivers $driver_class_net_files"
-+fi
-+fi
-+
-+fi;
-+
-+
-+
-+# Checking for alias natsemi
-+# Check whether --enable-natsemi or --disable-natsemi was given.
-+if test "${enable_natsemi+set}" = set; then
-+ enableval="$enable_natsemi"
-+ enable_natsemi="$enable_natsemi"
-+
-+fi;
-+
-+# Checking for device driver option natsemi
-+# Check whether --enable-natsemi or --disable-natsemi was given.
-+if test "${enable_natsemi+set}" = set; then
-+ enableval="$enable_natsemi"
-+
-+if test "x$enableval" != xno; then
-+
-+cat >>confdefs.h <<\_ACEOF
-+#define CONFIG_NATSEMI 1
-+_ACEOF
-+
-+device_drivers="$device_drivers natsemi.o"
-+if test "${driver_class_net_selected+set}" != set; then
-+ driver_class_net_selected=yes
-+ cat >>confdefs.h <<_ACEOF
-+#define $driver_class_net_option 1
-+_ACEOF
-+
-+ device_drivers="$device_drivers $driver_class_net_files"
-+fi
-+fi
-+
-+fi;
-+
-+
-+
-+# Checking for alias myson803
-+# Check whether --enable-myson803 or --disable-myson803 was given.
-+if test "${enable_myson803+set}" = set; then
-+ enableval="$enable_myson803"
-+ enable_myson803="$enable_myson803"
-+
-+fi;
-+
-+# Checking for device driver option myson803
-+# Check whether --enable-myson803 or --disable-myson803 was given.
-+if test "${enable_myson803+set}" = set; then
-+ enableval="$enable_myson803"
-+
-+if test "x$enableval" != xno; then
-+
-+cat >>confdefs.h <<\_ACEOF
-+#define CONFIG_MYSON803 1
-+_ACEOF
-+
-+device_drivers="$device_drivers myson803.o"
-+if test "${driver_class_net_selected+set}" != set; then
-+ driver_class_net_selected=yes
-+ cat >>confdefs.h <<_ACEOF
-+#define $driver_class_net_option 1
-+_ACEOF
-+
-+ device_drivers="$device_drivers $driver_class_net_files"
-+fi
-+fi
-+
-+fi;
-+
-+
-+
-+# Checking for alias ns820
-+# Check whether --enable-ns820 or --disable-ns820 was given.
-+if test "${enable_ns820+set}" = set; then
-+ enableval="$enable_ns820"
-+ enable_ns820="$enable_ns820"
-+
-+fi;
-+
-+# Checking for device driver option ns820
-+# Check whether --enable-ns820 or --disable-ns820 was given.
-+if test "${enable_ns820+set}" = set; then
-+ enableval="$enable_ns820"
-+
-+if test "x$enableval" != xno; then
-+
-+cat >>confdefs.h <<\_ACEOF
-+#define CONFIG_NS820 1
-+_ACEOF
-+
-+device_drivers="$device_drivers ns820.o"
-+if test "${driver_class_net_selected+set}" != set; then
-+ driver_class_net_selected=yes
-+ cat >>confdefs.h <<_ACEOF
-+#define $driver_class_net_option 1
-+_ACEOF
-+
-+ device_drivers="$device_drivers $driver_class_net_files"
-+fi
-+fi
-+
-+fi;
-+
-+
-+
- # Checking for device driver option ne2000
- # Check whether --enable-ne2000 or --disable-ne2000 was given.
- if test "${enable_ne2000+set}" = set; then
-@@ -5008,6 +5312,40 @@
+@@ -3891,6 +3904,33 @@
-+# Checking for alias sis900
-+# Check whether --enable-sis900 or --disable-sis900 was given.
-+if test "${enable_sis900+set}" = set; then
-+ enableval="$enable_sis900"
-+ enable_sis900="$enable_sis900"
-+
-+fi;
+
+# Checking for device driver option sis900
+# Check whether --enable-sis900 or --disable-sis900 was given.
@@ -399,9 +77,8 @@ diff -Naur gnumach-20050801.orig/i386/linux/configure gnumach-20050801/i386/linu
# Checking for alias sk_g16
# Check whether --enable-sk_g16 or --disable-sk_g16 was given.
if test "${enable_sk_g16+set}" = set; then
-diff -Naur gnumach-20050801.orig/i386/linux/device-drivers.h.in gnumach-20050801/i386/linux/device-drivers.h.in
---- gnumach-20050801.orig/i386/linux/device-drivers.h.in 2005-07-25 06:48:31.000000000 +0300
-+++ gnumach-20050801/i386/linux/device-drivers.h.in 2005-08-01 04:04:33.000000000 +0300
+--- i386/linux/device-drivers.h.in 2006-02-01 22:58:08.000000000 +0200
++++ i386/linux/device-drivers.h.in 2006-02-02 04:55:11.000000000 +0200
@@ -18,6 +18,9 @@
/* floppy */
#undef CONFIG_BLK_DEV_FD
@@ -412,50 +89,7 @@ diff -Naur gnumach-20050801.orig/i386/linux/device-drivers.h.in gnumach-20050801
/* ide */
#undef CONFIG_BLK_DEV_IDE
-@@ -75,6 +78,9 @@
- /* fmv18x */
- #undef CONFIG_FMV18X
-
-+/* hamachi */
-+#undef CONFIG_HAMACHI
-+
- /* hp100 */
- #undef CONFIG_HP100
-
-@@ -87,6 +93,9 @@
- /* Driver Class net */
- #undef CONFIG_INET
-
-+/* intel_gige */
-+#undef CONFIG_INTEL_GIGE
-+
- /* lance */
- #undef CONFIG_LANCE
-
-@@ -102,6 +111,12 @@
- /* 686 */
- #undef CONFIG_M686
-
-+/* myson803 */
-+#undef CONFIG_MYSON803
-+
-+/* natsemi */
-+#undef CONFIG_NATSEMI
-+
- /* ne2000 */
- #undef CONFIG_NE2000
-
-@@ -114,6 +129,9 @@
- /* ni65 */
- #undef CONFIG_NI65
-
-+/* ns820 */
-+#undef CONFIG_NS820
-+
- /* pcnet32 */
- #undef CONFIG_PCNET32
-
-@@ -213,9 +231,18 @@
+@@ -228,6 +231,9 @@
/* seeq8005 */
#undef CONFIG_SEEQ8005
@@ -465,288 +99,3 @@ diff -Naur gnumach-20050801.orig/i386/linux/device-drivers.h.in gnumach-20050801
/* skg16 */
#undef CONFIG_SK_G16
-+/* starfire */
-+#undef CONFIG_STARFIRE
-+
-+/* sundance */
-+#undef CONFIG_SUNDANCE
-+
- /* tlan */
- #undef CONFIG_TLAN
-
-@@ -237,6 +264,9 @@
- /* wd80x3 */
- #undef CONFIG_WD80x3
-
-+/* winbond_840 */
-+#undef CONFIG_WINBOND840
-+
- /* yellowfin */
- #undef CONFIG_YELLOWFIN
-
-diff -Naur gnumach-20050801.orig/i386/linux/device-drivers.h.in~ gnumach-20050801/i386/linux/device-drivers.h.in~
---- gnumach-20050801.orig/i386/linux/device-drivers.h.in~ 1970-01-01 02:00:00.000000000 +0200
-+++ gnumach-20050801/i386/linux/device-drivers.h.in~ 2005-07-25 06:48:31.000000000 +0300
-@@ -0,0 +1,262 @@
-+/* device-drivers.h.in. Generated from configure.ac by autoheader. */
-+
-+/* 3c515 */
-+#undef CONFIG_3C515
-+
-+/* ac3200 */
-+#undef CONFIG_AC3200
-+
-+/* apricot */
-+#undef CONFIG_APRICOT
-+
-+/* at1700 */
-+#undef CONFIG_AT1700
-+
-+/* atp */
-+#undef CONFIG_ATP
-+
-+/* floppy */
-+#undef CONFIG_BLK_DEV_FD
-+
-+/* ide */
-+#undef CONFIG_BLK_DEV_IDE
-+
-+/* de4x5 */
-+#undef CONFIG_DE4X5
-+
-+/* de600 */
-+#undef CONFIG_DE600
-+
-+/* de620 */
-+#undef CONFIG_DE620
-+
-+/* elcp */
-+#undef CONFIG_DEC_ELCP
-+
-+/* depca */
-+#undef CONFIG_DEPCA
-+
-+/* e2100 */
-+#undef CONFIG_E2100
-+
-+/* eexpress */
-+#undef CONFIG_EEXPRESS
-+
-+/* eexpresspro */
-+#undef CONFIG_EEXPRESS_PRO
-+
-+/* eexpresspro100 */
-+#undef CONFIG_EEXPRESS_PRO100B
-+
-+/* el1 */
-+#undef CONFIG_EL1
-+
-+/* el16 */
-+#undef CONFIG_EL16
-+
-+/* el2 */
-+#undef CONFIG_EL2
-+
-+/* el3 */
-+#undef CONFIG_EL3
-+
-+/* elplus */
-+#undef CONFIG_ELPLUS
-+
-+/* epic */
-+#undef CONFIG_EPIC
-+
-+/* eth16i */
-+#undef CONFIG_ETH16I
-+
-+/* ewrk3 */
-+#undef CONFIG_EWRK3
-+
-+/* fmv18x */
-+#undef CONFIG_FMV18X
-+
-+/* hp100 */
-+#undef CONFIG_HP100
-+
-+/* hplan */
-+#undef CONFIG_HPLAN
-+
-+/* hplanplus */
-+#undef CONFIG_HPLAN_PLUS
-+
-+/* Driver Class net */
-+#undef CONFIG_INET
-+
-+/* lance */
-+#undef CONFIG_LANCE
-+
-+/* 386 */
-+#undef CONFIG_M386
-+
-+/* 486 */
-+#undef CONFIG_M486
-+
-+/* 586 */
-+#undef CONFIG_M586
-+
-+/* 686 */
-+#undef CONFIG_M686
-+
-+/* ne2000 */
-+#undef CONFIG_NE2000
-+
-+/* ne2kpci */
-+#undef CONFIG_NE2K_PCI
-+
-+/* ni52 */
-+#undef CONFIG_NI52
-+
-+/* ni65 */
-+#undef CONFIG_NI65
-+
-+/* pcnet32 */
-+#undef CONFIG_PCNET32
-+
-+/* rtl8139 */
-+#undef CONFIG_RTL8139
-+
-+/* Driver Class scsi */
-+#undef CONFIG_SCSI
-+
-+/* wd7000 */
-+#undef CONFIG_SCSI_7000FASST
-+
-+/* advansys */
-+#undef CONFIG_SCSI_ADVANSYS
-+
-+/* aha152x */
-+#undef CONFIG_SCSI_AHA152X
-+
-+/* aha1542 */
-+#undef CONFIG_SCSI_AHA1542
-+
-+/* aha1740 */
-+#undef CONFIG_SCSI_AHA1740
-+
-+/* aic7xxx */
-+#undef CONFIG_SCSI_AIC7XXX
-+
-+/* am53c974 */
-+#undef CONFIG_SCSI_AM53C974
-+
-+/* buslogic */
-+#undef CONFIG_SCSI_BUSLOGIC
-+
-+/* dc390t */
-+#undef CONFIG_SCSI_DC390T
-+
-+/* dtc3280 */
-+#undef CONFIG_SCSI_DTC3280
-+
-+/* eata */
-+#undef CONFIG_SCSI_EATA
-+
-+/* eatadma */
-+#undef CONFIG_SCSI_EATA_DMA
-+
-+/* eatapio */
-+#undef CONFIG_SCSI_EATA_PIO
-+
-+/* futuredomain */
-+#undef CONFIG_SCSI_FUTURE_DOMAIN
-+
-+/* gdth */
-+#undef CONFIG_SCSI_GDTH
-+
-+/* ncr5380 */
-+#undef CONFIG_SCSI_GENERIC_NCR5380
-+
-+/* in2000 */
-+#undef CONFIG_SCSI_IN2000
-+
-+/* ncr53c406a */
-+#undef CONFIG_SCSI_NCR53C406A
-+
-+/* ncr53c7xx */
-+#undef CONFIG_SCSI_NCR53C7xx
-+
-+/* ncr53c8xx */
-+#undef CONFIG_SCSI_NCR53C8XX
-+
-+/* scsi omit flashpoint */
-+#undef CONFIG_SCSI_OMIT_FLASHPOINT
-+
-+/* pas16 */
-+#undef CONFIG_SCSI_PASS16
-+
-+/* ppa */
-+#undef CONFIG_SCSI_PPA
-+
-+/* qlogicfas */
-+#undef CONFIG_SCSI_QLOGIC_FAS
-+
-+/* qlogicisp */
-+#undef CONFIG_SCSI_QLOGIC_ISP
-+
-+/* seagate */
-+#undef CONFIG_SCSI_SEAGATE
-+
-+/* t128 */
-+#undef CONFIG_SCSI_T128
-+
-+/* u1434f */
-+#undef CONFIG_SCSI_U14_34F
-+
-+/* ultrastor */
-+#undef CONFIG_SCSI_ULTRASTOR
-+
-+/* seeq8005 */
-+#undef CONFIG_SEEQ8005
-+
-+/* skg16 */
-+#undef CONFIG_SK_G16
-+
-+/* tlan */
-+#undef CONFIG_TLAN
-+
-+/* ul */
-+#undef CONFIG_ULTRA
-+
-+/* ul32 */
-+#undef CONFIG_ULTRA32
-+
-+/* viarhine */
-+#undef CONFIG_VIA_RHINE
-+
-+/* vortex */
-+#undef CONFIG_VORTEX
-+
-+/* wavelan */
-+#undef CONFIG_WAVELAN
-+
-+/* wd80x3 */
-+#undef CONFIG_WD80x3
-+
-+/* yellowfin */
-+#undef CONFIG_YELLOWFIN
-+
-+/* znet */
-+#undef CONFIG_ZNET
-+
-+/* CPU */
-+#undef CPU
-+
-+/* Define to the address where bug reports for this package should be sent. */
-+#undef PACKAGE_BUGREPORT
-+
-+/* Define to the full name of this package. */
-+#undef PACKAGE_NAME
-+
-+/* Define to the full name and version of this package. */
-+#undef PACKAGE_STRING
-+
-+/* Define to the one symbol short name of this package. */
-+#undef PACKAGE_TARNAME
-+
-+/* Define to the version of this package. */
-+#undef PACKAGE_VERSION