]> git.openfabrics.org - ~shefty/rdma-dev.git/commitdiff
de6*/dl2k/sundance: Move the D-Link drivers
authorJeff Kirsher <jeffrey.t.kirsher@intel.com>
Fri, 20 May 2011 07:04:35 +0000 (00:04 -0700)
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>
Thu, 11 Aug 2011 23:29:50 +0000 (16:29 -0700)
Move the D-Link drivers into drivers/net/ethernet/dlink/ and
make the necessary Kconfig and Makefile changes.

CC: Bjorn Ekwall <bj0rn@blox.se>
CC: Donald Becker <becker@scyld.com>
CC: Edward Peng <edward_peng@dlink.com.tw>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
20 files changed:
drivers/net/Kconfig
drivers/net/Makefile
drivers/net/de600.c [deleted file]
drivers/net/de600.h [deleted file]
drivers/net/de620.c [deleted file]
drivers/net/de620.h [deleted file]
drivers/net/dl2k.c [deleted file]
drivers/net/dl2k.h [deleted file]
drivers/net/ethernet/Kconfig
drivers/net/ethernet/Makefile
drivers/net/ethernet/dlink/Kconfig [new file with mode: 0644]
drivers/net/ethernet/dlink/Makefile [new file with mode: 0644]
drivers/net/ethernet/dlink/de600.c [new file with mode: 0644]
drivers/net/ethernet/dlink/de600.h [new file with mode: 0644]
drivers/net/ethernet/dlink/de620.c [new file with mode: 0644]
drivers/net/ethernet/dlink/de620.h [new file with mode: 0644]
drivers/net/ethernet/dlink/dl2k.c [new file with mode: 0644]
drivers/net/ethernet/dlink/dl2k.h [new file with mode: 0644]
drivers/net/ethernet/dlink/sundance.c [new file with mode: 0644]
drivers/net/sundance.c [deleted file]

index 42408d7dc1c25696981e4728464f72e608b041b3..8799caf64c98ba39a7a4dac25ca272658fd649a2 100644 (file)
@@ -623,26 +623,6 @@ config SIS900
          To compile this driver as a module, choose M here: the module
          will be called sis900.  This is recommended.
 
-config SUNDANCE
-       tristate "Sundance Alta support"
-       depends on NET_PCI && PCI
-       select CRC32
-       select MII
-       help
-         This driver is for the Sundance "Alta" chip.
-         More specific information and updates are available from
-         <http://www.scyld.com/network/sundance.html>.
-
-config SUNDANCE_MMIO
-       bool "Use MMIO instead of PIO"
-       depends on SUNDANCE
-       help
-         Enable memory-mapped I/O for interaction with Sundance NIC registers.
-         Do NOT enable this by default, PIO (enabled when MMIO is disabled)
-         is known to solve bugs on certain chips.
-
-         If unsure, say N.
-
 config TLAN
        tristate "TI ThunderLAN support"
        depends on NET_PCI && (PCI || EISA)
@@ -740,36 +720,6 @@ config NET_POCKET
          the questions about this class of network devices. If you say Y, you
          will be asked for your specific device in the following questions.
 
-config DE600
-       tristate "D-Link DE600 pocket adapter support"
-       depends on NET_POCKET && PARPORT
-       ---help---
-         This is a network (Ethernet) device which attaches to your parallel
-         port. Read <file:Documentation/networking/DLINK.txt> as well as the
-         Ethernet-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>, if you want to use
-         this. It is possible to have several devices share a single parallel
-         port and it is safe to compile the corresponding drivers into the
-         kernel.
-
-         To compile this driver as a module, choose M here: the module
-         will be called de600.
-
-config DE620
-       tristate "D-Link DE620 pocket adapter support"
-       depends on NET_POCKET && PARPORT
-       ---help---
-         This is a network (Ethernet) device which attaches to your parallel
-         port. Read <file:Documentation/networking/DLINK.txt> as well as the
-         Ethernet-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>, if you want to use
-         this. It is possible to have several devices share a single parallel
-         port and it is safe to compile the corresponding drivers into the
-         kernel.
-
-         To compile this driver as a module, choose M here: the module
-         will be called de620.
-
 config SGISEEQ
        tristate "SGI Seeq ethernet controller support"
        depends on SGI_HAS_SEEQ
@@ -862,20 +812,6 @@ menuconfig NETDEV_1000
 
 if NETDEV_1000
 
-config DL2K
-       tristate "DL2000/TC902x-based Gigabit Ethernet support"
-       depends on PCI
-       select CRC32
-       help
-         This driver supports DL2000/TC902x-based Gigabit ethernet cards,
-         which includes
-         D-Link DGE-550T Gigabit Ethernet Adapter.
-         D-Link DL2000-based Gigabit Ethernet Adapter.
-         Sundance/Tamarack TC902x Gigabit Ethernet Adapter.
-
-         To compile this driver as a module, choose M here: the
-         module will be called dl2k.
-
 config IP1000
        tristate "IP1000 Gigabit Ethernet support"
        depends on PCI && EXPERIMENTAL
index d142fc5ef68c9a6da7209f28408f21600f7866d9..ecd8c9f664d270ac1bbbcf9d9caf290ae047905e 100644 (file)
@@ -67,7 +67,6 @@ obj-$(CONFIG_SH_ETH) += sh_eth.o
 # end link order section
 #
 
-obj-$(CONFIG_SUNDANCE) += sundance.o
 obj-$(CONFIG_HAMACHI) += hamachi.o
 obj-$(CONFIG_NET) += Space.o loopback.o
 obj-$(CONFIG_SEEQ8005) += seeq8005.o
@@ -106,8 +105,6 @@ obj-$(CONFIG_DUMMY) += dummy.o
 obj-$(CONFIG_IFB) += ifb.o
 obj-$(CONFIG_MACVLAN) += macvlan.o
 obj-$(CONFIG_MACVTAP) += macvtap.o
-obj-$(CONFIG_DE600) += de600.o
-obj-$(CONFIG_DE620) += de620.o
 obj-$(CONFIG_DEFXX) += defxx.o
 obj-$(CONFIG_SGISEEQ) += sgiseeq.o
 obj-$(CONFIG_SGI_O2MACE_ETH) += meth.o
@@ -123,7 +120,6 @@ obj-$(CONFIG_SGI_IOC3_ETH) += ioc3-eth.o
 obj-$(CONFIG_TUN) += tun.o
 obj-$(CONFIG_VETH) += veth.o
 obj-$(CONFIG_NET_NETX) += netx-eth.o
-obj-$(CONFIG_DL2K) += dl2k.o
 obj-$(CONFIG_PXA168_ETH) += pxa168_eth.o
 obj-$(CONFIG_BFIN_MAC) += bfin_mac.o
 obj-$(CONFIG_DM9000) += dm9000.o
diff --git a/drivers/net/de600.c b/drivers/net/de600.c
deleted file mode 100644 (file)
index 23a6539..0000000
+++ /dev/null
@@ -1,530 +0,0 @@
-static const char version[] = "de600.c: $Revision: 1.41-2.5 $,  Bjorn Ekwall (bj0rn@blox.se)\n";
-/*
- *     de600.c
- *
- *     Linux driver for the D-Link DE-600 Ethernet pocket adapter.
- *
- *     Portions (C) Copyright 1993, 1994 by Bjorn Ekwall
- *     The Author may be reached as bj0rn@blox.se
- *
- *     Based on adapter information gathered from DE600.ASM by D-Link Inc.,
- *     as included on disk C in the v.2.11 of PC/TCP from FTP Software.
- *     For DE600.asm:
- *             Portions (C) Copyright 1990 D-Link, Inc.
- *             Copyright, 1988-1992, Russell Nelson, Crynwr Software
- *
- *     Adapted to the sample network driver core for linux,
- *     written by: Donald Becker <becker@super.org>
- *             (Now at <becker@scyld.com>)
- *
- **************************************************************/
-/*
- *     This program is free software; you can redistribute it and/or modify
- *     it under the terms of the GNU General Public License as published by
- *     the Free Software Foundation; either version 2, or (at your option)
- *     any later version.
- *
- *     This program is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- *     You should have received a copy of the GNU General Public License
- *     along with this program; if not, write to the Free Software
- *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- **************************************************************/
-
-/* Add more time here if your adapter won't work OK: */
-#define DE600_SLOW_DOWN        udelay(delay_time)
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/string.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <asm/system.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-
-#include <asm/io.h>
-
-#include "de600.h"
-
-static unsigned int check_lost = 1;
-module_param(check_lost, bool, 0);
-MODULE_PARM_DESC(check_lost, "If set then check for unplugged de600");
-
-static unsigned int delay_time = 10;
-module_param(delay_time, int, 0);
-MODULE_PARM_DESC(delay_time, "DE-600 deley on I/O in microseconds");
-
-
-/*
- * D-Link driver variables:
- */
-
-static volatile int            rx_page;
-
-#define TX_PAGES 2
-static volatile int            tx_fifo[TX_PAGES];
-static volatile int            tx_fifo_in;
-static volatile int            tx_fifo_out;
-static volatile int            free_tx_pages = TX_PAGES;
-static int                     was_down;
-static DEFINE_SPINLOCK(de600_lock);
-
-static inline u8 de600_read_status(struct net_device *dev)
-{
-       u8 status;
-
-       outb_p(STATUS, DATA_PORT);
-       status = inb(STATUS_PORT);
-       outb_p(NULL_COMMAND | HI_NIBBLE, DATA_PORT);
-
-       return status;
-}
-
-static inline u8 de600_read_byte(unsigned char type, struct net_device *dev)
-{
-       /* dev used by macros */
-       u8 lo;
-       outb_p((type), DATA_PORT);
-       lo = ((unsigned char)inb(STATUS_PORT)) >> 4;
-       outb_p((type) | HI_NIBBLE, DATA_PORT);
-       return ((unsigned char)inb(STATUS_PORT) & (unsigned char)0xf0) | lo;
-}
-
-/*
- * Open/initialize the board.  This is called (in the current kernel)
- * after booting when 'ifconfig <dev->name> $IP_ADDR' is run (in rc.inet1).
- *
- * 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 a non-reboot way to recover if something goes wrong.
- */
-
-static int de600_open(struct net_device *dev)
-{
-       unsigned long flags;
-       int ret = request_irq(DE600_IRQ, de600_interrupt, 0, dev->name, dev);
-       if (ret) {
-               printk(KERN_ERR "%s: unable to get IRQ %d\n", dev->name, DE600_IRQ);
-               return ret;
-       }
-       spin_lock_irqsave(&de600_lock, flags);
-       ret = adapter_init(dev);
-       spin_unlock_irqrestore(&de600_lock, flags);
-       return ret;
-}
-
-/*
- * The inverse routine to de600_open().
- */
-
-static int de600_close(struct net_device *dev)
-{
-       select_nic();
-       rx_page = 0;
-       de600_put_command(RESET);
-       de600_put_command(STOP_RESET);
-       de600_put_command(0);
-       select_prn();
-       free_irq(DE600_IRQ, dev);
-       return 0;
-}
-
-static inline void trigger_interrupt(struct net_device *dev)
-{
-       de600_put_command(FLIP_IRQ);
-       select_prn();
-       DE600_SLOW_DOWN;
-       select_nic();
-       de600_put_command(0);
-}
-
-/*
- * Copy a buffer to the adapter transmit page memory.
- * Start sending.
- */
-
-static int de600_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-       unsigned long flags;
-       int     transmit_from;
-       int     len;
-       int     tickssofar;
-       u8      *buffer = skb->data;
-       int     i;
-
-       if (free_tx_pages <= 0) {       /* Do timeouts, to avoid hangs. */
-               tickssofar = jiffies - dev_trans_start(dev);
-               if (tickssofar < HZ/20)
-                       return NETDEV_TX_BUSY;
-               /* else */
-               printk(KERN_WARNING "%s: transmit timed out (%d), %s?\n", dev->name, tickssofar, "network cable problem");
-               /* Restart the adapter. */
-               spin_lock_irqsave(&de600_lock, flags);
-               if (adapter_init(dev)) {
-                       spin_unlock_irqrestore(&de600_lock, flags);
-                       return NETDEV_TX_BUSY;
-               }
-               spin_unlock_irqrestore(&de600_lock, flags);
-       }
-
-       /* Start real output */
-       pr_debug("de600_start_xmit:len=%d, page %d/%d\n", skb->len, tx_fifo_in, free_tx_pages);
-
-       if ((len = skb->len) < RUNT)
-               len = RUNT;
-
-       spin_lock_irqsave(&de600_lock, flags);
-       select_nic();
-       tx_fifo[tx_fifo_in] = transmit_from = tx_page_adr(tx_fifo_in) - len;
-       tx_fifo_in = (tx_fifo_in + 1) % TX_PAGES; /* Next free tx page */
-
-       if(check_lost)
-       {
-               /* This costs about 40 instructions per packet... */
-               de600_setup_address(NODE_ADDRESS, RW_ADDR);
-               de600_read_byte(READ_DATA, dev);
-               if (was_down || (de600_read_byte(READ_DATA, dev) != 0xde)) {
-                       if (adapter_init(dev)) {
-                               spin_unlock_irqrestore(&de600_lock, flags);
-                               return NETDEV_TX_BUSY;
-                       }
-               }
-       }
-
-       de600_setup_address(transmit_from, RW_ADDR);
-       for (i = 0;  i < skb->len ; ++i, ++buffer)
-               de600_put_byte(*buffer);
-       for (; i < len; ++i)
-               de600_put_byte(0);
-
-       if (free_tx_pages-- == TX_PAGES) { /* No transmission going on */
-               dev->trans_start = jiffies;
-               netif_start_queue(dev); /* allow more packets into adapter */
-               /* Send page and generate a faked interrupt */
-               de600_setup_address(transmit_from, TX_ADDR);
-               de600_put_command(TX_ENABLE);
-       }
-       else {
-               if (free_tx_pages)
-                       netif_start_queue(dev);
-               else
-                       netif_stop_queue(dev);
-               select_prn();
-       }
-       spin_unlock_irqrestore(&de600_lock, flags);
-       dev_kfree_skb(skb);
-       return NETDEV_TX_OK;
-}
-
-/*
- * The typical workload of the driver:
- * Handle the network interface interrupts.
- */
-
-static irqreturn_t de600_interrupt(int irq, void *dev_id)
-{
-       struct net_device       *dev = dev_id;
-       u8              irq_status;
-       int             retrig = 0;
-       int             boguscount = 0;
-
-       spin_lock(&de600_lock);
-
-       select_nic();
-       irq_status = de600_read_status(dev);
-
-       do {
-               pr_debug("de600_interrupt (%02X)\n", irq_status);
-
-               if (irq_status & RX_GOOD)
-                       de600_rx_intr(dev);
-               else if (!(irq_status & RX_BUSY))
-                       de600_put_command(RX_ENABLE);
-
-               /* Any transmission in progress? */
-               if (free_tx_pages < TX_PAGES)
-                       retrig = de600_tx_intr(dev, irq_status);
-               else
-                       retrig = 0;
-
-               irq_status = de600_read_status(dev);
-       } while ( (irq_status & RX_GOOD) || ((++boguscount < 100) && retrig) );
-       /*
-        * Yeah, it _looks_ like busy waiting, smells like busy waiting
-        * and I know it's not PC, but please, it will only occur once
-        * in a while and then only for a loop or so (< 1ms for sure!)
-        */
-
-       /* Enable adapter interrupts */
-       select_prn();
-       if (retrig)
-               trigger_interrupt(dev);
-       spin_unlock(&de600_lock);
-       return IRQ_HANDLED;
-}
-
-static int de600_tx_intr(struct net_device *dev, int irq_status)
-{
-       /*
-        * Returns 1 if tx still not done
-        */
-
-       /* Check if current transmission is done yet */
-       if (irq_status & TX_BUSY)
-               return 1; /* tx not done, try again */
-
-       /* else */
-       /* If last transmission OK then bump fifo index */
-       if (!(irq_status & TX_FAILED16)) {
-               tx_fifo_out = (tx_fifo_out + 1) % TX_PAGES;
-               ++free_tx_pages;
-               dev->stats.tx_packets++;
-               netif_wake_queue(dev);
-       }
-
-       /* More to send, or resend last packet? */
-       if ((free_tx_pages < TX_PAGES) || (irq_status & TX_FAILED16)) {
-               dev->trans_start = jiffies;
-               de600_setup_address(tx_fifo[tx_fifo_out], TX_ADDR);
-               de600_put_command(TX_ENABLE);
-               return 1;
-       }
-       /* else */
-
-       return 0;
-}
-
-/*
- * We have a good packet, get it out of the adapter.
- */
-static void de600_rx_intr(struct net_device *dev)
-{
-       struct sk_buff  *skb;
-       int             i;
-       int             read_from;
-       int             size;
-       unsigned char   *buffer;
-
-       /* Get size of received packet */
-       size = de600_read_byte(RX_LEN, dev);    /* low byte */
-       size += (de600_read_byte(RX_LEN, dev) << 8);    /* high byte */
-       size -= 4;      /* Ignore trailing 4 CRC-bytes */
-
-       /* Tell adapter where to store next incoming packet, enable receiver */
-       read_from = rx_page_adr();
-       next_rx_page();
-       de600_put_command(RX_ENABLE);
-
-       if ((size < 32)  ||  (size > 1535)) {
-               printk(KERN_WARNING "%s: Bogus packet size %d.\n", dev->name, size);
-               if (size > 10000)
-                       adapter_init(dev);
-               return;
-       }
-
-       skb = dev_alloc_skb(size+2);
-       if (skb == NULL) {
-               printk("%s: Couldn't allocate a sk_buff of size %d.\n", dev->name, size);
-               return;
-       }
-       /* else */
-
-       skb_reserve(skb,2);     /* Align */
-
-       /* 'skb->data' points to the start of sk_buff data area. */
-       buffer = skb_put(skb,size);
-
-       /* copy the packet into the buffer */
-       de600_setup_address(read_from, RW_ADDR);
-       for (i = size; i > 0; --i, ++buffer)
-               *buffer = de600_read_byte(READ_DATA, dev);
-
-       skb->protocol=eth_type_trans(skb,dev);
-
-       netif_rx(skb);
-
-       /* update stats */
-       dev->stats.rx_packets++; /* count all receives */
-       dev->stats.rx_bytes += size; /* count all received bytes */
-
-       /*
-        * If any worth-while packets have been received, netif_rx()
-        * will work on them when we get to the tasklets.
-        */
-}
-
-static const struct net_device_ops de600_netdev_ops = {
-       .ndo_open               = de600_open,
-       .ndo_stop               = de600_close,
-       .ndo_start_xmit         = de600_start_xmit,
-       .ndo_change_mtu         = eth_change_mtu,
-       .ndo_set_mac_address    = eth_mac_addr,
-       .ndo_validate_addr      = eth_validate_addr,
-};
-
-
-static struct net_device * __init de600_probe(void)
-{
-       int     i;
-       struct net_device *dev;
-       int err;
-
-       dev = alloc_etherdev(0);
-       if (!dev)
-               return ERR_PTR(-ENOMEM);
-
-
-       if (!request_region(DE600_IO, 3, "de600")) {
-               printk(KERN_WARNING "DE600: port 0x%x busy\n", DE600_IO);
-               err = -EBUSY;
-               goto out;
-       }
-
-       printk(KERN_INFO "%s: D-Link DE-600 pocket adapter", dev->name);
-       /* Alpha testers must have the version number to report bugs. */
-       pr_debug("%s", version);
-
-       /* probe for adapter */
-       err = -ENODEV;
-       rx_page = 0;
-       select_nic();
-       (void)de600_read_status(dev);
-       de600_put_command(RESET);
-       de600_put_command(STOP_RESET);
-       if (de600_read_status(dev) & 0xf0) {
-               printk(": not at I/O %#3x.\n", DATA_PORT);
-               goto out1;
-       }
-
-       /*
-        * Maybe we found one,
-        * have to check if it is a D-Link DE-600 adapter...
-        */
-
-       /* Get the adapter ethernet address from the ROM */
-       de600_setup_address(NODE_ADDRESS, RW_ADDR);
-       for (i = 0; i < ETH_ALEN; i++) {
-               dev->dev_addr[i] = de600_read_byte(READ_DATA, dev);
-               dev->broadcast[i] = 0xff;
-       }
-
-       /* Check magic code */
-       if ((dev->dev_addr[1] == 0xde) && (dev->dev_addr[2] == 0x15)) {
-               /* OK, install real address */
-               dev->dev_addr[0] = 0x00;
-               dev->dev_addr[1] = 0x80;
-               dev->dev_addr[2] = 0xc8;
-               dev->dev_addr[3] &= 0x0f;
-               dev->dev_addr[3] |= 0x70;
-       } else {
-               printk(" not identified in the printer port\n");
-               goto out1;
-       }
-
-       printk(", Ethernet Address: %pM\n", dev->dev_addr);
-
-       dev->netdev_ops = &de600_netdev_ops;
-
-       dev->flags&=~IFF_MULTICAST;
-
-       select_prn();
-
-       err = register_netdev(dev);
-       if (err)
-               goto out1;
-
-       return dev;
-
-out1:
-       release_region(DE600_IO, 3);
-out:
-       free_netdev(dev);
-       return ERR_PTR(err);
-}
-
-static int adapter_init(struct net_device *dev)
-{
-       int     i;
-
-       select_nic();
-       rx_page = 0; /* used by RESET */
-       de600_put_command(RESET);
-       de600_put_command(STOP_RESET);
-
-       /* Check if it is still there... */
-       /* Get the some bytes of the adapter ethernet address from the ROM */
-       de600_setup_address(NODE_ADDRESS, RW_ADDR);
-       de600_read_byte(READ_DATA, dev);
-       if ((de600_read_byte(READ_DATA, dev) != 0xde) ||
-           (de600_read_byte(READ_DATA, dev) != 0x15)) {
-       /* was: if (de600_read_status(dev) & 0xf0) { */
-               printk("Something has happened to the DE-600!  Please check it and do a new ifconfig!\n");
-               /* Goodbye, cruel world... */
-               dev->flags &= ~IFF_UP;
-               de600_close(dev);
-               was_down = 1;
-               netif_stop_queue(dev); /* Transmit busy...  */
-               return 1; /* failed */
-       }
-
-       if (was_down) {
-               printk(KERN_INFO "%s: Thanks, I feel much better now!\n", dev->name);
-               was_down = 0;
-       }
-
-       tx_fifo_in = 0;
-       tx_fifo_out = 0;
-       free_tx_pages = TX_PAGES;
-
-
-       /* set the ether address. */
-       de600_setup_address(NODE_ADDRESS, RW_ADDR);
-       for (i = 0; i < ETH_ALEN; i++)
-               de600_put_byte(dev->dev_addr[i]);
-
-       /* where to start saving incoming packets */
-       rx_page = RX_BP | RX_BASE_PAGE;
-       de600_setup_address(MEM_4K, RW_ADDR);
-       /* Enable receiver */
-       de600_put_command(RX_ENABLE);
-       select_prn();
-
-       netif_start_queue(dev);
-
-       return 0; /* OK */
-}
-
-static struct net_device *de600_dev;
-
-static int __init de600_init(void)
-{
-       de600_dev = de600_probe();
-       if (IS_ERR(de600_dev))
-               return PTR_ERR(de600_dev);
-       return 0;
-}
-
-static void __exit de600_exit(void)
-{
-       unregister_netdev(de600_dev);
-       release_region(DE600_IO, 3);
-       free_netdev(de600_dev);
-}
-
-module_init(de600_init);
-module_exit(de600_exit);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/de600.h b/drivers/net/de600.h
deleted file mode 100644 (file)
index e80ecba..0000000
+++ /dev/null
@@ -1,168 +0,0 @@
-/**************************************************
- *                                                *
- * Definition of D-Link Ethernet Pocket adapter   *
- *                                                *
- **************************************************/
-/*
- * D-Link Ethernet pocket adapter ports
- */
-/*
- * OK, so I'm cheating, but there are an awful lot of
- * reads and writes in order to get anything in and out
- * of the DE-600 with 4 bits at a time in the parallel port,
- * so every saved instruction really helps :-)
- */
-
-#ifndef DE600_IO
-#define DE600_IO       0x378
-#endif
-
-#define DATA_PORT      (DE600_IO)
-#define STATUS_PORT    (DE600_IO + 1)
-#define COMMAND_PORT   (DE600_IO + 2)
-
-#ifndef DE600_IRQ
-#define DE600_IRQ      7
-#endif
-/*
- * It really should look like this, and autoprobing as well...
- *
-#define DATA_PORT      (dev->base_addr + 0)
-#define STATUS_PORT    (dev->base_addr + 1)
-#define COMMAND_PORT   (dev->base_addr + 2)
-#define DE600_IRQ      dev->irq
- */
-
-/*
- * D-Link COMMAND_PORT commands
- */
-#define SELECT_NIC     0x04 /* select Network Interface Card */
-#define SELECT_PRN     0x1c /* select Printer */
-#define NML_PRN                0xec /* normal Printer situation */
-#define IRQEN          0x10 /* enable IRQ line */
-
-/*
- * D-Link STATUS_PORT
- */
-#define RX_BUSY                0x80
-#define RX_GOOD                0x40
-#define TX_FAILED16    0x10
-#define TX_BUSY                0x08
-
-/*
- * D-Link DATA_PORT commands
- * command in low 4 bits
- * data in high 4 bits
- * select current data nibble with HI_NIBBLE bit
- */
-#define WRITE_DATA     0x00 /* write memory */
-#define READ_DATA      0x01 /* read memory */
-#define STATUS         0x02 /* read  status register */
-#define COMMAND                0x03 /* write command register (see COMMAND below) */
-#define NULL_COMMAND   0x04 /* null command */
-#define RX_LEN         0x05 /* read  received packet length */
-#define TX_ADDR                0x06 /* set adapter transmit memory address */
-#define RW_ADDR                0x07 /* set adapter read/write memory address */
-#define HI_NIBBLE      0x08 /* read/write the high nibble of data,
-                               or-ed with rest of command */
-
-/*
- * command register, accessed through DATA_PORT with low bits = COMMAND
- */
-#define RX_ALL         0x01 /* PROMISCUOUS */
-#define RX_BP          0x02 /* default: BROADCAST & PHYSICAL ADDRESS */
-#define RX_MBP         0x03 /* MULTICAST, BROADCAST & PHYSICAL ADDRESS */
-
-#define TX_ENABLE      0x04 /* bit 2 */
-#define RX_ENABLE      0x08 /* bit 3 */
-
-#define RESET          0x80 /* set bit 7 high */
-#define STOP_RESET     0x00 /* set bit 7 low */
-
-/*
- * data to command register
- * (high 4 bits in write to DATA_PORT)
- */
-#define RX_PAGE2_SELECT        0x10 /* bit 4, only 2 pages to select */
-#define RX_BASE_PAGE   0x20 /* bit 5, always set when specifying RX_ADDR */
-#define FLIP_IRQ       0x40 /* bit 6 */
-
-/*
- * D-Link adapter internal memory:
- *
- * 0-2K 1:st transmit page (send from pointer up to 2K)
- * 2-4K        2:nd transmit page (send from pointer up to 4K)
- *
- * 4-6K 1:st receive page (data from 4K upwards)
- * 6-8K 2:nd receive page (data from 6K upwards)
- *
- * 8K+ Adapter ROM (contains magic code and last 3 bytes of Ethernet address)
- */
-#define MEM_2K         0x0800 /* 2048 */
-#define MEM_4K         0x1000 /* 4096 */
-#define MEM_6K         0x1800 /* 6144 */
-#define NODE_ADDRESS   0x2000 /* 8192 */
-
-#define RUNT 60                /* Too small Ethernet packet */
-
-/**************************************************
- *                                                *
- *             End of definition                  *
- *                                                *
- **************************************************/
-
-/*
- * Index to functions, as function prototypes.
- */
-/* Routines used internally. (See "convenience macros") */
-static u8      de600_read_status(struct net_device *dev);
-static u8      de600_read_byte(unsigned char type, struct net_device *dev);
-
-/* Put in the device structure. */
-static int     de600_open(struct net_device *dev);
-static int     de600_close(struct net_device *dev);
-static int     de600_start_xmit(struct sk_buff *skb, struct net_device *dev);
-
-/* Dispatch from interrupts. */
-static irqreturn_t de600_interrupt(int irq, void *dev_id);
-static int     de600_tx_intr(struct net_device *dev, int irq_status);
-static void    de600_rx_intr(struct net_device *dev);
-
-/* Initialization */
-static void    trigger_interrupt(struct net_device *dev);
-static int     adapter_init(struct net_device *dev);
-
-/*
- * Convenience macros/functions for D-Link adapter
- */
-
-#define select_prn() outb_p(SELECT_PRN, COMMAND_PORT); DE600_SLOW_DOWN
-#define select_nic() outb_p(SELECT_NIC, COMMAND_PORT); DE600_SLOW_DOWN
-
-/* Thanks for hints from Mark Burton <markb@ordern.demon.co.uk> */
-#define de600_put_byte(data) ( \
-       outb_p(((data) << 4)   | WRITE_DATA            , DATA_PORT), \
-       outb_p(((data) & 0xf0) | WRITE_DATA | HI_NIBBLE, DATA_PORT))
-
-/*
- * The first two outb_p()'s below could perhaps be deleted if there
- * would be more delay in the last two. Not certain about it yet...
- */
-#define de600_put_command(cmd) ( \
-       outb_p(( rx_page        << 4)   | COMMAND            , DATA_PORT), \
-       outb_p(( rx_page        & 0xf0) | COMMAND | HI_NIBBLE, DATA_PORT), \
-       outb_p(((rx_page | cmd) << 4)   | COMMAND            , DATA_PORT), \
-       outb_p(((rx_page | cmd) & 0xf0) | COMMAND | HI_NIBBLE, DATA_PORT))
-
-#define de600_setup_address(addr,type) ( \
-       outb_p((((addr) << 4) & 0xf0) | type            , DATA_PORT), \
-       outb_p(( (addr)       & 0xf0) | type | HI_NIBBLE, DATA_PORT), \
-       outb_p((((addr) >> 4) & 0xf0) | type            , DATA_PORT), \
-       outb_p((((addr) >> 8) & 0xf0) | type | HI_NIBBLE, DATA_PORT))
-
-#define rx_page_adr() ((rx_page & RX_PAGE2_SELECT)?(MEM_6K):(MEM_4K))
-
-/* Flip bit, only 2 pages */
-#define next_rx_page() (rx_page ^= RX_PAGE2_SELECT)
-
-#define tx_page_adr(a) (((a) + 1) * MEM_2K)
diff --git a/drivers/net/de620.c b/drivers/net/de620.c
deleted file mode 100644 (file)
index 1c51a75..0000000
+++ /dev/null
@@ -1,988 +0,0 @@
-/*
- *     de620.c $Revision: 1.40 $ BETA
- *
- *
- *     Linux driver for the D-Link DE-620 Ethernet pocket adapter.
- *
- *     Portions (C) Copyright 1993, 1994 by Bjorn Ekwall <bj0rn@blox.se>
- *
- *     Based on adapter information gathered from DOS packetdriver
- *     sources from D-Link Inc:  (Special thanks to Henry Ngai of D-Link.)
- *             Portions (C) Copyright D-Link SYSTEM Inc. 1991, 1992
- *             Copyright, 1988, Russell Nelson, Crynwr Software
- *
- *     Adapted to the sample network driver core for linux,
- *     written by: Donald Becker <becker@super.org>
- *             (Now at <becker@scyld.com>)
- *
- *     Valuable assistance from:
- *             J. Joshua Kopper <kopper@rtsg.mot.com>
- *             Olav Kvittem <Olav.Kvittem@uninett.no>
- *             Germano Caronni <caronni@nessie.cs.id.ethz.ch>
- *             Jeremy Fitzhardinge <jeremy@suite.sw.oz.au>
- *
- *****************************************************************************/
-/*
- *     This program is free software; you can redistribute it and/or modify
- *     it under the terms of the GNU General Public License as published by
- *     the Free Software Foundation; either version 2, or (at your option)
- *     any later version.
- *
- *     This program is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- *     You should have received a copy of the GNU General Public License
- *     along with this program; if not, write to the Free Software
- *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *****************************************************************************/
-static const char version[] =
-       "de620.c: $Revision: 1.40 $,  Bjorn Ekwall <bj0rn@blox.se>\n";
-
-/***********************************************************************
- *
- * "Tuning" section.
- *
- * Compile-time options: (see below for descriptions)
- * -DDE620_IO=0x378    (lpt1)
- * -DDE620_IRQ=7       (lpt1)
- * -DSHUTDOWN_WHEN_LOST
- * -DCOUNT_LOOPS
- * -DLOWSPEED
- * -DREAD_DELAY
- * -DWRITE_DELAY
- */
-
-/*
- * This driver assumes that the printer port is a "normal",
- * dumb, uni-directional port!
- * If your port is "fancy" in any way, please try to set it to "normal"
- * with your BIOS setup.  I have no access to machines with bi-directional
- * ports, so I can't test such a driver :-(
- * (Yes, I _know_ it is possible to use DE620 with bidirectional ports...)
- *
- * There are some clones of DE620 out there, with different names.
- * If the current driver does not recognize a clone, try to change
- * the following #define to:
- *
- * #define DE620_CLONE 1
- */
-#define DE620_CLONE 0
-
-/*
- * If the adapter has problems with high speeds, enable this #define
- * otherwise full printerport speed will be attempted.
- *
- * You can tune the READ_DELAY/WRITE_DELAY below if you enable LOWSPEED
- *
-#define LOWSPEED
- */
-
-#ifndef READ_DELAY
-#define READ_DELAY 100 /* adapter internal read delay in 100ns units */
-#endif
-
-#ifndef WRITE_DELAY
-#define WRITE_DELAY 100        /* adapter internal write delay in 100ns units */
-#endif
-
-/*
- * Enable this #define if you want the adapter to do a "ifconfig down" on
- * itself when we have detected that something is possibly wrong with it.
- * The default behaviour is to retry with "adapter_init()" until success.
- * This should be used for debugging purposes only.
- *
-#define SHUTDOWN_WHEN_LOST
- */
-
-#ifdef LOWSPEED
-/*
- * Enable this #define if you want to see debugging output that show how long
- * we have to wait before the DE-620 is ready for the next read/write/command.
- *
-#define COUNT_LOOPS
- */
-#endif
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/string.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-
-#include <asm/io.h>
-#include <asm/system.h>
-
-/* Constant definitions for the DE-620 registers, commands and bits */
-#include "de620.h"
-
-typedef unsigned char byte;
-
-/*******************************************************
- *                                                     *
- * Definition of D-Link DE-620 Ethernet Pocket adapter *
- * See also "de620.h"                                  *
- *                                                     *
- *******************************************************/
-#ifndef DE620_IO /* Compile-time configurable */
-#define DE620_IO 0x378
-#endif
-
-#ifndef DE620_IRQ /* Compile-time configurable */
-#define DE620_IRQ      7
-#endif
-
-#define DATA_PORT      (dev->base_addr)
-#define STATUS_PORT    (dev->base_addr + 1)
-#define COMMAND_PORT   (dev->base_addr + 2)
-
-#define RUNT 60                /* Too small Ethernet packet */
-#define GIANT 1514     /* largest legal size packet, no fcs */
-
-/*
- * Force media with insmod:
- *     insmod de620.o bnc=1
- * or
- *     insmod de620.o utp=1
- *
- * Force io and/or irq with insmod:
- *     insmod de620.o io=0x378 irq=7
- *
- * Make a clone skip the Ethernet-address range check:
- *     insmod de620.o clone=1
- */
-static int bnc;
-static int utp;
-static int io  = DE620_IO;
-static int irq = DE620_IRQ;
-static int clone = DE620_CLONE;
-
-static spinlock_t de620_lock;
-
-module_param(bnc, int, 0);
-module_param(utp, int, 0);
-module_param(io, int, 0);
-module_param(irq, int, 0);
-module_param(clone, int, 0);
-MODULE_PARM_DESC(bnc, "DE-620 set BNC medium (0-1)");
-MODULE_PARM_DESC(utp, "DE-620 set UTP medium (0-1)");
-MODULE_PARM_DESC(io, "DE-620 I/O base address,required");
-MODULE_PARM_DESC(irq, "DE-620 IRQ number,required");
-MODULE_PARM_DESC(clone, "Check also for non-D-Link DE-620 clones (0-1)");
-
-/***********************************************
- *                                             *
- * Index to functions, as function prototypes. *
- *                                             *
- ***********************************************/
-
-/*
- * Routines used internally. (See also "convenience macros.. below")
- */
-
-/* Put in the device structure. */
-static int     de620_open(struct net_device *);
-static int     de620_close(struct net_device *);
-static void    de620_set_multicast_list(struct net_device *);
-static int     de620_start_xmit(struct sk_buff *, struct net_device *);
-
-/* Dispatch from interrupts. */
-static irqreturn_t de620_interrupt(int, void *);
-static int     de620_rx_intr(struct net_device *);
-
-/* Initialization */
-static int     adapter_init(struct net_device *);
-static int     read_eeprom(struct net_device *);
-
-
-/*
- * D-Link driver variables:
- */
-#define SCR_DEF NIBBLEMODE |INTON | SLEEP | AUTOTX
-#define        TCR_DEF RXPB                    /* not used: | TXSUCINT | T16INT */
-#define DE620_RX_START_PAGE 12         /* 12 pages (=3k) reserved for tx */
-#define DEF_NIC_CMD IRQEN | ICEN | DS1
-
-static volatile byte   NIC_Cmd;
-static volatile byte   next_rx_page;
-static byte            first_rx_page;
-static byte            last_rx_page;
-static byte            EIPRegister;
-
-static struct nic {
-       byte    NodeID[6];
-       byte    RAM_Size;
-       byte    Model;
-       byte    Media;
-       byte    SCR;
-} nic_data;
-
-/**********************************************************
- *                                                        *
- * Convenience macros/functions for D-Link DE-620 adapter *
- *                                                        *
- **********************************************************/
-#define de620_tx_buffs(dd) (inb(STATUS_PORT) & (TXBF0 | TXBF1))
-#define de620_flip_ds(dd) NIC_Cmd ^= DS0 | DS1; outb(NIC_Cmd, COMMAND_PORT);
-
-/* Check for ready-status, and return a nibble (high 4 bits) for data input */
-#ifdef COUNT_LOOPS
-static int tot_cnt;
-#endif
-static inline byte
-de620_ready(struct net_device *dev)
-{
-       byte value;
-       register short int cnt = 0;
-
-       while ((((value = inb(STATUS_PORT)) & READY) == 0) && (cnt <= 1000))
-               ++cnt;
-
-#ifdef COUNT_LOOPS
-       tot_cnt += cnt;
-#endif
-       return value & 0xf0; /* nibble */
-}
-
-static inline void
-de620_send_command(struct net_device *dev, byte cmd)
-{
-       de620_ready(dev);
-       if (cmd == W_DUMMY)
-               outb(NIC_Cmd, COMMAND_PORT);
-
-       outb(cmd, DATA_PORT);
-
-       outb(NIC_Cmd ^ CS0, COMMAND_PORT);
-       de620_ready(dev);
-       outb(NIC_Cmd, COMMAND_PORT);
-}
-
-static inline void
-de620_put_byte(struct net_device *dev, byte value)
-{
-       /* The de620_ready() makes 7 loops, on the average, on a DX2/66 */
-       de620_ready(dev);
-       outb(value, DATA_PORT);
-       de620_flip_ds(dev);
-}
-
-static inline byte
-de620_read_byte(struct net_device *dev)
-{
-       byte value;
-
-       /* The de620_ready() makes 7 loops, on the average, on a DX2/66 */
-       value = de620_ready(dev); /* High nibble */
-       de620_flip_ds(dev);
-       value |= de620_ready(dev) >> 4; /* Low nibble */
-       return value;
-}
-
-static inline void
-de620_write_block(struct net_device *dev, byte *buffer, int count, int pad)
-{
-#ifndef LOWSPEED
-       byte uflip = NIC_Cmd ^ (DS0 | DS1);
-       byte dflip = NIC_Cmd;
-#else /* LOWSPEED */
-#ifdef COUNT_LOOPS
-       int bytes = count;
-#endif /* COUNT_LOOPS */
-#endif /* LOWSPEED */
-
-#ifdef LOWSPEED
-#ifdef COUNT_LOOPS
-       tot_cnt = 0;
-#endif /* COUNT_LOOPS */
-       /* No further optimization useful, the limit is in the adapter. */
-       for ( ; count > 0; --count, ++buffer) {
-               de620_put_byte(dev,*buffer);
-       }
-       for ( count = pad ; count > 0; --count, ++buffer) {
-               de620_put_byte(dev, 0);
-       }
-       de620_send_command(dev,W_DUMMY);
-#ifdef COUNT_LOOPS
-       /* trial debug output: loops per byte in de620_ready() */
-       printk("WRITE(%d)\n", tot_cnt/((bytes?bytes:1)));
-#endif /* COUNT_LOOPS */
-#else /* not LOWSPEED */
-       for ( ; count > 0; count -=2) {
-               outb(*buffer++, DATA_PORT);
-               outb(uflip, COMMAND_PORT);
-               outb(*buffer++, DATA_PORT);
-               outb(dflip, COMMAND_PORT);
-       }
-       de620_send_command(dev,W_DUMMY);
-#endif /* LOWSPEED */
-}
-
-static inline void
-de620_read_block(struct net_device *dev, byte *data, int count)
-{
-#ifndef LOWSPEED
-       byte value;
-       byte uflip = NIC_Cmd ^ (DS0 | DS1);
-       byte dflip = NIC_Cmd;
-#else /* LOWSPEED */
-#ifdef COUNT_LOOPS
-       int bytes = count;
-
-       tot_cnt = 0;
-#endif /* COUNT_LOOPS */
-#endif /* LOWSPEED */
-
-#ifdef LOWSPEED
-       /* No further optimization useful, the limit is in the adapter. */
-       while (count-- > 0) {
-               *data++ = de620_read_byte(dev);
-               de620_flip_ds(dev);
-       }
-#ifdef COUNT_LOOPS
-       /* trial debug output: loops per byte in de620_ready() */
-       printk("READ(%d)\n", tot_cnt/(2*(bytes?bytes:1)));
-#endif /* COUNT_LOOPS */
-#else /* not LOWSPEED */
-       while (count-- > 0) {
-               value = inb(STATUS_PORT) & 0xf0; /* High nibble */
-               outb(uflip, COMMAND_PORT);
-               *data++ = value | inb(STATUS_PORT) >> 4; /* Low nibble */
-               outb(dflip , COMMAND_PORT);
-       }
-#endif /* LOWSPEED */
-}
-
-static inline void
-de620_set_delay(struct net_device *dev)
-{
-       de620_ready(dev);
-       outb(W_DFR, DATA_PORT);
-       outb(NIC_Cmd ^ CS0, COMMAND_PORT);
-
-       de620_ready(dev);
-#ifdef LOWSPEED
-       outb(WRITE_DELAY, DATA_PORT);
-#else
-       outb(0, DATA_PORT);
-#endif
-       de620_flip_ds(dev);
-
-       de620_ready(dev);
-#ifdef LOWSPEED
-       outb(READ_DELAY, DATA_PORT);
-#else
-       outb(0, DATA_PORT);
-#endif
-       de620_flip_ds(dev);
-}
-
-static inline void
-de620_set_register(struct net_device *dev, byte reg, byte value)
-{
-       de620_ready(dev);
-       outb(reg, DATA_PORT);
-       outb(NIC_Cmd ^ CS0, COMMAND_PORT);
-
-       de620_put_byte(dev, value);
-}
-
-static inline byte
-de620_get_register(struct net_device *dev, byte reg)
-{
-       byte value;
-
-       de620_send_command(dev,reg);
-       value = de620_read_byte(dev);
-       de620_send_command(dev,W_DUMMY);
-
-       return value;
-}
-
-/*********************************************************************
- *
- * Open/initialize the board.
- *
- * 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 a non-reboot way to recover if something goes wrong.
- *
- */
-static int de620_open(struct net_device *dev)
-{
-       int ret = request_irq(dev->irq, de620_interrupt, 0, dev->name, dev);
-       if (ret) {
-               printk (KERN_ERR "%s: unable to get IRQ %d\n", dev->name, dev->irq);
-               return ret;
-       }
-
-       if (adapter_init(dev)) {
-               ret = -EIO;
-               goto out_free_irq;
-       }
-
-       netif_start_queue(dev);
-       return 0;
-
-out_free_irq:
-       free_irq(dev->irq, dev);
-       return ret;
-}
-
-/************************************************
- *
- * The inverse routine to de620_open().
- *
- */
-
-static int de620_close(struct net_device *dev)
-{
-       netif_stop_queue(dev);
-       /* disable recv */
-       de620_set_register(dev, W_TCR, RXOFF);
-       free_irq(dev->irq, dev);
-       return 0;
-}
-
-/*********************************************
- *
- * Set or clear the multicast filter for this adaptor.
- * (no real multicast implemented for the DE-620, but she can be promiscuous...)
- *
- */
-
-static void de620_set_multicast_list(struct net_device *dev)
-{
-       if (!netdev_mc_empty(dev) || dev->flags&(IFF_ALLMULTI|IFF_PROMISC))
-       { /* Enable promiscuous mode */
-               de620_set_register(dev, W_TCR, (TCR_DEF & ~RXPBM) | RXALL);
-       }
-       else
-       { /* Disable promiscuous mode, use normal mode */
-               de620_set_register(dev, W_TCR, TCR_DEF);
-       }
-}
-
-/*******************************************************
- *
- * Handle timeouts on transmit
- */
-
-static void de620_timeout(struct net_device *dev)
-{
-       printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name, "network cable problem");
-       /* Restart the adapter. */
-       if (!adapter_init(dev)) /* maybe close it */
-               netif_wake_queue(dev);
-}
-
-/*******************************************************
- *
- * Copy a buffer to the adapter transmit page memory.
- * Start sending.
- */
-static int de620_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-       unsigned long flags;
-       int len;
-       byte *buffer = skb->data;
-       byte using_txbuf;
-
-       using_txbuf = de620_tx_buffs(dev); /* Peek at the adapter */
-
-       netif_stop_queue(dev);
-
-
-       if ((len = skb->len) < RUNT)
-               len = RUNT;
-       if (len & 1) /* send an even number of bytes */
-               ++len;
-
-       /* Start real output */
-
-       spin_lock_irqsave(&de620_lock, flags);
-       pr_debug("de620_start_xmit: len=%d, bufs 0x%02x\n",
-               (int)skb->len, using_txbuf);
-
-       /* select a free tx buffer. if there is one... */
-       switch (using_txbuf) {
-       default: /* both are free: use TXBF0 */
-       case TXBF1: /* use TXBF0 */
-               de620_send_command(dev,W_CR | RW0);
-               using_txbuf |= TXBF0;
-               break;
-
-       case TXBF0: /* use TXBF1 */
-               de620_send_command(dev,W_CR | RW1);
-               using_txbuf |= TXBF1;
-               break;
-
-       case (TXBF0 | TXBF1): /* NONE!!! */
-               printk(KERN_WARNING "%s: No tx-buffer available!\n", dev->name);
-               spin_unlock_irqrestore(&de620_lock, flags);
-               return NETDEV_TX_BUSY;
-       }
-       de620_write_block(dev, buffer, skb->len, len-skb->len);
-
-       if(!(using_txbuf == (TXBF0 | TXBF1)))
-               netif_wake_queue(dev);
-
-       dev->stats.tx_packets++;
-       spin_unlock_irqrestore(&de620_lock, flags);
-       dev_kfree_skb (skb);
-       return NETDEV_TX_OK;
-}
-
-/*****************************************************
- *
- * Handle the network interface interrupts.
- *
- */
-static irqreturn_t
-de620_interrupt(int irq_in, void *dev_id)
-{
-       struct net_device *dev = dev_id;
-       byte irq_status;
-       int bogus_count = 0;
-       int again = 0;
-
-       spin_lock(&de620_lock);
-
-       /* Read the status register (_not_ the status port) */
-       irq_status = de620_get_register(dev, R_STS);
-
-       pr_debug("de620_interrupt (%2.2X)\n", irq_status);
-
-       if (irq_status & RXGOOD) {
-               do {
-                       again = de620_rx_intr(dev);
-                       pr_debug("again=%d\n", again);
-               }
-               while (again && (++bogus_count < 100));
-       }
-
-       if(de620_tx_buffs(dev) != (TXBF0 | TXBF1))
-               netif_wake_queue(dev);
-
-       spin_unlock(&de620_lock);
-       return IRQ_HANDLED;
-}
-
-/**************************************
- *
- * Get a packet from the adapter
- *
- * Send it "upstairs"
- *
- */
-static int de620_rx_intr(struct net_device *dev)
-{
-       struct header_buf {
-               byte            status;
-               byte            Rx_NextPage;
-               unsigned short  Rx_ByteCount;
-       } header_buf;
-       struct sk_buff *skb;
-       int size;
-       byte *buffer;
-       byte pagelink;
-       byte curr_page;
-
-       pr_debug("de620_rx_intr: next_rx_page = %d\n", next_rx_page);
-
-       /* Tell the adapter that we are going to read data, and from where */
-       de620_send_command(dev, W_CR | RRN);
-       de620_set_register(dev, W_RSA1, next_rx_page);
-       de620_set_register(dev, W_RSA0, 0);
-
-       /* Deep breath, and away we goooooo */
-       de620_read_block(dev, (byte *)&header_buf, sizeof(struct header_buf));
-       pr_debug("page status=0x%02x, nextpage=%d, packetsize=%d\n",
-               header_buf.status, header_buf.Rx_NextPage,
-               header_buf.Rx_ByteCount);
-
-       /* Plausible page header? */
-       pagelink = header_buf.Rx_NextPage;
-       if ((pagelink < first_rx_page) || (last_rx_page < pagelink)) {
-               /* Ouch... Forget it! Skip all and start afresh... */
-               printk(KERN_WARNING "%s: Ring overrun? Restoring...\n", dev->name);
-               /* You win some, you lose some. And sometimes plenty... */
-               adapter_init(dev);
-               netif_wake_queue(dev);
-               dev->stats.rx_over_errors++;
-               return 0;
-       }
-
-       /* OK, this look good, so far. Let's see if it's consistent... */
-       /* Let's compute the start of the next packet, based on where we are */
-       pagelink = next_rx_page +
-               ((header_buf.Rx_ByteCount + (4 - 1 + 0x100)) >> 8);
-
-       /* Are we going to wrap around the page counter? */
-       if (pagelink > last_rx_page)
-               pagelink -= (last_rx_page - first_rx_page + 1);
-
-       /* Is the _computed_ next page number equal to what the adapter says? */
-       if (pagelink != header_buf.Rx_NextPage) {
-               /* Naah, we'll skip this packet. Probably bogus data as well */
-               printk(KERN_WARNING "%s: Page link out of sync! Restoring...\n", dev->name);
-               next_rx_page = header_buf.Rx_NextPage; /* at least a try... */
-               de620_send_command(dev, W_DUMMY);
-               de620_set_register(dev, W_NPRF, next_rx_page);
-               dev->stats.rx_over_errors++;
-               return 0;
-       }
-       next_rx_page = pagelink;
-
-       size = header_buf.Rx_ByteCount - 4;
-       if ((size < RUNT) || (GIANT < size)) {
-               printk(KERN_WARNING "%s: Illegal packet size: %d!\n", dev->name, size);
-       }
-       else { /* Good packet? */
-               skb = dev_alloc_skb(size+2);
-               if (skb == NULL) { /* Yeah, but no place to put it... */
-                       printk(KERN_WARNING "%s: Couldn't allocate a sk_buff of size %d.\n", dev->name, size);
-                       dev->stats.rx_dropped++;
-               }
-               else { /* Yep! Go get it! */
-                       skb_reserve(skb,2);     /* Align */
-                       /* skb->data points to the start of sk_buff data area */
-                       buffer = skb_put(skb,size);
-                       /* copy the packet into the buffer */
-                       de620_read_block(dev, buffer, size);
-                       pr_debug("Read %d bytes\n", size);
-                       skb->protocol=eth_type_trans(skb,dev);
-                       netif_rx(skb); /* deliver it "upstairs" */
-                       /* count all receives */
-                       dev->stats.rx_packets++;
-                       dev->stats.rx_bytes += size;
-               }
-       }
-
-       /* Let's peek ahead to see if we have read the last current packet */
-       /* NOTE! We're _not_ checking the 'EMPTY'-flag! This seems better... */
-       curr_page = de620_get_register(dev, R_CPR);
-       de620_set_register(dev, W_NPRF, next_rx_page);
-       pr_debug("next_rx_page=%d CPR=%d\n", next_rx_page, curr_page);
-
-       return next_rx_page != curr_page; /* That was slightly tricky... */
-}
-
-/*********************************************
- *
- * Reset the adapter to a known state
- *
- */
-static int adapter_init(struct net_device *dev)
-{
-       int i;
-       static int was_down;
-
-       if ((nic_data.Model == 3) || (nic_data.Model == 0)) { /* CT */
-               EIPRegister = NCTL0;
-               if (nic_data.Media != 1)
-                       EIPRegister |= NIS0;    /* not BNC */
-       }
-       else if (nic_data.Model == 2) { /* UTP */
-               EIPRegister = NCTL0 | NIS0;
-       }
-
-       if (utp)
-               EIPRegister = NCTL0 | NIS0;
-       if (bnc)
-               EIPRegister = NCTL0;
-
-       de620_send_command(dev, W_CR | RNOP | CLEAR);
-       de620_send_command(dev, W_CR | RNOP);
-
-       de620_set_register(dev, W_SCR, SCR_DEF);
-       /* disable recv to wait init */
-       de620_set_register(dev, W_TCR, RXOFF);
-
-       /* Set the node ID in the adapter */
-       for (i = 0; i < 6; ++i) { /* W_PARn = 0xaa + n */
-               de620_set_register(dev, W_PAR0 + i, dev->dev_addr[i]);
-       }
-
-       de620_set_register(dev, W_EIP, EIPRegister);
-
-       next_rx_page = first_rx_page = DE620_RX_START_PAGE;
-       if (nic_data.RAM_Size)
-               last_rx_page = nic_data.RAM_Size - 1;
-       else /* 64k RAM */
-               last_rx_page = 255;
-
-       de620_set_register(dev, W_SPR, first_rx_page); /* Start Page Register*/
-       de620_set_register(dev, W_EPR, last_rx_page);  /* End Page Register */
-       de620_set_register(dev, W_CPR, first_rx_page);/*Current Page Register*/
-       de620_send_command(dev, W_NPR | first_rx_page); /* Next Page Register*/
-       de620_send_command(dev, W_DUMMY);
-       de620_set_delay(dev);
-
-       /* Final sanity check: Anybody out there? */
-       /* Let's hope some bits from the statusregister make a good check */
-#define CHECK_MASK (  0 | TXSUC |  T16  |  0  | RXCRC | RXSHORT |  0  |  0  )
-#define CHECK_OK   (  0 |   0   |  0    |  0  |   0   |   0     |  0  |  0  )
-        /* success:   X     0      0       X      0       0        X     X  */
-        /* ignore:   EEDI                RXGOOD                   COLS  LNKS*/
-
-       if (((i = de620_get_register(dev, R_STS)) & CHECK_MASK) != CHECK_OK) {
-               printk(KERN_ERR "%s: Something has happened to the DE-620!  Please check it"
-#ifdef SHUTDOWN_WHEN_LOST
-                       " and do a new ifconfig"
-#endif
-                       "! (%02x)\n", dev->name, i);
-#ifdef SHUTDOWN_WHEN_LOST
-               /* Goodbye, cruel world... */
-               dev->flags &= ~IFF_UP;
-               de620_close(dev);
-#endif
-               was_down = 1;
-               return 1; /* failed */
-       }
-       if (was_down) {
-               printk(KERN_WARNING "%s: Thanks, I feel much better now!\n", dev->name);
-               was_down = 0;
-       }
-
-       /* All OK, go ahead... */
-       de620_set_register(dev, W_TCR, TCR_DEF);
-
-       return 0; /* all ok */
-}
-
-static const struct net_device_ops de620_netdev_ops = {
-       .ndo_open               = de620_open,
-       .ndo_stop               = de620_close,
-       .ndo_start_xmit         = de620_start_xmit,
-       .ndo_tx_timeout         = de620_timeout,
-       .ndo_set_multicast_list = de620_set_multicast_list,
-       .ndo_change_mtu         = eth_change_mtu,
-       .ndo_set_mac_address    = eth_mac_addr,
-       .ndo_validate_addr      = eth_validate_addr,
-};
-
-/******************************************************************************
- *
- * Only start-up code below
- *
- */
-/****************************************
- *
- * Check if there is a DE-620 connected
- */
-struct net_device * __init de620_probe(int unit)
-{
-       byte checkbyte = 0xa5;
-       struct net_device *dev;
-       int err = -ENOMEM;
-       int i;
-
-       dev = alloc_etherdev(0);
-       if (!dev)
-               goto out;
-
-       spin_lock_init(&de620_lock);
-
-       /*
-        * This is where the base_addr and irq gets set.
-        * Tunable at compile-time and insmod-time
-        */
-       dev->base_addr = io;
-       dev->irq       = irq;
-
-       /* allow overriding parameters on command line */
-       if (unit >= 0) {
-               sprintf(dev->name, "eth%d", unit);
-               netdev_boot_setup_check(dev);
-       }
-
-       pr_debug("%s", version);
-
-       printk(KERN_INFO "D-Link DE-620 pocket adapter");
-
-       if (!request_region(dev->base_addr, 3, "de620")) {
-               printk(" io 0x%3lX, which is busy.\n", dev->base_addr);
-               err = -EBUSY;
-               goto out1;
-       }
-
-       /* Initially, configure basic nibble mode, so we can read the EEPROM */
-       NIC_Cmd = DEF_NIC_CMD;
-       de620_set_register(dev, W_EIP, EIPRegister);
-
-       /* Anybody out there? */
-       de620_set_register(dev, W_CPR, checkbyte);
-       checkbyte = de620_get_register(dev, R_CPR);
-
-       if ((checkbyte != 0xa5) || (read_eeprom(dev) != 0)) {
-               printk(" not identified in the printer port\n");
-               err = -ENODEV;
-               goto out2;
-       }
-
-       /* else, got it! */
-       dev->dev_addr[0] = nic_data.NodeID[0];
-       for (i = 1; i < ETH_ALEN; i++) {
-               dev->dev_addr[i] = nic_data.NodeID[i];
-               dev->broadcast[i] = 0xff;
-       }
-
-       printk(", Ethernet Address: %pM", dev->dev_addr);
-
-       printk(" (%dk RAM,",
-               (nic_data.RAM_Size) ? (nic_data.RAM_Size >> 2) : 64);
-
-       if (nic_data.Media == 1)
-               printk(" BNC)\n");
-       else
-               printk(" UTP)\n");
-
-       dev->netdev_ops = &de620_netdev_ops;
-       dev->watchdog_timeo     = HZ*2;
-
-       /* base_addr and irq are already set, see above! */
-
-       /* dump eeprom */
-       pr_debug("\nEEPROM contents:\n"
-               "RAM_Size = 0x%02X\n"
-               "NodeID = %pM\n"
-               "Model = %d\n"
-               "Media = %d\n"
-               "SCR = 0x%02x\n", nic_data.RAM_Size, nic_data.NodeID,
-               nic_data.Model, nic_data.Media, nic_data.SCR);
-
-       err = register_netdev(dev);
-       if (err)
-               goto out2;
-       return dev;
-
-out2:
-       release_region(dev->base_addr, 3);
-out1:
-       free_netdev(dev);
-out:
-       return ERR_PTR(err);
-}
-
-/**********************************
- *
- * Read info from on-board EEPROM
- *
- * Note: Bitwise serial I/O to/from the EEPROM vi the status _register_!
- */
-#define sendit(dev,data) de620_set_register(dev, W_EIP, data | EIPRegister);
-
-static unsigned short __init ReadAWord(struct net_device *dev, int from)
-{
-       unsigned short data;
-       int nbits;
-
-       /* cs   [__~~] SET SEND STATE */
-       /* di   [____]                */
-       /* sck  [_~~_]                */
-       sendit(dev, 0); sendit(dev, 1); sendit(dev, 5); sendit(dev, 4);
-
-       /* Send the 9-bit address from where we want to read the 16-bit word */
-       for (nbits = 9; nbits > 0; --nbits, from <<= 1) {
-               if (from & 0x0100) { /* bit set? */
-                       /* cs    [~~~~] SEND 1 */
-                       /* di    [~~~~]        */
-                       /* sck   [_~~_]        */
-                       sendit(dev, 6); sendit(dev, 7); sendit(dev, 7); sendit(dev, 6);
-               }
-               else {
-                       /* cs    [~~~~] SEND 0 */
-                       /* di    [____]        */
-                       /* sck   [_~~_]        */
-                       sendit(dev, 4); sendit(dev, 5); sendit(dev, 5); sendit(dev, 4);
-               }
-       }
-
-       /* Shift in the 16-bit word. The bits appear serially in EEDI (=0x80) */
-       for (data = 0, nbits = 16; nbits > 0; --nbits) {
-               /* cs    [~~~~] SEND 0 */
-               /* di    [____]        */
-               /* sck   [_~~_]        */
-               sendit(dev, 4); sendit(dev, 5); sendit(dev, 5); sendit(dev, 4);
-               data = (data << 1) | ((de620_get_register(dev, R_STS) & EEDI) >> 7);
-       }
-       /* cs    [____] RESET SEND STATE */
-       /* di    [____]                  */
-       /* sck   [_~~_]                  */
-       sendit(dev, 0); sendit(dev, 1); sendit(dev, 1); sendit(dev, 0);
-
-       return data;
-}
-
-static int __init read_eeprom(struct net_device *dev)
-{
-       unsigned short wrd;
-
-       /* D-Link Ethernet addresses are in the series  00:80:c8:7X:XX:XX:XX */
-       wrd = ReadAWord(dev, 0x1aa);    /* bytes 0 + 1 of NodeID */
-       if (!clone && (wrd != htons(0x0080))) /* Valid D-Link ether sequence? */
-               return -1; /* Nope, not a DE-620 */
-       nic_data.NodeID[0] = wrd & 0xff;
-       nic_data.NodeID[1] = wrd >> 8;
-
-       wrd = ReadAWord(dev, 0x1ab);    /* bytes 2 + 3 of NodeID */
-       if (!clone && ((wrd & 0xff) != 0xc8)) /* Valid D-Link ether sequence? */
-               return -1; /* Nope, not a DE-620 */
-       nic_data.NodeID[2] = wrd & 0xff;
-       nic_data.NodeID[3] = wrd >> 8;
-
-       wrd = ReadAWord(dev, 0x1ac);    /* bytes 4 + 5 of NodeID */
-       nic_data.NodeID[4] = wrd & 0xff;
-       nic_data.NodeID[5] = wrd >> 8;
-
-       wrd = ReadAWord(dev, 0x1ad);    /* RAM size in pages (256 bytes). 0 = 64k */
-       nic_data.RAM_Size = (wrd >> 8);
-
-       wrd = ReadAWord(dev, 0x1ae);    /* hardware model (CT = 3) */
-       nic_data.Model = (wrd & 0xff);
-
-       wrd = ReadAWord(dev, 0x1af); /* media (indicates BNC/UTP) */
-       nic_data.Media = (wrd & 0xff);
-
-       wrd = ReadAWord(dev, 0x1a8); /* System Configuration Register */
-       nic_data.SCR = (wrd >> 8);
-
-       return 0; /* no errors */
-}
-
-/******************************************************************************
- *
- * Loadable module skeleton
- *
- */
-#ifdef MODULE
-static struct net_device *de620_dev;
-
-int __init init_module(void)
-{
-       de620_dev = de620_probe(-1);
-       if (IS_ERR(de620_dev))
-               return PTR_ERR(de620_dev);
-       return 0;
-}
-
-void cleanup_module(void)
-{
-       unregister_netdev(de620_dev);
-       release_region(de620_dev->base_addr, 3);
-       free_netdev(de620_dev);
-}
-#endif /* MODULE */
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/de620.h b/drivers/net/de620.h
deleted file mode 100644 (file)
index e8d9a88..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-/*********************************************************
- *                                                       *
- * Definition of D-Link DE-620 Ethernet Pocket adapter   *
- *                                                       *
- *********************************************************/
-
-/* DE-620's CMD port Command */
-#define CS0            0x08    /* 1->0 command strobe */
-#define ICEN           0x04    /* 0=enable DL3520 host interface */
-#define DS0            0x02    /* 1->0 data strobe 0 */
-#define DS1            0x01    /* 1->0 data strobe 1 */
-
-#define WDIR           0x20    /* general 0=read  1=write */
-#define RDIR           0x00    /*  (not 100% confirm ) */
-#define PS2WDIR                0x00    /* ps/2 mode 1=read, 0=write */
-#define PS2RDIR                0x20
-
-#define IRQEN          0x10    /* 1 = enable printer IRQ line */
-#define SELECTIN       0x08    /* 1 = select printer */
-#define INITP          0x04    /* 0 = initial printer */
-#define AUTOFEED       0x02    /* 1 = printer auto form feed */
-#define STROBE         0x01    /* 0->1 data strobe */
-
-#define RESET          0x08
-#define NIS0           0x20    /* 0 = BNC, 1 = UTP */
-#define NCTL0          0x10
-
-/* DE-620 DIC Command */
-#define W_DUMMY                0x00    /* DIC reserved command */
-#define W_CR           0x20    /* DIC write command register */
-#define W_NPR          0x40    /* DIC write Next Page Register */
-#define W_TBR          0x60    /* DIC write Tx Byte Count 1 reg */
-#define W_RSA          0x80    /* DIC write Remote Start Addr 1 */
-
-/* DE-620's STAT port bits 7-4 */
-#define EMPTY          0x80    /* 1 = receive buffer empty */
-#define INTLEVEL       0x40    /* 1 = interrupt level is high */
-#define TXBF1          0x20    /* 1 = transmit buffer 1 is in use */
-#define TXBF0          0x10    /* 1 = transmit buffer 0 is in use */
-#define READY          0x08    /* 1 = h/w ready to accept cmd/data */
-
-/* IDC 1 Command */
-#define        W_RSA1          0xa0    /* write remote start address 1 */
-#define        W_RSA0          0xa1    /* write remote start address 0 */
-#define        W_NPRF          0xa2    /* write next page register NPR15-NPR8 */
-#define        W_DFR           0xa3    /* write delay factor register */
-#define        W_CPR           0xa4    /* write current page register */
-#define        W_SPR           0xa5    /* write start page register */
-#define        W_EPR           0xa6    /* write end page register */
-#define        W_SCR           0xa7    /* write system configuration register */
-#define        W_TCR           0xa8    /* write Transceiver Configuration reg */
-#define        W_EIP           0xa9    /* write EEPM Interface port */
-#define        W_PAR0          0xaa    /* write physical address register 0 */
-#define        W_PAR1          0xab    /* write physical address register 1 */
-#define        W_PAR2          0xac    /* write physical address register 2 */
-#define        W_PAR3          0xad    /* write physical address register 3 */
-#define        W_PAR4          0xae    /* write physical address register 4 */
-#define        W_PAR5          0xaf    /* write physical address register 5 */
-
-/* IDC 2 Command */
-#define        R_STS           0xc0    /* read status register */
-#define        R_CPR           0xc1    /* read current page register */
-#define        R_BPR           0xc2    /* read boundary page register */
-#define        R_TDR           0xc3    /* read time domain reflectometry reg */
-
-/* STATUS Register */
-#define EEDI           0x80    /* EEPM DO pin */
-#define TXSUC          0x40    /* tx success */
-#define T16            0x20    /* tx fail 16 times */
-#define TS1            0x40    /* 0=Tx success, 1=T16 */
-#define TS0            0x20    /* 0=Tx success, 1=T16 */
-#define RXGOOD         0x10    /* rx a good packet */
-#define RXCRC          0x08    /* rx a CRC error packet */
-#define RXSHORT                0x04    /* rx a short packet */
-#define COLS           0x02    /* coaxial collision status */
-#define LNKS           0x01    /* UTP link status */
-
-/* Command Register */
-#define CLEAR          0x10    /* reset part of hardware */
-#define NOPER          0x08    /* No Operation */
-#define RNOP           0x08
-#define RRA            0x06    /* After RR then auto-advance NPR & BPR(=NPR-1) */
-#define RRN            0x04    /* Normal Remote Read mode */
-#define RW1            0x02    /* Remote Write tx buffer 1  ( page 6 - 11 ) */
-#define RW0            0x00    /* Remote Write tx buffer 0  ( page 0 - 5 ) */
-#define TXEN           0x01    /* 0->1 tx enable */
-
-/* System Configuration Register */
-#define TESTON         0x80    /* test host data transfer reliability */
-#define SLEEP          0x40    /* sleep mode */
-#if 0
-#define FASTMODE       0x04    /* fast mode for intel 82360SL fast mode */
-#define BYTEMODE       0x02    /* byte mode */
-#else
-#define FASTMODE       0x20    /* fast mode for intel 82360SL fast mode */
-#define BYTEMODE       0x10    /* byte mode */
-#endif
-#define NIBBLEMODE     0x00    /* nibble mode */
-#define IRQINV         0x08    /* turn off IRQ line inverter */
-#define IRQNML         0x00    /* turn on IRQ line inverter */
-#define INTON          0x04
-#define AUTOFFSET      0x02    /* auto shift address to TPR+12 */
-#define AUTOTX         0x01    /* auto tx when leave RW mode */
-
-/* Transceiver Configuration Register */
-#define JABBER         0x80    /* generate jabber condition */
-#define TXSUCINT       0x40    /* enable tx success interrupt */
-#define T16INT         0x20    /* enable T16 interrupt */
-#define RXERRPKT       0x10    /* accept CRC error or short packet */
-#define EXTERNALB2     0x0C    /* external loopback 2 */
-#define EXTERNALB1     0x08    /* external loopback 1 */
-#define INTERNALB      0x04    /* internal loopback */
-#define NMLOPERATE     0x00    /* normal operation */
-#define RXPBM          0x03    /* rx physical, broadcast, multicast */
-#define RXPB           0x02    /* rx physical, broadcast */
-#define RXALL          0x01    /* rx all packet */
-#define RXOFF          0x00    /* rx disable */
diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c
deleted file mode 100644 (file)
index ed73e4a..0000000
+++ /dev/null
@@ -1,1824 +0,0 @@
-/*  D-Link DL2000-based Gigabit Ethernet Adapter Linux driver */
-/*
-    Copyright (c) 2001, 2002 by D-Link Corporation
-    Written by Edward Peng.<edward_peng@dlink.com.tw>
-    Created 03-May-2001, base on Linux' sundance.c.
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-*/
-
-#define DRV_NAME       "DL2000/TC902x-based linux driver"
-#define DRV_VERSION    "v1.19"
-#define DRV_RELDATE    "2007/08/12"
-#include "dl2k.h"
-#include <linux/dma-mapping.h>
-
-static char version[] __devinitdata =
-      KERN_INFO DRV_NAME " " DRV_VERSION " " DRV_RELDATE "\n";
-#define MAX_UNITS 8
-static int mtu[MAX_UNITS];
-static int vlan[MAX_UNITS];
-static int jumbo[MAX_UNITS];
-static char *media[MAX_UNITS];
-static int tx_flow=-1;
-static int rx_flow=-1;
-static int copy_thresh;
-static int rx_coalesce=10;     /* Rx frame count each interrupt */
-static int rx_timeout=200;     /* Rx DMA wait time in 640ns increments */
-static int tx_coalesce=16;     /* HW xmit count each TxDMAComplete */
-
-
-MODULE_AUTHOR ("Edward Peng");
-MODULE_DESCRIPTION ("D-Link DL2000-based Gigabit Ethernet Adapter");
-MODULE_LICENSE("GPL");
-module_param_array(mtu, int, NULL, 0);
-module_param_array(media, charp, NULL, 0);
-module_param_array(vlan, int, NULL, 0);
-module_param_array(jumbo, int, NULL, 0);
-module_param(tx_flow, int, 0);
-module_param(rx_flow, int, 0);
-module_param(copy_thresh, int, 0);
-module_param(rx_coalesce, int, 0);     /* Rx frame count each interrupt */
-module_param(rx_timeout, int, 0);      /* Rx DMA wait time in 64ns increments */
-module_param(tx_coalesce, int, 0); /* HW xmit count each TxDMAComplete */
-
-
-/* Enable the default interrupts */
-#define DEFAULT_INTR (RxDMAComplete | HostError | IntRequested | TxDMAComplete| \
-       UpdateStats | LinkEvent)
-#define EnableInt() \
-writew(DEFAULT_INTR, ioaddr + IntEnable)
-
-static const int max_intrloop = 50;
-static const int multicast_filter_limit = 0x40;
-
-static int rio_open (struct net_device *dev);
-static void rio_timer (unsigned long data);
-static void rio_tx_timeout (struct net_device *dev);
-static void alloc_list (struct net_device *dev);
-static netdev_tx_t start_xmit (struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t rio_interrupt (int irq, void *dev_instance);
-static void rio_free_tx (struct net_device *dev, int irq);
-static void tx_error (struct net_device *dev, int tx_status);
-static int receive_packet (struct net_device *dev);
-static void rio_error (struct net_device *dev, int int_status);
-static int change_mtu (struct net_device *dev, int new_mtu);
-static void set_multicast (struct net_device *dev);
-static struct net_device_stats *get_stats (struct net_device *dev);
-static int clear_stats (struct net_device *dev);
-static int rio_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
-static int rio_close (struct net_device *dev);
-static int find_miiphy (struct net_device *dev);
-static int parse_eeprom (struct net_device *dev);
-static int read_eeprom (long ioaddr, int eep_addr);
-static int mii_wait_link (struct net_device *dev, int wait);
-static int mii_set_media (struct net_device *dev);
-static int mii_get_media (struct net_device *dev);
-static int mii_set_media_pcs (struct net_device *dev);
-static int mii_get_media_pcs (struct net_device *dev);
-static int mii_read (struct net_device *dev, int phy_addr, int reg_num);
-static int mii_write (struct net_device *dev, int phy_addr, int reg_num,
-                     u16 data);
-
-static const struct ethtool_ops ethtool_ops;
-
-static const struct net_device_ops netdev_ops = {
-       .ndo_open               = rio_open,
-       .ndo_start_xmit = start_xmit,
-       .ndo_stop               = rio_close,
-       .ndo_get_stats          = get_stats,
-       .ndo_validate_addr      = eth_validate_addr,
-       .ndo_set_mac_address    = eth_mac_addr,
-       .ndo_set_multicast_list = set_multicast,
-       .ndo_do_ioctl           = rio_ioctl,
-       .ndo_tx_timeout         = rio_tx_timeout,
-       .ndo_change_mtu         = change_mtu,
-};
-
-static int __devinit
-rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent)
-{
-       struct net_device *dev;
-       struct netdev_private *np;
-       static int card_idx;
-       int chip_idx = ent->driver_data;
-       int err, irq;
-       long ioaddr;
-       static int version_printed;
-       void *ring_space;
-       dma_addr_t ring_dma;
-
-       if (!version_printed++)
-               printk ("%s", version);
-
-       err = pci_enable_device (pdev);
-       if (err)
-               return err;
-
-       irq = pdev->irq;
-       err = pci_request_regions (pdev, "dl2k");
-       if (err)
-               goto err_out_disable;
-
-       pci_set_master (pdev);
-       dev = alloc_etherdev (sizeof (*np));
-       if (!dev) {
-               err = -ENOMEM;
-               goto err_out_res;
-       }
-       SET_NETDEV_DEV(dev, &pdev->dev);
-
-#ifdef MEM_MAPPING
-       ioaddr = pci_resource_start (pdev, 1);
-       ioaddr = (long) ioremap (ioaddr, RIO_IO_SIZE);
-       if (!ioaddr) {
-               err = -ENOMEM;
-               goto err_out_dev;
-       }
-#else
-       ioaddr = pci_resource_start (pdev, 0);
-#endif
-       dev->base_addr = ioaddr;
-       dev->irq = irq;
-       np = netdev_priv(dev);
-       np->chip_id = chip_idx;
-       np->pdev = pdev;
-       spin_lock_init (&np->tx_lock);
-       spin_lock_init (&np->rx_lock);
-
-       /* Parse manual configuration */
-       np->an_enable = 1;
-       np->tx_coalesce = 1;
-       if (card_idx < MAX_UNITS) {
-               if (media[card_idx] != NULL) {
-                       np->an_enable = 0;
-                       if (strcmp (media[card_idx], "auto") == 0 ||
-                           strcmp (media[card_idx], "autosense") == 0 ||
-                           strcmp (media[card_idx], "0") == 0 ) {
-                               np->an_enable = 2;
-                       } else if (strcmp (media[card_idx], "100mbps_fd") == 0 ||
-                           strcmp (media[card_idx], "4") == 0) {
-                               np->speed = 100;
-                               np->full_duplex = 1;
-                       } else if (strcmp (media[card_idx], "100mbps_hd") == 0 ||
-                                  strcmp (media[card_idx], "3") == 0) {
-                               np->speed = 100;
-                               np->full_duplex = 0;
-                       } else if (strcmp (media[card_idx], "10mbps_fd") == 0 ||
-                                  strcmp (media[card_idx], "2") == 0) {
-                               np->speed = 10;
-                               np->full_duplex = 1;
-                       } else if (strcmp (media[card_idx], "10mbps_hd") == 0 ||
-                                  strcmp (media[card_idx], "1") == 0) {
-                               np->speed = 10;
-                               np->full_duplex = 0;
-                       } else if (strcmp (media[card_idx], "1000mbps_fd") == 0 ||
-                                strcmp (media[card_idx], "6") == 0) {
-                               np->speed=1000;
-                               np->full_duplex=1;
-                       } else if (strcmp (media[card_idx], "1000mbps_hd") == 0 ||
-                                strcmp (media[card_idx], "5") == 0) {
-                               np->speed = 1000;
-                               np->full_duplex = 0;
-                       } else {
-                               np->an_enable = 1;
-                       }
-               }
-               if (jumbo[card_idx] != 0) {
-                       np->jumbo = 1;
-                       dev->mtu = MAX_JUMBO;
-               } else {
-                       np->jumbo = 0;
-                       if (mtu[card_idx] > 0 && mtu[card_idx] < PACKET_SIZE)
-                               dev->mtu = mtu[card_idx];
-               }
-               np->vlan = (vlan[card_idx] > 0 && vlan[card_idx] < 4096) ?
-                   vlan[card_idx] : 0;
-               if (rx_coalesce > 0 && rx_timeout > 0) {
-                       np->rx_coalesce = rx_coalesce;
-                       np->rx_timeout = rx_timeout;
-                       np->coalesce = 1;
-               }
-               np->tx_flow = (tx_flow == 0) ? 0 : 1;
-               np->rx_flow = (rx_flow == 0) ? 0 : 1;
-
-               if (tx_coalesce < 1)
-                       tx_coalesce = 1;
-               else if (tx_coalesce > TX_RING_SIZE-1)
-                       tx_coalesce = TX_RING_SIZE - 1;
-       }
-       dev->netdev_ops = &netdev_ops;
-       dev->watchdog_timeo = TX_TIMEOUT;
-       SET_ETHTOOL_OPS(dev, &ethtool_ops);
-#if 0
-       dev->features = NETIF_F_IP_CSUM;
-#endif
-       pci_set_drvdata (pdev, dev);
-
-       ring_space = pci_alloc_consistent (pdev, TX_TOTAL_SIZE, &ring_dma);
-       if (!ring_space)
-               goto err_out_iounmap;
-       np->tx_ring = ring_space;
-       np->tx_ring_dma = ring_dma;
-
-       ring_space = pci_alloc_consistent (pdev, RX_TOTAL_SIZE, &ring_dma);
-       if (!ring_space)
-               goto err_out_unmap_tx;
-       np->rx_ring = ring_space;
-       np->rx_ring_dma = ring_dma;
-
-       /* Parse eeprom data */
-       parse_eeprom (dev);
-
-       /* Find PHY address */
-       err = find_miiphy (dev);
-       if (err)
-               goto err_out_unmap_rx;
-
-       /* Fiber device? */
-       np->phy_media = (readw(ioaddr + ASICCtrl) & PhyMedia) ? 1 : 0;
-       np->link_status = 0;
-       /* Set media and reset PHY */
-       if (np->phy_media) {
-               /* default Auto-Negotiation for fiber deivices */
-               if (np->an_enable == 2) {
-                       np->an_enable = 1;
-               }
-               mii_set_media_pcs (dev);
-       } else {
-               /* Auto-Negotiation is mandatory for 1000BASE-T,
-                  IEEE 802.3ab Annex 28D page 14 */
-               if (np->speed == 1000)
-                       np->an_enable = 1;
-               mii_set_media (dev);
-       }
-
-       err = register_netdev (dev);
-       if (err)
-               goto err_out_unmap_rx;
-
-       card_idx++;
-
-       printk (KERN_INFO "%s: %s, %pM, IRQ %d\n",
-               dev->name, np->name, dev->dev_addr, irq);
-       if (tx_coalesce > 1)
-               printk(KERN_INFO "tx_coalesce:\t%d packets\n",
-                               tx_coalesce);
-       if (np->coalesce)
-               printk(KERN_INFO
-                      "rx_coalesce:\t%d packets\n"
-                      "rx_timeout: \t%d ns\n",
-                               np->rx_coalesce, np->rx_timeout*640);
-       if (np->vlan)
-               printk(KERN_INFO "vlan(id):\t%d\n", np->vlan);
-       return 0;
-
-      err_out_unmap_rx:
-       pci_free_consistent (pdev, RX_TOTAL_SIZE, np->rx_ring, np->rx_ring_dma);
-      err_out_unmap_tx:
-       pci_free_consistent (pdev, TX_TOTAL_SIZE, np->tx_ring, np->tx_ring_dma);
-      err_out_iounmap:
-#ifdef MEM_MAPPING
-       iounmap ((void *) ioaddr);
-
-      err_out_dev:
-#endif
-       free_netdev (dev);
-
-      err_out_res:
-       pci_release_regions (pdev);
-
-      err_out_disable:
-       pci_disable_device (pdev);
-       return err;
-}
-
-static int
-find_miiphy (struct net_device *dev)
-{
-       int i, phy_found = 0;
-       struct netdev_private *np;
-       long ioaddr;
-       np = netdev_priv(dev);
-       ioaddr = dev->base_addr;
-       np->phy_addr = 1;
-
-       for (i = 31; i >= 0; i--) {
-               int mii_status = mii_read (dev, i, 1);
-               if (mii_status != 0xffff && mii_status != 0x0000) {
-                       np->phy_addr = i;
-                       phy_found++;
-               }
-       }
-       if (!phy_found) {
-               printk (KERN_ERR "%s: No MII PHY found!\n", dev->name);
-               return -ENODEV;
-       }
-       return 0;
-}
-
-static int
-parse_eeprom (struct net_device *dev)
-{
-       int i, j;
-       long ioaddr = dev->base_addr;
-       u8 sromdata[256];
-       u8 *psib;
-       u32 crc;
-       PSROM_t psrom = (PSROM_t) sromdata;
-       struct netdev_private *np = netdev_priv(dev);
-
-       int cid, next;
-
-#ifdef MEM_MAPPING
-       ioaddr = pci_resource_start (np->pdev, 0);
-#endif
-       /* Read eeprom */
-       for (i = 0; i < 128; i++) {
-               ((__le16 *) sromdata)[i] = cpu_to_le16(read_eeprom (ioaddr, i));
-       }
-#ifdef MEM_MAPPING
-       ioaddr = dev->base_addr;
-#endif
-       if (np->pdev->vendor == PCI_VENDOR_ID_DLINK) {  /* D-Link Only */
-               /* Check CRC */
-               crc = ~ether_crc_le (256 - 4, sromdata);
-               if (psrom->crc != cpu_to_le32(crc)) {
-                       printk (KERN_ERR "%s: EEPROM data CRC error.\n",
-                                       dev->name);
-                       return -1;
-               }
-       }
-
-       /* Set MAC address */
-       for (i = 0; i < 6; i++)
-               dev->dev_addr[i] = psrom->mac_addr[i];
-
-       if (np->pdev->vendor != PCI_VENDOR_ID_DLINK) {
-               return 0;
-       }
-
-       /* Parse Software Information Block */
-       i = 0x30;
-       psib = (u8 *) sromdata;
-       do {
-               cid = psib[i++];
-               next = psib[i++];
-               if ((cid == 0 && next == 0) || (cid == 0xff && next == 0xff)) {
-                       printk (KERN_ERR "Cell data error\n");
-                       return -1;
-               }
-               switch (cid) {
-               case 0: /* Format version */
-                       break;
-               case 1: /* End of cell */
-                       return 0;
-               case 2: /* Duplex Polarity */
-                       np->duplex_polarity = psib[i];
-                       writeb (readb (ioaddr + PhyCtrl) | psib[i],
-                               ioaddr + PhyCtrl);
-                       break;
-               case 3: /* Wake Polarity */
-                       np->wake_polarity = psib[i];
-                       break;
-               case 9: /* Adapter description */
-                       j = (next - i > 255) ? 255 : next - i;
-                       memcpy (np->name, &(psib[i]), j);
-                       break;
-               case 4:
-               case 5:
-               case 6:
-               case 7:
-               case 8: /* Reversed */
-                       break;
-               default:        /* Unknown cell */
-                       return -1;
-               }
-               i = next;
-       } while (1);
-
-       return 0;
-}
-
-static int
-rio_open (struct net_device *dev)
-{
-       struct netdev_private *np = netdev_priv(dev);
-       long ioaddr = dev->base_addr;
-       int i;
-       u16 macctrl;
-
-       i = request_irq (dev->irq, rio_interrupt, IRQF_SHARED, dev->name, dev);
-       if (i)
-               return i;
-
-       /* Reset all logic functions */
-       writew (GlobalReset | DMAReset | FIFOReset | NetworkReset | HostReset,
-               ioaddr + ASICCtrl + 2);
-       mdelay(10);
-
-       /* DebugCtrl bit 4, 5, 9 must set */
-       writel (readl (ioaddr + DebugCtrl) | 0x0230, ioaddr + DebugCtrl);
-
-       /* Jumbo frame */
-       if (np->jumbo != 0)
-               writew (MAX_JUMBO+14, ioaddr + MaxFrameSize);
-
-       alloc_list (dev);
-
-       /* Get station address */
-       for (i = 0; i < 6; i++)
-               writeb (dev->dev_addr[i], ioaddr + StationAddr0 + i);
-
-       set_multicast (dev);
-       if (np->coalesce) {
-               writel (np->rx_coalesce | np->rx_timeout << 16,
-                       ioaddr + RxDMAIntCtrl);
-       }
-       /* Set RIO to poll every N*320nsec. */
-       writeb (0x20, ioaddr + RxDMAPollPeriod);
-       writeb (0xff, ioaddr + TxDMAPollPeriod);
-       writeb (0x30, ioaddr + RxDMABurstThresh);
-       writeb (0x30, ioaddr + RxDMAUrgentThresh);
-       writel (0x0007ffff, ioaddr + RmonStatMask);
-       /* clear statistics */
-       clear_stats (dev);
-
-       /* VLAN supported */
-       if (np->vlan) {
-               /* priority field in RxDMAIntCtrl  */
-               writel (readl(ioaddr + RxDMAIntCtrl) | 0x7 << 10,
-                       ioaddr + RxDMAIntCtrl);
-               /* VLANId */
-               writew (np->vlan, ioaddr + VLANId);
-               /* Length/Type should be 0x8100 */
-               writel (0x8100 << 16 | np->vlan, ioaddr + VLANTag);
-               /* Enable AutoVLANuntagging, but disable AutoVLANtagging.
-                  VLAN information tagged by TFC' VID, CFI fields. */
-               writel (readl (ioaddr + MACCtrl) | AutoVLANuntagging,
-                       ioaddr + MACCtrl);
-       }
-
-       init_timer (&np->timer);
-       np->timer.expires = jiffies + 1*HZ;
-       np->timer.data = (unsigned long) dev;
-       np->timer.function = rio_timer;
-       add_timer (&np->timer);
-
-       /* Start Tx/Rx */
-       writel (readl (ioaddr + MACCtrl) | StatsEnable | RxEnable | TxEnable,
-                       ioaddr + MACCtrl);
-
-       macctrl = 0;
-       macctrl |= (np->vlan) ? AutoVLANuntagging : 0;
-       macctrl |= (np->full_duplex) ? DuplexSelect : 0;
-       macctrl |= (np->tx_flow) ? TxFlowControlEnable : 0;
-       macctrl |= (np->rx_flow) ? RxFlowControlEnable : 0;
-       writew(macctrl, ioaddr + MACCtrl);
-
-       netif_start_queue (dev);
-
-       /* Enable default interrupts */
-       EnableInt ();
-       return 0;
-}
-
-static void
-rio_timer (unsigned long data)
-{
-       struct net_device *dev = (struct net_device *)data;
-       struct netdev_private *np = netdev_priv(dev);
-       unsigned int entry;
-       int next_tick = 1*HZ;
-       unsigned long flags;
-
-       spin_lock_irqsave(&np->rx_lock, flags);
-       /* Recover rx ring exhausted error */
-       if (np->cur_rx - np->old_rx >= RX_RING_SIZE) {
-               printk(KERN_INFO "Try to recover rx ring exhausted...\n");
-               /* Re-allocate skbuffs to fill the descriptor ring */
-               for (; np->cur_rx - np->old_rx > 0; np->old_rx++) {
-                       struct sk_buff *skb;
-                       entry = np->old_rx % RX_RING_SIZE;
-                       /* Dropped packets don't need to re-allocate */
-                       if (np->rx_skbuff[entry] == NULL) {
-                               skb = netdev_alloc_skb_ip_align(dev,
-                                                               np->rx_buf_sz);
-                               if (skb == NULL) {
-                                       np->rx_ring[entry].fraginfo = 0;
-                                       printk (KERN_INFO
-                                               "%s: Still unable to re-allocate Rx skbuff.#%d\n",
-                                               dev->name, entry);
-                                       break;
-                               }
-                               np->rx_skbuff[entry] = skb;
-                               np->rx_ring[entry].fraginfo =
-                                   cpu_to_le64 (pci_map_single
-                                        (np->pdev, skb->data, np->rx_buf_sz,
-                                         PCI_DMA_FROMDEVICE));
-                       }
-                       np->rx_ring[entry].fraginfo |=
-                           cpu_to_le64((u64)np->rx_buf_sz << 48);
-                       np->rx_ring[entry].status = 0;
-               } /* end for */
-       } /* end if */
-       spin_unlock_irqrestore (&np->rx_lock, flags);
-       np->timer.expires = jiffies + next_tick;
-       add_timer(&np->timer);
-}
-
-static void
-rio_tx_timeout (struct net_device *dev)
-{
-       long ioaddr = dev->base_addr;
-
-       printk (KERN_INFO "%s: Tx timed out (%4.4x), is buffer full?\n",
-               dev->name, readl (ioaddr + TxStatus));
-       rio_free_tx(dev, 0);
-       dev->if_port = 0;
-       dev->trans_start = jiffies; /* prevent tx timeout */
-}
-
- /* allocate and initialize Tx and Rx descriptors */
-static void
-alloc_list (struct net_device *dev)
-{
-       struct netdev_private *np = netdev_priv(dev);
-       int i;
-
-       np->cur_rx = np->cur_tx = 0;
-       np->old_rx = np->old_tx = 0;
-       np->rx_buf_sz = (dev->mtu <= 1500 ? PACKET_SIZE : dev->mtu + 32);
-
-       /* Initialize Tx descriptors, TFDListPtr leaves in start_xmit(). */
-       for (i = 0; i < TX_RING_SIZE; i++) {
-               np->tx_skbuff[i] = NULL;
-               np->tx_ring[i].status = cpu_to_le64 (TFDDone);
-               np->tx_ring[i].next_desc = cpu_to_le64 (np->tx_ring_dma +
-                                             ((i+1)%TX_RING_SIZE) *
-                                             sizeof (struct netdev_desc));
-       }
-
-       /* Initialize Rx descriptors */
-       for (i = 0; i < RX_RING_SIZE; i++) {
-               np->rx_ring[i].next_desc = cpu_to_le64 (np->rx_ring_dma +
-                                               ((i + 1) % RX_RING_SIZE) *
-                                               sizeof (struct netdev_desc));
-               np->rx_ring[i].status = 0;
-               np->rx_ring[i].fraginfo = 0;
-               np->rx_skbuff[i] = NULL;
-       }
-
-       /* Allocate the rx buffers */
-       for (i = 0; i < RX_RING_SIZE; i++) {
-               /* Allocated fixed size of skbuff */
-               struct sk_buff *skb;
-
-               skb = netdev_alloc_skb_ip_align(dev, np->rx_buf_sz);
-               np->rx_skbuff[i] = skb;
-               if (skb == NULL) {
-                       printk (KERN_ERR
-                               "%s: alloc_list: allocate Rx buffer error! ",
-                               dev->name);
-                       break;
-               }
-               /* Rubicon now supports 40 bits of addressing space. */
-               np->rx_ring[i].fraginfo =
-                   cpu_to_le64 ( pci_map_single (
-                                 np->pdev, skb->data, np->rx_buf_sz,
-                                 PCI_DMA_FROMDEVICE));
-               np->rx_ring[i].fraginfo |= cpu_to_le64((u64)np->rx_buf_sz << 48);
-       }
-
-       /* Set RFDListPtr */
-       writel (np->rx_ring_dma, dev->base_addr + RFDListPtr0);
-       writel (0, dev->base_addr + RFDListPtr1);
-}
-
-static netdev_tx_t
-start_xmit (struct sk_buff *skb, struct net_device *dev)
-{
-       struct netdev_private *np = netdev_priv(dev);
-       struct netdev_desc *txdesc;
-       unsigned entry;
-       u32 ioaddr;
-       u64 tfc_vlan_tag = 0;
-
-       if (np->link_status == 0) {     /* Link Down */
-               dev_kfree_skb(skb);
-               return NETDEV_TX_OK;
-       }
-       ioaddr = dev->base_addr;
-       entry = np->cur_tx % TX_RING_SIZE;
-       np->tx_skbuff[entry] = skb;
-       txdesc = &np->tx_ring[entry];
-
-#if 0
-       if (skb->ip_summed == CHECKSUM_PARTIAL) {
-               txdesc->status |=
-                   cpu_to_le64 (TCPChecksumEnable | UDPChecksumEnable |
-                                IPChecksumEnable);
-       }
-#endif
-       if (np->vlan) {
-               tfc_vlan_tag = VLANTagInsert |
-                   ((u64)np->vlan << 32) |
-                   ((u64)skb->priority << 45);
-       }
-       txdesc->fraginfo = cpu_to_le64 (pci_map_single (np->pdev, skb->data,
-                                                       skb->len,
-                                                       PCI_DMA_TODEVICE));
-       txdesc->fraginfo |= cpu_to_le64((u64)skb->len << 48);
-
-       /* DL2K bug: DMA fails to get next descriptor ptr in 10Mbps mode
-        * Work around: Always use 1 descriptor in 10Mbps mode */
-       if (entry % np->tx_coalesce == 0 || np->speed == 10)
-               txdesc->status = cpu_to_le64 (entry | tfc_vlan_tag |
-                                             WordAlignDisable |
-                                             TxDMAIndicate |
-                                             (1 << FragCountShift));
-       else
-               txdesc->status = cpu_to_le64 (entry | tfc_vlan_tag |
-                                             WordAlignDisable |
-                                             (1 << FragCountShift));
-
-       /* TxDMAPollNow */
-       writel (readl (ioaddr + DMACtrl) | 0x00001000, ioaddr + DMACtrl);
-       /* Schedule ISR */
-       writel(10000, ioaddr + CountDown);
-       np->cur_tx = (np->cur_tx + 1) % TX_RING_SIZE;
-       if ((np->cur_tx - np->old_tx + TX_RING_SIZE) % TX_RING_SIZE
-                       < TX_QUEUE_LEN - 1 && np->speed != 10) {
-               /* do nothing */
-       } else if (!netif_queue_stopped(dev)) {
-               netif_stop_queue (dev);
-       }
-
-       /* The first TFDListPtr */
-       if (readl (dev->base_addr + TFDListPtr0) == 0) {
-               writel (np->tx_ring_dma + entry * sizeof (struct netdev_desc),
-                       dev->base_addr + TFDListPtr0);
-               writel (0, dev->base_addr + TFDListPtr1);
-       }
-
-       return NETDEV_TX_OK;
-}
-
-static irqreturn_t
-rio_interrupt (int irq, void *dev_instance)
-{
-       struct net_device *dev = dev_instance;
-       struct netdev_private *np;
-       unsigned int_status;
-       long ioaddr;
-       int cnt = max_intrloop;
-       int handled = 0;
-
-       ioaddr = dev->base_addr;
-       np = netdev_priv(dev);
-       while (1) {
-               int_status = readw (ioaddr + IntStatus);
-               writew (int_status, ioaddr + IntStatus);
-               int_status &= DEFAULT_INTR;
-               if (int_status == 0 || --cnt < 0)
-                       break;
-               handled = 1;
-               /* Processing received packets */
-               if (int_status & RxDMAComplete)
-                       receive_packet (dev);
-               /* TxDMAComplete interrupt */
-               if ((int_status & (TxDMAComplete|IntRequested))) {
-                       int tx_status;
-                       tx_status = readl (ioaddr + TxStatus);
-                       if (tx_status & 0x01)
-                               tx_error (dev, tx_status);
-                       /* Free used tx skbuffs */
-                       rio_free_tx (dev, 1);
-               }
-
-               /* Handle uncommon events */
-               if (int_status &
-                   (HostError | LinkEvent | UpdateStats))
-                       rio_error (dev, int_status);
-       }
-       if (np->cur_tx != np->old_tx)
-               writel (100, ioaddr + CountDown);
-       return IRQ_RETVAL(handled);
-}
-
-static inline dma_addr_t desc_to_dma(struct netdev_desc *desc)
-{
-       return le64_to_cpu(desc->fraginfo) & DMA_BIT_MASK(48);
-}
-
-static void
-rio_free_tx (struct net_device *dev, int irq)
-{
-       struct netdev_private *np = netdev_priv(dev);
-       int entry = np->old_tx % TX_RING_SIZE;
-       int tx_use = 0;
-       unsigned long flag = 0;
-
-       if (irq)
-               spin_lock(&np->tx_lock);
-       else
-               spin_lock_irqsave(&np->tx_lock, flag);
-
-       /* Free used tx skbuffs */
-       while (entry != np->cur_tx) {
-               struct sk_buff *skb;
-
-               if (!(np->tx_ring[entry].status & cpu_to_le64(TFDDone)))
-                       break;
-               skb = np->tx_skbuff[entry];
-               pci_unmap_single (np->pdev,
-                                 desc_to_dma(&np->tx_ring[entry]),
-                                 skb->len, PCI_DMA_TODEVICE);
-               if (irq)
-                       dev_kfree_skb_irq (skb);
-               else
-                       dev_kfree_skb (skb);
-
-               np->tx_skbuff[entry] = NULL;
-               entry = (entry + 1) % TX_RING_SIZE;
-               tx_use++;
-       }
-       if (irq)
-               spin_unlock(&np->tx_lock);
-       else
-               spin_unlock_irqrestore(&np->tx_lock, flag);
-       np->old_tx = entry;
-
-       /* If the ring is no longer full, clear tx_full and
-          call netif_wake_queue() */
-
-       if (netif_queue_stopped(dev) &&
-           ((np->cur_tx - np->old_tx + TX_RING_SIZE) % TX_RING_SIZE
-           < TX_QUEUE_LEN - 1 || np->speed == 10)) {
-               netif_wake_queue (dev);
-       }
-}
-
-static void
-tx_error (struct net_device *dev, int tx_status)
-{
-       struct netdev_private *np;
-       long ioaddr = dev->base_addr;
-       int frame_id;
-       int i;
-
-       np = netdev_priv(dev);
-
-       frame_id = (tx_status & 0xffff0000);
-       printk (KERN_ERR "%s: Transmit error, TxStatus %4.4x, FrameId %d.\n",
-               dev->name, tx_status, frame_id);
-       np->stats.tx_errors++;
-       /* Ttransmit Underrun */
-       if (tx_status & 0x10) {
-               np->stats.tx_fifo_errors++;
-               writew (readw (ioaddr + TxStartThresh) + 0x10,
-                       ioaddr + TxStartThresh);
-               /* Transmit Underrun need to set TxReset, DMARest, FIFOReset */
-               writew (TxReset | DMAReset | FIFOReset | NetworkReset,
-                       ioaddr + ASICCtrl + 2);
-               /* Wait for ResetBusy bit clear */
-               for (i = 50; i > 0; i--) {
-                       if ((readw (ioaddr + ASICCtrl + 2) & ResetBusy) == 0)
-                               break;
-                       mdelay (1);
-               }
-               rio_free_tx (dev, 1);
-               /* Reset TFDListPtr */
-               writel (np->tx_ring_dma +
-                       np->old_tx * sizeof (struct netdev_desc),
-                       dev->base_addr + TFDListPtr0);
-               writel (0, dev->base_addr + TFDListPtr1);
-
-               /* Let TxStartThresh stay default value */
-       }
-       /* Late Collision */
-       if (tx_status & 0x04) {
-               np->stats.tx_fifo_errors++;
-               /* TxReset and clear FIFO */
-               writew (TxReset | FIFOReset, ioaddr + ASICCtrl + 2);
-               /* Wait reset done */
-               for (i = 50; i > 0; i--) {
-                       if ((readw (ioaddr + ASICCtrl + 2) & ResetBusy) == 0)
-                               break;
-                       mdelay (1);
-               }
-               /* Let TxStartThresh stay default value */
-       }
-       /* Maximum Collisions */
-#ifdef ETHER_STATS
-       if (tx_status & 0x08)
-               np->stats.collisions16++;
-#else
-       if (tx_status & 0x08)
-               np->stats.collisions++;
-#endif
-       /* Restart the Tx */
-       writel (readw (dev->base_addr + MACCtrl) | TxEnable, ioaddr + MACCtrl);
-}
-
-static int
-receive_packet (struct net_device *dev)
-{
-       struct netdev_private *np = netdev_priv(dev);
-       int entry = np->cur_rx % RX_RING_SIZE;
-       int cnt = 30;
-
-       /* If RFDDone, FrameStart and FrameEnd set, there is a new packet in. */
-       while (1) {
-               struct netdev_desc *desc = &np->rx_ring[entry];
-               int pkt_len;
-               u64 frame_status;
-
-               if (!(desc->status & cpu_to_le64(RFDDone)) ||
-                   !(desc->status & cpu_to_le64(FrameStart)) ||
-                   !(desc->status & cpu_to_le64(FrameEnd)))
-                       break;
-
-               /* Chip omits the CRC. */
-               frame_status = le64_to_cpu(desc->status);
-               pkt_len = frame_status & 0xffff;
-               if (--cnt < 0)
-                       break;
-               /* Update rx error statistics, drop packet. */
-               if (frame_status & RFS_Errors) {
-                       np->stats.rx_errors++;
-                       if (frame_status & (RxRuntFrame | RxLengthError))
-                               np->stats.rx_length_errors++;
-                       if (frame_status & RxFCSError)
-                               np->stats.rx_crc_errors++;
-                       if (frame_status & RxAlignmentError && np->speed != 1000)
-                               np->stats.rx_frame_errors++;
-                       if (frame_status & RxFIFOOverrun)
-                               np->stats.rx_fifo_errors++;
-               } else {
-                       struct sk_buff *skb;
-
-                       /* Small skbuffs for short packets */
-                       if (pkt_len > copy_thresh) {
-                               pci_unmap_single (np->pdev,
-                                                 desc_to_dma(desc),
-                                                 np->rx_buf_sz,
-                                                 PCI_DMA_FROMDEVICE);
-                               skb_put (skb = np->rx_skbuff[entry], pkt_len);
-                               np->rx_skbuff[entry] = NULL;
-                       } else if ((skb = netdev_alloc_skb_ip_align(dev, pkt_len))) {
-                               pci_dma_sync_single_for_cpu(np->pdev,
-                                                           desc_to_dma(desc),
-                                                           np->rx_buf_sz,
-                                                           PCI_DMA_FROMDEVICE);
-                               skb_copy_to_linear_data (skb,
-                                                 np->rx_skbuff[entry]->data,
-                                                 pkt_len);
-                               skb_put (skb, pkt_len);
-                               pci_dma_sync_single_for_device(np->pdev,
-                                                              desc_to_dma(desc),
-                                                              np->rx_buf_sz,
-                                                              PCI_DMA_FROMDEVICE);
-                       }
-                       skb->protocol = eth_type_trans (skb, dev);
-#if 0
-                       /* Checksum done by hw, but csum value unavailable. */
-                       if (np->pdev->pci_rev_id >= 0x0c &&
-                               !(frame_status & (TCPError | UDPError | IPError))) {
-                               skb->ip_summed = CHECKSUM_UNNECESSARY;
-                       }
-#endif
-                       netif_rx (skb);
-               }
-               entry = (entry + 1) % RX_RING_SIZE;
-       }
-       spin_lock(&np->rx_lock);
-       np->cur_rx = entry;
-       /* Re-allocate skbuffs to fill the descriptor ring */
-       entry = np->old_rx;
-       while (entry != np->cur_rx) {
-               struct sk_buff *skb;
-               /* Dropped packets don't need to re-allocate */
-               if (np->rx_skbuff[entry] == NULL) {
-                       skb = netdev_alloc_skb_ip_align(dev, np->rx_buf_sz);
-                       if (skb == NULL) {
-                               np->rx_ring[entry].fraginfo = 0;
-                               printk (KERN_INFO
-                                       "%s: receive_packet: "
-                                       "Unable to re-allocate Rx skbuff.#%d\n",
-                                       dev->name, entry);
-                               break;
-                       }
-                       np->rx_skbuff[entry] = skb;
-                       np->rx_ring[entry].fraginfo =
-                           cpu_to_le64 (pci_map_single
-                                        (np->pdev, skb->data, np->rx_buf_sz,
-                                         PCI_DMA_FROMDEVICE));
-               }
-               np->rx_ring[entry].fraginfo |=
-                   cpu_to_le64((u64)np->rx_buf_sz << 48);
-               np->rx_ring[entry].status = 0;
-               entry = (entry + 1) % RX_RING_SIZE;
-       }
-       np->old_rx = entry;
-       spin_unlock(&np->rx_lock);
-       return 0;
-}
-
-static void
-rio_error (struct net_device *dev, int int_status)
-{
-       long ioaddr = dev->base_addr;
-       struct netdev_private *np = netdev_priv(dev);
-       u16 macctrl;
-
-       /* Link change event */
-       if (int_status & LinkEvent) {
-               if (mii_wait_link (dev, 10) == 0) {
-                       printk (KERN_INFO "%s: Link up\n", dev->name);
-                       if (np->phy_media)
-                               mii_get_media_pcs (dev);
-                       else
-                               mii_get_media (dev);
-                       if (np->speed == 1000)
-                               np->tx_coalesce = tx_coalesce;
-                       else
-                               np->tx_coalesce = 1;
-                       macctrl = 0;
-                       macctrl |= (np->vlan) ? AutoVLANuntagging : 0;
-                       macctrl |= (np->full_duplex) ? DuplexSelect : 0;
-                       macctrl |= (np->tx_flow) ?
-                               TxFlowControlEnable : 0;
-                       macctrl |= (np->rx_flow) ?
-                               RxFlowControlEnable : 0;
-                       writew(macctrl, ioaddr + MACCtrl);
-                       np->link_status = 1;
-                       netif_carrier_on(dev);
-               } else {
-                       printk (KERN_INFO "%s: Link off\n", dev->name);
-                       np->link_status = 0;
-                       netif_carrier_off(dev);
-               }
-       }
-
-       /* UpdateStats statistics registers */
-       if (int_status & UpdateStats) {
-               get_stats (dev);
-       }
-
-       /* PCI Error, a catastronphic error related to the bus interface
-          occurs, set GlobalReset and HostReset to reset. */
-       if (int_status & HostError) {
-               printk (KERN_ERR "%s: HostError! IntStatus %4.4x.\n",
-                       dev->name, int_status);
-               writew (GlobalReset | HostReset, ioaddr + ASICCtrl + 2);
-               mdelay (500);
-       }
-}
-
-static struct net_device_stats *
-get_stats (struct net_device *dev)
-{
-       long ioaddr = dev->base_addr;
-       struct netdev_private *np = netdev_priv(dev);
-#ifdef MEM_MAPPING
-       int i;
-#endif
-       unsigned int stat_reg;
-
-       /* All statistics registers need to be acknowledged,
-          else statistic overflow could cause problems */
-
-       np->stats.rx_packets += readl (ioaddr + FramesRcvOk);
-       np->stats.tx_packets += readl (ioaddr + FramesXmtOk);
-       np->stats.rx_bytes += readl (ioaddr + OctetRcvOk);
-       np->stats.tx_bytes += readl (ioaddr + OctetXmtOk);
-
-       np->stats.multicast = readl (ioaddr + McstFramesRcvdOk);
-       np->stats.collisions += readl (ioaddr + SingleColFrames)
-                            +  readl (ioaddr + MultiColFrames);
-
-       /* detailed tx errors */
-       stat_reg = readw (ioaddr + FramesAbortXSColls);
-       np->stats.tx_aborted_errors += stat_reg;
-       np->stats.tx_errors += stat_reg;
-
-       stat_reg = readw (ioaddr + CarrierSenseErrors);
-       np->stats.tx_carrier_errors += stat_reg;
-       np->stats.tx_errors += stat_reg;
-
-       /* Clear all other statistic register. */
-       readl (ioaddr + McstOctetXmtOk);
-       readw (ioaddr + BcstFramesXmtdOk);
-       readl (ioaddr + McstFramesXmtdOk);
-       readw (ioaddr + BcstFramesRcvdOk);
-       readw (ioaddr + MacControlFramesRcvd);
-       readw (ioaddr + FrameTooLongErrors);
-       readw (ioaddr + InRangeLengthErrors);
-       readw (ioaddr + FramesCheckSeqErrors);
-       readw (ioaddr + FramesLostRxErrors);
-       readl (ioaddr + McstOctetXmtOk);
-       readl (ioaddr + BcstOctetXmtOk);
-       readl (ioaddr + McstFramesXmtdOk);
-       readl (ioaddr + FramesWDeferredXmt);
-       readl (ioaddr + LateCollisions);
-       readw (ioaddr + BcstFramesXmtdOk);
-       readw (ioaddr + MacControlFramesXmtd);
-       readw (ioaddr + FramesWEXDeferal);
-
-#ifdef MEM_MAPPING
-       for (i = 0x100; i <= 0x150; i += 4)
-               readl (ioaddr + i);
-#endif
-       readw (ioaddr + TxJumboFrames);
-       readw (ioaddr + RxJumboFrames);
-       readw (ioaddr + TCPCheckSumErrors);
-       readw (ioaddr + UDPCheckSumErrors);
-       readw (ioaddr + IPCheckSumErrors);
-       return &np->stats;
-}
-
-static int
-clear_stats (struct net_device *dev)
-{
-       long ioaddr = dev->base_addr;
-#ifdef MEM_MAPPING
-       int i;
-#endif
-
-       /* All statistics registers need to be acknowledged,
-          else statistic overflow could cause problems */
-       readl (ioaddr + FramesRcvOk);
-       readl (ioaddr + FramesXmtOk);
-       readl (ioaddr + OctetRcvOk);
-       readl (ioaddr + OctetXmtOk);
-
-       readl (ioaddr + McstFramesRcvdOk);
-       readl (ioaddr + SingleColFrames);
-       readl (ioaddr + MultiColFrames);
-       readl (ioaddr + LateCollisions);
-       /* detailed rx errors */
-       readw (ioaddr + FrameTooLongErrors);
-       readw (ioaddr + InRangeLengthErrors);
-       readw (ioaddr + FramesCheckSeqErrors);
-       readw (ioaddr + FramesLostRxErrors);
-
-       /* detailed tx errors */
-       readw (ioaddr + FramesAbortXSColls);
-       readw (ioaddr + CarrierSenseErrors);
-
-       /* Clear all other statistic register. */
-       readl (ioaddr + McstOctetXmtOk);
-       readw (ioaddr + BcstFramesXmtdOk);
-       readl (ioaddr + McstFramesXmtdOk);
-       readw (ioaddr + BcstFramesRcvdOk);
-       readw (ioaddr + MacControlFramesRcvd);
-       readl (ioaddr + McstOctetXmtOk);
-       readl (ioaddr + BcstOctetXmtOk);
-       readl (ioaddr + McstFramesXmtdOk);
-       readl (ioaddr + FramesWDeferredXmt);
-       readw (ioaddr + BcstFramesXmtdOk);
-       readw (ioaddr + MacControlFramesXmtd);
-       readw (ioaddr + FramesWEXDeferal);
-#ifdef MEM_MAPPING
-       for (i = 0x100; i <= 0x150; i += 4)
-               readl (ioaddr + i);
-#endif
-       readw (ioaddr + TxJumboFrames);
-       readw (ioaddr + RxJumboFrames);
-       readw (ioaddr + TCPCheckSumErrors);
-       readw (ioaddr + UDPCheckSumErrors);
-       readw (ioaddr + IPCheckSumErrors);
-       return 0;
-}
-
-
-static int
-change_mtu (struct net_device *dev, int new_mtu)
-{
-       struct netdev_private *np = netdev_priv(dev);
-       int max = (np->jumbo) ? MAX_JUMBO : 1536;
-
-       if ((new_mtu < 68) || (new_mtu > max)) {
-               return -EINVAL;
-       }
-
-       dev->mtu = new_mtu;
-
-       return 0;
-}
-
-static void
-set_multicast (struct net_device *dev)
-{
-       long ioaddr = dev->base_addr;
-       u32 hash_table[2];
-       u16 rx_mode = 0;
-       struct netdev_private *np = netdev_priv(dev);
-
-       hash_table[0] = hash_table[1] = 0;
-       /* RxFlowcontrol DA: 01-80-C2-00-00-01. Hash index=0x39 */
-       hash_table[1] |= 0x02000000;
-       if (dev->flags & IFF_PROMISC) {
-               /* Receive all frames promiscuously. */
-               rx_mode = ReceiveAllFrames;
-       } else if ((dev->flags & IFF_ALLMULTI) ||
-                       (netdev_mc_count(dev) > multicast_filter_limit)) {
-               /* Receive broadcast and multicast frames */
-               rx_mode = ReceiveBroadcast | ReceiveMulticast | ReceiveUnicast;
-       } else if (!netdev_mc_empty(dev)) {
-               struct netdev_hw_addr *ha;
-               /* Receive broadcast frames and multicast frames filtering
-                  by Hashtable */
-               rx_mode =
-                   ReceiveBroadcast | ReceiveMulticastHash | ReceiveUnicast;
-               netdev_for_each_mc_addr(ha, dev) {
-                       int bit, index = 0;
-                       int crc = ether_crc_le(ETH_ALEN, ha->addr);
-                       /* The inverted high significant 6 bits of CRC are
-                          used as an index to hashtable */
-                       for (bit = 0; bit < 6; bit++)
-                               if (crc & (1 << (31 - bit)))
-                                       index |= (1 << bit);
-                       hash_table[index / 32] |= (1 << (index % 32));
-               }
-       } else {
-               rx_mode = ReceiveBroadcast | ReceiveUnicast;
-       }
-       if (np->vlan) {
-               /* ReceiveVLANMatch field in ReceiveMode */
-               rx_mode |= ReceiveVLANMatch;
-       }
-
-       writel (hash_table[0], ioaddr + HashTable0);
-       writel (hash_table[1], ioaddr + HashTable1);
-       writew (rx_mode, ioaddr + ReceiveMode);
-}
-
-static void rio_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
-{
-       struct netdev_private *np = netdev_priv(dev);
-       strcpy(info->driver, "dl2k");
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->bus_info, pci_name(np->pdev));
-}
-
-static int rio_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
-{
-       struct netdev_private *np = netdev_priv(dev);
-       if (np->phy_media) {
-               /* fiber device */
-               cmd->supported = SUPPORTED_Autoneg | SUPPORTED_FIBRE;
-               cmd->advertising= ADVERTISED_Autoneg | ADVERTISED_FIBRE;
-               cmd->port = PORT_FIBRE;
-               cmd->transceiver = XCVR_INTERNAL;
-       } else {
-               /* copper device */
-               cmd->supported = SUPPORTED_10baseT_Half |
-                       SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half
-                       | SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Full |
-                       SUPPORTED_Autoneg | SUPPORTED_MII;
-               cmd->advertising = ADVERTISED_10baseT_Half |
-                       ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Half |
-                       ADVERTISED_100baseT_Full | ADVERTISED_1000baseT_Full|
-                       ADVERTISED_Autoneg | ADVERTISED_MII;
-               cmd->port = PORT_MII;
-               cmd->transceiver = XCVR_INTERNAL;
-       }
-       if ( np->link_status ) {
-               ethtool_cmd_speed_set(cmd, np->speed);
-               cmd->duplex = np->full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
-       } else {
-               ethtool_cmd_speed_set(cmd, -1);
-               cmd->duplex = -1;
-       }
-       if ( np->an_enable)
-               cmd->autoneg = AUTONEG_ENABLE;
-       else
-               cmd->autoneg = AUTONEG_DISABLE;
-
-       cmd->phy_address = np->phy_addr;
-       return 0;
-}
-
-static int rio_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
-{
-       struct netdev_private *np = netdev_priv(dev);
-       netif_carrier_off(dev);
-       if (cmd->autoneg == AUTONEG_ENABLE) {
-               if (np->an_enable)
-                       return 0;
-               else {
-                       np->an_enable = 1;
-                       mii_set_media(dev);
-                       return 0;
-               }
-       } else {
-               np->an_enable = 0;
-               if (np->speed == 1000) {
-                       ethtool_cmd_speed_set(cmd, SPEED_100);
-                       cmd->duplex = DUPLEX_FULL;
-                       printk("Warning!! Can't disable Auto negotiation in 1000Mbps, change to Manual 100Mbps, Full duplex.\n");
-               }
-               switch (ethtool_cmd_speed(cmd)) {
-               case SPEED_10:
-                       np->speed = 10;
-                       np->full_duplex = (cmd->duplex == DUPLEX_FULL);
-                       break;
-               case SPEED_100:
-                       np->speed = 100;
-                       np->full_duplex = (cmd->duplex == DUPLEX_FULL);
-                       break;
-               case SPEED_1000: /* not supported */
-               default:
-                       return -EINVAL;
-               }
-               mii_set_media(dev);
-       }
-       return 0;
-}
-
-static u32 rio_get_link(struct net_device *dev)
-{
-       struct netdev_private *np = netdev_priv(dev);
-       return np->link_status;
-}
-
-static const struct ethtool_ops ethtool_ops = {
-       .get_drvinfo = rio_get_drvinfo,
-       .get_settings = rio_get_settings,
-       .set_settings = rio_set_settings,
-       .get_link = rio_get_link,
-};
-
-static int
-rio_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
-{
-       int phy_addr;
-       struct netdev_private *np = netdev_priv(dev);
-       struct mii_data *miidata = (struct mii_data *) &rq->ifr_ifru;
-
-       struct netdev_desc *desc;
-       int i;
-
-       phy_addr = np->phy_addr;
-       switch (cmd) {
-       case SIOCDEVPRIVATE:
-               break;
-
-       case SIOCDEVPRIVATE + 1:
-               miidata->out_value = mii_read (dev, phy_addr, miidata->reg_num);
-               break;
-       case SIOCDEVPRIVATE + 2:
-               mii_write (dev, phy_addr, miidata->reg_num, miidata->in_value);
-               break;
-       case SIOCDEVPRIVATE + 3:
-               break;
-       case SIOCDEVPRIVATE + 4:
-               break;
-       case SIOCDEVPRIVATE + 5:
-               netif_stop_queue (dev);
-               break;
-       case SIOCDEVPRIVATE + 6:
-               netif_wake_queue (dev);
-               break;
-       case SIOCDEVPRIVATE + 7:
-               printk
-                   ("tx_full=%x cur_tx=%lx old_tx=%lx cur_rx=%lx old_rx=%lx\n",
-                    netif_queue_stopped(dev), np->cur_tx, np->old_tx, np->cur_rx,
-                    np->old_rx);
-               break;
-       case SIOCDEVPRIVATE + 8:
-               printk("TX ring:\n");
-               for (i = 0; i < TX_RING_SIZE; i++) {
-                       desc = &np->tx_ring[i];
-                       printk
-                           ("%02x:cur:%08x next:%08x status:%08x frag1:%08x frag0:%08x",
-                            i,
-                            (u32) (np->tx_ring_dma + i * sizeof (*desc)),
-                            (u32)le64_to_cpu(desc->next_desc),
-                            (u32)le64_to_cpu(desc->status),
-                            (u32)(le64_to_cpu(desc->fraginfo) >> 32),
-                            (u32)le64_to_cpu(desc->fraginfo));
-                       printk ("\n");
-               }
-               printk ("\n");
-               break;
-
-       default:
-               return -EOPNOTSUPP;
-       }
-       return 0;
-}
-
-#define EEP_READ 0x0200
-#define EEP_BUSY 0x8000
-/* Read the EEPROM word */
-/* We use I/O instruction to read/write eeprom to avoid fail on some machines */
-static int
-read_eeprom (long ioaddr, int eep_addr)
-{
-       int i = 1000;
-       outw (EEP_READ | (eep_addr & 0xff), ioaddr + EepromCtrl);
-       while (i-- > 0) {
-               if (!(inw (ioaddr + EepromCtrl) & EEP_BUSY)) {
-                       return inw (ioaddr + EepromData);
-               }
-       }
-       return 0;
-}
-
-enum phy_ctrl_bits {
-       MII_READ = 0x00, MII_CLK = 0x01, MII_DATA1 = 0x02, MII_WRITE = 0x04,
-       MII_DUPLEX = 0x08,
-};
-
-#define mii_delay() readb(ioaddr)
-static void
-mii_sendbit (struct net_device *dev, u32 data)
-{
-       long ioaddr = dev->base_addr + PhyCtrl;
-       data = (data) ? MII_DATA1 : 0;
-       data |= MII_WRITE;
-       data |= (readb (ioaddr) & 0xf8) | MII_WRITE;
-       writeb (data, ioaddr);
-       mii_delay ();
-       writeb (data | MII_CLK, ioaddr);
-       mii_delay ();
-}
-
-static int
-mii_getbit (struct net_device *dev)
-{
-       long ioaddr = dev->base_addr + PhyCtrl;
-       u8 data;
-
-       data = (readb (ioaddr) & 0xf8) | MII_READ;
-       writeb (data, ioaddr);
-       mii_delay ();
-       writeb (data | MII_CLK, ioaddr);
-       mii_delay ();
-       return ((readb (ioaddr) >> 1) & 1);
-}
-
-static void
-mii_send_bits (struct net_device *dev, u32 data, int len)
-{
-       int i;
-       for (i = len - 1; i >= 0; i--) {
-               mii_sendbit (dev, data & (1 << i));
-       }
-}
-
-static int
-mii_read (struct net_device *dev, int phy_addr, int reg_num)
-{
-       u32 cmd;
-       int i;
-       u32 retval = 0;
-
-       /* Preamble */
-       mii_send_bits (dev, 0xffffffff, 32);
-       /* ST(2), OP(2), ADDR(5), REG#(5), TA(2), Data(16) total 32 bits */
-       /* ST,OP = 0110'b for read operation */
-       cmd = (0x06 << 10 | phy_addr << 5 | reg_num);
-       mii_send_bits (dev, cmd, 14);
-       /* Turnaround */
-       if (mii_getbit (dev))
-               goto err_out;
-       /* Read data */
-       for (i = 0; i < 16; i++) {
-               retval |= mii_getbit (dev);
-               retval <<= 1;
-       }
-       /* End cycle */
-       mii_getbit (dev);
-       return (retval >> 1) & 0xffff;
-
-      err_out:
-       return 0;
-}
-static int
-mii_write (struct net_device *dev, int phy_addr, int reg_num, u16 data)
-{
-       u32 cmd;
-
-       /* Preamble */
-       mii_send_bits (dev, 0xffffffff, 32);
-       /* ST(2), OP(2), ADDR(5), REG#(5), TA(2), Data(16) total 32 bits */
-       /* ST,OP,AAAAA,RRRRR,TA = 0101xxxxxxxxxx10'b = 0x5002 for write */
-       cmd = (0x5002 << 16) | (phy_addr << 23) | (reg_num << 18) | data;
-       mii_send_bits (dev, cmd, 32);
-       /* End cycle */
-       mii_getbit (dev);
-       return 0;
-}
-static int
-mii_wait_link (struct net_device *dev, int wait)
-{
-       __u16 bmsr;
-       int phy_addr;
-       struct netdev_private *np;
-
-       np = netdev_priv(dev);
-       phy_addr = np->phy_addr;
-
-       do {
-               bmsr = mii_read (dev, phy_addr, MII_BMSR);
-               if (bmsr & MII_BMSR_LINK_STATUS)
-                       return 0;
-               mdelay (1);
-       } while (--wait > 0);
-       return -1;
-}
-static int
-mii_get_media (struct net_device *dev)
-{
-       __u16 negotiate;
-       __u16 bmsr;
-       __u16 mscr;
-       __u16 mssr;
-       int phy_addr;
-       struct netdev_private *np;
-
-       np = netdev_priv(dev);
-       phy_addr = np->phy_addr;
-
-       bmsr = mii_read (dev, phy_addr, MII_BMSR);
-       if (np->an_enable) {
-               if (!(bmsr & MII_BMSR_AN_COMPLETE)) {
-                       /* Auto-Negotiation not completed */
-                       return -1;
-               }
-               negotiate = mii_read (dev, phy_addr, MII_ANAR) &
-                       mii_read (dev, phy_addr, MII_ANLPAR);
-               mscr = mii_read (dev, phy_addr, MII_MSCR);
-               mssr = mii_read (dev, phy_addr, MII_MSSR);
-               if (mscr & MII_MSCR_1000BT_FD && mssr & MII_MSSR_LP_1000BT_FD) {
-                       np->speed = 1000;
-                       np->full_duplex = 1;
-                       printk (KERN_INFO "Auto 1000 Mbps, Full duplex\n");
-               } else if (mscr & MII_MSCR_1000BT_HD && mssr & MII_MSSR_LP_1000BT_HD) {
-                       np->speed = 1000;
-                       np->full_duplex = 0;
-                       printk (KERN_INFO "Auto 1000 Mbps, Half duplex\n");
-               } else if (negotiate & MII_ANAR_100BX_FD) {
-                       np->speed = 100;
-                       np->full_duplex = 1;
-                       printk (KERN_INFO "Auto 100 Mbps, Full duplex\n");
-               } else if (negotiate & MII_ANAR_100BX_HD) {
-                       np->speed = 100;
-                       np->full_duplex = 0;
-                       printk (KERN_INFO "Auto 100 Mbps, Half duplex\n");
-               } else if (negotiate & MII_ANAR_10BT_FD) {
-                       np->speed = 10;
-                       np->full_duplex = 1;
-                       printk (KERN_INFO "Auto 10 Mbps, Full duplex\n");
-               } else if (negotiate & MII_ANAR_10BT_HD) {
-                       np->speed = 10;
-                       np->full_duplex = 0;
-                       printk (KERN_INFO "Auto 10 Mbps, Half duplex\n");
-               }
-               if (negotiate & MII_ANAR_PAUSE) {
-                       np->tx_flow &= 1;
-                       np->rx_flow &= 1;
-               } else if (negotiate & MII_ANAR_ASYMMETRIC) {
-                       np->tx_flow = 0;
-                       np->rx_flow &= 1;
-               }
-               /* else tx_flow, rx_flow = user select  */
-       } else {
-               __u16 bmcr = mii_read (dev, phy_addr, MII_BMCR);
-               switch (bmcr & (MII_BMCR_SPEED_100 | MII_BMCR_SPEED_1000)) {
-               case MII_BMCR_SPEED_1000:
-                       printk (KERN_INFO "Operating at 1000 Mbps, ");
-                       break;
-               case MII_BMCR_SPEED_100:
-                       printk (KERN_INFO "Operating at 100 Mbps, ");
-                       break;
-               case 0:
-                       printk (KERN_INFO "Operating at 10 Mbps, ");
-               }
-               if (bmcr & MII_BMCR_DUPLEX_MODE) {
-                       printk (KERN_CONT "Full duplex\n");
-               } else {
-                       printk (KERN_CONT "Half duplex\n");
-               }
-       }
-       if (np->tx_flow)
-               printk(KERN_INFO "Enable Tx Flow Control\n");
-       else
-               printk(KERN_INFO "Disable Tx Flow Control\n");
-       if (np->rx_flow)
-               printk(KERN_INFO "Enable Rx Flow Control\n");
-       else
-               printk(KERN_INFO "Disable Rx Flow Control\n");
-
-       return 0;
-}
-
-static int
-mii_set_media (struct net_device *dev)
-{
-       __u16 pscr;
-       __u16 bmcr;
-       __u16 bmsr;
-       __u16 anar;
-       int phy_addr;
-       struct netdev_private *np;
-       np = netdev_priv(dev);
-       phy_addr = np->phy_addr;
-
-       /* Does user set speed? */
-       if (np->an_enable) {
-               /* Advertise capabilities */
-               bmsr = mii_read (dev, phy_addr, MII_BMSR);
-               anar = mii_read (dev, phy_addr, MII_ANAR) &
-                            ~MII_ANAR_100BX_FD &
-                            ~MII_ANAR_100BX_HD &
-                            ~MII_ANAR_100BT4 &
-                            ~MII_ANAR_10BT_FD &
-                            ~MII_ANAR_10BT_HD;
-               if (bmsr & MII_BMSR_100BX_FD)
-                       anar |= MII_ANAR_100BX_FD;
-               if (bmsr & MII_BMSR_100BX_HD)
-                       anar |= MII_ANAR_100BX_HD;
-               if (bmsr & MII_BMSR_100BT4)
-                       anar |= MII_ANAR_100BT4;
-               if (bmsr & MII_BMSR_10BT_FD)
-                       anar |= MII_ANAR_10BT_FD;
-               if (bmsr & MII_BMSR_10BT_HD)
-                       anar |= MII_ANAR_10BT_HD;
-               anar |= MII_ANAR_PAUSE | MII_ANAR_ASYMMETRIC;
-               mii_write (dev, phy_addr, MII_ANAR, anar);
-
-               /* Enable Auto crossover */
-               pscr = mii_read (dev, phy_addr, MII_PHY_SCR);
-               pscr |= 3 << 5; /* 11'b */
-               mii_write (dev, phy_addr, MII_PHY_SCR, pscr);
-
-               /* Soft reset PHY */
-               mii_write (dev, phy_addr, MII_BMCR, MII_BMCR_RESET);
-               bmcr = MII_BMCR_AN_ENABLE | MII_BMCR_RESTART_AN | MII_BMCR_RESET;
-               mii_write (dev, phy_addr, MII_BMCR, bmcr);
-               mdelay(1);
-       } else {
-               /* Force speed setting */
-               /* 1) Disable Auto crossover */
-               pscr = mii_read (dev, phy_addr, MII_PHY_SCR);
-               pscr &= ~(3 << 5);
-               mii_write (dev, phy_addr, MII_PHY_SCR, pscr);
-
-               /* 2) PHY Reset */
-               bmcr = mii_read (dev, phy_addr, MII_BMCR);
-               bmcr |= MII_BMCR_RESET;
-               mii_write (dev, phy_addr, MII_BMCR, bmcr);
-
-               /* 3) Power Down */
-               bmcr = 0x1940;  /* must be 0x1940 */
-               mii_write (dev, phy_addr, MII_BMCR, bmcr);
-               mdelay (100);   /* wait a certain time */
-
-               /* 4) Advertise nothing */
-               mii_write (dev, phy_addr, MII_ANAR, 0);
-
-               /* 5) Set media and Power Up */
-               bmcr = MII_BMCR_POWER_DOWN;
-               if (np->speed == 100) {
-                       bmcr |= MII_BMCR_SPEED_100;
-                       printk (KERN_INFO "Manual 100 Mbps, ");
-               } else if (np->speed == 10) {
-                       printk (KERN_INFO "Manual 10 Mbps, ");
-               }
-               if (np->full_duplex) {
-                       bmcr |= MII_BMCR_DUPLEX_MODE;
-                       printk (KERN_CONT "Full duplex\n");
-               } else {
-                       printk (KERN_CONT "Half duplex\n");
-               }
-#if 0
-               /* Set 1000BaseT Master/Slave setting */
-               mscr = mii_read (dev, phy_addr, MII_MSCR);
-               mscr |= MII_MSCR_CFG_ENABLE;
-               mscr &= ~MII_MSCR_CFG_VALUE = 0;
-#endif
-               mii_write (dev, phy_addr, MII_BMCR, bmcr);
-               mdelay(10);
-       }
-       return 0;
-}
-
-static int
-mii_get_media_pcs (struct net_device *dev)
-{
-       __u16 negotiate;
-       __u16 bmsr;
-       int phy_addr;
-       struct netdev_private *np;
-
-       np = netdev_priv(dev);
-       phy_addr = np->phy_addr;
-
-       bmsr = mii_read (dev, phy_addr, PCS_BMSR);
-       if (np->an_enable) {
-               if (!(bmsr & MII_BMSR_AN_COMPLETE)) {
-                       /* Auto-Negotiation not completed */
-                       return -1;
-               }
-               negotiate = mii_read (dev, phy_addr, PCS_ANAR) &
-                       mii_read (dev, phy_addr, PCS_ANLPAR);
-               np->speed = 1000;
-               if (negotiate & PCS_ANAR_FULL_DUPLEX) {
-                       printk (KERN_INFO "Auto 1000 Mbps, Full duplex\n");
-                       np->full_duplex = 1;
-               } else {
-                       printk (KERN_INFO "Auto 1000 Mbps, half duplex\n");
-                       np->full_duplex = 0;
-               }
-               if (negotiate & PCS_ANAR_PAUSE) {
-                       np->tx_flow &= 1;
-                       np->rx_flow &= 1;
-               } else if (negotiate & PCS_ANAR_ASYMMETRIC) {
-                       np->tx_flow = 0;
-                       np->rx_flow &= 1;
-               }
-               /* else tx_flow, rx_flow = user select  */
-       } else {
-               __u16 bmcr = mii_read (dev, phy_addr, PCS_BMCR);
-               printk (KERN_INFO "Operating at 1000 Mbps, ");
-               if (bmcr & MII_BMCR_DUPLEX_MODE) {
-                       printk (KERN_CONT "Full duplex\n");
-               } else {
-                       printk (KERN_CONT "Half duplex\n");
-               }
-       }
-       if (np->tx_flow)
-               printk(KERN_INFO "Enable Tx Flow Control\n");
-       else
-               printk(KERN_INFO "Disable Tx Flow Control\n");
-       if (np->rx_flow)
-               printk(KERN_INFO "Enable Rx Flow Control\n");
-       else
-               printk(KERN_INFO "Disable Rx Flow Control\n");
-
-       return 0;
-}
-
-static int
-mii_set_media_pcs (struct net_device *dev)
-{
-       __u16 bmcr;
-       __u16 esr;
-       __u16 anar;
-       int phy_addr;
-       struct netdev_private *np;
-       np = netdev_priv(dev);
-       phy_addr = np->phy_addr;
-
-       /* Auto-Negotiation? */
-       if (np->an_enable) {
-               /* Advertise capabilities */
-               esr = mii_read (dev, phy_addr, PCS_ESR);
-               anar = mii_read (dev, phy_addr, MII_ANAR) &
-                       ~PCS_ANAR_HALF_DUPLEX &
-                       ~PCS_ANAR_FULL_DUPLEX;
-               if (esr & (MII_ESR_1000BT_HD | MII_ESR_1000BX_HD))
-                       anar |= PCS_ANAR_HALF_DUPLEX;
-               if (esr & (MII_ESR_1000BT_FD | MII_ESR_1000BX_FD))
-                       anar |= PCS_ANAR_FULL_DUPLEX;
-               anar |= PCS_ANAR_PAUSE | PCS_ANAR_ASYMMETRIC;
-               mii_write (dev, phy_addr, MII_ANAR, anar);
-
-               /* Soft reset PHY */
-               mii_write (dev, phy_addr, MII_BMCR, MII_BMCR_RESET);
-               bmcr = MII_BMCR_AN_ENABLE | MII_BMCR_RESTART_AN |
-                      MII_BMCR_RESET;
-               mii_write (dev, phy_addr, MII_BMCR, bmcr);
-               mdelay(1);
-       } else {
-               /* Force speed setting */
-               /* PHY Reset */
-               bmcr = MII_BMCR_RESET;
-               mii_write (dev, phy_addr, MII_BMCR, bmcr);
-               mdelay(10);
-               if (np->full_duplex) {
-                       bmcr = MII_BMCR_DUPLEX_MODE;
-                       printk (KERN_INFO "Manual full duplex\n");
-               } else {
-                       bmcr = 0;
-                       printk (KERN_INFO "Manual half duplex\n");
-               }
-               mii_write (dev, phy_addr, MII_BMCR, bmcr);
-               mdelay(10);
-
-               /*  Advertise nothing */
-               mii_write (dev, phy_addr, MII_ANAR, 0);
-       }
-       return 0;
-}
-
-
-static int
-rio_close (struct net_device *dev)
-{
-       long ioaddr = dev->base_addr;
-       struct netdev_private *np = netdev_priv(dev);
-       struct sk_buff *skb;
-       int i;
-
-       netif_stop_queue (dev);
-
-       /* Disable interrupts */
-       writew (0, ioaddr + IntEnable);
-
-       /* Stop Tx and Rx logics */
-       writel (TxDisable | RxDisable | StatsDisable, ioaddr + MACCtrl);
-
-       free_irq (dev->irq, dev);
-       del_timer_sync (&np->timer);
-
-       /* Free all the skbuffs in the queue. */
-       for (i = 0; i < RX_RING_SIZE; i++) {
-               skb = np->rx_skbuff[i];
-               if (skb) {
-                       pci_unmap_single(np->pdev,
-                                        desc_to_dma(&np->rx_ring[i]),
-                                        skb->len, PCI_DMA_FROMDEVICE);
-                       dev_kfree_skb (skb);
-                       np->rx_skbuff[i] = NULL;
-               }
-               np->rx_ring[i].status = 0;
-               np->rx_ring[i].fraginfo = 0;
-       }
-       for (i = 0; i < TX_RING_SIZE; i++) {
-               skb = np->tx_skbuff[i];
-               if (skb) {
-                       pci_unmap_single(np->pdev,
-                                        desc_to_dma(&np->tx_ring[i]),
-                                        skb->len, PCI_DMA_TODEVICE);
-                       dev_kfree_skb (skb);
-                       np->tx_skbuff[i] = NULL;
-               }
-       }
-
-       return 0;
-}
-
-static void __devexit
-rio_remove1 (struct pci_dev *pdev)
-{
-       struct net_device *dev = pci_get_drvdata (pdev);
-
-       if (dev) {
-               struct netdev_private *np = netdev_priv(dev);
-
-               unregister_netdev (dev);
-               pci_free_consistent (pdev, RX_TOTAL_SIZE, np->rx_ring,
-                                    np->rx_ring_dma);
-               pci_free_consistent (pdev, TX_TOTAL_SIZE, np->tx_ring,
-                                    np->tx_ring_dma);
-#ifdef MEM_MAPPING
-               iounmap ((char *) (dev->base_addr));
-#endif
-               free_netdev (dev);
-               pci_release_regions (pdev);
-               pci_disable_device (pdev);
-       }
-       pci_set_drvdata (pdev, NULL);
-}
-
-static struct pci_driver rio_driver = {
-       .name           = "dl2k",
-       .id_table       = rio_pci_tbl,
-       .probe          = rio_probe1,
-       .remove         = __devexit_p(rio_remove1),
-};
-
-static int __init
-rio_init (void)
-{
-       return pci_register_driver(&rio_driver);
-}
-
-static void __exit
-rio_exit (void)
-{
-       pci_unregister_driver (&rio_driver);
-}
-
-module_init (rio_init);
-module_exit (rio_exit);
-
-/*
-
-Compile command:
-
-gcc -D__KERNEL__ -DMODULE -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -c dl2k.c
-
-Read Documentation/networking/dl2k.txt for details.
-
-*/
-
diff --git a/drivers/net/dl2k.h b/drivers/net/dl2k.h
deleted file mode 100644 (file)
index 7caab3d..0000000
+++ /dev/null
@@ -1,554 +0,0 @@
-/*  D-Link DL2000-based Gigabit Ethernet Adapter Linux driver */
-/*
-    Copyright (c) 2001, 2002 by D-Link Corporation
-    Written by Edward Peng.<edward_peng@dlink.com.tw>
-    Created 03-May-2001, base on Linux' sundance.c.
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-*/
-
-#ifndef __DL2K_H__
-#define __DL2K_H__
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/init.h>
-#include <linux/crc32.h>
-#include <linux/ethtool.h>
-#include <linux/bitops.h>
-#include <asm/processor.h>     /* Processor type for cache alignment. */
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <linux/delay.h>
-#include <linux/spinlock.h>
-#include <linux/time.h>
-#define TX_RING_SIZE   256
-#define TX_QUEUE_LEN   (TX_RING_SIZE - 1) /* Limit ring entries actually used.*/
-#define RX_RING_SIZE   256
-#define TX_TOTAL_SIZE  TX_RING_SIZE*sizeof(struct netdev_desc)
-#define RX_TOTAL_SIZE  RX_RING_SIZE*sizeof(struct netdev_desc)
-
-/* This driver was written to use PCI memory space, however x86-oriented
-   hardware often uses I/O space accesses. */
-#ifndef MEM_MAPPING
-#undef readb
-#undef readw
-#undef readl
-#undef writeb
-#undef writew
-#undef writel
-#define readb inb
-#define readw inw
-#define readl inl
-#define writeb outb
-#define writew outw
-#define writel outl
-#endif
-
-/* Offsets to the device registers.
-   Unlike software-only systems, device drivers interact with complex hardware.
-   It's not useful to define symbolic names for every register bit in the
-   device.  The name can only partially document the semantics and make
-   the driver longer and more difficult to read.
-   In general, only the important configuration values or bits changed
-   multiple times should be defined symbolically.
-*/
-enum dl2x_offsets {
-       /* I/O register offsets */
-       DMACtrl = 0x00,
-       RxDMAStatus = 0x08,
-       TFDListPtr0 = 0x10,
-       TFDListPtr1 = 0x14,
-       TxDMABurstThresh = 0x18,
-       TxDMAUrgentThresh = 0x19,
-       TxDMAPollPeriod = 0x1a,
-       RFDListPtr0 = 0x1c,
-       RFDListPtr1 = 0x20,
-       RxDMABurstThresh = 0x24,
-       RxDMAUrgentThresh = 0x25,
-       RxDMAPollPeriod = 0x26,
-       RxDMAIntCtrl = 0x28,
-       DebugCtrl = 0x2c,
-       ASICCtrl = 0x30,
-       FifoCtrl = 0x38,
-       RxEarlyThresh = 0x3a,
-       FlowOffThresh = 0x3c,
-       FlowOnThresh = 0x3e,
-       TxStartThresh = 0x44,
-       EepromData = 0x48,
-       EepromCtrl = 0x4a,
-       ExpromAddr = 0x4c,
-       Exprodata = 0x50,
-       WakeEvent = 0x51,
-       CountDown = 0x54,
-       IntStatusAck = 0x5a,
-       IntEnable = 0x5c,
-       IntStatus = 0x5e,
-       TxStatus = 0x60,
-       MACCtrl = 0x6c,
-       VLANTag = 0x70,
-       PhyCtrl = 0x76,
-       StationAddr0 = 0x78,
-       StationAddr1 = 0x7a,
-       StationAddr2 = 0x7c,
-       VLANId = 0x80,
-       MaxFrameSize = 0x86,
-       ReceiveMode = 0x88,
-       HashTable0 = 0x8c,
-       HashTable1 = 0x90,
-       RmonStatMask = 0x98,
-       StatMask = 0x9c,
-       RxJumboFrames = 0xbc,
-       TCPCheckSumErrors = 0xc0,
-       IPCheckSumErrors = 0xc2,
-       UDPCheckSumErrors = 0xc4,
-       TxJumboFrames = 0xf4,
-       /* Ethernet MIB statistic register offsets */
-       OctetRcvOk = 0xa8,
-       McstOctetRcvOk = 0xac,
-       BcstOctetRcvOk = 0xb0,
-       FramesRcvOk = 0xb4,
-       McstFramesRcvdOk = 0xb8,
-       BcstFramesRcvdOk = 0xbe,
-       MacControlFramesRcvd = 0xc6,
-       FrameTooLongErrors = 0xc8,
-       InRangeLengthErrors = 0xca,
-       FramesCheckSeqErrors = 0xcc,
-       FramesLostRxErrors = 0xce,
-       OctetXmtOk = 0xd0,
-       McstOctetXmtOk = 0xd4,
-       BcstOctetXmtOk = 0xd8,
-       FramesXmtOk = 0xdc,
-       McstFramesXmtdOk = 0xe0,
-       FramesWDeferredXmt = 0xe4,
-       LateCollisions = 0xe8,
-       MultiColFrames = 0xec,
-       SingleColFrames = 0xf0,
-       BcstFramesXmtdOk = 0xf6,
-       CarrierSenseErrors = 0xf8,
-       MacControlFramesXmtd = 0xfa,
-       FramesAbortXSColls = 0xfc,
-       FramesWEXDeferal = 0xfe,
-       /* RMON statistic register offsets */
-       EtherStatsCollisions = 0x100,
-       EtherStatsOctetsTransmit = 0x104,
-       EtherStatsPktsTransmit = 0x108,
-       EtherStatsPkts64OctetTransmit = 0x10c,
-       EtherStats65to127OctetsTransmit = 0x110,
-       EtherStatsPkts128to255OctetsTransmit = 0x114,
-       EtherStatsPkts256to511OctetsTransmit = 0x118,
-       EtherStatsPkts512to1023OctetsTransmit = 0x11c,
-       EtherStatsPkts1024to1518OctetsTransmit = 0x120,
-       EtherStatsCRCAlignErrors = 0x124,
-       EtherStatsUndersizePkts = 0x128,
-       EtherStatsFragments = 0x12c,
-       EtherStatsJabbers = 0x130,
-       EtherStatsOctets = 0x134,
-       EtherStatsPkts = 0x138,
-       EtherStats64Octets = 0x13c,
-       EtherStatsPkts65to127Octets = 0x140,
-       EtherStatsPkts128to255Octets = 0x144,
-       EtherStatsPkts256to511Octets = 0x148,
-       EtherStatsPkts512to1023Octets = 0x14c,
-       EtherStatsPkts1024to1518Octets = 0x150,
-};
-
-/* Bits in the interrupt status/mask registers. */
-enum IntStatus_bits {
-       InterruptStatus = 0x0001,
-       HostError = 0x0002,
-       MACCtrlFrame = 0x0008,
-       TxComplete = 0x0004,
-       RxComplete = 0x0010,
-       RxEarly = 0x0020,
-       IntRequested = 0x0040,
-       UpdateStats = 0x0080,
-       LinkEvent = 0x0100,
-       TxDMAComplete = 0x0200,
-       RxDMAComplete = 0x0400,
-       RFDListEnd = 0x0800,
-       RxDMAPriority = 0x1000,
-};
-
-/* Bits in the ReceiveMode register. */
-enum ReceiveMode_bits {
-       ReceiveUnicast = 0x0001,
-       ReceiveMulticast = 0x0002,
-       ReceiveBroadcast = 0x0004,
-       ReceiveAllFrames = 0x0008,
-       ReceiveMulticastHash = 0x0010,
-       ReceiveIPMulticast = 0x0020,
-       ReceiveVLANMatch = 0x0100,
-       ReceiveVLANHash = 0x0200,
-};
-/* Bits in MACCtrl. */
-enum MACCtrl_bits {
-       DuplexSelect = 0x20,
-       TxFlowControlEnable = 0x80,
-       RxFlowControlEnable = 0x0100,
-       RcvFCS = 0x200,
-       AutoVLANtagging = 0x1000,
-       AutoVLANuntagging = 0x2000,
-       StatsEnable = 0x00200000,
-       StatsDisable = 0x00400000,
-       StatsEnabled = 0x00800000,
-       TxEnable = 0x01000000,
-       TxDisable = 0x02000000,
-       TxEnabled = 0x04000000,
-       RxEnable = 0x08000000,
-       RxDisable = 0x10000000,
-       RxEnabled = 0x20000000,
-};
-
-enum ASICCtrl_LoWord_bits {
-       PhyMedia = 0x0080,
-};
-
-enum ASICCtrl_HiWord_bits {
-       GlobalReset = 0x0001,
-       RxReset = 0x0002,
-       TxReset = 0x0004,
-       DMAReset = 0x0008,
-       FIFOReset = 0x0010,
-       NetworkReset = 0x0020,
-       HostReset = 0x0040,
-       ResetBusy = 0x0400,
-};
-
-/* Transmit Frame Control bits */
-enum TFC_bits {
-       DwordAlign = 0x00000000,
-       WordAlignDisable = 0x00030000,
-       WordAlign = 0x00020000,
-       TCPChecksumEnable = 0x00040000,
-       UDPChecksumEnable = 0x00080000,
-       IPChecksumEnable = 0x00100000,
-       FCSAppendDisable = 0x00200000,
-       TxIndicate = 0x00400000,
-       TxDMAIndicate = 0x00800000,
-       FragCountShift = 24,
-       VLANTagInsert = 0x0000000010000000,
-       TFDDone = 0x80000000,
-       VIDShift = 32,
-       UsePriorityShift = 48,
-};
-
-/* Receive Frames Status bits */
-enum RFS_bits {
-       RxFIFOOverrun = 0x00010000,
-       RxRuntFrame = 0x00020000,
-       RxAlignmentError = 0x00040000,
-       RxFCSError = 0x00080000,
-       RxOverSizedFrame = 0x00100000,
-       RxLengthError = 0x00200000,
-       VLANDetected = 0x00400000,
-       TCPDetected = 0x00800000,
-       TCPError = 0x01000000,
-       UDPDetected = 0x02000000,
-       UDPError = 0x04000000,
-       IPDetected = 0x08000000,
-       IPError = 0x10000000,
-       FrameStart = 0x20000000,
-       FrameEnd = 0x40000000,
-       RFDDone = 0x80000000,
-       TCIShift = 32,
-       RFS_Errors = 0x003f0000,
-};
-
-#define MII_RESET_TIME_OUT             10000
-/* MII register */
-enum _mii_reg {
-       MII_BMCR = 0,
-       MII_BMSR = 1,
-       MII_PHY_ID1 = 2,
-       MII_PHY_ID2 = 3,
-       MII_ANAR = 4,
-       MII_ANLPAR = 5,
-       MII_ANER = 6,
-       MII_ANNPT = 7,
-       MII_ANLPRNP = 8,
-       MII_MSCR = 9,
-       MII_MSSR = 10,
-       MII_ESR = 15,
-       MII_PHY_SCR = 16,
-};
-/* PCS register */
-enum _pcs_reg {
-       PCS_BMCR = 0,
-       PCS_BMSR = 1,
-       PCS_ANAR = 4,
-       PCS_ANLPAR = 5,
-       PCS_ANER = 6,
-       PCS_ANNPT = 7,
-       PCS_ANLPRNP = 8,
-       PCS_ESR = 15,
-};
-
-/* Basic Mode Control Register */
-enum _mii_bmcr {
-       MII_BMCR_RESET = 0x8000,
-       MII_BMCR_LOOP_BACK = 0x4000,
-       MII_BMCR_SPEED_LSB = 0x2000,
-       MII_BMCR_AN_ENABLE = 0x1000,
-       MII_BMCR_POWER_DOWN = 0x0800,
-       MII_BMCR_ISOLATE = 0x0400,
-       MII_BMCR_RESTART_AN = 0x0200,
-       MII_BMCR_DUPLEX_MODE = 0x0100,
-       MII_BMCR_COL_TEST = 0x0080,
-       MII_BMCR_SPEED_MSB = 0x0040,
-       MII_BMCR_SPEED_RESERVED = 0x003f,
-       MII_BMCR_SPEED_10 = 0,
-       MII_BMCR_SPEED_100 = MII_BMCR_SPEED_LSB,
-       MII_BMCR_SPEED_1000 = MII_BMCR_SPEED_MSB,
-};
-
-/* Basic Mode Status Register */
-enum _mii_bmsr {
-       MII_BMSR_100BT4 = 0x8000,
-       MII_BMSR_100BX_FD = 0x4000,
-       MII_BMSR_100BX_HD = 0x2000,
-       MII_BMSR_10BT_FD = 0x1000,
-       MII_BMSR_10BT_HD = 0x0800,
-       MII_BMSR_100BT2_FD = 0x0400,
-       MII_BMSR_100BT2_HD = 0x0200,
-       MII_BMSR_EXT_STATUS = 0x0100,
-       MII_BMSR_PREAMBLE_SUPP = 0x0040,
-       MII_BMSR_AN_COMPLETE = 0x0020,
-       MII_BMSR_REMOTE_FAULT = 0x0010,
-       MII_BMSR_AN_ABILITY = 0x0008,
-       MII_BMSR_LINK_STATUS = 0x0004,
-       MII_BMSR_JABBER_DETECT = 0x0002,
-       MII_BMSR_EXT_CAP = 0x0001,
-};
-
-/* ANAR */
-enum _mii_anar {
-       MII_ANAR_NEXT_PAGE = 0x8000,
-       MII_ANAR_REMOTE_FAULT = 0x4000,
-       MII_ANAR_ASYMMETRIC = 0x0800,
-       MII_ANAR_PAUSE = 0x0400,
-       MII_ANAR_100BT4 = 0x0200,
-       MII_ANAR_100BX_FD = 0x0100,
-       MII_ANAR_100BX_HD = 0x0080,
-       MII_ANAR_10BT_FD = 0x0020,
-       MII_ANAR_10BT_HD = 0x0010,
-       MII_ANAR_SELECTOR = 0x001f,
-       MII_IEEE8023_CSMACD = 0x0001,
-};
-
-/* ANLPAR */
-enum _mii_anlpar {
-       MII_ANLPAR_NEXT_PAGE = MII_ANAR_NEXT_PAGE,
-       MII_ANLPAR_REMOTE_FAULT = MII_ANAR_REMOTE_FAULT,
-       MII_ANLPAR_ASYMMETRIC = MII_ANAR_ASYMMETRIC,
-       MII_ANLPAR_PAUSE = MII_ANAR_PAUSE,
-       MII_ANLPAR_100BT4 = MII_ANAR_100BT4,
-       MII_ANLPAR_100BX_FD = MII_ANAR_100BX_FD,
-       MII_ANLPAR_100BX_HD = MII_ANAR_100BX_HD,
-       MII_ANLPAR_10BT_FD = MII_ANAR_10BT_FD,
-       MII_ANLPAR_10BT_HD = MII_ANAR_10BT_HD,
-       MII_ANLPAR_SELECTOR = MII_ANAR_SELECTOR,
-};
-
-/* Auto-Negotiation Expansion Register */
-enum _mii_aner {
-       MII_ANER_PAR_DETECT_FAULT = 0x0010,
-       MII_ANER_LP_NEXTPAGABLE = 0x0008,
-       MII_ANER_NETXTPAGABLE = 0x0004,
-       MII_ANER_PAGE_RECEIVED = 0x0002,
-       MII_ANER_LP_NEGOTIABLE = 0x0001,
-};
-
-/* MASTER-SLAVE Control Register */
-enum _mii_mscr {
-       MII_MSCR_TEST_MODE = 0xe000,
-       MII_MSCR_CFG_ENABLE = 0x1000,
-       MII_MSCR_CFG_VALUE = 0x0800,
-       MII_MSCR_PORT_VALUE = 0x0400,
-       MII_MSCR_1000BT_FD = 0x0200,
-       MII_MSCR_1000BT_HD = 0X0100,
-};
-
-/* MASTER-SLAVE Status Register */
-enum _mii_mssr {
-       MII_MSSR_CFG_FAULT = 0x8000,
-       MII_MSSR_CFG_RES = 0x4000,
-       MII_MSSR_LOCAL_RCV_STATUS = 0x2000,
-       MII_MSSR_REMOTE_RCVR = 0x1000,
-       MII_MSSR_LP_1000BT_FD = 0x0800,
-       MII_MSSR_LP_1000BT_HD = 0x0400,
-       MII_MSSR_IDLE_ERR_COUNT = 0x00ff,
-};
-
-/* IEEE Extened Status Register */
-enum _mii_esr {
-       MII_ESR_1000BX_FD = 0x8000,
-       MII_ESR_1000BX_HD = 0x4000,
-       MII_ESR_1000BT_FD = 0x2000,
-       MII_ESR_1000BT_HD = 0x1000,
-};
-/* PHY Specific Control Register */
-#if 0
-typedef union t_MII_PHY_SCR {
-       u16 image;
-       struct {
-               u16 disable_jabber:1;   // bit 0
-               u16 polarity_reversal:1;        // bit 1
-               u16 SEQ_test:1; // bit 2
-               u16 _bit_3:1;   // bit 3
-               u16 disable_CLK125:1;   // bit 4
-               u16 mdi_crossover_mode:2;       // bit 6:5
-               u16 enable_ext_dist:1;  // bit 7
-               u16 _bit_8_9:2; // bit 9:8
-               u16 force_link:1;       // bit 10
-               u16 assert_CRS:1;       // bit 11
-               u16 rcv_fifo_depth:2;   // bit 13:12
-               u16 xmit_fifo_depth:2;  // bit 15:14
-       } bits;
-} PHY_SCR_t, *PPHY_SCR_t;
-#endif
-
-typedef enum t_MII_ADMIN_STATUS {
-       adm_reset,
-       adm_operational,
-       adm_loopback,
-       adm_power_down,
-       adm_isolate
-} MII_ADMIN_t, *PMII_ADMIN_t;
-
-/* Physical Coding Sublayer Management (PCS) */
-/* PCS control and status registers bitmap as the same as MII */
-/* PCS Extended Status register bitmap as the same as MII */
-/* PCS ANAR */
-enum _pcs_anar {
-       PCS_ANAR_NEXT_PAGE = 0x8000,
-       PCS_ANAR_REMOTE_FAULT = 0x3000,
-       PCS_ANAR_ASYMMETRIC = 0x0100,
-       PCS_ANAR_PAUSE = 0x0080,
-       PCS_ANAR_HALF_DUPLEX = 0x0040,
-       PCS_ANAR_FULL_DUPLEX = 0x0020,
-};
-/* PCS ANLPAR */
-enum _pcs_anlpar {
-       PCS_ANLPAR_NEXT_PAGE = PCS_ANAR_NEXT_PAGE,
-       PCS_ANLPAR_REMOTE_FAULT = PCS_ANAR_REMOTE_FAULT,
-       PCS_ANLPAR_ASYMMETRIC = PCS_ANAR_ASYMMETRIC,
-       PCS_ANLPAR_PAUSE = PCS_ANAR_PAUSE,
-       PCS_ANLPAR_HALF_DUPLEX = PCS_ANAR_HALF_DUPLEX,
-       PCS_ANLPAR_FULL_DUPLEX = PCS_ANAR_FULL_DUPLEX,
-};
-
-typedef struct t_SROM {
-       u16 config_param;       /* 0x00 */
-       u16 asic_ctrl;          /* 0x02 */
-       u16 sub_vendor_id;      /* 0x04 */
-       u16 sub_system_id;      /* 0x06 */
-       u16 reserved1[12];      /* 0x08-0x1f */
-       u8 mac_addr[6];         /* 0x20-0x25 */
-       u8 reserved2[10];       /* 0x26-0x2f */
-       u8 sib[204];            /* 0x30-0xfb */
-       u32 crc;                /* 0xfc-0xff */
-} SROM_t, *PSROM_t;
-
-/* Ioctl custom data */
-struct ioctl_data {
-       char signature[10];
-       int cmd;
-       int len;
-       char *data;
-};
-
-struct mii_data {
-       __u16 reserved;
-       __u16 reg_num;
-       __u16 in_value;
-       __u16 out_value;
-};
-
-/* The Rx and Tx buffer descriptors. */
-struct netdev_desc {
-       __le64 next_desc;
-       __le64 status;
-       __le64 fraginfo;
-};
-
-#define PRIV_ALIGN     15      /* Required alignment mask */
-/* Use  __attribute__((aligned (L1_CACHE_BYTES)))  to maintain alignment
-   within the structure. */
-struct netdev_private {
-       /* Descriptor rings first for alignment. */
-       struct netdev_desc *rx_ring;
-       struct netdev_desc *tx_ring;
-       struct sk_buff *rx_skbuff[RX_RING_SIZE];
-       struct sk_buff *tx_skbuff[TX_RING_SIZE];
-       dma_addr_t tx_ring_dma;
-       dma_addr_t rx_ring_dma;
-       struct pci_dev *pdev;
-       spinlock_t tx_lock;
-       spinlock_t rx_lock;
-       struct net_device_stats stats;
-       unsigned int rx_buf_sz;         /* Based on MTU+slack. */
-       unsigned int speed;             /* Operating speed */
-       unsigned int vlan;              /* VLAN Id */
-       unsigned int chip_id;           /* PCI table chip id */
-       unsigned int rx_coalesce;       /* Maximum frames each RxDMAComplete intr */
-       unsigned int rx_timeout;        /* Wait time between RxDMAComplete intr */
-       unsigned int tx_coalesce;       /* Maximum frames each tx interrupt */
-       unsigned int full_duplex:1;     /* Full-duplex operation requested. */
-       unsigned int an_enable:2;       /* Auto-Negotiated Enable */
-       unsigned int jumbo:1;           /* Jumbo frame enable */
-       unsigned int coalesce:1;        /* Rx coalescing enable */
-       unsigned int tx_flow:1;         /* Tx flow control enable */
-       unsigned int rx_flow:1;         /* Rx flow control enable */
-       unsigned int phy_media:1;       /* 1: fiber, 0: copper */
-       unsigned int link_status:1;     /* Current link status */
-       struct netdev_desc *last_tx;    /* Last Tx descriptor used. */
-       unsigned long cur_rx, old_rx;   /* Producer/consumer ring indices */
-       unsigned long cur_tx, old_tx;
-       struct timer_list timer;
-       int wake_polarity;
-       char name[256];         /* net device description */
-       u8 duplex_polarity;
-       u16 mcast_filter[4];
-       u16 advertising;        /* NWay media advertisement */
-       u16 negotiate;          /* Negotiated media */
-       int phy_addr;           /* PHY addresses. */
-};
-
-/* The station address location in the EEPROM. */
-/* The struct pci_device_id consist of:
-        vendor, device          Vendor and device ID to match (or PCI_ANY_ID)
-        subvendor, subdevice    Subsystem vendor and device ID to match (or PCI_ANY_ID)
-        class                   Device class to match. The class_mask tells which bits
-        class_mask              of the class are honored during the comparison.
-        driver_data             Data private to the driver.
-*/
-
-static DEFINE_PCI_DEVICE_TABLE(rio_pci_tbl) = {
-       {0x1186, 0x4000, PCI_ANY_ID, PCI_ANY_ID, },
-       {0x13f0, 0x1021, PCI_ANY_ID, PCI_ANY_ID, },
-       { }
-};
-MODULE_DEVICE_TABLE (pci, rio_pci_tbl);
-#define TX_TIMEOUT  (4*HZ)
-#define PACKET_SIZE            1536
-#define MAX_JUMBO              8000
-#define RIO_IO_SIZE             340
-#define DEFAULT_RXC            5
-#define DEFAULT_RXT            750
-#define DEFAULT_TXC            1
-#define MAX_TXC                        8
-#endif                         /* __DL2K_H__ */
index fecac79b009b13bf72baf91515f43c92d0c20013..8007e20972e48cfb500b7434bb6cc295e06ccc50 100644 (file)
@@ -18,6 +18,7 @@ source "drivers/net/ethernet/broadcom/Kconfig"
 source "drivers/net/ethernet/brocade/Kconfig"
 source "drivers/net/ethernet/chelsio/Kconfig"
 source "drivers/net/ethernet/cisco/Kconfig"
+source "drivers/net/ethernet/dlink/Kconfig"
 source "drivers/net/ethernet/emulex/Kconfig"
 source "drivers/net/ethernet/neterion/Kconfig"
 source "drivers/net/ethernet/faraday/Kconfig"
index 0092c30db18f1bdad0d58422ba8ad90502850a71..22ef3808f439cbb80c27a6a7016a7dc3ad0f9c87 100644 (file)
@@ -10,6 +10,7 @@ obj-$(CONFIG_NET_VENDOR_BROADCOM) += broadcom/
 obj-$(CONFIG_NET_VENDOR_BROCADE) += brocade/
 obj-$(CONFIG_NET_VENDOR_CHELSIO) += chelsio/
 obj-$(CONFIG_NET_VENDOR_CISCO) += cisco/
+obj-$(CONFIG_NET_VENDOR_DLINK) += dlink/
 obj-$(CONFIG_NET_VENDOR_EMULEX) += emulex/
 obj-$(CONFIG_NET_VENDOR_EXAR) += neterion/
 obj-$(CONFIG_NET_VENDOR_FARADAY) += faraday/
diff --git a/drivers/net/ethernet/dlink/Kconfig b/drivers/net/ethernet/dlink/Kconfig
new file mode 100644 (file)
index 0000000..9fdb66b
--- /dev/null
@@ -0,0 +1,84 @@
+#
+# D-Link device configuration
+#
+
+config NET_VENDOR_DLINK
+       bool "D-Link devices"
+       depends on PCI || PARPORT
+       ---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 doesn't directly affect the
+         kernel: saying N will just cause the configurator to skip all
+         the questions about D-Link devices. If you say Y, you will be asked for
+         your specific card in the following questions.
+
+if NET_VENDOR_DLINK
+
+config DE600
+       tristate "D-Link DE600 pocket adapter support"
+       depends on PARPORT
+       ---help---
+         This is a network (Ethernet) device which attaches to your parallel
+         port. Read <file:Documentation/networking/DLINK.txt> as well as the
+         Ethernet-HOWTO, available from
+         <http://www.tldp.org/docs.html#howto>, if you want to use
+         this. It is possible to have several devices share a single parallel
+         port and it is safe to compile the corresponding drivers into the
+         kernel.
+
+         To compile this driver as a module, choose M here: the module
+         will be called de600.
+
+config DE620
+       tristate "D-Link DE620 pocket adapter support"
+       depends on PARPORT
+       ---help---
+         This is a network (Ethernet) device which attaches to your parallel
+         port. Read <file:Documentation/networking/DLINK.txt> as well as the
+         Ethernet-HOWTO, available from
+         <http://www.tldp.org/docs.html#howto>, if you want to use
+         this. It is possible to have several devices share a single parallel
+         port and it is safe to compile the corresponding drivers into the
+         kernel.
+
+         To compile this driver as a module, choose M here: the module
+         will be called de620.
+
+config DL2K
+       tristate "DL2000/TC902x-based Gigabit Ethernet support"
+       depends on PCI
+       select CRC32
+       ---help---
+         This driver supports DL2000/TC902x-based Gigabit ethernet cards,
+         which includes
+         D-Link DGE-550T Gigabit Ethernet Adapter.
+         D-Link DL2000-based Gigabit Ethernet Adapter.
+         Sundance/Tamarack TC902x Gigabit Ethernet Adapter.
+
+         To compile this driver as a module, choose M here: the
+         module will be called dl2k.
+
+config SUNDANCE
+       tristate "Sundance Alta support"
+       depends on PCI
+       select CRC32
+       select MII
+       ---help---
+         This driver is for the Sundance "Alta" chip.
+         More specific information and updates are available from
+         <http://www.scyld.com/network/sundance.html>.
+
+config SUNDANCE_MMIO
+       bool "Use MMIO instead of PIO"
+       depends on SUNDANCE
+       ---help---
+         Enable memory-mapped I/O for interaction with Sundance NIC registers.
+         Do NOT enable this by default, PIO (enabled when MMIO is disabled)
+         is known to solve bugs on certain chips.
+
+         If unsure, say N.
+
+endif # NET_VENDOR_DLINK
diff --git a/drivers/net/ethernet/dlink/Makefile b/drivers/net/ethernet/dlink/Makefile
new file mode 100644 (file)
index 0000000..c705eaa
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# Makefile for the D-Link network device drivers.
+#
+
+obj-$(CONFIG_DE600) += de600.o
+obj-$(CONFIG_DE620) += de620.o
+obj-$(CONFIG_DL2K) += dl2k.o
+obj-$(CONFIG_SUNDANCE) += sundance.o
diff --git a/drivers/net/ethernet/dlink/de600.c b/drivers/net/ethernet/dlink/de600.c
new file mode 100644 (file)
index 0000000..23a6539
--- /dev/null
@@ -0,0 +1,530 @@
+static const char version[] = "de600.c: $Revision: 1.41-2.5 $,  Bjorn Ekwall (bj0rn@blox.se)\n";
+/*
+ *     de600.c
+ *
+ *     Linux driver for the D-Link DE-600 Ethernet pocket adapter.
+ *
+ *     Portions (C) Copyright 1993, 1994 by Bjorn Ekwall
+ *     The Author may be reached as bj0rn@blox.se
+ *
+ *     Based on adapter information gathered from DE600.ASM by D-Link Inc.,
+ *     as included on disk C in the v.2.11 of PC/TCP from FTP Software.
+ *     For DE600.asm:
+ *             Portions (C) Copyright 1990 D-Link, Inc.
+ *             Copyright, 1988-1992, Russell Nelson, Crynwr Software
+ *
+ *     Adapted to the sample network driver core for linux,
+ *     written by: Donald Becker <becker@super.org>
+ *             (Now at <becker@scyld.com>)
+ *
+ **************************************************************/
+/*
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License as published by
+ *     the Free Software Foundation; either version 2, or (at your option)
+ *     any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************/
+
+/* Add more time here if your adapter won't work OK: */
+#define DE600_SLOW_DOWN        udelay(delay_time)
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/string.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <asm/system.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include <asm/io.h>
+
+#include "de600.h"
+
+static unsigned int check_lost = 1;
+module_param(check_lost, bool, 0);
+MODULE_PARM_DESC(check_lost, "If set then check for unplugged de600");
+
+static unsigned int delay_time = 10;
+module_param(delay_time, int, 0);
+MODULE_PARM_DESC(delay_time, "DE-600 deley on I/O in microseconds");
+
+
+/*
+ * D-Link driver variables:
+ */
+
+static volatile int            rx_page;
+
+#define TX_PAGES 2
+static volatile int            tx_fifo[TX_PAGES];
+static volatile int            tx_fifo_in;
+static volatile int            tx_fifo_out;
+static volatile int            free_tx_pages = TX_PAGES;
+static int                     was_down;
+static DEFINE_SPINLOCK(de600_lock);
+
+static inline u8 de600_read_status(struct net_device *dev)
+{
+       u8 status;
+
+       outb_p(STATUS, DATA_PORT);
+       status = inb(STATUS_PORT);
+       outb_p(NULL_COMMAND | HI_NIBBLE, DATA_PORT);
+
+       return status;
+}
+
+static inline u8 de600_read_byte(unsigned char type, struct net_device *dev)
+{
+       /* dev used by macros */
+       u8 lo;
+       outb_p((type), DATA_PORT);
+       lo = ((unsigned char)inb(STATUS_PORT)) >> 4;
+       outb_p((type) | HI_NIBBLE, DATA_PORT);
+       return ((unsigned char)inb(STATUS_PORT) & (unsigned char)0xf0) | lo;
+}
+
+/*
+ * Open/initialize the board.  This is called (in the current kernel)
+ * after booting when 'ifconfig <dev->name> $IP_ADDR' is run (in rc.inet1).
+ *
+ * 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 a non-reboot way to recover if something goes wrong.
+ */
+
+static int de600_open(struct net_device *dev)
+{
+       unsigned long flags;
+       int ret = request_irq(DE600_IRQ, de600_interrupt, 0, dev->name, dev);
+       if (ret) {
+               printk(KERN_ERR "%s: unable to get IRQ %d\n", dev->name, DE600_IRQ);
+               return ret;
+       }
+       spin_lock_irqsave(&de600_lock, flags);
+       ret = adapter_init(dev);
+       spin_unlock_irqrestore(&de600_lock, flags);
+       return ret;
+}
+
+/*
+ * The inverse routine to de600_open().
+ */
+
+static int de600_close(struct net_device *dev)
+{
+       select_nic();
+       rx_page = 0;
+       de600_put_command(RESET);
+       de600_put_command(STOP_RESET);
+       de600_put_command(0);
+       select_prn();
+       free_irq(DE600_IRQ, dev);
+       return 0;
+}
+
+static inline void trigger_interrupt(struct net_device *dev)
+{
+       de600_put_command(FLIP_IRQ);
+       select_prn();
+       DE600_SLOW_DOWN;
+       select_nic();
+       de600_put_command(0);
+}
+
+/*
+ * Copy a buffer to the adapter transmit page memory.
+ * Start sending.
+ */
+
+static int de600_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       unsigned long flags;
+       int     transmit_from;
+       int     len;
+       int     tickssofar;
+       u8      *buffer = skb->data;
+       int     i;
+
+       if (free_tx_pages <= 0) {       /* Do timeouts, to avoid hangs. */
+               tickssofar = jiffies - dev_trans_start(dev);
+               if (tickssofar < HZ/20)
+                       return NETDEV_TX_BUSY;
+               /* else */
+               printk(KERN_WARNING "%s: transmit timed out (%d), %s?\n", dev->name, tickssofar, "network cable problem");
+               /* Restart the adapter. */
+               spin_lock_irqsave(&de600_lock, flags);
+               if (adapter_init(dev)) {
+                       spin_unlock_irqrestore(&de600_lock, flags);
+                       return NETDEV_TX_BUSY;
+               }
+               spin_unlock_irqrestore(&de600_lock, flags);
+       }
+
+       /* Start real output */
+       pr_debug("de600_start_xmit:len=%d, page %d/%d\n", skb->len, tx_fifo_in, free_tx_pages);
+
+       if ((len = skb->len) < RUNT)
+               len = RUNT;
+
+       spin_lock_irqsave(&de600_lock, flags);
+       select_nic();
+       tx_fifo[tx_fifo_in] = transmit_from = tx_page_adr(tx_fifo_in) - len;
+       tx_fifo_in = (tx_fifo_in + 1) % TX_PAGES; /* Next free tx page */
+
+       if(check_lost)
+       {
+               /* This costs about 40 instructions per packet... */
+               de600_setup_address(NODE_ADDRESS, RW_ADDR);
+               de600_read_byte(READ_DATA, dev);
+               if (was_down || (de600_read_byte(READ_DATA, dev) != 0xde)) {
+                       if (adapter_init(dev)) {
+                               spin_unlock_irqrestore(&de600_lock, flags);
+                               return NETDEV_TX_BUSY;
+                       }
+               }
+       }
+
+       de600_setup_address(transmit_from, RW_ADDR);
+       for (i = 0;  i < skb->len ; ++i, ++buffer)
+               de600_put_byte(*buffer);
+       for (; i < len; ++i)
+               de600_put_byte(0);
+
+       if (free_tx_pages-- == TX_PAGES) { /* No transmission going on */
+               dev->trans_start = jiffies;
+               netif_start_queue(dev); /* allow more packets into adapter */
+               /* Send page and generate a faked interrupt */
+               de600_setup_address(transmit_from, TX_ADDR);
+               de600_put_command(TX_ENABLE);
+       }
+       else {
+               if (free_tx_pages)
+                       netif_start_queue(dev);
+               else
+                       netif_stop_queue(dev);
+               select_prn();
+       }
+       spin_unlock_irqrestore(&de600_lock, flags);
+       dev_kfree_skb(skb);
+       return NETDEV_TX_OK;
+}
+
+/*
+ * The typical workload of the driver:
+ * Handle the network interface interrupts.
+ */
+
+static irqreturn_t de600_interrupt(int irq, void *dev_id)
+{
+       struct net_device       *dev = dev_id;
+       u8              irq_status;
+       int             retrig = 0;
+       int             boguscount = 0;
+
+       spin_lock(&de600_lock);
+
+       select_nic();
+       irq_status = de600_read_status(dev);
+
+       do {
+               pr_debug("de600_interrupt (%02X)\n", irq_status);
+
+               if (irq_status & RX_GOOD)
+                       de600_rx_intr(dev);
+               else if (!(irq_status & RX_BUSY))
+                       de600_put_command(RX_ENABLE);
+
+               /* Any transmission in progress? */
+               if (free_tx_pages < TX_PAGES)
+                       retrig = de600_tx_intr(dev, irq_status);
+               else
+                       retrig = 0;
+
+               irq_status = de600_read_status(dev);
+       } while ( (irq_status & RX_GOOD) || ((++boguscount < 100) && retrig) );
+       /*
+        * Yeah, it _looks_ like busy waiting, smells like busy waiting
+        * and I know it's not PC, but please, it will only occur once
+        * in a while and then only for a loop or so (< 1ms for sure!)
+        */
+
+       /* Enable adapter interrupts */
+       select_prn();
+       if (retrig)
+               trigger_interrupt(dev);
+       spin_unlock(&de600_lock);
+       return IRQ_HANDLED;
+}
+
+static int de600_tx_intr(struct net_device *dev, int irq_status)
+{
+       /*
+        * Returns 1 if tx still not done
+        */
+
+       /* Check if current transmission is done yet */
+       if (irq_status & TX_BUSY)
+               return 1; /* tx not done, try again */
+
+       /* else */
+       /* If last transmission OK then bump fifo index */
+       if (!(irq_status & TX_FAILED16)) {
+               tx_fifo_out = (tx_fifo_out + 1) % TX_PAGES;
+               ++free_tx_pages;
+               dev->stats.tx_packets++;
+               netif_wake_queue(dev);
+       }
+
+       /* More to send, or resend last packet? */
+       if ((free_tx_pages < TX_PAGES) || (irq_status & TX_FAILED16)) {
+               dev->trans_start = jiffies;
+               de600_setup_address(tx_fifo[tx_fifo_out], TX_ADDR);
+               de600_put_command(TX_ENABLE);
+               return 1;
+       }
+       /* else */
+
+       return 0;
+}
+
+/*
+ * We have a good packet, get it out of the adapter.
+ */
+static void de600_rx_intr(struct net_device *dev)
+{
+       struct sk_buff  *skb;
+       int             i;
+       int             read_from;
+       int             size;
+       unsigned char   *buffer;
+
+       /* Get size of received packet */
+       size = de600_read_byte(RX_LEN, dev);    /* low byte */
+       size += (de600_read_byte(RX_LEN, dev) << 8);    /* high byte */
+       size -= 4;      /* Ignore trailing 4 CRC-bytes */
+
+       /* Tell adapter where to store next incoming packet, enable receiver */
+       read_from = rx_page_adr();
+       next_rx_page();
+       de600_put_command(RX_ENABLE);
+
+       if ((size < 32)  ||  (size > 1535)) {
+               printk(KERN_WARNING "%s: Bogus packet size %d.\n", dev->name, size);
+               if (size > 10000)
+                       adapter_init(dev);
+               return;
+       }
+
+       skb = dev_alloc_skb(size+2);
+       if (skb == NULL) {
+               printk("%s: Couldn't allocate a sk_buff of size %d.\n", dev->name, size);
+               return;
+       }
+       /* else */
+
+       skb_reserve(skb,2);     /* Align */
+
+       /* 'skb->data' points to the start of sk_buff data area. */
+       buffer = skb_put(skb,size);
+
+       /* copy the packet into the buffer */
+       de600_setup_address(read_from, RW_ADDR);
+       for (i = size; i > 0; --i, ++buffer)
+               *buffer = de600_read_byte(READ_DATA, dev);
+
+       skb->protocol=eth_type_trans(skb,dev);
+
+       netif_rx(skb);
+
+       /* update stats */
+       dev->stats.rx_packets++; /* count all receives */
+       dev->stats.rx_bytes += size; /* count all received bytes */
+
+       /*
+        * If any worth-while packets have been received, netif_rx()
+        * will work on them when we get to the tasklets.
+        */
+}
+
+static const struct net_device_ops de600_netdev_ops = {
+       .ndo_open               = de600_open,
+       .ndo_stop               = de600_close,
+       .ndo_start_xmit         = de600_start_xmit,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
+
+static struct net_device * __init de600_probe(void)
+{
+       int     i;
+       struct net_device *dev;
+       int err;
+
+       dev = alloc_etherdev(0);
+       if (!dev)
+               return ERR_PTR(-ENOMEM);
+
+
+       if (!request_region(DE600_IO, 3, "de600")) {
+               printk(KERN_WARNING "DE600: port 0x%x busy\n", DE600_IO);
+               err = -EBUSY;
+               goto out;
+       }
+
+       printk(KERN_INFO "%s: D-Link DE-600 pocket adapter", dev->name);
+       /* Alpha testers must have the version number to report bugs. */
+       pr_debug("%s", version);
+
+       /* probe for adapter */
+       err = -ENODEV;
+       rx_page = 0;
+       select_nic();
+       (void)de600_read_status(dev);
+       de600_put_command(RESET);
+       de600_put_command(STOP_RESET);
+       if (de600_read_status(dev) & 0xf0) {
+               printk(": not at I/O %#3x.\n", DATA_PORT);
+               goto out1;
+       }
+
+       /*
+        * Maybe we found one,
+        * have to check if it is a D-Link DE-600 adapter...
+        */
+
+       /* Get the adapter ethernet address from the ROM */
+       de600_setup_address(NODE_ADDRESS, RW_ADDR);
+       for (i = 0; i < ETH_ALEN; i++) {
+               dev->dev_addr[i] = de600_read_byte(READ_DATA, dev);
+               dev->broadcast[i] = 0xff;
+       }
+
+       /* Check magic code */
+       if ((dev->dev_addr[1] == 0xde) && (dev->dev_addr[2] == 0x15)) {
+               /* OK, install real address */
+               dev->dev_addr[0] = 0x00;
+               dev->dev_addr[1] = 0x80;
+               dev->dev_addr[2] = 0xc8;
+               dev->dev_addr[3] &= 0x0f;
+               dev->dev_addr[3] |= 0x70;
+       } else {
+               printk(" not identified in the printer port\n");
+               goto out1;
+       }
+
+       printk(", Ethernet Address: %pM\n", dev->dev_addr);
+
+       dev->netdev_ops = &de600_netdev_ops;
+
+       dev->flags&=~IFF_MULTICAST;
+
+       select_prn();
+
+       err = register_netdev(dev);
+       if (err)
+               goto out1;
+
+       return dev;
+
+out1:
+       release_region(DE600_IO, 3);
+out:
+       free_netdev(dev);
+       return ERR_PTR(err);
+}
+
+static int adapter_init(struct net_device *dev)
+{
+       int     i;
+
+       select_nic();
+       rx_page = 0; /* used by RESET */
+       de600_put_command(RESET);
+       de600_put_command(STOP_RESET);
+
+       /* Check if it is still there... */
+       /* Get the some bytes of the adapter ethernet address from the ROM */
+       de600_setup_address(NODE_ADDRESS, RW_ADDR);
+       de600_read_byte(READ_DATA, dev);
+       if ((de600_read_byte(READ_DATA, dev) != 0xde) ||
+           (de600_read_byte(READ_DATA, dev) != 0x15)) {
+       /* was: if (de600_read_status(dev) & 0xf0) { */
+               printk("Something has happened to the DE-600!  Please check it and do a new ifconfig!\n");
+               /* Goodbye, cruel world... */
+               dev->flags &= ~IFF_UP;
+               de600_close(dev);
+               was_down = 1;
+               netif_stop_queue(dev); /* Transmit busy...  */
+               return 1; /* failed */
+       }
+
+       if (was_down) {
+               printk(KERN_INFO "%s: Thanks, I feel much better now!\n", dev->name);
+               was_down = 0;
+       }
+
+       tx_fifo_in = 0;
+       tx_fifo_out = 0;
+       free_tx_pages = TX_PAGES;
+
+
+       /* set the ether address. */
+       de600_setup_address(NODE_ADDRESS, RW_ADDR);
+       for (i = 0; i < ETH_ALEN; i++)
+               de600_put_byte(dev->dev_addr[i]);
+
+       /* where to start saving incoming packets */
+       rx_page = RX_BP | RX_BASE_PAGE;
+       de600_setup_address(MEM_4K, RW_ADDR);
+       /* Enable receiver */
+       de600_put_command(RX_ENABLE);
+       select_prn();
+
+       netif_start_queue(dev);
+
+       return 0; /* OK */
+}
+
+static struct net_device *de600_dev;
+
+static int __init de600_init(void)
+{
+       de600_dev = de600_probe();
+       if (IS_ERR(de600_dev))
+               return PTR_ERR(de600_dev);
+       return 0;
+}
+
+static void __exit de600_exit(void)
+{
+       unregister_netdev(de600_dev);
+       release_region(DE600_IO, 3);
+       free_netdev(de600_dev);
+}
+
+module_init(de600_init);
+module_exit(de600_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/dlink/de600.h b/drivers/net/ethernet/dlink/de600.h
new file mode 100644 (file)
index 0000000..e80ecba
--- /dev/null
@@ -0,0 +1,168 @@
+/**************************************************
+ *                                                *
+ * Definition of D-Link Ethernet Pocket adapter   *
+ *                                                *
+ **************************************************/
+/*
+ * D-Link Ethernet pocket adapter ports
+ */
+/*
+ * OK, so I'm cheating, but there are an awful lot of
+ * reads and writes in order to get anything in and out
+ * of the DE-600 with 4 bits at a time in the parallel port,
+ * so every saved instruction really helps :-)
+ */
+
+#ifndef DE600_IO
+#define DE600_IO       0x378
+#endif
+
+#define DATA_PORT      (DE600_IO)
+#define STATUS_PORT    (DE600_IO + 1)
+#define COMMAND_PORT   (DE600_IO + 2)
+
+#ifndef DE600_IRQ
+#define DE600_IRQ      7
+#endif
+/*
+ * It really should look like this, and autoprobing as well...
+ *
+#define DATA_PORT      (dev->base_addr + 0)
+#define STATUS_PORT    (dev->base_addr + 1)
+#define COMMAND_PORT   (dev->base_addr + 2)
+#define DE600_IRQ      dev->irq
+ */
+
+/*
+ * D-Link COMMAND_PORT commands
+ */
+#define SELECT_NIC     0x04 /* select Network Interface Card */
+#define SELECT_PRN     0x1c /* select Printer */
+#define NML_PRN                0xec /* normal Printer situation */
+#define IRQEN          0x10 /* enable IRQ line */
+
+/*
+ * D-Link STATUS_PORT
+ */
+#define RX_BUSY                0x80
+#define RX_GOOD                0x40
+#define TX_FAILED16    0x10
+#define TX_BUSY                0x08
+
+/*
+ * D-Link DATA_PORT commands
+ * command in low 4 bits
+ * data in high 4 bits
+ * select current data nibble with HI_NIBBLE bit
+ */
+#define WRITE_DATA     0x00 /* write memory */
+#define READ_DATA      0x01 /* read memory */
+#define STATUS         0x02 /* read  status register */
+#define COMMAND                0x03 /* write command register (see COMMAND below) */
+#define NULL_COMMAND   0x04 /* null command */
+#define RX_LEN         0x05 /* read  received packet length */
+#define TX_ADDR                0x06 /* set adapter transmit memory address */
+#define RW_ADDR                0x07 /* set adapter read/write memory address */
+#define HI_NIBBLE      0x08 /* read/write the high nibble of data,
+                               or-ed with rest of command */
+
+/*
+ * command register, accessed through DATA_PORT with low bits = COMMAND
+ */
+#define RX_ALL         0x01 /* PROMISCUOUS */
+#define RX_BP          0x02 /* default: BROADCAST & PHYSICAL ADDRESS */
+#define RX_MBP         0x03 /* MULTICAST, BROADCAST & PHYSICAL ADDRESS */
+
+#define TX_ENABLE      0x04 /* bit 2 */
+#define RX_ENABLE      0x08 /* bit 3 */
+
+#define RESET          0x80 /* set bit 7 high */
+#define STOP_RESET     0x00 /* set bit 7 low */
+
+/*
+ * data to command register
+ * (high 4 bits in write to DATA_PORT)
+ */
+#define RX_PAGE2_SELECT        0x10 /* bit 4, only 2 pages to select */
+#define RX_BASE_PAGE   0x20 /* bit 5, always set when specifying RX_ADDR */
+#define FLIP_IRQ       0x40 /* bit 6 */
+
+/*
+ * D-Link adapter internal memory:
+ *
+ * 0-2K 1:st transmit page (send from pointer up to 2K)
+ * 2-4K        2:nd transmit page (send from pointer up to 4K)
+ *
+ * 4-6K 1:st receive page (data from 4K upwards)
+ * 6-8K 2:nd receive page (data from 6K upwards)
+ *
+ * 8K+ Adapter ROM (contains magic code and last 3 bytes of Ethernet address)
+ */
+#define MEM_2K         0x0800 /* 2048 */
+#define MEM_4K         0x1000 /* 4096 */
+#define MEM_6K         0x1800 /* 6144 */
+#define NODE_ADDRESS   0x2000 /* 8192 */
+
+#define RUNT 60                /* Too small Ethernet packet */
+
+/**************************************************
+ *                                                *
+ *             End of definition                  *
+ *                                                *
+ **************************************************/
+
+/*
+ * Index to functions, as function prototypes.
+ */
+/* Routines used internally. (See "convenience macros") */
+static u8      de600_read_status(struct net_device *dev);
+static u8      de600_read_byte(unsigned char type, struct net_device *dev);
+
+/* Put in the device structure. */
+static int     de600_open(struct net_device *dev);
+static int     de600_close(struct net_device *dev);
+static int     de600_start_xmit(struct sk_buff *skb, struct net_device *dev);
+
+/* Dispatch from interrupts. */
+static irqreturn_t de600_interrupt(int irq, void *dev_id);
+static int     de600_tx_intr(struct net_device *dev, int irq_status);
+static void    de600_rx_intr(struct net_device *dev);
+
+/* Initialization */
+static void    trigger_interrupt(struct net_device *dev);
+static int     adapter_init(struct net_device *dev);
+
+/*
+ * Convenience macros/functions for D-Link adapter
+ */
+
+#define select_prn() outb_p(SELECT_PRN, COMMAND_PORT); DE600_SLOW_DOWN
+#define select_nic() outb_p(SELECT_NIC, COMMAND_PORT); DE600_SLOW_DOWN
+
+/* Thanks for hints from Mark Burton <markb@ordern.demon.co.uk> */
+#define de600_put_byte(data) ( \
+       outb_p(((data) << 4)   | WRITE_DATA            , DATA_PORT), \
+       outb_p(((data) & 0xf0) | WRITE_DATA | HI_NIBBLE, DATA_PORT))
+
+/*
+ * The first two outb_p()'s below could perhaps be deleted if there
+ * would be more delay in the last two. Not certain about it yet...
+ */
+#define de600_put_command(cmd) ( \
+       outb_p(( rx_page        << 4)   | COMMAND            , DATA_PORT), \
+       outb_p(( rx_page        & 0xf0) | COMMAND | HI_NIBBLE, DATA_PORT), \
+       outb_p(((rx_page | cmd) << 4)   | COMMAND            , DATA_PORT), \
+       outb_p(((rx_page | cmd) & 0xf0) | COMMAND | HI_NIBBLE, DATA_PORT))
+
+#define de600_setup_address(addr,type) ( \
+       outb_p((((addr) << 4) & 0xf0) | type            , DATA_PORT), \
+       outb_p(( (addr)       & 0xf0) | type | HI_NIBBLE, DATA_PORT), \
+       outb_p((((addr) >> 4) & 0xf0) | type            , DATA_PORT), \
+       outb_p((((addr) >> 8) & 0xf0) | type | HI_NIBBLE, DATA_PORT))
+
+#define rx_page_adr() ((rx_page & RX_PAGE2_SELECT)?(MEM_6K):(MEM_4K))
+
+/* Flip bit, only 2 pages */
+#define next_rx_page() (rx_page ^= RX_PAGE2_SELECT)
+
+#define tx_page_adr(a) (((a) + 1) * MEM_2K)
diff --git a/drivers/net/ethernet/dlink/de620.c b/drivers/net/ethernet/dlink/de620.c
new file mode 100644 (file)
index 0000000..1c51a75
--- /dev/null
@@ -0,0 +1,988 @@
+/*
+ *     de620.c $Revision: 1.40 $ BETA
+ *
+ *
+ *     Linux driver for the D-Link DE-620 Ethernet pocket adapter.
+ *
+ *     Portions (C) Copyright 1993, 1994 by Bjorn Ekwall <bj0rn@blox.se>
+ *
+ *     Based on adapter information gathered from DOS packetdriver
+ *     sources from D-Link Inc:  (Special thanks to Henry Ngai of D-Link.)
+ *             Portions (C) Copyright D-Link SYSTEM Inc. 1991, 1992
+ *             Copyright, 1988, Russell Nelson, Crynwr Software
+ *
+ *     Adapted to the sample network driver core for linux,
+ *     written by: Donald Becker <becker@super.org>
+ *             (Now at <becker@scyld.com>)
+ *
+ *     Valuable assistance from:
+ *             J. Joshua Kopper <kopper@rtsg.mot.com>
+ *             Olav Kvittem <Olav.Kvittem@uninett.no>
+ *             Germano Caronni <caronni@nessie.cs.id.ethz.ch>
+ *             Jeremy Fitzhardinge <jeremy@suite.sw.oz.au>
+ *
+ *****************************************************************************/
+/*
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License as published by
+ *     the Free Software Foundation; either version 2, or (at your option)
+ *     any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *****************************************************************************/
+static const char version[] =
+       "de620.c: $Revision: 1.40 $,  Bjorn Ekwall <bj0rn@blox.se>\n";
+
+/***********************************************************************
+ *
+ * "Tuning" section.
+ *
+ * Compile-time options: (see below for descriptions)
+ * -DDE620_IO=0x378    (lpt1)
+ * -DDE620_IRQ=7       (lpt1)
+ * -DSHUTDOWN_WHEN_LOST
+ * -DCOUNT_LOOPS
+ * -DLOWSPEED
+ * -DREAD_DELAY
+ * -DWRITE_DELAY
+ */
+
+/*
+ * This driver assumes that the printer port is a "normal",
+ * dumb, uni-directional port!
+ * If your port is "fancy" in any way, please try to set it to "normal"
+ * with your BIOS setup.  I have no access to machines with bi-directional
+ * ports, so I can't test such a driver :-(
+ * (Yes, I _know_ it is possible to use DE620 with bidirectional ports...)
+ *
+ * There are some clones of DE620 out there, with different names.
+ * If the current driver does not recognize a clone, try to change
+ * the following #define to:
+ *
+ * #define DE620_CLONE 1
+ */
+#define DE620_CLONE 0
+
+/*
+ * If the adapter has problems with high speeds, enable this #define
+ * otherwise full printerport speed will be attempted.
+ *
+ * You can tune the READ_DELAY/WRITE_DELAY below if you enable LOWSPEED
+ *
+#define LOWSPEED
+ */
+
+#ifndef READ_DELAY
+#define READ_DELAY 100 /* adapter internal read delay in 100ns units */
+#endif
+
+#ifndef WRITE_DELAY
+#define WRITE_DELAY 100        /* adapter internal write delay in 100ns units */
+#endif
+
+/*
+ * Enable this #define if you want the adapter to do a "ifconfig down" on
+ * itself when we have detected that something is possibly wrong with it.
+ * The default behaviour is to retry with "adapter_init()" until success.
+ * This should be used for debugging purposes only.
+ *
+#define SHUTDOWN_WHEN_LOST
+ */
+
+#ifdef LOWSPEED
+/*
+ * Enable this #define if you want to see debugging output that show how long
+ * we have to wait before the DE-620 is ready for the next read/write/command.
+ *
+#define COUNT_LOOPS
+ */
+#endif
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/string.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include <asm/io.h>
+#include <asm/system.h>
+
+/* Constant definitions for the DE-620 registers, commands and bits */
+#include "de620.h"
+
+typedef unsigned char byte;
+
+/*******************************************************
+ *                                                     *
+ * Definition of D-Link DE-620 Ethernet Pocket adapter *
+ * See also "de620.h"                                  *
+ *                                                     *
+ *******************************************************/
+#ifndef DE620_IO /* Compile-time configurable */
+#define DE620_IO 0x378
+#endif
+
+#ifndef DE620_IRQ /* Compile-time configurable */
+#define DE620_IRQ      7
+#endif
+
+#define DATA_PORT      (dev->base_addr)
+#define STATUS_PORT    (dev->base_addr + 1)
+#define COMMAND_PORT   (dev->base_addr + 2)
+
+#define RUNT 60                /* Too small Ethernet packet */
+#define GIANT 1514     /* largest legal size packet, no fcs */
+
+/*
+ * Force media with insmod:
+ *     insmod de620.o bnc=1
+ * or
+ *     insmod de620.o utp=1
+ *
+ * Force io and/or irq with insmod:
+ *     insmod de620.o io=0x378 irq=7
+ *
+ * Make a clone skip the Ethernet-address range check:
+ *     insmod de620.o clone=1
+ */
+static int bnc;
+static int utp;
+static int io  = DE620_IO;
+static int irq = DE620_IRQ;
+static int clone = DE620_CLONE;
+
+static spinlock_t de620_lock;
+
+module_param(bnc, int, 0);
+module_param(utp, int, 0);
+module_param(io, int, 0);
+module_param(irq, int, 0);
+module_param(clone, int, 0);
+MODULE_PARM_DESC(bnc, "DE-620 set BNC medium (0-1)");
+MODULE_PARM_DESC(utp, "DE-620 set UTP medium (0-1)");
+MODULE_PARM_DESC(io, "DE-620 I/O base address,required");
+MODULE_PARM_DESC(irq, "DE-620 IRQ number,required");
+MODULE_PARM_DESC(clone, "Check also for non-D-Link DE-620 clones (0-1)");
+
+/***********************************************
+ *                                             *
+ * Index to functions, as function prototypes. *
+ *                                             *
+ ***********************************************/
+
+/*
+ * Routines used internally. (See also "convenience macros.. below")
+ */
+
+/* Put in the device structure. */
+static int     de620_open(struct net_device *);
+static int     de620_close(struct net_device *);
+static void    de620_set_multicast_list(struct net_device *);
+static int     de620_start_xmit(struct sk_buff *, struct net_device *);
+
+/* Dispatch from interrupts. */
+static irqreturn_t de620_interrupt(int, void *);
+static int     de620_rx_intr(struct net_device *);
+
+/* Initialization */
+static int     adapter_init(struct net_device *);
+static int     read_eeprom(struct net_device *);
+
+
+/*
+ * D-Link driver variables:
+ */
+#define SCR_DEF NIBBLEMODE |INTON | SLEEP | AUTOTX
+#define        TCR_DEF RXPB                    /* not used: | TXSUCINT | T16INT */
+#define DE620_RX_START_PAGE 12         /* 12 pages (=3k) reserved for tx */
+#define DEF_NIC_CMD IRQEN | ICEN | DS1
+
+static volatile byte   NIC_Cmd;
+static volatile byte   next_rx_page;
+static byte            first_rx_page;
+static byte            last_rx_page;
+static byte            EIPRegister;
+
+static struct nic {
+       byte    NodeID[6];
+       byte    RAM_Size;
+       byte    Model;
+       byte    Media;
+       byte    SCR;
+} nic_data;
+
+/**********************************************************
+ *                                                        *
+ * Convenience macros/functions for D-Link DE-620 adapter *
+ *                                                        *
+ **********************************************************/
+#define de620_tx_buffs(dd) (inb(STATUS_PORT) & (TXBF0 | TXBF1))
+#define de620_flip_ds(dd) NIC_Cmd ^= DS0 | DS1; outb(NIC_Cmd, COMMAND_PORT);
+
+/* Check for ready-status, and return a nibble (high 4 bits) for data input */
+#ifdef COUNT_LOOPS
+static int tot_cnt;
+#endif
+static inline byte
+de620_ready(struct net_device *dev)
+{
+       byte value;
+       register short int cnt = 0;
+
+       while ((((value = inb(STATUS_PORT)) & READY) == 0) && (cnt <= 1000))
+               ++cnt;
+
+#ifdef COUNT_LOOPS
+       tot_cnt += cnt;
+#endif
+       return value & 0xf0; /* nibble */
+}
+
+static inline void
+de620_send_command(struct net_device *dev, byte cmd)
+{
+       de620_ready(dev);
+       if (cmd == W_DUMMY)
+               outb(NIC_Cmd, COMMAND_PORT);
+
+       outb(cmd, DATA_PORT);
+
+       outb(NIC_Cmd ^ CS0, COMMAND_PORT);
+       de620_ready(dev);
+       outb(NIC_Cmd, COMMAND_PORT);
+}
+
+static inline void
+de620_put_byte(struct net_device *dev, byte value)
+{
+       /* The de620_ready() makes 7 loops, on the average, on a DX2/66 */
+       de620_ready(dev);
+       outb(value, DATA_PORT);
+       de620_flip_ds(dev);
+}
+
+static inline byte
+de620_read_byte(struct net_device *dev)
+{
+       byte value;
+
+       /* The de620_ready() makes 7 loops, on the average, on a DX2/66 */
+       value = de620_ready(dev); /* High nibble */
+       de620_flip_ds(dev);
+       value |= de620_ready(dev) >> 4; /* Low nibble */
+       return value;
+}
+
+static inline void
+de620_write_block(struct net_device *dev, byte *buffer, int count, int pad)
+{
+#ifndef LOWSPEED
+       byte uflip = NIC_Cmd ^ (DS0 | DS1);
+       byte dflip = NIC_Cmd;
+#else /* LOWSPEED */
+#ifdef COUNT_LOOPS
+       int bytes = count;
+#endif /* COUNT_LOOPS */
+#endif /* LOWSPEED */
+
+#ifdef LOWSPEED
+#ifdef COUNT_LOOPS
+       tot_cnt = 0;
+#endif /* COUNT_LOOPS */
+       /* No further optimization useful, the limit is in the adapter. */
+       for ( ; count > 0; --count, ++buffer) {
+               de620_put_byte(dev,*buffer);
+       }
+       for ( count = pad ; count > 0; --count, ++buffer) {
+               de620_put_byte(dev, 0);
+       }
+       de620_send_command(dev,W_DUMMY);
+#ifdef COUNT_LOOPS
+       /* trial debug output: loops per byte in de620_ready() */
+       printk("WRITE(%d)\n", tot_cnt/((bytes?bytes:1)));
+#endif /* COUNT_LOOPS */
+#else /* not LOWSPEED */
+       for ( ; count > 0; count -=2) {
+               outb(*buffer++, DATA_PORT);
+               outb(uflip, COMMAND_PORT);
+               outb(*buffer++, DATA_PORT);
+               outb(dflip, COMMAND_PORT);
+       }
+       de620_send_command(dev,W_DUMMY);
+#endif /* LOWSPEED */
+}
+
+static inline void
+de620_read_block(struct net_device *dev, byte *data, int count)
+{
+#ifndef LOWSPEED
+       byte value;
+       byte uflip = NIC_Cmd ^ (DS0 | DS1);
+       byte dflip = NIC_Cmd;
+#else /* LOWSPEED */
+#ifdef COUNT_LOOPS
+       int bytes = count;
+
+       tot_cnt = 0;
+#endif /* COUNT_LOOPS */
+#endif /* LOWSPEED */
+
+#ifdef LOWSPEED
+       /* No further optimization useful, the limit is in the adapter. */
+       while (count-- > 0) {
+               *data++ = de620_read_byte(dev);
+               de620_flip_ds(dev);
+       }
+#ifdef COUNT_LOOPS
+       /* trial debug output: loops per byte in de620_ready() */
+       printk("READ(%d)\n", tot_cnt/(2*(bytes?bytes:1)));
+#endif /* COUNT_LOOPS */
+#else /* not LOWSPEED */
+       while (count-- > 0) {
+               value = inb(STATUS_PORT) & 0xf0; /* High nibble */
+               outb(uflip, COMMAND_PORT);
+               *data++ = value | inb(STATUS_PORT) >> 4; /* Low nibble */
+               outb(dflip , COMMAND_PORT);
+       }
+#endif /* LOWSPEED */
+}
+
+static inline void
+de620_set_delay(struct net_device *dev)
+{
+       de620_ready(dev);
+       outb(W_DFR, DATA_PORT);
+       outb(NIC_Cmd ^ CS0, COMMAND_PORT);
+
+       de620_ready(dev);
+#ifdef LOWSPEED
+       outb(WRITE_DELAY, DATA_PORT);
+#else
+       outb(0, DATA_PORT);
+#endif
+       de620_flip_ds(dev);
+
+       de620_ready(dev);
+#ifdef LOWSPEED
+       outb(READ_DELAY, DATA_PORT);
+#else
+       outb(0, DATA_PORT);
+#endif
+       de620_flip_ds(dev);
+}
+
+static inline void
+de620_set_register(struct net_device *dev, byte reg, byte value)
+{
+       de620_ready(dev);
+       outb(reg, DATA_PORT);
+       outb(NIC_Cmd ^ CS0, COMMAND_PORT);
+
+       de620_put_byte(dev, value);
+}
+
+static inline byte
+de620_get_register(struct net_device *dev, byte reg)
+{
+       byte value;
+
+       de620_send_command(dev,reg);
+       value = de620_read_byte(dev);
+       de620_send_command(dev,W_DUMMY);
+
+       return value;
+}
+
+/*********************************************************************
+ *
+ * Open/initialize the board.
+ *
+ * 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 a non-reboot way to recover if something goes wrong.
+ *
+ */
+static int de620_open(struct net_device *dev)
+{
+       int ret = request_irq(dev->irq, de620_interrupt, 0, dev->name, dev);
+       if (ret) {
+               printk (KERN_ERR "%s: unable to get IRQ %d\n", dev->name, dev->irq);
+               return ret;
+       }
+
+       if (adapter_init(dev)) {
+               ret = -EIO;
+               goto out_free_irq;
+       }
+
+       netif_start_queue(dev);
+       return 0;
+
+out_free_irq:
+       free_irq(dev->irq, dev);
+       return ret;
+}
+
+/************************************************
+ *
+ * The inverse routine to de620_open().
+ *
+ */
+
+static int de620_close(struct net_device *dev)
+{
+       netif_stop_queue(dev);
+       /* disable recv */
+       de620_set_register(dev, W_TCR, RXOFF);
+       free_irq(dev->irq, dev);
+       return 0;
+}
+
+/*********************************************
+ *
+ * Set or clear the multicast filter for this adaptor.
+ * (no real multicast implemented for the DE-620, but she can be promiscuous...)
+ *
+ */
+
+static void de620_set_multicast_list(struct net_device *dev)
+{
+       if (!netdev_mc_empty(dev) || dev->flags&(IFF_ALLMULTI|IFF_PROMISC))
+       { /* Enable promiscuous mode */
+               de620_set_register(dev, W_TCR, (TCR_DEF & ~RXPBM) | RXALL);
+       }
+       else
+       { /* Disable promiscuous mode, use normal mode */
+               de620_set_register(dev, W_TCR, TCR_DEF);
+       }
+}
+
+/*******************************************************
+ *
+ * Handle timeouts on transmit
+ */
+
+static void de620_timeout(struct net_device *dev)
+{
+       printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name, "network cable problem");
+       /* Restart the adapter. */
+       if (!adapter_init(dev)) /* maybe close it */
+               netif_wake_queue(dev);
+}
+
+/*******************************************************
+ *
+ * Copy a buffer to the adapter transmit page memory.
+ * Start sending.
+ */
+static int de620_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       unsigned long flags;
+       int len;
+       byte *buffer = skb->data;
+       byte using_txbuf;
+
+       using_txbuf = de620_tx_buffs(dev); /* Peek at the adapter */
+
+       netif_stop_queue(dev);
+
+
+       if ((len = skb->len) < RUNT)
+               len = RUNT;
+       if (len & 1) /* send an even number of bytes */
+               ++len;
+
+       /* Start real output */
+
+       spin_lock_irqsave(&de620_lock, flags);
+       pr_debug("de620_start_xmit: len=%d, bufs 0x%02x\n",
+               (int)skb->len, using_txbuf);
+
+       /* select a free tx buffer. if there is one... */
+       switch (using_txbuf) {
+       default: /* both are free: use TXBF0 */
+       case TXBF1: /* use TXBF0 */
+               de620_send_command(dev,W_CR | RW0);
+               using_txbuf |= TXBF0;
+               break;
+
+       case TXBF0: /* use TXBF1 */
+               de620_send_command(dev,W_CR | RW1);
+               using_txbuf |= TXBF1;
+               break;
+
+       case (TXBF0 | TXBF1): /* NONE!!! */
+               printk(KERN_WARNING "%s: No tx-buffer available!\n", dev->name);
+               spin_unlock_irqrestore(&de620_lock, flags);
+               return NETDEV_TX_BUSY;
+       }
+       de620_write_block(dev, buffer, skb->len, len-skb->len);
+
+       if(!(using_txbuf == (TXBF0 | TXBF1)))
+               netif_wake_queue(dev);
+
+       dev->stats.tx_packets++;
+       spin_unlock_irqrestore(&de620_lock, flags);
+       dev_kfree_skb (skb);
+       return NETDEV_TX_OK;
+}
+
+/*****************************************************
+ *
+ * Handle the network interface interrupts.
+ *
+ */
+static irqreturn_t
+de620_interrupt(int irq_in, void *dev_id)
+{
+       struct net_device *dev = dev_id;
+       byte irq_status;
+       int bogus_count = 0;
+       int again = 0;
+
+       spin_lock(&de620_lock);
+
+       /* Read the status register (_not_ the status port) */
+       irq_status = de620_get_register(dev, R_STS);
+
+       pr_debug("de620_interrupt (%2.2X)\n", irq_status);
+
+       if (irq_status & RXGOOD) {
+               do {
+                       again = de620_rx_intr(dev);
+                       pr_debug("again=%d\n", again);
+               }
+               while (again && (++bogus_count < 100));
+       }
+
+       if(de620_tx_buffs(dev) != (TXBF0 | TXBF1))
+               netif_wake_queue(dev);
+
+       spin_unlock(&de620_lock);
+       return IRQ_HANDLED;
+}
+
+/**************************************
+ *
+ * Get a packet from the adapter
+ *
+ * Send it "upstairs"
+ *
+ */
+static int de620_rx_intr(struct net_device *dev)
+{
+       struct header_buf {
+               byte            status;
+               byte            Rx_NextPage;
+               unsigned short  Rx_ByteCount;
+       } header_buf;
+       struct sk_buff *skb;
+       int size;
+       byte *buffer;
+       byte pagelink;
+       byte curr_page;
+
+       pr_debug("de620_rx_intr: next_rx_page = %d\n", next_rx_page);
+
+       /* Tell the adapter that we are going to read data, and from where */
+       de620_send_command(dev, W_CR | RRN);
+       de620_set_register(dev, W_RSA1, next_rx_page);
+       de620_set_register(dev, W_RSA0, 0);
+
+       /* Deep breath, and away we goooooo */
+       de620_read_block(dev, (byte *)&header_buf, sizeof(struct header_buf));
+       pr_debug("page status=0x%02x, nextpage=%d, packetsize=%d\n",
+               header_buf.status, header_buf.Rx_NextPage,
+               header_buf.Rx_ByteCount);
+
+       /* Plausible page header? */
+       pagelink = header_buf.Rx_NextPage;
+       if ((pagelink < first_rx_page) || (last_rx_page < pagelink)) {
+               /* Ouch... Forget it! Skip all and start afresh... */
+               printk(KERN_WARNING "%s: Ring overrun? Restoring...\n", dev->name);
+               /* You win some, you lose some. And sometimes plenty... */
+               adapter_init(dev);
+               netif_wake_queue(dev);
+               dev->stats.rx_over_errors++;
+               return 0;
+       }
+
+       /* OK, this look good, so far. Let's see if it's consistent... */
+       /* Let's compute the start of the next packet, based on where we are */
+       pagelink = next_rx_page +
+               ((header_buf.Rx_ByteCount + (4 - 1 + 0x100)) >> 8);
+
+       /* Are we going to wrap around the page counter? */
+       if (pagelink > last_rx_page)
+               pagelink -= (last_rx_page - first_rx_page + 1);
+
+       /* Is the _computed_ next page number equal to what the adapter says? */
+       if (pagelink != header_buf.Rx_NextPage) {
+               /* Naah, we'll skip this packet. Probably bogus data as well */
+               printk(KERN_WARNING "%s: Page link out of sync! Restoring...\n", dev->name);
+               next_rx_page = header_buf.Rx_NextPage; /* at least a try... */
+               de620_send_command(dev, W_DUMMY);
+               de620_set_register(dev, W_NPRF, next_rx_page);
+               dev->stats.rx_over_errors++;
+               return 0;
+       }
+       next_rx_page = pagelink;
+
+       size = header_buf.Rx_ByteCount - 4;
+       if ((size < RUNT) || (GIANT < size)) {
+               printk(KERN_WARNING "%s: Illegal packet size: %d!\n", dev->name, size);
+       }
+       else { /* Good packet? */
+               skb = dev_alloc_skb(size+2);
+               if (skb == NULL) { /* Yeah, but no place to put it... */
+                       printk(KERN_WARNING "%s: Couldn't allocate a sk_buff of size %d.\n", dev->name, size);
+                       dev->stats.rx_dropped++;
+               }
+               else { /* Yep! Go get it! */
+                       skb_reserve(skb,2);     /* Align */
+                       /* skb->data points to the start of sk_buff data area */
+                       buffer = skb_put(skb,size);
+                       /* copy the packet into the buffer */
+                       de620_read_block(dev, buffer, size);
+                       pr_debug("Read %d bytes\n", size);
+                       skb->protocol=eth_type_trans(skb,dev);
+                       netif_rx(skb); /* deliver it "upstairs" */
+                       /* count all receives */
+                       dev->stats.rx_packets++;
+                       dev->stats.rx_bytes += size;
+               }
+       }
+
+       /* Let's peek ahead to see if we have read the last current packet */
+       /* NOTE! We're _not_ checking the 'EMPTY'-flag! This seems better... */
+       curr_page = de620_get_register(dev, R_CPR);
+       de620_set_register(dev, W_NPRF, next_rx_page);
+       pr_debug("next_rx_page=%d CPR=%d\n", next_rx_page, curr_page);
+
+       return next_rx_page != curr_page; /* That was slightly tricky... */
+}
+
+/*********************************************
+ *
+ * Reset the adapter to a known state
+ *
+ */
+static int adapter_init(struct net_device *dev)
+{
+       int i;
+       static int was_down;
+
+       if ((nic_data.Model == 3) || (nic_data.Model == 0)) { /* CT */
+               EIPRegister = NCTL0;
+               if (nic_data.Media != 1)
+                       EIPRegister |= NIS0;    /* not BNC */
+       }
+       else if (nic_data.Model == 2) { /* UTP */
+               EIPRegister = NCTL0 | NIS0;
+       }
+
+       if (utp)
+               EIPRegister = NCTL0 | NIS0;
+       if (bnc)
+               EIPRegister = NCTL0;
+
+       de620_send_command(dev, W_CR | RNOP | CLEAR);
+       de620_send_command(dev, W_CR | RNOP);
+
+       de620_set_register(dev, W_SCR, SCR_DEF);
+       /* disable recv to wait init */
+       de620_set_register(dev, W_TCR, RXOFF);
+
+       /* Set the node ID in the adapter */
+       for (i = 0; i < 6; ++i) { /* W_PARn = 0xaa + n */
+               de620_set_register(dev, W_PAR0 + i, dev->dev_addr[i]);
+       }
+
+       de620_set_register(dev, W_EIP, EIPRegister);
+
+       next_rx_page = first_rx_page = DE620_RX_START_PAGE;
+       if (nic_data.RAM_Size)
+               last_rx_page = nic_data.RAM_Size - 1;
+       else /* 64k RAM */
+               last_rx_page = 255;
+
+       de620_set_register(dev, W_SPR, first_rx_page); /* Start Page Register*/
+       de620_set_register(dev, W_EPR, last_rx_page);  /* End Page Register */
+       de620_set_register(dev, W_CPR, first_rx_page);/*Current Page Register*/
+       de620_send_command(dev, W_NPR | first_rx_page); /* Next Page Register*/
+       de620_send_command(dev, W_DUMMY);
+       de620_set_delay(dev);
+
+       /* Final sanity check: Anybody out there? */
+       /* Let's hope some bits from the statusregister make a good check */
+#define CHECK_MASK (  0 | TXSUC |  T16  |  0  | RXCRC | RXSHORT |  0  |  0  )
+#define CHECK_OK   (  0 |   0   |  0    |  0  |   0   |   0     |  0  |  0  )
+        /* success:   X     0      0       X      0       0        X     X  */
+        /* ignore:   EEDI                RXGOOD                   COLS  LNKS*/
+
+       if (((i = de620_get_register(dev, R_STS)) & CHECK_MASK) != CHECK_OK) {
+               printk(KERN_ERR "%s: Something has happened to the DE-620!  Please check it"
+#ifdef SHUTDOWN_WHEN_LOST
+                       " and do a new ifconfig"
+#endif
+                       "! (%02x)\n", dev->name, i);
+#ifdef SHUTDOWN_WHEN_LOST
+               /* Goodbye, cruel world... */
+               dev->flags &= ~IFF_UP;
+               de620_close(dev);
+#endif
+               was_down = 1;
+               return 1; /* failed */
+       }
+       if (was_down) {
+               printk(KERN_WARNING "%s: Thanks, I feel much better now!\n", dev->name);
+               was_down = 0;
+       }
+
+       /* All OK, go ahead... */
+       de620_set_register(dev, W_TCR, TCR_DEF);
+
+       return 0; /* all ok */
+}
+
+static const struct net_device_ops de620_netdev_ops = {
+       .ndo_open               = de620_open,
+       .ndo_stop               = de620_close,
+       .ndo_start_xmit         = de620_start_xmit,
+       .ndo_tx_timeout         = de620_timeout,
+       .ndo_set_multicast_list = de620_set_multicast_list,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
+/******************************************************************************
+ *
+ * Only start-up code below
+ *
+ */
+/****************************************
+ *
+ * Check if there is a DE-620 connected
+ */
+struct net_device * __init de620_probe(int unit)
+{
+       byte checkbyte = 0xa5;
+       struct net_device *dev;
+       int err = -ENOMEM;
+       int i;
+
+       dev = alloc_etherdev(0);
+       if (!dev)
+               goto out;
+
+       spin_lock_init(&de620_lock);
+
+       /*
+        * This is where the base_addr and irq gets set.
+        * Tunable at compile-time and insmod-time
+        */
+       dev->base_addr = io;
+       dev->irq       = irq;
+
+       /* allow overriding parameters on command line */
+       if (unit >= 0) {
+               sprintf(dev->name, "eth%d", unit);
+               netdev_boot_setup_check(dev);
+       }
+
+       pr_debug("%s", version);
+
+       printk(KERN_INFO "D-Link DE-620 pocket adapter");
+
+       if (!request_region(dev->base_addr, 3, "de620")) {
+               printk(" io 0x%3lX, which is busy.\n", dev->base_addr);
+               err = -EBUSY;
+               goto out1;
+       }
+
+       /* Initially, configure basic nibble mode, so we can read the EEPROM */
+       NIC_Cmd = DEF_NIC_CMD;
+       de620_set_register(dev, W_EIP, EIPRegister);
+
+       /* Anybody out there? */
+       de620_set_register(dev, W_CPR, checkbyte);
+       checkbyte = de620_get_register(dev, R_CPR);
+
+       if ((checkbyte != 0xa5) || (read_eeprom(dev) != 0)) {
+               printk(" not identified in the printer port\n");
+               err = -ENODEV;
+               goto out2;
+       }
+
+       /* else, got it! */
+       dev->dev_addr[0] = nic_data.NodeID[0];
+       for (i = 1; i < ETH_ALEN; i++) {
+               dev->dev_addr[i] = nic_data.NodeID[i];
+               dev->broadcast[i] = 0xff;
+       }
+
+       printk(", Ethernet Address: %pM", dev->dev_addr);
+
+       printk(" (%dk RAM,",
+               (nic_data.RAM_Size) ? (nic_data.RAM_Size >> 2) : 64);
+
+       if (nic_data.Media == 1)
+               printk(" BNC)\n");
+       else
+               printk(" UTP)\n");
+
+       dev->netdev_ops = &de620_netdev_ops;
+       dev->watchdog_timeo     = HZ*2;
+
+       /* base_addr and irq are already set, see above! */
+
+       /* dump eeprom */
+       pr_debug("\nEEPROM contents:\n"
+               "RAM_Size = 0x%02X\n"
+               "NodeID = %pM\n"
+               "Model = %d\n"
+               "Media = %d\n"
+               "SCR = 0x%02x\n", nic_data.RAM_Size, nic_data.NodeID,
+               nic_data.Model, nic_data.Media, nic_data.SCR);
+
+       err = register_netdev(dev);
+       if (err)
+               goto out2;
+       return dev;
+
+out2:
+       release_region(dev->base_addr, 3);
+out1:
+       free_netdev(dev);
+out:
+       return ERR_PTR(err);
+}
+
+/**********************************
+ *
+ * Read info from on-board EEPROM
+ *
+ * Note: Bitwise serial I/O to/from the EEPROM vi the status _register_!
+ */
+#define sendit(dev,data) de620_set_register(dev, W_EIP, data | EIPRegister);
+
+static unsigned short __init ReadAWord(struct net_device *dev, int from)
+{
+       unsigned short data;
+       int nbits;
+
+       /* cs   [__~~] SET SEND STATE */
+       /* di   [____]                */
+       /* sck  [_~~_]                */
+       sendit(dev, 0); sendit(dev, 1); sendit(dev, 5); sendit(dev, 4);
+
+       /* Send the 9-bit address from where we want to read the 16-bit word */
+       for (nbits = 9; nbits > 0; --nbits, from <<= 1) {
+               if (from & 0x0100) { /* bit set? */
+                       /* cs    [~~~~] SEND 1 */
+                       /* di    [~~~~]        */
+                       /* sck   [_~~_]        */
+                       sendit(dev, 6); sendit(dev, 7); sendit(dev, 7); sendit(dev, 6);
+               }
+               else {
+                       /* cs    [~~~~] SEND 0 */
+                       /* di    [____]        */
+                       /* sck   [_~~_]        */
+                       sendit(dev, 4); sendit(dev, 5); sendit(dev, 5); sendit(dev, 4);
+               }
+       }
+
+       /* Shift in the 16-bit word. The bits appear serially in EEDI (=0x80) */
+       for (data = 0, nbits = 16; nbits > 0; --nbits) {
+               /* cs    [~~~~] SEND 0 */
+               /* di    [____]        */
+               /* sck   [_~~_]        */
+               sendit(dev, 4); sendit(dev, 5); sendit(dev, 5); sendit(dev, 4);
+               data = (data << 1) | ((de620_get_register(dev, R_STS) & EEDI) >> 7);
+       }
+       /* cs    [____] RESET SEND STATE */
+       /* di    [____]                  */
+       /* sck   [_~~_]                  */
+       sendit(dev, 0); sendit(dev, 1); sendit(dev, 1); sendit(dev, 0);
+
+       return data;
+}
+
+static int __init read_eeprom(struct net_device *dev)
+{
+       unsigned short wrd;
+
+       /* D-Link Ethernet addresses are in the series  00:80:c8:7X:XX:XX:XX */
+       wrd = ReadAWord(dev, 0x1aa);    /* bytes 0 + 1 of NodeID */
+       if (!clone && (wrd != htons(0x0080))) /* Valid D-Link ether sequence? */
+               return -1; /* Nope, not a DE-620 */
+       nic_data.NodeID[0] = wrd & 0xff;
+       nic_data.NodeID[1] = wrd >> 8;
+
+       wrd = ReadAWord(dev, 0x1ab);    /* bytes 2 + 3 of NodeID */
+       if (!clone && ((wrd & 0xff) != 0xc8)) /* Valid D-Link ether sequence? */
+               return -1; /* Nope, not a DE-620 */
+       nic_data.NodeID[2] = wrd & 0xff;
+       nic_data.NodeID[3] = wrd >> 8;
+
+       wrd = ReadAWord(dev, 0x1ac);    /* bytes 4 + 5 of NodeID */
+       nic_data.NodeID[4] = wrd & 0xff;
+       nic_data.NodeID[5] = wrd >> 8;
+
+       wrd = ReadAWord(dev, 0x1ad);    /* RAM size in pages (256 bytes). 0 = 64k */
+       nic_data.RAM_Size = (wrd >> 8);
+
+       wrd = ReadAWord(dev, 0x1ae);    /* hardware model (CT = 3) */
+       nic_data.Model = (wrd & 0xff);
+
+       wrd = ReadAWord(dev, 0x1af); /* media (indicates BNC/UTP) */
+       nic_data.Media = (wrd & 0xff);
+
+       wrd = ReadAWord(dev, 0x1a8); /* System Configuration Register */
+       nic_data.SCR = (wrd >> 8);
+
+       return 0; /* no errors */
+}
+
+/******************************************************************************
+ *
+ * Loadable module skeleton
+ *
+ */
+#ifdef MODULE
+static struct net_device *de620_dev;
+
+int __init init_module(void)
+{
+       de620_dev = de620_probe(-1);
+       if (IS_ERR(de620_dev))
+               return PTR_ERR(de620_dev);
+       return 0;
+}
+
+void cleanup_module(void)
+{
+       unregister_netdev(de620_dev);
+       release_region(de620_dev->base_addr, 3);
+       free_netdev(de620_dev);
+}
+#endif /* MODULE */
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/dlink/de620.h b/drivers/net/ethernet/dlink/de620.h
new file mode 100644 (file)
index 0000000..e8d9a88
--- /dev/null
@@ -0,0 +1,117 @@
+/*********************************************************
+ *                                                       *
+ * Definition of D-Link DE-620 Ethernet Pocket adapter   *
+ *                                                       *
+ *********************************************************/
+
+/* DE-620's CMD port Command */
+#define CS0            0x08    /* 1->0 command strobe */
+#define ICEN           0x04    /* 0=enable DL3520 host interface */
+#define DS0            0x02    /* 1->0 data strobe 0 */
+#define DS1            0x01    /* 1->0 data strobe 1 */
+
+#define WDIR           0x20    /* general 0=read  1=write */
+#define RDIR           0x00    /*  (not 100% confirm ) */
+#define PS2WDIR                0x00    /* ps/2 mode 1=read, 0=write */
+#define PS2RDIR                0x20
+
+#define IRQEN          0x10    /* 1 = enable printer IRQ line */
+#define SELECTIN       0x08    /* 1 = select printer */
+#define INITP          0x04    /* 0 = initial printer */
+#define AUTOFEED       0x02    /* 1 = printer auto form feed */
+#define STROBE         0x01    /* 0->1 data strobe */
+
+#define RESET          0x08
+#define NIS0           0x20    /* 0 = BNC, 1 = UTP */
+#define NCTL0          0x10
+
+/* DE-620 DIC Command */
+#define W_DUMMY                0x00    /* DIC reserved command */
+#define W_CR           0x20    /* DIC write command register */
+#define W_NPR          0x40    /* DIC write Next Page Register */
+#define W_TBR          0x60    /* DIC write Tx Byte Count 1 reg */
+#define W_RSA          0x80    /* DIC write Remote Start Addr 1 */
+
+/* DE-620's STAT port bits 7-4 */
+#define EMPTY          0x80    /* 1 = receive buffer empty */
+#define INTLEVEL       0x40    /* 1 = interrupt level is high */
+#define TXBF1          0x20    /* 1 = transmit buffer 1 is in use */
+#define TXBF0          0x10    /* 1 = transmit buffer 0 is in use */
+#define READY          0x08    /* 1 = h/w ready to accept cmd/data */
+
+/* IDC 1 Command */
+#define        W_RSA1          0xa0    /* write remote start address 1 */
+#define        W_RSA0          0xa1    /* write remote start address 0 */
+#define        W_NPRF          0xa2    /* write next page register NPR15-NPR8 */
+#define        W_DFR           0xa3    /* write delay factor register */
+#define        W_CPR           0xa4    /* write current page register */
+#define        W_SPR           0xa5    /* write start page register */
+#define        W_EPR           0xa6    /* write end page register */
+#define        W_SCR           0xa7    /* write system configuration register */
+#define        W_TCR           0xa8    /* write Transceiver Configuration reg */
+#define        W_EIP           0xa9    /* write EEPM Interface port */
+#define        W_PAR0          0xaa    /* write physical address register 0 */
+#define        W_PAR1          0xab    /* write physical address register 1 */
+#define        W_PAR2          0xac    /* write physical address register 2 */
+#define        W_PAR3          0xad    /* write physical address register 3 */
+#define        W_PAR4          0xae    /* write physical address register 4 */
+#define        W_PAR5          0xaf    /* write physical address register 5 */
+
+/* IDC 2 Command */
+#define        R_STS           0xc0    /* read status register */
+#define        R_CPR           0xc1    /* read current page register */
+#define        R_BPR           0xc2    /* read boundary page register */
+#define        R_TDR           0xc3    /* read time domain reflectometry reg */
+
+/* STATUS Register */
+#define EEDI           0x80    /* EEPM DO pin */
+#define TXSUC          0x40    /* tx success */
+#define T16            0x20    /* tx fail 16 times */
+#define TS1            0x40    /* 0=Tx success, 1=T16 */
+#define TS0            0x20    /* 0=Tx success, 1=T16 */
+#define RXGOOD         0x10    /* rx a good packet */
+#define RXCRC          0x08    /* rx a CRC error packet */
+#define RXSHORT                0x04    /* rx a short packet */
+#define COLS           0x02    /* coaxial collision status */
+#define LNKS           0x01    /* UTP link status */
+
+/* Command Register */
+#define CLEAR          0x10    /* reset part of hardware */
+#define NOPER          0x08    /* No Operation */
+#define RNOP           0x08
+#define RRA            0x06    /* After RR then auto-advance NPR & BPR(=NPR-1) */
+#define RRN            0x04    /* Normal Remote Read mode */
+#define RW1            0x02    /* Remote Write tx buffer 1  ( page 6 - 11 ) */
+#define RW0            0x00    /* Remote Write tx buffer 0  ( page 0 - 5 ) */
+#define TXEN           0x01    /* 0->1 tx enable */
+
+/* System Configuration Register */
+#define TESTON         0x80    /* test host data transfer reliability */
+#define SLEEP          0x40    /* sleep mode */
+#if 0
+#define FASTMODE       0x04    /* fast mode for intel 82360SL fast mode */
+#define BYTEMODE       0x02    /* byte mode */
+#else
+#define FASTMODE       0x20    /* fast mode for intel 82360SL fast mode */
+#define BYTEMODE       0x10    /* byte mode */
+#endif
+#define NIBBLEMODE     0x00    /* nibble mode */
+#define IRQINV         0x08    /* turn off IRQ line inverter */
+#define IRQNML         0x00    /* turn on IRQ line inverter */
+#define INTON          0x04
+#define AUTOFFSET      0x02    /* auto shift address to TPR+12 */
+#define AUTOTX         0x01    /* auto tx when leave RW mode */
+
+/* Transceiver Configuration Register */
+#define JABBER         0x80    /* generate jabber condition */
+#define TXSUCINT       0x40    /* enable tx success interrupt */
+#define T16INT         0x20    /* enable T16 interrupt */
+#define RXERRPKT       0x10    /* accept CRC error or short packet */
+#define EXTERNALB2     0x0C    /* external loopback 2 */
+#define EXTERNALB1     0x08    /* external loopback 1 */
+#define INTERNALB      0x04    /* internal loopback */
+#define NMLOPERATE     0x00    /* normal operation */
+#define RXPBM          0x03    /* rx physical, broadcast, multicast */
+#define RXPB           0x02    /* rx physical, broadcast */
+#define RXALL          0x01    /* rx all packet */
+#define RXOFF          0x00    /* rx disable */
diff --git a/drivers/net/ethernet/dlink/dl2k.c b/drivers/net/ethernet/dlink/dl2k.c
new file mode 100644 (file)
index 0000000..ed73e4a
--- /dev/null
@@ -0,0 +1,1824 @@
+/*  D-Link DL2000-based Gigabit Ethernet Adapter Linux driver */
+/*
+    Copyright (c) 2001, 2002 by D-Link Corporation
+    Written by Edward Peng.<edward_peng@dlink.com.tw>
+    Created 03-May-2001, base on Linux' sundance.c.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+*/
+
+#define DRV_NAME       "DL2000/TC902x-based linux driver"
+#define DRV_VERSION    "v1.19"
+#define DRV_RELDATE    "2007/08/12"
+#include "dl2k.h"
+#include <linux/dma-mapping.h>
+
+static char version[] __devinitdata =
+      KERN_INFO DRV_NAME " " DRV_VERSION " " DRV_RELDATE "\n";
+#define MAX_UNITS 8
+static int mtu[MAX_UNITS];
+static int vlan[MAX_UNITS];
+static int jumbo[MAX_UNITS];
+static char *media[MAX_UNITS];
+static int tx_flow=-1;
+static int rx_flow=-1;
+static int copy_thresh;
+static int rx_coalesce=10;     /* Rx frame count each interrupt */
+static int rx_timeout=200;     /* Rx DMA wait time in 640ns increments */
+static int tx_coalesce=16;     /* HW xmit count each TxDMAComplete */
+
+
+MODULE_AUTHOR ("Edward Peng");
+MODULE_DESCRIPTION ("D-Link DL2000-based Gigabit Ethernet Adapter");
+MODULE_LICENSE("GPL");
+module_param_array(mtu, int, NULL, 0);
+module_param_array(media, charp, NULL, 0);
+module_param_array(vlan, int, NULL, 0);
+module_param_array(jumbo, int, NULL, 0);
+module_param(tx_flow, int, 0);
+module_param(rx_flow, int, 0);
+module_param(copy_thresh, int, 0);
+module_param(rx_coalesce, int, 0);     /* Rx frame count each interrupt */
+module_param(rx_timeout, int, 0);      /* Rx DMA wait time in 64ns increments */
+module_param(tx_coalesce, int, 0); /* HW xmit count each TxDMAComplete */
+
+
+/* Enable the default interrupts */
+#define DEFAULT_INTR (RxDMAComplete | HostError | IntRequested | TxDMAComplete| \
+       UpdateStats | LinkEvent)
+#define EnableInt() \
+writew(DEFAULT_INTR, ioaddr + IntEnable)
+
+static const int max_intrloop = 50;
+static const int multicast_filter_limit = 0x40;
+
+static int rio_open (struct net_device *dev);
+static void rio_timer (unsigned long data);
+static void rio_tx_timeout (struct net_device *dev);
+static void alloc_list (struct net_device *dev);
+static netdev_tx_t start_xmit (struct sk_buff *skb, struct net_device *dev);
+static irqreturn_t rio_interrupt (int irq, void *dev_instance);
+static void rio_free_tx (struct net_device *dev, int irq);
+static void tx_error (struct net_device *dev, int tx_status);
+static int receive_packet (struct net_device *dev);
+static void rio_error (struct net_device *dev, int int_status);
+static int change_mtu (struct net_device *dev, int new_mtu);
+static void set_multicast (struct net_device *dev);
+static struct net_device_stats *get_stats (struct net_device *dev);
+static int clear_stats (struct net_device *dev);
+static int rio_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
+static int rio_close (struct net_device *dev);
+static int find_miiphy (struct net_device *dev);
+static int parse_eeprom (struct net_device *dev);
+static int read_eeprom (long ioaddr, int eep_addr);
+static int mii_wait_link (struct net_device *dev, int wait);
+static int mii_set_media (struct net_device *dev);
+static int mii_get_media (struct net_device *dev);
+static int mii_set_media_pcs (struct net_device *dev);
+static int mii_get_media_pcs (struct net_device *dev);
+static int mii_read (struct net_device *dev, int phy_addr, int reg_num);
+static int mii_write (struct net_device *dev, int phy_addr, int reg_num,
+                     u16 data);
+
+static const struct ethtool_ops ethtool_ops;
+
+static const struct net_device_ops netdev_ops = {
+       .ndo_open               = rio_open,
+       .ndo_start_xmit = start_xmit,
+       .ndo_stop               = rio_close,
+       .ndo_get_stats          = get_stats,
+       .ndo_validate_addr      = eth_validate_addr,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_set_multicast_list = set_multicast,
+       .ndo_do_ioctl           = rio_ioctl,
+       .ndo_tx_timeout         = rio_tx_timeout,
+       .ndo_change_mtu         = change_mtu,
+};
+
+static int __devinit
+rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+       struct net_device *dev;
+       struct netdev_private *np;
+       static int card_idx;
+       int chip_idx = ent->driver_data;
+       int err, irq;
+       long ioaddr;
+       static int version_printed;
+       void *ring_space;
+       dma_addr_t ring_dma;
+
+       if (!version_printed++)
+               printk ("%s", version);
+
+       err = pci_enable_device (pdev);
+       if (err)
+               return err;
+
+       irq = pdev->irq;
+       err = pci_request_regions (pdev, "dl2k");
+       if (err)
+               goto err_out_disable;
+
+       pci_set_master (pdev);
+       dev = alloc_etherdev (sizeof (*np));
+       if (!dev) {
+               err = -ENOMEM;
+               goto err_out_res;
+       }
+       SET_NETDEV_DEV(dev, &pdev->dev);
+
+#ifdef MEM_MAPPING
+       ioaddr = pci_resource_start (pdev, 1);
+       ioaddr = (long) ioremap (ioaddr, RIO_IO_SIZE);
+       if (!ioaddr) {
+               err = -ENOMEM;
+               goto err_out_dev;
+       }
+#else
+       ioaddr = pci_resource_start (pdev, 0);
+#endif
+       dev->base_addr = ioaddr;
+       dev->irq = irq;
+       np = netdev_priv(dev);
+       np->chip_id = chip_idx;
+       np->pdev = pdev;
+       spin_lock_init (&np->tx_lock);
+       spin_lock_init (&np->rx_lock);
+
+       /* Parse manual configuration */
+       np->an_enable = 1;
+       np->tx_coalesce = 1;
+       if (card_idx < MAX_UNITS) {
+               if (media[card_idx] != NULL) {
+                       np->an_enable = 0;
+                       if (strcmp (media[card_idx], "auto") == 0 ||
+                           strcmp (media[card_idx], "autosense") == 0 ||
+                           strcmp (media[card_idx], "0") == 0 ) {
+                               np->an_enable = 2;
+                       } else if (strcmp (media[card_idx], "100mbps_fd") == 0 ||
+                           strcmp (media[card_idx], "4") == 0) {
+                               np->speed = 100;
+                               np->full_duplex = 1;
+                       } else if (strcmp (media[card_idx], "100mbps_hd") == 0 ||
+                                  strcmp (media[card_idx], "3") == 0) {
+                               np->speed = 100;
+                               np->full_duplex = 0;
+                       } else if (strcmp (media[card_idx], "10mbps_fd") == 0 ||
+                                  strcmp (media[card_idx], "2") == 0) {
+                               np->speed = 10;
+                               np->full_duplex = 1;
+                       } else if (strcmp (media[card_idx], "10mbps_hd") == 0 ||
+                                  strcmp (media[card_idx], "1") == 0) {
+                               np->speed = 10;
+                               np->full_duplex = 0;
+                       } else if (strcmp (media[card_idx], "1000mbps_fd") == 0 ||
+                                strcmp (media[card_idx], "6") == 0) {
+                               np->speed=1000;
+                               np->full_duplex=1;
+                       } else if (strcmp (media[card_idx], "1000mbps_hd") == 0 ||
+                                strcmp (media[card_idx], "5") == 0) {
+                               np->speed = 1000;
+                               np->full_duplex = 0;
+                       } else {
+                               np->an_enable = 1;
+                       }
+               }
+               if (jumbo[card_idx] != 0) {
+                       np->jumbo = 1;
+                       dev->mtu = MAX_JUMBO;
+               } else {
+                       np->jumbo = 0;
+                       if (mtu[card_idx] > 0 && mtu[card_idx] < PACKET_SIZE)
+                               dev->mtu = mtu[card_idx];
+               }
+               np->vlan = (vlan[card_idx] > 0 && vlan[card_idx] < 4096) ?
+                   vlan[card_idx] : 0;
+               if (rx_coalesce > 0 && rx_timeout > 0) {
+                       np->rx_coalesce = rx_coalesce;
+                       np->rx_timeout = rx_timeout;
+                       np->coalesce = 1;
+               }
+               np->tx_flow = (tx_flow == 0) ? 0 : 1;
+               np->rx_flow = (rx_flow == 0) ? 0 : 1;
+
+               if (tx_coalesce < 1)
+                       tx_coalesce = 1;
+               else if (tx_coalesce > TX_RING_SIZE-1)
+                       tx_coalesce = TX_RING_SIZE - 1;
+       }
+       dev->netdev_ops = &netdev_ops;
+       dev->watchdog_timeo = TX_TIMEOUT;
+       SET_ETHTOOL_OPS(dev, &ethtool_ops);
+#if 0
+       dev->features = NETIF_F_IP_CSUM;
+#endif
+       pci_set_drvdata (pdev, dev);
+
+       ring_space = pci_alloc_consistent (pdev, TX_TOTAL_SIZE, &ring_dma);
+       if (!ring_space)
+               goto err_out_iounmap;
+       np->tx_ring = ring_space;
+       np->tx_ring_dma = ring_dma;
+
+       ring_space = pci_alloc_consistent (pdev, RX_TOTAL_SIZE, &ring_dma);
+       if (!ring_space)
+               goto err_out_unmap_tx;
+       np->rx_ring = ring_space;
+       np->rx_ring_dma = ring_dma;
+
+       /* Parse eeprom data */
+       parse_eeprom (dev);
+
+       /* Find PHY address */
+       err = find_miiphy (dev);
+       if (err)
+               goto err_out_unmap_rx;
+
+       /* Fiber device? */
+       np->phy_media = (readw(ioaddr + ASICCtrl) & PhyMedia) ? 1 : 0;
+       np->link_status = 0;
+       /* Set media and reset PHY */
+       if (np->phy_media) {
+               /* default Auto-Negotiation for fiber deivices */
+               if (np->an_enable == 2) {
+                       np->an_enable = 1;
+               }
+               mii_set_media_pcs (dev);
+       } else {
+               /* Auto-Negotiation is mandatory for 1000BASE-T,
+                  IEEE 802.3ab Annex 28D page 14 */
+               if (np->speed == 1000)
+                       np->an_enable = 1;
+               mii_set_media (dev);
+       }
+
+       err = register_netdev (dev);
+       if (err)
+               goto err_out_unmap_rx;
+
+       card_idx++;
+
+       printk (KERN_INFO "%s: %s, %pM, IRQ %d\n",
+               dev->name, np->name, dev->dev_addr, irq);
+       if (tx_coalesce > 1)
+               printk(KERN_INFO "tx_coalesce:\t%d packets\n",
+                               tx_coalesce);
+       if (np->coalesce)
+               printk(KERN_INFO
+                      "rx_coalesce:\t%d packets\n"
+                      "rx_timeout: \t%d ns\n",
+                               np->rx_coalesce, np->rx_timeout*640);
+       if (np->vlan)
+               printk(KERN_INFO "vlan(id):\t%d\n", np->vlan);
+       return 0;
+
+      err_out_unmap_rx:
+       pci_free_consistent (pdev, RX_TOTAL_SIZE, np->rx_ring, np->rx_ring_dma);
+      err_out_unmap_tx:
+       pci_free_consistent (pdev, TX_TOTAL_SIZE, np->tx_ring, np->tx_ring_dma);
+      err_out_iounmap:
+#ifdef MEM_MAPPING
+       iounmap ((void *) ioaddr);
+
+      err_out_dev:
+#endif
+       free_netdev (dev);
+
+      err_out_res:
+       pci_release_regions (pdev);
+
+      err_out_disable:
+       pci_disable_device (pdev);
+       return err;
+}
+
+static int
+find_miiphy (struct net_device *dev)
+{
+       int i, phy_found = 0;
+       struct netdev_private *np;
+       long ioaddr;
+       np = netdev_priv(dev);
+       ioaddr = dev->base_addr;
+       np->phy_addr = 1;
+
+       for (i = 31; i >= 0; i--) {
+               int mii_status = mii_read (dev, i, 1);
+               if (mii_status != 0xffff && mii_status != 0x0000) {
+                       np->phy_addr = i;
+                       phy_found++;
+               }
+       }
+       if (!phy_found) {
+               printk (KERN_ERR "%s: No MII PHY found!\n", dev->name);
+               return -ENODEV;
+       }
+       return 0;
+}
+
+static int
+parse_eeprom (struct net_device *dev)
+{
+       int i, j;
+       long ioaddr = dev->base_addr;
+       u8 sromdata[256];
+       u8 *psib;
+       u32 crc;
+       PSROM_t psrom = (PSROM_t) sromdata;
+       struct netdev_private *np = netdev_priv(dev);
+
+       int cid, next;
+
+#ifdef MEM_MAPPING
+       ioaddr = pci_resource_start (np->pdev, 0);
+#endif
+       /* Read eeprom */
+       for (i = 0; i < 128; i++) {
+               ((__le16 *) sromdata)[i] = cpu_to_le16(read_eeprom (ioaddr, i));
+       }
+#ifdef MEM_MAPPING
+       ioaddr = dev->base_addr;
+#endif
+       if (np->pdev->vendor == PCI_VENDOR_ID_DLINK) {  /* D-Link Only */
+               /* Check CRC */
+               crc = ~ether_crc_le (256 - 4, sromdata);
+               if (psrom->crc != cpu_to_le32(crc)) {
+                       printk (KERN_ERR "%s: EEPROM data CRC error.\n",
+                                       dev->name);
+                       return -1;
+               }
+       }
+
+       /* Set MAC address */
+       for (i = 0; i < 6; i++)
+               dev->dev_addr[i] = psrom->mac_addr[i];
+
+       if (np->pdev->vendor != PCI_VENDOR_ID_DLINK) {
+               return 0;
+       }
+
+       /* Parse Software Information Block */
+       i = 0x30;
+       psib = (u8 *) sromdata;
+       do {
+               cid = psib[i++];
+               next = psib[i++];
+               if ((cid == 0 && next == 0) || (cid == 0xff && next == 0xff)) {
+                       printk (KERN_ERR "Cell data error\n");
+                       return -1;
+               }
+               switch (cid) {
+               case 0: /* Format version */
+                       break;
+               case 1: /* End of cell */
+                       return 0;
+               case 2: /* Duplex Polarity */
+                       np->duplex_polarity = psib[i];
+                       writeb (readb (ioaddr + PhyCtrl) | psib[i],
+                               ioaddr + PhyCtrl);
+                       break;
+               case 3: /* Wake Polarity */
+                       np->wake_polarity = psib[i];
+                       break;
+               case 9: /* Adapter description */
+                       j = (next - i > 255) ? 255 : next - i;
+                       memcpy (np->name, &(psib[i]), j);
+                       break;
+               case 4:
+               case 5:
+               case 6:
+               case 7:
+               case 8: /* Reversed */
+                       break;
+               default:        /* Unknown cell */
+                       return -1;
+               }
+               i = next;
+       } while (1);
+
+       return 0;
+}
+
+static int
+rio_open (struct net_device *dev)
+{
+       struct netdev_private *np = netdev_priv(dev);
+       long ioaddr = dev->base_addr;
+       int i;
+       u16 macctrl;
+
+       i = request_irq (dev->irq, rio_interrupt, IRQF_SHARED, dev->name, dev);
+       if (i)
+               return i;
+
+       /* Reset all logic functions */
+       writew (GlobalReset | DMAReset | FIFOReset | NetworkReset | HostReset,
+               ioaddr + ASICCtrl + 2);
+       mdelay(10);
+
+       /* DebugCtrl bit 4, 5, 9 must set */
+       writel (readl (ioaddr + DebugCtrl) | 0x0230, ioaddr + DebugCtrl);
+
+       /* Jumbo frame */
+       if (np->jumbo != 0)
+               writew (MAX_JUMBO+14, ioaddr + MaxFrameSize);
+
+       alloc_list (dev);
+
+       /* Get station address */
+       for (i = 0; i < 6; i++)
+               writeb (dev->dev_addr[i], ioaddr + StationAddr0 + i);
+
+       set_multicast (dev);
+       if (np->coalesce) {
+               writel (np->rx_coalesce | np->rx_timeout << 16,
+                       ioaddr + RxDMAIntCtrl);
+       }
+       /* Set RIO to poll every N*320nsec. */
+       writeb (0x20, ioaddr + RxDMAPollPeriod);
+       writeb (0xff, ioaddr + TxDMAPollPeriod);
+       writeb (0x30, ioaddr + RxDMABurstThresh);
+       writeb (0x30, ioaddr + RxDMAUrgentThresh);
+       writel (0x0007ffff, ioaddr + RmonStatMask);
+       /* clear statistics */
+       clear_stats (dev);
+
+       /* VLAN supported */
+       if (np->vlan) {
+               /* priority field in RxDMAIntCtrl  */
+               writel (readl(ioaddr + RxDMAIntCtrl) | 0x7 << 10,
+                       ioaddr + RxDMAIntCtrl);
+               /* VLANId */
+               writew (np->vlan, ioaddr + VLANId);
+               /* Length/Type should be 0x8100 */
+               writel (0x8100 << 16 | np->vlan, ioaddr + VLANTag);
+               /* Enable AutoVLANuntagging, but disable AutoVLANtagging.
+                  VLAN information tagged by TFC' VID, CFI fields. */
+               writel (readl (ioaddr + MACCtrl) | AutoVLANuntagging,
+                       ioaddr + MACCtrl);
+       }
+
+       init_timer (&np->timer);
+       np->timer.expires = jiffies + 1*HZ;
+       np->timer.data = (unsigned long) dev;
+       np->timer.function = rio_timer;
+       add_timer (&np->timer);
+
+       /* Start Tx/Rx */
+       writel (readl (ioaddr + MACCtrl) | StatsEnable | RxEnable | TxEnable,
+                       ioaddr + MACCtrl);
+
+       macctrl = 0;
+       macctrl |= (np->vlan) ? AutoVLANuntagging : 0;
+       macctrl |= (np->full_duplex) ? DuplexSelect : 0;
+       macctrl |= (np->tx_flow) ? TxFlowControlEnable : 0;
+       macctrl |= (np->rx_flow) ? RxFlowControlEnable : 0;
+       writew(macctrl, ioaddr + MACCtrl);
+
+       netif_start_queue (dev);
+
+       /* Enable default interrupts */
+       EnableInt ();
+       return 0;
+}
+
+static void
+rio_timer (unsigned long data)
+{
+       struct net_device *dev = (struct net_device *)data;
+       struct netdev_private *np = netdev_priv(dev);
+       unsigned int entry;
+       int next_tick = 1*HZ;
+       unsigned long flags;
+
+       spin_lock_irqsave(&np->rx_lock, flags);
+       /* Recover rx ring exhausted error */
+       if (np->cur_rx - np->old_rx >= RX_RING_SIZE) {
+               printk(KERN_INFO "Try to recover rx ring exhausted...\n");
+               /* Re-allocate skbuffs to fill the descriptor ring */
+               for (; np->cur_rx - np->old_rx > 0; np->old_rx++) {
+                       struct sk_buff *skb;
+                       entry = np->old_rx % RX_RING_SIZE;
+                       /* Dropped packets don't need to re-allocate */
+                       if (np->rx_skbuff[entry] == NULL) {
+                               skb = netdev_alloc_skb_ip_align(dev,
+                                                               np->rx_buf_sz);
+                               if (skb == NULL) {
+                                       np->rx_ring[entry].fraginfo = 0;
+                                       printk (KERN_INFO
+                                               "%s: Still unable to re-allocate Rx skbuff.#%d\n",
+                                               dev->name, entry);
+                                       break;
+                               }
+                               np->rx_skbuff[entry] = skb;
+                               np->rx_ring[entry].fraginfo =
+                                   cpu_to_le64 (pci_map_single
+                                        (np->pdev, skb->data, np->rx_buf_sz,
+                                         PCI_DMA_FROMDEVICE));
+                       }
+                       np->rx_ring[entry].fraginfo |=
+                           cpu_to_le64((u64)np->rx_buf_sz << 48);
+                       np->rx_ring[entry].status = 0;
+               } /* end for */
+       } /* end if */
+       spin_unlock_irqrestore (&np->rx_lock, flags);
+       np->timer.expires = jiffies + next_tick;
+       add_timer(&np->timer);
+}
+
+static void
+rio_tx_timeout (struct net_device *dev)
+{
+       long ioaddr = dev->base_addr;
+
+       printk (KERN_INFO "%s: Tx timed out (%4.4x), is buffer full?\n",
+               dev->name, readl (ioaddr + TxStatus));
+       rio_free_tx(dev, 0);
+       dev->if_port = 0;
+       dev->trans_start = jiffies; /* prevent tx timeout */
+}
+
+ /* allocate and initialize Tx and Rx descriptors */
+static void
+alloc_list (struct net_device *dev)
+{
+       struct netdev_private *np = netdev_priv(dev);
+       int i;
+
+       np->cur_rx = np->cur_tx = 0;
+       np->old_rx = np->old_tx = 0;
+       np->rx_buf_sz = (dev->mtu <= 1500 ? PACKET_SIZE : dev->mtu + 32);
+
+       /* Initialize Tx descriptors, TFDListPtr leaves in start_xmit(). */
+       for (i = 0; i < TX_RING_SIZE; i++) {
+               np->tx_skbuff[i] = NULL;
+               np->tx_ring[i].status = cpu_to_le64 (TFDDone);
+               np->tx_ring[i].next_desc = cpu_to_le64 (np->tx_ring_dma +
+                                             ((i+1)%TX_RING_SIZE) *
+                                             sizeof (struct netdev_desc));
+       }
+
+       /* Initialize Rx descriptors */
+       for (i = 0; i < RX_RING_SIZE; i++) {
+               np->rx_ring[i].next_desc = cpu_to_le64 (np->rx_ring_dma +
+                                               ((i + 1) % RX_RING_SIZE) *
+                                               sizeof (struct netdev_desc));
+               np->rx_ring[i].status = 0;
+               np->rx_ring[i].fraginfo = 0;
+               np->rx_skbuff[i] = NULL;
+       }
+
+       /* Allocate the rx buffers */
+       for (i = 0; i < RX_RING_SIZE; i++) {
+               /* Allocated fixed size of skbuff */
+               struct sk_buff *skb;
+
+               skb = netdev_alloc_skb_ip_align(dev, np->rx_buf_sz);
+               np->rx_skbuff[i] = skb;
+               if (skb == NULL) {
+                       printk (KERN_ERR
+                               "%s: alloc_list: allocate Rx buffer error! ",
+                               dev->name);
+                       break;
+               }
+               /* Rubicon now supports 40 bits of addressing space. */
+               np->rx_ring[i].fraginfo =
+                   cpu_to_le64 ( pci_map_single (
+                                 np->pdev, skb->data, np->rx_buf_sz,
+                                 PCI_DMA_FROMDEVICE));
+               np->rx_ring[i].fraginfo |= cpu_to_le64((u64)np->rx_buf_sz << 48);
+       }
+
+       /* Set RFDListPtr */
+       writel (np->rx_ring_dma, dev->base_addr + RFDListPtr0);
+       writel (0, dev->base_addr + RFDListPtr1);
+}
+
+static netdev_tx_t
+start_xmit (struct sk_buff *skb, struct net_device *dev)
+{
+       struct netdev_private *np = netdev_priv(dev);
+       struct netdev_desc *txdesc;
+       unsigned entry;
+       u32 ioaddr;
+       u64 tfc_vlan_tag = 0;
+
+       if (np->link_status == 0) {     /* Link Down */
+               dev_kfree_skb(skb);
+               return NETDEV_TX_OK;
+       }
+       ioaddr = dev->base_addr;
+       entry = np->cur_tx % TX_RING_SIZE;
+       np->tx_skbuff[entry] = skb;
+       txdesc = &np->tx_ring[entry];
+
+#if 0
+       if (skb->ip_summed == CHECKSUM_PARTIAL) {
+               txdesc->status |=
+                   cpu_to_le64 (TCPChecksumEnable | UDPChecksumEnable |
+                                IPChecksumEnable);
+       }
+#endif
+       if (np->vlan) {
+               tfc_vlan_tag = VLANTagInsert |
+                   ((u64)np->vlan << 32) |
+                   ((u64)skb->priority << 45);
+       }
+       txdesc->fraginfo = cpu_to_le64 (pci_map_single (np->pdev, skb->data,
+                                                       skb->len,
+                                                       PCI_DMA_TODEVICE));
+       txdesc->fraginfo |= cpu_to_le64((u64)skb->len << 48);
+
+       /* DL2K bug: DMA fails to get next descriptor ptr in 10Mbps mode
+        * Work around: Always use 1 descriptor in 10Mbps mode */
+       if (entry % np->tx_coalesce == 0 || np->speed == 10)
+               txdesc->status = cpu_to_le64 (entry | tfc_vlan_tag |
+                                             WordAlignDisable |
+                                             TxDMAIndicate |
+                                             (1 << FragCountShift));
+       else
+               txdesc->status = cpu_to_le64 (entry | tfc_vlan_tag |
+                                             WordAlignDisable |
+                                             (1 << FragCountShift));
+
+       /* TxDMAPollNow */
+       writel (readl (ioaddr + DMACtrl) | 0x00001000, ioaddr + DMACtrl);
+       /* Schedule ISR */
+       writel(10000, ioaddr + CountDown);
+       np->cur_tx = (np->cur_tx + 1) % TX_RING_SIZE;
+       if ((np->cur_tx - np->old_tx + TX_RING_SIZE) % TX_RING_SIZE
+                       < TX_QUEUE_LEN - 1 && np->speed != 10) {
+               /* do nothing */
+       } else if (!netif_queue_stopped(dev)) {
+               netif_stop_queue (dev);
+       }
+
+       /* The first TFDListPtr */
+       if (readl (dev->base_addr + TFDListPtr0) == 0) {
+               writel (np->tx_ring_dma + entry * sizeof (struct netdev_desc),
+                       dev->base_addr + TFDListPtr0);
+               writel (0, dev->base_addr + TFDListPtr1);
+       }
+
+       return NETDEV_TX_OK;
+}
+
+static irqreturn_t
+rio_interrupt (int irq, void *dev_instance)
+{
+       struct net_device *dev = dev_instance;
+       struct netdev_private *np;
+       unsigned int_status;
+       long ioaddr;
+       int cnt = max_intrloop;
+       int handled = 0;
+
+       ioaddr = dev->base_addr;
+       np = netdev_priv(dev);
+       while (1) {
+               int_status = readw (ioaddr + IntStatus);
+               writew (int_status, ioaddr + IntStatus);
+               int_status &= DEFAULT_INTR;
+               if (int_status == 0 || --cnt < 0)
+                       break;
+               handled = 1;
+               /* Processing received packets */
+               if (int_status & RxDMAComplete)
+                       receive_packet (dev);
+               /* TxDMAComplete interrupt */
+               if ((int_status & (TxDMAComplete|IntRequested))) {
+                       int tx_status;
+                       tx_status = readl (ioaddr + TxStatus);
+                       if (tx_status & 0x01)
+                               tx_error (dev, tx_status);
+                       /* Free used tx skbuffs */
+                       rio_free_tx (dev, 1);
+               }
+
+               /* Handle uncommon events */
+               if (int_status &
+                   (HostError | LinkEvent | UpdateStats))
+                       rio_error (dev, int_status);
+       }
+       if (np->cur_tx != np->old_tx)
+               writel (100, ioaddr + CountDown);
+       return IRQ_RETVAL(handled);
+}
+
+static inline dma_addr_t desc_to_dma(struct netdev_desc *desc)
+{
+       return le64_to_cpu(desc->fraginfo) & DMA_BIT_MASK(48);
+}
+
+static void
+rio_free_tx (struct net_device *dev, int irq)
+{
+       struct netdev_private *np = netdev_priv(dev);
+       int entry = np->old_tx % TX_RING_SIZE;
+       int tx_use = 0;
+       unsigned long flag = 0;
+
+       if (irq)
+               spin_lock(&np->tx_lock);
+       else
+               spin_lock_irqsave(&np->tx_lock, flag);
+
+       /* Free used tx skbuffs */
+       while (entry != np->cur_tx) {
+               struct sk_buff *skb;
+
+               if (!(np->tx_ring[entry].status & cpu_to_le64(TFDDone)))
+                       break;
+               skb = np->tx_skbuff[entry];
+               pci_unmap_single (np->pdev,
+                                 desc_to_dma(&np->tx_ring[entry]),
+                                 skb->len, PCI_DMA_TODEVICE);
+               if (irq)
+                       dev_kfree_skb_irq (skb);
+               else
+                       dev_kfree_skb (skb);
+
+               np->tx_skbuff[entry] = NULL;
+               entry = (entry + 1) % TX_RING_SIZE;
+               tx_use++;
+       }
+       if (irq)
+               spin_unlock(&np->tx_lock);
+       else
+               spin_unlock_irqrestore(&np->tx_lock, flag);
+       np->old_tx = entry;
+
+       /* If the ring is no longer full, clear tx_full and
+          call netif_wake_queue() */
+
+       if (netif_queue_stopped(dev) &&
+           ((np->cur_tx - np->old_tx + TX_RING_SIZE) % TX_RING_SIZE
+           < TX_QUEUE_LEN - 1 || np->speed == 10)) {
+               netif_wake_queue (dev);
+       }
+}
+
+static void
+tx_error (struct net_device *dev, int tx_status)
+{
+       struct netdev_private *np;
+       long ioaddr = dev->base_addr;
+       int frame_id;
+       int i;
+
+       np = netdev_priv(dev);
+
+       frame_id = (tx_status & 0xffff0000);
+       printk (KERN_ERR "%s: Transmit error, TxStatus %4.4x, FrameId %d.\n",
+               dev->name, tx_status, frame_id);
+       np->stats.tx_errors++;
+       /* Ttransmit Underrun */
+       if (tx_status & 0x10) {
+               np->stats.tx_fifo_errors++;
+               writew (readw (ioaddr + TxStartThresh) + 0x10,
+                       ioaddr + TxStartThresh);
+               /* Transmit Underrun need to set TxReset, DMARest, FIFOReset */
+               writew (TxReset | DMAReset | FIFOReset | NetworkReset,
+                       ioaddr + ASICCtrl + 2);
+               /* Wait for ResetBusy bit clear */
+               for (i = 50; i > 0; i--) {
+                       if ((readw (ioaddr + ASICCtrl + 2) & ResetBusy) == 0)
+                               break;
+                       mdelay (1);
+               }
+               rio_free_tx (dev, 1);
+               /* Reset TFDListPtr */
+               writel (np->tx_ring_dma +
+                       np->old_tx * sizeof (struct netdev_desc),
+                       dev->base_addr + TFDListPtr0);
+               writel (0, dev->base_addr + TFDListPtr1);
+
+               /* Let TxStartThresh stay default value */
+       }
+       /* Late Collision */
+       if (tx_status & 0x04) {
+               np->stats.tx_fifo_errors++;
+               /* TxReset and clear FIFO */
+               writew (TxReset | FIFOReset, ioaddr + ASICCtrl + 2);
+               /* Wait reset done */
+               for (i = 50; i > 0; i--) {
+                       if ((readw (ioaddr + ASICCtrl + 2) & ResetBusy) == 0)
+                               break;
+                       mdelay (1);
+               }
+               /* Let TxStartThresh stay default value */
+       }
+       /* Maximum Collisions */
+#ifdef ETHER_STATS
+       if (tx_status & 0x08)
+               np->stats.collisions16++;
+#else
+       if (tx_status & 0x08)
+               np->stats.collisions++;
+#endif
+       /* Restart the Tx */
+       writel (readw (dev->base_addr + MACCtrl) | TxEnable, ioaddr + MACCtrl);
+}
+
+static int
+receive_packet (struct net_device *dev)
+{
+       struct netdev_private *np = netdev_priv(dev);
+       int entry = np->cur_rx % RX_RING_SIZE;
+       int cnt = 30;
+
+       /* If RFDDone, FrameStart and FrameEnd set, there is a new packet in. */
+       while (1) {
+               struct netdev_desc *desc = &np->rx_ring[entry];
+               int pkt_len;
+               u64 frame_status;
+
+               if (!(desc->status & cpu_to_le64(RFDDone)) ||
+                   !(desc->status & cpu_to_le64(FrameStart)) ||
+                   !(desc->status & cpu_to_le64(FrameEnd)))
+                       break;
+
+               /* Chip omits the CRC. */
+               frame_status = le64_to_cpu(desc->status);
+               pkt_len = frame_status & 0xffff;
+               if (--cnt < 0)
+                       break;
+               /* Update rx error statistics, drop packet. */
+               if (frame_status & RFS_Errors) {
+                       np->stats.rx_errors++;
+                       if (frame_status & (RxRuntFrame | RxLengthError))
+                               np->stats.rx_length_errors++;
+                       if (frame_status & RxFCSError)
+                               np->stats.rx_crc_errors++;
+                       if (frame_status & RxAlignmentError && np->speed != 1000)
+                               np->stats.rx_frame_errors++;
+                       if (frame_status & RxFIFOOverrun)
+                               np->stats.rx_fifo_errors++;
+               } else {
+                       struct sk_buff *skb;
+
+                       /* Small skbuffs for short packets */
+                       if (pkt_len > copy_thresh) {
+                               pci_unmap_single (np->pdev,
+                                                 desc_to_dma(desc),
+                                                 np->rx_buf_sz,
+                                                 PCI_DMA_FROMDEVICE);
+                               skb_put (skb = np->rx_skbuff[entry], pkt_len);
+                               np->rx_skbuff[entry] = NULL;
+                       } else if ((skb = netdev_alloc_skb_ip_align(dev, pkt_len))) {
+                               pci_dma_sync_single_for_cpu(np->pdev,
+                                                           desc_to_dma(desc),
+                                                           np->rx_buf_sz,
+                                                           PCI_DMA_FROMDEVICE);
+                               skb_copy_to_linear_data (skb,
+                                                 np->rx_skbuff[entry]->data,
+                                                 pkt_len);
+                               skb_put (skb, pkt_len);
+                               pci_dma_sync_single_for_device(np->pdev,
+                                                              desc_to_dma(desc),
+                                                              np->rx_buf_sz,
+                                                              PCI_DMA_FROMDEVICE);
+                       }
+                       skb->protocol = eth_type_trans (skb, dev);
+#if 0
+                       /* Checksum done by hw, but csum value unavailable. */
+                       if (np->pdev->pci_rev_id >= 0x0c &&
+                               !(frame_status & (TCPError | UDPError | IPError))) {
+                               skb->ip_summed = CHECKSUM_UNNECESSARY;
+                       }
+#endif
+                       netif_rx (skb);
+               }
+               entry = (entry + 1) % RX_RING_SIZE;
+       }
+       spin_lock(&np->rx_lock);
+       np->cur_rx = entry;
+       /* Re-allocate skbuffs to fill the descriptor ring */
+       entry = np->old_rx;
+       while (entry != np->cur_rx) {
+               struct sk_buff *skb;
+               /* Dropped packets don't need to re-allocate */
+               if (np->rx_skbuff[entry] == NULL) {
+                       skb = netdev_alloc_skb_ip_align(dev, np->rx_buf_sz);
+                       if (skb == NULL) {
+                               np->rx_ring[entry].fraginfo = 0;
+                               printk (KERN_INFO
+                                       "%s: receive_packet: "
+                                       "Unable to re-allocate Rx skbuff.#%d\n",
+                                       dev->name, entry);
+                               break;
+                       }
+                       np->rx_skbuff[entry] = skb;
+                       np->rx_ring[entry].fraginfo =
+                           cpu_to_le64 (pci_map_single
+                                        (np->pdev, skb->data, np->rx_buf_sz,
+                                         PCI_DMA_FROMDEVICE));
+               }
+               np->rx_ring[entry].fraginfo |=
+                   cpu_to_le64((u64)np->rx_buf_sz << 48);
+               np->rx_ring[entry].status = 0;
+               entry = (entry + 1) % RX_RING_SIZE;
+       }
+       np->old_rx = entry;
+       spin_unlock(&np->rx_lock);
+       return 0;
+}
+
+static void
+rio_error (struct net_device *dev, int int_status)
+{
+       long ioaddr = dev->base_addr;
+       struct netdev_private *np = netdev_priv(dev);
+       u16 macctrl;
+
+       /* Link change event */
+       if (int_status & LinkEvent) {
+               if (mii_wait_link (dev, 10) == 0) {
+                       printk (KERN_INFO "%s: Link up\n", dev->name);
+                       if (np->phy_media)
+                               mii_get_media_pcs (dev);
+                       else
+                               mii_get_media (dev);
+                       if (np->speed == 1000)
+                               np->tx_coalesce = tx_coalesce;
+                       else
+                               np->tx_coalesce = 1;
+                       macctrl = 0;
+                       macctrl |= (np->vlan) ? AutoVLANuntagging : 0;
+                       macctrl |= (np->full_duplex) ? DuplexSelect : 0;
+                       macctrl |= (np->tx_flow) ?
+                               TxFlowControlEnable : 0;
+                       macctrl |= (np->rx_flow) ?
+                               RxFlowControlEnable : 0;
+                       writew(macctrl, ioaddr + MACCtrl);
+                       np->link_status = 1;
+                       netif_carrier_on(dev);
+               } else {
+                       printk (KERN_INFO "%s: Link off\n", dev->name);
+                       np->link_status = 0;
+                       netif_carrier_off(dev);
+               }
+       }
+
+       /* UpdateStats statistics registers */
+       if (int_status & UpdateStats) {
+               get_stats (dev);
+       }
+
+       /* PCI Error, a catastronphic error related to the bus interface
+          occurs, set GlobalReset and HostReset to reset. */
+       if (int_status & HostError) {
+               printk (KERN_ERR "%s: HostError! IntStatus %4.4x.\n",
+                       dev->name, int_status);
+               writew (GlobalReset | HostReset, ioaddr + ASICCtrl + 2);
+               mdelay (500);
+       }
+}
+
+static struct net_device_stats *
+get_stats (struct net_device *dev)
+{
+       long ioaddr = dev->base_addr;
+       struct netdev_private *np = netdev_priv(dev);
+#ifdef MEM_MAPPING
+       int i;
+#endif
+       unsigned int stat_reg;
+
+       /* All statistics registers need to be acknowledged,
+          else statistic overflow could cause problems */
+
+       np->stats.rx_packets += readl (ioaddr + FramesRcvOk);
+       np->stats.tx_packets += readl (ioaddr + FramesXmtOk);
+       np->stats.rx_bytes += readl (ioaddr + OctetRcvOk);
+       np->stats.tx_bytes += readl (ioaddr + OctetXmtOk);
+
+       np->stats.multicast = readl (ioaddr + McstFramesRcvdOk);
+       np->stats.collisions += readl (ioaddr + SingleColFrames)
+                            +  readl (ioaddr + MultiColFrames);
+
+       /* detailed tx errors */
+       stat_reg = readw (ioaddr + FramesAbortXSColls);
+       np->stats.tx_aborted_errors += stat_reg;
+       np->stats.tx_errors += stat_reg;
+
+       stat_reg = readw (ioaddr + CarrierSenseErrors);
+       np->stats.tx_carrier_errors += stat_reg;
+       np->stats.tx_errors += stat_reg;
+
+       /* Clear all other statistic register. */
+       readl (ioaddr + McstOctetXmtOk);
+       readw (ioaddr + BcstFramesXmtdOk);
+       readl (ioaddr + McstFramesXmtdOk);
+       readw (ioaddr + BcstFramesRcvdOk);
+       readw (ioaddr + MacControlFramesRcvd);
+       readw (ioaddr + FrameTooLongErrors);
+       readw (ioaddr + InRangeLengthErrors);
+       readw (ioaddr + FramesCheckSeqErrors);
+       readw (ioaddr + FramesLostRxErrors);
+       readl (ioaddr + McstOctetXmtOk);
+       readl (ioaddr + BcstOctetXmtOk);
+       readl (ioaddr + McstFramesXmtdOk);
+       readl (ioaddr + FramesWDeferredXmt);
+       readl (ioaddr + LateCollisions);
+       readw (ioaddr + BcstFramesXmtdOk);
+       readw (ioaddr + MacControlFramesXmtd);
+       readw (ioaddr + FramesWEXDeferal);
+
+#ifdef MEM_MAPPING
+       for (i = 0x100; i <= 0x150; i += 4)
+               readl (ioaddr + i);
+#endif
+       readw (ioaddr + TxJumboFrames);
+       readw (ioaddr + RxJumboFrames);
+       readw (ioaddr + TCPCheckSumErrors);
+       readw (ioaddr + UDPCheckSumErrors);
+       readw (ioaddr + IPCheckSumErrors);
+       return &np->stats;
+}
+
+static int
+clear_stats (struct net_device *dev)
+{
+       long ioaddr = dev->base_addr;
+#ifdef MEM_MAPPING
+       int i;
+#endif
+
+       /* All statistics registers need to be acknowledged,
+          else statistic overflow could cause problems */
+       readl (ioaddr + FramesRcvOk);
+       readl (ioaddr + FramesXmtOk);
+       readl (ioaddr + OctetRcvOk);
+       readl (ioaddr + OctetXmtOk);
+
+       readl (ioaddr + McstFramesRcvdOk);
+       readl (ioaddr + SingleColFrames);
+       readl (ioaddr + MultiColFrames);
+       readl (ioaddr + LateCollisions);
+       /* detailed rx errors */
+       readw (ioaddr + FrameTooLongErrors);
+       readw (ioaddr + InRangeLengthErrors);
+       readw (ioaddr + FramesCheckSeqErrors);
+       readw (ioaddr + FramesLostRxErrors);
+
+       /* detailed tx errors */
+       readw (ioaddr + FramesAbortXSColls);
+       readw (ioaddr + CarrierSenseErrors);
+
+       /* Clear all other statistic register. */
+       readl (ioaddr + McstOctetXmtOk);
+       readw (ioaddr + BcstFramesXmtdOk);
+       readl (ioaddr + McstFramesXmtdOk);
+       readw (ioaddr + BcstFramesRcvdOk);
+       readw (ioaddr + MacControlFramesRcvd);
+       readl (ioaddr + McstOctetXmtOk);
+       readl (ioaddr + BcstOctetXmtOk);
+       readl (ioaddr + McstFramesXmtdOk);
+       readl (ioaddr + FramesWDeferredXmt);
+       readw (ioaddr + BcstFramesXmtdOk);
+       readw (ioaddr + MacControlFramesXmtd);
+       readw (ioaddr + FramesWEXDeferal);
+#ifdef MEM_MAPPING
+       for (i = 0x100; i <= 0x150; i += 4)
+               readl (ioaddr + i);
+#endif
+       readw (ioaddr + TxJumboFrames);
+       readw (ioaddr + RxJumboFrames);
+       readw (ioaddr + TCPCheckSumErrors);
+       readw (ioaddr + UDPCheckSumErrors);
+       readw (ioaddr + IPCheckSumErrors);
+       return 0;
+}
+
+
+static int
+change_mtu (struct net_device *dev, int new_mtu)
+{
+       struct netdev_private *np = netdev_priv(dev);
+       int max = (np->jumbo) ? MAX_JUMBO : 1536;
+
+       if ((new_mtu < 68) || (new_mtu > max)) {
+               return -EINVAL;
+       }
+
+       dev->mtu = new_mtu;
+
+       return 0;
+}
+
+static void
+set_multicast (struct net_device *dev)
+{
+       long ioaddr = dev->base_addr;
+       u32 hash_table[2];
+       u16 rx_mode = 0;
+       struct netdev_private *np = netdev_priv(dev);
+
+       hash_table[0] = hash_table[1] = 0;
+       /* RxFlowcontrol DA: 01-80-C2-00-00-01. Hash index=0x39 */
+       hash_table[1] |= 0x02000000;
+       if (dev->flags & IFF_PROMISC) {
+               /* Receive all frames promiscuously. */
+               rx_mode = ReceiveAllFrames;
+       } else if ((dev->flags & IFF_ALLMULTI) ||
+                       (netdev_mc_count(dev) > multicast_filter_limit)) {
+               /* Receive broadcast and multicast frames */
+               rx_mode = ReceiveBroadcast | ReceiveMulticast | ReceiveUnicast;
+       } else if (!netdev_mc_empty(dev)) {
+               struct netdev_hw_addr *ha;
+               /* Receive broadcast frames and multicast frames filtering
+                  by Hashtable */
+               rx_mode =
+                   ReceiveBroadcast | ReceiveMulticastHash | ReceiveUnicast;
+               netdev_for_each_mc_addr(ha, dev) {
+                       int bit, index = 0;
+                       int crc = ether_crc_le(ETH_ALEN, ha->addr);
+                       /* The inverted high significant 6 bits of CRC are
+                          used as an index to hashtable */
+                       for (bit = 0; bit < 6; bit++)
+                               if (crc & (1 << (31 - bit)))
+                                       index |= (1 << bit);
+                       hash_table[index / 32] |= (1 << (index % 32));
+               }
+       } else {
+               rx_mode = ReceiveBroadcast | ReceiveUnicast;
+       }
+       if (np->vlan) {
+               /* ReceiveVLANMatch field in ReceiveMode */
+               rx_mode |= ReceiveVLANMatch;
+       }
+
+       writel (hash_table[0], ioaddr + HashTable0);
+       writel (hash_table[1], ioaddr + HashTable1);
+       writew (rx_mode, ioaddr + ReceiveMode);
+}
+
+static void rio_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+       struct netdev_private *np = netdev_priv(dev);
+       strcpy(info->driver, "dl2k");
+       strcpy(info->version, DRV_VERSION);
+       strcpy(info->bus_info, pci_name(np->pdev));
+}
+
+static int rio_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct netdev_private *np = netdev_priv(dev);
+       if (np->phy_media) {
+               /* fiber device */
+               cmd->supported = SUPPORTED_Autoneg | SUPPORTED_FIBRE;
+               cmd->advertising= ADVERTISED_Autoneg | ADVERTISED_FIBRE;
+               cmd->port = PORT_FIBRE;
+               cmd->transceiver = XCVR_INTERNAL;
+       } else {
+               /* copper device */
+               cmd->supported = SUPPORTED_10baseT_Half |
+                       SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half
+                       | SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Full |
+                       SUPPORTED_Autoneg | SUPPORTED_MII;
+               cmd->advertising = ADVERTISED_10baseT_Half |
+                       ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Half |
+                       ADVERTISED_100baseT_Full | ADVERTISED_1000baseT_Full|
+                       ADVERTISED_Autoneg | ADVERTISED_MII;
+               cmd->port = PORT_MII;
+               cmd->transceiver = XCVR_INTERNAL;
+       }
+       if ( np->link_status ) {
+               ethtool_cmd_speed_set(cmd, np->speed);
+               cmd->duplex = np->full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
+       } else {
+               ethtool_cmd_speed_set(cmd, -1);
+               cmd->duplex = -1;
+       }
+       if ( np->an_enable)
+               cmd->autoneg = AUTONEG_ENABLE;
+       else
+               cmd->autoneg = AUTONEG_DISABLE;
+
+       cmd->phy_address = np->phy_addr;
+       return 0;
+}
+
+static int rio_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct netdev_private *np = netdev_priv(dev);
+       netif_carrier_off(dev);
+       if (cmd->autoneg == AUTONEG_ENABLE) {
+               if (np->an_enable)
+                       return 0;
+               else {
+                       np->an_enable = 1;
+                       mii_set_media(dev);
+                       return 0;
+               }
+       } else {
+               np->an_enable = 0;
+               if (np->speed == 1000) {
+                       ethtool_cmd_speed_set(cmd, SPEED_100);
+                       cmd->duplex = DUPLEX_FULL;
+                       printk("Warning!! Can't disable Auto negotiation in 1000Mbps, change to Manual 100Mbps, Full duplex.\n");
+               }
+               switch (ethtool_cmd_speed(cmd)) {
+               case SPEED_10:
+                       np->speed = 10;
+                       np->full_duplex = (cmd->duplex == DUPLEX_FULL);
+                       break;
+               case SPEED_100:
+                       np->speed = 100;
+                       np->full_duplex = (cmd->duplex == DUPLEX_FULL);
+                       break;
+               case SPEED_1000: /* not supported */
+               default:
+                       return -EINVAL;
+               }
+               mii_set_media(dev);
+       }
+       return 0;
+}
+
+static u32 rio_get_link(struct net_device *dev)
+{
+       struct netdev_private *np = netdev_priv(dev);
+       return np->link_status;
+}
+
+static const struct ethtool_ops ethtool_ops = {
+       .get_drvinfo = rio_get_drvinfo,
+       .get_settings = rio_get_settings,
+       .set_settings = rio_set_settings,
+       .get_link = rio_get_link,
+};
+
+static int
+rio_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
+{
+       int phy_addr;
+       struct netdev_private *np = netdev_priv(dev);
+       struct mii_data *miidata = (struct mii_data *) &rq->ifr_ifru;
+
+       struct netdev_desc *desc;
+       int i;
+
+       phy_addr = np->phy_addr;
+       switch (cmd) {
+       case SIOCDEVPRIVATE:
+               break;
+
+       case SIOCDEVPRIVATE + 1:
+               miidata->out_value = mii_read (dev, phy_addr, miidata->reg_num);
+               break;
+       case SIOCDEVPRIVATE + 2:
+               mii_write (dev, phy_addr, miidata->reg_num, miidata->in_value);
+               break;
+       case SIOCDEVPRIVATE + 3:
+               break;
+       case SIOCDEVPRIVATE + 4:
+               break;
+       case SIOCDEVPRIVATE + 5:
+               netif_stop_queue (dev);
+               break;
+       case SIOCDEVPRIVATE + 6:
+               netif_wake_queue (dev);
+               break;
+       case SIOCDEVPRIVATE + 7:
+               printk
+                   ("tx_full=%x cur_tx=%lx old_tx=%lx cur_rx=%lx old_rx=%lx\n",
+                    netif_queue_stopped(dev), np->cur_tx, np->old_tx, np->cur_rx,
+                    np->old_rx);
+               break;
+       case SIOCDEVPRIVATE + 8:
+               printk("TX ring:\n");
+               for (i = 0; i < TX_RING_SIZE; i++) {
+                       desc = &np->tx_ring[i];
+                       printk
+                           ("%02x:cur:%08x next:%08x status:%08x frag1:%08x frag0:%08x",
+                            i,
+                            (u32) (np->tx_ring_dma + i * sizeof (*desc)),
+                            (u32)le64_to_cpu(desc->next_desc),
+                            (u32)le64_to_cpu(desc->status),
+                            (u32)(le64_to_cpu(desc->fraginfo) >> 32),
+                            (u32)le64_to_cpu(desc->fraginfo));
+                       printk ("\n");
+               }
+               printk ("\n");
+               break;
+
+       default:
+               return -EOPNOTSUPP;
+       }
+       return 0;
+}
+
+#define EEP_READ 0x0200
+#define EEP_BUSY 0x8000
+/* Read the EEPROM word */
+/* We use I/O instruction to read/write eeprom to avoid fail on some machines */
+static int
+read_eeprom (long ioaddr, int eep_addr)
+{
+       int i = 1000;
+       outw (EEP_READ | (eep_addr & 0xff), ioaddr + EepromCtrl);
+       while (i-- > 0) {
+               if (!(inw (ioaddr + EepromCtrl) & EEP_BUSY)) {
+                       return inw (ioaddr + EepromData);
+               }
+       }
+       return 0;
+}
+
+enum phy_ctrl_bits {
+       MII_READ = 0x00, MII_CLK = 0x01, MII_DATA1 = 0x02, MII_WRITE = 0x04,
+       MII_DUPLEX = 0x08,
+};
+
+#define mii_delay() readb(ioaddr)
+static void
+mii_sendbit (struct net_device *dev, u32 data)
+{
+       long ioaddr = dev->base_addr + PhyCtrl;
+       data = (data) ? MII_DATA1 : 0;
+       data |= MII_WRITE;
+       data |= (readb (ioaddr) & 0xf8) | MII_WRITE;
+       writeb (data, ioaddr);
+       mii_delay ();
+       writeb (data | MII_CLK, ioaddr);
+       mii_delay ();
+}
+
+static int
+mii_getbit (struct net_device *dev)
+{
+       long ioaddr = dev->base_addr + PhyCtrl;
+       u8 data;
+
+       data = (readb (ioaddr) & 0xf8) | MII_READ;
+       writeb (data, ioaddr);
+       mii_delay ();
+       writeb (data | MII_CLK, ioaddr);
+       mii_delay ();
+       return ((readb (ioaddr) >> 1) & 1);
+}
+
+static void
+mii_send_bits (struct net_device *dev, u32 data, int len)
+{
+       int i;
+       for (i = len - 1; i >= 0; i--) {
+               mii_sendbit (dev, data & (1 << i));
+       }
+}
+
+static int
+mii_read (struct net_device *dev, int phy_addr, int reg_num)
+{
+       u32 cmd;
+       int i;
+       u32 retval = 0;
+
+       /* Preamble */
+       mii_send_bits (dev, 0xffffffff, 32);
+       /* ST(2), OP(2), ADDR(5), REG#(5), TA(2), Data(16) total 32 bits */
+       /* ST,OP = 0110'b for read operation */
+       cmd = (0x06 << 10 | phy_addr << 5 | reg_num);
+       mii_send_bits (dev, cmd, 14);
+       /* Turnaround */
+       if (mii_getbit (dev))
+               goto err_out;
+       /* Read data */
+       for (i = 0; i < 16; i++) {
+               retval |= mii_getbit (dev);
+               retval <<= 1;
+       }
+       /* End cycle */
+       mii_getbit (dev);
+       return (retval >> 1) & 0xffff;
+
+      err_out:
+       return 0;
+}
+static int
+mii_write (struct net_device *dev, int phy_addr, int reg_num, u16 data)
+{
+       u32 cmd;
+
+       /* Preamble */
+       mii_send_bits (dev, 0xffffffff, 32);
+       /* ST(2), OP(2), ADDR(5), REG#(5), TA(2), Data(16) total 32 bits */
+       /* ST,OP,AAAAA,RRRRR,TA = 0101xxxxxxxxxx10'b = 0x5002 for write */
+       cmd = (0x5002 << 16) | (phy_addr << 23) | (reg_num << 18) | data;
+       mii_send_bits (dev, cmd, 32);
+       /* End cycle */
+       mii_getbit (dev);
+       return 0;
+}
+static int
+mii_wait_link (struct net_device *dev, int wait)
+{
+       __u16 bmsr;
+       int phy_addr;
+       struct netdev_private *np;
+
+       np = netdev_priv(dev);
+       phy_addr = np->phy_addr;
+
+       do {
+               bmsr = mii_read (dev, phy_addr, MII_BMSR);
+               if (bmsr & MII_BMSR_LINK_STATUS)
+                       return 0;
+               mdelay (1);
+       } while (--wait > 0);
+       return -1;
+}
+static int
+mii_get_media (struct net_device *dev)
+{
+       __u16 negotiate;
+       __u16 bmsr;
+       __u16 mscr;
+       __u16 mssr;
+       int phy_addr;
+       struct netdev_private *np;
+
+       np = netdev_priv(dev);
+       phy_addr = np->phy_addr;
+
+       bmsr = mii_read (dev, phy_addr, MII_BMSR);
+       if (np->an_enable) {
+               if (!(bmsr & MII_BMSR_AN_COMPLETE)) {
+                       /* Auto-Negotiation not completed */
+                       return -1;
+               }
+               negotiate = mii_read (dev, phy_addr, MII_ANAR) &
+                       mii_read (dev, phy_addr, MII_ANLPAR);
+               mscr = mii_read (dev, phy_addr, MII_MSCR);
+               mssr = mii_read (dev, phy_addr, MII_MSSR);
+               if (mscr & MII_MSCR_1000BT_FD && mssr & MII_MSSR_LP_1000BT_FD) {
+                       np->speed = 1000;
+                       np->full_duplex = 1;
+                       printk (KERN_INFO "Auto 1000 Mbps, Full duplex\n");
+               } else if (mscr & MII_MSCR_1000BT_HD && mssr & MII_MSSR_LP_1000BT_HD) {
+                       np->speed = 1000;
+                       np->full_duplex = 0;
+                       printk (KERN_INFO "Auto 1000 Mbps, Half duplex\n");
+               } else if (negotiate & MII_ANAR_100BX_FD) {
+                       np->speed = 100;
+                       np->full_duplex = 1;
+                       printk (KERN_INFO "Auto 100 Mbps, Full duplex\n");
+               } else if (negotiate & MII_ANAR_100BX_HD) {
+                       np->speed = 100;
+                       np->full_duplex = 0;
+                       printk (KERN_INFO "Auto 100 Mbps, Half duplex\n");
+               } else if (negotiate & MII_ANAR_10BT_FD) {
+                       np->speed = 10;
+                       np->full_duplex = 1;
+                       printk (KERN_INFO "Auto 10 Mbps, Full duplex\n");
+               } else if (negotiate & MII_ANAR_10BT_HD) {
+                       np->speed = 10;
+                       np->full_duplex = 0;
+                       printk (KERN_INFO "Auto 10 Mbps, Half duplex\n");
+               }
+               if (negotiate & MII_ANAR_PAUSE) {
+                       np->tx_flow &= 1;
+                       np->rx_flow &= 1;
+               } else if (negotiate & MII_ANAR_ASYMMETRIC) {
+                       np->tx_flow = 0;
+                       np->rx_flow &= 1;
+               }
+               /* else tx_flow, rx_flow = user select  */
+       } else {
+               __u16 bmcr = mii_read (dev, phy_addr, MII_BMCR);
+               switch (bmcr & (MII_BMCR_SPEED_100 | MII_BMCR_SPEED_1000)) {
+               case MII_BMCR_SPEED_1000:
+                       printk (KERN_INFO "Operating at 1000 Mbps, ");
+                       break;
+               case MII_BMCR_SPEED_100:
+                       printk (KERN_INFO "Operating at 100 Mbps, ");
+                       break;
+               case 0:
+                       printk (KERN_INFO "Operating at 10 Mbps, ");
+               }
+               if (bmcr & MII_BMCR_DUPLEX_MODE) {
+                       printk (KERN_CONT "Full duplex\n");
+               } else {
+                       printk (KERN_CONT "Half duplex\n");
+               }
+       }
+       if (np->tx_flow)
+               printk(KERN_INFO "Enable Tx Flow Control\n");
+       else
+               printk(KERN_INFO "Disable Tx Flow Control\n");
+       if (np->rx_flow)
+               printk(KERN_INFO "Enable Rx Flow Control\n");
+       else
+               printk(KERN_INFO "Disable Rx Flow Control\n");
+
+       return 0;
+}
+
+static int
+mii_set_media (struct net_device *dev)
+{
+       __u16 pscr;
+       __u16 bmcr;
+       __u16 bmsr;
+       __u16 anar;
+       int phy_addr;
+       struct netdev_private *np;
+       np = netdev_priv(dev);
+       phy_addr = np->phy_addr;
+
+       /* Does user set speed? */
+       if (np->an_enable) {
+               /* Advertise capabilities */
+               bmsr = mii_read (dev, phy_addr, MII_BMSR);
+               anar = mii_read (dev, phy_addr, MII_ANAR) &
+                            ~MII_ANAR_100BX_FD &
+                            ~MII_ANAR_100BX_HD &
+                            ~MII_ANAR_100BT4 &
+                            ~MII_ANAR_10BT_FD &
+                            ~MII_ANAR_10BT_HD;
+               if (bmsr & MII_BMSR_100BX_FD)
+                       anar |= MII_ANAR_100BX_FD;
+               if (bmsr & MII_BMSR_100BX_HD)
+                       anar |= MII_ANAR_100BX_HD;
+               if (bmsr & MII_BMSR_100BT4)
+                       anar |= MII_ANAR_100BT4;
+               if (bmsr & MII_BMSR_10BT_FD)
+                       anar |= MII_ANAR_10BT_FD;
+               if (bmsr & MII_BMSR_10BT_HD)
+                       anar |= MII_ANAR_10BT_HD;
+               anar |= MII_ANAR_PAUSE | MII_ANAR_ASYMMETRIC;
+               mii_write (dev, phy_addr, MII_ANAR, anar);
+
+               /* Enable Auto crossover */
+               pscr = mii_read (dev, phy_addr, MII_PHY_SCR);
+               pscr |= 3 << 5; /* 11'b */
+               mii_write (dev, phy_addr, MII_PHY_SCR, pscr);
+
+               /* Soft reset PHY */
+               mii_write (dev, phy_addr, MII_BMCR, MII_BMCR_RESET);
+               bmcr = MII_BMCR_AN_ENABLE | MII_BMCR_RESTART_AN | MII_BMCR_RESET;
+               mii_write (dev, phy_addr, MII_BMCR, bmcr);
+               mdelay(1);
+       } else {
+               /* Force speed setting */
+               /* 1) Disable Auto crossover */
+               pscr = mii_read (dev, phy_addr, MII_PHY_SCR);
+               pscr &= ~(3 << 5);
+               mii_write (dev, phy_addr, MII_PHY_SCR, pscr);
+
+               /* 2) PHY Reset */
+               bmcr = mii_read (dev, phy_addr, MII_BMCR);
+               bmcr |= MII_BMCR_RESET;
+               mii_write (dev, phy_addr, MII_BMCR, bmcr);
+
+               /* 3) Power Down */
+               bmcr = 0x1940;  /* must be 0x1940 */
+               mii_write (dev, phy_addr, MII_BMCR, bmcr);
+               mdelay (100);   /* wait a certain time */
+
+               /* 4) Advertise nothing */
+               mii_write (dev, phy_addr, MII_ANAR, 0);
+
+               /* 5) Set media and Power Up */
+               bmcr = MII_BMCR_POWER_DOWN;
+               if (np->speed == 100) {
+                       bmcr |= MII_BMCR_SPEED_100;
+                       printk (KERN_INFO "Manual 100 Mbps, ");
+               } else if (np->speed == 10) {
+                       printk (KERN_INFO "Manual 10 Mbps, ");
+               }
+               if (np->full_duplex) {
+                       bmcr |= MII_BMCR_DUPLEX_MODE;
+                       printk (KERN_CONT "Full duplex\n");
+               } else {
+                       printk (KERN_CONT "Half duplex\n");
+               }
+#if 0
+               /* Set 1000BaseT Master/Slave setting */
+               mscr = mii_read (dev, phy_addr, MII_MSCR);
+               mscr |= MII_MSCR_CFG_ENABLE;
+               mscr &= ~MII_MSCR_CFG_VALUE = 0;
+#endif
+               mii_write (dev, phy_addr, MII_BMCR, bmcr);
+               mdelay(10);
+       }
+       return 0;
+}
+
+static int
+mii_get_media_pcs (struct net_device *dev)
+{
+       __u16 negotiate;
+       __u16 bmsr;
+       int phy_addr;
+       struct netdev_private *np;
+
+       np = netdev_priv(dev);
+       phy_addr = np->phy_addr;
+
+       bmsr = mii_read (dev, phy_addr, PCS_BMSR);
+       if (np->an_enable) {
+               if (!(bmsr & MII_BMSR_AN_COMPLETE)) {
+                       /* Auto-Negotiation not completed */
+                       return -1;
+               }
+               negotiate = mii_read (dev, phy_addr, PCS_ANAR) &
+                       mii_read (dev, phy_addr, PCS_ANLPAR);
+               np->speed = 1000;
+               if (negotiate & PCS_ANAR_FULL_DUPLEX) {
+                       printk (KERN_INFO "Auto 1000 Mbps, Full duplex\n");
+                       np->full_duplex = 1;
+               } else {
+                       printk (KERN_INFO "Auto 1000 Mbps, half duplex\n");
+                       np->full_duplex = 0;
+               }
+               if (negotiate & PCS_ANAR_PAUSE) {
+                       np->tx_flow &= 1;
+                       np->rx_flow &= 1;
+               } else if (negotiate & PCS_ANAR_ASYMMETRIC) {
+                       np->tx_flow = 0;
+                       np->rx_flow &= 1;
+               }
+               /* else tx_flow, rx_flow = user select  */
+       } else {
+               __u16 bmcr = mii_read (dev, phy_addr, PCS_BMCR);
+               printk (KERN_INFO "Operating at 1000 Mbps, ");
+               if (bmcr & MII_BMCR_DUPLEX_MODE) {
+                       printk (KERN_CONT "Full duplex\n");
+               } else {
+                       printk (KERN_CONT "Half duplex\n");
+               }
+       }
+       if (np->tx_flow)
+               printk(KERN_INFO "Enable Tx Flow Control\n");
+       else
+               printk(KERN_INFO "Disable Tx Flow Control\n");
+       if (np->rx_flow)
+               printk(KERN_INFO "Enable Rx Flow Control\n");
+       else
+               printk(KERN_INFO "Disable Rx Flow Control\n");
+
+       return 0;
+}
+
+static int
+mii_set_media_pcs (struct net_device *dev)
+{
+       __u16 bmcr;
+       __u16 esr;
+       __u16 anar;
+       int phy_addr;
+       struct netdev_private *np;
+       np = netdev_priv(dev);
+       phy_addr = np->phy_addr;
+
+       /* Auto-Negotiation? */
+       if (np->an_enable) {
+               /* Advertise capabilities */
+               esr = mii_read (dev, phy_addr, PCS_ESR);
+               anar = mii_read (dev, phy_addr, MII_ANAR) &
+                       ~PCS_ANAR_HALF_DUPLEX &
+                       ~PCS_ANAR_FULL_DUPLEX;
+               if (esr & (MII_ESR_1000BT_HD | MII_ESR_1000BX_HD))
+                       anar |= PCS_ANAR_HALF_DUPLEX;
+               if (esr & (MII_ESR_1000BT_FD | MII_ESR_1000BX_FD))
+                       anar |= PCS_ANAR_FULL_DUPLEX;
+               anar |= PCS_ANAR_PAUSE | PCS_ANAR_ASYMMETRIC;
+               mii_write (dev, phy_addr, MII_ANAR, anar);
+
+               /* Soft reset PHY */
+               mii_write (dev, phy_addr, MII_BMCR, MII_BMCR_RESET);
+               bmcr = MII_BMCR_AN_ENABLE | MII_BMCR_RESTART_AN |
+                      MII_BMCR_RESET;
+               mii_write (dev, phy_addr, MII_BMCR, bmcr);
+               mdelay(1);
+       } else {
+               /* Force speed setting */
+               /* PHY Reset */
+               bmcr = MII_BMCR_RESET;
+               mii_write (dev, phy_addr, MII_BMCR, bmcr);
+               mdelay(10);
+               if (np->full_duplex) {
+                       bmcr = MII_BMCR_DUPLEX_MODE;
+                       printk (KERN_INFO "Manual full duplex\n");
+               } else {
+                       bmcr = 0;
+                       printk (KERN_INFO "Manual half duplex\n");
+               }
+               mii_write (dev, phy_addr, MII_BMCR, bmcr);
+               mdelay(10);
+
+               /*  Advertise nothing */
+               mii_write (dev, phy_addr, MII_ANAR, 0);
+       }
+       return 0;
+}
+
+
+static int
+rio_close (struct net_device *dev)
+{
+       long ioaddr = dev->base_addr;
+       struct netdev_private *np = netdev_priv(dev);
+       struct sk_buff *skb;
+       int i;
+
+       netif_stop_queue (dev);
+
+       /* Disable interrupts */
+       writew (0, ioaddr + IntEnable);
+
+       /* Stop Tx and Rx logics */
+       writel (TxDisable | RxDisable | StatsDisable, ioaddr + MACCtrl);
+
+       free_irq (dev->irq, dev);
+       del_timer_sync (&np->timer);
+
+       /* Free all the skbuffs in the queue. */
+       for (i = 0; i < RX_RING_SIZE; i++) {
+               skb = np->rx_skbuff[i];
+               if (skb) {
+                       pci_unmap_single(np->pdev,
+                                        desc_to_dma(&np->rx_ring[i]),
+                                        skb->len, PCI_DMA_FROMDEVICE);
+                       dev_kfree_skb (skb);
+                       np->rx_skbuff[i] = NULL;
+               }
+               np->rx_ring[i].status = 0;
+               np->rx_ring[i].fraginfo = 0;
+       }
+       for (i = 0; i < TX_RING_SIZE; i++) {
+               skb = np->tx_skbuff[i];
+               if (skb) {
+                       pci_unmap_single(np->pdev,
+                                        desc_to_dma(&np->tx_ring[i]),
+                                        skb->len, PCI_DMA_TODEVICE);
+                       dev_kfree_skb (skb);
+                       np->tx_skbuff[i] = NULL;
+               }
+       }
+
+       return 0;
+}
+
+static void __devexit
+rio_remove1 (struct pci_dev *pdev)
+{
+       struct net_device *dev = pci_get_drvdata (pdev);
+
+       if (dev) {
+               struct netdev_private *np = netdev_priv(dev);
+
+               unregister_netdev (dev);
+               pci_free_consistent (pdev, RX_TOTAL_SIZE, np->rx_ring,
+                                    np->rx_ring_dma);
+               pci_free_consistent (pdev, TX_TOTAL_SIZE, np->tx_ring,
+                                    np->tx_ring_dma);
+#ifdef MEM_MAPPING
+               iounmap ((char *) (dev->base_addr));
+#endif
+               free_netdev (dev);
+               pci_release_regions (pdev);
+               pci_disable_device (pdev);
+       }
+       pci_set_drvdata (pdev, NULL);
+}
+
+static struct pci_driver rio_driver = {
+       .name           = "dl2k",
+       .id_table       = rio_pci_tbl,
+       .probe          = rio_probe1,
+       .remove         = __devexit_p(rio_remove1),
+};
+
+static int __init
+rio_init (void)
+{
+       return pci_register_driver(&rio_driver);
+}
+
+static void __exit
+rio_exit (void)
+{
+       pci_unregister_driver (&rio_driver);
+}
+
+module_init (rio_init);
+module_exit (rio_exit);
+
+/*
+
+Compile command:
+
+gcc -D__KERNEL__ -DMODULE -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -c dl2k.c
+
+Read Documentation/networking/dl2k.txt for details.
+
+*/
+
diff --git a/drivers/net/ethernet/dlink/dl2k.h b/drivers/net/ethernet/dlink/dl2k.h
new file mode 100644 (file)
index 0000000..7caab3d
--- /dev/null
@@ -0,0 +1,554 @@
+/*  D-Link DL2000-based Gigabit Ethernet Adapter Linux driver */
+/*
+    Copyright (c) 2001, 2002 by D-Link Corporation
+    Written by Edward Peng.<edward_peng@dlink.com.tw>
+    Created 03-May-2001, base on Linux' sundance.c.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+*/
+
+#ifndef __DL2K_H__
+#define __DL2K_H__
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/crc32.h>
+#include <linux/ethtool.h>
+#include <linux/bitops.h>
+#include <asm/processor.h>     /* Processor type for cache alignment. */
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/time.h>
+#define TX_RING_SIZE   256
+#define TX_QUEUE_LEN   (TX_RING_SIZE - 1) /* Limit ring entries actually used.*/
+#define RX_RING_SIZE   256
+#define TX_TOTAL_SIZE  TX_RING_SIZE*sizeof(struct netdev_desc)
+#define RX_TOTAL_SIZE  RX_RING_SIZE*sizeof(struct netdev_desc)
+
+/* This driver was written to use PCI memory space, however x86-oriented
+   hardware often uses I/O space accesses. */
+#ifndef MEM_MAPPING
+#undef readb
+#undef readw
+#undef readl
+#undef writeb
+#undef writew
+#undef writel
+#define readb inb
+#define readw inw
+#define readl inl
+#define writeb outb
+#define writew outw
+#define writel outl
+#endif
+
+/* Offsets to the device registers.
+   Unlike software-only systems, device drivers interact with complex hardware.
+   It's not useful to define symbolic names for every register bit in the
+   device.  The name can only partially document the semantics and make
+   the driver longer and more difficult to read.
+   In general, only the important configuration values or bits changed
+   multiple times should be defined symbolically.
+*/
+enum dl2x_offsets {
+       /* I/O register offsets */
+       DMACtrl = 0x00,
+       RxDMAStatus = 0x08,
+       TFDListPtr0 = 0x10,
+       TFDListPtr1 = 0x14,
+       TxDMABurstThresh = 0x18,
+       TxDMAUrgentThresh = 0x19,
+       TxDMAPollPeriod = 0x1a,
+       RFDListPtr0 = 0x1c,
+       RFDListPtr1 = 0x20,
+       RxDMABurstThresh = 0x24,
+       RxDMAUrgentThresh = 0x25,
+       RxDMAPollPeriod = 0x26,
+       RxDMAIntCtrl = 0x28,
+       DebugCtrl = 0x2c,
+       ASICCtrl = 0x30,
+       FifoCtrl = 0x38,
+       RxEarlyThresh = 0x3a,
+       FlowOffThresh = 0x3c,
+       FlowOnThresh = 0x3e,
+       TxStartThresh = 0x44,
+       EepromData = 0x48,
+       EepromCtrl = 0x4a,
+       ExpromAddr = 0x4c,
+       Exprodata = 0x50,
+       WakeEvent = 0x51,
+       CountDown = 0x54,
+       IntStatusAck = 0x5a,
+       IntEnable = 0x5c,
+       IntStatus = 0x5e,
+       TxStatus = 0x60,
+       MACCtrl = 0x6c,
+       VLANTag = 0x70,
+       PhyCtrl = 0x76,
+       StationAddr0 = 0x78,
+       StationAddr1 = 0x7a,
+       StationAddr2 = 0x7c,
+       VLANId = 0x80,
+       MaxFrameSize = 0x86,
+       ReceiveMode = 0x88,
+       HashTable0 = 0x8c,
+       HashTable1 = 0x90,
+       RmonStatMask = 0x98,
+       StatMask = 0x9c,
+       RxJumboFrames = 0xbc,
+       TCPCheckSumErrors = 0xc0,
+       IPCheckSumErrors = 0xc2,
+       UDPCheckSumErrors = 0xc4,
+       TxJumboFrames = 0xf4,
+       /* Ethernet MIB statistic register offsets */
+       OctetRcvOk = 0xa8,
+       McstOctetRcvOk = 0xac,
+       BcstOctetRcvOk = 0xb0,
+       FramesRcvOk = 0xb4,
+       McstFramesRcvdOk = 0xb8,
+       BcstFramesRcvdOk = 0xbe,
+       MacControlFramesRcvd = 0xc6,
+       FrameTooLongErrors = 0xc8,
+       InRangeLengthErrors = 0xca,
+       FramesCheckSeqErrors = 0xcc,
+       FramesLostRxErrors = 0xce,
+       OctetXmtOk = 0xd0,
+       McstOctetXmtOk = 0xd4,
+       BcstOctetXmtOk = 0xd8,
+       FramesXmtOk = 0xdc,
+       McstFramesXmtdOk = 0xe0,
+       FramesWDeferredXmt = 0xe4,
+       LateCollisions = 0xe8,
+       MultiColFrames = 0xec,
+       SingleColFrames = 0xf0,
+       BcstFramesXmtdOk = 0xf6,
+       CarrierSenseErrors = 0xf8,
+       MacControlFramesXmtd = 0xfa,
+       FramesAbortXSColls = 0xfc,
+       FramesWEXDeferal = 0xfe,
+       /* RMON statistic register offsets */
+       EtherStatsCollisions = 0x100,
+       EtherStatsOctetsTransmit = 0x104,
+       EtherStatsPktsTransmit = 0x108,
+       EtherStatsPkts64OctetTransmit = 0x10c,
+       EtherStats65to127OctetsTransmit = 0x110,
+       EtherStatsPkts128to255OctetsTransmit = 0x114,
+       EtherStatsPkts256to511OctetsTransmit = 0x118,
+       EtherStatsPkts512to1023OctetsTransmit = 0x11c,
+       EtherStatsPkts1024to1518OctetsTransmit = 0x120,
+       EtherStatsCRCAlignErrors = 0x124,
+       EtherStatsUndersizePkts = 0x128,
+       EtherStatsFragments = 0x12c,
+       EtherStatsJabbers = 0x130,
+       EtherStatsOctets = 0x134,
+       EtherStatsPkts = 0x138,
+       EtherStats64Octets = 0x13c,
+       EtherStatsPkts65to127Octets = 0x140,
+       EtherStatsPkts128to255Octets = 0x144,
+       EtherStatsPkts256to511Octets = 0x148,
+       EtherStatsPkts512to1023Octets = 0x14c,
+       EtherStatsPkts1024to1518Octets = 0x150,
+};
+
+/* Bits in the interrupt status/mask registers. */
+enum IntStatus_bits {
+       InterruptStatus = 0x0001,
+       HostError = 0x0002,
+       MACCtrlFrame = 0x0008,
+       TxComplete = 0x0004,
+       RxComplete = 0x0010,
+       RxEarly = 0x0020,
+       IntRequested = 0x0040,
+       UpdateStats = 0x0080,
+       LinkEvent = 0x0100,
+       TxDMAComplete = 0x0200,
+       RxDMAComplete = 0x0400,
+       RFDListEnd = 0x0800,
+       RxDMAPriority = 0x1000,
+};
+
+/* Bits in the ReceiveMode register. */
+enum ReceiveMode_bits {
+       ReceiveUnicast = 0x0001,
+       ReceiveMulticast = 0x0002,
+       ReceiveBroadcast = 0x0004,
+       ReceiveAllFrames = 0x0008,
+       ReceiveMulticastHash = 0x0010,
+       ReceiveIPMulticast = 0x0020,
+       ReceiveVLANMatch = 0x0100,
+       ReceiveVLANHash = 0x0200,
+};
+/* Bits in MACCtrl. */
+enum MACCtrl_bits {
+       DuplexSelect = 0x20,
+       TxFlowControlEnable = 0x80,
+       RxFlowControlEnable = 0x0100,
+       RcvFCS = 0x200,
+       AutoVLANtagging = 0x1000,
+       AutoVLANuntagging = 0x2000,
+       StatsEnable = 0x00200000,
+       StatsDisable = 0x00400000,
+       StatsEnabled = 0x00800000,
+       TxEnable = 0x01000000,
+       TxDisable = 0x02000000,
+       TxEnabled = 0x04000000,
+       RxEnable = 0x08000000,
+       RxDisable = 0x10000000,
+       RxEnabled = 0x20000000,
+};
+
+enum ASICCtrl_LoWord_bits {
+       PhyMedia = 0x0080,
+};
+
+enum ASICCtrl_HiWord_bits {
+       GlobalReset = 0x0001,
+       RxReset = 0x0002,
+       TxReset = 0x0004,
+       DMAReset = 0x0008,
+       FIFOReset = 0x0010,
+       NetworkReset = 0x0020,
+       HostReset = 0x0040,
+       ResetBusy = 0x0400,
+};
+
+/* Transmit Frame Control bits */
+enum TFC_bits {
+       DwordAlign = 0x00000000,
+       WordAlignDisable = 0x00030000,
+       WordAlign = 0x00020000,
+       TCPChecksumEnable = 0x00040000,
+       UDPChecksumEnable = 0x00080000,
+       IPChecksumEnable = 0x00100000,
+       FCSAppendDisable = 0x00200000,
+       TxIndicate = 0x00400000,
+       TxDMAIndicate = 0x00800000,
+       FragCountShift = 24,
+       VLANTagInsert = 0x0000000010000000,
+       TFDDone = 0x80000000,
+       VIDShift = 32,
+       UsePriorityShift = 48,
+};
+
+/* Receive Frames Status bits */
+enum RFS_bits {
+       RxFIFOOverrun = 0x00010000,
+       RxRuntFrame = 0x00020000,
+       RxAlignmentError = 0x00040000,
+       RxFCSError = 0x00080000,
+       RxOverSizedFrame = 0x00100000,
+       RxLengthError = 0x00200000,
+       VLANDetected = 0x00400000,
+       TCPDetected = 0x00800000,
+       TCPError = 0x01000000,
+       UDPDetected = 0x02000000,
+       UDPError = 0x04000000,
+       IPDetected = 0x08000000,
+       IPError = 0x10000000,
+       FrameStart = 0x20000000,
+       FrameEnd = 0x40000000,
+       RFDDone = 0x80000000,
+       TCIShift = 32,
+       RFS_Errors = 0x003f0000,
+};
+
+#define MII_RESET_TIME_OUT             10000
+/* MII register */
+enum _mii_reg {
+       MII_BMCR = 0,
+       MII_BMSR = 1,
+       MII_PHY_ID1 = 2,
+       MII_PHY_ID2 = 3,
+       MII_ANAR = 4,
+       MII_ANLPAR = 5,
+       MII_ANER = 6,
+       MII_ANNPT = 7,
+       MII_ANLPRNP = 8,
+       MII_MSCR = 9,
+       MII_MSSR = 10,
+       MII_ESR = 15,
+       MII_PHY_SCR = 16,
+};
+/* PCS register */
+enum _pcs_reg {
+       PCS_BMCR = 0,
+       PCS_BMSR = 1,
+       PCS_ANAR = 4,
+       PCS_ANLPAR = 5,
+       PCS_ANER = 6,
+       PCS_ANNPT = 7,
+       PCS_ANLPRNP = 8,
+       PCS_ESR = 15,
+};
+
+/* Basic Mode Control Register */
+enum _mii_bmcr {
+       MII_BMCR_RESET = 0x8000,
+       MII_BMCR_LOOP_BACK = 0x4000,
+       MII_BMCR_SPEED_LSB = 0x2000,
+       MII_BMCR_AN_ENABLE = 0x1000,
+       MII_BMCR_POWER_DOWN = 0x0800,
+       MII_BMCR_ISOLATE = 0x0400,
+       MII_BMCR_RESTART_AN = 0x0200,
+       MII_BMCR_DUPLEX_MODE = 0x0100,
+       MII_BMCR_COL_TEST = 0x0080,
+       MII_BMCR_SPEED_MSB = 0x0040,
+       MII_BMCR_SPEED_RESERVED = 0x003f,
+       MII_BMCR_SPEED_10 = 0,
+       MII_BMCR_SPEED_100 = MII_BMCR_SPEED_LSB,
+       MII_BMCR_SPEED_1000 = MII_BMCR_SPEED_MSB,
+};
+
+/* Basic Mode Status Register */
+enum _mii_bmsr {
+       MII_BMSR_100BT4 = 0x8000,
+       MII_BMSR_100BX_FD = 0x4000,
+       MII_BMSR_100BX_HD = 0x2000,
+       MII_BMSR_10BT_FD = 0x1000,
+       MII_BMSR_10BT_HD = 0x0800,
+       MII_BMSR_100BT2_FD = 0x0400,
+       MII_BMSR_100BT2_HD = 0x0200,
+       MII_BMSR_EXT_STATUS = 0x0100,
+       MII_BMSR_PREAMBLE_SUPP = 0x0040,
+       MII_BMSR_AN_COMPLETE = 0x0020,
+       MII_BMSR_REMOTE_FAULT = 0x0010,
+       MII_BMSR_AN_ABILITY = 0x0008,
+       MII_BMSR_LINK_STATUS = 0x0004,
+       MII_BMSR_JABBER_DETECT = 0x0002,
+       MII_BMSR_EXT_CAP = 0x0001,
+};
+
+/* ANAR */
+enum _mii_anar {
+       MII_ANAR_NEXT_PAGE = 0x8000,
+       MII_ANAR_REMOTE_FAULT = 0x4000,
+       MII_ANAR_ASYMMETRIC = 0x0800,
+       MII_ANAR_PAUSE = 0x0400,
+       MII_ANAR_100BT4 = 0x0200,
+       MII_ANAR_100BX_FD = 0x0100,
+       MII_ANAR_100BX_HD = 0x0080,
+       MII_ANAR_10BT_FD = 0x0020,
+       MII_ANAR_10BT_HD = 0x0010,
+       MII_ANAR_SELECTOR = 0x001f,
+       MII_IEEE8023_CSMACD = 0x0001,
+};
+
+/* ANLPAR */
+enum _mii_anlpar {
+       MII_ANLPAR_NEXT_PAGE = MII_ANAR_NEXT_PAGE,
+       MII_ANLPAR_REMOTE_FAULT = MII_ANAR_REMOTE_FAULT,
+       MII_ANLPAR_ASYMMETRIC = MII_ANAR_ASYMMETRIC,
+       MII_ANLPAR_PAUSE = MII_ANAR_PAUSE,
+       MII_ANLPAR_100BT4 = MII_ANAR_100BT4,
+       MII_ANLPAR_100BX_FD = MII_ANAR_100BX_FD,
+       MII_ANLPAR_100BX_HD = MII_ANAR_100BX_HD,
+       MII_ANLPAR_10BT_FD = MII_ANAR_10BT_FD,
+       MII_ANLPAR_10BT_HD = MII_ANAR_10BT_HD,
+       MII_ANLPAR_SELECTOR = MII_ANAR_SELECTOR,
+};
+
+/* Auto-Negotiation Expansion Register */
+enum _mii_aner {
+       MII_ANER_PAR_DETECT_FAULT = 0x0010,
+       MII_ANER_LP_NEXTPAGABLE = 0x0008,
+       MII_ANER_NETXTPAGABLE = 0x0004,
+       MII_ANER_PAGE_RECEIVED = 0x0002,
+       MII_ANER_LP_NEGOTIABLE = 0x0001,
+};
+
+/* MASTER-SLAVE Control Register */
+enum _mii_mscr {
+       MII_MSCR_TEST_MODE = 0xe000,
+       MII_MSCR_CFG_ENABLE = 0x1000,
+       MII_MSCR_CFG_VALUE = 0x0800,
+       MII_MSCR_PORT_VALUE = 0x0400,
+       MII_MSCR_1000BT_FD = 0x0200,
+       MII_MSCR_1000BT_HD = 0X0100,
+};
+
+/* MASTER-SLAVE Status Register */
+enum _mii_mssr {
+       MII_MSSR_CFG_FAULT = 0x8000,
+       MII_MSSR_CFG_RES = 0x4000,
+       MII_MSSR_LOCAL_RCV_STATUS = 0x2000,
+       MII_MSSR_REMOTE_RCVR = 0x1000,
+       MII_MSSR_LP_1000BT_FD = 0x0800,
+       MII_MSSR_LP_1000BT_HD = 0x0400,
+       MII_MSSR_IDLE_ERR_COUNT = 0x00ff,
+};
+
+/* IEEE Extened Status Register */
+enum _mii_esr {
+       MII_ESR_1000BX_FD = 0x8000,
+       MII_ESR_1000BX_HD = 0x4000,
+       MII_ESR_1000BT_FD = 0x2000,
+       MII_ESR_1000BT_HD = 0x1000,
+};
+/* PHY Specific Control Register */
+#if 0
+typedef union t_MII_PHY_SCR {
+       u16 image;
+       struct {
+               u16 disable_jabber:1;   // bit 0
+               u16 polarity_reversal:1;        // bit 1
+               u16 SEQ_test:1; // bit 2
+               u16 _bit_3:1;   // bit 3
+               u16 disable_CLK125:1;   // bit 4
+               u16 mdi_crossover_mode:2;       // bit 6:5
+               u16 enable_ext_dist:1;  // bit 7
+               u16 _bit_8_9:2; // bit 9:8
+               u16 force_link:1;       // bit 10
+               u16 assert_CRS:1;       // bit 11
+               u16 rcv_fifo_depth:2;   // bit 13:12
+               u16 xmit_fifo_depth:2;  // bit 15:14
+       } bits;
+} PHY_SCR_t, *PPHY_SCR_t;
+#endif
+
+typedef enum t_MII_ADMIN_STATUS {
+       adm_reset,
+       adm_operational,
+       adm_loopback,
+       adm_power_down,
+       adm_isolate
+} MII_ADMIN_t, *PMII_ADMIN_t;
+
+/* Physical Coding Sublayer Management (PCS) */
+/* PCS control and status registers bitmap as the same as MII */
+/* PCS Extended Status register bitmap as the same as MII */
+/* PCS ANAR */
+enum _pcs_anar {
+       PCS_ANAR_NEXT_PAGE = 0x8000,
+       PCS_ANAR_REMOTE_FAULT = 0x3000,
+       PCS_ANAR_ASYMMETRIC = 0x0100,
+       PCS_ANAR_PAUSE = 0x0080,
+       PCS_ANAR_HALF_DUPLEX = 0x0040,
+       PCS_ANAR_FULL_DUPLEX = 0x0020,
+};
+/* PCS ANLPAR */
+enum _pcs_anlpar {
+       PCS_ANLPAR_NEXT_PAGE = PCS_ANAR_NEXT_PAGE,
+       PCS_ANLPAR_REMOTE_FAULT = PCS_ANAR_REMOTE_FAULT,
+       PCS_ANLPAR_ASYMMETRIC = PCS_ANAR_ASYMMETRIC,
+       PCS_ANLPAR_PAUSE = PCS_ANAR_PAUSE,
+       PCS_ANLPAR_HALF_DUPLEX = PCS_ANAR_HALF_DUPLEX,
+       PCS_ANLPAR_FULL_DUPLEX = PCS_ANAR_FULL_DUPLEX,
+};
+
+typedef struct t_SROM {
+       u16 config_param;       /* 0x00 */
+       u16 asic_ctrl;          /* 0x02 */
+       u16 sub_vendor_id;      /* 0x04 */
+       u16 sub_system_id;      /* 0x06 */
+       u16 reserved1[12];      /* 0x08-0x1f */
+       u8 mac_addr[6];         /* 0x20-0x25 */
+       u8 reserved2[10];       /* 0x26-0x2f */
+       u8 sib[204];            /* 0x30-0xfb */
+       u32 crc;                /* 0xfc-0xff */
+} SROM_t, *PSROM_t;
+
+/* Ioctl custom data */
+struct ioctl_data {
+       char signature[10];
+       int cmd;
+       int len;
+       char *data;
+};
+
+struct mii_data {
+       __u16 reserved;
+       __u16 reg_num;
+       __u16 in_value;
+       __u16 out_value;
+};
+
+/* The Rx and Tx buffer descriptors. */
+struct netdev_desc {
+       __le64 next_desc;
+       __le64 status;
+       __le64 fraginfo;
+};
+
+#define PRIV_ALIGN     15      /* Required alignment mask */
+/* Use  __attribute__((aligned (L1_CACHE_BYTES)))  to maintain alignment
+   within the structure. */
+struct netdev_private {
+       /* Descriptor rings first for alignment. */
+       struct netdev_desc *rx_ring;
+       struct netdev_desc *tx_ring;
+       struct sk_buff *rx_skbuff[RX_RING_SIZE];
+       struct sk_buff *tx_skbuff[TX_RING_SIZE];
+       dma_addr_t tx_ring_dma;
+       dma_addr_t rx_ring_dma;
+       struct pci_dev *pdev;
+       spinlock_t tx_lock;
+       spinlock_t rx_lock;
+       struct net_device_stats stats;
+       unsigned int rx_buf_sz;         /* Based on MTU+slack. */
+       unsigned int speed;             /* Operating speed */
+       unsigned int vlan;              /* VLAN Id */
+       unsigned int chip_id;           /* PCI table chip id */
+       unsigned int rx_coalesce;       /* Maximum frames each RxDMAComplete intr */
+       unsigned int rx_timeout;        /* Wait time between RxDMAComplete intr */
+       unsigned int tx_coalesce;       /* Maximum frames each tx interrupt */
+       unsigned int full_duplex:1;     /* Full-duplex operation requested. */
+       unsigned int an_enable:2;       /* Auto-Negotiated Enable */
+       unsigned int jumbo:1;           /* Jumbo frame enable */
+       unsigned int coalesce:1;        /* Rx coalescing enable */
+       unsigned int tx_flow:1;         /* Tx flow control enable */
+       unsigned int rx_flow:1;         /* Rx flow control enable */
+       unsigned int phy_media:1;       /* 1: fiber, 0: copper */
+       unsigned int link_status:1;     /* Current link status */
+       struct netdev_desc *last_tx;    /* Last Tx descriptor used. */
+       unsigned long cur_rx, old_rx;   /* Producer/consumer ring indices */
+       unsigned long cur_tx, old_tx;
+       struct timer_list timer;
+       int wake_polarity;
+       char name[256];         /* net device description */
+       u8 duplex_polarity;
+       u16 mcast_filter[4];
+       u16 advertising;        /* NWay media advertisement */
+       u16 negotiate;          /* Negotiated media */
+       int phy_addr;           /* PHY addresses. */
+};
+
+/* The station address location in the EEPROM. */
+/* The struct pci_device_id consist of:
+        vendor, device          Vendor and device ID to match (or PCI_ANY_ID)
+        subvendor, subdevice    Subsystem vendor and device ID to match (or PCI_ANY_ID)
+        class                   Device class to match. The class_mask tells which bits
+        class_mask              of the class are honored during the comparison.
+        driver_data             Data private to the driver.
+*/
+
+static DEFINE_PCI_DEVICE_TABLE(rio_pci_tbl) = {
+       {0x1186, 0x4000, PCI_ANY_ID, PCI_ANY_ID, },
+       {0x13f0, 0x1021, PCI_ANY_ID, PCI_ANY_ID, },
+       { }
+};
+MODULE_DEVICE_TABLE (pci, rio_pci_tbl);
+#define TX_TIMEOUT  (4*HZ)
+#define PACKET_SIZE            1536
+#define MAX_JUMBO              8000
+#define RIO_IO_SIZE             340
+#define DEFAULT_RXC            5
+#define DEFAULT_RXT            750
+#define DEFAULT_TXC            1
+#define MAX_TXC                        8
+#endif                         /* __DL2K_H__ */
diff --git a/drivers/net/ethernet/dlink/sundance.c b/drivers/net/ethernet/dlink/sundance.c
new file mode 100644 (file)
index 0000000..4793df8
--- /dev/null
@@ -0,0 +1,1940 @@
+/* sundance.c: A Linux device driver for the Sundance ST201 "Alta". */
+/*
+       Written 1999-2000 by Donald Becker.
+
+       This software may be used and distributed according to the terms of
+       the GNU General Public License (GPL), incorporated herein by reference.
+       Drivers based on or derived from this code fall under the GPL and must
+       retain the authorship, copyright and license notice.  This file is not
+       a complete program and may only be used when the entire operating
+       system is licensed under the GPL.
+
+       The author may be reached as becker@scyld.com, or C/O
+       Scyld Computing Corporation
+       410 Severn Ave., Suite 210
+       Annapolis MD 21403
+
+       Support and updates available at
+       http://www.scyld.com/network/sundance.html
+       [link no longer provides useful info -jgarzik]
+       Archives of the mailing list are still available at
+       http://www.beowulf.org/pipermail/netdrivers/
+
+*/
+
+#define DRV_NAME       "sundance"
+#define DRV_VERSION    "1.2"
+#define DRV_RELDATE    "11-Sep-2006"
+
+
+/* The user-configurable values.
+   These may be modified when a driver module is loaded.*/
+static int debug = 1;                  /* 1 normal messages, 0 quiet .. 7 verbose. */
+/* Maximum number of multicast addresses to filter (vs. rx-all-multicast).
+   Typical is a 64 element hash table based on the Ethernet CRC.  */
+static const int multicast_filter_limit = 32;
+
+/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
+   Setting to > 1518 effectively disables this feature.
+   This chip can receive into offset buffers, so the Alpha does not
+   need a copy-align. */
+static int rx_copybreak;
+static int flowctrl=1;
+
+/* media[] specifies the media type the NIC operates at.
+                autosense      Autosensing active media.
+                10mbps_hd      10Mbps half duplex.
+                10mbps_fd      10Mbps full duplex.
+                100mbps_hd     100Mbps half duplex.
+                100mbps_fd     100Mbps full duplex.
+                0              Autosensing active media.
+                1              10Mbps half duplex.
+                2              10Mbps full duplex.
+                3              100Mbps half duplex.
+                4              100Mbps full duplex.
+*/
+#define MAX_UNITS 8
+static char *media[MAX_UNITS];
+
+
+/* Operational parameters that are set at compile time. */
+
+/* Keep the ring sizes a power of two for compile efficiency.
+   The compiler will convert <unsigned>'%'<2^N> into a bit mask.
+   Making the Tx ring too large decreases the effectiveness of channel
+   bonding and packet priority, and more than 128 requires modifying the
+   Tx error recovery.
+   Large receive rings merely waste memory. */
+#define TX_RING_SIZE   32
+#define TX_QUEUE_LEN   (TX_RING_SIZE - 1) /* Limit ring entries actually used.  */
+#define RX_RING_SIZE   64
+#define RX_BUDGET      32
+#define TX_TOTAL_SIZE  TX_RING_SIZE*sizeof(struct netdev_desc)
+#define RX_TOTAL_SIZE  RX_RING_SIZE*sizeof(struct netdev_desc)
+
+/* Operational parameters that usually are not changed. */
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT  (4*HZ)
+#define PKT_BUF_SZ             1536    /* Size of each temporary Rx buffer.*/
+
+/* Include files, designed to support most kernel versions 2.0.0 and later. */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <asm/uaccess.h>
+#include <asm/processor.h>             /* Processor type for cache alignment. */
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/dma-mapping.h>
+#include <linux/crc32.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+
+/* These identify the driver base version and may not be removed. */
+static const char version[] __devinitconst =
+       KERN_INFO DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE
+       " Written by Donald Becker\n";
+
+MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
+MODULE_DESCRIPTION("Sundance Alta Ethernet driver");
+MODULE_LICENSE("GPL");
+
+module_param(debug, int, 0);
+module_param(rx_copybreak, int, 0);
+module_param_array(media, charp, NULL, 0);
+module_param(flowctrl, int, 0);
+MODULE_PARM_DESC(debug, "Sundance Alta debug level (0-5)");
+MODULE_PARM_DESC(rx_copybreak, "Sundance Alta copy breakpoint for copy-only-tiny-frames");
+MODULE_PARM_DESC(flowctrl, "Sundance Alta flow control [0|1]");
+
+/*
+                               Theory of Operation
+
+I. Board Compatibility
+
+This driver is designed for the Sundance Technologies "Alta" ST201 chip.
+
+II. Board-specific settings
+
+III. Driver operation
+
+IIIa. Ring buffers
+
+This driver uses two statically allocated fixed-size descriptor lists
+formed into rings by a branch from the final descriptor to the beginning of
+the list.  The ring sizes are set at compile time by RX/TX_RING_SIZE.
+Some chips explicitly use only 2^N sized rings, while others use a
+'next descriptor' pointer that the driver forms into rings.
+
+IIIb/c. Transmit/Receive Structure
+
+This driver uses a zero-copy receive and transmit scheme.
+The driver allocates full frame size skbuffs for the Rx ring buffers at
+open() time and passes the skb->data field to the chip as receive data
+buffers.  When an incoming frame is less than RX_COPYBREAK bytes long,
+a fresh skbuff is allocated and the frame is copied to the new skbuff.
+When the incoming frame is larger, the skbuff is passed directly up the
+protocol stack.  Buffers consumed this way are replaced by newly allocated
+skbuffs in a later phase of receives.
+
+The RX_COPYBREAK value is chosen to trade-off the memory wasted by
+using a full-sized skbuff for small frames vs. the copying costs of larger
+frames.  New boards are typically used in generously configured machines
+and the underfilled buffers have negligible impact compared to the benefit of
+a single allocation size, so the default value of zero results in never
+copying packets.  When copying is done, the cost is usually mitigated by using
+a combined copy/checksum routine.  Copying also preloads the cache, which is
+most useful with small frames.
+
+A subtle aspect of the operation is that the IP header at offset 14 in an
+ethernet frame isn't longword aligned for further processing.
+Unaligned buffers are permitted by the Sundance hardware, so
+frames are received into the skbuff at an offset of "+2", 16-byte aligning
+the IP header.
+
+IIId. Synchronization
+
+The driver runs as two independent, single-threaded flows of control.  One
+is the send-packet routine, which enforces single-threaded use by the
+dev->tbusy flag.  The other thread is the interrupt handler, which is single
+threaded by the hardware and interrupt handling software.
+
+The send packet thread has partial control over the Tx ring and 'dev->tbusy'
+flag.  It sets the tbusy flag whenever it's queuing a Tx packet. If the next
+queue slot is empty, it clears the tbusy flag when finished otherwise it sets
+the 'lp->tx_full' flag.
+
+The interrupt handler has exclusive control over the Rx ring and records stats
+from the Tx ring.  After reaping the stats, it marks the Tx queue entry as
+empty by incrementing the dirty_tx mark. Iff the 'lp->tx_full' flag is set, it
+clears both the tx_full and tbusy flags.
+
+IV. Notes
+
+IVb. References
+
+The Sundance ST201 datasheet, preliminary version.
+The Kendin KS8723 datasheet, preliminary version.
+The ICplus IP100 datasheet, preliminary version.
+http://www.scyld.com/expert/100mbps.html
+http://www.scyld.com/expert/NWay.html
+
+IVc. Errata
+
+*/
+
+/* Work-around for Kendin chip bugs. */
+#ifndef CONFIG_SUNDANCE_MMIO
+#define USE_IO_OPS 1
+#endif
+
+static DEFINE_PCI_DEVICE_TABLE(sundance_pci_tbl) = {
+       { 0x1186, 0x1002, 0x1186, 0x1002, 0, 0, 0 },
+       { 0x1186, 0x1002, 0x1186, 0x1003, 0, 0, 1 },
+       { 0x1186, 0x1002, 0x1186, 0x1012, 0, 0, 2 },
+       { 0x1186, 0x1002, 0x1186, 0x1040, 0, 0, 3 },
+       { 0x1186, 0x1002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
+       { 0x13F0, 0x0201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5 },
+       { 0x13F0, 0x0200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6 },
+       { }
+};
+MODULE_DEVICE_TABLE(pci, sundance_pci_tbl);
+
+enum {
+       netdev_io_size = 128
+};
+
+struct pci_id_info {
+        const char *name;
+};
+static const struct pci_id_info pci_id_tbl[] __devinitdata = {
+       {"D-Link DFE-550TX FAST Ethernet Adapter"},
+       {"D-Link DFE-550FX 100Mbps Fiber-optics Adapter"},
+       {"D-Link DFE-580TX 4 port Server Adapter"},
+       {"D-Link DFE-530TXS FAST Ethernet Adapter"},
+       {"D-Link DL10050-based FAST Ethernet Adapter"},
+       {"Sundance Technology Alta"},
+       {"IC Plus Corporation IP100A FAST Ethernet Adapter"},
+       { }     /* terminate list. */
+};
+
+/* This driver was written to use PCI memory space, however x86-oriented
+   hardware often uses I/O space accesses. */
+
+/* Offsets to the device registers.
+   Unlike software-only systems, device drivers interact with complex hardware.
+   It's not useful to define symbolic names for every register bit in the
+   device.  The name can only partially document the semantics and make
+   the driver longer and more difficult to read.
+   In general, only the important configuration values or bits changed
+   multiple times should be defined symbolically.
+*/
+enum alta_offsets {
+       DMACtrl = 0x00,
+       TxListPtr = 0x04,
+       TxDMABurstThresh = 0x08,
+       TxDMAUrgentThresh = 0x09,
+       TxDMAPollPeriod = 0x0a,
+       RxDMAStatus = 0x0c,
+       RxListPtr = 0x10,
+       DebugCtrl0 = 0x1a,
+       DebugCtrl1 = 0x1c,
+       RxDMABurstThresh = 0x14,
+       RxDMAUrgentThresh = 0x15,
+       RxDMAPollPeriod = 0x16,
+       LEDCtrl = 0x1a,
+       ASICCtrl = 0x30,
+       EEData = 0x34,
+       EECtrl = 0x36,
+       FlashAddr = 0x40,
+       FlashData = 0x44,
+       TxStatus = 0x46,
+       TxFrameId = 0x47,
+       DownCounter = 0x18,
+       IntrClear = 0x4a,
+       IntrEnable = 0x4c,
+       IntrStatus = 0x4e,
+       MACCtrl0 = 0x50,
+       MACCtrl1 = 0x52,
+       StationAddr = 0x54,
+       MaxFrameSize = 0x5A,
+       RxMode = 0x5c,
+       MIICtrl = 0x5e,
+       MulticastFilter0 = 0x60,
+       MulticastFilter1 = 0x64,
+       RxOctetsLow = 0x68,
+       RxOctetsHigh = 0x6a,
+       TxOctetsLow = 0x6c,
+       TxOctetsHigh = 0x6e,
+       TxFramesOK = 0x70,
+       RxFramesOK = 0x72,
+       StatsCarrierError = 0x74,
+       StatsLateColl = 0x75,
+       StatsMultiColl = 0x76,
+       StatsOneColl = 0x77,
+       StatsTxDefer = 0x78,
+       RxMissed = 0x79,
+       StatsTxXSDefer = 0x7a,
+       StatsTxAbort = 0x7b,
+       StatsBcastTx = 0x7c,
+       StatsBcastRx = 0x7d,
+       StatsMcastTx = 0x7e,
+       StatsMcastRx = 0x7f,
+       /* Aliased and bogus values! */
+       RxStatus = 0x0c,
+};
+
+#define ASIC_HI_WORD(x)        ((x) + 2)
+
+enum ASICCtrl_HiWord_bit {
+       GlobalReset = 0x0001,
+       RxReset = 0x0002,
+       TxReset = 0x0004,
+       DMAReset = 0x0008,
+       FIFOReset = 0x0010,
+       NetworkReset = 0x0020,
+       HostReset = 0x0040,
+       ResetBusy = 0x0400,
+};
+
+/* Bits in the interrupt status/mask registers. */
+enum intr_status_bits {
+       IntrSummary=0x0001, IntrPCIErr=0x0002, IntrMACCtrl=0x0008,
+       IntrTxDone=0x0004, IntrRxDone=0x0010, IntrRxStart=0x0020,
+       IntrDrvRqst=0x0040,
+       StatsMax=0x0080, LinkChange=0x0100,
+       IntrTxDMADone=0x0200, IntrRxDMADone=0x0400,
+};
+
+/* Bits in the RxMode register. */
+enum rx_mode_bits {
+       AcceptAllIPMulti=0x20, AcceptMultiHash=0x10, AcceptAll=0x08,
+       AcceptBroadcast=0x04, AcceptMulticast=0x02, AcceptMyPhys=0x01,
+};
+/* Bits in MACCtrl. */
+enum mac_ctrl0_bits {
+       EnbFullDuplex=0x20, EnbRcvLargeFrame=0x40,
+       EnbFlowCtrl=0x100, EnbPassRxCRC=0x200,
+};
+enum mac_ctrl1_bits {
+       StatsEnable=0x0020,     StatsDisable=0x0040, StatsEnabled=0x0080,
+       TxEnable=0x0100, TxDisable=0x0200, TxEnabled=0x0400,
+       RxEnable=0x0800, RxDisable=0x1000, RxEnabled=0x2000,
+};
+
+/* The Rx and Tx buffer descriptors. */
+/* Note that using only 32 bit fields simplifies conversion to big-endian
+   architectures. */
+struct netdev_desc {
+       __le32 next_desc;
+       __le32 status;
+       struct desc_frag { __le32 addr, length; } frag[1];
+};
+
+/* Bits in netdev_desc.status */
+enum desc_status_bits {
+       DescOwn=0x8000,
+       DescEndPacket=0x4000,
+       DescEndRing=0x2000,
+       LastFrag=0x80000000,
+       DescIntrOnTx=0x8000,
+       DescIntrOnDMADone=0x80000000,
+       DisableAlign = 0x00000001,
+};
+
+#define PRIV_ALIGN     15      /* Required alignment mask */
+/* Use  __attribute__((aligned (L1_CACHE_BYTES)))  to maintain alignment
+   within the structure. */
+#define MII_CNT                4
+struct netdev_private {
+       /* Descriptor rings first for alignment. */
+       struct netdev_desc *rx_ring;
+       struct netdev_desc *tx_ring;
+       struct sk_buff* rx_skbuff[RX_RING_SIZE];
+       struct sk_buff* tx_skbuff[TX_RING_SIZE];
+        dma_addr_t tx_ring_dma;
+        dma_addr_t rx_ring_dma;
+       struct timer_list timer;                /* Media monitoring timer. */
+       /* ethtool extra stats */
+       struct {
+               u64 tx_multiple_collisions;
+               u64 tx_single_collisions;
+               u64 tx_late_collisions;
+               u64 tx_deferred;
+               u64 tx_deferred_excessive;
+               u64 tx_aborted;
+               u64 tx_bcasts;
+               u64 rx_bcasts;
+               u64 tx_mcasts;
+               u64 rx_mcasts;
+       } xstats;
+       /* Frequently used values: keep some adjacent for cache effect. */
+       spinlock_t lock;
+       int msg_enable;
+       int chip_id;
+       unsigned int cur_rx, dirty_rx;          /* Producer/consumer ring indices */
+       unsigned int rx_buf_sz;                 /* Based on MTU+slack. */
+       struct netdev_desc *last_tx;            /* Last Tx descriptor used. */
+       unsigned int cur_tx, dirty_tx;
+       /* These values are keep track of the transceiver/media in use. */
+       unsigned int flowctrl:1;
+       unsigned int default_port:4;            /* Last dev->if_port value. */
+       unsigned int an_enable:1;
+       unsigned int speed;
+       struct tasklet_struct rx_tasklet;
+       struct tasklet_struct tx_tasklet;
+       int budget;
+       int cur_task;
+       /* Multicast and receive mode. */
+       spinlock_t mcastlock;                   /* SMP lock multicast updates. */
+       u16 mcast_filter[4];
+       /* MII transceiver section. */
+       struct mii_if_info mii_if;
+       int mii_preamble_required;
+       unsigned char phys[MII_CNT];            /* MII device addresses, only first one used. */
+       struct pci_dev *pci_dev;
+       void __iomem *base;
+       spinlock_t statlock;
+};
+
+/* The station address location in the EEPROM. */
+#define EEPROM_SA_OFFSET       0x10
+#define DEFAULT_INTR (IntrRxDMADone | IntrPCIErr | \
+                       IntrDrvRqst | IntrTxDone | StatsMax | \
+                       LinkChange)
+
+static int  change_mtu(struct net_device *dev, int new_mtu);
+static int  eeprom_read(void __iomem *ioaddr, int location);
+static int  mdio_read(struct net_device *dev, int phy_id, int location);
+static void mdio_write(struct net_device *dev, int phy_id, int location, int value);
+static int  mdio_wait_link(struct net_device *dev, int wait);
+static int  netdev_open(struct net_device *dev);
+static void check_duplex(struct net_device *dev);
+static void netdev_timer(unsigned long data);
+static void tx_timeout(struct net_device *dev);
+static void init_ring(struct net_device *dev);
+static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev);
+static int reset_tx (struct net_device *dev);
+static irqreturn_t intr_handler(int irq, void *dev_instance);
+static void rx_poll(unsigned long data);
+static void tx_poll(unsigned long data);
+static void refill_rx (struct net_device *dev);
+static void netdev_error(struct net_device *dev, int intr_status);
+static void netdev_error(struct net_device *dev, int intr_status);
+static void set_rx_mode(struct net_device *dev);
+static int __set_mac_addr(struct net_device *dev);
+static int sundance_set_mac_addr(struct net_device *dev, void *data);
+static struct net_device_stats *get_stats(struct net_device *dev);
+static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static int  netdev_close(struct net_device *dev);
+static const struct ethtool_ops ethtool_ops;
+
+static void sundance_reset(struct net_device *dev, unsigned long reset_cmd)
+{
+       struct netdev_private *np = netdev_priv(dev);
+       void __iomem *ioaddr = np->base + ASICCtrl;
+       int countdown;
+
+       /* ST201 documentation states ASICCtrl is a 32bit register */
+       iowrite32 (reset_cmd | ioread32 (ioaddr), ioaddr);
+       /* ST201 documentation states reset can take up to 1 ms */
+       countdown = 10 + 1;
+       while (ioread32 (ioaddr) & (ResetBusy << 16)) {
+               if (--countdown == 0) {
+                       printk(KERN_WARNING "%s : reset not completed !!\n", dev->name);
+                       break;
+               }
+               udelay(100);
+       }
+}
+
+static const struct net_device_ops netdev_ops = {
+       .ndo_open               = netdev_open,
+       .ndo_stop               = netdev_close,
+       .ndo_start_xmit         = start_tx,
+       .ndo_get_stats          = get_stats,
+       .ndo_set_multicast_list = set_rx_mode,
+       .ndo_do_ioctl           = netdev_ioctl,
+       .ndo_tx_timeout         = tx_timeout,
+       .ndo_change_mtu         = change_mtu,
+       .ndo_set_mac_address    = sundance_set_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
+static int __devinit sundance_probe1 (struct pci_dev *pdev,
+                                     const struct pci_device_id *ent)
+{
+       struct net_device *dev;
+       struct netdev_private *np;
+       static int card_idx;
+       int chip_idx = ent->driver_data;
+       int irq;
+       int i;
+       void __iomem *ioaddr;
+       u16 mii_ctl;
+       void *ring_space;
+       dma_addr_t ring_dma;
+#ifdef USE_IO_OPS
+       int bar = 0;
+#else
+       int bar = 1;
+#endif
+       int phy, phy_end, phy_idx = 0;
+
+/* when built into the kernel, we only print version if device is found */
+#ifndef MODULE
+       static int printed_version;
+       if (!printed_version++)
+               printk(version);
+#endif
+
+       if (pci_enable_device(pdev))
+               return -EIO;
+       pci_set_master(pdev);
+
+       irq = pdev->irq;
+
+       dev = alloc_etherdev(sizeof(*np));
+       if (!dev)
+               return -ENOMEM;
+       SET_NETDEV_DEV(dev, &pdev->dev);
+
+       if (pci_request_regions(pdev, DRV_NAME))
+               goto err_out_netdev;
+
+       ioaddr = pci_iomap(pdev, bar, netdev_io_size);
+       if (!ioaddr)
+               goto err_out_res;
+
+       for (i = 0; i < 3; i++)
+               ((__le16 *)dev->dev_addr)[i] =
+                       cpu_to_le16(eeprom_read(ioaddr, i + EEPROM_SA_OFFSET));
+       memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
+
+       dev->base_addr = (unsigned long)ioaddr;
+       dev->irq = irq;
+
+       np = netdev_priv(dev);
+       np->base = ioaddr;
+       np->pci_dev = pdev;
+       np->chip_id = chip_idx;
+       np->msg_enable = (1 << debug) - 1;
+       spin_lock_init(&np->lock);
+       spin_lock_init(&np->statlock);
+       tasklet_init(&np->rx_tasklet, rx_poll, (unsigned long)dev);
+       tasklet_init(&np->tx_tasklet, tx_poll, (unsigned long)dev);
+
+       ring_space = dma_alloc_coherent(&pdev->dev, TX_TOTAL_SIZE,
+                       &ring_dma, GFP_KERNEL);
+       if (!ring_space)
+               goto err_out_cleardev;
+       np->tx_ring = (struct netdev_desc *)ring_space;
+       np->tx_ring_dma = ring_dma;
+
+       ring_space = dma_alloc_coherent(&pdev->dev, RX_TOTAL_SIZE,
+                       &ring_dma, GFP_KERNEL);
+       if (!ring_space)
+               goto err_out_unmap_tx;
+       np->rx_ring = (struct netdev_desc *)ring_space;
+       np->rx_ring_dma = ring_dma;
+
+       np->mii_if.dev = dev;
+       np->mii_if.mdio_read = mdio_read;
+       np->mii_if.mdio_write = mdio_write;
+       np->mii_if.phy_id_mask = 0x1f;
+       np->mii_if.reg_num_mask = 0x1f;
+
+       /* The chip-specific entries in the device structure. */
+       dev->netdev_ops = &netdev_ops;
+       SET_ETHTOOL_OPS(dev, &ethtool_ops);
+       dev->watchdog_timeo = TX_TIMEOUT;
+
+       pci_set_drvdata(pdev, dev);
+
+       i = register_netdev(dev);
+       if (i)
+               goto err_out_unmap_rx;
+
+       printk(KERN_INFO "%s: %s at %p, %pM, IRQ %d.\n",
+              dev->name, pci_id_tbl[chip_idx].name, ioaddr,
+              dev->dev_addr, irq);
+
+       np->phys[0] = 1;                /* Default setting */
+       np->mii_preamble_required++;
+
+       /*
+        * It seems some phys doesn't deal well with address 0 being accessed
+        * first
+        */
+       if (sundance_pci_tbl[np->chip_id].device == 0x0200) {
+               phy = 0;
+               phy_end = 31;
+       } else {
+               phy = 1;
+               phy_end = 32;   /* wraps to zero, due to 'phy & 0x1f' */
+       }
+       for (; phy <= phy_end && phy_idx < MII_CNT; phy++) {
+               int phyx = phy & 0x1f;
+               int mii_status = mdio_read(dev, phyx, MII_BMSR);
+               if (mii_status != 0xffff  &&  mii_status != 0x0000) {
+                       np->phys[phy_idx++] = phyx;
+                       np->mii_if.advertising = mdio_read(dev, phyx, MII_ADVERTISE);
+                       if ((mii_status & 0x0040) == 0)
+                               np->mii_preamble_required++;
+                       printk(KERN_INFO "%s: MII PHY found at address %d, status "
+                                  "0x%4.4x advertising %4.4x.\n",
+                                  dev->name, phyx, mii_status, np->mii_if.advertising);
+               }
+       }
+       np->mii_preamble_required--;
+
+       if (phy_idx == 0) {
+               printk(KERN_INFO "%s: No MII transceiver found, aborting.  ASIC status %x\n",
+                          dev->name, ioread32(ioaddr + ASICCtrl));
+               goto err_out_unregister;
+       }
+
+       np->mii_if.phy_id = np->phys[0];
+
+       /* Parse override configuration */
+       np->an_enable = 1;
+       if (card_idx < MAX_UNITS) {
+               if (media[card_idx] != NULL) {
+                       np->an_enable = 0;
+                       if (strcmp (media[card_idx], "100mbps_fd") == 0 ||
+                           strcmp (media[card_idx], "4") == 0) {
+                               np->speed = 100;
+                               np->mii_if.full_duplex = 1;
+                       } else if (strcmp (media[card_idx], "100mbps_hd") == 0 ||
+                                  strcmp (media[card_idx], "3") == 0) {
+                               np->speed = 100;
+                               np->mii_if.full_duplex = 0;
+                       } else if (strcmp (media[card_idx], "10mbps_fd") == 0 ||
+                                  strcmp (media[card_idx], "2") == 0) {
+                               np->speed = 10;
+                               np->mii_if.full_duplex = 1;
+                       } else if (strcmp (media[card_idx], "10mbps_hd") == 0 ||
+                                  strcmp (media[card_idx], "1") == 0) {
+                               np->speed = 10;
+                               np->mii_if.full_duplex = 0;
+                       } else {
+                               np->an_enable = 1;
+                       }
+               }
+               if (flowctrl == 1)
+                       np->flowctrl = 1;
+       }
+
+       /* Fibre PHY? */
+       if (ioread32 (ioaddr + ASICCtrl) & 0x80) {
+               /* Default 100Mbps Full */
+               if (np->an_enable) {
+                       np->speed = 100;
+                       np->mii_if.full_duplex = 1;
+                       np->an_enable = 0;
+               }
+       }
+       /* Reset PHY */
+       mdio_write (dev, np->phys[0], MII_BMCR, BMCR_RESET);
+       mdelay (300);
+       /* If flow control enabled, we need to advertise it.*/
+       if (np->flowctrl)
+               mdio_write (dev, np->phys[0], MII_ADVERTISE, np->mii_if.advertising | 0x0400);
+       mdio_write (dev, np->phys[0], MII_BMCR, BMCR_ANENABLE|BMCR_ANRESTART);
+       /* Force media type */
+       if (!np->an_enable) {
+               mii_ctl = 0;
+               mii_ctl |= (np->speed == 100) ? BMCR_SPEED100 : 0;
+               mii_ctl |= (np->mii_if.full_duplex) ? BMCR_FULLDPLX : 0;
+               mdio_write (dev, np->phys[0], MII_BMCR, mii_ctl);
+               printk (KERN_INFO "Override speed=%d, %s duplex\n",
+                       np->speed, np->mii_if.full_duplex ? "Full" : "Half");
+
+       }
+
+       /* Perhaps move the reset here? */
+       /* Reset the chip to erase previous misconfiguration. */
+       if (netif_msg_hw(np))
+               printk("ASIC Control is %x.\n", ioread32(ioaddr + ASICCtrl));
+       sundance_reset(dev, 0x00ff << 16);
+       if (netif_msg_hw(np))
+               printk("ASIC Control is now %x.\n", ioread32(ioaddr + ASICCtrl));
+
+       card_idx++;
+       return 0;
+
+err_out_unregister:
+       unregister_netdev(dev);
+err_out_unmap_rx:
+       dma_free_coherent(&pdev->dev, RX_TOTAL_SIZE,
+               np->rx_ring, np->rx_ring_dma);
+err_out_unmap_tx:
+       dma_free_coherent(&pdev->dev, TX_TOTAL_SIZE,
+               np->tx_ring, np->tx_ring_dma);
+err_out_cleardev:
+       pci_set_drvdata(pdev, NULL);
+       pci_iounmap(pdev, ioaddr);
+err_out_res:
+       pci_release_regions(pdev);
+err_out_netdev:
+       free_netdev (dev);
+       return -ENODEV;
+}
+
+static int change_mtu(struct net_device *dev, int new_mtu)
+{
+       if ((new_mtu < 68) || (new_mtu > 8191)) /* Set by RxDMAFrameLen */
+               return -EINVAL;
+       if (netif_running(dev))
+               return -EBUSY;
+       dev->mtu = new_mtu;
+       return 0;
+}
+
+#define eeprom_delay(ee_addr)  ioread32(ee_addr)
+/* Read the EEPROM and MII Management Data I/O (MDIO) interfaces. */
+static int __devinit eeprom_read(void __iomem *ioaddr, int location)
+{
+       int boguscnt = 10000;           /* Typical 1900 ticks. */
+       iowrite16(0x0200 | (location & 0xff), ioaddr + EECtrl);
+       do {
+               eeprom_delay(ioaddr + EECtrl);
+               if (! (ioread16(ioaddr + EECtrl) & 0x8000)) {
+                       return ioread16(ioaddr + EEData);
+               }
+       } while (--boguscnt > 0);
+       return 0;
+}
+
+/*  MII transceiver control section.
+       Read and write the MII registers using software-generated serial
+       MDIO protocol.  See the MII specifications or DP83840A data sheet
+       for details.
+
+       The maximum data clock rate is 2.5 Mhz.  The minimum timing is usually
+       met by back-to-back 33Mhz PCI cycles. */
+#define mdio_delay() ioread8(mdio_addr)
+
+enum mii_reg_bits {
+       MDIO_ShiftClk=0x0001, MDIO_Data=0x0002, MDIO_EnbOutput=0x0004,
+};
+#define MDIO_EnbIn  (0)
+#define MDIO_WRITE0 (MDIO_EnbOutput)
+#define MDIO_WRITE1 (MDIO_Data | MDIO_EnbOutput)
+
+/* Generate the preamble required for initial synchronization and
+   a few older transceivers. */
+static void mdio_sync(void __iomem *mdio_addr)
+{
+       int bits = 32;
+
+       /* Establish sync by sending at least 32 logic ones. */
+       while (--bits >= 0) {
+               iowrite8(MDIO_WRITE1, mdio_addr);
+               mdio_delay();
+               iowrite8(MDIO_WRITE1 | MDIO_ShiftClk, mdio_addr);
+               mdio_delay();
+       }
+}
+
+static int mdio_read(struct net_device *dev, int phy_id, int location)
+{
+       struct netdev_private *np = netdev_priv(dev);
+       void __iomem *mdio_addr = np->base + MIICtrl;
+       int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;
+       int i, retval = 0;
+
+       if (np->mii_preamble_required)
+               mdio_sync(mdio_addr);
+
+       /* Shift the read command bits out. */
+       for (i = 15; i >= 0; i--) {
+               int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
+
+               iowrite8(dataval, mdio_addr);
+               mdio_delay();
+               iowrite8(dataval | MDIO_ShiftClk, mdio_addr);
+               mdio_delay();
+       }
+       /* Read the two transition, 16 data, and wire-idle bits. */
+       for (i = 19; i > 0; i--) {
+               iowrite8(MDIO_EnbIn, mdio_addr);
+               mdio_delay();
+               retval = (retval << 1) | ((ioread8(mdio_addr) & MDIO_Data) ? 1 : 0);
+               iowrite8(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);
+               mdio_delay();
+       }
+       return (retval>>1) & 0xffff;
+}
+
+static void mdio_write(struct net_device *dev, int phy_id, int location, int value)
+{
+       struct netdev_private *np = netdev_priv(dev);
+       void __iomem *mdio_addr = np->base + MIICtrl;
+       int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;
+       int i;
+
+       if (np->mii_preamble_required)
+               mdio_sync(mdio_addr);
+
+       /* Shift the command bits out. */
+       for (i = 31; i >= 0; i--) {
+               int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
+
+               iowrite8(dataval, mdio_addr);
+               mdio_delay();
+               iowrite8(dataval | MDIO_ShiftClk, mdio_addr);
+               mdio_delay();
+       }
+       /* Clear out extra bits. */
+       for (i = 2; i > 0; i--) {
+               iowrite8(MDIO_EnbIn, mdio_addr);
+               mdio_delay();
+               iowrite8(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);
+               mdio_delay();
+       }
+}
+
+static int mdio_wait_link(struct net_device *dev, int wait)
+{
+       int bmsr;
+       int phy_id;
+       struct netdev_private *np;
+
+       np = netdev_priv(dev);
+       phy_id = np->phys[0];
+
+       do {
+               bmsr = mdio_read(dev, phy_id, MII_BMSR);
+               if (bmsr & 0x0004)
+                       return 0;
+               mdelay(1);
+       } while (--wait > 0);
+       return -1;
+}
+
+static int netdev_open(struct net_device *dev)
+{
+       struct netdev_private *np = netdev_priv(dev);
+       void __iomem *ioaddr = np->base;
+       unsigned long flags;
+       int i;
+
+       /* Do we need to reset the chip??? */
+
+       i = request_irq(dev->irq, intr_handler, IRQF_SHARED, dev->name, dev);
+       if (i)
+               return i;
+
+       if (netif_msg_ifup(np))
+               printk(KERN_DEBUG "%s: netdev_open() irq %d.\n",
+                          dev->name, dev->irq);
+       init_ring(dev);
+
+       iowrite32(np->rx_ring_dma, ioaddr + RxListPtr);
+       /* The Tx list pointer is written as packets are queued. */
+
+       /* Initialize other registers. */
+       __set_mac_addr(dev);
+#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
+       iowrite16(dev->mtu + 18, ioaddr + MaxFrameSize);
+#else
+       iowrite16(dev->mtu + 14, ioaddr + MaxFrameSize);
+#endif
+       if (dev->mtu > 2047)
+               iowrite32(ioread32(ioaddr + ASICCtrl) | 0x0C, ioaddr + ASICCtrl);
+
+       /* Configure the PCI bus bursts and FIFO thresholds. */
+
+       if (dev->if_port == 0)
+               dev->if_port = np->default_port;
+
+       spin_lock_init(&np->mcastlock);
+
+       set_rx_mode(dev);
+       iowrite16(0, ioaddr + IntrEnable);
+       iowrite16(0, ioaddr + DownCounter);
+       /* Set the chip to poll every N*320nsec. */
+       iowrite8(100, ioaddr + RxDMAPollPeriod);
+       iowrite8(127, ioaddr + TxDMAPollPeriod);
+       /* Fix DFE-580TX packet drop issue */
+       if (np->pci_dev->revision >= 0x14)
+               iowrite8(0x01, ioaddr + DebugCtrl1);
+       netif_start_queue(dev);
+
+       spin_lock_irqsave(&np->lock, flags);
+       reset_tx(dev);
+       spin_unlock_irqrestore(&np->lock, flags);
+
+       iowrite16 (StatsEnable | RxEnable | TxEnable, ioaddr + MACCtrl1);
+
+       if (netif_msg_ifup(np))
+               printk(KERN_DEBUG "%s: Done netdev_open(), status: Rx %x Tx %x "
+                          "MAC Control %x, %4.4x %4.4x.\n",
+                          dev->name, ioread32(ioaddr + RxStatus), ioread8(ioaddr + TxStatus),
+                          ioread32(ioaddr + MACCtrl0),
+                          ioread16(ioaddr + MACCtrl1), ioread16(ioaddr + MACCtrl0));
+
+       /* Set the timer to check for link beat. */
+       init_timer(&np->timer);
+       np->timer.expires = jiffies + 3*HZ;
+       np->timer.data = (unsigned long)dev;
+       np->timer.function = netdev_timer;                              /* timer handler */
+       add_timer(&np->timer);
+
+       /* Enable interrupts by setting the interrupt mask. */
+       iowrite16(DEFAULT_INTR, ioaddr + IntrEnable);
+
+       return 0;
+}
+
+static void check_duplex(struct net_device *dev)
+{
+       struct netdev_private *np = netdev_priv(dev);
+       void __iomem *ioaddr = np->base;
+       int mii_lpa = mdio_read(dev, np->phys[0], MII_LPA);
+       int negotiated = mii_lpa & np->mii_if.advertising;
+       int duplex;
+
+       /* Force media */
+       if (!np->an_enable || mii_lpa == 0xffff) {
+               if (np->mii_if.full_duplex)
+                       iowrite16 (ioread16 (ioaddr + MACCtrl0) | EnbFullDuplex,
+                               ioaddr + MACCtrl0);
+               return;
+       }
+
+       /* Autonegotiation */
+       duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;
+       if (np->mii_if.full_duplex != duplex) {
+               np->mii_if.full_duplex = duplex;
+               if (netif_msg_link(np))
+                       printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d "
+                                  "negotiated capability %4.4x.\n", dev->name,
+                                  duplex ? "full" : "half", np->phys[0], negotiated);
+               iowrite16(ioread16(ioaddr + MACCtrl0) | (duplex ? 0x20 : 0), ioaddr + MACCtrl0);
+       }
+}
+
+static void netdev_timer(unsigned long data)
+{
+       struct net_device *dev = (struct net_device *)data;
+       struct netdev_private *np = netdev_priv(dev);
+       void __iomem *ioaddr = np->base;
+       int next_tick = 10*HZ;
+
+       if (netif_msg_timer(np)) {
+               printk(KERN_DEBUG "%s: Media selection timer tick, intr status %4.4x, "
+                          "Tx %x Rx %x.\n",
+                          dev->name, ioread16(ioaddr + IntrEnable),
+                          ioread8(ioaddr + TxStatus), ioread32(ioaddr + RxStatus));
+       }
+       check_duplex(dev);
+       np->timer.expires = jiffies + next_tick;
+       add_timer(&np->timer);
+}
+
+static void tx_timeout(struct net_device *dev)
+{
+       struct netdev_private *np = netdev_priv(dev);
+       void __iomem *ioaddr = np->base;
+       unsigned long flag;
+
+       netif_stop_queue(dev);
+       tasklet_disable(&np->tx_tasklet);
+       iowrite16(0, ioaddr + IntrEnable);
+       printk(KERN_WARNING "%s: Transmit timed out, TxStatus %2.2x "
+                  "TxFrameId %2.2x,"
+                  " resetting...\n", dev->name, ioread8(ioaddr + TxStatus),
+                  ioread8(ioaddr + TxFrameId));
+
+       {
+               int i;
+               for (i=0; i<TX_RING_SIZE; i++) {
+                       printk(KERN_DEBUG "%02x %08llx %08x %08x(%02x) %08x %08x\n", i,
+                               (unsigned long long)(np->tx_ring_dma + i*sizeof(*np->tx_ring)),
+                               le32_to_cpu(np->tx_ring[i].next_desc),
+                               le32_to_cpu(np->tx_ring[i].status),
+                               (le32_to_cpu(np->tx_ring[i].status) >> 2) & 0xff,
+                               le32_to_cpu(np->tx_ring[i].frag[0].addr),
+                               le32_to_cpu(np->tx_ring[i].frag[0].length));
+               }
+               printk(KERN_DEBUG "TxListPtr=%08x netif_queue_stopped=%d\n",
+                       ioread32(np->base + TxListPtr),
+                       netif_queue_stopped(dev));
+               printk(KERN_DEBUG "cur_tx=%d(%02x) dirty_tx=%d(%02x)\n",
+                       np->cur_tx, np->cur_tx % TX_RING_SIZE,
+                       np->dirty_tx, np->dirty_tx % TX_RING_SIZE);
+               printk(KERN_DEBUG "cur_rx=%d dirty_rx=%d\n", np->cur_rx, np->dirty_rx);
+               printk(KERN_DEBUG "cur_task=%d\n", np->cur_task);
+       }
+       spin_lock_irqsave(&np->lock, flag);
+
+       /* Stop and restart the chip's Tx processes . */
+       reset_tx(dev);
+       spin_unlock_irqrestore(&np->lock, flag);
+
+       dev->if_port = 0;
+
+       dev->trans_start = jiffies; /* prevent tx timeout */
+       dev->stats.tx_errors++;
+       if (np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 4) {
+               netif_wake_queue(dev);
+       }
+       iowrite16(DEFAULT_INTR, ioaddr + IntrEnable);
+       tasklet_enable(&np->tx_tasklet);
+}
+
+
+/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
+static void init_ring(struct net_device *dev)
+{
+       struct netdev_private *np = netdev_priv(dev);
+       int i;
+
+       np->cur_rx = np->cur_tx = 0;
+       np->dirty_rx = np->dirty_tx = 0;
+       np->cur_task = 0;
+
+       np->rx_buf_sz = (dev->mtu <= 1520 ? PKT_BUF_SZ : dev->mtu + 16);
+
+       /* Initialize all Rx descriptors. */
+       for (i = 0; i < RX_RING_SIZE; i++) {
+               np->rx_ring[i].next_desc = cpu_to_le32(np->rx_ring_dma +
+                       ((i+1)%RX_RING_SIZE)*sizeof(*np->rx_ring));
+               np->rx_ring[i].status = 0;
+               np->rx_ring[i].frag[0].length = 0;
+               np->rx_skbuff[i] = NULL;
+       }
+
+       /* Fill in the Rx buffers.  Handle allocation failure gracefully. */
+       for (i = 0; i < RX_RING_SIZE; i++) {
+               struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz + 2);
+               np->rx_skbuff[i] = skb;
+               if (skb == NULL)
+                       break;
+               skb->dev = dev;         /* Mark as being used by this device. */
+               skb_reserve(skb, 2);    /* 16 byte align the IP header. */
+               np->rx_ring[i].frag[0].addr = cpu_to_le32(
+                       dma_map_single(&np->pci_dev->dev, skb->data,
+                               np->rx_buf_sz, DMA_FROM_DEVICE));
+               if (dma_mapping_error(&np->pci_dev->dev,
+                                       np->rx_ring[i].frag[0].addr)) {
+                       dev_kfree_skb(skb);
+                       np->rx_skbuff[i] = NULL;
+                       break;
+               }
+               np->rx_ring[i].frag[0].length = cpu_to_le32(np->rx_buf_sz | LastFrag);
+       }
+       np->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
+
+       for (i = 0; i < TX_RING_SIZE; i++) {
+               np->tx_skbuff[i] = NULL;
+               np->tx_ring[i].status = 0;
+       }
+}
+
+static void tx_poll (unsigned long data)
+{
+       struct net_device *dev = (struct net_device *)data;
+       struct netdev_private *np = netdev_priv(dev);
+       unsigned head = np->cur_task % TX_RING_SIZE;
+       struct netdev_desc *txdesc =
+               &np->tx_ring[(np->cur_tx - 1) % TX_RING_SIZE];
+
+       /* Chain the next pointer */
+       for (; np->cur_tx - np->cur_task > 0; np->cur_task++) {
+               int entry = np->cur_task % TX_RING_SIZE;
+               txdesc = &np->tx_ring[entry];
+               if (np->last_tx) {
+                       np->last_tx->next_desc = cpu_to_le32(np->tx_ring_dma +
+                               entry*sizeof(struct netdev_desc));
+               }
+               np->last_tx = txdesc;
+       }
+       /* Indicate the latest descriptor of tx ring */
+       txdesc->status |= cpu_to_le32(DescIntrOnTx);
+
+       if (ioread32 (np->base + TxListPtr) == 0)
+               iowrite32 (np->tx_ring_dma + head * sizeof(struct netdev_desc),
+                       np->base + TxListPtr);
+}
+
+static netdev_tx_t
+start_tx (struct sk_buff *skb, struct net_device *dev)
+{
+       struct netdev_private *np = netdev_priv(dev);
+       struct netdev_desc *txdesc;
+       unsigned entry;
+
+       /* Calculate the next Tx descriptor entry. */
+       entry = np->cur_tx % TX_RING_SIZE;
+       np->tx_skbuff[entry] = skb;
+       txdesc = &np->tx_ring[entry];
+
+       txdesc->next_desc = 0;
+       txdesc->status = cpu_to_le32 ((entry << 2) | DisableAlign);
+       txdesc->frag[0].addr = cpu_to_le32(dma_map_single(&np->pci_dev->dev,
+                               skb->data, skb->len, DMA_TO_DEVICE));
+       if (dma_mapping_error(&np->pci_dev->dev,
+                               txdesc->frag[0].addr))
+                       goto drop_frame;
+       txdesc->frag[0].length = cpu_to_le32 (skb->len | LastFrag);
+
+       /* Increment cur_tx before tasklet_schedule() */
+       np->cur_tx++;
+       mb();
+       /* Schedule a tx_poll() task */
+       tasklet_schedule(&np->tx_tasklet);
+
+       /* On some architectures: explicitly flush cache lines here. */
+       if (np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 1 &&
+           !netif_queue_stopped(dev)) {
+               /* do nothing */
+       } else {
+               netif_stop_queue (dev);
+       }
+       if (netif_msg_tx_queued(np)) {
+               printk (KERN_DEBUG
+                       "%s: Transmit frame #%d queued in slot %d.\n",
+                       dev->name, np->cur_tx, entry);
+       }
+       return NETDEV_TX_OK;
+
+drop_frame:
+       dev_kfree_skb(skb);
+       np->tx_skbuff[entry] = NULL;
+       dev->stats.tx_dropped++;
+       return NETDEV_TX_OK;
+}
+
+/* Reset hardware tx and free all of tx buffers */
+static int
+reset_tx (struct net_device *dev)
+{
+       struct netdev_private *np = netdev_priv(dev);
+       void __iomem *ioaddr = np->base;
+       struct sk_buff *skb;
+       int i;
+
+       /* Reset tx logic, TxListPtr will be cleaned */
+       iowrite16 (TxDisable, ioaddr + MACCtrl1);
+       sundance_reset(dev, (NetworkReset|FIFOReset|DMAReset|TxReset) << 16);
+
+       /* free all tx skbuff */
+       for (i = 0; i < TX_RING_SIZE; i++) {
+               np->tx_ring[i].next_desc = 0;
+
+               skb = np->tx_skbuff[i];
+               if (skb) {
+                       dma_unmap_single(&np->pci_dev->dev,
+                               le32_to_cpu(np->tx_ring[i].frag[0].addr),
+                               skb->len, DMA_TO_DEVICE);
+                       dev_kfree_skb_any(skb);
+                       np->tx_skbuff[i] = NULL;
+                       dev->stats.tx_dropped++;
+               }
+       }
+       np->cur_tx = np->dirty_tx = 0;
+       np->cur_task = 0;
+
+       np->last_tx = NULL;
+       iowrite8(127, ioaddr + TxDMAPollPeriod);
+
+       iowrite16 (StatsEnable | RxEnable | TxEnable, ioaddr + MACCtrl1);
+       return 0;
+}
+
+/* The interrupt handler cleans up after the Tx thread,
+   and schedule a Rx thread work */
+static irqreturn_t intr_handler(int irq, void *dev_instance)
+{
+       struct net_device *dev = (struct net_device *)dev_instance;
+       struct netdev_private *np = netdev_priv(dev);
+       void __iomem *ioaddr = np->base;
+       int hw_frame_id;
+       int tx_cnt;
+       int tx_status;
+       int handled = 0;
+       int i;
+
+
+       do {
+               int intr_status = ioread16(ioaddr + IntrStatus);
+               iowrite16(intr_status, ioaddr + IntrStatus);
+
+               if (netif_msg_intr(np))
+                       printk(KERN_DEBUG "%s: Interrupt, status %4.4x.\n",
+                                  dev->name, intr_status);
+
+               if (!(intr_status & DEFAULT_INTR))
+                       break;
+
+               handled = 1;
+
+               if (intr_status & (IntrRxDMADone)) {
+                       iowrite16(DEFAULT_INTR & ~(IntrRxDone|IntrRxDMADone),
+                                       ioaddr + IntrEnable);
+                       if (np->budget < 0)
+                               np->budget = RX_BUDGET;
+                       tasklet_schedule(&np->rx_tasklet);
+               }
+               if (intr_status & (IntrTxDone | IntrDrvRqst)) {
+                       tx_status = ioread16 (ioaddr + TxStatus);
+                       for (tx_cnt=32; tx_status & 0x80; --tx_cnt) {
+                               if (netif_msg_tx_done(np))
+                                       printk
+                                           ("%s: Transmit status is %2.2x.\n",
+                                       dev->name, tx_status);
+                               if (tx_status & 0x1e) {
+                                       if (netif_msg_tx_err(np))
+                                               printk("%s: Transmit error status %4.4x.\n",
+                                                          dev->name, tx_status);
+                                       dev->stats.tx_errors++;
+                                       if (tx_status & 0x10)
+                                               dev->stats.tx_fifo_errors++;
+                                       if (tx_status & 0x08)
+                                               dev->stats.collisions++;
+                                       if (tx_status & 0x04)
+                                               dev->stats.tx_fifo_errors++;
+                                       if (tx_status & 0x02)
+                                               dev->stats.tx_window_errors++;
+
+                                       /*
+                                       ** This reset has been verified on
+                                       ** DFE-580TX boards ! phdm@macqel.be.
+                                       */
+                                       if (tx_status & 0x10) { /* TxUnderrun */
+                                               /* Restart Tx FIFO and transmitter */
+                                               sundance_reset(dev, (NetworkReset|FIFOReset|TxReset) << 16);
+                                               /* No need to reset the Tx pointer here */
+                                       }
+                                       /* Restart the Tx. Need to make sure tx enabled */
+                                       i = 10;
+                                       do {
+                                               iowrite16(ioread16(ioaddr + MACCtrl1) | TxEnable, ioaddr + MACCtrl1);
+                                               if (ioread16(ioaddr + MACCtrl1) & TxEnabled)
+                                                       break;
+                                               mdelay(1);
+                                       } while (--i);
+                               }
+                               /* Yup, this is a documentation bug.  It cost me *hours*. */
+                               iowrite16 (0, ioaddr + TxStatus);
+                               if (tx_cnt < 0) {
+                                       iowrite32(5000, ioaddr + DownCounter);
+                                       break;
+                               }
+                               tx_status = ioread16 (ioaddr + TxStatus);
+                       }
+                       hw_frame_id = (tx_status >> 8) & 0xff;
+               } else  {
+                       hw_frame_id = ioread8(ioaddr + TxFrameId);
+               }
+
+               if (np->pci_dev->revision >= 0x14) {
+                       spin_lock(&np->lock);
+                       for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) {
+                               int entry = np->dirty_tx % TX_RING_SIZE;
+                               struct sk_buff *skb;
+                               int sw_frame_id;
+                               sw_frame_id = (le32_to_cpu(
+                                       np->tx_ring[entry].status) >> 2) & 0xff;
+                               if (sw_frame_id == hw_frame_id &&
+                                       !(le32_to_cpu(np->tx_ring[entry].status)
+                                       & 0x00010000))
+                                               break;
+                               if (sw_frame_id == (hw_frame_id + 1) %
+                                       TX_RING_SIZE)
+                                               break;
+                               skb = np->tx_skbuff[entry];
+                               /* Free the original skb. */
+                               dma_unmap_single(&np->pci_dev->dev,
+                                       le32_to_cpu(np->tx_ring[entry].frag[0].addr),
+                                       skb->len, DMA_TO_DEVICE);
+                               dev_kfree_skb_irq (np->tx_skbuff[entry]);
+                               np->tx_skbuff[entry] = NULL;
+                               np->tx_ring[entry].frag[0].addr = 0;
+                               np->tx_ring[entry].frag[0].length = 0;
+                       }
+                       spin_unlock(&np->lock);
+               } else {
+                       spin_lock(&np->lock);
+                       for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) {
+                               int entry = np->dirty_tx % TX_RING_SIZE;
+                               struct sk_buff *skb;
+                               if (!(le32_to_cpu(np->tx_ring[entry].status)
+                                                       & 0x00010000))
+                                       break;
+                               skb = np->tx_skbuff[entry];
+                               /* Free the original skb. */
+                               dma_unmap_single(&np->pci_dev->dev,
+                                       le32_to_cpu(np->tx_ring[entry].frag[0].addr),
+                                       skb->len, DMA_TO_DEVICE);
+                               dev_kfree_skb_irq (np->tx_skbuff[entry]);
+                               np->tx_skbuff[entry] = NULL;
+                               np->tx_ring[entry].frag[0].addr = 0;
+                               np->tx_ring[entry].frag[0].length = 0;
+                       }
+                       spin_unlock(&np->lock);
+               }
+
+               if (netif_queue_stopped(dev) &&
+                       np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 4) {
+                       /* The ring is no longer full, clear busy flag. */
+                       netif_wake_queue (dev);
+               }
+               /* Abnormal error summary/uncommon events handlers. */
+               if (intr_status & (IntrPCIErr | LinkChange | StatsMax))
+                       netdev_error(dev, intr_status);
+       } while (0);
+       if (netif_msg_intr(np))
+               printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
+                          dev->name, ioread16(ioaddr + IntrStatus));
+       return IRQ_RETVAL(handled);
+}
+
+static void rx_poll(unsigned long data)
+{
+       struct net_device *dev = (struct net_device *)data;
+       struct netdev_private *np = netdev_priv(dev);
+       int entry = np->cur_rx % RX_RING_SIZE;
+       int boguscnt = np->budget;
+       void __iomem *ioaddr = np->base;
+       int received = 0;
+
+       /* If EOP is set on the next entry, it's a new packet. Send it up. */
+       while (1) {
+               struct netdev_desc *desc = &(np->rx_ring[entry]);
+               u32 frame_status = le32_to_cpu(desc->status);
+               int pkt_len;
+
+               if (--boguscnt < 0) {
+                       goto not_done;
+               }
+               if (!(frame_status & DescOwn))
+                       break;
+               pkt_len = frame_status & 0x1fff;        /* Chip omits the CRC. */
+               if (netif_msg_rx_status(np))
+                       printk(KERN_DEBUG "  netdev_rx() status was %8.8x.\n",
+                                  frame_status);
+               if (frame_status & 0x001f4000) {
+                       /* There was a error. */
+                       if (netif_msg_rx_err(np))
+                               printk(KERN_DEBUG "  netdev_rx() Rx error was %8.8x.\n",
+                                          frame_status);
+                       dev->stats.rx_errors++;
+                       if (frame_status & 0x00100000)
+                               dev->stats.rx_length_errors++;
+                       if (frame_status & 0x00010000)
+                               dev->stats.rx_fifo_errors++;
+                       if (frame_status & 0x00060000)
+                               dev->stats.rx_frame_errors++;
+                       if (frame_status & 0x00080000)
+                               dev->stats.rx_crc_errors++;
+                       if (frame_status & 0x00100000) {
+                               printk(KERN_WARNING "%s: Oversized Ethernet frame,"
+                                          " status %8.8x.\n",
+                                          dev->name, frame_status);
+                       }
+               } else {
+                       struct sk_buff *skb;
+#ifndef final_version
+                       if (netif_msg_rx_status(np))
+                               printk(KERN_DEBUG "  netdev_rx() normal Rx pkt length %d"
+                                          ", bogus_cnt %d.\n",
+                                          pkt_len, boguscnt);
+#endif
+                       /* Check if the packet is long enough to accept without copying
+                          to a minimally-sized skbuff. */
+                       if (pkt_len < rx_copybreak &&
+                           (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
+                               skb_reserve(skb, 2);    /* 16 byte align the IP header */
+                               dma_sync_single_for_cpu(&np->pci_dev->dev,
+                                               le32_to_cpu(desc->frag[0].addr),
+                                               np->rx_buf_sz, DMA_FROM_DEVICE);
+                               skb_copy_to_linear_data(skb, np->rx_skbuff[entry]->data, pkt_len);
+                               dma_sync_single_for_device(&np->pci_dev->dev,
+                                               le32_to_cpu(desc->frag[0].addr),
+                                               np->rx_buf_sz, DMA_FROM_DEVICE);
+                               skb_put(skb, pkt_len);
+                       } else {
+                               dma_unmap_single(&np->pci_dev->dev,
+                                       le32_to_cpu(desc->frag[0].addr),
+                                       np->rx_buf_sz, DMA_FROM_DEVICE);
+                               skb_put(skb = np->rx_skbuff[entry], pkt_len);
+                               np->rx_skbuff[entry] = NULL;
+                       }
+                       skb->protocol = eth_type_trans(skb, dev);
+                       /* Note: checksum -> skb->ip_summed = CHECKSUM_UNNECESSARY; */
+                       netif_rx(skb);
+               }
+               entry = (entry + 1) % RX_RING_SIZE;
+               received++;
+       }
+       np->cur_rx = entry;
+       refill_rx (dev);
+       np->budget -= received;
+       iowrite16(DEFAULT_INTR, ioaddr + IntrEnable);
+       return;
+
+not_done:
+       np->cur_rx = entry;
+       refill_rx (dev);
+       if (!received)
+               received = 1;
+       np->budget -= received;
+       if (np->budget <= 0)
+               np->budget = RX_BUDGET;
+       tasklet_schedule(&np->rx_tasklet);
+}
+
+static void refill_rx (struct net_device *dev)
+{
+       struct netdev_private *np = netdev_priv(dev);
+       int entry;
+       int cnt = 0;
+
+       /* Refill the Rx ring buffers. */
+       for (;(np->cur_rx - np->dirty_rx + RX_RING_SIZE) % RX_RING_SIZE > 0;
+               np->dirty_rx = (np->dirty_rx + 1) % RX_RING_SIZE) {
+               struct sk_buff *skb;
+               entry = np->dirty_rx % RX_RING_SIZE;
+               if (np->rx_skbuff[entry] == NULL) {
+                       skb = dev_alloc_skb(np->rx_buf_sz + 2);
+                       np->rx_skbuff[entry] = skb;
+                       if (skb == NULL)
+                               break;          /* Better luck next round. */
+                       skb->dev = dev;         /* Mark as being used by this device. */
+                       skb_reserve(skb, 2);    /* Align IP on 16 byte boundaries */
+                       np->rx_ring[entry].frag[0].addr = cpu_to_le32(
+                               dma_map_single(&np->pci_dev->dev, skb->data,
+                                       np->rx_buf_sz, DMA_FROM_DEVICE));
+                       if (dma_mapping_error(&np->pci_dev->dev,
+                                   np->rx_ring[entry].frag[0].addr)) {
+                           dev_kfree_skb_irq(skb);
+                           np->rx_skbuff[entry] = NULL;
+                           break;
+                       }
+               }
+               /* Perhaps we need not reset this field. */
+               np->rx_ring[entry].frag[0].length =
+                       cpu_to_le32(np->rx_buf_sz | LastFrag);
+               np->rx_ring[entry].status = 0;
+               cnt++;
+       }
+}
+static void netdev_error(struct net_device *dev, int intr_status)
+{
+       struct netdev_private *np = netdev_priv(dev);
+       void __iomem *ioaddr = np->base;
+       u16 mii_ctl, mii_advertise, mii_lpa;
+       int speed;
+
+       if (intr_status & LinkChange) {
+               if (mdio_wait_link(dev, 10) == 0) {
+                       printk(KERN_INFO "%s: Link up\n", dev->name);
+                       if (np->an_enable) {
+                               mii_advertise = mdio_read(dev, np->phys[0],
+                                                          MII_ADVERTISE);
+                               mii_lpa = mdio_read(dev, np->phys[0], MII_LPA);
+                               mii_advertise &= mii_lpa;
+                               printk(KERN_INFO "%s: Link changed: ",
+                                       dev->name);
+                               if (mii_advertise & ADVERTISE_100FULL) {
+                                       np->speed = 100;
+                                       printk("100Mbps, full duplex\n");
+                               } else if (mii_advertise & ADVERTISE_100HALF) {
+                                       np->speed = 100;
+                                       printk("100Mbps, half duplex\n");
+                               } else if (mii_advertise & ADVERTISE_10FULL) {
+                                       np->speed = 10;
+                                       printk("10Mbps, full duplex\n");
+                               } else if (mii_advertise & ADVERTISE_10HALF) {
+                                       np->speed = 10;
+                                       printk("10Mbps, half duplex\n");
+                               } else
+                                       printk("\n");
+
+                       } else {
+                               mii_ctl = mdio_read(dev, np->phys[0], MII_BMCR);
+                               speed = (mii_ctl & BMCR_SPEED100) ? 100 : 10;
+                               np->speed = speed;
+                               printk(KERN_INFO "%s: Link changed: %dMbps ,",
+                                       dev->name, speed);
+                               printk("%s duplex.\n",
+                                       (mii_ctl & BMCR_FULLDPLX) ?
+                                               "full" : "half");
+                       }
+                       check_duplex(dev);
+                       if (np->flowctrl && np->mii_if.full_duplex) {
+                               iowrite16(ioread16(ioaddr + MulticastFilter1+2) | 0x0200,
+                                       ioaddr + MulticastFilter1+2);
+                               iowrite16(ioread16(ioaddr + MACCtrl0) | EnbFlowCtrl,
+                                       ioaddr + MACCtrl0);
+                       }
+                       netif_carrier_on(dev);
+               } else {
+                       printk(KERN_INFO "%s: Link down\n", dev->name);
+                       netif_carrier_off(dev);
+               }
+       }
+       if (intr_status & StatsMax) {
+               get_stats(dev);
+       }
+       if (intr_status & IntrPCIErr) {
+               printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n",
+                          dev->name, intr_status);
+               /* We must do a global reset of DMA to continue. */
+       }
+}
+
+static struct net_device_stats *get_stats(struct net_device *dev)
+{
+       struct netdev_private *np = netdev_priv(dev);
+       void __iomem *ioaddr = np->base;
+       unsigned long flags;
+       u8 late_coll, single_coll, mult_coll;
+
+       spin_lock_irqsave(&np->statlock, flags);
+       /* The chip only need report frame silently dropped. */
+       dev->stats.rx_missed_errors     += ioread8(ioaddr + RxMissed);
+       dev->stats.tx_packets += ioread16(ioaddr + TxFramesOK);
+       dev->stats.rx_packets += ioread16(ioaddr + RxFramesOK);
+       dev->stats.tx_carrier_errors += ioread8(ioaddr + StatsCarrierError);
+
+       mult_coll = ioread8(ioaddr + StatsMultiColl);
+       np->xstats.tx_multiple_collisions += mult_coll;
+       single_coll = ioread8(ioaddr + StatsOneColl);
+       np->xstats.tx_single_collisions += single_coll;
+       late_coll = ioread8(ioaddr + StatsLateColl);
+       np->xstats.tx_late_collisions += late_coll;
+       dev->stats.collisions += mult_coll
+               + single_coll
+               + late_coll;
+
+       np->xstats.tx_deferred += ioread8(ioaddr + StatsTxDefer);
+       np->xstats.tx_deferred_excessive += ioread8(ioaddr + StatsTxXSDefer);
+       np->xstats.tx_aborted += ioread8(ioaddr + StatsTxAbort);
+       np->xstats.tx_bcasts += ioread8(ioaddr + StatsBcastTx);
+       np->xstats.rx_bcasts += ioread8(ioaddr + StatsBcastRx);
+       np->xstats.tx_mcasts += ioread8(ioaddr + StatsMcastTx);
+       np->xstats.rx_mcasts += ioread8(ioaddr + StatsMcastRx);
+
+       dev->stats.tx_bytes += ioread16(ioaddr + TxOctetsLow);
+       dev->stats.tx_bytes += ioread16(ioaddr + TxOctetsHigh) << 16;
+       dev->stats.rx_bytes += ioread16(ioaddr + RxOctetsLow);
+       dev->stats.rx_bytes += ioread16(ioaddr + RxOctetsHigh) << 16;
+
+       spin_unlock_irqrestore(&np->statlock, flags);
+
+       return &dev->stats;
+}
+
+static void set_rx_mode(struct net_device *dev)
+{
+       struct netdev_private *np = netdev_priv(dev);
+       void __iomem *ioaddr = np->base;
+       u16 mc_filter[4];                       /* Multicast hash filter */
+       u32 rx_mode;
+       int i;
+
+       if (dev->flags & IFF_PROMISC) {                 /* Set promiscuous. */
+               memset(mc_filter, 0xff, sizeof(mc_filter));
+               rx_mode = AcceptBroadcast | AcceptMulticast | AcceptAll | AcceptMyPhys;
+       } else if ((netdev_mc_count(dev) > multicast_filter_limit) ||
+                  (dev->flags & IFF_ALLMULTI)) {
+               /* Too many to match, or accept all multicasts. */
+               memset(mc_filter, 0xff, sizeof(mc_filter));
+               rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
+       } else if (!netdev_mc_empty(dev)) {
+               struct netdev_hw_addr *ha;
+               int bit;
+               int index;
+               int crc;
+               memset (mc_filter, 0, sizeof (mc_filter));
+               netdev_for_each_mc_addr(ha, dev) {
+                       crc = ether_crc_le(ETH_ALEN, ha->addr);
+                       for (index=0, bit=0; bit < 6; bit++, crc <<= 1)
+                               if (crc & 0x80000000) index |= 1 << bit;
+                       mc_filter[index/16] |= (1 << (index % 16));
+               }
+               rx_mode = AcceptBroadcast | AcceptMultiHash | AcceptMyPhys;
+       } else {
+               iowrite8(AcceptBroadcast | AcceptMyPhys, ioaddr + RxMode);
+               return;
+       }
+       if (np->mii_if.full_duplex && np->flowctrl)
+               mc_filter[3] |= 0x0200;
+
+       for (i = 0; i < 4; i++)
+               iowrite16(mc_filter[i], ioaddr + MulticastFilter0 + i*2);
+       iowrite8(rx_mode, ioaddr + RxMode);
+}
+
+static int __set_mac_addr(struct net_device *dev)
+{
+       struct netdev_private *np = netdev_priv(dev);
+       u16 addr16;
+
+       addr16 = (dev->dev_addr[0] | (dev->dev_addr[1] << 8));
+       iowrite16(addr16, np->base + StationAddr);
+       addr16 = (dev->dev_addr[2] | (dev->dev_addr[3] << 8));
+       iowrite16(addr16, np->base + StationAddr+2);
+       addr16 = (dev->dev_addr[4] | (dev->dev_addr[5] << 8));
+       iowrite16(addr16, np->base + StationAddr+4);
+       return 0;
+}
+
+/* Invoked with rtnl_lock held */
+static int sundance_set_mac_addr(struct net_device *dev, void *data)
+{
+       const struct sockaddr *addr = data;
+
+       if (!is_valid_ether_addr(addr->sa_data))
+               return -EINVAL;
+       memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
+       __set_mac_addr(dev);
+
+       return 0;
+}
+
+static const struct {
+       const char name[ETH_GSTRING_LEN];
+} sundance_stats[] = {
+       { "tx_multiple_collisions" },
+       { "tx_single_collisions" },
+       { "tx_late_collisions" },
+       { "tx_deferred" },
+       { "tx_deferred_excessive" },
+       { "tx_aborted" },
+       { "tx_bcasts" },
+       { "rx_bcasts" },
+       { "tx_mcasts" },
+       { "rx_mcasts" },
+};
+
+static int check_if_running(struct net_device *dev)
+{
+       if (!netif_running(dev))
+               return -EINVAL;
+       return 0;
+}
+
+static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+       struct netdev_private *np = netdev_priv(dev);
+       strcpy(info->driver, DRV_NAME);
+       strcpy(info->version, DRV_VERSION);
+       strcpy(info->bus_info, pci_name(np->pci_dev));
+}
+
+static int get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+       struct netdev_private *np = netdev_priv(dev);
+       spin_lock_irq(&np->lock);
+       mii_ethtool_gset(&np->mii_if, ecmd);
+       spin_unlock_irq(&np->lock);
+       return 0;
+}
+
+static int set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+       struct netdev_private *np = netdev_priv(dev);
+       int res;
+       spin_lock_irq(&np->lock);
+       res = mii_ethtool_sset(&np->mii_if, ecmd);
+       spin_unlock_irq(&np->lock);
+       return res;
+}
+
+static int nway_reset(struct net_device *dev)
+{
+       struct netdev_private *np = netdev_priv(dev);
+       return mii_nway_restart(&np->mii_if);
+}
+
+static u32 get_link(struct net_device *dev)
+{
+       struct netdev_private *np = netdev_priv(dev);
+       return mii_link_ok(&np->mii_if);
+}
+
+static u32 get_msglevel(struct net_device *dev)
+{
+       struct netdev_private *np = netdev_priv(dev);
+       return np->msg_enable;
+}
+
+static void set_msglevel(struct net_device *dev, u32 val)
+{
+       struct netdev_private *np = netdev_priv(dev);
+       np->msg_enable = val;
+}
+
+static void get_strings(struct net_device *dev, u32 stringset,
+               u8 *data)
+{
+       if (stringset == ETH_SS_STATS)
+               memcpy(data, sundance_stats, sizeof(sundance_stats));
+}
+
+static int get_sset_count(struct net_device *dev, int sset)
+{
+       switch (sset) {
+       case ETH_SS_STATS:
+               return ARRAY_SIZE(sundance_stats);
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+static void get_ethtool_stats(struct net_device *dev,
+               struct ethtool_stats *stats, u64 *data)
+{
+       struct netdev_private *np = netdev_priv(dev);
+       int i = 0;
+
+       get_stats(dev);
+       data[i++] = np->xstats.tx_multiple_collisions;
+       data[i++] = np->xstats.tx_single_collisions;
+       data[i++] = np->xstats.tx_late_collisions;
+       data[i++] = np->xstats.tx_deferred;
+       data[i++] = np->xstats.tx_deferred_excessive;
+       data[i++] = np->xstats.tx_aborted;
+       data[i++] = np->xstats.tx_bcasts;
+       data[i++] = np->xstats.rx_bcasts;
+       data[i++] = np->xstats.tx_mcasts;
+       data[i++] = np->xstats.rx_mcasts;
+}
+
+static const struct ethtool_ops ethtool_ops = {
+       .begin = check_if_running,
+       .get_drvinfo = get_drvinfo,
+       .get_settings = get_settings,
+       .set_settings = set_settings,
+       .nway_reset = nway_reset,
+       .get_link = get_link,
+       .get_msglevel = get_msglevel,
+       .set_msglevel = set_msglevel,
+       .get_strings = get_strings,
+       .get_sset_count = get_sset_count,
+       .get_ethtool_stats = get_ethtool_stats,
+};
+
+static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+       struct netdev_private *np = netdev_priv(dev);
+       int rc;
+
+       if (!netif_running(dev))
+               return -EINVAL;
+
+       spin_lock_irq(&np->lock);
+       rc = generic_mii_ioctl(&np->mii_if, if_mii(rq), cmd, NULL);
+       spin_unlock_irq(&np->lock);
+
+       return rc;
+}
+
+static int netdev_close(struct net_device *dev)
+{
+       struct netdev_private *np = netdev_priv(dev);
+       void __iomem *ioaddr = np->base;
+       struct sk_buff *skb;
+       int i;
+
+       /* Wait and kill tasklet */
+       tasklet_kill(&np->rx_tasklet);
+       tasklet_kill(&np->tx_tasklet);
+       np->cur_tx = 0;
+       np->dirty_tx = 0;
+       np->cur_task = 0;
+       np->last_tx = NULL;
+
+       netif_stop_queue(dev);
+
+       if (netif_msg_ifdown(np)) {
+               printk(KERN_DEBUG "%s: Shutting down ethercard, status was Tx %2.2x "
+                          "Rx %4.4x Int %2.2x.\n",
+                          dev->name, ioread8(ioaddr + TxStatus),
+                          ioread32(ioaddr + RxStatus), ioread16(ioaddr + IntrStatus));
+               printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d,  Rx %d / %d.\n",
+                          dev->name, np->cur_tx, np->dirty_tx, np->cur_rx, np->dirty_rx);
+       }
+
+       /* Disable interrupts by clearing the interrupt mask. */
+       iowrite16(0x0000, ioaddr + IntrEnable);
+
+       /* Disable Rx and Tx DMA for safely release resource */
+       iowrite32(0x500, ioaddr + DMACtrl);
+
+       /* Stop the chip's Tx and Rx processes. */
+       iowrite16(TxDisable | RxDisable | StatsDisable, ioaddr + MACCtrl1);
+
+       for (i = 2000; i > 0; i--) {
+               if ((ioread32(ioaddr + DMACtrl) & 0xc000) == 0)
+                       break;
+               mdelay(1);
+       }
+
+       iowrite16(GlobalReset | DMAReset | FIFOReset | NetworkReset,
+                       ioaddr + ASIC_HI_WORD(ASICCtrl));
+
+       for (i = 2000; i > 0; i--) {
+               if ((ioread16(ioaddr + ASIC_HI_WORD(ASICCtrl)) & ResetBusy) == 0)
+                       break;
+               mdelay(1);
+       }
+
+#ifdef __i386__
+       if (netif_msg_hw(np)) {
+               printk(KERN_DEBUG "  Tx ring at %8.8x:\n",
+                          (int)(np->tx_ring_dma));
+               for (i = 0; i < TX_RING_SIZE; i++)
+                       printk(KERN_DEBUG " #%d desc. %4.4x %8.8x %8.8x.\n",
+                                  i, np->tx_ring[i].status, np->tx_ring[i].frag[0].addr,
+                                  np->tx_ring[i].frag[0].length);
+               printk(KERN_DEBUG "  Rx ring %8.8x:\n",
+                          (int)(np->rx_ring_dma));
+               for (i = 0; i < /*RX_RING_SIZE*/4 ; i++) {
+                       printk(KERN_DEBUG " #%d desc. %4.4x %4.4x %8.8x\n",
+                                  i, np->rx_ring[i].status, np->rx_ring[i].frag[0].addr,
+                                  np->rx_ring[i].frag[0].length);
+               }
+       }
+#endif /* __i386__ debugging only */
+
+       free_irq(dev->irq, dev);
+
+       del_timer_sync(&np->timer);
+
+       /* Free all the skbuffs in the Rx queue. */
+       for (i = 0; i < RX_RING_SIZE; i++) {
+               np->rx_ring[i].status = 0;
+               skb = np->rx_skbuff[i];
+               if (skb) {
+                       dma_unmap_single(&np->pci_dev->dev,
+                               le32_to_cpu(np->rx_ring[i].frag[0].addr),
+                               np->rx_buf_sz, DMA_FROM_DEVICE);
+                       dev_kfree_skb(skb);
+                       np->rx_skbuff[i] = NULL;
+               }
+               np->rx_ring[i].frag[0].addr = cpu_to_le32(0xBADF00D0); /* poison */
+       }
+       for (i = 0; i < TX_RING_SIZE; i++) {
+               np->tx_ring[i].next_desc = 0;
+               skb = np->tx_skbuff[i];
+               if (skb) {
+                       dma_unmap_single(&np->pci_dev->dev,
+                               le32_to_cpu(np->tx_ring[i].frag[0].addr),
+                               skb->len, DMA_TO_DEVICE);
+                       dev_kfree_skb(skb);
+                       np->tx_skbuff[i] = NULL;
+               }
+       }
+
+       return 0;
+}
+
+static void __devexit sundance_remove1 (struct pci_dev *pdev)
+{
+       struct net_device *dev = pci_get_drvdata(pdev);
+
+       if (dev) {
+           struct netdev_private *np = netdev_priv(dev);
+           unregister_netdev(dev);
+           dma_free_coherent(&pdev->dev, RX_TOTAL_SIZE,
+                   np->rx_ring, np->rx_ring_dma);
+           dma_free_coherent(&pdev->dev, TX_TOTAL_SIZE,
+                   np->tx_ring, np->tx_ring_dma);
+           pci_iounmap(pdev, np->base);
+           pci_release_regions(pdev);
+           free_netdev(dev);
+           pci_set_drvdata(pdev, NULL);
+       }
+}
+
+#ifdef CONFIG_PM
+
+static int sundance_suspend(struct pci_dev *pci_dev, pm_message_t state)
+{
+       struct net_device *dev = pci_get_drvdata(pci_dev);
+
+       if (!netif_running(dev))
+               return 0;
+
+       netdev_close(dev);
+       netif_device_detach(dev);
+
+       pci_save_state(pci_dev);
+       pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state));
+
+       return 0;
+}
+
+static int sundance_resume(struct pci_dev *pci_dev)
+{
+       struct net_device *dev = pci_get_drvdata(pci_dev);
+       int err = 0;
+
+       if (!netif_running(dev))
+               return 0;
+
+       pci_set_power_state(pci_dev, PCI_D0);
+       pci_restore_state(pci_dev);
+
+       err = netdev_open(dev);
+       if (err) {
+               printk(KERN_ERR "%s: Can't resume interface!\n",
+                               dev->name);
+               goto out;
+       }
+
+       netif_device_attach(dev);
+
+out:
+       return err;
+}
+
+#endif /* CONFIG_PM */
+
+static struct pci_driver sundance_driver = {
+       .name           = DRV_NAME,
+       .id_table       = sundance_pci_tbl,
+       .probe          = sundance_probe1,
+       .remove         = __devexit_p(sundance_remove1),
+#ifdef CONFIG_PM
+       .suspend        = sundance_suspend,
+       .resume         = sundance_resume,
+#endif /* CONFIG_PM */
+};
+
+static int __init sundance_init(void)
+{
+/* when a module, this is printed whether or not devices are found in probe */
+#ifdef MODULE
+       printk(version);
+#endif
+       return pci_register_driver(&sundance_driver);
+}
+
+static void __exit sundance_exit(void)
+{
+       pci_unregister_driver(&sundance_driver);
+}
+
+module_init(sundance_init);
+module_exit(sundance_exit);
+
+
diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c
deleted file mode 100644 (file)
index 4793df8..0000000
+++ /dev/null
@@ -1,1940 +0,0 @@
-/* sundance.c: A Linux device driver for the Sundance ST201 "Alta". */
-/*
-       Written 1999-2000 by Donald Becker.
-
-       This software may be used and distributed according to the terms of
-       the GNU General Public License (GPL), incorporated herein by reference.
-       Drivers based on or derived from this code fall under the GPL and must
-       retain the authorship, copyright and license notice.  This file is not
-       a complete program and may only be used when the entire operating
-       system is licensed under the GPL.
-
-       The author may be reached as becker@scyld.com, or C/O
-       Scyld Computing Corporation
-       410 Severn Ave., Suite 210
-       Annapolis MD 21403
-
-       Support and updates available at
-       http://www.scyld.com/network/sundance.html
-       [link no longer provides useful info -jgarzik]
-       Archives of the mailing list are still available at
-       http://www.beowulf.org/pipermail/netdrivers/
-
-*/
-
-#define DRV_NAME       "sundance"
-#define DRV_VERSION    "1.2"
-#define DRV_RELDATE    "11-Sep-2006"
-
-
-/* The user-configurable values.
-   These may be modified when a driver module is loaded.*/
-static int debug = 1;                  /* 1 normal messages, 0 quiet .. 7 verbose. */
-/* Maximum number of multicast addresses to filter (vs. rx-all-multicast).
-   Typical is a 64 element hash table based on the Ethernet CRC.  */
-static const int multicast_filter_limit = 32;
-
-/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
-   Setting to > 1518 effectively disables this feature.
-   This chip can receive into offset buffers, so the Alpha does not
-   need a copy-align. */
-static int rx_copybreak;
-static int flowctrl=1;
-
-/* media[] specifies the media type the NIC operates at.
-                autosense      Autosensing active media.
-                10mbps_hd      10Mbps half duplex.
-                10mbps_fd      10Mbps full duplex.
-                100mbps_hd     100Mbps half duplex.
-                100mbps_fd     100Mbps full duplex.
-                0              Autosensing active media.
-                1              10Mbps half duplex.
-                2              10Mbps full duplex.
-                3              100Mbps half duplex.
-                4              100Mbps full duplex.
-*/
-#define MAX_UNITS 8
-static char *media[MAX_UNITS];
-
-
-/* Operational parameters that are set at compile time. */
-
-/* Keep the ring sizes a power of two for compile efficiency.
-   The compiler will convert <unsigned>'%'<2^N> into a bit mask.
-   Making the Tx ring too large decreases the effectiveness of channel
-   bonding and packet priority, and more than 128 requires modifying the
-   Tx error recovery.
-   Large receive rings merely waste memory. */
-#define TX_RING_SIZE   32
-#define TX_QUEUE_LEN   (TX_RING_SIZE - 1) /* Limit ring entries actually used.  */
-#define RX_RING_SIZE   64
-#define RX_BUDGET      32
-#define TX_TOTAL_SIZE  TX_RING_SIZE*sizeof(struct netdev_desc)
-#define RX_TOTAL_SIZE  RX_RING_SIZE*sizeof(struct netdev_desc)
-
-/* Operational parameters that usually are not changed. */
-/* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT  (4*HZ)
-#define PKT_BUF_SZ             1536    /* Size of each temporary Rx buffer.*/
-
-/* Include files, designed to support most kernel versions 2.0.0 and later. */
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/init.h>
-#include <linux/bitops.h>
-#include <asm/uaccess.h>
-#include <asm/processor.h>             /* Processor type for cache alignment. */
-#include <asm/io.h>
-#include <linux/delay.h>
-#include <linux/spinlock.h>
-#include <linux/dma-mapping.h>
-#include <linux/crc32.h>
-#include <linux/ethtool.h>
-#include <linux/mii.h>
-
-/* These identify the driver base version and may not be removed. */
-static const char version[] __devinitconst =
-       KERN_INFO DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE
-       " Written by Donald Becker\n";
-
-MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
-MODULE_DESCRIPTION("Sundance Alta Ethernet driver");
-MODULE_LICENSE("GPL");
-
-module_param(debug, int, 0);
-module_param(rx_copybreak, int, 0);
-module_param_array(media, charp, NULL, 0);
-module_param(flowctrl, int, 0);
-MODULE_PARM_DESC(debug, "Sundance Alta debug level (0-5)");
-MODULE_PARM_DESC(rx_copybreak, "Sundance Alta copy breakpoint for copy-only-tiny-frames");
-MODULE_PARM_DESC(flowctrl, "Sundance Alta flow control [0|1]");
-
-/*
-                               Theory of Operation
-
-I. Board Compatibility
-
-This driver is designed for the Sundance Technologies "Alta" ST201 chip.
-
-II. Board-specific settings
-
-III. Driver operation
-
-IIIa. Ring buffers
-
-This driver uses two statically allocated fixed-size descriptor lists
-formed into rings by a branch from the final descriptor to the beginning of
-the list.  The ring sizes are set at compile time by RX/TX_RING_SIZE.
-Some chips explicitly use only 2^N sized rings, while others use a
-'next descriptor' pointer that the driver forms into rings.
-
-IIIb/c. Transmit/Receive Structure
-
-This driver uses a zero-copy receive and transmit scheme.
-The driver allocates full frame size skbuffs for the Rx ring buffers at
-open() time and passes the skb->data field to the chip as receive data
-buffers.  When an incoming frame is less than RX_COPYBREAK bytes long,
-a fresh skbuff is allocated and the frame is copied to the new skbuff.
-When the incoming frame is larger, the skbuff is passed directly up the
-protocol stack.  Buffers consumed this way are replaced by newly allocated
-skbuffs in a later phase of receives.
-
-The RX_COPYBREAK value is chosen to trade-off the memory wasted by
-using a full-sized skbuff for small frames vs. the copying costs of larger
-frames.  New boards are typically used in generously configured machines
-and the underfilled buffers have negligible impact compared to the benefit of
-a single allocation size, so the default value of zero results in never
-copying packets.  When copying is done, the cost is usually mitigated by using
-a combined copy/checksum routine.  Copying also preloads the cache, which is
-most useful with small frames.
-
-A subtle aspect of the operation is that the IP header at offset 14 in an
-ethernet frame isn't longword aligned for further processing.
-Unaligned buffers are permitted by the Sundance hardware, so
-frames are received into the skbuff at an offset of "+2", 16-byte aligning
-the IP header.
-
-IIId. Synchronization
-
-The driver runs as two independent, single-threaded flows of control.  One
-is the send-packet routine, which enforces single-threaded use by the
-dev->tbusy flag.  The other thread is the interrupt handler, which is single
-threaded by the hardware and interrupt handling software.
-
-The send packet thread has partial control over the Tx ring and 'dev->tbusy'
-flag.  It sets the tbusy flag whenever it's queuing a Tx packet. If the next
-queue slot is empty, it clears the tbusy flag when finished otherwise it sets
-the 'lp->tx_full' flag.
-
-The interrupt handler has exclusive control over the Rx ring and records stats
-from the Tx ring.  After reaping the stats, it marks the Tx queue entry as
-empty by incrementing the dirty_tx mark. Iff the 'lp->tx_full' flag is set, it
-clears both the tx_full and tbusy flags.
-
-IV. Notes
-
-IVb. References
-
-The Sundance ST201 datasheet, preliminary version.
-The Kendin KS8723 datasheet, preliminary version.
-The ICplus IP100 datasheet, preliminary version.
-http://www.scyld.com/expert/100mbps.html
-http://www.scyld.com/expert/NWay.html
-
-IVc. Errata
-
-*/
-
-/* Work-around for Kendin chip bugs. */
-#ifndef CONFIG_SUNDANCE_MMIO
-#define USE_IO_OPS 1
-#endif
-
-static DEFINE_PCI_DEVICE_TABLE(sundance_pci_tbl) = {
-       { 0x1186, 0x1002, 0x1186, 0x1002, 0, 0, 0 },
-       { 0x1186, 0x1002, 0x1186, 0x1003, 0, 0, 1 },
-       { 0x1186, 0x1002, 0x1186, 0x1012, 0, 0, 2 },
-       { 0x1186, 0x1002, 0x1186, 0x1040, 0, 0, 3 },
-       { 0x1186, 0x1002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
-       { 0x13F0, 0x0201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5 },
-       { 0x13F0, 0x0200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6 },
-       { }
-};
-MODULE_DEVICE_TABLE(pci, sundance_pci_tbl);
-
-enum {
-       netdev_io_size = 128
-};
-
-struct pci_id_info {
-        const char *name;
-};
-static const struct pci_id_info pci_id_tbl[] __devinitdata = {
-       {"D-Link DFE-550TX FAST Ethernet Adapter"},
-       {"D-Link DFE-550FX 100Mbps Fiber-optics Adapter"},
-       {"D-Link DFE-580TX 4 port Server Adapter"},
-       {"D-Link DFE-530TXS FAST Ethernet Adapter"},
-       {"D-Link DL10050-based FAST Ethernet Adapter"},
-       {"Sundance Technology Alta"},
-       {"IC Plus Corporation IP100A FAST Ethernet Adapter"},
-       { }     /* terminate list. */
-};
-
-/* This driver was written to use PCI memory space, however x86-oriented
-   hardware often uses I/O space accesses. */
-
-/* Offsets to the device registers.
-   Unlike software-only systems, device drivers interact with complex hardware.
-   It's not useful to define symbolic names for every register bit in the
-   device.  The name can only partially document the semantics and make
-   the driver longer and more difficult to read.
-   In general, only the important configuration values or bits changed
-   multiple times should be defined symbolically.
-*/
-enum alta_offsets {
-       DMACtrl = 0x00,
-       TxListPtr = 0x04,
-       TxDMABurstThresh = 0x08,
-       TxDMAUrgentThresh = 0x09,
-       TxDMAPollPeriod = 0x0a,
-       RxDMAStatus = 0x0c,
-       RxListPtr = 0x10,
-       DebugCtrl0 = 0x1a,
-       DebugCtrl1 = 0x1c,
-       RxDMABurstThresh = 0x14,
-       RxDMAUrgentThresh = 0x15,
-       RxDMAPollPeriod = 0x16,
-       LEDCtrl = 0x1a,
-       ASICCtrl = 0x30,
-       EEData = 0x34,
-       EECtrl = 0x36,
-       FlashAddr = 0x40,
-       FlashData = 0x44,
-       TxStatus = 0x46,
-       TxFrameId = 0x47,
-       DownCounter = 0x18,
-       IntrClear = 0x4a,
-       IntrEnable = 0x4c,
-       IntrStatus = 0x4e,
-       MACCtrl0 = 0x50,
-       MACCtrl1 = 0x52,
-       StationAddr = 0x54,
-       MaxFrameSize = 0x5A,
-       RxMode = 0x5c,
-       MIICtrl = 0x5e,
-       MulticastFilter0 = 0x60,
-       MulticastFilter1 = 0x64,
-       RxOctetsLow = 0x68,
-       RxOctetsHigh = 0x6a,
-       TxOctetsLow = 0x6c,
-       TxOctetsHigh = 0x6e,
-       TxFramesOK = 0x70,
-       RxFramesOK = 0x72,
-       StatsCarrierError = 0x74,
-       StatsLateColl = 0x75,
-       StatsMultiColl = 0x76,
-       StatsOneColl = 0x77,
-       StatsTxDefer = 0x78,
-       RxMissed = 0x79,
-       StatsTxXSDefer = 0x7a,
-       StatsTxAbort = 0x7b,
-       StatsBcastTx = 0x7c,
-       StatsBcastRx = 0x7d,
-       StatsMcastTx = 0x7e,
-       StatsMcastRx = 0x7f,
-       /* Aliased and bogus values! */
-       RxStatus = 0x0c,
-};
-
-#define ASIC_HI_WORD(x)        ((x) + 2)
-
-enum ASICCtrl_HiWord_bit {
-       GlobalReset = 0x0001,
-       RxReset = 0x0002,
-       TxReset = 0x0004,
-       DMAReset = 0x0008,
-       FIFOReset = 0x0010,
-       NetworkReset = 0x0020,
-       HostReset = 0x0040,
-       ResetBusy = 0x0400,
-};
-
-/* Bits in the interrupt status/mask registers. */
-enum intr_status_bits {
-       IntrSummary=0x0001, IntrPCIErr=0x0002, IntrMACCtrl=0x0008,
-       IntrTxDone=0x0004, IntrRxDone=0x0010, IntrRxStart=0x0020,
-       IntrDrvRqst=0x0040,
-       StatsMax=0x0080, LinkChange=0x0100,
-       IntrTxDMADone=0x0200, IntrRxDMADone=0x0400,
-};
-
-/* Bits in the RxMode register. */
-enum rx_mode_bits {
-       AcceptAllIPMulti=0x20, AcceptMultiHash=0x10, AcceptAll=0x08,
-       AcceptBroadcast=0x04, AcceptMulticast=0x02, AcceptMyPhys=0x01,
-};
-/* Bits in MACCtrl. */
-enum mac_ctrl0_bits {
-       EnbFullDuplex=0x20, EnbRcvLargeFrame=0x40,
-       EnbFlowCtrl=0x100, EnbPassRxCRC=0x200,
-};
-enum mac_ctrl1_bits {
-       StatsEnable=0x0020,     StatsDisable=0x0040, StatsEnabled=0x0080,
-       TxEnable=0x0100, TxDisable=0x0200, TxEnabled=0x0400,
-       RxEnable=0x0800, RxDisable=0x1000, RxEnabled=0x2000,
-};
-
-/* The Rx and Tx buffer descriptors. */
-/* Note that using only 32 bit fields simplifies conversion to big-endian
-   architectures. */
-struct netdev_desc {
-       __le32 next_desc;
-       __le32 status;
-       struct desc_frag { __le32 addr, length; } frag[1];
-};
-
-/* Bits in netdev_desc.status */
-enum desc_status_bits {
-       DescOwn=0x8000,
-       DescEndPacket=0x4000,
-       DescEndRing=0x2000,
-       LastFrag=0x80000000,
-       DescIntrOnTx=0x8000,
-       DescIntrOnDMADone=0x80000000,
-       DisableAlign = 0x00000001,
-};
-
-#define PRIV_ALIGN     15      /* Required alignment mask */
-/* Use  __attribute__((aligned (L1_CACHE_BYTES)))  to maintain alignment
-   within the structure. */
-#define MII_CNT                4
-struct netdev_private {
-       /* Descriptor rings first for alignment. */
-       struct netdev_desc *rx_ring;
-       struct netdev_desc *tx_ring;
-       struct sk_buff* rx_skbuff[RX_RING_SIZE];
-       struct sk_buff* tx_skbuff[TX_RING_SIZE];
-        dma_addr_t tx_ring_dma;
-        dma_addr_t rx_ring_dma;
-       struct timer_list timer;                /* Media monitoring timer. */
-       /* ethtool extra stats */
-       struct {
-               u64 tx_multiple_collisions;
-               u64 tx_single_collisions;
-               u64 tx_late_collisions;
-               u64 tx_deferred;
-               u64 tx_deferred_excessive;
-               u64 tx_aborted;
-               u64 tx_bcasts;
-               u64 rx_bcasts;
-               u64 tx_mcasts;
-               u64 rx_mcasts;
-       } xstats;
-       /* Frequently used values: keep some adjacent for cache effect. */
-       spinlock_t lock;
-       int msg_enable;
-       int chip_id;
-       unsigned int cur_rx, dirty_rx;          /* Producer/consumer ring indices */
-       unsigned int rx_buf_sz;                 /* Based on MTU+slack. */
-       struct netdev_desc *last_tx;            /* Last Tx descriptor used. */
-       unsigned int cur_tx, dirty_tx;
-       /* These values are keep track of the transceiver/media in use. */
-       unsigned int flowctrl:1;
-       unsigned int default_port:4;            /* Last dev->if_port value. */
-       unsigned int an_enable:1;
-       unsigned int speed;
-       struct tasklet_struct rx_tasklet;
-       struct tasklet_struct tx_tasklet;
-       int budget;
-       int cur_task;
-       /* Multicast and receive mode. */
-       spinlock_t mcastlock;                   /* SMP lock multicast updates. */
-       u16 mcast_filter[4];
-       /* MII transceiver section. */
-       struct mii_if_info mii_if;
-       int mii_preamble_required;
-       unsigned char phys[MII_CNT];            /* MII device addresses, only first one used. */
-       struct pci_dev *pci_dev;
-       void __iomem *base;
-       spinlock_t statlock;
-};
-
-/* The station address location in the EEPROM. */
-#define EEPROM_SA_OFFSET       0x10
-#define DEFAULT_INTR (IntrRxDMADone | IntrPCIErr | \
-                       IntrDrvRqst | IntrTxDone | StatsMax | \
-                       LinkChange)
-
-static int  change_mtu(struct net_device *dev, int new_mtu);
-static int  eeprom_read(void __iomem *ioaddr, int location);
-static int  mdio_read(struct net_device *dev, int phy_id, int location);
-static void mdio_write(struct net_device *dev, int phy_id, int location, int value);
-static int  mdio_wait_link(struct net_device *dev, int wait);
-static int  netdev_open(struct net_device *dev);
-static void check_duplex(struct net_device *dev);
-static void netdev_timer(unsigned long data);
-static void tx_timeout(struct net_device *dev);
-static void init_ring(struct net_device *dev);
-static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev);
-static int reset_tx (struct net_device *dev);
-static irqreturn_t intr_handler(int irq, void *dev_instance);
-static void rx_poll(unsigned long data);
-static void tx_poll(unsigned long data);
-static void refill_rx (struct net_device *dev);
-static void netdev_error(struct net_device *dev, int intr_status);
-static void netdev_error(struct net_device *dev, int intr_status);
-static void set_rx_mode(struct net_device *dev);
-static int __set_mac_addr(struct net_device *dev);
-static int sundance_set_mac_addr(struct net_device *dev, void *data);
-static struct net_device_stats *get_stats(struct net_device *dev);
-static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static int  netdev_close(struct net_device *dev);
-static const struct ethtool_ops ethtool_ops;
-
-static void sundance_reset(struct net_device *dev, unsigned long reset_cmd)
-{
-       struct netdev_private *np = netdev_priv(dev);
-       void __iomem *ioaddr = np->base + ASICCtrl;
-       int countdown;
-
-       /* ST201 documentation states ASICCtrl is a 32bit register */
-       iowrite32 (reset_cmd | ioread32 (ioaddr), ioaddr);
-       /* ST201 documentation states reset can take up to 1 ms */
-       countdown = 10 + 1;
-       while (ioread32 (ioaddr) & (ResetBusy << 16)) {
-               if (--countdown == 0) {
-                       printk(KERN_WARNING "%s : reset not completed !!\n", dev->name);
-                       break;
-               }
-               udelay(100);
-       }
-}
-
-static const struct net_device_ops netdev_ops = {
-       .ndo_open               = netdev_open,
-       .ndo_stop               = netdev_close,
-       .ndo_start_xmit         = start_tx,
-       .ndo_get_stats          = get_stats,
-       .ndo_set_multicast_list = set_rx_mode,
-       .ndo_do_ioctl           = netdev_ioctl,
-       .ndo_tx_timeout         = tx_timeout,
-       .ndo_change_mtu         = change_mtu,
-       .ndo_set_mac_address    = sundance_set_mac_addr,
-       .ndo_validate_addr      = eth_validate_addr,
-};
-
-static int __devinit sundance_probe1 (struct pci_dev *pdev,
-                                     const struct pci_device_id *ent)
-{
-       struct net_device *dev;
-       struct netdev_private *np;
-       static int card_idx;
-       int chip_idx = ent->driver_data;
-       int irq;
-       int i;
-       void __iomem *ioaddr;
-       u16 mii_ctl;
-       void *ring_space;
-       dma_addr_t ring_dma;
-#ifdef USE_IO_OPS
-       int bar = 0;
-#else
-       int bar = 1;
-#endif
-       int phy, phy_end, phy_idx = 0;
-
-/* when built into the kernel, we only print version if device is found */
-#ifndef MODULE
-       static int printed_version;
-       if (!printed_version++)
-               printk(version);
-#endif
-
-       if (pci_enable_device(pdev))
-               return -EIO;
-       pci_set_master(pdev);
-
-       irq = pdev->irq;
-
-       dev = alloc_etherdev(sizeof(*np));
-       if (!dev)
-               return -ENOMEM;
-       SET_NETDEV_DEV(dev, &pdev->dev);
-
-       if (pci_request_regions(pdev, DRV_NAME))
-               goto err_out_netdev;
-
-       ioaddr = pci_iomap(pdev, bar, netdev_io_size);
-       if (!ioaddr)
-               goto err_out_res;
-
-       for (i = 0; i < 3; i++)
-               ((__le16 *)dev->dev_addr)[i] =
-                       cpu_to_le16(eeprom_read(ioaddr, i + EEPROM_SA_OFFSET));
-       memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
-
-       dev->base_addr = (unsigned long)ioaddr;
-       dev->irq = irq;
-
-       np = netdev_priv(dev);
-       np->base = ioaddr;
-       np->pci_dev = pdev;
-       np->chip_id = chip_idx;
-       np->msg_enable = (1 << debug) - 1;
-       spin_lock_init(&np->lock);
-       spin_lock_init(&np->statlock);
-       tasklet_init(&np->rx_tasklet, rx_poll, (unsigned long)dev);
-       tasklet_init(&np->tx_tasklet, tx_poll, (unsigned long)dev);
-
-       ring_space = dma_alloc_coherent(&pdev->dev, TX_TOTAL_SIZE,
-                       &ring_dma, GFP_KERNEL);
-       if (!ring_space)
-               goto err_out_cleardev;
-       np->tx_ring = (struct netdev_desc *)ring_space;
-       np->tx_ring_dma = ring_dma;
-
-       ring_space = dma_alloc_coherent(&pdev->dev, RX_TOTAL_SIZE,
-                       &ring_dma, GFP_KERNEL);
-       if (!ring_space)
-               goto err_out_unmap_tx;
-       np->rx_ring = (struct netdev_desc *)ring_space;
-       np->rx_ring_dma = ring_dma;
-
-       np->mii_if.dev = dev;
-       np->mii_if.mdio_read = mdio_read;
-       np->mii_if.mdio_write = mdio_write;
-       np->mii_if.phy_id_mask = 0x1f;
-       np->mii_if.reg_num_mask = 0x1f;
-
-       /* The chip-specific entries in the device structure. */
-       dev->netdev_ops = &netdev_ops;
-       SET_ETHTOOL_OPS(dev, &ethtool_ops);
-       dev->watchdog_timeo = TX_TIMEOUT;
-
-       pci_set_drvdata(pdev, dev);
-
-       i = register_netdev(dev);
-       if (i)
-               goto err_out_unmap_rx;
-
-       printk(KERN_INFO "%s: %s at %p, %pM, IRQ %d.\n",
-              dev->name, pci_id_tbl[chip_idx].name, ioaddr,
-              dev->dev_addr, irq);
-
-       np->phys[0] = 1;                /* Default setting */
-       np->mii_preamble_required++;
-
-       /*
-        * It seems some phys doesn't deal well with address 0 being accessed
-        * first
-        */
-       if (sundance_pci_tbl[np->chip_id].device == 0x0200) {
-               phy = 0;
-               phy_end = 31;
-       } else {
-               phy = 1;
-               phy_end = 32;   /* wraps to zero, due to 'phy & 0x1f' */
-       }
-       for (; phy <= phy_end && phy_idx < MII_CNT; phy++) {
-               int phyx = phy & 0x1f;
-               int mii_status = mdio_read(dev, phyx, MII_BMSR);
-               if (mii_status != 0xffff  &&  mii_status != 0x0000) {
-                       np->phys[phy_idx++] = phyx;
-                       np->mii_if.advertising = mdio_read(dev, phyx, MII_ADVERTISE);
-                       if ((mii_status & 0x0040) == 0)
-                               np->mii_preamble_required++;
-                       printk(KERN_INFO "%s: MII PHY found at address %d, status "
-                                  "0x%4.4x advertising %4.4x.\n",
-                                  dev->name, phyx, mii_status, np->mii_if.advertising);
-               }
-       }
-       np->mii_preamble_required--;
-
-       if (phy_idx == 0) {
-               printk(KERN_INFO "%s: No MII transceiver found, aborting.  ASIC status %x\n",
-                          dev->name, ioread32(ioaddr + ASICCtrl));
-               goto err_out_unregister;
-       }
-
-       np->mii_if.phy_id = np->phys[0];
-
-       /* Parse override configuration */
-       np->an_enable = 1;
-       if (card_idx < MAX_UNITS) {
-               if (media[card_idx] != NULL) {
-                       np->an_enable = 0;
-                       if (strcmp (media[card_idx], "100mbps_fd") == 0 ||
-                           strcmp (media[card_idx], "4") == 0) {
-                               np->speed = 100;
-                               np->mii_if.full_duplex = 1;
-                       } else if (strcmp (media[card_idx], "100mbps_hd") == 0 ||
-                                  strcmp (media[card_idx], "3") == 0) {
-                               np->speed = 100;
-                               np->mii_if.full_duplex = 0;
-                       } else if (strcmp (media[card_idx], "10mbps_fd") == 0 ||
-                                  strcmp (media[card_idx], "2") == 0) {
-                               np->speed = 10;
-                               np->mii_if.full_duplex = 1;
-                       } else if (strcmp (media[card_idx], "10mbps_hd") == 0 ||
-                                  strcmp (media[card_idx], "1") == 0) {
-                               np->speed = 10;
-                               np->mii_if.full_duplex = 0;
-                       } else {
-                               np->an_enable = 1;
-                       }
-               }
-               if (flowctrl == 1)
-                       np->flowctrl = 1;
-       }
-
-       /* Fibre PHY? */
-       if (ioread32 (ioaddr + ASICCtrl) & 0x80) {
-               /* Default 100Mbps Full */
-               if (np->an_enable) {
-                       np->speed = 100;
-                       np->mii_if.full_duplex = 1;
-                       np->an_enable = 0;
-               }
-       }
-       /* Reset PHY */
-       mdio_write (dev, np->phys[0], MII_BMCR, BMCR_RESET);
-       mdelay (300);
-       /* If flow control enabled, we need to advertise it.*/
-       if (np->flowctrl)
-               mdio_write (dev, np->phys[0], MII_ADVERTISE, np->mii_if.advertising | 0x0400);
-       mdio_write (dev, np->phys[0], MII_BMCR, BMCR_ANENABLE|BMCR_ANRESTART);
-       /* Force media type */
-       if (!np->an_enable) {
-               mii_ctl = 0;
-               mii_ctl |= (np->speed == 100) ? BMCR_SPEED100 : 0;
-               mii_ctl |= (np->mii_if.full_duplex) ? BMCR_FULLDPLX : 0;
-               mdio_write (dev, np->phys[0], MII_BMCR, mii_ctl);
-               printk (KERN_INFO "Override speed=%d, %s duplex\n",
-                       np->speed, np->mii_if.full_duplex ? "Full" : "Half");
-
-       }
-
-       /* Perhaps move the reset here? */
-       /* Reset the chip to erase previous misconfiguration. */
-       if (netif_msg_hw(np))
-               printk("ASIC Control is %x.\n", ioread32(ioaddr + ASICCtrl));
-       sundance_reset(dev, 0x00ff << 16);
-       if (netif_msg_hw(np))
-               printk("ASIC Control is now %x.\n", ioread32(ioaddr + ASICCtrl));
-
-       card_idx++;
-       return 0;
-
-err_out_unregister:
-       unregister_netdev(dev);
-err_out_unmap_rx:
-       dma_free_coherent(&pdev->dev, RX_TOTAL_SIZE,
-               np->rx_ring, np->rx_ring_dma);
-err_out_unmap_tx:
-       dma_free_coherent(&pdev->dev, TX_TOTAL_SIZE,
-               np->tx_ring, np->tx_ring_dma);
-err_out_cleardev:
-       pci_set_drvdata(pdev, NULL);
-       pci_iounmap(pdev, ioaddr);
-err_out_res:
-       pci_release_regions(pdev);
-err_out_netdev:
-       free_netdev (dev);
-       return -ENODEV;
-}
-
-static int change_mtu(struct net_device *dev, int new_mtu)
-{
-       if ((new_mtu < 68) || (new_mtu > 8191)) /* Set by RxDMAFrameLen */
-               return -EINVAL;
-       if (netif_running(dev))
-               return -EBUSY;
-       dev->mtu = new_mtu;
-       return 0;
-}
-
-#define eeprom_delay(ee_addr)  ioread32(ee_addr)
-/* Read the EEPROM and MII Management Data I/O (MDIO) interfaces. */
-static int __devinit eeprom_read(void __iomem *ioaddr, int location)
-{
-       int boguscnt = 10000;           /* Typical 1900 ticks. */
-       iowrite16(0x0200 | (location & 0xff), ioaddr + EECtrl);
-       do {
-               eeprom_delay(ioaddr + EECtrl);
-               if (! (ioread16(ioaddr + EECtrl) & 0x8000)) {
-                       return ioread16(ioaddr + EEData);
-               }
-       } while (--boguscnt > 0);
-       return 0;
-}
-
-/*  MII transceiver control section.
-       Read and write the MII registers using software-generated serial
-       MDIO protocol.  See the MII specifications or DP83840A data sheet
-       for details.
-
-       The maximum data clock rate is 2.5 Mhz.  The minimum timing is usually
-       met by back-to-back 33Mhz PCI cycles. */
-#define mdio_delay() ioread8(mdio_addr)
-
-enum mii_reg_bits {
-       MDIO_ShiftClk=0x0001, MDIO_Data=0x0002, MDIO_EnbOutput=0x0004,
-};
-#define MDIO_EnbIn  (0)
-#define MDIO_WRITE0 (MDIO_EnbOutput)
-#define MDIO_WRITE1 (MDIO_Data | MDIO_EnbOutput)
-
-/* Generate the preamble required for initial synchronization and
-   a few older transceivers. */
-static void mdio_sync(void __iomem *mdio_addr)
-{
-       int bits = 32;
-
-       /* Establish sync by sending at least 32 logic ones. */
-       while (--bits >= 0) {
-               iowrite8(MDIO_WRITE1, mdio_addr);
-               mdio_delay();
-               iowrite8(MDIO_WRITE1 | MDIO_ShiftClk, mdio_addr);
-               mdio_delay();
-       }
-}
-
-static int mdio_read(struct net_device *dev, int phy_id, int location)
-{
-       struct netdev_private *np = netdev_priv(dev);
-       void __iomem *mdio_addr = np->base + MIICtrl;
-       int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;
-       int i, retval = 0;
-
-       if (np->mii_preamble_required)
-               mdio_sync(mdio_addr);
-
-       /* Shift the read command bits out. */
-       for (i = 15; i >= 0; i--) {
-               int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
-
-               iowrite8(dataval, mdio_addr);
-               mdio_delay();
-               iowrite8(dataval | MDIO_ShiftClk, mdio_addr);
-               mdio_delay();
-       }
-       /* Read the two transition, 16 data, and wire-idle bits. */
-       for (i = 19; i > 0; i--) {
-               iowrite8(MDIO_EnbIn, mdio_addr);
-               mdio_delay();
-               retval = (retval << 1) | ((ioread8(mdio_addr) & MDIO_Data) ? 1 : 0);
-               iowrite8(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);
-               mdio_delay();
-       }
-       return (retval>>1) & 0xffff;
-}
-
-static void mdio_write(struct net_device *dev, int phy_id, int location, int value)
-{
-       struct netdev_private *np = netdev_priv(dev);
-       void __iomem *mdio_addr = np->base + MIICtrl;
-       int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;
-       int i;
-
-       if (np->mii_preamble_required)
-               mdio_sync(mdio_addr);
-
-       /* Shift the command bits out. */
-       for (i = 31; i >= 0; i--) {
-               int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
-
-               iowrite8(dataval, mdio_addr);
-               mdio_delay();
-               iowrite8(dataval | MDIO_ShiftClk, mdio_addr);
-               mdio_delay();
-       }
-       /* Clear out extra bits. */
-       for (i = 2; i > 0; i--) {
-               iowrite8(MDIO_EnbIn, mdio_addr);
-               mdio_delay();
-               iowrite8(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);
-               mdio_delay();
-       }
-}
-
-static int mdio_wait_link(struct net_device *dev, int wait)
-{
-       int bmsr;
-       int phy_id;
-       struct netdev_private *np;
-
-       np = netdev_priv(dev);
-       phy_id = np->phys[0];
-
-       do {
-               bmsr = mdio_read(dev, phy_id, MII_BMSR);
-               if (bmsr & 0x0004)
-                       return 0;
-               mdelay(1);
-       } while (--wait > 0);
-       return -1;
-}
-
-static int netdev_open(struct net_device *dev)
-{
-       struct netdev_private *np = netdev_priv(dev);
-       void __iomem *ioaddr = np->base;
-       unsigned long flags;
-       int i;
-
-       /* Do we need to reset the chip??? */
-
-       i = request_irq(dev->irq, intr_handler, IRQF_SHARED, dev->name, dev);
-       if (i)
-               return i;
-
-       if (netif_msg_ifup(np))
-               printk(KERN_DEBUG "%s: netdev_open() irq %d.\n",
-                          dev->name, dev->irq);
-       init_ring(dev);
-
-       iowrite32(np->rx_ring_dma, ioaddr + RxListPtr);
-       /* The Tx list pointer is written as packets are queued. */
-
-       /* Initialize other registers. */
-       __set_mac_addr(dev);
-#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
-       iowrite16(dev->mtu + 18, ioaddr + MaxFrameSize);
-#else
-       iowrite16(dev->mtu + 14, ioaddr + MaxFrameSize);
-#endif
-       if (dev->mtu > 2047)
-               iowrite32(ioread32(ioaddr + ASICCtrl) | 0x0C, ioaddr + ASICCtrl);
-
-       /* Configure the PCI bus bursts and FIFO thresholds. */
-
-       if (dev->if_port == 0)
-               dev->if_port = np->default_port;
-
-       spin_lock_init(&np->mcastlock);
-
-       set_rx_mode(dev);
-       iowrite16(0, ioaddr + IntrEnable);
-       iowrite16(0, ioaddr + DownCounter);
-       /* Set the chip to poll every N*320nsec. */
-       iowrite8(100, ioaddr + RxDMAPollPeriod);
-       iowrite8(127, ioaddr + TxDMAPollPeriod);
-       /* Fix DFE-580TX packet drop issue */
-       if (np->pci_dev->revision >= 0x14)
-               iowrite8(0x01, ioaddr + DebugCtrl1);
-       netif_start_queue(dev);
-
-       spin_lock_irqsave(&np->lock, flags);
-       reset_tx(dev);
-       spin_unlock_irqrestore(&np->lock, flags);
-
-       iowrite16 (StatsEnable | RxEnable | TxEnable, ioaddr + MACCtrl1);
-
-       if (netif_msg_ifup(np))
-               printk(KERN_DEBUG "%s: Done netdev_open(), status: Rx %x Tx %x "
-                          "MAC Control %x, %4.4x %4.4x.\n",
-                          dev->name, ioread32(ioaddr + RxStatus), ioread8(ioaddr + TxStatus),
-                          ioread32(ioaddr + MACCtrl0),
-                          ioread16(ioaddr + MACCtrl1), ioread16(ioaddr + MACCtrl0));
-
-       /* Set the timer to check for link beat. */
-       init_timer(&np->timer);
-       np->timer.expires = jiffies + 3*HZ;
-       np->timer.data = (unsigned long)dev;
-       np->timer.function = netdev_timer;                              /* timer handler */
-       add_timer(&np->timer);
-
-       /* Enable interrupts by setting the interrupt mask. */
-       iowrite16(DEFAULT_INTR, ioaddr + IntrEnable);
-
-       return 0;
-}
-
-static void check_duplex(struct net_device *dev)
-{
-       struct netdev_private *np = netdev_priv(dev);
-       void __iomem *ioaddr = np->base;
-       int mii_lpa = mdio_read(dev, np->phys[0], MII_LPA);
-       int negotiated = mii_lpa & np->mii_if.advertising;
-       int duplex;
-
-       /* Force media */
-       if (!np->an_enable || mii_lpa == 0xffff) {
-               if (np->mii_if.full_duplex)
-                       iowrite16 (ioread16 (ioaddr + MACCtrl0) | EnbFullDuplex,
-                               ioaddr + MACCtrl0);
-               return;
-       }
-
-       /* Autonegotiation */
-       duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;
-       if (np->mii_if.full_duplex != duplex) {
-               np->mii_if.full_duplex = duplex;
-               if (netif_msg_link(np))
-                       printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d "
-                                  "negotiated capability %4.4x.\n", dev->name,
-                                  duplex ? "full" : "half", np->phys[0], negotiated);
-               iowrite16(ioread16(ioaddr + MACCtrl0) | (duplex ? 0x20 : 0), ioaddr + MACCtrl0);
-       }
-}
-
-static void netdev_timer(unsigned long data)
-{
-       struct net_device *dev = (struct net_device *)data;
-       struct netdev_private *np = netdev_priv(dev);
-       void __iomem *ioaddr = np->base;
-       int next_tick = 10*HZ;
-
-       if (netif_msg_timer(np)) {
-               printk(KERN_DEBUG "%s: Media selection timer tick, intr status %4.4x, "
-                          "Tx %x Rx %x.\n",
-                          dev->name, ioread16(ioaddr + IntrEnable),
-                          ioread8(ioaddr + TxStatus), ioread32(ioaddr + RxStatus));
-       }
-       check_duplex(dev);
-       np->timer.expires = jiffies + next_tick;
-       add_timer(&np->timer);
-}
-
-static void tx_timeout(struct net_device *dev)
-{
-       struct netdev_private *np = netdev_priv(dev);
-       void __iomem *ioaddr = np->base;
-       unsigned long flag;
-
-       netif_stop_queue(dev);
-       tasklet_disable(&np->tx_tasklet);
-       iowrite16(0, ioaddr + IntrEnable);
-       printk(KERN_WARNING "%s: Transmit timed out, TxStatus %2.2x "
-                  "TxFrameId %2.2x,"
-                  " resetting...\n", dev->name, ioread8(ioaddr + TxStatus),
-                  ioread8(ioaddr + TxFrameId));
-
-       {
-               int i;
-               for (i=0; i<TX_RING_SIZE; i++) {
-                       printk(KERN_DEBUG "%02x %08llx %08x %08x(%02x) %08x %08x\n", i,
-                               (unsigned long long)(np->tx_ring_dma + i*sizeof(*np->tx_ring)),
-                               le32_to_cpu(np->tx_ring[i].next_desc),
-                               le32_to_cpu(np->tx_ring[i].status),
-                               (le32_to_cpu(np->tx_ring[i].status) >> 2) & 0xff,
-                               le32_to_cpu(np->tx_ring[i].frag[0].addr),
-                               le32_to_cpu(np->tx_ring[i].frag[0].length));
-               }
-               printk(KERN_DEBUG "TxListPtr=%08x netif_queue_stopped=%d\n",
-                       ioread32(np->base + TxListPtr),
-                       netif_queue_stopped(dev));
-               printk(KERN_DEBUG "cur_tx=%d(%02x) dirty_tx=%d(%02x)\n",
-                       np->cur_tx, np->cur_tx % TX_RING_SIZE,
-                       np->dirty_tx, np->dirty_tx % TX_RING_SIZE);
-               printk(KERN_DEBUG "cur_rx=%d dirty_rx=%d\n", np->cur_rx, np->dirty_rx);
-               printk(KERN_DEBUG "cur_task=%d\n", np->cur_task);
-       }
-       spin_lock_irqsave(&np->lock, flag);
-
-       /* Stop and restart the chip's Tx processes . */
-       reset_tx(dev);
-       spin_unlock_irqrestore(&np->lock, flag);
-
-       dev->if_port = 0;
-
-       dev->trans_start = jiffies; /* prevent tx timeout */
-       dev->stats.tx_errors++;
-       if (np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 4) {
-               netif_wake_queue(dev);
-       }
-       iowrite16(DEFAULT_INTR, ioaddr + IntrEnable);
-       tasklet_enable(&np->tx_tasklet);
-}
-
-
-/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
-static void init_ring(struct net_device *dev)
-{
-       struct netdev_private *np = netdev_priv(dev);
-       int i;
-
-       np->cur_rx = np->cur_tx = 0;
-       np->dirty_rx = np->dirty_tx = 0;
-       np->cur_task = 0;
-
-       np->rx_buf_sz = (dev->mtu <= 1520 ? PKT_BUF_SZ : dev->mtu + 16);
-
-       /* Initialize all Rx descriptors. */
-       for (i = 0; i < RX_RING_SIZE; i++) {
-               np->rx_ring[i].next_desc = cpu_to_le32(np->rx_ring_dma +
-                       ((i+1)%RX_RING_SIZE)*sizeof(*np->rx_ring));
-               np->rx_ring[i].status = 0;
-               np->rx_ring[i].frag[0].length = 0;
-               np->rx_skbuff[i] = NULL;
-       }
-
-       /* Fill in the Rx buffers.  Handle allocation failure gracefully. */
-       for (i = 0; i < RX_RING_SIZE; i++) {
-               struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz + 2);
-               np->rx_skbuff[i] = skb;
-               if (skb == NULL)
-                       break;
-               skb->dev = dev;         /* Mark as being used by this device. */
-               skb_reserve(skb, 2);    /* 16 byte align the IP header. */
-               np->rx_ring[i].frag[0].addr = cpu_to_le32(
-                       dma_map_single(&np->pci_dev->dev, skb->data,
-                               np->rx_buf_sz, DMA_FROM_DEVICE));
-               if (dma_mapping_error(&np->pci_dev->dev,
-                                       np->rx_ring[i].frag[0].addr)) {
-                       dev_kfree_skb(skb);
-                       np->rx_skbuff[i] = NULL;
-                       break;
-               }
-               np->rx_ring[i].frag[0].length = cpu_to_le32(np->rx_buf_sz | LastFrag);
-       }
-       np->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
-
-       for (i = 0; i < TX_RING_SIZE; i++) {
-               np->tx_skbuff[i] = NULL;
-               np->tx_ring[i].status = 0;
-       }
-}
-
-static void tx_poll (unsigned long data)
-{
-       struct net_device *dev = (struct net_device *)data;
-       struct netdev_private *np = netdev_priv(dev);
-       unsigned head = np->cur_task % TX_RING_SIZE;
-       struct netdev_desc *txdesc =
-               &np->tx_ring[(np->cur_tx - 1) % TX_RING_SIZE];
-
-       /* Chain the next pointer */
-       for (; np->cur_tx - np->cur_task > 0; np->cur_task++) {
-               int entry = np->cur_task % TX_RING_SIZE;
-               txdesc = &np->tx_ring[entry];
-               if (np->last_tx) {
-                       np->last_tx->next_desc = cpu_to_le32(np->tx_ring_dma +
-                               entry*sizeof(struct netdev_desc));
-               }
-               np->last_tx = txdesc;
-       }
-       /* Indicate the latest descriptor of tx ring */
-       txdesc->status |= cpu_to_le32(DescIntrOnTx);
-
-       if (ioread32 (np->base + TxListPtr) == 0)
-               iowrite32 (np->tx_ring_dma + head * sizeof(struct netdev_desc),
-                       np->base + TxListPtr);
-}
-
-static netdev_tx_t
-start_tx (struct sk_buff *skb, struct net_device *dev)
-{
-       struct netdev_private *np = netdev_priv(dev);
-       struct netdev_desc *txdesc;
-       unsigned entry;
-
-       /* Calculate the next Tx descriptor entry. */
-       entry = np->cur_tx % TX_RING_SIZE;
-       np->tx_skbuff[entry] = skb;
-       txdesc = &np->tx_ring[entry];
-
-       txdesc->next_desc = 0;
-       txdesc->status = cpu_to_le32 ((entry << 2) | DisableAlign);
-       txdesc->frag[0].addr = cpu_to_le32(dma_map_single(&np->pci_dev->dev,
-                               skb->data, skb->len, DMA_TO_DEVICE));
-       if (dma_mapping_error(&np->pci_dev->dev,
-                               txdesc->frag[0].addr))
-                       goto drop_frame;
-       txdesc->frag[0].length = cpu_to_le32 (skb->len | LastFrag);
-
-       /* Increment cur_tx before tasklet_schedule() */
-       np->cur_tx++;
-       mb();
-       /* Schedule a tx_poll() task */
-       tasklet_schedule(&np->tx_tasklet);
-
-       /* On some architectures: explicitly flush cache lines here. */
-       if (np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 1 &&
-           !netif_queue_stopped(dev)) {
-               /* do nothing */
-       } else {
-               netif_stop_queue (dev);
-       }
-       if (netif_msg_tx_queued(np)) {
-               printk (KERN_DEBUG
-                       "%s: Transmit frame #%d queued in slot %d.\n",
-                       dev->name, np->cur_tx, entry);
-       }
-       return NETDEV_TX_OK;
-
-drop_frame:
-       dev_kfree_skb(skb);
-       np->tx_skbuff[entry] = NULL;
-       dev->stats.tx_dropped++;
-       return NETDEV_TX_OK;
-}
-
-/* Reset hardware tx and free all of tx buffers */
-static int
-reset_tx (struct net_device *dev)
-{
-       struct netdev_private *np = netdev_priv(dev);
-       void __iomem *ioaddr = np->base;
-       struct sk_buff *skb;
-       int i;
-
-       /* Reset tx logic, TxListPtr will be cleaned */
-       iowrite16 (TxDisable, ioaddr + MACCtrl1);
-       sundance_reset(dev, (NetworkReset|FIFOReset|DMAReset|TxReset) << 16);
-
-       /* free all tx skbuff */
-       for (i = 0; i < TX_RING_SIZE; i++) {
-               np->tx_ring[i].next_desc = 0;
-
-               skb = np->tx_skbuff[i];
-               if (skb) {
-                       dma_unmap_single(&np->pci_dev->dev,
-                               le32_to_cpu(np->tx_ring[i].frag[0].addr),
-                               skb->len, DMA_TO_DEVICE);
-                       dev_kfree_skb_any(skb);
-                       np->tx_skbuff[i] = NULL;
-                       dev->stats.tx_dropped++;
-               }
-       }
-       np->cur_tx = np->dirty_tx = 0;
-       np->cur_task = 0;
-
-       np->last_tx = NULL;
-       iowrite8(127, ioaddr + TxDMAPollPeriod);
-
-       iowrite16 (StatsEnable | RxEnable | TxEnable, ioaddr + MACCtrl1);
-       return 0;
-}
-
-/* The interrupt handler cleans up after the Tx thread,
-   and schedule a Rx thread work */
-static irqreturn_t intr_handler(int irq, void *dev_instance)
-{
-       struct net_device *dev = (struct net_device *)dev_instance;
-       struct netdev_private *np = netdev_priv(dev);
-       void __iomem *ioaddr = np->base;
-       int hw_frame_id;
-       int tx_cnt;
-       int tx_status;
-       int handled = 0;
-       int i;
-
-
-       do {
-               int intr_status = ioread16(ioaddr + IntrStatus);
-               iowrite16(intr_status, ioaddr + IntrStatus);
-
-               if (netif_msg_intr(np))
-                       printk(KERN_DEBUG "%s: Interrupt, status %4.4x.\n",
-                                  dev->name, intr_status);
-
-               if (!(intr_status & DEFAULT_INTR))
-                       break;
-
-               handled = 1;
-
-               if (intr_status & (IntrRxDMADone)) {
-                       iowrite16(DEFAULT_INTR & ~(IntrRxDone|IntrRxDMADone),
-                                       ioaddr + IntrEnable);
-                       if (np->budget < 0)
-                               np->budget = RX_BUDGET;
-                       tasklet_schedule(&np->rx_tasklet);
-               }
-               if (intr_status & (IntrTxDone | IntrDrvRqst)) {
-                       tx_status = ioread16 (ioaddr + TxStatus);
-                       for (tx_cnt=32; tx_status & 0x80; --tx_cnt) {
-                               if (netif_msg_tx_done(np))
-                                       printk
-                                           ("%s: Transmit status is %2.2x.\n",
-                                       dev->name, tx_status);
-                               if (tx_status & 0x1e) {
-                                       if (netif_msg_tx_err(np))
-                                               printk("%s: Transmit error status %4.4x.\n",
-                                                          dev->name, tx_status);
-                                       dev->stats.tx_errors++;
-                                       if (tx_status & 0x10)
-                                               dev->stats.tx_fifo_errors++;
-                                       if (tx_status & 0x08)
-                                               dev->stats.collisions++;
-                                       if (tx_status & 0x04)
-                                               dev->stats.tx_fifo_errors++;
-                                       if (tx_status & 0x02)
-                                               dev->stats.tx_window_errors++;
-
-                                       /*
-                                       ** This reset has been verified on
-                                       ** DFE-580TX boards ! phdm@macqel.be.
-                                       */
-                                       if (tx_status & 0x10) { /* TxUnderrun */
-                                               /* Restart Tx FIFO and transmitter */
-                                               sundance_reset(dev, (NetworkReset|FIFOReset|TxReset) << 16);
-                                               /* No need to reset the Tx pointer here */
-                                       }
-                                       /* Restart the Tx. Need to make sure tx enabled */
-                                       i = 10;
-                                       do {
-                                               iowrite16(ioread16(ioaddr + MACCtrl1) | TxEnable, ioaddr + MACCtrl1);
-                                               if (ioread16(ioaddr + MACCtrl1) & TxEnabled)
-                                                       break;
-                                               mdelay(1);
-                                       } while (--i);
-                               }
-                               /* Yup, this is a documentation bug.  It cost me *hours*. */
-                               iowrite16 (0, ioaddr + TxStatus);
-                               if (tx_cnt < 0) {
-                                       iowrite32(5000, ioaddr + DownCounter);
-                                       break;
-                               }
-                               tx_status = ioread16 (ioaddr + TxStatus);
-                       }
-                       hw_frame_id = (tx_status >> 8) & 0xff;
-               } else  {
-                       hw_frame_id = ioread8(ioaddr + TxFrameId);
-               }
-
-               if (np->pci_dev->revision >= 0x14) {
-                       spin_lock(&np->lock);
-                       for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) {
-                               int entry = np->dirty_tx % TX_RING_SIZE;
-                               struct sk_buff *skb;
-                               int sw_frame_id;
-                               sw_frame_id = (le32_to_cpu(
-                                       np->tx_ring[entry].status) >> 2) & 0xff;
-                               if (sw_frame_id == hw_frame_id &&
-                                       !(le32_to_cpu(np->tx_ring[entry].status)
-                                       & 0x00010000))
-                                               break;
-                               if (sw_frame_id == (hw_frame_id + 1) %
-                                       TX_RING_SIZE)
-                                               break;
-                               skb = np->tx_skbuff[entry];
-                               /* Free the original skb. */
-                               dma_unmap_single(&np->pci_dev->dev,
-                                       le32_to_cpu(np->tx_ring[entry].frag[0].addr),
-                                       skb->len, DMA_TO_DEVICE);
-                               dev_kfree_skb_irq (np->tx_skbuff[entry]);
-                               np->tx_skbuff[entry] = NULL;
-                               np->tx_ring[entry].frag[0].addr = 0;
-                               np->tx_ring[entry].frag[0].length = 0;
-                       }
-                       spin_unlock(&np->lock);
-               } else {
-                       spin_lock(&np->lock);
-                       for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) {
-                               int entry = np->dirty_tx % TX_RING_SIZE;
-                               struct sk_buff *skb;
-                               if (!(le32_to_cpu(np->tx_ring[entry].status)
-                                                       & 0x00010000))
-                                       break;
-                               skb = np->tx_skbuff[entry];
-                               /* Free the original skb. */
-                               dma_unmap_single(&np->pci_dev->dev,
-                                       le32_to_cpu(np->tx_ring[entry].frag[0].addr),
-                                       skb->len, DMA_TO_DEVICE);
-                               dev_kfree_skb_irq (np->tx_skbuff[entry]);
-                               np->tx_skbuff[entry] = NULL;
-                               np->tx_ring[entry].frag[0].addr = 0;
-                               np->tx_ring[entry].frag[0].length = 0;
-                       }
-                       spin_unlock(&np->lock);
-               }
-
-               if (netif_queue_stopped(dev) &&
-                       np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 4) {
-                       /* The ring is no longer full, clear busy flag. */
-                       netif_wake_queue (dev);
-               }
-               /* Abnormal error summary/uncommon events handlers. */
-               if (intr_status & (IntrPCIErr | LinkChange | StatsMax))
-                       netdev_error(dev, intr_status);
-       } while (0);
-       if (netif_msg_intr(np))
-               printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
-                          dev->name, ioread16(ioaddr + IntrStatus));
-       return IRQ_RETVAL(handled);
-}
-
-static void rx_poll(unsigned long data)
-{
-       struct net_device *dev = (struct net_device *)data;
-       struct netdev_private *np = netdev_priv(dev);
-       int entry = np->cur_rx % RX_RING_SIZE;
-       int boguscnt = np->budget;
-       void __iomem *ioaddr = np->base;
-       int received = 0;
-
-       /* If EOP is set on the next entry, it's a new packet. Send it up. */
-       while (1) {
-               struct netdev_desc *desc = &(np->rx_ring[entry]);
-               u32 frame_status = le32_to_cpu(desc->status);
-               int pkt_len;
-
-               if (--boguscnt < 0) {
-                       goto not_done;
-               }
-               if (!(frame_status & DescOwn))
-                       break;
-               pkt_len = frame_status & 0x1fff;        /* Chip omits the CRC. */
-               if (netif_msg_rx_status(np))
-                       printk(KERN_DEBUG "  netdev_rx() status was %8.8x.\n",
-                                  frame_status);
-               if (frame_status & 0x001f4000) {
-                       /* There was a error. */
-                       if (netif_msg_rx_err(np))
-                               printk(KERN_DEBUG "  netdev_rx() Rx error was %8.8x.\n",
-                                          frame_status);
-                       dev->stats.rx_errors++;
-                       if (frame_status & 0x00100000)
-                               dev->stats.rx_length_errors++;
-                       if (frame_status & 0x00010000)
-                               dev->stats.rx_fifo_errors++;
-                       if (frame_status & 0x00060000)
-                               dev->stats.rx_frame_errors++;
-                       if (frame_status & 0x00080000)
-                               dev->stats.rx_crc_errors++;
-                       if (frame_status & 0x00100000) {
-                               printk(KERN_WARNING "%s: Oversized Ethernet frame,"
-                                          " status %8.8x.\n",
-                                          dev->name, frame_status);
-                       }
-               } else {
-                       struct sk_buff *skb;
-#ifndef final_version
-                       if (netif_msg_rx_status(np))
-                               printk(KERN_DEBUG "  netdev_rx() normal Rx pkt length %d"
-                                          ", bogus_cnt %d.\n",
-                                          pkt_len, boguscnt);
-#endif
-                       /* Check if the packet is long enough to accept without copying
-                          to a minimally-sized skbuff. */
-                       if (pkt_len < rx_copybreak &&
-                           (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
-                               skb_reserve(skb, 2);    /* 16 byte align the IP header */
-                               dma_sync_single_for_cpu(&np->pci_dev->dev,
-                                               le32_to_cpu(desc->frag[0].addr),
-                                               np->rx_buf_sz, DMA_FROM_DEVICE);
-                               skb_copy_to_linear_data(skb, np->rx_skbuff[entry]->data, pkt_len);
-                               dma_sync_single_for_device(&np->pci_dev->dev,
-                                               le32_to_cpu(desc->frag[0].addr),
-                                               np->rx_buf_sz, DMA_FROM_DEVICE);
-                               skb_put(skb, pkt_len);
-                       } else {
-                               dma_unmap_single(&np->pci_dev->dev,
-                                       le32_to_cpu(desc->frag[0].addr),
-                                       np->rx_buf_sz, DMA_FROM_DEVICE);
-                               skb_put(skb = np->rx_skbuff[entry], pkt_len);
-                               np->rx_skbuff[entry] = NULL;
-                       }
-                       skb->protocol = eth_type_trans(skb, dev);
-                       /* Note: checksum -> skb->ip_summed = CHECKSUM_UNNECESSARY; */
-                       netif_rx(skb);
-               }
-               entry = (entry + 1) % RX_RING_SIZE;
-               received++;
-       }
-       np->cur_rx = entry;
-       refill_rx (dev);
-       np->budget -= received;
-       iowrite16(DEFAULT_INTR, ioaddr + IntrEnable);
-       return;
-
-not_done:
-       np->cur_rx = entry;
-       refill_rx (dev);
-       if (!received)
-               received = 1;
-       np->budget -= received;
-       if (np->budget <= 0)
-               np->budget = RX_BUDGET;
-       tasklet_schedule(&np->rx_tasklet);
-}
-
-static void refill_rx (struct net_device *dev)
-{
-       struct netdev_private *np = netdev_priv(dev);
-       int entry;
-       int cnt = 0;
-
-       /* Refill the Rx ring buffers. */
-       for (;(np->cur_rx - np->dirty_rx + RX_RING_SIZE) % RX_RING_SIZE > 0;
-               np->dirty_rx = (np->dirty_rx + 1) % RX_RING_SIZE) {
-               struct sk_buff *skb;
-               entry = np->dirty_rx % RX_RING_SIZE;
-               if (np->rx_skbuff[entry] == NULL) {
-                       skb = dev_alloc_skb(np->rx_buf_sz + 2);
-                       np->rx_skbuff[entry] = skb;
-                       if (skb == NULL)
-                               break;          /* Better luck next round. */
-                       skb->dev = dev;         /* Mark as being used by this device. */
-                       skb_reserve(skb, 2);    /* Align IP on 16 byte boundaries */
-                       np->rx_ring[entry].frag[0].addr = cpu_to_le32(
-                               dma_map_single(&np->pci_dev->dev, skb->data,
-                                       np->rx_buf_sz, DMA_FROM_DEVICE));
-                       if (dma_mapping_error(&np->pci_dev->dev,
-                                   np->rx_ring[entry].frag[0].addr)) {
-                           dev_kfree_skb_irq(skb);
-                           np->rx_skbuff[entry] = NULL;
-                           break;
-                       }
-               }
-               /* Perhaps we need not reset this field. */
-               np->rx_ring[entry].frag[0].length =
-                       cpu_to_le32(np->rx_buf_sz | LastFrag);
-               np->rx_ring[entry].status = 0;
-               cnt++;
-       }
-}
-static void netdev_error(struct net_device *dev, int intr_status)
-{
-       struct netdev_private *np = netdev_priv(dev);
-       void __iomem *ioaddr = np->base;
-       u16 mii_ctl, mii_advertise, mii_lpa;
-       int speed;
-
-       if (intr_status & LinkChange) {
-               if (mdio_wait_link(dev, 10) == 0) {
-                       printk(KERN_INFO "%s: Link up\n", dev->name);
-                       if (np->an_enable) {
-                               mii_advertise = mdio_read(dev, np->phys[0],
-                                                          MII_ADVERTISE);
-                               mii_lpa = mdio_read(dev, np->phys[0], MII_LPA);
-                               mii_advertise &= mii_lpa;
-                               printk(KERN_INFO "%s: Link changed: ",
-                                       dev->name);
-                               if (mii_advertise & ADVERTISE_100FULL) {
-                                       np->speed = 100;
-                                       printk("100Mbps, full duplex\n");
-                               } else if (mii_advertise & ADVERTISE_100HALF) {
-                                       np->speed = 100;
-                                       printk("100Mbps, half duplex\n");
-                               } else if (mii_advertise & ADVERTISE_10FULL) {
-                                       np->speed = 10;
-                                       printk("10Mbps, full duplex\n");
-                               } else if (mii_advertise & ADVERTISE_10HALF) {
-                                       np->speed = 10;
-                                       printk("10Mbps, half duplex\n");
-                               } else
-                                       printk("\n");
-
-                       } else {
-                               mii_ctl = mdio_read(dev, np->phys[0], MII_BMCR);
-                               speed = (mii_ctl & BMCR_SPEED100) ? 100 : 10;
-                               np->speed = speed;
-                               printk(KERN_INFO "%s: Link changed: %dMbps ,",
-                                       dev->name, speed);
-                               printk("%s duplex.\n",
-                                       (mii_ctl & BMCR_FULLDPLX) ?
-                                               "full" : "half");
-                       }
-                       check_duplex(dev);
-                       if (np->flowctrl && np->mii_if.full_duplex) {
-                               iowrite16(ioread16(ioaddr + MulticastFilter1+2) | 0x0200,
-                                       ioaddr + MulticastFilter1+2);
-                               iowrite16(ioread16(ioaddr + MACCtrl0) | EnbFlowCtrl,
-                                       ioaddr + MACCtrl0);
-                       }
-                       netif_carrier_on(dev);
-               } else {
-                       printk(KERN_INFO "%s: Link down\n", dev->name);
-                       netif_carrier_off(dev);
-               }
-       }
-       if (intr_status & StatsMax) {
-               get_stats(dev);
-       }
-       if (intr_status & IntrPCIErr) {
-               printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n",
-                          dev->name, intr_status);
-               /* We must do a global reset of DMA to continue. */
-       }
-}
-
-static struct net_device_stats *get_stats(struct net_device *dev)
-{
-       struct netdev_private *np = netdev_priv(dev);
-       void __iomem *ioaddr = np->base;
-       unsigned long flags;
-       u8 late_coll, single_coll, mult_coll;
-
-       spin_lock_irqsave(&np->statlock, flags);
-       /* The chip only need report frame silently dropped. */
-       dev->stats.rx_missed_errors     += ioread8(ioaddr + RxMissed);
-       dev->stats.tx_packets += ioread16(ioaddr + TxFramesOK);
-       dev->stats.rx_packets += ioread16(ioaddr + RxFramesOK);
-       dev->stats.tx_carrier_errors += ioread8(ioaddr + StatsCarrierError);
-
-       mult_coll = ioread8(ioaddr + StatsMultiColl);
-       np->xstats.tx_multiple_collisions += mult_coll;
-       single_coll = ioread8(ioaddr + StatsOneColl);
-       np->xstats.tx_single_collisions += single_coll;
-       late_coll = ioread8(ioaddr + StatsLateColl);
-       np->xstats.tx_late_collisions += late_coll;
-       dev->stats.collisions += mult_coll
-               + single_coll
-               + late_coll;
-
-       np->xstats.tx_deferred += ioread8(ioaddr + StatsTxDefer);
-       np->xstats.tx_deferred_excessive += ioread8(ioaddr + StatsTxXSDefer);
-       np->xstats.tx_aborted += ioread8(ioaddr + StatsTxAbort);
-       np->xstats.tx_bcasts += ioread8(ioaddr + StatsBcastTx);
-       np->xstats.rx_bcasts += ioread8(ioaddr + StatsBcastRx);
-       np->xstats.tx_mcasts += ioread8(ioaddr + StatsMcastTx);
-       np->xstats.rx_mcasts += ioread8(ioaddr + StatsMcastRx);
-
-       dev->stats.tx_bytes += ioread16(ioaddr + TxOctetsLow);
-       dev->stats.tx_bytes += ioread16(ioaddr + TxOctetsHigh) << 16;
-       dev->stats.rx_bytes += ioread16(ioaddr + RxOctetsLow);
-       dev->stats.rx_bytes += ioread16(ioaddr + RxOctetsHigh) << 16;
-
-       spin_unlock_irqrestore(&np->statlock, flags);
-
-       return &dev->stats;
-}
-
-static void set_rx_mode(struct net_device *dev)
-{
-       struct netdev_private *np = netdev_priv(dev);
-       void __iomem *ioaddr = np->base;
-       u16 mc_filter[4];                       /* Multicast hash filter */
-       u32 rx_mode;
-       int i;
-
-       if (dev->flags & IFF_PROMISC) {                 /* Set promiscuous. */
-               memset(mc_filter, 0xff, sizeof(mc_filter));
-               rx_mode = AcceptBroadcast | AcceptMulticast | AcceptAll | AcceptMyPhys;
-       } else if ((netdev_mc_count(dev) > multicast_filter_limit) ||
-                  (dev->flags & IFF_ALLMULTI)) {
-               /* Too many to match, or accept all multicasts. */
-               memset(mc_filter, 0xff, sizeof(mc_filter));
-               rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
-       } else if (!netdev_mc_empty(dev)) {
-               struct netdev_hw_addr *ha;
-               int bit;
-               int index;
-               int crc;
-               memset (mc_filter, 0, sizeof (mc_filter));
-               netdev_for_each_mc_addr(ha, dev) {
-                       crc = ether_crc_le(ETH_ALEN, ha->addr);
-                       for (index=0, bit=0; bit < 6; bit++, crc <<= 1)
-                               if (crc & 0x80000000) index |= 1 << bit;
-                       mc_filter[index/16] |= (1 << (index % 16));
-               }
-               rx_mode = AcceptBroadcast | AcceptMultiHash | AcceptMyPhys;
-       } else {
-               iowrite8(AcceptBroadcast | AcceptMyPhys, ioaddr + RxMode);
-               return;
-       }
-       if (np->mii_if.full_duplex && np->flowctrl)
-               mc_filter[3] |= 0x0200;
-
-       for (i = 0; i < 4; i++)
-               iowrite16(mc_filter[i], ioaddr + MulticastFilter0 + i*2);
-       iowrite8(rx_mode, ioaddr + RxMode);
-}
-
-static int __set_mac_addr(struct net_device *dev)
-{
-       struct netdev_private *np = netdev_priv(dev);
-       u16 addr16;
-
-       addr16 = (dev->dev_addr[0] | (dev->dev_addr[1] << 8));
-       iowrite16(addr16, np->base + StationAddr);
-       addr16 = (dev->dev_addr[2] | (dev->dev_addr[3] << 8));
-       iowrite16(addr16, np->base + StationAddr+2);
-       addr16 = (dev->dev_addr[4] | (dev->dev_addr[5] << 8));
-       iowrite16(addr16, np->base + StationAddr+4);
-       return 0;
-}
-
-/* Invoked with rtnl_lock held */
-static int sundance_set_mac_addr(struct net_device *dev, void *data)
-{
-       const struct sockaddr *addr = data;
-
-       if (!is_valid_ether_addr(addr->sa_data))
-               return -EINVAL;
-       memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
-       __set_mac_addr(dev);
-
-       return 0;
-}
-
-static const struct {
-       const char name[ETH_GSTRING_LEN];
-} sundance_stats[] = {
-       { "tx_multiple_collisions" },
-       { "tx_single_collisions" },
-       { "tx_late_collisions" },
-       { "tx_deferred" },
-       { "tx_deferred_excessive" },
-       { "tx_aborted" },
-       { "tx_bcasts" },
-       { "rx_bcasts" },
-       { "tx_mcasts" },
-       { "rx_mcasts" },
-};
-
-static int check_if_running(struct net_device *dev)
-{
-       if (!netif_running(dev))
-               return -EINVAL;
-       return 0;
-}
-
-static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
-{
-       struct netdev_private *np = netdev_priv(dev);
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->bus_info, pci_name(np->pci_dev));
-}
-
-static int get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
-{
-       struct netdev_private *np = netdev_priv(dev);
-       spin_lock_irq(&np->lock);
-       mii_ethtool_gset(&np->mii_if, ecmd);
-       spin_unlock_irq(&np->lock);
-       return 0;
-}
-
-static int set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
-{
-       struct netdev_private *np = netdev_priv(dev);
-       int res;
-       spin_lock_irq(&np->lock);
-       res = mii_ethtool_sset(&np->mii_if, ecmd);
-       spin_unlock_irq(&np->lock);
-       return res;
-}
-
-static int nway_reset(struct net_device *dev)
-{
-       struct netdev_private *np = netdev_priv(dev);
-       return mii_nway_restart(&np->mii_if);
-}
-
-static u32 get_link(struct net_device *dev)
-{
-       struct netdev_private *np = netdev_priv(dev);
-       return mii_link_ok(&np->mii_if);
-}
-
-static u32 get_msglevel(struct net_device *dev)
-{
-       struct netdev_private *np = netdev_priv(dev);
-       return np->msg_enable;
-}
-
-static void set_msglevel(struct net_device *dev, u32 val)
-{
-       struct netdev_private *np = netdev_priv(dev);
-       np->msg_enable = val;
-}
-
-static void get_strings(struct net_device *dev, u32 stringset,
-               u8 *data)
-{
-       if (stringset == ETH_SS_STATS)
-               memcpy(data, sundance_stats, sizeof(sundance_stats));
-}
-
-static int get_sset_count(struct net_device *dev, int sset)
-{
-       switch (sset) {
-       case ETH_SS_STATS:
-               return ARRAY_SIZE(sundance_stats);
-       default:
-               return -EOPNOTSUPP;
-       }
-}
-
-static void get_ethtool_stats(struct net_device *dev,
-               struct ethtool_stats *stats, u64 *data)
-{
-       struct netdev_private *np = netdev_priv(dev);
-       int i = 0;
-
-       get_stats(dev);
-       data[i++] = np->xstats.tx_multiple_collisions;
-       data[i++] = np->xstats.tx_single_collisions;
-       data[i++] = np->xstats.tx_late_collisions;
-       data[i++] = np->xstats.tx_deferred;
-       data[i++] = np->xstats.tx_deferred_excessive;
-       data[i++] = np->xstats.tx_aborted;
-       data[i++] = np->xstats.tx_bcasts;
-       data[i++] = np->xstats.rx_bcasts;
-       data[i++] = np->xstats.tx_mcasts;
-       data[i++] = np->xstats.rx_mcasts;
-}
-
-static const struct ethtool_ops ethtool_ops = {
-       .begin = check_if_running,
-       .get_drvinfo = get_drvinfo,
-       .get_settings = get_settings,
-       .set_settings = set_settings,
-       .nway_reset = nway_reset,
-       .get_link = get_link,
-       .get_msglevel = get_msglevel,
-       .set_msglevel = set_msglevel,
-       .get_strings = get_strings,
-       .get_sset_count = get_sset_count,
-       .get_ethtool_stats = get_ethtool_stats,
-};
-
-static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
-       struct netdev_private *np = netdev_priv(dev);
-       int rc;
-
-       if (!netif_running(dev))
-               return -EINVAL;
-
-       spin_lock_irq(&np->lock);
-       rc = generic_mii_ioctl(&np->mii_if, if_mii(rq), cmd, NULL);
-       spin_unlock_irq(&np->lock);
-
-       return rc;
-}
-
-static int netdev_close(struct net_device *dev)
-{
-       struct netdev_private *np = netdev_priv(dev);
-       void __iomem *ioaddr = np->base;
-       struct sk_buff *skb;
-       int i;
-
-       /* Wait and kill tasklet */
-       tasklet_kill(&np->rx_tasklet);
-       tasklet_kill(&np->tx_tasklet);
-       np->cur_tx = 0;
-       np->dirty_tx = 0;
-       np->cur_task = 0;
-       np->last_tx = NULL;
-
-       netif_stop_queue(dev);
-
-       if (netif_msg_ifdown(np)) {
-               printk(KERN_DEBUG "%s: Shutting down ethercard, status was Tx %2.2x "
-                          "Rx %4.4x Int %2.2x.\n",
-                          dev->name, ioread8(ioaddr + TxStatus),
-                          ioread32(ioaddr + RxStatus), ioread16(ioaddr + IntrStatus));
-               printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d,  Rx %d / %d.\n",
-                          dev->name, np->cur_tx, np->dirty_tx, np->cur_rx, np->dirty_rx);
-       }
-
-       /* Disable interrupts by clearing the interrupt mask. */
-       iowrite16(0x0000, ioaddr + IntrEnable);
-
-       /* Disable Rx and Tx DMA for safely release resource */
-       iowrite32(0x500, ioaddr + DMACtrl);
-
-       /* Stop the chip's Tx and Rx processes. */
-       iowrite16(TxDisable | RxDisable | StatsDisable, ioaddr + MACCtrl1);
-
-       for (i = 2000; i > 0; i--) {
-               if ((ioread32(ioaddr + DMACtrl) & 0xc000) == 0)
-                       break;
-               mdelay(1);
-       }
-
-       iowrite16(GlobalReset | DMAReset | FIFOReset | NetworkReset,
-                       ioaddr + ASIC_HI_WORD(ASICCtrl));
-
-       for (i = 2000; i > 0; i--) {
-               if ((ioread16(ioaddr + ASIC_HI_WORD(ASICCtrl)) & ResetBusy) == 0)
-                       break;
-               mdelay(1);
-       }
-
-#ifdef __i386__
-       if (netif_msg_hw(np)) {
-               printk(KERN_DEBUG "  Tx ring at %8.8x:\n",
-                          (int)(np->tx_ring_dma));
-               for (i = 0; i < TX_RING_SIZE; i++)
-                       printk(KERN_DEBUG " #%d desc. %4.4x %8.8x %8.8x.\n",
-                                  i, np->tx_ring[i].status, np->tx_ring[i].frag[0].addr,
-                                  np->tx_ring[i].frag[0].length);
-               printk(KERN_DEBUG "  Rx ring %8.8x:\n",
-                          (int)(np->rx_ring_dma));
-               for (i = 0; i < /*RX_RING_SIZE*/4 ; i++) {
-                       printk(KERN_DEBUG " #%d desc. %4.4x %4.4x %8.8x\n",
-                                  i, np->rx_ring[i].status, np->rx_ring[i].frag[0].addr,
-                                  np->rx_ring[i].frag[0].length);
-               }
-       }
-#endif /* __i386__ debugging only */
-
-       free_irq(dev->irq, dev);
-
-       del_timer_sync(&np->timer);
-
-       /* Free all the skbuffs in the Rx queue. */
-       for (i = 0; i < RX_RING_SIZE; i++) {
-               np->rx_ring[i].status = 0;
-               skb = np->rx_skbuff[i];
-               if (skb) {
-                       dma_unmap_single(&np->pci_dev->dev,
-                               le32_to_cpu(np->rx_ring[i].frag[0].addr),
-                               np->rx_buf_sz, DMA_FROM_DEVICE);
-                       dev_kfree_skb(skb);
-                       np->rx_skbuff[i] = NULL;
-               }
-               np->rx_ring[i].frag[0].addr = cpu_to_le32(0xBADF00D0); /* poison */
-       }
-       for (i = 0; i < TX_RING_SIZE; i++) {
-               np->tx_ring[i].next_desc = 0;
-               skb = np->tx_skbuff[i];
-               if (skb) {
-                       dma_unmap_single(&np->pci_dev->dev,
-                               le32_to_cpu(np->tx_ring[i].frag[0].addr),
-                               skb->len, DMA_TO_DEVICE);
-                       dev_kfree_skb(skb);
-                       np->tx_skbuff[i] = NULL;
-               }
-       }
-
-       return 0;
-}
-
-static void __devexit sundance_remove1 (struct pci_dev *pdev)
-{
-       struct net_device *dev = pci_get_drvdata(pdev);
-
-       if (dev) {
-           struct netdev_private *np = netdev_priv(dev);
-           unregister_netdev(dev);
-           dma_free_coherent(&pdev->dev, RX_TOTAL_SIZE,
-                   np->rx_ring, np->rx_ring_dma);
-           dma_free_coherent(&pdev->dev, TX_TOTAL_SIZE,
-                   np->tx_ring, np->tx_ring_dma);
-           pci_iounmap(pdev, np->base);
-           pci_release_regions(pdev);
-           free_netdev(dev);
-           pci_set_drvdata(pdev, NULL);
-       }
-}
-
-#ifdef CONFIG_PM
-
-static int sundance_suspend(struct pci_dev *pci_dev, pm_message_t state)
-{
-       struct net_device *dev = pci_get_drvdata(pci_dev);
-
-       if (!netif_running(dev))
-               return 0;
-
-       netdev_close(dev);
-       netif_device_detach(dev);
-
-       pci_save_state(pci_dev);
-       pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state));
-
-       return 0;
-}
-
-static int sundance_resume(struct pci_dev *pci_dev)
-{
-       struct net_device *dev = pci_get_drvdata(pci_dev);
-       int err = 0;
-
-       if (!netif_running(dev))
-               return 0;
-
-       pci_set_power_state(pci_dev, PCI_D0);
-       pci_restore_state(pci_dev);
-
-       err = netdev_open(dev);
-       if (err) {
-               printk(KERN_ERR "%s: Can't resume interface!\n",
-                               dev->name);
-               goto out;
-       }
-
-       netif_device_attach(dev);
-
-out:
-       return err;
-}
-
-#endif /* CONFIG_PM */
-
-static struct pci_driver sundance_driver = {
-       .name           = DRV_NAME,
-       .id_table       = sundance_pci_tbl,
-       .probe          = sundance_probe1,
-       .remove         = __devexit_p(sundance_remove1),
-#ifdef CONFIG_PM
-       .suspend        = sundance_suspend,
-       .resume         = sundance_resume,
-#endif /* CONFIG_PM */
-};
-
-static int __init sundance_init(void)
-{
-/* when a module, this is printed whether or not devices are found in probe */
-#ifdef MODULE
-       printk(version);
-#endif
-       return pci_register_driver(&sundance_driver);
-}
-
-static void __exit sundance_exit(void)
-{
-       pci_unregister_driver(&sundance_driver);
-}
-
-module_init(sundance_init);
-module_exit(sundance_exit);
-
-