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)
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
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
# 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
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
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
+++ /dev/null
-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");
+++ /dev/null
-/**************************************************
- * *
- * 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)
+++ /dev/null
-/*
- * 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");
+++ /dev/null
-/*********************************************************
- * *
- * 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 */
+++ /dev/null
-/* 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, ðtool_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.
-
-*/
-
+++ /dev/null
-/* 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__ */
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"
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/
--- /dev/null
+#
+# 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
--- /dev/null
+#
+# 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
--- /dev/null
+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");
--- /dev/null
+/**************************************************
+ * *
+ * 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)
--- /dev/null
+/*
+ * 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");
--- /dev/null
+/*********************************************************
+ * *
+ * 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 */
--- /dev/null
+/* 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, ðtool_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.
+
+*/
+
--- /dev/null
+/* 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__ */
--- /dev/null
+/* 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, ðtool_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);
+
+
+++ /dev/null
-/* 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, ðtool_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);
-
-