i825xx: Move the Intel 82586/82593/82596 based drivers
authorJeff Kirsher <jeffrey.t.kirsher@intel.com>
Wed, 13 Jul 2011 22:38:08 +0000 (15:38 -0700)
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>
Thu, 11 Aug 2011 03:04:12 +0000 (20:04 -0700)
Move the drivers that use the i82586/i82593/i82596 chipsets into
drivers/net/ethernet/i825xx/ and make the necessary Kconfig and
Makefile changes.  There were 4 3Com drivers which were initially
moved into 3com/, which now reside in i825xx since they all used
the i82586 chip.

CC: Philip Blundell <philb@gnu.org>
CC: Russell King <linux@arm.linux.org.uk>
CC: <aris@cathedrallabs.org>
CC: Donald Becker <becker@scyld.com>
CC: Chris Beauregard <cpbeaure@undergrad.math.uwaterloo.ca>
CC: Richard Procter <rnp@paradise.net.nz>
CC: Andries Brouwer <aeb@cwi.nl>
CC: "M.Hipp" <hippm@informatik.uni-tuebingen.de>
CC: Richard Hirst <richard@sleepie.demon.co.uk>
CC: Sam Creasey <sammy@oh.verio.com>
CC: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
53 files changed:
MAINTAINERS
drivers/net/3c505.c [deleted file]
drivers/net/3c505.h [deleted file]
drivers/net/3c507.c [deleted file]
drivers/net/3c523.c [deleted file]
drivers/net/3c523.h [deleted file]
drivers/net/3c527.c [deleted file]
drivers/net/3c527.h [deleted file]
drivers/net/82596.c [deleted file]
drivers/net/Kconfig
drivers/net/Makefile
drivers/net/arm/Kconfig
drivers/net/arm/Makefile
drivers/net/arm/ether1.c [deleted file]
drivers/net/arm/ether1.h [deleted file]
drivers/net/eepro.c [deleted file]
drivers/net/eexpress.c [deleted file]
drivers/net/eexpress.h [deleted file]
drivers/net/ethernet/Kconfig
drivers/net/ethernet/Makefile
drivers/net/ethernet/i825xx/3c505.c [new file with mode: 0644]
drivers/net/ethernet/i825xx/3c505.h [new file with mode: 0644]
drivers/net/ethernet/i825xx/3c507.c [new file with mode: 0644]
drivers/net/ethernet/i825xx/3c523.c [new file with mode: 0644]
drivers/net/ethernet/i825xx/3c523.h [new file with mode: 0644]
drivers/net/ethernet/i825xx/3c527.c [new file with mode: 0644]
drivers/net/ethernet/i825xx/3c527.h [new file with mode: 0644]
drivers/net/ethernet/i825xx/82596.c [new file with mode: 0644]
drivers/net/ethernet/i825xx/Kconfig [new file with mode: 0644]
drivers/net/ethernet/i825xx/Makefile [new file with mode: 0644]
drivers/net/ethernet/i825xx/eepro.c [new file with mode: 0644]
drivers/net/ethernet/i825xx/eexpress.c [new file with mode: 0644]
drivers/net/ethernet/i825xx/eexpress.h [new file with mode: 0644]
drivers/net/ethernet/i825xx/ether1.c [new file with mode: 0644]
drivers/net/ethernet/i825xx/ether1.h [new file with mode: 0644]
drivers/net/ethernet/i825xx/lasi_82596.c [new file with mode: 0644]
drivers/net/ethernet/i825xx/lib82596.c [new file with mode: 0644]
drivers/net/ethernet/i825xx/lp486e.c [new file with mode: 0644]
drivers/net/ethernet/i825xx/ni52.c [new file with mode: 0644]
drivers/net/ethernet/i825xx/ni52.h [new file with mode: 0644]
drivers/net/ethernet/i825xx/sni_82596.c [new file with mode: 0644]
drivers/net/ethernet/i825xx/sun3_82586.c [new file with mode: 0644]
drivers/net/ethernet/i825xx/sun3_82586.h [new file with mode: 0644]
drivers/net/ethernet/i825xx/znet.c [new file with mode: 0644]
drivers/net/lasi_82596.c [deleted file]
drivers/net/lib82596.c [deleted file]
drivers/net/lp486e.c [deleted file]
drivers/net/ni52.c [deleted file]
drivers/net/ni52.h [deleted file]
drivers/net/sni_82596.c [deleted file]
drivers/net/sun3_82586.c [deleted file]
drivers/net/sun3_82586.h [deleted file]
drivers/net/znet.c [deleted file]

index 7c0294cdf9f1e1f5ec4b493293d0b849ebf3c871..5b368ccf757284734a32a41c67dab0fcf71fcc7a 100644 (file)
@@ -117,7 +117,7 @@ Maintainers List (try to look for most precise areas first)
 M:     Philip Blundell <philb@gnu.org>
 L:     netdev@vger.kernel.org
 S:     Maintained
-F:     drivers/net/3c505*
+F:     drivers/net/ethernet/i825xx/3c505*
 
 3C59X NETWORK DRIVER
 M:     Steffen Klassert <klassert@mathematik.tu-chemnitz.de>
@@ -1014,7 +1014,7 @@ F:        arch/arm/include/asm/hardware/ioc.h
 F:     arch/arm/include/asm/hardware/iomd.h
 F:     arch/arm/include/asm/hardware/memc.h
 F:     arch/arm/mach-rpc/
-F:     drivers/net/arm/ether*
+F:     drivers/net/arm/ether3*
 F:     drivers/scsi/arm/
 
 ARM/SHARK MACHINE SUPPORT
@@ -2510,7 +2510,7 @@ ETHEREXPRESS-16 NETWORK DRIVER
 M:     Philip Blundell <philb@gnu.org>
 L:     netdev@vger.kernel.org
 S:     Maintained
-F:     drivers/net/eexpress.*
+F:     drivers/net/ethernet/i825xx/eexpress.*
 
 ETHERNET BRIDGE
 M:     Stephen Hemminger <shemminger@linux-foundation.org>
diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c
deleted file mode 100644 (file)
index 88d766e..0000000
+++ /dev/null
@@ -1,1673 +0,0 @@
-/*
- * Linux Ethernet device driver for the 3Com Etherlink Plus (3C505)
- *      By Craig Southeren, Juha Laiho and Philip Blundell
- *
- * 3c505.c      This module implements an interface to the 3Com
- *              Etherlink Plus (3c505) Ethernet card. Linux device
- *              driver interface reverse engineered from the Linux 3C509
- *              device drivers. Some 3C505 information gleaned from
- *              the Crynwr packet driver. Still this driver would not
- *              be here without 3C505 technical reference provided by
- *              3Com.
- *
- * $Id: 3c505.c,v 1.10 1996/04/16 13:06:27 phil Exp $
- *
- * Authors:     Linux 3c505 device driver by
- *                      Craig Southeren, <craigs@ineluki.apana.org.au>
- *              Final debugging by
- *                      Andrew Tridgell, <tridge@nimbus.anu.edu.au>
- *              Auto irq/address, tuning, cleanup and v1.1.4+ kernel mods by
- *                      Juha Laiho, <jlaiho@ichaos.nullnet.fi>
- *              Linux 3C509 driver by
- *                      Donald Becker, <becker@super.org>
- *                     (Now at <becker@scyld.com>)
- *              Crynwr packet driver by
- *                      Krishnan Gopalan and Gregg Stefancik,
- *                      Clemson University Engineering Computer Operations.
- *                      Portions of the code have been adapted from the 3c505
- *                         driver for NCSA Telnet by Bruce Orchard and later
- *                         modified by Warren Van Houten and krus@diku.dk.
- *              3C505 technical information provided by
- *                      Terry Murphy, of 3Com Network Adapter Division
- *              Linux 1.3.0 changes by
- *                      Alan Cox <Alan.Cox@linux.org>
- *              More debugging, DMA support, currently maintained by
- *                      Philip Blundell <philb@gnu.org>
- *              Multicard/soft configurable dma channel/rev 2 hardware support
- *                      by Christopher Collins <ccollins@pcug.org.au>
- *             Ethtool support (jgarzik), 11/17/2001
- */
-
-#define DRV_NAME       "3c505"
-#define DRV_VERSION    "1.10a"
-
-
-/* Theory of operation:
- *
- * The 3c505 is quite an intelligent board.  All communication with it is done
- * by means of Primary Command Blocks (PCBs); these are transferred using PIO
- * through the command register.  The card has 256k of on-board RAM, which is
- * used to buffer received packets.  It might seem at first that more buffers
- * are better, but in fact this isn't true.  From my tests, it seems that
- * more than about 10 buffers are unnecessary, and there is a noticeable
- * performance hit in having more active on the card.  So the majority of the
- * card's memory isn't, in fact, used.  Sadly, the card only has one transmit
- * buffer and, short of loading our own firmware into it (which is what some
- * drivers resort to) there's nothing we can do about this.
- *
- * We keep up to 4 "receive packet" commands active on the board at a time.
- * When a packet comes in, so long as there is a receive command active, the
- * board will send us a "packet received" PCB and then add the data for that
- * packet to the DMA queue.  If a DMA transfer is not already in progress, we
- * set one up to start uploading the data.  We have to maintain a list of
- * backlogged receive packets, because the card may decide to tell us about
- * a newly-arrived packet at any time, and we may not be able to start a DMA
- * transfer immediately (ie one may already be going on).  We can't NAK the
- * PCB, because then it would throw the packet away.
- *
- * Trying to send a PCB to the card at the wrong moment seems to have bad
- * effects.  If we send it a transmit PCB while a receive DMA is happening,
- * it will just NAK the PCB and so we will have wasted our time.  Worse, it
- * sometimes seems to interrupt the transfer.  The majority of the low-level
- * code is protected by one huge semaphore -- "busy" -- which is set whenever
- * it probably isn't safe to do anything to the card.  The receive routine
- * must gain a lock on "busy" before it can start a DMA transfer, and the
- * transmit routine must gain a lock before it sends the first PCB to the card.
- * The send_pcb() routine also has an internal semaphore to protect it against
- * being re-entered (which would be disastrous) -- this is needed because
- * several things can happen asynchronously (re-priming the receiver and
- * asking the card for statistics, for example).  send_pcb() will also refuse
- * to talk to the card at all if a DMA upload is happening.  The higher-level
- * networking code will reschedule a later retry if some part of the driver
- * is blocked.  In practice, this doesn't seem to happen very often.
- */
-
-/* This driver may now work with revision 2.x hardware, since all the read
- * operations on the HCR have been removed (we now keep our own softcopy).
- * But I don't have an old card to test it on.
- *
- * This has had the bad effect that the autoprobe routine is now a bit
- * less friendly to other devices.  However, it was never very good.
- * before, so I doubt it will hurt anybody.
- */
-
-/* The driver is a mess.  I took Craig's and Juha's code, and hacked it firstly
- * to make it more reliable, and secondly to add DMA mode.  Many things could
- * probably be done better; the concurrency protection is particularly awful.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/interrupt.h>
-#include <linux/errno.h>
-#include <linux/in.h>
-#include <linux/ioport.h>
-#include <linux/spinlock.h>
-#include <linux/ethtool.h>
-#include <linux/delay.h>
-#include <linux/bitops.h>
-#include <linux/gfp.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/init.h>
-
-#include "3c505.h"
-
-/*********************************************************
- *
- *  define debug messages here as common strings to reduce space
- *
- *********************************************************/
-
-#define filename __FILE__
-
-#define timeout_msg "*** timeout at %s:%s (line %d) ***\n"
-#define TIMEOUT_MSG(lineno) \
-       pr_notice(timeout_msg, filename, __func__, (lineno))
-
-#define invalid_pcb_msg "*** invalid pcb length %d at %s:%s (line %d) ***\n"
-#define INVALID_PCB_MSG(len) \
-       pr_notice(invalid_pcb_msg, (len), filename, __func__, __LINE__)
-
-#define search_msg "%s: Looking for 3c505 adapter at address %#x..."
-
-#define stilllooking_msg "still looking..."
-
-#define found_msg "found.\n"
-
-#define notfound_msg "not found (reason = %d)\n"
-
-#define couldnot_msg "%s: 3c505 not found\n"
-
-/*********************************************************
- *
- *  various other debug stuff
- *
- *********************************************************/
-
-#ifdef ELP_DEBUG
-static int elp_debug = ELP_DEBUG;
-#else
-static int elp_debug;
-#endif
-#define debug elp_debug
-
-/*
- *  0 = no messages (well, some)
- *  1 = messages when high level commands performed
- *  2 = messages when low level commands performed
- *  3 = messages when interrupts received
- */
-
-/*****************************************************************
- *
- * List of I/O-addresses we try to auto-sense
- * Last element MUST BE 0!
- *****************************************************************/
-
-static int addr_list[] __initdata = {0x300, 0x280, 0x310, 0};
-
-/* Dma Memory related stuff */
-
-static unsigned long dma_mem_alloc(int size)
-{
-       int order = get_order(size);
-       return __get_dma_pages(GFP_KERNEL, order);
-}
-
-
-/*****************************************************************
- *
- * Functions for I/O (note the inline !)
- *
- *****************************************************************/
-
-static inline unsigned char inb_status(unsigned int base_addr)
-{
-       return inb(base_addr + PORT_STATUS);
-}
-
-static inline int inb_command(unsigned int base_addr)
-{
-       return inb(base_addr + PORT_COMMAND);
-}
-
-static inline void outb_control(unsigned char val, struct net_device *dev)
-{
-       outb(val, dev->base_addr + PORT_CONTROL);
-       ((elp_device *)(netdev_priv(dev)))->hcr_val = val;
-}
-
-#define HCR_VAL(x)   (((elp_device *)(netdev_priv(x)))->hcr_val)
-
-static inline void outb_command(unsigned char val, unsigned int base_addr)
-{
-       outb(val, base_addr + PORT_COMMAND);
-}
-
-static inline unsigned int backlog_next(unsigned int n)
-{
-       return (n + 1) % BACKLOG_SIZE;
-}
-
-/*****************************************************************
- *
- *  useful functions for accessing the adapter
- *
- *****************************************************************/
-
-/*
- * use this routine when accessing the ASF bits as they are
- * changed asynchronously by the adapter
- */
-
-/* get adapter PCB status */
-#define        GET_ASF(addr) \
-       (get_status(addr)&ASF_PCB_MASK)
-
-static inline int get_status(unsigned int base_addr)
-{
-       unsigned long timeout = jiffies + 10*HZ/100;
-       register int stat1;
-       do {
-               stat1 = inb_status(base_addr);
-       } while (stat1 != inb_status(base_addr) && time_before(jiffies, timeout));
-       if (time_after_eq(jiffies, timeout))
-               TIMEOUT_MSG(__LINE__);
-       return stat1;
-}
-
-static inline void set_hsf(struct net_device *dev, int hsf)
-{
-       elp_device *adapter = netdev_priv(dev);
-       unsigned long flags;
-
-       spin_lock_irqsave(&adapter->lock, flags);
-       outb_control((HCR_VAL(dev) & ~HSF_PCB_MASK) | hsf, dev);
-       spin_unlock_irqrestore(&adapter->lock, flags);
-}
-
-static bool start_receive(struct net_device *, pcb_struct *);
-
-static inline void adapter_reset(struct net_device *dev)
-{
-       unsigned long timeout;
-       elp_device *adapter = netdev_priv(dev);
-       unsigned char orig_hcr = adapter->hcr_val;
-
-       outb_control(0, dev);
-
-       if (inb_status(dev->base_addr) & ACRF) {
-               do {
-                       inb_command(dev->base_addr);
-                       timeout = jiffies + 2*HZ/100;
-                       while (time_before_eq(jiffies, timeout) && !(inb_status(dev->base_addr) & ACRF));
-               } while (inb_status(dev->base_addr) & ACRF);
-               set_hsf(dev, HSF_PCB_NAK);
-       }
-       outb_control(adapter->hcr_val | ATTN | DIR, dev);
-       mdelay(10);
-       outb_control(adapter->hcr_val & ~ATTN, dev);
-       mdelay(10);
-       outb_control(adapter->hcr_val | FLSH, dev);
-       mdelay(10);
-       outb_control(adapter->hcr_val & ~FLSH, dev);
-       mdelay(10);
-
-       outb_control(orig_hcr, dev);
-       if (!start_receive(dev, &adapter->tx_pcb))
-               pr_err("%s: start receive command failed\n", dev->name);
-}
-
-/* Check to make sure that a DMA transfer hasn't timed out.  This should
- * never happen in theory, but seems to occur occasionally if the card gets
- * prodded at the wrong time.
- */
-static inline void check_3c505_dma(struct net_device *dev)
-{
-       elp_device *adapter = netdev_priv(dev);
-       if (adapter->dmaing && time_after(jiffies, adapter->current_dma.start_time + 10)) {
-               unsigned long flags, f;
-               pr_err("%s: DMA %s timed out, %d bytes left\n", dev->name,
-                       adapter->current_dma.direction ? "download" : "upload",
-                       get_dma_residue(dev->dma));
-               spin_lock_irqsave(&adapter->lock, flags);
-               adapter->dmaing = 0;
-               adapter->busy = 0;
-
-               f=claim_dma_lock();
-               disable_dma(dev->dma);
-               release_dma_lock(f);
-
-               if (adapter->rx_active)
-                       adapter->rx_active--;
-               outb_control(adapter->hcr_val & ~(DMAE | TCEN | DIR), dev);
-               spin_unlock_irqrestore(&adapter->lock, flags);
-       }
-}
-
-/* Primitive functions used by send_pcb() */
-static inline bool send_pcb_slow(unsigned int base_addr, unsigned char byte)
-{
-       unsigned long timeout;
-       outb_command(byte, base_addr);
-       for (timeout = jiffies + 5*HZ/100; time_before(jiffies, timeout);) {
-               if (inb_status(base_addr) & HCRE)
-                       return false;
-       }
-       pr_warning("3c505: send_pcb_slow timed out\n");
-       return true;
-}
-
-static inline bool send_pcb_fast(unsigned int base_addr, unsigned char byte)
-{
-       unsigned int timeout;
-       outb_command(byte, base_addr);
-       for (timeout = 0; timeout < 40000; timeout++) {
-               if (inb_status(base_addr) & HCRE)
-                       return false;
-       }
-       pr_warning("3c505: send_pcb_fast timed out\n");
-       return true;
-}
-
-/* Check to see if the receiver needs restarting, and kick it if so */
-static inline void prime_rx(struct net_device *dev)
-{
-       elp_device *adapter = netdev_priv(dev);
-       while (adapter->rx_active < ELP_RX_PCBS && netif_running(dev)) {
-               if (!start_receive(dev, &adapter->itx_pcb))
-                       break;
-       }
-}
-
-/*****************************************************************
- *
- * send_pcb
- *   Send a PCB to the adapter.
- *
- *     output byte to command reg  --<--+
- *     wait until HCRE is non zero      |
- *     loop until all bytes sent   -->--+
- *     set HSF1 and HSF2 to 1
- *     output pcb length
- *     wait until ASF give ACK or NAK
- *     set HSF1 and HSF2 to 0
- *
- *****************************************************************/
-
-/* This can be quite slow -- the adapter is allowed to take up to 40ms
- * to respond to the initial interrupt.
- *
- * We run initially with interrupts turned on, but with a semaphore set
- * so that nobody tries to re-enter this code.  Once the first byte has
- * gone through, we turn interrupts off and then send the others (the
- * timeout is reduced to 500us).
- */
-
-static bool send_pcb(struct net_device *dev, pcb_struct * pcb)
-{
-       int i;
-       unsigned long timeout;
-       elp_device *adapter = netdev_priv(dev);
-       unsigned long flags;
-
-       check_3c505_dma(dev);
-
-       if (adapter->dmaing && adapter->current_dma.direction == 0)
-               return false;
-
-       /* Avoid contention */
-       if (test_and_set_bit(1, &adapter->send_pcb_semaphore)) {
-               if (elp_debug >= 3) {
-                       pr_debug("%s: send_pcb entered while threaded\n", dev->name);
-               }
-               return false;
-       }
-       /*
-        * load each byte into the command register and
-        * wait for the HCRE bit to indicate the adapter
-        * had read the byte
-        */
-       set_hsf(dev, 0);
-
-       if (send_pcb_slow(dev->base_addr, pcb->command))
-               goto abort;
-
-       spin_lock_irqsave(&adapter->lock, flags);
-
-       if (send_pcb_fast(dev->base_addr, pcb->length))
-               goto sti_abort;
-
-       for (i = 0; i < pcb->length; i++) {
-               if (send_pcb_fast(dev->base_addr, pcb->data.raw[i]))
-                       goto sti_abort;
-       }
-
-       outb_control(adapter->hcr_val | 3, dev);        /* signal end of PCB */
-       outb_command(2 + pcb->length, dev->base_addr);
-
-       /* now wait for the acknowledgement */
-       spin_unlock_irqrestore(&adapter->lock, flags);
-
-       for (timeout = jiffies + 5*HZ/100; time_before(jiffies, timeout);) {
-               switch (GET_ASF(dev->base_addr)) {
-               case ASF_PCB_ACK:
-                       adapter->send_pcb_semaphore = 0;
-                       return true;
-
-               case ASF_PCB_NAK:
-#ifdef ELP_DEBUG
-                       pr_debug("%s: send_pcb got NAK\n", dev->name);
-#endif
-                       goto abort;
-               }
-       }
-
-       if (elp_debug >= 1)
-               pr_debug("%s: timeout waiting for PCB acknowledge (status %02x)\n",
-                       dev->name, inb_status(dev->base_addr));
-       goto abort;
-
-      sti_abort:
-       spin_unlock_irqrestore(&adapter->lock, flags);
-      abort:
-       adapter->send_pcb_semaphore = 0;
-       return false;
-}
-
-
-/*****************************************************************
- *
- * receive_pcb
- *   Read a PCB from the adapter
- *
- *     wait for ACRF to be non-zero        ---<---+
- *     input a byte                               |
- *     if ASF1 and ASF2 were not both one         |
- *             before byte was read, loop      --->---+
- *     set HSF1 and HSF2 for ack
- *
- *****************************************************************/
-
-static bool receive_pcb(struct net_device *dev, pcb_struct * pcb)
-{
-       int i, j;
-       int total_length;
-       int stat;
-       unsigned long timeout;
-       unsigned long flags;
-
-       elp_device *adapter = netdev_priv(dev);
-
-       set_hsf(dev, 0);
-
-       /* get the command code */
-       timeout = jiffies + 2*HZ/100;
-       while (((stat = get_status(dev->base_addr)) & ACRF) == 0 && time_before(jiffies, timeout));
-       if (time_after_eq(jiffies, timeout)) {
-               TIMEOUT_MSG(__LINE__);
-               return false;
-       }
-       pcb->command = inb_command(dev->base_addr);
-
-       /* read the data length */
-       timeout = jiffies + 3*HZ/100;
-       while (((stat = get_status(dev->base_addr)) & ACRF) == 0 && time_before(jiffies, timeout));
-       if (time_after_eq(jiffies, timeout)) {
-               TIMEOUT_MSG(__LINE__);
-               pr_info("%s: status %02x\n", dev->name, stat);
-               return false;
-       }
-       pcb->length = inb_command(dev->base_addr);
-
-       if (pcb->length > MAX_PCB_DATA) {
-               INVALID_PCB_MSG(pcb->length);
-               adapter_reset(dev);
-               return false;
-       }
-       /* read the data */
-       spin_lock_irqsave(&adapter->lock, flags);
-       for (i = 0; i < MAX_PCB_DATA; i++) {
-               for (j = 0; j < 20000; j++) {
-                       stat = get_status(dev->base_addr);
-                       if (stat & ACRF)
-                               break;
-               }
-               pcb->data.raw[i] = inb_command(dev->base_addr);
-               if ((stat & ASF_PCB_MASK) == ASF_PCB_END || j >= 20000)
-                       break;
-       }
-       spin_unlock_irqrestore(&adapter->lock, flags);
-       if (i >= MAX_PCB_DATA) {
-               INVALID_PCB_MSG(i);
-               return false;
-       }
-       if (j >= 20000) {
-               TIMEOUT_MSG(__LINE__);
-               return false;
-       }
-       /* the last "data" byte was really the length! */
-       total_length = pcb->data.raw[i];
-
-       /* safety check total length vs data length */
-       if (total_length != (pcb->length + 2)) {
-               if (elp_debug >= 2)
-                       pr_warning("%s: mangled PCB received\n", dev->name);
-               set_hsf(dev, HSF_PCB_NAK);
-               return false;
-       }
-
-       if (pcb->command == CMD_RECEIVE_PACKET_COMPLETE) {
-               if (test_and_set_bit(0, (void *) &adapter->busy)) {
-                       if (backlog_next(adapter->rx_backlog.in) == adapter->rx_backlog.out) {
-                               set_hsf(dev, HSF_PCB_NAK);
-                               pr_warning("%s: PCB rejected, transfer in progress and backlog full\n", dev->name);
-                               pcb->command = 0;
-                               return true;
-                       } else {
-                               pcb->command = 0xff;
-                       }
-               }
-       }
-       set_hsf(dev, HSF_PCB_ACK);
-       return true;
-}
-
-/******************************************************
- *
- *  queue a receive command on the adapter so we will get an
- *  interrupt when a packet is received.
- *
- ******************************************************/
-
-static bool start_receive(struct net_device *dev, pcb_struct * tx_pcb)
-{
-       bool status;
-       elp_device *adapter = netdev_priv(dev);
-
-       if (elp_debug >= 3)
-               pr_debug("%s: restarting receiver\n", dev->name);
-       tx_pcb->command = CMD_RECEIVE_PACKET;
-       tx_pcb->length = sizeof(struct Rcv_pkt);
-       tx_pcb->data.rcv_pkt.buf_seg
-           = tx_pcb->data.rcv_pkt.buf_ofs = 0;         /* Unused */
-       tx_pcb->data.rcv_pkt.buf_len = 1600;
-       tx_pcb->data.rcv_pkt.timeout = 0;       /* set timeout to zero */
-       status = send_pcb(dev, tx_pcb);
-       if (status)
-               adapter->rx_active++;
-       return status;
-}
-
-/******************************************************
- *
- * extract a packet from the adapter
- * this routine is only called from within the interrupt
- * service routine, so no cli/sti calls are needed
- * note that the length is always assumed to be even
- *
- ******************************************************/
-
-static void receive_packet(struct net_device *dev, int len)
-{
-       int rlen;
-       elp_device *adapter = netdev_priv(dev);
-       void *target;
-       struct sk_buff *skb;
-       unsigned long flags;
-
-       rlen = (len + 1) & ~1;
-       skb = dev_alloc_skb(rlen + 2);
-
-       if (!skb) {
-               pr_warning("%s: memory squeeze, dropping packet\n", dev->name);
-               target = adapter->dma_buffer;
-               adapter->current_dma.target = NULL;
-               /* FIXME: stats */
-               return;
-       }
-
-       skb_reserve(skb, 2);
-       target = skb_put(skb, rlen);
-       if ((unsigned long)(target + rlen) >= MAX_DMA_ADDRESS) {
-               adapter->current_dma.target = target;
-               target = adapter->dma_buffer;
-       } else {
-               adapter->current_dma.target = NULL;
-       }
-
-       /* if this happens, we die */
-       if (test_and_set_bit(0, (void *) &adapter->dmaing))
-               pr_err("%s: rx blocked, DMA in progress, dir %d\n",
-                       dev->name, adapter->current_dma.direction);
-
-       adapter->current_dma.direction = 0;
-       adapter->current_dma.length = rlen;
-       adapter->current_dma.skb = skb;
-       adapter->current_dma.start_time = jiffies;
-
-       outb_control(adapter->hcr_val | DIR | TCEN | DMAE, dev);
-
-       flags=claim_dma_lock();
-       disable_dma(dev->dma);
-       clear_dma_ff(dev->dma);
-       set_dma_mode(dev->dma, 0x04);   /* dma read */
-       set_dma_addr(dev->dma, isa_virt_to_bus(target));
-       set_dma_count(dev->dma, rlen);
-       enable_dma(dev->dma);
-       release_dma_lock(flags);
-
-       if (elp_debug >= 3) {
-               pr_debug("%s: rx DMA transfer started\n", dev->name);
-       }
-
-       if (adapter->rx_active)
-               adapter->rx_active--;
-
-       if (!adapter->busy)
-               pr_warning("%s: receive_packet called, busy not set.\n", dev->name);
-}
-
-/******************************************************
- *
- * interrupt handler
- *
- ******************************************************/
-
-static irqreturn_t elp_interrupt(int irq, void *dev_id)
-{
-       int len;
-       int dlen;
-       int icount = 0;
-       struct net_device *dev = dev_id;
-       elp_device *adapter = netdev_priv(dev);
-       unsigned long timeout;
-
-       spin_lock(&adapter->lock);
-
-       do {
-               /*
-                * has a DMA transfer finished?
-                */
-               if (inb_status(dev->base_addr) & DONE) {
-                       if (!adapter->dmaing)
-                               pr_warning("%s: phantom DMA completed\n", dev->name);
-
-                       if (elp_debug >= 3)
-                               pr_debug("%s: %s DMA complete, status %02x\n", dev->name,
-                                       adapter->current_dma.direction ? "tx" : "rx",
-                                       inb_status(dev->base_addr));
-
-                       outb_control(adapter->hcr_val & ~(DMAE | TCEN | DIR), dev);
-                       if (adapter->current_dma.direction) {
-                               dev_kfree_skb_irq(adapter->current_dma.skb);
-                       } else {
-                               struct sk_buff *skb = adapter->current_dma.skb;
-                               if (skb) {
-                                       if (adapter->current_dma.target) {
-                                       /* have already done the skb_put() */
-                                       memcpy(adapter->current_dma.target, adapter->dma_buffer, adapter->current_dma.length);
-                                       }
-                                       skb->protocol = eth_type_trans(skb,dev);
-                                       dev->stats.rx_bytes += skb->len;
-                                       netif_rx(skb);
-                               }
-                       }
-                       adapter->dmaing = 0;
-                       if (adapter->rx_backlog.in != adapter->rx_backlog.out) {
-                               int t = adapter->rx_backlog.length[adapter->rx_backlog.out];
-                               adapter->rx_backlog.out = backlog_next(adapter->rx_backlog.out);
-                               if (elp_debug >= 2)
-                                       pr_debug("%s: receiving backlogged packet (%d)\n", dev->name, t);
-                               receive_packet(dev, t);
-                       } else {
-                               adapter->busy = 0;
-                       }
-               } else {
-                       /* has one timed out? */
-                       check_3c505_dma(dev);
-               }
-
-               /*
-                * receive a PCB from the adapter
-                */
-               timeout = jiffies + 3*HZ/100;
-               while ((inb_status(dev->base_addr) & ACRF) != 0 && time_before(jiffies, timeout)) {
-                       if (receive_pcb(dev, &adapter->irx_pcb)) {
-                               switch (adapter->irx_pcb.command)
-                               {
-                               case 0:
-                                       break;
-                                       /*
-                                        * received a packet - this must be handled fast
-                                        */
-                               case 0xff:
-                               case CMD_RECEIVE_PACKET_COMPLETE:
-                                       /* if the device isn't open, don't pass packets up the stack */
-                                       if (!netif_running(dev))
-                                               break;
-                                       len = adapter->irx_pcb.data.rcv_resp.pkt_len;
-                                       dlen = adapter->irx_pcb.data.rcv_resp.buf_len;
-                                       if (adapter->irx_pcb.data.rcv_resp.timeout != 0) {
-                                               pr_err("%s: interrupt - packet not received correctly\n", dev->name);
-                                       } else {
-                                               if (elp_debug >= 3) {
-                                                       pr_debug("%s: interrupt - packet received of length %i (%i)\n",
-                                                               dev->name, len, dlen);
-                                               }
-                                               if (adapter->irx_pcb.command == 0xff) {
-                                                       if (elp_debug >= 2)
-                                                               pr_debug("%s: adding packet to backlog (len = %d)\n",
-                                                                       dev->name, dlen);
-                                                       adapter->rx_backlog.length[adapter->rx_backlog.in] = dlen;
-                                                       adapter->rx_backlog.in = backlog_next(adapter->rx_backlog.in);
-                                               } else {
-                                                       receive_packet(dev, dlen);
-                                               }
-                                               if (elp_debug >= 3)
-                                                       pr_debug("%s: packet received\n", dev->name);
-                                       }
-                                       break;
-
-                                       /*
-                                        * 82586 configured correctly
-                                        */
-                               case CMD_CONFIGURE_82586_RESPONSE:
-                                       adapter->got[CMD_CONFIGURE_82586] = 1;
-                                       if (elp_debug >= 3)
-                                               pr_debug("%s: interrupt - configure response received\n", dev->name);
-                                       break;
-
-                                       /*
-                                        * Adapter memory configuration
-                                        */
-                               case CMD_CONFIGURE_ADAPTER_RESPONSE:
-                                       adapter->got[CMD_CONFIGURE_ADAPTER_MEMORY] = 1;
-                                       if (elp_debug >= 3)
-                                               pr_debug("%s: Adapter memory configuration %s.\n", dev->name,
-                                                      adapter->irx_pcb.data.failed ? "failed" : "succeeded");
-                                       break;
-
-                                       /*
-                                        * Multicast list loading
-                                        */
-                               case CMD_LOAD_MULTICAST_RESPONSE:
-                                       adapter->got[CMD_LOAD_MULTICAST_LIST] = 1;
-                                       if (elp_debug >= 3)
-                                               pr_debug("%s: Multicast address list loading %s.\n", dev->name,
-                                                      adapter->irx_pcb.data.failed ? "failed" : "succeeded");
-                                       break;
-
-                                       /*
-                                        * Station address setting
-                                        */
-                               case CMD_SET_ADDRESS_RESPONSE:
-                                       adapter->got[CMD_SET_STATION_ADDRESS] = 1;
-                                       if (elp_debug >= 3)
-                                               pr_debug("%s: Ethernet address setting %s.\n", dev->name,
-                                                      adapter->irx_pcb.data.failed ? "failed" : "succeeded");
-                                       break;
-
-
-                                       /*
-                                        * received board statistics
-                                        */
-                               case CMD_NETWORK_STATISTICS_RESPONSE:
-                                       dev->stats.rx_packets += adapter->irx_pcb.data.netstat.tot_recv;
-                                       dev->stats.tx_packets += adapter->irx_pcb.data.netstat.tot_xmit;
-                                       dev->stats.rx_crc_errors += adapter->irx_pcb.data.netstat.err_CRC;
-                                       dev->stats.rx_frame_errors += adapter->irx_pcb.data.netstat.err_align;
-                                       dev->stats.rx_fifo_errors += adapter->irx_pcb.data.netstat.err_ovrrun;
-                                       dev->stats.rx_over_errors += adapter->irx_pcb.data.netstat.err_res;
-                                       adapter->got[CMD_NETWORK_STATISTICS] = 1;
-                                       if (elp_debug >= 3)
-                                               pr_debug("%s: interrupt - statistics response received\n", dev->name);
-                                       break;
-
-                                       /*
-                                        * sent a packet
-                                        */
-                               case CMD_TRANSMIT_PACKET_COMPLETE:
-                                       if (elp_debug >= 3)
-                                               pr_debug("%s: interrupt - packet sent\n", dev->name);
-                                       if (!netif_running(dev))
-                                               break;
-                                       switch (adapter->irx_pcb.data.xmit_resp.c_stat) {
-                                       case 0xffff:
-                                               dev->stats.tx_aborted_errors++;
-                                               pr_info("%s: transmit timed out, network cable problem?\n", dev->name);
-                                               break;
-                                       case 0xfffe:
-                                               dev->stats.tx_fifo_errors++;
-                                               pr_info("%s: transmit timed out, FIFO underrun\n", dev->name);
-                                               break;
-                                       }
-                                       netif_wake_queue(dev);
-                                       break;
-
-                                       /*
-                                        * some unknown PCB
-                                        */
-                               default:
-                                       pr_debug("%s: unknown PCB received - %2.2x\n",
-                                               dev->name, adapter->irx_pcb.command);
-                                       break;
-                               }
-                       } else {
-                               pr_warning("%s: failed to read PCB on interrupt\n", dev->name);
-                               adapter_reset(dev);
-                       }
-               }
-
-       } while (icount++ < 5 && (inb_status(dev->base_addr) & (ACRF | DONE)));
-
-       prime_rx(dev);
-
-       /*
-        * indicate no longer in interrupt routine
-        */
-       spin_unlock(&adapter->lock);
-       return IRQ_HANDLED;
-}
-
-
-/******************************************************
- *
- * open the board
- *
- ******************************************************/
-
-static int elp_open(struct net_device *dev)
-{
-       elp_device *adapter = netdev_priv(dev);
-       int retval;
-
-       if (elp_debug >= 3)
-               pr_debug("%s: request to open device\n", dev->name);
-
-       /*
-        * make sure we actually found the device
-        */
-       if (adapter == NULL) {
-               pr_err("%s: Opening a non-existent physical device\n", dev->name);
-               return -EAGAIN;
-       }
-       /*
-        * disable interrupts on the board
-        */
-       outb_control(0, dev);
-
-       /*
-        * clear any pending interrupts
-        */
-       inb_command(dev->base_addr);
-       adapter_reset(dev);
-
-       /*
-        * no receive PCBs active
-        */
-       adapter->rx_active = 0;
-
-       adapter->busy = 0;
-       adapter->send_pcb_semaphore = 0;
-       adapter->rx_backlog.in = 0;
-       adapter->rx_backlog.out = 0;
-
-       spin_lock_init(&adapter->lock);
-
-       /*
-        * install our interrupt service routine
-        */
-       if ((retval = request_irq(dev->irq, elp_interrupt, 0, dev->name, dev))) {
-               pr_err("%s: could not allocate IRQ%d\n", dev->name, dev->irq);
-               return retval;
-       }
-       if ((retval = request_dma(dev->dma, dev->name))) {
-               free_irq(dev->irq, dev);
-               pr_err("%s: could not allocate DMA%d channel\n", dev->name, dev->dma);
-               return retval;
-       }
-       adapter->dma_buffer = (void *) dma_mem_alloc(DMA_BUFFER_SIZE);
-       if (!adapter->dma_buffer) {
-               pr_err("%s: could not allocate DMA buffer\n", dev->name);
-               free_dma(dev->dma);
-               free_irq(dev->irq, dev);
-               return -ENOMEM;
-       }
-       adapter->dmaing = 0;
-
-       /*
-        * enable interrupts on the board
-        */
-       outb_control(CMDE, dev);
-
-       /*
-        * configure adapter memory: we need 10 multicast addresses, default==0
-        */
-       if (elp_debug >= 3)
-               pr_debug("%s: sending 3c505 memory configuration command\n", dev->name);
-       adapter->tx_pcb.command = CMD_CONFIGURE_ADAPTER_MEMORY;
-       adapter->tx_pcb.data.memconf.cmd_q = 10;
-       adapter->tx_pcb.data.memconf.rcv_q = 20;
-       adapter->tx_pcb.data.memconf.mcast = 10;
-       adapter->tx_pcb.data.memconf.frame = 20;
-       adapter->tx_pcb.data.memconf.rcv_b = 20;
-       adapter->tx_pcb.data.memconf.progs = 0;
-       adapter->tx_pcb.length = sizeof(struct Memconf);
-       adapter->got[CMD_CONFIGURE_ADAPTER_MEMORY] = 0;
-       if (!send_pcb(dev, &adapter->tx_pcb))
-               pr_err("%s: couldn't send memory configuration command\n", dev->name);
-       else {
-               unsigned long timeout = jiffies + TIMEOUT;
-               while (adapter->got[CMD_CONFIGURE_ADAPTER_MEMORY] == 0 && time_before(jiffies, timeout));
-               if (time_after_eq(jiffies, timeout))
-                       TIMEOUT_MSG(__LINE__);
-       }
-
-
-       /*
-        * configure adapter to receive broadcast messages and wait for response
-        */
-       if (elp_debug >= 3)
-               pr_debug("%s: sending 82586 configure command\n", dev->name);
-       adapter->tx_pcb.command = CMD_CONFIGURE_82586;
-       adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_BROAD;
-       adapter->tx_pcb.length = 2;
-       adapter->got[CMD_CONFIGURE_82586] = 0;
-       if (!send_pcb(dev, &adapter->tx_pcb))
-               pr_err("%s: couldn't send 82586 configure command\n", dev->name);
-       else {
-               unsigned long timeout = jiffies + TIMEOUT;
-               while (adapter->got[CMD_CONFIGURE_82586] == 0 && time_before(jiffies, timeout));
-               if (time_after_eq(jiffies, timeout))
-                       TIMEOUT_MSG(__LINE__);
-       }
-
-       /* enable burst-mode DMA */
-       /* outb(0x1, dev->base_addr + PORT_AUXDMA); */
-
-       /*
-        * queue receive commands to provide buffering
-        */
-       prime_rx(dev);
-       if (elp_debug >= 3)
-               pr_debug("%s: %d receive PCBs active\n", dev->name, adapter->rx_active);
-
-       /*
-        * device is now officially open!
-        */
-
-       netif_start_queue(dev);
-       return 0;
-}
-
-
-/******************************************************
- *
- * send a packet to the adapter
- *
- ******************************************************/
-
-static netdev_tx_t send_packet(struct net_device *dev, struct sk_buff *skb)
-{
-       elp_device *adapter = netdev_priv(dev);
-       unsigned long target;
-       unsigned long flags;
-
-       /*
-        * make sure the length is even and no shorter than 60 bytes
-        */
-       unsigned int nlen = (((skb->len < 60) ? 60 : skb->len) + 1) & (~1);
-
-       if (test_and_set_bit(0, (void *) &adapter->busy)) {
-               if (elp_debug >= 2)
-                       pr_debug("%s: transmit blocked\n", dev->name);
-               return false;
-       }
-
-       dev->stats.tx_bytes += nlen;
-
-       /*
-        * send the adapter a transmit packet command. Ignore segment and offset
-        * and make sure the length is even
-        */
-       adapter->tx_pcb.command = CMD_TRANSMIT_PACKET;
-       adapter->tx_pcb.length = sizeof(struct Xmit_pkt);
-       adapter->tx_pcb.data.xmit_pkt.buf_ofs
-           = adapter->tx_pcb.data.xmit_pkt.buf_seg = 0;        /* Unused */
-       adapter->tx_pcb.data.xmit_pkt.pkt_len = nlen;
-
-       if (!send_pcb(dev, &adapter->tx_pcb)) {
-               adapter->busy = 0;
-               return false;
-       }
-       /* if this happens, we die */
-       if (test_and_set_bit(0, (void *) &adapter->dmaing))
-               pr_debug("%s: tx: DMA %d in progress\n", dev->name, adapter->current_dma.direction);
-
-       adapter->current_dma.direction = 1;
-       adapter->current_dma.start_time = jiffies;
-
-       if ((unsigned long)(skb->data + nlen) >= MAX_DMA_ADDRESS || nlen != skb->len) {
-               skb_copy_from_linear_data(skb, adapter->dma_buffer, nlen);
-               memset(adapter->dma_buffer+skb->len, 0, nlen-skb->len);
-               target = isa_virt_to_bus(adapter->dma_buffer);
-       }
-       else {
-               target = isa_virt_to_bus(skb->data);
-       }
-       adapter->current_dma.skb = skb;
-
-       flags=claim_dma_lock();
-       disable_dma(dev->dma);
-       clear_dma_ff(dev->dma);
-       set_dma_mode(dev->dma, 0x48);   /* dma memory -> io */
-       set_dma_addr(dev->dma, target);
-       set_dma_count(dev->dma, nlen);
-       outb_control(adapter->hcr_val | DMAE | TCEN, dev);
-       enable_dma(dev->dma);
-       release_dma_lock(flags);
-
-       if (elp_debug >= 3)
-               pr_debug("%s: DMA transfer started\n", dev->name);
-
-       return true;
-}
-
-/*
- *     The upper layer thinks we timed out
- */
-
-static void elp_timeout(struct net_device *dev)
-{
-       int stat;
-
-       stat = inb_status(dev->base_addr);
-       pr_warning("%s: transmit timed out, lost %s?\n", dev->name,
-                  (stat & ACRF) ? "interrupt" : "command");
-       if (elp_debug >= 1)
-               pr_debug("%s: status %#02x\n", dev->name, stat);
-       dev->trans_start = jiffies; /* prevent tx timeout */
-       dev->stats.tx_dropped++;
-       netif_wake_queue(dev);
-}
-
-/******************************************************
- *
- * start the transmitter
- *    return 0 if sent OK, else return 1
- *
- ******************************************************/
-
-static netdev_tx_t elp_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-       unsigned long flags;
-       elp_device *adapter = netdev_priv(dev);
-
-       spin_lock_irqsave(&adapter->lock, flags);
-       check_3c505_dma(dev);
-
-       if (elp_debug >= 3)
-               pr_debug("%s: request to send packet of length %d\n", dev->name, (int) skb->len);
-
-       netif_stop_queue(dev);
-
-       /*
-        * send the packet at skb->data for skb->len
-        */
-       if (!send_packet(dev, skb)) {
-               if (elp_debug >= 2) {
-                       pr_debug("%s: failed to transmit packet\n", dev->name);
-               }
-               spin_unlock_irqrestore(&adapter->lock, flags);
-               return NETDEV_TX_BUSY;
-       }
-       if (elp_debug >= 3)
-               pr_debug("%s: packet of length %d sent\n", dev->name, (int) skb->len);
-
-       prime_rx(dev);
-       spin_unlock_irqrestore(&adapter->lock, flags);
-       netif_start_queue(dev);
-       return NETDEV_TX_OK;
-}
-
-/******************************************************
- *
- * return statistics on the board
- *
- ******************************************************/
-
-static struct net_device_stats *elp_get_stats(struct net_device *dev)
-{
-       elp_device *adapter = netdev_priv(dev);
-
-       if (elp_debug >= 3)
-               pr_debug("%s: request for stats\n", dev->name);
-
-       /* If the device is closed, just return the latest stats we have,
-          - we cannot ask from the adapter without interrupts */
-       if (!netif_running(dev))
-               return &dev->stats;
-
-       /* send a get statistics command to the board */
-       adapter->tx_pcb.command = CMD_NETWORK_STATISTICS;
-       adapter->tx_pcb.length = 0;
-       adapter->got[CMD_NETWORK_STATISTICS] = 0;
-       if (!send_pcb(dev, &adapter->tx_pcb))
-               pr_err("%s: couldn't send get statistics command\n", dev->name);
-       else {
-               unsigned long timeout = jiffies + TIMEOUT;
-               while (adapter->got[CMD_NETWORK_STATISTICS] == 0 && time_before(jiffies, timeout));
-               if (time_after_eq(jiffies, timeout)) {
-                       TIMEOUT_MSG(__LINE__);
-                       return &dev->stats;
-               }
-       }
-
-       /* statistics are now up to date */
-       return &dev->stats;
-}
-
-
-static void netdev_get_drvinfo(struct net_device *dev,
-                              struct ethtool_drvinfo *info)
-{
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       sprintf(info->bus_info, "ISA 0x%lx", dev->base_addr);
-}
-
-static u32 netdev_get_msglevel(struct net_device *dev)
-{
-       return debug;
-}
-
-static void netdev_set_msglevel(struct net_device *dev, u32 level)
-{
-       debug = level;
-}
-
-static const struct ethtool_ops netdev_ethtool_ops = {
-       .get_drvinfo            = netdev_get_drvinfo,
-       .get_msglevel           = netdev_get_msglevel,
-       .set_msglevel           = netdev_set_msglevel,
-};
-
-/******************************************************
- *
- * close the board
- *
- ******************************************************/
-
-static int elp_close(struct net_device *dev)
-{
-       elp_device *adapter = netdev_priv(dev);
-
-       if (elp_debug >= 3)
-               pr_debug("%s: request to close device\n", dev->name);
-
-       netif_stop_queue(dev);
-
-       /* Someone may request the device statistic information even when
-        * the interface is closed. The following will update the statistics
-        * structure in the driver, so we'll be able to give current statistics.
-        */
-       (void) elp_get_stats(dev);
-
-       /*
-        * disable interrupts on the board
-        */
-       outb_control(0, dev);
-
-       /*
-        * release the IRQ
-        */
-       free_irq(dev->irq, dev);
-
-       free_dma(dev->dma);
-       free_pages((unsigned long) adapter->dma_buffer, get_order(DMA_BUFFER_SIZE));
-
-       return 0;
-}
-
-
-/************************************************************
- *
- * Set multicast list
- * num_addrs==0: clear mc_list
- * num_addrs==-1: set promiscuous mode
- * num_addrs>0: set mc_list
- *
- ************************************************************/
-
-static void elp_set_mc_list(struct net_device *dev)
-{
-       elp_device *adapter = netdev_priv(dev);
-       struct netdev_hw_addr *ha;
-       int i;
-       unsigned long flags;
-
-       if (elp_debug >= 3)
-               pr_debug("%s: request to set multicast list\n", dev->name);
-
-       spin_lock_irqsave(&adapter->lock, flags);
-
-       if (!(dev->flags & (IFF_PROMISC | IFF_ALLMULTI))) {
-               /* send a "load multicast list" command to the board, max 10 addrs/cmd */
-               /* if num_addrs==0 the list will be cleared */
-               adapter->tx_pcb.command = CMD_LOAD_MULTICAST_LIST;
-               adapter->tx_pcb.length = 6 * netdev_mc_count(dev);
-               i = 0;
-               netdev_for_each_mc_addr(ha, dev)
-                       memcpy(adapter->tx_pcb.data.multicast[i++],
-                              ha->addr, 6);
-               adapter->got[CMD_LOAD_MULTICAST_LIST] = 0;
-               if (!send_pcb(dev, &adapter->tx_pcb))
-                       pr_err("%s: couldn't send set_multicast command\n", dev->name);
-               else {
-                       unsigned long timeout = jiffies + TIMEOUT;
-                       while (adapter->got[CMD_LOAD_MULTICAST_LIST] == 0 && time_before(jiffies, timeout));
-                       if (time_after_eq(jiffies, timeout)) {
-                               TIMEOUT_MSG(__LINE__);
-                       }
-               }
-               if (!netdev_mc_empty(dev))
-                       adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_BROAD | RECV_MULTI;
-               else            /* num_addrs == 0 */
-                       adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_BROAD;
-       } else
-               adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_PROMISC;
-       /*
-        * configure adapter to receive messages (as specified above)
-        * and wait for response
-        */
-       if (elp_debug >= 3)
-               pr_debug("%s: sending 82586 configure command\n", dev->name);
-       adapter->tx_pcb.command = CMD_CONFIGURE_82586;
-       adapter->tx_pcb.length = 2;
-       adapter->got[CMD_CONFIGURE_82586] = 0;
-       if (!send_pcb(dev, &adapter->tx_pcb))
-       {
-               spin_unlock_irqrestore(&adapter->lock, flags);
-               pr_err("%s: couldn't send 82586 configure command\n", dev->name);
-       }
-       else {
-               unsigned long timeout = jiffies + TIMEOUT;
-               spin_unlock_irqrestore(&adapter->lock, flags);
-               while (adapter->got[CMD_CONFIGURE_82586] == 0 && time_before(jiffies, timeout));
-               if (time_after_eq(jiffies, timeout))
-                       TIMEOUT_MSG(__LINE__);
-       }
-}
-
-/************************************************************
- *
- * A couple of tests to see if there's 3C505 or not
- * Called only by elp_autodetect
- ************************************************************/
-
-static int __init elp_sense(struct net_device *dev)
-{
-       int addr = dev->base_addr;
-       const char *name = dev->name;
-       byte orig_HSR;
-
-       if (!request_region(addr, ELP_IO_EXTENT, "3c505"))
-               return -ENODEV;
-
-       orig_HSR = inb_status(addr);
-
-       if (elp_debug > 0)
-               pr_debug(search_msg, name, addr);
-
-       if (orig_HSR == 0xff) {
-               if (elp_debug > 0)
-                       pr_cont(notfound_msg, 1);
-               goto out;
-       }
-
-       /* Wait for a while; the adapter may still be booting up */
-       if (elp_debug > 0)
-               pr_cont(stilllooking_msg);
-
-       if (orig_HSR & DIR) {
-               /* If HCR.DIR is up, we pull it down. HSR.DIR should follow. */
-               outb(0, dev->base_addr + PORT_CONTROL);
-               msleep(300);
-               if (inb_status(addr) & DIR) {
-                       if (elp_debug > 0)
-                               pr_cont(notfound_msg, 2);
-                       goto out;
-               }
-       } else {
-               /* If HCR.DIR is down, we pull it up. HSR.DIR should follow. */
-               outb(DIR, dev->base_addr + PORT_CONTROL);
-               msleep(300);
-               if (!(inb_status(addr) & DIR)) {
-                       if (elp_debug > 0)
-                               pr_cont(notfound_msg, 3);
-                       goto out;
-               }
-       }
-       /*
-        * It certainly looks like a 3c505.
-        */
-       if (elp_debug > 0)
-               pr_cont(found_msg);
-
-       return 0;
-out:
-       release_region(addr, ELP_IO_EXTENT);
-       return -ENODEV;
-}
-
-/*************************************************************
- *
- * Search through addr_list[] and try to find a 3C505
- * Called only by eplus_probe
- *************************************************************/
-
-static int __init elp_autodetect(struct net_device *dev)
-{
-       int idx = 0;
-
-       /* if base address set, then only check that address
-          otherwise, run through the table */
-       if (dev->base_addr != 0) {      /* dev->base_addr == 0 ==> plain autodetect */
-               if (elp_sense(dev) == 0)
-                       return dev->base_addr;
-       } else
-               while ((dev->base_addr = addr_list[idx++])) {
-                       if (elp_sense(dev) == 0)
-                               return dev->base_addr;
-               }
-
-       /* could not find an adapter */
-       if (elp_debug > 0)
-               pr_debug(couldnot_msg, dev->name);
-
-       return 0;               /* Because of this, the layer above will return -ENODEV */
-}
-
-static const struct net_device_ops elp_netdev_ops = {
-       .ndo_open               = elp_open,
-       .ndo_stop               = elp_close,
-       .ndo_get_stats          = elp_get_stats,
-       .ndo_start_xmit         = elp_start_xmit,
-       .ndo_tx_timeout         = elp_timeout,
-       .ndo_set_multicast_list = elp_set_mc_list,
-       .ndo_change_mtu         = eth_change_mtu,
-       .ndo_set_mac_address    = eth_mac_addr,
-       .ndo_validate_addr      = eth_validate_addr,
-};
-
-/******************************************************
- *
- * probe for an Etherlink Plus board at the specified address
- *
- ******************************************************/
-
-/* There are three situations we need to be able to detect here:
-
- *  a) the card is idle
- *  b) the card is still booting up
- *  c) the card is stuck in a strange state (some DOS drivers do this)
- *
- * In case (a), all is well.  In case (b), we wait 10 seconds to see if the
- * card finishes booting, and carry on if so.  In case (c), we do a hard reset,
- * loop round, and hope for the best.
- *
- * This is all very unpleasant, but hopefully avoids the problems with the old
- * probe code (which had a 15-second delay if the card was idle, and didn't
- * work at all if it was in a weird state).
- */
-
-static int __init elplus_setup(struct net_device *dev)
-{
-       elp_device *adapter = netdev_priv(dev);
-       int i, tries, tries1, okay;
-       unsigned long timeout;
-       unsigned long cookie = 0;
-       int err = -ENODEV;
-
-       /*
-        *  setup adapter structure
-        */
-
-       dev->base_addr = elp_autodetect(dev);
-       if (!dev->base_addr)
-               return -ENODEV;
-
-       adapter->send_pcb_semaphore = 0;
-
-       for (tries1 = 0; tries1 < 3; tries1++) {
-               outb_control((adapter->hcr_val | CMDE) & ~DIR, dev);
-               /* First try to write just one byte, to see if the card is
-                * responding at all normally.
-                */
-               timeout = jiffies + 5*HZ/100;
-               okay = 0;
-               while (time_before(jiffies, timeout) && !(inb_status(dev->base_addr) & HCRE));
-               if ((inb_status(dev->base_addr) & HCRE)) {
-                       outb_command(0, dev->base_addr);        /* send a spurious byte */
-                       timeout = jiffies + 5*HZ/100;
-                       while (time_before(jiffies, timeout) && !(inb_status(dev->base_addr) & HCRE));
-                       if (inb_status(dev->base_addr) & HCRE)
-                               okay = 1;
-               }
-               if (!okay) {
-                       /* Nope, it's ignoring the command register.  This means that
-                        * either it's still booting up, or it's died.
-                        */
-                       pr_err("%s: command register wouldn't drain, ", dev->name);
-                       if ((inb_status(dev->base_addr) & 7) == 3) {
-                               /* If the adapter status is 3, it *could* still be booting.
-                                * Give it the benefit of the doubt for 10 seconds.
-                                */
-                               pr_cont("assuming 3c505 still starting\n");
-                               timeout = jiffies + 10*HZ;
-                               while (time_before(jiffies, timeout) && (inb_status(dev->base_addr) & 7));
-                               if (inb_status(dev->base_addr) & 7) {
-                                       pr_err("%s: 3c505 failed to start\n", dev->name);
-                               } else {
-                                       okay = 1;  /* It started */
-                               }
-                       } else {
-                               /* Otherwise, it must just be in a strange
-                                * state.  We probably need to kick it.
-                                */
-                               pr_cont("3c505 is sulking\n");
-                       }
-               }
-               for (tries = 0; tries < 5 && okay; tries++) {
-
-                       /*
-                        * Try to set the Ethernet address, to make sure that the board
-                        * is working.
-                        */
-                       adapter->tx_pcb.command = CMD_STATION_ADDRESS;
-                       adapter->tx_pcb.length = 0;
-                       cookie = probe_irq_on();
-                       if (!send_pcb(dev, &adapter->tx_pcb)) {
-                               pr_err("%s: could not send first PCB\n", dev->name);
-                               probe_irq_off(cookie);
-                               continue;
-                       }
-                       if (!receive_pcb(dev, &adapter->rx_pcb)) {
-                               pr_err("%s: could not read first PCB\n", dev->name);
-                               probe_irq_off(cookie);
-                               continue;
-                       }
-                       if ((adapter->rx_pcb.command != CMD_ADDRESS_RESPONSE) ||
-                           (adapter->rx_pcb.length != 6)) {
-                               pr_err("%s: first PCB wrong (%d, %d)\n", dev->name,
-                                       adapter->rx_pcb.command, adapter->rx_pcb.length);
-                               probe_irq_off(cookie);
-                               continue;
-                       }
-                       goto okay;
-               }
-               /* It's broken.  Do a hard reset to re-initialise the board,
-                * and try again.
-                */
-               pr_info("%s: resetting adapter\n", dev->name);
-               outb_control(adapter->hcr_val | FLSH | ATTN, dev);
-               outb_control(adapter->hcr_val & ~(FLSH | ATTN), dev);
-       }
-       pr_err("%s: failed to initialise 3c505\n", dev->name);
-       goto out;
-
-      okay:
-       if (dev->irq) {         /* Is there a preset IRQ? */
-               int rpt = probe_irq_off(cookie);
-               if (dev->irq != rpt) {
-                       pr_warning("%s: warning, irq %d configured but %d detected\n", dev->name, dev->irq, rpt);
-               }
-               /* if dev->irq == probe_irq_off(cookie), all is well */
-       } else                 /* No preset IRQ; just use what we can detect */
-               dev->irq = probe_irq_off(cookie);
-       switch (dev->irq) {    /* Legal, sane? */
-       case 0:
-               pr_err("%s: IRQ probe failed: check 3c505 jumpers.\n",
-                      dev->name);
-               goto out;
-       case 1:
-       case 6:
-       case 8:
-       case 13:
-               pr_err("%s: Impossible IRQ %d reported by probe_irq_off().\n",
-                      dev->name, dev->irq);
-                      goto out;
-       }
-       /*
-        *  Now we have the IRQ number so we can disable the interrupts from
-        *  the board until the board is opened.
-        */
-       outb_control(adapter->hcr_val & ~CMDE, dev);
-
-       /*
-        * copy Ethernet address into structure
-        */
-       for (i = 0; i < 6; i++)
-               dev->dev_addr[i] = adapter->rx_pcb.data.eth_addr[i];
-
-       /* find a DMA channel */
-       if (!dev->dma) {
-               if (dev->mem_start) {
-                       dev->dma = dev->mem_start & 7;
-               }
-               else {
-                       pr_warning("%s: warning, DMA channel not specified, using default\n", dev->name);
-                       dev->dma = ELP_DMA;
-               }
-       }
-
-       /*
-        * print remainder of startup message
-        */
-       pr_info("%s: 3c505 at %#lx, irq %d, dma %d, addr %pM, ",
-               dev->name, dev->base_addr, dev->irq, dev->dma, dev->dev_addr);
-       /*
-        * read more information from the adapter
-        */
-
-       adapter->tx_pcb.command = CMD_ADAPTER_INFO;
-       adapter->tx_pcb.length = 0;
-       if (!send_pcb(dev, &adapter->tx_pcb) ||
-           !receive_pcb(dev, &adapter->rx_pcb) ||
-           (adapter->rx_pcb.command != CMD_ADAPTER_INFO_RESPONSE) ||
-           (adapter->rx_pcb.length != 10)) {
-               pr_cont("not responding to second PCB\n");
-       }
-       pr_cont("rev %d.%d, %dk\n", adapter->rx_pcb.data.info.major_vers,
-               adapter->rx_pcb.data.info.minor_vers, adapter->rx_pcb.data.info.RAM_sz);
-
-       /*
-        * reconfigure the adapter memory to better suit our purposes
-        */
-       adapter->tx_pcb.command = CMD_CONFIGURE_ADAPTER_MEMORY;
-       adapter->tx_pcb.length = 12;
-       adapter->tx_pcb.data.memconf.cmd_q = 8;
-       adapter->tx_pcb.data.memconf.rcv_q = 8;
-       adapter->tx_pcb.data.memconf.mcast = 10;
-       adapter->tx_pcb.data.memconf.frame = 10;
-       adapter->tx_pcb.data.memconf.rcv_b = 10;
-       adapter->tx_pcb.data.memconf.progs = 0;
-       if (!send_pcb(dev, &adapter->tx_pcb) ||
-           !receive_pcb(dev, &adapter->rx_pcb) ||
-           (adapter->rx_pcb.command != CMD_CONFIGURE_ADAPTER_RESPONSE) ||
-           (adapter->rx_pcb.length != 2)) {
-               pr_err("%s: could not configure adapter memory\n", dev->name);
-       }
-       if (adapter->rx_pcb.data.configure) {
-               pr_err("%s: adapter configuration failed\n", dev->name);
-       }
-
-       dev->netdev_ops = &elp_netdev_ops;
-       dev->watchdog_timeo = 10*HZ;
-       dev->ethtool_ops = &netdev_ethtool_ops;         /* local */
-
-       dev->mem_start = dev->mem_end = 0;
-
-       err = register_netdev(dev);
-       if (err)
-               goto out;
-
-       return 0;
-out:
-       release_region(dev->base_addr, ELP_IO_EXTENT);
-       return err;
-}
-
-#ifndef MODULE
-struct net_device * __init elplus_probe(int unit)
-{
-       struct net_device *dev = alloc_etherdev(sizeof(elp_device));
-       int err;
-       if (!dev)
-               return ERR_PTR(-ENOMEM);
-
-       sprintf(dev->name, "eth%d", unit);
-       netdev_boot_setup_check(dev);
-
-       err = elplus_setup(dev);
-       if (err) {
-               free_netdev(dev);
-               return ERR_PTR(err);
-       }
-       return dev;
-}
-
-#else
-static struct net_device *dev_3c505[ELP_MAX_CARDS];
-static int io[ELP_MAX_CARDS];
-static int irq[ELP_MAX_CARDS];
-static int dma[ELP_MAX_CARDS];
-module_param_array(io, int, NULL, 0);
-module_param_array(irq, int, NULL, 0);
-module_param_array(dma, int, NULL, 0);
-MODULE_PARM_DESC(io, "EtherLink Plus I/O base address(es)");
-MODULE_PARM_DESC(irq, "EtherLink Plus IRQ number(s) (assigned)");
-MODULE_PARM_DESC(dma, "EtherLink Plus DMA channel(s)");
-
-int __init init_module(void)
-{
-       int this_dev, found = 0;
-
-       for (this_dev = 0; this_dev < ELP_MAX_CARDS; this_dev++) {
-               struct net_device *dev = alloc_etherdev(sizeof(elp_device));
-               if (!dev)
-                       break;
-
-               dev->irq = irq[this_dev];
-               dev->base_addr = io[this_dev];
-               if (dma[this_dev]) {
-                       dev->dma = dma[this_dev];
-               } else {
-                       dev->dma = ELP_DMA;
-                       pr_warning("3c505.c: warning, using default DMA channel,\n");
-               }
-               if (io[this_dev] == 0) {
-                       if (this_dev) {
-                               free_netdev(dev);
-                               break;
-                       }
-                       pr_notice("3c505.c: module autoprobe not recommended, give io=xx.\n");
-               }
-               if (elplus_setup(dev) != 0) {
-                       pr_warning("3c505.c: Failed to register card at 0x%x.\n", io[this_dev]);
-                       free_netdev(dev);
-                       break;
-               }
-               dev_3c505[this_dev] = dev;
-               found++;
-       }
-       if (!found)
-               return -ENODEV;
-       return 0;
-}
-
-void __exit cleanup_module(void)
-{
-       int this_dev;
-
-       for (this_dev = 0; this_dev < ELP_MAX_CARDS; this_dev++) {
-               struct net_device *dev = dev_3c505[this_dev];
-               if (dev) {
-                       unregister_netdev(dev);
-                       release_region(dev->base_addr, ELP_IO_EXTENT);
-                       free_netdev(dev);
-               }
-       }
-}
-
-#endif                         /* MODULE */
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/3c505.h b/drivers/net/3c505.h
deleted file mode 100644 (file)
index 04df2a9..0000000
+++ /dev/null
@@ -1,292 +0,0 @@
-/*****************************************************************
- *
- *  defines for 3Com Etherlink Plus adapter
- *
- *****************************************************************/
-
-#define ELP_DMA       6
-#define ELP_RX_PCBS   4
-#define ELP_MAX_CARDS 4
-
-/*
- * I/O register offsets
- */
-#define        PORT_COMMAND    0x00    /* read/write, 8-bit */
-#define        PORT_STATUS     0x02    /* read only, 8-bit */
-#define        PORT_AUXDMA     0x02    /* write only, 8-bit */
-#define        PORT_DATA       0x04    /* read/write, 16-bit */
-#define        PORT_CONTROL    0x06    /* read/write, 8-bit */
-
-#define ELP_IO_EXTENT  0x10    /* size of used IO registers */
-
-/*
- * host control registers bits
- */
-#define        ATTN    0x80    /* attention */
-#define        FLSH    0x40    /* flush data register */
-#define DMAE   0x20    /* DMA enable */
-#define DIR    0x10    /* direction */
-#define        TCEN    0x08    /* terminal count interrupt enable */
-#define        CMDE    0x04    /* command register interrupt enable */
-#define        HSF2    0x02    /* host status flag 2 */
-#define        HSF1    0x01    /* host status flag 1 */
-
-/*
- * combinations of HSF flags used for PCB transmission
- */
-#define        HSF_PCB_ACK     HSF1
-#define        HSF_PCB_NAK     HSF2
-#define        HSF_PCB_END     (HSF2|HSF1)
-#define        HSF_PCB_MASK    (HSF2|HSF1)
-
-/*
- * host status register bits
- */
-#define        HRDY    0x80    /* data register ready */
-#define        HCRE    0x40    /* command register empty */
-#define        ACRF    0x20    /* adapter command register full */
-/* #define DIR         0x10    direction - same as in control register */
-#define        DONE    0x08    /* DMA done */
-#define        ASF3    0x04    /* adapter status flag 3 */
-#define        ASF2    0x02    /* adapter status flag 2 */
-#define        ASF1    0x01    /* adapter status flag 1 */
-
-/*
- * combinations of ASF flags used for PCB reception
- */
-#define        ASF_PCB_ACK     ASF1
-#define        ASF_PCB_NAK     ASF2
-#define        ASF_PCB_END     (ASF2|ASF1)
-#define        ASF_PCB_MASK    (ASF2|ASF1)
-
-/*
- * host aux DMA register bits
- */
-#define        DMA_BRST        0x01    /* DMA burst */
-
-/*
- * maximum amount of data allowed in a PCB
- */
-#define        MAX_PCB_DATA    62
-
-/*****************************************************************
- *
- *  timeout value
- *     this is a rough value used for loops to stop them from
- *     locking up the whole machine in the case of failure or
- *     error conditions
- *
- *****************************************************************/
-
-#define        TIMEOUT 300
-
-/*****************************************************************
- *
- * PCB commands
- *
- *****************************************************************/
-
-enum {
-  /*
-   * host PCB commands
-   */
-  CMD_CONFIGURE_ADAPTER_MEMORY = 0x01,
-  CMD_CONFIGURE_82586          = 0x02,
-  CMD_STATION_ADDRESS          = 0x03,
-  CMD_DMA_DOWNLOAD             = 0x04,
-  CMD_DMA_UPLOAD               = 0x05,
-  CMD_PIO_DOWNLOAD             = 0x06,
-  CMD_PIO_UPLOAD               = 0x07,
-  CMD_RECEIVE_PACKET           = 0x08,
-  CMD_TRANSMIT_PACKET          = 0x09,
-  CMD_NETWORK_STATISTICS       = 0x0a,
-  CMD_LOAD_MULTICAST_LIST      = 0x0b,
-  CMD_CLEAR_PROGRAM            = 0x0c,
-  CMD_DOWNLOAD_PROGRAM         = 0x0d,
-  CMD_EXECUTE_PROGRAM          = 0x0e,
-  CMD_SELF_TEST                        = 0x0f,
-  CMD_SET_STATION_ADDRESS      = 0x10,
-  CMD_ADAPTER_INFO             = 0x11,
-  NUM_TRANSMIT_CMDS,
-
-  /*
-   * adapter PCB commands
-   */
-  CMD_CONFIGURE_ADAPTER_RESPONSE       = 0x31,
-  CMD_CONFIGURE_82586_RESPONSE         = 0x32,
-  CMD_ADDRESS_RESPONSE                 = 0x33,
-  CMD_DOWNLOAD_DATA_REQUEST            = 0x34,
-  CMD_UPLOAD_DATA_REQUEST              = 0x35,
-  CMD_RECEIVE_PACKET_COMPLETE          = 0x38,
-  CMD_TRANSMIT_PACKET_COMPLETE         = 0x39,
-  CMD_NETWORK_STATISTICS_RESPONSE      = 0x3a,
-  CMD_LOAD_MULTICAST_RESPONSE          = 0x3b,
-  CMD_CLEAR_PROGRAM_RESPONSE           = 0x3c,
-  CMD_DOWNLOAD_PROGRAM_RESPONSE                = 0x3d,
-  CMD_EXECUTE_RESPONSE                 = 0x3e,
-  CMD_SELF_TEST_RESPONSE               = 0x3f,
-  CMD_SET_ADDRESS_RESPONSE             = 0x40,
-  CMD_ADAPTER_INFO_RESPONSE            = 0x41
-};
-
-/* Definitions for the PCB data structure */
-
-/* Data units */
-typedef unsigned char         byte;
-typedef unsigned short int    word;
-typedef unsigned long int     dword;
-
-/* Data structures */
-struct Memconf {
-       word    cmd_q,
-               rcv_q,
-               mcast,
-               frame,
-               rcv_b,
-               progs;
-};
-
-struct Rcv_pkt {
-       word    buf_ofs,
-               buf_seg,
-               buf_len,
-               timeout;
-};
-
-struct Xmit_pkt {
-       word    buf_ofs,
-               buf_seg,
-               pkt_len;
-};
-
-struct Rcv_resp {
-       word    buf_ofs,
-               buf_seg,
-               buf_len,
-               pkt_len,
-               timeout,
-               status;
-       dword   timetag;
-};
-
-struct Xmit_resp {
-       word    buf_ofs,
-               buf_seg,
-               c_stat,
-               status;
-};
-
-
-struct Netstat {
-       dword   tot_recv,
-               tot_xmit;
-       word    err_CRC,
-               err_align,
-               err_res,
-               err_ovrrun;
-};
-
-
-struct Selftest {
-       word    error;
-       union {
-               word ROM_cksum;
-               struct {
-                       word ofs, seg;
-               } RAM;
-               word i82586;
-       } failure;
-};
-
-struct Info {
-       byte    minor_vers,
-               major_vers;
-       word    ROM_cksum,
-               RAM_sz,
-               free_ofs,
-               free_seg;
-};
-
-struct Memdump {
-       word size,
-            off,
-            seg;
-};
-
-/*
-Primary Command Block. The most important data structure. All communication
-between the host and the adapter is done with these. (Except for the actual
-Ethernet data, which has different packaging.)
-*/
-typedef struct {
-       byte    command;
-       byte    length;
-       union   {
-               struct Memconf          memconf;
-               word                    configure;
-               struct Rcv_pkt          rcv_pkt;
-               struct Xmit_pkt         xmit_pkt;
-               byte                    multicast[10][6];
-               byte                    eth_addr[6];
-               byte                    failed;
-               struct Rcv_resp         rcv_resp;
-               struct Xmit_resp        xmit_resp;
-               struct Netstat          netstat;
-               struct Selftest         selftest;
-               struct Info             info;
-               struct Memdump          memdump;
-               byte                    raw[62];
-       } data;
-} pcb_struct;
-
-/* These defines for 'configure' */
-#define RECV_STATION   0x00
-#define RECV_BROAD     0x01
-#define RECV_MULTI     0x02
-#define RECV_PROMISC   0x04
-#define NO_LOOPBACK    0x00
-#define INT_LOOPBACK   0x08
-#define EXT_LOOPBACK   0x10
-
-/*****************************************************************
- *
- *  structure to hold context information for adapter
- *
- *****************************************************************/
-
-#define DMA_BUFFER_SIZE  1600
-#define BACKLOG_SIZE      4
-
-typedef struct {
-       volatile short got[NUM_TRANSMIT_CMDS];  /* flags for
-                                                  command completion */
-       pcb_struct tx_pcb;      /* PCB for foreground sending */
-       pcb_struct rx_pcb;      /* PCB for foreground receiving */
-       pcb_struct itx_pcb;     /* PCB for background sending */
-       pcb_struct irx_pcb;     /* PCB for background receiving */
-
-       void *dma_buffer;
-
-       struct {
-               unsigned int length[BACKLOG_SIZE];
-               unsigned int in;
-               unsigned int out;
-       } rx_backlog;
-
-       struct {
-               unsigned int direction;
-               unsigned int length;
-               struct sk_buff *skb;
-               void *target;
-               unsigned long start_time;
-       } current_dma;
-
-       /* flags */
-       unsigned long send_pcb_semaphore;
-       unsigned long dmaing;
-       unsigned long busy;
-
-       unsigned int rx_active;  /* number of receive PCBs */
-        volatile unsigned char hcr_val;  /* what we think the HCR contains */
-        spinlock_t lock;       /* Interrupt v tx lock */
-} elp_device;
diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c
deleted file mode 100644 (file)
index 1e94555..0000000
+++ /dev/null
@@ -1,939 +0,0 @@
-/* 3c507.c: An EtherLink16 device driver for Linux. */
-/*
-       Written 1993,1994 by Donald Becker.
-
-       Copyright 1993 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 General Public License, incorporated herein by reference.
-
-       The author may be reached as becker@scyld.com, or C/O
-       Scyld Computing Corporation
-       410 Severn Ave., Suite 210
-       Annapolis MD 21403
-
-
-       Thanks go to jennings@Montrouge.SMR.slb.com ( Patrick Jennings)
-       and jrs@world.std.com (Rick Sladkey) for testing and bugfixes.
-       Mark Salazar <leslie@access.digex.net> made the changes for cards with
-       only 16K packet buffers.
-
-       Things remaining to do:
-       Verify that the tx and rx buffers don't have fencepost errors.
-       Move the theory of operation and memory map documentation.
-       The statistics need to be updated correctly.
-*/
-
-#define DRV_NAME               "3c507"
-#define DRV_VERSION            "1.10a"
-#define DRV_RELDATE            "11/17/2001"
-
-static const char version[] =
-       DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " Donald Becker (becker@scyld.com)\n";
-
-/*
-  Sources:
-       This driver wouldn't have been written with the availability of the
-       Crynwr driver source code.      It provided a known-working implementation
-       that filled in the gaping holes of the Intel documentation.  Three cheers
-       for Russ Nelson.
-
-       Intel Microcommunications Databook, Vol. 1, 1990.  It provides just enough
-       info that the casual reader might think that it documents the i82586 :-<.
-*/
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/string.h>
-#include <linux/spinlock.h>
-#include <linux/ethtool.h>
-#include <linux/errno.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/if_ether.h>
-#include <linux/skbuff.h>
-#include <linux/init.h>
-#include <linux/bitops.h>
-
-#include <asm/dma.h>
-#include <asm/io.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
-
-/* use 0 for production, 1 for verification, 2..7 for debug */
-#ifndef NET_DEBUG
-#define NET_DEBUG 1
-#endif
-static unsigned int net_debug = NET_DEBUG;
-#define debug net_debug
-
-
-/*
-                       Details of the i82586.
-
-   You'll really need the databook to understand the details of this part,
-   but the outline is that the i82586 has two separate processing units.
-   Both are started from a list of three configuration tables, of which only
-   the last, the System Control Block (SCB), is used after reset-time.  The SCB
-   has the following fields:
-               Status word
-               Command word
-               Tx/Command block addr.
-               Rx block addr.
-   The command word accepts the following controls for the Tx and Rx units:
-  */
-
-#define         CUC_START       0x0100
-#define         CUC_RESUME      0x0200
-#define         CUC_SUSPEND 0x0300
-#define         RX_START        0x0010
-#define         RX_RESUME       0x0020
-#define         RX_SUSPEND      0x0030
-
-/* The Rx unit uses a list of frame descriptors and a list of data buffer
-   descriptors.  We use full-sized (1518 byte) data buffers, so there is
-   a one-to-one pairing of frame descriptors to buffer descriptors.
-
-   The Tx ("command") unit executes a list of commands that look like:
-               Status word             Written by the 82586 when the command is done.
-               Command word    Command in lower 3 bits, post-command action in upper 3
-               Link word               The address of the next command.
-               Parameters              (as needed).
-
-       Some definitions related to the Command Word are:
- */
-#define CMD_EOL                0x8000                  /* The last command of the list, stop. */
-#define CMD_SUSP       0x4000                  /* Suspend after doing cmd. */
-#define CMD_INTR       0x2000                  /* Interrupt after doing cmd. */
-
-enum commands {
-       CmdNOp = 0, CmdSASetup = 1, CmdConfigure = 2, CmdMulticastList = 3,
-       CmdTx = 4, CmdTDR = 5, CmdDump = 6, CmdDiagnose = 7};
-
-/* Information that need to be kept for each board. */
-struct net_local {
-       int last_restart;
-       ushort rx_head;
-       ushort rx_tail;
-       ushort tx_head;
-       ushort tx_cmd_link;
-       ushort tx_reap;
-       ushort tx_pkts_in_ring;
-       spinlock_t lock;
-       void __iomem *base;
-};
-
-/*
-               Details of the EtherLink16 Implementation
-  The 3c507 is a generic shared-memory i82586 implementation.
-  The host can map 16K, 32K, 48K, or 64K of the 64K memory into
-  0x0[CD][08]0000, or all 64K into 0xF[02468]0000.
-  */
-
-/* Offsets from the base I/O address. */
-#define        SA_DATA         0       /* Station address data, or 3Com signature. */
-#define MISC_CTRL      6       /* Switch the SA_DATA banks, and bus config bits. */
-#define RESET_IRQ      10      /* Reset the latched IRQ line. */
-#define SIGNAL_CA      11      /* Frob the 82586 Channel Attention line. */
-#define ROM_CONFIG     13
-#define MEM_CONFIG     14
-#define IRQ_CONFIG     15
-#define EL16_IO_EXTENT 16
-
-/* The ID port is used at boot-time to locate the ethercard. */
-#define ID_PORT                0x100
-
-/* Offsets to registers in the mailbox (SCB). */
-#define iSCB_STATUS    0x8
-#define iSCB_CMD               0xA
-#define iSCB_CBL               0xC     /* Command BLock offset. */
-#define iSCB_RFA               0xE     /* Rx Frame Area offset. */
-
-/*  Since the 3c507 maps the shared memory window so that the last byte is
-       at 82586 address FFFF, the first byte is at 82586 address 0, 16K, 32K, or
-       48K corresponding to window sizes of 64K, 48K, 32K and 16K respectively.
-       We can account for this be setting the 'SBC Base' entry in the ISCP table
-       below for all the 16 bit offset addresses, and also adding the 'SCB Base'
-       value to all 24 bit physical addresses (in the SCP table and the TX and RX
-       Buffer Descriptors).
-                                       -Mark
-       */
-#define SCB_BASE               ((unsigned)64*1024 - (dev->mem_end - dev->mem_start))
-
-/*
-  What follows in 'init_words[]' is the "program" that is downloaded to the
-  82586 memory.         It's mostly tables and command blocks, and starts at the
-  reset address 0xfffff6.  This is designed to be similar to the EtherExpress,
-  thus the unusual location of the SCB at 0x0008.
-
-  Even with the additional "don't care" values, doing it this way takes less
-  program space than initializing the individual tables, and I feel it's much
-  cleaner.
-
-  The databook is particularly useless for the first two structures, I had
-  to use the Crynwr driver as an example.
-
-   The memory setup is as follows:
-   */
-
-#define CONFIG_CMD     0x0018
-#define SET_SA_CMD     0x0024
-#define SA_OFFSET      0x002A
-#define IDLELOOP       0x30
-#define TDR_CMD                0x38
-#define TDR_TIME       0x3C
-#define DUMP_CMD       0x40
-#define DIAG_CMD       0x48
-#define SET_MC_CMD     0x4E
-#define DUMP_DATA      0x56    /* A 170 byte buffer for dump and Set-MC into. */
-
-#define TX_BUF_START   0x0100
-#define NUM_TX_BUFS    5
-#define TX_BUF_SIZE    (1518+14+20+16) /* packet+header+TBD */
-
-#define RX_BUF_START   0x2000
-#define RX_BUF_SIZE    (1518+14+18)    /* packet+header+RBD */
-#define RX_BUF_END             (dev->mem_end - dev->mem_start)
-
-#define TX_TIMEOUT (HZ/20)
-
-/*
-  That's it: only 86 bytes to set up the beast, including every extra
-  command available.  The 170 byte buffer at DUMP_DATA is shared between the
-  Dump command (called only by the diagnostic program) and the SetMulticastList
-  command.
-
-  To complete the memory setup you only have to write the station address at
-  SA_OFFSET and create the Tx & Rx buffer lists.
-
-  The Tx command chain and buffer list is setup as follows:
-  A Tx command table, with the data buffer pointing to...
-  A Tx data buffer descriptor.  The packet is in a single buffer, rather than
-       chaining together several smaller buffers.
-  A NoOp command, which initially points to itself,
-  And the packet data.
-
-  A transmit is done by filling in the Tx command table and data buffer,
-  re-writing the NoOp command, and finally changing the offset of the last
-  command to point to the current Tx command.  When the Tx command is finished,
-  it jumps to the NoOp, when it loops until the next Tx command changes the
-  "link offset" in the NoOp.  This way the 82586 never has to go through the
-  slow restart sequence.
-
-  The Rx buffer list is set up in the obvious ring structure.  We have enough
-  memory (and low enough interrupt latency) that we can avoid the complicated
-  Rx buffer linked lists by alway associating a full-size Rx data buffer with
-  each Rx data frame.
-
-  I current use four transmit buffers starting at TX_BUF_START (0x0100), and
-  use the rest of memory, from RX_BUF_START to RX_BUF_END, for Rx buffers.
-
-  */
-
-static unsigned short init_words[] = {
-       /*      System Configuration Pointer (SCP). */
-       0x0000,                                 /* Set bus size to 16 bits. */
-       0,0,                                    /* pad words. */
-       0x0000,0x0000,                  /* ISCP phys addr, set in init_82586_mem(). */
-
-       /*      Intermediate System Configuration Pointer (ISCP). */
-       0x0001,                                 /* Status word that's cleared when init is done. */
-       0x0008,0,0,                             /* SCB offset, (skip, skip) */
-
-       /* System Control Block (SCB). */
-       0,0xf000|RX_START|CUC_START,    /* SCB status and cmd. */
-       CONFIG_CMD,                             /* Command list pointer, points to Configure. */
-       RX_BUF_START,                           /* Rx block list. */
-       0,0,0,0,                                /* Error count: CRC, align, buffer, overrun. */
-
-       /* 0x0018: Configure command.  Change to put MAC data with packet. */
-       0, CmdConfigure,                /* Status, command.             */
-       SET_SA_CMD,                             /* Next command is Set Station Addr. */
-       0x0804,                                 /* "4" bytes of config data, 8 byte FIFO. */
-       0x2e40,                                 /* Magic values, including MAC data location. */
-       0,                                              /* Unused pad word. */
-
-       /* 0x0024: Setup station address command. */
-       0, CmdSASetup,
-       SET_MC_CMD,                             /* Next command. */
-       0xaa00,0xb000,0x0bad,   /* Station address (to be filled in) */
-
-       /* 0x0030: NOP, looping back to itself.  Point to first Tx buffer to Tx. */
-       0, CmdNOp, IDLELOOP, 0 /* pad */,
-
-       /* 0x0038: A unused Time-Domain Reflectometer command. */
-       0, CmdTDR, IDLELOOP, 0,
-
-       /* 0x0040: An unused Dump State command. */
-       0, CmdDump, IDLELOOP, DUMP_DATA,
-
-       /* 0x0048: An unused Diagnose command. */
-       0, CmdDiagnose, IDLELOOP,
-
-       /* 0x004E: An empty set-multicast-list command. */
-       0, CmdMulticastList, IDLELOOP, 0,
-};
-
-/* Index to functions, as function prototypes. */
-
-static int     el16_probe1(struct net_device *dev, int ioaddr);
-static int     el16_open(struct net_device *dev);
-static netdev_tx_t el16_send_packet(struct sk_buff *skb,
-                                   struct net_device *dev);
-static irqreturn_t el16_interrupt(int irq, void *dev_id);
-static void el16_rx(struct net_device *dev);
-static int     el16_close(struct net_device *dev);
-static void el16_tx_timeout (struct net_device *dev);
-
-static void hardware_send_packet(struct net_device *dev, void *buf, short length, short pad);
-static void init_82586_mem(struct net_device *dev);
-static const struct ethtool_ops netdev_ethtool_ops;
-static void init_rx_bufs(struct net_device *);
-
-static int io = 0x300;
-static int irq;
-static int mem_start;
-
-
-/* Check for a network adaptor of this type, and return '0' iff one exists.
-       If dev->base_addr == 0, probe all likely locations.
-       If dev->base_addr == 1, always return failure.
-       If dev->base_addr == 2, (detachable devices only) allocate space for the
-       device and return success.
-       */
-
-struct net_device * __init el16_probe(int unit)
-{
-       struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
-       static const unsigned ports[] = { 0x300, 0x320, 0x340, 0x280, 0};
-       const unsigned *port;
-       int err = -ENODEV;
-
-       if (!dev)
-               return ERR_PTR(-ENODEV);
-
-       if (unit >= 0) {
-               sprintf(dev->name, "eth%d", unit);
-               netdev_boot_setup_check(dev);
-               io = dev->base_addr;
-               irq = dev->irq;
-               mem_start = dev->mem_start & 15;
-       }
-
-       if (io > 0x1ff)         /* Check a single specified location. */
-               err = el16_probe1(dev, io);
-       else if (io != 0)
-               err = -ENXIO;           /* Don't probe at all. */
-       else {
-               for (port = ports; *port; port++) {
-                       err = el16_probe1(dev, *port);
-                       if (!err)
-                               break;
-               }
-       }
-
-       if (err)
-               goto out;
-       err = register_netdev(dev);
-       if (err)
-               goto out1;
-       return dev;
-out1:
-       free_irq(dev->irq, dev);
-       iounmap(((struct net_local *)netdev_priv(dev))->base);
-       release_region(dev->base_addr, EL16_IO_EXTENT);
-out:
-       free_netdev(dev);
-       return ERR_PTR(err);
-}
-
-static const struct net_device_ops netdev_ops = {
-       .ndo_open               = el16_open,
-       .ndo_stop               = el16_close,
-       .ndo_start_xmit         = el16_send_packet,
-       .ndo_tx_timeout         = el16_tx_timeout,
-       .ndo_change_mtu         = eth_change_mtu,
-       .ndo_set_mac_address    = eth_mac_addr,
-       .ndo_validate_addr      = eth_validate_addr,
-};
-
-static int __init el16_probe1(struct net_device *dev, int ioaddr)
-{
-       static unsigned char init_ID_done;
-       int i, irq, irqval, retval;
-       struct net_local *lp;
-
-       if (init_ID_done == 0) {
-               ushort lrs_state = 0xff;
-               /* Send the ID sequence to the ID_PORT to enable the board(s). */
-               outb(0x00, ID_PORT);
-               for(i = 0; i < 255; i++) {
-                       outb(lrs_state, ID_PORT);
-                       lrs_state <<= 1;
-                       if (lrs_state & 0x100)
-                               lrs_state ^= 0xe7;
-               }
-               outb(0x00, ID_PORT);
-               init_ID_done = 1;
-       }
-
-       if (!request_region(ioaddr, EL16_IO_EXTENT, DRV_NAME))
-               return -ENODEV;
-
-       if ((inb(ioaddr) != '*') || (inb(ioaddr + 1) != '3') ||
-           (inb(ioaddr + 2) != 'C') || (inb(ioaddr + 3) != 'O')) {
-               retval = -ENODEV;
-               goto out;
-       }
-
-       pr_info("%s: 3c507 at %#x,", dev->name, ioaddr);
-
-       /* We should make a few more checks here, like the first three octets of
-          the S.A. for the manufacturer's code. */
-
-       irq = inb(ioaddr + IRQ_CONFIG) & 0x0f;
-
-       irqval = request_irq(irq, el16_interrupt, 0, DRV_NAME, dev);
-       if (irqval) {
-               pr_cont("\n");
-               pr_err("3c507: unable to get IRQ %d (irqval=%d).\n", irq, irqval);
-               retval = -EAGAIN;
-               goto out;
-       }
-
-       /* We've committed to using the board, and can start filling in *dev. */
-       dev->base_addr = ioaddr;
-
-       outb(0x01, ioaddr + MISC_CTRL);
-       for (i = 0; i < 6; i++)
-               dev->dev_addr[i] = inb(ioaddr + i);
-       pr_cont(" %pM", dev->dev_addr);
-
-       if (mem_start)
-               net_debug = mem_start & 7;
-
-#ifdef MEM_BASE
-       dev->mem_start = MEM_BASE;
-       dev->mem_end = dev->mem_start + 0x10000;
-#else
-       {
-               int base;
-               int size;
-               char mem_config = inb(ioaddr + MEM_CONFIG);
-               if (mem_config & 0x20) {
-                       size = 64*1024;
-                       base = 0xf00000 + (mem_config & 0x08 ? 0x080000
-                                                          : ((mem_config & 3) << 17));
-               } else {
-                       size = ((mem_config & 3) + 1) << 14;
-                       base = 0x0c0000 + ( (mem_config & 0x18) << 12);
-               }
-               dev->mem_start = base;
-               dev->mem_end = base + size;
-       }
-#endif
-
-       dev->if_port = (inb(ioaddr + ROM_CONFIG) & 0x80) ? 1 : 0;
-       dev->irq = inb(ioaddr + IRQ_CONFIG) & 0x0f;
-
-       pr_cont(", IRQ %d, %sternal xcvr, memory %#lx-%#lx.\n", dev->irq,
-                  dev->if_port ? "ex" : "in", dev->mem_start, dev->mem_end-1);
-
-       if (net_debug)
-               pr_debug("%s", version);
-
-       lp = netdev_priv(dev);
-       spin_lock_init(&lp->lock);
-       lp->base = ioremap(dev->mem_start, RX_BUF_END);
-       if (!lp->base) {
-               pr_err("3c507: unable to remap memory\n");
-               retval = -EAGAIN;
-               goto out1;
-       }
-
-       dev->netdev_ops = &netdev_ops;
-       dev->watchdog_timeo = TX_TIMEOUT;
-       dev->ethtool_ops = &netdev_ethtool_ops;
-       dev->flags &= ~IFF_MULTICAST;   /* Multicast doesn't work */
-       return 0;
-out1:
-       free_irq(dev->irq, dev);
-out:
-       release_region(ioaddr, EL16_IO_EXTENT);
-       return retval;
-}
-
-static int el16_open(struct net_device *dev)
-{
-       /* Initialize the 82586 memory and start it. */
-       init_82586_mem(dev);
-
-       netif_start_queue(dev);
-       return 0;
-}
-
-
-static void el16_tx_timeout (struct net_device *dev)
-{
-       struct net_local *lp = netdev_priv(dev);
-       int ioaddr = dev->base_addr;
-       void __iomem *shmem = lp->base;
-
-       if (net_debug > 1)
-               pr_debug("%s: transmit timed out, %s?  ", dev->name,
-                       readw(shmem + iSCB_STATUS) & 0x8000 ? "IRQ conflict" :
-                       "network cable problem");
-       /* Try to restart the adaptor. */
-       if (lp->last_restart == dev->stats.tx_packets) {
-               if (net_debug > 1)
-                       pr_cont("Resetting board.\n");
-               /* Completely reset the adaptor. */
-               init_82586_mem (dev);
-               lp->tx_pkts_in_ring = 0;
-       } else {
-               /* Issue the channel attention signal and hope it "gets better". */
-               if (net_debug > 1)
-                       pr_cont("Kicking board.\n");
-               writew(0xf000 | CUC_START | RX_START, shmem + iSCB_CMD);
-               outb (0, ioaddr + SIGNAL_CA);   /* Issue channel-attn. */
-               lp->last_restart = dev->stats.tx_packets;
-       }
-       dev->trans_start = jiffies; /* prevent tx timeout */
-       netif_wake_queue (dev);
-}
-
-
-static netdev_tx_t el16_send_packet (struct sk_buff *skb,
-                                    struct net_device *dev)
-{
-       struct net_local *lp = netdev_priv(dev);
-       int ioaddr = dev->base_addr;
-       unsigned long flags;
-       short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
-       unsigned char *buf = skb->data;
-
-       netif_stop_queue (dev);
-
-       spin_lock_irqsave (&lp->lock, flags);
-
-       dev->stats.tx_bytes += length;
-       /* Disable the 82586's input to the interrupt line. */
-       outb (0x80, ioaddr + MISC_CTRL);
-
-       hardware_send_packet (dev, buf, skb->len, length - skb->len);
-
-       /* Enable the 82586 interrupt input. */
-       outb (0x84, ioaddr + MISC_CTRL);
-
-       spin_unlock_irqrestore (&lp->lock, flags);
-
-       dev_kfree_skb (skb);
-
-       /* You might need to clean up and record Tx statistics here. */
-
-       return NETDEV_TX_OK;
-}
-
-/*     The typical workload of the driver:
-       Handle the network interface interrupts. */
-static irqreturn_t el16_interrupt(int irq, void *dev_id)
-{
-       struct net_device *dev = dev_id;
-       struct net_local *lp;
-       int ioaddr, status, boguscount = 0;
-       ushort ack_cmd = 0;
-       void __iomem *shmem;
-
-       if (dev == NULL) {
-               pr_err("net_interrupt(): irq %d for unknown device.\n", irq);
-               return IRQ_NONE;
-       }
-
-       ioaddr = dev->base_addr;
-       lp = netdev_priv(dev);
-       shmem = lp->base;
-
-       spin_lock(&lp->lock);
-
-       status = readw(shmem+iSCB_STATUS);
-
-       if (net_debug > 4) {
-               pr_debug("%s: 3c507 interrupt, status %4.4x.\n", dev->name, status);
-       }
-
-       /* Disable the 82586's input to the interrupt line. */
-       outb(0x80, ioaddr + MISC_CTRL);
-
-       /* Reap the Tx packet buffers. */
-       while (lp->tx_pkts_in_ring) {
-         unsigned short tx_status = readw(shmem+lp->tx_reap);
-         if (!(tx_status & 0x8000)) {
-               if (net_debug > 5)
-                       pr_debug("Tx command incomplete (%#x).\n", lp->tx_reap);
-               break;
-         }
-         /* Tx unsuccessful or some interesting status bit set. */
-         if (!(tx_status & 0x2000) || (tx_status & 0x0f3f)) {
-               dev->stats.tx_errors++;
-               if (tx_status & 0x0600)  dev->stats.tx_carrier_errors++;
-               if (tx_status & 0x0100)  dev->stats.tx_fifo_errors++;
-               if (!(tx_status & 0x0040))  dev->stats.tx_heartbeat_errors++;
-               if (tx_status & 0x0020)  dev->stats.tx_aborted_errors++;
-               dev->stats.collisions += tx_status & 0xf;
-         }
-         dev->stats.tx_packets++;
-         if (net_debug > 5)
-                 pr_debug("Reaped %x, Tx status %04x.\n" , lp->tx_reap, tx_status);
-         lp->tx_reap += TX_BUF_SIZE;
-         if (lp->tx_reap > RX_BUF_START - TX_BUF_SIZE)
-               lp->tx_reap = TX_BUF_START;
-
-         lp->tx_pkts_in_ring--;
-         /* There is always more space in the Tx ring buffer now. */
-         netif_wake_queue(dev);
-
-         if (++boguscount > 10)
-               break;
-       }
-
-       if (status & 0x4000) { /* Packet received. */
-               if (net_debug > 5)
-                       pr_debug("Received packet, rx_head %04x.\n", lp->rx_head);
-               el16_rx(dev);
-       }
-
-       /* Acknowledge the interrupt sources. */
-       ack_cmd = status & 0xf000;
-
-       if ((status & 0x0700) != 0x0200 && netif_running(dev)) {
-               if (net_debug)
-                       pr_debug("%s: Command unit stopped, status %04x, restarting.\n",
-                                  dev->name, status);
-               /* If this ever occurs we should really re-write the idle loop, reset
-                  the Tx list, and do a complete restart of the command unit.
-                  For now we rely on the Tx timeout if the resume doesn't work. */
-               ack_cmd |= CUC_RESUME;
-       }
-
-       if ((status & 0x0070) != 0x0040 && netif_running(dev)) {
-               /* The Rx unit is not ready, it must be hung.  Restart the receiver by
-                  initializing the rx buffers, and issuing an Rx start command. */
-               if (net_debug)
-                       pr_debug("%s: Rx unit stopped, status %04x, restarting.\n",
-                                  dev->name, status);
-               init_rx_bufs(dev);
-               writew(RX_BUF_START,shmem+iSCB_RFA);
-               ack_cmd |= RX_START;
-       }
-
-       writew(ack_cmd,shmem+iSCB_CMD);
-       outb(0, ioaddr + SIGNAL_CA);                    /* Issue channel-attn. */
-
-       /* Clear the latched interrupt. */
-       outb(0, ioaddr + RESET_IRQ);
-
-       /* Enable the 82586's interrupt input. */
-       outb(0x84, ioaddr + MISC_CTRL);
-       spin_unlock(&lp->lock);
-       return IRQ_HANDLED;
-}
-
-static int el16_close(struct net_device *dev)
-{
-       struct net_local *lp = netdev_priv(dev);
-       int ioaddr = dev->base_addr;
-       void __iomem *shmem = lp->base;
-
-       netif_stop_queue(dev);
-
-       /* Flush the Tx and disable Rx. */
-       writew(RX_SUSPEND | CUC_SUSPEND,shmem+iSCB_CMD);
-       outb(0, ioaddr + SIGNAL_CA);
-
-       /* Disable the 82586's input to the interrupt line. */
-       outb(0x80, ioaddr + MISC_CTRL);
-
-       /* We always physically use the IRQ line, so we don't do free_irq(). */
-
-       /* Update the statistics here. */
-
-       return 0;
-}
-
-/* Initialize the Rx-block list. */
-static void init_rx_bufs(struct net_device *dev)
-{
-       struct net_local *lp = netdev_priv(dev);
-       void __iomem *write_ptr;
-       unsigned short SCB_base = SCB_BASE;
-
-       int cur_rxbuf = lp->rx_head = RX_BUF_START;
-
-       /* Initialize each Rx frame + data buffer. */
-       do {    /* While there is room for one more. */
-
-               write_ptr = lp->base + cur_rxbuf;
-
-               writew(0x0000,write_ptr);                       /* Status */
-               writew(0x0000,write_ptr+=2);                    /* Command */
-               writew(cur_rxbuf + RX_BUF_SIZE,write_ptr+=2);   /* Link */
-               writew(cur_rxbuf + 22,write_ptr+=2);            /* Buffer offset */
-               writew(0x0000,write_ptr+=2);                    /* Pad for dest addr. */
-               writew(0x0000,write_ptr+=2);
-               writew(0x0000,write_ptr+=2);
-               writew(0x0000,write_ptr+=2);                    /* Pad for source addr. */
-               writew(0x0000,write_ptr+=2);
-               writew(0x0000,write_ptr+=2);
-               writew(0x0000,write_ptr+=2);                    /* Pad for protocol. */
-
-               writew(0x0000,write_ptr+=2);                    /* Buffer: Actual count */
-               writew(-1,write_ptr+=2);                        /* Buffer: Next (none). */
-               writew(cur_rxbuf + 0x20 + SCB_base,write_ptr+=2);/* Buffer: Address low */
-               writew(0x0000,write_ptr+=2);
-               /* Finally, the number of bytes in the buffer. */
-               writew(0x8000 + RX_BUF_SIZE-0x20,write_ptr+=2);
-
-               lp->rx_tail = cur_rxbuf;
-               cur_rxbuf += RX_BUF_SIZE;
-       } while (cur_rxbuf <= RX_BUF_END - RX_BUF_SIZE);
-
-       /* Terminate the list by setting the EOL bit, and wrap the pointer to make
-          the list a ring. */
-       write_ptr = lp->base + lp->rx_tail + 2;
-       writew(0xC000,write_ptr);                               /* Command, mark as last. */
-       writew(lp->rx_head,write_ptr+2);                        /* Link */
-}
-
-static void init_82586_mem(struct net_device *dev)
-{
-       struct net_local *lp = netdev_priv(dev);
-       short ioaddr = dev->base_addr;
-       void __iomem *shmem = lp->base;
-
-       /* Enable loopback to protect the wire while starting up,
-          and hold the 586 in reset during the memory initialization. */
-       outb(0x20, ioaddr + MISC_CTRL);
-
-       /* Fix the ISCP address and base. */
-       init_words[3] = SCB_BASE;
-       init_words[7] = SCB_BASE;
-
-       /* Write the words at 0xfff6 (address-aliased to 0xfffff6). */
-       memcpy_toio(lp->base + RX_BUF_END - 10, init_words, 10);
-
-       /* Write the words at 0x0000. */
-       memcpy_toio(lp->base, init_words + 5, sizeof(init_words) - 10);
-
-       /* Fill in the station address. */
-       memcpy_toio(lp->base+SA_OFFSET, dev->dev_addr, ETH_ALEN);
-
-       /* The Tx-block list is written as needed.  We just set up the values. */
-       lp->tx_cmd_link = IDLELOOP + 4;
-       lp->tx_head = lp->tx_reap = TX_BUF_START;
-
-       init_rx_bufs(dev);
-
-       /* Start the 586 by releasing the reset line, but leave loopback. */
-       outb(0xA0, ioaddr + MISC_CTRL);
-
-       /* This was time consuming to track down: you need to give two channel
-          attention signals to reliably start up the i82586. */
-       outb(0, ioaddr + SIGNAL_CA);
-
-       {
-               int boguscnt = 50;
-               while (readw(shmem+iSCB_STATUS) == 0)
-                       if (--boguscnt == 0) {
-                               pr_warning("%s: i82586 initialization timed out with status %04x, cmd %04x.\n",
-                                       dev->name, readw(shmem+iSCB_STATUS), readw(shmem+iSCB_CMD));
-                               break;
-                       }
-               /* Issue channel-attn -- the 82586 won't start. */
-               outb(0, ioaddr + SIGNAL_CA);
-       }
-
-       /* Disable loopback and enable interrupts. */
-       outb(0x84, ioaddr + MISC_CTRL);
-       if (net_debug > 4)
-               pr_debug("%s: Initialized 82586, status %04x.\n", dev->name,
-                          readw(shmem+iSCB_STATUS));
-}
-
-static void hardware_send_packet(struct net_device *dev, void *buf, short length, short pad)
-{
-       struct net_local *lp = netdev_priv(dev);
-       short ioaddr = dev->base_addr;
-       ushort tx_block = lp->tx_head;
-       void __iomem *write_ptr = lp->base + tx_block;
-       static char padding[ETH_ZLEN];
-
-       /* Set the write pointer to the Tx block, and put out the header. */
-       writew(0x0000,write_ptr);                       /* Tx status */
-       writew(CMD_INTR|CmdTx,write_ptr+=2);            /* Tx command */
-       writew(tx_block+16,write_ptr+=2);               /* Next command is a NoOp. */
-       writew(tx_block+8,write_ptr+=2);                        /* Data Buffer offset. */
-
-       /* Output the data buffer descriptor. */
-       writew((pad + length) | 0x8000,write_ptr+=2);           /* Byte count parameter. */
-       writew(-1,write_ptr+=2);                        /* No next data buffer. */
-       writew(tx_block+22+SCB_BASE,write_ptr+=2);      /* Buffer follows the NoOp command. */
-       writew(0x0000,write_ptr+=2);                    /* Buffer address high bits (always zero). */
-
-       /* Output the Loop-back NoOp command. */
-       writew(0x0000,write_ptr+=2);                    /* Tx status */
-       writew(CmdNOp,write_ptr+=2);                    /* Tx command */
-       writew(tx_block+16,write_ptr+=2);               /* Next is myself. */
-
-       /* Output the packet at the write pointer. */
-       memcpy_toio(write_ptr+2, buf, length);
-       if (pad)
-               memcpy_toio(write_ptr+length+2, padding, pad);
-
-       /* Set the old command link pointing to this send packet. */
-       writew(tx_block,lp->base + lp->tx_cmd_link);
-       lp->tx_cmd_link = tx_block + 20;
-
-       /* Set the next free tx region. */
-       lp->tx_head = tx_block + TX_BUF_SIZE;
-       if (lp->tx_head > RX_BUF_START - TX_BUF_SIZE)
-               lp->tx_head = TX_BUF_START;
-
-       if (net_debug > 4) {
-               pr_debug("%s: 3c507 @%x send length = %d, tx_block %3x, next %3x.\n",
-                          dev->name, ioaddr, length, tx_block, lp->tx_head);
-       }
-
-       /* Grimly block further packets if there has been insufficient reaping. */
-       if (++lp->tx_pkts_in_ring < NUM_TX_BUFS)
-               netif_wake_queue(dev);
-}
-
-static void el16_rx(struct net_device *dev)
-{
-       struct net_local *lp = netdev_priv(dev);
-       void __iomem *shmem = lp->base;
-       ushort rx_head = lp->rx_head;
-       ushort rx_tail = lp->rx_tail;
-       ushort boguscount = 10;
-       short frame_status;
-
-       while ((frame_status = readw(shmem+rx_head)) < 0) {   /* Command complete */
-               void __iomem *read_frame = lp->base + rx_head;
-               ushort rfd_cmd = readw(read_frame+2);
-               ushort next_rx_frame = readw(read_frame+4);
-               ushort data_buffer_addr = readw(read_frame+6);
-               void __iomem *data_frame = lp->base + data_buffer_addr;
-               ushort pkt_len = readw(data_frame);
-
-               if (rfd_cmd != 0 || data_buffer_addr != rx_head + 22 ||
-                   (pkt_len & 0xC000) != 0xC000) {
-                       pr_err("%s: Rx frame at %#x corrupted, "
-                              "status %04x cmd %04x next %04x "
-                              "data-buf @%04x %04x.\n",
-                              dev->name, rx_head, frame_status, rfd_cmd,
-                              next_rx_frame, data_buffer_addr, pkt_len);
-               } else if ((frame_status & 0x2000) == 0) {
-                       /* Frame Rxed, but with error. */
-                       dev->stats.rx_errors++;
-                       if (frame_status & 0x0800) dev->stats.rx_crc_errors++;
-                       if (frame_status & 0x0400) dev->stats.rx_frame_errors++;
-                       if (frame_status & 0x0200) dev->stats.rx_fifo_errors++;
-                       if (frame_status & 0x0100) dev->stats.rx_over_errors++;
-                       if (frame_status & 0x0080) dev->stats.rx_length_errors++;
-               } else {
-                       /* Malloc up new buffer. */
-                       struct sk_buff *skb;
-
-                       pkt_len &= 0x3fff;
-                       skb = dev_alloc_skb(pkt_len+2);
-                       if (skb == NULL) {
-                               pr_err("%s: Memory squeeze, dropping packet.\n",
-                                      dev->name);
-                               dev->stats.rx_dropped++;
-                               break;
-                       }
-
-                       skb_reserve(skb,2);
-
-                       /* 'skb->data' points to the start of sk_buff data area. */
-                       memcpy_fromio(skb_put(skb,pkt_len), data_frame + 10, pkt_len);
-
-                       skb->protocol=eth_type_trans(skb,dev);
-                       netif_rx(skb);
-                       dev->stats.rx_packets++;
-                       dev->stats.rx_bytes += pkt_len;
-               }
-
-               /* Clear the status word and set End-of-List on the rx frame. */
-               writew(0,read_frame);
-               writew(0xC000,read_frame+2);
-               /* Clear the end-of-list on the prev. RFD. */
-               writew(0x0000,lp->base + rx_tail + 2);
-
-               rx_tail = rx_head;
-               rx_head = next_rx_frame;
-               if (--boguscount == 0)
-                       break;
-       }
-
-       lp->rx_head = rx_head;
-       lp->rx_tail = rx_tail;
-}
-
-static void netdev_get_drvinfo(struct net_device *dev,
-                              struct ethtool_drvinfo *info)
-{
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       sprintf(info->bus_info, "ISA 0x%lx", dev->base_addr);
-}
-
-static u32 netdev_get_msglevel(struct net_device *dev)
-{
-       return debug;
-}
-
-static void netdev_set_msglevel(struct net_device *dev, u32 level)
-{
-       debug = level;
-}
-
-static const struct ethtool_ops netdev_ethtool_ops = {
-       .get_drvinfo            = netdev_get_drvinfo,
-       .get_msglevel           = netdev_get_msglevel,
-       .set_msglevel           = netdev_set_msglevel,
-};
-
-#ifdef MODULE
-static struct net_device *dev_3c507;
-module_param(io, int, 0);
-module_param(irq, int, 0);
-MODULE_PARM_DESC(io, "EtherLink16 I/O base address");
-MODULE_PARM_DESC(irq, "(ignored)");
-
-int __init init_module(void)
-{
-       if (io == 0)
-               pr_notice("3c507: You should not use auto-probing with insmod!\n");
-       dev_3c507 = el16_probe(-1);
-       return IS_ERR(dev_3c507) ? PTR_ERR(dev_3c507) : 0;
-}
-
-void __exit
-cleanup_module(void)
-{
-       struct net_device *dev = dev_3c507;
-       unregister_netdev(dev);
-       free_irq(dev->irq, dev);
-       iounmap(((struct net_local *)netdev_priv(dev))->base);
-       release_region(dev->base_addr, EL16_IO_EXTENT);
-       free_netdev(dev);
-}
-#endif /* MODULE */
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c
deleted file mode 100644 (file)
index bc0d1a1..0000000
+++ /dev/null
@@ -1,1312 +0,0 @@
-/*
-   net-3-driver for the 3c523 Etherlink/MC card (i82586 Ethernet chip)
-
-
-   This is an extension to the Linux operating system, and is covered by the
-   same GNU General Public License that covers that work.
-
-   Copyright 1995, 1996 by Chris Beauregard (cpbeaure@undergrad.math.uwaterloo.ca)
-
-   This is basically Michael Hipp's ni52 driver, with a new probing
-   algorithm and some minor changes to the 82586 CA and reset routines.
-   Thanks a lot Michael for a really clean i82586 implementation!  Unless
-   otherwise documented in ni52.c, any bugs are mine.
-
-   Contrary to the Ethernet-HOWTO, this isn't based on the 3c507 driver in
-   any way.  The ni52 is a lot easier to modify.
-
-   sources:
-   ni52.c
-
-   Crynwr packet driver collection was a great reference for my first
-   attempt at this sucker.  The 3c507 driver also helped, until I noticed
-   that ni52.c was a lot nicer.
-
-   EtherLink/MC: Micro Channel Ethernet Adapter Technical Reference
-   Manual, courtesy of 3Com CardFacts, documents the 3c523-specific
-   stuff.  Information on CardFacts is found in the Ethernet HOWTO.
-   Also see <a href="http://www.3com.com/">
-
-   Microprocessor Communications Support Chips, T.J. Byers, ISBN
-   0-444-01224-9, has a section on the i82586.  It tells you just enough
-   to know that you really don't want to learn how to program the chip.
-
-   The original device probe code was stolen from ps2esdi.c
-
-   Known Problems:
-   Since most of the code was stolen from ni52.c, you'll run across the
-   same bugs in the 0.62 version of ni52.c, plus maybe a few because of
-   the 3c523 idiosynchacies.  The 3c523 has 16K of RAM though, so there
-   shouldn't be the overrun problem that the 8K ni52 has.
-
-   This driver is for a 16K adapter.  It should work fine on the 64K
-   adapters, but it will only use one of the 4 banks of RAM.  Modifying
-   this for the 64K version would require a lot of heinous bank
-   switching, which I'm sure not interested in doing.  If you try to
-   implement a bank switching version, you'll basically have to remember
-   what bank is enabled and do a switch every time you access a memory
-   location that's not current.  You'll also have to remap pointers on
-   the driver side, because it only knows about 16K of the memory.
-   Anyone desperate or masochistic enough to try?
-
-   It seems to be stable now when multiple transmit buffers are used.  I
-   can't see any performance difference, but then I'm working on a 386SX.
-
-   Multicast doesn't work.  It doesn't even pretend to work.  Don't use
-   it.  Don't compile your kernel with multicast support.  I don't know
-   why.
-
-   Features:
-   This driver is useable as a loadable module.  If you try to specify an
-   IRQ or a IO address (via insmod 3c523.o irq=xx io=0xyyy), it will
-   search the MCA slots until it finds a 3c523 with the specified
-   parameters.
-
-   This driver does support multiple ethernet cards when used as a module
-   (up to MAX_3C523_CARDS, the default being 4)
-
-   This has been tested with both BNC and TP versions, internal and
-   external transceivers.  Haven't tested with the 64K version (that I
-   know of).
-
-   History:
-   Jan 1st, 1996
-   first public release
-   Feb 4th, 1996
-   update to 1.3.59, incorporated multicast diffs from ni52.c
-   Feb 15th, 1996
-   added shared irq support
-   Apr 1999
-   added support for multiple cards when used as a module
-   added option to disable multicast as is causes problems
-       Ganesh Sittampalam <ganesh.sittampalam@magdalen.oxford.ac.uk>
-       Stuart Adamson <stuart.adamson@compsoc.net>
-   Nov 2001
-   added support for ethtool (jgarzik)
-
-   $Header: /fsys2/home/chrisb/linux-1.3.59-MCA/drivers/net/RCS/3c523.c,v 1.1 1996/02/05 01:53:46 chrisb Exp chrisb $
- */
-
-#define DRV_NAME               "3c523"
-#define DRV_VERSION            "17-Nov-2001"
-
-#include <linux/init.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/skbuff.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/mca-legacy.h>
-#include <linux/ethtool.h>
-#include <linux/bitops.h>
-#include <linux/jiffies.h>
-
-#include <asm/uaccess.h>
-#include <asm/processor.h>
-#include <asm/io.h>
-
-#include "3c523.h"
-
-/*************************************************************************/
-#define DEBUG                  /* debug on */
-#define SYSBUSVAL 0            /* 1 = 8 Bit, 0 = 16 bit - 3c523 only does 16 bit */
-#undef ELMC_MULTICAST          /* Disable multicast support as it is somewhat seriously broken at the moment */
-
-#define make32(ptr16) (p->memtop + (short) (ptr16) )
-#define make24(ptr32) ((char *) (ptr32) - p->base)
-#define make16(ptr32) ((unsigned short) ((unsigned long) (ptr32) - (unsigned long) p->memtop ))
-
-/*************************************************************************/
-/*
-   Tables to which we can map values in the configuration registers.
- */
-static int irq_table[] __initdata = {
-       12, 7, 3, 9
-};
-
-static int csr_table[] __initdata = {
-       0x300, 0x1300, 0x2300, 0x3300
-};
-
-static int shm_table[] __initdata = {
-       0x0c0000, 0x0c8000, 0x0d0000, 0x0d8000
-};
-
-/******************* how to calculate the buffers *****************************
-
-
-  * IMPORTANT NOTE: if you configure only one NUM_XMIT_BUFFS, the driver works
-  * --------------- in a different (more stable?) mode. Only in this mode it's
-  *                 possible to configure the driver with 'NO_NOPCOMMANDS'
-
-sizeof(scp)=12; sizeof(scb)=16; sizeof(iscp)=8;
-sizeof(scp)+sizeof(iscp)+sizeof(scb) = 36 = INIT
-sizeof(rfd) = 24; sizeof(rbd) = 12;
-sizeof(tbd) = 8; sizeof(transmit_cmd) = 16;
-sizeof(nop_cmd) = 8;
-
-  * if you don't know the driver, better do not change this values: */
-
-#define RECV_BUFF_SIZE 1524    /* slightly oversized */
-#define XMIT_BUFF_SIZE 1524    /* slightly oversized */
-#define NUM_XMIT_BUFFS 1       /* config for both, 8K and 16K shmem */
-#define NUM_RECV_BUFFS_8  4    /* config for 8K shared mem */
-#define NUM_RECV_BUFFS_16 9    /* config for 16K shared mem */
-
-#if (NUM_XMIT_BUFFS == 1)
-#define NO_NOPCOMMANDS         /* only possible with NUM_XMIT_BUFFS=1 */
-#endif
-
-/**************************************************************************/
-
-#define DELAY(x) { mdelay(32 * x); }
-
-/* a much shorter delay: */
-#define DELAY_16(); { udelay(16) ; }
-
-/* wait for command with timeout: */
-#define WAIT_4_SCB_CMD() { int i; \
-  for(i=0;i<1024;i++) { \
-    if(!p->scb->cmd) break; \
-    DELAY_16(); \
-    if(i == 1023) { \
-      pr_warning("%s:%d: scb_cmd timed out .. resetting i82586\n",\
-       dev->name,__LINE__); \
-      elmc_id_reset586(); } } }
-
-static irqreturn_t elmc_interrupt(int irq, void *dev_id);
-static int elmc_open(struct net_device *dev);
-static int elmc_close(struct net_device *dev);
-static netdev_tx_t elmc_send_packet(struct sk_buff *, struct net_device *);
-static struct net_device_stats *elmc_get_stats(struct net_device *dev);
-static void elmc_timeout(struct net_device *dev);
-#ifdef ELMC_MULTICAST
-static void set_multicast_list(struct net_device *dev);
-#endif
-static const struct ethtool_ops netdev_ethtool_ops;
-
-/* helper-functions */
-static int init586(struct net_device *dev);
-static int check586(struct net_device *dev, unsigned long where, unsigned size);
-static void alloc586(struct net_device *dev);
-static void startrecv586(struct net_device *dev);
-static void *alloc_rfa(struct net_device *dev, void *ptr);
-static void elmc_rcv_int(struct net_device *dev);
-static void elmc_xmt_int(struct net_device *dev);
-static void elmc_rnr_int(struct net_device *dev);
-
-struct priv {
-       unsigned long base;
-       char *memtop;
-       unsigned long mapped_start;             /* Start of ioremap */
-       volatile struct rfd_struct *rfd_last, *rfd_top, *rfd_first;
-       volatile struct scp_struct *scp;        /* volatile is important */
-       volatile struct iscp_struct *iscp;      /* volatile is important */
-       volatile struct scb_struct *scb;        /* volatile is important */
-       volatile struct tbd_struct *xmit_buffs[NUM_XMIT_BUFFS];
-#if (NUM_XMIT_BUFFS == 1)
-       volatile struct transmit_cmd_struct *xmit_cmds[2];
-       volatile struct nop_cmd_struct *nop_cmds[2];
-#else
-       volatile struct transmit_cmd_struct *xmit_cmds[NUM_XMIT_BUFFS];
-       volatile struct nop_cmd_struct *nop_cmds[NUM_XMIT_BUFFS];
-#endif
-       volatile int nop_point, num_recv_buffs;
-       volatile char *xmit_cbuffs[NUM_XMIT_BUFFS];
-       volatile int xmit_count, xmit_last;
-       volatile int slot;
-};
-
-#define elmc_attn586()  {elmc_do_attn586(dev->base_addr,ELMC_CTRL_INTE);}
-#define elmc_reset586() {elmc_do_reset586(dev->base_addr,ELMC_CTRL_INTE);}
-
-/* with interrupts disabled - this will clear the interrupt bit in the
-   3c523 control register, and won't put it back.  This effectively
-   disables interrupts on the card. */
-#define elmc_id_attn586()  {elmc_do_attn586(dev->base_addr,0);}
-#define elmc_id_reset586() {elmc_do_reset586(dev->base_addr,0);}
-
-/*************************************************************************/
-/*
-   Do a Channel Attention on the 3c523.  This is extremely board dependent.
- */
-static void elmc_do_attn586(int ioaddr, int ints)
-{
-       /* the 3c523 requires a minimum of 500 ns.  The delays here might be
-          a little too large, and hence they may cut the performance of the
-          card slightly.  If someone who knows a little more about Linux
-          timing would care to play with these, I'd appreciate it. */
-
-       /* this bit masking stuff is crap.  I'd rather have separate
-          registers with strobe triggers for each of these functions.  <sigh>
-          Ya take what ya got. */
-
-       outb(ELMC_CTRL_RST | 0x3 | ELMC_CTRL_CA | ints, ioaddr + ELMC_CTRL);
-       DELAY_16();             /* > 500 ns */
-       outb(ELMC_CTRL_RST | 0x3 | ints, ioaddr + ELMC_CTRL);
-}
-
-/*************************************************************************/
-/*
-   Reset the 82586 on the 3c523.  Also very board dependent.
- */
-static void elmc_do_reset586(int ioaddr, int ints)
-{
-       /* toggle the RST bit low then high */
-       outb(0x3 | ELMC_CTRL_LBK, ioaddr + ELMC_CTRL);
-       DELAY_16();             /* > 500 ns */
-       outb(ELMC_CTRL_RST | ELMC_CTRL_LBK | 0x3, ioaddr + ELMC_CTRL);
-
-       elmc_do_attn586(ioaddr, ints);
-}
-
-/**********************************************
- * close device
- */
-
-static int elmc_close(struct net_device *dev)
-{
-       netif_stop_queue(dev);
-       elmc_id_reset586();     /* the hard way to stop the receiver */
-       free_irq(dev->irq, dev);
-       return 0;
-}
-
-/**********************************************
- * open device
- */
-
-static int elmc_open(struct net_device *dev)
-{
-       int ret;
-
-       elmc_id_attn586();      /* disable interrupts */
-
-       ret = request_irq(dev->irq, elmc_interrupt, IRQF_SHARED,
-                         dev->name, dev);
-       if (ret) {
-               pr_err("%s: couldn't get irq %d\n", dev->name, dev->irq);
-               elmc_id_reset586();
-               return ret;
-       }
-       alloc586(dev);
-       init586(dev);
-       startrecv586(dev);
-       netif_start_queue(dev);
-       return 0;               /* most done by init */
-}
-
-/**********************************************
- * Check to see if there's an 82586 out there.
- */
-
-static int __init check586(struct net_device *dev, unsigned long where, unsigned size)
-{
-       struct priv *p = netdev_priv(dev);
-       char *iscp_addrs[2];
-       int i = 0;
-
-       p->base = (unsigned long) isa_bus_to_virt((unsigned long)where) + size - 0x01000000;
-       p->memtop = isa_bus_to_virt((unsigned long)where) + size;
-       p->scp = (struct scp_struct *)(p->base + SCP_DEFAULT_ADDRESS);
-       memset((char *) p->scp, 0, sizeof(struct scp_struct));
-       p->scp->sysbus = SYSBUSVAL;     /* 1 = 8Bit-Bus, 0 = 16 Bit */
-
-       iscp_addrs[0] = isa_bus_to_virt((unsigned long)where);
-       iscp_addrs[1] = (char *) p->scp - sizeof(struct iscp_struct);
-
-       for (i = 0; i < 2; i++) {
-               p->iscp = (struct iscp_struct *) iscp_addrs[i];
-               memset((char *) p->iscp, 0, sizeof(struct iscp_struct));
-
-               p->scp->iscp = make24(p->iscp);
-               p->iscp->busy = 1;
-
-               elmc_id_reset586();
-
-               /* reset586 does an implicit CA */
-
-               /* apparently, you sometimes have to kick the 82586 twice... */
-               elmc_id_attn586();
-               DELAY(1);
-
-               if (p->iscp->busy) {    /* i82586 clears 'busy' after successful init */
-                       return 0;
-               }
-       }
-       return 1;
-}
-
-/******************************************************************
- * set iscp at the right place, called by elmc_probe and open586.
- */
-
-static void alloc586(struct net_device *dev)
-{
-       struct priv *p = netdev_priv(dev);
-
-       elmc_id_reset586();
-       DELAY(2);
-
-       p->scp = (struct scp_struct *) (p->base + SCP_DEFAULT_ADDRESS);
-       p->scb = (struct scb_struct *) isa_bus_to_virt(dev->mem_start);
-       p->iscp = (struct iscp_struct *) ((char *) p->scp - sizeof(struct iscp_struct));
-
-       memset((char *) p->iscp, 0, sizeof(struct iscp_struct));
-       memset((char *) p->scp, 0, sizeof(struct scp_struct));
-
-       p->scp->iscp = make24(p->iscp);
-       p->scp->sysbus = SYSBUSVAL;
-       p->iscp->scb_offset = make16(p->scb);
-
-       p->iscp->busy = 1;
-       elmc_id_reset586();
-       elmc_id_attn586();
-
-       DELAY(2);
-
-       if (p->iscp->busy)
-               pr_err("%s: Init-Problems (alloc).\n", dev->name);
-
-       memset((char *) p->scb, 0, sizeof(struct scb_struct));
-}
-
-/*****************************************************************/
-
-static int elmc_getinfo(char *buf, int slot, void *d)
-{
-       int len = 0;
-       struct net_device *dev = d;
-
-       if (dev == NULL)
-               return len;
-
-       len += sprintf(buf + len, "Revision: 0x%x\n",
-                      inb(dev->base_addr + ELMC_REVISION) & 0xf);
-       len += sprintf(buf + len, "IRQ: %d\n", dev->irq);
-       len += sprintf(buf + len, "IO Address: %#lx-%#lx\n", dev->base_addr,
-                      dev->base_addr + ELMC_IO_EXTENT);
-       len += sprintf(buf + len, "Memory: %#lx-%#lx\n", dev->mem_start,
-                      dev->mem_end - 1);
-       len += sprintf(buf + len, "Transceiver: %s\n", dev->if_port ?
-                      "External" : "Internal");
-       len += sprintf(buf + len, "Device: %s\n", dev->name);
-       len += sprintf(buf + len, "Hardware Address: %pM\n",
-                      dev->dev_addr);
-
-       return len;
-}                              /* elmc_getinfo() */
-
-static const struct net_device_ops netdev_ops = {
-       .ndo_open               = elmc_open,
-       .ndo_stop               = elmc_close,
-       .ndo_get_stats          = elmc_get_stats,
-       .ndo_start_xmit         = elmc_send_packet,
-       .ndo_tx_timeout         = elmc_timeout,
-#ifdef ELMC_MULTICAST
-       .ndo_set_multicast_list = set_multicast_list,
-#endif
-       .ndo_change_mtu         = eth_change_mtu,
-       .ndo_set_mac_address    = eth_mac_addr,
-       .ndo_validate_addr      = eth_validate_addr,
-};
-
-/*****************************************************************/
-
-static int __init do_elmc_probe(struct net_device *dev)
-{
-       static int slot;
-       int base_addr = dev->base_addr;
-       int irq = dev->irq;
-       u_char status = 0;
-       u_char revision = 0;
-       int i = 0;
-       unsigned int size = 0;
-       int retval;
-       struct priv *pr = netdev_priv(dev);
-
-       if (MCA_bus == 0) {
-               return -ENODEV;
-       }
-       /* search through the slots for the 3c523. */
-       slot = mca_find_adapter(ELMC_MCA_ID, 0);
-       while (slot != -1) {
-               status = mca_read_stored_pos(slot, 2);
-
-               dev->irq=irq_table[(status & ELMC_STATUS_IRQ_SELECT) >> 6];
-               dev->base_addr=csr_table[(status & ELMC_STATUS_CSR_SELECT) >> 1];
-
-               /*
-                  If we're trying to match a specified irq or IO address,
-                  we'll reject a match unless it's what we're looking for.
-                  Also reject it if the card is already in use.
-                */
-
-               if ((irq && irq != dev->irq) ||
-                   (base_addr && base_addr != dev->base_addr)) {
-                       slot = mca_find_adapter(ELMC_MCA_ID, slot + 1);
-                       continue;
-               }
-               if (!request_region(dev->base_addr, ELMC_IO_EXTENT, DRV_NAME)) {
-                       slot = mca_find_adapter(ELMC_MCA_ID, slot + 1);
-                       continue;
-               }
-
-               /* found what we're looking for... */
-               break;
-       }
-
-       /* we didn't find any 3c523 in the slots we checked for */
-       if (slot == MCA_NOTFOUND)
-               return (base_addr || irq) ? -ENXIO : -ENODEV;
-
-       mca_set_adapter_name(slot, "3Com 3c523 Etherlink/MC");
-       mca_set_adapter_procfn(slot, (MCA_ProcFn) elmc_getinfo, dev);
-
-       /* if we get this far, adapter has been found - carry on */
-       pr_info("%s: 3c523 adapter found in slot %d\n", dev->name, slot + 1);
-
-       /* Now we extract configuration info from the card.
-          The 3c523 provides information in two of the POS registers, but
-          the second one is only needed if we want to tell the card what IRQ
-          to use.  I suspect that whoever sets the thing up initially would
-          prefer we don't screw with those things.
-
-          Note that we read the status info when we found the card...
-
-          See 3c523.h for more details.
-        */
-
-       /* revision is stored in the first 4 bits of the revision register */
-       revision = inb(dev->base_addr + ELMC_REVISION) & 0xf;
-
-       /* according to docs, we read the interrupt and write it back to
-          the IRQ select register, since the POST might not configure the IRQ
-          properly. */
-       switch (dev->irq) {
-       case 3:
-               mca_write_pos(slot, 3, 0x04);
-               break;
-       case 7:
-               mca_write_pos(slot, 3, 0x02);
-               break;
-       case 9:
-               mca_write_pos(slot, 3, 0x08);
-               break;
-       case 12:
-               mca_write_pos(slot, 3, 0x01);
-               break;
-       }
-
-       pr->slot = slot;
-
-       pr_info("%s: 3Com 3c523 Rev 0x%x at %#lx\n", dev->name, (int) revision,
-              dev->base_addr);
-
-       /* Determine if we're using the on-board transceiver (i.e. coax) or
-          an external one.  The information is pretty much useless, but I
-          guess it's worth brownie points. */
-       dev->if_port = (status & ELMC_STATUS_DISABLE_THIN);
-
-       /* The 3c523 has a 24K chunk of memory.  The first 16K is the
-          shared memory, while the last 8K is for the EtherStart BIOS ROM.
-          Which we don't care much about here.  We'll just tell Linux that
-          we're using 16K.  MCA won't permit address space conflicts caused
-          by not mapping the other 8K. */
-       dev->mem_start = shm_table[(status & ELMC_STATUS_MEMORY_SELECT) >> 3];
-
-       /* We're using MCA, so it's a given that the information about memory
-          size is correct.  The Crynwr drivers do something like this. */
-
-       elmc_id_reset586();     /* seems like a good idea before checking it... */
-
-       size = 0x4000;          /* check for 16K mem */
-       if (!check586(dev, dev->mem_start, size)) {
-               pr_err("%s: memprobe, Can't find memory at 0x%lx!\n", dev->name,
-                      dev->mem_start);
-               retval = -ENODEV;
-               goto err_out;
-       }
-       dev->mem_end = dev->mem_start + size;   /* set mem_end showed by 'ifconfig' */
-
-       pr->memtop = isa_bus_to_virt(dev->mem_start) + size;
-       pr->base = (unsigned long) isa_bus_to_virt(dev->mem_start) + size - 0x01000000;
-       alloc586(dev);
-
-       elmc_id_reset586();     /* make sure it doesn't generate spurious ints */
-
-       /* set number of receive-buffs according to memsize */
-       pr->num_recv_buffs = NUM_RECV_BUFFS_16;
-
-       /* dump all the assorted information */
-       pr_info("%s: IRQ %d, %sternal xcvr, memory %#lx-%#lx.\n", dev->name,
-              dev->irq, dev->if_port ? "ex" : "in",
-              dev->mem_start, dev->mem_end - 1);
-
-       /* The hardware address for the 3c523 is stored in the first six
-          bytes of the IO address. */
-       for (i = 0; i < 6; i++)
-               dev->dev_addr[i] = inb(dev->base_addr + i);
-
-       pr_info("%s: hardware address %pM\n",
-              dev->name, dev->dev_addr);
-
-       dev->netdev_ops = &netdev_ops;
-       dev->watchdog_timeo = HZ;
-       dev->ethtool_ops = &netdev_ethtool_ops;
-
-       /* note that we haven't actually requested the IRQ from the kernel.
-          That gets done in elmc_open().  I'm not sure that's such a good idea,
-          but it works, so I'll go with it. */
-
-#ifndef ELMC_MULTICAST
-        dev->flags&=~IFF_MULTICAST;     /* Multicast doesn't work */
-#endif
-
-       retval = register_netdev(dev);
-       if (retval)
-               goto err_out;
-
-       return 0;
-err_out:
-       mca_set_adapter_procfn(slot, NULL, NULL);
-       release_region(dev->base_addr, ELMC_IO_EXTENT);
-       return retval;
-}
-
-#ifdef MODULE
-static void cleanup_card(struct net_device *dev)
-{
-       mca_set_adapter_procfn(((struct priv *)netdev_priv(dev))->slot,
-                               NULL, NULL);
-       release_region(dev->base_addr, ELMC_IO_EXTENT);
-}
-#else
-struct net_device * __init elmc_probe(int unit)
-{
-       struct net_device *dev = alloc_etherdev(sizeof(struct priv));
-       int err;
-
-       if (!dev)
-               return ERR_PTR(-ENOMEM);
-
-       sprintf(dev->name, "eth%d", unit);
-       netdev_boot_setup_check(dev);
-
-       err = do_elmc_probe(dev);
-       if (err)
-               goto out;
-       return dev;
-out:
-       free_netdev(dev);
-       return ERR_PTR(err);
-}
-#endif
-
-/**********************************************
- * init the chip (elmc-interrupt should be disabled?!)
- * needs a correct 'allocated' memory
- */
-
-static int init586(struct net_device *dev)
-{
-       void *ptr;
-       unsigned long s;
-       int i, result = 0;
-       struct priv *p = netdev_priv(dev);
-       volatile struct configure_cmd_struct *cfg_cmd;
-       volatile struct iasetup_cmd_struct *ias_cmd;
-       volatile struct tdr_cmd_struct *tdr_cmd;
-       volatile struct mcsetup_cmd_struct *mc_cmd;
-       struct netdev_hw_addr *ha;
-       int num_addrs = netdev_mc_count(dev);
-
-       ptr = (void *) ((char *) p->scb + sizeof(struct scb_struct));
-
-       cfg_cmd = (struct configure_cmd_struct *) ptr;  /* configure-command */
-       cfg_cmd->cmd_status = 0;
-       cfg_cmd->cmd_cmd = CMD_CONFIGURE | CMD_LAST;
-       cfg_cmd->cmd_link = 0xffff;
-
-       cfg_cmd->byte_cnt = 0x0a;       /* number of cfg bytes */
-       cfg_cmd->fifo = 0x08;   /* fifo-limit (8=tx:32/rx:64) */
-       cfg_cmd->sav_bf = 0x40; /* hold or discard bad recv frames (bit 7) */
-       cfg_cmd->adr_len = 0x2e;        /* addr_len |!src_insert |pre-len |loopback */
-       cfg_cmd->priority = 0x00;
-       cfg_cmd->ifs = 0x60;
-       cfg_cmd->time_low = 0x00;
-       cfg_cmd->time_high = 0xf2;
-       cfg_cmd->promisc = 0;
-       if (dev->flags & (IFF_ALLMULTI | IFF_PROMISC))
-               cfg_cmd->promisc = 1;
-       cfg_cmd->carr_coll = 0x00;
-
-       p->scb->cbl_offset = make16(cfg_cmd);
-
-       p->scb->cmd = CUC_START;        /* cmd.-unit start */
-       elmc_id_attn586();
-
-       s = jiffies;            /* warning: only active with interrupts on !! */
-       while (!(cfg_cmd->cmd_status & STAT_COMPL)) {
-               if (time_after(jiffies, s + 30*HZ/100))
-                       break;
-       }
-
-       if ((cfg_cmd->cmd_status & (STAT_OK | STAT_COMPL)) != (STAT_COMPL | STAT_OK)) {
-               pr_warning("%s (elmc): configure command failed: %x\n", dev->name, cfg_cmd->cmd_status);
-               return 1;
-       }
-       /*
-        * individual address setup
-        */
-       ias_cmd = (struct iasetup_cmd_struct *) ptr;
-
-       ias_cmd->cmd_status = 0;
-       ias_cmd->cmd_cmd = CMD_IASETUP | CMD_LAST;
-       ias_cmd->cmd_link = 0xffff;
-
-       memcpy((char *) &ias_cmd->iaddr, (char *) dev->dev_addr, ETH_ALEN);
-
-       p->scb->cbl_offset = make16(ias_cmd);
-
-       p->scb->cmd = CUC_START;        /* cmd.-unit start */
-       elmc_id_attn586();
-
-       s = jiffies;
-       while (!(ias_cmd->cmd_status & STAT_COMPL)) {
-               if (time_after(jiffies, s + 30*HZ/100))
-                       break;
-       }
-
-       if ((ias_cmd->cmd_status & (STAT_OK | STAT_COMPL)) != (STAT_OK | STAT_COMPL)) {
-               pr_warning("%s (elmc): individual address setup command failed: %04x\n",
-                       dev->name, ias_cmd->cmd_status);
-               return 1;
-       }
-       /*
-        * TDR, wire check .. e.g. no resistor e.t.c
-        */
-       tdr_cmd = (struct tdr_cmd_struct *) ptr;
-
-       tdr_cmd->cmd_status = 0;
-       tdr_cmd->cmd_cmd = CMD_TDR | CMD_LAST;
-       tdr_cmd->cmd_link = 0xffff;
-       tdr_cmd->status = 0;
-
-       p->scb->cbl_offset = make16(tdr_cmd);
-
-       p->scb->cmd = CUC_START;        /* cmd.-unit start */
-       elmc_attn586();
-
-       s = jiffies;
-       while (!(tdr_cmd->cmd_status & STAT_COMPL)) {
-               if (time_after(jiffies, s + 30*HZ/100)) {
-                       pr_warning("%s: %d Problems while running the TDR.\n", dev->name, __LINE__);
-                       result = 1;
-                       break;
-               }
-       }
-
-       if (!result) {
-               DELAY(2);       /* wait for result */
-               result = tdr_cmd->status;
-
-               p->scb->cmd = p->scb->status & STAT_MASK;
-               elmc_id_attn586();      /* ack the interrupts */
-
-               if (result & TDR_LNK_OK) {
-                       /* empty */
-               } else if (result & TDR_XCVR_PRB) {
-                       pr_warning("%s: TDR: Transceiver problem!\n", dev->name);
-               } else if (result & TDR_ET_OPN) {
-                       pr_warning("%s: TDR: No correct termination %d clocks away.\n", dev->name, result & TDR_TIMEMASK);
-               } else if (result & TDR_ET_SRT) {
-                       if (result & TDR_TIMEMASK)      /* time == 0 -> strange :-) */
-                               pr_warning("%s: TDR: Detected a short circuit %d clocks away.\n", dev->name, result & TDR_TIMEMASK);
-               } else {
-                       pr_warning("%s: TDR: Unknown status %04x\n", dev->name, result);
-               }
-       }
-       /*
-        * ack interrupts
-        */
-       p->scb->cmd = p->scb->status & STAT_MASK;
-       elmc_id_attn586();
-
-       /*
-        * alloc nop/xmit-cmds
-        */
-#if (NUM_XMIT_BUFFS == 1)
-       for (i = 0; i < 2; i++) {
-               p->nop_cmds[i] = (struct nop_cmd_struct *) ptr;
-               p->nop_cmds[i]->cmd_cmd = CMD_NOP;
-               p->nop_cmds[i]->cmd_status = 0;
-               p->nop_cmds[i]->cmd_link = make16((p->nop_cmds[i]));
-               ptr = (char *) ptr + sizeof(struct nop_cmd_struct);
-       }
-       p->xmit_cmds[0] = (struct transmit_cmd_struct *) ptr;   /* transmit cmd/buff 0 */
-       ptr = (char *) ptr + sizeof(struct transmit_cmd_struct);
-#else
-       for (i = 0; i < NUM_XMIT_BUFFS; i++) {
-               p->nop_cmds[i] = (struct nop_cmd_struct *) ptr;
-               p->nop_cmds[i]->cmd_cmd = CMD_NOP;
-               p->nop_cmds[i]->cmd_status = 0;
-               p->nop_cmds[i]->cmd_link = make16((p->nop_cmds[i]));
-               ptr = (char *) ptr + sizeof(struct nop_cmd_struct);
-               p->xmit_cmds[i] = (struct transmit_cmd_struct *) ptr;   /*transmit cmd/buff 0 */
-               ptr = (char *) ptr + sizeof(struct transmit_cmd_struct);
-       }
-#endif
-
-       ptr = alloc_rfa(dev, (void *) ptr);     /* init receive-frame-area */
-
-       /*
-        * Multicast setup
-        */
-
-       if (num_addrs) {
-               /* I don't understand this: do we really need memory after the init? */
-               int len = ((char *) p->iscp - (char *) ptr - 8) / 6;
-               if (len <= 0) {
-                       pr_err("%s: Ooooops, no memory for MC-Setup!\n", dev->name);
-               } else {
-                       if (len < num_addrs) {
-                               num_addrs = len;
-                               pr_warning("%s: Sorry, can only apply %d MC-Address(es).\n",
-                                      dev->name, num_addrs);
-                       }
-                       mc_cmd = (struct mcsetup_cmd_struct *) ptr;
-                       mc_cmd->cmd_status = 0;
-                       mc_cmd->cmd_cmd = CMD_MCSETUP | CMD_LAST;
-                       mc_cmd->cmd_link = 0xffff;
-                       mc_cmd->mc_cnt = num_addrs * 6;
-                       i = 0;
-                       netdev_for_each_mc_addr(ha, dev)
-                               memcpy((char *) mc_cmd->mc_list[i++],
-                                      ha->addr, 6);
-                       p->scb->cbl_offset = make16(mc_cmd);
-                       p->scb->cmd = CUC_START;
-                       elmc_id_attn586();
-                       s = jiffies;
-                       while (!(mc_cmd->cmd_status & STAT_COMPL)) {
-                               if (time_after(jiffies, s + 30*HZ/100))
-                                       break;
-                       }
-                       if (!(mc_cmd->cmd_status & STAT_COMPL)) {
-                               pr_warning("%s: Can't apply multicast-address-list.\n", dev->name);
-                       }
-               }
-       }
-       /*
-        * alloc xmit-buffs / init xmit_cmds
-        */
-       for (i = 0; i < NUM_XMIT_BUFFS; i++) {
-               p->xmit_cbuffs[i] = (char *) ptr;       /* char-buffs */
-               ptr = (char *) ptr + XMIT_BUFF_SIZE;
-               p->xmit_buffs[i] = (struct tbd_struct *) ptr;   /* TBD */
-               ptr = (char *) ptr + sizeof(struct tbd_struct);
-               if ((void *) ptr > (void *) p->iscp) {
-                       pr_err("%s: not enough shared-mem for your configuration!\n", dev->name);
-                       return 1;
-               }
-               memset((char *) (p->xmit_cmds[i]), 0, sizeof(struct transmit_cmd_struct));
-               memset((char *) (p->xmit_buffs[i]), 0, sizeof(struct tbd_struct));
-               p->xmit_cmds[i]->cmd_status = STAT_COMPL;
-               p->xmit_cmds[i]->cmd_cmd = CMD_XMIT | CMD_INT;
-               p->xmit_cmds[i]->tbd_offset = make16((p->xmit_buffs[i]));
-               p->xmit_buffs[i]->next = 0xffff;
-               p->xmit_buffs[i]->buffer = make24((p->xmit_cbuffs[i]));
-       }
-
-       p->xmit_count = 0;
-       p->xmit_last = 0;
-#ifndef NO_NOPCOMMANDS
-       p->nop_point = 0;
-#endif
-
-       /*
-        * 'start transmitter' (nop-loop)
-        */
-#ifndef NO_NOPCOMMANDS
-       p->scb->cbl_offset = make16(p->nop_cmds[0]);
-       p->scb->cmd = CUC_START;
-       elmc_id_attn586();
-       WAIT_4_SCB_CMD();
-#else
-       p->xmit_cmds[0]->cmd_link = 0xffff;
-       p->xmit_cmds[0]->cmd_cmd = CMD_XMIT | CMD_LAST | CMD_INT;
-#endif
-
-       return 0;
-}
-
-/******************************************************
- * This is a helper routine for elmc_rnr_int() and init586().
- * It sets up the Receive Frame Area (RFA).
- */
-
-static void *alloc_rfa(struct net_device *dev, void *ptr)
-{
-       volatile struct rfd_struct *rfd = (struct rfd_struct *) ptr;
-       volatile struct rbd_struct *rbd;
-       int i;
-       struct priv *p = netdev_priv(dev);
-
-       memset((char *) rfd, 0, sizeof(struct rfd_struct) * p->num_recv_buffs);
-       p->rfd_first = rfd;
-
-       for (i = 0; i < p->num_recv_buffs; i++) {
-               rfd[i].next = make16(rfd + (i + 1) % p->num_recv_buffs);
-       }
-       rfd[p->num_recv_buffs - 1].last = RFD_SUSP;     /* RU suspend */
-
-       ptr = (void *) (rfd + p->num_recv_buffs);
-
-       rbd = (struct rbd_struct *) ptr;
-       ptr = (void *) (rbd + p->num_recv_buffs);
-
-       /* clr descriptors */
-       memset((char *) rbd, 0, sizeof(struct rbd_struct) * p->num_recv_buffs);
-
-       for (i = 0; i < p->num_recv_buffs; i++) {
-               rbd[i].next = make16((rbd + (i + 1) % p->num_recv_buffs));
-               rbd[i].size = RECV_BUFF_SIZE;
-               rbd[i].buffer = make24(ptr);
-               ptr = (char *) ptr + RECV_BUFF_SIZE;
-       }
-
-       p->rfd_top = p->rfd_first;
-       p->rfd_last = p->rfd_first + p->num_recv_buffs - 1;
-
-       p->scb->rfa_offset = make16(p->rfd_first);
-       p->rfd_first->rbd_offset = make16(rbd);
-
-       return ptr;
-}
-
-
-/**************************************************
- * Interrupt Handler ...
- */
-
-static irqreturn_t
-elmc_interrupt(int irq, void *dev_id)
-{
-       struct net_device *dev = dev_id;
-       unsigned short stat;
-       struct priv *p;
-
-       if (!netif_running(dev)) {
-               /* The 3c523 has this habit of generating interrupts during the
-                  reset.  I'm not sure if the ni52 has this same problem, but it's
-                  really annoying if we haven't finished initializing it.  I was
-                  hoping all the elmc_id_* commands would disable this, but I
-                  might have missed a few. */
-
-               elmc_id_attn586();      /* ack inter. and disable any more */
-               return IRQ_HANDLED;
-       } else if (!(ELMC_CTRL_INT & inb(dev->base_addr + ELMC_CTRL))) {
-               /* wasn't this device */
-               return IRQ_NONE;
-       }
-       /* reading ELMC_CTRL also clears the INT bit. */
-
-       p = netdev_priv(dev);
-
-       while ((stat = p->scb->status & STAT_MASK))
-       {
-               p->scb->cmd = stat;
-               elmc_attn586(); /* ack inter. */
-
-               if (stat & STAT_CX) {
-                       /* command with I-bit set complete */
-                       elmc_xmt_int(dev);
-               }
-               if (stat & STAT_FR) {
-                       /* received a frame */
-                       elmc_rcv_int(dev);
-               }
-#ifndef NO_NOPCOMMANDS
-               if (stat & STAT_CNA) {
-                       /* CU went 'not ready' */
-                       if (netif_running(dev)) {
-                               pr_warning("%s: oops! CU has left active state. stat: %04x/%04x.\n",
-                                       dev->name, (int) stat, (int) p->scb->status);
-                       }
-               }
-#endif
-
-               if (stat & STAT_RNR) {
-                       /* RU went 'not ready' */
-
-                       if (p->scb->status & RU_SUSPEND) {
-                               /* special case: RU_SUSPEND */
-
-                               WAIT_4_SCB_CMD();
-                               p->scb->cmd = RUC_RESUME;
-                               elmc_attn586();
-                       } else {
-                               pr_warning("%s: Receiver-Unit went 'NOT READY': %04x/%04x.\n",
-                                       dev->name, (int) stat, (int) p->scb->status);
-                               elmc_rnr_int(dev);
-                       }
-               }
-               WAIT_4_SCB_CMD();       /* wait for ack. (elmc_xmt_int can be faster than ack!!) */
-               if (p->scb->cmd) {      /* timed out? */
-                       break;
-               }
-       }
-       return IRQ_HANDLED;
-}
-
-/*******************************************************
- * receive-interrupt
- */
-
-static void elmc_rcv_int(struct net_device *dev)
-{
-       int status;
-       unsigned short totlen;
-       struct sk_buff *skb;
-       struct rbd_struct *rbd;
-       struct priv *p = netdev_priv(dev);
-
-       for (; (status = p->rfd_top->status) & STAT_COMPL;) {
-               rbd = (struct rbd_struct *) make32(p->rfd_top->rbd_offset);
-
-               if (status & STAT_OK) {         /* frame received without error? */
-                       if ((totlen = rbd->status) & RBD_LAST) {        /* the first and the last buffer? */
-                               totlen &= RBD_MASK;     /* length of this frame */
-                               rbd->status = 0;
-                               skb = (struct sk_buff *) dev_alloc_skb(totlen + 2);
-                               if (skb != NULL) {
-                                       skb_reserve(skb, 2);    /* 16 byte alignment */
-                                       skb_put(skb,totlen);
-                                       skb_copy_to_linear_data(skb, (char *) p->base+(unsigned long) rbd->buffer,totlen);
-                                       skb->protocol = eth_type_trans(skb, dev);
-                                       netif_rx(skb);
-                                       dev->stats.rx_packets++;
-                                       dev->stats.rx_bytes += totlen;
-                               } else {
-                                       dev->stats.rx_dropped++;
-                               }
-                       } else {
-                               pr_warning("%s: received oversized frame.\n", dev->name);
-                               dev->stats.rx_dropped++;
-                       }
-               } else {        /* frame !(ok), only with 'save-bad-frames' */
-                       pr_warning("%s: oops! rfd-error-status: %04x\n", dev->name, status);
-                       dev->stats.rx_errors++;
-               }
-               p->rfd_top->status = 0;
-               p->rfd_top->last = RFD_SUSP;
-               p->rfd_last->last = 0;  /* delete RU_SUSP  */
-               p->rfd_last = p->rfd_top;
-               p->rfd_top = (struct rfd_struct *) make32(p->rfd_top->next);    /* step to next RFD */
-       }
-}
-
-/**********************************************************
- * handle 'Receiver went not ready'.
- */
-
-static void elmc_rnr_int(struct net_device *dev)
-{
-       struct priv *p = netdev_priv(dev);
-
-       dev->stats.rx_errors++;
-
-       WAIT_4_SCB_CMD();       /* wait for the last cmd */
-       p->scb->cmd = RUC_ABORT;        /* usually the RU is in the 'no resource'-state .. abort it now. */
-       elmc_attn586();
-       WAIT_4_SCB_CMD();       /* wait for accept cmd. */
-
-       alloc_rfa(dev, (char *) p->rfd_first);
-       startrecv586(dev);      /* restart RU */
-
-       pr_warning("%s: Receive-Unit restarted. Status: %04x\n", dev->name, p->scb->status);
-
-}
-
-/**********************************************************
- * handle xmit - interrupt
- */
-
-static void elmc_xmt_int(struct net_device *dev)
-{
-       int status;
-       struct priv *p = netdev_priv(dev);
-
-       status = p->xmit_cmds[p->xmit_last]->cmd_status;
-       if (!(status & STAT_COMPL)) {
-               pr_warning("%s: strange .. xmit-int without a 'COMPLETE'\n", dev->name);
-       }
-       if (status & STAT_OK) {
-               dev->stats.tx_packets++;
-               dev->stats.collisions += (status & TCMD_MAXCOLLMASK);
-       } else {
-               dev->stats.tx_errors++;
-               if (status & TCMD_LATECOLL) {
-                       pr_warning("%s: late collision detected.\n", dev->name);
-                       dev->stats.collisions++;
-               } else if (status & TCMD_NOCARRIER) {
-                       dev->stats.tx_carrier_errors++;
-                       pr_warning("%s: no carrier detected.\n", dev->name);
-               } else if (status & TCMD_LOSTCTS) {
-                       pr_warning("%s: loss of CTS detected.\n", dev->name);
-               } else if (status & TCMD_UNDERRUN) {
-                       dev->stats.tx_fifo_errors++;
-                       pr_warning("%s: DMA underrun detected.\n", dev->name);
-               } else if (status & TCMD_MAXCOLL) {
-                       pr_warning("%s: Max. collisions exceeded.\n", dev->name);
-                       dev->stats.collisions += 16;
-               }
-       }
-
-#if (NUM_XMIT_BUFFS != 1)
-       if ((++p->xmit_last) == NUM_XMIT_BUFFS) {
-               p->xmit_last = 0;
-       }
-#endif
-
-       netif_wake_queue(dev);
-}
-
-/***********************************************************
- * (re)start the receiver
- */
-
-static void startrecv586(struct net_device *dev)
-{
-       struct priv *p = netdev_priv(dev);
-
-       p->scb->rfa_offset = make16(p->rfd_first);
-       p->scb->cmd = RUC_START;
-       elmc_attn586();         /* start cmd. */
-       WAIT_4_SCB_CMD();       /* wait for accept cmd. (no timeout!!) */
-}
-
-/******************************************************
- * timeout
- */
-
-static void elmc_timeout(struct net_device *dev)
-{
-       struct priv *p = netdev_priv(dev);
-       /* COMMAND-UNIT active? */
-       if (p->scb->status & CU_ACTIVE) {
-               pr_debug("%s: strange ... timeout with CU active?!?\n", dev->name);
-               pr_debug("%s: X0: %04x N0: %04x N1: %04x %d\n", dev->name,
-                       (int)p->xmit_cmds[0]->cmd_status,
-                       (int)p->nop_cmds[0]->cmd_status,
-                       (int)p->nop_cmds[1]->cmd_status, (int)p->nop_point);
-               p->scb->cmd = CUC_ABORT;
-               elmc_attn586();
-               WAIT_4_SCB_CMD();
-               p->scb->cbl_offset = make16(p->nop_cmds[p->nop_point]);
-               p->scb->cmd = CUC_START;
-               elmc_attn586();
-               WAIT_4_SCB_CMD();
-               netif_wake_queue(dev);
-       } else {
-               pr_debug("%s: xmitter timed out, try to restart! stat: %04x\n",
-                       dev->name, p->scb->status);
-               pr_debug("%s: command-stats: %04x %04x\n", dev->name,
-                       p->xmit_cmds[0]->cmd_status, p->xmit_cmds[1]->cmd_status);
-               elmc_close(dev);
-               elmc_open(dev);
-       }
-}
-
-/******************************************************
- * send frame
- */
-
-static netdev_tx_t elmc_send_packet(struct sk_buff *skb, struct net_device *dev)
-{
-       int len;
-       int i;
-#ifndef NO_NOPCOMMANDS
-       int next_nop;
-#endif
-       struct priv *p = netdev_priv(dev);
-
-       netif_stop_queue(dev);
-
-       len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
-
-       if (len != skb->len)
-               memset((char *) p->xmit_cbuffs[p->xmit_count], 0, ETH_ZLEN);
-       skb_copy_from_linear_data(skb, (char *) p->xmit_cbuffs[p->xmit_count], skb->len);
-
-#if (NUM_XMIT_BUFFS == 1)
-#ifdef NO_NOPCOMMANDS
-       p->xmit_buffs[0]->size = TBD_LAST | len;
-       for (i = 0; i < 16; i++) {
-               p->scb->cbl_offset = make16(p->xmit_cmds[0]);
-               p->scb->cmd = CUC_START;
-               p->xmit_cmds[0]->cmd_status = 0;
-                       elmc_attn586();
-               if (!i) {
-                       dev_kfree_skb(skb);
-               }
-               WAIT_4_SCB_CMD();
-               if ((p->scb->status & CU_ACTIVE)) {     /* test it, because CU sometimes doesn't start immediately */
-                       break;
-               }
-               if (p->xmit_cmds[0]->cmd_status) {
-                       break;
-               }
-               if (i == 15) {
-                       pr_warning("%s: Can't start transmit-command.\n", dev->name);
-               }
-       }
-#else
-       next_nop = (p->nop_point + 1) & 0x1;
-       p->xmit_buffs[0]->size = TBD_LAST | len;
-
-       p->xmit_cmds[0]->cmd_link = p->nop_cmds[next_nop]->cmd_link
-           = make16((p->nop_cmds[next_nop]));
-       p->xmit_cmds[0]->cmd_status = p->nop_cmds[next_nop]->cmd_status = 0;
-
-       p->nop_cmds[p->nop_point]->cmd_link = make16((p->xmit_cmds[0]));
-       p->nop_point = next_nop;
-       dev_kfree_skb(skb);
-#endif
-#else
-       p->xmit_buffs[p->xmit_count]->size = TBD_LAST | len;
-       if ((next_nop = p->xmit_count + 1) == NUM_XMIT_BUFFS) {
-               next_nop = 0;
-       }
-       p->xmit_cmds[p->xmit_count]->cmd_status = 0;
-       p->xmit_cmds[p->xmit_count]->cmd_link = p->nop_cmds[next_nop]->cmd_link
-           = make16((p->nop_cmds[next_nop]));
-       p->nop_cmds[next_nop]->cmd_status = 0;
-               p->nop_cmds[p->xmit_count]->cmd_link = make16((p->xmit_cmds[p->xmit_count]));
-       p->xmit_count = next_nop;
-       if (p->xmit_count != p->xmit_last)
-               netif_wake_queue(dev);
-       dev_kfree_skb(skb);
-#endif
-       return NETDEV_TX_OK;
-}
-
-/*******************************************
- * Someone wanna have the statistics
- */
-
-static struct net_device_stats *elmc_get_stats(struct net_device *dev)
-{
-       struct priv *p = netdev_priv(dev);
-       unsigned short crc, aln, rsc, ovrn;
-
-       crc = p->scb->crc_errs; /* get error-statistic from the ni82586 */
-       p->scb->crc_errs -= crc;
-       aln = p->scb->aln_errs;
-       p->scb->aln_errs -= aln;
-       rsc = p->scb->rsc_errs;
-       p->scb->rsc_errs -= rsc;
-       ovrn = p->scb->ovrn_errs;
-       p->scb->ovrn_errs -= ovrn;
-
-       dev->stats.rx_crc_errors += crc;
-       dev->stats.rx_fifo_errors += ovrn;
-       dev->stats.rx_frame_errors += aln;
-       dev->stats.rx_dropped += rsc;
-
-       return &dev->stats;
-}
-
-/********************************************************
- * Set MC list ..
- */
-
-#ifdef ELMC_MULTICAST
-static void set_multicast_list(struct net_device *dev)
-{
-       if (!dev->start) {
-               /* without a running interface, promiscuous doesn't work */
-               return;
-       }
-       dev->start = 0;
-       alloc586(dev);
-       init586(dev);
-       startrecv586(dev);
-       dev->start = 1;
-}
-#endif
-
-static void netdev_get_drvinfo(struct net_device *dev,
-                              struct ethtool_drvinfo *info)
-{
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       sprintf(info->bus_info, "MCA 0x%lx", dev->base_addr);
-}
-
-static const struct ethtool_ops netdev_ethtool_ops = {
-       .get_drvinfo            = netdev_get_drvinfo,
-};
-
-#ifdef MODULE
-
-/* Increase if needed ;) */
-#define MAX_3C523_CARDS 4
-
-static struct net_device *dev_elmc[MAX_3C523_CARDS];
-static int irq[MAX_3C523_CARDS];
-static int io[MAX_3C523_CARDS];
-module_param_array(irq, int, NULL, 0);
-module_param_array(io, int, NULL, 0);
-MODULE_PARM_DESC(io, "EtherLink/MC I/O base address(es)");
-MODULE_PARM_DESC(irq, "EtherLink/MC IRQ number(s)");
-MODULE_LICENSE("GPL");
-
-int __init init_module(void)
-{
-       int this_dev,found = 0;
-
-       /* Loop until we either can't find any more cards, or we have MAX_3C523_CARDS */
-       for(this_dev=0; this_dev<MAX_3C523_CARDS; this_dev++) {
-               struct net_device *dev = alloc_etherdev(sizeof(struct priv));
-               if (!dev)
-                       break;
-               dev->irq=irq[this_dev];
-               dev->base_addr=io[this_dev];
-               if (do_elmc_probe(dev) == 0) {
-                       dev_elmc[this_dev] = dev;
-                       found++;
-                       continue;
-               }
-               free_netdev(dev);
-               if (io[this_dev]==0)
-                       break;
-               pr_warning("3c523.c: No 3c523 card found at io=%#x\n",io[this_dev]);
-       }
-
-       if(found==0) {
-               if (io[0]==0)
-                       pr_notice("3c523.c: No 3c523 cards found\n");
-               return -ENXIO;
-       } else return 0;
-}
-
-void __exit cleanup_module(void)
-{
-       int this_dev;
-       for (this_dev=0; this_dev<MAX_3C523_CARDS; this_dev++) {
-               struct net_device *dev = dev_elmc[this_dev];
-               if (dev) {
-                       unregister_netdev(dev);
-                       cleanup_card(dev);
-                       free_netdev(dev);
-               }
-       }
-}
-
-#endif                         /* MODULE */
diff --git a/drivers/net/3c523.h b/drivers/net/3c523.h
deleted file mode 100644 (file)
index 6956441..0000000
+++ /dev/null
@@ -1,355 +0,0 @@
-#ifndef _3c523_INCLUDE_
-#define _3c523_INCLUDE_
-/*
-       This is basically a hacked version of ni52.h, for the 3c523
-       Etherlink/MC.
-*/
-
-/*
- * Intel i82586 Ethernet definitions
- *
- * This is an extension to the Linux operating system, and is covered by the
- * same GNU General Public License that covers that work.
- *
- * Copyright 1995 by Chris Beauregard (cpbeaure@undergrad.math.uwaterloo.ca)
- *
- * See 3c523.c for details.
- *
- * $Header: /home/chrisb/linux-1.2.13-3c523/drivers/net/RCS/3c523.h,v 1.6 1996/01/20 05:09:00 chrisb Exp chrisb $
- */
-
-/*
- * where to find the System Configuration Pointer (SCP)
- */
-#define SCP_DEFAULT_ADDRESS 0xfffff4
-
-
-/*
- * System Configuration Pointer Struct
- */
-
-struct scp_struct
-{
-  unsigned short zero_dum0;    /* has to be zero */
-  unsigned char  sysbus;       /* 0=16Bit,1=8Bit */
-  unsigned char  zero_dum1;    /* has to be zero for 586 */
-  unsigned short zero_dum2;
-  unsigned short zero_dum3;
-  char          *iscp;         /* pointer to the iscp-block */
-};
-
-
-/*
- * Intermediate System Configuration Pointer (ISCP)
- */
-struct iscp_struct
-{
-  unsigned char  busy;          /* 586 clears after successful init */
-  unsigned char  zero_dummy;    /* hast to be zero */
-  unsigned short scb_offset;    /* pointeroffset to the scb_base */
-  char          *scb_base;      /* base-address of all 16-bit offsets */
-};
-
-/*
- * System Control Block (SCB)
- */
-struct scb_struct
-{
-  unsigned short status;        /* status word */
-  unsigned short cmd;           /* command word */
-  unsigned short cbl_offset;    /* pointeroffset, command block list */
-  unsigned short rfa_offset;    /* pointeroffset, receive frame area */
-  unsigned short crc_errs;      /* CRC-Error counter */
-  unsigned short aln_errs;      /* alignmenterror counter */
-  unsigned short rsc_errs;      /* Resourceerror counter */
-  unsigned short ovrn_errs;     /* OVerrunerror counter */
-};
-
-/*
- * possible command values for the command word
- */
-#define RUC_MASK       0x0070  /* mask for RU commands */
-#define RUC_NOP                0x0000  /* NOP-command */
-#define RUC_START      0x0010  /* start RU */
-#define RUC_RESUME     0x0020  /* resume RU after suspend */
-#define RUC_SUSPEND    0x0030  /* suspend RU */
-#define RUC_ABORT      0x0040  /* abort receiver operation immediately */
-
-#define CUC_MASK       0x0700  /* mask for CU command */
-#define CUC_NOP                0x0000  /* NOP-command */
-#define CUC_START      0x0100  /* start execution of 1. cmd on the CBL */
-#define CUC_RESUME     0x0200  /* resume after suspend */
-#define CUC_SUSPEND    0x0300  /* Suspend CU */
-#define CUC_ABORT      0x0400  /* abort command operation immediately */
-
-#define ACK_MASK       0xf000  /* mask for ACK command */
-#define ACK_CX         0x8000  /* acknowledges STAT_CX */
-#define ACK_FR         0x4000  /* ack. STAT_FR */
-#define ACK_CNA                0x2000  /* ack. STAT_CNA */
-#define ACK_RNR                0x1000  /* ack. STAT_RNR */
-
-/*
- * possible status values for the status word
- */
-#define STAT_MASK      0xf000  /* mask for cause of interrupt */
-#define STAT_CX                0x8000  /* CU finished cmd with its I bit set */
-#define STAT_FR                0x4000  /* RU finished receiving a frame */
-#define STAT_CNA       0x2000  /* CU left active state */
-#define STAT_RNR       0x1000  /* RU left ready state */
-
-#define CU_STATUS      0x700   /* CU status, 0=idle */
-#define CU_SUSPEND     0x100   /* CU is suspended */
-#define CU_ACTIVE      0x200   /* CU is active */
-
-#define RU_STATUS      0x70    /* RU status, 0=idle */
-#define RU_SUSPEND     0x10    /* RU suspended */
-#define RU_NOSPACE     0x20    /* RU no resources */
-#define RU_READY       0x40    /* RU is ready */
-
-/*
- * Receive Frame Descriptor (RFD)
- */
-struct rfd_struct
-{
-  unsigned short status;       /* status word */
-  unsigned short last;         /* Bit15,Last Frame on List / Bit14,suspend */
-  unsigned short next;         /* linkoffset to next RFD */
-  unsigned short rbd_offset;   /* pointeroffset to RBD-buffer */
-  unsigned char  dest[6];      /* ethernet-address, destination */
-  unsigned char  source[6];    /* ethernet-address, source */
-  unsigned short length;       /* 802.3 frame-length */
-  unsigned short zero_dummy;   /* dummy */
-};
-
-#define RFD_LAST     0x8000    /* last: last rfd in the list */
-#define RFD_SUSP     0x4000    /* last: suspend RU after  */
-#define RFD_ERRMASK  0x0fe1     /* status: errormask */
-#define RFD_MATCHADD 0x0002     /* status: Destinationaddress !matches IA */
-#define RFD_RNR      0x0200    /* status: receiver out of resources */
-
-/*
- * Receive Buffer Descriptor (RBD)
- */
-struct rbd_struct
-{
-  unsigned short status;       /* status word,number of used bytes in buff */
-  unsigned short next;         /* pointeroffset to next RBD */
-  char          *buffer;       /* receive buffer address pointer */
-  unsigned short size;         /* size of this buffer */
-  unsigned short zero_dummy;    /* dummy */
-};
-
-#define RBD_LAST       0x8000  /* last buffer */
-#define RBD_USED       0x4000  /* this buffer has data */
-#define RBD_MASK       0x3fff  /* size-mask for length */
-
-/*
- * Statusvalues for Commands/RFD
- */
-#define STAT_COMPL   0x8000    /* status: frame/command is complete */
-#define STAT_BUSY    0x4000    /* status: frame/command is busy */
-#define STAT_OK      0x2000    /* status: frame/command is ok */
-
-/*
- * Action-Commands
- */
-#define CMD_NOP                0x0000  /* NOP */
-#define CMD_IASETUP    0x0001  /* initial address setup command */
-#define CMD_CONFIGURE  0x0002  /* configure command */
-#define CMD_MCSETUP    0x0003  /* MC setup command */
-#define CMD_XMIT       0x0004  /* transmit command */
-#define CMD_TDR                0x0005  /* time domain reflectometer (TDR) command */
-#define CMD_DUMP       0x0006  /* dump command */
-#define CMD_DIAGNOSE   0x0007  /* diagnose command */
-
-/*
- * Action command bits
- */
-#define CMD_LAST       0x8000  /* indicates last command in the CBL */
-#define CMD_SUSPEND    0x4000  /* suspend CU after this CB */
-#define CMD_INT                0x2000  /* generate interrupt after execution */
-
-/*
- * NOP - command
- */
-struct nop_cmd_struct
-{
-  unsigned short cmd_status;   /* status of this command */
-  unsigned short cmd_cmd;       /* the command itself (+bits) */
-  unsigned short cmd_link;      /* offsetpointer to next command */
-};
-
-/*
- * IA Setup command
- */
-struct iasetup_cmd_struct
-{
-  unsigned short cmd_status;
-  unsigned short cmd_cmd;
-  unsigned short cmd_link;
-  unsigned char  iaddr[6];
-};
-
-/*
- * Configure command
- */
-struct configure_cmd_struct
-{
-  unsigned short cmd_status;
-  unsigned short cmd_cmd;
-  unsigned short cmd_link;
-  unsigned char  byte_cnt;   /* size of the config-cmd */
-  unsigned char  fifo;       /* fifo/recv monitor */
-  unsigned char  sav_bf;     /* save bad frames (bit7=1)*/
-  unsigned char  adr_len;    /* adr_len(0-2),al_loc(3),pream(4-5),loopbak(6-7)*/
-  unsigned char  priority;   /* lin_prio(0-2),exp_prio(4-6),bof_metd(7) */
-  unsigned char  ifs;        /* inter frame spacing */
-  unsigned char  time_low;   /* slot time low */
-  unsigned char  time_high;  /* slot time high(0-2) and max. retries(4-7) */
-  unsigned char  promisc;    /* promisc-mode(0) , et al (1-7) */
-  unsigned char  carr_coll;  /* carrier(0-3)/collision(4-7) stuff */
-  unsigned char  fram_len;   /* minimal frame len */
-  unsigned char  dummy;             /* dummy */
-};
-
-/*
- * Multicast Setup command
- */
-struct mcsetup_cmd_struct
-{
-  unsigned short cmd_status;
-  unsigned short cmd_cmd;
-  unsigned short cmd_link;
-  unsigned short mc_cnt;               /* number of bytes in the MC-List */
-  unsigned char  mc_list[0][6];        /* pointer to 6 bytes entries */
-};
-
-/*
- * transmit command
- */
-struct transmit_cmd_struct
-{
-  unsigned short cmd_status;
-  unsigned short cmd_cmd;
-  unsigned short cmd_link;
-  unsigned short tbd_offset;   /* pointeroffset to TBD */
-  unsigned char  dest[6];       /* destination address of the frame */
-  unsigned short length;       /* user defined: 802.3 length / Ether type */
-};
-
-#define TCMD_ERRMASK     0x0fa0
-#define TCMD_MAXCOLLMASK 0x000f
-#define TCMD_MAXCOLL     0x0020
-#define TCMD_HEARTBEAT   0x0040
-#define TCMD_DEFERRED    0x0080
-#define TCMD_UNDERRUN    0x0100
-#define TCMD_LOSTCTS     0x0200
-#define TCMD_NOCARRIER   0x0400
-#define TCMD_LATECOLL    0x0800
-
-struct tdr_cmd_struct
-{
-  unsigned short cmd_status;
-  unsigned short cmd_cmd;
-  unsigned short cmd_link;
-  unsigned short status;
-};
-
-#define TDR_LNK_OK     0x8000  /* No link problem identified */
-#define TDR_XCVR_PRB   0x4000  /* indicates a transceiver problem */
-#define TDR_ET_OPN     0x2000  /* open, no correct termination */
-#define TDR_ET_SRT     0x1000  /* TDR detected a short circuit */
-#define TDR_TIMEMASK   0x07ff  /* mask for the time field */
-
-/*
- * Transmit Buffer Descriptor (TBD)
- */
-struct tbd_struct
-{
-  unsigned short size;         /* size + EOF-Flag(15) */
-  unsigned short next;          /* pointeroffset to next TBD */
-  char          *buffer;        /* pointer to buffer */
-};
-
-#define TBD_LAST 0x8000         /* EOF-Flag, indicates last buffer in list */
-
-/*************************************************************************/
-/*
-Verbatim from the Crynwyr stuff:
-
-    The 3c523 responds with adapter code 0x6042 at slot
-registers xxx0 and xxx1.  The setup register is at xxx2 and
-contains the following bits:
-
-0: card enable
-2,1: csr address select
-    00 = 0300
-    01 = 1300
-    10 = 2300
-    11 = 3300
-4,3: shared memory address select
-    00 = 0c0000
-    01 = 0c8000
-    10 = 0d0000
-    11 = 0d8000
-5: set to disable on-board thinnet
-7,6: (read-only) shows selected irq
-    00 = 12
-    01 = 7
-    10 = 3
-    11 = 9
-
-The interrupt-select register is at xxx3 and uses one bit per irq.
-
-0: int 12
-1: int 7
-2: int 3
-3: int 9
-
-    Again, the documentation stresses that the setup register
-should never be written.  The interrupt-select register may be
-written with the value corresponding to bits 7.6 in
-the setup register to insure corret setup.
-*/
-
-/* Offsets from the base I/O address. */
-#define        ELMC_SA         0       /* first 6 bytes are IEEE network address */
-#define ELMC_CTRL      6       /* control & status register */
-#define ELMC_REVISION  7       /* revision register, first 4 bits only */
-#define ELMC_IO_EXTENT  8
-
-/* these are the bit selects for the port register 2 */
-#define ELMC_STATUS_ENABLED    0x01
-#define ELMC_STATUS_CSR_SELECT 0x06
-#define ELMC_STATUS_MEMORY_SELECT      0x18
-#define ELMC_STATUS_DISABLE_THIN       0x20
-#define ELMC_STATUS_IRQ_SELECT 0xc0
-
-/* this is the card id used in the detection code.  You might recognize
-it from @6042.adf */
-#define ELMC_MCA_ID 0x6042
-
-/*
-   The following define the bits for the control & status register
-
-   The bank select registers can be used if more than 16K of memory is
-   on the card.  For some stupid reason, bank 3 is the one for the
-   bottom 16K, and the card defaults to bank 0.  So we have to set the
-   bank to 3 before the card will even think of operating.  To get bank
-   3, set BS0 and BS1 to high (of course...)
-*/
-#define ELMC_CTRL_BS0  0x01    /* RW bank select */
-#define ELMC_CTRL_BS1  0x02    /* RW bank select */
-#define ELMC_CTRL_INTE 0x04    /* RW interrupt enable, assert high */
-#define ELMC_CTRL_INT  0x08    /* R interrupt active, assert high */
-/*#define ELMC_CTRL_*  0x10*/  /* reserved */
-#define ELMC_CTRL_LBK  0x20    /* RW loopback enable, assert high */
-#define ELMC_CTRL_CA   0x40    /* RW channel attention, assert high */
-#define ELMC_CTRL_RST  0x80    /* RW 82586 reset, assert low */
-
-/* some handy compound bits */
-
-/* normal operation should have bank 3 and RST high, ints enabled */
-#define ELMC_NORMAL (ELMC_CTRL_INTE|ELMC_CTRL_RST|0x3)
-
-#endif /* _3c523_INCLUDE_ */
diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c
deleted file mode 100644 (file)
index d9d056d..0000000
+++ /dev/null
@@ -1,1661 +0,0 @@
-/* 3c527.c: 3Com Etherlink/MC32 driver for Linux 2.4 and 2.6.
- *
- *     (c) Copyright 1998 Red Hat Software Inc
- *     Written by Alan Cox.
- *     Further debugging by Carl Drougge.
- *      Initial SMP support by Felipe W Damasio <felipewd@terra.com.br>
- *      Heavily modified by Richard Procter <rnp@paradise.net.nz>
- *
- *     Based on skeleton.c written 1993-94 by Donald Becker and ne2.c
- *     (for the MCA stuff) written by Wim Dumon.
- *
- *     Thanks to 3Com for making this possible by providing me with the
- *     documentation.
- *
- *     This software may be used and distributed according to the terms
- *     of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#define DRV_NAME               "3c527"
-#define DRV_VERSION            "0.7-SMP"
-#define DRV_RELDATE            "2003/09/21"
-
-static const char *version =
-DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " Richard Procter <rnp@paradise.net.nz>\n";
-
-/**
- * DOC: Traps for the unwary
- *
- *     The diagram (Figure 1-1) and the POS summary disagree with the
- *     "Interrupt Level" section in the manual.
- *
- *     The manual contradicts itself when describing the minimum number
- *     buffers in the 'configure lists' command.
- *     My card accepts a buffer config of 4/4.
- *
- *     Setting the SAV BP bit does not save bad packets, but
- *     only enables RX on-card stats collection.
- *
- *     The documentation in places seems to miss things. In actual fact
- *     I've always eventually found everything is documented, it just
- *     requires careful study.
- *
- * DOC: Theory Of Operation
- *
- *     The 3com 3c527 is a 32bit MCA bus mastering adapter with a large
- *     amount of on board intelligence that housekeeps a somewhat dumber
- *     Intel NIC. For performance we want to keep the transmit queue deep
- *     as the card can transmit packets while fetching others from main
- *     memory by bus master DMA. Transmission and reception are driven by
- *     circular buffer queues.
- *
- *     The mailboxes can be used for controlling how the card traverses
- *     its buffer rings, but are used only for initial setup in this
- *     implementation.  The exec mailbox allows a variety of commands to
- *     be executed. Each command must complete before the next is
- *     executed. Primarily we use the exec mailbox for controlling the
- *     multicast lists.  We have to do a certain amount of interesting
- *     hoop jumping as the multicast list changes can occur in interrupt
- *     state when the card has an exec command pending. We defer such
- *     events until the command completion interrupt.
- *
- *     A copy break scheme (taken from 3c59x.c) is employed whereby
- *     received frames exceeding a configurable length are passed
- *     directly to the higher networking layers without incuring a copy,
- *     in what amounts to a time/space trade-off.
- *
- *     The card also keeps a large amount of statistical information
- *     on-board. In a perfect world, these could be used safely at no
- *     cost. However, lacking information to the contrary, processing
- *     them without races would involve so much extra complexity as to
- *     make it unworthwhile to do so. In the end, a hybrid SW/HW
- *     implementation was made necessary --- see mc32_update_stats().
- *
- * DOC: Notes
- *
- *     It should be possible to use two or more cards, but at this stage
- *     only by loading two copies of the same module.
- *
- *     The on-board 82586 NIC has trouble receiving multiple
- *     back-to-back frames and so is likely to drop packets from fast
- *     senders.
-**/
-
-#include <linux/module.h>
-
-#include <linux/errno.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/if_ether.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/mca-legacy.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/skbuff.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/wait.h>
-#include <linux/ethtool.h>
-#include <linux/completion.h>
-#include <linux/bitops.h>
-#include <linux/semaphore.h>
-
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-
-#include "3c527.h"
-
-MODULE_LICENSE("GPL");
-
-/*
- * The name of the card. Is used for messages and in the requests for
- * io regions, irqs and dma channels
- */
-static const char* cardname = DRV_NAME;
-
-/* use 0 for production, 1 for verification, >2 for debug */
-#ifndef NET_DEBUG
-#define NET_DEBUG 2
-#endif
-
-static unsigned int mc32_debug = NET_DEBUG;
-
-/* The number of low I/O ports used by the ethercard. */
-#define MC32_IO_EXTENT 8
-
-/* As implemented, values must be a power-of-2 -- 4/8/16/32 */
-#define TX_RING_LEN     32       /* Typically the card supports 37  */
-#define RX_RING_LEN     8        /*     "       "        "          */
-
-/* Copy break point, see above for details.
- * Setting to > 1512 effectively disables this feature.        */
-#define RX_COPYBREAK    200      /* Value from 3c59x.c */
-
-/* Issue the 82586 workaround command - this is for "busy lans", but
- * basically means for all lans now days - has a performance (latency)
- * cost, but best set. */
-static const int WORKAROUND_82586=1;
-
-/* Pointers to buffers and their on-card records */
-struct mc32_ring_desc
-{
-       volatile struct skb_header *p;
-       struct sk_buff *skb;
-};
-
-/* Information that needs to be kept for each board. */
-struct mc32_local
-{
-       int slot;
-
-       u32 base;
-       volatile struct mc32_mailbox *rx_box;
-       volatile struct mc32_mailbox *tx_box;
-       volatile struct mc32_mailbox *exec_box;
-        volatile struct mc32_stats *stats;    /* Start of on-card statistics */
-        u16 tx_chain;           /* Transmit list start offset */
-       u16 rx_chain;           /* Receive list start offset */
-        u16 tx_len;             /* Transmit list count */
-        u16 rx_len;             /* Receive list count */
-
-       u16 xceiver_desired_state; /* HALTED or RUNNING */
-       u16 cmd_nonblocking;    /* Thread is uninterested in command result */
-       u16 mc_reload_wait;     /* A multicast load request is pending */
-       u32 mc_list_valid;      /* True when the mclist is set */
-
-       struct mc32_ring_desc tx_ring[TX_RING_LEN];     /* Host Transmit ring */
-       struct mc32_ring_desc rx_ring[RX_RING_LEN];     /* Host Receive ring */
-
-       atomic_t tx_count;      /* buffers left */
-       atomic_t tx_ring_head;  /* index to tx en-queue end */
-       u16 tx_ring_tail;       /* index to tx de-queue end */
-
-       u16 rx_ring_tail;       /* index to rx de-queue end */
-
-       struct semaphore cmd_mutex;    /* Serialises issuing of execute commands */
-        struct completion execution_cmd; /* Card has completed an execute command */
-       struct completion xceiver_cmd;   /* Card has completed a tx or rx command */
-};
-
-/* The station (ethernet) address prefix, used for a sanity check. */
-#define SA_ADDR0 0x02
-#define SA_ADDR1 0x60
-#define SA_ADDR2 0xAC
-
-struct mca_adapters_t {
-       unsigned int    id;
-       char            *name;
-};
-
-static const struct mca_adapters_t mc32_adapters[] = {
-       { 0x0041, "3COM EtherLink MC/32" },
-       { 0x8EF5, "IBM High Performance Lan Adapter" },
-       { 0x0000, NULL }
-};
-
-
-/* Macros for ring index manipulations */
-static inline u16 next_rx(u16 rx) { return (rx+1)&(RX_RING_LEN-1); };
-static inline u16 prev_rx(u16 rx) { return (rx-1)&(RX_RING_LEN-1); };
-
-static inline u16 next_tx(u16 tx) { return (tx+1)&(TX_RING_LEN-1); };
-
-
-/* Index to functions, as function prototypes. */
-static int     mc32_probe1(struct net_device *dev, int ioaddr);
-static int      mc32_command(struct net_device *dev, u16 cmd, void *data, int len);
-static int     mc32_open(struct net_device *dev);
-static void    mc32_timeout(struct net_device *dev);
-static netdev_tx_t mc32_send_packet(struct sk_buff *skb,
-                                   struct net_device *dev);
-static irqreturn_t mc32_interrupt(int irq, void *dev_id);
-static int     mc32_close(struct net_device *dev);
-static struct  net_device_stats *mc32_get_stats(struct net_device *dev);
-static void    mc32_set_multicast_list(struct net_device *dev);
-static void    mc32_reset_multicast_list(struct net_device *dev);
-static const struct ethtool_ops netdev_ethtool_ops;
-
-static void cleanup_card(struct net_device *dev)
-{
-       struct mc32_local *lp = netdev_priv(dev);
-       unsigned slot = lp->slot;
-       mca_mark_as_unused(slot);
-       mca_set_adapter_name(slot, NULL);
-       free_irq(dev->irq, dev);
-       release_region(dev->base_addr, MC32_IO_EXTENT);
-}
-
-/**
- * mc32_probe  -       Search for supported boards
- * @unit: interface number to use
- *
- * Because MCA bus is a real bus and we can scan for cards we could do a
- * single scan for all boards here. Right now we use the passed in device
- * structure and scan for only one board. This needs fixing for modules
- * in particular.
- */
-
-struct net_device *__init mc32_probe(int unit)
-{
-       struct net_device *dev = alloc_etherdev(sizeof(struct mc32_local));
-       static int current_mca_slot = -1;
-       int i;
-       int err;
-
-       if (!dev)
-               return ERR_PTR(-ENOMEM);
-
-       if (unit >= 0)
-               sprintf(dev->name, "eth%d", unit);
-
-       /* Do not check any supplied i/o locations.
-          POS registers usually don't fail :) */
-
-       /* MCA cards have POS registers.
-          Autodetecting MCA cards is extremely simple.
-          Just search for the card. */
-
-       for(i = 0; (mc32_adapters[i].name != NULL); i++) {
-               current_mca_slot =
-                       mca_find_unused_adapter(mc32_adapters[i].id, 0);
-
-               if(current_mca_slot != MCA_NOTFOUND) {
-                       if(!mc32_probe1(dev, current_mca_slot))
-                       {
-                               mca_set_adapter_name(current_mca_slot,
-                                               mc32_adapters[i].name);
-                               mca_mark_as_used(current_mca_slot);
-                               err = register_netdev(dev);
-                               if (err) {
-                                       cleanup_card(dev);
-                                       free_netdev(dev);
-                                       dev = ERR_PTR(err);
-                               }
-                               return dev;
-                       }
-
-               }
-       }
-       free_netdev(dev);
-       return ERR_PTR(-ENODEV);
-}
-
-static const struct net_device_ops netdev_ops = {
-       .ndo_open               = mc32_open,
-       .ndo_stop               = mc32_close,
-       .ndo_start_xmit         = mc32_send_packet,
-       .ndo_get_stats          = mc32_get_stats,
-       .ndo_set_multicast_list = mc32_set_multicast_list,
-       .ndo_tx_timeout         = mc32_timeout,
-       .ndo_change_mtu         = eth_change_mtu,
-       .ndo_set_mac_address    = eth_mac_addr,
-       .ndo_validate_addr      = eth_validate_addr,
-};
-
-/**
- * mc32_probe1 -       Check a given slot for a board and test the card
- * @dev:  Device structure to fill in
- * @slot: The MCA bus slot being used by this card
- *
- * Decode the slot data and configure the card structures. Having done this we
- * can reset the card and configure it. The card does a full self test cycle
- * in firmware so we have to wait for it to return and post us either a
- * failure case or some addresses we use to find the board internals.
- */
-
-static int __init mc32_probe1(struct net_device *dev, int slot)
-{
-       static unsigned version_printed;
-       int i, err;
-       u8 POS;
-       u32 base;
-       struct mc32_local *lp = netdev_priv(dev);
-       static const u16 mca_io_bases[] = {
-               0x7280,0x7290,
-               0x7680,0x7690,
-               0x7A80,0x7A90,
-               0x7E80,0x7E90
-       };
-       static const u32 mca_mem_bases[] = {
-               0x00C0000,
-               0x00C4000,
-               0x00C8000,
-               0x00CC000,
-               0x00D0000,
-               0x00D4000,
-               0x00D8000,
-               0x00DC000
-       };
-       static const char * const failures[] = {
-               "Processor instruction",
-               "Processor data bus",
-               "Processor data bus",
-               "Processor data bus",
-               "Adapter bus",
-               "ROM checksum",
-               "Base RAM",
-               "Extended RAM",
-               "82586 internal loopback",
-               "82586 initialisation failure",
-               "Adapter list configuration error"
-       };
-
-       /* Time to play MCA games */
-
-       if (mc32_debug  &&  version_printed++ == 0)
-               pr_debug("%s", version);
-
-       pr_info("%s: %s found in slot %d: ", dev->name, cardname, slot);
-
-       POS = mca_read_stored_pos(slot, 2);
-
-       if(!(POS&1))
-       {
-               pr_cont("disabled.\n");
-               return -ENODEV;
-       }
-
-       /* Fill in the 'dev' fields. */
-       dev->base_addr = mca_io_bases[(POS>>1)&7];
-       dev->mem_start = mca_mem_bases[(POS>>4)&7];
-
-       POS = mca_read_stored_pos(slot, 4);
-       if(!(POS&1))
-       {
-               pr_cont("memory window disabled.\n");
-               return -ENODEV;
-       }
-
-       POS = mca_read_stored_pos(slot, 5);
-
-       i=(POS>>4)&3;
-       if(i==3)
-       {
-               pr_cont("invalid memory window.\n");
-               return -ENODEV;
-       }
-
-       i*=16384;
-       i+=16384;
-
-       dev->mem_end=dev->mem_start + i;
-
-       dev->irq = ((POS>>2)&3)+9;
-
-       if(!request_region(dev->base_addr, MC32_IO_EXTENT, cardname))
-       {
-               pr_cont("io 0x%3lX, which is busy.\n", dev->base_addr);
-               return -EBUSY;
-       }
-
-       pr_cont("io 0x%3lX irq %d mem 0x%lX (%dK)\n",
-               dev->base_addr, dev->irq, dev->mem_start, i/1024);
-
-
-       /* We ought to set the cache line size here.. */
-
-
-       /*
-        *      Go PROM browsing
-        */
-
-       /* Retrieve and print the ethernet address. */
-       for (i = 0; i < 6; i++)
-       {
-               mca_write_pos(slot, 6, i+12);
-               mca_write_pos(slot, 7, 0);
-
-               dev->dev_addr[i] = mca_read_pos(slot,3);
-       }
-
-       pr_info("%s: Address %pM ", dev->name, dev->dev_addr);
-
-       mca_write_pos(slot, 6, 0);
-       mca_write_pos(slot, 7, 0);
-
-       POS = mca_read_stored_pos(slot, 4);
-
-       if(POS&2)
-               pr_cont(": BNC port selected.\n");
-       else
-               pr_cont(": AUI port selected.\n");
-
-       POS=inb(dev->base_addr+HOST_CTRL);
-       POS|=HOST_CTRL_ATTN|HOST_CTRL_RESET;
-       POS&=~HOST_CTRL_INTE;
-       outb(POS, dev->base_addr+HOST_CTRL);
-       /* Reset adapter */
-       udelay(100);
-       /* Reset off */
-       POS&=~(HOST_CTRL_ATTN|HOST_CTRL_RESET);
-       outb(POS, dev->base_addr+HOST_CTRL);
-
-       udelay(300);
-
-       /*
-        *      Grab the IRQ
-        */
-
-       err = request_irq(dev->irq, mc32_interrupt, IRQF_SHARED, DRV_NAME, dev);
-       if (err) {
-               release_region(dev->base_addr, MC32_IO_EXTENT);
-               pr_err("%s: unable to get IRQ %d.\n", DRV_NAME, dev->irq);
-               goto err_exit_ports;
-       }
-
-       memset(lp, 0, sizeof(struct mc32_local));
-       lp->slot = slot;
-
-       i=0;
-
-       base = inb(dev->base_addr);
-
-       while(base == 0xFF)
-       {
-               i++;
-               if(i == 1000)
-               {
-                       pr_err("%s: failed to boot adapter.\n", dev->name);
-                       err = -ENODEV;
-                       goto err_exit_irq;
-               }
-               udelay(1000);
-               if(inb(dev->base_addr+2)&(1<<5))
-                       base = inb(dev->base_addr);
-       }
-
-       if(base>0)
-       {
-               if(base < 0x0C)
-                       pr_err("%s: %s%s.\n", dev->name, failures[base-1],
-                               base<0x0A?" test failure":"");
-               else
-                       pr_err("%s: unknown failure %d.\n", dev->name, base);
-               err = -ENODEV;
-               goto err_exit_irq;
-       }
-
-       base=0;
-       for(i=0;i<4;i++)
-       {
-               int n=0;
-
-               while(!(inb(dev->base_addr+2)&(1<<5)))
-               {
-                       n++;
-                       udelay(50);
-                       if(n>100)
-                       {
-                               pr_err("%s: mailbox read fail (%d).\n", dev->name, i);
-                               err = -ENODEV;
-                               goto err_exit_irq;
-                       }
-               }
-
-               base|=(inb(dev->base_addr)<<(8*i));
-       }
-
-       lp->exec_box=isa_bus_to_virt(dev->mem_start+base);
-
-       base=lp->exec_box->data[1]<<16|lp->exec_box->data[0];
-
-       lp->base = dev->mem_start+base;
-
-       lp->rx_box=isa_bus_to_virt(lp->base + lp->exec_box->data[2]);
-       lp->tx_box=isa_bus_to_virt(lp->base + lp->exec_box->data[3]);
-
-       lp->stats = isa_bus_to_virt(lp->base + lp->exec_box->data[5]);
-
-       /*
-        *      Descriptor chains (card relative)
-        */
-
-       lp->tx_chain            = lp->exec_box->data[8];   /* Transmit list start offset */
-       lp->rx_chain            = lp->exec_box->data[10];  /* Receive list start offset */
-       lp->tx_len              = lp->exec_box->data[9];   /* Transmit list count */
-       lp->rx_len              = lp->exec_box->data[11];  /* Receive list count */
-
-       sema_init(&lp->cmd_mutex, 0);
-       init_completion(&lp->execution_cmd);
-       init_completion(&lp->xceiver_cmd);
-
-       pr_info("%s: Firmware Rev %d. %d RX buffers, %d TX buffers. Base of 0x%08X.\n",
-               dev->name, lp->exec_box->data[12], lp->rx_len, lp->tx_len, lp->base);
-
-       dev->netdev_ops         = &netdev_ops;
-       dev->watchdog_timeo     = HZ*5; /* Board does all the work */
-       dev->ethtool_ops        = &netdev_ethtool_ops;
-
-       return 0;
-
-err_exit_irq:
-       free_irq(dev->irq, dev);
-err_exit_ports:
-       release_region(dev->base_addr, MC32_IO_EXTENT);
-       return err;
-}
-
-
-/**
- *     mc32_ready_poll         -       wait until we can feed it a command
- *     @dev:   The device to wait for
- *
- *     Wait until the card becomes ready to accept a command via the
- *     command register. This tells us nothing about the completion
- *     status of any pending commands and takes very little time at all.
- */
-
-static inline void mc32_ready_poll(struct net_device *dev)
-{
-       int ioaddr = dev->base_addr;
-       while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));
-}
-
-
-/**
- *     mc32_command_nowait     -       send a command non blocking
- *     @dev: The 3c527 to issue the command to
- *     @cmd: The command word to write to the mailbox
- *     @data: A data block if the command expects one
- *     @len: Length of the data block
- *
- *     Send a command from interrupt state. If there is a command
- *     currently being executed then we return an error of -1. It
- *     simply isn't viable to wait around as commands may be
- *     slow. This can theoretically be starved on SMP, but it's hard
- *     to see a realistic situation.  We do not wait for the command
- *     to complete --- we rely on the interrupt handler to tidy up
- *     after us.
- */
-
-static int mc32_command_nowait(struct net_device *dev, u16 cmd, void *data, int len)
-{
-       struct mc32_local *lp = netdev_priv(dev);
-       int ioaddr = dev->base_addr;
-       int ret = -1;
-
-       if (down_trylock(&lp->cmd_mutex) == 0)
-       {
-               lp->cmd_nonblocking=1;
-               lp->exec_box->mbox=0;
-               lp->exec_box->mbox=cmd;
-               memcpy((void *)lp->exec_box->data, data, len);
-               barrier();      /* the memcpy forgot the volatile so be sure */
-
-               /* Send the command */
-               mc32_ready_poll(dev);
-               outb(1<<6, ioaddr+HOST_CMD);
-
-               ret = 0;
-
-               /* Interrupt handler will signal mutex on completion */
-       }
-
-       return ret;
-}
-
-
-/**
- *     mc32_command    -       send a command and sleep until completion
- *     @dev: The 3c527 card to issue the command to
- *     @cmd: The command word to write to the mailbox
- *     @data: A data block if the command expects one
- *     @len: Length of the data block
- *
- *     Sends exec commands in a user context. This permits us to wait around
- *     for the replies and also to wait for the command buffer to complete
- *     from a previous command before we execute our command. After our
- *     command completes we will attempt any pending multicast reload
- *     we blocked off by hogging the exec buffer.
- *
- *     You feed the card a command, you wait, it interrupts you get a
- *     reply. All well and good. The complication arises because you use
- *     commands for filter list changes which come in at bh level from things
- *     like IPV6 group stuff.
- */
-
-static int mc32_command(struct net_device *dev, u16 cmd, void *data, int len)
-{
-       struct mc32_local *lp = netdev_priv(dev);
-       int ioaddr = dev->base_addr;
-       int ret = 0;
-
-       down(&lp->cmd_mutex);
-
-       /*
-        *     My Turn
-        */
-
-       lp->cmd_nonblocking=0;
-       lp->exec_box->mbox=0;
-       lp->exec_box->mbox=cmd;
-       memcpy((void *)lp->exec_box->data, data, len);
-       barrier();      /* the memcpy forgot the volatile so be sure */
-
-       mc32_ready_poll(dev);
-       outb(1<<6, ioaddr+HOST_CMD);
-
-       wait_for_completion(&lp->execution_cmd);
-
-       if(lp->exec_box->mbox&(1<<13))
-               ret = -1;
-
-       up(&lp->cmd_mutex);
-
-       /*
-        *      A multicast set got blocked - try it now
-         */
-
-       if(lp->mc_reload_wait)
-       {
-               mc32_reset_multicast_list(dev);
-       }
-
-       return ret;
-}
-
-
-/**
- *     mc32_start_transceiver  -       tell board to restart tx/rx
- *     @dev: The 3c527 card to issue the command to
- *
- *     This may be called from the interrupt state, where it is used
- *     to restart the rx ring if the card runs out of rx buffers.
- *
- *     We must first check if it's ok to (re)start the transceiver. See
- *      mc32_close for details.
- */
-
-static void mc32_start_transceiver(struct net_device *dev) {
-
-       struct mc32_local *lp = netdev_priv(dev);
-       int ioaddr = dev->base_addr;
-
-       /* Ignore RX overflow on device closure */
-       if (lp->xceiver_desired_state==HALTED)
-               return;
-
-       /* Give the card the offset to the post-EOL-bit RX descriptor */
-       mc32_ready_poll(dev);
-       lp->rx_box->mbox=0;
-       lp->rx_box->data[0]=lp->rx_ring[prev_rx(lp->rx_ring_tail)].p->next;
-       outb(HOST_CMD_START_RX, ioaddr+HOST_CMD);
-
-       mc32_ready_poll(dev);
-       lp->tx_box->mbox=0;
-       outb(HOST_CMD_RESTRT_TX, ioaddr+HOST_CMD);   /* card ignores this on RX restart */
-
-       /* We are not interrupted on start completion */
-}
-
-
-/**
- *     mc32_halt_transceiver   -       tell board to stop tx/rx
- *     @dev: The 3c527 card to issue the command to
- *
- *     We issue the commands to halt the card's transceiver. In fact,
- *     after some experimenting we now simply tell the card to
- *     suspend. When issuing aborts occasionally odd things happened.
- *
- *     We then sleep until the card has notified us that both rx and
- *     tx have been suspended.
- */
-
-static void mc32_halt_transceiver(struct net_device *dev)
-{
-       struct mc32_local *lp = netdev_priv(dev);
-       int ioaddr = dev->base_addr;
-
-       mc32_ready_poll(dev);
-       lp->rx_box->mbox=0;
-       outb(HOST_CMD_SUSPND_RX, ioaddr+HOST_CMD);
-       wait_for_completion(&lp->xceiver_cmd);
-
-       mc32_ready_poll(dev);
-       lp->tx_box->mbox=0;
-       outb(HOST_CMD_SUSPND_TX, ioaddr+HOST_CMD);
-       wait_for_completion(&lp->xceiver_cmd);
-}
-
-
-/**
- *     mc32_load_rx_ring       -       load the ring of receive buffers
- *     @dev: 3c527 to build the ring for
- *
- *     This initialises the on-card and driver datastructures to
- *     the point where mc32_start_transceiver() can be called.
- *
- *     The card sets up the receive ring for us. We are required to use the
- *     ring it provides, although the size of the ring is configurable.
- *
- *     We allocate an sk_buff for each ring entry in turn and
- *     initialise its house-keeping info. At the same time, we read
- *     each 'next' pointer in our rx_ring array. This reduces slow
- *     shared-memory reads and makes it easy to access predecessor
- *     descriptors.
- *
- *     We then set the end-of-list bit for the last entry so that the
- *     card will know when it has run out of buffers.
- */
-
-static int mc32_load_rx_ring(struct net_device *dev)
-{
-       struct mc32_local *lp = netdev_priv(dev);
-       int i;
-       u16 rx_base;
-       volatile struct skb_header *p;
-
-       rx_base=lp->rx_chain;
-
-       for(i=0; i<RX_RING_LEN; i++) {
-               lp->rx_ring[i].skb=alloc_skb(1532, GFP_KERNEL);
-               if (lp->rx_ring[i].skb==NULL) {
-                       for (;i>=0;i--)
-                               kfree_skb(lp->rx_ring[i].skb);
-                       return -ENOBUFS;
-               }
-               skb_reserve(lp->rx_ring[i].skb, 18);
-
-               p=isa_bus_to_virt(lp->base+rx_base);
-
-               p->control=0;
-               p->data=isa_virt_to_bus(lp->rx_ring[i].skb->data);
-               p->status=0;
-               p->length=1532;
-
-               lp->rx_ring[i].p=p;
-               rx_base=p->next;
-       }
-
-       lp->rx_ring[i-1].p->control |= CONTROL_EOL;
-
-       lp->rx_ring_tail=0;
-
-       return 0;
-}
-
-
-/**
- *     mc32_flush_rx_ring      -       free the ring of receive buffers
- *     @lp: Local data of 3c527 to flush the rx ring of
- *
- *     Free the buffer for each ring slot. This may be called
- *      before mc32_load_rx_ring(), eg. on error in mc32_open().
- *      Requires rx skb pointers to point to a valid skb, or NULL.
- */
-
-static void mc32_flush_rx_ring(struct net_device *dev)
-{
-       struct mc32_local *lp = netdev_priv(dev);
-       int i;
-
-       for(i=0; i < RX_RING_LEN; i++)
-       {
-               if (lp->rx_ring[i].skb) {
-                       dev_kfree_skb(lp->rx_ring[i].skb);
-                       lp->rx_ring[i].skb = NULL;
-               }
-               lp->rx_ring[i].p=NULL;
-       }
-}
-
-
-/**
- *     mc32_load_tx_ring       -       load transmit ring
- *     @dev: The 3c527 card to issue the command to
- *
- *     This sets up the host transmit data-structures.
- *
- *     First, we obtain from the card it's current position in the tx
- *     ring, so that we will know where to begin transmitting
- *     packets.
- *
- *     Then, we read the 'next' pointers from the on-card tx ring into
- *     our tx_ring array to reduce slow shared-mem reads. Finally, we
- *     intitalise the tx house keeping variables.
- *
- */
-
-static void mc32_load_tx_ring(struct net_device *dev)
-{
-       struct mc32_local *lp = netdev_priv(dev);
-       volatile struct skb_header *p;
-       int i;
-       u16 tx_base;
-
-       tx_base=lp->tx_box->data[0];
-
-       for(i=0 ; i<TX_RING_LEN ; i++)
-       {
-               p=isa_bus_to_virt(lp->base+tx_base);
-               lp->tx_ring[i].p=p;
-               lp->tx_ring[i].skb=NULL;
-
-               tx_base=p->next;
-       }
-
-       /* -1 so that tx_ring_head cannot "lap" tx_ring_tail */
-       /* see mc32_tx_ring */
-
-       atomic_set(&lp->tx_count, TX_RING_LEN-1);
-       atomic_set(&lp->tx_ring_head, 0);
-       lp->tx_ring_tail=0;
-}
-
-
-/**
- *     mc32_flush_tx_ring      -       free transmit ring
- *     @lp: Local data of 3c527 to flush the tx ring of
- *
- *      If the ring is non-empty, zip over the it, freeing any
- *      allocated skb_buffs.  The tx ring house-keeping variables are
- *      then reset. Requires rx skb pointers to point to a valid skb,
- *      or NULL.
- */
-
-static void mc32_flush_tx_ring(struct net_device *dev)
-{
-       struct mc32_local *lp = netdev_priv(dev);
-       int i;
-
-       for (i=0; i < TX_RING_LEN; i++)
-       {
-               if (lp->tx_ring[i].skb)
-               {
-                       dev_kfree_skb(lp->tx_ring[i].skb);
-                       lp->tx_ring[i].skb = NULL;
-               }
-       }
-
-       atomic_set(&lp->tx_count, 0);
-       atomic_set(&lp->tx_ring_head, 0);
-       lp->tx_ring_tail=0;
-}
-
-
-/**
- *     mc32_open       -       handle 'up' of card
- *     @dev: device to open
- *
- *     The user is trying to bring the card into ready state. This requires
- *     a brief dialogue with the card. Firstly we enable interrupts and then
- *     'indications'. Without these enabled the card doesn't bother telling
- *     us what it has done. This had me puzzled for a week.
- *
- *     We configure the number of card descriptors, then load the network
- *     address and multicast filters. Turn on the workaround mode. This
- *     works around a bug in the 82586 - it asks the firmware to do
- *     so. It has a performance (latency) hit but is needed on busy
- *     [read most] lans. We load the ring with buffers then we kick it
- *     all off.
- */
-
-static int mc32_open(struct net_device *dev)
-{
-       int ioaddr = dev->base_addr;
-       struct mc32_local *lp = netdev_priv(dev);
-       u8 one=1;
-       u8 regs;
-       u16 descnumbuffs[2] = {TX_RING_LEN, RX_RING_LEN};
-
-       /*
-        *      Interrupts enabled
-        */
-
-       regs=inb(ioaddr+HOST_CTRL);
-       regs|=HOST_CTRL_INTE;
-       outb(regs, ioaddr+HOST_CTRL);
-
-       /*
-        *      Allow ourselves to issue commands
-        */
-
-       up(&lp->cmd_mutex);
-
-
-       /*
-        *      Send the indications on command
-        */
-
-       mc32_command(dev, 4, &one, 2);
-
-       /*
-        *      Poke it to make sure it's really dead.
-        */
-
-       mc32_halt_transceiver(dev);
-       mc32_flush_tx_ring(dev);
-
-       /*
-        *      Ask card to set up on-card descriptors to our spec
-        */
-
-       if(mc32_command(dev, 8, descnumbuffs, 4)) {
-               pr_info("%s: %s rejected our buffer configuration!\n",
-                      dev->name, cardname);
-               mc32_close(dev);
-               return -ENOBUFS;
-       }
-
-       /* Report new configuration */
-       mc32_command(dev, 6, NULL, 0);
-
-       lp->tx_chain            = lp->exec_box->data[8];   /* Transmit list start offset */
-       lp->rx_chain            = lp->exec_box->data[10];  /* Receive list start offset */
-       lp->tx_len              = lp->exec_box->data[9];   /* Transmit list count */
-       lp->rx_len              = lp->exec_box->data[11];  /* Receive list count */
-
-       /* Set Network Address */
-       mc32_command(dev, 1, dev->dev_addr, 6);
-
-       /* Set the filters */
-       mc32_set_multicast_list(dev);
-
-       if (WORKAROUND_82586) {
-               u16 zero_word=0;
-               mc32_command(dev, 0x0D, &zero_word, 2);   /* 82586 bug workaround on  */
-       }
-
-       mc32_load_tx_ring(dev);
-
-       if(mc32_load_rx_ring(dev))
-       {
-               mc32_close(dev);
-               return -ENOBUFS;
-       }
-
-       lp->xceiver_desired_state = RUNNING;
-
-       /* And finally, set the ball rolling... */
-       mc32_start_transceiver(dev);
-
-       netif_start_queue(dev);
-
-       return 0;
-}
-
-
-/**
- *     mc32_timeout    -       handle a timeout from the network layer
- *     @dev: 3c527 that timed out
- *
- *     Handle a timeout on transmit from the 3c527. This normally means
- *     bad things as the hardware handles cable timeouts and mess for
- *     us.
- *
- */
-
-static void mc32_timeout(struct net_device *dev)
-{
-       pr_warning("%s: transmit timed out?\n", dev->name);
-       /* Try to restart the adaptor. */
-       netif_wake_queue(dev);
-}
-
-
-/**
- *     mc32_send_packet        -       queue a frame for transmit
- *     @skb: buffer to transmit
- *     @dev: 3c527 to send it out of
- *
- *     Transmit a buffer. This normally means throwing the buffer onto
- *     the transmit queue as the queue is quite large. If the queue is
- *     full then we set tx_busy and return. Once the interrupt handler
- *     gets messages telling it to reclaim transmit queue entries, we will
- *     clear tx_busy and the kernel will start calling this again.
- *
- *      We do not disable interrupts or acquire any locks; this can
- *      run concurrently with mc32_tx_ring(), and the function itself
- *      is serialised at a higher layer. However, similarly for the
- *      card itself, we must ensure that we update tx_ring_head only
- *      after we've established a valid packet on the tx ring (and
- *      before we let the card "see" it, to prevent it racing with the
- *      irq handler).
- *
- */
-
-static netdev_tx_t mc32_send_packet(struct sk_buff *skb,
-                                   struct net_device *dev)
-{
-       struct mc32_local *lp = netdev_priv(dev);
-       u32 head = atomic_read(&lp->tx_ring_head);
-
-       volatile struct skb_header *p, *np;
-
-       netif_stop_queue(dev);
-
-       if(atomic_read(&lp->tx_count)==0) {
-               return NETDEV_TX_BUSY;
-       }
-
-       if (skb_padto(skb, ETH_ZLEN)) {
-               netif_wake_queue(dev);
-               return NETDEV_TX_OK;
-       }
-
-       atomic_dec(&lp->tx_count);
-
-       /* P is the last sending/sent buffer as a pointer */
-       p=lp->tx_ring[head].p;
-
-       head = next_tx(head);
-
-       /* NP is the buffer we will be loading */
-       np=lp->tx_ring[head].p;
-
-       /* We will need this to flush the buffer out */
-       lp->tx_ring[head].skb=skb;
-
-       np->length      = unlikely(skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len;
-       np->data        = isa_virt_to_bus(skb->data);
-       np->status      = 0;
-       np->control     = CONTROL_EOP | CONTROL_EOL;
-       wmb();
-
-       /*
-        * The new frame has been setup; we can now
-        * let the interrupt handler and card "see" it
-        */
-
-       atomic_set(&lp->tx_ring_head, head);
-       p->control     &= ~CONTROL_EOL;
-
-       netif_wake_queue(dev);
-       return NETDEV_TX_OK;
-}
-
-
-/**
- *     mc32_update_stats       -       pull off the on board statistics
- *     @dev: 3c527 to service
- *
- *
- *     Query and reset the on-card stats. There's the small possibility
- *     of a race here, which would result in an underestimation of
- *     actual errors. As such, we'd prefer to keep all our stats
- *     collection in software. As a rule, we do. However it can't be
- *     used for rx errors and collisions as, by default, the card discards
- *     bad rx packets.
- *
- *     Setting the SAV BP in the rx filter command supposedly
- *     stops this behaviour. However, testing shows that it only seems to
- *     enable the collation of on-card rx statistics --- the driver
- *     never sees an RX descriptor with an error status set.
- *
- */
-
-static void mc32_update_stats(struct net_device *dev)
-{
-       struct mc32_local *lp = netdev_priv(dev);
-       volatile struct mc32_stats *st = lp->stats;
-
-       u32 rx_errors=0;
-
-       rx_errors+=dev->stats.rx_crc_errors   +=st->rx_crc_errors;
-                                                  st->rx_crc_errors=0;
-       rx_errors+=dev->stats.rx_fifo_errors  +=st->rx_overrun_errors;
-                                                  st->rx_overrun_errors=0;
-       rx_errors+=dev->stats.rx_frame_errors +=st->rx_alignment_errors;
-                                                  st->rx_alignment_errors=0;
-       rx_errors+=dev->stats.rx_length_errors+=st->rx_tooshort_errors;
-                                                  st->rx_tooshort_errors=0;
-       rx_errors+=dev->stats.rx_missed_errors+=st->rx_outofresource_errors;
-                                                  st->rx_outofresource_errors=0;
-        dev->stats.rx_errors=rx_errors;
-
-       /* Number of packets which saw one collision */
-       dev->stats.collisions+=st->dataC[10];
-       st->dataC[10]=0;
-
-       /* Number of packets which saw 2--15 collisions */
-       dev->stats.collisions+=st->dataC[11];
-       st->dataC[11]=0;
-}
-
-
-/**
- *     mc32_rx_ring    -       process the receive ring
- *     @dev: 3c527 that needs its receive ring processing
- *
- *
- *     We have received one or more indications from the card that a
- *     receive has completed. The buffer ring thus contains dirty
- *     entries. We walk the ring by iterating over the circular rx_ring
- *     array, starting at the next dirty buffer (which happens to be the
- *     one we finished up at last time around).
- *
- *     For each completed packet, we will either copy it and pass it up
- *     the stack or, if the packet is near MTU sized, we allocate
- *     another buffer and flip the old one up the stack.
- *
- *     We must succeed in keeping a buffer on the ring. If necessary we
- *     will toss a received packet rather than lose a ring entry. Once
- *     the first uncompleted descriptor is found, we move the
- *     End-Of-List bit to include the buffers just processed.
- *
- */
-
-static void mc32_rx_ring(struct net_device *dev)
-{
-       struct mc32_local *lp = netdev_priv(dev);
-       volatile struct skb_header *p;
-       u16 rx_ring_tail;
-       u16 rx_old_tail;
-       int x=0;
-
-       rx_old_tail = rx_ring_tail = lp->rx_ring_tail;
-
-       do
-       {
-               p=lp->rx_ring[rx_ring_tail].p;
-
-               if(!(p->status & (1<<7))) { /* Not COMPLETED */
-                       break;
-               }
-               if(p->status & (1<<6)) /* COMPLETED_OK */
-               {
-
-                       u16 length=p->length;
-                       struct sk_buff *skb;
-                       struct sk_buff *newskb;
-
-                       /* Try to save time by avoiding a copy on big frames */
-
-                       if ((length > RX_COPYBREAK) &&
-                           ((newskb=dev_alloc_skb(1532)) != NULL))
-                       {
-                               skb=lp->rx_ring[rx_ring_tail].skb;
-                               skb_put(skb, length);
-
-                               skb_reserve(newskb,18);
-                               lp->rx_ring[rx_ring_tail].skb=newskb;
-                               p->data=isa_virt_to_bus(newskb->data);
-                       }
-                       else
-                       {
-                               skb=dev_alloc_skb(length+2);
-
-                               if(skb==NULL) {
-                                       dev->stats.rx_dropped++;
-                                       goto dropped;
-                               }
-
-                               skb_reserve(skb,2);
-                               memcpy(skb_put(skb, length),
-                                      lp->rx_ring[rx_ring_tail].skb->data, length);
-                       }
-
-                       skb->protocol=eth_type_trans(skb,dev);
-                       dev->stats.rx_packets++;
-                       dev->stats.rx_bytes += length;
-                       netif_rx(skb);
-               }
-
-       dropped:
-               p->length = 1532;
-               p->status = 0;
-
-               rx_ring_tail=next_rx(rx_ring_tail);
-       }
-        while(x++<48);
-
-       /* If there was actually a frame to be processed, place the EOL bit */
-       /* at the descriptor prior to the one to be filled next */
-
-       if (rx_ring_tail != rx_old_tail)
-       {
-               lp->rx_ring[prev_rx(rx_ring_tail)].p->control |=  CONTROL_EOL;
-               lp->rx_ring[prev_rx(rx_old_tail)].p->control  &= ~CONTROL_EOL;
-
-               lp->rx_ring_tail=rx_ring_tail;
-       }
-}
-
-
-/**
- *     mc32_tx_ring    -       process completed transmits
- *     @dev: 3c527 that needs its transmit ring processing
- *
- *
- *     This operates in a similar fashion to mc32_rx_ring. We iterate
- *     over the transmit ring. For each descriptor which has been
- *     processed by the card, we free its associated buffer and note
- *     any errors. This continues until the transmit ring is emptied
- *     or we reach a descriptor that hasn't yet been processed by the
- *     card.
- *
- */
-
-static void mc32_tx_ring(struct net_device *dev)
-{
-       struct mc32_local *lp = netdev_priv(dev);
-       volatile struct skb_header *np;
-
-       /*
-        * We rely on head==tail to mean 'queue empty'.
-        * This is why lp->tx_count=TX_RING_LEN-1: in order to prevent
-        * tx_ring_head wrapping to tail and confusing a 'queue empty'
-        * condition with 'queue full'
-        */
-
-       while (lp->tx_ring_tail != atomic_read(&lp->tx_ring_head))
-       {
-               u16 t;
-
-               t=next_tx(lp->tx_ring_tail);
-               np=lp->tx_ring[t].p;
-
-               if(!(np->status & (1<<7)))
-               {
-                       /* Not COMPLETED */
-                       break;
-               }
-               dev->stats.tx_packets++;
-               if(!(np->status & (1<<6))) /* Not COMPLETED_OK */
-               {
-                       dev->stats.tx_errors++;
-
-                       switch(np->status&0x0F)
-                       {
-                               case 1:
-                                       dev->stats.tx_aborted_errors++;
-                                       break; /* Max collisions */
-                               case 2:
-                                       dev->stats.tx_fifo_errors++;
-                                       break;
-                               case 3:
-                                       dev->stats.tx_carrier_errors++;
-                                       break;
-                               case 4:
-                                       dev->stats.tx_window_errors++;
-                                       break;  /* CTS Lost */
-                               case 5:
-                                       dev->stats.tx_aborted_errors++;
-                                       break; /* Transmit timeout */
-                       }
-               }
-               /* Packets are sent in order - this is
-                   basically a FIFO queue of buffers matching
-                   the card ring */
-               dev->stats.tx_bytes+=lp->tx_ring[t].skb->len;
-               dev_kfree_skb_irq(lp->tx_ring[t].skb);
-               lp->tx_ring[t].skb=NULL;
-               atomic_inc(&lp->tx_count);
-               netif_wake_queue(dev);
-
-               lp->tx_ring_tail=t;
-       }
-
-}
-
-
-/**
- *     mc32_interrupt          -       handle an interrupt from a 3c527
- *     @irq: Interrupt number
- *     @dev_id: 3c527 that requires servicing
- *     @regs: Registers (unused)
- *
- *
- *     An interrupt is raised whenever the 3c527 writes to the command
- *     register. This register contains the message it wishes to send us
- *     packed into a single byte field. We keep reading status entries
- *     until we have processed all the control items, but simply count
- *     transmit and receive reports. When all reports are in we empty the
- *     transceiver rings as appropriate. This saves the overhead of
- *     multiple command requests.
- *
- *     Because MCA is level-triggered, we shouldn't miss indications.
- *     Therefore, we needn't ask the card to suspend interrupts within
- *     this handler. The card receives an implicit acknowledgment of the
- *     current interrupt when we read the command register.
- *
- */
-
-static irqreturn_t mc32_interrupt(int irq, void *dev_id)
-{
-       struct net_device *dev = dev_id;
-       struct mc32_local *lp;
-       int ioaddr, status, boguscount = 0;
-       int rx_event = 0;
-       int tx_event = 0;
-
-       ioaddr = dev->base_addr;
-       lp = netdev_priv(dev);
-
-       /* See whats cooking */
-
-       while((inb(ioaddr+HOST_STATUS)&HOST_STATUS_CWR) && boguscount++<2000)
-       {
-               status=inb(ioaddr+HOST_CMD);
-
-               pr_debug("Status TX%d RX%d EX%d OV%d BC%d\n",
-                       (status&7), (status>>3)&7, (status>>6)&1,
-                       (status>>7)&1, boguscount);
-
-               switch(status&7)
-               {
-                       case 0:
-                               break;
-                       case 6: /* TX fail */
-                       case 2: /* TX ok */
-                               tx_event = 1;
-                               break;
-                       case 3: /* Halt */
-                       case 4: /* Abort */
-                               complete(&lp->xceiver_cmd);
-                               break;
-                       default:
-                               pr_notice("%s: strange tx ack %d\n", dev->name, status&7);
-               }
-               status>>=3;
-               switch(status&7)
-               {
-                       case 0:
-                               break;
-                       case 2: /* RX */
-                               rx_event=1;
-                               break;
-                       case 3: /* Halt */
-                       case 4: /* Abort */
-                               complete(&lp->xceiver_cmd);
-                               break;
-                       case 6:
-                               /* Out of RX buffers stat */
-                               /* Must restart rx */
-                               dev->stats.rx_dropped++;
-                               mc32_rx_ring(dev);
-                               mc32_start_transceiver(dev);
-                               break;
-                       default:
-                               pr_notice("%s: strange rx ack %d\n",
-                                       dev->name, status&7);
-               }
-               status>>=3;
-               if(status&1)
-               {
-                       /*
-                        * No thread is waiting: we need to tidy
-                        * up ourself.
-                        */
-
-                       if (lp->cmd_nonblocking) {
-                               up(&lp->cmd_mutex);
-                               if (lp->mc_reload_wait)
-                                       mc32_reset_multicast_list(dev);
-                       }
-                       else complete(&lp->execution_cmd);
-               }
-               if(status&2)
-               {
-                       /*
-                        *      We get interrupted once per
-                        *      counter that is about to overflow.
-                        */
-
-                       mc32_update_stats(dev);
-               }
-       }
-
-
-       /*
-        *      Process the transmit and receive rings
-         */
-
-       if(tx_event)
-               mc32_tx_ring(dev);
-
-       if(rx_event)
-               mc32_rx_ring(dev);
-
-       return IRQ_HANDLED;
-}
-
-
-/**
- *     mc32_close      -       user configuring the 3c527 down
- *     @dev: 3c527 card to shut down
- *
- *     The 3c527 is a bus mastering device. We must be careful how we
- *     shut it down. It may also be running shared interrupt so we have
- *     to be sure to silence it properly
- *
- *     We indicate that the card is closing to the rest of the
- *     driver.  Otherwise, it is possible that the card may run out
- *     of receive buffers and restart the transceiver while we're
- *     trying to close it.
- *
- *     We abort any receive and transmits going on and then wait until
- *     any pending exec commands have completed in other code threads.
- *     In theory we can't get here while that is true, in practice I am
- *     paranoid
- *
- *     We turn off the interrupt enable for the board to be sure it can't
- *     intefere with other devices.
- */
-
-static int mc32_close(struct net_device *dev)
-{
-       struct mc32_local *lp = netdev_priv(dev);
-       int ioaddr = dev->base_addr;
-
-       u8 regs;
-       u16 one=1;
-
-       lp->xceiver_desired_state = HALTED;
-       netif_stop_queue(dev);
-
-       /*
-        *      Send the indications on command (handy debug check)
-        */
-
-       mc32_command(dev, 4, &one, 2);
-
-       /* Shut down the transceiver */
-
-       mc32_halt_transceiver(dev);
-
-       /* Ensure we issue no more commands beyond this point */
-
-       down(&lp->cmd_mutex);
-
-       /* Ok the card is now stopping */
-
-       regs=inb(ioaddr+HOST_CTRL);
-       regs&=~HOST_CTRL_INTE;
-       outb(regs, ioaddr+HOST_CTRL);
-
-       mc32_flush_rx_ring(dev);
-       mc32_flush_tx_ring(dev);
-
-       mc32_update_stats(dev);
-
-       return 0;
-}
-
-
-/**
- *     mc32_get_stats          -       hand back stats to network layer
- *     @dev: The 3c527 card to handle
- *
- *     We've collected all the stats we can in software already. Now
- *     it's time to update those kept on-card and return the lot.
- *
- */
-
-static struct net_device_stats *mc32_get_stats(struct net_device *dev)
-{
-       mc32_update_stats(dev);
-       return &dev->stats;
-}
-
-
-/**
- *     do_mc32_set_multicast_list      -       attempt to update multicasts
- *     @dev: 3c527 device to load the list on
- *     @retry: indicates this is not the first call.
- *
- *
- *     Actually set or clear the multicast filter for this adaptor. The
- *     locking issues are handled by this routine. We have to track
- *     state as it may take multiple calls to get the command sequence
- *     completed. We just keep trying to schedule the loads until we
- *     manage to process them all.
- *
- *     num_addrs == -1 Promiscuous mode, receive all packets
- *
- *     num_addrs == 0  Normal mode, clear multicast list
- *
- *     num_addrs > 0   Multicast mode, receive normal and MC packets,
- *                     and do best-effort filtering.
- *
- *     See mc32_update_stats() regards setting the SAV BP bit.
- *
- */
-
-static void do_mc32_set_multicast_list(struct net_device *dev, int retry)
-{
-       struct mc32_local *lp = netdev_priv(dev);
-       u16 filt = (1<<2); /* Save Bad Packets, for stats purposes */
-
-       if ((dev->flags&IFF_PROMISC) ||
-           (dev->flags&IFF_ALLMULTI) ||
-           netdev_mc_count(dev) > 10)
-               /* Enable promiscuous mode */
-               filt |= 1;
-       else if (!netdev_mc_empty(dev))
-       {
-               unsigned char block[62];
-               unsigned char *bp;
-               struct netdev_hw_addr *ha;
-
-               if(retry==0)
-                       lp->mc_list_valid = 0;
-               if(!lp->mc_list_valid)
-               {
-                       block[1]=0;
-                       block[0]=netdev_mc_count(dev);
-                       bp=block+2;
-
-                       netdev_for_each_mc_addr(ha, dev) {
-                               memcpy(bp, ha->addr, 6);
-                               bp+=6;
-                       }
-                       if(mc32_command_nowait(dev, 2, block,
-                                              2+6*netdev_mc_count(dev))==-1)
-                       {
-                               lp->mc_reload_wait = 1;
-                               return;
-                       }
-                       lp->mc_list_valid=1;
-               }
-       }
-
-       if(mc32_command_nowait(dev, 0, &filt, 2)==-1)
-       {
-               lp->mc_reload_wait = 1;
-       }
-       else {
-               lp->mc_reload_wait = 0;
-       }
-}
-
-
-/**
- *     mc32_set_multicast_list -       queue multicast list update
- *     @dev: The 3c527 to use
- *
- *     Commence loading the multicast list. This is called when the kernel
- *     changes the lists. It will override any pending list we are trying to
- *     load.
- */
-
-static void mc32_set_multicast_list(struct net_device *dev)
-{
-       do_mc32_set_multicast_list(dev,0);
-}
-
-
-/**
- *     mc32_reset_multicast_list       -       reset multicast list
- *     @dev: The 3c527 to use
- *
- *     Attempt the next step in loading the multicast lists. If this attempt
- *     fails to complete then it will be scheduled and this function called
- *     again later from elsewhere.
- */
-
-static void mc32_reset_multicast_list(struct net_device *dev)
-{
-       do_mc32_set_multicast_list(dev,1);
-}
-
-static void netdev_get_drvinfo(struct net_device *dev,
-                              struct ethtool_drvinfo *info)
-{
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       sprintf(info->bus_info, "MCA 0x%lx", dev->base_addr);
-}
-
-static u32 netdev_get_msglevel(struct net_device *dev)
-{
-       return mc32_debug;
-}
-
-static void netdev_set_msglevel(struct net_device *dev, u32 level)
-{
-       mc32_debug = level;
-}
-
-static const struct ethtool_ops netdev_ethtool_ops = {
-       .get_drvinfo            = netdev_get_drvinfo,
-       .get_msglevel           = netdev_get_msglevel,
-       .set_msglevel           = netdev_set_msglevel,
-};
-
-#ifdef MODULE
-
-static struct net_device *this_device;
-
-/**
- *     init_module             -       entry point
- *
- *     Probe and locate a 3c527 card. This really should probe and locate
- *     all the 3c527 cards in the machine not just one of them. Yes you can
- *     insmod multiple modules for now but it's a hack.
- */
-
-int __init init_module(void)
-{
-       this_device = mc32_probe(-1);
-       if (IS_ERR(this_device))
-               return PTR_ERR(this_device);
-       return 0;
-}
-
-/**
- *     cleanup_module  -       free resources for an unload
- *
- *     Unloading time. We release the MCA bus resources and the interrupt
- *     at which point everything is ready to unload. The card must be stopped
- *     at this point or we would not have been called. When we unload we
- *     leave the card stopped but not totally shut down. When the card is
- *     initialized it must be rebooted or the rings reloaded before any
- *     transmit operations are allowed to start scribbling into memory.
- */
-
-void __exit cleanup_module(void)
-{
-       unregister_netdev(this_device);
-       cleanup_card(this_device);
-       free_netdev(this_device);
-}
-
-#endif /* MODULE */
diff --git a/drivers/net/3c527.h b/drivers/net/3c527.h
deleted file mode 100644 (file)
index d693b8d..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- *     3COM "EtherLink MC/32" Descriptions
- */
-
-/*
- *     Registers
- */
-
-#define HOST_CMD               0
-#define         HOST_CMD_START_RX   (1<<3)
-#define         HOST_CMD_SUSPND_RX  (3<<3)
-#define         HOST_CMD_RESTRT_RX  (5<<3)
-
-#define         HOST_CMD_SUSPND_TX  3
-#define         HOST_CMD_RESTRT_TX  5
-
-
-#define HOST_STATUS            2
-#define                HOST_STATUS_CRR (1<<6)
-#define                HOST_STATUS_CWR (1<<5)
-
-
-#define HOST_CTRL              6
-#define                HOST_CTRL_ATTN  (1<<7)
-#define        HOST_CTRL_RESET (1<<6)
-#define        HOST_CTRL_INTE  (1<<2)
-
-#define HOST_RAMPAGE           8
-
-#define HALTED 0
-#define RUNNING 1
-
-struct mc32_mailbox
-{
-       u16 mbox;
-       u16 data[1];
-} __packed;
-
-struct skb_header
-{
-       u8 status;
-       u8 control;
-       u16 next;       /* Do not change! */
-       u16 length;
-       u32 data;
-} __packed;
-
-struct mc32_stats
-{
-       /* RX Errors */
-       u32 rx_crc_errors;
-       u32 rx_alignment_errors;
-       u32 rx_overrun_errors;
-       u32 rx_tooshort_errors;
-       u32 rx_toolong_errors;
-       u32 rx_outofresource_errors;
-
-       u32 rx_discarded;  /* via card pattern match filter */
-
-       /* TX Errors */
-       u32 tx_max_collisions;
-       u32 tx_carrier_errors;
-       u32 tx_underrun_errors;
-       u32 tx_cts_errors;
-       u32 tx_timeout_errors;
-
-       /* various cruft */
-       u32 dataA[6];
-       u16 dataB[5];
-       u32 dataC[14];
-} __packed;
-
-#define STATUS_MASK    0x0F
-#define COMPLETED      (1<<7)
-#define COMPLETED_OK   (1<<6)
-#define BUFFER_BUSY    (1<<5)
-
-#define CONTROL_EOP    (1<<7)  /* End Of Packet */
-#define CONTROL_EOL    (1<<6)  /* End of List */
-
-#define MCA_MC32_ID    0x0041  /* Our MCA ident */
diff --git a/drivers/net/82596.c b/drivers/net/82596.c
deleted file mode 100644 (file)
index be1f197..0000000
+++ /dev/null
@@ -1,1632 +0,0 @@
-/* 82596.c: A generic 82596 ethernet driver for linux. */
-/*
-   Based on Apricot.c
-   Written 1994 by Mark Evans.
-   This driver is for the Apricot 82596 bus-master interface
-
-   Modularised 12/94 Mark Evans
-
-
-   Modified to support the 82596 ethernet chips on 680x0 VME boards.
-   by Richard Hirst <richard@sleepie.demon.co.uk>
-   Renamed to be 82596.c
-
-   980825:  Changed to receive directly in to sk_buffs which are
-   allocated at open() time.  Eliminates copy on incoming frames
-   (small ones are still copied).  Shared data now held in a
-   non-cached page, so we can run on 68060 in copyback mode.
-
-   TBD:
-   * look at deferring rx frames rather than discarding (as per tulip)
-   * handle tx ring full as per tulip
-   * performance test to tune rx_copybreak
-
-   Most of my modifications relate to the braindead big-endian
-   implementation by Intel.  When the i596 is operating in
-   'big-endian' mode, it thinks a 32 bit value of 0x12345678
-   should be stored as 0x56781234.  This is a real pain, when
-   you have linked lists which are shared by the 680x0 and the
-   i596.
-
-   Driver skeleton
-   Written 1993 by Donald Becker.
-   Copyright 1993 United States Government as represented by the Director,
-   National Security Agency. This software may only be used and distributed
-   according to the terms of the GNU General Public License as modified by SRC,
-   incorporated herein by reference.
-
-   The author may be reached as becker@scyld.com, or C/O
-   Scyld Computing Corporation, 410 Severn Ave., Suite 210, Annapolis MD 21403
-
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/init.h>
-#include <linux/bitops.h>
-#include <linux/gfp.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/pgtable.h>
-#include <asm/cacheflush.h>
-
-static char version[] __initdata =
-       "82596.c $Revision: 1.5 $\n";
-
-#define DRV_NAME       "82596"
-
-/* DEBUG flags
- */
-
-#define DEB_INIT       0x0001
-#define DEB_PROBE      0x0002
-#define DEB_SERIOUS    0x0004
-#define DEB_ERRORS     0x0008
-#define DEB_MULTI      0x0010
-#define DEB_TDR                0x0020
-#define DEB_OPEN       0x0040
-#define DEB_RESET      0x0080
-#define DEB_ADDCMD     0x0100
-#define DEB_STATUS     0x0200
-#define DEB_STARTTX    0x0400
-#define DEB_RXADDR     0x0800
-#define DEB_TXADDR     0x1000
-#define DEB_RXFRAME    0x2000
-#define DEB_INTS       0x4000
-#define DEB_STRUCT     0x8000
-#define DEB_ANY                0xffff
-
-
-#define DEB(x,y)       if (i596_debug & (x)) y
-
-
-#if defined(CONFIG_MVME16x_NET) || defined(CONFIG_MVME16x_NET_MODULE)
-#define ENABLE_MVME16x_NET
-#endif
-#if defined(CONFIG_BVME6000_NET) || defined(CONFIG_BVME6000_NET_MODULE)
-#define ENABLE_BVME6000_NET
-#endif
-#if defined(CONFIG_APRICOT) || defined(CONFIG_APRICOT_MODULE)
-#define ENABLE_APRICOT
-#endif
-
-#ifdef ENABLE_MVME16x_NET
-#include <asm/mvme16xhw.h>
-#endif
-#ifdef ENABLE_BVME6000_NET
-#include <asm/bvme6000hw.h>
-#endif
-
-/*
- * Define various macros for Channel Attention, word swapping etc., dependent
- * on architecture.  MVME and BVME are 680x0 based, otherwise it is Intel.
- */
-
-#ifdef __mc68000__
-#define WSWAPrfd(x)  ((struct i596_rfd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
-#define WSWAPrbd(x)  ((struct i596_rbd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
-#define WSWAPiscp(x) ((struct i596_iscp *)(((u32)(x)<<16) | ((((u32)(x)))>>16)))
-#define WSWAPscb(x)  ((struct i596_scb *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
-#define WSWAPcmd(x)  ((struct i596_cmd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
-#define WSWAPtbd(x)  ((struct i596_tbd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
-#define WSWAPchar(x) ((char *)            (((u32)(x)<<16) | ((((u32)(x)))>>16)))
-#define ISCP_BUSY      0x00010000
-#define MACH_IS_APRICOT        0
-#else
-#define WSWAPrfd(x)     ((struct i596_rfd *)((long)x))
-#define WSWAPrbd(x)     ((struct i596_rbd *)((long)x))
-#define WSWAPiscp(x)    ((struct i596_iscp *)((long)x))
-#define WSWAPscb(x)     ((struct i596_scb *)((long)x))
-#define WSWAPcmd(x)     ((struct i596_cmd *)((long)x))
-#define WSWAPtbd(x)     ((struct i596_tbd *)((long)x))
-#define WSWAPchar(x)    ((char *)((long)x))
-#define ISCP_BUSY      0x0001
-#define MACH_IS_APRICOT        1
-#endif
-
-/*
- * The MPU_PORT command allows direct access to the 82596. With PORT access
- * the following commands are available (p5-18). The 32-bit port command
- * must be word-swapped with the most significant word written first.
- * This only applies to VME boards.
- */
-#define PORT_RESET             0x00    /* reset 82596 */
-#define PORT_SELFTEST          0x01    /* selftest */
-#define PORT_ALTSCP            0x02    /* alternate SCB address */
-#define PORT_ALTDUMP           0x03    /* Alternate DUMP address */
-
-static int i596_debug = (DEB_SERIOUS|DEB_PROBE);
-
-MODULE_AUTHOR("Richard Hirst");
-MODULE_DESCRIPTION("i82596 driver");
-MODULE_LICENSE("GPL");
-
-module_param(i596_debug, int, 0);
-MODULE_PARM_DESC(i596_debug, "i82596 debug mask");
-
-
-/* Copy frames shorter than rx_copybreak, otherwise pass on up in
- * a full sized sk_buff.  Value of 100 stolen from tulip.c (!alpha).
- */
-static int rx_copybreak = 100;
-
-#define PKT_BUF_SZ     1536
-#define MAX_MC_CNT     64
-
-#define I596_TOTAL_SIZE 17
-
-#define I596_NULL ((void *)0xffffffff)
-
-#define CMD_EOL                0x8000  /* The last command of the list, stop. */
-#define CMD_SUSP       0x4000  /* Suspend after doing cmd. */
-#define CMD_INTR       0x2000  /* Interrupt after doing cmd. */
-
-#define CMD_FLEX       0x0008  /* Enable flexible memory model */
-
-enum commands {
-       CmdNOp = 0, CmdSASetup = 1, CmdConfigure = 2, CmdMulticastList = 3,
-       CmdTx = 4, CmdTDR = 5, CmdDump = 6, CmdDiagnose = 7
-};
-
-#define STAT_C         0x8000  /* Set to 0 after execution */
-#define STAT_B         0x4000  /* Command being executed */
-#define STAT_OK                0x2000  /* Command executed ok */
-#define STAT_A         0x1000  /* Command aborted */
-
-#define         CUC_START      0x0100
-#define         CUC_RESUME     0x0200
-#define         CUC_SUSPEND    0x0300
-#define         CUC_ABORT      0x0400
-#define         RX_START       0x0010
-#define         RX_RESUME      0x0020
-#define         RX_SUSPEND     0x0030
-#define         RX_ABORT       0x0040
-
-#define TX_TIMEOUT     (HZ/20)
-
-
-struct i596_reg {
-       unsigned short porthi;
-       unsigned short portlo;
-       unsigned long ca;
-};
-
-#define EOF            0x8000
-#define SIZE_MASK      0x3fff
-
-struct i596_tbd {
-       unsigned short size;
-       unsigned short pad;
-       struct i596_tbd *next;
-       char *data;
-};
-
-/* The command structure has two 'next' pointers; v_next is the address of
- * the next command as seen by the CPU, b_next is the address of the next
- * command as seen by the 82596.  The b_next pointer, as used by the 82596
- * always references the status field of the next command, rather than the
- * v_next field, because the 82596 is unaware of v_next.  It may seem more
- * logical to put v_next at the end of the structure, but we cannot do that
- * because the 82596 expects other fields to be there, depending on command
- * type.
- */
-
-struct i596_cmd {
-       struct i596_cmd *v_next;        /* Address from CPUs viewpoint */
-       unsigned short status;
-       unsigned short command;
-       struct i596_cmd *b_next;        /* Address from i596 viewpoint */
-};
-
-struct tx_cmd {
-       struct i596_cmd cmd;
-       struct i596_tbd *tbd;
-       unsigned short size;
-       unsigned short pad;
-       struct sk_buff *skb;    /* So we can free it after tx */
-};
-
-struct tdr_cmd {
-       struct i596_cmd cmd;
-       unsigned short status;
-       unsigned short pad;
-};
-
-struct mc_cmd {
-       struct i596_cmd cmd;
-       short mc_cnt;
-       char mc_addrs[MAX_MC_CNT*6];
-};
-
-struct sa_cmd {
-       struct i596_cmd cmd;
-       char eth_addr[8];
-};
-
-struct cf_cmd {
-       struct i596_cmd cmd;
-       char i596_config[16];
-};
-
-struct i596_rfd {
-       unsigned short stat;
-       unsigned short cmd;
-       struct i596_rfd *b_next;        /* Address from i596 viewpoint */
-       struct i596_rbd *rbd;
-       unsigned short count;
-       unsigned short size;
-       struct i596_rfd *v_next;        /* Address from CPUs viewpoint */
-       struct i596_rfd *v_prev;
-};
-
-struct i596_rbd {
-    unsigned short count;
-    unsigned short zero1;
-    struct i596_rbd *b_next;
-    unsigned char *b_data;             /* Address from i596 viewpoint */
-    unsigned short size;
-    unsigned short zero2;
-    struct sk_buff *skb;
-    struct i596_rbd *v_next;
-    struct i596_rbd *b_addr;           /* This rbd addr from i596 view */
-    unsigned char *v_data;             /* Address from CPUs viewpoint */
-};
-
-#define TX_RING_SIZE 64
-#define RX_RING_SIZE 16
-
-struct i596_scb {
-       unsigned short status;
-       unsigned short command;
-       struct i596_cmd *cmd;
-       struct i596_rfd *rfd;
-       unsigned long crc_err;
-       unsigned long align_err;
-       unsigned long resource_err;
-       unsigned long over_err;
-       unsigned long rcvdt_err;
-       unsigned long short_err;
-       unsigned short t_on;
-       unsigned short t_off;
-};
-
-struct i596_iscp {
-       unsigned long stat;
-       struct i596_scb *scb;
-};
-
-struct i596_scp {
-       unsigned long sysbus;
-       unsigned long pad;
-       struct i596_iscp *iscp;
-};
-
-struct i596_private {
-       volatile struct i596_scp scp;
-       volatile struct i596_iscp iscp;
-       volatile struct i596_scb scb;
-       struct sa_cmd sa_cmd;
-       struct cf_cmd cf_cmd;
-       struct tdr_cmd tdr_cmd;
-       struct mc_cmd mc_cmd;
-       unsigned long stat;
-       int last_restart __attribute__((aligned(4)));
-       struct i596_rfd *rfd_head;
-       struct i596_rbd *rbd_head;
-       struct i596_cmd *cmd_tail;
-       struct i596_cmd *cmd_head;
-       int cmd_backlog;
-       unsigned long last_cmd;
-       struct i596_rfd rfds[RX_RING_SIZE];
-       struct i596_rbd rbds[RX_RING_SIZE];
-       struct tx_cmd tx_cmds[TX_RING_SIZE];
-       struct i596_tbd tbds[TX_RING_SIZE];
-       int next_tx_cmd;
-       spinlock_t lock;
-};
-
-static char init_setup[] =
-{
-       0x8E,                   /* length, prefetch on */
-       0xC8,                   /* fifo to 8, monitor off */
-#ifdef CONFIG_VME
-       0xc0,                   /* don't save bad frames */
-#else
-       0x80,                   /* don't save bad frames */
-#endif
-       0x2E,                   /* No source address insertion, 8 byte preamble */
-       0x00,                   /* priority and backoff defaults */
-       0x60,                   /* interframe spacing */
-       0x00,                   /* slot time LSB */
-       0xf2,                   /* slot time and retries */
-       0x00,                   /* promiscuous mode */
-       0x00,                   /* collision detect */
-       0x40,                   /* minimum frame length */
-       0xff,
-       0x00,
-       0x7f /*  *multi IA */ };
-
-static int i596_open(struct net_device *dev);
-static netdev_tx_t i596_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t i596_interrupt(int irq, void *dev_id);
-static int i596_close(struct net_device *dev);
-static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd);
-static void i596_tx_timeout (struct net_device *dev);
-static void print_eth(unsigned char *buf, char *str);
-static void set_multicast_list(struct net_device *dev);
-
-static int rx_ring_size = RX_RING_SIZE;
-static int ticks_limit = 25;
-static int max_cmd_backlog = TX_RING_SIZE-1;
-
-
-static inline void CA(struct net_device *dev)
-{
-#ifdef ENABLE_MVME16x_NET
-       if (MACH_IS_MVME16x) {
-               ((struct i596_reg *) dev->base_addr)->ca = 1;
-       }
-#endif
-#ifdef ENABLE_BVME6000_NET
-       if (MACH_IS_BVME6000) {
-               volatile u32 i;
-
-               i = *(volatile u32 *) (dev->base_addr);
-       }
-#endif
-#ifdef ENABLE_APRICOT
-       if (MACH_IS_APRICOT) {
-               outw(0, (short) (dev->base_addr) + 4);
-       }
-#endif
-}
-
-
-static inline void MPU_PORT(struct net_device *dev, int c, volatile void *x)
-{
-#ifdef ENABLE_MVME16x_NET
-       if (MACH_IS_MVME16x) {
-               struct i596_reg *p = (struct i596_reg *) (dev->base_addr);
-               p->porthi = ((c) | (u32) (x)) & 0xffff;
-               p->portlo = ((c) | (u32) (x)) >> 16;
-       }
-#endif
-#ifdef ENABLE_BVME6000_NET
-       if (MACH_IS_BVME6000) {
-               u32 v = (u32) (c) | (u32) (x);
-               v = ((u32) (v) << 16) | ((u32) (v) >> 16);
-               *(volatile u32 *) dev->base_addr = v;
-               udelay(1);
-               *(volatile u32 *) dev->base_addr = v;
-       }
-#endif
-}
-
-
-static inline int wait_istat(struct net_device *dev, struct i596_private *lp, int delcnt, char *str)
-{
-       while (--delcnt && lp->iscp.stat)
-               udelay(10);
-       if (!delcnt) {
-               printk(KERN_ERR "%s: %s, status %4.4x, cmd %4.4x.\n",
-                    dev->name, str, lp->scb.status, lp->scb.command);
-               return -1;
-       }
-       else
-               return 0;
-}
-
-
-static inline int wait_cmd(struct net_device *dev, struct i596_private *lp, int delcnt, char *str)
-{
-       while (--delcnt && lp->scb.command)
-               udelay(10);
-       if (!delcnt) {
-               printk(KERN_ERR "%s: %s, status %4.4x, cmd %4.4x.\n",
-                    dev->name, str, lp->scb.status, lp->scb.command);
-               return -1;
-       }
-       else
-               return 0;
-}
-
-
-static inline int wait_cfg(struct net_device *dev, struct i596_cmd *cmd, int delcnt, char *str)
-{
-       volatile struct i596_cmd *c = cmd;
-
-       while (--delcnt && c->command)
-               udelay(10);
-       if (!delcnt) {
-               printk(KERN_ERR "%s: %s.\n", dev->name, str);
-               return -1;
-       }
-       else
-               return 0;
-}
-
-
-static void i596_display_data(struct net_device *dev)
-{
-       struct i596_private *lp = dev->ml_priv;
-       struct i596_cmd *cmd;
-       struct i596_rfd *rfd;
-       struct i596_rbd *rbd;
-
-       printk(KERN_ERR "lp and scp at %p, .sysbus = %08lx, .iscp = %p\n",
-              &lp->scp, lp->scp.sysbus, lp->scp.iscp);
-       printk(KERN_ERR "iscp at %p, iscp.stat = %08lx, .scb = %p\n",
-              &lp->iscp, lp->iscp.stat, lp->iscp.scb);
-       printk(KERN_ERR "scb at %p, scb.status = %04x, .command = %04x,"
-               " .cmd = %p, .rfd = %p\n",
-              &lp->scb, lp->scb.status, lp->scb.command,
-               lp->scb.cmd, lp->scb.rfd);
-       printk(KERN_ERR "   errors: crc %lx, align %lx, resource %lx,"
-               " over %lx, rcvdt %lx, short %lx\n",
-               lp->scb.crc_err, lp->scb.align_err, lp->scb.resource_err,
-               lp->scb.over_err, lp->scb.rcvdt_err, lp->scb.short_err);
-       cmd = lp->cmd_head;
-       while (cmd != I596_NULL) {
-               printk(KERN_ERR "cmd at %p, .status = %04x, .command = %04x, .b_next = %p\n",
-                 cmd, cmd->status, cmd->command, cmd->b_next);
-               cmd = cmd->v_next;
-       }
-       rfd = lp->rfd_head;
-       printk(KERN_ERR "rfd_head = %p\n", rfd);
-       do {
-               printk(KERN_ERR "   %p .stat %04x, .cmd %04x, b_next %p, rbd %p,"
-                        " count %04x\n",
-                       rfd, rfd->stat, rfd->cmd, rfd->b_next, rfd->rbd,
-                       rfd->count);
-               rfd = rfd->v_next;
-       } while (rfd != lp->rfd_head);
-       rbd = lp->rbd_head;
-       printk(KERN_ERR "rbd_head = %p\n", rbd);
-       do {
-               printk(KERN_ERR "   %p .count %04x, b_next %p, b_data %p, size %04x\n",
-                       rbd, rbd->count, rbd->b_next, rbd->b_data, rbd->size);
-               rbd = rbd->v_next;
-       } while (rbd != lp->rbd_head);
-}
-
-
-#if defined(ENABLE_MVME16x_NET) || defined(ENABLE_BVME6000_NET)
-static irqreturn_t i596_error(int irq, void *dev_id)
-{
-       struct net_device *dev = dev_id;
-#ifdef ENABLE_MVME16x_NET
-       if (MACH_IS_MVME16x) {
-               volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000;
-
-               pcc2[0x28] = 1;
-               pcc2[0x2b] = 0x1d;
-       }
-#endif
-#ifdef ENABLE_BVME6000_NET
-       if (MACH_IS_BVME6000) {
-               volatile unsigned char *ethirq = (unsigned char *) BVME_ETHIRQ_REG;
-
-               *ethirq = 1;
-               *ethirq = 3;
-       }
-#endif
-       printk(KERN_ERR "%s: Error interrupt\n", dev->name);
-       i596_display_data(dev);
-       return IRQ_HANDLED;
-}
-#endif
-
-static inline void remove_rx_bufs(struct net_device *dev)
-{
-       struct i596_private *lp = dev->ml_priv;
-       struct i596_rbd *rbd;
-       int i;
-
-       for (i = 0, rbd = lp->rbds; i < rx_ring_size; i++, rbd++) {
-               if (rbd->skb == NULL)
-                       break;
-               dev_kfree_skb(rbd->skb);
-               rbd->skb = NULL;
-       }
-}
-
-static inline int init_rx_bufs(struct net_device *dev)
-{
-       struct i596_private *lp = dev->ml_priv;
-       int i;
-       struct i596_rfd *rfd;
-       struct i596_rbd *rbd;
-
-       /* First build the Receive Buffer Descriptor List */
-
-       for (i = 0, rbd = lp->rbds; i < rx_ring_size; i++, rbd++) {
-               struct sk_buff *skb = dev_alloc_skb(PKT_BUF_SZ);
-
-               if (skb == NULL) {
-                       remove_rx_bufs(dev);
-                       return -ENOMEM;
-               }
-
-               skb->dev = dev;
-               rbd->v_next = rbd+1;
-               rbd->b_next = WSWAPrbd(virt_to_bus(rbd+1));
-               rbd->b_addr = WSWAPrbd(virt_to_bus(rbd));
-               rbd->skb = skb;
-               rbd->v_data = skb->data;
-               rbd->b_data = WSWAPchar(virt_to_bus(skb->data));
-               rbd->size = PKT_BUF_SZ;
-#ifdef __mc68000__
-               cache_clear(virt_to_phys(skb->data), PKT_BUF_SZ);
-#endif
-       }
-       lp->rbd_head = lp->rbds;
-       rbd = lp->rbds + rx_ring_size - 1;
-       rbd->v_next = lp->rbds;
-       rbd->b_next = WSWAPrbd(virt_to_bus(lp->rbds));
-
-       /* Now build the Receive Frame Descriptor List */
-
-       for (i = 0, rfd = lp->rfds; i < rx_ring_size; i++, rfd++) {
-               rfd->rbd = I596_NULL;
-               rfd->v_next = rfd+1;
-               rfd->v_prev = rfd-1;
-               rfd->b_next = WSWAPrfd(virt_to_bus(rfd+1));
-               rfd->cmd = CMD_FLEX;
-       }
-       lp->rfd_head = lp->rfds;
-       lp->scb.rfd = WSWAPrfd(virt_to_bus(lp->rfds));
-       rfd = lp->rfds;
-       rfd->rbd = lp->rbd_head;
-       rfd->v_prev = lp->rfds + rx_ring_size - 1;
-       rfd = lp->rfds + rx_ring_size - 1;
-       rfd->v_next = lp->rfds;
-       rfd->b_next = WSWAPrfd(virt_to_bus(lp->rfds));
-       rfd->cmd = CMD_EOL|CMD_FLEX;
-
-       return 0;
-}
-
-
-static void rebuild_rx_bufs(struct net_device *dev)
-{
-       struct i596_private *lp = dev->ml_priv;
-       int i;
-
-       /* Ensure rx frame/buffer descriptors are tidy */
-
-       for (i = 0; i < rx_ring_size; i++) {
-               lp->rfds[i].rbd = I596_NULL;
-               lp->rfds[i].cmd = CMD_FLEX;
-       }
-       lp->rfds[rx_ring_size-1].cmd = CMD_EOL|CMD_FLEX;
-       lp->rfd_head = lp->rfds;
-       lp->scb.rfd = WSWAPrfd(virt_to_bus(lp->rfds));
-       lp->rbd_head = lp->rbds;
-       lp->rfds[0].rbd = WSWAPrbd(virt_to_bus(lp->rbds));
-}
-
-
-static int init_i596_mem(struct net_device *dev)
-{
-       struct i596_private *lp = dev->ml_priv;
-#if !defined(ENABLE_MVME16x_NET) && !defined(ENABLE_BVME6000_NET) || defined(ENABLE_APRICOT)
-       short ioaddr = dev->base_addr;
-#endif
-       unsigned long flags;
-
-       MPU_PORT(dev, PORT_RESET, NULL);
-
-       udelay(100);            /* Wait 100us - seems to help */
-
-#if defined(ENABLE_MVME16x_NET) || defined(ENABLE_BVME6000_NET)
-#ifdef ENABLE_MVME16x_NET
-       if (MACH_IS_MVME16x) {
-               volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000;
-
-               /* Disable all ints for now */
-               pcc2[0x28] = 1;
-               pcc2[0x2a] = 0x48;
-               /* Following disables snooping.  Snooping is not required
-                * as we make appropriate use of non-cached pages for
-                * shared data, and cache_push/cache_clear.
-                */
-               pcc2[0x2b] = 0x08;
-       }
-#endif
-#ifdef ENABLE_BVME6000_NET
-       if (MACH_IS_BVME6000) {
-               volatile unsigned char *ethirq = (unsigned char *) BVME_ETHIRQ_REG;
-
-               *ethirq = 1;
-       }
-#endif
-
-       /* change the scp address */
-
-       MPU_PORT(dev, PORT_ALTSCP, (void *)virt_to_bus((void *)&lp->scp));
-
-#elif defined(ENABLE_APRICOT)
-
-       {
-               u32 scp = virt_to_bus(&lp->scp);
-
-               /* change the scp address */
-               outw(0, ioaddr);
-               outw(0, ioaddr);
-               outb(4, ioaddr + 0xf);
-               outw(scp | 2, ioaddr);
-               outw(scp >> 16, ioaddr);
-       }
-#endif
-
-       lp->last_cmd = jiffies;
-
-#ifdef ENABLE_MVME16x_NET
-       if (MACH_IS_MVME16x)
-               lp->scp.sysbus = 0x00000054;
-#endif
-#ifdef ENABLE_BVME6000_NET
-       if (MACH_IS_BVME6000)
-               lp->scp.sysbus = 0x0000004c;
-#endif
-#ifdef ENABLE_APRICOT
-       if (MACH_IS_APRICOT)
-               lp->scp.sysbus = 0x00440000;
-#endif
-
-       lp->scp.iscp = WSWAPiscp(virt_to_bus((void *)&lp->iscp));
-       lp->iscp.scb = WSWAPscb(virt_to_bus((void *)&lp->scb));
-       lp->iscp.stat = ISCP_BUSY;
-       lp->cmd_backlog = 0;
-
-       lp->cmd_head = lp->scb.cmd = I596_NULL;
-
-#ifdef ENABLE_BVME6000_NET
-       if (MACH_IS_BVME6000) {
-               lp->scb.t_on  = 7 * 25;
-               lp->scb.t_off = 1 * 25;
-       }
-#endif
-
-       DEB(DEB_INIT,printk(KERN_DEBUG "%s: starting i82596.\n", dev->name));
-
-#if defined(ENABLE_APRICOT)
-       (void) inb(ioaddr + 0x10);
-       outb(4, ioaddr + 0xf);
-#endif
-       CA(dev);
-
-       if (wait_istat(dev,lp,1000,"initialization timed out"))
-               goto failed;
-       DEB(DEB_INIT,printk(KERN_DEBUG "%s: i82596 initialization successful\n", dev->name));
-
-       /* Ensure rx frame/buffer descriptors are tidy */
-       rebuild_rx_bufs(dev);
-       lp->scb.command = 0;
-
-#ifdef ENABLE_MVME16x_NET
-       if (MACH_IS_MVME16x) {
-               volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000;
-
-               /* Enable ints, etc. now */
-               pcc2[0x2a] = 0x55;      /* Edge sensitive */
-               pcc2[0x2b] = 0x15;
-       }
-#endif
-#ifdef ENABLE_BVME6000_NET
-       if (MACH_IS_BVME6000) {
-               volatile unsigned char *ethirq = (unsigned char *) BVME_ETHIRQ_REG;
-
-               *ethirq = 3;
-       }
-#endif
-
-
-       DEB(DEB_INIT,printk(KERN_DEBUG "%s: queuing CmdConfigure\n", dev->name));
-       memcpy(lp->cf_cmd.i596_config, init_setup, 14);
-       lp->cf_cmd.cmd.command = CmdConfigure;
-       i596_add_cmd(dev, &lp->cf_cmd.cmd);
-
-       DEB(DEB_INIT,printk(KERN_DEBUG "%s: queuing CmdSASetup\n", dev->name));
-       memcpy(lp->sa_cmd.eth_addr, dev->dev_addr, 6);
-       lp->sa_cmd.cmd.command = CmdSASetup;
-       i596_add_cmd(dev, &lp->sa_cmd.cmd);
-
-       DEB(DEB_INIT,printk(KERN_DEBUG "%s: queuing CmdTDR\n", dev->name));
-       lp->tdr_cmd.cmd.command = CmdTDR;
-       i596_add_cmd(dev, &lp->tdr_cmd.cmd);
-
-       spin_lock_irqsave (&lp->lock, flags);
-
-       if (wait_cmd(dev,lp,1000,"timed out waiting to issue RX_START")) {
-               spin_unlock_irqrestore (&lp->lock, flags);
-               goto failed;
-       }
-       DEB(DEB_INIT,printk(KERN_DEBUG "%s: Issuing RX_START\n", dev->name));
-       lp->scb.command = RX_START;
-       CA(dev);
-
-       spin_unlock_irqrestore (&lp->lock, flags);
-
-       if (wait_cmd(dev,lp,1000,"RX_START not processed"))
-               goto failed;
-       DEB(DEB_INIT,printk(KERN_DEBUG "%s: Receive unit started OK\n", dev->name));
-       return 0;
-
-failed:
-       printk(KERN_CRIT "%s: Failed to initialise 82596\n", dev->name);
-       MPU_PORT(dev, PORT_RESET, NULL);
-       return -1;
-}
-
-static inline int i596_rx(struct net_device *dev)
-{
-       struct i596_private *lp = dev->ml_priv;
-       struct i596_rfd *rfd;
-       struct i596_rbd *rbd;
-       int frames = 0;
-
-       DEB(DEB_RXFRAME,printk(KERN_DEBUG "i596_rx(), rfd_head %p, rbd_head %p\n",
-                       lp->rfd_head, lp->rbd_head));
-
-       rfd = lp->rfd_head;             /* Ref next frame to check */
-
-       while ((rfd->stat) & STAT_C) {  /* Loop while complete frames */
-               if (rfd->rbd == I596_NULL)
-                       rbd = I596_NULL;
-               else if (rfd->rbd == lp->rbd_head->b_addr)
-                       rbd = lp->rbd_head;
-               else {
-                       printk(KERN_CRIT "%s: rbd chain broken!\n", dev->name);
-                       /* XXX Now what? */
-                       rbd = I596_NULL;
-               }
-               DEB(DEB_RXFRAME, printk(KERN_DEBUG "  rfd %p, rfd.rbd %p, rfd.stat %04x\n",
-                       rfd, rfd->rbd, rfd->stat));
-
-               if (rbd != I596_NULL && ((rfd->stat) & STAT_OK)) {
-                       /* a good frame */
-                       int pkt_len = rbd->count & 0x3fff;
-                       struct sk_buff *skb = rbd->skb;
-                       int rx_in_place = 0;
-
-                       DEB(DEB_RXADDR,print_eth(rbd->v_data, "received"));
-                       frames++;
-
-                       /* 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;
-
-                               /* Get fresh skbuff to replace filled one. */
-                               newskb = dev_alloc_skb(PKT_BUF_SZ);
-                               if (newskb == NULL) {
-                                       skb = NULL;     /* drop pkt */
-                                       goto memory_squeeze;
-                               }
-                               /* Pass up the skb already on the Rx ring. */
-                               skb_put(skb, pkt_len);
-                               rx_in_place = 1;
-                               rbd->skb = newskb;
-                               newskb->dev = dev;
-                               rbd->v_data = newskb->data;
-                               rbd->b_data = WSWAPchar(virt_to_bus(newskb->data));
-#ifdef __mc68000__
-                               cache_clear(virt_to_phys(newskb->data), PKT_BUF_SZ);
-#endif
-                       }
-                       else
-                               skb = dev_alloc_skb(pkt_len + 2);
-memory_squeeze:
-                       if (skb == NULL) {
-                               /* XXX tulip.c can defer packets here!! */
-                               printk(KERN_WARNING "%s: i596_rx Memory squeeze, dropping packet.\n", dev->name);
-                               dev->stats.rx_dropped++;
-                       }
-                       else {
-                               if (!rx_in_place) {
-                                       /* 16 byte align the data fields */
-                                       skb_reserve(skb, 2);
-                                       memcpy(skb_put(skb,pkt_len), rbd->v_data, pkt_len);
-                               }
-                               skb->protocol=eth_type_trans(skb,dev);
-                               skb->len = pkt_len;
-#ifdef __mc68000__
-                               cache_clear(virt_to_phys(rbd->skb->data),
-                                               pkt_len);
-#endif
-                               netif_rx(skb);
-                               dev->stats.rx_packets++;
-                               dev->stats.rx_bytes+=pkt_len;
-                       }
-               }
-               else {
-                       DEB(DEB_ERRORS, printk(KERN_DEBUG "%s: Error, rfd.stat = 0x%04x\n",
-                                       dev->name, rfd->stat));
-                       dev->stats.rx_errors++;
-                       if ((rfd->stat) & 0x0001)
-                               dev->stats.collisions++;
-                       if ((rfd->stat) & 0x0080)
-                               dev->stats.rx_length_errors++;
-                       if ((rfd->stat) & 0x0100)
-                               dev->stats.rx_over_errors++;
-                       if ((rfd->stat) & 0x0200)
-                               dev->stats.rx_fifo_errors++;
-                       if ((rfd->stat) & 0x0400)
-                               dev->stats.rx_frame_errors++;
-                       if ((rfd->stat) & 0x0800)
-                               dev->stats.rx_crc_errors++;
-                       if ((rfd->stat) & 0x1000)
-                               dev->stats.rx_length_errors++;
-               }
-
-               /* Clear the buffer descriptor count and EOF + F flags */
-
-               if (rbd != I596_NULL && (rbd->count & 0x4000)) {
-                       rbd->count = 0;
-                       lp->rbd_head = rbd->v_next;
-               }
-
-               /* Tidy the frame descriptor, marking it as end of list */
-
-               rfd->rbd = I596_NULL;
-               rfd->stat = 0;
-               rfd->cmd = CMD_EOL|CMD_FLEX;
-               rfd->count = 0;
-
-               /* Remove end-of-list from old end descriptor */
-
-               rfd->v_prev->cmd = CMD_FLEX;
-
-               /* Update record of next frame descriptor to process */
-
-               lp->scb.rfd = rfd->b_next;
-               lp->rfd_head = rfd->v_next;
-               rfd = lp->rfd_head;
-       }
-
-       DEB(DEB_RXFRAME,printk(KERN_DEBUG "frames %d\n", frames));
-
-       return 0;
-}
-
-
-static void i596_cleanup_cmd(struct net_device *dev, struct i596_private *lp)
-{
-       struct i596_cmd *ptr;
-
-       while (lp->cmd_head != I596_NULL) {
-               ptr = lp->cmd_head;
-               lp->cmd_head = ptr->v_next;
-               lp->cmd_backlog--;
-
-               switch ((ptr->command) & 0x7) {
-               case CmdTx:
-                       {
-                               struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr;
-                               struct sk_buff *skb = tx_cmd->skb;
-
-                               dev_kfree_skb(skb);
-
-                               dev->stats.tx_errors++;
-                               dev->stats.tx_aborted_errors++;
-
-                               ptr->v_next = ptr->b_next = I596_NULL;
-                               tx_cmd->cmd.command = 0;  /* Mark as free */
-                               break;
-                       }
-               default:
-                       ptr->v_next = ptr->b_next = I596_NULL;
-               }
-       }
-
-       wait_cmd(dev,lp,100,"i596_cleanup_cmd timed out");
-       lp->scb.cmd = I596_NULL;
-}
-
-static void i596_reset(struct net_device *dev, struct i596_private *lp,
-                       int ioaddr)
-{
-       unsigned long flags;
-
-       DEB(DEB_RESET,printk(KERN_DEBUG "i596_reset\n"));
-
-       spin_lock_irqsave (&lp->lock, flags);
-
-       wait_cmd(dev,lp,100,"i596_reset timed out");
-
-       netif_stop_queue(dev);
-
-       lp->scb.command = CUC_ABORT | RX_ABORT;
-       CA(dev);
-
-       /* wait for shutdown */
-       wait_cmd(dev,lp,1000,"i596_reset 2 timed out");
-       spin_unlock_irqrestore (&lp->lock, flags);
-
-       i596_cleanup_cmd(dev,lp);
-       i596_rx(dev);
-
-       netif_start_queue(dev);
-       init_i596_mem(dev);
-}
-
-static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd)
-{
-       struct i596_private *lp = dev->ml_priv;
-       int ioaddr = dev->base_addr;
-       unsigned long flags;
-
-       DEB(DEB_ADDCMD,printk(KERN_DEBUG "i596_add_cmd\n"));
-
-       cmd->status = 0;
-       cmd->command |= (CMD_EOL | CMD_INTR);
-       cmd->v_next = cmd->b_next = I596_NULL;
-
-       spin_lock_irqsave (&lp->lock, flags);
-
-       if (lp->cmd_head != I596_NULL) {
-               lp->cmd_tail->v_next = cmd;
-               lp->cmd_tail->b_next = WSWAPcmd(virt_to_bus(&cmd->status));
-       } else {
-               lp->cmd_head = cmd;
-               wait_cmd(dev,lp,100,"i596_add_cmd timed out");
-               lp->scb.cmd = WSWAPcmd(virt_to_bus(&cmd->status));
-               lp->scb.command = CUC_START;
-               CA(dev);
-       }
-       lp->cmd_tail = cmd;
-       lp->cmd_backlog++;
-
-       spin_unlock_irqrestore (&lp->lock, flags);
-
-       if (lp->cmd_backlog > max_cmd_backlog) {
-               unsigned long tickssofar = jiffies - lp->last_cmd;
-
-               if (tickssofar < ticks_limit)
-                       return;
-
-               printk(KERN_NOTICE "%s: command unit timed out, status resetting.\n", dev->name);
-
-               i596_reset(dev, lp, ioaddr);
-       }
-}
-
-static int i596_open(struct net_device *dev)
-{
-       int res = 0;
-
-       DEB(DEB_OPEN,printk(KERN_DEBUG "%s: i596_open() irq %d.\n", dev->name, dev->irq));
-
-       if (request_irq(dev->irq, i596_interrupt, 0, "i82596", dev)) {
-               printk(KERN_ERR "%s: IRQ %d not free\n", dev->name, dev->irq);
-               return -EAGAIN;
-       }
-#ifdef ENABLE_MVME16x_NET
-       if (MACH_IS_MVME16x) {
-               if (request_irq(0x56, i596_error, 0, "i82596_error", dev)) {
-                       res = -EAGAIN;
-                       goto err_irq_dev;
-               }
-       }
-#endif
-       res = init_rx_bufs(dev);
-       if (res)
-               goto err_irq_56;
-
-       netif_start_queue(dev);
-
-       if (init_i596_mem(dev)) {
-               res = -EAGAIN;
-               goto err_queue;
-       }
-
-       return 0;
-
-err_queue:
-       netif_stop_queue(dev);
-       remove_rx_bufs(dev);
-err_irq_56:
-#ifdef ENABLE_MVME16x_NET
-       free_irq(0x56, dev);
-err_irq_dev:
-#endif
-       free_irq(dev->irq, dev);
-
-       return res;
-}
-
-static void i596_tx_timeout (struct net_device *dev)
-{
-       struct i596_private *lp = dev->ml_priv;
-       int ioaddr = dev->base_addr;
-
-       /* Transmitter timeout, serious problems. */
-       DEB(DEB_ERRORS,printk(KERN_ERR "%s: transmit timed out, status resetting.\n",
-                       dev->name));
-
-       dev->stats.tx_errors++;
-
-       /* Try to restart the adaptor */
-       if (lp->last_restart == dev->stats.tx_packets) {
-               DEB(DEB_ERRORS,printk(KERN_ERR "Resetting board.\n"));
-               /* Shutdown and restart */
-               i596_reset (dev, lp, ioaddr);
-       } else {
-               /* Issue a channel attention signal */
-               DEB(DEB_ERRORS,printk(KERN_ERR "Kicking board.\n"));
-               lp->scb.command = CUC_START | RX_START;
-               CA (dev);
-               lp->last_restart = dev->stats.tx_packets;
-       }
-
-       dev->trans_start = jiffies; /* prevent tx timeout */
-       netif_wake_queue (dev);
-}
-
-static netdev_tx_t i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-       struct i596_private *lp = dev->ml_priv;
-       struct tx_cmd *tx_cmd;
-       struct i596_tbd *tbd;
-       short length = skb->len;
-
-       DEB(DEB_STARTTX,printk(KERN_DEBUG "%s: i596_start_xmit(%x,%p) called\n",
-                               dev->name, skb->len, skb->data));
-
-       if (skb->len < ETH_ZLEN) {
-               if (skb_padto(skb, ETH_ZLEN))
-                       return NETDEV_TX_OK;
-               length = ETH_ZLEN;
-       }
-       netif_stop_queue(dev);
-
-       tx_cmd = lp->tx_cmds + lp->next_tx_cmd;
-       tbd = lp->tbds + lp->next_tx_cmd;
-
-       if (tx_cmd->cmd.command) {
-               printk(KERN_NOTICE "%s: xmit ring full, dropping packet.\n",
-                               dev->name);
-               dev->stats.tx_dropped++;
-
-               dev_kfree_skb(skb);
-       } else {
-               if (++lp->next_tx_cmd == TX_RING_SIZE)
-                       lp->next_tx_cmd = 0;
-               tx_cmd->tbd = WSWAPtbd(virt_to_bus(tbd));
-               tbd->next = I596_NULL;
-
-               tx_cmd->cmd.command = CMD_FLEX | CmdTx;
-               tx_cmd->skb = skb;
-
-               tx_cmd->pad = 0;
-               tx_cmd->size = 0;
-               tbd->pad = 0;
-               tbd->size = EOF | length;
-
-               tbd->data = WSWAPchar(virt_to_bus(skb->data));
-
-#ifdef __mc68000__
-               cache_push(virt_to_phys(skb->data), length);
-#endif
-               DEB(DEB_TXADDR,print_eth(skb->data, "tx-queued"));
-               i596_add_cmd(dev, &tx_cmd->cmd);
-
-               dev->stats.tx_packets++;
-               dev->stats.tx_bytes += length;
-       }
-
-       netif_start_queue(dev);
-
-       return NETDEV_TX_OK;
-}
-
-static void print_eth(unsigned char *add, char *str)
-{
-       printk(KERN_DEBUG "i596 0x%p, %pM --> %pM %02X%02X, %s\n",
-              add, add + 6, add, add[12], add[13], str);
-}
-
-static int io = 0x300;
-static int irq = 10;
-
-static const struct net_device_ops i596_netdev_ops = {
-       .ndo_open               = i596_open,
-       .ndo_stop               = i596_close,
-       .ndo_start_xmit         = i596_start_xmit,
-       .ndo_set_multicast_list = set_multicast_list,
-       .ndo_tx_timeout         = i596_tx_timeout,
-       .ndo_change_mtu         = eth_change_mtu,
-       .ndo_set_mac_address    = eth_mac_addr,
-       .ndo_validate_addr      = eth_validate_addr,
-};
-
-struct net_device * __init i82596_probe(int unit)
-{
-       struct net_device *dev;
-       int i;
-       struct i596_private *lp;
-       char eth_addr[8];
-       static int probed;
-       int err;
-
-       if (probed)
-               return ERR_PTR(-ENODEV);
-       probed++;
-
-       dev = alloc_etherdev(0);
-       if (!dev)
-               return ERR_PTR(-ENOMEM);
-
-       if (unit >= 0) {
-               sprintf(dev->name, "eth%d", unit);
-               netdev_boot_setup_check(dev);
-       } else {
-               dev->base_addr = io;
-               dev->irq = irq;
-       }
-
-#ifdef ENABLE_MVME16x_NET
-       if (MACH_IS_MVME16x) {
-               if (mvme16x_config & MVME16x_CONFIG_NO_ETHERNET) {
-                       printk(KERN_NOTICE "Ethernet probe disabled - chip not present\n");
-                       err = -ENODEV;
-                       goto out;
-               }
-               memcpy(eth_addr, (void *) 0xfffc1f2c, 6);       /* YUCK! Get addr from NOVRAM */
-               dev->base_addr = MVME_I596_BASE;
-               dev->irq = (unsigned) MVME16x_IRQ_I596;
-               goto found;
-       }
-#endif
-#ifdef ENABLE_BVME6000_NET
-       if (MACH_IS_BVME6000) {
-               volatile unsigned char *rtc = (unsigned char *) BVME_RTC_BASE;
-               unsigned char msr = rtc[3];
-               int i;
-
-               rtc[3] |= 0x80;
-               for (i = 0; i < 6; i++)
-                       eth_addr[i] = rtc[i * 4 + 7];   /* Stored in RTC RAM at offset 1 */
-               rtc[3] = msr;
-               dev->base_addr = BVME_I596_BASE;
-               dev->irq = (unsigned) BVME_IRQ_I596;
-               goto found;
-       }
-#endif
-#ifdef ENABLE_APRICOT
-       {
-               int checksum = 0;
-               int ioaddr = 0x300;
-
-               /* this is easy the ethernet interface can only be at 0x300 */
-               /* first check nothing is already registered here */
-
-               if (!request_region(ioaddr, I596_TOTAL_SIZE, DRV_NAME)) {
-                       printk(KERN_ERR "82596: IO address 0x%04x in use\n", ioaddr);
-                       err = -EBUSY;
-                       goto out;
-               }
-
-               dev->base_addr = ioaddr;
-
-               for (i = 0; i < 8; i++) {
-                       eth_addr[i] = inb(ioaddr + 8 + i);
-                       checksum += eth_addr[i];
-               }
-
-               /* checksum is a multiple of 0x100, got this wrong first time
-                  some machines have 0x100, some 0x200. The DOS driver doesn't
-                  even bother with the checksum.
-                  Some other boards trip the checksum.. but then appear as
-                  ether address 0. Trap these - AC */
-
-               if ((checksum % 0x100) ||
-                   (memcmp(eth_addr, "\x00\x00\x49", 3) != 0)) {
-                       err = -ENODEV;
-                       goto out1;
-               }
-
-               dev->irq = 10;
-               goto found;
-       }
-#endif
-       err = -ENODEV;
-       goto out;
-
-found:
-       dev->mem_start = (int)__get_free_pages(GFP_ATOMIC, 0);
-       if (!dev->mem_start) {
-               err = -ENOMEM;
-               goto out1;
-       }
-
-       DEB(DEB_PROBE,printk(KERN_INFO "%s: 82596 at %#3lx,", dev->name, dev->base_addr));
-
-       for (i = 0; i < 6; i++)
-               DEB(DEB_PROBE,printk(" %2.2X", dev->dev_addr[i] = eth_addr[i]));
-
-       DEB(DEB_PROBE,printk(" IRQ %d.\n", dev->irq));
-
-       DEB(DEB_PROBE,printk(KERN_INFO "%s", version));
-
-       /* The 82596-specific entries in the device structure. */
-       dev->netdev_ops = &i596_netdev_ops;
-       dev->watchdog_timeo = TX_TIMEOUT;
-
-       dev->ml_priv = (void *)(dev->mem_start);
-
-       lp = dev->ml_priv;
-       DEB(DEB_INIT,printk(KERN_DEBUG "%s: lp at 0x%08lx (%zd bytes), "
-                       "lp->scb at 0x%08lx\n",
-                       dev->name, (unsigned long)lp,
-                       sizeof(struct i596_private), (unsigned long)&lp->scb));
-       memset((void *) lp, 0, sizeof(struct i596_private));
-
-#ifdef __mc68000__
-       cache_push(virt_to_phys((void *)(dev->mem_start)), 4096);
-       cache_clear(virt_to_phys((void *)(dev->mem_start)), 4096);
-       kernel_set_cachemode((void *)(dev->mem_start), 4096, IOMAP_NOCACHE_SER);
-#endif
-       lp->scb.command = 0;
-       lp->scb.cmd = I596_NULL;
-       lp->scb.rfd = I596_NULL;
-       spin_lock_init(&lp->lock);
-
-       err = register_netdev(dev);
-       if (err)
-               goto out2;
-       return dev;
-out2:
-#ifdef __mc68000__
-       /* XXX This assumes default cache mode to be IOMAP_FULL_CACHING,
-        * XXX which may be invalid (CONFIG_060_WRITETHROUGH)
-        */
-       kernel_set_cachemode((void *)(dev->mem_start), 4096,
-                       IOMAP_FULL_CACHING);
-#endif
-       free_page ((u32)(dev->mem_start));
-out1:
-#ifdef ENABLE_APRICOT
-       release_region(dev->base_addr, I596_TOTAL_SIZE);
-#endif
-out:
-       free_netdev(dev);
-       return ERR_PTR(err);
-}
-
-static irqreturn_t i596_interrupt(int irq, void *dev_id)
-{
-       struct net_device *dev = dev_id;
-       struct i596_private *lp;
-       short ioaddr;
-       unsigned short status, ack_cmd = 0;
-       int handled = 0;
-
-#ifdef ENABLE_BVME6000_NET
-       if (MACH_IS_BVME6000) {
-               if (*(char *) BVME_LOCAL_IRQ_STAT & BVME_ETHERR) {
-                       i596_error(irq, dev_id);
-                       return IRQ_HANDLED;
-               }
-       }
-#endif
-       if (dev == NULL) {
-               printk(KERN_ERR "i596_interrupt(): irq %d for unknown device.\n", irq);
-               return IRQ_NONE;
-       }
-
-       ioaddr = dev->base_addr;
-       lp = dev->ml_priv;
-
-       spin_lock (&lp->lock);
-
-       wait_cmd(dev,lp,100,"i596 interrupt, timeout");
-       status = lp->scb.status;
-
-       DEB(DEB_INTS,printk(KERN_DEBUG "%s: i596 interrupt, IRQ %d, status %4.4x.\n",
-                       dev->name, irq, status));
-
-       ack_cmd = status & 0xf000;
-
-       if ((status & 0x8000) || (status & 0x2000)) {
-               struct i596_cmd *ptr;
-
-               handled = 1;
-               if ((status & 0x8000))
-                       DEB(DEB_INTS,printk(KERN_DEBUG "%s: i596 interrupt completed command.\n", dev->name));
-               if ((status & 0x2000))
-                       DEB(DEB_INTS,printk(KERN_DEBUG "%s: i596 interrupt command unit inactive %x.\n", dev->name, status & 0x0700));
-
-               while ((lp->cmd_head != I596_NULL) && (lp->cmd_head->status & STAT_C)) {
-                       ptr = lp->cmd_head;
-
-                       DEB(DEB_STATUS,printk(KERN_DEBUG "cmd_head->status = %04x, ->command = %04x\n",
-                                      lp->cmd_head->status, lp->cmd_head->command));
-                       lp->cmd_head = ptr->v_next;
-                       lp->cmd_backlog--;
-
-                       switch ((ptr->command) & 0x7) {
-                       case CmdTx:
-                           {
-                               struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr;
-                               struct sk_buff *skb = tx_cmd->skb;
-
-                               if ((ptr->status) & STAT_OK) {
-                                       DEB(DEB_TXADDR,print_eth(skb->data, "tx-done"));
-                               } else {
-                                       dev->stats.tx_errors++;
-                                       if ((ptr->status) & 0x0020)
-                                               dev->stats.collisions++;
-                                       if (!((ptr->status) & 0x0040))
-                                               dev->stats.tx_heartbeat_errors++;
-                                       if ((ptr->status) & 0x0400)
-                                               dev->stats.tx_carrier_errors++;
-                                       if ((ptr->status) & 0x0800)
-                                               dev->stats.collisions++;
-                                       if ((ptr->status) & 0x1000)
-                                               dev->stats.tx_aborted_errors++;
-                               }
-
-                               dev_kfree_skb_irq(skb);
-
-                               tx_cmd->cmd.command = 0; /* Mark free */
-                               break;
-                           }
-                       case CmdTDR:
-                           {
-                               unsigned short status = ((struct tdr_cmd *)ptr)->status;
-
-                               if (status & 0x8000) {
-                                       DEB(DEB_TDR,printk(KERN_INFO "%s: link ok.\n", dev->name));
-                               } else {
-                                       if (status & 0x4000)
-                                               printk(KERN_ERR "%s: Transceiver problem.\n", dev->name);
-                                       if (status & 0x2000)
-                                               printk(KERN_ERR "%s: Termination problem.\n", dev->name);
-                                       if (status & 0x1000)
-                                               printk(KERN_ERR "%s: Short circuit.\n", dev->name);
-
-                                       DEB(DEB_TDR,printk(KERN_INFO "%s: Time %d.\n", dev->name, status & 0x07ff));
-                               }
-                               break;
-                           }
-                       case CmdConfigure:
-                       case CmdMulticastList:
-                               /* Zap command so set_multicast_list() knows it is free */
-                               ptr->command = 0;
-                               break;
-                       }
-                       ptr->v_next = ptr->b_next = I596_NULL;
-                       lp->last_cmd = jiffies;
-               }
-
-               ptr = lp->cmd_head;
-               while ((ptr != I596_NULL) && (ptr != lp->cmd_tail)) {
-                       ptr->command &= 0x1fff;
-                       ptr = ptr->v_next;
-               }
-
-               if ((lp->cmd_head != I596_NULL))
-                       ack_cmd |= CUC_START;
-               lp->scb.cmd = WSWAPcmd(virt_to_bus(&lp->cmd_head->status));
-       }
-       if ((status & 0x1000) || (status & 0x4000)) {
-               if ((status & 0x4000))
-                       DEB(DEB_INTS,printk(KERN_DEBUG "%s: i596 interrupt received a frame.\n", dev->name));
-               i596_rx(dev);
-               /* Only RX_START if stopped - RGH 07-07-96 */
-               if (status & 0x1000) {
-                       if (netif_running(dev)) {
-                               DEB(DEB_ERRORS,printk(KERN_ERR "%s: i596 interrupt receive unit inactive, status 0x%x\n", dev->name, status));
-                               ack_cmd |= RX_START;
-                               dev->stats.rx_errors++;
-                               dev->stats.rx_fifo_errors++;
-                               rebuild_rx_bufs(dev);
-                       }
-               }
-       }
-       wait_cmd(dev,lp,100,"i596 interrupt, timeout");
-       lp->scb.command = ack_cmd;
-
-#ifdef ENABLE_MVME16x_NET
-       if (MACH_IS_MVME16x) {
-               /* Ack the interrupt */
-
-               volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000;
-
-               pcc2[0x2a] |= 0x08;
-       }
-#endif
-#ifdef ENABLE_BVME6000_NET
-       if (MACH_IS_BVME6000) {
-               volatile unsigned char *ethirq = (unsigned char *) BVME_ETHIRQ_REG;
-
-               *ethirq = 1;
-               *ethirq = 3;
-       }
-#endif
-#ifdef ENABLE_APRICOT
-       (void) inb(ioaddr + 0x10);
-       outb(4, ioaddr + 0xf);
-#endif
-       CA(dev);
-
-       DEB(DEB_INTS,printk(KERN_DEBUG "%s: exiting interrupt.\n", dev->name));
-
-       spin_unlock (&lp->lock);
-       return IRQ_RETVAL(handled);
-}
-
-static int i596_close(struct net_device *dev)
-{
-       struct i596_private *lp = dev->ml_priv;
-       unsigned long flags;
-
-       netif_stop_queue(dev);
-
-       DEB(DEB_INIT,printk(KERN_DEBUG "%s: Shutting down ethercard, status was %4.4x.\n",
-                      dev->name, lp->scb.status));
-
-       spin_lock_irqsave(&lp->lock, flags);
-
-       wait_cmd(dev,lp,100,"close1 timed out");
-       lp->scb.command = CUC_ABORT | RX_ABORT;
-       CA(dev);
-
-       wait_cmd(dev,lp,100,"close2 timed out");
-
-       spin_unlock_irqrestore(&lp->lock, flags);
-       DEB(DEB_STRUCT,i596_display_data(dev));
-       i596_cleanup_cmd(dev,lp);
-
-#ifdef ENABLE_MVME16x_NET
-       if (MACH_IS_MVME16x) {
-               volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000;
-
-               /* Disable all ints */
-               pcc2[0x28] = 1;
-               pcc2[0x2a] = 0x40;
-               pcc2[0x2b] = 0x40;      /* Set snooping bits now! */
-       }
-#endif
-#ifdef ENABLE_BVME6000_NET
-       if (MACH_IS_BVME6000) {
-               volatile unsigned char *ethirq = (unsigned char *) BVME_ETHIRQ_REG;
-
-               *ethirq = 1;
-       }
-#endif
-
-#ifdef ENABLE_MVME16x_NET
-       free_irq(0x56, dev);
-#endif
-       free_irq(dev->irq, dev);
-       remove_rx_bufs(dev);
-
-       return 0;
-}
-
-/*
- *    Set or clear the multicast filter for this adaptor.
- */
-
-static void set_multicast_list(struct net_device *dev)
-{
-       struct i596_private *lp = dev->ml_priv;
-       int config = 0, cnt;
-
-       DEB(DEB_MULTI,printk(KERN_DEBUG "%s: set multicast list, %d entries, promisc %s, allmulti %s\n",
-               dev->name, netdev_mc_count(dev),
-               dev->flags & IFF_PROMISC  ? "ON" : "OFF",
-               dev->flags & IFF_ALLMULTI ? "ON" : "OFF"));
-
-       if (wait_cfg(dev, &lp->cf_cmd.cmd, 1000, "config change request timed out"))
-               return;
-
-       if ((dev->flags & IFF_PROMISC) && !(lp->cf_cmd.i596_config[8] & 0x01)) {
-               lp->cf_cmd.i596_config[8] |= 0x01;
-               config = 1;
-       }
-       if (!(dev->flags & IFF_PROMISC) && (lp->cf_cmd.i596_config[8] & 0x01)) {
-               lp->cf_cmd.i596_config[8] &= ~0x01;
-               config = 1;
-       }
-       if ((dev->flags & IFF_ALLMULTI) && (lp->cf_cmd.i596_config[11] & 0x20)) {
-               lp->cf_cmd.i596_config[11] &= ~0x20;
-               config = 1;
-       }
-       if (!(dev->flags & IFF_ALLMULTI) && !(lp->cf_cmd.i596_config[11] & 0x20)) {
-               lp->cf_cmd.i596_config[11] |= 0x20;
-               config = 1;
-       }
-       if (config) {
-               lp->cf_cmd.cmd.command = CmdConfigure;
-               i596_add_cmd(dev, &lp->cf_cmd.cmd);
-       }
-
-       cnt = netdev_mc_count(dev);
-       if (cnt > MAX_MC_CNT)
-       {
-               cnt = MAX_MC_CNT;
-               printk(KERN_ERR "%s: Only %d multicast addresses supported",
-                       dev->name, cnt);
-       }
-
-       if (!netdev_mc_empty(dev)) {
-               struct netdev_hw_addr *ha;
-               unsigned char *cp;
-               struct mc_cmd *cmd;
-
-               if (wait_cfg(dev, &lp->mc_cmd.cmd, 1000, "multicast list change request timed out"))
-                       return;
-               cmd = &lp->mc_cmd;
-               cmd->cmd.command = CmdMulticastList;
-               cmd->mc_cnt = cnt * ETH_ALEN;
-               cp = cmd->mc_addrs;
-               netdev_for_each_mc_addr(ha, dev) {
-                       if (!cnt--)
-                               break;
-                       memcpy(cp, ha->addr, ETH_ALEN);
-                       if (i596_debug > 1)
-                               DEB(DEB_MULTI,printk(KERN_INFO "%s: Adding address %pM\n",
-                                               dev->name, cp));
-                       cp += ETH_ALEN;
-               }
-               i596_add_cmd(dev, &cmd->cmd);
-       }
-}
-
-#ifdef MODULE
-static struct net_device *dev_82596;
-
-#ifdef ENABLE_APRICOT
-module_param(irq, int, 0);
-MODULE_PARM_DESC(irq, "Apricot IRQ number");
-#endif
-
-static int debug = -1;
-module_param(debug, int, 0);
-MODULE_PARM_DESC(debug, "i82596 debug mask");
-
-int __init init_module(void)
-{
-       if (debug >= 0)
-               i596_debug = debug;
-       dev_82596 = i82596_probe(-1);
-       if (IS_ERR(dev_82596))
-               return PTR_ERR(dev_82596);
-       return 0;
-}
-
-void __exit cleanup_module(void)
-{
-       unregister_netdev(dev_82596);
-#ifdef __mc68000__
-       /* XXX This assumes default cache mode to be IOMAP_FULL_CACHING,
-        * XXX which may be invalid (CONFIG_060_WRITETHROUGH)
-        */
-
-       kernel_set_cachemode((void *)(dev_82596->mem_start), 4096,
-                       IOMAP_FULL_CACHING);
-#endif
-       free_page ((u32)(dev_82596->mem_start));
-#ifdef ENABLE_APRICOT
-       /* If we don't do this, we can't re-insmod it later. */
-       release_region(dev_82596->base_addr, I596_TOTAL_SIZE);
-#endif
-       free_netdev(dev_82596);
-}
-
-#endif                         /* MODULE */
index 649918609cb64fd9da583e737abfd50cf585ce21..d7d0b3532bc339368dbf2c1d6d48b81009d56f1f 100644 (file)
@@ -306,47 +306,6 @@ config MACMACE
          say Y and read the Ethernet-HOWTO, available from
          <http://www.tldp.org/docs.html#howto>.
 
-config MVME16x_NET
-       tristate "MVME16x Ethernet support"
-       depends on MVME16x
-       help
-         This is the driver for the Ethernet interface on the Motorola
-         MVME162, 166, 167, 172 and 177 boards.  Say Y here to include the
-         driver for this chip in your kernel.
-         To compile this driver as a module, choose M here.
-
-config BVME6000_NET
-       tristate "BVME6000 Ethernet support"
-       depends on BVME6000
-       help
-         This is the driver for the Ethernet interface on BVME4000 and
-         BVME6000 VME boards.  Say Y here to include the driver for this chip
-         in your kernel.
-         To compile this driver as a module, choose M here.
-
-config SUN3_82586
-       bool "Sun3 on-board Intel 82586 support"
-       depends on SUN3
-       help
-         This driver enables support for the on-board Intel 82586 based
-         Ethernet adapter found on Sun 3/1xx and 3/2xx motherboards.  Note
-         that this driver does not support 82586-based adapters on additional
-         VME boards.
-
-config LASI_82596
-       tristate "Lasi ethernet"
-       depends on GSC
-       help
-         Say Y here to support the builtin Intel 82596 ethernet controller
-         found in Hewlett-Packard PA-RISC machines with 10Mbit ethernet.
-
-config SNI_82596
-       tristate "SNI RM ethernet"
-       depends on NET_ETHERNET && SNI_RM
-       help
-         Say Y here to support the on-board Intel 82596 ethernet controller
-         built into SNI RM machines.
-
 config KORINA
        tristate "Korina (IDT RC32434) Ethernet support"
        depends on NET_ETHERNET && MIKROTIK_RB532
@@ -462,63 +421,6 @@ config SUNVNET
        help
          Support for virtual network devices under Sun Logical Domains.
 
-config EL2
-       tristate "3c503 \"EtherLink II\" support"
-       depends on ISA
-       select CRC32
-       ---help---
-         If you have a network (Ethernet) card of this type, say Y and read
-         the Ethernet-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>.
-
-         To compile this driver as a module, choose M here. The module
-         will be called 3c503.
-
-config ELPLUS
-       tristate "3c505 \"EtherLink Plus\" support"
-       depends on ISA && ISA_DMA_API
-       ---help---
-         Information about this network (Ethernet) card can be found in
-         <file:Documentation/networking/3c505.txt>.  If you have a card of
-         this type, say Y and read the Ethernet-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>.
-
-         To compile this driver as a module, choose M here. The module
-         will be called 3c505.
-
-config EL16
-       tristate "3c507 \"EtherLink 16\" support (EXPERIMENTAL)"
-       depends on ISA && EXPERIMENTAL
-       ---help---
-         If you have a network (Ethernet) card of this type, say Y and read
-         the Ethernet-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>.
-
-         To compile this driver as a module, choose M here. The module
-         will be called 3c507.
-
-config ELMC
-       tristate "3c523 \"EtherLink/MC\" support"
-       depends on MCA_LEGACY
-       ---help---
-         If you have a network (Ethernet) card of this type, say Y and read
-         the Ethernet-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>.
-
-         To compile this driver as a module, choose M here. The module
-         will be called 3c523.
-
-config ELMC_II
-       tristate "3c527 \"EtherLink/MC 32\" support (EXPERIMENTAL)"
-       depends on MCA && MCA_LEGACY
-       ---help---
-         If you have a network (Ethernet) card of this type, say Y and read
-         the Ethernet-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>.
-
-         To compile this driver as a module, choose M here. The module
-         will be called 3c527.
-
 config BFIN_MAC
        tristate "Blackfin on-chip MAC support"
        depends on NET_ETHERNET && (BF516 || BF518 || BF526 || BF527 || BF536 || BF537)
@@ -684,7 +586,7 @@ config NET_VENDOR_RACAL
        depends on ISA
        help
          If you have a network (Ethernet) card belonging to this class, such
-         as the NI5010, NI5210 or NI6210, say Y and read the Ethernet-HOWTO,
+         as the NI5010, say Y and read the Ethernet-HOWTO,
          available from <http://www.tldp.org/docs.html#howto>.
 
          Note that the answer to this question doesn't directly affect the
@@ -704,17 +606,6 @@ config NI5010
          To compile this driver as a module, choose M here. The module
          will be called ni5010.
 
-config NI52
-       tristate "NI5210 support"
-       depends on NET_VENDOR_RACAL && ISA
-       help
-         If you have a network (Ethernet) card of this type, say Y and read
-         the Ethernet-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>.
-
-         To compile this driver as a module, choose M here. The module
-         will be called ni52.
-
 config DNET
        tristate "Dave ethernet support (DNET)"
        depends on NET_ETHERNET && HAS_IOMEM
@@ -782,41 +673,6 @@ config EWRK3
          To compile this driver as a module, choose M here. The module
          will be called ewrk3.
 
-config EEXPRESS
-       tristate "EtherExpress 16 support"
-       depends on NET_ISA
-       ---help---
-         If you have an EtherExpress16 network (Ethernet) card, say Y and
-         read the Ethernet-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>.  Note that the Intel
-         EtherExpress16 card used to be regarded as a very poor choice
-         because the driver was very unreliable. We now have a new driver
-         that should do better.
-
-         To compile this driver as a module, choose M here. The module
-         will be called eexpress.
-
-config EEXPRESS_PRO
-       tristate "EtherExpressPro support/EtherExpress 10 (i82595) support"
-       depends on NET_ISA
-       ---help---
-         If you have a network (Ethernet) card of this type, say Y. This
-         driver supports Intel i82595{FX,TX} based boards. Note however
-         that the EtherExpress PRO/100 Ethernet card has its own separate
-         driver.  Please read the Ethernet-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>.
-
-         To compile this driver as a module, choose M here. The module
-         will be called eepro.
-
-config LP486E
-       tristate "LP486E on board Ethernet"
-       depends on NET_ISA
-       help
-         Say Y here to support the 82596-based on-board Ethernet controller
-         for the Panther motherboard, which is one of the two shipped in the
-         Intel Professional Workstation.
-
 config ETH16I
        tristate "ICL EtherTeam 16i/32 support"
        depends on NET_ISA
@@ -828,16 +684,6 @@ config ETH16I
          To compile this driver as a module, choose M here. The module
          will be called eth16i.
 
-config ZNET
-       tristate "Zenith Z-Note support (EXPERIMENTAL)"
-       depends on NET_ISA && EXPERIMENTAL && ISA_DMA_API
-       help
-         The Zenith Z-Note notebook computer has a built-in network
-         (Ethernet) card, and this is the Linux driver for it. Note that the
-         IBM Thinkpad 300 is compatible with the Z-Note and is also supported
-         by this driver. Read the Ethernet-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>.
-
 config SEEQ8005
        tristate "SEEQ8005 support (EXPERIMENTAL)"
        depends on NET_ISA && EXPERIMENTAL
@@ -915,17 +761,6 @@ config KSZ884X_PCI
          To compile this driver as a module, choose M here. The module
          will be called ksz884x.
 
-config APRICOT
-       tristate "Apricot Xen-II on board Ethernet"
-       depends on NET_PCI && ISA
-       help
-         If you have a network (Ethernet) controller of this type, say Y and
-         read the Ethernet-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>.
-
-         To compile this driver as a module, choose M here. The module
-         will be called apricot.
-
 config FORCEDETH
        tristate "nForce Ethernet support"
        depends on NET_PCI && PCI
index e74b4244ee7f2bf60a6e5d5c27e97cc31968a137..49b3e87075d36b1ebce1027706307b9a0879001d 100644 (file)
@@ -130,36 +130,19 @@ obj-$(CONFIG_MACVLAN) += macvlan.o
 obj-$(CONFIG_MACVTAP) += macvtap.o
 obj-$(CONFIG_DE600) += de600.o
 obj-$(CONFIG_DE620) += de620.o
-obj-$(CONFIG_SUN3_82586) += sun3_82586.o
 obj-$(CONFIG_DEFXX) += defxx.o
 obj-$(CONFIG_SGISEEQ) += sgiseeq.o
 obj-$(CONFIG_SGI_O2MACE_ETH) += meth.o
 obj-$(CONFIG_AT1700) += at1700.o
-obj-$(CONFIG_EL16) += 3c507.o
-obj-$(CONFIG_ELMC) += 3c523.o
 obj-$(CONFIG_IBMLANA) += ibmlana.o
-obj-$(CONFIG_ELMC_II) += 3c527.o
-obj-$(CONFIG_EEXPRESS) += eexpress.o
-obj-$(CONFIG_EEXPRESS_PRO) += eepro.o
 obj-$(CONFIG_8139CP) += 8139cp.o
 obj-$(CONFIG_8139TOO) += 8139too.o
-obj-$(CONFIG_ZNET) += znet.o
 obj-$(CONFIG_CPMAC) += cpmac.o
 obj-$(CONFIG_EWRK3) += ewrk3.o
 obj-$(CONFIG_ATP) += atp.o
 obj-$(CONFIG_NI5010) += ni5010.o
-obj-$(CONFIG_NI52) += ni52.o
-obj-$(CONFIG_ELPLUS) += 3c505.o
-obj-$(CONFIG_APRICOT) += 82596.o
-obj-$(CONFIG_LASI_82596) += lasi_82596.o
-obj-$(CONFIG_SNI_82596) += sni_82596.o
-obj-$(CONFIG_MVME16x_NET) += 82596.o
-obj-$(CONFIG_BVME6000_NET) += 82596.o
 obj-$(CONFIG_SC92031) += sc92031.o
 
-# This is also a 82596 and should probably be merged
-obj-$(CONFIG_LP486E) += lp486e.o
-
 obj-$(CONFIG_ETH16I) += eth16i.o
 obj-$(CONFIG_EQUALIZER) += eql.o
 obj-$(CONFIG_KORINA) += korina.o
index 715bf2acc24b643d856da4f1fdcbadbd6f526d5f..7848b5f670131e35d1bda98db0dfadbf66333666 100644 (file)
@@ -3,13 +3,6 @@
 #  These are for Acorn's Expansion card network interfaces
 #
 
-config ARM_ETHER1
-       tristate "Acorn Ether1 support"
-       depends on ARM && ARCH_ACORN
-       help
-         If you have an Acorn system with one of these (AKA25) network cards,
-         you should say Y to this option if you wish to use it with Linux.
-
 config ARM_ETHER3
        tristate "Acorn/ANT Ether3 support"
        depends on ARM && ARCH_ACORN
index f1e6150b6757b24f422e01cc24ab53c54a98125d..6cca728b8094aca3f6c27a958dc336646d75b602 100644 (file)
@@ -4,7 +4,6 @@
 #
 
 obj-$(CONFIG_ARM_ETHER3)       += ether3.o
-obj-$(CONFIG_ARM_ETHER1)       += ether1.o
 obj-$(CONFIG_ARM_AT91_ETHER)   += at91_ether.o
 obj-$(CONFIG_ARM_KS8695_ETHER) += ks8695net.o
 obj-$(CONFIG_EP93XX_ETH)       += ep93xx_eth.o
diff --git a/drivers/net/arm/ether1.c b/drivers/net/arm/ether1.c
deleted file mode 100644 (file)
index b00781c..0000000
+++ /dev/null
@@ -1,1094 +0,0 @@
-/*
- *  linux/drivers/acorn/net/ether1.c
- *
- *  Copyright (C) 1996-2000 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- *  Acorn ether1 driver (82586 chip) for Acorn machines
- *
- * We basically keep two queues in the cards memory - one for transmit
- * and one for receive.  Each has a head and a tail.  The head is where
- * we/the chip adds packets to be transmitted/received, and the tail
- * is where the transmitter has got to/where the receiver will stop.
- * Both of these queues are circular, and since the chip is running
- * all the time, we have to be careful when we modify the pointers etc
- * so that the buffer memory contents is valid all the time.
- *
- * Change log:
- * 1.00        RMK                     Released
- * 1.01        RMK     19/03/1996      Transfers the last odd byte onto/off of the card now.
- * 1.02        RMK     25/05/1997      Added code to restart RU if it goes not ready
- * 1.03        RMK     14/09/1997      Cleaned up the handling of a reset during the TX interrupt.
- *                             Should prevent lockup.
- * 1.04 RMK    17/09/1997      Added more info when initialsation of chip goes wrong.
- *                             TDR now only reports failure when chip reports non-zero
- *                             TDR time-distance.
- * 1.05        RMK     31/12/1997      Removed calls to dev_tint for 2.1
- * 1.06        RMK     10/02/2000      Updated for 2.3.43
- * 1.07        RMK     13/05/2000      Updated for 2.3.99-pre8
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/device.h>
-#include <linux/init.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/bitops.h>
-
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/ecard.h>
-
-#define __ETHER1_C
-#include "ether1.h"
-
-static unsigned int net_debug = NET_DEBUG;
-
-#define BUFFER_SIZE    0x10000
-#define TX_AREA_START  0x00100
-#define TX_AREA_END    0x05000
-#define RX_AREA_START  0x05000
-#define RX_AREA_END    0x0fc00
-
-static int ether1_open(struct net_device *dev);
-static int ether1_sendpacket(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t ether1_interrupt(int irq, void *dev_id);
-static int ether1_close(struct net_device *dev);
-static void ether1_setmulticastlist(struct net_device *dev);
-static void ether1_timeout(struct net_device *dev);
-
-/* ------------------------------------------------------------------------- */
-
-static char version[] __devinitdata = "ether1 ethernet driver (c) 2000 Russell King v1.07\n";
-
-#define BUS_16 16
-#define BUS_8  8
-
-/* ------------------------------------------------------------------------- */
-
-#define DISABLEIRQS 1
-#define NORMALIRQS  0
-
-#define ether1_readw(dev, addr, type, offset, svflgs) ether1_inw_p (dev, addr + (int)(&((type *)0)->offset), svflgs)
-#define ether1_writew(dev, val, addr, type, offset, svflgs) ether1_outw_p (dev, val, addr + (int)(&((type *)0)->offset), svflgs)
-
-static inline unsigned short
-ether1_inw_p (struct net_device *dev, int addr, int svflgs)
-{
-       unsigned long flags;
-       unsigned short ret;
-
-       if (svflgs)
-               local_irq_save (flags);
-
-       writeb(addr >> 12, REG_PAGE);
-       ret = readw(ETHER1_RAM + ((addr & 4095) << 1));
-       if (svflgs)
-               local_irq_restore (flags);
-       return ret;
-}
-
-static inline void
-ether1_outw_p (struct net_device *dev, unsigned short val, int addr, int svflgs)
-{
-       unsigned long flags;
-
-       if (svflgs)
-               local_irq_save (flags);
-
-       writeb(addr >> 12, REG_PAGE);
-       writew(val, ETHER1_RAM + ((addr & 4095) << 1));
-       if (svflgs)
-               local_irq_restore (flags);
-}
-
-/*
- * Some inline assembler to allow fast transfers on to/off of the card.
- * Since this driver depends on some features presented by the ARM
- * specific architecture, and that you can't configure this driver
- * without specifiing ARM mode, this is not a problem.
- *
- * This routine is essentially an optimised memcpy from the card's
- * onboard RAM to kernel memory.
- */
-static void
-ether1_writebuffer (struct net_device *dev, void *data, unsigned int start, unsigned int length)
-{
-       unsigned int page, thislen, offset;
-       void __iomem *addr;
-
-       offset = start & 4095;
-       page = start >> 12;
-       addr = ETHER1_RAM + (offset << 1);
-
-       if (offset + length > 4096)
-               thislen = 4096 - offset;
-       else
-               thislen = length;
-
-       do {
-               int used;
-
-               writeb(page, REG_PAGE);
-               length -= thislen;
-
-               __asm__ __volatile__(
-       "subs   %3, %3, #2\n\
-       bmi     2f\n\
-1:     ldr     %0, [%1], #2\n\
-       mov     %0, %0, lsl #16\n\
-       orr     %0, %0, %0, lsr #16\n\
-       str     %0, [%2], #4\n\
-       subs    %3, %3, #2\n\
-       bmi     2f\n\
-       ldr     %0, [%1], #2\n\
-       mov     %0, %0, lsl #16\n\
-       orr     %0, %0, %0, lsr #16\n\
-       str     %0, [%2], #4\n\
-       subs    %3, %3, #2\n\
-       bmi     2f\n\
-       ldr     %0, [%1], #2\n\
-       mov     %0, %0, lsl #16\n\
-       orr     %0, %0, %0, lsr #16\n\
-       str     %0, [%2], #4\n\
-       subs    %3, %3, #2\n\
-       bmi     2f\n\
-       ldr     %0, [%1], #2\n\
-       mov     %0, %0, lsl #16\n\
-       orr     %0, %0, %0, lsr #16\n\
-       str     %0, [%2], #4\n\
-       subs    %3, %3, #2\n\
-       bpl     1b\n\
-2:     adds    %3, %3, #1\n\
-       ldreqb  %0, [%1]\n\
-       streqb  %0, [%2]"
-               : "=&r" (used), "=&r" (data)
-               : "r"  (addr), "r" (thislen), "1" (data));
-
-               addr = ETHER1_RAM;
-
-               thislen = length;
-               if (thislen > 4096)
-                       thislen = 4096;
-               page++;
-       } while (thislen);
-}
-
-static void
-ether1_readbuffer (struct net_device *dev, void *data, unsigned int start, unsigned int length)
-{
-       unsigned int page, thislen, offset;
-       void __iomem *addr;
-
-       offset = start & 4095;
-       page = start >> 12;
-       addr = ETHER1_RAM + (offset << 1);
-
-       if (offset + length > 4096)
-               thislen = 4096 - offset;
-       else
-               thislen = length;
-
-       do {
-               int used;
-
-               writeb(page, REG_PAGE);
-               length -= thislen;
-
-               __asm__ __volatile__(
-       "subs   %3, %3, #2\n\
-       bmi     2f\n\
-1:     ldr     %0, [%2], #4\n\
-       strb    %0, [%1], #1\n\
-       mov     %0, %0, lsr #8\n\
-       strb    %0, [%1], #1\n\
-       subs    %3, %3, #2\n\
-       bmi     2f\n\
-       ldr     %0, [%2], #4\n\
-       strb    %0, [%1], #1\n\
-       mov     %0, %0, lsr #8\n\
-       strb    %0, [%1], #1\n\
-       subs    %3, %3, #2\n\
-       bmi     2f\n\
-       ldr     %0, [%2], #4\n\
-       strb    %0, [%1], #1\n\
-       mov     %0, %0, lsr #8\n\
-       strb    %0, [%1], #1\n\
-       subs    %3, %3, #2\n\
-       bmi     2f\n\
-       ldr     %0, [%2], #4\n\
-       strb    %0, [%1], #1\n\
-       mov     %0, %0, lsr #8\n\
-       strb    %0, [%1], #1\n\
-       subs    %3, %3, #2\n\
-       bpl     1b\n\
-2:     adds    %3, %3, #1\n\
-       ldreqb  %0, [%2]\n\
-       streqb  %0, [%1]"
-               : "=&r" (used), "=&r" (data)
-               : "r"  (addr), "r" (thislen), "1" (data));
-
-               addr = ETHER1_RAM;
-
-               thislen = length;
-               if (thislen > 4096)
-                       thislen = 4096;
-               page++;
-       } while (thislen);
-}
-
-static int __devinit
-ether1_ramtest(struct net_device *dev, unsigned char byte)
-{
-       unsigned char *buffer = kmalloc (BUFFER_SIZE, GFP_KERNEL);
-       int i, ret = BUFFER_SIZE;
-       int max_errors = 15;
-       int bad = -1;
-       int bad_start = 0;
-
-       if (!buffer)
-               return 1;
-
-       memset (buffer, byte, BUFFER_SIZE);
-       ether1_writebuffer (dev, buffer, 0, BUFFER_SIZE);
-       memset (buffer, byte ^ 0xff, BUFFER_SIZE);
-       ether1_readbuffer (dev, buffer, 0, BUFFER_SIZE);
-
-       for (i = 0; i < BUFFER_SIZE; i++) {
-               if (buffer[i] != byte) {
-                       if (max_errors >= 0 && bad != buffer[i]) {
-                               if (bad != -1)
-                                       printk ("\n");
-                               printk (KERN_CRIT "%s: RAM failed with (%02X instead of %02X) at 0x%04X",
-                                       dev->name, buffer[i], byte, i);
-                               ret = -ENODEV;
-                               max_errors --;
-                               bad = buffer[i];
-                               bad_start = i;
-                       }
-               } else {
-                       if (bad != -1) {
-                               if (bad_start == i - 1)
-                                       printk ("\n");
-                               else
-                                       printk (" - 0x%04X\n", i - 1);
-                               bad = -1;
-                       }
-               }
-       }
-
-       if (bad != -1)
-               printk (" - 0x%04X\n", BUFFER_SIZE);
-       kfree (buffer);
-
-       return ret;
-}
-
-static int
-ether1_reset (struct net_device *dev)
-{
-       writeb(CTRL_RST|CTRL_ACK, REG_CONTROL);
-       return BUS_16;
-}
-
-static int __devinit
-ether1_init_2(struct net_device *dev)
-{
-       int i;
-       dev->mem_start = 0;
-
-       i = ether1_ramtest (dev, 0x5a);
-
-       if (i > 0)
-               i = ether1_ramtest (dev, 0x1e);
-
-       if (i <= 0)
-               return -ENODEV;
-
-       dev->mem_end = i;
-       return 0;
-}
-
-/*
- * These are the structures that are loaded into the ether RAM card to
- * initialise the 82586
- */
-
-/* at 0x0100 */
-#define NOP_ADDR       (TX_AREA_START)
-#define NOP_SIZE       (0x06)
-static nop_t  init_nop  = {
-       0,
-       CMD_NOP,
-       NOP_ADDR
-};
-
-/* at 0x003a */
-#define TDR_ADDR       (0x003a)
-#define TDR_SIZE       (0x08)
-static tdr_t  init_tdr = {
-       0,
-       CMD_TDR | CMD_INTR,
-       NOP_ADDR,
-       0
-};
-
-/* at 0x002e */
-#define MC_ADDR                (0x002e)
-#define MC_SIZE                (0x0c)
-static mc_t   init_mc   = {
-       0,
-       CMD_SETMULTICAST,
-       TDR_ADDR,
-       0,
-       { { 0, } }
-};
-
-/* at 0x0022 */
-#define SA_ADDR                (0x0022)
-#define SA_SIZE                (0x0c)
-static sa_t   init_sa   = {
-       0,
-       CMD_SETADDRESS,
-       MC_ADDR,
-       { 0, }
-};
-
-/* at 0x0010 */
-#define CFG_ADDR       (0x0010)
-#define CFG_SIZE       (0x12)
-static cfg_t  init_cfg  = {
-       0,
-       CMD_CONFIG,
-       SA_ADDR,
-       8,
-       8,
-       CFG8_SRDY,
-       CFG9_PREAMB8 | CFG9_ADDRLENBUF | CFG9_ADDRLEN(6),
-       0,
-       0x60,
-       0,
-       CFG13_RETRY(15) | CFG13_SLOTH(2),
-       0,
-};
-
-/* at 0x0000 */
-#define SCB_ADDR       (0x0000)
-#define SCB_SIZE       (0x10)
-static scb_t  init_scb  = {
-       0,
-       SCB_CMDACKRNR | SCB_CMDACKCNA | SCB_CMDACKFR | SCB_CMDACKCX,
-       CFG_ADDR,
-       RX_AREA_START,
-       0,
-       0,
-       0,
-       0
-};
-
-/* at 0xffee */
-#define ISCP_ADDR      (0xffee)
-#define ISCP_SIZE      (0x08)
-static iscp_t init_iscp = {
-       1,
-       SCB_ADDR,
-       0x0000,
-       0x0000
-};
-
-/* at 0xfff6 */
-#define SCP_ADDR       (0xfff6)
-#define SCP_SIZE       (0x0a)
-static scp_t  init_scp  = {
-       SCP_SY_16BBUS,
-       { 0, 0 },
-       ISCP_ADDR,
-       0
-};
-
-#define RFD_SIZE       (0x16)
-static rfd_t  init_rfd = {
-       0,
-       0,
-       0,
-       0,
-       { 0, },
-       { 0, },
-       0
-};
-
-#define RBD_SIZE       (0x0a)
-static rbd_t  init_rbd = {
-       0,
-       0,
-       0,
-       0,
-       ETH_FRAME_LEN + 8
-};
-
-#define TX_SIZE                (0x08)
-#define TBD_SIZE       (0x08)
-
-static int
-ether1_init_for_open (struct net_device *dev)
-{
-       int i, status, addr, next, next2;
-       int failures = 0;
-       unsigned long timeout;
-
-       writeb(CTRL_RST|CTRL_ACK, REG_CONTROL);
-
-       for (i = 0; i < 6; i++)
-               init_sa.sa_addr[i] = dev->dev_addr[i];
-
-       /* load data structures into ether1 RAM */
-       ether1_writebuffer (dev, &init_scp,  SCP_ADDR,  SCP_SIZE);
-       ether1_writebuffer (dev, &init_iscp, ISCP_ADDR, ISCP_SIZE);
-       ether1_writebuffer (dev, &init_scb,  SCB_ADDR,  SCB_SIZE);
-       ether1_writebuffer (dev, &init_cfg,  CFG_ADDR,  CFG_SIZE);
-       ether1_writebuffer (dev, &init_sa,   SA_ADDR,   SA_SIZE);
-       ether1_writebuffer (dev, &init_mc,   MC_ADDR,   MC_SIZE);
-       ether1_writebuffer (dev, &init_tdr,  TDR_ADDR,  TDR_SIZE);
-       ether1_writebuffer (dev, &init_nop,  NOP_ADDR,  NOP_SIZE);
-
-       if (ether1_readw(dev, CFG_ADDR, cfg_t, cfg_command, NORMALIRQS) != CMD_CONFIG) {
-               printk (KERN_ERR "%s: detected either RAM fault or compiler bug\n",
-                       dev->name);
-               return 1;
-       }
-
-       /*
-        * setup circularly linked list of { rfd, rbd, buffer }, with
-        * all rfds circularly linked, rbds circularly linked.
-        * First rfd is linked to scp, first rbd is linked to first
-        * rfd.  Last rbd has a suspend command.
-        */
-       addr = RX_AREA_START;
-       do {
-               next = addr + RFD_SIZE + RBD_SIZE + ETH_FRAME_LEN + 10;
-               next2 = next + RFD_SIZE + RBD_SIZE + ETH_FRAME_LEN + 10;
-
-               if (next2 >= RX_AREA_END) {
-                       next = RX_AREA_START;
-                       init_rfd.rfd_command = RFD_CMDEL | RFD_CMDSUSPEND;
-                       priv(dev)->rx_tail = addr;
-               } else
-                       init_rfd.rfd_command = 0;
-               if (addr == RX_AREA_START)
-                       init_rfd.rfd_rbdoffset = addr + RFD_SIZE;
-               else
-                       init_rfd.rfd_rbdoffset = 0;
-               init_rfd.rfd_link = next;
-               init_rbd.rbd_link = next + RFD_SIZE;
-               init_rbd.rbd_bufl = addr + RFD_SIZE + RBD_SIZE;
-
-               ether1_writebuffer (dev, &init_rfd, addr, RFD_SIZE);
-               ether1_writebuffer (dev, &init_rbd, addr + RFD_SIZE, RBD_SIZE);
-               addr = next;
-       } while (next2 < RX_AREA_END);
-
-       priv(dev)->tx_link = NOP_ADDR;
-       priv(dev)->tx_head = NOP_ADDR + NOP_SIZE;
-       priv(dev)->tx_tail = TDR_ADDR;
-       priv(dev)->rx_head = RX_AREA_START;
-
-       /* release reset & give 586 a prod */
-       priv(dev)->resetting = 1;
-       priv(dev)->initialising = 1;
-       writeb(CTRL_RST, REG_CONTROL);
-       writeb(0, REG_CONTROL);
-       writeb(CTRL_CA, REG_CONTROL);
-
-       /* 586 should now unset iscp.busy */
-       timeout = jiffies + HZ/2;
-       while (ether1_readw(dev, ISCP_ADDR, iscp_t, iscp_busy, DISABLEIRQS) == 1) {
-               if (time_after(jiffies, timeout)) {
-                       printk (KERN_WARNING "%s: can't initialise 82586: iscp is busy\n", dev->name);
-                       return 1;
-               }
-       }
-
-       /* check status of commands that we issued */
-       timeout += HZ/10;
-       while (((status = ether1_readw(dev, CFG_ADDR, cfg_t, cfg_status, DISABLEIRQS))
-                       & STAT_COMPLETE) == 0) {
-               if (time_after(jiffies, timeout))
-                       break;
-       }
-
-       if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) {
-               printk (KERN_WARNING "%s: can't initialise 82586: config status %04X\n", dev->name, status);
-               printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name,
-                       ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS),
-                       ether1_readw(dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS),
-                       ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS),
-                       ether1_readw(dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS));
-               failures += 1;
-       }
-
-       timeout += HZ/10;
-       while (((status = ether1_readw(dev, SA_ADDR, sa_t, sa_status, DISABLEIRQS))
-                       & STAT_COMPLETE) == 0) {
-               if (time_after(jiffies, timeout))
-                       break;
-       }
-
-       if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) {
-               printk (KERN_WARNING "%s: can't initialise 82586: set address status %04X\n", dev->name, status);
-               printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name,
-                       ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS),
-                       ether1_readw(dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS),
-                       ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS),
-                       ether1_readw(dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS));
-               failures += 1;
-       }
-
-       timeout += HZ/10;
-       while (((status = ether1_readw(dev, MC_ADDR, mc_t, mc_status, DISABLEIRQS))
-                       & STAT_COMPLETE) == 0) {
-               if (time_after(jiffies, timeout))
-                       break;
-       }
-
-       if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) {
-               printk (KERN_WARNING "%s: can't initialise 82586: set multicast status %04X\n", dev->name, status);
-               printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name,
-                       ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS),
-                       ether1_readw(dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS),
-                       ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS),
-                       ether1_readw(dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS));
-               failures += 1;
-       }
-
-       timeout += HZ;
-       while (((status = ether1_readw(dev, TDR_ADDR, tdr_t, tdr_status, DISABLEIRQS))
-                       & STAT_COMPLETE) == 0) {
-               if (time_after(jiffies, timeout))
-                       break;
-       }
-
-       if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) {
-               printk (KERN_WARNING "%s: can't tdr (ignored)\n", dev->name);
-               printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name,
-                       ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS),
-                       ether1_readw(dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS),
-                       ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS),
-                       ether1_readw(dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS));
-       } else {
-               status = ether1_readw(dev, TDR_ADDR, tdr_t, tdr_result, DISABLEIRQS);
-               if (status & TDR_XCVRPROB)
-                       printk (KERN_WARNING "%s: i/f failed tdr: transceiver problem\n", dev->name);
-               else if ((status & (TDR_SHORT|TDR_OPEN)) && (status & TDR_TIME)) {
-#ifdef FANCY
-                       printk (KERN_WARNING "%s: i/f failed tdr: cable %s %d.%d us away\n", dev->name,
-                               status & TDR_SHORT ? "short" : "open", (status & TDR_TIME) / 10,
-                               (status & TDR_TIME) % 10);
-#else
-                       printk (KERN_WARNING "%s: i/f failed tdr: cable %s %d clks away\n", dev->name,
-                               status & TDR_SHORT ? "short" : "open", (status & TDR_TIME));
-#endif
-               }
-       }
-
-       if (failures)
-               ether1_reset (dev);
-       return failures ? 1 : 0;
-}
-
-/* ------------------------------------------------------------------------- */
-
-static int
-ether1_txalloc (struct net_device *dev, int size)
-{
-       int start, tail;
-
-       size = (size + 1) & ~1;
-       tail = priv(dev)->tx_tail;
-
-       if (priv(dev)->tx_head + size > TX_AREA_END) {
-               if (tail > priv(dev)->tx_head)
-                       return -1;
-               start = TX_AREA_START;
-               if (start + size > tail)
-                       return -1;
-               priv(dev)->tx_head = start + size;
-       } else {
-               if (priv(dev)->tx_head < tail && (priv(dev)->tx_head + size) > tail)
-                       return -1;
-               start = priv(dev)->tx_head;
-               priv(dev)->tx_head += size;
-       }
-
-       return start;
-}
-
-static int
-ether1_open (struct net_device *dev)
-{
-       if (!is_valid_ether_addr(dev->dev_addr)) {
-               printk(KERN_WARNING "%s: invalid ethernet MAC address\n",
-                       dev->name);
-               return -EINVAL;
-       }
-
-       if (request_irq(dev->irq, ether1_interrupt, 0, "ether1", dev))
-               return -EAGAIN;
-
-       if (ether1_init_for_open (dev)) {
-               free_irq (dev->irq, dev);
-               return -EAGAIN;
-       }
-
-       netif_start_queue(dev);
-
-       return 0;
-}
-
-static void
-ether1_timeout(struct net_device *dev)
-{
-       printk(KERN_WARNING "%s: transmit timeout, network cable problem?\n",
-               dev->name);
-       printk(KERN_WARNING "%s: resetting device\n", dev->name);
-
-       ether1_reset (dev);
-
-       if (ether1_init_for_open (dev))
-               printk (KERN_ERR "%s: unable to restart interface\n", dev->name);
-
-       dev->stats.tx_errors++;
-       netif_wake_queue(dev);
-}
-
-static int
-ether1_sendpacket (struct sk_buff *skb, struct net_device *dev)
-{
-       int tmp, tst, nopaddr, txaddr, tbdaddr, dataddr;
-       unsigned long flags;
-       tx_t tx;
-       tbd_t tbd;
-       nop_t nop;
-
-       if (priv(dev)->restart) {
-               printk(KERN_WARNING "%s: resetting device\n", dev->name);
-
-               ether1_reset(dev);
-
-               if (ether1_init_for_open(dev))
-                       printk(KERN_ERR "%s: unable to restart interface\n", dev->name);
-               else
-                       priv(dev)->restart = 0;
-       }
-
-       if (skb->len < ETH_ZLEN) {
-               if (skb_padto(skb, ETH_ZLEN))
-                       goto out;
-       }
-
-       /*
-        * insert packet followed by a nop
-        */
-       txaddr = ether1_txalloc (dev, TX_SIZE);
-       tbdaddr = ether1_txalloc (dev, TBD_SIZE);
-       dataddr = ether1_txalloc (dev, skb->len);
-       nopaddr = ether1_txalloc (dev, NOP_SIZE);
-
-       tx.tx_status = 0;
-       tx.tx_command = CMD_TX | CMD_INTR;
-       tx.tx_link = nopaddr;
-       tx.tx_tbdoffset = tbdaddr;
-       tbd.tbd_opts = TBD_EOL | skb->len;
-       tbd.tbd_link = I82586_NULL;
-       tbd.tbd_bufl = dataddr;
-       tbd.tbd_bufh = 0;
-       nop.nop_status = 0;
-       nop.nop_command = CMD_NOP;
-       nop.nop_link = nopaddr;
-
-       local_irq_save(flags);
-       ether1_writebuffer (dev, &tx, txaddr, TX_SIZE);
-       ether1_writebuffer (dev, &tbd, tbdaddr, TBD_SIZE);
-       ether1_writebuffer (dev, skb->data, dataddr, skb->len);
-       ether1_writebuffer (dev, &nop, nopaddr, NOP_SIZE);
-       tmp = priv(dev)->tx_link;
-       priv(dev)->tx_link = nopaddr;
-
-       /* now reset the previous nop pointer */
-       ether1_writew(dev, txaddr, tmp, nop_t, nop_link, NORMALIRQS);
-
-       local_irq_restore(flags);
-
-       /* handle transmit */
-
-       /* check to see if we have room for a full sized ether frame */
-       tmp = priv(dev)->tx_head;
-       tst = ether1_txalloc (dev, TX_SIZE + TBD_SIZE + NOP_SIZE + ETH_FRAME_LEN);
-       priv(dev)->tx_head = tmp;
-       dev_kfree_skb (skb);
-
-       if (tst == -1)
-               netif_stop_queue(dev);
-
- out:
-       return NETDEV_TX_OK;
-}
-
-static void
-ether1_xmit_done (struct net_device *dev)
-{
-       nop_t nop;
-       int caddr, tst;
-
-       caddr = priv(dev)->tx_tail;
-
-again:
-       ether1_readbuffer (dev, &nop, caddr, NOP_SIZE);
-
-       switch (nop.nop_command & CMD_MASK) {
-       case CMD_TDR:
-               /* special case */
-               if (ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS)
-                               != (unsigned short)I82586_NULL) {
-                       ether1_writew(dev, SCB_CMDCUCSTART | SCB_CMDRXSTART, SCB_ADDR, scb_t,
-                                   scb_command, NORMALIRQS);
-                       writeb(CTRL_CA, REG_CONTROL);
-               }
-               priv(dev)->tx_tail = NOP_ADDR;
-               return;
-
-       case CMD_NOP:
-               if (nop.nop_link == caddr) {
-                       if (priv(dev)->initialising == 0)
-                               printk (KERN_WARNING "%s: strange command complete with no tx command!\n", dev->name);
-                       else
-                               priv(dev)->initialising = 0;
-                       return;
-               }
-               if (caddr == nop.nop_link)
-                       return;
-               caddr = nop.nop_link;
-               goto again;
-
-       case CMD_TX:
-               if (nop.nop_status & STAT_COMPLETE)
-                       break;
-               printk (KERN_ERR "%s: strange command complete without completed command\n", dev->name);
-               priv(dev)->restart = 1;
-               return;
-
-       default:
-               printk (KERN_WARNING "%s: strange command %d complete! (offset %04X)", dev->name,
-                       nop.nop_command & CMD_MASK, caddr);
-               priv(dev)->restart = 1;
-               return;
-       }
-
-       while (nop.nop_status & STAT_COMPLETE) {
-               if (nop.nop_status & STAT_OK) {
-                       dev->stats.tx_packets++;
-                       dev->stats.collisions += (nop.nop_status & STAT_COLLISIONS);
-               } else {
-                       dev->stats.tx_errors++;
-
-                       if (nop.nop_status & STAT_COLLAFTERTX)
-                               dev->stats.collisions++;
-                       if (nop.nop_status & STAT_NOCARRIER)
-                               dev->stats.tx_carrier_errors++;
-                       if (nop.nop_status & STAT_TXLOSTCTS)
-                               printk (KERN_WARNING "%s: cts lost\n", dev->name);
-                       if (nop.nop_status & STAT_TXSLOWDMA)
-                               dev->stats.tx_fifo_errors++;
-                       if (nop.nop_status & STAT_COLLEXCESSIVE)
-                               dev->stats.collisions += 16;
-               }
-
-               if (nop.nop_link == caddr) {
-                       printk (KERN_ERR "%s: tx buffer chaining error: tx command points to itself\n", dev->name);
-                       break;
-               }
-
-               caddr = nop.nop_link;
-               ether1_readbuffer (dev, &nop, caddr, NOP_SIZE);
-               if ((nop.nop_command & CMD_MASK) != CMD_NOP) {
-                       printk (KERN_ERR "%s: tx buffer chaining error: no nop after tx command\n", dev->name);
-                       break;
-               }
-
-               if (caddr == nop.nop_link)
-                       break;
-
-               caddr = nop.nop_link;
-               ether1_readbuffer (dev, &nop, caddr, NOP_SIZE);
-               if ((nop.nop_command & CMD_MASK) != CMD_TX) {
-                       printk (KERN_ERR "%s: tx buffer chaining error: no tx command after nop\n", dev->name);
-                       break;
-               }
-       }
-       priv(dev)->tx_tail = caddr;
-
-       caddr = priv(dev)->tx_head;
-       tst = ether1_txalloc (dev, TX_SIZE + TBD_SIZE + NOP_SIZE + ETH_FRAME_LEN);
-       priv(dev)->tx_head = caddr;
-       if (tst != -1)
-               netif_wake_queue(dev);
-}
-
-static void
-ether1_recv_done (struct net_device *dev)
-{
-       int status;
-       int nexttail, rbdaddr;
-       rbd_t rbd;
-
-       do {
-               status = ether1_readw(dev, priv(dev)->rx_head, rfd_t, rfd_status, NORMALIRQS);
-               if ((status & RFD_COMPLETE) == 0)
-                       break;
-
-               rbdaddr = ether1_readw(dev, priv(dev)->rx_head, rfd_t, rfd_rbdoffset, NORMALIRQS);
-               ether1_readbuffer (dev, &rbd, rbdaddr, RBD_SIZE);
-
-               if ((rbd.rbd_status & (RBD_EOF | RBD_ACNTVALID)) == (RBD_EOF | RBD_ACNTVALID)) {
-                       int length = rbd.rbd_status & RBD_ACNT;
-                       struct sk_buff *skb;
-
-                       length = (length + 1) & ~1;
-                       skb = dev_alloc_skb (length + 2);
-
-                       if (skb) {
-                               skb_reserve (skb, 2);
-
-                               ether1_readbuffer (dev, skb_put (skb, length), rbd.rbd_bufl, length);
-
-                               skb->protocol = eth_type_trans (skb, dev);
-                               netif_rx (skb);
-                               dev->stats.rx_packets++;
-                       } else
-                               dev->stats.rx_dropped++;
-               } else {
-                       printk(KERN_WARNING "%s: %s\n", dev->name,
-                               (rbd.rbd_status & RBD_EOF) ? "oversized packet" : "acnt not valid");
-                       dev->stats.rx_dropped++;
-               }
-
-               nexttail = ether1_readw(dev, priv(dev)->rx_tail, rfd_t, rfd_link, NORMALIRQS);
-               /* nexttail should be rx_head */
-               if (nexttail != priv(dev)->rx_head)
-                       printk(KERN_ERR "%s: receiver buffer chaining error (%04X != %04X)\n",
-                               dev->name, nexttail, priv(dev)->rx_head);
-               ether1_writew(dev, RFD_CMDEL | RFD_CMDSUSPEND, nexttail, rfd_t, rfd_command, NORMALIRQS);
-               ether1_writew(dev, 0, priv(dev)->rx_tail, rfd_t, rfd_command, NORMALIRQS);
-               ether1_writew(dev, 0, priv(dev)->rx_tail, rfd_t, rfd_status, NORMALIRQS);
-               ether1_writew(dev, 0, priv(dev)->rx_tail, rfd_t, rfd_rbdoffset, NORMALIRQS);
-       
-               priv(dev)->rx_tail = nexttail;
-               priv(dev)->rx_head = ether1_readw(dev, priv(dev)->rx_head, rfd_t, rfd_link, NORMALIRQS);
-       } while (1);
-}
-
-static irqreturn_t
-ether1_interrupt (int irq, void *dev_id)
-{
-       struct net_device *dev = (struct net_device *)dev_id;
-       int status;
-
-       status = ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS);
-
-       if (status) {
-               ether1_writew(dev, status & (SCB_STRNR | SCB_STCNA | SCB_STFR | SCB_STCX),
-                           SCB_ADDR, scb_t, scb_command, NORMALIRQS);
-               writeb(CTRL_CA | CTRL_ACK, REG_CONTROL);
-               if (status & SCB_STCX) {
-                       ether1_xmit_done (dev);
-               }
-               if (status & SCB_STCNA) {
-                       if (priv(dev)->resetting == 0)
-                               printk (KERN_WARNING "%s: CU went not ready ???\n", dev->name);
-                       else
-                               priv(dev)->resetting += 1;
-                       if (ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS)
-                                       != (unsigned short)I82586_NULL) {
-                               ether1_writew(dev, SCB_CMDCUCSTART, SCB_ADDR, scb_t, scb_command, NORMALIRQS);
-                               writeb(CTRL_CA, REG_CONTROL);
-                       }
-                       if (priv(dev)->resetting == 2)
-                               priv(dev)->resetting = 0;
-               }
-               if (status & SCB_STFR) {
-                       ether1_recv_done (dev);
-               }
-               if (status & SCB_STRNR) {
-                       if (ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS) & SCB_STRXSUSP) {
-                               printk (KERN_WARNING "%s: RU went not ready: RU suspended\n", dev->name);
-                               ether1_writew(dev, SCB_CMDRXRESUME, SCB_ADDR, scb_t, scb_command, NORMALIRQS);
-                               writeb(CTRL_CA, REG_CONTROL);
-                               dev->stats.rx_dropped++;        /* we suspended due to lack of buffer space */
-                       } else
-                               printk(KERN_WARNING "%s: RU went not ready: %04X\n", dev->name,
-                                       ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS));
-                       printk (KERN_WARNING "RU ptr = %04X\n", ether1_readw(dev, SCB_ADDR, scb_t, scb_rfa_offset,
-                                               NORMALIRQS));
-               }
-       } else
-               writeb(CTRL_ACK, REG_CONTROL);
-
-       return IRQ_HANDLED;
-}
-
-static int
-ether1_close (struct net_device *dev)
-{
-       ether1_reset (dev);
-
-       free_irq(dev->irq, dev);
-
-       return 0;
-}
-
-/*
- * Set or clear the multicast filter for this adaptor.
- * num_addrs == -1     Promiscuous mode, receive all packets.
- * num_addrs == 0      Normal mode, clear multicast list.
- * num_addrs > 0       Multicast mode, receive normal and MC packets, and do
- *                     best-effort filtering.
- */
-static void
-ether1_setmulticastlist (struct net_device *dev)
-{
-}
-
-/* ------------------------------------------------------------------------- */
-
-static void __devinit ether1_banner(void)
-{
-       static unsigned int version_printed = 0;
-
-       if (net_debug && version_printed++ == 0)
-               printk(KERN_INFO "%s", version);
-}
-
-static const struct net_device_ops ether1_netdev_ops = {
-       .ndo_open               = ether1_open,
-       .ndo_stop               = ether1_close,
-       .ndo_start_xmit         = ether1_sendpacket,
-       .ndo_set_multicast_list = ether1_setmulticastlist,
-       .ndo_tx_timeout         = ether1_timeout,
-       .ndo_validate_addr      = eth_validate_addr,
-       .ndo_change_mtu         = eth_change_mtu,
-       .ndo_set_mac_address    = eth_mac_addr,
-};
-
-static int __devinit
-ether1_probe(struct expansion_card *ec, const struct ecard_id *id)
-{
-       struct net_device *dev;
-       int i, ret = 0;
-
-       ether1_banner();
-
-       ret = ecard_request_resources(ec);
-       if (ret)
-               goto out;
-
-       dev = alloc_etherdev(sizeof(struct ether1_priv));
-       if (!dev) {
-               ret = -ENOMEM;
-               goto release;
-       }
-
-       SET_NETDEV_DEV(dev, &ec->dev);
-
-       dev->irq = ec->irq;
-       priv(dev)->base = ecardm_iomap(ec, ECARD_RES_IOCFAST, 0, 0);
-       if (!priv(dev)->base) {
-               ret = -ENOMEM;
-               goto free;
-       }
-
-       if ((priv(dev)->bus_type = ether1_reset(dev)) == 0) {
-               ret = -ENODEV;
-               goto free;
-       }
-
-       for (i = 0; i < 6; i++)
-               dev->dev_addr[i] = readb(IDPROM_ADDRESS + (i << 2));
-
-       if (ether1_init_2(dev)) {
-               ret = -ENODEV;
-               goto free;
-       }
-
-       dev->netdev_ops         = &ether1_netdev_ops;
-       dev->watchdog_timeo     = 5 * HZ / 100;
-
-       ret = register_netdev(dev);
-       if (ret)
-               goto free;
-
-       printk(KERN_INFO "%s: ether1 in slot %d, %pM\n",
-               dev->name, ec->slot_no, dev->dev_addr);
-    
-       ecard_set_drvdata(ec, dev);
-       return 0;
-
- free:
-       free_netdev(dev);
- release:
-       ecard_release_resources(ec);
- out:
-       return ret;
-}
-
-static void __devexit ether1_remove(struct expansion_card *ec)
-{
-       struct net_device *dev = ecard_get_drvdata(ec);
-
-       ecard_set_drvdata(ec, NULL);    
-
-       unregister_netdev(dev);
-       free_netdev(dev);
-       ecard_release_resources(ec);
-}
-
-static const struct ecard_id ether1_ids[] = {
-       { MANU_ACORN, PROD_ACORN_ETHER1 },
-       { 0xffff, 0xffff }
-};
-
-static struct ecard_driver ether1_driver = {
-       .probe          = ether1_probe,
-       .remove         = __devexit_p(ether1_remove),
-       .id_table       = ether1_ids,
-       .drv = {
-               .name   = "ether1",
-       },
-};
-
-static int __init ether1_init(void)
-{
-       return ecard_register_driver(&ether1_driver);
-}
-
-static void __exit ether1_exit(void)
-{
-       ecard_remove_driver(&ether1_driver);
-}
-
-module_init(ether1_init);
-module_exit(ether1_exit);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/arm/ether1.h b/drivers/net/arm/ether1.h
deleted file mode 100644 (file)
index 3a5830a..0000000
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- *  linux/drivers/acorn/net/ether1.h
- *
- *  Copyright (C) 1996 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- *  Network driver for Acorn Ether1 cards.
- */
-
-#ifndef _LINUX_ether1_H
-#define _LINUX_ether1_H
-
-#ifdef __ETHER1_C
-/* use 0 for production, 1 for verification, >2 for debug */
-#ifndef NET_DEBUG
-#define NET_DEBUG 0
-#endif
-
-#define priv(dev)      ((struct ether1_priv *)netdev_priv(dev))
-
-/* Page register */
-#define REG_PAGE       (priv(dev)->base + 0x0000)
-
-/* Control register */
-#define REG_CONTROL    (priv(dev)->base + 0x0004)
-#define CTRL_RST       0x01
-#define CTRL_LOOPBACK  0x02
-#define CTRL_CA                0x04
-#define CTRL_ACK       0x08
-
-#define ETHER1_RAM     (priv(dev)->base + 0x2000)
-
-/* HW address */
-#define IDPROM_ADDRESS (priv(dev)->base + 0x0024)
-
-struct ether1_priv {
-       void __iomem *base;
-       unsigned int tx_link;
-       unsigned int tx_head;
-       volatile unsigned int tx_tail;
-       volatile unsigned int rx_head;
-       volatile unsigned int rx_tail;
-       unsigned char bus_type;
-       unsigned char resetting;
-       unsigned char initialising : 1;
-       unsigned char restart      : 1;
-};
-
-#define I82586_NULL (-1)
-
-typedef struct { /* tdr */
-       unsigned short tdr_status;
-       unsigned short tdr_command;
-       unsigned short tdr_link;
-       unsigned short tdr_result;
-#define TDR_TIME       (0x7ff)
-#define TDR_SHORT      (1 << 12)
-#define TDR_OPEN       (1 << 13)
-#define TDR_XCVRPROB   (1 << 14)
-#define TDR_LNKOK      (1 << 15)
-} tdr_t;
-
-typedef struct { /* transmit */
-       unsigned short tx_status;
-       unsigned short tx_command;
-       unsigned short tx_link;
-       unsigned short tx_tbdoffset;
-} tx_t;
-
-typedef struct { /* tbd */
-       unsigned short tbd_opts;
-#define TBD_CNT                (0x3fff)
-#define TBD_EOL                (1 << 15)
-       unsigned short tbd_link;
-       unsigned short tbd_bufl;
-       unsigned short tbd_bufh;
-} tbd_t;
-
-typedef struct { /* rfd */
-       unsigned short rfd_status;
-#define RFD_NOEOF      (1 << 6)
-#define RFD_FRAMESHORT (1 << 7)
-#define RFD_DMAOVRN    (1 << 8)
-#define RFD_NORESOURCES        (1 << 9)
-#define RFD_ALIGNERROR (1 << 10)
-#define RFD_CRCERROR   (1 << 11)
-#define RFD_OK         (1 << 13)
-#define RFD_FDCONSUMED (1 << 14)
-#define RFD_COMPLETE   (1 << 15)
-       unsigned short rfd_command;
-#define RFD_CMDSUSPEND (1 << 14)
-#define RFD_CMDEL      (1 << 15)
-       unsigned short rfd_link;
-       unsigned short rfd_rbdoffset;
-       unsigned char  rfd_dest[6];
-       unsigned char  rfd_src[6];
-       unsigned short rfd_len;
-} rfd_t;
-
-typedef struct { /* rbd */
-       unsigned short rbd_status;
-#define RBD_ACNT       (0x3fff)
-#define RBD_ACNTVALID  (1 << 14)
-#define RBD_EOF                (1 << 15)
-       unsigned short rbd_link;
-       unsigned short rbd_bufl;
-       unsigned short rbd_bufh;
-       unsigned short rbd_len;
-} rbd_t;
-
-typedef struct { /* nop */
-       unsigned short nop_status;
-       unsigned short nop_command;
-       unsigned short nop_link;
-} nop_t;
-
-typedef struct { /* set multicast */
-       unsigned short mc_status;
-       unsigned short mc_command;
-       unsigned short mc_link;
-       unsigned short mc_cnt;
-       unsigned char  mc_addrs[1][6];
-} mc_t;
-
-typedef struct { /* set address */
-       unsigned short sa_status;
-       unsigned short sa_command;
-       unsigned short sa_link;
-       unsigned char  sa_addr[6];
-} sa_t;
-
-typedef struct { /* config command */
-       unsigned short cfg_status;
-       unsigned short cfg_command;
-       unsigned short cfg_link;
-       unsigned char  cfg_bytecnt;     /* size foll data: 4 - 12                */
-       unsigned char  cfg_fifolim;     /* FIFO threshold                        */
-       unsigned char  cfg_byte8;
-#define CFG8_SRDY      (1 << 6)
-#define CFG8_SAVEBADF  (1 << 7)
-       unsigned char  cfg_byte9;
-#define CFG9_ADDRLEN(x)        (x)
-#define CFG9_ADDRLENBUF        (1 << 3)
-#define CFG9_PREAMB2   (0 << 4)
-#define CFG9_PREAMB4   (1 << 4)
-#define CFG9_PREAMB8   (2 << 4)
-#define CFG9_PREAMB16  (3 << 4)
-#define CFG9_ILOOPBACK (1 << 6)
-#define CFG9_ELOOPBACK (1 << 7)
-       unsigned char  cfg_byte10;
-#define CFG10_LINPRI(x)        (x)
-#define CFG10_ACR(x)   (x << 4)
-#define CFG10_BOFMET   (1 << 7)
-       unsigned char  cfg_ifs;
-       unsigned char  cfg_slotl;
-       unsigned char  cfg_byte13;
-#define CFG13_SLOTH(x) (x)
-#define CFG13_RETRY(x) (x << 4)
-       unsigned char  cfg_byte14;
-#define CFG14_PROMISC  (1 << 0)
-#define CFG14_DISBRD   (1 << 1)
-#define CFG14_MANCH    (1 << 2)
-#define CFG14_TNCRS    (1 << 3)
-#define CFG14_NOCRC    (1 << 4)
-#define CFG14_CRC16    (1 << 5)
-#define CFG14_BTSTF    (1 << 6)
-#define CFG14_FLGPAD   (1 << 7)
-       unsigned char  cfg_byte15;
-#define CFG15_CSTF(x)  (x)
-#define CFG15_ICSS     (1 << 3)
-#define CFG15_CDTF(x)  (x << 4)
-#define CFG15_ICDS     (1 << 7)
-       unsigned short cfg_minfrmlen;
-} cfg_t;
-
-typedef struct { /* scb */
-       unsigned short scb_status;      /* status of 82586                      */
-#define SCB_STRXMASK           (7 << 4)        /* Receive unit status          */
-#define SCB_STRXIDLE           (0 << 4)        /* Idle                         */
-#define SCB_STRXSUSP           (1 << 4)        /* Suspended                    */
-#define SCB_STRXNRES           (2 << 4)        /* No resources                 */
-#define SCB_STRXRDY            (4 << 4)        /* Ready                        */
-#define SCB_STCUMASK           (7 << 8)        /* Command unit status          */
-#define SCB_STCUIDLE           (0 << 8)        /* Idle                         */
-#define SCB_STCUSUSP           (1 << 8)        /* Suspended                    */
-#define SCB_STCUACTV           (2 << 8)        /* Active                       */
-#define SCB_STRNR              (1 << 12)       /* Receive unit not ready       */
-#define SCB_STCNA              (1 << 13)       /* Command unit not ready       */
-#define SCB_STFR               (1 << 14)       /* Frame received               */
-#define SCB_STCX               (1 << 15)       /* Command completed            */
-       unsigned short scb_command;     /* Next command                         */
-#define SCB_CMDRXSTART         (1 << 4)        /* Start (at rfa_offset)        */
-#define SCB_CMDRXRESUME                (2 << 4)        /* Resume reception             */
-#define SCB_CMDRXSUSPEND       (3 << 4)        /* Suspend reception            */
-#define SCB_CMDRXABORT         (4 << 4)        /* Abort reception              */
-#define SCB_CMDCUCSTART                (1 << 8)        /* Start (at cbl_offset)        */
-#define SCB_CMDCUCRESUME       (2 << 8)        /* Resume execution             */
-#define SCB_CMDCUCSUSPEND      (3 << 8)        /* Suspend execution            */
-#define SCB_CMDCUCABORT                (4 << 8)        /* Abort execution              */
-#define SCB_CMDACKRNR          (1 << 12)       /* Ack RU not ready             */
-#define SCB_CMDACKCNA          (1 << 13)       /* Ack CU not ready             */
-#define SCB_CMDACKFR           (1 << 14)       /* Ack Frame received           */
-#define SCB_CMDACKCX           (1 << 15)       /* Ack Command complete         */
-       unsigned short scb_cbl_offset;  /* Offset of first command unit         */
-       unsigned short scb_rfa_offset;  /* Offset of first receive frame area   */
-       unsigned short scb_crc_errors;  /* Properly aligned frame with CRC error*/
-       unsigned short scb_aln_errors;  /* Misaligned frames                    */
-       unsigned short scb_rsc_errors;  /* Frames lost due to no space          */
-       unsigned short scb_ovn_errors;  /* Frames lost due to slow bus          */
-} scb_t;
-
-typedef struct { /* iscp */
-       unsigned short iscp_busy;       /* set by CPU before CA                 */
-       unsigned short iscp_offset;     /* offset of SCB                        */
-       unsigned short iscp_basel;      /* base of SCB                          */
-       unsigned short iscp_baseh;
-} iscp_t;
-
-    /* this address must be 0xfff6 */
-typedef struct { /* scp */
-       unsigned short scp_sysbus;      /* bus size */
-#define SCP_SY_16BBUS  0x00
-#define SCP_SY_8BBUS   0x01
-       unsigned short scp_junk[2];     /* junk */
-       unsigned short scp_iscpl;       /* lower 16 bits of iscp */
-       unsigned short scp_iscph;       /* upper 16 bits of iscp */
-} scp_t;
-
-/* commands */
-#define CMD_NOP                        0
-#define CMD_SETADDRESS         1
-#define CMD_CONFIG             2
-#define CMD_SETMULTICAST       3
-#define CMD_TX                 4
-#define CMD_TDR                        5
-#define CMD_DUMP               6
-#define CMD_DIAGNOSE           7
-
-#define CMD_MASK               7
-
-#define CMD_INTR               (1 << 13)
-#define CMD_SUSP               (1 << 14)
-#define CMD_EOL                        (1 << 15)
-
-#define STAT_COLLISIONS                (15)
-#define STAT_COLLEXCESSIVE     (1 << 5)
-#define STAT_COLLAFTERTX       (1 << 6)
-#define STAT_TXDEFERRED                (1 << 7)
-#define STAT_TXSLOWDMA         (1 << 8)
-#define STAT_TXLOSTCTS         (1 << 9)
-#define STAT_NOCARRIER         (1 << 10)
-#define STAT_FAIL              (1 << 11)
-#define STAT_ABORTED           (1 << 12)
-#define STAT_OK                        (1 << 13)
-#define STAT_BUSY              (1 << 14)
-#define STAT_COMPLETE          (1 << 15)
-#endif
-#endif
-
-/*
- * Ether1 card definitions:
- *
- * FAST accesses:
- *     +0      Page register
- *                     16 pages
- *     +4      Control
- *                     '1' = reset
- *                     '2' = loopback
- *                     '4' = CA
- *                     '8' = int ack
- *
- * RAM at address + 0x2000
- * Pod. Prod id = 3
- * Words after ID block [base + 8 words]
- *     +0 pcb issue (0x0c and 0xf3 invalid)
- *     +1 - +6 eth hw address
- */
diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c
deleted file mode 100644 (file)
index dfeb006..0000000
+++ /dev/null
@@ -1,1822 +0,0 @@
-/* eepro.c: Intel EtherExpress Pro/10 device driver for Linux. */
-/*
-       Written 1994, 1995,1996 by Bao C. Ha.
-
-       Copyright (C) 1994, 1995,1996 by Bao C. Ha.
-
-       This software may be used and distributed
-       according to the terms of the GNU General Public License,
-       incorporated herein by reference.
-
-       The author may be reached at bao.ha@srs.gov
-       or 418 Hastings Place, Martinez, GA 30907.
-
-       Things remaining to do:
-       Better record keeping of errors.
-       Eliminate transmit interrupt to reduce overhead.
-       Implement "concurrent processing". I won't be doing it!
-
-       Bugs:
-
-       If you have a problem of not detecting the 82595 during a
-       reboot (warm reset), disable the FLASH memory should fix it.
-       This is a compatibility hardware problem.
-
-       Versions:
-       0.13b   basic ethtool support (aris, 09/13/2004)
-       0.13a   in memory shortage, drop packets also in board
-               (Michael Westermann <mw@microdata-pos.de>, 07/30/2002)
-       0.13    irq sharing, rewrote probe function, fixed a nasty bug in
-               hardware_send_packet and a major cleanup (aris, 11/08/2001)
-       0.12d   fixing a problem with single card detected as eight eth devices
-               fixing a problem with sudden drop in card performance
-               (chris (asdn@go2.pl), 10/29/2001)
-       0.12c   fixing some problems with old cards (aris, 01/08/2001)
-       0.12b   misc fixes (aris, 06/26/2000)
-       0.12a   port of version 0.12a of 2.2.x kernels to 2.3.x
-               (aris (aris@conectiva.com.br), 05/19/2000)
-       0.11e   some tweaks about multiple cards support (PdP, jul/aug 1999)
-       0.11d   added __initdata, __init stuff; call spin_lock_init
-               in eepro_probe1. Replaced "eepro" by dev->name. Augmented
-               the code protected by spin_lock in interrupt routine
-               (PdP, 12/12/1998)
-       0.11c   minor cleanup (PdP, RMC, 09/12/1998)
-       0.11b   Pascal Dupuis (dupuis@lei.ucl.ac.be): works as a module
-               under 2.1.xx. Debug messages are flagged as KERN_DEBUG to
-               avoid console flooding. Added locking at critical parts. Now
-               the dawn thing is SMP safe.
-       0.11a   Attempt to get 2.1.xx support up (RMC)
-       0.11    Brian Candler added support for multiple cards. Tested as
-               a module, no idea if it works when compiled into kernel.
-
-       0.10e   Rick Bressler notified me that ifconfig up;ifconfig down fails
-               because the irq is lost somewhere. Fixed that by moving
-               request_irq and free_irq to eepro_open and eepro_close respectively.
-       0.10d   Ugh! Now Wakeup works. Was seriously broken in my first attempt.
-               I'll need to find a way to specify an ioport other than
-               the default one in the PnP case. PnP definitively sucks.
-               And, yes, this is not the only reason.
-       0.10c   PnP Wakeup Test for 595FX. uncomment #define PnPWakeup;
-               to use.
-       0.10b   Should work now with (some) Pro/10+. At least for
-               me (and my two cards) it does. _No_ guarantee for
-               function with non-Pro/10+ cards! (don't have any)
-               (RMC, 9/11/96)
-
-       0.10    Added support for the Etherexpress Pro/10+.  The
-               IRQ map was changed significantly from the old
-               pro/10.  The new interrupt map was provided by
-               Rainer M. Canavan (Canavan@Zeus.cs.bonn.edu).
-               (BCH, 9/3/96)
-
-       0.09    Fixed a race condition in the transmit algorithm,
-               which causes crashes under heavy load with fast
-               pentium computers.  The performance should also
-               improve a bit.  The size of RX buffer, and hence
-               TX buffer, can also be changed via lilo or insmod.
-               (BCH, 7/31/96)
-
-       0.08    Implement 32-bit I/O for the 82595TX and 82595FX
-               based lan cards.  Disable full-duplex mode if TPE
-               is not used.  (BCH, 4/8/96)
-
-       0.07a   Fix a stat report which counts every packet as a
-               heart-beat failure. (BCH, 6/3/95)
-
-       0.07    Modified to support all other 82595-based lan cards.
-               The IRQ vector of the EtherExpress Pro will be set
-               according to the value saved in the EEPROM.  For other
-               cards, I will do autoirq_request() to grab the next
-               available interrupt vector. (BCH, 3/17/95)
-
-       0.06a,b Interim released.  Minor changes in the comments and
-               print out format. (BCH, 3/9/95 and 3/14/95)
-
-       0.06    First stable release that I am comfortable with. (BCH,
-               3/2/95)
-
-       0.05    Complete testing of multicast. (BCH, 2/23/95)
-
-       0.04    Adding multicast support. (BCH, 2/14/95)
-
-       0.03    First widely alpha release for public testing.
-               (BCH, 2/14/95)
-
-*/
-
-static const char version[] =
-       "eepro.c: v0.13b 09/13/2004 aris@cathedrallabs.org\n";
-
-#include <linux/module.h>
-
-/*
-  Sources:
-
-       This driver wouldn't have been written without the availability
-       of the Crynwr's Lan595 driver source code.  It helps me to
-       familiarize with the 82595 chipset while waiting for the Intel
-       documentation.  I also learned how to detect the 82595 using
-       the packet driver's technique.
-
-       This driver is written by cutting and pasting the skeleton.c driver
-       provided by Donald Becker.  I also borrowed the EEPROM routine from
-       Donald Becker's 82586 driver.
-
-       Datasheet for the Intel 82595 (including the TX and FX version). It
-       provides just enough info that the casual reader might think that it
-       documents the i82595.
-
-       The User Manual for the 82595.  It provides a lot of the missing
-       information.
-
-*/
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/spinlock.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/bitops.h>
-#include <linux/ethtool.h>
-
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-
-#define DRV_NAME "eepro"
-#define DRV_VERSION "0.13c"
-
-#define compat_dev_kfree_skb( skb, mode ) dev_kfree_skb( (skb) )
-/* I had reports of looong delays with SLOW_DOWN defined as udelay(2) */
-#define SLOW_DOWN inb(0x80)
-/* udelay(2) */
-#define compat_init_data     __initdata
-enum iftype { AUI=0, BNC=1, TPE=2 };
-
-/* First, a few definitions that the brave might change. */
-/* A zero-terminated list of I/O addresses to be probed. */
-static unsigned int eepro_portlist[] compat_init_data =
-   { 0x300, 0x210, 0x240, 0x280, 0x2C0, 0x200, 0x320, 0x340, 0x360, 0};
-/* note: 0x300 is default, the 595FX supports ALL IO Ports
-  from 0x000 to 0x3F0, some of which are reserved in PCs */
-
-/* To try the (not-really PnP Wakeup: */
-/*
-#define PnPWakeup
-*/
-
-/* use 0 for production, 1 for verification, >2 for debug */
-#ifndef NET_DEBUG
-#define NET_DEBUG 0
-#endif
-static unsigned int net_debug = NET_DEBUG;
-
-/* The number of low I/O ports used by the ethercard. */
-#define EEPRO_IO_EXTENT        16
-
-/* Different 82595 chips */
-#define        LAN595          0
-#define        LAN595TX        1
-#define        LAN595FX        2
-#define        LAN595FX_10ISA  3
-
-/* Information that need to be kept for each board. */
-struct eepro_local {
-       unsigned rx_start;
-       unsigned tx_start; /* start of the transmit chain */
-       int tx_last;  /* pointer to last packet in the transmit chain */
-       unsigned tx_end;   /* end of the transmit chain (plus 1) */
-       int eepro;      /* 1 for the EtherExpress Pro/10,
-                          2 for the EtherExpress Pro/10+,
-                          3 for the EtherExpress 10 (blue cards),
-                          0 for other 82595-based lan cards. */
-       int version;    /* a flag to indicate if this is a TX or FX
-                                  version of the 82595 chip. */
-       int stepping;
-
-       spinlock_t lock; /* Serializing lock  */
-
-       unsigned rcv_ram;       /* pre-calculated space for rx */
-       unsigned xmt_ram;       /* pre-calculated space for tx */
-       unsigned char xmt_bar;
-       unsigned char xmt_lower_limit_reg;
-       unsigned char xmt_upper_limit_reg;
-       short xmt_lower_limit;
-       short xmt_upper_limit;
-       short rcv_lower_limit;
-       short rcv_upper_limit;
-       unsigned char eeprom_reg;
-       unsigned short word[8];
-};
-
-/* The station (ethernet) address prefix, used for IDing the board. */
-#define SA_ADDR0 0x00  /* Etherexpress Pro/10 */
-#define SA_ADDR1 0xaa
-#define SA_ADDR2 0x00
-
-#define GetBit(x,y) ((x & (1<<y))>>y)
-
-/* EEPROM Word 0: */
-#define ee_PnP       0  /* Plug 'n Play enable bit */
-#define ee_Word1     1  /* Word 1? */
-#define ee_BusWidth  2  /* 8/16 bit */
-#define ee_FlashAddr 3  /* Flash Address */
-#define ee_FlashMask 0x7   /* Mask */
-#define ee_AutoIO    6  /* */
-#define ee_reserved0 7  /* =0! */
-#define ee_Flash     8  /* Flash there? */
-#define ee_AutoNeg   9  /* Auto Negotiation enabled? */
-#define ee_IO0       10 /* IO Address LSB */
-#define ee_IO0Mask   0x /*...*/
-#define ee_IO1       15 /* IO MSB */
-
-/* EEPROM Word 1: */
-#define ee_IntSel    0   /* Interrupt */
-#define ee_IntMask   0x7
-#define ee_LI        3   /* Link Integrity 0= enabled */
-#define ee_PC        4   /* Polarity Correction 0= enabled */
-#define ee_TPE_AUI   5   /* PortSelection 1=TPE */
-#define ee_Jabber    6   /* Jabber prevention 0= enabled */
-#define ee_AutoPort  7   /* Auto Port Selection 1= Disabled */
-#define ee_SMOUT     8   /* SMout Pin Control 0= Input */
-#define ee_PROM      9   /* Flash EPROM / PROM 0=Flash */
-#define ee_reserved1 10  /* .. 12 =0! */
-#define ee_AltReady  13  /* Alternate Ready, 0=normal */
-#define ee_reserved2 14  /* =0! */
-#define ee_Duplex    15
-
-/* Word2,3,4: */
-#define ee_IA5       0 /*bit start for individual Addr Byte 5 */
-#define ee_IA4       8 /*bit start for individual Addr Byte 5 */
-#define ee_IA3       0 /*bit start for individual Addr Byte 5 */
-#define ee_IA2       8 /*bit start for individual Addr Byte 5 */
-#define ee_IA1       0 /*bit start for individual Addr Byte 5 */
-#define ee_IA0       8 /*bit start for individual Addr Byte 5 */
-
-/* Word 5: */
-#define ee_BNC_TPE   0 /* 0=TPE */
-#define ee_BootType  1 /* 00=None, 01=IPX, 10=ODI, 11=NDIS */
-#define ee_BootTypeMask 0x3
-#define ee_NumConn   3  /* Number of Connections 0= One or Two */
-#define ee_FlashSock 4  /* Presence of Flash Socket 0= Present */
-#define ee_PortTPE   5
-#define ee_PortBNC   6
-#define ee_PortAUI   7
-#define ee_PowerMgt  10 /* 0= disabled */
-#define ee_CP        13 /* Concurrent Processing */
-#define ee_CPMask    0x7
-
-/* Word 6: */
-#define ee_Stepping  0 /* Stepping info */
-#define ee_StepMask  0x0F
-#define ee_BoardID   4 /* Manucaturer Board ID, reserved */
-#define ee_BoardMask 0x0FFF
-
-/* Word 7: */
-#define ee_INT_TO_IRQ 0 /* int to IRQ Mapping  = 0x1EB8 for Pro/10+ */
-#define ee_FX_INT2IRQ 0x1EB8 /* the _only_ mapping allowed for FX chips */
-
-/*..*/
-#define ee_SIZE 0x40 /* total EEprom Size */
-#define ee_Checksum 0xBABA /* initial and final value for adding checksum */
-
-
-/* Card identification via EEprom:   */
-#define ee_addr_vendor 0x10  /* Word offset for EISA Vendor ID */
-#define ee_addr_id 0x11      /* Word offset for Card ID */
-#define ee_addr_SN 0x12      /* Serial Number */
-#define ee_addr_CRC_8 0x14   /* CRC over last thee Bytes */
-
-
-#define ee_vendor_intel0 0x25  /* Vendor ID Intel */
-#define ee_vendor_intel1 0xD4
-#define ee_id_eepro10p0 0x10   /* ID for eepro/10+ */
-#define ee_id_eepro10p1 0x31
-
-#define TX_TIMEOUT ((4*HZ)/10)
-
-/* Index to functions, as function prototypes. */
-
-static int     eepro_probe1(struct net_device *dev, int autoprobe);
-static int     eepro_open(struct net_device *dev);
-static netdev_tx_t eepro_send_packet(struct sk_buff *skb,
-                                    struct net_device *dev);
-static irqreturn_t eepro_interrupt(int irq, void *dev_id);
-static void    eepro_rx(struct net_device *dev);
-static void    eepro_transmit_interrupt(struct net_device *dev);
-static int     eepro_close(struct net_device *dev);
-static void     set_multicast_list(struct net_device *dev);
-static void     eepro_tx_timeout (struct net_device *dev);
-
-static int read_eeprom(int ioaddr, int location, struct net_device *dev);
-static int     hardware_send_packet(struct net_device *dev, void *buf, short length);
-static int     eepro_grab_irq(struct net_device *dev);
-
-/*
-                       Details of the i82595.
-
-You will need either the datasheet or the user manual to understand what
-is going on here.  The 82595 is very different from the 82586, 82593.
-
-The receive algorithm in eepro_rx() is just an implementation of the
-RCV ring structure that the Intel 82595 imposes at the hardware level.
-The receive buffer is set at 24K, and the transmit buffer is 8K.  I
-am assuming that the total buffer memory is 32K, which is true for the
-Intel EtherExpress Pro/10.  If it is less than that on a generic card,
-the driver will be broken.
-
-The transmit algorithm in the hardware_send_packet() is similar to the
-one in the eepro_rx().  The transmit buffer is a ring linked list.
-I just queue the next available packet to the end of the list.  In my
-system, the 82595 is so fast that the list seems to always contain a
-single packet.  In other systems with faster computers and more congested
-network traffics, the ring linked list should improve performance by
-allowing up to 8K worth of packets to be queued.
-
-The sizes of the receive and transmit buffers can now be changed via lilo
-or insmod.  Lilo uses the appended line "ether=io,irq,debug,rx-buffer,eth0"
-where rx-buffer is in KB unit.  Modules uses the parameter mem which is
-also in KB unit, for example "insmod io=io-address irq=0 mem=rx-buffer."
-The receive buffer has to be more than 3K or less than 29K.  Otherwise,
-it is reset to the default of 24K, and, hence, 8K for the trasnmit
-buffer (transmit-buffer = 32K - receive-buffer).
-
-*/
-#define RAM_SIZE        0x8000
-
-#define RCV_HEADER      8
-#define RCV_DEFAULT_RAM 0x6000
-
-#define XMT_HEADER      8
-#define XMT_DEFAULT_RAM        (RAM_SIZE - RCV_DEFAULT_RAM)
-
-#define XMT_START_PRO  RCV_DEFAULT_RAM
-#define XMT_START_10   0x0000
-#define RCV_START_PRO  0x0000
-#define RCV_START_10   XMT_DEFAULT_RAM
-
-#define        RCV_DONE        0x0008
-#define        RX_OK           0x2000
-#define        RX_ERROR        0x0d81
-
-#define        TX_DONE_BIT     0x0080
-#define        TX_OK           0x2000
-#define        CHAIN_BIT       0x8000
-#define        XMT_STATUS      0x02
-#define        XMT_CHAIN       0x04
-#define        XMT_COUNT       0x06
-
-#define        BANK0_SELECT    0x00
-#define        BANK1_SELECT    0x40
-#define        BANK2_SELECT    0x80
-
-/* Bank 0 registers */
-#define        COMMAND_REG     0x00    /* Register 0 */
-#define        MC_SETUP        0x03
-#define        XMT_CMD         0x04
-#define        DIAGNOSE_CMD    0x07
-#define        RCV_ENABLE_CMD  0x08
-#define        RCV_DISABLE_CMD 0x0a
-#define        STOP_RCV_CMD    0x0b
-#define        RESET_CMD       0x0e
-#define        POWER_DOWN_CMD  0x18
-#define        RESUME_XMT_CMD  0x1c
-#define        SEL_RESET_CMD   0x1e
-#define        STATUS_REG      0x01    /* Register 1 */
-#define        RX_INT          0x02
-#define        TX_INT          0x04
-#define        EXEC_STATUS     0x30
-#define        ID_REG          0x02    /* Register 2   */
-#define        R_ROBIN_BITS    0xc0    /* round robin counter */
-#define        ID_REG_MASK     0x2c
-#define        ID_REG_SIG      0x24
-#define        AUTO_ENABLE     0x10
-#define        INT_MASK_REG    0x03    /* Register 3   */
-#define        RX_STOP_MASK    0x01
-#define        RX_MASK         0x02
-#define        TX_MASK         0x04
-#define        EXEC_MASK       0x08
-#define        ALL_MASK        0x0f
-#define        IO_32_BIT       0x10
-#define        RCV_BAR         0x04    /* The following are word (16-bit) registers */
-#define        RCV_STOP        0x06
-
-#define        XMT_BAR_PRO     0x0a
-#define        XMT_BAR_10      0x0b
-
-#define        HOST_ADDRESS_REG        0x0c
-#define        IO_PORT         0x0e
-#define        IO_PORT_32_BIT  0x0c
-
-/* Bank 1 registers */
-#define        REG1    0x01
-#define        WORD_WIDTH      0x02
-#define        INT_ENABLE      0x80
-#define INT_NO_REG     0x02
-#define        RCV_LOWER_LIMIT_REG     0x08
-#define        RCV_UPPER_LIMIT_REG     0x09
-
-#define        XMT_LOWER_LIMIT_REG_PRO 0x0a
-#define        XMT_UPPER_LIMIT_REG_PRO 0x0b
-#define        XMT_LOWER_LIMIT_REG_10  0x0b
-#define        XMT_UPPER_LIMIT_REG_10  0x0a
-
-/* Bank 2 registers */
-#define        XMT_Chain_Int   0x20    /* Interrupt at the end of the transmit chain */
-#define        XMT_Chain_ErrStop       0x40 /* Interrupt at the end of the chain even if there are errors */
-#define        RCV_Discard_BadFrame    0x80 /* Throw bad frames away, and continue to receive others */
-#define        REG2            0x02
-#define        PRMSC_Mode      0x01
-#define        Multi_IA        0x20
-#define        REG3            0x03
-#define        TPE_BIT         0x04
-#define        BNC_BIT         0x20
-#define        REG13           0x0d
-#define        FDX             0x00
-#define        A_N_ENABLE      0x02
-
-#define        I_ADD_REG0      0x04
-#define        I_ADD_REG1      0x05
-#define        I_ADD_REG2      0x06
-#define        I_ADD_REG3      0x07
-#define        I_ADD_REG4      0x08
-#define        I_ADD_REG5      0x09
-
-#define        EEPROM_REG_PRO 0x0a
-#define        EEPROM_REG_10  0x0b
-
-#define EESK 0x01
-#define EECS 0x02
-#define EEDI 0x04
-#define EEDO 0x08
-
-/* do a full reset */
-#define eepro_reset(ioaddr) outb(RESET_CMD, ioaddr)
-
-/* do a nice reset */
-#define eepro_sel_reset(ioaddr)        { \
-                                       outb(SEL_RESET_CMD, ioaddr); \
-                                       SLOW_DOWN; \
-                                       SLOW_DOWN; \
-                                       }
-
-/* disable all interrupts */
-#define eepro_dis_int(ioaddr) outb(ALL_MASK, ioaddr + INT_MASK_REG)
-
-/* clear all interrupts */
-#define eepro_clear_int(ioaddr) outb(ALL_MASK, ioaddr + STATUS_REG)
-
-/* enable tx/rx */
-#define eepro_en_int(ioaddr) outb(ALL_MASK & ~(RX_MASK | TX_MASK), \
-                                                       ioaddr + INT_MASK_REG)
-
-/* enable exec event interrupt */
-#define eepro_en_intexec(ioaddr) outb(ALL_MASK & ~(EXEC_MASK), ioaddr + INT_MASK_REG)
-
-/* enable rx */
-#define eepro_en_rx(ioaddr) outb(RCV_ENABLE_CMD, ioaddr)
-
-/* disable rx */
-#define eepro_dis_rx(ioaddr) outb(RCV_DISABLE_CMD, ioaddr)
-
-/* switch bank */
-#define eepro_sw2bank0(ioaddr) outb(BANK0_SELECT, ioaddr)
-#define eepro_sw2bank1(ioaddr) outb(BANK1_SELECT, ioaddr)
-#define eepro_sw2bank2(ioaddr) outb(BANK2_SELECT, ioaddr)
-
-/* enable interrupt line */
-#define eepro_en_intline(ioaddr) outb(inb(ioaddr + REG1) | INT_ENABLE,\
-                               ioaddr + REG1)
-
-/* disable interrupt line */
-#define eepro_dis_intline(ioaddr) outb(inb(ioaddr + REG1) & 0x7f, \
-                               ioaddr + REG1);
-
-/* set diagnose flag */
-#define eepro_diag(ioaddr) outb(DIAGNOSE_CMD, ioaddr)
-
-/* ack for rx int */
-#define eepro_ack_rx(ioaddr) outb (RX_INT, ioaddr + STATUS_REG)
-
-/* ack for tx int */
-#define eepro_ack_tx(ioaddr) outb (TX_INT, ioaddr + STATUS_REG)
-
-/* a complete sel reset */
-#define eepro_complete_selreset(ioaddr) { \
-                                               dev->stats.tx_errors++;\
-                                               eepro_sel_reset(ioaddr);\
-                                               lp->tx_end = \
-                                                       lp->xmt_lower_limit;\
-                                               lp->tx_start = lp->tx_end;\
-                                               lp->tx_last = 0;\
-                                               dev->trans_start = jiffies;\
-                                               netif_wake_queue(dev);\
-                                               eepro_en_rx(ioaddr);\
-                                       }
-
-/* Check for a network adaptor of this type, and return '0' if one exists.
-   If dev->base_addr == 0, probe all likely locations.
-   If dev->base_addr == 1, always return failure.
-   If dev->base_addr == 2, allocate space for the device and return success
-   (detachable devices only).
-   */
-static int __init do_eepro_probe(struct net_device *dev)
-{
-       int i;
-       int base_addr = dev->base_addr;
-       int irq = dev->irq;
-
-#ifdef PnPWakeup
-       /* XXXX for multiple cards should this only be run once? */
-
-       /* Wakeup: */
-       #define WakeupPort 0x279
-       #define WakeupSeq    {0x6A, 0xB5, 0xDA, 0xED, 0xF6, 0xFB, 0x7D, 0xBE,\
-                             0xDF, 0x6F, 0x37, 0x1B, 0x0D, 0x86, 0xC3, 0x61,\
-                             0xB0, 0x58, 0x2C, 0x16, 0x8B, 0x45, 0xA2, 0xD1,\
-                             0xE8, 0x74, 0x3A, 0x9D, 0xCE, 0xE7, 0x73, 0x43}
-
-       {
-               unsigned short int WS[32]=WakeupSeq;
-
-               if (request_region(WakeupPort, 2, "eepro wakeup")) {
-                       if (net_debug>5)
-                               printk(KERN_DEBUG "Waking UP\n");
-
-                       outb_p(0,WakeupPort);
-                       outb_p(0,WakeupPort);
-                       for (i=0; i<32; i++) {
-                               outb_p(WS[i],WakeupPort);
-                               if (net_debug>5) printk(KERN_DEBUG ": %#x ",WS[i]);
-                       }
-
-                       release_region(WakeupPort, 2);
-               } else
-                       printk(KERN_WARNING "PnP wakeup region busy!\n");
-       }
-#endif
-
-       if (base_addr > 0x1ff)          /* Check a single specified location. */
-               return eepro_probe1(dev, 0);
-
-       else if (base_addr != 0)        /* Don't probe at all. */
-               return -ENXIO;
-
-       for (i = 0; eepro_portlist[i]; i++) {
-               dev->base_addr = eepro_portlist[i];
-               dev->irq = irq;
-               if (eepro_probe1(dev, 1) == 0)
-                       return 0;
-       }
-
-       return -ENODEV;
-}
-
-#ifndef MODULE
-struct net_device * __init eepro_probe(int unit)
-{
-       struct net_device *dev = alloc_etherdev(sizeof(struct eepro_local));
-       int err;
-
-       if (!dev)
-               return ERR_PTR(-ENODEV);
-
-       sprintf(dev->name, "eth%d", unit);
-       netdev_boot_setup_check(dev);
-
-       err = do_eepro_probe(dev);
-       if (err)
-               goto out;
-       return dev;
-out:
-       free_netdev(dev);
-       return ERR_PTR(err);
-}
-#endif
-
-static void __init printEEPROMInfo(struct net_device *dev)
-{
-       struct eepro_local *lp = netdev_priv(dev);
-       int ioaddr = dev->base_addr;
-       unsigned short Word;
-       int i,j;
-
-       j = ee_Checksum;
-       for (i = 0; i < 8; i++)
-               j += lp->word[i];
-       for ( ; i < ee_SIZE; i++)
-               j += read_eeprom(ioaddr, i, dev);
-
-       printk(KERN_DEBUG "Checksum: %#x\n",j&0xffff);
-
-       Word = lp->word[0];
-       printk(KERN_DEBUG "Word0:\n");
-       printk(KERN_DEBUG " Plug 'n Pray: %d\n",GetBit(Word,ee_PnP));
-       printk(KERN_DEBUG " Buswidth: %d\n",(GetBit(Word,ee_BusWidth)+1)*8 );
-       printk(KERN_DEBUG " AutoNegotiation: %d\n",GetBit(Word,ee_AutoNeg));
-       printk(KERN_DEBUG " IO Address: %#x\n", (Word>>ee_IO0)<<4);
-
-       if (net_debug>4)  {
-               Word = lp->word[1];
-               printk(KERN_DEBUG "Word1:\n");
-               printk(KERN_DEBUG " INT: %d\n", Word & ee_IntMask);
-               printk(KERN_DEBUG " LI: %d\n", GetBit(Word,ee_LI));
-               printk(KERN_DEBUG " PC: %d\n", GetBit(Word,ee_PC));
-               printk(KERN_DEBUG " TPE/AUI: %d\n", GetBit(Word,ee_TPE_AUI));
-               printk(KERN_DEBUG " Jabber: %d\n", GetBit(Word,ee_Jabber));
-               printk(KERN_DEBUG " AutoPort: %d\n", !GetBit(Word,ee_AutoPort));
-               printk(KERN_DEBUG " Duplex: %d\n", GetBit(Word,ee_Duplex));
-       }
-
-       Word = lp->word[5];
-       printk(KERN_DEBUG "Word5:\n");
-       printk(KERN_DEBUG " BNC: %d\n",GetBit(Word,ee_BNC_TPE));
-       printk(KERN_DEBUG " NumConnectors: %d\n",GetBit(Word,ee_NumConn));
-       printk(KERN_DEBUG " Has ");
-       if (GetBit(Word,ee_PortTPE)) printk(KERN_DEBUG "TPE ");
-       if (GetBit(Word,ee_PortBNC)) printk(KERN_DEBUG "BNC ");
-       if (GetBit(Word,ee_PortAUI)) printk(KERN_DEBUG "AUI ");
-       printk(KERN_DEBUG "port(s)\n");
-
-       Word = lp->word[6];
-       printk(KERN_DEBUG "Word6:\n");
-       printk(KERN_DEBUG " Stepping: %d\n",Word & ee_StepMask);
-       printk(KERN_DEBUG " BoardID: %d\n",Word>>ee_BoardID);
-
-       Word = lp->word[7];
-       printk(KERN_DEBUG "Word7:\n");
-       printk(KERN_DEBUG " INT to IRQ:\n");
-
-       for (i=0, j=0; i<15; i++)
-               if (GetBit(Word,i)) printk(KERN_DEBUG " INT%d -> IRQ %d;",j++,i);
-
-       printk(KERN_DEBUG "\n");
-}
-
-/* function to recalculate the limits of buffer based on rcv_ram */
-static void eepro_recalc (struct net_device *dev)
-{
-       struct eepro_local *    lp;
-
-       lp = netdev_priv(dev);
-       lp->xmt_ram = RAM_SIZE - lp->rcv_ram;
-
-       if (lp->eepro == LAN595FX_10ISA) {
-               lp->xmt_lower_limit = XMT_START_10;
-               lp->xmt_upper_limit = (lp->xmt_ram - 2);
-               lp->rcv_lower_limit = lp->xmt_ram;
-               lp->rcv_upper_limit = (RAM_SIZE - 2);
-       }
-       else {
-               lp->rcv_lower_limit = RCV_START_PRO;
-               lp->rcv_upper_limit = (lp->rcv_ram - 2);
-               lp->xmt_lower_limit = lp->rcv_ram;
-               lp->xmt_upper_limit = (RAM_SIZE - 2);
-       }
-}
-
-/* prints boot-time info */
-static void __init eepro_print_info (struct net_device *dev)
-{
-       struct eepro_local *    lp = netdev_priv(dev);
-       int                     i;
-       const char *            ifmap[] = {"AUI", "10Base2", "10BaseT"};
-
-       i = inb(dev->base_addr + ID_REG);
-       printk(KERN_DEBUG " id: %#x ",i);
-       printk(" io: %#x ", (unsigned)dev->base_addr);
-
-       switch (lp->eepro) {
-               case LAN595FX_10ISA:
-                       printk("%s: Intel EtherExpress 10 ISA\n at %#x,",
-                                       dev->name, (unsigned)dev->base_addr);
-                       break;
-               case LAN595FX:
-                       printk("%s: Intel EtherExpress Pro/10+ ISA\n at %#x,",
-                                       dev->name, (unsigned)dev->base_addr);
-                       break;
-               case LAN595TX:
-                       printk("%s: Intel EtherExpress Pro/10 ISA at %#x,",
-                                       dev->name, (unsigned)dev->base_addr);
-                       break;
-               case LAN595:
-                       printk("%s: Intel 82595-based lan card at %#x,",
-                                       dev->name, (unsigned)dev->base_addr);
-                       break;
-       }
-
-       printk(" %pM", dev->dev_addr);
-
-       if (net_debug > 3)
-               printk(KERN_DEBUG ", %dK RCV buffer",
-                               (int)(lp->rcv_ram)/1024);
-
-       if (dev->irq > 2)
-               printk(", IRQ %d, %s.\n", dev->irq, ifmap[dev->if_port]);
-       else
-               printk(", %s.\n", ifmap[dev->if_port]);
-
-       if (net_debug > 3) {
-               i = lp->word[5];
-               if (i & 0x2000) /* bit 13 of EEPROM word 5 */
-                       printk(KERN_DEBUG "%s: Concurrent Processing is "
-                               "enabled but not used!\n", dev->name);
-       }
-
-       /* Check the station address for the manufacturer's code */
-       if (net_debug>3)
-               printEEPROMInfo(dev);
-}
-
-static const struct ethtool_ops eepro_ethtool_ops;
-
-static const struct net_device_ops eepro_netdev_ops = {
-       .ndo_open               = eepro_open,
-       .ndo_stop               = eepro_close,
-       .ndo_start_xmit         = eepro_send_packet,
-       .ndo_set_multicast_list = set_multicast_list,
-       .ndo_tx_timeout         = eepro_tx_timeout,
-       .ndo_change_mtu         = eth_change_mtu,
-       .ndo_set_mac_address    = eth_mac_addr,
-       .ndo_validate_addr      = eth_validate_addr,
-};
-
-/* This is the real probe routine.  Linux has a history of friendly device
-   probes on the ISA bus.  A good device probe avoids doing writes, and
-   verifies that the correct device exists and functions.  */
-
-static int __init eepro_probe1(struct net_device *dev, int autoprobe)
-{
-       unsigned short station_addr[3], id, counter;
-       int i;
-       struct eepro_local *lp;
-       int ioaddr = dev->base_addr;
-       int err;
-
-       /* Grab the region so we can find another board if autoIRQ fails. */
-       if (!request_region(ioaddr, EEPRO_IO_EXTENT, DRV_NAME)) {
-               if (!autoprobe)
-                       printk(KERN_WARNING "EEPRO: io-port 0x%04x in use\n",
-                               ioaddr);
-               return -EBUSY;
-       }
-
-       /* Now, we are going to check for the signature of the
-          ID_REG (register 2 of bank 0) */
-
-       id = inb(ioaddr + ID_REG);
-
-       if ((id & ID_REG_MASK) != ID_REG_SIG)
-               goto exit;
-
-       /* We seem to have the 82595 signature, let's
-          play with its counter (last 2 bits of
-          register 2 of bank 0) to be sure. */
-
-       counter = id & R_ROBIN_BITS;
-
-       if ((inb(ioaddr + ID_REG) & R_ROBIN_BITS) != (counter + 0x40))
-               goto exit;
-
-       lp = netdev_priv(dev);
-       memset(lp, 0, sizeof(struct eepro_local));
-       lp->xmt_bar = XMT_BAR_PRO;
-       lp->xmt_lower_limit_reg = XMT_LOWER_LIMIT_REG_PRO;
-       lp->xmt_upper_limit_reg = XMT_UPPER_LIMIT_REG_PRO;
-       lp->eeprom_reg = EEPROM_REG_PRO;
-       spin_lock_init(&lp->lock);
-
-       /* Now, get the ethernet hardware address from
-          the EEPROM */
-       station_addr[0] = read_eeprom(ioaddr, 2, dev);
-
-       /* FIXME - find another way to know that we've found
-        * an Etherexpress 10
-        */
-       if (station_addr[0] == 0x0000 || station_addr[0] == 0xffff) {
-               lp->eepro = LAN595FX_10ISA;
-               lp->eeprom_reg = EEPROM_REG_10;
-               lp->xmt_lower_limit_reg = XMT_LOWER_LIMIT_REG_10;
-               lp->xmt_upper_limit_reg = XMT_UPPER_LIMIT_REG_10;
-               lp->xmt_bar = XMT_BAR_10;
-               station_addr[0] = read_eeprom(ioaddr, 2, dev);
-       }
-
-       /* get all words at once. will be used here and for ethtool */
-       for (i = 0; i < 8; i++) {
-               lp->word[i] = read_eeprom(ioaddr, i, dev);
-       }
-       station_addr[1] = lp->word[3];
-       station_addr[2] = lp->word[4];
-
-       if (!lp->eepro) {
-               if (lp->word[7] == ee_FX_INT2IRQ)
-                       lp->eepro = 2;
-               else if (station_addr[2] == SA_ADDR1)
-                       lp->eepro = 1;
-       }
-
-       /* Fill in the 'dev' fields. */
-       for (i=0; i < 6; i++)
-               dev->dev_addr[i] = ((unsigned char *) station_addr)[5-i];
-
-       /* RX buffer must be more than 3K and less than 29K */
-       if (dev->mem_end < 3072 || dev->mem_end > 29696)
-               lp->rcv_ram = RCV_DEFAULT_RAM;
-
-       /* calculate {xmt,rcv}_{lower,upper}_limit */
-       eepro_recalc(dev);
-
-       if (GetBit(lp->word[5], ee_BNC_TPE))
-               dev->if_port = BNC;
-       else
-               dev->if_port = TPE;
-
-       if (dev->irq < 2 && lp->eepro != 0) {
-               /* Mask off INT number */
-               int count = lp->word[1] & 7;
-               unsigned irqMask = lp->word[7];
-
-               while (count--)
-                       irqMask &= irqMask - 1;
-
-               count = ffs(irqMask);
-
-               if (count)
-                       dev->irq = count - 1;
-
-               if (dev->irq < 2) {
-                       printk(KERN_ERR " Duh! illegal interrupt vector stored in EEPROM.\n");
-                       goto exit;
-               } else if (dev->irq == 2) {
-                       dev->irq = 9;
-               }
-       }
-
-       dev->netdev_ops         = &eepro_netdev_ops;
-       dev->watchdog_timeo     = TX_TIMEOUT;
-       dev->ethtool_ops        = &eepro_ethtool_ops;
-
-       /* print boot time info */
-       eepro_print_info(dev);
-
-       /* reset 82595 */
-       eepro_reset(ioaddr);
-
-       err = register_netdev(dev);
-       if (err)
-               goto err;
-       return 0;
-exit:
-       err = -ENODEV;
-err:
-       release_region(dev->base_addr, EEPRO_IO_EXTENT);
-       return err;
-}
-
-/* Open/initialize the board.  This is called (in the current kernel)
-   sometime after booting when the 'ifconfig' program is run.
-
-   This routine should set everything up anew at each open, even
-   registers that "should" only need to be set once at boot, so that
-   there is non-reboot way to recover if something goes wrong.
-   */
-
-static const char irqrmap[] = {-1,-1,0,1,-1,2,-1,-1,-1,0,3,4,-1,-1,-1,-1};
-static const char irqrmap2[] = {-1,-1,4,0,1,2,-1,3,-1,4,5,6,7,-1,-1,-1};
-static int     eepro_grab_irq(struct net_device *dev)
-{
-       static const int irqlist[] = { 3, 4, 5, 7, 9, 10, 11, 12, 0 };
-       const int *irqp = irqlist;
-       int temp_reg, ioaddr = dev->base_addr;
-
-       eepro_sw2bank1(ioaddr); /* be CAREFUL, BANK 1 now */
-
-       /* Enable the interrupt line. */
-       eepro_en_intline(ioaddr);
-
-       /* be CAREFUL, BANK 0 now */
-       eepro_sw2bank0(ioaddr);
-
-       /* clear all interrupts */
-       eepro_clear_int(ioaddr);
-
-       /* Let EXEC event to interrupt */
-       eepro_en_intexec(ioaddr);
-
-       do {
-               eepro_sw2bank1(ioaddr); /* be CAREFUL, BANK 1 now */
-
-               temp_reg = inb(ioaddr + INT_NO_REG);
-               outb((temp_reg & 0xf8) | irqrmap[*irqp], ioaddr + INT_NO_REG);
-
-               eepro_sw2bank0(ioaddr); /* Switch back to Bank 0 */
-
-               if (request_irq (*irqp, NULL, IRQF_SHARED, "bogus", dev) != EBUSY) {
-                       unsigned long irq_mask;
-                       /* Twinkle the interrupt, and check if it's seen */
-                       irq_mask = probe_irq_on();
-
-                       eepro_diag(ioaddr); /* RESET the 82595 */
-                       mdelay(20);
-
-                       if (*irqp == probe_irq_off(irq_mask))  /* It's a good IRQ line */
-                               break;
-
-                       /* clear all interrupts */
-                       eepro_clear_int(ioaddr);
-               }
-       } while (*++irqp);
-
-       eepro_sw2bank1(ioaddr); /* Switch back to Bank 1 */
-
-       /* Disable the physical interrupt line. */
-       eepro_dis_intline(ioaddr);
-
-       eepro_sw2bank0(ioaddr); /* Switch back to Bank 0 */
-
-       /* Mask all the interrupts. */
-       eepro_dis_int(ioaddr);
-
-       /* clear all interrupts */
-       eepro_clear_int(ioaddr);
-
-       return dev->irq;
-}
-
-static int eepro_open(struct net_device *dev)
-{
-       unsigned short temp_reg, old8, old9;
-       int irqMask;
-       int i, ioaddr = dev->base_addr;
-       struct eepro_local *lp = netdev_priv(dev);
-
-       if (net_debug > 3)
-               printk(KERN_DEBUG "%s: entering eepro_open routine.\n", dev->name);
-
-       irqMask = lp->word[7];
-
-       if (lp->eepro == LAN595FX_10ISA) {
-               if (net_debug > 3) printk(KERN_DEBUG "p->eepro = 3;\n");
-       }
-       else if (irqMask == ee_FX_INT2IRQ) /* INT to IRQ Mask */
-               {
-                       lp->eepro = 2; /* Yes, an Intel EtherExpress Pro/10+ */
-                       if (net_debug > 3) printk(KERN_DEBUG "p->eepro = 2;\n");
-               }
-
-       else if ((dev->dev_addr[0] == SA_ADDR0 &&
-                       dev->dev_addr[1] == SA_ADDR1 &&
-                       dev->dev_addr[2] == SA_ADDR2))
-               {
-                       lp->eepro = 1;
-                       if (net_debug > 3) printk(KERN_DEBUG "p->eepro = 1;\n");
-               }  /* Yes, an Intel EtherExpress Pro/10 */
-
-       else lp->eepro = 0; /* No, it is a generic 82585 lan card */
-
-       /* Get the interrupt vector for the 82595 */
-       if (dev->irq < 2 && eepro_grab_irq(dev) == 0) {
-               printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, dev->irq);
-               return -EAGAIN;
-       }
-
-       if (request_irq(dev->irq , eepro_interrupt, 0, dev->name, dev)) {
-               printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, dev->irq);
-               return -EAGAIN;
-       }
-
-       /* Initialize the 82595. */
-
-       eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */
-       temp_reg = inb(ioaddr + lp->eeprom_reg);
-
-       lp->stepping = temp_reg >> 5;   /* Get the stepping number of the 595 */
-
-       if (net_debug > 3)
-               printk(KERN_DEBUG "The stepping of the 82595 is %d\n", lp->stepping);
-
-       if (temp_reg & 0x10) /* Check the TurnOff Enable bit */
-               outb(temp_reg & 0xef, ioaddr + lp->eeprom_reg);
-       for (i=0; i < 6; i++)
-               outb(dev->dev_addr[i] , ioaddr + I_ADD_REG0 + i);
-
-       temp_reg = inb(ioaddr + REG1);    /* Setup Transmit Chaining */
-       outb(temp_reg | XMT_Chain_Int | XMT_Chain_ErrStop /* and discard bad RCV frames */
-               | RCV_Discard_BadFrame, ioaddr + REG1);
-
-       temp_reg = inb(ioaddr + REG2); /* Match broadcast */
-       outb(temp_reg | 0x14, ioaddr + REG2);
-
-       temp_reg = inb(ioaddr + REG3);
-       outb(temp_reg & 0x3f, ioaddr + REG3); /* clear test mode */
-
-       /* Set the receiving mode */
-       eepro_sw2bank1(ioaddr); /* be CAREFUL, BANK 1 now */
-
-       /* Set the interrupt vector */
-       temp_reg = inb(ioaddr + INT_NO_REG);
-       if (lp->eepro == LAN595FX || lp->eepro == LAN595FX_10ISA)
-               outb((temp_reg & 0xf8) | irqrmap2[dev->irq], ioaddr + INT_NO_REG);
-       else outb((temp_reg & 0xf8) | irqrmap[dev->irq], ioaddr + INT_NO_REG);
-
-
-       temp_reg = inb(ioaddr + INT_NO_REG);
-       if (lp->eepro == LAN595FX || lp->eepro == LAN595FX_10ISA)
-               outb((temp_reg & 0xf0) | irqrmap2[dev->irq] | 0x08,ioaddr+INT_NO_REG);
-       else outb((temp_reg & 0xf8) | irqrmap[dev->irq], ioaddr + INT_NO_REG);
-
-       if (net_debug > 3)
-               printk(KERN_DEBUG "eepro_open: content of INT Reg is %x\n", temp_reg);
-
-
-       /* Initialize the RCV and XMT upper and lower limits */
-       outb(lp->rcv_lower_limit >> 8, ioaddr + RCV_LOWER_LIMIT_REG);
-       outb(lp->rcv_upper_limit >> 8, ioaddr + RCV_UPPER_LIMIT_REG);
-       outb(lp->xmt_lower_limit >> 8, ioaddr + lp->xmt_lower_limit_reg);
-       outb(lp->xmt_upper_limit >> 8, ioaddr + lp->xmt_upper_limit_reg);
-
-       /* Enable the interrupt line. */
-       eepro_en_intline(ioaddr);
-
-       /* Switch back to Bank 0 */
-       eepro_sw2bank0(ioaddr);
-
-       /* Let RX and TX events to interrupt */
-       eepro_en_int(ioaddr);
-
-       /* clear all interrupts */
-       eepro_clear_int(ioaddr);
-
-       /* Initialize RCV */
-       outw(lp->rcv_lower_limit, ioaddr + RCV_BAR);
-       lp->rx_start = lp->rcv_lower_limit;
-       outw(lp->rcv_upper_limit | 0xfe, ioaddr + RCV_STOP);
-
-       /* Initialize XMT */
-       outw(lp->xmt_lower_limit, ioaddr + lp->xmt_bar);
-       lp->tx_start = lp->tx_end = lp->xmt_lower_limit;
-       lp->tx_last = 0;
-
-       /* Check for the i82595TX and i82595FX */
-       old8 = inb(ioaddr + 8);
-       outb(~old8, ioaddr + 8);
-
-       if ((temp_reg = inb(ioaddr + 8)) == old8) {
-               if (net_debug > 3)
-                       printk(KERN_DEBUG "i82595 detected!\n");
-               lp->version = LAN595;
-       }
-       else {
-               lp->version = LAN595TX;
-               outb(old8, ioaddr + 8);
-               old9 = inb(ioaddr + 9);
-
-               if (irqMask==ee_FX_INT2IRQ) {
-                       if (net_debug > 3) {
-                               printk(KERN_DEBUG "IrqMask: %#x\n",irqMask);
-                               printk(KERN_DEBUG "i82595FX detected!\n");
-                       }
-                       lp->version = LAN595FX;
-                       outb(old9, ioaddr + 9);
-                       if (dev->if_port != TPE) {      /* Hopefully, this will fix the
-                                                       problem of using Pentiums and
-                                                       pro/10 w/ BNC. */
-                               eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */
-                               temp_reg = inb(ioaddr + REG13);
-                               /* disable the full duplex mode since it is not
-                               applicable with the 10Base2 cable. */
-                               outb(temp_reg & ~(FDX | A_N_ENABLE), REG13);
-                               eepro_sw2bank0(ioaddr); /* be CAREFUL, BANK 0 now */
-                       }
-               }
-               else if (net_debug > 3) {
-                       printk(KERN_DEBUG "temp_reg: %#x  ~old9: %#x\n",temp_reg,((~old9)&0xff));
-                       printk(KERN_DEBUG "i82595TX detected!\n");
-               }
-       }
-
-       eepro_sel_reset(ioaddr);
-
-       netif_start_queue(dev);
-
-       if (net_debug > 3)
-               printk(KERN_DEBUG "%s: exiting eepro_open routine.\n", dev->name);
-
-       /* enabling rx */
-       eepro_en_rx(ioaddr);
-
-       return 0;
-}
-
-static void eepro_tx_timeout (struct net_device *dev)
-{
-       struct eepro_local *lp = netdev_priv(dev);
-       int ioaddr = dev->base_addr;
-
-       /* if (net_debug > 1) */
-       printk (KERN_ERR "%s: transmit timed out, %s?\n", dev->name,
-               "network cable problem");
-       /* This is not a duplicate. One message for the console,
-          one for the log file  */
-       printk (KERN_DEBUG "%s: transmit timed out, %s?\n", dev->name,
-               "network cable problem");
-       eepro_complete_selreset(ioaddr);
-}
-
-
-static netdev_tx_t eepro_send_packet(struct sk_buff *skb,
-                                    struct net_device *dev)
-{
-       struct eepro_local *lp = netdev_priv(dev);
-       unsigned long flags;
-       int ioaddr = dev->base_addr;
-       short length = skb->len;
-
-       if (net_debug > 5)
-               printk(KERN_DEBUG  "%s: entering eepro_send_packet routine.\n", dev->name);
-
-       if (length < ETH_ZLEN) {
-               if (skb_padto(skb, ETH_ZLEN))
-                       return NETDEV_TX_OK;
-               length = ETH_ZLEN;
-       }
-       netif_stop_queue (dev);
-
-       eepro_dis_int(ioaddr);
-       spin_lock_irqsave(&lp->lock, flags);
-
-       {
-               unsigned char *buf = skb->data;
-
-               if (hardware_send_packet(dev, buf, length))
-                       /* we won't wake queue here because we're out of space */
-                       dev->stats.tx_dropped++;
-               else {
-                       dev->stats.tx_bytes+=skb->len;
-                       netif_wake_queue(dev);
-               }
-
-       }
-
-       dev_kfree_skb (skb);
-
-       /* You might need to clean up and record Tx statistics here. */
-       /* dev->stats.tx_aborted_errors++; */
-
-       if (net_debug > 5)
-               printk(KERN_DEBUG "%s: exiting eepro_send_packet routine.\n", dev->name);
-
-       eepro_en_int(ioaddr);
-       spin_unlock_irqrestore(&lp->lock, flags);
-
-       return NETDEV_TX_OK;
-}
-
-
-/*     The typical workload of the driver:
-       Handle the network interface interrupts. */
-
-static irqreturn_t
-eepro_interrupt(int irq, void *dev_id)
-{
-       struct net_device *dev = dev_id;
-       struct eepro_local *lp;
-       int ioaddr, status, boguscount = 20;
-       int handled = 0;
-
-       lp = netdev_priv(dev);
-
-        spin_lock(&lp->lock);
-
-       if (net_debug > 5)
-               printk(KERN_DEBUG "%s: entering eepro_interrupt routine.\n", dev->name);
-
-       ioaddr = dev->base_addr;
-
-       while (((status = inb(ioaddr + STATUS_REG)) & (RX_INT|TX_INT)) && (boguscount--))
-       {
-               handled = 1;
-               if (status & RX_INT) {
-                       if (net_debug > 4)
-                               printk(KERN_DEBUG "%s: packet received interrupt.\n", dev->name);
-
-                       eepro_dis_int(ioaddr);
-
-                       /* Get the received packets */
-                       eepro_ack_rx(ioaddr);
-                       eepro_rx(dev);
-
-                       eepro_en_int(ioaddr);
-               }
-               if (status & TX_INT) {
-                       if (net_debug > 4)
-                               printk(KERN_DEBUG "%s: packet transmit interrupt.\n", dev->name);
-
-
-                       eepro_dis_int(ioaddr);
-
-                       /* Process the status of transmitted packets */
-                       eepro_ack_tx(ioaddr);
-                       eepro_transmit_interrupt(dev);
-
-                       eepro_en_int(ioaddr);
-               }
-       }
-
-       if (net_debug > 5)
-               printk(KERN_DEBUG "%s: exiting eepro_interrupt routine.\n", dev->name);
-
-       spin_unlock(&lp->lock);
-       return IRQ_RETVAL(handled);
-}
-
-static int eepro_close(struct net_device *dev)
-{
-       struct eepro_local *lp = netdev_priv(dev);
-       int ioaddr = dev->base_addr;
-       short temp_reg;
-
-       netif_stop_queue(dev);
-
-       eepro_sw2bank1(ioaddr); /* Switch back to Bank 1 */
-
-       /* Disable the physical interrupt line. */
-       temp_reg = inb(ioaddr + REG1);
-       outb(temp_reg & 0x7f, ioaddr + REG1);
-
-       eepro_sw2bank0(ioaddr); /* Switch back to Bank 0 */
-
-       /* Flush the Tx and disable Rx. */
-       outb(STOP_RCV_CMD, ioaddr);
-       lp->tx_start = lp->tx_end = lp->xmt_lower_limit;
-       lp->tx_last = 0;
-
-       /* Mask all the interrupts. */
-       eepro_dis_int(ioaddr);
-
-       /* clear all interrupts */
-       eepro_clear_int(ioaddr);
-
-       /* Reset the 82595 */
-       eepro_reset(ioaddr);
-
-       /* release the interrupt */
-       free_irq(dev->irq, dev);
-
-       /* Update the statistics here. What statistics? */
-
-       return 0;
-}
-
-/* Set or clear the multicast filter for this adaptor.
- */
-static void
-set_multicast_list(struct net_device *dev)
-{
-       struct eepro_local *lp = netdev_priv(dev);
-       short ioaddr = dev->base_addr;
-       unsigned short mode;
-       struct netdev_hw_addr *ha;
-       int mc_count = netdev_mc_count(dev);
-
-       if (dev->flags&(IFF_ALLMULTI|IFF_PROMISC) || mc_count > 63)
-       {
-               eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */
-               mode = inb(ioaddr + REG2);
-               outb(mode | PRMSC_Mode, ioaddr + REG2);
-               mode = inb(ioaddr + REG3);
-               outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */
-               eepro_sw2bank0(ioaddr); /* Return to BANK 0 now */
-       }
-
-       else if (mc_count == 0)
-       {
-               eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */
-               mode = inb(ioaddr + REG2);
-               outb(mode & 0xd6, ioaddr + REG2); /* Turn off Multi-IA and PRMSC_Mode bits */
-               mode = inb(ioaddr + REG3);
-               outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */
-               eepro_sw2bank0(ioaddr); /* Return to BANK 0 now */
-       }
-
-       else
-       {
-               unsigned short status, *eaddrs;
-               int i, boguscount = 0;
-
-               /* Disable RX and TX interrupts.  Necessary to avoid
-                  corruption of the HOST_ADDRESS_REG by interrupt
-                  service routines. */
-               eepro_dis_int(ioaddr);
-
-               eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */
-               mode = inb(ioaddr + REG2);
-               outb(mode | Multi_IA, ioaddr + REG2);
-               mode = inb(ioaddr + REG3);
-               outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */
-               eepro_sw2bank0(ioaddr); /* Return to BANK 0 now */
-               outw(lp->tx_end, ioaddr + HOST_ADDRESS_REG);
-               outw(MC_SETUP, ioaddr + IO_PORT);
-               outw(0, ioaddr + IO_PORT);
-               outw(0, ioaddr + IO_PORT);
-               outw(6 * (mc_count + 1), ioaddr + IO_PORT);
-
-               netdev_for_each_mc_addr(ha, dev) {
-                       eaddrs = (unsigned short *) ha->addr;
-                       outw(*eaddrs++, ioaddr + IO_PORT);
-                       outw(*eaddrs++, ioaddr + IO_PORT);
-                       outw(*eaddrs++, ioaddr + IO_PORT);
-               }
-
-               eaddrs = (unsigned short *) dev->dev_addr;
-               outw(eaddrs[0], ioaddr + IO_PORT);
-               outw(eaddrs[1], ioaddr + IO_PORT);
-               outw(eaddrs[2], ioaddr + IO_PORT);
-               outw(lp->tx_end, ioaddr + lp->xmt_bar);
-               outb(MC_SETUP, ioaddr);
-
-               /* Update the transmit queue */
-               i = lp->tx_end + XMT_HEADER + 6 * (mc_count + 1);
-
-               if (lp->tx_start != lp->tx_end)
-               {
-                       /* update the next address and the chain bit in the
-                          last packet */
-                       outw(lp->tx_last + XMT_CHAIN, ioaddr + HOST_ADDRESS_REG);
-                       outw(i, ioaddr + IO_PORT);
-                       outw(lp->tx_last + XMT_COUNT, ioaddr + HOST_ADDRESS_REG);
-                       status = inw(ioaddr + IO_PORT);
-                       outw(status | CHAIN_BIT, ioaddr + IO_PORT);
-                       lp->tx_end = i ;
-               }
-               else {
-                       lp->tx_start = lp->tx_end = i ;
-               }
-
-               /* Acknowledge that the MC setup is done */
-               do { /* We should be doing this in the eepro_interrupt()! */
-                       SLOW_DOWN;
-                       SLOW_DOWN;
-                       if (inb(ioaddr + STATUS_REG) & 0x08)
-                       {
-                               i = inb(ioaddr);
-                               outb(0x08, ioaddr + STATUS_REG);
-
-                               if (i & 0x20) { /* command ABORTed */
-                                       printk(KERN_NOTICE "%s: multicast setup failed.\n",
-                                               dev->name);
-                                       break;
-                               } else if ((i & 0x0f) == 0x03)  { /* MC-Done */
-                                       printk(KERN_DEBUG "%s: set Rx mode to %d address%s.\n",
-                                               dev->name, mc_count,
-                                               mc_count > 1 ? "es":"");
-                                       break;
-                               }
-                       }
-               } while (++boguscount < 100);
-
-               /* Re-enable RX and TX interrupts */
-               eepro_en_int(ioaddr);
-       }
-       if (lp->eepro == LAN595FX_10ISA) {
-               eepro_complete_selreset(ioaddr);
-       }
-       else
-               eepro_en_rx(ioaddr);
-}
-
-/* The horrible routine to read a word from the serial EEPROM. */
-/* IMPORTANT - the 82595 will be set to Bank 0 after the eeprom is read */
-
-/* The delay between EEPROM clock transitions. */
-#define eeprom_delay() { udelay(40); }
-#define EE_READ_CMD (6 << 6)
-
-static int
-read_eeprom(int ioaddr, int location, struct net_device *dev)
-{
-       int i;
-       unsigned short retval = 0;
-       struct eepro_local *lp = netdev_priv(dev);
-       short ee_addr = ioaddr + lp->eeprom_reg;
-       int read_cmd = location | EE_READ_CMD;
-       short ctrl_val = EECS ;
-
-       /* XXXX - black magic */
-               eepro_sw2bank1(ioaddr);
-               outb(0x00, ioaddr + STATUS_REG);
-       /* XXXX - black magic */
-
-       eepro_sw2bank2(ioaddr);
-       outb(ctrl_val, ee_addr);
-
-       /* Shift the read command bits out. */
-       for (i = 8; i >= 0; i--) {
-               short outval = (read_cmd & (1 << i)) ? ctrl_val | EEDI
-                       : ctrl_val;
-               outb(outval, ee_addr);
-               outb(outval | EESK, ee_addr);   /* EEPROM clock tick. */
-               eeprom_delay();
-               outb(outval, ee_addr);  /* Finish EEPROM a clock tick. */
-               eeprom_delay();
-       }
-       outb(ctrl_val, ee_addr);
-
-       for (i = 16; i > 0; i--) {
-               outb(ctrl_val | EESK, ee_addr);  eeprom_delay();
-               retval = (retval << 1) | ((inb(ee_addr) & EEDO) ? 1 : 0);
-               outb(ctrl_val, ee_addr);  eeprom_delay();
-       }
-
-       /* Terminate the EEPROM access. */
-       ctrl_val &= ~EECS;
-       outb(ctrl_val | EESK, ee_addr);
-       eeprom_delay();
-       outb(ctrl_val, ee_addr);
-       eeprom_delay();
-       eepro_sw2bank0(ioaddr);
-       return retval;
-}
-
-static int
-hardware_send_packet(struct net_device *dev, void *buf, short length)
-{
-       struct eepro_local *lp = netdev_priv(dev);
-       short ioaddr = dev->base_addr;
-       unsigned status, tx_available, last, end;
-
-       if (net_debug > 5)
-               printk(KERN_DEBUG "%s: entering hardware_send_packet routine.\n", dev->name);
-
-       /* determine how much of the transmit buffer space is available */
-       if (lp->tx_end > lp->tx_start)
-               tx_available = lp->xmt_ram - (lp->tx_end - lp->tx_start);
-       else if (lp->tx_end < lp->tx_start)
-               tx_available = lp->tx_start - lp->tx_end;
-       else tx_available = lp->xmt_ram;
-
-       if (((((length + 3) >> 1) << 1) + 2*XMT_HEADER) >= tx_available) {
-               /* No space available ??? */
-               return 1;
-               }
-
-               last = lp->tx_end;
-               end = last + (((length + 3) >> 1) << 1) + XMT_HEADER;
-
-       if (end >= lp->xmt_upper_limit + 2) { /* the transmit buffer is wrapped around */
-               if ((lp->xmt_upper_limit + 2 - last) <= XMT_HEADER) {
-                               /* Arrrr!!!, must keep the xmt header together,
-                               several days were lost to chase this one down. */
-                       last = lp->xmt_lower_limit;
-                               end = last + (((length + 3) >> 1) << 1) + XMT_HEADER;
-                       }
-               else end = lp->xmt_lower_limit + (end -
-                                               lp->xmt_upper_limit + 2);
-               }
-
-               outw(last, ioaddr + HOST_ADDRESS_REG);
-               outw(XMT_CMD, ioaddr + IO_PORT);
-               outw(0, ioaddr + IO_PORT);
-               outw(end, ioaddr + IO_PORT);
-               outw(length, ioaddr + IO_PORT);
-
-               if (lp->version == LAN595)
-                       outsw(ioaddr + IO_PORT, buf, (length + 3) >> 1);
-               else {  /* LAN595TX or LAN595FX, capable of 32-bit I/O processing */
-                       unsigned short temp = inb(ioaddr + INT_MASK_REG);
-                       outb(temp | IO_32_BIT, ioaddr + INT_MASK_REG);
-                       outsl(ioaddr + IO_PORT_32_BIT, buf, (length + 3) >> 2);
-                       outb(temp & ~(IO_32_BIT), ioaddr + INT_MASK_REG);
-               }
-
-               /* A dummy read to flush the DRAM write pipeline */
-               status = inw(ioaddr + IO_PORT);
-
-               if (lp->tx_start == lp->tx_end) {
-               outw(last, ioaddr + lp->xmt_bar);
-                       outb(XMT_CMD, ioaddr);
-                       lp->tx_start = last;   /* I don't like to change tx_start here */
-               }
-               else {
-                       /* update the next address and the chain bit in the
-                       last packet */
-
-                       if (lp->tx_end != last) {
-                               outw(lp->tx_last + XMT_CHAIN, ioaddr + HOST_ADDRESS_REG);
-                               outw(last, ioaddr + IO_PORT);
-                       }
-
-                       outw(lp->tx_last + XMT_COUNT, ioaddr + HOST_ADDRESS_REG);
-                       status = inw(ioaddr + IO_PORT);
-                       outw(status | CHAIN_BIT, ioaddr + IO_PORT);
-
-                       /* Continue the transmit command */
-                       outb(RESUME_XMT_CMD, ioaddr);
-               }
-
-               lp->tx_last = last;
-               lp->tx_end = end;
-
-               if (net_debug > 5)
-                       printk(KERN_DEBUG "%s: exiting hardware_send_packet routine.\n", dev->name);
-
-       return 0;
-}
-
-static void
-eepro_rx(struct net_device *dev)
-{
-       struct eepro_local *lp = netdev_priv(dev);
-       short ioaddr = dev->base_addr;
-       short boguscount = 20;
-       short rcv_car = lp->rx_start;
-       unsigned rcv_event, rcv_status, rcv_next_frame, rcv_size;
-
-       if (net_debug > 5)
-               printk(KERN_DEBUG "%s: entering eepro_rx routine.\n", dev->name);
-
-       /* Set the read pointer to the start of the RCV */
-       outw(rcv_car, ioaddr + HOST_ADDRESS_REG);
-
-       rcv_event = inw(ioaddr + IO_PORT);
-
-       while (rcv_event == RCV_DONE) {
-
-               rcv_status = inw(ioaddr + IO_PORT);
-               rcv_next_frame = inw(ioaddr + IO_PORT);
-               rcv_size = inw(ioaddr + IO_PORT);
-
-               if ((rcv_status & (RX_OK | RX_ERROR)) == RX_OK) {
-
-                       /* Malloc up new buffer. */
-                       struct sk_buff *skb;
-
-                       dev->stats.rx_bytes+=rcv_size;
-                       rcv_size &= 0x3fff;
-                       skb = dev_alloc_skb(rcv_size+5);
-                       if (skb == NULL) {
-                               printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
-                               dev->stats.rx_dropped++;
-                               rcv_car = lp->rx_start + RCV_HEADER + rcv_size;
-                               lp->rx_start = rcv_next_frame;
-                               outw(rcv_next_frame, ioaddr + HOST_ADDRESS_REG);
-
-                               break;
-                       }
-                       skb_reserve(skb,2);
-
-                       if (lp->version == LAN595)
-                               insw(ioaddr+IO_PORT, skb_put(skb,rcv_size), (rcv_size + 3) >> 1);
-                       else { /* LAN595TX or LAN595FX, capable of 32-bit I/O processing */
-                               unsigned short temp = inb(ioaddr + INT_MASK_REG);
-                               outb(temp | IO_32_BIT, ioaddr + INT_MASK_REG);
-                               insl(ioaddr+IO_PORT_32_BIT, skb_put(skb,rcv_size),
-                                       (rcv_size + 3) >> 2);
-                               outb(temp & ~(IO_32_BIT), ioaddr + INT_MASK_REG);
-                       }
-
-                       skb->protocol = eth_type_trans(skb,dev);
-                       netif_rx(skb);
-                       dev->stats.rx_packets++;
-               }
-
-               else { /* Not sure will ever reach here,
-                       I set the 595 to discard bad received frames */
-                       dev->stats.rx_errors++;
-
-                       if (rcv_status & 0x0100)
-                               dev->stats.rx_over_errors++;
-
-                       else if (rcv_status & 0x0400)
-                               dev->stats.rx_frame_errors++;
-
-                       else if (rcv_status & 0x0800)
-                               dev->stats.rx_crc_errors++;
-
-                       printk(KERN_DEBUG "%s: event = %#x, status = %#x, next = %#x, size = %#x\n",
-                               dev->name, rcv_event, rcv_status, rcv_next_frame, rcv_size);
-               }
-
-               if (rcv_status & 0x1000)
-                       dev->stats.rx_length_errors++;
-
-               rcv_car = lp->rx_start + RCV_HEADER + rcv_size;
-               lp->rx_start = rcv_next_frame;
-
-               if (--boguscount == 0)
-                       break;
-
-               outw(rcv_next_frame, ioaddr + HOST_ADDRESS_REG);
-               rcv_event = inw(ioaddr + IO_PORT);
-
-       }
-       if (rcv_car == 0)
-               rcv_car = lp->rcv_upper_limit | 0xff;
-
-       outw(rcv_car - 1, ioaddr + RCV_STOP);
-
-       if (net_debug > 5)
-               printk(KERN_DEBUG "%s: exiting eepro_rx routine.\n", dev->name);
-}
-
-static void
-eepro_transmit_interrupt(struct net_device *dev)
-{
-       struct eepro_local *lp = netdev_priv(dev);
-       short ioaddr = dev->base_addr;
-       short boguscount = 25;
-       short xmt_status;
-
-       while ((lp->tx_start != lp->tx_end) && boguscount--) {
-
-               outw(lp->tx_start, ioaddr + HOST_ADDRESS_REG);
-               xmt_status = inw(ioaddr+IO_PORT);
-
-               if (!(xmt_status & TX_DONE_BIT))
-                               break;
-
-               xmt_status = inw(ioaddr+IO_PORT);
-               lp->tx_start = inw(ioaddr+IO_PORT);
-
-               netif_wake_queue (dev);
-
-               if (xmt_status & TX_OK)
-                       dev->stats.tx_packets++;
-               else {
-                       dev->stats.tx_errors++;
-                       if (xmt_status & 0x0400) {
-                               dev->stats.tx_carrier_errors++;
-                               printk(KERN_DEBUG "%s: carrier error\n",
-                                       dev->name);
-                               printk(KERN_DEBUG "%s: XMT status = %#x\n",
-                                       dev->name, xmt_status);
-                       }
-                       else {
-                               printk(KERN_DEBUG "%s: XMT status = %#x\n",
-                                       dev->name, xmt_status);
-                               printk(KERN_DEBUG "%s: XMT status = %#x\n",
-                                       dev->name, xmt_status);
-                       }
-               }
-               if (xmt_status & 0x000f) {
-                       dev->stats.collisions += (xmt_status & 0x000f);
-               }
-
-               if ((xmt_status & 0x0040) == 0x0) {
-                       dev->stats.tx_heartbeat_errors++;
-               }
-       }
-}
-
-static int eepro_ethtool_get_settings(struct net_device *dev,
-                                       struct ethtool_cmd *cmd)
-{
-       struct eepro_local      *lp = netdev_priv(dev);
-
-       cmd->supported =        SUPPORTED_10baseT_Half |
-                               SUPPORTED_10baseT_Full |
-                               SUPPORTED_Autoneg;
-       cmd->advertising =      ADVERTISED_10baseT_Half |
-                               ADVERTISED_10baseT_Full |
-                               ADVERTISED_Autoneg;
-
-       if (GetBit(lp->word[5], ee_PortTPE)) {
-               cmd->supported |= SUPPORTED_TP;
-               cmd->advertising |= ADVERTISED_TP;
-       }
-       if (GetBit(lp->word[5], ee_PortBNC)) {
-               cmd->supported |= SUPPORTED_BNC;
-               cmd->advertising |= ADVERTISED_BNC;
-       }
-       if (GetBit(lp->word[5], ee_PortAUI)) {
-               cmd->supported |= SUPPORTED_AUI;
-               cmd->advertising |= ADVERTISED_AUI;
-       }
-
-       ethtool_cmd_speed_set(cmd, SPEED_10);
-
-       if (dev->if_port == TPE && lp->word[1] & ee_Duplex) {
-               cmd->duplex = DUPLEX_FULL;
-       }
-       else {
-               cmd->duplex = DUPLEX_HALF;
-       }
-
-       cmd->port = dev->if_port;
-       cmd->phy_address = dev->base_addr;
-       cmd->transceiver = XCVR_INTERNAL;
-
-       if (lp->word[0] & ee_AutoNeg) {
-               cmd->autoneg = 1;
-       }
-
-       return 0;
-}
-
-static void eepro_ethtool_get_drvinfo(struct net_device *dev,
-                                       struct ethtool_drvinfo *drvinfo)
-{
-       strcpy(drvinfo->driver, DRV_NAME);
-       strcpy(drvinfo->version, DRV_VERSION);
-       sprintf(drvinfo->bus_info, "ISA 0x%lx", dev->base_addr);
-}
-
-static const struct ethtool_ops eepro_ethtool_ops = {
-       .get_settings   = eepro_ethtool_get_settings,
-       .get_drvinfo    = eepro_ethtool_get_drvinfo,
-};
-
-#ifdef MODULE
-
-#define MAX_EEPRO 8
-static struct net_device *dev_eepro[MAX_EEPRO];
-
-static int io[MAX_EEPRO] = {
-  [0 ... MAX_EEPRO-1] = -1
-};
-static int irq[MAX_EEPRO];
-static int mem[MAX_EEPRO] = {  /* Size of the rx buffer in KB */
-  [0 ... MAX_EEPRO-1] = RCV_DEFAULT_RAM/1024
-};
-static int autodetect;
-
-static int n_eepro;
-/* For linux 2.1.xx */
-
-MODULE_AUTHOR("Pascal Dupuis and others");
-MODULE_DESCRIPTION("Intel i82595 ISA EtherExpressPro10/10+ driver");
-MODULE_LICENSE("GPL");
-
-module_param_array(io, int, NULL, 0);
-module_param_array(irq, int, NULL, 0);
-module_param_array(mem, int, NULL, 0);
-module_param(autodetect, int, 0);
-MODULE_PARM_DESC(io, "EtherExpress Pro/10 I/O base address(es)");
-MODULE_PARM_DESC(irq, "EtherExpress Pro/10 IRQ number(s)");
-MODULE_PARM_DESC(mem, "EtherExpress Pro/10 Rx buffer size(es) in kB (3-29)");
-MODULE_PARM_DESC(autodetect, "EtherExpress Pro/10 force board(s) detection (0-1)");
-
-int __init init_module(void)
-{
-       struct net_device *dev;
-       int i;
-       if (io[0] == -1 && autodetect == 0) {
-               printk(KERN_WARNING "eepro_init_module: Probe is very dangerous in ISA boards!\n");
-               printk(KERN_WARNING "eepro_init_module: Please add \"autodetect=1\" to force probe\n");
-               return -ENODEV;
-       }
-       else if (autodetect) {
-               /* if autodetect is set then we must force detection */
-               for (i = 0; i < MAX_EEPRO; i++) {
-                       io[i] = 0;
-               }
-
-               printk(KERN_INFO "eepro_init_module: Auto-detecting boards (May God protect us...)\n");
-       }
-
-       for (i = 0; i < MAX_EEPRO && io[i] != -1; i++) {
-               dev = alloc_etherdev(sizeof(struct eepro_local));
-               if (!dev)
-                       break;
-
-               dev->mem_end = mem[i];
-               dev->base_addr = io[i];
-               dev->irq = irq[i];
-
-               if (do_eepro_probe(dev) == 0) {
-                       dev_eepro[n_eepro++] = dev;
-                       continue;
-               }
-               free_netdev(dev);
-               break;
-       }
-
-       if (n_eepro)
-               printk(KERN_INFO "%s", version);
-
-       return n_eepro ? 0 : -ENODEV;
-}
-
-void __exit
-cleanup_module(void)
-{
-       int i;
-
-       for (i=0; i<n_eepro; i++) {
-               struct net_device *dev = dev_eepro[i];
-               unregister_netdev(dev);
-               release_region(dev->base_addr, EEPRO_IO_EXTENT);
-               free_netdev(dev);
-       }
-}
-#endif /* MODULE */
diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c
deleted file mode 100644 (file)
index a192285..0000000
+++ /dev/null
@@ -1,1720 +0,0 @@
-/* Intel EtherExpress 16 device driver for Linux
- *
- * Written by John Sullivan, 1995
- *  based on original code by Donald Becker, with changes by
- *  Alan Cox and Pauline Middelink.
- *
- * Support for 8-bit mode by Zoltan Szilagyi <zoltans@cs.arizona.edu>
- *
- * Many modifications, and currently maintained, by
- *  Philip Blundell <philb@gnu.org>
- * Added the Compaq LTE  Alan Cox <alan@lxorguk.ukuu.org.uk>
- * Added MCA support Adam Fritzler
- *
- * Note - this driver is experimental still - it has problems on faster
- * machines. Someone needs to sit down and go through it line by line with
- * a databook...
- */
-
-/* The EtherExpress 16 is a fairly simple card, based on a shared-memory
- * design using the i82586 Ethernet coprocessor.  It bears no relationship,
- * as far as I know, to the similarly-named "EtherExpress Pro" range.
- *
- * Historically, Linux support for these cards has been very bad.  However,
- * things seem to be getting better slowly.
- */
-
-/* If your card is confused about what sort of interface it has (eg it
- * persistently reports "10baseT" when none is fitted), running 'SOFTSET /BART'
- * or 'SOFTSET /LISA' from DOS seems to help.
- */
-
-/* Here's the scoop on memory mapping.
- *
- * There are three ways to access EtherExpress card memory: either using the
- * shared-memory mapping, or using PIO through the dataport, or using PIO
- * through the "shadow memory" ports.
- *
- * The shadow memory system works by having the card map some of its memory
- * as follows:
- *
- * (the low five bits of the SMPTR are ignored)
- *
- *  base+0x4000..400f      memory at SMPTR+0..15
- *  base+0x8000..800f      memory at SMPTR+16..31
- *  base+0xc000..c007      dubious stuff (memory at SMPTR+16..23 apparently)
- *  base+0xc008..c00f      memory at 0x0008..0x000f
- *
- * This last set (the one at c008) is particularly handy because the SCB
- * lives at 0x0008.  So that set of ports gives us easy random access to data
- * in the SCB without having to mess around setting up pointers and the like.
- * We always use this method to access the SCB (via the scb_xx() functions).
- *
- * Dataport access works by aiming the appropriate (read or write) pointer
- * at the first address you're interested in, and then reading or writing from
- * the dataport.  The pointers auto-increment after each transfer.  We use
- * this for data transfer.
- *
- * We don't use the shared-memory system because it allegedly doesn't work on
- * all cards, and because it's a bit more prone to go wrong (it's one more
- * thing to configure...).
- */
-
-/* Known bugs:
- *
- * - The card seems to want to give us two interrupts every time something
- *   happens, where just one would be better.
- */
-
-/*
- *
- * Note by Zoltan Szilagyi 10-12-96:
- *
- * I've succeeded in eliminating the "CU wedged" messages, and hence the
- * lockups, which were only occurring with cards running in 8-bit mode ("force
- * 8-bit operation" in Intel's SoftSet utility). This version of the driver
- * sets the 82586 and the ASIC to 8-bit mode at startup; it also stops the
- * CU before submitting a packet for transmission, and then restarts it as soon
- * as the process of handing the packet is complete. This is definitely an
- * unnecessary slowdown if the card is running in 16-bit mode; therefore one
- * should detect 16-bit vs 8-bit mode from the EEPROM settings and act
- * accordingly. In 8-bit mode with this bugfix I'm getting about 150 K/s for
- * ftp's, which is significantly better than I get in DOS, so the overhead of
- * stopping and restarting the CU with each transmit is not prohibitive in
- * practice.
- *
- * Update by David Woodhouse 11/5/99:
- *
- * I've seen "CU wedged" messages in 16-bit mode, on the Alpha architecture.
- * I assume that this is because 16-bit accesses are actually handled as two
- * 8-bit accesses.
- */
-
-#ifdef __alpha__
-#define LOCKUP16 1
-#endif
-#ifndef LOCKUP16
-#define LOCKUP16 0
-#endif
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/string.h>
-#include <linux/in.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/mca-legacy.h>
-#include <linux/spinlock.h>
-#include <linux/bitops.h>
-#include <linux/jiffies.h>
-
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#ifndef NET_DEBUG
-#define NET_DEBUG 4
-#endif
-
-#include "eexpress.h"
-
-#define EEXP_IO_EXTENT  16
-
-/*
- * Private data declarations
- */
-
-struct net_local
-{
-       unsigned long last_tx;       /* jiffies when last transmit started */
-       unsigned long init_time;     /* jiffies when eexp_hw_init586 called */
-       unsigned short rx_first;     /* first rx buf, same as RX_BUF_START */
-       unsigned short rx_last;      /* last rx buf */
-       unsigned short rx_ptr;       /* first rx buf to look at */
-       unsigned short tx_head;      /* next free tx buf */
-       unsigned short tx_reap;      /* first in-use tx buf */
-       unsigned short tx_tail;      /* previous tx buf to tx_head */
-       unsigned short tx_link;      /* last known-executing tx buf */
-       unsigned short last_tx_restart;   /* set to tx_link when we
-                                            restart the CU */
-       unsigned char started;
-       unsigned short rx_buf_start;
-       unsigned short rx_buf_end;
-       unsigned short num_tx_bufs;
-       unsigned short num_rx_bufs;
-       unsigned char width;         /* 0 for 16bit, 1 for 8bit */
-       unsigned char was_promisc;
-       unsigned char old_mc_count;
-       spinlock_t lock;
-};
-
-/* This is the code and data that is downloaded to the EtherExpress card's
- * memory at boot time.
- */
-
-static unsigned short start_code[] = {
-/* 0x0000 */
-       0x0001,                 /* ISCP: busy - cleared after reset */
-       0x0008,0x0000,0x0000,   /* offset,address (lo,hi) of SCB */
-
-       0x0000,0x0000,          /* SCB: status, commands */
-       0x0000,0x0000,          /* links to first command block,
-                                  first receive descriptor */
-       0x0000,0x0000,          /* CRC error, alignment error counts */
-       0x0000,0x0000,          /* out of resources, overrun error counts */
-
-       0x0000,0x0000,          /* pad */
-       0x0000,0x0000,
-
-/* 0x20 -- start of 82586 CU program */
-#define CONF_LINK 0x20
-       0x0000,Cmd_Config,
-       0x0032,                 /* link to next command */
-       0x080c,                 /* 12 bytes follow : fifo threshold=8 */
-       0x2e40,                 /* don't rx bad frames
-                                * SRDY/ARDY => ext. sync. : preamble len=8
-                                * take addresses from data buffers
-                                * 6 bytes/address
-                                */
-       0x6000,                 /* default backoff method & priority
-                                * interframe spacing = 0x60 */
-       0xf200,                 /* slot time=0x200
-                                * max collision retry = 0xf */
-#define CONF_PROMISC  0x2e
-       0x0000,                 /* no HDLC : normal CRC : enable broadcast
-                                * disable promiscuous/multicast modes */
-       0x003c,                 /* minimum frame length = 60 octets) */
-
-       0x0000,Cmd_SetAddr,
-       0x003e,                 /* link to next command */
-#define CONF_HWADDR  0x38
-       0x0000,0x0000,0x0000,   /* hardware address placed here */
-
-       0x0000,Cmd_MCast,
-       0x0076,                 /* link to next command */
-#define CONF_NR_MULTICAST 0x44
-       0x0000,                 /* number of bytes in multicast address(es) */
-#define CONF_MULTICAST 0x46
-       0x0000, 0x0000, 0x0000, /* some addresses */
-       0x0000, 0x0000, 0x0000,
-       0x0000, 0x0000, 0x0000,
-       0x0000, 0x0000, 0x0000,
-       0x0000, 0x0000, 0x0000,
-       0x0000, 0x0000, 0x0000,
-       0x0000, 0x0000, 0x0000,
-       0x0000, 0x0000, 0x0000,
-
-#define CONF_DIAG_RESULT  0x76
-       0x0000, Cmd_Diag,
-       0x007c,                 /* link to next command */
-
-       0x0000,Cmd_TDR|Cmd_INT,
-       0x0084,
-#define CONF_TDR_RESULT  0x82
-       0x0000,
-
-       0x0000,Cmd_END|Cmd_Nop, /* end of configure sequence */
-       0x0084                  /* dummy link */
-};
-
-/* maps irq number to EtherExpress magic value */
-static char irqrmap[] = { 0,0,1,2,3,4,0,0,0,1,5,6,0,0,0,0 };
-
-#ifdef CONFIG_MCA_LEGACY
-/* mapping of the first four bits of the second POS register */
-static unsigned short mca_iomap[] = {
-       0x270, 0x260, 0x250, 0x240, 0x230, 0x220, 0x210, 0x200,
-       0x370, 0x360, 0x350, 0x340, 0x330, 0x320, 0x310, 0x300
-};
-/* bits 5-7 of the second POS register */
-static char mca_irqmap[] = { 12, 9, 3, 4, 5, 10, 11, 15 };
-#endif
-
-/*
- * Prototypes for Linux interface
- */
-
-static int eexp_open(struct net_device *dev);
-static int eexp_close(struct net_device *dev);
-static void eexp_timeout(struct net_device *dev);
-static netdev_tx_t eexp_xmit(struct sk_buff *buf,
-                            struct net_device *dev);
-
-static irqreturn_t eexp_irq(int irq, void *dev_addr);
-static void eexp_set_multicast(struct net_device *dev);
-
-/*
- * Prototypes for hardware access functions
- */
-
-static void eexp_hw_rx_pio(struct net_device *dev);
-static void eexp_hw_tx_pio(struct net_device *dev, unsigned short *buf,
-                      unsigned short len);
-static int eexp_hw_probe(struct net_device *dev,unsigned short ioaddr);
-static unsigned short eexp_hw_readeeprom(unsigned short ioaddr,
-                                        unsigned char location);
-
-static unsigned short eexp_hw_lasttxstat(struct net_device *dev);
-static void eexp_hw_txrestart(struct net_device *dev);
-
-static void eexp_hw_txinit    (struct net_device *dev);
-static void eexp_hw_rxinit    (struct net_device *dev);
-
-static void eexp_hw_init586   (struct net_device *dev);
-static void eexp_setup_filter (struct net_device *dev);
-
-static char *eexp_ifmap[]={"AUI", "BNC", "RJ45"};
-enum eexp_iftype {AUI=0, BNC=1, TPE=2};
-
-#define STARTED_RU      2
-#define STARTED_CU      1
-
-/*
- * Primitive hardware access functions.
- */
-
-static inline unsigned short scb_status(struct net_device *dev)
-{
-       return inw(dev->base_addr + 0xc008);
-}
-
-static inline unsigned short scb_rdcmd(struct net_device *dev)
-{
-       return inw(dev->base_addr + 0xc00a);
-}
-
-static inline void scb_command(struct net_device *dev, unsigned short cmd)
-{
-       outw(cmd, dev->base_addr + 0xc00a);
-}
-
-static inline void scb_wrcbl(struct net_device *dev, unsigned short val)
-{
-       outw(val, dev->base_addr + 0xc00c);
-}
-
-static inline void scb_wrrfa(struct net_device *dev, unsigned short val)
-{
-       outw(val, dev->base_addr + 0xc00e);
-}
-
-static inline void set_loopback(struct net_device *dev)
-{
-       outb(inb(dev->base_addr + Config) | 2, dev->base_addr + Config);
-}
-
-static inline void clear_loopback(struct net_device *dev)
-{
-       outb(inb(dev->base_addr + Config) & ~2, dev->base_addr + Config);
-}
-
-static inline unsigned short int SHADOW(short int addr)
-{
-       addr &= 0x1f;
-       if (addr > 0xf) addr += 0x3ff0;
-       return addr + 0x4000;
-}
-
-/*
- * Linux interface
- */
-
-/*
- * checks for presence of EtherExpress card
- */
-
-static int __init do_express_probe(struct net_device *dev)
-{
-       unsigned short *port;
-       static unsigned short ports[] = { 0x240,0x300,0x310,0x270,0x320,0x340,0 };
-       unsigned short ioaddr = dev->base_addr;
-       int dev_irq = dev->irq;
-       int err;
-
-       dev->if_port = 0xff; /* not set */
-
-#ifdef CONFIG_MCA_LEGACY
-       if (MCA_bus) {
-               int slot = 0;
-
-               /*
-                * Only find one card at a time.  Subsequent calls
-                * will find others, however, proper multicard MCA
-                * probing and setup can't be done with the
-                * old-style Space.c init routines.  -- ASF
-                */
-               while (slot != MCA_NOTFOUND) {
-                       int pos0, pos1;
-
-                       slot = mca_find_unused_adapter(0x628B, slot);
-                       if (slot == MCA_NOTFOUND)
-                               break;
-
-                       pos0 = mca_read_stored_pos(slot, 2);
-                       pos1 = mca_read_stored_pos(slot, 3);
-                       ioaddr = mca_iomap[pos1&0xf];
-
-                       dev->irq = mca_irqmap[(pos1>>4)&0x7];
-
-                       /*
-                        * XXX: Transceiver selection is done
-                        * differently on the MCA version.
-                        * How to get it to select something
-                        * other than external/AUI is currently
-                        * unknown.  This code is just for looks. -- ASF
-                        */
-                       if ((pos0 & 0x7) == 0x1)
-                               dev->if_port = AUI;
-                       else if ((pos0 & 0x7) == 0x5) {
-                               if (pos1 & 0x80)
-                                       dev->if_port = BNC;
-                               else
-                                       dev->if_port = TPE;
-                       }
-
-                       mca_set_adapter_name(slot, "Intel EtherExpress 16 MCA");
-                       mca_set_adapter_procfn(slot, NULL, dev);
-                       mca_mark_as_used(slot);
-
-                       break;
-               }
-       }
-#endif
-       if (ioaddr&0xfe00) {
-               if (!request_region(ioaddr, EEXP_IO_EXTENT, "EtherExpress"))
-                       return -EBUSY;
-               err = eexp_hw_probe(dev,ioaddr);
-               release_region(ioaddr, EEXP_IO_EXTENT);
-               return err;
-       } else if (ioaddr)
-               return -ENXIO;
-
-       for (port=&ports[0] ; *port ; port++ )
-       {
-               unsigned short sum = 0;
-               int i;
-               if (!request_region(*port, EEXP_IO_EXTENT, "EtherExpress"))
-                       continue;
-               for ( i=0 ; i<4 ; i++ )
-               {
-                       unsigned short t;
-                       t = inb(*port + ID_PORT);
-                       sum |= (t>>4) << ((t & 0x03)<<2);
-               }
-               if (sum==0xbaba && !eexp_hw_probe(dev,*port)) {
-                       release_region(*port, EEXP_IO_EXTENT);
-                       return 0;
-               }
-               release_region(*port, EEXP_IO_EXTENT);
-               dev->irq = dev_irq;
-       }
-       return -ENODEV;
-}
-
-#ifndef MODULE
-struct net_device * __init express_probe(int unit)
-{
-       struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
-       int err;
-
-       if (!dev)
-               return ERR_PTR(-ENOMEM);
-
-       sprintf(dev->name, "eth%d", unit);
-       netdev_boot_setup_check(dev);
-
-       err = do_express_probe(dev);
-       if (!err)
-               return dev;
-       free_netdev(dev);
-       return ERR_PTR(err);
-}
-#endif
-
-/*
- * open and initialize the adapter, ready for use
- */
-
-static int eexp_open(struct net_device *dev)
-{
-       int ret;
-       unsigned short ioaddr = dev->base_addr;
-       struct net_local *lp = netdev_priv(dev);
-
-#if NET_DEBUG > 6
-       printk(KERN_DEBUG "%s: eexp_open()\n", dev->name);
-#endif
-
-       if (!dev->irq || !irqrmap[dev->irq])
-               return -ENXIO;
-
-       ret = request_irq(dev->irq, eexp_irq, 0, dev->name, dev);
-       if (ret)
-               return ret;
-
-       if (!request_region(ioaddr, EEXP_IO_EXTENT, "EtherExpress")) {
-               printk(KERN_WARNING "EtherExpress io port %x, is busy.\n"
-                       , ioaddr);
-               goto err_out1;
-       }
-       if (!request_region(ioaddr+0x4000, EEXP_IO_EXTENT, "EtherExpress shadow")) {
-               printk(KERN_WARNING "EtherExpress io port %x, is busy.\n"
-                       , ioaddr+0x4000);
-               goto err_out2;
-       }
-       if (!request_region(ioaddr+0x8000, EEXP_IO_EXTENT, "EtherExpress shadow")) {
-               printk(KERN_WARNING "EtherExpress io port %x, is busy.\n"
-                       , ioaddr+0x8000);
-               goto err_out3;
-       }
-       if (!request_region(ioaddr+0xc000, EEXP_IO_EXTENT, "EtherExpress shadow")) {
-               printk(KERN_WARNING "EtherExpress io port %x, is busy.\n"
-                       , ioaddr+0xc000);
-               goto err_out4;
-       }
-
-       if (lp->width) {
-               printk("%s: forcing ASIC to 8-bit mode\n", dev->name);
-               outb(inb(dev->base_addr+Config)&~4, dev->base_addr+Config);
-       }
-
-       eexp_hw_init586(dev);
-       netif_start_queue(dev);
-#if NET_DEBUG > 6
-       printk(KERN_DEBUG "%s: leaving eexp_open()\n", dev->name);
-#endif
-       return 0;
-
-       err_out4:
-               release_region(ioaddr+0x8000, EEXP_IO_EXTENT);
-       err_out3:
-               release_region(ioaddr+0x4000, EEXP_IO_EXTENT);
-       err_out2:
-               release_region(ioaddr, EEXP_IO_EXTENT);
-       err_out1:
-               free_irq(dev->irq, dev);
-               return -EBUSY;
-}
-
-/*
- * close and disable the interface, leaving the 586 in reset.
- */
-
-static int eexp_close(struct net_device *dev)
-{
-       unsigned short ioaddr = dev->base_addr;
-       struct net_local *lp = netdev_priv(dev);
-
-       int irq = dev->irq;
-
-       netif_stop_queue(dev);
-
-       outb(SIRQ_dis|irqrmap[irq],ioaddr+SET_IRQ);
-       lp->started = 0;
-       scb_command(dev, SCB_CUsuspend|SCB_RUsuspend);
-       outb(0,ioaddr+SIGNAL_CA);
-       free_irq(irq,dev);
-       outb(i586_RST,ioaddr+EEPROM_Ctrl);
-       release_region(ioaddr, EEXP_IO_EXTENT);
-       release_region(ioaddr+0x4000, 16);
-       release_region(ioaddr+0x8000, 16);
-       release_region(ioaddr+0xc000, 16);
-
-       return 0;
-}
-
-/*
- * This gets called when a higher level thinks we are broken.  Check that
- * nothing has become jammed in the CU.
- */
-
-static void unstick_cu(struct net_device *dev)
-{
-       struct net_local *lp = netdev_priv(dev);
-       unsigned short ioaddr = dev->base_addr;
-
-       if (lp->started)
-       {
-               if (time_after(jiffies, dev_trans_start(dev) + HZ/2))
-               {
-                       if (lp->tx_link==lp->last_tx_restart)
-                       {
-                               unsigned short boguscount=200,rsst;
-                               printk(KERN_WARNING "%s: Retransmit timed out, status %04x, resetting...\n",
-                                      dev->name, scb_status(dev));
-                               eexp_hw_txinit(dev);
-                               lp->last_tx_restart = 0;
-                               scb_wrcbl(dev, lp->tx_link);
-                               scb_command(dev, SCB_CUstart);
-                               outb(0,ioaddr+SIGNAL_CA);
-                               while (!SCB_complete(rsst=scb_status(dev)))
-                               {
-                                       if (!--boguscount)
-                                       {
-                                               boguscount=200;
-                                               printk(KERN_WARNING "%s: Reset timed out status %04x, retrying...\n",
-                                                      dev->name,rsst);
-                                               scb_wrcbl(dev, lp->tx_link);
-                                               scb_command(dev, SCB_CUstart);
-                                               outb(0,ioaddr+SIGNAL_CA);
-                                       }
-                               }
-                               netif_wake_queue(dev);
-                       }
-                       else
-                       {
-                               unsigned short status = scb_status(dev);
-                               if (SCB_CUdead(status))
-                               {
-                                       unsigned short txstatus = eexp_hw_lasttxstat(dev);
-                                       printk(KERN_WARNING "%s: Transmit timed out, CU not active status %04x %04x, restarting...\n",
-                                              dev->name, status, txstatus);
-                                       eexp_hw_txrestart(dev);
-                               }
-                               else
-                               {
-                                       unsigned short txstatus = eexp_hw_lasttxstat(dev);
-                                       if (netif_queue_stopped(dev) && !txstatus)
-                                       {
-                                               printk(KERN_WARNING "%s: CU wedged, status %04x %04x, resetting...\n",
-                                                      dev->name,status,txstatus);
-                                               eexp_hw_init586(dev);
-                                               netif_wake_queue(dev);
-                                       }
-                                       else
-                                       {
-                                               printk(KERN_WARNING "%s: transmit timed out\n", dev->name);
-                                       }
-                               }
-                       }
-               }
-       }
-       else
-       {
-               if (time_after(jiffies, lp->init_time + 10))
-               {
-                       unsigned short status = scb_status(dev);
-                       printk(KERN_WARNING "%s: i82586 startup timed out, status %04x, resetting...\n",
-                              dev->name, status);
-                       eexp_hw_init586(dev);
-                       netif_wake_queue(dev);
-               }
-       }
-}
-
-static void eexp_timeout(struct net_device *dev)
-{
-       struct net_local *lp = netdev_priv(dev);
-#ifdef CONFIG_SMP
-       unsigned long flags;
-#endif
-       int status;
-
-       disable_irq(dev->irq);
-
-       /*
-        *      Best would be to use synchronize_irq(); spin_lock() here
-        *      lets make it work first..
-        */
-
-#ifdef CONFIG_SMP
-       spin_lock_irqsave(&lp->lock, flags);
-#endif
-
-       status = scb_status(dev);
-       unstick_cu(dev);
-       printk(KERN_INFO "%s: transmit timed out, %s?\n", dev->name,
-              (SCB_complete(status)?"lost interrupt":
-               "board on fire"));
-       dev->stats.tx_errors++;
-       lp->last_tx = jiffies;
-       if (!SCB_complete(status)) {
-               scb_command(dev, SCB_CUabort);
-               outb(0,dev->base_addr+SIGNAL_CA);
-       }
-       netif_wake_queue(dev);
-#ifdef CONFIG_SMP
-       spin_unlock_irqrestore(&lp->lock, flags);
-#endif
-}
-
-/*
- * Called to transmit a packet, or to allow us to right ourselves
- * if the kernel thinks we've died.
- */
-static netdev_tx_t eexp_xmit(struct sk_buff *buf, struct net_device *dev)
-{
-       short length = buf->len;
-#ifdef CONFIG_SMP
-       struct net_local *lp = netdev_priv(dev);
-       unsigned long flags;
-#endif
-
-#if NET_DEBUG > 6
-       printk(KERN_DEBUG "%s: eexp_xmit()\n", dev->name);
-#endif
-
-       if (buf->len < ETH_ZLEN) {
-               if (skb_padto(buf, ETH_ZLEN))
-                       return NETDEV_TX_OK;
-               length = ETH_ZLEN;
-       }
-
-       disable_irq(dev->irq);
-
-       /*
-        *      Best would be to use synchronize_irq(); spin_lock() here
-        *      lets make it work first..
-        */
-
-#ifdef CONFIG_SMP
-       spin_lock_irqsave(&lp->lock, flags);
-#endif
-
-       {
-               unsigned short *data = (unsigned short *)buf->data;
-
-               dev->stats.tx_bytes += length;
-
-               eexp_hw_tx_pio(dev,data,length);
-       }
-       dev_kfree_skb(buf);
-#ifdef CONFIG_SMP
-       spin_unlock_irqrestore(&lp->lock, flags);
-#endif
-       enable_irq(dev->irq);
-       return NETDEV_TX_OK;
-}
-
-/*
- * Handle an EtherExpress interrupt
- * If we've finished initializing, start the RU and CU up.
- * If we've already started, reap tx buffers, handle any received packets,
- * check to make sure we've not become wedged.
- */
-
-static unsigned short eexp_start_irq(struct net_device *dev,
-                                    unsigned short status)
-{
-       unsigned short ack_cmd = SCB_ack(status);
-       struct net_local *lp = netdev_priv(dev);
-       unsigned short ioaddr = dev->base_addr;
-       if ((dev->flags & IFF_UP) && !(lp->started & STARTED_CU)) {
-               short diag_status, tdr_status;
-               while (SCB_CUstat(status)==2)
-                       status = scb_status(dev);
-#if NET_DEBUG > 4
-               printk("%s: CU went non-active (status %04x)\n",
-                      dev->name, status);
-#endif
-
-               outw(CONF_DIAG_RESULT & ~31, ioaddr + SM_PTR);
-               diag_status = inw(ioaddr + SHADOW(CONF_DIAG_RESULT));
-               if (diag_status & 1<<11) {
-                       printk(KERN_WARNING "%s: 82586 failed self-test\n",
-                              dev->name);
-               } else if (!(diag_status & 1<<13)) {
-                       printk(KERN_WARNING "%s: 82586 self-test failed to complete\n", dev->name);
-               }
-
-               outw(CONF_TDR_RESULT & ~31, ioaddr + SM_PTR);
-               tdr_status = inw(ioaddr + SHADOW(CONF_TDR_RESULT));
-               if (tdr_status & (TDR_SHORT|TDR_OPEN)) {
-                       printk(KERN_WARNING "%s: TDR reports cable %s at %d tick%s\n", dev->name, (tdr_status & TDR_SHORT)?"short":"broken", tdr_status & TDR_TIME, ((tdr_status & TDR_TIME) != 1) ? "s" : "");
-               }
-               else if (tdr_status & TDR_XCVRPROBLEM) {
-                       printk(KERN_WARNING "%s: TDR reports transceiver problem\n", dev->name);
-               }
-               else if (tdr_status & TDR_LINKOK) {
-#if NET_DEBUG > 4
-                       printk(KERN_DEBUG "%s: TDR reports link OK\n", dev->name);
-#endif
-               } else {
-                       printk("%s: TDR is ga-ga (status %04x)\n", dev->name,
-                              tdr_status);
-               }
-
-               lp->started |= STARTED_CU;
-               scb_wrcbl(dev, lp->tx_link);
-               /* if the RU isn't running, start it now */
-               if (!(lp->started & STARTED_RU)) {
-                       ack_cmd |= SCB_RUstart;
-                       scb_wrrfa(dev, lp->rx_buf_start);
-                       lp->rx_ptr = lp->rx_buf_start;
-                       lp->started |= STARTED_RU;
-               }
-               ack_cmd |= SCB_CUstart | 0x2000;
-       }
-
-       if ((dev->flags & IFF_UP) && !(lp->started & STARTED_RU) && SCB_RUstat(status)==4)
-               lp->started|=STARTED_RU;
-
-       return ack_cmd;
-}
-
-static void eexp_cmd_clear(struct net_device *dev)
-{
-       unsigned long int oldtime = jiffies;
-       while (scb_rdcmd(dev) && (time_before(jiffies, oldtime + 10)));
-       if (scb_rdcmd(dev)) {
-               printk("%s: command didn't clear\n", dev->name);
-       }
-}
-
-static irqreturn_t eexp_irq(int dummy, void *dev_info)
-{
-       struct net_device *dev = dev_info;
-       struct net_local *lp;
-       unsigned short ioaddr,status,ack_cmd;
-       unsigned short old_read_ptr, old_write_ptr;
-
-       lp = netdev_priv(dev);
-       ioaddr = dev->base_addr;
-
-       spin_lock(&lp->lock);
-
-       old_read_ptr = inw(ioaddr+READ_PTR);
-       old_write_ptr = inw(ioaddr+WRITE_PTR);
-
-       outb(SIRQ_dis|irqrmap[dev->irq], ioaddr+SET_IRQ);
-
-       status = scb_status(dev);
-
-#if NET_DEBUG > 4
-       printk(KERN_DEBUG "%s: interrupt (status %x)\n", dev->name, status);
-#endif
-
-       if (lp->started == (STARTED_CU | STARTED_RU)) {
-
-               do {
-                       eexp_cmd_clear(dev);
-
-                       ack_cmd = SCB_ack(status);
-                       scb_command(dev, ack_cmd);
-                       outb(0,ioaddr+SIGNAL_CA);
-
-                       eexp_cmd_clear(dev);
-
-                       if (SCB_complete(status)) {
-                               if (!eexp_hw_lasttxstat(dev)) {
-                                       printk("%s: tx interrupt but no status\n", dev->name);
-                               }
-                       }
-
-                       if (SCB_rxdframe(status))
-                               eexp_hw_rx_pio(dev);
-
-                       status = scb_status(dev);
-               } while (status & 0xc000);
-
-               if (SCB_RUdead(status))
-               {
-                       printk(KERN_WARNING "%s: RU stopped: status %04x\n",
-                              dev->name,status);
-#if 0
-                       printk(KERN_WARNING "%s: cur_rfd=%04x, cur_rbd=%04x\n", dev->name, lp->cur_rfd, lp->cur_rbd);
-                       outw(lp->cur_rfd, ioaddr+READ_PTR);
-                       printk(KERN_WARNING "%s: [%04x]\n", dev->name, inw(ioaddr+DATAPORT));
-                       outw(lp->cur_rfd+6, ioaddr+READ_PTR);
-                       printk(KERN_WARNING "%s: rbd is %04x\n", dev->name, rbd= inw(ioaddr+DATAPORT));
-                       outw(rbd, ioaddr+READ_PTR);
-                       printk(KERN_WARNING "%s: [%04x %04x] ", dev->name, inw(ioaddr+DATAPORT), inw(ioaddr+DATAPORT));
-                       outw(rbd+8, ioaddr+READ_PTR);
-                       printk("[%04x]\n", inw(ioaddr+DATAPORT));
-#endif
-                       dev->stats.rx_errors++;
-#if 1
-                       eexp_hw_rxinit(dev);
-#else
-                       lp->cur_rfd = lp->first_rfd;
-#endif
-                       scb_wrrfa(dev, lp->rx_buf_start);
-                       scb_command(dev, SCB_RUstart);
-                       outb(0,ioaddr+SIGNAL_CA);
-               }
-       } else {
-               if (status & 0x8000)
-                       ack_cmd = eexp_start_irq(dev, status);
-               else
-                       ack_cmd = SCB_ack(status);
-               scb_command(dev, ack_cmd);
-               outb(0,ioaddr+SIGNAL_CA);
-       }
-
-       eexp_cmd_clear(dev);
-
-       outb(SIRQ_en|irqrmap[dev->irq], ioaddr+SET_IRQ);
-
-#if NET_DEBUG > 6
-       printk("%s: leaving eexp_irq()\n", dev->name);
-#endif
-       outw(old_read_ptr, ioaddr+READ_PTR);
-       outw(old_write_ptr, ioaddr+WRITE_PTR);
-
-       spin_unlock(&lp->lock);
-       return IRQ_HANDLED;
-}
-
-/*
- * Hardware access functions
- */
-
-/*
- * Set the cable type to use.
- */
-
-static void eexp_hw_set_interface(struct net_device *dev)
-{
-       unsigned char oldval = inb(dev->base_addr + 0x300e);
-       oldval &= ~0x82;
-       switch (dev->if_port) {
-       case TPE:
-               oldval |= 0x2;
-       case BNC:
-               oldval |= 0x80;
-               break;
-       }
-       outb(oldval, dev->base_addr+0x300e);
-       mdelay(20);
-}
-
-/*
- * Check all the receive buffers, and hand any received packets
- * to the upper levels. Basic sanity check on each frame
- * descriptor, though we don't bother trying to fix broken ones.
- */
-
-static void eexp_hw_rx_pio(struct net_device *dev)
-{
-       struct net_local *lp = netdev_priv(dev);
-       unsigned short rx_block = lp->rx_ptr;
-       unsigned short boguscount = lp->num_rx_bufs;
-       unsigned short ioaddr = dev->base_addr;
-       unsigned short status;
-
-#if NET_DEBUG > 6
-       printk(KERN_DEBUG "%s: eexp_hw_rx()\n", dev->name);
-#endif
-
-       do {
-               unsigned short rfd_cmd, rx_next, pbuf, pkt_len;
-
-               outw(rx_block, ioaddr + READ_PTR);
-               status = inw(ioaddr + DATAPORT);
-
-               if (FD_Done(status))
-               {
-                       rfd_cmd = inw(ioaddr + DATAPORT);
-                       rx_next = inw(ioaddr + DATAPORT);
-                       pbuf = inw(ioaddr + DATAPORT);
-
-                       outw(pbuf, ioaddr + READ_PTR);
-                       pkt_len = inw(ioaddr + DATAPORT);
-
-                       if (rfd_cmd!=0x0000)
-                       {
-                               printk(KERN_WARNING "%s: rfd_cmd not zero:0x%04x\n",
-                                      dev->name, rfd_cmd);
-                               continue;
-                       }
-                       else if (pbuf!=rx_block+0x16)
-                       {
-                               printk(KERN_WARNING "%s: rfd and rbd out of sync 0x%04x 0x%04x\n",
-                                      dev->name, rx_block+0x16, pbuf);
-                               continue;
-                       }
-                       else if ((pkt_len & 0xc000)!=0xc000)
-                       {
-                               printk(KERN_WARNING "%s: EOF or F not set on received buffer (%04x)\n",
-                                      dev->name, pkt_len & 0xc000);
-                               continue;
-                       }
-                       else if (!FD_OK(status))
-                       {
-                               dev->stats.rx_errors++;
-                               if (FD_CRC(status))
-                                       dev->stats.rx_crc_errors++;
-                               if (FD_Align(status))
-                                       dev->stats.rx_frame_errors++;
-                               if (FD_Resrc(status))
-                                       dev->stats.rx_fifo_errors++;
-                               if (FD_DMA(status))
-                                       dev->stats.rx_over_errors++;
-                               if (FD_Short(status))
-                                       dev->stats.rx_length_errors++;
-                       }
-                       else
-                       {
-                               struct sk_buff *skb;
-                               pkt_len &= 0x3fff;
-                               skb = dev_alloc_skb(pkt_len+16);
-                               if (skb == NULL)
-                               {
-                                       printk(KERN_WARNING "%s: Memory squeeze, dropping packet\n",dev->name);
-                                       dev->stats.rx_dropped++;
-                                       break;
-                               }
-                               skb_reserve(skb, 2);
-                               outw(pbuf+10, ioaddr+READ_PTR);
-                               insw(ioaddr+DATAPORT, skb_put(skb,pkt_len),(pkt_len+1)>>1);
-                               skb->protocol = eth_type_trans(skb,dev);
-                               netif_rx(skb);
-                               dev->stats.rx_packets++;
-                               dev->stats.rx_bytes += pkt_len;
-                       }
-                       outw(rx_block, ioaddr+WRITE_PTR);
-                       outw(0, ioaddr+DATAPORT);
-                       outw(0, ioaddr+DATAPORT);
-                       rx_block = rx_next;
-               }
-       } while (FD_Done(status) && boguscount--);
-       lp->rx_ptr = rx_block;
-}
-
-/*
- * Hand a packet to the card for transmission
- * If we get here, we MUST have already checked
- * to make sure there is room in the transmit
- * buffer region.
- */
-
-static void eexp_hw_tx_pio(struct net_device *dev, unsigned short *buf,
-                      unsigned short len)
-{
-       struct net_local *lp = netdev_priv(dev);
-       unsigned short ioaddr = dev->base_addr;
-
-       if (LOCKUP16 || lp->width) {
-               /* Stop the CU so that there is no chance that it
-                  jumps off to a bogus address while we are writing the
-                  pointer to the next transmit packet in 8-bit mode --
-                  this eliminates the "CU wedged" errors in 8-bit mode.
-                  (Zoltan Szilagyi 10-12-96) */
-               scb_command(dev, SCB_CUsuspend);
-               outw(0xFFFF, ioaddr+SIGNAL_CA);
-       }
-
-       outw(lp->tx_head, ioaddr + WRITE_PTR);
-
-       outw(0x0000, ioaddr + DATAPORT);
-        outw(Cmd_INT|Cmd_Xmit, ioaddr + DATAPORT);
-       outw(lp->tx_head+0x08, ioaddr + DATAPORT);
-       outw(lp->tx_head+0x0e, ioaddr + DATAPORT);
-
-       outw(0x0000, ioaddr + DATAPORT);
-       outw(0x0000, ioaddr + DATAPORT);
-       outw(lp->tx_head+0x08, ioaddr + DATAPORT);
-
-       outw(0x8000|len, ioaddr + DATAPORT);
-       outw(-1, ioaddr + DATAPORT);
-       outw(lp->tx_head+0x16, ioaddr + DATAPORT);
-       outw(0, ioaddr + DATAPORT);
-
-       outsw(ioaddr + DATAPORT, buf, (len+1)>>1);
-
-       outw(lp->tx_tail+0xc, ioaddr + WRITE_PTR);
-       outw(lp->tx_head, ioaddr + DATAPORT);
-
-       dev->trans_start = jiffies;
-       lp->tx_tail = lp->tx_head;
-       if (lp->tx_head==TX_BUF_START+((lp->num_tx_bufs-1)*TX_BUF_SIZE))
-               lp->tx_head = TX_BUF_START;
-       else
-               lp->tx_head += TX_BUF_SIZE;
-       if (lp->tx_head != lp->tx_reap)
-               netif_wake_queue(dev);
-
-       if (LOCKUP16 || lp->width) {
-               /* Restart the CU so that the packet can actually
-                  be transmitted. (Zoltan Szilagyi 10-12-96) */
-               scb_command(dev, SCB_CUresume);
-               outw(0xFFFF, ioaddr+SIGNAL_CA);
-       }
-
-       dev->stats.tx_packets++;
-       lp->last_tx = jiffies;
-}
-
-static const struct net_device_ops eexp_netdev_ops = {
-       .ndo_open               = eexp_open,
-       .ndo_stop               = eexp_close,
-       .ndo_start_xmit         = eexp_xmit,
-       .ndo_set_multicast_list = eexp_set_multicast,
-       .ndo_tx_timeout         = eexp_timeout,
-       .ndo_change_mtu         = eth_change_mtu,
-       .ndo_set_mac_address    = eth_mac_addr,
-       .ndo_validate_addr      = eth_validate_addr,
-};
-
-/*
- * Sanity check the suspected EtherExpress card
- * Read hardware address, reset card, size memory and initialize buffer
- * memory pointers. These are held in netdev_priv(), in case someone has more
- * than one card in a machine.
- */
-
-static int __init eexp_hw_probe(struct net_device *dev, unsigned short ioaddr)
-{
-       unsigned short hw_addr[3];
-       unsigned char buswidth;
-       unsigned int memory_size;
-       int i;
-       unsigned short xsum = 0;
-       struct net_local *lp = netdev_priv(dev);
-
-       printk("%s: EtherExpress 16 at %#x ",dev->name,ioaddr);
-
-       outb(ASIC_RST, ioaddr+EEPROM_Ctrl);
-       outb(0, ioaddr+EEPROM_Ctrl);
-       udelay(500);
-       outb(i586_RST, ioaddr+EEPROM_Ctrl);
-
-       hw_addr[0] = eexp_hw_readeeprom(ioaddr,2);
-       hw_addr[1] = eexp_hw_readeeprom(ioaddr,3);
-       hw_addr[2] = eexp_hw_readeeprom(ioaddr,4);
-
-       /* Standard Address or Compaq LTE Address */
-       if (!((hw_addr[2]==0x00aa && ((hw_addr[1] & 0xff00)==0x0000)) ||
-             (hw_addr[2]==0x0080 && ((hw_addr[1] & 0xff00)==0x5F00))))
-       {
-               printk(" rejected: invalid address %04x%04x%04x\n",
-                       hw_addr[2],hw_addr[1],hw_addr[0]);
-               return -ENODEV;
-       }
-
-       /* Calculate the EEPROM checksum.  Carry on anyway if it's bad,
-        * though.
-        */
-       for (i = 0; i < 64; i++)
-               xsum += eexp_hw_readeeprom(ioaddr, i);
-       if (xsum != 0xbaba)
-               printk(" (bad EEPROM xsum 0x%02x)", xsum);
-
-       dev->base_addr = ioaddr;
-       for ( i=0 ; i<6 ; i++ )
-               dev->dev_addr[i] = ((unsigned char *)hw_addr)[5-i];
-
-       {
-               static const char irqmap[] = { 0, 9, 3, 4, 5, 10, 11, 0 };
-               unsigned short setupval = eexp_hw_readeeprom(ioaddr,0);
-
-               /* Use the IRQ from EEPROM if none was given */
-               if (!dev->irq)
-                       dev->irq = irqmap[setupval>>13];
-
-               if (dev->if_port == 0xff) {
-                       dev->if_port = !(setupval & 0x1000) ? AUI :
-                               eexp_hw_readeeprom(ioaddr,5) & 0x1 ? TPE : BNC;
-               }
-
-               buswidth = !((setupval & 0x400) >> 10);
-       }
-
-       memset(lp, 0, sizeof(struct net_local));
-       spin_lock_init(&lp->lock);
-
-       printk("(IRQ %d, %s connector, %d-bit bus", dev->irq,
-              eexp_ifmap[dev->if_port], buswidth?8:16);
-
-       if (!request_region(dev->base_addr + 0x300e, 1, "EtherExpress"))
-               return -EBUSY;
-
-       eexp_hw_set_interface(dev);
-
-       release_region(dev->base_addr + 0x300e, 1);
-
-       /* Find out how much RAM we have on the card */
-       outw(0, dev->base_addr + WRITE_PTR);
-       for (i = 0; i < 32768; i++)
-               outw(0, dev->base_addr + DATAPORT);
-
-        for (memory_size = 0; memory_size < 64; memory_size++)
-       {
-               outw(memory_size<<10, dev->base_addr + READ_PTR);
-               if (inw(dev->base_addr+DATAPORT))
-                       break;
-               outw(memory_size<<10, dev->base_addr + WRITE_PTR);
-               outw(memory_size | 0x5000, dev->base_addr+DATAPORT);
-               outw(memory_size<<10, dev->base_addr + READ_PTR);
-               if (inw(dev->base_addr+DATAPORT) != (memory_size | 0x5000))
-                       break;
-       }
-
-       /* Sort out the number of buffers.  We may have 16, 32, 48 or 64k
-        * of RAM to play with.
-        */
-       lp->num_tx_bufs = 4;
-       lp->rx_buf_end = 0x3ff6;
-       switch (memory_size)
-       {
-       case 64:
-               lp->rx_buf_end += 0x4000;
-       case 48:
-               lp->num_tx_bufs += 4;
-               lp->rx_buf_end += 0x4000;
-       case 32:
-               lp->rx_buf_end += 0x4000;
-       case 16:
-               printk(", %dk RAM)\n", memory_size);
-               break;
-       default:
-               printk(") bad memory size (%dk).\n", memory_size);
-               return -ENODEV;
-               break;
-       }
-
-       lp->rx_buf_start = TX_BUF_START + (lp->num_tx_bufs*TX_BUF_SIZE);
-       lp->width = buswidth;
-
-       dev->netdev_ops = &eexp_netdev_ops;
-       dev->watchdog_timeo = 2*HZ;
-
-       return register_netdev(dev);
-}
-
-/*
- * Read a word from the EtherExpress on-board serial EEPROM.
- * The EEPROM contains 64 words of 16 bits.
- */
-static unsigned short __init eexp_hw_readeeprom(unsigned short ioaddr,
-                                                   unsigned char location)
-{
-       unsigned short cmd = 0x180|(location&0x7f);
-       unsigned short rval = 0,wval = EC_CS|i586_RST;
-       int i;
-
-       outb(EC_CS|i586_RST,ioaddr+EEPROM_Ctrl);
-       for (i=0x100 ; i ; i>>=1 )
-       {
-               if (cmd&i)
-                       wval |= EC_Wr;
-               else
-                       wval &= ~EC_Wr;
-
-               outb(wval,ioaddr+EEPROM_Ctrl);
-               outb(wval|EC_Clk,ioaddr+EEPROM_Ctrl);
-               eeprom_delay();
-               outb(wval,ioaddr+EEPROM_Ctrl);
-               eeprom_delay();
-       }
-       wval &= ~EC_Wr;
-       outb(wval,ioaddr+EEPROM_Ctrl);
-       for (i=0x8000 ; i ; i>>=1 )
-       {
-               outb(wval|EC_Clk,ioaddr+EEPROM_Ctrl);
-               eeprom_delay();
-               if (inb(ioaddr+EEPROM_Ctrl)&EC_Rd)
-                       rval |= i;
-               outb(wval,ioaddr+EEPROM_Ctrl);
-               eeprom_delay();
-       }
-       wval &= ~EC_CS;
-       outb(wval|EC_Clk,ioaddr+EEPROM_Ctrl);
-       eeprom_delay();
-       outb(wval,ioaddr+EEPROM_Ctrl);
-       eeprom_delay();
-       return rval;
-}
-
-/*
- * Reap tx buffers and return last transmit status.
- * if ==0 then either:
- *    a) we're not transmitting anything, so why are we here?
- *    b) we've died.
- * otherwise, Stat_Busy(return) means we've still got some packets
- * to transmit, Stat_Done(return) means our buffers should be empty
- * again
- */
-
-static unsigned short eexp_hw_lasttxstat(struct net_device *dev)
-{
-       struct net_local *lp = netdev_priv(dev);
-       unsigned short tx_block = lp->tx_reap;
-       unsigned short status;
-
-       if (!netif_queue_stopped(dev) && lp->tx_head==lp->tx_reap)
-               return 0x0000;
-
-       do
-       {
-               outw(tx_block & ~31, dev->base_addr + SM_PTR);
-               status = inw(dev->base_addr + SHADOW(tx_block));
-               if (!Stat_Done(status))
-               {
-                       lp->tx_link = tx_block;
-                       return status;
-               }
-               else
-               {
-                       lp->last_tx_restart = 0;
-                       dev->stats.collisions += Stat_NoColl(status);
-                       if (!Stat_OK(status))
-                       {
-                               char *whatsup = NULL;
-                               dev->stats.tx_errors++;
-                               if (Stat_Abort(status))
-                                       dev->stats.tx_aborted_errors++;
-                               if (Stat_TNoCar(status)) {
-                                       whatsup = "aborted, no carrier";
-                                       dev->stats.tx_carrier_errors++;
-                               }
-                               if (Stat_TNoCTS(status)) {
-                                       whatsup = "aborted, lost CTS";
-                                       dev->stats.tx_carrier_errors++;
-                               }
-                               if (Stat_TNoDMA(status)) {
-                                       whatsup = "FIFO underran";
-                                       dev->stats.tx_fifo_errors++;
-                               }
-                               if (Stat_TXColl(status)) {
-                                       whatsup = "aborted, too many collisions";
-                                       dev->stats.tx_aborted_errors++;
-                               }
-                               if (whatsup)
-                                       printk(KERN_INFO "%s: transmit %s\n",
-                                              dev->name, whatsup);
-                       }
-                       else
-                               dev->stats.tx_packets++;
-               }
-               if (tx_block == TX_BUF_START+((lp->num_tx_bufs-1)*TX_BUF_SIZE))
-                       lp->tx_reap = tx_block = TX_BUF_START;
-               else
-                       lp->tx_reap = tx_block += TX_BUF_SIZE;
-               netif_wake_queue(dev);
-       }
-       while (lp->tx_reap != lp->tx_head);
-
-       lp->tx_link = lp->tx_tail + 0x08;
-
-       return status;
-}
-
-/*
- * This should never happen. It is called when some higher routine detects
- * that the CU has stopped, to try to restart it from the last packet we knew
- * we were working on, or the idle loop if we had finished for the time.
- */
-
-static void eexp_hw_txrestart(struct net_device *dev)
-{
-       struct net_local *lp = netdev_priv(dev);
-       unsigned short ioaddr = dev->base_addr;
-
-       lp->last_tx_restart = lp->tx_link;
-       scb_wrcbl(dev, lp->tx_link);
-       scb_command(dev, SCB_CUstart);
-       outb(0,ioaddr+SIGNAL_CA);
-
-       {
-               unsigned short boguscount=50,failcount=5;
-               while (!scb_status(dev))
-               {
-                       if (!--boguscount)
-                       {
-                               if (--failcount)
-                               {
-                                       printk(KERN_WARNING "%s: CU start timed out, status %04x, cmd %04x\n", dev->name, scb_status(dev), scb_rdcmd(dev));
-                                       scb_wrcbl(dev, lp->tx_link);
-                                       scb_command(dev, SCB_CUstart);
-                                       outb(0,ioaddr+SIGNAL_CA);
-                                       boguscount = 100;
-                               }
-                               else
-                               {
-                                       printk(KERN_WARNING "%s: Failed to restart CU, resetting board...\n",dev->name);
-                                       eexp_hw_init586(dev);
-                                       netif_wake_queue(dev);
-                                       return;
-                               }
-                       }
-               }
-       }
-}
-
-/*
- * Writes down the list of transmit buffers into card memory.  Each
- * entry consists of an 82586 transmit command, followed by a jump
- * pointing to itself.  When we want to transmit a packet, we write
- * the data into the appropriate transmit buffer and then modify the
- * preceding jump to point at the new transmit command.  This means that
- * the 586 command unit is continuously active.
- */
-
-static void eexp_hw_txinit(struct net_device *dev)
-{
-       struct net_local *lp = netdev_priv(dev);
-       unsigned short tx_block = TX_BUF_START;
-       unsigned short curtbuf;
-       unsigned short ioaddr = dev->base_addr;
-
-       for ( curtbuf=0 ; curtbuf<lp->num_tx_bufs ; curtbuf++ )
-       {
-               outw(tx_block, ioaddr + WRITE_PTR);
-
-               outw(0x0000, ioaddr + DATAPORT);
-               outw(Cmd_INT|Cmd_Xmit, ioaddr + DATAPORT);
-               outw(tx_block+0x08, ioaddr + DATAPORT);
-               outw(tx_block+0x0e, ioaddr + DATAPORT);
-
-               outw(0x0000, ioaddr + DATAPORT);
-               outw(0x0000, ioaddr + DATAPORT);
-               outw(tx_block+0x08, ioaddr + DATAPORT);
-
-               outw(0x8000, ioaddr + DATAPORT);
-               outw(-1, ioaddr + DATAPORT);
-               outw(tx_block+0x16, ioaddr + DATAPORT);
-               outw(0x0000, ioaddr + DATAPORT);
-
-               tx_block += TX_BUF_SIZE;
-       }
-       lp->tx_head = TX_BUF_START;
-       lp->tx_reap = TX_BUF_START;
-       lp->tx_tail = tx_block - TX_BUF_SIZE;
-       lp->tx_link = lp->tx_tail + 0x08;
-       lp->rx_buf_start = tx_block;
-
-}
-
-/*
- * Write the circular list of receive buffer descriptors to card memory.
- * The end of the list isn't marked, which means that the 82586 receive
- * unit will loop until buffers become available (this avoids it giving us
- * "out of resources" messages).
- */
-
-static void eexp_hw_rxinit(struct net_device *dev)
-{
-       struct net_local *lp = netdev_priv(dev);
-       unsigned short rx_block = lp->rx_buf_start;
-       unsigned short ioaddr = dev->base_addr;
-
-       lp->num_rx_bufs = 0;
-       lp->rx_first = lp->rx_ptr = rx_block;
-       do
-       {
-               lp->num_rx_bufs++;
-
-               outw(rx_block, ioaddr + WRITE_PTR);
-
-               outw(0, ioaddr + DATAPORT);  outw(0, ioaddr+DATAPORT);
-               outw(rx_block + RX_BUF_SIZE, ioaddr+DATAPORT);
-               outw(0xffff, ioaddr+DATAPORT);
-
-               outw(0x0000, ioaddr+DATAPORT);
-               outw(0xdead, ioaddr+DATAPORT);
-               outw(0xdead, ioaddr+DATAPORT);
-               outw(0xdead, ioaddr+DATAPORT);
-               outw(0xdead, ioaddr+DATAPORT);
-               outw(0xdead, ioaddr+DATAPORT);
-               outw(0xdead, ioaddr+DATAPORT);
-
-               outw(0x0000, ioaddr+DATAPORT);
-               outw(rx_block + RX_BUF_SIZE + 0x16, ioaddr+DATAPORT);
-               outw(rx_block + 0x20, ioaddr+DATAPORT);
-               outw(0, ioaddr+DATAPORT);
-               outw(RX_BUF_SIZE-0x20, ioaddr+DATAPORT);
-
-               lp->rx_last = rx_block;
-               rx_block += RX_BUF_SIZE;
-       } while (rx_block <= lp->rx_buf_end-RX_BUF_SIZE);
-
-
-       /* Make first Rx frame descriptor point to first Rx buffer
-           descriptor */
-       outw(lp->rx_first + 6, ioaddr+WRITE_PTR);
-       outw(lp->rx_first + 0x16, ioaddr+DATAPORT);
-
-       /* Close Rx frame descriptor ring */
-       outw(lp->rx_last + 4, ioaddr+WRITE_PTR);
-       outw(lp->rx_first, ioaddr+DATAPORT);
-
-       /* Close Rx buffer descriptor ring */
-       outw(lp->rx_last + 0x16 + 2, ioaddr+WRITE_PTR);
-       outw(lp->rx_first + 0x16, ioaddr+DATAPORT);
-
-}
-
-/*
- * Un-reset the 586, and start the configuration sequence. We don't wait for
- * this to finish, but allow the interrupt handler to start the CU and RU for
- * us.  We can't start the receive/transmission system up before we know that
- * the hardware is configured correctly.
- */
-
-static void eexp_hw_init586(struct net_device *dev)
-{
-       struct net_local *lp = netdev_priv(dev);
-       unsigned short ioaddr = dev->base_addr;
-       int i;
-
-#if NET_DEBUG > 6
-       printk("%s: eexp_hw_init586()\n", dev->name);
-#endif
-
-       lp->started = 0;
-
-       set_loopback(dev);
-
-       outb(SIRQ_dis|irqrmap[dev->irq],ioaddr+SET_IRQ);
-
-       /* Download the startup code */
-       outw(lp->rx_buf_end & ~31, ioaddr + SM_PTR);
-       outw(lp->width?0x0001:0x0000, ioaddr + 0x8006);
-       outw(0x0000, ioaddr + 0x8008);
-       outw(0x0000, ioaddr + 0x800a);
-       outw(0x0000, ioaddr + 0x800c);
-       outw(0x0000, ioaddr + 0x800e);
-
-       for (i = 0; i < ARRAY_SIZE(start_code) * 2; i+=32) {
-               int j;
-               outw(i, ioaddr + SM_PTR);
-               for (j = 0; j < 16 && (i+j)/2 < ARRAY_SIZE(start_code); j+=2)
-                       outw(start_code[(i+j)/2],
-                            ioaddr+0x4000+j);
-               for (j = 0; j < 16 && (i+j+16)/2 < ARRAY_SIZE(start_code); j+=2)
-                       outw(start_code[(i+j+16)/2],
-                            ioaddr+0x8000+j);
-       }
-
-       /* Do we want promiscuous mode or multicast? */
-       outw(CONF_PROMISC & ~31, ioaddr+SM_PTR);
-       i = inw(ioaddr+SHADOW(CONF_PROMISC));
-       outw((dev->flags & IFF_PROMISC)?(i|1):(i & ~1),
-            ioaddr+SHADOW(CONF_PROMISC));
-       lp->was_promisc = dev->flags & IFF_PROMISC;
-#if 0
-       eexp_setup_filter(dev);
-#endif
-
-       /* Write our hardware address */
-       outw(CONF_HWADDR & ~31, ioaddr+SM_PTR);
-       outw(((unsigned short *)dev->dev_addr)[0], ioaddr+SHADOW(CONF_HWADDR));
-       outw(((unsigned short *)dev->dev_addr)[1],
-            ioaddr+SHADOW(CONF_HWADDR+2));
-       outw(((unsigned short *)dev->dev_addr)[2],
-            ioaddr+SHADOW(CONF_HWADDR+4));
-
-       eexp_hw_txinit(dev);
-       eexp_hw_rxinit(dev);
-
-       outb(0,ioaddr+EEPROM_Ctrl);
-       mdelay(5);
-
-       scb_command(dev, 0xf000);
-       outb(0,ioaddr+SIGNAL_CA);
-
-       outw(0, ioaddr+SM_PTR);
-
-       {
-               unsigned short rboguscount=50,rfailcount=5;
-               while (inw(ioaddr+0x4000))
-               {
-                       if (!--rboguscount)
-                       {
-                               printk(KERN_WARNING "%s: i82586 reset timed out, kicking...\n",
-                                       dev->name);
-                               scb_command(dev, 0);
-                               outb(0,ioaddr+SIGNAL_CA);
-                               rboguscount = 100;
-                               if (!--rfailcount)
-                               {
-                                       printk(KERN_WARNING "%s: i82586 not responding, giving up.\n",
-                                               dev->name);
-                                       return;
-                               }
-                       }
-               }
-       }
-
-        scb_wrcbl(dev, CONF_LINK);
-       scb_command(dev, 0xf000|SCB_CUstart);
-       outb(0,ioaddr+SIGNAL_CA);
-
-       {
-               unsigned short iboguscount=50,ifailcount=5;
-               while (!scb_status(dev))
-               {
-                       if (!--iboguscount)
-                       {
-                               if (--ifailcount)
-                               {
-                                       printk(KERN_WARNING "%s: i82586 initialization timed out, status %04x, cmd %04x\n",
-                                               dev->name, scb_status(dev), scb_rdcmd(dev));
-                                       scb_wrcbl(dev, CONF_LINK);
-                                       scb_command(dev, 0xf000|SCB_CUstart);
-                                       outb(0,ioaddr+SIGNAL_CA);
-                                       iboguscount = 100;
-                               }
-                               else
-                               {
-                                       printk(KERN_WARNING "%s: Failed to initialize i82586, giving up.\n",dev->name);
-                                       return;
-                               }
-                       }
-               }
-       }
-
-       clear_loopback(dev);
-       outb(SIRQ_en|irqrmap[dev->irq],ioaddr+SET_IRQ);
-
-       lp->init_time = jiffies;
-#if NET_DEBUG > 6
-        printk("%s: leaving eexp_hw_init586()\n", dev->name);
-#endif
-}
-
-static void eexp_setup_filter(struct net_device *dev)
-{
-       struct netdev_hw_addr *ha;
-       unsigned short ioaddr = dev->base_addr;
-       int count = netdev_mc_count(dev);
-       int i;
-       if (count > 8) {
-               printk(KERN_INFO "%s: too many multicast addresses (%d)\n",
-                      dev->name, count);
-               count = 8;
-       }
-
-       outw(CONF_NR_MULTICAST & ~31, ioaddr+SM_PTR);
-       outw(6*count, ioaddr+SHADOW(CONF_NR_MULTICAST));
-       i = 0;
-       netdev_for_each_mc_addr(ha, dev) {
-               unsigned short *data = (unsigned short *) ha->addr;
-
-               if (i == count)
-                       break;
-               outw((CONF_MULTICAST+(6*i)) & ~31, ioaddr+SM_PTR);
-               outw(data[0], ioaddr+SHADOW(CONF_MULTICAST+(6*i)));
-               outw((CONF_MULTICAST+(6*i)+2) & ~31, ioaddr+SM_PTR);
-               outw(data[1], ioaddr+SHADOW(CONF_MULTICAST+(6*i)+2));
-               outw((CONF_MULTICAST+(6*i)+4) & ~31, ioaddr+SM_PTR);
-               outw(data[2], ioaddr+SHADOW(CONF_MULTICAST+(6*i)+4));
-               i++;
-       }
-}
-
-/*
- * Set or clear the multicast filter for this adaptor.
- */
-static void
-eexp_set_multicast(struct net_device *dev)
-{
-        unsigned short ioaddr = dev->base_addr;
-        struct net_local *lp = netdev_priv(dev);
-        int kick = 0, i;
-        if ((dev->flags & IFF_PROMISC) != lp->was_promisc) {
-                outw(CONF_PROMISC & ~31, ioaddr+SM_PTR);
-                i = inw(ioaddr+SHADOW(CONF_PROMISC));
-                outw((dev->flags & IFF_PROMISC)?(i|1):(i & ~1),
-                     ioaddr+SHADOW(CONF_PROMISC));
-                lp->was_promisc = dev->flags & IFF_PROMISC;
-                kick = 1;
-        }
-        if (!(dev->flags & IFF_PROMISC)) {
-                eexp_setup_filter(dev);
-                if (lp->old_mc_count != netdev_mc_count(dev)) {
-                        kick = 1;
-                        lp->old_mc_count = netdev_mc_count(dev);
-                }
-        }
-        if (kick) {
-                unsigned long oj;
-                scb_command(dev, SCB_CUsuspend);
-                outb(0, ioaddr+SIGNAL_CA);
-                outb(0, ioaddr+SIGNAL_CA);
-#if 0
-                printk("%s: waiting for CU to go suspended\n", dev->name);
-#endif
-                oj = jiffies;
-                while ((SCB_CUstat(scb_status(dev)) == 2) &&
-                       (time_before(jiffies, oj + 2000)));
-               if (SCB_CUstat(scb_status(dev)) == 2)
-                       printk("%s: warning, CU didn't stop\n", dev->name);
-                lp->started &= ~(STARTED_CU);
-                scb_wrcbl(dev, CONF_LINK);
-                scb_command(dev, SCB_CUstart);
-                outb(0, ioaddr+SIGNAL_CA);
-        }
-}
-
-
-/*
- * MODULE stuff
- */
-
-#ifdef MODULE
-
-#define EEXP_MAX_CARDS     4    /* max number of cards to support */
-
-static struct net_device *dev_eexp[EEXP_MAX_CARDS];
-static int irq[EEXP_MAX_CARDS];
-static int io[EEXP_MAX_CARDS];
-
-module_param_array(io, int, NULL, 0);
-module_param_array(irq, int, NULL, 0);
-MODULE_PARM_DESC(io, "EtherExpress 16 I/O base address(es)");
-MODULE_PARM_DESC(irq, "EtherExpress 16 IRQ number(s)");
-MODULE_LICENSE("GPL");
-
-
-/* Ideally the user would give us io=, irq= for every card.  If any parameters
- * are specified, we verify and then use them.  If no parameters are given, we
- * autoprobe for one card only.
- */
-int __init init_module(void)
-{
-       struct net_device *dev;
-       int this_dev, found = 0;
-
-       for (this_dev = 0; this_dev < EEXP_MAX_CARDS; this_dev++) {
-               dev = alloc_etherdev(sizeof(struct net_local));
-               dev->irq = irq[this_dev];
-               dev->base_addr = io[this_dev];
-               if (io[this_dev] == 0) {
-                       if (this_dev)
-                               break;
-                       printk(KERN_NOTICE "eexpress.c: Module autoprobe not recommended, give io=xx.\n");
-               }
-               if (do_express_probe(dev) == 0) {
-                       dev_eexp[this_dev] = dev;
-                       found++;
-                       continue;
-               }
-               printk(KERN_WARNING "eexpress.c: Failed to register card at 0x%x.\n", io[this_dev]);
-               free_netdev(dev);
-               break;
-       }
-       if (found)
-               return 0;
-       return -ENXIO;
-}
-
-void __exit cleanup_module(void)
-{
-       int this_dev;
-
-       for (this_dev = 0; this_dev < EEXP_MAX_CARDS; this_dev++) {
-               struct net_device *dev = dev_eexp[this_dev];
-               if (dev) {
-                       unregister_netdev(dev);
-                       free_netdev(dev);
-               }
-       }
-}
-#endif
-
-/*
- * Local Variables:
- *  c-file-style: "linux"
- *  tab-width: 8
- * End:
- */
diff --git a/drivers/net/eexpress.h b/drivers/net/eexpress.h
deleted file mode 100644 (file)
index dc9c6ea..0000000
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * eexpress.h: Intel EtherExpress16 defines
- */
-
-/*
- * EtherExpress card register addresses
- * as offsets from the base IO region (dev->base_addr)
- */
-
-#define DATAPORT      0x0000
-#define WRITE_PTR     0x0002
-#define READ_PTR      0x0004
-#define SIGNAL_CA     0x0006
-#define SET_IRQ       0x0007
-#define SM_PTR        0x0008
-#define        MEM_Dec       0x000a
-#define MEM_Ctrl      0x000b
-#define MEM_Page_Ctrl 0x000c
-#define Config        0x000d
-#define EEPROM_Ctrl   0x000e
-#define ID_PORT       0x000f
-#define        MEM_ECtrl     0x000f
-
-/*
- * card register defines
- */
-
-/* SET_IRQ */
-#define SIRQ_en       0x08
-#define SIRQ_dis      0x00
-
-/* EEPROM_Ctrl */
-#define EC_Clk        0x01
-#define EC_CS         0x02
-#define EC_Wr         0x04
-#define EC_Rd         0x08
-#define ASIC_RST      0x40
-#define i586_RST      0x80
-
-#define eeprom_delay() { udelay(40); }
-
-/*
- * i82586 Memory Configuration
- */
-
-/* (System Configuration Pointer) System start up block, read after 586_RST */
-#define SCP_START 0xfff6
-
-/* Intermediate System Configuration Pointer */
-#define ISCP_START 0x0000
-
-/* System Command Block */
-#define SCB_START 0x0008
-
-/* Start of buffer region.  Everything before this is used for control
- * structures and the CU configuration program.  The memory layout is
- * determined in eexp_hw_probe(), once we know how much memory is
- * available on the card.
- */
-
-#define TX_BUF_START 0x0100
-
-#define TX_BUF_SIZE ((24+ETH_FRAME_LEN+31)&~0x1f)
-#define RX_BUF_SIZE ((32+ETH_FRAME_LEN+31)&~0x1f)
-
-/*
- * SCB defines
- */
-
-/* these functions take the SCB status word and test the relevant status bit */
-#define SCB_complete(s) (((s) & 0x8000) != 0)
-#define SCB_rxdframe(s) (((s) & 0x4000) != 0)
-#define SCB_CUdead(s)   (((s) & 0x2000) != 0)
-#define SCB_RUdead(s)   (((s) & 0x1000) != 0)
-#define SCB_ack(s)      ((s) & 0xf000)
-
-/* Command unit status: 0=idle, 1=suspended, 2=active */
-#define SCB_CUstat(s)   (((s)&0x0300)>>8)
-
-/* Receive unit status: 0=idle, 1=suspended, 2=out of resources, 4=ready */
-#define SCB_RUstat(s)   (((s)&0x0070)>>4)
-
-/* SCB commands */
-#define SCB_CUnop       0x0000
-#define SCB_CUstart     0x0100
-#define SCB_CUresume    0x0200
-#define SCB_CUsuspend   0x0300
-#define SCB_CUabort     0x0400
-#define SCB_resetchip   0x0080
-
-#define SCB_RUnop       0x0000
-#define SCB_RUstart     0x0010
-#define SCB_RUresume    0x0020
-#define SCB_RUsuspend   0x0030
-#define SCB_RUabort     0x0040
-
-/*
- * Command block defines
- */
-
-#define Stat_Done(s)    (((s) & 0x8000) != 0)
-#define Stat_Busy(s)    (((s) & 0x4000) != 0)
-#define Stat_OK(s)      (((s) & 0x2000) != 0)
-#define Stat_Abort(s)   (((s) & 0x1000) != 0)
-#define Stat_STFail     (((s) & 0x0800) != 0)
-#define Stat_TNoCar(s)  (((s) & 0x0400) != 0)
-#define Stat_TNoCTS(s)  (((s) & 0x0200) != 0)
-#define Stat_TNoDMA(s)  (((s) & 0x0100) != 0)
-#define Stat_TDefer(s)  (((s) & 0x0080) != 0)
-#define Stat_TColl(s)   (((s) & 0x0040) != 0)
-#define Stat_TXColl(s)  (((s) & 0x0020) != 0)
-#define Stat_NoColl(s)  ((s) & 0x000f)
-
-/* Cmd_END will end AFTER the command if this is the first
- * command block after an SCB_CUstart, but BEFORE the command
- * for all subsequent commands. Best strategy is to place
- * Cmd_INT on the last command in the sequence, followed by a
- * dummy Cmd_Nop with Cmd_END after this.
- */
-
-#define Cmd_END     0x8000
-#define Cmd_SUS     0x4000
-#define Cmd_INT     0x2000
-
-#define Cmd_Nop     0x0000
-#define Cmd_SetAddr 0x0001
-#define Cmd_Config  0x0002
-#define Cmd_MCast   0x0003
-#define Cmd_Xmit    0x0004
-#define Cmd_TDR     0x0005
-#define Cmd_Dump    0x0006
-#define Cmd_Diag    0x0007
-
-
-/*
- * Frame Descriptor (Receive block) defines
- */
-
-#define FD_Done(s)  (((s) & 0x8000) != 0)
-#define FD_Busy(s)  (((s) & 0x4000) != 0)
-#define FD_OK(s)    (((s) & 0x2000) != 0)
-
-#define FD_CRC(s)   (((s) & 0x0800) != 0)
-#define FD_Align(s) (((s) & 0x0400) != 0)
-#define FD_Resrc(s) (((s) & 0x0200) != 0)
-#define FD_DMA(s)   (((s) & 0x0100) != 0)
-#define FD_Short(s) (((s) & 0x0080) != 0)
-#define FD_NoEOF(s) (((s) & 0x0040) != 0)
-
-struct rfd_header {
-       volatile unsigned long flags;
-       volatile unsigned short link;
-       volatile unsigned short rbd_offset;
-       volatile unsigned short dstaddr1;
-       volatile unsigned short dstaddr2;
-       volatile unsigned short dstaddr3;
-       volatile unsigned short srcaddr1;
-       volatile unsigned short srcaddr2;
-       volatile unsigned short srcaddr3;
-       volatile unsigned short length;
-
-       /* This is actually a Receive Buffer Descriptor.  The way we
-        * arrange memory means that an RBD always follows the RFD that
-        * points to it, so they might as well be in the same structure.
-        */
-       volatile unsigned short actual_count;
-       volatile unsigned short next_rbd;
-       volatile unsigned short buf_addr1;
-       volatile unsigned short buf_addr2;
-       volatile unsigned short size;
-};
-
-/* Returned data from the Time Domain Reflectometer */
-
-#define TDR_LINKOK       (1<<15)
-#define TDR_XCVRPROBLEM  (1<<14)
-#define TDR_OPEN         (1<<13)
-#define TDR_SHORT        (1<<12)
-#define TDR_TIME         0x7ff
index ed5836ccb8d67d1edec5572ea053cdab3485131b..d0a8fa8ab7ec2710c5ac66a275676ed5d928eda9 100644 (file)
@@ -17,6 +17,7 @@ source "drivers/net/ethernet/amd/Kconfig"
 source "drivers/net/ethernet/broadcom/Kconfig"
 source "drivers/net/ethernet/chelsio/Kconfig"
 source "drivers/net/ethernet/intel/Kconfig"
+source "drivers/net/ethernet/i825xx/Kconfig"
 source "drivers/net/ethernet/qlogic/Kconfig"
 source "drivers/net/ethernet/smsc/Kconfig"
 
index 983fd275215138b375a1ad990d0e0eecbe402b30..6d3276a48012bf91005e8f6d16e8a05643e2d857 100644 (file)
@@ -8,5 +8,6 @@ obj-$(CONFIG_NET_VENDOR_AMD) += amd/
 obj-$(CONFIG_NET_VENDOR_BROADCOM) += broadcom/
 obj-$(CONFIG_NET_VENDOR_CHELSIO) += chelsio/
 obj-$(CONFIG_NET_VENDOR_INTEL) += intel/
+obj-$(CONFIG_NET_VENDOR_I825XX) += i825xx/
 obj-$(CONFIG_NET_VENDOR_QLOGIC) += qlogic/
 obj-$(CONFIG_NET_VENDOR_SMSC) += smsc/
diff --git a/drivers/net/ethernet/i825xx/3c505.c b/drivers/net/ethernet/i825xx/3c505.c
new file mode 100644 (file)
index 0000000..88d766e
--- /dev/null
@@ -0,0 +1,1673 @@
+/*
+ * Linux Ethernet device driver for the 3Com Etherlink Plus (3C505)
+ *      By Craig Southeren, Juha Laiho and Philip Blundell
+ *
+ * 3c505.c      This module implements an interface to the 3Com
+ *              Etherlink Plus (3c505) Ethernet card. Linux device
+ *              driver interface reverse engineered from the Linux 3C509
+ *              device drivers. Some 3C505 information gleaned from
+ *              the Crynwr packet driver. Still this driver would not
+ *              be here without 3C505 technical reference provided by
+ *              3Com.
+ *
+ * $Id: 3c505.c,v 1.10 1996/04/16 13:06:27 phil Exp $
+ *
+ * Authors:     Linux 3c505 device driver by
+ *                      Craig Southeren, <craigs@ineluki.apana.org.au>
+ *              Final debugging by
+ *                      Andrew Tridgell, <tridge@nimbus.anu.edu.au>
+ *              Auto irq/address, tuning, cleanup and v1.1.4+ kernel mods by
+ *                      Juha Laiho, <jlaiho@ichaos.nullnet.fi>
+ *              Linux 3C509 driver by
+ *                      Donald Becker, <becker@super.org>
+ *                     (Now at <becker@scyld.com>)
+ *              Crynwr packet driver by
+ *                      Krishnan Gopalan and Gregg Stefancik,
+ *                      Clemson University Engineering Computer Operations.
+ *                      Portions of the code have been adapted from the 3c505
+ *                         driver for NCSA Telnet by Bruce Orchard and later
+ *                         modified by Warren Van Houten and krus@diku.dk.
+ *              3C505 technical information provided by
+ *                      Terry Murphy, of 3Com Network Adapter Division
+ *              Linux 1.3.0 changes by
+ *                      Alan Cox <Alan.Cox@linux.org>
+ *              More debugging, DMA support, currently maintained by
+ *                      Philip Blundell <philb@gnu.org>
+ *              Multicard/soft configurable dma channel/rev 2 hardware support
+ *                      by Christopher Collins <ccollins@pcug.org.au>
+ *             Ethtool support (jgarzik), 11/17/2001
+ */
+
+#define DRV_NAME       "3c505"
+#define DRV_VERSION    "1.10a"
+
+
+/* Theory of operation:
+ *
+ * The 3c505 is quite an intelligent board.  All communication with it is done
+ * by means of Primary Command Blocks (PCBs); these are transferred using PIO
+ * through the command register.  The card has 256k of on-board RAM, which is
+ * used to buffer received packets.  It might seem at first that more buffers
+ * are better, but in fact this isn't true.  From my tests, it seems that
+ * more than about 10 buffers are unnecessary, and there is a noticeable
+ * performance hit in having more active on the card.  So the majority of the
+ * card's memory isn't, in fact, used.  Sadly, the card only has one transmit
+ * buffer and, short of loading our own firmware into it (which is what some
+ * drivers resort to) there's nothing we can do about this.
+ *
+ * We keep up to 4 "receive packet" commands active on the board at a time.
+ * When a packet comes in, so long as there is a receive command active, the
+ * board will send us a "packet received" PCB and then add the data for that
+ * packet to the DMA queue.  If a DMA transfer is not already in progress, we
+ * set one up to start uploading the data.  We have to maintain a list of
+ * backlogged receive packets, because the card may decide to tell us about
+ * a newly-arrived packet at any time, and we may not be able to start a DMA
+ * transfer immediately (ie one may already be going on).  We can't NAK the
+ * PCB, because then it would throw the packet away.
+ *
+ * Trying to send a PCB to the card at the wrong moment seems to have bad
+ * effects.  If we send it a transmit PCB while a receive DMA is happening,
+ * it will just NAK the PCB and so we will have wasted our time.  Worse, it
+ * sometimes seems to interrupt the transfer.  The majority of the low-level
+ * code is protected by one huge semaphore -- "busy" -- which is set whenever
+ * it probably isn't safe to do anything to the card.  The receive routine
+ * must gain a lock on "busy" before it can start a DMA transfer, and the
+ * transmit routine must gain a lock before it sends the first PCB to the card.
+ * The send_pcb() routine also has an internal semaphore to protect it against
+ * being re-entered (which would be disastrous) -- this is needed because
+ * several things can happen asynchronously (re-priming the receiver and
+ * asking the card for statistics, for example).  send_pcb() will also refuse
+ * to talk to the card at all if a DMA upload is happening.  The higher-level
+ * networking code will reschedule a later retry if some part of the driver
+ * is blocked.  In practice, this doesn't seem to happen very often.
+ */
+
+/* This driver may now work with revision 2.x hardware, since all the read
+ * operations on the HCR have been removed (we now keep our own softcopy).
+ * But I don't have an old card to test it on.
+ *
+ * This has had the bad effect that the autoprobe routine is now a bit
+ * less friendly to other devices.  However, it was never very good.
+ * before, so I doubt it will hurt anybody.
+ */
+
+/* The driver is a mess.  I took Craig's and Juha's code, and hacked it firstly
+ * to make it more reliable, and secondly to add DMA mode.  Many things could
+ * probably be done better; the concurrency protection is particularly awful.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/in.h>
+#include <linux/ioport.h>
+#include <linux/spinlock.h>
+#include <linux/ethtool.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+#include <linux/gfp.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+
+#include "3c505.h"
+
+/*********************************************************
+ *
+ *  define debug messages here as common strings to reduce space
+ *
+ *********************************************************/
+
+#define filename __FILE__
+
+#define timeout_msg "*** timeout at %s:%s (line %d) ***\n"
+#define TIMEOUT_MSG(lineno) \
+       pr_notice(timeout_msg, filename, __func__, (lineno))
+
+#define invalid_pcb_msg "*** invalid pcb length %d at %s:%s (line %d) ***\n"
+#define INVALID_PCB_MSG(len) \
+       pr_notice(invalid_pcb_msg, (len), filename, __func__, __LINE__)
+
+#define search_msg "%s: Looking for 3c505 adapter at address %#x..."
+
+#define stilllooking_msg "still looking..."
+
+#define found_msg "found.\n"
+
+#define notfound_msg "not found (reason = %d)\n"
+
+#define couldnot_msg "%s: 3c505 not found\n"
+
+/*********************************************************
+ *
+ *  various other debug stuff
+ *
+ *********************************************************/
+
+#ifdef ELP_DEBUG
+static int elp_debug = ELP_DEBUG;
+#else
+static int elp_debug;
+#endif
+#define debug elp_debug
+
+/*
+ *  0 = no messages (well, some)
+ *  1 = messages when high level commands performed
+ *  2 = messages when low level commands performed
+ *  3 = messages when interrupts received
+ */
+
+/*****************************************************************
+ *
+ * List of I/O-addresses we try to auto-sense
+ * Last element MUST BE 0!
+ *****************************************************************/
+
+static int addr_list[] __initdata = {0x300, 0x280, 0x310, 0};
+
+/* Dma Memory related stuff */
+
+static unsigned long dma_mem_alloc(int size)
+{
+       int order = get_order(size);
+       return __get_dma_pages(GFP_KERNEL, order);
+}
+
+
+/*****************************************************************
+ *
+ * Functions for I/O (note the inline !)
+ *
+ *****************************************************************/
+
+static inline unsigned char inb_status(unsigned int base_addr)
+{
+       return inb(base_addr + PORT_STATUS);
+}
+
+static inline int inb_command(unsigned int base_addr)
+{
+       return inb(base_addr + PORT_COMMAND);
+}
+
+static inline void outb_control(unsigned char val, struct net_device *dev)
+{
+       outb(val, dev->base_addr + PORT_CONTROL);
+       ((elp_device *)(netdev_priv(dev)))->hcr_val = val;
+}
+
+#define HCR_VAL(x)   (((elp_device *)(netdev_priv(x)))->hcr_val)
+
+static inline void outb_command(unsigned char val, unsigned int base_addr)
+{
+       outb(val, base_addr + PORT_COMMAND);
+}
+
+static inline unsigned int backlog_next(unsigned int n)
+{
+       return (n + 1) % BACKLOG_SIZE;
+}
+
+/*****************************************************************
+ *
+ *  useful functions for accessing the adapter
+ *
+ *****************************************************************/
+
+/*
+ * use this routine when accessing the ASF bits as they are
+ * changed asynchronously by the adapter
+ */
+
+/* get adapter PCB status */
+#define        GET_ASF(addr) \
+       (get_status(addr)&ASF_PCB_MASK)
+
+static inline int get_status(unsigned int base_addr)
+{
+       unsigned long timeout = jiffies + 10*HZ/100;
+       register int stat1;
+       do {
+               stat1 = inb_status(base_addr);
+       } while (stat1 != inb_status(base_addr) && time_before(jiffies, timeout));
+       if (time_after_eq(jiffies, timeout))
+               TIMEOUT_MSG(__LINE__);
+       return stat1;
+}
+
+static inline void set_hsf(struct net_device *dev, int hsf)
+{
+       elp_device *adapter = netdev_priv(dev);
+       unsigned long flags;
+
+       spin_lock_irqsave(&adapter->lock, flags);
+       outb_control((HCR_VAL(dev) & ~HSF_PCB_MASK) | hsf, dev);
+       spin_unlock_irqrestore(&adapter->lock, flags);
+}
+
+static bool start_receive(struct net_device *, pcb_struct *);
+
+static inline void adapter_reset(struct net_device *dev)
+{
+       unsigned long timeout;
+       elp_device *adapter = netdev_priv(dev);
+       unsigned char orig_hcr = adapter->hcr_val;
+
+       outb_control(0, dev);
+
+       if (inb_status(dev->base_addr) & ACRF) {
+               do {
+                       inb_command(dev->base_addr);
+                       timeout = jiffies + 2*HZ/100;
+                       while (time_before_eq(jiffies, timeout) && !(inb_status(dev->base_addr) & ACRF));
+               } while (inb_status(dev->base_addr) & ACRF);
+               set_hsf(dev, HSF_PCB_NAK);
+       }
+       outb_control(adapter->hcr_val | ATTN | DIR, dev);
+       mdelay(10);
+       outb_control(adapter->hcr_val & ~ATTN, dev);
+       mdelay(10);
+       outb_control(adapter->hcr_val | FLSH, dev);
+       mdelay(10);
+       outb_control(adapter->hcr_val & ~FLSH, dev);
+       mdelay(10);
+
+       outb_control(orig_hcr, dev);
+       if (!start_receive(dev, &adapter->tx_pcb))
+               pr_err("%s: start receive command failed\n", dev->name);
+}
+
+/* Check to make sure that a DMA transfer hasn't timed out.  This should
+ * never happen in theory, but seems to occur occasionally if the card gets
+ * prodded at the wrong time.
+ */
+static inline void check_3c505_dma(struct net_device *dev)
+{
+       elp_device *adapter = netdev_priv(dev);
+       if (adapter->dmaing && time_after(jiffies, adapter->current_dma.start_time + 10)) {
+               unsigned long flags, f;
+               pr_err("%s: DMA %s timed out, %d bytes left\n", dev->name,
+                       adapter->current_dma.direction ? "download" : "upload",
+                       get_dma_residue(dev->dma));
+               spin_lock_irqsave(&adapter->lock, flags);
+               adapter->dmaing = 0;
+               adapter->busy = 0;
+
+               f=claim_dma_lock();
+               disable_dma(dev->dma);
+               release_dma_lock(f);
+
+               if (adapter->rx_active)
+                       adapter->rx_active--;
+               outb_control(adapter->hcr_val & ~(DMAE | TCEN | DIR), dev);
+               spin_unlock_irqrestore(&adapter->lock, flags);
+       }
+}
+
+/* Primitive functions used by send_pcb() */
+static inline bool send_pcb_slow(unsigned int base_addr, unsigned char byte)
+{
+       unsigned long timeout;
+       outb_command(byte, base_addr);
+       for (timeout = jiffies + 5*HZ/100; time_before(jiffies, timeout);) {
+               if (inb_status(base_addr) & HCRE)
+                       return false;
+       }
+       pr_warning("3c505: send_pcb_slow timed out\n");
+       return true;
+}
+
+static inline bool send_pcb_fast(unsigned int base_addr, unsigned char byte)
+{
+       unsigned int timeout;
+       outb_command(byte, base_addr);
+       for (timeout = 0; timeout < 40000; timeout++) {
+               if (inb_status(base_addr) & HCRE)
+                       return false;
+       }
+       pr_warning("3c505: send_pcb_fast timed out\n");
+       return true;
+}
+
+/* Check to see if the receiver needs restarting, and kick it if so */
+static inline void prime_rx(struct net_device *dev)
+{
+       elp_device *adapter = netdev_priv(dev);
+       while (adapter->rx_active < ELP_RX_PCBS && netif_running(dev)) {
+               if (!start_receive(dev, &adapter->itx_pcb))
+                       break;
+       }
+}
+
+/*****************************************************************
+ *
+ * send_pcb
+ *   Send a PCB to the adapter.
+ *
+ *     output byte to command reg  --<--+
+ *     wait until HCRE is non zero      |
+ *     loop until all bytes sent   -->--+
+ *     set HSF1 and HSF2 to 1
+ *     output pcb length
+ *     wait until ASF give ACK or NAK
+ *     set HSF1 and HSF2 to 0
+ *
+ *****************************************************************/
+
+/* This can be quite slow -- the adapter is allowed to take up to 40ms
+ * to respond to the initial interrupt.
+ *
+ * We run initially with interrupts turned on, but with a semaphore set
+ * so that nobody tries to re-enter this code.  Once the first byte has
+ * gone through, we turn interrupts off and then send the others (the
+ * timeout is reduced to 500us).
+ */
+
+static bool send_pcb(struct net_device *dev, pcb_struct * pcb)
+{
+       int i;
+       unsigned long timeout;
+       elp_device *adapter = netdev_priv(dev);
+       unsigned long flags;
+
+       check_3c505_dma(dev);
+
+       if (adapter->dmaing && adapter->current_dma.direction == 0)
+               return false;
+
+       /* Avoid contention */
+       if (test_and_set_bit(1, &adapter->send_pcb_semaphore)) {
+               if (elp_debug >= 3) {
+                       pr_debug("%s: send_pcb entered while threaded\n", dev->name);
+               }
+               return false;
+       }
+       /*
+        * load each byte into the command register and
+        * wait for the HCRE bit to indicate the adapter
+        * had read the byte
+        */
+       set_hsf(dev, 0);
+
+       if (send_pcb_slow(dev->base_addr, pcb->command))
+               goto abort;
+
+       spin_lock_irqsave(&adapter->lock, flags);
+
+       if (send_pcb_fast(dev->base_addr, pcb->length))
+               goto sti_abort;
+
+       for (i = 0; i < pcb->length; i++) {
+               if (send_pcb_fast(dev->base_addr, pcb->data.raw[i]))
+                       goto sti_abort;
+       }
+
+       outb_control(adapter->hcr_val | 3, dev);        /* signal end of PCB */
+       outb_command(2 + pcb->length, dev->base_addr);
+
+       /* now wait for the acknowledgement */
+       spin_unlock_irqrestore(&adapter->lock, flags);
+
+       for (timeout = jiffies + 5*HZ/100; time_before(jiffies, timeout);) {
+               switch (GET_ASF(dev->base_addr)) {
+               case ASF_PCB_ACK:
+                       adapter->send_pcb_semaphore = 0;
+                       return true;
+
+               case ASF_PCB_NAK:
+#ifdef ELP_DEBUG
+                       pr_debug("%s: send_pcb got NAK\n", dev->name);
+#endif
+                       goto abort;
+               }
+       }
+
+       if (elp_debug >= 1)
+               pr_debug("%s: timeout waiting for PCB acknowledge (status %02x)\n",
+                       dev->name, inb_status(dev->base_addr));
+       goto abort;
+
+      sti_abort:
+       spin_unlock_irqrestore(&adapter->lock, flags);
+      abort:
+       adapter->send_pcb_semaphore = 0;
+       return false;
+}
+
+
+/*****************************************************************
+ *
+ * receive_pcb
+ *   Read a PCB from the adapter
+ *
+ *     wait for ACRF to be non-zero        ---<---+
+ *     input a byte                               |
+ *     if ASF1 and ASF2 were not both one         |
+ *             before byte was read, loop      --->---+
+ *     set HSF1 and HSF2 for ack
+ *
+ *****************************************************************/
+
+static bool receive_pcb(struct net_device *dev, pcb_struct * pcb)
+{
+       int i, j;
+       int total_length;
+       int stat;
+       unsigned long timeout;
+       unsigned long flags;
+
+       elp_device *adapter = netdev_priv(dev);
+
+       set_hsf(dev, 0);
+
+       /* get the command code */
+       timeout = jiffies + 2*HZ/100;
+       while (((stat = get_status(dev->base_addr)) & ACRF) == 0 && time_before(jiffies, timeout));
+       if (time_after_eq(jiffies, timeout)) {
+               TIMEOUT_MSG(__LINE__);
+               return false;
+       }
+       pcb->command = inb_command(dev->base_addr);
+
+       /* read the data length */
+       timeout = jiffies + 3*HZ/100;
+       while (((stat = get_status(dev->base_addr)) & ACRF) == 0 && time_before(jiffies, timeout));
+       if (time_after_eq(jiffies, timeout)) {
+               TIMEOUT_MSG(__LINE__);
+               pr_info("%s: status %02x\n", dev->name, stat);
+               return false;
+       }
+       pcb->length = inb_command(dev->base_addr);
+
+       if (pcb->length > MAX_PCB_DATA) {
+               INVALID_PCB_MSG(pcb->length);
+               adapter_reset(dev);
+               return false;
+       }
+       /* read the data */
+       spin_lock_irqsave(&adapter->lock, flags);
+       for (i = 0; i < MAX_PCB_DATA; i++) {
+               for (j = 0; j < 20000; j++) {
+                       stat = get_status(dev->base_addr);
+                       if (stat & ACRF)
+                               break;
+               }
+               pcb->data.raw[i] = inb_command(dev->base_addr);
+               if ((stat & ASF_PCB_MASK) == ASF_PCB_END || j >= 20000)
+                       break;
+       }
+       spin_unlock_irqrestore(&adapter->lock, flags);
+       if (i >= MAX_PCB_DATA) {
+               INVALID_PCB_MSG(i);
+               return false;
+       }
+       if (j >= 20000) {
+               TIMEOUT_MSG(__LINE__);
+               return false;
+       }
+       /* the last "data" byte was really the length! */
+       total_length = pcb->data.raw[i];
+
+       /* safety check total length vs data length */
+       if (total_length != (pcb->length + 2)) {
+               if (elp_debug >= 2)
+                       pr_warning("%s: mangled PCB received\n", dev->name);
+               set_hsf(dev, HSF_PCB_NAK);
+               return false;
+       }
+
+       if (pcb->command == CMD_RECEIVE_PACKET_COMPLETE) {
+               if (test_and_set_bit(0, (void *) &adapter->busy)) {
+                       if (backlog_next(adapter->rx_backlog.in) == adapter->rx_backlog.out) {
+                               set_hsf(dev, HSF_PCB_NAK);
+                               pr_warning("%s: PCB rejected, transfer in progress and backlog full\n", dev->name);
+                               pcb->command = 0;
+                               return true;
+                       } else {
+                               pcb->command = 0xff;
+                       }
+               }
+       }
+       set_hsf(dev, HSF_PCB_ACK);
+       return true;
+}
+
+/******************************************************
+ *
+ *  queue a receive command on the adapter so we will get an
+ *  interrupt when a packet is received.
+ *
+ ******************************************************/
+
+static bool start_receive(struct net_device *dev, pcb_struct * tx_pcb)
+{
+       bool status;
+       elp_device *adapter = netdev_priv(dev);
+
+       if (elp_debug >= 3)
+               pr_debug("%s: restarting receiver\n", dev->name);
+       tx_pcb->command = CMD_RECEIVE_PACKET;
+       tx_pcb->length = sizeof(struct Rcv_pkt);
+       tx_pcb->data.rcv_pkt.buf_seg
+           = tx_pcb->data.rcv_pkt.buf_ofs = 0;         /* Unused */
+       tx_pcb->data.rcv_pkt.buf_len = 1600;
+       tx_pcb->data.rcv_pkt.timeout = 0;       /* set timeout to zero */
+       status = send_pcb(dev, tx_pcb);
+       if (status)
+               adapter->rx_active++;
+       return status;
+}
+
+/******************************************************
+ *
+ * extract a packet from the adapter
+ * this routine is only called from within the interrupt
+ * service routine, so no cli/sti calls are needed
+ * note that the length is always assumed to be even
+ *
+ ******************************************************/
+
+static void receive_packet(struct net_device *dev, int len)
+{
+       int rlen;
+       elp_device *adapter = netdev_priv(dev);
+       void *target;
+       struct sk_buff *skb;
+       unsigned long flags;
+
+       rlen = (len + 1) & ~1;
+       skb = dev_alloc_skb(rlen + 2);
+
+       if (!skb) {
+               pr_warning("%s: memory squeeze, dropping packet\n", dev->name);
+               target = adapter->dma_buffer;
+               adapter->current_dma.target = NULL;
+               /* FIXME: stats */
+               return;
+       }
+
+       skb_reserve(skb, 2);
+       target = skb_put(skb, rlen);
+       if ((unsigned long)(target + rlen) >= MAX_DMA_ADDRESS) {
+               adapter->current_dma.target = target;
+               target = adapter->dma_buffer;
+       } else {
+               adapter->current_dma.target = NULL;
+       }
+
+       /* if this happens, we die */
+       if (test_and_set_bit(0, (void *) &adapter->dmaing))
+               pr_err("%s: rx blocked, DMA in progress, dir %d\n",
+                       dev->name, adapter->current_dma.direction);
+
+       adapter->current_dma.direction = 0;
+       adapter->current_dma.length = rlen;
+       adapter->current_dma.skb = skb;
+       adapter->current_dma.start_time = jiffies;
+
+       outb_control(adapter->hcr_val | DIR | TCEN | DMAE, dev);
+
+       flags=claim_dma_lock();
+       disable_dma(dev->dma);
+       clear_dma_ff(dev->dma);
+       set_dma_mode(dev->dma, 0x04);   /* dma read */
+       set_dma_addr(dev->dma, isa_virt_to_bus(target));
+       set_dma_count(dev->dma, rlen);
+       enable_dma(dev->dma);
+       release_dma_lock(flags);
+
+       if (elp_debug >= 3) {
+               pr_debug("%s: rx DMA transfer started\n", dev->name);
+       }
+
+       if (adapter->rx_active)
+               adapter->rx_active--;
+
+       if (!adapter->busy)
+               pr_warning("%s: receive_packet called, busy not set.\n", dev->name);
+}
+
+/******************************************************
+ *
+ * interrupt handler
+ *
+ ******************************************************/
+
+static irqreturn_t elp_interrupt(int irq, void *dev_id)
+{
+       int len;
+       int dlen;
+       int icount = 0;
+       struct net_device *dev = dev_id;
+       elp_device *adapter = netdev_priv(dev);
+       unsigned long timeout;
+
+       spin_lock(&adapter->lock);
+
+       do {
+               /*
+                * has a DMA transfer finished?
+                */
+               if (inb_status(dev->base_addr) & DONE) {
+                       if (!adapter->dmaing)
+                               pr_warning("%s: phantom DMA completed\n", dev->name);
+
+                       if (elp_debug >= 3)
+                               pr_debug("%s: %s DMA complete, status %02x\n", dev->name,
+                                       adapter->current_dma.direction ? "tx" : "rx",
+                                       inb_status(dev->base_addr));
+
+                       outb_control(adapter->hcr_val & ~(DMAE | TCEN | DIR), dev);
+                       if (adapter->current_dma.direction) {
+                               dev_kfree_skb_irq(adapter->current_dma.skb);
+                       } else {
+                               struct sk_buff *skb = adapter->current_dma.skb;
+                               if (skb) {
+                                       if (adapter->current_dma.target) {
+                                       /* have already done the skb_put() */
+                                       memcpy(adapter->current_dma.target, adapter->dma_buffer, adapter->current_dma.length);
+                                       }
+                                       skb->protocol = eth_type_trans(skb,dev);
+                                       dev->stats.rx_bytes += skb->len;
+                                       netif_rx(skb);
+                               }
+                       }
+                       adapter->dmaing = 0;
+                       if (adapter->rx_backlog.in != adapter->rx_backlog.out) {
+                               int t = adapter->rx_backlog.length[adapter->rx_backlog.out];
+                               adapter->rx_backlog.out = backlog_next(adapter->rx_backlog.out);
+                               if (elp_debug >= 2)
+                                       pr_debug("%s: receiving backlogged packet (%d)\n", dev->name, t);
+                               receive_packet(dev, t);
+                       } else {
+                               adapter->busy = 0;
+                       }
+               } else {
+                       /* has one timed out? */
+                       check_3c505_dma(dev);
+               }
+
+               /*
+                * receive a PCB from the adapter
+                */
+               timeout = jiffies + 3*HZ/100;
+               while ((inb_status(dev->base_addr) & ACRF) != 0 && time_before(jiffies, timeout)) {
+                       if (receive_pcb(dev, &adapter->irx_pcb)) {
+                               switch (adapter->irx_pcb.command)
+                               {
+                               case 0:
+                                       break;
+                                       /*
+                                        * received a packet - this must be handled fast
+                                        */
+                               case 0xff:
+                               case CMD_RECEIVE_PACKET_COMPLETE:
+                                       /* if the device isn't open, don't pass packets up the stack */
+                                       if (!netif_running(dev))
+                                               break;
+                                       len = adapter->irx_pcb.data.rcv_resp.pkt_len;
+                                       dlen = adapter->irx_pcb.data.rcv_resp.buf_len;
+                                       if (adapter->irx_pcb.data.rcv_resp.timeout != 0) {
+                                               pr_err("%s: interrupt - packet not received correctly\n", dev->name);
+                                       } else {
+                                               if (elp_debug >= 3) {
+                                                       pr_debug("%s: interrupt - packet received of length %i (%i)\n",
+                                                               dev->name, len, dlen);
+                                               }
+                                               if (adapter->irx_pcb.command == 0xff) {
+                                                       if (elp_debug >= 2)
+                                                               pr_debug("%s: adding packet to backlog (len = %d)\n",
+                                                                       dev->name, dlen);
+                                                       adapter->rx_backlog.length[adapter->rx_backlog.in] = dlen;
+                                                       adapter->rx_backlog.in = backlog_next(adapter->rx_backlog.in);
+                                               } else {
+                                                       receive_packet(dev, dlen);
+                                               }
+                                               if (elp_debug >= 3)
+                                                       pr_debug("%s: packet received\n", dev->name);
+                                       }
+                                       break;
+
+                                       /*
+                                        * 82586 configured correctly
+                                        */
+                               case CMD_CONFIGURE_82586_RESPONSE:
+                                       adapter->got[CMD_CONFIGURE_82586] = 1;
+                                       if (elp_debug >= 3)
+                                               pr_debug("%s: interrupt - configure response received\n", dev->name);
+                                       break;
+
+                                       /*
+                                        * Adapter memory configuration
+                                        */
+                               case CMD_CONFIGURE_ADAPTER_RESPONSE:
+                                       adapter->got[CMD_CONFIGURE_ADAPTER_MEMORY] = 1;
+                                       if (elp_debug >= 3)
+                                               pr_debug("%s: Adapter memory configuration %s.\n", dev->name,
+                                                      adapter->irx_pcb.data.failed ? "failed" : "succeeded");
+                                       break;
+
+                                       /*
+                                        * Multicast list loading
+                                        */
+                               case CMD_LOAD_MULTICAST_RESPONSE:
+                                       adapter->got[CMD_LOAD_MULTICAST_LIST] = 1;
+                                       if (elp_debug >= 3)
+                                               pr_debug("%s: Multicast address list loading %s.\n", dev->name,
+                                                      adapter->irx_pcb.data.failed ? "failed" : "succeeded");
+                                       break;
+
+                                       /*
+                                        * Station address setting
+                                        */
+                               case CMD_SET_ADDRESS_RESPONSE:
+                                       adapter->got[CMD_SET_STATION_ADDRESS] = 1;
+                                       if (elp_debug >= 3)
+                                               pr_debug("%s: Ethernet address setting %s.\n", dev->name,
+                                                      adapter->irx_pcb.data.failed ? "failed" : "succeeded");
+                                       break;
+
+
+                                       /*
+                                        * received board statistics
+                                        */
+                               case CMD_NETWORK_STATISTICS_RESPONSE:
+                                       dev->stats.rx_packets += adapter->irx_pcb.data.netstat.tot_recv;
+                                       dev->stats.tx_packets += adapter->irx_pcb.data.netstat.tot_xmit;
+                                       dev->stats.rx_crc_errors += adapter->irx_pcb.data.netstat.err_CRC;
+                                       dev->stats.rx_frame_errors += adapter->irx_pcb.data.netstat.err_align;
+                                       dev->stats.rx_fifo_errors += adapter->irx_pcb.data.netstat.err_ovrrun;
+                                       dev->stats.rx_over_errors += adapter->irx_pcb.data.netstat.err_res;
+                                       adapter->got[CMD_NETWORK_STATISTICS] = 1;
+                                       if (elp_debug >= 3)
+                                               pr_debug("%s: interrupt - statistics response received\n", dev->name);
+                                       break;
+
+                                       /*
+                                        * sent a packet
+                                        */
+                               case CMD_TRANSMIT_PACKET_COMPLETE:
+                                       if (elp_debug >= 3)
+                                               pr_debug("%s: interrupt - packet sent\n", dev->name);
+                                       if (!netif_running(dev))
+                                               break;
+                                       switch (adapter->irx_pcb.data.xmit_resp.c_stat) {
+                                       case 0xffff:
+                                               dev->stats.tx_aborted_errors++;
+                                               pr_info("%s: transmit timed out, network cable problem?\n", dev->name);
+                                               break;
+                                       case 0xfffe:
+                                               dev->stats.tx_fifo_errors++;
+                                               pr_info("%s: transmit timed out, FIFO underrun\n", dev->name);
+                                               break;
+                                       }
+                                       netif_wake_queue(dev);
+                                       break;
+
+                                       /*
+                                        * some unknown PCB
+                                        */
+                               default:
+                                       pr_debug("%s: unknown PCB received - %2.2x\n",
+                                               dev->name, adapter->irx_pcb.command);
+                                       break;
+                               }
+                       } else {
+                               pr_warning("%s: failed to read PCB on interrupt\n", dev->name);
+                               adapter_reset(dev);
+                       }
+               }
+
+       } while (icount++ < 5 && (inb_status(dev->base_addr) & (ACRF | DONE)));
+
+       prime_rx(dev);
+
+       /*
+        * indicate no longer in interrupt routine
+        */
+       spin_unlock(&adapter->lock);
+       return IRQ_HANDLED;
+}
+
+
+/******************************************************
+ *
+ * open the board
+ *
+ ******************************************************/
+
+static int elp_open(struct net_device *dev)
+{
+       elp_device *adapter = netdev_priv(dev);
+       int retval;
+
+       if (elp_debug >= 3)
+               pr_debug("%s: request to open device\n", dev->name);
+
+       /*
+        * make sure we actually found the device
+        */
+       if (adapter == NULL) {
+               pr_err("%s: Opening a non-existent physical device\n", dev->name);
+               return -EAGAIN;
+       }
+       /*
+        * disable interrupts on the board
+        */
+       outb_control(0, dev);
+
+       /*
+        * clear any pending interrupts
+        */
+       inb_command(dev->base_addr);
+       adapter_reset(dev);
+
+       /*
+        * no receive PCBs active
+        */
+       adapter->rx_active = 0;
+
+       adapter->busy = 0;
+       adapter->send_pcb_semaphore = 0;
+       adapter->rx_backlog.in = 0;
+       adapter->rx_backlog.out = 0;
+
+       spin_lock_init(&adapter->lock);
+
+       /*
+        * install our interrupt service routine
+        */
+       if ((retval = request_irq(dev->irq, elp_interrupt, 0, dev->name, dev))) {
+               pr_err("%s: could not allocate IRQ%d\n", dev->name, dev->irq);
+               return retval;
+       }
+       if ((retval = request_dma(dev->dma, dev->name))) {
+               free_irq(dev->irq, dev);
+               pr_err("%s: could not allocate DMA%d channel\n", dev->name, dev->dma);
+               return retval;
+       }
+       adapter->dma_buffer = (void *) dma_mem_alloc(DMA_BUFFER_SIZE);
+       if (!adapter->dma_buffer) {
+               pr_err("%s: could not allocate DMA buffer\n", dev->name);
+               free_dma(dev->dma);
+               free_irq(dev->irq, dev);
+               return -ENOMEM;
+       }
+       adapter->dmaing = 0;
+
+       /*
+        * enable interrupts on the board
+        */
+       outb_control(CMDE, dev);
+
+       /*
+        * configure adapter memory: we need 10 multicast addresses, default==0
+        */
+       if (elp_debug >= 3)
+               pr_debug("%s: sending 3c505 memory configuration command\n", dev->name);
+       adapter->tx_pcb.command = CMD_CONFIGURE_ADAPTER_MEMORY;
+       adapter->tx_pcb.data.memconf.cmd_q = 10;
+       adapter->tx_pcb.data.memconf.rcv_q = 20;
+       adapter->tx_pcb.data.memconf.mcast = 10;
+       adapter->tx_pcb.data.memconf.frame = 20;
+       adapter->tx_pcb.data.memconf.rcv_b = 20;
+       adapter->tx_pcb.data.memconf.progs = 0;
+       adapter->tx_pcb.length = sizeof(struct Memconf);
+       adapter->got[CMD_CONFIGURE_ADAPTER_MEMORY] = 0;
+       if (!send_pcb(dev, &adapter->tx_pcb))
+               pr_err("%s: couldn't send memory configuration command\n", dev->name);
+       else {
+               unsigned long timeout = jiffies + TIMEOUT;
+               while (adapter->got[CMD_CONFIGURE_ADAPTER_MEMORY] == 0 && time_before(jiffies, timeout));
+               if (time_after_eq(jiffies, timeout))
+                       TIMEOUT_MSG(__LINE__);
+       }
+
+
+       /*
+        * configure adapter to receive broadcast messages and wait for response
+        */
+       if (elp_debug >= 3)
+               pr_debug("%s: sending 82586 configure command\n", dev->name);
+       adapter->tx_pcb.command = CMD_CONFIGURE_82586;
+       adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_BROAD;
+       adapter->tx_pcb.length = 2;
+       adapter->got[CMD_CONFIGURE_82586] = 0;
+       if (!send_pcb(dev, &adapter->tx_pcb))
+               pr_err("%s: couldn't send 82586 configure command\n", dev->name);
+       else {
+               unsigned long timeout = jiffies + TIMEOUT;
+               while (adapter->got[CMD_CONFIGURE_82586] == 0 && time_before(jiffies, timeout));
+               if (time_after_eq(jiffies, timeout))
+                       TIMEOUT_MSG(__LINE__);
+       }
+
+       /* enable burst-mode DMA */
+       /* outb(0x1, dev->base_addr + PORT_AUXDMA); */
+
+       /*
+        * queue receive commands to provide buffering
+        */
+       prime_rx(dev);
+       if (elp_debug >= 3)
+               pr_debug("%s: %d receive PCBs active\n", dev->name, adapter->rx_active);
+
+       /*
+        * device is now officially open!
+        */
+
+       netif_start_queue(dev);
+       return 0;
+}
+
+
+/******************************************************
+ *
+ * send a packet to the adapter
+ *
+ ******************************************************/
+
+static netdev_tx_t send_packet(struct net_device *dev, struct sk_buff *skb)
+{
+       elp_device *adapter = netdev_priv(dev);
+       unsigned long target;
+       unsigned long flags;
+
+       /*
+        * make sure the length is even and no shorter than 60 bytes
+        */
+       unsigned int nlen = (((skb->len < 60) ? 60 : skb->len) + 1) & (~1);
+
+       if (test_and_set_bit(0, (void *) &adapter->busy)) {
+               if (elp_debug >= 2)
+                       pr_debug("%s: transmit blocked\n", dev->name);
+               return false;
+       }
+
+       dev->stats.tx_bytes += nlen;
+
+       /*
+        * send the adapter a transmit packet command. Ignore segment and offset
+        * and make sure the length is even
+        */
+       adapter->tx_pcb.command = CMD_TRANSMIT_PACKET;
+       adapter->tx_pcb.length = sizeof(struct Xmit_pkt);
+       adapter->tx_pcb.data.xmit_pkt.buf_ofs
+           = adapter->tx_pcb.data.xmit_pkt.buf_seg = 0;        /* Unused */
+       adapter->tx_pcb.data.xmit_pkt.pkt_len = nlen;
+
+       if (!send_pcb(dev, &adapter->tx_pcb)) {
+               adapter->busy = 0;
+               return false;
+       }
+       /* if this happens, we die */
+       if (test_and_set_bit(0, (void *) &adapter->dmaing))
+               pr_debug("%s: tx: DMA %d in progress\n", dev->name, adapter->current_dma.direction);
+
+       adapter->current_dma.direction = 1;
+       adapter->current_dma.start_time = jiffies;
+
+       if ((unsigned long)(skb->data + nlen) >= MAX_DMA_ADDRESS || nlen != skb->len) {
+               skb_copy_from_linear_data(skb, adapter->dma_buffer, nlen);
+               memset(adapter->dma_buffer+skb->len, 0, nlen-skb->len);
+               target = isa_virt_to_bus(adapter->dma_buffer);
+       }
+       else {
+               target = isa_virt_to_bus(skb->data);
+       }
+       adapter->current_dma.skb = skb;
+
+       flags=claim_dma_lock();
+       disable_dma(dev->dma);
+       clear_dma_ff(dev->dma);
+       set_dma_mode(dev->dma, 0x48);   /* dma memory -> io */
+       set_dma_addr(dev->dma, target);
+       set_dma_count(dev->dma, nlen);
+       outb_control(adapter->hcr_val | DMAE | TCEN, dev);
+       enable_dma(dev->dma);
+       release_dma_lock(flags);
+
+       if (elp_debug >= 3)
+               pr_debug("%s: DMA transfer started\n", dev->name);
+
+       return true;
+}
+
+/*
+ *     The upper layer thinks we timed out
+ */
+
+static void elp_timeout(struct net_device *dev)
+{
+       int stat;
+
+       stat = inb_status(dev->base_addr);
+       pr_warning("%s: transmit timed out, lost %s?\n", dev->name,
+                  (stat & ACRF) ? "interrupt" : "command");
+       if (elp_debug >= 1)
+               pr_debug("%s: status %#02x\n", dev->name, stat);
+       dev->trans_start = jiffies; /* prevent tx timeout */
+       dev->stats.tx_dropped++;
+       netif_wake_queue(dev);
+}
+
+/******************************************************
+ *
+ * start the transmitter
+ *    return 0 if sent OK, else return 1
+ *
+ ******************************************************/
+
+static netdev_tx_t elp_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       unsigned long flags;
+       elp_device *adapter = netdev_priv(dev);
+
+       spin_lock_irqsave(&adapter->lock, flags);
+       check_3c505_dma(dev);
+
+       if (elp_debug >= 3)
+               pr_debug("%s: request to send packet of length %d\n", dev->name, (int) skb->len);
+
+       netif_stop_queue(dev);
+
+       /*
+        * send the packet at skb->data for skb->len
+        */
+       if (!send_packet(dev, skb)) {
+               if (elp_debug >= 2) {
+                       pr_debug("%s: failed to transmit packet\n", dev->name);
+               }
+               spin_unlock_irqrestore(&adapter->lock, flags);
+               return NETDEV_TX_BUSY;
+       }
+       if (elp_debug >= 3)
+               pr_debug("%s: packet of length %d sent\n", dev->name, (int) skb->len);
+
+       prime_rx(dev);
+       spin_unlock_irqrestore(&adapter->lock, flags);
+       netif_start_queue(dev);
+       return NETDEV_TX_OK;
+}
+
+/******************************************************
+ *
+ * return statistics on the board
+ *
+ ******************************************************/
+
+static struct net_device_stats *elp_get_stats(struct net_device *dev)
+{
+       elp_device *adapter = netdev_priv(dev);
+
+       if (elp_debug >= 3)
+               pr_debug("%s: request for stats\n", dev->name);
+
+       /* If the device is closed, just return the latest stats we have,
+          - we cannot ask from the adapter without interrupts */
+       if (!netif_running(dev))
+               return &dev->stats;
+
+       /* send a get statistics command to the board */
+       adapter->tx_pcb.command = CMD_NETWORK_STATISTICS;
+       adapter->tx_pcb.length = 0;
+       adapter->got[CMD_NETWORK_STATISTICS] = 0;
+       if (!send_pcb(dev, &adapter->tx_pcb))
+               pr_err("%s: couldn't send get statistics command\n", dev->name);
+       else {
+               unsigned long timeout = jiffies + TIMEOUT;
+               while (adapter->got[CMD_NETWORK_STATISTICS] == 0 && time_before(jiffies, timeout));
+               if (time_after_eq(jiffies, timeout)) {
+                       TIMEOUT_MSG(__LINE__);
+                       return &dev->stats;
+               }
+       }
+
+       /* statistics are now up to date */
+       return &dev->stats;
+}
+
+
+static void netdev_get_drvinfo(struct net_device *dev,
+                              struct ethtool_drvinfo *info)
+{
+       strcpy(info->driver, DRV_NAME);
+       strcpy(info->version, DRV_VERSION);
+       sprintf(info->bus_info, "ISA 0x%lx", dev->base_addr);
+}
+
+static u32 netdev_get_msglevel(struct net_device *dev)
+{
+       return debug;
+}
+
+static void netdev_set_msglevel(struct net_device *dev, u32 level)
+{
+       debug = level;
+}
+
+static const struct ethtool_ops netdev_ethtool_ops = {
+       .get_drvinfo            = netdev_get_drvinfo,
+       .get_msglevel           = netdev_get_msglevel,
+       .set_msglevel           = netdev_set_msglevel,
+};
+
+/******************************************************
+ *
+ * close the board
+ *
+ ******************************************************/
+
+static int elp_close(struct net_device *dev)
+{
+       elp_device *adapter = netdev_priv(dev);
+
+       if (elp_debug >= 3)
+               pr_debug("%s: request to close device\n", dev->name);
+
+       netif_stop_queue(dev);
+
+       /* Someone may request the device statistic information even when
+        * the interface is closed. The following will update the statistics
+        * structure in the driver, so we'll be able to give current statistics.
+        */
+       (void) elp_get_stats(dev);
+
+       /*
+        * disable interrupts on the board
+        */
+       outb_control(0, dev);
+
+       /*
+        * release the IRQ
+        */
+       free_irq(dev->irq, dev);
+
+       free_dma(dev->dma);
+       free_pages((unsigned long) adapter->dma_buffer, get_order(DMA_BUFFER_SIZE));
+
+       return 0;
+}
+
+
+/************************************************************
+ *
+ * Set multicast list
+ * num_addrs==0: clear mc_list
+ * num_addrs==-1: set promiscuous mode
+ * num_addrs>0: set mc_list
+ *
+ ************************************************************/
+
+static void elp_set_mc_list(struct net_device *dev)
+{
+       elp_device *adapter = netdev_priv(dev);
+       struct netdev_hw_addr *ha;
+       int i;
+       unsigned long flags;
+
+       if (elp_debug >= 3)
+               pr_debug("%s: request to set multicast list\n", dev->name);
+
+       spin_lock_irqsave(&adapter->lock, flags);
+
+       if (!(dev->flags & (IFF_PROMISC | IFF_ALLMULTI))) {
+               /* send a "load multicast list" command to the board, max 10 addrs/cmd */
+               /* if num_addrs==0 the list will be cleared */
+               adapter->tx_pcb.command = CMD_LOAD_MULTICAST_LIST;
+               adapter->tx_pcb.length = 6 * netdev_mc_count(dev);
+               i = 0;
+               netdev_for_each_mc_addr(ha, dev)
+                       memcpy(adapter->tx_pcb.data.multicast[i++],
+                              ha->addr, 6);
+               adapter->got[CMD_LOAD_MULTICAST_LIST] = 0;
+               if (!send_pcb(dev, &adapter->tx_pcb))
+                       pr_err("%s: couldn't send set_multicast command\n", dev->name);
+               else {
+                       unsigned long timeout = jiffies + TIMEOUT;
+                       while (adapter->got[CMD_LOAD_MULTICAST_LIST] == 0 && time_before(jiffies, timeout));
+                       if (time_after_eq(jiffies, timeout)) {
+                               TIMEOUT_MSG(__LINE__);
+                       }
+               }
+               if (!netdev_mc_empty(dev))
+                       adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_BROAD | RECV_MULTI;
+               else            /* num_addrs == 0 */
+                       adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_BROAD;
+       } else
+               adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_PROMISC;
+       /*
+        * configure adapter to receive messages (as specified above)
+        * and wait for response
+        */
+       if (elp_debug >= 3)
+               pr_debug("%s: sending 82586 configure command\n", dev->name);
+       adapter->tx_pcb.command = CMD_CONFIGURE_82586;
+       adapter->tx_pcb.length = 2;
+       adapter->got[CMD_CONFIGURE_82586] = 0;
+       if (!send_pcb(dev, &adapter->tx_pcb))
+       {
+               spin_unlock_irqrestore(&adapter->lock, flags);
+               pr_err("%s: couldn't send 82586 configure command\n", dev->name);
+       }
+       else {
+               unsigned long timeout = jiffies + TIMEOUT;
+               spin_unlock_irqrestore(&adapter->lock, flags);
+               while (adapter->got[CMD_CONFIGURE_82586] == 0 && time_before(jiffies, timeout));
+               if (time_after_eq(jiffies, timeout))
+                       TIMEOUT_MSG(__LINE__);
+       }
+}
+
+/************************************************************
+ *
+ * A couple of tests to see if there's 3C505 or not
+ * Called only by elp_autodetect
+ ************************************************************/
+
+static int __init elp_sense(struct net_device *dev)
+{
+       int addr = dev->base_addr;
+       const char *name = dev->name;
+       byte orig_HSR;
+
+       if (!request_region(addr, ELP_IO_EXTENT, "3c505"))
+               return -ENODEV;
+
+       orig_HSR = inb_status(addr);
+
+       if (elp_debug > 0)
+               pr_debug(search_msg, name, addr);
+
+       if (orig_HSR == 0xff) {
+               if (elp_debug > 0)
+                       pr_cont(notfound_msg, 1);
+               goto out;
+       }
+
+       /* Wait for a while; the adapter may still be booting up */
+       if (elp_debug > 0)
+               pr_cont(stilllooking_msg);
+
+       if (orig_HSR & DIR) {
+               /* If HCR.DIR is up, we pull it down. HSR.DIR should follow. */
+               outb(0, dev->base_addr + PORT_CONTROL);
+               msleep(300);
+               if (inb_status(addr) & DIR) {
+                       if (elp_debug > 0)
+                               pr_cont(notfound_msg, 2);
+                       goto out;
+               }
+       } else {
+               /* If HCR.DIR is down, we pull it up. HSR.DIR should follow. */
+               outb(DIR, dev->base_addr + PORT_CONTROL);
+               msleep(300);
+               if (!(inb_status(addr) & DIR)) {
+                       if (elp_debug > 0)
+                               pr_cont(notfound_msg, 3);
+                       goto out;
+               }
+       }
+       /*
+        * It certainly looks like a 3c505.
+        */
+       if (elp_debug > 0)
+               pr_cont(found_msg);
+
+       return 0;
+out:
+       release_region(addr, ELP_IO_EXTENT);
+       return -ENODEV;
+}
+
+/*************************************************************
+ *
+ * Search through addr_list[] and try to find a 3C505
+ * Called only by eplus_probe
+ *************************************************************/
+
+static int __init elp_autodetect(struct net_device *dev)
+{
+       int idx = 0;
+
+       /* if base address set, then only check that address
+          otherwise, run through the table */
+       if (dev->base_addr != 0) {      /* dev->base_addr == 0 ==> plain autodetect */
+               if (elp_sense(dev) == 0)
+                       return dev->base_addr;
+       } else
+               while ((dev->base_addr = addr_list[idx++])) {
+                       if (elp_sense(dev) == 0)
+                               return dev->base_addr;
+               }
+
+       /* could not find an adapter */
+       if (elp_debug > 0)
+               pr_debug(couldnot_msg, dev->name);
+
+       return 0;               /* Because of this, the layer above will return -ENODEV */
+}
+
+static const struct net_device_ops elp_netdev_ops = {
+       .ndo_open               = elp_open,
+       .ndo_stop               = elp_close,
+       .ndo_get_stats          = elp_get_stats,
+       .ndo_start_xmit         = elp_start_xmit,
+       .ndo_tx_timeout         = elp_timeout,
+       .ndo_set_multicast_list = elp_set_mc_list,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
+/******************************************************
+ *
+ * probe for an Etherlink Plus board at the specified address
+ *
+ ******************************************************/
+
+/* There are three situations we need to be able to detect here:
+
+ *  a) the card is idle
+ *  b) the card is still booting up
+ *  c) the card is stuck in a strange state (some DOS drivers do this)
+ *
+ * In case (a), all is well.  In case (b), we wait 10 seconds to see if the
+ * card finishes booting, and carry on if so.  In case (c), we do a hard reset,
+ * loop round, and hope for the best.
+ *
+ * This is all very unpleasant, but hopefully avoids the problems with the old
+ * probe code (which had a 15-second delay if the card was idle, and didn't
+ * work at all if it was in a weird state).
+ */
+
+static int __init elplus_setup(struct net_device *dev)
+{
+       elp_device *adapter = netdev_priv(dev);
+       int i, tries, tries1, okay;
+       unsigned long timeout;
+       unsigned long cookie = 0;
+       int err = -ENODEV;
+
+       /*
+        *  setup adapter structure
+        */
+
+       dev->base_addr = elp_autodetect(dev);
+       if (!dev->base_addr)
+               return -ENODEV;
+
+       adapter->send_pcb_semaphore = 0;
+
+       for (tries1 = 0; tries1 < 3; tries1++) {
+               outb_control((adapter->hcr_val | CMDE) & ~DIR, dev);
+               /* First try to write just one byte, to see if the card is
+                * responding at all normally.
+                */
+               timeout = jiffies + 5*HZ/100;
+               okay = 0;
+               while (time_before(jiffies, timeout) && !(inb_status(dev->base_addr) & HCRE));
+               if ((inb_status(dev->base_addr) & HCRE)) {
+                       outb_command(0, dev->base_addr);        /* send a spurious byte */
+                       timeout = jiffies + 5*HZ/100;
+                       while (time_before(jiffies, timeout) && !(inb_status(dev->base_addr) & HCRE));
+                       if (inb_status(dev->base_addr) & HCRE)
+                               okay = 1;
+               }
+               if (!okay) {
+                       /* Nope, it's ignoring the command register.  This means that
+                        * either it's still booting up, or it's died.
+                        */
+                       pr_err("%s: command register wouldn't drain, ", dev->name);
+                       if ((inb_status(dev->base_addr) & 7) == 3) {
+                               /* If the adapter status is 3, it *could* still be booting.
+                                * Give it the benefit of the doubt for 10 seconds.
+                                */
+                               pr_cont("assuming 3c505 still starting\n");
+                               timeout = jiffies + 10*HZ;
+                               while (time_before(jiffies, timeout) && (inb_status(dev->base_addr) & 7));
+                               if (inb_status(dev->base_addr) & 7) {
+                                       pr_err("%s: 3c505 failed to start\n", dev->name);
+                               } else {
+                                       okay = 1;  /* It started */
+                               }
+                       } else {
+                               /* Otherwise, it must just be in a strange
+                                * state.  We probably need to kick it.
+                                */
+                               pr_cont("3c505 is sulking\n");
+                       }
+               }
+               for (tries = 0; tries < 5 && okay; tries++) {
+
+                       /*
+                        * Try to set the Ethernet address, to make sure that the board
+                        * is working.
+                        */
+                       adapter->tx_pcb.command = CMD_STATION_ADDRESS;
+                       adapter->tx_pcb.length = 0;
+                       cookie = probe_irq_on();
+                       if (!send_pcb(dev, &adapter->tx_pcb)) {
+                               pr_err("%s: could not send first PCB\n", dev->name);
+                               probe_irq_off(cookie);
+                               continue;
+                       }
+                       if (!receive_pcb(dev, &adapter->rx_pcb)) {
+                               pr_err("%s: could not read first PCB\n", dev->name);
+                               probe_irq_off(cookie);
+                               continue;
+                       }
+                       if ((adapter->rx_pcb.command != CMD_ADDRESS_RESPONSE) ||
+                           (adapter->rx_pcb.length != 6)) {
+                               pr_err("%s: first PCB wrong (%d, %d)\n", dev->name,
+                                       adapter->rx_pcb.command, adapter->rx_pcb.length);
+                               probe_irq_off(cookie);
+                               continue;
+                       }
+                       goto okay;
+               }
+               /* It's broken.  Do a hard reset to re-initialise the board,
+                * and try again.
+                */
+               pr_info("%s: resetting adapter\n", dev->name);
+               outb_control(adapter->hcr_val | FLSH | ATTN, dev);
+               outb_control(adapter->hcr_val & ~(FLSH | ATTN), dev);
+       }
+       pr_err("%s: failed to initialise 3c505\n", dev->name);
+       goto out;
+
+      okay:
+       if (dev->irq) {         /* Is there a preset IRQ? */
+               int rpt = probe_irq_off(cookie);
+               if (dev->irq != rpt) {
+                       pr_warning("%s: warning, irq %d configured but %d detected\n", dev->name, dev->irq, rpt);
+               }
+               /* if dev->irq == probe_irq_off(cookie), all is well */
+       } else                 /* No preset IRQ; just use what we can detect */
+               dev->irq = probe_irq_off(cookie);
+       switch (dev->irq) {    /* Legal, sane? */
+       case 0:
+               pr_err("%s: IRQ probe failed: check 3c505 jumpers.\n",
+                      dev->name);
+               goto out;
+       case 1:
+       case 6:
+       case 8:
+       case 13:
+               pr_err("%s: Impossible IRQ %d reported by probe_irq_off().\n",
+                      dev->name, dev->irq);
+                      goto out;
+       }
+       /*
+        *  Now we have the IRQ number so we can disable the interrupts from
+        *  the board until the board is opened.
+        */
+       outb_control(adapter->hcr_val & ~CMDE, dev);
+
+       /*
+        * copy Ethernet address into structure
+        */
+       for (i = 0; i < 6; i++)
+               dev->dev_addr[i] = adapter->rx_pcb.data.eth_addr[i];
+
+       /* find a DMA channel */
+       if (!dev->dma) {
+               if (dev->mem_start) {
+                       dev->dma = dev->mem_start & 7;
+               }
+               else {
+                       pr_warning("%s: warning, DMA channel not specified, using default\n", dev->name);
+                       dev->dma = ELP_DMA;
+               }
+       }
+
+       /*
+        * print remainder of startup message
+        */
+       pr_info("%s: 3c505 at %#lx, irq %d, dma %d, addr %pM, ",
+               dev->name, dev->base_addr, dev->irq, dev->dma, dev->dev_addr);
+       /*
+        * read more information from the adapter
+        */
+
+       adapter->tx_pcb.command = CMD_ADAPTER_INFO;
+       adapter->tx_pcb.length = 0;
+       if (!send_pcb(dev, &adapter->tx_pcb) ||
+           !receive_pcb(dev, &adapter->rx_pcb) ||
+           (adapter->rx_pcb.command != CMD_ADAPTER_INFO_RESPONSE) ||
+           (adapter->rx_pcb.length != 10)) {
+               pr_cont("not responding to second PCB\n");
+       }
+       pr_cont("rev %d.%d, %dk\n", adapter->rx_pcb.data.info.major_vers,
+               adapter->rx_pcb.data.info.minor_vers, adapter->rx_pcb.data.info.RAM_sz);
+
+       /*
+        * reconfigure the adapter memory to better suit our purposes
+        */
+       adapter->tx_pcb.command = CMD_CONFIGURE_ADAPTER_MEMORY;
+       adapter->tx_pcb.length = 12;
+       adapter->tx_pcb.data.memconf.cmd_q = 8;
+       adapter->tx_pcb.data.memconf.rcv_q = 8;
+       adapter->tx_pcb.data.memconf.mcast = 10;
+       adapter->tx_pcb.data.memconf.frame = 10;
+       adapter->tx_pcb.data.memconf.rcv_b = 10;
+       adapter->tx_pcb.data.memconf.progs = 0;
+       if (!send_pcb(dev, &adapter->tx_pcb) ||
+           !receive_pcb(dev, &adapter->rx_pcb) ||
+           (adapter->rx_pcb.command != CMD_CONFIGURE_ADAPTER_RESPONSE) ||
+           (adapter->rx_pcb.length != 2)) {
+               pr_err("%s: could not configure adapter memory\n", dev->name);
+       }
+       if (adapter->rx_pcb.data.configure) {
+               pr_err("%s: adapter configuration failed\n", dev->name);
+       }
+
+       dev->netdev_ops = &elp_netdev_ops;
+       dev->watchdog_timeo = 10*HZ;
+       dev->ethtool_ops = &netdev_ethtool_ops;         /* local */
+
+       dev->mem_start = dev->mem_end = 0;
+
+       err = register_netdev(dev);
+       if (err)
+               goto out;
+
+       return 0;
+out:
+       release_region(dev->base_addr, ELP_IO_EXTENT);
+       return err;
+}
+
+#ifndef MODULE
+struct net_device * __init elplus_probe(int unit)
+{
+       struct net_device *dev = alloc_etherdev(sizeof(elp_device));
+       int err;
+       if (!dev)
+               return ERR_PTR(-ENOMEM);
+
+       sprintf(dev->name, "eth%d", unit);
+       netdev_boot_setup_check(dev);
+
+       err = elplus_setup(dev);
+       if (err) {
+               free_netdev(dev);
+               return ERR_PTR(err);
+       }
+       return dev;
+}
+
+#else
+static struct net_device *dev_3c505[ELP_MAX_CARDS];
+static int io[ELP_MAX_CARDS];
+static int irq[ELP_MAX_CARDS];
+static int dma[ELP_MAX_CARDS];
+module_param_array(io, int, NULL, 0);
+module_param_array(irq, int, NULL, 0);
+module_param_array(dma, int, NULL, 0);
+MODULE_PARM_DESC(io, "EtherLink Plus I/O base address(es)");
+MODULE_PARM_DESC(irq, "EtherLink Plus IRQ number(s) (assigned)");
+MODULE_PARM_DESC(dma, "EtherLink Plus DMA channel(s)");
+
+int __init init_module(void)
+{
+       int this_dev, found = 0;
+
+       for (this_dev = 0; this_dev < ELP_MAX_CARDS; this_dev++) {
+               struct net_device *dev = alloc_etherdev(sizeof(elp_device));
+               if (!dev)
+                       break;
+
+               dev->irq = irq[this_dev];
+               dev->base_addr = io[this_dev];
+               if (dma[this_dev]) {
+                       dev->dma = dma[this_dev];
+               } else {
+                       dev->dma = ELP_DMA;
+                       pr_warning("3c505.c: warning, using default DMA channel,\n");
+               }
+               if (io[this_dev] == 0) {
+                       if (this_dev) {
+                               free_netdev(dev);
+                               break;
+                       }
+                       pr_notice("3c505.c: module autoprobe not recommended, give io=xx.\n");
+               }
+               if (elplus_setup(dev) != 0) {
+                       pr_warning("3c505.c: Failed to register card at 0x%x.\n", io[this_dev]);
+                       free_netdev(dev);
+                       break;
+               }
+               dev_3c505[this_dev] = dev;
+               found++;
+       }
+       if (!found)
+               return -ENODEV;
+       return 0;
+}
+
+void __exit cleanup_module(void)
+{
+       int this_dev;
+
+       for (this_dev = 0; this_dev < ELP_MAX_CARDS; this_dev++) {
+               struct net_device *dev = dev_3c505[this_dev];
+               if (dev) {
+                       unregister_netdev(dev);
+                       release_region(dev->base_addr, ELP_IO_EXTENT);
+                       free_netdev(dev);
+               }
+       }
+}
+
+#endif                         /* MODULE */
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/i825xx/3c505.h b/drivers/net/ethernet/i825xx/3c505.h
new file mode 100644 (file)
index 0000000..04df2a9
--- /dev/null
@@ -0,0 +1,292 @@
+/*****************************************************************
+ *
+ *  defines for 3Com Etherlink Plus adapter
+ *
+ *****************************************************************/
+
+#define ELP_DMA       6
+#define ELP_RX_PCBS   4
+#define ELP_MAX_CARDS 4
+
+/*
+ * I/O register offsets
+ */
+#define        PORT_COMMAND    0x00    /* read/write, 8-bit */
+#define        PORT_STATUS     0x02    /* read only, 8-bit */
+#define        PORT_AUXDMA     0x02    /* write only, 8-bit */
+#define        PORT_DATA       0x04    /* read/write, 16-bit */
+#define        PORT_CONTROL    0x06    /* read/write, 8-bit */
+
+#define ELP_IO_EXTENT  0x10    /* size of used IO registers */
+
+/*
+ * host control registers bits
+ */
+#define        ATTN    0x80    /* attention */
+#define        FLSH    0x40    /* flush data register */
+#define DMAE   0x20    /* DMA enable */
+#define DIR    0x10    /* direction */
+#define        TCEN    0x08    /* terminal count interrupt enable */
+#define        CMDE    0x04    /* command register interrupt enable */
+#define        HSF2    0x02    /* host status flag 2 */
+#define        HSF1    0x01    /* host status flag 1 */
+
+/*
+ * combinations of HSF flags used for PCB transmission
+ */
+#define        HSF_PCB_ACK     HSF1
+#define        HSF_PCB_NAK     HSF2
+#define        HSF_PCB_END     (HSF2|HSF1)
+#define        HSF_PCB_MASK    (HSF2|HSF1)
+
+/*
+ * host status register bits
+ */
+#define        HRDY    0x80    /* data register ready */
+#define        HCRE    0x40    /* command register empty */
+#define        ACRF    0x20    /* adapter command register full */
+/* #define DIR         0x10    direction - same as in control register */
+#define        DONE    0x08    /* DMA done */
+#define        ASF3    0x04    /* adapter status flag 3 */
+#define        ASF2    0x02    /* adapter status flag 2 */
+#define        ASF1    0x01    /* adapter status flag 1 */
+
+/*
+ * combinations of ASF flags used for PCB reception
+ */
+#define        ASF_PCB_ACK     ASF1
+#define        ASF_PCB_NAK     ASF2
+#define        ASF_PCB_END     (ASF2|ASF1)
+#define        ASF_PCB_MASK    (ASF2|ASF1)
+
+/*
+ * host aux DMA register bits
+ */
+#define        DMA_BRST        0x01    /* DMA burst */
+
+/*
+ * maximum amount of data allowed in a PCB
+ */
+#define        MAX_PCB_DATA    62
+
+/*****************************************************************
+ *
+ *  timeout value
+ *     this is a rough value used for loops to stop them from
+ *     locking up the whole machine in the case of failure or
+ *     error conditions
+ *
+ *****************************************************************/
+
+#define        TIMEOUT 300
+
+/*****************************************************************
+ *
+ * PCB commands
+ *
+ *****************************************************************/
+
+enum {
+  /*
+   * host PCB commands
+   */
+  CMD_CONFIGURE_ADAPTER_MEMORY = 0x01,
+  CMD_CONFIGURE_82586          = 0x02,
+  CMD_STATION_ADDRESS          = 0x03,
+  CMD_DMA_DOWNLOAD             = 0x04,
+  CMD_DMA_UPLOAD               = 0x05,
+  CMD_PIO_DOWNLOAD             = 0x06,
+  CMD_PIO_UPLOAD               = 0x07,
+  CMD_RECEIVE_PACKET           = 0x08,
+  CMD_TRANSMIT_PACKET          = 0x09,
+  CMD_NETWORK_STATISTICS       = 0x0a,
+  CMD_LOAD_MULTICAST_LIST      = 0x0b,
+  CMD_CLEAR_PROGRAM            = 0x0c,
+  CMD_DOWNLOAD_PROGRAM         = 0x0d,
+  CMD_EXECUTE_PROGRAM          = 0x0e,
+  CMD_SELF_TEST                        = 0x0f,
+  CMD_SET_STATION_ADDRESS      = 0x10,
+  CMD_ADAPTER_INFO             = 0x11,
+  NUM_TRANSMIT_CMDS,
+
+  /*
+   * adapter PCB commands
+   */
+  CMD_CONFIGURE_ADAPTER_RESPONSE       = 0x31,
+  CMD_CONFIGURE_82586_RESPONSE         = 0x32,
+  CMD_ADDRESS_RESPONSE                 = 0x33,
+  CMD_DOWNLOAD_DATA_REQUEST            = 0x34,
+  CMD_UPLOAD_DATA_REQUEST              = 0x35,
+  CMD_RECEIVE_PACKET_COMPLETE          = 0x38,
+  CMD_TRANSMIT_PACKET_COMPLETE         = 0x39,
+  CMD_NETWORK_STATISTICS_RESPONSE      = 0x3a,
+  CMD_LOAD_MULTICAST_RESPONSE          = 0x3b,
+  CMD_CLEAR_PROGRAM_RESPONSE           = 0x3c,
+  CMD_DOWNLOAD_PROGRAM_RESPONSE                = 0x3d,
+  CMD_EXECUTE_RESPONSE                 = 0x3e,
+  CMD_SELF_TEST_RESPONSE               = 0x3f,
+  CMD_SET_ADDRESS_RESPONSE             = 0x40,
+  CMD_ADAPTER_INFO_RESPONSE            = 0x41
+};
+
+/* Definitions for the PCB data structure */
+
+/* Data units */
+typedef unsigned char         byte;
+typedef unsigned short int    word;
+typedef unsigned long int     dword;
+
+/* Data structures */
+struct Memconf {
+       word    cmd_q,
+               rcv_q,
+               mcast,
+               frame,
+               rcv_b,
+               progs;
+};
+
+struct Rcv_pkt {
+       word    buf_ofs,
+               buf_seg,
+               buf_len,
+               timeout;
+};
+
+struct Xmit_pkt {
+       word    buf_ofs,
+               buf_seg,
+               pkt_len;
+};
+
+struct Rcv_resp {
+       word    buf_ofs,
+               buf_seg,
+               buf_len,
+               pkt_len,
+               timeout,
+               status;
+       dword   timetag;
+};
+
+struct Xmit_resp {
+       word    buf_ofs,
+               buf_seg,
+               c_stat,
+               status;
+};
+
+
+struct Netstat {
+       dword   tot_recv,
+               tot_xmit;
+       word    err_CRC,
+               err_align,
+               err_res,
+               err_ovrrun;
+};
+
+
+struct Selftest {
+       word    error;
+       union {
+               word ROM_cksum;
+               struct {
+                       word ofs, seg;
+               } RAM;
+               word i82586;
+       } failure;
+};
+
+struct Info {
+       byte    minor_vers,
+               major_vers;
+       word    ROM_cksum,
+               RAM_sz,
+               free_ofs,
+               free_seg;
+};
+
+struct Memdump {
+       word size,
+            off,
+            seg;
+};
+
+/*
+Primary Command Block. The most important data structure. All communication
+between the host and the adapter is done with these. (Except for the actual
+Ethernet data, which has different packaging.)
+*/
+typedef struct {
+       byte    command;
+       byte    length;
+       union   {
+               struct Memconf          memconf;
+               word                    configure;
+               struct Rcv_pkt          rcv_pkt;
+               struct Xmit_pkt         xmit_pkt;
+               byte                    multicast[10][6];
+               byte                    eth_addr[6];
+               byte                    failed;
+               struct Rcv_resp         rcv_resp;
+               struct Xmit_resp        xmit_resp;
+               struct Netstat          netstat;
+               struct Selftest         selftest;
+               struct Info             info;
+               struct Memdump          memdump;
+               byte                    raw[62];
+       } data;
+} pcb_struct;
+
+/* These defines for 'configure' */
+#define RECV_STATION   0x00
+#define RECV_BROAD     0x01
+#define RECV_MULTI     0x02
+#define RECV_PROMISC   0x04
+#define NO_LOOPBACK    0x00
+#define INT_LOOPBACK   0x08
+#define EXT_LOOPBACK   0x10
+
+/*****************************************************************
+ *
+ *  structure to hold context information for adapter
+ *
+ *****************************************************************/
+
+#define DMA_BUFFER_SIZE  1600
+#define BACKLOG_SIZE      4
+
+typedef struct {
+       volatile short got[NUM_TRANSMIT_CMDS];  /* flags for
+                                                  command completion */
+       pcb_struct tx_pcb;      /* PCB for foreground sending */
+       pcb_struct rx_pcb;      /* PCB for foreground receiving */
+       pcb_struct itx_pcb;     /* PCB for background sending */
+       pcb_struct irx_pcb;     /* PCB for background receiving */
+
+       void *dma_buffer;
+
+       struct {
+               unsigned int length[BACKLOG_SIZE];
+               unsigned int in;
+               unsigned int out;
+       } rx_backlog;
+
+       struct {
+               unsigned int direction;
+               unsigned int length;
+               struct sk_buff *skb;
+               void *target;
+               unsigned long start_time;
+       } current_dma;
+
+       /* flags */
+       unsigned long send_pcb_semaphore;
+       unsigned long dmaing;
+       unsigned long busy;
+
+       unsigned int rx_active;  /* number of receive PCBs */
+        volatile unsigned char hcr_val;  /* what we think the HCR contains */
+        spinlock_t lock;       /* Interrupt v tx lock */
+} elp_device;
diff --git a/drivers/net/ethernet/i825xx/3c507.c b/drivers/net/ethernet/i825xx/3c507.c
new file mode 100644 (file)
index 0000000..1e94555
--- /dev/null
@@ -0,0 +1,939 @@
+/* 3c507.c: An EtherLink16 device driver for Linux. */
+/*
+       Written 1993,1994 by Donald Becker.
+
+       Copyright 1993 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 General Public License, incorporated herein by reference.
+
+       The author may be reached as becker@scyld.com, or C/O
+       Scyld Computing Corporation
+       410 Severn Ave., Suite 210
+       Annapolis MD 21403
+
+
+       Thanks go to jennings@Montrouge.SMR.slb.com ( Patrick Jennings)
+       and jrs@world.std.com (Rick Sladkey) for testing and bugfixes.
+       Mark Salazar <leslie@access.digex.net> made the changes for cards with
+       only 16K packet buffers.
+
+       Things remaining to do:
+       Verify that the tx and rx buffers don't have fencepost errors.
+       Move the theory of operation and memory map documentation.
+       The statistics need to be updated correctly.
+*/
+
+#define DRV_NAME               "3c507"
+#define DRV_VERSION            "1.10a"
+#define DRV_RELDATE            "11/17/2001"
+
+static const char version[] =
+       DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " Donald Becker (becker@scyld.com)\n";
+
+/*
+  Sources:
+       This driver wouldn't have been written with the availability of the
+       Crynwr driver source code.      It provided a known-working implementation
+       that filled in the gaping holes of the Intel documentation.  Three cheers
+       for Russ Nelson.
+
+       Intel Microcommunications Databook, Vol. 1, 1990.  It provides just enough
+       info that the casual reader might think that it documents the i82586 :-<.
+*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/string.h>
+#include <linux/spinlock.h>
+#include <linux/ethtool.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/if_ether.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+/* use 0 for production, 1 for verification, 2..7 for debug */
+#ifndef NET_DEBUG
+#define NET_DEBUG 1
+#endif
+static unsigned int net_debug = NET_DEBUG;
+#define debug net_debug
+
+
+/*
+                       Details of the i82586.
+
+   You'll really need the databook to understand the details of this part,
+   but the outline is that the i82586 has two separate processing units.
+   Both are started from a list of three configuration tables, of which only
+   the last, the System Control Block (SCB), is used after reset-time.  The SCB
+   has the following fields:
+               Status word
+               Command word
+               Tx/Command block addr.
+               Rx block addr.
+   The command word accepts the following controls for the Tx and Rx units:
+  */
+
+#define         CUC_START       0x0100
+#define         CUC_RESUME      0x0200
+#define         CUC_SUSPEND 0x0300
+#define         RX_START        0x0010
+#define         RX_RESUME       0x0020
+#define         RX_SUSPEND      0x0030
+
+/* The Rx unit uses a list of frame descriptors and a list of data buffer
+   descriptors.  We use full-sized (1518 byte) data buffers, so there is
+   a one-to-one pairing of frame descriptors to buffer descriptors.
+
+   The Tx ("command") unit executes a list of commands that look like:
+               Status word             Written by the 82586 when the command is done.
+               Command word    Command in lower 3 bits, post-command action in upper 3
+               Link word               The address of the next command.
+               Parameters              (as needed).
+
+       Some definitions related to the Command Word are:
+ */
+#define CMD_EOL                0x8000                  /* The last command of the list, stop. */
+#define CMD_SUSP       0x4000                  /* Suspend after doing cmd. */
+#define CMD_INTR       0x2000                  /* Interrupt after doing cmd. */
+
+enum commands {
+       CmdNOp = 0, CmdSASetup = 1, CmdConfigure = 2, CmdMulticastList = 3,
+       CmdTx = 4, CmdTDR = 5, CmdDump = 6, CmdDiagnose = 7};
+
+/* Information that need to be kept for each board. */
+struct net_local {
+       int last_restart;
+       ushort rx_head;
+       ushort rx_tail;
+       ushort tx_head;
+       ushort tx_cmd_link;
+       ushort tx_reap;
+       ushort tx_pkts_in_ring;
+       spinlock_t lock;
+       void __iomem *base;
+};
+
+/*
+               Details of the EtherLink16 Implementation
+  The 3c507 is a generic shared-memory i82586 implementation.
+  The host can map 16K, 32K, 48K, or 64K of the 64K memory into
+  0x0[CD][08]0000, or all 64K into 0xF[02468]0000.
+  */
+
+/* Offsets from the base I/O address. */
+#define        SA_DATA         0       /* Station address data, or 3Com signature. */
+#define MISC_CTRL      6       /* Switch the SA_DATA banks, and bus config bits. */
+#define RESET_IRQ      10      /* Reset the latched IRQ line. */
+#define SIGNAL_CA      11      /* Frob the 82586 Channel Attention line. */
+#define ROM_CONFIG     13
+#define MEM_CONFIG     14
+#define IRQ_CONFIG     15
+#define EL16_IO_EXTENT 16
+
+/* The ID port is used at boot-time to locate the ethercard. */
+#define ID_PORT                0x100
+
+/* Offsets to registers in the mailbox (SCB). */
+#define iSCB_STATUS    0x8
+#define iSCB_CMD               0xA
+#define iSCB_CBL               0xC     /* Command BLock offset. */
+#define iSCB_RFA               0xE     /* Rx Frame Area offset. */
+
+/*  Since the 3c507 maps the shared memory window so that the last byte is
+       at 82586 address FFFF, the first byte is at 82586 address 0, 16K, 32K, or
+       48K corresponding to window sizes of 64K, 48K, 32K and 16K respectively.
+       We can account for this be setting the 'SBC Base' entry in the ISCP table
+       below for all the 16 bit offset addresses, and also adding the 'SCB Base'
+       value to all 24 bit physical addresses (in the SCP table and the TX and RX
+       Buffer Descriptors).
+                                       -Mark
+       */
+#define SCB_BASE               ((unsigned)64*1024 - (dev->mem_end - dev->mem_start))
+
+/*
+  What follows in 'init_words[]' is the "program" that is downloaded to the
+  82586 memory.         It's mostly tables and command blocks, and starts at the
+  reset address 0xfffff6.  This is designed to be similar to the EtherExpress,
+  thus the unusual location of the SCB at 0x0008.
+
+  Even with the additional "don't care" values, doing it this way takes less
+  program space than initializing the individual tables, and I feel it's much
+  cleaner.
+
+  The databook is particularly useless for the first two structures, I had
+  to use the Crynwr driver as an example.
+
+   The memory setup is as follows:
+   */
+
+#define CONFIG_CMD     0x0018
+#define SET_SA_CMD     0x0024
+#define SA_OFFSET      0x002A
+#define IDLELOOP       0x30
+#define TDR_CMD                0x38
+#define TDR_TIME       0x3C
+#define DUMP_CMD       0x40
+#define DIAG_CMD       0x48
+#define SET_MC_CMD     0x4E
+#define DUMP_DATA      0x56    /* A 170 byte buffer for dump and Set-MC into. */
+
+#define TX_BUF_START   0x0100
+#define NUM_TX_BUFS    5
+#define TX_BUF_SIZE    (1518+14+20+16) /* packet+header+TBD */
+
+#define RX_BUF_START   0x2000
+#define RX_BUF_SIZE    (1518+14+18)    /* packet+header+RBD */
+#define RX_BUF_END             (dev->mem_end - dev->mem_start)
+
+#define TX_TIMEOUT (HZ/20)
+
+/*
+  That's it: only 86 bytes to set up the beast, including every extra
+  command available.  The 170 byte buffer at DUMP_DATA is shared between the
+  Dump command (called only by the diagnostic program) and the SetMulticastList
+  command.
+
+  To complete the memory setup you only have to write the station address at
+  SA_OFFSET and create the Tx & Rx buffer lists.
+
+  The Tx command chain and buffer list is setup as follows:
+  A Tx command table, with the data buffer pointing to...
+  A Tx data buffer descriptor.  The packet is in a single buffer, rather than
+       chaining together several smaller buffers.
+  A NoOp command, which initially points to itself,
+  And the packet data.
+
+  A transmit is done by filling in the Tx command table and data buffer,
+  re-writing the NoOp command, and finally changing the offset of the last
+  command to point to the current Tx command.  When the Tx command is finished,
+  it jumps to the NoOp, when it loops until the next Tx command changes the
+  "link offset" in the NoOp.  This way the 82586 never has to go through the
+  slow restart sequence.
+
+  The Rx buffer list is set up in the obvious ring structure.  We have enough
+  memory (and low enough interrupt latency) that we can avoid the complicated
+  Rx buffer linked lists by alway associating a full-size Rx data buffer with
+  each Rx data frame.
+
+  I current use four transmit buffers starting at TX_BUF_START (0x0100), and
+  use the rest of memory, from RX_BUF_START to RX_BUF_END, for Rx buffers.
+
+  */
+
+static unsigned short init_words[] = {
+       /*      System Configuration Pointer (SCP). */
+       0x0000,                                 /* Set bus size to 16 bits. */
+       0,0,                                    /* pad words. */
+       0x0000,0x0000,                  /* ISCP phys addr, set in init_82586_mem(). */
+
+       /*      Intermediate System Configuration Pointer (ISCP). */
+       0x0001,                                 /* Status word that's cleared when init is done. */
+       0x0008,0,0,                             /* SCB offset, (skip, skip) */
+
+       /* System Control Block (SCB). */
+       0,0xf000|RX_START|CUC_START,    /* SCB status and cmd. */
+       CONFIG_CMD,                             /* Command list pointer, points to Configure. */
+       RX_BUF_START,                           /* Rx block list. */
+       0,0,0,0,                                /* Error count: CRC, align, buffer, overrun. */
+
+       /* 0x0018: Configure command.  Change to put MAC data with packet. */
+       0, CmdConfigure,                /* Status, command.             */
+       SET_SA_CMD,                             /* Next command is Set Station Addr. */
+       0x0804,                                 /* "4" bytes of config data, 8 byte FIFO. */
+       0x2e40,                                 /* Magic values, including MAC data location. */
+       0,                                              /* Unused pad word. */
+
+       /* 0x0024: Setup station address command. */
+       0, CmdSASetup,
+       SET_MC_CMD,                             /* Next command. */
+       0xaa00,0xb000,0x0bad,   /* Station address (to be filled in) */
+
+       /* 0x0030: NOP, looping back to itself.  Point to first Tx buffer to Tx. */
+       0, CmdNOp, IDLELOOP, 0 /* pad */,
+
+       /* 0x0038: A unused Time-Domain Reflectometer command. */
+       0, CmdTDR, IDLELOOP, 0,
+
+       /* 0x0040: An unused Dump State command. */
+       0, CmdDump, IDLELOOP, DUMP_DATA,
+
+       /* 0x0048: An unused Diagnose command. */
+       0, CmdDiagnose, IDLELOOP,
+
+       /* 0x004E: An empty set-multicast-list command. */
+       0, CmdMulticastList, IDLELOOP, 0,
+};
+
+/* Index to functions, as function prototypes. */
+
+static int     el16_probe1(struct net_device *dev, int ioaddr);
+static int     el16_open(struct net_device *dev);
+static netdev_tx_t el16_send_packet(struct sk_buff *skb,
+                                   struct net_device *dev);
+static irqreturn_t el16_interrupt(int irq, void *dev_id);
+static void el16_rx(struct net_device *dev);
+static int     el16_close(struct net_device *dev);
+static void el16_tx_timeout (struct net_device *dev);
+
+static void hardware_send_packet(struct net_device *dev, void *buf, short length, short pad);
+static void init_82586_mem(struct net_device *dev);
+static const struct ethtool_ops netdev_ethtool_ops;
+static void init_rx_bufs(struct net_device *);
+
+static int io = 0x300;
+static int irq;
+static int mem_start;
+
+
+/* Check for a network adaptor of this type, and return '0' iff one exists.
+       If dev->base_addr == 0, probe all likely locations.
+       If dev->base_addr == 1, always return failure.
+       If dev->base_addr == 2, (detachable devices only) allocate space for the
+       device and return success.
+       */
+
+struct net_device * __init el16_probe(int unit)
+{
+       struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
+       static const unsigned ports[] = { 0x300, 0x320, 0x340, 0x280, 0};
+       const unsigned *port;
+       int err = -ENODEV;
+
+       if (!dev)
+               return ERR_PTR(-ENODEV);
+
+       if (unit >= 0) {
+               sprintf(dev->name, "eth%d", unit);
+               netdev_boot_setup_check(dev);
+               io = dev->base_addr;
+               irq = dev->irq;
+               mem_start = dev->mem_start & 15;
+       }
+
+       if (io > 0x1ff)         /* Check a single specified location. */
+               err = el16_probe1(dev, io);
+       else if (io != 0)
+               err = -ENXIO;           /* Don't probe at all. */
+       else {
+               for (port = ports; *port; port++) {
+                       err = el16_probe1(dev, *port);
+                       if (!err)
+                               break;
+               }
+       }
+
+       if (err)
+               goto out;
+       err = register_netdev(dev);
+       if (err)
+               goto out1;
+       return dev;
+out1:
+       free_irq(dev->irq, dev);
+       iounmap(((struct net_local *)netdev_priv(dev))->base);
+       release_region(dev->base_addr, EL16_IO_EXTENT);
+out:
+       free_netdev(dev);
+       return ERR_PTR(err);
+}
+
+static const struct net_device_ops netdev_ops = {
+       .ndo_open               = el16_open,
+       .ndo_stop               = el16_close,
+       .ndo_start_xmit         = el16_send_packet,
+       .ndo_tx_timeout         = el16_tx_timeout,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
+static int __init el16_probe1(struct net_device *dev, int ioaddr)
+{
+       static unsigned char init_ID_done;
+       int i, irq, irqval, retval;
+       struct net_local *lp;
+
+       if (init_ID_done == 0) {
+               ushort lrs_state = 0xff;
+               /* Send the ID sequence to the ID_PORT to enable the board(s). */
+               outb(0x00, ID_PORT);
+               for(i = 0; i < 255; i++) {
+                       outb(lrs_state, ID_PORT);
+                       lrs_state <<= 1;
+                       if (lrs_state & 0x100)
+                               lrs_state ^= 0xe7;
+               }
+               outb(0x00, ID_PORT);
+               init_ID_done = 1;
+       }
+
+       if (!request_region(ioaddr, EL16_IO_EXTENT, DRV_NAME))
+               return -ENODEV;
+
+       if ((inb(ioaddr) != '*') || (inb(ioaddr + 1) != '3') ||
+           (inb(ioaddr + 2) != 'C') || (inb(ioaddr + 3) != 'O')) {
+               retval = -ENODEV;
+               goto out;
+       }
+
+       pr_info("%s: 3c507 at %#x,", dev->name, ioaddr);
+
+       /* We should make a few more checks here, like the first three octets of
+          the S.A. for the manufacturer's code. */
+
+       irq = inb(ioaddr + IRQ_CONFIG) & 0x0f;
+
+       irqval = request_irq(irq, el16_interrupt, 0, DRV_NAME, dev);
+       if (irqval) {
+               pr_cont("\n");
+               pr_err("3c507: unable to get IRQ %d (irqval=%d).\n", irq, irqval);
+               retval = -EAGAIN;
+               goto out;
+       }
+
+       /* We've committed to using the board, and can start filling in *dev. */
+       dev->base_addr = ioaddr;
+
+       outb(0x01, ioaddr + MISC_CTRL);
+       for (i = 0; i < 6; i++)
+               dev->dev_addr[i] = inb(ioaddr + i);
+       pr_cont(" %pM", dev->dev_addr);
+
+       if (mem_start)
+               net_debug = mem_start & 7;
+
+#ifdef MEM_BASE
+       dev->mem_start = MEM_BASE;
+       dev->mem_end = dev->mem_start + 0x10000;
+#else
+       {
+               int base;
+               int size;
+               char mem_config = inb(ioaddr + MEM_CONFIG);
+               if (mem_config & 0x20) {
+                       size = 64*1024;
+                       base = 0xf00000 + (mem_config & 0x08 ? 0x080000
+                                                          : ((mem_config & 3) << 17));
+               } else {
+                       size = ((mem_config & 3) + 1) << 14;
+                       base = 0x0c0000 + ( (mem_config & 0x18) << 12);
+               }
+               dev->mem_start = base;
+               dev->mem_end = base + size;
+       }
+#endif
+
+       dev->if_port = (inb(ioaddr + ROM_CONFIG) & 0x80) ? 1 : 0;
+       dev->irq = inb(ioaddr + IRQ_CONFIG) & 0x0f;
+
+       pr_cont(", IRQ %d, %sternal xcvr, memory %#lx-%#lx.\n", dev->irq,
+                  dev->if_port ? "ex" : "in", dev->mem_start, dev->mem_end-1);
+
+       if (net_debug)
+               pr_debug("%s", version);
+
+       lp = netdev_priv(dev);
+       spin_lock_init(&lp->lock);
+       lp->base = ioremap(dev->mem_start, RX_BUF_END);
+       if (!lp->base) {
+               pr_err("3c507: unable to remap memory\n");
+               retval = -EAGAIN;
+               goto out1;
+       }
+
+       dev->netdev_ops = &netdev_ops;
+       dev->watchdog_timeo = TX_TIMEOUT;
+       dev->ethtool_ops = &netdev_ethtool_ops;
+       dev->flags &= ~IFF_MULTICAST;   /* Multicast doesn't work */
+       return 0;
+out1:
+       free_irq(dev->irq, dev);
+out:
+       release_region(ioaddr, EL16_IO_EXTENT);
+       return retval;
+}
+
+static int el16_open(struct net_device *dev)
+{
+       /* Initialize the 82586 memory and start it. */
+       init_82586_mem(dev);
+
+       netif_start_queue(dev);
+       return 0;
+}
+
+
+static void el16_tx_timeout (struct net_device *dev)
+{
+       struct net_local *lp = netdev_priv(dev);
+       int ioaddr = dev->base_addr;
+       void __iomem *shmem = lp->base;
+
+       if (net_debug > 1)
+               pr_debug("%s: transmit timed out, %s?  ", dev->name,
+                       readw(shmem + iSCB_STATUS) & 0x8000 ? "IRQ conflict" :
+                       "network cable problem");
+       /* Try to restart the adaptor. */
+       if (lp->last_restart == dev->stats.tx_packets) {
+               if (net_debug > 1)
+                       pr_cont("Resetting board.\n");
+               /* Completely reset the adaptor. */
+               init_82586_mem (dev);
+               lp->tx_pkts_in_ring = 0;
+       } else {
+               /* Issue the channel attention signal and hope it "gets better". */
+               if (net_debug > 1)
+                       pr_cont("Kicking board.\n");
+               writew(0xf000 | CUC_START | RX_START, shmem + iSCB_CMD);
+               outb (0, ioaddr + SIGNAL_CA);   /* Issue channel-attn. */
+               lp->last_restart = dev->stats.tx_packets;
+       }
+       dev->trans_start = jiffies; /* prevent tx timeout */
+       netif_wake_queue (dev);
+}
+
+
+static netdev_tx_t el16_send_packet (struct sk_buff *skb,
+                                    struct net_device *dev)
+{
+       struct net_local *lp = netdev_priv(dev);
+       int ioaddr = dev->base_addr;
+       unsigned long flags;
+       short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+       unsigned char *buf = skb->data;
+
+       netif_stop_queue (dev);
+
+       spin_lock_irqsave (&lp->lock, flags);
+
+       dev->stats.tx_bytes += length;
+       /* Disable the 82586's input to the interrupt line. */
+       outb (0x80, ioaddr + MISC_CTRL);
+
+       hardware_send_packet (dev, buf, skb->len, length - skb->len);
+
+       /* Enable the 82586 interrupt input. */
+       outb (0x84, ioaddr + MISC_CTRL);
+
+       spin_unlock_irqrestore (&lp->lock, flags);
+
+       dev_kfree_skb (skb);
+
+       /* You might need to clean up and record Tx statistics here. */
+
+       return NETDEV_TX_OK;
+}
+
+/*     The typical workload of the driver:
+       Handle the network interface interrupts. */
+static irqreturn_t el16_interrupt(int irq, void *dev_id)
+{
+       struct net_device *dev = dev_id;
+       struct net_local *lp;
+       int ioaddr, status, boguscount = 0;
+       ushort ack_cmd = 0;
+       void __iomem *shmem;
+
+       if (dev == NULL) {
+               pr_err("net_interrupt(): irq %d for unknown device.\n", irq);
+               return IRQ_NONE;
+       }
+
+       ioaddr = dev->base_addr;
+       lp = netdev_priv(dev);
+       shmem = lp->base;
+
+       spin_lock(&lp->lock);
+
+       status = readw(shmem+iSCB_STATUS);
+
+       if (net_debug > 4) {
+               pr_debug("%s: 3c507 interrupt, status %4.4x.\n", dev->name, status);
+       }
+
+       /* Disable the 82586's input to the interrupt line. */
+       outb(0x80, ioaddr + MISC_CTRL);
+
+       /* Reap the Tx packet buffers. */
+       while (lp->tx_pkts_in_ring) {
+         unsigned short tx_status = readw(shmem+lp->tx_reap);
+         if (!(tx_status & 0x8000)) {
+               if (net_debug > 5)
+                       pr_debug("Tx command incomplete (%#x).\n", lp->tx_reap);
+               break;
+         }
+         /* Tx unsuccessful or some interesting status bit set. */
+         if (!(tx_status & 0x2000) || (tx_status & 0x0f3f)) {
+               dev->stats.tx_errors++;
+               if (tx_status & 0x0600)  dev->stats.tx_carrier_errors++;
+               if (tx_status & 0x0100)  dev->stats.tx_fifo_errors++;
+               if (!(tx_status & 0x0040))  dev->stats.tx_heartbeat_errors++;
+               if (tx_status & 0x0020)  dev->stats.tx_aborted_errors++;
+               dev->stats.collisions += tx_status & 0xf;
+         }
+         dev->stats.tx_packets++;
+         if (net_debug > 5)
+                 pr_debug("Reaped %x, Tx status %04x.\n" , lp->tx_reap, tx_status);
+         lp->tx_reap += TX_BUF_SIZE;
+         if (lp->tx_reap > RX_BUF_START - TX_BUF_SIZE)
+               lp->tx_reap = TX_BUF_START;
+
+         lp->tx_pkts_in_ring--;
+         /* There is always more space in the Tx ring buffer now. */
+         netif_wake_queue(dev);
+
+         if (++boguscount > 10)
+               break;
+       }
+
+       if (status & 0x4000) { /* Packet received. */
+               if (net_debug > 5)
+                       pr_debug("Received packet, rx_head %04x.\n", lp->rx_head);
+               el16_rx(dev);
+       }
+
+       /* Acknowledge the interrupt sources. */
+       ack_cmd = status & 0xf000;
+
+       if ((status & 0x0700) != 0x0200 && netif_running(dev)) {
+               if (net_debug)
+                       pr_debug("%s: Command unit stopped, status %04x, restarting.\n",
+                                  dev->name, status);
+               /* If this ever occurs we should really re-write the idle loop, reset
+                  the Tx list, and do a complete restart of the command unit.
+                  For now we rely on the Tx timeout if the resume doesn't work. */
+               ack_cmd |= CUC_RESUME;
+       }
+
+       if ((status & 0x0070) != 0x0040 && netif_running(dev)) {
+               /* The Rx unit is not ready, it must be hung.  Restart the receiver by
+                  initializing the rx buffers, and issuing an Rx start command. */
+               if (net_debug)
+                       pr_debug("%s: Rx unit stopped, status %04x, restarting.\n",
+                                  dev->name, status);
+               init_rx_bufs(dev);
+               writew(RX_BUF_START,shmem+iSCB_RFA);
+               ack_cmd |= RX_START;
+       }
+
+       writew(ack_cmd,shmem+iSCB_CMD);
+       outb(0, ioaddr + SIGNAL_CA);                    /* Issue channel-attn. */
+
+       /* Clear the latched interrupt. */
+       outb(0, ioaddr + RESET_IRQ);
+
+       /* Enable the 82586's interrupt input. */
+       outb(0x84, ioaddr + MISC_CTRL);
+       spin_unlock(&lp->lock);
+       return IRQ_HANDLED;
+}
+
+static int el16_close(struct net_device *dev)
+{
+       struct net_local *lp = netdev_priv(dev);
+       int ioaddr = dev->base_addr;
+       void __iomem *shmem = lp->base;
+
+       netif_stop_queue(dev);
+
+       /* Flush the Tx and disable Rx. */
+       writew(RX_SUSPEND | CUC_SUSPEND,shmem+iSCB_CMD);
+       outb(0, ioaddr + SIGNAL_CA);
+
+       /* Disable the 82586's input to the interrupt line. */
+       outb(0x80, ioaddr + MISC_CTRL);
+
+       /* We always physically use the IRQ line, so we don't do free_irq(). */
+
+       /* Update the statistics here. */
+
+       return 0;
+}
+
+/* Initialize the Rx-block list. */
+static void init_rx_bufs(struct net_device *dev)
+{
+       struct net_local *lp = netdev_priv(dev);
+       void __iomem *write_ptr;
+       unsigned short SCB_base = SCB_BASE;
+
+       int cur_rxbuf = lp->rx_head = RX_BUF_START;
+
+       /* Initialize each Rx frame + data buffer. */
+       do {    /* While there is room for one more. */
+
+               write_ptr = lp->base + cur_rxbuf;
+
+               writew(0x0000,write_ptr);                       /* Status */
+               writew(0x0000,write_ptr+=2);                    /* Command */
+               writew(cur_rxbuf + RX_BUF_SIZE,write_ptr+=2);   /* Link */
+               writew(cur_rxbuf + 22,write_ptr+=2);            /* Buffer offset */
+               writew(0x0000,write_ptr+=2);                    /* Pad for dest addr. */
+               writew(0x0000,write_ptr+=2);
+               writew(0x0000,write_ptr+=2);
+               writew(0x0000,write_ptr+=2);                    /* Pad for source addr. */
+               writew(0x0000,write_ptr+=2);
+               writew(0x0000,write_ptr+=2);
+               writew(0x0000,write_ptr+=2);                    /* Pad for protocol. */
+
+               writew(0x0000,write_ptr+=2);                    /* Buffer: Actual count */
+               writew(-1,write_ptr+=2);                        /* Buffer: Next (none). */
+               writew(cur_rxbuf + 0x20 + SCB_base,write_ptr+=2);/* Buffer: Address low */
+               writew(0x0000,write_ptr+=2);
+               /* Finally, the number of bytes in the buffer. */
+               writew(0x8000 + RX_BUF_SIZE-0x20,write_ptr+=2);
+
+               lp->rx_tail = cur_rxbuf;
+               cur_rxbuf += RX_BUF_SIZE;
+       } while (cur_rxbuf <= RX_BUF_END - RX_BUF_SIZE);
+
+       /* Terminate the list by setting the EOL bit, and wrap the pointer to make
+          the list a ring. */
+       write_ptr = lp->base + lp->rx_tail + 2;
+       writew(0xC000,write_ptr);                               /* Command, mark as last. */
+       writew(lp->rx_head,write_ptr+2);                        /* Link */
+}
+
+static void init_82586_mem(struct net_device *dev)
+{
+       struct net_local *lp = netdev_priv(dev);
+       short ioaddr = dev->base_addr;
+       void __iomem *shmem = lp->base;
+
+       /* Enable loopback to protect the wire while starting up,
+          and hold the 586 in reset during the memory initialization. */
+       outb(0x20, ioaddr + MISC_CTRL);
+
+       /* Fix the ISCP address and base. */
+       init_words[3] = SCB_BASE;
+       init_words[7] = SCB_BASE;
+
+       /* Write the words at 0xfff6 (address-aliased to 0xfffff6). */
+       memcpy_toio(lp->base + RX_BUF_END - 10, init_words, 10);
+
+       /* Write the words at 0x0000. */
+       memcpy_toio(lp->base, init_words + 5, sizeof(init_words) - 10);
+
+       /* Fill in the station address. */
+       memcpy_toio(lp->base+SA_OFFSET, dev->dev_addr, ETH_ALEN);
+
+       /* The Tx-block list is written as needed.  We just set up the values. */
+       lp->tx_cmd_link = IDLELOOP + 4;
+       lp->tx_head = lp->tx_reap = TX_BUF_START;
+
+       init_rx_bufs(dev);
+
+       /* Start the 586 by releasing the reset line, but leave loopback. */
+       outb(0xA0, ioaddr + MISC_CTRL);
+
+       /* This was time consuming to track down: you need to give two channel
+          attention signals to reliably start up the i82586. */
+       outb(0, ioaddr + SIGNAL_CA);
+
+       {
+               int boguscnt = 50;
+               while (readw(shmem+iSCB_STATUS) == 0)
+                       if (--boguscnt == 0) {
+                               pr_warning("%s: i82586 initialization timed out with status %04x, cmd %04x.\n",
+                                       dev->name, readw(shmem+iSCB_STATUS), readw(shmem+iSCB_CMD));
+                               break;
+                       }
+               /* Issue channel-attn -- the 82586 won't start. */
+               outb(0, ioaddr + SIGNAL_CA);
+       }
+
+       /* Disable loopback and enable interrupts. */
+       outb(0x84, ioaddr + MISC_CTRL);
+       if (net_debug > 4)
+               pr_debug("%s: Initialized 82586, status %04x.\n", dev->name,
+                          readw(shmem+iSCB_STATUS));
+}
+
+static void hardware_send_packet(struct net_device *dev, void *buf, short length, short pad)
+{
+       struct net_local *lp = netdev_priv(dev);
+       short ioaddr = dev->base_addr;
+       ushort tx_block = lp->tx_head;
+       void __iomem *write_ptr = lp->base + tx_block;
+       static char padding[ETH_ZLEN];
+
+       /* Set the write pointer to the Tx block, and put out the header. */
+       writew(0x0000,write_ptr);                       /* Tx status */
+       writew(CMD_INTR|CmdTx,write_ptr+=2);            /* Tx command */
+       writew(tx_block+16,write_ptr+=2);               /* Next command is a NoOp. */
+       writew(tx_block+8,write_ptr+=2);                        /* Data Buffer offset. */
+
+       /* Output the data buffer descriptor. */
+       writew((pad + length) | 0x8000,write_ptr+=2);           /* Byte count parameter. */
+       writew(-1,write_ptr+=2);                        /* No next data buffer. */
+       writew(tx_block+22+SCB_BASE,write_ptr+=2);      /* Buffer follows the NoOp command. */
+       writew(0x0000,write_ptr+=2);                    /* Buffer address high bits (always zero). */
+
+       /* Output the Loop-back NoOp command. */
+       writew(0x0000,write_ptr+=2);                    /* Tx status */
+       writew(CmdNOp,write_ptr+=2);                    /* Tx command */
+       writew(tx_block+16,write_ptr+=2);               /* Next is myself. */
+
+       /* Output the packet at the write pointer. */
+       memcpy_toio(write_ptr+2, buf, length);
+       if (pad)
+               memcpy_toio(write_ptr+length+2, padding, pad);
+
+       /* Set the old command link pointing to this send packet. */
+       writew(tx_block,lp->base + lp->tx_cmd_link);
+       lp->tx_cmd_link = tx_block + 20;
+
+       /* Set the next free tx region. */
+       lp->tx_head = tx_block + TX_BUF_SIZE;
+       if (lp->tx_head > RX_BUF_START - TX_BUF_SIZE)
+               lp->tx_head = TX_BUF_START;
+
+       if (net_debug > 4) {
+               pr_debug("%s: 3c507 @%x send length = %d, tx_block %3x, next %3x.\n",
+                          dev->name, ioaddr, length, tx_block, lp->tx_head);
+       }
+
+       /* Grimly block further packets if there has been insufficient reaping. */
+       if (++lp->tx_pkts_in_ring < NUM_TX_BUFS)
+               netif_wake_queue(dev);
+}
+
+static void el16_rx(struct net_device *dev)
+{
+       struct net_local *lp = netdev_priv(dev);
+       void __iomem *shmem = lp->base;
+       ushort rx_head = lp->rx_head;
+       ushort rx_tail = lp->rx_tail;
+       ushort boguscount = 10;
+       short frame_status;
+
+       while ((frame_status = readw(shmem+rx_head)) < 0) {   /* Command complete */
+               void __iomem *read_frame = lp->base + rx_head;
+               ushort rfd_cmd = readw(read_frame+2);
+               ushort next_rx_frame = readw(read_frame+4);
+               ushort data_buffer_addr = readw(read_frame+6);
+               void __iomem *data_frame = lp->base + data_buffer_addr;
+               ushort pkt_len = readw(data_frame);
+
+               if (rfd_cmd != 0 || data_buffer_addr != rx_head + 22 ||
+                   (pkt_len & 0xC000) != 0xC000) {
+                       pr_err("%s: Rx frame at %#x corrupted, "
+                              "status %04x cmd %04x next %04x "
+                              "data-buf @%04x %04x.\n",
+                              dev->name, rx_head, frame_status, rfd_cmd,
+                              next_rx_frame, data_buffer_addr, pkt_len);
+               } else if ((frame_status & 0x2000) == 0) {
+                       /* Frame Rxed, but with error. */
+                       dev->stats.rx_errors++;
+                       if (frame_status & 0x0800) dev->stats.rx_crc_errors++;
+                       if (frame_status & 0x0400) dev->stats.rx_frame_errors++;
+                       if (frame_status & 0x0200) dev->stats.rx_fifo_errors++;
+                       if (frame_status & 0x0100) dev->stats.rx_over_errors++;
+                       if (frame_status & 0x0080) dev->stats.rx_length_errors++;
+               } else {
+                       /* Malloc up new buffer. */
+                       struct sk_buff *skb;
+
+                       pkt_len &= 0x3fff;
+                       skb = dev_alloc_skb(pkt_len+2);
+                       if (skb == NULL) {
+                               pr_err("%s: Memory squeeze, dropping packet.\n",
+                                      dev->name);
+                               dev->stats.rx_dropped++;
+                               break;
+                       }
+
+                       skb_reserve(skb,2);
+
+                       /* 'skb->data' points to the start of sk_buff data area. */
+                       memcpy_fromio(skb_put(skb,pkt_len), data_frame + 10, pkt_len);
+
+                       skb->protocol=eth_type_trans(skb,dev);
+                       netif_rx(skb);
+                       dev->stats.rx_packets++;
+                       dev->stats.rx_bytes += pkt_len;
+               }
+
+               /* Clear the status word and set End-of-List on the rx frame. */
+               writew(0,read_frame);
+               writew(0xC000,read_frame+2);
+               /* Clear the end-of-list on the prev. RFD. */
+               writew(0x0000,lp->base + rx_tail + 2);
+
+               rx_tail = rx_head;
+               rx_head = next_rx_frame;
+               if (--boguscount == 0)
+                       break;
+       }
+
+       lp->rx_head = rx_head;
+       lp->rx_tail = rx_tail;
+}
+
+static void netdev_get_drvinfo(struct net_device *dev,
+                              struct ethtool_drvinfo *info)
+{
+       strcpy(info->driver, DRV_NAME);
+       strcpy(info->version, DRV_VERSION);
+       sprintf(info->bus_info, "ISA 0x%lx", dev->base_addr);
+}
+
+static u32 netdev_get_msglevel(struct net_device *dev)
+{
+       return debug;
+}
+
+static void netdev_set_msglevel(struct net_device *dev, u32 level)
+{
+       debug = level;
+}
+
+static const struct ethtool_ops netdev_ethtool_ops = {
+       .get_drvinfo            = netdev_get_drvinfo,
+       .get_msglevel           = netdev_get_msglevel,
+       .set_msglevel           = netdev_set_msglevel,
+};
+
+#ifdef MODULE
+static struct net_device *dev_3c507;
+module_param(io, int, 0);
+module_param(irq, int, 0);
+MODULE_PARM_DESC(io, "EtherLink16 I/O base address");
+MODULE_PARM_DESC(irq, "(ignored)");
+
+int __init init_module(void)
+{
+       if (io == 0)
+               pr_notice("3c507: You should not use auto-probing with insmod!\n");
+       dev_3c507 = el16_probe(-1);
+       return IS_ERR(dev_3c507) ? PTR_ERR(dev_3c507) : 0;
+}
+
+void __exit
+cleanup_module(void)
+{
+       struct net_device *dev = dev_3c507;
+       unregister_netdev(dev);
+       free_irq(dev->irq, dev);
+       iounmap(((struct net_local *)netdev_priv(dev))->base);
+       release_region(dev->base_addr, EL16_IO_EXTENT);
+       free_netdev(dev);
+}
+#endif /* MODULE */
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/i825xx/3c523.c b/drivers/net/ethernet/i825xx/3c523.c
new file mode 100644 (file)
index 0000000..bc0d1a1
--- /dev/null
@@ -0,0 +1,1312 @@
+/*
+   net-3-driver for the 3c523 Etherlink/MC card (i82586 Ethernet chip)
+
+
+   This is an extension to the Linux operating system, and is covered by the
+   same GNU General Public License that covers that work.
+
+   Copyright 1995, 1996 by Chris Beauregard (cpbeaure@undergrad.math.uwaterloo.ca)
+
+   This is basically Michael Hipp's ni52 driver, with a new probing
+   algorithm and some minor changes to the 82586 CA and reset routines.
+   Thanks a lot Michael for a really clean i82586 implementation!  Unless
+   otherwise documented in ni52.c, any bugs are mine.
+
+   Contrary to the Ethernet-HOWTO, this isn't based on the 3c507 driver in
+   any way.  The ni52 is a lot easier to modify.
+
+   sources:
+   ni52.c
+
+   Crynwr packet driver collection was a great reference for my first
+   attempt at this sucker.  The 3c507 driver also helped, until I noticed
+   that ni52.c was a lot nicer.
+
+   EtherLink/MC: Micro Channel Ethernet Adapter Technical Reference
+   Manual, courtesy of 3Com CardFacts, documents the 3c523-specific
+   stuff.  Information on CardFacts is found in the Ethernet HOWTO.
+   Also see <a href="http://www.3com.com/">
+
+   Microprocessor Communications Support Chips, T.J. Byers, ISBN
+   0-444-01224-9, has a section on the i82586.  It tells you just enough
+   to know that you really don't want to learn how to program the chip.
+
+   The original device probe code was stolen from ps2esdi.c
+
+   Known Problems:
+   Since most of the code was stolen from ni52.c, you'll run across the
+   same bugs in the 0.62 version of ni52.c, plus maybe a few because of
+   the 3c523 idiosynchacies.  The 3c523 has 16K of RAM though, so there
+   shouldn't be the overrun problem that the 8K ni52 has.
+
+   This driver is for a 16K adapter.  It should work fine on the 64K
+   adapters, but it will only use one of the 4 banks of RAM.  Modifying
+   this for the 64K version would require a lot of heinous bank
+   switching, which I'm sure not interested in doing.  If you try to
+   implement a bank switching version, you'll basically have to remember
+   what bank is enabled and do a switch every time you access a memory
+   location that's not current.  You'll also have to remap pointers on
+   the driver side, because it only knows about 16K of the memory.
+   Anyone desperate or masochistic enough to try?
+
+   It seems to be stable now when multiple transmit buffers are used.  I
+   can't see any performance difference, but then I'm working on a 386SX.
+
+   Multicast doesn't work.  It doesn't even pretend to work.  Don't use
+   it.  Don't compile your kernel with multicast support.  I don't know
+   why.
+
+   Features:
+   This driver is useable as a loadable module.  If you try to specify an
+   IRQ or a IO address (via insmod 3c523.o irq=xx io=0xyyy), it will
+   search the MCA slots until it finds a 3c523 with the specified
+   parameters.
+
+   This driver does support multiple ethernet cards when used as a module
+   (up to MAX_3C523_CARDS, the default being 4)
+
+   This has been tested with both BNC and TP versions, internal and
+   external transceivers.  Haven't tested with the 64K version (that I
+   know of).
+
+   History:
+   Jan 1st, 1996
+   first public release
+   Feb 4th, 1996
+   update to 1.3.59, incorporated multicast diffs from ni52.c
+   Feb 15th, 1996
+   added shared irq support
+   Apr 1999
+   added support for multiple cards when used as a module
+   added option to disable multicast as is causes problems
+       Ganesh Sittampalam <ganesh.sittampalam@magdalen.oxford.ac.uk>
+       Stuart Adamson <stuart.adamson@compsoc.net>
+   Nov 2001
+   added support for ethtool (jgarzik)
+
+   $Header: /fsys2/home/chrisb/linux-1.3.59-MCA/drivers/net/RCS/3c523.c,v 1.1 1996/02/05 01:53:46 chrisb Exp chrisb $
+ */
+
+#define DRV_NAME               "3c523"
+#define DRV_VERSION            "17-Nov-2001"
+
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/skbuff.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/mca-legacy.h>
+#include <linux/ethtool.h>
+#include <linux/bitops.h>
+#include <linux/jiffies.h>
+
+#include <asm/uaccess.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+
+#include "3c523.h"
+
+/*************************************************************************/
+#define DEBUG                  /* debug on */
+#define SYSBUSVAL 0            /* 1 = 8 Bit, 0 = 16 bit - 3c523 only does 16 bit */
+#undef ELMC_MULTICAST          /* Disable multicast support as it is somewhat seriously broken at the moment */
+
+#define make32(ptr16) (p->memtop + (short) (ptr16) )
+#define make24(ptr32) ((char *) (ptr32) - p->base)
+#define make16(ptr32) ((unsigned short) ((unsigned long) (ptr32) - (unsigned long) p->memtop ))
+
+/*************************************************************************/
+/*
+   Tables to which we can map values in the configuration registers.
+ */
+static int irq_table[] __initdata = {
+       12, 7, 3, 9
+};
+
+static int csr_table[] __initdata = {
+       0x300, 0x1300, 0x2300, 0x3300
+};
+
+static int shm_table[] __initdata = {
+       0x0c0000, 0x0c8000, 0x0d0000, 0x0d8000
+};
+
+/******************* how to calculate the buffers *****************************
+
+
+  * IMPORTANT NOTE: if you configure only one NUM_XMIT_BUFFS, the driver works
+  * --------------- in a different (more stable?) mode. Only in this mode it's
+  *                 possible to configure the driver with 'NO_NOPCOMMANDS'
+
+sizeof(scp)=12; sizeof(scb)=16; sizeof(iscp)=8;
+sizeof(scp)+sizeof(iscp)+sizeof(scb) = 36 = INIT
+sizeof(rfd) = 24; sizeof(rbd) = 12;
+sizeof(tbd) = 8; sizeof(transmit_cmd) = 16;
+sizeof(nop_cmd) = 8;
+
+  * if you don't know the driver, better do not change this values: */
+
+#define RECV_BUFF_SIZE 1524    /* slightly oversized */
+#define XMIT_BUFF_SIZE 1524    /* slightly oversized */
+#define NUM_XMIT_BUFFS 1       /* config for both, 8K and 16K shmem */
+#define NUM_RECV_BUFFS_8  4    /* config for 8K shared mem */
+#define NUM_RECV_BUFFS_16 9    /* config for 16K shared mem */
+
+#if (NUM_XMIT_BUFFS == 1)
+#define NO_NOPCOMMANDS         /* only possible with NUM_XMIT_BUFFS=1 */
+#endif
+
+/**************************************************************************/
+
+#define DELAY(x) { mdelay(32 * x); }
+
+/* a much shorter delay: */
+#define DELAY_16(); { udelay(16) ; }
+
+/* wait for command with timeout: */
+#define WAIT_4_SCB_CMD() { int i; \
+  for(i=0;i<1024;i++) { \
+    if(!p->scb->cmd) break; \
+    DELAY_16(); \
+    if(i == 1023) { \
+      pr_warning("%s:%d: scb_cmd timed out .. resetting i82586\n",\
+       dev->name,__LINE__); \
+      elmc_id_reset586(); } } }
+
+static irqreturn_t elmc_interrupt(int irq, void *dev_id);
+static int elmc_open(struct net_device *dev);
+static int elmc_close(struct net_device *dev);
+static netdev_tx_t elmc_send_packet(struct sk_buff *, struct net_device *);
+static struct net_device_stats *elmc_get_stats(struct net_device *dev);
+static void elmc_timeout(struct net_device *dev);
+#ifdef ELMC_MULTICAST
+static void set_multicast_list(struct net_device *dev);
+#endif
+static const struct ethtool_ops netdev_ethtool_ops;
+
+/* helper-functions */
+static int init586(struct net_device *dev);
+static int check586(struct net_device *dev, unsigned long where, unsigned size);
+static void alloc586(struct net_device *dev);
+static void startrecv586(struct net_device *dev);
+static void *alloc_rfa(struct net_device *dev, void *ptr);
+static void elmc_rcv_int(struct net_device *dev);
+static void elmc_xmt_int(struct net_device *dev);
+static void elmc_rnr_int(struct net_device *dev);
+
+struct priv {
+       unsigned long base;
+       char *memtop;
+       unsigned long mapped_start;             /* Start of ioremap */
+       volatile struct rfd_struct *rfd_last, *rfd_top, *rfd_first;
+       volatile struct scp_struct *scp;        /* volatile is important */
+       volatile struct iscp_struct *iscp;      /* volatile is important */
+       volatile struct scb_struct *scb;        /* volatile is important */
+       volatile struct tbd_struct *xmit_buffs[NUM_XMIT_BUFFS];
+#if (NUM_XMIT_BUFFS == 1)
+       volatile struct transmit_cmd_struct *xmit_cmds[2];
+       volatile struct nop_cmd_struct *nop_cmds[2];
+#else
+       volatile struct transmit_cmd_struct *xmit_cmds[NUM_XMIT_BUFFS];
+       volatile struct nop_cmd_struct *nop_cmds[NUM_XMIT_BUFFS];
+#endif
+       volatile int nop_point, num_recv_buffs;
+       volatile char *xmit_cbuffs[NUM_XMIT_BUFFS];
+       volatile int xmit_count, xmit_last;
+       volatile int slot;
+};
+
+#define elmc_attn586()  {elmc_do_attn586(dev->base_addr,ELMC_CTRL_INTE);}
+#define elmc_reset586() {elmc_do_reset586(dev->base_addr,ELMC_CTRL_INTE);}
+
+/* with interrupts disabled - this will clear the interrupt bit in the
+   3c523 control register, and won't put it back.  This effectively
+   disables interrupts on the card. */
+#define elmc_id_attn586()  {elmc_do_attn586(dev->base_addr,0);}
+#define elmc_id_reset586() {elmc_do_reset586(dev->base_addr,0);}
+
+/*************************************************************************/
+/*
+   Do a Channel Attention on the 3c523.  This is extremely board dependent.
+ */
+static void elmc_do_attn586(int ioaddr, int ints)
+{
+       /* the 3c523 requires a minimum of 500 ns.  The delays here might be
+          a little too large, and hence they may cut the performance of the
+          card slightly.  If someone who knows a little more about Linux
+          timing would care to play with these, I'd appreciate it. */
+
+       /* this bit masking stuff is crap.  I'd rather have separate
+          registers with strobe triggers for each of these functions.  <sigh>
+          Ya take what ya got. */
+
+       outb(ELMC_CTRL_RST | 0x3 | ELMC_CTRL_CA | ints, ioaddr + ELMC_CTRL);
+       DELAY_16();             /* > 500 ns */
+       outb(ELMC_CTRL_RST | 0x3 | ints, ioaddr + ELMC_CTRL);
+}
+
+/*************************************************************************/
+/*
+   Reset the 82586 on the 3c523.  Also very board dependent.
+ */
+static void elmc_do_reset586(int ioaddr, int ints)
+{
+       /* toggle the RST bit low then high */
+       outb(0x3 | ELMC_CTRL_LBK, ioaddr + ELMC_CTRL);
+       DELAY_16();             /* > 500 ns */
+       outb(ELMC_CTRL_RST | ELMC_CTRL_LBK | 0x3, ioaddr + ELMC_CTRL);
+
+       elmc_do_attn586(ioaddr, ints);
+}
+
+/**********************************************
+ * close device
+ */
+
+static int elmc_close(struct net_device *dev)
+{
+       netif_stop_queue(dev);
+       elmc_id_reset586();     /* the hard way to stop the receiver */
+       free_irq(dev->irq, dev);
+       return 0;
+}
+
+/**********************************************
+ * open device
+ */
+
+static int elmc_open(struct net_device *dev)
+{
+       int ret;
+
+       elmc_id_attn586();      /* disable interrupts */
+
+       ret = request_irq(dev->irq, elmc_interrupt, IRQF_SHARED,
+                         dev->name, dev);
+       if (ret) {
+               pr_err("%s: couldn't get irq %d\n", dev->name, dev->irq);
+               elmc_id_reset586();
+               return ret;
+       }
+       alloc586(dev);
+       init586(dev);
+       startrecv586(dev);
+       netif_start_queue(dev);
+       return 0;               /* most done by init */
+}
+
+/**********************************************
+ * Check to see if there's an 82586 out there.
+ */
+
+static int __init check586(struct net_device *dev, unsigned long where, unsigned size)
+{
+       struct priv *p = netdev_priv(dev);
+       char *iscp_addrs[2];
+       int i = 0;
+
+       p->base = (unsigned long) isa_bus_to_virt((unsigned long)where) + size - 0x01000000;
+       p->memtop = isa_bus_to_virt((unsigned long)where) + size;
+       p->scp = (struct scp_struct *)(p->base + SCP_DEFAULT_ADDRESS);
+       memset((char *) p->scp, 0, sizeof(struct scp_struct));
+       p->scp->sysbus = SYSBUSVAL;     /* 1 = 8Bit-Bus, 0 = 16 Bit */
+
+       iscp_addrs[0] = isa_bus_to_virt((unsigned long)where);
+       iscp_addrs[1] = (char *) p->scp - sizeof(struct iscp_struct);
+
+       for (i = 0; i < 2; i++) {
+               p->iscp = (struct iscp_struct *) iscp_addrs[i];
+               memset((char *) p->iscp, 0, sizeof(struct iscp_struct));
+
+               p->scp->iscp = make24(p->iscp);
+               p->iscp->busy = 1;
+
+               elmc_id_reset586();
+
+               /* reset586 does an implicit CA */
+
+               /* apparently, you sometimes have to kick the 82586 twice... */
+               elmc_id_attn586();
+               DELAY(1);
+
+               if (p->iscp->busy) {    /* i82586 clears 'busy' after successful init */
+                       return 0;
+               }
+       }
+       return 1;
+}
+
+/******************************************************************
+ * set iscp at the right place, called by elmc_probe and open586.
+ */
+
+static void alloc586(struct net_device *dev)
+{
+       struct priv *p = netdev_priv(dev);
+
+       elmc_id_reset586();
+       DELAY(2);
+
+       p->scp = (struct scp_struct *) (p->base + SCP_DEFAULT_ADDRESS);
+       p->scb = (struct scb_struct *) isa_bus_to_virt(dev->mem_start);
+       p->iscp = (struct iscp_struct *) ((char *) p->scp - sizeof(struct iscp_struct));
+
+       memset((char *) p->iscp, 0, sizeof(struct iscp_struct));
+       memset((char *) p->scp, 0, sizeof(struct scp_struct));
+
+       p->scp->iscp = make24(p->iscp);
+       p->scp->sysbus = SYSBUSVAL;
+       p->iscp->scb_offset = make16(p->scb);
+
+       p->iscp->busy = 1;
+       elmc_id_reset586();
+       elmc_id_attn586();
+
+       DELAY(2);
+
+       if (p->iscp->busy)
+               pr_err("%s: Init-Problems (alloc).\n", dev->name);
+
+       memset((char *) p->scb, 0, sizeof(struct scb_struct));
+}
+
+/*****************************************************************/
+
+static int elmc_getinfo(char *buf, int slot, void *d)
+{
+       int len = 0;
+       struct net_device *dev = d;
+
+       if (dev == NULL)
+               return len;
+
+       len += sprintf(buf + len, "Revision: 0x%x\n",
+                      inb(dev->base_addr + ELMC_REVISION) & 0xf);
+       len += sprintf(buf + len, "IRQ: %d\n", dev->irq);
+       len += sprintf(buf + len, "IO Address: %#lx-%#lx\n", dev->base_addr,
+                      dev->base_addr + ELMC_IO_EXTENT);
+       len += sprintf(buf + len, "Memory: %#lx-%#lx\n", dev->mem_start,
+                      dev->mem_end - 1);
+       len += sprintf(buf + len, "Transceiver: %s\n", dev->if_port ?
+                      "External" : "Internal");
+       len += sprintf(buf + len, "Device: %s\n", dev->name);
+       len += sprintf(buf + len, "Hardware Address: %pM\n",
+                      dev->dev_addr);
+
+       return len;
+}                              /* elmc_getinfo() */
+
+static const struct net_device_ops netdev_ops = {
+       .ndo_open               = elmc_open,
+       .ndo_stop               = elmc_close,
+       .ndo_get_stats          = elmc_get_stats,
+       .ndo_start_xmit         = elmc_send_packet,
+       .ndo_tx_timeout         = elmc_timeout,
+#ifdef ELMC_MULTICAST
+       .ndo_set_multicast_list = set_multicast_list,
+#endif
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
+/*****************************************************************/
+
+static int __init do_elmc_probe(struct net_device *dev)
+{
+       static int slot;
+       int base_addr = dev->base_addr;
+       int irq = dev->irq;
+       u_char status = 0;
+       u_char revision = 0;
+       int i = 0;
+       unsigned int size = 0;
+       int retval;
+       struct priv *pr = netdev_priv(dev);
+
+       if (MCA_bus == 0) {
+               return -ENODEV;
+       }
+       /* search through the slots for the 3c523. */
+       slot = mca_find_adapter(ELMC_MCA_ID, 0);
+       while (slot != -1) {
+               status = mca_read_stored_pos(slot, 2);
+
+               dev->irq=irq_table[(status & ELMC_STATUS_IRQ_SELECT) >> 6];
+               dev->base_addr=csr_table[(status & ELMC_STATUS_CSR_SELECT) >> 1];
+
+               /*
+                  If we're trying to match a specified irq or IO address,
+                  we'll reject a match unless it's what we're looking for.
+                  Also reject it if the card is already in use.
+                */
+
+               if ((irq && irq != dev->irq) ||
+                   (base_addr && base_addr != dev->base_addr)) {
+                       slot = mca_find_adapter(ELMC_MCA_ID, slot + 1);
+                       continue;
+               }
+               if (!request_region(dev->base_addr, ELMC_IO_EXTENT, DRV_NAME)) {
+                       slot = mca_find_adapter(ELMC_MCA_ID, slot + 1);
+                       continue;
+               }
+
+               /* found what we're looking for... */
+               break;
+       }
+
+       /* we didn't find any 3c523 in the slots we checked for */
+       if (slot == MCA_NOTFOUND)
+               return (base_addr || irq) ? -ENXIO : -ENODEV;
+
+       mca_set_adapter_name(slot, "3Com 3c523 Etherlink/MC");
+       mca_set_adapter_procfn(slot, (MCA_ProcFn) elmc_getinfo, dev);
+
+       /* if we get this far, adapter has been found - carry on */
+       pr_info("%s: 3c523 adapter found in slot %d\n", dev->name, slot + 1);
+
+       /* Now we extract configuration info from the card.
+          The 3c523 provides information in two of the POS registers, but
+          the second one is only needed if we want to tell the card what IRQ
+          to use.  I suspect that whoever sets the thing up initially would
+          prefer we don't screw with those things.
+
+          Note that we read the status info when we found the card...
+
+          See 3c523.h for more details.
+        */
+
+       /* revision is stored in the first 4 bits of the revision register */
+       revision = inb(dev->base_addr + ELMC_REVISION) & 0xf;
+
+       /* according to docs, we read the interrupt and write it back to
+          the IRQ select register, since the POST might not configure the IRQ
+          properly. */
+       switch (dev->irq) {
+       case 3:
+               mca_write_pos(slot, 3, 0x04);
+               break;
+       case 7:
+               mca_write_pos(slot, 3, 0x02);
+               break;
+       case 9:
+               mca_write_pos(slot, 3, 0x08);
+               break;
+       case 12:
+               mca_write_pos(slot, 3, 0x01);
+               break;
+       }
+
+       pr->slot = slot;
+
+       pr_info("%s: 3Com 3c523 Rev 0x%x at %#lx\n", dev->name, (int) revision,
+              dev->base_addr);
+
+       /* Determine if we're using the on-board transceiver (i.e. coax) or
+          an external one.  The information is pretty much useless, but I
+          guess it's worth brownie points. */
+       dev->if_port = (status & ELMC_STATUS_DISABLE_THIN);
+
+       /* The 3c523 has a 24K chunk of memory.  The first 16K is the
+          shared memory, while the last 8K is for the EtherStart BIOS ROM.
+          Which we don't care much about here.  We'll just tell Linux that
+          we're using 16K.  MCA won't permit address space conflicts caused
+          by not mapping the other 8K. */
+       dev->mem_start = shm_table[(status & ELMC_STATUS_MEMORY_SELECT) >> 3];
+
+       /* We're using MCA, so it's a given that the information about memory
+          size is correct.  The Crynwr drivers do something like this. */
+
+       elmc_id_reset586();     /* seems like a good idea before checking it... */
+
+       size = 0x4000;          /* check for 16K mem */
+       if (!check586(dev, dev->mem_start, size)) {
+               pr_err("%s: memprobe, Can't find memory at 0x%lx!\n", dev->name,
+                      dev->mem_start);
+               retval = -ENODEV;
+               goto err_out;
+       }
+       dev->mem_end = dev->mem_start + size;   /* set mem_end showed by 'ifconfig' */
+
+       pr->memtop = isa_bus_to_virt(dev->mem_start) + size;
+       pr->base = (unsigned long) isa_bus_to_virt(dev->mem_start) + size - 0x01000000;
+       alloc586(dev);
+
+       elmc_id_reset586();     /* make sure it doesn't generate spurious ints */
+
+       /* set number of receive-buffs according to memsize */
+       pr->num_recv_buffs = NUM_RECV_BUFFS_16;
+
+       /* dump all the assorted information */
+       pr_info("%s: IRQ %d, %sternal xcvr, memory %#lx-%#lx.\n", dev->name,
+              dev->irq, dev->if_port ? "ex" : "in",
+              dev->mem_start, dev->mem_end - 1);
+
+       /* The hardware address for the 3c523 is stored in the first six
+          bytes of the IO address. */
+       for (i = 0; i < 6; i++)
+               dev->dev_addr[i] = inb(dev->base_addr + i);
+
+       pr_info("%s: hardware address %pM\n",
+              dev->name, dev->dev_addr);
+
+       dev->netdev_ops = &netdev_ops;
+       dev->watchdog_timeo = HZ;
+       dev->ethtool_ops = &netdev_ethtool_ops;
+
+       /* note that we haven't actually requested the IRQ from the kernel.
+          That gets done in elmc_open().  I'm not sure that's such a good idea,
+          but it works, so I'll go with it. */
+
+#ifndef ELMC_MULTICAST
+        dev->flags&=~IFF_MULTICAST;     /* Multicast doesn't work */
+#endif
+
+       retval = register_netdev(dev);
+       if (retval)
+               goto err_out;
+
+       return 0;
+err_out:
+       mca_set_adapter_procfn(slot, NULL, NULL);
+       release_region(dev->base_addr, ELMC_IO_EXTENT);
+       return retval;
+}
+
+#ifdef MODULE
+static void cleanup_card(struct net_device *dev)
+{
+       mca_set_adapter_procfn(((struct priv *)netdev_priv(dev))->slot,
+                               NULL, NULL);
+       release_region(dev->base_addr, ELMC_IO_EXTENT);
+}
+#else
+struct net_device * __init elmc_probe(int unit)
+{
+       struct net_device *dev = alloc_etherdev(sizeof(struct priv));
+       int err;
+
+       if (!dev)
+               return ERR_PTR(-ENOMEM);
+
+       sprintf(dev->name, "eth%d", unit);
+       netdev_boot_setup_check(dev);
+
+       err = do_elmc_probe(dev);
+       if (err)
+               goto out;
+       return dev;
+out:
+       free_netdev(dev);
+       return ERR_PTR(err);
+}
+#endif
+
+/**********************************************
+ * init the chip (elmc-interrupt should be disabled?!)
+ * needs a correct 'allocated' memory
+ */
+
+static int init586(struct net_device *dev)
+{
+       void *ptr;
+       unsigned long s;
+       int i, result = 0;
+       struct priv *p = netdev_priv(dev);
+       volatile struct configure_cmd_struct *cfg_cmd;
+       volatile struct iasetup_cmd_struct *ias_cmd;
+       volatile struct tdr_cmd_struct *tdr_cmd;
+       volatile struct mcsetup_cmd_struct *mc_cmd;
+       struct netdev_hw_addr *ha;
+       int num_addrs = netdev_mc_count(dev);
+
+       ptr = (void *) ((char *) p->scb + sizeof(struct scb_struct));
+
+       cfg_cmd = (struct configure_cmd_struct *) ptr;  /* configure-command */
+       cfg_cmd->cmd_status = 0;
+       cfg_cmd->cmd_cmd = CMD_CONFIGURE | CMD_LAST;
+       cfg_cmd->cmd_link = 0xffff;
+
+       cfg_cmd->byte_cnt = 0x0a;       /* number of cfg bytes */
+       cfg_cmd->fifo = 0x08;   /* fifo-limit (8=tx:32/rx:64) */
+       cfg_cmd->sav_bf = 0x40; /* hold or discard bad recv frames (bit 7) */
+       cfg_cmd->adr_len = 0x2e;        /* addr_len |!src_insert |pre-len |loopback */
+       cfg_cmd->priority = 0x00;
+       cfg_cmd->ifs = 0x60;
+       cfg_cmd->time_low = 0x00;
+       cfg_cmd->time_high = 0xf2;
+       cfg_cmd->promisc = 0;
+       if (dev->flags & (IFF_ALLMULTI | IFF_PROMISC))
+               cfg_cmd->promisc = 1;
+       cfg_cmd->carr_coll = 0x00;
+
+       p->scb->cbl_offset = make16(cfg_cmd);
+
+       p->scb->cmd = CUC_START;        /* cmd.-unit start */
+       elmc_id_attn586();
+
+       s = jiffies;            /* warning: only active with interrupts on !! */
+       while (!(cfg_cmd->cmd_status & STAT_COMPL)) {
+               if (time_after(jiffies, s + 30*HZ/100))
+                       break;
+       }
+
+       if ((cfg_cmd->cmd_status & (STAT_OK | STAT_COMPL)) != (STAT_COMPL | STAT_OK)) {
+               pr_warning("%s (elmc): configure command failed: %x\n", dev->name, cfg_cmd->cmd_status);
+               return 1;
+       }
+       /*
+        * individual address setup
+        */
+       ias_cmd = (struct iasetup_cmd_struct *) ptr;
+
+       ias_cmd->cmd_status = 0;
+       ias_cmd->cmd_cmd = CMD_IASETUP | CMD_LAST;
+       ias_cmd->cmd_link = 0xffff;
+
+       memcpy((char *) &ias_cmd->iaddr, (char *) dev->dev_addr, ETH_ALEN);
+
+       p->scb->cbl_offset = make16(ias_cmd);
+
+       p->scb->cmd = CUC_START;        /* cmd.-unit start */
+       elmc_id_attn586();
+
+       s = jiffies;
+       while (!(ias_cmd->cmd_status & STAT_COMPL)) {
+               if (time_after(jiffies, s + 30*HZ/100))
+                       break;
+       }
+
+       if ((ias_cmd->cmd_status & (STAT_OK | STAT_COMPL)) != (STAT_OK | STAT_COMPL)) {
+               pr_warning("%s (elmc): individual address setup command failed: %04x\n",
+                       dev->name, ias_cmd->cmd_status);
+               return 1;
+       }
+       /*
+        * TDR, wire check .. e.g. no resistor e.t.c
+        */
+       tdr_cmd = (struct tdr_cmd_struct *) ptr;
+
+       tdr_cmd->cmd_status = 0;
+       tdr_cmd->cmd_cmd = CMD_TDR | CMD_LAST;
+       tdr_cmd->cmd_link = 0xffff;
+       tdr_cmd->status = 0;
+
+       p->scb->cbl_offset = make16(tdr_cmd);
+
+       p->scb->cmd = CUC_START;        /* cmd.-unit start */
+       elmc_attn586();
+
+       s = jiffies;
+       while (!(tdr_cmd->cmd_status & STAT_COMPL)) {
+               if (time_after(jiffies, s + 30*HZ/100)) {
+                       pr_warning("%s: %d Problems while running the TDR.\n", dev->name, __LINE__);
+                       result = 1;
+                       break;
+               }
+       }
+
+       if (!result) {
+               DELAY(2);       /* wait for result */
+               result = tdr_cmd->status;
+
+               p->scb->cmd = p->scb->status & STAT_MASK;
+               elmc_id_attn586();      /* ack the interrupts */
+
+               if (result & TDR_LNK_OK) {
+                       /* empty */
+               } else if (result & TDR_XCVR_PRB) {
+                       pr_warning("%s: TDR: Transceiver problem!\n", dev->name);
+               } else if (result & TDR_ET_OPN) {
+                       pr_warning("%s: TDR: No correct termination %d clocks away.\n", dev->name, result & TDR_TIMEMASK);
+               } else if (result & TDR_ET_SRT) {
+                       if (result & TDR_TIMEMASK)      /* time == 0 -> strange :-) */
+                               pr_warning("%s: TDR: Detected a short circuit %d clocks away.\n", dev->name, result & TDR_TIMEMASK);
+               } else {
+                       pr_warning("%s: TDR: Unknown status %04x\n", dev->name, result);
+               }
+       }
+       /*
+        * ack interrupts
+        */
+       p->scb->cmd = p->scb->status & STAT_MASK;
+       elmc_id_attn586();
+
+       /*
+        * alloc nop/xmit-cmds
+        */
+#if (NUM_XMIT_BUFFS == 1)
+       for (i = 0; i < 2; i++) {
+               p->nop_cmds[i] = (struct nop_cmd_struct *) ptr;
+               p->nop_cmds[i]->cmd_cmd = CMD_NOP;
+               p->nop_cmds[i]->cmd_status = 0;
+               p->nop_cmds[i]->cmd_link = make16((p->nop_cmds[i]));
+               ptr = (char *) ptr + sizeof(struct nop_cmd_struct);
+       }
+       p->xmit_cmds[0] = (struct transmit_cmd_struct *) ptr;   /* transmit cmd/buff 0 */
+       ptr = (char *) ptr + sizeof(struct transmit_cmd_struct);
+#else
+       for (i = 0; i < NUM_XMIT_BUFFS; i++) {
+               p->nop_cmds[i] = (struct nop_cmd_struct *) ptr;
+               p->nop_cmds[i]->cmd_cmd = CMD_NOP;
+               p->nop_cmds[i]->cmd_status = 0;
+               p->nop_cmds[i]->cmd_link = make16((p->nop_cmds[i]));
+               ptr = (char *) ptr + sizeof(struct nop_cmd_struct);
+               p->xmit_cmds[i] = (struct transmit_cmd_struct *) ptr;   /*transmit cmd/buff 0 */
+               ptr = (char *) ptr + sizeof(struct transmit_cmd_struct);
+       }
+#endif
+
+       ptr = alloc_rfa(dev, (void *) ptr);     /* init receive-frame-area */
+
+       /*
+        * Multicast setup
+        */
+
+       if (num_addrs) {
+               /* I don't understand this: do we really need memory after the init? */
+               int len = ((char *) p->iscp - (char *) ptr - 8) / 6;
+               if (len <= 0) {
+                       pr_err("%s: Ooooops, no memory for MC-Setup!\n", dev->name);
+               } else {
+                       if (len < num_addrs) {
+                               num_addrs = len;
+                               pr_warning("%s: Sorry, can only apply %d MC-Address(es).\n",
+                                      dev->name, num_addrs);
+                       }
+                       mc_cmd = (struct mcsetup_cmd_struct *) ptr;
+                       mc_cmd->cmd_status = 0;
+                       mc_cmd->cmd_cmd = CMD_MCSETUP | CMD_LAST;
+                       mc_cmd->cmd_link = 0xffff;
+                       mc_cmd->mc_cnt = num_addrs * 6;
+                       i = 0;
+                       netdev_for_each_mc_addr(ha, dev)
+                               memcpy((char *) mc_cmd->mc_list[i++],
+                                      ha->addr, 6);
+                       p->scb->cbl_offset = make16(mc_cmd);
+                       p->scb->cmd = CUC_START;
+                       elmc_id_attn586();
+                       s = jiffies;
+                       while (!(mc_cmd->cmd_status & STAT_COMPL)) {
+                               if (time_after(jiffies, s + 30*HZ/100))
+                                       break;
+                       }
+                       if (!(mc_cmd->cmd_status & STAT_COMPL)) {
+                               pr_warning("%s: Can't apply multicast-address-list.\n", dev->name);
+                       }
+               }
+       }
+       /*
+        * alloc xmit-buffs / init xmit_cmds
+        */
+       for (i = 0; i < NUM_XMIT_BUFFS; i++) {
+               p->xmit_cbuffs[i] = (char *) ptr;       /* char-buffs */
+               ptr = (char *) ptr + XMIT_BUFF_SIZE;
+               p->xmit_buffs[i] = (struct tbd_struct *) ptr;   /* TBD */
+               ptr = (char *) ptr + sizeof(struct tbd_struct);
+               if ((void *) ptr > (void *) p->iscp) {
+                       pr_err("%s: not enough shared-mem for your configuration!\n", dev->name);
+                       return 1;
+               }
+               memset((char *) (p->xmit_cmds[i]), 0, sizeof(struct transmit_cmd_struct));
+               memset((char *) (p->xmit_buffs[i]), 0, sizeof(struct tbd_struct));
+               p->xmit_cmds[i]->cmd_status = STAT_COMPL;
+               p->xmit_cmds[i]->cmd_cmd = CMD_XMIT | CMD_INT;
+               p->xmit_cmds[i]->tbd_offset = make16((p->xmit_buffs[i]));
+               p->xmit_buffs[i]->next = 0xffff;
+               p->xmit_buffs[i]->buffer = make24((p->xmit_cbuffs[i]));
+       }
+
+       p->xmit_count = 0;
+       p->xmit_last = 0;
+#ifndef NO_NOPCOMMANDS
+       p->nop_point = 0;
+#endif
+
+       /*
+        * 'start transmitter' (nop-loop)
+        */
+#ifndef NO_NOPCOMMANDS
+       p->scb->cbl_offset = make16(p->nop_cmds[0]);
+       p->scb->cmd = CUC_START;
+       elmc_id_attn586();
+       WAIT_4_SCB_CMD();
+#else
+       p->xmit_cmds[0]->cmd_link = 0xffff;
+       p->xmit_cmds[0]->cmd_cmd = CMD_XMIT | CMD_LAST | CMD_INT;
+#endif
+
+       return 0;
+}
+
+/******************************************************
+ * This is a helper routine for elmc_rnr_int() and init586().
+ * It sets up the Receive Frame Area (RFA).
+ */
+
+static void *alloc_rfa(struct net_device *dev, void *ptr)
+{
+       volatile struct rfd_struct *rfd = (struct rfd_struct *) ptr;
+       volatile struct rbd_struct *rbd;
+       int i;
+       struct priv *p = netdev_priv(dev);
+
+       memset((char *) rfd, 0, sizeof(struct rfd_struct) * p->num_recv_buffs);
+       p->rfd_first = rfd;
+
+       for (i = 0; i < p->num_recv_buffs; i++) {
+               rfd[i].next = make16(rfd + (i + 1) % p->num_recv_buffs);
+       }
+       rfd[p->num_recv_buffs - 1].last = RFD_SUSP;     /* RU suspend */
+
+       ptr = (void *) (rfd + p->num_recv_buffs);
+
+       rbd = (struct rbd_struct *) ptr;
+       ptr = (void *) (rbd + p->num_recv_buffs);
+
+       /* clr descriptors */
+       memset((char *) rbd, 0, sizeof(struct rbd_struct) * p->num_recv_buffs);
+
+       for (i = 0; i < p->num_recv_buffs; i++) {
+               rbd[i].next = make16((rbd + (i + 1) % p->num_recv_buffs));
+               rbd[i].size = RECV_BUFF_SIZE;
+               rbd[i].buffer = make24(ptr);
+               ptr = (char *) ptr + RECV_BUFF_SIZE;
+       }
+
+       p->rfd_top = p->rfd_first;
+       p->rfd_last = p->rfd_first + p->num_recv_buffs - 1;
+
+       p->scb->rfa_offset = make16(p->rfd_first);
+       p->rfd_first->rbd_offset = make16(rbd);
+
+       return ptr;
+}
+
+
+/**************************************************
+ * Interrupt Handler ...
+ */
+
+static irqreturn_t
+elmc_interrupt(int irq, void *dev_id)
+{
+       struct net_device *dev = dev_id;
+       unsigned short stat;
+       struct priv *p;
+
+       if (!netif_running(dev)) {
+               /* The 3c523 has this habit of generating interrupts during the
+                  reset.  I'm not sure if the ni52 has this same problem, but it's
+                  really annoying if we haven't finished initializing it.  I was
+                  hoping all the elmc_id_* commands would disable this, but I
+                  might have missed a few. */
+
+               elmc_id_attn586();      /* ack inter. and disable any more */
+               return IRQ_HANDLED;
+       } else if (!(ELMC_CTRL_INT & inb(dev->base_addr + ELMC_CTRL))) {
+               /* wasn't this device */
+               return IRQ_NONE;
+       }
+       /* reading ELMC_CTRL also clears the INT bit. */
+
+       p = netdev_priv(dev);
+
+       while ((stat = p->scb->status & STAT_MASK))
+       {
+               p->scb->cmd = stat;
+               elmc_attn586(); /* ack inter. */
+
+               if (stat & STAT_CX) {
+                       /* command with I-bit set complete */
+                       elmc_xmt_int(dev);
+               }
+               if (stat & STAT_FR) {
+                       /* received a frame */
+                       elmc_rcv_int(dev);
+               }
+#ifndef NO_NOPCOMMANDS
+               if (stat & STAT_CNA) {
+                       /* CU went 'not ready' */
+                       if (netif_running(dev)) {
+                               pr_warning("%s: oops! CU has left active state. stat: %04x/%04x.\n",
+                                       dev->name, (int) stat, (int) p->scb->status);
+                       }
+               }
+#endif
+
+               if (stat & STAT_RNR) {
+                       /* RU went 'not ready' */
+
+                       if (p->scb->status & RU_SUSPEND) {
+                               /* special case: RU_SUSPEND */
+
+                               WAIT_4_SCB_CMD();
+                               p->scb->cmd = RUC_RESUME;
+                               elmc_attn586();
+                       } else {
+                               pr_warning("%s: Receiver-Unit went 'NOT READY': %04x/%04x.\n",
+                                       dev->name, (int) stat, (int) p->scb->status);
+                               elmc_rnr_int(dev);
+                       }
+               }
+               WAIT_4_SCB_CMD();       /* wait for ack. (elmc_xmt_int can be faster than ack!!) */
+               if (p->scb->cmd) {      /* timed out? */
+                       break;
+               }
+       }
+       return IRQ_HANDLED;
+}
+
+/*******************************************************
+ * receive-interrupt
+ */
+
+static void elmc_rcv_int(struct net_device *dev)
+{
+       int status;
+       unsigned short totlen;
+       struct sk_buff *skb;
+       struct rbd_struct *rbd;
+       struct priv *p = netdev_priv(dev);
+
+       for (; (status = p->rfd_top->status) & STAT_COMPL;) {
+               rbd = (struct rbd_struct *) make32(p->rfd_top->rbd_offset);
+
+               if (status & STAT_OK) {         /* frame received without error? */
+                       if ((totlen = rbd->status) & RBD_LAST) {        /* the first and the last buffer? */
+                               totlen &= RBD_MASK;     /* length of this frame */
+                               rbd->status = 0;
+                               skb = (struct sk_buff *) dev_alloc_skb(totlen + 2);
+                               if (skb != NULL) {
+                                       skb_reserve(skb, 2);    /* 16 byte alignment */
+                                       skb_put(skb,totlen);
+                                       skb_copy_to_linear_data(skb, (char *) p->base+(unsigned long) rbd->buffer,totlen);
+                                       skb->protocol = eth_type_trans(skb, dev);
+                                       netif_rx(skb);
+                                       dev->stats.rx_packets++;
+                                       dev->stats.rx_bytes += totlen;
+                               } else {
+                                       dev->stats.rx_dropped++;
+                               }
+                       } else {
+                               pr_warning("%s: received oversized frame.\n", dev->name);
+                               dev->stats.rx_dropped++;
+                       }
+               } else {        /* frame !(ok), only with 'save-bad-frames' */
+                       pr_warning("%s: oops! rfd-error-status: %04x\n", dev->name, status);
+                       dev->stats.rx_errors++;
+               }
+               p->rfd_top->status = 0;
+               p->rfd_top->last = RFD_SUSP;
+               p->rfd_last->last = 0;  /* delete RU_SUSP  */
+               p->rfd_last = p->rfd_top;
+               p->rfd_top = (struct rfd_struct *) make32(p->rfd_top->next);    /* step to next RFD */
+       }
+}
+
+/**********************************************************
+ * handle 'Receiver went not ready'.
+ */
+
+static void elmc_rnr_int(struct net_device *dev)
+{
+       struct priv *p = netdev_priv(dev);
+
+       dev->stats.rx_errors++;
+
+       WAIT_4_SCB_CMD();       /* wait for the last cmd */
+       p->scb->cmd = RUC_ABORT;        /* usually the RU is in the 'no resource'-state .. abort it now. */
+       elmc_attn586();
+       WAIT_4_SCB_CMD();       /* wait for accept cmd. */
+
+       alloc_rfa(dev, (char *) p->rfd_first);
+       startrecv586(dev);      /* restart RU */
+
+       pr_warning("%s: Receive-Unit restarted. Status: %04x\n", dev->name, p->scb->status);
+
+}
+
+/**********************************************************
+ * handle xmit - interrupt
+ */
+
+static void elmc_xmt_int(struct net_device *dev)
+{
+       int status;
+       struct priv *p = netdev_priv(dev);
+
+       status = p->xmit_cmds[p->xmit_last]->cmd_status;
+       if (!(status & STAT_COMPL)) {
+               pr_warning("%s: strange .. xmit-int without a 'COMPLETE'\n", dev->name);
+       }
+       if (status & STAT_OK) {
+               dev->stats.tx_packets++;
+               dev->stats.collisions += (status & TCMD_MAXCOLLMASK);
+       } else {
+               dev->stats.tx_errors++;
+               if (status & TCMD_LATECOLL) {
+                       pr_warning("%s: late collision detected.\n", dev->name);
+                       dev->stats.collisions++;
+               } else if (status & TCMD_NOCARRIER) {
+                       dev->stats.tx_carrier_errors++;
+                       pr_warning("%s: no carrier detected.\n", dev->name);
+               } else if (status & TCMD_LOSTCTS) {
+                       pr_warning("%s: loss of CTS detected.\n", dev->name);
+               } else if (status & TCMD_UNDERRUN) {
+                       dev->stats.tx_fifo_errors++;
+                       pr_warning("%s: DMA underrun detected.\n", dev->name);
+               } else if (status & TCMD_MAXCOLL) {
+                       pr_warning("%s: Max. collisions exceeded.\n", dev->name);
+                       dev->stats.collisions += 16;
+               }
+       }
+
+#if (NUM_XMIT_BUFFS != 1)
+       if ((++p->xmit_last) == NUM_XMIT_BUFFS) {
+               p->xmit_last = 0;
+       }
+#endif
+
+       netif_wake_queue(dev);
+}
+
+/***********************************************************
+ * (re)start the receiver
+ */
+
+static void startrecv586(struct net_device *dev)
+{
+       struct priv *p = netdev_priv(dev);
+
+       p->scb->rfa_offset = make16(p->rfd_first);
+       p->scb->cmd = RUC_START;
+       elmc_attn586();         /* start cmd. */
+       WAIT_4_SCB_CMD();       /* wait for accept cmd. (no timeout!!) */
+}
+
+/******************************************************
+ * timeout
+ */
+
+static void elmc_timeout(struct net_device *dev)
+{
+       struct priv *p = netdev_priv(dev);
+       /* COMMAND-UNIT active? */
+       if (p->scb->status & CU_ACTIVE) {
+               pr_debug("%s: strange ... timeout with CU active?!?\n", dev->name);
+               pr_debug("%s: X0: %04x N0: %04x N1: %04x %d\n", dev->name,
+                       (int)p->xmit_cmds[0]->cmd_status,
+                       (int)p->nop_cmds[0]->cmd_status,
+                       (int)p->nop_cmds[1]->cmd_status, (int)p->nop_point);
+               p->scb->cmd = CUC_ABORT;
+               elmc_attn586();
+               WAIT_4_SCB_CMD();
+               p->scb->cbl_offset = make16(p->nop_cmds[p->nop_point]);
+               p->scb->cmd = CUC_START;
+               elmc_attn586();
+               WAIT_4_SCB_CMD();
+               netif_wake_queue(dev);
+       } else {
+               pr_debug("%s: xmitter timed out, try to restart! stat: %04x\n",
+                       dev->name, p->scb->status);
+               pr_debug("%s: command-stats: %04x %04x\n", dev->name,
+                       p->xmit_cmds[0]->cmd_status, p->xmit_cmds[1]->cmd_status);
+               elmc_close(dev);
+               elmc_open(dev);
+       }
+}
+
+/******************************************************
+ * send frame
+ */
+
+static netdev_tx_t elmc_send_packet(struct sk_buff *skb, struct net_device *dev)
+{
+       int len;
+       int i;
+#ifndef NO_NOPCOMMANDS
+       int next_nop;
+#endif
+       struct priv *p = netdev_priv(dev);
+
+       netif_stop_queue(dev);
+
+       len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
+
+       if (len != skb->len)
+               memset((char *) p->xmit_cbuffs[p->xmit_count], 0, ETH_ZLEN);
+       skb_copy_from_linear_data(skb, (char *) p->xmit_cbuffs[p->xmit_count], skb->len);
+
+#if (NUM_XMIT_BUFFS == 1)
+#ifdef NO_NOPCOMMANDS
+       p->xmit_buffs[0]->size = TBD_LAST | len;
+       for (i = 0; i < 16; i++) {
+               p->scb->cbl_offset = make16(p->xmit_cmds[0]);
+               p->scb->cmd = CUC_START;
+               p->xmit_cmds[0]->cmd_status = 0;
+                       elmc_attn586();
+               if (!i) {
+                       dev_kfree_skb(skb);
+               }
+               WAIT_4_SCB_CMD();
+               if ((p->scb->status & CU_ACTIVE)) {     /* test it, because CU sometimes doesn't start immediately */
+                       break;
+               }
+               if (p->xmit_cmds[0]->cmd_status) {
+                       break;
+               }
+               if (i == 15) {
+                       pr_warning("%s: Can't start transmit-command.\n", dev->name);
+               }
+       }
+#else
+       next_nop = (p->nop_point + 1) & 0x1;
+       p->xmit_buffs[0]->size = TBD_LAST | len;
+
+       p->xmit_cmds[0]->cmd_link = p->nop_cmds[next_nop]->cmd_link
+           = make16((p->nop_cmds[next_nop]));
+       p->xmit_cmds[0]->cmd_status = p->nop_cmds[next_nop]->cmd_status = 0;
+
+       p->nop_cmds[p->nop_point]->cmd_link = make16((p->xmit_cmds[0]));
+       p->nop_point = next_nop;
+       dev_kfree_skb(skb);
+#endif
+#else
+       p->xmit_buffs[p->xmit_count]->size = TBD_LAST | len;
+       if ((next_nop = p->xmit_count + 1) == NUM_XMIT_BUFFS) {
+               next_nop = 0;
+       }
+       p->xmit_cmds[p->xmit_count]->cmd_status = 0;
+       p->xmit_cmds[p->xmit_count]->cmd_link = p->nop_cmds[next_nop]->cmd_link
+           = make16((p->nop_cmds[next_nop]));
+       p->nop_cmds[next_nop]->cmd_status = 0;
+               p->nop_cmds[p->xmit_count]->cmd_link = make16((p->xmit_cmds[p->xmit_count]));
+       p->xmit_count = next_nop;
+       if (p->xmit_count != p->xmit_last)
+               netif_wake_queue(dev);
+       dev_kfree_skb(skb);
+#endif
+       return NETDEV_TX_OK;
+}
+
+/*******************************************
+ * Someone wanna have the statistics
+ */
+
+static struct net_device_stats *elmc_get_stats(struct net_device *dev)
+{
+       struct priv *p = netdev_priv(dev);
+       unsigned short crc, aln, rsc, ovrn;
+
+       crc = p->scb->crc_errs; /* get error-statistic from the ni82586 */
+       p->scb->crc_errs -= crc;
+       aln = p->scb->aln_errs;
+       p->scb->aln_errs -= aln;
+       rsc = p->scb->rsc_errs;
+       p->scb->rsc_errs -= rsc;
+       ovrn = p->scb->ovrn_errs;
+       p->scb->ovrn_errs -= ovrn;
+
+       dev->stats.rx_crc_errors += crc;
+       dev->stats.rx_fifo_errors += ovrn;
+       dev->stats.rx_frame_errors += aln;
+       dev->stats.rx_dropped += rsc;
+
+       return &dev->stats;
+}
+
+/********************************************************
+ * Set MC list ..
+ */
+
+#ifdef ELMC_MULTICAST
+static void set_multicast_list(struct net_device *dev)
+{
+       if (!dev->start) {
+               /* without a running interface, promiscuous doesn't work */
+               return;
+       }
+       dev->start = 0;
+       alloc586(dev);
+       init586(dev);
+       startrecv586(dev);
+       dev->start = 1;
+}
+#endif
+
+static void netdev_get_drvinfo(struct net_device *dev,
+                              struct ethtool_drvinfo *info)
+{
+       strcpy(info->driver, DRV_NAME);
+       strcpy(info->version, DRV_VERSION);
+       sprintf(info->bus_info, "MCA 0x%lx", dev->base_addr);
+}
+
+static const struct ethtool_ops netdev_ethtool_ops = {
+       .get_drvinfo            = netdev_get_drvinfo,
+};
+
+#ifdef MODULE
+
+/* Increase if needed ;) */
+#define MAX_3C523_CARDS 4
+
+static struct net_device *dev_elmc[MAX_3C523_CARDS];
+static int irq[MAX_3C523_CARDS];
+static int io[MAX_3C523_CARDS];
+module_param_array(irq, int, NULL, 0);
+module_param_array(io, int, NULL, 0);
+MODULE_PARM_DESC(io, "EtherLink/MC I/O base address(es)");
+MODULE_PARM_DESC(irq, "EtherLink/MC IRQ number(s)");
+MODULE_LICENSE("GPL");
+
+int __init init_module(void)
+{
+       int this_dev,found = 0;
+
+       /* Loop until we either can't find any more cards, or we have MAX_3C523_CARDS */
+       for(this_dev=0; this_dev<MAX_3C523_CARDS; this_dev++) {
+               struct net_device *dev = alloc_etherdev(sizeof(struct priv));
+               if (!dev)
+                       break;
+               dev->irq=irq[this_dev];
+               dev->base_addr=io[this_dev];
+               if (do_elmc_probe(dev) == 0) {
+                       dev_elmc[this_dev] = dev;
+                       found++;
+                       continue;
+               }
+               free_netdev(dev);
+               if (io[this_dev]==0)
+                       break;
+               pr_warning("3c523.c: No 3c523 card found at io=%#x\n",io[this_dev]);
+       }
+
+       if(found==0) {
+               if (io[0]==0)
+                       pr_notice("3c523.c: No 3c523 cards found\n");
+               return -ENXIO;
+       } else return 0;
+}
+
+void __exit cleanup_module(void)
+{
+       int this_dev;
+       for (this_dev=0; this_dev<MAX_3C523_CARDS; this_dev++) {
+               struct net_device *dev = dev_elmc[this_dev];
+               if (dev) {
+                       unregister_netdev(dev);
+                       cleanup_card(dev);
+                       free_netdev(dev);
+               }
+       }
+}
+
+#endif                         /* MODULE */
diff --git a/drivers/net/ethernet/i825xx/3c523.h b/drivers/net/ethernet/i825xx/3c523.h
new file mode 100644 (file)
index 0000000..6956441
--- /dev/null
@@ -0,0 +1,355 @@
+#ifndef _3c523_INCLUDE_
+#define _3c523_INCLUDE_
+/*
+       This is basically a hacked version of ni52.h, for the 3c523
+       Etherlink/MC.
+*/
+
+/*
+ * Intel i82586 Ethernet definitions
+ *
+ * This is an extension to the Linux operating system, and is covered by the
+ * same GNU General Public License that covers that work.
+ *
+ * Copyright 1995 by Chris Beauregard (cpbeaure@undergrad.math.uwaterloo.ca)
+ *
+ * See 3c523.c for details.
+ *
+ * $Header: /home/chrisb/linux-1.2.13-3c523/drivers/net/RCS/3c523.h,v 1.6 1996/01/20 05:09:00 chrisb Exp chrisb $
+ */
+
+/*
+ * where to find the System Configuration Pointer (SCP)
+ */
+#define SCP_DEFAULT_ADDRESS 0xfffff4
+
+
+/*
+ * System Configuration Pointer Struct
+ */
+
+struct scp_struct
+{
+  unsigned short zero_dum0;    /* has to be zero */
+  unsigned char  sysbus;       /* 0=16Bit,1=8Bit */
+  unsigned char  zero_dum1;    /* has to be zero for 586 */
+  unsigned short zero_dum2;
+  unsigned short zero_dum3;
+  char          *iscp;         /* pointer to the iscp-block */
+};
+
+
+/*
+ * Intermediate System Configuration Pointer (ISCP)
+ */
+struct iscp_struct
+{
+  unsigned char  busy;          /* 586 clears after successful init */
+  unsigned char  zero_dummy;    /* hast to be zero */
+  unsigned short scb_offset;    /* pointeroffset to the scb_base */
+  char          *scb_base;      /* base-address of all 16-bit offsets */
+};
+
+/*
+ * System Control Block (SCB)
+ */
+struct scb_struct
+{
+  unsigned short status;        /* status word */
+  unsigned short cmd;           /* command word */
+  unsigned short cbl_offset;    /* pointeroffset, command block list */
+  unsigned short rfa_offset;    /* pointeroffset, receive frame area */
+  unsigned short crc_errs;      /* CRC-Error counter */
+  unsigned short aln_errs;      /* alignmenterror counter */
+  unsigned short rsc_errs;      /* Resourceerror counter */
+  unsigned short ovrn_errs;     /* OVerrunerror counter */
+};
+
+/*
+ * possible command values for the command word
+ */
+#define RUC_MASK       0x0070  /* mask for RU commands */
+#define RUC_NOP                0x0000  /* NOP-command */
+#define RUC_START      0x0010  /* start RU */
+#define RUC_RESUME     0x0020  /* resume RU after suspend */
+#define RUC_SUSPEND    0x0030  /* suspend RU */
+#define RUC_ABORT      0x0040  /* abort receiver operation immediately */
+
+#define CUC_MASK       0x0700  /* mask for CU command */
+#define CUC_NOP                0x0000  /* NOP-command */
+#define CUC_START      0x0100  /* start execution of 1. cmd on the CBL */
+#define CUC_RESUME     0x0200  /* resume after suspend */
+#define CUC_SUSPEND    0x0300  /* Suspend CU */
+#define CUC_ABORT      0x0400  /* abort command operation immediately */
+
+#define ACK_MASK       0xf000  /* mask for ACK command */
+#define ACK_CX         0x8000  /* acknowledges STAT_CX */
+#define ACK_FR         0x4000  /* ack. STAT_FR */
+#define ACK_CNA                0x2000  /* ack. STAT_CNA */
+#define ACK_RNR                0x1000  /* ack. STAT_RNR */
+
+/*
+ * possible status values for the status word
+ */
+#define STAT_MASK      0xf000  /* mask for cause of interrupt */
+#define STAT_CX                0x8000  /* CU finished cmd with its I bit set */
+#define STAT_FR                0x4000  /* RU finished receiving a frame */
+#define STAT_CNA       0x2000  /* CU left active state */
+#define STAT_RNR       0x1000  /* RU left ready state */
+
+#define CU_STATUS      0x700   /* CU status, 0=idle */
+#define CU_SUSPEND     0x100   /* CU is suspended */
+#define CU_ACTIVE      0x200   /* CU is active */
+
+#define RU_STATUS      0x70    /* RU status, 0=idle */
+#define RU_SUSPEND     0x10    /* RU suspended */
+#define RU_NOSPACE     0x20    /* RU no resources */
+#define RU_READY       0x40    /* RU is ready */
+
+/*
+ * Receive Frame Descriptor (RFD)
+ */
+struct rfd_struct
+{
+  unsigned short status;       /* status word */
+  unsigned short last;         /* Bit15,Last Frame on List / Bit14,suspend */
+  unsigned short next;         /* linkoffset to next RFD */
+  unsigned short rbd_offset;   /* pointeroffset to RBD-buffer */
+  unsigned char  dest[6];      /* ethernet-address, destination */
+  unsigned char  source[6];    /* ethernet-address, source */
+  unsigned short length;       /* 802.3 frame-length */
+  unsigned short zero_dummy;   /* dummy */
+};
+
+#define RFD_LAST     0x8000    /* last: last rfd in the list */
+#define RFD_SUSP     0x4000    /* last: suspend RU after  */
+#define RFD_ERRMASK  0x0fe1     /* status: errormask */
+#define RFD_MATCHADD 0x0002     /* status: Destinationaddress !matches IA */
+#define RFD_RNR      0x0200    /* status: receiver out of resources */
+
+/*
+ * Receive Buffer Descriptor (RBD)
+ */
+struct rbd_struct
+{
+  unsigned short status;       /* status word,number of used bytes in buff */
+  unsigned short next;         /* pointeroffset to next RBD */
+  char          *buffer;       /* receive buffer address pointer */
+  unsigned short size;         /* size of this buffer */
+  unsigned short zero_dummy;    /* dummy */
+};
+
+#define RBD_LAST       0x8000  /* last buffer */
+#define RBD_USED       0x4000  /* this buffer has data */
+#define RBD_MASK       0x3fff  /* size-mask for length */
+
+/*
+ * Statusvalues for Commands/RFD
+ */
+#define STAT_COMPL   0x8000    /* status: frame/command is complete */
+#define STAT_BUSY    0x4000    /* status: frame/command is busy */
+#define STAT_OK      0x2000    /* status: frame/command is ok */
+
+/*
+ * Action-Commands
+ */
+#define CMD_NOP                0x0000  /* NOP */
+#define CMD_IASETUP    0x0001  /* initial address setup command */
+#define CMD_CONFIGURE  0x0002  /* configure command */
+#define CMD_MCSETUP    0x0003  /* MC setup command */
+#define CMD_XMIT       0x0004  /* transmit command */
+#define CMD_TDR                0x0005  /* time domain reflectometer (TDR) command */
+#define CMD_DUMP       0x0006  /* dump command */
+#define CMD_DIAGNOSE   0x0007  /* diagnose command */
+
+/*
+ * Action command bits
+ */
+#define CMD_LAST       0x8000  /* indicates last command in the CBL */
+#define CMD_SUSPEND    0x4000  /* suspend CU after this CB */
+#define CMD_INT                0x2000  /* generate interrupt after execution */
+
+/*
+ * NOP - command
+ */
+struct nop_cmd_struct
+{
+  unsigned short cmd_status;   /* status of this command */
+  unsigned short cmd_cmd;       /* the command itself (+bits) */
+  unsigned short cmd_link;      /* offsetpointer to next command */
+};
+
+/*
+ * IA Setup command
+ */
+struct iasetup_cmd_struct
+{
+  unsigned short cmd_status;
+  unsigned short cmd_cmd;
+  unsigned short cmd_link;
+  unsigned char  iaddr[6];
+};
+
+/*
+ * Configure command
+ */
+struct configure_cmd_struct
+{
+  unsigned short cmd_status;
+  unsigned short cmd_cmd;
+  unsigned short cmd_link;
+  unsigned char  byte_cnt;   /* size of the config-cmd */
+  unsigned char  fifo;       /* fifo/recv monitor */
+  unsigned char  sav_bf;     /* save bad frames (bit7=1)*/
+  unsigned char  adr_len;    /* adr_len(0-2),al_loc(3),pream(4-5),loopbak(6-7)*/
+  unsigned char  priority;   /* lin_prio(0-2),exp_prio(4-6),bof_metd(7) */
+  unsigned char  ifs;        /* inter frame spacing */
+  unsigned char  time_low;   /* slot time low */
+  unsigned char  time_high;  /* slot time high(0-2) and max. retries(4-7) */
+  unsigned char  promisc;    /* promisc-mode(0) , et al (1-7) */
+  unsigned char  carr_coll;  /* carrier(0-3)/collision(4-7) stuff */
+  unsigned char  fram_len;   /* minimal frame len */
+  unsigned char  dummy;             /* dummy */
+};
+
+/*
+ * Multicast Setup command
+ */
+struct mcsetup_cmd_struct
+{
+  unsigned short cmd_status;
+  unsigned short cmd_cmd;
+  unsigned short cmd_link;
+  unsigned short mc_cnt;               /* number of bytes in the MC-List */
+  unsigned char  mc_list[0][6];        /* pointer to 6 bytes entries */
+};
+
+/*
+ * transmit command
+ */
+struct transmit_cmd_struct
+{
+  unsigned short cmd_status;
+  unsigned short cmd_cmd;
+  unsigned short cmd_link;
+  unsigned short tbd_offset;   /* pointeroffset to TBD */
+  unsigned char  dest[6];       /* destination address of the frame */
+  unsigned short length;       /* user defined: 802.3 length / Ether type */
+};
+
+#define TCMD_ERRMASK     0x0fa0
+#define TCMD_MAXCOLLMASK 0x000f
+#define TCMD_MAXCOLL     0x0020
+#define TCMD_HEARTBEAT   0x0040
+#define TCMD_DEFERRED    0x0080
+#define TCMD_UNDERRUN    0x0100
+#define TCMD_LOSTCTS     0x0200
+#define TCMD_NOCARRIER   0x0400
+#define TCMD_LATECOLL    0x0800
+
+struct tdr_cmd_struct
+{
+  unsigned short cmd_status;
+  unsigned short cmd_cmd;
+  unsigned short cmd_link;
+  unsigned short status;
+};
+
+#define TDR_LNK_OK     0x8000  /* No link problem identified */
+#define TDR_XCVR_PRB   0x4000  /* indicates a transceiver problem */
+#define TDR_ET_OPN     0x2000  /* open, no correct termination */
+#define TDR_ET_SRT     0x1000  /* TDR detected a short circuit */
+#define TDR_TIMEMASK   0x07ff  /* mask for the time field */
+
+/*
+ * Transmit Buffer Descriptor (TBD)
+ */
+struct tbd_struct
+{
+  unsigned short size;         /* size + EOF-Flag(15) */
+  unsigned short next;          /* pointeroffset to next TBD */
+  char          *buffer;        /* pointer to buffer */
+};
+
+#define TBD_LAST 0x8000         /* EOF-Flag, indicates last buffer in list */
+
+/*************************************************************************/
+/*
+Verbatim from the Crynwyr stuff:
+
+    The 3c523 responds with adapter code 0x6042 at slot
+registers xxx0 and xxx1.  The setup register is at xxx2 and
+contains the following bits:
+
+0: card enable
+2,1: csr address select
+    00 = 0300
+    01 = 1300
+    10 = 2300
+    11 = 3300
+4,3: shared memory address select
+    00 = 0c0000
+    01 = 0c8000
+    10 = 0d0000
+    11 = 0d8000
+5: set to disable on-board thinnet
+7,6: (read-only) shows selected irq
+    00 = 12
+    01 = 7
+    10 = 3
+    11 = 9
+
+The interrupt-select register is at xxx3 and uses one bit per irq.
+
+0: int 12
+1: int 7
+2: int 3
+3: int 9
+
+    Again, the documentation stresses that the setup register
+should never be written.  The interrupt-select register may be
+written with the value corresponding to bits 7.6 in
+the setup register to insure corret setup.
+*/
+
+/* Offsets from the base I/O address. */
+#define        ELMC_SA         0       /* first 6 bytes are IEEE network address */
+#define ELMC_CTRL      6       /* control & status register */
+#define ELMC_REVISION  7       /* revision register, first 4 bits only */
+#define ELMC_IO_EXTENT  8
+
+/* these are the bit selects for the port register 2 */
+#define ELMC_STATUS_ENABLED    0x01
+#define ELMC_STATUS_CSR_SELECT 0x06
+#define ELMC_STATUS_MEMORY_SELECT      0x18
+#define ELMC_STATUS_DISABLE_THIN       0x20
+#define ELMC_STATUS_IRQ_SELECT 0xc0
+
+/* this is the card id used in the detection code.  You might recognize
+it from @6042.adf */
+#define ELMC_MCA_ID 0x6042
+
+/*
+   The following define the bits for the control & status register
+
+   The bank select registers can be used if more than 16K of memory is
+   on the card.  For some stupid reason, bank 3 is the one for the
+   bottom 16K, and the card defaults to bank 0.  So we have to set the
+   bank to 3 before the card will even think of operating.  To get bank
+   3, set BS0 and BS1 to high (of course...)
+*/
+#define ELMC_CTRL_BS0  0x01    /* RW bank select */
+#define ELMC_CTRL_BS1  0x02    /* RW bank select */
+#define ELMC_CTRL_INTE 0x04    /* RW interrupt enable, assert high */
+#define ELMC_CTRL_INT  0x08    /* R interrupt active, assert high */
+/*#define ELMC_CTRL_*  0x10*/  /* reserved */
+#define ELMC_CTRL_LBK  0x20    /* RW loopback enable, assert high */
+#define ELMC_CTRL_CA   0x40    /* RW channel attention, assert high */
+#define ELMC_CTRL_RST  0x80    /* RW 82586 reset, assert low */
+
+/* some handy compound bits */
+
+/* normal operation should have bank 3 and RST high, ints enabled */
+#define ELMC_NORMAL (ELMC_CTRL_INTE|ELMC_CTRL_RST|0x3)
+
+#endif /* _3c523_INCLUDE_ */
diff --git a/drivers/net/ethernet/i825xx/3c527.c b/drivers/net/ethernet/i825xx/3c527.c
new file mode 100644 (file)
index 0000000..d9d056d
--- /dev/null
@@ -0,0 +1,1661 @@
+/* 3c527.c: 3Com Etherlink/MC32 driver for Linux 2.4 and 2.6.
+ *
+ *     (c) Copyright 1998 Red Hat Software Inc
+ *     Written by Alan Cox.
+ *     Further debugging by Carl Drougge.
+ *      Initial SMP support by Felipe W Damasio <felipewd@terra.com.br>
+ *      Heavily modified by Richard Procter <rnp@paradise.net.nz>
+ *
+ *     Based on skeleton.c written 1993-94 by Donald Becker and ne2.c
+ *     (for the MCA stuff) written by Wim Dumon.
+ *
+ *     Thanks to 3Com for making this possible by providing me with the
+ *     documentation.
+ *
+ *     This software may be used and distributed according to the terms
+ *     of the GNU General Public License, incorporated herein by reference.
+ *
+ */
+
+#define DRV_NAME               "3c527"
+#define DRV_VERSION            "0.7-SMP"
+#define DRV_RELDATE            "2003/09/21"
+
+static const char *version =
+DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " Richard Procter <rnp@paradise.net.nz>\n";
+
+/**
+ * DOC: Traps for the unwary
+ *
+ *     The diagram (Figure 1-1) and the POS summary disagree with the
+ *     "Interrupt Level" section in the manual.
+ *
+ *     The manual contradicts itself when describing the minimum number
+ *     buffers in the 'configure lists' command.
+ *     My card accepts a buffer config of 4/4.
+ *
+ *     Setting the SAV BP bit does not save bad packets, but
+ *     only enables RX on-card stats collection.
+ *
+ *     The documentation in places seems to miss things. In actual fact
+ *     I've always eventually found everything is documented, it just
+ *     requires careful study.
+ *
+ * DOC: Theory Of Operation
+ *
+ *     The 3com 3c527 is a 32bit MCA bus mastering adapter with a large
+ *     amount of on board intelligence that housekeeps a somewhat dumber
+ *     Intel NIC. For performance we want to keep the transmit queue deep
+ *     as the card can transmit packets while fetching others from main
+ *     memory by bus master DMA. Transmission and reception are driven by
+ *     circular buffer queues.
+ *
+ *     The mailboxes can be used for controlling how the card traverses
+ *     its buffer rings, but are used only for initial setup in this
+ *     implementation.  The exec mailbox allows a variety of commands to
+ *     be executed. Each command must complete before the next is
+ *     executed. Primarily we use the exec mailbox for controlling the
+ *     multicast lists.  We have to do a certain amount of interesting
+ *     hoop jumping as the multicast list changes can occur in interrupt
+ *     state when the card has an exec command pending. We defer such
+ *     events until the command completion interrupt.
+ *
+ *     A copy break scheme (taken from 3c59x.c) is employed whereby
+ *     received frames exceeding a configurable length are passed
+ *     directly to the higher networking layers without incuring a copy,
+ *     in what amounts to a time/space trade-off.
+ *
+ *     The card also keeps a large amount of statistical information
+ *     on-board. In a perfect world, these could be used safely at no
+ *     cost. However, lacking information to the contrary, processing
+ *     them without races would involve so much extra complexity as to
+ *     make it unworthwhile to do so. In the end, a hybrid SW/HW
+ *     implementation was made necessary --- see mc32_update_stats().
+ *
+ * DOC: Notes
+ *
+ *     It should be possible to use two or more cards, but at this stage
+ *     only by loading two copies of the same module.
+ *
+ *     The on-board 82586 NIC has trouble receiving multiple
+ *     back-to-back frames and so is likely to drop packets from fast
+ *     senders.
+**/
+
+#include <linux/module.h>
+
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/if_ether.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/mca-legacy.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/wait.h>
+#include <linux/ethtool.h>
+#include <linux/completion.h>
+#include <linux/bitops.h>
+#include <linux/semaphore.h>
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#include "3c527.h"
+
+MODULE_LICENSE("GPL");
+
+/*
+ * The name of the card. Is used for messages and in the requests for
+ * io regions, irqs and dma channels
+ */
+static const char* cardname = DRV_NAME;
+
+/* use 0 for production, 1 for verification, >2 for debug */
+#ifndef NET_DEBUG
+#define NET_DEBUG 2
+#endif
+
+static unsigned int mc32_debug = NET_DEBUG;
+
+/* The number of low I/O ports used by the ethercard. */
+#define MC32_IO_EXTENT 8
+
+/* As implemented, values must be a power-of-2 -- 4/8/16/32 */
+#define TX_RING_LEN     32       /* Typically the card supports 37  */
+#define RX_RING_LEN     8        /*     "       "        "          */
+
+/* Copy break point, see above for details.
+ * Setting to > 1512 effectively disables this feature.        */
+#define RX_COPYBREAK    200      /* Value from 3c59x.c */
+
+/* Issue the 82586 workaround command - this is for "busy lans", but
+ * basically means for all lans now days - has a performance (latency)
+ * cost, but best set. */
+static const int WORKAROUND_82586=1;
+
+/* Pointers to buffers and their on-card records */
+struct mc32_ring_desc
+{
+       volatile struct skb_header *p;
+       struct sk_buff *skb;
+};
+
+/* Information that needs to be kept for each board. */
+struct mc32_local
+{
+       int slot;
+
+       u32 base;
+       volatile struct mc32_mailbox *rx_box;
+       volatile struct mc32_mailbox *tx_box;
+       volatile struct mc32_mailbox *exec_box;
+        volatile struct mc32_stats *stats;    /* Start of on-card statistics */
+        u16 tx_chain;           /* Transmit list start offset */
+       u16 rx_chain;           /* Receive list start offset */
+        u16 tx_len;             /* Transmit list count */
+        u16 rx_len;             /* Receive list count */
+
+       u16 xceiver_desired_state; /* HALTED or RUNNING */
+       u16 cmd_nonblocking;    /* Thread is uninterested in command result */
+       u16 mc_reload_wait;     /* A multicast load request is pending */
+       u32 mc_list_valid;      /* True when the mclist is set */
+
+       struct mc32_ring_desc tx_ring[TX_RING_LEN];     /* Host Transmit ring */
+       struct mc32_ring_desc rx_ring[RX_RING_LEN];     /* Host Receive ring */
+
+       atomic_t tx_count;      /* buffers left */
+       atomic_t tx_ring_head;  /* index to tx en-queue end */
+       u16 tx_ring_tail;       /* index to tx de-queue end */
+
+       u16 rx_ring_tail;       /* index to rx de-queue end */
+
+       struct semaphore cmd_mutex;    /* Serialises issuing of execute commands */
+        struct completion execution_cmd; /* Card has completed an execute command */
+       struct completion xceiver_cmd;   /* Card has completed a tx or rx command */
+};
+
+/* The station (ethernet) address prefix, used for a sanity check. */
+#define SA_ADDR0 0x02
+#define SA_ADDR1 0x60
+#define SA_ADDR2 0xAC
+
+struct mca_adapters_t {
+       unsigned int    id;
+       char            *name;
+};
+
+static const struct mca_adapters_t mc32_adapters[] = {
+       { 0x0041, "3COM EtherLink MC/32" },
+       { 0x8EF5, "IBM High Performance Lan Adapter" },
+       { 0x0000, NULL }
+};
+
+
+/* Macros for ring index manipulations */
+static inline u16 next_rx(u16 rx) { return (rx+1)&(RX_RING_LEN-1); };
+static inline u16 prev_rx(u16 rx) { return (rx-1)&(RX_RING_LEN-1); };
+
+static inline u16 next_tx(u16 tx) { return (tx+1)&(TX_RING_LEN-1); };
+
+
+/* Index to functions, as function prototypes. */
+static int     mc32_probe1(struct net_device *dev, int ioaddr);
+static int      mc32_command(struct net_device *dev, u16 cmd, void *data, int len);
+static int     mc32_open(struct net_device *dev);
+static void    mc32_timeout(struct net_device *dev);
+static netdev_tx_t mc32_send_packet(struct sk_buff *skb,
+                                   struct net_device *dev);
+static irqreturn_t mc32_interrupt(int irq, void *dev_id);
+static int     mc32_close(struct net_device *dev);
+static struct  net_device_stats *mc32_get_stats(struct net_device *dev);
+static void    mc32_set_multicast_list(struct net_device *dev);
+static void    mc32_reset_multicast_list(struct net_device *dev);
+static const struct ethtool_ops netdev_ethtool_ops;
+
+static void cleanup_card(struct net_device *dev)
+{
+       struct mc32_local *lp = netdev_priv(dev);
+       unsigned slot = lp->slot;
+       mca_mark_as_unused(slot);
+       mca_set_adapter_name(slot, NULL);
+       free_irq(dev->irq, dev);
+       release_region(dev->base_addr, MC32_IO_EXTENT);
+}
+
+/**
+ * mc32_probe  -       Search for supported boards
+ * @unit: interface number to use
+ *
+ * Because MCA bus is a real bus and we can scan for cards we could do a
+ * single scan for all boards here. Right now we use the passed in device
+ * structure and scan for only one board. This needs fixing for modules
+ * in particular.
+ */
+
+struct net_device *__init mc32_probe(int unit)
+{
+       struct net_device *dev = alloc_etherdev(sizeof(struct mc32_local));
+       static int current_mca_slot = -1;
+       int i;
+       int err;
+
+       if (!dev)
+               return ERR_PTR(-ENOMEM);
+
+       if (unit >= 0)
+               sprintf(dev->name, "eth%d", unit);
+
+       /* Do not check any supplied i/o locations.
+          POS registers usually don't fail :) */
+
+       /* MCA cards have POS registers.
+          Autodetecting MCA cards is extremely simple.
+          Just search for the card. */
+
+       for(i = 0; (mc32_adapters[i].name != NULL); i++) {
+               current_mca_slot =
+                       mca_find_unused_adapter(mc32_adapters[i].id, 0);
+
+               if(current_mca_slot != MCA_NOTFOUND) {
+                       if(!mc32_probe1(dev, current_mca_slot))
+                       {
+                               mca_set_adapter_name(current_mca_slot,
+                                               mc32_adapters[i].name);
+                               mca_mark_as_used(current_mca_slot);
+                               err = register_netdev(dev);
+                               if (err) {
+                                       cleanup_card(dev);
+                                       free_netdev(dev);
+                                       dev = ERR_PTR(err);
+                               }
+                               return dev;
+                       }
+
+               }
+       }
+       free_netdev(dev);
+       return ERR_PTR(-ENODEV);
+}
+
+static const struct net_device_ops netdev_ops = {
+       .ndo_open               = mc32_open,
+       .ndo_stop               = mc32_close,
+       .ndo_start_xmit         = mc32_send_packet,
+       .ndo_get_stats          = mc32_get_stats,
+       .ndo_set_multicast_list = mc32_set_multicast_list,
+       .ndo_tx_timeout         = mc32_timeout,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
+/**
+ * mc32_probe1 -       Check a given slot for a board and test the card
+ * @dev:  Device structure to fill in
+ * @slot: The MCA bus slot being used by this card
+ *
+ * Decode the slot data and configure the card structures. Having done this we
+ * can reset the card and configure it. The card does a full self test cycle
+ * in firmware so we have to wait for it to return and post us either a
+ * failure case or some addresses we use to find the board internals.
+ */
+
+static int __init mc32_probe1(struct net_device *dev, int slot)
+{
+       static unsigned version_printed;
+       int i, err;
+       u8 POS;
+       u32 base;
+       struct mc32_local *lp = netdev_priv(dev);
+       static const u16 mca_io_bases[] = {
+               0x7280,0x7290,
+               0x7680,0x7690,
+               0x7A80,0x7A90,
+               0x7E80,0x7E90
+       };
+       static const u32 mca_mem_bases[] = {
+               0x00C0000,
+               0x00C4000,
+               0x00C8000,
+               0x00CC000,
+               0x00D0000,
+               0x00D4000,
+               0x00D8000,
+               0x00DC000
+       };
+       static const char * const failures[] = {
+               "Processor instruction",
+               "Processor data bus",
+               "Processor data bus",
+               "Processor data bus",
+               "Adapter bus",
+               "ROM checksum",
+               "Base RAM",
+               "Extended RAM",
+               "82586 internal loopback",
+               "82586 initialisation failure",
+               "Adapter list configuration error"
+       };
+
+       /* Time to play MCA games */
+
+       if (mc32_debug  &&  version_printed++ == 0)
+               pr_debug("%s", version);
+
+       pr_info("%s: %s found in slot %d: ", dev->name, cardname, slot);
+
+       POS = mca_read_stored_pos(slot, 2);
+
+       if(!(POS&1))
+       {
+               pr_cont("disabled.\n");
+               return -ENODEV;
+       }
+
+       /* Fill in the 'dev' fields. */
+       dev->base_addr = mca_io_bases[(POS>>1)&7];
+       dev->mem_start = mca_mem_bases[(POS>>4)&7];
+
+       POS = mca_read_stored_pos(slot, 4);
+       if(!(POS&1))
+       {
+               pr_cont("memory window disabled.\n");
+               return -ENODEV;
+       }
+
+       POS = mca_read_stored_pos(slot, 5);
+
+       i=(POS>>4)&3;
+       if(i==3)
+       {
+               pr_cont("invalid memory window.\n");
+               return -ENODEV;
+       }
+
+       i*=16384;
+       i+=16384;
+
+       dev->mem_end=dev->mem_start + i;
+
+       dev->irq = ((POS>>2)&3)+9;
+
+       if(!request_region(dev->base_addr, MC32_IO_EXTENT, cardname))
+       {
+               pr_cont("io 0x%3lX, which is busy.\n", dev->base_addr);
+               return -EBUSY;
+       }
+
+       pr_cont("io 0x%3lX irq %d mem 0x%lX (%dK)\n",
+               dev->base_addr, dev->irq, dev->mem_start, i/1024);
+
+
+       /* We ought to set the cache line size here.. */
+
+
+       /*
+        *      Go PROM browsing
+        */
+
+       /* Retrieve and print the ethernet address. */
+       for (i = 0; i < 6; i++)
+       {
+               mca_write_pos(slot, 6, i+12);
+               mca_write_pos(slot, 7, 0);
+
+               dev->dev_addr[i] = mca_read_pos(slot,3);
+       }
+
+       pr_info("%s: Address %pM ", dev->name, dev->dev_addr);
+
+       mca_write_pos(slot, 6, 0);
+       mca_write_pos(slot, 7, 0);
+
+       POS = mca_read_stored_pos(slot, 4);
+
+       if(POS&2)
+               pr_cont(": BNC port selected.\n");
+       else
+               pr_cont(": AUI port selected.\n");
+
+       POS=inb(dev->base_addr+HOST_CTRL);
+       POS|=HOST_CTRL_ATTN|HOST_CTRL_RESET;
+       POS&=~HOST_CTRL_INTE;
+       outb(POS, dev->base_addr+HOST_CTRL);
+       /* Reset adapter */
+       udelay(100);
+       /* Reset off */
+       POS&=~(HOST_CTRL_ATTN|HOST_CTRL_RESET);
+       outb(POS, dev->base_addr+HOST_CTRL);
+
+       udelay(300);
+
+       /*
+        *      Grab the IRQ
+        */
+
+       err = request_irq(dev->irq, mc32_interrupt, IRQF_SHARED, DRV_NAME, dev);
+       if (err) {
+               release_region(dev->base_addr, MC32_IO_EXTENT);
+               pr_err("%s: unable to get IRQ %d.\n", DRV_NAME, dev->irq);
+               goto err_exit_ports;
+       }
+
+       memset(lp, 0, sizeof(struct mc32_local));
+       lp->slot = slot;
+
+       i=0;
+
+       base = inb(dev->base_addr);
+
+       while(base == 0xFF)
+       {
+               i++;
+               if(i == 1000)
+               {
+                       pr_err("%s: failed to boot adapter.\n", dev->name);
+                       err = -ENODEV;
+                       goto err_exit_irq;
+               }
+               udelay(1000);
+               if(inb(dev->base_addr+2)&(1<<5))
+                       base = inb(dev->base_addr);
+       }
+
+       if(base>0)
+       {
+               if(base < 0x0C)
+                       pr_err("%s: %s%s.\n", dev->name, failures[base-1],
+                               base<0x0A?" test failure":"");
+               else
+                       pr_err("%s: unknown failure %d.\n", dev->name, base);
+               err = -ENODEV;
+               goto err_exit_irq;
+       }
+
+       base=0;
+       for(i=0;i<4;i++)
+       {
+               int n=0;
+
+               while(!(inb(dev->base_addr+2)&(1<<5)))
+               {
+                       n++;
+                       udelay(50);
+                       if(n>100)
+                       {
+                               pr_err("%s: mailbox read fail (%d).\n", dev->name, i);
+                               err = -ENODEV;
+                               goto err_exit_irq;
+                       }
+               }
+
+               base|=(inb(dev->base_addr)<<(8*i));
+       }
+
+       lp->exec_box=isa_bus_to_virt(dev->mem_start+base);
+
+       base=lp->exec_box->data[1]<<16|lp->exec_box->data[0];
+
+       lp->base = dev->mem_start+base;
+
+       lp->rx_box=isa_bus_to_virt(lp->base + lp->exec_box->data[2]);
+       lp->tx_box=isa_bus_to_virt(lp->base + lp->exec_box->data[3]);
+
+       lp->stats = isa_bus_to_virt(lp->base + lp->exec_box->data[5]);
+
+       /*
+        *      Descriptor chains (card relative)
+        */
+
+       lp->tx_chain            = lp->exec_box->data[8];   /* Transmit list start offset */
+       lp->rx_chain            = lp->exec_box->data[10];  /* Receive list start offset */
+       lp->tx_len              = lp->exec_box->data[9];   /* Transmit list count */
+       lp->rx_len              = lp->exec_box->data[11];  /* Receive list count */
+
+       sema_init(&lp->cmd_mutex, 0);
+       init_completion(&lp->execution_cmd);
+       init_completion(&lp->xceiver_cmd);
+
+       pr_info("%s: Firmware Rev %d. %d RX buffers, %d TX buffers. Base of 0x%08X.\n",
+               dev->name, lp->exec_box->data[12], lp->rx_len, lp->tx_len, lp->base);
+
+       dev->netdev_ops         = &netdev_ops;
+       dev->watchdog_timeo     = HZ*5; /* Board does all the work */
+       dev->ethtool_ops        = &netdev_ethtool_ops;
+
+       return 0;
+
+err_exit_irq:
+       free_irq(dev->irq, dev);
+err_exit_ports:
+       release_region(dev->base_addr, MC32_IO_EXTENT);
+       return err;
+}
+
+
+/**
+ *     mc32_ready_poll         -       wait until we can feed it a command
+ *     @dev:   The device to wait for
+ *
+ *     Wait until the card becomes ready to accept a command via the
+ *     command register. This tells us nothing about the completion
+ *     status of any pending commands and takes very little time at all.
+ */
+
+static inline void mc32_ready_poll(struct net_device *dev)
+{
+       int ioaddr = dev->base_addr;
+       while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));
+}
+
+
+/**
+ *     mc32_command_nowait     -       send a command non blocking
+ *     @dev: The 3c527 to issue the command to
+ *     @cmd: The command word to write to the mailbox
+ *     @data: A data block if the command expects one
+ *     @len: Length of the data block
+ *
+ *     Send a command from interrupt state. If there is a command
+ *     currently being executed then we return an error of -1. It
+ *     simply isn't viable to wait around as commands may be
+ *     slow. This can theoretically be starved on SMP, but it's hard
+ *     to see a realistic situation.  We do not wait for the command
+ *     to complete --- we rely on the interrupt handler to tidy up
+ *     after us.
+ */
+
+static int mc32_command_nowait(struct net_device *dev, u16 cmd, void *data, int len)
+{
+       struct mc32_local *lp = netdev_priv(dev);
+       int ioaddr = dev->base_addr;
+       int ret = -1;
+
+       if (down_trylock(&lp->cmd_mutex) == 0)
+       {
+               lp->cmd_nonblocking=1;
+               lp->exec_box->mbox=0;
+               lp->exec_box->mbox=cmd;
+               memcpy((void *)lp->exec_box->data, data, len);
+               barrier();      /* the memcpy forgot the volatile so be sure */
+
+               /* Send the command */
+               mc32_ready_poll(dev);
+               outb(1<<6, ioaddr+HOST_CMD);
+
+               ret = 0;
+
+               /* Interrupt handler will signal mutex on completion */
+       }
+
+       return ret;
+}
+
+
+/**
+ *     mc32_command    -       send a command and sleep until completion
+ *     @dev: The 3c527 card to issue the command to
+ *     @cmd: The command word to write to the mailbox
+ *     @data: A data block if the command expects one
+ *     @len: Length of the data block
+ *
+ *     Sends exec commands in a user context. This permits us to wait around
+ *     for the replies and also to wait for the command buffer to complete
+ *     from a previous command before we execute our command. After our
+ *     command completes we will attempt any pending multicast reload
+ *     we blocked off by hogging the exec buffer.
+ *
+ *     You feed the card a command, you wait, it interrupts you get a
+ *     reply. All well and good. The complication arises because you use
+ *     commands for filter list changes which come in at bh level from things
+ *     like IPV6 group stuff.
+ */
+
+static int mc32_command(struct net_device *dev, u16 cmd, void *data, int len)
+{
+       struct mc32_local *lp = netdev_priv(dev);
+       int ioaddr = dev->base_addr;
+       int ret = 0;
+
+       down(&lp->cmd_mutex);
+
+       /*
+        *     My Turn
+        */
+
+       lp->cmd_nonblocking=0;
+       lp->exec_box->mbox=0;
+       lp->exec_box->mbox=cmd;
+       memcpy((void *)lp->exec_box->data, data, len);
+       barrier();      /* the memcpy forgot the volatile so be sure */
+
+       mc32_ready_poll(dev);
+       outb(1<<6, ioaddr+HOST_CMD);
+
+       wait_for_completion(&lp->execution_cmd);
+
+       if(lp->exec_box->mbox&(1<<13))
+               ret = -1;
+
+       up(&lp->cmd_mutex);
+
+       /*
+        *      A multicast set got blocked - try it now
+         */
+
+       if(lp->mc_reload_wait)
+       {
+               mc32_reset_multicast_list(dev);
+       }
+
+       return ret;
+}
+
+
+/**
+ *     mc32_start_transceiver  -       tell board to restart tx/rx
+ *     @dev: The 3c527 card to issue the command to
+ *
+ *     This may be called from the interrupt state, where it is used
+ *     to restart the rx ring if the card runs out of rx buffers.
+ *
+ *     We must first check if it's ok to (re)start the transceiver. See
+ *      mc32_close for details.
+ */
+
+static void mc32_start_transceiver(struct net_device *dev) {
+
+       struct mc32_local *lp = netdev_priv(dev);
+       int ioaddr = dev->base_addr;
+
+       /* Ignore RX overflow on device closure */
+       if (lp->xceiver_desired_state==HALTED)
+               return;
+
+       /* Give the card the offset to the post-EOL-bit RX descriptor */
+       mc32_ready_poll(dev);
+       lp->rx_box->mbox=0;
+       lp->rx_box->data[0]=lp->rx_ring[prev_rx(lp->rx_ring_tail)].p->next;
+       outb(HOST_CMD_START_RX, ioaddr+HOST_CMD);
+
+       mc32_ready_poll(dev);
+       lp->tx_box->mbox=0;
+       outb(HOST_CMD_RESTRT_TX, ioaddr+HOST_CMD);   /* card ignores this on RX restart */
+
+       /* We are not interrupted on start completion */
+}
+
+
+/**
+ *     mc32_halt_transceiver   -       tell board to stop tx/rx
+ *     @dev: The 3c527 card to issue the command to
+ *
+ *     We issue the commands to halt the card's transceiver. In fact,
+ *     after some experimenting we now simply tell the card to
+ *     suspend. When issuing aborts occasionally odd things happened.
+ *
+ *     We then sleep until the card has notified us that both rx and
+ *     tx have been suspended.
+ */
+
+static void mc32_halt_transceiver(struct net_device *dev)
+{
+       struct mc32_local *lp = netdev_priv(dev);
+       int ioaddr = dev->base_addr;
+
+       mc32_ready_poll(dev);
+       lp->rx_box->mbox=0;
+       outb(HOST_CMD_SUSPND_RX, ioaddr+HOST_CMD);
+       wait_for_completion(&lp->xceiver_cmd);
+
+       mc32_ready_poll(dev);
+       lp->tx_box->mbox=0;
+       outb(HOST_CMD_SUSPND_TX, ioaddr+HOST_CMD);
+       wait_for_completion(&lp->xceiver_cmd);
+}
+
+
+/**
+ *     mc32_load_rx_ring       -       load the ring of receive buffers
+ *     @dev: 3c527 to build the ring for
+ *
+ *     This initialises the on-card and driver datastructures to
+ *     the point where mc32_start_transceiver() can be called.
+ *
+ *     The card sets up the receive ring for us. We are required to use the
+ *     ring it provides, although the size of the ring is configurable.
+ *
+ *     We allocate an sk_buff for each ring entry in turn and
+ *     initialise its house-keeping info. At the same time, we read
+ *     each 'next' pointer in our rx_ring array. This reduces slow
+ *     shared-memory reads and makes it easy to access predecessor
+ *     descriptors.
+ *
+ *     We then set the end-of-list bit for the last entry so that the
+ *     card will know when it has run out of buffers.
+ */
+
+static int mc32_load_rx_ring(struct net_device *dev)
+{
+       struct mc32_local *lp = netdev_priv(dev);
+       int i;
+       u16 rx_base;
+       volatile struct skb_header *p;
+
+       rx_base=lp->rx_chain;
+
+       for(i=0; i<RX_RING_LEN; i++) {
+               lp->rx_ring[i].skb=alloc_skb(1532, GFP_KERNEL);
+               if (lp->rx_ring[i].skb==NULL) {
+                       for (;i>=0;i--)
+                               kfree_skb(lp->rx_ring[i].skb);
+                       return -ENOBUFS;
+               }
+               skb_reserve(lp->rx_ring[i].skb, 18);
+
+               p=isa_bus_to_virt(lp->base+rx_base);
+
+               p->control=0;
+               p->data=isa_virt_to_bus(lp->rx_ring[i].skb->data);
+               p->status=0;
+               p->length=1532;
+
+               lp->rx_ring[i].p=p;
+               rx_base=p->next;
+       }
+
+       lp->rx_ring[i-1].p->control |= CONTROL_EOL;
+
+       lp->rx_ring_tail=0;
+
+       return 0;
+}
+
+
+/**
+ *     mc32_flush_rx_ring      -       free the ring of receive buffers
+ *     @lp: Local data of 3c527 to flush the rx ring of
+ *
+ *     Free the buffer for each ring slot. This may be called
+ *      before mc32_load_rx_ring(), eg. on error in mc32_open().
+ *      Requires rx skb pointers to point to a valid skb, or NULL.
+ */
+
+static void mc32_flush_rx_ring(struct net_device *dev)
+{
+       struct mc32_local *lp = netdev_priv(dev);
+       int i;
+
+       for(i=0; i < RX_RING_LEN; i++)
+       {
+               if (lp->rx_ring[i].skb) {
+                       dev_kfree_skb(lp->rx_ring[i].skb);
+                       lp->rx_ring[i].skb = NULL;
+               }
+               lp->rx_ring[i].p=NULL;
+       }
+}
+
+
+/**
+ *     mc32_load_tx_ring       -       load transmit ring
+ *     @dev: The 3c527 card to issue the command to
+ *
+ *     This sets up the host transmit data-structures.
+ *
+ *     First, we obtain from the card it's current position in the tx
+ *     ring, so that we will know where to begin transmitting
+ *     packets.
+ *
+ *     Then, we read the 'next' pointers from the on-card tx ring into
+ *     our tx_ring array to reduce slow shared-mem reads. Finally, we
+ *     intitalise the tx house keeping variables.
+ *
+ */
+
+static void mc32_load_tx_ring(struct net_device *dev)
+{
+       struct mc32_local *lp = netdev_priv(dev);
+       volatile struct skb_header *p;
+       int i;
+       u16 tx_base;
+
+       tx_base=lp->tx_box->data[0];
+
+       for(i=0 ; i<TX_RING_LEN ; i++)
+       {
+               p=isa_bus_to_virt(lp->base+tx_base);
+               lp->tx_ring[i].p=p;
+               lp->tx_ring[i].skb=NULL;
+
+               tx_base=p->next;
+       }
+
+       /* -1 so that tx_ring_head cannot "lap" tx_ring_tail */
+       /* see mc32_tx_ring */
+
+       atomic_set(&lp->tx_count, TX_RING_LEN-1);
+       atomic_set(&lp->tx_ring_head, 0);
+       lp->tx_ring_tail=0;
+}
+
+
+/**
+ *     mc32_flush_tx_ring      -       free transmit ring
+ *     @lp: Local data of 3c527 to flush the tx ring of
+ *
+ *      If the ring is non-empty, zip over the it, freeing any
+ *      allocated skb_buffs.  The tx ring house-keeping variables are
+ *      then reset. Requires rx skb pointers to point to a valid skb,
+ *      or NULL.
+ */
+
+static void mc32_flush_tx_ring(struct net_device *dev)
+{
+       struct mc32_local *lp = netdev_priv(dev);
+       int i;
+
+       for (i=0; i < TX_RING_LEN; i++)
+       {
+               if (lp->tx_ring[i].skb)
+               {
+                       dev_kfree_skb(lp->tx_ring[i].skb);
+                       lp->tx_ring[i].skb = NULL;
+               }
+       }
+
+       atomic_set(&lp->tx_count, 0);
+       atomic_set(&lp->tx_ring_head, 0);
+       lp->tx_ring_tail=0;
+}
+
+
+/**
+ *     mc32_open       -       handle 'up' of card
+ *     @dev: device to open
+ *
+ *     The user is trying to bring the card into ready state. This requires
+ *     a brief dialogue with the card. Firstly we enable interrupts and then
+ *     'indications'. Without these enabled the card doesn't bother telling
+ *     us what it has done. This had me puzzled for a week.
+ *
+ *     We configure the number of card descriptors, then load the network
+ *     address and multicast filters. Turn on the workaround mode. This
+ *     works around a bug in the 82586 - it asks the firmware to do
+ *     so. It has a performance (latency) hit but is needed on busy
+ *     [read most] lans. We load the ring with buffers then we kick it
+ *     all off.
+ */
+
+static int mc32_open(struct net_device *dev)
+{
+       int ioaddr = dev->base_addr;
+       struct mc32_local *lp = netdev_priv(dev);
+       u8 one=1;
+       u8 regs;
+       u16 descnumbuffs[2] = {TX_RING_LEN, RX_RING_LEN};
+
+       /*
+        *      Interrupts enabled
+        */
+
+       regs=inb(ioaddr+HOST_CTRL);
+       regs|=HOST_CTRL_INTE;
+       outb(regs, ioaddr+HOST_CTRL);
+
+       /*
+        *      Allow ourselves to issue commands
+        */
+
+       up(&lp->cmd_mutex);
+
+
+       /*
+        *      Send the indications on command
+        */
+
+       mc32_command(dev, 4, &one, 2);
+
+       /*
+        *      Poke it to make sure it's really dead.
+        */
+
+       mc32_halt_transceiver(dev);
+       mc32_flush_tx_ring(dev);
+
+       /*
+        *      Ask card to set up on-card descriptors to our spec
+        */
+
+       if(mc32_command(dev, 8, descnumbuffs, 4)) {
+               pr_info("%s: %s rejected our buffer configuration!\n",
+                      dev->name, cardname);
+               mc32_close(dev);
+               return -ENOBUFS;
+       }
+
+       /* Report new configuration */
+       mc32_command(dev, 6, NULL, 0);
+
+       lp->tx_chain            = lp->exec_box->data[8];   /* Transmit list start offset */
+       lp->rx_chain            = lp->exec_box->data[10];  /* Receive list start offset */
+       lp->tx_len              = lp->exec_box->data[9];   /* Transmit list count */
+       lp->rx_len              = lp->exec_box->data[11];  /* Receive list count */
+
+       /* Set Network Address */
+       mc32_command(dev, 1, dev->dev_addr, 6);
+
+       /* Set the filters */
+       mc32_set_multicast_list(dev);
+
+       if (WORKAROUND_82586) {
+               u16 zero_word=0;
+               mc32_command(dev, 0x0D, &zero_word, 2);   /* 82586 bug workaround on  */
+       }
+
+       mc32_load_tx_ring(dev);
+
+       if(mc32_load_rx_ring(dev))
+       {
+               mc32_close(dev);
+               return -ENOBUFS;
+       }
+
+       lp->xceiver_desired_state = RUNNING;
+
+       /* And finally, set the ball rolling... */
+       mc32_start_transceiver(dev);
+
+       netif_start_queue(dev);
+
+       return 0;
+}
+
+
+/**
+ *     mc32_timeout    -       handle a timeout from the network layer
+ *     @dev: 3c527 that timed out
+ *
+ *     Handle a timeout on transmit from the 3c527. This normally means
+ *     bad things as the hardware handles cable timeouts and mess for
+ *     us.
+ *
+ */
+
+static void mc32_timeout(struct net_device *dev)
+{
+       pr_warning("%s: transmit timed out?\n", dev->name);
+       /* Try to restart the adaptor. */
+       netif_wake_queue(dev);
+}
+
+
+/**
+ *     mc32_send_packet        -       queue a frame for transmit
+ *     @skb: buffer to transmit
+ *     @dev: 3c527 to send it out of
+ *
+ *     Transmit a buffer. This normally means throwing the buffer onto
+ *     the transmit queue as the queue is quite large. If the queue is
+ *     full then we set tx_busy and return. Once the interrupt handler
+ *     gets messages telling it to reclaim transmit queue entries, we will
+ *     clear tx_busy and the kernel will start calling this again.
+ *
+ *      We do not disable interrupts or acquire any locks; this can
+ *      run concurrently with mc32_tx_ring(), and the function itself
+ *      is serialised at a higher layer. However, similarly for the
+ *      card itself, we must ensure that we update tx_ring_head only
+ *      after we've established a valid packet on the tx ring (and
+ *      before we let the card "see" it, to prevent it racing with the
+ *      irq handler).
+ *
+ */
+
+static netdev_tx_t mc32_send_packet(struct sk_buff *skb,
+                                   struct net_device *dev)
+{
+       struct mc32_local *lp = netdev_priv(dev);
+       u32 head = atomic_read(&lp->tx_ring_head);
+
+       volatile struct skb_header *p, *np;
+
+       netif_stop_queue(dev);
+
+       if(atomic_read(&lp->tx_count)==0) {
+               return NETDEV_TX_BUSY;
+       }
+
+       if (skb_padto(skb, ETH_ZLEN)) {
+               netif_wake_queue(dev);
+               return NETDEV_TX_OK;
+       }
+
+       atomic_dec(&lp->tx_count);
+
+       /* P is the last sending/sent buffer as a pointer */
+       p=lp->tx_ring[head].p;
+
+       head = next_tx(head);
+
+       /* NP is the buffer we will be loading */
+       np=lp->tx_ring[head].p;
+
+       /* We will need this to flush the buffer out */
+       lp->tx_ring[head].skb=skb;
+
+       np->length      = unlikely(skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len;
+       np->data        = isa_virt_to_bus(skb->data);
+       np->status      = 0;
+       np->control     = CONTROL_EOP | CONTROL_EOL;
+       wmb();
+
+       /*
+        * The new frame has been setup; we can now
+        * let the interrupt handler and card "see" it
+        */
+
+       atomic_set(&lp->tx_ring_head, head);
+       p->control     &= ~CONTROL_EOL;
+
+       netif_wake_queue(dev);
+       return NETDEV_TX_OK;
+}
+
+
+/**
+ *     mc32_update_stats       -       pull off the on board statistics
+ *     @dev: 3c527 to service
+ *
+ *
+ *     Query and reset the on-card stats. There's the small possibility
+ *     of a race here, which would result in an underestimation of
+ *     actual errors. As such, we'd prefer to keep all our stats
+ *     collection in software. As a rule, we do. However it can't be
+ *     used for rx errors and collisions as, by default, the card discards
+ *     bad rx packets.
+ *
+ *     Setting the SAV BP in the rx filter command supposedly
+ *     stops this behaviour. However, testing shows that it only seems to
+ *     enable the collation of on-card rx statistics --- the driver
+ *     never sees an RX descriptor with an error status set.
+ *
+ */
+
+static void mc32_update_stats(struct net_device *dev)
+{
+       struct mc32_local *lp = netdev_priv(dev);
+       volatile struct mc32_stats *st = lp->stats;
+
+       u32 rx_errors=0;
+
+       rx_errors+=dev->stats.rx_crc_errors   +=st->rx_crc_errors;
+                                                  st->rx_crc_errors=0;
+       rx_errors+=dev->stats.rx_fifo_errors  +=st->rx_overrun_errors;
+                                                  st->rx_overrun_errors=0;
+       rx_errors+=dev->stats.rx_frame_errors +=st->rx_alignment_errors;
+                                                  st->rx_alignment_errors=0;
+       rx_errors+=dev->stats.rx_length_errors+=st->rx_tooshort_errors;
+                                                  st->rx_tooshort_errors=0;
+       rx_errors+=dev->stats.rx_missed_errors+=st->rx_outofresource_errors;
+                                                  st->rx_outofresource_errors=0;
+        dev->stats.rx_errors=rx_errors;
+
+       /* Number of packets which saw one collision */
+       dev->stats.collisions+=st->dataC[10];
+       st->dataC[10]=0;
+
+       /* Number of packets which saw 2--15 collisions */
+       dev->stats.collisions+=st->dataC[11];
+       st->dataC[11]=0;
+}
+
+
+/**
+ *     mc32_rx_ring    -       process the receive ring
+ *     @dev: 3c527 that needs its receive ring processing
+ *
+ *
+ *     We have received one or more indications from the card that a
+ *     receive has completed. The buffer ring thus contains dirty
+ *     entries. We walk the ring by iterating over the circular rx_ring
+ *     array, starting at the next dirty buffer (which happens to be the
+ *     one we finished up at last time around).
+ *
+ *     For each completed packet, we will either copy it and pass it up
+ *     the stack or, if the packet is near MTU sized, we allocate
+ *     another buffer and flip the old one up the stack.
+ *
+ *     We must succeed in keeping a buffer on the ring. If necessary we
+ *     will toss a received packet rather than lose a ring entry. Once
+ *     the first uncompleted descriptor is found, we move the
+ *     End-Of-List bit to include the buffers just processed.
+ *
+ */
+
+static void mc32_rx_ring(struct net_device *dev)
+{
+       struct mc32_local *lp = netdev_priv(dev);
+       volatile struct skb_header *p;
+       u16 rx_ring_tail;
+       u16 rx_old_tail;
+       int x=0;
+
+       rx_old_tail = rx_ring_tail = lp->rx_ring_tail;
+
+       do
+       {
+               p=lp->rx_ring[rx_ring_tail].p;
+
+               if(!(p->status & (1<<7))) { /* Not COMPLETED */
+                       break;
+               }
+               if(p->status & (1<<6)) /* COMPLETED_OK */
+               {
+
+                       u16 length=p->length;
+                       struct sk_buff *skb;
+                       struct sk_buff *newskb;
+
+                       /* Try to save time by avoiding a copy on big frames */
+
+                       if ((length > RX_COPYBREAK) &&
+                           ((newskb=dev_alloc_skb(1532)) != NULL))
+                       {
+                               skb=lp->rx_ring[rx_ring_tail].skb;
+                               skb_put(skb, length);
+
+                               skb_reserve(newskb,18);
+                               lp->rx_ring[rx_ring_tail].skb=newskb;
+                               p->data=isa_virt_to_bus(newskb->data);
+                       }
+                       else
+                       {
+                               skb=dev_alloc_skb(length+2);
+
+                               if(skb==NULL) {
+                                       dev->stats.rx_dropped++;
+                                       goto dropped;
+                               }
+
+                               skb_reserve(skb,2);
+                               memcpy(skb_put(skb, length),
+                                      lp->rx_ring[rx_ring_tail].skb->data, length);
+                       }
+
+                       skb->protocol=eth_type_trans(skb,dev);
+                       dev->stats.rx_packets++;
+                       dev->stats.rx_bytes += length;
+                       netif_rx(skb);
+               }
+
+       dropped:
+               p->length = 1532;
+               p->status = 0;
+
+               rx_ring_tail=next_rx(rx_ring_tail);
+       }
+        while(x++<48);
+
+       /* If there was actually a frame to be processed, place the EOL bit */
+       /* at the descriptor prior to the one to be filled next */
+
+       if (rx_ring_tail != rx_old_tail)
+       {
+               lp->rx_ring[prev_rx(rx_ring_tail)].p->control |=  CONTROL_EOL;
+               lp->rx_ring[prev_rx(rx_old_tail)].p->control  &= ~CONTROL_EOL;
+
+               lp->rx_ring_tail=rx_ring_tail;
+       }
+}
+
+
+/**
+ *     mc32_tx_ring    -       process completed transmits
+ *     @dev: 3c527 that needs its transmit ring processing
+ *
+ *
+ *     This operates in a similar fashion to mc32_rx_ring. We iterate
+ *     over the transmit ring. For each descriptor which has been
+ *     processed by the card, we free its associated buffer and note
+ *     any errors. This continues until the transmit ring is emptied
+ *     or we reach a descriptor that hasn't yet been processed by the
+ *     card.
+ *
+ */
+
+static void mc32_tx_ring(struct net_device *dev)
+{
+       struct mc32_local *lp = netdev_priv(dev);
+       volatile struct skb_header *np;
+
+       /*
+        * We rely on head==tail to mean 'queue empty'.
+        * This is why lp->tx_count=TX_RING_LEN-1: in order to prevent
+        * tx_ring_head wrapping to tail and confusing a 'queue empty'
+        * condition with 'queue full'
+        */
+
+       while (lp->tx_ring_tail != atomic_read(&lp->tx_ring_head))
+       {
+               u16 t;
+
+               t=next_tx(lp->tx_ring_tail);
+               np=lp->tx_ring[t].p;
+
+               if(!(np->status & (1<<7)))
+               {
+                       /* Not COMPLETED */
+                       break;
+               }
+               dev->stats.tx_packets++;
+               if(!(np->status & (1<<6))) /* Not COMPLETED_OK */
+               {
+                       dev->stats.tx_errors++;
+
+                       switch(np->status&0x0F)
+                       {
+                               case 1:
+                                       dev->stats.tx_aborted_errors++;
+                                       break; /* Max collisions */
+                               case 2:
+                                       dev->stats.tx_fifo_errors++;
+                                       break;
+                               case 3:
+                                       dev->stats.tx_carrier_errors++;
+                                       break;
+                               case 4:
+                                       dev->stats.tx_window_errors++;
+                                       break;  /* CTS Lost */
+                               case 5:
+                                       dev->stats.tx_aborted_errors++;
+                                       break; /* Transmit timeout */
+                       }
+               }
+               /* Packets are sent in order - this is
+                   basically a FIFO queue of buffers matching
+                   the card ring */
+               dev->stats.tx_bytes+=lp->tx_ring[t].skb->len;
+               dev_kfree_skb_irq(lp->tx_ring[t].skb);
+               lp->tx_ring[t].skb=NULL;
+               atomic_inc(&lp->tx_count);
+               netif_wake_queue(dev);
+
+               lp->tx_ring_tail=t;
+       }
+
+}
+
+
+/**
+ *     mc32_interrupt          -       handle an interrupt from a 3c527
+ *     @irq: Interrupt number
+ *     @dev_id: 3c527 that requires servicing
+ *     @regs: Registers (unused)
+ *
+ *
+ *     An interrupt is raised whenever the 3c527 writes to the command
+ *     register. This register contains the message it wishes to send us
+ *     packed into a single byte field. We keep reading status entries
+ *     until we have processed all the control items, but simply count
+ *     transmit and receive reports. When all reports are in we empty the
+ *     transceiver rings as appropriate. This saves the overhead of
+ *     multiple command requests.
+ *
+ *     Because MCA is level-triggered, we shouldn't miss indications.
+ *     Therefore, we needn't ask the card to suspend interrupts within
+ *     this handler. The card receives an implicit acknowledgment of the
+ *     current interrupt when we read the command register.
+ *
+ */
+
+static irqreturn_t mc32_interrupt(int irq, void *dev_id)
+{
+       struct net_device *dev = dev_id;
+       struct mc32_local *lp;
+       int ioaddr, status, boguscount = 0;
+       int rx_event = 0;
+       int tx_event = 0;
+
+       ioaddr = dev->base_addr;
+       lp = netdev_priv(dev);
+
+       /* See whats cooking */
+
+       while((inb(ioaddr+HOST_STATUS)&HOST_STATUS_CWR) && boguscount++<2000)
+       {
+               status=inb(ioaddr+HOST_CMD);
+
+               pr_debug("Status TX%d RX%d EX%d OV%d BC%d\n",
+                       (status&7), (status>>3)&7, (status>>6)&1,
+                       (status>>7)&1, boguscount);
+
+               switch(status&7)
+               {
+                       case 0:
+                               break;
+                       case 6: /* TX fail */
+                       case 2: /* TX ok */
+                               tx_event = 1;
+                               break;
+                       case 3: /* Halt */
+                       case 4: /* Abort */
+                               complete(&lp->xceiver_cmd);
+                               break;
+                       default:
+                               pr_notice("%s: strange tx ack %d\n", dev->name, status&7);
+               }
+               status>>=3;
+               switch(status&7)
+               {
+                       case 0:
+                               break;
+                       case 2: /* RX */
+                               rx_event=1;
+                               break;
+                       case 3: /* Halt */
+                       case 4: /* Abort */
+                               complete(&lp->xceiver_cmd);
+                               break;
+                       case 6:
+                               /* Out of RX buffers stat */
+                               /* Must restart rx */
+                               dev->stats.rx_dropped++;
+                               mc32_rx_ring(dev);
+                               mc32_start_transceiver(dev);
+                               break;
+                       default:
+                               pr_notice("%s: strange rx ack %d\n",
+                                       dev->name, status&7);
+               }
+               status>>=3;
+               if(status&1)
+               {
+                       /*
+                        * No thread is waiting: we need to tidy
+                        * up ourself.
+                        */
+
+                       if (lp->cmd_nonblocking) {
+                               up(&lp->cmd_mutex);
+                               if (lp->mc_reload_wait)
+                                       mc32_reset_multicast_list(dev);
+                       }
+                       else complete(&lp->execution_cmd);
+               }
+               if(status&2)
+               {
+                       /*
+                        *      We get interrupted once per
+                        *      counter that is about to overflow.
+                        */
+
+                       mc32_update_stats(dev);
+               }
+       }
+
+
+       /*
+        *      Process the transmit and receive rings
+         */
+
+       if(tx_event)
+               mc32_tx_ring(dev);
+
+       if(rx_event)
+               mc32_rx_ring(dev);
+
+       return IRQ_HANDLED;
+}
+
+
+/**
+ *     mc32_close      -       user configuring the 3c527 down
+ *     @dev: 3c527 card to shut down
+ *
+ *     The 3c527 is a bus mastering device. We must be careful how we
+ *     shut it down. It may also be running shared interrupt so we have
+ *     to be sure to silence it properly
+ *
+ *     We indicate that the card is closing to the rest of the
+ *     driver.  Otherwise, it is possible that the card may run out
+ *     of receive buffers and restart the transceiver while we're
+ *     trying to close it.
+ *
+ *     We abort any receive and transmits going on and then wait until
+ *     any pending exec commands have completed in other code threads.
+ *     In theory we can't get here while that is true, in practice I am
+ *     paranoid
+ *
+ *     We turn off the interrupt enable for the board to be sure it can't
+ *     intefere with other devices.
+ */
+
+static int mc32_close(struct net_device *dev)
+{
+       struct mc32_local *lp = netdev_priv(dev);
+       int ioaddr = dev->base_addr;
+
+       u8 regs;
+       u16 one=1;
+
+       lp->xceiver_desired_state = HALTED;
+       netif_stop_queue(dev);
+
+       /*
+        *      Send the indications on command (handy debug check)
+        */
+
+       mc32_command(dev, 4, &one, 2);
+
+       /* Shut down the transceiver */
+
+       mc32_halt_transceiver(dev);
+
+       /* Ensure we issue no more commands beyond this point */
+
+       down(&lp->cmd_mutex);
+
+       /* Ok the card is now stopping */
+
+       regs=inb(ioaddr+HOST_CTRL);
+       regs&=~HOST_CTRL_INTE;
+       outb(regs, ioaddr+HOST_CTRL);
+
+       mc32_flush_rx_ring(dev);
+       mc32_flush_tx_ring(dev);
+
+       mc32_update_stats(dev);
+
+       return 0;
+}
+
+
+/**
+ *     mc32_get_stats          -       hand back stats to network layer
+ *     @dev: The 3c527 card to handle
+ *
+ *     We've collected all the stats we can in software already. Now
+ *     it's time to update those kept on-card and return the lot.
+ *
+ */
+
+static struct net_device_stats *mc32_get_stats(struct net_device *dev)
+{
+       mc32_update_stats(dev);
+       return &dev->stats;
+}
+
+
+/**
+ *     do_mc32_set_multicast_list      -       attempt to update multicasts
+ *     @dev: 3c527 device to load the list on
+ *     @retry: indicates this is not the first call.
+ *
+ *
+ *     Actually set or clear the multicast filter for this adaptor. The
+ *     locking issues are handled by this routine. We have to track
+ *     state as it may take multiple calls to get the command sequence
+ *     completed. We just keep trying to schedule the loads until we
+ *     manage to process them all.
+ *
+ *     num_addrs == -1 Promiscuous mode, receive all packets
+ *
+ *     num_addrs == 0  Normal mode, clear multicast list
+ *
+ *     num_addrs > 0   Multicast mode, receive normal and MC packets,
+ *                     and do best-effort filtering.
+ *
+ *     See mc32_update_stats() regards setting the SAV BP bit.
+ *
+ */
+
+static void do_mc32_set_multicast_list(struct net_device *dev, int retry)
+{
+       struct mc32_local *lp = netdev_priv(dev);
+       u16 filt = (1<<2); /* Save Bad Packets, for stats purposes */
+
+       if ((dev->flags&IFF_PROMISC) ||
+           (dev->flags&IFF_ALLMULTI) ||
+           netdev_mc_count(dev) > 10)
+               /* Enable promiscuous mode */
+               filt |= 1;
+       else if (!netdev_mc_empty(dev))
+       {
+               unsigned char block[62];
+               unsigned char *bp;
+               struct netdev_hw_addr *ha;
+
+               if(retry==0)
+                       lp->mc_list_valid = 0;
+               if(!lp->mc_list_valid)
+               {
+                       block[1]=0;
+                       block[0]=netdev_mc_count(dev);
+                       bp=block+2;
+
+                       netdev_for_each_mc_addr(ha, dev) {
+                               memcpy(bp, ha->addr, 6);
+                               bp+=6;
+                       }
+                       if(mc32_command_nowait(dev, 2, block,
+                                              2+6*netdev_mc_count(dev))==-1)
+                       {
+                               lp->mc_reload_wait = 1;
+                               return;
+                       }
+                       lp->mc_list_valid=1;
+               }
+       }
+
+       if(mc32_command_nowait(dev, 0, &filt, 2)==-1)
+       {
+               lp->mc_reload_wait = 1;
+       }
+       else {
+               lp->mc_reload_wait = 0;
+       }
+}
+
+
+/**
+ *     mc32_set_multicast_list -       queue multicast list update
+ *     @dev: The 3c527 to use
+ *
+ *     Commence loading the multicast list. This is called when the kernel
+ *     changes the lists. It will override any pending list we are trying to
+ *     load.
+ */
+
+static void mc32_set_multicast_list(struct net_device *dev)
+{
+       do_mc32_set_multicast_list(dev,0);
+}
+
+
+/**
+ *     mc32_reset_multicast_list       -       reset multicast list
+ *     @dev: The 3c527 to use
+ *
+ *     Attempt the next step in loading the multicast lists. If this attempt
+ *     fails to complete then it will be scheduled and this function called
+ *     again later from elsewhere.
+ */
+
+static void mc32_reset_multicast_list(struct net_device *dev)
+{
+       do_mc32_set_multicast_list(dev,1);
+}
+
+static void netdev_get_drvinfo(struct net_device *dev,
+                              struct ethtool_drvinfo *info)
+{
+       strcpy(info->driver, DRV_NAME);
+       strcpy(info->version, DRV_VERSION);
+       sprintf(info->bus_info, "MCA 0x%lx", dev->base_addr);
+}
+
+static u32 netdev_get_msglevel(struct net_device *dev)
+{
+       return mc32_debug;
+}
+
+static void netdev_set_msglevel(struct net_device *dev, u32 level)
+{
+       mc32_debug = level;
+}
+
+static const struct ethtool_ops netdev_ethtool_ops = {
+       .get_drvinfo            = netdev_get_drvinfo,
+       .get_msglevel           = netdev_get_msglevel,
+       .set_msglevel           = netdev_set_msglevel,
+};
+
+#ifdef MODULE
+
+static struct net_device *this_device;
+
+/**
+ *     init_module             -       entry point
+ *
+ *     Probe and locate a 3c527 card. This really should probe and locate
+ *     all the 3c527 cards in the machine not just one of them. Yes you can
+ *     insmod multiple modules for now but it's a hack.
+ */
+
+int __init init_module(void)
+{
+       this_device = mc32_probe(-1);
+       if (IS_ERR(this_device))
+               return PTR_ERR(this_device);
+       return 0;
+}
+
+/**
+ *     cleanup_module  -       free resources for an unload
+ *
+ *     Unloading time. We release the MCA bus resources and the interrupt
+ *     at which point everything is ready to unload. The card must be stopped
+ *     at this point or we would not have been called. When we unload we
+ *     leave the card stopped but not totally shut down. When the card is
+ *     initialized it must be rebooted or the rings reloaded before any
+ *     transmit operations are allowed to start scribbling into memory.
+ */
+
+void __exit cleanup_module(void)
+{
+       unregister_netdev(this_device);
+       cleanup_card(this_device);
+       free_netdev(this_device);
+}
+
+#endif /* MODULE */
diff --git a/drivers/net/ethernet/i825xx/3c527.h b/drivers/net/ethernet/i825xx/3c527.h
new file mode 100644 (file)
index 0000000..d693b8d
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ *     3COM "EtherLink MC/32" Descriptions
+ */
+
+/*
+ *     Registers
+ */
+
+#define HOST_CMD               0
+#define         HOST_CMD_START_RX   (1<<3)
+#define         HOST_CMD_SUSPND_RX  (3<<3)
+#define         HOST_CMD_RESTRT_RX  (5<<3)
+
+#define         HOST_CMD_SUSPND_TX  3
+#define         HOST_CMD_RESTRT_TX  5
+
+
+#define HOST_STATUS            2
+#define                HOST_STATUS_CRR (1<<6)
+#define                HOST_STATUS_CWR (1<<5)
+
+
+#define HOST_CTRL              6
+#define                HOST_CTRL_ATTN  (1<<7)
+#define        HOST_CTRL_RESET (1<<6)
+#define        HOST_CTRL_INTE  (1<<2)
+
+#define HOST_RAMPAGE           8
+
+#define HALTED 0
+#define RUNNING 1
+
+struct mc32_mailbox
+{
+       u16 mbox;
+       u16 data[1];
+} __packed;
+
+struct skb_header
+{
+       u8 status;
+       u8 control;
+       u16 next;       /* Do not change! */
+       u16 length;
+       u32 data;
+} __packed;
+
+struct mc32_stats
+{
+       /* RX Errors */
+       u32 rx_crc_errors;
+       u32 rx_alignment_errors;
+       u32 rx_overrun_errors;
+       u32 rx_tooshort_errors;
+       u32 rx_toolong_errors;
+       u32 rx_outofresource_errors;
+
+       u32 rx_discarded;  /* via card pattern match filter */
+
+       /* TX Errors */
+       u32 tx_max_collisions;
+       u32 tx_carrier_errors;
+       u32 tx_underrun_errors;
+       u32 tx_cts_errors;
+       u32 tx_timeout_errors;
+
+       /* various cruft */
+       u32 dataA[6];
+       u16 dataB[5];
+       u32 dataC[14];
+} __packed;
+
+#define STATUS_MASK    0x0F
+#define COMPLETED      (1<<7)
+#define COMPLETED_OK   (1<<6)
+#define BUFFER_BUSY    (1<<5)
+
+#define CONTROL_EOP    (1<<7)  /* End Of Packet */
+#define CONTROL_EOL    (1<<6)  /* End of List */
+
+#define MCA_MC32_ID    0x0041  /* Our MCA ident */
diff --git a/drivers/net/ethernet/i825xx/82596.c b/drivers/net/ethernet/i825xx/82596.c
new file mode 100644 (file)
index 0000000..be1f197
--- /dev/null
@@ -0,0 +1,1632 @@
+/* 82596.c: A generic 82596 ethernet driver for linux. */
+/*
+   Based on Apricot.c
+   Written 1994 by Mark Evans.
+   This driver is for the Apricot 82596 bus-master interface
+
+   Modularised 12/94 Mark Evans
+
+
+   Modified to support the 82596 ethernet chips on 680x0 VME boards.
+   by Richard Hirst <richard@sleepie.demon.co.uk>
+   Renamed to be 82596.c
+
+   980825:  Changed to receive directly in to sk_buffs which are
+   allocated at open() time.  Eliminates copy on incoming frames
+   (small ones are still copied).  Shared data now held in a
+   non-cached page, so we can run on 68060 in copyback mode.
+
+   TBD:
+   * look at deferring rx frames rather than discarding (as per tulip)
+   * handle tx ring full as per tulip
+   * performance test to tune rx_copybreak
+
+   Most of my modifications relate to the braindead big-endian
+   implementation by Intel.  When the i596 is operating in
+   'big-endian' mode, it thinks a 32 bit value of 0x12345678
+   should be stored as 0x56781234.  This is a real pain, when
+   you have linked lists which are shared by the 680x0 and the
+   i596.
+
+   Driver skeleton
+   Written 1993 by Donald Becker.
+   Copyright 1993 United States Government as represented by the Director,
+   National Security Agency. This software may only be used and distributed
+   according to the terms of the GNU General Public License as modified by SRC,
+   incorporated herein by reference.
+
+   The author may be reached as becker@scyld.com, or C/O
+   Scyld Computing Corporation, 410 Severn Ave., Suite 210, Annapolis MD 21403
+
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/gfp.h>
+
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/pgtable.h>
+#include <asm/cacheflush.h>
+
+static char version[] __initdata =
+       "82596.c $Revision: 1.5 $\n";
+
+#define DRV_NAME       "82596"
+
+/* DEBUG flags
+ */
+
+#define DEB_INIT       0x0001
+#define DEB_PROBE      0x0002
+#define DEB_SERIOUS    0x0004
+#define DEB_ERRORS     0x0008
+#define DEB_MULTI      0x0010
+#define DEB_TDR                0x0020
+#define DEB_OPEN       0x0040
+#define DEB_RESET      0x0080
+#define DEB_ADDCMD     0x0100
+#define DEB_STATUS     0x0200
+#define DEB_STARTTX    0x0400
+#define DEB_RXADDR     0x0800
+#define DEB_TXADDR     0x1000
+#define DEB_RXFRAME    0x2000
+#define DEB_INTS       0x4000
+#define DEB_STRUCT     0x8000
+#define DEB_ANY                0xffff
+
+
+#define DEB(x,y)       if (i596_debug & (x)) y
+
+
+#if defined(CONFIG_MVME16x_NET) || defined(CONFIG_MVME16x_NET_MODULE)
+#define ENABLE_MVME16x_NET
+#endif
+#if defined(CONFIG_BVME6000_NET) || defined(CONFIG_BVME6000_NET_MODULE)
+#define ENABLE_BVME6000_NET
+#endif
+#if defined(CONFIG_APRICOT) || defined(CONFIG_APRICOT_MODULE)
+#define ENABLE_APRICOT
+#endif
+
+#ifdef ENABLE_MVME16x_NET
+#include <asm/mvme16xhw.h>
+#endif
+#ifdef ENABLE_BVME6000_NET
+#include <asm/bvme6000hw.h>
+#endif
+
+/*
+ * Define various macros for Channel Attention, word swapping etc., dependent
+ * on architecture.  MVME and BVME are 680x0 based, otherwise it is Intel.
+ */
+
+#ifdef __mc68000__
+#define WSWAPrfd(x)  ((struct i596_rfd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
+#define WSWAPrbd(x)  ((struct i596_rbd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
+#define WSWAPiscp(x) ((struct i596_iscp *)(((u32)(x)<<16) | ((((u32)(x)))>>16)))
+#define WSWAPscb(x)  ((struct i596_scb *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
+#define WSWAPcmd(x)  ((struct i596_cmd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
+#define WSWAPtbd(x)  ((struct i596_tbd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
+#define WSWAPchar(x) ((char *)            (((u32)(x)<<16) | ((((u32)(x)))>>16)))
+#define ISCP_BUSY      0x00010000
+#define MACH_IS_APRICOT        0
+#else
+#define WSWAPrfd(x)     ((struct i596_rfd *)((long)x))
+#define WSWAPrbd(x)     ((struct i596_rbd *)((long)x))
+#define WSWAPiscp(x)    ((struct i596_iscp *)((long)x))
+#define WSWAPscb(x)     ((struct i596_scb *)((long)x))
+#define WSWAPcmd(x)     ((struct i596_cmd *)((long)x))
+#define WSWAPtbd(x)     ((struct i596_tbd *)((long)x))
+#define WSWAPchar(x)    ((char *)((long)x))
+#define ISCP_BUSY      0x0001
+#define MACH_IS_APRICOT        1
+#endif
+
+/*
+ * The MPU_PORT command allows direct access to the 82596. With PORT access
+ * the following commands are available (p5-18). The 32-bit port command
+ * must be word-swapped with the most significant word written first.
+ * This only applies to VME boards.
+ */
+#define PORT_RESET             0x00    /* reset 82596 */
+#define PORT_SELFTEST          0x01    /* selftest */
+#define PORT_ALTSCP            0x02    /* alternate SCB address */
+#define PORT_ALTDUMP           0x03    /* Alternate DUMP address */
+
+static int i596_debug = (DEB_SERIOUS|DEB_PROBE);
+
+MODULE_AUTHOR("Richard Hirst");
+MODULE_DESCRIPTION("i82596 driver");
+MODULE_LICENSE("GPL");
+
+module_param(i596_debug, int, 0);
+MODULE_PARM_DESC(i596_debug, "i82596 debug mask");
+
+
+/* Copy frames shorter than rx_copybreak, otherwise pass on up in
+ * a full sized sk_buff.  Value of 100 stolen from tulip.c (!alpha).
+ */
+static int rx_copybreak = 100;
+
+#define PKT_BUF_SZ     1536
+#define MAX_MC_CNT     64
+
+#define I596_TOTAL_SIZE 17
+
+#define I596_NULL ((void *)0xffffffff)
+
+#define CMD_EOL                0x8000  /* The last command of the list, stop. */
+#define CMD_SUSP       0x4000  /* Suspend after doing cmd. */
+#define CMD_INTR       0x2000  /* Interrupt after doing cmd. */
+
+#define CMD_FLEX       0x0008  /* Enable flexible memory model */
+
+enum commands {
+       CmdNOp = 0, CmdSASetup = 1, CmdConfigure = 2, CmdMulticastList = 3,
+       CmdTx = 4, CmdTDR = 5, CmdDump = 6, CmdDiagnose = 7
+};
+
+#define STAT_C         0x8000  /* Set to 0 after execution */
+#define STAT_B         0x4000  /* Command being executed */
+#define STAT_OK                0x2000  /* Command executed ok */
+#define STAT_A         0x1000  /* Command aborted */
+
+#define         CUC_START      0x0100
+#define         CUC_RESUME     0x0200
+#define         CUC_SUSPEND    0x0300
+#define         CUC_ABORT      0x0400
+#define         RX_START       0x0010
+#define         RX_RESUME      0x0020
+#define         RX_SUSPEND     0x0030
+#define         RX_ABORT       0x0040
+
+#define TX_TIMEOUT     (HZ/20)
+
+
+struct i596_reg {
+       unsigned short porthi;
+       unsigned short portlo;
+       unsigned long ca;
+};
+
+#define EOF            0x8000
+#define SIZE_MASK      0x3fff
+
+struct i596_tbd {
+       unsigned short size;
+       unsigned short pad;
+       struct i596_tbd *next;
+       char *data;
+};
+
+/* The command structure has two 'next' pointers; v_next is the address of
+ * the next command as seen by the CPU, b_next is the address of the next
+ * command as seen by the 82596.  The b_next pointer, as used by the 82596
+ * always references the status field of the next command, rather than the
+ * v_next field, because the 82596 is unaware of v_next.  It may seem more
+ * logical to put v_next at the end of the structure, but we cannot do that
+ * because the 82596 expects other fields to be there, depending on command
+ * type.
+ */
+
+struct i596_cmd {
+       struct i596_cmd *v_next;        /* Address from CPUs viewpoint */
+       unsigned short status;
+       unsigned short command;
+       struct i596_cmd *b_next;        /* Address from i596 viewpoint */
+};
+
+struct tx_cmd {
+       struct i596_cmd cmd;
+       struct i596_tbd *tbd;
+       unsigned short size;
+       unsigned short pad;
+       struct sk_buff *skb;    /* So we can free it after tx */
+};
+
+struct tdr_cmd {
+       struct i596_cmd cmd;
+       unsigned short status;
+       unsigned short pad;
+};
+
+struct mc_cmd {
+       struct i596_cmd cmd;
+       short mc_cnt;
+       char mc_addrs[MAX_MC_CNT*6];
+};
+
+struct sa_cmd {
+       struct i596_cmd cmd;
+       char eth_addr[8];
+};
+
+struct cf_cmd {
+       struct i596_cmd cmd;
+       char i596_config[16];
+};
+
+struct i596_rfd {
+       unsigned short stat;
+       unsigned short cmd;
+       struct i596_rfd *b_next;        /* Address from i596 viewpoint */
+       struct i596_rbd *rbd;
+       unsigned short count;
+       unsigned short size;
+       struct i596_rfd *v_next;        /* Address from CPUs viewpoint */
+       struct i596_rfd *v_prev;
+};
+
+struct i596_rbd {
+    unsigned short count;
+    unsigned short zero1;
+    struct i596_rbd *b_next;
+    unsigned char *b_data;             /* Address from i596 viewpoint */
+    unsigned short size;
+    unsigned short zero2;
+    struct sk_buff *skb;
+    struct i596_rbd *v_next;
+    struct i596_rbd *b_addr;           /* This rbd addr from i596 view */
+    unsigned char *v_data;             /* Address from CPUs viewpoint */
+};
+
+#define TX_RING_SIZE 64
+#define RX_RING_SIZE 16
+
+struct i596_scb {
+       unsigned short status;
+       unsigned short command;
+       struct i596_cmd *cmd;
+       struct i596_rfd *rfd;
+       unsigned long crc_err;
+       unsigned long align_err;
+       unsigned long resource_err;
+       unsigned long over_err;
+       unsigned long rcvdt_err;
+       unsigned long short_err;
+       unsigned short t_on;
+       unsigned short t_off;
+};
+
+struct i596_iscp {
+       unsigned long stat;
+       struct i596_scb *scb;
+};
+
+struct i596_scp {
+       unsigned long sysbus;
+       unsigned long pad;
+       struct i596_iscp *iscp;
+};
+
+struct i596_private {
+       volatile struct i596_scp scp;
+       volatile struct i596_iscp iscp;
+       volatile struct i596_scb scb;
+       struct sa_cmd sa_cmd;
+       struct cf_cmd cf_cmd;
+       struct tdr_cmd tdr_cmd;
+       struct mc_cmd mc_cmd;
+       unsigned long stat;
+       int last_restart __attribute__((aligned(4)));
+       struct i596_rfd *rfd_head;
+       struct i596_rbd *rbd_head;
+       struct i596_cmd *cmd_tail;
+       struct i596_cmd *cmd_head;
+       int cmd_backlog;
+       unsigned long last_cmd;
+       struct i596_rfd rfds[RX_RING_SIZE];
+       struct i596_rbd rbds[RX_RING_SIZE];
+       struct tx_cmd tx_cmds[TX_RING_SIZE];
+       struct i596_tbd tbds[TX_RING_SIZE];
+       int next_tx_cmd;
+       spinlock_t lock;
+};
+
+static char init_setup[] =
+{
+       0x8E,                   /* length, prefetch on */
+       0xC8,                   /* fifo to 8, monitor off */
+#ifdef CONFIG_VME
+       0xc0,                   /* don't save bad frames */
+#else
+       0x80,                   /* don't save bad frames */
+#endif
+       0x2E,                   /* No source address insertion, 8 byte preamble */
+       0x00,                   /* priority and backoff defaults */
+       0x60,                   /* interframe spacing */
+       0x00,                   /* slot time LSB */
+       0xf2,                   /* slot time and retries */
+       0x00,                   /* promiscuous mode */
+       0x00,                   /* collision detect */
+       0x40,                   /* minimum frame length */
+       0xff,
+       0x00,
+       0x7f /*  *multi IA */ };
+
+static int i596_open(struct net_device *dev);
+static netdev_tx_t i596_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static irqreturn_t i596_interrupt(int irq, void *dev_id);
+static int i596_close(struct net_device *dev);
+static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd);
+static void i596_tx_timeout (struct net_device *dev);
+static void print_eth(unsigned char *buf, char *str);
+static void set_multicast_list(struct net_device *dev);
+
+static int rx_ring_size = RX_RING_SIZE;
+static int ticks_limit = 25;
+static int max_cmd_backlog = TX_RING_SIZE-1;
+
+
+static inline void CA(struct net_device *dev)
+{
+#ifdef ENABLE_MVME16x_NET
+       if (MACH_IS_MVME16x) {
+               ((struct i596_reg *) dev->base_addr)->ca = 1;
+       }
+#endif
+#ifdef ENABLE_BVME6000_NET
+       if (MACH_IS_BVME6000) {
+               volatile u32 i;
+
+               i = *(volatile u32 *) (dev->base_addr);
+       }
+#endif
+#ifdef ENABLE_APRICOT
+       if (MACH_IS_APRICOT) {
+               outw(0, (short) (dev->base_addr) + 4);
+       }
+#endif
+}
+
+
+static inline void MPU_PORT(struct net_device *dev, int c, volatile void *x)
+{
+#ifdef ENABLE_MVME16x_NET
+       if (MACH_IS_MVME16x) {
+               struct i596_reg *p = (struct i596_reg *) (dev->base_addr);
+               p->porthi = ((c) | (u32) (x)) & 0xffff;
+               p->portlo = ((c) | (u32) (x)) >> 16;
+       }
+#endif
+#ifdef ENABLE_BVME6000_NET
+       if (MACH_IS_BVME6000) {
+               u32 v = (u32) (c) | (u32) (x);
+               v = ((u32) (v) << 16) | ((u32) (v) >> 16);
+               *(volatile u32 *) dev->base_addr = v;
+               udelay(1);
+               *(volatile u32 *) dev->base_addr = v;
+       }
+#endif
+}
+
+
+static inline int wait_istat(struct net_device *dev, struct i596_private *lp, int delcnt, char *str)
+{
+       while (--delcnt && lp->iscp.stat)
+               udelay(10);
+       if (!delcnt) {
+               printk(KERN_ERR "%s: %s, status %4.4x, cmd %4.4x.\n",
+                    dev->name, str, lp->scb.status, lp->scb.command);
+               return -1;
+       }
+       else
+               return 0;
+}
+
+
+static inline int wait_cmd(struct net_device *dev, struct i596_private *lp, int delcnt, char *str)
+{
+       while (--delcnt && lp->scb.command)
+               udelay(10);
+       if (!delcnt) {
+               printk(KERN_ERR "%s: %s, status %4.4x, cmd %4.4x.\n",
+                    dev->name, str, lp->scb.status, lp->scb.command);
+               return -1;
+       }
+       else
+               return 0;
+}
+
+
+static inline int wait_cfg(struct net_device *dev, struct i596_cmd *cmd, int delcnt, char *str)
+{
+       volatile struct i596_cmd *c = cmd;
+
+       while (--delcnt && c->command)
+               udelay(10);
+       if (!delcnt) {
+               printk(KERN_ERR "%s: %s.\n", dev->name, str);
+               return -1;
+       }
+       else
+               return 0;
+}
+
+
+static void i596_display_data(struct net_device *dev)
+{
+       struct i596_private *lp = dev->ml_priv;
+       struct i596_cmd *cmd;
+       struct i596_rfd *rfd;
+       struct i596_rbd *rbd;
+
+       printk(KERN_ERR "lp and scp at %p, .sysbus = %08lx, .iscp = %p\n",
+              &lp->scp, lp->scp.sysbus, lp->scp.iscp);
+       printk(KERN_ERR "iscp at %p, iscp.stat = %08lx, .scb = %p\n",
+              &lp->iscp, lp->iscp.stat, lp->iscp.scb);
+       printk(KERN_ERR "scb at %p, scb.status = %04x, .command = %04x,"
+               " .cmd = %p, .rfd = %p\n",
+              &lp->scb, lp->scb.status, lp->scb.command,
+               lp->scb.cmd, lp->scb.rfd);
+       printk(KERN_ERR "   errors: crc %lx, align %lx, resource %lx,"
+               " over %lx, rcvdt %lx, short %lx\n",
+               lp->scb.crc_err, lp->scb.align_err, lp->scb.resource_err,
+               lp->scb.over_err, lp->scb.rcvdt_err, lp->scb.short_err);
+       cmd = lp->cmd_head;
+       while (cmd != I596_NULL) {
+               printk(KERN_ERR "cmd at %p, .status = %04x, .command = %04x, .b_next = %p\n",
+                 cmd, cmd->status, cmd->command, cmd->b_next);
+               cmd = cmd->v_next;
+       }
+       rfd = lp->rfd_head;
+       printk(KERN_ERR "rfd_head = %p\n", rfd);
+       do {
+               printk(KERN_ERR "   %p .stat %04x, .cmd %04x, b_next %p, rbd %p,"
+                        " count %04x\n",
+                       rfd, rfd->stat, rfd->cmd, rfd->b_next, rfd->rbd,
+                       rfd->count);
+               rfd = rfd->v_next;
+       } while (rfd != lp->rfd_head);
+       rbd = lp->rbd_head;
+       printk(KERN_ERR "rbd_head = %p\n", rbd);
+       do {
+               printk(KERN_ERR "   %p .count %04x, b_next %p, b_data %p, size %04x\n",
+                       rbd, rbd->count, rbd->b_next, rbd->b_data, rbd->size);
+               rbd = rbd->v_next;
+       } while (rbd != lp->rbd_head);
+}
+
+
+#if defined(ENABLE_MVME16x_NET) || defined(ENABLE_BVME6000_NET)
+static irqreturn_t i596_error(int irq, void *dev_id)
+{
+       struct net_device *dev = dev_id;
+#ifdef ENABLE_MVME16x_NET
+       if (MACH_IS_MVME16x) {
+               volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000;
+
+               pcc2[0x28] = 1;
+               pcc2[0x2b] = 0x1d;
+       }
+#endif
+#ifdef ENABLE_BVME6000_NET
+       if (MACH_IS_BVME6000) {
+               volatile unsigned char *ethirq = (unsigned char *) BVME_ETHIRQ_REG;
+
+               *ethirq = 1;
+               *ethirq = 3;
+       }
+#endif
+       printk(KERN_ERR "%s: Error interrupt\n", dev->name);
+       i596_display_data(dev);
+       return IRQ_HANDLED;
+}
+#endif
+
+static inline void remove_rx_bufs(struct net_device *dev)
+{
+       struct i596_private *lp = dev->ml_priv;
+       struct i596_rbd *rbd;
+       int i;
+
+       for (i = 0, rbd = lp->rbds; i < rx_ring_size; i++, rbd++) {
+               if (rbd->skb == NULL)
+                       break;
+               dev_kfree_skb(rbd->skb);
+               rbd->skb = NULL;
+       }
+}
+
+static inline int init_rx_bufs(struct net_device *dev)
+{
+       struct i596_private *lp = dev->ml_priv;
+       int i;
+       struct i596_rfd *rfd;
+       struct i596_rbd *rbd;
+
+       /* First build the Receive Buffer Descriptor List */
+
+       for (i = 0, rbd = lp->rbds; i < rx_ring_size; i++, rbd++) {
+               struct sk_buff *skb = dev_alloc_skb(PKT_BUF_SZ);
+
+               if (skb == NULL) {
+                       remove_rx_bufs(dev);
+                       return -ENOMEM;
+               }
+
+               skb->dev = dev;
+               rbd->v_next = rbd+1;
+               rbd->b_next = WSWAPrbd(virt_to_bus(rbd+1));
+               rbd->b_addr = WSWAPrbd(virt_to_bus(rbd));
+               rbd->skb = skb;
+               rbd->v_data = skb->data;
+               rbd->b_data = WSWAPchar(virt_to_bus(skb->data));
+               rbd->size = PKT_BUF_SZ;
+#ifdef __mc68000__
+               cache_clear(virt_to_phys(skb->data), PKT_BUF_SZ);
+#endif
+       }
+       lp->rbd_head = lp->rbds;
+       rbd = lp->rbds + rx_ring_size - 1;
+       rbd->v_next = lp->rbds;
+       rbd->b_next = WSWAPrbd(virt_to_bus(lp->rbds));
+
+       /* Now build the Receive Frame Descriptor List */
+
+       for (i = 0, rfd = lp->rfds; i < rx_ring_size; i++, rfd++) {
+               rfd->rbd = I596_NULL;
+               rfd->v_next = rfd+1;
+               rfd->v_prev = rfd-1;
+               rfd->b_next = WSWAPrfd(virt_to_bus(rfd+1));
+               rfd->cmd = CMD_FLEX;
+       }
+       lp->rfd_head = lp->rfds;
+       lp->scb.rfd = WSWAPrfd(virt_to_bus(lp->rfds));
+       rfd = lp->rfds;
+       rfd->rbd = lp->rbd_head;
+       rfd->v_prev = lp->rfds + rx_ring_size - 1;
+       rfd = lp->rfds + rx_ring_size - 1;
+       rfd->v_next = lp->rfds;
+       rfd->b_next = WSWAPrfd(virt_to_bus(lp->rfds));
+       rfd->cmd = CMD_EOL|CMD_FLEX;
+
+       return 0;
+}
+
+
+static void rebuild_rx_bufs(struct net_device *dev)
+{
+       struct i596_private *lp = dev->ml_priv;
+       int i;
+
+       /* Ensure rx frame/buffer descriptors are tidy */
+
+       for (i = 0; i < rx_ring_size; i++) {
+               lp->rfds[i].rbd = I596_NULL;
+               lp->rfds[i].cmd = CMD_FLEX;
+       }
+       lp->rfds[rx_ring_size-1].cmd = CMD_EOL|CMD_FLEX;
+       lp->rfd_head = lp->rfds;
+       lp->scb.rfd = WSWAPrfd(virt_to_bus(lp->rfds));
+       lp->rbd_head = lp->rbds;
+       lp->rfds[0].rbd = WSWAPrbd(virt_to_bus(lp->rbds));
+}
+
+
+static int init_i596_mem(struct net_device *dev)
+{
+       struct i596_private *lp = dev->ml_priv;
+#if !defined(ENABLE_MVME16x_NET) && !defined(ENABLE_BVME6000_NET) || defined(ENABLE_APRICOT)
+       short ioaddr = dev->base_addr;
+#endif
+       unsigned long flags;
+
+       MPU_PORT(dev, PORT_RESET, NULL);
+
+       udelay(100);            /* Wait 100us - seems to help */
+
+#if defined(ENABLE_MVME16x_NET) || defined(ENABLE_BVME6000_NET)
+#ifdef ENABLE_MVME16x_NET
+       if (MACH_IS_MVME16x) {
+               volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000;
+
+               /* Disable all ints for now */
+               pcc2[0x28] = 1;
+               pcc2[0x2a] = 0x48;
+               /* Following disables snooping.  Snooping is not required
+                * as we make appropriate use of non-cached pages for
+                * shared data, and cache_push/cache_clear.
+                */
+               pcc2[0x2b] = 0x08;
+       }
+#endif
+#ifdef ENABLE_BVME6000_NET
+       if (MACH_IS_BVME6000) {
+               volatile unsigned char *ethirq = (unsigned char *) BVME_ETHIRQ_REG;
+
+               *ethirq = 1;
+       }
+#endif
+
+       /* change the scp address */
+
+       MPU_PORT(dev, PORT_ALTSCP, (void *)virt_to_bus((void *)&lp->scp));
+
+#elif defined(ENABLE_APRICOT)
+
+       {
+               u32 scp = virt_to_bus(&lp->scp);
+
+               /* change the scp address */
+               outw(0, ioaddr);
+               outw(0, ioaddr);
+               outb(4, ioaddr + 0xf);
+               outw(scp | 2, ioaddr);
+               outw(scp >> 16, ioaddr);
+       }
+#endif
+
+       lp->last_cmd = jiffies;
+
+#ifdef ENABLE_MVME16x_NET
+       if (MACH_IS_MVME16x)
+               lp->scp.sysbus = 0x00000054;
+#endif
+#ifdef ENABLE_BVME6000_NET
+       if (MACH_IS_BVME6000)
+               lp->scp.sysbus = 0x0000004c;
+#endif
+#ifdef ENABLE_APRICOT
+       if (MACH_IS_APRICOT)
+               lp->scp.sysbus = 0x00440000;
+#endif
+
+       lp->scp.iscp = WSWAPiscp(virt_to_bus((void *)&lp->iscp));
+       lp->iscp.scb = WSWAPscb(virt_to_bus((void *)&lp->scb));
+       lp->iscp.stat = ISCP_BUSY;
+       lp->cmd_backlog = 0;
+
+       lp->cmd_head = lp->scb.cmd = I596_NULL;
+
+#ifdef ENABLE_BVME6000_NET
+       if (MACH_IS_BVME6000) {
+               lp->scb.t_on  = 7 * 25;
+               lp->scb.t_off = 1 * 25;
+       }
+#endif
+
+       DEB(DEB_INIT,printk(KERN_DEBUG "%s: starting i82596.\n", dev->name));
+
+#if defined(ENABLE_APRICOT)
+       (void) inb(ioaddr + 0x10);
+       outb(4, ioaddr + 0xf);
+#endif
+       CA(dev);
+
+       if (wait_istat(dev,lp,1000,"initialization timed out"))
+               goto failed;
+       DEB(DEB_INIT,printk(KERN_DEBUG "%s: i82596 initialization successful\n", dev->name));
+
+       /* Ensure rx frame/buffer descriptors are tidy */
+       rebuild_rx_bufs(dev);
+       lp->scb.command = 0;
+
+#ifdef ENABLE_MVME16x_NET
+       if (MACH_IS_MVME16x) {
+               volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000;
+
+               /* Enable ints, etc. now */
+               pcc2[0x2a] = 0x55;      /* Edge sensitive */
+               pcc2[0x2b] = 0x15;
+       }
+#endif
+#ifdef ENABLE_BVME6000_NET
+       if (MACH_IS_BVME6000) {
+               volatile unsigned char *ethirq = (unsigned char *) BVME_ETHIRQ_REG;
+
+               *ethirq = 3;
+       }
+#endif
+
+
+       DEB(DEB_INIT,printk(KERN_DEBUG "%s: queuing CmdConfigure\n", dev->name));
+       memcpy(lp->cf_cmd.i596_config, init_setup, 14);
+       lp->cf_cmd.cmd.command = CmdConfigure;
+       i596_add_cmd(dev, &lp->cf_cmd.cmd);
+
+       DEB(DEB_INIT,printk(KERN_DEBUG "%s: queuing CmdSASetup\n", dev->name));
+       memcpy(lp->sa_cmd.eth_addr, dev->dev_addr, 6);
+       lp->sa_cmd.cmd.command = CmdSASetup;
+       i596_add_cmd(dev, &lp->sa_cmd.cmd);
+
+       DEB(DEB_INIT,printk(KERN_DEBUG "%s: queuing CmdTDR\n", dev->name));
+       lp->tdr_cmd.cmd.command = CmdTDR;
+       i596_add_cmd(dev, &lp->tdr_cmd.cmd);
+
+       spin_lock_irqsave (&lp->lock, flags);
+
+       if (wait_cmd(dev,lp,1000,"timed out waiting to issue RX_START")) {
+               spin_unlock_irqrestore (&lp->lock, flags);
+               goto failed;
+       }
+       DEB(DEB_INIT,printk(KERN_DEBUG "%s: Issuing RX_START\n", dev->name));
+       lp->scb.command = RX_START;
+       CA(dev);
+
+       spin_unlock_irqrestore (&lp->lock, flags);
+
+       if (wait_cmd(dev,lp,1000,"RX_START not processed"))
+               goto failed;
+       DEB(DEB_INIT,printk(KERN_DEBUG "%s: Receive unit started OK\n", dev->name));
+       return 0;
+
+failed:
+       printk(KERN_CRIT "%s: Failed to initialise 82596\n", dev->name);
+       MPU_PORT(dev, PORT_RESET, NULL);
+       return -1;
+}
+
+static inline int i596_rx(struct net_device *dev)
+{
+       struct i596_private *lp = dev->ml_priv;
+       struct i596_rfd *rfd;
+       struct i596_rbd *rbd;
+       int frames = 0;
+
+       DEB(DEB_RXFRAME,printk(KERN_DEBUG "i596_rx(), rfd_head %p, rbd_head %p\n",
+                       lp->rfd_head, lp->rbd_head));
+
+       rfd = lp->rfd_head;             /* Ref next frame to check */
+
+       while ((rfd->stat) & STAT_C) {  /* Loop while complete frames */
+               if (rfd->rbd == I596_NULL)
+                       rbd = I596_NULL;
+               else if (rfd->rbd == lp->rbd_head->b_addr)
+                       rbd = lp->rbd_head;
+               else {
+                       printk(KERN_CRIT "%s: rbd chain broken!\n", dev->name);
+                       /* XXX Now what? */
+                       rbd = I596_NULL;
+               }
+               DEB(DEB_RXFRAME, printk(KERN_DEBUG "  rfd %p, rfd.rbd %p, rfd.stat %04x\n",
+                       rfd, rfd->rbd, rfd->stat));
+
+               if (rbd != I596_NULL && ((rfd->stat) & STAT_OK)) {
+                       /* a good frame */
+                       int pkt_len = rbd->count & 0x3fff;
+                       struct sk_buff *skb = rbd->skb;
+                       int rx_in_place = 0;
+
+                       DEB(DEB_RXADDR,print_eth(rbd->v_data, "received"));
+                       frames++;
+
+                       /* 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;
+
+                               /* Get fresh skbuff to replace filled one. */
+                               newskb = dev_alloc_skb(PKT_BUF_SZ);
+                               if (newskb == NULL) {
+                                       skb = NULL;     /* drop pkt */
+                                       goto memory_squeeze;
+                               }
+                               /* Pass up the skb already on the Rx ring. */
+                               skb_put(skb, pkt_len);
+                               rx_in_place = 1;
+                               rbd->skb = newskb;
+                               newskb->dev = dev;
+                               rbd->v_data = newskb->data;
+                               rbd->b_data = WSWAPchar(virt_to_bus(newskb->data));
+#ifdef __mc68000__
+                               cache_clear(virt_to_phys(newskb->data), PKT_BUF_SZ);
+#endif
+                       }
+                       else
+                               skb = dev_alloc_skb(pkt_len + 2);
+memory_squeeze:
+                       if (skb == NULL) {
+                               /* XXX tulip.c can defer packets here!! */
+                               printk(KERN_WARNING "%s: i596_rx Memory squeeze, dropping packet.\n", dev->name);
+                               dev->stats.rx_dropped++;
+                       }
+                       else {
+                               if (!rx_in_place) {
+                                       /* 16 byte align the data fields */
+                                       skb_reserve(skb, 2);
+                                       memcpy(skb_put(skb,pkt_len), rbd->v_data, pkt_len);
+                               }
+                               skb->protocol=eth_type_trans(skb,dev);
+                               skb->len = pkt_len;
+#ifdef __mc68000__
+                               cache_clear(virt_to_phys(rbd->skb->data),
+                                               pkt_len);
+#endif
+                               netif_rx(skb);
+                               dev->stats.rx_packets++;
+                               dev->stats.rx_bytes+=pkt_len;
+                       }
+               }
+               else {
+                       DEB(DEB_ERRORS, printk(KERN_DEBUG "%s: Error, rfd.stat = 0x%04x\n",
+                                       dev->name, rfd->stat));
+                       dev->stats.rx_errors++;
+                       if ((rfd->stat) & 0x0001)
+                               dev->stats.collisions++;
+                       if ((rfd->stat) & 0x0080)
+                               dev->stats.rx_length_errors++;
+                       if ((rfd->stat) & 0x0100)
+                               dev->stats.rx_over_errors++;
+                       if ((rfd->stat) & 0x0200)
+                               dev->stats.rx_fifo_errors++;
+                       if ((rfd->stat) & 0x0400)
+                               dev->stats.rx_frame_errors++;
+                       if ((rfd->stat) & 0x0800)
+                               dev->stats.rx_crc_errors++;
+                       if ((rfd->stat) & 0x1000)
+                               dev->stats.rx_length_errors++;
+               }
+
+               /* Clear the buffer descriptor count and EOF + F flags */
+
+               if (rbd != I596_NULL && (rbd->count & 0x4000)) {
+                       rbd->count = 0;
+                       lp->rbd_head = rbd->v_next;
+               }
+
+               /* Tidy the frame descriptor, marking it as end of list */
+
+               rfd->rbd = I596_NULL;
+               rfd->stat = 0;
+               rfd->cmd = CMD_EOL|CMD_FLEX;
+               rfd->count = 0;
+
+               /* Remove end-of-list from old end descriptor */
+
+               rfd->v_prev->cmd = CMD_FLEX;
+
+               /* Update record of next frame descriptor to process */
+
+               lp->scb.rfd = rfd->b_next;
+               lp->rfd_head = rfd->v_next;
+               rfd = lp->rfd_head;
+       }
+
+       DEB(DEB_RXFRAME,printk(KERN_DEBUG "frames %d\n", frames));
+
+       return 0;
+}
+
+
+static void i596_cleanup_cmd(struct net_device *dev, struct i596_private *lp)
+{
+       struct i596_cmd *ptr;
+
+       while (lp->cmd_head != I596_NULL) {
+               ptr = lp->cmd_head;
+               lp->cmd_head = ptr->v_next;
+               lp->cmd_backlog--;
+
+               switch ((ptr->command) & 0x7) {
+               case CmdTx:
+                       {
+                               struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr;
+                               struct sk_buff *skb = tx_cmd->skb;
+
+                               dev_kfree_skb(skb);
+
+                               dev->stats.tx_errors++;
+                               dev->stats.tx_aborted_errors++;
+
+                               ptr->v_next = ptr->b_next = I596_NULL;
+                               tx_cmd->cmd.command = 0;  /* Mark as free */
+                               break;
+                       }
+               default:
+                       ptr->v_next = ptr->b_next = I596_NULL;
+               }
+       }
+
+       wait_cmd(dev,lp,100,"i596_cleanup_cmd timed out");
+       lp->scb.cmd = I596_NULL;
+}
+
+static void i596_reset(struct net_device *dev, struct i596_private *lp,
+                       int ioaddr)
+{
+       unsigned long flags;
+
+       DEB(DEB_RESET,printk(KERN_DEBUG "i596_reset\n"));
+
+       spin_lock_irqsave (&lp->lock, flags);
+
+       wait_cmd(dev,lp,100,"i596_reset timed out");
+
+       netif_stop_queue(dev);
+
+       lp->scb.command = CUC_ABORT | RX_ABORT;
+       CA(dev);
+
+       /* wait for shutdown */
+       wait_cmd(dev,lp,1000,"i596_reset 2 timed out");
+       spin_unlock_irqrestore (&lp->lock, flags);
+
+       i596_cleanup_cmd(dev,lp);
+       i596_rx(dev);
+
+       netif_start_queue(dev);
+       init_i596_mem(dev);
+}
+
+static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd)
+{
+       struct i596_private *lp = dev->ml_priv;
+       int ioaddr = dev->base_addr;
+       unsigned long flags;
+
+       DEB(DEB_ADDCMD,printk(KERN_DEBUG "i596_add_cmd\n"));
+
+       cmd->status = 0;
+       cmd->command |= (CMD_EOL | CMD_INTR);
+       cmd->v_next = cmd->b_next = I596_NULL;
+
+       spin_lock_irqsave (&lp->lock, flags);
+
+       if (lp->cmd_head != I596_NULL) {
+               lp->cmd_tail->v_next = cmd;
+               lp->cmd_tail->b_next = WSWAPcmd(virt_to_bus(&cmd->status));
+       } else {
+               lp->cmd_head = cmd;
+               wait_cmd(dev,lp,100,"i596_add_cmd timed out");
+               lp->scb.cmd = WSWAPcmd(virt_to_bus(&cmd->status));
+               lp->scb.command = CUC_START;
+               CA(dev);
+       }
+       lp->cmd_tail = cmd;
+       lp->cmd_backlog++;
+
+       spin_unlock_irqrestore (&lp->lock, flags);
+
+       if (lp->cmd_backlog > max_cmd_backlog) {
+               unsigned long tickssofar = jiffies - lp->last_cmd;
+
+               if (tickssofar < ticks_limit)
+                       return;
+
+               printk(KERN_NOTICE "%s: command unit timed out, status resetting.\n", dev->name);
+
+               i596_reset(dev, lp, ioaddr);
+       }
+}
+
+static int i596_open(struct net_device *dev)
+{
+       int res = 0;
+
+       DEB(DEB_OPEN,printk(KERN_DEBUG "%s: i596_open() irq %d.\n", dev->name, dev->irq));
+
+       if (request_irq(dev->irq, i596_interrupt, 0, "i82596", dev)) {
+               printk(KERN_ERR "%s: IRQ %d not free\n", dev->name, dev->irq);
+               return -EAGAIN;
+       }
+#ifdef ENABLE_MVME16x_NET
+       if (MACH_IS_MVME16x) {
+               if (request_irq(0x56, i596_error, 0, "i82596_error", dev)) {
+                       res = -EAGAIN;
+                       goto err_irq_dev;
+               }
+       }
+#endif
+       res = init_rx_bufs(dev);
+       if (res)
+               goto err_irq_56;
+
+       netif_start_queue(dev);
+
+       if (init_i596_mem(dev)) {
+               res = -EAGAIN;
+               goto err_queue;
+       }
+
+       return 0;
+
+err_queue:
+       netif_stop_queue(dev);
+       remove_rx_bufs(dev);
+err_irq_56:
+#ifdef ENABLE_MVME16x_NET
+       free_irq(0x56, dev);
+err_irq_dev:
+#endif
+       free_irq(dev->irq, dev);
+
+       return res;
+}
+
+static void i596_tx_timeout (struct net_device *dev)
+{
+       struct i596_private *lp = dev->ml_priv;
+       int ioaddr = dev->base_addr;
+
+       /* Transmitter timeout, serious problems. */
+       DEB(DEB_ERRORS,printk(KERN_ERR "%s: transmit timed out, status resetting.\n",
+                       dev->name));
+
+       dev->stats.tx_errors++;
+
+       /* Try to restart the adaptor */
+       if (lp->last_restart == dev->stats.tx_packets) {
+               DEB(DEB_ERRORS,printk(KERN_ERR "Resetting board.\n"));
+               /* Shutdown and restart */
+               i596_reset (dev, lp, ioaddr);
+       } else {
+               /* Issue a channel attention signal */
+               DEB(DEB_ERRORS,printk(KERN_ERR "Kicking board.\n"));
+               lp->scb.command = CUC_START | RX_START;
+               CA (dev);
+               lp->last_restart = dev->stats.tx_packets;
+       }
+
+       dev->trans_start = jiffies; /* prevent tx timeout */
+       netif_wake_queue (dev);
+}
+
+static netdev_tx_t i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct i596_private *lp = dev->ml_priv;
+       struct tx_cmd *tx_cmd;
+       struct i596_tbd *tbd;
+       short length = skb->len;
+
+       DEB(DEB_STARTTX,printk(KERN_DEBUG "%s: i596_start_xmit(%x,%p) called\n",
+                               dev->name, skb->len, skb->data));
+
+       if (skb->len < ETH_ZLEN) {
+               if (skb_padto(skb, ETH_ZLEN))
+                       return NETDEV_TX_OK;
+               length = ETH_ZLEN;
+       }
+       netif_stop_queue(dev);
+
+       tx_cmd = lp->tx_cmds + lp->next_tx_cmd;
+       tbd = lp->tbds + lp->next_tx_cmd;
+
+       if (tx_cmd->cmd.command) {
+               printk(KERN_NOTICE "%s: xmit ring full, dropping packet.\n",
+                               dev->name);
+               dev->stats.tx_dropped++;
+
+               dev_kfree_skb(skb);
+       } else {
+               if (++lp->next_tx_cmd == TX_RING_SIZE)
+                       lp->next_tx_cmd = 0;
+               tx_cmd->tbd = WSWAPtbd(virt_to_bus(tbd));
+               tbd->next = I596_NULL;
+
+               tx_cmd->cmd.command = CMD_FLEX | CmdTx;
+               tx_cmd->skb = skb;
+
+               tx_cmd->pad = 0;
+               tx_cmd->size = 0;
+               tbd->pad = 0;
+               tbd->size = EOF | length;
+
+               tbd->data = WSWAPchar(virt_to_bus(skb->data));
+
+#ifdef __mc68000__
+               cache_push(virt_to_phys(skb->data), length);
+#endif
+               DEB(DEB_TXADDR,print_eth(skb->data, "tx-queued"));
+               i596_add_cmd(dev, &tx_cmd->cmd);
+
+               dev->stats.tx_packets++;
+               dev->stats.tx_bytes += length;
+       }
+
+       netif_start_queue(dev);
+
+       return NETDEV_TX_OK;
+}
+
+static void print_eth(unsigned char *add, char *str)
+{
+       printk(KERN_DEBUG "i596 0x%p, %pM --> %pM %02X%02X, %s\n",
+              add, add + 6, add, add[12], add[13], str);
+}
+
+static int io = 0x300;
+static int irq = 10;
+
+static const struct net_device_ops i596_netdev_ops = {
+       .ndo_open               = i596_open,
+       .ndo_stop               = i596_close,
+       .ndo_start_xmit         = i596_start_xmit,
+       .ndo_set_multicast_list = set_multicast_list,
+       .ndo_tx_timeout         = i596_tx_timeout,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
+struct net_device * __init i82596_probe(int unit)
+{
+       struct net_device *dev;
+       int i;
+       struct i596_private *lp;
+       char eth_addr[8];
+       static int probed;
+       int err;
+
+       if (probed)
+               return ERR_PTR(-ENODEV);
+       probed++;
+
+       dev = alloc_etherdev(0);
+       if (!dev)
+               return ERR_PTR(-ENOMEM);
+
+       if (unit >= 0) {
+               sprintf(dev->name, "eth%d", unit);
+               netdev_boot_setup_check(dev);
+       } else {
+               dev->base_addr = io;
+               dev->irq = irq;
+       }
+
+#ifdef ENABLE_MVME16x_NET
+       if (MACH_IS_MVME16x) {
+               if (mvme16x_config & MVME16x_CONFIG_NO_ETHERNET) {
+                       printk(KERN_NOTICE "Ethernet probe disabled - chip not present\n");
+                       err = -ENODEV;
+                       goto out;
+               }
+               memcpy(eth_addr, (void *) 0xfffc1f2c, 6);       /* YUCK! Get addr from NOVRAM */
+               dev->base_addr = MVME_I596_BASE;
+               dev->irq = (unsigned) MVME16x_IRQ_I596;
+               goto found;
+       }
+#endif
+#ifdef ENABLE_BVME6000_NET
+       if (MACH_IS_BVME6000) {
+               volatile unsigned char *rtc = (unsigned char *) BVME_RTC_BASE;
+               unsigned char msr = rtc[3];
+               int i;
+
+               rtc[3] |= 0x80;
+               for (i = 0; i < 6; i++)
+                       eth_addr[i] = rtc[i * 4 + 7];   /* Stored in RTC RAM at offset 1 */
+               rtc[3] = msr;
+               dev->base_addr = BVME_I596_BASE;
+               dev->irq = (unsigned) BVME_IRQ_I596;
+               goto found;
+       }
+#endif
+#ifdef ENABLE_APRICOT
+       {
+               int checksum = 0;
+               int ioaddr = 0x300;
+
+               /* this is easy the ethernet interface can only be at 0x300 */
+               /* first check nothing is already registered here */
+
+               if (!request_region(ioaddr, I596_TOTAL_SIZE, DRV_NAME)) {
+                       printk(KERN_ERR "82596: IO address 0x%04x in use\n", ioaddr);
+                       err = -EBUSY;
+                       goto out;
+               }
+
+               dev->base_addr = ioaddr;
+
+               for (i = 0; i < 8; i++) {
+                       eth_addr[i] = inb(ioaddr + 8 + i);
+                       checksum += eth_addr[i];
+               }
+
+               /* checksum is a multiple of 0x100, got this wrong first time
+                  some machines have 0x100, some 0x200. The DOS driver doesn't
+                  even bother with the checksum.
+                  Some other boards trip the checksum.. but then appear as
+                  ether address 0. Trap these - AC */
+
+               if ((checksum % 0x100) ||
+                   (memcmp(eth_addr, "\x00\x00\x49", 3) != 0)) {
+                       err = -ENODEV;
+                       goto out1;
+               }
+
+               dev->irq = 10;
+               goto found;
+       }
+#endif
+       err = -ENODEV;
+       goto out;
+
+found:
+       dev->mem_start = (int)__get_free_pages(GFP_ATOMIC, 0);
+       if (!dev->mem_start) {
+               err = -ENOMEM;
+               goto out1;
+       }
+
+       DEB(DEB_PROBE,printk(KERN_INFO "%s: 82596 at %#3lx,", dev->name, dev->base_addr));
+
+       for (i = 0; i < 6; i++)
+               DEB(DEB_PROBE,printk(" %2.2X", dev->dev_addr[i] = eth_addr[i]));
+
+       DEB(DEB_PROBE,printk(" IRQ %d.\n", dev->irq));
+
+       DEB(DEB_PROBE,printk(KERN_INFO "%s", version));
+
+       /* The 82596-specific entries in the device structure. */
+       dev->netdev_ops = &i596_netdev_ops;
+       dev->watchdog_timeo = TX_TIMEOUT;
+
+       dev->ml_priv = (void *)(dev->mem_start);
+
+       lp = dev->ml_priv;
+       DEB(DEB_INIT,printk(KERN_DEBUG "%s: lp at 0x%08lx (%zd bytes), "
+                       "lp->scb at 0x%08lx\n",
+                       dev->name, (unsigned long)lp,
+                       sizeof(struct i596_private), (unsigned long)&lp->scb));
+       memset((void *) lp, 0, sizeof(struct i596_private));
+
+#ifdef __mc68000__
+       cache_push(virt_to_phys((void *)(dev->mem_start)), 4096);
+       cache_clear(virt_to_phys((void *)(dev->mem_start)), 4096);
+       kernel_set_cachemode((void *)(dev->mem_start), 4096, IOMAP_NOCACHE_SER);
+#endif
+       lp->scb.command = 0;
+       lp->scb.cmd = I596_NULL;
+       lp->scb.rfd = I596_NULL;
+       spin_lock_init(&lp->lock);
+
+       err = register_netdev(dev);
+       if (err)
+               goto out2;
+       return dev;
+out2:
+#ifdef __mc68000__
+       /* XXX This assumes default cache mode to be IOMAP_FULL_CACHING,
+        * XXX which may be invalid (CONFIG_060_WRITETHROUGH)
+        */
+       kernel_set_cachemode((void *)(dev->mem_start), 4096,
+                       IOMAP_FULL_CACHING);
+#endif
+       free_page ((u32)(dev->mem_start));
+out1:
+#ifdef ENABLE_APRICOT
+       release_region(dev->base_addr, I596_TOTAL_SIZE);
+#endif
+out:
+       free_netdev(dev);
+       return ERR_PTR(err);
+}
+
+static irqreturn_t i596_interrupt(int irq, void *dev_id)
+{
+       struct net_device *dev = dev_id;
+       struct i596_private *lp;
+       short ioaddr;
+       unsigned short status, ack_cmd = 0;
+       int handled = 0;
+
+#ifdef ENABLE_BVME6000_NET
+       if (MACH_IS_BVME6000) {
+               if (*(char *) BVME_LOCAL_IRQ_STAT & BVME_ETHERR) {
+                       i596_error(irq, dev_id);
+                       return IRQ_HANDLED;
+               }
+       }
+#endif
+       if (dev == NULL) {
+               printk(KERN_ERR "i596_interrupt(): irq %d for unknown device.\n", irq);
+               return IRQ_NONE;
+       }
+
+       ioaddr = dev->base_addr;
+       lp = dev->ml_priv;
+
+       spin_lock (&lp->lock);
+
+       wait_cmd(dev,lp,100,"i596 interrupt, timeout");
+       status = lp->scb.status;
+
+       DEB(DEB_INTS,printk(KERN_DEBUG "%s: i596 interrupt, IRQ %d, status %4.4x.\n",
+                       dev->name, irq, status));
+
+       ack_cmd = status & 0xf000;
+
+       if ((status & 0x8000) || (status & 0x2000)) {
+               struct i596_cmd *ptr;
+
+               handled = 1;
+               if ((status & 0x8000))
+                       DEB(DEB_INTS,printk(KERN_DEBUG "%s: i596 interrupt completed command.\n", dev->name));
+               if ((status & 0x2000))
+                       DEB(DEB_INTS,printk(KERN_DEBUG "%s: i596 interrupt command unit inactive %x.\n", dev->name, status & 0x0700));
+
+               while ((lp->cmd_head != I596_NULL) && (lp->cmd_head->status & STAT_C)) {
+                       ptr = lp->cmd_head;
+
+                       DEB(DEB_STATUS,printk(KERN_DEBUG "cmd_head->status = %04x, ->command = %04x\n",
+                                      lp->cmd_head->status, lp->cmd_head->command));
+                       lp->cmd_head = ptr->v_next;
+                       lp->cmd_backlog--;
+
+                       switch ((ptr->command) & 0x7) {
+                       case CmdTx:
+                           {
+                               struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr;
+                               struct sk_buff *skb = tx_cmd->skb;
+
+                               if ((ptr->status) & STAT_OK) {
+                                       DEB(DEB_TXADDR,print_eth(skb->data, "tx-done"));
+                               } else {
+                                       dev->stats.tx_errors++;
+                                       if ((ptr->status) & 0x0020)
+                                               dev->stats.collisions++;
+                                       if (!((ptr->status) & 0x0040))
+                                               dev->stats.tx_heartbeat_errors++;
+                                       if ((ptr->status) & 0x0400)
+                                               dev->stats.tx_carrier_errors++;
+                                       if ((ptr->status) & 0x0800)
+                                               dev->stats.collisions++;
+                                       if ((ptr->status) & 0x1000)
+                                               dev->stats.tx_aborted_errors++;
+                               }
+
+                               dev_kfree_skb_irq(skb);
+
+                               tx_cmd->cmd.command = 0; /* Mark free */
+                               break;
+                           }
+                       case CmdTDR:
+                           {
+                               unsigned short status = ((struct tdr_cmd *)ptr)->status;
+
+                               if (status & 0x8000) {
+                                       DEB(DEB_TDR,printk(KERN_INFO "%s: link ok.\n", dev->name));
+                               } else {
+                                       if (status & 0x4000)
+                                               printk(KERN_ERR "%s: Transceiver problem.\n", dev->name);
+                                       if (status & 0x2000)
+                                               printk(KERN_ERR "%s: Termination problem.\n", dev->name);
+                                       if (status & 0x1000)
+                                               printk(KERN_ERR "%s: Short circuit.\n", dev->name);
+
+                                       DEB(DEB_TDR,printk(KERN_INFO "%s: Time %d.\n", dev->name, status & 0x07ff));
+                               }
+                               break;
+                           }
+                       case CmdConfigure:
+                       case CmdMulticastList:
+                               /* Zap command so set_multicast_list() knows it is free */
+                               ptr->command = 0;
+                               break;
+                       }
+                       ptr->v_next = ptr->b_next = I596_NULL;
+                       lp->last_cmd = jiffies;
+               }
+
+               ptr = lp->cmd_head;
+               while ((ptr != I596_NULL) && (ptr != lp->cmd_tail)) {
+                       ptr->command &= 0x1fff;
+                       ptr = ptr->v_next;
+               }
+
+               if ((lp->cmd_head != I596_NULL))
+                       ack_cmd |= CUC_START;
+               lp->scb.cmd = WSWAPcmd(virt_to_bus(&lp->cmd_head->status));
+       }
+       if ((status & 0x1000) || (status & 0x4000)) {
+               if ((status & 0x4000))
+                       DEB(DEB_INTS,printk(KERN_DEBUG "%s: i596 interrupt received a frame.\n", dev->name));
+               i596_rx(dev);
+               /* Only RX_START if stopped - RGH 07-07-96 */
+               if (status & 0x1000) {
+                       if (netif_running(dev)) {
+                               DEB(DEB_ERRORS,printk(KERN_ERR "%s: i596 interrupt receive unit inactive, status 0x%x\n", dev->name, status));
+                               ack_cmd |= RX_START;
+                               dev->stats.rx_errors++;
+                               dev->stats.rx_fifo_errors++;
+                               rebuild_rx_bufs(dev);
+                       }
+               }
+       }
+       wait_cmd(dev,lp,100,"i596 interrupt, timeout");
+       lp->scb.command = ack_cmd;
+
+#ifdef ENABLE_MVME16x_NET
+       if (MACH_IS_MVME16x) {
+               /* Ack the interrupt */
+
+               volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000;
+
+               pcc2[0x2a] |= 0x08;
+       }
+#endif
+#ifdef ENABLE_BVME6000_NET
+       if (MACH_IS_BVME6000) {
+               volatile unsigned char *ethirq = (unsigned char *) BVME_ETHIRQ_REG;
+
+               *ethirq = 1;
+               *ethirq = 3;
+       }
+#endif
+#ifdef ENABLE_APRICOT
+       (void) inb(ioaddr + 0x10);
+       outb(4, ioaddr + 0xf);
+#endif
+       CA(dev);
+
+       DEB(DEB_INTS,printk(KERN_DEBUG "%s: exiting interrupt.\n", dev->name));
+
+       spin_unlock (&lp->lock);
+       return IRQ_RETVAL(handled);
+}
+
+static int i596_close(struct net_device *dev)
+{
+       struct i596_private *lp = dev->ml_priv;
+       unsigned long flags;
+
+       netif_stop_queue(dev);
+
+       DEB(DEB_INIT,printk(KERN_DEBUG "%s: Shutting down ethercard, status was %4.4x.\n",
+                      dev->name, lp->scb.status));
+
+       spin_lock_irqsave(&lp->lock, flags);
+
+       wait_cmd(dev,lp,100,"close1 timed out");
+       lp->scb.command = CUC_ABORT | RX_ABORT;
+       CA(dev);
+
+       wait_cmd(dev,lp,100,"close2 timed out");
+
+       spin_unlock_irqrestore(&lp->lock, flags);
+       DEB(DEB_STRUCT,i596_display_data(dev));
+       i596_cleanup_cmd(dev,lp);
+
+#ifdef ENABLE_MVME16x_NET
+       if (MACH_IS_MVME16x) {
+               volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000;
+
+               /* Disable all ints */
+               pcc2[0x28] = 1;
+               pcc2[0x2a] = 0x40;
+               pcc2[0x2b] = 0x40;      /* Set snooping bits now! */
+       }
+#endif
+#ifdef ENABLE_BVME6000_NET
+       if (MACH_IS_BVME6000) {
+               volatile unsigned char *ethirq = (unsigned char *) BVME_ETHIRQ_REG;
+
+               *ethirq = 1;
+       }
+#endif
+
+#ifdef ENABLE_MVME16x_NET
+       free_irq(0x56, dev);
+#endif
+       free_irq(dev->irq, dev);
+       remove_rx_bufs(dev);
+
+       return 0;
+}
+
+/*
+ *    Set or clear the multicast filter for this adaptor.
+ */
+
+static void set_multicast_list(struct net_device *dev)
+{
+       struct i596_private *lp = dev->ml_priv;
+       int config = 0, cnt;
+
+       DEB(DEB_MULTI,printk(KERN_DEBUG "%s: set multicast list, %d entries, promisc %s, allmulti %s\n",
+               dev->name, netdev_mc_count(dev),
+               dev->flags & IFF_PROMISC  ? "ON" : "OFF",
+               dev->flags & IFF_ALLMULTI ? "ON" : "OFF"));
+
+       if (wait_cfg(dev, &lp->cf_cmd.cmd, 1000, "config change request timed out"))
+               return;
+
+       if ((dev->flags & IFF_PROMISC) && !(lp->cf_cmd.i596_config[8] & 0x01)) {
+               lp->cf_cmd.i596_config[8] |= 0x01;
+               config = 1;
+       }
+       if (!(dev->flags & IFF_PROMISC) && (lp->cf_cmd.i596_config[8] & 0x01)) {
+               lp->cf_cmd.i596_config[8] &= ~0x01;
+               config = 1;
+       }
+       if ((dev->flags & IFF_ALLMULTI) && (lp->cf_cmd.i596_config[11] & 0x20)) {
+               lp->cf_cmd.i596_config[11] &= ~0x20;
+               config = 1;
+       }
+       if (!(dev->flags & IFF_ALLMULTI) && !(lp->cf_cmd.i596_config[11] & 0x20)) {
+               lp->cf_cmd.i596_config[11] |= 0x20;
+               config = 1;
+       }
+       if (config) {
+               lp->cf_cmd.cmd.command = CmdConfigure;
+               i596_add_cmd(dev, &lp->cf_cmd.cmd);
+       }
+
+       cnt = netdev_mc_count(dev);
+       if (cnt > MAX_MC_CNT)
+       {
+               cnt = MAX_MC_CNT;
+               printk(KERN_ERR "%s: Only %d multicast addresses supported",
+                       dev->name, cnt);
+       }
+
+       if (!netdev_mc_empty(dev)) {
+               struct netdev_hw_addr *ha;
+               unsigned char *cp;
+               struct mc_cmd *cmd;
+
+               if (wait_cfg(dev, &lp->mc_cmd.cmd, 1000, "multicast list change request timed out"))
+                       return;
+               cmd = &lp->mc_cmd;
+               cmd->cmd.command = CmdMulticastList;
+               cmd->mc_cnt = cnt * ETH_ALEN;
+               cp = cmd->mc_addrs;
+               netdev_for_each_mc_addr(ha, dev) {
+                       if (!cnt--)
+                               break;
+                       memcpy(cp, ha->addr, ETH_ALEN);
+                       if (i596_debug > 1)
+                               DEB(DEB_MULTI,printk(KERN_INFO "%s: Adding address %pM\n",
+                                               dev->name, cp));
+                       cp += ETH_ALEN;
+               }
+               i596_add_cmd(dev, &cmd->cmd);
+       }
+}
+
+#ifdef MODULE
+static struct net_device *dev_82596;
+
+#ifdef ENABLE_APRICOT
+module_param(irq, int, 0);
+MODULE_PARM_DESC(irq, "Apricot IRQ number");
+#endif
+
+static int debug = -1;
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "i82596 debug mask");
+
+int __init init_module(void)
+{
+       if (debug >= 0)
+               i596_debug = debug;
+       dev_82596 = i82596_probe(-1);
+       if (IS_ERR(dev_82596))
+               return PTR_ERR(dev_82596);
+       return 0;
+}
+
+void __exit cleanup_module(void)
+{
+       unregister_netdev(dev_82596);
+#ifdef __mc68000__
+       /* XXX This assumes default cache mode to be IOMAP_FULL_CACHING,
+        * XXX which may be invalid (CONFIG_060_WRITETHROUGH)
+        */
+
+       kernel_set_cachemode((void *)(dev_82596->mem_start), 4096,
+                       IOMAP_FULL_CACHING);
+#endif
+       free_page ((u32)(dev_82596->mem_start));
+#ifdef ENABLE_APRICOT
+       /* If we don't do this, we can't re-insmod it later. */
+       release_region(dev_82596->base_addr, I596_TOTAL_SIZE);
+#endif
+       free_netdev(dev_82596);
+}
+
+#endif                         /* MODULE */
diff --git a/drivers/net/ethernet/i825xx/Kconfig b/drivers/net/ethernet/i825xx/Kconfig
new file mode 100644 (file)
index 0000000..5c30a5b
--- /dev/null
@@ -0,0 +1,182 @@
+#
+# Intel 82596/82593/82596 network device configuration
+#
+
+config NET_VENDOR_I825XX
+       bool "Intel (82586/82593/82596) devices"
+       depends on NET_VENDOR_INTEL && (ISA || ISA_DMA_API || ARM || \
+                  ARCH_ACORN || MCA || MCA_LEGACY || SNI_RM || SUN3 || \
+                  GSC || BVME6000 || MVME16x || EXPERIMENTAL)
+       ---help---
+         If you have a network (Ethernet) card belonging to this class, say Y
+         and read the Ethernet-HOWTO, available from
+         <http://www.tldp.org/docs.html#howto>.
+
+         Note that the answer to this question does not directly affect the
+         kernel: saying N will just cause the configurator to skip all
+         the questions about these devices. If you say Y, you will be asked for
+         your specific card in the following questions.
+
+if NET_VENDOR_I825XX
+
+config ELPLUS
+       tristate "3c505 \"EtherLink Plus\" support"
+       depends on ISA && ISA_DMA_API
+       ---help---
+         Information about this network (Ethernet) card can be found in
+         <file:Documentation/networking/3c505.txt>.  If you have a card of
+         this type, say Y and read the Ethernet-HOWTO, available from
+         <http://www.tldp.org/docs.html#howto>.
+
+         To compile this driver as a module, choose M here. The module
+         will be called 3c505.
+
+config EL16
+       tristate "3c507 \"EtherLink 16\" support (EXPERIMENTAL)"
+       depends on ISA && EXPERIMENTAL
+       ---help---
+         If you have a network (Ethernet) card of this type, say Y and read
+         the Ethernet-HOWTO, available from
+         <http://www.tldp.org/docs.html#howto>.
+
+         To compile this driver as a module, choose M here. The module
+         will be called 3c507.
+
+config ELMC
+       tristate "3c523 \"EtherLink/MC\" support"
+       depends on MCA_LEGACY
+       ---help---
+         If you have a network (Ethernet) card of this type, say Y and read
+         the Ethernet-HOWTO, available from
+         <http://www.tldp.org/docs.html#howto>.
+
+         To compile this driver as a module, choose M here. The module
+         will be called 3c523.
+
+config ELMC_II
+       tristate "3c527 \"EtherLink/MC 32\" support (EXPERIMENTAL)"
+       depends on MCA && MCA_LEGACY
+       ---help---
+         If you have a network (Ethernet) card of this type, say Y and read
+         the Ethernet-HOWTO, available from
+         <http://www.tldp.org/docs.html#howto>.
+
+         To compile this driver as a module, choose M here. The module
+         will be called 3c527.
+
+config ARM_ETHER1
+       tristate "Acorn Ether1 support"
+       depends on ARM && ARCH_ACORN
+       ---help---
+         If you have an Acorn system with one of these (AKA25) network cards,
+         you should say Y to this option if you wish to use it with Linux.
+
+config APRICOT
+       tristate "Apricot Xen-II on board Ethernet"
+       depends on ISA
+       ---help---
+         If you have a network (Ethernet) controller of this type, say Y and
+         read the Ethernet-HOWTO, available from
+         <http://www.tldp.org/docs.html#howto>.
+
+         To compile this driver as a module, choose M here. The module
+         will be called apricot.
+
+config BVME6000_NET
+       tristate "BVME6000 Ethernet support"
+       depends on BVME6000MVME16x
+       ---help---
+         This is the driver for the Ethernet interface on BVME4000 and
+         BVME6000 VME boards.  Say Y here to include the driver for this chip
+         in your kernel.
+         To compile this driver as a module, choose M here.
+
+config EEXPRESS
+       tristate "EtherExpress 16 support"
+       depends on ISA
+       ---help---
+         If you have an EtherExpress16 network (Ethernet) card, say Y and
+         read the Ethernet-HOWTO, available from
+         <http://www.tldp.org/docs.html#howto>.  Note that the Intel
+         EtherExpress16 card used to be regarded as a very poor choice
+         because the driver was very unreliable. We now have a new driver
+         that should do better.
+
+         To compile this driver as a module, choose M here. The module
+         will be called eexpress.
+
+config EEXPRESS_PRO
+       tristate "EtherExpressPro support/EtherExpress 10 (i82595) support"
+       depends on ISA
+       ---help---
+         If you have a network (Ethernet) card of this type, say Y. This
+         driver supports Intel i82595{FX,TX} based boards. Note however
+         that the EtherExpress PRO/100 Ethernet card has its own separate
+         driver.  Please read the Ethernet-HOWTO, available from
+         <http://www.tldp.org/docs.html#howto>.
+
+         To compile this driver as a module, choose M here. The module
+         will be called eepro.
+
+config LASI_82596
+       tristate "Lasi ethernet"
+       depends on GSC
+       ---help---
+         Say Y here to support the builtin Intel 82596 ethernet controller
+         found in Hewlett-Packard PA-RISC machines with 10Mbit ethernet.
+
+config LP486E
+       tristate "LP486E on board Ethernet"
+       depends on ISA
+       ---help---
+         Say Y here to support the 82596-based on-board Ethernet controller
+         for the Panther motherboard, which is one of the two shipped in the
+         Intel Professional Workstation.
+
+config MVME16x_NET
+       tristate "MVME16x Ethernet support"
+       depends on MVME16x
+       ---help---
+         This is the driver for the Ethernet interface on the Motorola
+         MVME162, 166, 167, 172 and 177 boards.  Say Y here to include the
+         driver for this chip in your kernel.
+         To compile this driver as a module, choose M here.
+
+config NI52
+       tristate "NI5210 support"
+       depends on ISA
+       ---help---
+         If you have a network (Ethernet) card of this type, say Y and read
+         the Ethernet-HOWTO, available from
+         <http://www.tldp.org/docs.html#howto>.
+
+         To compile this driver as a module, choose M here. The module
+         will be called ni52.
+
+config SNI_82596
+       tristate "SNI RM ethernet"
+       depends on SNI_RM
+       ---help---
+         Say Y here to support the on-board Intel 82596 ethernet controller
+         built into SNI RM machines.
+
+config SUN3_82586
+       bool "Sun3 on-board Intel 82586 support"
+       depends on SUN3
+       ---help---
+         This driver enables support for the on-board Intel 82586 based
+         Ethernet adapter found on Sun 3/1xx and 3/2xx motherboards.  Note
+         that this driver does not support 82586-based adapters on additional
+         VME boards.
+
+config ZNET
+       tristate "Zenith Z-Note support (EXPERIMENTAL)"
+       depends on EXPERIMENTAL && ISA_DMA_API
+       ---help---
+         The Zenith Z-Note notebook computer has a built-in network
+         (Ethernet) card, and this is the Linux driver for it. Note that the
+         IBM Thinkpad 300 is compatible with the Z-Note and is also supported
+         by this driver. Read the Ethernet-HOWTO, available from
+         <http://www.tldp.org/docs.html#howto>.
+
+endif # NET_VENDOR_I825XX
diff --git a/drivers/net/ethernet/i825xx/Makefile b/drivers/net/ethernet/i825xx/Makefile
new file mode 100644 (file)
index 0000000..f68a369
--- /dev/null
@@ -0,0 +1,20 @@
+#
+# Makefile for the Intel 82586/82593/82596 chipset device drivers.
+#
+
+obj-$(CONFIG_ARM_ETHER1) += ether1.o
+obj-$(CONFIG_EEXPRESS) += eexpress.o
+obj-$(CONFIG_EEXPRESS_PRO) += eepro.o
+obj-$(CONFIG_ELPLUS) += 3c505.o
+obj-$(CONFIG_EL16) += 3c507.o
+obj-$(CONFIG_ELMC) += 3c523.o
+obj-$(CONFIG_ELMC_II) += 3c527.o
+obj-$(CONFIG_LP486E) += lp486e.o
+obj-$(CONFIG_NI52) += ni52.o
+obj-$(CONFIG_SUN3_82586) += sun3_82586.o
+obj-$(CONFIG_ZNET) += znet.o
+obj-$(CONFIG_APRICOT) += 82596.o
+obj-$(CONFIG_LASI_82596) += lasi_82596.o
+obj-$(CONFIG_SNI_82596) += sni_82596.o
+obj-$(CONFIG_MVME16x_NET) += 82596.o
+obj-$(CONFIG_BVME6000_NET) += 82596.o
diff --git a/drivers/net/ethernet/i825xx/eepro.c b/drivers/net/ethernet/i825xx/eepro.c
new file mode 100644 (file)
index 0000000..dfeb006
--- /dev/null
@@ -0,0 +1,1822 @@
+/* eepro.c: Intel EtherExpress Pro/10 device driver for Linux. */
+/*
+       Written 1994, 1995,1996 by Bao C. Ha.
+
+       Copyright (C) 1994, 1995,1996 by Bao C. Ha.
+
+       This software may be used and distributed
+       according to the terms of the GNU General Public License,
+       incorporated herein by reference.
+
+       The author may be reached at bao.ha@srs.gov
+       or 418 Hastings Place, Martinez, GA 30907.
+
+       Things remaining to do:
+       Better record keeping of errors.
+       Eliminate transmit interrupt to reduce overhead.
+       Implement "concurrent processing". I won't be doing it!
+
+       Bugs:
+
+       If you have a problem of not detecting the 82595 during a
+       reboot (warm reset), disable the FLASH memory should fix it.
+       This is a compatibility hardware problem.
+
+       Versions:
+       0.13b   basic ethtool support (aris, 09/13/2004)
+       0.13a   in memory shortage, drop packets also in board
+               (Michael Westermann <mw@microdata-pos.de>, 07/30/2002)
+       0.13    irq sharing, rewrote probe function, fixed a nasty bug in
+               hardware_send_packet and a major cleanup (aris, 11/08/2001)
+       0.12d   fixing a problem with single card detected as eight eth devices
+               fixing a problem with sudden drop in card performance
+               (chris (asdn@go2.pl), 10/29/2001)
+       0.12c   fixing some problems with old cards (aris, 01/08/2001)
+       0.12b   misc fixes (aris, 06/26/2000)
+       0.12a   port of version 0.12a of 2.2.x kernels to 2.3.x
+               (aris (aris@conectiva.com.br), 05/19/2000)
+       0.11e   some tweaks about multiple cards support (PdP, jul/aug 1999)
+       0.11d   added __initdata, __init stuff; call spin_lock_init
+               in eepro_probe1. Replaced "eepro" by dev->name. Augmented
+               the code protected by spin_lock in interrupt routine
+               (PdP, 12/12/1998)
+       0.11c   minor cleanup (PdP, RMC, 09/12/1998)
+       0.11b   Pascal Dupuis (dupuis@lei.ucl.ac.be): works as a module
+               under 2.1.xx. Debug messages are flagged as KERN_DEBUG to
+               avoid console flooding. Added locking at critical parts. Now
+               the dawn thing is SMP safe.
+       0.11a   Attempt to get 2.1.xx support up (RMC)
+       0.11    Brian Candler added support for multiple cards. Tested as
+               a module, no idea if it works when compiled into kernel.
+
+       0.10e   Rick Bressler notified me that ifconfig up;ifconfig down fails
+               because the irq is lost somewhere. Fixed that by moving
+               request_irq and free_irq to eepro_open and eepro_close respectively.
+       0.10d   Ugh! Now Wakeup works. Was seriously broken in my first attempt.
+               I'll need to find a way to specify an ioport other than
+               the default one in the PnP case. PnP definitively sucks.
+               And, yes, this is not the only reason.
+       0.10c   PnP Wakeup Test for 595FX. uncomment #define PnPWakeup;
+               to use.
+       0.10b   Should work now with (some) Pro/10+. At least for
+               me (and my two cards) it does. _No_ guarantee for
+               function with non-Pro/10+ cards! (don't have any)
+               (RMC, 9/11/96)
+
+       0.10    Added support for the Etherexpress Pro/10+.  The
+               IRQ map was changed significantly from the old
+               pro/10.  The new interrupt map was provided by
+               Rainer M. Canavan (Canavan@Zeus.cs.bonn.edu).
+               (BCH, 9/3/96)
+
+       0.09    Fixed a race condition in the transmit algorithm,
+               which causes crashes under heavy load with fast
+               pentium computers.  The performance should also
+               improve a bit.  The size of RX buffer, and hence
+               TX buffer, can also be changed via lilo or insmod.
+               (BCH, 7/31/96)
+
+       0.08    Implement 32-bit I/O for the 82595TX and 82595FX
+               based lan cards.  Disable full-duplex mode if TPE
+               is not used.  (BCH, 4/8/96)
+
+       0.07a   Fix a stat report which counts every packet as a
+               heart-beat failure. (BCH, 6/3/95)
+
+       0.07    Modified to support all other 82595-based lan cards.
+               The IRQ vector of the EtherExpress Pro will be set
+               according to the value saved in the EEPROM.  For other
+               cards, I will do autoirq_request() to grab the next
+               available interrupt vector. (BCH, 3/17/95)
+
+       0.06a,b Interim released.  Minor changes in the comments and
+               print out format. (BCH, 3/9/95 and 3/14/95)
+
+       0.06    First stable release that I am comfortable with. (BCH,
+               3/2/95)
+
+       0.05    Complete testing of multicast. (BCH, 2/23/95)
+
+       0.04    Adding multicast support. (BCH, 2/14/95)
+
+       0.03    First widely alpha release for public testing.
+               (BCH, 2/14/95)
+
+*/
+
+static const char version[] =
+       "eepro.c: v0.13b 09/13/2004 aris@cathedrallabs.org\n";
+
+#include <linux/module.h>
+
+/*
+  Sources:
+
+       This driver wouldn't have been written without the availability
+       of the Crynwr's Lan595 driver source code.  It helps me to
+       familiarize with the 82595 chipset while waiting for the Intel
+       documentation.  I also learned how to detect the 82595 using
+       the packet driver's technique.
+
+       This driver is written by cutting and pasting the skeleton.c driver
+       provided by Donald Becker.  I also borrowed the EEPROM routine from
+       Donald Becker's 82586 driver.
+
+       Datasheet for the Intel 82595 (including the TX and FX version). It
+       provides just enough info that the casual reader might think that it
+       documents the i82595.
+
+       The User Manual for the 82595.  It provides a lot of the missing
+       information.
+
+*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+#include <linux/ethtool.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#define DRV_NAME "eepro"
+#define DRV_VERSION "0.13c"
+
+#define compat_dev_kfree_skb( skb, mode ) dev_kfree_skb( (skb) )
+/* I had reports of looong delays with SLOW_DOWN defined as udelay(2) */
+#define SLOW_DOWN inb(0x80)
+/* udelay(2) */
+#define compat_init_data     __initdata
+enum iftype { AUI=0, BNC=1, TPE=2 };
+
+/* First, a few definitions that the brave might change. */
+/* A zero-terminated list of I/O addresses to be probed. */
+static unsigned int eepro_portlist[] compat_init_data =
+   { 0x300, 0x210, 0x240, 0x280, 0x2C0, 0x200, 0x320, 0x340, 0x360, 0};
+/* note: 0x300 is default, the 595FX supports ALL IO Ports
+  from 0x000 to 0x3F0, some of which are reserved in PCs */
+
+/* To try the (not-really PnP Wakeup: */
+/*
+#define PnPWakeup
+*/
+
+/* use 0 for production, 1 for verification, >2 for debug */
+#ifndef NET_DEBUG
+#define NET_DEBUG 0
+#endif
+static unsigned int net_debug = NET_DEBUG;
+
+/* The number of low I/O ports used by the ethercard. */
+#define EEPRO_IO_EXTENT        16
+
+/* Different 82595 chips */
+#define        LAN595          0
+#define        LAN595TX        1
+#define        LAN595FX        2
+#define        LAN595FX_10ISA  3
+
+/* Information that need to be kept for each board. */
+struct eepro_local {
+       unsigned rx_start;
+       unsigned tx_start; /* start of the transmit chain */
+       int tx_last;  /* pointer to last packet in the transmit chain */
+       unsigned tx_end;   /* end of the transmit chain (plus 1) */
+       int eepro;      /* 1 for the EtherExpress Pro/10,
+                          2 for the EtherExpress Pro/10+,
+                          3 for the EtherExpress 10 (blue cards),
+                          0 for other 82595-based lan cards. */
+       int version;    /* a flag to indicate if this is a TX or FX
+                                  version of the 82595 chip. */
+       int stepping;
+
+       spinlock_t lock; /* Serializing lock  */
+
+       unsigned rcv_ram;       /* pre-calculated space for rx */
+       unsigned xmt_ram;       /* pre-calculated space for tx */
+       unsigned char xmt_bar;
+       unsigned char xmt_lower_limit_reg;
+       unsigned char xmt_upper_limit_reg;
+       short xmt_lower_limit;
+       short xmt_upper_limit;
+       short rcv_lower_limit;
+       short rcv_upper_limit;
+       unsigned char eeprom_reg;
+       unsigned short word[8];
+};
+
+/* The station (ethernet) address prefix, used for IDing the board. */
+#define SA_ADDR0 0x00  /* Etherexpress Pro/10 */
+#define SA_ADDR1 0xaa
+#define SA_ADDR2 0x00
+
+#define GetBit(x,y) ((x & (1<<y))>>y)
+
+/* EEPROM Word 0: */
+#define ee_PnP       0  /* Plug 'n Play enable bit */
+#define ee_Word1     1  /* Word 1? */
+#define ee_BusWidth  2  /* 8/16 bit */
+#define ee_FlashAddr 3  /* Flash Address */
+#define ee_FlashMask 0x7   /* Mask */
+#define ee_AutoIO    6  /* */
+#define ee_reserved0 7  /* =0! */
+#define ee_Flash     8  /* Flash there? */
+#define ee_AutoNeg   9  /* Auto Negotiation enabled? */
+#define ee_IO0       10 /* IO Address LSB */
+#define ee_IO0Mask   0x /*...*/
+#define ee_IO1       15 /* IO MSB */
+
+/* EEPROM Word 1: */
+#define ee_IntSel    0   /* Interrupt */
+#define ee_IntMask   0x7
+#define ee_LI        3   /* Link Integrity 0= enabled */
+#define ee_PC        4   /* Polarity Correction 0= enabled */
+#define ee_TPE_AUI   5   /* PortSelection 1=TPE */
+#define ee_Jabber    6   /* Jabber prevention 0= enabled */
+#define ee_AutoPort  7   /* Auto Port Selection 1= Disabled */
+#define ee_SMOUT     8   /* SMout Pin Control 0= Input */
+#define ee_PROM      9   /* Flash EPROM / PROM 0=Flash */
+#define ee_reserved1 10  /* .. 12 =0! */
+#define ee_AltReady  13  /* Alternate Ready, 0=normal */
+#define ee_reserved2 14  /* =0! */
+#define ee_Duplex    15
+
+/* Word2,3,4: */
+#define ee_IA5       0 /*bit start for individual Addr Byte 5 */
+#define ee_IA4       8 /*bit start for individual Addr Byte 5 */
+#define ee_IA3       0 /*bit start for individual Addr Byte 5 */
+#define ee_IA2       8 /*bit start for individual Addr Byte 5 */
+#define ee_IA1       0 /*bit start for individual Addr Byte 5 */
+#define ee_IA0       8 /*bit start for individual Addr Byte 5 */
+
+/* Word 5: */
+#define ee_BNC_TPE   0 /* 0=TPE */
+#define ee_BootType  1 /* 00=None, 01=IPX, 10=ODI, 11=NDIS */
+#define ee_BootTypeMask 0x3
+#define ee_NumConn   3  /* Number of Connections 0= One or Two */
+#define ee_FlashSock 4  /* Presence of Flash Socket 0= Present */
+#define ee_PortTPE   5
+#define ee_PortBNC   6
+#define ee_PortAUI   7
+#define ee_PowerMgt  10 /* 0= disabled */
+#define ee_CP        13 /* Concurrent Processing */
+#define ee_CPMask    0x7
+
+/* Word 6: */
+#define ee_Stepping  0 /* Stepping info */
+#define ee_StepMask  0x0F
+#define ee_BoardID   4 /* Manucaturer Board ID, reserved */
+#define ee_BoardMask 0x0FFF
+
+/* Word 7: */
+#define ee_INT_TO_IRQ 0 /* int to IRQ Mapping  = 0x1EB8 for Pro/10+ */
+#define ee_FX_INT2IRQ 0x1EB8 /* the _only_ mapping allowed for FX chips */
+
+/*..*/
+#define ee_SIZE 0x40 /* total EEprom Size */
+#define ee_Checksum 0xBABA /* initial and final value for adding checksum */
+
+
+/* Card identification via EEprom:   */
+#define ee_addr_vendor 0x10  /* Word offset for EISA Vendor ID */
+#define ee_addr_id 0x11      /* Word offset for Card ID */
+#define ee_addr_SN 0x12      /* Serial Number */
+#define ee_addr_CRC_8 0x14   /* CRC over last thee Bytes */
+
+
+#define ee_vendor_intel0 0x25  /* Vendor ID Intel */
+#define ee_vendor_intel1 0xD4
+#define ee_id_eepro10p0 0x10   /* ID for eepro/10+ */
+#define ee_id_eepro10p1 0x31
+
+#define TX_TIMEOUT ((4*HZ)/10)
+
+/* Index to functions, as function prototypes. */
+
+static int     eepro_probe1(struct net_device *dev, int autoprobe);
+static int     eepro_open(struct net_device *dev);
+static netdev_tx_t eepro_send_packet(struct sk_buff *skb,
+                                    struct net_device *dev);
+static irqreturn_t eepro_interrupt(int irq, void *dev_id);
+static void    eepro_rx(struct net_device *dev);
+static void    eepro_transmit_interrupt(struct net_device *dev);
+static int     eepro_close(struct net_device *dev);
+static void     set_multicast_list(struct net_device *dev);
+static void     eepro_tx_timeout (struct net_device *dev);
+
+static int read_eeprom(int ioaddr, int location, struct net_device *dev);
+static int     hardware_send_packet(struct net_device *dev, void *buf, short length);
+static int     eepro_grab_irq(struct net_device *dev);
+
+/*
+                       Details of the i82595.
+
+You will need either the datasheet or the user manual to understand what
+is going on here.  The 82595 is very different from the 82586, 82593.
+
+The receive algorithm in eepro_rx() is just an implementation of the
+RCV ring structure that the Intel 82595 imposes at the hardware level.
+The receive buffer is set at 24K, and the transmit buffer is 8K.  I
+am assuming that the total buffer memory is 32K, which is true for the
+Intel EtherExpress Pro/10.  If it is less than that on a generic card,
+the driver will be broken.
+
+The transmit algorithm in the hardware_send_packet() is similar to the
+one in the eepro_rx().  The transmit buffer is a ring linked list.
+I just queue the next available packet to the end of the list.  In my
+system, the 82595 is so fast that the list seems to always contain a
+single packet.  In other systems with faster computers and more congested
+network traffics, the ring linked list should improve performance by
+allowing up to 8K worth of packets to be queued.
+
+The sizes of the receive and transmit buffers can now be changed via lilo
+or insmod.  Lilo uses the appended line "ether=io,irq,debug,rx-buffer,eth0"
+where rx-buffer is in KB unit.  Modules uses the parameter mem which is
+also in KB unit, for example "insmod io=io-address irq=0 mem=rx-buffer."
+The receive buffer has to be more than 3K or less than 29K.  Otherwise,
+it is reset to the default of 24K, and, hence, 8K for the trasnmit
+buffer (transmit-buffer = 32K - receive-buffer).
+
+*/
+#define RAM_SIZE        0x8000
+
+#define RCV_HEADER      8
+#define RCV_DEFAULT_RAM 0x6000
+
+#define XMT_HEADER      8
+#define XMT_DEFAULT_RAM        (RAM_SIZE - RCV_DEFAULT_RAM)
+
+#define XMT_START_PRO  RCV_DEFAULT_RAM
+#define XMT_START_10   0x0000
+#define RCV_START_PRO  0x0000
+#define RCV_START_10   XMT_DEFAULT_RAM
+
+#define        RCV_DONE        0x0008
+#define        RX_OK           0x2000
+#define        RX_ERROR        0x0d81
+
+#define        TX_DONE_BIT     0x0080
+#define        TX_OK           0x2000
+#define        CHAIN_BIT       0x8000
+#define        XMT_STATUS      0x02
+#define        XMT_CHAIN       0x04
+#define        XMT_COUNT       0x06
+
+#define        BANK0_SELECT    0x00
+#define        BANK1_SELECT    0x40
+#define        BANK2_SELECT    0x80
+
+/* Bank 0 registers */
+#define        COMMAND_REG     0x00    /* Register 0 */
+#define        MC_SETUP        0x03
+#define        XMT_CMD         0x04
+#define        DIAGNOSE_CMD    0x07
+#define        RCV_ENABLE_CMD  0x08
+#define        RCV_DISABLE_CMD 0x0a
+#define        STOP_RCV_CMD    0x0b
+#define        RESET_CMD       0x0e
+#define        POWER_DOWN_CMD  0x18
+#define        RESUME_XMT_CMD  0x1c
+#define        SEL_RESET_CMD   0x1e
+#define        STATUS_REG      0x01    /* Register 1 */
+#define        RX_INT          0x02
+#define        TX_INT          0x04
+#define        EXEC_STATUS     0x30
+#define        ID_REG          0x02    /* Register 2   */
+#define        R_ROBIN_BITS    0xc0    /* round robin counter */
+#define        ID_REG_MASK     0x2c
+#define        ID_REG_SIG      0x24
+#define        AUTO_ENABLE     0x10
+#define        INT_MASK_REG    0x03    /* Register 3   */
+#define        RX_STOP_MASK    0x01
+#define        RX_MASK         0x02
+#define        TX_MASK         0x04
+#define        EXEC_MASK       0x08
+#define        ALL_MASK        0x0f
+#define        IO_32_BIT       0x10
+#define        RCV_BAR         0x04    /* The following are word (16-bit) registers */
+#define        RCV_STOP        0x06
+
+#define        XMT_BAR_PRO     0x0a
+#define        XMT_BAR_10      0x0b
+
+#define        HOST_ADDRESS_REG        0x0c
+#define        IO_PORT         0x0e
+#define        IO_PORT_32_BIT  0x0c
+
+/* Bank 1 registers */
+#define        REG1    0x01
+#define        WORD_WIDTH      0x02
+#define        INT_ENABLE      0x80
+#define INT_NO_REG     0x02
+#define        RCV_LOWER_LIMIT_REG     0x08
+#define        RCV_UPPER_LIMIT_REG     0x09
+
+#define        XMT_LOWER_LIMIT_REG_PRO 0x0a
+#define        XMT_UPPER_LIMIT_REG_PRO 0x0b
+#define        XMT_LOWER_LIMIT_REG_10  0x0b
+#define        XMT_UPPER_LIMIT_REG_10  0x0a
+
+/* Bank 2 registers */
+#define        XMT_Chain_Int   0x20    /* Interrupt at the end of the transmit chain */
+#define        XMT_Chain_ErrStop       0x40 /* Interrupt at the end of the chain even if there are errors */
+#define        RCV_Discard_BadFrame    0x80 /* Throw bad frames away, and continue to receive others */
+#define        REG2            0x02
+#define        PRMSC_Mode      0x01
+#define        Multi_IA        0x20
+#define        REG3            0x03
+#define        TPE_BIT         0x04
+#define        BNC_BIT         0x20
+#define        REG13           0x0d
+#define        FDX             0x00
+#define        A_N_ENABLE      0x02
+
+#define        I_ADD_REG0      0x04
+#define        I_ADD_REG1      0x05
+#define        I_ADD_REG2      0x06
+#define        I_ADD_REG3      0x07
+#define        I_ADD_REG4      0x08
+#define        I_ADD_REG5      0x09
+
+#define        EEPROM_REG_PRO 0x0a
+#define        EEPROM_REG_10  0x0b
+
+#define EESK 0x01
+#define EECS 0x02
+#define EEDI 0x04
+#define EEDO 0x08
+
+/* do a full reset */
+#define eepro_reset(ioaddr) outb(RESET_CMD, ioaddr)
+
+/* do a nice reset */
+#define eepro_sel_reset(ioaddr)        { \
+                                       outb(SEL_RESET_CMD, ioaddr); \
+                                       SLOW_DOWN; \
+                                       SLOW_DOWN; \
+                                       }
+
+/* disable all interrupts */
+#define eepro_dis_int(ioaddr) outb(ALL_MASK, ioaddr + INT_MASK_REG)
+
+/* clear all interrupts */
+#define eepro_clear_int(ioaddr) outb(ALL_MASK, ioaddr + STATUS_REG)
+
+/* enable tx/rx */
+#define eepro_en_int(ioaddr) outb(ALL_MASK & ~(RX_MASK | TX_MASK), \
+                                                       ioaddr + INT_MASK_REG)
+
+/* enable exec event interrupt */
+#define eepro_en_intexec(ioaddr) outb(ALL_MASK & ~(EXEC_MASK), ioaddr + INT_MASK_REG)
+
+/* enable rx */
+#define eepro_en_rx(ioaddr) outb(RCV_ENABLE_CMD, ioaddr)
+
+/* disable rx */
+#define eepro_dis_rx(ioaddr) outb(RCV_DISABLE_CMD, ioaddr)
+
+/* switch bank */
+#define eepro_sw2bank0(ioaddr) outb(BANK0_SELECT, ioaddr)
+#define eepro_sw2bank1(ioaddr) outb(BANK1_SELECT, ioaddr)
+#define eepro_sw2bank2(ioaddr) outb(BANK2_SELECT, ioaddr)
+
+/* enable interrupt line */
+#define eepro_en_intline(ioaddr) outb(inb(ioaddr + REG1) | INT_ENABLE,\
+                               ioaddr + REG1)
+
+/* disable interrupt line */
+#define eepro_dis_intline(ioaddr) outb(inb(ioaddr + REG1) & 0x7f, \
+                               ioaddr + REG1);
+
+/* set diagnose flag */
+#define eepro_diag(ioaddr) outb(DIAGNOSE_CMD, ioaddr)
+
+/* ack for rx int */
+#define eepro_ack_rx(ioaddr) outb (RX_INT, ioaddr + STATUS_REG)
+
+/* ack for tx int */
+#define eepro_ack_tx(ioaddr) outb (TX_INT, ioaddr + STATUS_REG)
+
+/* a complete sel reset */
+#define eepro_complete_selreset(ioaddr) { \
+                                               dev->stats.tx_errors++;\
+                                               eepro_sel_reset(ioaddr);\
+                                               lp->tx_end = \
+                                                       lp->xmt_lower_limit;\
+                                               lp->tx_start = lp->tx_end;\
+                                               lp->tx_last = 0;\
+                                               dev->trans_start = jiffies;\
+                                               netif_wake_queue(dev);\
+                                               eepro_en_rx(ioaddr);\
+                                       }
+
+/* Check for a network adaptor of this type, and return '0' if one exists.
+   If dev->base_addr == 0, probe all likely locations.
+   If dev->base_addr == 1, always return failure.
+   If dev->base_addr == 2, allocate space for the device and return success
+   (detachable devices only).
+   */
+static int __init do_eepro_probe(struct net_device *dev)
+{
+       int i;
+       int base_addr = dev->base_addr;
+       int irq = dev->irq;
+
+#ifdef PnPWakeup
+       /* XXXX for multiple cards should this only be run once? */
+
+       /* Wakeup: */
+       #define WakeupPort 0x279
+       #define WakeupSeq    {0x6A, 0xB5, 0xDA, 0xED, 0xF6, 0xFB, 0x7D, 0xBE,\
+                             0xDF, 0x6F, 0x37, 0x1B, 0x0D, 0x86, 0xC3, 0x61,\
+                             0xB0, 0x58, 0x2C, 0x16, 0x8B, 0x45, 0xA2, 0xD1,\
+                             0xE8, 0x74, 0x3A, 0x9D, 0xCE, 0xE7, 0x73, 0x43}
+
+       {
+               unsigned short int WS[32]=WakeupSeq;
+
+               if (request_region(WakeupPort, 2, "eepro wakeup")) {
+                       if (net_debug>5)
+                               printk(KERN_DEBUG "Waking UP\n");
+
+                       outb_p(0,WakeupPort);
+                       outb_p(0,WakeupPort);
+                       for (i=0; i<32; i++) {
+                               outb_p(WS[i],WakeupPort);
+                               if (net_debug>5) printk(KERN_DEBUG ": %#x ",WS[i]);
+                       }
+
+                       release_region(WakeupPort, 2);
+               } else
+                       printk(KERN_WARNING "PnP wakeup region busy!\n");
+       }
+#endif
+
+       if (base_addr > 0x1ff)          /* Check a single specified location. */
+               return eepro_probe1(dev, 0);
+
+       else if (base_addr != 0)        /* Don't probe at all. */
+               return -ENXIO;
+
+       for (i = 0; eepro_portlist[i]; i++) {
+               dev->base_addr = eepro_portlist[i];
+               dev->irq = irq;
+               if (eepro_probe1(dev, 1) == 0)
+                       return 0;
+       }
+
+       return -ENODEV;
+}
+
+#ifndef MODULE
+struct net_device * __init eepro_probe(int unit)
+{
+       struct net_device *dev = alloc_etherdev(sizeof(struct eepro_local));
+       int err;
+
+       if (!dev)
+               return ERR_PTR(-ENODEV);
+
+       sprintf(dev->name, "eth%d", unit);
+       netdev_boot_setup_check(dev);
+
+       err = do_eepro_probe(dev);
+       if (err)
+               goto out;
+       return dev;
+out:
+       free_netdev(dev);
+       return ERR_PTR(err);
+}
+#endif
+
+static void __init printEEPROMInfo(struct net_device *dev)
+{
+       struct eepro_local *lp = netdev_priv(dev);
+       int ioaddr = dev->base_addr;
+       unsigned short Word;
+       int i,j;
+
+       j = ee_Checksum;
+       for (i = 0; i < 8; i++)
+               j += lp->word[i];
+       for ( ; i < ee_SIZE; i++)
+               j += read_eeprom(ioaddr, i, dev);
+
+       printk(KERN_DEBUG "Checksum: %#x\n",j&0xffff);
+
+       Word = lp->word[0];
+       printk(KERN_DEBUG "Word0:\n");
+       printk(KERN_DEBUG " Plug 'n Pray: %d\n",GetBit(Word,ee_PnP));
+       printk(KERN_DEBUG " Buswidth: %d\n",(GetBit(Word,ee_BusWidth)+1)*8 );
+       printk(KERN_DEBUG " AutoNegotiation: %d\n",GetBit(Word,ee_AutoNeg));
+       printk(KERN_DEBUG " IO Address: %#x\n", (Word>>ee_IO0)<<4);
+
+       if (net_debug>4)  {
+               Word = lp->word[1];
+               printk(KERN_DEBUG "Word1:\n");
+               printk(KERN_DEBUG " INT: %d\n", Word & ee_IntMask);
+               printk(KERN_DEBUG " LI: %d\n", GetBit(Word,ee_LI));
+               printk(KERN_DEBUG " PC: %d\n", GetBit(Word,ee_PC));
+               printk(KERN_DEBUG " TPE/AUI: %d\n", GetBit(Word,ee_TPE_AUI));
+               printk(KERN_DEBUG " Jabber: %d\n", GetBit(Word,ee_Jabber));
+               printk(KERN_DEBUG " AutoPort: %d\n", !GetBit(Word,ee_AutoPort));
+               printk(KERN_DEBUG " Duplex: %d\n", GetBit(Word,ee_Duplex));
+       }
+
+       Word = lp->word[5];
+       printk(KERN_DEBUG "Word5:\n");
+       printk(KERN_DEBUG " BNC: %d\n",GetBit(Word,ee_BNC_TPE));
+       printk(KERN_DEBUG " NumConnectors: %d\n",GetBit(Word,ee_NumConn));
+       printk(KERN_DEBUG " Has ");
+       if (GetBit(Word,ee_PortTPE)) printk(KERN_DEBUG "TPE ");
+       if (GetBit(Word,ee_PortBNC)) printk(KERN_DEBUG "BNC ");
+       if (GetBit(Word,ee_PortAUI)) printk(KERN_DEBUG "AUI ");
+       printk(KERN_DEBUG "port(s)\n");
+
+       Word = lp->word[6];
+       printk(KERN_DEBUG "Word6:\n");
+       printk(KERN_DEBUG " Stepping: %d\n",Word & ee_StepMask);
+       printk(KERN_DEBUG " BoardID: %d\n",Word>>ee_BoardID);
+
+       Word = lp->word[7];
+       printk(KERN_DEBUG "Word7:\n");
+       printk(KERN_DEBUG " INT to IRQ:\n");
+
+       for (i=0, j=0; i<15; i++)
+               if (GetBit(Word,i)) printk(KERN_DEBUG " INT%d -> IRQ %d;",j++,i);
+
+       printk(KERN_DEBUG "\n");
+}
+
+/* function to recalculate the limits of buffer based on rcv_ram */
+static void eepro_recalc (struct net_device *dev)
+{
+       struct eepro_local *    lp;
+
+       lp = netdev_priv(dev);
+       lp->xmt_ram = RAM_SIZE - lp->rcv_ram;
+
+       if (lp->eepro == LAN595FX_10ISA) {
+               lp->xmt_lower_limit = XMT_START_10;
+               lp->xmt_upper_limit = (lp->xmt_ram - 2);
+               lp->rcv_lower_limit = lp->xmt_ram;
+               lp->rcv_upper_limit = (RAM_SIZE - 2);
+       }
+       else {
+               lp->rcv_lower_limit = RCV_START_PRO;
+               lp->rcv_upper_limit = (lp->rcv_ram - 2);
+               lp->xmt_lower_limit = lp->rcv_ram;
+               lp->xmt_upper_limit = (RAM_SIZE - 2);
+       }
+}
+
+/* prints boot-time info */
+static void __init eepro_print_info (struct net_device *dev)
+{
+       struct eepro_local *    lp = netdev_priv(dev);
+       int                     i;
+       const char *            ifmap[] = {"AUI", "10Base2", "10BaseT"};
+
+       i = inb(dev->base_addr + ID_REG);
+       printk(KERN_DEBUG " id: %#x ",i);
+       printk(" io: %#x ", (unsigned)dev->base_addr);
+
+       switch (lp->eepro) {
+               case LAN595FX_10ISA:
+                       printk("%s: Intel EtherExpress 10 ISA\n at %#x,",
+                                       dev->name, (unsigned)dev->base_addr);
+                       break;
+               case LAN595FX:
+                       printk("%s: Intel EtherExpress Pro/10+ ISA\n at %#x,",
+                                       dev->name, (unsigned)dev->base_addr);
+                       break;
+               case LAN595TX:
+                       printk("%s: Intel EtherExpress Pro/10 ISA at %#x,",
+                                       dev->name, (unsigned)dev->base_addr);
+                       break;
+               case LAN595:
+                       printk("%s: Intel 82595-based lan card at %#x,",
+                                       dev->name, (unsigned)dev->base_addr);
+                       break;
+       }
+
+       printk(" %pM", dev->dev_addr);
+
+       if (net_debug > 3)
+               printk(KERN_DEBUG ", %dK RCV buffer",
+                               (int)(lp->rcv_ram)/1024);
+
+       if (dev->irq > 2)
+               printk(", IRQ %d, %s.\n", dev->irq, ifmap[dev->if_port]);
+       else
+               printk(", %s.\n", ifmap[dev->if_port]);
+
+       if (net_debug > 3) {
+               i = lp->word[5];
+               if (i & 0x2000) /* bit 13 of EEPROM word 5 */
+                       printk(KERN_DEBUG "%s: Concurrent Processing is "
+                               "enabled but not used!\n", dev->name);
+       }
+
+       /* Check the station address for the manufacturer's code */
+       if (net_debug>3)
+               printEEPROMInfo(dev);
+}
+
+static const struct ethtool_ops eepro_ethtool_ops;
+
+static const struct net_device_ops eepro_netdev_ops = {
+       .ndo_open               = eepro_open,
+       .ndo_stop               = eepro_close,
+       .ndo_start_xmit         = eepro_send_packet,
+       .ndo_set_multicast_list = set_multicast_list,
+       .ndo_tx_timeout         = eepro_tx_timeout,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
+/* This is the real probe routine.  Linux has a history of friendly device
+   probes on the ISA bus.  A good device probe avoids doing writes, and
+   verifies that the correct device exists and functions.  */
+
+static int __init eepro_probe1(struct net_device *dev, int autoprobe)
+{
+       unsigned short station_addr[3], id, counter;
+       int i;
+       struct eepro_local *lp;
+       int ioaddr = dev->base_addr;
+       int err;
+
+       /* Grab the region so we can find another board if autoIRQ fails. */
+       if (!request_region(ioaddr, EEPRO_IO_EXTENT, DRV_NAME)) {
+               if (!autoprobe)
+                       printk(KERN_WARNING "EEPRO: io-port 0x%04x in use\n",
+                               ioaddr);
+               return -EBUSY;
+       }
+
+       /* Now, we are going to check for the signature of the
+          ID_REG (register 2 of bank 0) */
+
+       id = inb(ioaddr + ID_REG);
+
+       if ((id & ID_REG_MASK) != ID_REG_SIG)
+               goto exit;
+
+       /* We seem to have the 82595 signature, let's
+          play with its counter (last 2 bits of
+          register 2 of bank 0) to be sure. */
+
+       counter = id & R_ROBIN_BITS;
+
+       if ((inb(ioaddr + ID_REG) & R_ROBIN_BITS) != (counter + 0x40))
+               goto exit;
+
+       lp = netdev_priv(dev);
+       memset(lp, 0, sizeof(struct eepro_local));
+       lp->xmt_bar = XMT_BAR_PRO;
+       lp->xmt_lower_limit_reg = XMT_LOWER_LIMIT_REG_PRO;
+       lp->xmt_upper_limit_reg = XMT_UPPER_LIMIT_REG_PRO;
+       lp->eeprom_reg = EEPROM_REG_PRO;
+       spin_lock_init(&lp->lock);
+
+       /* Now, get the ethernet hardware address from
+          the EEPROM */
+       station_addr[0] = read_eeprom(ioaddr, 2, dev);
+
+       /* FIXME - find another way to know that we've found
+        * an Etherexpress 10
+        */
+       if (station_addr[0] == 0x0000 || station_addr[0] == 0xffff) {
+               lp->eepro = LAN595FX_10ISA;
+               lp->eeprom_reg = EEPROM_REG_10;
+               lp->xmt_lower_limit_reg = XMT_LOWER_LIMIT_REG_10;
+               lp->xmt_upper_limit_reg = XMT_UPPER_LIMIT_REG_10;
+               lp->xmt_bar = XMT_BAR_10;
+               station_addr[0] = read_eeprom(ioaddr, 2, dev);
+       }
+
+       /* get all words at once. will be used here and for ethtool */
+       for (i = 0; i < 8; i++) {
+               lp->word[i] = read_eeprom(ioaddr, i, dev);
+       }
+       station_addr[1] = lp->word[3];
+       station_addr[2] = lp->word[4];
+
+       if (!lp->eepro) {
+               if (lp->word[7] == ee_FX_INT2IRQ)
+                       lp->eepro = 2;
+               else if (station_addr[2] == SA_ADDR1)
+                       lp->eepro = 1;
+       }
+
+       /* Fill in the 'dev' fields. */
+       for (i=0; i < 6; i++)
+               dev->dev_addr[i] = ((unsigned char *) station_addr)[5-i];
+
+       /* RX buffer must be more than 3K and less than 29K */
+       if (dev->mem_end < 3072 || dev->mem_end > 29696)
+               lp->rcv_ram = RCV_DEFAULT_RAM;
+
+       /* calculate {xmt,rcv}_{lower,upper}_limit */
+       eepro_recalc(dev);
+
+       if (GetBit(lp->word[5], ee_BNC_TPE))
+               dev->if_port = BNC;
+       else
+               dev->if_port = TPE;
+
+       if (dev->irq < 2 && lp->eepro != 0) {
+               /* Mask off INT number */
+               int count = lp->word[1] & 7;
+               unsigned irqMask = lp->word[7];
+
+               while (count--)
+                       irqMask &= irqMask - 1;
+
+               count = ffs(irqMask);
+
+               if (count)
+                       dev->irq = count - 1;
+
+               if (dev->irq < 2) {
+                       printk(KERN_ERR " Duh! illegal interrupt vector stored in EEPROM.\n");
+                       goto exit;
+               } else if (dev->irq == 2) {
+                       dev->irq = 9;
+               }
+       }
+
+       dev->netdev_ops         = &eepro_netdev_ops;
+       dev->watchdog_timeo     = TX_TIMEOUT;
+       dev->ethtool_ops        = &eepro_ethtool_ops;
+
+       /* print boot time info */
+       eepro_print_info(dev);
+
+       /* reset 82595 */
+       eepro_reset(ioaddr);
+
+       err = register_netdev(dev);
+       if (err)
+               goto err;
+       return 0;
+exit:
+       err = -ENODEV;
+err:
+       release_region(dev->base_addr, EEPRO_IO_EXTENT);
+       return err;
+}
+
+/* Open/initialize the board.  This is called (in the current kernel)
+   sometime after booting when the 'ifconfig' program is run.
+
+   This routine should set everything up anew at each open, even
+   registers that "should" only need to be set once at boot, so that
+   there is non-reboot way to recover if something goes wrong.
+   */
+
+static const char irqrmap[] = {-1,-1,0,1,-1,2,-1,-1,-1,0,3,4,-1,-1,-1,-1};
+static const char irqrmap2[] = {-1,-1,4,0,1,2,-1,3,-1,4,5,6,7,-1,-1,-1};
+static int     eepro_grab_irq(struct net_device *dev)
+{
+       static const int irqlist[] = { 3, 4, 5, 7, 9, 10, 11, 12, 0 };
+       const int *irqp = irqlist;
+       int temp_reg, ioaddr = dev->base_addr;
+
+       eepro_sw2bank1(ioaddr); /* be CAREFUL, BANK 1 now */
+
+       /* Enable the interrupt line. */
+       eepro_en_intline(ioaddr);
+
+       /* be CAREFUL, BANK 0 now */
+       eepro_sw2bank0(ioaddr);
+
+       /* clear all interrupts */
+       eepro_clear_int(ioaddr);
+
+       /* Let EXEC event to interrupt */
+       eepro_en_intexec(ioaddr);
+
+       do {
+               eepro_sw2bank1(ioaddr); /* be CAREFUL, BANK 1 now */
+
+               temp_reg = inb(ioaddr + INT_NO_REG);
+               outb((temp_reg & 0xf8) | irqrmap[*irqp], ioaddr + INT_NO_REG);
+
+               eepro_sw2bank0(ioaddr); /* Switch back to Bank 0 */
+
+               if (request_irq (*irqp, NULL, IRQF_SHARED, "bogus", dev) != EBUSY) {
+                       unsigned long irq_mask;
+                       /* Twinkle the interrupt, and check if it's seen */
+                       irq_mask = probe_irq_on();
+
+                       eepro_diag(ioaddr); /* RESET the 82595 */
+                       mdelay(20);
+
+                       if (*irqp == probe_irq_off(irq_mask))  /* It's a good IRQ line */
+                               break;
+
+                       /* clear all interrupts */
+                       eepro_clear_int(ioaddr);
+               }
+       } while (*++irqp);
+
+       eepro_sw2bank1(ioaddr); /* Switch back to Bank 1 */
+
+       /* Disable the physical interrupt line. */
+       eepro_dis_intline(ioaddr);
+
+       eepro_sw2bank0(ioaddr); /* Switch back to Bank 0 */
+
+       /* Mask all the interrupts. */
+       eepro_dis_int(ioaddr);
+
+       /* clear all interrupts */
+       eepro_clear_int(ioaddr);
+
+       return dev->irq;
+}
+
+static int eepro_open(struct net_device *dev)
+{
+       unsigned short temp_reg, old8, old9;
+       int irqMask;
+       int i, ioaddr = dev->base_addr;
+       struct eepro_local *lp = netdev_priv(dev);
+
+       if (net_debug > 3)
+               printk(KERN_DEBUG "%s: entering eepro_open routine.\n", dev->name);
+
+       irqMask = lp->word[7];
+
+       if (lp->eepro == LAN595FX_10ISA) {
+               if (net_debug > 3) printk(KERN_DEBUG "p->eepro = 3;\n");
+       }
+       else if (irqMask == ee_FX_INT2IRQ) /* INT to IRQ Mask */
+               {
+                       lp->eepro = 2; /* Yes, an Intel EtherExpress Pro/10+ */
+                       if (net_debug > 3) printk(KERN_DEBUG "p->eepro = 2;\n");
+               }
+
+       else if ((dev->dev_addr[0] == SA_ADDR0 &&
+                       dev->dev_addr[1] == SA_ADDR1 &&
+                       dev->dev_addr[2] == SA_ADDR2))
+               {
+                       lp->eepro = 1;
+                       if (net_debug > 3) printk(KERN_DEBUG "p->eepro = 1;\n");
+               }  /* Yes, an Intel EtherExpress Pro/10 */
+
+       else lp->eepro = 0; /* No, it is a generic 82585 lan card */
+
+       /* Get the interrupt vector for the 82595 */
+       if (dev->irq < 2 && eepro_grab_irq(dev) == 0) {
+               printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, dev->irq);
+               return -EAGAIN;
+       }
+
+       if (request_irq(dev->irq , eepro_interrupt, 0, dev->name, dev)) {
+               printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, dev->irq);
+               return -EAGAIN;
+       }
+
+       /* Initialize the 82595. */
+
+       eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */
+       temp_reg = inb(ioaddr + lp->eeprom_reg);
+
+       lp->stepping = temp_reg >> 5;   /* Get the stepping number of the 595 */
+
+       if (net_debug > 3)
+               printk(KERN_DEBUG "The stepping of the 82595 is %d\n", lp->stepping);
+
+       if (temp_reg & 0x10) /* Check the TurnOff Enable bit */
+               outb(temp_reg & 0xef, ioaddr + lp->eeprom_reg);
+       for (i=0; i < 6; i++)
+               outb(dev->dev_addr[i] , ioaddr + I_ADD_REG0 + i);
+
+       temp_reg = inb(ioaddr + REG1);    /* Setup Transmit Chaining */
+       outb(temp_reg | XMT_Chain_Int | XMT_Chain_ErrStop /* and discard bad RCV frames */
+               | RCV_Discard_BadFrame, ioaddr + REG1);
+
+       temp_reg = inb(ioaddr + REG2); /* Match broadcast */
+       outb(temp_reg | 0x14, ioaddr + REG2);
+
+       temp_reg = inb(ioaddr + REG3);
+       outb(temp_reg & 0x3f, ioaddr + REG3); /* clear test mode */
+
+       /* Set the receiving mode */
+       eepro_sw2bank1(ioaddr); /* be CAREFUL, BANK 1 now */
+
+       /* Set the interrupt vector */
+       temp_reg = inb(ioaddr + INT_NO_REG);
+       if (lp->eepro == LAN595FX || lp->eepro == LAN595FX_10ISA)
+               outb((temp_reg & 0xf8) | irqrmap2[dev->irq], ioaddr + INT_NO_REG);
+       else outb((temp_reg & 0xf8) | irqrmap[dev->irq], ioaddr + INT_NO_REG);
+
+
+       temp_reg = inb(ioaddr + INT_NO_REG);
+       if (lp->eepro == LAN595FX || lp->eepro == LAN595FX_10ISA)
+               outb((temp_reg & 0xf0) | irqrmap2[dev->irq] | 0x08,ioaddr+INT_NO_REG);
+       else outb((temp_reg & 0xf8) | irqrmap[dev->irq], ioaddr + INT_NO_REG);
+
+       if (net_debug > 3)
+               printk(KERN_DEBUG "eepro_open: content of INT Reg is %x\n", temp_reg);
+
+
+       /* Initialize the RCV and XMT upper and lower limits */
+       outb(lp->rcv_lower_limit >> 8, ioaddr + RCV_LOWER_LIMIT_REG);
+       outb(lp->rcv_upper_limit >> 8, ioaddr + RCV_UPPER_LIMIT_REG);
+       outb(lp->xmt_lower_limit >> 8, ioaddr + lp->xmt_lower_limit_reg);
+       outb(lp->xmt_upper_limit >> 8, ioaddr + lp->xmt_upper_limit_reg);
+
+       /* Enable the interrupt line. */
+       eepro_en_intline(ioaddr);
+
+       /* Switch back to Bank 0 */
+       eepro_sw2bank0(ioaddr);
+
+       /* Let RX and TX events to interrupt */
+       eepro_en_int(ioaddr);
+
+       /* clear all interrupts */
+       eepro_clear_int(ioaddr);
+
+       /* Initialize RCV */
+       outw(lp->rcv_lower_limit, ioaddr + RCV_BAR);
+       lp->rx_start = lp->rcv_lower_limit;
+       outw(lp->rcv_upper_limit | 0xfe, ioaddr + RCV_STOP);
+
+       /* Initialize XMT */
+       outw(lp->xmt_lower_limit, ioaddr + lp->xmt_bar);
+       lp->tx_start = lp->tx_end = lp->xmt_lower_limit;
+       lp->tx_last = 0;
+
+       /* Check for the i82595TX and i82595FX */
+       old8 = inb(ioaddr + 8);
+       outb(~old8, ioaddr + 8);
+
+       if ((temp_reg = inb(ioaddr + 8)) == old8) {
+               if (net_debug > 3)
+                       printk(KERN_DEBUG "i82595 detected!\n");
+               lp->version = LAN595;
+       }
+       else {
+               lp->version = LAN595TX;
+               outb(old8, ioaddr + 8);
+               old9 = inb(ioaddr + 9);
+
+               if (irqMask==ee_FX_INT2IRQ) {
+                       if (net_debug > 3) {
+                               printk(KERN_DEBUG "IrqMask: %#x\n",irqMask);
+                               printk(KERN_DEBUG "i82595FX detected!\n");
+                       }
+                       lp->version = LAN595FX;
+                       outb(old9, ioaddr + 9);
+                       if (dev->if_port != TPE) {      /* Hopefully, this will fix the
+                                                       problem of using Pentiums and
+                                                       pro/10 w/ BNC. */
+                               eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */
+                               temp_reg = inb(ioaddr + REG13);
+                               /* disable the full duplex mode since it is not
+                               applicable with the 10Base2 cable. */
+                               outb(temp_reg & ~(FDX | A_N_ENABLE), REG13);
+                               eepro_sw2bank0(ioaddr); /* be CAREFUL, BANK 0 now */
+                       }
+               }
+               else if (net_debug > 3) {
+                       printk(KERN_DEBUG "temp_reg: %#x  ~old9: %#x\n",temp_reg,((~old9)&0xff));
+                       printk(KERN_DEBUG "i82595TX detected!\n");
+               }
+       }
+
+       eepro_sel_reset(ioaddr);
+
+       netif_start_queue(dev);
+
+       if (net_debug > 3)
+               printk(KERN_DEBUG "%s: exiting eepro_open routine.\n", dev->name);
+
+       /* enabling rx */
+       eepro_en_rx(ioaddr);
+
+       return 0;
+}
+
+static void eepro_tx_timeout (struct net_device *dev)
+{
+       struct eepro_local *lp = netdev_priv(dev);
+       int ioaddr = dev->base_addr;
+
+       /* if (net_debug > 1) */
+       printk (KERN_ERR "%s: transmit timed out, %s?\n", dev->name,
+               "network cable problem");
+       /* This is not a duplicate. One message for the console,
+          one for the log file  */
+       printk (KERN_DEBUG "%s: transmit timed out, %s?\n", dev->name,
+               "network cable problem");
+       eepro_complete_selreset(ioaddr);
+}
+
+
+static netdev_tx_t eepro_send_packet(struct sk_buff *skb,
+                                    struct net_device *dev)
+{
+       struct eepro_local *lp = netdev_priv(dev);
+       unsigned long flags;
+       int ioaddr = dev->base_addr;
+       short length = skb->len;
+
+       if (net_debug > 5)
+               printk(KERN_DEBUG  "%s: entering eepro_send_packet routine.\n", dev->name);
+
+       if (length < ETH_ZLEN) {
+               if (skb_padto(skb, ETH_ZLEN))
+                       return NETDEV_TX_OK;
+               length = ETH_ZLEN;
+       }
+       netif_stop_queue (dev);
+
+       eepro_dis_int(ioaddr);
+       spin_lock_irqsave(&lp->lock, flags);
+
+       {
+               unsigned char *buf = skb->data;
+
+               if (hardware_send_packet(dev, buf, length))
+                       /* we won't wake queue here because we're out of space */
+                       dev->stats.tx_dropped++;
+               else {
+                       dev->stats.tx_bytes+=skb->len;
+                       netif_wake_queue(dev);
+               }
+
+       }
+
+       dev_kfree_skb (skb);
+
+       /* You might need to clean up and record Tx statistics here. */
+       /* dev->stats.tx_aborted_errors++; */
+
+       if (net_debug > 5)
+               printk(KERN_DEBUG "%s: exiting eepro_send_packet routine.\n", dev->name);
+
+       eepro_en_int(ioaddr);
+       spin_unlock_irqrestore(&lp->lock, flags);
+
+       return NETDEV_TX_OK;
+}
+
+
+/*     The typical workload of the driver:
+       Handle the network interface interrupts. */
+
+static irqreturn_t
+eepro_interrupt(int irq, void *dev_id)
+{
+       struct net_device *dev = dev_id;
+       struct eepro_local *lp;
+       int ioaddr, status, boguscount = 20;
+       int handled = 0;
+
+       lp = netdev_priv(dev);
+
+        spin_lock(&lp->lock);
+
+       if (net_debug > 5)
+               printk(KERN_DEBUG "%s: entering eepro_interrupt routine.\n", dev->name);
+
+       ioaddr = dev->base_addr;
+
+       while (((status = inb(ioaddr + STATUS_REG)) & (RX_INT|TX_INT)) && (boguscount--))
+       {
+               handled = 1;
+               if (status & RX_INT) {
+                       if (net_debug > 4)
+                               printk(KERN_DEBUG "%s: packet received interrupt.\n", dev->name);
+
+                       eepro_dis_int(ioaddr);
+
+                       /* Get the received packets */
+                       eepro_ack_rx(ioaddr);
+                       eepro_rx(dev);
+
+                       eepro_en_int(ioaddr);
+               }
+               if (status & TX_INT) {
+                       if (net_debug > 4)
+                               printk(KERN_DEBUG "%s: packet transmit interrupt.\n", dev->name);
+
+
+                       eepro_dis_int(ioaddr);
+
+                       /* Process the status of transmitted packets */
+                       eepro_ack_tx(ioaddr);
+                       eepro_transmit_interrupt(dev);
+
+                       eepro_en_int(ioaddr);
+               }
+       }
+
+       if (net_debug > 5)
+               printk(KERN_DEBUG "%s: exiting eepro_interrupt routine.\n", dev->name);
+
+       spin_unlock(&lp->lock);
+       return IRQ_RETVAL(handled);
+}
+
+static int eepro_close(struct net_device *dev)
+{
+       struct eepro_local *lp = netdev_priv(dev);
+       int ioaddr = dev->base_addr;
+       short temp_reg;
+
+       netif_stop_queue(dev);
+
+       eepro_sw2bank1(ioaddr); /* Switch back to Bank 1 */
+
+       /* Disable the physical interrupt line. */
+       temp_reg = inb(ioaddr + REG1);
+       outb(temp_reg & 0x7f, ioaddr + REG1);
+
+       eepro_sw2bank0(ioaddr); /* Switch back to Bank 0 */
+
+       /* Flush the Tx and disable Rx. */
+       outb(STOP_RCV_CMD, ioaddr);
+       lp->tx_start = lp->tx_end = lp->xmt_lower_limit;
+       lp->tx_last = 0;
+
+       /* Mask all the interrupts. */
+       eepro_dis_int(ioaddr);
+
+       /* clear all interrupts */
+       eepro_clear_int(ioaddr);
+
+       /* Reset the 82595 */
+       eepro_reset(ioaddr);
+
+       /* release the interrupt */
+       free_irq(dev->irq, dev);
+
+       /* Update the statistics here. What statistics? */
+
+       return 0;
+}
+
+/* Set or clear the multicast filter for this adaptor.
+ */
+static void
+set_multicast_list(struct net_device *dev)
+{
+       struct eepro_local *lp = netdev_priv(dev);
+       short ioaddr = dev->base_addr;
+       unsigned short mode;
+       struct netdev_hw_addr *ha;
+       int mc_count = netdev_mc_count(dev);
+
+       if (dev->flags&(IFF_ALLMULTI|IFF_PROMISC) || mc_count > 63)
+       {
+               eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */
+               mode = inb(ioaddr + REG2);
+               outb(mode | PRMSC_Mode, ioaddr + REG2);
+               mode = inb(ioaddr + REG3);
+               outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */
+               eepro_sw2bank0(ioaddr); /* Return to BANK 0 now */
+       }
+
+       else if (mc_count == 0)
+       {
+               eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */
+               mode = inb(ioaddr + REG2);
+               outb(mode & 0xd6, ioaddr + REG2); /* Turn off Multi-IA and PRMSC_Mode bits */
+               mode = inb(ioaddr + REG3);
+               outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */
+               eepro_sw2bank0(ioaddr); /* Return to BANK 0 now */
+       }
+
+       else
+       {
+               unsigned short status, *eaddrs;
+               int i, boguscount = 0;
+
+               /* Disable RX and TX interrupts.  Necessary to avoid
+                  corruption of the HOST_ADDRESS_REG by interrupt
+                  service routines. */
+               eepro_dis_int(ioaddr);
+
+               eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */
+               mode = inb(ioaddr + REG2);
+               outb(mode | Multi_IA, ioaddr + REG2);
+               mode = inb(ioaddr + REG3);
+               outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */
+               eepro_sw2bank0(ioaddr); /* Return to BANK 0 now */
+               outw(lp->tx_end, ioaddr + HOST_ADDRESS_REG);
+               outw(MC_SETUP, ioaddr + IO_PORT);
+               outw(0, ioaddr + IO_PORT);
+               outw(0, ioaddr + IO_PORT);
+               outw(6 * (mc_count + 1), ioaddr + IO_PORT);
+
+               netdev_for_each_mc_addr(ha, dev) {
+                       eaddrs = (unsigned short *) ha->addr;
+                       outw(*eaddrs++, ioaddr + IO_PORT);
+                       outw(*eaddrs++, ioaddr + IO_PORT);
+                       outw(*eaddrs++, ioaddr + IO_PORT);
+               }
+
+               eaddrs = (unsigned short *) dev->dev_addr;
+               outw(eaddrs[0], ioaddr + IO_PORT);
+               outw(eaddrs[1], ioaddr + IO_PORT);
+               outw(eaddrs[2], ioaddr + IO_PORT);
+               outw(lp->tx_end, ioaddr + lp->xmt_bar);
+               outb(MC_SETUP, ioaddr);
+
+               /* Update the transmit queue */
+               i = lp->tx_end + XMT_HEADER + 6 * (mc_count + 1);
+
+               if (lp->tx_start != lp->tx_end)
+               {
+                       /* update the next address and the chain bit in the
+                          last packet */
+                       outw(lp->tx_last + XMT_CHAIN, ioaddr + HOST_ADDRESS_REG);
+                       outw(i, ioaddr + IO_PORT);
+                       outw(lp->tx_last + XMT_COUNT, ioaddr + HOST_ADDRESS_REG);
+                       status = inw(ioaddr + IO_PORT);
+                       outw(status | CHAIN_BIT, ioaddr + IO_PORT);
+                       lp->tx_end = i ;
+               }
+               else {
+                       lp->tx_start = lp->tx_end = i ;
+               }
+
+               /* Acknowledge that the MC setup is done */
+               do { /* We should be doing this in the eepro_interrupt()! */
+                       SLOW_DOWN;
+                       SLOW_DOWN;
+                       if (inb(ioaddr + STATUS_REG) & 0x08)
+                       {
+                               i = inb(ioaddr);
+                               outb(0x08, ioaddr + STATUS_REG);
+
+                               if (i & 0x20) { /* command ABORTed */
+                                       printk(KERN_NOTICE "%s: multicast setup failed.\n",
+                                               dev->name);
+                                       break;
+                               } else if ((i & 0x0f) == 0x03)  { /* MC-Done */
+                                       printk(KERN_DEBUG "%s: set Rx mode to %d address%s.\n",
+                                               dev->name, mc_count,
+                                               mc_count > 1 ? "es":"");
+                                       break;
+                               }
+                       }
+               } while (++boguscount < 100);
+
+               /* Re-enable RX and TX interrupts */
+               eepro_en_int(ioaddr);
+       }
+       if (lp->eepro == LAN595FX_10ISA) {
+               eepro_complete_selreset(ioaddr);
+       }
+       else
+               eepro_en_rx(ioaddr);
+}
+
+/* The horrible routine to read a word from the serial EEPROM. */
+/* IMPORTANT - the 82595 will be set to Bank 0 after the eeprom is read */
+
+/* The delay between EEPROM clock transitions. */
+#define eeprom_delay() { udelay(40); }
+#define EE_READ_CMD (6 << 6)
+
+static int
+read_eeprom(int ioaddr, int location, struct net_device *dev)
+{
+       int i;
+       unsigned short retval = 0;
+       struct eepro_local *lp = netdev_priv(dev);
+       short ee_addr = ioaddr + lp->eeprom_reg;
+       int read_cmd = location | EE_READ_CMD;
+       short ctrl_val = EECS ;
+
+       /* XXXX - black magic */
+               eepro_sw2bank1(ioaddr);
+               outb(0x00, ioaddr + STATUS_REG);
+       /* XXXX - black magic */
+
+       eepro_sw2bank2(ioaddr);
+       outb(ctrl_val, ee_addr);
+
+       /* Shift the read command bits out. */
+       for (i = 8; i >= 0; i--) {
+               short outval = (read_cmd & (1 << i)) ? ctrl_val | EEDI
+                       : ctrl_val;
+               outb(outval, ee_addr);
+               outb(outval | EESK, ee_addr);   /* EEPROM clock tick. */
+               eeprom_delay();
+               outb(outval, ee_addr);  /* Finish EEPROM a clock tick. */
+               eeprom_delay();
+       }
+       outb(ctrl_val, ee_addr);
+
+       for (i = 16; i > 0; i--) {
+               outb(ctrl_val | EESK, ee_addr);  eeprom_delay();
+               retval = (retval << 1) | ((inb(ee_addr) & EEDO) ? 1 : 0);
+               outb(ctrl_val, ee_addr);  eeprom_delay();
+       }
+
+       /* Terminate the EEPROM access. */
+       ctrl_val &= ~EECS;
+       outb(ctrl_val | EESK, ee_addr);
+       eeprom_delay();
+       outb(ctrl_val, ee_addr);
+       eeprom_delay();
+       eepro_sw2bank0(ioaddr);
+       return retval;
+}
+
+static int
+hardware_send_packet(struct net_device *dev, void *buf, short length)
+{
+       struct eepro_local *lp = netdev_priv(dev);
+       short ioaddr = dev->base_addr;
+       unsigned status, tx_available, last, end;
+
+       if (net_debug > 5)
+               printk(KERN_DEBUG "%s: entering hardware_send_packet routine.\n", dev->name);
+
+       /* determine how much of the transmit buffer space is available */
+       if (lp->tx_end > lp->tx_start)
+               tx_available = lp->xmt_ram - (lp->tx_end - lp->tx_start);
+       else if (lp->tx_end < lp->tx_start)
+               tx_available = lp->tx_start - lp->tx_end;
+       else tx_available = lp->xmt_ram;
+
+       if (((((length + 3) >> 1) << 1) + 2*XMT_HEADER) >= tx_available) {
+               /* No space available ??? */
+               return 1;
+               }
+
+               last = lp->tx_end;
+               end = last + (((length + 3) >> 1) << 1) + XMT_HEADER;
+
+       if (end >= lp->xmt_upper_limit + 2) { /* the transmit buffer is wrapped around */
+               if ((lp->xmt_upper_limit + 2 - last) <= XMT_HEADER) {
+                               /* Arrrr!!!, must keep the xmt header together,
+                               several days were lost to chase this one down. */
+                       last = lp->xmt_lower_limit;
+                               end = last + (((length + 3) >> 1) << 1) + XMT_HEADER;
+                       }
+               else end = lp->xmt_lower_limit + (end -
+                                               lp->xmt_upper_limit + 2);
+               }
+
+               outw(last, ioaddr + HOST_ADDRESS_REG);
+               outw(XMT_CMD, ioaddr + IO_PORT);
+               outw(0, ioaddr + IO_PORT);
+               outw(end, ioaddr + IO_PORT);
+               outw(length, ioaddr + IO_PORT);
+
+               if (lp->version == LAN595)
+                       outsw(ioaddr + IO_PORT, buf, (length + 3) >> 1);
+               else {  /* LAN595TX or LAN595FX, capable of 32-bit I/O processing */
+                       unsigned short temp = inb(ioaddr + INT_MASK_REG);
+                       outb(temp | IO_32_BIT, ioaddr + INT_MASK_REG);
+                       outsl(ioaddr + IO_PORT_32_BIT, buf, (length + 3) >> 2);
+                       outb(temp & ~(IO_32_BIT), ioaddr + INT_MASK_REG);
+               }
+
+               /* A dummy read to flush the DRAM write pipeline */
+               status = inw(ioaddr + IO_PORT);
+
+               if (lp->tx_start == lp->tx_end) {
+               outw(last, ioaddr + lp->xmt_bar);
+                       outb(XMT_CMD, ioaddr);
+                       lp->tx_start = last;   /* I don't like to change tx_start here */
+               }
+               else {
+                       /* update the next address and the chain bit in the
+                       last packet */
+
+                       if (lp->tx_end != last) {
+                               outw(lp->tx_last + XMT_CHAIN, ioaddr + HOST_ADDRESS_REG);
+                               outw(last, ioaddr + IO_PORT);
+                       }
+
+                       outw(lp->tx_last + XMT_COUNT, ioaddr + HOST_ADDRESS_REG);
+                       status = inw(ioaddr + IO_PORT);
+                       outw(status | CHAIN_BIT, ioaddr + IO_PORT);
+
+                       /* Continue the transmit command */
+                       outb(RESUME_XMT_CMD, ioaddr);
+               }
+
+               lp->tx_last = last;
+               lp->tx_end = end;
+
+               if (net_debug > 5)
+                       printk(KERN_DEBUG "%s: exiting hardware_send_packet routine.\n", dev->name);
+
+       return 0;
+}
+
+static void
+eepro_rx(struct net_device *dev)
+{
+       struct eepro_local *lp = netdev_priv(dev);
+       short ioaddr = dev->base_addr;
+       short boguscount = 20;
+       short rcv_car = lp->rx_start;
+       unsigned rcv_event, rcv_status, rcv_next_frame, rcv_size;
+
+       if (net_debug > 5)
+               printk(KERN_DEBUG "%s: entering eepro_rx routine.\n", dev->name);
+
+       /* Set the read pointer to the start of the RCV */
+       outw(rcv_car, ioaddr + HOST_ADDRESS_REG);
+
+       rcv_event = inw(ioaddr + IO_PORT);
+
+       while (rcv_event == RCV_DONE) {
+
+               rcv_status = inw(ioaddr + IO_PORT);
+               rcv_next_frame = inw(ioaddr + IO_PORT);
+               rcv_size = inw(ioaddr + IO_PORT);
+
+               if ((rcv_status & (RX_OK | RX_ERROR)) == RX_OK) {
+
+                       /* Malloc up new buffer. */
+                       struct sk_buff *skb;
+
+                       dev->stats.rx_bytes+=rcv_size;
+                       rcv_size &= 0x3fff;
+                       skb = dev_alloc_skb(rcv_size+5);
+                       if (skb == NULL) {
+                               printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
+                               dev->stats.rx_dropped++;
+                               rcv_car = lp->rx_start + RCV_HEADER + rcv_size;
+                               lp->rx_start = rcv_next_frame;
+                               outw(rcv_next_frame, ioaddr + HOST_ADDRESS_REG);
+
+                               break;
+                       }
+                       skb_reserve(skb,2);
+
+                       if (lp->version == LAN595)
+                               insw(ioaddr+IO_PORT, skb_put(skb,rcv_size), (rcv_size + 3) >> 1);
+                       else { /* LAN595TX or LAN595FX, capable of 32-bit I/O processing */
+                               unsigned short temp = inb(ioaddr + INT_MASK_REG);
+                               outb(temp | IO_32_BIT, ioaddr + INT_MASK_REG);
+                               insl(ioaddr+IO_PORT_32_BIT, skb_put(skb,rcv_size),
+                                       (rcv_size + 3) >> 2);
+                               outb(temp & ~(IO_32_BIT), ioaddr + INT_MASK_REG);
+                       }
+
+                       skb->protocol = eth_type_trans(skb,dev);
+                       netif_rx(skb);
+                       dev->stats.rx_packets++;
+               }
+
+               else { /* Not sure will ever reach here,
+                       I set the 595 to discard bad received frames */
+                       dev->stats.rx_errors++;
+
+                       if (rcv_status & 0x0100)
+                               dev->stats.rx_over_errors++;
+
+                       else if (rcv_status & 0x0400)
+                               dev->stats.rx_frame_errors++;
+
+                       else if (rcv_status & 0x0800)
+                               dev->stats.rx_crc_errors++;
+
+                       printk(KERN_DEBUG "%s: event = %#x, status = %#x, next = %#x, size = %#x\n",
+                               dev->name, rcv_event, rcv_status, rcv_next_frame, rcv_size);
+               }
+
+               if (rcv_status & 0x1000)
+                       dev->stats.rx_length_errors++;
+
+               rcv_car = lp->rx_start + RCV_HEADER + rcv_size;
+               lp->rx_start = rcv_next_frame;
+
+               if (--boguscount == 0)
+                       break;
+
+               outw(rcv_next_frame, ioaddr + HOST_ADDRESS_REG);
+               rcv_event = inw(ioaddr + IO_PORT);
+
+       }
+       if (rcv_car == 0)
+               rcv_car = lp->rcv_upper_limit | 0xff;
+
+       outw(rcv_car - 1, ioaddr + RCV_STOP);
+
+       if (net_debug > 5)
+               printk(KERN_DEBUG "%s: exiting eepro_rx routine.\n", dev->name);
+}
+
+static void
+eepro_transmit_interrupt(struct net_device *dev)
+{
+       struct eepro_local *lp = netdev_priv(dev);
+       short ioaddr = dev->base_addr;
+       short boguscount = 25;
+       short xmt_status;
+
+       while ((lp->tx_start != lp->tx_end) && boguscount--) {
+
+               outw(lp->tx_start, ioaddr + HOST_ADDRESS_REG);
+               xmt_status = inw(ioaddr+IO_PORT);
+
+               if (!(xmt_status & TX_DONE_BIT))
+                               break;
+
+               xmt_status = inw(ioaddr+IO_PORT);
+               lp->tx_start = inw(ioaddr+IO_PORT);
+
+               netif_wake_queue (dev);
+
+               if (xmt_status & TX_OK)
+                       dev->stats.tx_packets++;
+               else {
+                       dev->stats.tx_errors++;
+                       if (xmt_status & 0x0400) {
+                               dev->stats.tx_carrier_errors++;
+                               printk(KERN_DEBUG "%s: carrier error\n",
+                                       dev->name);
+                               printk(KERN_DEBUG "%s: XMT status = %#x\n",
+                                       dev->name, xmt_status);
+                       }
+                       else {
+                               printk(KERN_DEBUG "%s: XMT status = %#x\n",
+                                       dev->name, xmt_status);
+                               printk(KERN_DEBUG "%s: XMT status = %#x\n",
+                                       dev->name, xmt_status);
+                       }
+               }
+               if (xmt_status & 0x000f) {
+                       dev->stats.collisions += (xmt_status & 0x000f);
+               }
+
+               if ((xmt_status & 0x0040) == 0x0) {
+                       dev->stats.tx_heartbeat_errors++;
+               }
+       }
+}
+
+static int eepro_ethtool_get_settings(struct net_device *dev,
+                                       struct ethtool_cmd *cmd)
+{
+       struct eepro_local      *lp = netdev_priv(dev);
+
+       cmd->supported =        SUPPORTED_10baseT_Half |
+                               SUPPORTED_10baseT_Full |
+                               SUPPORTED_Autoneg;
+       cmd->advertising =      ADVERTISED_10baseT_Half |
+                               ADVERTISED_10baseT_Full |
+                               ADVERTISED_Autoneg;
+
+       if (GetBit(lp->word[5], ee_PortTPE)) {
+               cmd->supported |= SUPPORTED_TP;
+               cmd->advertising |= ADVERTISED_TP;
+       }
+       if (GetBit(lp->word[5], ee_PortBNC)) {
+               cmd->supported |= SUPPORTED_BNC;
+               cmd->advertising |= ADVERTISED_BNC;
+       }
+       if (GetBit(lp->word[5], ee_PortAUI)) {
+               cmd->supported |= SUPPORTED_AUI;
+               cmd->advertising |= ADVERTISED_AUI;
+       }
+
+       ethtool_cmd_speed_set(cmd, SPEED_10);
+
+       if (dev->if_port == TPE && lp->word[1] & ee_Duplex) {
+               cmd->duplex = DUPLEX_FULL;
+       }
+       else {
+               cmd->duplex = DUPLEX_HALF;
+       }
+
+       cmd->port = dev->if_port;
+       cmd->phy_address = dev->base_addr;
+       cmd->transceiver = XCVR_INTERNAL;
+
+       if (lp->word[0] & ee_AutoNeg) {
+               cmd->autoneg = 1;
+       }
+
+       return 0;
+}
+
+static void eepro_ethtool_get_drvinfo(struct net_device *dev,
+                                       struct ethtool_drvinfo *drvinfo)
+{
+       strcpy(drvinfo->driver, DRV_NAME);
+       strcpy(drvinfo->version, DRV_VERSION);
+       sprintf(drvinfo->bus_info, "ISA 0x%lx", dev->base_addr);
+}
+
+static const struct ethtool_ops eepro_ethtool_ops = {
+       .get_settings   = eepro_ethtool_get_settings,
+       .get_drvinfo    = eepro_ethtool_get_drvinfo,
+};
+
+#ifdef MODULE
+
+#define MAX_EEPRO 8
+static struct net_device *dev_eepro[MAX_EEPRO];
+
+static int io[MAX_EEPRO] = {
+  [0 ... MAX_EEPRO-1] = -1
+};
+static int irq[MAX_EEPRO];
+static int mem[MAX_EEPRO] = {  /* Size of the rx buffer in KB */
+  [0 ... MAX_EEPRO-1] = RCV_DEFAULT_RAM/1024
+};
+static int autodetect;
+
+static int n_eepro;
+/* For linux 2.1.xx */
+
+MODULE_AUTHOR("Pascal Dupuis and others");
+MODULE_DESCRIPTION("Intel i82595 ISA EtherExpressPro10/10+ driver");
+MODULE_LICENSE("GPL");
+
+module_param_array(io, int, NULL, 0);
+module_param_array(irq, int, NULL, 0);
+module_param_array(mem, int, NULL, 0);
+module_param(autodetect, int, 0);
+MODULE_PARM_DESC(io, "EtherExpress Pro/10 I/O base address(es)");
+MODULE_PARM_DESC(irq, "EtherExpress Pro/10 IRQ number(s)");
+MODULE_PARM_DESC(mem, "EtherExpress Pro/10 Rx buffer size(es) in kB (3-29)");
+MODULE_PARM_DESC(autodetect, "EtherExpress Pro/10 force board(s) detection (0-1)");
+
+int __init init_module(void)
+{
+       struct net_device *dev;
+       int i;
+       if (io[0] == -1 && autodetect == 0) {
+               printk(KERN_WARNING "eepro_init_module: Probe is very dangerous in ISA boards!\n");
+               printk(KERN_WARNING "eepro_init_module: Please add \"autodetect=1\" to force probe\n");
+               return -ENODEV;
+       }
+       else if (autodetect) {
+               /* if autodetect is set then we must force detection */
+               for (i = 0; i < MAX_EEPRO; i++) {
+                       io[i] = 0;
+               }
+
+               printk(KERN_INFO "eepro_init_module: Auto-detecting boards (May God protect us...)\n");
+       }
+
+       for (i = 0; i < MAX_EEPRO && io[i] != -1; i++) {
+               dev = alloc_etherdev(sizeof(struct eepro_local));
+               if (!dev)
+                       break;
+
+               dev->mem_end = mem[i];
+               dev->base_addr = io[i];
+               dev->irq = irq[i];
+
+               if (do_eepro_probe(dev) == 0) {
+                       dev_eepro[n_eepro++] = dev;
+                       continue;
+               }
+               free_netdev(dev);
+               break;
+       }
+
+       if (n_eepro)
+               printk(KERN_INFO "%s", version);
+
+       return n_eepro ? 0 : -ENODEV;
+}
+
+void __exit
+cleanup_module(void)
+{
+       int i;
+
+       for (i=0; i<n_eepro; i++) {
+               struct net_device *dev = dev_eepro[i];
+               unregister_netdev(dev);
+               release_region(dev->base_addr, EEPRO_IO_EXTENT);
+               free_netdev(dev);
+       }
+}
+#endif /* MODULE */
diff --git a/drivers/net/ethernet/i825xx/eexpress.c b/drivers/net/ethernet/i825xx/eexpress.c
new file mode 100644 (file)
index 0000000..a192285
--- /dev/null
@@ -0,0 +1,1720 @@
+/* Intel EtherExpress 16 device driver for Linux
+ *
+ * Written by John Sullivan, 1995
+ *  based on original code by Donald Becker, with changes by
+ *  Alan Cox and Pauline Middelink.
+ *
+ * Support for 8-bit mode by Zoltan Szilagyi <zoltans@cs.arizona.edu>
+ *
+ * Many modifications, and currently maintained, by
+ *  Philip Blundell <philb@gnu.org>
+ * Added the Compaq LTE  Alan Cox <alan@lxorguk.ukuu.org.uk>
+ * Added MCA support Adam Fritzler
+ *
+ * Note - this driver is experimental still - it has problems on faster
+ * machines. Someone needs to sit down and go through it line by line with
+ * a databook...
+ */
+
+/* The EtherExpress 16 is a fairly simple card, based on a shared-memory
+ * design using the i82586 Ethernet coprocessor.  It bears no relationship,
+ * as far as I know, to the similarly-named "EtherExpress Pro" range.
+ *
+ * Historically, Linux support for these cards has been very bad.  However,
+ * things seem to be getting better slowly.
+ */
+
+/* If your card is confused about what sort of interface it has (eg it
+ * persistently reports "10baseT" when none is fitted), running 'SOFTSET /BART'
+ * or 'SOFTSET /LISA' from DOS seems to help.
+ */
+
+/* Here's the scoop on memory mapping.
+ *
+ * There are three ways to access EtherExpress card memory: either using the
+ * shared-memory mapping, or using PIO through the dataport, or using PIO
+ * through the "shadow memory" ports.
+ *
+ * The shadow memory system works by having the card map some of its memory
+ * as follows:
+ *
+ * (the low five bits of the SMPTR are ignored)
+ *
+ *  base+0x4000..400f      memory at SMPTR+0..15
+ *  base+0x8000..800f      memory at SMPTR+16..31
+ *  base+0xc000..c007      dubious stuff (memory at SMPTR+16..23 apparently)
+ *  base+0xc008..c00f      memory at 0x0008..0x000f
+ *
+ * This last set (the one at c008) is particularly handy because the SCB
+ * lives at 0x0008.  So that set of ports gives us easy random access to data
+ * in the SCB without having to mess around setting up pointers and the like.
+ * We always use this method to access the SCB (via the scb_xx() functions).
+ *
+ * Dataport access works by aiming the appropriate (read or write) pointer
+ * at the first address you're interested in, and then reading or writing from
+ * the dataport.  The pointers auto-increment after each transfer.  We use
+ * this for data transfer.
+ *
+ * We don't use the shared-memory system because it allegedly doesn't work on
+ * all cards, and because it's a bit more prone to go wrong (it's one more
+ * thing to configure...).
+ */
+
+/* Known bugs:
+ *
+ * - The card seems to want to give us two interrupts every time something
+ *   happens, where just one would be better.
+ */
+
+/*
+ *
+ * Note by Zoltan Szilagyi 10-12-96:
+ *
+ * I've succeeded in eliminating the "CU wedged" messages, and hence the
+ * lockups, which were only occurring with cards running in 8-bit mode ("force
+ * 8-bit operation" in Intel's SoftSet utility). This version of the driver
+ * sets the 82586 and the ASIC to 8-bit mode at startup; it also stops the
+ * CU before submitting a packet for transmission, and then restarts it as soon
+ * as the process of handing the packet is complete. This is definitely an
+ * unnecessary slowdown if the card is running in 16-bit mode; therefore one
+ * should detect 16-bit vs 8-bit mode from the EEPROM settings and act
+ * accordingly. In 8-bit mode with this bugfix I'm getting about 150 K/s for
+ * ftp's, which is significantly better than I get in DOS, so the overhead of
+ * stopping and restarting the CU with each transmit is not prohibitive in
+ * practice.
+ *
+ * Update by David Woodhouse 11/5/99:
+ *
+ * I've seen "CU wedged" messages in 16-bit mode, on the Alpha architecture.
+ * I assume that this is because 16-bit accesses are actually handled as two
+ * 8-bit accesses.
+ */
+
+#ifdef __alpha__
+#define LOCKUP16 1
+#endif
+#ifndef LOCKUP16
+#define LOCKUP16 0
+#endif
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/string.h>
+#include <linux/in.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/mca-legacy.h>
+#include <linux/spinlock.h>
+#include <linux/bitops.h>
+#include <linux/jiffies.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#ifndef NET_DEBUG
+#define NET_DEBUG 4
+#endif
+
+#include "eexpress.h"
+
+#define EEXP_IO_EXTENT  16
+
+/*
+ * Private data declarations
+ */
+
+struct net_local
+{
+       unsigned long last_tx;       /* jiffies when last transmit started */
+       unsigned long init_time;     /* jiffies when eexp_hw_init586 called */
+       unsigned short rx_first;     /* first rx buf, same as RX_BUF_START */
+       unsigned short rx_last;      /* last rx buf */
+       unsigned short rx_ptr;       /* first rx buf to look at */
+       unsigned short tx_head;      /* next free tx buf */
+       unsigned short tx_reap;      /* first in-use tx buf */
+       unsigned short tx_tail;      /* previous tx buf to tx_head */
+       unsigned short tx_link;      /* last known-executing tx buf */
+       unsigned short last_tx_restart;   /* set to tx_link when we
+                                            restart the CU */
+       unsigned char started;
+       unsigned short rx_buf_start;
+       unsigned short rx_buf_end;
+       unsigned short num_tx_bufs;
+       unsigned short num_rx_bufs;
+       unsigned char width;         /* 0 for 16bit, 1 for 8bit */
+       unsigned char was_promisc;
+       unsigned char old_mc_count;
+       spinlock_t lock;
+};
+
+/* This is the code and data that is downloaded to the EtherExpress card's
+ * memory at boot time.
+ */
+
+static unsigned short start_code[] = {
+/* 0x0000 */
+       0x0001,                 /* ISCP: busy - cleared after reset */
+       0x0008,0x0000,0x0000,   /* offset,address (lo,hi) of SCB */
+
+       0x0000,0x0000,          /* SCB: status, commands */
+       0x0000,0x0000,          /* links to first command block,
+                                  first receive descriptor */
+       0x0000,0x0000,          /* CRC error, alignment error counts */
+       0x0000,0x0000,          /* out of resources, overrun error counts */
+
+       0x0000,0x0000,          /* pad */
+       0x0000,0x0000,
+
+/* 0x20 -- start of 82586 CU program */
+#define CONF_LINK 0x20
+       0x0000,Cmd_Config,
+       0x0032,                 /* link to next command */
+       0x080c,                 /* 12 bytes follow : fifo threshold=8 */
+       0x2e40,                 /* don't rx bad frames
+                                * SRDY/ARDY => ext. sync. : preamble len=8
+                                * take addresses from data buffers
+                                * 6 bytes/address
+                                */
+       0x6000,                 /* default backoff method & priority
+                                * interframe spacing = 0x60 */
+       0xf200,                 /* slot time=0x200
+                                * max collision retry = 0xf */
+#define CONF_PROMISC  0x2e
+       0x0000,                 /* no HDLC : normal CRC : enable broadcast
+                                * disable promiscuous/multicast modes */
+       0x003c,                 /* minimum frame length = 60 octets) */
+
+       0x0000,Cmd_SetAddr,
+       0x003e,                 /* link to next command */
+#define CONF_HWADDR  0x38
+       0x0000,0x0000,0x0000,   /* hardware address placed here */
+
+       0x0000,Cmd_MCast,
+       0x0076,                 /* link to next command */
+#define CONF_NR_MULTICAST 0x44
+       0x0000,                 /* number of bytes in multicast address(es) */
+#define CONF_MULTICAST 0x46
+       0x0000, 0x0000, 0x0000, /* some addresses */
+       0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000,
+
+#define CONF_DIAG_RESULT  0x76
+       0x0000, Cmd_Diag,
+       0x007c,                 /* link to next command */
+
+       0x0000,Cmd_TDR|Cmd_INT,
+       0x0084,
+#define CONF_TDR_RESULT  0x82
+       0x0000,
+
+       0x0000,Cmd_END|Cmd_Nop, /* end of configure sequence */
+       0x0084                  /* dummy link */
+};
+
+/* maps irq number to EtherExpress magic value */
+static char irqrmap[] = { 0,0,1,2,3,4,0,0,0,1,5,6,0,0,0,0 };
+
+#ifdef CONFIG_MCA_LEGACY
+/* mapping of the first four bits of the second POS register */
+static unsigned short mca_iomap[] = {
+       0x270, 0x260, 0x250, 0x240, 0x230, 0x220, 0x210, 0x200,
+       0x370, 0x360, 0x350, 0x340, 0x330, 0x320, 0x310, 0x300
+};
+/* bits 5-7 of the second POS register */
+static char mca_irqmap[] = { 12, 9, 3, 4, 5, 10, 11, 15 };
+#endif
+
+/*
+ * Prototypes for Linux interface
+ */
+
+static int eexp_open(struct net_device *dev);
+static int eexp_close(struct net_device *dev);
+static void eexp_timeout(struct net_device *dev);
+static netdev_tx_t eexp_xmit(struct sk_buff *buf,
+                            struct net_device *dev);
+
+static irqreturn_t eexp_irq(int irq, void *dev_addr);
+static void eexp_set_multicast(struct net_device *dev);
+
+/*
+ * Prototypes for hardware access functions
+ */
+
+static void eexp_hw_rx_pio(struct net_device *dev);
+static void eexp_hw_tx_pio(struct net_device *dev, unsigned short *buf,
+                      unsigned short len);
+static int eexp_hw_probe(struct net_device *dev,unsigned short ioaddr);
+static unsigned short eexp_hw_readeeprom(unsigned short ioaddr,
+                                        unsigned char location);
+
+static unsigned short eexp_hw_lasttxstat(struct net_device *dev);
+static void eexp_hw_txrestart(struct net_device *dev);
+
+static void eexp_hw_txinit    (struct net_device *dev);
+static void eexp_hw_rxinit    (struct net_device *dev);
+
+static void eexp_hw_init586   (struct net_device *dev);
+static void eexp_setup_filter (struct net_device *dev);
+
+static char *eexp_ifmap[]={"AUI", "BNC", "RJ45"};
+enum eexp_iftype {AUI=0, BNC=1, TPE=2};
+
+#define STARTED_RU      2
+#define STARTED_CU      1
+
+/*
+ * Primitive hardware access functions.
+ */
+
+static inline unsigned short scb_status(struct net_device *dev)
+{
+       return inw(dev->base_addr + 0xc008);
+}
+
+static inline unsigned short scb_rdcmd(struct net_device *dev)
+{
+       return inw(dev->base_addr + 0xc00a);
+}
+
+static inline void scb_command(struct net_device *dev, unsigned short cmd)
+{
+       outw(cmd, dev->base_addr + 0xc00a);
+}
+
+static inline void scb_wrcbl(struct net_device *dev, unsigned short val)
+{
+       outw(val, dev->base_addr + 0xc00c);
+}
+
+static inline void scb_wrrfa(struct net_device *dev, unsigned short val)
+{
+       outw(val, dev->base_addr + 0xc00e);
+}
+
+static inline void set_loopback(struct net_device *dev)
+{
+       outb(inb(dev->base_addr + Config) | 2, dev->base_addr + Config);
+}
+
+static inline void clear_loopback(struct net_device *dev)
+{
+       outb(inb(dev->base_addr + Config) & ~2, dev->base_addr + Config);
+}
+
+static inline unsigned short int SHADOW(short int addr)
+{
+       addr &= 0x1f;
+       if (addr > 0xf) addr += 0x3ff0;
+       return addr + 0x4000;
+}
+
+/*
+ * Linux interface
+ */
+
+/*
+ * checks for presence of EtherExpress card
+ */
+
+static int __init do_express_probe(struct net_device *dev)
+{
+       unsigned short *port;
+       static unsigned short ports[] = { 0x240,0x300,0x310,0x270,0x320,0x340,0 };
+       unsigned short ioaddr = dev->base_addr;
+       int dev_irq = dev->irq;
+       int err;
+
+       dev->if_port = 0xff; /* not set */
+
+#ifdef CONFIG_MCA_LEGACY
+       if (MCA_bus) {
+               int slot = 0;
+
+               /*
+                * Only find one card at a time.  Subsequent calls
+                * will find others, however, proper multicard MCA
+                * probing and setup can't be done with the
+                * old-style Space.c init routines.  -- ASF
+                */
+               while (slot != MCA_NOTFOUND) {
+                       int pos0, pos1;
+
+                       slot = mca_find_unused_adapter(0x628B, slot);
+                       if (slot == MCA_NOTFOUND)
+                               break;
+
+                       pos0 = mca_read_stored_pos(slot, 2);
+                       pos1 = mca_read_stored_pos(slot, 3);
+                       ioaddr = mca_iomap[pos1&0xf];
+
+                       dev->irq = mca_irqmap[(pos1>>4)&0x7];
+
+                       /*
+                        * XXX: Transceiver selection is done
+                        * differently on the MCA version.
+                        * How to get it to select something
+                        * other than external/AUI is currently
+                        * unknown.  This code is just for looks. -- ASF
+                        */
+                       if ((pos0 & 0x7) == 0x1)
+                               dev->if_port = AUI;
+                       else if ((pos0 & 0x7) == 0x5) {
+                               if (pos1 & 0x80)
+                                       dev->if_port = BNC;
+                               else
+                                       dev->if_port = TPE;
+                       }
+
+                       mca_set_adapter_name(slot, "Intel EtherExpress 16 MCA");
+                       mca_set_adapter_procfn(slot, NULL, dev);
+                       mca_mark_as_used(slot);
+
+                       break;
+               }
+       }
+#endif
+       if (ioaddr&0xfe00) {
+               if (!request_region(ioaddr, EEXP_IO_EXTENT, "EtherExpress"))
+                       return -EBUSY;
+               err = eexp_hw_probe(dev,ioaddr);
+               release_region(ioaddr, EEXP_IO_EXTENT);
+               return err;
+       } else if (ioaddr)
+               return -ENXIO;
+
+       for (port=&ports[0] ; *port ; port++ )
+       {
+               unsigned short sum = 0;
+               int i;
+               if (!request_region(*port, EEXP_IO_EXTENT, "EtherExpress"))
+                       continue;
+               for ( i=0 ; i<4 ; i++ )
+               {
+                       unsigned short t;
+                       t = inb(*port + ID_PORT);
+                       sum |= (t>>4) << ((t & 0x03)<<2);
+               }
+               if (sum==0xbaba && !eexp_hw_probe(dev,*port)) {
+                       release_region(*port, EEXP_IO_EXTENT);
+                       return 0;
+               }
+               release_region(*port, EEXP_IO_EXTENT);
+               dev->irq = dev_irq;
+       }
+       return -ENODEV;
+}
+
+#ifndef MODULE
+struct net_device * __init express_probe(int unit)
+{
+       struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
+       int err;
+
+       if (!dev)
+               return ERR_PTR(-ENOMEM);
+
+       sprintf(dev->name, "eth%d", unit);
+       netdev_boot_setup_check(dev);
+
+       err = do_express_probe(dev);
+       if (!err)
+               return dev;
+       free_netdev(dev);
+       return ERR_PTR(err);
+}
+#endif
+
+/*
+ * open and initialize the adapter, ready for use
+ */
+
+static int eexp_open(struct net_device *dev)
+{
+       int ret;
+       unsigned short ioaddr = dev->base_addr;
+       struct net_local *lp = netdev_priv(dev);
+
+#if NET_DEBUG > 6
+       printk(KERN_DEBUG "%s: eexp_open()\n", dev->name);
+#endif
+
+       if (!dev->irq || !irqrmap[dev->irq])
+               return -ENXIO;
+
+       ret = request_irq(dev->irq, eexp_irq, 0, dev->name, dev);
+       if (ret)
+               return ret;
+
+       if (!request_region(ioaddr, EEXP_IO_EXTENT, "EtherExpress")) {
+               printk(KERN_WARNING "EtherExpress io port %x, is busy.\n"
+                       , ioaddr);
+               goto err_out1;
+       }
+       if (!request_region(ioaddr+0x4000, EEXP_IO_EXTENT, "EtherExpress shadow")) {
+               printk(KERN_WARNING "EtherExpress io port %x, is busy.\n"
+                       , ioaddr+0x4000);
+               goto err_out2;
+       }
+       if (!request_region(ioaddr+0x8000, EEXP_IO_EXTENT, "EtherExpress shadow")) {
+               printk(KERN_WARNING "EtherExpress io port %x, is busy.\n"
+                       , ioaddr+0x8000);
+               goto err_out3;
+       }
+       if (!request_region(ioaddr+0xc000, EEXP_IO_EXTENT, "EtherExpress shadow")) {
+               printk(KERN_WARNING "EtherExpress io port %x, is busy.\n"
+                       , ioaddr+0xc000);
+               goto err_out4;
+       }
+
+       if (lp->width) {
+               printk("%s: forcing ASIC to 8-bit mode\n", dev->name);
+               outb(inb(dev->base_addr+Config)&~4, dev->base_addr+Config);
+       }
+
+       eexp_hw_init586(dev);
+       netif_start_queue(dev);
+#if NET_DEBUG > 6
+       printk(KERN_DEBUG "%s: leaving eexp_open()\n", dev->name);
+#endif
+       return 0;
+
+       err_out4:
+               release_region(ioaddr+0x8000, EEXP_IO_EXTENT);
+       err_out3:
+               release_region(ioaddr+0x4000, EEXP_IO_EXTENT);
+       err_out2:
+               release_region(ioaddr, EEXP_IO_EXTENT);
+       err_out1:
+               free_irq(dev->irq, dev);
+               return -EBUSY;
+}
+
+/*
+ * close and disable the interface, leaving the 586 in reset.
+ */
+
+static int eexp_close(struct net_device *dev)
+{
+       unsigned short ioaddr = dev->base_addr;
+       struct net_local *lp = netdev_priv(dev);
+
+       int irq = dev->irq;
+
+       netif_stop_queue(dev);
+
+       outb(SIRQ_dis|irqrmap[irq],ioaddr+SET_IRQ);
+       lp->started = 0;
+       scb_command(dev, SCB_CUsuspend|SCB_RUsuspend);
+       outb(0,ioaddr+SIGNAL_CA);
+       free_irq(irq,dev);
+       outb(i586_RST,ioaddr+EEPROM_Ctrl);
+       release_region(ioaddr, EEXP_IO_EXTENT);
+       release_region(ioaddr+0x4000, 16);
+       release_region(ioaddr+0x8000, 16);
+       release_region(ioaddr+0xc000, 16);
+
+       return 0;
+}
+
+/*
+ * This gets called when a higher level thinks we are broken.  Check that
+ * nothing has become jammed in the CU.
+ */
+
+static void unstick_cu(struct net_device *dev)
+{
+       struct net_local *lp = netdev_priv(dev);
+       unsigned short ioaddr = dev->base_addr;
+
+       if (lp->started)
+       {
+               if (time_after(jiffies, dev_trans_start(dev) + HZ/2))
+               {
+                       if (lp->tx_link==lp->last_tx_restart)
+                       {
+                               unsigned short boguscount=200,rsst;
+                               printk(KERN_WARNING "%s: Retransmit timed out, status %04x, resetting...\n",
+                                      dev->name, scb_status(dev));
+                               eexp_hw_txinit(dev);
+                               lp->last_tx_restart = 0;
+                               scb_wrcbl(dev, lp->tx_link);
+                               scb_command(dev, SCB_CUstart);
+                               outb(0,ioaddr+SIGNAL_CA);
+                               while (!SCB_complete(rsst=scb_status(dev)))
+                               {
+                                       if (!--boguscount)
+                                       {
+                                               boguscount=200;
+                                               printk(KERN_WARNING "%s: Reset timed out status %04x, retrying...\n",
+                                                      dev->name,rsst);
+                                               scb_wrcbl(dev, lp->tx_link);
+                                               scb_command(dev, SCB_CUstart);
+                                               outb(0,ioaddr+SIGNAL_CA);
+                                       }
+                               }
+                               netif_wake_queue(dev);
+                       }
+                       else
+                       {
+                               unsigned short status = scb_status(dev);
+                               if (SCB_CUdead(status))
+                               {
+                                       unsigned short txstatus = eexp_hw_lasttxstat(dev);
+                                       printk(KERN_WARNING "%s: Transmit timed out, CU not active status %04x %04x, restarting...\n",
+                                              dev->name, status, txstatus);
+                                       eexp_hw_txrestart(dev);
+                               }
+                               else
+                               {
+                                       unsigned short txstatus = eexp_hw_lasttxstat(dev);
+                                       if (netif_queue_stopped(dev) && !txstatus)
+                                       {
+                                               printk(KERN_WARNING "%s: CU wedged, status %04x %04x, resetting...\n",
+                                                      dev->name,status,txstatus);
+                                               eexp_hw_init586(dev);
+                                               netif_wake_queue(dev);
+                                       }
+                                       else
+                                       {
+                                               printk(KERN_WARNING "%s: transmit timed out\n", dev->name);
+                                       }
+                               }
+                       }
+               }
+       }
+       else
+       {
+               if (time_after(jiffies, lp->init_time + 10))
+               {
+                       unsigned short status = scb_status(dev);
+                       printk(KERN_WARNING "%s: i82586 startup timed out, status %04x, resetting...\n",
+                              dev->name, status);
+                       eexp_hw_init586(dev);
+                       netif_wake_queue(dev);
+               }
+       }
+}
+
+static void eexp_timeout(struct net_device *dev)
+{
+       struct net_local *lp = netdev_priv(dev);
+#ifdef CONFIG_SMP
+       unsigned long flags;
+#endif
+       int status;
+
+       disable_irq(dev->irq);
+
+       /*
+        *      Best would be to use synchronize_irq(); spin_lock() here
+        *      lets make it work first..
+        */
+
+#ifdef CONFIG_SMP
+       spin_lock_irqsave(&lp->lock, flags);
+#endif
+
+       status = scb_status(dev);
+       unstick_cu(dev);
+       printk(KERN_INFO "%s: transmit timed out, %s?\n", dev->name,
+              (SCB_complete(status)?"lost interrupt":
+               "board on fire"));
+       dev->stats.tx_errors++;
+       lp->last_tx = jiffies;
+       if (!SCB_complete(status)) {
+               scb_command(dev, SCB_CUabort);
+               outb(0,dev->base_addr+SIGNAL_CA);
+       }
+       netif_wake_queue(dev);
+#ifdef CONFIG_SMP
+       spin_unlock_irqrestore(&lp->lock, flags);
+#endif
+}
+
+/*
+ * Called to transmit a packet, or to allow us to right ourselves
+ * if the kernel thinks we've died.
+ */
+static netdev_tx_t eexp_xmit(struct sk_buff *buf, struct net_device *dev)
+{
+       short length = buf->len;
+#ifdef CONFIG_SMP
+       struct net_local *lp = netdev_priv(dev);
+       unsigned long flags;
+#endif
+
+#if NET_DEBUG > 6
+       printk(KERN_DEBUG "%s: eexp_xmit()\n", dev->name);
+#endif
+
+       if (buf->len < ETH_ZLEN) {
+               if (skb_padto(buf, ETH_ZLEN))
+                       return NETDEV_TX_OK;
+               length = ETH_ZLEN;
+       }
+
+       disable_irq(dev->irq);
+
+       /*
+        *      Best would be to use synchronize_irq(); spin_lock() here
+        *      lets make it work first..
+        */
+
+#ifdef CONFIG_SMP
+       spin_lock_irqsave(&lp->lock, flags);
+#endif
+
+       {
+               unsigned short *data = (unsigned short *)buf->data;
+
+               dev->stats.tx_bytes += length;
+
+               eexp_hw_tx_pio(dev,data,length);
+       }
+       dev_kfree_skb(buf);
+#ifdef CONFIG_SMP
+       spin_unlock_irqrestore(&lp->lock, flags);
+#endif
+       enable_irq(dev->irq);
+       return NETDEV_TX_OK;
+}
+
+/*
+ * Handle an EtherExpress interrupt
+ * If we've finished initializing, start the RU and CU up.
+ * If we've already started, reap tx buffers, handle any received packets,
+ * check to make sure we've not become wedged.
+ */
+
+static unsigned short eexp_start_irq(struct net_device *dev,
+                                    unsigned short status)
+{
+       unsigned short ack_cmd = SCB_ack(status);
+       struct net_local *lp = netdev_priv(dev);
+       unsigned short ioaddr = dev->base_addr;
+       if ((dev->flags & IFF_UP) && !(lp->started & STARTED_CU)) {
+               short diag_status, tdr_status;
+               while (SCB_CUstat(status)==2)
+                       status = scb_status(dev);
+#if NET_DEBUG > 4
+               printk("%s: CU went non-active (status %04x)\n",
+                      dev->name, status);
+#endif
+
+               outw(CONF_DIAG_RESULT & ~31, ioaddr + SM_PTR);
+               diag_status = inw(ioaddr + SHADOW(CONF_DIAG_RESULT));
+               if (diag_status & 1<<11) {
+                       printk(KERN_WARNING "%s: 82586 failed self-test\n",
+                              dev->name);
+               } else if (!(diag_status & 1<<13)) {
+                       printk(KERN_WARNING "%s: 82586 self-test failed to complete\n", dev->name);
+               }
+
+               outw(CONF_TDR_RESULT & ~31, ioaddr + SM_PTR);
+               tdr_status = inw(ioaddr + SHADOW(CONF_TDR_RESULT));
+               if (tdr_status & (TDR_SHORT|TDR_OPEN)) {
+                       printk(KERN_WARNING "%s: TDR reports cable %s at %d tick%s\n", dev->name, (tdr_status & TDR_SHORT)?"short":"broken", tdr_status & TDR_TIME, ((tdr_status & TDR_TIME) != 1) ? "s" : "");
+               }
+               else if (tdr_status & TDR_XCVRPROBLEM) {
+                       printk(KERN_WARNING "%s: TDR reports transceiver problem\n", dev->name);
+               }
+               else if (tdr_status & TDR_LINKOK) {
+#if NET_DEBUG > 4
+                       printk(KERN_DEBUG "%s: TDR reports link OK\n", dev->name);
+#endif
+               } else {
+                       printk("%s: TDR is ga-ga (status %04x)\n", dev->name,
+                              tdr_status);
+               }
+
+               lp->started |= STARTED_CU;
+               scb_wrcbl(dev, lp->tx_link);
+               /* if the RU isn't running, start it now */
+               if (!(lp->started & STARTED_RU)) {
+                       ack_cmd |= SCB_RUstart;
+                       scb_wrrfa(dev, lp->rx_buf_start);
+                       lp->rx_ptr = lp->rx_buf_start;
+                       lp->started |= STARTED_RU;
+               }
+               ack_cmd |= SCB_CUstart | 0x2000;
+       }
+
+       if ((dev->flags & IFF_UP) && !(lp->started & STARTED_RU) && SCB_RUstat(status)==4)
+               lp->started|=STARTED_RU;
+
+       return ack_cmd;
+}
+
+static void eexp_cmd_clear(struct net_device *dev)
+{
+       unsigned long int oldtime = jiffies;
+       while (scb_rdcmd(dev) && (time_before(jiffies, oldtime + 10)));
+       if (scb_rdcmd(dev)) {
+               printk("%s: command didn't clear\n", dev->name);
+       }
+}
+
+static irqreturn_t eexp_irq(int dummy, void *dev_info)
+{
+       struct net_device *dev = dev_info;
+       struct net_local *lp;
+       unsigned short ioaddr,status,ack_cmd;
+       unsigned short old_read_ptr, old_write_ptr;
+
+       lp = netdev_priv(dev);
+       ioaddr = dev->base_addr;
+
+       spin_lock(&lp->lock);
+
+       old_read_ptr = inw(ioaddr+READ_PTR);
+       old_write_ptr = inw(ioaddr+WRITE_PTR);
+
+       outb(SIRQ_dis|irqrmap[dev->irq], ioaddr+SET_IRQ);
+
+       status = scb_status(dev);
+
+#if NET_DEBUG > 4
+       printk(KERN_DEBUG "%s: interrupt (status %x)\n", dev->name, status);
+#endif
+
+       if (lp->started == (STARTED_CU | STARTED_RU)) {
+
+               do {
+                       eexp_cmd_clear(dev);
+
+                       ack_cmd = SCB_ack(status);
+                       scb_command(dev, ack_cmd);
+                       outb(0,ioaddr+SIGNAL_CA);
+
+                       eexp_cmd_clear(dev);
+
+                       if (SCB_complete(status)) {
+                               if (!eexp_hw_lasttxstat(dev)) {
+                                       printk("%s: tx interrupt but no status\n", dev->name);
+                               }
+                       }
+
+                       if (SCB_rxdframe(status))
+                               eexp_hw_rx_pio(dev);
+
+                       status = scb_status(dev);
+               } while (status & 0xc000);
+
+               if (SCB_RUdead(status))
+               {
+                       printk(KERN_WARNING "%s: RU stopped: status %04x\n",
+                              dev->name,status);
+#if 0
+                       printk(KERN_WARNING "%s: cur_rfd=%04x, cur_rbd=%04x\n", dev->name, lp->cur_rfd, lp->cur_rbd);
+                       outw(lp->cur_rfd, ioaddr+READ_PTR);
+                       printk(KERN_WARNING "%s: [%04x]\n", dev->name, inw(ioaddr+DATAPORT));
+                       outw(lp->cur_rfd+6, ioaddr+READ_PTR);
+                       printk(KERN_WARNING "%s: rbd is %04x\n", dev->name, rbd= inw(ioaddr+DATAPORT));
+                       outw(rbd, ioaddr+READ_PTR);
+                       printk(KERN_WARNING "%s: [%04x %04x] ", dev->name, inw(ioaddr+DATAPORT), inw(ioaddr+DATAPORT));
+                       outw(rbd+8, ioaddr+READ_PTR);
+                       printk("[%04x]\n", inw(ioaddr+DATAPORT));
+#endif
+                       dev->stats.rx_errors++;
+#if 1
+                       eexp_hw_rxinit(dev);
+#else
+                       lp->cur_rfd = lp->first_rfd;
+#endif
+                       scb_wrrfa(dev, lp->rx_buf_start);
+                       scb_command(dev, SCB_RUstart);
+                       outb(0,ioaddr+SIGNAL_CA);
+               }
+       } else {
+               if (status & 0x8000)
+                       ack_cmd = eexp_start_irq(dev, status);
+               else
+                       ack_cmd = SCB_ack(status);
+               scb_command(dev, ack_cmd);
+               outb(0,ioaddr+SIGNAL_CA);
+       }
+
+       eexp_cmd_clear(dev);
+
+       outb(SIRQ_en|irqrmap[dev->irq], ioaddr+SET_IRQ);
+
+#if NET_DEBUG > 6
+       printk("%s: leaving eexp_irq()\n", dev->name);
+#endif
+       outw(old_read_ptr, ioaddr+READ_PTR);
+       outw(old_write_ptr, ioaddr+WRITE_PTR);
+
+       spin_unlock(&lp->lock);
+       return IRQ_HANDLED;
+}
+
+/*
+ * Hardware access functions
+ */
+
+/*
+ * Set the cable type to use.
+ */
+
+static void eexp_hw_set_interface(struct net_device *dev)
+{
+       unsigned char oldval = inb(dev->base_addr + 0x300e);
+       oldval &= ~0x82;
+       switch (dev->if_port) {
+       case TPE:
+               oldval |= 0x2;
+       case BNC:
+               oldval |= 0x80;
+               break;
+       }
+       outb(oldval, dev->base_addr+0x300e);
+       mdelay(20);
+}
+
+/*
+ * Check all the receive buffers, and hand any received packets
+ * to the upper levels. Basic sanity check on each frame
+ * descriptor, though we don't bother trying to fix broken ones.
+ */
+
+static void eexp_hw_rx_pio(struct net_device *dev)
+{
+       struct net_local *lp = netdev_priv(dev);
+       unsigned short rx_block = lp->rx_ptr;
+       unsigned short boguscount = lp->num_rx_bufs;
+       unsigned short ioaddr = dev->base_addr;
+       unsigned short status;
+
+#if NET_DEBUG > 6
+       printk(KERN_DEBUG "%s: eexp_hw_rx()\n", dev->name);
+#endif
+
+       do {
+               unsigned short rfd_cmd, rx_next, pbuf, pkt_len;
+
+               outw(rx_block, ioaddr + READ_PTR);
+               status = inw(ioaddr + DATAPORT);
+
+               if (FD_Done(status))
+               {
+                       rfd_cmd = inw(ioaddr + DATAPORT);
+                       rx_next = inw(ioaddr + DATAPORT);
+                       pbuf = inw(ioaddr + DATAPORT);
+
+                       outw(pbuf, ioaddr + READ_PTR);
+                       pkt_len = inw(ioaddr + DATAPORT);
+
+                       if (rfd_cmd!=0x0000)
+                       {
+                               printk(KERN_WARNING "%s: rfd_cmd not zero:0x%04x\n",
+                                      dev->name, rfd_cmd);
+                               continue;
+                       }
+                       else if (pbuf!=rx_block+0x16)
+                       {
+                               printk(KERN_WARNING "%s: rfd and rbd out of sync 0x%04x 0x%04x\n",
+                                      dev->name, rx_block+0x16, pbuf);
+                               continue;
+                       }
+                       else if ((pkt_len & 0xc000)!=0xc000)
+                       {
+                               printk(KERN_WARNING "%s: EOF or F not set on received buffer (%04x)\n",
+                                      dev->name, pkt_len & 0xc000);
+                               continue;
+                       }
+                       else if (!FD_OK(status))
+                       {
+                               dev->stats.rx_errors++;
+                               if (FD_CRC(status))
+                                       dev->stats.rx_crc_errors++;
+                               if (FD_Align(status))
+                                       dev->stats.rx_frame_errors++;
+                               if (FD_Resrc(status))
+                                       dev->stats.rx_fifo_errors++;
+                               if (FD_DMA(status))
+                                       dev->stats.rx_over_errors++;
+                               if (FD_Short(status))
+                                       dev->stats.rx_length_errors++;
+                       }
+                       else
+                       {
+                               struct sk_buff *skb;
+                               pkt_len &= 0x3fff;
+                               skb = dev_alloc_skb(pkt_len+16);
+                               if (skb == NULL)
+                               {
+                                       printk(KERN_WARNING "%s: Memory squeeze, dropping packet\n",dev->name);
+                                       dev->stats.rx_dropped++;
+                                       break;
+                               }
+                               skb_reserve(skb, 2);
+                               outw(pbuf+10, ioaddr+READ_PTR);
+                               insw(ioaddr+DATAPORT, skb_put(skb,pkt_len),(pkt_len+1)>>1);
+                               skb->protocol = eth_type_trans(skb,dev);
+                               netif_rx(skb);
+                               dev->stats.rx_packets++;
+                               dev->stats.rx_bytes += pkt_len;
+                       }
+                       outw(rx_block, ioaddr+WRITE_PTR);
+                       outw(0, ioaddr+DATAPORT);
+                       outw(0, ioaddr+DATAPORT);
+                       rx_block = rx_next;
+               }
+       } while (FD_Done(status) && boguscount--);
+       lp->rx_ptr = rx_block;
+}
+
+/*
+ * Hand a packet to the card for transmission
+ * If we get here, we MUST have already checked
+ * to make sure there is room in the transmit
+ * buffer region.
+ */
+
+static void eexp_hw_tx_pio(struct net_device *dev, unsigned short *buf,
+                      unsigned short len)
+{
+       struct net_local *lp = netdev_priv(dev);
+       unsigned short ioaddr = dev->base_addr;
+
+       if (LOCKUP16 || lp->width) {
+               /* Stop the CU so that there is no chance that it
+                  jumps off to a bogus address while we are writing the
+                  pointer to the next transmit packet in 8-bit mode --
+                  this eliminates the "CU wedged" errors in 8-bit mode.
+                  (Zoltan Szilagyi 10-12-96) */
+               scb_command(dev, SCB_CUsuspend);
+               outw(0xFFFF, ioaddr+SIGNAL_CA);
+       }
+
+       outw(lp->tx_head, ioaddr + WRITE_PTR);
+
+       outw(0x0000, ioaddr + DATAPORT);
+        outw(Cmd_INT|Cmd_Xmit, ioaddr + DATAPORT);
+       outw(lp->tx_head+0x08, ioaddr + DATAPORT);
+       outw(lp->tx_head+0x0e, ioaddr + DATAPORT);
+
+       outw(0x0000, ioaddr + DATAPORT);
+       outw(0x0000, ioaddr + DATAPORT);
+       outw(lp->tx_head+0x08, ioaddr + DATAPORT);
+
+       outw(0x8000|len, ioaddr + DATAPORT);
+       outw(-1, ioaddr + DATAPORT);
+       outw(lp->tx_head+0x16, ioaddr + DATAPORT);
+       outw(0, ioaddr + DATAPORT);
+
+       outsw(ioaddr + DATAPORT, buf, (len+1)>>1);
+
+       outw(lp->tx_tail+0xc, ioaddr + WRITE_PTR);
+       outw(lp->tx_head, ioaddr + DATAPORT);
+
+       dev->trans_start = jiffies;
+       lp->tx_tail = lp->tx_head;
+       if (lp->tx_head==TX_BUF_START+((lp->num_tx_bufs-1)*TX_BUF_SIZE))
+               lp->tx_head = TX_BUF_START;
+       else
+               lp->tx_head += TX_BUF_SIZE;
+       if (lp->tx_head != lp->tx_reap)
+               netif_wake_queue(dev);
+
+       if (LOCKUP16 || lp->width) {
+               /* Restart the CU so that the packet can actually
+                  be transmitted. (Zoltan Szilagyi 10-12-96) */
+               scb_command(dev, SCB_CUresume);
+               outw(0xFFFF, ioaddr+SIGNAL_CA);
+       }
+
+       dev->stats.tx_packets++;
+       lp->last_tx = jiffies;
+}
+
+static const struct net_device_ops eexp_netdev_ops = {
+       .ndo_open               = eexp_open,
+       .ndo_stop               = eexp_close,
+       .ndo_start_xmit         = eexp_xmit,
+       .ndo_set_multicast_list = eexp_set_multicast,
+       .ndo_tx_timeout         = eexp_timeout,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
+/*
+ * Sanity check the suspected EtherExpress card
+ * Read hardware address, reset card, size memory and initialize buffer
+ * memory pointers. These are held in netdev_priv(), in case someone has more
+ * than one card in a machine.
+ */
+
+static int __init eexp_hw_probe(struct net_device *dev, unsigned short ioaddr)
+{
+       unsigned short hw_addr[3];
+       unsigned char buswidth;
+       unsigned int memory_size;
+       int i;
+       unsigned short xsum = 0;
+       struct net_local *lp = netdev_priv(dev);
+
+       printk("%s: EtherExpress 16 at %#x ",dev->name,ioaddr);
+
+       outb(ASIC_RST, ioaddr+EEPROM_Ctrl);
+       outb(0, ioaddr+EEPROM_Ctrl);
+       udelay(500);
+       outb(i586_RST, ioaddr+EEPROM_Ctrl);
+
+       hw_addr[0] = eexp_hw_readeeprom(ioaddr,2);
+       hw_addr[1] = eexp_hw_readeeprom(ioaddr,3);
+       hw_addr[2] = eexp_hw_readeeprom(ioaddr,4);
+
+       /* Standard Address or Compaq LTE Address */
+       if (!((hw_addr[2]==0x00aa && ((hw_addr[1] & 0xff00)==0x0000)) ||
+             (hw_addr[2]==0x0080 && ((hw_addr[1] & 0xff00)==0x5F00))))
+       {
+               printk(" rejected: invalid address %04x%04x%04x\n",
+                       hw_addr[2],hw_addr[1],hw_addr[0]);
+               return -ENODEV;
+       }
+
+       /* Calculate the EEPROM checksum.  Carry on anyway if it's bad,
+        * though.
+        */
+       for (i = 0; i < 64; i++)
+               xsum += eexp_hw_readeeprom(ioaddr, i);
+       if (xsum != 0xbaba)
+               printk(" (bad EEPROM xsum 0x%02x)", xsum);
+
+       dev->base_addr = ioaddr;
+       for ( i=0 ; i<6 ; i++ )
+               dev->dev_addr[i] = ((unsigned char *)hw_addr)[5-i];
+
+       {
+               static const char irqmap[] = { 0, 9, 3, 4, 5, 10, 11, 0 };
+               unsigned short setupval = eexp_hw_readeeprom(ioaddr,0);
+
+               /* Use the IRQ from EEPROM if none was given */
+               if (!dev->irq)
+                       dev->irq = irqmap[setupval>>13];
+
+               if (dev->if_port == 0xff) {
+                       dev->if_port = !(setupval & 0x1000) ? AUI :
+                               eexp_hw_readeeprom(ioaddr,5) & 0x1 ? TPE : BNC;
+               }
+
+               buswidth = !((setupval & 0x400) >> 10);
+       }
+
+       memset(lp, 0, sizeof(struct net_local));
+       spin_lock_init(&lp->lock);
+
+       printk("(IRQ %d, %s connector, %d-bit bus", dev->irq,
+              eexp_ifmap[dev->if_port], buswidth?8:16);
+
+       if (!request_region(dev->base_addr + 0x300e, 1, "EtherExpress"))
+               return -EBUSY;
+
+       eexp_hw_set_interface(dev);
+
+       release_region(dev->base_addr + 0x300e, 1);
+
+       /* Find out how much RAM we have on the card */
+       outw(0, dev->base_addr + WRITE_PTR);
+       for (i = 0; i < 32768; i++)
+               outw(0, dev->base_addr + DATAPORT);
+
+        for (memory_size = 0; memory_size < 64; memory_size++)
+       {
+               outw(memory_size<<10, dev->base_addr + READ_PTR);
+               if (inw(dev->base_addr+DATAPORT))
+                       break;
+               outw(memory_size<<10, dev->base_addr + WRITE_PTR);
+               outw(memory_size | 0x5000, dev->base_addr+DATAPORT);
+               outw(memory_size<<10, dev->base_addr + READ_PTR);
+               if (inw(dev->base_addr+DATAPORT) != (memory_size | 0x5000))
+                       break;
+       }
+
+       /* Sort out the number of buffers.  We may have 16, 32, 48 or 64k
+        * of RAM to play with.
+        */
+       lp->num_tx_bufs = 4;
+       lp->rx_buf_end = 0x3ff6;
+       switch (memory_size)
+       {
+       case 64:
+               lp->rx_buf_end += 0x4000;
+       case 48:
+               lp->num_tx_bufs += 4;
+               lp->rx_buf_end += 0x4000;
+       case 32:
+               lp->rx_buf_end += 0x4000;
+       case 16:
+               printk(", %dk RAM)\n", memory_size);
+               break;
+       default:
+               printk(") bad memory size (%dk).\n", memory_size);
+               return -ENODEV;
+               break;
+       }
+
+       lp->rx_buf_start = TX_BUF_START + (lp->num_tx_bufs*TX_BUF_SIZE);
+       lp->width = buswidth;
+
+       dev->netdev_ops = &eexp_netdev_ops;
+       dev->watchdog_timeo = 2*HZ;
+
+       return register_netdev(dev);
+}
+
+/*
+ * Read a word from the EtherExpress on-board serial EEPROM.
+ * The EEPROM contains 64 words of 16 bits.
+ */
+static unsigned short __init eexp_hw_readeeprom(unsigned short ioaddr,
+                                                   unsigned char location)
+{
+       unsigned short cmd = 0x180|(location&0x7f);
+       unsigned short rval = 0,wval = EC_CS|i586_RST;
+       int i;
+
+       outb(EC_CS|i586_RST,ioaddr+EEPROM_Ctrl);
+       for (i=0x100 ; i ; i>>=1 )
+       {
+               if (cmd&i)
+                       wval |= EC_Wr;
+               else
+                       wval &= ~EC_Wr;
+
+               outb(wval,ioaddr+EEPROM_Ctrl);
+               outb(wval|EC_Clk,ioaddr+EEPROM_Ctrl);
+               eeprom_delay();
+               outb(wval,ioaddr+EEPROM_Ctrl);
+               eeprom_delay();
+       }
+       wval &= ~EC_Wr;
+       outb(wval,ioaddr+EEPROM_Ctrl);
+       for (i=0x8000 ; i ; i>>=1 )
+       {
+               outb(wval|EC_Clk,ioaddr+EEPROM_Ctrl);
+               eeprom_delay();
+               if (inb(ioaddr+EEPROM_Ctrl)&EC_Rd)
+                       rval |= i;
+               outb(wval,ioaddr+EEPROM_Ctrl);
+               eeprom_delay();
+       }
+       wval &= ~EC_CS;
+       outb(wval|EC_Clk,ioaddr+EEPROM_Ctrl);
+       eeprom_delay();
+       outb(wval,ioaddr+EEPROM_Ctrl);
+       eeprom_delay();
+       return rval;
+}
+
+/*
+ * Reap tx buffers and return last transmit status.
+ * if ==0 then either:
+ *    a) we're not transmitting anything, so why are we here?
+ *    b) we've died.
+ * otherwise, Stat_Busy(return) means we've still got some packets
+ * to transmit, Stat_Done(return) means our buffers should be empty
+ * again
+ */
+
+static unsigned short eexp_hw_lasttxstat(struct net_device *dev)
+{
+       struct net_local *lp = netdev_priv(dev);
+       unsigned short tx_block = lp->tx_reap;
+       unsigned short status;
+
+       if (!netif_queue_stopped(dev) && lp->tx_head==lp->tx_reap)
+               return 0x0000;
+
+       do
+       {
+               outw(tx_block & ~31, dev->base_addr + SM_PTR);
+               status = inw(dev->base_addr + SHADOW(tx_block));
+               if (!Stat_Done(status))
+               {
+                       lp->tx_link = tx_block;
+                       return status;
+               }
+               else
+               {
+                       lp->last_tx_restart = 0;
+                       dev->stats.collisions += Stat_NoColl(status);
+                       if (!Stat_OK(status))
+                       {
+                               char *whatsup = NULL;
+                               dev->stats.tx_errors++;
+                               if (Stat_Abort(status))
+                                       dev->stats.tx_aborted_errors++;
+                               if (Stat_TNoCar(status)) {
+                                       whatsup = "aborted, no carrier";
+                                       dev->stats.tx_carrier_errors++;
+                               }
+                               if (Stat_TNoCTS(status)) {
+                                       whatsup = "aborted, lost CTS";
+                                       dev->stats.tx_carrier_errors++;
+                               }
+                               if (Stat_TNoDMA(status)) {
+                                       whatsup = "FIFO underran";
+                                       dev->stats.tx_fifo_errors++;
+                               }
+                               if (Stat_TXColl(status)) {
+                                       whatsup = "aborted, too many collisions";
+                                       dev->stats.tx_aborted_errors++;
+                               }
+                               if (whatsup)
+                                       printk(KERN_INFO "%s: transmit %s\n",
+                                              dev->name, whatsup);
+                       }
+                       else
+                               dev->stats.tx_packets++;
+               }
+               if (tx_block == TX_BUF_START+((lp->num_tx_bufs-1)*TX_BUF_SIZE))
+                       lp->tx_reap = tx_block = TX_BUF_START;
+               else
+                       lp->tx_reap = tx_block += TX_BUF_SIZE;
+               netif_wake_queue(dev);
+       }
+       while (lp->tx_reap != lp->tx_head);
+
+       lp->tx_link = lp->tx_tail + 0x08;
+
+       return status;
+}
+
+/*
+ * This should never happen. It is called when some higher routine detects
+ * that the CU has stopped, to try to restart it from the last packet we knew
+ * we were working on, or the idle loop if we had finished for the time.
+ */
+
+static void eexp_hw_txrestart(struct net_device *dev)
+{
+       struct net_local *lp = netdev_priv(dev);
+       unsigned short ioaddr = dev->base_addr;
+
+       lp->last_tx_restart = lp->tx_link;
+       scb_wrcbl(dev, lp->tx_link);
+       scb_command(dev, SCB_CUstart);
+       outb(0,ioaddr+SIGNAL_CA);
+
+       {
+               unsigned short boguscount=50,failcount=5;
+               while (!scb_status(dev))
+               {
+                       if (!--boguscount)
+                       {
+                               if (--failcount)
+                               {
+                                       printk(KERN_WARNING "%s: CU start timed out, status %04x, cmd %04x\n", dev->name, scb_status(dev), scb_rdcmd(dev));
+                                       scb_wrcbl(dev, lp->tx_link);
+                                       scb_command(dev, SCB_CUstart);
+                                       outb(0,ioaddr+SIGNAL_CA);
+                                       boguscount = 100;
+                               }
+                               else
+                               {
+                                       printk(KERN_WARNING "%s: Failed to restart CU, resetting board...\n",dev->name);
+                                       eexp_hw_init586(dev);
+                                       netif_wake_queue(dev);
+                                       return;
+                               }
+                       }
+               }
+       }
+}
+
+/*
+ * Writes down the list of transmit buffers into card memory.  Each
+ * entry consists of an 82586 transmit command, followed by a jump
+ * pointing to itself.  When we want to transmit a packet, we write
+ * the data into the appropriate transmit buffer and then modify the
+ * preceding jump to point at the new transmit command.  This means that
+ * the 586 command unit is continuously active.
+ */
+
+static void eexp_hw_txinit(struct net_device *dev)
+{
+       struct net_local *lp = netdev_priv(dev);
+       unsigned short tx_block = TX_BUF_START;
+       unsigned short curtbuf;
+       unsigned short ioaddr = dev->base_addr;
+
+       for ( curtbuf=0 ; curtbuf<lp->num_tx_bufs ; curtbuf++ )
+       {
+               outw(tx_block, ioaddr + WRITE_PTR);
+
+               outw(0x0000, ioaddr + DATAPORT);
+               outw(Cmd_INT|Cmd_Xmit, ioaddr + DATAPORT);
+               outw(tx_block+0x08, ioaddr + DATAPORT);
+               outw(tx_block+0x0e, ioaddr + DATAPORT);
+
+               outw(0x0000, ioaddr + DATAPORT);
+               outw(0x0000, ioaddr + DATAPORT);
+               outw(tx_block+0x08, ioaddr + DATAPORT);
+
+               outw(0x8000, ioaddr + DATAPORT);
+               outw(-1, ioaddr + DATAPORT);
+               outw(tx_block+0x16, ioaddr + DATAPORT);
+               outw(0x0000, ioaddr + DATAPORT);
+
+               tx_block += TX_BUF_SIZE;
+       }
+       lp->tx_head = TX_BUF_START;
+       lp->tx_reap = TX_BUF_START;
+       lp->tx_tail = tx_block - TX_BUF_SIZE;
+       lp->tx_link = lp->tx_tail + 0x08;
+       lp->rx_buf_start = tx_block;
+
+}
+
+/*
+ * Write the circular list of receive buffer descriptors to card memory.
+ * The end of the list isn't marked, which means that the 82586 receive
+ * unit will loop until buffers become available (this avoids it giving us
+ * "out of resources" messages).
+ */
+
+static void eexp_hw_rxinit(struct net_device *dev)
+{
+       struct net_local *lp = netdev_priv(dev);
+       unsigned short rx_block = lp->rx_buf_start;
+       unsigned short ioaddr = dev->base_addr;
+
+       lp->num_rx_bufs = 0;
+       lp->rx_first = lp->rx_ptr = rx_block;
+       do
+       {
+               lp->num_rx_bufs++;
+
+               outw(rx_block, ioaddr + WRITE_PTR);
+
+               outw(0, ioaddr + DATAPORT);  outw(0, ioaddr+DATAPORT);
+               outw(rx_block + RX_BUF_SIZE, ioaddr+DATAPORT);
+               outw(0xffff, ioaddr+DATAPORT);
+
+               outw(0x0000, ioaddr+DATAPORT);
+               outw(0xdead, ioaddr+DATAPORT);
+               outw(0xdead, ioaddr+DATAPORT);
+               outw(0xdead, ioaddr+DATAPORT);
+               outw(0xdead, ioaddr+DATAPORT);
+               outw(0xdead, ioaddr+DATAPORT);
+               outw(0xdead, ioaddr+DATAPORT);
+
+               outw(0x0000, ioaddr+DATAPORT);
+               outw(rx_block + RX_BUF_SIZE + 0x16, ioaddr+DATAPORT);
+               outw(rx_block + 0x20, ioaddr+DATAPORT);
+               outw(0, ioaddr+DATAPORT);
+               outw(RX_BUF_SIZE-0x20, ioaddr+DATAPORT);
+
+               lp->rx_last = rx_block;
+               rx_block += RX_BUF_SIZE;
+       } while (rx_block <= lp->rx_buf_end-RX_BUF_SIZE);
+
+
+       /* Make first Rx frame descriptor point to first Rx buffer
+           descriptor */
+       outw(lp->rx_first + 6, ioaddr+WRITE_PTR);
+       outw(lp->rx_first + 0x16, ioaddr+DATAPORT);
+
+       /* Close Rx frame descriptor ring */
+       outw(lp->rx_last + 4, ioaddr+WRITE_PTR);
+       outw(lp->rx_first, ioaddr+DATAPORT);
+
+       /* Close Rx buffer descriptor ring */
+       outw(lp->rx_last + 0x16 + 2, ioaddr+WRITE_PTR);
+       outw(lp->rx_first + 0x16, ioaddr+DATAPORT);
+
+}
+
+/*
+ * Un-reset the 586, and start the configuration sequence. We don't wait for
+ * this to finish, but allow the interrupt handler to start the CU and RU for
+ * us.  We can't start the receive/transmission system up before we know that
+ * the hardware is configured correctly.
+ */
+
+static void eexp_hw_init586(struct net_device *dev)
+{
+       struct net_local *lp = netdev_priv(dev);
+       unsigned short ioaddr = dev->base_addr;
+       int i;
+
+#if NET_DEBUG > 6
+       printk("%s: eexp_hw_init586()\n", dev->name);
+#endif
+
+       lp->started = 0;
+
+       set_loopback(dev);
+
+       outb(SIRQ_dis|irqrmap[dev->irq],ioaddr+SET_IRQ);
+
+       /* Download the startup code */
+       outw(lp->rx_buf_end & ~31, ioaddr + SM_PTR);
+       outw(lp->width?0x0001:0x0000, ioaddr + 0x8006);
+       outw(0x0000, ioaddr + 0x8008);
+       outw(0x0000, ioaddr + 0x800a);
+       outw(0x0000, ioaddr + 0x800c);
+       outw(0x0000, ioaddr + 0x800e);
+
+       for (i = 0; i < ARRAY_SIZE(start_code) * 2; i+=32) {
+               int j;
+               outw(i, ioaddr + SM_PTR);
+               for (j = 0; j < 16 && (i+j)/2 < ARRAY_SIZE(start_code); j+=2)
+                       outw(start_code[(i+j)/2],
+                            ioaddr+0x4000+j);
+               for (j = 0; j < 16 && (i+j+16)/2 < ARRAY_SIZE(start_code); j+=2)
+                       outw(start_code[(i+j+16)/2],
+                            ioaddr+0x8000+j);
+       }
+
+       /* Do we want promiscuous mode or multicast? */
+       outw(CONF_PROMISC & ~31, ioaddr+SM_PTR);
+       i = inw(ioaddr+SHADOW(CONF_PROMISC));
+       outw((dev->flags & IFF_PROMISC)?(i|1):(i & ~1),
+            ioaddr+SHADOW(CONF_PROMISC));
+       lp->was_promisc = dev->flags & IFF_PROMISC;
+#if 0
+       eexp_setup_filter(dev);
+#endif
+
+       /* Write our hardware address */
+       outw(CONF_HWADDR & ~31, ioaddr+SM_PTR);
+       outw(((unsigned short *)dev->dev_addr)[0], ioaddr+SHADOW(CONF_HWADDR));
+       outw(((unsigned short *)dev->dev_addr)[1],
+            ioaddr+SHADOW(CONF_HWADDR+2));
+       outw(((unsigned short *)dev->dev_addr)[2],
+            ioaddr+SHADOW(CONF_HWADDR+4));
+
+       eexp_hw_txinit(dev);
+       eexp_hw_rxinit(dev);
+
+       outb(0,ioaddr+EEPROM_Ctrl);
+       mdelay(5);
+
+       scb_command(dev, 0xf000);
+       outb(0,ioaddr+SIGNAL_CA);
+
+       outw(0, ioaddr+SM_PTR);
+
+       {
+               unsigned short rboguscount=50,rfailcount=5;
+               while (inw(ioaddr+0x4000))
+               {
+                       if (!--rboguscount)
+                       {
+                               printk(KERN_WARNING "%s: i82586 reset timed out, kicking...\n",
+                                       dev->name);
+                               scb_command(dev, 0);
+                               outb(0,ioaddr+SIGNAL_CA);
+                               rboguscount = 100;
+                               if (!--rfailcount)
+                               {
+                                       printk(KERN_WARNING "%s: i82586 not responding, giving up.\n",
+                                               dev->name);
+                                       return;
+                               }
+                       }
+               }
+       }
+
+        scb_wrcbl(dev, CONF_LINK);
+       scb_command(dev, 0xf000|SCB_CUstart);
+       outb(0,ioaddr+SIGNAL_CA);
+
+       {
+               unsigned short iboguscount=50,ifailcount=5;
+               while (!scb_status(dev))
+               {
+                       if (!--iboguscount)
+                       {
+                               if (--ifailcount)
+                               {
+                                       printk(KERN_WARNING "%s: i82586 initialization timed out, status %04x, cmd %04x\n",
+                                               dev->name, scb_status(dev), scb_rdcmd(dev));
+                                       scb_wrcbl(dev, CONF_LINK);
+                                       scb_command(dev, 0xf000|SCB_CUstart);
+                                       outb(0,ioaddr+SIGNAL_CA);
+                                       iboguscount = 100;
+                               }
+                               else
+                               {
+                                       printk(KERN_WARNING "%s: Failed to initialize i82586, giving up.\n",dev->name);
+                                       return;
+                               }
+                       }
+               }
+       }
+
+       clear_loopback(dev);
+       outb(SIRQ_en|irqrmap[dev->irq],ioaddr+SET_IRQ);
+
+       lp->init_time = jiffies;
+#if NET_DEBUG > 6
+        printk("%s: leaving eexp_hw_init586()\n", dev->name);
+#endif
+}
+
+static void eexp_setup_filter(struct net_device *dev)
+{
+       struct netdev_hw_addr *ha;
+       unsigned short ioaddr = dev->base_addr;
+       int count = netdev_mc_count(dev);
+       int i;
+       if (count > 8) {
+               printk(KERN_INFO "%s: too many multicast addresses (%d)\n",
+                      dev->name, count);
+               count = 8;
+       }
+
+       outw(CONF_NR_MULTICAST & ~31, ioaddr+SM_PTR);
+       outw(6*count, ioaddr+SHADOW(CONF_NR_MULTICAST));
+       i = 0;
+       netdev_for_each_mc_addr(ha, dev) {
+               unsigned short *data = (unsigned short *) ha->addr;
+
+               if (i == count)
+                       break;
+               outw((CONF_MULTICAST+(6*i)) & ~31, ioaddr+SM_PTR);
+               outw(data[0], ioaddr+SHADOW(CONF_MULTICAST+(6*i)));
+               outw((CONF_MULTICAST+(6*i)+2) & ~31, ioaddr+SM_PTR);
+               outw(data[1], ioaddr+SHADOW(CONF_MULTICAST+(6*i)+2));
+               outw((CONF_MULTICAST+(6*i)+4) & ~31, ioaddr+SM_PTR);
+               outw(data[2], ioaddr+SHADOW(CONF_MULTICAST+(6*i)+4));
+               i++;
+       }
+}
+
+/*
+ * Set or clear the multicast filter for this adaptor.
+ */
+static void
+eexp_set_multicast(struct net_device *dev)
+{
+        unsigned short ioaddr = dev->base_addr;
+        struct net_local *lp = netdev_priv(dev);
+        int kick = 0, i;
+        if ((dev->flags & IFF_PROMISC) != lp->was_promisc) {
+                outw(CONF_PROMISC & ~31, ioaddr+SM_PTR);
+                i = inw(ioaddr+SHADOW(CONF_PROMISC));
+                outw((dev->flags & IFF_PROMISC)?(i|1):(i & ~1),
+                     ioaddr+SHADOW(CONF_PROMISC));
+                lp->was_promisc = dev->flags & IFF_PROMISC;
+                kick = 1;
+        }
+        if (!(dev->flags & IFF_PROMISC)) {
+                eexp_setup_filter(dev);
+                if (lp->old_mc_count != netdev_mc_count(dev)) {
+                        kick = 1;
+                        lp->old_mc_count = netdev_mc_count(dev);
+                }
+        }
+        if (kick) {
+                unsigned long oj;
+                scb_command(dev, SCB_CUsuspend);
+                outb(0, ioaddr+SIGNAL_CA);
+                outb(0, ioaddr+SIGNAL_CA);
+#if 0
+                printk("%s: waiting for CU to go suspended\n", dev->name);
+#endif
+                oj = jiffies;
+                while ((SCB_CUstat(scb_status(dev)) == 2) &&
+                       (time_before(jiffies, oj + 2000)));
+               if (SCB_CUstat(scb_status(dev)) == 2)
+                       printk("%s: warning, CU didn't stop\n", dev->name);
+                lp->started &= ~(STARTED_CU);
+                scb_wrcbl(dev, CONF_LINK);
+                scb_command(dev, SCB_CUstart);
+                outb(0, ioaddr+SIGNAL_CA);
+        }
+}
+
+
+/*
+ * MODULE stuff
+ */
+
+#ifdef MODULE
+
+#define EEXP_MAX_CARDS     4    /* max number of cards to support */
+
+static struct net_device *dev_eexp[EEXP_MAX_CARDS];
+static int irq[EEXP_MAX_CARDS];
+static int io[EEXP_MAX_CARDS];
+
+module_param_array(io, int, NULL, 0);
+module_param_array(irq, int, NULL, 0);
+MODULE_PARM_DESC(io, "EtherExpress 16 I/O base address(es)");
+MODULE_PARM_DESC(irq, "EtherExpress 16 IRQ number(s)");
+MODULE_LICENSE("GPL");
+
+
+/* Ideally the user would give us io=, irq= for every card.  If any parameters
+ * are specified, we verify and then use them.  If no parameters are given, we
+ * autoprobe for one card only.
+ */
+int __init init_module(void)
+{
+       struct net_device *dev;
+       int this_dev, found = 0;
+
+       for (this_dev = 0; this_dev < EEXP_MAX_CARDS; this_dev++) {
+               dev = alloc_etherdev(sizeof(struct net_local));
+               dev->irq = irq[this_dev];
+               dev->base_addr = io[this_dev];
+               if (io[this_dev] == 0) {
+                       if (this_dev)
+                               break;
+                       printk(KERN_NOTICE "eexpress.c: Module autoprobe not recommended, give io=xx.\n");
+               }
+               if (do_express_probe(dev) == 0) {
+                       dev_eexp[this_dev] = dev;
+                       found++;
+                       continue;
+               }
+               printk(KERN_WARNING "eexpress.c: Failed to register card at 0x%x.\n", io[this_dev]);
+               free_netdev(dev);
+               break;
+       }
+       if (found)
+               return 0;
+       return -ENXIO;
+}
+
+void __exit cleanup_module(void)
+{
+       int this_dev;
+
+       for (this_dev = 0; this_dev < EEXP_MAX_CARDS; this_dev++) {
+               struct net_device *dev = dev_eexp[this_dev];
+               if (dev) {
+                       unregister_netdev(dev);
+                       free_netdev(dev);
+               }
+       }
+}
+#endif
+
+/*
+ * Local Variables:
+ *  c-file-style: "linux"
+ *  tab-width: 8
+ * End:
+ */
diff --git a/drivers/net/ethernet/i825xx/eexpress.h b/drivers/net/ethernet/i825xx/eexpress.h
new file mode 100644 (file)
index 0000000..dc9c6ea
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * eexpress.h: Intel EtherExpress16 defines
+ */
+
+/*
+ * EtherExpress card register addresses
+ * as offsets from the base IO region (dev->base_addr)
+ */
+
+#define DATAPORT      0x0000
+#define WRITE_PTR     0x0002
+#define READ_PTR      0x0004
+#define SIGNAL_CA     0x0006
+#define SET_IRQ       0x0007
+#define SM_PTR        0x0008
+#define        MEM_Dec       0x000a
+#define MEM_Ctrl      0x000b
+#define MEM_Page_Ctrl 0x000c
+#define Config        0x000d
+#define EEPROM_Ctrl   0x000e
+#define ID_PORT       0x000f
+#define        MEM_ECtrl     0x000f
+
+/*
+ * card register defines
+ */
+
+/* SET_IRQ */
+#define SIRQ_en       0x08
+#define SIRQ_dis      0x00
+
+/* EEPROM_Ctrl */
+#define EC_Clk        0x01
+#define EC_CS         0x02
+#define EC_Wr         0x04
+#define EC_Rd         0x08
+#define ASIC_RST      0x40
+#define i586_RST      0x80
+
+#define eeprom_delay() { udelay(40); }
+
+/*
+ * i82586 Memory Configuration
+ */
+
+/* (System Configuration Pointer) System start up block, read after 586_RST */
+#define SCP_START 0xfff6
+
+/* Intermediate System Configuration Pointer */
+#define ISCP_START 0x0000
+
+/* System Command Block */
+#define SCB_START 0x0008
+
+/* Start of buffer region.  Everything before this is used for control
+ * structures and the CU configuration program.  The memory layout is
+ * determined in eexp_hw_probe(), once we know how much memory is
+ * available on the card.
+ */
+
+#define TX_BUF_START 0x0100
+
+#define TX_BUF_SIZE ((24+ETH_FRAME_LEN+31)&~0x1f)
+#define RX_BUF_SIZE ((32+ETH_FRAME_LEN+31)&~0x1f)
+
+/*
+ * SCB defines
+ */
+
+/* these functions take the SCB status word and test the relevant status bit */
+#define SCB_complete(s) (((s) & 0x8000) != 0)
+#define SCB_rxdframe(s) (((s) & 0x4000) != 0)
+#define SCB_CUdead(s)   (((s) & 0x2000) != 0)
+#define SCB_RUdead(s)   (((s) & 0x1000) != 0)
+#define SCB_ack(s)      ((s) & 0xf000)
+
+/* Command unit status: 0=idle, 1=suspended, 2=active */
+#define SCB_CUstat(s)   (((s)&0x0300)>>8)
+
+/* Receive unit status: 0=idle, 1=suspended, 2=out of resources, 4=ready */
+#define SCB_RUstat(s)   (((s)&0x0070)>>4)
+
+/* SCB commands */
+#define SCB_CUnop       0x0000
+#define SCB_CUstart     0x0100
+#define SCB_CUresume    0x0200
+#define SCB_CUsuspend   0x0300
+#define SCB_CUabort     0x0400
+#define SCB_resetchip   0x0080
+
+#define SCB_RUnop       0x0000
+#define SCB_RUstart     0x0010
+#define SCB_RUresume    0x0020
+#define SCB_RUsuspend   0x0030
+#define SCB_RUabort     0x0040
+
+/*
+ * Command block defines
+ */
+
+#define Stat_Done(s)    (((s) & 0x8000) != 0)
+#define Stat_Busy(s)    (((s) & 0x4000) != 0)
+#define Stat_OK(s)      (((s) & 0x2000) != 0)
+#define Stat_Abort(s)   (((s) & 0x1000) != 0)
+#define Stat_STFail     (((s) & 0x0800) != 0)
+#define Stat_TNoCar(s)  (((s) & 0x0400) != 0)
+#define Stat_TNoCTS(s)  (((s) & 0x0200) != 0)
+#define Stat_TNoDMA(s)  (((s) & 0x0100) != 0)
+#define Stat_TDefer(s)  (((s) & 0x0080) != 0)
+#define Stat_TColl(s)   (((s) & 0x0040) != 0)
+#define Stat_TXColl(s)  (((s) & 0x0020) != 0)
+#define Stat_NoColl(s)  ((s) & 0x000f)
+
+/* Cmd_END will end AFTER the command if this is the first
+ * command block after an SCB_CUstart, but BEFORE the command
+ * for all subsequent commands. Best strategy is to place
+ * Cmd_INT on the last command in the sequence, followed by a
+ * dummy Cmd_Nop with Cmd_END after this.
+ */
+
+#define Cmd_END     0x8000
+#define Cmd_SUS     0x4000
+#define Cmd_INT     0x2000
+
+#define Cmd_Nop     0x0000
+#define Cmd_SetAddr 0x0001
+#define Cmd_Config  0x0002
+#define Cmd_MCast   0x0003
+#define Cmd_Xmit    0x0004
+#define Cmd_TDR     0x0005
+#define Cmd_Dump    0x0006
+#define Cmd_Diag    0x0007
+
+
+/*
+ * Frame Descriptor (Receive block) defines
+ */
+
+#define FD_Done(s)  (((s) & 0x8000) != 0)
+#define FD_Busy(s)  (((s) & 0x4000) != 0)
+#define FD_OK(s)    (((s) & 0x2000) != 0)
+
+#define FD_CRC(s)   (((s) & 0x0800) != 0)
+#define FD_Align(s) (((s) & 0x0400) != 0)
+#define FD_Resrc(s) (((s) & 0x0200) != 0)
+#define FD_DMA(s)   (((s) & 0x0100) != 0)
+#define FD_Short(s) (((s) & 0x0080) != 0)
+#define FD_NoEOF(s) (((s) & 0x0040) != 0)
+
+struct rfd_header {
+       volatile unsigned long flags;
+       volatile unsigned short link;
+       volatile unsigned short rbd_offset;
+       volatile unsigned short dstaddr1;
+       volatile unsigned short dstaddr2;
+       volatile unsigned short dstaddr3;
+       volatile unsigned short srcaddr1;
+       volatile unsigned short srcaddr2;
+       volatile unsigned short srcaddr3;
+       volatile unsigned short length;
+
+       /* This is actually a Receive Buffer Descriptor.  The way we
+        * arrange memory means that an RBD always follows the RFD that
+        * points to it, so they might as well be in the same structure.
+        */
+       volatile unsigned short actual_count;
+       volatile unsigned short next_rbd;
+       volatile unsigned short buf_addr1;
+       volatile unsigned short buf_addr2;
+       volatile unsigned short size;
+};
+
+/* Returned data from the Time Domain Reflectometer */
+
+#define TDR_LINKOK       (1<<15)
+#define TDR_XCVRPROBLEM  (1<<14)
+#define TDR_OPEN         (1<<13)
+#define TDR_SHORT        (1<<12)
+#define TDR_TIME         0x7ff
diff --git a/drivers/net/ethernet/i825xx/ether1.c b/drivers/net/ethernet/i825xx/ether1.c
new file mode 100644 (file)
index 0000000..b00781c
--- /dev/null
@@ -0,0 +1,1094 @@
+/*
+ *  linux/drivers/acorn/net/ether1.c
+ *
+ *  Copyright (C) 1996-2000 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *  Acorn ether1 driver (82586 chip) for Acorn machines
+ *
+ * We basically keep two queues in the cards memory - one for transmit
+ * and one for receive.  Each has a head and a tail.  The head is where
+ * we/the chip adds packets to be transmitted/received, and the tail
+ * is where the transmitter has got to/where the receiver will stop.
+ * Both of these queues are circular, and since the chip is running
+ * all the time, we have to be careful when we modify the pointers etc
+ * so that the buffer memory contents is valid all the time.
+ *
+ * Change log:
+ * 1.00        RMK                     Released
+ * 1.01        RMK     19/03/1996      Transfers the last odd byte onto/off of the card now.
+ * 1.02        RMK     25/05/1997      Added code to restart RU if it goes not ready
+ * 1.03        RMK     14/09/1997      Cleaned up the handling of a reset during the TX interrupt.
+ *                             Should prevent lockup.
+ * 1.04 RMK    17/09/1997      Added more info when initialsation of chip goes wrong.
+ *                             TDR now only reports failure when chip reports non-zero
+ *                             TDR time-distance.
+ * 1.05        RMK     31/12/1997      Removed calls to dev_tint for 2.1
+ * 1.06        RMK     10/02/2000      Updated for 2.3.43
+ * 1.07        RMK     13/05/2000      Updated for 2.3.99-pre8
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/bitops.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/ecard.h>
+
+#define __ETHER1_C
+#include "ether1.h"
+
+static unsigned int net_debug = NET_DEBUG;
+
+#define BUFFER_SIZE    0x10000
+#define TX_AREA_START  0x00100
+#define TX_AREA_END    0x05000
+#define RX_AREA_START  0x05000
+#define RX_AREA_END    0x0fc00
+
+static int ether1_open(struct net_device *dev);
+static int ether1_sendpacket(struct sk_buff *skb, struct net_device *dev);
+static irqreturn_t ether1_interrupt(int irq, void *dev_id);
+static int ether1_close(struct net_device *dev);
+static void ether1_setmulticastlist(struct net_device *dev);
+static void ether1_timeout(struct net_device *dev);
+
+/* ------------------------------------------------------------------------- */
+
+static char version[] __devinitdata = "ether1 ethernet driver (c) 2000 Russell King v1.07\n";
+
+#define BUS_16 16
+#define BUS_8  8
+
+/* ------------------------------------------------------------------------- */
+
+#define DISABLEIRQS 1
+#define NORMALIRQS  0
+
+#define ether1_readw(dev, addr, type, offset, svflgs) ether1_inw_p (dev, addr + (int)(&((type *)0)->offset), svflgs)
+#define ether1_writew(dev, val, addr, type, offset, svflgs) ether1_outw_p (dev, val, addr + (int)(&((type *)0)->offset), svflgs)
+
+static inline unsigned short
+ether1_inw_p (struct net_device *dev, int addr, int svflgs)
+{
+       unsigned long flags;
+       unsigned short ret;
+
+       if (svflgs)
+               local_irq_save (flags);
+
+       writeb(addr >> 12, REG_PAGE);
+       ret = readw(ETHER1_RAM + ((addr & 4095) << 1));
+       if (svflgs)
+               local_irq_restore (flags);
+       return ret;
+}
+
+static inline void
+ether1_outw_p (struct net_device *dev, unsigned short val, int addr, int svflgs)
+{
+       unsigned long flags;
+
+       if (svflgs)
+               local_irq_save (flags);
+
+       writeb(addr >> 12, REG_PAGE);
+       writew(val, ETHER1_RAM + ((addr & 4095) << 1));
+       if (svflgs)
+               local_irq_restore (flags);
+}
+
+/*
+ * Some inline assembler to allow fast transfers on to/off of the card.
+ * Since this driver depends on some features presented by the ARM
+ * specific architecture, and that you can't configure this driver
+ * without specifiing ARM mode, this is not a problem.
+ *
+ * This routine is essentially an optimised memcpy from the card's
+ * onboard RAM to kernel memory.
+ */
+static void
+ether1_writebuffer (struct net_device *dev, void *data, unsigned int start, unsigned int length)
+{
+       unsigned int page, thislen, offset;
+       void __iomem *addr;
+
+       offset = start & 4095;
+       page = start >> 12;
+       addr = ETHER1_RAM + (offset << 1);
+
+       if (offset + length > 4096)
+               thislen = 4096 - offset;
+       else
+               thislen = length;
+
+       do {
+               int used;
+
+               writeb(page, REG_PAGE);
+               length -= thislen;
+
+               __asm__ __volatile__(
+       "subs   %3, %3, #2\n\
+       bmi     2f\n\
+1:     ldr     %0, [%1], #2\n\
+       mov     %0, %0, lsl #16\n\
+       orr     %0, %0, %0, lsr #16\n\
+       str     %0, [%2], #4\n\
+       subs    %3, %3, #2\n\
+       bmi     2f\n\
+       ldr     %0, [%1], #2\n\
+       mov     %0, %0, lsl #16\n\
+       orr     %0, %0, %0, lsr #16\n\
+       str     %0, [%2], #4\n\
+       subs    %3, %3, #2\n\
+       bmi     2f\n\
+       ldr     %0, [%1], #2\n\
+       mov     %0, %0, lsl #16\n\
+       orr     %0, %0, %0, lsr #16\n\
+       str     %0, [%2], #4\n\
+       subs    %3, %3, #2\n\
+       bmi     2f\n\
+       ldr     %0, [%1], #2\n\
+       mov     %0, %0, lsl #16\n\
+       orr     %0, %0, %0, lsr #16\n\
+       str     %0, [%2], #4\n\
+       subs    %3, %3, #2\n\
+       bpl     1b\n\
+2:     adds    %3, %3, #1\n\
+       ldreqb  %0, [%1]\n\
+       streqb  %0, [%2]"
+               : "=&r" (used), "=&r" (data)
+               : "r"  (addr), "r" (thislen), "1" (data));
+
+               addr = ETHER1_RAM;
+
+               thislen = length;
+               if (thislen > 4096)
+                       thislen = 4096;
+               page++;
+       } while (thislen);
+}
+
+static void
+ether1_readbuffer (struct net_device *dev, void *data, unsigned int start, unsigned int length)
+{
+       unsigned int page, thislen, offset;
+       void __iomem *addr;
+
+       offset = start & 4095;
+       page = start >> 12;
+       addr = ETHER1_RAM + (offset << 1);
+
+       if (offset + length > 4096)
+               thislen = 4096 - offset;
+       else
+               thislen = length;
+
+       do {
+               int used;
+
+               writeb(page, REG_PAGE);
+               length -= thislen;
+
+               __asm__ __volatile__(
+       "subs   %3, %3, #2\n\
+       bmi     2f\n\
+1:     ldr     %0, [%2], #4\n\
+       strb    %0, [%1], #1\n\
+       mov     %0, %0, lsr #8\n\
+       strb    %0, [%1], #1\n\
+       subs    %3, %3, #2\n\
+       bmi     2f\n\
+       ldr     %0, [%2], #4\n\
+       strb    %0, [%1], #1\n\
+       mov     %0, %0, lsr #8\n\
+       strb    %0, [%1], #1\n\
+       subs    %3, %3, #2\n\
+       bmi     2f\n\
+       ldr     %0, [%2], #4\n\
+       strb    %0, [%1], #1\n\
+       mov     %0, %0, lsr #8\n\
+       strb    %0, [%1], #1\n\
+       subs    %3, %3, #2\n\
+       bmi     2f\n\
+       ldr     %0, [%2], #4\n\
+       strb    %0, [%1], #1\n\
+       mov     %0, %0, lsr #8\n\
+       strb    %0, [%1], #1\n\
+       subs    %3, %3, #2\n\
+       bpl     1b\n\
+2:     adds    %3, %3, #1\n\
+       ldreqb  %0, [%2]\n\
+       streqb  %0, [%1]"
+               : "=&r" (used), "=&r" (data)
+               : "r"  (addr), "r" (thislen), "1" (data));
+
+               addr = ETHER1_RAM;
+
+               thislen = length;
+               if (thislen > 4096)
+                       thislen = 4096;
+               page++;
+       } while (thislen);
+}
+
+static int __devinit
+ether1_ramtest(struct net_device *dev, unsigned char byte)
+{
+       unsigned char *buffer = kmalloc (BUFFER_SIZE, GFP_KERNEL);
+       int i, ret = BUFFER_SIZE;
+       int max_errors = 15;
+       int bad = -1;
+       int bad_start = 0;
+
+       if (!buffer)
+               return 1;
+
+       memset (buffer, byte, BUFFER_SIZE);
+       ether1_writebuffer (dev, buffer, 0, BUFFER_SIZE);
+       memset (buffer, byte ^ 0xff, BUFFER_SIZE);
+       ether1_readbuffer (dev, buffer, 0, BUFFER_SIZE);
+
+       for (i = 0; i < BUFFER_SIZE; i++) {
+               if (buffer[i] != byte) {
+                       if (max_errors >= 0 && bad != buffer[i]) {
+                               if (bad != -1)
+                                       printk ("\n");
+                               printk (KERN_CRIT "%s: RAM failed with (%02X instead of %02X) at 0x%04X",
+                                       dev->name, buffer[i], byte, i);
+                               ret = -ENODEV;
+                               max_errors --;
+                               bad = buffer[i];
+                               bad_start = i;
+                       }
+               } else {
+                       if (bad != -1) {
+                               if (bad_start == i - 1)
+                                       printk ("\n");
+                               else
+                                       printk (" - 0x%04X\n", i - 1);
+                               bad = -1;
+                       }
+               }
+       }
+
+       if (bad != -1)
+               printk (" - 0x%04X\n", BUFFER_SIZE);
+       kfree (buffer);
+
+       return ret;
+}
+
+static int
+ether1_reset (struct net_device *dev)
+{
+       writeb(CTRL_RST|CTRL_ACK, REG_CONTROL);
+       return BUS_16;
+}
+
+static int __devinit
+ether1_init_2(struct net_device *dev)
+{
+       int i;
+       dev->mem_start = 0;
+
+       i = ether1_ramtest (dev, 0x5a);
+
+       if (i > 0)
+               i = ether1_ramtest (dev, 0x1e);
+
+       if (i <= 0)
+               return -ENODEV;
+
+       dev->mem_end = i;
+       return 0;
+}
+
+/*
+ * These are the structures that are loaded into the ether RAM card to
+ * initialise the 82586
+ */
+
+/* at 0x0100 */
+#define NOP_ADDR       (TX_AREA_START)
+#define NOP_SIZE       (0x06)
+static nop_t  init_nop  = {
+       0,
+       CMD_NOP,
+       NOP_ADDR
+};
+
+/* at 0x003a */
+#define TDR_ADDR       (0x003a)
+#define TDR_SIZE       (0x08)
+static tdr_t  init_tdr = {
+       0,
+       CMD_TDR | CMD_INTR,
+       NOP_ADDR,
+       0
+};
+
+/* at 0x002e */
+#define MC_ADDR                (0x002e)
+#define MC_SIZE                (0x0c)
+static mc_t   init_mc   = {
+       0,
+       CMD_SETMULTICAST,
+       TDR_ADDR,
+       0,
+       { { 0, } }
+};
+
+/* at 0x0022 */
+#define SA_ADDR                (0x0022)
+#define SA_SIZE                (0x0c)
+static sa_t   init_sa   = {
+       0,
+       CMD_SETADDRESS,
+       MC_ADDR,
+       { 0, }
+};
+
+/* at 0x0010 */
+#define CFG_ADDR       (0x0010)
+#define CFG_SIZE       (0x12)
+static cfg_t  init_cfg  = {
+       0,
+       CMD_CONFIG,
+       SA_ADDR,
+       8,
+       8,
+       CFG8_SRDY,
+       CFG9_PREAMB8 | CFG9_ADDRLENBUF | CFG9_ADDRLEN(6),
+       0,
+       0x60,
+       0,
+       CFG13_RETRY(15) | CFG13_SLOTH(2),
+       0,
+};
+
+/* at 0x0000 */
+#define SCB_ADDR       (0x0000)
+#define SCB_SIZE       (0x10)
+static scb_t  init_scb  = {
+       0,
+       SCB_CMDACKRNR | SCB_CMDACKCNA | SCB_CMDACKFR | SCB_CMDACKCX,
+       CFG_ADDR,
+       RX_AREA_START,
+       0,
+       0,
+       0,
+       0
+};
+
+/* at 0xffee */
+#define ISCP_ADDR      (0xffee)
+#define ISCP_SIZE      (0x08)
+static iscp_t init_iscp = {
+       1,
+       SCB_ADDR,
+       0x0000,
+       0x0000
+};
+
+/* at 0xfff6 */
+#define SCP_ADDR       (0xfff6)
+#define SCP_SIZE       (0x0a)
+static scp_t  init_scp  = {
+       SCP_SY_16BBUS,
+       { 0, 0 },
+       ISCP_ADDR,
+       0
+};
+
+#define RFD_SIZE       (0x16)
+static rfd_t  init_rfd = {
+       0,
+       0,
+       0,
+       0,
+       { 0, },
+       { 0, },
+       0
+};
+
+#define RBD_SIZE       (0x0a)
+static rbd_t  init_rbd = {
+       0,
+       0,
+       0,
+       0,
+       ETH_FRAME_LEN + 8
+};
+
+#define TX_SIZE                (0x08)
+#define TBD_SIZE       (0x08)
+
+static int
+ether1_init_for_open (struct net_device *dev)
+{
+       int i, status, addr, next, next2;
+       int failures = 0;
+       unsigned long timeout;
+
+       writeb(CTRL_RST|CTRL_ACK, REG_CONTROL);
+
+       for (i = 0; i < 6; i++)
+               init_sa.sa_addr[i] = dev->dev_addr[i];
+
+       /* load data structures into ether1 RAM */
+       ether1_writebuffer (dev, &init_scp,  SCP_ADDR,  SCP_SIZE);
+       ether1_writebuffer (dev, &init_iscp, ISCP_ADDR, ISCP_SIZE);
+       ether1_writebuffer (dev, &init_scb,  SCB_ADDR,  SCB_SIZE);
+       ether1_writebuffer (dev, &init_cfg,  CFG_ADDR,  CFG_SIZE);
+       ether1_writebuffer (dev, &init_sa,   SA_ADDR,   SA_SIZE);
+       ether1_writebuffer (dev, &init_mc,   MC_ADDR,   MC_SIZE);
+       ether1_writebuffer (dev, &init_tdr,  TDR_ADDR,  TDR_SIZE);
+       ether1_writebuffer (dev, &init_nop,  NOP_ADDR,  NOP_SIZE);
+
+       if (ether1_readw(dev, CFG_ADDR, cfg_t, cfg_command, NORMALIRQS) != CMD_CONFIG) {
+               printk (KERN_ERR "%s: detected either RAM fault or compiler bug\n",
+                       dev->name);
+               return 1;
+       }
+
+       /*
+        * setup circularly linked list of { rfd, rbd, buffer }, with
+        * all rfds circularly linked, rbds circularly linked.
+        * First rfd is linked to scp, first rbd is linked to first
+        * rfd.  Last rbd has a suspend command.
+        */
+       addr = RX_AREA_START;
+       do {
+               next = addr + RFD_SIZE + RBD_SIZE + ETH_FRAME_LEN + 10;
+               next2 = next + RFD_SIZE + RBD_SIZE + ETH_FRAME_LEN + 10;
+
+               if (next2 >= RX_AREA_END) {
+                       next = RX_AREA_START;
+                       init_rfd.rfd_command = RFD_CMDEL | RFD_CMDSUSPEND;
+                       priv(dev)->rx_tail = addr;
+               } else
+                       init_rfd.rfd_command = 0;
+               if (addr == RX_AREA_START)
+                       init_rfd.rfd_rbdoffset = addr + RFD_SIZE;
+               else
+                       init_rfd.rfd_rbdoffset = 0;
+               init_rfd.rfd_link = next;
+               init_rbd.rbd_link = next + RFD_SIZE;
+               init_rbd.rbd_bufl = addr + RFD_SIZE + RBD_SIZE;
+
+               ether1_writebuffer (dev, &init_rfd, addr, RFD_SIZE);
+               ether1_writebuffer (dev, &init_rbd, addr + RFD_SIZE, RBD_SIZE);
+               addr = next;
+       } while (next2 < RX_AREA_END);
+
+       priv(dev)->tx_link = NOP_ADDR;
+       priv(dev)->tx_head = NOP_ADDR + NOP_SIZE;
+       priv(dev)->tx_tail = TDR_ADDR;
+       priv(dev)->rx_head = RX_AREA_START;
+
+       /* release reset & give 586 a prod */
+       priv(dev)->resetting = 1;
+       priv(dev)->initialising = 1;
+       writeb(CTRL_RST, REG_CONTROL);
+       writeb(0, REG_CONTROL);
+       writeb(CTRL_CA, REG_CONTROL);
+
+       /* 586 should now unset iscp.busy */
+       timeout = jiffies + HZ/2;
+       while (ether1_readw(dev, ISCP_ADDR, iscp_t, iscp_busy, DISABLEIRQS) == 1) {
+               if (time_after(jiffies, timeout)) {
+                       printk (KERN_WARNING "%s: can't initialise 82586: iscp is busy\n", dev->name);
+                       return 1;
+               }
+       }
+
+       /* check status of commands that we issued */
+       timeout += HZ/10;
+       while (((status = ether1_readw(dev, CFG_ADDR, cfg_t, cfg_status, DISABLEIRQS))
+                       & STAT_COMPLETE) == 0) {
+               if (time_after(jiffies, timeout))
+                       break;
+       }
+
+       if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) {
+               printk (KERN_WARNING "%s: can't initialise 82586: config status %04X\n", dev->name, status);
+               printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name,
+                       ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS),
+                       ether1_readw(dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS),
+                       ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS),
+                       ether1_readw(dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS));
+               failures += 1;
+       }
+
+       timeout += HZ/10;
+       while (((status = ether1_readw(dev, SA_ADDR, sa_t, sa_status, DISABLEIRQS))
+                       & STAT_COMPLETE) == 0) {
+               if (time_after(jiffies, timeout))
+                       break;
+       }
+
+       if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) {
+               printk (KERN_WARNING "%s: can't initialise 82586: set address status %04X\n", dev->name, status);
+               printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name,
+                       ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS),
+                       ether1_readw(dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS),
+                       ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS),
+                       ether1_readw(dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS));
+               failures += 1;
+       }
+
+       timeout += HZ/10;
+       while (((status = ether1_readw(dev, MC_ADDR, mc_t, mc_status, DISABLEIRQS))
+                       & STAT_COMPLETE) == 0) {
+               if (time_after(jiffies, timeout))
+                       break;
+       }
+
+       if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) {
+               printk (KERN_WARNING "%s: can't initialise 82586: set multicast status %04X\n", dev->name, status);
+               printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name,
+                       ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS),
+                       ether1_readw(dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS),
+                       ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS),
+                       ether1_readw(dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS));
+               failures += 1;
+       }
+
+       timeout += HZ;
+       while (((status = ether1_readw(dev, TDR_ADDR, tdr_t, tdr_status, DISABLEIRQS))
+                       & STAT_COMPLETE) == 0) {
+               if (time_after(jiffies, timeout))
+                       break;
+       }
+
+       if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) {
+               printk (KERN_WARNING "%s: can't tdr (ignored)\n", dev->name);
+               printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name,
+                       ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS),
+                       ether1_readw(dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS),
+                       ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS),
+                       ether1_readw(dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS));
+       } else {
+               status = ether1_readw(dev, TDR_ADDR, tdr_t, tdr_result, DISABLEIRQS);
+               if (status & TDR_XCVRPROB)
+                       printk (KERN_WARNING "%s: i/f failed tdr: transceiver problem\n", dev->name);
+               else if ((status & (TDR_SHORT|TDR_OPEN)) && (status & TDR_TIME)) {
+#ifdef FANCY
+                       printk (KERN_WARNING "%s: i/f failed tdr: cable %s %d.%d us away\n", dev->name,
+                               status & TDR_SHORT ? "short" : "open", (status & TDR_TIME) / 10,
+                               (status & TDR_TIME) % 10);
+#else
+                       printk (KERN_WARNING "%s: i/f failed tdr: cable %s %d clks away\n", dev->name,
+                               status & TDR_SHORT ? "short" : "open", (status & TDR_TIME));
+#endif
+               }
+       }
+
+       if (failures)
+               ether1_reset (dev);
+       return failures ? 1 : 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int
+ether1_txalloc (struct net_device *dev, int size)
+{
+       int start, tail;
+
+       size = (size + 1) & ~1;
+       tail = priv(dev)->tx_tail;
+
+       if (priv(dev)->tx_head + size > TX_AREA_END) {
+               if (tail > priv(dev)->tx_head)
+                       return -1;
+               start = TX_AREA_START;
+               if (start + size > tail)
+                       return -1;
+               priv(dev)->tx_head = start + size;
+       } else {
+               if (priv(dev)->tx_head < tail && (priv(dev)->tx_head + size) > tail)
+                       return -1;
+               start = priv(dev)->tx_head;
+               priv(dev)->tx_head += size;
+       }
+
+       return start;
+}
+
+static int
+ether1_open (struct net_device *dev)
+{
+       if (!is_valid_ether_addr(dev->dev_addr)) {
+               printk(KERN_WARNING "%s: invalid ethernet MAC address\n",
+                       dev->name);
+               return -EINVAL;
+       }
+
+       if (request_irq(dev->irq, ether1_interrupt, 0, "ether1", dev))
+               return -EAGAIN;
+
+       if (ether1_init_for_open (dev)) {
+               free_irq (dev->irq, dev);
+               return -EAGAIN;
+       }
+
+       netif_start_queue(dev);
+
+       return 0;
+}
+
+static void
+ether1_timeout(struct net_device *dev)
+{
+       printk(KERN_WARNING "%s: transmit timeout, network cable problem?\n",
+               dev->name);
+       printk(KERN_WARNING "%s: resetting device\n", dev->name);
+
+       ether1_reset (dev);
+
+       if (ether1_init_for_open (dev))
+               printk (KERN_ERR "%s: unable to restart interface\n", dev->name);
+
+       dev->stats.tx_errors++;
+       netif_wake_queue(dev);
+}
+
+static int
+ether1_sendpacket (struct sk_buff *skb, struct net_device *dev)
+{
+       int tmp, tst, nopaddr, txaddr, tbdaddr, dataddr;
+       unsigned long flags;
+       tx_t tx;
+       tbd_t tbd;
+       nop_t nop;
+
+       if (priv(dev)->restart) {
+               printk(KERN_WARNING "%s: resetting device\n", dev->name);
+
+               ether1_reset(dev);
+
+               if (ether1_init_for_open(dev))
+                       printk(KERN_ERR "%s: unable to restart interface\n", dev->name);
+               else
+                       priv(dev)->restart = 0;
+       }
+
+       if (skb->len < ETH_ZLEN) {
+               if (skb_padto(skb, ETH_ZLEN))
+                       goto out;
+       }
+
+       /*
+        * insert packet followed by a nop
+        */
+       txaddr = ether1_txalloc (dev, TX_SIZE);
+       tbdaddr = ether1_txalloc (dev, TBD_SIZE);
+       dataddr = ether1_txalloc (dev, skb->len);
+       nopaddr = ether1_txalloc (dev, NOP_SIZE);
+
+       tx.tx_status = 0;
+       tx.tx_command = CMD_TX | CMD_INTR;
+       tx.tx_link = nopaddr;
+       tx.tx_tbdoffset = tbdaddr;
+       tbd.tbd_opts = TBD_EOL | skb->len;
+       tbd.tbd_link = I82586_NULL;
+       tbd.tbd_bufl = dataddr;
+       tbd.tbd_bufh = 0;
+       nop.nop_status = 0;
+       nop.nop_command = CMD_NOP;
+       nop.nop_link = nopaddr;
+
+       local_irq_save(flags);
+       ether1_writebuffer (dev, &tx, txaddr, TX_SIZE);
+       ether1_writebuffer (dev, &tbd, tbdaddr, TBD_SIZE);
+       ether1_writebuffer (dev, skb->data, dataddr, skb->len);
+       ether1_writebuffer (dev, &nop, nopaddr, NOP_SIZE);
+       tmp = priv(dev)->tx_link;
+       priv(dev)->tx_link = nopaddr;
+
+       /* now reset the previous nop pointer */
+       ether1_writew(dev, txaddr, tmp, nop_t, nop_link, NORMALIRQS);
+
+       local_irq_restore(flags);
+
+       /* handle transmit */
+
+       /* check to see if we have room for a full sized ether frame */
+       tmp = priv(dev)->tx_head;
+       tst = ether1_txalloc (dev, TX_SIZE + TBD_SIZE + NOP_SIZE + ETH_FRAME_LEN);
+       priv(dev)->tx_head = tmp;
+       dev_kfree_skb (skb);
+
+       if (tst == -1)
+               netif_stop_queue(dev);
+
+ out:
+       return NETDEV_TX_OK;
+}
+
+static void
+ether1_xmit_done (struct net_device *dev)
+{
+       nop_t nop;
+       int caddr, tst;
+
+       caddr = priv(dev)->tx_tail;
+
+again:
+       ether1_readbuffer (dev, &nop, caddr, NOP_SIZE);
+
+       switch (nop.nop_command & CMD_MASK) {
+       case CMD_TDR:
+               /* special case */
+               if (ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS)
+                               != (unsigned short)I82586_NULL) {
+                       ether1_writew(dev, SCB_CMDCUCSTART | SCB_CMDRXSTART, SCB_ADDR, scb_t,
+                                   scb_command, NORMALIRQS);
+                       writeb(CTRL_CA, REG_CONTROL);
+               }
+               priv(dev)->tx_tail = NOP_ADDR;
+               return;
+
+       case CMD_NOP:
+               if (nop.nop_link == caddr) {
+                       if (priv(dev)->initialising == 0)
+                               printk (KERN_WARNING "%s: strange command complete with no tx command!\n", dev->name);
+                       else
+                               priv(dev)->initialising = 0;
+                       return;
+               }
+               if (caddr == nop.nop_link)
+                       return;
+               caddr = nop.nop_link;
+               goto again;
+
+       case CMD_TX:
+               if (nop.nop_status & STAT_COMPLETE)
+                       break;
+               printk (KERN_ERR "%s: strange command complete without completed command\n", dev->name);
+               priv(dev)->restart = 1;
+               return;
+
+       default:
+               printk (KERN_WARNING "%s: strange command %d complete! (offset %04X)", dev->name,
+                       nop.nop_command & CMD_MASK, caddr);
+               priv(dev)->restart = 1;
+               return;
+       }
+
+       while (nop.nop_status & STAT_COMPLETE) {
+               if (nop.nop_status & STAT_OK) {
+                       dev->stats.tx_packets++;
+                       dev->stats.collisions += (nop.nop_status & STAT_COLLISIONS);
+               } else {
+                       dev->stats.tx_errors++;
+
+                       if (nop.nop_status & STAT_COLLAFTERTX)
+                               dev->stats.collisions++;
+                       if (nop.nop_status & STAT_NOCARRIER)
+                               dev->stats.tx_carrier_errors++;
+                       if (nop.nop_status & STAT_TXLOSTCTS)
+                               printk (KERN_WARNING "%s: cts lost\n", dev->name);
+                       if (nop.nop_status & STAT_TXSLOWDMA)
+                               dev->stats.tx_fifo_errors++;
+                       if (nop.nop_status & STAT_COLLEXCESSIVE)
+                               dev->stats.collisions += 16;
+               }
+
+               if (nop.nop_link == caddr) {
+                       printk (KERN_ERR "%s: tx buffer chaining error: tx command points to itself\n", dev->name);
+                       break;
+               }
+
+               caddr = nop.nop_link;
+               ether1_readbuffer (dev, &nop, caddr, NOP_SIZE);
+               if ((nop.nop_command & CMD_MASK) != CMD_NOP) {
+                       printk (KERN_ERR "%s: tx buffer chaining error: no nop after tx command\n", dev->name);
+                       break;
+               }
+
+               if (caddr == nop.nop_link)
+                       break;
+
+               caddr = nop.nop_link;
+               ether1_readbuffer (dev, &nop, caddr, NOP_SIZE);
+               if ((nop.nop_command & CMD_MASK) != CMD_TX) {
+                       printk (KERN_ERR "%s: tx buffer chaining error: no tx command after nop\n", dev->name);
+                       break;
+               }
+       }
+       priv(dev)->tx_tail = caddr;
+
+       caddr = priv(dev)->tx_head;
+       tst = ether1_txalloc (dev, TX_SIZE + TBD_SIZE + NOP_SIZE + ETH_FRAME_LEN);
+       priv(dev)->tx_head = caddr;
+       if (tst != -1)
+               netif_wake_queue(dev);
+}
+
+static void
+ether1_recv_done (struct net_device *dev)
+{
+       int status;
+       int nexttail, rbdaddr;
+       rbd_t rbd;
+
+       do {
+               status = ether1_readw(dev, priv(dev)->rx_head, rfd_t, rfd_status, NORMALIRQS);
+               if ((status & RFD_COMPLETE) == 0)
+                       break;
+
+               rbdaddr = ether1_readw(dev, priv(dev)->rx_head, rfd_t, rfd_rbdoffset, NORMALIRQS);
+               ether1_readbuffer (dev, &rbd, rbdaddr, RBD_SIZE);
+
+               if ((rbd.rbd_status & (RBD_EOF | RBD_ACNTVALID)) == (RBD_EOF | RBD_ACNTVALID)) {
+                       int length = rbd.rbd_status & RBD_ACNT;
+                       struct sk_buff *skb;
+
+                       length = (length + 1) & ~1;
+                       skb = dev_alloc_skb (length + 2);
+
+                       if (skb) {
+                               skb_reserve (skb, 2);
+
+                               ether1_readbuffer (dev, skb_put (skb, length), rbd.rbd_bufl, length);
+
+                               skb->protocol = eth_type_trans (skb, dev);
+                               netif_rx (skb);
+                               dev->stats.rx_packets++;
+                       } else
+                               dev->stats.rx_dropped++;
+               } else {
+                       printk(KERN_WARNING "%s: %s\n", dev->name,
+                               (rbd.rbd_status & RBD_EOF) ? "oversized packet" : "acnt not valid");
+                       dev->stats.rx_dropped++;
+               }
+
+               nexttail = ether1_readw(dev, priv(dev)->rx_tail, rfd_t, rfd_link, NORMALIRQS);
+               /* nexttail should be rx_head */
+               if (nexttail != priv(dev)->rx_head)
+                       printk(KERN_ERR "%s: receiver buffer chaining error (%04X != %04X)\n",
+                               dev->name, nexttail, priv(dev)->rx_head);
+               ether1_writew(dev, RFD_CMDEL | RFD_CMDSUSPEND, nexttail, rfd_t, rfd_command, NORMALIRQS);
+               ether1_writew(dev, 0, priv(dev)->rx_tail, rfd_t, rfd_command, NORMALIRQS);
+               ether1_writew(dev, 0, priv(dev)->rx_tail, rfd_t, rfd_status, NORMALIRQS);
+               ether1_writew(dev, 0, priv(dev)->rx_tail, rfd_t, rfd_rbdoffset, NORMALIRQS);
+       
+               priv(dev)->rx_tail = nexttail;
+               priv(dev)->rx_head = ether1_readw(dev, priv(dev)->rx_head, rfd_t, rfd_link, NORMALIRQS);
+       } while (1);
+}
+
+static irqreturn_t
+ether1_interrupt (int irq, void *dev_id)
+{
+       struct net_device *dev = (struct net_device *)dev_id;
+       int status;
+
+       status = ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS);
+
+       if (status) {
+               ether1_writew(dev, status & (SCB_STRNR | SCB_STCNA | SCB_STFR | SCB_STCX),
+                           SCB_ADDR, scb_t, scb_command, NORMALIRQS);
+               writeb(CTRL_CA | CTRL_ACK, REG_CONTROL);
+               if (status & SCB_STCX) {
+                       ether1_xmit_done (dev);
+               }
+               if (status & SCB_STCNA) {
+                       if (priv(dev)->resetting == 0)
+                               printk (KERN_WARNING "%s: CU went not ready ???\n", dev->name);
+                       else
+                               priv(dev)->resetting += 1;
+                       if (ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS)
+                                       != (unsigned short)I82586_NULL) {
+                               ether1_writew(dev, SCB_CMDCUCSTART, SCB_ADDR, scb_t, scb_command, NORMALIRQS);
+                               writeb(CTRL_CA, REG_CONTROL);
+                       }
+                       if (priv(dev)->resetting == 2)
+                               priv(dev)->resetting = 0;
+               }
+               if (status & SCB_STFR) {
+                       ether1_recv_done (dev);
+               }
+               if (status & SCB_STRNR) {
+                       if (ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS) & SCB_STRXSUSP) {
+                               printk (KERN_WARNING "%s: RU went not ready: RU suspended\n", dev->name);
+                               ether1_writew(dev, SCB_CMDRXRESUME, SCB_ADDR, scb_t, scb_command, NORMALIRQS);
+                               writeb(CTRL_CA, REG_CONTROL);
+                               dev->stats.rx_dropped++;        /* we suspended due to lack of buffer space */
+                       } else
+                               printk(KERN_WARNING "%s: RU went not ready: %04X\n", dev->name,
+                                       ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS));
+                       printk (KERN_WARNING "RU ptr = %04X\n", ether1_readw(dev, SCB_ADDR, scb_t, scb_rfa_offset,
+                                               NORMALIRQS));
+               }
+       } else
+               writeb(CTRL_ACK, REG_CONTROL);
+
+       return IRQ_HANDLED;
+}
+
+static int
+ether1_close (struct net_device *dev)
+{
+       ether1_reset (dev);
+
+       free_irq(dev->irq, dev);
+
+       return 0;
+}
+
+/*
+ * Set or clear the multicast filter for this adaptor.
+ * num_addrs == -1     Promiscuous mode, receive all packets.
+ * num_addrs == 0      Normal mode, clear multicast list.
+ * num_addrs > 0       Multicast mode, receive normal and MC packets, and do
+ *                     best-effort filtering.
+ */
+static void
+ether1_setmulticastlist (struct net_device *dev)
+{
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void __devinit ether1_banner(void)
+{
+       static unsigned int version_printed = 0;
+
+       if (net_debug && version_printed++ == 0)
+               printk(KERN_INFO "%s", version);
+}
+
+static const struct net_device_ops ether1_netdev_ops = {
+       .ndo_open               = ether1_open,
+       .ndo_stop               = ether1_close,
+       .ndo_start_xmit         = ether1_sendpacket,
+       .ndo_set_multicast_list = ether1_setmulticastlist,
+       .ndo_tx_timeout         = ether1_timeout,
+       .ndo_validate_addr      = eth_validate_addr,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+};
+
+static int __devinit
+ether1_probe(struct expansion_card *ec, const struct ecard_id *id)
+{
+       struct net_device *dev;
+       int i, ret = 0;
+
+       ether1_banner();
+
+       ret = ecard_request_resources(ec);
+       if (ret)
+               goto out;
+
+       dev = alloc_etherdev(sizeof(struct ether1_priv));
+       if (!dev) {
+               ret = -ENOMEM;
+               goto release;
+       }
+
+       SET_NETDEV_DEV(dev, &ec->dev);
+
+       dev->irq = ec->irq;
+       priv(dev)->base = ecardm_iomap(ec, ECARD_RES_IOCFAST, 0, 0);
+       if (!priv(dev)->base) {
+               ret = -ENOMEM;
+               goto free;
+       }
+
+       if ((priv(dev)->bus_type = ether1_reset(dev)) == 0) {
+               ret = -ENODEV;
+               goto free;
+       }
+
+       for (i = 0; i < 6; i++)
+               dev->dev_addr[i] = readb(IDPROM_ADDRESS + (i << 2));
+
+       if (ether1_init_2(dev)) {
+               ret = -ENODEV;
+               goto free;
+       }
+
+       dev->netdev_ops         = &ether1_netdev_ops;
+       dev->watchdog_timeo     = 5 * HZ / 100;
+
+       ret = register_netdev(dev);
+       if (ret)
+               goto free;
+
+       printk(KERN_INFO "%s: ether1 in slot %d, %pM\n",
+               dev->name, ec->slot_no, dev->dev_addr);
+    
+       ecard_set_drvdata(ec, dev);
+       return 0;
+
+ free:
+       free_netdev(dev);
+ release:
+       ecard_release_resources(ec);
+ out:
+       return ret;
+}
+
+static void __devexit ether1_remove(struct expansion_card *ec)
+{
+       struct net_device *dev = ecard_get_drvdata(ec);
+
+       ecard_set_drvdata(ec, NULL);    
+
+       unregister_netdev(dev);
+       free_netdev(dev);
+       ecard_release_resources(ec);
+}
+
+static const struct ecard_id ether1_ids[] = {
+       { MANU_ACORN, PROD_ACORN_ETHER1 },
+       { 0xffff, 0xffff }
+};
+
+static struct ecard_driver ether1_driver = {
+       .probe          = ether1_probe,
+       .remove         = __devexit_p(ether1_remove),
+       .id_table       = ether1_ids,
+       .drv = {
+               .name   = "ether1",
+       },
+};
+
+static int __init ether1_init(void)
+{
+       return ecard_register_driver(&ether1_driver);
+}
+
+static void __exit ether1_exit(void)
+{
+       ecard_remove_driver(&ether1_driver);
+}
+
+module_init(ether1_init);
+module_exit(ether1_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/i825xx/ether1.h b/drivers/net/ethernet/i825xx/ether1.h
new file mode 100644 (file)
index 0000000..3a5830a
--- /dev/null
@@ -0,0 +1,280 @@
+/*
+ *  linux/drivers/acorn/net/ether1.h
+ *
+ *  Copyright (C) 1996 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *  Network driver for Acorn Ether1 cards.
+ */
+
+#ifndef _LINUX_ether1_H
+#define _LINUX_ether1_H
+
+#ifdef __ETHER1_C
+/* use 0 for production, 1 for verification, >2 for debug */
+#ifndef NET_DEBUG
+#define NET_DEBUG 0
+#endif
+
+#define priv(dev)      ((struct ether1_priv *)netdev_priv(dev))
+
+/* Page register */
+#define REG_PAGE       (priv(dev)->base + 0x0000)
+
+/* Control register */
+#define REG_CONTROL    (priv(dev)->base + 0x0004)
+#define CTRL_RST       0x01
+#define CTRL_LOOPBACK  0x02
+#define CTRL_CA                0x04
+#define CTRL_ACK       0x08
+
+#define ETHER1_RAM     (priv(dev)->base + 0x2000)
+
+/* HW address */
+#define IDPROM_ADDRESS (priv(dev)->base + 0x0024)
+
+struct ether1_priv {
+       void __iomem *base;
+       unsigned int tx_link;
+       unsigned int tx_head;
+       volatile unsigned int tx_tail;
+       volatile unsigned int rx_head;
+       volatile unsigned int rx_tail;
+       unsigned char bus_type;
+       unsigned char resetting;
+       unsigned char initialising : 1;
+       unsigned char restart      : 1;
+};
+
+#define I82586_NULL (-1)
+
+typedef struct { /* tdr */
+       unsigned short tdr_status;
+       unsigned short tdr_command;
+       unsigned short tdr_link;
+       unsigned short tdr_result;
+#define TDR_TIME       (0x7ff)
+#define TDR_SHORT      (1 << 12)
+#define TDR_OPEN       (1 << 13)
+#define TDR_XCVRPROB   (1 << 14)
+#define TDR_LNKOK      (1 << 15)
+} tdr_t;
+
+typedef struct { /* transmit */
+       unsigned short tx_status;
+       unsigned short tx_command;
+       unsigned short tx_link;
+       unsigned short tx_tbdoffset;
+} tx_t;
+
+typedef struct { /* tbd */
+       unsigned short tbd_opts;
+#define TBD_CNT                (0x3fff)
+#define TBD_EOL                (1 << 15)
+       unsigned short tbd_link;
+       unsigned short tbd_bufl;
+       unsigned short tbd_bufh;
+} tbd_t;
+
+typedef struct { /* rfd */
+       unsigned short rfd_status;
+#define RFD_NOEOF      (1 << 6)
+#define RFD_FRAMESHORT (1 << 7)
+#define RFD_DMAOVRN    (1 << 8)
+#define RFD_NORESOURCES        (1 << 9)
+#define RFD_ALIGNERROR (1 << 10)
+#define RFD_CRCERROR   (1 << 11)
+#define RFD_OK         (1 << 13)
+#define RFD_FDCONSUMED (1 << 14)
+#define RFD_COMPLETE   (1 << 15)
+       unsigned short rfd_command;
+#define RFD_CMDSUSPEND (1 << 14)
+#define RFD_CMDEL      (1 << 15)
+       unsigned short rfd_link;
+       unsigned short rfd_rbdoffset;
+       unsigned char  rfd_dest[6];
+       unsigned char  rfd_src[6];
+       unsigned short rfd_len;
+} rfd_t;
+
+typedef struct { /* rbd */
+       unsigned short rbd_status;
+#define RBD_ACNT       (0x3fff)
+#define RBD_ACNTVALID  (1 << 14)
+#define RBD_EOF                (1 << 15)
+       unsigned short rbd_link;
+       unsigned short rbd_bufl;
+       unsigned short rbd_bufh;
+       unsigned short rbd_len;
+} rbd_t;
+
+typedef struct { /* nop */
+       unsigned short nop_status;
+       unsigned short nop_command;
+       unsigned short nop_link;
+} nop_t;
+
+typedef struct { /* set multicast */
+       unsigned short mc_status;
+       unsigned short mc_command;
+       unsigned short mc_link;
+       unsigned short mc_cnt;
+       unsigned char  mc_addrs[1][6];
+} mc_t;
+
+typedef struct { /* set address */
+       unsigned short sa_status;
+       unsigned short sa_command;
+       unsigned short sa_link;
+       unsigned char  sa_addr[6];
+} sa_t;
+
+typedef struct { /* config command */
+       unsigned short cfg_status;
+       unsigned short cfg_command;
+       unsigned short cfg_link;
+       unsigned char  cfg_bytecnt;     /* size foll data: 4 - 12                */
+       unsigned char  cfg_fifolim;     /* FIFO threshold                        */
+       unsigned char  cfg_byte8;
+#define CFG8_SRDY      (1 << 6)
+#define CFG8_SAVEBADF  (1 << 7)
+       unsigned char  cfg_byte9;
+#define CFG9_ADDRLEN(x)        (x)
+#define CFG9_ADDRLENBUF        (1 << 3)
+#define CFG9_PREAMB2   (0 << 4)
+#define CFG9_PREAMB4   (1 << 4)
+#define CFG9_PREAMB8   (2 << 4)
+#define CFG9_PREAMB16  (3 << 4)
+#define CFG9_ILOOPBACK (1 << 6)
+#define CFG9_ELOOPBACK (1 << 7)
+       unsigned char  cfg_byte10;
+#define CFG10_LINPRI(x)        (x)
+#define CFG10_ACR(x)   (x << 4)
+#define CFG10_BOFMET   (1 << 7)
+       unsigned char  cfg_ifs;
+       unsigned char  cfg_slotl;
+       unsigned char  cfg_byte13;
+#define CFG13_SLOTH(x) (x)
+#define CFG13_RETRY(x) (x << 4)
+       unsigned char  cfg_byte14;
+#define CFG14_PROMISC  (1 << 0)
+#define CFG14_DISBRD   (1 << 1)
+#define CFG14_MANCH    (1 << 2)
+#define CFG14_TNCRS    (1 << 3)
+#define CFG14_NOCRC    (1 << 4)
+#define CFG14_CRC16    (1 << 5)
+#define CFG14_BTSTF    (1 << 6)
+#define CFG14_FLGPAD   (1 << 7)
+       unsigned char  cfg_byte15;
+#define CFG15_CSTF(x)  (x)
+#define CFG15_ICSS     (1 << 3)
+#define CFG15_CDTF(x)  (x << 4)
+#define CFG15_ICDS     (1 << 7)
+       unsigned short cfg_minfrmlen;
+} cfg_t;
+
+typedef struct { /* scb */
+       unsigned short scb_status;      /* status of 82586                      */
+#define SCB_STRXMASK           (7 << 4)        /* Receive unit status          */
+#define SCB_STRXIDLE           (0 << 4)        /* Idle                         */
+#define SCB_STRXSUSP           (1 << 4)        /* Suspended                    */
+#define SCB_STRXNRES           (2 << 4)        /* No resources                 */
+#define SCB_STRXRDY            (4 << 4)        /* Ready                        */
+#define SCB_STCUMASK           (7 << 8)        /* Command unit status          */
+#define SCB_STCUIDLE           (0 << 8)        /* Idle                         */
+#define SCB_STCUSUSP           (1 << 8)        /* Suspended                    */
+#define SCB_STCUACTV           (2 << 8)        /* Active                       */
+#define SCB_STRNR              (1 << 12)       /* Receive unit not ready       */
+#define SCB_STCNA              (1 << 13)       /* Command unit not ready       */
+#define SCB_STFR               (1 << 14)       /* Frame received               */
+#define SCB_STCX               (1 << 15)       /* Command completed            */
+       unsigned short scb_command;     /* Next command                         */
+#define SCB_CMDRXSTART         (1 << 4)        /* Start (at rfa_offset)        */
+#define SCB_CMDRXRESUME                (2 << 4)        /* Resume reception             */
+#define SCB_CMDRXSUSPEND       (3 << 4)        /* Suspend reception            */
+#define SCB_CMDRXABORT         (4 << 4)        /* Abort reception              */
+#define SCB_CMDCUCSTART                (1 << 8)        /* Start (at cbl_offset)        */
+#define SCB_CMDCUCRESUME       (2 << 8)        /* Resume execution             */
+#define SCB_CMDCUCSUSPEND      (3 << 8)        /* Suspend execution            */
+#define SCB_CMDCUCABORT                (4 << 8)        /* Abort execution              */
+#define SCB_CMDACKRNR          (1 << 12)       /* Ack RU not ready             */
+#define SCB_CMDACKCNA          (1 << 13)       /* Ack CU not ready             */
+#define SCB_CMDACKFR           (1 << 14)       /* Ack Frame received           */
+#define SCB_CMDACKCX           (1 << 15)       /* Ack Command complete         */
+       unsigned short scb_cbl_offset;  /* Offset of first command unit         */
+       unsigned short scb_rfa_offset;  /* Offset of first receive frame area   */
+       unsigned short scb_crc_errors;  /* Properly aligned frame with CRC error*/
+       unsigned short scb_aln_errors;  /* Misaligned frames                    */
+       unsigned short scb_rsc_errors;  /* Frames lost due to no space          */
+       unsigned short scb_ovn_errors;  /* Frames lost due to slow bus          */
+} scb_t;
+
+typedef struct { /* iscp */
+       unsigned short iscp_busy;       /* set by CPU before CA                 */
+       unsigned short iscp_offset;     /* offset of SCB                        */
+       unsigned short iscp_basel;      /* base of SCB                          */
+       unsigned short iscp_baseh;
+} iscp_t;
+
+    /* this address must be 0xfff6 */
+typedef struct { /* scp */
+       unsigned short scp_sysbus;      /* bus size */
+#define SCP_SY_16BBUS  0x00
+#define SCP_SY_8BBUS   0x01
+       unsigned short scp_junk[2];     /* junk */
+       unsigned short scp_iscpl;       /* lower 16 bits of iscp */
+       unsigned short scp_iscph;       /* upper 16 bits of iscp */
+} scp_t;
+
+/* commands */
+#define CMD_NOP                        0
+#define CMD_SETADDRESS         1
+#define CMD_CONFIG             2
+#define CMD_SETMULTICAST       3
+#define CMD_TX                 4
+#define CMD_TDR                        5
+#define CMD_DUMP               6
+#define CMD_DIAGNOSE           7
+
+#define CMD_MASK               7
+
+#define CMD_INTR               (1 << 13)
+#define CMD_SUSP               (1 << 14)
+#define CMD_EOL                        (1 << 15)
+
+#define STAT_COLLISIONS                (15)
+#define STAT_COLLEXCESSIVE     (1 << 5)
+#define STAT_COLLAFTERTX       (1 << 6)
+#define STAT_TXDEFERRED                (1 << 7)
+#define STAT_TXSLOWDMA         (1 << 8)
+#define STAT_TXLOSTCTS         (1 << 9)
+#define STAT_NOCARRIER         (1 << 10)
+#define STAT_FAIL              (1 << 11)
+#define STAT_ABORTED           (1 << 12)
+#define STAT_OK                        (1 << 13)
+#define STAT_BUSY              (1 << 14)
+#define STAT_COMPLETE          (1 << 15)
+#endif
+#endif
+
+/*
+ * Ether1 card definitions:
+ *
+ * FAST accesses:
+ *     +0      Page register
+ *                     16 pages
+ *     +4      Control
+ *                     '1' = reset
+ *                     '2' = loopback
+ *                     '4' = CA
+ *                     '8' = int ack
+ *
+ * RAM at address + 0x2000
+ * Pod. Prod id = 3
+ * Words after ID block [base + 8 words]
+ *     +0 pcb issue (0x0c and 0xf3 invalid)
+ *     +1 - +6 eth hw address
+ */
diff --git a/drivers/net/ethernet/i825xx/lasi_82596.c b/drivers/net/ethernet/i825xx/lasi_82596.c
new file mode 100644 (file)
index 0000000..6eba352
--- /dev/null
@@ -0,0 +1,238 @@
+/* lasi_82596.c -- driver for the intel 82596 ethernet controller, as
+   munged into HPPA boxen .
+
+   This driver is based upon 82596.c, original credits are below...
+   but there were too many hoops which HP wants jumped through to
+   keep this code in there in a sane manner.
+
+   3 primary sources of the mess --
+   1) hppa needs *lots* of cacheline flushing to keep this kind of
+   MMIO running.
+
+   2) The 82596 needs to see all of its pointers as their physical
+   address.  Thus virt_to_bus/bus_to_virt are *everywhere*.
+
+   3) The implementation HP is using seems to be significantly pickier
+   about when and how the command and RX units are started.  some
+   command ordering was changed.
+
+   Examination of the mach driver leads one to believe that there
+   might be a saner way to pull this off...  anyone who feels like a
+   full rewrite can be my guest.
+
+   Split 02/13/2000 Sam Creasey (sammy@oh.verio.com)
+
+   02/01/2000  Initial modifications for parisc by Helge Deller (deller@gmx.de)
+   03/02/2000  changes for better/correct(?) cache-flushing (deller)
+*/
+
+/* 82596.c: A generic 82596 ethernet driver for linux. */
+/*
+   Based on Apricot.c
+   Written 1994 by Mark Evans.
+   This driver is for the Apricot 82596 bus-master interface
+
+   Modularised 12/94 Mark Evans
+
+
+   Modified to support the 82596 ethernet chips on 680x0 VME boards.
+   by Richard Hirst <richard@sleepie.demon.co.uk>
+   Renamed to be 82596.c
+
+   980825:  Changed to receive directly in to sk_buffs which are
+   allocated at open() time.  Eliminates copy on incoming frames
+   (small ones are still copied).  Shared data now held in a
+   non-cached page, so we can run on 68060 in copyback mode.
+
+   TBD:
+   * look at deferring rx frames rather than discarding (as per tulip)
+   * handle tx ring full as per tulip
+   * performance test to tune rx_copybreak
+
+   Most of my modifications relate to the braindead big-endian
+   implementation by Intel.  When the i596 is operating in
+   'big-endian' mode, it thinks a 32 bit value of 0x12345678
+   should be stored as 0x56781234.  This is a real pain, when
+   you have linked lists which are shared by the 680x0 and the
+   i596.
+
+   Driver skeleton
+   Written 1993 by Donald Becker.
+   Copyright 1993 United States Government as represented by the Director,
+   National Security Agency. This software may only be used and distributed
+   according to the terms of the GNU General Public License as modified by SRC,
+   incorporated herein by reference.
+
+   The author may be reached as becker@scyld.com, or C/O
+   Scyld Computing Corporation, 410 Severn Ave., Suite 210, Annapolis MD 21403
+
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/bitops.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/pdc.h>
+#include <asm/parisc-device.h>
+
+#define LASI_82596_DRIVER_VERSION "LASI 82596 driver - Revision: 1.30"
+
+#define PA_I82596_RESET                0       /* Offsets relative to LASI-LAN-Addr.*/
+#define PA_CPU_PORT_L_ACCESS   4
+#define PA_CHANNEL_ATTENTION   8
+
+#define OPT_SWAP_PORT  0x0001  /* Need to wordswp on the MPU port */
+
+#define DMA_ALLOC                        dma_alloc_noncoherent
+#define DMA_FREE                         dma_free_noncoherent
+#define DMA_WBACK(ndev, addr, len) \
+       do { dma_cache_sync((ndev)->dev.parent, (void *)addr, len, DMA_TO_DEVICE); } while (0)
+
+#define DMA_INV(ndev, addr, len) \
+       do { dma_cache_sync((ndev)->dev.parent, (void *)addr, len, DMA_FROM_DEVICE); } while (0)
+
+#define DMA_WBACK_INV(ndev, addr, len) \
+       do { dma_cache_sync((ndev)->dev.parent, (void *)addr, len, DMA_BIDIRECTIONAL); } while (0)
+
+#define SYSBUS      0x0000006c;
+
+/* big endian CPU, 82596 "big" endian mode */
+#define SWAP32(x)   (((u32)(x)<<16) | ((((u32)(x)))>>16))
+#define SWAP16(x)   (x)
+
+#include "lib82596.c"
+
+MODULE_AUTHOR("Richard Hirst");
+MODULE_DESCRIPTION("i82596 driver");
+MODULE_LICENSE("GPL");
+module_param(i596_debug, int, 0);
+MODULE_PARM_DESC(i596_debug, "lasi_82596 debug mask");
+
+static inline void ca(struct net_device *dev)
+{
+       gsc_writel(0, dev->base_addr + PA_CHANNEL_ATTENTION);
+}
+
+
+static void mpu_port(struct net_device *dev, int c, dma_addr_t x)
+{
+       struct i596_private *lp = netdev_priv(dev);
+
+       u32 v = (u32) (c) | (u32) (x);
+       u16 a, b;
+
+       if (lp->options & OPT_SWAP_PORT) {
+               a = v >> 16;
+               b = v & 0xffff;
+       } else {
+               a = v & 0xffff;
+               b = v >> 16;
+       }
+
+       gsc_writel(a, dev->base_addr + PA_CPU_PORT_L_ACCESS);
+       udelay(1);
+       gsc_writel(b, dev->base_addr + PA_CPU_PORT_L_ACCESS);
+}
+
+#define LAN_PROM_ADDR  0xF0810000
+
+static int __devinit
+lan_init_chip(struct parisc_device *dev)
+{
+       struct  net_device *netdevice;
+       struct i596_private *lp;
+       int     retval;
+       int i;
+
+       if (!dev->irq) {
+               printk(KERN_ERR "%s: IRQ not found for i82596 at 0x%lx\n",
+                       __FILE__, (unsigned long)dev->hpa.start);
+               return -ENODEV;
+       }
+
+       printk(KERN_INFO "Found i82596 at 0x%lx, IRQ %d\n",
+                       (unsigned long)dev->hpa.start, dev->irq);
+
+       netdevice = alloc_etherdev(sizeof(struct i596_private));
+       if (!netdevice)
+               return -ENOMEM;
+       SET_NETDEV_DEV(netdevice, &dev->dev);
+       parisc_set_drvdata (dev, netdevice);
+
+       netdevice->base_addr = dev->hpa.start;
+       netdevice->irq = dev->irq;
+
+       if (pdc_lan_station_id(netdevice->dev_addr, netdevice->base_addr)) {
+               for (i = 0; i < 6; i++) {
+                       netdevice->dev_addr[i] = gsc_readb(LAN_PROM_ADDR + i);
+               }
+               printk(KERN_INFO
+                      "%s: MAC of HP700 LAN read from EEPROM\n", __FILE__);
+       }
+
+       lp = netdev_priv(netdevice);
+       lp->options = dev->id.sversion == 0x72 ? OPT_SWAP_PORT : 0;
+
+       retval = i82596_probe(netdevice);
+       if (retval) {
+               free_netdev(netdevice);
+               return -ENODEV;
+       }
+       return retval;
+}
+
+static int __devexit lan_remove_chip (struct parisc_device *pdev)
+{
+       struct net_device *dev = parisc_get_drvdata(pdev);
+       struct i596_private *lp = netdev_priv(dev);
+
+       unregister_netdev (dev);
+       DMA_FREE(&pdev->dev, sizeof(struct i596_private),
+                (void *)lp->dma, lp->dma_addr);
+       free_netdev (dev);
+       return 0;
+}
+
+static struct parisc_device_id lan_tbl[] = {
+       { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0008a },
+       { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00072 },
+       { 0, }
+};
+
+MODULE_DEVICE_TABLE(parisc, lan_tbl);
+
+static struct parisc_driver lan_driver = {
+       .name           = "lasi_82596",
+       .id_table       = lan_tbl,
+       .probe          = lan_init_chip,
+       .remove         = __devexit_p(lan_remove_chip),
+};
+
+static int __devinit lasi_82596_init(void)
+{
+       printk(KERN_INFO LASI_82596_DRIVER_VERSION "\n");
+       return register_parisc_driver(&lan_driver);
+}
+
+module_init(lasi_82596_init);
+
+static void __exit lasi_82596_exit(void)
+{
+       unregister_parisc_driver(&lan_driver);
+}
+
+module_exit(lasi_82596_exit);
diff --git a/drivers/net/ethernet/i825xx/lib82596.c b/drivers/net/ethernet/i825xx/lib82596.c
new file mode 100644 (file)
index 0000000..9e04289
--- /dev/null
@@ -0,0 +1,1412 @@
+/* lasi_82596.c -- driver for the intel 82596 ethernet controller, as
+   munged into HPPA boxen .
+
+   This driver is based upon 82596.c, original credits are below...
+   but there were too many hoops which HP wants jumped through to
+   keep this code in there in a sane manner.
+
+   3 primary sources of the mess --
+   1) hppa needs *lots* of cacheline flushing to keep this kind of
+   MMIO running.
+
+   2) The 82596 needs to see all of its pointers as their physical
+   address.  Thus virt_to_bus/bus_to_virt are *everywhere*.
+
+   3) The implementation HP is using seems to be significantly pickier
+   about when and how the command and RX units are started.  some
+   command ordering was changed.
+
+   Examination of the mach driver leads one to believe that there
+   might be a saner way to pull this off...  anyone who feels like a
+   full rewrite can be my guest.
+
+   Split 02/13/2000 Sam Creasey (sammy@oh.verio.com)
+
+   02/01/2000  Initial modifications for parisc by Helge Deller (deller@gmx.de)
+   03/02/2000  changes for better/correct(?) cache-flushing (deller)
+*/
+
+/* 82596.c: A generic 82596 ethernet driver for linux. */
+/*
+   Based on Apricot.c
+   Written 1994 by Mark Evans.
+   This driver is for the Apricot 82596 bus-master interface
+
+   Modularised 12/94 Mark Evans
+
+
+   Modified to support the 82596 ethernet chips on 680x0 VME boards.
+   by Richard Hirst <richard@sleepie.demon.co.uk>
+   Renamed to be 82596.c
+
+   980825:  Changed to receive directly in to sk_buffs which are
+   allocated at open() time.  Eliminates copy on incoming frames
+   (small ones are still copied).  Shared data now held in a
+   non-cached page, so we can run on 68060 in copyback mode.
+
+   TBD:
+   * look at deferring rx frames rather than discarding (as per tulip)
+   * handle tx ring full as per tulip
+   * performance test to tune rx_copybreak
+
+   Most of my modifications relate to the braindead big-endian
+   implementation by Intel.  When the i596 is operating in
+   'big-endian' mode, it thinks a 32 bit value of 0x12345678
+   should be stored as 0x56781234.  This is a real pain, when
+   you have linked lists which are shared by the 680x0 and the
+   i596.
+
+   Driver skeleton
+   Written 1993 by Donald Becker.
+   Copyright 1993 United States Government as represented by the Director,
+   National Security Agency. This software may only be used and distributed
+   according to the terms of the GNU General Public License as modified by SRC,
+   incorporated herein by reference.
+
+   The author may be reached as becker@scyld.com, or C/O
+   Scyld Computing Corporation, 410 Severn Ave., Suite 210, Annapolis MD 21403
+
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/bitops.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/gfp.h>
+
+/* DEBUG flags
+ */
+
+#define DEB_INIT       0x0001
+#define DEB_PROBE      0x0002
+#define DEB_SERIOUS    0x0004
+#define DEB_ERRORS     0x0008
+#define DEB_MULTI      0x0010
+#define DEB_TDR                0x0020
+#define DEB_OPEN       0x0040
+#define DEB_RESET      0x0080
+#define DEB_ADDCMD     0x0100
+#define DEB_STATUS     0x0200
+#define DEB_STARTTX    0x0400
+#define DEB_RXADDR     0x0800
+#define DEB_TXADDR     0x1000
+#define DEB_RXFRAME    0x2000
+#define DEB_INTS       0x4000
+#define DEB_STRUCT     0x8000
+#define DEB_ANY                0xffff
+
+
+#define DEB(x, y)      if (i596_debug & (x)) { y; }
+
+
+/*
+ * The MPU_PORT command allows direct access to the 82596. With PORT access
+ * the following commands are available (p5-18). The 32-bit port command
+ * must be word-swapped with the most significant word written first.
+ * This only applies to VME boards.
+ */
+#define PORT_RESET             0x00    /* reset 82596 */
+#define PORT_SELFTEST          0x01    /* selftest */
+#define PORT_ALTSCP            0x02    /* alternate SCB address */
+#define PORT_ALTDUMP           0x03    /* Alternate DUMP address */
+
+static int i596_debug = (DEB_SERIOUS|DEB_PROBE);
+
+/* Copy frames shorter than rx_copybreak, otherwise pass on up in
+ * a full sized sk_buff.  Value of 100 stolen from tulip.c (!alpha).
+ */
+static int rx_copybreak = 100;
+
+#define PKT_BUF_SZ     1536
+#define MAX_MC_CNT     64
+
+#define ISCP_BUSY      0x0001
+
+#define I596_NULL ((u32)0xffffffff)
+
+#define CMD_EOL                0x8000  /* The last command of the list, stop. */
+#define CMD_SUSP       0x4000  /* Suspend after doing cmd. */
+#define CMD_INTR       0x2000  /* Interrupt after doing cmd. */
+
+#define CMD_FLEX       0x0008  /* Enable flexible memory model */
+
+enum commands {
+       CmdNOp = 0, CmdSASetup = 1, CmdConfigure = 2, CmdMulticastList = 3,
+       CmdTx = 4, CmdTDR = 5, CmdDump = 6, CmdDiagnose = 7
+};
+
+#define STAT_C         0x8000  /* Set to 0 after execution */
+#define STAT_B         0x4000  /* Command being executed */
+#define STAT_OK                0x2000  /* Command executed ok */
+#define STAT_A         0x1000  /* Command aborted */
+
+#define         CUC_START      0x0100
+#define         CUC_RESUME     0x0200
+#define         CUC_SUSPEND    0x0300
+#define         CUC_ABORT      0x0400
+#define         RX_START       0x0010
+#define         RX_RESUME      0x0020
+#define         RX_SUSPEND     0x0030
+#define         RX_ABORT       0x0040
+
+#define TX_TIMEOUT     (HZ/20)
+
+
+struct i596_reg {
+       unsigned short porthi;
+       unsigned short portlo;
+       u32            ca;
+};
+
+#define EOF            0x8000
+#define SIZE_MASK      0x3fff
+
+struct i596_tbd {
+       unsigned short size;
+       unsigned short pad;
+       u32            next;
+       u32            data;
+       u32 cache_pad[5];               /* Total 32 bytes... */
+};
+
+/* The command structure has two 'next' pointers; v_next is the address of
+ * the next command as seen by the CPU, b_next is the address of the next
+ * command as seen by the 82596.  The b_next pointer, as used by the 82596
+ * always references the status field of the next command, rather than the
+ * v_next field, because the 82596 is unaware of v_next.  It may seem more
+ * logical to put v_next at the end of the structure, but we cannot do that
+ * because the 82596 expects other fields to be there, depending on command
+ * type.
+ */
+
+struct i596_cmd {
+       struct i596_cmd *v_next;        /* Address from CPUs viewpoint */
+       unsigned short status;
+       unsigned short command;
+       u32            b_next;  /* Address from i596 viewpoint */
+};
+
+struct tx_cmd {
+       struct i596_cmd cmd;
+       u32            tbd;
+       unsigned short size;
+       unsigned short pad;
+       struct sk_buff *skb;            /* So we can free it after tx */
+       dma_addr_t dma_addr;
+#ifdef __LP64__
+       u32 cache_pad[6];               /* Total 64 bytes... */
+#else
+       u32 cache_pad[1];               /* Total 32 bytes... */
+#endif
+};
+
+struct tdr_cmd {
+       struct i596_cmd cmd;
+       unsigned short status;
+       unsigned short pad;
+};
+
+struct mc_cmd {
+       struct i596_cmd cmd;
+       short mc_cnt;
+       char mc_addrs[MAX_MC_CNT*6];
+};
+
+struct sa_cmd {
+       struct i596_cmd cmd;
+       char eth_addr[8];
+};
+
+struct cf_cmd {
+       struct i596_cmd cmd;
+       char i596_config[16];
+};
+
+struct i596_rfd {
+       unsigned short stat;
+       unsigned short cmd;
+       u32            b_next;  /* Address from i596 viewpoint */
+       u32            rbd;
+       unsigned short count;
+       unsigned short size;
+       struct i596_rfd *v_next;        /* Address from CPUs viewpoint */
+       struct i596_rfd *v_prev;
+#ifndef __LP64__
+       u32 cache_pad[2];               /* Total 32 bytes... */
+#endif
+};
+
+struct i596_rbd {
+       /* hardware data */
+       unsigned short count;
+       unsigned short zero1;
+       u32            b_next;
+       u32            b_data;          /* Address from i596 viewpoint */
+       unsigned short size;
+       unsigned short zero2;
+       /* driver data */
+       struct sk_buff *skb;
+       struct i596_rbd *v_next;
+       u32            b_addr;          /* This rbd addr from i596 view */
+       unsigned char *v_data;          /* Address from CPUs viewpoint */
+                                       /* Total 32 bytes... */
+#ifdef __LP64__
+    u32 cache_pad[4];
+#endif
+};
+
+/* These values as chosen so struct i596_dma fits in one page... */
+
+#define TX_RING_SIZE 32
+#define RX_RING_SIZE 16
+
+struct i596_scb {
+       unsigned short status;
+       unsigned short command;
+       u32           cmd;
+       u32           rfd;
+       u32           crc_err;
+       u32           align_err;
+       u32           resource_err;
+       u32           over_err;
+       u32           rcvdt_err;
+       u32           short_err;
+       unsigned short t_on;
+       unsigned short t_off;
+};
+
+struct i596_iscp {
+       u32 stat;
+       u32 scb;
+};
+
+struct i596_scp {
+       u32 sysbus;
+       u32 pad;
+       u32 iscp;
+};
+
+struct i596_dma {
+       struct i596_scp scp                     __attribute__((aligned(32)));
+       volatile struct i596_iscp iscp          __attribute__((aligned(32)));
+       volatile struct i596_scb scb            __attribute__((aligned(32)));
+       struct sa_cmd sa_cmd                    __attribute__((aligned(32)));
+       struct cf_cmd cf_cmd                    __attribute__((aligned(32)));
+       struct tdr_cmd tdr_cmd                  __attribute__((aligned(32)));
+       struct mc_cmd mc_cmd                    __attribute__((aligned(32)));
+       struct i596_rfd rfds[RX_RING_SIZE]      __attribute__((aligned(32)));
+       struct i596_rbd rbds[RX_RING_SIZE]      __attribute__((aligned(32)));
+       struct tx_cmd tx_cmds[TX_RING_SIZE]     __attribute__((aligned(32)));
+       struct i596_tbd tbds[TX_RING_SIZE]      __attribute__((aligned(32)));
+};
+
+struct i596_private {
+       struct i596_dma *dma;
+       u32    stat;
+       int last_restart;
+       struct i596_rfd *rfd_head;
+       struct i596_rbd *rbd_head;
+       struct i596_cmd *cmd_tail;
+       struct i596_cmd *cmd_head;
+       int cmd_backlog;
+       u32    last_cmd;
+       int next_tx_cmd;
+       int options;
+       spinlock_t lock;       /* serialize access to chip */
+       dma_addr_t dma_addr;
+       void __iomem *mpu_port;
+       void __iomem *ca;
+};
+
+static const char init_setup[] =
+{
+       0x8E,           /* length, prefetch on */
+       0xC8,           /* fifo to 8, monitor off */
+       0x80,           /* don't save bad frames */
+       0x2E,           /* No source address insertion, 8 byte preamble */
+       0x00,           /* priority and backoff defaults */
+       0x60,           /* interframe spacing */
+       0x00,           /* slot time LSB */
+       0xf2,           /* slot time and retries */
+       0x00,           /* promiscuous mode */
+       0x00,           /* collision detect */
+       0x40,           /* minimum frame length */
+       0xff,
+       0x00,
+       0x7f /*  *multi IA */ };
+
+static int i596_open(struct net_device *dev);
+static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static irqreturn_t i596_interrupt(int irq, void *dev_id);
+static int i596_close(struct net_device *dev);
+static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd);
+static void i596_tx_timeout (struct net_device *dev);
+static void print_eth(unsigned char *buf, char *str);
+static void set_multicast_list(struct net_device *dev);
+static inline void ca(struct net_device *dev);
+static void mpu_port(struct net_device *dev, int c, dma_addr_t x);
+
+static int rx_ring_size = RX_RING_SIZE;
+static int ticks_limit = 100;
+static int max_cmd_backlog = TX_RING_SIZE-1;
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void i596_poll_controller(struct net_device *dev);
+#endif
+
+
+static inline int wait_istat(struct net_device *dev, struct i596_dma *dma, int delcnt, char *str)
+{
+       DMA_INV(dev, &(dma->iscp), sizeof(struct i596_iscp));
+       while (--delcnt && dma->iscp.stat) {
+               udelay(10);
+               DMA_INV(dev, &(dma->iscp), sizeof(struct i596_iscp));
+       }
+       if (!delcnt) {
+               printk(KERN_ERR "%s: %s, iscp.stat %04x, didn't clear\n",
+                    dev->name, str, SWAP16(dma->iscp.stat));
+               return -1;
+       } else
+               return 0;
+}
+
+
+static inline int wait_cmd(struct net_device *dev, struct i596_dma *dma, int delcnt, char *str)
+{
+       DMA_INV(dev, &(dma->scb), sizeof(struct i596_scb));
+       while (--delcnt && dma->scb.command) {
+               udelay(10);
+               DMA_INV(dev, &(dma->scb), sizeof(struct i596_scb));
+       }
+       if (!delcnt) {
+               printk(KERN_ERR "%s: %s, status %4.4x, cmd %4.4x.\n",
+                      dev->name, str,
+                      SWAP16(dma->scb.status),
+                      SWAP16(dma->scb.command));
+               return -1;
+       } else
+               return 0;
+}
+
+
+static void i596_display_data(struct net_device *dev)
+{
+       struct i596_private *lp = netdev_priv(dev);
+       struct i596_dma *dma = lp->dma;
+       struct i596_cmd *cmd;
+       struct i596_rfd *rfd;
+       struct i596_rbd *rbd;
+
+       printk(KERN_DEBUG "lp and scp at %p, .sysbus = %08x, .iscp = %08x\n",
+              &dma->scp, dma->scp.sysbus, SWAP32(dma->scp.iscp));
+       printk(KERN_DEBUG "iscp at %p, iscp.stat = %08x, .scb = %08x\n",
+              &dma->iscp, SWAP32(dma->iscp.stat), SWAP32(dma->iscp.scb));
+       printk(KERN_DEBUG "scb at %p, scb.status = %04x, .command = %04x,"
+               " .cmd = %08x, .rfd = %08x\n",
+              &dma->scb, SWAP16(dma->scb.status), SWAP16(dma->scb.command),
+               SWAP16(dma->scb.cmd), SWAP32(dma->scb.rfd));
+       printk(KERN_DEBUG "   errors: crc %x, align %x, resource %x,"
+              " over %x, rcvdt %x, short %x\n",
+              SWAP32(dma->scb.crc_err), SWAP32(dma->scb.align_err),
+              SWAP32(dma->scb.resource_err), SWAP32(dma->scb.over_err),
+              SWAP32(dma->scb.rcvdt_err), SWAP32(dma->scb.short_err));
+       cmd = lp->cmd_head;
+       while (cmd != NULL) {
+               printk(KERN_DEBUG
+                      "cmd at %p, .status = %04x, .command = %04x,"
+                      " .b_next = %08x\n",
+                      cmd, SWAP16(cmd->status), SWAP16(cmd->command),
+                      SWAP32(cmd->b_next));
+               cmd = cmd->v_next;
+       }
+       rfd = lp->rfd_head;
+       printk(KERN_DEBUG "rfd_head = %p\n", rfd);
+       do {
+               printk(KERN_DEBUG
+                      "   %p .stat %04x, .cmd %04x, b_next %08x, rbd %08x,"
+                      " count %04x\n",
+                      rfd, SWAP16(rfd->stat), SWAP16(rfd->cmd),
+                      SWAP32(rfd->b_next), SWAP32(rfd->rbd),
+                      SWAP16(rfd->count));
+               rfd = rfd->v_next;
+       } while (rfd != lp->rfd_head);
+       rbd = lp->rbd_head;
+       printk(KERN_DEBUG "rbd_head = %p\n", rbd);
+       do {
+               printk(KERN_DEBUG
+                      "   %p .count %04x, b_next %08x, b_data %08x,"
+                      " size %04x\n",
+                       rbd, SWAP16(rbd->count), SWAP32(rbd->b_next),
+                      SWAP32(rbd->b_data), SWAP16(rbd->size));
+               rbd = rbd->v_next;
+       } while (rbd != lp->rbd_head);
+       DMA_INV(dev, dma, sizeof(struct i596_dma));
+}
+
+
+#define virt_to_dma(lp, v) ((lp)->dma_addr + (dma_addr_t)((unsigned long)(v)-(unsigned long)((lp)->dma)))
+
+static inline int init_rx_bufs(struct net_device *dev)
+{
+       struct i596_private *lp = netdev_priv(dev);
+       struct i596_dma *dma = lp->dma;
+       int i;
+       struct i596_rfd *rfd;
+       struct i596_rbd *rbd;
+
+       /* First build the Receive Buffer Descriptor List */
+
+       for (i = 0, rbd = dma->rbds; i < rx_ring_size; i++, rbd++) {
+               dma_addr_t dma_addr;
+               struct sk_buff *skb;
+
+               skb = netdev_alloc_skb_ip_align(dev, PKT_BUF_SZ);
+               if (skb == NULL)
+                       return -1;
+               dma_addr = dma_map_single(dev->dev.parent, skb->data,
+                                         PKT_BUF_SZ, DMA_FROM_DEVICE);
+               rbd->v_next = rbd+1;
+               rbd->b_next = SWAP32(virt_to_dma(lp, rbd+1));
+               rbd->b_addr = SWAP32(virt_to_dma(lp, rbd));
+               rbd->skb = skb;
+               rbd->v_data = skb->data;
+               rbd->b_data = SWAP32(dma_addr);
+               rbd->size = SWAP16(PKT_BUF_SZ);
+       }
+       lp->rbd_head = dma->rbds;
+       rbd = dma->rbds + rx_ring_size - 1;
+       rbd->v_next = dma->rbds;
+       rbd->b_next = SWAP32(virt_to_dma(lp, dma->rbds));
+
+       /* Now build the Receive Frame Descriptor List */
+
+       for (i = 0, rfd = dma->rfds; i < rx_ring_size; i++, rfd++) {
+               rfd->rbd = I596_NULL;
+               rfd->v_next = rfd+1;
+               rfd->v_prev = rfd-1;
+               rfd->b_next = SWAP32(virt_to_dma(lp, rfd+1));
+               rfd->cmd = SWAP16(CMD_FLEX);
+       }
+       lp->rfd_head = dma->rfds;
+       dma->scb.rfd = SWAP32(virt_to_dma(lp, dma->rfds));
+       rfd = dma->rfds;
+       rfd->rbd = SWAP32(virt_to_dma(lp, lp->rbd_head));
+       rfd->v_prev = dma->rfds + rx_ring_size - 1;
+       rfd = dma->rfds + rx_ring_size - 1;
+       rfd->v_next = dma->rfds;
+       rfd->b_next = SWAP32(virt_to_dma(lp, dma->rfds));
+       rfd->cmd = SWAP16(CMD_EOL|CMD_FLEX);
+
+       DMA_WBACK_INV(dev, dma, sizeof(struct i596_dma));
+       return 0;
+}
+
+static inline void remove_rx_bufs(struct net_device *dev)
+{
+       struct i596_private *lp = netdev_priv(dev);
+       struct i596_rbd *rbd;
+       int i;
+
+       for (i = 0, rbd = lp->dma->rbds; i < rx_ring_size; i++, rbd++) {
+               if (rbd->skb == NULL)
+                       break;
+               dma_unmap_single(dev->dev.parent,
+                                (dma_addr_t)SWAP32(rbd->b_data),
+                                PKT_BUF_SZ, DMA_FROM_DEVICE);
+               dev_kfree_skb(rbd->skb);
+       }
+}
+
+
+static void rebuild_rx_bufs(struct net_device *dev)
+{
+       struct i596_private *lp = netdev_priv(dev);
+       struct i596_dma *dma = lp->dma;
+       int i;
+
+       /* Ensure rx frame/buffer descriptors are tidy */
+
+       for (i = 0; i < rx_ring_size; i++) {
+               dma->rfds[i].rbd = I596_NULL;
+               dma->rfds[i].cmd = SWAP16(CMD_FLEX);
+       }
+       dma->rfds[rx_ring_size-1].cmd = SWAP16(CMD_EOL|CMD_FLEX);
+       lp->rfd_head = dma->rfds;
+       dma->scb.rfd = SWAP32(virt_to_dma(lp, dma->rfds));
+       lp->rbd_head = dma->rbds;
+       dma->rfds[0].rbd = SWAP32(virt_to_dma(lp, dma->rbds));
+
+       DMA_WBACK_INV(dev, dma, sizeof(struct i596_dma));
+}
+
+
+static int init_i596_mem(struct net_device *dev)
+{
+       struct i596_private *lp = netdev_priv(dev);
+       struct i596_dma *dma = lp->dma;
+       unsigned long flags;
+
+       mpu_port(dev, PORT_RESET, 0);
+       udelay(100);                    /* Wait 100us - seems to help */
+
+       /* change the scp address */
+
+       lp->last_cmd = jiffies;
+
+       dma->scp.sysbus = SYSBUS;
+       dma->scp.iscp = SWAP32(virt_to_dma(lp, &(dma->iscp)));
+       dma->iscp.scb = SWAP32(virt_to_dma(lp, &(dma->scb)));
+       dma->iscp.stat = SWAP32(ISCP_BUSY);
+       lp->cmd_backlog = 0;
+
+       lp->cmd_head = NULL;
+       dma->scb.cmd = I596_NULL;
+
+       DEB(DEB_INIT, printk(KERN_DEBUG "%s: starting i82596.\n", dev->name));
+
+       DMA_WBACK(dev, &(dma->scp), sizeof(struct i596_scp));
+       DMA_WBACK(dev, &(dma->iscp), sizeof(struct i596_iscp));
+       DMA_WBACK(dev, &(dma->scb), sizeof(struct i596_scb));
+
+       mpu_port(dev, PORT_ALTSCP, virt_to_dma(lp, &dma->scp));
+       ca(dev);
+       if (wait_istat(dev, dma, 1000, "initialization timed out"))
+               goto failed;
+       DEB(DEB_INIT, printk(KERN_DEBUG
+                            "%s: i82596 initialization successful\n",
+                            dev->name));
+
+       if (request_irq(dev->irq, i596_interrupt, 0, "i82596", dev)) {
+               printk(KERN_ERR "%s: IRQ %d not free\n", dev->name, dev->irq);
+               goto failed;
+       }
+
+       /* Ensure rx frame/buffer descriptors are tidy */
+       rebuild_rx_bufs(dev);
+
+       dma->scb.command = 0;
+       DMA_WBACK(dev, &(dma->scb), sizeof(struct i596_scb));
+
+       DEB(DEB_INIT, printk(KERN_DEBUG
+                            "%s: queuing CmdConfigure\n", dev->name));
+       memcpy(dma->cf_cmd.i596_config, init_setup, 14);
+       dma->cf_cmd.cmd.command = SWAP16(CmdConfigure);
+       DMA_WBACK(dev, &(dma->cf_cmd), sizeof(struct cf_cmd));
+       i596_add_cmd(dev, &dma->cf_cmd.cmd);
+
+       DEB(DEB_INIT, printk(KERN_DEBUG "%s: queuing CmdSASetup\n", dev->name));
+       memcpy(dma->sa_cmd.eth_addr, dev->dev_addr, 6);
+       dma->sa_cmd.cmd.command = SWAP16(CmdSASetup);
+       DMA_WBACK(dev, &(dma->sa_cmd), sizeof(struct sa_cmd));
+       i596_add_cmd(dev, &dma->sa_cmd.cmd);
+
+       DEB(DEB_INIT, printk(KERN_DEBUG "%s: queuing CmdTDR\n", dev->name));
+       dma->tdr_cmd.cmd.command = SWAP16(CmdTDR);
+       DMA_WBACK(dev, &(dma->tdr_cmd), sizeof(struct tdr_cmd));
+       i596_add_cmd(dev, &dma->tdr_cmd.cmd);
+
+       spin_lock_irqsave (&lp->lock, flags);
+
+       if (wait_cmd(dev, dma, 1000, "timed out waiting to issue RX_START")) {
+               spin_unlock_irqrestore (&lp->lock, flags);
+               goto failed_free_irq;
+       }
+       DEB(DEB_INIT, printk(KERN_DEBUG "%s: Issuing RX_START\n", dev->name));
+       dma->scb.command = SWAP16(RX_START);
+       dma->scb.rfd = SWAP32(virt_to_dma(lp, dma->rfds));
+       DMA_WBACK(dev, &(dma->scb), sizeof(struct i596_scb));
+
+       ca(dev);
+
+       spin_unlock_irqrestore (&lp->lock, flags);
+       if (wait_cmd(dev, dma, 1000, "RX_START not processed"))
+               goto failed_free_irq;
+       DEB(DEB_INIT, printk(KERN_DEBUG
+                            "%s: Receive unit started OK\n", dev->name));
+       return 0;
+
+failed_free_irq:
+       free_irq(dev->irq, dev);
+failed:
+       printk(KERN_ERR "%s: Failed to initialise 82596\n", dev->name);
+       mpu_port(dev, PORT_RESET, 0);
+       return -1;
+}
+
+
+static inline int i596_rx(struct net_device *dev)
+{
+       struct i596_private *lp = netdev_priv(dev);
+       struct i596_rfd *rfd;
+       struct i596_rbd *rbd;
+       int frames = 0;
+
+       DEB(DEB_RXFRAME, printk(KERN_DEBUG
+                               "i596_rx(), rfd_head %p, rbd_head %p\n",
+                               lp->rfd_head, lp->rbd_head));
+
+
+       rfd = lp->rfd_head;             /* Ref next frame to check */
+
+       DMA_INV(dev, rfd, sizeof(struct i596_rfd));
+       while (rfd->stat & SWAP16(STAT_C)) {    /* Loop while complete frames */
+               if (rfd->rbd == I596_NULL)
+                       rbd = NULL;
+               else if (rfd->rbd == lp->rbd_head->b_addr) {
+                       rbd = lp->rbd_head;
+                       DMA_INV(dev, rbd, sizeof(struct i596_rbd));
+               } else {
+                       printk(KERN_ERR "%s: rbd chain broken!\n", dev->name);
+                       /* XXX Now what? */
+                       rbd = NULL;
+               }
+               DEB(DEB_RXFRAME, printk(KERN_DEBUG
+                                     "  rfd %p, rfd.rbd %08x, rfd.stat %04x\n",
+                                     rfd, rfd->rbd, rfd->stat));
+
+               if (rbd != NULL && (rfd->stat & SWAP16(STAT_OK))) {
+                       /* a good frame */
+                       int pkt_len = SWAP16(rbd->count) & 0x3fff;
+                       struct sk_buff *skb = rbd->skb;
+                       int rx_in_place = 0;
+
+                       DEB(DEB_RXADDR, print_eth(rbd->v_data, "received"));
+                       frames++;
+
+                       /* 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;
+                               dma_addr_t dma_addr;
+
+                               dma_unmap_single(dev->dev.parent,
+                                                (dma_addr_t)SWAP32(rbd->b_data),
+                                                PKT_BUF_SZ, DMA_FROM_DEVICE);
+                               /* Get fresh skbuff to replace filled one. */
+                               newskb = netdev_alloc_skb_ip_align(dev,
+                                                                  PKT_BUF_SZ);
+                               if (newskb == NULL) {
+                                       skb = NULL;     /* drop pkt */
+                                       goto memory_squeeze;
+                               }
+
+                               /* Pass up the skb already on the Rx ring. */
+                               skb_put(skb, pkt_len);
+                               rx_in_place = 1;
+                               rbd->skb = newskb;
+                               dma_addr = dma_map_single(dev->dev.parent,
+                                                         newskb->data,
+                                                         PKT_BUF_SZ,
+                                                         DMA_FROM_DEVICE);
+                               rbd->v_data = newskb->data;
+                               rbd->b_data = SWAP32(dma_addr);
+                               DMA_WBACK_INV(dev, rbd, sizeof(struct i596_rbd));
+                       } else
+                               skb = netdev_alloc_skb_ip_align(dev, pkt_len);
+memory_squeeze:
+                       if (skb == NULL) {
+                               /* XXX tulip.c can defer packets here!! */
+                               printk(KERN_ERR
+                                      "%s: i596_rx Memory squeeze, dropping packet.\n",
+                                      dev->name);
+                               dev->stats.rx_dropped++;
+                       } else {
+                               if (!rx_in_place) {
+                                       /* 16 byte align the data fields */
+                                       dma_sync_single_for_cpu(dev->dev.parent,
+                                                               (dma_addr_t)SWAP32(rbd->b_data),
+                                                               PKT_BUF_SZ, DMA_FROM_DEVICE);
+                                       memcpy(skb_put(skb, pkt_len), rbd->v_data, pkt_len);
+                                       dma_sync_single_for_device(dev->dev.parent,
+                                                                  (dma_addr_t)SWAP32(rbd->b_data),
+                                                                  PKT_BUF_SZ, DMA_FROM_DEVICE);
+                               }
+                               skb->len = pkt_len;
+                               skb->protocol = eth_type_trans(skb, dev);
+                               netif_rx(skb);
+                               dev->stats.rx_packets++;
+                               dev->stats.rx_bytes += pkt_len;
+                       }
+               } else {
+                       DEB(DEB_ERRORS, printk(KERN_DEBUG
+                                              "%s: Error, rfd.stat = 0x%04x\n",
+                                              dev->name, rfd->stat));
+                       dev->stats.rx_errors++;
+                       if (rfd->stat & SWAP16(0x0100))
+                               dev->stats.collisions++;
+                       if (rfd->stat & SWAP16(0x8000))
+                               dev->stats.rx_length_errors++;
+                       if (rfd->stat & SWAP16(0x0001))
+                               dev->stats.rx_over_errors++;
+                       if (rfd->stat & SWAP16(0x0002))
+                               dev->stats.rx_fifo_errors++;
+                       if (rfd->stat & SWAP16(0x0004))
+                               dev->stats.rx_frame_errors++;
+                       if (rfd->stat & SWAP16(0x0008))
+                               dev->stats.rx_crc_errors++;
+                       if (rfd->stat & SWAP16(0x0010))
+                               dev->stats.rx_length_errors++;
+               }
+
+               /* Clear the buffer descriptor count and EOF + F flags */
+
+               if (rbd != NULL && (rbd->count & SWAP16(0x4000))) {
+                       rbd->count = 0;
+                       lp->rbd_head = rbd->v_next;
+                       DMA_WBACK_INV(dev, rbd, sizeof(struct i596_rbd));
+               }
+
+               /* Tidy the frame descriptor, marking it as end of list */
+
+               rfd->rbd = I596_NULL;
+               rfd->stat = 0;
+               rfd->cmd = SWAP16(CMD_EOL|CMD_FLEX);
+               rfd->count = 0;
+
+               /* Update record of next frame descriptor to process */
+
+               lp->dma->scb.rfd = rfd->b_next;
+               lp->rfd_head = rfd->v_next;
+               DMA_WBACK_INV(dev, rfd, sizeof(struct i596_rfd));
+
+               /* Remove end-of-list from old end descriptor */
+
+               rfd->v_prev->cmd = SWAP16(CMD_FLEX);
+               DMA_WBACK_INV(dev, rfd->v_prev, sizeof(struct i596_rfd));
+               rfd = lp->rfd_head;
+               DMA_INV(dev, rfd, sizeof(struct i596_rfd));
+       }
+
+       DEB(DEB_RXFRAME, printk(KERN_DEBUG "frames %d\n", frames));
+
+       return 0;
+}
+
+
+static inline void i596_cleanup_cmd(struct net_device *dev, struct i596_private *lp)
+{
+       struct i596_cmd *ptr;
+
+       while (lp->cmd_head != NULL) {
+               ptr = lp->cmd_head;
+               lp->cmd_head = ptr->v_next;
+               lp->cmd_backlog--;
+
+               switch (SWAP16(ptr->command) & 0x7) {
+               case CmdTx:
+                       {
+                               struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr;
+                               struct sk_buff *skb = tx_cmd->skb;
+                               dma_unmap_single(dev->dev.parent,
+                                                tx_cmd->dma_addr,
+                                                skb->len, DMA_TO_DEVICE);
+
+                               dev_kfree_skb(skb);
+
+                               dev->stats.tx_errors++;
+                               dev->stats.tx_aborted_errors++;
+
+                               ptr->v_next = NULL;
+                               ptr->b_next = I596_NULL;
+                               tx_cmd->cmd.command = 0;  /* Mark as free */
+                               break;
+                       }
+               default:
+                       ptr->v_next = NULL;
+                       ptr->b_next = I596_NULL;
+               }
+               DMA_WBACK_INV(dev, ptr, sizeof(struct i596_cmd));
+       }
+
+       wait_cmd(dev, lp->dma, 100, "i596_cleanup_cmd timed out");
+       lp->dma->scb.cmd = I596_NULL;
+       DMA_WBACK(dev, &(lp->dma->scb), sizeof(struct i596_scb));
+}
+
+
+static inline void i596_reset(struct net_device *dev, struct i596_private *lp)
+{
+       unsigned long flags;
+
+       DEB(DEB_RESET, printk(KERN_DEBUG "i596_reset\n"));
+
+       spin_lock_irqsave (&lp->lock, flags);
+
+       wait_cmd(dev, lp->dma, 100, "i596_reset timed out");
+
+       netif_stop_queue(dev);
+
+       /* FIXME: this command might cause an lpmc */
+       lp->dma->scb.command = SWAP16(CUC_ABORT | RX_ABORT);
+       DMA_WBACK(dev, &(lp->dma->scb), sizeof(struct i596_scb));
+       ca(dev);
+
+       /* wait for shutdown */
+       wait_cmd(dev, lp->dma, 1000, "i596_reset 2 timed out");
+       spin_unlock_irqrestore (&lp->lock, flags);
+
+       i596_cleanup_cmd(dev, lp);
+       i596_rx(dev);
+
+       netif_start_queue(dev);
+       init_i596_mem(dev);
+}
+
+
+static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd)
+{
+       struct i596_private *lp = netdev_priv(dev);
+       struct i596_dma *dma = lp->dma;
+       unsigned long flags;
+
+       DEB(DEB_ADDCMD, printk(KERN_DEBUG "i596_add_cmd cmd_head %p\n",
+                              lp->cmd_head));
+
+       cmd->status = 0;
+       cmd->command |= SWAP16(CMD_EOL | CMD_INTR);
+       cmd->v_next = NULL;
+       cmd->b_next = I596_NULL;
+       DMA_WBACK(dev, cmd, sizeof(struct i596_cmd));
+
+       spin_lock_irqsave (&lp->lock, flags);
+
+       if (lp->cmd_head != NULL) {
+               lp->cmd_tail->v_next = cmd;
+               lp->cmd_tail->b_next = SWAP32(virt_to_dma(lp, &cmd->status));
+               DMA_WBACK(dev, lp->cmd_tail, sizeof(struct i596_cmd));
+       } else {
+               lp->cmd_head = cmd;
+               wait_cmd(dev, dma, 100, "i596_add_cmd timed out");
+               dma->scb.cmd = SWAP32(virt_to_dma(lp, &cmd->status));
+               dma->scb.command = SWAP16(CUC_START);
+               DMA_WBACK(dev, &(dma->scb), sizeof(struct i596_scb));
+               ca(dev);
+       }
+       lp->cmd_tail = cmd;
+       lp->cmd_backlog++;
+
+       spin_unlock_irqrestore (&lp->lock, flags);
+
+       if (lp->cmd_backlog > max_cmd_backlog) {
+               unsigned long tickssofar = jiffies - lp->last_cmd;
+
+               if (tickssofar < ticks_limit)
+                       return;
+
+               printk(KERN_ERR
+                      "%s: command unit timed out, status resetting.\n",
+                      dev->name);
+#if 1
+               i596_reset(dev, lp);
+#endif
+       }
+}
+
+static int i596_open(struct net_device *dev)
+{
+       DEB(DEB_OPEN, printk(KERN_DEBUG
+                            "%s: i596_open() irq %d.\n", dev->name, dev->irq));
+
+       if (init_rx_bufs(dev)) {
+               printk(KERN_ERR "%s: Failed to init rx bufs\n", dev->name);
+               return -EAGAIN;
+       }
+       if (init_i596_mem(dev)) {
+               printk(KERN_ERR "%s: Failed to init memory\n", dev->name);
+               goto out_remove_rx_bufs;
+       }
+       netif_start_queue(dev);
+
+       return 0;
+
+out_remove_rx_bufs:
+       remove_rx_bufs(dev);
+       return -EAGAIN;
+}
+
+static void i596_tx_timeout (struct net_device *dev)
+{
+       struct i596_private *lp = netdev_priv(dev);
+
+       /* Transmitter timeout, serious problems. */
+       DEB(DEB_ERRORS, printk(KERN_DEBUG
+                              "%s: transmit timed out, status resetting.\n",
+                              dev->name));
+
+       dev->stats.tx_errors++;
+
+       /* Try to restart the adaptor */
+       if (lp->last_restart == dev->stats.tx_packets) {
+               DEB(DEB_ERRORS, printk(KERN_DEBUG "Resetting board.\n"));
+               /* Shutdown and restart */
+               i596_reset (dev, lp);
+       } else {
+               /* Issue a channel attention signal */
+               DEB(DEB_ERRORS, printk(KERN_DEBUG "Kicking board.\n"));
+               lp->dma->scb.command = SWAP16(CUC_START | RX_START);
+               DMA_WBACK_INV(dev, &(lp->dma->scb), sizeof(struct i596_scb));
+               ca (dev);
+               lp->last_restart = dev->stats.tx_packets;
+       }
+
+       dev->trans_start = jiffies; /* prevent tx timeout */
+       netif_wake_queue (dev);
+}
+
+
+static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct i596_private *lp = netdev_priv(dev);
+       struct tx_cmd *tx_cmd;
+       struct i596_tbd *tbd;
+       short length = skb->len;
+
+       DEB(DEB_STARTTX, printk(KERN_DEBUG
+                               "%s: i596_start_xmit(%x,%p) called\n",
+                               dev->name, skb->len, skb->data));
+
+       if (length < ETH_ZLEN) {
+               if (skb_padto(skb, ETH_ZLEN))
+                       return NETDEV_TX_OK;
+               length = ETH_ZLEN;
+       }
+
+       netif_stop_queue(dev);
+
+       tx_cmd = lp->dma->tx_cmds + lp->next_tx_cmd;
+       tbd = lp->dma->tbds + lp->next_tx_cmd;
+
+       if (tx_cmd->cmd.command) {
+               DEB(DEB_ERRORS, printk(KERN_DEBUG
+                                      "%s: xmit ring full, dropping packet.\n",
+                                      dev->name));
+               dev->stats.tx_dropped++;
+
+               dev_kfree_skb(skb);
+       } else {
+               if (++lp->next_tx_cmd == TX_RING_SIZE)
+                       lp->next_tx_cmd = 0;
+               tx_cmd->tbd = SWAP32(virt_to_dma(lp, tbd));
+               tbd->next = I596_NULL;
+
+               tx_cmd->cmd.command = SWAP16(CMD_FLEX | CmdTx);
+               tx_cmd->skb = skb;
+
+               tx_cmd->pad = 0;
+               tx_cmd->size = 0;
+               tbd->pad = 0;
+               tbd->size = SWAP16(EOF | length);
+
+               tx_cmd->dma_addr = dma_map_single(dev->dev.parent, skb->data,
+                                                 skb->len, DMA_TO_DEVICE);
+               tbd->data = SWAP32(tx_cmd->dma_addr);
+
+               DEB(DEB_TXADDR, print_eth(skb->data, "tx-queued"));
+               DMA_WBACK_INV(dev, tx_cmd, sizeof(struct tx_cmd));
+               DMA_WBACK_INV(dev, tbd, sizeof(struct i596_tbd));
+               i596_add_cmd(dev, &tx_cmd->cmd);
+
+               dev->stats.tx_packets++;
+               dev->stats.tx_bytes += length;
+       }
+
+       netif_start_queue(dev);
+
+       return NETDEV_TX_OK;
+}
+
+static void print_eth(unsigned char *add, char *str)
+{
+       printk(KERN_DEBUG "i596 0x%p, %pM --> %pM %02X%02X, %s\n",
+              add, add + 6, add, add[12], add[13], str);
+}
+static const struct net_device_ops i596_netdev_ops = {
+       .ndo_open               = i596_open,
+       .ndo_stop               = i596_close,
+       .ndo_start_xmit         = i596_start_xmit,
+       .ndo_set_multicast_list = set_multicast_list,
+       .ndo_tx_timeout         = i596_tx_timeout,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_validate_addr      = eth_validate_addr,
+       .ndo_set_mac_address    = eth_mac_addr,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_poll_controller    = i596_poll_controller,
+#endif
+};
+
+static int __devinit i82596_probe(struct net_device *dev)
+{
+       int i;
+       struct i596_private *lp = netdev_priv(dev);
+       struct i596_dma *dma;
+
+       /* This lot is ensure things have been cache line aligned. */
+       BUILD_BUG_ON(sizeof(struct i596_rfd) != 32);
+       BUILD_BUG_ON(sizeof(struct i596_rbd) &  31);
+       BUILD_BUG_ON(sizeof(struct tx_cmd)   &  31);
+       BUILD_BUG_ON(sizeof(struct i596_tbd) != 32);
+#ifndef __LP64__
+       BUILD_BUG_ON(sizeof(struct i596_dma) > 4096);
+#endif
+
+       if (!dev->base_addr || !dev->irq)
+               return -ENODEV;
+
+       dma = (struct i596_dma *) DMA_ALLOC(dev->dev.parent,
+               sizeof(struct i596_dma), &lp->dma_addr, GFP_KERNEL);
+       if (!dma) {
+               printk(KERN_ERR "%s: Couldn't get shared memory\n", __FILE__);
+               return -ENOMEM;
+       }
+
+       dev->netdev_ops = &i596_netdev_ops;
+       dev->watchdog_timeo = TX_TIMEOUT;
+
+       memset(dma, 0, sizeof(struct i596_dma));
+       lp->dma = dma;
+
+       dma->scb.command = 0;
+       dma->scb.cmd = I596_NULL;
+       dma->scb.rfd = I596_NULL;
+       spin_lock_init(&lp->lock);
+
+       DMA_WBACK_INV(dev, dma, sizeof(struct i596_dma));
+
+       i = register_netdev(dev);
+       if (i) {
+               DMA_FREE(dev->dev.parent, sizeof(struct i596_dma),
+                                   (void *)dma, lp->dma_addr);
+               return i;
+       }
+
+       DEB(DEB_PROBE, printk(KERN_INFO "%s: 82596 at %#3lx, %pM IRQ %d.\n",
+                             dev->name, dev->base_addr, dev->dev_addr,
+                             dev->irq));
+       DEB(DEB_INIT, printk(KERN_INFO
+                            "%s: dma at 0x%p (%d bytes), lp->scb at 0x%p\n",
+                            dev->name, dma, (int)sizeof(struct i596_dma),
+                            &dma->scb));
+
+       return 0;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void i596_poll_controller(struct net_device *dev)
+{
+       disable_irq(dev->irq);
+       i596_interrupt(dev->irq, dev);
+       enable_irq(dev->irq);
+}
+#endif
+
+static irqreturn_t i596_interrupt(int irq, void *dev_id)
+{
+       struct net_device *dev = dev_id;
+       struct i596_private *lp;
+       struct i596_dma *dma;
+       unsigned short status, ack_cmd = 0;
+
+       lp = netdev_priv(dev);
+       dma = lp->dma;
+
+       spin_lock (&lp->lock);
+
+       wait_cmd(dev, dma, 100, "i596 interrupt, timeout");
+       status = SWAP16(dma->scb.status);
+
+       DEB(DEB_INTS, printk(KERN_DEBUG
+                            "%s: i596 interrupt, IRQ %d, status %4.4x.\n",
+                       dev->name, dev->irq, status));
+
+       ack_cmd = status & 0xf000;
+
+       if (!ack_cmd) {
+               DEB(DEB_ERRORS, printk(KERN_DEBUG
+                                      "%s: interrupt with no events\n",
+                                      dev->name));
+               spin_unlock (&lp->lock);
+               return IRQ_NONE;
+       }
+
+       if ((status & 0x8000) || (status & 0x2000)) {
+               struct i596_cmd *ptr;
+
+               if ((status & 0x8000))
+                       DEB(DEB_INTS,
+                           printk(KERN_DEBUG
+                                  "%s: i596 interrupt completed command.\n",
+                                  dev->name));
+               if ((status & 0x2000))
+                       DEB(DEB_INTS,
+                           printk(KERN_DEBUG
+                                  "%s: i596 interrupt command unit inactive %x.\n",
+                                  dev->name, status & 0x0700));
+
+               while (lp->cmd_head != NULL) {
+                       DMA_INV(dev, lp->cmd_head, sizeof(struct i596_cmd));
+                       if (!(lp->cmd_head->status & SWAP16(STAT_C)))
+                               break;
+
+                       ptr = lp->cmd_head;
+
+                       DEB(DEB_STATUS,
+                           printk(KERN_DEBUG
+                                  "cmd_head->status = %04x, ->command = %04x\n",
+                                  SWAP16(lp->cmd_head->status),
+                                  SWAP16(lp->cmd_head->command)));
+                       lp->cmd_head = ptr->v_next;
+                       lp->cmd_backlog--;
+
+                       switch (SWAP16(ptr->command) & 0x7) {
+                       case CmdTx:
+                           {
+                               struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr;
+                               struct sk_buff *skb = tx_cmd->skb;
+
+                               if (ptr->status & SWAP16(STAT_OK)) {
+                                       DEB(DEB_TXADDR,
+                                           print_eth(skb->data, "tx-done"));
+                               } else {
+                                       dev->stats.tx_errors++;
+                                       if (ptr->status & SWAP16(0x0020))
+                                               dev->stats.collisions++;
+                                       if (!(ptr->status & SWAP16(0x0040)))
+                                               dev->stats.tx_heartbeat_errors++;
+                                       if (ptr->status & SWAP16(0x0400))
+                                               dev->stats.tx_carrier_errors++;
+                                       if (ptr->status & SWAP16(0x0800))
+                                               dev->stats.collisions++;
+                                       if (ptr->status & SWAP16(0x1000))
+                                               dev->stats.tx_aborted_errors++;
+                               }
+                               dma_unmap_single(dev->dev.parent,
+                                                tx_cmd->dma_addr,
+                                                skb->len, DMA_TO_DEVICE);
+                               dev_kfree_skb_irq(skb);
+
+                               tx_cmd->cmd.command = 0; /* Mark free */
+                               break;
+                           }
+                       case CmdTDR:
+                           {
+                               unsigned short status = SWAP16(((struct tdr_cmd *)ptr)->status);
+
+                               if (status & 0x8000) {
+                                       DEB(DEB_ANY,
+                                           printk(KERN_DEBUG "%s: link ok.\n",
+                                                  dev->name));
+                               } else {
+                                       if (status & 0x4000)
+                                               printk(KERN_ERR
+                                                      "%s: Transceiver problem.\n",
+                                                      dev->name);
+                                       if (status & 0x2000)
+                                               printk(KERN_ERR
+                                                      "%s: Termination problem.\n",
+                                                      dev->name);
+                                       if (status & 0x1000)
+                                               printk(KERN_ERR
+                                                      "%s: Short circuit.\n",
+                                                      dev->name);
+
+                                       DEB(DEB_TDR,
+                                           printk(KERN_DEBUG "%s: Time %d.\n",
+                                                  dev->name, status & 0x07ff));
+                               }
+                               break;
+                           }
+                       case CmdConfigure:
+                               /*
+                                * Zap command so set_multicast_list() know
+                                * it is free
+                                */
+                               ptr->command = 0;
+                               break;
+                       }
+                       ptr->v_next = NULL;
+                       ptr->b_next = I596_NULL;
+                       DMA_WBACK(dev, ptr, sizeof(struct i596_cmd));
+                       lp->last_cmd = jiffies;
+               }
+
+               /* This mess is arranging that only the last of any outstanding
+                * commands has the interrupt bit set.  Should probably really
+                * only add to the cmd queue when the CU is stopped.
+                */
+               ptr = lp->cmd_head;
+               while ((ptr != NULL) && (ptr != lp->cmd_tail)) {
+                       struct i596_cmd *prev = ptr;
+
+                       ptr->command &= SWAP16(0x1fff);
+                       ptr = ptr->v_next;
+                       DMA_WBACK_INV(dev, prev, sizeof(struct i596_cmd));
+               }
+
+               if (lp->cmd_head != NULL)
+                       ack_cmd |= CUC_START;
+               dma->scb.cmd = SWAP32(virt_to_dma(lp, &lp->cmd_head->status));
+               DMA_WBACK_INV(dev, &dma->scb, sizeof(struct i596_scb));
+       }
+       if ((status & 0x1000) || (status & 0x4000)) {
+               if ((status & 0x4000))
+                       DEB(DEB_INTS,
+                           printk(KERN_DEBUG
+                                  "%s: i596 interrupt received a frame.\n",
+                                  dev->name));
+               i596_rx(dev);
+               /* Only RX_START if stopped - RGH 07-07-96 */
+               if (status & 0x1000) {
+                       if (netif_running(dev)) {
+                               DEB(DEB_ERRORS,
+                                   printk(KERN_DEBUG
+                                          "%s: i596 interrupt receive unit inactive, status 0x%x\n",
+                                          dev->name, status));
+                               ack_cmd |= RX_START;
+                               dev->stats.rx_errors++;
+                               dev->stats.rx_fifo_errors++;
+                               rebuild_rx_bufs(dev);
+                       }
+               }
+       }
+       wait_cmd(dev, dma, 100, "i596 interrupt, timeout");
+       dma->scb.command = SWAP16(ack_cmd);
+       DMA_WBACK(dev, &dma->scb, sizeof(struct i596_scb));
+
+       /* DANGER: I suspect that some kind of interrupt
+        acknowledgement aside from acking the 82596 might be needed
+        here...  but it's running acceptably without */
+
+       ca(dev);
+
+       wait_cmd(dev, dma, 100, "i596 interrupt, exit timeout");
+       DEB(DEB_INTS, printk(KERN_DEBUG "%s: exiting interrupt.\n", dev->name));
+
+       spin_unlock (&lp->lock);
+       return IRQ_HANDLED;
+}
+
+static int i596_close(struct net_device *dev)
+{
+       struct i596_private *lp = netdev_priv(dev);
+       unsigned long flags;
+
+       netif_stop_queue(dev);
+
+       DEB(DEB_INIT,
+           printk(KERN_DEBUG
+                  "%s: Shutting down ethercard, status was %4.4x.\n",
+                  dev->name, SWAP16(lp->dma->scb.status)));
+
+       spin_lock_irqsave(&lp->lock, flags);
+
+       wait_cmd(dev, lp->dma, 100, "close1 timed out");
+       lp->dma->scb.command = SWAP16(CUC_ABORT | RX_ABORT);
+       DMA_WBACK(dev, &lp->dma->scb, sizeof(struct i596_scb));
+
+       ca(dev);
+
+       wait_cmd(dev, lp->dma, 100, "close2 timed out");
+       spin_unlock_irqrestore(&lp->lock, flags);
+       DEB(DEB_STRUCT, i596_display_data(dev));
+       i596_cleanup_cmd(dev, lp);
+
+       free_irq(dev->irq, dev);
+       remove_rx_bufs(dev);
+
+       return 0;
+}
+
+/*
+ *    Set or clear the multicast filter for this adaptor.
+ */
+
+static void set_multicast_list(struct net_device *dev)
+{
+       struct i596_private *lp = netdev_priv(dev);
+       struct i596_dma *dma = lp->dma;
+       int config = 0, cnt;
+
+       DEB(DEB_MULTI,
+           printk(KERN_DEBUG
+                  "%s: set multicast list, %d entries, promisc %s, allmulti %s\n",
+                  dev->name, netdev_mc_count(dev),
+                  dev->flags & IFF_PROMISC ? "ON" : "OFF",
+                  dev->flags & IFF_ALLMULTI ? "ON" : "OFF"));
+
+       if ((dev->flags & IFF_PROMISC) &&
+           !(dma->cf_cmd.i596_config[8] & 0x01)) {
+               dma->cf_cmd.i596_config[8] |= 0x01;
+               config = 1;
+       }
+       if (!(dev->flags & IFF_PROMISC) &&
+           (dma->cf_cmd.i596_config[8] & 0x01)) {
+               dma->cf_cmd.i596_config[8] &= ~0x01;
+               config = 1;
+       }
+       if ((dev->flags & IFF_ALLMULTI) &&
+           (dma->cf_cmd.i596_config[11] & 0x20)) {
+               dma->cf_cmd.i596_config[11] &= ~0x20;
+               config = 1;
+       }
+       if (!(dev->flags & IFF_ALLMULTI) &&
+           !(dma->cf_cmd.i596_config[11] & 0x20)) {
+               dma->cf_cmd.i596_config[11] |= 0x20;
+               config = 1;
+       }
+       if (config) {
+               if (dma->cf_cmd.cmd.command)
+                       printk(KERN_INFO
+                              "%s: config change request already queued\n",
+                              dev->name);
+               else {
+                       dma->cf_cmd.cmd.command = SWAP16(CmdConfigure);
+                       DMA_WBACK_INV(dev, &dma->cf_cmd, sizeof(struct cf_cmd));
+                       i596_add_cmd(dev, &dma->cf_cmd.cmd);
+               }
+       }
+
+       cnt = netdev_mc_count(dev);
+       if (cnt > MAX_MC_CNT) {
+               cnt = MAX_MC_CNT;
+               printk(KERN_NOTICE "%s: Only %d multicast addresses supported",
+                       dev->name, cnt);
+       }
+
+       if (!netdev_mc_empty(dev)) {
+               struct netdev_hw_addr *ha;
+               unsigned char *cp;
+               struct mc_cmd *cmd;
+
+               cmd = &dma->mc_cmd;
+               cmd->cmd.command = SWAP16(CmdMulticastList);
+               cmd->mc_cnt = SWAP16(netdev_mc_count(dev) * 6);
+               cp = cmd->mc_addrs;
+               netdev_for_each_mc_addr(ha, dev) {
+                       if (!cnt--)
+                               break;
+                       memcpy(cp, ha->addr, 6);
+                       if (i596_debug > 1)
+                               DEB(DEB_MULTI,
+                                   printk(KERN_DEBUG
+                                          "%s: Adding address %pM\n",
+                                          dev->name, cp));
+                       cp += 6;
+               }
+               DMA_WBACK_INV(dev, &dma->mc_cmd, sizeof(struct mc_cmd));
+               i596_add_cmd(dev, &cmd->cmd);
+       }
+}
diff --git a/drivers/net/ethernet/i825xx/lp486e.c b/drivers/net/ethernet/i825xx/lp486e.c
new file mode 100644 (file)
index 0000000..385a953
--- /dev/null
@@ -0,0 +1,1339 @@
+/* Intel Professional Workstation/panther ethernet driver */
+/* lp486e.c: A panther 82596 ethernet driver for linux. */
+/*
+    History and copyrights:
+
+    Driver skeleton
+        Written 1993 by Donald Becker.
+        Copyright 1993 United States Government as represented by the Director,
+        National Security Agency.  This software may only be used and
+       distributed according to the terms of the GNU General Public License
+       as modified by SRC, incorporated herein by reference.
+
+        The author may be reached as becker@scyld.com, or C/O
+       Scyld Computing Corporation
+       410 Severn Ave., Suite 210
+       Annapolis MD 21403
+
+    Apricot
+        Written 1994 by Mark Evans.
+        This driver is for the Apricot 82596 bus-master interface
+
+        Modularised 12/94 Mark Evans
+
+    Professional Workstation
+       Derived from apricot.c by Ard van Breemen
+       <ard@murphy.nl>|<ard@cstmel.hobby.nl>|<ard@cstmel.nl.eu.org>
+
+       Credits:
+       Thanks to Murphy Software BV for letting me write this in their time.
+       Well, actually, I get paid doing this...
+       (Also: see http://www.murphy.nl for murphy, and my homepage ~ard for
+       more information on the Professional Workstation)
+
+    Present version
+       aeb@cwi.nl
+*/
+/*
+    There are currently two motherboards that I know of in the
+    professional workstation. The only one that I know is the
+    intel panther motherboard. -- ard
+*/
+/*
+The pws is equipped with an intel 82596. This is a very intelligent controller
+which runs its own micro-code. Communication with the hostprocessor is done
+through linked lists of commands and buffers in the hostprocessors memory.
+A complete description of the 82596 is available from intel. Search for
+a file called "29021806.pdf". It is a complete description of the chip itself.
+To use it for the pws some additions are needed regarding generation of
+the PORT and CA signal, and the interrupt glue needed for a pc.
+I/O map:
+PORT  SIZE ACTION MEANING
+0xCB0    2 WRITE  Lower 16 bits for PORT command
+0xCB2    2 WRITE  Upper 16 bits for PORT command, and issue of PORT command
+0xCB4    1 WRITE  Generation of CA signal
+0xCB8    1 WRITE  Clear interrupt glue
+All other communication is through memory!
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/bitops.h>
+
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#define DRV_NAME "lp486e"
+
+/* debug print flags */
+#define LOG_SRCDST    0x80000000
+#define LOG_STATINT   0x40000000
+#define LOG_STARTINT  0x20000000
+
+#define i596_debug debug
+
+static int i596_debug = 0;
+
+static const char * const medianame[] = {
+       "10baseT", "AUI",
+       "10baseT-FD", "AUI-FD",
+};
+
+#define LP486E_TOTAL_SIZE 16
+
+#define I596_NULL (0xffffffff)
+
+#define CMD_EOL                0x8000  /* The last command of the list, stop. */
+#define CMD_SUSP       0x4000  /* Suspend after doing cmd. */
+#define CMD_INTR       0x2000  /* Interrupt after doing cmd. */
+
+#define CMD_FLEX       0x0008  /* Enable flexible memory model */
+
+enum commands {
+       CmdNOP = 0,
+       CmdIASetup = 1,
+       CmdConfigure = 2,
+       CmdMulticastList = 3,
+       CmdTx = 4,
+       CmdTDR = 5,
+       CmdDump = 6,
+       CmdDiagnose = 7
+};
+
+#if 0
+static const char *CUcmdnames[8] = { "NOP", "IASetup", "Configure", "MulticastList",
+                                    "Tx", "TDR", "Dump", "Diagnose" };
+#endif
+
+/* Status word bits */
+#define        STAT_CX         0x8000  /* The CU finished executing a command
+                                  with the Interrupt bit set */
+#define        STAT_FR         0x4000  /* The RU finished receiving a frame */
+#define        STAT_CNA        0x2000  /* The CU left the active state */
+#define        STAT_RNR        0x1000  /* The RU left the active state */
+#define STAT_ACK       (STAT_CX | STAT_FR | STAT_CNA | STAT_RNR)
+#define        STAT_CUS        0x0700  /* Status of CU: 0: idle, 1: suspended,
+                                  2: active, 3-7: unused */
+#define STAT_RUS       0x00f0  /* Status of RU: 0: idle, 1: suspended,
+                                  2: no resources, 4: ready,
+                                  10: no resources due to no more RBDs,
+                                  12: no more RBDs, other: unused */
+#define        STAT_T          0x0008  /* Bus throttle timers loaded */
+#define        STAT_ZERO       0x0807  /* Always zero */
+
+#if 0
+static char *CUstates[8] = {
+       "idle", "suspended", "active", 0, 0, 0, 0, 0
+};
+static char *RUstates[16] = {
+       "idle", "suspended", "no resources", 0, "ready", 0, 0, 0,
+       0, 0, "no RBDs", 0, "out of RBDs", 0, 0, 0
+};
+
+static void
+i596_out_status(int status) {
+       int bad = 0;
+       char *s;
+
+       printk("status %4.4x:", status);
+       if (status == 0xffff)
+               printk(" strange..\n");
+       else {
+               if (status & STAT_CX)
+                       printk("  CU done");
+               if (status & STAT_CNA)
+                       printk("  CU stopped");
+               if (status & STAT_FR)
+                       printk("  got a frame");
+               if (status & STAT_RNR)
+                       printk("  RU stopped");
+               if (status & STAT_T)
+                       printk("  throttled");
+               if (status & STAT_ZERO)
+                       bad = 1;
+               s = CUstates[(status & STAT_CUS) >> 8];
+               if (!s)
+                       bad = 1;
+               else
+                       printk("  CU(%s)", s);
+               s = RUstates[(status & STAT_RUS) >> 4];
+               if (!s)
+                       bad = 1;
+               else
+                       printk("  RU(%s)", s);
+               if (bad)
+                       printk("  bad status");
+               printk("\n");
+       }
+}
+#endif
+
+/* Command word bits */
+#define ACK_CX         0x8000
+#define ACK_FR         0x4000
+#define ACK_CNA                0x2000
+#define ACK_RNR                0x1000
+
+#define CUC_START      0x0100
+#define CUC_RESUME     0x0200
+#define CUC_SUSPEND    0x0300
+#define CUC_ABORT      0x0400
+
+#define RX_START       0x0010
+#define RX_RESUME      0x0020
+#define RX_SUSPEND     0x0030
+#define RX_ABORT       0x0040
+
+typedef u32 phys_addr;
+
+static inline phys_addr
+va_to_pa(void *x) {
+       return x ? virt_to_bus(x) : I596_NULL;
+}
+
+static inline void *
+pa_to_va(phys_addr x) {
+       return (x == I596_NULL) ? NULL : bus_to_virt(x);
+}
+
+/* status bits for cmd */
+#define CMD_STAT_C     0x8000  /* CU command complete */
+#define CMD_STAT_B     0x4000  /* CU command in progress */
+#define CMD_STAT_OK    0x2000  /* CU command completed without errors */
+#define CMD_STAT_A     0x1000  /* CU command abnormally terminated */
+
+struct i596_cmd {              /* 8 bytes */
+       unsigned short status;
+       unsigned short command;
+       phys_addr pa_next;      /* va_to_pa(struct i596_cmd *next) */
+};
+
+#define EOF            0x8000
+#define SIZE_MASK      0x3fff
+
+struct i596_tbd {
+       unsigned short size;
+       unsigned short pad;
+       phys_addr pa_next;      /* va_to_pa(struct i596_tbd *next) */
+       phys_addr pa_data;      /* va_to_pa(char *data) */
+       struct sk_buff *skb;
+};
+
+struct tx_cmd {
+       struct i596_cmd cmd;
+       phys_addr pa_tbd;       /* va_to_pa(struct i596_tbd *tbd) */
+       unsigned short size;
+       unsigned short pad;
+};
+
+/* status bits for rfd */
+#define RFD_STAT_C     0x8000  /* Frame reception complete */
+#define RFD_STAT_B     0x4000  /* Frame reception in progress */
+#define RFD_STAT_OK    0x2000  /* Frame received without errors */
+#define RFD_STATUS     0x1fff
+#define RFD_LENGTH_ERR 0x1000
+#define RFD_CRC_ERR    0x0800
+#define RFD_ALIGN_ERR  0x0400
+#define RFD_NOBUFS_ERR 0x0200
+#define RFD_DMA_ERR    0x0100  /* DMA overrun failure to acquire system bus */
+#define RFD_SHORT_FRAME_ERR    0x0080
+#define RFD_NOEOP_ERR  0x0040
+#define RFD_TRUNC_ERR  0x0020
+#define RFD_MULTICAST  0x0002  /* 0: destination had our address
+                                  1: destination was broadcast/multicast */
+#define RFD_COLLISION  0x0001
+
+/* receive frame descriptor */
+struct i596_rfd {
+       unsigned short stat;
+       unsigned short cmd;
+       phys_addr pa_next;      /* va_to_pa(struct i596_rfd *next) */
+       phys_addr pa_rbd;       /* va_to_pa(struct i596_rbd *rbd) */
+       unsigned short count;
+       unsigned short size;
+       char data[1532];
+};
+
+#define RBD_EL         0x8000
+#define RBD_P          0x4000
+#define RBD_SIZEMASK   0x3fff
+#define RBD_EOF                0x8000
+#define RBD_F          0x4000
+
+/* receive buffer descriptor */
+struct i596_rbd {
+       unsigned short size;
+       unsigned short pad;
+       phys_addr pa_next;      /* va_to_pa(struct i596_tbd *next) */
+       phys_addr pa_data;      /* va_to_pa(char *data) */
+       phys_addr pa_prev;      /* va_to_pa(struct i596_tbd *prev) */
+
+       /* Driver private part */
+       struct sk_buff *skb;
+};
+
+#define RX_RING_SIZE 64
+#define RX_SKBSIZE (ETH_FRAME_LEN+10)
+#define RX_RBD_SIZE 32
+
+/* System Control Block - 40 bytes */
+struct i596_scb {
+       u16 status;             /* 0 */
+       u16 command;            /* 2 */
+       phys_addr pa_cmd;       /* 4 - va_to_pa(struct i596_cmd *cmd) */
+       phys_addr pa_rfd;       /* 8 - va_to_pa(struct i596_rfd *rfd) */
+       u32 crc_err;            /* 12 */
+       u32 align_err;          /* 16 */
+       u32 resource_err;       /* 20 */
+       u32 over_err;           /* 24 */
+       u32 rcvdt_err;          /* 28 */
+       u32 short_err;          /* 32 */
+       u16 t_on;               /* 36 */
+       u16 t_off;              /* 38 */
+};
+
+/* Intermediate System Configuration Pointer - 8 bytes */
+struct i596_iscp {
+       u32 busy;               /* 0 */
+       phys_addr pa_scb;       /* 4 - va_to_pa(struct i596_scb *scb) */
+};
+
+/* System Configuration Pointer - 12 bytes */
+struct i596_scp {
+       u32 sysbus;             /* 0 */
+       u32 pad;                /* 4 */
+       phys_addr pa_iscp;      /* 8 - va_to_pa(struct i596_iscp *iscp) */
+};
+
+/* Selftest and dump results - needs 16-byte alignment */
+/*
+ * The size of the dump area is 304 bytes. When the dump is executed
+ * by the Port command an extra word will be appended to the dump area.
+ * The extra word is a copy of the Dump status word (containing the
+ * C, B, OK bits). [I find 0xa006, with a0 for C+OK and 6 for dump]
+ */
+struct i596_dump {
+       u16 dump[153];          /* (304 = 130h) + 2 bytes */
+};
+
+struct i596_private {          /* aligned to a 16-byte boundary */
+       struct i596_scp scp;    /* 0 - needs 16-byte alignment */
+       struct i596_iscp iscp;  /* 12 */
+       struct i596_scb scb;    /* 20 */
+       u32 dummy;              /* 60 */
+       struct i596_dump dump;  /* 64 - needs 16-byte alignment */
+
+       struct i596_cmd set_add;
+       char eth_addr[8];       /* directly follows set_add */
+
+       struct i596_cmd set_conf;
+       char i596_config[16];   /* directly follows set_conf */
+
+       struct i596_cmd tdr;
+       unsigned long tdr_stat; /* directly follows tdr */
+
+       int last_restart;
+       struct i596_rbd *rbd_list;
+       struct i596_rbd *rbd_tail;
+       struct i596_rfd *rx_tail;
+       struct i596_cmd *cmd_tail;
+       struct i596_cmd *cmd_head;
+       int cmd_backlog;
+       unsigned long last_cmd;
+       spinlock_t cmd_lock;
+};
+
+static char init_setup[14] = {
+       0x8E,   /* length 14 bytes, prefetch on */
+       0xC8,   /* default: fifo to 8, monitor off */
+       0x40,   /* default: don't save bad frames (apricot.c had 0x80) */
+       0x2E,   /* (default is 0x26)
+                  No source address insertion, 8 byte preamble */
+       0x00,   /* default priority and backoff */
+       0x60,   /* default interframe spacing */
+       0x00,   /* default slot time LSB */
+       0xf2,   /* default slot time and nr of retries */
+       0x00,   /* default various bits
+                  (0: promiscuous mode, 1: broadcast disable,
+                   2: encoding mode, 3: transmit on no CRS,
+                   4: no CRC insertion, 5: CRC type,
+                   6: bit stuffing, 7: padding) */
+       0x00,   /* default carrier sense and collision detect */
+       0x40,   /* default minimum frame length */
+       0xff,   /* (default is 0xff, and that is what apricot.c has;
+                  elp486.c has 0xfb: Enable crc append in memory.) */
+       0x00,   /* default: not full duplex */
+       0x7f    /* (default is 0x3f) multi IA */
+};
+
+static int i596_open(struct net_device *dev);
+static netdev_tx_t i596_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static irqreturn_t i596_interrupt(int irq, void *dev_id);
+static int i596_close(struct net_device *dev);
+static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd);
+static void print_eth(char *);
+static void set_multicast_list(struct net_device *dev);
+static void i596_tx_timeout(struct net_device *dev);
+
+static int
+i596_timeout(struct net_device *dev, char *msg, int ct) {
+       struct i596_private *lp;
+       int boguscnt = ct;
+
+       lp = netdev_priv(dev);
+       while (lp->scb.command) {
+               if (--boguscnt == 0) {
+                       printk("%s: %s timed out - stat %4.4x, cmd %4.4x\n",
+                              dev->name, msg,
+                              lp->scb.status, lp->scb.command);
+                       return 1;
+               }
+               udelay(5);
+               barrier();
+       }
+       return 0;
+}
+
+static inline int
+init_rx_bufs(struct net_device *dev, int num) {
+       struct i596_private *lp;
+       struct i596_rfd *rfd;
+       int i;
+       // struct i596_rbd *rbd;
+
+       lp = netdev_priv(dev);
+       lp->scb.pa_rfd = I596_NULL;
+
+       for (i = 0; i < num; i++) {
+               rfd = kmalloc(sizeof(struct i596_rfd), GFP_KERNEL);
+               if (rfd == NULL)
+                       break;
+
+               rfd->stat = 0;
+               rfd->pa_rbd = I596_NULL;
+               rfd->count = 0;
+               rfd->size = 1532;
+               if (i == 0) {
+                       rfd->cmd = CMD_EOL;
+                       lp->rx_tail = rfd;
+               } else {
+                       rfd->cmd = 0;
+               }
+               rfd->pa_next = lp->scb.pa_rfd;
+               lp->scb.pa_rfd = va_to_pa(rfd);
+               lp->rx_tail->pa_next = lp->scb.pa_rfd;
+       }
+
+#if 0
+       for (i = 0; i<RX_RBD_SIZE; i++) {
+               rbd = kmalloc(sizeof(struct i596_rbd), GFP_KERNEL);
+               if (rbd) {
+                       rbd->pad = 0;
+                       rbd->count = 0;
+                       rbd->skb = dev_alloc_skb(RX_SKBSIZE);
+                       if (!rbd->skb) {
+                               printk("dev_alloc_skb failed");
+                       }
+                       rbd->next = rfd->rbd;
+                       if (i) {
+                               rfd->rbd->prev = rbd;
+                               rbd->size = RX_SKBSIZE;
+                       } else {
+                               rbd->size = (RX_SKBSIZE | RBD_EL);
+                               lp->rbd_tail = rbd;
+                       }
+
+                       rfd->rbd = rbd;
+               } else {
+                       printk("Could not kmalloc rbd\n");
+               }
+       }
+       lp->rbd_tail->next = rfd->rbd;
+#endif
+       return i;
+}
+
+static inline void
+remove_rx_bufs(struct net_device *dev) {
+       struct i596_private *lp;
+       struct i596_rfd *rfd;
+
+       lp = netdev_priv(dev);
+       lp->rx_tail->pa_next = I596_NULL;
+
+       do {
+               rfd = pa_to_va(lp->scb.pa_rfd);
+               lp->scb.pa_rfd = rfd->pa_next;
+               kfree(rfd);
+       } while (rfd != lp->rx_tail);
+
+       lp->rx_tail = NULL;
+
+#if 0
+       for (lp->rbd_list) {
+       }
+#endif
+}
+
+#define PORT_RESET              0x00    /* reset 82596 */
+#define PORT_SELFTEST           0x01    /* selftest */
+#define PORT_ALTSCP             0x02    /* alternate SCB address */
+#define PORT_DUMP               0x03    /* dump */
+
+#define IOADDR 0xcb0           /* real constant */
+#define IRQ    10              /* default IRQ - can be changed by ECU */
+
+/* The 82596 requires two 16-bit write cycles for a port command */
+static inline void
+PORT(phys_addr a, unsigned int cmd) {
+       if (a & 0xf)
+               printk("lp486e.c: PORT: address not aligned\n");
+       outw(((a & 0xffff) | cmd), IOADDR);
+       outw(((a>>16) & 0xffff), IOADDR+2);
+}
+
+static inline void
+CA(void) {
+       outb(0, IOADDR+4);
+       udelay(8);
+}
+
+static inline void
+CLEAR_INT(void) {
+       outb(0, IOADDR+8);
+}
+
+#if 0
+/* selftest or dump */
+static void
+i596_port_do(struct net_device *dev, int portcmd, char *cmdname) {
+       struct i596_private *lp = netdev_priv(dev);
+       u16 *outp;
+       int i, m;
+
+       memset((void *)&(lp->dump), 0, sizeof(struct i596_dump));
+       outp = &(lp->dump.dump[0]);
+
+       PORT(va_to_pa(outp), portcmd);
+       mdelay(30);             /* random, unmotivated */
+
+       printk("lp486e i82596 %s result:\n", cmdname);
+       for (m = ARRAY_SIZE(lp->dump.dump); m && lp->dump.dump[m-1] == 0; m--)
+               ;
+       for (i = 0; i < m; i++) {
+               printk(" %04x", lp->dump.dump[i]);
+               if (i%8 == 7)
+                       printk("\n");
+       }
+       printk("\n");
+}
+#endif
+
+static int
+i596_scp_setup(struct net_device *dev) {
+       struct i596_private *lp = netdev_priv(dev);
+       int boguscnt;
+
+       /* Setup SCP, ISCP, SCB */
+       /*
+        * sysbus bits:
+        *  only a single byte is significant - here 0x44
+        *  0x80: big endian mode (details depend on stepping)
+        *  0x40: 1
+        *  0x20: interrupt pin is active low
+        *  0x10: lock function disabled
+        *  0x08: external triggering of bus throttle timers
+        *  0x06: 00: 82586 compat mode, 01: segmented mode, 10: linear mode
+        *  0x01: unused
+        */
+       lp->scp.sysbus = 0x00440000;            /* linear mode */
+       lp->scp.pad = 0;                        /* must be zero */
+       lp->scp.pa_iscp = va_to_pa(&(lp->iscp));
+
+       /*
+        * The CPU sets the ISCP to 1 before it gives the first CA()
+        */
+       lp->iscp.busy = 0x0001;
+       lp->iscp.pa_scb = va_to_pa(&(lp->scb));
+
+       lp->scb.command = 0;
+       lp->scb.status = 0;
+       lp->scb.pa_cmd = I596_NULL;
+       /* lp->scb.pa_rfd has been initialised already */
+
+       lp->last_cmd = jiffies;
+       lp->cmd_backlog = 0;
+       lp->cmd_head = NULL;
+
+       /*
+        * Reset the 82596.
+        * We need to wait 10 systemclock cycles, and
+        * 5 serial clock cycles.
+        */
+       PORT(0, PORT_RESET);    /* address part ignored */
+       udelay(100);
+
+       /*
+        * Before the CA signal is asserted, the default SCP address
+        * (0x00fffff4) can be changed to a 16-byte aligned value
+        */
+       PORT(va_to_pa(&lp->scp), PORT_ALTSCP);  /* change the scp address */
+
+       /*
+        * The initialization procedure begins when a
+        * Channel Attention signal is asserted after a reset.
+        */
+
+       CA();
+
+       /*
+        * The ISCP busy is cleared by the 82596 after the SCB address is read.
+        */
+       boguscnt = 100;
+       while (lp->iscp.busy) {
+               if (--boguscnt == 0) {
+                       /* No i82596 present? */
+                       printk("%s: i82596 initialization timed out\n",
+                              dev->name);
+                       return 1;
+               }
+               udelay(5);
+               barrier();
+       }
+       /* I find here boguscnt==100, so no delay was required. */
+
+       return 0;
+}
+
+static int
+init_i596(struct net_device *dev) {
+       struct i596_private *lp;
+
+       if (i596_scp_setup(dev))
+               return 1;
+
+       lp = netdev_priv(dev);
+       lp->scb.command = 0;
+
+       memcpy ((void *)lp->i596_config, init_setup, 14);
+       lp->set_conf.command = CmdConfigure;
+       i596_add_cmd(dev, (void *)&lp->set_conf);
+
+       memcpy ((void *)lp->eth_addr, dev->dev_addr, 6);
+       lp->set_add.command = CmdIASetup;
+       i596_add_cmd(dev, (struct i596_cmd *)&lp->set_add);
+
+       lp->tdr.command = CmdTDR;
+       i596_add_cmd(dev, (struct i596_cmd *)&lp->tdr);
+
+       if (lp->scb.command && i596_timeout(dev, "i82596 init", 200))
+               return 1;
+
+       lp->scb.command = RX_START;
+       CA();
+
+       barrier();
+
+       if (lp->scb.command && i596_timeout(dev, "Receive Unit start", 100))
+               return 1;
+
+       return 0;
+}
+
+/* Receive a single frame */
+static inline int
+i596_rx_one(struct net_device *dev, struct i596_private *lp,
+           struct i596_rfd *rfd, int *frames) {
+
+       if (rfd->stat & RFD_STAT_OK) {
+               /* a good frame */
+               int pkt_len = (rfd->count & 0x3fff);
+               struct sk_buff *skb = dev_alloc_skb(pkt_len);
+
+               (*frames)++;
+
+               if (rfd->cmd & CMD_EOL)
+                       printk("Received on EOL\n");
+
+               if (skb == NULL) {
+                       printk ("%s: i596_rx Memory squeeze, "
+                               "dropping packet.\n", dev->name);
+                       dev->stats.rx_dropped++;
+                       return 1;
+               }
+
+               memcpy(skb_put(skb,pkt_len), rfd->data, pkt_len);
+
+               skb->protocol = eth_type_trans(skb,dev);
+               netif_rx(skb);
+               dev->stats.rx_packets++;
+       } else {
+#if 0
+               printk("Frame reception error status %04x\n",
+                      rfd->stat);
+#endif
+               dev->stats.rx_errors++;
+               if (rfd->stat & RFD_COLLISION)
+                       dev->stats.collisions++;
+               if (rfd->stat & RFD_SHORT_FRAME_ERR)
+                       dev->stats.rx_length_errors++;
+               if (rfd->stat & RFD_DMA_ERR)
+                       dev->stats.rx_over_errors++;
+               if (rfd->stat & RFD_NOBUFS_ERR)
+                       dev->stats.rx_fifo_errors++;
+               if (rfd->stat & RFD_ALIGN_ERR)
+                       dev->stats.rx_frame_errors++;
+               if (rfd->stat & RFD_CRC_ERR)
+                       dev->stats.rx_crc_errors++;
+               if (rfd->stat & RFD_LENGTH_ERR)
+                       dev->stats.rx_length_errors++;
+       }
+       rfd->stat = rfd->count = 0;
+       return 0;
+}
+
+static int
+i596_rx(struct net_device *dev) {
+       struct i596_private *lp = netdev_priv(dev);
+       struct i596_rfd *rfd;
+       int frames = 0;
+
+       while (1) {
+               rfd = pa_to_va(lp->scb.pa_rfd);
+               if (!rfd) {
+                       printk(KERN_ERR "i596_rx: NULL rfd?\n");
+                       return 0;
+               }
+#if 1
+               if (rfd->stat && !(rfd->stat & (RFD_STAT_C | RFD_STAT_B)))
+                       printk("SF:%p-%04x\n", rfd, rfd->stat);
+#endif
+               if (!(rfd->stat & RFD_STAT_C))
+                       break;          /* next one not ready */
+               if (i596_rx_one(dev, lp, rfd, &frames))
+                       break;          /* out of memory */
+               rfd->cmd = CMD_EOL;
+               lp->rx_tail->cmd = 0;
+               lp->rx_tail = rfd;
+               lp->scb.pa_rfd = rfd->pa_next;
+               barrier();
+       }
+
+       return frames;
+}
+
+static void
+i596_cleanup_cmd(struct net_device *dev) {
+       struct i596_private *lp;
+       struct i596_cmd *cmd;
+
+       lp = netdev_priv(dev);
+       while (lp->cmd_head) {
+               cmd = (struct i596_cmd *)lp->cmd_head;
+
+               lp->cmd_head = pa_to_va(lp->cmd_head->pa_next);
+               lp->cmd_backlog--;
+
+               switch ((cmd->command) & 0x7) {
+                       case CmdTx: {
+                               struct tx_cmd *tx_cmd = (struct tx_cmd *) cmd;
+                               struct i596_tbd * tx_cmd_tbd;
+                               tx_cmd_tbd = pa_to_va(tx_cmd->pa_tbd);
+
+                               dev_kfree_skb_any(tx_cmd_tbd->skb);
+
+                               dev->stats.tx_errors++;
+                               dev->stats.tx_aborted_errors++;
+
+                               cmd->pa_next = I596_NULL;
+                               kfree((unsigned char *)tx_cmd);
+                               netif_wake_queue(dev);
+                               break;
+                       }
+                       case CmdMulticastList: {
+                               // unsigned short count = *((unsigned short *) (ptr + 1));
+
+                               cmd->pa_next = I596_NULL;
+                               kfree((unsigned char *)cmd);
+                               break;
+                       }
+                       default: {
+                               cmd->pa_next = I596_NULL;
+                               break;
+                       }
+               }
+               barrier();
+       }
+
+       if (lp->scb.command && i596_timeout(dev, "i596_cleanup_cmd", 100))
+               ;
+
+       lp->scb.pa_cmd = va_to_pa(lp->cmd_head);
+}
+
+static void i596_reset(struct net_device *dev, struct i596_private *lp, int ioaddr) {
+
+       if (lp->scb.command && i596_timeout(dev, "i596_reset", 100))
+               ;
+
+       netif_stop_queue(dev);
+
+       lp->scb.command = CUC_ABORT | RX_ABORT;
+       CA();
+       barrier();
+
+       /* wait for shutdown */
+       if (lp->scb.command && i596_timeout(dev, "i596_reset(2)", 400))
+               ;
+
+       i596_cleanup_cmd(dev);
+       i596_rx(dev);
+
+       netif_start_queue(dev);
+       /*dev_kfree_skb(skb, FREE_WRITE);*/
+       init_i596(dev);
+}
+
+static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd) {
+       struct i596_private *lp = netdev_priv(dev);
+       int ioaddr = dev->base_addr;
+       unsigned long flags;
+
+       cmd->status = 0;
+       cmd->command |= (CMD_EOL | CMD_INTR);
+       cmd->pa_next = I596_NULL;
+
+       spin_lock_irqsave(&lp->cmd_lock, flags);
+
+       if (lp->cmd_head) {
+               lp->cmd_tail->pa_next = va_to_pa(cmd);
+       } else {
+               lp->cmd_head = cmd;
+               if (lp->scb.command && i596_timeout(dev, "i596_add_cmd", 100))
+                       ;
+               lp->scb.pa_cmd = va_to_pa(cmd);
+               lp->scb.command = CUC_START;
+               CA();
+       }
+       lp->cmd_tail = cmd;
+       lp->cmd_backlog++;
+
+       lp->cmd_head = pa_to_va(lp->scb.pa_cmd);
+       spin_unlock_irqrestore(&lp->cmd_lock, flags);
+
+       if (lp->cmd_backlog > 16) {
+               int tickssofar = jiffies - lp->last_cmd;
+               if (tickssofar < HZ/4)
+                       return;
+
+               printk(KERN_WARNING "%s: command unit timed out, status resetting.\n", dev->name);
+               i596_reset(dev, lp, ioaddr);
+       }
+}
+
+static int i596_open(struct net_device *dev)
+{
+       int i;
+
+       i = request_irq(dev->irq, i596_interrupt, IRQF_SHARED, dev->name, dev);
+       if (i) {
+               printk(KERN_ERR "%s: IRQ %d not free\n", dev->name, dev->irq);
+               return i;
+       }
+
+       if ((i = init_rx_bufs(dev, RX_RING_SIZE)) < RX_RING_SIZE)
+               printk(KERN_ERR "%s: only able to allocate %d receive buffers\n", dev->name, i);
+
+       if (i < 4) {
+               free_irq(dev->irq, dev);
+               return -EAGAIN;
+       }
+       netif_start_queue(dev);
+       init_i596(dev);
+       return 0;                       /* Always succeed */
+}
+
+static netdev_tx_t i596_start_xmit (struct sk_buff *skb, struct net_device *dev) {
+       struct tx_cmd *tx_cmd;
+       short length;
+
+       length = skb->len;
+
+       if (length < ETH_ZLEN) {
+               if (skb_padto(skb, ETH_ZLEN))
+                       return NETDEV_TX_OK;
+               length = ETH_ZLEN;
+       }
+
+       tx_cmd = kmalloc((sizeof (struct tx_cmd) + sizeof (struct i596_tbd)), GFP_ATOMIC);
+       if (tx_cmd == NULL) {
+               printk(KERN_WARNING "%s: i596_xmit Memory squeeze, dropping packet.\n", dev->name);
+               dev->stats.tx_dropped++;
+               dev_kfree_skb (skb);
+       } else {
+               struct i596_tbd *tx_cmd_tbd;
+               tx_cmd_tbd = (struct i596_tbd *) (tx_cmd + 1);
+               tx_cmd->pa_tbd = va_to_pa (tx_cmd_tbd);
+               tx_cmd_tbd->pa_next = I596_NULL;
+
+               tx_cmd->cmd.command = (CMD_FLEX | CmdTx);
+
+               tx_cmd->pad = 0;
+               tx_cmd->size = 0;
+               tx_cmd_tbd->pad = 0;
+               tx_cmd_tbd->size = (EOF | length);
+
+               tx_cmd_tbd->pa_data = va_to_pa (skb->data);
+               tx_cmd_tbd->skb = skb;
+
+               if (i596_debug & LOG_SRCDST)
+                       print_eth (skb->data);
+
+               i596_add_cmd (dev, (struct i596_cmd *) tx_cmd);
+
+               dev->stats.tx_packets++;
+       }
+
+       return NETDEV_TX_OK;
+}
+
+static void
+i596_tx_timeout (struct net_device *dev) {
+       struct i596_private *lp = netdev_priv(dev);
+       int ioaddr = dev->base_addr;
+
+       /* Transmitter timeout, serious problems. */
+       printk(KERN_WARNING "%s: transmit timed out, status resetting.\n", dev->name);
+       dev->stats.tx_errors++;
+
+       /* Try to restart the adaptor */
+       if (lp->last_restart == dev->stats.tx_packets) {
+               printk ("Resetting board.\n");
+
+               /* Shutdown and restart */
+               i596_reset (dev, lp, ioaddr);
+       } else {
+               /* Issue a channel attention signal */
+               printk ("Kicking board.\n");
+               lp->scb.command = (CUC_START | RX_START);
+               CA();
+               lp->last_restart = dev->stats.tx_packets;
+       }
+       netif_wake_queue(dev);
+}
+
+static void print_eth(char *add)
+{
+       int i;
+
+       printk ("Dest  ");
+       for (i = 0; i < 6; i++)
+               printk(" %2.2X", (unsigned char) add[i]);
+       printk ("\n");
+
+       printk ("Source");
+       for (i = 0; i < 6; i++)
+               printk(" %2.2X", (unsigned char) add[i+6]);
+       printk ("\n");
+
+       printk ("type %2.2X%2.2X\n",
+               (unsigned char) add[12], (unsigned char) add[13]);
+}
+
+static const struct net_device_ops i596_netdev_ops = {
+       .ndo_open               = i596_open,
+       .ndo_stop               = i596_close,
+       .ndo_start_xmit         = i596_start_xmit,
+       .ndo_set_multicast_list = set_multicast_list,
+       .ndo_tx_timeout         = i596_tx_timeout,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
+static int __init lp486e_probe(struct net_device *dev) {
+       struct i596_private *lp;
+       unsigned char eth_addr[6] = { 0, 0xaa, 0, 0, 0, 0 };
+       unsigned char *bios;
+       int i, j;
+       int ret = -ENOMEM;
+       static int probed;
+
+       if (probed)
+               return -ENODEV;
+       probed++;
+
+       if (!request_region(IOADDR, LP486E_TOTAL_SIZE, DRV_NAME)) {
+               printk(KERN_ERR "lp486e: IO address 0x%x in use\n", IOADDR);
+               return -EBUSY;
+       }
+
+       lp = netdev_priv(dev);
+       spin_lock_init(&lp->cmd_lock);
+
+       /*
+        * Do we really have this thing?
+        */
+       if (i596_scp_setup(dev)) {
+               ret = -ENODEV;
+               goto err_out_kfree;
+       }
+
+       dev->base_addr = IOADDR;
+       dev->irq = IRQ;
+
+
+       /*
+        * How do we find the ethernet address? I don't know.
+        * One possibility is to look at the EISA configuration area
+        * [0xe8000-0xe9fff]. This contains the ethernet address
+        * but not at a fixed address - things depend on setup options.
+        *
+        * If we find no address, or the wrong address, use
+        *   ifconfig eth0 hw ether a1:a2:a3:a4:a5:a6
+        * with the value found in the BIOS setup.
+        */
+       bios = bus_to_virt(0xe8000);
+       for (j = 0; j < 0x2000; j++) {
+               if (bios[j] == 0 && bios[j+1] == 0xaa && bios[j+2] == 0) {
+                       printk("%s: maybe address at BIOS 0x%x:",
+                              dev->name, 0xe8000+j);
+                       for (i = 0; i < 6; i++) {
+                               eth_addr[i] = bios[i+j];
+                               printk(" %2.2X", eth_addr[i]);
+                       }
+                       printk("\n");
+               }
+       }
+
+       printk("%s: lp486e 82596 at %#3lx, IRQ %d,",
+              dev->name, dev->base_addr, dev->irq);
+       for (i = 0; i < 6; i++)
+               printk(" %2.2X", dev->dev_addr[i] = eth_addr[i]);
+       printk("\n");
+
+       /* The LP486E-specific entries in the device structure. */
+       dev->netdev_ops = &i596_netdev_ops;
+       dev->watchdog_timeo = 5*HZ;
+
+#if 0
+       /* selftest reports 0x320925ae - don't know what that means */
+       i596_port_do(dev, PORT_SELFTEST, "selftest");
+       i596_port_do(dev, PORT_DUMP, "dump");
+#endif
+       return 0;
+
+err_out_kfree:
+       release_region(IOADDR, LP486E_TOTAL_SIZE);
+       return ret;
+}
+
+static inline void
+i596_handle_CU_completion(struct net_device *dev,
+                         struct i596_private *lp,
+                         unsigned short status,
+                         unsigned short *ack_cmdp) {
+       struct i596_cmd *cmd;
+       int frames_out = 0;
+       int commands_done = 0;
+       int cmd_val;
+       unsigned long flags;
+
+       spin_lock_irqsave(&lp->cmd_lock, flags);
+       cmd = lp->cmd_head;
+
+       while (lp->cmd_head && (lp->cmd_head->status & CMD_STAT_C)) {
+               cmd = lp->cmd_head;
+
+               lp->cmd_head = pa_to_va(lp->cmd_head->pa_next);
+               lp->cmd_backlog--;
+
+               commands_done++;
+               cmd_val = cmd->command & 0x7;
+#if 0
+               printk("finished CU %s command (%d)\n",
+                      CUcmdnames[cmd_val], cmd_val);
+#endif
+               switch (cmd_val) {
+               case CmdTx:
+               {
+                       struct tx_cmd *tx_cmd;
+                       struct i596_tbd *tx_cmd_tbd;
+
+                       tx_cmd = (struct tx_cmd *) cmd;
+                       tx_cmd_tbd = pa_to_va(tx_cmd->pa_tbd);
+
+                       frames_out++;
+                       if (cmd->status & CMD_STAT_OK) {
+                               if (i596_debug)
+                                       print_eth(pa_to_va(tx_cmd_tbd->pa_data));
+                       } else {
+                               dev->stats.tx_errors++;
+                               if (i596_debug)
+                                       printk("transmission failure:%04x\n",
+                                              cmd->status);
+                               if (cmd->status & 0x0020)
+                                       dev->stats.collisions++;
+                               if (!(cmd->status & 0x0040))
+                                       dev->stats.tx_heartbeat_errors++;
+                               if (cmd->status & 0x0400)
+                                       dev->stats.tx_carrier_errors++;
+                               if (cmd->status & 0x0800)
+                                       dev->stats.collisions++;
+                               if (cmd->status & 0x1000)
+                                       dev->stats.tx_aborted_errors++;
+                       }
+                       dev_kfree_skb_irq(tx_cmd_tbd->skb);
+
+                       cmd->pa_next = I596_NULL;
+                       kfree((unsigned char *)tx_cmd);
+                       netif_wake_queue(dev);
+                       break;
+               }
+
+               case CmdMulticastList:
+                       cmd->pa_next = I596_NULL;
+                       kfree((unsigned char *)cmd);
+                       break;
+
+               case CmdTDR:
+               {
+                       unsigned long status = *((unsigned long *) (cmd + 1));
+                       if (status & 0x8000) {
+                               if (i596_debug)
+                                       printk("%s: link ok.\n", dev->name);
+                       } else {
+                               if (status & 0x4000)
+                                       printk("%s: Transceiver problem.\n",
+                                              dev->name);
+                               if (status & 0x2000)
+                                       printk("%s: Termination problem.\n",
+                                              dev->name);
+                               if (status & 0x1000)
+                                       printk("%s: Short circuit.\n",
+                                              dev->name);
+                               printk("%s: Time %ld.\n",
+                                      dev->name, status & 0x07ff);
+                       }
+               }
+               default:
+                       cmd->pa_next = I596_NULL;
+                       lp->last_cmd = jiffies;
+
+               }
+               barrier();
+       }
+
+       cmd = lp->cmd_head;
+       while (cmd && (cmd != lp->cmd_tail)) {
+               cmd->command &= 0x1fff;
+               cmd = pa_to_va(cmd->pa_next);
+               barrier();
+       }
+
+       if (lp->cmd_head)
+               *ack_cmdp |= CUC_START;
+       lp->scb.pa_cmd = va_to_pa(lp->cmd_head);
+       spin_unlock_irqrestore(&lp->cmd_lock, flags);
+}
+
+static irqreturn_t
+i596_interrupt(int irq, void *dev_instance)
+{
+       struct net_device *dev = dev_instance;
+       struct i596_private *lp = netdev_priv(dev);
+       unsigned short status, ack_cmd = 0;
+       int frames_in = 0;
+
+       /*
+        * The 82596 examines the command, performs the required action,
+        * and then clears the SCB command word.
+        */
+       if (lp->scb.command && i596_timeout(dev, "interrupt", 40))
+               ;
+
+       /*
+        * The status word indicates the status of the 82596.
+        * It is modified only by the 82596.
+        *
+        * [So, we must not clear it. I find often status 0xffff,
+        *  which is not one of the values allowed by the docs.]
+        */
+       status = lp->scb.status;
+#if 0
+       if (i596_debug) {
+               printk("%s: i596 interrupt, ", dev->name);
+               i596_out_status(status);
+       }
+#endif
+       /* Impossible, but it happens - perhaps when we get
+          a receive interrupt but scb.pa_rfd is I596_NULL. */
+       if (status == 0xffff) {
+               printk("%s: i596_interrupt: got status 0xffff\n", dev->name);
+               goto out;
+       }
+
+       ack_cmd = (status & STAT_ACK);
+
+       if (status & (STAT_CX | STAT_CNA))
+               i596_handle_CU_completion(dev, lp, status, &ack_cmd);
+
+       if (status & (STAT_FR | STAT_RNR)) {
+               /* Restart the receive unit when it got inactive somehow */
+               if ((status & STAT_RNR) && netif_running(dev))
+                       ack_cmd |= RX_START;
+
+               if (status & STAT_FR) {
+                       frames_in = i596_rx(dev);
+                       if (!frames_in)
+                               printk("receive frame reported, but no frames\n");
+               }
+       }
+
+       /* acknowledge the interrupt */
+       /*
+       if ((lp->scb.pa_cmd != I596_NULL) && netif_running(dev))
+               ack_cmd |= CUC_START;
+       */
+
+       if (lp->scb.command && i596_timeout(dev, "i596 interrupt", 100))
+               ;
+
+       lp->scb.command = ack_cmd;
+
+       CLEAR_INT();
+       CA();
+
+ out:
+       return IRQ_HANDLED;
+}
+
+static int i596_close(struct net_device *dev) {
+       struct i596_private *lp = netdev_priv(dev);
+
+       netif_stop_queue(dev);
+
+       if (i596_debug)
+               printk("%s: Shutting down ethercard, status was %4.4x.\n",
+                      dev->name, lp->scb.status);
+
+       lp->scb.command = (CUC_ABORT | RX_ABORT);
+       CA();
+
+       i596_cleanup_cmd(dev);
+
+       if (lp->scb.command && i596_timeout(dev, "i596_close", 200))
+               ;
+
+       free_irq(dev->irq, dev);
+       remove_rx_bufs(dev);
+
+       return 0;
+}
+
+/*
+*      Set or clear the multicast filter for this adaptor.
+*/
+
+static void set_multicast_list(struct net_device *dev) {
+       struct i596_private *lp = netdev_priv(dev);
+       struct i596_cmd *cmd;
+
+       if (i596_debug > 1)
+               printk ("%s: set multicast list %d\n",
+                       dev->name, netdev_mc_count(dev));
+
+       if (!netdev_mc_empty(dev)) {
+               struct netdev_hw_addr *ha;
+               char *cp;
+               cmd = kmalloc(sizeof(struct i596_cmd) + 2 +
+                             netdev_mc_count(dev) * 6, GFP_ATOMIC);
+               if (cmd == NULL) {
+                       printk (KERN_ERR "%s: set_multicast Memory squeeze.\n", dev->name);
+                       return;
+               }
+               cmd->command = CmdMulticastList;
+               *((unsigned short *) (cmd + 1)) = netdev_mc_count(dev) * 6;
+               cp = ((char *)(cmd + 1))+2;
+               netdev_for_each_mc_addr(ha, dev) {
+                       memcpy(cp, ha->addr, 6);
+                       cp += 6;
+               }
+               if (i596_debug & LOG_SRCDST)
+                       print_eth (((char *)(cmd + 1)) + 2);
+               i596_add_cmd(dev, cmd);
+       } else {
+               if (lp->set_conf.pa_next != I596_NULL) {
+                       return;
+               }
+               if (netdev_mc_empty(dev) &&
+                   !(dev->flags & (IFF_PROMISC | IFF_ALLMULTI))) {
+                       lp->i596_config[8] &= ~0x01;
+               } else {
+                       lp->i596_config[8] |= 0x01;
+               }
+
+               i596_add_cmd(dev, (struct i596_cmd *) &lp->set_conf);
+       }
+}
+
+MODULE_AUTHOR("Ard van Breemen <ard@cstmel.nl.eu.org>");
+MODULE_DESCRIPTION("Intel Panther onboard i82596 driver");
+MODULE_LICENSE("GPL");
+
+static struct net_device *dev_lp486e;
+static int full_duplex;
+static int options;
+static int io = IOADDR;
+static int irq = IRQ;
+
+module_param(debug, int, 0);
+//module_param(max_interrupt_work, int, 0);
+//module_param(reverse_probe, int, 0);
+//module_param(rx_copybreak, int, 0);
+module_param(options, int, 0);
+module_param(full_duplex, int, 0);
+
+static int __init lp486e_init_module(void) {
+       int err;
+       struct net_device *dev = alloc_etherdev(sizeof(struct i596_private));
+       if (!dev)
+               return -ENOMEM;
+
+       dev->irq = irq;
+       dev->base_addr = io;
+       err = lp486e_probe(dev);
+       if (err) {
+               free_netdev(dev);
+               return err;
+       }
+       err = register_netdev(dev);
+       if (err) {
+               release_region(dev->base_addr, LP486E_TOTAL_SIZE);
+               free_netdev(dev);
+               return err;
+       }
+       dev_lp486e = dev;
+       full_duplex = 0;
+       options = 0;
+       return 0;
+}
+
+static void __exit lp486e_cleanup_module(void) {
+       unregister_netdev(dev_lp486e);
+       release_region(dev_lp486e->base_addr, LP486E_TOTAL_SIZE);
+       free_netdev(dev_lp486e);
+}
+
+module_init(lp486e_init_module);
+module_exit(lp486e_cleanup_module);
diff --git a/drivers/net/ethernet/i825xx/ni52.c b/drivers/net/ethernet/i825xx/ni52.c
new file mode 100644 (file)
index 0000000..d973fc6
--- /dev/null
@@ -0,0 +1,1346 @@
+/*
+ * net-3-driver for the NI5210 card (i82586 Ethernet chip)
+ *
+ * This is an extension to the Linux operating system, and is covered by the
+ * same GNU General Public License that covers that work.
+ *
+ * Alphacode 0.82 (96/09/29) for Linux 2.0.0 (or later)
+ * Copyrights (c) 1994,1995,1996 by M.Hipp (hippm@informatik.uni-tuebingen.de)
+ *    [feel free to mail ....]
+ *
+ * when using as module: (no autoprobing!)
+ *   run with e.g:
+ *       insmod ni52.o io=0x360 irq=9 memstart=0xd0000 memend=0xd4000
+ *
+ * CAN YOU PLEASE REPORT ME YOUR PERFORMANCE EXPERIENCES !!.
+ *
+ * If you find a bug, please report me:
+ *   The kernel panic output and any kmsg from the ni52 driver
+ *   the ni5210-driver-version and the linux-kernel version
+ *   how many shared memory (memsize) on the netcard,
+ *   bootprom: yes/no, base_addr, mem_start
+ *   maybe the ni5210-card revision and the i82586 version
+ *
+ * autoprobe for: base_addr: 0x300,0x280,0x360,0x320,0x340
+ *                mem_start: 0xd0000,0xd2000,0xc8000,0xca000,0xd4000,0xd6000,
+ *                           0xd8000,0xcc000,0xce000,0xda000,0xdc000
+ *
+ * sources:
+ *   skeleton.c from Donald Becker
+ *
+ * I have also done a look in the following sources: (mail me if you need them)
+ *   crynwr-packet-driver by Russ Nelson
+ *   Garret A. Wollman's (fourth) i82586-driver for BSD
+ *   (before getting an i82596 (yes 596 not 586) manual, the existing drivers
+ *    helped me a lot to understand this tricky chip.)
+ *
+ * Known Problems:
+ *   The internal sysbus seems to be slow. So we often lose packets because of
+ *   overruns while receiving from a fast remote host.
+ *   This can slow down TCP connections. Maybe the newer ni5210 cards are
+ *   better. My experience is, that if a machine sends with more than about
+ *   500-600K/s the fifo/sysbus overflows.
+ *
+ * IMPORTANT NOTE:
+ *   On fast networks, it's a (very) good idea to have 16K shared memory. With
+ *   8K, we can store only 4 receive frames, so it can (easily) happen that a
+ *   remote machine 'overruns' our system.
+ *
+ * Known i82586/card problems (I'm sure, there are many more!):
+ *   Running the NOP-mode, the i82586 sometimes seems to forget to report
+ *   every xmit-interrupt until we restart the CU.
+ *   Another MAJOR bug is, that the RU sometimes seems to ignore the EL-Bit
+ *   in the RBD-Struct which indicates an end of the RBD queue.
+ *   Instead, the RU fetches another (randomly selected and
+ *   usually used) RBD and begins to fill it. (Maybe, this happens only if
+ *   the last buffer from the previous RFD fits exact into the queue and
+ *   the next RFD can't fetch an initial RBD. Anyone knows more? )
+ *
+ * results from ftp performance tests with Linux 1.2.5
+ *   send and receive about 350-400 KByte/s (peak up to 460 kbytes/s)
+ *   sending in NOP-mode: peak performance up to 530K/s (but better don't
+ *   run this mode)
+ */
+
+/*
+ * 29.Sept.96: virt_to_bus changes for new memory scheme
+ * 19.Feb.96: more Mcast changes, module support (MH)
+ *
+ * 18.Nov.95: Mcast changes (AC).
+ *
+ * 23.April.95: fixed(?) receiving problems by configuring a RFD more
+ *              than the number of RBD's. Can maybe cause other problems.
+ * 18.April.95: Added MODULE support (MH)
+ * 17.April.95: MC related changes in init586() and set_multicast_list().
+ *              removed use of 'jiffies' in init586() (MH)
+ *
+ * 19.Sep.94: Added Multicast support (not tested yet) (MH)
+ *
+ * 18.Sep.94: Workaround for 'EL-Bug'. Removed flexible RBD-handling.
+ *            Now, every RFD has exact one RBD. (MH)
+ *
+ * 14.Sep.94: added promiscuous mode, a few cleanups (MH)
+ *
+ * 19.Aug.94: changed request_irq() parameter (MH)
+ *
+ * 20.July.94: removed cleanup bugs, removed a 16K-mem-probe-bug (MH)
+ *
+ * 19.July.94: lotsa cleanups .. (MH)
+ *
+ * 17.July.94: some patches ... verified to run with 1.1.29 (MH)
+ *
+ * 4.July.94: patches for Linux 1.1.24  (MH)
+ *
+ * 26.March.94: patches for Linux 1.0 and iomem-auto-probe (MH)
+ *
+ * 30.Sep.93: Added nop-chain .. driver now runs with only one Xmit-Buff,
+ *                             too (MH)
+ *
+ * < 30.Sep.93: first versions
+ */
+
+static int debuglevel; /* debug-printk 0: off 1: a few 2: more */
+static int automatic_resume; /* experimental .. better should be zero */
+static int rfdadd;     /* rfdadd=1 may be better for 8K MEM cards */
+static int fifo = 0x8; /* don't change */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <asm/io.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include "ni52.h"
+
+#define DRV_NAME "ni52"
+
+#define DEBUG       /* debug on */
+#define SYSBUSVAL 1 /* 8 Bit */
+
+#define ni_attn586()  { outb(0, dev->base_addr + NI52_ATTENTION); }
+#define ni_reset586() { outb(0, dev->base_addr + NI52_RESET); }
+#define ni_disint()   { outb(0, dev->base_addr + NI52_INTDIS); }
+#define ni_enaint()   { outb(0, dev->base_addr + NI52_INTENA); }
+
+#define make32(ptr16) ((void __iomem *)(p->memtop + (short) (ptr16)))
+#define make24(ptr32) ((char __iomem *)(ptr32)) - p->base
+#define make16(ptr32) ((unsigned short) ((char __iomem *)(ptr32)\
+                                       - p->memtop))
+
+/******************* how to calculate the buffers *****************************
+
+  * IMPORTANT NOTE: if you configure only one NUM_XMIT_BUFFS, the driver works
+  * --------------- in a different (more stable?) mode. Only in this mode it's
+  *                 possible to configure the driver with 'NO_NOPCOMMANDS'
+
+sizeof(scp)=12; sizeof(scb)=16; sizeof(iscp)=8;
+sizeof(scp)+sizeof(iscp)+sizeof(scb) = 36 = INIT
+sizeof(rfd) = 24; sizeof(rbd) = 12;
+sizeof(tbd) = 8; sizeof(transmit_cmd) = 16;
+sizeof(nop_cmd) = 8;
+
+  * if you don't know the driver, better do not change these values: */
+
+#define RECV_BUFF_SIZE 1524 /* slightly oversized */
+#define XMIT_BUFF_SIZE 1524 /* slightly oversized */
+#define NUM_XMIT_BUFFS 1    /* config for both, 8K and 16K shmem */
+#define NUM_RECV_BUFFS_8  4 /* config for 8K shared mem */
+#define NUM_RECV_BUFFS_16 9 /* config for 16K shared mem */
+#define NO_NOPCOMMANDS      /* only possible with NUM_XMIT_BUFFS=1 */
+
+/**************************************************************************/
+
+
+#define NI52_TOTAL_SIZE 16
+#define NI52_ADDR0 0x02
+#define NI52_ADDR1 0x07
+#define NI52_ADDR2 0x01
+
+static int     ni52_probe1(struct net_device *dev, int ioaddr);
+static irqreturn_t ni52_interrupt(int irq, void *dev_id);
+static int     ni52_open(struct net_device *dev);
+static int     ni52_close(struct net_device *dev);
+static netdev_tx_t ni52_send_packet(struct sk_buff *, struct net_device *);
+static struct  net_device_stats *ni52_get_stats(struct net_device *dev);
+static void    set_multicast_list(struct net_device *dev);
+static void    ni52_timeout(struct net_device *dev);
+
+/* helper-functions */
+static int     init586(struct net_device *dev);
+static int     check586(struct net_device *dev, unsigned size);
+static void    alloc586(struct net_device *dev);
+static void    startrecv586(struct net_device *dev);
+static void   __iomem *alloc_rfa(struct net_device *dev, void __iomem *ptr);
+static void    ni52_rcv_int(struct net_device *dev);
+static void    ni52_xmt_int(struct net_device *dev);
+static void    ni52_rnr_int(struct net_device *dev);
+
+struct priv {
+       char __iomem *base;
+       char __iomem *mapped;
+       char __iomem *memtop;
+       spinlock_t spinlock;
+       int reset;
+       struct rfd_struct __iomem *rfd_last, *rfd_top, *rfd_first;
+       struct scp_struct __iomem *scp;
+       struct iscp_struct __iomem *iscp;
+       struct scb_struct __iomem *scb;
+       struct tbd_struct __iomem *xmit_buffs[NUM_XMIT_BUFFS];
+#if (NUM_XMIT_BUFFS == 1)
+       struct transmit_cmd_struct __iomem *xmit_cmds[2];
+       struct nop_cmd_struct __iomem *nop_cmds[2];
+#else
+       struct transmit_cmd_struct __iomem *xmit_cmds[NUM_XMIT_BUFFS];
+       struct nop_cmd_struct __iomem *nop_cmds[NUM_XMIT_BUFFS];
+#endif
+       int nop_point, num_recv_buffs;
+       char __iomem *xmit_cbuffs[NUM_XMIT_BUFFS];
+       int xmit_count, xmit_last;
+};
+
+/* wait for command with timeout: */
+static void wait_for_scb_cmd(struct net_device *dev)
+{
+       struct priv *p = netdev_priv(dev);
+       int i;
+       for (i = 0; i < 16384; i++) {
+               if (readb(&p->scb->cmd_cuc) == 0)
+                     break;
+               udelay(4);
+               if (i == 16383) {
+                       printk(KERN_ERR "%s: scb_cmd timed out: %04x,%04x .. disabling i82586!!\n",
+                               dev->name, readb(&p->scb->cmd_cuc), readb(&p->scb->cus));
+                       if (!p->reset) {
+                               p->reset = 1;
+                               ni_reset586();
+                       }
+               }
+       }
+}
+
+static void wait_for_scb_cmd_ruc(struct net_device *dev)
+{
+       struct priv *p = netdev_priv(dev);
+       int i;
+       for (i = 0; i < 16384; i++) {
+               if (readb(&p->scb->cmd_ruc) == 0)
+                       break;
+               udelay(4);
+               if (i == 16383) {
+                       printk(KERN_ERR "%s: scb_cmd (ruc) timed out: %04x,%04x .. disabling i82586!!\n",
+                               dev->name, readb(&p->scb->cmd_ruc),
+                               readb(&p->scb->rus));
+                       if (!p->reset) {
+                               p->reset = 1;
+                               ni_reset586();
+                       }
+               }
+       }
+}
+
+static void wait_for_stat_compl(void __iomem *p)
+{
+       struct nop_cmd_struct __iomem *addr = p;
+       int i;
+       for (i = 0; i < 32767; i++) {
+               if (readw(&((addr)->cmd_status)) & STAT_COMPL)
+                       break;
+               udelay(32);
+       }
+}
+
+/**********************************************
+ * close device
+ */
+static int ni52_close(struct net_device *dev)
+{
+       free_irq(dev->irq, dev);
+       ni_reset586(); /* the hard way to stop the receiver */
+       netif_stop_queue(dev);
+       return 0;
+}
+
+/**********************************************
+ * open device
+ */
+static int ni52_open(struct net_device *dev)
+{
+       int ret;
+
+       ni_disint();
+       alloc586(dev);
+       init586(dev);
+       startrecv586(dev);
+       ni_enaint();
+
+       ret = request_irq(dev->irq, ni52_interrupt, 0, dev->name, dev);
+       if (ret) {
+               ni_reset586();
+               return ret;
+       }
+       netif_start_queue(dev);
+       return 0; /* most done by init */
+}
+
+static int check_iscp(struct net_device *dev, void __iomem *addr)
+{
+       struct iscp_struct __iomem *iscp = addr;
+       struct priv *p = netdev_priv(dev);
+       memset_io(iscp, 0, sizeof(struct iscp_struct));
+
+       writel(make24(iscp), &p->scp->iscp);
+       writeb(1, &iscp->busy);
+
+       ni_reset586();
+       ni_attn586();
+       mdelay(32);     /* wait a while... */
+       /* i82586 clears 'busy' after successful init */
+       if (readb(&iscp->busy))
+               return 0;
+       return 1;
+}
+
+/**********************************************
+ * Check to see if there's an 82586 out there.
+ */
+static int check586(struct net_device *dev, unsigned size)
+{
+       struct priv *p = netdev_priv(dev);
+       int i;
+
+       p->mapped = ioremap(dev->mem_start, size);
+       if (!p->mapped)
+               return 0;
+
+       p->base = p->mapped + size - 0x01000000;
+       p->memtop = p->mapped + size;
+       p->scp = (struct scp_struct __iomem *)(p->base + SCP_DEFAULT_ADDRESS);
+       p->scb  = (struct scb_struct __iomem *) p->mapped;
+       p->iscp = (struct iscp_struct __iomem *)p->scp - 1;
+       memset_io(p->scp, 0, sizeof(struct scp_struct));
+       for (i = 0; i < sizeof(struct scp_struct); i++)
+               /* memory was writeable? */
+               if (readb((char __iomem *)p->scp + i))
+                       goto Enodev;
+       writeb(SYSBUSVAL, &p->scp->sysbus);     /* 1 = 8Bit-Bus, 0 = 16 Bit */
+       if (readb(&p->scp->sysbus) != SYSBUSVAL)
+               goto Enodev;
+
+       if (!check_iscp(dev, p->mapped))
+               goto Enodev;
+       if (!check_iscp(dev, p->iscp))
+               goto Enodev;
+       return 1;
+Enodev:
+       iounmap(p->mapped);
+       return 0;
+}
+
+/******************************************************************
+ * set iscp at the right place, called by ni52_probe1 and open586.
+ */
+static void alloc586(struct net_device *dev)
+{
+       struct priv *p = netdev_priv(dev);
+
+       ni_reset586();
+       mdelay(32);
+
+       memset_io(p->iscp, 0, sizeof(struct iscp_struct));
+       memset_io(p->scp , 0, sizeof(struct scp_struct));
+
+       writel(make24(p->iscp), &p->scp->iscp);
+       writeb(SYSBUSVAL, &p->scp->sysbus);
+       writew(make16(p->scb), &p->iscp->scb_offset);
+
+       writeb(1, &p->iscp->busy);
+       ni_reset586();
+       ni_attn586();
+
+       mdelay(32);
+
+       if (readb(&p->iscp->busy))
+               printk(KERN_ERR "%s: Init-Problems (alloc).\n", dev->name);
+
+       p->reset = 0;
+
+       memset_io(p->scb, 0, sizeof(struct scb_struct));
+}
+
+/* set: io,irq,memstart,memend or set it when calling insmod */
+static int irq = 9;
+static int io = 0x300;
+static long memstart;  /* e.g 0xd0000 */
+static long memend;    /* e.g 0xd4000 */
+
+/**********************************************
+ * probe the ni5210-card
+ */
+struct net_device * __init ni52_probe(int unit)
+{
+       struct net_device *dev = alloc_etherdev(sizeof(struct priv));
+       static const int ports[] = {0x300, 0x280, 0x360, 0x320, 0x340, 0};
+       const int *port;
+       struct priv *p;
+       int err = 0;
+
+       if (!dev)
+               return ERR_PTR(-ENOMEM);
+
+       p = netdev_priv(dev);
+
+       if (unit >= 0) {
+               sprintf(dev->name, "eth%d", unit);
+               netdev_boot_setup_check(dev);
+               io = dev->base_addr;
+               irq = dev->irq;
+               memstart = dev->mem_start;
+               memend = dev->mem_end;
+       }
+
+       if (io > 0x1ff) {       /* Check a single specified location. */
+               err = ni52_probe1(dev, io);
+       } else if (io > 0) {            /* Don't probe at all. */
+               err = -ENXIO;
+       } else {
+               for (port = ports; *port && ni52_probe1(dev, *port) ; port++)
+                       ;
+               if (*port)
+                       goto got_it;
+#ifdef FULL_IO_PROBE
+               for (io = 0x200; io < 0x400 && ni52_probe1(dev, io); io += 8)
+                       ;
+               if (io < 0x400)
+                       goto got_it;
+#endif
+               err = -ENODEV;
+       }
+       if (err)
+               goto out;
+got_it:
+       err = register_netdev(dev);
+       if (err)
+               goto out1;
+       return dev;
+out1:
+       iounmap(p->mapped);
+       release_region(dev->base_addr, NI52_TOTAL_SIZE);
+out:
+       free_netdev(dev);
+       return ERR_PTR(err);
+}
+
+static const struct net_device_ops ni52_netdev_ops = {
+       .ndo_open               = ni52_open,
+       .ndo_stop               = ni52_close,
+       .ndo_get_stats          = ni52_get_stats,
+       .ndo_tx_timeout         = ni52_timeout,
+       .ndo_start_xmit         = ni52_send_packet,
+       .ndo_set_multicast_list = set_multicast_list,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
+static int __init ni52_probe1(struct net_device *dev, int ioaddr)
+{
+       int i, size, retval;
+       struct priv *priv = netdev_priv(dev);
+
+       dev->base_addr = ioaddr;
+       dev->irq = irq;
+       dev->mem_start = memstart;
+       dev->mem_end = memend;
+
+       spin_lock_init(&priv->spinlock);
+
+       if (!request_region(ioaddr, NI52_TOTAL_SIZE, DRV_NAME))
+               return -EBUSY;
+
+       if (!(inb(ioaddr+NI52_MAGIC1) == NI52_MAGICVAL1) ||
+           !(inb(ioaddr+NI52_MAGIC2) == NI52_MAGICVAL2)) {
+               retval = -ENODEV;
+               goto out;
+       }
+
+       for (i = 0; i < ETH_ALEN; i++)
+               dev->dev_addr[i] = inb(dev->base_addr+i);
+
+       if (dev->dev_addr[0] != NI52_ADDR0 || dev->dev_addr[1] != NI52_ADDR1 ||
+           dev->dev_addr[2] != NI52_ADDR2) {
+               retval = -ENODEV;
+               goto out;
+       }
+
+       printk(KERN_INFO "%s: NI5210 found at %#3lx, ",
+                               dev->name, dev->base_addr);
+
+       /*
+        * check (or search) IO-Memory, 8K and 16K
+        */
+#ifdef MODULE
+       size = dev->mem_end - dev->mem_start;
+       if (size != 0x2000 && size != 0x4000) {
+               printk("\n");
+               printk(KERN_ERR "%s: Invalid memory size %d. Allowed is 0x2000 or 0x4000 bytes.\n", dev->name, size);
+               retval = -ENODEV;
+               goto out;
+       }
+       if (!check586(dev, size)) {
+               printk(KERN_ERR "?memcheck, Can't find memory at 0x%lx with size %d!\n", dev->mem_start, size);
+               retval = -ENODEV;
+               goto out;
+       }
+#else
+       if (dev->mem_start != 0) {
+               /* no auto-mem-probe */
+               size = 0x4000; /* check for 16K mem */
+               if (!check586(dev, size)) {
+                       size = 0x2000; /* check for 8K mem */
+                       if (!check586(dev, size)) {
+                               printk(KERN_ERR "?memprobe, Can't find memory at 0x%lx!\n", dev->mem_start);
+                               retval = -ENODEV;
+                               goto out;
+                       }
+               }
+       } else {
+               static const unsigned long memaddrs[] = {
+                       0xc8000, 0xca000, 0xcc000, 0xce000, 0xd0000, 0xd2000,
+                       0xd4000, 0xd6000, 0xd8000, 0xda000, 0xdc000, 0
+               };
+               for (i = 0;; i++) {
+                       if (!memaddrs[i]) {
+                               printk(KERN_ERR "?memprobe, Can't find io-memory!\n");
+                               retval = -ENODEV;
+                               goto out;
+                       }
+                       dev->mem_start = memaddrs[i];
+                       size = 0x2000; /* check for 8K mem */
+                       if (check586(dev, size))
+                               /* 8K-check */
+                               break;
+                       size = 0x4000; /* check for 16K mem */
+                       if (check586(dev, size))
+                               /* 16K-check */
+                               break;
+               }
+       }
+       /* set mem_end showed by 'ifconfig' */
+       dev->mem_end = dev->mem_start + size;
+#endif
+
+       alloc586(dev);
+
+       /* set number of receive-buffs according to memsize */
+       if (size == 0x2000)
+               priv->num_recv_buffs = NUM_RECV_BUFFS_8;
+       else
+               priv->num_recv_buffs = NUM_RECV_BUFFS_16;
+
+       printk(KERN_DEBUG "Memaddr: 0x%lx, Memsize: %d, ",
+                               dev->mem_start, size);
+
+       if (dev->irq < 2) {
+               unsigned long irq_mask;
+
+               irq_mask = probe_irq_on();
+               ni_reset586();
+               ni_attn586();
+
+               mdelay(20);
+               dev->irq = probe_irq_off(irq_mask);
+               if (!dev->irq) {
+                       printk("?autoirq, Failed to detect IRQ line!\n");
+                       retval = -EAGAIN;
+                       iounmap(priv->mapped);
+                       goto out;
+               }
+               printk("IRQ %d (autodetected).\n", dev->irq);
+       } else {
+               if (dev->irq == 2)
+                       dev->irq = 9;
+               printk("IRQ %d (assigned and not checked!).\n", dev->irq);
+       }
+
+       dev->netdev_ops         = &ni52_netdev_ops;
+       dev->watchdog_timeo     = HZ/20;
+
+       return 0;
+out:
+       release_region(ioaddr, NI52_TOTAL_SIZE);
+       return retval;
+}
+
+/**********************************************
+ * init the chip (ni52-interrupt should be disabled?!)
+ * needs a correct 'allocated' memory
+ */
+
+static int init586(struct net_device *dev)
+{
+       void __iomem *ptr;
+       int i, result = 0;
+       struct priv *p = netdev_priv(dev);
+       struct configure_cmd_struct __iomem *cfg_cmd;
+       struct iasetup_cmd_struct __iomem *ias_cmd;
+       struct tdr_cmd_struct __iomem *tdr_cmd;
+       struct mcsetup_cmd_struct __iomem *mc_cmd;
+       struct netdev_hw_addr *ha;
+       int num_addrs = netdev_mc_count(dev);
+
+       ptr = p->scb + 1;
+
+       cfg_cmd = ptr; /* configure-command */
+       writew(0, &cfg_cmd->cmd_status);
+       writew(CMD_CONFIGURE | CMD_LAST, &cfg_cmd->cmd_cmd);
+       writew(0xFFFF, &cfg_cmd->cmd_link);
+
+       /* number of cfg bytes */
+       writeb(0x0a, &cfg_cmd->byte_cnt);
+       /* fifo-limit (8=tx:32/rx:64) */
+       writeb(fifo, &cfg_cmd->fifo);
+       /* hold or discard bad recv frames (bit 7) */
+       writeb(0x40, &cfg_cmd->sav_bf);
+       /* addr_len |!src_insert |pre-len |loopback */
+       writeb(0x2e, &cfg_cmd->adr_len);
+       writeb(0x00, &cfg_cmd->priority);
+       writeb(0x60, &cfg_cmd->ifs);
+       writeb(0x00, &cfg_cmd->time_low);
+       writeb(0xf2, &cfg_cmd->time_high);
+       writeb(0x00, &cfg_cmd->promisc);
+       if (dev->flags & IFF_ALLMULTI) {
+               int len = ((char __iomem *)p->iscp - (char __iomem *)ptr - 8) / 6;
+               if (num_addrs > len) {
+                       printk(KERN_ERR "%s: switching to promisc. mode\n",
+                               dev->name);
+                       writeb(0x01, &cfg_cmd->promisc);
+               }
+       }
+       if (dev->flags & IFF_PROMISC)
+               writeb(0x01, &cfg_cmd->promisc);
+       writeb(0x00, &cfg_cmd->carr_coll);
+       writew(make16(cfg_cmd), &p->scb->cbl_offset);
+       writeb(0, &p->scb->cmd_ruc);
+
+       writeb(CUC_START, &p->scb->cmd_cuc); /* cmd.-unit start */
+       ni_attn586();
+
+       wait_for_stat_compl(cfg_cmd);
+
+       if ((readw(&cfg_cmd->cmd_status) & (STAT_OK|STAT_COMPL)) !=
+                                                       (STAT_COMPL|STAT_OK)) {
+               printk(KERN_ERR "%s: configure command failed: %x\n",
+                               dev->name, readw(&cfg_cmd->cmd_status));
+               return 1;
+       }
+
+       /*
+        * individual address setup
+        */
+
+       ias_cmd = ptr;
+
+       writew(0, &ias_cmd->cmd_status);
+       writew(CMD_IASETUP | CMD_LAST, &ias_cmd->cmd_cmd);
+       writew(0xffff, &ias_cmd->cmd_link);
+
+       memcpy_toio(&ias_cmd->iaddr, (char *)dev->dev_addr, ETH_ALEN);
+
+       writew(make16(ias_cmd), &p->scb->cbl_offset);
+
+       writeb(CUC_START, &p->scb->cmd_cuc); /* cmd.-unit start */
+       ni_attn586();
+
+       wait_for_stat_compl(ias_cmd);
+
+       if ((readw(&ias_cmd->cmd_status) & (STAT_OK|STAT_COMPL)) !=
+                                                       (STAT_OK|STAT_COMPL)) {
+               printk(KERN_ERR "%s (ni52): individual address setup command failed: %04x\n", dev->name, readw(&ias_cmd->cmd_status));
+               return 1;
+       }
+
+       /*
+        * TDR, wire check .. e.g. no resistor e.t.c
+        */
+
+       tdr_cmd = ptr;
+
+       writew(0, &tdr_cmd->cmd_status);
+       writew(CMD_TDR | CMD_LAST, &tdr_cmd->cmd_cmd);
+       writew(0xffff, &tdr_cmd->cmd_link);
+       writew(0, &tdr_cmd->status);
+
+       writew(make16(tdr_cmd), &p->scb->cbl_offset);
+       writeb(CUC_START, &p->scb->cmd_cuc); /* cmd.-unit start */
+       ni_attn586();
+
+       wait_for_stat_compl(tdr_cmd);
+
+       if (!(readw(&tdr_cmd->cmd_status) & STAT_COMPL))
+               printk(KERN_ERR "%s: Problems while running the TDR.\n",
+                               dev->name);
+       else {
+               udelay(16);
+               result = readw(&tdr_cmd->status);
+               writeb(readb(&p->scb->cus) & STAT_MASK, &p->scb->cmd_cuc);
+               ni_attn586(); /* ack the interrupts */
+
+               if (result & TDR_LNK_OK)
+                       ;
+               else if (result & TDR_XCVR_PRB)
+                       printk(KERN_ERR "%s: TDR: Transceiver problem. Check the cable(s)!\n",
+                               dev->name);
+               else if (result & TDR_ET_OPN)
+                       printk(KERN_ERR "%s: TDR: No correct termination %d clocks away.\n",
+                               dev->name, result & TDR_TIMEMASK);
+               else if (result & TDR_ET_SRT) {
+                       /* time == 0 -> strange :-) */
+                       if (result & TDR_TIMEMASK)
+                               printk(KERN_ERR "%s: TDR: Detected a short circuit %d clocks away.\n",
+                                       dev->name, result & TDR_TIMEMASK);
+               } else
+                       printk(KERN_ERR "%s: TDR: Unknown status %04x\n",
+                                               dev->name, result);
+       }
+
+       /*
+        * Multicast setup
+        */
+       if (num_addrs && !(dev->flags & IFF_PROMISC)) {
+               mc_cmd = ptr;
+               writew(0, &mc_cmd->cmd_status);
+               writew(CMD_MCSETUP | CMD_LAST, &mc_cmd->cmd_cmd);
+               writew(0xffff, &mc_cmd->cmd_link);
+               writew(num_addrs * 6, &mc_cmd->mc_cnt);
+
+               i = 0;
+               netdev_for_each_mc_addr(ha, dev)
+                       memcpy_toio(mc_cmd->mc_list[i++], ha->addr, 6);
+
+               writew(make16(mc_cmd), &p->scb->cbl_offset);
+               writeb(CUC_START, &p->scb->cmd_cuc);
+               ni_attn586();
+
+               wait_for_stat_compl(mc_cmd);
+
+               if ((readw(&mc_cmd->cmd_status) & (STAT_COMPL|STAT_OK))
+                                                != (STAT_COMPL|STAT_OK))
+                       printk(KERN_ERR "%s: Can't apply multicast-address-list.\n", dev->name);
+       }
+
+       /*
+        * alloc nop/xmit-cmds
+        */
+#if (NUM_XMIT_BUFFS == 1)
+       for (i = 0; i < 2; i++) {
+               p->nop_cmds[i] = ptr;
+               writew(CMD_NOP, &p->nop_cmds[i]->cmd_cmd);
+               writew(0, &p->nop_cmds[i]->cmd_status);
+               writew(make16(p->nop_cmds[i]), &p->nop_cmds[i]->cmd_link);
+               ptr = ptr + sizeof(struct nop_cmd_struct);
+       }
+#else
+       for (i = 0; i < NUM_XMIT_BUFFS; i++) {
+               p->nop_cmds[i] = ptr;
+               writew(CMD_NOP, &p->nop_cmds[i]->cmd_cmd);
+               writew(0, &p->nop_cmds[i]->cmd_status);
+               writew(make16(p->nop_cmds[i]), &p->nop_cmds[i]->cmd_link);
+               ptr = ptr + sizeof(struct nop_cmd_struct);
+       }
+#endif
+
+       ptr = alloc_rfa(dev, ptr); /* init receive-frame-area */
+
+       /*
+        * alloc xmit-buffs / init xmit_cmds
+        */
+       for (i = 0; i < NUM_XMIT_BUFFS; i++) {
+               /* Transmit cmd/buff 0 */
+               p->xmit_cmds[i] = ptr;
+               ptr = ptr + sizeof(struct transmit_cmd_struct);
+               p->xmit_cbuffs[i] = ptr; /* char-buffs */
+               ptr = ptr + XMIT_BUFF_SIZE;
+               p->xmit_buffs[i] = ptr; /* TBD */
+               ptr = ptr + sizeof(struct tbd_struct);
+               if ((void __iomem *)ptr > (void __iomem *)p->iscp) {
+                       printk(KERN_ERR "%s: not enough shared-mem for your configuration!\n",
+                               dev->name);
+                       return 1;
+               }
+               memset_io(p->xmit_cmds[i], 0,
+                                       sizeof(struct transmit_cmd_struct));
+               memset_io(p->xmit_buffs[i], 0,
+                                       sizeof(struct tbd_struct));
+               writew(make16(p->nop_cmds[(i+1)%NUM_XMIT_BUFFS]),
+                                       &p->xmit_cmds[i]->cmd_link);
+               writew(STAT_COMPL, &p->xmit_cmds[i]->cmd_status);
+               writew(CMD_XMIT|CMD_INT, &p->xmit_cmds[i]->cmd_cmd);
+               writew(make16(p->xmit_buffs[i]), &p->xmit_cmds[i]->tbd_offset);
+               writew(0xffff, &p->xmit_buffs[i]->next);
+               writel(make24(p->xmit_cbuffs[i]), &p->xmit_buffs[i]->buffer);
+       }
+
+       p->xmit_count = 0;
+       p->xmit_last    = 0;
+#ifndef NO_NOPCOMMANDS
+       p->nop_point    = 0;
+#endif
+
+        /*
+               * 'start transmitter'
+               */
+#ifndef NO_NOPCOMMANDS
+       writew(make16(p->nop_cmds[0]), &p->scb->cbl_offset);
+       writeb(CUC_START, &p->scb->cmd_cuc);
+       ni_attn586();
+       wait_for_scb_cmd(dev);
+#else
+       writew(make16(p->xmit_cmds[0]), &p->xmit_cmds[0]->cmd_link);
+       writew(CMD_XMIT | CMD_SUSPEND | CMD_INT, &p->xmit_cmds[0]->cmd_cmd);
+#endif
+
+       /*
+        * ack. interrupts
+        */
+       writeb(readb(&p->scb->cus) & STAT_MASK, &p->scb->cmd_cuc);
+       ni_attn586();
+       udelay(16);
+
+       ni_enaint();
+
+       return 0;
+}
+
+/******************************************************
+ * This is a helper routine for ni52_rnr_int() and init586().
+ * It sets up the Receive Frame Area (RFA).
+ */
+
+static void __iomem *alloc_rfa(struct net_device *dev, void __iomem *ptr)
+{
+       struct rfd_struct __iomem *rfd = ptr;
+       struct rbd_struct __iomem *rbd;
+       int i;
+       struct priv *p = netdev_priv(dev);
+
+       memset_io(rfd, 0,
+               sizeof(struct rfd_struct) * (p->num_recv_buffs + rfdadd));
+       p->rfd_first = rfd;
+
+       for (i = 0; i < (p->num_recv_buffs + rfdadd); i++) {
+               writew(make16(rfd + (i+1) % (p->num_recv_buffs+rfdadd)),
+                       &rfd[i].next);
+               writew(0xffff, &rfd[i].rbd_offset);
+       }
+       /* RU suspend */
+       writeb(RFD_SUSP, &rfd[p->num_recv_buffs-1+rfdadd].last);
+
+       ptr = rfd + (p->num_recv_buffs + rfdadd);
+
+       rbd = ptr;
+       ptr = rbd + p->num_recv_buffs;
+
+        /* clr descriptors */
+       memset_io(rbd, 0, sizeof(struct rbd_struct) * (p->num_recv_buffs));
+
+       for (i = 0; i < p->num_recv_buffs; i++) {
+               writew(make16(rbd + (i+1) % p->num_recv_buffs), &rbd[i].next);
+               writew(RECV_BUFF_SIZE, &rbd[i].size);
+               writel(make24(ptr), &rbd[i].buffer);
+               ptr = ptr + RECV_BUFF_SIZE;
+       }
+       p->rfd_top      = p->rfd_first;
+       p->rfd_last = p->rfd_first + (p->num_recv_buffs - 1 + rfdadd);
+
+       writew(make16(p->rfd_first), &p->scb->rfa_offset);
+       writew(make16(rbd), &p->rfd_first->rbd_offset);
+
+       return ptr;
+}
+
+
+/**************************************************
+ * Interrupt Handler ...
+ */
+
+static irqreturn_t ni52_interrupt(int irq, void *dev_id)
+{
+       struct net_device *dev = dev_id;
+       unsigned int stat;
+       int cnt = 0;
+       struct priv *p;
+
+       p = netdev_priv(dev);
+
+       if (debuglevel > 1)
+               printk("I");
+
+       spin_lock(&p->spinlock);
+
+       wait_for_scb_cmd(dev); /* wait for last command */
+
+       while ((stat = readb(&p->scb->cus) & STAT_MASK)) {
+               writeb(stat, &p->scb->cmd_cuc);
+               ni_attn586();
+
+               if (stat & STAT_FR)      /* received a frame */
+                       ni52_rcv_int(dev);
+
+               if (stat & STAT_RNR) { /* RU went 'not ready' */
+                       printk("(R)");
+                       if (readb(&p->scb->rus) & RU_SUSPEND) {
+                               /* special case: RU_SUSPEND */
+                               wait_for_scb_cmd(dev);
+                               writeb(RUC_RESUME, &p->scb->cmd_ruc);
+                               ni_attn586();
+                               wait_for_scb_cmd_ruc(dev);
+                       } else {
+                               printk(KERN_ERR "%s: Receiver-Unit went 'NOT READY': %04x/%02x.\n",
+                                       dev->name, stat, readb(&p->scb->rus));
+                               ni52_rnr_int(dev);
+                       }
+               }
+
+               /* Command with I-bit set complete */
+               if (stat & STAT_CX)
+                        ni52_xmt_int(dev);
+
+#ifndef NO_NOPCOMMANDS
+               if (stat & STAT_CNA) {  /* CU went 'not ready' */
+                       if (netif_running(dev))
+                               printk(KERN_ERR "%s: oops! CU has left active state. stat: %04x/%02x.\n",
+                                       dev->name, stat, readb(&p->scb->cus));
+               }
+#endif
+
+               if (debuglevel > 1)
+                       printk("%d", cnt++);
+
+               /* Wait for ack. (ni52_xmt_int can be faster than ack!!) */
+               wait_for_scb_cmd(dev);
+               if (readb(&p->scb->cmd_cuc)) {   /* timed out? */
+                       printk(KERN_ERR "%s: Acknowledge timed out.\n",
+                               dev->name);
+                       ni_disint();
+                       break;
+               }
+       }
+       spin_unlock(&p->spinlock);
+
+       if (debuglevel > 1)
+               printk("i");
+       return IRQ_HANDLED;
+}
+
+/*******************************************************
+ * receive-interrupt
+ */
+
+static void ni52_rcv_int(struct net_device *dev)
+{
+       int status, cnt = 0;
+       unsigned short totlen;
+       struct sk_buff *skb;
+       struct rbd_struct __iomem *rbd;
+       struct priv *p = netdev_priv(dev);
+
+       if (debuglevel > 0)
+               printk("R");
+
+       for (; (status = readb(&p->rfd_top->stat_high)) & RFD_COMPL;) {
+               rbd = make32(readw(&p->rfd_top->rbd_offset));
+               if (status & RFD_OK) { /* frame received without error? */
+                       totlen = readw(&rbd->status);
+                       if (totlen & RBD_LAST) {
+                               /* the first and the last buffer? */
+                               totlen &= RBD_MASK; /* length of this frame */
+                               writew(0x00, &rbd->status);
+                               skb = (struct sk_buff *)dev_alloc_skb(totlen+2);
+                               if (skb != NULL) {
+                                       skb_reserve(skb, 2);
+                                       skb_put(skb, totlen);
+                                       memcpy_fromio(skb->data, p->base + readl(&rbd->buffer), totlen);
+                                       skb->protocol = eth_type_trans(skb, dev);
+                                       netif_rx(skb);
+                                       dev->stats.rx_packets++;
+                                       dev->stats.rx_bytes += totlen;
+                               } else
+                                       dev->stats.rx_dropped++;
+                       } else {
+                               int rstat;
+                                /* free all RBD's until RBD_LAST is set */
+                               totlen = 0;
+                               while (!((rstat = readw(&rbd->status)) & RBD_LAST)) {
+                                       totlen += rstat & RBD_MASK;
+                                       if (!rstat) {
+                                               printk(KERN_ERR "%s: Whoops .. no end mark in RBD list\n", dev->name);
+                                               break;
+                                       }
+                                       writew(0, &rbd->status);
+                                       rbd = make32(readw(&rbd->next));
+                               }
+                               totlen += rstat & RBD_MASK;
+                               writew(0, &rbd->status);
+                               printk(KERN_ERR "%s: received oversized frame! length: %d\n",
+                                       dev->name, totlen);
+                               dev->stats.rx_dropped++;
+                        }
+               } else {/* frame !(ok), only with 'save-bad-frames' */
+                       printk(KERN_ERR "%s: oops! rfd-error-status: %04x\n",
+                               dev->name, status);
+                       dev->stats.rx_errors++;
+               }
+               writeb(0, &p->rfd_top->stat_high);
+               writeb(RFD_SUSP, &p->rfd_top->last); /* maybe exchange by RFD_LAST */
+               writew(0xffff, &p->rfd_top->rbd_offset);
+               writeb(0, &p->rfd_last->last);  /* delete RFD_SUSP      */
+               p->rfd_last = p->rfd_top;
+               p->rfd_top = make32(readw(&p->rfd_top->next)); /* step to next RFD */
+               writew(make16(p->rfd_top), &p->scb->rfa_offset);
+
+               if (debuglevel > 0)
+                       printk("%d", cnt++);
+       }
+
+       if (automatic_resume) {
+               wait_for_scb_cmd(dev);
+               writeb(RUC_RESUME, &p->scb->cmd_ruc);
+               ni_attn586();
+               wait_for_scb_cmd_ruc(dev);
+       }
+
+#ifdef WAIT_4_BUSY
+       {
+               int i;
+               for (i = 0; i < 1024; i++) {
+                       if (p->rfd_top->status)
+                               break;
+                       udelay(16);
+                       if (i == 1023)
+                               printk(KERN_ERR "%s: RU hasn't fetched next RFD (not busy/complete)\n", dev->name);
+               }
+       }
+#endif
+       if (debuglevel > 0)
+               printk("r");
+}
+
+/**********************************************************
+ * handle 'Receiver went not ready'.
+ */
+
+static void ni52_rnr_int(struct net_device *dev)
+{
+       struct priv *p = netdev_priv(dev);
+
+       dev->stats.rx_errors++;
+
+       wait_for_scb_cmd(dev);          /* wait for the last cmd, WAIT_4_FULLSTAT?? */
+       writeb(RUC_ABORT, &p->scb->cmd_ruc); /* usually the RU is in the 'no resource'-state .. abort it now. */
+       ni_attn586();
+       wait_for_scb_cmd_ruc(dev);              /* wait for accept cmd. */
+
+       alloc_rfa(dev, p->rfd_first);
+       /* maybe add a check here, before restarting the RU */
+       startrecv586(dev); /* restart RU */
+
+       printk(KERN_ERR "%s: Receive-Unit restarted. Status: %04x\n",
+               dev->name, readb(&p->scb->rus));
+
+}
+
+/**********************************************************
+ * handle xmit - interrupt
+ */
+
+static void ni52_xmt_int(struct net_device *dev)
+{
+       int status;
+       struct priv *p = netdev_priv(dev);
+
+       if (debuglevel > 0)
+               printk("X");
+
+       status = readw(&p->xmit_cmds[p->xmit_last]->cmd_status);
+       if (!(status & STAT_COMPL))
+               printk(KERN_ERR "%s: strange .. xmit-int without a 'COMPLETE'\n", dev->name);
+
+       if (status & STAT_OK) {
+               dev->stats.tx_packets++;
+               dev->stats.collisions += (status & TCMD_MAXCOLLMASK);
+       } else {
+               dev->stats.tx_errors++;
+               if (status & TCMD_LATECOLL) {
+                       printk(KERN_ERR "%s: late collision detected.\n",
+                               dev->name);
+                       dev->stats.collisions++;
+               } else if (status & TCMD_NOCARRIER) {
+                       dev->stats.tx_carrier_errors++;
+                       printk(KERN_ERR "%s: no carrier detected.\n",
+                               dev->name);
+               } else if (status & TCMD_LOSTCTS)
+                       printk(KERN_ERR "%s: loss of CTS detected.\n",
+                               dev->name);
+               else if (status & TCMD_UNDERRUN) {
+                       dev->stats.tx_fifo_errors++;
+                       printk(KERN_ERR "%s: DMA underrun detected.\n",
+                               dev->name);
+               } else if (status & TCMD_MAXCOLL) {
+                       printk(KERN_ERR "%s: Max. collisions exceeded.\n",
+                               dev->name);
+                       dev->stats.collisions += 16;
+               }
+       }
+#if (NUM_XMIT_BUFFS > 1)
+       if ((++p->xmit_last) == NUM_XMIT_BUFFS)
+               p->xmit_last = 0;
+#endif
+       netif_wake_queue(dev);
+}
+
+/***********************************************************
+ * (re)start the receiver
+ */
+
+static void startrecv586(struct net_device *dev)
+{
+       struct priv *p = netdev_priv(dev);
+
+       wait_for_scb_cmd(dev);
+       wait_for_scb_cmd_ruc(dev);
+       writew(make16(p->rfd_first), &p->scb->rfa_offset);
+       writeb(RUC_START, &p->scb->cmd_ruc);
+       ni_attn586();           /* start cmd. */
+       wait_for_scb_cmd_ruc(dev);
+       /* wait for accept cmd. (no timeout!!) */
+}
+
+static void ni52_timeout(struct net_device *dev)
+{
+       struct priv *p = netdev_priv(dev);
+#ifndef NO_NOPCOMMANDS
+       if (readb(&p->scb->cus) & CU_ACTIVE) { /* COMMAND-UNIT active? */
+               netif_wake_queue(dev);
+#ifdef DEBUG
+               printk(KERN_ERR "%s: strange ... timeout with CU active?!?\n",
+                       dev->name);
+               printk(KERN_ERR "%s: X0: %04x N0: %04x N1: %04x %d\n",
+                       dev->name, (int)p->xmit_cmds[0]->cmd_status,
+                       readw(&p->nop_cmds[0]->cmd_status),
+                       readw(&p->nop_cmds[1]->cmd_status),
+                       p->nop_point);
+#endif
+               writeb(CUC_ABORT, &p->scb->cmd_cuc);
+               ni_attn586();
+               wait_for_scb_cmd(dev);
+               writew(make16(p->nop_cmds[p->nop_point]), &p->scb->cbl_offset);
+               writeb(CUC_START, &p->scb->cmd_cuc);
+               ni_attn586();
+               wait_for_scb_cmd(dev);
+               dev->trans_start = jiffies; /* prevent tx timeout */
+               return 0;
+       }
+#endif
+       {
+#ifdef DEBUG
+               printk(KERN_ERR "%s: xmitter timed out, try to restart! stat: %02x\n",
+                               dev->name, readb(&p->scb->cus));
+               printk(KERN_ERR "%s: command-stats: %04x %04x\n",
+                               dev->name,
+                               readw(&p->xmit_cmds[0]->cmd_status),
+                               readw(&p->xmit_cmds[1]->cmd_status));
+               printk(KERN_ERR "%s: check, whether you set the right interrupt number!\n",
+                               dev->name);
+#endif
+               ni52_close(dev);
+               ni52_open(dev);
+       }
+       dev->trans_start = jiffies; /* prevent tx timeout */
+}
+
+/******************************************************
+ * send frame
+ */
+
+static netdev_tx_t ni52_send_packet(struct sk_buff *skb,
+                                   struct net_device *dev)
+{
+       int len, i;
+#ifndef NO_NOPCOMMANDS
+       int next_nop;
+#endif
+       struct priv *p = netdev_priv(dev);
+
+       if (skb->len > XMIT_BUFF_SIZE) {
+               printk(KERN_ERR "%s: Sorry, max. framelength is %d bytes. The length of your frame is %d bytes.\n", dev->name, XMIT_BUFF_SIZE, skb->len);
+               return NETDEV_TX_OK;
+       }
+
+       netif_stop_queue(dev);
+
+       memcpy_toio(p->xmit_cbuffs[p->xmit_count], skb->data, skb->len);
+       len = skb->len;
+       if (len < ETH_ZLEN) {
+               len = ETH_ZLEN;
+               memset_io(p->xmit_cbuffs[p->xmit_count]+skb->len, 0,
+                                                       len - skb->len);
+       }
+
+#if (NUM_XMIT_BUFFS == 1)
+#      ifdef NO_NOPCOMMANDS
+
+#ifdef DEBUG
+       if (readb(&p->scb->cus) & CU_ACTIVE) {
+               printk(KERN_ERR "%s: Hmmm .. CU is still running and we wanna send a new packet.\n", dev->name);
+               printk(KERN_ERR "%s: stat: %04x %04x\n",
+                               dev->name, readb(&p->scb->cus),
+                               readw(&p->xmit_cmds[0]->cmd_status));
+       }
+#endif
+       writew(TBD_LAST | len, &p->xmit_buffs[0]->size);
+       for (i = 0; i < 16; i++) {
+               writew(0, &p->xmit_cmds[0]->cmd_status);
+               wait_for_scb_cmd(dev);
+               if ((readb(&p->scb->cus) & CU_STATUS) == CU_SUSPEND)
+                       writeb(CUC_RESUME, &p->scb->cmd_cuc);
+               else {
+                       writew(make16(p->xmit_cmds[0]), &p->scb->cbl_offset);
+                       writeb(CUC_START, &p->scb->cmd_cuc);
+               }
+               ni_attn586();
+               if (!i)
+                       dev_kfree_skb(skb);
+               wait_for_scb_cmd(dev);
+               /* test it, because CU sometimes doesn't start immediately */
+               if (readb(&p->scb->cus) & CU_ACTIVE)
+                       break;
+               if (readw(&p->xmit_cmds[0]->cmd_status))
+                       break;
+               if (i == 15)
+                       printk(KERN_WARNING "%s: Can't start transmit-command.\n", dev->name);
+       }
+#      else
+       next_nop = (p->nop_point + 1) & 0x1;
+       writew(TBD_LAST | len, &p->xmit_buffs[0]->size);
+       writew(make16(p->nop_cmds[next_nop]), &p->xmit_cmds[0]->cmd_link);
+       writew(make16(p->nop_cmds[next_nop]),
+                               &p->nop_cmds[next_nop]->cmd_link);
+       writew(0, &p->xmit_cmds[0]->cmd_status);
+       writew(0, &p->nop_cmds[next_nop]->cmd_status);
+
+       writew(make16(p->xmit_cmds[0]), &p->nop_cmds[p->nop_point]->cmd_link);
+       p->nop_point = next_nop;
+       dev_kfree_skb(skb);
+#      endif
+#else
+       writew(TBD_LAST | len, &p->xmit_buffs[p->xmit_count]->size);
+       next_nop = p->xmit_count + 1
+       if (next_nop == NUM_XMIT_BUFFS)
+               next_nop = 0;
+       writew(0, &p->xmit_cmds[p->xmit_count]->cmd_status);
+       /* linkpointer of xmit-command already points to next nop cmd */
+       writew(make16(p->nop_cmds[next_nop]),
+                               &p->nop_cmds[next_nop]->cmd_link);
+       writew(0, &p->nop_cmds[next_nop]->cmd_status);
+       writew(make16(p->xmit_cmds[p->xmit_count]),
+                               &p->nop_cmds[p->xmit_count]->cmd_link);
+       p->xmit_count = next_nop;
+       {
+               unsigned long flags;
+               spin_lock_irqsave(&p->spinlock);
+               if (p->xmit_count != p->xmit_last)
+                       netif_wake_queue(dev);
+               spin_unlock_irqrestore(&p->spinlock);
+       }
+       dev_kfree_skb(skb);
+#endif
+       return NETDEV_TX_OK;
+}
+
+/*******************************************
+ * Someone wanna have the statistics
+ */
+
+static struct net_device_stats *ni52_get_stats(struct net_device *dev)
+{
+       struct priv *p = netdev_priv(dev);
+       unsigned short crc, aln, rsc, ovrn;
+
+       /* Get error-statistics from the ni82586 */
+       crc = readw(&p->scb->crc_errs);
+       writew(0, &p->scb->crc_errs);
+       aln = readw(&p->scb->aln_errs);
+       writew(0, &p->scb->aln_errs);
+       rsc = readw(&p->scb->rsc_errs);
+       writew(0, &p->scb->rsc_errs);
+       ovrn = readw(&p->scb->ovrn_errs);
+       writew(0, &p->scb->ovrn_errs);
+
+       dev->stats.rx_crc_errors += crc;
+       dev->stats.rx_fifo_errors += ovrn;
+       dev->stats.rx_frame_errors += aln;
+       dev->stats.rx_dropped += rsc;
+
+       return &dev->stats;
+}
+
+/********************************************************
+ * Set MC list ..
+ */
+
+static void set_multicast_list(struct net_device *dev)
+{
+       netif_stop_queue(dev);
+       ni_disint();
+       alloc586(dev);
+       init586(dev);
+       startrecv586(dev);
+       ni_enaint();
+       netif_wake_queue(dev);
+}
+
+#ifdef MODULE
+static struct net_device *dev_ni52;
+
+module_param(io, int, 0);
+module_param(irq, int, 0);
+module_param(memstart, long, 0);
+module_param(memend, long, 0);
+MODULE_PARM_DESC(io, "NI5210 I/O base address,required");
+MODULE_PARM_DESC(irq, "NI5210 IRQ number,required");
+MODULE_PARM_DESC(memstart, "NI5210 memory base address,required");
+MODULE_PARM_DESC(memend, "NI5210 memory end address,required");
+
+int __init init_module(void)
+{
+       if (io <= 0x0 || !memend || !memstart || irq < 2) {
+               printk(KERN_ERR "ni52: Autoprobing not allowed for modules.\n");
+               printk(KERN_ERR "ni52: Set symbols 'io' 'irq' 'memstart' and 'memend'\n");
+               return -ENODEV;
+       }
+       dev_ni52 = ni52_probe(-1);
+       if (IS_ERR(dev_ni52))
+               return PTR_ERR(dev_ni52);
+       return 0;
+}
+
+void __exit cleanup_module(void)
+{
+       struct priv *p = netdev_priv(dev_ni52);
+       unregister_netdev(dev_ni52);
+       iounmap(p->mapped);
+       release_region(dev_ni52->base_addr, NI52_TOTAL_SIZE);
+       free_netdev(dev_ni52);
+}
+#endif /* MODULE */
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/i825xx/ni52.h b/drivers/net/ethernet/i825xx/ni52.h
new file mode 100644 (file)
index 0000000..0a03b28
--- /dev/null
@@ -0,0 +1,310 @@
+/*
+ * Intel i82586 Ethernet definitions
+ *
+ * This is an extension to the Linux operating system, and is covered by the
+ * same GNU General Public License that covers that work.
+ *
+ * copyrights (c) 1994 by Michael Hipp (hippm@informatik.uni-tuebingen.de)
+ *
+ * I have done a look in the following sources:
+ *   crynwr-packet-driver by Russ Nelson
+ *   Garret A. Wollman's i82586-driver for BSD
+ */
+
+
+#define NI52_RESET     0  /* writing to this address, resets the i82586 */
+#define NI52_ATTENTION 1  /* channel attention, kick the 586 */
+#define NI52_TENA      3  /* 2-5 possibly wrong, Xmit enable */
+#define NI52_TDIS      2  /* Xmit disable */
+#define NI52_INTENA    5  /* Interrupt enable */
+#define NI52_INTDIS    4  /* Interrupt disable */
+#define NI52_MAGIC1    6  /* dunno exact function */
+#define NI52_MAGIC2    7  /* dunno exact function */
+
+#define NI52_MAGICVAL1 0x00  /* magic-values for ni5210 card */
+#define NI52_MAGICVAL2 0x55
+
+/*
+ * where to find the System Configuration Pointer (SCP)
+ */
+#define SCP_DEFAULT_ADDRESS 0xfffff4
+
+
+/*
+ * System Configuration Pointer Struct
+ */
+
+struct scp_struct
+{
+       u16 zero_dum0;  /* has to be zero */
+       u8 sysbus;      /* 0=16Bit,1=8Bit */
+       u8 zero_dum1;   /* has to be zero for 586 */
+       u16 zero_dum2;
+       u16 zero_dum3;
+       u32 iscp;               /* pointer to the iscp-block */
+};
+
+
+/*
+ * Intermediate System Configuration Pointer (ISCP)
+ */
+struct iscp_struct
+{
+       u8 busy;          /* 586 clears after successful init */
+       u8 zero_dummy;    /* has to be zero */
+       u16 scb_offset;    /* pointeroffset to the scb_base */
+       u32 scb_base;      /* base-address of all 16-bit offsets */
+};
+
+/*
+ * System Control Block (SCB)
+ */
+struct scb_struct
+{
+       u8 rus;
+       u8 cus;
+       u8 cmd_ruc;        /* command word: RU part */
+       u8 cmd_cuc;        /* command word: CU part & ACK */
+       u16 cbl_offset;    /* pointeroffset, command block list */
+       u16 rfa_offset;    /* pointeroffset, receive frame area */
+       u16 crc_errs;      /* CRC-Error counter */
+       u16 aln_errs;      /* alignmenterror counter */
+       u16 rsc_errs;      /* Resourceerror counter */
+       u16 ovrn_errs;     /* OVerrunerror counter */
+};
+
+/*
+ * possible command values for the command word
+ */
+#define RUC_MASK       0x0070  /* mask for RU commands */
+#define RUC_NOP                0x0000  /* NOP-command */
+#define RUC_START      0x0010  /* start RU */
+#define RUC_RESUME     0x0020  /* resume RU after suspend */
+#define RUC_SUSPEND    0x0030  /* suspend RU */
+#define RUC_ABORT      0x0040  /* abort receiver operation immediately */
+
+#define CUC_MASK        0x07  /* mask for CU command */
+#define CUC_NOP         0x00  /* NOP-command */
+#define CUC_START       0x01  /* start execution of 1. cmd on the CBL */
+#define CUC_RESUME      0x02  /* resume after suspend */
+#define CUC_SUSPEND     0x03  /* Suspend CU */
+#define CUC_ABORT       0x04  /* abort command operation immediately */
+
+#define ACK_MASK        0xf0  /* mask for ACK command */
+#define ACK_CX          0x80  /* acknowledges STAT_CX */
+#define ACK_FR          0x40  /* ack. STAT_FR */
+#define ACK_CNA         0x20  /* ack. STAT_CNA */
+#define ACK_RNR         0x10  /* ack. STAT_RNR */
+
+/*
+ * possible status values for the status word
+ */
+#define STAT_MASK       0xf0  /* mask for cause of interrupt */
+#define STAT_CX         0x80  /* CU finished cmd with its I bit set */
+#define STAT_FR         0x40  /* RU finished receiving a frame */
+#define STAT_CNA        0x20  /* CU left active state */
+#define STAT_RNR        0x10  /* RU left ready state */
+
+#define CU_STATUS       0x7   /* CU status, 0=idle */
+#define CU_SUSPEND      0x1   /* CU is suspended */
+#define CU_ACTIVE       0x2   /* CU is active */
+
+#define RU_STATUS      0x70    /* RU status, 0=idle */
+#define RU_SUSPEND     0x10    /* RU suspended */
+#define RU_NOSPACE     0x20    /* RU no resources */
+#define RU_READY       0x40    /* RU is ready */
+
+/*
+ * Receive Frame Descriptor (RFD)
+ */
+struct rfd_struct
+{
+       u8  stat_low;   /* status word */
+       u8  stat_high;  /* status word */
+       u8  rfd_sf;     /* 82596 mode only */
+       u8  last;               /* Bit15,Last Frame on List / Bit14,suspend */
+       u16 next;               /* linkoffset to next RFD */
+       u16 rbd_offset; /* pointeroffset to RBD-buffer */
+       u8  dest[6];    /* ethernet-address, destination */
+       u8  source[6];  /* ethernet-address, source */
+       u16 length;     /* 802.3 frame-length */
+       u16 zero_dummy; /* dummy */
+};
+
+#define RFD_LAST     0x80      /* last: last rfd in the list */
+#define RFD_SUSP     0x40      /* last: suspend RU after  */
+#define RFD_COMPL    0x80
+#define RFD_OK       0x20
+#define RFD_BUSY     0x40
+#define RFD_ERR_LEN  0x10     /* Length error (if enabled length-checking */
+#define RFD_ERR_CRC  0x08     /* CRC error */
+#define RFD_ERR_ALGN 0x04     /* Alignment error */
+#define RFD_ERR_RNR  0x02     /* status: receiver out of resources */
+#define RFD_ERR_OVR  0x01     /* DMA Overrun! */
+
+#define RFD_ERR_FTS  0x0080    /* Frame to short */
+#define RFD_ERR_NEOP 0x0040    /* No EOP flag (for bitstuffing only) */
+#define RFD_ERR_TRUN 0x0020    /* (82596 only/SF mode) indicates truncated frame */
+#define RFD_MATCHADD 0x0002     /* status: Destinationaddress !matches IA (only 82596) */
+#define RFD_COLLDET  0x0001    /* Detected collision during reception */
+
+/*
+ * Receive Buffer Descriptor (RBD)
+ */
+struct rbd_struct
+{
+       u16 status;     /* status word,number of used bytes in buff */
+       u16 next;               /* pointeroffset to next RBD */
+       u32 buffer;     /* receive buffer address pointer */
+       u16 size;               /* size of this buffer */
+       u16 zero_dummy;    /* dummy */
+};
+
+#define RBD_LAST       0x8000  /* last buffer */
+#define RBD_USED       0x4000  /* this buffer has data */
+#define RBD_MASK       0x3fff  /* size-mask for length */
+
+/*
+ * Statusvalues for Commands/RFD
+ */
+#define STAT_COMPL   0x8000    /* status: frame/command is complete */
+#define STAT_BUSY    0x4000    /* status: frame/command is busy */
+#define STAT_OK      0x2000    /* status: frame/command is ok */
+
+/*
+ * Action-Commands
+ */
+#define CMD_NOP                0x0000  /* NOP */
+#define CMD_IASETUP    0x0001  /* initial address setup command */
+#define CMD_CONFIGURE  0x0002  /* configure command */
+#define CMD_MCSETUP    0x0003  /* MC setup command */
+#define CMD_XMIT       0x0004  /* transmit command */
+#define CMD_TDR                0x0005  /* time domain reflectometer (TDR) command */
+#define CMD_DUMP       0x0006  /* dump command */
+#define CMD_DIAGNOSE   0x0007  /* diagnose command */
+
+/*
+ * Action command bits
+ */
+#define CMD_LAST       0x8000  /* indicates last command in the CBL */
+#define CMD_SUSPEND    0x4000  /* suspend CU after this CB */
+#define CMD_INT                0x2000  /* generate interrupt after execution */
+
+/*
+ * NOP - command
+ */
+struct nop_cmd_struct
+{
+       u16 cmd_status; /* status of this command */
+       u16 cmd_cmd;       /* the command itself (+bits) */
+       u16 cmd_link;      /* offsetpointer to next command */
+};
+
+/*
+ * IA Setup command
+ */
+struct iasetup_cmd_struct
+{
+       u16 cmd_status;
+       u16 cmd_cmd;
+       u16 cmd_link;
+       u8  iaddr[6];
+};
+
+/*
+ * Configure command
+ */
+struct configure_cmd_struct
+{
+       u16 cmd_status;
+       u16 cmd_cmd;
+       u16 cmd_link;
+       u8  byte_cnt;   /* size of the config-cmd */
+       u8  fifo;       /* fifo/recv monitor */
+       u8  sav_bf;     /* save bad frames (bit7=1)*/
+       u8  adr_len;    /* adr_len(0-2),al_loc(3),pream(4-5),loopbak(6-7)*/
+       u8  priority;   /* lin_prio(0-2),exp_prio(4-6),bof_metd(7) */
+       u8  ifs;        /* inter frame spacing */
+       u8  time_low;   /* slot time low */
+       u8  time_high;  /* slot time high(0-2) and max. retries(4-7) */
+       u8  promisc;    /* promisc-mode(0) , et al (1-7) */
+       u8  carr_coll;  /* carrier(0-3)/collision(4-7) stuff */
+       u8  fram_len;   /* minimal frame len */
+       u8  dummy;           /* dummy */
+};
+
+/*
+ * Multicast Setup command
+ */
+struct mcsetup_cmd_struct
+{
+       u16 cmd_status;
+       u16 cmd_cmd;
+       u16 cmd_link;
+       u16 mc_cnt;             /* number of bytes in the MC-List */
+       u8  mc_list[0][6];      /* pointer to 6 bytes entries */
+};
+
+/*
+ * DUMP command
+ */
+struct dump_cmd_struct
+{
+       u16 cmd_status;
+       u16 cmd_cmd;
+       u16 cmd_link;
+       u16 dump_offset;    /* pointeroffset to DUMP space */
+};
+
+/*
+ * transmit command
+ */
+struct transmit_cmd_struct
+{
+       u16 cmd_status;
+       u16 cmd_cmd;
+       u16 cmd_link;
+       u16 tbd_offset; /* pointeroffset to TBD */
+       u8  dest[6];       /* destination address of the frame */
+       u16 length;     /* user defined: 802.3 length / Ether type */
+};
+
+#define TCMD_ERRMASK     0x0fa0
+#define TCMD_MAXCOLLMASK 0x000f
+#define TCMD_MAXCOLL     0x0020
+#define TCMD_HEARTBEAT   0x0040
+#define TCMD_DEFERRED    0x0080
+#define TCMD_UNDERRUN    0x0100
+#define TCMD_LOSTCTS     0x0200
+#define TCMD_NOCARRIER   0x0400
+#define TCMD_LATECOLL    0x0800
+
+struct tdr_cmd_struct
+{
+       u16 cmd_status;
+       u16 cmd_cmd;
+       u16 cmd_link;
+       u16 status;
+};
+
+#define TDR_LNK_OK     0x8000  /* No link problem identified */
+#define TDR_XCVR_PRB   0x4000  /* indicates a transceiver problem */
+#define TDR_ET_OPN     0x2000  /* open, no correct termination */
+#define TDR_ET_SRT     0x1000  /* TDR detected a short circuit */
+#define TDR_TIMEMASK   0x07ff  /* mask for the time field */
+
+/*
+ * Transmit Buffer Descriptor (TBD)
+ */
+struct tbd_struct
+{
+       u16 size;               /* size + EOF-Flag(15) */
+       u16 next;          /* pointeroffset to next TBD */
+       u32 buffer;        /* pointer to buffer */
+};
+
+#define TBD_LAST 0x8000         /* EOF-Flag, indicates last buffer in list */
+
+
+
+
diff --git a/drivers/net/ethernet/i825xx/sni_82596.c b/drivers/net/ethernet/i825xx/sni_82596.c
new file mode 100644 (file)
index 0000000..6b2a888
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * sni_82596.c -- driver for intel 82596 ethernet controller, as
+ *               used in older SNI RM machines
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/bitops.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+
+#define SNI_82596_DRIVER_VERSION "SNI RM 82596 driver - Revision: 0.01"
+
+static const char sni_82596_string[] = "snirm_82596";
+
+#define DMA_ALLOC                      dma_alloc_coherent
+#define DMA_FREE                       dma_free_coherent
+#define DMA_WBACK(priv, addr, len)     do { } while (0)
+#define DMA_INV(priv, addr, len)       do { } while (0)
+#define DMA_WBACK_INV(priv, addr, len) do { } while (0)
+
+#define SYSBUS      0x00004400
+
+/* big endian CPU, 82596 little endian */
+#define SWAP32(x)   cpu_to_le32((u32)(x))
+#define SWAP16(x)   cpu_to_le16((u16)(x))
+
+#define OPT_MPU_16BIT    0x01
+
+#include "lib82596.c"
+
+MODULE_AUTHOR("Thomas Bogendoerfer");
+MODULE_DESCRIPTION("i82596 driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:snirm_82596");
+module_param(i596_debug, int, 0);
+MODULE_PARM_DESC(i596_debug, "82596 debug mask");
+
+static inline void ca(struct net_device *dev)
+{
+       struct i596_private *lp = netdev_priv(dev);
+
+       writel(0, lp->ca);
+}
+
+
+static void mpu_port(struct net_device *dev, int c, dma_addr_t x)
+{
+       struct i596_private *lp = netdev_priv(dev);
+
+       u32 v = (u32) (c) | (u32) (x);
+
+       if (lp->options & OPT_MPU_16BIT) {
+               writew(v & 0xffff, lp->mpu_port);
+               wmb();  /* order writes to MPU port */
+               udelay(1);
+               writew(v >> 16, lp->mpu_port);
+       } else {
+               writel(v, lp->mpu_port);
+               wmb();  /* order writes to MPU port */
+               udelay(1);
+               writel(v, lp->mpu_port);
+       }
+}
+
+
+static int __devinit sni_82596_probe(struct platform_device *dev)
+{
+       struct  net_device *netdevice;
+       struct i596_private *lp;
+       struct  resource *res, *ca, *idprom, *options;
+       int     retval = -ENOMEM;
+       void __iomem *mpu_addr;
+       void __iomem *ca_addr;
+       u8 __iomem *eth_addr;
+
+       res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+       ca = platform_get_resource(dev, IORESOURCE_MEM, 1);
+       options = platform_get_resource(dev, 0, 0);
+       idprom = platform_get_resource(dev, IORESOURCE_MEM, 2);
+       if (!res || !ca || !options || !idprom)
+               return -ENODEV;
+       mpu_addr = ioremap_nocache(res->start, 4);
+       if (!mpu_addr)
+               return -ENOMEM;
+       ca_addr = ioremap_nocache(ca->start, 4);
+       if (!ca_addr)
+               goto probe_failed_free_mpu;
+
+       printk(KERN_INFO "Found i82596 at 0x%x\n", res->start);
+
+       netdevice = alloc_etherdev(sizeof(struct i596_private));
+       if (!netdevice)
+               goto probe_failed_free_ca;
+
+       SET_NETDEV_DEV(netdevice, &dev->dev);
+       platform_set_drvdata (dev, netdevice);
+
+       netdevice->base_addr = res->start;
+       netdevice->irq = platform_get_irq(dev, 0);
+
+       eth_addr = ioremap_nocache(idprom->start, 0x10);
+       if (!eth_addr)
+               goto probe_failed;
+
+       /* someone seems to like messed up stuff */
+       netdevice->dev_addr[0] = readb(eth_addr + 0x0b);
+       netdevice->dev_addr[1] = readb(eth_addr + 0x0a);
+       netdevice->dev_addr[2] = readb(eth_addr + 0x09);
+       netdevice->dev_addr[3] = readb(eth_addr + 0x08);
+       netdevice->dev_addr[4] = readb(eth_addr + 0x07);
+       netdevice->dev_addr[5] = readb(eth_addr + 0x06);
+       iounmap(eth_addr);
+
+       if (!netdevice->irq) {
+               printk(KERN_ERR "%s: IRQ not found for i82596 at 0x%lx\n",
+                       __FILE__, netdevice->base_addr);
+               goto probe_failed;
+       }
+
+       lp = netdev_priv(netdevice);
+       lp->options = options->flags & IORESOURCE_BITS;
+       lp->ca = ca_addr;
+       lp->mpu_port = mpu_addr;
+
+       retval = i82596_probe(netdevice);
+       if (retval == 0)
+               return 0;
+
+probe_failed:
+       free_netdev(netdevice);
+probe_failed_free_ca:
+       iounmap(ca_addr);
+probe_failed_free_mpu:
+       iounmap(mpu_addr);
+       return retval;
+}
+
+static int __devexit sni_82596_driver_remove(struct platform_device *pdev)
+{
+       struct net_device *dev = platform_get_drvdata(pdev);
+       struct i596_private *lp = netdev_priv(dev);
+
+       unregister_netdev(dev);
+       DMA_FREE(dev->dev.parent, sizeof(struct i596_private),
+                lp->dma, lp->dma_addr);
+       iounmap(lp->ca);
+       iounmap(lp->mpu_port);
+       free_netdev (dev);
+       return 0;
+}
+
+static struct platform_driver sni_82596_driver = {
+       .probe  = sni_82596_probe,
+       .remove = __devexit_p(sni_82596_driver_remove),
+       .driver = {
+               .name   = sni_82596_string,
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __devinit sni_82596_init(void)
+{
+       printk(KERN_INFO SNI_82596_DRIVER_VERSION "\n");
+       return platform_driver_register(&sni_82596_driver);
+}
+
+
+static void __exit sni_82596_exit(void)
+{
+       platform_driver_unregister(&sni_82596_driver);
+}
+
+module_init(sni_82596_init);
+module_exit(sni_82596_exit);
diff --git a/drivers/net/ethernet/i825xx/sun3_82586.c b/drivers/net/ethernet/i825xx/sun3_82586.c
new file mode 100644 (file)
index 0000000..b6ae53b
--- /dev/null
@@ -0,0 +1,1213 @@
+/*
+ * Sun3 i82586 Ethernet driver
+ *
+ * Cloned from ni52.c for the Sun3 by Sam Creasey (sammy@sammy.net)
+ *
+ * Original copyright follows:
+ * --------------------------
+ *
+ * net-3-driver for the NI5210 card (i82586 Ethernet chip)
+ *
+ * This is an extension to the Linux operating system, and is covered by the
+ * same Gnu Public License that covers that work.
+ *
+ * Alphacode 0.82 (96/09/29) for Linux 2.0.0 (or later)
+ * Copyrights (c) 1994,1995,1996 by M.Hipp (hippm@informatik.uni-tuebingen.de)
+ * --------------------------
+ *
+ * Consult ni52.c for further notes from the original driver.
+ *
+ * This incarnation currently supports the OBIO version of the i82586 chip
+ * used in certain sun3 models.  It should be fairly doable to expand this
+ * to support VME if I should every acquire such a board.
+ *
+ */
+
+static int debuglevel = 0; /* debug-printk 0: off 1: a few 2: more */
+static int automatic_resume = 0; /* experimental .. better should be zero */
+static int rfdadd = 0; /* rfdadd=1 may be better for 8K MEM cards */
+static int fifo=0x8;   /* don't change */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <asm/io.h>
+#include <asm/idprom.h>
+#include <asm/machines.h>
+#include <asm/sun3mmu.h>
+#include <asm/dvma.h>
+#include <asm/byteorder.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include "sun3_82586.h"
+
+#define DRV_NAME "sun3_82586"
+
+#define DEBUG       /* debug on */
+#define SYSBUSVAL 0 /* 16 Bit */
+#define SUN3_82586_TOTAL_SIZE  PAGE_SIZE
+
+#define sun3_attn586()  {*(volatile unsigned char *)(dev->base_addr) |= IEOB_ATTEN; *(volatile unsigned char *)(dev->base_addr) &= ~IEOB_ATTEN;}
+#define sun3_reset586() {*(volatile unsigned char *)(dev->base_addr) = 0; udelay(100); *(volatile unsigned char *)(dev->base_addr) = IEOB_NORSET;}
+#define sun3_disint()   {*(volatile unsigned char *)(dev->base_addr) &= ~IEOB_IENAB;}
+#define sun3_enaint()   {*(volatile unsigned char *)(dev->base_addr) |= IEOB_IENAB;}
+#define sun3_active()   {*(volatile unsigned char *)(dev->base_addr) |= (IEOB_IENAB|IEOB_ONAIR|IEOB_NORSET);}
+
+#define make32(ptr16) (p->memtop + (swab16((unsigned short) (ptr16))) )
+#define make24(ptr32) (char *)swab32(( ((unsigned long) (ptr32)) - p->base))
+#define make16(ptr32) (swab16((unsigned short) ((unsigned long)(ptr32) - (unsigned long) p->memtop )))
+
+/******************* how to calculate the buffers *****************************
+
+  * IMPORTANT NOTE: if you configure only one NUM_XMIT_BUFFS, the driver works
+  * --------------- in a different (more stable?) mode. Only in this mode it's
+  *                 possible to configure the driver with 'NO_NOPCOMMANDS'
+
+sizeof(scp)=12; sizeof(scb)=16; sizeof(iscp)=8;
+sizeof(scp)+sizeof(iscp)+sizeof(scb) = 36 = INIT
+sizeof(rfd) = 24; sizeof(rbd) = 12;
+sizeof(tbd) = 8; sizeof(transmit_cmd) = 16;
+sizeof(nop_cmd) = 8;
+
+  * if you don't know the driver, better do not change these values: */
+
+#define RECV_BUFF_SIZE 1536 /* slightly oversized */
+#define XMIT_BUFF_SIZE 1536 /* slightly oversized */
+#define NUM_XMIT_BUFFS 1    /* config for 32K shmem */
+#define NUM_RECV_BUFFS_8 4 /* config for 32K shared mem */
+#define NUM_RECV_BUFFS_16 9 /* config for 32K shared mem */
+#define NUM_RECV_BUFFS_32 16 /* config for 32K shared mem */
+#define NO_NOPCOMMANDS      /* only possible with NUM_XMIT_BUFFS=1 */
+
+/**************************************************************************/
+
+/* different DELAYs */
+#define DELAY(x) mdelay(32 * x);
+#define DELAY_16(); { udelay(16); }
+#define DELAY_18(); { udelay(4); }
+
+/* wait for command with timeout: */
+#define WAIT_4_SCB_CMD() \
+{ int i; \
+  for(i=0;i<16384;i++) { \
+    if(!p->scb->cmd_cuc) break; \
+    DELAY_18(); \
+    if(i == 16383) { \
+      printk("%s: scb_cmd timed out: %04x,%04x .. disabling i82586!!\n",dev->name,p->scb->cmd_cuc,p->scb->cus); \
+       if(!p->reseted) { p->reseted = 1; sun3_reset586(); } } } }
+
+#define WAIT_4_SCB_CMD_RUC() { int i; \
+  for(i=0;i<16384;i++) { \
+    if(!p->scb->cmd_ruc) break; \
+    DELAY_18(); \
+    if(i == 16383) { \
+      printk("%s: scb_cmd (ruc) timed out: %04x,%04x .. disabling i82586!!\n",dev->name,p->scb->cmd_ruc,p->scb->rus); \
+       if(!p->reseted) { p->reseted = 1; sun3_reset586(); } } } }
+
+#define WAIT_4_STAT_COMPL(addr) { int i; \
+   for(i=0;i<32767;i++) { \
+     if(swab16((addr)->cmd_status) & STAT_COMPL) break; \
+     DELAY_16(); DELAY_16(); } }
+
+static int     sun3_82586_probe1(struct net_device *dev,int ioaddr);
+static irqreturn_t sun3_82586_interrupt(int irq,void *dev_id);
+static int     sun3_82586_open(struct net_device *dev);
+static int     sun3_82586_close(struct net_device *dev);
+static int     sun3_82586_send_packet(struct sk_buff *,struct net_device *);
+static struct  net_device_stats *sun3_82586_get_stats(struct net_device *dev);
+static void    set_multicast_list(struct net_device *dev);
+static void    sun3_82586_timeout(struct net_device *dev);
+#if 0
+static void    sun3_82586_dump(struct net_device *,void *);
+#endif
+
+/* helper-functions */
+static int     init586(struct net_device *dev);
+static int     check586(struct net_device *dev,char *where,unsigned size);
+static void    alloc586(struct net_device *dev);
+static void    startrecv586(struct net_device *dev);
+static void   *alloc_rfa(struct net_device *dev,void *ptr);
+static void    sun3_82586_rcv_int(struct net_device *dev);
+static void    sun3_82586_xmt_int(struct net_device *dev);
+static void    sun3_82586_rnr_int(struct net_device *dev);
+
+struct priv
+{
+       unsigned long base;
+       char *memtop;
+       long int lock;
+       int reseted;
+       volatile struct rfd_struct      *rfd_last,*rfd_top,*rfd_first;
+       volatile struct scp_struct      *scp;   /* volatile is important */
+       volatile struct iscp_struct     *iscp;  /* volatile is important */
+       volatile struct scb_struct      *scb;   /* volatile is important */
+       volatile struct tbd_struct      *xmit_buffs[NUM_XMIT_BUFFS];
+       volatile struct transmit_cmd_struct *xmit_cmds[NUM_XMIT_BUFFS];
+#if (NUM_XMIT_BUFFS == 1)
+       volatile struct nop_cmd_struct *nop_cmds[2];
+#else
+       volatile struct nop_cmd_struct *nop_cmds[NUM_XMIT_BUFFS];
+#endif
+       volatile int            nop_point,num_recv_buffs;
+       volatile char           *xmit_cbuffs[NUM_XMIT_BUFFS];
+       volatile int            xmit_count,xmit_last;
+};
+
+/**********************************************
+ * close device
+ */
+static int sun3_82586_close(struct net_device *dev)
+{
+       free_irq(dev->irq, dev);
+
+       sun3_reset586(); /* the hard way to stop the receiver */
+
+       netif_stop_queue(dev);
+
+       return 0;
+}
+
+/**********************************************
+ * open device
+ */
+static int sun3_82586_open(struct net_device *dev)
+{
+       int ret;
+
+       sun3_disint();
+       alloc586(dev);
+       init586(dev);
+       startrecv586(dev);
+       sun3_enaint();
+
+       ret = request_irq(dev->irq, sun3_82586_interrupt,0,dev->name,dev);
+       if (ret)
+       {
+               sun3_reset586();
+               return ret;
+       }
+
+       netif_start_queue(dev);
+
+       return 0; /* most done by init */
+}
+
+/**********************************************
+ * Check to see if there's an 82586 out there.
+ */
+static int check586(struct net_device *dev,char *where,unsigned size)
+{
+       struct priv pb;
+       struct priv *p = &pb;
+       char *iscp_addr;
+       int i;
+
+       p->base = (unsigned long) dvma_btov(0);
+       p->memtop = (char *)dvma_btov((unsigned long)where);
+       p->scp = (struct scp_struct *)(p->base + SCP_DEFAULT_ADDRESS);
+       memset((char *)p->scp,0, sizeof(struct scp_struct));
+       for(i=0;i<sizeof(struct scp_struct);i++) /* memory was writeable? */
+               if(((char *)p->scp)[i])
+                       return 0;
+       p->scp->sysbus = SYSBUSVAL;                             /* 1 = 8Bit-Bus, 0 = 16 Bit */
+       if(p->scp->sysbus != SYSBUSVAL)
+               return 0;
+
+       iscp_addr = (char *)dvma_btov((unsigned long)where);
+
+       p->iscp = (struct iscp_struct *) iscp_addr;
+       memset((char *)p->iscp,0, sizeof(struct iscp_struct));
+
+       p->scp->iscp = make24(p->iscp);
+       p->iscp->busy = 1;
+
+       sun3_reset586();
+       sun3_attn586();
+       DELAY(1);       /* wait a while... */
+
+       if(p->iscp->busy) /* i82586 clears 'busy' after successful init */
+               return 0;
+
+       return 1;
+}
+
+/******************************************************************
+ * set iscp at the right place, called by sun3_82586_probe1 and open586.
+ */
+static void alloc586(struct net_device *dev)
+{
+       struct priv *p = netdev_priv(dev);
+
+       sun3_reset586();
+       DELAY(1);
+
+       p->scp  = (struct scp_struct *) (p->base + SCP_DEFAULT_ADDRESS);
+       p->iscp = (struct iscp_struct *) dvma_btov(dev->mem_start);
+       p->scb  = (struct scb_struct *)  ((char *)p->iscp + sizeof(struct iscp_struct));
+
+       memset((char *) p->iscp,0,sizeof(struct iscp_struct));
+       memset((char *) p->scp ,0,sizeof(struct scp_struct));
+
+       p->scp->iscp = make24(p->iscp);
+       p->scp->sysbus = SYSBUSVAL;
+       p->iscp->scb_offset = make16(p->scb);
+       p->iscp->scb_base = make24(dvma_btov(dev->mem_start));
+
+       p->iscp->busy = 1;
+       sun3_reset586();
+       sun3_attn586();
+
+       DELAY(1);
+
+       if(p->iscp->busy)
+               printk("%s: Init-Problems (alloc).\n",dev->name);
+
+       p->reseted = 0;
+
+       memset((char *)p->scb,0,sizeof(struct scb_struct));
+}
+
+struct net_device * __init sun3_82586_probe(int unit)
+{
+       struct net_device *dev;
+       unsigned long ioaddr;
+       static int found = 0;
+       int err = -ENOMEM;
+
+       /* check that this machine has an onboard 82586 */
+       switch(idprom->id_machtype) {
+       case SM_SUN3|SM_3_160:
+       case SM_SUN3|SM_3_260:
+               /* these machines have 82586 */
+               break;
+
+       default:
+               return ERR_PTR(-ENODEV);
+       }
+
+       if (found)
+               return ERR_PTR(-ENODEV);
+
+       ioaddr = (unsigned long)ioremap(IE_OBIO, SUN3_82586_TOTAL_SIZE);
+       if (!ioaddr)
+               return ERR_PTR(-ENOMEM);
+       found = 1;
+
+       dev = alloc_etherdev(sizeof(struct priv));
+       if (!dev)
+               goto out;
+       if (unit >= 0) {
+               sprintf(dev->name, "eth%d", unit);
+               netdev_boot_setup_check(dev);
+       }
+
+       dev->irq = IE_IRQ;
+       dev->base_addr = ioaddr;
+       err = sun3_82586_probe1(dev, ioaddr);
+       if (err)
+               goto out1;
+       err = register_netdev(dev);
+       if (err)
+               goto out2;
+       return dev;
+
+out2:
+       release_region(ioaddr, SUN3_82586_TOTAL_SIZE);
+out1:
+       free_netdev(dev);
+out:
+       iounmap((void __iomem *)ioaddr);
+       return ERR_PTR(err);
+}
+
+static const struct net_device_ops sun3_82586_netdev_ops = {
+       .ndo_open               = sun3_82586_open,
+       .ndo_stop               = sun3_82586_close,
+       .ndo_start_xmit         = sun3_82586_send_packet,
+       .ndo_set_multicast_list = set_multicast_list,
+       .ndo_tx_timeout         = sun3_82586_timeout,
+       .ndo_get_stats          = sun3_82586_get_stats,
+       .ndo_validate_addr      = eth_validate_addr,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_change_mtu         = eth_change_mtu,
+};
+
+static int __init sun3_82586_probe1(struct net_device *dev,int ioaddr)
+{
+       int i, size, retval;
+
+       if (!request_region(ioaddr, SUN3_82586_TOTAL_SIZE, DRV_NAME))
+               return -EBUSY;
+
+       /* copy in the ethernet address from the prom */
+       for(i = 0; i < 6 ; i++)
+            dev->dev_addr[i] = idprom->id_ethaddr[i];
+
+       printk("%s: SUN3 Intel 82586 found at %lx, ",dev->name,dev->base_addr);
+
+       /*
+        * check (or search) IO-Memory, 32K
+        */
+       size = 0x8000;
+
+       dev->mem_start = (unsigned long)dvma_malloc_align(0x8000, 0x1000);
+       dev->mem_end = dev->mem_start + size;
+
+       if(size != 0x2000 && size != 0x4000 && size != 0x8000) {
+               printk("\n%s: Illegal memory size %d. Allowed is 0x2000 or 0x4000 or 0x8000 bytes.\n",dev->name,size);
+               retval = -ENODEV;
+               goto out;
+       }
+       if(!check586(dev,(char *) dev->mem_start,size)) {
+               printk("?memcheck, Can't find memory at 0x%lx with size %d!\n",dev->mem_start,size);
+               retval = -ENODEV;
+               goto out;
+       }
+
+       ((struct priv *)netdev_priv(dev))->memtop =
+                                       (char *)dvma_btov(dev->mem_start);
+       ((struct priv *)netdev_priv(dev))->base = (unsigned long) dvma_btov(0);
+       alloc586(dev);
+
+       /* set number of receive-buffs according to memsize */
+       if(size == 0x2000)
+               ((struct priv *)netdev_priv(dev))->num_recv_buffs =
+                                                       NUM_RECV_BUFFS_8;
+       else if(size == 0x4000)
+               ((struct priv *)netdev_priv(dev))->num_recv_buffs =
+                                                       NUM_RECV_BUFFS_16;
+       else
+               ((struct priv *)netdev_priv(dev))->num_recv_buffs =
+                                                       NUM_RECV_BUFFS_32;
+
+       printk("Memaddr: 0x%lx, Memsize: %d, IRQ %d\n",dev->mem_start,size, dev->irq);
+
+       dev->netdev_ops         = &sun3_82586_netdev_ops;
+       dev->watchdog_timeo     = HZ/20;
+
+       dev->if_port            = 0;
+       return 0;
+out:
+       release_region(ioaddr, SUN3_82586_TOTAL_SIZE);
+       return retval;
+}
+
+
+static int init586(struct net_device *dev)
+{
+       void *ptr;
+       int i,result=0;
+       struct priv *p = netdev_priv(dev);
+       volatile struct configure_cmd_struct    *cfg_cmd;
+       volatile struct iasetup_cmd_struct *ias_cmd;
+       volatile struct tdr_cmd_struct *tdr_cmd;
+       volatile struct mcsetup_cmd_struct *mc_cmd;
+       struct netdev_hw_addr *ha;
+       int num_addrs=netdev_mc_count(dev);
+
+       ptr = (void *) ((char *)p->scb + sizeof(struct scb_struct));
+
+       cfg_cmd = (struct configure_cmd_struct *)ptr; /* configure-command */
+       cfg_cmd->cmd_status     = 0;
+       cfg_cmd->cmd_cmd        = swab16(CMD_CONFIGURE | CMD_LAST);
+       cfg_cmd->cmd_link       = 0xffff;
+
+       cfg_cmd->byte_cnt       = 0x0a; /* number of cfg bytes */
+       cfg_cmd->fifo           = fifo; /* fifo-limit (8=tx:32/rx:64) */
+       cfg_cmd->sav_bf         = 0x40; /* hold or discard bad recv frames (bit 7) */
+       cfg_cmd->adr_len        = 0x2e; /* addr_len |!src_insert |pre-len |loopback */
+       cfg_cmd->priority       = 0x00;
+       cfg_cmd->ifs            = 0x60;
+       cfg_cmd->time_low       = 0x00;
+       cfg_cmd->time_high      = 0xf2;
+       cfg_cmd->promisc        = 0;
+       if(dev->flags & IFF_ALLMULTI) {
+               int len = ((char *) p->iscp - (char *) ptr - 8) / 6;
+               if(num_addrs > len)     {
+                       printk("%s: switching to promisc. mode\n",dev->name);
+                       cfg_cmd->promisc = 1;
+               }
+       }
+       if(dev->flags&IFF_PROMISC)
+               cfg_cmd->promisc = 1;
+       cfg_cmd->carr_coll      = 0x00;
+
+       p->scb->cbl_offset      = make16(cfg_cmd);
+       p->scb->cmd_ruc         = 0;
+
+       p->scb->cmd_cuc         = CUC_START; /* cmd.-unit start */
+       sun3_attn586();
+
+       WAIT_4_STAT_COMPL(cfg_cmd);
+
+       if((swab16(cfg_cmd->cmd_status) & (STAT_OK|STAT_COMPL)) != (STAT_COMPL|STAT_OK))
+       {
+               printk("%s: configure command failed: %x\n",dev->name,swab16(cfg_cmd->cmd_status));
+               return 1;
+       }
+
+       /*
+        * individual address setup
+        */
+
+       ias_cmd = (struct iasetup_cmd_struct *)ptr;
+
+       ias_cmd->cmd_status     = 0;
+       ias_cmd->cmd_cmd        = swab16(CMD_IASETUP | CMD_LAST);
+       ias_cmd->cmd_link       = 0xffff;
+
+       memcpy((char *)&ias_cmd->iaddr,(char *) dev->dev_addr,ETH_ALEN);
+
+       p->scb->cbl_offset = make16(ias_cmd);
+
+       p->scb->cmd_cuc = CUC_START; /* cmd.-unit start */
+       sun3_attn586();
+
+       WAIT_4_STAT_COMPL(ias_cmd);
+
+       if((swab16(ias_cmd->cmd_status) & (STAT_OK|STAT_COMPL)) != (STAT_OK|STAT_COMPL)) {
+               printk("%s (82586): individual address setup command failed: %04x\n",dev->name,swab16(ias_cmd->cmd_status));
+               return 1;
+       }
+
+       /*
+        * TDR, wire check .. e.g. no resistor e.t.c
+        */
+
+       tdr_cmd = (struct tdr_cmd_struct *)ptr;
+
+       tdr_cmd->cmd_status     = 0;
+       tdr_cmd->cmd_cmd        = swab16(CMD_TDR | CMD_LAST);
+       tdr_cmd->cmd_link       = 0xffff;
+       tdr_cmd->status         = 0;
+
+       p->scb->cbl_offset = make16(tdr_cmd);
+       p->scb->cmd_cuc = CUC_START; /* cmd.-unit start */
+       sun3_attn586();
+
+       WAIT_4_STAT_COMPL(tdr_cmd);
+
+       if(!(swab16(tdr_cmd->cmd_status) & STAT_COMPL))
+       {
+               printk("%s: Problems while running the TDR.\n",dev->name);
+       }
+       else
+       {
+               DELAY_16(); /* wait for result */
+               result = swab16(tdr_cmd->status);
+
+               p->scb->cmd_cuc = p->scb->cus & STAT_MASK;
+               sun3_attn586(); /* ack the interrupts */
+
+               if(result & TDR_LNK_OK)
+                       ;
+               else if(result & TDR_XCVR_PRB)
+                       printk("%s: TDR: Transceiver problem. Check the cable(s)!\n",dev->name);
+               else if(result & TDR_ET_OPN)
+                       printk("%s: TDR: No correct termination %d clocks away.\n",dev->name,result & TDR_TIMEMASK);
+               else if(result & TDR_ET_SRT)
+               {
+                       if (result & TDR_TIMEMASK) /* time == 0 -> strange :-) */
+                               printk("%s: TDR: Detected a short circuit %d clocks away.\n",dev->name,result & TDR_TIMEMASK);
+               }
+               else
+                       printk("%s: TDR: Unknown status %04x\n",dev->name,result);
+       }
+
+       /*
+        * Multicast setup
+        */
+       if(num_addrs && !(dev->flags & IFF_PROMISC) )
+       {
+               mc_cmd = (struct mcsetup_cmd_struct *) ptr;
+               mc_cmd->cmd_status = 0;
+               mc_cmd->cmd_cmd = swab16(CMD_MCSETUP | CMD_LAST);
+               mc_cmd->cmd_link = 0xffff;
+               mc_cmd->mc_cnt = swab16(num_addrs * 6);
+
+               i = 0;
+               netdev_for_each_mc_addr(ha, dev)
+                       memcpy((char *) mc_cmd->mc_list[i++],
+                              ha->addr, ETH_ALEN);
+
+               p->scb->cbl_offset = make16(mc_cmd);
+               p->scb->cmd_cuc = CUC_START;
+               sun3_attn586();
+
+               WAIT_4_STAT_COMPL(mc_cmd);
+
+               if( (swab16(mc_cmd->cmd_status) & (STAT_COMPL|STAT_OK)) != (STAT_COMPL|STAT_OK) )
+                       printk("%s: Can't apply multicast-address-list.\n",dev->name);
+       }
+
+       /*
+        * alloc nop/xmit-cmds
+        */
+#if (NUM_XMIT_BUFFS == 1)
+       for(i=0;i<2;i++)
+       {
+               p->nop_cmds[i]                  = (struct nop_cmd_struct *)ptr;
+               p->nop_cmds[i]->cmd_cmd         = swab16(CMD_NOP);
+               p->nop_cmds[i]->cmd_status      = 0;
+               p->nop_cmds[i]->cmd_link        = make16((p->nop_cmds[i]));
+               ptr = (char *) ptr + sizeof(struct nop_cmd_struct);
+       }
+#else
+       for(i=0;i<NUM_XMIT_BUFFS;i++)
+       {
+               p->nop_cmds[i]                  = (struct nop_cmd_struct *)ptr;
+               p->nop_cmds[i]->cmd_cmd         = swab16(CMD_NOP);
+               p->nop_cmds[i]->cmd_status      = 0;
+               p->nop_cmds[i]->cmd_link        = make16((p->nop_cmds[i]));
+               ptr = (char *) ptr + sizeof(struct nop_cmd_struct);
+       }
+#endif
+
+       ptr = alloc_rfa(dev,(void *)ptr); /* init receive-frame-area */
+
+       /*
+        * alloc xmit-buffs / init xmit_cmds
+        */
+       for(i=0;i<NUM_XMIT_BUFFS;i++)
+       {
+               p->xmit_cmds[i] = (struct transmit_cmd_struct *)ptr; /*transmit cmd/buff 0*/
+               ptr = (char *) ptr + sizeof(struct transmit_cmd_struct);
+               p->xmit_cbuffs[i] = (char *)ptr; /* char-buffs */
+               ptr = (char *) ptr + XMIT_BUFF_SIZE;
+               p->xmit_buffs[i] = (struct tbd_struct *)ptr; /* TBD */
+               ptr = (char *) ptr + sizeof(struct tbd_struct);
+               if((void *)ptr > (void *)dev->mem_end)
+               {
+                       printk("%s: not enough shared-mem for your configuration!\n",dev->name);
+                       return 1;
+               }
+               memset((char *)(p->xmit_cmds[i]) ,0, sizeof(struct transmit_cmd_struct));
+               memset((char *)(p->xmit_buffs[i]),0, sizeof(struct tbd_struct));
+               p->xmit_cmds[i]->cmd_link = make16(p->nop_cmds[(i+1)%NUM_XMIT_BUFFS]);
+               p->xmit_cmds[i]->cmd_status = swab16(STAT_COMPL);
+               p->xmit_cmds[i]->cmd_cmd = swab16(CMD_XMIT | CMD_INT);
+               p->xmit_cmds[i]->tbd_offset = make16((p->xmit_buffs[i]));
+               p->xmit_buffs[i]->next = 0xffff;
+               p->xmit_buffs[i]->buffer = make24((p->xmit_cbuffs[i]));
+       }
+
+       p->xmit_count = 0;
+       p->xmit_last    = 0;
+#ifndef NO_NOPCOMMANDS
+       p->nop_point    = 0;
+#endif
+
+        /*
+               * 'start transmitter'
+               */
+#ifndef NO_NOPCOMMANDS
+       p->scb->cbl_offset = make16(p->nop_cmds[0]);
+       p->scb->cmd_cuc = CUC_START;
+       sun3_attn586();
+       WAIT_4_SCB_CMD();
+#else
+       p->xmit_cmds[0]->cmd_link = make16(p->xmit_cmds[0]);
+       p->xmit_cmds[0]->cmd_cmd        = swab16(CMD_XMIT | CMD_SUSPEND | CMD_INT);
+#endif
+
+       /*
+        * ack. interrupts
+        */
+       p->scb->cmd_cuc = p->scb->cus & STAT_MASK;
+       sun3_attn586();
+       DELAY_16();
+
+       sun3_enaint();
+       sun3_active();
+
+       return 0;
+}
+
+/******************************************************
+ * This is a helper routine for sun3_82586_rnr_int() and init586().
+ * It sets up the Receive Frame Area (RFA).
+ */
+
+static void *alloc_rfa(struct net_device *dev,void *ptr)
+{
+       volatile struct rfd_struct *rfd = (struct rfd_struct *)ptr;
+       volatile struct rbd_struct *rbd;
+       int i;
+       struct priv *p = netdev_priv(dev);
+
+       memset((char *) rfd,0,sizeof(struct rfd_struct)*(p->num_recv_buffs+rfdadd));
+       p->rfd_first = rfd;
+
+       for(i = 0; i < (p->num_recv_buffs+rfdadd); i++) {
+               rfd[i].next = make16(rfd + (i+1) % (p->num_recv_buffs+rfdadd) );
+               rfd[i].rbd_offset = 0xffff;
+       }
+       rfd[p->num_recv_buffs-1+rfdadd].last = RFD_SUSP;         /* RU suspend */
+
+       ptr = (void *) (rfd + (p->num_recv_buffs + rfdadd) );
+
+       rbd = (struct rbd_struct *) ptr;
+       ptr = (void *) (rbd + p->num_recv_buffs);
+
+        /* clr descriptors */
+       memset((char *) rbd,0,sizeof(struct rbd_struct)*(p->num_recv_buffs));
+
+       for(i=0;i<p->num_recv_buffs;i++)
+       {
+               rbd[i].next = make16((rbd + (i+1) % p->num_recv_buffs));
+               rbd[i].size = swab16(RECV_BUFF_SIZE);
+               rbd[i].buffer = make24(ptr);
+               ptr = (char *) ptr + RECV_BUFF_SIZE;
+       }
+
+       p->rfd_top      = p->rfd_first;
+       p->rfd_last = p->rfd_first + (p->num_recv_buffs - 1 + rfdadd);
+
+       p->scb->rfa_offset              = make16(p->rfd_first);
+       p->rfd_first->rbd_offset        = make16(rbd);
+
+       return ptr;
+}
+
+
+/**************************************************
+ * Interrupt Handler ...
+ */
+
+static irqreturn_t sun3_82586_interrupt(int irq,void *dev_id)
+{
+       struct net_device *dev = dev_id;
+       unsigned short stat;
+       int cnt=0;
+       struct priv *p;
+
+       if (!dev) {
+               printk ("sun3_82586-interrupt: irq %d for unknown device.\n",irq);
+               return IRQ_NONE;
+       }
+       p = netdev_priv(dev);
+
+       if(debuglevel > 1)
+               printk("I");
+
+       WAIT_4_SCB_CMD(); /* wait for last command      */
+
+       while((stat=p->scb->cus & STAT_MASK))
+       {
+               p->scb->cmd_cuc = stat;
+               sun3_attn586();
+
+               if(stat & STAT_FR)       /* received a frame */
+                       sun3_82586_rcv_int(dev);
+
+               if(stat & STAT_RNR) /* RU went 'not ready' */
+               {
+                       printk("(R)");
+                       if(p->scb->rus & RU_SUSPEND) /* special case: RU_SUSPEND */
+                       {
+                               WAIT_4_SCB_CMD();
+                               p->scb->cmd_ruc = RUC_RESUME;
+                               sun3_attn586();
+                               WAIT_4_SCB_CMD_RUC();
+                       }
+                       else
+                       {
+                               printk("%s: Receiver-Unit went 'NOT READY': %04x/%02x.\n",dev->name,(int) stat,(int) p->scb->rus);
+                               sun3_82586_rnr_int(dev);
+                       }
+               }
+
+               if(stat & STAT_CX)              /* command with I-bit set complete */
+                        sun3_82586_xmt_int(dev);
+
+#ifndef NO_NOPCOMMANDS
+               if(stat & STAT_CNA)     /* CU went 'not ready' */
+               {
+                       if(netif_running(dev))
+                               printk("%s: oops! CU has left active state. stat: %04x/%02x.\n",dev->name,(int) stat,(int) p->scb->cus);
+               }
+#endif
+
+               if(debuglevel > 1)
+                       printk("%d",cnt++);
+
+               WAIT_4_SCB_CMD(); /* wait for ack. (sun3_82586_xmt_int can be faster than ack!!) */
+               if(p->scb->cmd_cuc)      /* timed out? */
+               {
+                       printk("%s: Acknowledge timed out.\n",dev->name);
+                       sun3_disint();
+                       break;
+               }
+       }
+
+       if(debuglevel > 1)
+               printk("i");
+       return IRQ_HANDLED;
+}
+
+/*******************************************************
+ * receive-interrupt
+ */
+
+static void sun3_82586_rcv_int(struct net_device *dev)
+{
+       int status,cnt=0;
+       unsigned short totlen;
+       struct sk_buff *skb;
+       struct rbd_struct *rbd;
+       struct priv *p = netdev_priv(dev);
+
+       if(debuglevel > 0)
+               printk("R");
+
+       for(;(status = p->rfd_top->stat_high) & RFD_COMPL;)
+       {
+                       rbd = (struct rbd_struct *) make32(p->rfd_top->rbd_offset);
+
+                       if(status & RFD_OK) /* frame received without error? */
+                       {
+                               if( (totlen = swab16(rbd->status)) & RBD_LAST) /* the first and the last buffer? */
+                               {
+                                       totlen &= RBD_MASK; /* length of this frame */
+                                       rbd->status = 0;
+                                       skb = (struct sk_buff *) dev_alloc_skb(totlen+2);
+                                       if(skb != NULL)
+                                       {
+                                               skb_reserve(skb,2);
+                                               skb_put(skb,totlen);
+                                               skb_copy_to_linear_data(skb,(char *) p->base+swab32((unsigned long) rbd->buffer),totlen);
+                                               skb->protocol=eth_type_trans(skb,dev);
+                                               netif_rx(skb);
+                                               dev->stats.rx_packets++;
+                                       }
+                                       else
+                                               dev->stats.rx_dropped++;
+                               }
+                               else
+                               {
+                                       int rstat;
+                                                /* free all RBD's until RBD_LAST is set */
+                                       totlen = 0;
+                                       while(!((rstat=swab16(rbd->status)) & RBD_LAST))
+                                       {
+                                               totlen += rstat & RBD_MASK;
+                                               if(!rstat)
+                                               {
+                                                       printk("%s: Whoops .. no end mark in RBD list\n",dev->name);
+                                                       break;
+                                               }
+                                               rbd->status = 0;
+                                               rbd = (struct rbd_struct *) make32(rbd->next);
+                                       }
+                                       totlen += rstat & RBD_MASK;
+                                       rbd->status = 0;
+                                       printk("%s: received oversized frame! length: %d\n",dev->name,totlen);
+                                       dev->stats.rx_dropped++;
+                        }
+               }
+               else /* frame !(ok), only with 'save-bad-frames' */
+               {
+                       printk("%s: oops! rfd-error-status: %04x\n",dev->name,status);
+                       dev->stats.rx_errors++;
+               }
+               p->rfd_top->stat_high = 0;
+               p->rfd_top->last = RFD_SUSP; /* maybe exchange by RFD_LAST */
+               p->rfd_top->rbd_offset = 0xffff;
+               p->rfd_last->last = 0;                          /* delete RFD_SUSP      */
+               p->rfd_last = p->rfd_top;
+               p->rfd_top = (struct rfd_struct *) make32(p->rfd_top->next); /* step to next RFD */
+               p->scb->rfa_offset = make16(p->rfd_top);
+
+               if(debuglevel > 0)
+                       printk("%d",cnt++);
+       }
+
+       if(automatic_resume)
+       {
+               WAIT_4_SCB_CMD();
+               p->scb->cmd_ruc = RUC_RESUME;
+               sun3_attn586();
+               WAIT_4_SCB_CMD_RUC();
+       }
+
+#ifdef WAIT_4_BUSY
+       {
+               int i;
+               for(i=0;i<1024;i++)
+               {
+                       if(p->rfd_top->status)
+                               break;
+                       DELAY_16();
+                       if(i == 1023)
+                               printk("%s: RU hasn't fetched next RFD (not busy/complete)\n",dev->name);
+               }
+       }
+#endif
+
+#if 0
+       if(!at_least_one)
+       {
+               int i;
+               volatile struct rfd_struct *rfds=p->rfd_top;
+               volatile struct rbd_struct *rbds;
+               printk("%s: received a FC intr. without having a frame: %04x %d\n",dev->name,status,old_at_least);
+               for(i=0;i< (p->num_recv_buffs+4);i++)
+               {
+                       rbds = (struct rbd_struct *) make32(rfds->rbd_offset);
+                       printk("%04x:%04x ",rfds->status,rbds->status);
+                       rfds = (struct rfd_struct *) make32(rfds->next);
+               }
+               printk("\nerrs: %04x %04x stat: %04x\n",(int)p->scb->rsc_errs,(int)p->scb->ovrn_errs,(int)p->scb->status);
+               printk("\nerrs: %04x %04x rus: %02x, cus: %02x\n",(int)p->scb->rsc_errs,(int)p->scb->ovrn_errs,(int)p->scb->rus,(int)p->scb->cus);
+       }
+       old_at_least = at_least_one;
+#endif
+
+       if(debuglevel > 0)
+               printk("r");
+}
+
+/**********************************************************
+ * handle 'Receiver went not ready'.
+ */
+
+static void sun3_82586_rnr_int(struct net_device *dev)
+{
+       struct priv *p = netdev_priv(dev);
+
+       dev->stats.rx_errors++;
+
+       WAIT_4_SCB_CMD();               /* wait for the last cmd, WAIT_4_FULLSTAT?? */
+       p->scb->cmd_ruc = RUC_ABORT; /* usually the RU is in the 'no resource'-state .. abort it now. */
+       sun3_attn586();
+       WAIT_4_SCB_CMD_RUC();           /* wait for accept cmd. */
+
+       alloc_rfa(dev,(char *)p->rfd_first);
+/* maybe add a check here, before restarting the RU */
+       startrecv586(dev); /* restart RU */
+
+       printk("%s: Receive-Unit restarted. Status: %04x\n",dev->name,p->scb->rus);
+
+}
+
+/**********************************************************
+ * handle xmit - interrupt
+ */
+
+static void sun3_82586_xmt_int(struct net_device *dev)
+{
+       int status;
+       struct priv *p = netdev_priv(dev);
+
+       if(debuglevel > 0)
+               printk("X");
+
+       status = swab16(p->xmit_cmds[p->xmit_last]->cmd_status);
+       if(!(status & STAT_COMPL))
+               printk("%s: strange .. xmit-int without a 'COMPLETE'\n",dev->name);
+
+       if(status & STAT_OK)
+       {
+               dev->stats.tx_packets++;
+               dev->stats.collisions += (status & TCMD_MAXCOLLMASK);
+       }
+       else
+       {
+               dev->stats.tx_errors++;
+               if(status & TCMD_LATECOLL) {
+                       printk("%s: late collision detected.\n",dev->name);
+                       dev->stats.collisions++;
+               }
+               else if(status & TCMD_NOCARRIER) {
+                       dev->stats.tx_carrier_errors++;
+                       printk("%s: no carrier detected.\n",dev->name);
+               }
+               else if(status & TCMD_LOSTCTS)
+                       printk("%s: loss of CTS detected.\n",dev->name);
+               else if(status & TCMD_UNDERRUN) {
+                       dev->stats.tx_fifo_errors++;
+                       printk("%s: DMA underrun detected.\n",dev->name);
+               }
+               else if(status & TCMD_MAXCOLL) {
+                       printk("%s: Max. collisions exceeded.\n",dev->name);
+                       dev->stats.collisions += 16;
+               }
+       }
+
+#if (NUM_XMIT_BUFFS > 1)
+       if( (++p->xmit_last) == NUM_XMIT_BUFFS)
+               p->xmit_last = 0;
+#endif
+       netif_wake_queue(dev);
+}
+
+/***********************************************************
+ * (re)start the receiver
+ */
+
+static void startrecv586(struct net_device *dev)
+{
+       struct priv *p = netdev_priv(dev);
+
+       WAIT_4_SCB_CMD();
+       WAIT_4_SCB_CMD_RUC();
+       p->scb->rfa_offset = make16(p->rfd_first);
+       p->scb->cmd_ruc = RUC_START;
+       sun3_attn586();         /* start cmd. */
+       WAIT_4_SCB_CMD_RUC();   /* wait for accept cmd. (no timeout!!) */
+}
+
+static void sun3_82586_timeout(struct net_device *dev)
+{
+       struct priv *p = netdev_priv(dev);
+#ifndef NO_NOPCOMMANDS
+       if(p->scb->cus & CU_ACTIVE) /* COMMAND-UNIT active? */
+       {
+               netif_wake_queue(dev);
+#ifdef DEBUG
+               printk("%s: strange ... timeout with CU active?!?\n",dev->name);
+               printk("%s: X0: %04x N0: %04x N1: %04x %d\n",dev->name,(int)swab16(p->xmit_cmds[0]->cmd_status),(int)swab16(p->nop_cmds[0]->cmd_status),(int)swab16(p->nop_cmds[1]->cmd_status),(int)p->nop_point);
+#endif
+               p->scb->cmd_cuc = CUC_ABORT;
+               sun3_attn586();
+               WAIT_4_SCB_CMD();
+               p->scb->cbl_offset = make16(p->nop_cmds[p->nop_point]);
+               p->scb->cmd_cuc = CUC_START;
+               sun3_attn586();
+               WAIT_4_SCB_CMD();
+               dev->trans_start = jiffies; /* prevent tx timeout */
+               return 0;
+       }
+#endif
+       {
+#ifdef DEBUG
+               printk("%s: xmitter timed out, try to restart! stat: %02x\n",dev->name,p->scb->cus);
+               printk("%s: command-stats: %04x %04x\n",dev->name,swab16(p->xmit_cmds[0]->cmd_status),swab16(p->xmit_cmds[1]->cmd_status));
+               printk("%s: check, whether you set the right interrupt number!\n",dev->name);
+#endif
+               sun3_82586_close(dev);
+               sun3_82586_open(dev);
+       }
+       dev->trans_start = jiffies; /* prevent tx timeout */
+}
+
+/******************************************************
+ * send frame
+ */
+
+static int sun3_82586_send_packet(struct sk_buff *skb, struct net_device *dev)
+{
+       int len,i;
+#ifndef NO_NOPCOMMANDS
+       int next_nop;
+#endif
+       struct priv *p = netdev_priv(dev);
+
+       if(skb->len > XMIT_BUFF_SIZE)
+       {
+               printk("%s: Sorry, max. framelength is %d bytes. The length of your frame is %d bytes.\n",dev->name,XMIT_BUFF_SIZE,skb->len);
+               return NETDEV_TX_OK;
+       }
+
+       netif_stop_queue(dev);
+
+#if(NUM_XMIT_BUFFS > 1)
+       if(test_and_set_bit(0,(void *) &p->lock)) {
+               printk("%s: Queue was locked\n",dev->name);
+               return NETDEV_TX_BUSY;
+       }
+       else
+#endif
+       {
+               len = skb->len;
+               if (len < ETH_ZLEN) {
+                       memset((void *)p->xmit_cbuffs[p->xmit_count], 0,
+                              ETH_ZLEN);
+                       len = ETH_ZLEN;
+               }
+               skb_copy_from_linear_data(skb, (void *)p->xmit_cbuffs[p->xmit_count], skb->len);
+
+#if (NUM_XMIT_BUFFS == 1)
+#      ifdef NO_NOPCOMMANDS
+
+#ifdef DEBUG
+               if(p->scb->cus & CU_ACTIVE)
+               {
+                       printk("%s: Hmmm .. CU is still running and we wanna send a new packet.\n",dev->name);
+                       printk("%s: stat: %04x %04x\n",dev->name,p->scb->cus,swab16(p->xmit_cmds[0]->cmd_status));
+               }
+#endif
+
+               p->xmit_buffs[0]->size = swab16(TBD_LAST | len);
+               for(i=0;i<16;i++)
+               {
+                       p->xmit_cmds[0]->cmd_status = 0;
+                       WAIT_4_SCB_CMD();
+                       if( (p->scb->cus & CU_STATUS) == CU_SUSPEND)
+                               p->scb->cmd_cuc = CUC_RESUME;
+                       else
+                       {
+                               p->scb->cbl_offset = make16(p->xmit_cmds[0]);
+                               p->scb->cmd_cuc = CUC_START;
+                       }
+
+                       sun3_attn586();
+                       if(!i)
+                               dev_kfree_skb(skb);
+                       WAIT_4_SCB_CMD();
+                       if( (p->scb->cus & CU_ACTIVE)) /* test it, because CU sometimes doesn't start immediately */
+                               break;
+                       if(p->xmit_cmds[0]->cmd_status)
+                               break;
+                       if(i==15)
+                               printk("%s: Can't start transmit-command.\n",dev->name);
+               }
+#      else
+               next_nop = (p->nop_point + 1) & 0x1;
+               p->xmit_buffs[0]->size = swab16(TBD_LAST | len);
+
+               p->xmit_cmds[0]->cmd_link        = p->nop_cmds[next_nop]->cmd_link
+                       = make16((p->nop_cmds[next_nop]));
+               p->xmit_cmds[0]->cmd_status = p->nop_cmds[next_nop]->cmd_status = 0;
+
+               p->nop_cmds[p->nop_point]->cmd_link = make16((p->xmit_cmds[0]));
+               p->nop_point = next_nop;
+               dev_kfree_skb(skb);
+#      endif
+#else
+               p->xmit_buffs[p->xmit_count]->size = swab16(TBD_LAST | len);
+               if( (next_nop = p->xmit_count + 1) == NUM_XMIT_BUFFS )
+                       next_nop = 0;
+
+               p->xmit_cmds[p->xmit_count]->cmd_status = 0;
+               /* linkpointer of xmit-command already points to next nop cmd */
+               p->nop_cmds[next_nop]->cmd_link = make16((p->nop_cmds[next_nop]));
+               p->nop_cmds[next_nop]->cmd_status = 0;
+
+               p->nop_cmds[p->xmit_count]->cmd_link = make16((p->xmit_cmds[p->xmit_count]));
+               p->xmit_count = next_nop;
+
+               {
+                       unsigned long flags;
+                       local_irq_save(flags);
+                       if(p->xmit_count != p->xmit_last)
+                               netif_wake_queue(dev);
+                       p->lock = 0;
+                       local_irq_restore(flags);
+               }
+               dev_kfree_skb(skb);
+#endif
+       }
+       return NETDEV_TX_OK;
+}
+
+/*******************************************
+ * Someone wanna have the statistics
+ */
+
+static struct net_device_stats *sun3_82586_get_stats(struct net_device *dev)
+{
+       struct priv *p = netdev_priv(dev);
+       unsigned short crc,aln,rsc,ovrn;
+
+       crc = swab16(p->scb->crc_errs); /* get error-statistic from the ni82586 */
+       p->scb->crc_errs = 0;
+       aln = swab16(p->scb->aln_errs);
+       p->scb->aln_errs = 0;
+       rsc = swab16(p->scb->rsc_errs);
+       p->scb->rsc_errs = 0;
+       ovrn = swab16(p->scb->ovrn_errs);
+       p->scb->ovrn_errs = 0;
+
+       dev->stats.rx_crc_errors += crc;
+       dev->stats.rx_fifo_errors += ovrn;
+       dev->stats.rx_frame_errors += aln;
+       dev->stats.rx_dropped += rsc;
+
+       return &dev->stats;
+}
+
+/********************************************************
+ * Set MC list ..
+ */
+
+static void set_multicast_list(struct net_device *dev)
+{
+       netif_stop_queue(dev);
+       sun3_disint();
+       alloc586(dev);
+       init586(dev);
+       startrecv586(dev);
+       sun3_enaint();
+       netif_wake_queue(dev);
+}
+
+#ifdef MODULE
+#error This code is not currently supported as a module
+static struct net_device *dev_sun3_82586;
+
+int init_module(void)
+{
+       dev_sun3_82586 = sun3_82586_probe(-1);
+       if (IS_ERR(dev_sun3_82586))
+               return PTR_ERR(dev_sun3_82586);
+       return 0;
+}
+
+void cleanup_module(void)
+{
+       unsigned long ioaddr = dev_sun3_82586->base_addr;
+       unregister_netdev(dev_sun3_82586);
+       release_region(ioaddr, SUN3_82586_TOTAL_SIZE);
+       iounmap((void *)ioaddr);
+       free_netdev(dev_sun3_82586);
+}
+#endif /* MODULE */
+
+#if 0
+/*
+ * DUMP .. we expect a not running CMD unit and enough space
+ */
+void sun3_82586_dump(struct net_device *dev,void *ptr)
+{
+       struct priv *p = netdev_priv(dev);
+       struct dump_cmd_struct *dump_cmd = (struct dump_cmd_struct *) ptr;
+       int i;
+
+       p->scb->cmd_cuc = CUC_ABORT;
+       sun3_attn586();
+       WAIT_4_SCB_CMD();
+       WAIT_4_SCB_CMD_RUC();
+
+       dump_cmd->cmd_status = 0;
+       dump_cmd->cmd_cmd = CMD_DUMP | CMD_LAST;
+       dump_cmd->dump_offset = make16((dump_cmd + 1));
+       dump_cmd->cmd_link = 0xffff;
+
+       p->scb->cbl_offset = make16(dump_cmd);
+       p->scb->cmd_cuc = CUC_START;
+       sun3_attn586();
+       WAIT_4_STAT_COMPL(dump_cmd);
+
+       if( (dump_cmd->cmd_status & (STAT_COMPL|STAT_OK)) != (STAT_COMPL|STAT_OK) )
+                               printk("%s: Can't get dump information.\n",dev->name);
+
+       for(i=0;i<170;i++) {
+               printk("%02x ",(int) ((unsigned char *) (dump_cmd + 1))[i]);
+               if(i % 24 == 23)
+                       printk("\n");
+       }
+       printk("\n");
+}
+#endif
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/i825xx/sun3_82586.h b/drivers/net/ethernet/i825xx/sun3_82586.h
new file mode 100644 (file)
index 0000000..93346f0
--- /dev/null
@@ -0,0 +1,318 @@
+/*
+ * Intel i82586 Ethernet definitions
+ *
+ * This is an extension to the Linux operating system, and is covered by the
+ * same Gnu Public License that covers that work.
+ *
+ * copyrights (c) 1994 by Michael Hipp (hippm@informatik.uni-tuebingen.de)
+ *
+ * I have done a look in the following sources:
+ *   crynwr-packet-driver by Russ Nelson
+ *   Garret A. Wollman's i82586-driver for BSD
+ */
+
+/*
+ * Cloned from ni52.h, copyright as above.
+ *
+ * Modified for Sun3 OBIO i82586 by Sam Creasey (sammy@sammy.net)
+ */
+
+
+/* defines for the obio chip (not vme) */
+#define IEOB_NORSET 0x80        /* don't reset the board */
+#define IEOB_ONAIR  0x40        /* put us on the air */
+#define IEOB_ATTEN  0x20        /* attention! */
+#define IEOB_IENAB  0x10        /* interrupt enable */
+#define IEOB_XXXXX  0x08        /* free bit */
+#define IEOB_XCVRL2 0x04        /* level 2 transceiver? */
+#define IEOB_BUSERR 0x02        /* bus error */
+#define IEOB_INT    0x01        /* interrupt */
+
+/* where the obio one lives */
+#define IE_OBIO 0xc0000
+#define IE_IRQ 3
+
+/*
+ * where to find the System Configuration Pointer (SCP)
+ */
+#define SCP_DEFAULT_ADDRESS 0xfffff4
+
+
+/*
+ * System Configuration Pointer Struct
+ */
+
+struct scp_struct
+{
+  unsigned short zero_dum0;    /* has to be zero */
+  unsigned char  sysbus;       /* 0=16Bit,1=8Bit */
+  unsigned char  zero_dum1;    /* has to be zero for 586 */
+  unsigned short zero_dum2;
+  unsigned short zero_dum3;
+  char          *iscp;         /* pointer to the iscp-block */
+};
+
+
+/*
+ * Intermediate System Configuration Pointer (ISCP)
+ */
+struct iscp_struct
+{
+  unsigned char  busy;          /* 586 clears after successful init */
+  unsigned char  zero_dummy;    /* has to be zero */
+  unsigned short scb_offset;    /* pointeroffset to the scb_base */
+  char          *scb_base;      /* base-address of all 16-bit offsets */
+};
+
+/*
+ * System Control Block (SCB)
+ */
+struct scb_struct
+{
+  unsigned char rus;
+  unsigned char cus;
+  unsigned char cmd_ruc;           /* command word: RU part */
+  unsigned char cmd_cuc;           /* command word: CU part & ACK */
+  unsigned short cbl_offset;    /* pointeroffset, command block list */
+  unsigned short rfa_offset;    /* pointeroffset, receive frame area */
+  unsigned short crc_errs;      /* CRC-Error counter */
+  unsigned short aln_errs;      /* allignmenterror counter */
+  unsigned short rsc_errs;      /* Resourceerror counter */
+  unsigned short ovrn_errs;     /* OVerrunerror counter */
+};
+
+/*
+ * possible command values for the command word
+ */
+#define RUC_MASK       0x0070  /* mask for RU commands */
+#define RUC_NOP                0x0000  /* NOP-command */
+#define RUC_START      0x0010  /* start RU */
+#define RUC_RESUME     0x0020  /* resume RU after suspend */
+#define RUC_SUSPEND    0x0030  /* suspend RU */
+#define RUC_ABORT      0x0040  /* abort receiver operation immediately */
+
+#define CUC_MASK        0x07  /* mask for CU command */
+#define CUC_NOP         0x00  /* NOP-command */
+#define CUC_START       0x01  /* start execution of 1. cmd on the CBL */
+#define CUC_RESUME      0x02  /* resume after suspend */
+#define CUC_SUSPEND     0x03  /* Suspend CU */
+#define CUC_ABORT       0x04  /* abort command operation immediately */
+
+#define ACK_MASK        0xf0  /* mask for ACK command */
+#define ACK_CX          0x80  /* acknowledges STAT_CX */
+#define ACK_FR          0x40  /* ack. STAT_FR */
+#define ACK_CNA         0x20  /* ack. STAT_CNA */
+#define ACK_RNR         0x10  /* ack. STAT_RNR */
+
+/*
+ * possible status values for the status word
+ */
+#define STAT_MASK       0xf0  /* mask for cause of interrupt */
+#define STAT_CX         0x80  /* CU finished cmd with its I bit set */
+#define STAT_FR         0x40  /* RU finished receiving a frame */
+#define STAT_CNA        0x20  /* CU left active state */
+#define STAT_RNR        0x10  /* RU left ready state */
+
+#define CU_STATUS       0x7   /* CU status, 0=idle */
+#define CU_SUSPEND      0x1   /* CU is suspended */
+#define CU_ACTIVE       0x2   /* CU is active */
+
+#define RU_STATUS      0x70    /* RU status, 0=idle */
+#define RU_SUSPEND     0x10    /* RU suspended */
+#define RU_NOSPACE     0x20    /* RU no resources */
+#define RU_READY       0x40    /* RU is ready */
+
+/*
+ * Receive Frame Descriptor (RFD)
+ */
+struct rfd_struct
+{
+  unsigned char  stat_low;     /* status word */
+  unsigned char  stat_high;    /* status word */
+  unsigned char  rfd_sf;       /* 82596 mode only */
+  unsigned char  last;         /* Bit15,Last Frame on List / Bit14,suspend */
+  unsigned short next;         /* linkoffset to next RFD */
+  unsigned short rbd_offset;   /* pointeroffset to RBD-buffer */
+  unsigned char  dest[6];      /* ethernet-address, destination */
+  unsigned char  source[6];    /* ethernet-address, source */
+  unsigned short length;       /* 802.3 frame-length */
+  unsigned short zero_dummy;   /* dummy */
+};
+
+#define RFD_LAST     0x80      /* last: last rfd in the list */
+#define RFD_SUSP     0x40      /* last: suspend RU after  */
+#define RFD_COMPL    0x80
+#define RFD_OK       0x20
+#define RFD_BUSY     0x40
+#define RFD_ERR_LEN  0x10     /* Length error (if enabled length-checking */
+#define RFD_ERR_CRC  0x08     /* CRC error */
+#define RFD_ERR_ALGN 0x04     /* Alignment error */
+#define RFD_ERR_RNR  0x02     /* status: receiver out of resources */
+#define RFD_ERR_OVR  0x01     /* DMA Overrun! */
+
+#define RFD_ERR_FTS  0x0080    /* Frame to short */
+#define RFD_ERR_NEOP 0x0040    /* No EOP flag (for bitstuffing only) */
+#define RFD_ERR_TRUN 0x0020    /* (82596 only/SF mode) indicates truncated frame */
+#define RFD_MATCHADD 0x0002     /* status: Destinationaddress !matches IA (only 82596) */
+#define RFD_COLLDET  0x0001    /* Detected collision during reception */
+
+/*
+ * Receive Buffer Descriptor (RBD)
+ */
+struct rbd_struct
+{
+  unsigned short status;       /* status word,number of used bytes in buff */
+  unsigned short next;         /* pointeroffset to next RBD */
+  char          *buffer;       /* receive buffer address pointer */
+  unsigned short size;         /* size of this buffer */
+  unsigned short zero_dummy;    /* dummy */
+};
+
+#define RBD_LAST       0x8000  /* last buffer */
+#define RBD_USED       0x4000  /* this buffer has data */
+#define RBD_MASK       0x3fff  /* size-mask for length */
+
+/*
+ * Statusvalues for Commands/RFD
+ */
+#define STAT_COMPL   0x8000    /* status: frame/command is complete */
+#define STAT_BUSY    0x4000    /* status: frame/command is busy */
+#define STAT_OK      0x2000    /* status: frame/command is ok */
+
+/*
+ * Action-Commands
+ */
+#define CMD_NOP                0x0000  /* NOP */
+#define CMD_IASETUP    0x0001  /* initial address setup command */
+#define CMD_CONFIGURE  0x0002  /* configure command */
+#define CMD_MCSETUP    0x0003  /* MC setup command */
+#define CMD_XMIT       0x0004  /* transmit command */
+#define CMD_TDR                0x0005  /* time domain reflectometer (TDR) command */
+#define CMD_DUMP       0x0006  /* dump command */
+#define CMD_DIAGNOSE   0x0007  /* diagnose command */
+
+/*
+ * Action command bits
+ */
+#define CMD_LAST       0x8000  /* indicates last command in the CBL */
+#define CMD_SUSPEND    0x4000  /* suspend CU after this CB */
+#define CMD_INT                0x2000  /* generate interrupt after execution */
+
+/*
+ * NOP - command
+ */
+struct nop_cmd_struct
+{
+  unsigned short cmd_status;   /* status of this command */
+  unsigned short cmd_cmd;       /* the command itself (+bits) */
+  unsigned short cmd_link;      /* offsetpointer to next command */
+};
+
+/*
+ * IA Setup command
+ */
+struct iasetup_cmd_struct
+{
+  unsigned short cmd_status;
+  unsigned short cmd_cmd;
+  unsigned short cmd_link;
+  unsigned char  iaddr[6];
+};
+
+/*
+ * Configure command
+ */
+struct configure_cmd_struct
+{
+  unsigned short cmd_status;
+  unsigned short cmd_cmd;
+  unsigned short cmd_link;
+  unsigned char  byte_cnt;   /* size of the config-cmd */
+  unsigned char  fifo;       /* fifo/recv monitor */
+  unsigned char  sav_bf;     /* save bad frames (bit7=1)*/
+  unsigned char  adr_len;    /* adr_len(0-2),al_loc(3),pream(4-5),loopbak(6-7)*/
+  unsigned char  priority;   /* lin_prio(0-2),exp_prio(4-6),bof_metd(7) */
+  unsigned char  ifs;        /* inter frame spacing */
+  unsigned char  time_low;   /* slot time low */
+  unsigned char  time_high;  /* slot time high(0-2) and max. retries(4-7) */
+  unsigned char  promisc;    /* promisc-mode(0) , et al (1-7) */
+  unsigned char  carr_coll;  /* carrier(0-3)/collision(4-7) stuff */
+  unsigned char  fram_len;   /* minimal frame len */
+  unsigned char  dummy;             /* dummy */
+};
+
+/*
+ * Multicast Setup command
+ */
+struct mcsetup_cmd_struct
+{
+  unsigned short cmd_status;
+  unsigned short cmd_cmd;
+  unsigned short cmd_link;
+  unsigned short mc_cnt;               /* number of bytes in the MC-List */
+  unsigned char  mc_list[0][6];        /* pointer to 6 bytes entries */
+};
+
+/*
+ * DUMP command
+ */
+struct dump_cmd_struct
+{
+  unsigned short cmd_status;
+  unsigned short cmd_cmd;
+  unsigned short cmd_link;
+  unsigned short dump_offset;    /* pointeroffset to DUMP space */
+};
+
+/*
+ * transmit command
+ */
+struct transmit_cmd_struct
+{
+  unsigned short cmd_status;
+  unsigned short cmd_cmd;
+  unsigned short cmd_link;
+  unsigned short tbd_offset;   /* pointeroffset to TBD */
+  unsigned char  dest[6];       /* destination address of the frame */
+  unsigned short length;       /* user defined: 802.3 length / Ether type */
+};
+
+#define TCMD_ERRMASK     0x0fa0
+#define TCMD_MAXCOLLMASK 0x000f
+#define TCMD_MAXCOLL     0x0020
+#define TCMD_HEARTBEAT   0x0040
+#define TCMD_DEFERRED    0x0080
+#define TCMD_UNDERRUN    0x0100
+#define TCMD_LOSTCTS     0x0200
+#define TCMD_NOCARRIER   0x0400
+#define TCMD_LATECOLL    0x0800
+
+struct tdr_cmd_struct
+{
+  unsigned short cmd_status;
+  unsigned short cmd_cmd;
+  unsigned short cmd_link;
+  unsigned short status;
+};
+
+#define TDR_LNK_OK     0x8000  /* No link problem identified */
+#define TDR_XCVR_PRB   0x4000  /* indicates a transceiver problem */
+#define TDR_ET_OPN     0x2000  /* open, no correct termination */
+#define TDR_ET_SRT     0x1000  /* TDR detected a short circuit */
+#define TDR_TIMEMASK   0x07ff  /* mask for the time field */
+
+/*
+ * Transmit Buffer Descriptor (TBD)
+ */
+struct tbd_struct
+{
+  unsigned short size;         /* size + EOF-Flag(15) */
+  unsigned short next;          /* pointeroffset to next TBD */
+  char          *buffer;        /* pointer to buffer */
+};
+
+#define TBD_LAST 0x8000         /* EOF-Flag, indicates last buffer in list */
+
+
+
+
diff --git a/drivers/net/ethernet/i825xx/znet.c b/drivers/net/ethernet/i825xx/znet.c
new file mode 100644 (file)
index 0000000..8b88817
--- /dev/null
@@ -0,0 +1,924 @@
+/* znet.c: An Zenith Z-Note ethernet driver for linux. */
+
+/*
+       Written by Donald Becker.
+
+       The author may be reached as becker@scyld.com.
+       This driver is based on the Linux skeleton driver.  The copyright of the
+       skeleton driver is held by the United States Government, as represented
+       by DIRNSA, and it is released under the GPL.
+
+       Thanks to Mike Hollick for alpha testing and suggestions.
+
+  References:
+          The Crynwr packet driver.
+
+         "82593 CSMA/CD Core LAN Controller" Intel datasheet, 1992
+         Intel Microcommunications Databook, Vol. 1, 1990.
+    As usual with Intel, the documentation is incomplete and inaccurate.
+       I had to read the Crynwr packet driver to figure out how to actually
+       use the i82593, and guess at what register bits matched the loosely
+       related i82586.
+
+                                       Theory of Operation
+
+       The i82593 used in the Zenith Z-Note series operates using two(!) slave
+       DMA     channels, one interrupt, and one 8-bit I/O port.
+
+       While there     several ways to configure '593 DMA system, I chose the one
+       that seemed commensurate with the highest system performance in the face
+       of moderate interrupt latency: Both DMA channels are configured as
+       recirculating ring buffers, with one channel (#0) dedicated to Rx and
+       the other channel (#1) to Tx and configuration.  (Note that this is
+       different than the Crynwr driver, where the Tx DMA channel is initialized
+       before each operation.  That approach simplifies operation and Tx error
+       recovery, but requires additional I/O in normal operation and precludes
+       transmit buffer chaining.)
+
+       Both rings are set to 8192 bytes using {TX,RX}_RING_SIZE.  This provides
+       a reasonable ring size for Rx, while simplifying DMA buffer allocation --
+       DMA buffers must not cross a 128K boundary.  (In truth the size selection
+       was influenced by my lack of '593 documentation.  I thus was constrained
+       to use the Crynwr '593 initialization table, which sets the Rx ring size
+       to 8K.)
+
+       Despite my usual low opinion about Intel-designed parts, I must admit
+       that the bulk data handling of the i82593 is a good design for
+       an integrated system, like a laptop, where using two slave DMA channels
+       doesn't pose a problem.  I still take issue with using only a single I/O
+       port.  In the same controlled environment there are essentially no
+       limitations on I/O space, and using multiple locations would eliminate
+       the     need for multiple operations when looking at status registers,
+       setting the Rx ring boundary, or switching to promiscuous mode.
+
+       I also question Zenith's selection of the '593: one of the advertised
+       advantages of earlier Intel parts was that if you figured out the magic
+       initialization incantation you could use the same part on many different
+       network types.  Zenith's use of the "FriendlyNet" (sic) connector rather
+       than an on-board transceiver leads me to believe that they were planning
+       to take advantage of this.  But, uhmmm, the '593 omits all but ethernet
+       functionality from the serial subsystem.
+ */
+
+/* 10/2002
+
+   o Resurected for Linux 2.5+ by Marc Zyngier <maz@wild-wind.fr.eu.org> :
+
+   - Removed strange DMA snooping in znet_sent_packet, which lead to
+     TX buffer corruption on my laptop.
+   - Use init_etherdev stuff.
+   - Use kmalloc-ed DMA buffers.
+   - Use as few global variables as possible.
+   - Use proper resources management.
+   - Use wireless/i82593.h as much as possible (structure, constants)
+   - Compiles as module or build-in.
+   - Now survives unplugging/replugging cable.
+
+   Some code was taken from wavelan_cs.
+
+   Tested on a vintage Zenith Z-Note 433Lnp+. Probably broken on
+   anything else. Testers (and detailed bug reports) are welcome :-).
+
+   o TODO :
+
+   - Properly handle multicast
+   - Understand why some traffic patterns add a 1s latency...
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/bitops.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#include <linux/i82593.h>
+
+static char version[] __initdata = "znet.c:v1.02 9/23/94 becker@scyld.com\n";
+
+#ifndef ZNET_DEBUG
+#define ZNET_DEBUG 1
+#endif
+static unsigned int znet_debug = ZNET_DEBUG;
+module_param (znet_debug, int, 0);
+MODULE_PARM_DESC (znet_debug, "ZNet debug level");
+MODULE_LICENSE("GPL");
+
+/* The DMA modes we need aren't in <dma.h>. */
+#define DMA_RX_MODE            0x14    /* Auto init, I/O to mem, ++, demand. */
+#define DMA_TX_MODE            0x18    /* Auto init, Mem to I/O, ++, demand. */
+#define dma_page_eq(ptr1, ptr2) ((long)(ptr1)>>17 == (long)(ptr2)>>17)
+#define RX_BUF_SIZE 8192
+#define TX_BUF_SIZE 8192
+#define DMA_BUF_SIZE (RX_BUF_SIZE + 16)        /* 8k + 16 bytes for trailers */
+
+#define TX_TIMEOUT     (HZ/10)
+
+struct znet_private {
+       int rx_dma, tx_dma;
+       spinlock_t lock;
+       short sia_base, sia_size, io_size;
+       struct i82593_conf_block i593_init;
+       /* The starting, current, and end pointers for the packet buffers. */
+       ushort *rx_start, *rx_cur, *rx_end;
+       ushort *tx_start, *tx_cur, *tx_end;
+       ushort tx_buf_len;                      /* Tx buffer length, in words. */
+};
+
+/* Only one can be built-in;-> */
+static struct net_device *znet_dev;
+
+struct netidblk {
+       char magic[8];          /* The magic number (string) "NETIDBLK" */
+       unsigned char netid[8]; /* The physical station address */
+       char nettype, globalopt;
+       char vendor[8];         /* The machine vendor and product name. */
+       char product[8];
+       char irq1, irq2;                /* Interrupts, only one is currently used.      */
+       char dma1, dma2;
+       short dma_mem_misc[8];          /* DMA buffer locations (unused in Linux). */
+       short iobase1, iosize1;
+       short iobase2, iosize2;         /* Second iobase unused. */
+       char driver_options;                    /* Misc. bits */
+       char pad;
+};
+
+static int     znet_open(struct net_device *dev);
+static netdev_tx_t znet_send_packet(struct sk_buff *skb,
+                                   struct net_device *dev);
+static irqreturn_t znet_interrupt(int irq, void *dev_id);
+static void    znet_rx(struct net_device *dev);
+static int     znet_close(struct net_device *dev);
+static void hardware_init(struct net_device *dev);
+static void update_stop_hit(short ioaddr, unsigned short rx_stop_offset);
+static void znet_tx_timeout (struct net_device *dev);
+
+/* Request needed resources */
+static int znet_request_resources (struct net_device *dev)
+{
+       struct znet_private *znet = netdev_priv(dev);
+
+       if (request_irq (dev->irq, znet_interrupt, 0, "ZNet", dev))
+               goto failed;
+       if (request_dma (znet->rx_dma, "ZNet rx"))
+               goto free_irq;
+       if (request_dma (znet->tx_dma, "ZNet tx"))
+               goto free_rx_dma;
+       if (!request_region (znet->sia_base, znet->sia_size, "ZNet SIA"))
+               goto free_tx_dma;
+       if (!request_region (dev->base_addr, znet->io_size, "ZNet I/O"))
+               goto free_sia;
+
+       return 0;                               /* Happy ! */
+
+ free_sia:
+       release_region (znet->sia_base, znet->sia_size);
+ free_tx_dma:
+       free_dma (znet->tx_dma);
+ free_rx_dma:
+       free_dma (znet->rx_dma);
+ free_irq:
+       free_irq (dev->irq, dev);
+ failed:
+       return -1;
+}
+
+static void znet_release_resources (struct net_device *dev)
+{
+       struct znet_private *znet = netdev_priv(dev);
+
+       release_region (znet->sia_base, znet->sia_size);
+       release_region (dev->base_addr, znet->io_size);
+       free_dma (znet->tx_dma);
+       free_dma (znet->rx_dma);
+       free_irq (dev->irq, dev);
+}
+
+/* Keep the magical SIA stuff in a single function... */
+static void znet_transceiver_power (struct net_device *dev, int on)
+{
+       struct znet_private *znet = netdev_priv(dev);
+       unsigned char v;
+
+       /* Turn on/off the 82501 SIA, using zenith-specific magic. */
+       /* Select LAN control register */
+       outb(0x10, znet->sia_base);
+
+       if (on)
+               v = inb(znet->sia_base + 1) | 0x84;
+       else
+               v = inb(znet->sia_base + 1) & ~0x84;
+
+       outb(v, znet->sia_base+1); /* Turn on/off LAN power (bit 2). */
+}
+
+/* Init the i82593, with current promisc/mcast configuration.
+   Also used from hardware_init. */
+static void znet_set_multicast_list (struct net_device *dev)
+{
+       struct znet_private *znet = netdev_priv(dev);
+       short ioaddr = dev->base_addr;
+       struct i82593_conf_block *cfblk = &znet->i593_init;
+
+       memset(cfblk, 0x00, sizeof(struct i82593_conf_block));
+
+        /* The configuration block.  What an undocumented nightmare.
+          The first set of values are those suggested (without explanation)
+          for ethernet in the Intel 82586 databook.  The rest appear to be
+          completely undocumented, except for cryptic notes in the Crynwr
+          packet driver.  This driver uses the Crynwr values verbatim. */
+
+       /* maz : Rewritten to take advantage of the wanvelan includes.
+          At least we have names, not just blind values */
+
+       /* Byte 0 */
+       cfblk->fifo_limit = 10; /* = 16 B rx and 80 B tx fifo thresholds */
+       cfblk->forgnesi = 0;    /* 0=82C501, 1=AMD7992B compatibility */
+       cfblk->fifo_32 = 1;
+       cfblk->d6mod = 0;       /* Run in i82593 advanced mode */
+       cfblk->throttle_enb = 1;
+
+       /* Byte 1 */
+       cfblk->throttle = 8;    /* Continuous w/interrupts, 128-clock DMA. */
+       cfblk->cntrxint = 0;    /* enable continuous mode receive interrupts */
+       cfblk->contin = 1;      /* enable continuous mode */
+
+       /* Byte 2 */
+       cfblk->addr_len = ETH_ALEN;
+       cfblk->acloc = 1;       /* Disable source addr insertion by i82593 */
+       cfblk->preamb_len = 2;  /* 8 bytes preamble */
+       cfblk->loopback = 0;    /* Loopback off */
+
+       /* Byte 3 */
+       cfblk->lin_prio = 0;    /* Default priorities & backoff methods. */
+       cfblk->tbofstop = 0;
+       cfblk->exp_prio = 0;
+       cfblk->bof_met = 0;
+
+       /* Byte 4 */
+       cfblk->ifrm_spc = 6;    /* 96 bit times interframe spacing */
+
+       /* Byte 5 */
+       cfblk->slottim_low = 0; /* 512 bit times slot time (low) */
+
+       /* Byte 6 */
+       cfblk->slottim_hi = 2;  /* 512 bit times slot time (high) */
+       cfblk->max_retr = 15;   /* 15 collisions retries */
+
+       /* Byte 7 */
+       cfblk->prmisc = ((dev->flags & IFF_PROMISC) ? 1 : 0); /* Promiscuous mode */
+       cfblk->bc_dis = 0;      /* Enable broadcast reception */
+       cfblk->crs_1 = 0;       /* Don't transmit without carrier sense */
+       cfblk->nocrc_ins = 0;   /* i82593 generates CRC */
+       cfblk->crc_1632 = 0;    /* 32-bit Autodin-II CRC */
+       cfblk->crs_cdt = 0;     /* CD not to be interpreted as CS */
+
+       /* Byte 8 */
+       cfblk->cs_filter = 0;   /* CS is recognized immediately */
+       cfblk->crs_src = 0;     /* External carrier sense */
+       cfblk->cd_filter = 0;   /* CD is recognized immediately */
+
+       /* Byte 9 */
+       cfblk->min_fr_len = ETH_ZLEN >> 2; /* Minimum frame length */
+
+       /* Byte A */
+       cfblk->lng_typ = 1;     /* Type/length checks OFF */
+       cfblk->lng_fld = 1;     /* Disable 802.3 length field check */
+       cfblk->rxcrc_xf = 1;    /* Don't transfer CRC to memory */
+       cfblk->artx = 1;        /* Disable automatic retransmission */
+       cfblk->sarec = 1;       /* Disable source addr trig of CD */
+       cfblk->tx_jabber = 0;   /* Disable jabber jam sequence */
+       cfblk->hash_1 = 1;      /* Use bits 0-5 in mc address hash */
+       cfblk->lbpkpol = 0;     /* Loopback pin active high */
+
+       /* Byte B */
+       cfblk->fdx = 0;         /* Disable full duplex operation */
+
+       /* Byte C */
+       cfblk->dummy_6 = 0x3f;  /* all ones, Default multicast addresses & backoff. */
+       cfblk->mult_ia = 0;     /* No multiple individual addresses */
+       cfblk->dis_bof = 0;     /* Disable the backoff algorithm ?! */
+
+       /* Byte D */
+       cfblk->dummy_1 = 1;     /* set to 1 */
+       cfblk->tx_ifs_retrig = 3; /* Hmm... Disabled */
+       cfblk->mc_all = (!netdev_mc_empty(dev) ||
+                       (dev->flags & IFF_ALLMULTI)); /* multicast all mode */
+       cfblk->rcv_mon = 0;     /* Monitor mode disabled */
+       cfblk->frag_acpt = 0;   /* Do not accept fragments */
+       cfblk->tstrttrs = 0;    /* No start transmission threshold */
+
+       /* Byte E */
+       cfblk->fretx = 1;       /* FIFO automatic retransmission */
+       cfblk->runt_eop = 0;    /* drop "runt" packets */
+       cfblk->hw_sw_pin = 0;   /* ?? */
+       cfblk->big_endn = 0;    /* Big Endian ? no... */
+       cfblk->syncrqs = 1;     /* Synchronous DRQ deassertion... */
+       cfblk->sttlen = 1;      /* 6 byte status registers */
+       cfblk->rx_eop = 0;      /* Signal EOP on packet reception */
+       cfblk->tx_eop = 0;      /* Signal EOP on packet transmission */
+
+       /* Byte F */
+       cfblk->rbuf_size = RX_BUF_SIZE >> 12; /* Set receive buffer size */
+       cfblk->rcvstop = 1;     /* Enable Receive Stop Register */
+
+       if (znet_debug > 2) {
+               int i;
+               unsigned char *c;
+
+               for (i = 0, c = (char *) cfblk; i < sizeof (*cfblk); i++)
+                       printk ("%02X ", c[i]);
+               printk ("\n");
+       }
+
+       *znet->tx_cur++ = sizeof(struct i82593_conf_block);
+       memcpy(znet->tx_cur, cfblk, sizeof(struct i82593_conf_block));
+       znet->tx_cur += sizeof(struct i82593_conf_block)/2;
+       outb(OP0_CONFIGURE | CR0_CHNL, ioaddr);
+
+       /* XXX FIXME maz : Add multicast addresses here, so having a
+        * multicast address configured isn't equal to IFF_ALLMULTI */
+}
+
+static const struct net_device_ops znet_netdev_ops = {
+       .ndo_open               = znet_open,
+       .ndo_stop               = znet_close,
+       .ndo_start_xmit         = znet_send_packet,
+       .ndo_set_multicast_list = znet_set_multicast_list,
+       .ndo_tx_timeout         = znet_tx_timeout,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
+/* The Z-Note probe is pretty easy.  The NETIDBLK exists in the safe-to-probe
+   BIOS area.  We just scan for the signature, and pull the vital parameters
+   out of the structure. */
+
+static int __init znet_probe (void)
+{
+       int i;
+       struct netidblk *netinfo;
+       struct znet_private *znet;
+       struct net_device *dev;
+       char *p;
+       int err = -ENOMEM;
+
+       /* This code scans the region 0xf0000 to 0xfffff for a "NETIDBLK". */
+       for(p = (char *)phys_to_virt(0xf0000); p < (char *)phys_to_virt(0x100000); p++)
+               if (*p == 'N'  &&  strncmp(p, "NETIDBLK", 8) == 0)
+                       break;
+
+       if (p >= (char *)phys_to_virt(0x100000)) {
+               if (znet_debug > 1)
+                       printk(KERN_INFO "No Z-Note ethernet adaptor found.\n");
+               return -ENODEV;
+       }
+
+       dev = alloc_etherdev(sizeof(struct znet_private));
+       if (!dev)
+               return -ENOMEM;
+
+       znet = netdev_priv(dev);
+
+       netinfo = (struct netidblk *)p;
+       dev->base_addr = netinfo->iobase1;
+       dev->irq = netinfo->irq1;
+
+       /* The station address is in the "netidblk" at 0x0f0000. */
+       for (i = 0; i < 6; i++)
+               dev->dev_addr[i] = netinfo->netid[i];
+
+       printk(KERN_INFO "%s: ZNET at %#3lx, %pM"
+              ", using IRQ %d DMA %d and %d.\n",
+              dev->name, dev->base_addr, dev->dev_addr,
+              dev->irq, netinfo->dma1, netinfo->dma2);
+
+       if (znet_debug > 1) {
+               printk(KERN_INFO "%s: vendor '%16.16s' IRQ1 %d IRQ2 %d DMA1 %d DMA2 %d.\n",
+                      dev->name, netinfo->vendor,
+                      netinfo->irq1, netinfo->irq2,
+                      netinfo->dma1, netinfo->dma2);
+               printk(KERN_INFO "%s: iobase1 %#x size %d iobase2 %#x size %d net type %2.2x.\n",
+                      dev->name, netinfo->iobase1, netinfo->iosize1,
+                      netinfo->iobase2, netinfo->iosize2, netinfo->nettype);
+       }
+
+       if (znet_debug > 0)
+               printk(KERN_INFO "%s", version);
+
+       znet->rx_dma = netinfo->dma1;
+       znet->tx_dma = netinfo->dma2;
+       spin_lock_init(&znet->lock);
+       znet->sia_base = 0xe6;  /* Magic address for the 82501 SIA */
+       znet->sia_size = 2;
+       /* maz: Despite the '593 being advertised above as using a
+        * single 8bits I/O port, this driver does many 16bits
+        * access. So set io_size accordingly */
+       znet->io_size  = 2;
+
+       if (!(znet->rx_start = kmalloc (DMA_BUF_SIZE, GFP_KERNEL | GFP_DMA)))
+               goto free_dev;
+       if (!(znet->tx_start = kmalloc (DMA_BUF_SIZE, GFP_KERNEL | GFP_DMA)))
+               goto free_rx;
+
+       if (!dma_page_eq (znet->rx_start, znet->rx_start + (RX_BUF_SIZE/2-1)) ||
+           !dma_page_eq (znet->tx_start, znet->tx_start + (TX_BUF_SIZE/2-1))) {
+               printk (KERN_WARNING "tx/rx crossing DMA frontiers, giving up\n");
+               goto free_tx;
+       }
+
+       znet->rx_end = znet->rx_start + RX_BUF_SIZE/2;
+       znet->tx_buf_len = TX_BUF_SIZE/2;
+       znet->tx_end = znet->tx_start + znet->tx_buf_len;
+
+       /* The ZNET-specific entries in the device structure. */
+       dev->netdev_ops = &znet_netdev_ops;
+       dev->watchdog_timeo = TX_TIMEOUT;
+       err = register_netdev(dev);
+       if (err)
+               goto free_tx;
+       znet_dev = dev;
+       return 0;
+
+ free_tx:
+       kfree(znet->tx_start);
+ free_rx:
+       kfree(znet->rx_start);
+ free_dev:
+       free_netdev(dev);
+       return err;
+}
+
+
+static int znet_open(struct net_device *dev)
+{
+       int ioaddr = dev->base_addr;
+
+       if (znet_debug > 2)
+               printk(KERN_DEBUG "%s: znet_open() called.\n", dev->name);
+
+       /* These should never fail.  You can't add devices to a sealed box! */
+       if (znet_request_resources (dev)) {
+               printk(KERN_WARNING "%s: Not opened -- resource busy?!?\n", dev->name);
+               return -EBUSY;
+       }
+
+       znet_transceiver_power (dev, 1);
+
+       /* According to the Crynwr driver we should wait 50 msec. for the
+          LAN clock to stabilize.  My experiments indicates that the '593 can
+          be initialized immediately.  The delay is probably needed for the
+          DC-to-DC converter to come up to full voltage, and for the oscillator
+          to be spot-on at 20Mhz before transmitting.
+          Until this proves to be a problem we rely on the higher layers for the
+          delay and save allocating a timer entry. */
+
+       /* maz : Well, I'm getting every time the following message
+        * without the delay on a 486@33. This machine is much too
+        * fast... :-) So maybe the Crynwr driver wasn't wrong after
+        * all, even if the message is completly harmless on my
+        * setup. */
+       mdelay (50);
+
+       /* This follows the packet driver's lead, and checks for success. */
+       if (inb(ioaddr) != 0x10 && inb(ioaddr) != 0x00)
+               printk(KERN_WARNING "%s: Problem turning on the transceiver power.\n",
+                      dev->name);
+
+       hardware_init(dev);
+       netif_start_queue (dev);
+
+       return 0;
+}
+
+
+static void znet_tx_timeout (struct net_device *dev)
+{
+       int ioaddr = dev->base_addr;
+       ushort event, tx_status, rx_offset, state;
+
+       outb (CR0_STATUS_0, ioaddr);
+       event = inb (ioaddr);
+       outb (CR0_STATUS_1, ioaddr);
+       tx_status = inw (ioaddr);
+       outb (CR0_STATUS_2, ioaddr);
+       rx_offset = inw (ioaddr);
+       outb (CR0_STATUS_3, ioaddr);
+       state = inb (ioaddr);
+       printk (KERN_WARNING "%s: transmit timed out, status %02x %04x %04x %02x,"
+        " resetting.\n", dev->name, event, tx_status, rx_offset, state);
+       if (tx_status == TX_LOST_CRS)
+               printk (KERN_WARNING "%s: Tx carrier error, check transceiver cable.\n",
+                       dev->name);
+       outb (OP0_RESET, ioaddr);
+       hardware_init (dev);
+       netif_wake_queue (dev);
+}
+
+static netdev_tx_t znet_send_packet(struct sk_buff *skb, struct net_device *dev)
+{
+       int ioaddr = dev->base_addr;
+       struct znet_private *znet = netdev_priv(dev);
+       unsigned long flags;
+       short length = skb->len;
+
+       if (znet_debug > 4)
+               printk(KERN_DEBUG "%s: ZNet_send_packet.\n", dev->name);
+
+       if (length < ETH_ZLEN) {
+               if (skb_padto(skb, ETH_ZLEN))
+                       return NETDEV_TX_OK;
+               length = ETH_ZLEN;
+       }
+
+       netif_stop_queue (dev);
+
+       /* Check that the part hasn't reset itself, probably from suspend. */
+       outb(CR0_STATUS_0, ioaddr);
+       if (inw(ioaddr) == 0x0010 &&
+           inw(ioaddr) == 0x0000 &&
+           inw(ioaddr) == 0x0010) {
+               if (znet_debug > 1)
+                       printk (KERN_WARNING "%s : waking up\n", dev->name);
+               hardware_init(dev);
+               znet_transceiver_power (dev, 1);
+       }
+
+       if (1) {
+               unsigned char *buf = (void *)skb->data;
+               ushort *tx_link = znet->tx_cur - 1;
+               ushort rnd_len = (length + 1)>>1;
+
+               dev->stats.tx_bytes+=length;
+
+               if (znet->tx_cur >= znet->tx_end)
+                 znet->tx_cur = znet->tx_start;
+               *znet->tx_cur++ = length;
+               if (znet->tx_cur + rnd_len + 1 > znet->tx_end) {
+                       int semi_cnt = (znet->tx_end - znet->tx_cur)<<1; /* Cvrt to byte cnt. */
+                       memcpy(znet->tx_cur, buf, semi_cnt);
+                       rnd_len -= semi_cnt>>1;
+                       memcpy(znet->tx_start, buf + semi_cnt, length - semi_cnt);
+                       znet->tx_cur = znet->tx_start + rnd_len;
+               } else {
+                       memcpy(znet->tx_cur, buf, skb->len);
+                       znet->tx_cur += rnd_len;
+               }
+               *znet->tx_cur++ = 0;
+
+               spin_lock_irqsave(&znet->lock, flags);
+               {
+                       *tx_link = OP0_TRANSMIT | CR0_CHNL;
+                       /* Is this always safe to do? */
+                       outb(OP0_TRANSMIT | CR0_CHNL, ioaddr);
+               }
+               spin_unlock_irqrestore (&znet->lock, flags);
+
+               netif_start_queue (dev);
+
+               if (znet_debug > 4)
+                 printk(KERN_DEBUG "%s: Transmitter queued, length %d.\n", dev->name, length);
+       }
+       dev_kfree_skb(skb);
+       return NETDEV_TX_OK;
+}
+
+/* The ZNET interrupt handler. */
+static irqreturn_t znet_interrupt(int irq, void *dev_id)
+{
+       struct net_device *dev = dev_id;
+       struct znet_private *znet = netdev_priv(dev);
+       int ioaddr;
+       int boguscnt = 20;
+       int handled = 0;
+
+       spin_lock (&znet->lock);
+
+       ioaddr = dev->base_addr;
+
+       outb(CR0_STATUS_0, ioaddr);
+       do {
+               ushort status = inb(ioaddr);
+               if (znet_debug > 5) {
+                       ushort result, rx_ptr, running;
+                       outb(CR0_STATUS_1, ioaddr);
+                       result = inw(ioaddr);
+                       outb(CR0_STATUS_2, ioaddr);
+                       rx_ptr = inw(ioaddr);
+                       outb(CR0_STATUS_3, ioaddr);
+                       running = inb(ioaddr);
+                       printk(KERN_DEBUG "%s: interrupt, status %02x, %04x %04x %02x serial %d.\n",
+                                dev->name, status, result, rx_ptr, running, boguscnt);
+               }
+               if ((status & SR0_INTERRUPT) == 0)
+                       break;
+
+               handled = 1;
+
+               if ((status & SR0_EVENT_MASK) == SR0_TRANSMIT_DONE ||
+                   (status & SR0_EVENT_MASK) == SR0_RETRANSMIT_DONE ||
+                   (status & SR0_EVENT_MASK) == SR0_TRANSMIT_NO_CRC_DONE) {
+                       int tx_status;
+                       outb(CR0_STATUS_1, ioaddr);
+                       tx_status = inw(ioaddr);
+                       /* It's undocumented, but tx_status seems to match the i82586. */
+                       if (tx_status & TX_OK) {
+                               dev->stats.tx_packets++;
+                               dev->stats.collisions += tx_status & TX_NCOL_MASK;
+                       } else {
+                               if (tx_status & (TX_LOST_CTS | TX_LOST_CRS))
+                                       dev->stats.tx_carrier_errors++;
+                               if (tx_status & TX_UND_RUN)
+                                       dev->stats.tx_fifo_errors++;
+                               if (!(tx_status & TX_HRT_BEAT))
+                                       dev->stats.tx_heartbeat_errors++;
+                               if (tx_status & TX_MAX_COL)
+                                       dev->stats.tx_aborted_errors++;
+                               /* ...and the catch-all. */
+                               if ((tx_status | (TX_LOST_CRS | TX_LOST_CTS | TX_UND_RUN | TX_HRT_BEAT | TX_MAX_COL)) != (TX_LOST_CRS | TX_LOST_CTS | TX_UND_RUN | TX_HRT_BEAT | TX_MAX_COL))
+                                       dev->stats.tx_errors++;
+
+                               /* Transceiver may be stuck if cable
+                                * was removed while emitting a
+                                * packet. Flip it off, then on to
+                                * reset it. This is very empirical,
+                                * but it seems to work. */
+
+                               znet_transceiver_power (dev, 0);
+                               znet_transceiver_power (dev, 1);
+                       }
+                       netif_wake_queue (dev);
+               }
+
+               if ((status & SR0_RECEPTION) ||
+                   (status & SR0_EVENT_MASK) == SR0_STOP_REG_HIT) {
+                       znet_rx(dev);
+               }
+               /* Clear the interrupts we've handled. */
+               outb(CR0_INT_ACK, ioaddr);
+       } while (boguscnt--);
+
+       spin_unlock (&znet->lock);
+
+       return IRQ_RETVAL(handled);
+}
+
+static void znet_rx(struct net_device *dev)
+{
+       struct znet_private *znet = netdev_priv(dev);
+       int ioaddr = dev->base_addr;
+       int boguscount = 1;
+       short next_frame_end_offset = 0;                /* Offset of next frame start. */
+       short *cur_frame_end;
+       short cur_frame_end_offset;
+
+       outb(CR0_STATUS_2, ioaddr);
+       cur_frame_end_offset = inw(ioaddr);
+
+       if (cur_frame_end_offset == znet->rx_cur - znet->rx_start) {
+               printk(KERN_WARNING "%s: Interrupted, but nothing to receive, offset %03x.\n",
+                          dev->name, cur_frame_end_offset);
+               return;
+       }
+
+       /* Use same method as the Crynwr driver: construct a forward list in
+          the same area of the backwards links we now have.  This allows us to
+          pass packets to the upper layers in the order they were received --
+          important for fast-path sequential operations. */
+       while (znet->rx_start + cur_frame_end_offset != znet->rx_cur &&
+              ++boguscount < 5) {
+               unsigned short hi_cnt, lo_cnt, hi_status, lo_status;
+               int count, status;
+
+               if (cur_frame_end_offset < 4) {
+                       /* Oh no, we have a special case: the frame trailer wraps around
+                          the end of the ring buffer.  We've saved space at the end of
+                          the ring buffer for just this problem. */
+                       memcpy(znet->rx_end, znet->rx_start, 8);
+                       cur_frame_end_offset += (RX_BUF_SIZE/2);
+               }
+               cur_frame_end = znet->rx_start + cur_frame_end_offset - 4;
+
+               lo_status = *cur_frame_end++;
+               hi_status = *cur_frame_end++;
+               status = ((hi_status & 0xff) << 8) + (lo_status & 0xff);
+               lo_cnt = *cur_frame_end++;
+               hi_cnt = *cur_frame_end++;
+               count = ((hi_cnt & 0xff) << 8) + (lo_cnt & 0xff);
+
+               if (znet_debug > 5)
+                 printk(KERN_DEBUG "Constructing trailer at location %03x, %04x %04x %04x %04x"
+                                " count %#x status %04x.\n",
+                                cur_frame_end_offset<<1, lo_status, hi_status, lo_cnt, hi_cnt,
+                                count, status);
+               cur_frame_end[-4] = status;
+               cur_frame_end[-3] = next_frame_end_offset;
+               cur_frame_end[-2] = count;
+               next_frame_end_offset = cur_frame_end_offset;
+               cur_frame_end_offset -= ((count + 1)>>1) + 3;
+               if (cur_frame_end_offset < 0)
+                 cur_frame_end_offset += RX_BUF_SIZE/2;
+       }
+
+       /* Now step  forward through the list. */
+       do {
+               ushort *this_rfp_ptr = znet->rx_start + next_frame_end_offset;
+               int status = this_rfp_ptr[-4];
+               int pkt_len = this_rfp_ptr[-2];
+
+               if (znet_debug > 5)
+                 printk(KERN_DEBUG "Looking at trailer ending at %04x status %04x length %03x"
+                                " next %04x.\n", next_frame_end_offset<<1, status, pkt_len,
+                                this_rfp_ptr[-3]<<1);
+               /* Once again we must assume that the i82586 docs apply. */
+               if ( ! (status & RX_RCV_OK)) { /* There was an error. */
+                       dev->stats.rx_errors++;
+                       if (status & RX_CRC_ERR) dev->stats.rx_crc_errors++;
+                       if (status & RX_ALG_ERR) dev->stats.rx_frame_errors++;
+#if 0
+                       if (status & 0x0200) dev->stats.rx_over_errors++; /* Wrong. */
+                       if (status & 0x0100) dev->stats.rx_fifo_errors++;
+#else
+                       /* maz : Wild guess... */
+                       if (status & RX_OVRRUN) dev->stats.rx_over_errors++;
+#endif
+                       if (status & RX_SRT_FRM) dev->stats.rx_length_errors++;
+               } else if (pkt_len > 1536) {
+                       dev->stats.rx_length_errors++;
+               } else {
+                       /* Malloc up new buffer. */
+                       struct sk_buff *skb;
+
+                       skb = dev_alloc_skb(pkt_len);
+                       if (skb == NULL) {
+                               if (znet_debug)
+                                 printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
+                               dev->stats.rx_dropped++;
+                               break;
+                       }
+
+                       if (&znet->rx_cur[(pkt_len+1)>>1] > znet->rx_end) {
+                               int semi_cnt = (znet->rx_end - znet->rx_cur)<<1;
+                               memcpy(skb_put(skb,semi_cnt), znet->rx_cur, semi_cnt);
+                               memcpy(skb_put(skb,pkt_len-semi_cnt), znet->rx_start,
+                                          pkt_len - semi_cnt);
+                       } else {
+                               memcpy(skb_put(skb,pkt_len), znet->rx_cur, pkt_len);
+                               if (znet_debug > 6) {
+                                       unsigned int *packet = (unsigned int *) skb->data;
+                                       printk(KERN_DEBUG "Packet data is %08x %08x %08x %08x.\n", packet[0],
+                                                  packet[1], packet[2], packet[3]);
+                               }
+                 }
+                 skb->protocol=eth_type_trans(skb,dev);
+                 netif_rx(skb);
+                 dev->stats.rx_packets++;
+                 dev->stats.rx_bytes += pkt_len;
+               }
+               znet->rx_cur = this_rfp_ptr;
+               if (znet->rx_cur >= znet->rx_end)
+                       znet->rx_cur -= RX_BUF_SIZE/2;
+               update_stop_hit(ioaddr, (znet->rx_cur - znet->rx_start)<<1);
+               next_frame_end_offset = this_rfp_ptr[-3];
+               if (next_frame_end_offset == 0)         /* Read all the frames? */
+                       break;                  /* Done for now */
+               this_rfp_ptr = znet->rx_start + next_frame_end_offset;
+       } while (--boguscount);
+
+       /* If any worth-while packets have been received, dev_rint()
+          has done a mark_bh(INET_BH) for us and will work on them
+          when we get to the bottom-half routine. */
+}
+
+/* The inverse routine to znet_open(). */
+static int znet_close(struct net_device *dev)
+{
+       int ioaddr = dev->base_addr;
+
+       netif_stop_queue (dev);
+
+       outb(OP0_RESET, ioaddr);                        /* CMD0_RESET */
+
+       if (znet_debug > 1)
+               printk(KERN_DEBUG "%s: Shutting down ethercard.\n", dev->name);
+       /* Turn off transceiver power. */
+       znet_transceiver_power (dev, 0);
+
+       znet_release_resources (dev);
+
+       return 0;
+}
+
+static void show_dma(struct net_device *dev)
+{
+       short ioaddr = dev->base_addr;
+       unsigned char stat = inb (ioaddr);
+       struct znet_private *znet = netdev_priv(dev);
+       unsigned long flags;
+       short dma_port = ((znet->tx_dma&3)<<2) + IO_DMA2_BASE;
+       unsigned addr = inb(dma_port);
+       short residue;
+
+       addr |= inb(dma_port) << 8;
+       residue = get_dma_residue(znet->tx_dma);
+
+       if (znet_debug > 1) {
+               flags=claim_dma_lock();
+               printk(KERN_DEBUG "Stat:%02x Addr: %04x cnt:%3x\n",
+                      stat, addr<<1, residue);
+               release_dma_lock(flags);
+       }
+}
+
+/* Initialize the hardware.  We have to do this when the board is open()ed
+   or when we come out of suspend mode. */
+static void hardware_init(struct net_device *dev)
+{
+       unsigned long flags;
+       short ioaddr = dev->base_addr;
+       struct znet_private *znet = netdev_priv(dev);
+
+       znet->rx_cur = znet->rx_start;
+       znet->tx_cur = znet->tx_start;
+
+       /* Reset the chip, and start it up. */
+       outb(OP0_RESET, ioaddr);
+
+       flags=claim_dma_lock();
+       disable_dma(znet->rx_dma);              /* reset by an interrupting task. */
+       clear_dma_ff(znet->rx_dma);
+       set_dma_mode(znet->rx_dma, DMA_RX_MODE);
+       set_dma_addr(znet->rx_dma, (unsigned int) znet->rx_start);
+       set_dma_count(znet->rx_dma, RX_BUF_SIZE);
+       enable_dma(znet->rx_dma);
+       /* Now set up the Tx channel. */
+       disable_dma(znet->tx_dma);
+       clear_dma_ff(znet->tx_dma);
+       set_dma_mode(znet->tx_dma, DMA_TX_MODE);
+       set_dma_addr(znet->tx_dma, (unsigned int) znet->tx_start);
+       set_dma_count(znet->tx_dma, znet->tx_buf_len<<1);
+       enable_dma(znet->tx_dma);
+       release_dma_lock(flags);
+
+       if (znet_debug > 1)
+         printk(KERN_DEBUG "%s: Initializing the i82593, rx buf %p tx buf %p\n",
+                        dev->name, znet->rx_start,znet->tx_start);
+       /* Do an empty configure command, just like the Crynwr driver.  This
+          resets to chip to its default values. */
+       *znet->tx_cur++ = 0;
+       *znet->tx_cur++ = 0;
+       show_dma(dev);
+       outb(OP0_CONFIGURE | CR0_CHNL, ioaddr);
+
+       znet_set_multicast_list (dev);
+
+       *znet->tx_cur++ = 6;
+       memcpy(znet->tx_cur, dev->dev_addr, 6);
+       znet->tx_cur += 3;
+       show_dma(dev);
+       outb(OP0_IA_SETUP | CR0_CHNL, ioaddr);
+       show_dma(dev);
+
+       update_stop_hit(ioaddr, 8192);
+       if (znet_debug > 1)  printk(KERN_DEBUG "enabling Rx.\n");
+       outb(OP0_RCV_ENABLE, ioaddr);
+       netif_start_queue (dev);
+}
+
+static void update_stop_hit(short ioaddr, unsigned short rx_stop_offset)
+{
+       outb(OP0_SWIT_TO_PORT_1 | CR0_CHNL, ioaddr);
+       if (znet_debug > 5)
+         printk(KERN_DEBUG "Updating stop hit with value %02x.\n",
+                        (rx_stop_offset >> 6) | CR1_STOP_REG_UPDATE);
+       outb((rx_stop_offset >> 6) | CR1_STOP_REG_UPDATE, ioaddr);
+       outb(OP1_SWIT_TO_PORT_0, ioaddr);
+}
+
+static __exit void znet_cleanup (void)
+{
+       if (znet_dev) {
+               struct znet_private *znet = netdev_priv(znet_dev);
+
+               unregister_netdev (znet_dev);
+               kfree (znet->rx_start);
+               kfree (znet->tx_start);
+               free_netdev (znet_dev);
+       }
+}
+
+module_init (znet_probe);
+module_exit (znet_cleanup);
diff --git a/drivers/net/lasi_82596.c b/drivers/net/lasi_82596.c
deleted file mode 100644 (file)
index 6eba352..0000000
+++ /dev/null
@@ -1,238 +0,0 @@
-/* lasi_82596.c -- driver for the intel 82596 ethernet controller, as
-   munged into HPPA boxen .
-
-   This driver is based upon 82596.c, original credits are below...
-   but there were too many hoops which HP wants jumped through to
-   keep this code in there in a sane manner.
-
-   3 primary sources of the mess --
-   1) hppa needs *lots* of cacheline flushing to keep this kind of
-   MMIO running.
-
-   2) The 82596 needs to see all of its pointers as their physical
-   address.  Thus virt_to_bus/bus_to_virt are *everywhere*.
-
-   3) The implementation HP is using seems to be significantly pickier
-   about when and how the command and RX units are started.  some
-   command ordering was changed.
-
-   Examination of the mach driver leads one to believe that there
-   might be a saner way to pull this off...  anyone who feels like a
-   full rewrite can be my guest.
-
-   Split 02/13/2000 Sam Creasey (sammy@oh.verio.com)
-
-   02/01/2000  Initial modifications for parisc by Helge Deller (deller@gmx.de)
-   03/02/2000  changes for better/correct(?) cache-flushing (deller)
-*/
-
-/* 82596.c: A generic 82596 ethernet driver for linux. */
-/*
-   Based on Apricot.c
-   Written 1994 by Mark Evans.
-   This driver is for the Apricot 82596 bus-master interface
-
-   Modularised 12/94 Mark Evans
-
-
-   Modified to support the 82596 ethernet chips on 680x0 VME boards.
-   by Richard Hirst <richard@sleepie.demon.co.uk>
-   Renamed to be 82596.c
-
-   980825:  Changed to receive directly in to sk_buffs which are
-   allocated at open() time.  Eliminates copy on incoming frames
-   (small ones are still copied).  Shared data now held in a
-   non-cached page, so we can run on 68060 in copyback mode.
-
-   TBD:
-   * look at deferring rx frames rather than discarding (as per tulip)
-   * handle tx ring full as per tulip
-   * performance test to tune rx_copybreak
-
-   Most of my modifications relate to the braindead big-endian
-   implementation by Intel.  When the i596 is operating in
-   'big-endian' mode, it thinks a 32 bit value of 0x12345678
-   should be stored as 0x56781234.  This is a real pain, when
-   you have linked lists which are shared by the 680x0 and the
-   i596.
-
-   Driver skeleton
-   Written 1993 by Donald Becker.
-   Copyright 1993 United States Government as represented by the Director,
-   National Security Agency. This software may only be used and distributed
-   according to the terms of the GNU General Public License as modified by SRC,
-   incorporated herein by reference.
-
-   The author may be reached as becker@scyld.com, or C/O
-   Scyld Computing Corporation, 410 Severn Ave., Suite 210, Annapolis MD 21403
-
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/ptrace.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/bitops.h>
-#include <linux/dma-mapping.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/pdc.h>
-#include <asm/parisc-device.h>
-
-#define LASI_82596_DRIVER_VERSION "LASI 82596 driver - Revision: 1.30"
-
-#define PA_I82596_RESET                0       /* Offsets relative to LASI-LAN-Addr.*/
-#define PA_CPU_PORT_L_ACCESS   4
-#define PA_CHANNEL_ATTENTION   8
-
-#define OPT_SWAP_PORT  0x0001  /* Need to wordswp on the MPU port */
-
-#define DMA_ALLOC                        dma_alloc_noncoherent
-#define DMA_FREE                         dma_free_noncoherent
-#define DMA_WBACK(ndev, addr, len) \
-       do { dma_cache_sync((ndev)->dev.parent, (void *)addr, len, DMA_TO_DEVICE); } while (0)
-
-#define DMA_INV(ndev, addr, len) \
-       do { dma_cache_sync((ndev)->dev.parent, (void *)addr, len, DMA_FROM_DEVICE); } while (0)
-
-#define DMA_WBACK_INV(ndev, addr, len) \
-       do { dma_cache_sync((ndev)->dev.parent, (void *)addr, len, DMA_BIDIRECTIONAL); } while (0)
-
-#define SYSBUS      0x0000006c;
-
-/* big endian CPU, 82596 "big" endian mode */
-#define SWAP32(x)   (((u32)(x)<<16) | ((((u32)(x)))>>16))
-#define SWAP16(x)   (x)
-
-#include "lib82596.c"
-
-MODULE_AUTHOR("Richard Hirst");
-MODULE_DESCRIPTION("i82596 driver");
-MODULE_LICENSE("GPL");
-module_param(i596_debug, int, 0);
-MODULE_PARM_DESC(i596_debug, "lasi_82596 debug mask");
-
-static inline void ca(struct net_device *dev)
-{
-       gsc_writel(0, dev->base_addr + PA_CHANNEL_ATTENTION);
-}
-
-
-static void mpu_port(struct net_device *dev, int c, dma_addr_t x)
-{
-       struct i596_private *lp = netdev_priv(dev);
-
-       u32 v = (u32) (c) | (u32) (x);
-       u16 a, b;
-
-       if (lp->options & OPT_SWAP_PORT) {
-               a = v >> 16;
-               b = v & 0xffff;
-       } else {
-               a = v & 0xffff;
-               b = v >> 16;
-       }
-
-       gsc_writel(a, dev->base_addr + PA_CPU_PORT_L_ACCESS);
-       udelay(1);
-       gsc_writel(b, dev->base_addr + PA_CPU_PORT_L_ACCESS);
-}
-
-#define LAN_PROM_ADDR  0xF0810000
-
-static int __devinit
-lan_init_chip(struct parisc_device *dev)
-{
-       struct  net_device *netdevice;
-       struct i596_private *lp;
-       int     retval;
-       int i;
-
-       if (!dev->irq) {
-               printk(KERN_ERR "%s: IRQ not found for i82596 at 0x%lx\n",
-                       __FILE__, (unsigned long)dev->hpa.start);
-               return -ENODEV;
-       }
-
-       printk(KERN_INFO "Found i82596 at 0x%lx, IRQ %d\n",
-                       (unsigned long)dev->hpa.start, dev->irq);
-
-       netdevice = alloc_etherdev(sizeof(struct i596_private));
-       if (!netdevice)
-               return -ENOMEM;
-       SET_NETDEV_DEV(netdevice, &dev->dev);
-       parisc_set_drvdata (dev, netdevice);
-
-       netdevice->base_addr = dev->hpa.start;
-       netdevice->irq = dev->irq;
-
-       if (pdc_lan_station_id(netdevice->dev_addr, netdevice->base_addr)) {
-               for (i = 0; i < 6; i++) {
-                       netdevice->dev_addr[i] = gsc_readb(LAN_PROM_ADDR + i);
-               }
-               printk(KERN_INFO
-                      "%s: MAC of HP700 LAN read from EEPROM\n", __FILE__);
-       }
-
-       lp = netdev_priv(netdevice);
-       lp->options = dev->id.sversion == 0x72 ? OPT_SWAP_PORT : 0;
-
-       retval = i82596_probe(netdevice);
-       if (retval) {
-               free_netdev(netdevice);
-               return -ENODEV;
-       }
-       return retval;
-}
-
-static int __devexit lan_remove_chip (struct parisc_device *pdev)
-{
-       struct net_device *dev = parisc_get_drvdata(pdev);
-       struct i596_private *lp = netdev_priv(dev);
-
-       unregister_netdev (dev);
-       DMA_FREE(&pdev->dev, sizeof(struct i596_private),
-                (void *)lp->dma, lp->dma_addr);
-       free_netdev (dev);
-       return 0;
-}
-
-static struct parisc_device_id lan_tbl[] = {
-       { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0008a },
-       { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00072 },
-       { 0, }
-};
-
-MODULE_DEVICE_TABLE(parisc, lan_tbl);
-
-static struct parisc_driver lan_driver = {
-       .name           = "lasi_82596",
-       .id_table       = lan_tbl,
-       .probe          = lan_init_chip,
-       .remove         = __devexit_p(lan_remove_chip),
-};
-
-static int __devinit lasi_82596_init(void)
-{
-       printk(KERN_INFO LASI_82596_DRIVER_VERSION "\n");
-       return register_parisc_driver(&lan_driver);
-}
-
-module_init(lasi_82596_init);
-
-static void __exit lasi_82596_exit(void)
-{
-       unregister_parisc_driver(&lan_driver);
-}
-
-module_exit(lasi_82596_exit);
diff --git a/drivers/net/lib82596.c b/drivers/net/lib82596.c
deleted file mode 100644 (file)
index 9e04289..0000000
+++ /dev/null
@@ -1,1412 +0,0 @@
-/* lasi_82596.c -- driver for the intel 82596 ethernet controller, as
-   munged into HPPA boxen .
-
-   This driver is based upon 82596.c, original credits are below...
-   but there were too many hoops which HP wants jumped through to
-   keep this code in there in a sane manner.
-
-   3 primary sources of the mess --
-   1) hppa needs *lots* of cacheline flushing to keep this kind of
-   MMIO running.
-
-   2) The 82596 needs to see all of its pointers as their physical
-   address.  Thus virt_to_bus/bus_to_virt are *everywhere*.
-
-   3) The implementation HP is using seems to be significantly pickier
-   about when and how the command and RX units are started.  some
-   command ordering was changed.
-
-   Examination of the mach driver leads one to believe that there
-   might be a saner way to pull this off...  anyone who feels like a
-   full rewrite can be my guest.
-
-   Split 02/13/2000 Sam Creasey (sammy@oh.verio.com)
-
-   02/01/2000  Initial modifications for parisc by Helge Deller (deller@gmx.de)
-   03/02/2000  changes for better/correct(?) cache-flushing (deller)
-*/
-
-/* 82596.c: A generic 82596 ethernet driver for linux. */
-/*
-   Based on Apricot.c
-   Written 1994 by Mark Evans.
-   This driver is for the Apricot 82596 bus-master interface
-
-   Modularised 12/94 Mark Evans
-
-
-   Modified to support the 82596 ethernet chips on 680x0 VME boards.
-   by Richard Hirst <richard@sleepie.demon.co.uk>
-   Renamed to be 82596.c
-
-   980825:  Changed to receive directly in to sk_buffs which are
-   allocated at open() time.  Eliminates copy on incoming frames
-   (small ones are still copied).  Shared data now held in a
-   non-cached page, so we can run on 68060 in copyback mode.
-
-   TBD:
-   * look at deferring rx frames rather than discarding (as per tulip)
-   * handle tx ring full as per tulip
-   * performance test to tune rx_copybreak
-
-   Most of my modifications relate to the braindead big-endian
-   implementation by Intel.  When the i596 is operating in
-   'big-endian' mode, it thinks a 32 bit value of 0x12345678
-   should be stored as 0x56781234.  This is a real pain, when
-   you have linked lists which are shared by the 680x0 and the
-   i596.
-
-   Driver skeleton
-   Written 1993 by Donald Becker.
-   Copyright 1993 United States Government as represented by the Director,
-   National Security Agency. This software may only be used and distributed
-   according to the terms of the GNU General Public License as modified by SRC,
-   incorporated herein by reference.
-
-   The author may be reached as becker@scyld.com, or C/O
-   Scyld Computing Corporation, 410 Severn Ave., Suite 210, Annapolis MD 21403
-
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/bitops.h>
-#include <linux/dma-mapping.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-#include <linux/gfp.h>
-
-/* DEBUG flags
- */
-
-#define DEB_INIT       0x0001
-#define DEB_PROBE      0x0002
-#define DEB_SERIOUS    0x0004
-#define DEB_ERRORS     0x0008
-#define DEB_MULTI      0x0010
-#define DEB_TDR                0x0020
-#define DEB_OPEN       0x0040
-#define DEB_RESET      0x0080
-#define DEB_ADDCMD     0x0100
-#define DEB_STATUS     0x0200
-#define DEB_STARTTX    0x0400
-#define DEB_RXADDR     0x0800
-#define DEB_TXADDR     0x1000
-#define DEB_RXFRAME    0x2000
-#define DEB_INTS       0x4000
-#define DEB_STRUCT     0x8000
-#define DEB_ANY                0xffff
-
-
-#define DEB(x, y)      if (i596_debug & (x)) { y; }
-
-
-/*
- * The MPU_PORT command allows direct access to the 82596. With PORT access
- * the following commands are available (p5-18). The 32-bit port command
- * must be word-swapped with the most significant word written first.
- * This only applies to VME boards.
- */
-#define PORT_RESET             0x00    /* reset 82596 */
-#define PORT_SELFTEST          0x01    /* selftest */
-#define PORT_ALTSCP            0x02    /* alternate SCB address */
-#define PORT_ALTDUMP           0x03    /* Alternate DUMP address */
-
-static int i596_debug = (DEB_SERIOUS|DEB_PROBE);
-
-/* Copy frames shorter than rx_copybreak, otherwise pass on up in
- * a full sized sk_buff.  Value of 100 stolen from tulip.c (!alpha).
- */
-static int rx_copybreak = 100;
-
-#define PKT_BUF_SZ     1536
-#define MAX_MC_CNT     64
-
-#define ISCP_BUSY      0x0001
-
-#define I596_NULL ((u32)0xffffffff)
-
-#define CMD_EOL                0x8000  /* The last command of the list, stop. */
-#define CMD_SUSP       0x4000  /* Suspend after doing cmd. */
-#define CMD_INTR       0x2000  /* Interrupt after doing cmd. */
-
-#define CMD_FLEX       0x0008  /* Enable flexible memory model */
-
-enum commands {
-       CmdNOp = 0, CmdSASetup = 1, CmdConfigure = 2, CmdMulticastList = 3,
-       CmdTx = 4, CmdTDR = 5, CmdDump = 6, CmdDiagnose = 7
-};
-
-#define STAT_C         0x8000  /* Set to 0 after execution */
-#define STAT_B         0x4000  /* Command being executed */
-#define STAT_OK                0x2000  /* Command executed ok */
-#define STAT_A         0x1000  /* Command aborted */
-
-#define         CUC_START      0x0100
-#define         CUC_RESUME     0x0200
-#define         CUC_SUSPEND    0x0300
-#define         CUC_ABORT      0x0400
-#define         RX_START       0x0010
-#define         RX_RESUME      0x0020
-#define         RX_SUSPEND     0x0030
-#define         RX_ABORT       0x0040
-
-#define TX_TIMEOUT     (HZ/20)
-
-
-struct i596_reg {
-       unsigned short porthi;
-       unsigned short portlo;
-       u32            ca;
-};
-
-#define EOF            0x8000
-#define SIZE_MASK      0x3fff
-
-struct i596_tbd {
-       unsigned short size;
-       unsigned short pad;
-       u32            next;
-       u32            data;
-       u32 cache_pad[5];               /* Total 32 bytes... */
-};
-
-/* The command structure has two 'next' pointers; v_next is the address of
- * the next command as seen by the CPU, b_next is the address of the next
- * command as seen by the 82596.  The b_next pointer, as used by the 82596
- * always references the status field of the next command, rather than the
- * v_next field, because the 82596 is unaware of v_next.  It may seem more
- * logical to put v_next at the end of the structure, but we cannot do that
- * because the 82596 expects other fields to be there, depending on command
- * type.
- */
-
-struct i596_cmd {
-       struct i596_cmd *v_next;        /* Address from CPUs viewpoint */
-       unsigned short status;
-       unsigned short command;
-       u32            b_next;  /* Address from i596 viewpoint */
-};
-
-struct tx_cmd {
-       struct i596_cmd cmd;
-       u32            tbd;
-       unsigned short size;
-       unsigned short pad;
-       struct sk_buff *skb;            /* So we can free it after tx */
-       dma_addr_t dma_addr;
-#ifdef __LP64__
-       u32 cache_pad[6];               /* Total 64 bytes... */
-#else
-       u32 cache_pad[1];               /* Total 32 bytes... */
-#endif
-};
-
-struct tdr_cmd {
-       struct i596_cmd cmd;
-       unsigned short status;
-       unsigned short pad;
-};
-
-struct mc_cmd {
-       struct i596_cmd cmd;
-       short mc_cnt;
-       char mc_addrs[MAX_MC_CNT*6];
-};
-
-struct sa_cmd {
-       struct i596_cmd cmd;
-       char eth_addr[8];
-};
-
-struct cf_cmd {
-       struct i596_cmd cmd;
-       char i596_config[16];
-};
-
-struct i596_rfd {
-       unsigned short stat;
-       unsigned short cmd;
-       u32            b_next;  /* Address from i596 viewpoint */
-       u32            rbd;
-       unsigned short count;
-       unsigned short size;
-       struct i596_rfd *v_next;        /* Address from CPUs viewpoint */
-       struct i596_rfd *v_prev;
-#ifndef __LP64__
-       u32 cache_pad[2];               /* Total 32 bytes... */
-#endif
-};
-
-struct i596_rbd {
-       /* hardware data */
-       unsigned short count;
-       unsigned short zero1;
-       u32            b_next;
-       u32            b_data;          /* Address from i596 viewpoint */
-       unsigned short size;
-       unsigned short zero2;
-       /* driver data */
-       struct sk_buff *skb;
-       struct i596_rbd *v_next;
-       u32            b_addr;          /* This rbd addr from i596 view */
-       unsigned char *v_data;          /* Address from CPUs viewpoint */
-                                       /* Total 32 bytes... */
-#ifdef __LP64__
-    u32 cache_pad[4];
-#endif
-};
-
-/* These values as chosen so struct i596_dma fits in one page... */
-
-#define TX_RING_SIZE 32
-#define RX_RING_SIZE 16
-
-struct i596_scb {
-       unsigned short status;
-       unsigned short command;
-       u32           cmd;
-       u32           rfd;
-       u32           crc_err;
-       u32           align_err;
-       u32           resource_err;
-       u32           over_err;
-       u32           rcvdt_err;
-       u32           short_err;
-       unsigned short t_on;
-       unsigned short t_off;
-};
-
-struct i596_iscp {
-       u32 stat;
-       u32 scb;
-};
-
-struct i596_scp {
-       u32 sysbus;
-       u32 pad;
-       u32 iscp;
-};
-
-struct i596_dma {
-       struct i596_scp scp                     __attribute__((aligned(32)));
-       volatile struct i596_iscp iscp          __attribute__((aligned(32)));
-       volatile struct i596_scb scb            __attribute__((aligned(32)));
-       struct sa_cmd sa_cmd                    __attribute__((aligned(32)));
-       struct cf_cmd cf_cmd                    __attribute__((aligned(32)));
-       struct tdr_cmd tdr_cmd                  __attribute__((aligned(32)));
-       struct mc_cmd mc_cmd                    __attribute__((aligned(32)));
-       struct i596_rfd rfds[RX_RING_SIZE]      __attribute__((aligned(32)));
-       struct i596_rbd rbds[RX_RING_SIZE]      __attribute__((aligned(32)));
-       struct tx_cmd tx_cmds[TX_RING_SIZE]     __attribute__((aligned(32)));
-       struct i596_tbd tbds[TX_RING_SIZE]      __attribute__((aligned(32)));
-};
-
-struct i596_private {
-       struct i596_dma *dma;
-       u32    stat;
-       int last_restart;
-       struct i596_rfd *rfd_head;
-       struct i596_rbd *rbd_head;
-       struct i596_cmd *cmd_tail;
-       struct i596_cmd *cmd_head;
-       int cmd_backlog;
-       u32    last_cmd;
-       int next_tx_cmd;
-       int options;
-       spinlock_t lock;       /* serialize access to chip */
-       dma_addr_t dma_addr;
-       void __iomem *mpu_port;
-       void __iomem *ca;
-};
-
-static const char init_setup[] =
-{
-       0x8E,           /* length, prefetch on */
-       0xC8,           /* fifo to 8, monitor off */
-       0x80,           /* don't save bad frames */
-       0x2E,           /* No source address insertion, 8 byte preamble */
-       0x00,           /* priority and backoff defaults */
-       0x60,           /* interframe spacing */
-       0x00,           /* slot time LSB */
-       0xf2,           /* slot time and retries */
-       0x00,           /* promiscuous mode */
-       0x00,           /* collision detect */
-       0x40,           /* minimum frame length */
-       0xff,
-       0x00,
-       0x7f /*  *multi IA */ };
-
-static int i596_open(struct net_device *dev);
-static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t i596_interrupt(int irq, void *dev_id);
-static int i596_close(struct net_device *dev);
-static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd);
-static void i596_tx_timeout (struct net_device *dev);
-static void print_eth(unsigned char *buf, char *str);
-static void set_multicast_list(struct net_device *dev);
-static inline void ca(struct net_device *dev);
-static void mpu_port(struct net_device *dev, int c, dma_addr_t x);
-
-static int rx_ring_size = RX_RING_SIZE;
-static int ticks_limit = 100;
-static int max_cmd_backlog = TX_RING_SIZE-1;
-
-#ifdef CONFIG_NET_POLL_CONTROLLER
-static void i596_poll_controller(struct net_device *dev);
-#endif
-
-
-static inline int wait_istat(struct net_device *dev, struct i596_dma *dma, int delcnt, char *str)
-{
-       DMA_INV(dev, &(dma->iscp), sizeof(struct i596_iscp));
-       while (--delcnt && dma->iscp.stat) {
-               udelay(10);
-               DMA_INV(dev, &(dma->iscp), sizeof(struct i596_iscp));
-       }
-       if (!delcnt) {
-               printk(KERN_ERR "%s: %s, iscp.stat %04x, didn't clear\n",
-                    dev->name, str, SWAP16(dma->iscp.stat));
-               return -1;
-       } else
-               return 0;
-}
-
-
-static inline int wait_cmd(struct net_device *dev, struct i596_dma *dma, int delcnt, char *str)
-{
-       DMA_INV(dev, &(dma->scb), sizeof(struct i596_scb));
-       while (--delcnt && dma->scb.command) {
-               udelay(10);
-               DMA_INV(dev, &(dma->scb), sizeof(struct i596_scb));
-       }
-       if (!delcnt) {
-               printk(KERN_ERR "%s: %s, status %4.4x, cmd %4.4x.\n",
-                      dev->name, str,
-                      SWAP16(dma->scb.status),
-                      SWAP16(dma->scb.command));
-               return -1;
-       } else
-               return 0;
-}
-
-
-static void i596_display_data(struct net_device *dev)
-{
-       struct i596_private *lp = netdev_priv(dev);
-       struct i596_dma *dma = lp->dma;
-       struct i596_cmd *cmd;
-       struct i596_rfd *rfd;
-       struct i596_rbd *rbd;
-
-       printk(KERN_DEBUG "lp and scp at %p, .sysbus = %08x, .iscp = %08x\n",
-              &dma->scp, dma->scp.sysbus, SWAP32(dma->scp.iscp));
-       printk(KERN_DEBUG "iscp at %p, iscp.stat = %08x, .scb = %08x\n",
-              &dma->iscp, SWAP32(dma->iscp.stat), SWAP32(dma->iscp.scb));
-       printk(KERN_DEBUG "scb at %p, scb.status = %04x, .command = %04x,"
-               " .cmd = %08x, .rfd = %08x\n",
-              &dma->scb, SWAP16(dma->scb.status), SWAP16(dma->scb.command),
-               SWAP16(dma->scb.cmd), SWAP32(dma->scb.rfd));
-       printk(KERN_DEBUG "   errors: crc %x, align %x, resource %x,"
-              " over %x, rcvdt %x, short %x\n",
-              SWAP32(dma->scb.crc_err), SWAP32(dma->scb.align_err),
-              SWAP32(dma->scb.resource_err), SWAP32(dma->scb.over_err),
-              SWAP32(dma->scb.rcvdt_err), SWAP32(dma->scb.short_err));
-       cmd = lp->cmd_head;
-       while (cmd != NULL) {
-               printk(KERN_DEBUG
-                      "cmd at %p, .status = %04x, .command = %04x,"
-                      " .b_next = %08x\n",
-                      cmd, SWAP16(cmd->status), SWAP16(cmd->command),
-                      SWAP32(cmd->b_next));
-               cmd = cmd->v_next;
-       }
-       rfd = lp->rfd_head;
-       printk(KERN_DEBUG "rfd_head = %p\n", rfd);
-       do {
-               printk(KERN_DEBUG
-                      "   %p .stat %04x, .cmd %04x, b_next %08x, rbd %08x,"
-                      " count %04x\n",
-                      rfd, SWAP16(rfd->stat), SWAP16(rfd->cmd),
-                      SWAP32(rfd->b_next), SWAP32(rfd->rbd),
-                      SWAP16(rfd->count));
-               rfd = rfd->v_next;
-       } while (rfd != lp->rfd_head);
-       rbd = lp->rbd_head;
-       printk(KERN_DEBUG "rbd_head = %p\n", rbd);
-       do {
-               printk(KERN_DEBUG
-                      "   %p .count %04x, b_next %08x, b_data %08x,"
-                      " size %04x\n",
-                       rbd, SWAP16(rbd->count), SWAP32(rbd->b_next),
-                      SWAP32(rbd->b_data), SWAP16(rbd->size));
-               rbd = rbd->v_next;
-       } while (rbd != lp->rbd_head);
-       DMA_INV(dev, dma, sizeof(struct i596_dma));
-}
-
-
-#define virt_to_dma(lp, v) ((lp)->dma_addr + (dma_addr_t)((unsigned long)(v)-(unsigned long)((lp)->dma)))
-
-static inline int init_rx_bufs(struct net_device *dev)
-{
-       struct i596_private *lp = netdev_priv(dev);
-       struct i596_dma *dma = lp->dma;
-       int i;
-       struct i596_rfd *rfd;
-       struct i596_rbd *rbd;
-
-       /* First build the Receive Buffer Descriptor List */
-
-       for (i = 0, rbd = dma->rbds; i < rx_ring_size; i++, rbd++) {
-               dma_addr_t dma_addr;
-               struct sk_buff *skb;
-
-               skb = netdev_alloc_skb_ip_align(dev, PKT_BUF_SZ);
-               if (skb == NULL)
-                       return -1;
-               dma_addr = dma_map_single(dev->dev.parent, skb->data,
-                                         PKT_BUF_SZ, DMA_FROM_DEVICE);
-               rbd->v_next = rbd+1;
-               rbd->b_next = SWAP32(virt_to_dma(lp, rbd+1));
-               rbd->b_addr = SWAP32(virt_to_dma(lp, rbd));
-               rbd->skb = skb;
-               rbd->v_data = skb->data;
-               rbd->b_data = SWAP32(dma_addr);
-               rbd->size = SWAP16(PKT_BUF_SZ);
-       }
-       lp->rbd_head = dma->rbds;
-       rbd = dma->rbds + rx_ring_size - 1;
-       rbd->v_next = dma->rbds;
-       rbd->b_next = SWAP32(virt_to_dma(lp, dma->rbds));
-
-       /* Now build the Receive Frame Descriptor List */
-
-       for (i = 0, rfd = dma->rfds; i < rx_ring_size; i++, rfd++) {
-               rfd->rbd = I596_NULL;
-               rfd->v_next = rfd+1;
-               rfd->v_prev = rfd-1;
-               rfd->b_next = SWAP32(virt_to_dma(lp, rfd+1));
-               rfd->cmd = SWAP16(CMD_FLEX);
-       }
-       lp->rfd_head = dma->rfds;
-       dma->scb.rfd = SWAP32(virt_to_dma(lp, dma->rfds));
-       rfd = dma->rfds;
-       rfd->rbd = SWAP32(virt_to_dma(lp, lp->rbd_head));
-       rfd->v_prev = dma->rfds + rx_ring_size - 1;
-       rfd = dma->rfds + rx_ring_size - 1;
-       rfd->v_next = dma->rfds;
-       rfd->b_next = SWAP32(virt_to_dma(lp, dma->rfds));
-       rfd->cmd = SWAP16(CMD_EOL|CMD_FLEX);
-
-       DMA_WBACK_INV(dev, dma, sizeof(struct i596_dma));
-       return 0;
-}
-
-static inline void remove_rx_bufs(struct net_device *dev)
-{
-       struct i596_private *lp = netdev_priv(dev);
-       struct i596_rbd *rbd;
-       int i;
-
-       for (i = 0, rbd = lp->dma->rbds; i < rx_ring_size; i++, rbd++) {
-               if (rbd->skb == NULL)
-                       break;
-               dma_unmap_single(dev->dev.parent,
-                                (dma_addr_t)SWAP32(rbd->b_data),
-                                PKT_BUF_SZ, DMA_FROM_DEVICE);
-               dev_kfree_skb(rbd->skb);
-       }
-}
-
-
-static void rebuild_rx_bufs(struct net_device *dev)
-{
-       struct i596_private *lp = netdev_priv(dev);
-       struct i596_dma *dma = lp->dma;
-       int i;
-
-       /* Ensure rx frame/buffer descriptors are tidy */
-
-       for (i = 0; i < rx_ring_size; i++) {
-               dma->rfds[i].rbd = I596_NULL;
-               dma->rfds[i].cmd = SWAP16(CMD_FLEX);
-       }
-       dma->rfds[rx_ring_size-1].cmd = SWAP16(CMD_EOL|CMD_FLEX);
-       lp->rfd_head = dma->rfds;
-       dma->scb.rfd = SWAP32(virt_to_dma(lp, dma->rfds));
-       lp->rbd_head = dma->rbds;
-       dma->rfds[0].rbd = SWAP32(virt_to_dma(lp, dma->rbds));
-
-       DMA_WBACK_INV(dev, dma, sizeof(struct i596_dma));
-}
-
-
-static int init_i596_mem(struct net_device *dev)
-{
-       struct i596_private *lp = netdev_priv(dev);
-       struct i596_dma *dma = lp->dma;
-       unsigned long flags;
-
-       mpu_port(dev, PORT_RESET, 0);
-       udelay(100);                    /* Wait 100us - seems to help */
-
-       /* change the scp address */
-
-       lp->last_cmd = jiffies;
-
-       dma->scp.sysbus = SYSBUS;
-       dma->scp.iscp = SWAP32(virt_to_dma(lp, &(dma->iscp)));
-       dma->iscp.scb = SWAP32(virt_to_dma(lp, &(dma->scb)));
-       dma->iscp.stat = SWAP32(ISCP_BUSY);
-       lp->cmd_backlog = 0;
-
-       lp->cmd_head = NULL;
-       dma->scb.cmd = I596_NULL;
-
-       DEB(DEB_INIT, printk(KERN_DEBUG "%s: starting i82596.\n", dev->name));
-
-       DMA_WBACK(dev, &(dma->scp), sizeof(struct i596_scp));
-       DMA_WBACK(dev, &(dma->iscp), sizeof(struct i596_iscp));
-       DMA_WBACK(dev, &(dma->scb), sizeof(struct i596_scb));
-
-       mpu_port(dev, PORT_ALTSCP, virt_to_dma(lp, &dma->scp));
-       ca(dev);
-       if (wait_istat(dev, dma, 1000, "initialization timed out"))
-               goto failed;
-       DEB(DEB_INIT, printk(KERN_DEBUG
-                            "%s: i82596 initialization successful\n",
-                            dev->name));
-
-       if (request_irq(dev->irq, i596_interrupt, 0, "i82596", dev)) {
-               printk(KERN_ERR "%s: IRQ %d not free\n", dev->name, dev->irq);
-               goto failed;
-       }
-
-       /* Ensure rx frame/buffer descriptors are tidy */
-       rebuild_rx_bufs(dev);
-
-       dma->scb.command = 0;
-       DMA_WBACK(dev, &(dma->scb), sizeof(struct i596_scb));
-
-       DEB(DEB_INIT, printk(KERN_DEBUG
-                            "%s: queuing CmdConfigure\n", dev->name));
-       memcpy(dma->cf_cmd.i596_config, init_setup, 14);
-       dma->cf_cmd.cmd.command = SWAP16(CmdConfigure);
-       DMA_WBACK(dev, &(dma->cf_cmd), sizeof(struct cf_cmd));
-       i596_add_cmd(dev, &dma->cf_cmd.cmd);
-
-       DEB(DEB_INIT, printk(KERN_DEBUG "%s: queuing CmdSASetup\n", dev->name));
-       memcpy(dma->sa_cmd.eth_addr, dev->dev_addr, 6);
-       dma->sa_cmd.cmd.command = SWAP16(CmdSASetup);
-       DMA_WBACK(dev, &(dma->sa_cmd), sizeof(struct sa_cmd));
-       i596_add_cmd(dev, &dma->sa_cmd.cmd);
-
-       DEB(DEB_INIT, printk(KERN_DEBUG "%s: queuing CmdTDR\n", dev->name));
-       dma->tdr_cmd.cmd.command = SWAP16(CmdTDR);
-       DMA_WBACK(dev, &(dma->tdr_cmd), sizeof(struct tdr_cmd));
-       i596_add_cmd(dev, &dma->tdr_cmd.cmd);
-
-       spin_lock_irqsave (&lp->lock, flags);
-
-       if (wait_cmd(dev, dma, 1000, "timed out waiting to issue RX_START")) {
-               spin_unlock_irqrestore (&lp->lock, flags);
-               goto failed_free_irq;
-       }
-       DEB(DEB_INIT, printk(KERN_DEBUG "%s: Issuing RX_START\n", dev->name));
-       dma->scb.command = SWAP16(RX_START);
-       dma->scb.rfd = SWAP32(virt_to_dma(lp, dma->rfds));
-       DMA_WBACK(dev, &(dma->scb), sizeof(struct i596_scb));
-
-       ca(dev);
-
-       spin_unlock_irqrestore (&lp->lock, flags);
-       if (wait_cmd(dev, dma, 1000, "RX_START not processed"))
-               goto failed_free_irq;
-       DEB(DEB_INIT, printk(KERN_DEBUG
-                            "%s: Receive unit started OK\n", dev->name));
-       return 0;
-
-failed_free_irq:
-       free_irq(dev->irq, dev);
-failed:
-       printk(KERN_ERR "%s: Failed to initialise 82596\n", dev->name);
-       mpu_port(dev, PORT_RESET, 0);
-       return -1;
-}
-
-
-static inline int i596_rx(struct net_device *dev)
-{
-       struct i596_private *lp = netdev_priv(dev);
-       struct i596_rfd *rfd;
-       struct i596_rbd *rbd;
-       int frames = 0;
-
-       DEB(DEB_RXFRAME, printk(KERN_DEBUG
-                               "i596_rx(), rfd_head %p, rbd_head %p\n",
-                               lp->rfd_head, lp->rbd_head));
-
-
-       rfd = lp->rfd_head;             /* Ref next frame to check */
-
-       DMA_INV(dev, rfd, sizeof(struct i596_rfd));
-       while (rfd->stat & SWAP16(STAT_C)) {    /* Loop while complete frames */
-               if (rfd->rbd == I596_NULL)
-                       rbd = NULL;
-               else if (rfd->rbd == lp->rbd_head->b_addr) {
-                       rbd = lp->rbd_head;
-                       DMA_INV(dev, rbd, sizeof(struct i596_rbd));
-               } else {
-                       printk(KERN_ERR "%s: rbd chain broken!\n", dev->name);
-                       /* XXX Now what? */
-                       rbd = NULL;
-               }
-               DEB(DEB_RXFRAME, printk(KERN_DEBUG
-                                     "  rfd %p, rfd.rbd %08x, rfd.stat %04x\n",
-                                     rfd, rfd->rbd, rfd->stat));
-
-               if (rbd != NULL && (rfd->stat & SWAP16(STAT_OK))) {
-                       /* a good frame */
-                       int pkt_len = SWAP16(rbd->count) & 0x3fff;
-                       struct sk_buff *skb = rbd->skb;
-                       int rx_in_place = 0;
-
-                       DEB(DEB_RXADDR, print_eth(rbd->v_data, "received"));
-                       frames++;
-
-                       /* 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;
-                               dma_addr_t dma_addr;
-
-                               dma_unmap_single(dev->dev.parent,
-                                                (dma_addr_t)SWAP32(rbd->b_data),
-                                                PKT_BUF_SZ, DMA_FROM_DEVICE);
-                               /* Get fresh skbuff to replace filled one. */
-                               newskb = netdev_alloc_skb_ip_align(dev,
-                                                                  PKT_BUF_SZ);
-                               if (newskb == NULL) {
-                                       skb = NULL;     /* drop pkt */
-                                       goto memory_squeeze;
-                               }
-
-                               /* Pass up the skb already on the Rx ring. */
-                               skb_put(skb, pkt_len);
-                               rx_in_place = 1;
-                               rbd->skb = newskb;
-                               dma_addr = dma_map_single(dev->dev.parent,
-                                                         newskb->data,
-                                                         PKT_BUF_SZ,
-                                                         DMA_FROM_DEVICE);
-                               rbd->v_data = newskb->data;
-                               rbd->b_data = SWAP32(dma_addr);
-                               DMA_WBACK_INV(dev, rbd, sizeof(struct i596_rbd));
-                       } else
-                               skb = netdev_alloc_skb_ip_align(dev, pkt_len);
-memory_squeeze:
-                       if (skb == NULL) {
-                               /* XXX tulip.c can defer packets here!! */
-                               printk(KERN_ERR
-                                      "%s: i596_rx Memory squeeze, dropping packet.\n",
-                                      dev->name);
-                               dev->stats.rx_dropped++;
-                       } else {
-                               if (!rx_in_place) {
-                                       /* 16 byte align the data fields */
-                                       dma_sync_single_for_cpu(dev->dev.parent,
-                                                               (dma_addr_t)SWAP32(rbd->b_data),
-                                                               PKT_BUF_SZ, DMA_FROM_DEVICE);
-                                       memcpy(skb_put(skb, pkt_len), rbd->v_data, pkt_len);
-                                       dma_sync_single_for_device(dev->dev.parent,
-                                                                  (dma_addr_t)SWAP32(rbd->b_data),
-                                                                  PKT_BUF_SZ, DMA_FROM_DEVICE);
-                               }
-                               skb->len = pkt_len;
-                               skb->protocol = eth_type_trans(skb, dev);
-                               netif_rx(skb);
-                               dev->stats.rx_packets++;
-                               dev->stats.rx_bytes += pkt_len;
-                       }
-               } else {
-                       DEB(DEB_ERRORS, printk(KERN_DEBUG
-                                              "%s: Error, rfd.stat = 0x%04x\n",
-                                              dev->name, rfd->stat));
-                       dev->stats.rx_errors++;
-                       if (rfd->stat & SWAP16(0x0100))
-                               dev->stats.collisions++;
-                       if (rfd->stat & SWAP16(0x8000))
-                               dev->stats.rx_length_errors++;
-                       if (rfd->stat & SWAP16(0x0001))
-                               dev->stats.rx_over_errors++;
-                       if (rfd->stat & SWAP16(0x0002))
-                               dev->stats.rx_fifo_errors++;
-                       if (rfd->stat & SWAP16(0x0004))
-                               dev->stats.rx_frame_errors++;
-                       if (rfd->stat & SWAP16(0x0008))
-                               dev->stats.rx_crc_errors++;
-                       if (rfd->stat & SWAP16(0x0010))
-                               dev->stats.rx_length_errors++;
-               }
-
-               /* Clear the buffer descriptor count and EOF + F flags */
-
-               if (rbd != NULL && (rbd->count & SWAP16(0x4000))) {
-                       rbd->count = 0;
-                       lp->rbd_head = rbd->v_next;
-                       DMA_WBACK_INV(dev, rbd, sizeof(struct i596_rbd));
-               }
-
-               /* Tidy the frame descriptor, marking it as end of list */
-
-               rfd->rbd = I596_NULL;
-               rfd->stat = 0;
-               rfd->cmd = SWAP16(CMD_EOL|CMD_FLEX);
-               rfd->count = 0;
-
-               /* Update record of next frame descriptor to process */
-
-               lp->dma->scb.rfd = rfd->b_next;
-               lp->rfd_head = rfd->v_next;
-               DMA_WBACK_INV(dev, rfd, sizeof(struct i596_rfd));
-
-               /* Remove end-of-list from old end descriptor */
-
-               rfd->v_prev->cmd = SWAP16(CMD_FLEX);
-               DMA_WBACK_INV(dev, rfd->v_prev, sizeof(struct i596_rfd));
-               rfd = lp->rfd_head;
-               DMA_INV(dev, rfd, sizeof(struct i596_rfd));
-       }
-
-       DEB(DEB_RXFRAME, printk(KERN_DEBUG "frames %d\n", frames));
-
-       return 0;
-}
-
-
-static inline void i596_cleanup_cmd(struct net_device *dev, struct i596_private *lp)
-{
-       struct i596_cmd *ptr;
-
-       while (lp->cmd_head != NULL) {
-               ptr = lp->cmd_head;
-               lp->cmd_head = ptr->v_next;
-               lp->cmd_backlog--;
-
-               switch (SWAP16(ptr->command) & 0x7) {
-               case CmdTx:
-                       {
-                               struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr;
-                               struct sk_buff *skb = tx_cmd->skb;
-                               dma_unmap_single(dev->dev.parent,
-                                                tx_cmd->dma_addr,
-                                                skb->len, DMA_TO_DEVICE);
-
-                               dev_kfree_skb(skb);
-
-                               dev->stats.tx_errors++;
-                               dev->stats.tx_aborted_errors++;
-
-                               ptr->v_next = NULL;
-                               ptr->b_next = I596_NULL;
-                               tx_cmd->cmd.command = 0;  /* Mark as free */
-                               break;
-                       }
-               default:
-                       ptr->v_next = NULL;
-                       ptr->b_next = I596_NULL;
-               }
-               DMA_WBACK_INV(dev, ptr, sizeof(struct i596_cmd));
-       }
-
-       wait_cmd(dev, lp->dma, 100, "i596_cleanup_cmd timed out");
-       lp->dma->scb.cmd = I596_NULL;
-       DMA_WBACK(dev, &(lp->dma->scb), sizeof(struct i596_scb));
-}
-
-
-static inline void i596_reset(struct net_device *dev, struct i596_private *lp)
-{
-       unsigned long flags;
-
-       DEB(DEB_RESET, printk(KERN_DEBUG "i596_reset\n"));
-
-       spin_lock_irqsave (&lp->lock, flags);
-
-       wait_cmd(dev, lp->dma, 100, "i596_reset timed out");
-
-       netif_stop_queue(dev);
-
-       /* FIXME: this command might cause an lpmc */
-       lp->dma->scb.command = SWAP16(CUC_ABORT | RX_ABORT);
-       DMA_WBACK(dev, &(lp->dma->scb), sizeof(struct i596_scb));
-       ca(dev);
-
-       /* wait for shutdown */
-       wait_cmd(dev, lp->dma, 1000, "i596_reset 2 timed out");
-       spin_unlock_irqrestore (&lp->lock, flags);
-
-       i596_cleanup_cmd(dev, lp);
-       i596_rx(dev);
-
-       netif_start_queue(dev);
-       init_i596_mem(dev);
-}
-
-
-static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd)
-{
-       struct i596_private *lp = netdev_priv(dev);
-       struct i596_dma *dma = lp->dma;
-       unsigned long flags;
-
-       DEB(DEB_ADDCMD, printk(KERN_DEBUG "i596_add_cmd cmd_head %p\n",
-                              lp->cmd_head));
-
-       cmd->status = 0;
-       cmd->command |= SWAP16(CMD_EOL | CMD_INTR);
-       cmd->v_next = NULL;
-       cmd->b_next = I596_NULL;
-       DMA_WBACK(dev, cmd, sizeof(struct i596_cmd));
-
-       spin_lock_irqsave (&lp->lock, flags);
-
-       if (lp->cmd_head != NULL) {
-               lp->cmd_tail->v_next = cmd;
-               lp->cmd_tail->b_next = SWAP32(virt_to_dma(lp, &cmd->status));
-               DMA_WBACK(dev, lp->cmd_tail, sizeof(struct i596_cmd));
-       } else {
-               lp->cmd_head = cmd;
-               wait_cmd(dev, dma, 100, "i596_add_cmd timed out");
-               dma->scb.cmd = SWAP32(virt_to_dma(lp, &cmd->status));
-               dma->scb.command = SWAP16(CUC_START);
-               DMA_WBACK(dev, &(dma->scb), sizeof(struct i596_scb));
-               ca(dev);
-       }
-       lp->cmd_tail = cmd;
-       lp->cmd_backlog++;
-
-       spin_unlock_irqrestore (&lp->lock, flags);
-
-       if (lp->cmd_backlog > max_cmd_backlog) {
-               unsigned long tickssofar = jiffies - lp->last_cmd;
-
-               if (tickssofar < ticks_limit)
-                       return;
-
-               printk(KERN_ERR
-                      "%s: command unit timed out, status resetting.\n",
-                      dev->name);
-#if 1
-               i596_reset(dev, lp);
-#endif
-       }
-}
-
-static int i596_open(struct net_device *dev)
-{
-       DEB(DEB_OPEN, printk(KERN_DEBUG
-                            "%s: i596_open() irq %d.\n", dev->name, dev->irq));
-
-       if (init_rx_bufs(dev)) {
-               printk(KERN_ERR "%s: Failed to init rx bufs\n", dev->name);
-               return -EAGAIN;
-       }
-       if (init_i596_mem(dev)) {
-               printk(KERN_ERR "%s: Failed to init memory\n", dev->name);
-               goto out_remove_rx_bufs;
-       }
-       netif_start_queue(dev);
-
-       return 0;
-
-out_remove_rx_bufs:
-       remove_rx_bufs(dev);
-       return -EAGAIN;
-}
-
-static void i596_tx_timeout (struct net_device *dev)
-{
-       struct i596_private *lp = netdev_priv(dev);
-
-       /* Transmitter timeout, serious problems. */
-       DEB(DEB_ERRORS, printk(KERN_DEBUG
-                              "%s: transmit timed out, status resetting.\n",
-                              dev->name));
-
-       dev->stats.tx_errors++;
-
-       /* Try to restart the adaptor */
-       if (lp->last_restart == dev->stats.tx_packets) {
-               DEB(DEB_ERRORS, printk(KERN_DEBUG "Resetting board.\n"));
-               /* Shutdown and restart */
-               i596_reset (dev, lp);
-       } else {
-               /* Issue a channel attention signal */
-               DEB(DEB_ERRORS, printk(KERN_DEBUG "Kicking board.\n"));
-               lp->dma->scb.command = SWAP16(CUC_START | RX_START);
-               DMA_WBACK_INV(dev, &(lp->dma->scb), sizeof(struct i596_scb));
-               ca (dev);
-               lp->last_restart = dev->stats.tx_packets;
-       }
-
-       dev->trans_start = jiffies; /* prevent tx timeout */
-       netif_wake_queue (dev);
-}
-
-
-static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-       struct i596_private *lp = netdev_priv(dev);
-       struct tx_cmd *tx_cmd;
-       struct i596_tbd *tbd;
-       short length = skb->len;
-
-       DEB(DEB_STARTTX, printk(KERN_DEBUG
-                               "%s: i596_start_xmit(%x,%p) called\n",
-                               dev->name, skb->len, skb->data));
-
-       if (length < ETH_ZLEN) {
-               if (skb_padto(skb, ETH_ZLEN))
-                       return NETDEV_TX_OK;
-               length = ETH_ZLEN;
-       }
-
-       netif_stop_queue(dev);
-
-       tx_cmd = lp->dma->tx_cmds + lp->next_tx_cmd;
-       tbd = lp->dma->tbds + lp->next_tx_cmd;
-
-       if (tx_cmd->cmd.command) {
-               DEB(DEB_ERRORS, printk(KERN_DEBUG
-                                      "%s: xmit ring full, dropping packet.\n",
-                                      dev->name));
-               dev->stats.tx_dropped++;
-
-               dev_kfree_skb(skb);
-       } else {
-               if (++lp->next_tx_cmd == TX_RING_SIZE)
-                       lp->next_tx_cmd = 0;
-               tx_cmd->tbd = SWAP32(virt_to_dma(lp, tbd));
-               tbd->next = I596_NULL;
-
-               tx_cmd->cmd.command = SWAP16(CMD_FLEX | CmdTx);
-               tx_cmd->skb = skb;
-
-               tx_cmd->pad = 0;
-               tx_cmd->size = 0;
-               tbd->pad = 0;
-               tbd->size = SWAP16(EOF | length);
-
-               tx_cmd->dma_addr = dma_map_single(dev->dev.parent, skb->data,
-                                                 skb->len, DMA_TO_DEVICE);
-               tbd->data = SWAP32(tx_cmd->dma_addr);
-
-               DEB(DEB_TXADDR, print_eth(skb->data, "tx-queued"));
-               DMA_WBACK_INV(dev, tx_cmd, sizeof(struct tx_cmd));
-               DMA_WBACK_INV(dev, tbd, sizeof(struct i596_tbd));
-               i596_add_cmd(dev, &tx_cmd->cmd);
-
-               dev->stats.tx_packets++;
-               dev->stats.tx_bytes += length;
-       }
-
-       netif_start_queue(dev);
-
-       return NETDEV_TX_OK;
-}
-
-static void print_eth(unsigned char *add, char *str)
-{
-       printk(KERN_DEBUG "i596 0x%p, %pM --> %pM %02X%02X, %s\n",
-              add, add + 6, add, add[12], add[13], str);
-}
-static const struct net_device_ops i596_netdev_ops = {
-       .ndo_open               = i596_open,
-       .ndo_stop               = i596_close,
-       .ndo_start_xmit         = i596_start_xmit,
-       .ndo_set_multicast_list = set_multicast_list,
-       .ndo_tx_timeout         = i596_tx_timeout,
-       .ndo_change_mtu         = eth_change_mtu,
-       .ndo_validate_addr      = eth_validate_addr,
-       .ndo_set_mac_address    = eth_mac_addr,
-#ifdef CONFIG_NET_POLL_CONTROLLER
-       .ndo_poll_controller    = i596_poll_controller,
-#endif
-};
-
-static int __devinit i82596_probe(struct net_device *dev)
-{
-       int i;
-       struct i596_private *lp = netdev_priv(dev);
-       struct i596_dma *dma;
-
-       /* This lot is ensure things have been cache line aligned. */
-       BUILD_BUG_ON(sizeof(struct i596_rfd) != 32);
-       BUILD_BUG_ON(sizeof(struct i596_rbd) &  31);
-       BUILD_BUG_ON(sizeof(struct tx_cmd)   &  31);
-       BUILD_BUG_ON(sizeof(struct i596_tbd) != 32);
-#ifndef __LP64__
-       BUILD_BUG_ON(sizeof(struct i596_dma) > 4096);
-#endif
-
-       if (!dev->base_addr || !dev->irq)
-               return -ENODEV;
-
-       dma = (struct i596_dma *) DMA_ALLOC(dev->dev.parent,
-               sizeof(struct i596_dma), &lp->dma_addr, GFP_KERNEL);
-       if (!dma) {
-               printk(KERN_ERR "%s: Couldn't get shared memory\n", __FILE__);
-               return -ENOMEM;
-       }
-
-       dev->netdev_ops = &i596_netdev_ops;
-       dev->watchdog_timeo = TX_TIMEOUT;
-
-       memset(dma, 0, sizeof(struct i596_dma));
-       lp->dma = dma;
-
-       dma->scb.command = 0;
-       dma->scb.cmd = I596_NULL;
-       dma->scb.rfd = I596_NULL;
-       spin_lock_init(&lp->lock);
-
-       DMA_WBACK_INV(dev, dma, sizeof(struct i596_dma));
-
-       i = register_netdev(dev);
-       if (i) {
-               DMA_FREE(dev->dev.parent, sizeof(struct i596_dma),
-                                   (void *)dma, lp->dma_addr);
-               return i;
-       }
-
-       DEB(DEB_PROBE, printk(KERN_INFO "%s: 82596 at %#3lx, %pM IRQ %d.\n",
-                             dev->name, dev->base_addr, dev->dev_addr,
-                             dev->irq));
-       DEB(DEB_INIT, printk(KERN_INFO
-                            "%s: dma at 0x%p (%d bytes), lp->scb at 0x%p\n",
-                            dev->name, dma, (int)sizeof(struct i596_dma),
-                            &dma->scb));
-
-       return 0;
-}
-
-#ifdef CONFIG_NET_POLL_CONTROLLER
-static void i596_poll_controller(struct net_device *dev)
-{
-       disable_irq(dev->irq);
-       i596_interrupt(dev->irq, dev);
-       enable_irq(dev->irq);
-}
-#endif
-
-static irqreturn_t i596_interrupt(int irq, void *dev_id)
-{
-       struct net_device *dev = dev_id;
-       struct i596_private *lp;
-       struct i596_dma *dma;
-       unsigned short status, ack_cmd = 0;
-
-       lp = netdev_priv(dev);
-       dma = lp->dma;
-
-       spin_lock (&lp->lock);
-
-       wait_cmd(dev, dma, 100, "i596 interrupt, timeout");
-       status = SWAP16(dma->scb.status);
-
-       DEB(DEB_INTS, printk(KERN_DEBUG
-                            "%s: i596 interrupt, IRQ %d, status %4.4x.\n",
-                       dev->name, dev->irq, status));
-
-       ack_cmd = status & 0xf000;
-
-       if (!ack_cmd) {
-               DEB(DEB_ERRORS, printk(KERN_DEBUG
-                                      "%s: interrupt with no events\n",
-                                      dev->name));
-               spin_unlock (&lp->lock);
-               return IRQ_NONE;
-       }
-
-       if ((status & 0x8000) || (status & 0x2000)) {
-               struct i596_cmd *ptr;
-
-               if ((status & 0x8000))
-                       DEB(DEB_INTS,
-                           printk(KERN_DEBUG
-                                  "%s: i596 interrupt completed command.\n",
-                                  dev->name));
-               if ((status & 0x2000))
-                       DEB(DEB_INTS,
-                           printk(KERN_DEBUG
-                                  "%s: i596 interrupt command unit inactive %x.\n",
-                                  dev->name, status & 0x0700));
-
-               while (lp->cmd_head != NULL) {
-                       DMA_INV(dev, lp->cmd_head, sizeof(struct i596_cmd));
-                       if (!(lp->cmd_head->status & SWAP16(STAT_C)))
-                               break;
-
-                       ptr = lp->cmd_head;
-
-                       DEB(DEB_STATUS,
-                           printk(KERN_DEBUG
-                                  "cmd_head->status = %04x, ->command = %04x\n",
-                                  SWAP16(lp->cmd_head->status),
-                                  SWAP16(lp->cmd_head->command)));
-                       lp->cmd_head = ptr->v_next;
-                       lp->cmd_backlog--;
-
-                       switch (SWAP16(ptr->command) & 0x7) {
-                       case CmdTx:
-                           {
-                               struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr;
-                               struct sk_buff *skb = tx_cmd->skb;
-
-                               if (ptr->status & SWAP16(STAT_OK)) {
-                                       DEB(DEB_TXADDR,
-                                           print_eth(skb->data, "tx-done"));
-                               } else {
-                                       dev->stats.tx_errors++;
-                                       if (ptr->status & SWAP16(0x0020))
-                                               dev->stats.collisions++;
-                                       if (!(ptr->status & SWAP16(0x0040)))
-                                               dev->stats.tx_heartbeat_errors++;
-                                       if (ptr->status & SWAP16(0x0400))
-                                               dev->stats.tx_carrier_errors++;
-                                       if (ptr->status & SWAP16(0x0800))
-                                               dev->stats.collisions++;
-                                       if (ptr->status & SWAP16(0x1000))
-                                               dev->stats.tx_aborted_errors++;
-                               }
-                               dma_unmap_single(dev->dev.parent,
-                                                tx_cmd->dma_addr,
-                                                skb->len, DMA_TO_DEVICE);
-                               dev_kfree_skb_irq(skb);
-
-                               tx_cmd->cmd.command = 0; /* Mark free */
-                               break;
-                           }
-                       case CmdTDR:
-                           {
-                               unsigned short status = SWAP16(((struct tdr_cmd *)ptr)->status);
-
-                               if (status & 0x8000) {
-                                       DEB(DEB_ANY,
-                                           printk(KERN_DEBUG "%s: link ok.\n",
-                                                  dev->name));
-                               } else {
-                                       if (status & 0x4000)
-                                               printk(KERN_ERR
-                                                      "%s: Transceiver problem.\n",
-                                                      dev->name);
-                                       if (status & 0x2000)
-                                               printk(KERN_ERR
-                                                      "%s: Termination problem.\n",
-                                                      dev->name);
-                                       if (status & 0x1000)
-                                               printk(KERN_ERR
-                                                      "%s: Short circuit.\n",
-                                                      dev->name);
-
-                                       DEB(DEB_TDR,
-                                           printk(KERN_DEBUG "%s: Time %d.\n",
-                                                  dev->name, status & 0x07ff));
-                               }
-                               break;
-                           }
-                       case CmdConfigure:
-                               /*
-                                * Zap command so set_multicast_list() know
-                                * it is free
-                                */
-                               ptr->command = 0;
-                               break;
-                       }
-                       ptr->v_next = NULL;
-                       ptr->b_next = I596_NULL;
-                       DMA_WBACK(dev, ptr, sizeof(struct i596_cmd));
-                       lp->last_cmd = jiffies;
-               }
-
-               /* This mess is arranging that only the last of any outstanding
-                * commands has the interrupt bit set.  Should probably really
-                * only add to the cmd queue when the CU is stopped.
-                */
-               ptr = lp->cmd_head;
-               while ((ptr != NULL) && (ptr != lp->cmd_tail)) {
-                       struct i596_cmd *prev = ptr;
-
-                       ptr->command &= SWAP16(0x1fff);
-                       ptr = ptr->v_next;
-                       DMA_WBACK_INV(dev, prev, sizeof(struct i596_cmd));
-               }
-
-               if (lp->cmd_head != NULL)
-                       ack_cmd |= CUC_START;
-               dma->scb.cmd = SWAP32(virt_to_dma(lp, &lp->cmd_head->status));
-               DMA_WBACK_INV(dev, &dma->scb, sizeof(struct i596_scb));
-       }
-       if ((status & 0x1000) || (status & 0x4000)) {
-               if ((status & 0x4000))
-                       DEB(DEB_INTS,
-                           printk(KERN_DEBUG
-                                  "%s: i596 interrupt received a frame.\n",
-                                  dev->name));
-               i596_rx(dev);
-               /* Only RX_START if stopped - RGH 07-07-96 */
-               if (status & 0x1000) {
-                       if (netif_running(dev)) {
-                               DEB(DEB_ERRORS,
-                                   printk(KERN_DEBUG
-                                          "%s: i596 interrupt receive unit inactive, status 0x%x\n",
-                                          dev->name, status));
-                               ack_cmd |= RX_START;
-                               dev->stats.rx_errors++;
-                               dev->stats.rx_fifo_errors++;
-                               rebuild_rx_bufs(dev);
-                       }
-               }
-       }
-       wait_cmd(dev, dma, 100, "i596 interrupt, timeout");
-       dma->scb.command = SWAP16(ack_cmd);
-       DMA_WBACK(dev, &dma->scb, sizeof(struct i596_scb));
-
-       /* DANGER: I suspect that some kind of interrupt
-        acknowledgement aside from acking the 82596 might be needed
-        here...  but it's running acceptably without */
-
-       ca(dev);
-
-       wait_cmd(dev, dma, 100, "i596 interrupt, exit timeout");
-       DEB(DEB_INTS, printk(KERN_DEBUG "%s: exiting interrupt.\n", dev->name));
-
-       spin_unlock (&lp->lock);
-       return IRQ_HANDLED;
-}
-
-static int i596_close(struct net_device *dev)
-{
-       struct i596_private *lp = netdev_priv(dev);
-       unsigned long flags;
-
-       netif_stop_queue(dev);
-
-       DEB(DEB_INIT,
-           printk(KERN_DEBUG
-                  "%s: Shutting down ethercard, status was %4.4x.\n",
-                  dev->name, SWAP16(lp->dma->scb.status)));
-
-       spin_lock_irqsave(&lp->lock, flags);
-
-       wait_cmd(dev, lp->dma, 100, "close1 timed out");
-       lp->dma->scb.command = SWAP16(CUC_ABORT | RX_ABORT);
-       DMA_WBACK(dev, &lp->dma->scb, sizeof(struct i596_scb));
-
-       ca(dev);
-
-       wait_cmd(dev, lp->dma, 100, "close2 timed out");
-       spin_unlock_irqrestore(&lp->lock, flags);
-       DEB(DEB_STRUCT, i596_display_data(dev));
-       i596_cleanup_cmd(dev, lp);
-
-       free_irq(dev->irq, dev);
-       remove_rx_bufs(dev);
-
-       return 0;
-}
-
-/*
- *    Set or clear the multicast filter for this adaptor.
- */
-
-static void set_multicast_list(struct net_device *dev)
-{
-       struct i596_private *lp = netdev_priv(dev);
-       struct i596_dma *dma = lp->dma;
-       int config = 0, cnt;
-
-       DEB(DEB_MULTI,
-           printk(KERN_DEBUG
-                  "%s: set multicast list, %d entries, promisc %s, allmulti %s\n",
-                  dev->name, netdev_mc_count(dev),
-                  dev->flags & IFF_PROMISC ? "ON" : "OFF",
-                  dev->flags & IFF_ALLMULTI ? "ON" : "OFF"));
-
-       if ((dev->flags & IFF_PROMISC) &&
-           !(dma->cf_cmd.i596_config[8] & 0x01)) {
-               dma->cf_cmd.i596_config[8] |= 0x01;
-               config = 1;
-       }
-       if (!(dev->flags & IFF_PROMISC) &&
-           (dma->cf_cmd.i596_config[8] & 0x01)) {
-               dma->cf_cmd.i596_config[8] &= ~0x01;
-               config = 1;
-       }
-       if ((dev->flags & IFF_ALLMULTI) &&
-           (dma->cf_cmd.i596_config[11] & 0x20)) {
-               dma->cf_cmd.i596_config[11] &= ~0x20;
-               config = 1;
-       }
-       if (!(dev->flags & IFF_ALLMULTI) &&
-           !(dma->cf_cmd.i596_config[11] & 0x20)) {
-               dma->cf_cmd.i596_config[11] |= 0x20;
-               config = 1;
-       }
-       if (config) {
-               if (dma->cf_cmd.cmd.command)
-                       printk(KERN_INFO
-                              "%s: config change request already queued\n",
-                              dev->name);
-               else {
-                       dma->cf_cmd.cmd.command = SWAP16(CmdConfigure);
-                       DMA_WBACK_INV(dev, &dma->cf_cmd, sizeof(struct cf_cmd));
-                       i596_add_cmd(dev, &dma->cf_cmd.cmd);
-               }
-       }
-
-       cnt = netdev_mc_count(dev);
-       if (cnt > MAX_MC_CNT) {
-               cnt = MAX_MC_CNT;
-               printk(KERN_NOTICE "%s: Only %d multicast addresses supported",
-                       dev->name, cnt);
-       }
-
-       if (!netdev_mc_empty(dev)) {
-               struct netdev_hw_addr *ha;
-               unsigned char *cp;
-               struct mc_cmd *cmd;
-
-               cmd = &dma->mc_cmd;
-               cmd->cmd.command = SWAP16(CmdMulticastList);
-               cmd->mc_cnt = SWAP16(netdev_mc_count(dev) * 6);
-               cp = cmd->mc_addrs;
-               netdev_for_each_mc_addr(ha, dev) {
-                       if (!cnt--)
-                               break;
-                       memcpy(cp, ha->addr, 6);
-                       if (i596_debug > 1)
-                               DEB(DEB_MULTI,
-                                   printk(KERN_DEBUG
-                                          "%s: Adding address %pM\n",
-                                          dev->name, cp));
-                       cp += 6;
-               }
-               DMA_WBACK_INV(dev, &dma->mc_cmd, sizeof(struct mc_cmd));
-               i596_add_cmd(dev, &cmd->cmd);
-       }
-}
diff --git a/drivers/net/lp486e.c b/drivers/net/lp486e.c
deleted file mode 100644 (file)
index 385a953..0000000
+++ /dev/null
@@ -1,1339 +0,0 @@
-/* Intel Professional Workstation/panther ethernet driver */
-/* lp486e.c: A panther 82596 ethernet driver for linux. */
-/*
-    History and copyrights:
-
-    Driver skeleton
-        Written 1993 by Donald Becker.
-        Copyright 1993 United States Government as represented by the Director,
-        National Security Agency.  This software may only be used and
-       distributed according to the terms of the GNU General Public License
-       as modified by SRC, incorporated herein by reference.
-
-        The author may be reached as becker@scyld.com, or C/O
-       Scyld Computing Corporation
-       410 Severn Ave., Suite 210
-       Annapolis MD 21403
-
-    Apricot
-        Written 1994 by Mark Evans.
-        This driver is for the Apricot 82596 bus-master interface
-
-        Modularised 12/94 Mark Evans
-
-    Professional Workstation
-       Derived from apricot.c by Ard van Breemen
-       <ard@murphy.nl>|<ard@cstmel.hobby.nl>|<ard@cstmel.nl.eu.org>
-
-       Credits:
-       Thanks to Murphy Software BV for letting me write this in their time.
-       Well, actually, I get paid doing this...
-       (Also: see http://www.murphy.nl for murphy, and my homepage ~ard for
-       more information on the Professional Workstation)
-
-    Present version
-       aeb@cwi.nl
-*/
-/*
-    There are currently two motherboards that I know of in the
-    professional workstation. The only one that I know is the
-    intel panther motherboard. -- ard
-*/
-/*
-The pws is equipped with an intel 82596. This is a very intelligent controller
-which runs its own micro-code. Communication with the hostprocessor is done
-through linked lists of commands and buffers in the hostprocessors memory.
-A complete description of the 82596 is available from intel. Search for
-a file called "29021806.pdf". It is a complete description of the chip itself.
-To use it for the pws some additions are needed regarding generation of
-the PORT and CA signal, and the interrupt glue needed for a pc.
-I/O map:
-PORT  SIZE ACTION MEANING
-0xCB0    2 WRITE  Lower 16 bits for PORT command
-0xCB2    2 WRITE  Upper 16 bits for PORT command, and issue of PORT command
-0xCB4    1 WRITE  Generation of CA signal
-0xCB8    1 WRITE  Clear interrupt glue
-All other communication is through memory!
-*/
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/bitops.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-
-#define DRV_NAME "lp486e"
-
-/* debug print flags */
-#define LOG_SRCDST    0x80000000
-#define LOG_STATINT   0x40000000
-#define LOG_STARTINT  0x20000000
-
-#define i596_debug debug
-
-static int i596_debug = 0;
-
-static const char * const medianame[] = {
-       "10baseT", "AUI",
-       "10baseT-FD", "AUI-FD",
-};
-
-#define LP486E_TOTAL_SIZE 16
-
-#define I596_NULL (0xffffffff)
-
-#define CMD_EOL                0x8000  /* The last command of the list, stop. */
-#define CMD_SUSP       0x4000  /* Suspend after doing cmd. */
-#define CMD_INTR       0x2000  /* Interrupt after doing cmd. */
-
-#define CMD_FLEX       0x0008  /* Enable flexible memory model */
-
-enum commands {
-       CmdNOP = 0,
-       CmdIASetup = 1,
-       CmdConfigure = 2,
-       CmdMulticastList = 3,
-       CmdTx = 4,
-       CmdTDR = 5,
-       CmdDump = 6,
-       CmdDiagnose = 7
-};
-
-#if 0
-static const char *CUcmdnames[8] = { "NOP", "IASetup", "Configure", "MulticastList",
-                                    "Tx", "TDR", "Dump", "Diagnose" };
-#endif
-
-/* Status word bits */
-#define        STAT_CX         0x8000  /* The CU finished executing a command
-                                  with the Interrupt bit set */
-#define        STAT_FR         0x4000  /* The RU finished receiving a frame */
-#define        STAT_CNA        0x2000  /* The CU left the active state */
-#define        STAT_RNR        0x1000  /* The RU left the active state */
-#define STAT_ACK       (STAT_CX | STAT_FR | STAT_CNA | STAT_RNR)
-#define        STAT_CUS        0x0700  /* Status of CU: 0: idle, 1: suspended,
-                                  2: active, 3-7: unused */
-#define STAT_RUS       0x00f0  /* Status of RU: 0: idle, 1: suspended,
-                                  2: no resources, 4: ready,
-                                  10: no resources due to no more RBDs,
-                                  12: no more RBDs, other: unused */
-#define        STAT_T          0x0008  /* Bus throttle timers loaded */
-#define        STAT_ZERO       0x0807  /* Always zero */
-
-#if 0
-static char *CUstates[8] = {
-       "idle", "suspended", "active", 0, 0, 0, 0, 0
-};
-static char *RUstates[16] = {
-       "idle", "suspended", "no resources", 0, "ready", 0, 0, 0,
-       0, 0, "no RBDs", 0, "out of RBDs", 0, 0, 0
-};
-
-static void
-i596_out_status(int status) {
-       int bad = 0;
-       char *s;
-
-       printk("status %4.4x:", status);
-       if (status == 0xffff)
-               printk(" strange..\n");
-       else {
-               if (status & STAT_CX)
-                       printk("  CU done");
-               if (status & STAT_CNA)
-                       printk("  CU stopped");
-               if (status & STAT_FR)
-                       printk("  got a frame");
-               if (status & STAT_RNR)
-                       printk("  RU stopped");
-               if (status & STAT_T)
-                       printk("  throttled");
-               if (status & STAT_ZERO)
-                       bad = 1;
-               s = CUstates[(status & STAT_CUS) >> 8];
-               if (!s)
-                       bad = 1;
-               else
-                       printk("  CU(%s)", s);
-               s = RUstates[(status & STAT_RUS) >> 4];
-               if (!s)
-                       bad = 1;
-               else
-                       printk("  RU(%s)", s);
-               if (bad)
-                       printk("  bad status");
-               printk("\n");
-       }
-}
-#endif
-
-/* Command word bits */
-#define ACK_CX         0x8000
-#define ACK_FR         0x4000
-#define ACK_CNA                0x2000
-#define ACK_RNR                0x1000
-
-#define CUC_START      0x0100
-#define CUC_RESUME     0x0200
-#define CUC_SUSPEND    0x0300
-#define CUC_ABORT      0x0400
-
-#define RX_START       0x0010
-#define RX_RESUME      0x0020
-#define RX_SUSPEND     0x0030
-#define RX_ABORT       0x0040
-
-typedef u32 phys_addr;
-
-static inline phys_addr
-va_to_pa(void *x) {
-       return x ? virt_to_bus(x) : I596_NULL;
-}
-
-static inline void *
-pa_to_va(phys_addr x) {
-       return (x == I596_NULL) ? NULL : bus_to_virt(x);
-}
-
-/* status bits for cmd */
-#define CMD_STAT_C     0x8000  /* CU command complete */
-#define CMD_STAT_B     0x4000  /* CU command in progress */
-#define CMD_STAT_OK    0x2000  /* CU command completed without errors */
-#define CMD_STAT_A     0x1000  /* CU command abnormally terminated */
-
-struct i596_cmd {              /* 8 bytes */
-       unsigned short status;
-       unsigned short command;
-       phys_addr pa_next;      /* va_to_pa(struct i596_cmd *next) */
-};
-
-#define EOF            0x8000
-#define SIZE_MASK      0x3fff
-
-struct i596_tbd {
-       unsigned short size;
-       unsigned short pad;
-       phys_addr pa_next;      /* va_to_pa(struct i596_tbd *next) */
-       phys_addr pa_data;      /* va_to_pa(char *data) */
-       struct sk_buff *skb;
-};
-
-struct tx_cmd {
-       struct i596_cmd cmd;
-       phys_addr pa_tbd;       /* va_to_pa(struct i596_tbd *tbd) */
-       unsigned short size;
-       unsigned short pad;
-};
-
-/* status bits for rfd */
-#define RFD_STAT_C     0x8000  /* Frame reception complete */
-#define RFD_STAT_B     0x4000  /* Frame reception in progress */
-#define RFD_STAT_OK    0x2000  /* Frame received without errors */
-#define RFD_STATUS     0x1fff
-#define RFD_LENGTH_ERR 0x1000
-#define RFD_CRC_ERR    0x0800
-#define RFD_ALIGN_ERR  0x0400
-#define RFD_NOBUFS_ERR 0x0200
-#define RFD_DMA_ERR    0x0100  /* DMA overrun failure to acquire system bus */
-#define RFD_SHORT_FRAME_ERR    0x0080
-#define RFD_NOEOP_ERR  0x0040
-#define RFD_TRUNC_ERR  0x0020
-#define RFD_MULTICAST  0x0002  /* 0: destination had our address
-                                  1: destination was broadcast/multicast */
-#define RFD_COLLISION  0x0001
-
-/* receive frame descriptor */
-struct i596_rfd {
-       unsigned short stat;
-       unsigned short cmd;
-       phys_addr pa_next;      /* va_to_pa(struct i596_rfd *next) */
-       phys_addr pa_rbd;       /* va_to_pa(struct i596_rbd *rbd) */
-       unsigned short count;
-       unsigned short size;
-       char data[1532];
-};
-
-#define RBD_EL         0x8000
-#define RBD_P          0x4000
-#define RBD_SIZEMASK   0x3fff
-#define RBD_EOF                0x8000
-#define RBD_F          0x4000
-
-/* receive buffer descriptor */
-struct i596_rbd {
-       unsigned short size;
-       unsigned short pad;
-       phys_addr pa_next;      /* va_to_pa(struct i596_tbd *next) */
-       phys_addr pa_data;      /* va_to_pa(char *data) */
-       phys_addr pa_prev;      /* va_to_pa(struct i596_tbd *prev) */
-
-       /* Driver private part */
-       struct sk_buff *skb;
-};
-
-#define RX_RING_SIZE 64
-#define RX_SKBSIZE (ETH_FRAME_LEN+10)
-#define RX_RBD_SIZE 32
-
-/* System Control Block - 40 bytes */
-struct i596_scb {
-       u16 status;             /* 0 */
-       u16 command;            /* 2 */
-       phys_addr pa_cmd;       /* 4 - va_to_pa(struct i596_cmd *cmd) */
-       phys_addr pa_rfd;       /* 8 - va_to_pa(struct i596_rfd *rfd) */
-       u32 crc_err;            /* 12 */
-       u32 align_err;          /* 16 */
-       u32 resource_err;       /* 20 */
-       u32 over_err;           /* 24 */
-       u32 rcvdt_err;          /* 28 */
-       u32 short_err;          /* 32 */
-       u16 t_on;               /* 36 */
-       u16 t_off;              /* 38 */
-};
-
-/* Intermediate System Configuration Pointer - 8 bytes */
-struct i596_iscp {
-       u32 busy;               /* 0 */
-       phys_addr pa_scb;       /* 4 - va_to_pa(struct i596_scb *scb) */
-};
-
-/* System Configuration Pointer - 12 bytes */
-struct i596_scp {
-       u32 sysbus;             /* 0 */
-       u32 pad;                /* 4 */
-       phys_addr pa_iscp;      /* 8 - va_to_pa(struct i596_iscp *iscp) */
-};
-
-/* Selftest and dump results - needs 16-byte alignment */
-/*
- * The size of the dump area is 304 bytes. When the dump is executed
- * by the Port command an extra word will be appended to the dump area.
- * The extra word is a copy of the Dump status word (containing the
- * C, B, OK bits). [I find 0xa006, with a0 for C+OK and 6 for dump]
- */
-struct i596_dump {
-       u16 dump[153];          /* (304 = 130h) + 2 bytes */
-};
-
-struct i596_private {          /* aligned to a 16-byte boundary */
-       struct i596_scp scp;    /* 0 - needs 16-byte alignment */
-       struct i596_iscp iscp;  /* 12 */
-       struct i596_scb scb;    /* 20 */
-       u32 dummy;              /* 60 */
-       struct i596_dump dump;  /* 64 - needs 16-byte alignment */
-
-       struct i596_cmd set_add;
-       char eth_addr[8];       /* directly follows set_add */
-
-       struct i596_cmd set_conf;
-       char i596_config[16];   /* directly follows set_conf */
-
-       struct i596_cmd tdr;
-       unsigned long tdr_stat; /* directly follows tdr */
-
-       int last_restart;
-       struct i596_rbd *rbd_list;
-       struct i596_rbd *rbd_tail;
-       struct i596_rfd *rx_tail;
-       struct i596_cmd *cmd_tail;
-       struct i596_cmd *cmd_head;
-       int cmd_backlog;
-       unsigned long last_cmd;
-       spinlock_t cmd_lock;
-};
-
-static char init_setup[14] = {
-       0x8E,   /* length 14 bytes, prefetch on */
-       0xC8,   /* default: fifo to 8, monitor off */
-       0x40,   /* default: don't save bad frames (apricot.c had 0x80) */
-       0x2E,   /* (default is 0x26)
-                  No source address insertion, 8 byte preamble */
-       0x00,   /* default priority and backoff */
-       0x60,   /* default interframe spacing */
-       0x00,   /* default slot time LSB */
-       0xf2,   /* default slot time and nr of retries */
-       0x00,   /* default various bits
-                  (0: promiscuous mode, 1: broadcast disable,
-                   2: encoding mode, 3: transmit on no CRS,
-                   4: no CRC insertion, 5: CRC type,
-                   6: bit stuffing, 7: padding) */
-       0x00,   /* default carrier sense and collision detect */
-       0x40,   /* default minimum frame length */
-       0xff,   /* (default is 0xff, and that is what apricot.c has;
-                  elp486.c has 0xfb: Enable crc append in memory.) */
-       0x00,   /* default: not full duplex */
-       0x7f    /* (default is 0x3f) multi IA */
-};
-
-static int i596_open(struct net_device *dev);
-static netdev_tx_t i596_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t i596_interrupt(int irq, void *dev_id);
-static int i596_close(struct net_device *dev);
-static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd);
-static void print_eth(char *);
-static void set_multicast_list(struct net_device *dev);
-static void i596_tx_timeout(struct net_device *dev);
-
-static int
-i596_timeout(struct net_device *dev, char *msg, int ct) {
-       struct i596_private *lp;
-       int boguscnt = ct;
-
-       lp = netdev_priv(dev);
-       while (lp->scb.command) {
-               if (--boguscnt == 0) {
-                       printk("%s: %s timed out - stat %4.4x, cmd %4.4x\n",
-                              dev->name, msg,
-                              lp->scb.status, lp->scb.command);
-                       return 1;
-               }
-               udelay(5);
-               barrier();
-       }
-       return 0;
-}
-
-static inline int
-init_rx_bufs(struct net_device *dev, int num) {
-       struct i596_private *lp;
-       struct i596_rfd *rfd;
-       int i;
-       // struct i596_rbd *rbd;
-
-       lp = netdev_priv(dev);
-       lp->scb.pa_rfd = I596_NULL;
-
-       for (i = 0; i < num; i++) {
-               rfd = kmalloc(sizeof(struct i596_rfd), GFP_KERNEL);
-               if (rfd == NULL)
-                       break;
-
-               rfd->stat = 0;
-               rfd->pa_rbd = I596_NULL;
-               rfd->count = 0;
-               rfd->size = 1532;
-               if (i == 0) {
-                       rfd->cmd = CMD_EOL;
-                       lp->rx_tail = rfd;
-               } else {
-                       rfd->cmd = 0;
-               }
-               rfd->pa_next = lp->scb.pa_rfd;
-               lp->scb.pa_rfd = va_to_pa(rfd);
-               lp->rx_tail->pa_next = lp->scb.pa_rfd;
-       }
-
-#if 0
-       for (i = 0; i<RX_RBD_SIZE; i++) {
-               rbd = kmalloc(sizeof(struct i596_rbd), GFP_KERNEL);
-               if (rbd) {
-                       rbd->pad = 0;
-                       rbd->count = 0;
-                       rbd->skb = dev_alloc_skb(RX_SKBSIZE);
-                       if (!rbd->skb) {
-                               printk("dev_alloc_skb failed");
-                       }
-                       rbd->next = rfd->rbd;
-                       if (i) {
-                               rfd->rbd->prev = rbd;
-                               rbd->size = RX_SKBSIZE;
-                       } else {
-                               rbd->size = (RX_SKBSIZE | RBD_EL);
-                               lp->rbd_tail = rbd;
-                       }
-
-                       rfd->rbd = rbd;
-               } else {
-                       printk("Could not kmalloc rbd\n");
-               }
-       }
-       lp->rbd_tail->next = rfd->rbd;
-#endif
-       return i;
-}
-
-static inline void
-remove_rx_bufs(struct net_device *dev) {
-       struct i596_private *lp;
-       struct i596_rfd *rfd;
-
-       lp = netdev_priv(dev);
-       lp->rx_tail->pa_next = I596_NULL;
-
-       do {
-               rfd = pa_to_va(lp->scb.pa_rfd);
-               lp->scb.pa_rfd = rfd->pa_next;
-               kfree(rfd);
-       } while (rfd != lp->rx_tail);
-
-       lp->rx_tail = NULL;
-
-#if 0
-       for (lp->rbd_list) {
-       }
-#endif
-}
-
-#define PORT_RESET              0x00    /* reset 82596 */
-#define PORT_SELFTEST           0x01    /* selftest */
-#define PORT_ALTSCP             0x02    /* alternate SCB address */
-#define PORT_DUMP               0x03    /* dump */
-
-#define IOADDR 0xcb0           /* real constant */
-#define IRQ    10              /* default IRQ - can be changed by ECU */
-
-/* The 82596 requires two 16-bit write cycles for a port command */
-static inline void
-PORT(phys_addr a, unsigned int cmd) {
-       if (a & 0xf)
-               printk("lp486e.c: PORT: address not aligned\n");
-       outw(((a & 0xffff) | cmd), IOADDR);
-       outw(((a>>16) & 0xffff), IOADDR+2);
-}
-
-static inline void
-CA(void) {
-       outb(0, IOADDR+4);
-       udelay(8);
-}
-
-static inline void
-CLEAR_INT(void) {
-       outb(0, IOADDR+8);
-}
-
-#if 0
-/* selftest or dump */
-static void
-i596_port_do(struct net_device *dev, int portcmd, char *cmdname) {
-       struct i596_private *lp = netdev_priv(dev);
-       u16 *outp;
-       int i, m;
-
-       memset((void *)&(lp->dump), 0, sizeof(struct i596_dump));
-       outp = &(lp->dump.dump[0]);
-
-       PORT(va_to_pa(outp), portcmd);
-       mdelay(30);             /* random, unmotivated */
-
-       printk("lp486e i82596 %s result:\n", cmdname);
-       for (m = ARRAY_SIZE(lp->dump.dump); m && lp->dump.dump[m-1] == 0; m--)
-               ;
-       for (i = 0; i < m; i++) {
-               printk(" %04x", lp->dump.dump[i]);
-               if (i%8 == 7)
-                       printk("\n");
-       }
-       printk("\n");
-}
-#endif
-
-static int
-i596_scp_setup(struct net_device *dev) {
-       struct i596_private *lp = netdev_priv(dev);
-       int boguscnt;
-
-       /* Setup SCP, ISCP, SCB */
-       /*
-        * sysbus bits:
-        *  only a single byte is significant - here 0x44
-        *  0x80: big endian mode (details depend on stepping)
-        *  0x40: 1
-        *  0x20: interrupt pin is active low
-        *  0x10: lock function disabled
-        *  0x08: external triggering of bus throttle timers
-        *  0x06: 00: 82586 compat mode, 01: segmented mode, 10: linear mode
-        *  0x01: unused
-        */
-       lp->scp.sysbus = 0x00440000;            /* linear mode */
-       lp->scp.pad = 0;                        /* must be zero */
-       lp->scp.pa_iscp = va_to_pa(&(lp->iscp));
-
-       /*
-        * The CPU sets the ISCP to 1 before it gives the first CA()
-        */
-       lp->iscp.busy = 0x0001;
-       lp->iscp.pa_scb = va_to_pa(&(lp->scb));
-
-       lp->scb.command = 0;
-       lp->scb.status = 0;
-       lp->scb.pa_cmd = I596_NULL;
-       /* lp->scb.pa_rfd has been initialised already */
-
-       lp->last_cmd = jiffies;
-       lp->cmd_backlog = 0;
-       lp->cmd_head = NULL;
-
-       /*
-        * Reset the 82596.
-        * We need to wait 10 systemclock cycles, and
-        * 5 serial clock cycles.
-        */
-       PORT(0, PORT_RESET);    /* address part ignored */
-       udelay(100);
-
-       /*
-        * Before the CA signal is asserted, the default SCP address
-        * (0x00fffff4) can be changed to a 16-byte aligned value
-        */
-       PORT(va_to_pa(&lp->scp), PORT_ALTSCP);  /* change the scp address */
-
-       /*
-        * The initialization procedure begins when a
-        * Channel Attention signal is asserted after a reset.
-        */
-
-       CA();
-
-       /*
-        * The ISCP busy is cleared by the 82596 after the SCB address is read.
-        */
-       boguscnt = 100;
-       while (lp->iscp.busy) {
-               if (--boguscnt == 0) {
-                       /* No i82596 present? */
-                       printk("%s: i82596 initialization timed out\n",
-                              dev->name);
-                       return 1;
-               }
-               udelay(5);
-               barrier();
-       }
-       /* I find here boguscnt==100, so no delay was required. */
-
-       return 0;
-}
-
-static int
-init_i596(struct net_device *dev) {
-       struct i596_private *lp;
-
-       if (i596_scp_setup(dev))
-               return 1;
-
-       lp = netdev_priv(dev);
-       lp->scb.command = 0;
-
-       memcpy ((void *)lp->i596_config, init_setup, 14);
-       lp->set_conf.command = CmdConfigure;
-       i596_add_cmd(dev, (void *)&lp->set_conf);
-
-       memcpy ((void *)lp->eth_addr, dev->dev_addr, 6);
-       lp->set_add.command = CmdIASetup;
-       i596_add_cmd(dev, (struct i596_cmd *)&lp->set_add);
-
-       lp->tdr.command = CmdTDR;
-       i596_add_cmd(dev, (struct i596_cmd *)&lp->tdr);
-
-       if (lp->scb.command && i596_timeout(dev, "i82596 init", 200))
-               return 1;
-
-       lp->scb.command = RX_START;
-       CA();
-
-       barrier();
-
-       if (lp->scb.command && i596_timeout(dev, "Receive Unit start", 100))
-               return 1;
-
-       return 0;
-}
-
-/* Receive a single frame */
-static inline int
-i596_rx_one(struct net_device *dev, struct i596_private *lp,
-           struct i596_rfd *rfd, int *frames) {
-
-       if (rfd->stat & RFD_STAT_OK) {
-               /* a good frame */
-               int pkt_len = (rfd->count & 0x3fff);
-               struct sk_buff *skb = dev_alloc_skb(pkt_len);
-
-               (*frames)++;
-
-               if (rfd->cmd & CMD_EOL)
-                       printk("Received on EOL\n");
-
-               if (skb == NULL) {
-                       printk ("%s: i596_rx Memory squeeze, "
-                               "dropping packet.\n", dev->name);
-                       dev->stats.rx_dropped++;
-                       return 1;
-               }
-
-               memcpy(skb_put(skb,pkt_len), rfd->data, pkt_len);
-
-               skb->protocol = eth_type_trans(skb,dev);
-               netif_rx(skb);
-               dev->stats.rx_packets++;
-       } else {
-#if 0
-               printk("Frame reception error status %04x\n",
-                      rfd->stat);
-#endif
-               dev->stats.rx_errors++;
-               if (rfd->stat & RFD_COLLISION)
-                       dev->stats.collisions++;
-               if (rfd->stat & RFD_SHORT_FRAME_ERR)
-                       dev->stats.rx_length_errors++;
-               if (rfd->stat & RFD_DMA_ERR)
-                       dev->stats.rx_over_errors++;
-               if (rfd->stat & RFD_NOBUFS_ERR)
-                       dev->stats.rx_fifo_errors++;
-               if (rfd->stat & RFD_ALIGN_ERR)
-                       dev->stats.rx_frame_errors++;
-               if (rfd->stat & RFD_CRC_ERR)
-                       dev->stats.rx_crc_errors++;
-               if (rfd->stat & RFD_LENGTH_ERR)
-                       dev->stats.rx_length_errors++;
-       }
-       rfd->stat = rfd->count = 0;
-       return 0;
-}
-
-static int
-i596_rx(struct net_device *dev) {
-       struct i596_private *lp = netdev_priv(dev);
-       struct i596_rfd *rfd;
-       int frames = 0;
-
-       while (1) {
-               rfd = pa_to_va(lp->scb.pa_rfd);
-               if (!rfd) {
-                       printk(KERN_ERR "i596_rx: NULL rfd?\n");
-                       return 0;
-               }
-#if 1
-               if (rfd->stat && !(rfd->stat & (RFD_STAT_C | RFD_STAT_B)))
-                       printk("SF:%p-%04x\n", rfd, rfd->stat);
-#endif
-               if (!(rfd->stat & RFD_STAT_C))
-                       break;          /* next one not ready */
-               if (i596_rx_one(dev, lp, rfd, &frames))
-                       break;          /* out of memory */
-               rfd->cmd = CMD_EOL;
-               lp->rx_tail->cmd = 0;
-               lp->rx_tail = rfd;
-               lp->scb.pa_rfd = rfd->pa_next;
-               barrier();
-       }
-
-       return frames;
-}
-
-static void
-i596_cleanup_cmd(struct net_device *dev) {
-       struct i596_private *lp;
-       struct i596_cmd *cmd;
-
-       lp = netdev_priv(dev);
-       while (lp->cmd_head) {
-               cmd = (struct i596_cmd *)lp->cmd_head;
-
-               lp->cmd_head = pa_to_va(lp->cmd_head->pa_next);
-               lp->cmd_backlog--;
-
-               switch ((cmd->command) & 0x7) {
-                       case CmdTx: {
-                               struct tx_cmd *tx_cmd = (struct tx_cmd *) cmd;
-                               struct i596_tbd * tx_cmd_tbd;
-                               tx_cmd_tbd = pa_to_va(tx_cmd->pa_tbd);
-
-                               dev_kfree_skb_any(tx_cmd_tbd->skb);
-
-                               dev->stats.tx_errors++;
-                               dev->stats.tx_aborted_errors++;
-
-                               cmd->pa_next = I596_NULL;
-                               kfree((unsigned char *)tx_cmd);
-                               netif_wake_queue(dev);
-                               break;
-                       }
-                       case CmdMulticastList: {
-                               // unsigned short count = *((unsigned short *) (ptr + 1));
-
-                               cmd->pa_next = I596_NULL;
-                               kfree((unsigned char *)cmd);
-                               break;
-                       }
-                       default: {
-                               cmd->pa_next = I596_NULL;
-                               break;
-                       }
-               }
-               barrier();
-       }
-
-       if (lp->scb.command && i596_timeout(dev, "i596_cleanup_cmd", 100))
-               ;
-
-       lp->scb.pa_cmd = va_to_pa(lp->cmd_head);
-}
-
-static void i596_reset(struct net_device *dev, struct i596_private *lp, int ioaddr) {
-
-       if (lp->scb.command && i596_timeout(dev, "i596_reset", 100))
-               ;
-
-       netif_stop_queue(dev);
-
-       lp->scb.command = CUC_ABORT | RX_ABORT;
-       CA();
-       barrier();
-
-       /* wait for shutdown */
-       if (lp->scb.command && i596_timeout(dev, "i596_reset(2)", 400))
-               ;
-
-       i596_cleanup_cmd(dev);
-       i596_rx(dev);
-
-       netif_start_queue(dev);
-       /*dev_kfree_skb(skb, FREE_WRITE);*/
-       init_i596(dev);
-}
-
-static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd) {
-       struct i596_private *lp = netdev_priv(dev);
-       int ioaddr = dev->base_addr;
-       unsigned long flags;
-
-       cmd->status = 0;
-       cmd->command |= (CMD_EOL | CMD_INTR);
-       cmd->pa_next = I596_NULL;
-
-       spin_lock_irqsave(&lp->cmd_lock, flags);
-
-       if (lp->cmd_head) {
-               lp->cmd_tail->pa_next = va_to_pa(cmd);
-       } else {
-               lp->cmd_head = cmd;
-               if (lp->scb.command && i596_timeout(dev, "i596_add_cmd", 100))
-                       ;
-               lp->scb.pa_cmd = va_to_pa(cmd);
-               lp->scb.command = CUC_START;
-               CA();
-       }
-       lp->cmd_tail = cmd;
-       lp->cmd_backlog++;
-
-       lp->cmd_head = pa_to_va(lp->scb.pa_cmd);
-       spin_unlock_irqrestore(&lp->cmd_lock, flags);
-
-       if (lp->cmd_backlog > 16) {
-               int tickssofar = jiffies - lp->last_cmd;
-               if (tickssofar < HZ/4)
-                       return;
-
-               printk(KERN_WARNING "%s: command unit timed out, status resetting.\n", dev->name);
-               i596_reset(dev, lp, ioaddr);
-       }
-}
-
-static int i596_open(struct net_device *dev)
-{
-       int i;
-
-       i = request_irq(dev->irq, i596_interrupt, IRQF_SHARED, dev->name, dev);
-       if (i) {
-               printk(KERN_ERR "%s: IRQ %d not free\n", dev->name, dev->irq);
-               return i;
-       }
-
-       if ((i = init_rx_bufs(dev, RX_RING_SIZE)) < RX_RING_SIZE)
-               printk(KERN_ERR "%s: only able to allocate %d receive buffers\n", dev->name, i);
-
-       if (i < 4) {
-               free_irq(dev->irq, dev);
-               return -EAGAIN;
-       }
-       netif_start_queue(dev);
-       init_i596(dev);
-       return 0;                       /* Always succeed */
-}
-
-static netdev_tx_t i596_start_xmit (struct sk_buff *skb, struct net_device *dev) {
-       struct tx_cmd *tx_cmd;
-       short length;
-
-       length = skb->len;
-
-       if (length < ETH_ZLEN) {
-               if (skb_padto(skb, ETH_ZLEN))
-                       return NETDEV_TX_OK;
-               length = ETH_ZLEN;
-       }
-
-       tx_cmd = kmalloc((sizeof (struct tx_cmd) + sizeof (struct i596_tbd)), GFP_ATOMIC);
-       if (tx_cmd == NULL) {
-               printk(KERN_WARNING "%s: i596_xmit Memory squeeze, dropping packet.\n", dev->name);
-               dev->stats.tx_dropped++;
-               dev_kfree_skb (skb);
-       } else {
-               struct i596_tbd *tx_cmd_tbd;
-               tx_cmd_tbd = (struct i596_tbd *) (tx_cmd + 1);
-               tx_cmd->pa_tbd = va_to_pa (tx_cmd_tbd);
-               tx_cmd_tbd->pa_next = I596_NULL;
-
-               tx_cmd->cmd.command = (CMD_FLEX | CmdTx);
-
-               tx_cmd->pad = 0;
-               tx_cmd->size = 0;
-               tx_cmd_tbd->pad = 0;
-               tx_cmd_tbd->size = (EOF | length);
-
-               tx_cmd_tbd->pa_data = va_to_pa (skb->data);
-               tx_cmd_tbd->skb = skb;
-
-               if (i596_debug & LOG_SRCDST)
-                       print_eth (skb->data);
-
-               i596_add_cmd (dev, (struct i596_cmd *) tx_cmd);
-
-               dev->stats.tx_packets++;
-       }
-
-       return NETDEV_TX_OK;
-}
-
-static void
-i596_tx_timeout (struct net_device *dev) {
-       struct i596_private *lp = netdev_priv(dev);
-       int ioaddr = dev->base_addr;
-
-       /* Transmitter timeout, serious problems. */
-       printk(KERN_WARNING "%s: transmit timed out, status resetting.\n", dev->name);
-       dev->stats.tx_errors++;
-
-       /* Try to restart the adaptor */
-       if (lp->last_restart == dev->stats.tx_packets) {
-               printk ("Resetting board.\n");
-
-               /* Shutdown and restart */
-               i596_reset (dev, lp, ioaddr);
-       } else {
-               /* Issue a channel attention signal */
-               printk ("Kicking board.\n");
-               lp->scb.command = (CUC_START | RX_START);
-               CA();
-               lp->last_restart = dev->stats.tx_packets;
-       }
-       netif_wake_queue(dev);
-}
-
-static void print_eth(char *add)
-{
-       int i;
-
-       printk ("Dest  ");
-       for (i = 0; i < 6; i++)
-               printk(" %2.2X", (unsigned char) add[i]);
-       printk ("\n");
-
-       printk ("Source");
-       for (i = 0; i < 6; i++)
-               printk(" %2.2X", (unsigned char) add[i+6]);
-       printk ("\n");
-
-       printk ("type %2.2X%2.2X\n",
-               (unsigned char) add[12], (unsigned char) add[13]);
-}
-
-static const struct net_device_ops i596_netdev_ops = {
-       .ndo_open               = i596_open,
-       .ndo_stop               = i596_close,
-       .ndo_start_xmit         = i596_start_xmit,
-       .ndo_set_multicast_list = set_multicast_list,
-       .ndo_tx_timeout         = i596_tx_timeout,
-       .ndo_change_mtu         = eth_change_mtu,
-       .ndo_set_mac_address    = eth_mac_addr,
-       .ndo_validate_addr      = eth_validate_addr,
-};
-
-static int __init lp486e_probe(struct net_device *dev) {
-       struct i596_private *lp;
-       unsigned char eth_addr[6] = { 0, 0xaa, 0, 0, 0, 0 };
-       unsigned char *bios;
-       int i, j;
-       int ret = -ENOMEM;
-       static int probed;
-
-       if (probed)
-               return -ENODEV;
-       probed++;
-
-       if (!request_region(IOADDR, LP486E_TOTAL_SIZE, DRV_NAME)) {
-               printk(KERN_ERR "lp486e: IO address 0x%x in use\n", IOADDR);
-               return -EBUSY;
-       }
-
-       lp = netdev_priv(dev);
-       spin_lock_init(&lp->cmd_lock);
-
-       /*
-        * Do we really have this thing?
-        */
-       if (i596_scp_setup(dev)) {
-               ret = -ENODEV;
-               goto err_out_kfree;
-       }
-
-       dev->base_addr = IOADDR;
-       dev->irq = IRQ;
-
-
-       /*
-        * How do we find the ethernet address? I don't know.
-        * One possibility is to look at the EISA configuration area
-        * [0xe8000-0xe9fff]. This contains the ethernet address
-        * but not at a fixed address - things depend on setup options.
-        *
-        * If we find no address, or the wrong address, use
-        *   ifconfig eth0 hw ether a1:a2:a3:a4:a5:a6
-        * with the value found in the BIOS setup.
-        */
-       bios = bus_to_virt(0xe8000);
-       for (j = 0; j < 0x2000; j++) {
-               if (bios[j] == 0 && bios[j+1] == 0xaa && bios[j+2] == 0) {
-                       printk("%s: maybe address at BIOS 0x%x:",
-                              dev->name, 0xe8000+j);
-                       for (i = 0; i < 6; i++) {
-                               eth_addr[i] = bios[i+j];
-                               printk(" %2.2X", eth_addr[i]);
-                       }
-                       printk("\n");
-               }
-       }
-
-       printk("%s: lp486e 82596 at %#3lx, IRQ %d,",
-              dev->name, dev->base_addr, dev->irq);
-       for (i = 0; i < 6; i++)
-               printk(" %2.2X", dev->dev_addr[i] = eth_addr[i]);
-       printk("\n");
-
-       /* The LP486E-specific entries in the device structure. */
-       dev->netdev_ops = &i596_netdev_ops;
-       dev->watchdog_timeo = 5*HZ;
-
-#if 0
-       /* selftest reports 0x320925ae - don't know what that means */
-       i596_port_do(dev, PORT_SELFTEST, "selftest");
-       i596_port_do(dev, PORT_DUMP, "dump");
-#endif
-       return 0;
-
-err_out_kfree:
-       release_region(IOADDR, LP486E_TOTAL_SIZE);
-       return ret;
-}
-
-static inline void
-i596_handle_CU_completion(struct net_device *dev,
-                         struct i596_private *lp,
-                         unsigned short status,
-                         unsigned short *ack_cmdp) {
-       struct i596_cmd *cmd;
-       int frames_out = 0;
-       int commands_done = 0;
-       int cmd_val;
-       unsigned long flags;
-
-       spin_lock_irqsave(&lp->cmd_lock, flags);
-       cmd = lp->cmd_head;
-
-       while (lp->cmd_head && (lp->cmd_head->status & CMD_STAT_C)) {
-               cmd = lp->cmd_head;
-
-               lp->cmd_head = pa_to_va(lp->cmd_head->pa_next);
-               lp->cmd_backlog--;
-
-               commands_done++;
-               cmd_val = cmd->command & 0x7;
-#if 0
-               printk("finished CU %s command (%d)\n",
-                      CUcmdnames[cmd_val], cmd_val);
-#endif
-               switch (cmd_val) {
-               case CmdTx:
-               {
-                       struct tx_cmd *tx_cmd;
-                       struct i596_tbd *tx_cmd_tbd;
-
-                       tx_cmd = (struct tx_cmd *) cmd;
-                       tx_cmd_tbd = pa_to_va(tx_cmd->pa_tbd);
-
-                       frames_out++;
-                       if (cmd->status & CMD_STAT_OK) {
-                               if (i596_debug)
-                                       print_eth(pa_to_va(tx_cmd_tbd->pa_data));
-                       } else {
-                               dev->stats.tx_errors++;
-                               if (i596_debug)
-                                       printk("transmission failure:%04x\n",
-                                              cmd->status);
-                               if (cmd->status & 0x0020)
-                                       dev->stats.collisions++;
-                               if (!(cmd->status & 0x0040))
-                                       dev->stats.tx_heartbeat_errors++;
-                               if (cmd->status & 0x0400)
-                                       dev->stats.tx_carrier_errors++;
-                               if (cmd->status & 0x0800)
-                                       dev->stats.collisions++;
-                               if (cmd->status & 0x1000)
-                                       dev->stats.tx_aborted_errors++;
-                       }
-                       dev_kfree_skb_irq(tx_cmd_tbd->skb);
-
-                       cmd->pa_next = I596_NULL;
-                       kfree((unsigned char *)tx_cmd);
-                       netif_wake_queue(dev);
-                       break;
-               }
-
-               case CmdMulticastList:
-                       cmd->pa_next = I596_NULL;
-                       kfree((unsigned char *)cmd);
-                       break;
-
-               case CmdTDR:
-               {
-                       unsigned long status = *((unsigned long *) (cmd + 1));
-                       if (status & 0x8000) {
-                               if (i596_debug)
-                                       printk("%s: link ok.\n", dev->name);
-                       } else {
-                               if (status & 0x4000)
-                                       printk("%s: Transceiver problem.\n",
-                                              dev->name);
-                               if (status & 0x2000)
-                                       printk("%s: Termination problem.\n",
-                                              dev->name);
-                               if (status & 0x1000)
-                                       printk("%s: Short circuit.\n",
-                                              dev->name);
-                               printk("%s: Time %ld.\n",
-                                      dev->name, status & 0x07ff);
-                       }
-               }
-               default:
-                       cmd->pa_next = I596_NULL;
-                       lp->last_cmd = jiffies;
-
-               }
-               barrier();
-       }
-
-       cmd = lp->cmd_head;
-       while (cmd && (cmd != lp->cmd_tail)) {
-               cmd->command &= 0x1fff;
-               cmd = pa_to_va(cmd->pa_next);
-               barrier();
-       }
-
-       if (lp->cmd_head)
-               *ack_cmdp |= CUC_START;
-       lp->scb.pa_cmd = va_to_pa(lp->cmd_head);
-       spin_unlock_irqrestore(&lp->cmd_lock, flags);
-}
-
-static irqreturn_t
-i596_interrupt(int irq, void *dev_instance)
-{
-       struct net_device *dev = dev_instance;
-       struct i596_private *lp = netdev_priv(dev);
-       unsigned short status, ack_cmd = 0;
-       int frames_in = 0;
-
-       /*
-        * The 82596 examines the command, performs the required action,
-        * and then clears the SCB command word.
-        */
-       if (lp->scb.command && i596_timeout(dev, "interrupt", 40))
-               ;
-
-       /*
-        * The status word indicates the status of the 82596.
-        * It is modified only by the 82596.
-        *
-        * [So, we must not clear it. I find often status 0xffff,
-        *  which is not one of the values allowed by the docs.]
-        */
-       status = lp->scb.status;
-#if 0
-       if (i596_debug) {
-               printk("%s: i596 interrupt, ", dev->name);
-               i596_out_status(status);
-       }
-#endif
-       /* Impossible, but it happens - perhaps when we get
-          a receive interrupt but scb.pa_rfd is I596_NULL. */
-       if (status == 0xffff) {
-               printk("%s: i596_interrupt: got status 0xffff\n", dev->name);
-               goto out;
-       }
-
-       ack_cmd = (status & STAT_ACK);
-
-       if (status & (STAT_CX | STAT_CNA))
-               i596_handle_CU_completion(dev, lp, status, &ack_cmd);
-
-       if (status & (STAT_FR | STAT_RNR)) {
-               /* Restart the receive unit when it got inactive somehow */
-               if ((status & STAT_RNR) && netif_running(dev))
-                       ack_cmd |= RX_START;
-
-               if (status & STAT_FR) {
-                       frames_in = i596_rx(dev);
-                       if (!frames_in)
-                               printk("receive frame reported, but no frames\n");
-               }
-       }
-
-       /* acknowledge the interrupt */
-       /*
-       if ((lp->scb.pa_cmd != I596_NULL) && netif_running(dev))
-               ack_cmd |= CUC_START;
-       */
-
-       if (lp->scb.command && i596_timeout(dev, "i596 interrupt", 100))
-               ;
-
-       lp->scb.command = ack_cmd;
-
-       CLEAR_INT();
-       CA();
-
- out:
-       return IRQ_HANDLED;
-}
-
-static int i596_close(struct net_device *dev) {
-       struct i596_private *lp = netdev_priv(dev);
-
-       netif_stop_queue(dev);
-
-       if (i596_debug)
-               printk("%s: Shutting down ethercard, status was %4.4x.\n",
-                      dev->name, lp->scb.status);
-
-       lp->scb.command = (CUC_ABORT | RX_ABORT);
-       CA();
-
-       i596_cleanup_cmd(dev);
-
-       if (lp->scb.command && i596_timeout(dev, "i596_close", 200))
-               ;
-
-       free_irq(dev->irq, dev);
-       remove_rx_bufs(dev);
-
-       return 0;
-}
-
-/*
-*      Set or clear the multicast filter for this adaptor.
-*/
-
-static void set_multicast_list(struct net_device *dev) {
-       struct i596_private *lp = netdev_priv(dev);
-       struct i596_cmd *cmd;
-
-       if (i596_debug > 1)
-               printk ("%s: set multicast list %d\n",
-                       dev->name, netdev_mc_count(dev));
-
-       if (!netdev_mc_empty(dev)) {
-               struct netdev_hw_addr *ha;
-               char *cp;
-               cmd = kmalloc(sizeof(struct i596_cmd) + 2 +
-                             netdev_mc_count(dev) * 6, GFP_ATOMIC);
-               if (cmd == NULL) {
-                       printk (KERN_ERR "%s: set_multicast Memory squeeze.\n", dev->name);
-                       return;
-               }
-               cmd->command = CmdMulticastList;
-               *((unsigned short *) (cmd + 1)) = netdev_mc_count(dev) * 6;
-               cp = ((char *)(cmd + 1))+2;
-               netdev_for_each_mc_addr(ha, dev) {
-                       memcpy(cp, ha->addr, 6);
-                       cp += 6;
-               }
-               if (i596_debug & LOG_SRCDST)
-                       print_eth (((char *)(cmd + 1)) + 2);
-               i596_add_cmd(dev, cmd);
-       } else {
-               if (lp->set_conf.pa_next != I596_NULL) {
-                       return;
-               }
-               if (netdev_mc_empty(dev) &&
-                   !(dev->flags & (IFF_PROMISC | IFF_ALLMULTI))) {
-                       lp->i596_config[8] &= ~0x01;
-               } else {
-                       lp->i596_config[8] |= 0x01;
-               }
-
-               i596_add_cmd(dev, (struct i596_cmd *) &lp->set_conf);
-       }
-}
-
-MODULE_AUTHOR("Ard van Breemen <ard@cstmel.nl.eu.org>");
-MODULE_DESCRIPTION("Intel Panther onboard i82596 driver");
-MODULE_LICENSE("GPL");
-
-static struct net_device *dev_lp486e;
-static int full_duplex;
-static int options;
-static int io = IOADDR;
-static int irq = IRQ;
-
-module_param(debug, int, 0);
-//module_param(max_interrupt_work, int, 0);
-//module_param(reverse_probe, int, 0);
-//module_param(rx_copybreak, int, 0);
-module_param(options, int, 0);
-module_param(full_duplex, int, 0);
-
-static int __init lp486e_init_module(void) {
-       int err;
-       struct net_device *dev = alloc_etherdev(sizeof(struct i596_private));
-       if (!dev)
-               return -ENOMEM;
-
-       dev->irq = irq;
-       dev->base_addr = io;
-       err = lp486e_probe(dev);
-       if (err) {
-               free_netdev(dev);
-               return err;
-       }
-       err = register_netdev(dev);
-       if (err) {
-               release_region(dev->base_addr, LP486E_TOTAL_SIZE);
-               free_netdev(dev);
-               return err;
-       }
-       dev_lp486e = dev;
-       full_duplex = 0;
-       options = 0;
-       return 0;
-}
-
-static void __exit lp486e_cleanup_module(void) {
-       unregister_netdev(dev_lp486e);
-       release_region(dev_lp486e->base_addr, LP486E_TOTAL_SIZE);
-       free_netdev(dev_lp486e);
-}
-
-module_init(lp486e_init_module);
-module_exit(lp486e_cleanup_module);
diff --git a/drivers/net/ni52.c b/drivers/net/ni52.c
deleted file mode 100644 (file)
index d973fc6..0000000
+++ /dev/null
@@ -1,1346 +0,0 @@
-/*
- * net-3-driver for the NI5210 card (i82586 Ethernet chip)
- *
- * This is an extension to the Linux operating system, and is covered by the
- * same GNU General Public License that covers that work.
- *
- * Alphacode 0.82 (96/09/29) for Linux 2.0.0 (or later)
- * Copyrights (c) 1994,1995,1996 by M.Hipp (hippm@informatik.uni-tuebingen.de)
- *    [feel free to mail ....]
- *
- * when using as module: (no autoprobing!)
- *   run with e.g:
- *       insmod ni52.o io=0x360 irq=9 memstart=0xd0000 memend=0xd4000
- *
- * CAN YOU PLEASE REPORT ME YOUR PERFORMANCE EXPERIENCES !!.
- *
- * If you find a bug, please report me:
- *   The kernel panic output and any kmsg from the ni52 driver
- *   the ni5210-driver-version and the linux-kernel version
- *   how many shared memory (memsize) on the netcard,
- *   bootprom: yes/no, base_addr, mem_start
- *   maybe the ni5210-card revision and the i82586 version
- *
- * autoprobe for: base_addr: 0x300,0x280,0x360,0x320,0x340
- *                mem_start: 0xd0000,0xd2000,0xc8000,0xca000,0xd4000,0xd6000,
- *                           0xd8000,0xcc000,0xce000,0xda000,0xdc000
- *
- * sources:
- *   skeleton.c from Donald Becker
- *
- * I have also done a look in the following sources: (mail me if you need them)
- *   crynwr-packet-driver by Russ Nelson
- *   Garret A. Wollman's (fourth) i82586-driver for BSD
- *   (before getting an i82596 (yes 596 not 586) manual, the existing drivers
- *    helped me a lot to understand this tricky chip.)
- *
- * Known Problems:
- *   The internal sysbus seems to be slow. So we often lose packets because of
- *   overruns while receiving from a fast remote host.
- *   This can slow down TCP connections. Maybe the newer ni5210 cards are
- *   better. My experience is, that if a machine sends with more than about
- *   500-600K/s the fifo/sysbus overflows.
- *
- * IMPORTANT NOTE:
- *   On fast networks, it's a (very) good idea to have 16K shared memory. With
- *   8K, we can store only 4 receive frames, so it can (easily) happen that a
- *   remote machine 'overruns' our system.
- *
- * Known i82586/card problems (I'm sure, there are many more!):
- *   Running the NOP-mode, the i82586 sometimes seems to forget to report
- *   every xmit-interrupt until we restart the CU.
- *   Another MAJOR bug is, that the RU sometimes seems to ignore the EL-Bit
- *   in the RBD-Struct which indicates an end of the RBD queue.
- *   Instead, the RU fetches another (randomly selected and
- *   usually used) RBD and begins to fill it. (Maybe, this happens only if
- *   the last buffer from the previous RFD fits exact into the queue and
- *   the next RFD can't fetch an initial RBD. Anyone knows more? )
- *
- * results from ftp performance tests with Linux 1.2.5
- *   send and receive about 350-400 KByte/s (peak up to 460 kbytes/s)
- *   sending in NOP-mode: peak performance up to 530K/s (but better don't
- *   run this mode)
- */
-
-/*
- * 29.Sept.96: virt_to_bus changes for new memory scheme
- * 19.Feb.96: more Mcast changes, module support (MH)
- *
- * 18.Nov.95: Mcast changes (AC).
- *
- * 23.April.95: fixed(?) receiving problems by configuring a RFD more
- *              than the number of RBD's. Can maybe cause other problems.
- * 18.April.95: Added MODULE support (MH)
- * 17.April.95: MC related changes in init586() and set_multicast_list().
- *              removed use of 'jiffies' in init586() (MH)
- *
- * 19.Sep.94: Added Multicast support (not tested yet) (MH)
- *
- * 18.Sep.94: Workaround for 'EL-Bug'. Removed flexible RBD-handling.
- *            Now, every RFD has exact one RBD. (MH)
- *
- * 14.Sep.94: added promiscuous mode, a few cleanups (MH)
- *
- * 19.Aug.94: changed request_irq() parameter (MH)
- *
- * 20.July.94: removed cleanup bugs, removed a 16K-mem-probe-bug (MH)
- *
- * 19.July.94: lotsa cleanups .. (MH)
- *
- * 17.July.94: some patches ... verified to run with 1.1.29 (MH)
- *
- * 4.July.94: patches for Linux 1.1.24  (MH)
- *
- * 26.March.94: patches for Linux 1.0 and iomem-auto-probe (MH)
- *
- * 30.Sep.93: Added nop-chain .. driver now runs with only one Xmit-Buff,
- *                             too (MH)
- *
- * < 30.Sep.93: first versions
- */
-
-static int debuglevel; /* debug-printk 0: off 1: a few 2: more */
-static int automatic_resume; /* experimental .. better should be zero */
-static int rfdadd;     /* rfdadd=1 may be better for 8K MEM cards */
-static int fifo = 0x8; /* don't change */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/bitops.h>
-#include <asm/io.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-
-#include "ni52.h"
-
-#define DRV_NAME "ni52"
-
-#define DEBUG       /* debug on */
-#define SYSBUSVAL 1 /* 8 Bit */
-
-#define ni_attn586()  { outb(0, dev->base_addr + NI52_ATTENTION); }
-#define ni_reset586() { outb(0, dev->base_addr + NI52_RESET); }
-#define ni_disint()   { outb(0, dev->base_addr + NI52_INTDIS); }
-#define ni_enaint()   { outb(0, dev->base_addr + NI52_INTENA); }
-
-#define make32(ptr16) ((void __iomem *)(p->memtop + (short) (ptr16)))
-#define make24(ptr32) ((char __iomem *)(ptr32)) - p->base
-#define make16(ptr32) ((unsigned short) ((char __iomem *)(ptr32)\
-                                       - p->memtop))
-
-/******************* how to calculate the buffers *****************************
-
-  * IMPORTANT NOTE: if you configure only one NUM_XMIT_BUFFS, the driver works
-  * --------------- in a different (more stable?) mode. Only in this mode it's
-  *                 possible to configure the driver with 'NO_NOPCOMMANDS'
-
-sizeof(scp)=12; sizeof(scb)=16; sizeof(iscp)=8;
-sizeof(scp)+sizeof(iscp)+sizeof(scb) = 36 = INIT
-sizeof(rfd) = 24; sizeof(rbd) = 12;
-sizeof(tbd) = 8; sizeof(transmit_cmd) = 16;
-sizeof(nop_cmd) = 8;
-
-  * if you don't know the driver, better do not change these values: */
-
-#define RECV_BUFF_SIZE 1524 /* slightly oversized */
-#define XMIT_BUFF_SIZE 1524 /* slightly oversized */
-#define NUM_XMIT_BUFFS 1    /* config for both, 8K and 16K shmem */
-#define NUM_RECV_BUFFS_8  4 /* config for 8K shared mem */
-#define NUM_RECV_BUFFS_16 9 /* config for 16K shared mem */
-#define NO_NOPCOMMANDS      /* only possible with NUM_XMIT_BUFFS=1 */
-
-/**************************************************************************/
-
-
-#define NI52_TOTAL_SIZE 16
-#define NI52_ADDR0 0x02
-#define NI52_ADDR1 0x07
-#define NI52_ADDR2 0x01
-
-static int     ni52_probe1(struct net_device *dev, int ioaddr);
-static irqreturn_t ni52_interrupt(int irq, void *dev_id);
-static int     ni52_open(struct net_device *dev);
-static int     ni52_close(struct net_device *dev);
-static netdev_tx_t ni52_send_packet(struct sk_buff *, struct net_device *);
-static struct  net_device_stats *ni52_get_stats(struct net_device *dev);
-static void    set_multicast_list(struct net_device *dev);
-static void    ni52_timeout(struct net_device *dev);
-
-/* helper-functions */
-static int     init586(struct net_device *dev);
-static int     check586(struct net_device *dev, unsigned size);
-static void    alloc586(struct net_device *dev);
-static void    startrecv586(struct net_device *dev);
-static void   __iomem *alloc_rfa(struct net_device *dev, void __iomem *ptr);
-static void    ni52_rcv_int(struct net_device *dev);
-static void    ni52_xmt_int(struct net_device *dev);
-static void    ni52_rnr_int(struct net_device *dev);
-
-struct priv {
-       char __iomem *base;
-       char __iomem *mapped;
-       char __iomem *memtop;
-       spinlock_t spinlock;
-       int reset;
-       struct rfd_struct __iomem *rfd_last, *rfd_top, *rfd_first;
-       struct scp_struct __iomem *scp;
-       struct iscp_struct __iomem *iscp;
-       struct scb_struct __iomem *scb;
-       struct tbd_struct __iomem *xmit_buffs[NUM_XMIT_BUFFS];
-#if (NUM_XMIT_BUFFS == 1)
-       struct transmit_cmd_struct __iomem *xmit_cmds[2];
-       struct nop_cmd_struct __iomem *nop_cmds[2];
-#else
-       struct transmit_cmd_struct __iomem *xmit_cmds[NUM_XMIT_BUFFS];
-       struct nop_cmd_struct __iomem *nop_cmds[NUM_XMIT_BUFFS];
-#endif
-       int nop_point, num_recv_buffs;
-       char __iomem *xmit_cbuffs[NUM_XMIT_BUFFS];
-       int xmit_count, xmit_last;
-};
-
-/* wait for command with timeout: */
-static void wait_for_scb_cmd(struct net_device *dev)
-{
-       struct priv *p = netdev_priv(dev);
-       int i;
-       for (i = 0; i < 16384; i++) {
-               if (readb(&p->scb->cmd_cuc) == 0)
-                     break;
-               udelay(4);
-               if (i == 16383) {
-                       printk(KERN_ERR "%s: scb_cmd timed out: %04x,%04x .. disabling i82586!!\n",
-                               dev->name, readb(&p->scb->cmd_cuc), readb(&p->scb->cus));
-                       if (!p->reset) {
-                               p->reset = 1;
-                               ni_reset586();
-                       }
-               }
-       }
-}
-
-static void wait_for_scb_cmd_ruc(struct net_device *dev)
-{
-       struct priv *p = netdev_priv(dev);
-       int i;
-       for (i = 0; i < 16384; i++) {
-               if (readb(&p->scb->cmd_ruc) == 0)
-                       break;
-               udelay(4);
-               if (i == 16383) {
-                       printk(KERN_ERR "%s: scb_cmd (ruc) timed out: %04x,%04x .. disabling i82586!!\n",
-                               dev->name, readb(&p->scb->cmd_ruc),
-                               readb(&p->scb->rus));
-                       if (!p->reset) {
-                               p->reset = 1;
-                               ni_reset586();
-                       }
-               }
-       }
-}
-
-static void wait_for_stat_compl(void __iomem *p)
-{
-       struct nop_cmd_struct __iomem *addr = p;
-       int i;
-       for (i = 0; i < 32767; i++) {
-               if (readw(&((addr)->cmd_status)) & STAT_COMPL)
-                       break;
-               udelay(32);
-       }
-}
-
-/**********************************************
- * close device
- */
-static int ni52_close(struct net_device *dev)
-{
-       free_irq(dev->irq, dev);
-       ni_reset586(); /* the hard way to stop the receiver */
-       netif_stop_queue(dev);
-       return 0;
-}
-
-/**********************************************
- * open device
- */
-static int ni52_open(struct net_device *dev)
-{
-       int ret;
-
-       ni_disint();
-       alloc586(dev);
-       init586(dev);
-       startrecv586(dev);
-       ni_enaint();
-
-       ret = request_irq(dev->irq, ni52_interrupt, 0, dev->name, dev);
-       if (ret) {
-               ni_reset586();
-               return ret;
-       }
-       netif_start_queue(dev);
-       return 0; /* most done by init */
-}
-
-static int check_iscp(struct net_device *dev, void __iomem *addr)
-{
-       struct iscp_struct __iomem *iscp = addr;
-       struct priv *p = netdev_priv(dev);
-       memset_io(iscp, 0, sizeof(struct iscp_struct));
-
-       writel(make24(iscp), &p->scp->iscp);
-       writeb(1, &iscp->busy);
-
-       ni_reset586();
-       ni_attn586();
-       mdelay(32);     /* wait a while... */
-       /* i82586 clears 'busy' after successful init */
-       if (readb(&iscp->busy))
-               return 0;
-       return 1;
-}
-
-/**********************************************
- * Check to see if there's an 82586 out there.
- */
-static int check586(struct net_device *dev, unsigned size)
-{
-       struct priv *p = netdev_priv(dev);
-       int i;
-
-       p->mapped = ioremap(dev->mem_start, size);
-       if (!p->mapped)
-               return 0;
-
-       p->base = p->mapped + size - 0x01000000;
-       p->memtop = p->mapped + size;
-       p->scp = (struct scp_struct __iomem *)(p->base + SCP_DEFAULT_ADDRESS);
-       p->scb  = (struct scb_struct __iomem *) p->mapped;
-       p->iscp = (struct iscp_struct __iomem *)p->scp - 1;
-       memset_io(p->scp, 0, sizeof(struct scp_struct));
-       for (i = 0; i < sizeof(struct scp_struct); i++)
-               /* memory was writeable? */
-               if (readb((char __iomem *)p->scp + i))
-                       goto Enodev;
-       writeb(SYSBUSVAL, &p->scp->sysbus);     /* 1 = 8Bit-Bus, 0 = 16 Bit */
-       if (readb(&p->scp->sysbus) != SYSBUSVAL)
-               goto Enodev;
-
-       if (!check_iscp(dev, p->mapped))
-               goto Enodev;
-       if (!check_iscp(dev, p->iscp))
-               goto Enodev;
-       return 1;
-Enodev:
-       iounmap(p->mapped);
-       return 0;
-}
-
-/******************************************************************
- * set iscp at the right place, called by ni52_probe1 and open586.
- */
-static void alloc586(struct net_device *dev)
-{
-       struct priv *p = netdev_priv(dev);
-
-       ni_reset586();
-       mdelay(32);
-
-       memset_io(p->iscp, 0, sizeof(struct iscp_struct));
-       memset_io(p->scp , 0, sizeof(struct scp_struct));
-
-       writel(make24(p->iscp), &p->scp->iscp);
-       writeb(SYSBUSVAL, &p->scp->sysbus);
-       writew(make16(p->scb), &p->iscp->scb_offset);
-
-       writeb(1, &p->iscp->busy);
-       ni_reset586();
-       ni_attn586();
-
-       mdelay(32);
-
-       if (readb(&p->iscp->busy))
-               printk(KERN_ERR "%s: Init-Problems (alloc).\n", dev->name);
-
-       p->reset = 0;
-
-       memset_io(p->scb, 0, sizeof(struct scb_struct));
-}
-
-/* set: io,irq,memstart,memend or set it when calling insmod */
-static int irq = 9;
-static int io = 0x300;
-static long memstart;  /* e.g 0xd0000 */
-static long memend;    /* e.g 0xd4000 */
-
-/**********************************************
- * probe the ni5210-card
- */
-struct net_device * __init ni52_probe(int unit)
-{
-       struct net_device *dev = alloc_etherdev(sizeof(struct priv));
-       static const int ports[] = {0x300, 0x280, 0x360, 0x320, 0x340, 0};
-       const int *port;
-       struct priv *p;
-       int err = 0;
-
-       if (!dev)
-               return ERR_PTR(-ENOMEM);
-
-       p = netdev_priv(dev);
-
-       if (unit >= 0) {
-               sprintf(dev->name, "eth%d", unit);
-               netdev_boot_setup_check(dev);
-               io = dev->base_addr;
-               irq = dev->irq;
-               memstart = dev->mem_start;
-               memend = dev->mem_end;
-       }
-
-       if (io > 0x1ff) {       /* Check a single specified location. */
-               err = ni52_probe1(dev, io);
-       } else if (io > 0) {            /* Don't probe at all. */
-               err = -ENXIO;
-       } else {
-               for (port = ports; *port && ni52_probe1(dev, *port) ; port++)
-                       ;
-               if (*port)
-                       goto got_it;
-#ifdef FULL_IO_PROBE
-               for (io = 0x200; io < 0x400 && ni52_probe1(dev, io); io += 8)
-                       ;
-               if (io < 0x400)
-                       goto got_it;
-#endif
-               err = -ENODEV;
-       }
-       if (err)
-               goto out;
-got_it:
-       err = register_netdev(dev);
-       if (err)
-               goto out1;
-       return dev;
-out1:
-       iounmap(p->mapped);
-       release_region(dev->base_addr, NI52_TOTAL_SIZE);
-out:
-       free_netdev(dev);
-       return ERR_PTR(err);
-}
-
-static const struct net_device_ops ni52_netdev_ops = {
-       .ndo_open               = ni52_open,
-       .ndo_stop               = ni52_close,
-       .ndo_get_stats          = ni52_get_stats,
-       .ndo_tx_timeout         = ni52_timeout,
-       .ndo_start_xmit         = ni52_send_packet,
-       .ndo_set_multicast_list = set_multicast_list,
-       .ndo_change_mtu         = eth_change_mtu,
-       .ndo_set_mac_address    = eth_mac_addr,
-       .ndo_validate_addr      = eth_validate_addr,
-};
-
-static int __init ni52_probe1(struct net_device *dev, int ioaddr)
-{
-       int i, size, retval;
-       struct priv *priv = netdev_priv(dev);
-
-       dev->base_addr = ioaddr;
-       dev->irq = irq;
-       dev->mem_start = memstart;
-       dev->mem_end = memend;
-
-       spin_lock_init(&priv->spinlock);
-
-       if (!request_region(ioaddr, NI52_TOTAL_SIZE, DRV_NAME))
-               return -EBUSY;
-
-       if (!(inb(ioaddr+NI52_MAGIC1) == NI52_MAGICVAL1) ||
-           !(inb(ioaddr+NI52_MAGIC2) == NI52_MAGICVAL2)) {
-               retval = -ENODEV;
-               goto out;
-       }
-
-       for (i = 0; i < ETH_ALEN; i++)
-               dev->dev_addr[i] = inb(dev->base_addr+i);
-
-       if (dev->dev_addr[0] != NI52_ADDR0 || dev->dev_addr[1] != NI52_ADDR1 ||
-           dev->dev_addr[2] != NI52_ADDR2) {
-               retval = -ENODEV;
-               goto out;
-       }
-
-       printk(KERN_INFO "%s: NI5210 found at %#3lx, ",
-                               dev->name, dev->base_addr);
-
-       /*
-        * check (or search) IO-Memory, 8K and 16K
-        */
-#ifdef MODULE
-       size = dev->mem_end - dev->mem_start;
-       if (size != 0x2000 && size != 0x4000) {
-               printk("\n");
-               printk(KERN_ERR "%s: Invalid memory size %d. Allowed is 0x2000 or 0x4000 bytes.\n", dev->name, size);
-               retval = -ENODEV;
-               goto out;
-       }
-       if (!check586(dev, size)) {
-               printk(KERN_ERR "?memcheck, Can't find memory at 0x%lx with size %d!\n", dev->mem_start, size);
-               retval = -ENODEV;
-               goto out;
-       }
-#else
-       if (dev->mem_start != 0) {
-               /* no auto-mem-probe */
-               size = 0x4000; /* check for 16K mem */
-               if (!check586(dev, size)) {
-                       size = 0x2000; /* check for 8K mem */
-                       if (!check586(dev, size)) {
-                               printk(KERN_ERR "?memprobe, Can't find memory at 0x%lx!\n", dev->mem_start);
-                               retval = -ENODEV;
-                               goto out;
-                       }
-               }
-       } else {
-               static const unsigned long memaddrs[] = {
-                       0xc8000, 0xca000, 0xcc000, 0xce000, 0xd0000, 0xd2000,
-                       0xd4000, 0xd6000, 0xd8000, 0xda000, 0xdc000, 0
-               };
-               for (i = 0;; i++) {
-                       if (!memaddrs[i]) {
-                               printk(KERN_ERR "?memprobe, Can't find io-memory!\n");
-                               retval = -ENODEV;
-                               goto out;
-                       }
-                       dev->mem_start = memaddrs[i];
-                       size = 0x2000; /* check for 8K mem */
-                       if (check586(dev, size))
-                               /* 8K-check */
-                               break;
-                       size = 0x4000; /* check for 16K mem */
-                       if (check586(dev, size))
-                               /* 16K-check */
-                               break;
-               }
-       }
-       /* set mem_end showed by 'ifconfig' */
-       dev->mem_end = dev->mem_start + size;
-#endif
-
-       alloc586(dev);
-
-       /* set number of receive-buffs according to memsize */
-       if (size == 0x2000)
-               priv->num_recv_buffs = NUM_RECV_BUFFS_8;
-       else
-               priv->num_recv_buffs = NUM_RECV_BUFFS_16;
-
-       printk(KERN_DEBUG "Memaddr: 0x%lx, Memsize: %d, ",
-                               dev->mem_start, size);
-
-       if (dev->irq < 2) {
-               unsigned long irq_mask;
-
-               irq_mask = probe_irq_on();
-               ni_reset586();
-               ni_attn586();
-
-               mdelay(20);
-               dev->irq = probe_irq_off(irq_mask);
-               if (!dev->irq) {
-                       printk("?autoirq, Failed to detect IRQ line!\n");
-                       retval = -EAGAIN;
-                       iounmap(priv->mapped);
-                       goto out;
-               }
-               printk("IRQ %d (autodetected).\n", dev->irq);
-       } else {
-               if (dev->irq == 2)
-                       dev->irq = 9;
-               printk("IRQ %d (assigned and not checked!).\n", dev->irq);
-       }
-
-       dev->netdev_ops         = &ni52_netdev_ops;
-       dev->watchdog_timeo     = HZ/20;
-
-       return 0;
-out:
-       release_region(ioaddr, NI52_TOTAL_SIZE);
-       return retval;
-}
-
-/**********************************************
- * init the chip (ni52-interrupt should be disabled?!)
- * needs a correct 'allocated' memory
- */
-
-static int init586(struct net_device *dev)
-{
-       void __iomem *ptr;
-       int i, result = 0;
-       struct priv *p = netdev_priv(dev);
-       struct configure_cmd_struct __iomem *cfg_cmd;
-       struct iasetup_cmd_struct __iomem *ias_cmd;
-       struct tdr_cmd_struct __iomem *tdr_cmd;
-       struct mcsetup_cmd_struct __iomem *mc_cmd;
-       struct netdev_hw_addr *ha;
-       int num_addrs = netdev_mc_count(dev);
-
-       ptr = p->scb + 1;
-
-       cfg_cmd = ptr; /* configure-command */
-       writew(0, &cfg_cmd->cmd_status);
-       writew(CMD_CONFIGURE | CMD_LAST, &cfg_cmd->cmd_cmd);
-       writew(0xFFFF, &cfg_cmd->cmd_link);
-
-       /* number of cfg bytes */
-       writeb(0x0a, &cfg_cmd->byte_cnt);
-       /* fifo-limit (8=tx:32/rx:64) */
-       writeb(fifo, &cfg_cmd->fifo);
-       /* hold or discard bad recv frames (bit 7) */
-       writeb(0x40, &cfg_cmd->sav_bf);
-       /* addr_len |!src_insert |pre-len |loopback */
-       writeb(0x2e, &cfg_cmd->adr_len);
-       writeb(0x00, &cfg_cmd->priority);
-       writeb(0x60, &cfg_cmd->ifs);
-       writeb(0x00, &cfg_cmd->time_low);
-       writeb(0xf2, &cfg_cmd->time_high);
-       writeb(0x00, &cfg_cmd->promisc);
-       if (dev->flags & IFF_ALLMULTI) {
-               int len = ((char __iomem *)p->iscp - (char __iomem *)ptr - 8) / 6;
-               if (num_addrs > len) {
-                       printk(KERN_ERR "%s: switching to promisc. mode\n",
-                               dev->name);
-                       writeb(0x01, &cfg_cmd->promisc);
-               }
-       }
-       if (dev->flags & IFF_PROMISC)
-               writeb(0x01, &cfg_cmd->promisc);
-       writeb(0x00, &cfg_cmd->carr_coll);
-       writew(make16(cfg_cmd), &p->scb->cbl_offset);
-       writeb(0, &p->scb->cmd_ruc);
-
-       writeb(CUC_START, &p->scb->cmd_cuc); /* cmd.-unit start */
-       ni_attn586();
-
-       wait_for_stat_compl(cfg_cmd);
-
-       if ((readw(&cfg_cmd->cmd_status) & (STAT_OK|STAT_COMPL)) !=
-                                                       (STAT_COMPL|STAT_OK)) {
-               printk(KERN_ERR "%s: configure command failed: %x\n",
-                               dev->name, readw(&cfg_cmd->cmd_status));
-               return 1;
-       }
-
-       /*
-        * individual address setup
-        */
-
-       ias_cmd = ptr;
-
-       writew(0, &ias_cmd->cmd_status);
-       writew(CMD_IASETUP | CMD_LAST, &ias_cmd->cmd_cmd);
-       writew(0xffff, &ias_cmd->cmd_link);
-
-       memcpy_toio(&ias_cmd->iaddr, (char *)dev->dev_addr, ETH_ALEN);
-
-       writew(make16(ias_cmd), &p->scb->cbl_offset);
-
-       writeb(CUC_START, &p->scb->cmd_cuc); /* cmd.-unit start */
-       ni_attn586();
-
-       wait_for_stat_compl(ias_cmd);
-
-       if ((readw(&ias_cmd->cmd_status) & (STAT_OK|STAT_COMPL)) !=
-                                                       (STAT_OK|STAT_COMPL)) {
-               printk(KERN_ERR "%s (ni52): individual address setup command failed: %04x\n", dev->name, readw(&ias_cmd->cmd_status));
-               return 1;
-       }
-
-       /*
-        * TDR, wire check .. e.g. no resistor e.t.c
-        */
-
-       tdr_cmd = ptr;
-
-       writew(0, &tdr_cmd->cmd_status);
-       writew(CMD_TDR | CMD_LAST, &tdr_cmd->cmd_cmd);
-       writew(0xffff, &tdr_cmd->cmd_link);
-       writew(0, &tdr_cmd->status);
-
-       writew(make16(tdr_cmd), &p->scb->cbl_offset);
-       writeb(CUC_START, &p->scb->cmd_cuc); /* cmd.-unit start */
-       ni_attn586();
-
-       wait_for_stat_compl(tdr_cmd);
-
-       if (!(readw(&tdr_cmd->cmd_status) & STAT_COMPL))
-               printk(KERN_ERR "%s: Problems while running the TDR.\n",
-                               dev->name);
-       else {
-               udelay(16);
-               result = readw(&tdr_cmd->status);
-               writeb(readb(&p->scb->cus) & STAT_MASK, &p->scb->cmd_cuc);
-               ni_attn586(); /* ack the interrupts */
-
-               if (result & TDR_LNK_OK)
-                       ;
-               else if (result & TDR_XCVR_PRB)
-                       printk(KERN_ERR "%s: TDR: Transceiver problem. Check the cable(s)!\n",
-                               dev->name);
-               else if (result & TDR_ET_OPN)
-                       printk(KERN_ERR "%s: TDR: No correct termination %d clocks away.\n",
-                               dev->name, result & TDR_TIMEMASK);
-               else if (result & TDR_ET_SRT) {
-                       /* time == 0 -> strange :-) */
-                       if (result & TDR_TIMEMASK)
-                               printk(KERN_ERR "%s: TDR: Detected a short circuit %d clocks away.\n",
-                                       dev->name, result & TDR_TIMEMASK);
-               } else
-                       printk(KERN_ERR "%s: TDR: Unknown status %04x\n",
-                                               dev->name, result);
-       }
-
-       /*
-        * Multicast setup
-        */
-       if (num_addrs && !(dev->flags & IFF_PROMISC)) {
-               mc_cmd = ptr;
-               writew(0, &mc_cmd->cmd_status);
-               writew(CMD_MCSETUP | CMD_LAST, &mc_cmd->cmd_cmd);
-               writew(0xffff, &mc_cmd->cmd_link);
-               writew(num_addrs * 6, &mc_cmd->mc_cnt);
-
-               i = 0;
-               netdev_for_each_mc_addr(ha, dev)
-                       memcpy_toio(mc_cmd->mc_list[i++], ha->addr, 6);
-
-               writew(make16(mc_cmd), &p->scb->cbl_offset);
-               writeb(CUC_START, &p->scb->cmd_cuc);
-               ni_attn586();
-
-               wait_for_stat_compl(mc_cmd);
-
-               if ((readw(&mc_cmd->cmd_status) & (STAT_COMPL|STAT_OK))
-                                                != (STAT_COMPL|STAT_OK))
-                       printk(KERN_ERR "%s: Can't apply multicast-address-list.\n", dev->name);
-       }
-
-       /*
-        * alloc nop/xmit-cmds
-        */
-#if (NUM_XMIT_BUFFS == 1)
-       for (i = 0; i < 2; i++) {
-               p->nop_cmds[i] = ptr;
-               writew(CMD_NOP, &p->nop_cmds[i]->cmd_cmd);
-               writew(0, &p->nop_cmds[i]->cmd_status);
-               writew(make16(p->nop_cmds[i]), &p->nop_cmds[i]->cmd_link);
-               ptr = ptr + sizeof(struct nop_cmd_struct);
-       }
-#else
-       for (i = 0; i < NUM_XMIT_BUFFS; i++) {
-               p->nop_cmds[i] = ptr;
-               writew(CMD_NOP, &p->nop_cmds[i]->cmd_cmd);
-               writew(0, &p->nop_cmds[i]->cmd_status);
-               writew(make16(p->nop_cmds[i]), &p->nop_cmds[i]->cmd_link);
-               ptr = ptr + sizeof(struct nop_cmd_struct);
-       }
-#endif
-
-       ptr = alloc_rfa(dev, ptr); /* init receive-frame-area */
-
-       /*
-        * alloc xmit-buffs / init xmit_cmds
-        */
-       for (i = 0; i < NUM_XMIT_BUFFS; i++) {
-               /* Transmit cmd/buff 0 */
-               p->xmit_cmds[i] = ptr;
-               ptr = ptr + sizeof(struct transmit_cmd_struct);
-               p->xmit_cbuffs[i] = ptr; /* char-buffs */
-               ptr = ptr + XMIT_BUFF_SIZE;
-               p->xmit_buffs[i] = ptr; /* TBD */
-               ptr = ptr + sizeof(struct tbd_struct);
-               if ((void __iomem *)ptr > (void __iomem *)p->iscp) {
-                       printk(KERN_ERR "%s: not enough shared-mem for your configuration!\n",
-                               dev->name);
-                       return 1;
-               }
-               memset_io(p->xmit_cmds[i], 0,
-                                       sizeof(struct transmit_cmd_struct));
-               memset_io(p->xmit_buffs[i], 0,
-                                       sizeof(struct tbd_struct));
-               writew(make16(p->nop_cmds[(i+1)%NUM_XMIT_BUFFS]),
-                                       &p->xmit_cmds[i]->cmd_link);
-               writew(STAT_COMPL, &p->xmit_cmds[i]->cmd_status);
-               writew(CMD_XMIT|CMD_INT, &p->xmit_cmds[i]->cmd_cmd);
-               writew(make16(p->xmit_buffs[i]), &p->xmit_cmds[i]->tbd_offset);
-               writew(0xffff, &p->xmit_buffs[i]->next);
-               writel(make24(p->xmit_cbuffs[i]), &p->xmit_buffs[i]->buffer);
-       }
-
-       p->xmit_count = 0;
-       p->xmit_last    = 0;
-#ifndef NO_NOPCOMMANDS
-       p->nop_point    = 0;
-#endif
-
-        /*
-               * 'start transmitter'
-               */
-#ifndef NO_NOPCOMMANDS
-       writew(make16(p->nop_cmds[0]), &p->scb->cbl_offset);
-       writeb(CUC_START, &p->scb->cmd_cuc);
-       ni_attn586();
-       wait_for_scb_cmd(dev);
-#else
-       writew(make16(p->xmit_cmds[0]), &p->xmit_cmds[0]->cmd_link);
-       writew(CMD_XMIT | CMD_SUSPEND | CMD_INT, &p->xmit_cmds[0]->cmd_cmd);
-#endif
-
-       /*
-        * ack. interrupts
-        */
-       writeb(readb(&p->scb->cus) & STAT_MASK, &p->scb->cmd_cuc);
-       ni_attn586();
-       udelay(16);
-
-       ni_enaint();
-
-       return 0;
-}
-
-/******************************************************
- * This is a helper routine for ni52_rnr_int() and init586().
- * It sets up the Receive Frame Area (RFA).
- */
-
-static void __iomem *alloc_rfa(struct net_device *dev, void __iomem *ptr)
-{
-       struct rfd_struct __iomem *rfd = ptr;
-       struct rbd_struct __iomem *rbd;
-       int i;
-       struct priv *p = netdev_priv(dev);
-
-       memset_io(rfd, 0,
-               sizeof(struct rfd_struct) * (p->num_recv_buffs + rfdadd));
-       p->rfd_first = rfd;
-
-       for (i = 0; i < (p->num_recv_buffs + rfdadd); i++) {
-               writew(make16(rfd + (i+1) % (p->num_recv_buffs+rfdadd)),
-                       &rfd[i].next);
-               writew(0xffff, &rfd[i].rbd_offset);
-       }
-       /* RU suspend */
-       writeb(RFD_SUSP, &rfd[p->num_recv_buffs-1+rfdadd].last);
-
-       ptr = rfd + (p->num_recv_buffs + rfdadd);
-
-       rbd = ptr;
-       ptr = rbd + p->num_recv_buffs;
-
-        /* clr descriptors */
-       memset_io(rbd, 0, sizeof(struct rbd_struct) * (p->num_recv_buffs));
-
-       for (i = 0; i < p->num_recv_buffs; i++) {
-               writew(make16(rbd + (i+1) % p->num_recv_buffs), &rbd[i].next);
-               writew(RECV_BUFF_SIZE, &rbd[i].size);
-               writel(make24(ptr), &rbd[i].buffer);
-               ptr = ptr + RECV_BUFF_SIZE;
-       }
-       p->rfd_top      = p->rfd_first;
-       p->rfd_last = p->rfd_first + (p->num_recv_buffs - 1 + rfdadd);
-
-       writew(make16(p->rfd_first), &p->scb->rfa_offset);
-       writew(make16(rbd), &p->rfd_first->rbd_offset);
-
-       return ptr;
-}
-
-
-/**************************************************
- * Interrupt Handler ...
- */
-
-static irqreturn_t ni52_interrupt(int irq, void *dev_id)
-{
-       struct net_device *dev = dev_id;
-       unsigned int stat;
-       int cnt = 0;
-       struct priv *p;
-
-       p = netdev_priv(dev);
-
-       if (debuglevel > 1)
-               printk("I");
-
-       spin_lock(&p->spinlock);
-
-       wait_for_scb_cmd(dev); /* wait for last command */
-
-       while ((stat = readb(&p->scb->cus) & STAT_MASK)) {
-               writeb(stat, &p->scb->cmd_cuc);
-               ni_attn586();
-
-               if (stat & STAT_FR)      /* received a frame */
-                       ni52_rcv_int(dev);
-
-               if (stat & STAT_RNR) { /* RU went 'not ready' */
-                       printk("(R)");
-                       if (readb(&p->scb->rus) & RU_SUSPEND) {
-                               /* special case: RU_SUSPEND */
-                               wait_for_scb_cmd(dev);
-                               writeb(RUC_RESUME, &p->scb->cmd_ruc);
-                               ni_attn586();
-                               wait_for_scb_cmd_ruc(dev);
-                       } else {
-                               printk(KERN_ERR "%s: Receiver-Unit went 'NOT READY': %04x/%02x.\n",
-                                       dev->name, stat, readb(&p->scb->rus));
-                               ni52_rnr_int(dev);
-                       }
-               }
-
-               /* Command with I-bit set complete */
-               if (stat & STAT_CX)
-                        ni52_xmt_int(dev);
-
-#ifndef NO_NOPCOMMANDS
-               if (stat & STAT_CNA) {  /* CU went 'not ready' */
-                       if (netif_running(dev))
-                               printk(KERN_ERR "%s: oops! CU has left active state. stat: %04x/%02x.\n",
-                                       dev->name, stat, readb(&p->scb->cus));
-               }
-#endif
-
-               if (debuglevel > 1)
-                       printk("%d", cnt++);
-
-               /* Wait for ack. (ni52_xmt_int can be faster than ack!!) */
-               wait_for_scb_cmd(dev);
-               if (readb(&p->scb->cmd_cuc)) {   /* timed out? */
-                       printk(KERN_ERR "%s: Acknowledge timed out.\n",
-                               dev->name);
-                       ni_disint();
-                       break;
-               }
-       }
-       spin_unlock(&p->spinlock);
-
-       if (debuglevel > 1)
-               printk("i");
-       return IRQ_HANDLED;
-}
-
-/*******************************************************
- * receive-interrupt
- */
-
-static void ni52_rcv_int(struct net_device *dev)
-{
-       int status, cnt = 0;
-       unsigned short totlen;
-       struct sk_buff *skb;
-       struct rbd_struct __iomem *rbd;
-       struct priv *p = netdev_priv(dev);
-
-       if (debuglevel > 0)
-               printk("R");
-
-       for (; (status = readb(&p->rfd_top->stat_high)) & RFD_COMPL;) {
-               rbd = make32(readw(&p->rfd_top->rbd_offset));
-               if (status & RFD_OK) { /* frame received without error? */
-                       totlen = readw(&rbd->status);
-                       if (totlen & RBD_LAST) {
-                               /* the first and the last buffer? */
-                               totlen &= RBD_MASK; /* length of this frame */
-                               writew(0x00, &rbd->status);
-                               skb = (struct sk_buff *)dev_alloc_skb(totlen+2);
-                               if (skb != NULL) {
-                                       skb_reserve(skb, 2);
-                                       skb_put(skb, totlen);
-                                       memcpy_fromio(skb->data, p->base + readl(&rbd->buffer), totlen);
-                                       skb->protocol = eth_type_trans(skb, dev);
-                                       netif_rx(skb);
-                                       dev->stats.rx_packets++;
-                                       dev->stats.rx_bytes += totlen;
-                               } else
-                                       dev->stats.rx_dropped++;
-                       } else {
-                               int rstat;
-                                /* free all RBD's until RBD_LAST is set */
-                               totlen = 0;
-                               while (!((rstat = readw(&rbd->status)) & RBD_LAST)) {
-                                       totlen += rstat & RBD_MASK;
-                                       if (!rstat) {
-                                               printk(KERN_ERR "%s: Whoops .. no end mark in RBD list\n", dev->name);
-                                               break;
-                                       }
-                                       writew(0, &rbd->status);
-                                       rbd = make32(readw(&rbd->next));
-                               }
-                               totlen += rstat & RBD_MASK;
-                               writew(0, &rbd->status);
-                               printk(KERN_ERR "%s: received oversized frame! length: %d\n",
-                                       dev->name, totlen);
-                               dev->stats.rx_dropped++;
-                        }
-               } else {/* frame !(ok), only with 'save-bad-frames' */
-                       printk(KERN_ERR "%s: oops! rfd-error-status: %04x\n",
-                               dev->name, status);
-                       dev->stats.rx_errors++;
-               }
-               writeb(0, &p->rfd_top->stat_high);
-               writeb(RFD_SUSP, &p->rfd_top->last); /* maybe exchange by RFD_LAST */
-               writew(0xffff, &p->rfd_top->rbd_offset);
-               writeb(0, &p->rfd_last->last);  /* delete RFD_SUSP      */
-               p->rfd_last = p->rfd_top;
-               p->rfd_top = make32(readw(&p->rfd_top->next)); /* step to next RFD */
-               writew(make16(p->rfd_top), &p->scb->rfa_offset);
-
-               if (debuglevel > 0)
-                       printk("%d", cnt++);
-       }
-
-       if (automatic_resume) {
-               wait_for_scb_cmd(dev);
-               writeb(RUC_RESUME, &p->scb->cmd_ruc);
-               ni_attn586();
-               wait_for_scb_cmd_ruc(dev);
-       }
-
-#ifdef WAIT_4_BUSY
-       {
-               int i;
-               for (i = 0; i < 1024; i++) {
-                       if (p->rfd_top->status)
-                               break;
-                       udelay(16);
-                       if (i == 1023)
-                               printk(KERN_ERR "%s: RU hasn't fetched next RFD (not busy/complete)\n", dev->name);
-               }
-       }
-#endif
-       if (debuglevel > 0)
-               printk("r");
-}
-
-/**********************************************************
- * handle 'Receiver went not ready'.
- */
-
-static void ni52_rnr_int(struct net_device *dev)
-{
-       struct priv *p = netdev_priv(dev);
-
-       dev->stats.rx_errors++;
-
-       wait_for_scb_cmd(dev);          /* wait for the last cmd, WAIT_4_FULLSTAT?? */
-       writeb(RUC_ABORT, &p->scb->cmd_ruc); /* usually the RU is in the 'no resource'-state .. abort it now. */
-       ni_attn586();
-       wait_for_scb_cmd_ruc(dev);              /* wait for accept cmd. */
-
-       alloc_rfa(dev, p->rfd_first);
-       /* maybe add a check here, before restarting the RU */
-       startrecv586(dev); /* restart RU */
-
-       printk(KERN_ERR "%s: Receive-Unit restarted. Status: %04x\n",
-               dev->name, readb(&p->scb->rus));
-
-}
-
-/**********************************************************
- * handle xmit - interrupt
- */
-
-static void ni52_xmt_int(struct net_device *dev)
-{
-       int status;
-       struct priv *p = netdev_priv(dev);
-
-       if (debuglevel > 0)
-               printk("X");
-
-       status = readw(&p->xmit_cmds[p->xmit_last]->cmd_status);
-       if (!(status & STAT_COMPL))
-               printk(KERN_ERR "%s: strange .. xmit-int without a 'COMPLETE'\n", dev->name);
-
-       if (status & STAT_OK) {
-               dev->stats.tx_packets++;
-               dev->stats.collisions += (status & TCMD_MAXCOLLMASK);
-       } else {
-               dev->stats.tx_errors++;
-               if (status & TCMD_LATECOLL) {
-                       printk(KERN_ERR "%s: late collision detected.\n",
-                               dev->name);
-                       dev->stats.collisions++;
-               } else if (status & TCMD_NOCARRIER) {
-                       dev->stats.tx_carrier_errors++;
-                       printk(KERN_ERR "%s: no carrier detected.\n",
-                               dev->name);
-               } else if (status & TCMD_LOSTCTS)
-                       printk(KERN_ERR "%s: loss of CTS detected.\n",
-                               dev->name);
-               else if (status & TCMD_UNDERRUN) {
-                       dev->stats.tx_fifo_errors++;
-                       printk(KERN_ERR "%s: DMA underrun detected.\n",
-                               dev->name);
-               } else if (status & TCMD_MAXCOLL) {
-                       printk(KERN_ERR "%s: Max. collisions exceeded.\n",
-                               dev->name);
-                       dev->stats.collisions += 16;
-               }
-       }
-#if (NUM_XMIT_BUFFS > 1)
-       if ((++p->xmit_last) == NUM_XMIT_BUFFS)
-               p->xmit_last = 0;
-#endif
-       netif_wake_queue(dev);
-}
-
-/***********************************************************
- * (re)start the receiver
- */
-
-static void startrecv586(struct net_device *dev)
-{
-       struct priv *p = netdev_priv(dev);
-
-       wait_for_scb_cmd(dev);
-       wait_for_scb_cmd_ruc(dev);
-       writew(make16(p->rfd_first), &p->scb->rfa_offset);
-       writeb(RUC_START, &p->scb->cmd_ruc);
-       ni_attn586();           /* start cmd. */
-       wait_for_scb_cmd_ruc(dev);
-       /* wait for accept cmd. (no timeout!!) */
-}
-
-static void ni52_timeout(struct net_device *dev)
-{
-       struct priv *p = netdev_priv(dev);
-#ifndef NO_NOPCOMMANDS
-       if (readb(&p->scb->cus) & CU_ACTIVE) { /* COMMAND-UNIT active? */
-               netif_wake_queue(dev);
-#ifdef DEBUG
-               printk(KERN_ERR "%s: strange ... timeout with CU active?!?\n",
-                       dev->name);
-               printk(KERN_ERR "%s: X0: %04x N0: %04x N1: %04x %d\n",
-                       dev->name, (int)p->xmit_cmds[0]->cmd_status,
-                       readw(&p->nop_cmds[0]->cmd_status),
-                       readw(&p->nop_cmds[1]->cmd_status),
-                       p->nop_point);
-#endif
-               writeb(CUC_ABORT, &p->scb->cmd_cuc);
-               ni_attn586();
-               wait_for_scb_cmd(dev);
-               writew(make16(p->nop_cmds[p->nop_point]), &p->scb->cbl_offset);
-               writeb(CUC_START, &p->scb->cmd_cuc);
-               ni_attn586();
-               wait_for_scb_cmd(dev);
-               dev->trans_start = jiffies; /* prevent tx timeout */
-               return 0;
-       }
-#endif
-       {
-#ifdef DEBUG
-               printk(KERN_ERR "%s: xmitter timed out, try to restart! stat: %02x\n",
-                               dev->name, readb(&p->scb->cus));
-               printk(KERN_ERR "%s: command-stats: %04x %04x\n",
-                               dev->name,
-                               readw(&p->xmit_cmds[0]->cmd_status),
-                               readw(&p->xmit_cmds[1]->cmd_status));
-               printk(KERN_ERR "%s: check, whether you set the right interrupt number!\n",
-                               dev->name);
-#endif
-               ni52_close(dev);
-               ni52_open(dev);
-       }
-       dev->trans_start = jiffies; /* prevent tx timeout */
-}
-
-/******************************************************
- * send frame
- */
-
-static netdev_tx_t ni52_send_packet(struct sk_buff *skb,
-                                   struct net_device *dev)
-{
-       int len, i;
-#ifndef NO_NOPCOMMANDS
-       int next_nop;
-#endif
-       struct priv *p = netdev_priv(dev);
-
-       if (skb->len > XMIT_BUFF_SIZE) {
-               printk(KERN_ERR "%s: Sorry, max. framelength is %d bytes. The length of your frame is %d bytes.\n", dev->name, XMIT_BUFF_SIZE, skb->len);
-               return NETDEV_TX_OK;
-       }
-
-       netif_stop_queue(dev);
-
-       memcpy_toio(p->xmit_cbuffs[p->xmit_count], skb->data, skb->len);
-       len = skb->len;
-       if (len < ETH_ZLEN) {
-               len = ETH_ZLEN;
-               memset_io(p->xmit_cbuffs[p->xmit_count]+skb->len, 0,
-                                                       len - skb->len);
-       }
-
-#if (NUM_XMIT_BUFFS == 1)
-#      ifdef NO_NOPCOMMANDS
-
-#ifdef DEBUG
-       if (readb(&p->scb->cus) & CU_ACTIVE) {
-               printk(KERN_ERR "%s: Hmmm .. CU is still running and we wanna send a new packet.\n", dev->name);
-               printk(KERN_ERR "%s: stat: %04x %04x\n",
-                               dev->name, readb(&p->scb->cus),
-                               readw(&p->xmit_cmds[0]->cmd_status));
-       }
-#endif
-       writew(TBD_LAST | len, &p->xmit_buffs[0]->size);
-       for (i = 0; i < 16; i++) {
-               writew(0, &p->xmit_cmds[0]->cmd_status);
-               wait_for_scb_cmd(dev);
-               if ((readb(&p->scb->cus) & CU_STATUS) == CU_SUSPEND)
-                       writeb(CUC_RESUME, &p->scb->cmd_cuc);
-               else {
-                       writew(make16(p->xmit_cmds[0]), &p->scb->cbl_offset);
-                       writeb(CUC_START, &p->scb->cmd_cuc);
-               }
-               ni_attn586();
-               if (!i)
-                       dev_kfree_skb(skb);
-               wait_for_scb_cmd(dev);
-               /* test it, because CU sometimes doesn't start immediately */
-               if (readb(&p->scb->cus) & CU_ACTIVE)
-                       break;
-               if (readw(&p->xmit_cmds[0]->cmd_status))
-                       break;
-               if (i == 15)
-                       printk(KERN_WARNING "%s: Can't start transmit-command.\n", dev->name);
-       }
-#      else
-       next_nop = (p->nop_point + 1) & 0x1;
-       writew(TBD_LAST | len, &p->xmit_buffs[0]->size);
-       writew(make16(p->nop_cmds[next_nop]), &p->xmit_cmds[0]->cmd_link);
-       writew(make16(p->nop_cmds[next_nop]),
-                               &p->nop_cmds[next_nop]->cmd_link);
-       writew(0, &p->xmit_cmds[0]->cmd_status);
-       writew(0, &p->nop_cmds[next_nop]->cmd_status);
-
-       writew(make16(p->xmit_cmds[0]), &p->nop_cmds[p->nop_point]->cmd_link);
-       p->nop_point = next_nop;
-       dev_kfree_skb(skb);
-#      endif
-#else
-       writew(TBD_LAST | len, &p->xmit_buffs[p->xmit_count]->size);
-       next_nop = p->xmit_count + 1
-       if (next_nop == NUM_XMIT_BUFFS)
-               next_nop = 0;
-       writew(0, &p->xmit_cmds[p->xmit_count]->cmd_status);
-       /* linkpointer of xmit-command already points to next nop cmd */
-       writew(make16(p->nop_cmds[next_nop]),
-                               &p->nop_cmds[next_nop]->cmd_link);
-       writew(0, &p->nop_cmds[next_nop]->cmd_status);
-       writew(make16(p->xmit_cmds[p->xmit_count]),
-                               &p->nop_cmds[p->xmit_count]->cmd_link);
-       p->xmit_count = next_nop;
-       {
-               unsigned long flags;
-               spin_lock_irqsave(&p->spinlock);
-               if (p->xmit_count != p->xmit_last)
-                       netif_wake_queue(dev);
-               spin_unlock_irqrestore(&p->spinlock);
-       }
-       dev_kfree_skb(skb);
-#endif
-       return NETDEV_TX_OK;
-}
-
-/*******************************************
- * Someone wanna have the statistics
- */
-
-static struct net_device_stats *ni52_get_stats(struct net_device *dev)
-{
-       struct priv *p = netdev_priv(dev);
-       unsigned short crc, aln, rsc, ovrn;
-
-       /* Get error-statistics from the ni82586 */
-       crc = readw(&p->scb->crc_errs);
-       writew(0, &p->scb->crc_errs);
-       aln = readw(&p->scb->aln_errs);
-       writew(0, &p->scb->aln_errs);
-       rsc = readw(&p->scb->rsc_errs);
-       writew(0, &p->scb->rsc_errs);
-       ovrn = readw(&p->scb->ovrn_errs);
-       writew(0, &p->scb->ovrn_errs);
-
-       dev->stats.rx_crc_errors += crc;
-       dev->stats.rx_fifo_errors += ovrn;
-       dev->stats.rx_frame_errors += aln;
-       dev->stats.rx_dropped += rsc;
-
-       return &dev->stats;
-}
-
-/********************************************************
- * Set MC list ..
- */
-
-static void set_multicast_list(struct net_device *dev)
-{
-       netif_stop_queue(dev);
-       ni_disint();
-       alloc586(dev);
-       init586(dev);
-       startrecv586(dev);
-       ni_enaint();
-       netif_wake_queue(dev);
-}
-
-#ifdef MODULE
-static struct net_device *dev_ni52;
-
-module_param(io, int, 0);
-module_param(irq, int, 0);
-module_param(memstart, long, 0);
-module_param(memend, long, 0);
-MODULE_PARM_DESC(io, "NI5210 I/O base address,required");
-MODULE_PARM_DESC(irq, "NI5210 IRQ number,required");
-MODULE_PARM_DESC(memstart, "NI5210 memory base address,required");
-MODULE_PARM_DESC(memend, "NI5210 memory end address,required");
-
-int __init init_module(void)
-{
-       if (io <= 0x0 || !memend || !memstart || irq < 2) {
-               printk(KERN_ERR "ni52: Autoprobing not allowed for modules.\n");
-               printk(KERN_ERR "ni52: Set symbols 'io' 'irq' 'memstart' and 'memend'\n");
-               return -ENODEV;
-       }
-       dev_ni52 = ni52_probe(-1);
-       if (IS_ERR(dev_ni52))
-               return PTR_ERR(dev_ni52);
-       return 0;
-}
-
-void __exit cleanup_module(void)
-{
-       struct priv *p = netdev_priv(dev_ni52);
-       unregister_netdev(dev_ni52);
-       iounmap(p->mapped);
-       release_region(dev_ni52->base_addr, NI52_TOTAL_SIZE);
-       free_netdev(dev_ni52);
-}
-#endif /* MODULE */
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/ni52.h b/drivers/net/ni52.h
deleted file mode 100644 (file)
index 0a03b28..0000000
+++ /dev/null
@@ -1,310 +0,0 @@
-/*
- * Intel i82586 Ethernet definitions
- *
- * This is an extension to the Linux operating system, and is covered by the
- * same GNU General Public License that covers that work.
- *
- * copyrights (c) 1994 by Michael Hipp (hippm@informatik.uni-tuebingen.de)
- *
- * I have done a look in the following sources:
- *   crynwr-packet-driver by Russ Nelson
- *   Garret A. Wollman's i82586-driver for BSD
- */
-
-
-#define NI52_RESET     0  /* writing to this address, resets the i82586 */
-#define NI52_ATTENTION 1  /* channel attention, kick the 586 */
-#define NI52_TENA      3  /* 2-5 possibly wrong, Xmit enable */
-#define NI52_TDIS      2  /* Xmit disable */
-#define NI52_INTENA    5  /* Interrupt enable */
-#define NI52_INTDIS    4  /* Interrupt disable */
-#define NI52_MAGIC1    6  /* dunno exact function */
-#define NI52_MAGIC2    7  /* dunno exact function */
-
-#define NI52_MAGICVAL1 0x00  /* magic-values for ni5210 card */
-#define NI52_MAGICVAL2 0x55
-
-/*
- * where to find the System Configuration Pointer (SCP)
- */
-#define SCP_DEFAULT_ADDRESS 0xfffff4
-
-
-/*
- * System Configuration Pointer Struct
- */
-
-struct scp_struct
-{
-       u16 zero_dum0;  /* has to be zero */
-       u8 sysbus;      /* 0=16Bit,1=8Bit */
-       u8 zero_dum1;   /* has to be zero for 586 */
-       u16 zero_dum2;
-       u16 zero_dum3;
-       u32 iscp;               /* pointer to the iscp-block */
-};
-
-
-/*
- * Intermediate System Configuration Pointer (ISCP)
- */
-struct iscp_struct
-{
-       u8 busy;          /* 586 clears after successful init */
-       u8 zero_dummy;    /* has to be zero */
-       u16 scb_offset;    /* pointeroffset to the scb_base */
-       u32 scb_base;      /* base-address of all 16-bit offsets */
-};
-
-/*
- * System Control Block (SCB)
- */
-struct scb_struct
-{
-       u8 rus;
-       u8 cus;
-       u8 cmd_ruc;        /* command word: RU part */
-       u8 cmd_cuc;        /* command word: CU part & ACK */
-       u16 cbl_offset;    /* pointeroffset, command block list */
-       u16 rfa_offset;    /* pointeroffset, receive frame area */
-       u16 crc_errs;      /* CRC-Error counter */
-       u16 aln_errs;      /* alignmenterror counter */
-       u16 rsc_errs;      /* Resourceerror counter */
-       u16 ovrn_errs;     /* OVerrunerror counter */
-};
-
-/*
- * possible command values for the command word
- */
-#define RUC_MASK       0x0070  /* mask for RU commands */
-#define RUC_NOP                0x0000  /* NOP-command */
-#define RUC_START      0x0010  /* start RU */
-#define RUC_RESUME     0x0020  /* resume RU after suspend */
-#define RUC_SUSPEND    0x0030  /* suspend RU */
-#define RUC_ABORT      0x0040  /* abort receiver operation immediately */
-
-#define CUC_MASK        0x07  /* mask for CU command */
-#define CUC_NOP         0x00  /* NOP-command */
-#define CUC_START       0x01  /* start execution of 1. cmd on the CBL */
-#define CUC_RESUME      0x02  /* resume after suspend */
-#define CUC_SUSPEND     0x03  /* Suspend CU */
-#define CUC_ABORT       0x04  /* abort command operation immediately */
-
-#define ACK_MASK        0xf0  /* mask for ACK command */
-#define ACK_CX          0x80  /* acknowledges STAT_CX */
-#define ACK_FR          0x40  /* ack. STAT_FR */
-#define ACK_CNA         0x20  /* ack. STAT_CNA */
-#define ACK_RNR         0x10  /* ack. STAT_RNR */
-
-/*
- * possible status values for the status word
- */
-#define STAT_MASK       0xf0  /* mask for cause of interrupt */
-#define STAT_CX         0x80  /* CU finished cmd with its I bit set */
-#define STAT_FR         0x40  /* RU finished receiving a frame */
-#define STAT_CNA        0x20  /* CU left active state */
-#define STAT_RNR        0x10  /* RU left ready state */
-
-#define CU_STATUS       0x7   /* CU status, 0=idle */
-#define CU_SUSPEND      0x1   /* CU is suspended */
-#define CU_ACTIVE       0x2   /* CU is active */
-
-#define RU_STATUS      0x70    /* RU status, 0=idle */
-#define RU_SUSPEND     0x10    /* RU suspended */
-#define RU_NOSPACE     0x20    /* RU no resources */
-#define RU_READY       0x40    /* RU is ready */
-
-/*
- * Receive Frame Descriptor (RFD)
- */
-struct rfd_struct
-{
-       u8  stat_low;   /* status word */
-       u8  stat_high;  /* status word */
-       u8  rfd_sf;     /* 82596 mode only */
-       u8  last;               /* Bit15,Last Frame on List / Bit14,suspend */
-       u16 next;               /* linkoffset to next RFD */
-       u16 rbd_offset; /* pointeroffset to RBD-buffer */
-       u8  dest[6];    /* ethernet-address, destination */
-       u8  source[6];  /* ethernet-address, source */
-       u16 length;     /* 802.3 frame-length */
-       u16 zero_dummy; /* dummy */
-};
-
-#define RFD_LAST     0x80      /* last: last rfd in the list */
-#define RFD_SUSP     0x40      /* last: suspend RU after  */
-#define RFD_COMPL    0x80
-#define RFD_OK       0x20
-#define RFD_BUSY     0x40
-#define RFD_ERR_LEN  0x10     /* Length error (if enabled length-checking */
-#define RFD_ERR_CRC  0x08     /* CRC error */
-#define RFD_ERR_ALGN 0x04     /* Alignment error */
-#define RFD_ERR_RNR  0x02     /* status: receiver out of resources */
-#define RFD_ERR_OVR  0x01     /* DMA Overrun! */
-
-#define RFD_ERR_FTS  0x0080    /* Frame to short */
-#define RFD_ERR_NEOP 0x0040    /* No EOP flag (for bitstuffing only) */
-#define RFD_ERR_TRUN 0x0020    /* (82596 only/SF mode) indicates truncated frame */
-#define RFD_MATCHADD 0x0002     /* status: Destinationaddress !matches IA (only 82596) */
-#define RFD_COLLDET  0x0001    /* Detected collision during reception */
-
-/*
- * Receive Buffer Descriptor (RBD)
- */
-struct rbd_struct
-{
-       u16 status;     /* status word,number of used bytes in buff */
-       u16 next;               /* pointeroffset to next RBD */
-       u32 buffer;     /* receive buffer address pointer */
-       u16 size;               /* size of this buffer */
-       u16 zero_dummy;    /* dummy */
-};
-
-#define RBD_LAST       0x8000  /* last buffer */
-#define RBD_USED       0x4000  /* this buffer has data */
-#define RBD_MASK       0x3fff  /* size-mask for length */
-
-/*
- * Statusvalues for Commands/RFD
- */
-#define STAT_COMPL   0x8000    /* status: frame/command is complete */
-#define STAT_BUSY    0x4000    /* status: frame/command is busy */
-#define STAT_OK      0x2000    /* status: frame/command is ok */
-
-/*
- * Action-Commands
- */
-#define CMD_NOP                0x0000  /* NOP */
-#define CMD_IASETUP    0x0001  /* initial address setup command */
-#define CMD_CONFIGURE  0x0002  /* configure command */
-#define CMD_MCSETUP    0x0003  /* MC setup command */
-#define CMD_XMIT       0x0004  /* transmit command */
-#define CMD_TDR                0x0005  /* time domain reflectometer (TDR) command */
-#define CMD_DUMP       0x0006  /* dump command */
-#define CMD_DIAGNOSE   0x0007  /* diagnose command */
-
-/*
- * Action command bits
- */
-#define CMD_LAST       0x8000  /* indicates last command in the CBL */
-#define CMD_SUSPEND    0x4000  /* suspend CU after this CB */
-#define CMD_INT                0x2000  /* generate interrupt after execution */
-
-/*
- * NOP - command
- */
-struct nop_cmd_struct
-{
-       u16 cmd_status; /* status of this command */
-       u16 cmd_cmd;       /* the command itself (+bits) */
-       u16 cmd_link;      /* offsetpointer to next command */
-};
-
-/*
- * IA Setup command
- */
-struct iasetup_cmd_struct
-{
-       u16 cmd_status;
-       u16 cmd_cmd;
-       u16 cmd_link;
-       u8  iaddr[6];
-};
-
-/*
- * Configure command
- */
-struct configure_cmd_struct
-{
-       u16 cmd_status;
-       u16 cmd_cmd;
-       u16 cmd_link;
-       u8  byte_cnt;   /* size of the config-cmd */
-       u8  fifo;       /* fifo/recv monitor */
-       u8  sav_bf;     /* save bad frames (bit7=1)*/
-       u8  adr_len;    /* adr_len(0-2),al_loc(3),pream(4-5),loopbak(6-7)*/
-       u8  priority;   /* lin_prio(0-2),exp_prio(4-6),bof_metd(7) */
-       u8  ifs;        /* inter frame spacing */
-       u8  time_low;   /* slot time low */
-       u8  time_high;  /* slot time high(0-2) and max. retries(4-7) */
-       u8  promisc;    /* promisc-mode(0) , et al (1-7) */
-       u8  carr_coll;  /* carrier(0-3)/collision(4-7) stuff */
-       u8  fram_len;   /* minimal frame len */
-       u8  dummy;           /* dummy */
-};
-
-/*
- * Multicast Setup command
- */
-struct mcsetup_cmd_struct
-{
-       u16 cmd_status;
-       u16 cmd_cmd;
-       u16 cmd_link;
-       u16 mc_cnt;             /* number of bytes in the MC-List */
-       u8  mc_list[0][6];      /* pointer to 6 bytes entries */
-};
-
-/*
- * DUMP command
- */
-struct dump_cmd_struct
-{
-       u16 cmd_status;
-       u16 cmd_cmd;
-       u16 cmd_link;
-       u16 dump_offset;    /* pointeroffset to DUMP space */
-};
-
-/*
- * transmit command
- */
-struct transmit_cmd_struct
-{
-       u16 cmd_status;
-       u16 cmd_cmd;
-       u16 cmd_link;
-       u16 tbd_offset; /* pointeroffset to TBD */
-       u8  dest[6];       /* destination address of the frame */
-       u16 length;     /* user defined: 802.3 length / Ether type */
-};
-
-#define TCMD_ERRMASK     0x0fa0
-#define TCMD_MAXCOLLMASK 0x000f
-#define TCMD_MAXCOLL     0x0020
-#define TCMD_HEARTBEAT   0x0040
-#define TCMD_DEFERRED    0x0080
-#define TCMD_UNDERRUN    0x0100
-#define TCMD_LOSTCTS     0x0200
-#define TCMD_NOCARRIER   0x0400
-#define TCMD_LATECOLL    0x0800
-
-struct tdr_cmd_struct
-{
-       u16 cmd_status;
-       u16 cmd_cmd;
-       u16 cmd_link;
-       u16 status;
-};
-
-#define TDR_LNK_OK     0x8000  /* No link problem identified */
-#define TDR_XCVR_PRB   0x4000  /* indicates a transceiver problem */
-#define TDR_ET_OPN     0x2000  /* open, no correct termination */
-#define TDR_ET_SRT     0x1000  /* TDR detected a short circuit */
-#define TDR_TIMEMASK   0x07ff  /* mask for the time field */
-
-/*
- * Transmit Buffer Descriptor (TBD)
- */
-struct tbd_struct
-{
-       u16 size;               /* size + EOF-Flag(15) */
-       u16 next;          /* pointeroffset to next TBD */
-       u32 buffer;        /* pointer to buffer */
-};
-
-#define TBD_LAST 0x8000         /* EOF-Flag, indicates last buffer in list */
-
-
-
-
diff --git a/drivers/net/sni_82596.c b/drivers/net/sni_82596.c
deleted file mode 100644 (file)
index 6b2a888..0000000
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * sni_82596.c -- driver for intel 82596 ethernet controller, as
- *               used in older SNI RM machines
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/bitops.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-
-#define SNI_82596_DRIVER_VERSION "SNI RM 82596 driver - Revision: 0.01"
-
-static const char sni_82596_string[] = "snirm_82596";
-
-#define DMA_ALLOC                      dma_alloc_coherent
-#define DMA_FREE                       dma_free_coherent
-#define DMA_WBACK(priv, addr, len)     do { } while (0)
-#define DMA_INV(priv, addr, len)       do { } while (0)
-#define DMA_WBACK_INV(priv, addr, len) do { } while (0)
-
-#define SYSBUS      0x00004400
-
-/* big endian CPU, 82596 little endian */
-#define SWAP32(x)   cpu_to_le32((u32)(x))
-#define SWAP16(x)   cpu_to_le16((u16)(x))
-
-#define OPT_MPU_16BIT    0x01
-
-#include "lib82596.c"
-
-MODULE_AUTHOR("Thomas Bogendoerfer");
-MODULE_DESCRIPTION("i82596 driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:snirm_82596");
-module_param(i596_debug, int, 0);
-MODULE_PARM_DESC(i596_debug, "82596 debug mask");
-
-static inline void ca(struct net_device *dev)
-{
-       struct i596_private *lp = netdev_priv(dev);
-
-       writel(0, lp->ca);
-}
-
-
-static void mpu_port(struct net_device *dev, int c, dma_addr_t x)
-{
-       struct i596_private *lp = netdev_priv(dev);
-
-       u32 v = (u32) (c) | (u32) (x);
-
-       if (lp->options & OPT_MPU_16BIT) {
-               writew(v & 0xffff, lp->mpu_port);
-               wmb();  /* order writes to MPU port */
-               udelay(1);
-               writew(v >> 16, lp->mpu_port);
-       } else {
-               writel(v, lp->mpu_port);
-               wmb();  /* order writes to MPU port */
-               udelay(1);
-               writel(v, lp->mpu_port);
-       }
-}
-
-
-static int __devinit sni_82596_probe(struct platform_device *dev)
-{
-       struct  net_device *netdevice;
-       struct i596_private *lp;
-       struct  resource *res, *ca, *idprom, *options;
-       int     retval = -ENOMEM;
-       void __iomem *mpu_addr;
-       void __iomem *ca_addr;
-       u8 __iomem *eth_addr;
-
-       res = platform_get_resource(dev, IORESOURCE_MEM, 0);
-       ca = platform_get_resource(dev, IORESOURCE_MEM, 1);
-       options = platform_get_resource(dev, 0, 0);
-       idprom = platform_get_resource(dev, IORESOURCE_MEM, 2);
-       if (!res || !ca || !options || !idprom)
-               return -ENODEV;
-       mpu_addr = ioremap_nocache(res->start, 4);
-       if (!mpu_addr)
-               return -ENOMEM;
-       ca_addr = ioremap_nocache(ca->start, 4);
-       if (!ca_addr)
-               goto probe_failed_free_mpu;
-
-       printk(KERN_INFO "Found i82596 at 0x%x\n", res->start);
-
-       netdevice = alloc_etherdev(sizeof(struct i596_private));
-       if (!netdevice)
-               goto probe_failed_free_ca;
-
-       SET_NETDEV_DEV(netdevice, &dev->dev);
-       platform_set_drvdata (dev, netdevice);
-
-       netdevice->base_addr = res->start;
-       netdevice->irq = platform_get_irq(dev, 0);
-
-       eth_addr = ioremap_nocache(idprom->start, 0x10);
-       if (!eth_addr)
-               goto probe_failed;
-
-       /* someone seems to like messed up stuff */
-       netdevice->dev_addr[0] = readb(eth_addr + 0x0b);
-       netdevice->dev_addr[1] = readb(eth_addr + 0x0a);
-       netdevice->dev_addr[2] = readb(eth_addr + 0x09);
-       netdevice->dev_addr[3] = readb(eth_addr + 0x08);
-       netdevice->dev_addr[4] = readb(eth_addr + 0x07);
-       netdevice->dev_addr[5] = readb(eth_addr + 0x06);
-       iounmap(eth_addr);
-
-       if (!netdevice->irq) {
-               printk(KERN_ERR "%s: IRQ not found for i82596 at 0x%lx\n",
-                       __FILE__, netdevice->base_addr);
-               goto probe_failed;
-       }
-
-       lp = netdev_priv(netdevice);
-       lp->options = options->flags & IORESOURCE_BITS;
-       lp->ca = ca_addr;
-       lp->mpu_port = mpu_addr;
-
-       retval = i82596_probe(netdevice);
-       if (retval == 0)
-               return 0;
-
-probe_failed:
-       free_netdev(netdevice);
-probe_failed_free_ca:
-       iounmap(ca_addr);
-probe_failed_free_mpu:
-       iounmap(mpu_addr);
-       return retval;
-}
-
-static int __devexit sni_82596_driver_remove(struct platform_device *pdev)
-{
-       struct net_device *dev = platform_get_drvdata(pdev);
-       struct i596_private *lp = netdev_priv(dev);
-
-       unregister_netdev(dev);
-       DMA_FREE(dev->dev.parent, sizeof(struct i596_private),
-                lp->dma, lp->dma_addr);
-       iounmap(lp->ca);
-       iounmap(lp->mpu_port);
-       free_netdev (dev);
-       return 0;
-}
-
-static struct platform_driver sni_82596_driver = {
-       .probe  = sni_82596_probe,
-       .remove = __devexit_p(sni_82596_driver_remove),
-       .driver = {
-               .name   = sni_82596_string,
-               .owner  = THIS_MODULE,
-       },
-};
-
-static int __devinit sni_82596_init(void)
-{
-       printk(KERN_INFO SNI_82596_DRIVER_VERSION "\n");
-       return platform_driver_register(&sni_82596_driver);
-}
-
-
-static void __exit sni_82596_exit(void)
-{
-       platform_driver_unregister(&sni_82596_driver);
-}
-
-module_init(sni_82596_init);
-module_exit(sni_82596_exit);
diff --git a/drivers/net/sun3_82586.c b/drivers/net/sun3_82586.c
deleted file mode 100644 (file)
index b6ae53b..0000000
+++ /dev/null
@@ -1,1213 +0,0 @@
-/*
- * Sun3 i82586 Ethernet driver
- *
- * Cloned from ni52.c for the Sun3 by Sam Creasey (sammy@sammy.net)
- *
- * Original copyright follows:
- * --------------------------
- *
- * net-3-driver for the NI5210 card (i82586 Ethernet chip)
- *
- * This is an extension to the Linux operating system, and is covered by the
- * same Gnu Public License that covers that work.
- *
- * Alphacode 0.82 (96/09/29) for Linux 2.0.0 (or later)
- * Copyrights (c) 1994,1995,1996 by M.Hipp (hippm@informatik.uni-tuebingen.de)
- * --------------------------
- *
- * Consult ni52.c for further notes from the original driver.
- *
- * This incarnation currently supports the OBIO version of the i82586 chip
- * used in certain sun3 models.  It should be fairly doable to expand this
- * to support VME if I should every acquire such a board.
- *
- */
-
-static int debuglevel = 0; /* debug-printk 0: off 1: a few 2: more */
-static int automatic_resume = 0; /* experimental .. better should be zero */
-static int rfdadd = 0; /* rfdadd=1 may be better for 8K MEM cards */
-static int fifo=0x8;   /* don't change */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/bitops.h>
-#include <asm/io.h>
-#include <asm/idprom.h>
-#include <asm/machines.h>
-#include <asm/sun3mmu.h>
-#include <asm/dvma.h>
-#include <asm/byteorder.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-
-#include "sun3_82586.h"
-
-#define DRV_NAME "sun3_82586"
-
-#define DEBUG       /* debug on */
-#define SYSBUSVAL 0 /* 16 Bit */
-#define SUN3_82586_TOTAL_SIZE  PAGE_SIZE
-
-#define sun3_attn586()  {*(volatile unsigned char *)(dev->base_addr) |= IEOB_ATTEN; *(volatile unsigned char *)(dev->base_addr) &= ~IEOB_ATTEN;}
-#define sun3_reset586() {*(volatile unsigned char *)(dev->base_addr) = 0; udelay(100); *(volatile unsigned char *)(dev->base_addr) = IEOB_NORSET;}
-#define sun3_disint()   {*(volatile unsigned char *)(dev->base_addr) &= ~IEOB_IENAB;}
-#define sun3_enaint()   {*(volatile unsigned char *)(dev->base_addr) |= IEOB_IENAB;}
-#define sun3_active()   {*(volatile unsigned char *)(dev->base_addr) |= (IEOB_IENAB|IEOB_ONAIR|IEOB_NORSET);}
-
-#define make32(ptr16) (p->memtop + (swab16((unsigned short) (ptr16))) )
-#define make24(ptr32) (char *)swab32(( ((unsigned long) (ptr32)) - p->base))
-#define make16(ptr32) (swab16((unsigned short) ((unsigned long)(ptr32) - (unsigned long) p->memtop )))
-
-/******************* how to calculate the buffers *****************************
-
-  * IMPORTANT NOTE: if you configure only one NUM_XMIT_BUFFS, the driver works
-  * --------------- in a different (more stable?) mode. Only in this mode it's
-  *                 possible to configure the driver with 'NO_NOPCOMMANDS'
-
-sizeof(scp)=12; sizeof(scb)=16; sizeof(iscp)=8;
-sizeof(scp)+sizeof(iscp)+sizeof(scb) = 36 = INIT
-sizeof(rfd) = 24; sizeof(rbd) = 12;
-sizeof(tbd) = 8; sizeof(transmit_cmd) = 16;
-sizeof(nop_cmd) = 8;
-
-  * if you don't know the driver, better do not change these values: */
-
-#define RECV_BUFF_SIZE 1536 /* slightly oversized */
-#define XMIT_BUFF_SIZE 1536 /* slightly oversized */
-#define NUM_XMIT_BUFFS 1    /* config for 32K shmem */
-#define NUM_RECV_BUFFS_8 4 /* config for 32K shared mem */
-#define NUM_RECV_BUFFS_16 9 /* config for 32K shared mem */
-#define NUM_RECV_BUFFS_32 16 /* config for 32K shared mem */
-#define NO_NOPCOMMANDS      /* only possible with NUM_XMIT_BUFFS=1 */
-
-/**************************************************************************/
-
-/* different DELAYs */
-#define DELAY(x) mdelay(32 * x);
-#define DELAY_16(); { udelay(16); }
-#define DELAY_18(); { udelay(4); }
-
-/* wait for command with timeout: */
-#define WAIT_4_SCB_CMD() \
-{ int i; \
-  for(i=0;i<16384;i++) { \
-    if(!p->scb->cmd_cuc) break; \
-    DELAY_18(); \
-    if(i == 16383) { \
-      printk("%s: scb_cmd timed out: %04x,%04x .. disabling i82586!!\n",dev->name,p->scb->cmd_cuc,p->scb->cus); \
-       if(!p->reseted) { p->reseted = 1; sun3_reset586(); } } } }
-
-#define WAIT_4_SCB_CMD_RUC() { int i; \
-  for(i=0;i<16384;i++) { \
-    if(!p->scb->cmd_ruc) break; \
-    DELAY_18(); \
-    if(i == 16383) { \
-      printk("%s: scb_cmd (ruc) timed out: %04x,%04x .. disabling i82586!!\n",dev->name,p->scb->cmd_ruc,p->scb->rus); \
-       if(!p->reseted) { p->reseted = 1; sun3_reset586(); } } } }
-
-#define WAIT_4_STAT_COMPL(addr) { int i; \
-   for(i=0;i<32767;i++) { \
-     if(swab16((addr)->cmd_status) & STAT_COMPL) break; \
-     DELAY_16(); DELAY_16(); } }
-
-static int     sun3_82586_probe1(struct net_device *dev,int ioaddr);
-static irqreturn_t sun3_82586_interrupt(int irq,void *dev_id);
-static int     sun3_82586_open(struct net_device *dev);
-static int     sun3_82586_close(struct net_device *dev);
-static int     sun3_82586_send_packet(struct sk_buff *,struct net_device *);
-static struct  net_device_stats *sun3_82586_get_stats(struct net_device *dev);
-static void    set_multicast_list(struct net_device *dev);
-static void    sun3_82586_timeout(struct net_device *dev);
-#if 0
-static void    sun3_82586_dump(struct net_device *,void *);
-#endif
-
-/* helper-functions */
-static int     init586(struct net_device *dev);
-static int     check586(struct net_device *dev,char *where,unsigned size);
-static void    alloc586(struct net_device *dev);
-static void    startrecv586(struct net_device *dev);
-static void   *alloc_rfa(struct net_device *dev,void *ptr);
-static void    sun3_82586_rcv_int(struct net_device *dev);
-static void    sun3_82586_xmt_int(struct net_device *dev);
-static void    sun3_82586_rnr_int(struct net_device *dev);
-
-struct priv
-{
-       unsigned long base;
-       char *memtop;
-       long int lock;
-       int reseted;
-       volatile struct rfd_struct      *rfd_last,*rfd_top,*rfd_first;
-       volatile struct scp_struct      *scp;   /* volatile is important */
-       volatile struct iscp_struct     *iscp;  /* volatile is important */
-       volatile struct scb_struct      *scb;   /* volatile is important */
-       volatile struct tbd_struct      *xmit_buffs[NUM_XMIT_BUFFS];
-       volatile struct transmit_cmd_struct *xmit_cmds[NUM_XMIT_BUFFS];
-#if (NUM_XMIT_BUFFS == 1)
-       volatile struct nop_cmd_struct *nop_cmds[2];
-#else
-       volatile struct nop_cmd_struct *nop_cmds[NUM_XMIT_BUFFS];
-#endif
-       volatile int            nop_point,num_recv_buffs;
-       volatile char           *xmit_cbuffs[NUM_XMIT_BUFFS];
-       volatile int            xmit_count,xmit_last;
-};
-
-/**********************************************
- * close device
- */
-static int sun3_82586_close(struct net_device *dev)
-{
-       free_irq(dev->irq, dev);
-
-       sun3_reset586(); /* the hard way to stop the receiver */
-
-       netif_stop_queue(dev);
-
-       return 0;
-}
-
-/**********************************************
- * open device
- */
-static int sun3_82586_open(struct net_device *dev)
-{
-       int ret;
-
-       sun3_disint();
-       alloc586(dev);
-       init586(dev);
-       startrecv586(dev);
-       sun3_enaint();
-
-       ret = request_irq(dev->irq, sun3_82586_interrupt,0,dev->name,dev);
-       if (ret)
-       {
-               sun3_reset586();
-               return ret;
-       }
-
-       netif_start_queue(dev);
-
-       return 0; /* most done by init */
-}
-
-/**********************************************
- * Check to see if there's an 82586 out there.
- */
-static int check586(struct net_device *dev,char *where,unsigned size)
-{
-       struct priv pb;
-       struct priv *p = &pb;
-       char *iscp_addr;
-       int i;
-
-       p->base = (unsigned long) dvma_btov(0);
-       p->memtop = (char *)dvma_btov((unsigned long)where);
-       p->scp = (struct scp_struct *)(p->base + SCP_DEFAULT_ADDRESS);
-       memset((char *)p->scp,0, sizeof(struct scp_struct));
-       for(i=0;i<sizeof(struct scp_struct);i++) /* memory was writeable? */
-               if(((char *)p->scp)[i])
-                       return 0;
-       p->scp->sysbus = SYSBUSVAL;                             /* 1 = 8Bit-Bus, 0 = 16 Bit */
-       if(p->scp->sysbus != SYSBUSVAL)
-               return 0;
-
-       iscp_addr = (char *)dvma_btov((unsigned long)where);
-
-       p->iscp = (struct iscp_struct *) iscp_addr;
-       memset((char *)p->iscp,0, sizeof(struct iscp_struct));
-
-       p->scp->iscp = make24(p->iscp);
-       p->iscp->busy = 1;
-
-       sun3_reset586();
-       sun3_attn586();
-       DELAY(1);       /* wait a while... */
-
-       if(p->iscp->busy) /* i82586 clears 'busy' after successful init */
-               return 0;
-
-       return 1;
-}
-
-/******************************************************************
- * set iscp at the right place, called by sun3_82586_probe1 and open586.
- */
-static void alloc586(struct net_device *dev)
-{
-       struct priv *p = netdev_priv(dev);
-
-       sun3_reset586();
-       DELAY(1);
-
-       p->scp  = (struct scp_struct *) (p->base + SCP_DEFAULT_ADDRESS);
-       p->iscp = (struct iscp_struct *) dvma_btov(dev->mem_start);
-       p->scb  = (struct scb_struct *)  ((char *)p->iscp + sizeof(struct iscp_struct));
-
-       memset((char *) p->iscp,0,sizeof(struct iscp_struct));
-       memset((char *) p->scp ,0,sizeof(struct scp_struct));
-
-       p->scp->iscp = make24(p->iscp);
-       p->scp->sysbus = SYSBUSVAL;
-       p->iscp->scb_offset = make16(p->scb);
-       p->iscp->scb_base = make24(dvma_btov(dev->mem_start));
-
-       p->iscp->busy = 1;
-       sun3_reset586();
-       sun3_attn586();
-
-       DELAY(1);
-
-       if(p->iscp->busy)
-               printk("%s: Init-Problems (alloc).\n",dev->name);
-
-       p->reseted = 0;
-
-       memset((char *)p->scb,0,sizeof(struct scb_struct));
-}
-
-struct net_device * __init sun3_82586_probe(int unit)
-{
-       struct net_device *dev;
-       unsigned long ioaddr;
-       static int found = 0;
-       int err = -ENOMEM;
-
-       /* check that this machine has an onboard 82586 */
-       switch(idprom->id_machtype) {
-       case SM_SUN3|SM_3_160:
-       case SM_SUN3|SM_3_260:
-               /* these machines have 82586 */
-               break;
-
-       default:
-               return ERR_PTR(-ENODEV);
-       }
-
-       if (found)
-               return ERR_PTR(-ENODEV);
-
-       ioaddr = (unsigned long)ioremap(IE_OBIO, SUN3_82586_TOTAL_SIZE);
-       if (!ioaddr)
-               return ERR_PTR(-ENOMEM);
-       found = 1;
-
-       dev = alloc_etherdev(sizeof(struct priv));
-       if (!dev)
-               goto out;
-       if (unit >= 0) {
-               sprintf(dev->name, "eth%d", unit);
-               netdev_boot_setup_check(dev);
-       }
-
-       dev->irq = IE_IRQ;
-       dev->base_addr = ioaddr;
-       err = sun3_82586_probe1(dev, ioaddr);
-       if (err)
-               goto out1;
-       err = register_netdev(dev);
-       if (err)
-               goto out2;
-       return dev;
-
-out2:
-       release_region(ioaddr, SUN3_82586_TOTAL_SIZE);
-out1:
-       free_netdev(dev);
-out:
-       iounmap((void __iomem *)ioaddr);
-       return ERR_PTR(err);
-}
-
-static const struct net_device_ops sun3_82586_netdev_ops = {
-       .ndo_open               = sun3_82586_open,
-       .ndo_stop               = sun3_82586_close,
-       .ndo_start_xmit         = sun3_82586_send_packet,
-       .ndo_set_multicast_list = set_multicast_list,
-       .ndo_tx_timeout         = sun3_82586_timeout,
-       .ndo_get_stats          = sun3_82586_get_stats,
-       .ndo_validate_addr      = eth_validate_addr,
-       .ndo_set_mac_address    = eth_mac_addr,
-       .ndo_change_mtu         = eth_change_mtu,
-};
-
-static int __init sun3_82586_probe1(struct net_device *dev,int ioaddr)
-{
-       int i, size, retval;
-
-       if (!request_region(ioaddr, SUN3_82586_TOTAL_SIZE, DRV_NAME))
-               return -EBUSY;
-
-       /* copy in the ethernet address from the prom */
-       for(i = 0; i < 6 ; i++)
-            dev->dev_addr[i] = idprom->id_ethaddr[i];
-
-       printk("%s: SUN3 Intel 82586 found at %lx, ",dev->name,dev->base_addr);
-
-       /*
-        * check (or search) IO-Memory, 32K
-        */
-       size = 0x8000;
-
-       dev->mem_start = (unsigned long)dvma_malloc_align(0x8000, 0x1000);
-       dev->mem_end = dev->mem_start + size;
-
-       if(size != 0x2000 && size != 0x4000 && size != 0x8000) {
-               printk("\n%s: Illegal memory size %d. Allowed is 0x2000 or 0x4000 or 0x8000 bytes.\n",dev->name,size);
-               retval = -ENODEV;
-               goto out;
-       }
-       if(!check586(dev,(char *) dev->mem_start,size)) {
-               printk("?memcheck, Can't find memory at 0x%lx with size %d!\n",dev->mem_start,size);
-               retval = -ENODEV;
-               goto out;
-       }
-
-       ((struct priv *)netdev_priv(dev))->memtop =
-                                       (char *)dvma_btov(dev->mem_start);
-       ((struct priv *)netdev_priv(dev))->base = (unsigned long) dvma_btov(0);
-       alloc586(dev);
-
-       /* set number of receive-buffs according to memsize */
-       if(size == 0x2000)
-               ((struct priv *)netdev_priv(dev))->num_recv_buffs =
-                                                       NUM_RECV_BUFFS_8;
-       else if(size == 0x4000)
-               ((struct priv *)netdev_priv(dev))->num_recv_buffs =
-                                                       NUM_RECV_BUFFS_16;
-       else
-               ((struct priv *)netdev_priv(dev))->num_recv_buffs =
-                                                       NUM_RECV_BUFFS_32;
-
-       printk("Memaddr: 0x%lx, Memsize: %d, IRQ %d\n",dev->mem_start,size, dev->irq);
-
-       dev->netdev_ops         = &sun3_82586_netdev_ops;
-       dev->watchdog_timeo     = HZ/20;
-
-       dev->if_port            = 0;
-       return 0;
-out:
-       release_region(ioaddr, SUN3_82586_TOTAL_SIZE);
-       return retval;
-}
-
-
-static int init586(struct net_device *dev)
-{
-       void *ptr;
-       int i,result=0;
-       struct priv *p = netdev_priv(dev);
-       volatile struct configure_cmd_struct    *cfg_cmd;
-       volatile struct iasetup_cmd_struct *ias_cmd;
-       volatile struct tdr_cmd_struct *tdr_cmd;
-       volatile struct mcsetup_cmd_struct *mc_cmd;
-       struct netdev_hw_addr *ha;
-       int num_addrs=netdev_mc_count(dev);
-
-       ptr = (void *) ((char *)p->scb + sizeof(struct scb_struct));
-
-       cfg_cmd = (struct configure_cmd_struct *)ptr; /* configure-command */
-       cfg_cmd->cmd_status     = 0;
-       cfg_cmd->cmd_cmd        = swab16(CMD_CONFIGURE | CMD_LAST);
-       cfg_cmd->cmd_link       = 0xffff;
-
-       cfg_cmd->byte_cnt       = 0x0a; /* number of cfg bytes */
-       cfg_cmd->fifo           = fifo; /* fifo-limit (8=tx:32/rx:64) */
-       cfg_cmd->sav_bf         = 0x40; /* hold or discard bad recv frames (bit 7) */
-       cfg_cmd->adr_len        = 0x2e; /* addr_len |!src_insert |pre-len |loopback */
-       cfg_cmd->priority       = 0x00;
-       cfg_cmd->ifs            = 0x60;
-       cfg_cmd->time_low       = 0x00;
-       cfg_cmd->time_high      = 0xf2;
-       cfg_cmd->promisc        = 0;
-       if(dev->flags & IFF_ALLMULTI) {
-               int len = ((char *) p->iscp - (char *) ptr - 8) / 6;
-               if(num_addrs > len)     {
-                       printk("%s: switching to promisc. mode\n",dev->name);
-                       cfg_cmd->promisc = 1;
-               }
-       }
-       if(dev->flags&IFF_PROMISC)
-               cfg_cmd->promisc = 1;
-       cfg_cmd->carr_coll      = 0x00;
-
-       p->scb->cbl_offset      = make16(cfg_cmd);
-       p->scb->cmd_ruc         = 0;
-
-       p->scb->cmd_cuc         = CUC_START; /* cmd.-unit start */
-       sun3_attn586();
-
-       WAIT_4_STAT_COMPL(cfg_cmd);
-
-       if((swab16(cfg_cmd->cmd_status) & (STAT_OK|STAT_COMPL)) != (STAT_COMPL|STAT_OK))
-       {
-               printk("%s: configure command failed: %x\n",dev->name,swab16(cfg_cmd->cmd_status));
-               return 1;
-       }
-
-       /*
-        * individual address setup
-        */
-
-       ias_cmd = (struct iasetup_cmd_struct *)ptr;
-
-       ias_cmd->cmd_status     = 0;
-       ias_cmd->cmd_cmd        = swab16(CMD_IASETUP | CMD_LAST);
-       ias_cmd->cmd_link       = 0xffff;
-
-       memcpy((char *)&ias_cmd->iaddr,(char *) dev->dev_addr,ETH_ALEN);
-
-       p->scb->cbl_offset = make16(ias_cmd);
-
-       p->scb->cmd_cuc = CUC_START; /* cmd.-unit start */
-       sun3_attn586();
-
-       WAIT_4_STAT_COMPL(ias_cmd);
-
-       if((swab16(ias_cmd->cmd_status) & (STAT_OK|STAT_COMPL)) != (STAT_OK|STAT_COMPL)) {
-               printk("%s (82586): individual address setup command failed: %04x\n",dev->name,swab16(ias_cmd->cmd_status));
-               return 1;
-       }
-
-       /*
-        * TDR, wire check .. e.g. no resistor e.t.c
-        */
-
-       tdr_cmd = (struct tdr_cmd_struct *)ptr;
-
-       tdr_cmd->cmd_status     = 0;
-       tdr_cmd->cmd_cmd        = swab16(CMD_TDR | CMD_LAST);
-       tdr_cmd->cmd_link       = 0xffff;
-       tdr_cmd->status         = 0;
-
-       p->scb->cbl_offset = make16(tdr_cmd);
-       p->scb->cmd_cuc = CUC_START; /* cmd.-unit start */
-       sun3_attn586();
-
-       WAIT_4_STAT_COMPL(tdr_cmd);
-
-       if(!(swab16(tdr_cmd->cmd_status) & STAT_COMPL))
-       {
-               printk("%s: Problems while running the TDR.\n",dev->name);
-       }
-       else
-       {
-               DELAY_16(); /* wait for result */
-               result = swab16(tdr_cmd->status);
-
-               p->scb->cmd_cuc = p->scb->cus & STAT_MASK;
-               sun3_attn586(); /* ack the interrupts */
-
-               if(result & TDR_LNK_OK)
-                       ;
-               else if(result & TDR_XCVR_PRB)
-                       printk("%s: TDR: Transceiver problem. Check the cable(s)!\n",dev->name);
-               else if(result & TDR_ET_OPN)
-                       printk("%s: TDR: No correct termination %d clocks away.\n",dev->name,result & TDR_TIMEMASK);
-               else if(result & TDR_ET_SRT)
-               {
-                       if (result & TDR_TIMEMASK) /* time == 0 -> strange :-) */
-                               printk("%s: TDR: Detected a short circuit %d clocks away.\n",dev->name,result & TDR_TIMEMASK);
-               }
-               else
-                       printk("%s: TDR: Unknown status %04x\n",dev->name,result);
-       }
-
-       /*
-        * Multicast setup
-        */
-       if(num_addrs && !(dev->flags & IFF_PROMISC) )
-       {
-               mc_cmd = (struct mcsetup_cmd_struct *) ptr;
-               mc_cmd->cmd_status = 0;
-               mc_cmd->cmd_cmd = swab16(CMD_MCSETUP | CMD_LAST);
-               mc_cmd->cmd_link = 0xffff;
-               mc_cmd->mc_cnt = swab16(num_addrs * 6);
-
-               i = 0;
-               netdev_for_each_mc_addr(ha, dev)
-                       memcpy((char *) mc_cmd->mc_list[i++],
-                              ha->addr, ETH_ALEN);
-
-               p->scb->cbl_offset = make16(mc_cmd);
-               p->scb->cmd_cuc = CUC_START;
-               sun3_attn586();
-
-               WAIT_4_STAT_COMPL(mc_cmd);
-
-               if( (swab16(mc_cmd->cmd_status) & (STAT_COMPL|STAT_OK)) != (STAT_COMPL|STAT_OK) )
-                       printk("%s: Can't apply multicast-address-list.\n",dev->name);
-       }
-
-       /*
-        * alloc nop/xmit-cmds
-        */
-#if (NUM_XMIT_BUFFS == 1)
-       for(i=0;i<2;i++)
-       {
-               p->nop_cmds[i]                  = (struct nop_cmd_struct *)ptr;
-               p->nop_cmds[i]->cmd_cmd         = swab16(CMD_NOP);
-               p->nop_cmds[i]->cmd_status      = 0;
-               p->nop_cmds[i]->cmd_link        = make16((p->nop_cmds[i]));
-               ptr = (char *) ptr + sizeof(struct nop_cmd_struct);
-       }
-#else
-       for(i=0;i<NUM_XMIT_BUFFS;i++)
-       {
-               p->nop_cmds[i]                  = (struct nop_cmd_struct *)ptr;
-               p->nop_cmds[i]->cmd_cmd         = swab16(CMD_NOP);
-               p->nop_cmds[i]->cmd_status      = 0;
-               p->nop_cmds[i]->cmd_link        = make16((p->nop_cmds[i]));
-               ptr = (char *) ptr + sizeof(struct nop_cmd_struct);
-       }
-#endif
-
-       ptr = alloc_rfa(dev,(void *)ptr); /* init receive-frame-area */
-
-       /*
-        * alloc xmit-buffs / init xmit_cmds
-        */
-       for(i=0;i<NUM_XMIT_BUFFS;i++)
-       {
-               p->xmit_cmds[i] = (struct transmit_cmd_struct *)ptr; /*transmit cmd/buff 0*/
-               ptr = (char *) ptr + sizeof(struct transmit_cmd_struct);
-               p->xmit_cbuffs[i] = (char *)ptr; /* char-buffs */
-               ptr = (char *) ptr + XMIT_BUFF_SIZE;
-               p->xmit_buffs[i] = (struct tbd_struct *)ptr; /* TBD */
-               ptr = (char *) ptr + sizeof(struct tbd_struct);
-               if((void *)ptr > (void *)dev->mem_end)
-               {
-                       printk("%s: not enough shared-mem for your configuration!\n",dev->name);
-                       return 1;
-               }
-               memset((char *)(p->xmit_cmds[i]) ,0, sizeof(struct transmit_cmd_struct));
-               memset((char *)(p->xmit_buffs[i]),0, sizeof(struct tbd_struct));
-               p->xmit_cmds[i]->cmd_link = make16(p->nop_cmds[(i+1)%NUM_XMIT_BUFFS]);
-               p->xmit_cmds[i]->cmd_status = swab16(STAT_COMPL);
-               p->xmit_cmds[i]->cmd_cmd = swab16(CMD_XMIT | CMD_INT);
-               p->xmit_cmds[i]->tbd_offset = make16((p->xmit_buffs[i]));
-               p->xmit_buffs[i]->next = 0xffff;
-               p->xmit_buffs[i]->buffer = make24((p->xmit_cbuffs[i]));
-       }
-
-       p->xmit_count = 0;
-       p->xmit_last    = 0;
-#ifndef NO_NOPCOMMANDS
-       p->nop_point    = 0;
-#endif
-
-        /*
-               * 'start transmitter'
-               */
-#ifndef NO_NOPCOMMANDS
-       p->scb->cbl_offset = make16(p->nop_cmds[0]);
-       p->scb->cmd_cuc = CUC_START;
-       sun3_attn586();
-       WAIT_4_SCB_CMD();
-#else
-       p->xmit_cmds[0]->cmd_link = make16(p->xmit_cmds[0]);
-       p->xmit_cmds[0]->cmd_cmd        = swab16(CMD_XMIT | CMD_SUSPEND | CMD_INT);
-#endif
-
-       /*
-        * ack. interrupts
-        */
-       p->scb->cmd_cuc = p->scb->cus & STAT_MASK;
-       sun3_attn586();
-       DELAY_16();
-
-       sun3_enaint();
-       sun3_active();
-
-       return 0;
-}
-
-/******************************************************
- * This is a helper routine for sun3_82586_rnr_int() and init586().
- * It sets up the Receive Frame Area (RFA).
- */
-
-static void *alloc_rfa(struct net_device *dev,void *ptr)
-{
-       volatile struct rfd_struct *rfd = (struct rfd_struct *)ptr;
-       volatile struct rbd_struct *rbd;
-       int i;
-       struct priv *p = netdev_priv(dev);
-
-       memset((char *) rfd,0,sizeof(struct rfd_struct)*(p->num_recv_buffs+rfdadd));
-       p->rfd_first = rfd;
-
-       for(i = 0; i < (p->num_recv_buffs+rfdadd); i++) {
-               rfd[i].next = make16(rfd + (i+1) % (p->num_recv_buffs+rfdadd) );
-               rfd[i].rbd_offset = 0xffff;
-       }
-       rfd[p->num_recv_buffs-1+rfdadd].last = RFD_SUSP;         /* RU suspend */
-
-       ptr = (void *) (rfd + (p->num_recv_buffs + rfdadd) );
-
-       rbd = (struct rbd_struct *) ptr;
-       ptr = (void *) (rbd + p->num_recv_buffs);
-
-        /* clr descriptors */
-       memset((char *) rbd,0,sizeof(struct rbd_struct)*(p->num_recv_buffs));
-
-       for(i=0;i<p->num_recv_buffs;i++)
-       {
-               rbd[i].next = make16((rbd + (i+1) % p->num_recv_buffs));
-               rbd[i].size = swab16(RECV_BUFF_SIZE);
-               rbd[i].buffer = make24(ptr);
-               ptr = (char *) ptr + RECV_BUFF_SIZE;
-       }
-
-       p->rfd_top      = p->rfd_first;
-       p->rfd_last = p->rfd_first + (p->num_recv_buffs - 1 + rfdadd);
-
-       p->scb->rfa_offset              = make16(p->rfd_first);
-       p->rfd_first->rbd_offset        = make16(rbd);
-
-       return ptr;
-}
-
-
-/**************************************************
- * Interrupt Handler ...
- */
-
-static irqreturn_t sun3_82586_interrupt(int irq,void *dev_id)
-{
-       struct net_device *dev = dev_id;
-       unsigned short stat;
-       int cnt=0;
-       struct priv *p;
-
-       if (!dev) {
-               printk ("sun3_82586-interrupt: irq %d for unknown device.\n",irq);
-               return IRQ_NONE;
-       }
-       p = netdev_priv(dev);
-
-       if(debuglevel > 1)
-               printk("I");
-
-       WAIT_4_SCB_CMD(); /* wait for last command      */
-
-       while((stat=p->scb->cus & STAT_MASK))
-       {
-               p->scb->cmd_cuc = stat;
-               sun3_attn586();
-
-               if(stat & STAT_FR)       /* received a frame */
-                       sun3_82586_rcv_int(dev);
-
-               if(stat & STAT_RNR) /* RU went 'not ready' */
-               {
-                       printk("(R)");
-                       if(p->scb->rus & RU_SUSPEND) /* special case: RU_SUSPEND */
-                       {
-                               WAIT_4_SCB_CMD();
-                               p->scb->cmd_ruc = RUC_RESUME;
-                               sun3_attn586();
-                               WAIT_4_SCB_CMD_RUC();
-                       }
-                       else
-                       {
-                               printk("%s: Receiver-Unit went 'NOT READY': %04x/%02x.\n",dev->name,(int) stat,(int) p->scb->rus);
-                               sun3_82586_rnr_int(dev);
-                       }
-               }
-
-               if(stat & STAT_CX)              /* command with I-bit set complete */
-                        sun3_82586_xmt_int(dev);
-
-#ifndef NO_NOPCOMMANDS
-               if(stat & STAT_CNA)     /* CU went 'not ready' */
-               {
-                       if(netif_running(dev))
-                               printk("%s: oops! CU has left active state. stat: %04x/%02x.\n",dev->name,(int) stat,(int) p->scb->cus);
-               }
-#endif
-
-               if(debuglevel > 1)
-                       printk("%d",cnt++);
-
-               WAIT_4_SCB_CMD(); /* wait for ack. (sun3_82586_xmt_int can be faster than ack!!) */
-               if(p->scb->cmd_cuc)      /* timed out? */
-               {
-                       printk("%s: Acknowledge timed out.\n",dev->name);
-                       sun3_disint();
-                       break;
-               }
-       }
-
-       if(debuglevel > 1)
-               printk("i");
-       return IRQ_HANDLED;
-}
-
-/*******************************************************
- * receive-interrupt
- */
-
-static void sun3_82586_rcv_int(struct net_device *dev)
-{
-       int status,cnt=0;
-       unsigned short totlen;
-       struct sk_buff *skb;
-       struct rbd_struct *rbd;
-       struct priv *p = netdev_priv(dev);
-
-       if(debuglevel > 0)
-               printk("R");
-
-       for(;(status = p->rfd_top->stat_high) & RFD_COMPL;)
-       {
-                       rbd = (struct rbd_struct *) make32(p->rfd_top->rbd_offset);
-
-                       if(status & RFD_OK) /* frame received without error? */
-                       {
-                               if( (totlen = swab16(rbd->status)) & RBD_LAST) /* the first and the last buffer? */
-                               {
-                                       totlen &= RBD_MASK; /* length of this frame */
-                                       rbd->status = 0;
-                                       skb = (struct sk_buff *) dev_alloc_skb(totlen+2);
-                                       if(skb != NULL)
-                                       {
-                                               skb_reserve(skb,2);
-                                               skb_put(skb,totlen);
-                                               skb_copy_to_linear_data(skb,(char *) p->base+swab32((unsigned long) rbd->buffer),totlen);
-                                               skb->protocol=eth_type_trans(skb,dev);
-                                               netif_rx(skb);
-                                               dev->stats.rx_packets++;
-                                       }
-                                       else
-                                               dev->stats.rx_dropped++;
-                               }
-                               else
-                               {
-                                       int rstat;
-                                                /* free all RBD's until RBD_LAST is set */
-                                       totlen = 0;
-                                       while(!((rstat=swab16(rbd->status)) & RBD_LAST))
-                                       {
-                                               totlen += rstat & RBD_MASK;
-                                               if(!rstat)
-                                               {
-                                                       printk("%s: Whoops .. no end mark in RBD list\n",dev->name);
-                                                       break;
-                                               }
-                                               rbd->status = 0;
-                                               rbd = (struct rbd_struct *) make32(rbd->next);
-                                       }
-                                       totlen += rstat & RBD_MASK;
-                                       rbd->status = 0;
-                                       printk("%s: received oversized frame! length: %d\n",dev->name,totlen);
-                                       dev->stats.rx_dropped++;
-                        }
-               }
-               else /* frame !(ok), only with 'save-bad-frames' */
-               {
-                       printk("%s: oops! rfd-error-status: %04x\n",dev->name,status);
-                       dev->stats.rx_errors++;
-               }
-               p->rfd_top->stat_high = 0;
-               p->rfd_top->last = RFD_SUSP; /* maybe exchange by RFD_LAST */
-               p->rfd_top->rbd_offset = 0xffff;
-               p->rfd_last->last = 0;                          /* delete RFD_SUSP      */
-               p->rfd_last = p->rfd_top;
-               p->rfd_top = (struct rfd_struct *) make32(p->rfd_top->next); /* step to next RFD */
-               p->scb->rfa_offset = make16(p->rfd_top);
-
-               if(debuglevel > 0)
-                       printk("%d",cnt++);
-       }
-
-       if(automatic_resume)
-       {
-               WAIT_4_SCB_CMD();
-               p->scb->cmd_ruc = RUC_RESUME;
-               sun3_attn586();
-               WAIT_4_SCB_CMD_RUC();
-       }
-
-#ifdef WAIT_4_BUSY
-       {
-               int i;
-               for(i=0;i<1024;i++)
-               {
-                       if(p->rfd_top->status)
-                               break;
-                       DELAY_16();
-                       if(i == 1023)
-                               printk("%s: RU hasn't fetched next RFD (not busy/complete)\n",dev->name);
-               }
-       }
-#endif
-
-#if 0
-       if(!at_least_one)
-       {
-               int i;
-               volatile struct rfd_struct *rfds=p->rfd_top;
-               volatile struct rbd_struct *rbds;
-               printk("%s: received a FC intr. without having a frame: %04x %d\n",dev->name,status,old_at_least);
-               for(i=0;i< (p->num_recv_buffs+4);i++)
-               {
-                       rbds = (struct rbd_struct *) make32(rfds->rbd_offset);
-                       printk("%04x:%04x ",rfds->status,rbds->status);
-                       rfds = (struct rfd_struct *) make32(rfds->next);
-               }
-               printk("\nerrs: %04x %04x stat: %04x\n",(int)p->scb->rsc_errs,(int)p->scb->ovrn_errs,(int)p->scb->status);
-               printk("\nerrs: %04x %04x rus: %02x, cus: %02x\n",(int)p->scb->rsc_errs,(int)p->scb->ovrn_errs,(int)p->scb->rus,(int)p->scb->cus);
-       }
-       old_at_least = at_least_one;
-#endif
-
-       if(debuglevel > 0)
-               printk("r");
-}
-
-/**********************************************************
- * handle 'Receiver went not ready'.
- */
-
-static void sun3_82586_rnr_int(struct net_device *dev)
-{
-       struct priv *p = netdev_priv(dev);
-
-       dev->stats.rx_errors++;
-
-       WAIT_4_SCB_CMD();               /* wait for the last cmd, WAIT_4_FULLSTAT?? */
-       p->scb->cmd_ruc = RUC_ABORT; /* usually the RU is in the 'no resource'-state .. abort it now. */
-       sun3_attn586();
-       WAIT_4_SCB_CMD_RUC();           /* wait for accept cmd. */
-
-       alloc_rfa(dev,(char *)p->rfd_first);
-/* maybe add a check here, before restarting the RU */
-       startrecv586(dev); /* restart RU */
-
-       printk("%s: Receive-Unit restarted. Status: %04x\n",dev->name,p->scb->rus);
-
-}
-
-/**********************************************************
- * handle xmit - interrupt
- */
-
-static void sun3_82586_xmt_int(struct net_device *dev)
-{
-       int status;
-       struct priv *p = netdev_priv(dev);
-
-       if(debuglevel > 0)
-               printk("X");
-
-       status = swab16(p->xmit_cmds[p->xmit_last]->cmd_status);
-       if(!(status & STAT_COMPL))
-               printk("%s: strange .. xmit-int without a 'COMPLETE'\n",dev->name);
-
-       if(status & STAT_OK)
-       {
-               dev->stats.tx_packets++;
-               dev->stats.collisions += (status & TCMD_MAXCOLLMASK);
-       }
-       else
-       {
-               dev->stats.tx_errors++;
-               if(status & TCMD_LATECOLL) {
-                       printk("%s: late collision detected.\n",dev->name);
-                       dev->stats.collisions++;
-               }
-               else if(status & TCMD_NOCARRIER) {
-                       dev->stats.tx_carrier_errors++;
-                       printk("%s: no carrier detected.\n",dev->name);
-               }
-               else if(status & TCMD_LOSTCTS)
-                       printk("%s: loss of CTS detected.\n",dev->name);
-               else if(status & TCMD_UNDERRUN) {
-                       dev->stats.tx_fifo_errors++;
-                       printk("%s: DMA underrun detected.\n",dev->name);
-               }
-               else if(status & TCMD_MAXCOLL) {
-                       printk("%s: Max. collisions exceeded.\n",dev->name);
-                       dev->stats.collisions += 16;
-               }
-       }
-
-#if (NUM_XMIT_BUFFS > 1)
-       if( (++p->xmit_last) == NUM_XMIT_BUFFS)
-               p->xmit_last = 0;
-#endif
-       netif_wake_queue(dev);
-}
-
-/***********************************************************
- * (re)start the receiver
- */
-
-static void startrecv586(struct net_device *dev)
-{
-       struct priv *p = netdev_priv(dev);
-
-       WAIT_4_SCB_CMD();
-       WAIT_4_SCB_CMD_RUC();
-       p->scb->rfa_offset = make16(p->rfd_first);
-       p->scb->cmd_ruc = RUC_START;
-       sun3_attn586();         /* start cmd. */
-       WAIT_4_SCB_CMD_RUC();   /* wait for accept cmd. (no timeout!!) */
-}
-
-static void sun3_82586_timeout(struct net_device *dev)
-{
-       struct priv *p = netdev_priv(dev);
-#ifndef NO_NOPCOMMANDS
-       if(p->scb->cus & CU_ACTIVE) /* COMMAND-UNIT active? */
-       {
-               netif_wake_queue(dev);
-#ifdef DEBUG
-               printk("%s: strange ... timeout with CU active?!?\n",dev->name);
-               printk("%s: X0: %04x N0: %04x N1: %04x %d\n",dev->name,(int)swab16(p->xmit_cmds[0]->cmd_status),(int)swab16(p->nop_cmds[0]->cmd_status),(int)swab16(p->nop_cmds[1]->cmd_status),(int)p->nop_point);
-#endif
-               p->scb->cmd_cuc = CUC_ABORT;
-               sun3_attn586();
-               WAIT_4_SCB_CMD();
-               p->scb->cbl_offset = make16(p->nop_cmds[p->nop_point]);
-               p->scb->cmd_cuc = CUC_START;
-               sun3_attn586();
-               WAIT_4_SCB_CMD();
-               dev->trans_start = jiffies; /* prevent tx timeout */
-               return 0;
-       }
-#endif
-       {
-#ifdef DEBUG
-               printk("%s: xmitter timed out, try to restart! stat: %02x\n",dev->name,p->scb->cus);
-               printk("%s: command-stats: %04x %04x\n",dev->name,swab16(p->xmit_cmds[0]->cmd_status),swab16(p->xmit_cmds[1]->cmd_status));
-               printk("%s: check, whether you set the right interrupt number!\n",dev->name);
-#endif
-               sun3_82586_close(dev);
-               sun3_82586_open(dev);
-       }
-       dev->trans_start = jiffies; /* prevent tx timeout */
-}
-
-/******************************************************
- * send frame
- */
-
-static int sun3_82586_send_packet(struct sk_buff *skb, struct net_device *dev)
-{
-       int len,i;
-#ifndef NO_NOPCOMMANDS
-       int next_nop;
-#endif
-       struct priv *p = netdev_priv(dev);
-
-       if(skb->len > XMIT_BUFF_SIZE)
-       {
-               printk("%s: Sorry, max. framelength is %d bytes. The length of your frame is %d bytes.\n",dev->name,XMIT_BUFF_SIZE,skb->len);
-               return NETDEV_TX_OK;
-       }
-
-       netif_stop_queue(dev);
-
-#if(NUM_XMIT_BUFFS > 1)
-       if(test_and_set_bit(0,(void *) &p->lock)) {
-               printk("%s: Queue was locked\n",dev->name);
-               return NETDEV_TX_BUSY;
-       }
-       else
-#endif
-       {
-               len = skb->len;
-               if (len < ETH_ZLEN) {
-                       memset((void *)p->xmit_cbuffs[p->xmit_count], 0,
-                              ETH_ZLEN);
-                       len = ETH_ZLEN;
-               }
-               skb_copy_from_linear_data(skb, (void *)p->xmit_cbuffs[p->xmit_count], skb->len);
-
-#if (NUM_XMIT_BUFFS == 1)
-#      ifdef NO_NOPCOMMANDS
-
-#ifdef DEBUG
-               if(p->scb->cus & CU_ACTIVE)
-               {
-                       printk("%s: Hmmm .. CU is still running and we wanna send a new packet.\n",dev->name);
-                       printk("%s: stat: %04x %04x\n",dev->name,p->scb->cus,swab16(p->xmit_cmds[0]->cmd_status));
-               }
-#endif
-
-               p->xmit_buffs[0]->size = swab16(TBD_LAST | len);
-               for(i=0;i<16;i++)
-               {
-                       p->xmit_cmds[0]->cmd_status = 0;
-                       WAIT_4_SCB_CMD();
-                       if( (p->scb->cus & CU_STATUS) == CU_SUSPEND)
-                               p->scb->cmd_cuc = CUC_RESUME;
-                       else
-                       {
-                               p->scb->cbl_offset = make16(p->xmit_cmds[0]);
-                               p->scb->cmd_cuc = CUC_START;
-                       }
-
-                       sun3_attn586();
-                       if(!i)
-                               dev_kfree_skb(skb);
-                       WAIT_4_SCB_CMD();
-                       if( (p->scb->cus & CU_ACTIVE)) /* test it, because CU sometimes doesn't start immediately */
-                               break;
-                       if(p->xmit_cmds[0]->cmd_status)
-                               break;
-                       if(i==15)
-                               printk("%s: Can't start transmit-command.\n",dev->name);
-               }
-#      else
-               next_nop = (p->nop_point + 1) & 0x1;
-               p->xmit_buffs[0]->size = swab16(TBD_LAST | len);
-
-               p->xmit_cmds[0]->cmd_link        = p->nop_cmds[next_nop]->cmd_link
-                       = make16((p->nop_cmds[next_nop]));
-               p->xmit_cmds[0]->cmd_status = p->nop_cmds[next_nop]->cmd_status = 0;
-
-               p->nop_cmds[p->nop_point]->cmd_link = make16((p->xmit_cmds[0]));
-               p->nop_point = next_nop;
-               dev_kfree_skb(skb);
-#      endif
-#else
-               p->xmit_buffs[p->xmit_count]->size = swab16(TBD_LAST | len);
-               if( (next_nop = p->xmit_count + 1) == NUM_XMIT_BUFFS )
-                       next_nop = 0;
-
-               p->xmit_cmds[p->xmit_count]->cmd_status = 0;
-               /* linkpointer of xmit-command already points to next nop cmd */
-               p->nop_cmds[next_nop]->cmd_link = make16((p->nop_cmds[next_nop]));
-               p->nop_cmds[next_nop]->cmd_status = 0;
-
-               p->nop_cmds[p->xmit_count]->cmd_link = make16((p->xmit_cmds[p->xmit_count]));
-               p->xmit_count = next_nop;
-
-               {
-                       unsigned long flags;
-                       local_irq_save(flags);
-                       if(p->xmit_count != p->xmit_last)
-                               netif_wake_queue(dev);
-                       p->lock = 0;
-                       local_irq_restore(flags);
-               }
-               dev_kfree_skb(skb);
-#endif
-       }
-       return NETDEV_TX_OK;
-}
-
-/*******************************************
- * Someone wanna have the statistics
- */
-
-static struct net_device_stats *sun3_82586_get_stats(struct net_device *dev)
-{
-       struct priv *p = netdev_priv(dev);
-       unsigned short crc,aln,rsc,ovrn;
-
-       crc = swab16(p->scb->crc_errs); /* get error-statistic from the ni82586 */
-       p->scb->crc_errs = 0;
-       aln = swab16(p->scb->aln_errs);
-       p->scb->aln_errs = 0;
-       rsc = swab16(p->scb->rsc_errs);
-       p->scb->rsc_errs = 0;
-       ovrn = swab16(p->scb->ovrn_errs);
-       p->scb->ovrn_errs = 0;
-
-       dev->stats.rx_crc_errors += crc;
-       dev->stats.rx_fifo_errors += ovrn;
-       dev->stats.rx_frame_errors += aln;
-       dev->stats.rx_dropped += rsc;
-
-       return &dev->stats;
-}
-
-/********************************************************
- * Set MC list ..
- */
-
-static void set_multicast_list(struct net_device *dev)
-{
-       netif_stop_queue(dev);
-       sun3_disint();
-       alloc586(dev);
-       init586(dev);
-       startrecv586(dev);
-       sun3_enaint();
-       netif_wake_queue(dev);
-}
-
-#ifdef MODULE
-#error This code is not currently supported as a module
-static struct net_device *dev_sun3_82586;
-
-int init_module(void)
-{
-       dev_sun3_82586 = sun3_82586_probe(-1);
-       if (IS_ERR(dev_sun3_82586))
-               return PTR_ERR(dev_sun3_82586);
-       return 0;
-}
-
-void cleanup_module(void)
-{
-       unsigned long ioaddr = dev_sun3_82586->base_addr;
-       unregister_netdev(dev_sun3_82586);
-       release_region(ioaddr, SUN3_82586_TOTAL_SIZE);
-       iounmap((void *)ioaddr);
-       free_netdev(dev_sun3_82586);
-}
-#endif /* MODULE */
-
-#if 0
-/*
- * DUMP .. we expect a not running CMD unit and enough space
- */
-void sun3_82586_dump(struct net_device *dev,void *ptr)
-{
-       struct priv *p = netdev_priv(dev);
-       struct dump_cmd_struct *dump_cmd = (struct dump_cmd_struct *) ptr;
-       int i;
-
-       p->scb->cmd_cuc = CUC_ABORT;
-       sun3_attn586();
-       WAIT_4_SCB_CMD();
-       WAIT_4_SCB_CMD_RUC();
-
-       dump_cmd->cmd_status = 0;
-       dump_cmd->cmd_cmd = CMD_DUMP | CMD_LAST;
-       dump_cmd->dump_offset = make16((dump_cmd + 1));
-       dump_cmd->cmd_link = 0xffff;
-
-       p->scb->cbl_offset = make16(dump_cmd);
-       p->scb->cmd_cuc = CUC_START;
-       sun3_attn586();
-       WAIT_4_STAT_COMPL(dump_cmd);
-
-       if( (dump_cmd->cmd_status & (STAT_COMPL|STAT_OK)) != (STAT_COMPL|STAT_OK) )
-                               printk("%s: Can't get dump information.\n",dev->name);
-
-       for(i=0;i<170;i++) {
-               printk("%02x ",(int) ((unsigned char *) (dump_cmd + 1))[i]);
-               if(i % 24 == 23)
-                       printk("\n");
-       }
-       printk("\n");
-}
-#endif
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/sun3_82586.h b/drivers/net/sun3_82586.h
deleted file mode 100644 (file)
index 93346f0..0000000
+++ /dev/null
@@ -1,318 +0,0 @@
-/*
- * Intel i82586 Ethernet definitions
- *
- * This is an extension to the Linux operating system, and is covered by the
- * same Gnu Public License that covers that work.
- *
- * copyrights (c) 1994 by Michael Hipp (hippm@informatik.uni-tuebingen.de)
- *
- * I have done a look in the following sources:
- *   crynwr-packet-driver by Russ Nelson
- *   Garret A. Wollman's i82586-driver for BSD
- */
-
-/*
- * Cloned from ni52.h, copyright as above.
- *
- * Modified for Sun3 OBIO i82586 by Sam Creasey (sammy@sammy.net)
- */
-
-
-/* defines for the obio chip (not vme) */
-#define IEOB_NORSET 0x80        /* don't reset the board */
-#define IEOB_ONAIR  0x40        /* put us on the air */
-#define IEOB_ATTEN  0x20        /* attention! */
-#define IEOB_IENAB  0x10        /* interrupt enable */
-#define IEOB_XXXXX  0x08        /* free bit */
-#define IEOB_XCVRL2 0x04        /* level 2 transceiver? */
-#define IEOB_BUSERR 0x02        /* bus error */
-#define IEOB_INT    0x01        /* interrupt */
-
-/* where the obio one lives */
-#define IE_OBIO 0xc0000
-#define IE_IRQ 3
-
-/*
- * where to find the System Configuration Pointer (SCP)
- */
-#define SCP_DEFAULT_ADDRESS 0xfffff4
-
-
-/*
- * System Configuration Pointer Struct
- */
-
-struct scp_struct
-{
-  unsigned short zero_dum0;    /* has to be zero */
-  unsigned char  sysbus;       /* 0=16Bit,1=8Bit */
-  unsigned char  zero_dum1;    /* has to be zero for 586 */
-  unsigned short zero_dum2;
-  unsigned short zero_dum3;
-  char          *iscp;         /* pointer to the iscp-block */
-};
-
-
-/*
- * Intermediate System Configuration Pointer (ISCP)
- */
-struct iscp_struct
-{
-  unsigned char  busy;          /* 586 clears after successful init */
-  unsigned char  zero_dummy;    /* has to be zero */
-  unsigned short scb_offset;    /* pointeroffset to the scb_base */
-  char          *scb_base;      /* base-address of all 16-bit offsets */
-};
-
-/*
- * System Control Block (SCB)
- */
-struct scb_struct
-{
-  unsigned char rus;
-  unsigned char cus;
-  unsigned char cmd_ruc;           /* command word: RU part */
-  unsigned char cmd_cuc;           /* command word: CU part & ACK */
-  unsigned short cbl_offset;    /* pointeroffset, command block list */
-  unsigned short rfa_offset;    /* pointeroffset, receive frame area */
-  unsigned short crc_errs;      /* CRC-Error counter */
-  unsigned short aln_errs;      /* allignmenterror counter */
-  unsigned short rsc_errs;      /* Resourceerror counter */
-  unsigned short ovrn_errs;     /* OVerrunerror counter */
-};
-
-/*
- * possible command values for the command word
- */
-#define RUC_MASK       0x0070  /* mask for RU commands */
-#define RUC_NOP                0x0000  /* NOP-command */
-#define RUC_START      0x0010  /* start RU */
-#define RUC_RESUME     0x0020  /* resume RU after suspend */
-#define RUC_SUSPEND    0x0030  /* suspend RU */
-#define RUC_ABORT      0x0040  /* abort receiver operation immediately */
-
-#define CUC_MASK        0x07  /* mask for CU command */
-#define CUC_NOP         0x00  /* NOP-command */
-#define CUC_START       0x01  /* start execution of 1. cmd on the CBL */
-#define CUC_RESUME      0x02  /* resume after suspend */
-#define CUC_SUSPEND     0x03  /* Suspend CU */
-#define CUC_ABORT       0x04  /* abort command operation immediately */
-
-#define ACK_MASK        0xf0  /* mask for ACK command */
-#define ACK_CX          0x80  /* acknowledges STAT_CX */
-#define ACK_FR          0x40  /* ack. STAT_FR */
-#define ACK_CNA         0x20  /* ack. STAT_CNA */
-#define ACK_RNR         0x10  /* ack. STAT_RNR */
-
-/*
- * possible status values for the status word
- */
-#define STAT_MASK       0xf0  /* mask for cause of interrupt */
-#define STAT_CX         0x80  /* CU finished cmd with its I bit set */
-#define STAT_FR         0x40  /* RU finished receiving a frame */
-#define STAT_CNA        0x20  /* CU left active state */
-#define STAT_RNR        0x10  /* RU left ready state */
-
-#define CU_STATUS       0x7   /* CU status, 0=idle */
-#define CU_SUSPEND      0x1   /* CU is suspended */
-#define CU_ACTIVE       0x2   /* CU is active */
-
-#define RU_STATUS      0x70    /* RU status, 0=idle */
-#define RU_SUSPEND     0x10    /* RU suspended */
-#define RU_NOSPACE     0x20    /* RU no resources */
-#define RU_READY       0x40    /* RU is ready */
-
-/*
- * Receive Frame Descriptor (RFD)
- */
-struct rfd_struct
-{
-  unsigned char  stat_low;     /* status word */
-  unsigned char  stat_high;    /* status word */
-  unsigned char  rfd_sf;       /* 82596 mode only */
-  unsigned char  last;         /* Bit15,Last Frame on List / Bit14,suspend */
-  unsigned short next;         /* linkoffset to next RFD */
-  unsigned short rbd_offset;   /* pointeroffset to RBD-buffer */
-  unsigned char  dest[6];      /* ethernet-address, destination */
-  unsigned char  source[6];    /* ethernet-address, source */
-  unsigned short length;       /* 802.3 frame-length */
-  unsigned short zero_dummy;   /* dummy */
-};
-
-#define RFD_LAST     0x80      /* last: last rfd in the list */
-#define RFD_SUSP     0x40      /* last: suspend RU after  */
-#define RFD_COMPL    0x80
-#define RFD_OK       0x20
-#define RFD_BUSY     0x40
-#define RFD_ERR_LEN  0x10     /* Length error (if enabled length-checking */
-#define RFD_ERR_CRC  0x08     /* CRC error */
-#define RFD_ERR_ALGN 0x04     /* Alignment error */
-#define RFD_ERR_RNR  0x02     /* status: receiver out of resources */
-#define RFD_ERR_OVR  0x01     /* DMA Overrun! */
-
-#define RFD_ERR_FTS  0x0080    /* Frame to short */
-#define RFD_ERR_NEOP 0x0040    /* No EOP flag (for bitstuffing only) */
-#define RFD_ERR_TRUN 0x0020    /* (82596 only/SF mode) indicates truncated frame */
-#define RFD_MATCHADD 0x0002     /* status: Destinationaddress !matches IA (only 82596) */
-#define RFD_COLLDET  0x0001    /* Detected collision during reception */
-
-/*
- * Receive Buffer Descriptor (RBD)
- */
-struct rbd_struct
-{
-  unsigned short status;       /* status word,number of used bytes in buff */
-  unsigned short next;         /* pointeroffset to next RBD */
-  char          *buffer;       /* receive buffer address pointer */
-  unsigned short size;         /* size of this buffer */
-  unsigned short zero_dummy;    /* dummy */
-};
-
-#define RBD_LAST       0x8000  /* last buffer */
-#define RBD_USED       0x4000  /* this buffer has data */
-#define RBD_MASK       0x3fff  /* size-mask for length */
-
-/*
- * Statusvalues for Commands/RFD
- */
-#define STAT_COMPL   0x8000    /* status: frame/command is complete */
-#define STAT_BUSY    0x4000    /* status: frame/command is busy */
-#define STAT_OK      0x2000    /* status: frame/command is ok */
-
-/*
- * Action-Commands
- */
-#define CMD_NOP                0x0000  /* NOP */
-#define CMD_IASETUP    0x0001  /* initial address setup command */
-#define CMD_CONFIGURE  0x0002  /* configure command */
-#define CMD_MCSETUP    0x0003  /* MC setup command */
-#define CMD_XMIT       0x0004  /* transmit command */
-#define CMD_TDR                0x0005  /* time domain reflectometer (TDR) command */
-#define CMD_DUMP       0x0006  /* dump command */
-#define CMD_DIAGNOSE   0x0007  /* diagnose command */
-
-/*
- * Action command bits
- */
-#define CMD_LAST       0x8000  /* indicates last command in the CBL */
-#define CMD_SUSPEND    0x4000  /* suspend CU after this CB */
-#define CMD_INT                0x2000  /* generate interrupt after execution */
-
-/*
- * NOP - command
- */
-struct nop_cmd_struct
-{
-  unsigned short cmd_status;   /* status of this command */
-  unsigned short cmd_cmd;       /* the command itself (+bits) */
-  unsigned short cmd_link;      /* offsetpointer to next command */
-};
-
-/*
- * IA Setup command
- */
-struct iasetup_cmd_struct
-{
-  unsigned short cmd_status;
-  unsigned short cmd_cmd;
-  unsigned short cmd_link;
-  unsigned char  iaddr[6];
-};
-
-/*
- * Configure command
- */
-struct configure_cmd_struct
-{
-  unsigned short cmd_status;
-  unsigned short cmd_cmd;
-  unsigned short cmd_link;
-  unsigned char  byte_cnt;   /* size of the config-cmd */
-  unsigned char  fifo;       /* fifo/recv monitor */
-  unsigned char  sav_bf;     /* save bad frames (bit7=1)*/
-  unsigned char  adr_len;    /* adr_len(0-2),al_loc(3),pream(4-5),loopbak(6-7)*/
-  unsigned char  priority;   /* lin_prio(0-2),exp_prio(4-6),bof_metd(7) */
-  unsigned char  ifs;        /* inter frame spacing */
-  unsigned char  time_low;   /* slot time low */
-  unsigned char  time_high;  /* slot time high(0-2) and max. retries(4-7) */
-  unsigned char  promisc;    /* promisc-mode(0) , et al (1-7) */
-  unsigned char  carr_coll;  /* carrier(0-3)/collision(4-7) stuff */
-  unsigned char  fram_len;   /* minimal frame len */
-  unsigned char  dummy;             /* dummy */
-};
-
-/*
- * Multicast Setup command
- */
-struct mcsetup_cmd_struct
-{
-  unsigned short cmd_status;
-  unsigned short cmd_cmd;
-  unsigned short cmd_link;
-  unsigned short mc_cnt;               /* number of bytes in the MC-List */
-  unsigned char  mc_list[0][6];        /* pointer to 6 bytes entries */
-};
-
-/*
- * DUMP command
- */
-struct dump_cmd_struct
-{
-  unsigned short cmd_status;
-  unsigned short cmd_cmd;
-  unsigned short cmd_link;
-  unsigned short dump_offset;    /* pointeroffset to DUMP space */
-};
-
-/*
- * transmit command
- */
-struct transmit_cmd_struct
-{
-  unsigned short cmd_status;
-  unsigned short cmd_cmd;
-  unsigned short cmd_link;
-  unsigned short tbd_offset;   /* pointeroffset to TBD */
-  unsigned char  dest[6];       /* destination address of the frame */
-  unsigned short length;       /* user defined: 802.3 length / Ether type */
-};
-
-#define TCMD_ERRMASK     0x0fa0
-#define TCMD_MAXCOLLMASK 0x000f
-#define TCMD_MAXCOLL     0x0020
-#define TCMD_HEARTBEAT   0x0040
-#define TCMD_DEFERRED    0x0080
-#define TCMD_UNDERRUN    0x0100
-#define TCMD_LOSTCTS     0x0200
-#define TCMD_NOCARRIER   0x0400
-#define TCMD_LATECOLL    0x0800
-
-struct tdr_cmd_struct
-{
-  unsigned short cmd_status;
-  unsigned short cmd_cmd;
-  unsigned short cmd_link;
-  unsigned short status;
-};
-
-#define TDR_LNK_OK     0x8000  /* No link problem identified */
-#define TDR_XCVR_PRB   0x4000  /* indicates a transceiver problem */
-#define TDR_ET_OPN     0x2000  /* open, no correct termination */
-#define TDR_ET_SRT     0x1000  /* TDR detected a short circuit */
-#define TDR_TIMEMASK   0x07ff  /* mask for the time field */
-
-/*
- * Transmit Buffer Descriptor (TBD)
- */
-struct tbd_struct
-{
-  unsigned short size;         /* size + EOF-Flag(15) */
-  unsigned short next;          /* pointeroffset to next TBD */
-  char          *buffer;        /* pointer to buffer */
-};
-
-#define TBD_LAST 0x8000         /* EOF-Flag, indicates last buffer in list */
-
-
-
-
diff --git a/drivers/net/znet.c b/drivers/net/znet.c
deleted file mode 100644 (file)
index 8b88817..0000000
+++ /dev/null
@@ -1,924 +0,0 @@
-/* znet.c: An Zenith Z-Note ethernet driver for linux. */
-
-/*
-       Written by Donald Becker.
-
-       The author may be reached as becker@scyld.com.
-       This driver is based on the Linux skeleton driver.  The copyright of the
-       skeleton driver is held by the United States Government, as represented
-       by DIRNSA, and it is released under the GPL.
-
-       Thanks to Mike Hollick for alpha testing and suggestions.
-
-  References:
-          The Crynwr packet driver.
-
-         "82593 CSMA/CD Core LAN Controller" Intel datasheet, 1992
-         Intel Microcommunications Databook, Vol. 1, 1990.
-    As usual with Intel, the documentation is incomplete and inaccurate.
-       I had to read the Crynwr packet driver to figure out how to actually
-       use the i82593, and guess at what register bits matched the loosely
-       related i82586.
-
-                                       Theory of Operation
-
-       The i82593 used in the Zenith Z-Note series operates using two(!) slave
-       DMA     channels, one interrupt, and one 8-bit I/O port.
-
-       While there     several ways to configure '593 DMA system, I chose the one
-       that seemed commensurate with the highest system performance in the face
-       of moderate interrupt latency: Both DMA channels are configured as
-       recirculating ring buffers, with one channel (#0) dedicated to Rx and
-       the other channel (#1) to Tx and configuration.  (Note that this is
-       different than the Crynwr driver, where the Tx DMA channel is initialized
-       before each operation.  That approach simplifies operation and Tx error
-       recovery, but requires additional I/O in normal operation and precludes
-       transmit buffer chaining.)
-
-       Both rings are set to 8192 bytes using {TX,RX}_RING_SIZE.  This provides
-       a reasonable ring size for Rx, while simplifying DMA buffer allocation --
-       DMA buffers must not cross a 128K boundary.  (In truth the size selection
-       was influenced by my lack of '593 documentation.  I thus was constrained
-       to use the Crynwr '593 initialization table, which sets the Rx ring size
-       to 8K.)
-
-       Despite my usual low opinion about Intel-designed parts, I must admit
-       that the bulk data handling of the i82593 is a good design for
-       an integrated system, like a laptop, where using two slave DMA channels
-       doesn't pose a problem.  I still take issue with using only a single I/O
-       port.  In the same controlled environment there are essentially no
-       limitations on I/O space, and using multiple locations would eliminate
-       the     need for multiple operations when looking at status registers,
-       setting the Rx ring boundary, or switching to promiscuous mode.
-
-       I also question Zenith's selection of the '593: one of the advertised
-       advantages of earlier Intel parts was that if you figured out the magic
-       initialization incantation you could use the same part on many different
-       network types.  Zenith's use of the "FriendlyNet" (sic) connector rather
-       than an on-board transceiver leads me to believe that they were planning
-       to take advantage of this.  But, uhmmm, the '593 omits all but ethernet
-       functionality from the serial subsystem.
- */
-
-/* 10/2002
-
-   o Resurected for Linux 2.5+ by Marc Zyngier <maz@wild-wind.fr.eu.org> :
-
-   - Removed strange DMA snooping in znet_sent_packet, which lead to
-     TX buffer corruption on my laptop.
-   - Use init_etherdev stuff.
-   - Use kmalloc-ed DMA buffers.
-   - Use as few global variables as possible.
-   - Use proper resources management.
-   - Use wireless/i82593.h as much as possible (structure, constants)
-   - Compiles as module or build-in.
-   - Now survives unplugging/replugging cable.
-
-   Some code was taken from wavelan_cs.
-
-   Tested on a vintage Zenith Z-Note 433Lnp+. Probably broken on
-   anything else. Testers (and detailed bug reports) are welcome :-).
-
-   o TODO :
-
-   - Properly handle multicast
-   - Understand why some traffic patterns add a 1s latency...
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/if_arp.h>
-#include <linux/bitops.h>
-
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-
-#include <linux/i82593.h>
-
-static char version[] __initdata = "znet.c:v1.02 9/23/94 becker@scyld.com\n";
-
-#ifndef ZNET_DEBUG
-#define ZNET_DEBUG 1
-#endif
-static unsigned int znet_debug = ZNET_DEBUG;
-module_param (znet_debug, int, 0);
-MODULE_PARM_DESC (znet_debug, "ZNet debug level");
-MODULE_LICENSE("GPL");
-
-/* The DMA modes we need aren't in <dma.h>. */
-#define DMA_RX_MODE            0x14    /* Auto init, I/O to mem, ++, demand. */
-#define DMA_TX_MODE            0x18    /* Auto init, Mem to I/O, ++, demand. */
-#define dma_page_eq(ptr1, ptr2) ((long)(ptr1)>>17 == (long)(ptr2)>>17)
-#define RX_BUF_SIZE 8192
-#define TX_BUF_SIZE 8192
-#define DMA_BUF_SIZE (RX_BUF_SIZE + 16)        /* 8k + 16 bytes for trailers */
-
-#define TX_TIMEOUT     (HZ/10)
-
-struct znet_private {
-       int rx_dma, tx_dma;
-       spinlock_t lock;
-       short sia_base, sia_size, io_size;
-       struct i82593_conf_block i593_init;
-       /* The starting, current, and end pointers for the packet buffers. */
-       ushort *rx_start, *rx_cur, *rx_end;
-       ushort *tx_start, *tx_cur, *tx_end;
-       ushort tx_buf_len;                      /* Tx buffer length, in words. */
-};
-
-/* Only one can be built-in;-> */
-static struct net_device *znet_dev;
-
-struct netidblk {
-       char magic[8];          /* The magic number (string) "NETIDBLK" */
-       unsigned char netid[8]; /* The physical station address */
-       char nettype, globalopt;
-       char vendor[8];         /* The machine vendor and product name. */
-       char product[8];
-       char irq1, irq2;                /* Interrupts, only one is currently used.      */
-       char dma1, dma2;
-       short dma_mem_misc[8];          /* DMA buffer locations (unused in Linux). */
-       short iobase1, iosize1;
-       short iobase2, iosize2;         /* Second iobase unused. */
-       char driver_options;                    /* Misc. bits */
-       char pad;
-};
-
-static int     znet_open(struct net_device *dev);
-static netdev_tx_t znet_send_packet(struct sk_buff *skb,
-                                   struct net_device *dev);
-static irqreturn_t znet_interrupt(int irq, void *dev_id);
-static void    znet_rx(struct net_device *dev);
-static int     znet_close(struct net_device *dev);
-static void hardware_init(struct net_device *dev);
-static void update_stop_hit(short ioaddr, unsigned short rx_stop_offset);
-static void znet_tx_timeout (struct net_device *dev);
-
-/* Request needed resources */
-static int znet_request_resources (struct net_device *dev)
-{
-       struct znet_private *znet = netdev_priv(dev);
-
-       if (request_irq (dev->irq, znet_interrupt, 0, "ZNet", dev))
-               goto failed;
-       if (request_dma (znet->rx_dma, "ZNet rx"))
-               goto free_irq;
-       if (request_dma (znet->tx_dma, "ZNet tx"))
-               goto free_rx_dma;
-       if (!request_region (znet->sia_base, znet->sia_size, "ZNet SIA"))
-               goto free_tx_dma;
-       if (!request_region (dev->base_addr, znet->io_size, "ZNet I/O"))
-               goto free_sia;
-
-       return 0;                               /* Happy ! */
-
- free_sia:
-       release_region (znet->sia_base, znet->sia_size);
- free_tx_dma:
-       free_dma (znet->tx_dma);
- free_rx_dma:
-       free_dma (znet->rx_dma);
- free_irq:
-       free_irq (dev->irq, dev);
- failed:
-       return -1;
-}
-
-static void znet_release_resources (struct net_device *dev)
-{
-       struct znet_private *znet = netdev_priv(dev);
-
-       release_region (znet->sia_base, znet->sia_size);
-       release_region (dev->base_addr, znet->io_size);
-       free_dma (znet->tx_dma);
-       free_dma (znet->rx_dma);
-       free_irq (dev->irq, dev);
-}
-
-/* Keep the magical SIA stuff in a single function... */
-static void znet_transceiver_power (struct net_device *dev, int on)
-{
-       struct znet_private *znet = netdev_priv(dev);
-       unsigned char v;
-
-       /* Turn on/off the 82501 SIA, using zenith-specific magic. */
-       /* Select LAN control register */
-       outb(0x10, znet->sia_base);
-
-       if (on)
-               v = inb(znet->sia_base + 1) | 0x84;
-       else
-               v = inb(znet->sia_base + 1) & ~0x84;
-
-       outb(v, znet->sia_base+1); /* Turn on/off LAN power (bit 2). */
-}
-
-/* Init the i82593, with current promisc/mcast configuration.
-   Also used from hardware_init. */
-static void znet_set_multicast_list (struct net_device *dev)
-{
-       struct znet_private *znet = netdev_priv(dev);
-       short ioaddr = dev->base_addr;
-       struct i82593_conf_block *cfblk = &znet->i593_init;
-
-       memset(cfblk, 0x00, sizeof(struct i82593_conf_block));
-
-        /* The configuration block.  What an undocumented nightmare.
-          The first set of values are those suggested (without explanation)
-          for ethernet in the Intel 82586 databook.  The rest appear to be
-          completely undocumented, except for cryptic notes in the Crynwr
-          packet driver.  This driver uses the Crynwr values verbatim. */
-
-       /* maz : Rewritten to take advantage of the wanvelan includes.
-          At least we have names, not just blind values */
-
-       /* Byte 0 */
-       cfblk->fifo_limit = 10; /* = 16 B rx and 80 B tx fifo thresholds */
-       cfblk->forgnesi = 0;    /* 0=82C501, 1=AMD7992B compatibility */
-       cfblk->fifo_32 = 1;
-       cfblk->d6mod = 0;       /* Run in i82593 advanced mode */
-       cfblk->throttle_enb = 1;
-
-       /* Byte 1 */
-       cfblk->throttle = 8;    /* Continuous w/interrupts, 128-clock DMA. */
-       cfblk->cntrxint = 0;    /* enable continuous mode receive interrupts */
-       cfblk->contin = 1;      /* enable continuous mode */
-
-       /* Byte 2 */
-       cfblk->addr_len = ETH_ALEN;
-       cfblk->acloc = 1;       /* Disable source addr insertion by i82593 */
-       cfblk->preamb_len = 2;  /* 8 bytes preamble */
-       cfblk->loopback = 0;    /* Loopback off */
-
-       /* Byte 3 */
-       cfblk->lin_prio = 0;    /* Default priorities & backoff methods. */
-       cfblk->tbofstop = 0;
-       cfblk->exp_prio = 0;
-       cfblk->bof_met = 0;
-
-       /* Byte 4 */
-       cfblk->ifrm_spc = 6;    /* 96 bit times interframe spacing */
-
-       /* Byte 5 */
-       cfblk->slottim_low = 0; /* 512 bit times slot time (low) */
-
-       /* Byte 6 */
-       cfblk->slottim_hi = 2;  /* 512 bit times slot time (high) */
-       cfblk->max_retr = 15;   /* 15 collisions retries */
-
-       /* Byte 7 */
-       cfblk->prmisc = ((dev->flags & IFF_PROMISC) ? 1 : 0); /* Promiscuous mode */
-       cfblk->bc_dis = 0;      /* Enable broadcast reception */
-       cfblk->crs_1 = 0;       /* Don't transmit without carrier sense */
-       cfblk->nocrc_ins = 0;   /* i82593 generates CRC */
-       cfblk->crc_1632 = 0;    /* 32-bit Autodin-II CRC */
-       cfblk->crs_cdt = 0;     /* CD not to be interpreted as CS */
-
-       /* Byte 8 */
-       cfblk->cs_filter = 0;   /* CS is recognized immediately */
-       cfblk->crs_src = 0;     /* External carrier sense */
-       cfblk->cd_filter = 0;   /* CD is recognized immediately */
-
-       /* Byte 9 */
-       cfblk->min_fr_len = ETH_ZLEN >> 2; /* Minimum frame length */
-
-       /* Byte A */
-       cfblk->lng_typ = 1;     /* Type/length checks OFF */
-       cfblk->lng_fld = 1;     /* Disable 802.3 length field check */
-       cfblk->rxcrc_xf = 1;    /* Don't transfer CRC to memory */
-       cfblk->artx = 1;        /* Disable automatic retransmission */
-       cfblk->sarec = 1;       /* Disable source addr trig of CD */
-       cfblk->tx_jabber = 0;   /* Disable jabber jam sequence */
-       cfblk->hash_1 = 1;      /* Use bits 0-5 in mc address hash */
-       cfblk->lbpkpol = 0;     /* Loopback pin active high */
-
-       /* Byte B */
-       cfblk->fdx = 0;         /* Disable full duplex operation */
-
-       /* Byte C */
-       cfblk->dummy_6 = 0x3f;  /* all ones, Default multicast addresses & backoff. */
-       cfblk->mult_ia = 0;     /* No multiple individual addresses */
-       cfblk->dis_bof = 0;     /* Disable the backoff algorithm ?! */
-
-       /* Byte D */
-       cfblk->dummy_1 = 1;     /* set to 1 */
-       cfblk->tx_ifs_retrig = 3; /* Hmm... Disabled */
-       cfblk->mc_all = (!netdev_mc_empty(dev) ||
-                       (dev->flags & IFF_ALLMULTI)); /* multicast all mode */
-       cfblk->rcv_mon = 0;     /* Monitor mode disabled */
-       cfblk->frag_acpt = 0;   /* Do not accept fragments */
-       cfblk->tstrttrs = 0;    /* No start transmission threshold */
-
-       /* Byte E */
-       cfblk->fretx = 1;       /* FIFO automatic retransmission */
-       cfblk->runt_eop = 0;    /* drop "runt" packets */
-       cfblk->hw_sw_pin = 0;   /* ?? */
-       cfblk->big_endn = 0;    /* Big Endian ? no... */
-       cfblk->syncrqs = 1;     /* Synchronous DRQ deassertion... */
-       cfblk->sttlen = 1;      /* 6 byte status registers */
-       cfblk->rx_eop = 0;      /* Signal EOP on packet reception */
-       cfblk->tx_eop = 0;      /* Signal EOP on packet transmission */
-
-       /* Byte F */
-       cfblk->rbuf_size = RX_BUF_SIZE >> 12; /* Set receive buffer size */
-       cfblk->rcvstop = 1;     /* Enable Receive Stop Register */
-
-       if (znet_debug > 2) {
-               int i;
-               unsigned char *c;
-
-               for (i = 0, c = (char *) cfblk; i < sizeof (*cfblk); i++)
-                       printk ("%02X ", c[i]);
-               printk ("\n");
-       }
-
-       *znet->tx_cur++ = sizeof(struct i82593_conf_block);
-       memcpy(znet->tx_cur, cfblk, sizeof(struct i82593_conf_block));
-       znet->tx_cur += sizeof(struct i82593_conf_block)/2;
-       outb(OP0_CONFIGURE | CR0_CHNL, ioaddr);
-
-       /* XXX FIXME maz : Add multicast addresses here, so having a
-        * multicast address configured isn't equal to IFF_ALLMULTI */
-}
-
-static const struct net_device_ops znet_netdev_ops = {
-       .ndo_open               = znet_open,
-       .ndo_stop               = znet_close,
-       .ndo_start_xmit         = znet_send_packet,
-       .ndo_set_multicast_list = znet_set_multicast_list,
-       .ndo_tx_timeout         = znet_tx_timeout,
-       .ndo_change_mtu         = eth_change_mtu,
-       .ndo_set_mac_address    = eth_mac_addr,
-       .ndo_validate_addr      = eth_validate_addr,
-};
-
-/* The Z-Note probe is pretty easy.  The NETIDBLK exists in the safe-to-probe
-   BIOS area.  We just scan for the signature, and pull the vital parameters
-   out of the structure. */
-
-static int __init znet_probe (void)
-{
-       int i;
-       struct netidblk *netinfo;
-       struct znet_private *znet;
-       struct net_device *dev;
-       char *p;
-       int err = -ENOMEM;
-
-       /* This code scans the region 0xf0000 to 0xfffff for a "NETIDBLK". */
-       for(p = (char *)phys_to_virt(0xf0000); p < (char *)phys_to_virt(0x100000); p++)
-               if (*p == 'N'  &&  strncmp(p, "NETIDBLK", 8) == 0)
-                       break;
-
-       if (p >= (char *)phys_to_virt(0x100000)) {
-               if (znet_debug > 1)
-                       printk(KERN_INFO "No Z-Note ethernet adaptor found.\n");
-               return -ENODEV;
-       }
-
-       dev = alloc_etherdev(sizeof(struct znet_private));
-       if (!dev)
-               return -ENOMEM;
-
-       znet = netdev_priv(dev);
-
-       netinfo = (struct netidblk *)p;
-       dev->base_addr = netinfo->iobase1;
-       dev->irq = netinfo->irq1;
-
-       /* The station address is in the "netidblk" at 0x0f0000. */
-       for (i = 0; i < 6; i++)
-               dev->dev_addr[i] = netinfo->netid[i];
-
-       printk(KERN_INFO "%s: ZNET at %#3lx, %pM"
-              ", using IRQ %d DMA %d and %d.\n",
-              dev->name, dev->base_addr, dev->dev_addr,
-              dev->irq, netinfo->dma1, netinfo->dma2);
-
-       if (znet_debug > 1) {
-               printk(KERN_INFO "%s: vendor '%16.16s' IRQ1 %d IRQ2 %d DMA1 %d DMA2 %d.\n",
-                      dev->name, netinfo->vendor,
-                      netinfo->irq1, netinfo->irq2,
-                      netinfo->dma1, netinfo->dma2);
-               printk(KERN_INFO "%s: iobase1 %#x size %d iobase2 %#x size %d net type %2.2x.\n",
-                      dev->name, netinfo->iobase1, netinfo->iosize1,
-                      netinfo->iobase2, netinfo->iosize2, netinfo->nettype);
-       }
-
-       if (znet_debug > 0)
-               printk(KERN_INFO "%s", version);
-
-       znet->rx_dma = netinfo->dma1;
-       znet->tx_dma = netinfo->dma2;
-       spin_lock_init(&znet->lock);
-       znet->sia_base = 0xe6;  /* Magic address for the 82501 SIA */
-       znet->sia_size = 2;
-       /* maz: Despite the '593 being advertised above as using a
-        * single 8bits I/O port, this driver does many 16bits
-        * access. So set io_size accordingly */
-       znet->io_size  = 2;
-
-       if (!(znet->rx_start = kmalloc (DMA_BUF_SIZE, GFP_KERNEL | GFP_DMA)))
-               goto free_dev;
-       if (!(znet->tx_start = kmalloc (DMA_BUF_SIZE, GFP_KERNEL | GFP_DMA)))
-               goto free_rx;
-
-       if (!dma_page_eq (znet->rx_start, znet->rx_start + (RX_BUF_SIZE/2-1)) ||
-           !dma_page_eq (znet->tx_start, znet->tx_start + (TX_BUF_SIZE/2-1))) {
-               printk (KERN_WARNING "tx/rx crossing DMA frontiers, giving up\n");
-               goto free_tx;
-       }
-
-       znet->rx_end = znet->rx_start + RX_BUF_SIZE/2;
-       znet->tx_buf_len = TX_BUF_SIZE/2;
-       znet->tx_end = znet->tx_start + znet->tx_buf_len;
-
-       /* The ZNET-specific entries in the device structure. */
-       dev->netdev_ops = &znet_netdev_ops;
-       dev->watchdog_timeo = TX_TIMEOUT;
-       err = register_netdev(dev);
-       if (err)
-               goto free_tx;
-       znet_dev = dev;
-       return 0;
-
- free_tx:
-       kfree(znet->tx_start);
- free_rx:
-       kfree(znet->rx_start);
- free_dev:
-       free_netdev(dev);
-       return err;
-}
-
-
-static int znet_open(struct net_device *dev)
-{
-       int ioaddr = dev->base_addr;
-
-       if (znet_debug > 2)
-               printk(KERN_DEBUG "%s: znet_open() called.\n", dev->name);
-
-       /* These should never fail.  You can't add devices to a sealed box! */
-       if (znet_request_resources (dev)) {
-               printk(KERN_WARNING "%s: Not opened -- resource busy?!?\n", dev->name);
-               return -EBUSY;
-       }
-
-       znet_transceiver_power (dev, 1);
-
-       /* According to the Crynwr driver we should wait 50 msec. for the
-          LAN clock to stabilize.  My experiments indicates that the '593 can
-          be initialized immediately.  The delay is probably needed for the
-          DC-to-DC converter to come up to full voltage, and for the oscillator
-          to be spot-on at 20Mhz before transmitting.
-          Until this proves to be a problem we rely on the higher layers for the
-          delay and save allocating a timer entry. */
-
-       /* maz : Well, I'm getting every time the following message
-        * without the delay on a 486@33. This machine is much too
-        * fast... :-) So maybe the Crynwr driver wasn't wrong after
-        * all, even if the message is completly harmless on my
-        * setup. */
-       mdelay (50);
-
-       /* This follows the packet driver's lead, and checks for success. */
-       if (inb(ioaddr) != 0x10 && inb(ioaddr) != 0x00)
-               printk(KERN_WARNING "%s: Problem turning on the transceiver power.\n",
-                      dev->name);
-
-       hardware_init(dev);
-       netif_start_queue (dev);
-
-       return 0;
-}
-
-
-static void znet_tx_timeout (struct net_device *dev)
-{
-       int ioaddr = dev->base_addr;
-       ushort event, tx_status, rx_offset, state;
-
-       outb (CR0_STATUS_0, ioaddr);
-       event = inb (ioaddr);
-       outb (CR0_STATUS_1, ioaddr);
-       tx_status = inw (ioaddr);
-       outb (CR0_STATUS_2, ioaddr);
-       rx_offset = inw (ioaddr);
-       outb (CR0_STATUS_3, ioaddr);
-       state = inb (ioaddr);
-       printk (KERN_WARNING "%s: transmit timed out, status %02x %04x %04x %02x,"
-        " resetting.\n", dev->name, event, tx_status, rx_offset, state);
-       if (tx_status == TX_LOST_CRS)
-               printk (KERN_WARNING "%s: Tx carrier error, check transceiver cable.\n",
-                       dev->name);
-       outb (OP0_RESET, ioaddr);
-       hardware_init (dev);
-       netif_wake_queue (dev);
-}
-
-static netdev_tx_t znet_send_packet(struct sk_buff *skb, struct net_device *dev)
-{
-       int ioaddr = dev->base_addr;
-       struct znet_private *znet = netdev_priv(dev);
-       unsigned long flags;
-       short length = skb->len;
-
-       if (znet_debug > 4)
-               printk(KERN_DEBUG "%s: ZNet_send_packet.\n", dev->name);
-
-       if (length < ETH_ZLEN) {
-               if (skb_padto(skb, ETH_ZLEN))
-                       return NETDEV_TX_OK;
-               length = ETH_ZLEN;
-       }
-
-       netif_stop_queue (dev);
-
-       /* Check that the part hasn't reset itself, probably from suspend. */
-       outb(CR0_STATUS_0, ioaddr);
-       if (inw(ioaddr) == 0x0010 &&
-           inw(ioaddr) == 0x0000 &&
-           inw(ioaddr) == 0x0010) {
-               if (znet_debug > 1)
-                       printk (KERN_WARNING "%s : waking up\n", dev->name);
-               hardware_init(dev);
-               znet_transceiver_power (dev, 1);
-       }
-
-       if (1) {
-               unsigned char *buf = (void *)skb->data;
-               ushort *tx_link = znet->tx_cur - 1;
-               ushort rnd_len = (length + 1)>>1;
-
-               dev->stats.tx_bytes+=length;
-
-               if (znet->tx_cur >= znet->tx_end)
-                 znet->tx_cur = znet->tx_start;
-               *znet->tx_cur++ = length;
-               if (znet->tx_cur + rnd_len + 1 > znet->tx_end) {
-                       int semi_cnt = (znet->tx_end - znet->tx_cur)<<1; /* Cvrt to byte cnt. */
-                       memcpy(znet->tx_cur, buf, semi_cnt);
-                       rnd_len -= semi_cnt>>1;
-                       memcpy(znet->tx_start, buf + semi_cnt, length - semi_cnt);
-                       znet->tx_cur = znet->tx_start + rnd_len;
-               } else {
-                       memcpy(znet->tx_cur, buf, skb->len);
-                       znet->tx_cur += rnd_len;
-               }
-               *znet->tx_cur++ = 0;
-
-               spin_lock_irqsave(&znet->lock, flags);
-               {
-                       *tx_link = OP0_TRANSMIT | CR0_CHNL;
-                       /* Is this always safe to do? */
-                       outb(OP0_TRANSMIT | CR0_CHNL, ioaddr);
-               }
-               spin_unlock_irqrestore (&znet->lock, flags);
-
-               netif_start_queue (dev);
-
-               if (znet_debug > 4)
-                 printk(KERN_DEBUG "%s: Transmitter queued, length %d.\n", dev->name, length);
-       }
-       dev_kfree_skb(skb);
-       return NETDEV_TX_OK;
-}
-
-/* The ZNET interrupt handler. */
-static irqreturn_t znet_interrupt(int irq, void *dev_id)
-{
-       struct net_device *dev = dev_id;
-       struct znet_private *znet = netdev_priv(dev);
-       int ioaddr;
-       int boguscnt = 20;
-       int handled = 0;
-
-       spin_lock (&znet->lock);
-
-       ioaddr = dev->base_addr;
-
-       outb(CR0_STATUS_0, ioaddr);
-       do {
-               ushort status = inb(ioaddr);
-               if (znet_debug > 5) {
-                       ushort result, rx_ptr, running;
-                       outb(CR0_STATUS_1, ioaddr);
-                       result = inw(ioaddr);
-                       outb(CR0_STATUS_2, ioaddr);
-                       rx_ptr = inw(ioaddr);
-                       outb(CR0_STATUS_3, ioaddr);
-                       running = inb(ioaddr);
-                       printk(KERN_DEBUG "%s: interrupt, status %02x, %04x %04x %02x serial %d.\n",
-                                dev->name, status, result, rx_ptr, running, boguscnt);
-               }
-               if ((status & SR0_INTERRUPT) == 0)
-                       break;
-
-               handled = 1;
-
-               if ((status & SR0_EVENT_MASK) == SR0_TRANSMIT_DONE ||
-                   (status & SR0_EVENT_MASK) == SR0_RETRANSMIT_DONE ||
-                   (status & SR0_EVENT_MASK) == SR0_TRANSMIT_NO_CRC_DONE) {
-                       int tx_status;
-                       outb(CR0_STATUS_1, ioaddr);
-                       tx_status = inw(ioaddr);
-                       /* It's undocumented, but tx_status seems to match the i82586. */
-                       if (tx_status & TX_OK) {
-                               dev->stats.tx_packets++;
-                               dev->stats.collisions += tx_status & TX_NCOL_MASK;
-                       } else {
-                               if (tx_status & (TX_LOST_CTS | TX_LOST_CRS))
-                                       dev->stats.tx_carrier_errors++;
-                               if (tx_status & TX_UND_RUN)
-                                       dev->stats.tx_fifo_errors++;
-                               if (!(tx_status & TX_HRT_BEAT))
-                                       dev->stats.tx_heartbeat_errors++;
-                               if (tx_status & TX_MAX_COL)
-                                       dev->stats.tx_aborted_errors++;
-                               /* ...and the catch-all. */
-                               if ((tx_status | (TX_LOST_CRS | TX_LOST_CTS | TX_UND_RUN | TX_HRT_BEAT | TX_MAX_COL)) != (TX_LOST_CRS | TX_LOST_CTS | TX_UND_RUN | TX_HRT_BEAT | TX_MAX_COL))
-                                       dev->stats.tx_errors++;
-
-                               /* Transceiver may be stuck if cable
-                                * was removed while emitting a
-                                * packet. Flip it off, then on to
-                                * reset it. This is very empirical,
-                                * but it seems to work. */
-
-                               znet_transceiver_power (dev, 0);
-                               znet_transceiver_power (dev, 1);
-                       }
-                       netif_wake_queue (dev);
-               }
-
-               if ((status & SR0_RECEPTION) ||
-                   (status & SR0_EVENT_MASK) == SR0_STOP_REG_HIT) {
-                       znet_rx(dev);
-               }
-               /* Clear the interrupts we've handled. */
-               outb(CR0_INT_ACK, ioaddr);
-       } while (boguscnt--);
-
-       spin_unlock (&znet->lock);
-
-       return IRQ_RETVAL(handled);
-}
-
-static void znet_rx(struct net_device *dev)
-{
-       struct znet_private *znet = netdev_priv(dev);
-       int ioaddr = dev->base_addr;
-       int boguscount = 1;
-       short next_frame_end_offset = 0;                /* Offset of next frame start. */
-       short *cur_frame_end;
-       short cur_frame_end_offset;
-
-       outb(CR0_STATUS_2, ioaddr);
-       cur_frame_end_offset = inw(ioaddr);
-
-       if (cur_frame_end_offset == znet->rx_cur - znet->rx_start) {
-               printk(KERN_WARNING "%s: Interrupted, but nothing to receive, offset %03x.\n",
-                          dev->name, cur_frame_end_offset);
-               return;
-       }
-
-       /* Use same method as the Crynwr driver: construct a forward list in
-          the same area of the backwards links we now have.  This allows us to
-          pass packets to the upper layers in the order they were received --
-          important for fast-path sequential operations. */
-       while (znet->rx_start + cur_frame_end_offset != znet->rx_cur &&
-              ++boguscount < 5) {
-               unsigned short hi_cnt, lo_cnt, hi_status, lo_status;
-               int count, status;
-
-               if (cur_frame_end_offset < 4) {
-                       /* Oh no, we have a special case: the frame trailer wraps around
-                          the end of the ring buffer.  We've saved space at the end of
-                          the ring buffer for just this problem. */
-                       memcpy(znet->rx_end, znet->rx_start, 8);
-                       cur_frame_end_offset += (RX_BUF_SIZE/2);
-               }
-               cur_frame_end = znet->rx_start + cur_frame_end_offset - 4;
-
-               lo_status = *cur_frame_end++;
-               hi_status = *cur_frame_end++;
-               status = ((hi_status & 0xff) << 8) + (lo_status & 0xff);
-               lo_cnt = *cur_frame_end++;
-               hi_cnt = *cur_frame_end++;
-               count = ((hi_cnt & 0xff) << 8) + (lo_cnt & 0xff);
-
-               if (znet_debug > 5)
-                 printk(KERN_DEBUG "Constructing trailer at location %03x, %04x %04x %04x %04x"
-                                " count %#x status %04x.\n",
-                                cur_frame_end_offset<<1, lo_status, hi_status, lo_cnt, hi_cnt,
-                                count, status);
-               cur_frame_end[-4] = status;
-               cur_frame_end[-3] = next_frame_end_offset;
-               cur_frame_end[-2] = count;
-               next_frame_end_offset = cur_frame_end_offset;
-               cur_frame_end_offset -= ((count + 1)>>1) + 3;
-               if (cur_frame_end_offset < 0)
-                 cur_frame_end_offset += RX_BUF_SIZE/2;
-       }
-
-       /* Now step  forward through the list. */
-       do {
-               ushort *this_rfp_ptr = znet->rx_start + next_frame_end_offset;
-               int status = this_rfp_ptr[-4];
-               int pkt_len = this_rfp_ptr[-2];
-
-               if (znet_debug > 5)
-                 printk(KERN_DEBUG "Looking at trailer ending at %04x status %04x length %03x"
-                                " next %04x.\n", next_frame_end_offset<<1, status, pkt_len,
-                                this_rfp_ptr[-3]<<1);
-               /* Once again we must assume that the i82586 docs apply. */
-               if ( ! (status & RX_RCV_OK)) { /* There was an error. */
-                       dev->stats.rx_errors++;
-                       if (status & RX_CRC_ERR) dev->stats.rx_crc_errors++;
-                       if (status & RX_ALG_ERR) dev->stats.rx_frame_errors++;
-#if 0
-                       if (status & 0x0200) dev->stats.rx_over_errors++; /* Wrong. */
-                       if (status & 0x0100) dev->stats.rx_fifo_errors++;
-#else
-                       /* maz : Wild guess... */
-                       if (status & RX_OVRRUN) dev->stats.rx_over_errors++;
-#endif
-                       if (status & RX_SRT_FRM) dev->stats.rx_length_errors++;
-               } else if (pkt_len > 1536) {
-                       dev->stats.rx_length_errors++;
-               } else {
-                       /* Malloc up new buffer. */
-                       struct sk_buff *skb;
-
-                       skb = dev_alloc_skb(pkt_len);
-                       if (skb == NULL) {
-                               if (znet_debug)
-                                 printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
-                               dev->stats.rx_dropped++;
-                               break;
-                       }
-
-                       if (&znet->rx_cur[(pkt_len+1)>>1] > znet->rx_end) {
-                               int semi_cnt = (znet->rx_end - znet->rx_cur)<<1;
-                               memcpy(skb_put(skb,semi_cnt), znet->rx_cur, semi_cnt);
-                               memcpy(skb_put(skb,pkt_len-semi_cnt), znet->rx_start,
-                                          pkt_len - semi_cnt);
-                       } else {
-                               memcpy(skb_put(skb,pkt_len), znet->rx_cur, pkt_len);
-                               if (znet_debug > 6) {
-                                       unsigned int *packet = (unsigned int *) skb->data;
-                                       printk(KERN_DEBUG "Packet data is %08x %08x %08x %08x.\n", packet[0],
-                                                  packet[1], packet[2], packet[3]);
-                               }
-                 }
-                 skb->protocol=eth_type_trans(skb,dev);
-                 netif_rx(skb);
-                 dev->stats.rx_packets++;
-                 dev->stats.rx_bytes += pkt_len;
-               }
-               znet->rx_cur = this_rfp_ptr;
-               if (znet->rx_cur >= znet->rx_end)
-                       znet->rx_cur -= RX_BUF_SIZE/2;
-               update_stop_hit(ioaddr, (znet->rx_cur - znet->rx_start)<<1);
-               next_frame_end_offset = this_rfp_ptr[-3];
-               if (next_frame_end_offset == 0)         /* Read all the frames? */
-                       break;                  /* Done for now */
-               this_rfp_ptr = znet->rx_start + next_frame_end_offset;
-       } while (--boguscount);
-
-       /* If any worth-while packets have been received, dev_rint()
-          has done a mark_bh(INET_BH) for us and will work on them
-          when we get to the bottom-half routine. */
-}
-
-/* The inverse routine to znet_open(). */
-static int znet_close(struct net_device *dev)
-{
-       int ioaddr = dev->base_addr;
-
-       netif_stop_queue (dev);
-
-       outb(OP0_RESET, ioaddr);                        /* CMD0_RESET */
-
-       if (znet_debug > 1)
-               printk(KERN_DEBUG "%s: Shutting down ethercard.\n", dev->name);
-       /* Turn off transceiver power. */
-       znet_transceiver_power (dev, 0);
-
-       znet_release_resources (dev);
-
-       return 0;
-}
-
-static void show_dma(struct net_device *dev)
-{
-       short ioaddr = dev->base_addr;
-       unsigned char stat = inb (ioaddr);
-       struct znet_private *znet = netdev_priv(dev);
-       unsigned long flags;
-       short dma_port = ((znet->tx_dma&3)<<2) + IO_DMA2_BASE;
-       unsigned addr = inb(dma_port);
-       short residue;
-
-       addr |= inb(dma_port) << 8;
-       residue = get_dma_residue(znet->tx_dma);
-
-       if (znet_debug > 1) {
-               flags=claim_dma_lock();
-               printk(KERN_DEBUG "Stat:%02x Addr: %04x cnt:%3x\n",
-                      stat, addr<<1, residue);
-               release_dma_lock(flags);
-       }
-}
-
-/* Initialize the hardware.  We have to do this when the board is open()ed
-   or when we come out of suspend mode. */
-static void hardware_init(struct net_device *dev)
-{
-       unsigned long flags;
-       short ioaddr = dev->base_addr;
-       struct znet_private *znet = netdev_priv(dev);
-
-       znet->rx_cur = znet->rx_start;
-       znet->tx_cur = znet->tx_start;
-
-       /* Reset the chip, and start it up. */
-       outb(OP0_RESET, ioaddr);
-
-       flags=claim_dma_lock();
-       disable_dma(znet->rx_dma);              /* reset by an interrupting task. */
-       clear_dma_ff(znet->rx_dma);
-       set_dma_mode(znet->rx_dma, DMA_RX_MODE);
-       set_dma_addr(znet->rx_dma, (unsigned int) znet->rx_start);
-       set_dma_count(znet->rx_dma, RX_BUF_SIZE);
-       enable_dma(znet->rx_dma);
-       /* Now set up the Tx channel. */
-       disable_dma(znet->tx_dma);
-       clear_dma_ff(znet->tx_dma);
-       set_dma_mode(znet->tx_dma, DMA_TX_MODE);
-       set_dma_addr(znet->tx_dma, (unsigned int) znet->tx_start);
-       set_dma_count(znet->tx_dma, znet->tx_buf_len<<1);
-       enable_dma(znet->tx_dma);
-       release_dma_lock(flags);
-
-       if (znet_debug > 1)
-         printk(KERN_DEBUG "%s: Initializing the i82593, rx buf %p tx buf %p\n",
-                        dev->name, znet->rx_start,znet->tx_start);
-       /* Do an empty configure command, just like the Crynwr driver.  This
-          resets to chip to its default values. */
-       *znet->tx_cur++ = 0;
-       *znet->tx_cur++ = 0;
-       show_dma(dev);
-       outb(OP0_CONFIGURE | CR0_CHNL, ioaddr);
-
-       znet_set_multicast_list (dev);
-
-       *znet->tx_cur++ = 6;
-       memcpy(znet->tx_cur, dev->dev_addr, 6);
-       znet->tx_cur += 3;
-       show_dma(dev);
-       outb(OP0_IA_SETUP | CR0_CHNL, ioaddr);
-       show_dma(dev);
-
-       update_stop_hit(ioaddr, 8192);
-       if (znet_debug > 1)  printk(KERN_DEBUG "enabling Rx.\n");
-       outb(OP0_RCV_ENABLE, ioaddr);
-       netif_start_queue (dev);
-}
-
-static void update_stop_hit(short ioaddr, unsigned short rx_stop_offset)
-{
-       outb(OP0_SWIT_TO_PORT_1 | CR0_CHNL, ioaddr);
-       if (znet_debug > 5)
-         printk(KERN_DEBUG "Updating stop hit with value %02x.\n",
-                        (rx_stop_offset >> 6) | CR1_STOP_REG_UPDATE);
-       outb((rx_stop_offset >> 6) | CR1_STOP_REG_UPDATE, ioaddr);
-       outb(OP1_SWIT_TO_PORT_0, ioaddr);
-}
-
-static __exit void znet_cleanup (void)
-{
-       if (znet_dev) {
-               struct znet_private *znet = netdev_priv(znet_dev);
-
-               unregister_netdev (znet_dev);
-               kfree (znet->rx_start);
-               kfree (znet->tx_start);
-               free_netdev (znet_dev);
-       }
-}
-
-module_init (znet_probe);
-module_exit (znet_cleanup);