M: Philip Blundell <philb@gnu.org>
L: netdev@vger.kernel.org
S: Maintained
-F: drivers/net/3c505*
+F: drivers/net/ethernet/i825xx/3c505*
3C59X NETWORK DRIVER
M: Steffen Klassert <klassert@mathematik.tu-chemnitz.de>
F: arch/arm/include/asm/hardware/iomd.h
F: arch/arm/include/asm/hardware/memc.h
F: arch/arm/mach-rpc/
-F: drivers/net/arm/ether*
+F: drivers/net/arm/ether3*
F: drivers/scsi/arm/
ARM/SHARK MACHINE SUPPORT
M: Philip Blundell <philb@gnu.org>
L: netdev@vger.kernel.org
S: Maintained
-F: drivers/net/eexpress.*
+F: drivers/net/ethernet/i825xx/eexpress.*
ETHERNET BRIDGE
M: Stephen Hemminger <shemminger@linux-foundation.org>
+++ /dev/null
-/*
- * Linux Ethernet device driver for the 3Com Etherlink Plus (3C505)
- * By Craig Southeren, Juha Laiho and Philip Blundell
- *
- * 3c505.c This module implements an interface to the 3Com
- * Etherlink Plus (3c505) Ethernet card. Linux device
- * driver interface reverse engineered from the Linux 3C509
- * device drivers. Some 3C505 information gleaned from
- * the Crynwr packet driver. Still this driver would not
- * be here without 3C505 technical reference provided by
- * 3Com.
- *
- * $Id: 3c505.c,v 1.10 1996/04/16 13:06:27 phil Exp $
- *
- * Authors: Linux 3c505 device driver by
- * Craig Southeren, <craigs@ineluki.apana.org.au>
- * Final debugging by
- * Andrew Tridgell, <tridge@nimbus.anu.edu.au>
- * Auto irq/address, tuning, cleanup and v1.1.4+ kernel mods by
- * Juha Laiho, <jlaiho@ichaos.nullnet.fi>
- * Linux 3C509 driver by
- * Donald Becker, <becker@super.org>
- * (Now at <becker@scyld.com>)
- * Crynwr packet driver by
- * Krishnan Gopalan and Gregg Stefancik,
- * Clemson University Engineering Computer Operations.
- * Portions of the code have been adapted from the 3c505
- * driver for NCSA Telnet by Bruce Orchard and later
- * modified by Warren Van Houten and krus@diku.dk.
- * 3C505 technical information provided by
- * Terry Murphy, of 3Com Network Adapter Division
- * Linux 1.3.0 changes by
- * Alan Cox <Alan.Cox@linux.org>
- * More debugging, DMA support, currently maintained by
- * Philip Blundell <philb@gnu.org>
- * Multicard/soft configurable dma channel/rev 2 hardware support
- * by Christopher Collins <ccollins@pcug.org.au>
- * Ethtool support (jgarzik), 11/17/2001
- */
-
-#define DRV_NAME "3c505"
-#define DRV_VERSION "1.10a"
-
-
-/* Theory of operation:
- *
- * The 3c505 is quite an intelligent board. All communication with it is done
- * by means of Primary Command Blocks (PCBs); these are transferred using PIO
- * through the command register. The card has 256k of on-board RAM, which is
- * used to buffer received packets. It might seem at first that more buffers
- * are better, but in fact this isn't true. From my tests, it seems that
- * more than about 10 buffers are unnecessary, and there is a noticeable
- * performance hit in having more active on the card. So the majority of the
- * card's memory isn't, in fact, used. Sadly, the card only has one transmit
- * buffer and, short of loading our own firmware into it (which is what some
- * drivers resort to) there's nothing we can do about this.
- *
- * We keep up to 4 "receive packet" commands active on the board at a time.
- * When a packet comes in, so long as there is a receive command active, the
- * board will send us a "packet received" PCB and then add the data for that
- * packet to the DMA queue. If a DMA transfer is not already in progress, we
- * set one up to start uploading the data. We have to maintain a list of
- * backlogged receive packets, because the card may decide to tell us about
- * a newly-arrived packet at any time, and we may not be able to start a DMA
- * transfer immediately (ie one may already be going on). We can't NAK the
- * PCB, because then it would throw the packet away.
- *
- * Trying to send a PCB to the card at the wrong moment seems to have bad
- * effects. If we send it a transmit PCB while a receive DMA is happening,
- * it will just NAK the PCB and so we will have wasted our time. Worse, it
- * sometimes seems to interrupt the transfer. The majority of the low-level
- * code is protected by one huge semaphore -- "busy" -- which is set whenever
- * it probably isn't safe to do anything to the card. The receive routine
- * must gain a lock on "busy" before it can start a DMA transfer, and the
- * transmit routine must gain a lock before it sends the first PCB to the card.
- * The send_pcb() routine also has an internal semaphore to protect it against
- * being re-entered (which would be disastrous) -- this is needed because
- * several things can happen asynchronously (re-priming the receiver and
- * asking the card for statistics, for example). send_pcb() will also refuse
- * to talk to the card at all if a DMA upload is happening. The higher-level
- * networking code will reschedule a later retry if some part of the driver
- * is blocked. In practice, this doesn't seem to happen very often.
- */
-
-/* This driver may now work with revision 2.x hardware, since all the read
- * operations on the HCR have been removed (we now keep our own softcopy).
- * But I don't have an old card to test it on.
- *
- * This has had the bad effect that the autoprobe routine is now a bit
- * less friendly to other devices. However, it was never very good.
- * before, so I doubt it will hurt anybody.
- */
-
-/* The driver is a mess. I took Craig's and Juha's code, and hacked it firstly
- * to make it more reliable, and secondly to add DMA mode. Many things could
- * probably be done better; the concurrency protection is particularly awful.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/interrupt.h>
-#include <linux/errno.h>
-#include <linux/in.h>
-#include <linux/ioport.h>
-#include <linux/spinlock.h>
-#include <linux/ethtool.h>
-#include <linux/delay.h>
-#include <linux/bitops.h>
-#include <linux/gfp.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/init.h>
-
-#include "3c505.h"
-
-/*********************************************************
- *
- * define debug messages here as common strings to reduce space
- *
- *********************************************************/
-
-#define filename __FILE__
-
-#define timeout_msg "*** timeout at %s:%s (line %d) ***\n"
-#define TIMEOUT_MSG(lineno) \
- pr_notice(timeout_msg, filename, __func__, (lineno))
-
-#define invalid_pcb_msg "*** invalid pcb length %d at %s:%s (line %d) ***\n"
-#define INVALID_PCB_MSG(len) \
- pr_notice(invalid_pcb_msg, (len), filename, __func__, __LINE__)
-
-#define search_msg "%s: Looking for 3c505 adapter at address %#x..."
-
-#define stilllooking_msg "still looking..."
-
-#define found_msg "found.\n"
-
-#define notfound_msg "not found (reason = %d)\n"
-
-#define couldnot_msg "%s: 3c505 not found\n"
-
-/*********************************************************
- *
- * various other debug stuff
- *
- *********************************************************/
-
-#ifdef ELP_DEBUG
-static int elp_debug = ELP_DEBUG;
-#else
-static int elp_debug;
-#endif
-#define debug elp_debug
-
-/*
- * 0 = no messages (well, some)
- * 1 = messages when high level commands performed
- * 2 = messages when low level commands performed
- * 3 = messages when interrupts received
- */
-
-/*****************************************************************
- *
- * List of I/O-addresses we try to auto-sense
- * Last element MUST BE 0!
- *****************************************************************/
-
-static int addr_list[] __initdata = {0x300, 0x280, 0x310, 0};
-
-/* Dma Memory related stuff */
-
-static unsigned long dma_mem_alloc(int size)
-{
- int order = get_order(size);
- return __get_dma_pages(GFP_KERNEL, order);
-}
-
-
-/*****************************************************************
- *
- * Functions for I/O (note the inline !)
- *
- *****************************************************************/
-
-static inline unsigned char inb_status(unsigned int base_addr)
-{
- return inb(base_addr + PORT_STATUS);
-}
-
-static inline int inb_command(unsigned int base_addr)
-{
- return inb(base_addr + PORT_COMMAND);
-}
-
-static inline void outb_control(unsigned char val, struct net_device *dev)
-{
- outb(val, dev->base_addr + PORT_CONTROL);
- ((elp_device *)(netdev_priv(dev)))->hcr_val = val;
-}
-
-#define HCR_VAL(x) (((elp_device *)(netdev_priv(x)))->hcr_val)
-
-static inline void outb_command(unsigned char val, unsigned int base_addr)
-{
- outb(val, base_addr + PORT_COMMAND);
-}
-
-static inline unsigned int backlog_next(unsigned int n)
-{
- return (n + 1) % BACKLOG_SIZE;
-}
-
-/*****************************************************************
- *
- * useful functions for accessing the adapter
- *
- *****************************************************************/
-
-/*
- * use this routine when accessing the ASF bits as they are
- * changed asynchronously by the adapter
- */
-
-/* get adapter PCB status */
-#define GET_ASF(addr) \
- (get_status(addr)&ASF_PCB_MASK)
-
-static inline int get_status(unsigned int base_addr)
-{
- unsigned long timeout = jiffies + 10*HZ/100;
- register int stat1;
- do {
- stat1 = inb_status(base_addr);
- } while (stat1 != inb_status(base_addr) && time_before(jiffies, timeout));
- if (time_after_eq(jiffies, timeout))
- TIMEOUT_MSG(__LINE__);
- return stat1;
-}
-
-static inline void set_hsf(struct net_device *dev, int hsf)
-{
- elp_device *adapter = netdev_priv(dev);
- unsigned long flags;
-
- spin_lock_irqsave(&adapter->lock, flags);
- outb_control((HCR_VAL(dev) & ~HSF_PCB_MASK) | hsf, dev);
- spin_unlock_irqrestore(&adapter->lock, flags);
-}
-
-static bool start_receive(struct net_device *, pcb_struct *);
-
-static inline void adapter_reset(struct net_device *dev)
-{
- unsigned long timeout;
- elp_device *adapter = netdev_priv(dev);
- unsigned char orig_hcr = adapter->hcr_val;
-
- outb_control(0, dev);
-
- if (inb_status(dev->base_addr) & ACRF) {
- do {
- inb_command(dev->base_addr);
- timeout = jiffies + 2*HZ/100;
- while (time_before_eq(jiffies, timeout) && !(inb_status(dev->base_addr) & ACRF));
- } while (inb_status(dev->base_addr) & ACRF);
- set_hsf(dev, HSF_PCB_NAK);
- }
- outb_control(adapter->hcr_val | ATTN | DIR, dev);
- mdelay(10);
- outb_control(adapter->hcr_val & ~ATTN, dev);
- mdelay(10);
- outb_control(adapter->hcr_val | FLSH, dev);
- mdelay(10);
- outb_control(adapter->hcr_val & ~FLSH, dev);
- mdelay(10);
-
- outb_control(orig_hcr, dev);
- if (!start_receive(dev, &adapter->tx_pcb))
- pr_err("%s: start receive command failed\n", dev->name);
-}
-
-/* Check to make sure that a DMA transfer hasn't timed out. This should
- * never happen in theory, but seems to occur occasionally if the card gets
- * prodded at the wrong time.
- */
-static inline void check_3c505_dma(struct net_device *dev)
-{
- elp_device *adapter = netdev_priv(dev);
- if (adapter->dmaing && time_after(jiffies, adapter->current_dma.start_time + 10)) {
- unsigned long flags, f;
- pr_err("%s: DMA %s timed out, %d bytes left\n", dev->name,
- adapter->current_dma.direction ? "download" : "upload",
- get_dma_residue(dev->dma));
- spin_lock_irqsave(&adapter->lock, flags);
- adapter->dmaing = 0;
- adapter->busy = 0;
-
- f=claim_dma_lock();
- disable_dma(dev->dma);
- release_dma_lock(f);
-
- if (adapter->rx_active)
- adapter->rx_active--;
- outb_control(adapter->hcr_val & ~(DMAE | TCEN | DIR), dev);
- spin_unlock_irqrestore(&adapter->lock, flags);
- }
-}
-
-/* Primitive functions used by send_pcb() */
-static inline bool send_pcb_slow(unsigned int base_addr, unsigned char byte)
-{
- unsigned long timeout;
- outb_command(byte, base_addr);
- for (timeout = jiffies + 5*HZ/100; time_before(jiffies, timeout);) {
- if (inb_status(base_addr) & HCRE)
- return false;
- }
- pr_warning("3c505: send_pcb_slow timed out\n");
- return true;
-}
-
-static inline bool send_pcb_fast(unsigned int base_addr, unsigned char byte)
-{
- unsigned int timeout;
- outb_command(byte, base_addr);
- for (timeout = 0; timeout < 40000; timeout++) {
- if (inb_status(base_addr) & HCRE)
- return false;
- }
- pr_warning("3c505: send_pcb_fast timed out\n");
- return true;
-}
-
-/* Check to see if the receiver needs restarting, and kick it if so */
-static inline void prime_rx(struct net_device *dev)
-{
- elp_device *adapter = netdev_priv(dev);
- while (adapter->rx_active < ELP_RX_PCBS && netif_running(dev)) {
- if (!start_receive(dev, &adapter->itx_pcb))
- break;
- }
-}
-
-/*****************************************************************
- *
- * send_pcb
- * Send a PCB to the adapter.
- *
- * output byte to command reg --<--+
- * wait until HCRE is non zero |
- * loop until all bytes sent -->--+
- * set HSF1 and HSF2 to 1
- * output pcb length
- * wait until ASF give ACK or NAK
- * set HSF1 and HSF2 to 0
- *
- *****************************************************************/
-
-/* This can be quite slow -- the adapter is allowed to take up to 40ms
- * to respond to the initial interrupt.
- *
- * We run initially with interrupts turned on, but with a semaphore set
- * so that nobody tries to re-enter this code. Once the first byte has
- * gone through, we turn interrupts off and then send the others (the
- * timeout is reduced to 500us).
- */
-
-static bool send_pcb(struct net_device *dev, pcb_struct * pcb)
-{
- int i;
- unsigned long timeout;
- elp_device *adapter = netdev_priv(dev);
- unsigned long flags;
-
- check_3c505_dma(dev);
-
- if (adapter->dmaing && adapter->current_dma.direction == 0)
- return false;
-
- /* Avoid contention */
- if (test_and_set_bit(1, &adapter->send_pcb_semaphore)) {
- if (elp_debug >= 3) {
- pr_debug("%s: send_pcb entered while threaded\n", dev->name);
- }
- return false;
- }
- /*
- * load each byte into the command register and
- * wait for the HCRE bit to indicate the adapter
- * had read the byte
- */
- set_hsf(dev, 0);
-
- if (send_pcb_slow(dev->base_addr, pcb->command))
- goto abort;
-
- spin_lock_irqsave(&adapter->lock, flags);
-
- if (send_pcb_fast(dev->base_addr, pcb->length))
- goto sti_abort;
-
- for (i = 0; i < pcb->length; i++) {
- if (send_pcb_fast(dev->base_addr, pcb->data.raw[i]))
- goto sti_abort;
- }
-
- outb_control(adapter->hcr_val | 3, dev); /* signal end of PCB */
- outb_command(2 + pcb->length, dev->base_addr);
-
- /* now wait for the acknowledgement */
- spin_unlock_irqrestore(&adapter->lock, flags);
-
- for (timeout = jiffies + 5*HZ/100; time_before(jiffies, timeout);) {
- switch (GET_ASF(dev->base_addr)) {
- case ASF_PCB_ACK:
- adapter->send_pcb_semaphore = 0;
- return true;
-
- case ASF_PCB_NAK:
-#ifdef ELP_DEBUG
- pr_debug("%s: send_pcb got NAK\n", dev->name);
-#endif
- goto abort;
- }
- }
-
- if (elp_debug >= 1)
- pr_debug("%s: timeout waiting for PCB acknowledge (status %02x)\n",
- dev->name, inb_status(dev->base_addr));
- goto abort;
-
- sti_abort:
- spin_unlock_irqrestore(&adapter->lock, flags);
- abort:
- adapter->send_pcb_semaphore = 0;
- return false;
-}
-
-
-/*****************************************************************
- *
- * receive_pcb
- * Read a PCB from the adapter
- *
- * wait for ACRF to be non-zero ---<---+
- * input a byte |
- * if ASF1 and ASF2 were not both one |
- * before byte was read, loop --->---+
- * set HSF1 and HSF2 for ack
- *
- *****************************************************************/
-
-static bool receive_pcb(struct net_device *dev, pcb_struct * pcb)
-{
- int i, j;
- int total_length;
- int stat;
- unsigned long timeout;
- unsigned long flags;
-
- elp_device *adapter = netdev_priv(dev);
-
- set_hsf(dev, 0);
-
- /* get the command code */
- timeout = jiffies + 2*HZ/100;
- while (((stat = get_status(dev->base_addr)) & ACRF) == 0 && time_before(jiffies, timeout));
- if (time_after_eq(jiffies, timeout)) {
- TIMEOUT_MSG(__LINE__);
- return false;
- }
- pcb->command = inb_command(dev->base_addr);
-
- /* read the data length */
- timeout = jiffies + 3*HZ/100;
- while (((stat = get_status(dev->base_addr)) & ACRF) == 0 && time_before(jiffies, timeout));
- if (time_after_eq(jiffies, timeout)) {
- TIMEOUT_MSG(__LINE__);
- pr_info("%s: status %02x\n", dev->name, stat);
- return false;
- }
- pcb->length = inb_command(dev->base_addr);
-
- if (pcb->length > MAX_PCB_DATA) {
- INVALID_PCB_MSG(pcb->length);
- adapter_reset(dev);
- return false;
- }
- /* read the data */
- spin_lock_irqsave(&adapter->lock, flags);
- for (i = 0; i < MAX_PCB_DATA; i++) {
- for (j = 0; j < 20000; j++) {
- stat = get_status(dev->base_addr);
- if (stat & ACRF)
- break;
- }
- pcb->data.raw[i] = inb_command(dev->base_addr);
- if ((stat & ASF_PCB_MASK) == ASF_PCB_END || j >= 20000)
- break;
- }
- spin_unlock_irqrestore(&adapter->lock, flags);
- if (i >= MAX_PCB_DATA) {
- INVALID_PCB_MSG(i);
- return false;
- }
- if (j >= 20000) {
- TIMEOUT_MSG(__LINE__);
- return false;
- }
- /* the last "data" byte was really the length! */
- total_length = pcb->data.raw[i];
-
- /* safety check total length vs data length */
- if (total_length != (pcb->length + 2)) {
- if (elp_debug >= 2)
- pr_warning("%s: mangled PCB received\n", dev->name);
- set_hsf(dev, HSF_PCB_NAK);
- return false;
- }
-
- if (pcb->command == CMD_RECEIVE_PACKET_COMPLETE) {
- if (test_and_set_bit(0, (void *) &adapter->busy)) {
- if (backlog_next(adapter->rx_backlog.in) == adapter->rx_backlog.out) {
- set_hsf(dev, HSF_PCB_NAK);
- pr_warning("%s: PCB rejected, transfer in progress and backlog full\n", dev->name);
- pcb->command = 0;
- return true;
- } else {
- pcb->command = 0xff;
- }
- }
- }
- set_hsf(dev, HSF_PCB_ACK);
- return true;
-}
-
-/******************************************************
- *
- * queue a receive command on the adapter so we will get an
- * interrupt when a packet is received.
- *
- ******************************************************/
-
-static bool start_receive(struct net_device *dev, pcb_struct * tx_pcb)
-{
- bool status;
- elp_device *adapter = netdev_priv(dev);
-
- if (elp_debug >= 3)
- pr_debug("%s: restarting receiver\n", dev->name);
- tx_pcb->command = CMD_RECEIVE_PACKET;
- tx_pcb->length = sizeof(struct Rcv_pkt);
- tx_pcb->data.rcv_pkt.buf_seg
- = tx_pcb->data.rcv_pkt.buf_ofs = 0; /* Unused */
- tx_pcb->data.rcv_pkt.buf_len = 1600;
- tx_pcb->data.rcv_pkt.timeout = 0; /* set timeout to zero */
- status = send_pcb(dev, tx_pcb);
- if (status)
- adapter->rx_active++;
- return status;
-}
-
-/******************************************************
- *
- * extract a packet from the adapter
- * this routine is only called from within the interrupt
- * service routine, so no cli/sti calls are needed
- * note that the length is always assumed to be even
- *
- ******************************************************/
-
-static void receive_packet(struct net_device *dev, int len)
-{
- int rlen;
- elp_device *adapter = netdev_priv(dev);
- void *target;
- struct sk_buff *skb;
- unsigned long flags;
-
- rlen = (len + 1) & ~1;
- skb = dev_alloc_skb(rlen + 2);
-
- if (!skb) {
- pr_warning("%s: memory squeeze, dropping packet\n", dev->name);
- target = adapter->dma_buffer;
- adapter->current_dma.target = NULL;
- /* FIXME: stats */
- return;
- }
-
- skb_reserve(skb, 2);
- target = skb_put(skb, rlen);
- if ((unsigned long)(target + rlen) >= MAX_DMA_ADDRESS) {
- adapter->current_dma.target = target;
- target = adapter->dma_buffer;
- } else {
- adapter->current_dma.target = NULL;
- }
-
- /* if this happens, we die */
- if (test_and_set_bit(0, (void *) &adapter->dmaing))
- pr_err("%s: rx blocked, DMA in progress, dir %d\n",
- dev->name, adapter->current_dma.direction);
-
- adapter->current_dma.direction = 0;
- adapter->current_dma.length = rlen;
- adapter->current_dma.skb = skb;
- adapter->current_dma.start_time = jiffies;
-
- outb_control(adapter->hcr_val | DIR | TCEN | DMAE, dev);
-
- flags=claim_dma_lock();
- disable_dma(dev->dma);
- clear_dma_ff(dev->dma);
- set_dma_mode(dev->dma, 0x04); /* dma read */
- set_dma_addr(dev->dma, isa_virt_to_bus(target));
- set_dma_count(dev->dma, rlen);
- enable_dma(dev->dma);
- release_dma_lock(flags);
-
- if (elp_debug >= 3) {
- pr_debug("%s: rx DMA transfer started\n", dev->name);
- }
-
- if (adapter->rx_active)
- adapter->rx_active--;
-
- if (!adapter->busy)
- pr_warning("%s: receive_packet called, busy not set.\n", dev->name);
-}
-
-/******************************************************
- *
- * interrupt handler
- *
- ******************************************************/
-
-static irqreturn_t elp_interrupt(int irq, void *dev_id)
-{
- int len;
- int dlen;
- int icount = 0;
- struct net_device *dev = dev_id;
- elp_device *adapter = netdev_priv(dev);
- unsigned long timeout;
-
- spin_lock(&adapter->lock);
-
- do {
- /*
- * has a DMA transfer finished?
- */
- if (inb_status(dev->base_addr) & DONE) {
- if (!adapter->dmaing)
- pr_warning("%s: phantom DMA completed\n", dev->name);
-
- if (elp_debug >= 3)
- pr_debug("%s: %s DMA complete, status %02x\n", dev->name,
- adapter->current_dma.direction ? "tx" : "rx",
- inb_status(dev->base_addr));
-
- outb_control(adapter->hcr_val & ~(DMAE | TCEN | DIR), dev);
- if (adapter->current_dma.direction) {
- dev_kfree_skb_irq(adapter->current_dma.skb);
- } else {
- struct sk_buff *skb = adapter->current_dma.skb;
- if (skb) {
- if (adapter->current_dma.target) {
- /* have already done the skb_put() */
- memcpy(adapter->current_dma.target, adapter->dma_buffer, adapter->current_dma.length);
- }
- skb->protocol = eth_type_trans(skb,dev);
- dev->stats.rx_bytes += skb->len;
- netif_rx(skb);
- }
- }
- adapter->dmaing = 0;
- if (adapter->rx_backlog.in != adapter->rx_backlog.out) {
- int t = adapter->rx_backlog.length[adapter->rx_backlog.out];
- adapter->rx_backlog.out = backlog_next(adapter->rx_backlog.out);
- if (elp_debug >= 2)
- pr_debug("%s: receiving backlogged packet (%d)\n", dev->name, t);
- receive_packet(dev, t);
- } else {
- adapter->busy = 0;
- }
- } else {
- /* has one timed out? */
- check_3c505_dma(dev);
- }
-
- /*
- * receive a PCB from the adapter
- */
- timeout = jiffies + 3*HZ/100;
- while ((inb_status(dev->base_addr) & ACRF) != 0 && time_before(jiffies, timeout)) {
- if (receive_pcb(dev, &adapter->irx_pcb)) {
- switch (adapter->irx_pcb.command)
- {
- case 0:
- break;
- /*
- * received a packet - this must be handled fast
- */
- case 0xff:
- case CMD_RECEIVE_PACKET_COMPLETE:
- /* if the device isn't open, don't pass packets up the stack */
- if (!netif_running(dev))
- break;
- len = adapter->irx_pcb.data.rcv_resp.pkt_len;
- dlen = adapter->irx_pcb.data.rcv_resp.buf_len;
- if (adapter->irx_pcb.data.rcv_resp.timeout != 0) {
- pr_err("%s: interrupt - packet not received correctly\n", dev->name);
- } else {
- if (elp_debug >= 3) {
- pr_debug("%s: interrupt - packet received of length %i (%i)\n",
- dev->name, len, dlen);
- }
- if (adapter->irx_pcb.command == 0xff) {
- if (elp_debug >= 2)
- pr_debug("%s: adding packet to backlog (len = %d)\n",
- dev->name, dlen);
- adapter->rx_backlog.length[adapter->rx_backlog.in] = dlen;
- adapter->rx_backlog.in = backlog_next(adapter->rx_backlog.in);
- } else {
- receive_packet(dev, dlen);
- }
- if (elp_debug >= 3)
- pr_debug("%s: packet received\n", dev->name);
- }
- break;
-
- /*
- * 82586 configured correctly
- */
- case CMD_CONFIGURE_82586_RESPONSE:
- adapter->got[CMD_CONFIGURE_82586] = 1;
- if (elp_debug >= 3)
- pr_debug("%s: interrupt - configure response received\n", dev->name);
- break;
-
- /*
- * Adapter memory configuration
- */
- case CMD_CONFIGURE_ADAPTER_RESPONSE:
- adapter->got[CMD_CONFIGURE_ADAPTER_MEMORY] = 1;
- if (elp_debug >= 3)
- pr_debug("%s: Adapter memory configuration %s.\n", dev->name,
- adapter->irx_pcb.data.failed ? "failed" : "succeeded");
- break;
-
- /*
- * Multicast list loading
- */
- case CMD_LOAD_MULTICAST_RESPONSE:
- adapter->got[CMD_LOAD_MULTICAST_LIST] = 1;
- if (elp_debug >= 3)
- pr_debug("%s: Multicast address list loading %s.\n", dev->name,
- adapter->irx_pcb.data.failed ? "failed" : "succeeded");
- break;
-
- /*
- * Station address setting
- */
- case CMD_SET_ADDRESS_RESPONSE:
- adapter->got[CMD_SET_STATION_ADDRESS] = 1;
- if (elp_debug >= 3)
- pr_debug("%s: Ethernet address setting %s.\n", dev->name,
- adapter->irx_pcb.data.failed ? "failed" : "succeeded");
- break;
-
-
- /*
- * received board statistics
- */
- case CMD_NETWORK_STATISTICS_RESPONSE:
- dev->stats.rx_packets += adapter->irx_pcb.data.netstat.tot_recv;
- dev->stats.tx_packets += adapter->irx_pcb.data.netstat.tot_xmit;
- dev->stats.rx_crc_errors += adapter->irx_pcb.data.netstat.err_CRC;
- dev->stats.rx_frame_errors += adapter->irx_pcb.data.netstat.err_align;
- dev->stats.rx_fifo_errors += adapter->irx_pcb.data.netstat.err_ovrrun;
- dev->stats.rx_over_errors += adapter->irx_pcb.data.netstat.err_res;
- adapter->got[CMD_NETWORK_STATISTICS] = 1;
- if (elp_debug >= 3)
- pr_debug("%s: interrupt - statistics response received\n", dev->name);
- break;
-
- /*
- * sent a packet
- */
- case CMD_TRANSMIT_PACKET_COMPLETE:
- if (elp_debug >= 3)
- pr_debug("%s: interrupt - packet sent\n", dev->name);
- if (!netif_running(dev))
- break;
- switch (adapter->irx_pcb.data.xmit_resp.c_stat) {
- case 0xffff:
- dev->stats.tx_aborted_errors++;
- pr_info("%s: transmit timed out, network cable problem?\n", dev->name);
- break;
- case 0xfffe:
- dev->stats.tx_fifo_errors++;
- pr_info("%s: transmit timed out, FIFO underrun\n", dev->name);
- break;
- }
- netif_wake_queue(dev);
- break;
-
- /*
- * some unknown PCB
- */
- default:
- pr_debug("%s: unknown PCB received - %2.2x\n",
- dev->name, adapter->irx_pcb.command);
- break;
- }
- } else {
- pr_warning("%s: failed to read PCB on interrupt\n", dev->name);
- adapter_reset(dev);
- }
- }
-
- } while (icount++ < 5 && (inb_status(dev->base_addr) & (ACRF | DONE)));
-
- prime_rx(dev);
-
- /*
- * indicate no longer in interrupt routine
- */
- spin_unlock(&adapter->lock);
- return IRQ_HANDLED;
-}
-
-
-/******************************************************
- *
- * open the board
- *
- ******************************************************/
-
-static int elp_open(struct net_device *dev)
-{
- elp_device *adapter = netdev_priv(dev);
- int retval;
-
- if (elp_debug >= 3)
- pr_debug("%s: request to open device\n", dev->name);
-
- /*
- * make sure we actually found the device
- */
- if (adapter == NULL) {
- pr_err("%s: Opening a non-existent physical device\n", dev->name);
- return -EAGAIN;
- }
- /*
- * disable interrupts on the board
- */
- outb_control(0, dev);
-
- /*
- * clear any pending interrupts
- */
- inb_command(dev->base_addr);
- adapter_reset(dev);
-
- /*
- * no receive PCBs active
- */
- adapter->rx_active = 0;
-
- adapter->busy = 0;
- adapter->send_pcb_semaphore = 0;
- adapter->rx_backlog.in = 0;
- adapter->rx_backlog.out = 0;
-
- spin_lock_init(&adapter->lock);
-
- /*
- * install our interrupt service routine
- */
- if ((retval = request_irq(dev->irq, elp_interrupt, 0, dev->name, dev))) {
- pr_err("%s: could not allocate IRQ%d\n", dev->name, dev->irq);
- return retval;
- }
- if ((retval = request_dma(dev->dma, dev->name))) {
- free_irq(dev->irq, dev);
- pr_err("%s: could not allocate DMA%d channel\n", dev->name, dev->dma);
- return retval;
- }
- adapter->dma_buffer = (void *) dma_mem_alloc(DMA_BUFFER_SIZE);
- if (!adapter->dma_buffer) {
- pr_err("%s: could not allocate DMA buffer\n", dev->name);
- free_dma(dev->dma);
- free_irq(dev->irq, dev);
- return -ENOMEM;
- }
- adapter->dmaing = 0;
-
- /*
- * enable interrupts on the board
- */
- outb_control(CMDE, dev);
-
- /*
- * configure adapter memory: we need 10 multicast addresses, default==0
- */
- if (elp_debug >= 3)
- pr_debug("%s: sending 3c505 memory configuration command\n", dev->name);
- adapter->tx_pcb.command = CMD_CONFIGURE_ADAPTER_MEMORY;
- adapter->tx_pcb.data.memconf.cmd_q = 10;
- adapter->tx_pcb.data.memconf.rcv_q = 20;
- adapter->tx_pcb.data.memconf.mcast = 10;
- adapter->tx_pcb.data.memconf.frame = 20;
- adapter->tx_pcb.data.memconf.rcv_b = 20;
- adapter->tx_pcb.data.memconf.progs = 0;
- adapter->tx_pcb.length = sizeof(struct Memconf);
- adapter->got[CMD_CONFIGURE_ADAPTER_MEMORY] = 0;
- if (!send_pcb(dev, &adapter->tx_pcb))
- pr_err("%s: couldn't send memory configuration command\n", dev->name);
- else {
- unsigned long timeout = jiffies + TIMEOUT;
- while (adapter->got[CMD_CONFIGURE_ADAPTER_MEMORY] == 0 && time_before(jiffies, timeout));
- if (time_after_eq(jiffies, timeout))
- TIMEOUT_MSG(__LINE__);
- }
-
-
- /*
- * configure adapter to receive broadcast messages and wait for response
- */
- if (elp_debug >= 3)
- pr_debug("%s: sending 82586 configure command\n", dev->name);
- adapter->tx_pcb.command = CMD_CONFIGURE_82586;
- adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_BROAD;
- adapter->tx_pcb.length = 2;
- adapter->got[CMD_CONFIGURE_82586] = 0;
- if (!send_pcb(dev, &adapter->tx_pcb))
- pr_err("%s: couldn't send 82586 configure command\n", dev->name);
- else {
- unsigned long timeout = jiffies + TIMEOUT;
- while (adapter->got[CMD_CONFIGURE_82586] == 0 && time_before(jiffies, timeout));
- if (time_after_eq(jiffies, timeout))
- TIMEOUT_MSG(__LINE__);
- }
-
- /* enable burst-mode DMA */
- /* outb(0x1, dev->base_addr + PORT_AUXDMA); */
-
- /*
- * queue receive commands to provide buffering
- */
- prime_rx(dev);
- if (elp_debug >= 3)
- pr_debug("%s: %d receive PCBs active\n", dev->name, adapter->rx_active);
-
- /*
- * device is now officially open!
- */
-
- netif_start_queue(dev);
- return 0;
-}
-
-
-/******************************************************
- *
- * send a packet to the adapter
- *
- ******************************************************/
-
-static netdev_tx_t send_packet(struct net_device *dev, struct sk_buff *skb)
-{
- elp_device *adapter = netdev_priv(dev);
- unsigned long target;
- unsigned long flags;
-
- /*
- * make sure the length is even and no shorter than 60 bytes
- */
- unsigned int nlen = (((skb->len < 60) ? 60 : skb->len) + 1) & (~1);
-
- if (test_and_set_bit(0, (void *) &adapter->busy)) {
- if (elp_debug >= 2)
- pr_debug("%s: transmit blocked\n", dev->name);
- return false;
- }
-
- dev->stats.tx_bytes += nlen;
-
- /*
- * send the adapter a transmit packet command. Ignore segment and offset
- * and make sure the length is even
- */
- adapter->tx_pcb.command = CMD_TRANSMIT_PACKET;
- adapter->tx_pcb.length = sizeof(struct Xmit_pkt);
- adapter->tx_pcb.data.xmit_pkt.buf_ofs
- = adapter->tx_pcb.data.xmit_pkt.buf_seg = 0; /* Unused */
- adapter->tx_pcb.data.xmit_pkt.pkt_len = nlen;
-
- if (!send_pcb(dev, &adapter->tx_pcb)) {
- adapter->busy = 0;
- return false;
- }
- /* if this happens, we die */
- if (test_and_set_bit(0, (void *) &adapter->dmaing))
- pr_debug("%s: tx: DMA %d in progress\n", dev->name, adapter->current_dma.direction);
-
- adapter->current_dma.direction = 1;
- adapter->current_dma.start_time = jiffies;
-
- if ((unsigned long)(skb->data + nlen) >= MAX_DMA_ADDRESS || nlen != skb->len) {
- skb_copy_from_linear_data(skb, adapter->dma_buffer, nlen);
- memset(adapter->dma_buffer+skb->len, 0, nlen-skb->len);
- target = isa_virt_to_bus(adapter->dma_buffer);
- }
- else {
- target = isa_virt_to_bus(skb->data);
- }
- adapter->current_dma.skb = skb;
-
- flags=claim_dma_lock();
- disable_dma(dev->dma);
- clear_dma_ff(dev->dma);
- set_dma_mode(dev->dma, 0x48); /* dma memory -> io */
- set_dma_addr(dev->dma, target);
- set_dma_count(dev->dma, nlen);
- outb_control(adapter->hcr_val | DMAE | TCEN, dev);
- enable_dma(dev->dma);
- release_dma_lock(flags);
-
- if (elp_debug >= 3)
- pr_debug("%s: DMA transfer started\n", dev->name);
-
- return true;
-}
-
-/*
- * The upper layer thinks we timed out
- */
-
-static void elp_timeout(struct net_device *dev)
-{
- int stat;
-
- stat = inb_status(dev->base_addr);
- pr_warning("%s: transmit timed out, lost %s?\n", dev->name,
- (stat & ACRF) ? "interrupt" : "command");
- if (elp_debug >= 1)
- pr_debug("%s: status %#02x\n", dev->name, stat);
- dev->trans_start = jiffies; /* prevent tx timeout */
- dev->stats.tx_dropped++;
- netif_wake_queue(dev);
-}
-
-/******************************************************
- *
- * start the transmitter
- * return 0 if sent OK, else return 1
- *
- ******************************************************/
-
-static netdev_tx_t elp_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- unsigned long flags;
- elp_device *adapter = netdev_priv(dev);
-
- spin_lock_irqsave(&adapter->lock, flags);
- check_3c505_dma(dev);
-
- if (elp_debug >= 3)
- pr_debug("%s: request to send packet of length %d\n", dev->name, (int) skb->len);
-
- netif_stop_queue(dev);
-
- /*
- * send the packet at skb->data for skb->len
- */
- if (!send_packet(dev, skb)) {
- if (elp_debug >= 2) {
- pr_debug("%s: failed to transmit packet\n", dev->name);
- }
- spin_unlock_irqrestore(&adapter->lock, flags);
- return NETDEV_TX_BUSY;
- }
- if (elp_debug >= 3)
- pr_debug("%s: packet of length %d sent\n", dev->name, (int) skb->len);
-
- prime_rx(dev);
- spin_unlock_irqrestore(&adapter->lock, flags);
- netif_start_queue(dev);
- return NETDEV_TX_OK;
-}
-
-/******************************************************
- *
- * return statistics on the board
- *
- ******************************************************/
-
-static struct net_device_stats *elp_get_stats(struct net_device *dev)
-{
- elp_device *adapter = netdev_priv(dev);
-
- if (elp_debug >= 3)
- pr_debug("%s: request for stats\n", dev->name);
-
- /* If the device is closed, just return the latest stats we have,
- - we cannot ask from the adapter without interrupts */
- if (!netif_running(dev))
- return &dev->stats;
-
- /* send a get statistics command to the board */
- adapter->tx_pcb.command = CMD_NETWORK_STATISTICS;
- adapter->tx_pcb.length = 0;
- adapter->got[CMD_NETWORK_STATISTICS] = 0;
- if (!send_pcb(dev, &adapter->tx_pcb))
- pr_err("%s: couldn't send get statistics command\n", dev->name);
- else {
- unsigned long timeout = jiffies + TIMEOUT;
- while (adapter->got[CMD_NETWORK_STATISTICS] == 0 && time_before(jiffies, timeout));
- if (time_after_eq(jiffies, timeout)) {
- TIMEOUT_MSG(__LINE__);
- return &dev->stats;
- }
- }
-
- /* statistics are now up to date */
- return &dev->stats;
-}
-
-
-static void netdev_get_drvinfo(struct net_device *dev,
- struct ethtool_drvinfo *info)
-{
- strcpy(info->driver, DRV_NAME);
- strcpy(info->version, DRV_VERSION);
- sprintf(info->bus_info, "ISA 0x%lx", dev->base_addr);
-}
-
-static u32 netdev_get_msglevel(struct net_device *dev)
-{
- return debug;
-}
-
-static void netdev_set_msglevel(struct net_device *dev, u32 level)
-{
- debug = level;
-}
-
-static const struct ethtool_ops netdev_ethtool_ops = {
- .get_drvinfo = netdev_get_drvinfo,
- .get_msglevel = netdev_get_msglevel,
- .set_msglevel = netdev_set_msglevel,
-};
-
-/******************************************************
- *
- * close the board
- *
- ******************************************************/
-
-static int elp_close(struct net_device *dev)
-{
- elp_device *adapter = netdev_priv(dev);
-
- if (elp_debug >= 3)
- pr_debug("%s: request to close device\n", dev->name);
-
- netif_stop_queue(dev);
-
- /* Someone may request the device statistic information even when
- * the interface is closed. The following will update the statistics
- * structure in the driver, so we'll be able to give current statistics.
- */
- (void) elp_get_stats(dev);
-
- /*
- * disable interrupts on the board
- */
- outb_control(0, dev);
-
- /*
- * release the IRQ
- */
- free_irq(dev->irq, dev);
-
- free_dma(dev->dma);
- free_pages((unsigned long) adapter->dma_buffer, get_order(DMA_BUFFER_SIZE));
-
- return 0;
-}
-
-
-/************************************************************
- *
- * Set multicast list
- * num_addrs==0: clear mc_list
- * num_addrs==-1: set promiscuous mode
- * num_addrs>0: set mc_list
- *
- ************************************************************/
-
-static void elp_set_mc_list(struct net_device *dev)
-{
- elp_device *adapter = netdev_priv(dev);
- struct netdev_hw_addr *ha;
- int i;
- unsigned long flags;
-
- if (elp_debug >= 3)
- pr_debug("%s: request to set multicast list\n", dev->name);
-
- spin_lock_irqsave(&adapter->lock, flags);
-
- if (!(dev->flags & (IFF_PROMISC | IFF_ALLMULTI))) {
- /* send a "load multicast list" command to the board, max 10 addrs/cmd */
- /* if num_addrs==0 the list will be cleared */
- adapter->tx_pcb.command = CMD_LOAD_MULTICAST_LIST;
- adapter->tx_pcb.length = 6 * netdev_mc_count(dev);
- i = 0;
- netdev_for_each_mc_addr(ha, dev)
- memcpy(adapter->tx_pcb.data.multicast[i++],
- ha->addr, 6);
- adapter->got[CMD_LOAD_MULTICAST_LIST] = 0;
- if (!send_pcb(dev, &adapter->tx_pcb))
- pr_err("%s: couldn't send set_multicast command\n", dev->name);
- else {
- unsigned long timeout = jiffies + TIMEOUT;
- while (adapter->got[CMD_LOAD_MULTICAST_LIST] == 0 && time_before(jiffies, timeout));
- if (time_after_eq(jiffies, timeout)) {
- TIMEOUT_MSG(__LINE__);
- }
- }
- if (!netdev_mc_empty(dev))
- adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_BROAD | RECV_MULTI;
- else /* num_addrs == 0 */
- adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_BROAD;
- } else
- adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_PROMISC;
- /*
- * configure adapter to receive messages (as specified above)
- * and wait for response
- */
- if (elp_debug >= 3)
- pr_debug("%s: sending 82586 configure command\n", dev->name);
- adapter->tx_pcb.command = CMD_CONFIGURE_82586;
- adapter->tx_pcb.length = 2;
- adapter->got[CMD_CONFIGURE_82586] = 0;
- if (!send_pcb(dev, &adapter->tx_pcb))
- {
- spin_unlock_irqrestore(&adapter->lock, flags);
- pr_err("%s: couldn't send 82586 configure command\n", dev->name);
- }
- else {
- unsigned long timeout = jiffies + TIMEOUT;
- spin_unlock_irqrestore(&adapter->lock, flags);
- while (adapter->got[CMD_CONFIGURE_82586] == 0 && time_before(jiffies, timeout));
- if (time_after_eq(jiffies, timeout))
- TIMEOUT_MSG(__LINE__);
- }
-}
-
-/************************************************************
- *
- * A couple of tests to see if there's 3C505 or not
- * Called only by elp_autodetect
- ************************************************************/
-
-static int __init elp_sense(struct net_device *dev)
-{
- int addr = dev->base_addr;
- const char *name = dev->name;
- byte orig_HSR;
-
- if (!request_region(addr, ELP_IO_EXTENT, "3c505"))
- return -ENODEV;
-
- orig_HSR = inb_status(addr);
-
- if (elp_debug > 0)
- pr_debug(search_msg, name, addr);
-
- if (orig_HSR == 0xff) {
- if (elp_debug > 0)
- pr_cont(notfound_msg, 1);
- goto out;
- }
-
- /* Wait for a while; the adapter may still be booting up */
- if (elp_debug > 0)
- pr_cont(stilllooking_msg);
-
- if (orig_HSR & DIR) {
- /* If HCR.DIR is up, we pull it down. HSR.DIR should follow. */
- outb(0, dev->base_addr + PORT_CONTROL);
- msleep(300);
- if (inb_status(addr) & DIR) {
- if (elp_debug > 0)
- pr_cont(notfound_msg, 2);
- goto out;
- }
- } else {
- /* If HCR.DIR is down, we pull it up. HSR.DIR should follow. */
- outb(DIR, dev->base_addr + PORT_CONTROL);
- msleep(300);
- if (!(inb_status(addr) & DIR)) {
- if (elp_debug > 0)
- pr_cont(notfound_msg, 3);
- goto out;
- }
- }
- /*
- * It certainly looks like a 3c505.
- */
- if (elp_debug > 0)
- pr_cont(found_msg);
-
- return 0;
-out:
- release_region(addr, ELP_IO_EXTENT);
- return -ENODEV;
-}
-
-/*************************************************************
- *
- * Search through addr_list[] and try to find a 3C505
- * Called only by eplus_probe
- *************************************************************/
-
-static int __init elp_autodetect(struct net_device *dev)
-{
- int idx = 0;
-
- /* if base address set, then only check that address
- otherwise, run through the table */
- if (dev->base_addr != 0) { /* dev->base_addr == 0 ==> plain autodetect */
- if (elp_sense(dev) == 0)
- return dev->base_addr;
- } else
- while ((dev->base_addr = addr_list[idx++])) {
- if (elp_sense(dev) == 0)
- return dev->base_addr;
- }
-
- /* could not find an adapter */
- if (elp_debug > 0)
- pr_debug(couldnot_msg, dev->name);
-
- return 0; /* Because of this, the layer above will return -ENODEV */
-}
-
-static const struct net_device_ops elp_netdev_ops = {
- .ndo_open = elp_open,
- .ndo_stop = elp_close,
- .ndo_get_stats = elp_get_stats,
- .ndo_start_xmit = elp_start_xmit,
- .ndo_tx_timeout = elp_timeout,
- .ndo_set_multicast_list = elp_set_mc_list,
- .ndo_change_mtu = eth_change_mtu,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-/******************************************************
- *
- * probe for an Etherlink Plus board at the specified address
- *
- ******************************************************/
-
-/* There are three situations we need to be able to detect here:
-
- * a) the card is idle
- * b) the card is still booting up
- * c) the card is stuck in a strange state (some DOS drivers do this)
- *
- * In case (a), all is well. In case (b), we wait 10 seconds to see if the
- * card finishes booting, and carry on if so. In case (c), we do a hard reset,
- * loop round, and hope for the best.
- *
- * This is all very unpleasant, but hopefully avoids the problems with the old
- * probe code (which had a 15-second delay if the card was idle, and didn't
- * work at all if it was in a weird state).
- */
-
-static int __init elplus_setup(struct net_device *dev)
-{
- elp_device *adapter = netdev_priv(dev);
- int i, tries, tries1, okay;
- unsigned long timeout;
- unsigned long cookie = 0;
- int err = -ENODEV;
-
- /*
- * setup adapter structure
- */
-
- dev->base_addr = elp_autodetect(dev);
- if (!dev->base_addr)
- return -ENODEV;
-
- adapter->send_pcb_semaphore = 0;
-
- for (tries1 = 0; tries1 < 3; tries1++) {
- outb_control((adapter->hcr_val | CMDE) & ~DIR, dev);
- /* First try to write just one byte, to see if the card is
- * responding at all normally.
- */
- timeout = jiffies + 5*HZ/100;
- okay = 0;
- while (time_before(jiffies, timeout) && !(inb_status(dev->base_addr) & HCRE));
- if ((inb_status(dev->base_addr) & HCRE)) {
- outb_command(0, dev->base_addr); /* send a spurious byte */
- timeout = jiffies + 5*HZ/100;
- while (time_before(jiffies, timeout) && !(inb_status(dev->base_addr) & HCRE));
- if (inb_status(dev->base_addr) & HCRE)
- okay = 1;
- }
- if (!okay) {
- /* Nope, it's ignoring the command register. This means that
- * either it's still booting up, or it's died.
- */
- pr_err("%s: command register wouldn't drain, ", dev->name);
- if ((inb_status(dev->base_addr) & 7) == 3) {
- /* If the adapter status is 3, it *could* still be booting.
- * Give it the benefit of the doubt for 10 seconds.
- */
- pr_cont("assuming 3c505 still starting\n");
- timeout = jiffies + 10*HZ;
- while (time_before(jiffies, timeout) && (inb_status(dev->base_addr) & 7));
- if (inb_status(dev->base_addr) & 7) {
- pr_err("%s: 3c505 failed to start\n", dev->name);
- } else {
- okay = 1; /* It started */
- }
- } else {
- /* Otherwise, it must just be in a strange
- * state. We probably need to kick it.
- */
- pr_cont("3c505 is sulking\n");
- }
- }
- for (tries = 0; tries < 5 && okay; tries++) {
-
- /*
- * Try to set the Ethernet address, to make sure that the board
- * is working.
- */
- adapter->tx_pcb.command = CMD_STATION_ADDRESS;
- adapter->tx_pcb.length = 0;
- cookie = probe_irq_on();
- if (!send_pcb(dev, &adapter->tx_pcb)) {
- pr_err("%s: could not send first PCB\n", dev->name);
- probe_irq_off(cookie);
- continue;
- }
- if (!receive_pcb(dev, &adapter->rx_pcb)) {
- pr_err("%s: could not read first PCB\n", dev->name);
- probe_irq_off(cookie);
- continue;
- }
- if ((adapter->rx_pcb.command != CMD_ADDRESS_RESPONSE) ||
- (adapter->rx_pcb.length != 6)) {
- pr_err("%s: first PCB wrong (%d, %d)\n", dev->name,
- adapter->rx_pcb.command, adapter->rx_pcb.length);
- probe_irq_off(cookie);
- continue;
- }
- goto okay;
- }
- /* It's broken. Do a hard reset to re-initialise the board,
- * and try again.
- */
- pr_info("%s: resetting adapter\n", dev->name);
- outb_control(adapter->hcr_val | FLSH | ATTN, dev);
- outb_control(adapter->hcr_val & ~(FLSH | ATTN), dev);
- }
- pr_err("%s: failed to initialise 3c505\n", dev->name);
- goto out;
-
- okay:
- if (dev->irq) { /* Is there a preset IRQ? */
- int rpt = probe_irq_off(cookie);
- if (dev->irq != rpt) {
- pr_warning("%s: warning, irq %d configured but %d detected\n", dev->name, dev->irq, rpt);
- }
- /* if dev->irq == probe_irq_off(cookie), all is well */
- } else /* No preset IRQ; just use what we can detect */
- dev->irq = probe_irq_off(cookie);
- switch (dev->irq) { /* Legal, sane? */
- case 0:
- pr_err("%s: IRQ probe failed: check 3c505 jumpers.\n",
- dev->name);
- goto out;
- case 1:
- case 6:
- case 8:
- case 13:
- pr_err("%s: Impossible IRQ %d reported by probe_irq_off().\n",
- dev->name, dev->irq);
- goto out;
- }
- /*
- * Now we have the IRQ number so we can disable the interrupts from
- * the board until the board is opened.
- */
- outb_control(adapter->hcr_val & ~CMDE, dev);
-
- /*
- * copy Ethernet address into structure
- */
- for (i = 0; i < 6; i++)
- dev->dev_addr[i] = adapter->rx_pcb.data.eth_addr[i];
-
- /* find a DMA channel */
- if (!dev->dma) {
- if (dev->mem_start) {
- dev->dma = dev->mem_start & 7;
- }
- else {
- pr_warning("%s: warning, DMA channel not specified, using default\n", dev->name);
- dev->dma = ELP_DMA;
- }
- }
-
- /*
- * print remainder of startup message
- */
- pr_info("%s: 3c505 at %#lx, irq %d, dma %d, addr %pM, ",
- dev->name, dev->base_addr, dev->irq, dev->dma, dev->dev_addr);
- /*
- * read more information from the adapter
- */
-
- adapter->tx_pcb.command = CMD_ADAPTER_INFO;
- adapter->tx_pcb.length = 0;
- if (!send_pcb(dev, &adapter->tx_pcb) ||
- !receive_pcb(dev, &adapter->rx_pcb) ||
- (adapter->rx_pcb.command != CMD_ADAPTER_INFO_RESPONSE) ||
- (adapter->rx_pcb.length != 10)) {
- pr_cont("not responding to second PCB\n");
- }
- pr_cont("rev %d.%d, %dk\n", adapter->rx_pcb.data.info.major_vers,
- adapter->rx_pcb.data.info.minor_vers, adapter->rx_pcb.data.info.RAM_sz);
-
- /*
- * reconfigure the adapter memory to better suit our purposes
- */
- adapter->tx_pcb.command = CMD_CONFIGURE_ADAPTER_MEMORY;
- adapter->tx_pcb.length = 12;
- adapter->tx_pcb.data.memconf.cmd_q = 8;
- adapter->tx_pcb.data.memconf.rcv_q = 8;
- adapter->tx_pcb.data.memconf.mcast = 10;
- adapter->tx_pcb.data.memconf.frame = 10;
- adapter->tx_pcb.data.memconf.rcv_b = 10;
- adapter->tx_pcb.data.memconf.progs = 0;
- if (!send_pcb(dev, &adapter->tx_pcb) ||
- !receive_pcb(dev, &adapter->rx_pcb) ||
- (adapter->rx_pcb.command != CMD_CONFIGURE_ADAPTER_RESPONSE) ||
- (adapter->rx_pcb.length != 2)) {
- pr_err("%s: could not configure adapter memory\n", dev->name);
- }
- if (adapter->rx_pcb.data.configure) {
- pr_err("%s: adapter configuration failed\n", dev->name);
- }
-
- dev->netdev_ops = &elp_netdev_ops;
- dev->watchdog_timeo = 10*HZ;
- dev->ethtool_ops = &netdev_ethtool_ops; /* local */
-
- dev->mem_start = dev->mem_end = 0;
-
- err = register_netdev(dev);
- if (err)
- goto out;
-
- return 0;
-out:
- release_region(dev->base_addr, ELP_IO_EXTENT);
- return err;
-}
-
-#ifndef MODULE
-struct net_device * __init elplus_probe(int unit)
-{
- struct net_device *dev = alloc_etherdev(sizeof(elp_device));
- int err;
- if (!dev)
- return ERR_PTR(-ENOMEM);
-
- sprintf(dev->name, "eth%d", unit);
- netdev_boot_setup_check(dev);
-
- err = elplus_setup(dev);
- if (err) {
- free_netdev(dev);
- return ERR_PTR(err);
- }
- return dev;
-}
-
-#else
-static struct net_device *dev_3c505[ELP_MAX_CARDS];
-static int io[ELP_MAX_CARDS];
-static int irq[ELP_MAX_CARDS];
-static int dma[ELP_MAX_CARDS];
-module_param_array(io, int, NULL, 0);
-module_param_array(irq, int, NULL, 0);
-module_param_array(dma, int, NULL, 0);
-MODULE_PARM_DESC(io, "EtherLink Plus I/O base address(es)");
-MODULE_PARM_DESC(irq, "EtherLink Plus IRQ number(s) (assigned)");
-MODULE_PARM_DESC(dma, "EtherLink Plus DMA channel(s)");
-
-int __init init_module(void)
-{
- int this_dev, found = 0;
-
- for (this_dev = 0; this_dev < ELP_MAX_CARDS; this_dev++) {
- struct net_device *dev = alloc_etherdev(sizeof(elp_device));
- if (!dev)
- break;
-
- dev->irq = irq[this_dev];
- dev->base_addr = io[this_dev];
- if (dma[this_dev]) {
- dev->dma = dma[this_dev];
- } else {
- dev->dma = ELP_DMA;
- pr_warning("3c505.c: warning, using default DMA channel,\n");
- }
- if (io[this_dev] == 0) {
- if (this_dev) {
- free_netdev(dev);
- break;
- }
- pr_notice("3c505.c: module autoprobe not recommended, give io=xx.\n");
- }
- if (elplus_setup(dev) != 0) {
- pr_warning("3c505.c: Failed to register card at 0x%x.\n", io[this_dev]);
- free_netdev(dev);
- break;
- }
- dev_3c505[this_dev] = dev;
- found++;
- }
- if (!found)
- return -ENODEV;
- return 0;
-}
-
-void __exit cleanup_module(void)
-{
- int this_dev;
-
- for (this_dev = 0; this_dev < ELP_MAX_CARDS; this_dev++) {
- struct net_device *dev = dev_3c505[this_dev];
- if (dev) {
- unregister_netdev(dev);
- release_region(dev->base_addr, ELP_IO_EXTENT);
- free_netdev(dev);
- }
- }
-}
-
-#endif /* MODULE */
-MODULE_LICENSE("GPL");
+++ /dev/null
-/*****************************************************************
- *
- * defines for 3Com Etherlink Plus adapter
- *
- *****************************************************************/
-
-#define ELP_DMA 6
-#define ELP_RX_PCBS 4
-#define ELP_MAX_CARDS 4
-
-/*
- * I/O register offsets
- */
-#define PORT_COMMAND 0x00 /* read/write, 8-bit */
-#define PORT_STATUS 0x02 /* read only, 8-bit */
-#define PORT_AUXDMA 0x02 /* write only, 8-bit */
-#define PORT_DATA 0x04 /* read/write, 16-bit */
-#define PORT_CONTROL 0x06 /* read/write, 8-bit */
-
-#define ELP_IO_EXTENT 0x10 /* size of used IO registers */
-
-/*
- * host control registers bits
- */
-#define ATTN 0x80 /* attention */
-#define FLSH 0x40 /* flush data register */
-#define DMAE 0x20 /* DMA enable */
-#define DIR 0x10 /* direction */
-#define TCEN 0x08 /* terminal count interrupt enable */
-#define CMDE 0x04 /* command register interrupt enable */
-#define HSF2 0x02 /* host status flag 2 */
-#define HSF1 0x01 /* host status flag 1 */
-
-/*
- * combinations of HSF flags used for PCB transmission
- */
-#define HSF_PCB_ACK HSF1
-#define HSF_PCB_NAK HSF2
-#define HSF_PCB_END (HSF2|HSF1)
-#define HSF_PCB_MASK (HSF2|HSF1)
-
-/*
- * host status register bits
- */
-#define HRDY 0x80 /* data register ready */
-#define HCRE 0x40 /* command register empty */
-#define ACRF 0x20 /* adapter command register full */
-/* #define DIR 0x10 direction - same as in control register */
-#define DONE 0x08 /* DMA done */
-#define ASF3 0x04 /* adapter status flag 3 */
-#define ASF2 0x02 /* adapter status flag 2 */
-#define ASF1 0x01 /* adapter status flag 1 */
-
-/*
- * combinations of ASF flags used for PCB reception
- */
-#define ASF_PCB_ACK ASF1
-#define ASF_PCB_NAK ASF2
-#define ASF_PCB_END (ASF2|ASF1)
-#define ASF_PCB_MASK (ASF2|ASF1)
-
-/*
- * host aux DMA register bits
- */
-#define DMA_BRST 0x01 /* DMA burst */
-
-/*
- * maximum amount of data allowed in a PCB
- */
-#define MAX_PCB_DATA 62
-
-/*****************************************************************
- *
- * timeout value
- * this is a rough value used for loops to stop them from
- * locking up the whole machine in the case of failure or
- * error conditions
- *
- *****************************************************************/
-
-#define TIMEOUT 300
-
-/*****************************************************************
- *
- * PCB commands
- *
- *****************************************************************/
-
-enum {
- /*
- * host PCB commands
- */
- CMD_CONFIGURE_ADAPTER_MEMORY = 0x01,
- CMD_CONFIGURE_82586 = 0x02,
- CMD_STATION_ADDRESS = 0x03,
- CMD_DMA_DOWNLOAD = 0x04,
- CMD_DMA_UPLOAD = 0x05,
- CMD_PIO_DOWNLOAD = 0x06,
- CMD_PIO_UPLOAD = 0x07,
- CMD_RECEIVE_PACKET = 0x08,
- CMD_TRANSMIT_PACKET = 0x09,
- CMD_NETWORK_STATISTICS = 0x0a,
- CMD_LOAD_MULTICAST_LIST = 0x0b,
- CMD_CLEAR_PROGRAM = 0x0c,
- CMD_DOWNLOAD_PROGRAM = 0x0d,
- CMD_EXECUTE_PROGRAM = 0x0e,
- CMD_SELF_TEST = 0x0f,
- CMD_SET_STATION_ADDRESS = 0x10,
- CMD_ADAPTER_INFO = 0x11,
- NUM_TRANSMIT_CMDS,
-
- /*
- * adapter PCB commands
- */
- CMD_CONFIGURE_ADAPTER_RESPONSE = 0x31,
- CMD_CONFIGURE_82586_RESPONSE = 0x32,
- CMD_ADDRESS_RESPONSE = 0x33,
- CMD_DOWNLOAD_DATA_REQUEST = 0x34,
- CMD_UPLOAD_DATA_REQUEST = 0x35,
- CMD_RECEIVE_PACKET_COMPLETE = 0x38,
- CMD_TRANSMIT_PACKET_COMPLETE = 0x39,
- CMD_NETWORK_STATISTICS_RESPONSE = 0x3a,
- CMD_LOAD_MULTICAST_RESPONSE = 0x3b,
- CMD_CLEAR_PROGRAM_RESPONSE = 0x3c,
- CMD_DOWNLOAD_PROGRAM_RESPONSE = 0x3d,
- CMD_EXECUTE_RESPONSE = 0x3e,
- CMD_SELF_TEST_RESPONSE = 0x3f,
- CMD_SET_ADDRESS_RESPONSE = 0x40,
- CMD_ADAPTER_INFO_RESPONSE = 0x41
-};
-
-/* Definitions for the PCB data structure */
-
-/* Data units */
-typedef unsigned char byte;
-typedef unsigned short int word;
-typedef unsigned long int dword;
-
-/* Data structures */
-struct Memconf {
- word cmd_q,
- rcv_q,
- mcast,
- frame,
- rcv_b,
- progs;
-};
-
-struct Rcv_pkt {
- word buf_ofs,
- buf_seg,
- buf_len,
- timeout;
-};
-
-struct Xmit_pkt {
- word buf_ofs,
- buf_seg,
- pkt_len;
-};
-
-struct Rcv_resp {
- word buf_ofs,
- buf_seg,
- buf_len,
- pkt_len,
- timeout,
- status;
- dword timetag;
-};
-
-struct Xmit_resp {
- word buf_ofs,
- buf_seg,
- c_stat,
- status;
-};
-
-
-struct Netstat {
- dword tot_recv,
- tot_xmit;
- word err_CRC,
- err_align,
- err_res,
- err_ovrrun;
-};
-
-
-struct Selftest {
- word error;
- union {
- word ROM_cksum;
- struct {
- word ofs, seg;
- } RAM;
- word i82586;
- } failure;
-};
-
-struct Info {
- byte minor_vers,
- major_vers;
- word ROM_cksum,
- RAM_sz,
- free_ofs,
- free_seg;
-};
-
-struct Memdump {
- word size,
- off,
- seg;
-};
-
-/*
-Primary Command Block. The most important data structure. All communication
-between the host and the adapter is done with these. (Except for the actual
-Ethernet data, which has different packaging.)
-*/
-typedef struct {
- byte command;
- byte length;
- union {
- struct Memconf memconf;
- word configure;
- struct Rcv_pkt rcv_pkt;
- struct Xmit_pkt xmit_pkt;
- byte multicast[10][6];
- byte eth_addr[6];
- byte failed;
- struct Rcv_resp rcv_resp;
- struct Xmit_resp xmit_resp;
- struct Netstat netstat;
- struct Selftest selftest;
- struct Info info;
- struct Memdump memdump;
- byte raw[62];
- } data;
-} pcb_struct;
-
-/* These defines for 'configure' */
-#define RECV_STATION 0x00
-#define RECV_BROAD 0x01
-#define RECV_MULTI 0x02
-#define RECV_PROMISC 0x04
-#define NO_LOOPBACK 0x00
-#define INT_LOOPBACK 0x08
-#define EXT_LOOPBACK 0x10
-
-/*****************************************************************
- *
- * structure to hold context information for adapter
- *
- *****************************************************************/
-
-#define DMA_BUFFER_SIZE 1600
-#define BACKLOG_SIZE 4
-
-typedef struct {
- volatile short got[NUM_TRANSMIT_CMDS]; /* flags for
- command completion */
- pcb_struct tx_pcb; /* PCB for foreground sending */
- pcb_struct rx_pcb; /* PCB for foreground receiving */
- pcb_struct itx_pcb; /* PCB for background sending */
- pcb_struct irx_pcb; /* PCB for background receiving */
-
- void *dma_buffer;
-
- struct {
- unsigned int length[BACKLOG_SIZE];
- unsigned int in;
- unsigned int out;
- } rx_backlog;
-
- struct {
- unsigned int direction;
- unsigned int length;
- struct sk_buff *skb;
- void *target;
- unsigned long start_time;
- } current_dma;
-
- /* flags */
- unsigned long send_pcb_semaphore;
- unsigned long dmaing;
- unsigned long busy;
-
- unsigned int rx_active; /* number of receive PCBs */
- volatile unsigned char hcr_val; /* what we think the HCR contains */
- spinlock_t lock; /* Interrupt v tx lock */
-} elp_device;
+++ /dev/null
-/* 3c507.c: An EtherLink16 device driver for Linux. */
-/*
- Written 1993,1994 by Donald Becker.
-
- Copyright 1993 United States Government as represented by the
- Director, National Security Agency.
-
- This software may be used and distributed according to the terms
- of the GNU General Public License, incorporated herein by reference.
-
- The author may be reached as becker@scyld.com, or C/O
- Scyld Computing Corporation
- 410 Severn Ave., Suite 210
- Annapolis MD 21403
-
-
- Thanks go to jennings@Montrouge.SMR.slb.com ( Patrick Jennings)
- and jrs@world.std.com (Rick Sladkey) for testing and bugfixes.
- Mark Salazar <leslie@access.digex.net> made the changes for cards with
- only 16K packet buffers.
-
- Things remaining to do:
- Verify that the tx and rx buffers don't have fencepost errors.
- Move the theory of operation and memory map documentation.
- The statistics need to be updated correctly.
-*/
-
-#define DRV_NAME "3c507"
-#define DRV_VERSION "1.10a"
-#define DRV_RELDATE "11/17/2001"
-
-static const char version[] =
- DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " Donald Becker (becker@scyld.com)\n";
-
-/*
- Sources:
- This driver wouldn't have been written with the availability of the
- Crynwr driver source code. It provided a known-working implementation
- that filled in the gaping holes of the Intel documentation. Three cheers
- for Russ Nelson.
-
- Intel Microcommunications Databook, Vol. 1, 1990. It provides just enough
- info that the casual reader might think that it documents the i82586 :-<.
-*/
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/string.h>
-#include <linux/spinlock.h>
-#include <linux/ethtool.h>
-#include <linux/errno.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/if_ether.h>
-#include <linux/skbuff.h>
-#include <linux/init.h>
-#include <linux/bitops.h>
-
-#include <asm/dma.h>
-#include <asm/io.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
-
-/* use 0 for production, 1 for verification, 2..7 for debug */
-#ifndef NET_DEBUG
-#define NET_DEBUG 1
-#endif
-static unsigned int net_debug = NET_DEBUG;
-#define debug net_debug
-
-
-/*
- Details of the i82586.
-
- You'll really need the databook to understand the details of this part,
- but the outline is that the i82586 has two separate processing units.
- Both are started from a list of three configuration tables, of which only
- the last, the System Control Block (SCB), is used after reset-time. The SCB
- has the following fields:
- Status word
- Command word
- Tx/Command block addr.
- Rx block addr.
- The command word accepts the following controls for the Tx and Rx units:
- */
-
-#define CUC_START 0x0100
-#define CUC_RESUME 0x0200
-#define CUC_SUSPEND 0x0300
-#define RX_START 0x0010
-#define RX_RESUME 0x0020
-#define RX_SUSPEND 0x0030
-
-/* The Rx unit uses a list of frame descriptors and a list of data buffer
- descriptors. We use full-sized (1518 byte) data buffers, so there is
- a one-to-one pairing of frame descriptors to buffer descriptors.
-
- The Tx ("command") unit executes a list of commands that look like:
- Status word Written by the 82586 when the command is done.
- Command word Command in lower 3 bits, post-command action in upper 3
- Link word The address of the next command.
- Parameters (as needed).
-
- Some definitions related to the Command Word are:
- */
-#define CMD_EOL 0x8000 /* The last command of the list, stop. */
-#define CMD_SUSP 0x4000 /* Suspend after doing cmd. */
-#define CMD_INTR 0x2000 /* Interrupt after doing cmd. */
-
-enum commands {
- CmdNOp = 0, CmdSASetup = 1, CmdConfigure = 2, CmdMulticastList = 3,
- CmdTx = 4, CmdTDR = 5, CmdDump = 6, CmdDiagnose = 7};
-
-/* Information that need to be kept for each board. */
-struct net_local {
- int last_restart;
- ushort rx_head;
- ushort rx_tail;
- ushort tx_head;
- ushort tx_cmd_link;
- ushort tx_reap;
- ushort tx_pkts_in_ring;
- spinlock_t lock;
- void __iomem *base;
-};
-
-/*
- Details of the EtherLink16 Implementation
- The 3c507 is a generic shared-memory i82586 implementation.
- The host can map 16K, 32K, 48K, or 64K of the 64K memory into
- 0x0[CD][08]0000, or all 64K into 0xF[02468]0000.
- */
-
-/* Offsets from the base I/O address. */
-#define SA_DATA 0 /* Station address data, or 3Com signature. */
-#define MISC_CTRL 6 /* Switch the SA_DATA banks, and bus config bits. */
-#define RESET_IRQ 10 /* Reset the latched IRQ line. */
-#define SIGNAL_CA 11 /* Frob the 82586 Channel Attention line. */
-#define ROM_CONFIG 13
-#define MEM_CONFIG 14
-#define IRQ_CONFIG 15
-#define EL16_IO_EXTENT 16
-
-/* The ID port is used at boot-time to locate the ethercard. */
-#define ID_PORT 0x100
-
-/* Offsets to registers in the mailbox (SCB). */
-#define iSCB_STATUS 0x8
-#define iSCB_CMD 0xA
-#define iSCB_CBL 0xC /* Command BLock offset. */
-#define iSCB_RFA 0xE /* Rx Frame Area offset. */
-
-/* Since the 3c507 maps the shared memory window so that the last byte is
- at 82586 address FFFF, the first byte is at 82586 address 0, 16K, 32K, or
- 48K corresponding to window sizes of 64K, 48K, 32K and 16K respectively.
- We can account for this be setting the 'SBC Base' entry in the ISCP table
- below for all the 16 bit offset addresses, and also adding the 'SCB Base'
- value to all 24 bit physical addresses (in the SCP table and the TX and RX
- Buffer Descriptors).
- -Mark
- */
-#define SCB_BASE ((unsigned)64*1024 - (dev->mem_end - dev->mem_start))
-
-/*
- What follows in 'init_words[]' is the "program" that is downloaded to the
- 82586 memory. It's mostly tables and command blocks, and starts at the
- reset address 0xfffff6. This is designed to be similar to the EtherExpress,
- thus the unusual location of the SCB at 0x0008.
-
- Even with the additional "don't care" values, doing it this way takes less
- program space than initializing the individual tables, and I feel it's much
- cleaner.
-
- The databook is particularly useless for the first two structures, I had
- to use the Crynwr driver as an example.
-
- The memory setup is as follows:
- */
-
-#define CONFIG_CMD 0x0018
-#define SET_SA_CMD 0x0024
-#define SA_OFFSET 0x002A
-#define IDLELOOP 0x30
-#define TDR_CMD 0x38
-#define TDR_TIME 0x3C
-#define DUMP_CMD 0x40
-#define DIAG_CMD 0x48
-#define SET_MC_CMD 0x4E
-#define DUMP_DATA 0x56 /* A 170 byte buffer for dump and Set-MC into. */
-
-#define TX_BUF_START 0x0100
-#define NUM_TX_BUFS 5
-#define TX_BUF_SIZE (1518+14+20+16) /* packet+header+TBD */
-
-#define RX_BUF_START 0x2000
-#define RX_BUF_SIZE (1518+14+18) /* packet+header+RBD */
-#define RX_BUF_END (dev->mem_end - dev->mem_start)
-
-#define TX_TIMEOUT (HZ/20)
-
-/*
- That's it: only 86 bytes to set up the beast, including every extra
- command available. The 170 byte buffer at DUMP_DATA is shared between the
- Dump command (called only by the diagnostic program) and the SetMulticastList
- command.
-
- To complete the memory setup you only have to write the station address at
- SA_OFFSET and create the Tx & Rx buffer lists.
-
- The Tx command chain and buffer list is setup as follows:
- A Tx command table, with the data buffer pointing to...
- A Tx data buffer descriptor. The packet is in a single buffer, rather than
- chaining together several smaller buffers.
- A NoOp command, which initially points to itself,
- And the packet data.
-
- A transmit is done by filling in the Tx command table and data buffer,
- re-writing the NoOp command, and finally changing the offset of the last
- command to point to the current Tx command. When the Tx command is finished,
- it jumps to the NoOp, when it loops until the next Tx command changes the
- "link offset" in the NoOp. This way the 82586 never has to go through the
- slow restart sequence.
-
- The Rx buffer list is set up in the obvious ring structure. We have enough
- memory (and low enough interrupt latency) that we can avoid the complicated
- Rx buffer linked lists by alway associating a full-size Rx data buffer with
- each Rx data frame.
-
- I current use four transmit buffers starting at TX_BUF_START (0x0100), and
- use the rest of memory, from RX_BUF_START to RX_BUF_END, for Rx buffers.
-
- */
-
-static unsigned short init_words[] = {
- /* System Configuration Pointer (SCP). */
- 0x0000, /* Set bus size to 16 bits. */
- 0,0, /* pad words. */
- 0x0000,0x0000, /* ISCP phys addr, set in init_82586_mem(). */
-
- /* Intermediate System Configuration Pointer (ISCP). */
- 0x0001, /* Status word that's cleared when init is done. */
- 0x0008,0,0, /* SCB offset, (skip, skip) */
-
- /* System Control Block (SCB). */
- 0,0xf000|RX_START|CUC_START, /* SCB status and cmd. */
- CONFIG_CMD, /* Command list pointer, points to Configure. */
- RX_BUF_START, /* Rx block list. */
- 0,0,0,0, /* Error count: CRC, align, buffer, overrun. */
-
- /* 0x0018: Configure command. Change to put MAC data with packet. */
- 0, CmdConfigure, /* Status, command. */
- SET_SA_CMD, /* Next command is Set Station Addr. */
- 0x0804, /* "4" bytes of config data, 8 byte FIFO. */
- 0x2e40, /* Magic values, including MAC data location. */
- 0, /* Unused pad word. */
-
- /* 0x0024: Setup station address command. */
- 0, CmdSASetup,
- SET_MC_CMD, /* Next command. */
- 0xaa00,0xb000,0x0bad, /* Station address (to be filled in) */
-
- /* 0x0030: NOP, looping back to itself. Point to first Tx buffer to Tx. */
- 0, CmdNOp, IDLELOOP, 0 /* pad */,
-
- /* 0x0038: A unused Time-Domain Reflectometer command. */
- 0, CmdTDR, IDLELOOP, 0,
-
- /* 0x0040: An unused Dump State command. */
- 0, CmdDump, IDLELOOP, DUMP_DATA,
-
- /* 0x0048: An unused Diagnose command. */
- 0, CmdDiagnose, IDLELOOP,
-
- /* 0x004E: An empty set-multicast-list command. */
- 0, CmdMulticastList, IDLELOOP, 0,
-};
-
-/* Index to functions, as function prototypes. */
-
-static int el16_probe1(struct net_device *dev, int ioaddr);
-static int el16_open(struct net_device *dev);
-static netdev_tx_t el16_send_packet(struct sk_buff *skb,
- struct net_device *dev);
-static irqreturn_t el16_interrupt(int irq, void *dev_id);
-static void el16_rx(struct net_device *dev);
-static int el16_close(struct net_device *dev);
-static void el16_tx_timeout (struct net_device *dev);
-
-static void hardware_send_packet(struct net_device *dev, void *buf, short length, short pad);
-static void init_82586_mem(struct net_device *dev);
-static const struct ethtool_ops netdev_ethtool_ops;
-static void init_rx_bufs(struct net_device *);
-
-static int io = 0x300;
-static int irq;
-static int mem_start;
-
-
-/* Check for a network adaptor of this type, and return '0' iff one exists.
- If dev->base_addr == 0, probe all likely locations.
- If dev->base_addr == 1, always return failure.
- If dev->base_addr == 2, (detachable devices only) allocate space for the
- device and return success.
- */
-
-struct net_device * __init el16_probe(int unit)
-{
- struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
- static const unsigned ports[] = { 0x300, 0x320, 0x340, 0x280, 0};
- const unsigned *port;
- int err = -ENODEV;
-
- if (!dev)
- return ERR_PTR(-ENODEV);
-
- if (unit >= 0) {
- sprintf(dev->name, "eth%d", unit);
- netdev_boot_setup_check(dev);
- io = dev->base_addr;
- irq = dev->irq;
- mem_start = dev->mem_start & 15;
- }
-
- if (io > 0x1ff) /* Check a single specified location. */
- err = el16_probe1(dev, io);
- else if (io != 0)
- err = -ENXIO; /* Don't probe at all. */
- else {
- for (port = ports; *port; port++) {
- err = el16_probe1(dev, *port);
- if (!err)
- break;
- }
- }
-
- if (err)
- goto out;
- err = register_netdev(dev);
- if (err)
- goto out1;
- return dev;
-out1:
- free_irq(dev->irq, dev);
- iounmap(((struct net_local *)netdev_priv(dev))->base);
- release_region(dev->base_addr, EL16_IO_EXTENT);
-out:
- free_netdev(dev);
- return ERR_PTR(err);
-}
-
-static const struct net_device_ops netdev_ops = {
- .ndo_open = el16_open,
- .ndo_stop = el16_close,
- .ndo_start_xmit = el16_send_packet,
- .ndo_tx_timeout = el16_tx_timeout,
- .ndo_change_mtu = eth_change_mtu,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-static int __init el16_probe1(struct net_device *dev, int ioaddr)
-{
- static unsigned char init_ID_done;
- int i, irq, irqval, retval;
- struct net_local *lp;
-
- if (init_ID_done == 0) {
- ushort lrs_state = 0xff;
- /* Send the ID sequence to the ID_PORT to enable the board(s). */
- outb(0x00, ID_PORT);
- for(i = 0; i < 255; i++) {
- outb(lrs_state, ID_PORT);
- lrs_state <<= 1;
- if (lrs_state & 0x100)
- lrs_state ^= 0xe7;
- }
- outb(0x00, ID_PORT);
- init_ID_done = 1;
- }
-
- if (!request_region(ioaddr, EL16_IO_EXTENT, DRV_NAME))
- return -ENODEV;
-
- if ((inb(ioaddr) != '*') || (inb(ioaddr + 1) != '3') ||
- (inb(ioaddr + 2) != 'C') || (inb(ioaddr + 3) != 'O')) {
- retval = -ENODEV;
- goto out;
- }
-
- pr_info("%s: 3c507 at %#x,", dev->name, ioaddr);
-
- /* We should make a few more checks here, like the first three octets of
- the S.A. for the manufacturer's code. */
-
- irq = inb(ioaddr + IRQ_CONFIG) & 0x0f;
-
- irqval = request_irq(irq, el16_interrupt, 0, DRV_NAME, dev);
- if (irqval) {
- pr_cont("\n");
- pr_err("3c507: unable to get IRQ %d (irqval=%d).\n", irq, irqval);
- retval = -EAGAIN;
- goto out;
- }
-
- /* We've committed to using the board, and can start filling in *dev. */
- dev->base_addr = ioaddr;
-
- outb(0x01, ioaddr + MISC_CTRL);
- for (i = 0; i < 6; i++)
- dev->dev_addr[i] = inb(ioaddr + i);
- pr_cont(" %pM", dev->dev_addr);
-
- if (mem_start)
- net_debug = mem_start & 7;
-
-#ifdef MEM_BASE
- dev->mem_start = MEM_BASE;
- dev->mem_end = dev->mem_start + 0x10000;
-#else
- {
- int base;
- int size;
- char mem_config = inb(ioaddr + MEM_CONFIG);
- if (mem_config & 0x20) {
- size = 64*1024;
- base = 0xf00000 + (mem_config & 0x08 ? 0x080000
- : ((mem_config & 3) << 17));
- } else {
- size = ((mem_config & 3) + 1) << 14;
- base = 0x0c0000 + ( (mem_config & 0x18) << 12);
- }
- dev->mem_start = base;
- dev->mem_end = base + size;
- }
-#endif
-
- dev->if_port = (inb(ioaddr + ROM_CONFIG) & 0x80) ? 1 : 0;
- dev->irq = inb(ioaddr + IRQ_CONFIG) & 0x0f;
-
- pr_cont(", IRQ %d, %sternal xcvr, memory %#lx-%#lx.\n", dev->irq,
- dev->if_port ? "ex" : "in", dev->mem_start, dev->mem_end-1);
-
- if (net_debug)
- pr_debug("%s", version);
-
- lp = netdev_priv(dev);
- spin_lock_init(&lp->lock);
- lp->base = ioremap(dev->mem_start, RX_BUF_END);
- if (!lp->base) {
- pr_err("3c507: unable to remap memory\n");
- retval = -EAGAIN;
- goto out1;
- }
-
- dev->netdev_ops = &netdev_ops;
- dev->watchdog_timeo = TX_TIMEOUT;
- dev->ethtool_ops = &netdev_ethtool_ops;
- dev->flags &= ~IFF_MULTICAST; /* Multicast doesn't work */
- return 0;
-out1:
- free_irq(dev->irq, dev);
-out:
- release_region(ioaddr, EL16_IO_EXTENT);
- return retval;
-}
-
-static int el16_open(struct net_device *dev)
-{
- /* Initialize the 82586 memory and start it. */
- init_82586_mem(dev);
-
- netif_start_queue(dev);
- return 0;
-}
-
-
-static void el16_tx_timeout (struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
- int ioaddr = dev->base_addr;
- void __iomem *shmem = lp->base;
-
- if (net_debug > 1)
- pr_debug("%s: transmit timed out, %s? ", dev->name,
- readw(shmem + iSCB_STATUS) & 0x8000 ? "IRQ conflict" :
- "network cable problem");
- /* Try to restart the adaptor. */
- if (lp->last_restart == dev->stats.tx_packets) {
- if (net_debug > 1)
- pr_cont("Resetting board.\n");
- /* Completely reset the adaptor. */
- init_82586_mem (dev);
- lp->tx_pkts_in_ring = 0;
- } else {
- /* Issue the channel attention signal and hope it "gets better". */
- if (net_debug > 1)
- pr_cont("Kicking board.\n");
- writew(0xf000 | CUC_START | RX_START, shmem + iSCB_CMD);
- outb (0, ioaddr + SIGNAL_CA); /* Issue channel-attn. */
- lp->last_restart = dev->stats.tx_packets;
- }
- dev->trans_start = jiffies; /* prevent tx timeout */
- netif_wake_queue (dev);
-}
-
-
-static netdev_tx_t el16_send_packet (struct sk_buff *skb,
- struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
- int ioaddr = dev->base_addr;
- unsigned long flags;
- short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
- unsigned char *buf = skb->data;
-
- netif_stop_queue (dev);
-
- spin_lock_irqsave (&lp->lock, flags);
-
- dev->stats.tx_bytes += length;
- /* Disable the 82586's input to the interrupt line. */
- outb (0x80, ioaddr + MISC_CTRL);
-
- hardware_send_packet (dev, buf, skb->len, length - skb->len);
-
- /* Enable the 82586 interrupt input. */
- outb (0x84, ioaddr + MISC_CTRL);
-
- spin_unlock_irqrestore (&lp->lock, flags);
-
- dev_kfree_skb (skb);
-
- /* You might need to clean up and record Tx statistics here. */
-
- return NETDEV_TX_OK;
-}
-
-/* The typical workload of the driver:
- Handle the network interface interrupts. */
-static irqreturn_t el16_interrupt(int irq, void *dev_id)
-{
- struct net_device *dev = dev_id;
- struct net_local *lp;
- int ioaddr, status, boguscount = 0;
- ushort ack_cmd = 0;
- void __iomem *shmem;
-
- if (dev == NULL) {
- pr_err("net_interrupt(): irq %d for unknown device.\n", irq);
- return IRQ_NONE;
- }
-
- ioaddr = dev->base_addr;
- lp = netdev_priv(dev);
- shmem = lp->base;
-
- spin_lock(&lp->lock);
-
- status = readw(shmem+iSCB_STATUS);
-
- if (net_debug > 4) {
- pr_debug("%s: 3c507 interrupt, status %4.4x.\n", dev->name, status);
- }
-
- /* Disable the 82586's input to the interrupt line. */
- outb(0x80, ioaddr + MISC_CTRL);
-
- /* Reap the Tx packet buffers. */
- while (lp->tx_pkts_in_ring) {
- unsigned short tx_status = readw(shmem+lp->tx_reap);
- if (!(tx_status & 0x8000)) {
- if (net_debug > 5)
- pr_debug("Tx command incomplete (%#x).\n", lp->tx_reap);
- break;
- }
- /* Tx unsuccessful or some interesting status bit set. */
- if (!(tx_status & 0x2000) || (tx_status & 0x0f3f)) {
- dev->stats.tx_errors++;
- if (tx_status & 0x0600) dev->stats.tx_carrier_errors++;
- if (tx_status & 0x0100) dev->stats.tx_fifo_errors++;
- if (!(tx_status & 0x0040)) dev->stats.tx_heartbeat_errors++;
- if (tx_status & 0x0020) dev->stats.tx_aborted_errors++;
- dev->stats.collisions += tx_status & 0xf;
- }
- dev->stats.tx_packets++;
- if (net_debug > 5)
- pr_debug("Reaped %x, Tx status %04x.\n" , lp->tx_reap, tx_status);
- lp->tx_reap += TX_BUF_SIZE;
- if (lp->tx_reap > RX_BUF_START - TX_BUF_SIZE)
- lp->tx_reap = TX_BUF_START;
-
- lp->tx_pkts_in_ring--;
- /* There is always more space in the Tx ring buffer now. */
- netif_wake_queue(dev);
-
- if (++boguscount > 10)
- break;
- }
-
- if (status & 0x4000) { /* Packet received. */
- if (net_debug > 5)
- pr_debug("Received packet, rx_head %04x.\n", lp->rx_head);
- el16_rx(dev);
- }
-
- /* Acknowledge the interrupt sources. */
- ack_cmd = status & 0xf000;
-
- if ((status & 0x0700) != 0x0200 && netif_running(dev)) {
- if (net_debug)
- pr_debug("%s: Command unit stopped, status %04x, restarting.\n",
- dev->name, status);
- /* If this ever occurs we should really re-write the idle loop, reset
- the Tx list, and do a complete restart of the command unit.
- For now we rely on the Tx timeout if the resume doesn't work. */
- ack_cmd |= CUC_RESUME;
- }
-
- if ((status & 0x0070) != 0x0040 && netif_running(dev)) {
- /* The Rx unit is not ready, it must be hung. Restart the receiver by
- initializing the rx buffers, and issuing an Rx start command. */
- if (net_debug)
- pr_debug("%s: Rx unit stopped, status %04x, restarting.\n",
- dev->name, status);
- init_rx_bufs(dev);
- writew(RX_BUF_START,shmem+iSCB_RFA);
- ack_cmd |= RX_START;
- }
-
- writew(ack_cmd,shmem+iSCB_CMD);
- outb(0, ioaddr + SIGNAL_CA); /* Issue channel-attn. */
-
- /* Clear the latched interrupt. */
- outb(0, ioaddr + RESET_IRQ);
-
- /* Enable the 82586's interrupt input. */
- outb(0x84, ioaddr + MISC_CTRL);
- spin_unlock(&lp->lock);
- return IRQ_HANDLED;
-}
-
-static int el16_close(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
- int ioaddr = dev->base_addr;
- void __iomem *shmem = lp->base;
-
- netif_stop_queue(dev);
-
- /* Flush the Tx and disable Rx. */
- writew(RX_SUSPEND | CUC_SUSPEND,shmem+iSCB_CMD);
- outb(0, ioaddr + SIGNAL_CA);
-
- /* Disable the 82586's input to the interrupt line. */
- outb(0x80, ioaddr + MISC_CTRL);
-
- /* We always physically use the IRQ line, so we don't do free_irq(). */
-
- /* Update the statistics here. */
-
- return 0;
-}
-
-/* Initialize the Rx-block list. */
-static void init_rx_bufs(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
- void __iomem *write_ptr;
- unsigned short SCB_base = SCB_BASE;
-
- int cur_rxbuf = lp->rx_head = RX_BUF_START;
-
- /* Initialize each Rx frame + data buffer. */
- do { /* While there is room for one more. */
-
- write_ptr = lp->base + cur_rxbuf;
-
- writew(0x0000,write_ptr); /* Status */
- writew(0x0000,write_ptr+=2); /* Command */
- writew(cur_rxbuf + RX_BUF_SIZE,write_ptr+=2); /* Link */
- writew(cur_rxbuf + 22,write_ptr+=2); /* Buffer offset */
- writew(0x0000,write_ptr+=2); /* Pad for dest addr. */
- writew(0x0000,write_ptr+=2);
- writew(0x0000,write_ptr+=2);
- writew(0x0000,write_ptr+=2); /* Pad for source addr. */
- writew(0x0000,write_ptr+=2);
- writew(0x0000,write_ptr+=2);
- writew(0x0000,write_ptr+=2); /* Pad for protocol. */
-
- writew(0x0000,write_ptr+=2); /* Buffer: Actual count */
- writew(-1,write_ptr+=2); /* Buffer: Next (none). */
- writew(cur_rxbuf + 0x20 + SCB_base,write_ptr+=2);/* Buffer: Address low */
- writew(0x0000,write_ptr+=2);
- /* Finally, the number of bytes in the buffer. */
- writew(0x8000 + RX_BUF_SIZE-0x20,write_ptr+=2);
-
- lp->rx_tail = cur_rxbuf;
- cur_rxbuf += RX_BUF_SIZE;
- } while (cur_rxbuf <= RX_BUF_END - RX_BUF_SIZE);
-
- /* Terminate the list by setting the EOL bit, and wrap the pointer to make
- the list a ring. */
- write_ptr = lp->base + lp->rx_tail + 2;
- writew(0xC000,write_ptr); /* Command, mark as last. */
- writew(lp->rx_head,write_ptr+2); /* Link */
-}
-
-static void init_82586_mem(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
- short ioaddr = dev->base_addr;
- void __iomem *shmem = lp->base;
-
- /* Enable loopback to protect the wire while starting up,
- and hold the 586 in reset during the memory initialization. */
- outb(0x20, ioaddr + MISC_CTRL);
-
- /* Fix the ISCP address and base. */
- init_words[3] = SCB_BASE;
- init_words[7] = SCB_BASE;
-
- /* Write the words at 0xfff6 (address-aliased to 0xfffff6). */
- memcpy_toio(lp->base + RX_BUF_END - 10, init_words, 10);
-
- /* Write the words at 0x0000. */
- memcpy_toio(lp->base, init_words + 5, sizeof(init_words) - 10);
-
- /* Fill in the station address. */
- memcpy_toio(lp->base+SA_OFFSET, dev->dev_addr, ETH_ALEN);
-
- /* The Tx-block list is written as needed. We just set up the values. */
- lp->tx_cmd_link = IDLELOOP + 4;
- lp->tx_head = lp->tx_reap = TX_BUF_START;
-
- init_rx_bufs(dev);
-
- /* Start the 586 by releasing the reset line, but leave loopback. */
- outb(0xA0, ioaddr + MISC_CTRL);
-
- /* This was time consuming to track down: you need to give two channel
- attention signals to reliably start up the i82586. */
- outb(0, ioaddr + SIGNAL_CA);
-
- {
- int boguscnt = 50;
- while (readw(shmem+iSCB_STATUS) == 0)
- if (--boguscnt == 0) {
- pr_warning("%s: i82586 initialization timed out with status %04x, cmd %04x.\n",
- dev->name, readw(shmem+iSCB_STATUS), readw(shmem+iSCB_CMD));
- break;
- }
- /* Issue channel-attn -- the 82586 won't start. */
- outb(0, ioaddr + SIGNAL_CA);
- }
-
- /* Disable loopback and enable interrupts. */
- outb(0x84, ioaddr + MISC_CTRL);
- if (net_debug > 4)
- pr_debug("%s: Initialized 82586, status %04x.\n", dev->name,
- readw(shmem+iSCB_STATUS));
-}
-
-static void hardware_send_packet(struct net_device *dev, void *buf, short length, short pad)
-{
- struct net_local *lp = netdev_priv(dev);
- short ioaddr = dev->base_addr;
- ushort tx_block = lp->tx_head;
- void __iomem *write_ptr = lp->base + tx_block;
- static char padding[ETH_ZLEN];
-
- /* Set the write pointer to the Tx block, and put out the header. */
- writew(0x0000,write_ptr); /* Tx status */
- writew(CMD_INTR|CmdTx,write_ptr+=2); /* Tx command */
- writew(tx_block+16,write_ptr+=2); /* Next command is a NoOp. */
- writew(tx_block+8,write_ptr+=2); /* Data Buffer offset. */
-
- /* Output the data buffer descriptor. */
- writew((pad + length) | 0x8000,write_ptr+=2); /* Byte count parameter. */
- writew(-1,write_ptr+=2); /* No next data buffer. */
- writew(tx_block+22+SCB_BASE,write_ptr+=2); /* Buffer follows the NoOp command. */
- writew(0x0000,write_ptr+=2); /* Buffer address high bits (always zero). */
-
- /* Output the Loop-back NoOp command. */
- writew(0x0000,write_ptr+=2); /* Tx status */
- writew(CmdNOp,write_ptr+=2); /* Tx command */
- writew(tx_block+16,write_ptr+=2); /* Next is myself. */
-
- /* Output the packet at the write pointer. */
- memcpy_toio(write_ptr+2, buf, length);
- if (pad)
- memcpy_toio(write_ptr+length+2, padding, pad);
-
- /* Set the old command link pointing to this send packet. */
- writew(tx_block,lp->base + lp->tx_cmd_link);
- lp->tx_cmd_link = tx_block + 20;
-
- /* Set the next free tx region. */
- lp->tx_head = tx_block + TX_BUF_SIZE;
- if (lp->tx_head > RX_BUF_START - TX_BUF_SIZE)
- lp->tx_head = TX_BUF_START;
-
- if (net_debug > 4) {
- pr_debug("%s: 3c507 @%x send length = %d, tx_block %3x, next %3x.\n",
- dev->name, ioaddr, length, tx_block, lp->tx_head);
- }
-
- /* Grimly block further packets if there has been insufficient reaping. */
- if (++lp->tx_pkts_in_ring < NUM_TX_BUFS)
- netif_wake_queue(dev);
-}
-
-static void el16_rx(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
- void __iomem *shmem = lp->base;
- ushort rx_head = lp->rx_head;
- ushort rx_tail = lp->rx_tail;
- ushort boguscount = 10;
- short frame_status;
-
- while ((frame_status = readw(shmem+rx_head)) < 0) { /* Command complete */
- void __iomem *read_frame = lp->base + rx_head;
- ushort rfd_cmd = readw(read_frame+2);
- ushort next_rx_frame = readw(read_frame+4);
- ushort data_buffer_addr = readw(read_frame+6);
- void __iomem *data_frame = lp->base + data_buffer_addr;
- ushort pkt_len = readw(data_frame);
-
- if (rfd_cmd != 0 || data_buffer_addr != rx_head + 22 ||
- (pkt_len & 0xC000) != 0xC000) {
- pr_err("%s: Rx frame at %#x corrupted, "
- "status %04x cmd %04x next %04x "
- "data-buf @%04x %04x.\n",
- dev->name, rx_head, frame_status, rfd_cmd,
- next_rx_frame, data_buffer_addr, pkt_len);
- } else if ((frame_status & 0x2000) == 0) {
- /* Frame Rxed, but with error. */
- dev->stats.rx_errors++;
- if (frame_status & 0x0800) dev->stats.rx_crc_errors++;
- if (frame_status & 0x0400) dev->stats.rx_frame_errors++;
- if (frame_status & 0x0200) dev->stats.rx_fifo_errors++;
- if (frame_status & 0x0100) dev->stats.rx_over_errors++;
- if (frame_status & 0x0080) dev->stats.rx_length_errors++;
- } else {
- /* Malloc up new buffer. */
- struct sk_buff *skb;
-
- pkt_len &= 0x3fff;
- skb = dev_alloc_skb(pkt_len+2);
- if (skb == NULL) {
- pr_err("%s: Memory squeeze, dropping packet.\n",
- dev->name);
- dev->stats.rx_dropped++;
- break;
- }
-
- skb_reserve(skb,2);
-
- /* 'skb->data' points to the start of sk_buff data area. */
- memcpy_fromio(skb_put(skb,pkt_len), data_frame + 10, pkt_len);
-
- skb->protocol=eth_type_trans(skb,dev);
- netif_rx(skb);
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += pkt_len;
- }
-
- /* Clear the status word and set End-of-List on the rx frame. */
- writew(0,read_frame);
- writew(0xC000,read_frame+2);
- /* Clear the end-of-list on the prev. RFD. */
- writew(0x0000,lp->base + rx_tail + 2);
-
- rx_tail = rx_head;
- rx_head = next_rx_frame;
- if (--boguscount == 0)
- break;
- }
-
- lp->rx_head = rx_head;
- lp->rx_tail = rx_tail;
-}
-
-static void netdev_get_drvinfo(struct net_device *dev,
- struct ethtool_drvinfo *info)
-{
- strcpy(info->driver, DRV_NAME);
- strcpy(info->version, DRV_VERSION);
- sprintf(info->bus_info, "ISA 0x%lx", dev->base_addr);
-}
-
-static u32 netdev_get_msglevel(struct net_device *dev)
-{
- return debug;
-}
-
-static void netdev_set_msglevel(struct net_device *dev, u32 level)
-{
- debug = level;
-}
-
-static const struct ethtool_ops netdev_ethtool_ops = {
- .get_drvinfo = netdev_get_drvinfo,
- .get_msglevel = netdev_get_msglevel,
- .set_msglevel = netdev_set_msglevel,
-};
-
-#ifdef MODULE
-static struct net_device *dev_3c507;
-module_param(io, int, 0);
-module_param(irq, int, 0);
-MODULE_PARM_DESC(io, "EtherLink16 I/O base address");
-MODULE_PARM_DESC(irq, "(ignored)");
-
-int __init init_module(void)
-{
- if (io == 0)
- pr_notice("3c507: You should not use auto-probing with insmod!\n");
- dev_3c507 = el16_probe(-1);
- return IS_ERR(dev_3c507) ? PTR_ERR(dev_3c507) : 0;
-}
-
-void __exit
-cleanup_module(void)
-{
- struct net_device *dev = dev_3c507;
- unregister_netdev(dev);
- free_irq(dev->irq, dev);
- iounmap(((struct net_local *)netdev_priv(dev))->base);
- release_region(dev->base_addr, EL16_IO_EXTENT);
- free_netdev(dev);
-}
-#endif /* MODULE */
-MODULE_LICENSE("GPL");
+++ /dev/null
-/*
- net-3-driver for the 3c523 Etherlink/MC card (i82586 Ethernet chip)
-
-
- This is an extension to the Linux operating system, and is covered by the
- same GNU General Public License that covers that work.
-
- Copyright 1995, 1996 by Chris Beauregard (cpbeaure@undergrad.math.uwaterloo.ca)
-
- This is basically Michael Hipp's ni52 driver, with a new probing
- algorithm and some minor changes to the 82586 CA and reset routines.
- Thanks a lot Michael for a really clean i82586 implementation! Unless
- otherwise documented in ni52.c, any bugs are mine.
-
- Contrary to the Ethernet-HOWTO, this isn't based on the 3c507 driver in
- any way. The ni52 is a lot easier to modify.
-
- sources:
- ni52.c
-
- Crynwr packet driver collection was a great reference for my first
- attempt at this sucker. The 3c507 driver also helped, until I noticed
- that ni52.c was a lot nicer.
-
- EtherLink/MC: Micro Channel Ethernet Adapter Technical Reference
- Manual, courtesy of 3Com CardFacts, documents the 3c523-specific
- stuff. Information on CardFacts is found in the Ethernet HOWTO.
- Also see <a href="http://www.3com.com/">
-
- Microprocessor Communications Support Chips, T.J. Byers, ISBN
- 0-444-01224-9, has a section on the i82586. It tells you just enough
- to know that you really don't want to learn how to program the chip.
-
- The original device probe code was stolen from ps2esdi.c
-
- Known Problems:
- Since most of the code was stolen from ni52.c, you'll run across the
- same bugs in the 0.62 version of ni52.c, plus maybe a few because of
- the 3c523 idiosynchacies. The 3c523 has 16K of RAM though, so there
- shouldn't be the overrun problem that the 8K ni52 has.
-
- This driver is for a 16K adapter. It should work fine on the 64K
- adapters, but it will only use one of the 4 banks of RAM. Modifying
- this for the 64K version would require a lot of heinous bank
- switching, which I'm sure not interested in doing. If you try to
- implement a bank switching version, you'll basically have to remember
- what bank is enabled and do a switch every time you access a memory
- location that's not current. You'll also have to remap pointers on
- the driver side, because it only knows about 16K of the memory.
- Anyone desperate or masochistic enough to try?
-
- It seems to be stable now when multiple transmit buffers are used. I
- can't see any performance difference, but then I'm working on a 386SX.
-
- Multicast doesn't work. It doesn't even pretend to work. Don't use
- it. Don't compile your kernel with multicast support. I don't know
- why.
-
- Features:
- This driver is useable as a loadable module. If you try to specify an
- IRQ or a IO address (via insmod 3c523.o irq=xx io=0xyyy), it will
- search the MCA slots until it finds a 3c523 with the specified
- parameters.
-
- This driver does support multiple ethernet cards when used as a module
- (up to MAX_3C523_CARDS, the default being 4)
-
- This has been tested with both BNC and TP versions, internal and
- external transceivers. Haven't tested with the 64K version (that I
- know of).
-
- History:
- Jan 1st, 1996
- first public release
- Feb 4th, 1996
- update to 1.3.59, incorporated multicast diffs from ni52.c
- Feb 15th, 1996
- added shared irq support
- Apr 1999
- added support for multiple cards when used as a module
- added option to disable multicast as is causes problems
- Ganesh Sittampalam <ganesh.sittampalam@magdalen.oxford.ac.uk>
- Stuart Adamson <stuart.adamson@compsoc.net>
- Nov 2001
- added support for ethtool (jgarzik)
-
- $Header: /fsys2/home/chrisb/linux-1.3.59-MCA/drivers/net/RCS/3c523.c,v 1.1 1996/02/05 01:53:46 chrisb Exp chrisb $
- */
-
-#define DRV_NAME "3c523"
-#define DRV_VERSION "17-Nov-2001"
-
-#include <linux/init.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/skbuff.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/mca-legacy.h>
-#include <linux/ethtool.h>
-#include <linux/bitops.h>
-#include <linux/jiffies.h>
-
-#include <asm/uaccess.h>
-#include <asm/processor.h>
-#include <asm/io.h>
-
-#include "3c523.h"
-
-/*************************************************************************/
-#define DEBUG /* debug on */
-#define SYSBUSVAL 0 /* 1 = 8 Bit, 0 = 16 bit - 3c523 only does 16 bit */
-#undef ELMC_MULTICAST /* Disable multicast support as it is somewhat seriously broken at the moment */
-
-#define make32(ptr16) (p->memtop + (short) (ptr16) )
-#define make24(ptr32) ((char *) (ptr32) - p->base)
-#define make16(ptr32) ((unsigned short) ((unsigned long) (ptr32) - (unsigned long) p->memtop ))
-
-/*************************************************************************/
-/*
- Tables to which we can map values in the configuration registers.
- */
-static int irq_table[] __initdata = {
- 12, 7, 3, 9
-};
-
-static int csr_table[] __initdata = {
- 0x300, 0x1300, 0x2300, 0x3300
-};
-
-static int shm_table[] __initdata = {
- 0x0c0000, 0x0c8000, 0x0d0000, 0x0d8000
-};
-
-/******************* how to calculate the buffers *****************************
-
-
- * IMPORTANT NOTE: if you configure only one NUM_XMIT_BUFFS, the driver works
- * --------------- in a different (more stable?) mode. Only in this mode it's
- * possible to configure the driver with 'NO_NOPCOMMANDS'
-
-sizeof(scp)=12; sizeof(scb)=16; sizeof(iscp)=8;
-sizeof(scp)+sizeof(iscp)+sizeof(scb) = 36 = INIT
-sizeof(rfd) = 24; sizeof(rbd) = 12;
-sizeof(tbd) = 8; sizeof(transmit_cmd) = 16;
-sizeof(nop_cmd) = 8;
-
- * if you don't know the driver, better do not change this values: */
-
-#define RECV_BUFF_SIZE 1524 /* slightly oversized */
-#define XMIT_BUFF_SIZE 1524 /* slightly oversized */
-#define NUM_XMIT_BUFFS 1 /* config for both, 8K and 16K shmem */
-#define NUM_RECV_BUFFS_8 4 /* config for 8K shared mem */
-#define NUM_RECV_BUFFS_16 9 /* config for 16K shared mem */
-
-#if (NUM_XMIT_BUFFS == 1)
-#define NO_NOPCOMMANDS /* only possible with NUM_XMIT_BUFFS=1 */
-#endif
-
-/**************************************************************************/
-
-#define DELAY(x) { mdelay(32 * x); }
-
-/* a much shorter delay: */
-#define DELAY_16(); { udelay(16) ; }
-
-/* wait for command with timeout: */
-#define WAIT_4_SCB_CMD() { int i; \
- for(i=0;i<1024;i++) { \
- if(!p->scb->cmd) break; \
- DELAY_16(); \
- if(i == 1023) { \
- pr_warning("%s:%d: scb_cmd timed out .. resetting i82586\n",\
- dev->name,__LINE__); \
- elmc_id_reset586(); } } }
-
-static irqreturn_t elmc_interrupt(int irq, void *dev_id);
-static int elmc_open(struct net_device *dev);
-static int elmc_close(struct net_device *dev);
-static netdev_tx_t elmc_send_packet(struct sk_buff *, struct net_device *);
-static struct net_device_stats *elmc_get_stats(struct net_device *dev);
-static void elmc_timeout(struct net_device *dev);
-#ifdef ELMC_MULTICAST
-static void set_multicast_list(struct net_device *dev);
-#endif
-static const struct ethtool_ops netdev_ethtool_ops;
-
-/* helper-functions */
-static int init586(struct net_device *dev);
-static int check586(struct net_device *dev, unsigned long where, unsigned size);
-static void alloc586(struct net_device *dev);
-static void startrecv586(struct net_device *dev);
-static void *alloc_rfa(struct net_device *dev, void *ptr);
-static void elmc_rcv_int(struct net_device *dev);
-static void elmc_xmt_int(struct net_device *dev);
-static void elmc_rnr_int(struct net_device *dev);
-
-struct priv {
- unsigned long base;
- char *memtop;
- unsigned long mapped_start; /* Start of ioremap */
- volatile struct rfd_struct *rfd_last, *rfd_top, *rfd_first;
- volatile struct scp_struct *scp; /* volatile is important */
- volatile struct iscp_struct *iscp; /* volatile is important */
- volatile struct scb_struct *scb; /* volatile is important */
- volatile struct tbd_struct *xmit_buffs[NUM_XMIT_BUFFS];
-#if (NUM_XMIT_BUFFS == 1)
- volatile struct transmit_cmd_struct *xmit_cmds[2];
- volatile struct nop_cmd_struct *nop_cmds[2];
-#else
- volatile struct transmit_cmd_struct *xmit_cmds[NUM_XMIT_BUFFS];
- volatile struct nop_cmd_struct *nop_cmds[NUM_XMIT_BUFFS];
-#endif
- volatile int nop_point, num_recv_buffs;
- volatile char *xmit_cbuffs[NUM_XMIT_BUFFS];
- volatile int xmit_count, xmit_last;
- volatile int slot;
-};
-
-#define elmc_attn586() {elmc_do_attn586(dev->base_addr,ELMC_CTRL_INTE);}
-#define elmc_reset586() {elmc_do_reset586(dev->base_addr,ELMC_CTRL_INTE);}
-
-/* with interrupts disabled - this will clear the interrupt bit in the
- 3c523 control register, and won't put it back. This effectively
- disables interrupts on the card. */
-#define elmc_id_attn586() {elmc_do_attn586(dev->base_addr,0);}
-#define elmc_id_reset586() {elmc_do_reset586(dev->base_addr,0);}
-
-/*************************************************************************/
-/*
- Do a Channel Attention on the 3c523. This is extremely board dependent.
- */
-static void elmc_do_attn586(int ioaddr, int ints)
-{
- /* the 3c523 requires a minimum of 500 ns. The delays here might be
- a little too large, and hence they may cut the performance of the
- card slightly. If someone who knows a little more about Linux
- timing would care to play with these, I'd appreciate it. */
-
- /* this bit masking stuff is crap. I'd rather have separate
- registers with strobe triggers for each of these functions. <sigh>
- Ya take what ya got. */
-
- outb(ELMC_CTRL_RST | 0x3 | ELMC_CTRL_CA | ints, ioaddr + ELMC_CTRL);
- DELAY_16(); /* > 500 ns */
- outb(ELMC_CTRL_RST | 0x3 | ints, ioaddr + ELMC_CTRL);
-}
-
-/*************************************************************************/
-/*
- Reset the 82586 on the 3c523. Also very board dependent.
- */
-static void elmc_do_reset586(int ioaddr, int ints)
-{
- /* toggle the RST bit low then high */
- outb(0x3 | ELMC_CTRL_LBK, ioaddr + ELMC_CTRL);
- DELAY_16(); /* > 500 ns */
- outb(ELMC_CTRL_RST | ELMC_CTRL_LBK | 0x3, ioaddr + ELMC_CTRL);
-
- elmc_do_attn586(ioaddr, ints);
-}
-
-/**********************************************
- * close device
- */
-
-static int elmc_close(struct net_device *dev)
-{
- netif_stop_queue(dev);
- elmc_id_reset586(); /* the hard way to stop the receiver */
- free_irq(dev->irq, dev);
- return 0;
-}
-
-/**********************************************
- * open device
- */
-
-static int elmc_open(struct net_device *dev)
-{
- int ret;
-
- elmc_id_attn586(); /* disable interrupts */
-
- ret = request_irq(dev->irq, elmc_interrupt, IRQF_SHARED,
- dev->name, dev);
- if (ret) {
- pr_err("%s: couldn't get irq %d\n", dev->name, dev->irq);
- elmc_id_reset586();
- return ret;
- }
- alloc586(dev);
- init586(dev);
- startrecv586(dev);
- netif_start_queue(dev);
- return 0; /* most done by init */
-}
-
-/**********************************************
- * Check to see if there's an 82586 out there.
- */
-
-static int __init check586(struct net_device *dev, unsigned long where, unsigned size)
-{
- struct priv *p = netdev_priv(dev);
- char *iscp_addrs[2];
- int i = 0;
-
- p->base = (unsigned long) isa_bus_to_virt((unsigned long)where) + size - 0x01000000;
- p->memtop = isa_bus_to_virt((unsigned long)where) + size;
- p->scp = (struct scp_struct *)(p->base + SCP_DEFAULT_ADDRESS);
- memset((char *) p->scp, 0, sizeof(struct scp_struct));
- p->scp->sysbus = SYSBUSVAL; /* 1 = 8Bit-Bus, 0 = 16 Bit */
-
- iscp_addrs[0] = isa_bus_to_virt((unsigned long)where);
- iscp_addrs[1] = (char *) p->scp - sizeof(struct iscp_struct);
-
- for (i = 0; i < 2; i++) {
- p->iscp = (struct iscp_struct *) iscp_addrs[i];
- memset((char *) p->iscp, 0, sizeof(struct iscp_struct));
-
- p->scp->iscp = make24(p->iscp);
- p->iscp->busy = 1;
-
- elmc_id_reset586();
-
- /* reset586 does an implicit CA */
-
- /* apparently, you sometimes have to kick the 82586 twice... */
- elmc_id_attn586();
- DELAY(1);
-
- if (p->iscp->busy) { /* i82586 clears 'busy' after successful init */
- return 0;
- }
- }
- return 1;
-}
-
-/******************************************************************
- * set iscp at the right place, called by elmc_probe and open586.
- */
-
-static void alloc586(struct net_device *dev)
-{
- struct priv *p = netdev_priv(dev);
-
- elmc_id_reset586();
- DELAY(2);
-
- p->scp = (struct scp_struct *) (p->base + SCP_DEFAULT_ADDRESS);
- p->scb = (struct scb_struct *) isa_bus_to_virt(dev->mem_start);
- p->iscp = (struct iscp_struct *) ((char *) p->scp - sizeof(struct iscp_struct));
-
- memset((char *) p->iscp, 0, sizeof(struct iscp_struct));
- memset((char *) p->scp, 0, sizeof(struct scp_struct));
-
- p->scp->iscp = make24(p->iscp);
- p->scp->sysbus = SYSBUSVAL;
- p->iscp->scb_offset = make16(p->scb);
-
- p->iscp->busy = 1;
- elmc_id_reset586();
- elmc_id_attn586();
-
- DELAY(2);
-
- if (p->iscp->busy)
- pr_err("%s: Init-Problems (alloc).\n", dev->name);
-
- memset((char *) p->scb, 0, sizeof(struct scb_struct));
-}
-
-/*****************************************************************/
-
-static int elmc_getinfo(char *buf, int slot, void *d)
-{
- int len = 0;
- struct net_device *dev = d;
-
- if (dev == NULL)
- return len;
-
- len += sprintf(buf + len, "Revision: 0x%x\n",
- inb(dev->base_addr + ELMC_REVISION) & 0xf);
- len += sprintf(buf + len, "IRQ: %d\n", dev->irq);
- len += sprintf(buf + len, "IO Address: %#lx-%#lx\n", dev->base_addr,
- dev->base_addr + ELMC_IO_EXTENT);
- len += sprintf(buf + len, "Memory: %#lx-%#lx\n", dev->mem_start,
- dev->mem_end - 1);
- len += sprintf(buf + len, "Transceiver: %s\n", dev->if_port ?
- "External" : "Internal");
- len += sprintf(buf + len, "Device: %s\n", dev->name);
- len += sprintf(buf + len, "Hardware Address: %pM\n",
- dev->dev_addr);
-
- return len;
-} /* elmc_getinfo() */
-
-static const struct net_device_ops netdev_ops = {
- .ndo_open = elmc_open,
- .ndo_stop = elmc_close,
- .ndo_get_stats = elmc_get_stats,
- .ndo_start_xmit = elmc_send_packet,
- .ndo_tx_timeout = elmc_timeout,
-#ifdef ELMC_MULTICAST
- .ndo_set_multicast_list = set_multicast_list,
-#endif
- .ndo_change_mtu = eth_change_mtu,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-/*****************************************************************/
-
-static int __init do_elmc_probe(struct net_device *dev)
-{
- static int slot;
- int base_addr = dev->base_addr;
- int irq = dev->irq;
- u_char status = 0;
- u_char revision = 0;
- int i = 0;
- unsigned int size = 0;
- int retval;
- struct priv *pr = netdev_priv(dev);
-
- if (MCA_bus == 0) {
- return -ENODEV;
- }
- /* search through the slots for the 3c523. */
- slot = mca_find_adapter(ELMC_MCA_ID, 0);
- while (slot != -1) {
- status = mca_read_stored_pos(slot, 2);
-
- dev->irq=irq_table[(status & ELMC_STATUS_IRQ_SELECT) >> 6];
- dev->base_addr=csr_table[(status & ELMC_STATUS_CSR_SELECT) >> 1];
-
- /*
- If we're trying to match a specified irq or IO address,
- we'll reject a match unless it's what we're looking for.
- Also reject it if the card is already in use.
- */
-
- if ((irq && irq != dev->irq) ||
- (base_addr && base_addr != dev->base_addr)) {
- slot = mca_find_adapter(ELMC_MCA_ID, slot + 1);
- continue;
- }
- if (!request_region(dev->base_addr, ELMC_IO_EXTENT, DRV_NAME)) {
- slot = mca_find_adapter(ELMC_MCA_ID, slot + 1);
- continue;
- }
-
- /* found what we're looking for... */
- break;
- }
-
- /* we didn't find any 3c523 in the slots we checked for */
- if (slot == MCA_NOTFOUND)
- return (base_addr || irq) ? -ENXIO : -ENODEV;
-
- mca_set_adapter_name(slot, "3Com 3c523 Etherlink/MC");
- mca_set_adapter_procfn(slot, (MCA_ProcFn) elmc_getinfo, dev);
-
- /* if we get this far, adapter has been found - carry on */
- pr_info("%s: 3c523 adapter found in slot %d\n", dev->name, slot + 1);
-
- /* Now we extract configuration info from the card.
- The 3c523 provides information in two of the POS registers, but
- the second one is only needed if we want to tell the card what IRQ
- to use. I suspect that whoever sets the thing up initially would
- prefer we don't screw with those things.
-
- Note that we read the status info when we found the card...
-
- See 3c523.h for more details.
- */
-
- /* revision is stored in the first 4 bits of the revision register */
- revision = inb(dev->base_addr + ELMC_REVISION) & 0xf;
-
- /* according to docs, we read the interrupt and write it back to
- the IRQ select register, since the POST might not configure the IRQ
- properly. */
- switch (dev->irq) {
- case 3:
- mca_write_pos(slot, 3, 0x04);
- break;
- case 7:
- mca_write_pos(slot, 3, 0x02);
- break;
- case 9:
- mca_write_pos(slot, 3, 0x08);
- break;
- case 12:
- mca_write_pos(slot, 3, 0x01);
- break;
- }
-
- pr->slot = slot;
-
- pr_info("%s: 3Com 3c523 Rev 0x%x at %#lx\n", dev->name, (int) revision,
- dev->base_addr);
-
- /* Determine if we're using the on-board transceiver (i.e. coax) or
- an external one. The information is pretty much useless, but I
- guess it's worth brownie points. */
- dev->if_port = (status & ELMC_STATUS_DISABLE_THIN);
-
- /* The 3c523 has a 24K chunk of memory. The first 16K is the
- shared memory, while the last 8K is for the EtherStart BIOS ROM.
- Which we don't care much about here. We'll just tell Linux that
- we're using 16K. MCA won't permit address space conflicts caused
- by not mapping the other 8K. */
- dev->mem_start = shm_table[(status & ELMC_STATUS_MEMORY_SELECT) >> 3];
-
- /* We're using MCA, so it's a given that the information about memory
- size is correct. The Crynwr drivers do something like this. */
-
- elmc_id_reset586(); /* seems like a good idea before checking it... */
-
- size = 0x4000; /* check for 16K mem */
- if (!check586(dev, dev->mem_start, size)) {
- pr_err("%s: memprobe, Can't find memory at 0x%lx!\n", dev->name,
- dev->mem_start);
- retval = -ENODEV;
- goto err_out;
- }
- dev->mem_end = dev->mem_start + size; /* set mem_end showed by 'ifconfig' */
-
- pr->memtop = isa_bus_to_virt(dev->mem_start) + size;
- pr->base = (unsigned long) isa_bus_to_virt(dev->mem_start) + size - 0x01000000;
- alloc586(dev);
-
- elmc_id_reset586(); /* make sure it doesn't generate spurious ints */
-
- /* set number of receive-buffs according to memsize */
- pr->num_recv_buffs = NUM_RECV_BUFFS_16;
-
- /* dump all the assorted information */
- pr_info("%s: IRQ %d, %sternal xcvr, memory %#lx-%#lx.\n", dev->name,
- dev->irq, dev->if_port ? "ex" : "in",
- dev->mem_start, dev->mem_end - 1);
-
- /* The hardware address for the 3c523 is stored in the first six
- bytes of the IO address. */
- for (i = 0; i < 6; i++)
- dev->dev_addr[i] = inb(dev->base_addr + i);
-
- pr_info("%s: hardware address %pM\n",
- dev->name, dev->dev_addr);
-
- dev->netdev_ops = &netdev_ops;
- dev->watchdog_timeo = HZ;
- dev->ethtool_ops = &netdev_ethtool_ops;
-
- /* note that we haven't actually requested the IRQ from the kernel.
- That gets done in elmc_open(). I'm not sure that's such a good idea,
- but it works, so I'll go with it. */
-
-#ifndef ELMC_MULTICAST
- dev->flags&=~IFF_MULTICAST; /* Multicast doesn't work */
-#endif
-
- retval = register_netdev(dev);
- if (retval)
- goto err_out;
-
- return 0;
-err_out:
- mca_set_adapter_procfn(slot, NULL, NULL);
- release_region(dev->base_addr, ELMC_IO_EXTENT);
- return retval;
-}
-
-#ifdef MODULE
-static void cleanup_card(struct net_device *dev)
-{
- mca_set_adapter_procfn(((struct priv *)netdev_priv(dev))->slot,
- NULL, NULL);
- release_region(dev->base_addr, ELMC_IO_EXTENT);
-}
-#else
-struct net_device * __init elmc_probe(int unit)
-{
- struct net_device *dev = alloc_etherdev(sizeof(struct priv));
- int err;
-
- if (!dev)
- return ERR_PTR(-ENOMEM);
-
- sprintf(dev->name, "eth%d", unit);
- netdev_boot_setup_check(dev);
-
- err = do_elmc_probe(dev);
- if (err)
- goto out;
- return dev;
-out:
- free_netdev(dev);
- return ERR_PTR(err);
-}
-#endif
-
-/**********************************************
- * init the chip (elmc-interrupt should be disabled?!)
- * needs a correct 'allocated' memory
- */
-
-static int init586(struct net_device *dev)
-{
- void *ptr;
- unsigned long s;
- int i, result = 0;
- struct priv *p = netdev_priv(dev);
- volatile struct configure_cmd_struct *cfg_cmd;
- volatile struct iasetup_cmd_struct *ias_cmd;
- volatile struct tdr_cmd_struct *tdr_cmd;
- volatile struct mcsetup_cmd_struct *mc_cmd;
- struct netdev_hw_addr *ha;
- int num_addrs = netdev_mc_count(dev);
-
- ptr = (void *) ((char *) p->scb + sizeof(struct scb_struct));
-
- cfg_cmd = (struct configure_cmd_struct *) ptr; /* configure-command */
- cfg_cmd->cmd_status = 0;
- cfg_cmd->cmd_cmd = CMD_CONFIGURE | CMD_LAST;
- cfg_cmd->cmd_link = 0xffff;
-
- cfg_cmd->byte_cnt = 0x0a; /* number of cfg bytes */
- cfg_cmd->fifo = 0x08; /* fifo-limit (8=tx:32/rx:64) */
- cfg_cmd->sav_bf = 0x40; /* hold or discard bad recv frames (bit 7) */
- cfg_cmd->adr_len = 0x2e; /* addr_len |!src_insert |pre-len |loopback */
- cfg_cmd->priority = 0x00;
- cfg_cmd->ifs = 0x60;
- cfg_cmd->time_low = 0x00;
- cfg_cmd->time_high = 0xf2;
- cfg_cmd->promisc = 0;
- if (dev->flags & (IFF_ALLMULTI | IFF_PROMISC))
- cfg_cmd->promisc = 1;
- cfg_cmd->carr_coll = 0x00;
-
- p->scb->cbl_offset = make16(cfg_cmd);
-
- p->scb->cmd = CUC_START; /* cmd.-unit start */
- elmc_id_attn586();
-
- s = jiffies; /* warning: only active with interrupts on !! */
- while (!(cfg_cmd->cmd_status & STAT_COMPL)) {
- if (time_after(jiffies, s + 30*HZ/100))
- break;
- }
-
- if ((cfg_cmd->cmd_status & (STAT_OK | STAT_COMPL)) != (STAT_COMPL | STAT_OK)) {
- pr_warning("%s (elmc): configure command failed: %x\n", dev->name, cfg_cmd->cmd_status);
- return 1;
- }
- /*
- * individual address setup
- */
- ias_cmd = (struct iasetup_cmd_struct *) ptr;
-
- ias_cmd->cmd_status = 0;
- ias_cmd->cmd_cmd = CMD_IASETUP | CMD_LAST;
- ias_cmd->cmd_link = 0xffff;
-
- memcpy((char *) &ias_cmd->iaddr, (char *) dev->dev_addr, ETH_ALEN);
-
- p->scb->cbl_offset = make16(ias_cmd);
-
- p->scb->cmd = CUC_START; /* cmd.-unit start */
- elmc_id_attn586();
-
- s = jiffies;
- while (!(ias_cmd->cmd_status & STAT_COMPL)) {
- if (time_after(jiffies, s + 30*HZ/100))
- break;
- }
-
- if ((ias_cmd->cmd_status & (STAT_OK | STAT_COMPL)) != (STAT_OK | STAT_COMPL)) {
- pr_warning("%s (elmc): individual address setup command failed: %04x\n",
- dev->name, ias_cmd->cmd_status);
- return 1;
- }
- /*
- * TDR, wire check .. e.g. no resistor e.t.c
- */
- tdr_cmd = (struct tdr_cmd_struct *) ptr;
-
- tdr_cmd->cmd_status = 0;
- tdr_cmd->cmd_cmd = CMD_TDR | CMD_LAST;
- tdr_cmd->cmd_link = 0xffff;
- tdr_cmd->status = 0;
-
- p->scb->cbl_offset = make16(tdr_cmd);
-
- p->scb->cmd = CUC_START; /* cmd.-unit start */
- elmc_attn586();
-
- s = jiffies;
- while (!(tdr_cmd->cmd_status & STAT_COMPL)) {
- if (time_after(jiffies, s + 30*HZ/100)) {
- pr_warning("%s: %d Problems while running the TDR.\n", dev->name, __LINE__);
- result = 1;
- break;
- }
- }
-
- if (!result) {
- DELAY(2); /* wait for result */
- result = tdr_cmd->status;
-
- p->scb->cmd = p->scb->status & STAT_MASK;
- elmc_id_attn586(); /* ack the interrupts */
-
- if (result & TDR_LNK_OK) {
- /* empty */
- } else if (result & TDR_XCVR_PRB) {
- pr_warning("%s: TDR: Transceiver problem!\n", dev->name);
- } else if (result & TDR_ET_OPN) {
- pr_warning("%s: TDR: No correct termination %d clocks away.\n", dev->name, result & TDR_TIMEMASK);
- } else if (result & TDR_ET_SRT) {
- if (result & TDR_TIMEMASK) /* time == 0 -> strange :-) */
- pr_warning("%s: TDR: Detected a short circuit %d clocks away.\n", dev->name, result & TDR_TIMEMASK);
- } else {
- pr_warning("%s: TDR: Unknown status %04x\n", dev->name, result);
- }
- }
- /*
- * ack interrupts
- */
- p->scb->cmd = p->scb->status & STAT_MASK;
- elmc_id_attn586();
-
- /*
- * alloc nop/xmit-cmds
- */
-#if (NUM_XMIT_BUFFS == 1)
- for (i = 0; i < 2; i++) {
- p->nop_cmds[i] = (struct nop_cmd_struct *) ptr;
- p->nop_cmds[i]->cmd_cmd = CMD_NOP;
- p->nop_cmds[i]->cmd_status = 0;
- p->nop_cmds[i]->cmd_link = make16((p->nop_cmds[i]));
- ptr = (char *) ptr + sizeof(struct nop_cmd_struct);
- }
- p->xmit_cmds[0] = (struct transmit_cmd_struct *) ptr; /* transmit cmd/buff 0 */
- ptr = (char *) ptr + sizeof(struct transmit_cmd_struct);
-#else
- for (i = 0; i < NUM_XMIT_BUFFS; i++) {
- p->nop_cmds[i] = (struct nop_cmd_struct *) ptr;
- p->nop_cmds[i]->cmd_cmd = CMD_NOP;
- p->nop_cmds[i]->cmd_status = 0;
- p->nop_cmds[i]->cmd_link = make16((p->nop_cmds[i]));
- ptr = (char *) ptr + sizeof(struct nop_cmd_struct);
- p->xmit_cmds[i] = (struct transmit_cmd_struct *) ptr; /*transmit cmd/buff 0 */
- ptr = (char *) ptr + sizeof(struct transmit_cmd_struct);
- }
-#endif
-
- ptr = alloc_rfa(dev, (void *) ptr); /* init receive-frame-area */
-
- /*
- * Multicast setup
- */
-
- if (num_addrs) {
- /* I don't understand this: do we really need memory after the init? */
- int len = ((char *) p->iscp - (char *) ptr - 8) / 6;
- if (len <= 0) {
- pr_err("%s: Ooooops, no memory for MC-Setup!\n", dev->name);
- } else {
- if (len < num_addrs) {
- num_addrs = len;
- pr_warning("%s: Sorry, can only apply %d MC-Address(es).\n",
- dev->name, num_addrs);
- }
- mc_cmd = (struct mcsetup_cmd_struct *) ptr;
- mc_cmd->cmd_status = 0;
- mc_cmd->cmd_cmd = CMD_MCSETUP | CMD_LAST;
- mc_cmd->cmd_link = 0xffff;
- mc_cmd->mc_cnt = num_addrs * 6;
- i = 0;
- netdev_for_each_mc_addr(ha, dev)
- memcpy((char *) mc_cmd->mc_list[i++],
- ha->addr, 6);
- p->scb->cbl_offset = make16(mc_cmd);
- p->scb->cmd = CUC_START;
- elmc_id_attn586();
- s = jiffies;
- while (!(mc_cmd->cmd_status & STAT_COMPL)) {
- if (time_after(jiffies, s + 30*HZ/100))
- break;
- }
- if (!(mc_cmd->cmd_status & STAT_COMPL)) {
- pr_warning("%s: Can't apply multicast-address-list.\n", dev->name);
- }
- }
- }
- /*
- * alloc xmit-buffs / init xmit_cmds
- */
- for (i = 0; i < NUM_XMIT_BUFFS; i++) {
- p->xmit_cbuffs[i] = (char *) ptr; /* char-buffs */
- ptr = (char *) ptr + XMIT_BUFF_SIZE;
- p->xmit_buffs[i] = (struct tbd_struct *) ptr; /* TBD */
- ptr = (char *) ptr + sizeof(struct tbd_struct);
- if ((void *) ptr > (void *) p->iscp) {
- pr_err("%s: not enough shared-mem for your configuration!\n", dev->name);
- return 1;
- }
- memset((char *) (p->xmit_cmds[i]), 0, sizeof(struct transmit_cmd_struct));
- memset((char *) (p->xmit_buffs[i]), 0, sizeof(struct tbd_struct));
- p->xmit_cmds[i]->cmd_status = STAT_COMPL;
- p->xmit_cmds[i]->cmd_cmd = CMD_XMIT | CMD_INT;
- p->xmit_cmds[i]->tbd_offset = make16((p->xmit_buffs[i]));
- p->xmit_buffs[i]->next = 0xffff;
- p->xmit_buffs[i]->buffer = make24((p->xmit_cbuffs[i]));
- }
-
- p->xmit_count = 0;
- p->xmit_last = 0;
-#ifndef NO_NOPCOMMANDS
- p->nop_point = 0;
-#endif
-
- /*
- * 'start transmitter' (nop-loop)
- */
-#ifndef NO_NOPCOMMANDS
- p->scb->cbl_offset = make16(p->nop_cmds[0]);
- p->scb->cmd = CUC_START;
- elmc_id_attn586();
- WAIT_4_SCB_CMD();
-#else
- p->xmit_cmds[0]->cmd_link = 0xffff;
- p->xmit_cmds[0]->cmd_cmd = CMD_XMIT | CMD_LAST | CMD_INT;
-#endif
-
- return 0;
-}
-
-/******************************************************
- * This is a helper routine for elmc_rnr_int() and init586().
- * It sets up the Receive Frame Area (RFA).
- */
-
-static void *alloc_rfa(struct net_device *dev, void *ptr)
-{
- volatile struct rfd_struct *rfd = (struct rfd_struct *) ptr;
- volatile struct rbd_struct *rbd;
- int i;
- struct priv *p = netdev_priv(dev);
-
- memset((char *) rfd, 0, sizeof(struct rfd_struct) * p->num_recv_buffs);
- p->rfd_first = rfd;
-
- for (i = 0; i < p->num_recv_buffs; i++) {
- rfd[i].next = make16(rfd + (i + 1) % p->num_recv_buffs);
- }
- rfd[p->num_recv_buffs - 1].last = RFD_SUSP; /* RU suspend */
-
- ptr = (void *) (rfd + p->num_recv_buffs);
-
- rbd = (struct rbd_struct *) ptr;
- ptr = (void *) (rbd + p->num_recv_buffs);
-
- /* clr descriptors */
- memset((char *) rbd, 0, sizeof(struct rbd_struct) * p->num_recv_buffs);
-
- for (i = 0; i < p->num_recv_buffs; i++) {
- rbd[i].next = make16((rbd + (i + 1) % p->num_recv_buffs));
- rbd[i].size = RECV_BUFF_SIZE;
- rbd[i].buffer = make24(ptr);
- ptr = (char *) ptr + RECV_BUFF_SIZE;
- }
-
- p->rfd_top = p->rfd_first;
- p->rfd_last = p->rfd_first + p->num_recv_buffs - 1;
-
- p->scb->rfa_offset = make16(p->rfd_first);
- p->rfd_first->rbd_offset = make16(rbd);
-
- return ptr;
-}
-
-
-/**************************************************
- * Interrupt Handler ...
- */
-
-static irqreturn_t
-elmc_interrupt(int irq, void *dev_id)
-{
- struct net_device *dev = dev_id;
- unsigned short stat;
- struct priv *p;
-
- if (!netif_running(dev)) {
- /* The 3c523 has this habit of generating interrupts during the
- reset. I'm not sure if the ni52 has this same problem, but it's
- really annoying if we haven't finished initializing it. I was
- hoping all the elmc_id_* commands would disable this, but I
- might have missed a few. */
-
- elmc_id_attn586(); /* ack inter. and disable any more */
- return IRQ_HANDLED;
- } else if (!(ELMC_CTRL_INT & inb(dev->base_addr + ELMC_CTRL))) {
- /* wasn't this device */
- return IRQ_NONE;
- }
- /* reading ELMC_CTRL also clears the INT bit. */
-
- p = netdev_priv(dev);
-
- while ((stat = p->scb->status & STAT_MASK))
- {
- p->scb->cmd = stat;
- elmc_attn586(); /* ack inter. */
-
- if (stat & STAT_CX) {
- /* command with I-bit set complete */
- elmc_xmt_int(dev);
- }
- if (stat & STAT_FR) {
- /* received a frame */
- elmc_rcv_int(dev);
- }
-#ifndef NO_NOPCOMMANDS
- if (stat & STAT_CNA) {
- /* CU went 'not ready' */
- if (netif_running(dev)) {
- pr_warning("%s: oops! CU has left active state. stat: %04x/%04x.\n",
- dev->name, (int) stat, (int) p->scb->status);
- }
- }
-#endif
-
- if (stat & STAT_RNR) {
- /* RU went 'not ready' */
-
- if (p->scb->status & RU_SUSPEND) {
- /* special case: RU_SUSPEND */
-
- WAIT_4_SCB_CMD();
- p->scb->cmd = RUC_RESUME;
- elmc_attn586();
- } else {
- pr_warning("%s: Receiver-Unit went 'NOT READY': %04x/%04x.\n",
- dev->name, (int) stat, (int) p->scb->status);
- elmc_rnr_int(dev);
- }
- }
- WAIT_4_SCB_CMD(); /* wait for ack. (elmc_xmt_int can be faster than ack!!) */
- if (p->scb->cmd) { /* timed out? */
- break;
- }
- }
- return IRQ_HANDLED;
-}
-
-/*******************************************************
- * receive-interrupt
- */
-
-static void elmc_rcv_int(struct net_device *dev)
-{
- int status;
- unsigned short totlen;
- struct sk_buff *skb;
- struct rbd_struct *rbd;
- struct priv *p = netdev_priv(dev);
-
- for (; (status = p->rfd_top->status) & STAT_COMPL;) {
- rbd = (struct rbd_struct *) make32(p->rfd_top->rbd_offset);
-
- if (status & STAT_OK) { /* frame received without error? */
- if ((totlen = rbd->status) & RBD_LAST) { /* the first and the last buffer? */
- totlen &= RBD_MASK; /* length of this frame */
- rbd->status = 0;
- skb = (struct sk_buff *) dev_alloc_skb(totlen + 2);
- if (skb != NULL) {
- skb_reserve(skb, 2); /* 16 byte alignment */
- skb_put(skb,totlen);
- skb_copy_to_linear_data(skb, (char *) p->base+(unsigned long) rbd->buffer,totlen);
- skb->protocol = eth_type_trans(skb, dev);
- netif_rx(skb);
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += totlen;
- } else {
- dev->stats.rx_dropped++;
- }
- } else {
- pr_warning("%s: received oversized frame.\n", dev->name);
- dev->stats.rx_dropped++;
- }
- } else { /* frame !(ok), only with 'save-bad-frames' */
- pr_warning("%s: oops! rfd-error-status: %04x\n", dev->name, status);
- dev->stats.rx_errors++;
- }
- p->rfd_top->status = 0;
- p->rfd_top->last = RFD_SUSP;
- p->rfd_last->last = 0; /* delete RU_SUSP */
- p->rfd_last = p->rfd_top;
- p->rfd_top = (struct rfd_struct *) make32(p->rfd_top->next); /* step to next RFD */
- }
-}
-
-/**********************************************************
- * handle 'Receiver went not ready'.
- */
-
-static void elmc_rnr_int(struct net_device *dev)
-{
- struct priv *p = netdev_priv(dev);
-
- dev->stats.rx_errors++;
-
- WAIT_4_SCB_CMD(); /* wait for the last cmd */
- p->scb->cmd = RUC_ABORT; /* usually the RU is in the 'no resource'-state .. abort it now. */
- elmc_attn586();
- WAIT_4_SCB_CMD(); /* wait for accept cmd. */
-
- alloc_rfa(dev, (char *) p->rfd_first);
- startrecv586(dev); /* restart RU */
-
- pr_warning("%s: Receive-Unit restarted. Status: %04x\n", dev->name, p->scb->status);
-
-}
-
-/**********************************************************
- * handle xmit - interrupt
- */
-
-static void elmc_xmt_int(struct net_device *dev)
-{
- int status;
- struct priv *p = netdev_priv(dev);
-
- status = p->xmit_cmds[p->xmit_last]->cmd_status;
- if (!(status & STAT_COMPL)) {
- pr_warning("%s: strange .. xmit-int without a 'COMPLETE'\n", dev->name);
- }
- if (status & STAT_OK) {
- dev->stats.tx_packets++;
- dev->stats.collisions += (status & TCMD_MAXCOLLMASK);
- } else {
- dev->stats.tx_errors++;
- if (status & TCMD_LATECOLL) {
- pr_warning("%s: late collision detected.\n", dev->name);
- dev->stats.collisions++;
- } else if (status & TCMD_NOCARRIER) {
- dev->stats.tx_carrier_errors++;
- pr_warning("%s: no carrier detected.\n", dev->name);
- } else if (status & TCMD_LOSTCTS) {
- pr_warning("%s: loss of CTS detected.\n", dev->name);
- } else if (status & TCMD_UNDERRUN) {
- dev->stats.tx_fifo_errors++;
- pr_warning("%s: DMA underrun detected.\n", dev->name);
- } else if (status & TCMD_MAXCOLL) {
- pr_warning("%s: Max. collisions exceeded.\n", dev->name);
- dev->stats.collisions += 16;
- }
- }
-
-#if (NUM_XMIT_BUFFS != 1)
- if ((++p->xmit_last) == NUM_XMIT_BUFFS) {
- p->xmit_last = 0;
- }
-#endif
-
- netif_wake_queue(dev);
-}
-
-/***********************************************************
- * (re)start the receiver
- */
-
-static void startrecv586(struct net_device *dev)
-{
- struct priv *p = netdev_priv(dev);
-
- p->scb->rfa_offset = make16(p->rfd_first);
- p->scb->cmd = RUC_START;
- elmc_attn586(); /* start cmd. */
- WAIT_4_SCB_CMD(); /* wait for accept cmd. (no timeout!!) */
-}
-
-/******************************************************
- * timeout
- */
-
-static void elmc_timeout(struct net_device *dev)
-{
- struct priv *p = netdev_priv(dev);
- /* COMMAND-UNIT active? */
- if (p->scb->status & CU_ACTIVE) {
- pr_debug("%s: strange ... timeout with CU active?!?\n", dev->name);
- pr_debug("%s: X0: %04x N0: %04x N1: %04x %d\n", dev->name,
- (int)p->xmit_cmds[0]->cmd_status,
- (int)p->nop_cmds[0]->cmd_status,
- (int)p->nop_cmds[1]->cmd_status, (int)p->nop_point);
- p->scb->cmd = CUC_ABORT;
- elmc_attn586();
- WAIT_4_SCB_CMD();
- p->scb->cbl_offset = make16(p->nop_cmds[p->nop_point]);
- p->scb->cmd = CUC_START;
- elmc_attn586();
- WAIT_4_SCB_CMD();
- netif_wake_queue(dev);
- } else {
- pr_debug("%s: xmitter timed out, try to restart! stat: %04x\n",
- dev->name, p->scb->status);
- pr_debug("%s: command-stats: %04x %04x\n", dev->name,
- p->xmit_cmds[0]->cmd_status, p->xmit_cmds[1]->cmd_status);
- elmc_close(dev);
- elmc_open(dev);
- }
-}
-
-/******************************************************
- * send frame
- */
-
-static netdev_tx_t elmc_send_packet(struct sk_buff *skb, struct net_device *dev)
-{
- int len;
- int i;
-#ifndef NO_NOPCOMMANDS
- int next_nop;
-#endif
- struct priv *p = netdev_priv(dev);
-
- netif_stop_queue(dev);
-
- len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
-
- if (len != skb->len)
- memset((char *) p->xmit_cbuffs[p->xmit_count], 0, ETH_ZLEN);
- skb_copy_from_linear_data(skb, (char *) p->xmit_cbuffs[p->xmit_count], skb->len);
-
-#if (NUM_XMIT_BUFFS == 1)
-#ifdef NO_NOPCOMMANDS
- p->xmit_buffs[0]->size = TBD_LAST | len;
- for (i = 0; i < 16; i++) {
- p->scb->cbl_offset = make16(p->xmit_cmds[0]);
- p->scb->cmd = CUC_START;
- p->xmit_cmds[0]->cmd_status = 0;
- elmc_attn586();
- if (!i) {
- dev_kfree_skb(skb);
- }
- WAIT_4_SCB_CMD();
- if ((p->scb->status & CU_ACTIVE)) { /* test it, because CU sometimes doesn't start immediately */
- break;
- }
- if (p->xmit_cmds[0]->cmd_status) {
- break;
- }
- if (i == 15) {
- pr_warning("%s: Can't start transmit-command.\n", dev->name);
- }
- }
-#else
- next_nop = (p->nop_point + 1) & 0x1;
- p->xmit_buffs[0]->size = TBD_LAST | len;
-
- p->xmit_cmds[0]->cmd_link = p->nop_cmds[next_nop]->cmd_link
- = make16((p->nop_cmds[next_nop]));
- p->xmit_cmds[0]->cmd_status = p->nop_cmds[next_nop]->cmd_status = 0;
-
- p->nop_cmds[p->nop_point]->cmd_link = make16((p->xmit_cmds[0]));
- p->nop_point = next_nop;
- dev_kfree_skb(skb);
-#endif
-#else
- p->xmit_buffs[p->xmit_count]->size = TBD_LAST | len;
- if ((next_nop = p->xmit_count + 1) == NUM_XMIT_BUFFS) {
- next_nop = 0;
- }
- p->xmit_cmds[p->xmit_count]->cmd_status = 0;
- p->xmit_cmds[p->xmit_count]->cmd_link = p->nop_cmds[next_nop]->cmd_link
- = make16((p->nop_cmds[next_nop]));
- p->nop_cmds[next_nop]->cmd_status = 0;
- p->nop_cmds[p->xmit_count]->cmd_link = make16((p->xmit_cmds[p->xmit_count]));
- p->xmit_count = next_nop;
- if (p->xmit_count != p->xmit_last)
- netif_wake_queue(dev);
- dev_kfree_skb(skb);
-#endif
- return NETDEV_TX_OK;
-}
-
-/*******************************************
- * Someone wanna have the statistics
- */
-
-static struct net_device_stats *elmc_get_stats(struct net_device *dev)
-{
- struct priv *p = netdev_priv(dev);
- unsigned short crc, aln, rsc, ovrn;
-
- crc = p->scb->crc_errs; /* get error-statistic from the ni82586 */
- p->scb->crc_errs -= crc;
- aln = p->scb->aln_errs;
- p->scb->aln_errs -= aln;
- rsc = p->scb->rsc_errs;
- p->scb->rsc_errs -= rsc;
- ovrn = p->scb->ovrn_errs;
- p->scb->ovrn_errs -= ovrn;
-
- dev->stats.rx_crc_errors += crc;
- dev->stats.rx_fifo_errors += ovrn;
- dev->stats.rx_frame_errors += aln;
- dev->stats.rx_dropped += rsc;
-
- return &dev->stats;
-}
-
-/********************************************************
- * Set MC list ..
- */
-
-#ifdef ELMC_MULTICAST
-static void set_multicast_list(struct net_device *dev)
-{
- if (!dev->start) {
- /* without a running interface, promiscuous doesn't work */
- return;
- }
- dev->start = 0;
- alloc586(dev);
- init586(dev);
- startrecv586(dev);
- dev->start = 1;
-}
-#endif
-
-static void netdev_get_drvinfo(struct net_device *dev,
- struct ethtool_drvinfo *info)
-{
- strcpy(info->driver, DRV_NAME);
- strcpy(info->version, DRV_VERSION);
- sprintf(info->bus_info, "MCA 0x%lx", dev->base_addr);
-}
-
-static const struct ethtool_ops netdev_ethtool_ops = {
- .get_drvinfo = netdev_get_drvinfo,
-};
-
-#ifdef MODULE
-
-/* Increase if needed ;) */
-#define MAX_3C523_CARDS 4
-
-static struct net_device *dev_elmc[MAX_3C523_CARDS];
-static int irq[MAX_3C523_CARDS];
-static int io[MAX_3C523_CARDS];
-module_param_array(irq, int, NULL, 0);
-module_param_array(io, int, NULL, 0);
-MODULE_PARM_DESC(io, "EtherLink/MC I/O base address(es)");
-MODULE_PARM_DESC(irq, "EtherLink/MC IRQ number(s)");
-MODULE_LICENSE("GPL");
-
-int __init init_module(void)
-{
- int this_dev,found = 0;
-
- /* Loop until we either can't find any more cards, or we have MAX_3C523_CARDS */
- for(this_dev=0; this_dev<MAX_3C523_CARDS; this_dev++) {
- struct net_device *dev = alloc_etherdev(sizeof(struct priv));
- if (!dev)
- break;
- dev->irq=irq[this_dev];
- dev->base_addr=io[this_dev];
- if (do_elmc_probe(dev) == 0) {
- dev_elmc[this_dev] = dev;
- found++;
- continue;
- }
- free_netdev(dev);
- if (io[this_dev]==0)
- break;
- pr_warning("3c523.c: No 3c523 card found at io=%#x\n",io[this_dev]);
- }
-
- if(found==0) {
- if (io[0]==0)
- pr_notice("3c523.c: No 3c523 cards found\n");
- return -ENXIO;
- } else return 0;
-}
-
-void __exit cleanup_module(void)
-{
- int this_dev;
- for (this_dev=0; this_dev<MAX_3C523_CARDS; this_dev++) {
- struct net_device *dev = dev_elmc[this_dev];
- if (dev) {
- unregister_netdev(dev);
- cleanup_card(dev);
- free_netdev(dev);
- }
- }
-}
-
-#endif /* MODULE */
+++ /dev/null
-#ifndef _3c523_INCLUDE_
-#define _3c523_INCLUDE_
-/*
- This is basically a hacked version of ni52.h, for the 3c523
- Etherlink/MC.
-*/
-
-/*
- * Intel i82586 Ethernet definitions
- *
- * This is an extension to the Linux operating system, and is covered by the
- * same GNU General Public License that covers that work.
- *
- * Copyright 1995 by Chris Beauregard (cpbeaure@undergrad.math.uwaterloo.ca)
- *
- * See 3c523.c for details.
- *
- * $Header: /home/chrisb/linux-1.2.13-3c523/drivers/net/RCS/3c523.h,v 1.6 1996/01/20 05:09:00 chrisb Exp chrisb $
- */
-
-/*
- * where to find the System Configuration Pointer (SCP)
- */
-#define SCP_DEFAULT_ADDRESS 0xfffff4
-
-
-/*
- * System Configuration Pointer Struct
- */
-
-struct scp_struct
-{
- unsigned short zero_dum0; /* has to be zero */
- unsigned char sysbus; /* 0=16Bit,1=8Bit */
- unsigned char zero_dum1; /* has to be zero for 586 */
- unsigned short zero_dum2;
- unsigned short zero_dum3;
- char *iscp; /* pointer to the iscp-block */
-};
-
-
-/*
- * Intermediate System Configuration Pointer (ISCP)
- */
-struct iscp_struct
-{
- unsigned char busy; /* 586 clears after successful init */
- unsigned char zero_dummy; /* hast to be zero */
- unsigned short scb_offset; /* pointeroffset to the scb_base */
- char *scb_base; /* base-address of all 16-bit offsets */
-};
-
-/*
- * System Control Block (SCB)
- */
-struct scb_struct
-{
- unsigned short status; /* status word */
- unsigned short cmd; /* command word */
- unsigned short cbl_offset; /* pointeroffset, command block list */
- unsigned short rfa_offset; /* pointeroffset, receive frame area */
- unsigned short crc_errs; /* CRC-Error counter */
- unsigned short aln_errs; /* alignmenterror counter */
- unsigned short rsc_errs; /* Resourceerror counter */
- unsigned short ovrn_errs; /* OVerrunerror counter */
-};
-
-/*
- * possible command values for the command word
- */
-#define RUC_MASK 0x0070 /* mask for RU commands */
-#define RUC_NOP 0x0000 /* NOP-command */
-#define RUC_START 0x0010 /* start RU */
-#define RUC_RESUME 0x0020 /* resume RU after suspend */
-#define RUC_SUSPEND 0x0030 /* suspend RU */
-#define RUC_ABORT 0x0040 /* abort receiver operation immediately */
-
-#define CUC_MASK 0x0700 /* mask for CU command */
-#define CUC_NOP 0x0000 /* NOP-command */
-#define CUC_START 0x0100 /* start execution of 1. cmd on the CBL */
-#define CUC_RESUME 0x0200 /* resume after suspend */
-#define CUC_SUSPEND 0x0300 /* Suspend CU */
-#define CUC_ABORT 0x0400 /* abort command operation immediately */
-
-#define ACK_MASK 0xf000 /* mask for ACK command */
-#define ACK_CX 0x8000 /* acknowledges STAT_CX */
-#define ACK_FR 0x4000 /* ack. STAT_FR */
-#define ACK_CNA 0x2000 /* ack. STAT_CNA */
-#define ACK_RNR 0x1000 /* ack. STAT_RNR */
-
-/*
- * possible status values for the status word
- */
-#define STAT_MASK 0xf000 /* mask for cause of interrupt */
-#define STAT_CX 0x8000 /* CU finished cmd with its I bit set */
-#define STAT_FR 0x4000 /* RU finished receiving a frame */
-#define STAT_CNA 0x2000 /* CU left active state */
-#define STAT_RNR 0x1000 /* RU left ready state */
-
-#define CU_STATUS 0x700 /* CU status, 0=idle */
-#define CU_SUSPEND 0x100 /* CU is suspended */
-#define CU_ACTIVE 0x200 /* CU is active */
-
-#define RU_STATUS 0x70 /* RU status, 0=idle */
-#define RU_SUSPEND 0x10 /* RU suspended */
-#define RU_NOSPACE 0x20 /* RU no resources */
-#define RU_READY 0x40 /* RU is ready */
-
-/*
- * Receive Frame Descriptor (RFD)
- */
-struct rfd_struct
-{
- unsigned short status; /* status word */
- unsigned short last; /* Bit15,Last Frame on List / Bit14,suspend */
- unsigned short next; /* linkoffset to next RFD */
- unsigned short rbd_offset; /* pointeroffset to RBD-buffer */
- unsigned char dest[6]; /* ethernet-address, destination */
- unsigned char source[6]; /* ethernet-address, source */
- unsigned short length; /* 802.3 frame-length */
- unsigned short zero_dummy; /* dummy */
-};
-
-#define RFD_LAST 0x8000 /* last: last rfd in the list */
-#define RFD_SUSP 0x4000 /* last: suspend RU after */
-#define RFD_ERRMASK 0x0fe1 /* status: errormask */
-#define RFD_MATCHADD 0x0002 /* status: Destinationaddress !matches IA */
-#define RFD_RNR 0x0200 /* status: receiver out of resources */
-
-/*
- * Receive Buffer Descriptor (RBD)
- */
-struct rbd_struct
-{
- unsigned short status; /* status word,number of used bytes in buff */
- unsigned short next; /* pointeroffset to next RBD */
- char *buffer; /* receive buffer address pointer */
- unsigned short size; /* size of this buffer */
- unsigned short zero_dummy; /* dummy */
-};
-
-#define RBD_LAST 0x8000 /* last buffer */
-#define RBD_USED 0x4000 /* this buffer has data */
-#define RBD_MASK 0x3fff /* size-mask for length */
-
-/*
- * Statusvalues for Commands/RFD
- */
-#define STAT_COMPL 0x8000 /* status: frame/command is complete */
-#define STAT_BUSY 0x4000 /* status: frame/command is busy */
-#define STAT_OK 0x2000 /* status: frame/command is ok */
-
-/*
- * Action-Commands
- */
-#define CMD_NOP 0x0000 /* NOP */
-#define CMD_IASETUP 0x0001 /* initial address setup command */
-#define CMD_CONFIGURE 0x0002 /* configure command */
-#define CMD_MCSETUP 0x0003 /* MC setup command */
-#define CMD_XMIT 0x0004 /* transmit command */
-#define CMD_TDR 0x0005 /* time domain reflectometer (TDR) command */
-#define CMD_DUMP 0x0006 /* dump command */
-#define CMD_DIAGNOSE 0x0007 /* diagnose command */
-
-/*
- * Action command bits
- */
-#define CMD_LAST 0x8000 /* indicates last command in the CBL */
-#define CMD_SUSPEND 0x4000 /* suspend CU after this CB */
-#define CMD_INT 0x2000 /* generate interrupt after execution */
-
-/*
- * NOP - command
- */
-struct nop_cmd_struct
-{
- unsigned short cmd_status; /* status of this command */
- unsigned short cmd_cmd; /* the command itself (+bits) */
- unsigned short cmd_link; /* offsetpointer to next command */
-};
-
-/*
- * IA Setup command
- */
-struct iasetup_cmd_struct
-{
- unsigned short cmd_status;
- unsigned short cmd_cmd;
- unsigned short cmd_link;
- unsigned char iaddr[6];
-};
-
-/*
- * Configure command
- */
-struct configure_cmd_struct
-{
- unsigned short cmd_status;
- unsigned short cmd_cmd;
- unsigned short cmd_link;
- unsigned char byte_cnt; /* size of the config-cmd */
- unsigned char fifo; /* fifo/recv monitor */
- unsigned char sav_bf; /* save bad frames (bit7=1)*/
- unsigned char adr_len; /* adr_len(0-2),al_loc(3),pream(4-5),loopbak(6-7)*/
- unsigned char priority; /* lin_prio(0-2),exp_prio(4-6),bof_metd(7) */
- unsigned char ifs; /* inter frame spacing */
- unsigned char time_low; /* slot time low */
- unsigned char time_high; /* slot time high(0-2) and max. retries(4-7) */
- unsigned char promisc; /* promisc-mode(0) , et al (1-7) */
- unsigned char carr_coll; /* carrier(0-3)/collision(4-7) stuff */
- unsigned char fram_len; /* minimal frame len */
- unsigned char dummy; /* dummy */
-};
-
-/*
- * Multicast Setup command
- */
-struct mcsetup_cmd_struct
-{
- unsigned short cmd_status;
- unsigned short cmd_cmd;
- unsigned short cmd_link;
- unsigned short mc_cnt; /* number of bytes in the MC-List */
- unsigned char mc_list[0][6]; /* pointer to 6 bytes entries */
-};
-
-/*
- * transmit command
- */
-struct transmit_cmd_struct
-{
- unsigned short cmd_status;
- unsigned short cmd_cmd;
- unsigned short cmd_link;
- unsigned short tbd_offset; /* pointeroffset to TBD */
- unsigned char dest[6]; /* destination address of the frame */
- unsigned short length; /* user defined: 802.3 length / Ether type */
-};
-
-#define TCMD_ERRMASK 0x0fa0
-#define TCMD_MAXCOLLMASK 0x000f
-#define TCMD_MAXCOLL 0x0020
-#define TCMD_HEARTBEAT 0x0040
-#define TCMD_DEFERRED 0x0080
-#define TCMD_UNDERRUN 0x0100
-#define TCMD_LOSTCTS 0x0200
-#define TCMD_NOCARRIER 0x0400
-#define TCMD_LATECOLL 0x0800
-
-struct tdr_cmd_struct
-{
- unsigned short cmd_status;
- unsigned short cmd_cmd;
- unsigned short cmd_link;
- unsigned short status;
-};
-
-#define TDR_LNK_OK 0x8000 /* No link problem identified */
-#define TDR_XCVR_PRB 0x4000 /* indicates a transceiver problem */
-#define TDR_ET_OPN 0x2000 /* open, no correct termination */
-#define TDR_ET_SRT 0x1000 /* TDR detected a short circuit */
-#define TDR_TIMEMASK 0x07ff /* mask for the time field */
-
-/*
- * Transmit Buffer Descriptor (TBD)
- */
-struct tbd_struct
-{
- unsigned short size; /* size + EOF-Flag(15) */
- unsigned short next; /* pointeroffset to next TBD */
- char *buffer; /* pointer to buffer */
-};
-
-#define TBD_LAST 0x8000 /* EOF-Flag, indicates last buffer in list */
-
-/*************************************************************************/
-/*
-Verbatim from the Crynwyr stuff:
-
- The 3c523 responds with adapter code 0x6042 at slot
-registers xxx0 and xxx1. The setup register is at xxx2 and
-contains the following bits:
-
-0: card enable
-2,1: csr address select
- 00 = 0300
- 01 = 1300
- 10 = 2300
- 11 = 3300
-4,3: shared memory address select
- 00 = 0c0000
- 01 = 0c8000
- 10 = 0d0000
- 11 = 0d8000
-5: set to disable on-board thinnet
-7,6: (read-only) shows selected irq
- 00 = 12
- 01 = 7
- 10 = 3
- 11 = 9
-
-The interrupt-select register is at xxx3 and uses one bit per irq.
-
-0: int 12
-1: int 7
-2: int 3
-3: int 9
-
- Again, the documentation stresses that the setup register
-should never be written. The interrupt-select register may be
-written with the value corresponding to bits 7.6 in
-the setup register to insure corret setup.
-*/
-
-/* Offsets from the base I/O address. */
-#define ELMC_SA 0 /* first 6 bytes are IEEE network address */
-#define ELMC_CTRL 6 /* control & status register */
-#define ELMC_REVISION 7 /* revision register, first 4 bits only */
-#define ELMC_IO_EXTENT 8
-
-/* these are the bit selects for the port register 2 */
-#define ELMC_STATUS_ENABLED 0x01
-#define ELMC_STATUS_CSR_SELECT 0x06
-#define ELMC_STATUS_MEMORY_SELECT 0x18
-#define ELMC_STATUS_DISABLE_THIN 0x20
-#define ELMC_STATUS_IRQ_SELECT 0xc0
-
-/* this is the card id used in the detection code. You might recognize
-it from @6042.adf */
-#define ELMC_MCA_ID 0x6042
-
-/*
- The following define the bits for the control & status register
-
- The bank select registers can be used if more than 16K of memory is
- on the card. For some stupid reason, bank 3 is the one for the
- bottom 16K, and the card defaults to bank 0. So we have to set the
- bank to 3 before the card will even think of operating. To get bank
- 3, set BS0 and BS1 to high (of course...)
-*/
-#define ELMC_CTRL_BS0 0x01 /* RW bank select */
-#define ELMC_CTRL_BS1 0x02 /* RW bank select */
-#define ELMC_CTRL_INTE 0x04 /* RW interrupt enable, assert high */
-#define ELMC_CTRL_INT 0x08 /* R interrupt active, assert high */
-/*#define ELMC_CTRL_* 0x10*/ /* reserved */
-#define ELMC_CTRL_LBK 0x20 /* RW loopback enable, assert high */
-#define ELMC_CTRL_CA 0x40 /* RW channel attention, assert high */
-#define ELMC_CTRL_RST 0x80 /* RW 82586 reset, assert low */
-
-/* some handy compound bits */
-
-/* normal operation should have bank 3 and RST high, ints enabled */
-#define ELMC_NORMAL (ELMC_CTRL_INTE|ELMC_CTRL_RST|0x3)
-
-#endif /* _3c523_INCLUDE_ */
+++ /dev/null
-/* 3c527.c: 3Com Etherlink/MC32 driver for Linux 2.4 and 2.6.
- *
- * (c) Copyright 1998 Red Hat Software Inc
- * Written by Alan Cox.
- * Further debugging by Carl Drougge.
- * Initial SMP support by Felipe W Damasio <felipewd@terra.com.br>
- * Heavily modified by Richard Procter <rnp@paradise.net.nz>
- *
- * Based on skeleton.c written 1993-94 by Donald Becker and ne2.c
- * (for the MCA stuff) written by Wim Dumon.
- *
- * Thanks to 3Com for making this possible by providing me with the
- * documentation.
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#define DRV_NAME "3c527"
-#define DRV_VERSION "0.7-SMP"
-#define DRV_RELDATE "2003/09/21"
-
-static const char *version =
-DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " Richard Procter <rnp@paradise.net.nz>\n";
-
-/**
- * DOC: Traps for the unwary
- *
- * The diagram (Figure 1-1) and the POS summary disagree with the
- * "Interrupt Level" section in the manual.
- *
- * The manual contradicts itself when describing the minimum number
- * buffers in the 'configure lists' command.
- * My card accepts a buffer config of 4/4.
- *
- * Setting the SAV BP bit does not save bad packets, but
- * only enables RX on-card stats collection.
- *
- * The documentation in places seems to miss things. In actual fact
- * I've always eventually found everything is documented, it just
- * requires careful study.
- *
- * DOC: Theory Of Operation
- *
- * The 3com 3c527 is a 32bit MCA bus mastering adapter with a large
- * amount of on board intelligence that housekeeps a somewhat dumber
- * Intel NIC. For performance we want to keep the transmit queue deep
- * as the card can transmit packets while fetching others from main
- * memory by bus master DMA. Transmission and reception are driven by
- * circular buffer queues.
- *
- * The mailboxes can be used for controlling how the card traverses
- * its buffer rings, but are used only for initial setup in this
- * implementation. The exec mailbox allows a variety of commands to
- * be executed. Each command must complete before the next is
- * executed. Primarily we use the exec mailbox for controlling the
- * multicast lists. We have to do a certain amount of interesting
- * hoop jumping as the multicast list changes can occur in interrupt
- * state when the card has an exec command pending. We defer such
- * events until the command completion interrupt.
- *
- * A copy break scheme (taken from 3c59x.c) is employed whereby
- * received frames exceeding a configurable length are passed
- * directly to the higher networking layers without incuring a copy,
- * in what amounts to a time/space trade-off.
- *
- * The card also keeps a large amount of statistical information
- * on-board. In a perfect world, these could be used safely at no
- * cost. However, lacking information to the contrary, processing
- * them without races would involve so much extra complexity as to
- * make it unworthwhile to do so. In the end, a hybrid SW/HW
- * implementation was made necessary --- see mc32_update_stats().
- *
- * DOC: Notes
- *
- * It should be possible to use two or more cards, but at this stage
- * only by loading two copies of the same module.
- *
- * The on-board 82586 NIC has trouble receiving multiple
- * back-to-back frames and so is likely to drop packets from fast
- * senders.
-**/
-
-#include <linux/module.h>
-
-#include <linux/errno.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/if_ether.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/mca-legacy.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/skbuff.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/wait.h>
-#include <linux/ethtool.h>
-#include <linux/completion.h>
-#include <linux/bitops.h>
-#include <linux/semaphore.h>
-
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-
-#include "3c527.h"
-
-MODULE_LICENSE("GPL");
-
-/*
- * The name of the card. Is used for messages and in the requests for
- * io regions, irqs and dma channels
- */
-static const char* cardname = DRV_NAME;
-
-/* use 0 for production, 1 for verification, >2 for debug */
-#ifndef NET_DEBUG
-#define NET_DEBUG 2
-#endif
-
-static unsigned int mc32_debug = NET_DEBUG;
-
-/* The number of low I/O ports used by the ethercard. */
-#define MC32_IO_EXTENT 8
-
-/* As implemented, values must be a power-of-2 -- 4/8/16/32 */
-#define TX_RING_LEN 32 /* Typically the card supports 37 */
-#define RX_RING_LEN 8 /* " " " */
-
-/* Copy break point, see above for details.
- * Setting to > 1512 effectively disables this feature. */
-#define RX_COPYBREAK 200 /* Value from 3c59x.c */
-
-/* Issue the 82586 workaround command - this is for "busy lans", but
- * basically means for all lans now days - has a performance (latency)
- * cost, but best set. */
-static const int WORKAROUND_82586=1;
-
-/* Pointers to buffers and their on-card records */
-struct mc32_ring_desc
-{
- volatile struct skb_header *p;
- struct sk_buff *skb;
-};
-
-/* Information that needs to be kept for each board. */
-struct mc32_local
-{
- int slot;
-
- u32 base;
- volatile struct mc32_mailbox *rx_box;
- volatile struct mc32_mailbox *tx_box;
- volatile struct mc32_mailbox *exec_box;
- volatile struct mc32_stats *stats; /* Start of on-card statistics */
- u16 tx_chain; /* Transmit list start offset */
- u16 rx_chain; /* Receive list start offset */
- u16 tx_len; /* Transmit list count */
- u16 rx_len; /* Receive list count */
-
- u16 xceiver_desired_state; /* HALTED or RUNNING */
- u16 cmd_nonblocking; /* Thread is uninterested in command result */
- u16 mc_reload_wait; /* A multicast load request is pending */
- u32 mc_list_valid; /* True when the mclist is set */
-
- struct mc32_ring_desc tx_ring[TX_RING_LEN]; /* Host Transmit ring */
- struct mc32_ring_desc rx_ring[RX_RING_LEN]; /* Host Receive ring */
-
- atomic_t tx_count; /* buffers left */
- atomic_t tx_ring_head; /* index to tx en-queue end */
- u16 tx_ring_tail; /* index to tx de-queue end */
-
- u16 rx_ring_tail; /* index to rx de-queue end */
-
- struct semaphore cmd_mutex; /* Serialises issuing of execute commands */
- struct completion execution_cmd; /* Card has completed an execute command */
- struct completion xceiver_cmd; /* Card has completed a tx or rx command */
-};
-
-/* The station (ethernet) address prefix, used for a sanity check. */
-#define SA_ADDR0 0x02
-#define SA_ADDR1 0x60
-#define SA_ADDR2 0xAC
-
-struct mca_adapters_t {
- unsigned int id;
- char *name;
-};
-
-static const struct mca_adapters_t mc32_adapters[] = {
- { 0x0041, "3COM EtherLink MC/32" },
- { 0x8EF5, "IBM High Performance Lan Adapter" },
- { 0x0000, NULL }
-};
-
-
-/* Macros for ring index manipulations */
-static inline u16 next_rx(u16 rx) { return (rx+1)&(RX_RING_LEN-1); };
-static inline u16 prev_rx(u16 rx) { return (rx-1)&(RX_RING_LEN-1); };
-
-static inline u16 next_tx(u16 tx) { return (tx+1)&(TX_RING_LEN-1); };
-
-
-/* Index to functions, as function prototypes. */
-static int mc32_probe1(struct net_device *dev, int ioaddr);
-static int mc32_command(struct net_device *dev, u16 cmd, void *data, int len);
-static int mc32_open(struct net_device *dev);
-static void mc32_timeout(struct net_device *dev);
-static netdev_tx_t mc32_send_packet(struct sk_buff *skb,
- struct net_device *dev);
-static irqreturn_t mc32_interrupt(int irq, void *dev_id);
-static int mc32_close(struct net_device *dev);
-static struct net_device_stats *mc32_get_stats(struct net_device *dev);
-static void mc32_set_multicast_list(struct net_device *dev);
-static void mc32_reset_multicast_list(struct net_device *dev);
-static const struct ethtool_ops netdev_ethtool_ops;
-
-static void cleanup_card(struct net_device *dev)
-{
- struct mc32_local *lp = netdev_priv(dev);
- unsigned slot = lp->slot;
- mca_mark_as_unused(slot);
- mca_set_adapter_name(slot, NULL);
- free_irq(dev->irq, dev);
- release_region(dev->base_addr, MC32_IO_EXTENT);
-}
-
-/**
- * mc32_probe - Search for supported boards
- * @unit: interface number to use
- *
- * Because MCA bus is a real bus and we can scan for cards we could do a
- * single scan for all boards here. Right now we use the passed in device
- * structure and scan for only one board. This needs fixing for modules
- * in particular.
- */
-
-struct net_device *__init mc32_probe(int unit)
-{
- struct net_device *dev = alloc_etherdev(sizeof(struct mc32_local));
- static int current_mca_slot = -1;
- int i;
- int err;
-
- if (!dev)
- return ERR_PTR(-ENOMEM);
-
- if (unit >= 0)
- sprintf(dev->name, "eth%d", unit);
-
- /* Do not check any supplied i/o locations.
- POS registers usually don't fail :) */
-
- /* MCA cards have POS registers.
- Autodetecting MCA cards is extremely simple.
- Just search for the card. */
-
- for(i = 0; (mc32_adapters[i].name != NULL); i++) {
- current_mca_slot =
- mca_find_unused_adapter(mc32_adapters[i].id, 0);
-
- if(current_mca_slot != MCA_NOTFOUND) {
- if(!mc32_probe1(dev, current_mca_slot))
- {
- mca_set_adapter_name(current_mca_slot,
- mc32_adapters[i].name);
- mca_mark_as_used(current_mca_slot);
- err = register_netdev(dev);
- if (err) {
- cleanup_card(dev);
- free_netdev(dev);
- dev = ERR_PTR(err);
- }
- return dev;
- }
-
- }
- }
- free_netdev(dev);
- return ERR_PTR(-ENODEV);
-}
-
-static const struct net_device_ops netdev_ops = {
- .ndo_open = mc32_open,
- .ndo_stop = mc32_close,
- .ndo_start_xmit = mc32_send_packet,
- .ndo_get_stats = mc32_get_stats,
- .ndo_set_multicast_list = mc32_set_multicast_list,
- .ndo_tx_timeout = mc32_timeout,
- .ndo_change_mtu = eth_change_mtu,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-/**
- * mc32_probe1 - Check a given slot for a board and test the card
- * @dev: Device structure to fill in
- * @slot: The MCA bus slot being used by this card
- *
- * Decode the slot data and configure the card structures. Having done this we
- * can reset the card and configure it. The card does a full self test cycle
- * in firmware so we have to wait for it to return and post us either a
- * failure case or some addresses we use to find the board internals.
- */
-
-static int __init mc32_probe1(struct net_device *dev, int slot)
-{
- static unsigned version_printed;
- int i, err;
- u8 POS;
- u32 base;
- struct mc32_local *lp = netdev_priv(dev);
- static const u16 mca_io_bases[] = {
- 0x7280,0x7290,
- 0x7680,0x7690,
- 0x7A80,0x7A90,
- 0x7E80,0x7E90
- };
- static const u32 mca_mem_bases[] = {
- 0x00C0000,
- 0x00C4000,
- 0x00C8000,
- 0x00CC000,
- 0x00D0000,
- 0x00D4000,
- 0x00D8000,
- 0x00DC000
- };
- static const char * const failures[] = {
- "Processor instruction",
- "Processor data bus",
- "Processor data bus",
- "Processor data bus",
- "Adapter bus",
- "ROM checksum",
- "Base RAM",
- "Extended RAM",
- "82586 internal loopback",
- "82586 initialisation failure",
- "Adapter list configuration error"
- };
-
- /* Time to play MCA games */
-
- if (mc32_debug && version_printed++ == 0)
- pr_debug("%s", version);
-
- pr_info("%s: %s found in slot %d: ", dev->name, cardname, slot);
-
- POS = mca_read_stored_pos(slot, 2);
-
- if(!(POS&1))
- {
- pr_cont("disabled.\n");
- return -ENODEV;
- }
-
- /* Fill in the 'dev' fields. */
- dev->base_addr = mca_io_bases[(POS>>1)&7];
- dev->mem_start = mca_mem_bases[(POS>>4)&7];
-
- POS = mca_read_stored_pos(slot, 4);
- if(!(POS&1))
- {
- pr_cont("memory window disabled.\n");
- return -ENODEV;
- }
-
- POS = mca_read_stored_pos(slot, 5);
-
- i=(POS>>4)&3;
- if(i==3)
- {
- pr_cont("invalid memory window.\n");
- return -ENODEV;
- }
-
- i*=16384;
- i+=16384;
-
- dev->mem_end=dev->mem_start + i;
-
- dev->irq = ((POS>>2)&3)+9;
-
- if(!request_region(dev->base_addr, MC32_IO_EXTENT, cardname))
- {
- pr_cont("io 0x%3lX, which is busy.\n", dev->base_addr);
- return -EBUSY;
- }
-
- pr_cont("io 0x%3lX irq %d mem 0x%lX (%dK)\n",
- dev->base_addr, dev->irq, dev->mem_start, i/1024);
-
-
- /* We ought to set the cache line size here.. */
-
-
- /*
- * Go PROM browsing
- */
-
- /* Retrieve and print the ethernet address. */
- for (i = 0; i < 6; i++)
- {
- mca_write_pos(slot, 6, i+12);
- mca_write_pos(slot, 7, 0);
-
- dev->dev_addr[i] = mca_read_pos(slot,3);
- }
-
- pr_info("%s: Address %pM ", dev->name, dev->dev_addr);
-
- mca_write_pos(slot, 6, 0);
- mca_write_pos(slot, 7, 0);
-
- POS = mca_read_stored_pos(slot, 4);
-
- if(POS&2)
- pr_cont(": BNC port selected.\n");
- else
- pr_cont(": AUI port selected.\n");
-
- POS=inb(dev->base_addr+HOST_CTRL);
- POS|=HOST_CTRL_ATTN|HOST_CTRL_RESET;
- POS&=~HOST_CTRL_INTE;
- outb(POS, dev->base_addr+HOST_CTRL);
- /* Reset adapter */
- udelay(100);
- /* Reset off */
- POS&=~(HOST_CTRL_ATTN|HOST_CTRL_RESET);
- outb(POS, dev->base_addr+HOST_CTRL);
-
- udelay(300);
-
- /*
- * Grab the IRQ
- */
-
- err = request_irq(dev->irq, mc32_interrupt, IRQF_SHARED, DRV_NAME, dev);
- if (err) {
- release_region(dev->base_addr, MC32_IO_EXTENT);
- pr_err("%s: unable to get IRQ %d.\n", DRV_NAME, dev->irq);
- goto err_exit_ports;
- }
-
- memset(lp, 0, sizeof(struct mc32_local));
- lp->slot = slot;
-
- i=0;
-
- base = inb(dev->base_addr);
-
- while(base == 0xFF)
- {
- i++;
- if(i == 1000)
- {
- pr_err("%s: failed to boot adapter.\n", dev->name);
- err = -ENODEV;
- goto err_exit_irq;
- }
- udelay(1000);
- if(inb(dev->base_addr+2)&(1<<5))
- base = inb(dev->base_addr);
- }
-
- if(base>0)
- {
- if(base < 0x0C)
- pr_err("%s: %s%s.\n", dev->name, failures[base-1],
- base<0x0A?" test failure":"");
- else
- pr_err("%s: unknown failure %d.\n", dev->name, base);
- err = -ENODEV;
- goto err_exit_irq;
- }
-
- base=0;
- for(i=0;i<4;i++)
- {
- int n=0;
-
- while(!(inb(dev->base_addr+2)&(1<<5)))
- {
- n++;
- udelay(50);
- if(n>100)
- {
- pr_err("%s: mailbox read fail (%d).\n", dev->name, i);
- err = -ENODEV;
- goto err_exit_irq;
- }
- }
-
- base|=(inb(dev->base_addr)<<(8*i));
- }
-
- lp->exec_box=isa_bus_to_virt(dev->mem_start+base);
-
- base=lp->exec_box->data[1]<<16|lp->exec_box->data[0];
-
- lp->base = dev->mem_start+base;
-
- lp->rx_box=isa_bus_to_virt(lp->base + lp->exec_box->data[2]);
- lp->tx_box=isa_bus_to_virt(lp->base + lp->exec_box->data[3]);
-
- lp->stats = isa_bus_to_virt(lp->base + lp->exec_box->data[5]);
-
- /*
- * Descriptor chains (card relative)
- */
-
- lp->tx_chain = lp->exec_box->data[8]; /* Transmit list start offset */
- lp->rx_chain = lp->exec_box->data[10]; /* Receive list start offset */
- lp->tx_len = lp->exec_box->data[9]; /* Transmit list count */
- lp->rx_len = lp->exec_box->data[11]; /* Receive list count */
-
- sema_init(&lp->cmd_mutex, 0);
- init_completion(&lp->execution_cmd);
- init_completion(&lp->xceiver_cmd);
-
- pr_info("%s: Firmware Rev %d. %d RX buffers, %d TX buffers. Base of 0x%08X.\n",
- dev->name, lp->exec_box->data[12], lp->rx_len, lp->tx_len, lp->base);
-
- dev->netdev_ops = &netdev_ops;
- dev->watchdog_timeo = HZ*5; /* Board does all the work */
- dev->ethtool_ops = &netdev_ethtool_ops;
-
- return 0;
-
-err_exit_irq:
- free_irq(dev->irq, dev);
-err_exit_ports:
- release_region(dev->base_addr, MC32_IO_EXTENT);
- return err;
-}
-
-
-/**
- * mc32_ready_poll - wait until we can feed it a command
- * @dev: The device to wait for
- *
- * Wait until the card becomes ready to accept a command via the
- * command register. This tells us nothing about the completion
- * status of any pending commands and takes very little time at all.
- */
-
-static inline void mc32_ready_poll(struct net_device *dev)
-{
- int ioaddr = dev->base_addr;
- while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));
-}
-
-
-/**
- * mc32_command_nowait - send a command non blocking
- * @dev: The 3c527 to issue the command to
- * @cmd: The command word to write to the mailbox
- * @data: A data block if the command expects one
- * @len: Length of the data block
- *
- * Send a command from interrupt state. If there is a command
- * currently being executed then we return an error of -1. It
- * simply isn't viable to wait around as commands may be
- * slow. This can theoretically be starved on SMP, but it's hard
- * to see a realistic situation. We do not wait for the command
- * to complete --- we rely on the interrupt handler to tidy up
- * after us.
- */
-
-static int mc32_command_nowait(struct net_device *dev, u16 cmd, void *data, int len)
-{
- struct mc32_local *lp = netdev_priv(dev);
- int ioaddr = dev->base_addr;
- int ret = -1;
-
- if (down_trylock(&lp->cmd_mutex) == 0)
- {
- lp->cmd_nonblocking=1;
- lp->exec_box->mbox=0;
- lp->exec_box->mbox=cmd;
- memcpy((void *)lp->exec_box->data, data, len);
- barrier(); /* the memcpy forgot the volatile so be sure */
-
- /* Send the command */
- mc32_ready_poll(dev);
- outb(1<<6, ioaddr+HOST_CMD);
-
- ret = 0;
-
- /* Interrupt handler will signal mutex on completion */
- }
-
- return ret;
-}
-
-
-/**
- * mc32_command - send a command and sleep until completion
- * @dev: The 3c527 card to issue the command to
- * @cmd: The command word to write to the mailbox
- * @data: A data block if the command expects one
- * @len: Length of the data block
- *
- * Sends exec commands in a user context. This permits us to wait around
- * for the replies and also to wait for the command buffer to complete
- * from a previous command before we execute our command. After our
- * command completes we will attempt any pending multicast reload
- * we blocked off by hogging the exec buffer.
- *
- * You feed the card a command, you wait, it interrupts you get a
- * reply. All well and good. The complication arises because you use
- * commands for filter list changes which come in at bh level from things
- * like IPV6 group stuff.
- */
-
-static int mc32_command(struct net_device *dev, u16 cmd, void *data, int len)
-{
- struct mc32_local *lp = netdev_priv(dev);
- int ioaddr = dev->base_addr;
- int ret = 0;
-
- down(&lp->cmd_mutex);
-
- /*
- * My Turn
- */
-
- lp->cmd_nonblocking=0;
- lp->exec_box->mbox=0;
- lp->exec_box->mbox=cmd;
- memcpy((void *)lp->exec_box->data, data, len);
- barrier(); /* the memcpy forgot the volatile so be sure */
-
- mc32_ready_poll(dev);
- outb(1<<6, ioaddr+HOST_CMD);
-
- wait_for_completion(&lp->execution_cmd);
-
- if(lp->exec_box->mbox&(1<<13))
- ret = -1;
-
- up(&lp->cmd_mutex);
-
- /*
- * A multicast set got blocked - try it now
- */
-
- if(lp->mc_reload_wait)
- {
- mc32_reset_multicast_list(dev);
- }
-
- return ret;
-}
-
-
-/**
- * mc32_start_transceiver - tell board to restart tx/rx
- * @dev: The 3c527 card to issue the command to
- *
- * This may be called from the interrupt state, where it is used
- * to restart the rx ring if the card runs out of rx buffers.
- *
- * We must first check if it's ok to (re)start the transceiver. See
- * mc32_close for details.
- */
-
-static void mc32_start_transceiver(struct net_device *dev) {
-
- struct mc32_local *lp = netdev_priv(dev);
- int ioaddr = dev->base_addr;
-
- /* Ignore RX overflow on device closure */
- if (lp->xceiver_desired_state==HALTED)
- return;
-
- /* Give the card the offset to the post-EOL-bit RX descriptor */
- mc32_ready_poll(dev);
- lp->rx_box->mbox=0;
- lp->rx_box->data[0]=lp->rx_ring[prev_rx(lp->rx_ring_tail)].p->next;
- outb(HOST_CMD_START_RX, ioaddr+HOST_CMD);
-
- mc32_ready_poll(dev);
- lp->tx_box->mbox=0;
- outb(HOST_CMD_RESTRT_TX, ioaddr+HOST_CMD); /* card ignores this on RX restart */
-
- /* We are not interrupted on start completion */
-}
-
-
-/**
- * mc32_halt_transceiver - tell board to stop tx/rx
- * @dev: The 3c527 card to issue the command to
- *
- * We issue the commands to halt the card's transceiver. In fact,
- * after some experimenting we now simply tell the card to
- * suspend. When issuing aborts occasionally odd things happened.
- *
- * We then sleep until the card has notified us that both rx and
- * tx have been suspended.
- */
-
-static void mc32_halt_transceiver(struct net_device *dev)
-{
- struct mc32_local *lp = netdev_priv(dev);
- int ioaddr = dev->base_addr;
-
- mc32_ready_poll(dev);
- lp->rx_box->mbox=0;
- outb(HOST_CMD_SUSPND_RX, ioaddr+HOST_CMD);
- wait_for_completion(&lp->xceiver_cmd);
-
- mc32_ready_poll(dev);
- lp->tx_box->mbox=0;
- outb(HOST_CMD_SUSPND_TX, ioaddr+HOST_CMD);
- wait_for_completion(&lp->xceiver_cmd);
-}
-
-
-/**
- * mc32_load_rx_ring - load the ring of receive buffers
- * @dev: 3c527 to build the ring for
- *
- * This initialises the on-card and driver datastructures to
- * the point where mc32_start_transceiver() can be called.
- *
- * The card sets up the receive ring for us. We are required to use the
- * ring it provides, although the size of the ring is configurable.
- *
- * We allocate an sk_buff for each ring entry in turn and
- * initialise its house-keeping info. At the same time, we read
- * each 'next' pointer in our rx_ring array. This reduces slow
- * shared-memory reads and makes it easy to access predecessor
- * descriptors.
- *
- * We then set the end-of-list bit for the last entry so that the
- * card will know when it has run out of buffers.
- */
-
-static int mc32_load_rx_ring(struct net_device *dev)
-{
- struct mc32_local *lp = netdev_priv(dev);
- int i;
- u16 rx_base;
- volatile struct skb_header *p;
-
- rx_base=lp->rx_chain;
-
- for(i=0; i<RX_RING_LEN; i++) {
- lp->rx_ring[i].skb=alloc_skb(1532, GFP_KERNEL);
- if (lp->rx_ring[i].skb==NULL) {
- for (;i>=0;i--)
- kfree_skb(lp->rx_ring[i].skb);
- return -ENOBUFS;
- }
- skb_reserve(lp->rx_ring[i].skb, 18);
-
- p=isa_bus_to_virt(lp->base+rx_base);
-
- p->control=0;
- p->data=isa_virt_to_bus(lp->rx_ring[i].skb->data);
- p->status=0;
- p->length=1532;
-
- lp->rx_ring[i].p=p;
- rx_base=p->next;
- }
-
- lp->rx_ring[i-1].p->control |= CONTROL_EOL;
-
- lp->rx_ring_tail=0;
-
- return 0;
-}
-
-
-/**
- * mc32_flush_rx_ring - free the ring of receive buffers
- * @lp: Local data of 3c527 to flush the rx ring of
- *
- * Free the buffer for each ring slot. This may be called
- * before mc32_load_rx_ring(), eg. on error in mc32_open().
- * Requires rx skb pointers to point to a valid skb, or NULL.
- */
-
-static void mc32_flush_rx_ring(struct net_device *dev)
-{
- struct mc32_local *lp = netdev_priv(dev);
- int i;
-
- for(i=0; i < RX_RING_LEN; i++)
- {
- if (lp->rx_ring[i].skb) {
- dev_kfree_skb(lp->rx_ring[i].skb);
- lp->rx_ring[i].skb = NULL;
- }
- lp->rx_ring[i].p=NULL;
- }
-}
-
-
-/**
- * mc32_load_tx_ring - load transmit ring
- * @dev: The 3c527 card to issue the command to
- *
- * This sets up the host transmit data-structures.
- *
- * First, we obtain from the card it's current position in the tx
- * ring, so that we will know where to begin transmitting
- * packets.
- *
- * Then, we read the 'next' pointers from the on-card tx ring into
- * our tx_ring array to reduce slow shared-mem reads. Finally, we
- * intitalise the tx house keeping variables.
- *
- */
-
-static void mc32_load_tx_ring(struct net_device *dev)
-{
- struct mc32_local *lp = netdev_priv(dev);
- volatile struct skb_header *p;
- int i;
- u16 tx_base;
-
- tx_base=lp->tx_box->data[0];
-
- for(i=0 ; i<TX_RING_LEN ; i++)
- {
- p=isa_bus_to_virt(lp->base+tx_base);
- lp->tx_ring[i].p=p;
- lp->tx_ring[i].skb=NULL;
-
- tx_base=p->next;
- }
-
- /* -1 so that tx_ring_head cannot "lap" tx_ring_tail */
- /* see mc32_tx_ring */
-
- atomic_set(&lp->tx_count, TX_RING_LEN-1);
- atomic_set(&lp->tx_ring_head, 0);
- lp->tx_ring_tail=0;
-}
-
-
-/**
- * mc32_flush_tx_ring - free transmit ring
- * @lp: Local data of 3c527 to flush the tx ring of
- *
- * If the ring is non-empty, zip over the it, freeing any
- * allocated skb_buffs. The tx ring house-keeping variables are
- * then reset. Requires rx skb pointers to point to a valid skb,
- * or NULL.
- */
-
-static void mc32_flush_tx_ring(struct net_device *dev)
-{
- struct mc32_local *lp = netdev_priv(dev);
- int i;
-
- for (i=0; i < TX_RING_LEN; i++)
- {
- if (lp->tx_ring[i].skb)
- {
- dev_kfree_skb(lp->tx_ring[i].skb);
- lp->tx_ring[i].skb = NULL;
- }
- }
-
- atomic_set(&lp->tx_count, 0);
- atomic_set(&lp->tx_ring_head, 0);
- lp->tx_ring_tail=0;
-}
-
-
-/**
- * mc32_open - handle 'up' of card
- * @dev: device to open
- *
- * The user is trying to bring the card into ready state. This requires
- * a brief dialogue with the card. Firstly we enable interrupts and then
- * 'indications'. Without these enabled the card doesn't bother telling
- * us what it has done. This had me puzzled for a week.
- *
- * We configure the number of card descriptors, then load the network
- * address and multicast filters. Turn on the workaround mode. This
- * works around a bug in the 82586 - it asks the firmware to do
- * so. It has a performance (latency) hit but is needed on busy
- * [read most] lans. We load the ring with buffers then we kick it
- * all off.
- */
-
-static int mc32_open(struct net_device *dev)
-{
- int ioaddr = dev->base_addr;
- struct mc32_local *lp = netdev_priv(dev);
- u8 one=1;
- u8 regs;
- u16 descnumbuffs[2] = {TX_RING_LEN, RX_RING_LEN};
-
- /*
- * Interrupts enabled
- */
-
- regs=inb(ioaddr+HOST_CTRL);
- regs|=HOST_CTRL_INTE;
- outb(regs, ioaddr+HOST_CTRL);
-
- /*
- * Allow ourselves to issue commands
- */
-
- up(&lp->cmd_mutex);
-
-
- /*
- * Send the indications on command
- */
-
- mc32_command(dev, 4, &one, 2);
-
- /*
- * Poke it to make sure it's really dead.
- */
-
- mc32_halt_transceiver(dev);
- mc32_flush_tx_ring(dev);
-
- /*
- * Ask card to set up on-card descriptors to our spec
- */
-
- if(mc32_command(dev, 8, descnumbuffs, 4)) {
- pr_info("%s: %s rejected our buffer configuration!\n",
- dev->name, cardname);
- mc32_close(dev);
- return -ENOBUFS;
- }
-
- /* Report new configuration */
- mc32_command(dev, 6, NULL, 0);
-
- lp->tx_chain = lp->exec_box->data[8]; /* Transmit list start offset */
- lp->rx_chain = lp->exec_box->data[10]; /* Receive list start offset */
- lp->tx_len = lp->exec_box->data[9]; /* Transmit list count */
- lp->rx_len = lp->exec_box->data[11]; /* Receive list count */
-
- /* Set Network Address */
- mc32_command(dev, 1, dev->dev_addr, 6);
-
- /* Set the filters */
- mc32_set_multicast_list(dev);
-
- if (WORKAROUND_82586) {
- u16 zero_word=0;
- mc32_command(dev, 0x0D, &zero_word, 2); /* 82586 bug workaround on */
- }
-
- mc32_load_tx_ring(dev);
-
- if(mc32_load_rx_ring(dev))
- {
- mc32_close(dev);
- return -ENOBUFS;
- }
-
- lp->xceiver_desired_state = RUNNING;
-
- /* And finally, set the ball rolling... */
- mc32_start_transceiver(dev);
-
- netif_start_queue(dev);
-
- return 0;
-}
-
-
-/**
- * mc32_timeout - handle a timeout from the network layer
- * @dev: 3c527 that timed out
- *
- * Handle a timeout on transmit from the 3c527. This normally means
- * bad things as the hardware handles cable timeouts and mess for
- * us.
- *
- */
-
-static void mc32_timeout(struct net_device *dev)
-{
- pr_warning("%s: transmit timed out?\n", dev->name);
- /* Try to restart the adaptor. */
- netif_wake_queue(dev);
-}
-
-
-/**
- * mc32_send_packet - queue a frame for transmit
- * @skb: buffer to transmit
- * @dev: 3c527 to send it out of
- *
- * Transmit a buffer. This normally means throwing the buffer onto
- * the transmit queue as the queue is quite large. If the queue is
- * full then we set tx_busy and return. Once the interrupt handler
- * gets messages telling it to reclaim transmit queue entries, we will
- * clear tx_busy and the kernel will start calling this again.
- *
- * We do not disable interrupts or acquire any locks; this can
- * run concurrently with mc32_tx_ring(), and the function itself
- * is serialised at a higher layer. However, similarly for the
- * card itself, we must ensure that we update tx_ring_head only
- * after we've established a valid packet on the tx ring (and
- * before we let the card "see" it, to prevent it racing with the
- * irq handler).
- *
- */
-
-static netdev_tx_t mc32_send_packet(struct sk_buff *skb,
- struct net_device *dev)
-{
- struct mc32_local *lp = netdev_priv(dev);
- u32 head = atomic_read(&lp->tx_ring_head);
-
- volatile struct skb_header *p, *np;
-
- netif_stop_queue(dev);
-
- if(atomic_read(&lp->tx_count)==0) {
- return NETDEV_TX_BUSY;
- }
-
- if (skb_padto(skb, ETH_ZLEN)) {
- netif_wake_queue(dev);
- return NETDEV_TX_OK;
- }
-
- atomic_dec(&lp->tx_count);
-
- /* P is the last sending/sent buffer as a pointer */
- p=lp->tx_ring[head].p;
-
- head = next_tx(head);
-
- /* NP is the buffer we will be loading */
- np=lp->tx_ring[head].p;
-
- /* We will need this to flush the buffer out */
- lp->tx_ring[head].skb=skb;
-
- np->length = unlikely(skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len;
- np->data = isa_virt_to_bus(skb->data);
- np->status = 0;
- np->control = CONTROL_EOP | CONTROL_EOL;
- wmb();
-
- /*
- * The new frame has been setup; we can now
- * let the interrupt handler and card "see" it
- */
-
- atomic_set(&lp->tx_ring_head, head);
- p->control &= ~CONTROL_EOL;
-
- netif_wake_queue(dev);
- return NETDEV_TX_OK;
-}
-
-
-/**
- * mc32_update_stats - pull off the on board statistics
- * @dev: 3c527 to service
- *
- *
- * Query and reset the on-card stats. There's the small possibility
- * of a race here, which would result in an underestimation of
- * actual errors. As such, we'd prefer to keep all our stats
- * collection in software. As a rule, we do. However it can't be
- * used for rx errors and collisions as, by default, the card discards
- * bad rx packets.
- *
- * Setting the SAV BP in the rx filter command supposedly
- * stops this behaviour. However, testing shows that it only seems to
- * enable the collation of on-card rx statistics --- the driver
- * never sees an RX descriptor with an error status set.
- *
- */
-
-static void mc32_update_stats(struct net_device *dev)
-{
- struct mc32_local *lp = netdev_priv(dev);
- volatile struct mc32_stats *st = lp->stats;
-
- u32 rx_errors=0;
-
- rx_errors+=dev->stats.rx_crc_errors +=st->rx_crc_errors;
- st->rx_crc_errors=0;
- rx_errors+=dev->stats.rx_fifo_errors +=st->rx_overrun_errors;
- st->rx_overrun_errors=0;
- rx_errors+=dev->stats.rx_frame_errors +=st->rx_alignment_errors;
- st->rx_alignment_errors=0;
- rx_errors+=dev->stats.rx_length_errors+=st->rx_tooshort_errors;
- st->rx_tooshort_errors=0;
- rx_errors+=dev->stats.rx_missed_errors+=st->rx_outofresource_errors;
- st->rx_outofresource_errors=0;
- dev->stats.rx_errors=rx_errors;
-
- /* Number of packets which saw one collision */
- dev->stats.collisions+=st->dataC[10];
- st->dataC[10]=0;
-
- /* Number of packets which saw 2--15 collisions */
- dev->stats.collisions+=st->dataC[11];
- st->dataC[11]=0;
-}
-
-
-/**
- * mc32_rx_ring - process the receive ring
- * @dev: 3c527 that needs its receive ring processing
- *
- *
- * We have received one or more indications from the card that a
- * receive has completed. The buffer ring thus contains dirty
- * entries. We walk the ring by iterating over the circular rx_ring
- * array, starting at the next dirty buffer (which happens to be the
- * one we finished up at last time around).
- *
- * For each completed packet, we will either copy it and pass it up
- * the stack or, if the packet is near MTU sized, we allocate
- * another buffer and flip the old one up the stack.
- *
- * We must succeed in keeping a buffer on the ring. If necessary we
- * will toss a received packet rather than lose a ring entry. Once
- * the first uncompleted descriptor is found, we move the
- * End-Of-List bit to include the buffers just processed.
- *
- */
-
-static void mc32_rx_ring(struct net_device *dev)
-{
- struct mc32_local *lp = netdev_priv(dev);
- volatile struct skb_header *p;
- u16 rx_ring_tail;
- u16 rx_old_tail;
- int x=0;
-
- rx_old_tail = rx_ring_tail = lp->rx_ring_tail;
-
- do
- {
- p=lp->rx_ring[rx_ring_tail].p;
-
- if(!(p->status & (1<<7))) { /* Not COMPLETED */
- break;
- }
- if(p->status & (1<<6)) /* COMPLETED_OK */
- {
-
- u16 length=p->length;
- struct sk_buff *skb;
- struct sk_buff *newskb;
-
- /* Try to save time by avoiding a copy on big frames */
-
- if ((length > RX_COPYBREAK) &&
- ((newskb=dev_alloc_skb(1532)) != NULL))
- {
- skb=lp->rx_ring[rx_ring_tail].skb;
- skb_put(skb, length);
-
- skb_reserve(newskb,18);
- lp->rx_ring[rx_ring_tail].skb=newskb;
- p->data=isa_virt_to_bus(newskb->data);
- }
- else
- {
- skb=dev_alloc_skb(length+2);
-
- if(skb==NULL) {
- dev->stats.rx_dropped++;
- goto dropped;
- }
-
- skb_reserve(skb,2);
- memcpy(skb_put(skb, length),
- lp->rx_ring[rx_ring_tail].skb->data, length);
- }
-
- skb->protocol=eth_type_trans(skb,dev);
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += length;
- netif_rx(skb);
- }
-
- dropped:
- p->length = 1532;
- p->status = 0;
-
- rx_ring_tail=next_rx(rx_ring_tail);
- }
- while(x++<48);
-
- /* If there was actually a frame to be processed, place the EOL bit */
- /* at the descriptor prior to the one to be filled next */
-
- if (rx_ring_tail != rx_old_tail)
- {
- lp->rx_ring[prev_rx(rx_ring_tail)].p->control |= CONTROL_EOL;
- lp->rx_ring[prev_rx(rx_old_tail)].p->control &= ~CONTROL_EOL;
-
- lp->rx_ring_tail=rx_ring_tail;
- }
-}
-
-
-/**
- * mc32_tx_ring - process completed transmits
- * @dev: 3c527 that needs its transmit ring processing
- *
- *
- * This operates in a similar fashion to mc32_rx_ring. We iterate
- * over the transmit ring. For each descriptor which has been
- * processed by the card, we free its associated buffer and note
- * any errors. This continues until the transmit ring is emptied
- * or we reach a descriptor that hasn't yet been processed by the
- * card.
- *
- */
-
-static void mc32_tx_ring(struct net_device *dev)
-{
- struct mc32_local *lp = netdev_priv(dev);
- volatile struct skb_header *np;
-
- /*
- * We rely on head==tail to mean 'queue empty'.
- * This is why lp->tx_count=TX_RING_LEN-1: in order to prevent
- * tx_ring_head wrapping to tail and confusing a 'queue empty'
- * condition with 'queue full'
- */
-
- while (lp->tx_ring_tail != atomic_read(&lp->tx_ring_head))
- {
- u16 t;
-
- t=next_tx(lp->tx_ring_tail);
- np=lp->tx_ring[t].p;
-
- if(!(np->status & (1<<7)))
- {
- /* Not COMPLETED */
- break;
- }
- dev->stats.tx_packets++;
- if(!(np->status & (1<<6))) /* Not COMPLETED_OK */
- {
- dev->stats.tx_errors++;
-
- switch(np->status&0x0F)
- {
- case 1:
- dev->stats.tx_aborted_errors++;
- break; /* Max collisions */
- case 2:
- dev->stats.tx_fifo_errors++;
- break;
- case 3:
- dev->stats.tx_carrier_errors++;
- break;
- case 4:
- dev->stats.tx_window_errors++;
- break; /* CTS Lost */
- case 5:
- dev->stats.tx_aborted_errors++;
- break; /* Transmit timeout */
- }
- }
- /* Packets are sent in order - this is
- basically a FIFO queue of buffers matching
- the card ring */
- dev->stats.tx_bytes+=lp->tx_ring[t].skb->len;
- dev_kfree_skb_irq(lp->tx_ring[t].skb);
- lp->tx_ring[t].skb=NULL;
- atomic_inc(&lp->tx_count);
- netif_wake_queue(dev);
-
- lp->tx_ring_tail=t;
- }
-
-}
-
-
-/**
- * mc32_interrupt - handle an interrupt from a 3c527
- * @irq: Interrupt number
- * @dev_id: 3c527 that requires servicing
- * @regs: Registers (unused)
- *
- *
- * An interrupt is raised whenever the 3c527 writes to the command
- * register. This register contains the message it wishes to send us
- * packed into a single byte field. We keep reading status entries
- * until we have processed all the control items, but simply count
- * transmit and receive reports. When all reports are in we empty the
- * transceiver rings as appropriate. This saves the overhead of
- * multiple command requests.
- *
- * Because MCA is level-triggered, we shouldn't miss indications.
- * Therefore, we needn't ask the card to suspend interrupts within
- * this handler. The card receives an implicit acknowledgment of the
- * current interrupt when we read the command register.
- *
- */
-
-static irqreturn_t mc32_interrupt(int irq, void *dev_id)
-{
- struct net_device *dev = dev_id;
- struct mc32_local *lp;
- int ioaddr, status, boguscount = 0;
- int rx_event = 0;
- int tx_event = 0;
-
- ioaddr = dev->base_addr;
- lp = netdev_priv(dev);
-
- /* See whats cooking */
-
- while((inb(ioaddr+HOST_STATUS)&HOST_STATUS_CWR) && boguscount++<2000)
- {
- status=inb(ioaddr+HOST_CMD);
-
- pr_debug("Status TX%d RX%d EX%d OV%d BC%d\n",
- (status&7), (status>>3)&7, (status>>6)&1,
- (status>>7)&1, boguscount);
-
- switch(status&7)
- {
- case 0:
- break;
- case 6: /* TX fail */
- case 2: /* TX ok */
- tx_event = 1;
- break;
- case 3: /* Halt */
- case 4: /* Abort */
- complete(&lp->xceiver_cmd);
- break;
- default:
- pr_notice("%s: strange tx ack %d\n", dev->name, status&7);
- }
- status>>=3;
- switch(status&7)
- {
- case 0:
- break;
- case 2: /* RX */
- rx_event=1;
- break;
- case 3: /* Halt */
- case 4: /* Abort */
- complete(&lp->xceiver_cmd);
- break;
- case 6:
- /* Out of RX buffers stat */
- /* Must restart rx */
- dev->stats.rx_dropped++;
- mc32_rx_ring(dev);
- mc32_start_transceiver(dev);
- break;
- default:
- pr_notice("%s: strange rx ack %d\n",
- dev->name, status&7);
- }
- status>>=3;
- if(status&1)
- {
- /*
- * No thread is waiting: we need to tidy
- * up ourself.
- */
-
- if (lp->cmd_nonblocking) {
- up(&lp->cmd_mutex);
- if (lp->mc_reload_wait)
- mc32_reset_multicast_list(dev);
- }
- else complete(&lp->execution_cmd);
- }
- if(status&2)
- {
- /*
- * We get interrupted once per
- * counter that is about to overflow.
- */
-
- mc32_update_stats(dev);
- }
- }
-
-
- /*
- * Process the transmit and receive rings
- */
-
- if(tx_event)
- mc32_tx_ring(dev);
-
- if(rx_event)
- mc32_rx_ring(dev);
-
- return IRQ_HANDLED;
-}
-
-
-/**
- * mc32_close - user configuring the 3c527 down
- * @dev: 3c527 card to shut down
- *
- * The 3c527 is a bus mastering device. We must be careful how we
- * shut it down. It may also be running shared interrupt so we have
- * to be sure to silence it properly
- *
- * We indicate that the card is closing to the rest of the
- * driver. Otherwise, it is possible that the card may run out
- * of receive buffers and restart the transceiver while we're
- * trying to close it.
- *
- * We abort any receive and transmits going on and then wait until
- * any pending exec commands have completed in other code threads.
- * In theory we can't get here while that is true, in practice I am
- * paranoid
- *
- * We turn off the interrupt enable for the board to be sure it can't
- * intefere with other devices.
- */
-
-static int mc32_close(struct net_device *dev)
-{
- struct mc32_local *lp = netdev_priv(dev);
- int ioaddr = dev->base_addr;
-
- u8 regs;
- u16 one=1;
-
- lp->xceiver_desired_state = HALTED;
- netif_stop_queue(dev);
-
- /*
- * Send the indications on command (handy debug check)
- */
-
- mc32_command(dev, 4, &one, 2);
-
- /* Shut down the transceiver */
-
- mc32_halt_transceiver(dev);
-
- /* Ensure we issue no more commands beyond this point */
-
- down(&lp->cmd_mutex);
-
- /* Ok the card is now stopping */
-
- regs=inb(ioaddr+HOST_CTRL);
- regs&=~HOST_CTRL_INTE;
- outb(regs, ioaddr+HOST_CTRL);
-
- mc32_flush_rx_ring(dev);
- mc32_flush_tx_ring(dev);
-
- mc32_update_stats(dev);
-
- return 0;
-}
-
-
-/**
- * mc32_get_stats - hand back stats to network layer
- * @dev: The 3c527 card to handle
- *
- * We've collected all the stats we can in software already. Now
- * it's time to update those kept on-card and return the lot.
- *
- */
-
-static struct net_device_stats *mc32_get_stats(struct net_device *dev)
-{
- mc32_update_stats(dev);
- return &dev->stats;
-}
-
-
-/**
- * do_mc32_set_multicast_list - attempt to update multicasts
- * @dev: 3c527 device to load the list on
- * @retry: indicates this is not the first call.
- *
- *
- * Actually set or clear the multicast filter for this adaptor. The
- * locking issues are handled by this routine. We have to track
- * state as it may take multiple calls to get the command sequence
- * completed. We just keep trying to schedule the loads until we
- * manage to process them all.
- *
- * num_addrs == -1 Promiscuous mode, receive all packets
- *
- * num_addrs == 0 Normal mode, clear multicast list
- *
- * num_addrs > 0 Multicast mode, receive normal and MC packets,
- * and do best-effort filtering.
- *
- * See mc32_update_stats() regards setting the SAV BP bit.
- *
- */
-
-static void do_mc32_set_multicast_list(struct net_device *dev, int retry)
-{
- struct mc32_local *lp = netdev_priv(dev);
- u16 filt = (1<<2); /* Save Bad Packets, for stats purposes */
-
- if ((dev->flags&IFF_PROMISC) ||
- (dev->flags&IFF_ALLMULTI) ||
- netdev_mc_count(dev) > 10)
- /* Enable promiscuous mode */
- filt |= 1;
- else if (!netdev_mc_empty(dev))
- {
- unsigned char block[62];
- unsigned char *bp;
- struct netdev_hw_addr *ha;
-
- if(retry==0)
- lp->mc_list_valid = 0;
- if(!lp->mc_list_valid)
- {
- block[1]=0;
- block[0]=netdev_mc_count(dev);
- bp=block+2;
-
- netdev_for_each_mc_addr(ha, dev) {
- memcpy(bp, ha->addr, 6);
- bp+=6;
- }
- if(mc32_command_nowait(dev, 2, block,
- 2+6*netdev_mc_count(dev))==-1)
- {
- lp->mc_reload_wait = 1;
- return;
- }
- lp->mc_list_valid=1;
- }
- }
-
- if(mc32_command_nowait(dev, 0, &filt, 2)==-1)
- {
- lp->mc_reload_wait = 1;
- }
- else {
- lp->mc_reload_wait = 0;
- }
-}
-
-
-/**
- * mc32_set_multicast_list - queue multicast list update
- * @dev: The 3c527 to use
- *
- * Commence loading the multicast list. This is called when the kernel
- * changes the lists. It will override any pending list we are trying to
- * load.
- */
-
-static void mc32_set_multicast_list(struct net_device *dev)
-{
- do_mc32_set_multicast_list(dev,0);
-}
-
-
-/**
- * mc32_reset_multicast_list - reset multicast list
- * @dev: The 3c527 to use
- *
- * Attempt the next step in loading the multicast lists. If this attempt
- * fails to complete then it will be scheduled and this function called
- * again later from elsewhere.
- */
-
-static void mc32_reset_multicast_list(struct net_device *dev)
-{
- do_mc32_set_multicast_list(dev,1);
-}
-
-static void netdev_get_drvinfo(struct net_device *dev,
- struct ethtool_drvinfo *info)
-{
- strcpy(info->driver, DRV_NAME);
- strcpy(info->version, DRV_VERSION);
- sprintf(info->bus_info, "MCA 0x%lx", dev->base_addr);
-}
-
-static u32 netdev_get_msglevel(struct net_device *dev)
-{
- return mc32_debug;
-}
-
-static void netdev_set_msglevel(struct net_device *dev, u32 level)
-{
- mc32_debug = level;
-}
-
-static const struct ethtool_ops netdev_ethtool_ops = {
- .get_drvinfo = netdev_get_drvinfo,
- .get_msglevel = netdev_get_msglevel,
- .set_msglevel = netdev_set_msglevel,
-};
-
-#ifdef MODULE
-
-static struct net_device *this_device;
-
-/**
- * init_module - entry point
- *
- * Probe and locate a 3c527 card. This really should probe and locate
- * all the 3c527 cards in the machine not just one of them. Yes you can
- * insmod multiple modules for now but it's a hack.
- */
-
-int __init init_module(void)
-{
- this_device = mc32_probe(-1);
- if (IS_ERR(this_device))
- return PTR_ERR(this_device);
- return 0;
-}
-
-/**
- * cleanup_module - free resources for an unload
- *
- * Unloading time. We release the MCA bus resources and the interrupt
- * at which point everything is ready to unload. The card must be stopped
- * at this point or we would not have been called. When we unload we
- * leave the card stopped but not totally shut down. When the card is
- * initialized it must be rebooted or the rings reloaded before any
- * transmit operations are allowed to start scribbling into memory.
- */
-
-void __exit cleanup_module(void)
-{
- unregister_netdev(this_device);
- cleanup_card(this_device);
- free_netdev(this_device);
-}
-
-#endif /* MODULE */
+++ /dev/null
-/*
- * 3COM "EtherLink MC/32" Descriptions
- */
-
-/*
- * Registers
- */
-
-#define HOST_CMD 0
-#define HOST_CMD_START_RX (1<<3)
-#define HOST_CMD_SUSPND_RX (3<<3)
-#define HOST_CMD_RESTRT_RX (5<<3)
-
-#define HOST_CMD_SUSPND_TX 3
-#define HOST_CMD_RESTRT_TX 5
-
-
-#define HOST_STATUS 2
-#define HOST_STATUS_CRR (1<<6)
-#define HOST_STATUS_CWR (1<<5)
-
-
-#define HOST_CTRL 6
-#define HOST_CTRL_ATTN (1<<7)
-#define HOST_CTRL_RESET (1<<6)
-#define HOST_CTRL_INTE (1<<2)
-
-#define HOST_RAMPAGE 8
-
-#define HALTED 0
-#define RUNNING 1
-
-struct mc32_mailbox
-{
- u16 mbox;
- u16 data[1];
-} __packed;
-
-struct skb_header
-{
- u8 status;
- u8 control;
- u16 next; /* Do not change! */
- u16 length;
- u32 data;
-} __packed;
-
-struct mc32_stats
-{
- /* RX Errors */
- u32 rx_crc_errors;
- u32 rx_alignment_errors;
- u32 rx_overrun_errors;
- u32 rx_tooshort_errors;
- u32 rx_toolong_errors;
- u32 rx_outofresource_errors;
-
- u32 rx_discarded; /* via card pattern match filter */
-
- /* TX Errors */
- u32 tx_max_collisions;
- u32 tx_carrier_errors;
- u32 tx_underrun_errors;
- u32 tx_cts_errors;
- u32 tx_timeout_errors;
-
- /* various cruft */
- u32 dataA[6];
- u16 dataB[5];
- u32 dataC[14];
-} __packed;
-
-#define STATUS_MASK 0x0F
-#define COMPLETED (1<<7)
-#define COMPLETED_OK (1<<6)
-#define BUFFER_BUSY (1<<5)
-
-#define CONTROL_EOP (1<<7) /* End Of Packet */
-#define CONTROL_EOL (1<<6) /* End of List */
-
-#define MCA_MC32_ID 0x0041 /* Our MCA ident */
+++ /dev/null
-/* 82596.c: A generic 82596 ethernet driver for linux. */
-/*
- Based on Apricot.c
- Written 1994 by Mark Evans.
- This driver is for the Apricot 82596 bus-master interface
-
- Modularised 12/94 Mark Evans
-
-
- Modified to support the 82596 ethernet chips on 680x0 VME boards.
- by Richard Hirst <richard@sleepie.demon.co.uk>
- Renamed to be 82596.c
-
- 980825: Changed to receive directly in to sk_buffs which are
- allocated at open() time. Eliminates copy on incoming frames
- (small ones are still copied). Shared data now held in a
- non-cached page, so we can run on 68060 in copyback mode.
-
- TBD:
- * look at deferring rx frames rather than discarding (as per tulip)
- * handle tx ring full as per tulip
- * performance test to tune rx_copybreak
-
- Most of my modifications relate to the braindead big-endian
- implementation by Intel. When the i596 is operating in
- 'big-endian' mode, it thinks a 32 bit value of 0x12345678
- should be stored as 0x56781234. This is a real pain, when
- you have linked lists which are shared by the 680x0 and the
- i596.
-
- Driver skeleton
- Written 1993 by Donald Becker.
- Copyright 1993 United States Government as represented by the Director,
- National Security Agency. This software may only be used and distributed
- according to the terms of the GNU General Public License as modified by SRC,
- incorporated herein by reference.
-
- The author may be reached as becker@scyld.com, or C/O
- Scyld Computing Corporation, 410 Severn Ave., Suite 210, Annapolis MD 21403
-
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/init.h>
-#include <linux/bitops.h>
-#include <linux/gfp.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/pgtable.h>
-#include <asm/cacheflush.h>
-
-static char version[] __initdata =
- "82596.c $Revision: 1.5 $\n";
-
-#define DRV_NAME "82596"
-
-/* DEBUG flags
- */
-
-#define DEB_INIT 0x0001
-#define DEB_PROBE 0x0002
-#define DEB_SERIOUS 0x0004
-#define DEB_ERRORS 0x0008
-#define DEB_MULTI 0x0010
-#define DEB_TDR 0x0020
-#define DEB_OPEN 0x0040
-#define DEB_RESET 0x0080
-#define DEB_ADDCMD 0x0100
-#define DEB_STATUS 0x0200
-#define DEB_STARTTX 0x0400
-#define DEB_RXADDR 0x0800
-#define DEB_TXADDR 0x1000
-#define DEB_RXFRAME 0x2000
-#define DEB_INTS 0x4000
-#define DEB_STRUCT 0x8000
-#define DEB_ANY 0xffff
-
-
-#define DEB(x,y) if (i596_debug & (x)) y
-
-
-#if defined(CONFIG_MVME16x_NET) || defined(CONFIG_MVME16x_NET_MODULE)
-#define ENABLE_MVME16x_NET
-#endif
-#if defined(CONFIG_BVME6000_NET) || defined(CONFIG_BVME6000_NET_MODULE)
-#define ENABLE_BVME6000_NET
-#endif
-#if defined(CONFIG_APRICOT) || defined(CONFIG_APRICOT_MODULE)
-#define ENABLE_APRICOT
-#endif
-
-#ifdef ENABLE_MVME16x_NET
-#include <asm/mvme16xhw.h>
-#endif
-#ifdef ENABLE_BVME6000_NET
-#include <asm/bvme6000hw.h>
-#endif
-
-/*
- * Define various macros for Channel Attention, word swapping etc., dependent
- * on architecture. MVME and BVME are 680x0 based, otherwise it is Intel.
- */
-
-#ifdef __mc68000__
-#define WSWAPrfd(x) ((struct i596_rfd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
-#define WSWAPrbd(x) ((struct i596_rbd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
-#define WSWAPiscp(x) ((struct i596_iscp *)(((u32)(x)<<16) | ((((u32)(x)))>>16)))
-#define WSWAPscb(x) ((struct i596_scb *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
-#define WSWAPcmd(x) ((struct i596_cmd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
-#define WSWAPtbd(x) ((struct i596_tbd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
-#define WSWAPchar(x) ((char *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
-#define ISCP_BUSY 0x00010000
-#define MACH_IS_APRICOT 0
-#else
-#define WSWAPrfd(x) ((struct i596_rfd *)((long)x))
-#define WSWAPrbd(x) ((struct i596_rbd *)((long)x))
-#define WSWAPiscp(x) ((struct i596_iscp *)((long)x))
-#define WSWAPscb(x) ((struct i596_scb *)((long)x))
-#define WSWAPcmd(x) ((struct i596_cmd *)((long)x))
-#define WSWAPtbd(x) ((struct i596_tbd *)((long)x))
-#define WSWAPchar(x) ((char *)((long)x))
-#define ISCP_BUSY 0x0001
-#define MACH_IS_APRICOT 1
-#endif
-
-/*
- * The MPU_PORT command allows direct access to the 82596. With PORT access
- * the following commands are available (p5-18). The 32-bit port command
- * must be word-swapped with the most significant word written first.
- * This only applies to VME boards.
- */
-#define PORT_RESET 0x00 /* reset 82596 */
-#define PORT_SELFTEST 0x01 /* selftest */
-#define PORT_ALTSCP 0x02 /* alternate SCB address */
-#define PORT_ALTDUMP 0x03 /* Alternate DUMP address */
-
-static int i596_debug = (DEB_SERIOUS|DEB_PROBE);
-
-MODULE_AUTHOR("Richard Hirst");
-MODULE_DESCRIPTION("i82596 driver");
-MODULE_LICENSE("GPL");
-
-module_param(i596_debug, int, 0);
-MODULE_PARM_DESC(i596_debug, "i82596 debug mask");
-
-
-/* Copy frames shorter than rx_copybreak, otherwise pass on up in
- * a full sized sk_buff. Value of 100 stolen from tulip.c (!alpha).
- */
-static int rx_copybreak = 100;
-
-#define PKT_BUF_SZ 1536
-#define MAX_MC_CNT 64
-
-#define I596_TOTAL_SIZE 17
-
-#define I596_NULL ((void *)0xffffffff)
-
-#define CMD_EOL 0x8000 /* The last command of the list, stop. */
-#define CMD_SUSP 0x4000 /* Suspend after doing cmd. */
-#define CMD_INTR 0x2000 /* Interrupt after doing cmd. */
-
-#define CMD_FLEX 0x0008 /* Enable flexible memory model */
-
-enum commands {
- CmdNOp = 0, CmdSASetup = 1, CmdConfigure = 2, CmdMulticastList = 3,
- CmdTx = 4, CmdTDR = 5, CmdDump = 6, CmdDiagnose = 7
-};
-
-#define STAT_C 0x8000 /* Set to 0 after execution */
-#define STAT_B 0x4000 /* Command being executed */
-#define STAT_OK 0x2000 /* Command executed ok */
-#define STAT_A 0x1000 /* Command aborted */
-
-#define CUC_START 0x0100
-#define CUC_RESUME 0x0200
-#define CUC_SUSPEND 0x0300
-#define CUC_ABORT 0x0400
-#define RX_START 0x0010
-#define RX_RESUME 0x0020
-#define RX_SUSPEND 0x0030
-#define RX_ABORT 0x0040
-
-#define TX_TIMEOUT (HZ/20)
-
-
-struct i596_reg {
- unsigned short porthi;
- unsigned short portlo;
- unsigned long ca;
-};
-
-#define EOF 0x8000
-#define SIZE_MASK 0x3fff
-
-struct i596_tbd {
- unsigned short size;
- unsigned short pad;
- struct i596_tbd *next;
- char *data;
-};
-
-/* The command structure has two 'next' pointers; v_next is the address of
- * the next command as seen by the CPU, b_next is the address of the next
- * command as seen by the 82596. The b_next pointer, as used by the 82596
- * always references the status field of the next command, rather than the
- * v_next field, because the 82596 is unaware of v_next. It may seem more
- * logical to put v_next at the end of the structure, but we cannot do that
- * because the 82596 expects other fields to be there, depending on command
- * type.
- */
-
-struct i596_cmd {
- struct i596_cmd *v_next; /* Address from CPUs viewpoint */
- unsigned short status;
- unsigned short command;
- struct i596_cmd *b_next; /* Address from i596 viewpoint */
-};
-
-struct tx_cmd {
- struct i596_cmd cmd;
- struct i596_tbd *tbd;
- unsigned short size;
- unsigned short pad;
- struct sk_buff *skb; /* So we can free it after tx */
-};
-
-struct tdr_cmd {
- struct i596_cmd cmd;
- unsigned short status;
- unsigned short pad;
-};
-
-struct mc_cmd {
- struct i596_cmd cmd;
- short mc_cnt;
- char mc_addrs[MAX_MC_CNT*6];
-};
-
-struct sa_cmd {
- struct i596_cmd cmd;
- char eth_addr[8];
-};
-
-struct cf_cmd {
- struct i596_cmd cmd;
- char i596_config[16];
-};
-
-struct i596_rfd {
- unsigned short stat;
- unsigned short cmd;
- struct i596_rfd *b_next; /* Address from i596 viewpoint */
- struct i596_rbd *rbd;
- unsigned short count;
- unsigned short size;
- struct i596_rfd *v_next; /* Address from CPUs viewpoint */
- struct i596_rfd *v_prev;
-};
-
-struct i596_rbd {
- unsigned short count;
- unsigned short zero1;
- struct i596_rbd *b_next;
- unsigned char *b_data; /* Address from i596 viewpoint */
- unsigned short size;
- unsigned short zero2;
- struct sk_buff *skb;
- struct i596_rbd *v_next;
- struct i596_rbd *b_addr; /* This rbd addr from i596 view */
- unsigned char *v_data; /* Address from CPUs viewpoint */
-};
-
-#define TX_RING_SIZE 64
-#define RX_RING_SIZE 16
-
-struct i596_scb {
- unsigned short status;
- unsigned short command;
- struct i596_cmd *cmd;
- struct i596_rfd *rfd;
- unsigned long crc_err;
- unsigned long align_err;
- unsigned long resource_err;
- unsigned long over_err;
- unsigned long rcvdt_err;
- unsigned long short_err;
- unsigned short t_on;
- unsigned short t_off;
-};
-
-struct i596_iscp {
- unsigned long stat;
- struct i596_scb *scb;
-};
-
-struct i596_scp {
- unsigned long sysbus;
- unsigned long pad;
- struct i596_iscp *iscp;
-};
-
-struct i596_private {
- volatile struct i596_scp scp;
- volatile struct i596_iscp iscp;
- volatile struct i596_scb scb;
- struct sa_cmd sa_cmd;
- struct cf_cmd cf_cmd;
- struct tdr_cmd tdr_cmd;
- struct mc_cmd mc_cmd;
- unsigned long stat;
- int last_restart __attribute__((aligned(4)));
- struct i596_rfd *rfd_head;
- struct i596_rbd *rbd_head;
- struct i596_cmd *cmd_tail;
- struct i596_cmd *cmd_head;
- int cmd_backlog;
- unsigned long last_cmd;
- struct i596_rfd rfds[RX_RING_SIZE];
- struct i596_rbd rbds[RX_RING_SIZE];
- struct tx_cmd tx_cmds[TX_RING_SIZE];
- struct i596_tbd tbds[TX_RING_SIZE];
- int next_tx_cmd;
- spinlock_t lock;
-};
-
-static char init_setup[] =
-{
- 0x8E, /* length, prefetch on */
- 0xC8, /* fifo to 8, monitor off */
-#ifdef CONFIG_VME
- 0xc0, /* don't save bad frames */
-#else
- 0x80, /* don't save bad frames */
-#endif
- 0x2E, /* No source address insertion, 8 byte preamble */
- 0x00, /* priority and backoff defaults */
- 0x60, /* interframe spacing */
- 0x00, /* slot time LSB */
- 0xf2, /* slot time and retries */
- 0x00, /* promiscuous mode */
- 0x00, /* collision detect */
- 0x40, /* minimum frame length */
- 0xff,
- 0x00,
- 0x7f /* *multi IA */ };
-
-static int i596_open(struct net_device *dev);
-static netdev_tx_t i596_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t i596_interrupt(int irq, void *dev_id);
-static int i596_close(struct net_device *dev);
-static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd);
-static void i596_tx_timeout (struct net_device *dev);
-static void print_eth(unsigned char *buf, char *str);
-static void set_multicast_list(struct net_device *dev);
-
-static int rx_ring_size = RX_RING_SIZE;
-static int ticks_limit = 25;
-static int max_cmd_backlog = TX_RING_SIZE-1;
-
-
-static inline void CA(struct net_device *dev)
-{
-#ifdef ENABLE_MVME16x_NET
- if (MACH_IS_MVME16x) {
- ((struct i596_reg *) dev->base_addr)->ca = 1;
- }
-#endif
-#ifdef ENABLE_BVME6000_NET
- if (MACH_IS_BVME6000) {
- volatile u32 i;
-
- i = *(volatile u32 *) (dev->base_addr);
- }
-#endif
-#ifdef ENABLE_APRICOT
- if (MACH_IS_APRICOT) {
- outw(0, (short) (dev->base_addr) + 4);
- }
-#endif
-}
-
-
-static inline void MPU_PORT(struct net_device *dev, int c, volatile void *x)
-{
-#ifdef ENABLE_MVME16x_NET
- if (MACH_IS_MVME16x) {
- struct i596_reg *p = (struct i596_reg *) (dev->base_addr);
- p->porthi = ((c) | (u32) (x)) & 0xffff;
- p->portlo = ((c) | (u32) (x)) >> 16;
- }
-#endif
-#ifdef ENABLE_BVME6000_NET
- if (MACH_IS_BVME6000) {
- u32 v = (u32) (c) | (u32) (x);
- v = ((u32) (v) << 16) | ((u32) (v) >> 16);
- *(volatile u32 *) dev->base_addr = v;
- udelay(1);
- *(volatile u32 *) dev->base_addr = v;
- }
-#endif
-}
-
-
-static inline int wait_istat(struct net_device *dev, struct i596_private *lp, int delcnt, char *str)
-{
- while (--delcnt && lp->iscp.stat)
- udelay(10);
- if (!delcnt) {
- printk(KERN_ERR "%s: %s, status %4.4x, cmd %4.4x.\n",
- dev->name, str, lp->scb.status, lp->scb.command);
- return -1;
- }
- else
- return 0;
-}
-
-
-static inline int wait_cmd(struct net_device *dev, struct i596_private *lp, int delcnt, char *str)
-{
- while (--delcnt && lp->scb.command)
- udelay(10);
- if (!delcnt) {
- printk(KERN_ERR "%s: %s, status %4.4x, cmd %4.4x.\n",
- dev->name, str, lp->scb.status, lp->scb.command);
- return -1;
- }
- else
- return 0;
-}
-
-
-static inline int wait_cfg(struct net_device *dev, struct i596_cmd *cmd, int delcnt, char *str)
-{
- volatile struct i596_cmd *c = cmd;
-
- while (--delcnt && c->command)
- udelay(10);
- if (!delcnt) {
- printk(KERN_ERR "%s: %s.\n", dev->name, str);
- return -1;
- }
- else
- return 0;
-}
-
-
-static void i596_display_data(struct net_device *dev)
-{
- struct i596_private *lp = dev->ml_priv;
- struct i596_cmd *cmd;
- struct i596_rfd *rfd;
- struct i596_rbd *rbd;
-
- printk(KERN_ERR "lp and scp at %p, .sysbus = %08lx, .iscp = %p\n",
- &lp->scp, lp->scp.sysbus, lp->scp.iscp);
- printk(KERN_ERR "iscp at %p, iscp.stat = %08lx, .scb = %p\n",
- &lp->iscp, lp->iscp.stat, lp->iscp.scb);
- printk(KERN_ERR "scb at %p, scb.status = %04x, .command = %04x,"
- " .cmd = %p, .rfd = %p\n",
- &lp->scb, lp->scb.status, lp->scb.command,
- lp->scb.cmd, lp->scb.rfd);
- printk(KERN_ERR " errors: crc %lx, align %lx, resource %lx,"
- " over %lx, rcvdt %lx, short %lx\n",
- lp->scb.crc_err, lp->scb.align_err, lp->scb.resource_err,
- lp->scb.over_err, lp->scb.rcvdt_err, lp->scb.short_err);
- cmd = lp->cmd_head;
- while (cmd != I596_NULL) {
- printk(KERN_ERR "cmd at %p, .status = %04x, .command = %04x, .b_next = %p\n",
- cmd, cmd->status, cmd->command, cmd->b_next);
- cmd = cmd->v_next;
- }
- rfd = lp->rfd_head;
- printk(KERN_ERR "rfd_head = %p\n", rfd);
- do {
- printk(KERN_ERR " %p .stat %04x, .cmd %04x, b_next %p, rbd %p,"
- " count %04x\n",
- rfd, rfd->stat, rfd->cmd, rfd->b_next, rfd->rbd,
- rfd->count);
- rfd = rfd->v_next;
- } while (rfd != lp->rfd_head);
- rbd = lp->rbd_head;
- printk(KERN_ERR "rbd_head = %p\n", rbd);
- do {
- printk(KERN_ERR " %p .count %04x, b_next %p, b_data %p, size %04x\n",
- rbd, rbd->count, rbd->b_next, rbd->b_data, rbd->size);
- rbd = rbd->v_next;
- } while (rbd != lp->rbd_head);
-}
-
-
-#if defined(ENABLE_MVME16x_NET) || defined(ENABLE_BVME6000_NET)
-static irqreturn_t i596_error(int irq, void *dev_id)
-{
- struct net_device *dev = dev_id;
-#ifdef ENABLE_MVME16x_NET
- if (MACH_IS_MVME16x) {
- volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000;
-
- pcc2[0x28] = 1;
- pcc2[0x2b] = 0x1d;
- }
-#endif
-#ifdef ENABLE_BVME6000_NET
- if (MACH_IS_BVME6000) {
- volatile unsigned char *ethirq = (unsigned char *) BVME_ETHIRQ_REG;
-
- *ethirq = 1;
- *ethirq = 3;
- }
-#endif
- printk(KERN_ERR "%s: Error interrupt\n", dev->name);
- i596_display_data(dev);
- return IRQ_HANDLED;
-}
-#endif
-
-static inline void remove_rx_bufs(struct net_device *dev)
-{
- struct i596_private *lp = dev->ml_priv;
- struct i596_rbd *rbd;
- int i;
-
- for (i = 0, rbd = lp->rbds; i < rx_ring_size; i++, rbd++) {
- if (rbd->skb == NULL)
- break;
- dev_kfree_skb(rbd->skb);
- rbd->skb = NULL;
- }
-}
-
-static inline int init_rx_bufs(struct net_device *dev)
-{
- struct i596_private *lp = dev->ml_priv;
- int i;
- struct i596_rfd *rfd;
- struct i596_rbd *rbd;
-
- /* First build the Receive Buffer Descriptor List */
-
- for (i = 0, rbd = lp->rbds; i < rx_ring_size; i++, rbd++) {
- struct sk_buff *skb = dev_alloc_skb(PKT_BUF_SZ);
-
- if (skb == NULL) {
- remove_rx_bufs(dev);
- return -ENOMEM;
- }
-
- skb->dev = dev;
- rbd->v_next = rbd+1;
- rbd->b_next = WSWAPrbd(virt_to_bus(rbd+1));
- rbd->b_addr = WSWAPrbd(virt_to_bus(rbd));
- rbd->skb = skb;
- rbd->v_data = skb->data;
- rbd->b_data = WSWAPchar(virt_to_bus(skb->data));
- rbd->size = PKT_BUF_SZ;
-#ifdef __mc68000__
- cache_clear(virt_to_phys(skb->data), PKT_BUF_SZ);
-#endif
- }
- lp->rbd_head = lp->rbds;
- rbd = lp->rbds + rx_ring_size - 1;
- rbd->v_next = lp->rbds;
- rbd->b_next = WSWAPrbd(virt_to_bus(lp->rbds));
-
- /* Now build the Receive Frame Descriptor List */
-
- for (i = 0, rfd = lp->rfds; i < rx_ring_size; i++, rfd++) {
- rfd->rbd = I596_NULL;
- rfd->v_next = rfd+1;
- rfd->v_prev = rfd-1;
- rfd->b_next = WSWAPrfd(virt_to_bus(rfd+1));
- rfd->cmd = CMD_FLEX;
- }
- lp->rfd_head = lp->rfds;
- lp->scb.rfd = WSWAPrfd(virt_to_bus(lp->rfds));
- rfd = lp->rfds;
- rfd->rbd = lp->rbd_head;
- rfd->v_prev = lp->rfds + rx_ring_size - 1;
- rfd = lp->rfds + rx_ring_size - 1;
- rfd->v_next = lp->rfds;
- rfd->b_next = WSWAPrfd(virt_to_bus(lp->rfds));
- rfd->cmd = CMD_EOL|CMD_FLEX;
-
- return 0;
-}
-
-
-static void rebuild_rx_bufs(struct net_device *dev)
-{
- struct i596_private *lp = dev->ml_priv;
- int i;
-
- /* Ensure rx frame/buffer descriptors are tidy */
-
- for (i = 0; i < rx_ring_size; i++) {
- lp->rfds[i].rbd = I596_NULL;
- lp->rfds[i].cmd = CMD_FLEX;
- }
- lp->rfds[rx_ring_size-1].cmd = CMD_EOL|CMD_FLEX;
- lp->rfd_head = lp->rfds;
- lp->scb.rfd = WSWAPrfd(virt_to_bus(lp->rfds));
- lp->rbd_head = lp->rbds;
- lp->rfds[0].rbd = WSWAPrbd(virt_to_bus(lp->rbds));
-}
-
-
-static int init_i596_mem(struct net_device *dev)
-{
- struct i596_private *lp = dev->ml_priv;
-#if !defined(ENABLE_MVME16x_NET) && !defined(ENABLE_BVME6000_NET) || defined(ENABLE_APRICOT)
- short ioaddr = dev->base_addr;
-#endif
- unsigned long flags;
-
- MPU_PORT(dev, PORT_RESET, NULL);
-
- udelay(100); /* Wait 100us - seems to help */
-
-#if defined(ENABLE_MVME16x_NET) || defined(ENABLE_BVME6000_NET)
-#ifdef ENABLE_MVME16x_NET
- if (MACH_IS_MVME16x) {
- volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000;
-
- /* Disable all ints for now */
- pcc2[0x28] = 1;
- pcc2[0x2a] = 0x48;
- /* Following disables snooping. Snooping is not required
- * as we make appropriate use of non-cached pages for
- * shared data, and cache_push/cache_clear.
- */
- pcc2[0x2b] = 0x08;
- }
-#endif
-#ifdef ENABLE_BVME6000_NET
- if (MACH_IS_BVME6000) {
- volatile unsigned char *ethirq = (unsigned char *) BVME_ETHIRQ_REG;
-
- *ethirq = 1;
- }
-#endif
-
- /* change the scp address */
-
- MPU_PORT(dev, PORT_ALTSCP, (void *)virt_to_bus((void *)&lp->scp));
-
-#elif defined(ENABLE_APRICOT)
-
- {
- u32 scp = virt_to_bus(&lp->scp);
-
- /* change the scp address */
- outw(0, ioaddr);
- outw(0, ioaddr);
- outb(4, ioaddr + 0xf);
- outw(scp | 2, ioaddr);
- outw(scp >> 16, ioaddr);
- }
-#endif
-
- lp->last_cmd = jiffies;
-
-#ifdef ENABLE_MVME16x_NET
- if (MACH_IS_MVME16x)
- lp->scp.sysbus = 0x00000054;
-#endif
-#ifdef ENABLE_BVME6000_NET
- if (MACH_IS_BVME6000)
- lp->scp.sysbus = 0x0000004c;
-#endif
-#ifdef ENABLE_APRICOT
- if (MACH_IS_APRICOT)
- lp->scp.sysbus = 0x00440000;
-#endif
-
- lp->scp.iscp = WSWAPiscp(virt_to_bus((void *)&lp->iscp));
- lp->iscp.scb = WSWAPscb(virt_to_bus((void *)&lp->scb));
- lp->iscp.stat = ISCP_BUSY;
- lp->cmd_backlog = 0;
-
- lp->cmd_head = lp->scb.cmd = I596_NULL;
-
-#ifdef ENABLE_BVME6000_NET
- if (MACH_IS_BVME6000) {
- lp->scb.t_on = 7 * 25;
- lp->scb.t_off = 1 * 25;
- }
-#endif
-
- DEB(DEB_INIT,printk(KERN_DEBUG "%s: starting i82596.\n", dev->name));
-
-#if defined(ENABLE_APRICOT)
- (void) inb(ioaddr + 0x10);
- outb(4, ioaddr + 0xf);
-#endif
- CA(dev);
-
- if (wait_istat(dev,lp,1000,"initialization timed out"))
- goto failed;
- DEB(DEB_INIT,printk(KERN_DEBUG "%s: i82596 initialization successful\n", dev->name));
-
- /* Ensure rx frame/buffer descriptors are tidy */
- rebuild_rx_bufs(dev);
- lp->scb.command = 0;
-
-#ifdef ENABLE_MVME16x_NET
- if (MACH_IS_MVME16x) {
- volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000;
-
- /* Enable ints, etc. now */
- pcc2[0x2a] = 0x55; /* Edge sensitive */
- pcc2[0x2b] = 0x15;
- }
-#endif
-#ifdef ENABLE_BVME6000_NET
- if (MACH_IS_BVME6000) {
- volatile unsigned char *ethirq = (unsigned char *) BVME_ETHIRQ_REG;
-
- *ethirq = 3;
- }
-#endif
-
-
- DEB(DEB_INIT,printk(KERN_DEBUG "%s: queuing CmdConfigure\n", dev->name));
- memcpy(lp->cf_cmd.i596_config, init_setup, 14);
- lp->cf_cmd.cmd.command = CmdConfigure;
- i596_add_cmd(dev, &lp->cf_cmd.cmd);
-
- DEB(DEB_INIT,printk(KERN_DEBUG "%s: queuing CmdSASetup\n", dev->name));
- memcpy(lp->sa_cmd.eth_addr, dev->dev_addr, 6);
- lp->sa_cmd.cmd.command = CmdSASetup;
- i596_add_cmd(dev, &lp->sa_cmd.cmd);
-
- DEB(DEB_INIT,printk(KERN_DEBUG "%s: queuing CmdTDR\n", dev->name));
- lp->tdr_cmd.cmd.command = CmdTDR;
- i596_add_cmd(dev, &lp->tdr_cmd.cmd);
-
- spin_lock_irqsave (&lp->lock, flags);
-
- if (wait_cmd(dev,lp,1000,"timed out waiting to issue RX_START")) {
- spin_unlock_irqrestore (&lp->lock, flags);
- goto failed;
- }
- DEB(DEB_INIT,printk(KERN_DEBUG "%s: Issuing RX_START\n", dev->name));
- lp->scb.command = RX_START;
- CA(dev);
-
- spin_unlock_irqrestore (&lp->lock, flags);
-
- if (wait_cmd(dev,lp,1000,"RX_START not processed"))
- goto failed;
- DEB(DEB_INIT,printk(KERN_DEBUG "%s: Receive unit started OK\n", dev->name));
- return 0;
-
-failed:
- printk(KERN_CRIT "%s: Failed to initialise 82596\n", dev->name);
- MPU_PORT(dev, PORT_RESET, NULL);
- return -1;
-}
-
-static inline int i596_rx(struct net_device *dev)
-{
- struct i596_private *lp = dev->ml_priv;
- struct i596_rfd *rfd;
- struct i596_rbd *rbd;
- int frames = 0;
-
- DEB(DEB_RXFRAME,printk(KERN_DEBUG "i596_rx(), rfd_head %p, rbd_head %p\n",
- lp->rfd_head, lp->rbd_head));
-
- rfd = lp->rfd_head; /* Ref next frame to check */
-
- while ((rfd->stat) & STAT_C) { /* Loop while complete frames */
- if (rfd->rbd == I596_NULL)
- rbd = I596_NULL;
- else if (rfd->rbd == lp->rbd_head->b_addr)
- rbd = lp->rbd_head;
- else {
- printk(KERN_CRIT "%s: rbd chain broken!\n", dev->name);
- /* XXX Now what? */
- rbd = I596_NULL;
- }
- DEB(DEB_RXFRAME, printk(KERN_DEBUG " rfd %p, rfd.rbd %p, rfd.stat %04x\n",
- rfd, rfd->rbd, rfd->stat));
-
- if (rbd != I596_NULL && ((rfd->stat) & STAT_OK)) {
- /* a good frame */
- int pkt_len = rbd->count & 0x3fff;
- struct sk_buff *skb = rbd->skb;
- int rx_in_place = 0;
-
- DEB(DEB_RXADDR,print_eth(rbd->v_data, "received"));
- frames++;
-
- /* Check if the packet is long enough to just accept
- * without copying to a properly sized skbuff.
- */
-
- if (pkt_len > rx_copybreak) {
- struct sk_buff *newskb;
-
- /* Get fresh skbuff to replace filled one. */
- newskb = dev_alloc_skb(PKT_BUF_SZ);
- if (newskb == NULL) {
- skb = NULL; /* drop pkt */
- goto memory_squeeze;
- }
- /* Pass up the skb already on the Rx ring. */
- skb_put(skb, pkt_len);
- rx_in_place = 1;
- rbd->skb = newskb;
- newskb->dev = dev;
- rbd->v_data = newskb->data;
- rbd->b_data = WSWAPchar(virt_to_bus(newskb->data));
-#ifdef __mc68000__
- cache_clear(virt_to_phys(newskb->data), PKT_BUF_SZ);
-#endif
- }
- else
- skb = dev_alloc_skb(pkt_len + 2);
-memory_squeeze:
- if (skb == NULL) {
- /* XXX tulip.c can defer packets here!! */
- printk(KERN_WARNING "%s: i596_rx Memory squeeze, dropping packet.\n", dev->name);
- dev->stats.rx_dropped++;
- }
- else {
- if (!rx_in_place) {
- /* 16 byte align the data fields */
- skb_reserve(skb, 2);
- memcpy(skb_put(skb,pkt_len), rbd->v_data, pkt_len);
- }
- skb->protocol=eth_type_trans(skb,dev);
- skb->len = pkt_len;
-#ifdef __mc68000__
- cache_clear(virt_to_phys(rbd->skb->data),
- pkt_len);
-#endif
- netif_rx(skb);
- dev->stats.rx_packets++;
- dev->stats.rx_bytes+=pkt_len;
- }
- }
- else {
- DEB(DEB_ERRORS, printk(KERN_DEBUG "%s: Error, rfd.stat = 0x%04x\n",
- dev->name, rfd->stat));
- dev->stats.rx_errors++;
- if ((rfd->stat) & 0x0001)
- dev->stats.collisions++;
- if ((rfd->stat) & 0x0080)
- dev->stats.rx_length_errors++;
- if ((rfd->stat) & 0x0100)
- dev->stats.rx_over_errors++;
- if ((rfd->stat) & 0x0200)
- dev->stats.rx_fifo_errors++;
- if ((rfd->stat) & 0x0400)
- dev->stats.rx_frame_errors++;
- if ((rfd->stat) & 0x0800)
- dev->stats.rx_crc_errors++;
- if ((rfd->stat) & 0x1000)
- dev->stats.rx_length_errors++;
- }
-
- /* Clear the buffer descriptor count and EOF + F flags */
-
- if (rbd != I596_NULL && (rbd->count & 0x4000)) {
- rbd->count = 0;
- lp->rbd_head = rbd->v_next;
- }
-
- /* Tidy the frame descriptor, marking it as end of list */
-
- rfd->rbd = I596_NULL;
- rfd->stat = 0;
- rfd->cmd = CMD_EOL|CMD_FLEX;
- rfd->count = 0;
-
- /* Remove end-of-list from old end descriptor */
-
- rfd->v_prev->cmd = CMD_FLEX;
-
- /* Update record of next frame descriptor to process */
-
- lp->scb.rfd = rfd->b_next;
- lp->rfd_head = rfd->v_next;
- rfd = lp->rfd_head;
- }
-
- DEB(DEB_RXFRAME,printk(KERN_DEBUG "frames %d\n", frames));
-
- return 0;
-}
-
-
-static void i596_cleanup_cmd(struct net_device *dev, struct i596_private *lp)
-{
- struct i596_cmd *ptr;
-
- while (lp->cmd_head != I596_NULL) {
- ptr = lp->cmd_head;
- lp->cmd_head = ptr->v_next;
- lp->cmd_backlog--;
-
- switch ((ptr->command) & 0x7) {
- case CmdTx:
- {
- struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr;
- struct sk_buff *skb = tx_cmd->skb;
-
- dev_kfree_skb(skb);
-
- dev->stats.tx_errors++;
- dev->stats.tx_aborted_errors++;
-
- ptr->v_next = ptr->b_next = I596_NULL;
- tx_cmd->cmd.command = 0; /* Mark as free */
- break;
- }
- default:
- ptr->v_next = ptr->b_next = I596_NULL;
- }
- }
-
- wait_cmd(dev,lp,100,"i596_cleanup_cmd timed out");
- lp->scb.cmd = I596_NULL;
-}
-
-static void i596_reset(struct net_device *dev, struct i596_private *lp,
- int ioaddr)
-{
- unsigned long flags;
-
- DEB(DEB_RESET,printk(KERN_DEBUG "i596_reset\n"));
-
- spin_lock_irqsave (&lp->lock, flags);
-
- wait_cmd(dev,lp,100,"i596_reset timed out");
-
- netif_stop_queue(dev);
-
- lp->scb.command = CUC_ABORT | RX_ABORT;
- CA(dev);
-
- /* wait for shutdown */
- wait_cmd(dev,lp,1000,"i596_reset 2 timed out");
- spin_unlock_irqrestore (&lp->lock, flags);
-
- i596_cleanup_cmd(dev,lp);
- i596_rx(dev);
-
- netif_start_queue(dev);
- init_i596_mem(dev);
-}
-
-static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd)
-{
- struct i596_private *lp = dev->ml_priv;
- int ioaddr = dev->base_addr;
- unsigned long flags;
-
- DEB(DEB_ADDCMD,printk(KERN_DEBUG "i596_add_cmd\n"));
-
- cmd->status = 0;
- cmd->command |= (CMD_EOL | CMD_INTR);
- cmd->v_next = cmd->b_next = I596_NULL;
-
- spin_lock_irqsave (&lp->lock, flags);
-
- if (lp->cmd_head != I596_NULL) {
- lp->cmd_tail->v_next = cmd;
- lp->cmd_tail->b_next = WSWAPcmd(virt_to_bus(&cmd->status));
- } else {
- lp->cmd_head = cmd;
- wait_cmd(dev,lp,100,"i596_add_cmd timed out");
- lp->scb.cmd = WSWAPcmd(virt_to_bus(&cmd->status));
- lp->scb.command = CUC_START;
- CA(dev);
- }
- lp->cmd_tail = cmd;
- lp->cmd_backlog++;
-
- spin_unlock_irqrestore (&lp->lock, flags);
-
- if (lp->cmd_backlog > max_cmd_backlog) {
- unsigned long tickssofar = jiffies - lp->last_cmd;
-
- if (tickssofar < ticks_limit)
- return;
-
- printk(KERN_NOTICE "%s: command unit timed out, status resetting.\n", dev->name);
-
- i596_reset(dev, lp, ioaddr);
- }
-}
-
-static int i596_open(struct net_device *dev)
-{
- int res = 0;
-
- DEB(DEB_OPEN,printk(KERN_DEBUG "%s: i596_open() irq %d.\n", dev->name, dev->irq));
-
- if (request_irq(dev->irq, i596_interrupt, 0, "i82596", dev)) {
- printk(KERN_ERR "%s: IRQ %d not free\n", dev->name, dev->irq);
- return -EAGAIN;
- }
-#ifdef ENABLE_MVME16x_NET
- if (MACH_IS_MVME16x) {
- if (request_irq(0x56, i596_error, 0, "i82596_error", dev)) {
- res = -EAGAIN;
- goto err_irq_dev;
- }
- }
-#endif
- res = init_rx_bufs(dev);
- if (res)
- goto err_irq_56;
-
- netif_start_queue(dev);
-
- if (init_i596_mem(dev)) {
- res = -EAGAIN;
- goto err_queue;
- }
-
- return 0;
-
-err_queue:
- netif_stop_queue(dev);
- remove_rx_bufs(dev);
-err_irq_56:
-#ifdef ENABLE_MVME16x_NET
- free_irq(0x56, dev);
-err_irq_dev:
-#endif
- free_irq(dev->irq, dev);
-
- return res;
-}
-
-static void i596_tx_timeout (struct net_device *dev)
-{
- struct i596_private *lp = dev->ml_priv;
- int ioaddr = dev->base_addr;
-
- /* Transmitter timeout, serious problems. */
- DEB(DEB_ERRORS,printk(KERN_ERR "%s: transmit timed out, status resetting.\n",
- dev->name));
-
- dev->stats.tx_errors++;
-
- /* Try to restart the adaptor */
- if (lp->last_restart == dev->stats.tx_packets) {
- DEB(DEB_ERRORS,printk(KERN_ERR "Resetting board.\n"));
- /* Shutdown and restart */
- i596_reset (dev, lp, ioaddr);
- } else {
- /* Issue a channel attention signal */
- DEB(DEB_ERRORS,printk(KERN_ERR "Kicking board.\n"));
- lp->scb.command = CUC_START | RX_START;
- CA (dev);
- lp->last_restart = dev->stats.tx_packets;
- }
-
- dev->trans_start = jiffies; /* prevent tx timeout */
- netif_wake_queue (dev);
-}
-
-static netdev_tx_t i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- struct i596_private *lp = dev->ml_priv;
- struct tx_cmd *tx_cmd;
- struct i596_tbd *tbd;
- short length = skb->len;
-
- DEB(DEB_STARTTX,printk(KERN_DEBUG "%s: i596_start_xmit(%x,%p) called\n",
- dev->name, skb->len, skb->data));
-
- if (skb->len < ETH_ZLEN) {
- if (skb_padto(skb, ETH_ZLEN))
- return NETDEV_TX_OK;
- length = ETH_ZLEN;
- }
- netif_stop_queue(dev);
-
- tx_cmd = lp->tx_cmds + lp->next_tx_cmd;
- tbd = lp->tbds + lp->next_tx_cmd;
-
- if (tx_cmd->cmd.command) {
- printk(KERN_NOTICE "%s: xmit ring full, dropping packet.\n",
- dev->name);
- dev->stats.tx_dropped++;
-
- dev_kfree_skb(skb);
- } else {
- if (++lp->next_tx_cmd == TX_RING_SIZE)
- lp->next_tx_cmd = 0;
- tx_cmd->tbd = WSWAPtbd(virt_to_bus(tbd));
- tbd->next = I596_NULL;
-
- tx_cmd->cmd.command = CMD_FLEX | CmdTx;
- tx_cmd->skb = skb;
-
- tx_cmd->pad = 0;
- tx_cmd->size = 0;
- tbd->pad = 0;
- tbd->size = EOF | length;
-
- tbd->data = WSWAPchar(virt_to_bus(skb->data));
-
-#ifdef __mc68000__
- cache_push(virt_to_phys(skb->data), length);
-#endif
- DEB(DEB_TXADDR,print_eth(skb->data, "tx-queued"));
- i596_add_cmd(dev, &tx_cmd->cmd);
-
- dev->stats.tx_packets++;
- dev->stats.tx_bytes += length;
- }
-
- netif_start_queue(dev);
-
- return NETDEV_TX_OK;
-}
-
-static void print_eth(unsigned char *add, char *str)
-{
- printk(KERN_DEBUG "i596 0x%p, %pM --> %pM %02X%02X, %s\n",
- add, add + 6, add, add[12], add[13], str);
-}
-
-static int io = 0x300;
-static int irq = 10;
-
-static const struct net_device_ops i596_netdev_ops = {
- .ndo_open = i596_open,
- .ndo_stop = i596_close,
- .ndo_start_xmit = i596_start_xmit,
- .ndo_set_multicast_list = set_multicast_list,
- .ndo_tx_timeout = i596_tx_timeout,
- .ndo_change_mtu = eth_change_mtu,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-struct net_device * __init i82596_probe(int unit)
-{
- struct net_device *dev;
- int i;
- struct i596_private *lp;
- char eth_addr[8];
- static int probed;
- int err;
-
- if (probed)
- return ERR_PTR(-ENODEV);
- probed++;
-
- dev = alloc_etherdev(0);
- if (!dev)
- return ERR_PTR(-ENOMEM);
-
- if (unit >= 0) {
- sprintf(dev->name, "eth%d", unit);
- netdev_boot_setup_check(dev);
- } else {
- dev->base_addr = io;
- dev->irq = irq;
- }
-
-#ifdef ENABLE_MVME16x_NET
- if (MACH_IS_MVME16x) {
- if (mvme16x_config & MVME16x_CONFIG_NO_ETHERNET) {
- printk(KERN_NOTICE "Ethernet probe disabled - chip not present\n");
- err = -ENODEV;
- goto out;
- }
- memcpy(eth_addr, (void *) 0xfffc1f2c, 6); /* YUCK! Get addr from NOVRAM */
- dev->base_addr = MVME_I596_BASE;
- dev->irq = (unsigned) MVME16x_IRQ_I596;
- goto found;
- }
-#endif
-#ifdef ENABLE_BVME6000_NET
- if (MACH_IS_BVME6000) {
- volatile unsigned char *rtc = (unsigned char *) BVME_RTC_BASE;
- unsigned char msr = rtc[3];
- int i;
-
- rtc[3] |= 0x80;
- for (i = 0; i < 6; i++)
- eth_addr[i] = rtc[i * 4 + 7]; /* Stored in RTC RAM at offset 1 */
- rtc[3] = msr;
- dev->base_addr = BVME_I596_BASE;
- dev->irq = (unsigned) BVME_IRQ_I596;
- goto found;
- }
-#endif
-#ifdef ENABLE_APRICOT
- {
- int checksum = 0;
- int ioaddr = 0x300;
-
- /* this is easy the ethernet interface can only be at 0x300 */
- /* first check nothing is already registered here */
-
- if (!request_region(ioaddr, I596_TOTAL_SIZE, DRV_NAME)) {
- printk(KERN_ERR "82596: IO address 0x%04x in use\n", ioaddr);
- err = -EBUSY;
- goto out;
- }
-
- dev->base_addr = ioaddr;
-
- for (i = 0; i < 8; i++) {
- eth_addr[i] = inb(ioaddr + 8 + i);
- checksum += eth_addr[i];
- }
-
- /* checksum is a multiple of 0x100, got this wrong first time
- some machines have 0x100, some 0x200. The DOS driver doesn't
- even bother with the checksum.
- Some other boards trip the checksum.. but then appear as
- ether address 0. Trap these - AC */
-
- if ((checksum % 0x100) ||
- (memcmp(eth_addr, "\x00\x00\x49", 3) != 0)) {
- err = -ENODEV;
- goto out1;
- }
-
- dev->irq = 10;
- goto found;
- }
-#endif
- err = -ENODEV;
- goto out;
-
-found:
- dev->mem_start = (int)__get_free_pages(GFP_ATOMIC, 0);
- if (!dev->mem_start) {
- err = -ENOMEM;
- goto out1;
- }
-
- DEB(DEB_PROBE,printk(KERN_INFO "%s: 82596 at %#3lx,", dev->name, dev->base_addr));
-
- for (i = 0; i < 6; i++)
- DEB(DEB_PROBE,printk(" %2.2X", dev->dev_addr[i] = eth_addr[i]));
-
- DEB(DEB_PROBE,printk(" IRQ %d.\n", dev->irq));
-
- DEB(DEB_PROBE,printk(KERN_INFO "%s", version));
-
- /* The 82596-specific entries in the device structure. */
- dev->netdev_ops = &i596_netdev_ops;
- dev->watchdog_timeo = TX_TIMEOUT;
-
- dev->ml_priv = (void *)(dev->mem_start);
-
- lp = dev->ml_priv;
- DEB(DEB_INIT,printk(KERN_DEBUG "%s: lp at 0x%08lx (%zd bytes), "
- "lp->scb at 0x%08lx\n",
- dev->name, (unsigned long)lp,
- sizeof(struct i596_private), (unsigned long)&lp->scb));
- memset((void *) lp, 0, sizeof(struct i596_private));
-
-#ifdef __mc68000__
- cache_push(virt_to_phys((void *)(dev->mem_start)), 4096);
- cache_clear(virt_to_phys((void *)(dev->mem_start)), 4096);
- kernel_set_cachemode((void *)(dev->mem_start), 4096, IOMAP_NOCACHE_SER);
-#endif
- lp->scb.command = 0;
- lp->scb.cmd = I596_NULL;
- lp->scb.rfd = I596_NULL;
- spin_lock_init(&lp->lock);
-
- err = register_netdev(dev);
- if (err)
- goto out2;
- return dev;
-out2:
-#ifdef __mc68000__
- /* XXX This assumes default cache mode to be IOMAP_FULL_CACHING,
- * XXX which may be invalid (CONFIG_060_WRITETHROUGH)
- */
- kernel_set_cachemode((void *)(dev->mem_start), 4096,
- IOMAP_FULL_CACHING);
-#endif
- free_page ((u32)(dev->mem_start));
-out1:
-#ifdef ENABLE_APRICOT
- release_region(dev->base_addr, I596_TOTAL_SIZE);
-#endif
-out:
- free_netdev(dev);
- return ERR_PTR(err);
-}
-
-static irqreturn_t i596_interrupt(int irq, void *dev_id)
-{
- struct net_device *dev = dev_id;
- struct i596_private *lp;
- short ioaddr;
- unsigned short status, ack_cmd = 0;
- int handled = 0;
-
-#ifdef ENABLE_BVME6000_NET
- if (MACH_IS_BVME6000) {
- if (*(char *) BVME_LOCAL_IRQ_STAT & BVME_ETHERR) {
- i596_error(irq, dev_id);
- return IRQ_HANDLED;
- }
- }
-#endif
- if (dev == NULL) {
- printk(KERN_ERR "i596_interrupt(): irq %d for unknown device.\n", irq);
- return IRQ_NONE;
- }
-
- ioaddr = dev->base_addr;
- lp = dev->ml_priv;
-
- spin_lock (&lp->lock);
-
- wait_cmd(dev,lp,100,"i596 interrupt, timeout");
- status = lp->scb.status;
-
- DEB(DEB_INTS,printk(KERN_DEBUG "%s: i596 interrupt, IRQ %d, status %4.4x.\n",
- dev->name, irq, status));
-
- ack_cmd = status & 0xf000;
-
- if ((status & 0x8000) || (status & 0x2000)) {
- struct i596_cmd *ptr;
-
- handled = 1;
- if ((status & 0x8000))
- DEB(DEB_INTS,printk(KERN_DEBUG "%s: i596 interrupt completed command.\n", dev->name));
- if ((status & 0x2000))
- DEB(DEB_INTS,printk(KERN_DEBUG "%s: i596 interrupt command unit inactive %x.\n", dev->name, status & 0x0700));
-
- while ((lp->cmd_head != I596_NULL) && (lp->cmd_head->status & STAT_C)) {
- ptr = lp->cmd_head;
-
- DEB(DEB_STATUS,printk(KERN_DEBUG "cmd_head->status = %04x, ->command = %04x\n",
- lp->cmd_head->status, lp->cmd_head->command));
- lp->cmd_head = ptr->v_next;
- lp->cmd_backlog--;
-
- switch ((ptr->command) & 0x7) {
- case CmdTx:
- {
- struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr;
- struct sk_buff *skb = tx_cmd->skb;
-
- if ((ptr->status) & STAT_OK) {
- DEB(DEB_TXADDR,print_eth(skb->data, "tx-done"));
- } else {
- dev->stats.tx_errors++;
- if ((ptr->status) & 0x0020)
- dev->stats.collisions++;
- if (!((ptr->status) & 0x0040))
- dev->stats.tx_heartbeat_errors++;
- if ((ptr->status) & 0x0400)
- dev->stats.tx_carrier_errors++;
- if ((ptr->status) & 0x0800)
- dev->stats.collisions++;
- if ((ptr->status) & 0x1000)
- dev->stats.tx_aborted_errors++;
- }
-
- dev_kfree_skb_irq(skb);
-
- tx_cmd->cmd.command = 0; /* Mark free */
- break;
- }
- case CmdTDR:
- {
- unsigned short status = ((struct tdr_cmd *)ptr)->status;
-
- if (status & 0x8000) {
- DEB(DEB_TDR,printk(KERN_INFO "%s: link ok.\n", dev->name));
- } else {
- if (status & 0x4000)
- printk(KERN_ERR "%s: Transceiver problem.\n", dev->name);
- if (status & 0x2000)
- printk(KERN_ERR "%s: Termination problem.\n", dev->name);
- if (status & 0x1000)
- printk(KERN_ERR "%s: Short circuit.\n", dev->name);
-
- DEB(DEB_TDR,printk(KERN_INFO "%s: Time %d.\n", dev->name, status & 0x07ff));
- }
- break;
- }
- case CmdConfigure:
- case CmdMulticastList:
- /* Zap command so set_multicast_list() knows it is free */
- ptr->command = 0;
- break;
- }
- ptr->v_next = ptr->b_next = I596_NULL;
- lp->last_cmd = jiffies;
- }
-
- ptr = lp->cmd_head;
- while ((ptr != I596_NULL) && (ptr != lp->cmd_tail)) {
- ptr->command &= 0x1fff;
- ptr = ptr->v_next;
- }
-
- if ((lp->cmd_head != I596_NULL))
- ack_cmd |= CUC_START;
- lp->scb.cmd = WSWAPcmd(virt_to_bus(&lp->cmd_head->status));
- }
- if ((status & 0x1000) || (status & 0x4000)) {
- if ((status & 0x4000))
- DEB(DEB_INTS,printk(KERN_DEBUG "%s: i596 interrupt received a frame.\n", dev->name));
- i596_rx(dev);
- /* Only RX_START if stopped - RGH 07-07-96 */
- if (status & 0x1000) {
- if (netif_running(dev)) {
- DEB(DEB_ERRORS,printk(KERN_ERR "%s: i596 interrupt receive unit inactive, status 0x%x\n", dev->name, status));
- ack_cmd |= RX_START;
- dev->stats.rx_errors++;
- dev->stats.rx_fifo_errors++;
- rebuild_rx_bufs(dev);
- }
- }
- }
- wait_cmd(dev,lp,100,"i596 interrupt, timeout");
- lp->scb.command = ack_cmd;
-
-#ifdef ENABLE_MVME16x_NET
- if (MACH_IS_MVME16x) {
- /* Ack the interrupt */
-
- volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000;
-
- pcc2[0x2a] |= 0x08;
- }
-#endif
-#ifdef ENABLE_BVME6000_NET
- if (MACH_IS_BVME6000) {
- volatile unsigned char *ethirq = (unsigned char *) BVME_ETHIRQ_REG;
-
- *ethirq = 1;
- *ethirq = 3;
- }
-#endif
-#ifdef ENABLE_APRICOT
- (void) inb(ioaddr + 0x10);
- outb(4, ioaddr + 0xf);
-#endif
- CA(dev);
-
- DEB(DEB_INTS,printk(KERN_DEBUG "%s: exiting interrupt.\n", dev->name));
-
- spin_unlock (&lp->lock);
- return IRQ_RETVAL(handled);
-}
-
-static int i596_close(struct net_device *dev)
-{
- struct i596_private *lp = dev->ml_priv;
- unsigned long flags;
-
- netif_stop_queue(dev);
-
- DEB(DEB_INIT,printk(KERN_DEBUG "%s: Shutting down ethercard, status was %4.4x.\n",
- dev->name, lp->scb.status));
-
- spin_lock_irqsave(&lp->lock, flags);
-
- wait_cmd(dev,lp,100,"close1 timed out");
- lp->scb.command = CUC_ABORT | RX_ABORT;
- CA(dev);
-
- wait_cmd(dev,lp,100,"close2 timed out");
-
- spin_unlock_irqrestore(&lp->lock, flags);
- DEB(DEB_STRUCT,i596_display_data(dev));
- i596_cleanup_cmd(dev,lp);
-
-#ifdef ENABLE_MVME16x_NET
- if (MACH_IS_MVME16x) {
- volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000;
-
- /* Disable all ints */
- pcc2[0x28] = 1;
- pcc2[0x2a] = 0x40;
- pcc2[0x2b] = 0x40; /* Set snooping bits now! */
- }
-#endif
-#ifdef ENABLE_BVME6000_NET
- if (MACH_IS_BVME6000) {
- volatile unsigned char *ethirq = (unsigned char *) BVME_ETHIRQ_REG;
-
- *ethirq = 1;
- }
-#endif
-
-#ifdef ENABLE_MVME16x_NET
- free_irq(0x56, dev);
-#endif
- free_irq(dev->irq, dev);
- remove_rx_bufs(dev);
-
- return 0;
-}
-
-/*
- * Set or clear the multicast filter for this adaptor.
- */
-
-static void set_multicast_list(struct net_device *dev)
-{
- struct i596_private *lp = dev->ml_priv;
- int config = 0, cnt;
-
- DEB(DEB_MULTI,printk(KERN_DEBUG "%s: set multicast list, %d entries, promisc %s, allmulti %s\n",
- dev->name, netdev_mc_count(dev),
- dev->flags & IFF_PROMISC ? "ON" : "OFF",
- dev->flags & IFF_ALLMULTI ? "ON" : "OFF"));
-
- if (wait_cfg(dev, &lp->cf_cmd.cmd, 1000, "config change request timed out"))
- return;
-
- if ((dev->flags & IFF_PROMISC) && !(lp->cf_cmd.i596_config[8] & 0x01)) {
- lp->cf_cmd.i596_config[8] |= 0x01;
- config = 1;
- }
- if (!(dev->flags & IFF_PROMISC) && (lp->cf_cmd.i596_config[8] & 0x01)) {
- lp->cf_cmd.i596_config[8] &= ~0x01;
- config = 1;
- }
- if ((dev->flags & IFF_ALLMULTI) && (lp->cf_cmd.i596_config[11] & 0x20)) {
- lp->cf_cmd.i596_config[11] &= ~0x20;
- config = 1;
- }
- if (!(dev->flags & IFF_ALLMULTI) && !(lp->cf_cmd.i596_config[11] & 0x20)) {
- lp->cf_cmd.i596_config[11] |= 0x20;
- config = 1;
- }
- if (config) {
- lp->cf_cmd.cmd.command = CmdConfigure;
- i596_add_cmd(dev, &lp->cf_cmd.cmd);
- }
-
- cnt = netdev_mc_count(dev);
- if (cnt > MAX_MC_CNT)
- {
- cnt = MAX_MC_CNT;
- printk(KERN_ERR "%s: Only %d multicast addresses supported",
- dev->name, cnt);
- }
-
- if (!netdev_mc_empty(dev)) {
- struct netdev_hw_addr *ha;
- unsigned char *cp;
- struct mc_cmd *cmd;
-
- if (wait_cfg(dev, &lp->mc_cmd.cmd, 1000, "multicast list change request timed out"))
- return;
- cmd = &lp->mc_cmd;
- cmd->cmd.command = CmdMulticastList;
- cmd->mc_cnt = cnt * ETH_ALEN;
- cp = cmd->mc_addrs;
- netdev_for_each_mc_addr(ha, dev) {
- if (!cnt--)
- break;
- memcpy(cp, ha->addr, ETH_ALEN);
- if (i596_debug > 1)
- DEB(DEB_MULTI,printk(KERN_INFO "%s: Adding address %pM\n",
- dev->name, cp));
- cp += ETH_ALEN;
- }
- i596_add_cmd(dev, &cmd->cmd);
- }
-}
-
-#ifdef MODULE
-static struct net_device *dev_82596;
-
-#ifdef ENABLE_APRICOT
-module_param(irq, int, 0);
-MODULE_PARM_DESC(irq, "Apricot IRQ number");
-#endif
-
-static int debug = -1;
-module_param(debug, int, 0);
-MODULE_PARM_DESC(debug, "i82596 debug mask");
-
-int __init init_module(void)
-{
- if (debug >= 0)
- i596_debug = debug;
- dev_82596 = i82596_probe(-1);
- if (IS_ERR(dev_82596))
- return PTR_ERR(dev_82596);
- return 0;
-}
-
-void __exit cleanup_module(void)
-{
- unregister_netdev(dev_82596);
-#ifdef __mc68000__
- /* XXX This assumes default cache mode to be IOMAP_FULL_CACHING,
- * XXX which may be invalid (CONFIG_060_WRITETHROUGH)
- */
-
- kernel_set_cachemode((void *)(dev_82596->mem_start), 4096,
- IOMAP_FULL_CACHING);
-#endif
- free_page ((u32)(dev_82596->mem_start));
-#ifdef ENABLE_APRICOT
- /* If we don't do this, we can't re-insmod it later. */
- release_region(dev_82596->base_addr, I596_TOTAL_SIZE);
-#endif
- free_netdev(dev_82596);
-}
-
-#endif /* MODULE */
say Y and read the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
-config MVME16x_NET
- tristate "MVME16x Ethernet support"
- depends on MVME16x
- help
- This is the driver for the Ethernet interface on the Motorola
- MVME162, 166, 167, 172 and 177 boards. Say Y here to include the
- driver for this chip in your kernel.
- To compile this driver as a module, choose M here.
-
-config BVME6000_NET
- tristate "BVME6000 Ethernet support"
- depends on BVME6000
- help
- This is the driver for the Ethernet interface on BVME4000 and
- BVME6000 VME boards. Say Y here to include the driver for this chip
- in your kernel.
- To compile this driver as a module, choose M here.
-
-config SUN3_82586
- bool "Sun3 on-board Intel 82586 support"
- depends on SUN3
- help
- This driver enables support for the on-board Intel 82586 based
- Ethernet adapter found on Sun 3/1xx and 3/2xx motherboards. Note
- that this driver does not support 82586-based adapters on additional
- VME boards.
-
-config LASI_82596
- tristate "Lasi ethernet"
- depends on GSC
- help
- Say Y here to support the builtin Intel 82596 ethernet controller
- found in Hewlett-Packard PA-RISC machines with 10Mbit ethernet.
-
-config SNI_82596
- tristate "SNI RM ethernet"
- depends on NET_ETHERNET && SNI_RM
- help
- Say Y here to support the on-board Intel 82596 ethernet controller
- built into SNI RM machines.
-
config KORINA
tristate "Korina (IDT RC32434) Ethernet support"
depends on NET_ETHERNET && MIKROTIK_RB532
help
Support for virtual network devices under Sun Logical Domains.
-config EL2
- tristate "3c503 \"EtherLink II\" support"
- depends on ISA
- select CRC32
- ---help---
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called 3c503.
-
-config ELPLUS
- tristate "3c505 \"EtherLink Plus\" support"
- depends on ISA && ISA_DMA_API
- ---help---
- Information about this network (Ethernet) card can be found in
- <file:Documentation/networking/3c505.txt>. If you have a card of
- this type, say Y and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called 3c505.
-
-config EL16
- tristate "3c507 \"EtherLink 16\" support (EXPERIMENTAL)"
- depends on ISA && EXPERIMENTAL
- ---help---
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called 3c507.
-
-config ELMC
- tristate "3c523 \"EtherLink/MC\" support"
- depends on MCA_LEGACY
- ---help---
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called 3c523.
-
-config ELMC_II
- tristate "3c527 \"EtherLink/MC 32\" support (EXPERIMENTAL)"
- depends on MCA && MCA_LEGACY
- ---help---
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called 3c527.
-
config BFIN_MAC
tristate "Blackfin on-chip MAC support"
depends on NET_ETHERNET && (BF516 || BF518 || BF526 || BF527 || BF536 || BF537)
depends on ISA
help
If you have a network (Ethernet) card belonging to this class, such
- as the NI5010, NI5210 or NI6210, say Y and read the Ethernet-HOWTO,
+ as the NI5010, say Y and read the Ethernet-HOWTO,
available from <http://www.tldp.org/docs.html#howto>.
Note that the answer to this question doesn't directly affect the
To compile this driver as a module, choose M here. The module
will be called ni5010.
-config NI52
- tristate "NI5210 support"
- depends on NET_VENDOR_RACAL && ISA
- help
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called ni52.
-
config DNET
tristate "Dave ethernet support (DNET)"
depends on NET_ETHERNET && HAS_IOMEM
To compile this driver as a module, choose M here. The module
will be called ewrk3.
-config EEXPRESS
- tristate "EtherExpress 16 support"
- depends on NET_ISA
- ---help---
- If you have an EtherExpress16 network (Ethernet) card, say Y and
- read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>. Note that the Intel
- EtherExpress16 card used to be regarded as a very poor choice
- because the driver was very unreliable. We now have a new driver
- that should do better.
-
- To compile this driver as a module, choose M here. The module
- will be called eexpress.
-
-config EEXPRESS_PRO
- tristate "EtherExpressPro support/EtherExpress 10 (i82595) support"
- depends on NET_ISA
- ---help---
- If you have a network (Ethernet) card of this type, say Y. This
- driver supports Intel i82595{FX,TX} based boards. Note however
- that the EtherExpress PRO/100 Ethernet card has its own separate
- driver. Please read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called eepro.
-
-config LP486E
- tristate "LP486E on board Ethernet"
- depends on NET_ISA
- help
- Say Y here to support the 82596-based on-board Ethernet controller
- for the Panther motherboard, which is one of the two shipped in the
- Intel Professional Workstation.
-
config ETH16I
tristate "ICL EtherTeam 16i/32 support"
depends on NET_ISA
To compile this driver as a module, choose M here. The module
will be called eth16i.
-config ZNET
- tristate "Zenith Z-Note support (EXPERIMENTAL)"
- depends on NET_ISA && EXPERIMENTAL && ISA_DMA_API
- help
- The Zenith Z-Note notebook computer has a built-in network
- (Ethernet) card, and this is the Linux driver for it. Note that the
- IBM Thinkpad 300 is compatible with the Z-Note and is also supported
- by this driver. Read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
config SEEQ8005
tristate "SEEQ8005 support (EXPERIMENTAL)"
depends on NET_ISA && EXPERIMENTAL
To compile this driver as a module, choose M here. The module
will be called ksz884x.
-config APRICOT
- tristate "Apricot Xen-II on board Ethernet"
- depends on NET_PCI && ISA
- help
- If you have a network (Ethernet) controller of this type, say Y and
- read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called apricot.
-
config FORCEDETH
tristate "nForce Ethernet support"
depends on NET_PCI && PCI
obj-$(CONFIG_MACVTAP) += macvtap.o
obj-$(CONFIG_DE600) += de600.o
obj-$(CONFIG_DE620) += de620.o
-obj-$(CONFIG_SUN3_82586) += sun3_82586.o
obj-$(CONFIG_DEFXX) += defxx.o
obj-$(CONFIG_SGISEEQ) += sgiseeq.o
obj-$(CONFIG_SGI_O2MACE_ETH) += meth.o
obj-$(CONFIG_AT1700) += at1700.o
-obj-$(CONFIG_EL16) += 3c507.o
-obj-$(CONFIG_ELMC) += 3c523.o
obj-$(CONFIG_IBMLANA) += ibmlana.o
-obj-$(CONFIG_ELMC_II) += 3c527.o
-obj-$(CONFIG_EEXPRESS) += eexpress.o
-obj-$(CONFIG_EEXPRESS_PRO) += eepro.o
obj-$(CONFIG_8139CP) += 8139cp.o
obj-$(CONFIG_8139TOO) += 8139too.o
-obj-$(CONFIG_ZNET) += znet.o
obj-$(CONFIG_CPMAC) += cpmac.o
obj-$(CONFIG_EWRK3) += ewrk3.o
obj-$(CONFIG_ATP) += atp.o
obj-$(CONFIG_NI5010) += ni5010.o
-obj-$(CONFIG_NI52) += ni52.o
-obj-$(CONFIG_ELPLUS) += 3c505.o
-obj-$(CONFIG_APRICOT) += 82596.o
-obj-$(CONFIG_LASI_82596) += lasi_82596.o
-obj-$(CONFIG_SNI_82596) += sni_82596.o
-obj-$(CONFIG_MVME16x_NET) += 82596.o
-obj-$(CONFIG_BVME6000_NET) += 82596.o
obj-$(CONFIG_SC92031) += sc92031.o
-# This is also a 82596 and should probably be merged
-obj-$(CONFIG_LP486E) += lp486e.o
-
obj-$(CONFIG_ETH16I) += eth16i.o
obj-$(CONFIG_EQUALIZER) += eql.o
obj-$(CONFIG_KORINA) += korina.o
# These are for Acorn's Expansion card network interfaces
#
-config ARM_ETHER1
- tristate "Acorn Ether1 support"
- depends on ARM && ARCH_ACORN
- help
- If you have an Acorn system with one of these (AKA25) network cards,
- you should say Y to this option if you wish to use it with Linux.
-
config ARM_ETHER3
tristate "Acorn/ANT Ether3 support"
depends on ARM && ARCH_ACORN
#
obj-$(CONFIG_ARM_ETHER3) += ether3.o
-obj-$(CONFIG_ARM_ETHER1) += ether1.o
obj-$(CONFIG_ARM_AT91_ETHER) += at91_ether.o
obj-$(CONFIG_ARM_KS8695_ETHER) += ks8695net.o
obj-$(CONFIG_EP93XX_ETH) += ep93xx_eth.o
+++ /dev/null
-/*
- * linux/drivers/acorn/net/ether1.c
- *
- * Copyright (C) 1996-2000 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Acorn ether1 driver (82586 chip) for Acorn machines
- *
- * We basically keep two queues in the cards memory - one for transmit
- * and one for receive. Each has a head and a tail. The head is where
- * we/the chip adds packets to be transmitted/received, and the tail
- * is where the transmitter has got to/where the receiver will stop.
- * Both of these queues are circular, and since the chip is running
- * all the time, we have to be careful when we modify the pointers etc
- * so that the buffer memory contents is valid all the time.
- *
- * Change log:
- * 1.00 RMK Released
- * 1.01 RMK 19/03/1996 Transfers the last odd byte onto/off of the card now.
- * 1.02 RMK 25/05/1997 Added code to restart RU if it goes not ready
- * 1.03 RMK 14/09/1997 Cleaned up the handling of a reset during the TX interrupt.
- * Should prevent lockup.
- * 1.04 RMK 17/09/1997 Added more info when initialsation of chip goes wrong.
- * TDR now only reports failure when chip reports non-zero
- * TDR time-distance.
- * 1.05 RMK 31/12/1997 Removed calls to dev_tint for 2.1
- * 1.06 RMK 10/02/2000 Updated for 2.3.43
- * 1.07 RMK 13/05/2000 Updated for 2.3.99-pre8
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/device.h>
-#include <linux/init.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/bitops.h>
-
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/ecard.h>
-
-#define __ETHER1_C
-#include "ether1.h"
-
-static unsigned int net_debug = NET_DEBUG;
-
-#define BUFFER_SIZE 0x10000
-#define TX_AREA_START 0x00100
-#define TX_AREA_END 0x05000
-#define RX_AREA_START 0x05000
-#define RX_AREA_END 0x0fc00
-
-static int ether1_open(struct net_device *dev);
-static int ether1_sendpacket(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t ether1_interrupt(int irq, void *dev_id);
-static int ether1_close(struct net_device *dev);
-static void ether1_setmulticastlist(struct net_device *dev);
-static void ether1_timeout(struct net_device *dev);
-
-/* ------------------------------------------------------------------------- */
-
-static char version[] __devinitdata = "ether1 ethernet driver (c) 2000 Russell King v1.07\n";
-
-#define BUS_16 16
-#define BUS_8 8
-
-/* ------------------------------------------------------------------------- */
-
-#define DISABLEIRQS 1
-#define NORMALIRQS 0
-
-#define ether1_readw(dev, addr, type, offset, svflgs) ether1_inw_p (dev, addr + (int)(&((type *)0)->offset), svflgs)
-#define ether1_writew(dev, val, addr, type, offset, svflgs) ether1_outw_p (dev, val, addr + (int)(&((type *)0)->offset), svflgs)
-
-static inline unsigned short
-ether1_inw_p (struct net_device *dev, int addr, int svflgs)
-{
- unsigned long flags;
- unsigned short ret;
-
- if (svflgs)
- local_irq_save (flags);
-
- writeb(addr >> 12, REG_PAGE);
- ret = readw(ETHER1_RAM + ((addr & 4095) << 1));
- if (svflgs)
- local_irq_restore (flags);
- return ret;
-}
-
-static inline void
-ether1_outw_p (struct net_device *dev, unsigned short val, int addr, int svflgs)
-{
- unsigned long flags;
-
- if (svflgs)
- local_irq_save (flags);
-
- writeb(addr >> 12, REG_PAGE);
- writew(val, ETHER1_RAM + ((addr & 4095) << 1));
- if (svflgs)
- local_irq_restore (flags);
-}
-
-/*
- * Some inline assembler to allow fast transfers on to/off of the card.
- * Since this driver depends on some features presented by the ARM
- * specific architecture, and that you can't configure this driver
- * without specifiing ARM mode, this is not a problem.
- *
- * This routine is essentially an optimised memcpy from the card's
- * onboard RAM to kernel memory.
- */
-static void
-ether1_writebuffer (struct net_device *dev, void *data, unsigned int start, unsigned int length)
-{
- unsigned int page, thislen, offset;
- void __iomem *addr;
-
- offset = start & 4095;
- page = start >> 12;
- addr = ETHER1_RAM + (offset << 1);
-
- if (offset + length > 4096)
- thislen = 4096 - offset;
- else
- thislen = length;
-
- do {
- int used;
-
- writeb(page, REG_PAGE);
- length -= thislen;
-
- __asm__ __volatile__(
- "subs %3, %3, #2\n\
- bmi 2f\n\
-1: ldr %0, [%1], #2\n\
- mov %0, %0, lsl #16\n\
- orr %0, %0, %0, lsr #16\n\
- str %0, [%2], #4\n\
- subs %3, %3, #2\n\
- bmi 2f\n\
- ldr %0, [%1], #2\n\
- mov %0, %0, lsl #16\n\
- orr %0, %0, %0, lsr #16\n\
- str %0, [%2], #4\n\
- subs %3, %3, #2\n\
- bmi 2f\n\
- ldr %0, [%1], #2\n\
- mov %0, %0, lsl #16\n\
- orr %0, %0, %0, lsr #16\n\
- str %0, [%2], #4\n\
- subs %3, %3, #2\n\
- bmi 2f\n\
- ldr %0, [%1], #2\n\
- mov %0, %0, lsl #16\n\
- orr %0, %0, %0, lsr #16\n\
- str %0, [%2], #4\n\
- subs %3, %3, #2\n\
- bpl 1b\n\
-2: adds %3, %3, #1\n\
- ldreqb %0, [%1]\n\
- streqb %0, [%2]"
- : "=&r" (used), "=&r" (data)
- : "r" (addr), "r" (thislen), "1" (data));
-
- addr = ETHER1_RAM;
-
- thislen = length;
- if (thislen > 4096)
- thislen = 4096;
- page++;
- } while (thislen);
-}
-
-static void
-ether1_readbuffer (struct net_device *dev, void *data, unsigned int start, unsigned int length)
-{
- unsigned int page, thislen, offset;
- void __iomem *addr;
-
- offset = start & 4095;
- page = start >> 12;
- addr = ETHER1_RAM + (offset << 1);
-
- if (offset + length > 4096)
- thislen = 4096 - offset;
- else
- thislen = length;
-
- do {
- int used;
-
- writeb(page, REG_PAGE);
- length -= thislen;
-
- __asm__ __volatile__(
- "subs %3, %3, #2\n\
- bmi 2f\n\
-1: ldr %0, [%2], #4\n\
- strb %0, [%1], #1\n\
- mov %0, %0, lsr #8\n\
- strb %0, [%1], #1\n\
- subs %3, %3, #2\n\
- bmi 2f\n\
- ldr %0, [%2], #4\n\
- strb %0, [%1], #1\n\
- mov %0, %0, lsr #8\n\
- strb %0, [%1], #1\n\
- subs %3, %3, #2\n\
- bmi 2f\n\
- ldr %0, [%2], #4\n\
- strb %0, [%1], #1\n\
- mov %0, %0, lsr #8\n\
- strb %0, [%1], #1\n\
- subs %3, %3, #2\n\
- bmi 2f\n\
- ldr %0, [%2], #4\n\
- strb %0, [%1], #1\n\
- mov %0, %0, lsr #8\n\
- strb %0, [%1], #1\n\
- subs %3, %3, #2\n\
- bpl 1b\n\
-2: adds %3, %3, #1\n\
- ldreqb %0, [%2]\n\
- streqb %0, [%1]"
- : "=&r" (used), "=&r" (data)
- : "r" (addr), "r" (thislen), "1" (data));
-
- addr = ETHER1_RAM;
-
- thislen = length;
- if (thislen > 4096)
- thislen = 4096;
- page++;
- } while (thislen);
-}
-
-static int __devinit
-ether1_ramtest(struct net_device *dev, unsigned char byte)
-{
- unsigned char *buffer = kmalloc (BUFFER_SIZE, GFP_KERNEL);
- int i, ret = BUFFER_SIZE;
- int max_errors = 15;
- int bad = -1;
- int bad_start = 0;
-
- if (!buffer)
- return 1;
-
- memset (buffer, byte, BUFFER_SIZE);
- ether1_writebuffer (dev, buffer, 0, BUFFER_SIZE);
- memset (buffer, byte ^ 0xff, BUFFER_SIZE);
- ether1_readbuffer (dev, buffer, 0, BUFFER_SIZE);
-
- for (i = 0; i < BUFFER_SIZE; i++) {
- if (buffer[i] != byte) {
- if (max_errors >= 0 && bad != buffer[i]) {
- if (bad != -1)
- printk ("\n");
- printk (KERN_CRIT "%s: RAM failed with (%02X instead of %02X) at 0x%04X",
- dev->name, buffer[i], byte, i);
- ret = -ENODEV;
- max_errors --;
- bad = buffer[i];
- bad_start = i;
- }
- } else {
- if (bad != -1) {
- if (bad_start == i - 1)
- printk ("\n");
- else
- printk (" - 0x%04X\n", i - 1);
- bad = -1;
- }
- }
- }
-
- if (bad != -1)
- printk (" - 0x%04X\n", BUFFER_SIZE);
- kfree (buffer);
-
- return ret;
-}
-
-static int
-ether1_reset (struct net_device *dev)
-{
- writeb(CTRL_RST|CTRL_ACK, REG_CONTROL);
- return BUS_16;
-}
-
-static int __devinit
-ether1_init_2(struct net_device *dev)
-{
- int i;
- dev->mem_start = 0;
-
- i = ether1_ramtest (dev, 0x5a);
-
- if (i > 0)
- i = ether1_ramtest (dev, 0x1e);
-
- if (i <= 0)
- return -ENODEV;
-
- dev->mem_end = i;
- return 0;
-}
-
-/*
- * These are the structures that are loaded into the ether RAM card to
- * initialise the 82586
- */
-
-/* at 0x0100 */
-#define NOP_ADDR (TX_AREA_START)
-#define NOP_SIZE (0x06)
-static nop_t init_nop = {
- 0,
- CMD_NOP,
- NOP_ADDR
-};
-
-/* at 0x003a */
-#define TDR_ADDR (0x003a)
-#define TDR_SIZE (0x08)
-static tdr_t init_tdr = {
- 0,
- CMD_TDR | CMD_INTR,
- NOP_ADDR,
- 0
-};
-
-/* at 0x002e */
-#define MC_ADDR (0x002e)
-#define MC_SIZE (0x0c)
-static mc_t init_mc = {
- 0,
- CMD_SETMULTICAST,
- TDR_ADDR,
- 0,
- { { 0, } }
-};
-
-/* at 0x0022 */
-#define SA_ADDR (0x0022)
-#define SA_SIZE (0x0c)
-static sa_t init_sa = {
- 0,
- CMD_SETADDRESS,
- MC_ADDR,
- { 0, }
-};
-
-/* at 0x0010 */
-#define CFG_ADDR (0x0010)
-#define CFG_SIZE (0x12)
-static cfg_t init_cfg = {
- 0,
- CMD_CONFIG,
- SA_ADDR,
- 8,
- 8,
- CFG8_SRDY,
- CFG9_PREAMB8 | CFG9_ADDRLENBUF | CFG9_ADDRLEN(6),
- 0,
- 0x60,
- 0,
- CFG13_RETRY(15) | CFG13_SLOTH(2),
- 0,
-};
-
-/* at 0x0000 */
-#define SCB_ADDR (0x0000)
-#define SCB_SIZE (0x10)
-static scb_t init_scb = {
- 0,
- SCB_CMDACKRNR | SCB_CMDACKCNA | SCB_CMDACKFR | SCB_CMDACKCX,
- CFG_ADDR,
- RX_AREA_START,
- 0,
- 0,
- 0,
- 0
-};
-
-/* at 0xffee */
-#define ISCP_ADDR (0xffee)
-#define ISCP_SIZE (0x08)
-static iscp_t init_iscp = {
- 1,
- SCB_ADDR,
- 0x0000,
- 0x0000
-};
-
-/* at 0xfff6 */
-#define SCP_ADDR (0xfff6)
-#define SCP_SIZE (0x0a)
-static scp_t init_scp = {
- SCP_SY_16BBUS,
- { 0, 0 },
- ISCP_ADDR,
- 0
-};
-
-#define RFD_SIZE (0x16)
-static rfd_t init_rfd = {
- 0,
- 0,
- 0,
- 0,
- { 0, },
- { 0, },
- 0
-};
-
-#define RBD_SIZE (0x0a)
-static rbd_t init_rbd = {
- 0,
- 0,
- 0,
- 0,
- ETH_FRAME_LEN + 8
-};
-
-#define TX_SIZE (0x08)
-#define TBD_SIZE (0x08)
-
-static int
-ether1_init_for_open (struct net_device *dev)
-{
- int i, status, addr, next, next2;
- int failures = 0;
- unsigned long timeout;
-
- writeb(CTRL_RST|CTRL_ACK, REG_CONTROL);
-
- for (i = 0; i < 6; i++)
- init_sa.sa_addr[i] = dev->dev_addr[i];
-
- /* load data structures into ether1 RAM */
- ether1_writebuffer (dev, &init_scp, SCP_ADDR, SCP_SIZE);
- ether1_writebuffer (dev, &init_iscp, ISCP_ADDR, ISCP_SIZE);
- ether1_writebuffer (dev, &init_scb, SCB_ADDR, SCB_SIZE);
- ether1_writebuffer (dev, &init_cfg, CFG_ADDR, CFG_SIZE);
- ether1_writebuffer (dev, &init_sa, SA_ADDR, SA_SIZE);
- ether1_writebuffer (dev, &init_mc, MC_ADDR, MC_SIZE);
- ether1_writebuffer (dev, &init_tdr, TDR_ADDR, TDR_SIZE);
- ether1_writebuffer (dev, &init_nop, NOP_ADDR, NOP_SIZE);
-
- if (ether1_readw(dev, CFG_ADDR, cfg_t, cfg_command, NORMALIRQS) != CMD_CONFIG) {
- printk (KERN_ERR "%s: detected either RAM fault or compiler bug\n",
- dev->name);
- return 1;
- }
-
- /*
- * setup circularly linked list of { rfd, rbd, buffer }, with
- * all rfds circularly linked, rbds circularly linked.
- * First rfd is linked to scp, first rbd is linked to first
- * rfd. Last rbd has a suspend command.
- */
- addr = RX_AREA_START;
- do {
- next = addr + RFD_SIZE + RBD_SIZE + ETH_FRAME_LEN + 10;
- next2 = next + RFD_SIZE + RBD_SIZE + ETH_FRAME_LEN + 10;
-
- if (next2 >= RX_AREA_END) {
- next = RX_AREA_START;
- init_rfd.rfd_command = RFD_CMDEL | RFD_CMDSUSPEND;
- priv(dev)->rx_tail = addr;
- } else
- init_rfd.rfd_command = 0;
- if (addr == RX_AREA_START)
- init_rfd.rfd_rbdoffset = addr + RFD_SIZE;
- else
- init_rfd.rfd_rbdoffset = 0;
- init_rfd.rfd_link = next;
- init_rbd.rbd_link = next + RFD_SIZE;
- init_rbd.rbd_bufl = addr + RFD_SIZE + RBD_SIZE;
-
- ether1_writebuffer (dev, &init_rfd, addr, RFD_SIZE);
- ether1_writebuffer (dev, &init_rbd, addr + RFD_SIZE, RBD_SIZE);
- addr = next;
- } while (next2 < RX_AREA_END);
-
- priv(dev)->tx_link = NOP_ADDR;
- priv(dev)->tx_head = NOP_ADDR + NOP_SIZE;
- priv(dev)->tx_tail = TDR_ADDR;
- priv(dev)->rx_head = RX_AREA_START;
-
- /* release reset & give 586 a prod */
- priv(dev)->resetting = 1;
- priv(dev)->initialising = 1;
- writeb(CTRL_RST, REG_CONTROL);
- writeb(0, REG_CONTROL);
- writeb(CTRL_CA, REG_CONTROL);
-
- /* 586 should now unset iscp.busy */
- timeout = jiffies + HZ/2;
- while (ether1_readw(dev, ISCP_ADDR, iscp_t, iscp_busy, DISABLEIRQS) == 1) {
- if (time_after(jiffies, timeout)) {
- printk (KERN_WARNING "%s: can't initialise 82586: iscp is busy\n", dev->name);
- return 1;
- }
- }
-
- /* check status of commands that we issued */
- timeout += HZ/10;
- while (((status = ether1_readw(dev, CFG_ADDR, cfg_t, cfg_status, DISABLEIRQS))
- & STAT_COMPLETE) == 0) {
- if (time_after(jiffies, timeout))
- break;
- }
-
- if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) {
- printk (KERN_WARNING "%s: can't initialise 82586: config status %04X\n", dev->name, status);
- printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name,
- ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS),
- ether1_readw(dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS),
- ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS),
- ether1_readw(dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS));
- failures += 1;
- }
-
- timeout += HZ/10;
- while (((status = ether1_readw(dev, SA_ADDR, sa_t, sa_status, DISABLEIRQS))
- & STAT_COMPLETE) == 0) {
- if (time_after(jiffies, timeout))
- break;
- }
-
- if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) {
- printk (KERN_WARNING "%s: can't initialise 82586: set address status %04X\n", dev->name, status);
- printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name,
- ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS),
- ether1_readw(dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS),
- ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS),
- ether1_readw(dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS));
- failures += 1;
- }
-
- timeout += HZ/10;
- while (((status = ether1_readw(dev, MC_ADDR, mc_t, mc_status, DISABLEIRQS))
- & STAT_COMPLETE) == 0) {
- if (time_after(jiffies, timeout))
- break;
- }
-
- if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) {
- printk (KERN_WARNING "%s: can't initialise 82586: set multicast status %04X\n", dev->name, status);
- printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name,
- ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS),
- ether1_readw(dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS),
- ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS),
- ether1_readw(dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS));
- failures += 1;
- }
-
- timeout += HZ;
- while (((status = ether1_readw(dev, TDR_ADDR, tdr_t, tdr_status, DISABLEIRQS))
- & STAT_COMPLETE) == 0) {
- if (time_after(jiffies, timeout))
- break;
- }
-
- if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) {
- printk (KERN_WARNING "%s: can't tdr (ignored)\n", dev->name);
- printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name,
- ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS),
- ether1_readw(dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS),
- ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS),
- ether1_readw(dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS));
- } else {
- status = ether1_readw(dev, TDR_ADDR, tdr_t, tdr_result, DISABLEIRQS);
- if (status & TDR_XCVRPROB)
- printk (KERN_WARNING "%s: i/f failed tdr: transceiver problem\n", dev->name);
- else if ((status & (TDR_SHORT|TDR_OPEN)) && (status & TDR_TIME)) {
-#ifdef FANCY
- printk (KERN_WARNING "%s: i/f failed tdr: cable %s %d.%d us away\n", dev->name,
- status & TDR_SHORT ? "short" : "open", (status & TDR_TIME) / 10,
- (status & TDR_TIME) % 10);
-#else
- printk (KERN_WARNING "%s: i/f failed tdr: cable %s %d clks away\n", dev->name,
- status & TDR_SHORT ? "short" : "open", (status & TDR_TIME));
-#endif
- }
- }
-
- if (failures)
- ether1_reset (dev);
- return failures ? 1 : 0;
-}
-
-/* ------------------------------------------------------------------------- */
-
-static int
-ether1_txalloc (struct net_device *dev, int size)
-{
- int start, tail;
-
- size = (size + 1) & ~1;
- tail = priv(dev)->tx_tail;
-
- if (priv(dev)->tx_head + size > TX_AREA_END) {
- if (tail > priv(dev)->tx_head)
- return -1;
- start = TX_AREA_START;
- if (start + size > tail)
- return -1;
- priv(dev)->tx_head = start + size;
- } else {
- if (priv(dev)->tx_head < tail && (priv(dev)->tx_head + size) > tail)
- return -1;
- start = priv(dev)->tx_head;
- priv(dev)->tx_head += size;
- }
-
- return start;
-}
-
-static int
-ether1_open (struct net_device *dev)
-{
- if (!is_valid_ether_addr(dev->dev_addr)) {
- printk(KERN_WARNING "%s: invalid ethernet MAC address\n",
- dev->name);
- return -EINVAL;
- }
-
- if (request_irq(dev->irq, ether1_interrupt, 0, "ether1", dev))
- return -EAGAIN;
-
- if (ether1_init_for_open (dev)) {
- free_irq (dev->irq, dev);
- return -EAGAIN;
- }
-
- netif_start_queue(dev);
-
- return 0;
-}
-
-static void
-ether1_timeout(struct net_device *dev)
-{
- printk(KERN_WARNING "%s: transmit timeout, network cable problem?\n",
- dev->name);
- printk(KERN_WARNING "%s: resetting device\n", dev->name);
-
- ether1_reset (dev);
-
- if (ether1_init_for_open (dev))
- printk (KERN_ERR "%s: unable to restart interface\n", dev->name);
-
- dev->stats.tx_errors++;
- netif_wake_queue(dev);
-}
-
-static int
-ether1_sendpacket (struct sk_buff *skb, struct net_device *dev)
-{
- int tmp, tst, nopaddr, txaddr, tbdaddr, dataddr;
- unsigned long flags;
- tx_t tx;
- tbd_t tbd;
- nop_t nop;
-
- if (priv(dev)->restart) {
- printk(KERN_WARNING "%s: resetting device\n", dev->name);
-
- ether1_reset(dev);
-
- if (ether1_init_for_open(dev))
- printk(KERN_ERR "%s: unable to restart interface\n", dev->name);
- else
- priv(dev)->restart = 0;
- }
-
- if (skb->len < ETH_ZLEN) {
- if (skb_padto(skb, ETH_ZLEN))
- goto out;
- }
-
- /*
- * insert packet followed by a nop
- */
- txaddr = ether1_txalloc (dev, TX_SIZE);
- tbdaddr = ether1_txalloc (dev, TBD_SIZE);
- dataddr = ether1_txalloc (dev, skb->len);
- nopaddr = ether1_txalloc (dev, NOP_SIZE);
-
- tx.tx_status = 0;
- tx.tx_command = CMD_TX | CMD_INTR;
- tx.tx_link = nopaddr;
- tx.tx_tbdoffset = tbdaddr;
- tbd.tbd_opts = TBD_EOL | skb->len;
- tbd.tbd_link = I82586_NULL;
- tbd.tbd_bufl = dataddr;
- tbd.tbd_bufh = 0;
- nop.nop_status = 0;
- nop.nop_command = CMD_NOP;
- nop.nop_link = nopaddr;
-
- local_irq_save(flags);
- ether1_writebuffer (dev, &tx, txaddr, TX_SIZE);
- ether1_writebuffer (dev, &tbd, tbdaddr, TBD_SIZE);
- ether1_writebuffer (dev, skb->data, dataddr, skb->len);
- ether1_writebuffer (dev, &nop, nopaddr, NOP_SIZE);
- tmp = priv(dev)->tx_link;
- priv(dev)->tx_link = nopaddr;
-
- /* now reset the previous nop pointer */
- ether1_writew(dev, txaddr, tmp, nop_t, nop_link, NORMALIRQS);
-
- local_irq_restore(flags);
-
- /* handle transmit */
-
- /* check to see if we have room for a full sized ether frame */
- tmp = priv(dev)->tx_head;
- tst = ether1_txalloc (dev, TX_SIZE + TBD_SIZE + NOP_SIZE + ETH_FRAME_LEN);
- priv(dev)->tx_head = tmp;
- dev_kfree_skb (skb);
-
- if (tst == -1)
- netif_stop_queue(dev);
-
- out:
- return NETDEV_TX_OK;
-}
-
-static void
-ether1_xmit_done (struct net_device *dev)
-{
- nop_t nop;
- int caddr, tst;
-
- caddr = priv(dev)->tx_tail;
-
-again:
- ether1_readbuffer (dev, &nop, caddr, NOP_SIZE);
-
- switch (nop.nop_command & CMD_MASK) {
- case CMD_TDR:
- /* special case */
- if (ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS)
- != (unsigned short)I82586_NULL) {
- ether1_writew(dev, SCB_CMDCUCSTART | SCB_CMDRXSTART, SCB_ADDR, scb_t,
- scb_command, NORMALIRQS);
- writeb(CTRL_CA, REG_CONTROL);
- }
- priv(dev)->tx_tail = NOP_ADDR;
- return;
-
- case CMD_NOP:
- if (nop.nop_link == caddr) {
- if (priv(dev)->initialising == 0)
- printk (KERN_WARNING "%s: strange command complete with no tx command!\n", dev->name);
- else
- priv(dev)->initialising = 0;
- return;
- }
- if (caddr == nop.nop_link)
- return;
- caddr = nop.nop_link;
- goto again;
-
- case CMD_TX:
- if (nop.nop_status & STAT_COMPLETE)
- break;
- printk (KERN_ERR "%s: strange command complete without completed command\n", dev->name);
- priv(dev)->restart = 1;
- return;
-
- default:
- printk (KERN_WARNING "%s: strange command %d complete! (offset %04X)", dev->name,
- nop.nop_command & CMD_MASK, caddr);
- priv(dev)->restart = 1;
- return;
- }
-
- while (nop.nop_status & STAT_COMPLETE) {
- if (nop.nop_status & STAT_OK) {
- dev->stats.tx_packets++;
- dev->stats.collisions += (nop.nop_status & STAT_COLLISIONS);
- } else {
- dev->stats.tx_errors++;
-
- if (nop.nop_status & STAT_COLLAFTERTX)
- dev->stats.collisions++;
- if (nop.nop_status & STAT_NOCARRIER)
- dev->stats.tx_carrier_errors++;
- if (nop.nop_status & STAT_TXLOSTCTS)
- printk (KERN_WARNING "%s: cts lost\n", dev->name);
- if (nop.nop_status & STAT_TXSLOWDMA)
- dev->stats.tx_fifo_errors++;
- if (nop.nop_status & STAT_COLLEXCESSIVE)
- dev->stats.collisions += 16;
- }
-
- if (nop.nop_link == caddr) {
- printk (KERN_ERR "%s: tx buffer chaining error: tx command points to itself\n", dev->name);
- break;
- }
-
- caddr = nop.nop_link;
- ether1_readbuffer (dev, &nop, caddr, NOP_SIZE);
- if ((nop.nop_command & CMD_MASK) != CMD_NOP) {
- printk (KERN_ERR "%s: tx buffer chaining error: no nop after tx command\n", dev->name);
- break;
- }
-
- if (caddr == nop.nop_link)
- break;
-
- caddr = nop.nop_link;
- ether1_readbuffer (dev, &nop, caddr, NOP_SIZE);
- if ((nop.nop_command & CMD_MASK) != CMD_TX) {
- printk (KERN_ERR "%s: tx buffer chaining error: no tx command after nop\n", dev->name);
- break;
- }
- }
- priv(dev)->tx_tail = caddr;
-
- caddr = priv(dev)->tx_head;
- tst = ether1_txalloc (dev, TX_SIZE + TBD_SIZE + NOP_SIZE + ETH_FRAME_LEN);
- priv(dev)->tx_head = caddr;
- if (tst != -1)
- netif_wake_queue(dev);
-}
-
-static void
-ether1_recv_done (struct net_device *dev)
-{
- int status;
- int nexttail, rbdaddr;
- rbd_t rbd;
-
- do {
- status = ether1_readw(dev, priv(dev)->rx_head, rfd_t, rfd_status, NORMALIRQS);
- if ((status & RFD_COMPLETE) == 0)
- break;
-
- rbdaddr = ether1_readw(dev, priv(dev)->rx_head, rfd_t, rfd_rbdoffset, NORMALIRQS);
- ether1_readbuffer (dev, &rbd, rbdaddr, RBD_SIZE);
-
- if ((rbd.rbd_status & (RBD_EOF | RBD_ACNTVALID)) == (RBD_EOF | RBD_ACNTVALID)) {
- int length = rbd.rbd_status & RBD_ACNT;
- struct sk_buff *skb;
-
- length = (length + 1) & ~1;
- skb = dev_alloc_skb (length + 2);
-
- if (skb) {
- skb_reserve (skb, 2);
-
- ether1_readbuffer (dev, skb_put (skb, length), rbd.rbd_bufl, length);
-
- skb->protocol = eth_type_trans (skb, dev);
- netif_rx (skb);
- dev->stats.rx_packets++;
- } else
- dev->stats.rx_dropped++;
- } else {
- printk(KERN_WARNING "%s: %s\n", dev->name,
- (rbd.rbd_status & RBD_EOF) ? "oversized packet" : "acnt not valid");
- dev->stats.rx_dropped++;
- }
-
- nexttail = ether1_readw(dev, priv(dev)->rx_tail, rfd_t, rfd_link, NORMALIRQS);
- /* nexttail should be rx_head */
- if (nexttail != priv(dev)->rx_head)
- printk(KERN_ERR "%s: receiver buffer chaining error (%04X != %04X)\n",
- dev->name, nexttail, priv(dev)->rx_head);
- ether1_writew(dev, RFD_CMDEL | RFD_CMDSUSPEND, nexttail, rfd_t, rfd_command, NORMALIRQS);
- ether1_writew(dev, 0, priv(dev)->rx_tail, rfd_t, rfd_command, NORMALIRQS);
- ether1_writew(dev, 0, priv(dev)->rx_tail, rfd_t, rfd_status, NORMALIRQS);
- ether1_writew(dev, 0, priv(dev)->rx_tail, rfd_t, rfd_rbdoffset, NORMALIRQS);
-
- priv(dev)->rx_tail = nexttail;
- priv(dev)->rx_head = ether1_readw(dev, priv(dev)->rx_head, rfd_t, rfd_link, NORMALIRQS);
- } while (1);
-}
-
-static irqreturn_t
-ether1_interrupt (int irq, void *dev_id)
-{
- struct net_device *dev = (struct net_device *)dev_id;
- int status;
-
- status = ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS);
-
- if (status) {
- ether1_writew(dev, status & (SCB_STRNR | SCB_STCNA | SCB_STFR | SCB_STCX),
- SCB_ADDR, scb_t, scb_command, NORMALIRQS);
- writeb(CTRL_CA | CTRL_ACK, REG_CONTROL);
- if (status & SCB_STCX) {
- ether1_xmit_done (dev);
- }
- if (status & SCB_STCNA) {
- if (priv(dev)->resetting == 0)
- printk (KERN_WARNING "%s: CU went not ready ???\n", dev->name);
- else
- priv(dev)->resetting += 1;
- if (ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS)
- != (unsigned short)I82586_NULL) {
- ether1_writew(dev, SCB_CMDCUCSTART, SCB_ADDR, scb_t, scb_command, NORMALIRQS);
- writeb(CTRL_CA, REG_CONTROL);
- }
- if (priv(dev)->resetting == 2)
- priv(dev)->resetting = 0;
- }
- if (status & SCB_STFR) {
- ether1_recv_done (dev);
- }
- if (status & SCB_STRNR) {
- if (ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS) & SCB_STRXSUSP) {
- printk (KERN_WARNING "%s: RU went not ready: RU suspended\n", dev->name);
- ether1_writew(dev, SCB_CMDRXRESUME, SCB_ADDR, scb_t, scb_command, NORMALIRQS);
- writeb(CTRL_CA, REG_CONTROL);
- dev->stats.rx_dropped++; /* we suspended due to lack of buffer space */
- } else
- printk(KERN_WARNING "%s: RU went not ready: %04X\n", dev->name,
- ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS));
- printk (KERN_WARNING "RU ptr = %04X\n", ether1_readw(dev, SCB_ADDR, scb_t, scb_rfa_offset,
- NORMALIRQS));
- }
- } else
- writeb(CTRL_ACK, REG_CONTROL);
-
- return IRQ_HANDLED;
-}
-
-static int
-ether1_close (struct net_device *dev)
-{
- ether1_reset (dev);
-
- free_irq(dev->irq, dev);
-
- return 0;
-}
-
-/*
- * Set or clear the multicast filter for this adaptor.
- * num_addrs == -1 Promiscuous mode, receive all packets.
- * num_addrs == 0 Normal mode, clear multicast list.
- * num_addrs > 0 Multicast mode, receive normal and MC packets, and do
- * best-effort filtering.
- */
-static void
-ether1_setmulticastlist (struct net_device *dev)
-{
-}
-
-/* ------------------------------------------------------------------------- */
-
-static void __devinit ether1_banner(void)
-{
- static unsigned int version_printed = 0;
-
- if (net_debug && version_printed++ == 0)
- printk(KERN_INFO "%s", version);
-}
-
-static const struct net_device_ops ether1_netdev_ops = {
- .ndo_open = ether1_open,
- .ndo_stop = ether1_close,
- .ndo_start_xmit = ether1_sendpacket,
- .ndo_set_multicast_list = ether1_setmulticastlist,
- .ndo_tx_timeout = ether1_timeout,
- .ndo_validate_addr = eth_validate_addr,
- .ndo_change_mtu = eth_change_mtu,
- .ndo_set_mac_address = eth_mac_addr,
-};
-
-static int __devinit
-ether1_probe(struct expansion_card *ec, const struct ecard_id *id)
-{
- struct net_device *dev;
- int i, ret = 0;
-
- ether1_banner();
-
- ret = ecard_request_resources(ec);
- if (ret)
- goto out;
-
- dev = alloc_etherdev(sizeof(struct ether1_priv));
- if (!dev) {
- ret = -ENOMEM;
- goto release;
- }
-
- SET_NETDEV_DEV(dev, &ec->dev);
-
- dev->irq = ec->irq;
- priv(dev)->base = ecardm_iomap(ec, ECARD_RES_IOCFAST, 0, 0);
- if (!priv(dev)->base) {
- ret = -ENOMEM;
- goto free;
- }
-
- if ((priv(dev)->bus_type = ether1_reset(dev)) == 0) {
- ret = -ENODEV;
- goto free;
- }
-
- for (i = 0; i < 6; i++)
- dev->dev_addr[i] = readb(IDPROM_ADDRESS + (i << 2));
-
- if (ether1_init_2(dev)) {
- ret = -ENODEV;
- goto free;
- }
-
- dev->netdev_ops = ðer1_netdev_ops;
- dev->watchdog_timeo = 5 * HZ / 100;
-
- ret = register_netdev(dev);
- if (ret)
- goto free;
-
- printk(KERN_INFO "%s: ether1 in slot %d, %pM\n",
- dev->name, ec->slot_no, dev->dev_addr);
-
- ecard_set_drvdata(ec, dev);
- return 0;
-
- free:
- free_netdev(dev);
- release:
- ecard_release_resources(ec);
- out:
- return ret;
-}
-
-static void __devexit ether1_remove(struct expansion_card *ec)
-{
- struct net_device *dev = ecard_get_drvdata(ec);
-
- ecard_set_drvdata(ec, NULL);
-
- unregister_netdev(dev);
- free_netdev(dev);
- ecard_release_resources(ec);
-}
-
-static const struct ecard_id ether1_ids[] = {
- { MANU_ACORN, PROD_ACORN_ETHER1 },
- { 0xffff, 0xffff }
-};
-
-static struct ecard_driver ether1_driver = {
- .probe = ether1_probe,
- .remove = __devexit_p(ether1_remove),
- .id_table = ether1_ids,
- .drv = {
- .name = "ether1",
- },
-};
-
-static int __init ether1_init(void)
-{
- return ecard_register_driver(ðer1_driver);
-}
-
-static void __exit ether1_exit(void)
-{
- ecard_remove_driver(ðer1_driver);
-}
-
-module_init(ether1_init);
-module_exit(ether1_exit);
-
-MODULE_LICENSE("GPL");
+++ /dev/null
-/*
- * linux/drivers/acorn/net/ether1.h
- *
- * Copyright (C) 1996 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Network driver for Acorn Ether1 cards.
- */
-
-#ifndef _LINUX_ether1_H
-#define _LINUX_ether1_H
-
-#ifdef __ETHER1_C
-/* use 0 for production, 1 for verification, >2 for debug */
-#ifndef NET_DEBUG
-#define NET_DEBUG 0
-#endif
-
-#define priv(dev) ((struct ether1_priv *)netdev_priv(dev))
-
-/* Page register */
-#define REG_PAGE (priv(dev)->base + 0x0000)
-
-/* Control register */
-#define REG_CONTROL (priv(dev)->base + 0x0004)
-#define CTRL_RST 0x01
-#define CTRL_LOOPBACK 0x02
-#define CTRL_CA 0x04
-#define CTRL_ACK 0x08
-
-#define ETHER1_RAM (priv(dev)->base + 0x2000)
-
-/* HW address */
-#define IDPROM_ADDRESS (priv(dev)->base + 0x0024)
-
-struct ether1_priv {
- void __iomem *base;
- unsigned int tx_link;
- unsigned int tx_head;
- volatile unsigned int tx_tail;
- volatile unsigned int rx_head;
- volatile unsigned int rx_tail;
- unsigned char bus_type;
- unsigned char resetting;
- unsigned char initialising : 1;
- unsigned char restart : 1;
-};
-
-#define I82586_NULL (-1)
-
-typedef struct { /* tdr */
- unsigned short tdr_status;
- unsigned short tdr_command;
- unsigned short tdr_link;
- unsigned short tdr_result;
-#define TDR_TIME (0x7ff)
-#define TDR_SHORT (1 << 12)
-#define TDR_OPEN (1 << 13)
-#define TDR_XCVRPROB (1 << 14)
-#define TDR_LNKOK (1 << 15)
-} tdr_t;
-
-typedef struct { /* transmit */
- unsigned short tx_status;
- unsigned short tx_command;
- unsigned short tx_link;
- unsigned short tx_tbdoffset;
-} tx_t;
-
-typedef struct { /* tbd */
- unsigned short tbd_opts;
-#define TBD_CNT (0x3fff)
-#define TBD_EOL (1 << 15)
- unsigned short tbd_link;
- unsigned short tbd_bufl;
- unsigned short tbd_bufh;
-} tbd_t;
-
-typedef struct { /* rfd */
- unsigned short rfd_status;
-#define RFD_NOEOF (1 << 6)
-#define RFD_FRAMESHORT (1 << 7)
-#define RFD_DMAOVRN (1 << 8)
-#define RFD_NORESOURCES (1 << 9)
-#define RFD_ALIGNERROR (1 << 10)
-#define RFD_CRCERROR (1 << 11)
-#define RFD_OK (1 << 13)
-#define RFD_FDCONSUMED (1 << 14)
-#define RFD_COMPLETE (1 << 15)
- unsigned short rfd_command;
-#define RFD_CMDSUSPEND (1 << 14)
-#define RFD_CMDEL (1 << 15)
- unsigned short rfd_link;
- unsigned short rfd_rbdoffset;
- unsigned char rfd_dest[6];
- unsigned char rfd_src[6];
- unsigned short rfd_len;
-} rfd_t;
-
-typedef struct { /* rbd */
- unsigned short rbd_status;
-#define RBD_ACNT (0x3fff)
-#define RBD_ACNTVALID (1 << 14)
-#define RBD_EOF (1 << 15)
- unsigned short rbd_link;
- unsigned short rbd_bufl;
- unsigned short rbd_bufh;
- unsigned short rbd_len;
-} rbd_t;
-
-typedef struct { /* nop */
- unsigned short nop_status;
- unsigned short nop_command;
- unsigned short nop_link;
-} nop_t;
-
-typedef struct { /* set multicast */
- unsigned short mc_status;
- unsigned short mc_command;
- unsigned short mc_link;
- unsigned short mc_cnt;
- unsigned char mc_addrs[1][6];
-} mc_t;
-
-typedef struct { /* set address */
- unsigned short sa_status;
- unsigned short sa_command;
- unsigned short sa_link;
- unsigned char sa_addr[6];
-} sa_t;
-
-typedef struct { /* config command */
- unsigned short cfg_status;
- unsigned short cfg_command;
- unsigned short cfg_link;
- unsigned char cfg_bytecnt; /* size foll data: 4 - 12 */
- unsigned char cfg_fifolim; /* FIFO threshold */
- unsigned char cfg_byte8;
-#define CFG8_SRDY (1 << 6)
-#define CFG8_SAVEBADF (1 << 7)
- unsigned char cfg_byte9;
-#define CFG9_ADDRLEN(x) (x)
-#define CFG9_ADDRLENBUF (1 << 3)
-#define CFG9_PREAMB2 (0 << 4)
-#define CFG9_PREAMB4 (1 << 4)
-#define CFG9_PREAMB8 (2 << 4)
-#define CFG9_PREAMB16 (3 << 4)
-#define CFG9_ILOOPBACK (1 << 6)
-#define CFG9_ELOOPBACK (1 << 7)
- unsigned char cfg_byte10;
-#define CFG10_LINPRI(x) (x)
-#define CFG10_ACR(x) (x << 4)
-#define CFG10_BOFMET (1 << 7)
- unsigned char cfg_ifs;
- unsigned char cfg_slotl;
- unsigned char cfg_byte13;
-#define CFG13_SLOTH(x) (x)
-#define CFG13_RETRY(x) (x << 4)
- unsigned char cfg_byte14;
-#define CFG14_PROMISC (1 << 0)
-#define CFG14_DISBRD (1 << 1)
-#define CFG14_MANCH (1 << 2)
-#define CFG14_TNCRS (1 << 3)
-#define CFG14_NOCRC (1 << 4)
-#define CFG14_CRC16 (1 << 5)
-#define CFG14_BTSTF (1 << 6)
-#define CFG14_FLGPAD (1 << 7)
- unsigned char cfg_byte15;
-#define CFG15_CSTF(x) (x)
-#define CFG15_ICSS (1 << 3)
-#define CFG15_CDTF(x) (x << 4)
-#define CFG15_ICDS (1 << 7)
- unsigned short cfg_minfrmlen;
-} cfg_t;
-
-typedef struct { /* scb */
- unsigned short scb_status; /* status of 82586 */
-#define SCB_STRXMASK (7 << 4) /* Receive unit status */
-#define SCB_STRXIDLE (0 << 4) /* Idle */
-#define SCB_STRXSUSP (1 << 4) /* Suspended */
-#define SCB_STRXNRES (2 << 4) /* No resources */
-#define SCB_STRXRDY (4 << 4) /* Ready */
-#define SCB_STCUMASK (7 << 8) /* Command unit status */
-#define SCB_STCUIDLE (0 << 8) /* Idle */
-#define SCB_STCUSUSP (1 << 8) /* Suspended */
-#define SCB_STCUACTV (2 << 8) /* Active */
-#define SCB_STRNR (1 << 12) /* Receive unit not ready */
-#define SCB_STCNA (1 << 13) /* Command unit not ready */
-#define SCB_STFR (1 << 14) /* Frame received */
-#define SCB_STCX (1 << 15) /* Command completed */
- unsigned short scb_command; /* Next command */
-#define SCB_CMDRXSTART (1 << 4) /* Start (at rfa_offset) */
-#define SCB_CMDRXRESUME (2 << 4) /* Resume reception */
-#define SCB_CMDRXSUSPEND (3 << 4) /* Suspend reception */
-#define SCB_CMDRXABORT (4 << 4) /* Abort reception */
-#define SCB_CMDCUCSTART (1 << 8) /* Start (at cbl_offset) */
-#define SCB_CMDCUCRESUME (2 << 8) /* Resume execution */
-#define SCB_CMDCUCSUSPEND (3 << 8) /* Suspend execution */
-#define SCB_CMDCUCABORT (4 << 8) /* Abort execution */
-#define SCB_CMDACKRNR (1 << 12) /* Ack RU not ready */
-#define SCB_CMDACKCNA (1 << 13) /* Ack CU not ready */
-#define SCB_CMDACKFR (1 << 14) /* Ack Frame received */
-#define SCB_CMDACKCX (1 << 15) /* Ack Command complete */
- unsigned short scb_cbl_offset; /* Offset of first command unit */
- unsigned short scb_rfa_offset; /* Offset of first receive frame area */
- unsigned short scb_crc_errors; /* Properly aligned frame with CRC error*/
- unsigned short scb_aln_errors; /* Misaligned frames */
- unsigned short scb_rsc_errors; /* Frames lost due to no space */
- unsigned short scb_ovn_errors; /* Frames lost due to slow bus */
-} scb_t;
-
-typedef struct { /* iscp */
- unsigned short iscp_busy; /* set by CPU before CA */
- unsigned short iscp_offset; /* offset of SCB */
- unsigned short iscp_basel; /* base of SCB */
- unsigned short iscp_baseh;
-} iscp_t;
-
- /* this address must be 0xfff6 */
-typedef struct { /* scp */
- unsigned short scp_sysbus; /* bus size */
-#define SCP_SY_16BBUS 0x00
-#define SCP_SY_8BBUS 0x01
- unsigned short scp_junk[2]; /* junk */
- unsigned short scp_iscpl; /* lower 16 bits of iscp */
- unsigned short scp_iscph; /* upper 16 bits of iscp */
-} scp_t;
-
-/* commands */
-#define CMD_NOP 0
-#define CMD_SETADDRESS 1
-#define CMD_CONFIG 2
-#define CMD_SETMULTICAST 3
-#define CMD_TX 4
-#define CMD_TDR 5
-#define CMD_DUMP 6
-#define CMD_DIAGNOSE 7
-
-#define CMD_MASK 7
-
-#define CMD_INTR (1 << 13)
-#define CMD_SUSP (1 << 14)
-#define CMD_EOL (1 << 15)
-
-#define STAT_COLLISIONS (15)
-#define STAT_COLLEXCESSIVE (1 << 5)
-#define STAT_COLLAFTERTX (1 << 6)
-#define STAT_TXDEFERRED (1 << 7)
-#define STAT_TXSLOWDMA (1 << 8)
-#define STAT_TXLOSTCTS (1 << 9)
-#define STAT_NOCARRIER (1 << 10)
-#define STAT_FAIL (1 << 11)
-#define STAT_ABORTED (1 << 12)
-#define STAT_OK (1 << 13)
-#define STAT_BUSY (1 << 14)
-#define STAT_COMPLETE (1 << 15)
-#endif
-#endif
-
-/*
- * Ether1 card definitions:
- *
- * FAST accesses:
- * +0 Page register
- * 16 pages
- * +4 Control
- * '1' = reset
- * '2' = loopback
- * '4' = CA
- * '8' = int ack
- *
- * RAM at address + 0x2000
- * Pod. Prod id = 3
- * Words after ID block [base + 8 words]
- * +0 pcb issue (0x0c and 0xf3 invalid)
- * +1 - +6 eth hw address
- */
+++ /dev/null
-/* eepro.c: Intel EtherExpress Pro/10 device driver for Linux. */
-/*
- Written 1994, 1995,1996 by Bao C. Ha.
-
- Copyright (C) 1994, 1995,1996 by Bao C. Ha.
-
- This software may be used and distributed
- according to the terms of the GNU General Public License,
- incorporated herein by reference.
-
- The author may be reached at bao.ha@srs.gov
- or 418 Hastings Place, Martinez, GA 30907.
-
- Things remaining to do:
- Better record keeping of errors.
- Eliminate transmit interrupt to reduce overhead.
- Implement "concurrent processing". I won't be doing it!
-
- Bugs:
-
- If you have a problem of not detecting the 82595 during a
- reboot (warm reset), disable the FLASH memory should fix it.
- This is a compatibility hardware problem.
-
- Versions:
- 0.13b basic ethtool support (aris, 09/13/2004)
- 0.13a in memory shortage, drop packets also in board
- (Michael Westermann <mw@microdata-pos.de>, 07/30/2002)
- 0.13 irq sharing, rewrote probe function, fixed a nasty bug in
- hardware_send_packet and a major cleanup (aris, 11/08/2001)
- 0.12d fixing a problem with single card detected as eight eth devices
- fixing a problem with sudden drop in card performance
- (chris (asdn@go2.pl), 10/29/2001)
- 0.12c fixing some problems with old cards (aris, 01/08/2001)
- 0.12b misc fixes (aris, 06/26/2000)
- 0.12a port of version 0.12a of 2.2.x kernels to 2.3.x
- (aris (aris@conectiva.com.br), 05/19/2000)
- 0.11e some tweaks about multiple cards support (PdP, jul/aug 1999)
- 0.11d added __initdata, __init stuff; call spin_lock_init
- in eepro_probe1. Replaced "eepro" by dev->name. Augmented
- the code protected by spin_lock in interrupt routine
- (PdP, 12/12/1998)
- 0.11c minor cleanup (PdP, RMC, 09/12/1998)
- 0.11b Pascal Dupuis (dupuis@lei.ucl.ac.be): works as a module
- under 2.1.xx. Debug messages are flagged as KERN_DEBUG to
- avoid console flooding. Added locking at critical parts. Now
- the dawn thing is SMP safe.
- 0.11a Attempt to get 2.1.xx support up (RMC)
- 0.11 Brian Candler added support for multiple cards. Tested as
- a module, no idea if it works when compiled into kernel.
-
- 0.10e Rick Bressler notified me that ifconfig up;ifconfig down fails
- because the irq is lost somewhere. Fixed that by moving
- request_irq and free_irq to eepro_open and eepro_close respectively.
- 0.10d Ugh! Now Wakeup works. Was seriously broken in my first attempt.
- I'll need to find a way to specify an ioport other than
- the default one in the PnP case. PnP definitively sucks.
- And, yes, this is not the only reason.
- 0.10c PnP Wakeup Test for 595FX. uncomment #define PnPWakeup;
- to use.
- 0.10b Should work now with (some) Pro/10+. At least for
- me (and my two cards) it does. _No_ guarantee for
- function with non-Pro/10+ cards! (don't have any)
- (RMC, 9/11/96)
-
- 0.10 Added support for the Etherexpress Pro/10+. The
- IRQ map was changed significantly from the old
- pro/10. The new interrupt map was provided by
- Rainer M. Canavan (Canavan@Zeus.cs.bonn.edu).
- (BCH, 9/3/96)
-
- 0.09 Fixed a race condition in the transmit algorithm,
- which causes crashes under heavy load with fast
- pentium computers. The performance should also
- improve a bit. The size of RX buffer, and hence
- TX buffer, can also be changed via lilo or insmod.
- (BCH, 7/31/96)
-
- 0.08 Implement 32-bit I/O for the 82595TX and 82595FX
- based lan cards. Disable full-duplex mode if TPE
- is not used. (BCH, 4/8/96)
-
- 0.07a Fix a stat report which counts every packet as a
- heart-beat failure. (BCH, 6/3/95)
-
- 0.07 Modified to support all other 82595-based lan cards.
- The IRQ vector of the EtherExpress Pro will be set
- according to the value saved in the EEPROM. For other
- cards, I will do autoirq_request() to grab the next
- available interrupt vector. (BCH, 3/17/95)
-
- 0.06a,b Interim released. Minor changes in the comments and
- print out format. (BCH, 3/9/95 and 3/14/95)
-
- 0.06 First stable release that I am comfortable with. (BCH,
- 3/2/95)
-
- 0.05 Complete testing of multicast. (BCH, 2/23/95)
-
- 0.04 Adding multicast support. (BCH, 2/14/95)
-
- 0.03 First widely alpha release for public testing.
- (BCH, 2/14/95)
-
-*/
-
-static const char version[] =
- "eepro.c: v0.13b 09/13/2004 aris@cathedrallabs.org\n";
-
-#include <linux/module.h>
-
-/*
- Sources:
-
- This driver wouldn't have been written without the availability
- of the Crynwr's Lan595 driver source code. It helps me to
- familiarize with the 82595 chipset while waiting for the Intel
- documentation. I also learned how to detect the 82595 using
- the packet driver's technique.
-
- This driver is written by cutting and pasting the skeleton.c driver
- provided by Donald Becker. I also borrowed the EEPROM routine from
- Donald Becker's 82586 driver.
-
- Datasheet for the Intel 82595 (including the TX and FX version). It
- provides just enough info that the casual reader might think that it
- documents the i82595.
-
- The User Manual for the 82595. It provides a lot of the missing
- information.
-
-*/
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/spinlock.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/bitops.h>
-#include <linux/ethtool.h>
-
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-
-#define DRV_NAME "eepro"
-#define DRV_VERSION "0.13c"
-
-#define compat_dev_kfree_skb( skb, mode ) dev_kfree_skb( (skb) )
-/* I had reports of looong delays with SLOW_DOWN defined as udelay(2) */
-#define SLOW_DOWN inb(0x80)
-/* udelay(2) */
-#define compat_init_data __initdata
-enum iftype { AUI=0, BNC=1, TPE=2 };
-
-/* First, a few definitions that the brave might change. */
-/* A zero-terminated list of I/O addresses to be probed. */
-static unsigned int eepro_portlist[] compat_init_data =
- { 0x300, 0x210, 0x240, 0x280, 0x2C0, 0x200, 0x320, 0x340, 0x360, 0};
-/* note: 0x300 is default, the 595FX supports ALL IO Ports
- from 0x000 to 0x3F0, some of which are reserved in PCs */
-
-/* To try the (not-really PnP Wakeup: */
-/*
-#define PnPWakeup
-*/
-
-/* use 0 for production, 1 for verification, >2 for debug */
-#ifndef NET_DEBUG
-#define NET_DEBUG 0
-#endif
-static unsigned int net_debug = NET_DEBUG;
-
-/* The number of low I/O ports used by the ethercard. */
-#define EEPRO_IO_EXTENT 16
-
-/* Different 82595 chips */
-#define LAN595 0
-#define LAN595TX 1
-#define LAN595FX 2
-#define LAN595FX_10ISA 3
-
-/* Information that need to be kept for each board. */
-struct eepro_local {
- unsigned rx_start;
- unsigned tx_start; /* start of the transmit chain */
- int tx_last; /* pointer to last packet in the transmit chain */
- unsigned tx_end; /* end of the transmit chain (plus 1) */
- int eepro; /* 1 for the EtherExpress Pro/10,
- 2 for the EtherExpress Pro/10+,
- 3 for the EtherExpress 10 (blue cards),
- 0 for other 82595-based lan cards. */
- int version; /* a flag to indicate if this is a TX or FX
- version of the 82595 chip. */
- int stepping;
-
- spinlock_t lock; /* Serializing lock */
-
- unsigned rcv_ram; /* pre-calculated space for rx */
- unsigned xmt_ram; /* pre-calculated space for tx */
- unsigned char xmt_bar;
- unsigned char xmt_lower_limit_reg;
- unsigned char xmt_upper_limit_reg;
- short xmt_lower_limit;
- short xmt_upper_limit;
- short rcv_lower_limit;
- short rcv_upper_limit;
- unsigned char eeprom_reg;
- unsigned short word[8];
-};
-
-/* The station (ethernet) address prefix, used for IDing the board. */
-#define SA_ADDR0 0x00 /* Etherexpress Pro/10 */
-#define SA_ADDR1 0xaa
-#define SA_ADDR2 0x00
-
-#define GetBit(x,y) ((x & (1<<y))>>y)
-
-/* EEPROM Word 0: */
-#define ee_PnP 0 /* Plug 'n Play enable bit */
-#define ee_Word1 1 /* Word 1? */
-#define ee_BusWidth 2 /* 8/16 bit */
-#define ee_FlashAddr 3 /* Flash Address */
-#define ee_FlashMask 0x7 /* Mask */
-#define ee_AutoIO 6 /* */
-#define ee_reserved0 7 /* =0! */
-#define ee_Flash 8 /* Flash there? */
-#define ee_AutoNeg 9 /* Auto Negotiation enabled? */
-#define ee_IO0 10 /* IO Address LSB */
-#define ee_IO0Mask 0x /*...*/
-#define ee_IO1 15 /* IO MSB */
-
-/* EEPROM Word 1: */
-#define ee_IntSel 0 /* Interrupt */
-#define ee_IntMask 0x7
-#define ee_LI 3 /* Link Integrity 0= enabled */
-#define ee_PC 4 /* Polarity Correction 0= enabled */
-#define ee_TPE_AUI 5 /* PortSelection 1=TPE */
-#define ee_Jabber 6 /* Jabber prevention 0= enabled */
-#define ee_AutoPort 7 /* Auto Port Selection 1= Disabled */
-#define ee_SMOUT 8 /* SMout Pin Control 0= Input */
-#define ee_PROM 9 /* Flash EPROM / PROM 0=Flash */
-#define ee_reserved1 10 /* .. 12 =0! */
-#define ee_AltReady 13 /* Alternate Ready, 0=normal */
-#define ee_reserved2 14 /* =0! */
-#define ee_Duplex 15
-
-/* Word2,3,4: */
-#define ee_IA5 0 /*bit start for individual Addr Byte 5 */
-#define ee_IA4 8 /*bit start for individual Addr Byte 5 */
-#define ee_IA3 0 /*bit start for individual Addr Byte 5 */
-#define ee_IA2 8 /*bit start for individual Addr Byte 5 */
-#define ee_IA1 0 /*bit start for individual Addr Byte 5 */
-#define ee_IA0 8 /*bit start for individual Addr Byte 5 */
-
-/* Word 5: */
-#define ee_BNC_TPE 0 /* 0=TPE */
-#define ee_BootType 1 /* 00=None, 01=IPX, 10=ODI, 11=NDIS */
-#define ee_BootTypeMask 0x3
-#define ee_NumConn 3 /* Number of Connections 0= One or Two */
-#define ee_FlashSock 4 /* Presence of Flash Socket 0= Present */
-#define ee_PortTPE 5
-#define ee_PortBNC 6
-#define ee_PortAUI 7
-#define ee_PowerMgt 10 /* 0= disabled */
-#define ee_CP 13 /* Concurrent Processing */
-#define ee_CPMask 0x7
-
-/* Word 6: */
-#define ee_Stepping 0 /* Stepping info */
-#define ee_StepMask 0x0F
-#define ee_BoardID 4 /* Manucaturer Board ID, reserved */
-#define ee_BoardMask 0x0FFF
-
-/* Word 7: */
-#define ee_INT_TO_IRQ 0 /* int to IRQ Mapping = 0x1EB8 for Pro/10+ */
-#define ee_FX_INT2IRQ 0x1EB8 /* the _only_ mapping allowed for FX chips */
-
-/*..*/
-#define ee_SIZE 0x40 /* total EEprom Size */
-#define ee_Checksum 0xBABA /* initial and final value for adding checksum */
-
-
-/* Card identification via EEprom: */
-#define ee_addr_vendor 0x10 /* Word offset for EISA Vendor ID */
-#define ee_addr_id 0x11 /* Word offset for Card ID */
-#define ee_addr_SN 0x12 /* Serial Number */
-#define ee_addr_CRC_8 0x14 /* CRC over last thee Bytes */
-
-
-#define ee_vendor_intel0 0x25 /* Vendor ID Intel */
-#define ee_vendor_intel1 0xD4
-#define ee_id_eepro10p0 0x10 /* ID for eepro/10+ */
-#define ee_id_eepro10p1 0x31
-
-#define TX_TIMEOUT ((4*HZ)/10)
-
-/* Index to functions, as function prototypes. */
-
-static int eepro_probe1(struct net_device *dev, int autoprobe);
-static int eepro_open(struct net_device *dev);
-static netdev_tx_t eepro_send_packet(struct sk_buff *skb,
- struct net_device *dev);
-static irqreturn_t eepro_interrupt(int irq, void *dev_id);
-static void eepro_rx(struct net_device *dev);
-static void eepro_transmit_interrupt(struct net_device *dev);
-static int eepro_close(struct net_device *dev);
-static void set_multicast_list(struct net_device *dev);
-static void eepro_tx_timeout (struct net_device *dev);
-
-static int read_eeprom(int ioaddr, int location, struct net_device *dev);
-static int hardware_send_packet(struct net_device *dev, void *buf, short length);
-static int eepro_grab_irq(struct net_device *dev);
-
-/*
- Details of the i82595.
-
-You will need either the datasheet or the user manual to understand what
-is going on here. The 82595 is very different from the 82586, 82593.
-
-The receive algorithm in eepro_rx() is just an implementation of the
-RCV ring structure that the Intel 82595 imposes at the hardware level.
-The receive buffer is set at 24K, and the transmit buffer is 8K. I
-am assuming that the total buffer memory is 32K, which is true for the
-Intel EtherExpress Pro/10. If it is less than that on a generic card,
-the driver will be broken.
-
-The transmit algorithm in the hardware_send_packet() is similar to the
-one in the eepro_rx(). The transmit buffer is a ring linked list.
-I just queue the next available packet to the end of the list. In my
-system, the 82595 is so fast that the list seems to always contain a
-single packet. In other systems with faster computers and more congested
-network traffics, the ring linked list should improve performance by
-allowing up to 8K worth of packets to be queued.
-
-The sizes of the receive and transmit buffers can now be changed via lilo
-or insmod. Lilo uses the appended line "ether=io,irq,debug,rx-buffer,eth0"
-where rx-buffer is in KB unit. Modules uses the parameter mem which is
-also in KB unit, for example "insmod io=io-address irq=0 mem=rx-buffer."
-The receive buffer has to be more than 3K or less than 29K. Otherwise,
-it is reset to the default of 24K, and, hence, 8K for the trasnmit
-buffer (transmit-buffer = 32K - receive-buffer).
-
-*/
-#define RAM_SIZE 0x8000
-
-#define RCV_HEADER 8
-#define RCV_DEFAULT_RAM 0x6000
-
-#define XMT_HEADER 8
-#define XMT_DEFAULT_RAM (RAM_SIZE - RCV_DEFAULT_RAM)
-
-#define XMT_START_PRO RCV_DEFAULT_RAM
-#define XMT_START_10 0x0000
-#define RCV_START_PRO 0x0000
-#define RCV_START_10 XMT_DEFAULT_RAM
-
-#define RCV_DONE 0x0008
-#define RX_OK 0x2000
-#define RX_ERROR 0x0d81
-
-#define TX_DONE_BIT 0x0080
-#define TX_OK 0x2000
-#define CHAIN_BIT 0x8000
-#define XMT_STATUS 0x02
-#define XMT_CHAIN 0x04
-#define XMT_COUNT 0x06
-
-#define BANK0_SELECT 0x00
-#define BANK1_SELECT 0x40
-#define BANK2_SELECT 0x80
-
-/* Bank 0 registers */
-#define COMMAND_REG 0x00 /* Register 0 */
-#define MC_SETUP 0x03
-#define XMT_CMD 0x04
-#define DIAGNOSE_CMD 0x07
-#define RCV_ENABLE_CMD 0x08
-#define RCV_DISABLE_CMD 0x0a
-#define STOP_RCV_CMD 0x0b
-#define RESET_CMD 0x0e
-#define POWER_DOWN_CMD 0x18
-#define RESUME_XMT_CMD 0x1c
-#define SEL_RESET_CMD 0x1e
-#define STATUS_REG 0x01 /* Register 1 */
-#define RX_INT 0x02
-#define TX_INT 0x04
-#define EXEC_STATUS 0x30
-#define ID_REG 0x02 /* Register 2 */
-#define R_ROBIN_BITS 0xc0 /* round robin counter */
-#define ID_REG_MASK 0x2c
-#define ID_REG_SIG 0x24
-#define AUTO_ENABLE 0x10
-#define INT_MASK_REG 0x03 /* Register 3 */
-#define RX_STOP_MASK 0x01
-#define RX_MASK 0x02
-#define TX_MASK 0x04
-#define EXEC_MASK 0x08
-#define ALL_MASK 0x0f
-#define IO_32_BIT 0x10
-#define RCV_BAR 0x04 /* The following are word (16-bit) registers */
-#define RCV_STOP 0x06
-
-#define XMT_BAR_PRO 0x0a
-#define XMT_BAR_10 0x0b
-
-#define HOST_ADDRESS_REG 0x0c
-#define IO_PORT 0x0e
-#define IO_PORT_32_BIT 0x0c
-
-/* Bank 1 registers */
-#define REG1 0x01
-#define WORD_WIDTH 0x02
-#define INT_ENABLE 0x80
-#define INT_NO_REG 0x02
-#define RCV_LOWER_LIMIT_REG 0x08
-#define RCV_UPPER_LIMIT_REG 0x09
-
-#define XMT_LOWER_LIMIT_REG_PRO 0x0a
-#define XMT_UPPER_LIMIT_REG_PRO 0x0b
-#define XMT_LOWER_LIMIT_REG_10 0x0b
-#define XMT_UPPER_LIMIT_REG_10 0x0a
-
-/* Bank 2 registers */
-#define XMT_Chain_Int 0x20 /* Interrupt at the end of the transmit chain */
-#define XMT_Chain_ErrStop 0x40 /* Interrupt at the end of the chain even if there are errors */
-#define RCV_Discard_BadFrame 0x80 /* Throw bad frames away, and continue to receive others */
-#define REG2 0x02
-#define PRMSC_Mode 0x01
-#define Multi_IA 0x20
-#define REG3 0x03
-#define TPE_BIT 0x04
-#define BNC_BIT 0x20
-#define REG13 0x0d
-#define FDX 0x00
-#define A_N_ENABLE 0x02
-
-#define I_ADD_REG0 0x04
-#define I_ADD_REG1 0x05
-#define I_ADD_REG2 0x06
-#define I_ADD_REG3 0x07
-#define I_ADD_REG4 0x08
-#define I_ADD_REG5 0x09
-
-#define EEPROM_REG_PRO 0x0a
-#define EEPROM_REG_10 0x0b
-
-#define EESK 0x01
-#define EECS 0x02
-#define EEDI 0x04
-#define EEDO 0x08
-
-/* do a full reset */
-#define eepro_reset(ioaddr) outb(RESET_CMD, ioaddr)
-
-/* do a nice reset */
-#define eepro_sel_reset(ioaddr) { \
- outb(SEL_RESET_CMD, ioaddr); \
- SLOW_DOWN; \
- SLOW_DOWN; \
- }
-
-/* disable all interrupts */
-#define eepro_dis_int(ioaddr) outb(ALL_MASK, ioaddr + INT_MASK_REG)
-
-/* clear all interrupts */
-#define eepro_clear_int(ioaddr) outb(ALL_MASK, ioaddr + STATUS_REG)
-
-/* enable tx/rx */
-#define eepro_en_int(ioaddr) outb(ALL_MASK & ~(RX_MASK | TX_MASK), \
- ioaddr + INT_MASK_REG)
-
-/* enable exec event interrupt */
-#define eepro_en_intexec(ioaddr) outb(ALL_MASK & ~(EXEC_MASK), ioaddr + INT_MASK_REG)
-
-/* enable rx */
-#define eepro_en_rx(ioaddr) outb(RCV_ENABLE_CMD, ioaddr)
-
-/* disable rx */
-#define eepro_dis_rx(ioaddr) outb(RCV_DISABLE_CMD, ioaddr)
-
-/* switch bank */
-#define eepro_sw2bank0(ioaddr) outb(BANK0_SELECT, ioaddr)
-#define eepro_sw2bank1(ioaddr) outb(BANK1_SELECT, ioaddr)
-#define eepro_sw2bank2(ioaddr) outb(BANK2_SELECT, ioaddr)
-
-/* enable interrupt line */
-#define eepro_en_intline(ioaddr) outb(inb(ioaddr + REG1) | INT_ENABLE,\
- ioaddr + REG1)
-
-/* disable interrupt line */
-#define eepro_dis_intline(ioaddr) outb(inb(ioaddr + REG1) & 0x7f, \
- ioaddr + REG1);
-
-/* set diagnose flag */
-#define eepro_diag(ioaddr) outb(DIAGNOSE_CMD, ioaddr)
-
-/* ack for rx int */
-#define eepro_ack_rx(ioaddr) outb (RX_INT, ioaddr + STATUS_REG)
-
-/* ack for tx int */
-#define eepro_ack_tx(ioaddr) outb (TX_INT, ioaddr + STATUS_REG)
-
-/* a complete sel reset */
-#define eepro_complete_selreset(ioaddr) { \
- dev->stats.tx_errors++;\
- eepro_sel_reset(ioaddr);\
- lp->tx_end = \
- lp->xmt_lower_limit;\
- lp->tx_start = lp->tx_end;\
- lp->tx_last = 0;\
- dev->trans_start = jiffies;\
- netif_wake_queue(dev);\
- eepro_en_rx(ioaddr);\
- }
-
-/* Check for a network adaptor of this type, and return '0' if one exists.
- If dev->base_addr == 0, probe all likely locations.
- If dev->base_addr == 1, always return failure.
- If dev->base_addr == 2, allocate space for the device and return success
- (detachable devices only).
- */
-static int __init do_eepro_probe(struct net_device *dev)
-{
- int i;
- int base_addr = dev->base_addr;
- int irq = dev->irq;
-
-#ifdef PnPWakeup
- /* XXXX for multiple cards should this only be run once? */
-
- /* Wakeup: */
- #define WakeupPort 0x279
- #define WakeupSeq {0x6A, 0xB5, 0xDA, 0xED, 0xF6, 0xFB, 0x7D, 0xBE,\
- 0xDF, 0x6F, 0x37, 0x1B, 0x0D, 0x86, 0xC3, 0x61,\
- 0xB0, 0x58, 0x2C, 0x16, 0x8B, 0x45, 0xA2, 0xD1,\
- 0xE8, 0x74, 0x3A, 0x9D, 0xCE, 0xE7, 0x73, 0x43}
-
- {
- unsigned short int WS[32]=WakeupSeq;
-
- if (request_region(WakeupPort, 2, "eepro wakeup")) {
- if (net_debug>5)
- printk(KERN_DEBUG "Waking UP\n");
-
- outb_p(0,WakeupPort);
- outb_p(0,WakeupPort);
- for (i=0; i<32; i++) {
- outb_p(WS[i],WakeupPort);
- if (net_debug>5) printk(KERN_DEBUG ": %#x ",WS[i]);
- }
-
- release_region(WakeupPort, 2);
- } else
- printk(KERN_WARNING "PnP wakeup region busy!\n");
- }
-#endif
-
- if (base_addr > 0x1ff) /* Check a single specified location. */
- return eepro_probe1(dev, 0);
-
- else if (base_addr != 0) /* Don't probe at all. */
- return -ENXIO;
-
- for (i = 0; eepro_portlist[i]; i++) {
- dev->base_addr = eepro_portlist[i];
- dev->irq = irq;
- if (eepro_probe1(dev, 1) == 0)
- return 0;
- }
-
- return -ENODEV;
-}
-
-#ifndef MODULE
-struct net_device * __init eepro_probe(int unit)
-{
- struct net_device *dev = alloc_etherdev(sizeof(struct eepro_local));
- int err;
-
- if (!dev)
- return ERR_PTR(-ENODEV);
-
- sprintf(dev->name, "eth%d", unit);
- netdev_boot_setup_check(dev);
-
- err = do_eepro_probe(dev);
- if (err)
- goto out;
- return dev;
-out:
- free_netdev(dev);
- return ERR_PTR(err);
-}
-#endif
-
-static void __init printEEPROMInfo(struct net_device *dev)
-{
- struct eepro_local *lp = netdev_priv(dev);
- int ioaddr = dev->base_addr;
- unsigned short Word;
- int i,j;
-
- j = ee_Checksum;
- for (i = 0; i < 8; i++)
- j += lp->word[i];
- for ( ; i < ee_SIZE; i++)
- j += read_eeprom(ioaddr, i, dev);
-
- printk(KERN_DEBUG "Checksum: %#x\n",j&0xffff);
-
- Word = lp->word[0];
- printk(KERN_DEBUG "Word0:\n");
- printk(KERN_DEBUG " Plug 'n Pray: %d\n",GetBit(Word,ee_PnP));
- printk(KERN_DEBUG " Buswidth: %d\n",(GetBit(Word,ee_BusWidth)+1)*8 );
- printk(KERN_DEBUG " AutoNegotiation: %d\n",GetBit(Word,ee_AutoNeg));
- printk(KERN_DEBUG " IO Address: %#x\n", (Word>>ee_IO0)<<4);
-
- if (net_debug>4) {
- Word = lp->word[1];
- printk(KERN_DEBUG "Word1:\n");
- printk(KERN_DEBUG " INT: %d\n", Word & ee_IntMask);
- printk(KERN_DEBUG " LI: %d\n", GetBit(Word,ee_LI));
- printk(KERN_DEBUG " PC: %d\n", GetBit(Word,ee_PC));
- printk(KERN_DEBUG " TPE/AUI: %d\n", GetBit(Word,ee_TPE_AUI));
- printk(KERN_DEBUG " Jabber: %d\n", GetBit(Word,ee_Jabber));
- printk(KERN_DEBUG " AutoPort: %d\n", !GetBit(Word,ee_AutoPort));
- printk(KERN_DEBUG " Duplex: %d\n", GetBit(Word,ee_Duplex));
- }
-
- Word = lp->word[5];
- printk(KERN_DEBUG "Word5:\n");
- printk(KERN_DEBUG " BNC: %d\n",GetBit(Word,ee_BNC_TPE));
- printk(KERN_DEBUG " NumConnectors: %d\n",GetBit(Word,ee_NumConn));
- printk(KERN_DEBUG " Has ");
- if (GetBit(Word,ee_PortTPE)) printk(KERN_DEBUG "TPE ");
- if (GetBit(Word,ee_PortBNC)) printk(KERN_DEBUG "BNC ");
- if (GetBit(Word,ee_PortAUI)) printk(KERN_DEBUG "AUI ");
- printk(KERN_DEBUG "port(s)\n");
-
- Word = lp->word[6];
- printk(KERN_DEBUG "Word6:\n");
- printk(KERN_DEBUG " Stepping: %d\n",Word & ee_StepMask);
- printk(KERN_DEBUG " BoardID: %d\n",Word>>ee_BoardID);
-
- Word = lp->word[7];
- printk(KERN_DEBUG "Word7:\n");
- printk(KERN_DEBUG " INT to IRQ:\n");
-
- for (i=0, j=0; i<15; i++)
- if (GetBit(Word,i)) printk(KERN_DEBUG " INT%d -> IRQ %d;",j++,i);
-
- printk(KERN_DEBUG "\n");
-}
-
-/* function to recalculate the limits of buffer based on rcv_ram */
-static void eepro_recalc (struct net_device *dev)
-{
- struct eepro_local * lp;
-
- lp = netdev_priv(dev);
- lp->xmt_ram = RAM_SIZE - lp->rcv_ram;
-
- if (lp->eepro == LAN595FX_10ISA) {
- lp->xmt_lower_limit = XMT_START_10;
- lp->xmt_upper_limit = (lp->xmt_ram - 2);
- lp->rcv_lower_limit = lp->xmt_ram;
- lp->rcv_upper_limit = (RAM_SIZE - 2);
- }
- else {
- lp->rcv_lower_limit = RCV_START_PRO;
- lp->rcv_upper_limit = (lp->rcv_ram - 2);
- lp->xmt_lower_limit = lp->rcv_ram;
- lp->xmt_upper_limit = (RAM_SIZE - 2);
- }
-}
-
-/* prints boot-time info */
-static void __init eepro_print_info (struct net_device *dev)
-{
- struct eepro_local * lp = netdev_priv(dev);
- int i;
- const char * ifmap[] = {"AUI", "10Base2", "10BaseT"};
-
- i = inb(dev->base_addr + ID_REG);
- printk(KERN_DEBUG " id: %#x ",i);
- printk(" io: %#x ", (unsigned)dev->base_addr);
-
- switch (lp->eepro) {
- case LAN595FX_10ISA:
- printk("%s: Intel EtherExpress 10 ISA\n at %#x,",
- dev->name, (unsigned)dev->base_addr);
- break;
- case LAN595FX:
- printk("%s: Intel EtherExpress Pro/10+ ISA\n at %#x,",
- dev->name, (unsigned)dev->base_addr);
- break;
- case LAN595TX:
- printk("%s: Intel EtherExpress Pro/10 ISA at %#x,",
- dev->name, (unsigned)dev->base_addr);
- break;
- case LAN595:
- printk("%s: Intel 82595-based lan card at %#x,",
- dev->name, (unsigned)dev->base_addr);
- break;
- }
-
- printk(" %pM", dev->dev_addr);
-
- if (net_debug > 3)
- printk(KERN_DEBUG ", %dK RCV buffer",
- (int)(lp->rcv_ram)/1024);
-
- if (dev->irq > 2)
- printk(", IRQ %d, %s.\n", dev->irq, ifmap[dev->if_port]);
- else
- printk(", %s.\n", ifmap[dev->if_port]);
-
- if (net_debug > 3) {
- i = lp->word[5];
- if (i & 0x2000) /* bit 13 of EEPROM word 5 */
- printk(KERN_DEBUG "%s: Concurrent Processing is "
- "enabled but not used!\n", dev->name);
- }
-
- /* Check the station address for the manufacturer's code */
- if (net_debug>3)
- printEEPROMInfo(dev);
-}
-
-static const struct ethtool_ops eepro_ethtool_ops;
-
-static const struct net_device_ops eepro_netdev_ops = {
- .ndo_open = eepro_open,
- .ndo_stop = eepro_close,
- .ndo_start_xmit = eepro_send_packet,
- .ndo_set_multicast_list = set_multicast_list,
- .ndo_tx_timeout = eepro_tx_timeout,
- .ndo_change_mtu = eth_change_mtu,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-/* This is the real probe routine. Linux has a history of friendly device
- probes on the ISA bus. A good device probe avoids doing writes, and
- verifies that the correct device exists and functions. */
-
-static int __init eepro_probe1(struct net_device *dev, int autoprobe)
-{
- unsigned short station_addr[3], id, counter;
- int i;
- struct eepro_local *lp;
- int ioaddr = dev->base_addr;
- int err;
-
- /* Grab the region so we can find another board if autoIRQ fails. */
- if (!request_region(ioaddr, EEPRO_IO_EXTENT, DRV_NAME)) {
- if (!autoprobe)
- printk(KERN_WARNING "EEPRO: io-port 0x%04x in use\n",
- ioaddr);
- return -EBUSY;
- }
-
- /* Now, we are going to check for the signature of the
- ID_REG (register 2 of bank 0) */
-
- id = inb(ioaddr + ID_REG);
-
- if ((id & ID_REG_MASK) != ID_REG_SIG)
- goto exit;
-
- /* We seem to have the 82595 signature, let's
- play with its counter (last 2 bits of
- register 2 of bank 0) to be sure. */
-
- counter = id & R_ROBIN_BITS;
-
- if ((inb(ioaddr + ID_REG) & R_ROBIN_BITS) != (counter + 0x40))
- goto exit;
-
- lp = netdev_priv(dev);
- memset(lp, 0, sizeof(struct eepro_local));
- lp->xmt_bar = XMT_BAR_PRO;
- lp->xmt_lower_limit_reg = XMT_LOWER_LIMIT_REG_PRO;
- lp->xmt_upper_limit_reg = XMT_UPPER_LIMIT_REG_PRO;
- lp->eeprom_reg = EEPROM_REG_PRO;
- spin_lock_init(&lp->lock);
-
- /* Now, get the ethernet hardware address from
- the EEPROM */
- station_addr[0] = read_eeprom(ioaddr, 2, dev);
-
- /* FIXME - find another way to know that we've found
- * an Etherexpress 10
- */
- if (station_addr[0] == 0x0000 || station_addr[0] == 0xffff) {
- lp->eepro = LAN595FX_10ISA;
- lp->eeprom_reg = EEPROM_REG_10;
- lp->xmt_lower_limit_reg = XMT_LOWER_LIMIT_REG_10;
- lp->xmt_upper_limit_reg = XMT_UPPER_LIMIT_REG_10;
- lp->xmt_bar = XMT_BAR_10;
- station_addr[0] = read_eeprom(ioaddr, 2, dev);
- }
-
- /* get all words at once. will be used here and for ethtool */
- for (i = 0; i < 8; i++) {
- lp->word[i] = read_eeprom(ioaddr, i, dev);
- }
- station_addr[1] = lp->word[3];
- station_addr[2] = lp->word[4];
-
- if (!lp->eepro) {
- if (lp->word[7] == ee_FX_INT2IRQ)
- lp->eepro = 2;
- else if (station_addr[2] == SA_ADDR1)
- lp->eepro = 1;
- }
-
- /* Fill in the 'dev' fields. */
- for (i=0; i < 6; i++)
- dev->dev_addr[i] = ((unsigned char *) station_addr)[5-i];
-
- /* RX buffer must be more than 3K and less than 29K */
- if (dev->mem_end < 3072 || dev->mem_end > 29696)
- lp->rcv_ram = RCV_DEFAULT_RAM;
-
- /* calculate {xmt,rcv}_{lower,upper}_limit */
- eepro_recalc(dev);
-
- if (GetBit(lp->word[5], ee_BNC_TPE))
- dev->if_port = BNC;
- else
- dev->if_port = TPE;
-
- if (dev->irq < 2 && lp->eepro != 0) {
- /* Mask off INT number */
- int count = lp->word[1] & 7;
- unsigned irqMask = lp->word[7];
-
- while (count--)
- irqMask &= irqMask - 1;
-
- count = ffs(irqMask);
-
- if (count)
- dev->irq = count - 1;
-
- if (dev->irq < 2) {
- printk(KERN_ERR " Duh! illegal interrupt vector stored in EEPROM.\n");
- goto exit;
- } else if (dev->irq == 2) {
- dev->irq = 9;
- }
- }
-
- dev->netdev_ops = &eepro_netdev_ops;
- dev->watchdog_timeo = TX_TIMEOUT;
- dev->ethtool_ops = &eepro_ethtool_ops;
-
- /* print boot time info */
- eepro_print_info(dev);
-
- /* reset 82595 */
- eepro_reset(ioaddr);
-
- err = register_netdev(dev);
- if (err)
- goto err;
- return 0;
-exit:
- err = -ENODEV;
-err:
- release_region(dev->base_addr, EEPRO_IO_EXTENT);
- return err;
-}
-
-/* Open/initialize the board. This is called (in the current kernel)
- sometime after booting when the 'ifconfig' program is run.
-
- This routine should set everything up anew at each open, even
- registers that "should" only need to be set once at boot, so that
- there is non-reboot way to recover if something goes wrong.
- */
-
-static const char irqrmap[] = {-1,-1,0,1,-1,2,-1,-1,-1,0,3,4,-1,-1,-1,-1};
-static const char irqrmap2[] = {-1,-1,4,0,1,2,-1,3,-1,4,5,6,7,-1,-1,-1};
-static int eepro_grab_irq(struct net_device *dev)
-{
- static const int irqlist[] = { 3, 4, 5, 7, 9, 10, 11, 12, 0 };
- const int *irqp = irqlist;
- int temp_reg, ioaddr = dev->base_addr;
-
- eepro_sw2bank1(ioaddr); /* be CAREFUL, BANK 1 now */
-
- /* Enable the interrupt line. */
- eepro_en_intline(ioaddr);
-
- /* be CAREFUL, BANK 0 now */
- eepro_sw2bank0(ioaddr);
-
- /* clear all interrupts */
- eepro_clear_int(ioaddr);
-
- /* Let EXEC event to interrupt */
- eepro_en_intexec(ioaddr);
-
- do {
- eepro_sw2bank1(ioaddr); /* be CAREFUL, BANK 1 now */
-
- temp_reg = inb(ioaddr + INT_NO_REG);
- outb((temp_reg & 0xf8) | irqrmap[*irqp], ioaddr + INT_NO_REG);
-
- eepro_sw2bank0(ioaddr); /* Switch back to Bank 0 */
-
- if (request_irq (*irqp, NULL, IRQF_SHARED, "bogus", dev) != EBUSY) {
- unsigned long irq_mask;
- /* Twinkle the interrupt, and check if it's seen */
- irq_mask = probe_irq_on();
-
- eepro_diag(ioaddr); /* RESET the 82595 */
- mdelay(20);
-
- if (*irqp == probe_irq_off(irq_mask)) /* It's a good IRQ line */
- break;
-
- /* clear all interrupts */
- eepro_clear_int(ioaddr);
- }
- } while (*++irqp);
-
- eepro_sw2bank1(ioaddr); /* Switch back to Bank 1 */
-
- /* Disable the physical interrupt line. */
- eepro_dis_intline(ioaddr);
-
- eepro_sw2bank0(ioaddr); /* Switch back to Bank 0 */
-
- /* Mask all the interrupts. */
- eepro_dis_int(ioaddr);
-
- /* clear all interrupts */
- eepro_clear_int(ioaddr);
-
- return dev->irq;
-}
-
-static int eepro_open(struct net_device *dev)
-{
- unsigned short temp_reg, old8, old9;
- int irqMask;
- int i, ioaddr = dev->base_addr;
- struct eepro_local *lp = netdev_priv(dev);
-
- if (net_debug > 3)
- printk(KERN_DEBUG "%s: entering eepro_open routine.\n", dev->name);
-
- irqMask = lp->word[7];
-
- if (lp->eepro == LAN595FX_10ISA) {
- if (net_debug > 3) printk(KERN_DEBUG "p->eepro = 3;\n");
- }
- else if (irqMask == ee_FX_INT2IRQ) /* INT to IRQ Mask */
- {
- lp->eepro = 2; /* Yes, an Intel EtherExpress Pro/10+ */
- if (net_debug > 3) printk(KERN_DEBUG "p->eepro = 2;\n");
- }
-
- else if ((dev->dev_addr[0] == SA_ADDR0 &&
- dev->dev_addr[1] == SA_ADDR1 &&
- dev->dev_addr[2] == SA_ADDR2))
- {
- lp->eepro = 1;
- if (net_debug > 3) printk(KERN_DEBUG "p->eepro = 1;\n");
- } /* Yes, an Intel EtherExpress Pro/10 */
-
- else lp->eepro = 0; /* No, it is a generic 82585 lan card */
-
- /* Get the interrupt vector for the 82595 */
- if (dev->irq < 2 && eepro_grab_irq(dev) == 0) {
- printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, dev->irq);
- return -EAGAIN;
- }
-
- if (request_irq(dev->irq , eepro_interrupt, 0, dev->name, dev)) {
- printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, dev->irq);
- return -EAGAIN;
- }
-
- /* Initialize the 82595. */
-
- eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */
- temp_reg = inb(ioaddr + lp->eeprom_reg);
-
- lp->stepping = temp_reg >> 5; /* Get the stepping number of the 595 */
-
- if (net_debug > 3)
- printk(KERN_DEBUG "The stepping of the 82595 is %d\n", lp->stepping);
-
- if (temp_reg & 0x10) /* Check the TurnOff Enable bit */
- outb(temp_reg & 0xef, ioaddr + lp->eeprom_reg);
- for (i=0; i < 6; i++)
- outb(dev->dev_addr[i] , ioaddr + I_ADD_REG0 + i);
-
- temp_reg = inb(ioaddr + REG1); /* Setup Transmit Chaining */
- outb(temp_reg | XMT_Chain_Int | XMT_Chain_ErrStop /* and discard bad RCV frames */
- | RCV_Discard_BadFrame, ioaddr + REG1);
-
- temp_reg = inb(ioaddr + REG2); /* Match broadcast */
- outb(temp_reg | 0x14, ioaddr + REG2);
-
- temp_reg = inb(ioaddr + REG3);
- outb(temp_reg & 0x3f, ioaddr + REG3); /* clear test mode */
-
- /* Set the receiving mode */
- eepro_sw2bank1(ioaddr); /* be CAREFUL, BANK 1 now */
-
- /* Set the interrupt vector */
- temp_reg = inb(ioaddr + INT_NO_REG);
- if (lp->eepro == LAN595FX || lp->eepro == LAN595FX_10ISA)
- outb((temp_reg & 0xf8) | irqrmap2[dev->irq], ioaddr + INT_NO_REG);
- else outb((temp_reg & 0xf8) | irqrmap[dev->irq], ioaddr + INT_NO_REG);
-
-
- temp_reg = inb(ioaddr + INT_NO_REG);
- if (lp->eepro == LAN595FX || lp->eepro == LAN595FX_10ISA)
- outb((temp_reg & 0xf0) | irqrmap2[dev->irq] | 0x08,ioaddr+INT_NO_REG);
- else outb((temp_reg & 0xf8) | irqrmap[dev->irq], ioaddr + INT_NO_REG);
-
- if (net_debug > 3)
- printk(KERN_DEBUG "eepro_open: content of INT Reg is %x\n", temp_reg);
-
-
- /* Initialize the RCV and XMT upper and lower limits */
- outb(lp->rcv_lower_limit >> 8, ioaddr + RCV_LOWER_LIMIT_REG);
- outb(lp->rcv_upper_limit >> 8, ioaddr + RCV_UPPER_LIMIT_REG);
- outb(lp->xmt_lower_limit >> 8, ioaddr + lp->xmt_lower_limit_reg);
- outb(lp->xmt_upper_limit >> 8, ioaddr + lp->xmt_upper_limit_reg);
-
- /* Enable the interrupt line. */
- eepro_en_intline(ioaddr);
-
- /* Switch back to Bank 0 */
- eepro_sw2bank0(ioaddr);
-
- /* Let RX and TX events to interrupt */
- eepro_en_int(ioaddr);
-
- /* clear all interrupts */
- eepro_clear_int(ioaddr);
-
- /* Initialize RCV */
- outw(lp->rcv_lower_limit, ioaddr + RCV_BAR);
- lp->rx_start = lp->rcv_lower_limit;
- outw(lp->rcv_upper_limit | 0xfe, ioaddr + RCV_STOP);
-
- /* Initialize XMT */
- outw(lp->xmt_lower_limit, ioaddr + lp->xmt_bar);
- lp->tx_start = lp->tx_end = lp->xmt_lower_limit;
- lp->tx_last = 0;
-
- /* Check for the i82595TX and i82595FX */
- old8 = inb(ioaddr + 8);
- outb(~old8, ioaddr + 8);
-
- if ((temp_reg = inb(ioaddr + 8)) == old8) {
- if (net_debug > 3)
- printk(KERN_DEBUG "i82595 detected!\n");
- lp->version = LAN595;
- }
- else {
- lp->version = LAN595TX;
- outb(old8, ioaddr + 8);
- old9 = inb(ioaddr + 9);
-
- if (irqMask==ee_FX_INT2IRQ) {
- if (net_debug > 3) {
- printk(KERN_DEBUG "IrqMask: %#x\n",irqMask);
- printk(KERN_DEBUG "i82595FX detected!\n");
- }
- lp->version = LAN595FX;
- outb(old9, ioaddr + 9);
- if (dev->if_port != TPE) { /* Hopefully, this will fix the
- problem of using Pentiums and
- pro/10 w/ BNC. */
- eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */
- temp_reg = inb(ioaddr + REG13);
- /* disable the full duplex mode since it is not
- applicable with the 10Base2 cable. */
- outb(temp_reg & ~(FDX | A_N_ENABLE), REG13);
- eepro_sw2bank0(ioaddr); /* be CAREFUL, BANK 0 now */
- }
- }
- else if (net_debug > 3) {
- printk(KERN_DEBUG "temp_reg: %#x ~old9: %#x\n",temp_reg,((~old9)&0xff));
- printk(KERN_DEBUG "i82595TX detected!\n");
- }
- }
-
- eepro_sel_reset(ioaddr);
-
- netif_start_queue(dev);
-
- if (net_debug > 3)
- printk(KERN_DEBUG "%s: exiting eepro_open routine.\n", dev->name);
-
- /* enabling rx */
- eepro_en_rx(ioaddr);
-
- return 0;
-}
-
-static void eepro_tx_timeout (struct net_device *dev)
-{
- struct eepro_local *lp = netdev_priv(dev);
- int ioaddr = dev->base_addr;
-
- /* if (net_debug > 1) */
- printk (KERN_ERR "%s: transmit timed out, %s?\n", dev->name,
- "network cable problem");
- /* This is not a duplicate. One message for the console,
- one for the log file */
- printk (KERN_DEBUG "%s: transmit timed out, %s?\n", dev->name,
- "network cable problem");
- eepro_complete_selreset(ioaddr);
-}
-
-
-static netdev_tx_t eepro_send_packet(struct sk_buff *skb,
- struct net_device *dev)
-{
- struct eepro_local *lp = netdev_priv(dev);
- unsigned long flags;
- int ioaddr = dev->base_addr;
- short length = skb->len;
-
- if (net_debug > 5)
- printk(KERN_DEBUG "%s: entering eepro_send_packet routine.\n", dev->name);
-
- if (length < ETH_ZLEN) {
- if (skb_padto(skb, ETH_ZLEN))
- return NETDEV_TX_OK;
- length = ETH_ZLEN;
- }
- netif_stop_queue (dev);
-
- eepro_dis_int(ioaddr);
- spin_lock_irqsave(&lp->lock, flags);
-
- {
- unsigned char *buf = skb->data;
-
- if (hardware_send_packet(dev, buf, length))
- /* we won't wake queue here because we're out of space */
- dev->stats.tx_dropped++;
- else {
- dev->stats.tx_bytes+=skb->len;
- netif_wake_queue(dev);
- }
-
- }
-
- dev_kfree_skb (skb);
-
- /* You might need to clean up and record Tx statistics here. */
- /* dev->stats.tx_aborted_errors++; */
-
- if (net_debug > 5)
- printk(KERN_DEBUG "%s: exiting eepro_send_packet routine.\n", dev->name);
-
- eepro_en_int(ioaddr);
- spin_unlock_irqrestore(&lp->lock, flags);
-
- return NETDEV_TX_OK;
-}
-
-
-/* The typical workload of the driver:
- Handle the network interface interrupts. */
-
-static irqreturn_t
-eepro_interrupt(int irq, void *dev_id)
-{
- struct net_device *dev = dev_id;
- struct eepro_local *lp;
- int ioaddr, status, boguscount = 20;
- int handled = 0;
-
- lp = netdev_priv(dev);
-
- spin_lock(&lp->lock);
-
- if (net_debug > 5)
- printk(KERN_DEBUG "%s: entering eepro_interrupt routine.\n", dev->name);
-
- ioaddr = dev->base_addr;
-
- while (((status = inb(ioaddr + STATUS_REG)) & (RX_INT|TX_INT)) && (boguscount--))
- {
- handled = 1;
- if (status & RX_INT) {
- if (net_debug > 4)
- printk(KERN_DEBUG "%s: packet received interrupt.\n", dev->name);
-
- eepro_dis_int(ioaddr);
-
- /* Get the received packets */
- eepro_ack_rx(ioaddr);
- eepro_rx(dev);
-
- eepro_en_int(ioaddr);
- }
- if (status & TX_INT) {
- if (net_debug > 4)
- printk(KERN_DEBUG "%s: packet transmit interrupt.\n", dev->name);
-
-
- eepro_dis_int(ioaddr);
-
- /* Process the status of transmitted packets */
- eepro_ack_tx(ioaddr);
- eepro_transmit_interrupt(dev);
-
- eepro_en_int(ioaddr);
- }
- }
-
- if (net_debug > 5)
- printk(KERN_DEBUG "%s: exiting eepro_interrupt routine.\n", dev->name);
-
- spin_unlock(&lp->lock);
- return IRQ_RETVAL(handled);
-}
-
-static int eepro_close(struct net_device *dev)
-{
- struct eepro_local *lp = netdev_priv(dev);
- int ioaddr = dev->base_addr;
- short temp_reg;
-
- netif_stop_queue(dev);
-
- eepro_sw2bank1(ioaddr); /* Switch back to Bank 1 */
-
- /* Disable the physical interrupt line. */
- temp_reg = inb(ioaddr + REG1);
- outb(temp_reg & 0x7f, ioaddr + REG1);
-
- eepro_sw2bank0(ioaddr); /* Switch back to Bank 0 */
-
- /* Flush the Tx and disable Rx. */
- outb(STOP_RCV_CMD, ioaddr);
- lp->tx_start = lp->tx_end = lp->xmt_lower_limit;
- lp->tx_last = 0;
-
- /* Mask all the interrupts. */
- eepro_dis_int(ioaddr);
-
- /* clear all interrupts */
- eepro_clear_int(ioaddr);
-
- /* Reset the 82595 */
- eepro_reset(ioaddr);
-
- /* release the interrupt */
- free_irq(dev->irq, dev);
-
- /* Update the statistics here. What statistics? */
-
- return 0;
-}
-
-/* Set or clear the multicast filter for this adaptor.
- */
-static void
-set_multicast_list(struct net_device *dev)
-{
- struct eepro_local *lp = netdev_priv(dev);
- short ioaddr = dev->base_addr;
- unsigned short mode;
- struct netdev_hw_addr *ha;
- int mc_count = netdev_mc_count(dev);
-
- if (dev->flags&(IFF_ALLMULTI|IFF_PROMISC) || mc_count > 63)
- {
- eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */
- mode = inb(ioaddr + REG2);
- outb(mode | PRMSC_Mode, ioaddr + REG2);
- mode = inb(ioaddr + REG3);
- outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */
- eepro_sw2bank0(ioaddr); /* Return to BANK 0 now */
- }
-
- else if (mc_count == 0)
- {
- eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */
- mode = inb(ioaddr + REG2);
- outb(mode & 0xd6, ioaddr + REG2); /* Turn off Multi-IA and PRMSC_Mode bits */
- mode = inb(ioaddr + REG3);
- outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */
- eepro_sw2bank0(ioaddr); /* Return to BANK 0 now */
- }
-
- else
- {
- unsigned short status, *eaddrs;
- int i, boguscount = 0;
-
- /* Disable RX and TX interrupts. Necessary to avoid
- corruption of the HOST_ADDRESS_REG by interrupt
- service routines. */
- eepro_dis_int(ioaddr);
-
- eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */
- mode = inb(ioaddr + REG2);
- outb(mode | Multi_IA, ioaddr + REG2);
- mode = inb(ioaddr + REG3);
- outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */
- eepro_sw2bank0(ioaddr); /* Return to BANK 0 now */
- outw(lp->tx_end, ioaddr + HOST_ADDRESS_REG);
- outw(MC_SETUP, ioaddr + IO_PORT);
- outw(0, ioaddr + IO_PORT);
- outw(0, ioaddr + IO_PORT);
- outw(6 * (mc_count + 1), ioaddr + IO_PORT);
-
- netdev_for_each_mc_addr(ha, dev) {
- eaddrs = (unsigned short *) ha->addr;
- outw(*eaddrs++, ioaddr + IO_PORT);
- outw(*eaddrs++, ioaddr + IO_PORT);
- outw(*eaddrs++, ioaddr + IO_PORT);
- }
-
- eaddrs = (unsigned short *) dev->dev_addr;
- outw(eaddrs[0], ioaddr + IO_PORT);
- outw(eaddrs[1], ioaddr + IO_PORT);
- outw(eaddrs[2], ioaddr + IO_PORT);
- outw(lp->tx_end, ioaddr + lp->xmt_bar);
- outb(MC_SETUP, ioaddr);
-
- /* Update the transmit queue */
- i = lp->tx_end + XMT_HEADER + 6 * (mc_count + 1);
-
- if (lp->tx_start != lp->tx_end)
- {
- /* update the next address and the chain bit in the
- last packet */
- outw(lp->tx_last + XMT_CHAIN, ioaddr + HOST_ADDRESS_REG);
- outw(i, ioaddr + IO_PORT);
- outw(lp->tx_last + XMT_COUNT, ioaddr + HOST_ADDRESS_REG);
- status = inw(ioaddr + IO_PORT);
- outw(status | CHAIN_BIT, ioaddr + IO_PORT);
- lp->tx_end = i ;
- }
- else {
- lp->tx_start = lp->tx_end = i ;
- }
-
- /* Acknowledge that the MC setup is done */
- do { /* We should be doing this in the eepro_interrupt()! */
- SLOW_DOWN;
- SLOW_DOWN;
- if (inb(ioaddr + STATUS_REG) & 0x08)
- {
- i = inb(ioaddr);
- outb(0x08, ioaddr + STATUS_REG);
-
- if (i & 0x20) { /* command ABORTed */
- printk(KERN_NOTICE "%s: multicast setup failed.\n",
- dev->name);
- break;
- } else if ((i & 0x0f) == 0x03) { /* MC-Done */
- printk(KERN_DEBUG "%s: set Rx mode to %d address%s.\n",
- dev->name, mc_count,
- mc_count > 1 ? "es":"");
- break;
- }
- }
- } while (++boguscount < 100);
-
- /* Re-enable RX and TX interrupts */
- eepro_en_int(ioaddr);
- }
- if (lp->eepro == LAN595FX_10ISA) {
- eepro_complete_selreset(ioaddr);
- }
- else
- eepro_en_rx(ioaddr);
-}
-
-/* The horrible routine to read a word from the serial EEPROM. */
-/* IMPORTANT - the 82595 will be set to Bank 0 after the eeprom is read */
-
-/* The delay between EEPROM clock transitions. */
-#define eeprom_delay() { udelay(40); }
-#define EE_READ_CMD (6 << 6)
-
-static int
-read_eeprom(int ioaddr, int location, struct net_device *dev)
-{
- int i;
- unsigned short retval = 0;
- struct eepro_local *lp = netdev_priv(dev);
- short ee_addr = ioaddr + lp->eeprom_reg;
- int read_cmd = location | EE_READ_CMD;
- short ctrl_val = EECS ;
-
- /* XXXX - black magic */
- eepro_sw2bank1(ioaddr);
- outb(0x00, ioaddr + STATUS_REG);
- /* XXXX - black magic */
-
- eepro_sw2bank2(ioaddr);
- outb(ctrl_val, ee_addr);
-
- /* Shift the read command bits out. */
- for (i = 8; i >= 0; i--) {
- short outval = (read_cmd & (1 << i)) ? ctrl_val | EEDI
- : ctrl_val;
- outb(outval, ee_addr);
- outb(outval | EESK, ee_addr); /* EEPROM clock tick. */
- eeprom_delay();
- outb(outval, ee_addr); /* Finish EEPROM a clock tick. */
- eeprom_delay();
- }
- outb(ctrl_val, ee_addr);
-
- for (i = 16; i > 0; i--) {
- outb(ctrl_val | EESK, ee_addr); eeprom_delay();
- retval = (retval << 1) | ((inb(ee_addr) & EEDO) ? 1 : 0);
- outb(ctrl_val, ee_addr); eeprom_delay();
- }
-
- /* Terminate the EEPROM access. */
- ctrl_val &= ~EECS;
- outb(ctrl_val | EESK, ee_addr);
- eeprom_delay();
- outb(ctrl_val, ee_addr);
- eeprom_delay();
- eepro_sw2bank0(ioaddr);
- return retval;
-}
-
-static int
-hardware_send_packet(struct net_device *dev, void *buf, short length)
-{
- struct eepro_local *lp = netdev_priv(dev);
- short ioaddr = dev->base_addr;
- unsigned status, tx_available, last, end;
-
- if (net_debug > 5)
- printk(KERN_DEBUG "%s: entering hardware_send_packet routine.\n", dev->name);
-
- /* determine how much of the transmit buffer space is available */
- if (lp->tx_end > lp->tx_start)
- tx_available = lp->xmt_ram - (lp->tx_end - lp->tx_start);
- else if (lp->tx_end < lp->tx_start)
- tx_available = lp->tx_start - lp->tx_end;
- else tx_available = lp->xmt_ram;
-
- if (((((length + 3) >> 1) << 1) + 2*XMT_HEADER) >= tx_available) {
- /* No space available ??? */
- return 1;
- }
-
- last = lp->tx_end;
- end = last + (((length + 3) >> 1) << 1) + XMT_HEADER;
-
- if (end >= lp->xmt_upper_limit + 2) { /* the transmit buffer is wrapped around */
- if ((lp->xmt_upper_limit + 2 - last) <= XMT_HEADER) {
- /* Arrrr!!!, must keep the xmt header together,
- several days were lost to chase this one down. */
- last = lp->xmt_lower_limit;
- end = last + (((length + 3) >> 1) << 1) + XMT_HEADER;
- }
- else end = lp->xmt_lower_limit + (end -
- lp->xmt_upper_limit + 2);
- }
-
- outw(last, ioaddr + HOST_ADDRESS_REG);
- outw(XMT_CMD, ioaddr + IO_PORT);
- outw(0, ioaddr + IO_PORT);
- outw(end, ioaddr + IO_PORT);
- outw(length, ioaddr + IO_PORT);
-
- if (lp->version == LAN595)
- outsw(ioaddr + IO_PORT, buf, (length + 3) >> 1);
- else { /* LAN595TX or LAN595FX, capable of 32-bit I/O processing */
- unsigned short temp = inb(ioaddr + INT_MASK_REG);
- outb(temp | IO_32_BIT, ioaddr + INT_MASK_REG);
- outsl(ioaddr + IO_PORT_32_BIT, buf, (length + 3) >> 2);
- outb(temp & ~(IO_32_BIT), ioaddr + INT_MASK_REG);
- }
-
- /* A dummy read to flush the DRAM write pipeline */
- status = inw(ioaddr + IO_PORT);
-
- if (lp->tx_start == lp->tx_end) {
- outw(last, ioaddr + lp->xmt_bar);
- outb(XMT_CMD, ioaddr);
- lp->tx_start = last; /* I don't like to change tx_start here */
- }
- else {
- /* update the next address and the chain bit in the
- last packet */
-
- if (lp->tx_end != last) {
- outw(lp->tx_last + XMT_CHAIN, ioaddr + HOST_ADDRESS_REG);
- outw(last, ioaddr + IO_PORT);
- }
-
- outw(lp->tx_last + XMT_COUNT, ioaddr + HOST_ADDRESS_REG);
- status = inw(ioaddr + IO_PORT);
- outw(status | CHAIN_BIT, ioaddr + IO_PORT);
-
- /* Continue the transmit command */
- outb(RESUME_XMT_CMD, ioaddr);
- }
-
- lp->tx_last = last;
- lp->tx_end = end;
-
- if (net_debug > 5)
- printk(KERN_DEBUG "%s: exiting hardware_send_packet routine.\n", dev->name);
-
- return 0;
-}
-
-static void
-eepro_rx(struct net_device *dev)
-{
- struct eepro_local *lp = netdev_priv(dev);
- short ioaddr = dev->base_addr;
- short boguscount = 20;
- short rcv_car = lp->rx_start;
- unsigned rcv_event, rcv_status, rcv_next_frame, rcv_size;
-
- if (net_debug > 5)
- printk(KERN_DEBUG "%s: entering eepro_rx routine.\n", dev->name);
-
- /* Set the read pointer to the start of the RCV */
- outw(rcv_car, ioaddr + HOST_ADDRESS_REG);
-
- rcv_event = inw(ioaddr + IO_PORT);
-
- while (rcv_event == RCV_DONE) {
-
- rcv_status = inw(ioaddr + IO_PORT);
- rcv_next_frame = inw(ioaddr + IO_PORT);
- rcv_size = inw(ioaddr + IO_PORT);
-
- if ((rcv_status & (RX_OK | RX_ERROR)) == RX_OK) {
-
- /* Malloc up new buffer. */
- struct sk_buff *skb;
-
- dev->stats.rx_bytes+=rcv_size;
- rcv_size &= 0x3fff;
- skb = dev_alloc_skb(rcv_size+5);
- if (skb == NULL) {
- printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
- dev->stats.rx_dropped++;
- rcv_car = lp->rx_start + RCV_HEADER + rcv_size;
- lp->rx_start = rcv_next_frame;
- outw(rcv_next_frame, ioaddr + HOST_ADDRESS_REG);
-
- break;
- }
- skb_reserve(skb,2);
-
- if (lp->version == LAN595)
- insw(ioaddr+IO_PORT, skb_put(skb,rcv_size), (rcv_size + 3) >> 1);
- else { /* LAN595TX or LAN595FX, capable of 32-bit I/O processing */
- unsigned short temp = inb(ioaddr + INT_MASK_REG);
- outb(temp | IO_32_BIT, ioaddr + INT_MASK_REG);
- insl(ioaddr+IO_PORT_32_BIT, skb_put(skb,rcv_size),
- (rcv_size + 3) >> 2);
- outb(temp & ~(IO_32_BIT), ioaddr + INT_MASK_REG);
- }
-
- skb->protocol = eth_type_trans(skb,dev);
- netif_rx(skb);
- dev->stats.rx_packets++;
- }
-
- else { /* Not sure will ever reach here,
- I set the 595 to discard bad received frames */
- dev->stats.rx_errors++;
-
- if (rcv_status & 0x0100)
- dev->stats.rx_over_errors++;
-
- else if (rcv_status & 0x0400)
- dev->stats.rx_frame_errors++;
-
- else if (rcv_status & 0x0800)
- dev->stats.rx_crc_errors++;
-
- printk(KERN_DEBUG "%s: event = %#x, status = %#x, next = %#x, size = %#x\n",
- dev->name, rcv_event, rcv_status, rcv_next_frame, rcv_size);
- }
-
- if (rcv_status & 0x1000)
- dev->stats.rx_length_errors++;
-
- rcv_car = lp->rx_start + RCV_HEADER + rcv_size;
- lp->rx_start = rcv_next_frame;
-
- if (--boguscount == 0)
- break;
-
- outw(rcv_next_frame, ioaddr + HOST_ADDRESS_REG);
- rcv_event = inw(ioaddr + IO_PORT);
-
- }
- if (rcv_car == 0)
- rcv_car = lp->rcv_upper_limit | 0xff;
-
- outw(rcv_car - 1, ioaddr + RCV_STOP);
-
- if (net_debug > 5)
- printk(KERN_DEBUG "%s: exiting eepro_rx routine.\n", dev->name);
-}
-
-static void
-eepro_transmit_interrupt(struct net_device *dev)
-{
- struct eepro_local *lp = netdev_priv(dev);
- short ioaddr = dev->base_addr;
- short boguscount = 25;
- short xmt_status;
-
- while ((lp->tx_start != lp->tx_end) && boguscount--) {
-
- outw(lp->tx_start, ioaddr + HOST_ADDRESS_REG);
- xmt_status = inw(ioaddr+IO_PORT);
-
- if (!(xmt_status & TX_DONE_BIT))
- break;
-
- xmt_status = inw(ioaddr+IO_PORT);
- lp->tx_start = inw(ioaddr+IO_PORT);
-
- netif_wake_queue (dev);
-
- if (xmt_status & TX_OK)
- dev->stats.tx_packets++;
- else {
- dev->stats.tx_errors++;
- if (xmt_status & 0x0400) {
- dev->stats.tx_carrier_errors++;
- printk(KERN_DEBUG "%s: carrier error\n",
- dev->name);
- printk(KERN_DEBUG "%s: XMT status = %#x\n",
- dev->name, xmt_status);
- }
- else {
- printk(KERN_DEBUG "%s: XMT status = %#x\n",
- dev->name, xmt_status);
- printk(KERN_DEBUG "%s: XMT status = %#x\n",
- dev->name, xmt_status);
- }
- }
- if (xmt_status & 0x000f) {
- dev->stats.collisions += (xmt_status & 0x000f);
- }
-
- if ((xmt_status & 0x0040) == 0x0) {
- dev->stats.tx_heartbeat_errors++;
- }
- }
-}
-
-static int eepro_ethtool_get_settings(struct net_device *dev,
- struct ethtool_cmd *cmd)
-{
- struct eepro_local *lp = netdev_priv(dev);
-
- cmd->supported = SUPPORTED_10baseT_Half |
- SUPPORTED_10baseT_Full |
- SUPPORTED_Autoneg;
- cmd->advertising = ADVERTISED_10baseT_Half |
- ADVERTISED_10baseT_Full |
- ADVERTISED_Autoneg;
-
- if (GetBit(lp->word[5], ee_PortTPE)) {
- cmd->supported |= SUPPORTED_TP;
- cmd->advertising |= ADVERTISED_TP;
- }
- if (GetBit(lp->word[5], ee_PortBNC)) {
- cmd->supported |= SUPPORTED_BNC;
- cmd->advertising |= ADVERTISED_BNC;
- }
- if (GetBit(lp->word[5], ee_PortAUI)) {
- cmd->supported |= SUPPORTED_AUI;
- cmd->advertising |= ADVERTISED_AUI;
- }
-
- ethtool_cmd_speed_set(cmd, SPEED_10);
-
- if (dev->if_port == TPE && lp->word[1] & ee_Duplex) {
- cmd->duplex = DUPLEX_FULL;
- }
- else {
- cmd->duplex = DUPLEX_HALF;
- }
-
- cmd->port = dev->if_port;
- cmd->phy_address = dev->base_addr;
- cmd->transceiver = XCVR_INTERNAL;
-
- if (lp->word[0] & ee_AutoNeg) {
- cmd->autoneg = 1;
- }
-
- return 0;
-}
-
-static void eepro_ethtool_get_drvinfo(struct net_device *dev,
- struct ethtool_drvinfo *drvinfo)
-{
- strcpy(drvinfo->driver, DRV_NAME);
- strcpy(drvinfo->version, DRV_VERSION);
- sprintf(drvinfo->bus_info, "ISA 0x%lx", dev->base_addr);
-}
-
-static const struct ethtool_ops eepro_ethtool_ops = {
- .get_settings = eepro_ethtool_get_settings,
- .get_drvinfo = eepro_ethtool_get_drvinfo,
-};
-
-#ifdef MODULE
-
-#define MAX_EEPRO 8
-static struct net_device *dev_eepro[MAX_EEPRO];
-
-static int io[MAX_EEPRO] = {
- [0 ... MAX_EEPRO-1] = -1
-};
-static int irq[MAX_EEPRO];
-static int mem[MAX_EEPRO] = { /* Size of the rx buffer in KB */
- [0 ... MAX_EEPRO-1] = RCV_DEFAULT_RAM/1024
-};
-static int autodetect;
-
-static int n_eepro;
-/* For linux 2.1.xx */
-
-MODULE_AUTHOR("Pascal Dupuis and others");
-MODULE_DESCRIPTION("Intel i82595 ISA EtherExpressPro10/10+ driver");
-MODULE_LICENSE("GPL");
-
-module_param_array(io, int, NULL, 0);
-module_param_array(irq, int, NULL, 0);
-module_param_array(mem, int, NULL, 0);
-module_param(autodetect, int, 0);
-MODULE_PARM_DESC(io, "EtherExpress Pro/10 I/O base address(es)");
-MODULE_PARM_DESC(irq, "EtherExpress Pro/10 IRQ number(s)");
-MODULE_PARM_DESC(mem, "EtherExpress Pro/10 Rx buffer size(es) in kB (3-29)");
-MODULE_PARM_DESC(autodetect, "EtherExpress Pro/10 force board(s) detection (0-1)");
-
-int __init init_module(void)
-{
- struct net_device *dev;
- int i;
- if (io[0] == -1 && autodetect == 0) {
- printk(KERN_WARNING "eepro_init_module: Probe is very dangerous in ISA boards!\n");
- printk(KERN_WARNING "eepro_init_module: Please add \"autodetect=1\" to force probe\n");
- return -ENODEV;
- }
- else if (autodetect) {
- /* if autodetect is set then we must force detection */
- for (i = 0; i < MAX_EEPRO; i++) {
- io[i] = 0;
- }
-
- printk(KERN_INFO "eepro_init_module: Auto-detecting boards (May God protect us...)\n");
- }
-
- for (i = 0; i < MAX_EEPRO && io[i] != -1; i++) {
- dev = alloc_etherdev(sizeof(struct eepro_local));
- if (!dev)
- break;
-
- dev->mem_end = mem[i];
- dev->base_addr = io[i];
- dev->irq = irq[i];
-
- if (do_eepro_probe(dev) == 0) {
- dev_eepro[n_eepro++] = dev;
- continue;
- }
- free_netdev(dev);
- break;
- }
-
- if (n_eepro)
- printk(KERN_INFO "%s", version);
-
- return n_eepro ? 0 : -ENODEV;
-}
-
-void __exit
-cleanup_module(void)
-{
- int i;
-
- for (i=0; i<n_eepro; i++) {
- struct net_device *dev = dev_eepro[i];
- unregister_netdev(dev);
- release_region(dev->base_addr, EEPRO_IO_EXTENT);
- free_netdev(dev);
- }
-}
-#endif /* MODULE */
+++ /dev/null
-/* Intel EtherExpress 16 device driver for Linux
- *
- * Written by John Sullivan, 1995
- * based on original code by Donald Becker, with changes by
- * Alan Cox and Pauline Middelink.
- *
- * Support for 8-bit mode by Zoltan Szilagyi <zoltans@cs.arizona.edu>
- *
- * Many modifications, and currently maintained, by
- * Philip Blundell <philb@gnu.org>
- * Added the Compaq LTE Alan Cox <alan@lxorguk.ukuu.org.uk>
- * Added MCA support Adam Fritzler
- *
- * Note - this driver is experimental still - it has problems on faster
- * machines. Someone needs to sit down and go through it line by line with
- * a databook...
- */
-
-/* The EtherExpress 16 is a fairly simple card, based on a shared-memory
- * design using the i82586 Ethernet coprocessor. It bears no relationship,
- * as far as I know, to the similarly-named "EtherExpress Pro" range.
- *
- * Historically, Linux support for these cards has been very bad. However,
- * things seem to be getting better slowly.
- */
-
-/* If your card is confused about what sort of interface it has (eg it
- * persistently reports "10baseT" when none is fitted), running 'SOFTSET /BART'
- * or 'SOFTSET /LISA' from DOS seems to help.
- */
-
-/* Here's the scoop on memory mapping.
- *
- * There are three ways to access EtherExpress card memory: either using the
- * shared-memory mapping, or using PIO through the dataport, or using PIO
- * through the "shadow memory" ports.
- *
- * The shadow memory system works by having the card map some of its memory
- * as follows:
- *
- * (the low five bits of the SMPTR are ignored)
- *
- * base+0x4000..400f memory at SMPTR+0..15
- * base+0x8000..800f memory at SMPTR+16..31
- * base+0xc000..c007 dubious stuff (memory at SMPTR+16..23 apparently)
- * base+0xc008..c00f memory at 0x0008..0x000f
- *
- * This last set (the one at c008) is particularly handy because the SCB
- * lives at 0x0008. So that set of ports gives us easy random access to data
- * in the SCB without having to mess around setting up pointers and the like.
- * We always use this method to access the SCB (via the scb_xx() functions).
- *
- * Dataport access works by aiming the appropriate (read or write) pointer
- * at the first address you're interested in, and then reading or writing from
- * the dataport. The pointers auto-increment after each transfer. We use
- * this for data transfer.
- *
- * We don't use the shared-memory system because it allegedly doesn't work on
- * all cards, and because it's a bit more prone to go wrong (it's one more
- * thing to configure...).
- */
-
-/* Known bugs:
- *
- * - The card seems to want to give us two interrupts every time something
- * happens, where just one would be better.
- */
-
-/*
- *
- * Note by Zoltan Szilagyi 10-12-96:
- *
- * I've succeeded in eliminating the "CU wedged" messages, and hence the
- * lockups, which were only occurring with cards running in 8-bit mode ("force
- * 8-bit operation" in Intel's SoftSet utility). This version of the driver
- * sets the 82586 and the ASIC to 8-bit mode at startup; it also stops the
- * CU before submitting a packet for transmission, and then restarts it as soon
- * as the process of handing the packet is complete. This is definitely an
- * unnecessary slowdown if the card is running in 16-bit mode; therefore one
- * should detect 16-bit vs 8-bit mode from the EEPROM settings and act
- * accordingly. In 8-bit mode with this bugfix I'm getting about 150 K/s for
- * ftp's, which is significantly better than I get in DOS, so the overhead of
- * stopping and restarting the CU with each transmit is not prohibitive in
- * practice.
- *
- * Update by David Woodhouse 11/5/99:
- *
- * I've seen "CU wedged" messages in 16-bit mode, on the Alpha architecture.
- * I assume that this is because 16-bit accesses are actually handled as two
- * 8-bit accesses.
- */
-
-#ifdef __alpha__
-#define LOCKUP16 1
-#endif
-#ifndef LOCKUP16
-#define LOCKUP16 0
-#endif
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/string.h>
-#include <linux/in.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/mca-legacy.h>
-#include <linux/spinlock.h>
-#include <linux/bitops.h>
-#include <linux/jiffies.h>
-
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#ifndef NET_DEBUG
-#define NET_DEBUG 4
-#endif
-
-#include "eexpress.h"
-
-#define EEXP_IO_EXTENT 16
-
-/*
- * Private data declarations
- */
-
-struct net_local
-{
- unsigned long last_tx; /* jiffies when last transmit started */
- unsigned long init_time; /* jiffies when eexp_hw_init586 called */
- unsigned short rx_first; /* first rx buf, same as RX_BUF_START */
- unsigned short rx_last; /* last rx buf */
- unsigned short rx_ptr; /* first rx buf to look at */
- unsigned short tx_head; /* next free tx buf */
- unsigned short tx_reap; /* first in-use tx buf */
- unsigned short tx_tail; /* previous tx buf to tx_head */
- unsigned short tx_link; /* last known-executing tx buf */
- unsigned short last_tx_restart; /* set to tx_link when we
- restart the CU */
- unsigned char started;
- unsigned short rx_buf_start;
- unsigned short rx_buf_end;
- unsigned short num_tx_bufs;
- unsigned short num_rx_bufs;
- unsigned char width; /* 0 for 16bit, 1 for 8bit */
- unsigned char was_promisc;
- unsigned char old_mc_count;
- spinlock_t lock;
-};
-
-/* This is the code and data that is downloaded to the EtherExpress card's
- * memory at boot time.
- */
-
-static unsigned short start_code[] = {
-/* 0x0000 */
- 0x0001, /* ISCP: busy - cleared after reset */
- 0x0008,0x0000,0x0000, /* offset,address (lo,hi) of SCB */
-
- 0x0000,0x0000, /* SCB: status, commands */
- 0x0000,0x0000, /* links to first command block,
- first receive descriptor */
- 0x0000,0x0000, /* CRC error, alignment error counts */
- 0x0000,0x0000, /* out of resources, overrun error counts */
-
- 0x0000,0x0000, /* pad */
- 0x0000,0x0000,
-
-/* 0x20 -- start of 82586 CU program */
-#define CONF_LINK 0x20
- 0x0000,Cmd_Config,
- 0x0032, /* link to next command */
- 0x080c, /* 12 bytes follow : fifo threshold=8 */
- 0x2e40, /* don't rx bad frames
- * SRDY/ARDY => ext. sync. : preamble len=8
- * take addresses from data buffers
- * 6 bytes/address
- */
- 0x6000, /* default backoff method & priority
- * interframe spacing = 0x60 */
- 0xf200, /* slot time=0x200
- * max collision retry = 0xf */
-#define CONF_PROMISC 0x2e
- 0x0000, /* no HDLC : normal CRC : enable broadcast
- * disable promiscuous/multicast modes */
- 0x003c, /* minimum frame length = 60 octets) */
-
- 0x0000,Cmd_SetAddr,
- 0x003e, /* link to next command */
-#define CONF_HWADDR 0x38
- 0x0000,0x0000,0x0000, /* hardware address placed here */
-
- 0x0000,Cmd_MCast,
- 0x0076, /* link to next command */
-#define CONF_NR_MULTICAST 0x44
- 0x0000, /* number of bytes in multicast address(es) */
-#define CONF_MULTICAST 0x46
- 0x0000, 0x0000, 0x0000, /* some addresses */
- 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000,
-
-#define CONF_DIAG_RESULT 0x76
- 0x0000, Cmd_Diag,
- 0x007c, /* link to next command */
-
- 0x0000,Cmd_TDR|Cmd_INT,
- 0x0084,
-#define CONF_TDR_RESULT 0x82
- 0x0000,
-
- 0x0000,Cmd_END|Cmd_Nop, /* end of configure sequence */
- 0x0084 /* dummy link */
-};
-
-/* maps irq number to EtherExpress magic value */
-static char irqrmap[] = { 0,0,1,2,3,4,0,0,0,1,5,6,0,0,0,0 };
-
-#ifdef CONFIG_MCA_LEGACY
-/* mapping of the first four bits of the second POS register */
-static unsigned short mca_iomap[] = {
- 0x270, 0x260, 0x250, 0x240, 0x230, 0x220, 0x210, 0x200,
- 0x370, 0x360, 0x350, 0x340, 0x330, 0x320, 0x310, 0x300
-};
-/* bits 5-7 of the second POS register */
-static char mca_irqmap[] = { 12, 9, 3, 4, 5, 10, 11, 15 };
-#endif
-
-/*
- * Prototypes for Linux interface
- */
-
-static int eexp_open(struct net_device *dev);
-static int eexp_close(struct net_device *dev);
-static void eexp_timeout(struct net_device *dev);
-static netdev_tx_t eexp_xmit(struct sk_buff *buf,
- struct net_device *dev);
-
-static irqreturn_t eexp_irq(int irq, void *dev_addr);
-static void eexp_set_multicast(struct net_device *dev);
-
-/*
- * Prototypes for hardware access functions
- */
-
-static void eexp_hw_rx_pio(struct net_device *dev);
-static void eexp_hw_tx_pio(struct net_device *dev, unsigned short *buf,
- unsigned short len);
-static int eexp_hw_probe(struct net_device *dev,unsigned short ioaddr);
-static unsigned short eexp_hw_readeeprom(unsigned short ioaddr,
- unsigned char location);
-
-static unsigned short eexp_hw_lasttxstat(struct net_device *dev);
-static void eexp_hw_txrestart(struct net_device *dev);
-
-static void eexp_hw_txinit (struct net_device *dev);
-static void eexp_hw_rxinit (struct net_device *dev);
-
-static void eexp_hw_init586 (struct net_device *dev);
-static void eexp_setup_filter (struct net_device *dev);
-
-static char *eexp_ifmap[]={"AUI", "BNC", "RJ45"};
-enum eexp_iftype {AUI=0, BNC=1, TPE=2};
-
-#define STARTED_RU 2
-#define STARTED_CU 1
-
-/*
- * Primitive hardware access functions.
- */
-
-static inline unsigned short scb_status(struct net_device *dev)
-{
- return inw(dev->base_addr + 0xc008);
-}
-
-static inline unsigned short scb_rdcmd(struct net_device *dev)
-{
- return inw(dev->base_addr + 0xc00a);
-}
-
-static inline void scb_command(struct net_device *dev, unsigned short cmd)
-{
- outw(cmd, dev->base_addr + 0xc00a);
-}
-
-static inline void scb_wrcbl(struct net_device *dev, unsigned short val)
-{
- outw(val, dev->base_addr + 0xc00c);
-}
-
-static inline void scb_wrrfa(struct net_device *dev, unsigned short val)
-{
- outw(val, dev->base_addr + 0xc00e);
-}
-
-static inline void set_loopback(struct net_device *dev)
-{
- outb(inb(dev->base_addr + Config) | 2, dev->base_addr + Config);
-}
-
-static inline void clear_loopback(struct net_device *dev)
-{
- outb(inb(dev->base_addr + Config) & ~2, dev->base_addr + Config);
-}
-
-static inline unsigned short int SHADOW(short int addr)
-{
- addr &= 0x1f;
- if (addr > 0xf) addr += 0x3ff0;
- return addr + 0x4000;
-}
-
-/*
- * Linux interface
- */
-
-/*
- * checks for presence of EtherExpress card
- */
-
-static int __init do_express_probe(struct net_device *dev)
-{
- unsigned short *port;
- static unsigned short ports[] = { 0x240,0x300,0x310,0x270,0x320,0x340,0 };
- unsigned short ioaddr = dev->base_addr;
- int dev_irq = dev->irq;
- int err;
-
- dev->if_port = 0xff; /* not set */
-
-#ifdef CONFIG_MCA_LEGACY
- if (MCA_bus) {
- int slot = 0;
-
- /*
- * Only find one card at a time. Subsequent calls
- * will find others, however, proper multicard MCA
- * probing and setup can't be done with the
- * old-style Space.c init routines. -- ASF
- */
- while (slot != MCA_NOTFOUND) {
- int pos0, pos1;
-
- slot = mca_find_unused_adapter(0x628B, slot);
- if (slot == MCA_NOTFOUND)
- break;
-
- pos0 = mca_read_stored_pos(slot, 2);
- pos1 = mca_read_stored_pos(slot, 3);
- ioaddr = mca_iomap[pos1&0xf];
-
- dev->irq = mca_irqmap[(pos1>>4)&0x7];
-
- /*
- * XXX: Transceiver selection is done
- * differently on the MCA version.
- * How to get it to select something
- * other than external/AUI is currently
- * unknown. This code is just for looks. -- ASF
- */
- if ((pos0 & 0x7) == 0x1)
- dev->if_port = AUI;
- else if ((pos0 & 0x7) == 0x5) {
- if (pos1 & 0x80)
- dev->if_port = BNC;
- else
- dev->if_port = TPE;
- }
-
- mca_set_adapter_name(slot, "Intel EtherExpress 16 MCA");
- mca_set_adapter_procfn(slot, NULL, dev);
- mca_mark_as_used(slot);
-
- break;
- }
- }
-#endif
- if (ioaddr&0xfe00) {
- if (!request_region(ioaddr, EEXP_IO_EXTENT, "EtherExpress"))
- return -EBUSY;
- err = eexp_hw_probe(dev,ioaddr);
- release_region(ioaddr, EEXP_IO_EXTENT);
- return err;
- } else if (ioaddr)
- return -ENXIO;
-
- for (port=&ports[0] ; *port ; port++ )
- {
- unsigned short sum = 0;
- int i;
- if (!request_region(*port, EEXP_IO_EXTENT, "EtherExpress"))
- continue;
- for ( i=0 ; i<4 ; i++ )
- {
- unsigned short t;
- t = inb(*port + ID_PORT);
- sum |= (t>>4) << ((t & 0x03)<<2);
- }
- if (sum==0xbaba && !eexp_hw_probe(dev,*port)) {
- release_region(*port, EEXP_IO_EXTENT);
- return 0;
- }
- release_region(*port, EEXP_IO_EXTENT);
- dev->irq = dev_irq;
- }
- return -ENODEV;
-}
-
-#ifndef MODULE
-struct net_device * __init express_probe(int unit)
-{
- struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
- int err;
-
- if (!dev)
- return ERR_PTR(-ENOMEM);
-
- sprintf(dev->name, "eth%d", unit);
- netdev_boot_setup_check(dev);
-
- err = do_express_probe(dev);
- if (!err)
- return dev;
- free_netdev(dev);
- return ERR_PTR(err);
-}
-#endif
-
-/*
- * open and initialize the adapter, ready for use
- */
-
-static int eexp_open(struct net_device *dev)
-{
- int ret;
- unsigned short ioaddr = dev->base_addr;
- struct net_local *lp = netdev_priv(dev);
-
-#if NET_DEBUG > 6
- printk(KERN_DEBUG "%s: eexp_open()\n", dev->name);
-#endif
-
- if (!dev->irq || !irqrmap[dev->irq])
- return -ENXIO;
-
- ret = request_irq(dev->irq, eexp_irq, 0, dev->name, dev);
- if (ret)
- return ret;
-
- if (!request_region(ioaddr, EEXP_IO_EXTENT, "EtherExpress")) {
- printk(KERN_WARNING "EtherExpress io port %x, is busy.\n"
- , ioaddr);
- goto err_out1;
- }
- if (!request_region(ioaddr+0x4000, EEXP_IO_EXTENT, "EtherExpress shadow")) {
- printk(KERN_WARNING "EtherExpress io port %x, is busy.\n"
- , ioaddr+0x4000);
- goto err_out2;
- }
- if (!request_region(ioaddr+0x8000, EEXP_IO_EXTENT, "EtherExpress shadow")) {
- printk(KERN_WARNING "EtherExpress io port %x, is busy.\n"
- , ioaddr+0x8000);
- goto err_out3;
- }
- if (!request_region(ioaddr+0xc000, EEXP_IO_EXTENT, "EtherExpress shadow")) {
- printk(KERN_WARNING "EtherExpress io port %x, is busy.\n"
- , ioaddr+0xc000);
- goto err_out4;
- }
-
- if (lp->width) {
- printk("%s: forcing ASIC to 8-bit mode\n", dev->name);
- outb(inb(dev->base_addr+Config)&~4, dev->base_addr+Config);
- }
-
- eexp_hw_init586(dev);
- netif_start_queue(dev);
-#if NET_DEBUG > 6
- printk(KERN_DEBUG "%s: leaving eexp_open()\n", dev->name);
-#endif
- return 0;
-
- err_out4:
- release_region(ioaddr+0x8000, EEXP_IO_EXTENT);
- err_out3:
- release_region(ioaddr+0x4000, EEXP_IO_EXTENT);
- err_out2:
- release_region(ioaddr, EEXP_IO_EXTENT);
- err_out1:
- free_irq(dev->irq, dev);
- return -EBUSY;
-}
-
-/*
- * close and disable the interface, leaving the 586 in reset.
- */
-
-static int eexp_close(struct net_device *dev)
-{
- unsigned short ioaddr = dev->base_addr;
- struct net_local *lp = netdev_priv(dev);
-
- int irq = dev->irq;
-
- netif_stop_queue(dev);
-
- outb(SIRQ_dis|irqrmap[irq],ioaddr+SET_IRQ);
- lp->started = 0;
- scb_command(dev, SCB_CUsuspend|SCB_RUsuspend);
- outb(0,ioaddr+SIGNAL_CA);
- free_irq(irq,dev);
- outb(i586_RST,ioaddr+EEPROM_Ctrl);
- release_region(ioaddr, EEXP_IO_EXTENT);
- release_region(ioaddr+0x4000, 16);
- release_region(ioaddr+0x8000, 16);
- release_region(ioaddr+0xc000, 16);
-
- return 0;
-}
-
-/*
- * This gets called when a higher level thinks we are broken. Check that
- * nothing has become jammed in the CU.
- */
-
-static void unstick_cu(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
- unsigned short ioaddr = dev->base_addr;
-
- if (lp->started)
- {
- if (time_after(jiffies, dev_trans_start(dev) + HZ/2))
- {
- if (lp->tx_link==lp->last_tx_restart)
- {
- unsigned short boguscount=200,rsst;
- printk(KERN_WARNING "%s: Retransmit timed out, status %04x, resetting...\n",
- dev->name, scb_status(dev));
- eexp_hw_txinit(dev);
- lp->last_tx_restart = 0;
- scb_wrcbl(dev, lp->tx_link);
- scb_command(dev, SCB_CUstart);
- outb(0,ioaddr+SIGNAL_CA);
- while (!SCB_complete(rsst=scb_status(dev)))
- {
- if (!--boguscount)
- {
- boguscount=200;
- printk(KERN_WARNING "%s: Reset timed out status %04x, retrying...\n",
- dev->name,rsst);
- scb_wrcbl(dev, lp->tx_link);
- scb_command(dev, SCB_CUstart);
- outb(0,ioaddr+SIGNAL_CA);
- }
- }
- netif_wake_queue(dev);
- }
- else
- {
- unsigned short status = scb_status(dev);
- if (SCB_CUdead(status))
- {
- unsigned short txstatus = eexp_hw_lasttxstat(dev);
- printk(KERN_WARNING "%s: Transmit timed out, CU not active status %04x %04x, restarting...\n",
- dev->name, status, txstatus);
- eexp_hw_txrestart(dev);
- }
- else
- {
- unsigned short txstatus = eexp_hw_lasttxstat(dev);
- if (netif_queue_stopped(dev) && !txstatus)
- {
- printk(KERN_WARNING "%s: CU wedged, status %04x %04x, resetting...\n",
- dev->name,status,txstatus);
- eexp_hw_init586(dev);
- netif_wake_queue(dev);
- }
- else
- {
- printk(KERN_WARNING "%s: transmit timed out\n", dev->name);
- }
- }
- }
- }
- }
- else
- {
- if (time_after(jiffies, lp->init_time + 10))
- {
- unsigned short status = scb_status(dev);
- printk(KERN_WARNING "%s: i82586 startup timed out, status %04x, resetting...\n",
- dev->name, status);
- eexp_hw_init586(dev);
- netif_wake_queue(dev);
- }
- }
-}
-
-static void eexp_timeout(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
-#ifdef CONFIG_SMP
- unsigned long flags;
-#endif
- int status;
-
- disable_irq(dev->irq);
-
- /*
- * Best would be to use synchronize_irq(); spin_lock() here
- * lets make it work first..
- */
-
-#ifdef CONFIG_SMP
- spin_lock_irqsave(&lp->lock, flags);
-#endif
-
- status = scb_status(dev);
- unstick_cu(dev);
- printk(KERN_INFO "%s: transmit timed out, %s?\n", dev->name,
- (SCB_complete(status)?"lost interrupt":
- "board on fire"));
- dev->stats.tx_errors++;
- lp->last_tx = jiffies;
- if (!SCB_complete(status)) {
- scb_command(dev, SCB_CUabort);
- outb(0,dev->base_addr+SIGNAL_CA);
- }
- netif_wake_queue(dev);
-#ifdef CONFIG_SMP
- spin_unlock_irqrestore(&lp->lock, flags);
-#endif
-}
-
-/*
- * Called to transmit a packet, or to allow us to right ourselves
- * if the kernel thinks we've died.
- */
-static netdev_tx_t eexp_xmit(struct sk_buff *buf, struct net_device *dev)
-{
- short length = buf->len;
-#ifdef CONFIG_SMP
- struct net_local *lp = netdev_priv(dev);
- unsigned long flags;
-#endif
-
-#if NET_DEBUG > 6
- printk(KERN_DEBUG "%s: eexp_xmit()\n", dev->name);
-#endif
-
- if (buf->len < ETH_ZLEN) {
- if (skb_padto(buf, ETH_ZLEN))
- return NETDEV_TX_OK;
- length = ETH_ZLEN;
- }
-
- disable_irq(dev->irq);
-
- /*
- * Best would be to use synchronize_irq(); spin_lock() here
- * lets make it work first..
- */
-
-#ifdef CONFIG_SMP
- spin_lock_irqsave(&lp->lock, flags);
-#endif
-
- {
- unsigned short *data = (unsigned short *)buf->data;
-
- dev->stats.tx_bytes += length;
-
- eexp_hw_tx_pio(dev,data,length);
- }
- dev_kfree_skb(buf);
-#ifdef CONFIG_SMP
- spin_unlock_irqrestore(&lp->lock, flags);
-#endif
- enable_irq(dev->irq);
- return NETDEV_TX_OK;
-}
-
-/*
- * Handle an EtherExpress interrupt
- * If we've finished initializing, start the RU and CU up.
- * If we've already started, reap tx buffers, handle any received packets,
- * check to make sure we've not become wedged.
- */
-
-static unsigned short eexp_start_irq(struct net_device *dev,
- unsigned short status)
-{
- unsigned short ack_cmd = SCB_ack(status);
- struct net_local *lp = netdev_priv(dev);
- unsigned short ioaddr = dev->base_addr;
- if ((dev->flags & IFF_UP) && !(lp->started & STARTED_CU)) {
- short diag_status, tdr_status;
- while (SCB_CUstat(status)==2)
- status = scb_status(dev);
-#if NET_DEBUG > 4
- printk("%s: CU went non-active (status %04x)\n",
- dev->name, status);
-#endif
-
- outw(CONF_DIAG_RESULT & ~31, ioaddr + SM_PTR);
- diag_status = inw(ioaddr + SHADOW(CONF_DIAG_RESULT));
- if (diag_status & 1<<11) {
- printk(KERN_WARNING "%s: 82586 failed self-test\n",
- dev->name);
- } else if (!(diag_status & 1<<13)) {
- printk(KERN_WARNING "%s: 82586 self-test failed to complete\n", dev->name);
- }
-
- outw(CONF_TDR_RESULT & ~31, ioaddr + SM_PTR);
- tdr_status = inw(ioaddr + SHADOW(CONF_TDR_RESULT));
- if (tdr_status & (TDR_SHORT|TDR_OPEN)) {
- printk(KERN_WARNING "%s: TDR reports cable %s at %d tick%s\n", dev->name, (tdr_status & TDR_SHORT)?"short":"broken", tdr_status & TDR_TIME, ((tdr_status & TDR_TIME) != 1) ? "s" : "");
- }
- else if (tdr_status & TDR_XCVRPROBLEM) {
- printk(KERN_WARNING "%s: TDR reports transceiver problem\n", dev->name);
- }
- else if (tdr_status & TDR_LINKOK) {
-#if NET_DEBUG > 4
- printk(KERN_DEBUG "%s: TDR reports link OK\n", dev->name);
-#endif
- } else {
- printk("%s: TDR is ga-ga (status %04x)\n", dev->name,
- tdr_status);
- }
-
- lp->started |= STARTED_CU;
- scb_wrcbl(dev, lp->tx_link);
- /* if the RU isn't running, start it now */
- if (!(lp->started & STARTED_RU)) {
- ack_cmd |= SCB_RUstart;
- scb_wrrfa(dev, lp->rx_buf_start);
- lp->rx_ptr = lp->rx_buf_start;
- lp->started |= STARTED_RU;
- }
- ack_cmd |= SCB_CUstart | 0x2000;
- }
-
- if ((dev->flags & IFF_UP) && !(lp->started & STARTED_RU) && SCB_RUstat(status)==4)
- lp->started|=STARTED_RU;
-
- return ack_cmd;
-}
-
-static void eexp_cmd_clear(struct net_device *dev)
-{
- unsigned long int oldtime = jiffies;
- while (scb_rdcmd(dev) && (time_before(jiffies, oldtime + 10)));
- if (scb_rdcmd(dev)) {
- printk("%s: command didn't clear\n", dev->name);
- }
-}
-
-static irqreturn_t eexp_irq(int dummy, void *dev_info)
-{
- struct net_device *dev = dev_info;
- struct net_local *lp;
- unsigned short ioaddr,status,ack_cmd;
- unsigned short old_read_ptr, old_write_ptr;
-
- lp = netdev_priv(dev);
- ioaddr = dev->base_addr;
-
- spin_lock(&lp->lock);
-
- old_read_ptr = inw(ioaddr+READ_PTR);
- old_write_ptr = inw(ioaddr+WRITE_PTR);
-
- outb(SIRQ_dis|irqrmap[dev->irq], ioaddr+SET_IRQ);
-
- status = scb_status(dev);
-
-#if NET_DEBUG > 4
- printk(KERN_DEBUG "%s: interrupt (status %x)\n", dev->name, status);
-#endif
-
- if (lp->started == (STARTED_CU | STARTED_RU)) {
-
- do {
- eexp_cmd_clear(dev);
-
- ack_cmd = SCB_ack(status);
- scb_command(dev, ack_cmd);
- outb(0,ioaddr+SIGNAL_CA);
-
- eexp_cmd_clear(dev);
-
- if (SCB_complete(status)) {
- if (!eexp_hw_lasttxstat(dev)) {
- printk("%s: tx interrupt but no status\n", dev->name);
- }
- }
-
- if (SCB_rxdframe(status))
- eexp_hw_rx_pio(dev);
-
- status = scb_status(dev);
- } while (status & 0xc000);
-
- if (SCB_RUdead(status))
- {
- printk(KERN_WARNING "%s: RU stopped: status %04x\n",
- dev->name,status);
-#if 0
- printk(KERN_WARNING "%s: cur_rfd=%04x, cur_rbd=%04x\n", dev->name, lp->cur_rfd, lp->cur_rbd);
- outw(lp->cur_rfd, ioaddr+READ_PTR);
- printk(KERN_WARNING "%s: [%04x]\n", dev->name, inw(ioaddr+DATAPORT));
- outw(lp->cur_rfd+6, ioaddr+READ_PTR);
- printk(KERN_WARNING "%s: rbd is %04x\n", dev->name, rbd= inw(ioaddr+DATAPORT));
- outw(rbd, ioaddr+READ_PTR);
- printk(KERN_WARNING "%s: [%04x %04x] ", dev->name, inw(ioaddr+DATAPORT), inw(ioaddr+DATAPORT));
- outw(rbd+8, ioaddr+READ_PTR);
- printk("[%04x]\n", inw(ioaddr+DATAPORT));
-#endif
- dev->stats.rx_errors++;
-#if 1
- eexp_hw_rxinit(dev);
-#else
- lp->cur_rfd = lp->first_rfd;
-#endif
- scb_wrrfa(dev, lp->rx_buf_start);
- scb_command(dev, SCB_RUstart);
- outb(0,ioaddr+SIGNAL_CA);
- }
- } else {
- if (status & 0x8000)
- ack_cmd = eexp_start_irq(dev, status);
- else
- ack_cmd = SCB_ack(status);
- scb_command(dev, ack_cmd);
- outb(0,ioaddr+SIGNAL_CA);
- }
-
- eexp_cmd_clear(dev);
-
- outb(SIRQ_en|irqrmap[dev->irq], ioaddr+SET_IRQ);
-
-#if NET_DEBUG > 6
- printk("%s: leaving eexp_irq()\n", dev->name);
-#endif
- outw(old_read_ptr, ioaddr+READ_PTR);
- outw(old_write_ptr, ioaddr+WRITE_PTR);
-
- spin_unlock(&lp->lock);
- return IRQ_HANDLED;
-}
-
-/*
- * Hardware access functions
- */
-
-/*
- * Set the cable type to use.
- */
-
-static void eexp_hw_set_interface(struct net_device *dev)
-{
- unsigned char oldval = inb(dev->base_addr + 0x300e);
- oldval &= ~0x82;
- switch (dev->if_port) {
- case TPE:
- oldval |= 0x2;
- case BNC:
- oldval |= 0x80;
- break;
- }
- outb(oldval, dev->base_addr+0x300e);
- mdelay(20);
-}
-
-/*
- * Check all the receive buffers, and hand any received packets
- * to the upper levels. Basic sanity check on each frame
- * descriptor, though we don't bother trying to fix broken ones.
- */
-
-static void eexp_hw_rx_pio(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
- unsigned short rx_block = lp->rx_ptr;
- unsigned short boguscount = lp->num_rx_bufs;
- unsigned short ioaddr = dev->base_addr;
- unsigned short status;
-
-#if NET_DEBUG > 6
- printk(KERN_DEBUG "%s: eexp_hw_rx()\n", dev->name);
-#endif
-
- do {
- unsigned short rfd_cmd, rx_next, pbuf, pkt_len;
-
- outw(rx_block, ioaddr + READ_PTR);
- status = inw(ioaddr + DATAPORT);
-
- if (FD_Done(status))
- {
- rfd_cmd = inw(ioaddr + DATAPORT);
- rx_next = inw(ioaddr + DATAPORT);
- pbuf = inw(ioaddr + DATAPORT);
-
- outw(pbuf, ioaddr + READ_PTR);
- pkt_len = inw(ioaddr + DATAPORT);
-
- if (rfd_cmd!=0x0000)
- {
- printk(KERN_WARNING "%s: rfd_cmd not zero:0x%04x\n",
- dev->name, rfd_cmd);
- continue;
- }
- else if (pbuf!=rx_block+0x16)
- {
- printk(KERN_WARNING "%s: rfd and rbd out of sync 0x%04x 0x%04x\n",
- dev->name, rx_block+0x16, pbuf);
- continue;
- }
- else if ((pkt_len & 0xc000)!=0xc000)
- {
- printk(KERN_WARNING "%s: EOF or F not set on received buffer (%04x)\n",
- dev->name, pkt_len & 0xc000);
- continue;
- }
- else if (!FD_OK(status))
- {
- dev->stats.rx_errors++;
- if (FD_CRC(status))
- dev->stats.rx_crc_errors++;
- if (FD_Align(status))
- dev->stats.rx_frame_errors++;
- if (FD_Resrc(status))
- dev->stats.rx_fifo_errors++;
- if (FD_DMA(status))
- dev->stats.rx_over_errors++;
- if (FD_Short(status))
- dev->stats.rx_length_errors++;
- }
- else
- {
- struct sk_buff *skb;
- pkt_len &= 0x3fff;
- skb = dev_alloc_skb(pkt_len+16);
- if (skb == NULL)
- {
- printk(KERN_WARNING "%s: Memory squeeze, dropping packet\n",dev->name);
- dev->stats.rx_dropped++;
- break;
- }
- skb_reserve(skb, 2);
- outw(pbuf+10, ioaddr+READ_PTR);
- insw(ioaddr+DATAPORT, skb_put(skb,pkt_len),(pkt_len+1)>>1);
- skb->protocol = eth_type_trans(skb,dev);
- netif_rx(skb);
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += pkt_len;
- }
- outw(rx_block, ioaddr+WRITE_PTR);
- outw(0, ioaddr+DATAPORT);
- outw(0, ioaddr+DATAPORT);
- rx_block = rx_next;
- }
- } while (FD_Done(status) && boguscount--);
- lp->rx_ptr = rx_block;
-}
-
-/*
- * Hand a packet to the card for transmission
- * If we get here, we MUST have already checked
- * to make sure there is room in the transmit
- * buffer region.
- */
-
-static void eexp_hw_tx_pio(struct net_device *dev, unsigned short *buf,
- unsigned short len)
-{
- struct net_local *lp = netdev_priv(dev);
- unsigned short ioaddr = dev->base_addr;
-
- if (LOCKUP16 || lp->width) {
- /* Stop the CU so that there is no chance that it
- jumps off to a bogus address while we are writing the
- pointer to the next transmit packet in 8-bit mode --
- this eliminates the "CU wedged" errors in 8-bit mode.
- (Zoltan Szilagyi 10-12-96) */
- scb_command(dev, SCB_CUsuspend);
- outw(0xFFFF, ioaddr+SIGNAL_CA);
- }
-
- outw(lp->tx_head, ioaddr + WRITE_PTR);
-
- outw(0x0000, ioaddr + DATAPORT);
- outw(Cmd_INT|Cmd_Xmit, ioaddr + DATAPORT);
- outw(lp->tx_head+0x08, ioaddr + DATAPORT);
- outw(lp->tx_head+0x0e, ioaddr + DATAPORT);
-
- outw(0x0000, ioaddr + DATAPORT);
- outw(0x0000, ioaddr + DATAPORT);
- outw(lp->tx_head+0x08, ioaddr + DATAPORT);
-
- outw(0x8000|len, ioaddr + DATAPORT);
- outw(-1, ioaddr + DATAPORT);
- outw(lp->tx_head+0x16, ioaddr + DATAPORT);
- outw(0, ioaddr + DATAPORT);
-
- outsw(ioaddr + DATAPORT, buf, (len+1)>>1);
-
- outw(lp->tx_tail+0xc, ioaddr + WRITE_PTR);
- outw(lp->tx_head, ioaddr + DATAPORT);
-
- dev->trans_start = jiffies;
- lp->tx_tail = lp->tx_head;
- if (lp->tx_head==TX_BUF_START+((lp->num_tx_bufs-1)*TX_BUF_SIZE))
- lp->tx_head = TX_BUF_START;
- else
- lp->tx_head += TX_BUF_SIZE;
- if (lp->tx_head != lp->tx_reap)
- netif_wake_queue(dev);
-
- if (LOCKUP16 || lp->width) {
- /* Restart the CU so that the packet can actually
- be transmitted. (Zoltan Szilagyi 10-12-96) */
- scb_command(dev, SCB_CUresume);
- outw(0xFFFF, ioaddr+SIGNAL_CA);
- }
-
- dev->stats.tx_packets++;
- lp->last_tx = jiffies;
-}
-
-static const struct net_device_ops eexp_netdev_ops = {
- .ndo_open = eexp_open,
- .ndo_stop = eexp_close,
- .ndo_start_xmit = eexp_xmit,
- .ndo_set_multicast_list = eexp_set_multicast,
- .ndo_tx_timeout = eexp_timeout,
- .ndo_change_mtu = eth_change_mtu,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-/*
- * Sanity check the suspected EtherExpress card
- * Read hardware address, reset card, size memory and initialize buffer
- * memory pointers. These are held in netdev_priv(), in case someone has more
- * than one card in a machine.
- */
-
-static int __init eexp_hw_probe(struct net_device *dev, unsigned short ioaddr)
-{
- unsigned short hw_addr[3];
- unsigned char buswidth;
- unsigned int memory_size;
- int i;
- unsigned short xsum = 0;
- struct net_local *lp = netdev_priv(dev);
-
- printk("%s: EtherExpress 16 at %#x ",dev->name,ioaddr);
-
- outb(ASIC_RST, ioaddr+EEPROM_Ctrl);
- outb(0, ioaddr+EEPROM_Ctrl);
- udelay(500);
- outb(i586_RST, ioaddr+EEPROM_Ctrl);
-
- hw_addr[0] = eexp_hw_readeeprom(ioaddr,2);
- hw_addr[1] = eexp_hw_readeeprom(ioaddr,3);
- hw_addr[2] = eexp_hw_readeeprom(ioaddr,4);
-
- /* Standard Address or Compaq LTE Address */
- if (!((hw_addr[2]==0x00aa && ((hw_addr[1] & 0xff00)==0x0000)) ||
- (hw_addr[2]==0x0080 && ((hw_addr[1] & 0xff00)==0x5F00))))
- {
- printk(" rejected: invalid address %04x%04x%04x\n",
- hw_addr[2],hw_addr[1],hw_addr[0]);
- return -ENODEV;
- }
-
- /* Calculate the EEPROM checksum. Carry on anyway if it's bad,
- * though.
- */
- for (i = 0; i < 64; i++)
- xsum += eexp_hw_readeeprom(ioaddr, i);
- if (xsum != 0xbaba)
- printk(" (bad EEPROM xsum 0x%02x)", xsum);
-
- dev->base_addr = ioaddr;
- for ( i=0 ; i<6 ; i++ )
- dev->dev_addr[i] = ((unsigned char *)hw_addr)[5-i];
-
- {
- static const char irqmap[] = { 0, 9, 3, 4, 5, 10, 11, 0 };
- unsigned short setupval = eexp_hw_readeeprom(ioaddr,0);
-
- /* Use the IRQ from EEPROM if none was given */
- if (!dev->irq)
- dev->irq = irqmap[setupval>>13];
-
- if (dev->if_port == 0xff) {
- dev->if_port = !(setupval & 0x1000) ? AUI :
- eexp_hw_readeeprom(ioaddr,5) & 0x1 ? TPE : BNC;
- }
-
- buswidth = !((setupval & 0x400) >> 10);
- }
-
- memset(lp, 0, sizeof(struct net_local));
- spin_lock_init(&lp->lock);
-
- printk("(IRQ %d, %s connector, %d-bit bus", dev->irq,
- eexp_ifmap[dev->if_port], buswidth?8:16);
-
- if (!request_region(dev->base_addr + 0x300e, 1, "EtherExpress"))
- return -EBUSY;
-
- eexp_hw_set_interface(dev);
-
- release_region(dev->base_addr + 0x300e, 1);
-
- /* Find out how much RAM we have on the card */
- outw(0, dev->base_addr + WRITE_PTR);
- for (i = 0; i < 32768; i++)
- outw(0, dev->base_addr + DATAPORT);
-
- for (memory_size = 0; memory_size < 64; memory_size++)
- {
- outw(memory_size<<10, dev->base_addr + READ_PTR);
- if (inw(dev->base_addr+DATAPORT))
- break;
- outw(memory_size<<10, dev->base_addr + WRITE_PTR);
- outw(memory_size | 0x5000, dev->base_addr+DATAPORT);
- outw(memory_size<<10, dev->base_addr + READ_PTR);
- if (inw(dev->base_addr+DATAPORT) != (memory_size | 0x5000))
- break;
- }
-
- /* Sort out the number of buffers. We may have 16, 32, 48 or 64k
- * of RAM to play with.
- */
- lp->num_tx_bufs = 4;
- lp->rx_buf_end = 0x3ff6;
- switch (memory_size)
- {
- case 64:
- lp->rx_buf_end += 0x4000;
- case 48:
- lp->num_tx_bufs += 4;
- lp->rx_buf_end += 0x4000;
- case 32:
- lp->rx_buf_end += 0x4000;
- case 16:
- printk(", %dk RAM)\n", memory_size);
- break;
- default:
- printk(") bad memory size (%dk).\n", memory_size);
- return -ENODEV;
- break;
- }
-
- lp->rx_buf_start = TX_BUF_START + (lp->num_tx_bufs*TX_BUF_SIZE);
- lp->width = buswidth;
-
- dev->netdev_ops = &eexp_netdev_ops;
- dev->watchdog_timeo = 2*HZ;
-
- return register_netdev(dev);
-}
-
-/*
- * Read a word from the EtherExpress on-board serial EEPROM.
- * The EEPROM contains 64 words of 16 bits.
- */
-static unsigned short __init eexp_hw_readeeprom(unsigned short ioaddr,
- unsigned char location)
-{
- unsigned short cmd = 0x180|(location&0x7f);
- unsigned short rval = 0,wval = EC_CS|i586_RST;
- int i;
-
- outb(EC_CS|i586_RST,ioaddr+EEPROM_Ctrl);
- for (i=0x100 ; i ; i>>=1 )
- {
- if (cmd&i)
- wval |= EC_Wr;
- else
- wval &= ~EC_Wr;
-
- outb(wval,ioaddr+EEPROM_Ctrl);
- outb(wval|EC_Clk,ioaddr+EEPROM_Ctrl);
- eeprom_delay();
- outb(wval,ioaddr+EEPROM_Ctrl);
- eeprom_delay();
- }
- wval &= ~EC_Wr;
- outb(wval,ioaddr+EEPROM_Ctrl);
- for (i=0x8000 ; i ; i>>=1 )
- {
- outb(wval|EC_Clk,ioaddr+EEPROM_Ctrl);
- eeprom_delay();
- if (inb(ioaddr+EEPROM_Ctrl)&EC_Rd)
- rval |= i;
- outb(wval,ioaddr+EEPROM_Ctrl);
- eeprom_delay();
- }
- wval &= ~EC_CS;
- outb(wval|EC_Clk,ioaddr+EEPROM_Ctrl);
- eeprom_delay();
- outb(wval,ioaddr+EEPROM_Ctrl);
- eeprom_delay();
- return rval;
-}
-
-/*
- * Reap tx buffers and return last transmit status.
- * if ==0 then either:
- * a) we're not transmitting anything, so why are we here?
- * b) we've died.
- * otherwise, Stat_Busy(return) means we've still got some packets
- * to transmit, Stat_Done(return) means our buffers should be empty
- * again
- */
-
-static unsigned short eexp_hw_lasttxstat(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
- unsigned short tx_block = lp->tx_reap;
- unsigned short status;
-
- if (!netif_queue_stopped(dev) && lp->tx_head==lp->tx_reap)
- return 0x0000;
-
- do
- {
- outw(tx_block & ~31, dev->base_addr + SM_PTR);
- status = inw(dev->base_addr + SHADOW(tx_block));
- if (!Stat_Done(status))
- {
- lp->tx_link = tx_block;
- return status;
- }
- else
- {
- lp->last_tx_restart = 0;
- dev->stats.collisions += Stat_NoColl(status);
- if (!Stat_OK(status))
- {
- char *whatsup = NULL;
- dev->stats.tx_errors++;
- if (Stat_Abort(status))
- dev->stats.tx_aborted_errors++;
- if (Stat_TNoCar(status)) {
- whatsup = "aborted, no carrier";
- dev->stats.tx_carrier_errors++;
- }
- if (Stat_TNoCTS(status)) {
- whatsup = "aborted, lost CTS";
- dev->stats.tx_carrier_errors++;
- }
- if (Stat_TNoDMA(status)) {
- whatsup = "FIFO underran";
- dev->stats.tx_fifo_errors++;
- }
- if (Stat_TXColl(status)) {
- whatsup = "aborted, too many collisions";
- dev->stats.tx_aborted_errors++;
- }
- if (whatsup)
- printk(KERN_INFO "%s: transmit %s\n",
- dev->name, whatsup);
- }
- else
- dev->stats.tx_packets++;
- }
- if (tx_block == TX_BUF_START+((lp->num_tx_bufs-1)*TX_BUF_SIZE))
- lp->tx_reap = tx_block = TX_BUF_START;
- else
- lp->tx_reap = tx_block += TX_BUF_SIZE;
- netif_wake_queue(dev);
- }
- while (lp->tx_reap != lp->tx_head);
-
- lp->tx_link = lp->tx_tail + 0x08;
-
- return status;
-}
-
-/*
- * This should never happen. It is called when some higher routine detects
- * that the CU has stopped, to try to restart it from the last packet we knew
- * we were working on, or the idle loop if we had finished for the time.
- */
-
-static void eexp_hw_txrestart(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
- unsigned short ioaddr = dev->base_addr;
-
- lp->last_tx_restart = lp->tx_link;
- scb_wrcbl(dev, lp->tx_link);
- scb_command(dev, SCB_CUstart);
- outb(0,ioaddr+SIGNAL_CA);
-
- {
- unsigned short boguscount=50,failcount=5;
- while (!scb_status(dev))
- {
- if (!--boguscount)
- {
- if (--failcount)
- {
- printk(KERN_WARNING "%s: CU start timed out, status %04x, cmd %04x\n", dev->name, scb_status(dev), scb_rdcmd(dev));
- scb_wrcbl(dev, lp->tx_link);
- scb_command(dev, SCB_CUstart);
- outb(0,ioaddr+SIGNAL_CA);
- boguscount = 100;
- }
- else
- {
- printk(KERN_WARNING "%s: Failed to restart CU, resetting board...\n",dev->name);
- eexp_hw_init586(dev);
- netif_wake_queue(dev);
- return;
- }
- }
- }
- }
-}
-
-/*
- * Writes down the list of transmit buffers into card memory. Each
- * entry consists of an 82586 transmit command, followed by a jump
- * pointing to itself. When we want to transmit a packet, we write
- * the data into the appropriate transmit buffer and then modify the
- * preceding jump to point at the new transmit command. This means that
- * the 586 command unit is continuously active.
- */
-
-static void eexp_hw_txinit(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
- unsigned short tx_block = TX_BUF_START;
- unsigned short curtbuf;
- unsigned short ioaddr = dev->base_addr;
-
- for ( curtbuf=0 ; curtbuf<lp->num_tx_bufs ; curtbuf++ )
- {
- outw(tx_block, ioaddr + WRITE_PTR);
-
- outw(0x0000, ioaddr + DATAPORT);
- outw(Cmd_INT|Cmd_Xmit, ioaddr + DATAPORT);
- outw(tx_block+0x08, ioaddr + DATAPORT);
- outw(tx_block+0x0e, ioaddr + DATAPORT);
-
- outw(0x0000, ioaddr + DATAPORT);
- outw(0x0000, ioaddr + DATAPORT);
- outw(tx_block+0x08, ioaddr + DATAPORT);
-
- outw(0x8000, ioaddr + DATAPORT);
- outw(-1, ioaddr + DATAPORT);
- outw(tx_block+0x16, ioaddr + DATAPORT);
- outw(0x0000, ioaddr + DATAPORT);
-
- tx_block += TX_BUF_SIZE;
- }
- lp->tx_head = TX_BUF_START;
- lp->tx_reap = TX_BUF_START;
- lp->tx_tail = tx_block - TX_BUF_SIZE;
- lp->tx_link = lp->tx_tail + 0x08;
- lp->rx_buf_start = tx_block;
-
-}
-
-/*
- * Write the circular list of receive buffer descriptors to card memory.
- * The end of the list isn't marked, which means that the 82586 receive
- * unit will loop until buffers become available (this avoids it giving us
- * "out of resources" messages).
- */
-
-static void eexp_hw_rxinit(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
- unsigned short rx_block = lp->rx_buf_start;
- unsigned short ioaddr = dev->base_addr;
-
- lp->num_rx_bufs = 0;
- lp->rx_first = lp->rx_ptr = rx_block;
- do
- {
- lp->num_rx_bufs++;
-
- outw(rx_block, ioaddr + WRITE_PTR);
-
- outw(0, ioaddr + DATAPORT); outw(0, ioaddr+DATAPORT);
- outw(rx_block + RX_BUF_SIZE, ioaddr+DATAPORT);
- outw(0xffff, ioaddr+DATAPORT);
-
- outw(0x0000, ioaddr+DATAPORT);
- outw(0xdead, ioaddr+DATAPORT);
- outw(0xdead, ioaddr+DATAPORT);
- outw(0xdead, ioaddr+DATAPORT);
- outw(0xdead, ioaddr+DATAPORT);
- outw(0xdead, ioaddr+DATAPORT);
- outw(0xdead, ioaddr+DATAPORT);
-
- outw(0x0000, ioaddr+DATAPORT);
- outw(rx_block + RX_BUF_SIZE + 0x16, ioaddr+DATAPORT);
- outw(rx_block + 0x20, ioaddr+DATAPORT);
- outw(0, ioaddr+DATAPORT);
- outw(RX_BUF_SIZE-0x20, ioaddr+DATAPORT);
-
- lp->rx_last = rx_block;
- rx_block += RX_BUF_SIZE;
- } while (rx_block <= lp->rx_buf_end-RX_BUF_SIZE);
-
-
- /* Make first Rx frame descriptor point to first Rx buffer
- descriptor */
- outw(lp->rx_first + 6, ioaddr+WRITE_PTR);
- outw(lp->rx_first + 0x16, ioaddr+DATAPORT);
-
- /* Close Rx frame descriptor ring */
- outw(lp->rx_last + 4, ioaddr+WRITE_PTR);
- outw(lp->rx_first, ioaddr+DATAPORT);
-
- /* Close Rx buffer descriptor ring */
- outw(lp->rx_last + 0x16 + 2, ioaddr+WRITE_PTR);
- outw(lp->rx_first + 0x16, ioaddr+DATAPORT);
-
-}
-
-/*
- * Un-reset the 586, and start the configuration sequence. We don't wait for
- * this to finish, but allow the interrupt handler to start the CU and RU for
- * us. We can't start the receive/transmission system up before we know that
- * the hardware is configured correctly.
- */
-
-static void eexp_hw_init586(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
- unsigned short ioaddr = dev->base_addr;
- int i;
-
-#if NET_DEBUG > 6
- printk("%s: eexp_hw_init586()\n", dev->name);
-#endif
-
- lp->started = 0;
-
- set_loopback(dev);
-
- outb(SIRQ_dis|irqrmap[dev->irq],ioaddr+SET_IRQ);
-
- /* Download the startup code */
- outw(lp->rx_buf_end & ~31, ioaddr + SM_PTR);
- outw(lp->width?0x0001:0x0000, ioaddr + 0x8006);
- outw(0x0000, ioaddr + 0x8008);
- outw(0x0000, ioaddr + 0x800a);
- outw(0x0000, ioaddr + 0x800c);
- outw(0x0000, ioaddr + 0x800e);
-
- for (i = 0; i < ARRAY_SIZE(start_code) * 2; i+=32) {
- int j;
- outw(i, ioaddr + SM_PTR);
- for (j = 0; j < 16 && (i+j)/2 < ARRAY_SIZE(start_code); j+=2)
- outw(start_code[(i+j)/2],
- ioaddr+0x4000+j);
- for (j = 0; j < 16 && (i+j+16)/2 < ARRAY_SIZE(start_code); j+=2)
- outw(start_code[(i+j+16)/2],
- ioaddr+0x8000+j);
- }
-
- /* Do we want promiscuous mode or multicast? */
- outw(CONF_PROMISC & ~31, ioaddr+SM_PTR);
- i = inw(ioaddr+SHADOW(CONF_PROMISC));
- outw((dev->flags & IFF_PROMISC)?(i|1):(i & ~1),
- ioaddr+SHADOW(CONF_PROMISC));
- lp->was_promisc = dev->flags & IFF_PROMISC;
-#if 0
- eexp_setup_filter(dev);
-#endif
-
- /* Write our hardware address */
- outw(CONF_HWADDR & ~31, ioaddr+SM_PTR);
- outw(((unsigned short *)dev->dev_addr)[0], ioaddr+SHADOW(CONF_HWADDR));
- outw(((unsigned short *)dev->dev_addr)[1],
- ioaddr+SHADOW(CONF_HWADDR+2));
- outw(((unsigned short *)dev->dev_addr)[2],
- ioaddr+SHADOW(CONF_HWADDR+4));
-
- eexp_hw_txinit(dev);
- eexp_hw_rxinit(dev);
-
- outb(0,ioaddr+EEPROM_Ctrl);
- mdelay(5);
-
- scb_command(dev, 0xf000);
- outb(0,ioaddr+SIGNAL_CA);
-
- outw(0, ioaddr+SM_PTR);
-
- {
- unsigned short rboguscount=50,rfailcount=5;
- while (inw(ioaddr+0x4000))
- {
- if (!--rboguscount)
- {
- printk(KERN_WARNING "%s: i82586 reset timed out, kicking...\n",
- dev->name);
- scb_command(dev, 0);
- outb(0,ioaddr+SIGNAL_CA);
- rboguscount = 100;
- if (!--rfailcount)
- {
- printk(KERN_WARNING "%s: i82586 not responding, giving up.\n",
- dev->name);
- return;
- }
- }
- }
- }
-
- scb_wrcbl(dev, CONF_LINK);
- scb_command(dev, 0xf000|SCB_CUstart);
- outb(0,ioaddr+SIGNAL_CA);
-
- {
- unsigned short iboguscount=50,ifailcount=5;
- while (!scb_status(dev))
- {
- if (!--iboguscount)
- {
- if (--ifailcount)
- {
- printk(KERN_WARNING "%s: i82586 initialization timed out, status %04x, cmd %04x\n",
- dev->name, scb_status(dev), scb_rdcmd(dev));
- scb_wrcbl(dev, CONF_LINK);
- scb_command(dev, 0xf000|SCB_CUstart);
- outb(0,ioaddr+SIGNAL_CA);
- iboguscount = 100;
- }
- else
- {
- printk(KERN_WARNING "%s: Failed to initialize i82586, giving up.\n",dev->name);
- return;
- }
- }
- }
- }
-
- clear_loopback(dev);
- outb(SIRQ_en|irqrmap[dev->irq],ioaddr+SET_IRQ);
-
- lp->init_time = jiffies;
-#if NET_DEBUG > 6
- printk("%s: leaving eexp_hw_init586()\n", dev->name);
-#endif
-}
-
-static void eexp_setup_filter(struct net_device *dev)
-{
- struct netdev_hw_addr *ha;
- unsigned short ioaddr = dev->base_addr;
- int count = netdev_mc_count(dev);
- int i;
- if (count > 8) {
- printk(KERN_INFO "%s: too many multicast addresses (%d)\n",
- dev->name, count);
- count = 8;
- }
-
- outw(CONF_NR_MULTICAST & ~31, ioaddr+SM_PTR);
- outw(6*count, ioaddr+SHADOW(CONF_NR_MULTICAST));
- i = 0;
- netdev_for_each_mc_addr(ha, dev) {
- unsigned short *data = (unsigned short *) ha->addr;
-
- if (i == count)
- break;
- outw((CONF_MULTICAST+(6*i)) & ~31, ioaddr+SM_PTR);
- outw(data[0], ioaddr+SHADOW(CONF_MULTICAST+(6*i)));
- outw((CONF_MULTICAST+(6*i)+2) & ~31, ioaddr+SM_PTR);
- outw(data[1], ioaddr+SHADOW(CONF_MULTICAST+(6*i)+2));
- outw((CONF_MULTICAST+(6*i)+4) & ~31, ioaddr+SM_PTR);
- outw(data[2], ioaddr+SHADOW(CONF_MULTICAST+(6*i)+4));
- i++;
- }
-}
-
-/*
- * Set or clear the multicast filter for this adaptor.
- */
-static void
-eexp_set_multicast(struct net_device *dev)
-{
- unsigned short ioaddr = dev->base_addr;
- struct net_local *lp = netdev_priv(dev);
- int kick = 0, i;
- if ((dev->flags & IFF_PROMISC) != lp->was_promisc) {
- outw(CONF_PROMISC & ~31, ioaddr+SM_PTR);
- i = inw(ioaddr+SHADOW(CONF_PROMISC));
- outw((dev->flags & IFF_PROMISC)?(i|1):(i & ~1),
- ioaddr+SHADOW(CONF_PROMISC));
- lp->was_promisc = dev->flags & IFF_PROMISC;
- kick = 1;
- }
- if (!(dev->flags & IFF_PROMISC)) {
- eexp_setup_filter(dev);
- if (lp->old_mc_count != netdev_mc_count(dev)) {
- kick = 1;
- lp->old_mc_count = netdev_mc_count(dev);
- }
- }
- if (kick) {
- unsigned long oj;
- scb_command(dev, SCB_CUsuspend);
- outb(0, ioaddr+SIGNAL_CA);
- outb(0, ioaddr+SIGNAL_CA);
-#if 0
- printk("%s: waiting for CU to go suspended\n", dev->name);
-#endif
- oj = jiffies;
- while ((SCB_CUstat(scb_status(dev)) == 2) &&
- (time_before(jiffies, oj + 2000)));
- if (SCB_CUstat(scb_status(dev)) == 2)
- printk("%s: warning, CU didn't stop\n", dev->name);
- lp->started &= ~(STARTED_CU);
- scb_wrcbl(dev, CONF_LINK);
- scb_command(dev, SCB_CUstart);
- outb(0, ioaddr+SIGNAL_CA);
- }
-}
-
-
-/*
- * MODULE stuff
- */
-
-#ifdef MODULE
-
-#define EEXP_MAX_CARDS 4 /* max number of cards to support */
-
-static struct net_device *dev_eexp[EEXP_MAX_CARDS];
-static int irq[EEXP_MAX_CARDS];
-static int io[EEXP_MAX_CARDS];
-
-module_param_array(io, int, NULL, 0);
-module_param_array(irq, int, NULL, 0);
-MODULE_PARM_DESC(io, "EtherExpress 16 I/O base address(es)");
-MODULE_PARM_DESC(irq, "EtherExpress 16 IRQ number(s)");
-MODULE_LICENSE("GPL");
-
-
-/* Ideally the user would give us io=, irq= for every card. If any parameters
- * are specified, we verify and then use them. If no parameters are given, we
- * autoprobe for one card only.
- */
-int __init init_module(void)
-{
- struct net_device *dev;
- int this_dev, found = 0;
-
- for (this_dev = 0; this_dev < EEXP_MAX_CARDS; this_dev++) {
- dev = alloc_etherdev(sizeof(struct net_local));
- dev->irq = irq[this_dev];
- dev->base_addr = io[this_dev];
- if (io[this_dev] == 0) {
- if (this_dev)
- break;
- printk(KERN_NOTICE "eexpress.c: Module autoprobe not recommended, give io=xx.\n");
- }
- if (do_express_probe(dev) == 0) {
- dev_eexp[this_dev] = dev;
- found++;
- continue;
- }
- printk(KERN_WARNING "eexpress.c: Failed to register card at 0x%x.\n", io[this_dev]);
- free_netdev(dev);
- break;
- }
- if (found)
- return 0;
- return -ENXIO;
-}
-
-void __exit cleanup_module(void)
-{
- int this_dev;
-
- for (this_dev = 0; this_dev < EEXP_MAX_CARDS; this_dev++) {
- struct net_device *dev = dev_eexp[this_dev];
- if (dev) {
- unregister_netdev(dev);
- free_netdev(dev);
- }
- }
-}
-#endif
-
-/*
- * Local Variables:
- * c-file-style: "linux"
- * tab-width: 8
- * End:
- */
+++ /dev/null
-/*
- * eexpress.h: Intel EtherExpress16 defines
- */
-
-/*
- * EtherExpress card register addresses
- * as offsets from the base IO region (dev->base_addr)
- */
-
-#define DATAPORT 0x0000
-#define WRITE_PTR 0x0002
-#define READ_PTR 0x0004
-#define SIGNAL_CA 0x0006
-#define SET_IRQ 0x0007
-#define SM_PTR 0x0008
-#define MEM_Dec 0x000a
-#define MEM_Ctrl 0x000b
-#define MEM_Page_Ctrl 0x000c
-#define Config 0x000d
-#define EEPROM_Ctrl 0x000e
-#define ID_PORT 0x000f
-#define MEM_ECtrl 0x000f
-
-/*
- * card register defines
- */
-
-/* SET_IRQ */
-#define SIRQ_en 0x08
-#define SIRQ_dis 0x00
-
-/* EEPROM_Ctrl */
-#define EC_Clk 0x01
-#define EC_CS 0x02
-#define EC_Wr 0x04
-#define EC_Rd 0x08
-#define ASIC_RST 0x40
-#define i586_RST 0x80
-
-#define eeprom_delay() { udelay(40); }
-
-/*
- * i82586 Memory Configuration
- */
-
-/* (System Configuration Pointer) System start up block, read after 586_RST */
-#define SCP_START 0xfff6
-
-/* Intermediate System Configuration Pointer */
-#define ISCP_START 0x0000
-
-/* System Command Block */
-#define SCB_START 0x0008
-
-/* Start of buffer region. Everything before this is used for control
- * structures and the CU configuration program. The memory layout is
- * determined in eexp_hw_probe(), once we know how much memory is
- * available on the card.
- */
-
-#define TX_BUF_START 0x0100
-
-#define TX_BUF_SIZE ((24+ETH_FRAME_LEN+31)&~0x1f)
-#define RX_BUF_SIZE ((32+ETH_FRAME_LEN+31)&~0x1f)
-
-/*
- * SCB defines
- */
-
-/* these functions take the SCB status word and test the relevant status bit */
-#define SCB_complete(s) (((s) & 0x8000) != 0)
-#define SCB_rxdframe(s) (((s) & 0x4000) != 0)
-#define SCB_CUdead(s) (((s) & 0x2000) != 0)
-#define SCB_RUdead(s) (((s) & 0x1000) != 0)
-#define SCB_ack(s) ((s) & 0xf000)
-
-/* Command unit status: 0=idle, 1=suspended, 2=active */
-#define SCB_CUstat(s) (((s)&0x0300)>>8)
-
-/* Receive unit status: 0=idle, 1=suspended, 2=out of resources, 4=ready */
-#define SCB_RUstat(s) (((s)&0x0070)>>4)
-
-/* SCB commands */
-#define SCB_CUnop 0x0000
-#define SCB_CUstart 0x0100
-#define SCB_CUresume 0x0200
-#define SCB_CUsuspend 0x0300
-#define SCB_CUabort 0x0400
-#define SCB_resetchip 0x0080
-
-#define SCB_RUnop 0x0000
-#define SCB_RUstart 0x0010
-#define SCB_RUresume 0x0020
-#define SCB_RUsuspend 0x0030
-#define SCB_RUabort 0x0040
-
-/*
- * Command block defines
- */
-
-#define Stat_Done(s) (((s) & 0x8000) != 0)
-#define Stat_Busy(s) (((s) & 0x4000) != 0)
-#define Stat_OK(s) (((s) & 0x2000) != 0)
-#define Stat_Abort(s) (((s) & 0x1000) != 0)
-#define Stat_STFail (((s) & 0x0800) != 0)
-#define Stat_TNoCar(s) (((s) & 0x0400) != 0)
-#define Stat_TNoCTS(s) (((s) & 0x0200) != 0)
-#define Stat_TNoDMA(s) (((s) & 0x0100) != 0)
-#define Stat_TDefer(s) (((s) & 0x0080) != 0)
-#define Stat_TColl(s) (((s) & 0x0040) != 0)
-#define Stat_TXColl(s) (((s) & 0x0020) != 0)
-#define Stat_NoColl(s) ((s) & 0x000f)
-
-/* Cmd_END will end AFTER the command if this is the first
- * command block after an SCB_CUstart, but BEFORE the command
- * for all subsequent commands. Best strategy is to place
- * Cmd_INT on the last command in the sequence, followed by a
- * dummy Cmd_Nop with Cmd_END after this.
- */
-
-#define Cmd_END 0x8000
-#define Cmd_SUS 0x4000
-#define Cmd_INT 0x2000
-
-#define Cmd_Nop 0x0000
-#define Cmd_SetAddr 0x0001
-#define Cmd_Config 0x0002
-#define Cmd_MCast 0x0003
-#define Cmd_Xmit 0x0004
-#define Cmd_TDR 0x0005
-#define Cmd_Dump 0x0006
-#define Cmd_Diag 0x0007
-
-
-/*
- * Frame Descriptor (Receive block) defines
- */
-
-#define FD_Done(s) (((s) & 0x8000) != 0)
-#define FD_Busy(s) (((s) & 0x4000) != 0)
-#define FD_OK(s) (((s) & 0x2000) != 0)
-
-#define FD_CRC(s) (((s) & 0x0800) != 0)
-#define FD_Align(s) (((s) & 0x0400) != 0)
-#define FD_Resrc(s) (((s) & 0x0200) != 0)
-#define FD_DMA(s) (((s) & 0x0100) != 0)
-#define FD_Short(s) (((s) & 0x0080) != 0)
-#define FD_NoEOF(s) (((s) & 0x0040) != 0)
-
-struct rfd_header {
- volatile unsigned long flags;
- volatile unsigned short link;
- volatile unsigned short rbd_offset;
- volatile unsigned short dstaddr1;
- volatile unsigned short dstaddr2;
- volatile unsigned short dstaddr3;
- volatile unsigned short srcaddr1;
- volatile unsigned short srcaddr2;
- volatile unsigned short srcaddr3;
- volatile unsigned short length;
-
- /* This is actually a Receive Buffer Descriptor. The way we
- * arrange memory means that an RBD always follows the RFD that
- * points to it, so they might as well be in the same structure.
- */
- volatile unsigned short actual_count;
- volatile unsigned short next_rbd;
- volatile unsigned short buf_addr1;
- volatile unsigned short buf_addr2;
- volatile unsigned short size;
-};
-
-/* Returned data from the Time Domain Reflectometer */
-
-#define TDR_LINKOK (1<<15)
-#define TDR_XCVRPROBLEM (1<<14)
-#define TDR_OPEN (1<<13)
-#define TDR_SHORT (1<<12)
-#define TDR_TIME 0x7ff
source "drivers/net/ethernet/broadcom/Kconfig"
source "drivers/net/ethernet/chelsio/Kconfig"
source "drivers/net/ethernet/intel/Kconfig"
+source "drivers/net/ethernet/i825xx/Kconfig"
source "drivers/net/ethernet/qlogic/Kconfig"
source "drivers/net/ethernet/smsc/Kconfig"
obj-$(CONFIG_NET_VENDOR_BROADCOM) += broadcom/
obj-$(CONFIG_NET_VENDOR_CHELSIO) += chelsio/
obj-$(CONFIG_NET_VENDOR_INTEL) += intel/
+obj-$(CONFIG_NET_VENDOR_I825XX) += i825xx/
obj-$(CONFIG_NET_VENDOR_QLOGIC) += qlogic/
obj-$(CONFIG_NET_VENDOR_SMSC) += smsc/
--- /dev/null
+/*
+ * Linux Ethernet device driver for the 3Com Etherlink Plus (3C505)
+ * By Craig Southeren, Juha Laiho and Philip Blundell
+ *
+ * 3c505.c This module implements an interface to the 3Com
+ * Etherlink Plus (3c505) Ethernet card. Linux device
+ * driver interface reverse engineered from the Linux 3C509
+ * device drivers. Some 3C505 information gleaned from
+ * the Crynwr packet driver. Still this driver would not
+ * be here without 3C505 technical reference provided by
+ * 3Com.
+ *
+ * $Id: 3c505.c,v 1.10 1996/04/16 13:06:27 phil Exp $
+ *
+ * Authors: Linux 3c505 device driver by
+ * Craig Southeren, <craigs@ineluki.apana.org.au>
+ * Final debugging by
+ * Andrew Tridgell, <tridge@nimbus.anu.edu.au>
+ * Auto irq/address, tuning, cleanup and v1.1.4+ kernel mods by
+ * Juha Laiho, <jlaiho@ichaos.nullnet.fi>
+ * Linux 3C509 driver by
+ * Donald Becker, <becker@super.org>
+ * (Now at <becker@scyld.com>)
+ * Crynwr packet driver by
+ * Krishnan Gopalan and Gregg Stefancik,
+ * Clemson University Engineering Computer Operations.
+ * Portions of the code have been adapted from the 3c505
+ * driver for NCSA Telnet by Bruce Orchard and later
+ * modified by Warren Van Houten and krus@diku.dk.
+ * 3C505 technical information provided by
+ * Terry Murphy, of 3Com Network Adapter Division
+ * Linux 1.3.0 changes by
+ * Alan Cox <Alan.Cox@linux.org>
+ * More debugging, DMA support, currently maintained by
+ * Philip Blundell <philb@gnu.org>
+ * Multicard/soft configurable dma channel/rev 2 hardware support
+ * by Christopher Collins <ccollins@pcug.org.au>
+ * Ethtool support (jgarzik), 11/17/2001
+ */
+
+#define DRV_NAME "3c505"
+#define DRV_VERSION "1.10a"
+
+
+/* Theory of operation:
+ *
+ * The 3c505 is quite an intelligent board. All communication with it is done
+ * by means of Primary Command Blocks (PCBs); these are transferred using PIO
+ * through the command register. The card has 256k of on-board RAM, which is
+ * used to buffer received packets. It might seem at first that more buffers
+ * are better, but in fact this isn't true. From my tests, it seems that
+ * more than about 10 buffers are unnecessary, and there is a noticeable
+ * performance hit in having more active on the card. So the majority of the
+ * card's memory isn't, in fact, used. Sadly, the card only has one transmit
+ * buffer and, short of loading our own firmware into it (which is what some
+ * drivers resort to) there's nothing we can do about this.
+ *
+ * We keep up to 4 "receive packet" commands active on the board at a time.
+ * When a packet comes in, so long as there is a receive command active, the
+ * board will send us a "packet received" PCB and then add the data for that
+ * packet to the DMA queue. If a DMA transfer is not already in progress, we
+ * set one up to start uploading the data. We have to maintain a list of
+ * backlogged receive packets, because the card may decide to tell us about
+ * a newly-arrived packet at any time, and we may not be able to start a DMA
+ * transfer immediately (ie one may already be going on). We can't NAK the
+ * PCB, because then it would throw the packet away.
+ *
+ * Trying to send a PCB to the card at the wrong moment seems to have bad
+ * effects. If we send it a transmit PCB while a receive DMA is happening,
+ * it will just NAK the PCB and so we will have wasted our time. Worse, it
+ * sometimes seems to interrupt the transfer. The majority of the low-level
+ * code is protected by one huge semaphore -- "busy" -- which is set whenever
+ * it probably isn't safe to do anything to the card. The receive routine
+ * must gain a lock on "busy" before it can start a DMA transfer, and the
+ * transmit routine must gain a lock before it sends the first PCB to the card.
+ * The send_pcb() routine also has an internal semaphore to protect it against
+ * being re-entered (which would be disastrous) -- this is needed because
+ * several things can happen asynchronously (re-priming the receiver and
+ * asking the card for statistics, for example). send_pcb() will also refuse
+ * to talk to the card at all if a DMA upload is happening. The higher-level
+ * networking code will reschedule a later retry if some part of the driver
+ * is blocked. In practice, this doesn't seem to happen very often.
+ */
+
+/* This driver may now work with revision 2.x hardware, since all the read
+ * operations on the HCR have been removed (we now keep our own softcopy).
+ * But I don't have an old card to test it on.
+ *
+ * This has had the bad effect that the autoprobe routine is now a bit
+ * less friendly to other devices. However, it was never very good.
+ * before, so I doubt it will hurt anybody.
+ */
+
+/* The driver is a mess. I took Craig's and Juha's code, and hacked it firstly
+ * to make it more reliable, and secondly to add DMA mode. Many things could
+ * probably be done better; the concurrency protection is particularly awful.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/in.h>
+#include <linux/ioport.h>
+#include <linux/spinlock.h>
+#include <linux/ethtool.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+#include <linux/gfp.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+
+#include "3c505.h"
+
+/*********************************************************
+ *
+ * define debug messages here as common strings to reduce space
+ *
+ *********************************************************/
+
+#define filename __FILE__
+
+#define timeout_msg "*** timeout at %s:%s (line %d) ***\n"
+#define TIMEOUT_MSG(lineno) \
+ pr_notice(timeout_msg, filename, __func__, (lineno))
+
+#define invalid_pcb_msg "*** invalid pcb length %d at %s:%s (line %d) ***\n"
+#define INVALID_PCB_MSG(len) \
+ pr_notice(invalid_pcb_msg, (len), filename, __func__, __LINE__)
+
+#define search_msg "%s: Looking for 3c505 adapter at address %#x..."
+
+#define stilllooking_msg "still looking..."
+
+#define found_msg "found.\n"
+
+#define notfound_msg "not found (reason = %d)\n"
+
+#define couldnot_msg "%s: 3c505 not found\n"
+
+/*********************************************************
+ *
+ * various other debug stuff
+ *
+ *********************************************************/
+
+#ifdef ELP_DEBUG
+static int elp_debug = ELP_DEBUG;
+#else
+static int elp_debug;
+#endif
+#define debug elp_debug
+
+/*
+ * 0 = no messages (well, some)
+ * 1 = messages when high level commands performed
+ * 2 = messages when low level commands performed
+ * 3 = messages when interrupts received
+ */
+
+/*****************************************************************
+ *
+ * List of I/O-addresses we try to auto-sense
+ * Last element MUST BE 0!
+ *****************************************************************/
+
+static int addr_list[] __initdata = {0x300, 0x280, 0x310, 0};
+
+/* Dma Memory related stuff */
+
+static unsigned long dma_mem_alloc(int size)
+{
+ int order = get_order(size);
+ return __get_dma_pages(GFP_KERNEL, order);
+}
+
+
+/*****************************************************************
+ *
+ * Functions for I/O (note the inline !)
+ *
+ *****************************************************************/
+
+static inline unsigned char inb_status(unsigned int base_addr)
+{
+ return inb(base_addr + PORT_STATUS);
+}
+
+static inline int inb_command(unsigned int base_addr)
+{
+ return inb(base_addr + PORT_COMMAND);
+}
+
+static inline void outb_control(unsigned char val, struct net_device *dev)
+{
+ outb(val, dev->base_addr + PORT_CONTROL);
+ ((elp_device *)(netdev_priv(dev)))->hcr_val = val;
+}
+
+#define HCR_VAL(x) (((elp_device *)(netdev_priv(x)))->hcr_val)
+
+static inline void outb_command(unsigned char val, unsigned int base_addr)
+{
+ outb(val, base_addr + PORT_COMMAND);
+}
+
+static inline unsigned int backlog_next(unsigned int n)
+{
+ return (n + 1) % BACKLOG_SIZE;
+}
+
+/*****************************************************************
+ *
+ * useful functions for accessing the adapter
+ *
+ *****************************************************************/
+
+/*
+ * use this routine when accessing the ASF bits as they are
+ * changed asynchronously by the adapter
+ */
+
+/* get adapter PCB status */
+#define GET_ASF(addr) \
+ (get_status(addr)&ASF_PCB_MASK)
+
+static inline int get_status(unsigned int base_addr)
+{
+ unsigned long timeout = jiffies + 10*HZ/100;
+ register int stat1;
+ do {
+ stat1 = inb_status(base_addr);
+ } while (stat1 != inb_status(base_addr) && time_before(jiffies, timeout));
+ if (time_after_eq(jiffies, timeout))
+ TIMEOUT_MSG(__LINE__);
+ return stat1;
+}
+
+static inline void set_hsf(struct net_device *dev, int hsf)
+{
+ elp_device *adapter = netdev_priv(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&adapter->lock, flags);
+ outb_control((HCR_VAL(dev) & ~HSF_PCB_MASK) | hsf, dev);
+ spin_unlock_irqrestore(&adapter->lock, flags);
+}
+
+static bool start_receive(struct net_device *, pcb_struct *);
+
+static inline void adapter_reset(struct net_device *dev)
+{
+ unsigned long timeout;
+ elp_device *adapter = netdev_priv(dev);
+ unsigned char orig_hcr = adapter->hcr_val;
+
+ outb_control(0, dev);
+
+ if (inb_status(dev->base_addr) & ACRF) {
+ do {
+ inb_command(dev->base_addr);
+ timeout = jiffies + 2*HZ/100;
+ while (time_before_eq(jiffies, timeout) && !(inb_status(dev->base_addr) & ACRF));
+ } while (inb_status(dev->base_addr) & ACRF);
+ set_hsf(dev, HSF_PCB_NAK);
+ }
+ outb_control(adapter->hcr_val | ATTN | DIR, dev);
+ mdelay(10);
+ outb_control(adapter->hcr_val & ~ATTN, dev);
+ mdelay(10);
+ outb_control(adapter->hcr_val | FLSH, dev);
+ mdelay(10);
+ outb_control(adapter->hcr_val & ~FLSH, dev);
+ mdelay(10);
+
+ outb_control(orig_hcr, dev);
+ if (!start_receive(dev, &adapter->tx_pcb))
+ pr_err("%s: start receive command failed\n", dev->name);
+}
+
+/* Check to make sure that a DMA transfer hasn't timed out. This should
+ * never happen in theory, but seems to occur occasionally if the card gets
+ * prodded at the wrong time.
+ */
+static inline void check_3c505_dma(struct net_device *dev)
+{
+ elp_device *adapter = netdev_priv(dev);
+ if (adapter->dmaing && time_after(jiffies, adapter->current_dma.start_time + 10)) {
+ unsigned long flags, f;
+ pr_err("%s: DMA %s timed out, %d bytes left\n", dev->name,
+ adapter->current_dma.direction ? "download" : "upload",
+ get_dma_residue(dev->dma));
+ spin_lock_irqsave(&adapter->lock, flags);
+ adapter->dmaing = 0;
+ adapter->busy = 0;
+
+ f=claim_dma_lock();
+ disable_dma(dev->dma);
+ release_dma_lock(f);
+
+ if (adapter->rx_active)
+ adapter->rx_active--;
+ outb_control(adapter->hcr_val & ~(DMAE | TCEN | DIR), dev);
+ spin_unlock_irqrestore(&adapter->lock, flags);
+ }
+}
+
+/* Primitive functions used by send_pcb() */
+static inline bool send_pcb_slow(unsigned int base_addr, unsigned char byte)
+{
+ unsigned long timeout;
+ outb_command(byte, base_addr);
+ for (timeout = jiffies + 5*HZ/100; time_before(jiffies, timeout);) {
+ if (inb_status(base_addr) & HCRE)
+ return false;
+ }
+ pr_warning("3c505: send_pcb_slow timed out\n");
+ return true;
+}
+
+static inline bool send_pcb_fast(unsigned int base_addr, unsigned char byte)
+{
+ unsigned int timeout;
+ outb_command(byte, base_addr);
+ for (timeout = 0; timeout < 40000; timeout++) {
+ if (inb_status(base_addr) & HCRE)
+ return false;
+ }
+ pr_warning("3c505: send_pcb_fast timed out\n");
+ return true;
+}
+
+/* Check to see if the receiver needs restarting, and kick it if so */
+static inline void prime_rx(struct net_device *dev)
+{
+ elp_device *adapter = netdev_priv(dev);
+ while (adapter->rx_active < ELP_RX_PCBS && netif_running(dev)) {
+ if (!start_receive(dev, &adapter->itx_pcb))
+ break;
+ }
+}
+
+/*****************************************************************
+ *
+ * send_pcb
+ * Send a PCB to the adapter.
+ *
+ * output byte to command reg --<--+
+ * wait until HCRE is non zero |
+ * loop until all bytes sent -->--+
+ * set HSF1 and HSF2 to 1
+ * output pcb length
+ * wait until ASF give ACK or NAK
+ * set HSF1 and HSF2 to 0
+ *
+ *****************************************************************/
+
+/* This can be quite slow -- the adapter is allowed to take up to 40ms
+ * to respond to the initial interrupt.
+ *
+ * We run initially with interrupts turned on, but with a semaphore set
+ * so that nobody tries to re-enter this code. Once the first byte has
+ * gone through, we turn interrupts off and then send the others (the
+ * timeout is reduced to 500us).
+ */
+
+static bool send_pcb(struct net_device *dev, pcb_struct * pcb)
+{
+ int i;
+ unsigned long timeout;
+ elp_device *adapter = netdev_priv(dev);
+ unsigned long flags;
+
+ check_3c505_dma(dev);
+
+ if (adapter->dmaing && adapter->current_dma.direction == 0)
+ return false;
+
+ /* Avoid contention */
+ if (test_and_set_bit(1, &adapter->send_pcb_semaphore)) {
+ if (elp_debug >= 3) {
+ pr_debug("%s: send_pcb entered while threaded\n", dev->name);
+ }
+ return false;
+ }
+ /*
+ * load each byte into the command register and
+ * wait for the HCRE bit to indicate the adapter
+ * had read the byte
+ */
+ set_hsf(dev, 0);
+
+ if (send_pcb_slow(dev->base_addr, pcb->command))
+ goto abort;
+
+ spin_lock_irqsave(&adapter->lock, flags);
+
+ if (send_pcb_fast(dev->base_addr, pcb->length))
+ goto sti_abort;
+
+ for (i = 0; i < pcb->length; i++) {
+ if (send_pcb_fast(dev->base_addr, pcb->data.raw[i]))
+ goto sti_abort;
+ }
+
+ outb_control(adapter->hcr_val | 3, dev); /* signal end of PCB */
+ outb_command(2 + pcb->length, dev->base_addr);
+
+ /* now wait for the acknowledgement */
+ spin_unlock_irqrestore(&adapter->lock, flags);
+
+ for (timeout = jiffies + 5*HZ/100; time_before(jiffies, timeout);) {
+ switch (GET_ASF(dev->base_addr)) {
+ case ASF_PCB_ACK:
+ adapter->send_pcb_semaphore = 0;
+ return true;
+
+ case ASF_PCB_NAK:
+#ifdef ELP_DEBUG
+ pr_debug("%s: send_pcb got NAK\n", dev->name);
+#endif
+ goto abort;
+ }
+ }
+
+ if (elp_debug >= 1)
+ pr_debug("%s: timeout waiting for PCB acknowledge (status %02x)\n",
+ dev->name, inb_status(dev->base_addr));
+ goto abort;
+
+ sti_abort:
+ spin_unlock_irqrestore(&adapter->lock, flags);
+ abort:
+ adapter->send_pcb_semaphore = 0;
+ return false;
+}
+
+
+/*****************************************************************
+ *
+ * receive_pcb
+ * Read a PCB from the adapter
+ *
+ * wait for ACRF to be non-zero ---<---+
+ * input a byte |
+ * if ASF1 and ASF2 were not both one |
+ * before byte was read, loop --->---+
+ * set HSF1 and HSF2 for ack
+ *
+ *****************************************************************/
+
+static bool receive_pcb(struct net_device *dev, pcb_struct * pcb)
+{
+ int i, j;
+ int total_length;
+ int stat;
+ unsigned long timeout;
+ unsigned long flags;
+
+ elp_device *adapter = netdev_priv(dev);
+
+ set_hsf(dev, 0);
+
+ /* get the command code */
+ timeout = jiffies + 2*HZ/100;
+ while (((stat = get_status(dev->base_addr)) & ACRF) == 0 && time_before(jiffies, timeout));
+ if (time_after_eq(jiffies, timeout)) {
+ TIMEOUT_MSG(__LINE__);
+ return false;
+ }
+ pcb->command = inb_command(dev->base_addr);
+
+ /* read the data length */
+ timeout = jiffies + 3*HZ/100;
+ while (((stat = get_status(dev->base_addr)) & ACRF) == 0 && time_before(jiffies, timeout));
+ if (time_after_eq(jiffies, timeout)) {
+ TIMEOUT_MSG(__LINE__);
+ pr_info("%s: status %02x\n", dev->name, stat);
+ return false;
+ }
+ pcb->length = inb_command(dev->base_addr);
+
+ if (pcb->length > MAX_PCB_DATA) {
+ INVALID_PCB_MSG(pcb->length);
+ adapter_reset(dev);
+ return false;
+ }
+ /* read the data */
+ spin_lock_irqsave(&adapter->lock, flags);
+ for (i = 0; i < MAX_PCB_DATA; i++) {
+ for (j = 0; j < 20000; j++) {
+ stat = get_status(dev->base_addr);
+ if (stat & ACRF)
+ break;
+ }
+ pcb->data.raw[i] = inb_command(dev->base_addr);
+ if ((stat & ASF_PCB_MASK) == ASF_PCB_END || j >= 20000)
+ break;
+ }
+ spin_unlock_irqrestore(&adapter->lock, flags);
+ if (i >= MAX_PCB_DATA) {
+ INVALID_PCB_MSG(i);
+ return false;
+ }
+ if (j >= 20000) {
+ TIMEOUT_MSG(__LINE__);
+ return false;
+ }
+ /* the last "data" byte was really the length! */
+ total_length = pcb->data.raw[i];
+
+ /* safety check total length vs data length */
+ if (total_length != (pcb->length + 2)) {
+ if (elp_debug >= 2)
+ pr_warning("%s: mangled PCB received\n", dev->name);
+ set_hsf(dev, HSF_PCB_NAK);
+ return false;
+ }
+
+ if (pcb->command == CMD_RECEIVE_PACKET_COMPLETE) {
+ if (test_and_set_bit(0, (void *) &adapter->busy)) {
+ if (backlog_next(adapter->rx_backlog.in) == adapter->rx_backlog.out) {
+ set_hsf(dev, HSF_PCB_NAK);
+ pr_warning("%s: PCB rejected, transfer in progress and backlog full\n", dev->name);
+ pcb->command = 0;
+ return true;
+ } else {
+ pcb->command = 0xff;
+ }
+ }
+ }
+ set_hsf(dev, HSF_PCB_ACK);
+ return true;
+}
+
+/******************************************************
+ *
+ * queue a receive command on the adapter so we will get an
+ * interrupt when a packet is received.
+ *
+ ******************************************************/
+
+static bool start_receive(struct net_device *dev, pcb_struct * tx_pcb)
+{
+ bool status;
+ elp_device *adapter = netdev_priv(dev);
+
+ if (elp_debug >= 3)
+ pr_debug("%s: restarting receiver\n", dev->name);
+ tx_pcb->command = CMD_RECEIVE_PACKET;
+ tx_pcb->length = sizeof(struct Rcv_pkt);
+ tx_pcb->data.rcv_pkt.buf_seg
+ = tx_pcb->data.rcv_pkt.buf_ofs = 0; /* Unused */
+ tx_pcb->data.rcv_pkt.buf_len = 1600;
+ tx_pcb->data.rcv_pkt.timeout = 0; /* set timeout to zero */
+ status = send_pcb(dev, tx_pcb);
+ if (status)
+ adapter->rx_active++;
+ return status;
+}
+
+/******************************************************
+ *
+ * extract a packet from the adapter
+ * this routine is only called from within the interrupt
+ * service routine, so no cli/sti calls are needed
+ * note that the length is always assumed to be even
+ *
+ ******************************************************/
+
+static void receive_packet(struct net_device *dev, int len)
+{
+ int rlen;
+ elp_device *adapter = netdev_priv(dev);
+ void *target;
+ struct sk_buff *skb;
+ unsigned long flags;
+
+ rlen = (len + 1) & ~1;
+ skb = dev_alloc_skb(rlen + 2);
+
+ if (!skb) {
+ pr_warning("%s: memory squeeze, dropping packet\n", dev->name);
+ target = adapter->dma_buffer;
+ adapter->current_dma.target = NULL;
+ /* FIXME: stats */
+ return;
+ }
+
+ skb_reserve(skb, 2);
+ target = skb_put(skb, rlen);
+ if ((unsigned long)(target + rlen) >= MAX_DMA_ADDRESS) {
+ adapter->current_dma.target = target;
+ target = adapter->dma_buffer;
+ } else {
+ adapter->current_dma.target = NULL;
+ }
+
+ /* if this happens, we die */
+ if (test_and_set_bit(0, (void *) &adapter->dmaing))
+ pr_err("%s: rx blocked, DMA in progress, dir %d\n",
+ dev->name, adapter->current_dma.direction);
+
+ adapter->current_dma.direction = 0;
+ adapter->current_dma.length = rlen;
+ adapter->current_dma.skb = skb;
+ adapter->current_dma.start_time = jiffies;
+
+ outb_control(adapter->hcr_val | DIR | TCEN | DMAE, dev);
+
+ flags=claim_dma_lock();
+ disable_dma(dev->dma);
+ clear_dma_ff(dev->dma);
+ set_dma_mode(dev->dma, 0x04); /* dma read */
+ set_dma_addr(dev->dma, isa_virt_to_bus(target));
+ set_dma_count(dev->dma, rlen);
+ enable_dma(dev->dma);
+ release_dma_lock(flags);
+
+ if (elp_debug >= 3) {
+ pr_debug("%s: rx DMA transfer started\n", dev->name);
+ }
+
+ if (adapter->rx_active)
+ adapter->rx_active--;
+
+ if (!adapter->busy)
+ pr_warning("%s: receive_packet called, busy not set.\n", dev->name);
+}
+
+/******************************************************
+ *
+ * interrupt handler
+ *
+ ******************************************************/
+
+static irqreturn_t elp_interrupt(int irq, void *dev_id)
+{
+ int len;
+ int dlen;
+ int icount = 0;
+ struct net_device *dev = dev_id;
+ elp_device *adapter = netdev_priv(dev);
+ unsigned long timeout;
+
+ spin_lock(&adapter->lock);
+
+ do {
+ /*
+ * has a DMA transfer finished?
+ */
+ if (inb_status(dev->base_addr) & DONE) {
+ if (!adapter->dmaing)
+ pr_warning("%s: phantom DMA completed\n", dev->name);
+
+ if (elp_debug >= 3)
+ pr_debug("%s: %s DMA complete, status %02x\n", dev->name,
+ adapter->current_dma.direction ? "tx" : "rx",
+ inb_status(dev->base_addr));
+
+ outb_control(adapter->hcr_val & ~(DMAE | TCEN | DIR), dev);
+ if (adapter->current_dma.direction) {
+ dev_kfree_skb_irq(adapter->current_dma.skb);
+ } else {
+ struct sk_buff *skb = adapter->current_dma.skb;
+ if (skb) {
+ if (adapter->current_dma.target) {
+ /* have already done the skb_put() */
+ memcpy(adapter->current_dma.target, adapter->dma_buffer, adapter->current_dma.length);
+ }
+ skb->protocol = eth_type_trans(skb,dev);
+ dev->stats.rx_bytes += skb->len;
+ netif_rx(skb);
+ }
+ }
+ adapter->dmaing = 0;
+ if (adapter->rx_backlog.in != adapter->rx_backlog.out) {
+ int t = adapter->rx_backlog.length[adapter->rx_backlog.out];
+ adapter->rx_backlog.out = backlog_next(adapter->rx_backlog.out);
+ if (elp_debug >= 2)
+ pr_debug("%s: receiving backlogged packet (%d)\n", dev->name, t);
+ receive_packet(dev, t);
+ } else {
+ adapter->busy = 0;
+ }
+ } else {
+ /* has one timed out? */
+ check_3c505_dma(dev);
+ }
+
+ /*
+ * receive a PCB from the adapter
+ */
+ timeout = jiffies + 3*HZ/100;
+ while ((inb_status(dev->base_addr) & ACRF) != 0 && time_before(jiffies, timeout)) {
+ if (receive_pcb(dev, &adapter->irx_pcb)) {
+ switch (adapter->irx_pcb.command)
+ {
+ case 0:
+ break;
+ /*
+ * received a packet - this must be handled fast
+ */
+ case 0xff:
+ case CMD_RECEIVE_PACKET_COMPLETE:
+ /* if the device isn't open, don't pass packets up the stack */
+ if (!netif_running(dev))
+ break;
+ len = adapter->irx_pcb.data.rcv_resp.pkt_len;
+ dlen = adapter->irx_pcb.data.rcv_resp.buf_len;
+ if (adapter->irx_pcb.data.rcv_resp.timeout != 0) {
+ pr_err("%s: interrupt - packet not received correctly\n", dev->name);
+ } else {
+ if (elp_debug >= 3) {
+ pr_debug("%s: interrupt - packet received of length %i (%i)\n",
+ dev->name, len, dlen);
+ }
+ if (adapter->irx_pcb.command == 0xff) {
+ if (elp_debug >= 2)
+ pr_debug("%s: adding packet to backlog (len = %d)\n",
+ dev->name, dlen);
+ adapter->rx_backlog.length[adapter->rx_backlog.in] = dlen;
+ adapter->rx_backlog.in = backlog_next(adapter->rx_backlog.in);
+ } else {
+ receive_packet(dev, dlen);
+ }
+ if (elp_debug >= 3)
+ pr_debug("%s: packet received\n", dev->name);
+ }
+ break;
+
+ /*
+ * 82586 configured correctly
+ */
+ case CMD_CONFIGURE_82586_RESPONSE:
+ adapter->got[CMD_CONFIGURE_82586] = 1;
+ if (elp_debug >= 3)
+ pr_debug("%s: interrupt - configure response received\n", dev->name);
+ break;
+
+ /*
+ * Adapter memory configuration
+ */
+ case CMD_CONFIGURE_ADAPTER_RESPONSE:
+ adapter->got[CMD_CONFIGURE_ADAPTER_MEMORY] = 1;
+ if (elp_debug >= 3)
+ pr_debug("%s: Adapter memory configuration %s.\n", dev->name,
+ adapter->irx_pcb.data.failed ? "failed" : "succeeded");
+ break;
+
+ /*
+ * Multicast list loading
+ */
+ case CMD_LOAD_MULTICAST_RESPONSE:
+ adapter->got[CMD_LOAD_MULTICAST_LIST] = 1;
+ if (elp_debug >= 3)
+ pr_debug("%s: Multicast address list loading %s.\n", dev->name,
+ adapter->irx_pcb.data.failed ? "failed" : "succeeded");
+ break;
+
+ /*
+ * Station address setting
+ */
+ case CMD_SET_ADDRESS_RESPONSE:
+ adapter->got[CMD_SET_STATION_ADDRESS] = 1;
+ if (elp_debug >= 3)
+ pr_debug("%s: Ethernet address setting %s.\n", dev->name,
+ adapter->irx_pcb.data.failed ? "failed" : "succeeded");
+ break;
+
+
+ /*
+ * received board statistics
+ */
+ case CMD_NETWORK_STATISTICS_RESPONSE:
+ dev->stats.rx_packets += adapter->irx_pcb.data.netstat.tot_recv;
+ dev->stats.tx_packets += adapter->irx_pcb.data.netstat.tot_xmit;
+ dev->stats.rx_crc_errors += adapter->irx_pcb.data.netstat.err_CRC;
+ dev->stats.rx_frame_errors += adapter->irx_pcb.data.netstat.err_align;
+ dev->stats.rx_fifo_errors += adapter->irx_pcb.data.netstat.err_ovrrun;
+ dev->stats.rx_over_errors += adapter->irx_pcb.data.netstat.err_res;
+ adapter->got[CMD_NETWORK_STATISTICS] = 1;
+ if (elp_debug >= 3)
+ pr_debug("%s: interrupt - statistics response received\n", dev->name);
+ break;
+
+ /*
+ * sent a packet
+ */
+ case CMD_TRANSMIT_PACKET_COMPLETE:
+ if (elp_debug >= 3)
+ pr_debug("%s: interrupt - packet sent\n", dev->name);
+ if (!netif_running(dev))
+ break;
+ switch (adapter->irx_pcb.data.xmit_resp.c_stat) {
+ case 0xffff:
+ dev->stats.tx_aborted_errors++;
+ pr_info("%s: transmit timed out, network cable problem?\n", dev->name);
+ break;
+ case 0xfffe:
+ dev->stats.tx_fifo_errors++;
+ pr_info("%s: transmit timed out, FIFO underrun\n", dev->name);
+ break;
+ }
+ netif_wake_queue(dev);
+ break;
+
+ /*
+ * some unknown PCB
+ */
+ default:
+ pr_debug("%s: unknown PCB received - %2.2x\n",
+ dev->name, adapter->irx_pcb.command);
+ break;
+ }
+ } else {
+ pr_warning("%s: failed to read PCB on interrupt\n", dev->name);
+ adapter_reset(dev);
+ }
+ }
+
+ } while (icount++ < 5 && (inb_status(dev->base_addr) & (ACRF | DONE)));
+
+ prime_rx(dev);
+
+ /*
+ * indicate no longer in interrupt routine
+ */
+ spin_unlock(&adapter->lock);
+ return IRQ_HANDLED;
+}
+
+
+/******************************************************
+ *
+ * open the board
+ *
+ ******************************************************/
+
+static int elp_open(struct net_device *dev)
+{
+ elp_device *adapter = netdev_priv(dev);
+ int retval;
+
+ if (elp_debug >= 3)
+ pr_debug("%s: request to open device\n", dev->name);
+
+ /*
+ * make sure we actually found the device
+ */
+ if (adapter == NULL) {
+ pr_err("%s: Opening a non-existent physical device\n", dev->name);
+ return -EAGAIN;
+ }
+ /*
+ * disable interrupts on the board
+ */
+ outb_control(0, dev);
+
+ /*
+ * clear any pending interrupts
+ */
+ inb_command(dev->base_addr);
+ adapter_reset(dev);
+
+ /*
+ * no receive PCBs active
+ */
+ adapter->rx_active = 0;
+
+ adapter->busy = 0;
+ adapter->send_pcb_semaphore = 0;
+ adapter->rx_backlog.in = 0;
+ adapter->rx_backlog.out = 0;
+
+ spin_lock_init(&adapter->lock);
+
+ /*
+ * install our interrupt service routine
+ */
+ if ((retval = request_irq(dev->irq, elp_interrupt, 0, dev->name, dev))) {
+ pr_err("%s: could not allocate IRQ%d\n", dev->name, dev->irq);
+ return retval;
+ }
+ if ((retval = request_dma(dev->dma, dev->name))) {
+ free_irq(dev->irq, dev);
+ pr_err("%s: could not allocate DMA%d channel\n", dev->name, dev->dma);
+ return retval;
+ }
+ adapter->dma_buffer = (void *) dma_mem_alloc(DMA_BUFFER_SIZE);
+ if (!adapter->dma_buffer) {
+ pr_err("%s: could not allocate DMA buffer\n", dev->name);
+ free_dma(dev->dma);
+ free_irq(dev->irq, dev);
+ return -ENOMEM;
+ }
+ adapter->dmaing = 0;
+
+ /*
+ * enable interrupts on the board
+ */
+ outb_control(CMDE, dev);
+
+ /*
+ * configure adapter memory: we need 10 multicast addresses, default==0
+ */
+ if (elp_debug >= 3)
+ pr_debug("%s: sending 3c505 memory configuration command\n", dev->name);
+ adapter->tx_pcb.command = CMD_CONFIGURE_ADAPTER_MEMORY;
+ adapter->tx_pcb.data.memconf.cmd_q = 10;
+ adapter->tx_pcb.data.memconf.rcv_q = 20;
+ adapter->tx_pcb.data.memconf.mcast = 10;
+ adapter->tx_pcb.data.memconf.frame = 20;
+ adapter->tx_pcb.data.memconf.rcv_b = 20;
+ adapter->tx_pcb.data.memconf.progs = 0;
+ adapter->tx_pcb.length = sizeof(struct Memconf);
+ adapter->got[CMD_CONFIGURE_ADAPTER_MEMORY] = 0;
+ if (!send_pcb(dev, &adapter->tx_pcb))
+ pr_err("%s: couldn't send memory configuration command\n", dev->name);
+ else {
+ unsigned long timeout = jiffies + TIMEOUT;
+ while (adapter->got[CMD_CONFIGURE_ADAPTER_MEMORY] == 0 && time_before(jiffies, timeout));
+ if (time_after_eq(jiffies, timeout))
+ TIMEOUT_MSG(__LINE__);
+ }
+
+
+ /*
+ * configure adapter to receive broadcast messages and wait for response
+ */
+ if (elp_debug >= 3)
+ pr_debug("%s: sending 82586 configure command\n", dev->name);
+ adapter->tx_pcb.command = CMD_CONFIGURE_82586;
+ adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_BROAD;
+ adapter->tx_pcb.length = 2;
+ adapter->got[CMD_CONFIGURE_82586] = 0;
+ if (!send_pcb(dev, &adapter->tx_pcb))
+ pr_err("%s: couldn't send 82586 configure command\n", dev->name);
+ else {
+ unsigned long timeout = jiffies + TIMEOUT;
+ while (adapter->got[CMD_CONFIGURE_82586] == 0 && time_before(jiffies, timeout));
+ if (time_after_eq(jiffies, timeout))
+ TIMEOUT_MSG(__LINE__);
+ }
+
+ /* enable burst-mode DMA */
+ /* outb(0x1, dev->base_addr + PORT_AUXDMA); */
+
+ /*
+ * queue receive commands to provide buffering
+ */
+ prime_rx(dev);
+ if (elp_debug >= 3)
+ pr_debug("%s: %d receive PCBs active\n", dev->name, adapter->rx_active);
+
+ /*
+ * device is now officially open!
+ */
+
+ netif_start_queue(dev);
+ return 0;
+}
+
+
+/******************************************************
+ *
+ * send a packet to the adapter
+ *
+ ******************************************************/
+
+static netdev_tx_t send_packet(struct net_device *dev, struct sk_buff *skb)
+{
+ elp_device *adapter = netdev_priv(dev);
+ unsigned long target;
+ unsigned long flags;
+
+ /*
+ * make sure the length is even and no shorter than 60 bytes
+ */
+ unsigned int nlen = (((skb->len < 60) ? 60 : skb->len) + 1) & (~1);
+
+ if (test_and_set_bit(0, (void *) &adapter->busy)) {
+ if (elp_debug >= 2)
+ pr_debug("%s: transmit blocked\n", dev->name);
+ return false;
+ }
+
+ dev->stats.tx_bytes += nlen;
+
+ /*
+ * send the adapter a transmit packet command. Ignore segment and offset
+ * and make sure the length is even
+ */
+ adapter->tx_pcb.command = CMD_TRANSMIT_PACKET;
+ adapter->tx_pcb.length = sizeof(struct Xmit_pkt);
+ adapter->tx_pcb.data.xmit_pkt.buf_ofs
+ = adapter->tx_pcb.data.xmit_pkt.buf_seg = 0; /* Unused */
+ adapter->tx_pcb.data.xmit_pkt.pkt_len = nlen;
+
+ if (!send_pcb(dev, &adapter->tx_pcb)) {
+ adapter->busy = 0;
+ return false;
+ }
+ /* if this happens, we die */
+ if (test_and_set_bit(0, (void *) &adapter->dmaing))
+ pr_debug("%s: tx: DMA %d in progress\n", dev->name, adapter->current_dma.direction);
+
+ adapter->current_dma.direction = 1;
+ adapter->current_dma.start_time = jiffies;
+
+ if ((unsigned long)(skb->data + nlen) >= MAX_DMA_ADDRESS || nlen != skb->len) {
+ skb_copy_from_linear_data(skb, adapter->dma_buffer, nlen);
+ memset(adapter->dma_buffer+skb->len, 0, nlen-skb->len);
+ target = isa_virt_to_bus(adapter->dma_buffer);
+ }
+ else {
+ target = isa_virt_to_bus(skb->data);
+ }
+ adapter->current_dma.skb = skb;
+
+ flags=claim_dma_lock();
+ disable_dma(dev->dma);
+ clear_dma_ff(dev->dma);
+ set_dma_mode(dev->dma, 0x48); /* dma memory -> io */
+ set_dma_addr(dev->dma, target);
+ set_dma_count(dev->dma, nlen);
+ outb_control(adapter->hcr_val | DMAE | TCEN, dev);
+ enable_dma(dev->dma);
+ release_dma_lock(flags);
+
+ if (elp_debug >= 3)
+ pr_debug("%s: DMA transfer started\n", dev->name);
+
+ return true;
+}
+
+/*
+ * The upper layer thinks we timed out
+ */
+
+static void elp_timeout(struct net_device *dev)
+{
+ int stat;
+
+ stat = inb_status(dev->base_addr);
+ pr_warning("%s: transmit timed out, lost %s?\n", dev->name,
+ (stat & ACRF) ? "interrupt" : "command");
+ if (elp_debug >= 1)
+ pr_debug("%s: status %#02x\n", dev->name, stat);
+ dev->trans_start = jiffies; /* prevent tx timeout */
+ dev->stats.tx_dropped++;
+ netif_wake_queue(dev);
+}
+
+/******************************************************
+ *
+ * start the transmitter
+ * return 0 if sent OK, else return 1
+ *
+ ******************************************************/
+
+static netdev_tx_t elp_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ unsigned long flags;
+ elp_device *adapter = netdev_priv(dev);
+
+ spin_lock_irqsave(&adapter->lock, flags);
+ check_3c505_dma(dev);
+
+ if (elp_debug >= 3)
+ pr_debug("%s: request to send packet of length %d\n", dev->name, (int) skb->len);
+
+ netif_stop_queue(dev);
+
+ /*
+ * send the packet at skb->data for skb->len
+ */
+ if (!send_packet(dev, skb)) {
+ if (elp_debug >= 2) {
+ pr_debug("%s: failed to transmit packet\n", dev->name);
+ }
+ spin_unlock_irqrestore(&adapter->lock, flags);
+ return NETDEV_TX_BUSY;
+ }
+ if (elp_debug >= 3)
+ pr_debug("%s: packet of length %d sent\n", dev->name, (int) skb->len);
+
+ prime_rx(dev);
+ spin_unlock_irqrestore(&adapter->lock, flags);
+ netif_start_queue(dev);
+ return NETDEV_TX_OK;
+}
+
+/******************************************************
+ *
+ * return statistics on the board
+ *
+ ******************************************************/
+
+static struct net_device_stats *elp_get_stats(struct net_device *dev)
+{
+ elp_device *adapter = netdev_priv(dev);
+
+ if (elp_debug >= 3)
+ pr_debug("%s: request for stats\n", dev->name);
+
+ /* If the device is closed, just return the latest stats we have,
+ - we cannot ask from the adapter without interrupts */
+ if (!netif_running(dev))
+ return &dev->stats;
+
+ /* send a get statistics command to the board */
+ adapter->tx_pcb.command = CMD_NETWORK_STATISTICS;
+ adapter->tx_pcb.length = 0;
+ adapter->got[CMD_NETWORK_STATISTICS] = 0;
+ if (!send_pcb(dev, &adapter->tx_pcb))
+ pr_err("%s: couldn't send get statistics command\n", dev->name);
+ else {
+ unsigned long timeout = jiffies + TIMEOUT;
+ while (adapter->got[CMD_NETWORK_STATISTICS] == 0 && time_before(jiffies, timeout));
+ if (time_after_eq(jiffies, timeout)) {
+ TIMEOUT_MSG(__LINE__);
+ return &dev->stats;
+ }
+ }
+
+ /* statistics are now up to date */
+ return &dev->stats;
+}
+
+
+static void netdev_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+{
+ strcpy(info->driver, DRV_NAME);
+ strcpy(info->version, DRV_VERSION);
+ sprintf(info->bus_info, "ISA 0x%lx", dev->base_addr);
+}
+
+static u32 netdev_get_msglevel(struct net_device *dev)
+{
+ return debug;
+}
+
+static void netdev_set_msglevel(struct net_device *dev, u32 level)
+{
+ debug = level;
+}
+
+static const struct ethtool_ops netdev_ethtool_ops = {
+ .get_drvinfo = netdev_get_drvinfo,
+ .get_msglevel = netdev_get_msglevel,
+ .set_msglevel = netdev_set_msglevel,
+};
+
+/******************************************************
+ *
+ * close the board
+ *
+ ******************************************************/
+
+static int elp_close(struct net_device *dev)
+{
+ elp_device *adapter = netdev_priv(dev);
+
+ if (elp_debug >= 3)
+ pr_debug("%s: request to close device\n", dev->name);
+
+ netif_stop_queue(dev);
+
+ /* Someone may request the device statistic information even when
+ * the interface is closed. The following will update the statistics
+ * structure in the driver, so we'll be able to give current statistics.
+ */
+ (void) elp_get_stats(dev);
+
+ /*
+ * disable interrupts on the board
+ */
+ outb_control(0, dev);
+
+ /*
+ * release the IRQ
+ */
+ free_irq(dev->irq, dev);
+
+ free_dma(dev->dma);
+ free_pages((unsigned long) adapter->dma_buffer, get_order(DMA_BUFFER_SIZE));
+
+ return 0;
+}
+
+
+/************************************************************
+ *
+ * Set multicast list
+ * num_addrs==0: clear mc_list
+ * num_addrs==-1: set promiscuous mode
+ * num_addrs>0: set mc_list
+ *
+ ************************************************************/
+
+static void elp_set_mc_list(struct net_device *dev)
+{
+ elp_device *adapter = netdev_priv(dev);
+ struct netdev_hw_addr *ha;
+ int i;
+ unsigned long flags;
+
+ if (elp_debug >= 3)
+ pr_debug("%s: request to set multicast list\n", dev->name);
+
+ spin_lock_irqsave(&adapter->lock, flags);
+
+ if (!(dev->flags & (IFF_PROMISC | IFF_ALLMULTI))) {
+ /* send a "load multicast list" command to the board, max 10 addrs/cmd */
+ /* if num_addrs==0 the list will be cleared */
+ adapter->tx_pcb.command = CMD_LOAD_MULTICAST_LIST;
+ adapter->tx_pcb.length = 6 * netdev_mc_count(dev);
+ i = 0;
+ netdev_for_each_mc_addr(ha, dev)
+ memcpy(adapter->tx_pcb.data.multicast[i++],
+ ha->addr, 6);
+ adapter->got[CMD_LOAD_MULTICAST_LIST] = 0;
+ if (!send_pcb(dev, &adapter->tx_pcb))
+ pr_err("%s: couldn't send set_multicast command\n", dev->name);
+ else {
+ unsigned long timeout = jiffies + TIMEOUT;
+ while (adapter->got[CMD_LOAD_MULTICAST_LIST] == 0 && time_before(jiffies, timeout));
+ if (time_after_eq(jiffies, timeout)) {
+ TIMEOUT_MSG(__LINE__);
+ }
+ }
+ if (!netdev_mc_empty(dev))
+ adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_BROAD | RECV_MULTI;
+ else /* num_addrs == 0 */
+ adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_BROAD;
+ } else
+ adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_PROMISC;
+ /*
+ * configure adapter to receive messages (as specified above)
+ * and wait for response
+ */
+ if (elp_debug >= 3)
+ pr_debug("%s: sending 82586 configure command\n", dev->name);
+ adapter->tx_pcb.command = CMD_CONFIGURE_82586;
+ adapter->tx_pcb.length = 2;
+ adapter->got[CMD_CONFIGURE_82586] = 0;
+ if (!send_pcb(dev, &adapter->tx_pcb))
+ {
+ spin_unlock_irqrestore(&adapter->lock, flags);
+ pr_err("%s: couldn't send 82586 configure command\n", dev->name);
+ }
+ else {
+ unsigned long timeout = jiffies + TIMEOUT;
+ spin_unlock_irqrestore(&adapter->lock, flags);
+ while (adapter->got[CMD_CONFIGURE_82586] == 0 && time_before(jiffies, timeout));
+ if (time_after_eq(jiffies, timeout))
+ TIMEOUT_MSG(__LINE__);
+ }
+}
+
+/************************************************************
+ *
+ * A couple of tests to see if there's 3C505 or not
+ * Called only by elp_autodetect
+ ************************************************************/
+
+static int __init elp_sense(struct net_device *dev)
+{
+ int addr = dev->base_addr;
+ const char *name = dev->name;
+ byte orig_HSR;
+
+ if (!request_region(addr, ELP_IO_EXTENT, "3c505"))
+ return -ENODEV;
+
+ orig_HSR = inb_status(addr);
+
+ if (elp_debug > 0)
+ pr_debug(search_msg, name, addr);
+
+ if (orig_HSR == 0xff) {
+ if (elp_debug > 0)
+ pr_cont(notfound_msg, 1);
+ goto out;
+ }
+
+ /* Wait for a while; the adapter may still be booting up */
+ if (elp_debug > 0)
+ pr_cont(stilllooking_msg);
+
+ if (orig_HSR & DIR) {
+ /* If HCR.DIR is up, we pull it down. HSR.DIR should follow. */
+ outb(0, dev->base_addr + PORT_CONTROL);
+ msleep(300);
+ if (inb_status(addr) & DIR) {
+ if (elp_debug > 0)
+ pr_cont(notfound_msg, 2);
+ goto out;
+ }
+ } else {
+ /* If HCR.DIR is down, we pull it up. HSR.DIR should follow. */
+ outb(DIR, dev->base_addr + PORT_CONTROL);
+ msleep(300);
+ if (!(inb_status(addr) & DIR)) {
+ if (elp_debug > 0)
+ pr_cont(notfound_msg, 3);
+ goto out;
+ }
+ }
+ /*
+ * It certainly looks like a 3c505.
+ */
+ if (elp_debug > 0)
+ pr_cont(found_msg);
+
+ return 0;
+out:
+ release_region(addr, ELP_IO_EXTENT);
+ return -ENODEV;
+}
+
+/*************************************************************
+ *
+ * Search through addr_list[] and try to find a 3C505
+ * Called only by eplus_probe
+ *************************************************************/
+
+static int __init elp_autodetect(struct net_device *dev)
+{
+ int idx = 0;
+
+ /* if base address set, then only check that address
+ otherwise, run through the table */
+ if (dev->base_addr != 0) { /* dev->base_addr == 0 ==> plain autodetect */
+ if (elp_sense(dev) == 0)
+ return dev->base_addr;
+ } else
+ while ((dev->base_addr = addr_list[idx++])) {
+ if (elp_sense(dev) == 0)
+ return dev->base_addr;
+ }
+
+ /* could not find an adapter */
+ if (elp_debug > 0)
+ pr_debug(couldnot_msg, dev->name);
+
+ return 0; /* Because of this, the layer above will return -ENODEV */
+}
+
+static const struct net_device_ops elp_netdev_ops = {
+ .ndo_open = elp_open,
+ .ndo_stop = elp_close,
+ .ndo_get_stats = elp_get_stats,
+ .ndo_start_xmit = elp_start_xmit,
+ .ndo_tx_timeout = elp_timeout,
+ .ndo_set_multicast_list = elp_set_mc_list,
+ .ndo_change_mtu = eth_change_mtu,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+};
+
+/******************************************************
+ *
+ * probe for an Etherlink Plus board at the specified address
+ *
+ ******************************************************/
+
+/* There are three situations we need to be able to detect here:
+
+ * a) the card is idle
+ * b) the card is still booting up
+ * c) the card is stuck in a strange state (some DOS drivers do this)
+ *
+ * In case (a), all is well. In case (b), we wait 10 seconds to see if the
+ * card finishes booting, and carry on if so. In case (c), we do a hard reset,
+ * loop round, and hope for the best.
+ *
+ * This is all very unpleasant, but hopefully avoids the problems with the old
+ * probe code (which had a 15-second delay if the card was idle, and didn't
+ * work at all if it was in a weird state).
+ */
+
+static int __init elplus_setup(struct net_device *dev)
+{
+ elp_device *adapter = netdev_priv(dev);
+ int i, tries, tries1, okay;
+ unsigned long timeout;
+ unsigned long cookie = 0;
+ int err = -ENODEV;
+
+ /*
+ * setup adapter structure
+ */
+
+ dev->base_addr = elp_autodetect(dev);
+ if (!dev->base_addr)
+ return -ENODEV;
+
+ adapter->send_pcb_semaphore = 0;
+
+ for (tries1 = 0; tries1 < 3; tries1++) {
+ outb_control((adapter->hcr_val | CMDE) & ~DIR, dev);
+ /* First try to write just one byte, to see if the card is
+ * responding at all normally.
+ */
+ timeout = jiffies + 5*HZ/100;
+ okay = 0;
+ while (time_before(jiffies, timeout) && !(inb_status(dev->base_addr) & HCRE));
+ if ((inb_status(dev->base_addr) & HCRE)) {
+ outb_command(0, dev->base_addr); /* send a spurious byte */
+ timeout = jiffies + 5*HZ/100;
+ while (time_before(jiffies, timeout) && !(inb_status(dev->base_addr) & HCRE));
+ if (inb_status(dev->base_addr) & HCRE)
+ okay = 1;
+ }
+ if (!okay) {
+ /* Nope, it's ignoring the command register. This means that
+ * either it's still booting up, or it's died.
+ */
+ pr_err("%s: command register wouldn't drain, ", dev->name);
+ if ((inb_status(dev->base_addr) & 7) == 3) {
+ /* If the adapter status is 3, it *could* still be booting.
+ * Give it the benefit of the doubt for 10 seconds.
+ */
+ pr_cont("assuming 3c505 still starting\n");
+ timeout = jiffies + 10*HZ;
+ while (time_before(jiffies, timeout) && (inb_status(dev->base_addr) & 7));
+ if (inb_status(dev->base_addr) & 7) {
+ pr_err("%s: 3c505 failed to start\n", dev->name);
+ } else {
+ okay = 1; /* It started */
+ }
+ } else {
+ /* Otherwise, it must just be in a strange
+ * state. We probably need to kick it.
+ */
+ pr_cont("3c505 is sulking\n");
+ }
+ }
+ for (tries = 0; tries < 5 && okay; tries++) {
+
+ /*
+ * Try to set the Ethernet address, to make sure that the board
+ * is working.
+ */
+ adapter->tx_pcb.command = CMD_STATION_ADDRESS;
+ adapter->tx_pcb.length = 0;
+ cookie = probe_irq_on();
+ if (!send_pcb(dev, &adapter->tx_pcb)) {
+ pr_err("%s: could not send first PCB\n", dev->name);
+ probe_irq_off(cookie);
+ continue;
+ }
+ if (!receive_pcb(dev, &adapter->rx_pcb)) {
+ pr_err("%s: could not read first PCB\n", dev->name);
+ probe_irq_off(cookie);
+ continue;
+ }
+ if ((adapter->rx_pcb.command != CMD_ADDRESS_RESPONSE) ||
+ (adapter->rx_pcb.length != 6)) {
+ pr_err("%s: first PCB wrong (%d, %d)\n", dev->name,
+ adapter->rx_pcb.command, adapter->rx_pcb.length);
+ probe_irq_off(cookie);
+ continue;
+ }
+ goto okay;
+ }
+ /* It's broken. Do a hard reset to re-initialise the board,
+ * and try again.
+ */
+ pr_info("%s: resetting adapter\n", dev->name);
+ outb_control(adapter->hcr_val | FLSH | ATTN, dev);
+ outb_control(adapter->hcr_val & ~(FLSH | ATTN), dev);
+ }
+ pr_err("%s: failed to initialise 3c505\n", dev->name);
+ goto out;
+
+ okay:
+ if (dev->irq) { /* Is there a preset IRQ? */
+ int rpt = probe_irq_off(cookie);
+ if (dev->irq != rpt) {
+ pr_warning("%s: warning, irq %d configured but %d detected\n", dev->name, dev->irq, rpt);
+ }
+ /* if dev->irq == probe_irq_off(cookie), all is well */
+ } else /* No preset IRQ; just use what we can detect */
+ dev->irq = probe_irq_off(cookie);
+ switch (dev->irq) { /* Legal, sane? */
+ case 0:
+ pr_err("%s: IRQ probe failed: check 3c505 jumpers.\n",
+ dev->name);
+ goto out;
+ case 1:
+ case 6:
+ case 8:
+ case 13:
+ pr_err("%s: Impossible IRQ %d reported by probe_irq_off().\n",
+ dev->name, dev->irq);
+ goto out;
+ }
+ /*
+ * Now we have the IRQ number so we can disable the interrupts from
+ * the board until the board is opened.
+ */
+ outb_control(adapter->hcr_val & ~CMDE, dev);
+
+ /*
+ * copy Ethernet address into structure
+ */
+ for (i = 0; i < 6; i++)
+ dev->dev_addr[i] = adapter->rx_pcb.data.eth_addr[i];
+
+ /* find a DMA channel */
+ if (!dev->dma) {
+ if (dev->mem_start) {
+ dev->dma = dev->mem_start & 7;
+ }
+ else {
+ pr_warning("%s: warning, DMA channel not specified, using default\n", dev->name);
+ dev->dma = ELP_DMA;
+ }
+ }
+
+ /*
+ * print remainder of startup message
+ */
+ pr_info("%s: 3c505 at %#lx, irq %d, dma %d, addr %pM, ",
+ dev->name, dev->base_addr, dev->irq, dev->dma, dev->dev_addr);
+ /*
+ * read more information from the adapter
+ */
+
+ adapter->tx_pcb.command = CMD_ADAPTER_INFO;
+ adapter->tx_pcb.length = 0;
+ if (!send_pcb(dev, &adapter->tx_pcb) ||
+ !receive_pcb(dev, &adapter->rx_pcb) ||
+ (adapter->rx_pcb.command != CMD_ADAPTER_INFO_RESPONSE) ||
+ (adapter->rx_pcb.length != 10)) {
+ pr_cont("not responding to second PCB\n");
+ }
+ pr_cont("rev %d.%d, %dk\n", adapter->rx_pcb.data.info.major_vers,
+ adapter->rx_pcb.data.info.minor_vers, adapter->rx_pcb.data.info.RAM_sz);
+
+ /*
+ * reconfigure the adapter memory to better suit our purposes
+ */
+ adapter->tx_pcb.command = CMD_CONFIGURE_ADAPTER_MEMORY;
+ adapter->tx_pcb.length = 12;
+ adapter->tx_pcb.data.memconf.cmd_q = 8;
+ adapter->tx_pcb.data.memconf.rcv_q = 8;
+ adapter->tx_pcb.data.memconf.mcast = 10;
+ adapter->tx_pcb.data.memconf.frame = 10;
+ adapter->tx_pcb.data.memconf.rcv_b = 10;
+ adapter->tx_pcb.data.memconf.progs = 0;
+ if (!send_pcb(dev, &adapter->tx_pcb) ||
+ !receive_pcb(dev, &adapter->rx_pcb) ||
+ (adapter->rx_pcb.command != CMD_CONFIGURE_ADAPTER_RESPONSE) ||
+ (adapter->rx_pcb.length != 2)) {
+ pr_err("%s: could not configure adapter memory\n", dev->name);
+ }
+ if (adapter->rx_pcb.data.configure) {
+ pr_err("%s: adapter configuration failed\n", dev->name);
+ }
+
+ dev->netdev_ops = &elp_netdev_ops;
+ dev->watchdog_timeo = 10*HZ;
+ dev->ethtool_ops = &netdev_ethtool_ops; /* local */
+
+ dev->mem_start = dev->mem_end = 0;
+
+ err = register_netdev(dev);
+ if (err)
+ goto out;
+
+ return 0;
+out:
+ release_region(dev->base_addr, ELP_IO_EXTENT);
+ return err;
+}
+
+#ifndef MODULE
+struct net_device * __init elplus_probe(int unit)
+{
+ struct net_device *dev = alloc_etherdev(sizeof(elp_device));
+ int err;
+ if (!dev)
+ return ERR_PTR(-ENOMEM);
+
+ sprintf(dev->name, "eth%d", unit);
+ netdev_boot_setup_check(dev);
+
+ err = elplus_setup(dev);
+ if (err) {
+ free_netdev(dev);
+ return ERR_PTR(err);
+ }
+ return dev;
+}
+
+#else
+static struct net_device *dev_3c505[ELP_MAX_CARDS];
+static int io[ELP_MAX_CARDS];
+static int irq[ELP_MAX_CARDS];
+static int dma[ELP_MAX_CARDS];
+module_param_array(io, int, NULL, 0);
+module_param_array(irq, int, NULL, 0);
+module_param_array(dma, int, NULL, 0);
+MODULE_PARM_DESC(io, "EtherLink Plus I/O base address(es)");
+MODULE_PARM_DESC(irq, "EtherLink Plus IRQ number(s) (assigned)");
+MODULE_PARM_DESC(dma, "EtherLink Plus DMA channel(s)");
+
+int __init init_module(void)
+{
+ int this_dev, found = 0;
+
+ for (this_dev = 0; this_dev < ELP_MAX_CARDS; this_dev++) {
+ struct net_device *dev = alloc_etherdev(sizeof(elp_device));
+ if (!dev)
+ break;
+
+ dev->irq = irq[this_dev];
+ dev->base_addr = io[this_dev];
+ if (dma[this_dev]) {
+ dev->dma = dma[this_dev];
+ } else {
+ dev->dma = ELP_DMA;
+ pr_warning("3c505.c: warning, using default DMA channel,\n");
+ }
+ if (io[this_dev] == 0) {
+ if (this_dev) {
+ free_netdev(dev);
+ break;
+ }
+ pr_notice("3c505.c: module autoprobe not recommended, give io=xx.\n");
+ }
+ if (elplus_setup(dev) != 0) {
+ pr_warning("3c505.c: Failed to register card at 0x%x.\n", io[this_dev]);
+ free_netdev(dev);
+ break;
+ }
+ dev_3c505[this_dev] = dev;
+ found++;
+ }
+ if (!found)
+ return -ENODEV;
+ return 0;
+}
+
+void __exit cleanup_module(void)
+{
+ int this_dev;
+
+ for (this_dev = 0; this_dev < ELP_MAX_CARDS; this_dev++) {
+ struct net_device *dev = dev_3c505[this_dev];
+ if (dev) {
+ unregister_netdev(dev);
+ release_region(dev->base_addr, ELP_IO_EXTENT);
+ free_netdev(dev);
+ }
+ }
+}
+
+#endif /* MODULE */
+MODULE_LICENSE("GPL");
--- /dev/null
+/*****************************************************************
+ *
+ * defines for 3Com Etherlink Plus adapter
+ *
+ *****************************************************************/
+
+#define ELP_DMA 6
+#define ELP_RX_PCBS 4
+#define ELP_MAX_CARDS 4
+
+/*
+ * I/O register offsets
+ */
+#define PORT_COMMAND 0x00 /* read/write, 8-bit */
+#define PORT_STATUS 0x02 /* read only, 8-bit */
+#define PORT_AUXDMA 0x02 /* write only, 8-bit */
+#define PORT_DATA 0x04 /* read/write, 16-bit */
+#define PORT_CONTROL 0x06 /* read/write, 8-bit */
+
+#define ELP_IO_EXTENT 0x10 /* size of used IO registers */
+
+/*
+ * host control registers bits
+ */
+#define ATTN 0x80 /* attention */
+#define FLSH 0x40 /* flush data register */
+#define DMAE 0x20 /* DMA enable */
+#define DIR 0x10 /* direction */
+#define TCEN 0x08 /* terminal count interrupt enable */
+#define CMDE 0x04 /* command register interrupt enable */
+#define HSF2 0x02 /* host status flag 2 */
+#define HSF1 0x01 /* host status flag 1 */
+
+/*
+ * combinations of HSF flags used for PCB transmission
+ */
+#define HSF_PCB_ACK HSF1
+#define HSF_PCB_NAK HSF2
+#define HSF_PCB_END (HSF2|HSF1)
+#define HSF_PCB_MASK (HSF2|HSF1)
+
+/*
+ * host status register bits
+ */
+#define HRDY 0x80 /* data register ready */
+#define HCRE 0x40 /* command register empty */
+#define ACRF 0x20 /* adapter command register full */
+/* #define DIR 0x10 direction - same as in control register */
+#define DONE 0x08 /* DMA done */
+#define ASF3 0x04 /* adapter status flag 3 */
+#define ASF2 0x02 /* adapter status flag 2 */
+#define ASF1 0x01 /* adapter status flag 1 */
+
+/*
+ * combinations of ASF flags used for PCB reception
+ */
+#define ASF_PCB_ACK ASF1
+#define ASF_PCB_NAK ASF2
+#define ASF_PCB_END (ASF2|ASF1)
+#define ASF_PCB_MASK (ASF2|ASF1)
+
+/*
+ * host aux DMA register bits
+ */
+#define DMA_BRST 0x01 /* DMA burst */
+
+/*
+ * maximum amount of data allowed in a PCB
+ */
+#define MAX_PCB_DATA 62
+
+/*****************************************************************
+ *
+ * timeout value
+ * this is a rough value used for loops to stop them from
+ * locking up the whole machine in the case of failure or
+ * error conditions
+ *
+ *****************************************************************/
+
+#define TIMEOUT 300
+
+/*****************************************************************
+ *
+ * PCB commands
+ *
+ *****************************************************************/
+
+enum {
+ /*
+ * host PCB commands
+ */
+ CMD_CONFIGURE_ADAPTER_MEMORY = 0x01,
+ CMD_CONFIGURE_82586 = 0x02,
+ CMD_STATION_ADDRESS = 0x03,
+ CMD_DMA_DOWNLOAD = 0x04,
+ CMD_DMA_UPLOAD = 0x05,
+ CMD_PIO_DOWNLOAD = 0x06,
+ CMD_PIO_UPLOAD = 0x07,
+ CMD_RECEIVE_PACKET = 0x08,
+ CMD_TRANSMIT_PACKET = 0x09,
+ CMD_NETWORK_STATISTICS = 0x0a,
+ CMD_LOAD_MULTICAST_LIST = 0x0b,
+ CMD_CLEAR_PROGRAM = 0x0c,
+ CMD_DOWNLOAD_PROGRAM = 0x0d,
+ CMD_EXECUTE_PROGRAM = 0x0e,
+ CMD_SELF_TEST = 0x0f,
+ CMD_SET_STATION_ADDRESS = 0x10,
+ CMD_ADAPTER_INFO = 0x11,
+ NUM_TRANSMIT_CMDS,
+
+ /*
+ * adapter PCB commands
+ */
+ CMD_CONFIGURE_ADAPTER_RESPONSE = 0x31,
+ CMD_CONFIGURE_82586_RESPONSE = 0x32,
+ CMD_ADDRESS_RESPONSE = 0x33,
+ CMD_DOWNLOAD_DATA_REQUEST = 0x34,
+ CMD_UPLOAD_DATA_REQUEST = 0x35,
+ CMD_RECEIVE_PACKET_COMPLETE = 0x38,
+ CMD_TRANSMIT_PACKET_COMPLETE = 0x39,
+ CMD_NETWORK_STATISTICS_RESPONSE = 0x3a,
+ CMD_LOAD_MULTICAST_RESPONSE = 0x3b,
+ CMD_CLEAR_PROGRAM_RESPONSE = 0x3c,
+ CMD_DOWNLOAD_PROGRAM_RESPONSE = 0x3d,
+ CMD_EXECUTE_RESPONSE = 0x3e,
+ CMD_SELF_TEST_RESPONSE = 0x3f,
+ CMD_SET_ADDRESS_RESPONSE = 0x40,
+ CMD_ADAPTER_INFO_RESPONSE = 0x41
+};
+
+/* Definitions for the PCB data structure */
+
+/* Data units */
+typedef unsigned char byte;
+typedef unsigned short int word;
+typedef unsigned long int dword;
+
+/* Data structures */
+struct Memconf {
+ word cmd_q,
+ rcv_q,
+ mcast,
+ frame,
+ rcv_b,
+ progs;
+};
+
+struct Rcv_pkt {
+ word buf_ofs,
+ buf_seg,
+ buf_len,
+ timeout;
+};
+
+struct Xmit_pkt {
+ word buf_ofs,
+ buf_seg,
+ pkt_len;
+};
+
+struct Rcv_resp {
+ word buf_ofs,
+ buf_seg,
+ buf_len,
+ pkt_len,
+ timeout,
+ status;
+ dword timetag;
+};
+
+struct Xmit_resp {
+ word buf_ofs,
+ buf_seg,
+ c_stat,
+ status;
+};
+
+
+struct Netstat {
+ dword tot_recv,
+ tot_xmit;
+ word err_CRC,
+ err_align,
+ err_res,
+ err_ovrrun;
+};
+
+
+struct Selftest {
+ word error;
+ union {
+ word ROM_cksum;
+ struct {
+ word ofs, seg;
+ } RAM;
+ word i82586;
+ } failure;
+};
+
+struct Info {
+ byte minor_vers,
+ major_vers;
+ word ROM_cksum,
+ RAM_sz,
+ free_ofs,
+ free_seg;
+};
+
+struct Memdump {
+ word size,
+ off,
+ seg;
+};
+
+/*
+Primary Command Block. The most important data structure. All communication
+between the host and the adapter is done with these. (Except for the actual
+Ethernet data, which has different packaging.)
+*/
+typedef struct {
+ byte command;
+ byte length;
+ union {
+ struct Memconf memconf;
+ word configure;
+ struct Rcv_pkt rcv_pkt;
+ struct Xmit_pkt xmit_pkt;
+ byte multicast[10][6];
+ byte eth_addr[6];
+ byte failed;
+ struct Rcv_resp rcv_resp;
+ struct Xmit_resp xmit_resp;
+ struct Netstat netstat;
+ struct Selftest selftest;
+ struct Info info;
+ struct Memdump memdump;
+ byte raw[62];
+ } data;
+} pcb_struct;
+
+/* These defines for 'configure' */
+#define RECV_STATION 0x00
+#define RECV_BROAD 0x01
+#define RECV_MULTI 0x02
+#define RECV_PROMISC 0x04
+#define NO_LOOPBACK 0x00
+#define INT_LOOPBACK 0x08
+#define EXT_LOOPBACK 0x10
+
+/*****************************************************************
+ *
+ * structure to hold context information for adapter
+ *
+ *****************************************************************/
+
+#define DMA_BUFFER_SIZE 1600
+#define BACKLOG_SIZE 4
+
+typedef struct {
+ volatile short got[NUM_TRANSMIT_CMDS]; /* flags for
+ command completion */
+ pcb_struct tx_pcb; /* PCB for foreground sending */
+ pcb_struct rx_pcb; /* PCB for foreground receiving */
+ pcb_struct itx_pcb; /* PCB for background sending */
+ pcb_struct irx_pcb; /* PCB for background receiving */
+
+ void *dma_buffer;
+
+ struct {
+ unsigned int length[BACKLOG_SIZE];
+ unsigned int in;
+ unsigned int out;
+ } rx_backlog;
+
+ struct {
+ unsigned int direction;
+ unsigned int length;
+ struct sk_buff *skb;
+ void *target;
+ unsigned long start_time;
+ } current_dma;
+
+ /* flags */
+ unsigned long send_pcb_semaphore;
+ unsigned long dmaing;
+ unsigned long busy;
+
+ unsigned int rx_active; /* number of receive PCBs */
+ volatile unsigned char hcr_val; /* what we think the HCR contains */
+ spinlock_t lock; /* Interrupt v tx lock */
+} elp_device;
--- /dev/null
+/* 3c507.c: An EtherLink16 device driver for Linux. */
+/*
+ Written 1993,1994 by Donald Becker.
+
+ Copyright 1993 United States Government as represented by the
+ Director, National Security Agency.
+
+ This software may be used and distributed according to the terms
+ of the GNU General Public License, incorporated herein by reference.
+
+ The author may be reached as becker@scyld.com, or C/O
+ Scyld Computing Corporation
+ 410 Severn Ave., Suite 210
+ Annapolis MD 21403
+
+
+ Thanks go to jennings@Montrouge.SMR.slb.com ( Patrick Jennings)
+ and jrs@world.std.com (Rick Sladkey) for testing and bugfixes.
+ Mark Salazar <leslie@access.digex.net> made the changes for cards with
+ only 16K packet buffers.
+
+ Things remaining to do:
+ Verify that the tx and rx buffers don't have fencepost errors.
+ Move the theory of operation and memory map documentation.
+ The statistics need to be updated correctly.
+*/
+
+#define DRV_NAME "3c507"
+#define DRV_VERSION "1.10a"
+#define DRV_RELDATE "11/17/2001"
+
+static const char version[] =
+ DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " Donald Becker (becker@scyld.com)\n";
+
+/*
+ Sources:
+ This driver wouldn't have been written with the availability of the
+ Crynwr driver source code. It provided a known-working implementation
+ that filled in the gaping holes of the Intel documentation. Three cheers
+ for Russ Nelson.
+
+ Intel Microcommunications Databook, Vol. 1, 1990. It provides just enough
+ info that the casual reader might think that it documents the i82586 :-<.
+*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/string.h>
+#include <linux/spinlock.h>
+#include <linux/ethtool.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/if_ether.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+/* use 0 for production, 1 for verification, 2..7 for debug */
+#ifndef NET_DEBUG
+#define NET_DEBUG 1
+#endif
+static unsigned int net_debug = NET_DEBUG;
+#define debug net_debug
+
+
+/*
+ Details of the i82586.
+
+ You'll really need the databook to understand the details of this part,
+ but the outline is that the i82586 has two separate processing units.
+ Both are started from a list of three configuration tables, of which only
+ the last, the System Control Block (SCB), is used after reset-time. The SCB
+ has the following fields:
+ Status word
+ Command word
+ Tx/Command block addr.
+ Rx block addr.
+ The command word accepts the following controls for the Tx and Rx units:
+ */
+
+#define CUC_START 0x0100
+#define CUC_RESUME 0x0200
+#define CUC_SUSPEND 0x0300
+#define RX_START 0x0010
+#define RX_RESUME 0x0020
+#define RX_SUSPEND 0x0030
+
+/* The Rx unit uses a list of frame descriptors and a list of data buffer
+ descriptors. We use full-sized (1518 byte) data buffers, so there is
+ a one-to-one pairing of frame descriptors to buffer descriptors.
+
+ The Tx ("command") unit executes a list of commands that look like:
+ Status word Written by the 82586 when the command is done.
+ Command word Command in lower 3 bits, post-command action in upper 3
+ Link word The address of the next command.
+ Parameters (as needed).
+
+ Some definitions related to the Command Word are:
+ */
+#define CMD_EOL 0x8000 /* The last command of the list, stop. */
+#define CMD_SUSP 0x4000 /* Suspend after doing cmd. */
+#define CMD_INTR 0x2000 /* Interrupt after doing cmd. */
+
+enum commands {
+ CmdNOp = 0, CmdSASetup = 1, CmdConfigure = 2, CmdMulticastList = 3,
+ CmdTx = 4, CmdTDR = 5, CmdDump = 6, CmdDiagnose = 7};
+
+/* Information that need to be kept for each board. */
+struct net_local {
+ int last_restart;
+ ushort rx_head;
+ ushort rx_tail;
+ ushort tx_head;
+ ushort tx_cmd_link;
+ ushort tx_reap;
+ ushort tx_pkts_in_ring;
+ spinlock_t lock;
+ void __iomem *base;
+};
+
+/*
+ Details of the EtherLink16 Implementation
+ The 3c507 is a generic shared-memory i82586 implementation.
+ The host can map 16K, 32K, 48K, or 64K of the 64K memory into
+ 0x0[CD][08]0000, or all 64K into 0xF[02468]0000.
+ */
+
+/* Offsets from the base I/O address. */
+#define SA_DATA 0 /* Station address data, or 3Com signature. */
+#define MISC_CTRL 6 /* Switch the SA_DATA banks, and bus config bits. */
+#define RESET_IRQ 10 /* Reset the latched IRQ line. */
+#define SIGNAL_CA 11 /* Frob the 82586 Channel Attention line. */
+#define ROM_CONFIG 13
+#define MEM_CONFIG 14
+#define IRQ_CONFIG 15
+#define EL16_IO_EXTENT 16
+
+/* The ID port is used at boot-time to locate the ethercard. */
+#define ID_PORT 0x100
+
+/* Offsets to registers in the mailbox (SCB). */
+#define iSCB_STATUS 0x8
+#define iSCB_CMD 0xA
+#define iSCB_CBL 0xC /* Command BLock offset. */
+#define iSCB_RFA 0xE /* Rx Frame Area offset. */
+
+/* Since the 3c507 maps the shared memory window so that the last byte is
+ at 82586 address FFFF, the first byte is at 82586 address 0, 16K, 32K, or
+ 48K corresponding to window sizes of 64K, 48K, 32K and 16K respectively.
+ We can account for this be setting the 'SBC Base' entry in the ISCP table
+ below for all the 16 bit offset addresses, and also adding the 'SCB Base'
+ value to all 24 bit physical addresses (in the SCP table and the TX and RX
+ Buffer Descriptors).
+ -Mark
+ */
+#define SCB_BASE ((unsigned)64*1024 - (dev->mem_end - dev->mem_start))
+
+/*
+ What follows in 'init_words[]' is the "program" that is downloaded to the
+ 82586 memory. It's mostly tables and command blocks, and starts at the
+ reset address 0xfffff6. This is designed to be similar to the EtherExpress,
+ thus the unusual location of the SCB at 0x0008.
+
+ Even with the additional "don't care" values, doing it this way takes less
+ program space than initializing the individual tables, and I feel it's much
+ cleaner.
+
+ The databook is particularly useless for the first two structures, I had
+ to use the Crynwr driver as an example.
+
+ The memory setup is as follows:
+ */
+
+#define CONFIG_CMD 0x0018
+#define SET_SA_CMD 0x0024
+#define SA_OFFSET 0x002A
+#define IDLELOOP 0x30
+#define TDR_CMD 0x38
+#define TDR_TIME 0x3C
+#define DUMP_CMD 0x40
+#define DIAG_CMD 0x48
+#define SET_MC_CMD 0x4E
+#define DUMP_DATA 0x56 /* A 170 byte buffer for dump and Set-MC into. */
+
+#define TX_BUF_START 0x0100
+#define NUM_TX_BUFS 5
+#define TX_BUF_SIZE (1518+14+20+16) /* packet+header+TBD */
+
+#define RX_BUF_START 0x2000
+#define RX_BUF_SIZE (1518+14+18) /* packet+header+RBD */
+#define RX_BUF_END (dev->mem_end - dev->mem_start)
+
+#define TX_TIMEOUT (HZ/20)
+
+/*
+ That's it: only 86 bytes to set up the beast, including every extra
+ command available. The 170 byte buffer at DUMP_DATA is shared between the
+ Dump command (called only by the diagnostic program) and the SetMulticastList
+ command.
+
+ To complete the memory setup you only have to write the station address at
+ SA_OFFSET and create the Tx & Rx buffer lists.
+
+ The Tx command chain and buffer list is setup as follows:
+ A Tx command table, with the data buffer pointing to...
+ A Tx data buffer descriptor. The packet is in a single buffer, rather than
+ chaining together several smaller buffers.
+ A NoOp command, which initially points to itself,
+ And the packet data.
+
+ A transmit is done by filling in the Tx command table and data buffer,
+ re-writing the NoOp command, and finally changing the offset of the last
+ command to point to the current Tx command. When the Tx command is finished,
+ it jumps to the NoOp, when it loops until the next Tx command changes the
+ "link offset" in the NoOp. This way the 82586 never has to go through the
+ slow restart sequence.
+
+ The Rx buffer list is set up in the obvious ring structure. We have enough
+ memory (and low enough interrupt latency) that we can avoid the complicated
+ Rx buffer linked lists by alway associating a full-size Rx data buffer with
+ each Rx data frame.
+
+ I current use four transmit buffers starting at TX_BUF_START (0x0100), and
+ use the rest of memory, from RX_BUF_START to RX_BUF_END, for Rx buffers.
+
+ */
+
+static unsigned short init_words[] = {
+ /* System Configuration Pointer (SCP). */
+ 0x0000, /* Set bus size to 16 bits. */
+ 0,0, /* pad words. */
+ 0x0000,0x0000, /* ISCP phys addr, set in init_82586_mem(). */
+
+ /* Intermediate System Configuration Pointer (ISCP). */
+ 0x0001, /* Status word that's cleared when init is done. */
+ 0x0008,0,0, /* SCB offset, (skip, skip) */
+
+ /* System Control Block (SCB). */
+ 0,0xf000|RX_START|CUC_START, /* SCB status and cmd. */
+ CONFIG_CMD, /* Command list pointer, points to Configure. */
+ RX_BUF_START, /* Rx block list. */
+ 0,0,0,0, /* Error count: CRC, align, buffer, overrun. */
+
+ /* 0x0018: Configure command. Change to put MAC data with packet. */
+ 0, CmdConfigure, /* Status, command. */
+ SET_SA_CMD, /* Next command is Set Station Addr. */
+ 0x0804, /* "4" bytes of config data, 8 byte FIFO. */
+ 0x2e40, /* Magic values, including MAC data location. */
+ 0, /* Unused pad word. */
+
+ /* 0x0024: Setup station address command. */
+ 0, CmdSASetup,
+ SET_MC_CMD, /* Next command. */
+ 0xaa00,0xb000,0x0bad, /* Station address (to be filled in) */
+
+ /* 0x0030: NOP, looping back to itself. Point to first Tx buffer to Tx. */
+ 0, CmdNOp, IDLELOOP, 0 /* pad */,
+
+ /* 0x0038: A unused Time-Domain Reflectometer command. */
+ 0, CmdTDR, IDLELOOP, 0,
+
+ /* 0x0040: An unused Dump State command. */
+ 0, CmdDump, IDLELOOP, DUMP_DATA,
+
+ /* 0x0048: An unused Diagnose command. */
+ 0, CmdDiagnose, IDLELOOP,
+
+ /* 0x004E: An empty set-multicast-list command. */
+ 0, CmdMulticastList, IDLELOOP, 0,
+};
+
+/* Index to functions, as function prototypes. */
+
+static int el16_probe1(struct net_device *dev, int ioaddr);
+static int el16_open(struct net_device *dev);
+static netdev_tx_t el16_send_packet(struct sk_buff *skb,
+ struct net_device *dev);
+static irqreturn_t el16_interrupt(int irq, void *dev_id);
+static void el16_rx(struct net_device *dev);
+static int el16_close(struct net_device *dev);
+static void el16_tx_timeout (struct net_device *dev);
+
+static void hardware_send_packet(struct net_device *dev, void *buf, short length, short pad);
+static void init_82586_mem(struct net_device *dev);
+static const struct ethtool_ops netdev_ethtool_ops;
+static void init_rx_bufs(struct net_device *);
+
+static int io = 0x300;
+static int irq;
+static int mem_start;
+
+
+/* Check for a network adaptor of this type, and return '0' iff one exists.
+ If dev->base_addr == 0, probe all likely locations.
+ If dev->base_addr == 1, always return failure.
+ If dev->base_addr == 2, (detachable devices only) allocate space for the
+ device and return success.
+ */
+
+struct net_device * __init el16_probe(int unit)
+{
+ struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
+ static const unsigned ports[] = { 0x300, 0x320, 0x340, 0x280, 0};
+ const unsigned *port;
+ int err = -ENODEV;
+
+ if (!dev)
+ return ERR_PTR(-ENODEV);
+
+ if (unit >= 0) {
+ sprintf(dev->name, "eth%d", unit);
+ netdev_boot_setup_check(dev);
+ io = dev->base_addr;
+ irq = dev->irq;
+ mem_start = dev->mem_start & 15;
+ }
+
+ if (io > 0x1ff) /* Check a single specified location. */
+ err = el16_probe1(dev, io);
+ else if (io != 0)
+ err = -ENXIO; /* Don't probe at all. */
+ else {
+ for (port = ports; *port; port++) {
+ err = el16_probe1(dev, *port);
+ if (!err)
+ break;
+ }
+ }
+
+ if (err)
+ goto out;
+ err = register_netdev(dev);
+ if (err)
+ goto out1;
+ return dev;
+out1:
+ free_irq(dev->irq, dev);
+ iounmap(((struct net_local *)netdev_priv(dev))->base);
+ release_region(dev->base_addr, EL16_IO_EXTENT);
+out:
+ free_netdev(dev);
+ return ERR_PTR(err);
+}
+
+static const struct net_device_ops netdev_ops = {
+ .ndo_open = el16_open,
+ .ndo_stop = el16_close,
+ .ndo_start_xmit = el16_send_packet,
+ .ndo_tx_timeout = el16_tx_timeout,
+ .ndo_change_mtu = eth_change_mtu,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+};
+
+static int __init el16_probe1(struct net_device *dev, int ioaddr)
+{
+ static unsigned char init_ID_done;
+ int i, irq, irqval, retval;
+ struct net_local *lp;
+
+ if (init_ID_done == 0) {
+ ushort lrs_state = 0xff;
+ /* Send the ID sequence to the ID_PORT to enable the board(s). */
+ outb(0x00, ID_PORT);
+ for(i = 0; i < 255; i++) {
+ outb(lrs_state, ID_PORT);
+ lrs_state <<= 1;
+ if (lrs_state & 0x100)
+ lrs_state ^= 0xe7;
+ }
+ outb(0x00, ID_PORT);
+ init_ID_done = 1;
+ }
+
+ if (!request_region(ioaddr, EL16_IO_EXTENT, DRV_NAME))
+ return -ENODEV;
+
+ if ((inb(ioaddr) != '*') || (inb(ioaddr + 1) != '3') ||
+ (inb(ioaddr + 2) != 'C') || (inb(ioaddr + 3) != 'O')) {
+ retval = -ENODEV;
+ goto out;
+ }
+
+ pr_info("%s: 3c507 at %#x,", dev->name, ioaddr);
+
+ /* We should make a few more checks here, like the first three octets of
+ the S.A. for the manufacturer's code. */
+
+ irq = inb(ioaddr + IRQ_CONFIG) & 0x0f;
+
+ irqval = request_irq(irq, el16_interrupt, 0, DRV_NAME, dev);
+ if (irqval) {
+ pr_cont("\n");
+ pr_err("3c507: unable to get IRQ %d (irqval=%d).\n", irq, irqval);
+ retval = -EAGAIN;
+ goto out;
+ }
+
+ /* We've committed to using the board, and can start filling in *dev. */
+ dev->base_addr = ioaddr;
+
+ outb(0x01, ioaddr + MISC_CTRL);
+ for (i = 0; i < 6; i++)
+ dev->dev_addr[i] = inb(ioaddr + i);
+ pr_cont(" %pM", dev->dev_addr);
+
+ if (mem_start)
+ net_debug = mem_start & 7;
+
+#ifdef MEM_BASE
+ dev->mem_start = MEM_BASE;
+ dev->mem_end = dev->mem_start + 0x10000;
+#else
+ {
+ int base;
+ int size;
+ char mem_config = inb(ioaddr + MEM_CONFIG);
+ if (mem_config & 0x20) {
+ size = 64*1024;
+ base = 0xf00000 + (mem_config & 0x08 ? 0x080000
+ : ((mem_config & 3) << 17));
+ } else {
+ size = ((mem_config & 3) + 1) << 14;
+ base = 0x0c0000 + ( (mem_config & 0x18) << 12);
+ }
+ dev->mem_start = base;
+ dev->mem_end = base + size;
+ }
+#endif
+
+ dev->if_port = (inb(ioaddr + ROM_CONFIG) & 0x80) ? 1 : 0;
+ dev->irq = inb(ioaddr + IRQ_CONFIG) & 0x0f;
+
+ pr_cont(", IRQ %d, %sternal xcvr, memory %#lx-%#lx.\n", dev->irq,
+ dev->if_port ? "ex" : "in", dev->mem_start, dev->mem_end-1);
+
+ if (net_debug)
+ pr_debug("%s", version);
+
+ lp = netdev_priv(dev);
+ spin_lock_init(&lp->lock);
+ lp->base = ioremap(dev->mem_start, RX_BUF_END);
+ if (!lp->base) {
+ pr_err("3c507: unable to remap memory\n");
+ retval = -EAGAIN;
+ goto out1;
+ }
+
+ dev->netdev_ops = &netdev_ops;
+ dev->watchdog_timeo = TX_TIMEOUT;
+ dev->ethtool_ops = &netdev_ethtool_ops;
+ dev->flags &= ~IFF_MULTICAST; /* Multicast doesn't work */
+ return 0;
+out1:
+ free_irq(dev->irq, dev);
+out:
+ release_region(ioaddr, EL16_IO_EXTENT);
+ return retval;
+}
+
+static int el16_open(struct net_device *dev)
+{
+ /* Initialize the 82586 memory and start it. */
+ init_82586_mem(dev);
+
+ netif_start_queue(dev);
+ return 0;
+}
+
+
+static void el16_tx_timeout (struct net_device *dev)
+{
+ struct net_local *lp = netdev_priv(dev);
+ int ioaddr = dev->base_addr;
+ void __iomem *shmem = lp->base;
+
+ if (net_debug > 1)
+ pr_debug("%s: transmit timed out, %s? ", dev->name,
+ readw(shmem + iSCB_STATUS) & 0x8000 ? "IRQ conflict" :
+ "network cable problem");
+ /* Try to restart the adaptor. */
+ if (lp->last_restart == dev->stats.tx_packets) {
+ if (net_debug > 1)
+ pr_cont("Resetting board.\n");
+ /* Completely reset the adaptor. */
+ init_82586_mem (dev);
+ lp->tx_pkts_in_ring = 0;
+ } else {
+ /* Issue the channel attention signal and hope it "gets better". */
+ if (net_debug > 1)
+ pr_cont("Kicking board.\n");
+ writew(0xf000 | CUC_START | RX_START, shmem + iSCB_CMD);
+ outb (0, ioaddr + SIGNAL_CA); /* Issue channel-attn. */
+ lp->last_restart = dev->stats.tx_packets;
+ }
+ dev->trans_start = jiffies; /* prevent tx timeout */
+ netif_wake_queue (dev);
+}
+
+
+static netdev_tx_t el16_send_packet (struct sk_buff *skb,
+ struct net_device *dev)
+{
+ struct net_local *lp = netdev_priv(dev);
+ int ioaddr = dev->base_addr;
+ unsigned long flags;
+ short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+ unsigned char *buf = skb->data;
+
+ netif_stop_queue (dev);
+
+ spin_lock_irqsave (&lp->lock, flags);
+
+ dev->stats.tx_bytes += length;
+ /* Disable the 82586's input to the interrupt line. */
+ outb (0x80, ioaddr + MISC_CTRL);
+
+ hardware_send_packet (dev, buf, skb->len, length - skb->len);
+
+ /* Enable the 82586 interrupt input. */
+ outb (0x84, ioaddr + MISC_CTRL);
+
+ spin_unlock_irqrestore (&lp->lock, flags);
+
+ dev_kfree_skb (skb);
+
+ /* You might need to clean up and record Tx statistics here. */
+
+ return NETDEV_TX_OK;
+}
+
+/* The typical workload of the driver:
+ Handle the network interface interrupts. */
+static irqreturn_t el16_interrupt(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct net_local *lp;
+ int ioaddr, status, boguscount = 0;
+ ushort ack_cmd = 0;
+ void __iomem *shmem;
+
+ if (dev == NULL) {
+ pr_err("net_interrupt(): irq %d for unknown device.\n", irq);
+ return IRQ_NONE;
+ }
+
+ ioaddr = dev->base_addr;
+ lp = netdev_priv(dev);
+ shmem = lp->base;
+
+ spin_lock(&lp->lock);
+
+ status = readw(shmem+iSCB_STATUS);
+
+ if (net_debug > 4) {
+ pr_debug("%s: 3c507 interrupt, status %4.4x.\n", dev->name, status);
+ }
+
+ /* Disable the 82586's input to the interrupt line. */
+ outb(0x80, ioaddr + MISC_CTRL);
+
+ /* Reap the Tx packet buffers. */
+ while (lp->tx_pkts_in_ring) {
+ unsigned short tx_status = readw(shmem+lp->tx_reap);
+ if (!(tx_status & 0x8000)) {
+ if (net_debug > 5)
+ pr_debug("Tx command incomplete (%#x).\n", lp->tx_reap);
+ break;
+ }
+ /* Tx unsuccessful or some interesting status bit set. */
+ if (!(tx_status & 0x2000) || (tx_status & 0x0f3f)) {
+ dev->stats.tx_errors++;
+ if (tx_status & 0x0600) dev->stats.tx_carrier_errors++;
+ if (tx_status & 0x0100) dev->stats.tx_fifo_errors++;
+ if (!(tx_status & 0x0040)) dev->stats.tx_heartbeat_errors++;
+ if (tx_status & 0x0020) dev->stats.tx_aborted_errors++;
+ dev->stats.collisions += tx_status & 0xf;
+ }
+ dev->stats.tx_packets++;
+ if (net_debug > 5)
+ pr_debug("Reaped %x, Tx status %04x.\n" , lp->tx_reap, tx_status);
+ lp->tx_reap += TX_BUF_SIZE;
+ if (lp->tx_reap > RX_BUF_START - TX_BUF_SIZE)
+ lp->tx_reap = TX_BUF_START;
+
+ lp->tx_pkts_in_ring--;
+ /* There is always more space in the Tx ring buffer now. */
+ netif_wake_queue(dev);
+
+ if (++boguscount > 10)
+ break;
+ }
+
+ if (status & 0x4000) { /* Packet received. */
+ if (net_debug > 5)
+ pr_debug("Received packet, rx_head %04x.\n", lp->rx_head);
+ el16_rx(dev);
+ }
+
+ /* Acknowledge the interrupt sources. */
+ ack_cmd = status & 0xf000;
+
+ if ((status & 0x0700) != 0x0200 && netif_running(dev)) {
+ if (net_debug)
+ pr_debug("%s: Command unit stopped, status %04x, restarting.\n",
+ dev->name, status);
+ /* If this ever occurs we should really re-write the idle loop, reset
+ the Tx list, and do a complete restart of the command unit.
+ For now we rely on the Tx timeout if the resume doesn't work. */
+ ack_cmd |= CUC_RESUME;
+ }
+
+ if ((status & 0x0070) != 0x0040 && netif_running(dev)) {
+ /* The Rx unit is not ready, it must be hung. Restart the receiver by
+ initializing the rx buffers, and issuing an Rx start command. */
+ if (net_debug)
+ pr_debug("%s: Rx unit stopped, status %04x, restarting.\n",
+ dev->name, status);
+ init_rx_bufs(dev);
+ writew(RX_BUF_START,shmem+iSCB_RFA);
+ ack_cmd |= RX_START;
+ }
+
+ writew(ack_cmd,shmem+iSCB_CMD);
+ outb(0, ioaddr + SIGNAL_CA); /* Issue channel-attn. */
+
+ /* Clear the latched interrupt. */
+ outb(0, ioaddr + RESET_IRQ);
+
+ /* Enable the 82586's interrupt input. */
+ outb(0x84, ioaddr + MISC_CTRL);
+ spin_unlock(&lp->lock);
+ return IRQ_HANDLED;
+}
+
+static int el16_close(struct net_device *dev)
+{
+ struct net_local *lp = netdev_priv(dev);
+ int ioaddr = dev->base_addr;
+ void __iomem *shmem = lp->base;
+
+ netif_stop_queue(dev);
+
+ /* Flush the Tx and disable Rx. */
+ writew(RX_SUSPEND | CUC_SUSPEND,shmem+iSCB_CMD);
+ outb(0, ioaddr + SIGNAL_CA);
+
+ /* Disable the 82586's input to the interrupt line. */
+ outb(0x80, ioaddr + MISC_CTRL);
+
+ /* We always physically use the IRQ line, so we don't do free_irq(). */
+
+ /* Update the statistics here. */
+
+ return 0;
+}
+
+/* Initialize the Rx-block list. */
+static void init_rx_bufs(struct net_device *dev)
+{
+ struct net_local *lp = netdev_priv(dev);
+ void __iomem *write_ptr;
+ unsigned short SCB_base = SCB_BASE;
+
+ int cur_rxbuf = lp->rx_head = RX_BUF_START;
+
+ /* Initialize each Rx frame + data buffer. */
+ do { /* While there is room for one more. */
+
+ write_ptr = lp->base + cur_rxbuf;
+
+ writew(0x0000,write_ptr); /* Status */
+ writew(0x0000,write_ptr+=2); /* Command */
+ writew(cur_rxbuf + RX_BUF_SIZE,write_ptr+=2); /* Link */
+ writew(cur_rxbuf + 22,write_ptr+=2); /* Buffer offset */
+ writew(0x0000,write_ptr+=2); /* Pad for dest addr. */
+ writew(0x0000,write_ptr+=2);
+ writew(0x0000,write_ptr+=2);
+ writew(0x0000,write_ptr+=2); /* Pad for source addr. */
+ writew(0x0000,write_ptr+=2);
+ writew(0x0000,write_ptr+=2);
+ writew(0x0000,write_ptr+=2); /* Pad for protocol. */
+
+ writew(0x0000,write_ptr+=2); /* Buffer: Actual count */
+ writew(-1,write_ptr+=2); /* Buffer: Next (none). */
+ writew(cur_rxbuf + 0x20 + SCB_base,write_ptr+=2);/* Buffer: Address low */
+ writew(0x0000,write_ptr+=2);
+ /* Finally, the number of bytes in the buffer. */
+ writew(0x8000 + RX_BUF_SIZE-0x20,write_ptr+=2);
+
+ lp->rx_tail = cur_rxbuf;
+ cur_rxbuf += RX_BUF_SIZE;
+ } while (cur_rxbuf <= RX_BUF_END - RX_BUF_SIZE);
+
+ /* Terminate the list by setting the EOL bit, and wrap the pointer to make
+ the list a ring. */
+ write_ptr = lp->base + lp->rx_tail + 2;
+ writew(0xC000,write_ptr); /* Command, mark as last. */
+ writew(lp->rx_head,write_ptr+2); /* Link */
+}
+
+static void init_82586_mem(struct net_device *dev)
+{
+ struct net_local *lp = netdev_priv(dev);
+ short ioaddr = dev->base_addr;
+ void __iomem *shmem = lp->base;
+
+ /* Enable loopback to protect the wire while starting up,
+ and hold the 586 in reset during the memory initialization. */
+ outb(0x20, ioaddr + MISC_CTRL);
+
+ /* Fix the ISCP address and base. */
+ init_words[3] = SCB_BASE;
+ init_words[7] = SCB_BASE;
+
+ /* Write the words at 0xfff6 (address-aliased to 0xfffff6). */
+ memcpy_toio(lp->base + RX_BUF_END - 10, init_words, 10);
+
+ /* Write the words at 0x0000. */
+ memcpy_toio(lp->base, init_words + 5, sizeof(init_words) - 10);
+
+ /* Fill in the station address. */
+ memcpy_toio(lp->base+SA_OFFSET, dev->dev_addr, ETH_ALEN);
+
+ /* The Tx-block list is written as needed. We just set up the values. */
+ lp->tx_cmd_link = IDLELOOP + 4;
+ lp->tx_head = lp->tx_reap = TX_BUF_START;
+
+ init_rx_bufs(dev);
+
+ /* Start the 586 by releasing the reset line, but leave loopback. */
+ outb(0xA0, ioaddr + MISC_CTRL);
+
+ /* This was time consuming to track down: you need to give two channel
+ attention signals to reliably start up the i82586. */
+ outb(0, ioaddr + SIGNAL_CA);
+
+ {
+ int boguscnt = 50;
+ while (readw(shmem+iSCB_STATUS) == 0)
+ if (--boguscnt == 0) {
+ pr_warning("%s: i82586 initialization timed out with status %04x, cmd %04x.\n",
+ dev->name, readw(shmem+iSCB_STATUS), readw(shmem+iSCB_CMD));
+ break;
+ }
+ /* Issue channel-attn -- the 82586 won't start. */
+ outb(0, ioaddr + SIGNAL_CA);
+ }
+
+ /* Disable loopback and enable interrupts. */
+ outb(0x84, ioaddr + MISC_CTRL);
+ if (net_debug > 4)
+ pr_debug("%s: Initialized 82586, status %04x.\n", dev->name,
+ readw(shmem+iSCB_STATUS));
+}
+
+static void hardware_send_packet(struct net_device *dev, void *buf, short length, short pad)
+{
+ struct net_local *lp = netdev_priv(dev);
+ short ioaddr = dev->base_addr;
+ ushort tx_block = lp->tx_head;
+ void __iomem *write_ptr = lp->base + tx_block;
+ static char padding[ETH_ZLEN];
+
+ /* Set the write pointer to the Tx block, and put out the header. */
+ writew(0x0000,write_ptr); /* Tx status */
+ writew(CMD_INTR|CmdTx,write_ptr+=2); /* Tx command */
+ writew(tx_block+16,write_ptr+=2); /* Next command is a NoOp. */
+ writew(tx_block+8,write_ptr+=2); /* Data Buffer offset. */
+
+ /* Output the data buffer descriptor. */
+ writew((pad + length) | 0x8000,write_ptr+=2); /* Byte count parameter. */
+ writew(-1,write_ptr+=2); /* No next data buffer. */
+ writew(tx_block+22+SCB_BASE,write_ptr+=2); /* Buffer follows the NoOp command. */
+ writew(0x0000,write_ptr+=2); /* Buffer address high bits (always zero). */
+
+ /* Output the Loop-back NoOp command. */
+ writew(0x0000,write_ptr+=2); /* Tx status */
+ writew(CmdNOp,write_ptr+=2); /* Tx command */
+ writew(tx_block+16,write_ptr+=2); /* Next is myself. */
+
+ /* Output the packet at the write pointer. */
+ memcpy_toio(write_ptr+2, buf, length);
+ if (pad)
+ memcpy_toio(write_ptr+length+2, padding, pad);
+
+ /* Set the old command link pointing to this send packet. */
+ writew(tx_block,lp->base + lp->tx_cmd_link);
+ lp->tx_cmd_link = tx_block + 20;
+
+ /* Set the next free tx region. */
+ lp->tx_head = tx_block + TX_BUF_SIZE;
+ if (lp->tx_head > RX_BUF_START - TX_BUF_SIZE)
+ lp->tx_head = TX_BUF_START;
+
+ if (net_debug > 4) {
+ pr_debug("%s: 3c507 @%x send length = %d, tx_block %3x, next %3x.\n",
+ dev->name, ioaddr, length, tx_block, lp->tx_head);
+ }
+
+ /* Grimly block further packets if there has been insufficient reaping. */
+ if (++lp->tx_pkts_in_ring < NUM_TX_BUFS)
+ netif_wake_queue(dev);
+}
+
+static void el16_rx(struct net_device *dev)
+{
+ struct net_local *lp = netdev_priv(dev);
+ void __iomem *shmem = lp->base;
+ ushort rx_head = lp->rx_head;
+ ushort rx_tail = lp->rx_tail;
+ ushort boguscount = 10;
+ short frame_status;
+
+ while ((frame_status = readw(shmem+rx_head)) < 0) { /* Command complete */
+ void __iomem *read_frame = lp->base + rx_head;
+ ushort rfd_cmd = readw(read_frame+2);
+ ushort next_rx_frame = readw(read_frame+4);
+ ushort data_buffer_addr = readw(read_frame+6);
+ void __iomem *data_frame = lp->base + data_buffer_addr;
+ ushort pkt_len = readw(data_frame);
+
+ if (rfd_cmd != 0 || data_buffer_addr != rx_head + 22 ||
+ (pkt_len & 0xC000) != 0xC000) {
+ pr_err("%s: Rx frame at %#x corrupted, "
+ "status %04x cmd %04x next %04x "
+ "data-buf @%04x %04x.\n",
+ dev->name, rx_head, frame_status, rfd_cmd,
+ next_rx_frame, data_buffer_addr, pkt_len);
+ } else if ((frame_status & 0x2000) == 0) {
+ /* Frame Rxed, but with error. */
+ dev->stats.rx_errors++;
+ if (frame_status & 0x0800) dev->stats.rx_crc_errors++;
+ if (frame_status & 0x0400) dev->stats.rx_frame_errors++;
+ if (frame_status & 0x0200) dev->stats.rx_fifo_errors++;
+ if (frame_status & 0x0100) dev->stats.rx_over_errors++;
+ if (frame_status & 0x0080) dev->stats.rx_length_errors++;
+ } else {
+ /* Malloc up new buffer. */
+ struct sk_buff *skb;
+
+ pkt_len &= 0x3fff;
+ skb = dev_alloc_skb(pkt_len+2);
+ if (skb == NULL) {
+ pr_err("%s: Memory squeeze, dropping packet.\n",
+ dev->name);
+ dev->stats.rx_dropped++;
+ break;
+ }
+
+ skb_reserve(skb,2);
+
+ /* 'skb->data' points to the start of sk_buff data area. */
+ memcpy_fromio(skb_put(skb,pkt_len), data_frame + 10, pkt_len);
+
+ skb->protocol=eth_type_trans(skb,dev);
+ netif_rx(skb);
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
+ }
+
+ /* Clear the status word and set End-of-List on the rx frame. */
+ writew(0,read_frame);
+ writew(0xC000,read_frame+2);
+ /* Clear the end-of-list on the prev. RFD. */
+ writew(0x0000,lp->base + rx_tail + 2);
+
+ rx_tail = rx_head;
+ rx_head = next_rx_frame;
+ if (--boguscount == 0)
+ break;
+ }
+
+ lp->rx_head = rx_head;
+ lp->rx_tail = rx_tail;
+}
+
+static void netdev_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+{
+ strcpy(info->driver, DRV_NAME);
+ strcpy(info->version, DRV_VERSION);
+ sprintf(info->bus_info, "ISA 0x%lx", dev->base_addr);
+}
+
+static u32 netdev_get_msglevel(struct net_device *dev)
+{
+ return debug;
+}
+
+static void netdev_set_msglevel(struct net_device *dev, u32 level)
+{
+ debug = level;
+}
+
+static const struct ethtool_ops netdev_ethtool_ops = {
+ .get_drvinfo = netdev_get_drvinfo,
+ .get_msglevel = netdev_get_msglevel,
+ .set_msglevel = netdev_set_msglevel,
+};
+
+#ifdef MODULE
+static struct net_device *dev_3c507;
+module_param(io, int, 0);
+module_param(irq, int, 0);
+MODULE_PARM_DESC(io, "EtherLink16 I/O base address");
+MODULE_PARM_DESC(irq, "(ignored)");
+
+int __init init_module(void)
+{
+ if (io == 0)
+ pr_notice("3c507: You should not use auto-probing with insmod!\n");
+ dev_3c507 = el16_probe(-1);
+ return IS_ERR(dev_3c507) ? PTR_ERR(dev_3c507) : 0;
+}
+
+void __exit
+cleanup_module(void)
+{
+ struct net_device *dev = dev_3c507;
+ unregister_netdev(dev);
+ free_irq(dev->irq, dev);
+ iounmap(((struct net_local *)netdev_priv(dev))->base);
+ release_region(dev->base_addr, EL16_IO_EXTENT);
+ free_netdev(dev);
+}
+#endif /* MODULE */
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ net-3-driver for the 3c523 Etherlink/MC card (i82586 Ethernet chip)
+
+
+ This is an extension to the Linux operating system, and is covered by the
+ same GNU General Public License that covers that work.
+
+ Copyright 1995, 1996 by Chris Beauregard (cpbeaure@undergrad.math.uwaterloo.ca)
+
+ This is basically Michael Hipp's ni52 driver, with a new probing
+ algorithm and some minor changes to the 82586 CA and reset routines.
+ Thanks a lot Michael for a really clean i82586 implementation! Unless
+ otherwise documented in ni52.c, any bugs are mine.
+
+ Contrary to the Ethernet-HOWTO, this isn't based on the 3c507 driver in
+ any way. The ni52 is a lot easier to modify.
+
+ sources:
+ ni52.c
+
+ Crynwr packet driver collection was a great reference for my first
+ attempt at this sucker. The 3c507 driver also helped, until I noticed
+ that ni52.c was a lot nicer.
+
+ EtherLink/MC: Micro Channel Ethernet Adapter Technical Reference
+ Manual, courtesy of 3Com CardFacts, documents the 3c523-specific
+ stuff. Information on CardFacts is found in the Ethernet HOWTO.
+ Also see <a href="http://www.3com.com/">
+
+ Microprocessor Communications Support Chips, T.J. Byers, ISBN
+ 0-444-01224-9, has a section on the i82586. It tells you just enough
+ to know that you really don't want to learn how to program the chip.
+
+ The original device probe code was stolen from ps2esdi.c
+
+ Known Problems:
+ Since most of the code was stolen from ni52.c, you'll run across the
+ same bugs in the 0.62 version of ni52.c, plus maybe a few because of
+ the 3c523 idiosynchacies. The 3c523 has 16K of RAM though, so there
+ shouldn't be the overrun problem that the 8K ni52 has.
+
+ This driver is for a 16K adapter. It should work fine on the 64K
+ adapters, but it will only use one of the 4 banks of RAM. Modifying
+ this for the 64K version would require a lot of heinous bank
+ switching, which I'm sure not interested in doing. If you try to
+ implement a bank switching version, you'll basically have to remember
+ what bank is enabled and do a switch every time you access a memory
+ location that's not current. You'll also have to remap pointers on
+ the driver side, because it only knows about 16K of the memory.
+ Anyone desperate or masochistic enough to try?
+
+ It seems to be stable now when multiple transmit buffers are used. I
+ can't see any performance difference, but then I'm working on a 386SX.
+
+ Multicast doesn't work. It doesn't even pretend to work. Don't use
+ it. Don't compile your kernel with multicast support. I don't know
+ why.
+
+ Features:
+ This driver is useable as a loadable module. If you try to specify an
+ IRQ or a IO address (via insmod 3c523.o irq=xx io=0xyyy), it will
+ search the MCA slots until it finds a 3c523 with the specified
+ parameters.
+
+ This driver does support multiple ethernet cards when used as a module
+ (up to MAX_3C523_CARDS, the default being 4)
+
+ This has been tested with both BNC and TP versions, internal and
+ external transceivers. Haven't tested with the 64K version (that I
+ know of).
+
+ History:
+ Jan 1st, 1996
+ first public release
+ Feb 4th, 1996
+ update to 1.3.59, incorporated multicast diffs from ni52.c
+ Feb 15th, 1996
+ added shared irq support
+ Apr 1999
+ added support for multiple cards when used as a module
+ added option to disable multicast as is causes problems
+ Ganesh Sittampalam <ganesh.sittampalam@magdalen.oxford.ac.uk>
+ Stuart Adamson <stuart.adamson@compsoc.net>
+ Nov 2001
+ added support for ethtool (jgarzik)
+
+ $Header: /fsys2/home/chrisb/linux-1.3.59-MCA/drivers/net/RCS/3c523.c,v 1.1 1996/02/05 01:53:46 chrisb Exp chrisb $
+ */
+
+#define DRV_NAME "3c523"
+#define DRV_VERSION "17-Nov-2001"
+
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/skbuff.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/mca-legacy.h>
+#include <linux/ethtool.h>
+#include <linux/bitops.h>
+#include <linux/jiffies.h>
+
+#include <asm/uaccess.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+
+#include "3c523.h"
+
+/*************************************************************************/
+#define DEBUG /* debug on */
+#define SYSBUSVAL 0 /* 1 = 8 Bit, 0 = 16 bit - 3c523 only does 16 bit */
+#undef ELMC_MULTICAST /* Disable multicast support as it is somewhat seriously broken at the moment */
+
+#define make32(ptr16) (p->memtop + (short) (ptr16) )
+#define make24(ptr32) ((char *) (ptr32) - p->base)
+#define make16(ptr32) ((unsigned short) ((unsigned long) (ptr32) - (unsigned long) p->memtop ))
+
+/*************************************************************************/
+/*
+ Tables to which we can map values in the configuration registers.
+ */
+static int irq_table[] __initdata = {
+ 12, 7, 3, 9
+};
+
+static int csr_table[] __initdata = {
+ 0x300, 0x1300, 0x2300, 0x3300
+};
+
+static int shm_table[] __initdata = {
+ 0x0c0000, 0x0c8000, 0x0d0000, 0x0d8000
+};
+
+/******************* how to calculate the buffers *****************************
+
+
+ * IMPORTANT NOTE: if you configure only one NUM_XMIT_BUFFS, the driver works
+ * --------------- in a different (more stable?) mode. Only in this mode it's
+ * possible to configure the driver with 'NO_NOPCOMMANDS'
+
+sizeof(scp)=12; sizeof(scb)=16; sizeof(iscp)=8;
+sizeof(scp)+sizeof(iscp)+sizeof(scb) = 36 = INIT
+sizeof(rfd) = 24; sizeof(rbd) = 12;
+sizeof(tbd) = 8; sizeof(transmit_cmd) = 16;
+sizeof(nop_cmd) = 8;
+
+ * if you don't know the driver, better do not change this values: */
+
+#define RECV_BUFF_SIZE 1524 /* slightly oversized */
+#define XMIT_BUFF_SIZE 1524 /* slightly oversized */
+#define NUM_XMIT_BUFFS 1 /* config for both, 8K and 16K shmem */
+#define NUM_RECV_BUFFS_8 4 /* config for 8K shared mem */
+#define NUM_RECV_BUFFS_16 9 /* config for 16K shared mem */
+
+#if (NUM_XMIT_BUFFS == 1)
+#define NO_NOPCOMMANDS /* only possible with NUM_XMIT_BUFFS=1 */
+#endif
+
+/**************************************************************************/
+
+#define DELAY(x) { mdelay(32 * x); }
+
+/* a much shorter delay: */
+#define DELAY_16(); { udelay(16) ; }
+
+/* wait for command with timeout: */
+#define WAIT_4_SCB_CMD() { int i; \
+ for(i=0;i<1024;i++) { \
+ if(!p->scb->cmd) break; \
+ DELAY_16(); \
+ if(i == 1023) { \
+ pr_warning("%s:%d: scb_cmd timed out .. resetting i82586\n",\
+ dev->name,__LINE__); \
+ elmc_id_reset586(); } } }
+
+static irqreturn_t elmc_interrupt(int irq, void *dev_id);
+static int elmc_open(struct net_device *dev);
+static int elmc_close(struct net_device *dev);
+static netdev_tx_t elmc_send_packet(struct sk_buff *, struct net_device *);
+static struct net_device_stats *elmc_get_stats(struct net_device *dev);
+static void elmc_timeout(struct net_device *dev);
+#ifdef ELMC_MULTICAST
+static void set_multicast_list(struct net_device *dev);
+#endif
+static const struct ethtool_ops netdev_ethtool_ops;
+
+/* helper-functions */
+static int init586(struct net_device *dev);
+static int check586(struct net_device *dev, unsigned long where, unsigned size);
+static void alloc586(struct net_device *dev);
+static void startrecv586(struct net_device *dev);
+static void *alloc_rfa(struct net_device *dev, void *ptr);
+static void elmc_rcv_int(struct net_device *dev);
+static void elmc_xmt_int(struct net_device *dev);
+static void elmc_rnr_int(struct net_device *dev);
+
+struct priv {
+ unsigned long base;
+ char *memtop;
+ unsigned long mapped_start; /* Start of ioremap */
+ volatile struct rfd_struct *rfd_last, *rfd_top, *rfd_first;
+ volatile struct scp_struct *scp; /* volatile is important */
+ volatile struct iscp_struct *iscp; /* volatile is important */
+ volatile struct scb_struct *scb; /* volatile is important */
+ volatile struct tbd_struct *xmit_buffs[NUM_XMIT_BUFFS];
+#if (NUM_XMIT_BUFFS == 1)
+ volatile struct transmit_cmd_struct *xmit_cmds[2];
+ volatile struct nop_cmd_struct *nop_cmds[2];
+#else
+ volatile struct transmit_cmd_struct *xmit_cmds[NUM_XMIT_BUFFS];
+ volatile struct nop_cmd_struct *nop_cmds[NUM_XMIT_BUFFS];
+#endif
+ volatile int nop_point, num_recv_buffs;
+ volatile char *xmit_cbuffs[NUM_XMIT_BUFFS];
+ volatile int xmit_count, xmit_last;
+ volatile int slot;
+};
+
+#define elmc_attn586() {elmc_do_attn586(dev->base_addr,ELMC_CTRL_INTE);}
+#define elmc_reset586() {elmc_do_reset586(dev->base_addr,ELMC_CTRL_INTE);}
+
+/* with interrupts disabled - this will clear the interrupt bit in the
+ 3c523 control register, and won't put it back. This effectively
+ disables interrupts on the card. */
+#define elmc_id_attn586() {elmc_do_attn586(dev->base_addr,0);}
+#define elmc_id_reset586() {elmc_do_reset586(dev->base_addr,0);}
+
+/*************************************************************************/
+/*
+ Do a Channel Attention on the 3c523. This is extremely board dependent.
+ */
+static void elmc_do_attn586(int ioaddr, int ints)
+{
+ /* the 3c523 requires a minimum of 500 ns. The delays here might be
+ a little too large, and hence they may cut the performance of the
+ card slightly. If someone who knows a little more about Linux
+ timing would care to play with these, I'd appreciate it. */
+
+ /* this bit masking stuff is crap. I'd rather have separate
+ registers with strobe triggers for each of these functions. <sigh>
+ Ya take what ya got. */
+
+ outb(ELMC_CTRL_RST | 0x3 | ELMC_CTRL_CA | ints, ioaddr + ELMC_CTRL);
+ DELAY_16(); /* > 500 ns */
+ outb(ELMC_CTRL_RST | 0x3 | ints, ioaddr + ELMC_CTRL);
+}
+
+/*************************************************************************/
+/*
+ Reset the 82586 on the 3c523. Also very board dependent.
+ */
+static void elmc_do_reset586(int ioaddr, int ints)
+{
+ /* toggle the RST bit low then high */
+ outb(0x3 | ELMC_CTRL_LBK, ioaddr + ELMC_CTRL);
+ DELAY_16(); /* > 500 ns */
+ outb(ELMC_CTRL_RST | ELMC_CTRL_LBK | 0x3, ioaddr + ELMC_CTRL);
+
+ elmc_do_attn586(ioaddr, ints);
+}
+
+/**********************************************
+ * close device
+ */
+
+static int elmc_close(struct net_device *dev)
+{
+ netif_stop_queue(dev);
+ elmc_id_reset586(); /* the hard way to stop the receiver */
+ free_irq(dev->irq, dev);
+ return 0;
+}
+
+/**********************************************
+ * open device
+ */
+
+static int elmc_open(struct net_device *dev)
+{
+ int ret;
+
+ elmc_id_attn586(); /* disable interrupts */
+
+ ret = request_irq(dev->irq, elmc_interrupt, IRQF_SHARED,
+ dev->name, dev);
+ if (ret) {
+ pr_err("%s: couldn't get irq %d\n", dev->name, dev->irq);
+ elmc_id_reset586();
+ return ret;
+ }
+ alloc586(dev);
+ init586(dev);
+ startrecv586(dev);
+ netif_start_queue(dev);
+ return 0; /* most done by init */
+}
+
+/**********************************************
+ * Check to see if there's an 82586 out there.
+ */
+
+static int __init check586(struct net_device *dev, unsigned long where, unsigned size)
+{
+ struct priv *p = netdev_priv(dev);
+ char *iscp_addrs[2];
+ int i = 0;
+
+ p->base = (unsigned long) isa_bus_to_virt((unsigned long)where) + size - 0x01000000;
+ p->memtop = isa_bus_to_virt((unsigned long)where) + size;
+ p->scp = (struct scp_struct *)(p->base + SCP_DEFAULT_ADDRESS);
+ memset((char *) p->scp, 0, sizeof(struct scp_struct));
+ p->scp->sysbus = SYSBUSVAL; /* 1 = 8Bit-Bus, 0 = 16 Bit */
+
+ iscp_addrs[0] = isa_bus_to_virt((unsigned long)where);
+ iscp_addrs[1] = (char *) p->scp - sizeof(struct iscp_struct);
+
+ for (i = 0; i < 2; i++) {
+ p->iscp = (struct iscp_struct *) iscp_addrs[i];
+ memset((char *) p->iscp, 0, sizeof(struct iscp_struct));
+
+ p->scp->iscp = make24(p->iscp);
+ p->iscp->busy = 1;
+
+ elmc_id_reset586();
+
+ /* reset586 does an implicit CA */
+
+ /* apparently, you sometimes have to kick the 82586 twice... */
+ elmc_id_attn586();
+ DELAY(1);
+
+ if (p->iscp->busy) { /* i82586 clears 'busy' after successful init */
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/******************************************************************
+ * set iscp at the right place, called by elmc_probe and open586.
+ */
+
+static void alloc586(struct net_device *dev)
+{
+ struct priv *p = netdev_priv(dev);
+
+ elmc_id_reset586();
+ DELAY(2);
+
+ p->scp = (struct scp_struct *) (p->base + SCP_DEFAULT_ADDRESS);
+ p->scb = (struct scb_struct *) isa_bus_to_virt(dev->mem_start);
+ p->iscp = (struct iscp_struct *) ((char *) p->scp - sizeof(struct iscp_struct));
+
+ memset((char *) p->iscp, 0, sizeof(struct iscp_struct));
+ memset((char *) p->scp, 0, sizeof(struct scp_struct));
+
+ p->scp->iscp = make24(p->iscp);
+ p->scp->sysbus = SYSBUSVAL;
+ p->iscp->scb_offset = make16(p->scb);
+
+ p->iscp->busy = 1;
+ elmc_id_reset586();
+ elmc_id_attn586();
+
+ DELAY(2);
+
+ if (p->iscp->busy)
+ pr_err("%s: Init-Problems (alloc).\n", dev->name);
+
+ memset((char *) p->scb, 0, sizeof(struct scb_struct));
+}
+
+/*****************************************************************/
+
+static int elmc_getinfo(char *buf, int slot, void *d)
+{
+ int len = 0;
+ struct net_device *dev = d;
+
+ if (dev == NULL)
+ return len;
+
+ len += sprintf(buf + len, "Revision: 0x%x\n",
+ inb(dev->base_addr + ELMC_REVISION) & 0xf);
+ len += sprintf(buf + len, "IRQ: %d\n", dev->irq);
+ len += sprintf(buf + len, "IO Address: %#lx-%#lx\n", dev->base_addr,
+ dev->base_addr + ELMC_IO_EXTENT);
+ len += sprintf(buf + len, "Memory: %#lx-%#lx\n", dev->mem_start,
+ dev->mem_end - 1);
+ len += sprintf(buf + len, "Transceiver: %s\n", dev->if_port ?
+ "External" : "Internal");
+ len += sprintf(buf + len, "Device: %s\n", dev->name);
+ len += sprintf(buf + len, "Hardware Address: %pM\n",
+ dev->dev_addr);
+
+ return len;
+} /* elmc_getinfo() */
+
+static const struct net_device_ops netdev_ops = {
+ .ndo_open = elmc_open,
+ .ndo_stop = elmc_close,
+ .ndo_get_stats = elmc_get_stats,
+ .ndo_start_xmit = elmc_send_packet,
+ .ndo_tx_timeout = elmc_timeout,
+#ifdef ELMC_MULTICAST
+ .ndo_set_multicast_list = set_multicast_list,
+#endif
+ .ndo_change_mtu = eth_change_mtu,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+};
+
+/*****************************************************************/
+
+static int __init do_elmc_probe(struct net_device *dev)
+{
+ static int slot;
+ int base_addr = dev->base_addr;
+ int irq = dev->irq;
+ u_char status = 0;
+ u_char revision = 0;
+ int i = 0;
+ unsigned int size = 0;
+ int retval;
+ struct priv *pr = netdev_priv(dev);
+
+ if (MCA_bus == 0) {
+ return -ENODEV;
+ }
+ /* search through the slots for the 3c523. */
+ slot = mca_find_adapter(ELMC_MCA_ID, 0);
+ while (slot != -1) {
+ status = mca_read_stored_pos(slot, 2);
+
+ dev->irq=irq_table[(status & ELMC_STATUS_IRQ_SELECT) >> 6];
+ dev->base_addr=csr_table[(status & ELMC_STATUS_CSR_SELECT) >> 1];
+
+ /*
+ If we're trying to match a specified irq or IO address,
+ we'll reject a match unless it's what we're looking for.
+ Also reject it if the card is already in use.
+ */
+
+ if ((irq && irq != dev->irq) ||
+ (base_addr && base_addr != dev->base_addr)) {
+ slot = mca_find_adapter(ELMC_MCA_ID, slot + 1);
+ continue;
+ }
+ if (!request_region(dev->base_addr, ELMC_IO_EXTENT, DRV_NAME)) {
+ slot = mca_find_adapter(ELMC_MCA_ID, slot + 1);
+ continue;
+ }
+
+ /* found what we're looking for... */
+ break;
+ }
+
+ /* we didn't find any 3c523 in the slots we checked for */
+ if (slot == MCA_NOTFOUND)
+ return (base_addr || irq) ? -ENXIO : -ENODEV;
+
+ mca_set_adapter_name(slot, "3Com 3c523 Etherlink/MC");
+ mca_set_adapter_procfn(slot, (MCA_ProcFn) elmc_getinfo, dev);
+
+ /* if we get this far, adapter has been found - carry on */
+ pr_info("%s: 3c523 adapter found in slot %d\n", dev->name, slot + 1);
+
+ /* Now we extract configuration info from the card.
+ The 3c523 provides information in two of the POS registers, but
+ the second one is only needed if we want to tell the card what IRQ
+ to use. I suspect that whoever sets the thing up initially would
+ prefer we don't screw with those things.
+
+ Note that we read the status info when we found the card...
+
+ See 3c523.h for more details.
+ */
+
+ /* revision is stored in the first 4 bits of the revision register */
+ revision = inb(dev->base_addr + ELMC_REVISION) & 0xf;
+
+ /* according to docs, we read the interrupt and write it back to
+ the IRQ select register, since the POST might not configure the IRQ
+ properly. */
+ switch (dev->irq) {
+ case 3:
+ mca_write_pos(slot, 3, 0x04);
+ break;
+ case 7:
+ mca_write_pos(slot, 3, 0x02);
+ break;
+ case 9:
+ mca_write_pos(slot, 3, 0x08);
+ break;
+ case 12:
+ mca_write_pos(slot, 3, 0x01);
+ break;
+ }
+
+ pr->slot = slot;
+
+ pr_info("%s: 3Com 3c523 Rev 0x%x at %#lx\n", dev->name, (int) revision,
+ dev->base_addr);
+
+ /* Determine if we're using the on-board transceiver (i.e. coax) or
+ an external one. The information is pretty much useless, but I
+ guess it's worth brownie points. */
+ dev->if_port = (status & ELMC_STATUS_DISABLE_THIN);
+
+ /* The 3c523 has a 24K chunk of memory. The first 16K is the
+ shared memory, while the last 8K is for the EtherStart BIOS ROM.
+ Which we don't care much about here. We'll just tell Linux that
+ we're using 16K. MCA won't permit address space conflicts caused
+ by not mapping the other 8K. */
+ dev->mem_start = shm_table[(status & ELMC_STATUS_MEMORY_SELECT) >> 3];
+
+ /* We're using MCA, so it's a given that the information about memory
+ size is correct. The Crynwr drivers do something like this. */
+
+ elmc_id_reset586(); /* seems like a good idea before checking it... */
+
+ size = 0x4000; /* check for 16K mem */
+ if (!check586(dev, dev->mem_start, size)) {
+ pr_err("%s: memprobe, Can't find memory at 0x%lx!\n", dev->name,
+ dev->mem_start);
+ retval = -ENODEV;
+ goto err_out;
+ }
+ dev->mem_end = dev->mem_start + size; /* set mem_end showed by 'ifconfig' */
+
+ pr->memtop = isa_bus_to_virt(dev->mem_start) + size;
+ pr->base = (unsigned long) isa_bus_to_virt(dev->mem_start) + size - 0x01000000;
+ alloc586(dev);
+
+ elmc_id_reset586(); /* make sure it doesn't generate spurious ints */
+
+ /* set number of receive-buffs according to memsize */
+ pr->num_recv_buffs = NUM_RECV_BUFFS_16;
+
+ /* dump all the assorted information */
+ pr_info("%s: IRQ %d, %sternal xcvr, memory %#lx-%#lx.\n", dev->name,
+ dev->irq, dev->if_port ? "ex" : "in",
+ dev->mem_start, dev->mem_end - 1);
+
+ /* The hardware address for the 3c523 is stored in the first six
+ bytes of the IO address. */
+ for (i = 0; i < 6; i++)
+ dev->dev_addr[i] = inb(dev->base_addr + i);
+
+ pr_info("%s: hardware address %pM\n",
+ dev->name, dev->dev_addr);
+
+ dev->netdev_ops = &netdev_ops;
+ dev->watchdog_timeo = HZ;
+ dev->ethtool_ops = &netdev_ethtool_ops;
+
+ /* note that we haven't actually requested the IRQ from the kernel.
+ That gets done in elmc_open(). I'm not sure that's such a good idea,
+ but it works, so I'll go with it. */
+
+#ifndef ELMC_MULTICAST
+ dev->flags&=~IFF_MULTICAST; /* Multicast doesn't work */
+#endif
+
+ retval = register_netdev(dev);
+ if (retval)
+ goto err_out;
+
+ return 0;
+err_out:
+ mca_set_adapter_procfn(slot, NULL, NULL);
+ release_region(dev->base_addr, ELMC_IO_EXTENT);
+ return retval;
+}
+
+#ifdef MODULE
+static void cleanup_card(struct net_device *dev)
+{
+ mca_set_adapter_procfn(((struct priv *)netdev_priv(dev))->slot,
+ NULL, NULL);
+ release_region(dev->base_addr, ELMC_IO_EXTENT);
+}
+#else
+struct net_device * __init elmc_probe(int unit)
+{
+ struct net_device *dev = alloc_etherdev(sizeof(struct priv));
+ int err;
+
+ if (!dev)
+ return ERR_PTR(-ENOMEM);
+
+ sprintf(dev->name, "eth%d", unit);
+ netdev_boot_setup_check(dev);
+
+ err = do_elmc_probe(dev);
+ if (err)
+ goto out;
+ return dev;
+out:
+ free_netdev(dev);
+ return ERR_PTR(err);
+}
+#endif
+
+/**********************************************
+ * init the chip (elmc-interrupt should be disabled?!)
+ * needs a correct 'allocated' memory
+ */
+
+static int init586(struct net_device *dev)
+{
+ void *ptr;
+ unsigned long s;
+ int i, result = 0;
+ struct priv *p = netdev_priv(dev);
+ volatile struct configure_cmd_struct *cfg_cmd;
+ volatile struct iasetup_cmd_struct *ias_cmd;
+ volatile struct tdr_cmd_struct *tdr_cmd;
+ volatile struct mcsetup_cmd_struct *mc_cmd;
+ struct netdev_hw_addr *ha;
+ int num_addrs = netdev_mc_count(dev);
+
+ ptr = (void *) ((char *) p->scb + sizeof(struct scb_struct));
+
+ cfg_cmd = (struct configure_cmd_struct *) ptr; /* configure-command */
+ cfg_cmd->cmd_status = 0;
+ cfg_cmd->cmd_cmd = CMD_CONFIGURE | CMD_LAST;
+ cfg_cmd->cmd_link = 0xffff;
+
+ cfg_cmd->byte_cnt = 0x0a; /* number of cfg bytes */
+ cfg_cmd->fifo = 0x08; /* fifo-limit (8=tx:32/rx:64) */
+ cfg_cmd->sav_bf = 0x40; /* hold or discard bad recv frames (bit 7) */
+ cfg_cmd->adr_len = 0x2e; /* addr_len |!src_insert |pre-len |loopback */
+ cfg_cmd->priority = 0x00;
+ cfg_cmd->ifs = 0x60;
+ cfg_cmd->time_low = 0x00;
+ cfg_cmd->time_high = 0xf2;
+ cfg_cmd->promisc = 0;
+ if (dev->flags & (IFF_ALLMULTI | IFF_PROMISC))
+ cfg_cmd->promisc = 1;
+ cfg_cmd->carr_coll = 0x00;
+
+ p->scb->cbl_offset = make16(cfg_cmd);
+
+ p->scb->cmd = CUC_START; /* cmd.-unit start */
+ elmc_id_attn586();
+
+ s = jiffies; /* warning: only active with interrupts on !! */
+ while (!(cfg_cmd->cmd_status & STAT_COMPL)) {
+ if (time_after(jiffies, s + 30*HZ/100))
+ break;
+ }
+
+ if ((cfg_cmd->cmd_status & (STAT_OK | STAT_COMPL)) != (STAT_COMPL | STAT_OK)) {
+ pr_warning("%s (elmc): configure command failed: %x\n", dev->name, cfg_cmd->cmd_status);
+ return 1;
+ }
+ /*
+ * individual address setup
+ */
+ ias_cmd = (struct iasetup_cmd_struct *) ptr;
+
+ ias_cmd->cmd_status = 0;
+ ias_cmd->cmd_cmd = CMD_IASETUP | CMD_LAST;
+ ias_cmd->cmd_link = 0xffff;
+
+ memcpy((char *) &ias_cmd->iaddr, (char *) dev->dev_addr, ETH_ALEN);
+
+ p->scb->cbl_offset = make16(ias_cmd);
+
+ p->scb->cmd = CUC_START; /* cmd.-unit start */
+ elmc_id_attn586();
+
+ s = jiffies;
+ while (!(ias_cmd->cmd_status & STAT_COMPL)) {
+ if (time_after(jiffies, s + 30*HZ/100))
+ break;
+ }
+
+ if ((ias_cmd->cmd_status & (STAT_OK | STAT_COMPL)) != (STAT_OK | STAT_COMPL)) {
+ pr_warning("%s (elmc): individual address setup command failed: %04x\n",
+ dev->name, ias_cmd->cmd_status);
+ return 1;
+ }
+ /*
+ * TDR, wire check .. e.g. no resistor e.t.c
+ */
+ tdr_cmd = (struct tdr_cmd_struct *) ptr;
+
+ tdr_cmd->cmd_status = 0;
+ tdr_cmd->cmd_cmd = CMD_TDR | CMD_LAST;
+ tdr_cmd->cmd_link = 0xffff;
+ tdr_cmd->status = 0;
+
+ p->scb->cbl_offset = make16(tdr_cmd);
+
+ p->scb->cmd = CUC_START; /* cmd.-unit start */
+ elmc_attn586();
+
+ s = jiffies;
+ while (!(tdr_cmd->cmd_status & STAT_COMPL)) {
+ if (time_after(jiffies, s + 30*HZ/100)) {
+ pr_warning("%s: %d Problems while running the TDR.\n", dev->name, __LINE__);
+ result = 1;
+ break;
+ }
+ }
+
+ if (!result) {
+ DELAY(2); /* wait for result */
+ result = tdr_cmd->status;
+
+ p->scb->cmd = p->scb->status & STAT_MASK;
+ elmc_id_attn586(); /* ack the interrupts */
+
+ if (result & TDR_LNK_OK) {
+ /* empty */
+ } else if (result & TDR_XCVR_PRB) {
+ pr_warning("%s: TDR: Transceiver problem!\n", dev->name);
+ } else if (result & TDR_ET_OPN) {
+ pr_warning("%s: TDR: No correct termination %d clocks away.\n", dev->name, result & TDR_TIMEMASK);
+ } else if (result & TDR_ET_SRT) {
+ if (result & TDR_TIMEMASK) /* time == 0 -> strange :-) */
+ pr_warning("%s: TDR: Detected a short circuit %d clocks away.\n", dev->name, result & TDR_TIMEMASK);
+ } else {
+ pr_warning("%s: TDR: Unknown status %04x\n", dev->name, result);
+ }
+ }
+ /*
+ * ack interrupts
+ */
+ p->scb->cmd = p->scb->status & STAT_MASK;
+ elmc_id_attn586();
+
+ /*
+ * alloc nop/xmit-cmds
+ */
+#if (NUM_XMIT_BUFFS == 1)
+ for (i = 0; i < 2; i++) {
+ p->nop_cmds[i] = (struct nop_cmd_struct *) ptr;
+ p->nop_cmds[i]->cmd_cmd = CMD_NOP;
+ p->nop_cmds[i]->cmd_status = 0;
+ p->nop_cmds[i]->cmd_link = make16((p->nop_cmds[i]));
+ ptr = (char *) ptr + sizeof(struct nop_cmd_struct);
+ }
+ p->xmit_cmds[0] = (struct transmit_cmd_struct *) ptr; /* transmit cmd/buff 0 */
+ ptr = (char *) ptr + sizeof(struct transmit_cmd_struct);
+#else
+ for (i = 0; i < NUM_XMIT_BUFFS; i++) {
+ p->nop_cmds[i] = (struct nop_cmd_struct *) ptr;
+ p->nop_cmds[i]->cmd_cmd = CMD_NOP;
+ p->nop_cmds[i]->cmd_status = 0;
+ p->nop_cmds[i]->cmd_link = make16((p->nop_cmds[i]));
+ ptr = (char *) ptr + sizeof(struct nop_cmd_struct);
+ p->xmit_cmds[i] = (struct transmit_cmd_struct *) ptr; /*transmit cmd/buff 0 */
+ ptr = (char *) ptr + sizeof(struct transmit_cmd_struct);
+ }
+#endif
+
+ ptr = alloc_rfa(dev, (void *) ptr); /* init receive-frame-area */
+
+ /*
+ * Multicast setup
+ */
+
+ if (num_addrs) {
+ /* I don't understand this: do we really need memory after the init? */
+ int len = ((char *) p->iscp - (char *) ptr - 8) / 6;
+ if (len <= 0) {
+ pr_err("%s: Ooooops, no memory for MC-Setup!\n", dev->name);
+ } else {
+ if (len < num_addrs) {
+ num_addrs = len;
+ pr_warning("%s: Sorry, can only apply %d MC-Address(es).\n",
+ dev->name, num_addrs);
+ }
+ mc_cmd = (struct mcsetup_cmd_struct *) ptr;
+ mc_cmd->cmd_status = 0;
+ mc_cmd->cmd_cmd = CMD_MCSETUP | CMD_LAST;
+ mc_cmd->cmd_link = 0xffff;
+ mc_cmd->mc_cnt = num_addrs * 6;
+ i = 0;
+ netdev_for_each_mc_addr(ha, dev)
+ memcpy((char *) mc_cmd->mc_list[i++],
+ ha->addr, 6);
+ p->scb->cbl_offset = make16(mc_cmd);
+ p->scb->cmd = CUC_START;
+ elmc_id_attn586();
+ s = jiffies;
+ while (!(mc_cmd->cmd_status & STAT_COMPL)) {
+ if (time_after(jiffies, s + 30*HZ/100))
+ break;
+ }
+ if (!(mc_cmd->cmd_status & STAT_COMPL)) {
+ pr_warning("%s: Can't apply multicast-address-list.\n", dev->name);
+ }
+ }
+ }
+ /*
+ * alloc xmit-buffs / init xmit_cmds
+ */
+ for (i = 0; i < NUM_XMIT_BUFFS; i++) {
+ p->xmit_cbuffs[i] = (char *) ptr; /* char-buffs */
+ ptr = (char *) ptr + XMIT_BUFF_SIZE;
+ p->xmit_buffs[i] = (struct tbd_struct *) ptr; /* TBD */
+ ptr = (char *) ptr + sizeof(struct tbd_struct);
+ if ((void *) ptr > (void *) p->iscp) {
+ pr_err("%s: not enough shared-mem for your configuration!\n", dev->name);
+ return 1;
+ }
+ memset((char *) (p->xmit_cmds[i]), 0, sizeof(struct transmit_cmd_struct));
+ memset((char *) (p->xmit_buffs[i]), 0, sizeof(struct tbd_struct));
+ p->xmit_cmds[i]->cmd_status = STAT_COMPL;
+ p->xmit_cmds[i]->cmd_cmd = CMD_XMIT | CMD_INT;
+ p->xmit_cmds[i]->tbd_offset = make16((p->xmit_buffs[i]));
+ p->xmit_buffs[i]->next = 0xffff;
+ p->xmit_buffs[i]->buffer = make24((p->xmit_cbuffs[i]));
+ }
+
+ p->xmit_count = 0;
+ p->xmit_last = 0;
+#ifndef NO_NOPCOMMANDS
+ p->nop_point = 0;
+#endif
+
+ /*
+ * 'start transmitter' (nop-loop)
+ */
+#ifndef NO_NOPCOMMANDS
+ p->scb->cbl_offset = make16(p->nop_cmds[0]);
+ p->scb->cmd = CUC_START;
+ elmc_id_attn586();
+ WAIT_4_SCB_CMD();
+#else
+ p->xmit_cmds[0]->cmd_link = 0xffff;
+ p->xmit_cmds[0]->cmd_cmd = CMD_XMIT | CMD_LAST | CMD_INT;
+#endif
+
+ return 0;
+}
+
+/******************************************************
+ * This is a helper routine for elmc_rnr_int() and init586().
+ * It sets up the Receive Frame Area (RFA).
+ */
+
+static void *alloc_rfa(struct net_device *dev, void *ptr)
+{
+ volatile struct rfd_struct *rfd = (struct rfd_struct *) ptr;
+ volatile struct rbd_struct *rbd;
+ int i;
+ struct priv *p = netdev_priv(dev);
+
+ memset((char *) rfd, 0, sizeof(struct rfd_struct) * p->num_recv_buffs);
+ p->rfd_first = rfd;
+
+ for (i = 0; i < p->num_recv_buffs; i++) {
+ rfd[i].next = make16(rfd + (i + 1) % p->num_recv_buffs);
+ }
+ rfd[p->num_recv_buffs - 1].last = RFD_SUSP; /* RU suspend */
+
+ ptr = (void *) (rfd + p->num_recv_buffs);
+
+ rbd = (struct rbd_struct *) ptr;
+ ptr = (void *) (rbd + p->num_recv_buffs);
+
+ /* clr descriptors */
+ memset((char *) rbd, 0, sizeof(struct rbd_struct) * p->num_recv_buffs);
+
+ for (i = 0; i < p->num_recv_buffs; i++) {
+ rbd[i].next = make16((rbd + (i + 1) % p->num_recv_buffs));
+ rbd[i].size = RECV_BUFF_SIZE;
+ rbd[i].buffer = make24(ptr);
+ ptr = (char *) ptr + RECV_BUFF_SIZE;
+ }
+
+ p->rfd_top = p->rfd_first;
+ p->rfd_last = p->rfd_first + p->num_recv_buffs - 1;
+
+ p->scb->rfa_offset = make16(p->rfd_first);
+ p->rfd_first->rbd_offset = make16(rbd);
+
+ return ptr;
+}
+
+
+/**************************************************
+ * Interrupt Handler ...
+ */
+
+static irqreturn_t
+elmc_interrupt(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ unsigned short stat;
+ struct priv *p;
+
+ if (!netif_running(dev)) {
+ /* The 3c523 has this habit of generating interrupts during the
+ reset. I'm not sure if the ni52 has this same problem, but it's
+ really annoying if we haven't finished initializing it. I was
+ hoping all the elmc_id_* commands would disable this, but I
+ might have missed a few. */
+
+ elmc_id_attn586(); /* ack inter. and disable any more */
+ return IRQ_HANDLED;
+ } else if (!(ELMC_CTRL_INT & inb(dev->base_addr + ELMC_CTRL))) {
+ /* wasn't this device */
+ return IRQ_NONE;
+ }
+ /* reading ELMC_CTRL also clears the INT bit. */
+
+ p = netdev_priv(dev);
+
+ while ((stat = p->scb->status & STAT_MASK))
+ {
+ p->scb->cmd = stat;
+ elmc_attn586(); /* ack inter. */
+
+ if (stat & STAT_CX) {
+ /* command with I-bit set complete */
+ elmc_xmt_int(dev);
+ }
+ if (stat & STAT_FR) {
+ /* received a frame */
+ elmc_rcv_int(dev);
+ }
+#ifndef NO_NOPCOMMANDS
+ if (stat & STAT_CNA) {
+ /* CU went 'not ready' */
+ if (netif_running(dev)) {
+ pr_warning("%s: oops! CU has left active state. stat: %04x/%04x.\n",
+ dev->name, (int) stat, (int) p->scb->status);
+ }
+ }
+#endif
+
+ if (stat & STAT_RNR) {
+ /* RU went 'not ready' */
+
+ if (p->scb->status & RU_SUSPEND) {
+ /* special case: RU_SUSPEND */
+
+ WAIT_4_SCB_CMD();
+ p->scb->cmd = RUC_RESUME;
+ elmc_attn586();
+ } else {
+ pr_warning("%s: Receiver-Unit went 'NOT READY': %04x/%04x.\n",
+ dev->name, (int) stat, (int) p->scb->status);
+ elmc_rnr_int(dev);
+ }
+ }
+ WAIT_4_SCB_CMD(); /* wait for ack. (elmc_xmt_int can be faster than ack!!) */
+ if (p->scb->cmd) { /* timed out? */
+ break;
+ }
+ }
+ return IRQ_HANDLED;
+}
+
+/*******************************************************
+ * receive-interrupt
+ */
+
+static void elmc_rcv_int(struct net_device *dev)
+{
+ int status;
+ unsigned short totlen;
+ struct sk_buff *skb;
+ struct rbd_struct *rbd;
+ struct priv *p = netdev_priv(dev);
+
+ for (; (status = p->rfd_top->status) & STAT_COMPL;) {
+ rbd = (struct rbd_struct *) make32(p->rfd_top->rbd_offset);
+
+ if (status & STAT_OK) { /* frame received without error? */
+ if ((totlen = rbd->status) & RBD_LAST) { /* the first and the last buffer? */
+ totlen &= RBD_MASK; /* length of this frame */
+ rbd->status = 0;
+ skb = (struct sk_buff *) dev_alloc_skb(totlen + 2);
+ if (skb != NULL) {
+ skb_reserve(skb, 2); /* 16 byte alignment */
+ skb_put(skb,totlen);
+ skb_copy_to_linear_data(skb, (char *) p->base+(unsigned long) rbd->buffer,totlen);
+ skb->protocol = eth_type_trans(skb, dev);
+ netif_rx(skb);
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += totlen;
+ } else {
+ dev->stats.rx_dropped++;
+ }
+ } else {
+ pr_warning("%s: received oversized frame.\n", dev->name);
+ dev->stats.rx_dropped++;
+ }
+ } else { /* frame !(ok), only with 'save-bad-frames' */
+ pr_warning("%s: oops! rfd-error-status: %04x\n", dev->name, status);
+ dev->stats.rx_errors++;
+ }
+ p->rfd_top->status = 0;
+ p->rfd_top->last = RFD_SUSP;
+ p->rfd_last->last = 0; /* delete RU_SUSP */
+ p->rfd_last = p->rfd_top;
+ p->rfd_top = (struct rfd_struct *) make32(p->rfd_top->next); /* step to next RFD */
+ }
+}
+
+/**********************************************************
+ * handle 'Receiver went not ready'.
+ */
+
+static void elmc_rnr_int(struct net_device *dev)
+{
+ struct priv *p = netdev_priv(dev);
+
+ dev->stats.rx_errors++;
+
+ WAIT_4_SCB_CMD(); /* wait for the last cmd */
+ p->scb->cmd = RUC_ABORT; /* usually the RU is in the 'no resource'-state .. abort it now. */
+ elmc_attn586();
+ WAIT_4_SCB_CMD(); /* wait for accept cmd. */
+
+ alloc_rfa(dev, (char *) p->rfd_first);
+ startrecv586(dev); /* restart RU */
+
+ pr_warning("%s: Receive-Unit restarted. Status: %04x\n", dev->name, p->scb->status);
+
+}
+
+/**********************************************************
+ * handle xmit - interrupt
+ */
+
+static void elmc_xmt_int(struct net_device *dev)
+{
+ int status;
+ struct priv *p = netdev_priv(dev);
+
+ status = p->xmit_cmds[p->xmit_last]->cmd_status;
+ if (!(status & STAT_COMPL)) {
+ pr_warning("%s: strange .. xmit-int without a 'COMPLETE'\n", dev->name);
+ }
+ if (status & STAT_OK) {
+ dev->stats.tx_packets++;
+ dev->stats.collisions += (status & TCMD_MAXCOLLMASK);
+ } else {
+ dev->stats.tx_errors++;
+ if (status & TCMD_LATECOLL) {
+ pr_warning("%s: late collision detected.\n", dev->name);
+ dev->stats.collisions++;
+ } else if (status & TCMD_NOCARRIER) {
+ dev->stats.tx_carrier_errors++;
+ pr_warning("%s: no carrier detected.\n", dev->name);
+ } else if (status & TCMD_LOSTCTS) {
+ pr_warning("%s: loss of CTS detected.\n", dev->name);
+ } else if (status & TCMD_UNDERRUN) {
+ dev->stats.tx_fifo_errors++;
+ pr_warning("%s: DMA underrun detected.\n", dev->name);
+ } else if (status & TCMD_MAXCOLL) {
+ pr_warning("%s: Max. collisions exceeded.\n", dev->name);
+ dev->stats.collisions += 16;
+ }
+ }
+
+#if (NUM_XMIT_BUFFS != 1)
+ if ((++p->xmit_last) == NUM_XMIT_BUFFS) {
+ p->xmit_last = 0;
+ }
+#endif
+
+ netif_wake_queue(dev);
+}
+
+/***********************************************************
+ * (re)start the receiver
+ */
+
+static void startrecv586(struct net_device *dev)
+{
+ struct priv *p = netdev_priv(dev);
+
+ p->scb->rfa_offset = make16(p->rfd_first);
+ p->scb->cmd = RUC_START;
+ elmc_attn586(); /* start cmd. */
+ WAIT_4_SCB_CMD(); /* wait for accept cmd. (no timeout!!) */
+}
+
+/******************************************************
+ * timeout
+ */
+
+static void elmc_timeout(struct net_device *dev)
+{
+ struct priv *p = netdev_priv(dev);
+ /* COMMAND-UNIT active? */
+ if (p->scb->status & CU_ACTIVE) {
+ pr_debug("%s: strange ... timeout with CU active?!?\n", dev->name);
+ pr_debug("%s: X0: %04x N0: %04x N1: %04x %d\n", dev->name,
+ (int)p->xmit_cmds[0]->cmd_status,
+ (int)p->nop_cmds[0]->cmd_status,
+ (int)p->nop_cmds[1]->cmd_status, (int)p->nop_point);
+ p->scb->cmd = CUC_ABORT;
+ elmc_attn586();
+ WAIT_4_SCB_CMD();
+ p->scb->cbl_offset = make16(p->nop_cmds[p->nop_point]);
+ p->scb->cmd = CUC_START;
+ elmc_attn586();
+ WAIT_4_SCB_CMD();
+ netif_wake_queue(dev);
+ } else {
+ pr_debug("%s: xmitter timed out, try to restart! stat: %04x\n",
+ dev->name, p->scb->status);
+ pr_debug("%s: command-stats: %04x %04x\n", dev->name,
+ p->xmit_cmds[0]->cmd_status, p->xmit_cmds[1]->cmd_status);
+ elmc_close(dev);
+ elmc_open(dev);
+ }
+}
+
+/******************************************************
+ * send frame
+ */
+
+static netdev_tx_t elmc_send_packet(struct sk_buff *skb, struct net_device *dev)
+{
+ int len;
+ int i;
+#ifndef NO_NOPCOMMANDS
+ int next_nop;
+#endif
+ struct priv *p = netdev_priv(dev);
+
+ netif_stop_queue(dev);
+
+ len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
+
+ if (len != skb->len)
+ memset((char *) p->xmit_cbuffs[p->xmit_count], 0, ETH_ZLEN);
+ skb_copy_from_linear_data(skb, (char *) p->xmit_cbuffs[p->xmit_count], skb->len);
+
+#if (NUM_XMIT_BUFFS == 1)
+#ifdef NO_NOPCOMMANDS
+ p->xmit_buffs[0]->size = TBD_LAST | len;
+ for (i = 0; i < 16; i++) {
+ p->scb->cbl_offset = make16(p->xmit_cmds[0]);
+ p->scb->cmd = CUC_START;
+ p->xmit_cmds[0]->cmd_status = 0;
+ elmc_attn586();
+ if (!i) {
+ dev_kfree_skb(skb);
+ }
+ WAIT_4_SCB_CMD();
+ if ((p->scb->status & CU_ACTIVE)) { /* test it, because CU sometimes doesn't start immediately */
+ break;
+ }
+ if (p->xmit_cmds[0]->cmd_status) {
+ break;
+ }
+ if (i == 15) {
+ pr_warning("%s: Can't start transmit-command.\n", dev->name);
+ }
+ }
+#else
+ next_nop = (p->nop_point + 1) & 0x1;
+ p->xmit_buffs[0]->size = TBD_LAST | len;
+
+ p->xmit_cmds[0]->cmd_link = p->nop_cmds[next_nop]->cmd_link
+ = make16((p->nop_cmds[next_nop]));
+ p->xmit_cmds[0]->cmd_status = p->nop_cmds[next_nop]->cmd_status = 0;
+
+ p->nop_cmds[p->nop_point]->cmd_link = make16((p->xmit_cmds[0]));
+ p->nop_point = next_nop;
+ dev_kfree_skb(skb);
+#endif
+#else
+ p->xmit_buffs[p->xmit_count]->size = TBD_LAST | len;
+ if ((next_nop = p->xmit_count + 1) == NUM_XMIT_BUFFS) {
+ next_nop = 0;
+ }
+ p->xmit_cmds[p->xmit_count]->cmd_status = 0;
+ p->xmit_cmds[p->xmit_count]->cmd_link = p->nop_cmds[next_nop]->cmd_link
+ = make16((p->nop_cmds[next_nop]));
+ p->nop_cmds[next_nop]->cmd_status = 0;
+ p->nop_cmds[p->xmit_count]->cmd_link = make16((p->xmit_cmds[p->xmit_count]));
+ p->xmit_count = next_nop;
+ if (p->xmit_count != p->xmit_last)
+ netif_wake_queue(dev);
+ dev_kfree_skb(skb);
+#endif
+ return NETDEV_TX_OK;
+}
+
+/*******************************************
+ * Someone wanna have the statistics
+ */
+
+static struct net_device_stats *elmc_get_stats(struct net_device *dev)
+{
+ struct priv *p = netdev_priv(dev);
+ unsigned short crc, aln, rsc, ovrn;
+
+ crc = p->scb->crc_errs; /* get error-statistic from the ni82586 */
+ p->scb->crc_errs -= crc;
+ aln = p->scb->aln_errs;
+ p->scb->aln_errs -= aln;
+ rsc = p->scb->rsc_errs;
+ p->scb->rsc_errs -= rsc;
+ ovrn = p->scb->ovrn_errs;
+ p->scb->ovrn_errs -= ovrn;
+
+ dev->stats.rx_crc_errors += crc;
+ dev->stats.rx_fifo_errors += ovrn;
+ dev->stats.rx_frame_errors += aln;
+ dev->stats.rx_dropped += rsc;
+
+ return &dev->stats;
+}
+
+/********************************************************
+ * Set MC list ..
+ */
+
+#ifdef ELMC_MULTICAST
+static void set_multicast_list(struct net_device *dev)
+{
+ if (!dev->start) {
+ /* without a running interface, promiscuous doesn't work */
+ return;
+ }
+ dev->start = 0;
+ alloc586(dev);
+ init586(dev);
+ startrecv586(dev);
+ dev->start = 1;
+}
+#endif
+
+static void netdev_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+{
+ strcpy(info->driver, DRV_NAME);
+ strcpy(info->version, DRV_VERSION);
+ sprintf(info->bus_info, "MCA 0x%lx", dev->base_addr);
+}
+
+static const struct ethtool_ops netdev_ethtool_ops = {
+ .get_drvinfo = netdev_get_drvinfo,
+};
+
+#ifdef MODULE
+
+/* Increase if needed ;) */
+#define MAX_3C523_CARDS 4
+
+static struct net_device *dev_elmc[MAX_3C523_CARDS];
+static int irq[MAX_3C523_CARDS];
+static int io[MAX_3C523_CARDS];
+module_param_array(irq, int, NULL, 0);
+module_param_array(io, int, NULL, 0);
+MODULE_PARM_DESC(io, "EtherLink/MC I/O base address(es)");
+MODULE_PARM_DESC(irq, "EtherLink/MC IRQ number(s)");
+MODULE_LICENSE("GPL");
+
+int __init init_module(void)
+{
+ int this_dev,found = 0;
+
+ /* Loop until we either can't find any more cards, or we have MAX_3C523_CARDS */
+ for(this_dev=0; this_dev<MAX_3C523_CARDS; this_dev++) {
+ struct net_device *dev = alloc_etherdev(sizeof(struct priv));
+ if (!dev)
+ break;
+ dev->irq=irq[this_dev];
+ dev->base_addr=io[this_dev];
+ if (do_elmc_probe(dev) == 0) {
+ dev_elmc[this_dev] = dev;
+ found++;
+ continue;
+ }
+ free_netdev(dev);
+ if (io[this_dev]==0)
+ break;
+ pr_warning("3c523.c: No 3c523 card found at io=%#x\n",io[this_dev]);
+ }
+
+ if(found==0) {
+ if (io[0]==0)
+ pr_notice("3c523.c: No 3c523 cards found\n");
+ return -ENXIO;
+ } else return 0;
+}
+
+void __exit cleanup_module(void)
+{
+ int this_dev;
+ for (this_dev=0; this_dev<MAX_3C523_CARDS; this_dev++) {
+ struct net_device *dev = dev_elmc[this_dev];
+ if (dev) {
+ unregister_netdev(dev);
+ cleanup_card(dev);
+ free_netdev(dev);
+ }
+ }
+}
+
+#endif /* MODULE */
--- /dev/null
+#ifndef _3c523_INCLUDE_
+#define _3c523_INCLUDE_
+/*
+ This is basically a hacked version of ni52.h, for the 3c523
+ Etherlink/MC.
+*/
+
+/*
+ * Intel i82586 Ethernet definitions
+ *
+ * This is an extension to the Linux operating system, and is covered by the
+ * same GNU General Public License that covers that work.
+ *
+ * Copyright 1995 by Chris Beauregard (cpbeaure@undergrad.math.uwaterloo.ca)
+ *
+ * See 3c523.c for details.
+ *
+ * $Header: /home/chrisb/linux-1.2.13-3c523/drivers/net/RCS/3c523.h,v 1.6 1996/01/20 05:09:00 chrisb Exp chrisb $
+ */
+
+/*
+ * where to find the System Configuration Pointer (SCP)
+ */
+#define SCP_DEFAULT_ADDRESS 0xfffff4
+
+
+/*
+ * System Configuration Pointer Struct
+ */
+
+struct scp_struct
+{
+ unsigned short zero_dum0; /* has to be zero */
+ unsigned char sysbus; /* 0=16Bit,1=8Bit */
+ unsigned char zero_dum1; /* has to be zero for 586 */
+ unsigned short zero_dum2;
+ unsigned short zero_dum3;
+ char *iscp; /* pointer to the iscp-block */
+};
+
+
+/*
+ * Intermediate System Configuration Pointer (ISCP)
+ */
+struct iscp_struct
+{
+ unsigned char busy; /* 586 clears after successful init */
+ unsigned char zero_dummy; /* hast to be zero */
+ unsigned short scb_offset; /* pointeroffset to the scb_base */
+ char *scb_base; /* base-address of all 16-bit offsets */
+};
+
+/*
+ * System Control Block (SCB)
+ */
+struct scb_struct
+{
+ unsigned short status; /* status word */
+ unsigned short cmd; /* command word */
+ unsigned short cbl_offset; /* pointeroffset, command block list */
+ unsigned short rfa_offset; /* pointeroffset, receive frame area */
+ unsigned short crc_errs; /* CRC-Error counter */
+ unsigned short aln_errs; /* alignmenterror counter */
+ unsigned short rsc_errs; /* Resourceerror counter */
+ unsigned short ovrn_errs; /* OVerrunerror counter */
+};
+
+/*
+ * possible command values for the command word
+ */
+#define RUC_MASK 0x0070 /* mask for RU commands */
+#define RUC_NOP 0x0000 /* NOP-command */
+#define RUC_START 0x0010 /* start RU */
+#define RUC_RESUME 0x0020 /* resume RU after suspend */
+#define RUC_SUSPEND 0x0030 /* suspend RU */
+#define RUC_ABORT 0x0040 /* abort receiver operation immediately */
+
+#define CUC_MASK 0x0700 /* mask for CU command */
+#define CUC_NOP 0x0000 /* NOP-command */
+#define CUC_START 0x0100 /* start execution of 1. cmd on the CBL */
+#define CUC_RESUME 0x0200 /* resume after suspend */
+#define CUC_SUSPEND 0x0300 /* Suspend CU */
+#define CUC_ABORT 0x0400 /* abort command operation immediately */
+
+#define ACK_MASK 0xf000 /* mask for ACK command */
+#define ACK_CX 0x8000 /* acknowledges STAT_CX */
+#define ACK_FR 0x4000 /* ack. STAT_FR */
+#define ACK_CNA 0x2000 /* ack. STAT_CNA */
+#define ACK_RNR 0x1000 /* ack. STAT_RNR */
+
+/*
+ * possible status values for the status word
+ */
+#define STAT_MASK 0xf000 /* mask for cause of interrupt */
+#define STAT_CX 0x8000 /* CU finished cmd with its I bit set */
+#define STAT_FR 0x4000 /* RU finished receiving a frame */
+#define STAT_CNA 0x2000 /* CU left active state */
+#define STAT_RNR 0x1000 /* RU left ready state */
+
+#define CU_STATUS 0x700 /* CU status, 0=idle */
+#define CU_SUSPEND 0x100 /* CU is suspended */
+#define CU_ACTIVE 0x200 /* CU is active */
+
+#define RU_STATUS 0x70 /* RU status, 0=idle */
+#define RU_SUSPEND 0x10 /* RU suspended */
+#define RU_NOSPACE 0x20 /* RU no resources */
+#define RU_READY 0x40 /* RU is ready */
+
+/*
+ * Receive Frame Descriptor (RFD)
+ */
+struct rfd_struct
+{
+ unsigned short status; /* status word */
+ unsigned short last; /* Bit15,Last Frame on List / Bit14,suspend */
+ unsigned short next; /* linkoffset to next RFD */
+ unsigned short rbd_offset; /* pointeroffset to RBD-buffer */
+ unsigned char dest[6]; /* ethernet-address, destination */
+ unsigned char source[6]; /* ethernet-address, source */
+ unsigned short length; /* 802.3 frame-length */
+ unsigned short zero_dummy; /* dummy */
+};
+
+#define RFD_LAST 0x8000 /* last: last rfd in the list */
+#define RFD_SUSP 0x4000 /* last: suspend RU after */
+#define RFD_ERRMASK 0x0fe1 /* status: errormask */
+#define RFD_MATCHADD 0x0002 /* status: Destinationaddress !matches IA */
+#define RFD_RNR 0x0200 /* status: receiver out of resources */
+
+/*
+ * Receive Buffer Descriptor (RBD)
+ */
+struct rbd_struct
+{
+ unsigned short status; /* status word,number of used bytes in buff */
+ unsigned short next; /* pointeroffset to next RBD */
+ char *buffer; /* receive buffer address pointer */
+ unsigned short size; /* size of this buffer */
+ unsigned short zero_dummy; /* dummy */
+};
+
+#define RBD_LAST 0x8000 /* last buffer */
+#define RBD_USED 0x4000 /* this buffer has data */
+#define RBD_MASK 0x3fff /* size-mask for length */
+
+/*
+ * Statusvalues for Commands/RFD
+ */
+#define STAT_COMPL 0x8000 /* status: frame/command is complete */
+#define STAT_BUSY 0x4000 /* status: frame/command is busy */
+#define STAT_OK 0x2000 /* status: frame/command is ok */
+
+/*
+ * Action-Commands
+ */
+#define CMD_NOP 0x0000 /* NOP */
+#define CMD_IASETUP 0x0001 /* initial address setup command */
+#define CMD_CONFIGURE 0x0002 /* configure command */
+#define CMD_MCSETUP 0x0003 /* MC setup command */
+#define CMD_XMIT 0x0004 /* transmit command */
+#define CMD_TDR 0x0005 /* time domain reflectometer (TDR) command */
+#define CMD_DUMP 0x0006 /* dump command */
+#define CMD_DIAGNOSE 0x0007 /* diagnose command */
+
+/*
+ * Action command bits
+ */
+#define CMD_LAST 0x8000 /* indicates last command in the CBL */
+#define CMD_SUSPEND 0x4000 /* suspend CU after this CB */
+#define CMD_INT 0x2000 /* generate interrupt after execution */
+
+/*
+ * NOP - command
+ */
+struct nop_cmd_struct
+{
+ unsigned short cmd_status; /* status of this command */
+ unsigned short cmd_cmd; /* the command itself (+bits) */
+ unsigned short cmd_link; /* offsetpointer to next command */
+};
+
+/*
+ * IA Setup command
+ */
+struct iasetup_cmd_struct
+{
+ unsigned short cmd_status;
+ unsigned short cmd_cmd;
+ unsigned short cmd_link;
+ unsigned char iaddr[6];
+};
+
+/*
+ * Configure command
+ */
+struct configure_cmd_struct
+{
+ unsigned short cmd_status;
+ unsigned short cmd_cmd;
+ unsigned short cmd_link;
+ unsigned char byte_cnt; /* size of the config-cmd */
+ unsigned char fifo; /* fifo/recv monitor */
+ unsigned char sav_bf; /* save bad frames (bit7=1)*/
+ unsigned char adr_len; /* adr_len(0-2),al_loc(3),pream(4-5),loopbak(6-7)*/
+ unsigned char priority; /* lin_prio(0-2),exp_prio(4-6),bof_metd(7) */
+ unsigned char ifs; /* inter frame spacing */
+ unsigned char time_low; /* slot time low */
+ unsigned char time_high; /* slot time high(0-2) and max. retries(4-7) */
+ unsigned char promisc; /* promisc-mode(0) , et al (1-7) */
+ unsigned char carr_coll; /* carrier(0-3)/collision(4-7) stuff */
+ unsigned char fram_len; /* minimal frame len */
+ unsigned char dummy; /* dummy */
+};
+
+/*
+ * Multicast Setup command
+ */
+struct mcsetup_cmd_struct
+{
+ unsigned short cmd_status;
+ unsigned short cmd_cmd;
+ unsigned short cmd_link;
+ unsigned short mc_cnt; /* number of bytes in the MC-List */
+ unsigned char mc_list[0][6]; /* pointer to 6 bytes entries */
+};
+
+/*
+ * transmit command
+ */
+struct transmit_cmd_struct
+{
+ unsigned short cmd_status;
+ unsigned short cmd_cmd;
+ unsigned short cmd_link;
+ unsigned short tbd_offset; /* pointeroffset to TBD */
+ unsigned char dest[6]; /* destination address of the frame */
+ unsigned short length; /* user defined: 802.3 length / Ether type */
+};
+
+#define TCMD_ERRMASK 0x0fa0
+#define TCMD_MAXCOLLMASK 0x000f
+#define TCMD_MAXCOLL 0x0020
+#define TCMD_HEARTBEAT 0x0040
+#define TCMD_DEFERRED 0x0080
+#define TCMD_UNDERRUN 0x0100
+#define TCMD_LOSTCTS 0x0200
+#define TCMD_NOCARRIER 0x0400
+#define TCMD_LATECOLL 0x0800
+
+struct tdr_cmd_struct
+{
+ unsigned short cmd_status;
+ unsigned short cmd_cmd;
+ unsigned short cmd_link;
+ unsigned short status;
+};
+
+#define TDR_LNK_OK 0x8000 /* No link problem identified */
+#define TDR_XCVR_PRB 0x4000 /* indicates a transceiver problem */
+#define TDR_ET_OPN 0x2000 /* open, no correct termination */
+#define TDR_ET_SRT 0x1000 /* TDR detected a short circuit */
+#define TDR_TIMEMASK 0x07ff /* mask for the time field */
+
+/*
+ * Transmit Buffer Descriptor (TBD)
+ */
+struct tbd_struct
+{
+ unsigned short size; /* size + EOF-Flag(15) */
+ unsigned short next; /* pointeroffset to next TBD */
+ char *buffer; /* pointer to buffer */
+};
+
+#define TBD_LAST 0x8000 /* EOF-Flag, indicates last buffer in list */
+
+/*************************************************************************/
+/*
+Verbatim from the Crynwyr stuff:
+
+ The 3c523 responds with adapter code 0x6042 at slot
+registers xxx0 and xxx1. The setup register is at xxx2 and
+contains the following bits:
+
+0: card enable
+2,1: csr address select
+ 00 = 0300
+ 01 = 1300
+ 10 = 2300
+ 11 = 3300
+4,3: shared memory address select
+ 00 = 0c0000
+ 01 = 0c8000
+ 10 = 0d0000
+ 11 = 0d8000
+5: set to disable on-board thinnet
+7,6: (read-only) shows selected irq
+ 00 = 12
+ 01 = 7
+ 10 = 3
+ 11 = 9
+
+The interrupt-select register is at xxx3 and uses one bit per irq.
+
+0: int 12
+1: int 7
+2: int 3
+3: int 9
+
+ Again, the documentation stresses that the setup register
+should never be written. The interrupt-select register may be
+written with the value corresponding to bits 7.6 in
+the setup register to insure corret setup.
+*/
+
+/* Offsets from the base I/O address. */
+#define ELMC_SA 0 /* first 6 bytes are IEEE network address */
+#define ELMC_CTRL 6 /* control & status register */
+#define ELMC_REVISION 7 /* revision register, first 4 bits only */
+#define ELMC_IO_EXTENT 8
+
+/* these are the bit selects for the port register 2 */
+#define ELMC_STATUS_ENABLED 0x01
+#define ELMC_STATUS_CSR_SELECT 0x06
+#define ELMC_STATUS_MEMORY_SELECT 0x18
+#define ELMC_STATUS_DISABLE_THIN 0x20
+#define ELMC_STATUS_IRQ_SELECT 0xc0
+
+/* this is the card id used in the detection code. You might recognize
+it from @6042.adf */
+#define ELMC_MCA_ID 0x6042
+
+/*
+ The following define the bits for the control & status register
+
+ The bank select registers can be used if more than 16K of memory is
+ on the card. For some stupid reason, bank 3 is the one for the
+ bottom 16K, and the card defaults to bank 0. So we have to set the
+ bank to 3 before the card will even think of operating. To get bank
+ 3, set BS0 and BS1 to high (of course...)
+*/
+#define ELMC_CTRL_BS0 0x01 /* RW bank select */
+#define ELMC_CTRL_BS1 0x02 /* RW bank select */
+#define ELMC_CTRL_INTE 0x04 /* RW interrupt enable, assert high */
+#define ELMC_CTRL_INT 0x08 /* R interrupt active, assert high */
+/*#define ELMC_CTRL_* 0x10*/ /* reserved */
+#define ELMC_CTRL_LBK 0x20 /* RW loopback enable, assert high */
+#define ELMC_CTRL_CA 0x40 /* RW channel attention, assert high */
+#define ELMC_CTRL_RST 0x80 /* RW 82586 reset, assert low */
+
+/* some handy compound bits */
+
+/* normal operation should have bank 3 and RST high, ints enabled */
+#define ELMC_NORMAL (ELMC_CTRL_INTE|ELMC_CTRL_RST|0x3)
+
+#endif /* _3c523_INCLUDE_ */
--- /dev/null
+/* 3c527.c: 3Com Etherlink/MC32 driver for Linux 2.4 and 2.6.
+ *
+ * (c) Copyright 1998 Red Hat Software Inc
+ * Written by Alan Cox.
+ * Further debugging by Carl Drougge.
+ * Initial SMP support by Felipe W Damasio <felipewd@terra.com.br>
+ * Heavily modified by Richard Procter <rnp@paradise.net.nz>
+ *
+ * Based on skeleton.c written 1993-94 by Donald Becker and ne2.c
+ * (for the MCA stuff) written by Wim Dumon.
+ *
+ * Thanks to 3Com for making this possible by providing me with the
+ * documentation.
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ */
+
+#define DRV_NAME "3c527"
+#define DRV_VERSION "0.7-SMP"
+#define DRV_RELDATE "2003/09/21"
+
+static const char *version =
+DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " Richard Procter <rnp@paradise.net.nz>\n";
+
+/**
+ * DOC: Traps for the unwary
+ *
+ * The diagram (Figure 1-1) and the POS summary disagree with the
+ * "Interrupt Level" section in the manual.
+ *
+ * The manual contradicts itself when describing the minimum number
+ * buffers in the 'configure lists' command.
+ * My card accepts a buffer config of 4/4.
+ *
+ * Setting the SAV BP bit does not save bad packets, but
+ * only enables RX on-card stats collection.
+ *
+ * The documentation in places seems to miss things. In actual fact
+ * I've always eventually found everything is documented, it just
+ * requires careful study.
+ *
+ * DOC: Theory Of Operation
+ *
+ * The 3com 3c527 is a 32bit MCA bus mastering adapter with a large
+ * amount of on board intelligence that housekeeps a somewhat dumber
+ * Intel NIC. For performance we want to keep the transmit queue deep
+ * as the card can transmit packets while fetching others from main
+ * memory by bus master DMA. Transmission and reception are driven by
+ * circular buffer queues.
+ *
+ * The mailboxes can be used for controlling how the card traverses
+ * its buffer rings, but are used only for initial setup in this
+ * implementation. The exec mailbox allows a variety of commands to
+ * be executed. Each command must complete before the next is
+ * executed. Primarily we use the exec mailbox for controlling the
+ * multicast lists. We have to do a certain amount of interesting
+ * hoop jumping as the multicast list changes can occur in interrupt
+ * state when the card has an exec command pending. We defer such
+ * events until the command completion interrupt.
+ *
+ * A copy break scheme (taken from 3c59x.c) is employed whereby
+ * received frames exceeding a configurable length are passed
+ * directly to the higher networking layers without incuring a copy,
+ * in what amounts to a time/space trade-off.
+ *
+ * The card also keeps a large amount of statistical information
+ * on-board. In a perfect world, these could be used safely at no
+ * cost. However, lacking information to the contrary, processing
+ * them without races would involve so much extra complexity as to
+ * make it unworthwhile to do so. In the end, a hybrid SW/HW
+ * implementation was made necessary --- see mc32_update_stats().
+ *
+ * DOC: Notes
+ *
+ * It should be possible to use two or more cards, but at this stage
+ * only by loading two copies of the same module.
+ *
+ * The on-board 82586 NIC has trouble receiving multiple
+ * back-to-back frames and so is likely to drop packets from fast
+ * senders.
+**/
+
+#include <linux/module.h>
+
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/if_ether.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/mca-legacy.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/wait.h>
+#include <linux/ethtool.h>
+#include <linux/completion.h>
+#include <linux/bitops.h>
+#include <linux/semaphore.h>
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#include "3c527.h"
+
+MODULE_LICENSE("GPL");
+
+/*
+ * The name of the card. Is used for messages and in the requests for
+ * io regions, irqs and dma channels
+ */
+static const char* cardname = DRV_NAME;
+
+/* use 0 for production, 1 for verification, >2 for debug */
+#ifndef NET_DEBUG
+#define NET_DEBUG 2
+#endif
+
+static unsigned int mc32_debug = NET_DEBUG;
+
+/* The number of low I/O ports used by the ethercard. */
+#define MC32_IO_EXTENT 8
+
+/* As implemented, values must be a power-of-2 -- 4/8/16/32 */
+#define TX_RING_LEN 32 /* Typically the card supports 37 */
+#define RX_RING_LEN 8 /* " " " */
+
+/* Copy break point, see above for details.
+ * Setting to > 1512 effectively disables this feature. */
+#define RX_COPYBREAK 200 /* Value from 3c59x.c */
+
+/* Issue the 82586 workaround command - this is for "busy lans", but
+ * basically means for all lans now days - has a performance (latency)
+ * cost, but best set. */
+static const int WORKAROUND_82586=1;
+
+/* Pointers to buffers and their on-card records */
+struct mc32_ring_desc
+{
+ volatile struct skb_header *p;
+ struct sk_buff *skb;
+};
+
+/* Information that needs to be kept for each board. */
+struct mc32_local
+{
+ int slot;
+
+ u32 base;
+ volatile struct mc32_mailbox *rx_box;
+ volatile struct mc32_mailbox *tx_box;
+ volatile struct mc32_mailbox *exec_box;
+ volatile struct mc32_stats *stats; /* Start of on-card statistics */
+ u16 tx_chain; /* Transmit list start offset */
+ u16 rx_chain; /* Receive list start offset */
+ u16 tx_len; /* Transmit list count */
+ u16 rx_len; /* Receive list count */
+
+ u16 xceiver_desired_state; /* HALTED or RUNNING */
+ u16 cmd_nonblocking; /* Thread is uninterested in command result */
+ u16 mc_reload_wait; /* A multicast load request is pending */
+ u32 mc_list_valid; /* True when the mclist is set */
+
+ struct mc32_ring_desc tx_ring[TX_RING_LEN]; /* Host Transmit ring */
+ struct mc32_ring_desc rx_ring[RX_RING_LEN]; /* Host Receive ring */
+
+ atomic_t tx_count; /* buffers left */
+ atomic_t tx_ring_head; /* index to tx en-queue end */
+ u16 tx_ring_tail; /* index to tx de-queue end */
+
+ u16 rx_ring_tail; /* index to rx de-queue end */
+
+ struct semaphore cmd_mutex; /* Serialises issuing of execute commands */
+ struct completion execution_cmd; /* Card has completed an execute command */
+ struct completion xceiver_cmd; /* Card has completed a tx or rx command */
+};
+
+/* The station (ethernet) address prefix, used for a sanity check. */
+#define SA_ADDR0 0x02
+#define SA_ADDR1 0x60
+#define SA_ADDR2 0xAC
+
+struct mca_adapters_t {
+ unsigned int id;
+ char *name;
+};
+
+static const struct mca_adapters_t mc32_adapters[] = {
+ { 0x0041, "3COM EtherLink MC/32" },
+ { 0x8EF5, "IBM High Performance Lan Adapter" },
+ { 0x0000, NULL }
+};
+
+
+/* Macros for ring index manipulations */
+static inline u16 next_rx(u16 rx) { return (rx+1)&(RX_RING_LEN-1); };
+static inline u16 prev_rx(u16 rx) { return (rx-1)&(RX_RING_LEN-1); };
+
+static inline u16 next_tx(u16 tx) { return (tx+1)&(TX_RING_LEN-1); };
+
+
+/* Index to functions, as function prototypes. */
+static int mc32_probe1(struct net_device *dev, int ioaddr);
+static int mc32_command(struct net_device *dev, u16 cmd, void *data, int len);
+static int mc32_open(struct net_device *dev);
+static void mc32_timeout(struct net_device *dev);
+static netdev_tx_t mc32_send_packet(struct sk_buff *skb,
+ struct net_device *dev);
+static irqreturn_t mc32_interrupt(int irq, void *dev_id);
+static int mc32_close(struct net_device *dev);
+static struct net_device_stats *mc32_get_stats(struct net_device *dev);
+static void mc32_set_multicast_list(struct net_device *dev);
+static void mc32_reset_multicast_list(struct net_device *dev);
+static const struct ethtool_ops netdev_ethtool_ops;
+
+static void cleanup_card(struct net_device *dev)
+{
+ struct mc32_local *lp = netdev_priv(dev);
+ unsigned slot = lp->slot;
+ mca_mark_as_unused(slot);
+ mca_set_adapter_name(slot, NULL);
+ free_irq(dev->irq, dev);
+ release_region(dev->base_addr, MC32_IO_EXTENT);
+}
+
+/**
+ * mc32_probe - Search for supported boards
+ * @unit: interface number to use
+ *
+ * Because MCA bus is a real bus and we can scan for cards we could do a
+ * single scan for all boards here. Right now we use the passed in device
+ * structure and scan for only one board. This needs fixing for modules
+ * in particular.
+ */
+
+struct net_device *__init mc32_probe(int unit)
+{
+ struct net_device *dev = alloc_etherdev(sizeof(struct mc32_local));
+ static int current_mca_slot = -1;
+ int i;
+ int err;
+
+ if (!dev)
+ return ERR_PTR(-ENOMEM);
+
+ if (unit >= 0)
+ sprintf(dev->name, "eth%d", unit);
+
+ /* Do not check any supplied i/o locations.
+ POS registers usually don't fail :) */
+
+ /* MCA cards have POS registers.
+ Autodetecting MCA cards is extremely simple.
+ Just search for the card. */
+
+ for(i = 0; (mc32_adapters[i].name != NULL); i++) {
+ current_mca_slot =
+ mca_find_unused_adapter(mc32_adapters[i].id, 0);
+
+ if(current_mca_slot != MCA_NOTFOUND) {
+ if(!mc32_probe1(dev, current_mca_slot))
+ {
+ mca_set_adapter_name(current_mca_slot,
+ mc32_adapters[i].name);
+ mca_mark_as_used(current_mca_slot);
+ err = register_netdev(dev);
+ if (err) {
+ cleanup_card(dev);
+ free_netdev(dev);
+ dev = ERR_PTR(err);
+ }
+ return dev;
+ }
+
+ }
+ }
+ free_netdev(dev);
+ return ERR_PTR(-ENODEV);
+}
+
+static const struct net_device_ops netdev_ops = {
+ .ndo_open = mc32_open,
+ .ndo_stop = mc32_close,
+ .ndo_start_xmit = mc32_send_packet,
+ .ndo_get_stats = mc32_get_stats,
+ .ndo_set_multicast_list = mc32_set_multicast_list,
+ .ndo_tx_timeout = mc32_timeout,
+ .ndo_change_mtu = eth_change_mtu,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+};
+
+/**
+ * mc32_probe1 - Check a given slot for a board and test the card
+ * @dev: Device structure to fill in
+ * @slot: The MCA bus slot being used by this card
+ *
+ * Decode the slot data and configure the card structures. Having done this we
+ * can reset the card and configure it. The card does a full self test cycle
+ * in firmware so we have to wait for it to return and post us either a
+ * failure case or some addresses we use to find the board internals.
+ */
+
+static int __init mc32_probe1(struct net_device *dev, int slot)
+{
+ static unsigned version_printed;
+ int i, err;
+ u8 POS;
+ u32 base;
+ struct mc32_local *lp = netdev_priv(dev);
+ static const u16 mca_io_bases[] = {
+ 0x7280,0x7290,
+ 0x7680,0x7690,
+ 0x7A80,0x7A90,
+ 0x7E80,0x7E90
+ };
+ static const u32 mca_mem_bases[] = {
+ 0x00C0000,
+ 0x00C4000,
+ 0x00C8000,
+ 0x00CC000,
+ 0x00D0000,
+ 0x00D4000,
+ 0x00D8000,
+ 0x00DC000
+ };
+ static const char * const failures[] = {
+ "Processor instruction",
+ "Processor data bus",
+ "Processor data bus",
+ "Processor data bus",
+ "Adapter bus",
+ "ROM checksum",
+ "Base RAM",
+ "Extended RAM",
+ "82586 internal loopback",
+ "82586 initialisation failure",
+ "Adapter list configuration error"
+ };
+
+ /* Time to play MCA games */
+
+ if (mc32_debug && version_printed++ == 0)
+ pr_debug("%s", version);
+
+ pr_info("%s: %s found in slot %d: ", dev->name, cardname, slot);
+
+ POS = mca_read_stored_pos(slot, 2);
+
+ if(!(POS&1))
+ {
+ pr_cont("disabled.\n");
+ return -ENODEV;
+ }
+
+ /* Fill in the 'dev' fields. */
+ dev->base_addr = mca_io_bases[(POS>>1)&7];
+ dev->mem_start = mca_mem_bases[(POS>>4)&7];
+
+ POS = mca_read_stored_pos(slot, 4);
+ if(!(POS&1))
+ {
+ pr_cont("memory window disabled.\n");
+ return -ENODEV;
+ }
+
+ POS = mca_read_stored_pos(slot, 5);
+
+ i=(POS>>4)&3;
+ if(i==3)
+ {
+ pr_cont("invalid memory window.\n");
+ return -ENODEV;
+ }
+
+ i*=16384;
+ i+=16384;
+
+ dev->mem_end=dev->mem_start + i;
+
+ dev->irq = ((POS>>2)&3)+9;
+
+ if(!request_region(dev->base_addr, MC32_IO_EXTENT, cardname))
+ {
+ pr_cont("io 0x%3lX, which is busy.\n", dev->base_addr);
+ return -EBUSY;
+ }
+
+ pr_cont("io 0x%3lX irq %d mem 0x%lX (%dK)\n",
+ dev->base_addr, dev->irq, dev->mem_start, i/1024);
+
+
+ /* We ought to set the cache line size here.. */
+
+
+ /*
+ * Go PROM browsing
+ */
+
+ /* Retrieve and print the ethernet address. */
+ for (i = 0; i < 6; i++)
+ {
+ mca_write_pos(slot, 6, i+12);
+ mca_write_pos(slot, 7, 0);
+
+ dev->dev_addr[i] = mca_read_pos(slot,3);
+ }
+
+ pr_info("%s: Address %pM ", dev->name, dev->dev_addr);
+
+ mca_write_pos(slot, 6, 0);
+ mca_write_pos(slot, 7, 0);
+
+ POS = mca_read_stored_pos(slot, 4);
+
+ if(POS&2)
+ pr_cont(": BNC port selected.\n");
+ else
+ pr_cont(": AUI port selected.\n");
+
+ POS=inb(dev->base_addr+HOST_CTRL);
+ POS|=HOST_CTRL_ATTN|HOST_CTRL_RESET;
+ POS&=~HOST_CTRL_INTE;
+ outb(POS, dev->base_addr+HOST_CTRL);
+ /* Reset adapter */
+ udelay(100);
+ /* Reset off */
+ POS&=~(HOST_CTRL_ATTN|HOST_CTRL_RESET);
+ outb(POS, dev->base_addr+HOST_CTRL);
+
+ udelay(300);
+
+ /*
+ * Grab the IRQ
+ */
+
+ err = request_irq(dev->irq, mc32_interrupt, IRQF_SHARED, DRV_NAME, dev);
+ if (err) {
+ release_region(dev->base_addr, MC32_IO_EXTENT);
+ pr_err("%s: unable to get IRQ %d.\n", DRV_NAME, dev->irq);
+ goto err_exit_ports;
+ }
+
+ memset(lp, 0, sizeof(struct mc32_local));
+ lp->slot = slot;
+
+ i=0;
+
+ base = inb(dev->base_addr);
+
+ while(base == 0xFF)
+ {
+ i++;
+ if(i == 1000)
+ {
+ pr_err("%s: failed to boot adapter.\n", dev->name);
+ err = -ENODEV;
+ goto err_exit_irq;
+ }
+ udelay(1000);
+ if(inb(dev->base_addr+2)&(1<<5))
+ base = inb(dev->base_addr);
+ }
+
+ if(base>0)
+ {
+ if(base < 0x0C)
+ pr_err("%s: %s%s.\n", dev->name, failures[base-1],
+ base<0x0A?" test failure":"");
+ else
+ pr_err("%s: unknown failure %d.\n", dev->name, base);
+ err = -ENODEV;
+ goto err_exit_irq;
+ }
+
+ base=0;
+ for(i=0;i<4;i++)
+ {
+ int n=0;
+
+ while(!(inb(dev->base_addr+2)&(1<<5)))
+ {
+ n++;
+ udelay(50);
+ if(n>100)
+ {
+ pr_err("%s: mailbox read fail (%d).\n", dev->name, i);
+ err = -ENODEV;
+ goto err_exit_irq;
+ }
+ }
+
+ base|=(inb(dev->base_addr)<<(8*i));
+ }
+
+ lp->exec_box=isa_bus_to_virt(dev->mem_start+base);
+
+ base=lp->exec_box->data[1]<<16|lp->exec_box->data[0];
+
+ lp->base = dev->mem_start+base;
+
+ lp->rx_box=isa_bus_to_virt(lp->base + lp->exec_box->data[2]);
+ lp->tx_box=isa_bus_to_virt(lp->base + lp->exec_box->data[3]);
+
+ lp->stats = isa_bus_to_virt(lp->base + lp->exec_box->data[5]);
+
+ /*
+ * Descriptor chains (card relative)
+ */
+
+ lp->tx_chain = lp->exec_box->data[8]; /* Transmit list start offset */
+ lp->rx_chain = lp->exec_box->data[10]; /* Receive list start offset */
+ lp->tx_len = lp->exec_box->data[9]; /* Transmit list count */
+ lp->rx_len = lp->exec_box->data[11]; /* Receive list count */
+
+ sema_init(&lp->cmd_mutex, 0);
+ init_completion(&lp->execution_cmd);
+ init_completion(&lp->xceiver_cmd);
+
+ pr_info("%s: Firmware Rev %d. %d RX buffers, %d TX buffers. Base of 0x%08X.\n",
+ dev->name, lp->exec_box->data[12], lp->rx_len, lp->tx_len, lp->base);
+
+ dev->netdev_ops = &netdev_ops;
+ dev->watchdog_timeo = HZ*5; /* Board does all the work */
+ dev->ethtool_ops = &netdev_ethtool_ops;
+
+ return 0;
+
+err_exit_irq:
+ free_irq(dev->irq, dev);
+err_exit_ports:
+ release_region(dev->base_addr, MC32_IO_EXTENT);
+ return err;
+}
+
+
+/**
+ * mc32_ready_poll - wait until we can feed it a command
+ * @dev: The device to wait for
+ *
+ * Wait until the card becomes ready to accept a command via the
+ * command register. This tells us nothing about the completion
+ * status of any pending commands and takes very little time at all.
+ */
+
+static inline void mc32_ready_poll(struct net_device *dev)
+{
+ int ioaddr = dev->base_addr;
+ while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));
+}
+
+
+/**
+ * mc32_command_nowait - send a command non blocking
+ * @dev: The 3c527 to issue the command to
+ * @cmd: The command word to write to the mailbox
+ * @data: A data block if the command expects one
+ * @len: Length of the data block
+ *
+ * Send a command from interrupt state. If there is a command
+ * currently being executed then we return an error of -1. It
+ * simply isn't viable to wait around as commands may be
+ * slow. This can theoretically be starved on SMP, but it's hard
+ * to see a realistic situation. We do not wait for the command
+ * to complete --- we rely on the interrupt handler to tidy up
+ * after us.
+ */
+
+static int mc32_command_nowait(struct net_device *dev, u16 cmd, void *data, int len)
+{
+ struct mc32_local *lp = netdev_priv(dev);
+ int ioaddr = dev->base_addr;
+ int ret = -1;
+
+ if (down_trylock(&lp->cmd_mutex) == 0)
+ {
+ lp->cmd_nonblocking=1;
+ lp->exec_box->mbox=0;
+ lp->exec_box->mbox=cmd;
+ memcpy((void *)lp->exec_box->data, data, len);
+ barrier(); /* the memcpy forgot the volatile so be sure */
+
+ /* Send the command */
+ mc32_ready_poll(dev);
+ outb(1<<6, ioaddr+HOST_CMD);
+
+ ret = 0;
+
+ /* Interrupt handler will signal mutex on completion */
+ }
+
+ return ret;
+}
+
+
+/**
+ * mc32_command - send a command and sleep until completion
+ * @dev: The 3c527 card to issue the command to
+ * @cmd: The command word to write to the mailbox
+ * @data: A data block if the command expects one
+ * @len: Length of the data block
+ *
+ * Sends exec commands in a user context. This permits us to wait around
+ * for the replies and also to wait for the command buffer to complete
+ * from a previous command before we execute our command. After our
+ * command completes we will attempt any pending multicast reload
+ * we blocked off by hogging the exec buffer.
+ *
+ * You feed the card a command, you wait, it interrupts you get a
+ * reply. All well and good. The complication arises because you use
+ * commands for filter list changes which come in at bh level from things
+ * like IPV6 group stuff.
+ */
+
+static int mc32_command(struct net_device *dev, u16 cmd, void *data, int len)
+{
+ struct mc32_local *lp = netdev_priv(dev);
+ int ioaddr = dev->base_addr;
+ int ret = 0;
+
+ down(&lp->cmd_mutex);
+
+ /*
+ * My Turn
+ */
+
+ lp->cmd_nonblocking=0;
+ lp->exec_box->mbox=0;
+ lp->exec_box->mbox=cmd;
+ memcpy((void *)lp->exec_box->data, data, len);
+ barrier(); /* the memcpy forgot the volatile so be sure */
+
+ mc32_ready_poll(dev);
+ outb(1<<6, ioaddr+HOST_CMD);
+
+ wait_for_completion(&lp->execution_cmd);
+
+ if(lp->exec_box->mbox&(1<<13))
+ ret = -1;
+
+ up(&lp->cmd_mutex);
+
+ /*
+ * A multicast set got blocked - try it now
+ */
+
+ if(lp->mc_reload_wait)
+ {
+ mc32_reset_multicast_list(dev);
+ }
+
+ return ret;
+}
+
+
+/**
+ * mc32_start_transceiver - tell board to restart tx/rx
+ * @dev: The 3c527 card to issue the command to
+ *
+ * This may be called from the interrupt state, where it is used
+ * to restart the rx ring if the card runs out of rx buffers.
+ *
+ * We must first check if it's ok to (re)start the transceiver. See
+ * mc32_close for details.
+ */
+
+static void mc32_start_transceiver(struct net_device *dev) {
+
+ struct mc32_local *lp = netdev_priv(dev);
+ int ioaddr = dev->base_addr;
+
+ /* Ignore RX overflow on device closure */
+ if (lp->xceiver_desired_state==HALTED)
+ return;
+
+ /* Give the card the offset to the post-EOL-bit RX descriptor */
+ mc32_ready_poll(dev);
+ lp->rx_box->mbox=0;
+ lp->rx_box->data[0]=lp->rx_ring[prev_rx(lp->rx_ring_tail)].p->next;
+ outb(HOST_CMD_START_RX, ioaddr+HOST_CMD);
+
+ mc32_ready_poll(dev);
+ lp->tx_box->mbox=0;
+ outb(HOST_CMD_RESTRT_TX, ioaddr+HOST_CMD); /* card ignores this on RX restart */
+
+ /* We are not interrupted on start completion */
+}
+
+
+/**
+ * mc32_halt_transceiver - tell board to stop tx/rx
+ * @dev: The 3c527 card to issue the command to
+ *
+ * We issue the commands to halt the card's transceiver. In fact,
+ * after some experimenting we now simply tell the card to
+ * suspend. When issuing aborts occasionally odd things happened.
+ *
+ * We then sleep until the card has notified us that both rx and
+ * tx have been suspended.
+ */
+
+static void mc32_halt_transceiver(struct net_device *dev)
+{
+ struct mc32_local *lp = netdev_priv(dev);
+ int ioaddr = dev->base_addr;
+
+ mc32_ready_poll(dev);
+ lp->rx_box->mbox=0;
+ outb(HOST_CMD_SUSPND_RX, ioaddr+HOST_CMD);
+ wait_for_completion(&lp->xceiver_cmd);
+
+ mc32_ready_poll(dev);
+ lp->tx_box->mbox=0;
+ outb(HOST_CMD_SUSPND_TX, ioaddr+HOST_CMD);
+ wait_for_completion(&lp->xceiver_cmd);
+}
+
+
+/**
+ * mc32_load_rx_ring - load the ring of receive buffers
+ * @dev: 3c527 to build the ring for
+ *
+ * This initialises the on-card and driver datastructures to
+ * the point where mc32_start_transceiver() can be called.
+ *
+ * The card sets up the receive ring for us. We are required to use the
+ * ring it provides, although the size of the ring is configurable.
+ *
+ * We allocate an sk_buff for each ring entry in turn and
+ * initialise its house-keeping info. At the same time, we read
+ * each 'next' pointer in our rx_ring array. This reduces slow
+ * shared-memory reads and makes it easy to access predecessor
+ * descriptors.
+ *
+ * We then set the end-of-list bit for the last entry so that the
+ * card will know when it has run out of buffers.
+ */
+
+static int mc32_load_rx_ring(struct net_device *dev)
+{
+ struct mc32_local *lp = netdev_priv(dev);
+ int i;
+ u16 rx_base;
+ volatile struct skb_header *p;
+
+ rx_base=lp->rx_chain;
+
+ for(i=0; i<RX_RING_LEN; i++) {
+ lp->rx_ring[i].skb=alloc_skb(1532, GFP_KERNEL);
+ if (lp->rx_ring[i].skb==NULL) {
+ for (;i>=0;i--)
+ kfree_skb(lp->rx_ring[i].skb);
+ return -ENOBUFS;
+ }
+ skb_reserve(lp->rx_ring[i].skb, 18);
+
+ p=isa_bus_to_virt(lp->base+rx_base);
+
+ p->control=0;
+ p->data=isa_virt_to_bus(lp->rx_ring[i].skb->data);
+ p->status=0;
+ p->length=1532;
+
+ lp->rx_ring[i].p=p;
+ rx_base=p->next;
+ }
+
+ lp->rx_ring[i-1].p->control |= CONTROL_EOL;
+
+ lp->rx_ring_tail=0;
+
+ return 0;
+}
+
+
+/**
+ * mc32_flush_rx_ring - free the ring of receive buffers
+ * @lp: Local data of 3c527 to flush the rx ring of
+ *
+ * Free the buffer for each ring slot. This may be called
+ * before mc32_load_rx_ring(), eg. on error in mc32_open().
+ * Requires rx skb pointers to point to a valid skb, or NULL.
+ */
+
+static void mc32_flush_rx_ring(struct net_device *dev)
+{
+ struct mc32_local *lp = netdev_priv(dev);
+ int i;
+
+ for(i=0; i < RX_RING_LEN; i++)
+ {
+ if (lp->rx_ring[i].skb) {
+ dev_kfree_skb(lp->rx_ring[i].skb);
+ lp->rx_ring[i].skb = NULL;
+ }
+ lp->rx_ring[i].p=NULL;
+ }
+}
+
+
+/**
+ * mc32_load_tx_ring - load transmit ring
+ * @dev: The 3c527 card to issue the command to
+ *
+ * This sets up the host transmit data-structures.
+ *
+ * First, we obtain from the card it's current position in the tx
+ * ring, so that we will know where to begin transmitting
+ * packets.
+ *
+ * Then, we read the 'next' pointers from the on-card tx ring into
+ * our tx_ring array to reduce slow shared-mem reads. Finally, we
+ * intitalise the tx house keeping variables.
+ *
+ */
+
+static void mc32_load_tx_ring(struct net_device *dev)
+{
+ struct mc32_local *lp = netdev_priv(dev);
+ volatile struct skb_header *p;
+ int i;
+ u16 tx_base;
+
+ tx_base=lp->tx_box->data[0];
+
+ for(i=0 ; i<TX_RING_LEN ; i++)
+ {
+ p=isa_bus_to_virt(lp->base+tx_base);
+ lp->tx_ring[i].p=p;
+ lp->tx_ring[i].skb=NULL;
+
+ tx_base=p->next;
+ }
+
+ /* -1 so that tx_ring_head cannot "lap" tx_ring_tail */
+ /* see mc32_tx_ring */
+
+ atomic_set(&lp->tx_count, TX_RING_LEN-1);
+ atomic_set(&lp->tx_ring_head, 0);
+ lp->tx_ring_tail=0;
+}
+
+
+/**
+ * mc32_flush_tx_ring - free transmit ring
+ * @lp: Local data of 3c527 to flush the tx ring of
+ *
+ * If the ring is non-empty, zip over the it, freeing any
+ * allocated skb_buffs. The tx ring house-keeping variables are
+ * then reset. Requires rx skb pointers to point to a valid skb,
+ * or NULL.
+ */
+
+static void mc32_flush_tx_ring(struct net_device *dev)
+{
+ struct mc32_local *lp = netdev_priv(dev);
+ int i;
+
+ for (i=0; i < TX_RING_LEN; i++)
+ {
+ if (lp->tx_ring[i].skb)
+ {
+ dev_kfree_skb(lp->tx_ring[i].skb);
+ lp->tx_ring[i].skb = NULL;
+ }
+ }
+
+ atomic_set(&lp->tx_count, 0);
+ atomic_set(&lp->tx_ring_head, 0);
+ lp->tx_ring_tail=0;
+}
+
+
+/**
+ * mc32_open - handle 'up' of card
+ * @dev: device to open
+ *
+ * The user is trying to bring the card into ready state. This requires
+ * a brief dialogue with the card. Firstly we enable interrupts and then
+ * 'indications'. Without these enabled the card doesn't bother telling
+ * us what it has done. This had me puzzled for a week.
+ *
+ * We configure the number of card descriptors, then load the network
+ * address and multicast filters. Turn on the workaround mode. This
+ * works around a bug in the 82586 - it asks the firmware to do
+ * so. It has a performance (latency) hit but is needed on busy
+ * [read most] lans. We load the ring with buffers then we kick it
+ * all off.
+ */
+
+static int mc32_open(struct net_device *dev)
+{
+ int ioaddr = dev->base_addr;
+ struct mc32_local *lp = netdev_priv(dev);
+ u8 one=1;
+ u8 regs;
+ u16 descnumbuffs[2] = {TX_RING_LEN, RX_RING_LEN};
+
+ /*
+ * Interrupts enabled
+ */
+
+ regs=inb(ioaddr+HOST_CTRL);
+ regs|=HOST_CTRL_INTE;
+ outb(regs, ioaddr+HOST_CTRL);
+
+ /*
+ * Allow ourselves to issue commands
+ */
+
+ up(&lp->cmd_mutex);
+
+
+ /*
+ * Send the indications on command
+ */
+
+ mc32_command(dev, 4, &one, 2);
+
+ /*
+ * Poke it to make sure it's really dead.
+ */
+
+ mc32_halt_transceiver(dev);
+ mc32_flush_tx_ring(dev);
+
+ /*
+ * Ask card to set up on-card descriptors to our spec
+ */
+
+ if(mc32_command(dev, 8, descnumbuffs, 4)) {
+ pr_info("%s: %s rejected our buffer configuration!\n",
+ dev->name, cardname);
+ mc32_close(dev);
+ return -ENOBUFS;
+ }
+
+ /* Report new configuration */
+ mc32_command(dev, 6, NULL, 0);
+
+ lp->tx_chain = lp->exec_box->data[8]; /* Transmit list start offset */
+ lp->rx_chain = lp->exec_box->data[10]; /* Receive list start offset */
+ lp->tx_len = lp->exec_box->data[9]; /* Transmit list count */
+ lp->rx_len = lp->exec_box->data[11]; /* Receive list count */
+
+ /* Set Network Address */
+ mc32_command(dev, 1, dev->dev_addr, 6);
+
+ /* Set the filters */
+ mc32_set_multicast_list(dev);
+
+ if (WORKAROUND_82586) {
+ u16 zero_word=0;
+ mc32_command(dev, 0x0D, &zero_word, 2); /* 82586 bug workaround on */
+ }
+
+ mc32_load_tx_ring(dev);
+
+ if(mc32_load_rx_ring(dev))
+ {
+ mc32_close(dev);
+ return -ENOBUFS;
+ }
+
+ lp->xceiver_desired_state = RUNNING;
+
+ /* And finally, set the ball rolling... */
+ mc32_start_transceiver(dev);
+
+ netif_start_queue(dev);
+
+ return 0;
+}
+
+
+/**
+ * mc32_timeout - handle a timeout from the network layer
+ * @dev: 3c527 that timed out
+ *
+ * Handle a timeout on transmit from the 3c527. This normally means
+ * bad things as the hardware handles cable timeouts and mess for
+ * us.
+ *
+ */
+
+static void mc32_timeout(struct net_device *dev)
+{
+ pr_warning("%s: transmit timed out?\n", dev->name);
+ /* Try to restart the adaptor. */
+ netif_wake_queue(dev);
+}
+
+
+/**
+ * mc32_send_packet - queue a frame for transmit
+ * @skb: buffer to transmit
+ * @dev: 3c527 to send it out of
+ *
+ * Transmit a buffer. This normally means throwing the buffer onto
+ * the transmit queue as the queue is quite large. If the queue is
+ * full then we set tx_busy and return. Once the interrupt handler
+ * gets messages telling it to reclaim transmit queue entries, we will
+ * clear tx_busy and the kernel will start calling this again.
+ *
+ * We do not disable interrupts or acquire any locks; this can
+ * run concurrently with mc32_tx_ring(), and the function itself
+ * is serialised at a higher layer. However, similarly for the
+ * card itself, we must ensure that we update tx_ring_head only
+ * after we've established a valid packet on the tx ring (and
+ * before we let the card "see" it, to prevent it racing with the
+ * irq handler).
+ *
+ */
+
+static netdev_tx_t mc32_send_packet(struct sk_buff *skb,
+ struct net_device *dev)
+{
+ struct mc32_local *lp = netdev_priv(dev);
+ u32 head = atomic_read(&lp->tx_ring_head);
+
+ volatile struct skb_header *p, *np;
+
+ netif_stop_queue(dev);
+
+ if(atomic_read(&lp->tx_count)==0) {
+ return NETDEV_TX_BUSY;
+ }
+
+ if (skb_padto(skb, ETH_ZLEN)) {
+ netif_wake_queue(dev);
+ return NETDEV_TX_OK;
+ }
+
+ atomic_dec(&lp->tx_count);
+
+ /* P is the last sending/sent buffer as a pointer */
+ p=lp->tx_ring[head].p;
+
+ head = next_tx(head);
+
+ /* NP is the buffer we will be loading */
+ np=lp->tx_ring[head].p;
+
+ /* We will need this to flush the buffer out */
+ lp->tx_ring[head].skb=skb;
+
+ np->length = unlikely(skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len;
+ np->data = isa_virt_to_bus(skb->data);
+ np->status = 0;
+ np->control = CONTROL_EOP | CONTROL_EOL;
+ wmb();
+
+ /*
+ * The new frame has been setup; we can now
+ * let the interrupt handler and card "see" it
+ */
+
+ atomic_set(&lp->tx_ring_head, head);
+ p->control &= ~CONTROL_EOL;
+
+ netif_wake_queue(dev);
+ return NETDEV_TX_OK;
+}
+
+
+/**
+ * mc32_update_stats - pull off the on board statistics
+ * @dev: 3c527 to service
+ *
+ *
+ * Query and reset the on-card stats. There's the small possibility
+ * of a race here, which would result in an underestimation of
+ * actual errors. As such, we'd prefer to keep all our stats
+ * collection in software. As a rule, we do. However it can't be
+ * used for rx errors and collisions as, by default, the card discards
+ * bad rx packets.
+ *
+ * Setting the SAV BP in the rx filter command supposedly
+ * stops this behaviour. However, testing shows that it only seems to
+ * enable the collation of on-card rx statistics --- the driver
+ * never sees an RX descriptor with an error status set.
+ *
+ */
+
+static void mc32_update_stats(struct net_device *dev)
+{
+ struct mc32_local *lp = netdev_priv(dev);
+ volatile struct mc32_stats *st = lp->stats;
+
+ u32 rx_errors=0;
+
+ rx_errors+=dev->stats.rx_crc_errors +=st->rx_crc_errors;
+ st->rx_crc_errors=0;
+ rx_errors+=dev->stats.rx_fifo_errors +=st->rx_overrun_errors;
+ st->rx_overrun_errors=0;
+ rx_errors+=dev->stats.rx_frame_errors +=st->rx_alignment_errors;
+ st->rx_alignment_errors=0;
+ rx_errors+=dev->stats.rx_length_errors+=st->rx_tooshort_errors;
+ st->rx_tooshort_errors=0;
+ rx_errors+=dev->stats.rx_missed_errors+=st->rx_outofresource_errors;
+ st->rx_outofresource_errors=0;
+ dev->stats.rx_errors=rx_errors;
+
+ /* Number of packets which saw one collision */
+ dev->stats.collisions+=st->dataC[10];
+ st->dataC[10]=0;
+
+ /* Number of packets which saw 2--15 collisions */
+ dev->stats.collisions+=st->dataC[11];
+ st->dataC[11]=0;
+}
+
+
+/**
+ * mc32_rx_ring - process the receive ring
+ * @dev: 3c527 that needs its receive ring processing
+ *
+ *
+ * We have received one or more indications from the card that a
+ * receive has completed. The buffer ring thus contains dirty
+ * entries. We walk the ring by iterating over the circular rx_ring
+ * array, starting at the next dirty buffer (which happens to be the
+ * one we finished up at last time around).
+ *
+ * For each completed packet, we will either copy it and pass it up
+ * the stack or, if the packet is near MTU sized, we allocate
+ * another buffer and flip the old one up the stack.
+ *
+ * We must succeed in keeping a buffer on the ring. If necessary we
+ * will toss a received packet rather than lose a ring entry. Once
+ * the first uncompleted descriptor is found, we move the
+ * End-Of-List bit to include the buffers just processed.
+ *
+ */
+
+static void mc32_rx_ring(struct net_device *dev)
+{
+ struct mc32_local *lp = netdev_priv(dev);
+ volatile struct skb_header *p;
+ u16 rx_ring_tail;
+ u16 rx_old_tail;
+ int x=0;
+
+ rx_old_tail = rx_ring_tail = lp->rx_ring_tail;
+
+ do
+ {
+ p=lp->rx_ring[rx_ring_tail].p;
+
+ if(!(p->status & (1<<7))) { /* Not COMPLETED */
+ break;
+ }
+ if(p->status & (1<<6)) /* COMPLETED_OK */
+ {
+
+ u16 length=p->length;
+ struct sk_buff *skb;
+ struct sk_buff *newskb;
+
+ /* Try to save time by avoiding a copy on big frames */
+
+ if ((length > RX_COPYBREAK) &&
+ ((newskb=dev_alloc_skb(1532)) != NULL))
+ {
+ skb=lp->rx_ring[rx_ring_tail].skb;
+ skb_put(skb, length);
+
+ skb_reserve(newskb,18);
+ lp->rx_ring[rx_ring_tail].skb=newskb;
+ p->data=isa_virt_to_bus(newskb->data);
+ }
+ else
+ {
+ skb=dev_alloc_skb(length+2);
+
+ if(skb==NULL) {
+ dev->stats.rx_dropped++;
+ goto dropped;
+ }
+
+ skb_reserve(skb,2);
+ memcpy(skb_put(skb, length),
+ lp->rx_ring[rx_ring_tail].skb->data, length);
+ }
+
+ skb->protocol=eth_type_trans(skb,dev);
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += length;
+ netif_rx(skb);
+ }
+
+ dropped:
+ p->length = 1532;
+ p->status = 0;
+
+ rx_ring_tail=next_rx(rx_ring_tail);
+ }
+ while(x++<48);
+
+ /* If there was actually a frame to be processed, place the EOL bit */
+ /* at the descriptor prior to the one to be filled next */
+
+ if (rx_ring_tail != rx_old_tail)
+ {
+ lp->rx_ring[prev_rx(rx_ring_tail)].p->control |= CONTROL_EOL;
+ lp->rx_ring[prev_rx(rx_old_tail)].p->control &= ~CONTROL_EOL;
+
+ lp->rx_ring_tail=rx_ring_tail;
+ }
+}
+
+
+/**
+ * mc32_tx_ring - process completed transmits
+ * @dev: 3c527 that needs its transmit ring processing
+ *
+ *
+ * This operates in a similar fashion to mc32_rx_ring. We iterate
+ * over the transmit ring. For each descriptor which has been
+ * processed by the card, we free its associated buffer and note
+ * any errors. This continues until the transmit ring is emptied
+ * or we reach a descriptor that hasn't yet been processed by the
+ * card.
+ *
+ */
+
+static void mc32_tx_ring(struct net_device *dev)
+{
+ struct mc32_local *lp = netdev_priv(dev);
+ volatile struct skb_header *np;
+
+ /*
+ * We rely on head==tail to mean 'queue empty'.
+ * This is why lp->tx_count=TX_RING_LEN-1: in order to prevent
+ * tx_ring_head wrapping to tail and confusing a 'queue empty'
+ * condition with 'queue full'
+ */
+
+ while (lp->tx_ring_tail != atomic_read(&lp->tx_ring_head))
+ {
+ u16 t;
+
+ t=next_tx(lp->tx_ring_tail);
+ np=lp->tx_ring[t].p;
+
+ if(!(np->status & (1<<7)))
+ {
+ /* Not COMPLETED */
+ break;
+ }
+ dev->stats.tx_packets++;
+ if(!(np->status & (1<<6))) /* Not COMPLETED_OK */
+ {
+ dev->stats.tx_errors++;
+
+ switch(np->status&0x0F)
+ {
+ case 1:
+ dev->stats.tx_aborted_errors++;
+ break; /* Max collisions */
+ case 2:
+ dev->stats.tx_fifo_errors++;
+ break;
+ case 3:
+ dev->stats.tx_carrier_errors++;
+ break;
+ case 4:
+ dev->stats.tx_window_errors++;
+ break; /* CTS Lost */
+ case 5:
+ dev->stats.tx_aborted_errors++;
+ break; /* Transmit timeout */
+ }
+ }
+ /* Packets are sent in order - this is
+ basically a FIFO queue of buffers matching
+ the card ring */
+ dev->stats.tx_bytes+=lp->tx_ring[t].skb->len;
+ dev_kfree_skb_irq(lp->tx_ring[t].skb);
+ lp->tx_ring[t].skb=NULL;
+ atomic_inc(&lp->tx_count);
+ netif_wake_queue(dev);
+
+ lp->tx_ring_tail=t;
+ }
+
+}
+
+
+/**
+ * mc32_interrupt - handle an interrupt from a 3c527
+ * @irq: Interrupt number
+ * @dev_id: 3c527 that requires servicing
+ * @regs: Registers (unused)
+ *
+ *
+ * An interrupt is raised whenever the 3c527 writes to the command
+ * register. This register contains the message it wishes to send us
+ * packed into a single byte field. We keep reading status entries
+ * until we have processed all the control items, but simply count
+ * transmit and receive reports. When all reports are in we empty the
+ * transceiver rings as appropriate. This saves the overhead of
+ * multiple command requests.
+ *
+ * Because MCA is level-triggered, we shouldn't miss indications.
+ * Therefore, we needn't ask the card to suspend interrupts within
+ * this handler. The card receives an implicit acknowledgment of the
+ * current interrupt when we read the command register.
+ *
+ */
+
+static irqreturn_t mc32_interrupt(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct mc32_local *lp;
+ int ioaddr, status, boguscount = 0;
+ int rx_event = 0;
+ int tx_event = 0;
+
+ ioaddr = dev->base_addr;
+ lp = netdev_priv(dev);
+
+ /* See whats cooking */
+
+ while((inb(ioaddr+HOST_STATUS)&HOST_STATUS_CWR) && boguscount++<2000)
+ {
+ status=inb(ioaddr+HOST_CMD);
+
+ pr_debug("Status TX%d RX%d EX%d OV%d BC%d\n",
+ (status&7), (status>>3)&7, (status>>6)&1,
+ (status>>7)&1, boguscount);
+
+ switch(status&7)
+ {
+ case 0:
+ break;
+ case 6: /* TX fail */
+ case 2: /* TX ok */
+ tx_event = 1;
+ break;
+ case 3: /* Halt */
+ case 4: /* Abort */
+ complete(&lp->xceiver_cmd);
+ break;
+ default:
+ pr_notice("%s: strange tx ack %d\n", dev->name, status&7);
+ }
+ status>>=3;
+ switch(status&7)
+ {
+ case 0:
+ break;
+ case 2: /* RX */
+ rx_event=1;
+ break;
+ case 3: /* Halt */
+ case 4: /* Abort */
+ complete(&lp->xceiver_cmd);
+ break;
+ case 6:
+ /* Out of RX buffers stat */
+ /* Must restart rx */
+ dev->stats.rx_dropped++;
+ mc32_rx_ring(dev);
+ mc32_start_transceiver(dev);
+ break;
+ default:
+ pr_notice("%s: strange rx ack %d\n",
+ dev->name, status&7);
+ }
+ status>>=3;
+ if(status&1)
+ {
+ /*
+ * No thread is waiting: we need to tidy
+ * up ourself.
+ */
+
+ if (lp->cmd_nonblocking) {
+ up(&lp->cmd_mutex);
+ if (lp->mc_reload_wait)
+ mc32_reset_multicast_list(dev);
+ }
+ else complete(&lp->execution_cmd);
+ }
+ if(status&2)
+ {
+ /*
+ * We get interrupted once per
+ * counter that is about to overflow.
+ */
+
+ mc32_update_stats(dev);
+ }
+ }
+
+
+ /*
+ * Process the transmit and receive rings
+ */
+
+ if(tx_event)
+ mc32_tx_ring(dev);
+
+ if(rx_event)
+ mc32_rx_ring(dev);
+
+ return IRQ_HANDLED;
+}
+
+
+/**
+ * mc32_close - user configuring the 3c527 down
+ * @dev: 3c527 card to shut down
+ *
+ * The 3c527 is a bus mastering device. We must be careful how we
+ * shut it down. It may also be running shared interrupt so we have
+ * to be sure to silence it properly
+ *
+ * We indicate that the card is closing to the rest of the
+ * driver. Otherwise, it is possible that the card may run out
+ * of receive buffers and restart the transceiver while we're
+ * trying to close it.
+ *
+ * We abort any receive and transmits going on and then wait until
+ * any pending exec commands have completed in other code threads.
+ * In theory we can't get here while that is true, in practice I am
+ * paranoid
+ *
+ * We turn off the interrupt enable for the board to be sure it can't
+ * intefere with other devices.
+ */
+
+static int mc32_close(struct net_device *dev)
+{
+ struct mc32_local *lp = netdev_priv(dev);
+ int ioaddr = dev->base_addr;
+
+ u8 regs;
+ u16 one=1;
+
+ lp->xceiver_desired_state = HALTED;
+ netif_stop_queue(dev);
+
+ /*
+ * Send the indications on command (handy debug check)
+ */
+
+ mc32_command(dev, 4, &one, 2);
+
+ /* Shut down the transceiver */
+
+ mc32_halt_transceiver(dev);
+
+ /* Ensure we issue no more commands beyond this point */
+
+ down(&lp->cmd_mutex);
+
+ /* Ok the card is now stopping */
+
+ regs=inb(ioaddr+HOST_CTRL);
+ regs&=~HOST_CTRL_INTE;
+ outb(regs, ioaddr+HOST_CTRL);
+
+ mc32_flush_rx_ring(dev);
+ mc32_flush_tx_ring(dev);
+
+ mc32_update_stats(dev);
+
+ return 0;
+}
+
+
+/**
+ * mc32_get_stats - hand back stats to network layer
+ * @dev: The 3c527 card to handle
+ *
+ * We've collected all the stats we can in software already. Now
+ * it's time to update those kept on-card and return the lot.
+ *
+ */
+
+static struct net_device_stats *mc32_get_stats(struct net_device *dev)
+{
+ mc32_update_stats(dev);
+ return &dev->stats;
+}
+
+
+/**
+ * do_mc32_set_multicast_list - attempt to update multicasts
+ * @dev: 3c527 device to load the list on
+ * @retry: indicates this is not the first call.
+ *
+ *
+ * Actually set or clear the multicast filter for this adaptor. The
+ * locking issues are handled by this routine. We have to track
+ * state as it may take multiple calls to get the command sequence
+ * completed. We just keep trying to schedule the loads until we
+ * manage to process them all.
+ *
+ * num_addrs == -1 Promiscuous mode, receive all packets
+ *
+ * num_addrs == 0 Normal mode, clear multicast list
+ *
+ * num_addrs > 0 Multicast mode, receive normal and MC packets,
+ * and do best-effort filtering.
+ *
+ * See mc32_update_stats() regards setting the SAV BP bit.
+ *
+ */
+
+static void do_mc32_set_multicast_list(struct net_device *dev, int retry)
+{
+ struct mc32_local *lp = netdev_priv(dev);
+ u16 filt = (1<<2); /* Save Bad Packets, for stats purposes */
+
+ if ((dev->flags&IFF_PROMISC) ||
+ (dev->flags&IFF_ALLMULTI) ||
+ netdev_mc_count(dev) > 10)
+ /* Enable promiscuous mode */
+ filt |= 1;
+ else if (!netdev_mc_empty(dev))
+ {
+ unsigned char block[62];
+ unsigned char *bp;
+ struct netdev_hw_addr *ha;
+
+ if(retry==0)
+ lp->mc_list_valid = 0;
+ if(!lp->mc_list_valid)
+ {
+ block[1]=0;
+ block[0]=netdev_mc_count(dev);
+ bp=block+2;
+
+ netdev_for_each_mc_addr(ha, dev) {
+ memcpy(bp, ha->addr, 6);
+ bp+=6;
+ }
+ if(mc32_command_nowait(dev, 2, block,
+ 2+6*netdev_mc_count(dev))==-1)
+ {
+ lp->mc_reload_wait = 1;
+ return;
+ }
+ lp->mc_list_valid=1;
+ }
+ }
+
+ if(mc32_command_nowait(dev, 0, &filt, 2)==-1)
+ {
+ lp->mc_reload_wait = 1;
+ }
+ else {
+ lp->mc_reload_wait = 0;
+ }
+}
+
+
+/**
+ * mc32_set_multicast_list - queue multicast list update
+ * @dev: The 3c527 to use
+ *
+ * Commence loading the multicast list. This is called when the kernel
+ * changes the lists. It will override any pending list we are trying to
+ * load.
+ */
+
+static void mc32_set_multicast_list(struct net_device *dev)
+{
+ do_mc32_set_multicast_list(dev,0);
+}
+
+
+/**
+ * mc32_reset_multicast_list - reset multicast list
+ * @dev: The 3c527 to use
+ *
+ * Attempt the next step in loading the multicast lists. If this attempt
+ * fails to complete then it will be scheduled and this function called
+ * again later from elsewhere.
+ */
+
+static void mc32_reset_multicast_list(struct net_device *dev)
+{
+ do_mc32_set_multicast_list(dev,1);
+}
+
+static void netdev_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+{
+ strcpy(info->driver, DRV_NAME);
+ strcpy(info->version, DRV_VERSION);
+ sprintf(info->bus_info, "MCA 0x%lx", dev->base_addr);
+}
+
+static u32 netdev_get_msglevel(struct net_device *dev)
+{
+ return mc32_debug;
+}
+
+static void netdev_set_msglevel(struct net_device *dev, u32 level)
+{
+ mc32_debug = level;
+}
+
+static const struct ethtool_ops netdev_ethtool_ops = {
+ .get_drvinfo = netdev_get_drvinfo,
+ .get_msglevel = netdev_get_msglevel,
+ .set_msglevel = netdev_set_msglevel,
+};
+
+#ifdef MODULE
+
+static struct net_device *this_device;
+
+/**
+ * init_module - entry point
+ *
+ * Probe and locate a 3c527 card. This really should probe and locate
+ * all the 3c527 cards in the machine not just one of them. Yes you can
+ * insmod multiple modules for now but it's a hack.
+ */
+
+int __init init_module(void)
+{
+ this_device = mc32_probe(-1);
+ if (IS_ERR(this_device))
+ return PTR_ERR(this_device);
+ return 0;
+}
+
+/**
+ * cleanup_module - free resources for an unload
+ *
+ * Unloading time. We release the MCA bus resources and the interrupt
+ * at which point everything is ready to unload. The card must be stopped
+ * at this point or we would not have been called. When we unload we
+ * leave the card stopped but not totally shut down. When the card is
+ * initialized it must be rebooted or the rings reloaded before any
+ * transmit operations are allowed to start scribbling into memory.
+ */
+
+void __exit cleanup_module(void)
+{
+ unregister_netdev(this_device);
+ cleanup_card(this_device);
+ free_netdev(this_device);
+}
+
+#endif /* MODULE */
--- /dev/null
+/*
+ * 3COM "EtherLink MC/32" Descriptions
+ */
+
+/*
+ * Registers
+ */
+
+#define HOST_CMD 0
+#define HOST_CMD_START_RX (1<<3)
+#define HOST_CMD_SUSPND_RX (3<<3)
+#define HOST_CMD_RESTRT_RX (5<<3)
+
+#define HOST_CMD_SUSPND_TX 3
+#define HOST_CMD_RESTRT_TX 5
+
+
+#define HOST_STATUS 2
+#define HOST_STATUS_CRR (1<<6)
+#define HOST_STATUS_CWR (1<<5)
+
+
+#define HOST_CTRL 6
+#define HOST_CTRL_ATTN (1<<7)
+#define HOST_CTRL_RESET (1<<6)
+#define HOST_CTRL_INTE (1<<2)
+
+#define HOST_RAMPAGE 8
+
+#define HALTED 0
+#define RUNNING 1
+
+struct mc32_mailbox
+{
+ u16 mbox;
+ u16 data[1];
+} __packed;
+
+struct skb_header
+{
+ u8 status;
+ u8 control;
+ u16 next; /* Do not change! */
+ u16 length;
+ u32 data;
+} __packed;
+
+struct mc32_stats
+{
+ /* RX Errors */
+ u32 rx_crc_errors;
+ u32 rx_alignment_errors;
+ u32 rx_overrun_errors;
+ u32 rx_tooshort_errors;
+ u32 rx_toolong_errors;
+ u32 rx_outofresource_errors;
+
+ u32 rx_discarded; /* via card pattern match filter */
+
+ /* TX Errors */
+ u32 tx_max_collisions;
+ u32 tx_carrier_errors;
+ u32 tx_underrun_errors;
+ u32 tx_cts_errors;
+ u32 tx_timeout_errors;
+
+ /* various cruft */
+ u32 dataA[6];
+ u16 dataB[5];
+ u32 dataC[14];
+} __packed;
+
+#define STATUS_MASK 0x0F
+#define COMPLETED (1<<7)
+#define COMPLETED_OK (1<<6)
+#define BUFFER_BUSY (1<<5)
+
+#define CONTROL_EOP (1<<7) /* End Of Packet */
+#define CONTROL_EOL (1<<6) /* End of List */
+
+#define MCA_MC32_ID 0x0041 /* Our MCA ident */
--- /dev/null
+/* 82596.c: A generic 82596 ethernet driver for linux. */
+/*
+ Based on Apricot.c
+ Written 1994 by Mark Evans.
+ This driver is for the Apricot 82596 bus-master interface
+
+ Modularised 12/94 Mark Evans
+
+
+ Modified to support the 82596 ethernet chips on 680x0 VME boards.
+ by Richard Hirst <richard@sleepie.demon.co.uk>
+ Renamed to be 82596.c
+
+ 980825: Changed to receive directly in to sk_buffs which are
+ allocated at open() time. Eliminates copy on incoming frames
+ (small ones are still copied). Shared data now held in a
+ non-cached page, so we can run on 68060 in copyback mode.
+
+ TBD:
+ * look at deferring rx frames rather than discarding (as per tulip)
+ * handle tx ring full as per tulip
+ * performance test to tune rx_copybreak
+
+ Most of my modifications relate to the braindead big-endian
+ implementation by Intel. When the i596 is operating in
+ 'big-endian' mode, it thinks a 32 bit value of 0x12345678
+ should be stored as 0x56781234. This is a real pain, when
+ you have linked lists which are shared by the 680x0 and the
+ i596.
+
+ Driver skeleton
+ Written 1993 by Donald Becker.
+ Copyright 1993 United States Government as represented by the Director,
+ National Security Agency. This software may only be used and distributed
+ according to the terms of the GNU General Public License as modified by SRC,
+ incorporated herein by reference.
+
+ The author may be reached as becker@scyld.com, or C/O
+ Scyld Computing Corporation, 410 Severn Ave., Suite 210, Annapolis MD 21403
+
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/gfp.h>
+
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/pgtable.h>
+#include <asm/cacheflush.h>
+
+static char version[] __initdata =
+ "82596.c $Revision: 1.5 $\n";
+
+#define DRV_NAME "82596"
+
+/* DEBUG flags
+ */
+
+#define DEB_INIT 0x0001
+#define DEB_PROBE 0x0002
+#define DEB_SERIOUS 0x0004
+#define DEB_ERRORS 0x0008
+#define DEB_MULTI 0x0010
+#define DEB_TDR 0x0020
+#define DEB_OPEN 0x0040
+#define DEB_RESET 0x0080
+#define DEB_ADDCMD 0x0100
+#define DEB_STATUS 0x0200
+#define DEB_STARTTX 0x0400
+#define DEB_RXADDR 0x0800
+#define DEB_TXADDR 0x1000
+#define DEB_RXFRAME 0x2000
+#define DEB_INTS 0x4000
+#define DEB_STRUCT 0x8000
+#define DEB_ANY 0xffff
+
+
+#define DEB(x,y) if (i596_debug & (x)) y
+
+
+#if defined(CONFIG_MVME16x_NET) || defined(CONFIG_MVME16x_NET_MODULE)
+#define ENABLE_MVME16x_NET
+#endif
+#if defined(CONFIG_BVME6000_NET) || defined(CONFIG_BVME6000_NET_MODULE)
+#define ENABLE_BVME6000_NET
+#endif
+#if defined(CONFIG_APRICOT) || defined(CONFIG_APRICOT_MODULE)
+#define ENABLE_APRICOT
+#endif
+
+#ifdef ENABLE_MVME16x_NET
+#include <asm/mvme16xhw.h>
+#endif
+#ifdef ENABLE_BVME6000_NET
+#include <asm/bvme6000hw.h>
+#endif
+
+/*
+ * Define various macros for Channel Attention, word swapping etc., dependent
+ * on architecture. MVME and BVME are 680x0 based, otherwise it is Intel.
+ */
+
+#ifdef __mc68000__
+#define WSWAPrfd(x) ((struct i596_rfd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
+#define WSWAPrbd(x) ((struct i596_rbd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
+#define WSWAPiscp(x) ((struct i596_iscp *)(((u32)(x)<<16) | ((((u32)(x)))>>16)))
+#define WSWAPscb(x) ((struct i596_scb *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
+#define WSWAPcmd(x) ((struct i596_cmd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
+#define WSWAPtbd(x) ((struct i596_tbd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
+#define WSWAPchar(x) ((char *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
+#define ISCP_BUSY 0x00010000
+#define MACH_IS_APRICOT 0
+#else
+#define WSWAPrfd(x) ((struct i596_rfd *)((long)x))
+#define WSWAPrbd(x) ((struct i596_rbd *)((long)x))
+#define WSWAPiscp(x) ((struct i596_iscp *)((long)x))
+#define WSWAPscb(x) ((struct i596_scb *)((long)x))
+#define WSWAPcmd(x) ((struct i596_cmd *)((long)x))
+#define WSWAPtbd(x) ((struct i596_tbd *)((long)x))
+#define WSWAPchar(x) ((char *)((long)x))
+#define ISCP_BUSY 0x0001
+#define MACH_IS_APRICOT 1
+#endif
+
+/*
+ * The MPU_PORT command allows direct access to the 82596. With PORT access
+ * the following commands are available (p5-18). The 32-bit port command
+ * must be word-swapped with the most significant word written first.
+ * This only applies to VME boards.
+ */
+#define PORT_RESET 0x00 /* reset 82596 */
+#define PORT_SELFTEST 0x01 /* selftest */
+#define PORT_ALTSCP 0x02 /* alternate SCB address */
+#define PORT_ALTDUMP 0x03 /* Alternate DUMP address */
+
+static int i596_debug = (DEB_SERIOUS|DEB_PROBE);
+
+MODULE_AUTHOR("Richard Hirst");
+MODULE_DESCRIPTION("i82596 driver");
+MODULE_LICENSE("GPL");
+
+module_param(i596_debug, int, 0);
+MODULE_PARM_DESC(i596_debug, "i82596 debug mask");
+
+
+/* Copy frames shorter than rx_copybreak, otherwise pass on up in
+ * a full sized sk_buff. Value of 100 stolen from tulip.c (!alpha).
+ */
+static int rx_copybreak = 100;
+
+#define PKT_BUF_SZ 1536
+#define MAX_MC_CNT 64
+
+#define I596_TOTAL_SIZE 17
+
+#define I596_NULL ((void *)0xffffffff)
+
+#define CMD_EOL 0x8000 /* The last command of the list, stop. */
+#define CMD_SUSP 0x4000 /* Suspend after doing cmd. */
+#define CMD_INTR 0x2000 /* Interrupt after doing cmd. */
+
+#define CMD_FLEX 0x0008 /* Enable flexible memory model */
+
+enum commands {
+ CmdNOp = 0, CmdSASetup = 1, CmdConfigure = 2, CmdMulticastList = 3,
+ CmdTx = 4, CmdTDR = 5, CmdDump = 6, CmdDiagnose = 7
+};
+
+#define STAT_C 0x8000 /* Set to 0 after execution */
+#define STAT_B 0x4000 /* Command being executed */
+#define STAT_OK 0x2000 /* Command executed ok */
+#define STAT_A 0x1000 /* Command aborted */
+
+#define CUC_START 0x0100
+#define CUC_RESUME 0x0200
+#define CUC_SUSPEND 0x0300
+#define CUC_ABORT 0x0400
+#define RX_START 0x0010
+#define RX_RESUME 0x0020
+#define RX_SUSPEND 0x0030
+#define RX_ABORT 0x0040
+
+#define TX_TIMEOUT (HZ/20)
+
+
+struct i596_reg {
+ unsigned short porthi;
+ unsigned short portlo;
+ unsigned long ca;
+};
+
+#define EOF 0x8000
+#define SIZE_MASK 0x3fff
+
+struct i596_tbd {
+ unsigned short size;
+ unsigned short pad;
+ struct i596_tbd *next;
+ char *data;
+};
+
+/* The command structure has two 'next' pointers; v_next is the address of
+ * the next command as seen by the CPU, b_next is the address of the next
+ * command as seen by the 82596. The b_next pointer, as used by the 82596
+ * always references the status field of the next command, rather than the
+ * v_next field, because the 82596 is unaware of v_next. It may seem more
+ * logical to put v_next at the end of the structure, but we cannot do that
+ * because the 82596 expects other fields to be there, depending on command
+ * type.
+ */
+
+struct i596_cmd {
+ struct i596_cmd *v_next; /* Address from CPUs viewpoint */
+ unsigned short status;
+ unsigned short command;
+ struct i596_cmd *b_next; /* Address from i596 viewpoint */
+};
+
+struct tx_cmd {
+ struct i596_cmd cmd;
+ struct i596_tbd *tbd;
+ unsigned short size;
+ unsigned short pad;
+ struct sk_buff *skb; /* So we can free it after tx */
+};
+
+struct tdr_cmd {
+ struct i596_cmd cmd;
+ unsigned short status;
+ unsigned short pad;
+};
+
+struct mc_cmd {
+ struct i596_cmd cmd;
+ short mc_cnt;
+ char mc_addrs[MAX_MC_CNT*6];
+};
+
+struct sa_cmd {
+ struct i596_cmd cmd;
+ char eth_addr[8];
+};
+
+struct cf_cmd {
+ struct i596_cmd cmd;
+ char i596_config[16];
+};
+
+struct i596_rfd {
+ unsigned short stat;
+ unsigned short cmd;
+ struct i596_rfd *b_next; /* Address from i596 viewpoint */
+ struct i596_rbd *rbd;
+ unsigned short count;
+ unsigned short size;
+ struct i596_rfd *v_next; /* Address from CPUs viewpoint */
+ struct i596_rfd *v_prev;
+};
+
+struct i596_rbd {
+ unsigned short count;
+ unsigned short zero1;
+ struct i596_rbd *b_next;
+ unsigned char *b_data; /* Address from i596 viewpoint */
+ unsigned short size;
+ unsigned short zero2;
+ struct sk_buff *skb;
+ struct i596_rbd *v_next;
+ struct i596_rbd *b_addr; /* This rbd addr from i596 view */
+ unsigned char *v_data; /* Address from CPUs viewpoint */
+};
+
+#define TX_RING_SIZE 64
+#define RX_RING_SIZE 16
+
+struct i596_scb {
+ unsigned short status;
+ unsigned short command;
+ struct i596_cmd *cmd;
+ struct i596_rfd *rfd;
+ unsigned long crc_err;
+ unsigned long align_err;
+ unsigned long resource_err;
+ unsigned long over_err;
+ unsigned long rcvdt_err;
+ unsigned long short_err;
+ unsigned short t_on;
+ unsigned short t_off;
+};
+
+struct i596_iscp {
+ unsigned long stat;
+ struct i596_scb *scb;
+};
+
+struct i596_scp {
+ unsigned long sysbus;
+ unsigned long pad;
+ struct i596_iscp *iscp;
+};
+
+struct i596_private {
+ volatile struct i596_scp scp;
+ volatile struct i596_iscp iscp;
+ volatile struct i596_scb scb;
+ struct sa_cmd sa_cmd;
+ struct cf_cmd cf_cmd;
+ struct tdr_cmd tdr_cmd;
+ struct mc_cmd mc_cmd;
+ unsigned long stat;
+ int last_restart __attribute__((aligned(4)));
+ struct i596_rfd *rfd_head;
+ struct i596_rbd *rbd_head;
+ struct i596_cmd *cmd_tail;
+ struct i596_cmd *cmd_head;
+ int cmd_backlog;
+ unsigned long last_cmd;
+ struct i596_rfd rfds[RX_RING_SIZE];
+ struct i596_rbd rbds[RX_RING_SIZE];
+ struct tx_cmd tx_cmds[TX_RING_SIZE];
+ struct i596_tbd tbds[TX_RING_SIZE];
+ int next_tx_cmd;
+ spinlock_t lock;
+};
+
+static char init_setup[] =
+{
+ 0x8E, /* length, prefetch on */
+ 0xC8, /* fifo to 8, monitor off */
+#ifdef CONFIG_VME
+ 0xc0, /* don't save bad frames */
+#else
+ 0x80, /* don't save bad frames */
+#endif
+ 0x2E, /* No source address insertion, 8 byte preamble */
+ 0x00, /* priority and backoff defaults */
+ 0x60, /* interframe spacing */
+ 0x00, /* slot time LSB */
+ 0xf2, /* slot time and retries */
+ 0x00, /* promiscuous mode */
+ 0x00, /* collision detect */
+ 0x40, /* minimum frame length */
+ 0xff,
+ 0x00,
+ 0x7f /* *multi IA */ };
+
+static int i596_open(struct net_device *dev);
+static netdev_tx_t i596_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static irqreturn_t i596_interrupt(int irq, void *dev_id);
+static int i596_close(struct net_device *dev);
+static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd);
+static void i596_tx_timeout (struct net_device *dev);
+static void print_eth(unsigned char *buf, char *str);
+static void set_multicast_list(struct net_device *dev);
+
+static int rx_ring_size = RX_RING_SIZE;
+static int ticks_limit = 25;
+static int max_cmd_backlog = TX_RING_SIZE-1;
+
+
+static inline void CA(struct net_device *dev)
+{
+#ifdef ENABLE_MVME16x_NET
+ if (MACH_IS_MVME16x) {
+ ((struct i596_reg *) dev->base_addr)->ca = 1;
+ }
+#endif
+#ifdef ENABLE_BVME6000_NET
+ if (MACH_IS_BVME6000) {
+ volatile u32 i;
+
+ i = *(volatile u32 *) (dev->base_addr);
+ }
+#endif
+#ifdef ENABLE_APRICOT
+ if (MACH_IS_APRICOT) {
+ outw(0, (short) (dev->base_addr) + 4);
+ }
+#endif
+}
+
+
+static inline void MPU_PORT(struct net_device *dev, int c, volatile void *x)
+{
+#ifdef ENABLE_MVME16x_NET
+ if (MACH_IS_MVME16x) {
+ struct i596_reg *p = (struct i596_reg *) (dev->base_addr);
+ p->porthi = ((c) | (u32) (x)) & 0xffff;
+ p->portlo = ((c) | (u32) (x)) >> 16;
+ }
+#endif
+#ifdef ENABLE_BVME6000_NET
+ if (MACH_IS_BVME6000) {
+ u32 v = (u32) (c) | (u32) (x);
+ v = ((u32) (v) << 16) | ((u32) (v) >> 16);
+ *(volatile u32 *) dev->base_addr = v;
+ udelay(1);
+ *(volatile u32 *) dev->base_addr = v;
+ }
+#endif
+}
+
+
+static inline int wait_istat(struct net_device *dev, struct i596_private *lp, int delcnt, char *str)
+{
+ while (--delcnt && lp->iscp.stat)
+ udelay(10);
+ if (!delcnt) {
+ printk(KERN_ERR "%s: %s, status %4.4x, cmd %4.4x.\n",
+ dev->name, str, lp->scb.status, lp->scb.command);
+ return -1;
+ }
+ else
+ return 0;
+}
+
+
+static inline int wait_cmd(struct net_device *dev, struct i596_private *lp, int delcnt, char *str)
+{
+ while (--delcnt && lp->scb.command)
+ udelay(10);
+ if (!delcnt) {
+ printk(KERN_ERR "%s: %s, status %4.4x, cmd %4.4x.\n",
+ dev->name, str, lp->scb.status, lp->scb.command);
+ return -1;
+ }
+ else
+ return 0;
+}
+
+
+static inline int wait_cfg(struct net_device *dev, struct i596_cmd *cmd, int delcnt, char *str)
+{
+ volatile struct i596_cmd *c = cmd;
+
+ while (--delcnt && c->command)
+ udelay(10);
+ if (!delcnt) {
+ printk(KERN_ERR "%s: %s.\n", dev->name, str);
+ return -1;
+ }
+ else
+ return 0;
+}
+
+
+static void i596_display_data(struct net_device *dev)
+{
+ struct i596_private *lp = dev->ml_priv;
+ struct i596_cmd *cmd;
+ struct i596_rfd *rfd;
+ struct i596_rbd *rbd;
+
+ printk(KERN_ERR "lp and scp at %p, .sysbus = %08lx, .iscp = %p\n",
+ &lp->scp, lp->scp.sysbus, lp->scp.iscp);
+ printk(KERN_ERR "iscp at %p, iscp.stat = %08lx, .scb = %p\n",
+ &lp->iscp, lp->iscp.stat, lp->iscp.scb);
+ printk(KERN_ERR "scb at %p, scb.status = %04x, .command = %04x,"
+ " .cmd = %p, .rfd = %p\n",
+ &lp->scb, lp->scb.status, lp->scb.command,
+ lp->scb.cmd, lp->scb.rfd);
+ printk(KERN_ERR " errors: crc %lx, align %lx, resource %lx,"
+ " over %lx, rcvdt %lx, short %lx\n",
+ lp->scb.crc_err, lp->scb.align_err, lp->scb.resource_err,
+ lp->scb.over_err, lp->scb.rcvdt_err, lp->scb.short_err);
+ cmd = lp->cmd_head;
+ while (cmd != I596_NULL) {
+ printk(KERN_ERR "cmd at %p, .status = %04x, .command = %04x, .b_next = %p\n",
+ cmd, cmd->status, cmd->command, cmd->b_next);
+ cmd = cmd->v_next;
+ }
+ rfd = lp->rfd_head;
+ printk(KERN_ERR "rfd_head = %p\n", rfd);
+ do {
+ printk(KERN_ERR " %p .stat %04x, .cmd %04x, b_next %p, rbd %p,"
+ " count %04x\n",
+ rfd, rfd->stat, rfd->cmd, rfd->b_next, rfd->rbd,
+ rfd->count);
+ rfd = rfd->v_next;
+ } while (rfd != lp->rfd_head);
+ rbd = lp->rbd_head;
+ printk(KERN_ERR "rbd_head = %p\n", rbd);
+ do {
+ printk(KERN_ERR " %p .count %04x, b_next %p, b_data %p, size %04x\n",
+ rbd, rbd->count, rbd->b_next, rbd->b_data, rbd->size);
+ rbd = rbd->v_next;
+ } while (rbd != lp->rbd_head);
+}
+
+
+#if defined(ENABLE_MVME16x_NET) || defined(ENABLE_BVME6000_NET)
+static irqreturn_t i596_error(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+#ifdef ENABLE_MVME16x_NET
+ if (MACH_IS_MVME16x) {
+ volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000;
+
+ pcc2[0x28] = 1;
+ pcc2[0x2b] = 0x1d;
+ }
+#endif
+#ifdef ENABLE_BVME6000_NET
+ if (MACH_IS_BVME6000) {
+ volatile unsigned char *ethirq = (unsigned char *) BVME_ETHIRQ_REG;
+
+ *ethirq = 1;
+ *ethirq = 3;
+ }
+#endif
+ printk(KERN_ERR "%s: Error interrupt\n", dev->name);
+ i596_display_data(dev);
+ return IRQ_HANDLED;
+}
+#endif
+
+static inline void remove_rx_bufs(struct net_device *dev)
+{
+ struct i596_private *lp = dev->ml_priv;
+ struct i596_rbd *rbd;
+ int i;
+
+ for (i = 0, rbd = lp->rbds; i < rx_ring_size; i++, rbd++) {
+ if (rbd->skb == NULL)
+ break;
+ dev_kfree_skb(rbd->skb);
+ rbd->skb = NULL;
+ }
+}
+
+static inline int init_rx_bufs(struct net_device *dev)
+{
+ struct i596_private *lp = dev->ml_priv;
+ int i;
+ struct i596_rfd *rfd;
+ struct i596_rbd *rbd;
+
+ /* First build the Receive Buffer Descriptor List */
+
+ for (i = 0, rbd = lp->rbds; i < rx_ring_size; i++, rbd++) {
+ struct sk_buff *skb = dev_alloc_skb(PKT_BUF_SZ);
+
+ if (skb == NULL) {
+ remove_rx_bufs(dev);
+ return -ENOMEM;
+ }
+
+ skb->dev = dev;
+ rbd->v_next = rbd+1;
+ rbd->b_next = WSWAPrbd(virt_to_bus(rbd+1));
+ rbd->b_addr = WSWAPrbd(virt_to_bus(rbd));
+ rbd->skb = skb;
+ rbd->v_data = skb->data;
+ rbd->b_data = WSWAPchar(virt_to_bus(skb->data));
+ rbd->size = PKT_BUF_SZ;
+#ifdef __mc68000__
+ cache_clear(virt_to_phys(skb->data), PKT_BUF_SZ);
+#endif
+ }
+ lp->rbd_head = lp->rbds;
+ rbd = lp->rbds + rx_ring_size - 1;
+ rbd->v_next = lp->rbds;
+ rbd->b_next = WSWAPrbd(virt_to_bus(lp->rbds));
+
+ /* Now build the Receive Frame Descriptor List */
+
+ for (i = 0, rfd = lp->rfds; i < rx_ring_size; i++, rfd++) {
+ rfd->rbd = I596_NULL;
+ rfd->v_next = rfd+1;
+ rfd->v_prev = rfd-1;
+ rfd->b_next = WSWAPrfd(virt_to_bus(rfd+1));
+ rfd->cmd = CMD_FLEX;
+ }
+ lp->rfd_head = lp->rfds;
+ lp->scb.rfd = WSWAPrfd(virt_to_bus(lp->rfds));
+ rfd = lp->rfds;
+ rfd->rbd = lp->rbd_head;
+ rfd->v_prev = lp->rfds + rx_ring_size - 1;
+ rfd = lp->rfds + rx_ring_size - 1;
+ rfd->v_next = lp->rfds;
+ rfd->b_next = WSWAPrfd(virt_to_bus(lp->rfds));
+ rfd->cmd = CMD_EOL|CMD_FLEX;
+
+ return 0;
+}
+
+
+static void rebuild_rx_bufs(struct net_device *dev)
+{
+ struct i596_private *lp = dev->ml_priv;
+ int i;
+
+ /* Ensure rx frame/buffer descriptors are tidy */
+
+ for (i = 0; i < rx_ring_size; i++) {
+ lp->rfds[i].rbd = I596_NULL;
+ lp->rfds[i].cmd = CMD_FLEX;
+ }
+ lp->rfds[rx_ring_size-1].cmd = CMD_EOL|CMD_FLEX;
+ lp->rfd_head = lp->rfds;
+ lp->scb.rfd = WSWAPrfd(virt_to_bus(lp->rfds));
+ lp->rbd_head = lp->rbds;
+ lp->rfds[0].rbd = WSWAPrbd(virt_to_bus(lp->rbds));
+}
+
+
+static int init_i596_mem(struct net_device *dev)
+{
+ struct i596_private *lp = dev->ml_priv;
+#if !defined(ENABLE_MVME16x_NET) && !defined(ENABLE_BVME6000_NET) || defined(ENABLE_APRICOT)
+ short ioaddr = dev->base_addr;
+#endif
+ unsigned long flags;
+
+ MPU_PORT(dev, PORT_RESET, NULL);
+
+ udelay(100); /* Wait 100us - seems to help */
+
+#if defined(ENABLE_MVME16x_NET) || defined(ENABLE_BVME6000_NET)
+#ifdef ENABLE_MVME16x_NET
+ if (MACH_IS_MVME16x) {
+ volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000;
+
+ /* Disable all ints for now */
+ pcc2[0x28] = 1;
+ pcc2[0x2a] = 0x48;
+ /* Following disables snooping. Snooping is not required
+ * as we make appropriate use of non-cached pages for
+ * shared data, and cache_push/cache_clear.
+ */
+ pcc2[0x2b] = 0x08;
+ }
+#endif
+#ifdef ENABLE_BVME6000_NET
+ if (MACH_IS_BVME6000) {
+ volatile unsigned char *ethirq = (unsigned char *) BVME_ETHIRQ_REG;
+
+ *ethirq = 1;
+ }
+#endif
+
+ /* change the scp address */
+
+ MPU_PORT(dev, PORT_ALTSCP, (void *)virt_to_bus((void *)&lp->scp));
+
+#elif defined(ENABLE_APRICOT)
+
+ {
+ u32 scp = virt_to_bus(&lp->scp);
+
+ /* change the scp address */
+ outw(0, ioaddr);
+ outw(0, ioaddr);
+ outb(4, ioaddr + 0xf);
+ outw(scp | 2, ioaddr);
+ outw(scp >> 16, ioaddr);
+ }
+#endif
+
+ lp->last_cmd = jiffies;
+
+#ifdef ENABLE_MVME16x_NET
+ if (MACH_IS_MVME16x)
+ lp->scp.sysbus = 0x00000054;
+#endif
+#ifdef ENABLE_BVME6000_NET
+ if (MACH_IS_BVME6000)
+ lp->scp.sysbus = 0x0000004c;
+#endif
+#ifdef ENABLE_APRICOT
+ if (MACH_IS_APRICOT)
+ lp->scp.sysbus = 0x00440000;
+#endif
+
+ lp->scp.iscp = WSWAPiscp(virt_to_bus((void *)&lp->iscp));
+ lp->iscp.scb = WSWAPscb(virt_to_bus((void *)&lp->scb));
+ lp->iscp.stat = ISCP_BUSY;
+ lp->cmd_backlog = 0;
+
+ lp->cmd_head = lp->scb.cmd = I596_NULL;
+
+#ifdef ENABLE_BVME6000_NET
+ if (MACH_IS_BVME6000) {
+ lp->scb.t_on = 7 * 25;
+ lp->scb.t_off = 1 * 25;
+ }
+#endif
+
+ DEB(DEB_INIT,printk(KERN_DEBUG "%s: starting i82596.\n", dev->name));
+
+#if defined(ENABLE_APRICOT)
+ (void) inb(ioaddr + 0x10);
+ outb(4, ioaddr + 0xf);
+#endif
+ CA(dev);
+
+ if (wait_istat(dev,lp,1000,"initialization timed out"))
+ goto failed;
+ DEB(DEB_INIT,printk(KERN_DEBUG "%s: i82596 initialization successful\n", dev->name));
+
+ /* Ensure rx frame/buffer descriptors are tidy */
+ rebuild_rx_bufs(dev);
+ lp->scb.command = 0;
+
+#ifdef ENABLE_MVME16x_NET
+ if (MACH_IS_MVME16x) {
+ volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000;
+
+ /* Enable ints, etc. now */
+ pcc2[0x2a] = 0x55; /* Edge sensitive */
+ pcc2[0x2b] = 0x15;
+ }
+#endif
+#ifdef ENABLE_BVME6000_NET
+ if (MACH_IS_BVME6000) {
+ volatile unsigned char *ethirq = (unsigned char *) BVME_ETHIRQ_REG;
+
+ *ethirq = 3;
+ }
+#endif
+
+
+ DEB(DEB_INIT,printk(KERN_DEBUG "%s: queuing CmdConfigure\n", dev->name));
+ memcpy(lp->cf_cmd.i596_config, init_setup, 14);
+ lp->cf_cmd.cmd.command = CmdConfigure;
+ i596_add_cmd(dev, &lp->cf_cmd.cmd);
+
+ DEB(DEB_INIT,printk(KERN_DEBUG "%s: queuing CmdSASetup\n", dev->name));
+ memcpy(lp->sa_cmd.eth_addr, dev->dev_addr, 6);
+ lp->sa_cmd.cmd.command = CmdSASetup;
+ i596_add_cmd(dev, &lp->sa_cmd.cmd);
+
+ DEB(DEB_INIT,printk(KERN_DEBUG "%s: queuing CmdTDR\n", dev->name));
+ lp->tdr_cmd.cmd.command = CmdTDR;
+ i596_add_cmd(dev, &lp->tdr_cmd.cmd);
+
+ spin_lock_irqsave (&lp->lock, flags);
+
+ if (wait_cmd(dev,lp,1000,"timed out waiting to issue RX_START")) {
+ spin_unlock_irqrestore (&lp->lock, flags);
+ goto failed;
+ }
+ DEB(DEB_INIT,printk(KERN_DEBUG "%s: Issuing RX_START\n", dev->name));
+ lp->scb.command = RX_START;
+ CA(dev);
+
+ spin_unlock_irqrestore (&lp->lock, flags);
+
+ if (wait_cmd(dev,lp,1000,"RX_START not processed"))
+ goto failed;
+ DEB(DEB_INIT,printk(KERN_DEBUG "%s: Receive unit started OK\n", dev->name));
+ return 0;
+
+failed:
+ printk(KERN_CRIT "%s: Failed to initialise 82596\n", dev->name);
+ MPU_PORT(dev, PORT_RESET, NULL);
+ return -1;
+}
+
+static inline int i596_rx(struct net_device *dev)
+{
+ struct i596_private *lp = dev->ml_priv;
+ struct i596_rfd *rfd;
+ struct i596_rbd *rbd;
+ int frames = 0;
+
+ DEB(DEB_RXFRAME,printk(KERN_DEBUG "i596_rx(), rfd_head %p, rbd_head %p\n",
+ lp->rfd_head, lp->rbd_head));
+
+ rfd = lp->rfd_head; /* Ref next frame to check */
+
+ while ((rfd->stat) & STAT_C) { /* Loop while complete frames */
+ if (rfd->rbd == I596_NULL)
+ rbd = I596_NULL;
+ else if (rfd->rbd == lp->rbd_head->b_addr)
+ rbd = lp->rbd_head;
+ else {
+ printk(KERN_CRIT "%s: rbd chain broken!\n", dev->name);
+ /* XXX Now what? */
+ rbd = I596_NULL;
+ }
+ DEB(DEB_RXFRAME, printk(KERN_DEBUG " rfd %p, rfd.rbd %p, rfd.stat %04x\n",
+ rfd, rfd->rbd, rfd->stat));
+
+ if (rbd != I596_NULL && ((rfd->stat) & STAT_OK)) {
+ /* a good frame */
+ int pkt_len = rbd->count & 0x3fff;
+ struct sk_buff *skb = rbd->skb;
+ int rx_in_place = 0;
+
+ DEB(DEB_RXADDR,print_eth(rbd->v_data, "received"));
+ frames++;
+
+ /* Check if the packet is long enough to just accept
+ * without copying to a properly sized skbuff.
+ */
+
+ if (pkt_len > rx_copybreak) {
+ struct sk_buff *newskb;
+
+ /* Get fresh skbuff to replace filled one. */
+ newskb = dev_alloc_skb(PKT_BUF_SZ);
+ if (newskb == NULL) {
+ skb = NULL; /* drop pkt */
+ goto memory_squeeze;
+ }
+ /* Pass up the skb already on the Rx ring. */
+ skb_put(skb, pkt_len);
+ rx_in_place = 1;
+ rbd->skb = newskb;
+ newskb->dev = dev;
+ rbd->v_data = newskb->data;
+ rbd->b_data = WSWAPchar(virt_to_bus(newskb->data));
+#ifdef __mc68000__
+ cache_clear(virt_to_phys(newskb->data), PKT_BUF_SZ);
+#endif
+ }
+ else
+ skb = dev_alloc_skb(pkt_len + 2);
+memory_squeeze:
+ if (skb == NULL) {
+ /* XXX tulip.c can defer packets here!! */
+ printk(KERN_WARNING "%s: i596_rx Memory squeeze, dropping packet.\n", dev->name);
+ dev->stats.rx_dropped++;
+ }
+ else {
+ if (!rx_in_place) {
+ /* 16 byte align the data fields */
+ skb_reserve(skb, 2);
+ memcpy(skb_put(skb,pkt_len), rbd->v_data, pkt_len);
+ }
+ skb->protocol=eth_type_trans(skb,dev);
+ skb->len = pkt_len;
+#ifdef __mc68000__
+ cache_clear(virt_to_phys(rbd->skb->data),
+ pkt_len);
+#endif
+ netif_rx(skb);
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes+=pkt_len;
+ }
+ }
+ else {
+ DEB(DEB_ERRORS, printk(KERN_DEBUG "%s: Error, rfd.stat = 0x%04x\n",
+ dev->name, rfd->stat));
+ dev->stats.rx_errors++;
+ if ((rfd->stat) & 0x0001)
+ dev->stats.collisions++;
+ if ((rfd->stat) & 0x0080)
+ dev->stats.rx_length_errors++;
+ if ((rfd->stat) & 0x0100)
+ dev->stats.rx_over_errors++;
+ if ((rfd->stat) & 0x0200)
+ dev->stats.rx_fifo_errors++;
+ if ((rfd->stat) & 0x0400)
+ dev->stats.rx_frame_errors++;
+ if ((rfd->stat) & 0x0800)
+ dev->stats.rx_crc_errors++;
+ if ((rfd->stat) & 0x1000)
+ dev->stats.rx_length_errors++;
+ }
+
+ /* Clear the buffer descriptor count and EOF + F flags */
+
+ if (rbd != I596_NULL && (rbd->count & 0x4000)) {
+ rbd->count = 0;
+ lp->rbd_head = rbd->v_next;
+ }
+
+ /* Tidy the frame descriptor, marking it as end of list */
+
+ rfd->rbd = I596_NULL;
+ rfd->stat = 0;
+ rfd->cmd = CMD_EOL|CMD_FLEX;
+ rfd->count = 0;
+
+ /* Remove end-of-list from old end descriptor */
+
+ rfd->v_prev->cmd = CMD_FLEX;
+
+ /* Update record of next frame descriptor to process */
+
+ lp->scb.rfd = rfd->b_next;
+ lp->rfd_head = rfd->v_next;
+ rfd = lp->rfd_head;
+ }
+
+ DEB(DEB_RXFRAME,printk(KERN_DEBUG "frames %d\n", frames));
+
+ return 0;
+}
+
+
+static void i596_cleanup_cmd(struct net_device *dev, struct i596_private *lp)
+{
+ struct i596_cmd *ptr;
+
+ while (lp->cmd_head != I596_NULL) {
+ ptr = lp->cmd_head;
+ lp->cmd_head = ptr->v_next;
+ lp->cmd_backlog--;
+
+ switch ((ptr->command) & 0x7) {
+ case CmdTx:
+ {
+ struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr;
+ struct sk_buff *skb = tx_cmd->skb;
+
+ dev_kfree_skb(skb);
+
+ dev->stats.tx_errors++;
+ dev->stats.tx_aborted_errors++;
+
+ ptr->v_next = ptr->b_next = I596_NULL;
+ tx_cmd->cmd.command = 0; /* Mark as free */
+ break;
+ }
+ default:
+ ptr->v_next = ptr->b_next = I596_NULL;
+ }
+ }
+
+ wait_cmd(dev,lp,100,"i596_cleanup_cmd timed out");
+ lp->scb.cmd = I596_NULL;
+}
+
+static void i596_reset(struct net_device *dev, struct i596_private *lp,
+ int ioaddr)
+{
+ unsigned long flags;
+
+ DEB(DEB_RESET,printk(KERN_DEBUG "i596_reset\n"));
+
+ spin_lock_irqsave (&lp->lock, flags);
+
+ wait_cmd(dev,lp,100,"i596_reset timed out");
+
+ netif_stop_queue(dev);
+
+ lp->scb.command = CUC_ABORT | RX_ABORT;
+ CA(dev);
+
+ /* wait for shutdown */
+ wait_cmd(dev,lp,1000,"i596_reset 2 timed out");
+ spin_unlock_irqrestore (&lp->lock, flags);
+
+ i596_cleanup_cmd(dev,lp);
+ i596_rx(dev);
+
+ netif_start_queue(dev);
+ init_i596_mem(dev);
+}
+
+static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd)
+{
+ struct i596_private *lp = dev->ml_priv;
+ int ioaddr = dev->base_addr;
+ unsigned long flags;
+
+ DEB(DEB_ADDCMD,printk(KERN_DEBUG "i596_add_cmd\n"));
+
+ cmd->status = 0;
+ cmd->command |= (CMD_EOL | CMD_INTR);
+ cmd->v_next = cmd->b_next = I596_NULL;
+
+ spin_lock_irqsave (&lp->lock, flags);
+
+ if (lp->cmd_head != I596_NULL) {
+ lp->cmd_tail->v_next = cmd;
+ lp->cmd_tail->b_next = WSWAPcmd(virt_to_bus(&cmd->status));
+ } else {
+ lp->cmd_head = cmd;
+ wait_cmd(dev,lp,100,"i596_add_cmd timed out");
+ lp->scb.cmd = WSWAPcmd(virt_to_bus(&cmd->status));
+ lp->scb.command = CUC_START;
+ CA(dev);
+ }
+ lp->cmd_tail = cmd;
+ lp->cmd_backlog++;
+
+ spin_unlock_irqrestore (&lp->lock, flags);
+
+ if (lp->cmd_backlog > max_cmd_backlog) {
+ unsigned long tickssofar = jiffies - lp->last_cmd;
+
+ if (tickssofar < ticks_limit)
+ return;
+
+ printk(KERN_NOTICE "%s: command unit timed out, status resetting.\n", dev->name);
+
+ i596_reset(dev, lp, ioaddr);
+ }
+}
+
+static int i596_open(struct net_device *dev)
+{
+ int res = 0;
+
+ DEB(DEB_OPEN,printk(KERN_DEBUG "%s: i596_open() irq %d.\n", dev->name, dev->irq));
+
+ if (request_irq(dev->irq, i596_interrupt, 0, "i82596", dev)) {
+ printk(KERN_ERR "%s: IRQ %d not free\n", dev->name, dev->irq);
+ return -EAGAIN;
+ }
+#ifdef ENABLE_MVME16x_NET
+ if (MACH_IS_MVME16x) {
+ if (request_irq(0x56, i596_error, 0, "i82596_error", dev)) {
+ res = -EAGAIN;
+ goto err_irq_dev;
+ }
+ }
+#endif
+ res = init_rx_bufs(dev);
+ if (res)
+ goto err_irq_56;
+
+ netif_start_queue(dev);
+
+ if (init_i596_mem(dev)) {
+ res = -EAGAIN;
+ goto err_queue;
+ }
+
+ return 0;
+
+err_queue:
+ netif_stop_queue(dev);
+ remove_rx_bufs(dev);
+err_irq_56:
+#ifdef ENABLE_MVME16x_NET
+ free_irq(0x56, dev);
+err_irq_dev:
+#endif
+ free_irq(dev->irq, dev);
+
+ return res;
+}
+
+static void i596_tx_timeout (struct net_device *dev)
+{
+ struct i596_private *lp = dev->ml_priv;
+ int ioaddr = dev->base_addr;
+
+ /* Transmitter timeout, serious problems. */
+ DEB(DEB_ERRORS,printk(KERN_ERR "%s: transmit timed out, status resetting.\n",
+ dev->name));
+
+ dev->stats.tx_errors++;
+
+ /* Try to restart the adaptor */
+ if (lp->last_restart == dev->stats.tx_packets) {
+ DEB(DEB_ERRORS,printk(KERN_ERR "Resetting board.\n"));
+ /* Shutdown and restart */
+ i596_reset (dev, lp, ioaddr);
+ } else {
+ /* Issue a channel attention signal */
+ DEB(DEB_ERRORS,printk(KERN_ERR "Kicking board.\n"));
+ lp->scb.command = CUC_START | RX_START;
+ CA (dev);
+ lp->last_restart = dev->stats.tx_packets;
+ }
+
+ dev->trans_start = jiffies; /* prevent tx timeout */
+ netif_wake_queue (dev);
+}
+
+static netdev_tx_t i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct i596_private *lp = dev->ml_priv;
+ struct tx_cmd *tx_cmd;
+ struct i596_tbd *tbd;
+ short length = skb->len;
+
+ DEB(DEB_STARTTX,printk(KERN_DEBUG "%s: i596_start_xmit(%x,%p) called\n",
+ dev->name, skb->len, skb->data));
+
+ if (skb->len < ETH_ZLEN) {
+ if (skb_padto(skb, ETH_ZLEN))
+ return NETDEV_TX_OK;
+ length = ETH_ZLEN;
+ }
+ netif_stop_queue(dev);
+
+ tx_cmd = lp->tx_cmds + lp->next_tx_cmd;
+ tbd = lp->tbds + lp->next_tx_cmd;
+
+ if (tx_cmd->cmd.command) {
+ printk(KERN_NOTICE "%s: xmit ring full, dropping packet.\n",
+ dev->name);
+ dev->stats.tx_dropped++;
+
+ dev_kfree_skb(skb);
+ } else {
+ if (++lp->next_tx_cmd == TX_RING_SIZE)
+ lp->next_tx_cmd = 0;
+ tx_cmd->tbd = WSWAPtbd(virt_to_bus(tbd));
+ tbd->next = I596_NULL;
+
+ tx_cmd->cmd.command = CMD_FLEX | CmdTx;
+ tx_cmd->skb = skb;
+
+ tx_cmd->pad = 0;
+ tx_cmd->size = 0;
+ tbd->pad = 0;
+ tbd->size = EOF | length;
+
+ tbd->data = WSWAPchar(virt_to_bus(skb->data));
+
+#ifdef __mc68000__
+ cache_push(virt_to_phys(skb->data), length);
+#endif
+ DEB(DEB_TXADDR,print_eth(skb->data, "tx-queued"));
+ i596_add_cmd(dev, &tx_cmd->cmd);
+
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += length;
+ }
+
+ netif_start_queue(dev);
+
+ return NETDEV_TX_OK;
+}
+
+static void print_eth(unsigned char *add, char *str)
+{
+ printk(KERN_DEBUG "i596 0x%p, %pM --> %pM %02X%02X, %s\n",
+ add, add + 6, add, add[12], add[13], str);
+}
+
+static int io = 0x300;
+static int irq = 10;
+
+static const struct net_device_ops i596_netdev_ops = {
+ .ndo_open = i596_open,
+ .ndo_stop = i596_close,
+ .ndo_start_xmit = i596_start_xmit,
+ .ndo_set_multicast_list = set_multicast_list,
+ .ndo_tx_timeout = i596_tx_timeout,
+ .ndo_change_mtu = eth_change_mtu,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+};
+
+struct net_device * __init i82596_probe(int unit)
+{
+ struct net_device *dev;
+ int i;
+ struct i596_private *lp;
+ char eth_addr[8];
+ static int probed;
+ int err;
+
+ if (probed)
+ return ERR_PTR(-ENODEV);
+ probed++;
+
+ dev = alloc_etherdev(0);
+ if (!dev)
+ return ERR_PTR(-ENOMEM);
+
+ if (unit >= 0) {
+ sprintf(dev->name, "eth%d", unit);
+ netdev_boot_setup_check(dev);
+ } else {
+ dev->base_addr = io;
+ dev->irq = irq;
+ }
+
+#ifdef ENABLE_MVME16x_NET
+ if (MACH_IS_MVME16x) {
+ if (mvme16x_config & MVME16x_CONFIG_NO_ETHERNET) {
+ printk(KERN_NOTICE "Ethernet probe disabled - chip not present\n");
+ err = -ENODEV;
+ goto out;
+ }
+ memcpy(eth_addr, (void *) 0xfffc1f2c, 6); /* YUCK! Get addr from NOVRAM */
+ dev->base_addr = MVME_I596_BASE;
+ dev->irq = (unsigned) MVME16x_IRQ_I596;
+ goto found;
+ }
+#endif
+#ifdef ENABLE_BVME6000_NET
+ if (MACH_IS_BVME6000) {
+ volatile unsigned char *rtc = (unsigned char *) BVME_RTC_BASE;
+ unsigned char msr = rtc[3];
+ int i;
+
+ rtc[3] |= 0x80;
+ for (i = 0; i < 6; i++)
+ eth_addr[i] = rtc[i * 4 + 7]; /* Stored in RTC RAM at offset 1 */
+ rtc[3] = msr;
+ dev->base_addr = BVME_I596_BASE;
+ dev->irq = (unsigned) BVME_IRQ_I596;
+ goto found;
+ }
+#endif
+#ifdef ENABLE_APRICOT
+ {
+ int checksum = 0;
+ int ioaddr = 0x300;
+
+ /* this is easy the ethernet interface can only be at 0x300 */
+ /* first check nothing is already registered here */
+
+ if (!request_region(ioaddr, I596_TOTAL_SIZE, DRV_NAME)) {
+ printk(KERN_ERR "82596: IO address 0x%04x in use\n", ioaddr);
+ err = -EBUSY;
+ goto out;
+ }
+
+ dev->base_addr = ioaddr;
+
+ for (i = 0; i < 8; i++) {
+ eth_addr[i] = inb(ioaddr + 8 + i);
+ checksum += eth_addr[i];
+ }
+
+ /* checksum is a multiple of 0x100, got this wrong first time
+ some machines have 0x100, some 0x200. The DOS driver doesn't
+ even bother with the checksum.
+ Some other boards trip the checksum.. but then appear as
+ ether address 0. Trap these - AC */
+
+ if ((checksum % 0x100) ||
+ (memcmp(eth_addr, "\x00\x00\x49", 3) != 0)) {
+ err = -ENODEV;
+ goto out1;
+ }
+
+ dev->irq = 10;
+ goto found;
+ }
+#endif
+ err = -ENODEV;
+ goto out;
+
+found:
+ dev->mem_start = (int)__get_free_pages(GFP_ATOMIC, 0);
+ if (!dev->mem_start) {
+ err = -ENOMEM;
+ goto out1;
+ }
+
+ DEB(DEB_PROBE,printk(KERN_INFO "%s: 82596 at %#3lx,", dev->name, dev->base_addr));
+
+ for (i = 0; i < 6; i++)
+ DEB(DEB_PROBE,printk(" %2.2X", dev->dev_addr[i] = eth_addr[i]));
+
+ DEB(DEB_PROBE,printk(" IRQ %d.\n", dev->irq));
+
+ DEB(DEB_PROBE,printk(KERN_INFO "%s", version));
+
+ /* The 82596-specific entries in the device structure. */
+ dev->netdev_ops = &i596_netdev_ops;
+ dev->watchdog_timeo = TX_TIMEOUT;
+
+ dev->ml_priv = (void *)(dev->mem_start);
+
+ lp = dev->ml_priv;
+ DEB(DEB_INIT,printk(KERN_DEBUG "%s: lp at 0x%08lx (%zd bytes), "
+ "lp->scb at 0x%08lx\n",
+ dev->name, (unsigned long)lp,
+ sizeof(struct i596_private), (unsigned long)&lp->scb));
+ memset((void *) lp, 0, sizeof(struct i596_private));
+
+#ifdef __mc68000__
+ cache_push(virt_to_phys((void *)(dev->mem_start)), 4096);
+ cache_clear(virt_to_phys((void *)(dev->mem_start)), 4096);
+ kernel_set_cachemode((void *)(dev->mem_start), 4096, IOMAP_NOCACHE_SER);
+#endif
+ lp->scb.command = 0;
+ lp->scb.cmd = I596_NULL;
+ lp->scb.rfd = I596_NULL;
+ spin_lock_init(&lp->lock);
+
+ err = register_netdev(dev);
+ if (err)
+ goto out2;
+ return dev;
+out2:
+#ifdef __mc68000__
+ /* XXX This assumes default cache mode to be IOMAP_FULL_CACHING,
+ * XXX which may be invalid (CONFIG_060_WRITETHROUGH)
+ */
+ kernel_set_cachemode((void *)(dev->mem_start), 4096,
+ IOMAP_FULL_CACHING);
+#endif
+ free_page ((u32)(dev->mem_start));
+out1:
+#ifdef ENABLE_APRICOT
+ release_region(dev->base_addr, I596_TOTAL_SIZE);
+#endif
+out:
+ free_netdev(dev);
+ return ERR_PTR(err);
+}
+
+static irqreturn_t i596_interrupt(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct i596_private *lp;
+ short ioaddr;
+ unsigned short status, ack_cmd = 0;
+ int handled = 0;
+
+#ifdef ENABLE_BVME6000_NET
+ if (MACH_IS_BVME6000) {
+ if (*(char *) BVME_LOCAL_IRQ_STAT & BVME_ETHERR) {
+ i596_error(irq, dev_id);
+ return IRQ_HANDLED;
+ }
+ }
+#endif
+ if (dev == NULL) {
+ printk(KERN_ERR "i596_interrupt(): irq %d for unknown device.\n", irq);
+ return IRQ_NONE;
+ }
+
+ ioaddr = dev->base_addr;
+ lp = dev->ml_priv;
+
+ spin_lock (&lp->lock);
+
+ wait_cmd(dev,lp,100,"i596 interrupt, timeout");
+ status = lp->scb.status;
+
+ DEB(DEB_INTS,printk(KERN_DEBUG "%s: i596 interrupt, IRQ %d, status %4.4x.\n",
+ dev->name, irq, status));
+
+ ack_cmd = status & 0xf000;
+
+ if ((status & 0x8000) || (status & 0x2000)) {
+ struct i596_cmd *ptr;
+
+ handled = 1;
+ if ((status & 0x8000))
+ DEB(DEB_INTS,printk(KERN_DEBUG "%s: i596 interrupt completed command.\n", dev->name));
+ if ((status & 0x2000))
+ DEB(DEB_INTS,printk(KERN_DEBUG "%s: i596 interrupt command unit inactive %x.\n", dev->name, status & 0x0700));
+
+ while ((lp->cmd_head != I596_NULL) && (lp->cmd_head->status & STAT_C)) {
+ ptr = lp->cmd_head;
+
+ DEB(DEB_STATUS,printk(KERN_DEBUG "cmd_head->status = %04x, ->command = %04x\n",
+ lp->cmd_head->status, lp->cmd_head->command));
+ lp->cmd_head = ptr->v_next;
+ lp->cmd_backlog--;
+
+ switch ((ptr->command) & 0x7) {
+ case CmdTx:
+ {
+ struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr;
+ struct sk_buff *skb = tx_cmd->skb;
+
+ if ((ptr->status) & STAT_OK) {
+ DEB(DEB_TXADDR,print_eth(skb->data, "tx-done"));
+ } else {
+ dev->stats.tx_errors++;
+ if ((ptr->status) & 0x0020)
+ dev->stats.collisions++;
+ if (!((ptr->status) & 0x0040))
+ dev->stats.tx_heartbeat_errors++;
+ if ((ptr->status) & 0x0400)
+ dev->stats.tx_carrier_errors++;
+ if ((ptr->status) & 0x0800)
+ dev->stats.collisions++;
+ if ((ptr->status) & 0x1000)
+ dev->stats.tx_aborted_errors++;
+ }
+
+ dev_kfree_skb_irq(skb);
+
+ tx_cmd->cmd.command = 0; /* Mark free */
+ break;
+ }
+ case CmdTDR:
+ {
+ unsigned short status = ((struct tdr_cmd *)ptr)->status;
+
+ if (status & 0x8000) {
+ DEB(DEB_TDR,printk(KERN_INFO "%s: link ok.\n", dev->name));
+ } else {
+ if (status & 0x4000)
+ printk(KERN_ERR "%s: Transceiver problem.\n", dev->name);
+ if (status & 0x2000)
+ printk(KERN_ERR "%s: Termination problem.\n", dev->name);
+ if (status & 0x1000)
+ printk(KERN_ERR "%s: Short circuit.\n", dev->name);
+
+ DEB(DEB_TDR,printk(KERN_INFO "%s: Time %d.\n", dev->name, status & 0x07ff));
+ }
+ break;
+ }
+ case CmdConfigure:
+ case CmdMulticastList:
+ /* Zap command so set_multicast_list() knows it is free */
+ ptr->command = 0;
+ break;
+ }
+ ptr->v_next = ptr->b_next = I596_NULL;
+ lp->last_cmd = jiffies;
+ }
+
+ ptr = lp->cmd_head;
+ while ((ptr != I596_NULL) && (ptr != lp->cmd_tail)) {
+ ptr->command &= 0x1fff;
+ ptr = ptr->v_next;
+ }
+
+ if ((lp->cmd_head != I596_NULL))
+ ack_cmd |= CUC_START;
+ lp->scb.cmd = WSWAPcmd(virt_to_bus(&lp->cmd_head->status));
+ }
+ if ((status & 0x1000) || (status & 0x4000)) {
+ if ((status & 0x4000))
+ DEB(DEB_INTS,printk(KERN_DEBUG "%s: i596 interrupt received a frame.\n", dev->name));
+ i596_rx(dev);
+ /* Only RX_START if stopped - RGH 07-07-96 */
+ if (status & 0x1000) {
+ if (netif_running(dev)) {
+ DEB(DEB_ERRORS,printk(KERN_ERR "%s: i596 interrupt receive unit inactive, status 0x%x\n", dev->name, status));
+ ack_cmd |= RX_START;
+ dev->stats.rx_errors++;
+ dev->stats.rx_fifo_errors++;
+ rebuild_rx_bufs(dev);
+ }
+ }
+ }
+ wait_cmd(dev,lp,100,"i596 interrupt, timeout");
+ lp->scb.command = ack_cmd;
+
+#ifdef ENABLE_MVME16x_NET
+ if (MACH_IS_MVME16x) {
+ /* Ack the interrupt */
+
+ volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000;
+
+ pcc2[0x2a] |= 0x08;
+ }
+#endif
+#ifdef ENABLE_BVME6000_NET
+ if (MACH_IS_BVME6000) {
+ volatile unsigned char *ethirq = (unsigned char *) BVME_ETHIRQ_REG;
+
+ *ethirq = 1;
+ *ethirq = 3;
+ }
+#endif
+#ifdef ENABLE_APRICOT
+ (void) inb(ioaddr + 0x10);
+ outb(4, ioaddr + 0xf);
+#endif
+ CA(dev);
+
+ DEB(DEB_INTS,printk(KERN_DEBUG "%s: exiting interrupt.\n", dev->name));
+
+ spin_unlock (&lp->lock);
+ return IRQ_RETVAL(handled);
+}
+
+static int i596_close(struct net_device *dev)
+{
+ struct i596_private *lp = dev->ml_priv;
+ unsigned long flags;
+
+ netif_stop_queue(dev);
+
+ DEB(DEB_INIT,printk(KERN_DEBUG "%s: Shutting down ethercard, status was %4.4x.\n",
+ dev->name, lp->scb.status));
+
+ spin_lock_irqsave(&lp->lock, flags);
+
+ wait_cmd(dev,lp,100,"close1 timed out");
+ lp->scb.command = CUC_ABORT | RX_ABORT;
+ CA(dev);
+
+ wait_cmd(dev,lp,100,"close2 timed out");
+
+ spin_unlock_irqrestore(&lp->lock, flags);
+ DEB(DEB_STRUCT,i596_display_data(dev));
+ i596_cleanup_cmd(dev,lp);
+
+#ifdef ENABLE_MVME16x_NET
+ if (MACH_IS_MVME16x) {
+ volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000;
+
+ /* Disable all ints */
+ pcc2[0x28] = 1;
+ pcc2[0x2a] = 0x40;
+ pcc2[0x2b] = 0x40; /* Set snooping bits now! */
+ }
+#endif
+#ifdef ENABLE_BVME6000_NET
+ if (MACH_IS_BVME6000) {
+ volatile unsigned char *ethirq = (unsigned char *) BVME_ETHIRQ_REG;
+
+ *ethirq = 1;
+ }
+#endif
+
+#ifdef ENABLE_MVME16x_NET
+ free_irq(0x56, dev);
+#endif
+ free_irq(dev->irq, dev);
+ remove_rx_bufs(dev);
+
+ return 0;
+}
+
+/*
+ * Set or clear the multicast filter for this adaptor.
+ */
+
+static void set_multicast_list(struct net_device *dev)
+{
+ struct i596_private *lp = dev->ml_priv;
+ int config = 0, cnt;
+
+ DEB(DEB_MULTI,printk(KERN_DEBUG "%s: set multicast list, %d entries, promisc %s, allmulti %s\n",
+ dev->name, netdev_mc_count(dev),
+ dev->flags & IFF_PROMISC ? "ON" : "OFF",
+ dev->flags & IFF_ALLMULTI ? "ON" : "OFF"));
+
+ if (wait_cfg(dev, &lp->cf_cmd.cmd, 1000, "config change request timed out"))
+ return;
+
+ if ((dev->flags & IFF_PROMISC) && !(lp->cf_cmd.i596_config[8] & 0x01)) {
+ lp->cf_cmd.i596_config[8] |= 0x01;
+ config = 1;
+ }
+ if (!(dev->flags & IFF_PROMISC) && (lp->cf_cmd.i596_config[8] & 0x01)) {
+ lp->cf_cmd.i596_config[8] &= ~0x01;
+ config = 1;
+ }
+ if ((dev->flags & IFF_ALLMULTI) && (lp->cf_cmd.i596_config[11] & 0x20)) {
+ lp->cf_cmd.i596_config[11] &= ~0x20;
+ config = 1;
+ }
+ if (!(dev->flags & IFF_ALLMULTI) && !(lp->cf_cmd.i596_config[11] & 0x20)) {
+ lp->cf_cmd.i596_config[11] |= 0x20;
+ config = 1;
+ }
+ if (config) {
+ lp->cf_cmd.cmd.command = CmdConfigure;
+ i596_add_cmd(dev, &lp->cf_cmd.cmd);
+ }
+
+ cnt = netdev_mc_count(dev);
+ if (cnt > MAX_MC_CNT)
+ {
+ cnt = MAX_MC_CNT;
+ printk(KERN_ERR "%s: Only %d multicast addresses supported",
+ dev->name, cnt);
+ }
+
+ if (!netdev_mc_empty(dev)) {
+ struct netdev_hw_addr *ha;
+ unsigned char *cp;
+ struct mc_cmd *cmd;
+
+ if (wait_cfg(dev, &lp->mc_cmd.cmd, 1000, "multicast list change request timed out"))
+ return;
+ cmd = &lp->mc_cmd;
+ cmd->cmd.command = CmdMulticastList;
+ cmd->mc_cnt = cnt * ETH_ALEN;
+ cp = cmd->mc_addrs;
+ netdev_for_each_mc_addr(ha, dev) {
+ if (!cnt--)
+ break;
+ memcpy(cp, ha->addr, ETH_ALEN);
+ if (i596_debug > 1)
+ DEB(DEB_MULTI,printk(KERN_INFO "%s: Adding address %pM\n",
+ dev->name, cp));
+ cp += ETH_ALEN;
+ }
+ i596_add_cmd(dev, &cmd->cmd);
+ }
+}
+
+#ifdef MODULE
+static struct net_device *dev_82596;
+
+#ifdef ENABLE_APRICOT
+module_param(irq, int, 0);
+MODULE_PARM_DESC(irq, "Apricot IRQ number");
+#endif
+
+static int debug = -1;
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "i82596 debug mask");
+
+int __init init_module(void)
+{
+ if (debug >= 0)
+ i596_debug = debug;
+ dev_82596 = i82596_probe(-1);
+ if (IS_ERR(dev_82596))
+ return PTR_ERR(dev_82596);
+ return 0;
+}
+
+void __exit cleanup_module(void)
+{
+ unregister_netdev(dev_82596);
+#ifdef __mc68000__
+ /* XXX This assumes default cache mode to be IOMAP_FULL_CACHING,
+ * XXX which may be invalid (CONFIG_060_WRITETHROUGH)
+ */
+
+ kernel_set_cachemode((void *)(dev_82596->mem_start), 4096,
+ IOMAP_FULL_CACHING);
+#endif
+ free_page ((u32)(dev_82596->mem_start));
+#ifdef ENABLE_APRICOT
+ /* If we don't do this, we can't re-insmod it later. */
+ release_region(dev_82596->base_addr, I596_TOTAL_SIZE);
+#endif
+ free_netdev(dev_82596);
+}
+
+#endif /* MODULE */
--- /dev/null
+#
+# Intel 82596/82593/82596 network device configuration
+#
+
+config NET_VENDOR_I825XX
+ bool "Intel (82586/82593/82596) devices"
+ depends on NET_VENDOR_INTEL && (ISA || ISA_DMA_API || ARM || \
+ ARCH_ACORN || MCA || MCA_LEGACY || SNI_RM || SUN3 || \
+ GSC || BVME6000 || MVME16x || EXPERIMENTAL)
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y
+ and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question does not directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about these devices. If you say Y, you will be asked for
+ your specific card in the following questions.
+
+if NET_VENDOR_I825XX
+
+config ELPLUS
+ tristate "3c505 \"EtherLink Plus\" support"
+ depends on ISA && ISA_DMA_API
+ ---help---
+ Information about this network (Ethernet) card can be found in
+ <file:Documentation/networking/3c505.txt>. If you have a card of
+ this type, say Y and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ To compile this driver as a module, choose M here. The module
+ will be called 3c505.
+
+config EL16
+ tristate "3c507 \"EtherLink 16\" support (EXPERIMENTAL)"
+ depends on ISA && EXPERIMENTAL
+ ---help---
+ If you have a network (Ethernet) card of this type, say Y and read
+ the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ To compile this driver as a module, choose M here. The module
+ will be called 3c507.
+
+config ELMC
+ tristate "3c523 \"EtherLink/MC\" support"
+ depends on MCA_LEGACY
+ ---help---
+ If you have a network (Ethernet) card of this type, say Y and read
+ the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ To compile this driver as a module, choose M here. The module
+ will be called 3c523.
+
+config ELMC_II
+ tristate "3c527 \"EtherLink/MC 32\" support (EXPERIMENTAL)"
+ depends on MCA && MCA_LEGACY
+ ---help---
+ If you have a network (Ethernet) card of this type, say Y and read
+ the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ To compile this driver as a module, choose M here. The module
+ will be called 3c527.
+
+config ARM_ETHER1
+ tristate "Acorn Ether1 support"
+ depends on ARM && ARCH_ACORN
+ ---help---
+ If you have an Acorn system with one of these (AKA25) network cards,
+ you should say Y to this option if you wish to use it with Linux.
+
+config APRICOT
+ tristate "Apricot Xen-II on board Ethernet"
+ depends on ISA
+ ---help---
+ If you have a network (Ethernet) controller of this type, say Y and
+ read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ To compile this driver as a module, choose M here. The module
+ will be called apricot.
+
+config BVME6000_NET
+ tristate "BVME6000 Ethernet support"
+ depends on BVME6000MVME16x
+ ---help---
+ This is the driver for the Ethernet interface on BVME4000 and
+ BVME6000 VME boards. Say Y here to include the driver for this chip
+ in your kernel.
+ To compile this driver as a module, choose M here.
+
+config EEXPRESS
+ tristate "EtherExpress 16 support"
+ depends on ISA
+ ---help---
+ If you have an EtherExpress16 network (Ethernet) card, say Y and
+ read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>. Note that the Intel
+ EtherExpress16 card used to be regarded as a very poor choice
+ because the driver was very unreliable. We now have a new driver
+ that should do better.
+
+ To compile this driver as a module, choose M here. The module
+ will be called eexpress.
+
+config EEXPRESS_PRO
+ tristate "EtherExpressPro support/EtherExpress 10 (i82595) support"
+ depends on ISA
+ ---help---
+ If you have a network (Ethernet) card of this type, say Y. This
+ driver supports Intel i82595{FX,TX} based boards. Note however
+ that the EtherExpress PRO/100 Ethernet card has its own separate
+ driver. Please read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ To compile this driver as a module, choose M here. The module
+ will be called eepro.
+
+config LASI_82596
+ tristate "Lasi ethernet"
+ depends on GSC
+ ---help---
+ Say Y here to support the builtin Intel 82596 ethernet controller
+ found in Hewlett-Packard PA-RISC machines with 10Mbit ethernet.
+
+config LP486E
+ tristate "LP486E on board Ethernet"
+ depends on ISA
+ ---help---
+ Say Y here to support the 82596-based on-board Ethernet controller
+ for the Panther motherboard, which is one of the two shipped in the
+ Intel Professional Workstation.
+
+config MVME16x_NET
+ tristate "MVME16x Ethernet support"
+ depends on MVME16x
+ ---help---
+ This is the driver for the Ethernet interface on the Motorola
+ MVME162, 166, 167, 172 and 177 boards. Say Y here to include the
+ driver for this chip in your kernel.
+ To compile this driver as a module, choose M here.
+
+config NI52
+ tristate "NI5210 support"
+ depends on ISA
+ ---help---
+ If you have a network (Ethernet) card of this type, say Y and read
+ the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ To compile this driver as a module, choose M here. The module
+ will be called ni52.
+
+config SNI_82596
+ tristate "SNI RM ethernet"
+ depends on SNI_RM
+ ---help---
+ Say Y here to support the on-board Intel 82596 ethernet controller
+ built into SNI RM machines.
+
+config SUN3_82586
+ bool "Sun3 on-board Intel 82586 support"
+ depends on SUN3
+ ---help---
+ This driver enables support for the on-board Intel 82586 based
+ Ethernet adapter found on Sun 3/1xx and 3/2xx motherboards. Note
+ that this driver does not support 82586-based adapters on additional
+ VME boards.
+
+config ZNET
+ tristate "Zenith Z-Note support (EXPERIMENTAL)"
+ depends on EXPERIMENTAL && ISA_DMA_API
+ ---help---
+ The Zenith Z-Note notebook computer has a built-in network
+ (Ethernet) card, and this is the Linux driver for it. Note that the
+ IBM Thinkpad 300 is compatible with the Z-Note and is also supported
+ by this driver. Read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+endif # NET_VENDOR_I825XX
--- /dev/null
+#
+# Makefile for the Intel 82586/82593/82596 chipset device drivers.
+#
+
+obj-$(CONFIG_ARM_ETHER1) += ether1.o
+obj-$(CONFIG_EEXPRESS) += eexpress.o
+obj-$(CONFIG_EEXPRESS_PRO) += eepro.o
+obj-$(CONFIG_ELPLUS) += 3c505.o
+obj-$(CONFIG_EL16) += 3c507.o
+obj-$(CONFIG_ELMC) += 3c523.o
+obj-$(CONFIG_ELMC_II) += 3c527.o
+obj-$(CONFIG_LP486E) += lp486e.o
+obj-$(CONFIG_NI52) += ni52.o
+obj-$(CONFIG_SUN3_82586) += sun3_82586.o
+obj-$(CONFIG_ZNET) += znet.o
+obj-$(CONFIG_APRICOT) += 82596.o
+obj-$(CONFIG_LASI_82596) += lasi_82596.o
+obj-$(CONFIG_SNI_82596) += sni_82596.o
+obj-$(CONFIG_MVME16x_NET) += 82596.o
+obj-$(CONFIG_BVME6000_NET) += 82596.o
--- /dev/null
+/* eepro.c: Intel EtherExpress Pro/10 device driver for Linux. */
+/*
+ Written 1994, 1995,1996 by Bao C. Ha.
+
+ Copyright (C) 1994, 1995,1996 by Bao C. Ha.
+
+ This software may be used and distributed
+ according to the terms of the GNU General Public License,
+ incorporated herein by reference.
+
+ The author may be reached at bao.ha@srs.gov
+ or 418 Hastings Place, Martinez, GA 30907.
+
+ Things remaining to do:
+ Better record keeping of errors.
+ Eliminate transmit interrupt to reduce overhead.
+ Implement "concurrent processing". I won't be doing it!
+
+ Bugs:
+
+ If you have a problem of not detecting the 82595 during a
+ reboot (warm reset), disable the FLASH memory should fix it.
+ This is a compatibility hardware problem.
+
+ Versions:
+ 0.13b basic ethtool support (aris, 09/13/2004)
+ 0.13a in memory shortage, drop packets also in board
+ (Michael Westermann <mw@microdata-pos.de>, 07/30/2002)
+ 0.13 irq sharing, rewrote probe function, fixed a nasty bug in
+ hardware_send_packet and a major cleanup (aris, 11/08/2001)
+ 0.12d fixing a problem with single card detected as eight eth devices
+ fixing a problem with sudden drop in card performance
+ (chris (asdn@go2.pl), 10/29/2001)
+ 0.12c fixing some problems with old cards (aris, 01/08/2001)
+ 0.12b misc fixes (aris, 06/26/2000)
+ 0.12a port of version 0.12a of 2.2.x kernels to 2.3.x
+ (aris (aris@conectiva.com.br), 05/19/2000)
+ 0.11e some tweaks about multiple cards support (PdP, jul/aug 1999)
+ 0.11d added __initdata, __init stuff; call spin_lock_init
+ in eepro_probe1. Replaced "eepro" by dev->name. Augmented
+ the code protected by spin_lock in interrupt routine
+ (PdP, 12/12/1998)
+ 0.11c minor cleanup (PdP, RMC, 09/12/1998)
+ 0.11b Pascal Dupuis (dupuis@lei.ucl.ac.be): works as a module
+ under 2.1.xx. Debug messages are flagged as KERN_DEBUG to
+ avoid console flooding. Added locking at critical parts. Now
+ the dawn thing is SMP safe.
+ 0.11a Attempt to get 2.1.xx support up (RMC)
+ 0.11 Brian Candler added support for multiple cards. Tested as
+ a module, no idea if it works when compiled into kernel.
+
+ 0.10e Rick Bressler notified me that ifconfig up;ifconfig down fails
+ because the irq is lost somewhere. Fixed that by moving
+ request_irq and free_irq to eepro_open and eepro_close respectively.
+ 0.10d Ugh! Now Wakeup works. Was seriously broken in my first attempt.
+ I'll need to find a way to specify an ioport other than
+ the default one in the PnP case. PnP definitively sucks.
+ And, yes, this is not the only reason.
+ 0.10c PnP Wakeup Test for 595FX. uncomment #define PnPWakeup;
+ to use.
+ 0.10b Should work now with (some) Pro/10+. At least for
+ me (and my two cards) it does. _No_ guarantee for
+ function with non-Pro/10+ cards! (don't have any)
+ (RMC, 9/11/96)
+
+ 0.10 Added support for the Etherexpress Pro/10+. The
+ IRQ map was changed significantly from the old
+ pro/10. The new interrupt map was provided by
+ Rainer M. Canavan (Canavan@Zeus.cs.bonn.edu).
+ (BCH, 9/3/96)
+
+ 0.09 Fixed a race condition in the transmit algorithm,
+ which causes crashes under heavy load with fast
+ pentium computers. The performance should also
+ improve a bit. The size of RX buffer, and hence
+ TX buffer, can also be changed via lilo or insmod.
+ (BCH, 7/31/96)
+
+ 0.08 Implement 32-bit I/O for the 82595TX and 82595FX
+ based lan cards. Disable full-duplex mode if TPE
+ is not used. (BCH, 4/8/96)
+
+ 0.07a Fix a stat report which counts every packet as a
+ heart-beat failure. (BCH, 6/3/95)
+
+ 0.07 Modified to support all other 82595-based lan cards.
+ The IRQ vector of the EtherExpress Pro will be set
+ according to the value saved in the EEPROM. For other
+ cards, I will do autoirq_request() to grab the next
+ available interrupt vector. (BCH, 3/17/95)
+
+ 0.06a,b Interim released. Minor changes in the comments and
+ print out format. (BCH, 3/9/95 and 3/14/95)
+
+ 0.06 First stable release that I am comfortable with. (BCH,
+ 3/2/95)
+
+ 0.05 Complete testing of multicast. (BCH, 2/23/95)
+
+ 0.04 Adding multicast support. (BCH, 2/14/95)
+
+ 0.03 First widely alpha release for public testing.
+ (BCH, 2/14/95)
+
+*/
+
+static const char version[] =
+ "eepro.c: v0.13b 09/13/2004 aris@cathedrallabs.org\n";
+
+#include <linux/module.h>
+
+/*
+ Sources:
+
+ This driver wouldn't have been written without the availability
+ of the Crynwr's Lan595 driver source code. It helps me to
+ familiarize with the 82595 chipset while waiting for the Intel
+ documentation. I also learned how to detect the 82595 using
+ the packet driver's technique.
+
+ This driver is written by cutting and pasting the skeleton.c driver
+ provided by Donald Becker. I also borrowed the EEPROM routine from
+ Donald Becker's 82586 driver.
+
+ Datasheet for the Intel 82595 (including the TX and FX version). It
+ provides just enough info that the casual reader might think that it
+ documents the i82595.
+
+ The User Manual for the 82595. It provides a lot of the missing
+ information.
+
+*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+#include <linux/ethtool.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#define DRV_NAME "eepro"
+#define DRV_VERSION "0.13c"
+
+#define compat_dev_kfree_skb( skb, mode ) dev_kfree_skb( (skb) )
+/* I had reports of looong delays with SLOW_DOWN defined as udelay(2) */
+#define SLOW_DOWN inb(0x80)
+/* udelay(2) */
+#define compat_init_data __initdata
+enum iftype { AUI=0, BNC=1, TPE=2 };
+
+/* First, a few definitions that the brave might change. */
+/* A zero-terminated list of I/O addresses to be probed. */
+static unsigned int eepro_portlist[] compat_init_data =
+ { 0x300, 0x210, 0x240, 0x280, 0x2C0, 0x200, 0x320, 0x340, 0x360, 0};
+/* note: 0x300 is default, the 595FX supports ALL IO Ports
+ from 0x000 to 0x3F0, some of which are reserved in PCs */
+
+/* To try the (not-really PnP Wakeup: */
+/*
+#define PnPWakeup
+*/
+
+/* use 0 for production, 1 for verification, >2 for debug */
+#ifndef NET_DEBUG
+#define NET_DEBUG 0
+#endif
+static unsigned int net_debug = NET_DEBUG;
+
+/* The number of low I/O ports used by the ethercard. */
+#define EEPRO_IO_EXTENT 16
+
+/* Different 82595 chips */
+#define LAN595 0
+#define LAN595TX 1
+#define LAN595FX 2
+#define LAN595FX_10ISA 3
+
+/* Information that need to be kept for each board. */
+struct eepro_local {
+ unsigned rx_start;
+ unsigned tx_start; /* start of the transmit chain */
+ int tx_last; /* pointer to last packet in the transmit chain */
+ unsigned tx_end; /* end of the transmit chain (plus 1) */
+ int eepro; /* 1 for the EtherExpress Pro/10,
+ 2 for the EtherExpress Pro/10+,
+ 3 for the EtherExpress 10 (blue cards),
+ 0 for other 82595-based lan cards. */
+ int version; /* a flag to indicate if this is a TX or FX
+ version of the 82595 chip. */
+ int stepping;
+
+ spinlock_t lock; /* Serializing lock */
+
+ unsigned rcv_ram; /* pre-calculated space for rx */
+ unsigned xmt_ram; /* pre-calculated space for tx */
+ unsigned char xmt_bar;
+ unsigned char xmt_lower_limit_reg;
+ unsigned char xmt_upper_limit_reg;
+ short xmt_lower_limit;
+ short xmt_upper_limit;
+ short rcv_lower_limit;
+ short rcv_upper_limit;
+ unsigned char eeprom_reg;
+ unsigned short word[8];
+};
+
+/* The station (ethernet) address prefix, used for IDing the board. */
+#define SA_ADDR0 0x00 /* Etherexpress Pro/10 */
+#define SA_ADDR1 0xaa
+#define SA_ADDR2 0x00
+
+#define GetBit(x,y) ((x & (1<<y))>>y)
+
+/* EEPROM Word 0: */
+#define ee_PnP 0 /* Plug 'n Play enable bit */
+#define ee_Word1 1 /* Word 1? */
+#define ee_BusWidth 2 /* 8/16 bit */
+#define ee_FlashAddr 3 /* Flash Address */
+#define ee_FlashMask 0x7 /* Mask */
+#define ee_AutoIO 6 /* */
+#define ee_reserved0 7 /* =0! */
+#define ee_Flash 8 /* Flash there? */
+#define ee_AutoNeg 9 /* Auto Negotiation enabled? */
+#define ee_IO0 10 /* IO Address LSB */
+#define ee_IO0Mask 0x /*...*/
+#define ee_IO1 15 /* IO MSB */
+
+/* EEPROM Word 1: */
+#define ee_IntSel 0 /* Interrupt */
+#define ee_IntMask 0x7
+#define ee_LI 3 /* Link Integrity 0= enabled */
+#define ee_PC 4 /* Polarity Correction 0= enabled */
+#define ee_TPE_AUI 5 /* PortSelection 1=TPE */
+#define ee_Jabber 6 /* Jabber prevention 0= enabled */
+#define ee_AutoPort 7 /* Auto Port Selection 1= Disabled */
+#define ee_SMOUT 8 /* SMout Pin Control 0= Input */
+#define ee_PROM 9 /* Flash EPROM / PROM 0=Flash */
+#define ee_reserved1 10 /* .. 12 =0! */
+#define ee_AltReady 13 /* Alternate Ready, 0=normal */
+#define ee_reserved2 14 /* =0! */
+#define ee_Duplex 15
+
+/* Word2,3,4: */
+#define ee_IA5 0 /*bit start for individual Addr Byte 5 */
+#define ee_IA4 8 /*bit start for individual Addr Byte 5 */
+#define ee_IA3 0 /*bit start for individual Addr Byte 5 */
+#define ee_IA2 8 /*bit start for individual Addr Byte 5 */
+#define ee_IA1 0 /*bit start for individual Addr Byte 5 */
+#define ee_IA0 8 /*bit start for individual Addr Byte 5 */
+
+/* Word 5: */
+#define ee_BNC_TPE 0 /* 0=TPE */
+#define ee_BootType 1 /* 00=None, 01=IPX, 10=ODI, 11=NDIS */
+#define ee_BootTypeMask 0x3
+#define ee_NumConn 3 /* Number of Connections 0= One or Two */
+#define ee_FlashSock 4 /* Presence of Flash Socket 0= Present */
+#define ee_PortTPE 5
+#define ee_PortBNC 6
+#define ee_PortAUI 7
+#define ee_PowerMgt 10 /* 0= disabled */
+#define ee_CP 13 /* Concurrent Processing */
+#define ee_CPMask 0x7
+
+/* Word 6: */
+#define ee_Stepping 0 /* Stepping info */
+#define ee_StepMask 0x0F
+#define ee_BoardID 4 /* Manucaturer Board ID, reserved */
+#define ee_BoardMask 0x0FFF
+
+/* Word 7: */
+#define ee_INT_TO_IRQ 0 /* int to IRQ Mapping = 0x1EB8 for Pro/10+ */
+#define ee_FX_INT2IRQ 0x1EB8 /* the _only_ mapping allowed for FX chips */
+
+/*..*/
+#define ee_SIZE 0x40 /* total EEprom Size */
+#define ee_Checksum 0xBABA /* initial and final value for adding checksum */
+
+
+/* Card identification via EEprom: */
+#define ee_addr_vendor 0x10 /* Word offset for EISA Vendor ID */
+#define ee_addr_id 0x11 /* Word offset for Card ID */
+#define ee_addr_SN 0x12 /* Serial Number */
+#define ee_addr_CRC_8 0x14 /* CRC over last thee Bytes */
+
+
+#define ee_vendor_intel0 0x25 /* Vendor ID Intel */
+#define ee_vendor_intel1 0xD4
+#define ee_id_eepro10p0 0x10 /* ID for eepro/10+ */
+#define ee_id_eepro10p1 0x31
+
+#define TX_TIMEOUT ((4*HZ)/10)
+
+/* Index to functions, as function prototypes. */
+
+static int eepro_probe1(struct net_device *dev, int autoprobe);
+static int eepro_open(struct net_device *dev);
+static netdev_tx_t eepro_send_packet(struct sk_buff *skb,
+ struct net_device *dev);
+static irqreturn_t eepro_interrupt(int irq, void *dev_id);
+static void eepro_rx(struct net_device *dev);
+static void eepro_transmit_interrupt(struct net_device *dev);
+static int eepro_close(struct net_device *dev);
+static void set_multicast_list(struct net_device *dev);
+static void eepro_tx_timeout (struct net_device *dev);
+
+static int read_eeprom(int ioaddr, int location, struct net_device *dev);
+static int hardware_send_packet(struct net_device *dev, void *buf, short length);
+static int eepro_grab_irq(struct net_device *dev);
+
+/*
+ Details of the i82595.
+
+You will need either the datasheet or the user manual to understand what
+is going on here. The 82595 is very different from the 82586, 82593.
+
+The receive algorithm in eepro_rx() is just an implementation of the
+RCV ring structure that the Intel 82595 imposes at the hardware level.
+The receive buffer is set at 24K, and the transmit buffer is 8K. I
+am assuming that the total buffer memory is 32K, which is true for the
+Intel EtherExpress Pro/10. If it is less than that on a generic card,
+the driver will be broken.
+
+The transmit algorithm in the hardware_send_packet() is similar to the
+one in the eepro_rx(). The transmit buffer is a ring linked list.
+I just queue the next available packet to the end of the list. In my
+system, the 82595 is so fast that the list seems to always contain a
+single packet. In other systems with faster computers and more congested
+network traffics, the ring linked list should improve performance by
+allowing up to 8K worth of packets to be queued.
+
+The sizes of the receive and transmit buffers can now be changed via lilo
+or insmod. Lilo uses the appended line "ether=io,irq,debug,rx-buffer,eth0"
+where rx-buffer is in KB unit. Modules uses the parameter mem which is
+also in KB unit, for example "insmod io=io-address irq=0 mem=rx-buffer."
+The receive buffer has to be more than 3K or less than 29K. Otherwise,
+it is reset to the default of 24K, and, hence, 8K for the trasnmit
+buffer (transmit-buffer = 32K - receive-buffer).
+
+*/
+#define RAM_SIZE 0x8000
+
+#define RCV_HEADER 8
+#define RCV_DEFAULT_RAM 0x6000
+
+#define XMT_HEADER 8
+#define XMT_DEFAULT_RAM (RAM_SIZE - RCV_DEFAULT_RAM)
+
+#define XMT_START_PRO RCV_DEFAULT_RAM
+#define XMT_START_10 0x0000
+#define RCV_START_PRO 0x0000
+#define RCV_START_10 XMT_DEFAULT_RAM
+
+#define RCV_DONE 0x0008
+#define RX_OK 0x2000
+#define RX_ERROR 0x0d81
+
+#define TX_DONE_BIT 0x0080
+#define TX_OK 0x2000
+#define CHAIN_BIT 0x8000
+#define XMT_STATUS 0x02
+#define XMT_CHAIN 0x04
+#define XMT_COUNT 0x06
+
+#define BANK0_SELECT 0x00
+#define BANK1_SELECT 0x40
+#define BANK2_SELECT 0x80
+
+/* Bank 0 registers */
+#define COMMAND_REG 0x00 /* Register 0 */
+#define MC_SETUP 0x03
+#define XMT_CMD 0x04
+#define DIAGNOSE_CMD 0x07
+#define RCV_ENABLE_CMD 0x08
+#define RCV_DISABLE_CMD 0x0a
+#define STOP_RCV_CMD 0x0b
+#define RESET_CMD 0x0e
+#define POWER_DOWN_CMD 0x18
+#define RESUME_XMT_CMD 0x1c
+#define SEL_RESET_CMD 0x1e
+#define STATUS_REG 0x01 /* Register 1 */
+#define RX_INT 0x02
+#define TX_INT 0x04
+#define EXEC_STATUS 0x30
+#define ID_REG 0x02 /* Register 2 */
+#define R_ROBIN_BITS 0xc0 /* round robin counter */
+#define ID_REG_MASK 0x2c
+#define ID_REG_SIG 0x24
+#define AUTO_ENABLE 0x10
+#define INT_MASK_REG 0x03 /* Register 3 */
+#define RX_STOP_MASK 0x01
+#define RX_MASK 0x02
+#define TX_MASK 0x04
+#define EXEC_MASK 0x08
+#define ALL_MASK 0x0f
+#define IO_32_BIT 0x10
+#define RCV_BAR 0x04 /* The following are word (16-bit) registers */
+#define RCV_STOP 0x06
+
+#define XMT_BAR_PRO 0x0a
+#define XMT_BAR_10 0x0b
+
+#define HOST_ADDRESS_REG 0x0c
+#define IO_PORT 0x0e
+#define IO_PORT_32_BIT 0x0c
+
+/* Bank 1 registers */
+#define REG1 0x01
+#define WORD_WIDTH 0x02
+#define INT_ENABLE 0x80
+#define INT_NO_REG 0x02
+#define RCV_LOWER_LIMIT_REG 0x08
+#define RCV_UPPER_LIMIT_REG 0x09
+
+#define XMT_LOWER_LIMIT_REG_PRO 0x0a
+#define XMT_UPPER_LIMIT_REG_PRO 0x0b
+#define XMT_LOWER_LIMIT_REG_10 0x0b
+#define XMT_UPPER_LIMIT_REG_10 0x0a
+
+/* Bank 2 registers */
+#define XMT_Chain_Int 0x20 /* Interrupt at the end of the transmit chain */
+#define XMT_Chain_ErrStop 0x40 /* Interrupt at the end of the chain even if there are errors */
+#define RCV_Discard_BadFrame 0x80 /* Throw bad frames away, and continue to receive others */
+#define REG2 0x02
+#define PRMSC_Mode 0x01
+#define Multi_IA 0x20
+#define REG3 0x03
+#define TPE_BIT 0x04
+#define BNC_BIT 0x20
+#define REG13 0x0d
+#define FDX 0x00
+#define A_N_ENABLE 0x02
+
+#define I_ADD_REG0 0x04
+#define I_ADD_REG1 0x05
+#define I_ADD_REG2 0x06
+#define I_ADD_REG3 0x07
+#define I_ADD_REG4 0x08
+#define I_ADD_REG5 0x09
+
+#define EEPROM_REG_PRO 0x0a
+#define EEPROM_REG_10 0x0b
+
+#define EESK 0x01
+#define EECS 0x02
+#define EEDI 0x04
+#define EEDO 0x08
+
+/* do a full reset */
+#define eepro_reset(ioaddr) outb(RESET_CMD, ioaddr)
+
+/* do a nice reset */
+#define eepro_sel_reset(ioaddr) { \
+ outb(SEL_RESET_CMD, ioaddr); \
+ SLOW_DOWN; \
+ SLOW_DOWN; \
+ }
+
+/* disable all interrupts */
+#define eepro_dis_int(ioaddr) outb(ALL_MASK, ioaddr + INT_MASK_REG)
+
+/* clear all interrupts */
+#define eepro_clear_int(ioaddr) outb(ALL_MASK, ioaddr + STATUS_REG)
+
+/* enable tx/rx */
+#define eepro_en_int(ioaddr) outb(ALL_MASK & ~(RX_MASK | TX_MASK), \
+ ioaddr + INT_MASK_REG)
+
+/* enable exec event interrupt */
+#define eepro_en_intexec(ioaddr) outb(ALL_MASK & ~(EXEC_MASK), ioaddr + INT_MASK_REG)
+
+/* enable rx */
+#define eepro_en_rx(ioaddr) outb(RCV_ENABLE_CMD, ioaddr)
+
+/* disable rx */
+#define eepro_dis_rx(ioaddr) outb(RCV_DISABLE_CMD, ioaddr)
+
+/* switch bank */
+#define eepro_sw2bank0(ioaddr) outb(BANK0_SELECT, ioaddr)
+#define eepro_sw2bank1(ioaddr) outb(BANK1_SELECT, ioaddr)
+#define eepro_sw2bank2(ioaddr) outb(BANK2_SELECT, ioaddr)
+
+/* enable interrupt line */
+#define eepro_en_intline(ioaddr) outb(inb(ioaddr + REG1) | INT_ENABLE,\
+ ioaddr + REG1)
+
+/* disable interrupt line */
+#define eepro_dis_intline(ioaddr) outb(inb(ioaddr + REG1) & 0x7f, \
+ ioaddr + REG1);
+
+/* set diagnose flag */
+#define eepro_diag(ioaddr) outb(DIAGNOSE_CMD, ioaddr)
+
+/* ack for rx int */
+#define eepro_ack_rx(ioaddr) outb (RX_INT, ioaddr + STATUS_REG)
+
+/* ack for tx int */
+#define eepro_ack_tx(ioaddr) outb (TX_INT, ioaddr + STATUS_REG)
+
+/* a complete sel reset */
+#define eepro_complete_selreset(ioaddr) { \
+ dev->stats.tx_errors++;\
+ eepro_sel_reset(ioaddr);\
+ lp->tx_end = \
+ lp->xmt_lower_limit;\
+ lp->tx_start = lp->tx_end;\
+ lp->tx_last = 0;\
+ dev->trans_start = jiffies;\
+ netif_wake_queue(dev);\
+ eepro_en_rx(ioaddr);\
+ }
+
+/* Check for a network adaptor of this type, and return '0' if one exists.
+ If dev->base_addr == 0, probe all likely locations.
+ If dev->base_addr == 1, always return failure.
+ If dev->base_addr == 2, allocate space for the device and return success
+ (detachable devices only).
+ */
+static int __init do_eepro_probe(struct net_device *dev)
+{
+ int i;
+ int base_addr = dev->base_addr;
+ int irq = dev->irq;
+
+#ifdef PnPWakeup
+ /* XXXX for multiple cards should this only be run once? */
+
+ /* Wakeup: */
+ #define WakeupPort 0x279
+ #define WakeupSeq {0x6A, 0xB5, 0xDA, 0xED, 0xF6, 0xFB, 0x7D, 0xBE,\
+ 0xDF, 0x6F, 0x37, 0x1B, 0x0D, 0x86, 0xC3, 0x61,\
+ 0xB0, 0x58, 0x2C, 0x16, 0x8B, 0x45, 0xA2, 0xD1,\
+ 0xE8, 0x74, 0x3A, 0x9D, 0xCE, 0xE7, 0x73, 0x43}
+
+ {
+ unsigned short int WS[32]=WakeupSeq;
+
+ if (request_region(WakeupPort, 2, "eepro wakeup")) {
+ if (net_debug>5)
+ printk(KERN_DEBUG "Waking UP\n");
+
+ outb_p(0,WakeupPort);
+ outb_p(0,WakeupPort);
+ for (i=0; i<32; i++) {
+ outb_p(WS[i],WakeupPort);
+ if (net_debug>5) printk(KERN_DEBUG ": %#x ",WS[i]);
+ }
+
+ release_region(WakeupPort, 2);
+ } else
+ printk(KERN_WARNING "PnP wakeup region busy!\n");
+ }
+#endif
+
+ if (base_addr > 0x1ff) /* Check a single specified location. */
+ return eepro_probe1(dev, 0);
+
+ else if (base_addr != 0) /* Don't probe at all. */
+ return -ENXIO;
+
+ for (i = 0; eepro_portlist[i]; i++) {
+ dev->base_addr = eepro_portlist[i];
+ dev->irq = irq;
+ if (eepro_probe1(dev, 1) == 0)
+ return 0;
+ }
+
+ return -ENODEV;
+}
+
+#ifndef MODULE
+struct net_device * __init eepro_probe(int unit)
+{
+ struct net_device *dev = alloc_etherdev(sizeof(struct eepro_local));
+ int err;
+
+ if (!dev)
+ return ERR_PTR(-ENODEV);
+
+ sprintf(dev->name, "eth%d", unit);
+ netdev_boot_setup_check(dev);
+
+ err = do_eepro_probe(dev);
+ if (err)
+ goto out;
+ return dev;
+out:
+ free_netdev(dev);
+ return ERR_PTR(err);
+}
+#endif
+
+static void __init printEEPROMInfo(struct net_device *dev)
+{
+ struct eepro_local *lp = netdev_priv(dev);
+ int ioaddr = dev->base_addr;
+ unsigned short Word;
+ int i,j;
+
+ j = ee_Checksum;
+ for (i = 0; i < 8; i++)
+ j += lp->word[i];
+ for ( ; i < ee_SIZE; i++)
+ j += read_eeprom(ioaddr, i, dev);
+
+ printk(KERN_DEBUG "Checksum: %#x\n",j&0xffff);
+
+ Word = lp->word[0];
+ printk(KERN_DEBUG "Word0:\n");
+ printk(KERN_DEBUG " Plug 'n Pray: %d\n",GetBit(Word,ee_PnP));
+ printk(KERN_DEBUG " Buswidth: %d\n",(GetBit(Word,ee_BusWidth)+1)*8 );
+ printk(KERN_DEBUG " AutoNegotiation: %d\n",GetBit(Word,ee_AutoNeg));
+ printk(KERN_DEBUG " IO Address: %#x\n", (Word>>ee_IO0)<<4);
+
+ if (net_debug>4) {
+ Word = lp->word[1];
+ printk(KERN_DEBUG "Word1:\n");
+ printk(KERN_DEBUG " INT: %d\n", Word & ee_IntMask);
+ printk(KERN_DEBUG " LI: %d\n", GetBit(Word,ee_LI));
+ printk(KERN_DEBUG " PC: %d\n", GetBit(Word,ee_PC));
+ printk(KERN_DEBUG " TPE/AUI: %d\n", GetBit(Word,ee_TPE_AUI));
+ printk(KERN_DEBUG " Jabber: %d\n", GetBit(Word,ee_Jabber));
+ printk(KERN_DEBUG " AutoPort: %d\n", !GetBit(Word,ee_AutoPort));
+ printk(KERN_DEBUG " Duplex: %d\n", GetBit(Word,ee_Duplex));
+ }
+
+ Word = lp->word[5];
+ printk(KERN_DEBUG "Word5:\n");
+ printk(KERN_DEBUG " BNC: %d\n",GetBit(Word,ee_BNC_TPE));
+ printk(KERN_DEBUG " NumConnectors: %d\n",GetBit(Word,ee_NumConn));
+ printk(KERN_DEBUG " Has ");
+ if (GetBit(Word,ee_PortTPE)) printk(KERN_DEBUG "TPE ");
+ if (GetBit(Word,ee_PortBNC)) printk(KERN_DEBUG "BNC ");
+ if (GetBit(Word,ee_PortAUI)) printk(KERN_DEBUG "AUI ");
+ printk(KERN_DEBUG "port(s)\n");
+
+ Word = lp->word[6];
+ printk(KERN_DEBUG "Word6:\n");
+ printk(KERN_DEBUG " Stepping: %d\n",Word & ee_StepMask);
+ printk(KERN_DEBUG " BoardID: %d\n",Word>>ee_BoardID);
+
+ Word = lp->word[7];
+ printk(KERN_DEBUG "Word7:\n");
+ printk(KERN_DEBUG " INT to IRQ:\n");
+
+ for (i=0, j=0; i<15; i++)
+ if (GetBit(Word,i)) printk(KERN_DEBUG " INT%d -> IRQ %d;",j++,i);
+
+ printk(KERN_DEBUG "\n");
+}
+
+/* function to recalculate the limits of buffer based on rcv_ram */
+static void eepro_recalc (struct net_device *dev)
+{
+ struct eepro_local * lp;
+
+ lp = netdev_priv(dev);
+ lp->xmt_ram = RAM_SIZE - lp->rcv_ram;
+
+ if (lp->eepro == LAN595FX_10ISA) {
+ lp->xmt_lower_limit = XMT_START_10;
+ lp->xmt_upper_limit = (lp->xmt_ram - 2);
+ lp->rcv_lower_limit = lp->xmt_ram;
+ lp->rcv_upper_limit = (RAM_SIZE - 2);
+ }
+ else {
+ lp->rcv_lower_limit = RCV_START_PRO;
+ lp->rcv_upper_limit = (lp->rcv_ram - 2);
+ lp->xmt_lower_limit = lp->rcv_ram;
+ lp->xmt_upper_limit = (RAM_SIZE - 2);
+ }
+}
+
+/* prints boot-time info */
+static void __init eepro_print_info (struct net_device *dev)
+{
+ struct eepro_local * lp = netdev_priv(dev);
+ int i;
+ const char * ifmap[] = {"AUI", "10Base2", "10BaseT"};
+
+ i = inb(dev->base_addr + ID_REG);
+ printk(KERN_DEBUG " id: %#x ",i);
+ printk(" io: %#x ", (unsigned)dev->base_addr);
+
+ switch (lp->eepro) {
+ case LAN595FX_10ISA:
+ printk("%s: Intel EtherExpress 10 ISA\n at %#x,",
+ dev->name, (unsigned)dev->base_addr);
+ break;
+ case LAN595FX:
+ printk("%s: Intel EtherExpress Pro/10+ ISA\n at %#x,",
+ dev->name, (unsigned)dev->base_addr);
+ break;
+ case LAN595TX:
+ printk("%s: Intel EtherExpress Pro/10 ISA at %#x,",
+ dev->name, (unsigned)dev->base_addr);
+ break;
+ case LAN595:
+ printk("%s: Intel 82595-based lan card at %#x,",
+ dev->name, (unsigned)dev->base_addr);
+ break;
+ }
+
+ printk(" %pM", dev->dev_addr);
+
+ if (net_debug > 3)
+ printk(KERN_DEBUG ", %dK RCV buffer",
+ (int)(lp->rcv_ram)/1024);
+
+ if (dev->irq > 2)
+ printk(", IRQ %d, %s.\n", dev->irq, ifmap[dev->if_port]);
+ else
+ printk(", %s.\n", ifmap[dev->if_port]);
+
+ if (net_debug > 3) {
+ i = lp->word[5];
+ if (i & 0x2000) /* bit 13 of EEPROM word 5 */
+ printk(KERN_DEBUG "%s: Concurrent Processing is "
+ "enabled but not used!\n", dev->name);
+ }
+
+ /* Check the station address for the manufacturer's code */
+ if (net_debug>3)
+ printEEPROMInfo(dev);
+}
+
+static const struct ethtool_ops eepro_ethtool_ops;
+
+static const struct net_device_ops eepro_netdev_ops = {
+ .ndo_open = eepro_open,
+ .ndo_stop = eepro_close,
+ .ndo_start_xmit = eepro_send_packet,
+ .ndo_set_multicast_list = set_multicast_list,
+ .ndo_tx_timeout = eepro_tx_timeout,
+ .ndo_change_mtu = eth_change_mtu,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+};
+
+/* This is the real probe routine. Linux has a history of friendly device
+ probes on the ISA bus. A good device probe avoids doing writes, and
+ verifies that the correct device exists and functions. */
+
+static int __init eepro_probe1(struct net_device *dev, int autoprobe)
+{
+ unsigned short station_addr[3], id, counter;
+ int i;
+ struct eepro_local *lp;
+ int ioaddr = dev->base_addr;
+ int err;
+
+ /* Grab the region so we can find another board if autoIRQ fails. */
+ if (!request_region(ioaddr, EEPRO_IO_EXTENT, DRV_NAME)) {
+ if (!autoprobe)
+ printk(KERN_WARNING "EEPRO: io-port 0x%04x in use\n",
+ ioaddr);
+ return -EBUSY;
+ }
+
+ /* Now, we are going to check for the signature of the
+ ID_REG (register 2 of bank 0) */
+
+ id = inb(ioaddr + ID_REG);
+
+ if ((id & ID_REG_MASK) != ID_REG_SIG)
+ goto exit;
+
+ /* We seem to have the 82595 signature, let's
+ play with its counter (last 2 bits of
+ register 2 of bank 0) to be sure. */
+
+ counter = id & R_ROBIN_BITS;
+
+ if ((inb(ioaddr + ID_REG) & R_ROBIN_BITS) != (counter + 0x40))
+ goto exit;
+
+ lp = netdev_priv(dev);
+ memset(lp, 0, sizeof(struct eepro_local));
+ lp->xmt_bar = XMT_BAR_PRO;
+ lp->xmt_lower_limit_reg = XMT_LOWER_LIMIT_REG_PRO;
+ lp->xmt_upper_limit_reg = XMT_UPPER_LIMIT_REG_PRO;
+ lp->eeprom_reg = EEPROM_REG_PRO;
+ spin_lock_init(&lp->lock);
+
+ /* Now, get the ethernet hardware address from
+ the EEPROM */
+ station_addr[0] = read_eeprom(ioaddr, 2, dev);
+
+ /* FIXME - find another way to know that we've found
+ * an Etherexpress 10
+ */
+ if (station_addr[0] == 0x0000 || station_addr[0] == 0xffff) {
+ lp->eepro = LAN595FX_10ISA;
+ lp->eeprom_reg = EEPROM_REG_10;
+ lp->xmt_lower_limit_reg = XMT_LOWER_LIMIT_REG_10;
+ lp->xmt_upper_limit_reg = XMT_UPPER_LIMIT_REG_10;
+ lp->xmt_bar = XMT_BAR_10;
+ station_addr[0] = read_eeprom(ioaddr, 2, dev);
+ }
+
+ /* get all words at once. will be used here and for ethtool */
+ for (i = 0; i < 8; i++) {
+ lp->word[i] = read_eeprom(ioaddr, i, dev);
+ }
+ station_addr[1] = lp->word[3];
+ station_addr[2] = lp->word[4];
+
+ if (!lp->eepro) {
+ if (lp->word[7] == ee_FX_INT2IRQ)
+ lp->eepro = 2;
+ else if (station_addr[2] == SA_ADDR1)
+ lp->eepro = 1;
+ }
+
+ /* Fill in the 'dev' fields. */
+ for (i=0; i < 6; i++)
+ dev->dev_addr[i] = ((unsigned char *) station_addr)[5-i];
+
+ /* RX buffer must be more than 3K and less than 29K */
+ if (dev->mem_end < 3072 || dev->mem_end > 29696)
+ lp->rcv_ram = RCV_DEFAULT_RAM;
+
+ /* calculate {xmt,rcv}_{lower,upper}_limit */
+ eepro_recalc(dev);
+
+ if (GetBit(lp->word[5], ee_BNC_TPE))
+ dev->if_port = BNC;
+ else
+ dev->if_port = TPE;
+
+ if (dev->irq < 2 && lp->eepro != 0) {
+ /* Mask off INT number */
+ int count = lp->word[1] & 7;
+ unsigned irqMask = lp->word[7];
+
+ while (count--)
+ irqMask &= irqMask - 1;
+
+ count = ffs(irqMask);
+
+ if (count)
+ dev->irq = count - 1;
+
+ if (dev->irq < 2) {
+ printk(KERN_ERR " Duh! illegal interrupt vector stored in EEPROM.\n");
+ goto exit;
+ } else if (dev->irq == 2) {
+ dev->irq = 9;
+ }
+ }
+
+ dev->netdev_ops = &eepro_netdev_ops;
+ dev->watchdog_timeo = TX_TIMEOUT;
+ dev->ethtool_ops = &eepro_ethtool_ops;
+
+ /* print boot time info */
+ eepro_print_info(dev);
+
+ /* reset 82595 */
+ eepro_reset(ioaddr);
+
+ err = register_netdev(dev);
+ if (err)
+ goto err;
+ return 0;
+exit:
+ err = -ENODEV;
+err:
+ release_region(dev->base_addr, EEPRO_IO_EXTENT);
+ return err;
+}
+
+/* Open/initialize the board. This is called (in the current kernel)
+ sometime after booting when the 'ifconfig' program is run.
+
+ This routine should set everything up anew at each open, even
+ registers that "should" only need to be set once at boot, so that
+ there is non-reboot way to recover if something goes wrong.
+ */
+
+static const char irqrmap[] = {-1,-1,0,1,-1,2,-1,-1,-1,0,3,4,-1,-1,-1,-1};
+static const char irqrmap2[] = {-1,-1,4,0,1,2,-1,3,-1,4,5,6,7,-1,-1,-1};
+static int eepro_grab_irq(struct net_device *dev)
+{
+ static const int irqlist[] = { 3, 4, 5, 7, 9, 10, 11, 12, 0 };
+ const int *irqp = irqlist;
+ int temp_reg, ioaddr = dev->base_addr;
+
+ eepro_sw2bank1(ioaddr); /* be CAREFUL, BANK 1 now */
+
+ /* Enable the interrupt line. */
+ eepro_en_intline(ioaddr);
+
+ /* be CAREFUL, BANK 0 now */
+ eepro_sw2bank0(ioaddr);
+
+ /* clear all interrupts */
+ eepro_clear_int(ioaddr);
+
+ /* Let EXEC event to interrupt */
+ eepro_en_intexec(ioaddr);
+
+ do {
+ eepro_sw2bank1(ioaddr); /* be CAREFUL, BANK 1 now */
+
+ temp_reg = inb(ioaddr + INT_NO_REG);
+ outb((temp_reg & 0xf8) | irqrmap[*irqp], ioaddr + INT_NO_REG);
+
+ eepro_sw2bank0(ioaddr); /* Switch back to Bank 0 */
+
+ if (request_irq (*irqp, NULL, IRQF_SHARED, "bogus", dev) != EBUSY) {
+ unsigned long irq_mask;
+ /* Twinkle the interrupt, and check if it's seen */
+ irq_mask = probe_irq_on();
+
+ eepro_diag(ioaddr); /* RESET the 82595 */
+ mdelay(20);
+
+ if (*irqp == probe_irq_off(irq_mask)) /* It's a good IRQ line */
+ break;
+
+ /* clear all interrupts */
+ eepro_clear_int(ioaddr);
+ }
+ } while (*++irqp);
+
+ eepro_sw2bank1(ioaddr); /* Switch back to Bank 1 */
+
+ /* Disable the physical interrupt line. */
+ eepro_dis_intline(ioaddr);
+
+ eepro_sw2bank0(ioaddr); /* Switch back to Bank 0 */
+
+ /* Mask all the interrupts. */
+ eepro_dis_int(ioaddr);
+
+ /* clear all interrupts */
+ eepro_clear_int(ioaddr);
+
+ return dev->irq;
+}
+
+static int eepro_open(struct net_device *dev)
+{
+ unsigned short temp_reg, old8, old9;
+ int irqMask;
+ int i, ioaddr = dev->base_addr;
+ struct eepro_local *lp = netdev_priv(dev);
+
+ if (net_debug > 3)
+ printk(KERN_DEBUG "%s: entering eepro_open routine.\n", dev->name);
+
+ irqMask = lp->word[7];
+
+ if (lp->eepro == LAN595FX_10ISA) {
+ if (net_debug > 3) printk(KERN_DEBUG "p->eepro = 3;\n");
+ }
+ else if (irqMask == ee_FX_INT2IRQ) /* INT to IRQ Mask */
+ {
+ lp->eepro = 2; /* Yes, an Intel EtherExpress Pro/10+ */
+ if (net_debug > 3) printk(KERN_DEBUG "p->eepro = 2;\n");
+ }
+
+ else if ((dev->dev_addr[0] == SA_ADDR0 &&
+ dev->dev_addr[1] == SA_ADDR1 &&
+ dev->dev_addr[2] == SA_ADDR2))
+ {
+ lp->eepro = 1;
+ if (net_debug > 3) printk(KERN_DEBUG "p->eepro = 1;\n");
+ } /* Yes, an Intel EtherExpress Pro/10 */
+
+ else lp->eepro = 0; /* No, it is a generic 82585 lan card */
+
+ /* Get the interrupt vector for the 82595 */
+ if (dev->irq < 2 && eepro_grab_irq(dev) == 0) {
+ printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, dev->irq);
+ return -EAGAIN;
+ }
+
+ if (request_irq(dev->irq , eepro_interrupt, 0, dev->name, dev)) {
+ printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, dev->irq);
+ return -EAGAIN;
+ }
+
+ /* Initialize the 82595. */
+
+ eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */
+ temp_reg = inb(ioaddr + lp->eeprom_reg);
+
+ lp->stepping = temp_reg >> 5; /* Get the stepping number of the 595 */
+
+ if (net_debug > 3)
+ printk(KERN_DEBUG "The stepping of the 82595 is %d\n", lp->stepping);
+
+ if (temp_reg & 0x10) /* Check the TurnOff Enable bit */
+ outb(temp_reg & 0xef, ioaddr + lp->eeprom_reg);
+ for (i=0; i < 6; i++)
+ outb(dev->dev_addr[i] , ioaddr + I_ADD_REG0 + i);
+
+ temp_reg = inb(ioaddr + REG1); /* Setup Transmit Chaining */
+ outb(temp_reg | XMT_Chain_Int | XMT_Chain_ErrStop /* and discard bad RCV frames */
+ | RCV_Discard_BadFrame, ioaddr + REG1);
+
+ temp_reg = inb(ioaddr + REG2); /* Match broadcast */
+ outb(temp_reg | 0x14, ioaddr + REG2);
+
+ temp_reg = inb(ioaddr + REG3);
+ outb(temp_reg & 0x3f, ioaddr + REG3); /* clear test mode */
+
+ /* Set the receiving mode */
+ eepro_sw2bank1(ioaddr); /* be CAREFUL, BANK 1 now */
+
+ /* Set the interrupt vector */
+ temp_reg = inb(ioaddr + INT_NO_REG);
+ if (lp->eepro == LAN595FX || lp->eepro == LAN595FX_10ISA)
+ outb((temp_reg & 0xf8) | irqrmap2[dev->irq], ioaddr + INT_NO_REG);
+ else outb((temp_reg & 0xf8) | irqrmap[dev->irq], ioaddr + INT_NO_REG);
+
+
+ temp_reg = inb(ioaddr + INT_NO_REG);
+ if (lp->eepro == LAN595FX || lp->eepro == LAN595FX_10ISA)
+ outb((temp_reg & 0xf0) | irqrmap2[dev->irq] | 0x08,ioaddr+INT_NO_REG);
+ else outb((temp_reg & 0xf8) | irqrmap[dev->irq], ioaddr + INT_NO_REG);
+
+ if (net_debug > 3)
+ printk(KERN_DEBUG "eepro_open: content of INT Reg is %x\n", temp_reg);
+
+
+ /* Initialize the RCV and XMT upper and lower limits */
+ outb(lp->rcv_lower_limit >> 8, ioaddr + RCV_LOWER_LIMIT_REG);
+ outb(lp->rcv_upper_limit >> 8, ioaddr + RCV_UPPER_LIMIT_REG);
+ outb(lp->xmt_lower_limit >> 8, ioaddr + lp->xmt_lower_limit_reg);
+ outb(lp->xmt_upper_limit >> 8, ioaddr + lp->xmt_upper_limit_reg);
+
+ /* Enable the interrupt line. */
+ eepro_en_intline(ioaddr);
+
+ /* Switch back to Bank 0 */
+ eepro_sw2bank0(ioaddr);
+
+ /* Let RX and TX events to interrupt */
+ eepro_en_int(ioaddr);
+
+ /* clear all interrupts */
+ eepro_clear_int(ioaddr);
+
+ /* Initialize RCV */
+ outw(lp->rcv_lower_limit, ioaddr + RCV_BAR);
+ lp->rx_start = lp->rcv_lower_limit;
+ outw(lp->rcv_upper_limit | 0xfe, ioaddr + RCV_STOP);
+
+ /* Initialize XMT */
+ outw(lp->xmt_lower_limit, ioaddr + lp->xmt_bar);
+ lp->tx_start = lp->tx_end = lp->xmt_lower_limit;
+ lp->tx_last = 0;
+
+ /* Check for the i82595TX and i82595FX */
+ old8 = inb(ioaddr + 8);
+ outb(~old8, ioaddr + 8);
+
+ if ((temp_reg = inb(ioaddr + 8)) == old8) {
+ if (net_debug > 3)
+ printk(KERN_DEBUG "i82595 detected!\n");
+ lp->version = LAN595;
+ }
+ else {
+ lp->version = LAN595TX;
+ outb(old8, ioaddr + 8);
+ old9 = inb(ioaddr + 9);
+
+ if (irqMask==ee_FX_INT2IRQ) {
+ if (net_debug > 3) {
+ printk(KERN_DEBUG "IrqMask: %#x\n",irqMask);
+ printk(KERN_DEBUG "i82595FX detected!\n");
+ }
+ lp->version = LAN595FX;
+ outb(old9, ioaddr + 9);
+ if (dev->if_port != TPE) { /* Hopefully, this will fix the
+ problem of using Pentiums and
+ pro/10 w/ BNC. */
+ eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */
+ temp_reg = inb(ioaddr + REG13);
+ /* disable the full duplex mode since it is not
+ applicable with the 10Base2 cable. */
+ outb(temp_reg & ~(FDX | A_N_ENABLE), REG13);
+ eepro_sw2bank0(ioaddr); /* be CAREFUL, BANK 0 now */
+ }
+ }
+ else if (net_debug > 3) {
+ printk(KERN_DEBUG "temp_reg: %#x ~old9: %#x\n",temp_reg,((~old9)&0xff));
+ printk(KERN_DEBUG "i82595TX detected!\n");
+ }
+ }
+
+ eepro_sel_reset(ioaddr);
+
+ netif_start_queue(dev);
+
+ if (net_debug > 3)
+ printk(KERN_DEBUG "%s: exiting eepro_open routine.\n", dev->name);
+
+ /* enabling rx */
+ eepro_en_rx(ioaddr);
+
+ return 0;
+}
+
+static void eepro_tx_timeout (struct net_device *dev)
+{
+ struct eepro_local *lp = netdev_priv(dev);
+ int ioaddr = dev->base_addr;
+
+ /* if (net_debug > 1) */
+ printk (KERN_ERR "%s: transmit timed out, %s?\n", dev->name,
+ "network cable problem");
+ /* This is not a duplicate. One message for the console,
+ one for the log file */
+ printk (KERN_DEBUG "%s: transmit timed out, %s?\n", dev->name,
+ "network cable problem");
+ eepro_complete_selreset(ioaddr);
+}
+
+
+static netdev_tx_t eepro_send_packet(struct sk_buff *skb,
+ struct net_device *dev)
+{
+ struct eepro_local *lp = netdev_priv(dev);
+ unsigned long flags;
+ int ioaddr = dev->base_addr;
+ short length = skb->len;
+
+ if (net_debug > 5)
+ printk(KERN_DEBUG "%s: entering eepro_send_packet routine.\n", dev->name);
+
+ if (length < ETH_ZLEN) {
+ if (skb_padto(skb, ETH_ZLEN))
+ return NETDEV_TX_OK;
+ length = ETH_ZLEN;
+ }
+ netif_stop_queue (dev);
+
+ eepro_dis_int(ioaddr);
+ spin_lock_irqsave(&lp->lock, flags);
+
+ {
+ unsigned char *buf = skb->data;
+
+ if (hardware_send_packet(dev, buf, length))
+ /* we won't wake queue here because we're out of space */
+ dev->stats.tx_dropped++;
+ else {
+ dev->stats.tx_bytes+=skb->len;
+ netif_wake_queue(dev);
+ }
+
+ }
+
+ dev_kfree_skb (skb);
+
+ /* You might need to clean up and record Tx statistics here. */
+ /* dev->stats.tx_aborted_errors++; */
+
+ if (net_debug > 5)
+ printk(KERN_DEBUG "%s: exiting eepro_send_packet routine.\n", dev->name);
+
+ eepro_en_int(ioaddr);
+ spin_unlock_irqrestore(&lp->lock, flags);
+
+ return NETDEV_TX_OK;
+}
+
+
+/* The typical workload of the driver:
+ Handle the network interface interrupts. */
+
+static irqreturn_t
+eepro_interrupt(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct eepro_local *lp;
+ int ioaddr, status, boguscount = 20;
+ int handled = 0;
+
+ lp = netdev_priv(dev);
+
+ spin_lock(&lp->lock);
+
+ if (net_debug > 5)
+ printk(KERN_DEBUG "%s: entering eepro_interrupt routine.\n", dev->name);
+
+ ioaddr = dev->base_addr;
+
+ while (((status = inb(ioaddr + STATUS_REG)) & (RX_INT|TX_INT)) && (boguscount--))
+ {
+ handled = 1;
+ if (status & RX_INT) {
+ if (net_debug > 4)
+ printk(KERN_DEBUG "%s: packet received interrupt.\n", dev->name);
+
+ eepro_dis_int(ioaddr);
+
+ /* Get the received packets */
+ eepro_ack_rx(ioaddr);
+ eepro_rx(dev);
+
+ eepro_en_int(ioaddr);
+ }
+ if (status & TX_INT) {
+ if (net_debug > 4)
+ printk(KERN_DEBUG "%s: packet transmit interrupt.\n", dev->name);
+
+
+ eepro_dis_int(ioaddr);
+
+ /* Process the status of transmitted packets */
+ eepro_ack_tx(ioaddr);
+ eepro_transmit_interrupt(dev);
+
+ eepro_en_int(ioaddr);
+ }
+ }
+
+ if (net_debug > 5)
+ printk(KERN_DEBUG "%s: exiting eepro_interrupt routine.\n", dev->name);
+
+ spin_unlock(&lp->lock);
+ return IRQ_RETVAL(handled);
+}
+
+static int eepro_close(struct net_device *dev)
+{
+ struct eepro_local *lp = netdev_priv(dev);
+ int ioaddr = dev->base_addr;
+ short temp_reg;
+
+ netif_stop_queue(dev);
+
+ eepro_sw2bank1(ioaddr); /* Switch back to Bank 1 */
+
+ /* Disable the physical interrupt line. */
+ temp_reg = inb(ioaddr + REG1);
+ outb(temp_reg & 0x7f, ioaddr + REG1);
+
+ eepro_sw2bank0(ioaddr); /* Switch back to Bank 0 */
+
+ /* Flush the Tx and disable Rx. */
+ outb(STOP_RCV_CMD, ioaddr);
+ lp->tx_start = lp->tx_end = lp->xmt_lower_limit;
+ lp->tx_last = 0;
+
+ /* Mask all the interrupts. */
+ eepro_dis_int(ioaddr);
+
+ /* clear all interrupts */
+ eepro_clear_int(ioaddr);
+
+ /* Reset the 82595 */
+ eepro_reset(ioaddr);
+
+ /* release the interrupt */
+ free_irq(dev->irq, dev);
+
+ /* Update the statistics here. What statistics? */
+
+ return 0;
+}
+
+/* Set or clear the multicast filter for this adaptor.
+ */
+static void
+set_multicast_list(struct net_device *dev)
+{
+ struct eepro_local *lp = netdev_priv(dev);
+ short ioaddr = dev->base_addr;
+ unsigned short mode;
+ struct netdev_hw_addr *ha;
+ int mc_count = netdev_mc_count(dev);
+
+ if (dev->flags&(IFF_ALLMULTI|IFF_PROMISC) || mc_count > 63)
+ {
+ eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */
+ mode = inb(ioaddr + REG2);
+ outb(mode | PRMSC_Mode, ioaddr + REG2);
+ mode = inb(ioaddr + REG3);
+ outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */
+ eepro_sw2bank0(ioaddr); /* Return to BANK 0 now */
+ }
+
+ else if (mc_count == 0)
+ {
+ eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */
+ mode = inb(ioaddr + REG2);
+ outb(mode & 0xd6, ioaddr + REG2); /* Turn off Multi-IA and PRMSC_Mode bits */
+ mode = inb(ioaddr + REG3);
+ outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */
+ eepro_sw2bank0(ioaddr); /* Return to BANK 0 now */
+ }
+
+ else
+ {
+ unsigned short status, *eaddrs;
+ int i, boguscount = 0;
+
+ /* Disable RX and TX interrupts. Necessary to avoid
+ corruption of the HOST_ADDRESS_REG by interrupt
+ service routines. */
+ eepro_dis_int(ioaddr);
+
+ eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */
+ mode = inb(ioaddr + REG2);
+ outb(mode | Multi_IA, ioaddr + REG2);
+ mode = inb(ioaddr + REG3);
+ outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */
+ eepro_sw2bank0(ioaddr); /* Return to BANK 0 now */
+ outw(lp->tx_end, ioaddr + HOST_ADDRESS_REG);
+ outw(MC_SETUP, ioaddr + IO_PORT);
+ outw(0, ioaddr + IO_PORT);
+ outw(0, ioaddr + IO_PORT);
+ outw(6 * (mc_count + 1), ioaddr + IO_PORT);
+
+ netdev_for_each_mc_addr(ha, dev) {
+ eaddrs = (unsigned short *) ha->addr;
+ outw(*eaddrs++, ioaddr + IO_PORT);
+ outw(*eaddrs++, ioaddr + IO_PORT);
+ outw(*eaddrs++, ioaddr + IO_PORT);
+ }
+
+ eaddrs = (unsigned short *) dev->dev_addr;
+ outw(eaddrs[0], ioaddr + IO_PORT);
+ outw(eaddrs[1], ioaddr + IO_PORT);
+ outw(eaddrs[2], ioaddr + IO_PORT);
+ outw(lp->tx_end, ioaddr + lp->xmt_bar);
+ outb(MC_SETUP, ioaddr);
+
+ /* Update the transmit queue */
+ i = lp->tx_end + XMT_HEADER + 6 * (mc_count + 1);
+
+ if (lp->tx_start != lp->tx_end)
+ {
+ /* update the next address and the chain bit in the
+ last packet */
+ outw(lp->tx_last + XMT_CHAIN, ioaddr + HOST_ADDRESS_REG);
+ outw(i, ioaddr + IO_PORT);
+ outw(lp->tx_last + XMT_COUNT, ioaddr + HOST_ADDRESS_REG);
+ status = inw(ioaddr + IO_PORT);
+ outw(status | CHAIN_BIT, ioaddr + IO_PORT);
+ lp->tx_end = i ;
+ }
+ else {
+ lp->tx_start = lp->tx_end = i ;
+ }
+
+ /* Acknowledge that the MC setup is done */
+ do { /* We should be doing this in the eepro_interrupt()! */
+ SLOW_DOWN;
+ SLOW_DOWN;
+ if (inb(ioaddr + STATUS_REG) & 0x08)
+ {
+ i = inb(ioaddr);
+ outb(0x08, ioaddr + STATUS_REG);
+
+ if (i & 0x20) { /* command ABORTed */
+ printk(KERN_NOTICE "%s: multicast setup failed.\n",
+ dev->name);
+ break;
+ } else if ((i & 0x0f) == 0x03) { /* MC-Done */
+ printk(KERN_DEBUG "%s: set Rx mode to %d address%s.\n",
+ dev->name, mc_count,
+ mc_count > 1 ? "es":"");
+ break;
+ }
+ }
+ } while (++boguscount < 100);
+
+ /* Re-enable RX and TX interrupts */
+ eepro_en_int(ioaddr);
+ }
+ if (lp->eepro == LAN595FX_10ISA) {
+ eepro_complete_selreset(ioaddr);
+ }
+ else
+ eepro_en_rx(ioaddr);
+}
+
+/* The horrible routine to read a word from the serial EEPROM. */
+/* IMPORTANT - the 82595 will be set to Bank 0 after the eeprom is read */
+
+/* The delay between EEPROM clock transitions. */
+#define eeprom_delay() { udelay(40); }
+#define EE_READ_CMD (6 << 6)
+
+static int
+read_eeprom(int ioaddr, int location, struct net_device *dev)
+{
+ int i;
+ unsigned short retval = 0;
+ struct eepro_local *lp = netdev_priv(dev);
+ short ee_addr = ioaddr + lp->eeprom_reg;
+ int read_cmd = location | EE_READ_CMD;
+ short ctrl_val = EECS ;
+
+ /* XXXX - black magic */
+ eepro_sw2bank1(ioaddr);
+ outb(0x00, ioaddr + STATUS_REG);
+ /* XXXX - black magic */
+
+ eepro_sw2bank2(ioaddr);
+ outb(ctrl_val, ee_addr);
+
+ /* Shift the read command bits out. */
+ for (i = 8; i >= 0; i--) {
+ short outval = (read_cmd & (1 << i)) ? ctrl_val | EEDI
+ : ctrl_val;
+ outb(outval, ee_addr);
+ outb(outval | EESK, ee_addr); /* EEPROM clock tick. */
+ eeprom_delay();
+ outb(outval, ee_addr); /* Finish EEPROM a clock tick. */
+ eeprom_delay();
+ }
+ outb(ctrl_val, ee_addr);
+
+ for (i = 16; i > 0; i--) {
+ outb(ctrl_val | EESK, ee_addr); eeprom_delay();
+ retval = (retval << 1) | ((inb(ee_addr) & EEDO) ? 1 : 0);
+ outb(ctrl_val, ee_addr); eeprom_delay();
+ }
+
+ /* Terminate the EEPROM access. */
+ ctrl_val &= ~EECS;
+ outb(ctrl_val | EESK, ee_addr);
+ eeprom_delay();
+ outb(ctrl_val, ee_addr);
+ eeprom_delay();
+ eepro_sw2bank0(ioaddr);
+ return retval;
+}
+
+static int
+hardware_send_packet(struct net_device *dev, void *buf, short length)
+{
+ struct eepro_local *lp = netdev_priv(dev);
+ short ioaddr = dev->base_addr;
+ unsigned status, tx_available, last, end;
+
+ if (net_debug > 5)
+ printk(KERN_DEBUG "%s: entering hardware_send_packet routine.\n", dev->name);
+
+ /* determine how much of the transmit buffer space is available */
+ if (lp->tx_end > lp->tx_start)
+ tx_available = lp->xmt_ram - (lp->tx_end - lp->tx_start);
+ else if (lp->tx_end < lp->tx_start)
+ tx_available = lp->tx_start - lp->tx_end;
+ else tx_available = lp->xmt_ram;
+
+ if (((((length + 3) >> 1) << 1) + 2*XMT_HEADER) >= tx_available) {
+ /* No space available ??? */
+ return 1;
+ }
+
+ last = lp->tx_end;
+ end = last + (((length + 3) >> 1) << 1) + XMT_HEADER;
+
+ if (end >= lp->xmt_upper_limit + 2) { /* the transmit buffer is wrapped around */
+ if ((lp->xmt_upper_limit + 2 - last) <= XMT_HEADER) {
+ /* Arrrr!!!, must keep the xmt header together,
+ several days were lost to chase this one down. */
+ last = lp->xmt_lower_limit;
+ end = last + (((length + 3) >> 1) << 1) + XMT_HEADER;
+ }
+ else end = lp->xmt_lower_limit + (end -
+ lp->xmt_upper_limit + 2);
+ }
+
+ outw(last, ioaddr + HOST_ADDRESS_REG);
+ outw(XMT_CMD, ioaddr + IO_PORT);
+ outw(0, ioaddr + IO_PORT);
+ outw(end, ioaddr + IO_PORT);
+ outw(length, ioaddr + IO_PORT);
+
+ if (lp->version == LAN595)
+ outsw(ioaddr + IO_PORT, buf, (length + 3) >> 1);
+ else { /* LAN595TX or LAN595FX, capable of 32-bit I/O processing */
+ unsigned short temp = inb(ioaddr + INT_MASK_REG);
+ outb(temp | IO_32_BIT, ioaddr + INT_MASK_REG);
+ outsl(ioaddr + IO_PORT_32_BIT, buf, (length + 3) >> 2);
+ outb(temp & ~(IO_32_BIT), ioaddr + INT_MASK_REG);
+ }
+
+ /* A dummy read to flush the DRAM write pipeline */
+ status = inw(ioaddr + IO_PORT);
+
+ if (lp->tx_start == lp->tx_end) {
+ outw(last, ioaddr + lp->xmt_bar);
+ outb(XMT_CMD, ioaddr);
+ lp->tx_start = last; /* I don't like to change tx_start here */
+ }
+ else {
+ /* update the next address and the chain bit in the
+ last packet */
+
+ if (lp->tx_end != last) {
+ outw(lp->tx_last + XMT_CHAIN, ioaddr + HOST_ADDRESS_REG);
+ outw(last, ioaddr + IO_PORT);
+ }
+
+ outw(lp->tx_last + XMT_COUNT, ioaddr + HOST_ADDRESS_REG);
+ status = inw(ioaddr + IO_PORT);
+ outw(status | CHAIN_BIT, ioaddr + IO_PORT);
+
+ /* Continue the transmit command */
+ outb(RESUME_XMT_CMD, ioaddr);
+ }
+
+ lp->tx_last = last;
+ lp->tx_end = end;
+
+ if (net_debug > 5)
+ printk(KERN_DEBUG "%s: exiting hardware_send_packet routine.\n", dev->name);
+
+ return 0;
+}
+
+static void
+eepro_rx(struct net_device *dev)
+{
+ struct eepro_local *lp = netdev_priv(dev);
+ short ioaddr = dev->base_addr;
+ short boguscount = 20;
+ short rcv_car = lp->rx_start;
+ unsigned rcv_event, rcv_status, rcv_next_frame, rcv_size;
+
+ if (net_debug > 5)
+ printk(KERN_DEBUG "%s: entering eepro_rx routine.\n", dev->name);
+
+ /* Set the read pointer to the start of the RCV */
+ outw(rcv_car, ioaddr + HOST_ADDRESS_REG);
+
+ rcv_event = inw(ioaddr + IO_PORT);
+
+ while (rcv_event == RCV_DONE) {
+
+ rcv_status = inw(ioaddr + IO_PORT);
+ rcv_next_frame = inw(ioaddr + IO_PORT);
+ rcv_size = inw(ioaddr + IO_PORT);
+
+ if ((rcv_status & (RX_OK | RX_ERROR)) == RX_OK) {
+
+ /* Malloc up new buffer. */
+ struct sk_buff *skb;
+
+ dev->stats.rx_bytes+=rcv_size;
+ rcv_size &= 0x3fff;
+ skb = dev_alloc_skb(rcv_size+5);
+ if (skb == NULL) {
+ printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
+ dev->stats.rx_dropped++;
+ rcv_car = lp->rx_start + RCV_HEADER + rcv_size;
+ lp->rx_start = rcv_next_frame;
+ outw(rcv_next_frame, ioaddr + HOST_ADDRESS_REG);
+
+ break;
+ }
+ skb_reserve(skb,2);
+
+ if (lp->version == LAN595)
+ insw(ioaddr+IO_PORT, skb_put(skb,rcv_size), (rcv_size + 3) >> 1);
+ else { /* LAN595TX or LAN595FX, capable of 32-bit I/O processing */
+ unsigned short temp = inb(ioaddr + INT_MASK_REG);
+ outb(temp | IO_32_BIT, ioaddr + INT_MASK_REG);
+ insl(ioaddr+IO_PORT_32_BIT, skb_put(skb,rcv_size),
+ (rcv_size + 3) >> 2);
+ outb(temp & ~(IO_32_BIT), ioaddr + INT_MASK_REG);
+ }
+
+ skb->protocol = eth_type_trans(skb,dev);
+ netif_rx(skb);
+ dev->stats.rx_packets++;
+ }
+
+ else { /* Not sure will ever reach here,
+ I set the 595 to discard bad received frames */
+ dev->stats.rx_errors++;
+
+ if (rcv_status & 0x0100)
+ dev->stats.rx_over_errors++;
+
+ else if (rcv_status & 0x0400)
+ dev->stats.rx_frame_errors++;
+
+ else if (rcv_status & 0x0800)
+ dev->stats.rx_crc_errors++;
+
+ printk(KERN_DEBUG "%s: event = %#x, status = %#x, next = %#x, size = %#x\n",
+ dev->name, rcv_event, rcv_status, rcv_next_frame, rcv_size);
+ }
+
+ if (rcv_status & 0x1000)
+ dev->stats.rx_length_errors++;
+
+ rcv_car = lp->rx_start + RCV_HEADER + rcv_size;
+ lp->rx_start = rcv_next_frame;
+
+ if (--boguscount == 0)
+ break;
+
+ outw(rcv_next_frame, ioaddr + HOST_ADDRESS_REG);
+ rcv_event = inw(ioaddr + IO_PORT);
+
+ }
+ if (rcv_car == 0)
+ rcv_car = lp->rcv_upper_limit | 0xff;
+
+ outw(rcv_car - 1, ioaddr + RCV_STOP);
+
+ if (net_debug > 5)
+ printk(KERN_DEBUG "%s: exiting eepro_rx routine.\n", dev->name);
+}
+
+static void
+eepro_transmit_interrupt(struct net_device *dev)
+{
+ struct eepro_local *lp = netdev_priv(dev);
+ short ioaddr = dev->base_addr;
+ short boguscount = 25;
+ short xmt_status;
+
+ while ((lp->tx_start != lp->tx_end) && boguscount--) {
+
+ outw(lp->tx_start, ioaddr + HOST_ADDRESS_REG);
+ xmt_status = inw(ioaddr+IO_PORT);
+
+ if (!(xmt_status & TX_DONE_BIT))
+ break;
+
+ xmt_status = inw(ioaddr+IO_PORT);
+ lp->tx_start = inw(ioaddr+IO_PORT);
+
+ netif_wake_queue (dev);
+
+ if (xmt_status & TX_OK)
+ dev->stats.tx_packets++;
+ else {
+ dev->stats.tx_errors++;
+ if (xmt_status & 0x0400) {
+ dev->stats.tx_carrier_errors++;
+ printk(KERN_DEBUG "%s: carrier error\n",
+ dev->name);
+ printk(KERN_DEBUG "%s: XMT status = %#x\n",
+ dev->name, xmt_status);
+ }
+ else {
+ printk(KERN_DEBUG "%s: XMT status = %#x\n",
+ dev->name, xmt_status);
+ printk(KERN_DEBUG "%s: XMT status = %#x\n",
+ dev->name, xmt_status);
+ }
+ }
+ if (xmt_status & 0x000f) {
+ dev->stats.collisions += (xmt_status & 0x000f);
+ }
+
+ if ((xmt_status & 0x0040) == 0x0) {
+ dev->stats.tx_heartbeat_errors++;
+ }
+ }
+}
+
+static int eepro_ethtool_get_settings(struct net_device *dev,
+ struct ethtool_cmd *cmd)
+{
+ struct eepro_local *lp = netdev_priv(dev);
+
+ cmd->supported = SUPPORTED_10baseT_Half |
+ SUPPORTED_10baseT_Full |
+ SUPPORTED_Autoneg;
+ cmd->advertising = ADVERTISED_10baseT_Half |
+ ADVERTISED_10baseT_Full |
+ ADVERTISED_Autoneg;
+
+ if (GetBit(lp->word[5], ee_PortTPE)) {
+ cmd->supported |= SUPPORTED_TP;
+ cmd->advertising |= ADVERTISED_TP;
+ }
+ if (GetBit(lp->word[5], ee_PortBNC)) {
+ cmd->supported |= SUPPORTED_BNC;
+ cmd->advertising |= ADVERTISED_BNC;
+ }
+ if (GetBit(lp->word[5], ee_PortAUI)) {
+ cmd->supported |= SUPPORTED_AUI;
+ cmd->advertising |= ADVERTISED_AUI;
+ }
+
+ ethtool_cmd_speed_set(cmd, SPEED_10);
+
+ if (dev->if_port == TPE && lp->word[1] & ee_Duplex) {
+ cmd->duplex = DUPLEX_FULL;
+ }
+ else {
+ cmd->duplex = DUPLEX_HALF;
+ }
+
+ cmd->port = dev->if_port;
+ cmd->phy_address = dev->base_addr;
+ cmd->transceiver = XCVR_INTERNAL;
+
+ if (lp->word[0] & ee_AutoNeg) {
+ cmd->autoneg = 1;
+ }
+
+ return 0;
+}
+
+static void eepro_ethtool_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *drvinfo)
+{
+ strcpy(drvinfo->driver, DRV_NAME);
+ strcpy(drvinfo->version, DRV_VERSION);
+ sprintf(drvinfo->bus_info, "ISA 0x%lx", dev->base_addr);
+}
+
+static const struct ethtool_ops eepro_ethtool_ops = {
+ .get_settings = eepro_ethtool_get_settings,
+ .get_drvinfo = eepro_ethtool_get_drvinfo,
+};
+
+#ifdef MODULE
+
+#define MAX_EEPRO 8
+static struct net_device *dev_eepro[MAX_EEPRO];
+
+static int io[MAX_EEPRO] = {
+ [0 ... MAX_EEPRO-1] = -1
+};
+static int irq[MAX_EEPRO];
+static int mem[MAX_EEPRO] = { /* Size of the rx buffer in KB */
+ [0 ... MAX_EEPRO-1] = RCV_DEFAULT_RAM/1024
+};
+static int autodetect;
+
+static int n_eepro;
+/* For linux 2.1.xx */
+
+MODULE_AUTHOR("Pascal Dupuis and others");
+MODULE_DESCRIPTION("Intel i82595 ISA EtherExpressPro10/10+ driver");
+MODULE_LICENSE("GPL");
+
+module_param_array(io, int, NULL, 0);
+module_param_array(irq, int, NULL, 0);
+module_param_array(mem, int, NULL, 0);
+module_param(autodetect, int, 0);
+MODULE_PARM_DESC(io, "EtherExpress Pro/10 I/O base address(es)");
+MODULE_PARM_DESC(irq, "EtherExpress Pro/10 IRQ number(s)");
+MODULE_PARM_DESC(mem, "EtherExpress Pro/10 Rx buffer size(es) in kB (3-29)");
+MODULE_PARM_DESC(autodetect, "EtherExpress Pro/10 force board(s) detection (0-1)");
+
+int __init init_module(void)
+{
+ struct net_device *dev;
+ int i;
+ if (io[0] == -1 && autodetect == 0) {
+ printk(KERN_WARNING "eepro_init_module: Probe is very dangerous in ISA boards!\n");
+ printk(KERN_WARNING "eepro_init_module: Please add \"autodetect=1\" to force probe\n");
+ return -ENODEV;
+ }
+ else if (autodetect) {
+ /* if autodetect is set then we must force detection */
+ for (i = 0; i < MAX_EEPRO; i++) {
+ io[i] = 0;
+ }
+
+ printk(KERN_INFO "eepro_init_module: Auto-detecting boards (May God protect us...)\n");
+ }
+
+ for (i = 0; i < MAX_EEPRO && io[i] != -1; i++) {
+ dev = alloc_etherdev(sizeof(struct eepro_local));
+ if (!dev)
+ break;
+
+ dev->mem_end = mem[i];
+ dev->base_addr = io[i];
+ dev->irq = irq[i];
+
+ if (do_eepro_probe(dev) == 0) {
+ dev_eepro[n_eepro++] = dev;
+ continue;
+ }
+ free_netdev(dev);
+ break;
+ }
+
+ if (n_eepro)
+ printk(KERN_INFO "%s", version);
+
+ return n_eepro ? 0 : -ENODEV;
+}
+
+void __exit
+cleanup_module(void)
+{
+ int i;
+
+ for (i=0; i<n_eepro; i++) {
+ struct net_device *dev = dev_eepro[i];
+ unregister_netdev(dev);
+ release_region(dev->base_addr, EEPRO_IO_EXTENT);
+ free_netdev(dev);
+ }
+}
+#endif /* MODULE */
--- /dev/null
+/* Intel EtherExpress 16 device driver for Linux
+ *
+ * Written by John Sullivan, 1995
+ * based on original code by Donald Becker, with changes by
+ * Alan Cox and Pauline Middelink.
+ *
+ * Support for 8-bit mode by Zoltan Szilagyi <zoltans@cs.arizona.edu>
+ *
+ * Many modifications, and currently maintained, by
+ * Philip Blundell <philb@gnu.org>
+ * Added the Compaq LTE Alan Cox <alan@lxorguk.ukuu.org.uk>
+ * Added MCA support Adam Fritzler
+ *
+ * Note - this driver is experimental still - it has problems on faster
+ * machines. Someone needs to sit down and go through it line by line with
+ * a databook...
+ */
+
+/* The EtherExpress 16 is a fairly simple card, based on a shared-memory
+ * design using the i82586 Ethernet coprocessor. It bears no relationship,
+ * as far as I know, to the similarly-named "EtherExpress Pro" range.
+ *
+ * Historically, Linux support for these cards has been very bad. However,
+ * things seem to be getting better slowly.
+ */
+
+/* If your card is confused about what sort of interface it has (eg it
+ * persistently reports "10baseT" when none is fitted), running 'SOFTSET /BART'
+ * or 'SOFTSET /LISA' from DOS seems to help.
+ */
+
+/* Here's the scoop on memory mapping.
+ *
+ * There are three ways to access EtherExpress card memory: either using the
+ * shared-memory mapping, or using PIO through the dataport, or using PIO
+ * through the "shadow memory" ports.
+ *
+ * The shadow memory system works by having the card map some of its memory
+ * as follows:
+ *
+ * (the low five bits of the SMPTR are ignored)
+ *
+ * base+0x4000..400f memory at SMPTR+0..15
+ * base+0x8000..800f memory at SMPTR+16..31
+ * base+0xc000..c007 dubious stuff (memory at SMPTR+16..23 apparently)
+ * base+0xc008..c00f memory at 0x0008..0x000f
+ *
+ * This last set (the one at c008) is particularly handy because the SCB
+ * lives at 0x0008. So that set of ports gives us easy random access to data
+ * in the SCB without having to mess around setting up pointers and the like.
+ * We always use this method to access the SCB (via the scb_xx() functions).
+ *
+ * Dataport access works by aiming the appropriate (read or write) pointer
+ * at the first address you're interested in, and then reading or writing from
+ * the dataport. The pointers auto-increment after each transfer. We use
+ * this for data transfer.
+ *
+ * We don't use the shared-memory system because it allegedly doesn't work on
+ * all cards, and because it's a bit more prone to go wrong (it's one more
+ * thing to configure...).
+ */
+
+/* Known bugs:
+ *
+ * - The card seems to want to give us two interrupts every time something
+ * happens, where just one would be better.
+ */
+
+/*
+ *
+ * Note by Zoltan Szilagyi 10-12-96:
+ *
+ * I've succeeded in eliminating the "CU wedged" messages, and hence the
+ * lockups, which were only occurring with cards running in 8-bit mode ("force
+ * 8-bit operation" in Intel's SoftSet utility). This version of the driver
+ * sets the 82586 and the ASIC to 8-bit mode at startup; it also stops the
+ * CU before submitting a packet for transmission, and then restarts it as soon
+ * as the process of handing the packet is complete. This is definitely an
+ * unnecessary slowdown if the card is running in 16-bit mode; therefore one
+ * should detect 16-bit vs 8-bit mode from the EEPROM settings and act
+ * accordingly. In 8-bit mode with this bugfix I'm getting about 150 K/s for
+ * ftp's, which is significantly better than I get in DOS, so the overhead of
+ * stopping and restarting the CU with each transmit is not prohibitive in
+ * practice.
+ *
+ * Update by David Woodhouse 11/5/99:
+ *
+ * I've seen "CU wedged" messages in 16-bit mode, on the Alpha architecture.
+ * I assume that this is because 16-bit accesses are actually handled as two
+ * 8-bit accesses.
+ */
+
+#ifdef __alpha__
+#define LOCKUP16 1
+#endif
+#ifndef LOCKUP16
+#define LOCKUP16 0
+#endif
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/string.h>
+#include <linux/in.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/mca-legacy.h>
+#include <linux/spinlock.h>
+#include <linux/bitops.h>
+#include <linux/jiffies.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#ifndef NET_DEBUG
+#define NET_DEBUG 4
+#endif
+
+#include "eexpress.h"
+
+#define EEXP_IO_EXTENT 16
+
+/*
+ * Private data declarations
+ */
+
+struct net_local
+{
+ unsigned long last_tx; /* jiffies when last transmit started */
+ unsigned long init_time; /* jiffies when eexp_hw_init586 called */
+ unsigned short rx_first; /* first rx buf, same as RX_BUF_START */
+ unsigned short rx_last; /* last rx buf */
+ unsigned short rx_ptr; /* first rx buf to look at */
+ unsigned short tx_head; /* next free tx buf */
+ unsigned short tx_reap; /* first in-use tx buf */
+ unsigned short tx_tail; /* previous tx buf to tx_head */
+ unsigned short tx_link; /* last known-executing tx buf */
+ unsigned short last_tx_restart; /* set to tx_link when we
+ restart the CU */
+ unsigned char started;
+ unsigned short rx_buf_start;
+ unsigned short rx_buf_end;
+ unsigned short num_tx_bufs;
+ unsigned short num_rx_bufs;
+ unsigned char width; /* 0 for 16bit, 1 for 8bit */
+ unsigned char was_promisc;
+ unsigned char old_mc_count;
+ spinlock_t lock;
+};
+
+/* This is the code and data that is downloaded to the EtherExpress card's
+ * memory at boot time.
+ */
+
+static unsigned short start_code[] = {
+/* 0x0000 */
+ 0x0001, /* ISCP: busy - cleared after reset */
+ 0x0008,0x0000,0x0000, /* offset,address (lo,hi) of SCB */
+
+ 0x0000,0x0000, /* SCB: status, commands */
+ 0x0000,0x0000, /* links to first command block,
+ first receive descriptor */
+ 0x0000,0x0000, /* CRC error, alignment error counts */
+ 0x0000,0x0000, /* out of resources, overrun error counts */
+
+ 0x0000,0x0000, /* pad */
+ 0x0000,0x0000,
+
+/* 0x20 -- start of 82586 CU program */
+#define CONF_LINK 0x20
+ 0x0000,Cmd_Config,
+ 0x0032, /* link to next command */
+ 0x080c, /* 12 bytes follow : fifo threshold=8 */
+ 0x2e40, /* don't rx bad frames
+ * SRDY/ARDY => ext. sync. : preamble len=8
+ * take addresses from data buffers
+ * 6 bytes/address
+ */
+ 0x6000, /* default backoff method & priority
+ * interframe spacing = 0x60 */
+ 0xf200, /* slot time=0x200
+ * max collision retry = 0xf */
+#define CONF_PROMISC 0x2e
+ 0x0000, /* no HDLC : normal CRC : enable broadcast
+ * disable promiscuous/multicast modes */
+ 0x003c, /* minimum frame length = 60 octets) */
+
+ 0x0000,Cmd_SetAddr,
+ 0x003e, /* link to next command */
+#define CONF_HWADDR 0x38
+ 0x0000,0x0000,0x0000, /* hardware address placed here */
+
+ 0x0000,Cmd_MCast,
+ 0x0076, /* link to next command */
+#define CONF_NR_MULTICAST 0x44
+ 0x0000, /* number of bytes in multicast address(es) */
+#define CONF_MULTICAST 0x46
+ 0x0000, 0x0000, 0x0000, /* some addresses */
+ 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000,
+
+#define CONF_DIAG_RESULT 0x76
+ 0x0000, Cmd_Diag,
+ 0x007c, /* link to next command */
+
+ 0x0000,Cmd_TDR|Cmd_INT,
+ 0x0084,
+#define CONF_TDR_RESULT 0x82
+ 0x0000,
+
+ 0x0000,Cmd_END|Cmd_Nop, /* end of configure sequence */
+ 0x0084 /* dummy link */
+};
+
+/* maps irq number to EtherExpress magic value */
+static char irqrmap[] = { 0,0,1,2,3,4,0,0,0,1,5,6,0,0,0,0 };
+
+#ifdef CONFIG_MCA_LEGACY
+/* mapping of the first four bits of the second POS register */
+static unsigned short mca_iomap[] = {
+ 0x270, 0x260, 0x250, 0x240, 0x230, 0x220, 0x210, 0x200,
+ 0x370, 0x360, 0x350, 0x340, 0x330, 0x320, 0x310, 0x300
+};
+/* bits 5-7 of the second POS register */
+static char mca_irqmap[] = { 12, 9, 3, 4, 5, 10, 11, 15 };
+#endif
+
+/*
+ * Prototypes for Linux interface
+ */
+
+static int eexp_open(struct net_device *dev);
+static int eexp_close(struct net_device *dev);
+static void eexp_timeout(struct net_device *dev);
+static netdev_tx_t eexp_xmit(struct sk_buff *buf,
+ struct net_device *dev);
+
+static irqreturn_t eexp_irq(int irq, void *dev_addr);
+static void eexp_set_multicast(struct net_device *dev);
+
+/*
+ * Prototypes for hardware access functions
+ */
+
+static void eexp_hw_rx_pio(struct net_device *dev);
+static void eexp_hw_tx_pio(struct net_device *dev, unsigned short *buf,
+ unsigned short len);
+static int eexp_hw_probe(struct net_device *dev,unsigned short ioaddr);
+static unsigned short eexp_hw_readeeprom(unsigned short ioaddr,
+ unsigned char location);
+
+static unsigned short eexp_hw_lasttxstat(struct net_device *dev);
+static void eexp_hw_txrestart(struct net_device *dev);
+
+static void eexp_hw_txinit (struct net_device *dev);
+static void eexp_hw_rxinit (struct net_device *dev);
+
+static void eexp_hw_init586 (struct net_device *dev);
+static void eexp_setup_filter (struct net_device *dev);
+
+static char *eexp_ifmap[]={"AUI", "BNC", "RJ45"};
+enum eexp_iftype {AUI=0, BNC=1, TPE=2};
+
+#define STARTED_RU 2
+#define STARTED_CU 1
+
+/*
+ * Primitive hardware access functions.
+ */
+
+static inline unsigned short scb_status(struct net_device *dev)
+{
+ return inw(dev->base_addr + 0xc008);
+}
+
+static inline unsigned short scb_rdcmd(struct net_device *dev)
+{
+ return inw(dev->base_addr + 0xc00a);
+}
+
+static inline void scb_command(struct net_device *dev, unsigned short cmd)
+{
+ outw(cmd, dev->base_addr + 0xc00a);
+}
+
+static inline void scb_wrcbl(struct net_device *dev, unsigned short val)
+{
+ outw(val, dev->base_addr + 0xc00c);
+}
+
+static inline void scb_wrrfa(struct net_device *dev, unsigned short val)
+{
+ outw(val, dev->base_addr + 0xc00e);
+}
+
+static inline void set_loopback(struct net_device *dev)
+{
+ outb(inb(dev->base_addr + Config) | 2, dev->base_addr + Config);
+}
+
+static inline void clear_loopback(struct net_device *dev)
+{
+ outb(inb(dev->base_addr + Config) & ~2, dev->base_addr + Config);
+}
+
+static inline unsigned short int SHADOW(short int addr)
+{
+ addr &= 0x1f;
+ if (addr > 0xf) addr += 0x3ff0;
+ return addr + 0x4000;
+}
+
+/*
+ * Linux interface
+ */
+
+/*
+ * checks for presence of EtherExpress card
+ */
+
+static int __init do_express_probe(struct net_device *dev)
+{
+ unsigned short *port;
+ static unsigned short ports[] = { 0x240,0x300,0x310,0x270,0x320,0x340,0 };
+ unsigned short ioaddr = dev->base_addr;
+ int dev_irq = dev->irq;
+ int err;
+
+ dev->if_port = 0xff; /* not set */
+
+#ifdef CONFIG_MCA_LEGACY
+ if (MCA_bus) {
+ int slot = 0;
+
+ /*
+ * Only find one card at a time. Subsequent calls
+ * will find others, however, proper multicard MCA
+ * probing and setup can't be done with the
+ * old-style Space.c init routines. -- ASF
+ */
+ while (slot != MCA_NOTFOUND) {
+ int pos0, pos1;
+
+ slot = mca_find_unused_adapter(0x628B, slot);
+ if (slot == MCA_NOTFOUND)
+ break;
+
+ pos0 = mca_read_stored_pos(slot, 2);
+ pos1 = mca_read_stored_pos(slot, 3);
+ ioaddr = mca_iomap[pos1&0xf];
+
+ dev->irq = mca_irqmap[(pos1>>4)&0x7];
+
+ /*
+ * XXX: Transceiver selection is done
+ * differently on the MCA version.
+ * How to get it to select something
+ * other than external/AUI is currently
+ * unknown. This code is just for looks. -- ASF
+ */
+ if ((pos0 & 0x7) == 0x1)
+ dev->if_port = AUI;
+ else if ((pos0 & 0x7) == 0x5) {
+ if (pos1 & 0x80)
+ dev->if_port = BNC;
+ else
+ dev->if_port = TPE;
+ }
+
+ mca_set_adapter_name(slot, "Intel EtherExpress 16 MCA");
+ mca_set_adapter_procfn(slot, NULL, dev);
+ mca_mark_as_used(slot);
+
+ break;
+ }
+ }
+#endif
+ if (ioaddr&0xfe00) {
+ if (!request_region(ioaddr, EEXP_IO_EXTENT, "EtherExpress"))
+ return -EBUSY;
+ err = eexp_hw_probe(dev,ioaddr);
+ release_region(ioaddr, EEXP_IO_EXTENT);
+ return err;
+ } else if (ioaddr)
+ return -ENXIO;
+
+ for (port=&ports[0] ; *port ; port++ )
+ {
+ unsigned short sum = 0;
+ int i;
+ if (!request_region(*port, EEXP_IO_EXTENT, "EtherExpress"))
+ continue;
+ for ( i=0 ; i<4 ; i++ )
+ {
+ unsigned short t;
+ t = inb(*port + ID_PORT);
+ sum |= (t>>4) << ((t & 0x03)<<2);
+ }
+ if (sum==0xbaba && !eexp_hw_probe(dev,*port)) {
+ release_region(*port, EEXP_IO_EXTENT);
+ return 0;
+ }
+ release_region(*port, EEXP_IO_EXTENT);
+ dev->irq = dev_irq;
+ }
+ return -ENODEV;
+}
+
+#ifndef MODULE
+struct net_device * __init express_probe(int unit)
+{
+ struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
+ int err;
+
+ if (!dev)
+ return ERR_PTR(-ENOMEM);
+
+ sprintf(dev->name, "eth%d", unit);
+ netdev_boot_setup_check(dev);
+
+ err = do_express_probe(dev);
+ if (!err)
+ return dev;
+ free_netdev(dev);
+ return ERR_PTR(err);
+}
+#endif
+
+/*
+ * open and initialize the adapter, ready for use
+ */
+
+static int eexp_open(struct net_device *dev)
+{
+ int ret;
+ unsigned short ioaddr = dev->base_addr;
+ struct net_local *lp = netdev_priv(dev);
+
+#if NET_DEBUG > 6
+ printk(KERN_DEBUG "%s: eexp_open()\n", dev->name);
+#endif
+
+ if (!dev->irq || !irqrmap[dev->irq])
+ return -ENXIO;
+
+ ret = request_irq(dev->irq, eexp_irq, 0, dev->name, dev);
+ if (ret)
+ return ret;
+
+ if (!request_region(ioaddr, EEXP_IO_EXTENT, "EtherExpress")) {
+ printk(KERN_WARNING "EtherExpress io port %x, is busy.\n"
+ , ioaddr);
+ goto err_out1;
+ }
+ if (!request_region(ioaddr+0x4000, EEXP_IO_EXTENT, "EtherExpress shadow")) {
+ printk(KERN_WARNING "EtherExpress io port %x, is busy.\n"
+ , ioaddr+0x4000);
+ goto err_out2;
+ }
+ if (!request_region(ioaddr+0x8000, EEXP_IO_EXTENT, "EtherExpress shadow")) {
+ printk(KERN_WARNING "EtherExpress io port %x, is busy.\n"
+ , ioaddr+0x8000);
+ goto err_out3;
+ }
+ if (!request_region(ioaddr+0xc000, EEXP_IO_EXTENT, "EtherExpress shadow")) {
+ printk(KERN_WARNING "EtherExpress io port %x, is busy.\n"
+ , ioaddr+0xc000);
+ goto err_out4;
+ }
+
+ if (lp->width) {
+ printk("%s: forcing ASIC to 8-bit mode\n", dev->name);
+ outb(inb(dev->base_addr+Config)&~4, dev->base_addr+Config);
+ }
+
+ eexp_hw_init586(dev);
+ netif_start_queue(dev);
+#if NET_DEBUG > 6
+ printk(KERN_DEBUG "%s: leaving eexp_open()\n", dev->name);
+#endif
+ return 0;
+
+ err_out4:
+ release_region(ioaddr+0x8000, EEXP_IO_EXTENT);
+ err_out3:
+ release_region(ioaddr+0x4000, EEXP_IO_EXTENT);
+ err_out2:
+ release_region(ioaddr, EEXP_IO_EXTENT);
+ err_out1:
+ free_irq(dev->irq, dev);
+ return -EBUSY;
+}
+
+/*
+ * close and disable the interface, leaving the 586 in reset.
+ */
+
+static int eexp_close(struct net_device *dev)
+{
+ unsigned short ioaddr = dev->base_addr;
+ struct net_local *lp = netdev_priv(dev);
+
+ int irq = dev->irq;
+
+ netif_stop_queue(dev);
+
+ outb(SIRQ_dis|irqrmap[irq],ioaddr+SET_IRQ);
+ lp->started = 0;
+ scb_command(dev, SCB_CUsuspend|SCB_RUsuspend);
+ outb(0,ioaddr+SIGNAL_CA);
+ free_irq(irq,dev);
+ outb(i586_RST,ioaddr+EEPROM_Ctrl);
+ release_region(ioaddr, EEXP_IO_EXTENT);
+ release_region(ioaddr+0x4000, 16);
+ release_region(ioaddr+0x8000, 16);
+ release_region(ioaddr+0xc000, 16);
+
+ return 0;
+}
+
+/*
+ * This gets called when a higher level thinks we are broken. Check that
+ * nothing has become jammed in the CU.
+ */
+
+static void unstick_cu(struct net_device *dev)
+{
+ struct net_local *lp = netdev_priv(dev);
+ unsigned short ioaddr = dev->base_addr;
+
+ if (lp->started)
+ {
+ if (time_after(jiffies, dev_trans_start(dev) + HZ/2))
+ {
+ if (lp->tx_link==lp->last_tx_restart)
+ {
+ unsigned short boguscount=200,rsst;
+ printk(KERN_WARNING "%s: Retransmit timed out, status %04x, resetting...\n",
+ dev->name, scb_status(dev));
+ eexp_hw_txinit(dev);
+ lp->last_tx_restart = 0;
+ scb_wrcbl(dev, lp->tx_link);
+ scb_command(dev, SCB_CUstart);
+ outb(0,ioaddr+SIGNAL_CA);
+ while (!SCB_complete(rsst=scb_status(dev)))
+ {
+ if (!--boguscount)
+ {
+ boguscount=200;
+ printk(KERN_WARNING "%s: Reset timed out status %04x, retrying...\n",
+ dev->name,rsst);
+ scb_wrcbl(dev, lp->tx_link);
+ scb_command(dev, SCB_CUstart);
+ outb(0,ioaddr+SIGNAL_CA);
+ }
+ }
+ netif_wake_queue(dev);
+ }
+ else
+ {
+ unsigned short status = scb_status(dev);
+ if (SCB_CUdead(status))
+ {
+ unsigned short txstatus = eexp_hw_lasttxstat(dev);
+ printk(KERN_WARNING "%s: Transmit timed out, CU not active status %04x %04x, restarting...\n",
+ dev->name, status, txstatus);
+ eexp_hw_txrestart(dev);
+ }
+ else
+ {
+ unsigned short txstatus = eexp_hw_lasttxstat(dev);
+ if (netif_queue_stopped(dev) && !txstatus)
+ {
+ printk(KERN_WARNING "%s: CU wedged, status %04x %04x, resetting...\n",
+ dev->name,status,txstatus);
+ eexp_hw_init586(dev);
+ netif_wake_queue(dev);
+ }
+ else
+ {
+ printk(KERN_WARNING "%s: transmit timed out\n", dev->name);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ if (time_after(jiffies, lp->init_time + 10))
+ {
+ unsigned short status = scb_status(dev);
+ printk(KERN_WARNING "%s: i82586 startup timed out, status %04x, resetting...\n",
+ dev->name, status);
+ eexp_hw_init586(dev);
+ netif_wake_queue(dev);
+ }
+ }
+}
+
+static void eexp_timeout(struct net_device *dev)
+{
+ struct net_local *lp = netdev_priv(dev);
+#ifdef CONFIG_SMP
+ unsigned long flags;
+#endif
+ int status;
+
+ disable_irq(dev->irq);
+
+ /*
+ * Best would be to use synchronize_irq(); spin_lock() here
+ * lets make it work first..
+ */
+
+#ifdef CONFIG_SMP
+ spin_lock_irqsave(&lp->lock, flags);
+#endif
+
+ status = scb_status(dev);
+ unstick_cu(dev);
+ printk(KERN_INFO "%s: transmit timed out, %s?\n", dev->name,
+ (SCB_complete(status)?"lost interrupt":
+ "board on fire"));
+ dev->stats.tx_errors++;
+ lp->last_tx = jiffies;
+ if (!SCB_complete(status)) {
+ scb_command(dev, SCB_CUabort);
+ outb(0,dev->base_addr+SIGNAL_CA);
+ }
+ netif_wake_queue(dev);
+#ifdef CONFIG_SMP
+ spin_unlock_irqrestore(&lp->lock, flags);
+#endif
+}
+
+/*
+ * Called to transmit a packet, or to allow us to right ourselves
+ * if the kernel thinks we've died.
+ */
+static netdev_tx_t eexp_xmit(struct sk_buff *buf, struct net_device *dev)
+{
+ short length = buf->len;
+#ifdef CONFIG_SMP
+ struct net_local *lp = netdev_priv(dev);
+ unsigned long flags;
+#endif
+
+#if NET_DEBUG > 6
+ printk(KERN_DEBUG "%s: eexp_xmit()\n", dev->name);
+#endif
+
+ if (buf->len < ETH_ZLEN) {
+ if (skb_padto(buf, ETH_ZLEN))
+ return NETDEV_TX_OK;
+ length = ETH_ZLEN;
+ }
+
+ disable_irq(dev->irq);
+
+ /*
+ * Best would be to use synchronize_irq(); spin_lock() here
+ * lets make it work first..
+ */
+
+#ifdef CONFIG_SMP
+ spin_lock_irqsave(&lp->lock, flags);
+#endif
+
+ {
+ unsigned short *data = (unsigned short *)buf->data;
+
+ dev->stats.tx_bytes += length;
+
+ eexp_hw_tx_pio(dev,data,length);
+ }
+ dev_kfree_skb(buf);
+#ifdef CONFIG_SMP
+ spin_unlock_irqrestore(&lp->lock, flags);
+#endif
+ enable_irq(dev->irq);
+ return NETDEV_TX_OK;
+}
+
+/*
+ * Handle an EtherExpress interrupt
+ * If we've finished initializing, start the RU and CU up.
+ * If we've already started, reap tx buffers, handle any received packets,
+ * check to make sure we've not become wedged.
+ */
+
+static unsigned short eexp_start_irq(struct net_device *dev,
+ unsigned short status)
+{
+ unsigned short ack_cmd = SCB_ack(status);
+ struct net_local *lp = netdev_priv(dev);
+ unsigned short ioaddr = dev->base_addr;
+ if ((dev->flags & IFF_UP) && !(lp->started & STARTED_CU)) {
+ short diag_status, tdr_status;
+ while (SCB_CUstat(status)==2)
+ status = scb_status(dev);
+#if NET_DEBUG > 4
+ printk("%s: CU went non-active (status %04x)\n",
+ dev->name, status);
+#endif
+
+ outw(CONF_DIAG_RESULT & ~31, ioaddr + SM_PTR);
+ diag_status = inw(ioaddr + SHADOW(CONF_DIAG_RESULT));
+ if (diag_status & 1<<11) {
+ printk(KERN_WARNING "%s: 82586 failed self-test\n",
+ dev->name);
+ } else if (!(diag_status & 1<<13)) {
+ printk(KERN_WARNING "%s: 82586 self-test failed to complete\n", dev->name);
+ }
+
+ outw(CONF_TDR_RESULT & ~31, ioaddr + SM_PTR);
+ tdr_status = inw(ioaddr + SHADOW(CONF_TDR_RESULT));
+ if (tdr_status & (TDR_SHORT|TDR_OPEN)) {
+ printk(KERN_WARNING "%s: TDR reports cable %s at %d tick%s\n", dev->name, (tdr_status & TDR_SHORT)?"short":"broken", tdr_status & TDR_TIME, ((tdr_status & TDR_TIME) != 1) ? "s" : "");
+ }
+ else if (tdr_status & TDR_XCVRPROBLEM) {
+ printk(KERN_WARNING "%s: TDR reports transceiver problem\n", dev->name);
+ }
+ else if (tdr_status & TDR_LINKOK) {
+#if NET_DEBUG > 4
+ printk(KERN_DEBUG "%s: TDR reports link OK\n", dev->name);
+#endif
+ } else {
+ printk("%s: TDR is ga-ga (status %04x)\n", dev->name,
+ tdr_status);
+ }
+
+ lp->started |= STARTED_CU;
+ scb_wrcbl(dev, lp->tx_link);
+ /* if the RU isn't running, start it now */
+ if (!(lp->started & STARTED_RU)) {
+ ack_cmd |= SCB_RUstart;
+ scb_wrrfa(dev, lp->rx_buf_start);
+ lp->rx_ptr = lp->rx_buf_start;
+ lp->started |= STARTED_RU;
+ }
+ ack_cmd |= SCB_CUstart | 0x2000;
+ }
+
+ if ((dev->flags & IFF_UP) && !(lp->started & STARTED_RU) && SCB_RUstat(status)==4)
+ lp->started|=STARTED_RU;
+
+ return ack_cmd;
+}
+
+static void eexp_cmd_clear(struct net_device *dev)
+{
+ unsigned long int oldtime = jiffies;
+ while (scb_rdcmd(dev) && (time_before(jiffies, oldtime + 10)));
+ if (scb_rdcmd(dev)) {
+ printk("%s: command didn't clear\n", dev->name);
+ }
+}
+
+static irqreturn_t eexp_irq(int dummy, void *dev_info)
+{
+ struct net_device *dev = dev_info;
+ struct net_local *lp;
+ unsigned short ioaddr,status,ack_cmd;
+ unsigned short old_read_ptr, old_write_ptr;
+
+ lp = netdev_priv(dev);
+ ioaddr = dev->base_addr;
+
+ spin_lock(&lp->lock);
+
+ old_read_ptr = inw(ioaddr+READ_PTR);
+ old_write_ptr = inw(ioaddr+WRITE_PTR);
+
+ outb(SIRQ_dis|irqrmap[dev->irq], ioaddr+SET_IRQ);
+
+ status = scb_status(dev);
+
+#if NET_DEBUG > 4
+ printk(KERN_DEBUG "%s: interrupt (status %x)\n", dev->name, status);
+#endif
+
+ if (lp->started == (STARTED_CU | STARTED_RU)) {
+
+ do {
+ eexp_cmd_clear(dev);
+
+ ack_cmd = SCB_ack(status);
+ scb_command(dev, ack_cmd);
+ outb(0,ioaddr+SIGNAL_CA);
+
+ eexp_cmd_clear(dev);
+
+ if (SCB_complete(status)) {
+ if (!eexp_hw_lasttxstat(dev)) {
+ printk("%s: tx interrupt but no status\n", dev->name);
+ }
+ }
+
+ if (SCB_rxdframe(status))
+ eexp_hw_rx_pio(dev);
+
+ status = scb_status(dev);
+ } while (status & 0xc000);
+
+ if (SCB_RUdead(status))
+ {
+ printk(KERN_WARNING "%s: RU stopped: status %04x\n",
+ dev->name,status);
+#if 0
+ printk(KERN_WARNING "%s: cur_rfd=%04x, cur_rbd=%04x\n", dev->name, lp->cur_rfd, lp->cur_rbd);
+ outw(lp->cur_rfd, ioaddr+READ_PTR);
+ printk(KERN_WARNING "%s: [%04x]\n", dev->name, inw(ioaddr+DATAPORT));
+ outw(lp->cur_rfd+6, ioaddr+READ_PTR);
+ printk(KERN_WARNING "%s: rbd is %04x\n", dev->name, rbd= inw(ioaddr+DATAPORT));
+ outw(rbd, ioaddr+READ_PTR);
+ printk(KERN_WARNING "%s: [%04x %04x] ", dev->name, inw(ioaddr+DATAPORT), inw(ioaddr+DATAPORT));
+ outw(rbd+8, ioaddr+READ_PTR);
+ printk("[%04x]\n", inw(ioaddr+DATAPORT));
+#endif
+ dev->stats.rx_errors++;
+#if 1
+ eexp_hw_rxinit(dev);
+#else
+ lp->cur_rfd = lp->first_rfd;
+#endif
+ scb_wrrfa(dev, lp->rx_buf_start);
+ scb_command(dev, SCB_RUstart);
+ outb(0,ioaddr+SIGNAL_CA);
+ }
+ } else {
+ if (status & 0x8000)
+ ack_cmd = eexp_start_irq(dev, status);
+ else
+ ack_cmd = SCB_ack(status);
+ scb_command(dev, ack_cmd);
+ outb(0,ioaddr+SIGNAL_CA);
+ }
+
+ eexp_cmd_clear(dev);
+
+ outb(SIRQ_en|irqrmap[dev->irq], ioaddr+SET_IRQ);
+
+#if NET_DEBUG > 6
+ printk("%s: leaving eexp_irq()\n", dev->name);
+#endif
+ outw(old_read_ptr, ioaddr+READ_PTR);
+ outw(old_write_ptr, ioaddr+WRITE_PTR);
+
+ spin_unlock(&lp->lock);
+ return IRQ_HANDLED;
+}
+
+/*
+ * Hardware access functions
+ */
+
+/*
+ * Set the cable type to use.
+ */
+
+static void eexp_hw_set_interface(struct net_device *dev)
+{
+ unsigned char oldval = inb(dev->base_addr + 0x300e);
+ oldval &= ~0x82;
+ switch (dev->if_port) {
+ case TPE:
+ oldval |= 0x2;
+ case BNC:
+ oldval |= 0x80;
+ break;
+ }
+ outb(oldval, dev->base_addr+0x300e);
+ mdelay(20);
+}
+
+/*
+ * Check all the receive buffers, and hand any received packets
+ * to the upper levels. Basic sanity check on each frame
+ * descriptor, though we don't bother trying to fix broken ones.
+ */
+
+static void eexp_hw_rx_pio(struct net_device *dev)
+{
+ struct net_local *lp = netdev_priv(dev);
+ unsigned short rx_block = lp->rx_ptr;
+ unsigned short boguscount = lp->num_rx_bufs;
+ unsigned short ioaddr = dev->base_addr;
+ unsigned short status;
+
+#if NET_DEBUG > 6
+ printk(KERN_DEBUG "%s: eexp_hw_rx()\n", dev->name);
+#endif
+
+ do {
+ unsigned short rfd_cmd, rx_next, pbuf, pkt_len;
+
+ outw(rx_block, ioaddr + READ_PTR);
+ status = inw(ioaddr + DATAPORT);
+
+ if (FD_Done(status))
+ {
+ rfd_cmd = inw(ioaddr + DATAPORT);
+ rx_next = inw(ioaddr + DATAPORT);
+ pbuf = inw(ioaddr + DATAPORT);
+
+ outw(pbuf, ioaddr + READ_PTR);
+ pkt_len = inw(ioaddr + DATAPORT);
+
+ if (rfd_cmd!=0x0000)
+ {
+ printk(KERN_WARNING "%s: rfd_cmd not zero:0x%04x\n",
+ dev->name, rfd_cmd);
+ continue;
+ }
+ else if (pbuf!=rx_block+0x16)
+ {
+ printk(KERN_WARNING "%s: rfd and rbd out of sync 0x%04x 0x%04x\n",
+ dev->name, rx_block+0x16, pbuf);
+ continue;
+ }
+ else if ((pkt_len & 0xc000)!=0xc000)
+ {
+ printk(KERN_WARNING "%s: EOF or F not set on received buffer (%04x)\n",
+ dev->name, pkt_len & 0xc000);
+ continue;
+ }
+ else if (!FD_OK(status))
+ {
+ dev->stats.rx_errors++;
+ if (FD_CRC(status))
+ dev->stats.rx_crc_errors++;
+ if (FD_Align(status))
+ dev->stats.rx_frame_errors++;
+ if (FD_Resrc(status))
+ dev->stats.rx_fifo_errors++;
+ if (FD_DMA(status))
+ dev->stats.rx_over_errors++;
+ if (FD_Short(status))
+ dev->stats.rx_length_errors++;
+ }
+ else
+ {
+ struct sk_buff *skb;
+ pkt_len &= 0x3fff;
+ skb = dev_alloc_skb(pkt_len+16);
+ if (skb == NULL)
+ {
+ printk(KERN_WARNING "%s: Memory squeeze, dropping packet\n",dev->name);
+ dev->stats.rx_dropped++;
+ break;
+ }
+ skb_reserve(skb, 2);
+ outw(pbuf+10, ioaddr+READ_PTR);
+ insw(ioaddr+DATAPORT, skb_put(skb,pkt_len),(pkt_len+1)>>1);
+ skb->protocol = eth_type_trans(skb,dev);
+ netif_rx(skb);
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
+ }
+ outw(rx_block, ioaddr+WRITE_PTR);
+ outw(0, ioaddr+DATAPORT);
+ outw(0, ioaddr+DATAPORT);
+ rx_block = rx_next;
+ }
+ } while (FD_Done(status) && boguscount--);
+ lp->rx_ptr = rx_block;
+}
+
+/*
+ * Hand a packet to the card for transmission
+ * If we get here, we MUST have already checked
+ * to make sure there is room in the transmit
+ * buffer region.
+ */
+
+static void eexp_hw_tx_pio(struct net_device *dev, unsigned short *buf,
+ unsigned short len)
+{
+ struct net_local *lp = netdev_priv(dev);
+ unsigned short ioaddr = dev->base_addr;
+
+ if (LOCKUP16 || lp->width) {
+ /* Stop the CU so that there is no chance that it
+ jumps off to a bogus address while we are writing the
+ pointer to the next transmit packet in 8-bit mode --
+ this eliminates the "CU wedged" errors in 8-bit mode.
+ (Zoltan Szilagyi 10-12-96) */
+ scb_command(dev, SCB_CUsuspend);
+ outw(0xFFFF, ioaddr+SIGNAL_CA);
+ }
+
+ outw(lp->tx_head, ioaddr + WRITE_PTR);
+
+ outw(0x0000, ioaddr + DATAPORT);
+ outw(Cmd_INT|Cmd_Xmit, ioaddr + DATAPORT);
+ outw(lp->tx_head+0x08, ioaddr + DATAPORT);
+ outw(lp->tx_head+0x0e, ioaddr + DATAPORT);
+
+ outw(0x0000, ioaddr + DATAPORT);
+ outw(0x0000, ioaddr + DATAPORT);
+ outw(lp->tx_head+0x08, ioaddr + DATAPORT);
+
+ outw(0x8000|len, ioaddr + DATAPORT);
+ outw(-1, ioaddr + DATAPORT);
+ outw(lp->tx_head+0x16, ioaddr + DATAPORT);
+ outw(0, ioaddr + DATAPORT);
+
+ outsw(ioaddr + DATAPORT, buf, (len+1)>>1);
+
+ outw(lp->tx_tail+0xc, ioaddr + WRITE_PTR);
+ outw(lp->tx_head, ioaddr + DATAPORT);
+
+ dev->trans_start = jiffies;
+ lp->tx_tail = lp->tx_head;
+ if (lp->tx_head==TX_BUF_START+((lp->num_tx_bufs-1)*TX_BUF_SIZE))
+ lp->tx_head = TX_BUF_START;
+ else
+ lp->tx_head += TX_BUF_SIZE;
+ if (lp->tx_head != lp->tx_reap)
+ netif_wake_queue(dev);
+
+ if (LOCKUP16 || lp->width) {
+ /* Restart the CU so that the packet can actually
+ be transmitted. (Zoltan Szilagyi 10-12-96) */
+ scb_command(dev, SCB_CUresume);
+ outw(0xFFFF, ioaddr+SIGNAL_CA);
+ }
+
+ dev->stats.tx_packets++;
+ lp->last_tx = jiffies;
+}
+
+static const struct net_device_ops eexp_netdev_ops = {
+ .ndo_open = eexp_open,
+ .ndo_stop = eexp_close,
+ .ndo_start_xmit = eexp_xmit,
+ .ndo_set_multicast_list = eexp_set_multicast,
+ .ndo_tx_timeout = eexp_timeout,
+ .ndo_change_mtu = eth_change_mtu,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+};
+
+/*
+ * Sanity check the suspected EtherExpress card
+ * Read hardware address, reset card, size memory and initialize buffer
+ * memory pointers. These are held in netdev_priv(), in case someone has more
+ * than one card in a machine.
+ */
+
+static int __init eexp_hw_probe(struct net_device *dev, unsigned short ioaddr)
+{
+ unsigned short hw_addr[3];
+ unsigned char buswidth;
+ unsigned int memory_size;
+ int i;
+ unsigned short xsum = 0;
+ struct net_local *lp = netdev_priv(dev);
+
+ printk("%s: EtherExpress 16 at %#x ",dev->name,ioaddr);
+
+ outb(ASIC_RST, ioaddr+EEPROM_Ctrl);
+ outb(0, ioaddr+EEPROM_Ctrl);
+ udelay(500);
+ outb(i586_RST, ioaddr+EEPROM_Ctrl);
+
+ hw_addr[0] = eexp_hw_readeeprom(ioaddr,2);
+ hw_addr[1] = eexp_hw_readeeprom(ioaddr,3);
+ hw_addr[2] = eexp_hw_readeeprom(ioaddr,4);
+
+ /* Standard Address or Compaq LTE Address */
+ if (!((hw_addr[2]==0x00aa && ((hw_addr[1] & 0xff00)==0x0000)) ||
+ (hw_addr[2]==0x0080 && ((hw_addr[1] & 0xff00)==0x5F00))))
+ {
+ printk(" rejected: invalid address %04x%04x%04x\n",
+ hw_addr[2],hw_addr[1],hw_addr[0]);
+ return -ENODEV;
+ }
+
+ /* Calculate the EEPROM checksum. Carry on anyway if it's bad,
+ * though.
+ */
+ for (i = 0; i < 64; i++)
+ xsum += eexp_hw_readeeprom(ioaddr, i);
+ if (xsum != 0xbaba)
+ printk(" (bad EEPROM xsum 0x%02x)", xsum);
+
+ dev->base_addr = ioaddr;
+ for ( i=0 ; i<6 ; i++ )
+ dev->dev_addr[i] = ((unsigned char *)hw_addr)[5-i];
+
+ {
+ static const char irqmap[] = { 0, 9, 3, 4, 5, 10, 11, 0 };
+ unsigned short setupval = eexp_hw_readeeprom(ioaddr,0);
+
+ /* Use the IRQ from EEPROM if none was given */
+ if (!dev->irq)
+ dev->irq = irqmap[setupval>>13];
+
+ if (dev->if_port == 0xff) {
+ dev->if_port = !(setupval & 0x1000) ? AUI :
+ eexp_hw_readeeprom(ioaddr,5) & 0x1 ? TPE : BNC;
+ }
+
+ buswidth = !((setupval & 0x400) >> 10);
+ }
+
+ memset(lp, 0, sizeof(struct net_local));
+ spin_lock_init(&lp->lock);
+
+ printk("(IRQ %d, %s connector, %d-bit bus", dev->irq,
+ eexp_ifmap[dev->if_port], buswidth?8:16);
+
+ if (!request_region(dev->base_addr + 0x300e, 1, "EtherExpress"))
+ return -EBUSY;
+
+ eexp_hw_set_interface(dev);
+
+ release_region(dev->base_addr + 0x300e, 1);
+
+ /* Find out how much RAM we have on the card */
+ outw(0, dev->base_addr + WRITE_PTR);
+ for (i = 0; i < 32768; i++)
+ outw(0, dev->base_addr + DATAPORT);
+
+ for (memory_size = 0; memory_size < 64; memory_size++)
+ {
+ outw(memory_size<<10, dev->base_addr + READ_PTR);
+ if (inw(dev->base_addr+DATAPORT))
+ break;
+ outw(memory_size<<10, dev->base_addr + WRITE_PTR);
+ outw(memory_size | 0x5000, dev->base_addr+DATAPORT);
+ outw(memory_size<<10, dev->base_addr + READ_PTR);
+ if (inw(dev->base_addr+DATAPORT) != (memory_size | 0x5000))
+ break;
+ }
+
+ /* Sort out the number of buffers. We may have 16, 32, 48 or 64k
+ * of RAM to play with.
+ */
+ lp->num_tx_bufs = 4;
+ lp->rx_buf_end = 0x3ff6;
+ switch (memory_size)
+ {
+ case 64:
+ lp->rx_buf_end += 0x4000;
+ case 48:
+ lp->num_tx_bufs += 4;
+ lp->rx_buf_end += 0x4000;
+ case 32:
+ lp->rx_buf_end += 0x4000;
+ case 16:
+ printk(", %dk RAM)\n", memory_size);
+ break;
+ default:
+ printk(") bad memory size (%dk).\n", memory_size);
+ return -ENODEV;
+ break;
+ }
+
+ lp->rx_buf_start = TX_BUF_START + (lp->num_tx_bufs*TX_BUF_SIZE);
+ lp->width = buswidth;
+
+ dev->netdev_ops = &eexp_netdev_ops;
+ dev->watchdog_timeo = 2*HZ;
+
+ return register_netdev(dev);
+}
+
+/*
+ * Read a word from the EtherExpress on-board serial EEPROM.
+ * The EEPROM contains 64 words of 16 bits.
+ */
+static unsigned short __init eexp_hw_readeeprom(unsigned short ioaddr,
+ unsigned char location)
+{
+ unsigned short cmd = 0x180|(location&0x7f);
+ unsigned short rval = 0,wval = EC_CS|i586_RST;
+ int i;
+
+ outb(EC_CS|i586_RST,ioaddr+EEPROM_Ctrl);
+ for (i=0x100 ; i ; i>>=1 )
+ {
+ if (cmd&i)
+ wval |= EC_Wr;
+ else
+ wval &= ~EC_Wr;
+
+ outb(wval,ioaddr+EEPROM_Ctrl);
+ outb(wval|EC_Clk,ioaddr+EEPROM_Ctrl);
+ eeprom_delay();
+ outb(wval,ioaddr+EEPROM_Ctrl);
+ eeprom_delay();
+ }
+ wval &= ~EC_Wr;
+ outb(wval,ioaddr+EEPROM_Ctrl);
+ for (i=0x8000 ; i ; i>>=1 )
+ {
+ outb(wval|EC_Clk,ioaddr+EEPROM_Ctrl);
+ eeprom_delay();
+ if (inb(ioaddr+EEPROM_Ctrl)&EC_Rd)
+ rval |= i;
+ outb(wval,ioaddr+EEPROM_Ctrl);
+ eeprom_delay();
+ }
+ wval &= ~EC_CS;
+ outb(wval|EC_Clk,ioaddr+EEPROM_Ctrl);
+ eeprom_delay();
+ outb(wval,ioaddr+EEPROM_Ctrl);
+ eeprom_delay();
+ return rval;
+}
+
+/*
+ * Reap tx buffers and return last transmit status.
+ * if ==0 then either:
+ * a) we're not transmitting anything, so why are we here?
+ * b) we've died.
+ * otherwise, Stat_Busy(return) means we've still got some packets
+ * to transmit, Stat_Done(return) means our buffers should be empty
+ * again
+ */
+
+static unsigned short eexp_hw_lasttxstat(struct net_device *dev)
+{
+ struct net_local *lp = netdev_priv(dev);
+ unsigned short tx_block = lp->tx_reap;
+ unsigned short status;
+
+ if (!netif_queue_stopped(dev) && lp->tx_head==lp->tx_reap)
+ return 0x0000;
+
+ do
+ {
+ outw(tx_block & ~31, dev->base_addr + SM_PTR);
+ status = inw(dev->base_addr + SHADOW(tx_block));
+ if (!Stat_Done(status))
+ {
+ lp->tx_link = tx_block;
+ return status;
+ }
+ else
+ {
+ lp->last_tx_restart = 0;
+ dev->stats.collisions += Stat_NoColl(status);
+ if (!Stat_OK(status))
+ {
+ char *whatsup = NULL;
+ dev->stats.tx_errors++;
+ if (Stat_Abort(status))
+ dev->stats.tx_aborted_errors++;
+ if (Stat_TNoCar(status)) {
+ whatsup = "aborted, no carrier";
+ dev->stats.tx_carrier_errors++;
+ }
+ if (Stat_TNoCTS(status)) {
+ whatsup = "aborted, lost CTS";
+ dev->stats.tx_carrier_errors++;
+ }
+ if (Stat_TNoDMA(status)) {
+ whatsup = "FIFO underran";
+ dev->stats.tx_fifo_errors++;
+ }
+ if (Stat_TXColl(status)) {
+ whatsup = "aborted, too many collisions";
+ dev->stats.tx_aborted_errors++;
+ }
+ if (whatsup)
+ printk(KERN_INFO "%s: transmit %s\n",
+ dev->name, whatsup);
+ }
+ else
+ dev->stats.tx_packets++;
+ }
+ if (tx_block == TX_BUF_START+((lp->num_tx_bufs-1)*TX_BUF_SIZE))
+ lp->tx_reap = tx_block = TX_BUF_START;
+ else
+ lp->tx_reap = tx_block += TX_BUF_SIZE;
+ netif_wake_queue(dev);
+ }
+ while (lp->tx_reap != lp->tx_head);
+
+ lp->tx_link = lp->tx_tail + 0x08;
+
+ return status;
+}
+
+/*
+ * This should never happen. It is called when some higher routine detects
+ * that the CU has stopped, to try to restart it from the last packet we knew
+ * we were working on, or the idle loop if we had finished for the time.
+ */
+
+static void eexp_hw_txrestart(struct net_device *dev)
+{
+ struct net_local *lp = netdev_priv(dev);
+ unsigned short ioaddr = dev->base_addr;
+
+ lp->last_tx_restart = lp->tx_link;
+ scb_wrcbl(dev, lp->tx_link);
+ scb_command(dev, SCB_CUstart);
+ outb(0,ioaddr+SIGNAL_CA);
+
+ {
+ unsigned short boguscount=50,failcount=5;
+ while (!scb_status(dev))
+ {
+ if (!--boguscount)
+ {
+ if (--failcount)
+ {
+ printk(KERN_WARNING "%s: CU start timed out, status %04x, cmd %04x\n", dev->name, scb_status(dev), scb_rdcmd(dev));
+ scb_wrcbl(dev, lp->tx_link);
+ scb_command(dev, SCB_CUstart);
+ outb(0,ioaddr+SIGNAL_CA);
+ boguscount = 100;
+ }
+ else
+ {
+ printk(KERN_WARNING "%s: Failed to restart CU, resetting board...\n",dev->name);
+ eexp_hw_init586(dev);
+ netif_wake_queue(dev);
+ return;
+ }
+ }
+ }
+ }
+}
+
+/*
+ * Writes down the list of transmit buffers into card memory. Each
+ * entry consists of an 82586 transmit command, followed by a jump
+ * pointing to itself. When we want to transmit a packet, we write
+ * the data into the appropriate transmit buffer and then modify the
+ * preceding jump to point at the new transmit command. This means that
+ * the 586 command unit is continuously active.
+ */
+
+static void eexp_hw_txinit(struct net_device *dev)
+{
+ struct net_local *lp = netdev_priv(dev);
+ unsigned short tx_block = TX_BUF_START;
+ unsigned short curtbuf;
+ unsigned short ioaddr = dev->base_addr;
+
+ for ( curtbuf=0 ; curtbuf<lp->num_tx_bufs ; curtbuf++ )
+ {
+ outw(tx_block, ioaddr + WRITE_PTR);
+
+ outw(0x0000, ioaddr + DATAPORT);
+ outw(Cmd_INT|Cmd_Xmit, ioaddr + DATAPORT);
+ outw(tx_block+0x08, ioaddr + DATAPORT);
+ outw(tx_block+0x0e, ioaddr + DATAPORT);
+
+ outw(0x0000, ioaddr + DATAPORT);
+ outw(0x0000, ioaddr + DATAPORT);
+ outw(tx_block+0x08, ioaddr + DATAPORT);
+
+ outw(0x8000, ioaddr + DATAPORT);
+ outw(-1, ioaddr + DATAPORT);
+ outw(tx_block+0x16, ioaddr + DATAPORT);
+ outw(0x0000, ioaddr + DATAPORT);
+
+ tx_block += TX_BUF_SIZE;
+ }
+ lp->tx_head = TX_BUF_START;
+ lp->tx_reap = TX_BUF_START;
+ lp->tx_tail = tx_block - TX_BUF_SIZE;
+ lp->tx_link = lp->tx_tail + 0x08;
+ lp->rx_buf_start = tx_block;
+
+}
+
+/*
+ * Write the circular list of receive buffer descriptors to card memory.
+ * The end of the list isn't marked, which means that the 82586 receive
+ * unit will loop until buffers become available (this avoids it giving us
+ * "out of resources" messages).
+ */
+
+static void eexp_hw_rxinit(struct net_device *dev)
+{
+ struct net_local *lp = netdev_priv(dev);
+ unsigned short rx_block = lp->rx_buf_start;
+ unsigned short ioaddr = dev->base_addr;
+
+ lp->num_rx_bufs = 0;
+ lp->rx_first = lp->rx_ptr = rx_block;
+ do
+ {
+ lp->num_rx_bufs++;
+
+ outw(rx_block, ioaddr + WRITE_PTR);
+
+ outw(0, ioaddr + DATAPORT); outw(0, ioaddr+DATAPORT);
+ outw(rx_block + RX_BUF_SIZE, ioaddr+DATAPORT);
+ outw(0xffff, ioaddr+DATAPORT);
+
+ outw(0x0000, ioaddr+DATAPORT);
+ outw(0xdead, ioaddr+DATAPORT);
+ outw(0xdead, ioaddr+DATAPORT);
+ outw(0xdead, ioaddr+DATAPORT);
+ outw(0xdead, ioaddr+DATAPORT);
+ outw(0xdead, ioaddr+DATAPORT);
+ outw(0xdead, ioaddr+DATAPORT);
+
+ outw(0x0000, ioaddr+DATAPORT);
+ outw(rx_block + RX_BUF_SIZE + 0x16, ioaddr+DATAPORT);
+ outw(rx_block + 0x20, ioaddr+DATAPORT);
+ outw(0, ioaddr+DATAPORT);
+ outw(RX_BUF_SIZE-0x20, ioaddr+DATAPORT);
+
+ lp->rx_last = rx_block;
+ rx_block += RX_BUF_SIZE;
+ } while (rx_block <= lp->rx_buf_end-RX_BUF_SIZE);
+
+
+ /* Make first Rx frame descriptor point to first Rx buffer
+ descriptor */
+ outw(lp->rx_first + 6, ioaddr+WRITE_PTR);
+ outw(lp->rx_first + 0x16, ioaddr+DATAPORT);
+
+ /* Close Rx frame descriptor ring */
+ outw(lp->rx_last + 4, ioaddr+WRITE_PTR);
+ outw(lp->rx_first, ioaddr+DATAPORT);
+
+ /* Close Rx buffer descriptor ring */
+ outw(lp->rx_last + 0x16 + 2, ioaddr+WRITE_PTR);
+ outw(lp->rx_first + 0x16, ioaddr+DATAPORT);
+
+}
+
+/*
+ * Un-reset the 586, and start the configuration sequence. We don't wait for
+ * this to finish, but allow the interrupt handler to start the CU and RU for
+ * us. We can't start the receive/transmission system up before we know that
+ * the hardware is configured correctly.
+ */
+
+static void eexp_hw_init586(struct net_device *dev)
+{
+ struct net_local *lp = netdev_priv(dev);
+ unsigned short ioaddr = dev->base_addr;
+ int i;
+
+#if NET_DEBUG > 6
+ printk("%s: eexp_hw_init586()\n", dev->name);
+#endif
+
+ lp->started = 0;
+
+ set_loopback(dev);
+
+ outb(SIRQ_dis|irqrmap[dev->irq],ioaddr+SET_IRQ);
+
+ /* Download the startup code */
+ outw(lp->rx_buf_end & ~31, ioaddr + SM_PTR);
+ outw(lp->width?0x0001:0x0000, ioaddr + 0x8006);
+ outw(0x0000, ioaddr + 0x8008);
+ outw(0x0000, ioaddr + 0x800a);
+ outw(0x0000, ioaddr + 0x800c);
+ outw(0x0000, ioaddr + 0x800e);
+
+ for (i = 0; i < ARRAY_SIZE(start_code) * 2; i+=32) {
+ int j;
+ outw(i, ioaddr + SM_PTR);
+ for (j = 0; j < 16 && (i+j)/2 < ARRAY_SIZE(start_code); j+=2)
+ outw(start_code[(i+j)/2],
+ ioaddr+0x4000+j);
+ for (j = 0; j < 16 && (i+j+16)/2 < ARRAY_SIZE(start_code); j+=2)
+ outw(start_code[(i+j+16)/2],
+ ioaddr+0x8000+j);
+ }
+
+ /* Do we want promiscuous mode or multicast? */
+ outw(CONF_PROMISC & ~31, ioaddr+SM_PTR);
+ i = inw(ioaddr+SHADOW(CONF_PROMISC));
+ outw((dev->flags & IFF_PROMISC)?(i|1):(i & ~1),
+ ioaddr+SHADOW(CONF_PROMISC));
+ lp->was_promisc = dev->flags & IFF_PROMISC;
+#if 0
+ eexp_setup_filter(dev);
+#endif
+
+ /* Write our hardware address */
+ outw(CONF_HWADDR & ~31, ioaddr+SM_PTR);
+ outw(((unsigned short *)dev->dev_addr)[0], ioaddr+SHADOW(CONF_HWADDR));
+ outw(((unsigned short *)dev->dev_addr)[1],
+ ioaddr+SHADOW(CONF_HWADDR+2));
+ outw(((unsigned short *)dev->dev_addr)[2],
+ ioaddr+SHADOW(CONF_HWADDR+4));
+
+ eexp_hw_txinit(dev);
+ eexp_hw_rxinit(dev);
+
+ outb(0,ioaddr+EEPROM_Ctrl);
+ mdelay(5);
+
+ scb_command(dev, 0xf000);
+ outb(0,ioaddr+SIGNAL_CA);
+
+ outw(0, ioaddr+SM_PTR);
+
+ {
+ unsigned short rboguscount=50,rfailcount=5;
+ while (inw(ioaddr+0x4000))
+ {
+ if (!--rboguscount)
+ {
+ printk(KERN_WARNING "%s: i82586 reset timed out, kicking...\n",
+ dev->name);
+ scb_command(dev, 0);
+ outb(0,ioaddr+SIGNAL_CA);
+ rboguscount = 100;
+ if (!--rfailcount)
+ {
+ printk(KERN_WARNING "%s: i82586 not responding, giving up.\n",
+ dev->name);
+ return;
+ }
+ }
+ }
+ }
+
+ scb_wrcbl(dev, CONF_LINK);
+ scb_command(dev, 0xf000|SCB_CUstart);
+ outb(0,ioaddr+SIGNAL_CA);
+
+ {
+ unsigned short iboguscount=50,ifailcount=5;
+ while (!scb_status(dev))
+ {
+ if (!--iboguscount)
+ {
+ if (--ifailcount)
+ {
+ printk(KERN_WARNING "%s: i82586 initialization timed out, status %04x, cmd %04x\n",
+ dev->name, scb_status(dev), scb_rdcmd(dev));
+ scb_wrcbl(dev, CONF_LINK);
+ scb_command(dev, 0xf000|SCB_CUstart);
+ outb(0,ioaddr+SIGNAL_CA);
+ iboguscount = 100;
+ }
+ else
+ {
+ printk(KERN_WARNING "%s: Failed to initialize i82586, giving up.\n",dev->name);
+ return;
+ }
+ }
+ }
+ }
+
+ clear_loopback(dev);
+ outb(SIRQ_en|irqrmap[dev->irq],ioaddr+SET_IRQ);
+
+ lp->init_time = jiffies;
+#if NET_DEBUG > 6
+ printk("%s: leaving eexp_hw_init586()\n", dev->name);
+#endif
+}
+
+static void eexp_setup_filter(struct net_device *dev)
+{
+ struct netdev_hw_addr *ha;
+ unsigned short ioaddr = dev->base_addr;
+ int count = netdev_mc_count(dev);
+ int i;
+ if (count > 8) {
+ printk(KERN_INFO "%s: too many multicast addresses (%d)\n",
+ dev->name, count);
+ count = 8;
+ }
+
+ outw(CONF_NR_MULTICAST & ~31, ioaddr+SM_PTR);
+ outw(6*count, ioaddr+SHADOW(CONF_NR_MULTICAST));
+ i = 0;
+ netdev_for_each_mc_addr(ha, dev) {
+ unsigned short *data = (unsigned short *) ha->addr;
+
+ if (i == count)
+ break;
+ outw((CONF_MULTICAST+(6*i)) & ~31, ioaddr+SM_PTR);
+ outw(data[0], ioaddr+SHADOW(CONF_MULTICAST+(6*i)));
+ outw((CONF_MULTICAST+(6*i)+2) & ~31, ioaddr+SM_PTR);
+ outw(data[1], ioaddr+SHADOW(CONF_MULTICAST+(6*i)+2));
+ outw((CONF_MULTICAST+(6*i)+4) & ~31, ioaddr+SM_PTR);
+ outw(data[2], ioaddr+SHADOW(CONF_MULTICAST+(6*i)+4));
+ i++;
+ }
+}
+
+/*
+ * Set or clear the multicast filter for this adaptor.
+ */
+static void
+eexp_set_multicast(struct net_device *dev)
+{
+ unsigned short ioaddr = dev->base_addr;
+ struct net_local *lp = netdev_priv(dev);
+ int kick = 0, i;
+ if ((dev->flags & IFF_PROMISC) != lp->was_promisc) {
+ outw(CONF_PROMISC & ~31, ioaddr+SM_PTR);
+ i = inw(ioaddr+SHADOW(CONF_PROMISC));
+ outw((dev->flags & IFF_PROMISC)?(i|1):(i & ~1),
+ ioaddr+SHADOW(CONF_PROMISC));
+ lp->was_promisc = dev->flags & IFF_PROMISC;
+ kick = 1;
+ }
+ if (!(dev->flags & IFF_PROMISC)) {
+ eexp_setup_filter(dev);
+ if (lp->old_mc_count != netdev_mc_count(dev)) {
+ kick = 1;
+ lp->old_mc_count = netdev_mc_count(dev);
+ }
+ }
+ if (kick) {
+ unsigned long oj;
+ scb_command(dev, SCB_CUsuspend);
+ outb(0, ioaddr+SIGNAL_CA);
+ outb(0, ioaddr+SIGNAL_CA);
+#if 0
+ printk("%s: waiting for CU to go suspended\n", dev->name);
+#endif
+ oj = jiffies;
+ while ((SCB_CUstat(scb_status(dev)) == 2) &&
+ (time_before(jiffies, oj + 2000)));
+ if (SCB_CUstat(scb_status(dev)) == 2)
+ printk("%s: warning, CU didn't stop\n", dev->name);
+ lp->started &= ~(STARTED_CU);
+ scb_wrcbl(dev, CONF_LINK);
+ scb_command(dev, SCB_CUstart);
+ outb(0, ioaddr+SIGNAL_CA);
+ }
+}
+
+
+/*
+ * MODULE stuff
+ */
+
+#ifdef MODULE
+
+#define EEXP_MAX_CARDS 4 /* max number of cards to support */
+
+static struct net_device *dev_eexp[EEXP_MAX_CARDS];
+static int irq[EEXP_MAX_CARDS];
+static int io[EEXP_MAX_CARDS];
+
+module_param_array(io, int, NULL, 0);
+module_param_array(irq, int, NULL, 0);
+MODULE_PARM_DESC(io, "EtherExpress 16 I/O base address(es)");
+MODULE_PARM_DESC(irq, "EtherExpress 16 IRQ number(s)");
+MODULE_LICENSE("GPL");
+
+
+/* Ideally the user would give us io=, irq= for every card. If any parameters
+ * are specified, we verify and then use them. If no parameters are given, we
+ * autoprobe for one card only.
+ */
+int __init init_module(void)
+{
+ struct net_device *dev;
+ int this_dev, found = 0;
+
+ for (this_dev = 0; this_dev < EEXP_MAX_CARDS; this_dev++) {
+ dev = alloc_etherdev(sizeof(struct net_local));
+ dev->irq = irq[this_dev];
+ dev->base_addr = io[this_dev];
+ if (io[this_dev] == 0) {
+ if (this_dev)
+ break;
+ printk(KERN_NOTICE "eexpress.c: Module autoprobe not recommended, give io=xx.\n");
+ }
+ if (do_express_probe(dev) == 0) {
+ dev_eexp[this_dev] = dev;
+ found++;
+ continue;
+ }
+ printk(KERN_WARNING "eexpress.c: Failed to register card at 0x%x.\n", io[this_dev]);
+ free_netdev(dev);
+ break;
+ }
+ if (found)
+ return 0;
+ return -ENXIO;
+}
+
+void __exit cleanup_module(void)
+{
+ int this_dev;
+
+ for (this_dev = 0; this_dev < EEXP_MAX_CARDS; this_dev++) {
+ struct net_device *dev = dev_eexp[this_dev];
+ if (dev) {
+ unregister_netdev(dev);
+ free_netdev(dev);
+ }
+ }
+}
+#endif
+
+/*
+ * Local Variables:
+ * c-file-style: "linux"
+ * tab-width: 8
+ * End:
+ */
--- /dev/null
+/*
+ * eexpress.h: Intel EtherExpress16 defines
+ */
+
+/*
+ * EtherExpress card register addresses
+ * as offsets from the base IO region (dev->base_addr)
+ */
+
+#define DATAPORT 0x0000
+#define WRITE_PTR 0x0002
+#define READ_PTR 0x0004
+#define SIGNAL_CA 0x0006
+#define SET_IRQ 0x0007
+#define SM_PTR 0x0008
+#define MEM_Dec 0x000a
+#define MEM_Ctrl 0x000b
+#define MEM_Page_Ctrl 0x000c
+#define Config 0x000d
+#define EEPROM_Ctrl 0x000e
+#define ID_PORT 0x000f
+#define MEM_ECtrl 0x000f
+
+/*
+ * card register defines
+ */
+
+/* SET_IRQ */
+#define SIRQ_en 0x08
+#define SIRQ_dis 0x00
+
+/* EEPROM_Ctrl */
+#define EC_Clk 0x01
+#define EC_CS 0x02
+#define EC_Wr 0x04
+#define EC_Rd 0x08
+#define ASIC_RST 0x40
+#define i586_RST 0x80
+
+#define eeprom_delay() { udelay(40); }
+
+/*
+ * i82586 Memory Configuration
+ */
+
+/* (System Configuration Pointer) System start up block, read after 586_RST */
+#define SCP_START 0xfff6
+
+/* Intermediate System Configuration Pointer */
+#define ISCP_START 0x0000
+
+/* System Command Block */
+#define SCB_START 0x0008
+
+/* Start of buffer region. Everything before this is used for control
+ * structures and the CU configuration program. The memory layout is
+ * determined in eexp_hw_probe(), once we know how much memory is
+ * available on the card.
+ */
+
+#define TX_BUF_START 0x0100
+
+#define TX_BUF_SIZE ((24+ETH_FRAME_LEN+31)&~0x1f)
+#define RX_BUF_SIZE ((32+ETH_FRAME_LEN+31)&~0x1f)
+
+/*
+ * SCB defines
+ */
+
+/* these functions take the SCB status word and test the relevant status bit */
+#define SCB_complete(s) (((s) & 0x8000) != 0)
+#define SCB_rxdframe(s) (((s) & 0x4000) != 0)
+#define SCB_CUdead(s) (((s) & 0x2000) != 0)
+#define SCB_RUdead(s) (((s) & 0x1000) != 0)
+#define SCB_ack(s) ((s) & 0xf000)
+
+/* Command unit status: 0=idle, 1=suspended, 2=active */
+#define SCB_CUstat(s) (((s)&0x0300)>>8)
+
+/* Receive unit status: 0=idle, 1=suspended, 2=out of resources, 4=ready */
+#define SCB_RUstat(s) (((s)&0x0070)>>4)
+
+/* SCB commands */
+#define SCB_CUnop 0x0000
+#define SCB_CUstart 0x0100
+#define SCB_CUresume 0x0200
+#define SCB_CUsuspend 0x0300
+#define SCB_CUabort 0x0400
+#define SCB_resetchip 0x0080
+
+#define SCB_RUnop 0x0000
+#define SCB_RUstart 0x0010
+#define SCB_RUresume 0x0020
+#define SCB_RUsuspend 0x0030
+#define SCB_RUabort 0x0040
+
+/*
+ * Command block defines
+ */
+
+#define Stat_Done(s) (((s) & 0x8000) != 0)
+#define Stat_Busy(s) (((s) & 0x4000) != 0)
+#define Stat_OK(s) (((s) & 0x2000) != 0)
+#define Stat_Abort(s) (((s) & 0x1000) != 0)
+#define Stat_STFail (((s) & 0x0800) != 0)
+#define Stat_TNoCar(s) (((s) & 0x0400) != 0)
+#define Stat_TNoCTS(s) (((s) & 0x0200) != 0)
+#define Stat_TNoDMA(s) (((s) & 0x0100) != 0)
+#define Stat_TDefer(s) (((s) & 0x0080) != 0)
+#define Stat_TColl(s) (((s) & 0x0040) != 0)
+#define Stat_TXColl(s) (((s) & 0x0020) != 0)
+#define Stat_NoColl(s) ((s) & 0x000f)
+
+/* Cmd_END will end AFTER the command if this is the first
+ * command block after an SCB_CUstart, but BEFORE the command
+ * for all subsequent commands. Best strategy is to place
+ * Cmd_INT on the last command in the sequence, followed by a
+ * dummy Cmd_Nop with Cmd_END after this.
+ */
+
+#define Cmd_END 0x8000
+#define Cmd_SUS 0x4000
+#define Cmd_INT 0x2000
+
+#define Cmd_Nop 0x0000
+#define Cmd_SetAddr 0x0001
+#define Cmd_Config 0x0002
+#define Cmd_MCast 0x0003
+#define Cmd_Xmit 0x0004
+#define Cmd_TDR 0x0005
+#define Cmd_Dump 0x0006
+#define Cmd_Diag 0x0007
+
+
+/*
+ * Frame Descriptor (Receive block) defines
+ */
+
+#define FD_Done(s) (((s) & 0x8000) != 0)
+#define FD_Busy(s) (((s) & 0x4000) != 0)
+#define FD_OK(s) (((s) & 0x2000) != 0)
+
+#define FD_CRC(s) (((s) & 0x0800) != 0)
+#define FD_Align(s) (((s) & 0x0400) != 0)
+#define FD_Resrc(s) (((s) & 0x0200) != 0)
+#define FD_DMA(s) (((s) & 0x0100) != 0)
+#define FD_Short(s) (((s) & 0x0080) != 0)
+#define FD_NoEOF(s) (((s) & 0x0040) != 0)
+
+struct rfd_header {
+ volatile unsigned long flags;
+ volatile unsigned short link;
+ volatile unsigned short rbd_offset;
+ volatile unsigned short dstaddr1;
+ volatile unsigned short dstaddr2;
+ volatile unsigned short dstaddr3;
+ volatile unsigned short srcaddr1;
+ volatile unsigned short srcaddr2;
+ volatile unsigned short srcaddr3;
+ volatile unsigned short length;
+
+ /* This is actually a Receive Buffer Descriptor. The way we
+ * arrange memory means that an RBD always follows the RFD that
+ * points to it, so they might as well be in the same structure.
+ */
+ volatile unsigned short actual_count;
+ volatile unsigned short next_rbd;
+ volatile unsigned short buf_addr1;
+ volatile unsigned short buf_addr2;
+ volatile unsigned short size;
+};
+
+/* Returned data from the Time Domain Reflectometer */
+
+#define TDR_LINKOK (1<<15)
+#define TDR_XCVRPROBLEM (1<<14)
+#define TDR_OPEN (1<<13)
+#define TDR_SHORT (1<<12)
+#define TDR_TIME 0x7ff
--- /dev/null
+/*
+ * linux/drivers/acorn/net/ether1.c
+ *
+ * Copyright (C) 1996-2000 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Acorn ether1 driver (82586 chip) for Acorn machines
+ *
+ * We basically keep two queues in the cards memory - one for transmit
+ * and one for receive. Each has a head and a tail. The head is where
+ * we/the chip adds packets to be transmitted/received, and the tail
+ * is where the transmitter has got to/where the receiver will stop.
+ * Both of these queues are circular, and since the chip is running
+ * all the time, we have to be careful when we modify the pointers etc
+ * so that the buffer memory contents is valid all the time.
+ *
+ * Change log:
+ * 1.00 RMK Released
+ * 1.01 RMK 19/03/1996 Transfers the last odd byte onto/off of the card now.
+ * 1.02 RMK 25/05/1997 Added code to restart RU if it goes not ready
+ * 1.03 RMK 14/09/1997 Cleaned up the handling of a reset during the TX interrupt.
+ * Should prevent lockup.
+ * 1.04 RMK 17/09/1997 Added more info when initialsation of chip goes wrong.
+ * TDR now only reports failure when chip reports non-zero
+ * TDR time-distance.
+ * 1.05 RMK 31/12/1997 Removed calls to dev_tint for 2.1
+ * 1.06 RMK 10/02/2000 Updated for 2.3.43
+ * 1.07 RMK 13/05/2000 Updated for 2.3.99-pre8
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/bitops.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/ecard.h>
+
+#define __ETHER1_C
+#include "ether1.h"
+
+static unsigned int net_debug = NET_DEBUG;
+
+#define BUFFER_SIZE 0x10000
+#define TX_AREA_START 0x00100
+#define TX_AREA_END 0x05000
+#define RX_AREA_START 0x05000
+#define RX_AREA_END 0x0fc00
+
+static int ether1_open(struct net_device *dev);
+static int ether1_sendpacket(struct sk_buff *skb, struct net_device *dev);
+static irqreturn_t ether1_interrupt(int irq, void *dev_id);
+static int ether1_close(struct net_device *dev);
+static void ether1_setmulticastlist(struct net_device *dev);
+static void ether1_timeout(struct net_device *dev);
+
+/* ------------------------------------------------------------------------- */
+
+static char version[] __devinitdata = "ether1 ethernet driver (c) 2000 Russell King v1.07\n";
+
+#define BUS_16 16
+#define BUS_8 8
+
+/* ------------------------------------------------------------------------- */
+
+#define DISABLEIRQS 1
+#define NORMALIRQS 0
+
+#define ether1_readw(dev, addr, type, offset, svflgs) ether1_inw_p (dev, addr + (int)(&((type *)0)->offset), svflgs)
+#define ether1_writew(dev, val, addr, type, offset, svflgs) ether1_outw_p (dev, val, addr + (int)(&((type *)0)->offset), svflgs)
+
+static inline unsigned short
+ether1_inw_p (struct net_device *dev, int addr, int svflgs)
+{
+ unsigned long flags;
+ unsigned short ret;
+
+ if (svflgs)
+ local_irq_save (flags);
+
+ writeb(addr >> 12, REG_PAGE);
+ ret = readw(ETHER1_RAM + ((addr & 4095) << 1));
+ if (svflgs)
+ local_irq_restore (flags);
+ return ret;
+}
+
+static inline void
+ether1_outw_p (struct net_device *dev, unsigned short val, int addr, int svflgs)
+{
+ unsigned long flags;
+
+ if (svflgs)
+ local_irq_save (flags);
+
+ writeb(addr >> 12, REG_PAGE);
+ writew(val, ETHER1_RAM + ((addr & 4095) << 1));
+ if (svflgs)
+ local_irq_restore (flags);
+}
+
+/*
+ * Some inline assembler to allow fast transfers on to/off of the card.
+ * Since this driver depends on some features presented by the ARM
+ * specific architecture, and that you can't configure this driver
+ * without specifiing ARM mode, this is not a problem.
+ *
+ * This routine is essentially an optimised memcpy from the card's
+ * onboard RAM to kernel memory.
+ */
+static void
+ether1_writebuffer (struct net_device *dev, void *data, unsigned int start, unsigned int length)
+{
+ unsigned int page, thislen, offset;
+ void __iomem *addr;
+
+ offset = start & 4095;
+ page = start >> 12;
+ addr = ETHER1_RAM + (offset << 1);
+
+ if (offset + length > 4096)
+ thislen = 4096 - offset;
+ else
+ thislen = length;
+
+ do {
+ int used;
+
+ writeb(page, REG_PAGE);
+ length -= thislen;
+
+ __asm__ __volatile__(
+ "subs %3, %3, #2\n\
+ bmi 2f\n\
+1: ldr %0, [%1], #2\n\
+ mov %0, %0, lsl #16\n\
+ orr %0, %0, %0, lsr #16\n\
+ str %0, [%2], #4\n\
+ subs %3, %3, #2\n\
+ bmi 2f\n\
+ ldr %0, [%1], #2\n\
+ mov %0, %0, lsl #16\n\
+ orr %0, %0, %0, lsr #16\n\
+ str %0, [%2], #4\n\
+ subs %3, %3, #2\n\
+ bmi 2f\n\
+ ldr %0, [%1], #2\n\
+ mov %0, %0, lsl #16\n\
+ orr %0, %0, %0, lsr #16\n\
+ str %0, [%2], #4\n\
+ subs %3, %3, #2\n\
+ bmi 2f\n\
+ ldr %0, [%1], #2\n\
+ mov %0, %0, lsl #16\n\
+ orr %0, %0, %0, lsr #16\n\
+ str %0, [%2], #4\n\
+ subs %3, %3, #2\n\
+ bpl 1b\n\
+2: adds %3, %3, #1\n\
+ ldreqb %0, [%1]\n\
+ streqb %0, [%2]"
+ : "=&r" (used), "=&r" (data)
+ : "r" (addr), "r" (thislen), "1" (data));
+
+ addr = ETHER1_RAM;
+
+ thislen = length;
+ if (thislen > 4096)
+ thislen = 4096;
+ page++;
+ } while (thislen);
+}
+
+static void
+ether1_readbuffer (struct net_device *dev, void *data, unsigned int start, unsigned int length)
+{
+ unsigned int page, thislen, offset;
+ void __iomem *addr;
+
+ offset = start & 4095;
+ page = start >> 12;
+ addr = ETHER1_RAM + (offset << 1);
+
+ if (offset + length > 4096)
+ thislen = 4096 - offset;
+ else
+ thislen = length;
+
+ do {
+ int used;
+
+ writeb(page, REG_PAGE);
+ length -= thislen;
+
+ __asm__ __volatile__(
+ "subs %3, %3, #2\n\
+ bmi 2f\n\
+1: ldr %0, [%2], #4\n\
+ strb %0, [%1], #1\n\
+ mov %0, %0, lsr #8\n\
+ strb %0, [%1], #1\n\
+ subs %3, %3, #2\n\
+ bmi 2f\n\
+ ldr %0, [%2], #4\n\
+ strb %0, [%1], #1\n\
+ mov %0, %0, lsr #8\n\
+ strb %0, [%1], #1\n\
+ subs %3, %3, #2\n\
+ bmi 2f\n\
+ ldr %0, [%2], #4\n\
+ strb %0, [%1], #1\n\
+ mov %0, %0, lsr #8\n\
+ strb %0, [%1], #1\n\
+ subs %3, %3, #2\n\
+ bmi 2f\n\
+ ldr %0, [%2], #4\n\
+ strb %0, [%1], #1\n\
+ mov %0, %0, lsr #8\n\
+ strb %0, [%1], #1\n\
+ subs %3, %3, #2\n\
+ bpl 1b\n\
+2: adds %3, %3, #1\n\
+ ldreqb %0, [%2]\n\
+ streqb %0, [%1]"
+ : "=&r" (used), "=&r" (data)
+ : "r" (addr), "r" (thislen), "1" (data));
+
+ addr = ETHER1_RAM;
+
+ thislen = length;
+ if (thislen > 4096)
+ thislen = 4096;
+ page++;
+ } while (thislen);
+}
+
+static int __devinit
+ether1_ramtest(struct net_device *dev, unsigned char byte)
+{
+ unsigned char *buffer = kmalloc (BUFFER_SIZE, GFP_KERNEL);
+ int i, ret = BUFFER_SIZE;
+ int max_errors = 15;
+ int bad = -1;
+ int bad_start = 0;
+
+ if (!buffer)
+ return 1;
+
+ memset (buffer, byte, BUFFER_SIZE);
+ ether1_writebuffer (dev, buffer, 0, BUFFER_SIZE);
+ memset (buffer, byte ^ 0xff, BUFFER_SIZE);
+ ether1_readbuffer (dev, buffer, 0, BUFFER_SIZE);
+
+ for (i = 0; i < BUFFER_SIZE; i++) {
+ if (buffer[i] != byte) {
+ if (max_errors >= 0 && bad != buffer[i]) {
+ if (bad != -1)
+ printk ("\n");
+ printk (KERN_CRIT "%s: RAM failed with (%02X instead of %02X) at 0x%04X",
+ dev->name, buffer[i], byte, i);
+ ret = -ENODEV;
+ max_errors --;
+ bad = buffer[i];
+ bad_start = i;
+ }
+ } else {
+ if (bad != -1) {
+ if (bad_start == i - 1)
+ printk ("\n");
+ else
+ printk (" - 0x%04X\n", i - 1);
+ bad = -1;
+ }
+ }
+ }
+
+ if (bad != -1)
+ printk (" - 0x%04X\n", BUFFER_SIZE);
+ kfree (buffer);
+
+ return ret;
+}
+
+static int
+ether1_reset (struct net_device *dev)
+{
+ writeb(CTRL_RST|CTRL_ACK, REG_CONTROL);
+ return BUS_16;
+}
+
+static int __devinit
+ether1_init_2(struct net_device *dev)
+{
+ int i;
+ dev->mem_start = 0;
+
+ i = ether1_ramtest (dev, 0x5a);
+
+ if (i > 0)
+ i = ether1_ramtest (dev, 0x1e);
+
+ if (i <= 0)
+ return -ENODEV;
+
+ dev->mem_end = i;
+ return 0;
+}
+
+/*
+ * These are the structures that are loaded into the ether RAM card to
+ * initialise the 82586
+ */
+
+/* at 0x0100 */
+#define NOP_ADDR (TX_AREA_START)
+#define NOP_SIZE (0x06)
+static nop_t init_nop = {
+ 0,
+ CMD_NOP,
+ NOP_ADDR
+};
+
+/* at 0x003a */
+#define TDR_ADDR (0x003a)
+#define TDR_SIZE (0x08)
+static tdr_t init_tdr = {
+ 0,
+ CMD_TDR | CMD_INTR,
+ NOP_ADDR,
+ 0
+};
+
+/* at 0x002e */
+#define MC_ADDR (0x002e)
+#define MC_SIZE (0x0c)
+static mc_t init_mc = {
+ 0,
+ CMD_SETMULTICAST,
+ TDR_ADDR,
+ 0,
+ { { 0, } }
+};
+
+/* at 0x0022 */
+#define SA_ADDR (0x0022)
+#define SA_SIZE (0x0c)
+static sa_t init_sa = {
+ 0,
+ CMD_SETADDRESS,
+ MC_ADDR,
+ { 0, }
+};
+
+/* at 0x0010 */
+#define CFG_ADDR (0x0010)
+#define CFG_SIZE (0x12)
+static cfg_t init_cfg = {
+ 0,
+ CMD_CONFIG,
+ SA_ADDR,
+ 8,
+ 8,
+ CFG8_SRDY,
+ CFG9_PREAMB8 | CFG9_ADDRLENBUF | CFG9_ADDRLEN(6),
+ 0,
+ 0x60,
+ 0,
+ CFG13_RETRY(15) | CFG13_SLOTH(2),
+ 0,
+};
+
+/* at 0x0000 */
+#define SCB_ADDR (0x0000)
+#define SCB_SIZE (0x10)
+static scb_t init_scb = {
+ 0,
+ SCB_CMDACKRNR | SCB_CMDACKCNA | SCB_CMDACKFR | SCB_CMDACKCX,
+ CFG_ADDR,
+ RX_AREA_START,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+/* at 0xffee */
+#define ISCP_ADDR (0xffee)
+#define ISCP_SIZE (0x08)
+static iscp_t init_iscp = {
+ 1,
+ SCB_ADDR,
+ 0x0000,
+ 0x0000
+};
+
+/* at 0xfff6 */
+#define SCP_ADDR (0xfff6)
+#define SCP_SIZE (0x0a)
+static scp_t init_scp = {
+ SCP_SY_16BBUS,
+ { 0, 0 },
+ ISCP_ADDR,
+ 0
+};
+
+#define RFD_SIZE (0x16)
+static rfd_t init_rfd = {
+ 0,
+ 0,
+ 0,
+ 0,
+ { 0, },
+ { 0, },
+ 0
+};
+
+#define RBD_SIZE (0x0a)
+static rbd_t init_rbd = {
+ 0,
+ 0,
+ 0,
+ 0,
+ ETH_FRAME_LEN + 8
+};
+
+#define TX_SIZE (0x08)
+#define TBD_SIZE (0x08)
+
+static int
+ether1_init_for_open (struct net_device *dev)
+{
+ int i, status, addr, next, next2;
+ int failures = 0;
+ unsigned long timeout;
+
+ writeb(CTRL_RST|CTRL_ACK, REG_CONTROL);
+
+ for (i = 0; i < 6; i++)
+ init_sa.sa_addr[i] = dev->dev_addr[i];
+
+ /* load data structures into ether1 RAM */
+ ether1_writebuffer (dev, &init_scp, SCP_ADDR, SCP_SIZE);
+ ether1_writebuffer (dev, &init_iscp, ISCP_ADDR, ISCP_SIZE);
+ ether1_writebuffer (dev, &init_scb, SCB_ADDR, SCB_SIZE);
+ ether1_writebuffer (dev, &init_cfg, CFG_ADDR, CFG_SIZE);
+ ether1_writebuffer (dev, &init_sa, SA_ADDR, SA_SIZE);
+ ether1_writebuffer (dev, &init_mc, MC_ADDR, MC_SIZE);
+ ether1_writebuffer (dev, &init_tdr, TDR_ADDR, TDR_SIZE);
+ ether1_writebuffer (dev, &init_nop, NOP_ADDR, NOP_SIZE);
+
+ if (ether1_readw(dev, CFG_ADDR, cfg_t, cfg_command, NORMALIRQS) != CMD_CONFIG) {
+ printk (KERN_ERR "%s: detected either RAM fault or compiler bug\n",
+ dev->name);
+ return 1;
+ }
+
+ /*
+ * setup circularly linked list of { rfd, rbd, buffer }, with
+ * all rfds circularly linked, rbds circularly linked.
+ * First rfd is linked to scp, first rbd is linked to first
+ * rfd. Last rbd has a suspend command.
+ */
+ addr = RX_AREA_START;
+ do {
+ next = addr + RFD_SIZE + RBD_SIZE + ETH_FRAME_LEN + 10;
+ next2 = next + RFD_SIZE + RBD_SIZE + ETH_FRAME_LEN + 10;
+
+ if (next2 >= RX_AREA_END) {
+ next = RX_AREA_START;
+ init_rfd.rfd_command = RFD_CMDEL | RFD_CMDSUSPEND;
+ priv(dev)->rx_tail = addr;
+ } else
+ init_rfd.rfd_command = 0;
+ if (addr == RX_AREA_START)
+ init_rfd.rfd_rbdoffset = addr + RFD_SIZE;
+ else
+ init_rfd.rfd_rbdoffset = 0;
+ init_rfd.rfd_link = next;
+ init_rbd.rbd_link = next + RFD_SIZE;
+ init_rbd.rbd_bufl = addr + RFD_SIZE + RBD_SIZE;
+
+ ether1_writebuffer (dev, &init_rfd, addr, RFD_SIZE);
+ ether1_writebuffer (dev, &init_rbd, addr + RFD_SIZE, RBD_SIZE);
+ addr = next;
+ } while (next2 < RX_AREA_END);
+
+ priv(dev)->tx_link = NOP_ADDR;
+ priv(dev)->tx_head = NOP_ADDR + NOP_SIZE;
+ priv(dev)->tx_tail = TDR_ADDR;
+ priv(dev)->rx_head = RX_AREA_START;
+
+ /* release reset & give 586 a prod */
+ priv(dev)->resetting = 1;
+ priv(dev)->initialising = 1;
+ writeb(CTRL_RST, REG_CONTROL);
+ writeb(0, REG_CONTROL);
+ writeb(CTRL_CA, REG_CONTROL);
+
+ /* 586 should now unset iscp.busy */
+ timeout = jiffies + HZ/2;
+ while (ether1_readw(dev, ISCP_ADDR, iscp_t, iscp_busy, DISABLEIRQS) == 1) {
+ if (time_after(jiffies, timeout)) {
+ printk (KERN_WARNING "%s: can't initialise 82586: iscp is busy\n", dev->name);
+ return 1;
+ }
+ }
+
+ /* check status of commands that we issued */
+ timeout += HZ/10;
+ while (((status = ether1_readw(dev, CFG_ADDR, cfg_t, cfg_status, DISABLEIRQS))
+ & STAT_COMPLETE) == 0) {
+ if (time_after(jiffies, timeout))
+ break;
+ }
+
+ if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) {
+ printk (KERN_WARNING "%s: can't initialise 82586: config status %04X\n", dev->name, status);
+ printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name,
+ ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS),
+ ether1_readw(dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS),
+ ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS),
+ ether1_readw(dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS));
+ failures += 1;
+ }
+
+ timeout += HZ/10;
+ while (((status = ether1_readw(dev, SA_ADDR, sa_t, sa_status, DISABLEIRQS))
+ & STAT_COMPLETE) == 0) {
+ if (time_after(jiffies, timeout))
+ break;
+ }
+
+ if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) {
+ printk (KERN_WARNING "%s: can't initialise 82586: set address status %04X\n", dev->name, status);
+ printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name,
+ ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS),
+ ether1_readw(dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS),
+ ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS),
+ ether1_readw(dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS));
+ failures += 1;
+ }
+
+ timeout += HZ/10;
+ while (((status = ether1_readw(dev, MC_ADDR, mc_t, mc_status, DISABLEIRQS))
+ & STAT_COMPLETE) == 0) {
+ if (time_after(jiffies, timeout))
+ break;
+ }
+
+ if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) {
+ printk (KERN_WARNING "%s: can't initialise 82586: set multicast status %04X\n", dev->name, status);
+ printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name,
+ ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS),
+ ether1_readw(dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS),
+ ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS),
+ ether1_readw(dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS));
+ failures += 1;
+ }
+
+ timeout += HZ;
+ while (((status = ether1_readw(dev, TDR_ADDR, tdr_t, tdr_status, DISABLEIRQS))
+ & STAT_COMPLETE) == 0) {
+ if (time_after(jiffies, timeout))
+ break;
+ }
+
+ if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) {
+ printk (KERN_WARNING "%s: can't tdr (ignored)\n", dev->name);
+ printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name,
+ ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS),
+ ether1_readw(dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS),
+ ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS),
+ ether1_readw(dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS));
+ } else {
+ status = ether1_readw(dev, TDR_ADDR, tdr_t, tdr_result, DISABLEIRQS);
+ if (status & TDR_XCVRPROB)
+ printk (KERN_WARNING "%s: i/f failed tdr: transceiver problem\n", dev->name);
+ else if ((status & (TDR_SHORT|TDR_OPEN)) && (status & TDR_TIME)) {
+#ifdef FANCY
+ printk (KERN_WARNING "%s: i/f failed tdr: cable %s %d.%d us away\n", dev->name,
+ status & TDR_SHORT ? "short" : "open", (status & TDR_TIME) / 10,
+ (status & TDR_TIME) % 10);
+#else
+ printk (KERN_WARNING "%s: i/f failed tdr: cable %s %d clks away\n", dev->name,
+ status & TDR_SHORT ? "short" : "open", (status & TDR_TIME));
+#endif
+ }
+ }
+
+ if (failures)
+ ether1_reset (dev);
+ return failures ? 1 : 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int
+ether1_txalloc (struct net_device *dev, int size)
+{
+ int start, tail;
+
+ size = (size + 1) & ~1;
+ tail = priv(dev)->tx_tail;
+
+ if (priv(dev)->tx_head + size > TX_AREA_END) {
+ if (tail > priv(dev)->tx_head)
+ return -1;
+ start = TX_AREA_START;
+ if (start + size > tail)
+ return -1;
+ priv(dev)->tx_head = start + size;
+ } else {
+ if (priv(dev)->tx_head < tail && (priv(dev)->tx_head + size) > tail)
+ return -1;
+ start = priv(dev)->tx_head;
+ priv(dev)->tx_head += size;
+ }
+
+ return start;
+}
+
+static int
+ether1_open (struct net_device *dev)
+{
+ if (!is_valid_ether_addr(dev->dev_addr)) {
+ printk(KERN_WARNING "%s: invalid ethernet MAC address\n",
+ dev->name);
+ return -EINVAL;
+ }
+
+ if (request_irq(dev->irq, ether1_interrupt, 0, "ether1", dev))
+ return -EAGAIN;
+
+ if (ether1_init_for_open (dev)) {
+ free_irq (dev->irq, dev);
+ return -EAGAIN;
+ }
+
+ netif_start_queue(dev);
+
+ return 0;
+}
+
+static void
+ether1_timeout(struct net_device *dev)
+{
+ printk(KERN_WARNING "%s: transmit timeout, network cable problem?\n",
+ dev->name);
+ printk(KERN_WARNING "%s: resetting device\n", dev->name);
+
+ ether1_reset (dev);
+
+ if (ether1_init_for_open (dev))
+ printk (KERN_ERR "%s: unable to restart interface\n", dev->name);
+
+ dev->stats.tx_errors++;
+ netif_wake_queue(dev);
+}
+
+static int
+ether1_sendpacket (struct sk_buff *skb, struct net_device *dev)
+{
+ int tmp, tst, nopaddr, txaddr, tbdaddr, dataddr;
+ unsigned long flags;
+ tx_t tx;
+ tbd_t tbd;
+ nop_t nop;
+
+ if (priv(dev)->restart) {
+ printk(KERN_WARNING "%s: resetting device\n", dev->name);
+
+ ether1_reset(dev);
+
+ if (ether1_init_for_open(dev))
+ printk(KERN_ERR "%s: unable to restart interface\n", dev->name);
+ else
+ priv(dev)->restart = 0;
+ }
+
+ if (skb->len < ETH_ZLEN) {
+ if (skb_padto(skb, ETH_ZLEN))
+ goto out;
+ }
+
+ /*
+ * insert packet followed by a nop
+ */
+ txaddr = ether1_txalloc (dev, TX_SIZE);
+ tbdaddr = ether1_txalloc (dev, TBD_SIZE);
+ dataddr = ether1_txalloc (dev, skb->len);
+ nopaddr = ether1_txalloc (dev, NOP_SIZE);
+
+ tx.tx_status = 0;
+ tx.tx_command = CMD_TX | CMD_INTR;
+ tx.tx_link = nopaddr;
+ tx.tx_tbdoffset = tbdaddr;
+ tbd.tbd_opts = TBD_EOL | skb->len;
+ tbd.tbd_link = I82586_NULL;
+ tbd.tbd_bufl = dataddr;
+ tbd.tbd_bufh = 0;
+ nop.nop_status = 0;
+ nop.nop_command = CMD_NOP;
+ nop.nop_link = nopaddr;
+
+ local_irq_save(flags);
+ ether1_writebuffer (dev, &tx, txaddr, TX_SIZE);
+ ether1_writebuffer (dev, &tbd, tbdaddr, TBD_SIZE);
+ ether1_writebuffer (dev, skb->data, dataddr, skb->len);
+ ether1_writebuffer (dev, &nop, nopaddr, NOP_SIZE);
+ tmp = priv(dev)->tx_link;
+ priv(dev)->tx_link = nopaddr;
+
+ /* now reset the previous nop pointer */
+ ether1_writew(dev, txaddr, tmp, nop_t, nop_link, NORMALIRQS);
+
+ local_irq_restore(flags);
+
+ /* handle transmit */
+
+ /* check to see if we have room for a full sized ether frame */
+ tmp = priv(dev)->tx_head;
+ tst = ether1_txalloc (dev, TX_SIZE + TBD_SIZE + NOP_SIZE + ETH_FRAME_LEN);
+ priv(dev)->tx_head = tmp;
+ dev_kfree_skb (skb);
+
+ if (tst == -1)
+ netif_stop_queue(dev);
+
+ out:
+ return NETDEV_TX_OK;
+}
+
+static void
+ether1_xmit_done (struct net_device *dev)
+{
+ nop_t nop;
+ int caddr, tst;
+
+ caddr = priv(dev)->tx_tail;
+
+again:
+ ether1_readbuffer (dev, &nop, caddr, NOP_SIZE);
+
+ switch (nop.nop_command & CMD_MASK) {
+ case CMD_TDR:
+ /* special case */
+ if (ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS)
+ != (unsigned short)I82586_NULL) {
+ ether1_writew(dev, SCB_CMDCUCSTART | SCB_CMDRXSTART, SCB_ADDR, scb_t,
+ scb_command, NORMALIRQS);
+ writeb(CTRL_CA, REG_CONTROL);
+ }
+ priv(dev)->tx_tail = NOP_ADDR;
+ return;
+
+ case CMD_NOP:
+ if (nop.nop_link == caddr) {
+ if (priv(dev)->initialising == 0)
+ printk (KERN_WARNING "%s: strange command complete with no tx command!\n", dev->name);
+ else
+ priv(dev)->initialising = 0;
+ return;
+ }
+ if (caddr == nop.nop_link)
+ return;
+ caddr = nop.nop_link;
+ goto again;
+
+ case CMD_TX:
+ if (nop.nop_status & STAT_COMPLETE)
+ break;
+ printk (KERN_ERR "%s: strange command complete without completed command\n", dev->name);
+ priv(dev)->restart = 1;
+ return;
+
+ default:
+ printk (KERN_WARNING "%s: strange command %d complete! (offset %04X)", dev->name,
+ nop.nop_command & CMD_MASK, caddr);
+ priv(dev)->restart = 1;
+ return;
+ }
+
+ while (nop.nop_status & STAT_COMPLETE) {
+ if (nop.nop_status & STAT_OK) {
+ dev->stats.tx_packets++;
+ dev->stats.collisions += (nop.nop_status & STAT_COLLISIONS);
+ } else {
+ dev->stats.tx_errors++;
+
+ if (nop.nop_status & STAT_COLLAFTERTX)
+ dev->stats.collisions++;
+ if (nop.nop_status & STAT_NOCARRIER)
+ dev->stats.tx_carrier_errors++;
+ if (nop.nop_status & STAT_TXLOSTCTS)
+ printk (KERN_WARNING "%s: cts lost\n", dev->name);
+ if (nop.nop_status & STAT_TXSLOWDMA)
+ dev->stats.tx_fifo_errors++;
+ if (nop.nop_status & STAT_COLLEXCESSIVE)
+ dev->stats.collisions += 16;
+ }
+
+ if (nop.nop_link == caddr) {
+ printk (KERN_ERR "%s: tx buffer chaining error: tx command points to itself\n", dev->name);
+ break;
+ }
+
+ caddr = nop.nop_link;
+ ether1_readbuffer (dev, &nop, caddr, NOP_SIZE);
+ if ((nop.nop_command & CMD_MASK) != CMD_NOP) {
+ printk (KERN_ERR "%s: tx buffer chaining error: no nop after tx command\n", dev->name);
+ break;
+ }
+
+ if (caddr == nop.nop_link)
+ break;
+
+ caddr = nop.nop_link;
+ ether1_readbuffer (dev, &nop, caddr, NOP_SIZE);
+ if ((nop.nop_command & CMD_MASK) != CMD_TX) {
+ printk (KERN_ERR "%s: tx buffer chaining error: no tx command after nop\n", dev->name);
+ break;
+ }
+ }
+ priv(dev)->tx_tail = caddr;
+
+ caddr = priv(dev)->tx_head;
+ tst = ether1_txalloc (dev, TX_SIZE + TBD_SIZE + NOP_SIZE + ETH_FRAME_LEN);
+ priv(dev)->tx_head = caddr;
+ if (tst != -1)
+ netif_wake_queue(dev);
+}
+
+static void
+ether1_recv_done (struct net_device *dev)
+{
+ int status;
+ int nexttail, rbdaddr;
+ rbd_t rbd;
+
+ do {
+ status = ether1_readw(dev, priv(dev)->rx_head, rfd_t, rfd_status, NORMALIRQS);
+ if ((status & RFD_COMPLETE) == 0)
+ break;
+
+ rbdaddr = ether1_readw(dev, priv(dev)->rx_head, rfd_t, rfd_rbdoffset, NORMALIRQS);
+ ether1_readbuffer (dev, &rbd, rbdaddr, RBD_SIZE);
+
+ if ((rbd.rbd_status & (RBD_EOF | RBD_ACNTVALID)) == (RBD_EOF | RBD_ACNTVALID)) {
+ int length = rbd.rbd_status & RBD_ACNT;
+ struct sk_buff *skb;
+
+ length = (length + 1) & ~1;
+ skb = dev_alloc_skb (length + 2);
+
+ if (skb) {
+ skb_reserve (skb, 2);
+
+ ether1_readbuffer (dev, skb_put (skb, length), rbd.rbd_bufl, length);
+
+ skb->protocol = eth_type_trans (skb, dev);
+ netif_rx (skb);
+ dev->stats.rx_packets++;
+ } else
+ dev->stats.rx_dropped++;
+ } else {
+ printk(KERN_WARNING "%s: %s\n", dev->name,
+ (rbd.rbd_status & RBD_EOF) ? "oversized packet" : "acnt not valid");
+ dev->stats.rx_dropped++;
+ }
+
+ nexttail = ether1_readw(dev, priv(dev)->rx_tail, rfd_t, rfd_link, NORMALIRQS);
+ /* nexttail should be rx_head */
+ if (nexttail != priv(dev)->rx_head)
+ printk(KERN_ERR "%s: receiver buffer chaining error (%04X != %04X)\n",
+ dev->name, nexttail, priv(dev)->rx_head);
+ ether1_writew(dev, RFD_CMDEL | RFD_CMDSUSPEND, nexttail, rfd_t, rfd_command, NORMALIRQS);
+ ether1_writew(dev, 0, priv(dev)->rx_tail, rfd_t, rfd_command, NORMALIRQS);
+ ether1_writew(dev, 0, priv(dev)->rx_tail, rfd_t, rfd_status, NORMALIRQS);
+ ether1_writew(dev, 0, priv(dev)->rx_tail, rfd_t, rfd_rbdoffset, NORMALIRQS);
+
+ priv(dev)->rx_tail = nexttail;
+ priv(dev)->rx_head = ether1_readw(dev, priv(dev)->rx_head, rfd_t, rfd_link, NORMALIRQS);
+ } while (1);
+}
+
+static irqreturn_t
+ether1_interrupt (int irq, void *dev_id)
+{
+ struct net_device *dev = (struct net_device *)dev_id;
+ int status;
+
+ status = ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS);
+
+ if (status) {
+ ether1_writew(dev, status & (SCB_STRNR | SCB_STCNA | SCB_STFR | SCB_STCX),
+ SCB_ADDR, scb_t, scb_command, NORMALIRQS);
+ writeb(CTRL_CA | CTRL_ACK, REG_CONTROL);
+ if (status & SCB_STCX) {
+ ether1_xmit_done (dev);
+ }
+ if (status & SCB_STCNA) {
+ if (priv(dev)->resetting == 0)
+ printk (KERN_WARNING "%s: CU went not ready ???\n", dev->name);
+ else
+ priv(dev)->resetting += 1;
+ if (ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS)
+ != (unsigned short)I82586_NULL) {
+ ether1_writew(dev, SCB_CMDCUCSTART, SCB_ADDR, scb_t, scb_command, NORMALIRQS);
+ writeb(CTRL_CA, REG_CONTROL);
+ }
+ if (priv(dev)->resetting == 2)
+ priv(dev)->resetting = 0;
+ }
+ if (status & SCB_STFR) {
+ ether1_recv_done (dev);
+ }
+ if (status & SCB_STRNR) {
+ if (ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS) & SCB_STRXSUSP) {
+ printk (KERN_WARNING "%s: RU went not ready: RU suspended\n", dev->name);
+ ether1_writew(dev, SCB_CMDRXRESUME, SCB_ADDR, scb_t, scb_command, NORMALIRQS);
+ writeb(CTRL_CA, REG_CONTROL);
+ dev->stats.rx_dropped++; /* we suspended due to lack of buffer space */
+ } else
+ printk(KERN_WARNING "%s: RU went not ready: %04X\n", dev->name,
+ ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS));
+ printk (KERN_WARNING "RU ptr = %04X\n", ether1_readw(dev, SCB_ADDR, scb_t, scb_rfa_offset,
+ NORMALIRQS));
+ }
+ } else
+ writeb(CTRL_ACK, REG_CONTROL);
+
+ return IRQ_HANDLED;
+}
+
+static int
+ether1_close (struct net_device *dev)
+{
+ ether1_reset (dev);
+
+ free_irq(dev->irq, dev);
+
+ return 0;
+}
+
+/*
+ * Set or clear the multicast filter for this adaptor.
+ * num_addrs == -1 Promiscuous mode, receive all packets.
+ * num_addrs == 0 Normal mode, clear multicast list.
+ * num_addrs > 0 Multicast mode, receive normal and MC packets, and do
+ * best-effort filtering.
+ */
+static void
+ether1_setmulticastlist (struct net_device *dev)
+{
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void __devinit ether1_banner(void)
+{
+ static unsigned int version_printed = 0;
+
+ if (net_debug && version_printed++ == 0)
+ printk(KERN_INFO "%s", version);
+}
+
+static const struct net_device_ops ether1_netdev_ops = {
+ .ndo_open = ether1_open,
+ .ndo_stop = ether1_close,
+ .ndo_start_xmit = ether1_sendpacket,
+ .ndo_set_multicast_list = ether1_setmulticastlist,
+ .ndo_tx_timeout = ether1_timeout,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_change_mtu = eth_change_mtu,
+ .ndo_set_mac_address = eth_mac_addr,
+};
+
+static int __devinit
+ether1_probe(struct expansion_card *ec, const struct ecard_id *id)
+{
+ struct net_device *dev;
+ int i, ret = 0;
+
+ ether1_banner();
+
+ ret = ecard_request_resources(ec);
+ if (ret)
+ goto out;
+
+ dev = alloc_etherdev(sizeof(struct ether1_priv));
+ if (!dev) {
+ ret = -ENOMEM;
+ goto release;
+ }
+
+ SET_NETDEV_DEV(dev, &ec->dev);
+
+ dev->irq = ec->irq;
+ priv(dev)->base = ecardm_iomap(ec, ECARD_RES_IOCFAST, 0, 0);
+ if (!priv(dev)->base) {
+ ret = -ENOMEM;
+ goto free;
+ }
+
+ if ((priv(dev)->bus_type = ether1_reset(dev)) == 0) {
+ ret = -ENODEV;
+ goto free;
+ }
+
+ for (i = 0; i < 6; i++)
+ dev->dev_addr[i] = readb(IDPROM_ADDRESS + (i << 2));
+
+ if (ether1_init_2(dev)) {
+ ret = -ENODEV;
+ goto free;
+ }
+
+ dev->netdev_ops = ðer1_netdev_ops;
+ dev->watchdog_timeo = 5 * HZ / 100;
+
+ ret = register_netdev(dev);
+ if (ret)
+ goto free;
+
+ printk(KERN_INFO "%s: ether1 in slot %d, %pM\n",
+ dev->name, ec->slot_no, dev->dev_addr);
+
+ ecard_set_drvdata(ec, dev);
+ return 0;
+
+ free:
+ free_netdev(dev);
+ release:
+ ecard_release_resources(ec);
+ out:
+ return ret;
+}
+
+static void __devexit ether1_remove(struct expansion_card *ec)
+{
+ struct net_device *dev = ecard_get_drvdata(ec);
+
+ ecard_set_drvdata(ec, NULL);
+
+ unregister_netdev(dev);
+ free_netdev(dev);
+ ecard_release_resources(ec);
+}
+
+static const struct ecard_id ether1_ids[] = {
+ { MANU_ACORN, PROD_ACORN_ETHER1 },
+ { 0xffff, 0xffff }
+};
+
+static struct ecard_driver ether1_driver = {
+ .probe = ether1_probe,
+ .remove = __devexit_p(ether1_remove),
+ .id_table = ether1_ids,
+ .drv = {
+ .name = "ether1",
+ },
+};
+
+static int __init ether1_init(void)
+{
+ return ecard_register_driver(ðer1_driver);
+}
+
+static void __exit ether1_exit(void)
+{
+ ecard_remove_driver(ðer1_driver);
+}
+
+module_init(ether1_init);
+module_exit(ether1_exit);
+
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * linux/drivers/acorn/net/ether1.h
+ *
+ * Copyright (C) 1996 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Network driver for Acorn Ether1 cards.
+ */
+
+#ifndef _LINUX_ether1_H
+#define _LINUX_ether1_H
+
+#ifdef __ETHER1_C
+/* use 0 for production, 1 for verification, >2 for debug */
+#ifndef NET_DEBUG
+#define NET_DEBUG 0
+#endif
+
+#define priv(dev) ((struct ether1_priv *)netdev_priv(dev))
+
+/* Page register */
+#define REG_PAGE (priv(dev)->base + 0x0000)
+
+/* Control register */
+#define REG_CONTROL (priv(dev)->base + 0x0004)
+#define CTRL_RST 0x01
+#define CTRL_LOOPBACK 0x02
+#define CTRL_CA 0x04
+#define CTRL_ACK 0x08
+
+#define ETHER1_RAM (priv(dev)->base + 0x2000)
+
+/* HW address */
+#define IDPROM_ADDRESS (priv(dev)->base + 0x0024)
+
+struct ether1_priv {
+ void __iomem *base;
+ unsigned int tx_link;
+ unsigned int tx_head;
+ volatile unsigned int tx_tail;
+ volatile unsigned int rx_head;
+ volatile unsigned int rx_tail;
+ unsigned char bus_type;
+ unsigned char resetting;
+ unsigned char initialising : 1;
+ unsigned char restart : 1;
+};
+
+#define I82586_NULL (-1)
+
+typedef struct { /* tdr */
+ unsigned short tdr_status;
+ unsigned short tdr_command;
+ unsigned short tdr_link;
+ unsigned short tdr_result;
+#define TDR_TIME (0x7ff)
+#define TDR_SHORT (1 << 12)
+#define TDR_OPEN (1 << 13)
+#define TDR_XCVRPROB (1 << 14)
+#define TDR_LNKOK (1 << 15)
+} tdr_t;
+
+typedef struct { /* transmit */
+ unsigned short tx_status;
+ unsigned short tx_command;
+ unsigned short tx_link;
+ unsigned short tx_tbdoffset;
+} tx_t;
+
+typedef struct { /* tbd */
+ unsigned short tbd_opts;
+#define TBD_CNT (0x3fff)
+#define TBD_EOL (1 << 15)
+ unsigned short tbd_link;
+ unsigned short tbd_bufl;
+ unsigned short tbd_bufh;
+} tbd_t;
+
+typedef struct { /* rfd */
+ unsigned short rfd_status;
+#define RFD_NOEOF (1 << 6)
+#define RFD_FRAMESHORT (1 << 7)
+#define RFD_DMAOVRN (1 << 8)
+#define RFD_NORESOURCES (1 << 9)
+#define RFD_ALIGNERROR (1 << 10)
+#define RFD_CRCERROR (1 << 11)
+#define RFD_OK (1 << 13)
+#define RFD_FDCONSUMED (1 << 14)
+#define RFD_COMPLETE (1 << 15)
+ unsigned short rfd_command;
+#define RFD_CMDSUSPEND (1 << 14)
+#define RFD_CMDEL (1 << 15)
+ unsigned short rfd_link;
+ unsigned short rfd_rbdoffset;
+ unsigned char rfd_dest[6];
+ unsigned char rfd_src[6];
+ unsigned short rfd_len;
+} rfd_t;
+
+typedef struct { /* rbd */
+ unsigned short rbd_status;
+#define RBD_ACNT (0x3fff)
+#define RBD_ACNTVALID (1 << 14)
+#define RBD_EOF (1 << 15)
+ unsigned short rbd_link;
+ unsigned short rbd_bufl;
+ unsigned short rbd_bufh;
+ unsigned short rbd_len;
+} rbd_t;
+
+typedef struct { /* nop */
+ unsigned short nop_status;
+ unsigned short nop_command;
+ unsigned short nop_link;
+} nop_t;
+
+typedef struct { /* set multicast */
+ unsigned short mc_status;
+ unsigned short mc_command;
+ unsigned short mc_link;
+ unsigned short mc_cnt;
+ unsigned char mc_addrs[1][6];
+} mc_t;
+
+typedef struct { /* set address */
+ unsigned short sa_status;
+ unsigned short sa_command;
+ unsigned short sa_link;
+ unsigned char sa_addr[6];
+} sa_t;
+
+typedef struct { /* config command */
+ unsigned short cfg_status;
+ unsigned short cfg_command;
+ unsigned short cfg_link;
+ unsigned char cfg_bytecnt; /* size foll data: 4 - 12 */
+ unsigned char cfg_fifolim; /* FIFO threshold */
+ unsigned char cfg_byte8;
+#define CFG8_SRDY (1 << 6)
+#define CFG8_SAVEBADF (1 << 7)
+ unsigned char cfg_byte9;
+#define CFG9_ADDRLEN(x) (x)
+#define CFG9_ADDRLENBUF (1 << 3)
+#define CFG9_PREAMB2 (0 << 4)
+#define CFG9_PREAMB4 (1 << 4)
+#define CFG9_PREAMB8 (2 << 4)
+#define CFG9_PREAMB16 (3 << 4)
+#define CFG9_ILOOPBACK (1 << 6)
+#define CFG9_ELOOPBACK (1 << 7)
+ unsigned char cfg_byte10;
+#define CFG10_LINPRI(x) (x)
+#define CFG10_ACR(x) (x << 4)
+#define CFG10_BOFMET (1 << 7)
+ unsigned char cfg_ifs;
+ unsigned char cfg_slotl;
+ unsigned char cfg_byte13;
+#define CFG13_SLOTH(x) (x)
+#define CFG13_RETRY(x) (x << 4)
+ unsigned char cfg_byte14;
+#define CFG14_PROMISC (1 << 0)
+#define CFG14_DISBRD (1 << 1)
+#define CFG14_MANCH (1 << 2)
+#define CFG14_TNCRS (1 << 3)
+#define CFG14_NOCRC (1 << 4)
+#define CFG14_CRC16 (1 << 5)
+#define CFG14_BTSTF (1 << 6)
+#define CFG14_FLGPAD (1 << 7)
+ unsigned char cfg_byte15;
+#define CFG15_CSTF(x) (x)
+#define CFG15_ICSS (1 << 3)
+#define CFG15_CDTF(x) (x << 4)
+#define CFG15_ICDS (1 << 7)
+ unsigned short cfg_minfrmlen;
+} cfg_t;
+
+typedef struct { /* scb */
+ unsigned short scb_status; /* status of 82586 */
+#define SCB_STRXMASK (7 << 4) /* Receive unit status */
+#define SCB_STRXIDLE (0 << 4) /* Idle */
+#define SCB_STRXSUSP (1 << 4) /* Suspended */
+#define SCB_STRXNRES (2 << 4) /* No resources */
+#define SCB_STRXRDY (4 << 4) /* Ready */
+#define SCB_STCUMASK (7 << 8) /* Command unit status */
+#define SCB_STCUIDLE (0 << 8) /* Idle */
+#define SCB_STCUSUSP (1 << 8) /* Suspended */
+#define SCB_STCUACTV (2 << 8) /* Active */
+#define SCB_STRNR (1 << 12) /* Receive unit not ready */
+#define SCB_STCNA (1 << 13) /* Command unit not ready */
+#define SCB_STFR (1 << 14) /* Frame received */
+#define SCB_STCX (1 << 15) /* Command completed */
+ unsigned short scb_command; /* Next command */
+#define SCB_CMDRXSTART (1 << 4) /* Start (at rfa_offset) */
+#define SCB_CMDRXRESUME (2 << 4) /* Resume reception */
+#define SCB_CMDRXSUSPEND (3 << 4) /* Suspend reception */
+#define SCB_CMDRXABORT (4 << 4) /* Abort reception */
+#define SCB_CMDCUCSTART (1 << 8) /* Start (at cbl_offset) */
+#define SCB_CMDCUCRESUME (2 << 8) /* Resume execution */
+#define SCB_CMDCUCSUSPEND (3 << 8) /* Suspend execution */
+#define SCB_CMDCUCABORT (4 << 8) /* Abort execution */
+#define SCB_CMDACKRNR (1 << 12) /* Ack RU not ready */
+#define SCB_CMDACKCNA (1 << 13) /* Ack CU not ready */
+#define SCB_CMDACKFR (1 << 14) /* Ack Frame received */
+#define SCB_CMDACKCX (1 << 15) /* Ack Command complete */
+ unsigned short scb_cbl_offset; /* Offset of first command unit */
+ unsigned short scb_rfa_offset; /* Offset of first receive frame area */
+ unsigned short scb_crc_errors; /* Properly aligned frame with CRC error*/
+ unsigned short scb_aln_errors; /* Misaligned frames */
+ unsigned short scb_rsc_errors; /* Frames lost due to no space */
+ unsigned short scb_ovn_errors; /* Frames lost due to slow bus */
+} scb_t;
+
+typedef struct { /* iscp */
+ unsigned short iscp_busy; /* set by CPU before CA */
+ unsigned short iscp_offset; /* offset of SCB */
+ unsigned short iscp_basel; /* base of SCB */
+ unsigned short iscp_baseh;
+} iscp_t;
+
+ /* this address must be 0xfff6 */
+typedef struct { /* scp */
+ unsigned short scp_sysbus; /* bus size */
+#define SCP_SY_16BBUS 0x00
+#define SCP_SY_8BBUS 0x01
+ unsigned short scp_junk[2]; /* junk */
+ unsigned short scp_iscpl; /* lower 16 bits of iscp */
+ unsigned short scp_iscph; /* upper 16 bits of iscp */
+} scp_t;
+
+/* commands */
+#define CMD_NOP 0
+#define CMD_SETADDRESS 1
+#define CMD_CONFIG 2
+#define CMD_SETMULTICAST 3
+#define CMD_TX 4
+#define CMD_TDR 5
+#define CMD_DUMP 6
+#define CMD_DIAGNOSE 7
+
+#define CMD_MASK 7
+
+#define CMD_INTR (1 << 13)
+#define CMD_SUSP (1 << 14)
+#define CMD_EOL (1 << 15)
+
+#define STAT_COLLISIONS (15)
+#define STAT_COLLEXCESSIVE (1 << 5)
+#define STAT_COLLAFTERTX (1 << 6)
+#define STAT_TXDEFERRED (1 << 7)
+#define STAT_TXSLOWDMA (1 << 8)
+#define STAT_TXLOSTCTS (1 << 9)
+#define STAT_NOCARRIER (1 << 10)
+#define STAT_FAIL (1 << 11)
+#define STAT_ABORTED (1 << 12)
+#define STAT_OK (1 << 13)
+#define STAT_BUSY (1 << 14)
+#define STAT_COMPLETE (1 << 15)
+#endif
+#endif
+
+/*
+ * Ether1 card definitions:
+ *
+ * FAST accesses:
+ * +0 Page register
+ * 16 pages
+ * +4 Control
+ * '1' = reset
+ * '2' = loopback
+ * '4' = CA
+ * '8' = int ack
+ *
+ * RAM at address + 0x2000
+ * Pod. Prod id = 3
+ * Words after ID block [base + 8 words]
+ * +0 pcb issue (0x0c and 0xf3 invalid)
+ * +1 - +6 eth hw address
+ */
--- /dev/null
+/* lasi_82596.c -- driver for the intel 82596 ethernet controller, as
+ munged into HPPA boxen .
+
+ This driver is based upon 82596.c, original credits are below...
+ but there were too many hoops which HP wants jumped through to
+ keep this code in there in a sane manner.
+
+ 3 primary sources of the mess --
+ 1) hppa needs *lots* of cacheline flushing to keep this kind of
+ MMIO running.
+
+ 2) The 82596 needs to see all of its pointers as their physical
+ address. Thus virt_to_bus/bus_to_virt are *everywhere*.
+
+ 3) The implementation HP is using seems to be significantly pickier
+ about when and how the command and RX units are started. some
+ command ordering was changed.
+
+ Examination of the mach driver leads one to believe that there
+ might be a saner way to pull this off... anyone who feels like a
+ full rewrite can be my guest.
+
+ Split 02/13/2000 Sam Creasey (sammy@oh.verio.com)
+
+ 02/01/2000 Initial modifications for parisc by Helge Deller (deller@gmx.de)
+ 03/02/2000 changes for better/correct(?) cache-flushing (deller)
+*/
+
+/* 82596.c: A generic 82596 ethernet driver for linux. */
+/*
+ Based on Apricot.c
+ Written 1994 by Mark Evans.
+ This driver is for the Apricot 82596 bus-master interface
+
+ Modularised 12/94 Mark Evans
+
+
+ Modified to support the 82596 ethernet chips on 680x0 VME boards.
+ by Richard Hirst <richard@sleepie.demon.co.uk>
+ Renamed to be 82596.c
+
+ 980825: Changed to receive directly in to sk_buffs which are
+ allocated at open() time. Eliminates copy on incoming frames
+ (small ones are still copied). Shared data now held in a
+ non-cached page, so we can run on 68060 in copyback mode.
+
+ TBD:
+ * look at deferring rx frames rather than discarding (as per tulip)
+ * handle tx ring full as per tulip
+ * performance test to tune rx_copybreak
+
+ Most of my modifications relate to the braindead big-endian
+ implementation by Intel. When the i596 is operating in
+ 'big-endian' mode, it thinks a 32 bit value of 0x12345678
+ should be stored as 0x56781234. This is a real pain, when
+ you have linked lists which are shared by the 680x0 and the
+ i596.
+
+ Driver skeleton
+ Written 1993 by Donald Becker.
+ Copyright 1993 United States Government as represented by the Director,
+ National Security Agency. This software may only be used and distributed
+ according to the terms of the GNU General Public License as modified by SRC,
+ incorporated herein by reference.
+
+ The author may be reached as becker@scyld.com, or C/O
+ Scyld Computing Corporation, 410 Severn Ave., Suite 210, Annapolis MD 21403
+
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/bitops.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/pdc.h>
+#include <asm/parisc-device.h>
+
+#define LASI_82596_DRIVER_VERSION "LASI 82596 driver - Revision: 1.30"
+
+#define PA_I82596_RESET 0 /* Offsets relative to LASI-LAN-Addr.*/
+#define PA_CPU_PORT_L_ACCESS 4
+#define PA_CHANNEL_ATTENTION 8
+
+#define OPT_SWAP_PORT 0x0001 /* Need to wordswp on the MPU port */
+
+#define DMA_ALLOC dma_alloc_noncoherent
+#define DMA_FREE dma_free_noncoherent
+#define DMA_WBACK(ndev, addr, len) \
+ do { dma_cache_sync((ndev)->dev.parent, (void *)addr, len, DMA_TO_DEVICE); } while (0)
+
+#define DMA_INV(ndev, addr, len) \
+ do { dma_cache_sync((ndev)->dev.parent, (void *)addr, len, DMA_FROM_DEVICE); } while (0)
+
+#define DMA_WBACK_INV(ndev, addr, len) \
+ do { dma_cache_sync((ndev)->dev.parent, (void *)addr, len, DMA_BIDIRECTIONAL); } while (0)
+
+#define SYSBUS 0x0000006c;
+
+/* big endian CPU, 82596 "big" endian mode */
+#define SWAP32(x) (((u32)(x)<<16) | ((((u32)(x)))>>16))
+#define SWAP16(x) (x)
+
+#include "lib82596.c"
+
+MODULE_AUTHOR("Richard Hirst");
+MODULE_DESCRIPTION("i82596 driver");
+MODULE_LICENSE("GPL");
+module_param(i596_debug, int, 0);
+MODULE_PARM_DESC(i596_debug, "lasi_82596 debug mask");
+
+static inline void ca(struct net_device *dev)
+{
+ gsc_writel(0, dev->base_addr + PA_CHANNEL_ATTENTION);
+}
+
+
+static void mpu_port(struct net_device *dev, int c, dma_addr_t x)
+{
+ struct i596_private *lp = netdev_priv(dev);
+
+ u32 v = (u32) (c) | (u32) (x);
+ u16 a, b;
+
+ if (lp->options & OPT_SWAP_PORT) {
+ a = v >> 16;
+ b = v & 0xffff;
+ } else {
+ a = v & 0xffff;
+ b = v >> 16;
+ }
+
+ gsc_writel(a, dev->base_addr + PA_CPU_PORT_L_ACCESS);
+ udelay(1);
+ gsc_writel(b, dev->base_addr + PA_CPU_PORT_L_ACCESS);
+}
+
+#define LAN_PROM_ADDR 0xF0810000
+
+static int __devinit
+lan_init_chip(struct parisc_device *dev)
+{
+ struct net_device *netdevice;
+ struct i596_private *lp;
+ int retval;
+ int i;
+
+ if (!dev->irq) {
+ printk(KERN_ERR "%s: IRQ not found for i82596 at 0x%lx\n",
+ __FILE__, (unsigned long)dev->hpa.start);
+ return -ENODEV;
+ }
+
+ printk(KERN_INFO "Found i82596 at 0x%lx, IRQ %d\n",
+ (unsigned long)dev->hpa.start, dev->irq);
+
+ netdevice = alloc_etherdev(sizeof(struct i596_private));
+ if (!netdevice)
+ return -ENOMEM;
+ SET_NETDEV_DEV(netdevice, &dev->dev);
+ parisc_set_drvdata (dev, netdevice);
+
+ netdevice->base_addr = dev->hpa.start;
+ netdevice->irq = dev->irq;
+
+ if (pdc_lan_station_id(netdevice->dev_addr, netdevice->base_addr)) {
+ for (i = 0; i < 6; i++) {
+ netdevice->dev_addr[i] = gsc_readb(LAN_PROM_ADDR + i);
+ }
+ printk(KERN_INFO
+ "%s: MAC of HP700 LAN read from EEPROM\n", __FILE__);
+ }
+
+ lp = netdev_priv(netdevice);
+ lp->options = dev->id.sversion == 0x72 ? OPT_SWAP_PORT : 0;
+
+ retval = i82596_probe(netdevice);
+ if (retval) {
+ free_netdev(netdevice);
+ return -ENODEV;
+ }
+ return retval;
+}
+
+static int __devexit lan_remove_chip (struct parisc_device *pdev)
+{
+ struct net_device *dev = parisc_get_drvdata(pdev);
+ struct i596_private *lp = netdev_priv(dev);
+
+ unregister_netdev (dev);
+ DMA_FREE(&pdev->dev, sizeof(struct i596_private),
+ (void *)lp->dma, lp->dma_addr);
+ free_netdev (dev);
+ return 0;
+}
+
+static struct parisc_device_id lan_tbl[] = {
+ { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0008a },
+ { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00072 },
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE(parisc, lan_tbl);
+
+static struct parisc_driver lan_driver = {
+ .name = "lasi_82596",
+ .id_table = lan_tbl,
+ .probe = lan_init_chip,
+ .remove = __devexit_p(lan_remove_chip),
+};
+
+static int __devinit lasi_82596_init(void)
+{
+ printk(KERN_INFO LASI_82596_DRIVER_VERSION "\n");
+ return register_parisc_driver(&lan_driver);
+}
+
+module_init(lasi_82596_init);
+
+static void __exit lasi_82596_exit(void)
+{
+ unregister_parisc_driver(&lan_driver);
+}
+
+module_exit(lasi_82596_exit);
--- /dev/null
+/* lasi_82596.c -- driver for the intel 82596 ethernet controller, as
+ munged into HPPA boxen .
+
+ This driver is based upon 82596.c, original credits are below...
+ but there were too many hoops which HP wants jumped through to
+ keep this code in there in a sane manner.
+
+ 3 primary sources of the mess --
+ 1) hppa needs *lots* of cacheline flushing to keep this kind of
+ MMIO running.
+
+ 2) The 82596 needs to see all of its pointers as their physical
+ address. Thus virt_to_bus/bus_to_virt are *everywhere*.
+
+ 3) The implementation HP is using seems to be significantly pickier
+ about when and how the command and RX units are started. some
+ command ordering was changed.
+
+ Examination of the mach driver leads one to believe that there
+ might be a saner way to pull this off... anyone who feels like a
+ full rewrite can be my guest.
+
+ Split 02/13/2000 Sam Creasey (sammy@oh.verio.com)
+
+ 02/01/2000 Initial modifications for parisc by Helge Deller (deller@gmx.de)
+ 03/02/2000 changes for better/correct(?) cache-flushing (deller)
+*/
+
+/* 82596.c: A generic 82596 ethernet driver for linux. */
+/*
+ Based on Apricot.c
+ Written 1994 by Mark Evans.
+ This driver is for the Apricot 82596 bus-master interface
+
+ Modularised 12/94 Mark Evans
+
+
+ Modified to support the 82596 ethernet chips on 680x0 VME boards.
+ by Richard Hirst <richard@sleepie.demon.co.uk>
+ Renamed to be 82596.c
+
+ 980825: Changed to receive directly in to sk_buffs which are
+ allocated at open() time. Eliminates copy on incoming frames
+ (small ones are still copied). Shared data now held in a
+ non-cached page, so we can run on 68060 in copyback mode.
+
+ TBD:
+ * look at deferring rx frames rather than discarding (as per tulip)
+ * handle tx ring full as per tulip
+ * performance test to tune rx_copybreak
+
+ Most of my modifications relate to the braindead big-endian
+ implementation by Intel. When the i596 is operating in
+ 'big-endian' mode, it thinks a 32 bit value of 0x12345678
+ should be stored as 0x56781234. This is a real pain, when
+ you have linked lists which are shared by the 680x0 and the
+ i596.
+
+ Driver skeleton
+ Written 1993 by Donald Becker.
+ Copyright 1993 United States Government as represented by the Director,
+ National Security Agency. This software may only be used and distributed
+ according to the terms of the GNU General Public License as modified by SRC,
+ incorporated herein by reference.
+
+ The author may be reached as becker@scyld.com, or C/O
+ Scyld Computing Corporation, 410 Severn Ave., Suite 210, Annapolis MD 21403
+
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/bitops.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/gfp.h>
+
+/* DEBUG flags
+ */
+
+#define DEB_INIT 0x0001
+#define DEB_PROBE 0x0002
+#define DEB_SERIOUS 0x0004
+#define DEB_ERRORS 0x0008
+#define DEB_MULTI 0x0010
+#define DEB_TDR 0x0020
+#define DEB_OPEN 0x0040
+#define DEB_RESET 0x0080
+#define DEB_ADDCMD 0x0100
+#define DEB_STATUS 0x0200
+#define DEB_STARTTX 0x0400
+#define DEB_RXADDR 0x0800
+#define DEB_TXADDR 0x1000
+#define DEB_RXFRAME 0x2000
+#define DEB_INTS 0x4000
+#define DEB_STRUCT 0x8000
+#define DEB_ANY 0xffff
+
+
+#define DEB(x, y) if (i596_debug & (x)) { y; }
+
+
+/*
+ * The MPU_PORT command allows direct access to the 82596. With PORT access
+ * the following commands are available (p5-18). The 32-bit port command
+ * must be word-swapped with the most significant word written first.
+ * This only applies to VME boards.
+ */
+#define PORT_RESET 0x00 /* reset 82596 */
+#define PORT_SELFTEST 0x01 /* selftest */
+#define PORT_ALTSCP 0x02 /* alternate SCB address */
+#define PORT_ALTDUMP 0x03 /* Alternate DUMP address */
+
+static int i596_debug = (DEB_SERIOUS|DEB_PROBE);
+
+/* Copy frames shorter than rx_copybreak, otherwise pass on up in
+ * a full sized sk_buff. Value of 100 stolen from tulip.c (!alpha).
+ */
+static int rx_copybreak = 100;
+
+#define PKT_BUF_SZ 1536
+#define MAX_MC_CNT 64
+
+#define ISCP_BUSY 0x0001
+
+#define I596_NULL ((u32)0xffffffff)
+
+#define CMD_EOL 0x8000 /* The last command of the list, stop. */
+#define CMD_SUSP 0x4000 /* Suspend after doing cmd. */
+#define CMD_INTR 0x2000 /* Interrupt after doing cmd. */
+
+#define CMD_FLEX 0x0008 /* Enable flexible memory model */
+
+enum commands {
+ CmdNOp = 0, CmdSASetup = 1, CmdConfigure = 2, CmdMulticastList = 3,
+ CmdTx = 4, CmdTDR = 5, CmdDump = 6, CmdDiagnose = 7
+};
+
+#define STAT_C 0x8000 /* Set to 0 after execution */
+#define STAT_B 0x4000 /* Command being executed */
+#define STAT_OK 0x2000 /* Command executed ok */
+#define STAT_A 0x1000 /* Command aborted */
+
+#define CUC_START 0x0100
+#define CUC_RESUME 0x0200
+#define CUC_SUSPEND 0x0300
+#define CUC_ABORT 0x0400
+#define RX_START 0x0010
+#define RX_RESUME 0x0020
+#define RX_SUSPEND 0x0030
+#define RX_ABORT 0x0040
+
+#define TX_TIMEOUT (HZ/20)
+
+
+struct i596_reg {
+ unsigned short porthi;
+ unsigned short portlo;
+ u32 ca;
+};
+
+#define EOF 0x8000
+#define SIZE_MASK 0x3fff
+
+struct i596_tbd {
+ unsigned short size;
+ unsigned short pad;
+ u32 next;
+ u32 data;
+ u32 cache_pad[5]; /* Total 32 bytes... */
+};
+
+/* The command structure has two 'next' pointers; v_next is the address of
+ * the next command as seen by the CPU, b_next is the address of the next
+ * command as seen by the 82596. The b_next pointer, as used by the 82596
+ * always references the status field of the next command, rather than the
+ * v_next field, because the 82596 is unaware of v_next. It may seem more
+ * logical to put v_next at the end of the structure, but we cannot do that
+ * because the 82596 expects other fields to be there, depending on command
+ * type.
+ */
+
+struct i596_cmd {
+ struct i596_cmd *v_next; /* Address from CPUs viewpoint */
+ unsigned short status;
+ unsigned short command;
+ u32 b_next; /* Address from i596 viewpoint */
+};
+
+struct tx_cmd {
+ struct i596_cmd cmd;
+ u32 tbd;
+ unsigned short size;
+ unsigned short pad;
+ struct sk_buff *skb; /* So we can free it after tx */
+ dma_addr_t dma_addr;
+#ifdef __LP64__
+ u32 cache_pad[6]; /* Total 64 bytes... */
+#else
+ u32 cache_pad[1]; /* Total 32 bytes... */
+#endif
+};
+
+struct tdr_cmd {
+ struct i596_cmd cmd;
+ unsigned short status;
+ unsigned short pad;
+};
+
+struct mc_cmd {
+ struct i596_cmd cmd;
+ short mc_cnt;
+ char mc_addrs[MAX_MC_CNT*6];
+};
+
+struct sa_cmd {
+ struct i596_cmd cmd;
+ char eth_addr[8];
+};
+
+struct cf_cmd {
+ struct i596_cmd cmd;
+ char i596_config[16];
+};
+
+struct i596_rfd {
+ unsigned short stat;
+ unsigned short cmd;
+ u32 b_next; /* Address from i596 viewpoint */
+ u32 rbd;
+ unsigned short count;
+ unsigned short size;
+ struct i596_rfd *v_next; /* Address from CPUs viewpoint */
+ struct i596_rfd *v_prev;
+#ifndef __LP64__
+ u32 cache_pad[2]; /* Total 32 bytes... */
+#endif
+};
+
+struct i596_rbd {
+ /* hardware data */
+ unsigned short count;
+ unsigned short zero1;
+ u32 b_next;
+ u32 b_data; /* Address from i596 viewpoint */
+ unsigned short size;
+ unsigned short zero2;
+ /* driver data */
+ struct sk_buff *skb;
+ struct i596_rbd *v_next;
+ u32 b_addr; /* This rbd addr from i596 view */
+ unsigned char *v_data; /* Address from CPUs viewpoint */
+ /* Total 32 bytes... */
+#ifdef __LP64__
+ u32 cache_pad[4];
+#endif
+};
+
+/* These values as chosen so struct i596_dma fits in one page... */
+
+#define TX_RING_SIZE 32
+#define RX_RING_SIZE 16
+
+struct i596_scb {
+ unsigned short status;
+ unsigned short command;
+ u32 cmd;
+ u32 rfd;
+ u32 crc_err;
+ u32 align_err;
+ u32 resource_err;
+ u32 over_err;
+ u32 rcvdt_err;
+ u32 short_err;
+ unsigned short t_on;
+ unsigned short t_off;
+};
+
+struct i596_iscp {
+ u32 stat;
+ u32 scb;
+};
+
+struct i596_scp {
+ u32 sysbus;
+ u32 pad;
+ u32 iscp;
+};
+
+struct i596_dma {
+ struct i596_scp scp __attribute__((aligned(32)));
+ volatile struct i596_iscp iscp __attribute__((aligned(32)));
+ volatile struct i596_scb scb __attribute__((aligned(32)));
+ struct sa_cmd sa_cmd __attribute__((aligned(32)));
+ struct cf_cmd cf_cmd __attribute__((aligned(32)));
+ struct tdr_cmd tdr_cmd __attribute__((aligned(32)));
+ struct mc_cmd mc_cmd __attribute__((aligned(32)));
+ struct i596_rfd rfds[RX_RING_SIZE] __attribute__((aligned(32)));
+ struct i596_rbd rbds[RX_RING_SIZE] __attribute__((aligned(32)));
+ struct tx_cmd tx_cmds[TX_RING_SIZE] __attribute__((aligned(32)));
+ struct i596_tbd tbds[TX_RING_SIZE] __attribute__((aligned(32)));
+};
+
+struct i596_private {
+ struct i596_dma *dma;
+ u32 stat;
+ int last_restart;
+ struct i596_rfd *rfd_head;
+ struct i596_rbd *rbd_head;
+ struct i596_cmd *cmd_tail;
+ struct i596_cmd *cmd_head;
+ int cmd_backlog;
+ u32 last_cmd;
+ int next_tx_cmd;
+ int options;
+ spinlock_t lock; /* serialize access to chip */
+ dma_addr_t dma_addr;
+ void __iomem *mpu_port;
+ void __iomem *ca;
+};
+
+static const char init_setup[] =
+{
+ 0x8E, /* length, prefetch on */
+ 0xC8, /* fifo to 8, monitor off */
+ 0x80, /* don't save bad frames */
+ 0x2E, /* No source address insertion, 8 byte preamble */
+ 0x00, /* priority and backoff defaults */
+ 0x60, /* interframe spacing */
+ 0x00, /* slot time LSB */
+ 0xf2, /* slot time and retries */
+ 0x00, /* promiscuous mode */
+ 0x00, /* collision detect */
+ 0x40, /* minimum frame length */
+ 0xff,
+ 0x00,
+ 0x7f /* *multi IA */ };
+
+static int i596_open(struct net_device *dev);
+static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static irqreturn_t i596_interrupt(int irq, void *dev_id);
+static int i596_close(struct net_device *dev);
+static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd);
+static void i596_tx_timeout (struct net_device *dev);
+static void print_eth(unsigned char *buf, char *str);
+static void set_multicast_list(struct net_device *dev);
+static inline void ca(struct net_device *dev);
+static void mpu_port(struct net_device *dev, int c, dma_addr_t x);
+
+static int rx_ring_size = RX_RING_SIZE;
+static int ticks_limit = 100;
+static int max_cmd_backlog = TX_RING_SIZE-1;
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void i596_poll_controller(struct net_device *dev);
+#endif
+
+
+static inline int wait_istat(struct net_device *dev, struct i596_dma *dma, int delcnt, char *str)
+{
+ DMA_INV(dev, &(dma->iscp), sizeof(struct i596_iscp));
+ while (--delcnt && dma->iscp.stat) {
+ udelay(10);
+ DMA_INV(dev, &(dma->iscp), sizeof(struct i596_iscp));
+ }
+ if (!delcnt) {
+ printk(KERN_ERR "%s: %s, iscp.stat %04x, didn't clear\n",
+ dev->name, str, SWAP16(dma->iscp.stat));
+ return -1;
+ } else
+ return 0;
+}
+
+
+static inline int wait_cmd(struct net_device *dev, struct i596_dma *dma, int delcnt, char *str)
+{
+ DMA_INV(dev, &(dma->scb), sizeof(struct i596_scb));
+ while (--delcnt && dma->scb.command) {
+ udelay(10);
+ DMA_INV(dev, &(dma->scb), sizeof(struct i596_scb));
+ }
+ if (!delcnt) {
+ printk(KERN_ERR "%s: %s, status %4.4x, cmd %4.4x.\n",
+ dev->name, str,
+ SWAP16(dma->scb.status),
+ SWAP16(dma->scb.command));
+ return -1;
+ } else
+ return 0;
+}
+
+
+static void i596_display_data(struct net_device *dev)
+{
+ struct i596_private *lp = netdev_priv(dev);
+ struct i596_dma *dma = lp->dma;
+ struct i596_cmd *cmd;
+ struct i596_rfd *rfd;
+ struct i596_rbd *rbd;
+
+ printk(KERN_DEBUG "lp and scp at %p, .sysbus = %08x, .iscp = %08x\n",
+ &dma->scp, dma->scp.sysbus, SWAP32(dma->scp.iscp));
+ printk(KERN_DEBUG "iscp at %p, iscp.stat = %08x, .scb = %08x\n",
+ &dma->iscp, SWAP32(dma->iscp.stat), SWAP32(dma->iscp.scb));
+ printk(KERN_DEBUG "scb at %p, scb.status = %04x, .command = %04x,"
+ " .cmd = %08x, .rfd = %08x\n",
+ &dma->scb, SWAP16(dma->scb.status), SWAP16(dma->scb.command),
+ SWAP16(dma->scb.cmd), SWAP32(dma->scb.rfd));
+ printk(KERN_DEBUG " errors: crc %x, align %x, resource %x,"
+ " over %x, rcvdt %x, short %x\n",
+ SWAP32(dma->scb.crc_err), SWAP32(dma->scb.align_err),
+ SWAP32(dma->scb.resource_err), SWAP32(dma->scb.over_err),
+ SWAP32(dma->scb.rcvdt_err), SWAP32(dma->scb.short_err));
+ cmd = lp->cmd_head;
+ while (cmd != NULL) {
+ printk(KERN_DEBUG
+ "cmd at %p, .status = %04x, .command = %04x,"
+ " .b_next = %08x\n",
+ cmd, SWAP16(cmd->status), SWAP16(cmd->command),
+ SWAP32(cmd->b_next));
+ cmd = cmd->v_next;
+ }
+ rfd = lp->rfd_head;
+ printk(KERN_DEBUG "rfd_head = %p\n", rfd);
+ do {
+ printk(KERN_DEBUG
+ " %p .stat %04x, .cmd %04x, b_next %08x, rbd %08x,"
+ " count %04x\n",
+ rfd, SWAP16(rfd->stat), SWAP16(rfd->cmd),
+ SWAP32(rfd->b_next), SWAP32(rfd->rbd),
+ SWAP16(rfd->count));
+ rfd = rfd->v_next;
+ } while (rfd != lp->rfd_head);
+ rbd = lp->rbd_head;
+ printk(KERN_DEBUG "rbd_head = %p\n", rbd);
+ do {
+ printk(KERN_DEBUG
+ " %p .count %04x, b_next %08x, b_data %08x,"
+ " size %04x\n",
+ rbd, SWAP16(rbd->count), SWAP32(rbd->b_next),
+ SWAP32(rbd->b_data), SWAP16(rbd->size));
+ rbd = rbd->v_next;
+ } while (rbd != lp->rbd_head);
+ DMA_INV(dev, dma, sizeof(struct i596_dma));
+}
+
+
+#define virt_to_dma(lp, v) ((lp)->dma_addr + (dma_addr_t)((unsigned long)(v)-(unsigned long)((lp)->dma)))
+
+static inline int init_rx_bufs(struct net_device *dev)
+{
+ struct i596_private *lp = netdev_priv(dev);
+ struct i596_dma *dma = lp->dma;
+ int i;
+ struct i596_rfd *rfd;
+ struct i596_rbd *rbd;
+
+ /* First build the Receive Buffer Descriptor List */
+
+ for (i = 0, rbd = dma->rbds; i < rx_ring_size; i++, rbd++) {
+ dma_addr_t dma_addr;
+ struct sk_buff *skb;
+
+ skb = netdev_alloc_skb_ip_align(dev, PKT_BUF_SZ);
+ if (skb == NULL)
+ return -1;
+ dma_addr = dma_map_single(dev->dev.parent, skb->data,
+ PKT_BUF_SZ, DMA_FROM_DEVICE);
+ rbd->v_next = rbd+1;
+ rbd->b_next = SWAP32(virt_to_dma(lp, rbd+1));
+ rbd->b_addr = SWAP32(virt_to_dma(lp, rbd));
+ rbd->skb = skb;
+ rbd->v_data = skb->data;
+ rbd->b_data = SWAP32(dma_addr);
+ rbd->size = SWAP16(PKT_BUF_SZ);
+ }
+ lp->rbd_head = dma->rbds;
+ rbd = dma->rbds + rx_ring_size - 1;
+ rbd->v_next = dma->rbds;
+ rbd->b_next = SWAP32(virt_to_dma(lp, dma->rbds));
+
+ /* Now build the Receive Frame Descriptor List */
+
+ for (i = 0, rfd = dma->rfds; i < rx_ring_size; i++, rfd++) {
+ rfd->rbd = I596_NULL;
+ rfd->v_next = rfd+1;
+ rfd->v_prev = rfd-1;
+ rfd->b_next = SWAP32(virt_to_dma(lp, rfd+1));
+ rfd->cmd = SWAP16(CMD_FLEX);
+ }
+ lp->rfd_head = dma->rfds;
+ dma->scb.rfd = SWAP32(virt_to_dma(lp, dma->rfds));
+ rfd = dma->rfds;
+ rfd->rbd = SWAP32(virt_to_dma(lp, lp->rbd_head));
+ rfd->v_prev = dma->rfds + rx_ring_size - 1;
+ rfd = dma->rfds + rx_ring_size - 1;
+ rfd->v_next = dma->rfds;
+ rfd->b_next = SWAP32(virt_to_dma(lp, dma->rfds));
+ rfd->cmd = SWAP16(CMD_EOL|CMD_FLEX);
+
+ DMA_WBACK_INV(dev, dma, sizeof(struct i596_dma));
+ return 0;
+}
+
+static inline void remove_rx_bufs(struct net_device *dev)
+{
+ struct i596_private *lp = netdev_priv(dev);
+ struct i596_rbd *rbd;
+ int i;
+
+ for (i = 0, rbd = lp->dma->rbds; i < rx_ring_size; i++, rbd++) {
+ if (rbd->skb == NULL)
+ break;
+ dma_unmap_single(dev->dev.parent,
+ (dma_addr_t)SWAP32(rbd->b_data),
+ PKT_BUF_SZ, DMA_FROM_DEVICE);
+ dev_kfree_skb(rbd->skb);
+ }
+}
+
+
+static void rebuild_rx_bufs(struct net_device *dev)
+{
+ struct i596_private *lp = netdev_priv(dev);
+ struct i596_dma *dma = lp->dma;
+ int i;
+
+ /* Ensure rx frame/buffer descriptors are tidy */
+
+ for (i = 0; i < rx_ring_size; i++) {
+ dma->rfds[i].rbd = I596_NULL;
+ dma->rfds[i].cmd = SWAP16(CMD_FLEX);
+ }
+ dma->rfds[rx_ring_size-1].cmd = SWAP16(CMD_EOL|CMD_FLEX);
+ lp->rfd_head = dma->rfds;
+ dma->scb.rfd = SWAP32(virt_to_dma(lp, dma->rfds));
+ lp->rbd_head = dma->rbds;
+ dma->rfds[0].rbd = SWAP32(virt_to_dma(lp, dma->rbds));
+
+ DMA_WBACK_INV(dev, dma, sizeof(struct i596_dma));
+}
+
+
+static int init_i596_mem(struct net_device *dev)
+{
+ struct i596_private *lp = netdev_priv(dev);
+ struct i596_dma *dma = lp->dma;
+ unsigned long flags;
+
+ mpu_port(dev, PORT_RESET, 0);
+ udelay(100); /* Wait 100us - seems to help */
+
+ /* change the scp address */
+
+ lp->last_cmd = jiffies;
+
+ dma->scp.sysbus = SYSBUS;
+ dma->scp.iscp = SWAP32(virt_to_dma(lp, &(dma->iscp)));
+ dma->iscp.scb = SWAP32(virt_to_dma(lp, &(dma->scb)));
+ dma->iscp.stat = SWAP32(ISCP_BUSY);
+ lp->cmd_backlog = 0;
+
+ lp->cmd_head = NULL;
+ dma->scb.cmd = I596_NULL;
+
+ DEB(DEB_INIT, printk(KERN_DEBUG "%s: starting i82596.\n", dev->name));
+
+ DMA_WBACK(dev, &(dma->scp), sizeof(struct i596_scp));
+ DMA_WBACK(dev, &(dma->iscp), sizeof(struct i596_iscp));
+ DMA_WBACK(dev, &(dma->scb), sizeof(struct i596_scb));
+
+ mpu_port(dev, PORT_ALTSCP, virt_to_dma(lp, &dma->scp));
+ ca(dev);
+ if (wait_istat(dev, dma, 1000, "initialization timed out"))
+ goto failed;
+ DEB(DEB_INIT, printk(KERN_DEBUG
+ "%s: i82596 initialization successful\n",
+ dev->name));
+
+ if (request_irq(dev->irq, i596_interrupt, 0, "i82596", dev)) {
+ printk(KERN_ERR "%s: IRQ %d not free\n", dev->name, dev->irq);
+ goto failed;
+ }
+
+ /* Ensure rx frame/buffer descriptors are tidy */
+ rebuild_rx_bufs(dev);
+
+ dma->scb.command = 0;
+ DMA_WBACK(dev, &(dma->scb), sizeof(struct i596_scb));
+
+ DEB(DEB_INIT, printk(KERN_DEBUG
+ "%s: queuing CmdConfigure\n", dev->name));
+ memcpy(dma->cf_cmd.i596_config, init_setup, 14);
+ dma->cf_cmd.cmd.command = SWAP16(CmdConfigure);
+ DMA_WBACK(dev, &(dma->cf_cmd), sizeof(struct cf_cmd));
+ i596_add_cmd(dev, &dma->cf_cmd.cmd);
+
+ DEB(DEB_INIT, printk(KERN_DEBUG "%s: queuing CmdSASetup\n", dev->name));
+ memcpy(dma->sa_cmd.eth_addr, dev->dev_addr, 6);
+ dma->sa_cmd.cmd.command = SWAP16(CmdSASetup);
+ DMA_WBACK(dev, &(dma->sa_cmd), sizeof(struct sa_cmd));
+ i596_add_cmd(dev, &dma->sa_cmd.cmd);
+
+ DEB(DEB_INIT, printk(KERN_DEBUG "%s: queuing CmdTDR\n", dev->name));
+ dma->tdr_cmd.cmd.command = SWAP16(CmdTDR);
+ DMA_WBACK(dev, &(dma->tdr_cmd), sizeof(struct tdr_cmd));
+ i596_add_cmd(dev, &dma->tdr_cmd.cmd);
+
+ spin_lock_irqsave (&lp->lock, flags);
+
+ if (wait_cmd(dev, dma, 1000, "timed out waiting to issue RX_START")) {
+ spin_unlock_irqrestore (&lp->lock, flags);
+ goto failed_free_irq;
+ }
+ DEB(DEB_INIT, printk(KERN_DEBUG "%s: Issuing RX_START\n", dev->name));
+ dma->scb.command = SWAP16(RX_START);
+ dma->scb.rfd = SWAP32(virt_to_dma(lp, dma->rfds));
+ DMA_WBACK(dev, &(dma->scb), sizeof(struct i596_scb));
+
+ ca(dev);
+
+ spin_unlock_irqrestore (&lp->lock, flags);
+ if (wait_cmd(dev, dma, 1000, "RX_START not processed"))
+ goto failed_free_irq;
+ DEB(DEB_INIT, printk(KERN_DEBUG
+ "%s: Receive unit started OK\n", dev->name));
+ return 0;
+
+failed_free_irq:
+ free_irq(dev->irq, dev);
+failed:
+ printk(KERN_ERR "%s: Failed to initialise 82596\n", dev->name);
+ mpu_port(dev, PORT_RESET, 0);
+ return -1;
+}
+
+
+static inline int i596_rx(struct net_device *dev)
+{
+ struct i596_private *lp = netdev_priv(dev);
+ struct i596_rfd *rfd;
+ struct i596_rbd *rbd;
+ int frames = 0;
+
+ DEB(DEB_RXFRAME, printk(KERN_DEBUG
+ "i596_rx(), rfd_head %p, rbd_head %p\n",
+ lp->rfd_head, lp->rbd_head));
+
+
+ rfd = lp->rfd_head; /* Ref next frame to check */
+
+ DMA_INV(dev, rfd, sizeof(struct i596_rfd));
+ while (rfd->stat & SWAP16(STAT_C)) { /* Loop while complete frames */
+ if (rfd->rbd == I596_NULL)
+ rbd = NULL;
+ else if (rfd->rbd == lp->rbd_head->b_addr) {
+ rbd = lp->rbd_head;
+ DMA_INV(dev, rbd, sizeof(struct i596_rbd));
+ } else {
+ printk(KERN_ERR "%s: rbd chain broken!\n", dev->name);
+ /* XXX Now what? */
+ rbd = NULL;
+ }
+ DEB(DEB_RXFRAME, printk(KERN_DEBUG
+ " rfd %p, rfd.rbd %08x, rfd.stat %04x\n",
+ rfd, rfd->rbd, rfd->stat));
+
+ if (rbd != NULL && (rfd->stat & SWAP16(STAT_OK))) {
+ /* a good frame */
+ int pkt_len = SWAP16(rbd->count) & 0x3fff;
+ struct sk_buff *skb = rbd->skb;
+ int rx_in_place = 0;
+
+ DEB(DEB_RXADDR, print_eth(rbd->v_data, "received"));
+ frames++;
+
+ /* Check if the packet is long enough to just accept
+ * without copying to a properly sized skbuff.
+ */
+
+ if (pkt_len > rx_copybreak) {
+ struct sk_buff *newskb;
+ dma_addr_t dma_addr;
+
+ dma_unmap_single(dev->dev.parent,
+ (dma_addr_t)SWAP32(rbd->b_data),
+ PKT_BUF_SZ, DMA_FROM_DEVICE);
+ /* Get fresh skbuff to replace filled one. */
+ newskb = netdev_alloc_skb_ip_align(dev,
+ PKT_BUF_SZ);
+ if (newskb == NULL) {
+ skb = NULL; /* drop pkt */
+ goto memory_squeeze;
+ }
+
+ /* Pass up the skb already on the Rx ring. */
+ skb_put(skb, pkt_len);
+ rx_in_place = 1;
+ rbd->skb = newskb;
+ dma_addr = dma_map_single(dev->dev.parent,
+ newskb->data,
+ PKT_BUF_SZ,
+ DMA_FROM_DEVICE);
+ rbd->v_data = newskb->data;
+ rbd->b_data = SWAP32(dma_addr);
+ DMA_WBACK_INV(dev, rbd, sizeof(struct i596_rbd));
+ } else
+ skb = netdev_alloc_skb_ip_align(dev, pkt_len);
+memory_squeeze:
+ if (skb == NULL) {
+ /* XXX tulip.c can defer packets here!! */
+ printk(KERN_ERR
+ "%s: i596_rx Memory squeeze, dropping packet.\n",
+ dev->name);
+ dev->stats.rx_dropped++;
+ } else {
+ if (!rx_in_place) {
+ /* 16 byte align the data fields */
+ dma_sync_single_for_cpu(dev->dev.parent,
+ (dma_addr_t)SWAP32(rbd->b_data),
+ PKT_BUF_SZ, DMA_FROM_DEVICE);
+ memcpy(skb_put(skb, pkt_len), rbd->v_data, pkt_len);
+ dma_sync_single_for_device(dev->dev.parent,
+ (dma_addr_t)SWAP32(rbd->b_data),
+ PKT_BUF_SZ, DMA_FROM_DEVICE);
+ }
+ skb->len = pkt_len;
+ skb->protocol = eth_type_trans(skb, dev);
+ netif_rx(skb);
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
+ }
+ } else {
+ DEB(DEB_ERRORS, printk(KERN_DEBUG
+ "%s: Error, rfd.stat = 0x%04x\n",
+ dev->name, rfd->stat));
+ dev->stats.rx_errors++;
+ if (rfd->stat & SWAP16(0x0100))
+ dev->stats.collisions++;
+ if (rfd->stat & SWAP16(0x8000))
+ dev->stats.rx_length_errors++;
+ if (rfd->stat & SWAP16(0x0001))
+ dev->stats.rx_over_errors++;
+ if (rfd->stat & SWAP16(0x0002))
+ dev->stats.rx_fifo_errors++;
+ if (rfd->stat & SWAP16(0x0004))
+ dev->stats.rx_frame_errors++;
+ if (rfd->stat & SWAP16(0x0008))
+ dev->stats.rx_crc_errors++;
+ if (rfd->stat & SWAP16(0x0010))
+ dev->stats.rx_length_errors++;
+ }
+
+ /* Clear the buffer descriptor count and EOF + F flags */
+
+ if (rbd != NULL && (rbd->count & SWAP16(0x4000))) {
+ rbd->count = 0;
+ lp->rbd_head = rbd->v_next;
+ DMA_WBACK_INV(dev, rbd, sizeof(struct i596_rbd));
+ }
+
+ /* Tidy the frame descriptor, marking it as end of list */
+
+ rfd->rbd = I596_NULL;
+ rfd->stat = 0;
+ rfd->cmd = SWAP16(CMD_EOL|CMD_FLEX);
+ rfd->count = 0;
+
+ /* Update record of next frame descriptor to process */
+
+ lp->dma->scb.rfd = rfd->b_next;
+ lp->rfd_head = rfd->v_next;
+ DMA_WBACK_INV(dev, rfd, sizeof(struct i596_rfd));
+
+ /* Remove end-of-list from old end descriptor */
+
+ rfd->v_prev->cmd = SWAP16(CMD_FLEX);
+ DMA_WBACK_INV(dev, rfd->v_prev, sizeof(struct i596_rfd));
+ rfd = lp->rfd_head;
+ DMA_INV(dev, rfd, sizeof(struct i596_rfd));
+ }
+
+ DEB(DEB_RXFRAME, printk(KERN_DEBUG "frames %d\n", frames));
+
+ return 0;
+}
+
+
+static inline void i596_cleanup_cmd(struct net_device *dev, struct i596_private *lp)
+{
+ struct i596_cmd *ptr;
+
+ while (lp->cmd_head != NULL) {
+ ptr = lp->cmd_head;
+ lp->cmd_head = ptr->v_next;
+ lp->cmd_backlog--;
+
+ switch (SWAP16(ptr->command) & 0x7) {
+ case CmdTx:
+ {
+ struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr;
+ struct sk_buff *skb = tx_cmd->skb;
+ dma_unmap_single(dev->dev.parent,
+ tx_cmd->dma_addr,
+ skb->len, DMA_TO_DEVICE);
+
+ dev_kfree_skb(skb);
+
+ dev->stats.tx_errors++;
+ dev->stats.tx_aborted_errors++;
+
+ ptr->v_next = NULL;
+ ptr->b_next = I596_NULL;
+ tx_cmd->cmd.command = 0; /* Mark as free */
+ break;
+ }
+ default:
+ ptr->v_next = NULL;
+ ptr->b_next = I596_NULL;
+ }
+ DMA_WBACK_INV(dev, ptr, sizeof(struct i596_cmd));
+ }
+
+ wait_cmd(dev, lp->dma, 100, "i596_cleanup_cmd timed out");
+ lp->dma->scb.cmd = I596_NULL;
+ DMA_WBACK(dev, &(lp->dma->scb), sizeof(struct i596_scb));
+}
+
+
+static inline void i596_reset(struct net_device *dev, struct i596_private *lp)
+{
+ unsigned long flags;
+
+ DEB(DEB_RESET, printk(KERN_DEBUG "i596_reset\n"));
+
+ spin_lock_irqsave (&lp->lock, flags);
+
+ wait_cmd(dev, lp->dma, 100, "i596_reset timed out");
+
+ netif_stop_queue(dev);
+
+ /* FIXME: this command might cause an lpmc */
+ lp->dma->scb.command = SWAP16(CUC_ABORT | RX_ABORT);
+ DMA_WBACK(dev, &(lp->dma->scb), sizeof(struct i596_scb));
+ ca(dev);
+
+ /* wait for shutdown */
+ wait_cmd(dev, lp->dma, 1000, "i596_reset 2 timed out");
+ spin_unlock_irqrestore (&lp->lock, flags);
+
+ i596_cleanup_cmd(dev, lp);
+ i596_rx(dev);
+
+ netif_start_queue(dev);
+ init_i596_mem(dev);
+}
+
+
+static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd)
+{
+ struct i596_private *lp = netdev_priv(dev);
+ struct i596_dma *dma = lp->dma;
+ unsigned long flags;
+
+ DEB(DEB_ADDCMD, printk(KERN_DEBUG "i596_add_cmd cmd_head %p\n",
+ lp->cmd_head));
+
+ cmd->status = 0;
+ cmd->command |= SWAP16(CMD_EOL | CMD_INTR);
+ cmd->v_next = NULL;
+ cmd->b_next = I596_NULL;
+ DMA_WBACK(dev, cmd, sizeof(struct i596_cmd));
+
+ spin_lock_irqsave (&lp->lock, flags);
+
+ if (lp->cmd_head != NULL) {
+ lp->cmd_tail->v_next = cmd;
+ lp->cmd_tail->b_next = SWAP32(virt_to_dma(lp, &cmd->status));
+ DMA_WBACK(dev, lp->cmd_tail, sizeof(struct i596_cmd));
+ } else {
+ lp->cmd_head = cmd;
+ wait_cmd(dev, dma, 100, "i596_add_cmd timed out");
+ dma->scb.cmd = SWAP32(virt_to_dma(lp, &cmd->status));
+ dma->scb.command = SWAP16(CUC_START);
+ DMA_WBACK(dev, &(dma->scb), sizeof(struct i596_scb));
+ ca(dev);
+ }
+ lp->cmd_tail = cmd;
+ lp->cmd_backlog++;
+
+ spin_unlock_irqrestore (&lp->lock, flags);
+
+ if (lp->cmd_backlog > max_cmd_backlog) {
+ unsigned long tickssofar = jiffies - lp->last_cmd;
+
+ if (tickssofar < ticks_limit)
+ return;
+
+ printk(KERN_ERR
+ "%s: command unit timed out, status resetting.\n",
+ dev->name);
+#if 1
+ i596_reset(dev, lp);
+#endif
+ }
+}
+
+static int i596_open(struct net_device *dev)
+{
+ DEB(DEB_OPEN, printk(KERN_DEBUG
+ "%s: i596_open() irq %d.\n", dev->name, dev->irq));
+
+ if (init_rx_bufs(dev)) {
+ printk(KERN_ERR "%s: Failed to init rx bufs\n", dev->name);
+ return -EAGAIN;
+ }
+ if (init_i596_mem(dev)) {
+ printk(KERN_ERR "%s: Failed to init memory\n", dev->name);
+ goto out_remove_rx_bufs;
+ }
+ netif_start_queue(dev);
+
+ return 0;
+
+out_remove_rx_bufs:
+ remove_rx_bufs(dev);
+ return -EAGAIN;
+}
+
+static void i596_tx_timeout (struct net_device *dev)
+{
+ struct i596_private *lp = netdev_priv(dev);
+
+ /* Transmitter timeout, serious problems. */
+ DEB(DEB_ERRORS, printk(KERN_DEBUG
+ "%s: transmit timed out, status resetting.\n",
+ dev->name));
+
+ dev->stats.tx_errors++;
+
+ /* Try to restart the adaptor */
+ if (lp->last_restart == dev->stats.tx_packets) {
+ DEB(DEB_ERRORS, printk(KERN_DEBUG "Resetting board.\n"));
+ /* Shutdown and restart */
+ i596_reset (dev, lp);
+ } else {
+ /* Issue a channel attention signal */
+ DEB(DEB_ERRORS, printk(KERN_DEBUG "Kicking board.\n"));
+ lp->dma->scb.command = SWAP16(CUC_START | RX_START);
+ DMA_WBACK_INV(dev, &(lp->dma->scb), sizeof(struct i596_scb));
+ ca (dev);
+ lp->last_restart = dev->stats.tx_packets;
+ }
+
+ dev->trans_start = jiffies; /* prevent tx timeout */
+ netif_wake_queue (dev);
+}
+
+
+static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct i596_private *lp = netdev_priv(dev);
+ struct tx_cmd *tx_cmd;
+ struct i596_tbd *tbd;
+ short length = skb->len;
+
+ DEB(DEB_STARTTX, printk(KERN_DEBUG
+ "%s: i596_start_xmit(%x,%p) called\n",
+ dev->name, skb->len, skb->data));
+
+ if (length < ETH_ZLEN) {
+ if (skb_padto(skb, ETH_ZLEN))
+ return NETDEV_TX_OK;
+ length = ETH_ZLEN;
+ }
+
+ netif_stop_queue(dev);
+
+ tx_cmd = lp->dma->tx_cmds + lp->next_tx_cmd;
+ tbd = lp->dma->tbds + lp->next_tx_cmd;
+
+ if (tx_cmd->cmd.command) {
+ DEB(DEB_ERRORS, printk(KERN_DEBUG
+ "%s: xmit ring full, dropping packet.\n",
+ dev->name));
+ dev->stats.tx_dropped++;
+
+ dev_kfree_skb(skb);
+ } else {
+ if (++lp->next_tx_cmd == TX_RING_SIZE)
+ lp->next_tx_cmd = 0;
+ tx_cmd->tbd = SWAP32(virt_to_dma(lp, tbd));
+ tbd->next = I596_NULL;
+
+ tx_cmd->cmd.command = SWAP16(CMD_FLEX | CmdTx);
+ tx_cmd->skb = skb;
+
+ tx_cmd->pad = 0;
+ tx_cmd->size = 0;
+ tbd->pad = 0;
+ tbd->size = SWAP16(EOF | length);
+
+ tx_cmd->dma_addr = dma_map_single(dev->dev.parent, skb->data,
+ skb->len, DMA_TO_DEVICE);
+ tbd->data = SWAP32(tx_cmd->dma_addr);
+
+ DEB(DEB_TXADDR, print_eth(skb->data, "tx-queued"));
+ DMA_WBACK_INV(dev, tx_cmd, sizeof(struct tx_cmd));
+ DMA_WBACK_INV(dev, tbd, sizeof(struct i596_tbd));
+ i596_add_cmd(dev, &tx_cmd->cmd);
+
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += length;
+ }
+
+ netif_start_queue(dev);
+
+ return NETDEV_TX_OK;
+}
+
+static void print_eth(unsigned char *add, char *str)
+{
+ printk(KERN_DEBUG "i596 0x%p, %pM --> %pM %02X%02X, %s\n",
+ add, add + 6, add, add[12], add[13], str);
+}
+static const struct net_device_ops i596_netdev_ops = {
+ .ndo_open = i596_open,
+ .ndo_stop = i596_close,
+ .ndo_start_xmit = i596_start_xmit,
+ .ndo_set_multicast_list = set_multicast_list,
+ .ndo_tx_timeout = i596_tx_timeout,
+ .ndo_change_mtu = eth_change_mtu,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = eth_mac_addr,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = i596_poll_controller,
+#endif
+};
+
+static int __devinit i82596_probe(struct net_device *dev)
+{
+ int i;
+ struct i596_private *lp = netdev_priv(dev);
+ struct i596_dma *dma;
+
+ /* This lot is ensure things have been cache line aligned. */
+ BUILD_BUG_ON(sizeof(struct i596_rfd) != 32);
+ BUILD_BUG_ON(sizeof(struct i596_rbd) & 31);
+ BUILD_BUG_ON(sizeof(struct tx_cmd) & 31);
+ BUILD_BUG_ON(sizeof(struct i596_tbd) != 32);
+#ifndef __LP64__
+ BUILD_BUG_ON(sizeof(struct i596_dma) > 4096);
+#endif
+
+ if (!dev->base_addr || !dev->irq)
+ return -ENODEV;
+
+ dma = (struct i596_dma *) DMA_ALLOC(dev->dev.parent,
+ sizeof(struct i596_dma), &lp->dma_addr, GFP_KERNEL);
+ if (!dma) {
+ printk(KERN_ERR "%s: Couldn't get shared memory\n", __FILE__);
+ return -ENOMEM;
+ }
+
+ dev->netdev_ops = &i596_netdev_ops;
+ dev->watchdog_timeo = TX_TIMEOUT;
+
+ memset(dma, 0, sizeof(struct i596_dma));
+ lp->dma = dma;
+
+ dma->scb.command = 0;
+ dma->scb.cmd = I596_NULL;
+ dma->scb.rfd = I596_NULL;
+ spin_lock_init(&lp->lock);
+
+ DMA_WBACK_INV(dev, dma, sizeof(struct i596_dma));
+
+ i = register_netdev(dev);
+ if (i) {
+ DMA_FREE(dev->dev.parent, sizeof(struct i596_dma),
+ (void *)dma, lp->dma_addr);
+ return i;
+ }
+
+ DEB(DEB_PROBE, printk(KERN_INFO "%s: 82596 at %#3lx, %pM IRQ %d.\n",
+ dev->name, dev->base_addr, dev->dev_addr,
+ dev->irq));
+ DEB(DEB_INIT, printk(KERN_INFO
+ "%s: dma at 0x%p (%d bytes), lp->scb at 0x%p\n",
+ dev->name, dma, (int)sizeof(struct i596_dma),
+ &dma->scb));
+
+ return 0;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void i596_poll_controller(struct net_device *dev)
+{
+ disable_irq(dev->irq);
+ i596_interrupt(dev->irq, dev);
+ enable_irq(dev->irq);
+}
+#endif
+
+static irqreturn_t i596_interrupt(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct i596_private *lp;
+ struct i596_dma *dma;
+ unsigned short status, ack_cmd = 0;
+
+ lp = netdev_priv(dev);
+ dma = lp->dma;
+
+ spin_lock (&lp->lock);
+
+ wait_cmd(dev, dma, 100, "i596 interrupt, timeout");
+ status = SWAP16(dma->scb.status);
+
+ DEB(DEB_INTS, printk(KERN_DEBUG
+ "%s: i596 interrupt, IRQ %d, status %4.4x.\n",
+ dev->name, dev->irq, status));
+
+ ack_cmd = status & 0xf000;
+
+ if (!ack_cmd) {
+ DEB(DEB_ERRORS, printk(KERN_DEBUG
+ "%s: interrupt with no events\n",
+ dev->name));
+ spin_unlock (&lp->lock);
+ return IRQ_NONE;
+ }
+
+ if ((status & 0x8000) || (status & 0x2000)) {
+ struct i596_cmd *ptr;
+
+ if ((status & 0x8000))
+ DEB(DEB_INTS,
+ printk(KERN_DEBUG
+ "%s: i596 interrupt completed command.\n",
+ dev->name));
+ if ((status & 0x2000))
+ DEB(DEB_INTS,
+ printk(KERN_DEBUG
+ "%s: i596 interrupt command unit inactive %x.\n",
+ dev->name, status & 0x0700));
+
+ while (lp->cmd_head != NULL) {
+ DMA_INV(dev, lp->cmd_head, sizeof(struct i596_cmd));
+ if (!(lp->cmd_head->status & SWAP16(STAT_C)))
+ break;
+
+ ptr = lp->cmd_head;
+
+ DEB(DEB_STATUS,
+ printk(KERN_DEBUG
+ "cmd_head->status = %04x, ->command = %04x\n",
+ SWAP16(lp->cmd_head->status),
+ SWAP16(lp->cmd_head->command)));
+ lp->cmd_head = ptr->v_next;
+ lp->cmd_backlog--;
+
+ switch (SWAP16(ptr->command) & 0x7) {
+ case CmdTx:
+ {
+ struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr;
+ struct sk_buff *skb = tx_cmd->skb;
+
+ if (ptr->status & SWAP16(STAT_OK)) {
+ DEB(DEB_TXADDR,
+ print_eth(skb->data, "tx-done"));
+ } else {
+ dev->stats.tx_errors++;
+ if (ptr->status & SWAP16(0x0020))
+ dev->stats.collisions++;
+ if (!(ptr->status & SWAP16(0x0040)))
+ dev->stats.tx_heartbeat_errors++;
+ if (ptr->status & SWAP16(0x0400))
+ dev->stats.tx_carrier_errors++;
+ if (ptr->status & SWAP16(0x0800))
+ dev->stats.collisions++;
+ if (ptr->status & SWAP16(0x1000))
+ dev->stats.tx_aborted_errors++;
+ }
+ dma_unmap_single(dev->dev.parent,
+ tx_cmd->dma_addr,
+ skb->len, DMA_TO_DEVICE);
+ dev_kfree_skb_irq(skb);
+
+ tx_cmd->cmd.command = 0; /* Mark free */
+ break;
+ }
+ case CmdTDR:
+ {
+ unsigned short status = SWAP16(((struct tdr_cmd *)ptr)->status);
+
+ if (status & 0x8000) {
+ DEB(DEB_ANY,
+ printk(KERN_DEBUG "%s: link ok.\n",
+ dev->name));
+ } else {
+ if (status & 0x4000)
+ printk(KERN_ERR
+ "%s: Transceiver problem.\n",
+ dev->name);
+ if (status & 0x2000)
+ printk(KERN_ERR
+ "%s: Termination problem.\n",
+ dev->name);
+ if (status & 0x1000)
+ printk(KERN_ERR
+ "%s: Short circuit.\n",
+ dev->name);
+
+ DEB(DEB_TDR,
+ printk(KERN_DEBUG "%s: Time %d.\n",
+ dev->name, status & 0x07ff));
+ }
+ break;
+ }
+ case CmdConfigure:
+ /*
+ * Zap command so set_multicast_list() know
+ * it is free
+ */
+ ptr->command = 0;
+ break;
+ }
+ ptr->v_next = NULL;
+ ptr->b_next = I596_NULL;
+ DMA_WBACK(dev, ptr, sizeof(struct i596_cmd));
+ lp->last_cmd = jiffies;
+ }
+
+ /* This mess is arranging that only the last of any outstanding
+ * commands has the interrupt bit set. Should probably really
+ * only add to the cmd queue when the CU is stopped.
+ */
+ ptr = lp->cmd_head;
+ while ((ptr != NULL) && (ptr != lp->cmd_tail)) {
+ struct i596_cmd *prev = ptr;
+
+ ptr->command &= SWAP16(0x1fff);
+ ptr = ptr->v_next;
+ DMA_WBACK_INV(dev, prev, sizeof(struct i596_cmd));
+ }
+
+ if (lp->cmd_head != NULL)
+ ack_cmd |= CUC_START;
+ dma->scb.cmd = SWAP32(virt_to_dma(lp, &lp->cmd_head->status));
+ DMA_WBACK_INV(dev, &dma->scb, sizeof(struct i596_scb));
+ }
+ if ((status & 0x1000) || (status & 0x4000)) {
+ if ((status & 0x4000))
+ DEB(DEB_INTS,
+ printk(KERN_DEBUG
+ "%s: i596 interrupt received a frame.\n",
+ dev->name));
+ i596_rx(dev);
+ /* Only RX_START if stopped - RGH 07-07-96 */
+ if (status & 0x1000) {
+ if (netif_running(dev)) {
+ DEB(DEB_ERRORS,
+ printk(KERN_DEBUG
+ "%s: i596 interrupt receive unit inactive, status 0x%x\n",
+ dev->name, status));
+ ack_cmd |= RX_START;
+ dev->stats.rx_errors++;
+ dev->stats.rx_fifo_errors++;
+ rebuild_rx_bufs(dev);
+ }
+ }
+ }
+ wait_cmd(dev, dma, 100, "i596 interrupt, timeout");
+ dma->scb.command = SWAP16(ack_cmd);
+ DMA_WBACK(dev, &dma->scb, sizeof(struct i596_scb));
+
+ /* DANGER: I suspect that some kind of interrupt
+ acknowledgement aside from acking the 82596 might be needed
+ here... but it's running acceptably without */
+
+ ca(dev);
+
+ wait_cmd(dev, dma, 100, "i596 interrupt, exit timeout");
+ DEB(DEB_INTS, printk(KERN_DEBUG "%s: exiting interrupt.\n", dev->name));
+
+ spin_unlock (&lp->lock);
+ return IRQ_HANDLED;
+}
+
+static int i596_close(struct net_device *dev)
+{
+ struct i596_private *lp = netdev_priv(dev);
+ unsigned long flags;
+
+ netif_stop_queue(dev);
+
+ DEB(DEB_INIT,
+ printk(KERN_DEBUG
+ "%s: Shutting down ethercard, status was %4.4x.\n",
+ dev->name, SWAP16(lp->dma->scb.status)));
+
+ spin_lock_irqsave(&lp->lock, flags);
+
+ wait_cmd(dev, lp->dma, 100, "close1 timed out");
+ lp->dma->scb.command = SWAP16(CUC_ABORT | RX_ABORT);
+ DMA_WBACK(dev, &lp->dma->scb, sizeof(struct i596_scb));
+
+ ca(dev);
+
+ wait_cmd(dev, lp->dma, 100, "close2 timed out");
+ spin_unlock_irqrestore(&lp->lock, flags);
+ DEB(DEB_STRUCT, i596_display_data(dev));
+ i596_cleanup_cmd(dev, lp);
+
+ free_irq(dev->irq, dev);
+ remove_rx_bufs(dev);
+
+ return 0;
+}
+
+/*
+ * Set or clear the multicast filter for this adaptor.
+ */
+
+static void set_multicast_list(struct net_device *dev)
+{
+ struct i596_private *lp = netdev_priv(dev);
+ struct i596_dma *dma = lp->dma;
+ int config = 0, cnt;
+
+ DEB(DEB_MULTI,
+ printk(KERN_DEBUG
+ "%s: set multicast list, %d entries, promisc %s, allmulti %s\n",
+ dev->name, netdev_mc_count(dev),
+ dev->flags & IFF_PROMISC ? "ON" : "OFF",
+ dev->flags & IFF_ALLMULTI ? "ON" : "OFF"));
+
+ if ((dev->flags & IFF_PROMISC) &&
+ !(dma->cf_cmd.i596_config[8] & 0x01)) {
+ dma->cf_cmd.i596_config[8] |= 0x01;
+ config = 1;
+ }
+ if (!(dev->flags & IFF_PROMISC) &&
+ (dma->cf_cmd.i596_config[8] & 0x01)) {
+ dma->cf_cmd.i596_config[8] &= ~0x01;
+ config = 1;
+ }
+ if ((dev->flags & IFF_ALLMULTI) &&
+ (dma->cf_cmd.i596_config[11] & 0x20)) {
+ dma->cf_cmd.i596_config[11] &= ~0x20;
+ config = 1;
+ }
+ if (!(dev->flags & IFF_ALLMULTI) &&
+ !(dma->cf_cmd.i596_config[11] & 0x20)) {
+ dma->cf_cmd.i596_config[11] |= 0x20;
+ config = 1;
+ }
+ if (config) {
+ if (dma->cf_cmd.cmd.command)
+ printk(KERN_INFO
+ "%s: config change request already queued\n",
+ dev->name);
+ else {
+ dma->cf_cmd.cmd.command = SWAP16(CmdConfigure);
+ DMA_WBACK_INV(dev, &dma->cf_cmd, sizeof(struct cf_cmd));
+ i596_add_cmd(dev, &dma->cf_cmd.cmd);
+ }
+ }
+
+ cnt = netdev_mc_count(dev);
+ if (cnt > MAX_MC_CNT) {
+ cnt = MAX_MC_CNT;
+ printk(KERN_NOTICE "%s: Only %d multicast addresses supported",
+ dev->name, cnt);
+ }
+
+ if (!netdev_mc_empty(dev)) {
+ struct netdev_hw_addr *ha;
+ unsigned char *cp;
+ struct mc_cmd *cmd;
+
+ cmd = &dma->mc_cmd;
+ cmd->cmd.command = SWAP16(CmdMulticastList);
+ cmd->mc_cnt = SWAP16(netdev_mc_count(dev) * 6);
+ cp = cmd->mc_addrs;
+ netdev_for_each_mc_addr(ha, dev) {
+ if (!cnt--)
+ break;
+ memcpy(cp, ha->addr, 6);
+ if (i596_debug > 1)
+ DEB(DEB_MULTI,
+ printk(KERN_DEBUG
+ "%s: Adding address %pM\n",
+ dev->name, cp));
+ cp += 6;
+ }
+ DMA_WBACK_INV(dev, &dma->mc_cmd, sizeof(struct mc_cmd));
+ i596_add_cmd(dev, &cmd->cmd);
+ }
+}
--- /dev/null
+/* Intel Professional Workstation/panther ethernet driver */
+/* lp486e.c: A panther 82596 ethernet driver for linux. */
+/*
+ History and copyrights:
+
+ Driver skeleton
+ Written 1993 by Donald Becker.
+ Copyright 1993 United States Government as represented by the Director,
+ National Security Agency. This software may only be used and
+ distributed according to the terms of the GNU General Public License
+ as modified by SRC, incorporated herein by reference.
+
+ The author may be reached as becker@scyld.com, or C/O
+ Scyld Computing Corporation
+ 410 Severn Ave., Suite 210
+ Annapolis MD 21403
+
+ Apricot
+ Written 1994 by Mark Evans.
+ This driver is for the Apricot 82596 bus-master interface
+
+ Modularised 12/94 Mark Evans
+
+ Professional Workstation
+ Derived from apricot.c by Ard van Breemen
+ <ard@murphy.nl>|<ard@cstmel.hobby.nl>|<ard@cstmel.nl.eu.org>
+
+ Credits:
+ Thanks to Murphy Software BV for letting me write this in their time.
+ Well, actually, I get paid doing this...
+ (Also: see http://www.murphy.nl for murphy, and my homepage ~ard for
+ more information on the Professional Workstation)
+
+ Present version
+ aeb@cwi.nl
+*/
+/*
+ There are currently two motherboards that I know of in the
+ professional workstation. The only one that I know is the
+ intel panther motherboard. -- ard
+*/
+/*
+The pws is equipped with an intel 82596. This is a very intelligent controller
+which runs its own micro-code. Communication with the hostprocessor is done
+through linked lists of commands and buffers in the hostprocessors memory.
+A complete description of the 82596 is available from intel. Search for
+a file called "29021806.pdf". It is a complete description of the chip itself.
+To use it for the pws some additions are needed regarding generation of
+the PORT and CA signal, and the interrupt glue needed for a pc.
+I/O map:
+PORT SIZE ACTION MEANING
+0xCB0 2 WRITE Lower 16 bits for PORT command
+0xCB2 2 WRITE Upper 16 bits for PORT command, and issue of PORT command
+0xCB4 1 WRITE Generation of CA signal
+0xCB8 1 WRITE Clear interrupt glue
+All other communication is through memory!
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/bitops.h>
+
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#define DRV_NAME "lp486e"
+
+/* debug print flags */
+#define LOG_SRCDST 0x80000000
+#define LOG_STATINT 0x40000000
+#define LOG_STARTINT 0x20000000
+
+#define i596_debug debug
+
+static int i596_debug = 0;
+
+static const char * const medianame[] = {
+ "10baseT", "AUI",
+ "10baseT-FD", "AUI-FD",
+};
+
+#define LP486E_TOTAL_SIZE 16
+
+#define I596_NULL (0xffffffff)
+
+#define CMD_EOL 0x8000 /* The last command of the list, stop. */
+#define CMD_SUSP 0x4000 /* Suspend after doing cmd. */
+#define CMD_INTR 0x2000 /* Interrupt after doing cmd. */
+
+#define CMD_FLEX 0x0008 /* Enable flexible memory model */
+
+enum commands {
+ CmdNOP = 0,
+ CmdIASetup = 1,
+ CmdConfigure = 2,
+ CmdMulticastList = 3,
+ CmdTx = 4,
+ CmdTDR = 5,
+ CmdDump = 6,
+ CmdDiagnose = 7
+};
+
+#if 0
+static const char *CUcmdnames[8] = { "NOP", "IASetup", "Configure", "MulticastList",
+ "Tx", "TDR", "Dump", "Diagnose" };
+#endif
+
+/* Status word bits */
+#define STAT_CX 0x8000 /* The CU finished executing a command
+ with the Interrupt bit set */
+#define STAT_FR 0x4000 /* The RU finished receiving a frame */
+#define STAT_CNA 0x2000 /* The CU left the active state */
+#define STAT_RNR 0x1000 /* The RU left the active state */
+#define STAT_ACK (STAT_CX | STAT_FR | STAT_CNA | STAT_RNR)
+#define STAT_CUS 0x0700 /* Status of CU: 0: idle, 1: suspended,
+ 2: active, 3-7: unused */
+#define STAT_RUS 0x00f0 /* Status of RU: 0: idle, 1: suspended,
+ 2: no resources, 4: ready,
+ 10: no resources due to no more RBDs,
+ 12: no more RBDs, other: unused */
+#define STAT_T 0x0008 /* Bus throttle timers loaded */
+#define STAT_ZERO 0x0807 /* Always zero */
+
+#if 0
+static char *CUstates[8] = {
+ "idle", "suspended", "active", 0, 0, 0, 0, 0
+};
+static char *RUstates[16] = {
+ "idle", "suspended", "no resources", 0, "ready", 0, 0, 0,
+ 0, 0, "no RBDs", 0, "out of RBDs", 0, 0, 0
+};
+
+static void
+i596_out_status(int status) {
+ int bad = 0;
+ char *s;
+
+ printk("status %4.4x:", status);
+ if (status == 0xffff)
+ printk(" strange..\n");
+ else {
+ if (status & STAT_CX)
+ printk(" CU done");
+ if (status & STAT_CNA)
+ printk(" CU stopped");
+ if (status & STAT_FR)
+ printk(" got a frame");
+ if (status & STAT_RNR)
+ printk(" RU stopped");
+ if (status & STAT_T)
+ printk(" throttled");
+ if (status & STAT_ZERO)
+ bad = 1;
+ s = CUstates[(status & STAT_CUS) >> 8];
+ if (!s)
+ bad = 1;
+ else
+ printk(" CU(%s)", s);
+ s = RUstates[(status & STAT_RUS) >> 4];
+ if (!s)
+ bad = 1;
+ else
+ printk(" RU(%s)", s);
+ if (bad)
+ printk(" bad status");
+ printk("\n");
+ }
+}
+#endif
+
+/* Command word bits */
+#define ACK_CX 0x8000
+#define ACK_FR 0x4000
+#define ACK_CNA 0x2000
+#define ACK_RNR 0x1000
+
+#define CUC_START 0x0100
+#define CUC_RESUME 0x0200
+#define CUC_SUSPEND 0x0300
+#define CUC_ABORT 0x0400
+
+#define RX_START 0x0010
+#define RX_RESUME 0x0020
+#define RX_SUSPEND 0x0030
+#define RX_ABORT 0x0040
+
+typedef u32 phys_addr;
+
+static inline phys_addr
+va_to_pa(void *x) {
+ return x ? virt_to_bus(x) : I596_NULL;
+}
+
+static inline void *
+pa_to_va(phys_addr x) {
+ return (x == I596_NULL) ? NULL : bus_to_virt(x);
+}
+
+/* status bits for cmd */
+#define CMD_STAT_C 0x8000 /* CU command complete */
+#define CMD_STAT_B 0x4000 /* CU command in progress */
+#define CMD_STAT_OK 0x2000 /* CU command completed without errors */
+#define CMD_STAT_A 0x1000 /* CU command abnormally terminated */
+
+struct i596_cmd { /* 8 bytes */
+ unsigned short status;
+ unsigned short command;
+ phys_addr pa_next; /* va_to_pa(struct i596_cmd *next) */
+};
+
+#define EOF 0x8000
+#define SIZE_MASK 0x3fff
+
+struct i596_tbd {
+ unsigned short size;
+ unsigned short pad;
+ phys_addr pa_next; /* va_to_pa(struct i596_tbd *next) */
+ phys_addr pa_data; /* va_to_pa(char *data) */
+ struct sk_buff *skb;
+};
+
+struct tx_cmd {
+ struct i596_cmd cmd;
+ phys_addr pa_tbd; /* va_to_pa(struct i596_tbd *tbd) */
+ unsigned short size;
+ unsigned short pad;
+};
+
+/* status bits for rfd */
+#define RFD_STAT_C 0x8000 /* Frame reception complete */
+#define RFD_STAT_B 0x4000 /* Frame reception in progress */
+#define RFD_STAT_OK 0x2000 /* Frame received without errors */
+#define RFD_STATUS 0x1fff
+#define RFD_LENGTH_ERR 0x1000
+#define RFD_CRC_ERR 0x0800
+#define RFD_ALIGN_ERR 0x0400
+#define RFD_NOBUFS_ERR 0x0200
+#define RFD_DMA_ERR 0x0100 /* DMA overrun failure to acquire system bus */
+#define RFD_SHORT_FRAME_ERR 0x0080
+#define RFD_NOEOP_ERR 0x0040
+#define RFD_TRUNC_ERR 0x0020
+#define RFD_MULTICAST 0x0002 /* 0: destination had our address
+ 1: destination was broadcast/multicast */
+#define RFD_COLLISION 0x0001
+
+/* receive frame descriptor */
+struct i596_rfd {
+ unsigned short stat;
+ unsigned short cmd;
+ phys_addr pa_next; /* va_to_pa(struct i596_rfd *next) */
+ phys_addr pa_rbd; /* va_to_pa(struct i596_rbd *rbd) */
+ unsigned short count;
+ unsigned short size;
+ char data[1532];
+};
+
+#define RBD_EL 0x8000
+#define RBD_P 0x4000
+#define RBD_SIZEMASK 0x3fff
+#define RBD_EOF 0x8000
+#define RBD_F 0x4000
+
+/* receive buffer descriptor */
+struct i596_rbd {
+ unsigned short size;
+ unsigned short pad;
+ phys_addr pa_next; /* va_to_pa(struct i596_tbd *next) */
+ phys_addr pa_data; /* va_to_pa(char *data) */
+ phys_addr pa_prev; /* va_to_pa(struct i596_tbd *prev) */
+
+ /* Driver private part */
+ struct sk_buff *skb;
+};
+
+#define RX_RING_SIZE 64
+#define RX_SKBSIZE (ETH_FRAME_LEN+10)
+#define RX_RBD_SIZE 32
+
+/* System Control Block - 40 bytes */
+struct i596_scb {
+ u16 status; /* 0 */
+ u16 command; /* 2 */
+ phys_addr pa_cmd; /* 4 - va_to_pa(struct i596_cmd *cmd) */
+ phys_addr pa_rfd; /* 8 - va_to_pa(struct i596_rfd *rfd) */
+ u32 crc_err; /* 12 */
+ u32 align_err; /* 16 */
+ u32 resource_err; /* 20 */
+ u32 over_err; /* 24 */
+ u32 rcvdt_err; /* 28 */
+ u32 short_err; /* 32 */
+ u16 t_on; /* 36 */
+ u16 t_off; /* 38 */
+};
+
+/* Intermediate System Configuration Pointer - 8 bytes */
+struct i596_iscp {
+ u32 busy; /* 0 */
+ phys_addr pa_scb; /* 4 - va_to_pa(struct i596_scb *scb) */
+};
+
+/* System Configuration Pointer - 12 bytes */
+struct i596_scp {
+ u32 sysbus; /* 0 */
+ u32 pad; /* 4 */
+ phys_addr pa_iscp; /* 8 - va_to_pa(struct i596_iscp *iscp) */
+};
+
+/* Selftest and dump results - needs 16-byte alignment */
+/*
+ * The size of the dump area is 304 bytes. When the dump is executed
+ * by the Port command an extra word will be appended to the dump area.
+ * The extra word is a copy of the Dump status word (containing the
+ * C, B, OK bits). [I find 0xa006, with a0 for C+OK and 6 for dump]
+ */
+struct i596_dump {
+ u16 dump[153]; /* (304 = 130h) + 2 bytes */
+};
+
+struct i596_private { /* aligned to a 16-byte boundary */
+ struct i596_scp scp; /* 0 - needs 16-byte alignment */
+ struct i596_iscp iscp; /* 12 */
+ struct i596_scb scb; /* 20 */
+ u32 dummy; /* 60 */
+ struct i596_dump dump; /* 64 - needs 16-byte alignment */
+
+ struct i596_cmd set_add;
+ char eth_addr[8]; /* directly follows set_add */
+
+ struct i596_cmd set_conf;
+ char i596_config[16]; /* directly follows set_conf */
+
+ struct i596_cmd tdr;
+ unsigned long tdr_stat; /* directly follows tdr */
+
+ int last_restart;
+ struct i596_rbd *rbd_list;
+ struct i596_rbd *rbd_tail;
+ struct i596_rfd *rx_tail;
+ struct i596_cmd *cmd_tail;
+ struct i596_cmd *cmd_head;
+ int cmd_backlog;
+ unsigned long last_cmd;
+ spinlock_t cmd_lock;
+};
+
+static char init_setup[14] = {
+ 0x8E, /* length 14 bytes, prefetch on */
+ 0xC8, /* default: fifo to 8, monitor off */
+ 0x40, /* default: don't save bad frames (apricot.c had 0x80) */
+ 0x2E, /* (default is 0x26)
+ No source address insertion, 8 byte preamble */
+ 0x00, /* default priority and backoff */
+ 0x60, /* default interframe spacing */
+ 0x00, /* default slot time LSB */
+ 0xf2, /* default slot time and nr of retries */
+ 0x00, /* default various bits
+ (0: promiscuous mode, 1: broadcast disable,
+ 2: encoding mode, 3: transmit on no CRS,
+ 4: no CRC insertion, 5: CRC type,
+ 6: bit stuffing, 7: padding) */
+ 0x00, /* default carrier sense and collision detect */
+ 0x40, /* default minimum frame length */
+ 0xff, /* (default is 0xff, and that is what apricot.c has;
+ elp486.c has 0xfb: Enable crc append in memory.) */
+ 0x00, /* default: not full duplex */
+ 0x7f /* (default is 0x3f) multi IA */
+};
+
+static int i596_open(struct net_device *dev);
+static netdev_tx_t i596_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static irqreturn_t i596_interrupt(int irq, void *dev_id);
+static int i596_close(struct net_device *dev);
+static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd);
+static void print_eth(char *);
+static void set_multicast_list(struct net_device *dev);
+static void i596_tx_timeout(struct net_device *dev);
+
+static int
+i596_timeout(struct net_device *dev, char *msg, int ct) {
+ struct i596_private *lp;
+ int boguscnt = ct;
+
+ lp = netdev_priv(dev);
+ while (lp->scb.command) {
+ if (--boguscnt == 0) {
+ printk("%s: %s timed out - stat %4.4x, cmd %4.4x\n",
+ dev->name, msg,
+ lp->scb.status, lp->scb.command);
+ return 1;
+ }
+ udelay(5);
+ barrier();
+ }
+ return 0;
+}
+
+static inline int
+init_rx_bufs(struct net_device *dev, int num) {
+ struct i596_private *lp;
+ struct i596_rfd *rfd;
+ int i;
+ // struct i596_rbd *rbd;
+
+ lp = netdev_priv(dev);
+ lp->scb.pa_rfd = I596_NULL;
+
+ for (i = 0; i < num; i++) {
+ rfd = kmalloc(sizeof(struct i596_rfd), GFP_KERNEL);
+ if (rfd == NULL)
+ break;
+
+ rfd->stat = 0;
+ rfd->pa_rbd = I596_NULL;
+ rfd->count = 0;
+ rfd->size = 1532;
+ if (i == 0) {
+ rfd->cmd = CMD_EOL;
+ lp->rx_tail = rfd;
+ } else {
+ rfd->cmd = 0;
+ }
+ rfd->pa_next = lp->scb.pa_rfd;
+ lp->scb.pa_rfd = va_to_pa(rfd);
+ lp->rx_tail->pa_next = lp->scb.pa_rfd;
+ }
+
+#if 0
+ for (i = 0; i<RX_RBD_SIZE; i++) {
+ rbd = kmalloc(sizeof(struct i596_rbd), GFP_KERNEL);
+ if (rbd) {
+ rbd->pad = 0;
+ rbd->count = 0;
+ rbd->skb = dev_alloc_skb(RX_SKBSIZE);
+ if (!rbd->skb) {
+ printk("dev_alloc_skb failed");
+ }
+ rbd->next = rfd->rbd;
+ if (i) {
+ rfd->rbd->prev = rbd;
+ rbd->size = RX_SKBSIZE;
+ } else {
+ rbd->size = (RX_SKBSIZE | RBD_EL);
+ lp->rbd_tail = rbd;
+ }
+
+ rfd->rbd = rbd;
+ } else {
+ printk("Could not kmalloc rbd\n");
+ }
+ }
+ lp->rbd_tail->next = rfd->rbd;
+#endif
+ return i;
+}
+
+static inline void
+remove_rx_bufs(struct net_device *dev) {
+ struct i596_private *lp;
+ struct i596_rfd *rfd;
+
+ lp = netdev_priv(dev);
+ lp->rx_tail->pa_next = I596_NULL;
+
+ do {
+ rfd = pa_to_va(lp->scb.pa_rfd);
+ lp->scb.pa_rfd = rfd->pa_next;
+ kfree(rfd);
+ } while (rfd != lp->rx_tail);
+
+ lp->rx_tail = NULL;
+
+#if 0
+ for (lp->rbd_list) {
+ }
+#endif
+}
+
+#define PORT_RESET 0x00 /* reset 82596 */
+#define PORT_SELFTEST 0x01 /* selftest */
+#define PORT_ALTSCP 0x02 /* alternate SCB address */
+#define PORT_DUMP 0x03 /* dump */
+
+#define IOADDR 0xcb0 /* real constant */
+#define IRQ 10 /* default IRQ - can be changed by ECU */
+
+/* The 82596 requires two 16-bit write cycles for a port command */
+static inline void
+PORT(phys_addr a, unsigned int cmd) {
+ if (a & 0xf)
+ printk("lp486e.c: PORT: address not aligned\n");
+ outw(((a & 0xffff) | cmd), IOADDR);
+ outw(((a>>16) & 0xffff), IOADDR+2);
+}
+
+static inline void
+CA(void) {
+ outb(0, IOADDR+4);
+ udelay(8);
+}
+
+static inline void
+CLEAR_INT(void) {
+ outb(0, IOADDR+8);
+}
+
+#if 0
+/* selftest or dump */
+static void
+i596_port_do(struct net_device *dev, int portcmd, char *cmdname) {
+ struct i596_private *lp = netdev_priv(dev);
+ u16 *outp;
+ int i, m;
+
+ memset((void *)&(lp->dump), 0, sizeof(struct i596_dump));
+ outp = &(lp->dump.dump[0]);
+
+ PORT(va_to_pa(outp), portcmd);
+ mdelay(30); /* random, unmotivated */
+
+ printk("lp486e i82596 %s result:\n", cmdname);
+ for (m = ARRAY_SIZE(lp->dump.dump); m && lp->dump.dump[m-1] == 0; m--)
+ ;
+ for (i = 0; i < m; i++) {
+ printk(" %04x", lp->dump.dump[i]);
+ if (i%8 == 7)
+ printk("\n");
+ }
+ printk("\n");
+}
+#endif
+
+static int
+i596_scp_setup(struct net_device *dev) {
+ struct i596_private *lp = netdev_priv(dev);
+ int boguscnt;
+
+ /* Setup SCP, ISCP, SCB */
+ /*
+ * sysbus bits:
+ * only a single byte is significant - here 0x44
+ * 0x80: big endian mode (details depend on stepping)
+ * 0x40: 1
+ * 0x20: interrupt pin is active low
+ * 0x10: lock function disabled
+ * 0x08: external triggering of bus throttle timers
+ * 0x06: 00: 82586 compat mode, 01: segmented mode, 10: linear mode
+ * 0x01: unused
+ */
+ lp->scp.sysbus = 0x00440000; /* linear mode */
+ lp->scp.pad = 0; /* must be zero */
+ lp->scp.pa_iscp = va_to_pa(&(lp->iscp));
+
+ /*
+ * The CPU sets the ISCP to 1 before it gives the first CA()
+ */
+ lp->iscp.busy = 0x0001;
+ lp->iscp.pa_scb = va_to_pa(&(lp->scb));
+
+ lp->scb.command = 0;
+ lp->scb.status = 0;
+ lp->scb.pa_cmd = I596_NULL;
+ /* lp->scb.pa_rfd has been initialised already */
+
+ lp->last_cmd = jiffies;
+ lp->cmd_backlog = 0;
+ lp->cmd_head = NULL;
+
+ /*
+ * Reset the 82596.
+ * We need to wait 10 systemclock cycles, and
+ * 5 serial clock cycles.
+ */
+ PORT(0, PORT_RESET); /* address part ignored */
+ udelay(100);
+
+ /*
+ * Before the CA signal is asserted, the default SCP address
+ * (0x00fffff4) can be changed to a 16-byte aligned value
+ */
+ PORT(va_to_pa(&lp->scp), PORT_ALTSCP); /* change the scp address */
+
+ /*
+ * The initialization procedure begins when a
+ * Channel Attention signal is asserted after a reset.
+ */
+
+ CA();
+
+ /*
+ * The ISCP busy is cleared by the 82596 after the SCB address is read.
+ */
+ boguscnt = 100;
+ while (lp->iscp.busy) {
+ if (--boguscnt == 0) {
+ /* No i82596 present? */
+ printk("%s: i82596 initialization timed out\n",
+ dev->name);
+ return 1;
+ }
+ udelay(5);
+ barrier();
+ }
+ /* I find here boguscnt==100, so no delay was required. */
+
+ return 0;
+}
+
+static int
+init_i596(struct net_device *dev) {
+ struct i596_private *lp;
+
+ if (i596_scp_setup(dev))
+ return 1;
+
+ lp = netdev_priv(dev);
+ lp->scb.command = 0;
+
+ memcpy ((void *)lp->i596_config, init_setup, 14);
+ lp->set_conf.command = CmdConfigure;
+ i596_add_cmd(dev, (void *)&lp->set_conf);
+
+ memcpy ((void *)lp->eth_addr, dev->dev_addr, 6);
+ lp->set_add.command = CmdIASetup;
+ i596_add_cmd(dev, (struct i596_cmd *)&lp->set_add);
+
+ lp->tdr.command = CmdTDR;
+ i596_add_cmd(dev, (struct i596_cmd *)&lp->tdr);
+
+ if (lp->scb.command && i596_timeout(dev, "i82596 init", 200))
+ return 1;
+
+ lp->scb.command = RX_START;
+ CA();
+
+ barrier();
+
+ if (lp->scb.command && i596_timeout(dev, "Receive Unit start", 100))
+ return 1;
+
+ return 0;
+}
+
+/* Receive a single frame */
+static inline int
+i596_rx_one(struct net_device *dev, struct i596_private *lp,
+ struct i596_rfd *rfd, int *frames) {
+
+ if (rfd->stat & RFD_STAT_OK) {
+ /* a good frame */
+ int pkt_len = (rfd->count & 0x3fff);
+ struct sk_buff *skb = dev_alloc_skb(pkt_len);
+
+ (*frames)++;
+
+ if (rfd->cmd & CMD_EOL)
+ printk("Received on EOL\n");
+
+ if (skb == NULL) {
+ printk ("%s: i596_rx Memory squeeze, "
+ "dropping packet.\n", dev->name);
+ dev->stats.rx_dropped++;
+ return 1;
+ }
+
+ memcpy(skb_put(skb,pkt_len), rfd->data, pkt_len);
+
+ skb->protocol = eth_type_trans(skb,dev);
+ netif_rx(skb);
+ dev->stats.rx_packets++;
+ } else {
+#if 0
+ printk("Frame reception error status %04x\n",
+ rfd->stat);
+#endif
+ dev->stats.rx_errors++;
+ if (rfd->stat & RFD_COLLISION)
+ dev->stats.collisions++;
+ if (rfd->stat & RFD_SHORT_FRAME_ERR)
+ dev->stats.rx_length_errors++;
+ if (rfd->stat & RFD_DMA_ERR)
+ dev->stats.rx_over_errors++;
+ if (rfd->stat & RFD_NOBUFS_ERR)
+ dev->stats.rx_fifo_errors++;
+ if (rfd->stat & RFD_ALIGN_ERR)
+ dev->stats.rx_frame_errors++;
+ if (rfd->stat & RFD_CRC_ERR)
+ dev->stats.rx_crc_errors++;
+ if (rfd->stat & RFD_LENGTH_ERR)
+ dev->stats.rx_length_errors++;
+ }
+ rfd->stat = rfd->count = 0;
+ return 0;
+}
+
+static int
+i596_rx(struct net_device *dev) {
+ struct i596_private *lp = netdev_priv(dev);
+ struct i596_rfd *rfd;
+ int frames = 0;
+
+ while (1) {
+ rfd = pa_to_va(lp->scb.pa_rfd);
+ if (!rfd) {
+ printk(KERN_ERR "i596_rx: NULL rfd?\n");
+ return 0;
+ }
+#if 1
+ if (rfd->stat && !(rfd->stat & (RFD_STAT_C | RFD_STAT_B)))
+ printk("SF:%p-%04x\n", rfd, rfd->stat);
+#endif
+ if (!(rfd->stat & RFD_STAT_C))
+ break; /* next one not ready */
+ if (i596_rx_one(dev, lp, rfd, &frames))
+ break; /* out of memory */
+ rfd->cmd = CMD_EOL;
+ lp->rx_tail->cmd = 0;
+ lp->rx_tail = rfd;
+ lp->scb.pa_rfd = rfd->pa_next;
+ barrier();
+ }
+
+ return frames;
+}
+
+static void
+i596_cleanup_cmd(struct net_device *dev) {
+ struct i596_private *lp;
+ struct i596_cmd *cmd;
+
+ lp = netdev_priv(dev);
+ while (lp->cmd_head) {
+ cmd = (struct i596_cmd *)lp->cmd_head;
+
+ lp->cmd_head = pa_to_va(lp->cmd_head->pa_next);
+ lp->cmd_backlog--;
+
+ switch ((cmd->command) & 0x7) {
+ case CmdTx: {
+ struct tx_cmd *tx_cmd = (struct tx_cmd *) cmd;
+ struct i596_tbd * tx_cmd_tbd;
+ tx_cmd_tbd = pa_to_va(tx_cmd->pa_tbd);
+
+ dev_kfree_skb_any(tx_cmd_tbd->skb);
+
+ dev->stats.tx_errors++;
+ dev->stats.tx_aborted_errors++;
+
+ cmd->pa_next = I596_NULL;
+ kfree((unsigned char *)tx_cmd);
+ netif_wake_queue(dev);
+ break;
+ }
+ case CmdMulticastList: {
+ // unsigned short count = *((unsigned short *) (ptr + 1));
+
+ cmd->pa_next = I596_NULL;
+ kfree((unsigned char *)cmd);
+ break;
+ }
+ default: {
+ cmd->pa_next = I596_NULL;
+ break;
+ }
+ }
+ barrier();
+ }
+
+ if (lp->scb.command && i596_timeout(dev, "i596_cleanup_cmd", 100))
+ ;
+
+ lp->scb.pa_cmd = va_to_pa(lp->cmd_head);
+}
+
+static void i596_reset(struct net_device *dev, struct i596_private *lp, int ioaddr) {
+
+ if (lp->scb.command && i596_timeout(dev, "i596_reset", 100))
+ ;
+
+ netif_stop_queue(dev);
+
+ lp->scb.command = CUC_ABORT | RX_ABORT;
+ CA();
+ barrier();
+
+ /* wait for shutdown */
+ if (lp->scb.command && i596_timeout(dev, "i596_reset(2)", 400))
+ ;
+
+ i596_cleanup_cmd(dev);
+ i596_rx(dev);
+
+ netif_start_queue(dev);
+ /*dev_kfree_skb(skb, FREE_WRITE);*/
+ init_i596(dev);
+}
+
+static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd) {
+ struct i596_private *lp = netdev_priv(dev);
+ int ioaddr = dev->base_addr;
+ unsigned long flags;
+
+ cmd->status = 0;
+ cmd->command |= (CMD_EOL | CMD_INTR);
+ cmd->pa_next = I596_NULL;
+
+ spin_lock_irqsave(&lp->cmd_lock, flags);
+
+ if (lp->cmd_head) {
+ lp->cmd_tail->pa_next = va_to_pa(cmd);
+ } else {
+ lp->cmd_head = cmd;
+ if (lp->scb.command && i596_timeout(dev, "i596_add_cmd", 100))
+ ;
+ lp->scb.pa_cmd = va_to_pa(cmd);
+ lp->scb.command = CUC_START;
+ CA();
+ }
+ lp->cmd_tail = cmd;
+ lp->cmd_backlog++;
+
+ lp->cmd_head = pa_to_va(lp->scb.pa_cmd);
+ spin_unlock_irqrestore(&lp->cmd_lock, flags);
+
+ if (lp->cmd_backlog > 16) {
+ int tickssofar = jiffies - lp->last_cmd;
+ if (tickssofar < HZ/4)
+ return;
+
+ printk(KERN_WARNING "%s: command unit timed out, status resetting.\n", dev->name);
+ i596_reset(dev, lp, ioaddr);
+ }
+}
+
+static int i596_open(struct net_device *dev)
+{
+ int i;
+
+ i = request_irq(dev->irq, i596_interrupt, IRQF_SHARED, dev->name, dev);
+ if (i) {
+ printk(KERN_ERR "%s: IRQ %d not free\n", dev->name, dev->irq);
+ return i;
+ }
+
+ if ((i = init_rx_bufs(dev, RX_RING_SIZE)) < RX_RING_SIZE)
+ printk(KERN_ERR "%s: only able to allocate %d receive buffers\n", dev->name, i);
+
+ if (i < 4) {
+ free_irq(dev->irq, dev);
+ return -EAGAIN;
+ }
+ netif_start_queue(dev);
+ init_i596(dev);
+ return 0; /* Always succeed */
+}
+
+static netdev_tx_t i596_start_xmit (struct sk_buff *skb, struct net_device *dev) {
+ struct tx_cmd *tx_cmd;
+ short length;
+
+ length = skb->len;
+
+ if (length < ETH_ZLEN) {
+ if (skb_padto(skb, ETH_ZLEN))
+ return NETDEV_TX_OK;
+ length = ETH_ZLEN;
+ }
+
+ tx_cmd = kmalloc((sizeof (struct tx_cmd) + sizeof (struct i596_tbd)), GFP_ATOMIC);
+ if (tx_cmd == NULL) {
+ printk(KERN_WARNING "%s: i596_xmit Memory squeeze, dropping packet.\n", dev->name);
+ dev->stats.tx_dropped++;
+ dev_kfree_skb (skb);
+ } else {
+ struct i596_tbd *tx_cmd_tbd;
+ tx_cmd_tbd = (struct i596_tbd *) (tx_cmd + 1);
+ tx_cmd->pa_tbd = va_to_pa (tx_cmd_tbd);
+ tx_cmd_tbd->pa_next = I596_NULL;
+
+ tx_cmd->cmd.command = (CMD_FLEX | CmdTx);
+
+ tx_cmd->pad = 0;
+ tx_cmd->size = 0;
+ tx_cmd_tbd->pad = 0;
+ tx_cmd_tbd->size = (EOF | length);
+
+ tx_cmd_tbd->pa_data = va_to_pa (skb->data);
+ tx_cmd_tbd->skb = skb;
+
+ if (i596_debug & LOG_SRCDST)
+ print_eth (skb->data);
+
+ i596_add_cmd (dev, (struct i596_cmd *) tx_cmd);
+
+ dev->stats.tx_packets++;
+ }
+
+ return NETDEV_TX_OK;
+}
+
+static void
+i596_tx_timeout (struct net_device *dev) {
+ struct i596_private *lp = netdev_priv(dev);
+ int ioaddr = dev->base_addr;
+
+ /* Transmitter timeout, serious problems. */
+ printk(KERN_WARNING "%s: transmit timed out, status resetting.\n", dev->name);
+ dev->stats.tx_errors++;
+
+ /* Try to restart the adaptor */
+ if (lp->last_restart == dev->stats.tx_packets) {
+ printk ("Resetting board.\n");
+
+ /* Shutdown and restart */
+ i596_reset (dev, lp, ioaddr);
+ } else {
+ /* Issue a channel attention signal */
+ printk ("Kicking board.\n");
+ lp->scb.command = (CUC_START | RX_START);
+ CA();
+ lp->last_restart = dev->stats.tx_packets;
+ }
+ netif_wake_queue(dev);
+}
+
+static void print_eth(char *add)
+{
+ int i;
+
+ printk ("Dest ");
+ for (i = 0; i < 6; i++)
+ printk(" %2.2X", (unsigned char) add[i]);
+ printk ("\n");
+
+ printk ("Source");
+ for (i = 0; i < 6; i++)
+ printk(" %2.2X", (unsigned char) add[i+6]);
+ printk ("\n");
+
+ printk ("type %2.2X%2.2X\n",
+ (unsigned char) add[12], (unsigned char) add[13]);
+}
+
+static const struct net_device_ops i596_netdev_ops = {
+ .ndo_open = i596_open,
+ .ndo_stop = i596_close,
+ .ndo_start_xmit = i596_start_xmit,
+ .ndo_set_multicast_list = set_multicast_list,
+ .ndo_tx_timeout = i596_tx_timeout,
+ .ndo_change_mtu = eth_change_mtu,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+};
+
+static int __init lp486e_probe(struct net_device *dev) {
+ struct i596_private *lp;
+ unsigned char eth_addr[6] = { 0, 0xaa, 0, 0, 0, 0 };
+ unsigned char *bios;
+ int i, j;
+ int ret = -ENOMEM;
+ static int probed;
+
+ if (probed)
+ return -ENODEV;
+ probed++;
+
+ if (!request_region(IOADDR, LP486E_TOTAL_SIZE, DRV_NAME)) {
+ printk(KERN_ERR "lp486e: IO address 0x%x in use\n", IOADDR);
+ return -EBUSY;
+ }
+
+ lp = netdev_priv(dev);
+ spin_lock_init(&lp->cmd_lock);
+
+ /*
+ * Do we really have this thing?
+ */
+ if (i596_scp_setup(dev)) {
+ ret = -ENODEV;
+ goto err_out_kfree;
+ }
+
+ dev->base_addr = IOADDR;
+ dev->irq = IRQ;
+
+
+ /*
+ * How do we find the ethernet address? I don't know.
+ * One possibility is to look at the EISA configuration area
+ * [0xe8000-0xe9fff]. This contains the ethernet address
+ * but not at a fixed address - things depend on setup options.
+ *
+ * If we find no address, or the wrong address, use
+ * ifconfig eth0 hw ether a1:a2:a3:a4:a5:a6
+ * with the value found in the BIOS setup.
+ */
+ bios = bus_to_virt(0xe8000);
+ for (j = 0; j < 0x2000; j++) {
+ if (bios[j] == 0 && bios[j+1] == 0xaa && bios[j+2] == 0) {
+ printk("%s: maybe address at BIOS 0x%x:",
+ dev->name, 0xe8000+j);
+ for (i = 0; i < 6; i++) {
+ eth_addr[i] = bios[i+j];
+ printk(" %2.2X", eth_addr[i]);
+ }
+ printk("\n");
+ }
+ }
+
+ printk("%s: lp486e 82596 at %#3lx, IRQ %d,",
+ dev->name, dev->base_addr, dev->irq);
+ for (i = 0; i < 6; i++)
+ printk(" %2.2X", dev->dev_addr[i] = eth_addr[i]);
+ printk("\n");
+
+ /* The LP486E-specific entries in the device structure. */
+ dev->netdev_ops = &i596_netdev_ops;
+ dev->watchdog_timeo = 5*HZ;
+
+#if 0
+ /* selftest reports 0x320925ae - don't know what that means */
+ i596_port_do(dev, PORT_SELFTEST, "selftest");
+ i596_port_do(dev, PORT_DUMP, "dump");
+#endif
+ return 0;
+
+err_out_kfree:
+ release_region(IOADDR, LP486E_TOTAL_SIZE);
+ return ret;
+}
+
+static inline void
+i596_handle_CU_completion(struct net_device *dev,
+ struct i596_private *lp,
+ unsigned short status,
+ unsigned short *ack_cmdp) {
+ struct i596_cmd *cmd;
+ int frames_out = 0;
+ int commands_done = 0;
+ int cmd_val;
+ unsigned long flags;
+
+ spin_lock_irqsave(&lp->cmd_lock, flags);
+ cmd = lp->cmd_head;
+
+ while (lp->cmd_head && (lp->cmd_head->status & CMD_STAT_C)) {
+ cmd = lp->cmd_head;
+
+ lp->cmd_head = pa_to_va(lp->cmd_head->pa_next);
+ lp->cmd_backlog--;
+
+ commands_done++;
+ cmd_val = cmd->command & 0x7;
+#if 0
+ printk("finished CU %s command (%d)\n",
+ CUcmdnames[cmd_val], cmd_val);
+#endif
+ switch (cmd_val) {
+ case CmdTx:
+ {
+ struct tx_cmd *tx_cmd;
+ struct i596_tbd *tx_cmd_tbd;
+
+ tx_cmd = (struct tx_cmd *) cmd;
+ tx_cmd_tbd = pa_to_va(tx_cmd->pa_tbd);
+
+ frames_out++;
+ if (cmd->status & CMD_STAT_OK) {
+ if (i596_debug)
+ print_eth(pa_to_va(tx_cmd_tbd->pa_data));
+ } else {
+ dev->stats.tx_errors++;
+ if (i596_debug)
+ printk("transmission failure:%04x\n",
+ cmd->status);
+ if (cmd->status & 0x0020)
+ dev->stats.collisions++;
+ if (!(cmd->status & 0x0040))
+ dev->stats.tx_heartbeat_errors++;
+ if (cmd->status & 0x0400)
+ dev->stats.tx_carrier_errors++;
+ if (cmd->status & 0x0800)
+ dev->stats.collisions++;
+ if (cmd->status & 0x1000)
+ dev->stats.tx_aborted_errors++;
+ }
+ dev_kfree_skb_irq(tx_cmd_tbd->skb);
+
+ cmd->pa_next = I596_NULL;
+ kfree((unsigned char *)tx_cmd);
+ netif_wake_queue(dev);
+ break;
+ }
+
+ case CmdMulticastList:
+ cmd->pa_next = I596_NULL;
+ kfree((unsigned char *)cmd);
+ break;
+
+ case CmdTDR:
+ {
+ unsigned long status = *((unsigned long *) (cmd + 1));
+ if (status & 0x8000) {
+ if (i596_debug)
+ printk("%s: link ok.\n", dev->name);
+ } else {
+ if (status & 0x4000)
+ printk("%s: Transceiver problem.\n",
+ dev->name);
+ if (status & 0x2000)
+ printk("%s: Termination problem.\n",
+ dev->name);
+ if (status & 0x1000)
+ printk("%s: Short circuit.\n",
+ dev->name);
+ printk("%s: Time %ld.\n",
+ dev->name, status & 0x07ff);
+ }
+ }
+ default:
+ cmd->pa_next = I596_NULL;
+ lp->last_cmd = jiffies;
+
+ }
+ barrier();
+ }
+
+ cmd = lp->cmd_head;
+ while (cmd && (cmd != lp->cmd_tail)) {
+ cmd->command &= 0x1fff;
+ cmd = pa_to_va(cmd->pa_next);
+ barrier();
+ }
+
+ if (lp->cmd_head)
+ *ack_cmdp |= CUC_START;
+ lp->scb.pa_cmd = va_to_pa(lp->cmd_head);
+ spin_unlock_irqrestore(&lp->cmd_lock, flags);
+}
+
+static irqreturn_t
+i596_interrupt(int irq, void *dev_instance)
+{
+ struct net_device *dev = dev_instance;
+ struct i596_private *lp = netdev_priv(dev);
+ unsigned short status, ack_cmd = 0;
+ int frames_in = 0;
+
+ /*
+ * The 82596 examines the command, performs the required action,
+ * and then clears the SCB command word.
+ */
+ if (lp->scb.command && i596_timeout(dev, "interrupt", 40))
+ ;
+
+ /*
+ * The status word indicates the status of the 82596.
+ * It is modified only by the 82596.
+ *
+ * [So, we must not clear it. I find often status 0xffff,
+ * which is not one of the values allowed by the docs.]
+ */
+ status = lp->scb.status;
+#if 0
+ if (i596_debug) {
+ printk("%s: i596 interrupt, ", dev->name);
+ i596_out_status(status);
+ }
+#endif
+ /* Impossible, but it happens - perhaps when we get
+ a receive interrupt but scb.pa_rfd is I596_NULL. */
+ if (status == 0xffff) {
+ printk("%s: i596_interrupt: got status 0xffff\n", dev->name);
+ goto out;
+ }
+
+ ack_cmd = (status & STAT_ACK);
+
+ if (status & (STAT_CX | STAT_CNA))
+ i596_handle_CU_completion(dev, lp, status, &ack_cmd);
+
+ if (status & (STAT_FR | STAT_RNR)) {
+ /* Restart the receive unit when it got inactive somehow */
+ if ((status & STAT_RNR) && netif_running(dev))
+ ack_cmd |= RX_START;
+
+ if (status & STAT_FR) {
+ frames_in = i596_rx(dev);
+ if (!frames_in)
+ printk("receive frame reported, but no frames\n");
+ }
+ }
+
+ /* acknowledge the interrupt */
+ /*
+ if ((lp->scb.pa_cmd != I596_NULL) && netif_running(dev))
+ ack_cmd |= CUC_START;
+ */
+
+ if (lp->scb.command && i596_timeout(dev, "i596 interrupt", 100))
+ ;
+
+ lp->scb.command = ack_cmd;
+
+ CLEAR_INT();
+ CA();
+
+ out:
+ return IRQ_HANDLED;
+}
+
+static int i596_close(struct net_device *dev) {
+ struct i596_private *lp = netdev_priv(dev);
+
+ netif_stop_queue(dev);
+
+ if (i596_debug)
+ printk("%s: Shutting down ethercard, status was %4.4x.\n",
+ dev->name, lp->scb.status);
+
+ lp->scb.command = (CUC_ABORT | RX_ABORT);
+ CA();
+
+ i596_cleanup_cmd(dev);
+
+ if (lp->scb.command && i596_timeout(dev, "i596_close", 200))
+ ;
+
+ free_irq(dev->irq, dev);
+ remove_rx_bufs(dev);
+
+ return 0;
+}
+
+/*
+* Set or clear the multicast filter for this adaptor.
+*/
+
+static void set_multicast_list(struct net_device *dev) {
+ struct i596_private *lp = netdev_priv(dev);
+ struct i596_cmd *cmd;
+
+ if (i596_debug > 1)
+ printk ("%s: set multicast list %d\n",
+ dev->name, netdev_mc_count(dev));
+
+ if (!netdev_mc_empty(dev)) {
+ struct netdev_hw_addr *ha;
+ char *cp;
+ cmd = kmalloc(sizeof(struct i596_cmd) + 2 +
+ netdev_mc_count(dev) * 6, GFP_ATOMIC);
+ if (cmd == NULL) {
+ printk (KERN_ERR "%s: set_multicast Memory squeeze.\n", dev->name);
+ return;
+ }
+ cmd->command = CmdMulticastList;
+ *((unsigned short *) (cmd + 1)) = netdev_mc_count(dev) * 6;
+ cp = ((char *)(cmd + 1))+2;
+ netdev_for_each_mc_addr(ha, dev) {
+ memcpy(cp, ha->addr, 6);
+ cp += 6;
+ }
+ if (i596_debug & LOG_SRCDST)
+ print_eth (((char *)(cmd + 1)) + 2);
+ i596_add_cmd(dev, cmd);
+ } else {
+ if (lp->set_conf.pa_next != I596_NULL) {
+ return;
+ }
+ if (netdev_mc_empty(dev) &&
+ !(dev->flags & (IFF_PROMISC | IFF_ALLMULTI))) {
+ lp->i596_config[8] &= ~0x01;
+ } else {
+ lp->i596_config[8] |= 0x01;
+ }
+
+ i596_add_cmd(dev, (struct i596_cmd *) &lp->set_conf);
+ }
+}
+
+MODULE_AUTHOR("Ard van Breemen <ard@cstmel.nl.eu.org>");
+MODULE_DESCRIPTION("Intel Panther onboard i82596 driver");
+MODULE_LICENSE("GPL");
+
+static struct net_device *dev_lp486e;
+static int full_duplex;
+static int options;
+static int io = IOADDR;
+static int irq = IRQ;
+
+module_param(debug, int, 0);
+//module_param(max_interrupt_work, int, 0);
+//module_param(reverse_probe, int, 0);
+//module_param(rx_copybreak, int, 0);
+module_param(options, int, 0);
+module_param(full_duplex, int, 0);
+
+static int __init lp486e_init_module(void) {
+ int err;
+ struct net_device *dev = alloc_etherdev(sizeof(struct i596_private));
+ if (!dev)
+ return -ENOMEM;
+
+ dev->irq = irq;
+ dev->base_addr = io;
+ err = lp486e_probe(dev);
+ if (err) {
+ free_netdev(dev);
+ return err;
+ }
+ err = register_netdev(dev);
+ if (err) {
+ release_region(dev->base_addr, LP486E_TOTAL_SIZE);
+ free_netdev(dev);
+ return err;
+ }
+ dev_lp486e = dev;
+ full_duplex = 0;
+ options = 0;
+ return 0;
+}
+
+static void __exit lp486e_cleanup_module(void) {
+ unregister_netdev(dev_lp486e);
+ release_region(dev_lp486e->base_addr, LP486E_TOTAL_SIZE);
+ free_netdev(dev_lp486e);
+}
+
+module_init(lp486e_init_module);
+module_exit(lp486e_cleanup_module);
--- /dev/null
+/*
+ * net-3-driver for the NI5210 card (i82586 Ethernet chip)
+ *
+ * This is an extension to the Linux operating system, and is covered by the
+ * same GNU General Public License that covers that work.
+ *
+ * Alphacode 0.82 (96/09/29) for Linux 2.0.0 (or later)
+ * Copyrights (c) 1994,1995,1996 by M.Hipp (hippm@informatik.uni-tuebingen.de)
+ * [feel free to mail ....]
+ *
+ * when using as module: (no autoprobing!)
+ * run with e.g:
+ * insmod ni52.o io=0x360 irq=9 memstart=0xd0000 memend=0xd4000
+ *
+ * CAN YOU PLEASE REPORT ME YOUR PERFORMANCE EXPERIENCES !!.
+ *
+ * If you find a bug, please report me:
+ * The kernel panic output and any kmsg from the ni52 driver
+ * the ni5210-driver-version and the linux-kernel version
+ * how many shared memory (memsize) on the netcard,
+ * bootprom: yes/no, base_addr, mem_start
+ * maybe the ni5210-card revision and the i82586 version
+ *
+ * autoprobe for: base_addr: 0x300,0x280,0x360,0x320,0x340
+ * mem_start: 0xd0000,0xd2000,0xc8000,0xca000,0xd4000,0xd6000,
+ * 0xd8000,0xcc000,0xce000,0xda000,0xdc000
+ *
+ * sources:
+ * skeleton.c from Donald Becker
+ *
+ * I have also done a look in the following sources: (mail me if you need them)
+ * crynwr-packet-driver by Russ Nelson
+ * Garret A. Wollman's (fourth) i82586-driver for BSD
+ * (before getting an i82596 (yes 596 not 586) manual, the existing drivers
+ * helped me a lot to understand this tricky chip.)
+ *
+ * Known Problems:
+ * The internal sysbus seems to be slow. So we often lose packets because of
+ * overruns while receiving from a fast remote host.
+ * This can slow down TCP connections. Maybe the newer ni5210 cards are
+ * better. My experience is, that if a machine sends with more than about
+ * 500-600K/s the fifo/sysbus overflows.
+ *
+ * IMPORTANT NOTE:
+ * On fast networks, it's a (very) good idea to have 16K shared memory. With
+ * 8K, we can store only 4 receive frames, so it can (easily) happen that a
+ * remote machine 'overruns' our system.
+ *
+ * Known i82586/card problems (I'm sure, there are many more!):
+ * Running the NOP-mode, the i82586 sometimes seems to forget to report
+ * every xmit-interrupt until we restart the CU.
+ * Another MAJOR bug is, that the RU sometimes seems to ignore the EL-Bit
+ * in the RBD-Struct which indicates an end of the RBD queue.
+ * Instead, the RU fetches another (randomly selected and
+ * usually used) RBD and begins to fill it. (Maybe, this happens only if
+ * the last buffer from the previous RFD fits exact into the queue and
+ * the next RFD can't fetch an initial RBD. Anyone knows more? )
+ *
+ * results from ftp performance tests with Linux 1.2.5
+ * send and receive about 350-400 KByte/s (peak up to 460 kbytes/s)
+ * sending in NOP-mode: peak performance up to 530K/s (but better don't
+ * run this mode)
+ */
+
+/*
+ * 29.Sept.96: virt_to_bus changes for new memory scheme
+ * 19.Feb.96: more Mcast changes, module support (MH)
+ *
+ * 18.Nov.95: Mcast changes (AC).
+ *
+ * 23.April.95: fixed(?) receiving problems by configuring a RFD more
+ * than the number of RBD's. Can maybe cause other problems.
+ * 18.April.95: Added MODULE support (MH)
+ * 17.April.95: MC related changes in init586() and set_multicast_list().
+ * removed use of 'jiffies' in init586() (MH)
+ *
+ * 19.Sep.94: Added Multicast support (not tested yet) (MH)
+ *
+ * 18.Sep.94: Workaround for 'EL-Bug'. Removed flexible RBD-handling.
+ * Now, every RFD has exact one RBD. (MH)
+ *
+ * 14.Sep.94: added promiscuous mode, a few cleanups (MH)
+ *
+ * 19.Aug.94: changed request_irq() parameter (MH)
+ *
+ * 20.July.94: removed cleanup bugs, removed a 16K-mem-probe-bug (MH)
+ *
+ * 19.July.94: lotsa cleanups .. (MH)
+ *
+ * 17.July.94: some patches ... verified to run with 1.1.29 (MH)
+ *
+ * 4.July.94: patches for Linux 1.1.24 (MH)
+ *
+ * 26.March.94: patches for Linux 1.0 and iomem-auto-probe (MH)
+ *
+ * 30.Sep.93: Added nop-chain .. driver now runs with only one Xmit-Buff,
+ * too (MH)
+ *
+ * < 30.Sep.93: first versions
+ */
+
+static int debuglevel; /* debug-printk 0: off 1: a few 2: more */
+static int automatic_resume; /* experimental .. better should be zero */
+static int rfdadd; /* rfdadd=1 may be better for 8K MEM cards */
+static int fifo = 0x8; /* don't change */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <asm/io.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include "ni52.h"
+
+#define DRV_NAME "ni52"
+
+#define DEBUG /* debug on */
+#define SYSBUSVAL 1 /* 8 Bit */
+
+#define ni_attn586() { outb(0, dev->base_addr + NI52_ATTENTION); }
+#define ni_reset586() { outb(0, dev->base_addr + NI52_RESET); }
+#define ni_disint() { outb(0, dev->base_addr + NI52_INTDIS); }
+#define ni_enaint() { outb(0, dev->base_addr + NI52_INTENA); }
+
+#define make32(ptr16) ((void __iomem *)(p->memtop + (short) (ptr16)))
+#define make24(ptr32) ((char __iomem *)(ptr32)) - p->base
+#define make16(ptr32) ((unsigned short) ((char __iomem *)(ptr32)\
+ - p->memtop))
+
+/******************* how to calculate the buffers *****************************
+
+ * IMPORTANT NOTE: if you configure only one NUM_XMIT_BUFFS, the driver works
+ * --------------- in a different (more stable?) mode. Only in this mode it's
+ * possible to configure the driver with 'NO_NOPCOMMANDS'
+
+sizeof(scp)=12; sizeof(scb)=16; sizeof(iscp)=8;
+sizeof(scp)+sizeof(iscp)+sizeof(scb) = 36 = INIT
+sizeof(rfd) = 24; sizeof(rbd) = 12;
+sizeof(tbd) = 8; sizeof(transmit_cmd) = 16;
+sizeof(nop_cmd) = 8;
+
+ * if you don't know the driver, better do not change these values: */
+
+#define RECV_BUFF_SIZE 1524 /* slightly oversized */
+#define XMIT_BUFF_SIZE 1524 /* slightly oversized */
+#define NUM_XMIT_BUFFS 1 /* config for both, 8K and 16K shmem */
+#define NUM_RECV_BUFFS_8 4 /* config for 8K shared mem */
+#define NUM_RECV_BUFFS_16 9 /* config for 16K shared mem */
+#define NO_NOPCOMMANDS /* only possible with NUM_XMIT_BUFFS=1 */
+
+/**************************************************************************/
+
+
+#define NI52_TOTAL_SIZE 16
+#define NI52_ADDR0 0x02
+#define NI52_ADDR1 0x07
+#define NI52_ADDR2 0x01
+
+static int ni52_probe1(struct net_device *dev, int ioaddr);
+static irqreturn_t ni52_interrupt(int irq, void *dev_id);
+static int ni52_open(struct net_device *dev);
+static int ni52_close(struct net_device *dev);
+static netdev_tx_t ni52_send_packet(struct sk_buff *, struct net_device *);
+static struct net_device_stats *ni52_get_stats(struct net_device *dev);
+static void set_multicast_list(struct net_device *dev);
+static void ni52_timeout(struct net_device *dev);
+
+/* helper-functions */
+static int init586(struct net_device *dev);
+static int check586(struct net_device *dev, unsigned size);
+static void alloc586(struct net_device *dev);
+static void startrecv586(struct net_device *dev);
+static void __iomem *alloc_rfa(struct net_device *dev, void __iomem *ptr);
+static void ni52_rcv_int(struct net_device *dev);
+static void ni52_xmt_int(struct net_device *dev);
+static void ni52_rnr_int(struct net_device *dev);
+
+struct priv {
+ char __iomem *base;
+ char __iomem *mapped;
+ char __iomem *memtop;
+ spinlock_t spinlock;
+ int reset;
+ struct rfd_struct __iomem *rfd_last, *rfd_top, *rfd_first;
+ struct scp_struct __iomem *scp;
+ struct iscp_struct __iomem *iscp;
+ struct scb_struct __iomem *scb;
+ struct tbd_struct __iomem *xmit_buffs[NUM_XMIT_BUFFS];
+#if (NUM_XMIT_BUFFS == 1)
+ struct transmit_cmd_struct __iomem *xmit_cmds[2];
+ struct nop_cmd_struct __iomem *nop_cmds[2];
+#else
+ struct transmit_cmd_struct __iomem *xmit_cmds[NUM_XMIT_BUFFS];
+ struct nop_cmd_struct __iomem *nop_cmds[NUM_XMIT_BUFFS];
+#endif
+ int nop_point, num_recv_buffs;
+ char __iomem *xmit_cbuffs[NUM_XMIT_BUFFS];
+ int xmit_count, xmit_last;
+};
+
+/* wait for command with timeout: */
+static void wait_for_scb_cmd(struct net_device *dev)
+{
+ struct priv *p = netdev_priv(dev);
+ int i;
+ for (i = 0; i < 16384; i++) {
+ if (readb(&p->scb->cmd_cuc) == 0)
+ break;
+ udelay(4);
+ if (i == 16383) {
+ printk(KERN_ERR "%s: scb_cmd timed out: %04x,%04x .. disabling i82586!!\n",
+ dev->name, readb(&p->scb->cmd_cuc), readb(&p->scb->cus));
+ if (!p->reset) {
+ p->reset = 1;
+ ni_reset586();
+ }
+ }
+ }
+}
+
+static void wait_for_scb_cmd_ruc(struct net_device *dev)
+{
+ struct priv *p = netdev_priv(dev);
+ int i;
+ for (i = 0; i < 16384; i++) {
+ if (readb(&p->scb->cmd_ruc) == 0)
+ break;
+ udelay(4);
+ if (i == 16383) {
+ printk(KERN_ERR "%s: scb_cmd (ruc) timed out: %04x,%04x .. disabling i82586!!\n",
+ dev->name, readb(&p->scb->cmd_ruc),
+ readb(&p->scb->rus));
+ if (!p->reset) {
+ p->reset = 1;
+ ni_reset586();
+ }
+ }
+ }
+}
+
+static void wait_for_stat_compl(void __iomem *p)
+{
+ struct nop_cmd_struct __iomem *addr = p;
+ int i;
+ for (i = 0; i < 32767; i++) {
+ if (readw(&((addr)->cmd_status)) & STAT_COMPL)
+ break;
+ udelay(32);
+ }
+}
+
+/**********************************************
+ * close device
+ */
+static int ni52_close(struct net_device *dev)
+{
+ free_irq(dev->irq, dev);
+ ni_reset586(); /* the hard way to stop the receiver */
+ netif_stop_queue(dev);
+ return 0;
+}
+
+/**********************************************
+ * open device
+ */
+static int ni52_open(struct net_device *dev)
+{
+ int ret;
+
+ ni_disint();
+ alloc586(dev);
+ init586(dev);
+ startrecv586(dev);
+ ni_enaint();
+
+ ret = request_irq(dev->irq, ni52_interrupt, 0, dev->name, dev);
+ if (ret) {
+ ni_reset586();
+ return ret;
+ }
+ netif_start_queue(dev);
+ return 0; /* most done by init */
+}
+
+static int check_iscp(struct net_device *dev, void __iomem *addr)
+{
+ struct iscp_struct __iomem *iscp = addr;
+ struct priv *p = netdev_priv(dev);
+ memset_io(iscp, 0, sizeof(struct iscp_struct));
+
+ writel(make24(iscp), &p->scp->iscp);
+ writeb(1, &iscp->busy);
+
+ ni_reset586();
+ ni_attn586();
+ mdelay(32); /* wait a while... */
+ /* i82586 clears 'busy' after successful init */
+ if (readb(&iscp->busy))
+ return 0;
+ return 1;
+}
+
+/**********************************************
+ * Check to see if there's an 82586 out there.
+ */
+static int check586(struct net_device *dev, unsigned size)
+{
+ struct priv *p = netdev_priv(dev);
+ int i;
+
+ p->mapped = ioremap(dev->mem_start, size);
+ if (!p->mapped)
+ return 0;
+
+ p->base = p->mapped + size - 0x01000000;
+ p->memtop = p->mapped + size;
+ p->scp = (struct scp_struct __iomem *)(p->base + SCP_DEFAULT_ADDRESS);
+ p->scb = (struct scb_struct __iomem *) p->mapped;
+ p->iscp = (struct iscp_struct __iomem *)p->scp - 1;
+ memset_io(p->scp, 0, sizeof(struct scp_struct));
+ for (i = 0; i < sizeof(struct scp_struct); i++)
+ /* memory was writeable? */
+ if (readb((char __iomem *)p->scp + i))
+ goto Enodev;
+ writeb(SYSBUSVAL, &p->scp->sysbus); /* 1 = 8Bit-Bus, 0 = 16 Bit */
+ if (readb(&p->scp->sysbus) != SYSBUSVAL)
+ goto Enodev;
+
+ if (!check_iscp(dev, p->mapped))
+ goto Enodev;
+ if (!check_iscp(dev, p->iscp))
+ goto Enodev;
+ return 1;
+Enodev:
+ iounmap(p->mapped);
+ return 0;
+}
+
+/******************************************************************
+ * set iscp at the right place, called by ni52_probe1 and open586.
+ */
+static void alloc586(struct net_device *dev)
+{
+ struct priv *p = netdev_priv(dev);
+
+ ni_reset586();
+ mdelay(32);
+
+ memset_io(p->iscp, 0, sizeof(struct iscp_struct));
+ memset_io(p->scp , 0, sizeof(struct scp_struct));
+
+ writel(make24(p->iscp), &p->scp->iscp);
+ writeb(SYSBUSVAL, &p->scp->sysbus);
+ writew(make16(p->scb), &p->iscp->scb_offset);
+
+ writeb(1, &p->iscp->busy);
+ ni_reset586();
+ ni_attn586();
+
+ mdelay(32);
+
+ if (readb(&p->iscp->busy))
+ printk(KERN_ERR "%s: Init-Problems (alloc).\n", dev->name);
+
+ p->reset = 0;
+
+ memset_io(p->scb, 0, sizeof(struct scb_struct));
+}
+
+/* set: io,irq,memstart,memend or set it when calling insmod */
+static int irq = 9;
+static int io = 0x300;
+static long memstart; /* e.g 0xd0000 */
+static long memend; /* e.g 0xd4000 */
+
+/**********************************************
+ * probe the ni5210-card
+ */
+struct net_device * __init ni52_probe(int unit)
+{
+ struct net_device *dev = alloc_etherdev(sizeof(struct priv));
+ static const int ports[] = {0x300, 0x280, 0x360, 0x320, 0x340, 0};
+ const int *port;
+ struct priv *p;
+ int err = 0;
+
+ if (!dev)
+ return ERR_PTR(-ENOMEM);
+
+ p = netdev_priv(dev);
+
+ if (unit >= 0) {
+ sprintf(dev->name, "eth%d", unit);
+ netdev_boot_setup_check(dev);
+ io = dev->base_addr;
+ irq = dev->irq;
+ memstart = dev->mem_start;
+ memend = dev->mem_end;
+ }
+
+ if (io > 0x1ff) { /* Check a single specified location. */
+ err = ni52_probe1(dev, io);
+ } else if (io > 0) { /* Don't probe at all. */
+ err = -ENXIO;
+ } else {
+ for (port = ports; *port && ni52_probe1(dev, *port) ; port++)
+ ;
+ if (*port)
+ goto got_it;
+#ifdef FULL_IO_PROBE
+ for (io = 0x200; io < 0x400 && ni52_probe1(dev, io); io += 8)
+ ;
+ if (io < 0x400)
+ goto got_it;
+#endif
+ err = -ENODEV;
+ }
+ if (err)
+ goto out;
+got_it:
+ err = register_netdev(dev);
+ if (err)
+ goto out1;
+ return dev;
+out1:
+ iounmap(p->mapped);
+ release_region(dev->base_addr, NI52_TOTAL_SIZE);
+out:
+ free_netdev(dev);
+ return ERR_PTR(err);
+}
+
+static const struct net_device_ops ni52_netdev_ops = {
+ .ndo_open = ni52_open,
+ .ndo_stop = ni52_close,
+ .ndo_get_stats = ni52_get_stats,
+ .ndo_tx_timeout = ni52_timeout,
+ .ndo_start_xmit = ni52_send_packet,
+ .ndo_set_multicast_list = set_multicast_list,
+ .ndo_change_mtu = eth_change_mtu,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+};
+
+static int __init ni52_probe1(struct net_device *dev, int ioaddr)
+{
+ int i, size, retval;
+ struct priv *priv = netdev_priv(dev);
+
+ dev->base_addr = ioaddr;
+ dev->irq = irq;
+ dev->mem_start = memstart;
+ dev->mem_end = memend;
+
+ spin_lock_init(&priv->spinlock);
+
+ if (!request_region(ioaddr, NI52_TOTAL_SIZE, DRV_NAME))
+ return -EBUSY;
+
+ if (!(inb(ioaddr+NI52_MAGIC1) == NI52_MAGICVAL1) ||
+ !(inb(ioaddr+NI52_MAGIC2) == NI52_MAGICVAL2)) {
+ retval = -ENODEV;
+ goto out;
+ }
+
+ for (i = 0; i < ETH_ALEN; i++)
+ dev->dev_addr[i] = inb(dev->base_addr+i);
+
+ if (dev->dev_addr[0] != NI52_ADDR0 || dev->dev_addr[1] != NI52_ADDR1 ||
+ dev->dev_addr[2] != NI52_ADDR2) {
+ retval = -ENODEV;
+ goto out;
+ }
+
+ printk(KERN_INFO "%s: NI5210 found at %#3lx, ",
+ dev->name, dev->base_addr);
+
+ /*
+ * check (or search) IO-Memory, 8K and 16K
+ */
+#ifdef MODULE
+ size = dev->mem_end - dev->mem_start;
+ if (size != 0x2000 && size != 0x4000) {
+ printk("\n");
+ printk(KERN_ERR "%s: Invalid memory size %d. Allowed is 0x2000 or 0x4000 bytes.\n", dev->name, size);
+ retval = -ENODEV;
+ goto out;
+ }
+ if (!check586(dev, size)) {
+ printk(KERN_ERR "?memcheck, Can't find memory at 0x%lx with size %d!\n", dev->mem_start, size);
+ retval = -ENODEV;
+ goto out;
+ }
+#else
+ if (dev->mem_start != 0) {
+ /* no auto-mem-probe */
+ size = 0x4000; /* check for 16K mem */
+ if (!check586(dev, size)) {
+ size = 0x2000; /* check for 8K mem */
+ if (!check586(dev, size)) {
+ printk(KERN_ERR "?memprobe, Can't find memory at 0x%lx!\n", dev->mem_start);
+ retval = -ENODEV;
+ goto out;
+ }
+ }
+ } else {
+ static const unsigned long memaddrs[] = {
+ 0xc8000, 0xca000, 0xcc000, 0xce000, 0xd0000, 0xd2000,
+ 0xd4000, 0xd6000, 0xd8000, 0xda000, 0xdc000, 0
+ };
+ for (i = 0;; i++) {
+ if (!memaddrs[i]) {
+ printk(KERN_ERR "?memprobe, Can't find io-memory!\n");
+ retval = -ENODEV;
+ goto out;
+ }
+ dev->mem_start = memaddrs[i];
+ size = 0x2000; /* check for 8K mem */
+ if (check586(dev, size))
+ /* 8K-check */
+ break;
+ size = 0x4000; /* check for 16K mem */
+ if (check586(dev, size))
+ /* 16K-check */
+ break;
+ }
+ }
+ /* set mem_end showed by 'ifconfig' */
+ dev->mem_end = dev->mem_start + size;
+#endif
+
+ alloc586(dev);
+
+ /* set number of receive-buffs according to memsize */
+ if (size == 0x2000)
+ priv->num_recv_buffs = NUM_RECV_BUFFS_8;
+ else
+ priv->num_recv_buffs = NUM_RECV_BUFFS_16;
+
+ printk(KERN_DEBUG "Memaddr: 0x%lx, Memsize: %d, ",
+ dev->mem_start, size);
+
+ if (dev->irq < 2) {
+ unsigned long irq_mask;
+
+ irq_mask = probe_irq_on();
+ ni_reset586();
+ ni_attn586();
+
+ mdelay(20);
+ dev->irq = probe_irq_off(irq_mask);
+ if (!dev->irq) {
+ printk("?autoirq, Failed to detect IRQ line!\n");
+ retval = -EAGAIN;
+ iounmap(priv->mapped);
+ goto out;
+ }
+ printk("IRQ %d (autodetected).\n", dev->irq);
+ } else {
+ if (dev->irq == 2)
+ dev->irq = 9;
+ printk("IRQ %d (assigned and not checked!).\n", dev->irq);
+ }
+
+ dev->netdev_ops = &ni52_netdev_ops;
+ dev->watchdog_timeo = HZ/20;
+
+ return 0;
+out:
+ release_region(ioaddr, NI52_TOTAL_SIZE);
+ return retval;
+}
+
+/**********************************************
+ * init the chip (ni52-interrupt should be disabled?!)
+ * needs a correct 'allocated' memory
+ */
+
+static int init586(struct net_device *dev)
+{
+ void __iomem *ptr;
+ int i, result = 0;
+ struct priv *p = netdev_priv(dev);
+ struct configure_cmd_struct __iomem *cfg_cmd;
+ struct iasetup_cmd_struct __iomem *ias_cmd;
+ struct tdr_cmd_struct __iomem *tdr_cmd;
+ struct mcsetup_cmd_struct __iomem *mc_cmd;
+ struct netdev_hw_addr *ha;
+ int num_addrs = netdev_mc_count(dev);
+
+ ptr = p->scb + 1;
+
+ cfg_cmd = ptr; /* configure-command */
+ writew(0, &cfg_cmd->cmd_status);
+ writew(CMD_CONFIGURE | CMD_LAST, &cfg_cmd->cmd_cmd);
+ writew(0xFFFF, &cfg_cmd->cmd_link);
+
+ /* number of cfg bytes */
+ writeb(0x0a, &cfg_cmd->byte_cnt);
+ /* fifo-limit (8=tx:32/rx:64) */
+ writeb(fifo, &cfg_cmd->fifo);
+ /* hold or discard bad recv frames (bit 7) */
+ writeb(0x40, &cfg_cmd->sav_bf);
+ /* addr_len |!src_insert |pre-len |loopback */
+ writeb(0x2e, &cfg_cmd->adr_len);
+ writeb(0x00, &cfg_cmd->priority);
+ writeb(0x60, &cfg_cmd->ifs);
+ writeb(0x00, &cfg_cmd->time_low);
+ writeb(0xf2, &cfg_cmd->time_high);
+ writeb(0x00, &cfg_cmd->promisc);
+ if (dev->flags & IFF_ALLMULTI) {
+ int len = ((char __iomem *)p->iscp - (char __iomem *)ptr - 8) / 6;
+ if (num_addrs > len) {
+ printk(KERN_ERR "%s: switching to promisc. mode\n",
+ dev->name);
+ writeb(0x01, &cfg_cmd->promisc);
+ }
+ }
+ if (dev->flags & IFF_PROMISC)
+ writeb(0x01, &cfg_cmd->promisc);
+ writeb(0x00, &cfg_cmd->carr_coll);
+ writew(make16(cfg_cmd), &p->scb->cbl_offset);
+ writeb(0, &p->scb->cmd_ruc);
+
+ writeb(CUC_START, &p->scb->cmd_cuc); /* cmd.-unit start */
+ ni_attn586();
+
+ wait_for_stat_compl(cfg_cmd);
+
+ if ((readw(&cfg_cmd->cmd_status) & (STAT_OK|STAT_COMPL)) !=
+ (STAT_COMPL|STAT_OK)) {
+ printk(KERN_ERR "%s: configure command failed: %x\n",
+ dev->name, readw(&cfg_cmd->cmd_status));
+ return 1;
+ }
+
+ /*
+ * individual address setup
+ */
+
+ ias_cmd = ptr;
+
+ writew(0, &ias_cmd->cmd_status);
+ writew(CMD_IASETUP | CMD_LAST, &ias_cmd->cmd_cmd);
+ writew(0xffff, &ias_cmd->cmd_link);
+
+ memcpy_toio(&ias_cmd->iaddr, (char *)dev->dev_addr, ETH_ALEN);
+
+ writew(make16(ias_cmd), &p->scb->cbl_offset);
+
+ writeb(CUC_START, &p->scb->cmd_cuc); /* cmd.-unit start */
+ ni_attn586();
+
+ wait_for_stat_compl(ias_cmd);
+
+ if ((readw(&ias_cmd->cmd_status) & (STAT_OK|STAT_COMPL)) !=
+ (STAT_OK|STAT_COMPL)) {
+ printk(KERN_ERR "%s (ni52): individual address setup command failed: %04x\n", dev->name, readw(&ias_cmd->cmd_status));
+ return 1;
+ }
+
+ /*
+ * TDR, wire check .. e.g. no resistor e.t.c
+ */
+
+ tdr_cmd = ptr;
+
+ writew(0, &tdr_cmd->cmd_status);
+ writew(CMD_TDR | CMD_LAST, &tdr_cmd->cmd_cmd);
+ writew(0xffff, &tdr_cmd->cmd_link);
+ writew(0, &tdr_cmd->status);
+
+ writew(make16(tdr_cmd), &p->scb->cbl_offset);
+ writeb(CUC_START, &p->scb->cmd_cuc); /* cmd.-unit start */
+ ni_attn586();
+
+ wait_for_stat_compl(tdr_cmd);
+
+ if (!(readw(&tdr_cmd->cmd_status) & STAT_COMPL))
+ printk(KERN_ERR "%s: Problems while running the TDR.\n",
+ dev->name);
+ else {
+ udelay(16);
+ result = readw(&tdr_cmd->status);
+ writeb(readb(&p->scb->cus) & STAT_MASK, &p->scb->cmd_cuc);
+ ni_attn586(); /* ack the interrupts */
+
+ if (result & TDR_LNK_OK)
+ ;
+ else if (result & TDR_XCVR_PRB)
+ printk(KERN_ERR "%s: TDR: Transceiver problem. Check the cable(s)!\n",
+ dev->name);
+ else if (result & TDR_ET_OPN)
+ printk(KERN_ERR "%s: TDR: No correct termination %d clocks away.\n",
+ dev->name, result & TDR_TIMEMASK);
+ else if (result & TDR_ET_SRT) {
+ /* time == 0 -> strange :-) */
+ if (result & TDR_TIMEMASK)
+ printk(KERN_ERR "%s: TDR: Detected a short circuit %d clocks away.\n",
+ dev->name, result & TDR_TIMEMASK);
+ } else
+ printk(KERN_ERR "%s: TDR: Unknown status %04x\n",
+ dev->name, result);
+ }
+
+ /*
+ * Multicast setup
+ */
+ if (num_addrs && !(dev->flags & IFF_PROMISC)) {
+ mc_cmd = ptr;
+ writew(0, &mc_cmd->cmd_status);
+ writew(CMD_MCSETUP | CMD_LAST, &mc_cmd->cmd_cmd);
+ writew(0xffff, &mc_cmd->cmd_link);
+ writew(num_addrs * 6, &mc_cmd->mc_cnt);
+
+ i = 0;
+ netdev_for_each_mc_addr(ha, dev)
+ memcpy_toio(mc_cmd->mc_list[i++], ha->addr, 6);
+
+ writew(make16(mc_cmd), &p->scb->cbl_offset);
+ writeb(CUC_START, &p->scb->cmd_cuc);
+ ni_attn586();
+
+ wait_for_stat_compl(mc_cmd);
+
+ if ((readw(&mc_cmd->cmd_status) & (STAT_COMPL|STAT_OK))
+ != (STAT_COMPL|STAT_OK))
+ printk(KERN_ERR "%s: Can't apply multicast-address-list.\n", dev->name);
+ }
+
+ /*
+ * alloc nop/xmit-cmds
+ */
+#if (NUM_XMIT_BUFFS == 1)
+ for (i = 0; i < 2; i++) {
+ p->nop_cmds[i] = ptr;
+ writew(CMD_NOP, &p->nop_cmds[i]->cmd_cmd);
+ writew(0, &p->nop_cmds[i]->cmd_status);
+ writew(make16(p->nop_cmds[i]), &p->nop_cmds[i]->cmd_link);
+ ptr = ptr + sizeof(struct nop_cmd_struct);
+ }
+#else
+ for (i = 0; i < NUM_XMIT_BUFFS; i++) {
+ p->nop_cmds[i] = ptr;
+ writew(CMD_NOP, &p->nop_cmds[i]->cmd_cmd);
+ writew(0, &p->nop_cmds[i]->cmd_status);
+ writew(make16(p->nop_cmds[i]), &p->nop_cmds[i]->cmd_link);
+ ptr = ptr + sizeof(struct nop_cmd_struct);
+ }
+#endif
+
+ ptr = alloc_rfa(dev, ptr); /* init receive-frame-area */
+
+ /*
+ * alloc xmit-buffs / init xmit_cmds
+ */
+ for (i = 0; i < NUM_XMIT_BUFFS; i++) {
+ /* Transmit cmd/buff 0 */
+ p->xmit_cmds[i] = ptr;
+ ptr = ptr + sizeof(struct transmit_cmd_struct);
+ p->xmit_cbuffs[i] = ptr; /* char-buffs */
+ ptr = ptr + XMIT_BUFF_SIZE;
+ p->xmit_buffs[i] = ptr; /* TBD */
+ ptr = ptr + sizeof(struct tbd_struct);
+ if ((void __iomem *)ptr > (void __iomem *)p->iscp) {
+ printk(KERN_ERR "%s: not enough shared-mem for your configuration!\n",
+ dev->name);
+ return 1;
+ }
+ memset_io(p->xmit_cmds[i], 0,
+ sizeof(struct transmit_cmd_struct));
+ memset_io(p->xmit_buffs[i], 0,
+ sizeof(struct tbd_struct));
+ writew(make16(p->nop_cmds[(i+1)%NUM_XMIT_BUFFS]),
+ &p->xmit_cmds[i]->cmd_link);
+ writew(STAT_COMPL, &p->xmit_cmds[i]->cmd_status);
+ writew(CMD_XMIT|CMD_INT, &p->xmit_cmds[i]->cmd_cmd);
+ writew(make16(p->xmit_buffs[i]), &p->xmit_cmds[i]->tbd_offset);
+ writew(0xffff, &p->xmit_buffs[i]->next);
+ writel(make24(p->xmit_cbuffs[i]), &p->xmit_buffs[i]->buffer);
+ }
+
+ p->xmit_count = 0;
+ p->xmit_last = 0;
+#ifndef NO_NOPCOMMANDS
+ p->nop_point = 0;
+#endif
+
+ /*
+ * 'start transmitter'
+ */
+#ifndef NO_NOPCOMMANDS
+ writew(make16(p->nop_cmds[0]), &p->scb->cbl_offset);
+ writeb(CUC_START, &p->scb->cmd_cuc);
+ ni_attn586();
+ wait_for_scb_cmd(dev);
+#else
+ writew(make16(p->xmit_cmds[0]), &p->xmit_cmds[0]->cmd_link);
+ writew(CMD_XMIT | CMD_SUSPEND | CMD_INT, &p->xmit_cmds[0]->cmd_cmd);
+#endif
+
+ /*
+ * ack. interrupts
+ */
+ writeb(readb(&p->scb->cus) & STAT_MASK, &p->scb->cmd_cuc);
+ ni_attn586();
+ udelay(16);
+
+ ni_enaint();
+
+ return 0;
+}
+
+/******************************************************
+ * This is a helper routine for ni52_rnr_int() and init586().
+ * It sets up the Receive Frame Area (RFA).
+ */
+
+static void __iomem *alloc_rfa(struct net_device *dev, void __iomem *ptr)
+{
+ struct rfd_struct __iomem *rfd = ptr;
+ struct rbd_struct __iomem *rbd;
+ int i;
+ struct priv *p = netdev_priv(dev);
+
+ memset_io(rfd, 0,
+ sizeof(struct rfd_struct) * (p->num_recv_buffs + rfdadd));
+ p->rfd_first = rfd;
+
+ for (i = 0; i < (p->num_recv_buffs + rfdadd); i++) {
+ writew(make16(rfd + (i+1) % (p->num_recv_buffs+rfdadd)),
+ &rfd[i].next);
+ writew(0xffff, &rfd[i].rbd_offset);
+ }
+ /* RU suspend */
+ writeb(RFD_SUSP, &rfd[p->num_recv_buffs-1+rfdadd].last);
+
+ ptr = rfd + (p->num_recv_buffs + rfdadd);
+
+ rbd = ptr;
+ ptr = rbd + p->num_recv_buffs;
+
+ /* clr descriptors */
+ memset_io(rbd, 0, sizeof(struct rbd_struct) * (p->num_recv_buffs));
+
+ for (i = 0; i < p->num_recv_buffs; i++) {
+ writew(make16(rbd + (i+1) % p->num_recv_buffs), &rbd[i].next);
+ writew(RECV_BUFF_SIZE, &rbd[i].size);
+ writel(make24(ptr), &rbd[i].buffer);
+ ptr = ptr + RECV_BUFF_SIZE;
+ }
+ p->rfd_top = p->rfd_first;
+ p->rfd_last = p->rfd_first + (p->num_recv_buffs - 1 + rfdadd);
+
+ writew(make16(p->rfd_first), &p->scb->rfa_offset);
+ writew(make16(rbd), &p->rfd_first->rbd_offset);
+
+ return ptr;
+}
+
+
+/**************************************************
+ * Interrupt Handler ...
+ */
+
+static irqreturn_t ni52_interrupt(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ unsigned int stat;
+ int cnt = 0;
+ struct priv *p;
+
+ p = netdev_priv(dev);
+
+ if (debuglevel > 1)
+ printk("I");
+
+ spin_lock(&p->spinlock);
+
+ wait_for_scb_cmd(dev); /* wait for last command */
+
+ while ((stat = readb(&p->scb->cus) & STAT_MASK)) {
+ writeb(stat, &p->scb->cmd_cuc);
+ ni_attn586();
+
+ if (stat & STAT_FR) /* received a frame */
+ ni52_rcv_int(dev);
+
+ if (stat & STAT_RNR) { /* RU went 'not ready' */
+ printk("(R)");
+ if (readb(&p->scb->rus) & RU_SUSPEND) {
+ /* special case: RU_SUSPEND */
+ wait_for_scb_cmd(dev);
+ writeb(RUC_RESUME, &p->scb->cmd_ruc);
+ ni_attn586();
+ wait_for_scb_cmd_ruc(dev);
+ } else {
+ printk(KERN_ERR "%s: Receiver-Unit went 'NOT READY': %04x/%02x.\n",
+ dev->name, stat, readb(&p->scb->rus));
+ ni52_rnr_int(dev);
+ }
+ }
+
+ /* Command with I-bit set complete */
+ if (stat & STAT_CX)
+ ni52_xmt_int(dev);
+
+#ifndef NO_NOPCOMMANDS
+ if (stat & STAT_CNA) { /* CU went 'not ready' */
+ if (netif_running(dev))
+ printk(KERN_ERR "%s: oops! CU has left active state. stat: %04x/%02x.\n",
+ dev->name, stat, readb(&p->scb->cus));
+ }
+#endif
+
+ if (debuglevel > 1)
+ printk("%d", cnt++);
+
+ /* Wait for ack. (ni52_xmt_int can be faster than ack!!) */
+ wait_for_scb_cmd(dev);
+ if (readb(&p->scb->cmd_cuc)) { /* timed out? */
+ printk(KERN_ERR "%s: Acknowledge timed out.\n",
+ dev->name);
+ ni_disint();
+ break;
+ }
+ }
+ spin_unlock(&p->spinlock);
+
+ if (debuglevel > 1)
+ printk("i");
+ return IRQ_HANDLED;
+}
+
+/*******************************************************
+ * receive-interrupt
+ */
+
+static void ni52_rcv_int(struct net_device *dev)
+{
+ int status, cnt = 0;
+ unsigned short totlen;
+ struct sk_buff *skb;
+ struct rbd_struct __iomem *rbd;
+ struct priv *p = netdev_priv(dev);
+
+ if (debuglevel > 0)
+ printk("R");
+
+ for (; (status = readb(&p->rfd_top->stat_high)) & RFD_COMPL;) {
+ rbd = make32(readw(&p->rfd_top->rbd_offset));
+ if (status & RFD_OK) { /* frame received without error? */
+ totlen = readw(&rbd->status);
+ if (totlen & RBD_LAST) {
+ /* the first and the last buffer? */
+ totlen &= RBD_MASK; /* length of this frame */
+ writew(0x00, &rbd->status);
+ skb = (struct sk_buff *)dev_alloc_skb(totlen+2);
+ if (skb != NULL) {
+ skb_reserve(skb, 2);
+ skb_put(skb, totlen);
+ memcpy_fromio(skb->data, p->base + readl(&rbd->buffer), totlen);
+ skb->protocol = eth_type_trans(skb, dev);
+ netif_rx(skb);
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += totlen;
+ } else
+ dev->stats.rx_dropped++;
+ } else {
+ int rstat;
+ /* free all RBD's until RBD_LAST is set */
+ totlen = 0;
+ while (!((rstat = readw(&rbd->status)) & RBD_LAST)) {
+ totlen += rstat & RBD_MASK;
+ if (!rstat) {
+ printk(KERN_ERR "%s: Whoops .. no end mark in RBD list\n", dev->name);
+ break;
+ }
+ writew(0, &rbd->status);
+ rbd = make32(readw(&rbd->next));
+ }
+ totlen += rstat & RBD_MASK;
+ writew(0, &rbd->status);
+ printk(KERN_ERR "%s: received oversized frame! length: %d\n",
+ dev->name, totlen);
+ dev->stats.rx_dropped++;
+ }
+ } else {/* frame !(ok), only with 'save-bad-frames' */
+ printk(KERN_ERR "%s: oops! rfd-error-status: %04x\n",
+ dev->name, status);
+ dev->stats.rx_errors++;
+ }
+ writeb(0, &p->rfd_top->stat_high);
+ writeb(RFD_SUSP, &p->rfd_top->last); /* maybe exchange by RFD_LAST */
+ writew(0xffff, &p->rfd_top->rbd_offset);
+ writeb(0, &p->rfd_last->last); /* delete RFD_SUSP */
+ p->rfd_last = p->rfd_top;
+ p->rfd_top = make32(readw(&p->rfd_top->next)); /* step to next RFD */
+ writew(make16(p->rfd_top), &p->scb->rfa_offset);
+
+ if (debuglevel > 0)
+ printk("%d", cnt++);
+ }
+
+ if (automatic_resume) {
+ wait_for_scb_cmd(dev);
+ writeb(RUC_RESUME, &p->scb->cmd_ruc);
+ ni_attn586();
+ wait_for_scb_cmd_ruc(dev);
+ }
+
+#ifdef WAIT_4_BUSY
+ {
+ int i;
+ for (i = 0; i < 1024; i++) {
+ if (p->rfd_top->status)
+ break;
+ udelay(16);
+ if (i == 1023)
+ printk(KERN_ERR "%s: RU hasn't fetched next RFD (not busy/complete)\n", dev->name);
+ }
+ }
+#endif
+ if (debuglevel > 0)
+ printk("r");
+}
+
+/**********************************************************
+ * handle 'Receiver went not ready'.
+ */
+
+static void ni52_rnr_int(struct net_device *dev)
+{
+ struct priv *p = netdev_priv(dev);
+
+ dev->stats.rx_errors++;
+
+ wait_for_scb_cmd(dev); /* wait for the last cmd, WAIT_4_FULLSTAT?? */
+ writeb(RUC_ABORT, &p->scb->cmd_ruc); /* usually the RU is in the 'no resource'-state .. abort it now. */
+ ni_attn586();
+ wait_for_scb_cmd_ruc(dev); /* wait for accept cmd. */
+
+ alloc_rfa(dev, p->rfd_first);
+ /* maybe add a check here, before restarting the RU */
+ startrecv586(dev); /* restart RU */
+
+ printk(KERN_ERR "%s: Receive-Unit restarted. Status: %04x\n",
+ dev->name, readb(&p->scb->rus));
+
+}
+
+/**********************************************************
+ * handle xmit - interrupt
+ */
+
+static void ni52_xmt_int(struct net_device *dev)
+{
+ int status;
+ struct priv *p = netdev_priv(dev);
+
+ if (debuglevel > 0)
+ printk("X");
+
+ status = readw(&p->xmit_cmds[p->xmit_last]->cmd_status);
+ if (!(status & STAT_COMPL))
+ printk(KERN_ERR "%s: strange .. xmit-int without a 'COMPLETE'\n", dev->name);
+
+ if (status & STAT_OK) {
+ dev->stats.tx_packets++;
+ dev->stats.collisions += (status & TCMD_MAXCOLLMASK);
+ } else {
+ dev->stats.tx_errors++;
+ if (status & TCMD_LATECOLL) {
+ printk(KERN_ERR "%s: late collision detected.\n",
+ dev->name);
+ dev->stats.collisions++;
+ } else if (status & TCMD_NOCARRIER) {
+ dev->stats.tx_carrier_errors++;
+ printk(KERN_ERR "%s: no carrier detected.\n",
+ dev->name);
+ } else if (status & TCMD_LOSTCTS)
+ printk(KERN_ERR "%s: loss of CTS detected.\n",
+ dev->name);
+ else if (status & TCMD_UNDERRUN) {
+ dev->stats.tx_fifo_errors++;
+ printk(KERN_ERR "%s: DMA underrun detected.\n",
+ dev->name);
+ } else if (status & TCMD_MAXCOLL) {
+ printk(KERN_ERR "%s: Max. collisions exceeded.\n",
+ dev->name);
+ dev->stats.collisions += 16;
+ }
+ }
+#if (NUM_XMIT_BUFFS > 1)
+ if ((++p->xmit_last) == NUM_XMIT_BUFFS)
+ p->xmit_last = 0;
+#endif
+ netif_wake_queue(dev);
+}
+
+/***********************************************************
+ * (re)start the receiver
+ */
+
+static void startrecv586(struct net_device *dev)
+{
+ struct priv *p = netdev_priv(dev);
+
+ wait_for_scb_cmd(dev);
+ wait_for_scb_cmd_ruc(dev);
+ writew(make16(p->rfd_first), &p->scb->rfa_offset);
+ writeb(RUC_START, &p->scb->cmd_ruc);
+ ni_attn586(); /* start cmd. */
+ wait_for_scb_cmd_ruc(dev);
+ /* wait for accept cmd. (no timeout!!) */
+}
+
+static void ni52_timeout(struct net_device *dev)
+{
+ struct priv *p = netdev_priv(dev);
+#ifndef NO_NOPCOMMANDS
+ if (readb(&p->scb->cus) & CU_ACTIVE) { /* COMMAND-UNIT active? */
+ netif_wake_queue(dev);
+#ifdef DEBUG
+ printk(KERN_ERR "%s: strange ... timeout with CU active?!?\n",
+ dev->name);
+ printk(KERN_ERR "%s: X0: %04x N0: %04x N1: %04x %d\n",
+ dev->name, (int)p->xmit_cmds[0]->cmd_status,
+ readw(&p->nop_cmds[0]->cmd_status),
+ readw(&p->nop_cmds[1]->cmd_status),
+ p->nop_point);
+#endif
+ writeb(CUC_ABORT, &p->scb->cmd_cuc);
+ ni_attn586();
+ wait_for_scb_cmd(dev);
+ writew(make16(p->nop_cmds[p->nop_point]), &p->scb->cbl_offset);
+ writeb(CUC_START, &p->scb->cmd_cuc);
+ ni_attn586();
+ wait_for_scb_cmd(dev);
+ dev->trans_start = jiffies; /* prevent tx timeout */
+ return 0;
+ }
+#endif
+ {
+#ifdef DEBUG
+ printk(KERN_ERR "%s: xmitter timed out, try to restart! stat: %02x\n",
+ dev->name, readb(&p->scb->cus));
+ printk(KERN_ERR "%s: command-stats: %04x %04x\n",
+ dev->name,
+ readw(&p->xmit_cmds[0]->cmd_status),
+ readw(&p->xmit_cmds[1]->cmd_status));
+ printk(KERN_ERR "%s: check, whether you set the right interrupt number!\n",
+ dev->name);
+#endif
+ ni52_close(dev);
+ ni52_open(dev);
+ }
+ dev->trans_start = jiffies; /* prevent tx timeout */
+}
+
+/******************************************************
+ * send frame
+ */
+
+static netdev_tx_t ni52_send_packet(struct sk_buff *skb,
+ struct net_device *dev)
+{
+ int len, i;
+#ifndef NO_NOPCOMMANDS
+ int next_nop;
+#endif
+ struct priv *p = netdev_priv(dev);
+
+ if (skb->len > XMIT_BUFF_SIZE) {
+ printk(KERN_ERR "%s: Sorry, max. framelength is %d bytes. The length of your frame is %d bytes.\n", dev->name, XMIT_BUFF_SIZE, skb->len);
+ return NETDEV_TX_OK;
+ }
+
+ netif_stop_queue(dev);
+
+ memcpy_toio(p->xmit_cbuffs[p->xmit_count], skb->data, skb->len);
+ len = skb->len;
+ if (len < ETH_ZLEN) {
+ len = ETH_ZLEN;
+ memset_io(p->xmit_cbuffs[p->xmit_count]+skb->len, 0,
+ len - skb->len);
+ }
+
+#if (NUM_XMIT_BUFFS == 1)
+# ifdef NO_NOPCOMMANDS
+
+#ifdef DEBUG
+ if (readb(&p->scb->cus) & CU_ACTIVE) {
+ printk(KERN_ERR "%s: Hmmm .. CU is still running and we wanna send a new packet.\n", dev->name);
+ printk(KERN_ERR "%s: stat: %04x %04x\n",
+ dev->name, readb(&p->scb->cus),
+ readw(&p->xmit_cmds[0]->cmd_status));
+ }
+#endif
+ writew(TBD_LAST | len, &p->xmit_buffs[0]->size);
+ for (i = 0; i < 16; i++) {
+ writew(0, &p->xmit_cmds[0]->cmd_status);
+ wait_for_scb_cmd(dev);
+ if ((readb(&p->scb->cus) & CU_STATUS) == CU_SUSPEND)
+ writeb(CUC_RESUME, &p->scb->cmd_cuc);
+ else {
+ writew(make16(p->xmit_cmds[0]), &p->scb->cbl_offset);
+ writeb(CUC_START, &p->scb->cmd_cuc);
+ }
+ ni_attn586();
+ if (!i)
+ dev_kfree_skb(skb);
+ wait_for_scb_cmd(dev);
+ /* test it, because CU sometimes doesn't start immediately */
+ if (readb(&p->scb->cus) & CU_ACTIVE)
+ break;
+ if (readw(&p->xmit_cmds[0]->cmd_status))
+ break;
+ if (i == 15)
+ printk(KERN_WARNING "%s: Can't start transmit-command.\n", dev->name);
+ }
+# else
+ next_nop = (p->nop_point + 1) & 0x1;
+ writew(TBD_LAST | len, &p->xmit_buffs[0]->size);
+ writew(make16(p->nop_cmds[next_nop]), &p->xmit_cmds[0]->cmd_link);
+ writew(make16(p->nop_cmds[next_nop]),
+ &p->nop_cmds[next_nop]->cmd_link);
+ writew(0, &p->xmit_cmds[0]->cmd_status);
+ writew(0, &p->nop_cmds[next_nop]->cmd_status);
+
+ writew(make16(p->xmit_cmds[0]), &p->nop_cmds[p->nop_point]->cmd_link);
+ p->nop_point = next_nop;
+ dev_kfree_skb(skb);
+# endif
+#else
+ writew(TBD_LAST | len, &p->xmit_buffs[p->xmit_count]->size);
+ next_nop = p->xmit_count + 1
+ if (next_nop == NUM_XMIT_BUFFS)
+ next_nop = 0;
+ writew(0, &p->xmit_cmds[p->xmit_count]->cmd_status);
+ /* linkpointer of xmit-command already points to next nop cmd */
+ writew(make16(p->nop_cmds[next_nop]),
+ &p->nop_cmds[next_nop]->cmd_link);
+ writew(0, &p->nop_cmds[next_nop]->cmd_status);
+ writew(make16(p->xmit_cmds[p->xmit_count]),
+ &p->nop_cmds[p->xmit_count]->cmd_link);
+ p->xmit_count = next_nop;
+ {
+ unsigned long flags;
+ spin_lock_irqsave(&p->spinlock);
+ if (p->xmit_count != p->xmit_last)
+ netif_wake_queue(dev);
+ spin_unlock_irqrestore(&p->spinlock);
+ }
+ dev_kfree_skb(skb);
+#endif
+ return NETDEV_TX_OK;
+}
+
+/*******************************************
+ * Someone wanna have the statistics
+ */
+
+static struct net_device_stats *ni52_get_stats(struct net_device *dev)
+{
+ struct priv *p = netdev_priv(dev);
+ unsigned short crc, aln, rsc, ovrn;
+
+ /* Get error-statistics from the ni82586 */
+ crc = readw(&p->scb->crc_errs);
+ writew(0, &p->scb->crc_errs);
+ aln = readw(&p->scb->aln_errs);
+ writew(0, &p->scb->aln_errs);
+ rsc = readw(&p->scb->rsc_errs);
+ writew(0, &p->scb->rsc_errs);
+ ovrn = readw(&p->scb->ovrn_errs);
+ writew(0, &p->scb->ovrn_errs);
+
+ dev->stats.rx_crc_errors += crc;
+ dev->stats.rx_fifo_errors += ovrn;
+ dev->stats.rx_frame_errors += aln;
+ dev->stats.rx_dropped += rsc;
+
+ return &dev->stats;
+}
+
+/********************************************************
+ * Set MC list ..
+ */
+
+static void set_multicast_list(struct net_device *dev)
+{
+ netif_stop_queue(dev);
+ ni_disint();
+ alloc586(dev);
+ init586(dev);
+ startrecv586(dev);
+ ni_enaint();
+ netif_wake_queue(dev);
+}
+
+#ifdef MODULE
+static struct net_device *dev_ni52;
+
+module_param(io, int, 0);
+module_param(irq, int, 0);
+module_param(memstart, long, 0);
+module_param(memend, long, 0);
+MODULE_PARM_DESC(io, "NI5210 I/O base address,required");
+MODULE_PARM_DESC(irq, "NI5210 IRQ number,required");
+MODULE_PARM_DESC(memstart, "NI5210 memory base address,required");
+MODULE_PARM_DESC(memend, "NI5210 memory end address,required");
+
+int __init init_module(void)
+{
+ if (io <= 0x0 || !memend || !memstart || irq < 2) {
+ printk(KERN_ERR "ni52: Autoprobing not allowed for modules.\n");
+ printk(KERN_ERR "ni52: Set symbols 'io' 'irq' 'memstart' and 'memend'\n");
+ return -ENODEV;
+ }
+ dev_ni52 = ni52_probe(-1);
+ if (IS_ERR(dev_ni52))
+ return PTR_ERR(dev_ni52);
+ return 0;
+}
+
+void __exit cleanup_module(void)
+{
+ struct priv *p = netdev_priv(dev_ni52);
+ unregister_netdev(dev_ni52);
+ iounmap(p->mapped);
+ release_region(dev_ni52->base_addr, NI52_TOTAL_SIZE);
+ free_netdev(dev_ni52);
+}
+#endif /* MODULE */
+
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * Intel i82586 Ethernet definitions
+ *
+ * This is an extension to the Linux operating system, and is covered by the
+ * same GNU General Public License that covers that work.
+ *
+ * copyrights (c) 1994 by Michael Hipp (hippm@informatik.uni-tuebingen.de)
+ *
+ * I have done a look in the following sources:
+ * crynwr-packet-driver by Russ Nelson
+ * Garret A. Wollman's i82586-driver for BSD
+ */
+
+
+#define NI52_RESET 0 /* writing to this address, resets the i82586 */
+#define NI52_ATTENTION 1 /* channel attention, kick the 586 */
+#define NI52_TENA 3 /* 2-5 possibly wrong, Xmit enable */
+#define NI52_TDIS 2 /* Xmit disable */
+#define NI52_INTENA 5 /* Interrupt enable */
+#define NI52_INTDIS 4 /* Interrupt disable */
+#define NI52_MAGIC1 6 /* dunno exact function */
+#define NI52_MAGIC2 7 /* dunno exact function */
+
+#define NI52_MAGICVAL1 0x00 /* magic-values for ni5210 card */
+#define NI52_MAGICVAL2 0x55
+
+/*
+ * where to find the System Configuration Pointer (SCP)
+ */
+#define SCP_DEFAULT_ADDRESS 0xfffff4
+
+
+/*
+ * System Configuration Pointer Struct
+ */
+
+struct scp_struct
+{
+ u16 zero_dum0; /* has to be zero */
+ u8 sysbus; /* 0=16Bit,1=8Bit */
+ u8 zero_dum1; /* has to be zero for 586 */
+ u16 zero_dum2;
+ u16 zero_dum3;
+ u32 iscp; /* pointer to the iscp-block */
+};
+
+
+/*
+ * Intermediate System Configuration Pointer (ISCP)
+ */
+struct iscp_struct
+{
+ u8 busy; /* 586 clears after successful init */
+ u8 zero_dummy; /* has to be zero */
+ u16 scb_offset; /* pointeroffset to the scb_base */
+ u32 scb_base; /* base-address of all 16-bit offsets */
+};
+
+/*
+ * System Control Block (SCB)
+ */
+struct scb_struct
+{
+ u8 rus;
+ u8 cus;
+ u8 cmd_ruc; /* command word: RU part */
+ u8 cmd_cuc; /* command word: CU part & ACK */
+ u16 cbl_offset; /* pointeroffset, command block list */
+ u16 rfa_offset; /* pointeroffset, receive frame area */
+ u16 crc_errs; /* CRC-Error counter */
+ u16 aln_errs; /* alignmenterror counter */
+ u16 rsc_errs; /* Resourceerror counter */
+ u16 ovrn_errs; /* OVerrunerror counter */
+};
+
+/*
+ * possible command values for the command word
+ */
+#define RUC_MASK 0x0070 /* mask for RU commands */
+#define RUC_NOP 0x0000 /* NOP-command */
+#define RUC_START 0x0010 /* start RU */
+#define RUC_RESUME 0x0020 /* resume RU after suspend */
+#define RUC_SUSPEND 0x0030 /* suspend RU */
+#define RUC_ABORT 0x0040 /* abort receiver operation immediately */
+
+#define CUC_MASK 0x07 /* mask for CU command */
+#define CUC_NOP 0x00 /* NOP-command */
+#define CUC_START 0x01 /* start execution of 1. cmd on the CBL */
+#define CUC_RESUME 0x02 /* resume after suspend */
+#define CUC_SUSPEND 0x03 /* Suspend CU */
+#define CUC_ABORT 0x04 /* abort command operation immediately */
+
+#define ACK_MASK 0xf0 /* mask for ACK command */
+#define ACK_CX 0x80 /* acknowledges STAT_CX */
+#define ACK_FR 0x40 /* ack. STAT_FR */
+#define ACK_CNA 0x20 /* ack. STAT_CNA */
+#define ACK_RNR 0x10 /* ack. STAT_RNR */
+
+/*
+ * possible status values for the status word
+ */
+#define STAT_MASK 0xf0 /* mask for cause of interrupt */
+#define STAT_CX 0x80 /* CU finished cmd with its I bit set */
+#define STAT_FR 0x40 /* RU finished receiving a frame */
+#define STAT_CNA 0x20 /* CU left active state */
+#define STAT_RNR 0x10 /* RU left ready state */
+
+#define CU_STATUS 0x7 /* CU status, 0=idle */
+#define CU_SUSPEND 0x1 /* CU is suspended */
+#define CU_ACTIVE 0x2 /* CU is active */
+
+#define RU_STATUS 0x70 /* RU status, 0=idle */
+#define RU_SUSPEND 0x10 /* RU suspended */
+#define RU_NOSPACE 0x20 /* RU no resources */
+#define RU_READY 0x40 /* RU is ready */
+
+/*
+ * Receive Frame Descriptor (RFD)
+ */
+struct rfd_struct
+{
+ u8 stat_low; /* status word */
+ u8 stat_high; /* status word */
+ u8 rfd_sf; /* 82596 mode only */
+ u8 last; /* Bit15,Last Frame on List / Bit14,suspend */
+ u16 next; /* linkoffset to next RFD */
+ u16 rbd_offset; /* pointeroffset to RBD-buffer */
+ u8 dest[6]; /* ethernet-address, destination */
+ u8 source[6]; /* ethernet-address, source */
+ u16 length; /* 802.3 frame-length */
+ u16 zero_dummy; /* dummy */
+};
+
+#define RFD_LAST 0x80 /* last: last rfd in the list */
+#define RFD_SUSP 0x40 /* last: suspend RU after */
+#define RFD_COMPL 0x80
+#define RFD_OK 0x20
+#define RFD_BUSY 0x40
+#define RFD_ERR_LEN 0x10 /* Length error (if enabled length-checking */
+#define RFD_ERR_CRC 0x08 /* CRC error */
+#define RFD_ERR_ALGN 0x04 /* Alignment error */
+#define RFD_ERR_RNR 0x02 /* status: receiver out of resources */
+#define RFD_ERR_OVR 0x01 /* DMA Overrun! */
+
+#define RFD_ERR_FTS 0x0080 /* Frame to short */
+#define RFD_ERR_NEOP 0x0040 /* No EOP flag (for bitstuffing only) */
+#define RFD_ERR_TRUN 0x0020 /* (82596 only/SF mode) indicates truncated frame */
+#define RFD_MATCHADD 0x0002 /* status: Destinationaddress !matches IA (only 82596) */
+#define RFD_COLLDET 0x0001 /* Detected collision during reception */
+
+/*
+ * Receive Buffer Descriptor (RBD)
+ */
+struct rbd_struct
+{
+ u16 status; /* status word,number of used bytes in buff */
+ u16 next; /* pointeroffset to next RBD */
+ u32 buffer; /* receive buffer address pointer */
+ u16 size; /* size of this buffer */
+ u16 zero_dummy; /* dummy */
+};
+
+#define RBD_LAST 0x8000 /* last buffer */
+#define RBD_USED 0x4000 /* this buffer has data */
+#define RBD_MASK 0x3fff /* size-mask for length */
+
+/*
+ * Statusvalues for Commands/RFD
+ */
+#define STAT_COMPL 0x8000 /* status: frame/command is complete */
+#define STAT_BUSY 0x4000 /* status: frame/command is busy */
+#define STAT_OK 0x2000 /* status: frame/command is ok */
+
+/*
+ * Action-Commands
+ */
+#define CMD_NOP 0x0000 /* NOP */
+#define CMD_IASETUP 0x0001 /* initial address setup command */
+#define CMD_CONFIGURE 0x0002 /* configure command */
+#define CMD_MCSETUP 0x0003 /* MC setup command */
+#define CMD_XMIT 0x0004 /* transmit command */
+#define CMD_TDR 0x0005 /* time domain reflectometer (TDR) command */
+#define CMD_DUMP 0x0006 /* dump command */
+#define CMD_DIAGNOSE 0x0007 /* diagnose command */
+
+/*
+ * Action command bits
+ */
+#define CMD_LAST 0x8000 /* indicates last command in the CBL */
+#define CMD_SUSPEND 0x4000 /* suspend CU after this CB */
+#define CMD_INT 0x2000 /* generate interrupt after execution */
+
+/*
+ * NOP - command
+ */
+struct nop_cmd_struct
+{
+ u16 cmd_status; /* status of this command */
+ u16 cmd_cmd; /* the command itself (+bits) */
+ u16 cmd_link; /* offsetpointer to next command */
+};
+
+/*
+ * IA Setup command
+ */
+struct iasetup_cmd_struct
+{
+ u16 cmd_status;
+ u16 cmd_cmd;
+ u16 cmd_link;
+ u8 iaddr[6];
+};
+
+/*
+ * Configure command
+ */
+struct configure_cmd_struct
+{
+ u16 cmd_status;
+ u16 cmd_cmd;
+ u16 cmd_link;
+ u8 byte_cnt; /* size of the config-cmd */
+ u8 fifo; /* fifo/recv monitor */
+ u8 sav_bf; /* save bad frames (bit7=1)*/
+ u8 adr_len; /* adr_len(0-2),al_loc(3),pream(4-5),loopbak(6-7)*/
+ u8 priority; /* lin_prio(0-2),exp_prio(4-6),bof_metd(7) */
+ u8 ifs; /* inter frame spacing */
+ u8 time_low; /* slot time low */
+ u8 time_high; /* slot time high(0-2) and max. retries(4-7) */
+ u8 promisc; /* promisc-mode(0) , et al (1-7) */
+ u8 carr_coll; /* carrier(0-3)/collision(4-7) stuff */
+ u8 fram_len; /* minimal frame len */
+ u8 dummy; /* dummy */
+};
+
+/*
+ * Multicast Setup command
+ */
+struct mcsetup_cmd_struct
+{
+ u16 cmd_status;
+ u16 cmd_cmd;
+ u16 cmd_link;
+ u16 mc_cnt; /* number of bytes in the MC-List */
+ u8 mc_list[0][6]; /* pointer to 6 bytes entries */
+};
+
+/*
+ * DUMP command
+ */
+struct dump_cmd_struct
+{
+ u16 cmd_status;
+ u16 cmd_cmd;
+ u16 cmd_link;
+ u16 dump_offset; /* pointeroffset to DUMP space */
+};
+
+/*
+ * transmit command
+ */
+struct transmit_cmd_struct
+{
+ u16 cmd_status;
+ u16 cmd_cmd;
+ u16 cmd_link;
+ u16 tbd_offset; /* pointeroffset to TBD */
+ u8 dest[6]; /* destination address of the frame */
+ u16 length; /* user defined: 802.3 length / Ether type */
+};
+
+#define TCMD_ERRMASK 0x0fa0
+#define TCMD_MAXCOLLMASK 0x000f
+#define TCMD_MAXCOLL 0x0020
+#define TCMD_HEARTBEAT 0x0040
+#define TCMD_DEFERRED 0x0080
+#define TCMD_UNDERRUN 0x0100
+#define TCMD_LOSTCTS 0x0200
+#define TCMD_NOCARRIER 0x0400
+#define TCMD_LATECOLL 0x0800
+
+struct tdr_cmd_struct
+{
+ u16 cmd_status;
+ u16 cmd_cmd;
+ u16 cmd_link;
+ u16 status;
+};
+
+#define TDR_LNK_OK 0x8000 /* No link problem identified */
+#define TDR_XCVR_PRB 0x4000 /* indicates a transceiver problem */
+#define TDR_ET_OPN 0x2000 /* open, no correct termination */
+#define TDR_ET_SRT 0x1000 /* TDR detected a short circuit */
+#define TDR_TIMEMASK 0x07ff /* mask for the time field */
+
+/*
+ * Transmit Buffer Descriptor (TBD)
+ */
+struct tbd_struct
+{
+ u16 size; /* size + EOF-Flag(15) */
+ u16 next; /* pointeroffset to next TBD */
+ u32 buffer; /* pointer to buffer */
+};
+
+#define TBD_LAST 0x8000 /* EOF-Flag, indicates last buffer in list */
+
+
+
+
--- /dev/null
+/*
+ * sni_82596.c -- driver for intel 82596 ethernet controller, as
+ * used in older SNI RM machines
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/bitops.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+
+#define SNI_82596_DRIVER_VERSION "SNI RM 82596 driver - Revision: 0.01"
+
+static const char sni_82596_string[] = "snirm_82596";
+
+#define DMA_ALLOC dma_alloc_coherent
+#define DMA_FREE dma_free_coherent
+#define DMA_WBACK(priv, addr, len) do { } while (0)
+#define DMA_INV(priv, addr, len) do { } while (0)
+#define DMA_WBACK_INV(priv, addr, len) do { } while (0)
+
+#define SYSBUS 0x00004400
+
+/* big endian CPU, 82596 little endian */
+#define SWAP32(x) cpu_to_le32((u32)(x))
+#define SWAP16(x) cpu_to_le16((u16)(x))
+
+#define OPT_MPU_16BIT 0x01
+
+#include "lib82596.c"
+
+MODULE_AUTHOR("Thomas Bogendoerfer");
+MODULE_DESCRIPTION("i82596 driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:snirm_82596");
+module_param(i596_debug, int, 0);
+MODULE_PARM_DESC(i596_debug, "82596 debug mask");
+
+static inline void ca(struct net_device *dev)
+{
+ struct i596_private *lp = netdev_priv(dev);
+
+ writel(0, lp->ca);
+}
+
+
+static void mpu_port(struct net_device *dev, int c, dma_addr_t x)
+{
+ struct i596_private *lp = netdev_priv(dev);
+
+ u32 v = (u32) (c) | (u32) (x);
+
+ if (lp->options & OPT_MPU_16BIT) {
+ writew(v & 0xffff, lp->mpu_port);
+ wmb(); /* order writes to MPU port */
+ udelay(1);
+ writew(v >> 16, lp->mpu_port);
+ } else {
+ writel(v, lp->mpu_port);
+ wmb(); /* order writes to MPU port */
+ udelay(1);
+ writel(v, lp->mpu_port);
+ }
+}
+
+
+static int __devinit sni_82596_probe(struct platform_device *dev)
+{
+ struct net_device *netdevice;
+ struct i596_private *lp;
+ struct resource *res, *ca, *idprom, *options;
+ int retval = -ENOMEM;
+ void __iomem *mpu_addr;
+ void __iomem *ca_addr;
+ u8 __iomem *eth_addr;
+
+ res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ ca = platform_get_resource(dev, IORESOURCE_MEM, 1);
+ options = platform_get_resource(dev, 0, 0);
+ idprom = platform_get_resource(dev, IORESOURCE_MEM, 2);
+ if (!res || !ca || !options || !idprom)
+ return -ENODEV;
+ mpu_addr = ioremap_nocache(res->start, 4);
+ if (!mpu_addr)
+ return -ENOMEM;
+ ca_addr = ioremap_nocache(ca->start, 4);
+ if (!ca_addr)
+ goto probe_failed_free_mpu;
+
+ printk(KERN_INFO "Found i82596 at 0x%x\n", res->start);
+
+ netdevice = alloc_etherdev(sizeof(struct i596_private));
+ if (!netdevice)
+ goto probe_failed_free_ca;
+
+ SET_NETDEV_DEV(netdevice, &dev->dev);
+ platform_set_drvdata (dev, netdevice);
+
+ netdevice->base_addr = res->start;
+ netdevice->irq = platform_get_irq(dev, 0);
+
+ eth_addr = ioremap_nocache(idprom->start, 0x10);
+ if (!eth_addr)
+ goto probe_failed;
+
+ /* someone seems to like messed up stuff */
+ netdevice->dev_addr[0] = readb(eth_addr + 0x0b);
+ netdevice->dev_addr[1] = readb(eth_addr + 0x0a);
+ netdevice->dev_addr[2] = readb(eth_addr + 0x09);
+ netdevice->dev_addr[3] = readb(eth_addr + 0x08);
+ netdevice->dev_addr[4] = readb(eth_addr + 0x07);
+ netdevice->dev_addr[5] = readb(eth_addr + 0x06);
+ iounmap(eth_addr);
+
+ if (!netdevice->irq) {
+ printk(KERN_ERR "%s: IRQ not found for i82596 at 0x%lx\n",
+ __FILE__, netdevice->base_addr);
+ goto probe_failed;
+ }
+
+ lp = netdev_priv(netdevice);
+ lp->options = options->flags & IORESOURCE_BITS;
+ lp->ca = ca_addr;
+ lp->mpu_port = mpu_addr;
+
+ retval = i82596_probe(netdevice);
+ if (retval == 0)
+ return 0;
+
+probe_failed:
+ free_netdev(netdevice);
+probe_failed_free_ca:
+ iounmap(ca_addr);
+probe_failed_free_mpu:
+ iounmap(mpu_addr);
+ return retval;
+}
+
+static int __devexit sni_82596_driver_remove(struct platform_device *pdev)
+{
+ struct net_device *dev = platform_get_drvdata(pdev);
+ struct i596_private *lp = netdev_priv(dev);
+
+ unregister_netdev(dev);
+ DMA_FREE(dev->dev.parent, sizeof(struct i596_private),
+ lp->dma, lp->dma_addr);
+ iounmap(lp->ca);
+ iounmap(lp->mpu_port);
+ free_netdev (dev);
+ return 0;
+}
+
+static struct platform_driver sni_82596_driver = {
+ .probe = sni_82596_probe,
+ .remove = __devexit_p(sni_82596_driver_remove),
+ .driver = {
+ .name = sni_82596_string,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __devinit sni_82596_init(void)
+{
+ printk(KERN_INFO SNI_82596_DRIVER_VERSION "\n");
+ return platform_driver_register(&sni_82596_driver);
+}
+
+
+static void __exit sni_82596_exit(void)
+{
+ platform_driver_unregister(&sni_82596_driver);
+}
+
+module_init(sni_82596_init);
+module_exit(sni_82596_exit);
--- /dev/null
+/*
+ * Sun3 i82586 Ethernet driver
+ *
+ * Cloned from ni52.c for the Sun3 by Sam Creasey (sammy@sammy.net)
+ *
+ * Original copyright follows:
+ * --------------------------
+ *
+ * net-3-driver for the NI5210 card (i82586 Ethernet chip)
+ *
+ * This is an extension to the Linux operating system, and is covered by the
+ * same Gnu Public License that covers that work.
+ *
+ * Alphacode 0.82 (96/09/29) for Linux 2.0.0 (or later)
+ * Copyrights (c) 1994,1995,1996 by M.Hipp (hippm@informatik.uni-tuebingen.de)
+ * --------------------------
+ *
+ * Consult ni52.c for further notes from the original driver.
+ *
+ * This incarnation currently supports the OBIO version of the i82586 chip
+ * used in certain sun3 models. It should be fairly doable to expand this
+ * to support VME if I should every acquire such a board.
+ *
+ */
+
+static int debuglevel = 0; /* debug-printk 0: off 1: a few 2: more */
+static int automatic_resume = 0; /* experimental .. better should be zero */
+static int rfdadd = 0; /* rfdadd=1 may be better for 8K MEM cards */
+static int fifo=0x8; /* don't change */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <asm/io.h>
+#include <asm/idprom.h>
+#include <asm/machines.h>
+#include <asm/sun3mmu.h>
+#include <asm/dvma.h>
+#include <asm/byteorder.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include "sun3_82586.h"
+
+#define DRV_NAME "sun3_82586"
+
+#define DEBUG /* debug on */
+#define SYSBUSVAL 0 /* 16 Bit */
+#define SUN3_82586_TOTAL_SIZE PAGE_SIZE
+
+#define sun3_attn586() {*(volatile unsigned char *)(dev->base_addr) |= IEOB_ATTEN; *(volatile unsigned char *)(dev->base_addr) &= ~IEOB_ATTEN;}
+#define sun3_reset586() {*(volatile unsigned char *)(dev->base_addr) = 0; udelay(100); *(volatile unsigned char *)(dev->base_addr) = IEOB_NORSET;}
+#define sun3_disint() {*(volatile unsigned char *)(dev->base_addr) &= ~IEOB_IENAB;}
+#define sun3_enaint() {*(volatile unsigned char *)(dev->base_addr) |= IEOB_IENAB;}
+#define sun3_active() {*(volatile unsigned char *)(dev->base_addr) |= (IEOB_IENAB|IEOB_ONAIR|IEOB_NORSET);}
+
+#define make32(ptr16) (p->memtop + (swab16((unsigned short) (ptr16))) )
+#define make24(ptr32) (char *)swab32(( ((unsigned long) (ptr32)) - p->base))
+#define make16(ptr32) (swab16((unsigned short) ((unsigned long)(ptr32) - (unsigned long) p->memtop )))
+
+/******************* how to calculate the buffers *****************************
+
+ * IMPORTANT NOTE: if you configure only one NUM_XMIT_BUFFS, the driver works
+ * --------------- in a different (more stable?) mode. Only in this mode it's
+ * possible to configure the driver with 'NO_NOPCOMMANDS'
+
+sizeof(scp)=12; sizeof(scb)=16; sizeof(iscp)=8;
+sizeof(scp)+sizeof(iscp)+sizeof(scb) = 36 = INIT
+sizeof(rfd) = 24; sizeof(rbd) = 12;
+sizeof(tbd) = 8; sizeof(transmit_cmd) = 16;
+sizeof(nop_cmd) = 8;
+
+ * if you don't know the driver, better do not change these values: */
+
+#define RECV_BUFF_SIZE 1536 /* slightly oversized */
+#define XMIT_BUFF_SIZE 1536 /* slightly oversized */
+#define NUM_XMIT_BUFFS 1 /* config for 32K shmem */
+#define NUM_RECV_BUFFS_8 4 /* config for 32K shared mem */
+#define NUM_RECV_BUFFS_16 9 /* config for 32K shared mem */
+#define NUM_RECV_BUFFS_32 16 /* config for 32K shared mem */
+#define NO_NOPCOMMANDS /* only possible with NUM_XMIT_BUFFS=1 */
+
+/**************************************************************************/
+
+/* different DELAYs */
+#define DELAY(x) mdelay(32 * x);
+#define DELAY_16(); { udelay(16); }
+#define DELAY_18(); { udelay(4); }
+
+/* wait for command with timeout: */
+#define WAIT_4_SCB_CMD() \
+{ int i; \
+ for(i=0;i<16384;i++) { \
+ if(!p->scb->cmd_cuc) break; \
+ DELAY_18(); \
+ if(i == 16383) { \
+ printk("%s: scb_cmd timed out: %04x,%04x .. disabling i82586!!\n",dev->name,p->scb->cmd_cuc,p->scb->cus); \
+ if(!p->reseted) { p->reseted = 1; sun3_reset586(); } } } }
+
+#define WAIT_4_SCB_CMD_RUC() { int i; \
+ for(i=0;i<16384;i++) { \
+ if(!p->scb->cmd_ruc) break; \
+ DELAY_18(); \
+ if(i == 16383) { \
+ printk("%s: scb_cmd (ruc) timed out: %04x,%04x .. disabling i82586!!\n",dev->name,p->scb->cmd_ruc,p->scb->rus); \
+ if(!p->reseted) { p->reseted = 1; sun3_reset586(); } } } }
+
+#define WAIT_4_STAT_COMPL(addr) { int i; \
+ for(i=0;i<32767;i++) { \
+ if(swab16((addr)->cmd_status) & STAT_COMPL) break; \
+ DELAY_16(); DELAY_16(); } }
+
+static int sun3_82586_probe1(struct net_device *dev,int ioaddr);
+static irqreturn_t sun3_82586_interrupt(int irq,void *dev_id);
+static int sun3_82586_open(struct net_device *dev);
+static int sun3_82586_close(struct net_device *dev);
+static int sun3_82586_send_packet(struct sk_buff *,struct net_device *);
+static struct net_device_stats *sun3_82586_get_stats(struct net_device *dev);
+static void set_multicast_list(struct net_device *dev);
+static void sun3_82586_timeout(struct net_device *dev);
+#if 0
+static void sun3_82586_dump(struct net_device *,void *);
+#endif
+
+/* helper-functions */
+static int init586(struct net_device *dev);
+static int check586(struct net_device *dev,char *where,unsigned size);
+static void alloc586(struct net_device *dev);
+static void startrecv586(struct net_device *dev);
+static void *alloc_rfa(struct net_device *dev,void *ptr);
+static void sun3_82586_rcv_int(struct net_device *dev);
+static void sun3_82586_xmt_int(struct net_device *dev);
+static void sun3_82586_rnr_int(struct net_device *dev);
+
+struct priv
+{
+ unsigned long base;
+ char *memtop;
+ long int lock;
+ int reseted;
+ volatile struct rfd_struct *rfd_last,*rfd_top,*rfd_first;
+ volatile struct scp_struct *scp; /* volatile is important */
+ volatile struct iscp_struct *iscp; /* volatile is important */
+ volatile struct scb_struct *scb; /* volatile is important */
+ volatile struct tbd_struct *xmit_buffs[NUM_XMIT_BUFFS];
+ volatile struct transmit_cmd_struct *xmit_cmds[NUM_XMIT_BUFFS];
+#if (NUM_XMIT_BUFFS == 1)
+ volatile struct nop_cmd_struct *nop_cmds[2];
+#else
+ volatile struct nop_cmd_struct *nop_cmds[NUM_XMIT_BUFFS];
+#endif
+ volatile int nop_point,num_recv_buffs;
+ volatile char *xmit_cbuffs[NUM_XMIT_BUFFS];
+ volatile int xmit_count,xmit_last;
+};
+
+/**********************************************
+ * close device
+ */
+static int sun3_82586_close(struct net_device *dev)
+{
+ free_irq(dev->irq, dev);
+
+ sun3_reset586(); /* the hard way to stop the receiver */
+
+ netif_stop_queue(dev);
+
+ return 0;
+}
+
+/**********************************************
+ * open device
+ */
+static int sun3_82586_open(struct net_device *dev)
+{
+ int ret;
+
+ sun3_disint();
+ alloc586(dev);
+ init586(dev);
+ startrecv586(dev);
+ sun3_enaint();
+
+ ret = request_irq(dev->irq, sun3_82586_interrupt,0,dev->name,dev);
+ if (ret)
+ {
+ sun3_reset586();
+ return ret;
+ }
+
+ netif_start_queue(dev);
+
+ return 0; /* most done by init */
+}
+
+/**********************************************
+ * Check to see if there's an 82586 out there.
+ */
+static int check586(struct net_device *dev,char *where,unsigned size)
+{
+ struct priv pb;
+ struct priv *p = &pb;
+ char *iscp_addr;
+ int i;
+
+ p->base = (unsigned long) dvma_btov(0);
+ p->memtop = (char *)dvma_btov((unsigned long)where);
+ p->scp = (struct scp_struct *)(p->base + SCP_DEFAULT_ADDRESS);
+ memset((char *)p->scp,0, sizeof(struct scp_struct));
+ for(i=0;i<sizeof(struct scp_struct);i++) /* memory was writeable? */
+ if(((char *)p->scp)[i])
+ return 0;
+ p->scp->sysbus = SYSBUSVAL; /* 1 = 8Bit-Bus, 0 = 16 Bit */
+ if(p->scp->sysbus != SYSBUSVAL)
+ return 0;
+
+ iscp_addr = (char *)dvma_btov((unsigned long)where);
+
+ p->iscp = (struct iscp_struct *) iscp_addr;
+ memset((char *)p->iscp,0, sizeof(struct iscp_struct));
+
+ p->scp->iscp = make24(p->iscp);
+ p->iscp->busy = 1;
+
+ sun3_reset586();
+ sun3_attn586();
+ DELAY(1); /* wait a while... */
+
+ if(p->iscp->busy) /* i82586 clears 'busy' after successful init */
+ return 0;
+
+ return 1;
+}
+
+/******************************************************************
+ * set iscp at the right place, called by sun3_82586_probe1 and open586.
+ */
+static void alloc586(struct net_device *dev)
+{
+ struct priv *p = netdev_priv(dev);
+
+ sun3_reset586();
+ DELAY(1);
+
+ p->scp = (struct scp_struct *) (p->base + SCP_DEFAULT_ADDRESS);
+ p->iscp = (struct iscp_struct *) dvma_btov(dev->mem_start);
+ p->scb = (struct scb_struct *) ((char *)p->iscp + sizeof(struct iscp_struct));
+
+ memset((char *) p->iscp,0,sizeof(struct iscp_struct));
+ memset((char *) p->scp ,0,sizeof(struct scp_struct));
+
+ p->scp->iscp = make24(p->iscp);
+ p->scp->sysbus = SYSBUSVAL;
+ p->iscp->scb_offset = make16(p->scb);
+ p->iscp->scb_base = make24(dvma_btov(dev->mem_start));
+
+ p->iscp->busy = 1;
+ sun3_reset586();
+ sun3_attn586();
+
+ DELAY(1);
+
+ if(p->iscp->busy)
+ printk("%s: Init-Problems (alloc).\n",dev->name);
+
+ p->reseted = 0;
+
+ memset((char *)p->scb,0,sizeof(struct scb_struct));
+}
+
+struct net_device * __init sun3_82586_probe(int unit)
+{
+ struct net_device *dev;
+ unsigned long ioaddr;
+ static int found = 0;
+ int err = -ENOMEM;
+
+ /* check that this machine has an onboard 82586 */
+ switch(idprom->id_machtype) {
+ case SM_SUN3|SM_3_160:
+ case SM_SUN3|SM_3_260:
+ /* these machines have 82586 */
+ break;
+
+ default:
+ return ERR_PTR(-ENODEV);
+ }
+
+ if (found)
+ return ERR_PTR(-ENODEV);
+
+ ioaddr = (unsigned long)ioremap(IE_OBIO, SUN3_82586_TOTAL_SIZE);
+ if (!ioaddr)
+ return ERR_PTR(-ENOMEM);
+ found = 1;
+
+ dev = alloc_etherdev(sizeof(struct priv));
+ if (!dev)
+ goto out;
+ if (unit >= 0) {
+ sprintf(dev->name, "eth%d", unit);
+ netdev_boot_setup_check(dev);
+ }
+
+ dev->irq = IE_IRQ;
+ dev->base_addr = ioaddr;
+ err = sun3_82586_probe1(dev, ioaddr);
+ if (err)
+ goto out1;
+ err = register_netdev(dev);
+ if (err)
+ goto out2;
+ return dev;
+
+out2:
+ release_region(ioaddr, SUN3_82586_TOTAL_SIZE);
+out1:
+ free_netdev(dev);
+out:
+ iounmap((void __iomem *)ioaddr);
+ return ERR_PTR(err);
+}
+
+static const struct net_device_ops sun3_82586_netdev_ops = {
+ .ndo_open = sun3_82586_open,
+ .ndo_stop = sun3_82586_close,
+ .ndo_start_xmit = sun3_82586_send_packet,
+ .ndo_set_multicast_list = set_multicast_list,
+ .ndo_tx_timeout = sun3_82586_timeout,
+ .ndo_get_stats = sun3_82586_get_stats,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_change_mtu = eth_change_mtu,
+};
+
+static int __init sun3_82586_probe1(struct net_device *dev,int ioaddr)
+{
+ int i, size, retval;
+
+ if (!request_region(ioaddr, SUN3_82586_TOTAL_SIZE, DRV_NAME))
+ return -EBUSY;
+
+ /* copy in the ethernet address from the prom */
+ for(i = 0; i < 6 ; i++)
+ dev->dev_addr[i] = idprom->id_ethaddr[i];
+
+ printk("%s: SUN3 Intel 82586 found at %lx, ",dev->name,dev->base_addr);
+
+ /*
+ * check (or search) IO-Memory, 32K
+ */
+ size = 0x8000;
+
+ dev->mem_start = (unsigned long)dvma_malloc_align(0x8000, 0x1000);
+ dev->mem_end = dev->mem_start + size;
+
+ if(size != 0x2000 && size != 0x4000 && size != 0x8000) {
+ printk("\n%s: Illegal memory size %d. Allowed is 0x2000 or 0x4000 or 0x8000 bytes.\n",dev->name,size);
+ retval = -ENODEV;
+ goto out;
+ }
+ if(!check586(dev,(char *) dev->mem_start,size)) {
+ printk("?memcheck, Can't find memory at 0x%lx with size %d!\n",dev->mem_start,size);
+ retval = -ENODEV;
+ goto out;
+ }
+
+ ((struct priv *)netdev_priv(dev))->memtop =
+ (char *)dvma_btov(dev->mem_start);
+ ((struct priv *)netdev_priv(dev))->base = (unsigned long) dvma_btov(0);
+ alloc586(dev);
+
+ /* set number of receive-buffs according to memsize */
+ if(size == 0x2000)
+ ((struct priv *)netdev_priv(dev))->num_recv_buffs =
+ NUM_RECV_BUFFS_8;
+ else if(size == 0x4000)
+ ((struct priv *)netdev_priv(dev))->num_recv_buffs =
+ NUM_RECV_BUFFS_16;
+ else
+ ((struct priv *)netdev_priv(dev))->num_recv_buffs =
+ NUM_RECV_BUFFS_32;
+
+ printk("Memaddr: 0x%lx, Memsize: %d, IRQ %d\n",dev->mem_start,size, dev->irq);
+
+ dev->netdev_ops = &sun3_82586_netdev_ops;
+ dev->watchdog_timeo = HZ/20;
+
+ dev->if_port = 0;
+ return 0;
+out:
+ release_region(ioaddr, SUN3_82586_TOTAL_SIZE);
+ return retval;
+}
+
+
+static int init586(struct net_device *dev)
+{
+ void *ptr;
+ int i,result=0;
+ struct priv *p = netdev_priv(dev);
+ volatile struct configure_cmd_struct *cfg_cmd;
+ volatile struct iasetup_cmd_struct *ias_cmd;
+ volatile struct tdr_cmd_struct *tdr_cmd;
+ volatile struct mcsetup_cmd_struct *mc_cmd;
+ struct netdev_hw_addr *ha;
+ int num_addrs=netdev_mc_count(dev);
+
+ ptr = (void *) ((char *)p->scb + sizeof(struct scb_struct));
+
+ cfg_cmd = (struct configure_cmd_struct *)ptr; /* configure-command */
+ cfg_cmd->cmd_status = 0;
+ cfg_cmd->cmd_cmd = swab16(CMD_CONFIGURE | CMD_LAST);
+ cfg_cmd->cmd_link = 0xffff;
+
+ cfg_cmd->byte_cnt = 0x0a; /* number of cfg bytes */
+ cfg_cmd->fifo = fifo; /* fifo-limit (8=tx:32/rx:64) */
+ cfg_cmd->sav_bf = 0x40; /* hold or discard bad recv frames (bit 7) */
+ cfg_cmd->adr_len = 0x2e; /* addr_len |!src_insert |pre-len |loopback */
+ cfg_cmd->priority = 0x00;
+ cfg_cmd->ifs = 0x60;
+ cfg_cmd->time_low = 0x00;
+ cfg_cmd->time_high = 0xf2;
+ cfg_cmd->promisc = 0;
+ if(dev->flags & IFF_ALLMULTI) {
+ int len = ((char *) p->iscp - (char *) ptr - 8) / 6;
+ if(num_addrs > len) {
+ printk("%s: switching to promisc. mode\n",dev->name);
+ cfg_cmd->promisc = 1;
+ }
+ }
+ if(dev->flags&IFF_PROMISC)
+ cfg_cmd->promisc = 1;
+ cfg_cmd->carr_coll = 0x00;
+
+ p->scb->cbl_offset = make16(cfg_cmd);
+ p->scb->cmd_ruc = 0;
+
+ p->scb->cmd_cuc = CUC_START; /* cmd.-unit start */
+ sun3_attn586();
+
+ WAIT_4_STAT_COMPL(cfg_cmd);
+
+ if((swab16(cfg_cmd->cmd_status) & (STAT_OK|STAT_COMPL)) != (STAT_COMPL|STAT_OK))
+ {
+ printk("%s: configure command failed: %x\n",dev->name,swab16(cfg_cmd->cmd_status));
+ return 1;
+ }
+
+ /*
+ * individual address setup
+ */
+
+ ias_cmd = (struct iasetup_cmd_struct *)ptr;
+
+ ias_cmd->cmd_status = 0;
+ ias_cmd->cmd_cmd = swab16(CMD_IASETUP | CMD_LAST);
+ ias_cmd->cmd_link = 0xffff;
+
+ memcpy((char *)&ias_cmd->iaddr,(char *) dev->dev_addr,ETH_ALEN);
+
+ p->scb->cbl_offset = make16(ias_cmd);
+
+ p->scb->cmd_cuc = CUC_START; /* cmd.-unit start */
+ sun3_attn586();
+
+ WAIT_4_STAT_COMPL(ias_cmd);
+
+ if((swab16(ias_cmd->cmd_status) & (STAT_OK|STAT_COMPL)) != (STAT_OK|STAT_COMPL)) {
+ printk("%s (82586): individual address setup command failed: %04x\n",dev->name,swab16(ias_cmd->cmd_status));
+ return 1;
+ }
+
+ /*
+ * TDR, wire check .. e.g. no resistor e.t.c
+ */
+
+ tdr_cmd = (struct tdr_cmd_struct *)ptr;
+
+ tdr_cmd->cmd_status = 0;
+ tdr_cmd->cmd_cmd = swab16(CMD_TDR | CMD_LAST);
+ tdr_cmd->cmd_link = 0xffff;
+ tdr_cmd->status = 0;
+
+ p->scb->cbl_offset = make16(tdr_cmd);
+ p->scb->cmd_cuc = CUC_START; /* cmd.-unit start */
+ sun3_attn586();
+
+ WAIT_4_STAT_COMPL(tdr_cmd);
+
+ if(!(swab16(tdr_cmd->cmd_status) & STAT_COMPL))
+ {
+ printk("%s: Problems while running the TDR.\n",dev->name);
+ }
+ else
+ {
+ DELAY_16(); /* wait for result */
+ result = swab16(tdr_cmd->status);
+
+ p->scb->cmd_cuc = p->scb->cus & STAT_MASK;
+ sun3_attn586(); /* ack the interrupts */
+
+ if(result & TDR_LNK_OK)
+ ;
+ else if(result & TDR_XCVR_PRB)
+ printk("%s: TDR: Transceiver problem. Check the cable(s)!\n",dev->name);
+ else if(result & TDR_ET_OPN)
+ printk("%s: TDR: No correct termination %d clocks away.\n",dev->name,result & TDR_TIMEMASK);
+ else if(result & TDR_ET_SRT)
+ {
+ if (result & TDR_TIMEMASK) /* time == 0 -> strange :-) */
+ printk("%s: TDR: Detected a short circuit %d clocks away.\n",dev->name,result & TDR_TIMEMASK);
+ }
+ else
+ printk("%s: TDR: Unknown status %04x\n",dev->name,result);
+ }
+
+ /*
+ * Multicast setup
+ */
+ if(num_addrs && !(dev->flags & IFF_PROMISC) )
+ {
+ mc_cmd = (struct mcsetup_cmd_struct *) ptr;
+ mc_cmd->cmd_status = 0;
+ mc_cmd->cmd_cmd = swab16(CMD_MCSETUP | CMD_LAST);
+ mc_cmd->cmd_link = 0xffff;
+ mc_cmd->mc_cnt = swab16(num_addrs * 6);
+
+ i = 0;
+ netdev_for_each_mc_addr(ha, dev)
+ memcpy((char *) mc_cmd->mc_list[i++],
+ ha->addr, ETH_ALEN);
+
+ p->scb->cbl_offset = make16(mc_cmd);
+ p->scb->cmd_cuc = CUC_START;
+ sun3_attn586();
+
+ WAIT_4_STAT_COMPL(mc_cmd);
+
+ if( (swab16(mc_cmd->cmd_status) & (STAT_COMPL|STAT_OK)) != (STAT_COMPL|STAT_OK) )
+ printk("%s: Can't apply multicast-address-list.\n",dev->name);
+ }
+
+ /*
+ * alloc nop/xmit-cmds
+ */
+#if (NUM_XMIT_BUFFS == 1)
+ for(i=0;i<2;i++)
+ {
+ p->nop_cmds[i] = (struct nop_cmd_struct *)ptr;
+ p->nop_cmds[i]->cmd_cmd = swab16(CMD_NOP);
+ p->nop_cmds[i]->cmd_status = 0;
+ p->nop_cmds[i]->cmd_link = make16((p->nop_cmds[i]));
+ ptr = (char *) ptr + sizeof(struct nop_cmd_struct);
+ }
+#else
+ for(i=0;i<NUM_XMIT_BUFFS;i++)
+ {
+ p->nop_cmds[i] = (struct nop_cmd_struct *)ptr;
+ p->nop_cmds[i]->cmd_cmd = swab16(CMD_NOP);
+ p->nop_cmds[i]->cmd_status = 0;
+ p->nop_cmds[i]->cmd_link = make16((p->nop_cmds[i]));
+ ptr = (char *) ptr + sizeof(struct nop_cmd_struct);
+ }
+#endif
+
+ ptr = alloc_rfa(dev,(void *)ptr); /* init receive-frame-area */
+
+ /*
+ * alloc xmit-buffs / init xmit_cmds
+ */
+ for(i=0;i<NUM_XMIT_BUFFS;i++)
+ {
+ p->xmit_cmds[i] = (struct transmit_cmd_struct *)ptr; /*transmit cmd/buff 0*/
+ ptr = (char *) ptr + sizeof(struct transmit_cmd_struct);
+ p->xmit_cbuffs[i] = (char *)ptr; /* char-buffs */
+ ptr = (char *) ptr + XMIT_BUFF_SIZE;
+ p->xmit_buffs[i] = (struct tbd_struct *)ptr; /* TBD */
+ ptr = (char *) ptr + sizeof(struct tbd_struct);
+ if((void *)ptr > (void *)dev->mem_end)
+ {
+ printk("%s: not enough shared-mem for your configuration!\n",dev->name);
+ return 1;
+ }
+ memset((char *)(p->xmit_cmds[i]) ,0, sizeof(struct transmit_cmd_struct));
+ memset((char *)(p->xmit_buffs[i]),0, sizeof(struct tbd_struct));
+ p->xmit_cmds[i]->cmd_link = make16(p->nop_cmds[(i+1)%NUM_XMIT_BUFFS]);
+ p->xmit_cmds[i]->cmd_status = swab16(STAT_COMPL);
+ p->xmit_cmds[i]->cmd_cmd = swab16(CMD_XMIT | CMD_INT);
+ p->xmit_cmds[i]->tbd_offset = make16((p->xmit_buffs[i]));
+ p->xmit_buffs[i]->next = 0xffff;
+ p->xmit_buffs[i]->buffer = make24((p->xmit_cbuffs[i]));
+ }
+
+ p->xmit_count = 0;
+ p->xmit_last = 0;
+#ifndef NO_NOPCOMMANDS
+ p->nop_point = 0;
+#endif
+
+ /*
+ * 'start transmitter'
+ */
+#ifndef NO_NOPCOMMANDS
+ p->scb->cbl_offset = make16(p->nop_cmds[0]);
+ p->scb->cmd_cuc = CUC_START;
+ sun3_attn586();
+ WAIT_4_SCB_CMD();
+#else
+ p->xmit_cmds[0]->cmd_link = make16(p->xmit_cmds[0]);
+ p->xmit_cmds[0]->cmd_cmd = swab16(CMD_XMIT | CMD_SUSPEND | CMD_INT);
+#endif
+
+ /*
+ * ack. interrupts
+ */
+ p->scb->cmd_cuc = p->scb->cus & STAT_MASK;
+ sun3_attn586();
+ DELAY_16();
+
+ sun3_enaint();
+ sun3_active();
+
+ return 0;
+}
+
+/******************************************************
+ * This is a helper routine for sun3_82586_rnr_int() and init586().
+ * It sets up the Receive Frame Area (RFA).
+ */
+
+static void *alloc_rfa(struct net_device *dev,void *ptr)
+{
+ volatile struct rfd_struct *rfd = (struct rfd_struct *)ptr;
+ volatile struct rbd_struct *rbd;
+ int i;
+ struct priv *p = netdev_priv(dev);
+
+ memset((char *) rfd,0,sizeof(struct rfd_struct)*(p->num_recv_buffs+rfdadd));
+ p->rfd_first = rfd;
+
+ for(i = 0; i < (p->num_recv_buffs+rfdadd); i++) {
+ rfd[i].next = make16(rfd + (i+1) % (p->num_recv_buffs+rfdadd) );
+ rfd[i].rbd_offset = 0xffff;
+ }
+ rfd[p->num_recv_buffs-1+rfdadd].last = RFD_SUSP; /* RU suspend */
+
+ ptr = (void *) (rfd + (p->num_recv_buffs + rfdadd) );
+
+ rbd = (struct rbd_struct *) ptr;
+ ptr = (void *) (rbd + p->num_recv_buffs);
+
+ /* clr descriptors */
+ memset((char *) rbd,0,sizeof(struct rbd_struct)*(p->num_recv_buffs));
+
+ for(i=0;i<p->num_recv_buffs;i++)
+ {
+ rbd[i].next = make16((rbd + (i+1) % p->num_recv_buffs));
+ rbd[i].size = swab16(RECV_BUFF_SIZE);
+ rbd[i].buffer = make24(ptr);
+ ptr = (char *) ptr + RECV_BUFF_SIZE;
+ }
+
+ p->rfd_top = p->rfd_first;
+ p->rfd_last = p->rfd_first + (p->num_recv_buffs - 1 + rfdadd);
+
+ p->scb->rfa_offset = make16(p->rfd_first);
+ p->rfd_first->rbd_offset = make16(rbd);
+
+ return ptr;
+}
+
+
+/**************************************************
+ * Interrupt Handler ...
+ */
+
+static irqreturn_t sun3_82586_interrupt(int irq,void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ unsigned short stat;
+ int cnt=0;
+ struct priv *p;
+
+ if (!dev) {
+ printk ("sun3_82586-interrupt: irq %d for unknown device.\n",irq);
+ return IRQ_NONE;
+ }
+ p = netdev_priv(dev);
+
+ if(debuglevel > 1)
+ printk("I");
+
+ WAIT_4_SCB_CMD(); /* wait for last command */
+
+ while((stat=p->scb->cus & STAT_MASK))
+ {
+ p->scb->cmd_cuc = stat;
+ sun3_attn586();
+
+ if(stat & STAT_FR) /* received a frame */
+ sun3_82586_rcv_int(dev);
+
+ if(stat & STAT_RNR) /* RU went 'not ready' */
+ {
+ printk("(R)");
+ if(p->scb->rus & RU_SUSPEND) /* special case: RU_SUSPEND */
+ {
+ WAIT_4_SCB_CMD();
+ p->scb->cmd_ruc = RUC_RESUME;
+ sun3_attn586();
+ WAIT_4_SCB_CMD_RUC();
+ }
+ else
+ {
+ printk("%s: Receiver-Unit went 'NOT READY': %04x/%02x.\n",dev->name,(int) stat,(int) p->scb->rus);
+ sun3_82586_rnr_int(dev);
+ }
+ }
+
+ if(stat & STAT_CX) /* command with I-bit set complete */
+ sun3_82586_xmt_int(dev);
+
+#ifndef NO_NOPCOMMANDS
+ if(stat & STAT_CNA) /* CU went 'not ready' */
+ {
+ if(netif_running(dev))
+ printk("%s: oops! CU has left active state. stat: %04x/%02x.\n",dev->name,(int) stat,(int) p->scb->cus);
+ }
+#endif
+
+ if(debuglevel > 1)
+ printk("%d",cnt++);
+
+ WAIT_4_SCB_CMD(); /* wait for ack. (sun3_82586_xmt_int can be faster than ack!!) */
+ if(p->scb->cmd_cuc) /* timed out? */
+ {
+ printk("%s: Acknowledge timed out.\n",dev->name);
+ sun3_disint();
+ break;
+ }
+ }
+
+ if(debuglevel > 1)
+ printk("i");
+ return IRQ_HANDLED;
+}
+
+/*******************************************************
+ * receive-interrupt
+ */
+
+static void sun3_82586_rcv_int(struct net_device *dev)
+{
+ int status,cnt=0;
+ unsigned short totlen;
+ struct sk_buff *skb;
+ struct rbd_struct *rbd;
+ struct priv *p = netdev_priv(dev);
+
+ if(debuglevel > 0)
+ printk("R");
+
+ for(;(status = p->rfd_top->stat_high) & RFD_COMPL;)
+ {
+ rbd = (struct rbd_struct *) make32(p->rfd_top->rbd_offset);
+
+ if(status & RFD_OK) /* frame received without error? */
+ {
+ if( (totlen = swab16(rbd->status)) & RBD_LAST) /* the first and the last buffer? */
+ {
+ totlen &= RBD_MASK; /* length of this frame */
+ rbd->status = 0;
+ skb = (struct sk_buff *) dev_alloc_skb(totlen+2);
+ if(skb != NULL)
+ {
+ skb_reserve(skb,2);
+ skb_put(skb,totlen);
+ skb_copy_to_linear_data(skb,(char *) p->base+swab32((unsigned long) rbd->buffer),totlen);
+ skb->protocol=eth_type_trans(skb,dev);
+ netif_rx(skb);
+ dev->stats.rx_packets++;
+ }
+ else
+ dev->stats.rx_dropped++;
+ }
+ else
+ {
+ int rstat;
+ /* free all RBD's until RBD_LAST is set */
+ totlen = 0;
+ while(!((rstat=swab16(rbd->status)) & RBD_LAST))
+ {
+ totlen += rstat & RBD_MASK;
+ if(!rstat)
+ {
+ printk("%s: Whoops .. no end mark in RBD list\n",dev->name);
+ break;
+ }
+ rbd->status = 0;
+ rbd = (struct rbd_struct *) make32(rbd->next);
+ }
+ totlen += rstat & RBD_MASK;
+ rbd->status = 0;
+ printk("%s: received oversized frame! length: %d\n",dev->name,totlen);
+ dev->stats.rx_dropped++;
+ }
+ }
+ else /* frame !(ok), only with 'save-bad-frames' */
+ {
+ printk("%s: oops! rfd-error-status: %04x\n",dev->name,status);
+ dev->stats.rx_errors++;
+ }
+ p->rfd_top->stat_high = 0;
+ p->rfd_top->last = RFD_SUSP; /* maybe exchange by RFD_LAST */
+ p->rfd_top->rbd_offset = 0xffff;
+ p->rfd_last->last = 0; /* delete RFD_SUSP */
+ p->rfd_last = p->rfd_top;
+ p->rfd_top = (struct rfd_struct *) make32(p->rfd_top->next); /* step to next RFD */
+ p->scb->rfa_offset = make16(p->rfd_top);
+
+ if(debuglevel > 0)
+ printk("%d",cnt++);
+ }
+
+ if(automatic_resume)
+ {
+ WAIT_4_SCB_CMD();
+ p->scb->cmd_ruc = RUC_RESUME;
+ sun3_attn586();
+ WAIT_4_SCB_CMD_RUC();
+ }
+
+#ifdef WAIT_4_BUSY
+ {
+ int i;
+ for(i=0;i<1024;i++)
+ {
+ if(p->rfd_top->status)
+ break;
+ DELAY_16();
+ if(i == 1023)
+ printk("%s: RU hasn't fetched next RFD (not busy/complete)\n",dev->name);
+ }
+ }
+#endif
+
+#if 0
+ if(!at_least_one)
+ {
+ int i;
+ volatile struct rfd_struct *rfds=p->rfd_top;
+ volatile struct rbd_struct *rbds;
+ printk("%s: received a FC intr. without having a frame: %04x %d\n",dev->name,status,old_at_least);
+ for(i=0;i< (p->num_recv_buffs+4);i++)
+ {
+ rbds = (struct rbd_struct *) make32(rfds->rbd_offset);
+ printk("%04x:%04x ",rfds->status,rbds->status);
+ rfds = (struct rfd_struct *) make32(rfds->next);
+ }
+ printk("\nerrs: %04x %04x stat: %04x\n",(int)p->scb->rsc_errs,(int)p->scb->ovrn_errs,(int)p->scb->status);
+ printk("\nerrs: %04x %04x rus: %02x, cus: %02x\n",(int)p->scb->rsc_errs,(int)p->scb->ovrn_errs,(int)p->scb->rus,(int)p->scb->cus);
+ }
+ old_at_least = at_least_one;
+#endif
+
+ if(debuglevel > 0)
+ printk("r");
+}
+
+/**********************************************************
+ * handle 'Receiver went not ready'.
+ */
+
+static void sun3_82586_rnr_int(struct net_device *dev)
+{
+ struct priv *p = netdev_priv(dev);
+
+ dev->stats.rx_errors++;
+
+ WAIT_4_SCB_CMD(); /* wait for the last cmd, WAIT_4_FULLSTAT?? */
+ p->scb->cmd_ruc = RUC_ABORT; /* usually the RU is in the 'no resource'-state .. abort it now. */
+ sun3_attn586();
+ WAIT_4_SCB_CMD_RUC(); /* wait for accept cmd. */
+
+ alloc_rfa(dev,(char *)p->rfd_first);
+/* maybe add a check here, before restarting the RU */
+ startrecv586(dev); /* restart RU */
+
+ printk("%s: Receive-Unit restarted. Status: %04x\n",dev->name,p->scb->rus);
+
+}
+
+/**********************************************************
+ * handle xmit - interrupt
+ */
+
+static void sun3_82586_xmt_int(struct net_device *dev)
+{
+ int status;
+ struct priv *p = netdev_priv(dev);
+
+ if(debuglevel > 0)
+ printk("X");
+
+ status = swab16(p->xmit_cmds[p->xmit_last]->cmd_status);
+ if(!(status & STAT_COMPL))
+ printk("%s: strange .. xmit-int without a 'COMPLETE'\n",dev->name);
+
+ if(status & STAT_OK)
+ {
+ dev->stats.tx_packets++;
+ dev->stats.collisions += (status & TCMD_MAXCOLLMASK);
+ }
+ else
+ {
+ dev->stats.tx_errors++;
+ if(status & TCMD_LATECOLL) {
+ printk("%s: late collision detected.\n",dev->name);
+ dev->stats.collisions++;
+ }
+ else if(status & TCMD_NOCARRIER) {
+ dev->stats.tx_carrier_errors++;
+ printk("%s: no carrier detected.\n",dev->name);
+ }
+ else if(status & TCMD_LOSTCTS)
+ printk("%s: loss of CTS detected.\n",dev->name);
+ else if(status & TCMD_UNDERRUN) {
+ dev->stats.tx_fifo_errors++;
+ printk("%s: DMA underrun detected.\n",dev->name);
+ }
+ else if(status & TCMD_MAXCOLL) {
+ printk("%s: Max. collisions exceeded.\n",dev->name);
+ dev->stats.collisions += 16;
+ }
+ }
+
+#if (NUM_XMIT_BUFFS > 1)
+ if( (++p->xmit_last) == NUM_XMIT_BUFFS)
+ p->xmit_last = 0;
+#endif
+ netif_wake_queue(dev);
+}
+
+/***********************************************************
+ * (re)start the receiver
+ */
+
+static void startrecv586(struct net_device *dev)
+{
+ struct priv *p = netdev_priv(dev);
+
+ WAIT_4_SCB_CMD();
+ WAIT_4_SCB_CMD_RUC();
+ p->scb->rfa_offset = make16(p->rfd_first);
+ p->scb->cmd_ruc = RUC_START;
+ sun3_attn586(); /* start cmd. */
+ WAIT_4_SCB_CMD_RUC(); /* wait for accept cmd. (no timeout!!) */
+}
+
+static void sun3_82586_timeout(struct net_device *dev)
+{
+ struct priv *p = netdev_priv(dev);
+#ifndef NO_NOPCOMMANDS
+ if(p->scb->cus & CU_ACTIVE) /* COMMAND-UNIT active? */
+ {
+ netif_wake_queue(dev);
+#ifdef DEBUG
+ printk("%s: strange ... timeout with CU active?!?\n",dev->name);
+ printk("%s: X0: %04x N0: %04x N1: %04x %d\n",dev->name,(int)swab16(p->xmit_cmds[0]->cmd_status),(int)swab16(p->nop_cmds[0]->cmd_status),(int)swab16(p->nop_cmds[1]->cmd_status),(int)p->nop_point);
+#endif
+ p->scb->cmd_cuc = CUC_ABORT;
+ sun3_attn586();
+ WAIT_4_SCB_CMD();
+ p->scb->cbl_offset = make16(p->nop_cmds[p->nop_point]);
+ p->scb->cmd_cuc = CUC_START;
+ sun3_attn586();
+ WAIT_4_SCB_CMD();
+ dev->trans_start = jiffies; /* prevent tx timeout */
+ return 0;
+ }
+#endif
+ {
+#ifdef DEBUG
+ printk("%s: xmitter timed out, try to restart! stat: %02x\n",dev->name,p->scb->cus);
+ printk("%s: command-stats: %04x %04x\n",dev->name,swab16(p->xmit_cmds[0]->cmd_status),swab16(p->xmit_cmds[1]->cmd_status));
+ printk("%s: check, whether you set the right interrupt number!\n",dev->name);
+#endif
+ sun3_82586_close(dev);
+ sun3_82586_open(dev);
+ }
+ dev->trans_start = jiffies; /* prevent tx timeout */
+}
+
+/******************************************************
+ * send frame
+ */
+
+static int sun3_82586_send_packet(struct sk_buff *skb, struct net_device *dev)
+{
+ int len,i;
+#ifndef NO_NOPCOMMANDS
+ int next_nop;
+#endif
+ struct priv *p = netdev_priv(dev);
+
+ if(skb->len > XMIT_BUFF_SIZE)
+ {
+ printk("%s: Sorry, max. framelength is %d bytes. The length of your frame is %d bytes.\n",dev->name,XMIT_BUFF_SIZE,skb->len);
+ return NETDEV_TX_OK;
+ }
+
+ netif_stop_queue(dev);
+
+#if(NUM_XMIT_BUFFS > 1)
+ if(test_and_set_bit(0,(void *) &p->lock)) {
+ printk("%s: Queue was locked\n",dev->name);
+ return NETDEV_TX_BUSY;
+ }
+ else
+#endif
+ {
+ len = skb->len;
+ if (len < ETH_ZLEN) {
+ memset((void *)p->xmit_cbuffs[p->xmit_count], 0,
+ ETH_ZLEN);
+ len = ETH_ZLEN;
+ }
+ skb_copy_from_linear_data(skb, (void *)p->xmit_cbuffs[p->xmit_count], skb->len);
+
+#if (NUM_XMIT_BUFFS == 1)
+# ifdef NO_NOPCOMMANDS
+
+#ifdef DEBUG
+ if(p->scb->cus & CU_ACTIVE)
+ {
+ printk("%s: Hmmm .. CU is still running and we wanna send a new packet.\n",dev->name);
+ printk("%s: stat: %04x %04x\n",dev->name,p->scb->cus,swab16(p->xmit_cmds[0]->cmd_status));
+ }
+#endif
+
+ p->xmit_buffs[0]->size = swab16(TBD_LAST | len);
+ for(i=0;i<16;i++)
+ {
+ p->xmit_cmds[0]->cmd_status = 0;
+ WAIT_4_SCB_CMD();
+ if( (p->scb->cus & CU_STATUS) == CU_SUSPEND)
+ p->scb->cmd_cuc = CUC_RESUME;
+ else
+ {
+ p->scb->cbl_offset = make16(p->xmit_cmds[0]);
+ p->scb->cmd_cuc = CUC_START;
+ }
+
+ sun3_attn586();
+ if(!i)
+ dev_kfree_skb(skb);
+ WAIT_4_SCB_CMD();
+ if( (p->scb->cus & CU_ACTIVE)) /* test it, because CU sometimes doesn't start immediately */
+ break;
+ if(p->xmit_cmds[0]->cmd_status)
+ break;
+ if(i==15)
+ printk("%s: Can't start transmit-command.\n",dev->name);
+ }
+# else
+ next_nop = (p->nop_point + 1) & 0x1;
+ p->xmit_buffs[0]->size = swab16(TBD_LAST | len);
+
+ p->xmit_cmds[0]->cmd_link = p->nop_cmds[next_nop]->cmd_link
+ = make16((p->nop_cmds[next_nop]));
+ p->xmit_cmds[0]->cmd_status = p->nop_cmds[next_nop]->cmd_status = 0;
+
+ p->nop_cmds[p->nop_point]->cmd_link = make16((p->xmit_cmds[0]));
+ p->nop_point = next_nop;
+ dev_kfree_skb(skb);
+# endif
+#else
+ p->xmit_buffs[p->xmit_count]->size = swab16(TBD_LAST | len);
+ if( (next_nop = p->xmit_count + 1) == NUM_XMIT_BUFFS )
+ next_nop = 0;
+
+ p->xmit_cmds[p->xmit_count]->cmd_status = 0;
+ /* linkpointer of xmit-command already points to next nop cmd */
+ p->nop_cmds[next_nop]->cmd_link = make16((p->nop_cmds[next_nop]));
+ p->nop_cmds[next_nop]->cmd_status = 0;
+
+ p->nop_cmds[p->xmit_count]->cmd_link = make16((p->xmit_cmds[p->xmit_count]));
+ p->xmit_count = next_nop;
+
+ {
+ unsigned long flags;
+ local_irq_save(flags);
+ if(p->xmit_count != p->xmit_last)
+ netif_wake_queue(dev);
+ p->lock = 0;
+ local_irq_restore(flags);
+ }
+ dev_kfree_skb(skb);
+#endif
+ }
+ return NETDEV_TX_OK;
+}
+
+/*******************************************
+ * Someone wanna have the statistics
+ */
+
+static struct net_device_stats *sun3_82586_get_stats(struct net_device *dev)
+{
+ struct priv *p = netdev_priv(dev);
+ unsigned short crc,aln,rsc,ovrn;
+
+ crc = swab16(p->scb->crc_errs); /* get error-statistic from the ni82586 */
+ p->scb->crc_errs = 0;
+ aln = swab16(p->scb->aln_errs);
+ p->scb->aln_errs = 0;
+ rsc = swab16(p->scb->rsc_errs);
+ p->scb->rsc_errs = 0;
+ ovrn = swab16(p->scb->ovrn_errs);
+ p->scb->ovrn_errs = 0;
+
+ dev->stats.rx_crc_errors += crc;
+ dev->stats.rx_fifo_errors += ovrn;
+ dev->stats.rx_frame_errors += aln;
+ dev->stats.rx_dropped += rsc;
+
+ return &dev->stats;
+}
+
+/********************************************************
+ * Set MC list ..
+ */
+
+static void set_multicast_list(struct net_device *dev)
+{
+ netif_stop_queue(dev);
+ sun3_disint();
+ alloc586(dev);
+ init586(dev);
+ startrecv586(dev);
+ sun3_enaint();
+ netif_wake_queue(dev);
+}
+
+#ifdef MODULE
+#error This code is not currently supported as a module
+static struct net_device *dev_sun3_82586;
+
+int init_module(void)
+{
+ dev_sun3_82586 = sun3_82586_probe(-1);
+ if (IS_ERR(dev_sun3_82586))
+ return PTR_ERR(dev_sun3_82586);
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ unsigned long ioaddr = dev_sun3_82586->base_addr;
+ unregister_netdev(dev_sun3_82586);
+ release_region(ioaddr, SUN3_82586_TOTAL_SIZE);
+ iounmap((void *)ioaddr);
+ free_netdev(dev_sun3_82586);
+}
+#endif /* MODULE */
+
+#if 0
+/*
+ * DUMP .. we expect a not running CMD unit and enough space
+ */
+void sun3_82586_dump(struct net_device *dev,void *ptr)
+{
+ struct priv *p = netdev_priv(dev);
+ struct dump_cmd_struct *dump_cmd = (struct dump_cmd_struct *) ptr;
+ int i;
+
+ p->scb->cmd_cuc = CUC_ABORT;
+ sun3_attn586();
+ WAIT_4_SCB_CMD();
+ WAIT_4_SCB_CMD_RUC();
+
+ dump_cmd->cmd_status = 0;
+ dump_cmd->cmd_cmd = CMD_DUMP | CMD_LAST;
+ dump_cmd->dump_offset = make16((dump_cmd + 1));
+ dump_cmd->cmd_link = 0xffff;
+
+ p->scb->cbl_offset = make16(dump_cmd);
+ p->scb->cmd_cuc = CUC_START;
+ sun3_attn586();
+ WAIT_4_STAT_COMPL(dump_cmd);
+
+ if( (dump_cmd->cmd_status & (STAT_COMPL|STAT_OK)) != (STAT_COMPL|STAT_OK) )
+ printk("%s: Can't get dump information.\n",dev->name);
+
+ for(i=0;i<170;i++) {
+ printk("%02x ",(int) ((unsigned char *) (dump_cmd + 1))[i]);
+ if(i % 24 == 23)
+ printk("\n");
+ }
+ printk("\n");
+}
+#endif
+
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * Intel i82586 Ethernet definitions
+ *
+ * This is an extension to the Linux operating system, and is covered by the
+ * same Gnu Public License that covers that work.
+ *
+ * copyrights (c) 1994 by Michael Hipp (hippm@informatik.uni-tuebingen.de)
+ *
+ * I have done a look in the following sources:
+ * crynwr-packet-driver by Russ Nelson
+ * Garret A. Wollman's i82586-driver for BSD
+ */
+
+/*
+ * Cloned from ni52.h, copyright as above.
+ *
+ * Modified for Sun3 OBIO i82586 by Sam Creasey (sammy@sammy.net)
+ */
+
+
+/* defines for the obio chip (not vme) */
+#define IEOB_NORSET 0x80 /* don't reset the board */
+#define IEOB_ONAIR 0x40 /* put us on the air */
+#define IEOB_ATTEN 0x20 /* attention! */
+#define IEOB_IENAB 0x10 /* interrupt enable */
+#define IEOB_XXXXX 0x08 /* free bit */
+#define IEOB_XCVRL2 0x04 /* level 2 transceiver? */
+#define IEOB_BUSERR 0x02 /* bus error */
+#define IEOB_INT 0x01 /* interrupt */
+
+/* where the obio one lives */
+#define IE_OBIO 0xc0000
+#define IE_IRQ 3
+
+/*
+ * where to find the System Configuration Pointer (SCP)
+ */
+#define SCP_DEFAULT_ADDRESS 0xfffff4
+
+
+/*
+ * System Configuration Pointer Struct
+ */
+
+struct scp_struct
+{
+ unsigned short zero_dum0; /* has to be zero */
+ unsigned char sysbus; /* 0=16Bit,1=8Bit */
+ unsigned char zero_dum1; /* has to be zero for 586 */
+ unsigned short zero_dum2;
+ unsigned short zero_dum3;
+ char *iscp; /* pointer to the iscp-block */
+};
+
+
+/*
+ * Intermediate System Configuration Pointer (ISCP)
+ */
+struct iscp_struct
+{
+ unsigned char busy; /* 586 clears after successful init */
+ unsigned char zero_dummy; /* has to be zero */
+ unsigned short scb_offset; /* pointeroffset to the scb_base */
+ char *scb_base; /* base-address of all 16-bit offsets */
+};
+
+/*
+ * System Control Block (SCB)
+ */
+struct scb_struct
+{
+ unsigned char rus;
+ unsigned char cus;
+ unsigned char cmd_ruc; /* command word: RU part */
+ unsigned char cmd_cuc; /* command word: CU part & ACK */
+ unsigned short cbl_offset; /* pointeroffset, command block list */
+ unsigned short rfa_offset; /* pointeroffset, receive frame area */
+ unsigned short crc_errs; /* CRC-Error counter */
+ unsigned short aln_errs; /* allignmenterror counter */
+ unsigned short rsc_errs; /* Resourceerror counter */
+ unsigned short ovrn_errs; /* OVerrunerror counter */
+};
+
+/*
+ * possible command values for the command word
+ */
+#define RUC_MASK 0x0070 /* mask for RU commands */
+#define RUC_NOP 0x0000 /* NOP-command */
+#define RUC_START 0x0010 /* start RU */
+#define RUC_RESUME 0x0020 /* resume RU after suspend */
+#define RUC_SUSPEND 0x0030 /* suspend RU */
+#define RUC_ABORT 0x0040 /* abort receiver operation immediately */
+
+#define CUC_MASK 0x07 /* mask for CU command */
+#define CUC_NOP 0x00 /* NOP-command */
+#define CUC_START 0x01 /* start execution of 1. cmd on the CBL */
+#define CUC_RESUME 0x02 /* resume after suspend */
+#define CUC_SUSPEND 0x03 /* Suspend CU */
+#define CUC_ABORT 0x04 /* abort command operation immediately */
+
+#define ACK_MASK 0xf0 /* mask for ACK command */
+#define ACK_CX 0x80 /* acknowledges STAT_CX */
+#define ACK_FR 0x40 /* ack. STAT_FR */
+#define ACK_CNA 0x20 /* ack. STAT_CNA */
+#define ACK_RNR 0x10 /* ack. STAT_RNR */
+
+/*
+ * possible status values for the status word
+ */
+#define STAT_MASK 0xf0 /* mask for cause of interrupt */
+#define STAT_CX 0x80 /* CU finished cmd with its I bit set */
+#define STAT_FR 0x40 /* RU finished receiving a frame */
+#define STAT_CNA 0x20 /* CU left active state */
+#define STAT_RNR 0x10 /* RU left ready state */
+
+#define CU_STATUS 0x7 /* CU status, 0=idle */
+#define CU_SUSPEND 0x1 /* CU is suspended */
+#define CU_ACTIVE 0x2 /* CU is active */
+
+#define RU_STATUS 0x70 /* RU status, 0=idle */
+#define RU_SUSPEND 0x10 /* RU suspended */
+#define RU_NOSPACE 0x20 /* RU no resources */
+#define RU_READY 0x40 /* RU is ready */
+
+/*
+ * Receive Frame Descriptor (RFD)
+ */
+struct rfd_struct
+{
+ unsigned char stat_low; /* status word */
+ unsigned char stat_high; /* status word */
+ unsigned char rfd_sf; /* 82596 mode only */
+ unsigned char last; /* Bit15,Last Frame on List / Bit14,suspend */
+ unsigned short next; /* linkoffset to next RFD */
+ unsigned short rbd_offset; /* pointeroffset to RBD-buffer */
+ unsigned char dest[6]; /* ethernet-address, destination */
+ unsigned char source[6]; /* ethernet-address, source */
+ unsigned short length; /* 802.3 frame-length */
+ unsigned short zero_dummy; /* dummy */
+};
+
+#define RFD_LAST 0x80 /* last: last rfd in the list */
+#define RFD_SUSP 0x40 /* last: suspend RU after */
+#define RFD_COMPL 0x80
+#define RFD_OK 0x20
+#define RFD_BUSY 0x40
+#define RFD_ERR_LEN 0x10 /* Length error (if enabled length-checking */
+#define RFD_ERR_CRC 0x08 /* CRC error */
+#define RFD_ERR_ALGN 0x04 /* Alignment error */
+#define RFD_ERR_RNR 0x02 /* status: receiver out of resources */
+#define RFD_ERR_OVR 0x01 /* DMA Overrun! */
+
+#define RFD_ERR_FTS 0x0080 /* Frame to short */
+#define RFD_ERR_NEOP 0x0040 /* No EOP flag (for bitstuffing only) */
+#define RFD_ERR_TRUN 0x0020 /* (82596 only/SF mode) indicates truncated frame */
+#define RFD_MATCHADD 0x0002 /* status: Destinationaddress !matches IA (only 82596) */
+#define RFD_COLLDET 0x0001 /* Detected collision during reception */
+
+/*
+ * Receive Buffer Descriptor (RBD)
+ */
+struct rbd_struct
+{
+ unsigned short status; /* status word,number of used bytes in buff */
+ unsigned short next; /* pointeroffset to next RBD */
+ char *buffer; /* receive buffer address pointer */
+ unsigned short size; /* size of this buffer */
+ unsigned short zero_dummy; /* dummy */
+};
+
+#define RBD_LAST 0x8000 /* last buffer */
+#define RBD_USED 0x4000 /* this buffer has data */
+#define RBD_MASK 0x3fff /* size-mask for length */
+
+/*
+ * Statusvalues for Commands/RFD
+ */
+#define STAT_COMPL 0x8000 /* status: frame/command is complete */
+#define STAT_BUSY 0x4000 /* status: frame/command is busy */
+#define STAT_OK 0x2000 /* status: frame/command is ok */
+
+/*
+ * Action-Commands
+ */
+#define CMD_NOP 0x0000 /* NOP */
+#define CMD_IASETUP 0x0001 /* initial address setup command */
+#define CMD_CONFIGURE 0x0002 /* configure command */
+#define CMD_MCSETUP 0x0003 /* MC setup command */
+#define CMD_XMIT 0x0004 /* transmit command */
+#define CMD_TDR 0x0005 /* time domain reflectometer (TDR) command */
+#define CMD_DUMP 0x0006 /* dump command */
+#define CMD_DIAGNOSE 0x0007 /* diagnose command */
+
+/*
+ * Action command bits
+ */
+#define CMD_LAST 0x8000 /* indicates last command in the CBL */
+#define CMD_SUSPEND 0x4000 /* suspend CU after this CB */
+#define CMD_INT 0x2000 /* generate interrupt after execution */
+
+/*
+ * NOP - command
+ */
+struct nop_cmd_struct
+{
+ unsigned short cmd_status; /* status of this command */
+ unsigned short cmd_cmd; /* the command itself (+bits) */
+ unsigned short cmd_link; /* offsetpointer to next command */
+};
+
+/*
+ * IA Setup command
+ */
+struct iasetup_cmd_struct
+{
+ unsigned short cmd_status;
+ unsigned short cmd_cmd;
+ unsigned short cmd_link;
+ unsigned char iaddr[6];
+};
+
+/*
+ * Configure command
+ */
+struct configure_cmd_struct
+{
+ unsigned short cmd_status;
+ unsigned short cmd_cmd;
+ unsigned short cmd_link;
+ unsigned char byte_cnt; /* size of the config-cmd */
+ unsigned char fifo; /* fifo/recv monitor */
+ unsigned char sav_bf; /* save bad frames (bit7=1)*/
+ unsigned char adr_len; /* adr_len(0-2),al_loc(3),pream(4-5),loopbak(6-7)*/
+ unsigned char priority; /* lin_prio(0-2),exp_prio(4-6),bof_metd(7) */
+ unsigned char ifs; /* inter frame spacing */
+ unsigned char time_low; /* slot time low */
+ unsigned char time_high; /* slot time high(0-2) and max. retries(4-7) */
+ unsigned char promisc; /* promisc-mode(0) , et al (1-7) */
+ unsigned char carr_coll; /* carrier(0-3)/collision(4-7) stuff */
+ unsigned char fram_len; /* minimal frame len */
+ unsigned char dummy; /* dummy */
+};
+
+/*
+ * Multicast Setup command
+ */
+struct mcsetup_cmd_struct
+{
+ unsigned short cmd_status;
+ unsigned short cmd_cmd;
+ unsigned short cmd_link;
+ unsigned short mc_cnt; /* number of bytes in the MC-List */
+ unsigned char mc_list[0][6]; /* pointer to 6 bytes entries */
+};
+
+/*
+ * DUMP command
+ */
+struct dump_cmd_struct
+{
+ unsigned short cmd_status;
+ unsigned short cmd_cmd;
+ unsigned short cmd_link;
+ unsigned short dump_offset; /* pointeroffset to DUMP space */
+};
+
+/*
+ * transmit command
+ */
+struct transmit_cmd_struct
+{
+ unsigned short cmd_status;
+ unsigned short cmd_cmd;
+ unsigned short cmd_link;
+ unsigned short tbd_offset; /* pointeroffset to TBD */
+ unsigned char dest[6]; /* destination address of the frame */
+ unsigned short length; /* user defined: 802.3 length / Ether type */
+};
+
+#define TCMD_ERRMASK 0x0fa0
+#define TCMD_MAXCOLLMASK 0x000f
+#define TCMD_MAXCOLL 0x0020
+#define TCMD_HEARTBEAT 0x0040
+#define TCMD_DEFERRED 0x0080
+#define TCMD_UNDERRUN 0x0100
+#define TCMD_LOSTCTS 0x0200
+#define TCMD_NOCARRIER 0x0400
+#define TCMD_LATECOLL 0x0800
+
+struct tdr_cmd_struct
+{
+ unsigned short cmd_status;
+ unsigned short cmd_cmd;
+ unsigned short cmd_link;
+ unsigned short status;
+};
+
+#define TDR_LNK_OK 0x8000 /* No link problem identified */
+#define TDR_XCVR_PRB 0x4000 /* indicates a transceiver problem */
+#define TDR_ET_OPN 0x2000 /* open, no correct termination */
+#define TDR_ET_SRT 0x1000 /* TDR detected a short circuit */
+#define TDR_TIMEMASK 0x07ff /* mask for the time field */
+
+/*
+ * Transmit Buffer Descriptor (TBD)
+ */
+struct tbd_struct
+{
+ unsigned short size; /* size + EOF-Flag(15) */
+ unsigned short next; /* pointeroffset to next TBD */
+ char *buffer; /* pointer to buffer */
+};
+
+#define TBD_LAST 0x8000 /* EOF-Flag, indicates last buffer in list */
+
+
+
+
--- /dev/null
+/* znet.c: An Zenith Z-Note ethernet driver for linux. */
+
+/*
+ Written by Donald Becker.
+
+ The author may be reached as becker@scyld.com.
+ This driver is based on the Linux skeleton driver. The copyright of the
+ skeleton driver is held by the United States Government, as represented
+ by DIRNSA, and it is released under the GPL.
+
+ Thanks to Mike Hollick for alpha testing and suggestions.
+
+ References:
+ The Crynwr packet driver.
+
+ "82593 CSMA/CD Core LAN Controller" Intel datasheet, 1992
+ Intel Microcommunications Databook, Vol. 1, 1990.
+ As usual with Intel, the documentation is incomplete and inaccurate.
+ I had to read the Crynwr packet driver to figure out how to actually
+ use the i82593, and guess at what register bits matched the loosely
+ related i82586.
+
+ Theory of Operation
+
+ The i82593 used in the Zenith Z-Note series operates using two(!) slave
+ DMA channels, one interrupt, and one 8-bit I/O port.
+
+ While there several ways to configure '593 DMA system, I chose the one
+ that seemed commensurate with the highest system performance in the face
+ of moderate interrupt latency: Both DMA channels are configured as
+ recirculating ring buffers, with one channel (#0) dedicated to Rx and
+ the other channel (#1) to Tx and configuration. (Note that this is
+ different than the Crynwr driver, where the Tx DMA channel is initialized
+ before each operation. That approach simplifies operation and Tx error
+ recovery, but requires additional I/O in normal operation and precludes
+ transmit buffer chaining.)
+
+ Both rings are set to 8192 bytes using {TX,RX}_RING_SIZE. This provides
+ a reasonable ring size for Rx, while simplifying DMA buffer allocation --
+ DMA buffers must not cross a 128K boundary. (In truth the size selection
+ was influenced by my lack of '593 documentation. I thus was constrained
+ to use the Crynwr '593 initialization table, which sets the Rx ring size
+ to 8K.)
+
+ Despite my usual low opinion about Intel-designed parts, I must admit
+ that the bulk data handling of the i82593 is a good design for
+ an integrated system, like a laptop, where using two slave DMA channels
+ doesn't pose a problem. I still take issue with using only a single I/O
+ port. In the same controlled environment there are essentially no
+ limitations on I/O space, and using multiple locations would eliminate
+ the need for multiple operations when looking at status registers,
+ setting the Rx ring boundary, or switching to promiscuous mode.
+
+ I also question Zenith's selection of the '593: one of the advertised
+ advantages of earlier Intel parts was that if you figured out the magic
+ initialization incantation you could use the same part on many different
+ network types. Zenith's use of the "FriendlyNet" (sic) connector rather
+ than an on-board transceiver leads me to believe that they were planning
+ to take advantage of this. But, uhmmm, the '593 omits all but ethernet
+ functionality from the serial subsystem.
+ */
+
+/* 10/2002
+
+ o Resurected for Linux 2.5+ by Marc Zyngier <maz@wild-wind.fr.eu.org> :
+
+ - Removed strange DMA snooping in znet_sent_packet, which lead to
+ TX buffer corruption on my laptop.
+ - Use init_etherdev stuff.
+ - Use kmalloc-ed DMA buffers.
+ - Use as few global variables as possible.
+ - Use proper resources management.
+ - Use wireless/i82593.h as much as possible (structure, constants)
+ - Compiles as module or build-in.
+ - Now survives unplugging/replugging cable.
+
+ Some code was taken from wavelan_cs.
+
+ Tested on a vintage Zenith Z-Note 433Lnp+. Probably broken on
+ anything else. Testers (and detailed bug reports) are welcome :-).
+
+ o TODO :
+
+ - Properly handle multicast
+ - Understand why some traffic patterns add a 1s latency...
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/bitops.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#include <linux/i82593.h>
+
+static char version[] __initdata = "znet.c:v1.02 9/23/94 becker@scyld.com\n";
+
+#ifndef ZNET_DEBUG
+#define ZNET_DEBUG 1
+#endif
+static unsigned int znet_debug = ZNET_DEBUG;
+module_param (znet_debug, int, 0);
+MODULE_PARM_DESC (znet_debug, "ZNet debug level");
+MODULE_LICENSE("GPL");
+
+/* The DMA modes we need aren't in <dma.h>. */
+#define DMA_RX_MODE 0x14 /* Auto init, I/O to mem, ++, demand. */
+#define DMA_TX_MODE 0x18 /* Auto init, Mem to I/O, ++, demand. */
+#define dma_page_eq(ptr1, ptr2) ((long)(ptr1)>>17 == (long)(ptr2)>>17)
+#define RX_BUF_SIZE 8192
+#define TX_BUF_SIZE 8192
+#define DMA_BUF_SIZE (RX_BUF_SIZE + 16) /* 8k + 16 bytes for trailers */
+
+#define TX_TIMEOUT (HZ/10)
+
+struct znet_private {
+ int rx_dma, tx_dma;
+ spinlock_t lock;
+ short sia_base, sia_size, io_size;
+ struct i82593_conf_block i593_init;
+ /* The starting, current, and end pointers for the packet buffers. */
+ ushort *rx_start, *rx_cur, *rx_end;
+ ushort *tx_start, *tx_cur, *tx_end;
+ ushort tx_buf_len; /* Tx buffer length, in words. */
+};
+
+/* Only one can be built-in;-> */
+static struct net_device *znet_dev;
+
+struct netidblk {
+ char magic[8]; /* The magic number (string) "NETIDBLK" */
+ unsigned char netid[8]; /* The physical station address */
+ char nettype, globalopt;
+ char vendor[8]; /* The machine vendor and product name. */
+ char product[8];
+ char irq1, irq2; /* Interrupts, only one is currently used. */
+ char dma1, dma2;
+ short dma_mem_misc[8]; /* DMA buffer locations (unused in Linux). */
+ short iobase1, iosize1;
+ short iobase2, iosize2; /* Second iobase unused. */
+ char driver_options; /* Misc. bits */
+ char pad;
+};
+
+static int znet_open(struct net_device *dev);
+static netdev_tx_t znet_send_packet(struct sk_buff *skb,
+ struct net_device *dev);
+static irqreturn_t znet_interrupt(int irq, void *dev_id);
+static void znet_rx(struct net_device *dev);
+static int znet_close(struct net_device *dev);
+static void hardware_init(struct net_device *dev);
+static void update_stop_hit(short ioaddr, unsigned short rx_stop_offset);
+static void znet_tx_timeout (struct net_device *dev);
+
+/* Request needed resources */
+static int znet_request_resources (struct net_device *dev)
+{
+ struct znet_private *znet = netdev_priv(dev);
+
+ if (request_irq (dev->irq, znet_interrupt, 0, "ZNet", dev))
+ goto failed;
+ if (request_dma (znet->rx_dma, "ZNet rx"))
+ goto free_irq;
+ if (request_dma (znet->tx_dma, "ZNet tx"))
+ goto free_rx_dma;
+ if (!request_region (znet->sia_base, znet->sia_size, "ZNet SIA"))
+ goto free_tx_dma;
+ if (!request_region (dev->base_addr, znet->io_size, "ZNet I/O"))
+ goto free_sia;
+
+ return 0; /* Happy ! */
+
+ free_sia:
+ release_region (znet->sia_base, znet->sia_size);
+ free_tx_dma:
+ free_dma (znet->tx_dma);
+ free_rx_dma:
+ free_dma (znet->rx_dma);
+ free_irq:
+ free_irq (dev->irq, dev);
+ failed:
+ return -1;
+}
+
+static void znet_release_resources (struct net_device *dev)
+{
+ struct znet_private *znet = netdev_priv(dev);
+
+ release_region (znet->sia_base, znet->sia_size);
+ release_region (dev->base_addr, znet->io_size);
+ free_dma (znet->tx_dma);
+ free_dma (znet->rx_dma);
+ free_irq (dev->irq, dev);
+}
+
+/* Keep the magical SIA stuff in a single function... */
+static void znet_transceiver_power (struct net_device *dev, int on)
+{
+ struct znet_private *znet = netdev_priv(dev);
+ unsigned char v;
+
+ /* Turn on/off the 82501 SIA, using zenith-specific magic. */
+ /* Select LAN control register */
+ outb(0x10, znet->sia_base);
+
+ if (on)
+ v = inb(znet->sia_base + 1) | 0x84;
+ else
+ v = inb(znet->sia_base + 1) & ~0x84;
+
+ outb(v, znet->sia_base+1); /* Turn on/off LAN power (bit 2). */
+}
+
+/* Init the i82593, with current promisc/mcast configuration.
+ Also used from hardware_init. */
+static void znet_set_multicast_list (struct net_device *dev)
+{
+ struct znet_private *znet = netdev_priv(dev);
+ short ioaddr = dev->base_addr;
+ struct i82593_conf_block *cfblk = &znet->i593_init;
+
+ memset(cfblk, 0x00, sizeof(struct i82593_conf_block));
+
+ /* The configuration block. What an undocumented nightmare.
+ The first set of values are those suggested (without explanation)
+ for ethernet in the Intel 82586 databook. The rest appear to be
+ completely undocumented, except for cryptic notes in the Crynwr
+ packet driver. This driver uses the Crynwr values verbatim. */
+
+ /* maz : Rewritten to take advantage of the wanvelan includes.
+ At least we have names, not just blind values */
+
+ /* Byte 0 */
+ cfblk->fifo_limit = 10; /* = 16 B rx and 80 B tx fifo thresholds */
+ cfblk->forgnesi = 0; /* 0=82C501, 1=AMD7992B compatibility */
+ cfblk->fifo_32 = 1;
+ cfblk->d6mod = 0; /* Run in i82593 advanced mode */
+ cfblk->throttle_enb = 1;
+
+ /* Byte 1 */
+ cfblk->throttle = 8; /* Continuous w/interrupts, 128-clock DMA. */
+ cfblk->cntrxint = 0; /* enable continuous mode receive interrupts */
+ cfblk->contin = 1; /* enable continuous mode */
+
+ /* Byte 2 */
+ cfblk->addr_len = ETH_ALEN;
+ cfblk->acloc = 1; /* Disable source addr insertion by i82593 */
+ cfblk->preamb_len = 2; /* 8 bytes preamble */
+ cfblk->loopback = 0; /* Loopback off */
+
+ /* Byte 3 */
+ cfblk->lin_prio = 0; /* Default priorities & backoff methods. */
+ cfblk->tbofstop = 0;
+ cfblk->exp_prio = 0;
+ cfblk->bof_met = 0;
+
+ /* Byte 4 */
+ cfblk->ifrm_spc = 6; /* 96 bit times interframe spacing */
+
+ /* Byte 5 */
+ cfblk->slottim_low = 0; /* 512 bit times slot time (low) */
+
+ /* Byte 6 */
+ cfblk->slottim_hi = 2; /* 512 bit times slot time (high) */
+ cfblk->max_retr = 15; /* 15 collisions retries */
+
+ /* Byte 7 */
+ cfblk->prmisc = ((dev->flags & IFF_PROMISC) ? 1 : 0); /* Promiscuous mode */
+ cfblk->bc_dis = 0; /* Enable broadcast reception */
+ cfblk->crs_1 = 0; /* Don't transmit without carrier sense */
+ cfblk->nocrc_ins = 0; /* i82593 generates CRC */
+ cfblk->crc_1632 = 0; /* 32-bit Autodin-II CRC */
+ cfblk->crs_cdt = 0; /* CD not to be interpreted as CS */
+
+ /* Byte 8 */
+ cfblk->cs_filter = 0; /* CS is recognized immediately */
+ cfblk->crs_src = 0; /* External carrier sense */
+ cfblk->cd_filter = 0; /* CD is recognized immediately */
+
+ /* Byte 9 */
+ cfblk->min_fr_len = ETH_ZLEN >> 2; /* Minimum frame length */
+
+ /* Byte A */
+ cfblk->lng_typ = 1; /* Type/length checks OFF */
+ cfblk->lng_fld = 1; /* Disable 802.3 length field check */
+ cfblk->rxcrc_xf = 1; /* Don't transfer CRC to memory */
+ cfblk->artx = 1; /* Disable automatic retransmission */
+ cfblk->sarec = 1; /* Disable source addr trig of CD */
+ cfblk->tx_jabber = 0; /* Disable jabber jam sequence */
+ cfblk->hash_1 = 1; /* Use bits 0-5 in mc address hash */
+ cfblk->lbpkpol = 0; /* Loopback pin active high */
+
+ /* Byte B */
+ cfblk->fdx = 0; /* Disable full duplex operation */
+
+ /* Byte C */
+ cfblk->dummy_6 = 0x3f; /* all ones, Default multicast addresses & backoff. */
+ cfblk->mult_ia = 0; /* No multiple individual addresses */
+ cfblk->dis_bof = 0; /* Disable the backoff algorithm ?! */
+
+ /* Byte D */
+ cfblk->dummy_1 = 1; /* set to 1 */
+ cfblk->tx_ifs_retrig = 3; /* Hmm... Disabled */
+ cfblk->mc_all = (!netdev_mc_empty(dev) ||
+ (dev->flags & IFF_ALLMULTI)); /* multicast all mode */
+ cfblk->rcv_mon = 0; /* Monitor mode disabled */
+ cfblk->frag_acpt = 0; /* Do not accept fragments */
+ cfblk->tstrttrs = 0; /* No start transmission threshold */
+
+ /* Byte E */
+ cfblk->fretx = 1; /* FIFO automatic retransmission */
+ cfblk->runt_eop = 0; /* drop "runt" packets */
+ cfblk->hw_sw_pin = 0; /* ?? */
+ cfblk->big_endn = 0; /* Big Endian ? no... */
+ cfblk->syncrqs = 1; /* Synchronous DRQ deassertion... */
+ cfblk->sttlen = 1; /* 6 byte status registers */
+ cfblk->rx_eop = 0; /* Signal EOP on packet reception */
+ cfblk->tx_eop = 0; /* Signal EOP on packet transmission */
+
+ /* Byte F */
+ cfblk->rbuf_size = RX_BUF_SIZE >> 12; /* Set receive buffer size */
+ cfblk->rcvstop = 1; /* Enable Receive Stop Register */
+
+ if (znet_debug > 2) {
+ int i;
+ unsigned char *c;
+
+ for (i = 0, c = (char *) cfblk; i < sizeof (*cfblk); i++)
+ printk ("%02X ", c[i]);
+ printk ("\n");
+ }
+
+ *znet->tx_cur++ = sizeof(struct i82593_conf_block);
+ memcpy(znet->tx_cur, cfblk, sizeof(struct i82593_conf_block));
+ znet->tx_cur += sizeof(struct i82593_conf_block)/2;
+ outb(OP0_CONFIGURE | CR0_CHNL, ioaddr);
+
+ /* XXX FIXME maz : Add multicast addresses here, so having a
+ * multicast address configured isn't equal to IFF_ALLMULTI */
+}
+
+static const struct net_device_ops znet_netdev_ops = {
+ .ndo_open = znet_open,
+ .ndo_stop = znet_close,
+ .ndo_start_xmit = znet_send_packet,
+ .ndo_set_multicast_list = znet_set_multicast_list,
+ .ndo_tx_timeout = znet_tx_timeout,
+ .ndo_change_mtu = eth_change_mtu,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+};
+
+/* The Z-Note probe is pretty easy. The NETIDBLK exists in the safe-to-probe
+ BIOS area. We just scan for the signature, and pull the vital parameters
+ out of the structure. */
+
+static int __init znet_probe (void)
+{
+ int i;
+ struct netidblk *netinfo;
+ struct znet_private *znet;
+ struct net_device *dev;
+ char *p;
+ int err = -ENOMEM;
+
+ /* This code scans the region 0xf0000 to 0xfffff for a "NETIDBLK". */
+ for(p = (char *)phys_to_virt(0xf0000); p < (char *)phys_to_virt(0x100000); p++)
+ if (*p == 'N' && strncmp(p, "NETIDBLK", 8) == 0)
+ break;
+
+ if (p >= (char *)phys_to_virt(0x100000)) {
+ if (znet_debug > 1)
+ printk(KERN_INFO "No Z-Note ethernet adaptor found.\n");
+ return -ENODEV;
+ }
+
+ dev = alloc_etherdev(sizeof(struct znet_private));
+ if (!dev)
+ return -ENOMEM;
+
+ znet = netdev_priv(dev);
+
+ netinfo = (struct netidblk *)p;
+ dev->base_addr = netinfo->iobase1;
+ dev->irq = netinfo->irq1;
+
+ /* The station address is in the "netidblk" at 0x0f0000. */
+ for (i = 0; i < 6; i++)
+ dev->dev_addr[i] = netinfo->netid[i];
+
+ printk(KERN_INFO "%s: ZNET at %#3lx, %pM"
+ ", using IRQ %d DMA %d and %d.\n",
+ dev->name, dev->base_addr, dev->dev_addr,
+ dev->irq, netinfo->dma1, netinfo->dma2);
+
+ if (znet_debug > 1) {
+ printk(KERN_INFO "%s: vendor '%16.16s' IRQ1 %d IRQ2 %d DMA1 %d DMA2 %d.\n",
+ dev->name, netinfo->vendor,
+ netinfo->irq1, netinfo->irq2,
+ netinfo->dma1, netinfo->dma2);
+ printk(KERN_INFO "%s: iobase1 %#x size %d iobase2 %#x size %d net type %2.2x.\n",
+ dev->name, netinfo->iobase1, netinfo->iosize1,
+ netinfo->iobase2, netinfo->iosize2, netinfo->nettype);
+ }
+
+ if (znet_debug > 0)
+ printk(KERN_INFO "%s", version);
+
+ znet->rx_dma = netinfo->dma1;
+ znet->tx_dma = netinfo->dma2;
+ spin_lock_init(&znet->lock);
+ znet->sia_base = 0xe6; /* Magic address for the 82501 SIA */
+ znet->sia_size = 2;
+ /* maz: Despite the '593 being advertised above as using a
+ * single 8bits I/O port, this driver does many 16bits
+ * access. So set io_size accordingly */
+ znet->io_size = 2;
+
+ if (!(znet->rx_start = kmalloc (DMA_BUF_SIZE, GFP_KERNEL | GFP_DMA)))
+ goto free_dev;
+ if (!(znet->tx_start = kmalloc (DMA_BUF_SIZE, GFP_KERNEL | GFP_DMA)))
+ goto free_rx;
+
+ if (!dma_page_eq (znet->rx_start, znet->rx_start + (RX_BUF_SIZE/2-1)) ||
+ !dma_page_eq (znet->tx_start, znet->tx_start + (TX_BUF_SIZE/2-1))) {
+ printk (KERN_WARNING "tx/rx crossing DMA frontiers, giving up\n");
+ goto free_tx;
+ }
+
+ znet->rx_end = znet->rx_start + RX_BUF_SIZE/2;
+ znet->tx_buf_len = TX_BUF_SIZE/2;
+ znet->tx_end = znet->tx_start + znet->tx_buf_len;
+
+ /* The ZNET-specific entries in the device structure. */
+ dev->netdev_ops = &znet_netdev_ops;
+ dev->watchdog_timeo = TX_TIMEOUT;
+ err = register_netdev(dev);
+ if (err)
+ goto free_tx;
+ znet_dev = dev;
+ return 0;
+
+ free_tx:
+ kfree(znet->tx_start);
+ free_rx:
+ kfree(znet->rx_start);
+ free_dev:
+ free_netdev(dev);
+ return err;
+}
+
+
+static int znet_open(struct net_device *dev)
+{
+ int ioaddr = dev->base_addr;
+
+ if (znet_debug > 2)
+ printk(KERN_DEBUG "%s: znet_open() called.\n", dev->name);
+
+ /* These should never fail. You can't add devices to a sealed box! */
+ if (znet_request_resources (dev)) {
+ printk(KERN_WARNING "%s: Not opened -- resource busy?!?\n", dev->name);
+ return -EBUSY;
+ }
+
+ znet_transceiver_power (dev, 1);
+
+ /* According to the Crynwr driver we should wait 50 msec. for the
+ LAN clock to stabilize. My experiments indicates that the '593 can
+ be initialized immediately. The delay is probably needed for the
+ DC-to-DC converter to come up to full voltage, and for the oscillator
+ to be spot-on at 20Mhz before transmitting.
+ Until this proves to be a problem we rely on the higher layers for the
+ delay and save allocating a timer entry. */
+
+ /* maz : Well, I'm getting every time the following message
+ * without the delay on a 486@33. This machine is much too
+ * fast... :-) So maybe the Crynwr driver wasn't wrong after
+ * all, even if the message is completly harmless on my
+ * setup. */
+ mdelay (50);
+
+ /* This follows the packet driver's lead, and checks for success. */
+ if (inb(ioaddr) != 0x10 && inb(ioaddr) != 0x00)
+ printk(KERN_WARNING "%s: Problem turning on the transceiver power.\n",
+ dev->name);
+
+ hardware_init(dev);
+ netif_start_queue (dev);
+
+ return 0;
+}
+
+
+static void znet_tx_timeout (struct net_device *dev)
+{
+ int ioaddr = dev->base_addr;
+ ushort event, tx_status, rx_offset, state;
+
+ outb (CR0_STATUS_0, ioaddr);
+ event = inb (ioaddr);
+ outb (CR0_STATUS_1, ioaddr);
+ tx_status = inw (ioaddr);
+ outb (CR0_STATUS_2, ioaddr);
+ rx_offset = inw (ioaddr);
+ outb (CR0_STATUS_3, ioaddr);
+ state = inb (ioaddr);
+ printk (KERN_WARNING "%s: transmit timed out, status %02x %04x %04x %02x,"
+ " resetting.\n", dev->name, event, tx_status, rx_offset, state);
+ if (tx_status == TX_LOST_CRS)
+ printk (KERN_WARNING "%s: Tx carrier error, check transceiver cable.\n",
+ dev->name);
+ outb (OP0_RESET, ioaddr);
+ hardware_init (dev);
+ netif_wake_queue (dev);
+}
+
+static netdev_tx_t znet_send_packet(struct sk_buff *skb, struct net_device *dev)
+{
+ int ioaddr = dev->base_addr;
+ struct znet_private *znet = netdev_priv(dev);
+ unsigned long flags;
+ short length = skb->len;
+
+ if (znet_debug > 4)
+ printk(KERN_DEBUG "%s: ZNet_send_packet.\n", dev->name);
+
+ if (length < ETH_ZLEN) {
+ if (skb_padto(skb, ETH_ZLEN))
+ return NETDEV_TX_OK;
+ length = ETH_ZLEN;
+ }
+
+ netif_stop_queue (dev);
+
+ /* Check that the part hasn't reset itself, probably from suspend. */
+ outb(CR0_STATUS_0, ioaddr);
+ if (inw(ioaddr) == 0x0010 &&
+ inw(ioaddr) == 0x0000 &&
+ inw(ioaddr) == 0x0010) {
+ if (znet_debug > 1)
+ printk (KERN_WARNING "%s : waking up\n", dev->name);
+ hardware_init(dev);
+ znet_transceiver_power (dev, 1);
+ }
+
+ if (1) {
+ unsigned char *buf = (void *)skb->data;
+ ushort *tx_link = znet->tx_cur - 1;
+ ushort rnd_len = (length + 1)>>1;
+
+ dev->stats.tx_bytes+=length;
+
+ if (znet->tx_cur >= znet->tx_end)
+ znet->tx_cur = znet->tx_start;
+ *znet->tx_cur++ = length;
+ if (znet->tx_cur + rnd_len + 1 > znet->tx_end) {
+ int semi_cnt = (znet->tx_end - znet->tx_cur)<<1; /* Cvrt to byte cnt. */
+ memcpy(znet->tx_cur, buf, semi_cnt);
+ rnd_len -= semi_cnt>>1;
+ memcpy(znet->tx_start, buf + semi_cnt, length - semi_cnt);
+ znet->tx_cur = znet->tx_start + rnd_len;
+ } else {
+ memcpy(znet->tx_cur, buf, skb->len);
+ znet->tx_cur += rnd_len;
+ }
+ *znet->tx_cur++ = 0;
+
+ spin_lock_irqsave(&znet->lock, flags);
+ {
+ *tx_link = OP0_TRANSMIT | CR0_CHNL;
+ /* Is this always safe to do? */
+ outb(OP0_TRANSMIT | CR0_CHNL, ioaddr);
+ }
+ spin_unlock_irqrestore (&znet->lock, flags);
+
+ netif_start_queue (dev);
+
+ if (znet_debug > 4)
+ printk(KERN_DEBUG "%s: Transmitter queued, length %d.\n", dev->name, length);
+ }
+ dev_kfree_skb(skb);
+ return NETDEV_TX_OK;
+}
+
+/* The ZNET interrupt handler. */
+static irqreturn_t znet_interrupt(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct znet_private *znet = netdev_priv(dev);
+ int ioaddr;
+ int boguscnt = 20;
+ int handled = 0;
+
+ spin_lock (&znet->lock);
+
+ ioaddr = dev->base_addr;
+
+ outb(CR0_STATUS_0, ioaddr);
+ do {
+ ushort status = inb(ioaddr);
+ if (znet_debug > 5) {
+ ushort result, rx_ptr, running;
+ outb(CR0_STATUS_1, ioaddr);
+ result = inw(ioaddr);
+ outb(CR0_STATUS_2, ioaddr);
+ rx_ptr = inw(ioaddr);
+ outb(CR0_STATUS_3, ioaddr);
+ running = inb(ioaddr);
+ printk(KERN_DEBUG "%s: interrupt, status %02x, %04x %04x %02x serial %d.\n",
+ dev->name, status, result, rx_ptr, running, boguscnt);
+ }
+ if ((status & SR0_INTERRUPT) == 0)
+ break;
+
+ handled = 1;
+
+ if ((status & SR0_EVENT_MASK) == SR0_TRANSMIT_DONE ||
+ (status & SR0_EVENT_MASK) == SR0_RETRANSMIT_DONE ||
+ (status & SR0_EVENT_MASK) == SR0_TRANSMIT_NO_CRC_DONE) {
+ int tx_status;
+ outb(CR0_STATUS_1, ioaddr);
+ tx_status = inw(ioaddr);
+ /* It's undocumented, but tx_status seems to match the i82586. */
+ if (tx_status & TX_OK) {
+ dev->stats.tx_packets++;
+ dev->stats.collisions += tx_status & TX_NCOL_MASK;
+ } else {
+ if (tx_status & (TX_LOST_CTS | TX_LOST_CRS))
+ dev->stats.tx_carrier_errors++;
+ if (tx_status & TX_UND_RUN)
+ dev->stats.tx_fifo_errors++;
+ if (!(tx_status & TX_HRT_BEAT))
+ dev->stats.tx_heartbeat_errors++;
+ if (tx_status & TX_MAX_COL)
+ dev->stats.tx_aborted_errors++;
+ /* ...and the catch-all. */
+ if ((tx_status | (TX_LOST_CRS | TX_LOST_CTS | TX_UND_RUN | TX_HRT_BEAT | TX_MAX_COL)) != (TX_LOST_CRS | TX_LOST_CTS | TX_UND_RUN | TX_HRT_BEAT | TX_MAX_COL))
+ dev->stats.tx_errors++;
+
+ /* Transceiver may be stuck if cable
+ * was removed while emitting a
+ * packet. Flip it off, then on to
+ * reset it. This is very empirical,
+ * but it seems to work. */
+
+ znet_transceiver_power (dev, 0);
+ znet_transceiver_power (dev, 1);
+ }
+ netif_wake_queue (dev);
+ }
+
+ if ((status & SR0_RECEPTION) ||
+ (status & SR0_EVENT_MASK) == SR0_STOP_REG_HIT) {
+ znet_rx(dev);
+ }
+ /* Clear the interrupts we've handled. */
+ outb(CR0_INT_ACK, ioaddr);
+ } while (boguscnt--);
+
+ spin_unlock (&znet->lock);
+
+ return IRQ_RETVAL(handled);
+}
+
+static void znet_rx(struct net_device *dev)
+{
+ struct znet_private *znet = netdev_priv(dev);
+ int ioaddr = dev->base_addr;
+ int boguscount = 1;
+ short next_frame_end_offset = 0; /* Offset of next frame start. */
+ short *cur_frame_end;
+ short cur_frame_end_offset;
+
+ outb(CR0_STATUS_2, ioaddr);
+ cur_frame_end_offset = inw(ioaddr);
+
+ if (cur_frame_end_offset == znet->rx_cur - znet->rx_start) {
+ printk(KERN_WARNING "%s: Interrupted, but nothing to receive, offset %03x.\n",
+ dev->name, cur_frame_end_offset);
+ return;
+ }
+
+ /* Use same method as the Crynwr driver: construct a forward list in
+ the same area of the backwards links we now have. This allows us to
+ pass packets to the upper layers in the order they were received --
+ important for fast-path sequential operations. */
+ while (znet->rx_start + cur_frame_end_offset != znet->rx_cur &&
+ ++boguscount < 5) {
+ unsigned short hi_cnt, lo_cnt, hi_status, lo_status;
+ int count, status;
+
+ if (cur_frame_end_offset < 4) {
+ /* Oh no, we have a special case: the frame trailer wraps around
+ the end of the ring buffer. We've saved space at the end of
+ the ring buffer for just this problem. */
+ memcpy(znet->rx_end, znet->rx_start, 8);
+ cur_frame_end_offset += (RX_BUF_SIZE/2);
+ }
+ cur_frame_end = znet->rx_start + cur_frame_end_offset - 4;
+
+ lo_status = *cur_frame_end++;
+ hi_status = *cur_frame_end++;
+ status = ((hi_status & 0xff) << 8) + (lo_status & 0xff);
+ lo_cnt = *cur_frame_end++;
+ hi_cnt = *cur_frame_end++;
+ count = ((hi_cnt & 0xff) << 8) + (lo_cnt & 0xff);
+
+ if (znet_debug > 5)
+ printk(KERN_DEBUG "Constructing trailer at location %03x, %04x %04x %04x %04x"
+ " count %#x status %04x.\n",
+ cur_frame_end_offset<<1, lo_status, hi_status, lo_cnt, hi_cnt,
+ count, status);
+ cur_frame_end[-4] = status;
+ cur_frame_end[-3] = next_frame_end_offset;
+ cur_frame_end[-2] = count;
+ next_frame_end_offset = cur_frame_end_offset;
+ cur_frame_end_offset -= ((count + 1)>>1) + 3;
+ if (cur_frame_end_offset < 0)
+ cur_frame_end_offset += RX_BUF_SIZE/2;
+ }
+
+ /* Now step forward through the list. */
+ do {
+ ushort *this_rfp_ptr = znet->rx_start + next_frame_end_offset;
+ int status = this_rfp_ptr[-4];
+ int pkt_len = this_rfp_ptr[-2];
+
+ if (znet_debug > 5)
+ printk(KERN_DEBUG "Looking at trailer ending at %04x status %04x length %03x"
+ " next %04x.\n", next_frame_end_offset<<1, status, pkt_len,
+ this_rfp_ptr[-3]<<1);
+ /* Once again we must assume that the i82586 docs apply. */
+ if ( ! (status & RX_RCV_OK)) { /* There was an error. */
+ dev->stats.rx_errors++;
+ if (status & RX_CRC_ERR) dev->stats.rx_crc_errors++;
+ if (status & RX_ALG_ERR) dev->stats.rx_frame_errors++;
+#if 0
+ if (status & 0x0200) dev->stats.rx_over_errors++; /* Wrong. */
+ if (status & 0x0100) dev->stats.rx_fifo_errors++;
+#else
+ /* maz : Wild guess... */
+ if (status & RX_OVRRUN) dev->stats.rx_over_errors++;
+#endif
+ if (status & RX_SRT_FRM) dev->stats.rx_length_errors++;
+ } else if (pkt_len > 1536) {
+ dev->stats.rx_length_errors++;
+ } else {
+ /* Malloc up new buffer. */
+ struct sk_buff *skb;
+
+ skb = dev_alloc_skb(pkt_len);
+ if (skb == NULL) {
+ if (znet_debug)
+ printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
+ dev->stats.rx_dropped++;
+ break;
+ }
+
+ if (&znet->rx_cur[(pkt_len+1)>>1] > znet->rx_end) {
+ int semi_cnt = (znet->rx_end - znet->rx_cur)<<1;
+ memcpy(skb_put(skb,semi_cnt), znet->rx_cur, semi_cnt);
+ memcpy(skb_put(skb,pkt_len-semi_cnt), znet->rx_start,
+ pkt_len - semi_cnt);
+ } else {
+ memcpy(skb_put(skb,pkt_len), znet->rx_cur, pkt_len);
+ if (znet_debug > 6) {
+ unsigned int *packet = (unsigned int *) skb->data;
+ printk(KERN_DEBUG "Packet data is %08x %08x %08x %08x.\n", packet[0],
+ packet[1], packet[2], packet[3]);
+ }
+ }
+ skb->protocol=eth_type_trans(skb,dev);
+ netif_rx(skb);
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
+ }
+ znet->rx_cur = this_rfp_ptr;
+ if (znet->rx_cur >= znet->rx_end)
+ znet->rx_cur -= RX_BUF_SIZE/2;
+ update_stop_hit(ioaddr, (znet->rx_cur - znet->rx_start)<<1);
+ next_frame_end_offset = this_rfp_ptr[-3];
+ if (next_frame_end_offset == 0) /* Read all the frames? */
+ break; /* Done for now */
+ this_rfp_ptr = znet->rx_start + next_frame_end_offset;
+ } while (--boguscount);
+
+ /* If any worth-while packets have been received, dev_rint()
+ has done a mark_bh(INET_BH) for us and will work on them
+ when we get to the bottom-half routine. */
+}
+
+/* The inverse routine to znet_open(). */
+static int znet_close(struct net_device *dev)
+{
+ int ioaddr = dev->base_addr;
+
+ netif_stop_queue (dev);
+
+ outb(OP0_RESET, ioaddr); /* CMD0_RESET */
+
+ if (znet_debug > 1)
+ printk(KERN_DEBUG "%s: Shutting down ethercard.\n", dev->name);
+ /* Turn off transceiver power. */
+ znet_transceiver_power (dev, 0);
+
+ znet_release_resources (dev);
+
+ return 0;
+}
+
+static void show_dma(struct net_device *dev)
+{
+ short ioaddr = dev->base_addr;
+ unsigned char stat = inb (ioaddr);
+ struct znet_private *znet = netdev_priv(dev);
+ unsigned long flags;
+ short dma_port = ((znet->tx_dma&3)<<2) + IO_DMA2_BASE;
+ unsigned addr = inb(dma_port);
+ short residue;
+
+ addr |= inb(dma_port) << 8;
+ residue = get_dma_residue(znet->tx_dma);
+
+ if (znet_debug > 1) {
+ flags=claim_dma_lock();
+ printk(KERN_DEBUG "Stat:%02x Addr: %04x cnt:%3x\n",
+ stat, addr<<1, residue);
+ release_dma_lock(flags);
+ }
+}
+
+/* Initialize the hardware. We have to do this when the board is open()ed
+ or when we come out of suspend mode. */
+static void hardware_init(struct net_device *dev)
+{
+ unsigned long flags;
+ short ioaddr = dev->base_addr;
+ struct znet_private *znet = netdev_priv(dev);
+
+ znet->rx_cur = znet->rx_start;
+ znet->tx_cur = znet->tx_start;
+
+ /* Reset the chip, and start it up. */
+ outb(OP0_RESET, ioaddr);
+
+ flags=claim_dma_lock();
+ disable_dma(znet->rx_dma); /* reset by an interrupting task. */
+ clear_dma_ff(znet->rx_dma);
+ set_dma_mode(znet->rx_dma, DMA_RX_MODE);
+ set_dma_addr(znet->rx_dma, (unsigned int) znet->rx_start);
+ set_dma_count(znet->rx_dma, RX_BUF_SIZE);
+ enable_dma(znet->rx_dma);
+ /* Now set up the Tx channel. */
+ disable_dma(znet->tx_dma);
+ clear_dma_ff(znet->tx_dma);
+ set_dma_mode(znet->tx_dma, DMA_TX_MODE);
+ set_dma_addr(znet->tx_dma, (unsigned int) znet->tx_start);
+ set_dma_count(znet->tx_dma, znet->tx_buf_len<<1);
+ enable_dma(znet->tx_dma);
+ release_dma_lock(flags);
+
+ if (znet_debug > 1)
+ printk(KERN_DEBUG "%s: Initializing the i82593, rx buf %p tx buf %p\n",
+ dev->name, znet->rx_start,znet->tx_start);
+ /* Do an empty configure command, just like the Crynwr driver. This
+ resets to chip to its default values. */
+ *znet->tx_cur++ = 0;
+ *znet->tx_cur++ = 0;
+ show_dma(dev);
+ outb(OP0_CONFIGURE | CR0_CHNL, ioaddr);
+
+ znet_set_multicast_list (dev);
+
+ *znet->tx_cur++ = 6;
+ memcpy(znet->tx_cur, dev->dev_addr, 6);
+ znet->tx_cur += 3;
+ show_dma(dev);
+ outb(OP0_IA_SETUP | CR0_CHNL, ioaddr);
+ show_dma(dev);
+
+ update_stop_hit(ioaddr, 8192);
+ if (znet_debug > 1) printk(KERN_DEBUG "enabling Rx.\n");
+ outb(OP0_RCV_ENABLE, ioaddr);
+ netif_start_queue (dev);
+}
+
+static void update_stop_hit(short ioaddr, unsigned short rx_stop_offset)
+{
+ outb(OP0_SWIT_TO_PORT_1 | CR0_CHNL, ioaddr);
+ if (znet_debug > 5)
+ printk(KERN_DEBUG "Updating stop hit with value %02x.\n",
+ (rx_stop_offset >> 6) | CR1_STOP_REG_UPDATE);
+ outb((rx_stop_offset >> 6) | CR1_STOP_REG_UPDATE, ioaddr);
+ outb(OP1_SWIT_TO_PORT_0, ioaddr);
+}
+
+static __exit void znet_cleanup (void)
+{
+ if (znet_dev) {
+ struct znet_private *znet = netdev_priv(znet_dev);
+
+ unregister_netdev (znet_dev);
+ kfree (znet->rx_start);
+ kfree (znet->tx_start);
+ free_netdev (znet_dev);
+ }
+}
+
+module_init (znet_probe);
+module_exit (znet_cleanup);
+++ /dev/null
-/* lasi_82596.c -- driver for the intel 82596 ethernet controller, as
- munged into HPPA boxen .
-
- This driver is based upon 82596.c, original credits are below...
- but there were too many hoops which HP wants jumped through to
- keep this code in there in a sane manner.
-
- 3 primary sources of the mess --
- 1) hppa needs *lots* of cacheline flushing to keep this kind of
- MMIO running.
-
- 2) The 82596 needs to see all of its pointers as their physical
- address. Thus virt_to_bus/bus_to_virt are *everywhere*.
-
- 3) The implementation HP is using seems to be significantly pickier
- about when and how the command and RX units are started. some
- command ordering was changed.
-
- Examination of the mach driver leads one to believe that there
- might be a saner way to pull this off... anyone who feels like a
- full rewrite can be my guest.
-
- Split 02/13/2000 Sam Creasey (sammy@oh.verio.com)
-
- 02/01/2000 Initial modifications for parisc by Helge Deller (deller@gmx.de)
- 03/02/2000 changes for better/correct(?) cache-flushing (deller)
-*/
-
-/* 82596.c: A generic 82596 ethernet driver for linux. */
-/*
- Based on Apricot.c
- Written 1994 by Mark Evans.
- This driver is for the Apricot 82596 bus-master interface
-
- Modularised 12/94 Mark Evans
-
-
- Modified to support the 82596 ethernet chips on 680x0 VME boards.
- by Richard Hirst <richard@sleepie.demon.co.uk>
- Renamed to be 82596.c
-
- 980825: Changed to receive directly in to sk_buffs which are
- allocated at open() time. Eliminates copy on incoming frames
- (small ones are still copied). Shared data now held in a
- non-cached page, so we can run on 68060 in copyback mode.
-
- TBD:
- * look at deferring rx frames rather than discarding (as per tulip)
- * handle tx ring full as per tulip
- * performance test to tune rx_copybreak
-
- Most of my modifications relate to the braindead big-endian
- implementation by Intel. When the i596 is operating in
- 'big-endian' mode, it thinks a 32 bit value of 0x12345678
- should be stored as 0x56781234. This is a real pain, when
- you have linked lists which are shared by the 680x0 and the
- i596.
-
- Driver skeleton
- Written 1993 by Donald Becker.
- Copyright 1993 United States Government as represented by the Director,
- National Security Agency. This software may only be used and distributed
- according to the terms of the GNU General Public License as modified by SRC,
- incorporated herein by reference.
-
- The author may be reached as becker@scyld.com, or C/O
- Scyld Computing Corporation, 410 Severn Ave., Suite 210, Annapolis MD 21403
-
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/ptrace.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/bitops.h>
-#include <linux/dma-mapping.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/pdc.h>
-#include <asm/parisc-device.h>
-
-#define LASI_82596_DRIVER_VERSION "LASI 82596 driver - Revision: 1.30"
-
-#define PA_I82596_RESET 0 /* Offsets relative to LASI-LAN-Addr.*/
-#define PA_CPU_PORT_L_ACCESS 4
-#define PA_CHANNEL_ATTENTION 8
-
-#define OPT_SWAP_PORT 0x0001 /* Need to wordswp on the MPU port */
-
-#define DMA_ALLOC dma_alloc_noncoherent
-#define DMA_FREE dma_free_noncoherent
-#define DMA_WBACK(ndev, addr, len) \
- do { dma_cache_sync((ndev)->dev.parent, (void *)addr, len, DMA_TO_DEVICE); } while (0)
-
-#define DMA_INV(ndev, addr, len) \
- do { dma_cache_sync((ndev)->dev.parent, (void *)addr, len, DMA_FROM_DEVICE); } while (0)
-
-#define DMA_WBACK_INV(ndev, addr, len) \
- do { dma_cache_sync((ndev)->dev.parent, (void *)addr, len, DMA_BIDIRECTIONAL); } while (0)
-
-#define SYSBUS 0x0000006c;
-
-/* big endian CPU, 82596 "big" endian mode */
-#define SWAP32(x) (((u32)(x)<<16) | ((((u32)(x)))>>16))
-#define SWAP16(x) (x)
-
-#include "lib82596.c"
-
-MODULE_AUTHOR("Richard Hirst");
-MODULE_DESCRIPTION("i82596 driver");
-MODULE_LICENSE("GPL");
-module_param(i596_debug, int, 0);
-MODULE_PARM_DESC(i596_debug, "lasi_82596 debug mask");
-
-static inline void ca(struct net_device *dev)
-{
- gsc_writel(0, dev->base_addr + PA_CHANNEL_ATTENTION);
-}
-
-
-static void mpu_port(struct net_device *dev, int c, dma_addr_t x)
-{
- struct i596_private *lp = netdev_priv(dev);
-
- u32 v = (u32) (c) | (u32) (x);
- u16 a, b;
-
- if (lp->options & OPT_SWAP_PORT) {
- a = v >> 16;
- b = v & 0xffff;
- } else {
- a = v & 0xffff;
- b = v >> 16;
- }
-
- gsc_writel(a, dev->base_addr + PA_CPU_PORT_L_ACCESS);
- udelay(1);
- gsc_writel(b, dev->base_addr + PA_CPU_PORT_L_ACCESS);
-}
-
-#define LAN_PROM_ADDR 0xF0810000
-
-static int __devinit
-lan_init_chip(struct parisc_device *dev)
-{
- struct net_device *netdevice;
- struct i596_private *lp;
- int retval;
- int i;
-
- if (!dev->irq) {
- printk(KERN_ERR "%s: IRQ not found for i82596 at 0x%lx\n",
- __FILE__, (unsigned long)dev->hpa.start);
- return -ENODEV;
- }
-
- printk(KERN_INFO "Found i82596 at 0x%lx, IRQ %d\n",
- (unsigned long)dev->hpa.start, dev->irq);
-
- netdevice = alloc_etherdev(sizeof(struct i596_private));
- if (!netdevice)
- return -ENOMEM;
- SET_NETDEV_DEV(netdevice, &dev->dev);
- parisc_set_drvdata (dev, netdevice);
-
- netdevice->base_addr = dev->hpa.start;
- netdevice->irq = dev->irq;
-
- if (pdc_lan_station_id(netdevice->dev_addr, netdevice->base_addr)) {
- for (i = 0; i < 6; i++) {
- netdevice->dev_addr[i] = gsc_readb(LAN_PROM_ADDR + i);
- }
- printk(KERN_INFO
- "%s: MAC of HP700 LAN read from EEPROM\n", __FILE__);
- }
-
- lp = netdev_priv(netdevice);
- lp->options = dev->id.sversion == 0x72 ? OPT_SWAP_PORT : 0;
-
- retval = i82596_probe(netdevice);
- if (retval) {
- free_netdev(netdevice);
- return -ENODEV;
- }
- return retval;
-}
-
-static int __devexit lan_remove_chip (struct parisc_device *pdev)
-{
- struct net_device *dev = parisc_get_drvdata(pdev);
- struct i596_private *lp = netdev_priv(dev);
-
- unregister_netdev (dev);
- DMA_FREE(&pdev->dev, sizeof(struct i596_private),
- (void *)lp->dma, lp->dma_addr);
- free_netdev (dev);
- return 0;
-}
-
-static struct parisc_device_id lan_tbl[] = {
- { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0008a },
- { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00072 },
- { 0, }
-};
-
-MODULE_DEVICE_TABLE(parisc, lan_tbl);
-
-static struct parisc_driver lan_driver = {
- .name = "lasi_82596",
- .id_table = lan_tbl,
- .probe = lan_init_chip,
- .remove = __devexit_p(lan_remove_chip),
-};
-
-static int __devinit lasi_82596_init(void)
-{
- printk(KERN_INFO LASI_82596_DRIVER_VERSION "\n");
- return register_parisc_driver(&lan_driver);
-}
-
-module_init(lasi_82596_init);
-
-static void __exit lasi_82596_exit(void)
-{
- unregister_parisc_driver(&lan_driver);
-}
-
-module_exit(lasi_82596_exit);
+++ /dev/null
-/* lasi_82596.c -- driver for the intel 82596 ethernet controller, as
- munged into HPPA boxen .
-
- This driver is based upon 82596.c, original credits are below...
- but there were too many hoops which HP wants jumped through to
- keep this code in there in a sane manner.
-
- 3 primary sources of the mess --
- 1) hppa needs *lots* of cacheline flushing to keep this kind of
- MMIO running.
-
- 2) The 82596 needs to see all of its pointers as their physical
- address. Thus virt_to_bus/bus_to_virt are *everywhere*.
-
- 3) The implementation HP is using seems to be significantly pickier
- about when and how the command and RX units are started. some
- command ordering was changed.
-
- Examination of the mach driver leads one to believe that there
- might be a saner way to pull this off... anyone who feels like a
- full rewrite can be my guest.
-
- Split 02/13/2000 Sam Creasey (sammy@oh.verio.com)
-
- 02/01/2000 Initial modifications for parisc by Helge Deller (deller@gmx.de)
- 03/02/2000 changes for better/correct(?) cache-flushing (deller)
-*/
-
-/* 82596.c: A generic 82596 ethernet driver for linux. */
-/*
- Based on Apricot.c
- Written 1994 by Mark Evans.
- This driver is for the Apricot 82596 bus-master interface
-
- Modularised 12/94 Mark Evans
-
-
- Modified to support the 82596 ethernet chips on 680x0 VME boards.
- by Richard Hirst <richard@sleepie.demon.co.uk>
- Renamed to be 82596.c
-
- 980825: Changed to receive directly in to sk_buffs which are
- allocated at open() time. Eliminates copy on incoming frames
- (small ones are still copied). Shared data now held in a
- non-cached page, so we can run on 68060 in copyback mode.
-
- TBD:
- * look at deferring rx frames rather than discarding (as per tulip)
- * handle tx ring full as per tulip
- * performance test to tune rx_copybreak
-
- Most of my modifications relate to the braindead big-endian
- implementation by Intel. When the i596 is operating in
- 'big-endian' mode, it thinks a 32 bit value of 0x12345678
- should be stored as 0x56781234. This is a real pain, when
- you have linked lists which are shared by the 680x0 and the
- i596.
-
- Driver skeleton
- Written 1993 by Donald Becker.
- Copyright 1993 United States Government as represented by the Director,
- National Security Agency. This software may only be used and distributed
- according to the terms of the GNU General Public License as modified by SRC,
- incorporated herein by reference.
-
- The author may be reached as becker@scyld.com, or C/O
- Scyld Computing Corporation, 410 Severn Ave., Suite 210, Annapolis MD 21403
-
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/bitops.h>
-#include <linux/dma-mapping.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-#include <linux/gfp.h>
-
-/* DEBUG flags
- */
-
-#define DEB_INIT 0x0001
-#define DEB_PROBE 0x0002
-#define DEB_SERIOUS 0x0004
-#define DEB_ERRORS 0x0008
-#define DEB_MULTI 0x0010
-#define DEB_TDR 0x0020
-#define DEB_OPEN 0x0040
-#define DEB_RESET 0x0080
-#define DEB_ADDCMD 0x0100
-#define DEB_STATUS 0x0200
-#define DEB_STARTTX 0x0400
-#define DEB_RXADDR 0x0800
-#define DEB_TXADDR 0x1000
-#define DEB_RXFRAME 0x2000
-#define DEB_INTS 0x4000
-#define DEB_STRUCT 0x8000
-#define DEB_ANY 0xffff
-
-
-#define DEB(x, y) if (i596_debug & (x)) { y; }
-
-
-/*
- * The MPU_PORT command allows direct access to the 82596. With PORT access
- * the following commands are available (p5-18). The 32-bit port command
- * must be word-swapped with the most significant word written first.
- * This only applies to VME boards.
- */
-#define PORT_RESET 0x00 /* reset 82596 */
-#define PORT_SELFTEST 0x01 /* selftest */
-#define PORT_ALTSCP 0x02 /* alternate SCB address */
-#define PORT_ALTDUMP 0x03 /* Alternate DUMP address */
-
-static int i596_debug = (DEB_SERIOUS|DEB_PROBE);
-
-/* Copy frames shorter than rx_copybreak, otherwise pass on up in
- * a full sized sk_buff. Value of 100 stolen from tulip.c (!alpha).
- */
-static int rx_copybreak = 100;
-
-#define PKT_BUF_SZ 1536
-#define MAX_MC_CNT 64
-
-#define ISCP_BUSY 0x0001
-
-#define I596_NULL ((u32)0xffffffff)
-
-#define CMD_EOL 0x8000 /* The last command of the list, stop. */
-#define CMD_SUSP 0x4000 /* Suspend after doing cmd. */
-#define CMD_INTR 0x2000 /* Interrupt after doing cmd. */
-
-#define CMD_FLEX 0x0008 /* Enable flexible memory model */
-
-enum commands {
- CmdNOp = 0, CmdSASetup = 1, CmdConfigure = 2, CmdMulticastList = 3,
- CmdTx = 4, CmdTDR = 5, CmdDump = 6, CmdDiagnose = 7
-};
-
-#define STAT_C 0x8000 /* Set to 0 after execution */
-#define STAT_B 0x4000 /* Command being executed */
-#define STAT_OK 0x2000 /* Command executed ok */
-#define STAT_A 0x1000 /* Command aborted */
-
-#define CUC_START 0x0100
-#define CUC_RESUME 0x0200
-#define CUC_SUSPEND 0x0300
-#define CUC_ABORT 0x0400
-#define RX_START 0x0010
-#define RX_RESUME 0x0020
-#define RX_SUSPEND 0x0030
-#define RX_ABORT 0x0040
-
-#define TX_TIMEOUT (HZ/20)
-
-
-struct i596_reg {
- unsigned short porthi;
- unsigned short portlo;
- u32 ca;
-};
-
-#define EOF 0x8000
-#define SIZE_MASK 0x3fff
-
-struct i596_tbd {
- unsigned short size;
- unsigned short pad;
- u32 next;
- u32 data;
- u32 cache_pad[5]; /* Total 32 bytes... */
-};
-
-/* The command structure has two 'next' pointers; v_next is the address of
- * the next command as seen by the CPU, b_next is the address of the next
- * command as seen by the 82596. The b_next pointer, as used by the 82596
- * always references the status field of the next command, rather than the
- * v_next field, because the 82596 is unaware of v_next. It may seem more
- * logical to put v_next at the end of the structure, but we cannot do that
- * because the 82596 expects other fields to be there, depending on command
- * type.
- */
-
-struct i596_cmd {
- struct i596_cmd *v_next; /* Address from CPUs viewpoint */
- unsigned short status;
- unsigned short command;
- u32 b_next; /* Address from i596 viewpoint */
-};
-
-struct tx_cmd {
- struct i596_cmd cmd;
- u32 tbd;
- unsigned short size;
- unsigned short pad;
- struct sk_buff *skb; /* So we can free it after tx */
- dma_addr_t dma_addr;
-#ifdef __LP64__
- u32 cache_pad[6]; /* Total 64 bytes... */
-#else
- u32 cache_pad[1]; /* Total 32 bytes... */
-#endif
-};
-
-struct tdr_cmd {
- struct i596_cmd cmd;
- unsigned short status;
- unsigned short pad;
-};
-
-struct mc_cmd {
- struct i596_cmd cmd;
- short mc_cnt;
- char mc_addrs[MAX_MC_CNT*6];
-};
-
-struct sa_cmd {
- struct i596_cmd cmd;
- char eth_addr[8];
-};
-
-struct cf_cmd {
- struct i596_cmd cmd;
- char i596_config[16];
-};
-
-struct i596_rfd {
- unsigned short stat;
- unsigned short cmd;
- u32 b_next; /* Address from i596 viewpoint */
- u32 rbd;
- unsigned short count;
- unsigned short size;
- struct i596_rfd *v_next; /* Address from CPUs viewpoint */
- struct i596_rfd *v_prev;
-#ifndef __LP64__
- u32 cache_pad[2]; /* Total 32 bytes... */
-#endif
-};
-
-struct i596_rbd {
- /* hardware data */
- unsigned short count;
- unsigned short zero1;
- u32 b_next;
- u32 b_data; /* Address from i596 viewpoint */
- unsigned short size;
- unsigned short zero2;
- /* driver data */
- struct sk_buff *skb;
- struct i596_rbd *v_next;
- u32 b_addr; /* This rbd addr from i596 view */
- unsigned char *v_data; /* Address from CPUs viewpoint */
- /* Total 32 bytes... */
-#ifdef __LP64__
- u32 cache_pad[4];
-#endif
-};
-
-/* These values as chosen so struct i596_dma fits in one page... */
-
-#define TX_RING_SIZE 32
-#define RX_RING_SIZE 16
-
-struct i596_scb {
- unsigned short status;
- unsigned short command;
- u32 cmd;
- u32 rfd;
- u32 crc_err;
- u32 align_err;
- u32 resource_err;
- u32 over_err;
- u32 rcvdt_err;
- u32 short_err;
- unsigned short t_on;
- unsigned short t_off;
-};
-
-struct i596_iscp {
- u32 stat;
- u32 scb;
-};
-
-struct i596_scp {
- u32 sysbus;
- u32 pad;
- u32 iscp;
-};
-
-struct i596_dma {
- struct i596_scp scp __attribute__((aligned(32)));
- volatile struct i596_iscp iscp __attribute__((aligned(32)));
- volatile struct i596_scb scb __attribute__((aligned(32)));
- struct sa_cmd sa_cmd __attribute__((aligned(32)));
- struct cf_cmd cf_cmd __attribute__((aligned(32)));
- struct tdr_cmd tdr_cmd __attribute__((aligned(32)));
- struct mc_cmd mc_cmd __attribute__((aligned(32)));
- struct i596_rfd rfds[RX_RING_SIZE] __attribute__((aligned(32)));
- struct i596_rbd rbds[RX_RING_SIZE] __attribute__((aligned(32)));
- struct tx_cmd tx_cmds[TX_RING_SIZE] __attribute__((aligned(32)));
- struct i596_tbd tbds[TX_RING_SIZE] __attribute__((aligned(32)));
-};
-
-struct i596_private {
- struct i596_dma *dma;
- u32 stat;
- int last_restart;
- struct i596_rfd *rfd_head;
- struct i596_rbd *rbd_head;
- struct i596_cmd *cmd_tail;
- struct i596_cmd *cmd_head;
- int cmd_backlog;
- u32 last_cmd;
- int next_tx_cmd;
- int options;
- spinlock_t lock; /* serialize access to chip */
- dma_addr_t dma_addr;
- void __iomem *mpu_port;
- void __iomem *ca;
-};
-
-static const char init_setup[] =
-{
- 0x8E, /* length, prefetch on */
- 0xC8, /* fifo to 8, monitor off */
- 0x80, /* don't save bad frames */
- 0x2E, /* No source address insertion, 8 byte preamble */
- 0x00, /* priority and backoff defaults */
- 0x60, /* interframe spacing */
- 0x00, /* slot time LSB */
- 0xf2, /* slot time and retries */
- 0x00, /* promiscuous mode */
- 0x00, /* collision detect */
- 0x40, /* minimum frame length */
- 0xff,
- 0x00,
- 0x7f /* *multi IA */ };
-
-static int i596_open(struct net_device *dev);
-static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t i596_interrupt(int irq, void *dev_id);
-static int i596_close(struct net_device *dev);
-static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd);
-static void i596_tx_timeout (struct net_device *dev);
-static void print_eth(unsigned char *buf, char *str);
-static void set_multicast_list(struct net_device *dev);
-static inline void ca(struct net_device *dev);
-static void mpu_port(struct net_device *dev, int c, dma_addr_t x);
-
-static int rx_ring_size = RX_RING_SIZE;
-static int ticks_limit = 100;
-static int max_cmd_backlog = TX_RING_SIZE-1;
-
-#ifdef CONFIG_NET_POLL_CONTROLLER
-static void i596_poll_controller(struct net_device *dev);
-#endif
-
-
-static inline int wait_istat(struct net_device *dev, struct i596_dma *dma, int delcnt, char *str)
-{
- DMA_INV(dev, &(dma->iscp), sizeof(struct i596_iscp));
- while (--delcnt && dma->iscp.stat) {
- udelay(10);
- DMA_INV(dev, &(dma->iscp), sizeof(struct i596_iscp));
- }
- if (!delcnt) {
- printk(KERN_ERR "%s: %s, iscp.stat %04x, didn't clear\n",
- dev->name, str, SWAP16(dma->iscp.stat));
- return -1;
- } else
- return 0;
-}
-
-
-static inline int wait_cmd(struct net_device *dev, struct i596_dma *dma, int delcnt, char *str)
-{
- DMA_INV(dev, &(dma->scb), sizeof(struct i596_scb));
- while (--delcnt && dma->scb.command) {
- udelay(10);
- DMA_INV(dev, &(dma->scb), sizeof(struct i596_scb));
- }
- if (!delcnt) {
- printk(KERN_ERR "%s: %s, status %4.4x, cmd %4.4x.\n",
- dev->name, str,
- SWAP16(dma->scb.status),
- SWAP16(dma->scb.command));
- return -1;
- } else
- return 0;
-}
-
-
-static void i596_display_data(struct net_device *dev)
-{
- struct i596_private *lp = netdev_priv(dev);
- struct i596_dma *dma = lp->dma;
- struct i596_cmd *cmd;
- struct i596_rfd *rfd;
- struct i596_rbd *rbd;
-
- printk(KERN_DEBUG "lp and scp at %p, .sysbus = %08x, .iscp = %08x\n",
- &dma->scp, dma->scp.sysbus, SWAP32(dma->scp.iscp));
- printk(KERN_DEBUG "iscp at %p, iscp.stat = %08x, .scb = %08x\n",
- &dma->iscp, SWAP32(dma->iscp.stat), SWAP32(dma->iscp.scb));
- printk(KERN_DEBUG "scb at %p, scb.status = %04x, .command = %04x,"
- " .cmd = %08x, .rfd = %08x\n",
- &dma->scb, SWAP16(dma->scb.status), SWAP16(dma->scb.command),
- SWAP16(dma->scb.cmd), SWAP32(dma->scb.rfd));
- printk(KERN_DEBUG " errors: crc %x, align %x, resource %x,"
- " over %x, rcvdt %x, short %x\n",
- SWAP32(dma->scb.crc_err), SWAP32(dma->scb.align_err),
- SWAP32(dma->scb.resource_err), SWAP32(dma->scb.over_err),
- SWAP32(dma->scb.rcvdt_err), SWAP32(dma->scb.short_err));
- cmd = lp->cmd_head;
- while (cmd != NULL) {
- printk(KERN_DEBUG
- "cmd at %p, .status = %04x, .command = %04x,"
- " .b_next = %08x\n",
- cmd, SWAP16(cmd->status), SWAP16(cmd->command),
- SWAP32(cmd->b_next));
- cmd = cmd->v_next;
- }
- rfd = lp->rfd_head;
- printk(KERN_DEBUG "rfd_head = %p\n", rfd);
- do {
- printk(KERN_DEBUG
- " %p .stat %04x, .cmd %04x, b_next %08x, rbd %08x,"
- " count %04x\n",
- rfd, SWAP16(rfd->stat), SWAP16(rfd->cmd),
- SWAP32(rfd->b_next), SWAP32(rfd->rbd),
- SWAP16(rfd->count));
- rfd = rfd->v_next;
- } while (rfd != lp->rfd_head);
- rbd = lp->rbd_head;
- printk(KERN_DEBUG "rbd_head = %p\n", rbd);
- do {
- printk(KERN_DEBUG
- " %p .count %04x, b_next %08x, b_data %08x,"
- " size %04x\n",
- rbd, SWAP16(rbd->count), SWAP32(rbd->b_next),
- SWAP32(rbd->b_data), SWAP16(rbd->size));
- rbd = rbd->v_next;
- } while (rbd != lp->rbd_head);
- DMA_INV(dev, dma, sizeof(struct i596_dma));
-}
-
-
-#define virt_to_dma(lp, v) ((lp)->dma_addr + (dma_addr_t)((unsigned long)(v)-(unsigned long)((lp)->dma)))
-
-static inline int init_rx_bufs(struct net_device *dev)
-{
- struct i596_private *lp = netdev_priv(dev);
- struct i596_dma *dma = lp->dma;
- int i;
- struct i596_rfd *rfd;
- struct i596_rbd *rbd;
-
- /* First build the Receive Buffer Descriptor List */
-
- for (i = 0, rbd = dma->rbds; i < rx_ring_size; i++, rbd++) {
- dma_addr_t dma_addr;
- struct sk_buff *skb;
-
- skb = netdev_alloc_skb_ip_align(dev, PKT_BUF_SZ);
- if (skb == NULL)
- return -1;
- dma_addr = dma_map_single(dev->dev.parent, skb->data,
- PKT_BUF_SZ, DMA_FROM_DEVICE);
- rbd->v_next = rbd+1;
- rbd->b_next = SWAP32(virt_to_dma(lp, rbd+1));
- rbd->b_addr = SWAP32(virt_to_dma(lp, rbd));
- rbd->skb = skb;
- rbd->v_data = skb->data;
- rbd->b_data = SWAP32(dma_addr);
- rbd->size = SWAP16(PKT_BUF_SZ);
- }
- lp->rbd_head = dma->rbds;
- rbd = dma->rbds + rx_ring_size - 1;
- rbd->v_next = dma->rbds;
- rbd->b_next = SWAP32(virt_to_dma(lp, dma->rbds));
-
- /* Now build the Receive Frame Descriptor List */
-
- for (i = 0, rfd = dma->rfds; i < rx_ring_size; i++, rfd++) {
- rfd->rbd = I596_NULL;
- rfd->v_next = rfd+1;
- rfd->v_prev = rfd-1;
- rfd->b_next = SWAP32(virt_to_dma(lp, rfd+1));
- rfd->cmd = SWAP16(CMD_FLEX);
- }
- lp->rfd_head = dma->rfds;
- dma->scb.rfd = SWAP32(virt_to_dma(lp, dma->rfds));
- rfd = dma->rfds;
- rfd->rbd = SWAP32(virt_to_dma(lp, lp->rbd_head));
- rfd->v_prev = dma->rfds + rx_ring_size - 1;
- rfd = dma->rfds + rx_ring_size - 1;
- rfd->v_next = dma->rfds;
- rfd->b_next = SWAP32(virt_to_dma(lp, dma->rfds));
- rfd->cmd = SWAP16(CMD_EOL|CMD_FLEX);
-
- DMA_WBACK_INV(dev, dma, sizeof(struct i596_dma));
- return 0;
-}
-
-static inline void remove_rx_bufs(struct net_device *dev)
-{
- struct i596_private *lp = netdev_priv(dev);
- struct i596_rbd *rbd;
- int i;
-
- for (i = 0, rbd = lp->dma->rbds; i < rx_ring_size; i++, rbd++) {
- if (rbd->skb == NULL)
- break;
- dma_unmap_single(dev->dev.parent,
- (dma_addr_t)SWAP32(rbd->b_data),
- PKT_BUF_SZ, DMA_FROM_DEVICE);
- dev_kfree_skb(rbd->skb);
- }
-}
-
-
-static void rebuild_rx_bufs(struct net_device *dev)
-{
- struct i596_private *lp = netdev_priv(dev);
- struct i596_dma *dma = lp->dma;
- int i;
-
- /* Ensure rx frame/buffer descriptors are tidy */
-
- for (i = 0; i < rx_ring_size; i++) {
- dma->rfds[i].rbd = I596_NULL;
- dma->rfds[i].cmd = SWAP16(CMD_FLEX);
- }
- dma->rfds[rx_ring_size-1].cmd = SWAP16(CMD_EOL|CMD_FLEX);
- lp->rfd_head = dma->rfds;
- dma->scb.rfd = SWAP32(virt_to_dma(lp, dma->rfds));
- lp->rbd_head = dma->rbds;
- dma->rfds[0].rbd = SWAP32(virt_to_dma(lp, dma->rbds));
-
- DMA_WBACK_INV(dev, dma, sizeof(struct i596_dma));
-}
-
-
-static int init_i596_mem(struct net_device *dev)
-{
- struct i596_private *lp = netdev_priv(dev);
- struct i596_dma *dma = lp->dma;
- unsigned long flags;
-
- mpu_port(dev, PORT_RESET, 0);
- udelay(100); /* Wait 100us - seems to help */
-
- /* change the scp address */
-
- lp->last_cmd = jiffies;
-
- dma->scp.sysbus = SYSBUS;
- dma->scp.iscp = SWAP32(virt_to_dma(lp, &(dma->iscp)));
- dma->iscp.scb = SWAP32(virt_to_dma(lp, &(dma->scb)));
- dma->iscp.stat = SWAP32(ISCP_BUSY);
- lp->cmd_backlog = 0;
-
- lp->cmd_head = NULL;
- dma->scb.cmd = I596_NULL;
-
- DEB(DEB_INIT, printk(KERN_DEBUG "%s: starting i82596.\n", dev->name));
-
- DMA_WBACK(dev, &(dma->scp), sizeof(struct i596_scp));
- DMA_WBACK(dev, &(dma->iscp), sizeof(struct i596_iscp));
- DMA_WBACK(dev, &(dma->scb), sizeof(struct i596_scb));
-
- mpu_port(dev, PORT_ALTSCP, virt_to_dma(lp, &dma->scp));
- ca(dev);
- if (wait_istat(dev, dma, 1000, "initialization timed out"))
- goto failed;
- DEB(DEB_INIT, printk(KERN_DEBUG
- "%s: i82596 initialization successful\n",
- dev->name));
-
- if (request_irq(dev->irq, i596_interrupt, 0, "i82596", dev)) {
- printk(KERN_ERR "%s: IRQ %d not free\n", dev->name, dev->irq);
- goto failed;
- }
-
- /* Ensure rx frame/buffer descriptors are tidy */
- rebuild_rx_bufs(dev);
-
- dma->scb.command = 0;
- DMA_WBACK(dev, &(dma->scb), sizeof(struct i596_scb));
-
- DEB(DEB_INIT, printk(KERN_DEBUG
- "%s: queuing CmdConfigure\n", dev->name));
- memcpy(dma->cf_cmd.i596_config, init_setup, 14);
- dma->cf_cmd.cmd.command = SWAP16(CmdConfigure);
- DMA_WBACK(dev, &(dma->cf_cmd), sizeof(struct cf_cmd));
- i596_add_cmd(dev, &dma->cf_cmd.cmd);
-
- DEB(DEB_INIT, printk(KERN_DEBUG "%s: queuing CmdSASetup\n", dev->name));
- memcpy(dma->sa_cmd.eth_addr, dev->dev_addr, 6);
- dma->sa_cmd.cmd.command = SWAP16(CmdSASetup);
- DMA_WBACK(dev, &(dma->sa_cmd), sizeof(struct sa_cmd));
- i596_add_cmd(dev, &dma->sa_cmd.cmd);
-
- DEB(DEB_INIT, printk(KERN_DEBUG "%s: queuing CmdTDR\n", dev->name));
- dma->tdr_cmd.cmd.command = SWAP16(CmdTDR);
- DMA_WBACK(dev, &(dma->tdr_cmd), sizeof(struct tdr_cmd));
- i596_add_cmd(dev, &dma->tdr_cmd.cmd);
-
- spin_lock_irqsave (&lp->lock, flags);
-
- if (wait_cmd(dev, dma, 1000, "timed out waiting to issue RX_START")) {
- spin_unlock_irqrestore (&lp->lock, flags);
- goto failed_free_irq;
- }
- DEB(DEB_INIT, printk(KERN_DEBUG "%s: Issuing RX_START\n", dev->name));
- dma->scb.command = SWAP16(RX_START);
- dma->scb.rfd = SWAP32(virt_to_dma(lp, dma->rfds));
- DMA_WBACK(dev, &(dma->scb), sizeof(struct i596_scb));
-
- ca(dev);
-
- spin_unlock_irqrestore (&lp->lock, flags);
- if (wait_cmd(dev, dma, 1000, "RX_START not processed"))
- goto failed_free_irq;
- DEB(DEB_INIT, printk(KERN_DEBUG
- "%s: Receive unit started OK\n", dev->name));
- return 0;
-
-failed_free_irq:
- free_irq(dev->irq, dev);
-failed:
- printk(KERN_ERR "%s: Failed to initialise 82596\n", dev->name);
- mpu_port(dev, PORT_RESET, 0);
- return -1;
-}
-
-
-static inline int i596_rx(struct net_device *dev)
-{
- struct i596_private *lp = netdev_priv(dev);
- struct i596_rfd *rfd;
- struct i596_rbd *rbd;
- int frames = 0;
-
- DEB(DEB_RXFRAME, printk(KERN_DEBUG
- "i596_rx(), rfd_head %p, rbd_head %p\n",
- lp->rfd_head, lp->rbd_head));
-
-
- rfd = lp->rfd_head; /* Ref next frame to check */
-
- DMA_INV(dev, rfd, sizeof(struct i596_rfd));
- while (rfd->stat & SWAP16(STAT_C)) { /* Loop while complete frames */
- if (rfd->rbd == I596_NULL)
- rbd = NULL;
- else if (rfd->rbd == lp->rbd_head->b_addr) {
- rbd = lp->rbd_head;
- DMA_INV(dev, rbd, sizeof(struct i596_rbd));
- } else {
- printk(KERN_ERR "%s: rbd chain broken!\n", dev->name);
- /* XXX Now what? */
- rbd = NULL;
- }
- DEB(DEB_RXFRAME, printk(KERN_DEBUG
- " rfd %p, rfd.rbd %08x, rfd.stat %04x\n",
- rfd, rfd->rbd, rfd->stat));
-
- if (rbd != NULL && (rfd->stat & SWAP16(STAT_OK))) {
- /* a good frame */
- int pkt_len = SWAP16(rbd->count) & 0x3fff;
- struct sk_buff *skb = rbd->skb;
- int rx_in_place = 0;
-
- DEB(DEB_RXADDR, print_eth(rbd->v_data, "received"));
- frames++;
-
- /* Check if the packet is long enough to just accept
- * without copying to a properly sized skbuff.
- */
-
- if (pkt_len > rx_copybreak) {
- struct sk_buff *newskb;
- dma_addr_t dma_addr;
-
- dma_unmap_single(dev->dev.parent,
- (dma_addr_t)SWAP32(rbd->b_data),
- PKT_BUF_SZ, DMA_FROM_DEVICE);
- /* Get fresh skbuff to replace filled one. */
- newskb = netdev_alloc_skb_ip_align(dev,
- PKT_BUF_SZ);
- if (newskb == NULL) {
- skb = NULL; /* drop pkt */
- goto memory_squeeze;
- }
-
- /* Pass up the skb already on the Rx ring. */
- skb_put(skb, pkt_len);
- rx_in_place = 1;
- rbd->skb = newskb;
- dma_addr = dma_map_single(dev->dev.parent,
- newskb->data,
- PKT_BUF_SZ,
- DMA_FROM_DEVICE);
- rbd->v_data = newskb->data;
- rbd->b_data = SWAP32(dma_addr);
- DMA_WBACK_INV(dev, rbd, sizeof(struct i596_rbd));
- } else
- skb = netdev_alloc_skb_ip_align(dev, pkt_len);
-memory_squeeze:
- if (skb == NULL) {
- /* XXX tulip.c can defer packets here!! */
- printk(KERN_ERR
- "%s: i596_rx Memory squeeze, dropping packet.\n",
- dev->name);
- dev->stats.rx_dropped++;
- } else {
- if (!rx_in_place) {
- /* 16 byte align the data fields */
- dma_sync_single_for_cpu(dev->dev.parent,
- (dma_addr_t)SWAP32(rbd->b_data),
- PKT_BUF_SZ, DMA_FROM_DEVICE);
- memcpy(skb_put(skb, pkt_len), rbd->v_data, pkt_len);
- dma_sync_single_for_device(dev->dev.parent,
- (dma_addr_t)SWAP32(rbd->b_data),
- PKT_BUF_SZ, DMA_FROM_DEVICE);
- }
- skb->len = pkt_len;
- skb->protocol = eth_type_trans(skb, dev);
- netif_rx(skb);
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += pkt_len;
- }
- } else {
- DEB(DEB_ERRORS, printk(KERN_DEBUG
- "%s: Error, rfd.stat = 0x%04x\n",
- dev->name, rfd->stat));
- dev->stats.rx_errors++;
- if (rfd->stat & SWAP16(0x0100))
- dev->stats.collisions++;
- if (rfd->stat & SWAP16(0x8000))
- dev->stats.rx_length_errors++;
- if (rfd->stat & SWAP16(0x0001))
- dev->stats.rx_over_errors++;
- if (rfd->stat & SWAP16(0x0002))
- dev->stats.rx_fifo_errors++;
- if (rfd->stat & SWAP16(0x0004))
- dev->stats.rx_frame_errors++;
- if (rfd->stat & SWAP16(0x0008))
- dev->stats.rx_crc_errors++;
- if (rfd->stat & SWAP16(0x0010))
- dev->stats.rx_length_errors++;
- }
-
- /* Clear the buffer descriptor count and EOF + F flags */
-
- if (rbd != NULL && (rbd->count & SWAP16(0x4000))) {
- rbd->count = 0;
- lp->rbd_head = rbd->v_next;
- DMA_WBACK_INV(dev, rbd, sizeof(struct i596_rbd));
- }
-
- /* Tidy the frame descriptor, marking it as end of list */
-
- rfd->rbd = I596_NULL;
- rfd->stat = 0;
- rfd->cmd = SWAP16(CMD_EOL|CMD_FLEX);
- rfd->count = 0;
-
- /* Update record of next frame descriptor to process */
-
- lp->dma->scb.rfd = rfd->b_next;
- lp->rfd_head = rfd->v_next;
- DMA_WBACK_INV(dev, rfd, sizeof(struct i596_rfd));
-
- /* Remove end-of-list from old end descriptor */
-
- rfd->v_prev->cmd = SWAP16(CMD_FLEX);
- DMA_WBACK_INV(dev, rfd->v_prev, sizeof(struct i596_rfd));
- rfd = lp->rfd_head;
- DMA_INV(dev, rfd, sizeof(struct i596_rfd));
- }
-
- DEB(DEB_RXFRAME, printk(KERN_DEBUG "frames %d\n", frames));
-
- return 0;
-}
-
-
-static inline void i596_cleanup_cmd(struct net_device *dev, struct i596_private *lp)
-{
- struct i596_cmd *ptr;
-
- while (lp->cmd_head != NULL) {
- ptr = lp->cmd_head;
- lp->cmd_head = ptr->v_next;
- lp->cmd_backlog--;
-
- switch (SWAP16(ptr->command) & 0x7) {
- case CmdTx:
- {
- struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr;
- struct sk_buff *skb = tx_cmd->skb;
- dma_unmap_single(dev->dev.parent,
- tx_cmd->dma_addr,
- skb->len, DMA_TO_DEVICE);
-
- dev_kfree_skb(skb);
-
- dev->stats.tx_errors++;
- dev->stats.tx_aborted_errors++;
-
- ptr->v_next = NULL;
- ptr->b_next = I596_NULL;
- tx_cmd->cmd.command = 0; /* Mark as free */
- break;
- }
- default:
- ptr->v_next = NULL;
- ptr->b_next = I596_NULL;
- }
- DMA_WBACK_INV(dev, ptr, sizeof(struct i596_cmd));
- }
-
- wait_cmd(dev, lp->dma, 100, "i596_cleanup_cmd timed out");
- lp->dma->scb.cmd = I596_NULL;
- DMA_WBACK(dev, &(lp->dma->scb), sizeof(struct i596_scb));
-}
-
-
-static inline void i596_reset(struct net_device *dev, struct i596_private *lp)
-{
- unsigned long flags;
-
- DEB(DEB_RESET, printk(KERN_DEBUG "i596_reset\n"));
-
- spin_lock_irqsave (&lp->lock, flags);
-
- wait_cmd(dev, lp->dma, 100, "i596_reset timed out");
-
- netif_stop_queue(dev);
-
- /* FIXME: this command might cause an lpmc */
- lp->dma->scb.command = SWAP16(CUC_ABORT | RX_ABORT);
- DMA_WBACK(dev, &(lp->dma->scb), sizeof(struct i596_scb));
- ca(dev);
-
- /* wait for shutdown */
- wait_cmd(dev, lp->dma, 1000, "i596_reset 2 timed out");
- spin_unlock_irqrestore (&lp->lock, flags);
-
- i596_cleanup_cmd(dev, lp);
- i596_rx(dev);
-
- netif_start_queue(dev);
- init_i596_mem(dev);
-}
-
-
-static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd)
-{
- struct i596_private *lp = netdev_priv(dev);
- struct i596_dma *dma = lp->dma;
- unsigned long flags;
-
- DEB(DEB_ADDCMD, printk(KERN_DEBUG "i596_add_cmd cmd_head %p\n",
- lp->cmd_head));
-
- cmd->status = 0;
- cmd->command |= SWAP16(CMD_EOL | CMD_INTR);
- cmd->v_next = NULL;
- cmd->b_next = I596_NULL;
- DMA_WBACK(dev, cmd, sizeof(struct i596_cmd));
-
- spin_lock_irqsave (&lp->lock, flags);
-
- if (lp->cmd_head != NULL) {
- lp->cmd_tail->v_next = cmd;
- lp->cmd_tail->b_next = SWAP32(virt_to_dma(lp, &cmd->status));
- DMA_WBACK(dev, lp->cmd_tail, sizeof(struct i596_cmd));
- } else {
- lp->cmd_head = cmd;
- wait_cmd(dev, dma, 100, "i596_add_cmd timed out");
- dma->scb.cmd = SWAP32(virt_to_dma(lp, &cmd->status));
- dma->scb.command = SWAP16(CUC_START);
- DMA_WBACK(dev, &(dma->scb), sizeof(struct i596_scb));
- ca(dev);
- }
- lp->cmd_tail = cmd;
- lp->cmd_backlog++;
-
- spin_unlock_irqrestore (&lp->lock, flags);
-
- if (lp->cmd_backlog > max_cmd_backlog) {
- unsigned long tickssofar = jiffies - lp->last_cmd;
-
- if (tickssofar < ticks_limit)
- return;
-
- printk(KERN_ERR
- "%s: command unit timed out, status resetting.\n",
- dev->name);
-#if 1
- i596_reset(dev, lp);
-#endif
- }
-}
-
-static int i596_open(struct net_device *dev)
-{
- DEB(DEB_OPEN, printk(KERN_DEBUG
- "%s: i596_open() irq %d.\n", dev->name, dev->irq));
-
- if (init_rx_bufs(dev)) {
- printk(KERN_ERR "%s: Failed to init rx bufs\n", dev->name);
- return -EAGAIN;
- }
- if (init_i596_mem(dev)) {
- printk(KERN_ERR "%s: Failed to init memory\n", dev->name);
- goto out_remove_rx_bufs;
- }
- netif_start_queue(dev);
-
- return 0;
-
-out_remove_rx_bufs:
- remove_rx_bufs(dev);
- return -EAGAIN;
-}
-
-static void i596_tx_timeout (struct net_device *dev)
-{
- struct i596_private *lp = netdev_priv(dev);
-
- /* Transmitter timeout, serious problems. */
- DEB(DEB_ERRORS, printk(KERN_DEBUG
- "%s: transmit timed out, status resetting.\n",
- dev->name));
-
- dev->stats.tx_errors++;
-
- /* Try to restart the adaptor */
- if (lp->last_restart == dev->stats.tx_packets) {
- DEB(DEB_ERRORS, printk(KERN_DEBUG "Resetting board.\n"));
- /* Shutdown and restart */
- i596_reset (dev, lp);
- } else {
- /* Issue a channel attention signal */
- DEB(DEB_ERRORS, printk(KERN_DEBUG "Kicking board.\n"));
- lp->dma->scb.command = SWAP16(CUC_START | RX_START);
- DMA_WBACK_INV(dev, &(lp->dma->scb), sizeof(struct i596_scb));
- ca (dev);
- lp->last_restart = dev->stats.tx_packets;
- }
-
- dev->trans_start = jiffies; /* prevent tx timeout */
- netif_wake_queue (dev);
-}
-
-
-static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- struct i596_private *lp = netdev_priv(dev);
- struct tx_cmd *tx_cmd;
- struct i596_tbd *tbd;
- short length = skb->len;
-
- DEB(DEB_STARTTX, printk(KERN_DEBUG
- "%s: i596_start_xmit(%x,%p) called\n",
- dev->name, skb->len, skb->data));
-
- if (length < ETH_ZLEN) {
- if (skb_padto(skb, ETH_ZLEN))
- return NETDEV_TX_OK;
- length = ETH_ZLEN;
- }
-
- netif_stop_queue(dev);
-
- tx_cmd = lp->dma->tx_cmds + lp->next_tx_cmd;
- tbd = lp->dma->tbds + lp->next_tx_cmd;
-
- if (tx_cmd->cmd.command) {
- DEB(DEB_ERRORS, printk(KERN_DEBUG
- "%s: xmit ring full, dropping packet.\n",
- dev->name));
- dev->stats.tx_dropped++;
-
- dev_kfree_skb(skb);
- } else {
- if (++lp->next_tx_cmd == TX_RING_SIZE)
- lp->next_tx_cmd = 0;
- tx_cmd->tbd = SWAP32(virt_to_dma(lp, tbd));
- tbd->next = I596_NULL;
-
- tx_cmd->cmd.command = SWAP16(CMD_FLEX | CmdTx);
- tx_cmd->skb = skb;
-
- tx_cmd->pad = 0;
- tx_cmd->size = 0;
- tbd->pad = 0;
- tbd->size = SWAP16(EOF | length);
-
- tx_cmd->dma_addr = dma_map_single(dev->dev.parent, skb->data,
- skb->len, DMA_TO_DEVICE);
- tbd->data = SWAP32(tx_cmd->dma_addr);
-
- DEB(DEB_TXADDR, print_eth(skb->data, "tx-queued"));
- DMA_WBACK_INV(dev, tx_cmd, sizeof(struct tx_cmd));
- DMA_WBACK_INV(dev, tbd, sizeof(struct i596_tbd));
- i596_add_cmd(dev, &tx_cmd->cmd);
-
- dev->stats.tx_packets++;
- dev->stats.tx_bytes += length;
- }
-
- netif_start_queue(dev);
-
- return NETDEV_TX_OK;
-}
-
-static void print_eth(unsigned char *add, char *str)
-{
- printk(KERN_DEBUG "i596 0x%p, %pM --> %pM %02X%02X, %s\n",
- add, add + 6, add, add[12], add[13], str);
-}
-static const struct net_device_ops i596_netdev_ops = {
- .ndo_open = i596_open,
- .ndo_stop = i596_close,
- .ndo_start_xmit = i596_start_xmit,
- .ndo_set_multicast_list = set_multicast_list,
- .ndo_tx_timeout = i596_tx_timeout,
- .ndo_change_mtu = eth_change_mtu,
- .ndo_validate_addr = eth_validate_addr,
- .ndo_set_mac_address = eth_mac_addr,
-#ifdef CONFIG_NET_POLL_CONTROLLER
- .ndo_poll_controller = i596_poll_controller,
-#endif
-};
-
-static int __devinit i82596_probe(struct net_device *dev)
-{
- int i;
- struct i596_private *lp = netdev_priv(dev);
- struct i596_dma *dma;
-
- /* This lot is ensure things have been cache line aligned. */
- BUILD_BUG_ON(sizeof(struct i596_rfd) != 32);
- BUILD_BUG_ON(sizeof(struct i596_rbd) & 31);
- BUILD_BUG_ON(sizeof(struct tx_cmd) & 31);
- BUILD_BUG_ON(sizeof(struct i596_tbd) != 32);
-#ifndef __LP64__
- BUILD_BUG_ON(sizeof(struct i596_dma) > 4096);
-#endif
-
- if (!dev->base_addr || !dev->irq)
- return -ENODEV;
-
- dma = (struct i596_dma *) DMA_ALLOC(dev->dev.parent,
- sizeof(struct i596_dma), &lp->dma_addr, GFP_KERNEL);
- if (!dma) {
- printk(KERN_ERR "%s: Couldn't get shared memory\n", __FILE__);
- return -ENOMEM;
- }
-
- dev->netdev_ops = &i596_netdev_ops;
- dev->watchdog_timeo = TX_TIMEOUT;
-
- memset(dma, 0, sizeof(struct i596_dma));
- lp->dma = dma;
-
- dma->scb.command = 0;
- dma->scb.cmd = I596_NULL;
- dma->scb.rfd = I596_NULL;
- spin_lock_init(&lp->lock);
-
- DMA_WBACK_INV(dev, dma, sizeof(struct i596_dma));
-
- i = register_netdev(dev);
- if (i) {
- DMA_FREE(dev->dev.parent, sizeof(struct i596_dma),
- (void *)dma, lp->dma_addr);
- return i;
- }
-
- DEB(DEB_PROBE, printk(KERN_INFO "%s: 82596 at %#3lx, %pM IRQ %d.\n",
- dev->name, dev->base_addr, dev->dev_addr,
- dev->irq));
- DEB(DEB_INIT, printk(KERN_INFO
- "%s: dma at 0x%p (%d bytes), lp->scb at 0x%p\n",
- dev->name, dma, (int)sizeof(struct i596_dma),
- &dma->scb));
-
- return 0;
-}
-
-#ifdef CONFIG_NET_POLL_CONTROLLER
-static void i596_poll_controller(struct net_device *dev)
-{
- disable_irq(dev->irq);
- i596_interrupt(dev->irq, dev);
- enable_irq(dev->irq);
-}
-#endif
-
-static irqreturn_t i596_interrupt(int irq, void *dev_id)
-{
- struct net_device *dev = dev_id;
- struct i596_private *lp;
- struct i596_dma *dma;
- unsigned short status, ack_cmd = 0;
-
- lp = netdev_priv(dev);
- dma = lp->dma;
-
- spin_lock (&lp->lock);
-
- wait_cmd(dev, dma, 100, "i596 interrupt, timeout");
- status = SWAP16(dma->scb.status);
-
- DEB(DEB_INTS, printk(KERN_DEBUG
- "%s: i596 interrupt, IRQ %d, status %4.4x.\n",
- dev->name, dev->irq, status));
-
- ack_cmd = status & 0xf000;
-
- if (!ack_cmd) {
- DEB(DEB_ERRORS, printk(KERN_DEBUG
- "%s: interrupt with no events\n",
- dev->name));
- spin_unlock (&lp->lock);
- return IRQ_NONE;
- }
-
- if ((status & 0x8000) || (status & 0x2000)) {
- struct i596_cmd *ptr;
-
- if ((status & 0x8000))
- DEB(DEB_INTS,
- printk(KERN_DEBUG
- "%s: i596 interrupt completed command.\n",
- dev->name));
- if ((status & 0x2000))
- DEB(DEB_INTS,
- printk(KERN_DEBUG
- "%s: i596 interrupt command unit inactive %x.\n",
- dev->name, status & 0x0700));
-
- while (lp->cmd_head != NULL) {
- DMA_INV(dev, lp->cmd_head, sizeof(struct i596_cmd));
- if (!(lp->cmd_head->status & SWAP16(STAT_C)))
- break;
-
- ptr = lp->cmd_head;
-
- DEB(DEB_STATUS,
- printk(KERN_DEBUG
- "cmd_head->status = %04x, ->command = %04x\n",
- SWAP16(lp->cmd_head->status),
- SWAP16(lp->cmd_head->command)));
- lp->cmd_head = ptr->v_next;
- lp->cmd_backlog--;
-
- switch (SWAP16(ptr->command) & 0x7) {
- case CmdTx:
- {
- struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr;
- struct sk_buff *skb = tx_cmd->skb;
-
- if (ptr->status & SWAP16(STAT_OK)) {
- DEB(DEB_TXADDR,
- print_eth(skb->data, "tx-done"));
- } else {
- dev->stats.tx_errors++;
- if (ptr->status & SWAP16(0x0020))
- dev->stats.collisions++;
- if (!(ptr->status & SWAP16(0x0040)))
- dev->stats.tx_heartbeat_errors++;
- if (ptr->status & SWAP16(0x0400))
- dev->stats.tx_carrier_errors++;
- if (ptr->status & SWAP16(0x0800))
- dev->stats.collisions++;
- if (ptr->status & SWAP16(0x1000))
- dev->stats.tx_aborted_errors++;
- }
- dma_unmap_single(dev->dev.parent,
- tx_cmd->dma_addr,
- skb->len, DMA_TO_DEVICE);
- dev_kfree_skb_irq(skb);
-
- tx_cmd->cmd.command = 0; /* Mark free */
- break;
- }
- case CmdTDR:
- {
- unsigned short status = SWAP16(((struct tdr_cmd *)ptr)->status);
-
- if (status & 0x8000) {
- DEB(DEB_ANY,
- printk(KERN_DEBUG "%s: link ok.\n",
- dev->name));
- } else {
- if (status & 0x4000)
- printk(KERN_ERR
- "%s: Transceiver problem.\n",
- dev->name);
- if (status & 0x2000)
- printk(KERN_ERR
- "%s: Termination problem.\n",
- dev->name);
- if (status & 0x1000)
- printk(KERN_ERR
- "%s: Short circuit.\n",
- dev->name);
-
- DEB(DEB_TDR,
- printk(KERN_DEBUG "%s: Time %d.\n",
- dev->name, status & 0x07ff));
- }
- break;
- }
- case CmdConfigure:
- /*
- * Zap command so set_multicast_list() know
- * it is free
- */
- ptr->command = 0;
- break;
- }
- ptr->v_next = NULL;
- ptr->b_next = I596_NULL;
- DMA_WBACK(dev, ptr, sizeof(struct i596_cmd));
- lp->last_cmd = jiffies;
- }
-
- /* This mess is arranging that only the last of any outstanding
- * commands has the interrupt bit set. Should probably really
- * only add to the cmd queue when the CU is stopped.
- */
- ptr = lp->cmd_head;
- while ((ptr != NULL) && (ptr != lp->cmd_tail)) {
- struct i596_cmd *prev = ptr;
-
- ptr->command &= SWAP16(0x1fff);
- ptr = ptr->v_next;
- DMA_WBACK_INV(dev, prev, sizeof(struct i596_cmd));
- }
-
- if (lp->cmd_head != NULL)
- ack_cmd |= CUC_START;
- dma->scb.cmd = SWAP32(virt_to_dma(lp, &lp->cmd_head->status));
- DMA_WBACK_INV(dev, &dma->scb, sizeof(struct i596_scb));
- }
- if ((status & 0x1000) || (status & 0x4000)) {
- if ((status & 0x4000))
- DEB(DEB_INTS,
- printk(KERN_DEBUG
- "%s: i596 interrupt received a frame.\n",
- dev->name));
- i596_rx(dev);
- /* Only RX_START if stopped - RGH 07-07-96 */
- if (status & 0x1000) {
- if (netif_running(dev)) {
- DEB(DEB_ERRORS,
- printk(KERN_DEBUG
- "%s: i596 interrupt receive unit inactive, status 0x%x\n",
- dev->name, status));
- ack_cmd |= RX_START;
- dev->stats.rx_errors++;
- dev->stats.rx_fifo_errors++;
- rebuild_rx_bufs(dev);
- }
- }
- }
- wait_cmd(dev, dma, 100, "i596 interrupt, timeout");
- dma->scb.command = SWAP16(ack_cmd);
- DMA_WBACK(dev, &dma->scb, sizeof(struct i596_scb));
-
- /* DANGER: I suspect that some kind of interrupt
- acknowledgement aside from acking the 82596 might be needed
- here... but it's running acceptably without */
-
- ca(dev);
-
- wait_cmd(dev, dma, 100, "i596 interrupt, exit timeout");
- DEB(DEB_INTS, printk(KERN_DEBUG "%s: exiting interrupt.\n", dev->name));
-
- spin_unlock (&lp->lock);
- return IRQ_HANDLED;
-}
-
-static int i596_close(struct net_device *dev)
-{
- struct i596_private *lp = netdev_priv(dev);
- unsigned long flags;
-
- netif_stop_queue(dev);
-
- DEB(DEB_INIT,
- printk(KERN_DEBUG
- "%s: Shutting down ethercard, status was %4.4x.\n",
- dev->name, SWAP16(lp->dma->scb.status)));
-
- spin_lock_irqsave(&lp->lock, flags);
-
- wait_cmd(dev, lp->dma, 100, "close1 timed out");
- lp->dma->scb.command = SWAP16(CUC_ABORT | RX_ABORT);
- DMA_WBACK(dev, &lp->dma->scb, sizeof(struct i596_scb));
-
- ca(dev);
-
- wait_cmd(dev, lp->dma, 100, "close2 timed out");
- spin_unlock_irqrestore(&lp->lock, flags);
- DEB(DEB_STRUCT, i596_display_data(dev));
- i596_cleanup_cmd(dev, lp);
-
- free_irq(dev->irq, dev);
- remove_rx_bufs(dev);
-
- return 0;
-}
-
-/*
- * Set or clear the multicast filter for this adaptor.
- */
-
-static void set_multicast_list(struct net_device *dev)
-{
- struct i596_private *lp = netdev_priv(dev);
- struct i596_dma *dma = lp->dma;
- int config = 0, cnt;
-
- DEB(DEB_MULTI,
- printk(KERN_DEBUG
- "%s: set multicast list, %d entries, promisc %s, allmulti %s\n",
- dev->name, netdev_mc_count(dev),
- dev->flags & IFF_PROMISC ? "ON" : "OFF",
- dev->flags & IFF_ALLMULTI ? "ON" : "OFF"));
-
- if ((dev->flags & IFF_PROMISC) &&
- !(dma->cf_cmd.i596_config[8] & 0x01)) {
- dma->cf_cmd.i596_config[8] |= 0x01;
- config = 1;
- }
- if (!(dev->flags & IFF_PROMISC) &&
- (dma->cf_cmd.i596_config[8] & 0x01)) {
- dma->cf_cmd.i596_config[8] &= ~0x01;
- config = 1;
- }
- if ((dev->flags & IFF_ALLMULTI) &&
- (dma->cf_cmd.i596_config[11] & 0x20)) {
- dma->cf_cmd.i596_config[11] &= ~0x20;
- config = 1;
- }
- if (!(dev->flags & IFF_ALLMULTI) &&
- !(dma->cf_cmd.i596_config[11] & 0x20)) {
- dma->cf_cmd.i596_config[11] |= 0x20;
- config = 1;
- }
- if (config) {
- if (dma->cf_cmd.cmd.command)
- printk(KERN_INFO
- "%s: config change request already queued\n",
- dev->name);
- else {
- dma->cf_cmd.cmd.command = SWAP16(CmdConfigure);
- DMA_WBACK_INV(dev, &dma->cf_cmd, sizeof(struct cf_cmd));
- i596_add_cmd(dev, &dma->cf_cmd.cmd);
- }
- }
-
- cnt = netdev_mc_count(dev);
- if (cnt > MAX_MC_CNT) {
- cnt = MAX_MC_CNT;
- printk(KERN_NOTICE "%s: Only %d multicast addresses supported",
- dev->name, cnt);
- }
-
- if (!netdev_mc_empty(dev)) {
- struct netdev_hw_addr *ha;
- unsigned char *cp;
- struct mc_cmd *cmd;
-
- cmd = &dma->mc_cmd;
- cmd->cmd.command = SWAP16(CmdMulticastList);
- cmd->mc_cnt = SWAP16(netdev_mc_count(dev) * 6);
- cp = cmd->mc_addrs;
- netdev_for_each_mc_addr(ha, dev) {
- if (!cnt--)
- break;
- memcpy(cp, ha->addr, 6);
- if (i596_debug > 1)
- DEB(DEB_MULTI,
- printk(KERN_DEBUG
- "%s: Adding address %pM\n",
- dev->name, cp));
- cp += 6;
- }
- DMA_WBACK_INV(dev, &dma->mc_cmd, sizeof(struct mc_cmd));
- i596_add_cmd(dev, &cmd->cmd);
- }
-}
+++ /dev/null
-/* Intel Professional Workstation/panther ethernet driver */
-/* lp486e.c: A panther 82596 ethernet driver for linux. */
-/*
- History and copyrights:
-
- Driver skeleton
- Written 1993 by Donald Becker.
- Copyright 1993 United States Government as represented by the Director,
- National Security Agency. This software may only be used and
- distributed according to the terms of the GNU General Public License
- as modified by SRC, incorporated herein by reference.
-
- The author may be reached as becker@scyld.com, or C/O
- Scyld Computing Corporation
- 410 Severn Ave., Suite 210
- Annapolis MD 21403
-
- Apricot
- Written 1994 by Mark Evans.
- This driver is for the Apricot 82596 bus-master interface
-
- Modularised 12/94 Mark Evans
-
- Professional Workstation
- Derived from apricot.c by Ard van Breemen
- <ard@murphy.nl>|<ard@cstmel.hobby.nl>|<ard@cstmel.nl.eu.org>
-
- Credits:
- Thanks to Murphy Software BV for letting me write this in their time.
- Well, actually, I get paid doing this...
- (Also: see http://www.murphy.nl for murphy, and my homepage ~ard for
- more information on the Professional Workstation)
-
- Present version
- aeb@cwi.nl
-*/
-/*
- There are currently two motherboards that I know of in the
- professional workstation. The only one that I know is the
- intel panther motherboard. -- ard
-*/
-/*
-The pws is equipped with an intel 82596. This is a very intelligent controller
-which runs its own micro-code. Communication with the hostprocessor is done
-through linked lists of commands and buffers in the hostprocessors memory.
-A complete description of the 82596 is available from intel. Search for
-a file called "29021806.pdf". It is a complete description of the chip itself.
-To use it for the pws some additions are needed regarding generation of
-the PORT and CA signal, and the interrupt glue needed for a pc.
-I/O map:
-PORT SIZE ACTION MEANING
-0xCB0 2 WRITE Lower 16 bits for PORT command
-0xCB2 2 WRITE Upper 16 bits for PORT command, and issue of PORT command
-0xCB4 1 WRITE Generation of CA signal
-0xCB8 1 WRITE Clear interrupt glue
-All other communication is through memory!
-*/
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/bitops.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-
-#define DRV_NAME "lp486e"
-
-/* debug print flags */
-#define LOG_SRCDST 0x80000000
-#define LOG_STATINT 0x40000000
-#define LOG_STARTINT 0x20000000
-
-#define i596_debug debug
-
-static int i596_debug = 0;
-
-static const char * const medianame[] = {
- "10baseT", "AUI",
- "10baseT-FD", "AUI-FD",
-};
-
-#define LP486E_TOTAL_SIZE 16
-
-#define I596_NULL (0xffffffff)
-
-#define CMD_EOL 0x8000 /* The last command of the list, stop. */
-#define CMD_SUSP 0x4000 /* Suspend after doing cmd. */
-#define CMD_INTR 0x2000 /* Interrupt after doing cmd. */
-
-#define CMD_FLEX 0x0008 /* Enable flexible memory model */
-
-enum commands {
- CmdNOP = 0,
- CmdIASetup = 1,
- CmdConfigure = 2,
- CmdMulticastList = 3,
- CmdTx = 4,
- CmdTDR = 5,
- CmdDump = 6,
- CmdDiagnose = 7
-};
-
-#if 0
-static const char *CUcmdnames[8] = { "NOP", "IASetup", "Configure", "MulticastList",
- "Tx", "TDR", "Dump", "Diagnose" };
-#endif
-
-/* Status word bits */
-#define STAT_CX 0x8000 /* The CU finished executing a command
- with the Interrupt bit set */
-#define STAT_FR 0x4000 /* The RU finished receiving a frame */
-#define STAT_CNA 0x2000 /* The CU left the active state */
-#define STAT_RNR 0x1000 /* The RU left the active state */
-#define STAT_ACK (STAT_CX | STAT_FR | STAT_CNA | STAT_RNR)
-#define STAT_CUS 0x0700 /* Status of CU: 0: idle, 1: suspended,
- 2: active, 3-7: unused */
-#define STAT_RUS 0x00f0 /* Status of RU: 0: idle, 1: suspended,
- 2: no resources, 4: ready,
- 10: no resources due to no more RBDs,
- 12: no more RBDs, other: unused */
-#define STAT_T 0x0008 /* Bus throttle timers loaded */
-#define STAT_ZERO 0x0807 /* Always zero */
-
-#if 0
-static char *CUstates[8] = {
- "idle", "suspended", "active", 0, 0, 0, 0, 0
-};
-static char *RUstates[16] = {
- "idle", "suspended", "no resources", 0, "ready", 0, 0, 0,
- 0, 0, "no RBDs", 0, "out of RBDs", 0, 0, 0
-};
-
-static void
-i596_out_status(int status) {
- int bad = 0;
- char *s;
-
- printk("status %4.4x:", status);
- if (status == 0xffff)
- printk(" strange..\n");
- else {
- if (status & STAT_CX)
- printk(" CU done");
- if (status & STAT_CNA)
- printk(" CU stopped");
- if (status & STAT_FR)
- printk(" got a frame");
- if (status & STAT_RNR)
- printk(" RU stopped");
- if (status & STAT_T)
- printk(" throttled");
- if (status & STAT_ZERO)
- bad = 1;
- s = CUstates[(status & STAT_CUS) >> 8];
- if (!s)
- bad = 1;
- else
- printk(" CU(%s)", s);
- s = RUstates[(status & STAT_RUS) >> 4];
- if (!s)
- bad = 1;
- else
- printk(" RU(%s)", s);
- if (bad)
- printk(" bad status");
- printk("\n");
- }
-}
-#endif
-
-/* Command word bits */
-#define ACK_CX 0x8000
-#define ACK_FR 0x4000
-#define ACK_CNA 0x2000
-#define ACK_RNR 0x1000
-
-#define CUC_START 0x0100
-#define CUC_RESUME 0x0200
-#define CUC_SUSPEND 0x0300
-#define CUC_ABORT 0x0400
-
-#define RX_START 0x0010
-#define RX_RESUME 0x0020
-#define RX_SUSPEND 0x0030
-#define RX_ABORT 0x0040
-
-typedef u32 phys_addr;
-
-static inline phys_addr
-va_to_pa(void *x) {
- return x ? virt_to_bus(x) : I596_NULL;
-}
-
-static inline void *
-pa_to_va(phys_addr x) {
- return (x == I596_NULL) ? NULL : bus_to_virt(x);
-}
-
-/* status bits for cmd */
-#define CMD_STAT_C 0x8000 /* CU command complete */
-#define CMD_STAT_B 0x4000 /* CU command in progress */
-#define CMD_STAT_OK 0x2000 /* CU command completed without errors */
-#define CMD_STAT_A 0x1000 /* CU command abnormally terminated */
-
-struct i596_cmd { /* 8 bytes */
- unsigned short status;
- unsigned short command;
- phys_addr pa_next; /* va_to_pa(struct i596_cmd *next) */
-};
-
-#define EOF 0x8000
-#define SIZE_MASK 0x3fff
-
-struct i596_tbd {
- unsigned short size;
- unsigned short pad;
- phys_addr pa_next; /* va_to_pa(struct i596_tbd *next) */
- phys_addr pa_data; /* va_to_pa(char *data) */
- struct sk_buff *skb;
-};
-
-struct tx_cmd {
- struct i596_cmd cmd;
- phys_addr pa_tbd; /* va_to_pa(struct i596_tbd *tbd) */
- unsigned short size;
- unsigned short pad;
-};
-
-/* status bits for rfd */
-#define RFD_STAT_C 0x8000 /* Frame reception complete */
-#define RFD_STAT_B 0x4000 /* Frame reception in progress */
-#define RFD_STAT_OK 0x2000 /* Frame received without errors */
-#define RFD_STATUS 0x1fff
-#define RFD_LENGTH_ERR 0x1000
-#define RFD_CRC_ERR 0x0800
-#define RFD_ALIGN_ERR 0x0400
-#define RFD_NOBUFS_ERR 0x0200
-#define RFD_DMA_ERR 0x0100 /* DMA overrun failure to acquire system bus */
-#define RFD_SHORT_FRAME_ERR 0x0080
-#define RFD_NOEOP_ERR 0x0040
-#define RFD_TRUNC_ERR 0x0020
-#define RFD_MULTICAST 0x0002 /* 0: destination had our address
- 1: destination was broadcast/multicast */
-#define RFD_COLLISION 0x0001
-
-/* receive frame descriptor */
-struct i596_rfd {
- unsigned short stat;
- unsigned short cmd;
- phys_addr pa_next; /* va_to_pa(struct i596_rfd *next) */
- phys_addr pa_rbd; /* va_to_pa(struct i596_rbd *rbd) */
- unsigned short count;
- unsigned short size;
- char data[1532];
-};
-
-#define RBD_EL 0x8000
-#define RBD_P 0x4000
-#define RBD_SIZEMASK 0x3fff
-#define RBD_EOF 0x8000
-#define RBD_F 0x4000
-
-/* receive buffer descriptor */
-struct i596_rbd {
- unsigned short size;
- unsigned short pad;
- phys_addr pa_next; /* va_to_pa(struct i596_tbd *next) */
- phys_addr pa_data; /* va_to_pa(char *data) */
- phys_addr pa_prev; /* va_to_pa(struct i596_tbd *prev) */
-
- /* Driver private part */
- struct sk_buff *skb;
-};
-
-#define RX_RING_SIZE 64
-#define RX_SKBSIZE (ETH_FRAME_LEN+10)
-#define RX_RBD_SIZE 32
-
-/* System Control Block - 40 bytes */
-struct i596_scb {
- u16 status; /* 0 */
- u16 command; /* 2 */
- phys_addr pa_cmd; /* 4 - va_to_pa(struct i596_cmd *cmd) */
- phys_addr pa_rfd; /* 8 - va_to_pa(struct i596_rfd *rfd) */
- u32 crc_err; /* 12 */
- u32 align_err; /* 16 */
- u32 resource_err; /* 20 */
- u32 over_err; /* 24 */
- u32 rcvdt_err; /* 28 */
- u32 short_err; /* 32 */
- u16 t_on; /* 36 */
- u16 t_off; /* 38 */
-};
-
-/* Intermediate System Configuration Pointer - 8 bytes */
-struct i596_iscp {
- u32 busy; /* 0 */
- phys_addr pa_scb; /* 4 - va_to_pa(struct i596_scb *scb) */
-};
-
-/* System Configuration Pointer - 12 bytes */
-struct i596_scp {
- u32 sysbus; /* 0 */
- u32 pad; /* 4 */
- phys_addr pa_iscp; /* 8 - va_to_pa(struct i596_iscp *iscp) */
-};
-
-/* Selftest and dump results - needs 16-byte alignment */
-/*
- * The size of the dump area is 304 bytes. When the dump is executed
- * by the Port command an extra word will be appended to the dump area.
- * The extra word is a copy of the Dump status word (containing the
- * C, B, OK bits). [I find 0xa006, with a0 for C+OK and 6 for dump]
- */
-struct i596_dump {
- u16 dump[153]; /* (304 = 130h) + 2 bytes */
-};
-
-struct i596_private { /* aligned to a 16-byte boundary */
- struct i596_scp scp; /* 0 - needs 16-byte alignment */
- struct i596_iscp iscp; /* 12 */
- struct i596_scb scb; /* 20 */
- u32 dummy; /* 60 */
- struct i596_dump dump; /* 64 - needs 16-byte alignment */
-
- struct i596_cmd set_add;
- char eth_addr[8]; /* directly follows set_add */
-
- struct i596_cmd set_conf;
- char i596_config[16]; /* directly follows set_conf */
-
- struct i596_cmd tdr;
- unsigned long tdr_stat; /* directly follows tdr */
-
- int last_restart;
- struct i596_rbd *rbd_list;
- struct i596_rbd *rbd_tail;
- struct i596_rfd *rx_tail;
- struct i596_cmd *cmd_tail;
- struct i596_cmd *cmd_head;
- int cmd_backlog;
- unsigned long last_cmd;
- spinlock_t cmd_lock;
-};
-
-static char init_setup[14] = {
- 0x8E, /* length 14 bytes, prefetch on */
- 0xC8, /* default: fifo to 8, monitor off */
- 0x40, /* default: don't save bad frames (apricot.c had 0x80) */
- 0x2E, /* (default is 0x26)
- No source address insertion, 8 byte preamble */
- 0x00, /* default priority and backoff */
- 0x60, /* default interframe spacing */
- 0x00, /* default slot time LSB */
- 0xf2, /* default slot time and nr of retries */
- 0x00, /* default various bits
- (0: promiscuous mode, 1: broadcast disable,
- 2: encoding mode, 3: transmit on no CRS,
- 4: no CRC insertion, 5: CRC type,
- 6: bit stuffing, 7: padding) */
- 0x00, /* default carrier sense and collision detect */
- 0x40, /* default minimum frame length */
- 0xff, /* (default is 0xff, and that is what apricot.c has;
- elp486.c has 0xfb: Enable crc append in memory.) */
- 0x00, /* default: not full duplex */
- 0x7f /* (default is 0x3f) multi IA */
-};
-
-static int i596_open(struct net_device *dev);
-static netdev_tx_t i596_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t i596_interrupt(int irq, void *dev_id);
-static int i596_close(struct net_device *dev);
-static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd);
-static void print_eth(char *);
-static void set_multicast_list(struct net_device *dev);
-static void i596_tx_timeout(struct net_device *dev);
-
-static int
-i596_timeout(struct net_device *dev, char *msg, int ct) {
- struct i596_private *lp;
- int boguscnt = ct;
-
- lp = netdev_priv(dev);
- while (lp->scb.command) {
- if (--boguscnt == 0) {
- printk("%s: %s timed out - stat %4.4x, cmd %4.4x\n",
- dev->name, msg,
- lp->scb.status, lp->scb.command);
- return 1;
- }
- udelay(5);
- barrier();
- }
- return 0;
-}
-
-static inline int
-init_rx_bufs(struct net_device *dev, int num) {
- struct i596_private *lp;
- struct i596_rfd *rfd;
- int i;
- // struct i596_rbd *rbd;
-
- lp = netdev_priv(dev);
- lp->scb.pa_rfd = I596_NULL;
-
- for (i = 0; i < num; i++) {
- rfd = kmalloc(sizeof(struct i596_rfd), GFP_KERNEL);
- if (rfd == NULL)
- break;
-
- rfd->stat = 0;
- rfd->pa_rbd = I596_NULL;
- rfd->count = 0;
- rfd->size = 1532;
- if (i == 0) {
- rfd->cmd = CMD_EOL;
- lp->rx_tail = rfd;
- } else {
- rfd->cmd = 0;
- }
- rfd->pa_next = lp->scb.pa_rfd;
- lp->scb.pa_rfd = va_to_pa(rfd);
- lp->rx_tail->pa_next = lp->scb.pa_rfd;
- }
-
-#if 0
- for (i = 0; i<RX_RBD_SIZE; i++) {
- rbd = kmalloc(sizeof(struct i596_rbd), GFP_KERNEL);
- if (rbd) {
- rbd->pad = 0;
- rbd->count = 0;
- rbd->skb = dev_alloc_skb(RX_SKBSIZE);
- if (!rbd->skb) {
- printk("dev_alloc_skb failed");
- }
- rbd->next = rfd->rbd;
- if (i) {
- rfd->rbd->prev = rbd;
- rbd->size = RX_SKBSIZE;
- } else {
- rbd->size = (RX_SKBSIZE | RBD_EL);
- lp->rbd_tail = rbd;
- }
-
- rfd->rbd = rbd;
- } else {
- printk("Could not kmalloc rbd\n");
- }
- }
- lp->rbd_tail->next = rfd->rbd;
-#endif
- return i;
-}
-
-static inline void
-remove_rx_bufs(struct net_device *dev) {
- struct i596_private *lp;
- struct i596_rfd *rfd;
-
- lp = netdev_priv(dev);
- lp->rx_tail->pa_next = I596_NULL;
-
- do {
- rfd = pa_to_va(lp->scb.pa_rfd);
- lp->scb.pa_rfd = rfd->pa_next;
- kfree(rfd);
- } while (rfd != lp->rx_tail);
-
- lp->rx_tail = NULL;
-
-#if 0
- for (lp->rbd_list) {
- }
-#endif
-}
-
-#define PORT_RESET 0x00 /* reset 82596 */
-#define PORT_SELFTEST 0x01 /* selftest */
-#define PORT_ALTSCP 0x02 /* alternate SCB address */
-#define PORT_DUMP 0x03 /* dump */
-
-#define IOADDR 0xcb0 /* real constant */
-#define IRQ 10 /* default IRQ - can be changed by ECU */
-
-/* The 82596 requires two 16-bit write cycles for a port command */
-static inline void
-PORT(phys_addr a, unsigned int cmd) {
- if (a & 0xf)
- printk("lp486e.c: PORT: address not aligned\n");
- outw(((a & 0xffff) | cmd), IOADDR);
- outw(((a>>16) & 0xffff), IOADDR+2);
-}
-
-static inline void
-CA(void) {
- outb(0, IOADDR+4);
- udelay(8);
-}
-
-static inline void
-CLEAR_INT(void) {
- outb(0, IOADDR+8);
-}
-
-#if 0
-/* selftest or dump */
-static void
-i596_port_do(struct net_device *dev, int portcmd, char *cmdname) {
- struct i596_private *lp = netdev_priv(dev);
- u16 *outp;
- int i, m;
-
- memset((void *)&(lp->dump), 0, sizeof(struct i596_dump));
- outp = &(lp->dump.dump[0]);
-
- PORT(va_to_pa(outp), portcmd);
- mdelay(30); /* random, unmotivated */
-
- printk("lp486e i82596 %s result:\n", cmdname);
- for (m = ARRAY_SIZE(lp->dump.dump); m && lp->dump.dump[m-1] == 0; m--)
- ;
- for (i = 0; i < m; i++) {
- printk(" %04x", lp->dump.dump[i]);
- if (i%8 == 7)
- printk("\n");
- }
- printk("\n");
-}
-#endif
-
-static int
-i596_scp_setup(struct net_device *dev) {
- struct i596_private *lp = netdev_priv(dev);
- int boguscnt;
-
- /* Setup SCP, ISCP, SCB */
- /*
- * sysbus bits:
- * only a single byte is significant - here 0x44
- * 0x80: big endian mode (details depend on stepping)
- * 0x40: 1
- * 0x20: interrupt pin is active low
- * 0x10: lock function disabled
- * 0x08: external triggering of bus throttle timers
- * 0x06: 00: 82586 compat mode, 01: segmented mode, 10: linear mode
- * 0x01: unused
- */
- lp->scp.sysbus = 0x00440000; /* linear mode */
- lp->scp.pad = 0; /* must be zero */
- lp->scp.pa_iscp = va_to_pa(&(lp->iscp));
-
- /*
- * The CPU sets the ISCP to 1 before it gives the first CA()
- */
- lp->iscp.busy = 0x0001;
- lp->iscp.pa_scb = va_to_pa(&(lp->scb));
-
- lp->scb.command = 0;
- lp->scb.status = 0;
- lp->scb.pa_cmd = I596_NULL;
- /* lp->scb.pa_rfd has been initialised already */
-
- lp->last_cmd = jiffies;
- lp->cmd_backlog = 0;
- lp->cmd_head = NULL;
-
- /*
- * Reset the 82596.
- * We need to wait 10 systemclock cycles, and
- * 5 serial clock cycles.
- */
- PORT(0, PORT_RESET); /* address part ignored */
- udelay(100);
-
- /*
- * Before the CA signal is asserted, the default SCP address
- * (0x00fffff4) can be changed to a 16-byte aligned value
- */
- PORT(va_to_pa(&lp->scp), PORT_ALTSCP); /* change the scp address */
-
- /*
- * The initialization procedure begins when a
- * Channel Attention signal is asserted after a reset.
- */
-
- CA();
-
- /*
- * The ISCP busy is cleared by the 82596 after the SCB address is read.
- */
- boguscnt = 100;
- while (lp->iscp.busy) {
- if (--boguscnt == 0) {
- /* No i82596 present? */
- printk("%s: i82596 initialization timed out\n",
- dev->name);
- return 1;
- }
- udelay(5);
- barrier();
- }
- /* I find here boguscnt==100, so no delay was required. */
-
- return 0;
-}
-
-static int
-init_i596(struct net_device *dev) {
- struct i596_private *lp;
-
- if (i596_scp_setup(dev))
- return 1;
-
- lp = netdev_priv(dev);
- lp->scb.command = 0;
-
- memcpy ((void *)lp->i596_config, init_setup, 14);
- lp->set_conf.command = CmdConfigure;
- i596_add_cmd(dev, (void *)&lp->set_conf);
-
- memcpy ((void *)lp->eth_addr, dev->dev_addr, 6);
- lp->set_add.command = CmdIASetup;
- i596_add_cmd(dev, (struct i596_cmd *)&lp->set_add);
-
- lp->tdr.command = CmdTDR;
- i596_add_cmd(dev, (struct i596_cmd *)&lp->tdr);
-
- if (lp->scb.command && i596_timeout(dev, "i82596 init", 200))
- return 1;
-
- lp->scb.command = RX_START;
- CA();
-
- barrier();
-
- if (lp->scb.command && i596_timeout(dev, "Receive Unit start", 100))
- return 1;
-
- return 0;
-}
-
-/* Receive a single frame */
-static inline int
-i596_rx_one(struct net_device *dev, struct i596_private *lp,
- struct i596_rfd *rfd, int *frames) {
-
- if (rfd->stat & RFD_STAT_OK) {
- /* a good frame */
- int pkt_len = (rfd->count & 0x3fff);
- struct sk_buff *skb = dev_alloc_skb(pkt_len);
-
- (*frames)++;
-
- if (rfd->cmd & CMD_EOL)
- printk("Received on EOL\n");
-
- if (skb == NULL) {
- printk ("%s: i596_rx Memory squeeze, "
- "dropping packet.\n", dev->name);
- dev->stats.rx_dropped++;
- return 1;
- }
-
- memcpy(skb_put(skb,pkt_len), rfd->data, pkt_len);
-
- skb->protocol = eth_type_trans(skb,dev);
- netif_rx(skb);
- dev->stats.rx_packets++;
- } else {
-#if 0
- printk("Frame reception error status %04x\n",
- rfd->stat);
-#endif
- dev->stats.rx_errors++;
- if (rfd->stat & RFD_COLLISION)
- dev->stats.collisions++;
- if (rfd->stat & RFD_SHORT_FRAME_ERR)
- dev->stats.rx_length_errors++;
- if (rfd->stat & RFD_DMA_ERR)
- dev->stats.rx_over_errors++;
- if (rfd->stat & RFD_NOBUFS_ERR)
- dev->stats.rx_fifo_errors++;
- if (rfd->stat & RFD_ALIGN_ERR)
- dev->stats.rx_frame_errors++;
- if (rfd->stat & RFD_CRC_ERR)
- dev->stats.rx_crc_errors++;
- if (rfd->stat & RFD_LENGTH_ERR)
- dev->stats.rx_length_errors++;
- }
- rfd->stat = rfd->count = 0;
- return 0;
-}
-
-static int
-i596_rx(struct net_device *dev) {
- struct i596_private *lp = netdev_priv(dev);
- struct i596_rfd *rfd;
- int frames = 0;
-
- while (1) {
- rfd = pa_to_va(lp->scb.pa_rfd);
- if (!rfd) {
- printk(KERN_ERR "i596_rx: NULL rfd?\n");
- return 0;
- }
-#if 1
- if (rfd->stat && !(rfd->stat & (RFD_STAT_C | RFD_STAT_B)))
- printk("SF:%p-%04x\n", rfd, rfd->stat);
-#endif
- if (!(rfd->stat & RFD_STAT_C))
- break; /* next one not ready */
- if (i596_rx_one(dev, lp, rfd, &frames))
- break; /* out of memory */
- rfd->cmd = CMD_EOL;
- lp->rx_tail->cmd = 0;
- lp->rx_tail = rfd;
- lp->scb.pa_rfd = rfd->pa_next;
- barrier();
- }
-
- return frames;
-}
-
-static void
-i596_cleanup_cmd(struct net_device *dev) {
- struct i596_private *lp;
- struct i596_cmd *cmd;
-
- lp = netdev_priv(dev);
- while (lp->cmd_head) {
- cmd = (struct i596_cmd *)lp->cmd_head;
-
- lp->cmd_head = pa_to_va(lp->cmd_head->pa_next);
- lp->cmd_backlog--;
-
- switch ((cmd->command) & 0x7) {
- case CmdTx: {
- struct tx_cmd *tx_cmd = (struct tx_cmd *) cmd;
- struct i596_tbd * tx_cmd_tbd;
- tx_cmd_tbd = pa_to_va(tx_cmd->pa_tbd);
-
- dev_kfree_skb_any(tx_cmd_tbd->skb);
-
- dev->stats.tx_errors++;
- dev->stats.tx_aborted_errors++;
-
- cmd->pa_next = I596_NULL;
- kfree((unsigned char *)tx_cmd);
- netif_wake_queue(dev);
- break;
- }
- case CmdMulticastList: {
- // unsigned short count = *((unsigned short *) (ptr + 1));
-
- cmd->pa_next = I596_NULL;
- kfree((unsigned char *)cmd);
- break;
- }
- default: {
- cmd->pa_next = I596_NULL;
- break;
- }
- }
- barrier();
- }
-
- if (lp->scb.command && i596_timeout(dev, "i596_cleanup_cmd", 100))
- ;
-
- lp->scb.pa_cmd = va_to_pa(lp->cmd_head);
-}
-
-static void i596_reset(struct net_device *dev, struct i596_private *lp, int ioaddr) {
-
- if (lp->scb.command && i596_timeout(dev, "i596_reset", 100))
- ;
-
- netif_stop_queue(dev);
-
- lp->scb.command = CUC_ABORT | RX_ABORT;
- CA();
- barrier();
-
- /* wait for shutdown */
- if (lp->scb.command && i596_timeout(dev, "i596_reset(2)", 400))
- ;
-
- i596_cleanup_cmd(dev);
- i596_rx(dev);
-
- netif_start_queue(dev);
- /*dev_kfree_skb(skb, FREE_WRITE);*/
- init_i596(dev);
-}
-
-static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd) {
- struct i596_private *lp = netdev_priv(dev);
- int ioaddr = dev->base_addr;
- unsigned long flags;
-
- cmd->status = 0;
- cmd->command |= (CMD_EOL | CMD_INTR);
- cmd->pa_next = I596_NULL;
-
- spin_lock_irqsave(&lp->cmd_lock, flags);
-
- if (lp->cmd_head) {
- lp->cmd_tail->pa_next = va_to_pa(cmd);
- } else {
- lp->cmd_head = cmd;
- if (lp->scb.command && i596_timeout(dev, "i596_add_cmd", 100))
- ;
- lp->scb.pa_cmd = va_to_pa(cmd);
- lp->scb.command = CUC_START;
- CA();
- }
- lp->cmd_tail = cmd;
- lp->cmd_backlog++;
-
- lp->cmd_head = pa_to_va(lp->scb.pa_cmd);
- spin_unlock_irqrestore(&lp->cmd_lock, flags);
-
- if (lp->cmd_backlog > 16) {
- int tickssofar = jiffies - lp->last_cmd;
- if (tickssofar < HZ/4)
- return;
-
- printk(KERN_WARNING "%s: command unit timed out, status resetting.\n", dev->name);
- i596_reset(dev, lp, ioaddr);
- }
-}
-
-static int i596_open(struct net_device *dev)
-{
- int i;
-
- i = request_irq(dev->irq, i596_interrupt, IRQF_SHARED, dev->name, dev);
- if (i) {
- printk(KERN_ERR "%s: IRQ %d not free\n", dev->name, dev->irq);
- return i;
- }
-
- if ((i = init_rx_bufs(dev, RX_RING_SIZE)) < RX_RING_SIZE)
- printk(KERN_ERR "%s: only able to allocate %d receive buffers\n", dev->name, i);
-
- if (i < 4) {
- free_irq(dev->irq, dev);
- return -EAGAIN;
- }
- netif_start_queue(dev);
- init_i596(dev);
- return 0; /* Always succeed */
-}
-
-static netdev_tx_t i596_start_xmit (struct sk_buff *skb, struct net_device *dev) {
- struct tx_cmd *tx_cmd;
- short length;
-
- length = skb->len;
-
- if (length < ETH_ZLEN) {
- if (skb_padto(skb, ETH_ZLEN))
- return NETDEV_TX_OK;
- length = ETH_ZLEN;
- }
-
- tx_cmd = kmalloc((sizeof (struct tx_cmd) + sizeof (struct i596_tbd)), GFP_ATOMIC);
- if (tx_cmd == NULL) {
- printk(KERN_WARNING "%s: i596_xmit Memory squeeze, dropping packet.\n", dev->name);
- dev->stats.tx_dropped++;
- dev_kfree_skb (skb);
- } else {
- struct i596_tbd *tx_cmd_tbd;
- tx_cmd_tbd = (struct i596_tbd *) (tx_cmd + 1);
- tx_cmd->pa_tbd = va_to_pa (tx_cmd_tbd);
- tx_cmd_tbd->pa_next = I596_NULL;
-
- tx_cmd->cmd.command = (CMD_FLEX | CmdTx);
-
- tx_cmd->pad = 0;
- tx_cmd->size = 0;
- tx_cmd_tbd->pad = 0;
- tx_cmd_tbd->size = (EOF | length);
-
- tx_cmd_tbd->pa_data = va_to_pa (skb->data);
- tx_cmd_tbd->skb = skb;
-
- if (i596_debug & LOG_SRCDST)
- print_eth (skb->data);
-
- i596_add_cmd (dev, (struct i596_cmd *) tx_cmd);
-
- dev->stats.tx_packets++;
- }
-
- return NETDEV_TX_OK;
-}
-
-static void
-i596_tx_timeout (struct net_device *dev) {
- struct i596_private *lp = netdev_priv(dev);
- int ioaddr = dev->base_addr;
-
- /* Transmitter timeout, serious problems. */
- printk(KERN_WARNING "%s: transmit timed out, status resetting.\n", dev->name);
- dev->stats.tx_errors++;
-
- /* Try to restart the adaptor */
- if (lp->last_restart == dev->stats.tx_packets) {
- printk ("Resetting board.\n");
-
- /* Shutdown and restart */
- i596_reset (dev, lp, ioaddr);
- } else {
- /* Issue a channel attention signal */
- printk ("Kicking board.\n");
- lp->scb.command = (CUC_START | RX_START);
- CA();
- lp->last_restart = dev->stats.tx_packets;
- }
- netif_wake_queue(dev);
-}
-
-static void print_eth(char *add)
-{
- int i;
-
- printk ("Dest ");
- for (i = 0; i < 6; i++)
- printk(" %2.2X", (unsigned char) add[i]);
- printk ("\n");
-
- printk ("Source");
- for (i = 0; i < 6; i++)
- printk(" %2.2X", (unsigned char) add[i+6]);
- printk ("\n");
-
- printk ("type %2.2X%2.2X\n",
- (unsigned char) add[12], (unsigned char) add[13]);
-}
-
-static const struct net_device_ops i596_netdev_ops = {
- .ndo_open = i596_open,
- .ndo_stop = i596_close,
- .ndo_start_xmit = i596_start_xmit,
- .ndo_set_multicast_list = set_multicast_list,
- .ndo_tx_timeout = i596_tx_timeout,
- .ndo_change_mtu = eth_change_mtu,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-static int __init lp486e_probe(struct net_device *dev) {
- struct i596_private *lp;
- unsigned char eth_addr[6] = { 0, 0xaa, 0, 0, 0, 0 };
- unsigned char *bios;
- int i, j;
- int ret = -ENOMEM;
- static int probed;
-
- if (probed)
- return -ENODEV;
- probed++;
-
- if (!request_region(IOADDR, LP486E_TOTAL_SIZE, DRV_NAME)) {
- printk(KERN_ERR "lp486e: IO address 0x%x in use\n", IOADDR);
- return -EBUSY;
- }
-
- lp = netdev_priv(dev);
- spin_lock_init(&lp->cmd_lock);
-
- /*
- * Do we really have this thing?
- */
- if (i596_scp_setup(dev)) {
- ret = -ENODEV;
- goto err_out_kfree;
- }
-
- dev->base_addr = IOADDR;
- dev->irq = IRQ;
-
-
- /*
- * How do we find the ethernet address? I don't know.
- * One possibility is to look at the EISA configuration area
- * [0xe8000-0xe9fff]. This contains the ethernet address
- * but not at a fixed address - things depend on setup options.
- *
- * If we find no address, or the wrong address, use
- * ifconfig eth0 hw ether a1:a2:a3:a4:a5:a6
- * with the value found in the BIOS setup.
- */
- bios = bus_to_virt(0xe8000);
- for (j = 0; j < 0x2000; j++) {
- if (bios[j] == 0 && bios[j+1] == 0xaa && bios[j+2] == 0) {
- printk("%s: maybe address at BIOS 0x%x:",
- dev->name, 0xe8000+j);
- for (i = 0; i < 6; i++) {
- eth_addr[i] = bios[i+j];
- printk(" %2.2X", eth_addr[i]);
- }
- printk("\n");
- }
- }
-
- printk("%s: lp486e 82596 at %#3lx, IRQ %d,",
- dev->name, dev->base_addr, dev->irq);
- for (i = 0; i < 6; i++)
- printk(" %2.2X", dev->dev_addr[i] = eth_addr[i]);
- printk("\n");
-
- /* The LP486E-specific entries in the device structure. */
- dev->netdev_ops = &i596_netdev_ops;
- dev->watchdog_timeo = 5*HZ;
-
-#if 0
- /* selftest reports 0x320925ae - don't know what that means */
- i596_port_do(dev, PORT_SELFTEST, "selftest");
- i596_port_do(dev, PORT_DUMP, "dump");
-#endif
- return 0;
-
-err_out_kfree:
- release_region(IOADDR, LP486E_TOTAL_SIZE);
- return ret;
-}
-
-static inline void
-i596_handle_CU_completion(struct net_device *dev,
- struct i596_private *lp,
- unsigned short status,
- unsigned short *ack_cmdp) {
- struct i596_cmd *cmd;
- int frames_out = 0;
- int commands_done = 0;
- int cmd_val;
- unsigned long flags;
-
- spin_lock_irqsave(&lp->cmd_lock, flags);
- cmd = lp->cmd_head;
-
- while (lp->cmd_head && (lp->cmd_head->status & CMD_STAT_C)) {
- cmd = lp->cmd_head;
-
- lp->cmd_head = pa_to_va(lp->cmd_head->pa_next);
- lp->cmd_backlog--;
-
- commands_done++;
- cmd_val = cmd->command & 0x7;
-#if 0
- printk("finished CU %s command (%d)\n",
- CUcmdnames[cmd_val], cmd_val);
-#endif
- switch (cmd_val) {
- case CmdTx:
- {
- struct tx_cmd *tx_cmd;
- struct i596_tbd *tx_cmd_tbd;
-
- tx_cmd = (struct tx_cmd *) cmd;
- tx_cmd_tbd = pa_to_va(tx_cmd->pa_tbd);
-
- frames_out++;
- if (cmd->status & CMD_STAT_OK) {
- if (i596_debug)
- print_eth(pa_to_va(tx_cmd_tbd->pa_data));
- } else {
- dev->stats.tx_errors++;
- if (i596_debug)
- printk("transmission failure:%04x\n",
- cmd->status);
- if (cmd->status & 0x0020)
- dev->stats.collisions++;
- if (!(cmd->status & 0x0040))
- dev->stats.tx_heartbeat_errors++;
- if (cmd->status & 0x0400)
- dev->stats.tx_carrier_errors++;
- if (cmd->status & 0x0800)
- dev->stats.collisions++;
- if (cmd->status & 0x1000)
- dev->stats.tx_aborted_errors++;
- }
- dev_kfree_skb_irq(tx_cmd_tbd->skb);
-
- cmd->pa_next = I596_NULL;
- kfree((unsigned char *)tx_cmd);
- netif_wake_queue(dev);
- break;
- }
-
- case CmdMulticastList:
- cmd->pa_next = I596_NULL;
- kfree((unsigned char *)cmd);
- break;
-
- case CmdTDR:
- {
- unsigned long status = *((unsigned long *) (cmd + 1));
- if (status & 0x8000) {
- if (i596_debug)
- printk("%s: link ok.\n", dev->name);
- } else {
- if (status & 0x4000)
- printk("%s: Transceiver problem.\n",
- dev->name);
- if (status & 0x2000)
- printk("%s: Termination problem.\n",
- dev->name);
- if (status & 0x1000)
- printk("%s: Short circuit.\n",
- dev->name);
- printk("%s: Time %ld.\n",
- dev->name, status & 0x07ff);
- }
- }
- default:
- cmd->pa_next = I596_NULL;
- lp->last_cmd = jiffies;
-
- }
- barrier();
- }
-
- cmd = lp->cmd_head;
- while (cmd && (cmd != lp->cmd_tail)) {
- cmd->command &= 0x1fff;
- cmd = pa_to_va(cmd->pa_next);
- barrier();
- }
-
- if (lp->cmd_head)
- *ack_cmdp |= CUC_START;
- lp->scb.pa_cmd = va_to_pa(lp->cmd_head);
- spin_unlock_irqrestore(&lp->cmd_lock, flags);
-}
-
-static irqreturn_t
-i596_interrupt(int irq, void *dev_instance)
-{
- struct net_device *dev = dev_instance;
- struct i596_private *lp = netdev_priv(dev);
- unsigned short status, ack_cmd = 0;
- int frames_in = 0;
-
- /*
- * The 82596 examines the command, performs the required action,
- * and then clears the SCB command word.
- */
- if (lp->scb.command && i596_timeout(dev, "interrupt", 40))
- ;
-
- /*
- * The status word indicates the status of the 82596.
- * It is modified only by the 82596.
- *
- * [So, we must not clear it. I find often status 0xffff,
- * which is not one of the values allowed by the docs.]
- */
- status = lp->scb.status;
-#if 0
- if (i596_debug) {
- printk("%s: i596 interrupt, ", dev->name);
- i596_out_status(status);
- }
-#endif
- /* Impossible, but it happens - perhaps when we get
- a receive interrupt but scb.pa_rfd is I596_NULL. */
- if (status == 0xffff) {
- printk("%s: i596_interrupt: got status 0xffff\n", dev->name);
- goto out;
- }
-
- ack_cmd = (status & STAT_ACK);
-
- if (status & (STAT_CX | STAT_CNA))
- i596_handle_CU_completion(dev, lp, status, &ack_cmd);
-
- if (status & (STAT_FR | STAT_RNR)) {
- /* Restart the receive unit when it got inactive somehow */
- if ((status & STAT_RNR) && netif_running(dev))
- ack_cmd |= RX_START;
-
- if (status & STAT_FR) {
- frames_in = i596_rx(dev);
- if (!frames_in)
- printk("receive frame reported, but no frames\n");
- }
- }
-
- /* acknowledge the interrupt */
- /*
- if ((lp->scb.pa_cmd != I596_NULL) && netif_running(dev))
- ack_cmd |= CUC_START;
- */
-
- if (lp->scb.command && i596_timeout(dev, "i596 interrupt", 100))
- ;
-
- lp->scb.command = ack_cmd;
-
- CLEAR_INT();
- CA();
-
- out:
- return IRQ_HANDLED;
-}
-
-static int i596_close(struct net_device *dev) {
- struct i596_private *lp = netdev_priv(dev);
-
- netif_stop_queue(dev);
-
- if (i596_debug)
- printk("%s: Shutting down ethercard, status was %4.4x.\n",
- dev->name, lp->scb.status);
-
- lp->scb.command = (CUC_ABORT | RX_ABORT);
- CA();
-
- i596_cleanup_cmd(dev);
-
- if (lp->scb.command && i596_timeout(dev, "i596_close", 200))
- ;
-
- free_irq(dev->irq, dev);
- remove_rx_bufs(dev);
-
- return 0;
-}
-
-/*
-* Set or clear the multicast filter for this adaptor.
-*/
-
-static void set_multicast_list(struct net_device *dev) {
- struct i596_private *lp = netdev_priv(dev);
- struct i596_cmd *cmd;
-
- if (i596_debug > 1)
- printk ("%s: set multicast list %d\n",
- dev->name, netdev_mc_count(dev));
-
- if (!netdev_mc_empty(dev)) {
- struct netdev_hw_addr *ha;
- char *cp;
- cmd = kmalloc(sizeof(struct i596_cmd) + 2 +
- netdev_mc_count(dev) * 6, GFP_ATOMIC);
- if (cmd == NULL) {
- printk (KERN_ERR "%s: set_multicast Memory squeeze.\n", dev->name);
- return;
- }
- cmd->command = CmdMulticastList;
- *((unsigned short *) (cmd + 1)) = netdev_mc_count(dev) * 6;
- cp = ((char *)(cmd + 1))+2;
- netdev_for_each_mc_addr(ha, dev) {
- memcpy(cp, ha->addr, 6);
- cp += 6;
- }
- if (i596_debug & LOG_SRCDST)
- print_eth (((char *)(cmd + 1)) + 2);
- i596_add_cmd(dev, cmd);
- } else {
- if (lp->set_conf.pa_next != I596_NULL) {
- return;
- }
- if (netdev_mc_empty(dev) &&
- !(dev->flags & (IFF_PROMISC | IFF_ALLMULTI))) {
- lp->i596_config[8] &= ~0x01;
- } else {
- lp->i596_config[8] |= 0x01;
- }
-
- i596_add_cmd(dev, (struct i596_cmd *) &lp->set_conf);
- }
-}
-
-MODULE_AUTHOR("Ard van Breemen <ard@cstmel.nl.eu.org>");
-MODULE_DESCRIPTION("Intel Panther onboard i82596 driver");
-MODULE_LICENSE("GPL");
-
-static struct net_device *dev_lp486e;
-static int full_duplex;
-static int options;
-static int io = IOADDR;
-static int irq = IRQ;
-
-module_param(debug, int, 0);
-//module_param(max_interrupt_work, int, 0);
-//module_param(reverse_probe, int, 0);
-//module_param(rx_copybreak, int, 0);
-module_param(options, int, 0);
-module_param(full_duplex, int, 0);
-
-static int __init lp486e_init_module(void) {
- int err;
- struct net_device *dev = alloc_etherdev(sizeof(struct i596_private));
- if (!dev)
- return -ENOMEM;
-
- dev->irq = irq;
- dev->base_addr = io;
- err = lp486e_probe(dev);
- if (err) {
- free_netdev(dev);
- return err;
- }
- err = register_netdev(dev);
- if (err) {
- release_region(dev->base_addr, LP486E_TOTAL_SIZE);
- free_netdev(dev);
- return err;
- }
- dev_lp486e = dev;
- full_duplex = 0;
- options = 0;
- return 0;
-}
-
-static void __exit lp486e_cleanup_module(void) {
- unregister_netdev(dev_lp486e);
- release_region(dev_lp486e->base_addr, LP486E_TOTAL_SIZE);
- free_netdev(dev_lp486e);
-}
-
-module_init(lp486e_init_module);
-module_exit(lp486e_cleanup_module);
+++ /dev/null
-/*
- * net-3-driver for the NI5210 card (i82586 Ethernet chip)
- *
- * This is an extension to the Linux operating system, and is covered by the
- * same GNU General Public License that covers that work.
- *
- * Alphacode 0.82 (96/09/29) for Linux 2.0.0 (or later)
- * Copyrights (c) 1994,1995,1996 by M.Hipp (hippm@informatik.uni-tuebingen.de)
- * [feel free to mail ....]
- *
- * when using as module: (no autoprobing!)
- * run with e.g:
- * insmod ni52.o io=0x360 irq=9 memstart=0xd0000 memend=0xd4000
- *
- * CAN YOU PLEASE REPORT ME YOUR PERFORMANCE EXPERIENCES !!.
- *
- * If you find a bug, please report me:
- * The kernel panic output and any kmsg from the ni52 driver
- * the ni5210-driver-version and the linux-kernel version
- * how many shared memory (memsize) on the netcard,
- * bootprom: yes/no, base_addr, mem_start
- * maybe the ni5210-card revision and the i82586 version
- *
- * autoprobe for: base_addr: 0x300,0x280,0x360,0x320,0x340
- * mem_start: 0xd0000,0xd2000,0xc8000,0xca000,0xd4000,0xd6000,
- * 0xd8000,0xcc000,0xce000,0xda000,0xdc000
- *
- * sources:
- * skeleton.c from Donald Becker
- *
- * I have also done a look in the following sources: (mail me if you need them)
- * crynwr-packet-driver by Russ Nelson
- * Garret A. Wollman's (fourth) i82586-driver for BSD
- * (before getting an i82596 (yes 596 not 586) manual, the existing drivers
- * helped me a lot to understand this tricky chip.)
- *
- * Known Problems:
- * The internal sysbus seems to be slow. So we often lose packets because of
- * overruns while receiving from a fast remote host.
- * This can slow down TCP connections. Maybe the newer ni5210 cards are
- * better. My experience is, that if a machine sends with more than about
- * 500-600K/s the fifo/sysbus overflows.
- *
- * IMPORTANT NOTE:
- * On fast networks, it's a (very) good idea to have 16K shared memory. With
- * 8K, we can store only 4 receive frames, so it can (easily) happen that a
- * remote machine 'overruns' our system.
- *
- * Known i82586/card problems (I'm sure, there are many more!):
- * Running the NOP-mode, the i82586 sometimes seems to forget to report
- * every xmit-interrupt until we restart the CU.
- * Another MAJOR bug is, that the RU sometimes seems to ignore the EL-Bit
- * in the RBD-Struct which indicates an end of the RBD queue.
- * Instead, the RU fetches another (randomly selected and
- * usually used) RBD and begins to fill it. (Maybe, this happens only if
- * the last buffer from the previous RFD fits exact into the queue and
- * the next RFD can't fetch an initial RBD. Anyone knows more? )
- *
- * results from ftp performance tests with Linux 1.2.5
- * send and receive about 350-400 KByte/s (peak up to 460 kbytes/s)
- * sending in NOP-mode: peak performance up to 530K/s (but better don't
- * run this mode)
- */
-
-/*
- * 29.Sept.96: virt_to_bus changes for new memory scheme
- * 19.Feb.96: more Mcast changes, module support (MH)
- *
- * 18.Nov.95: Mcast changes (AC).
- *
- * 23.April.95: fixed(?) receiving problems by configuring a RFD more
- * than the number of RBD's. Can maybe cause other problems.
- * 18.April.95: Added MODULE support (MH)
- * 17.April.95: MC related changes in init586() and set_multicast_list().
- * removed use of 'jiffies' in init586() (MH)
- *
- * 19.Sep.94: Added Multicast support (not tested yet) (MH)
- *
- * 18.Sep.94: Workaround for 'EL-Bug'. Removed flexible RBD-handling.
- * Now, every RFD has exact one RBD. (MH)
- *
- * 14.Sep.94: added promiscuous mode, a few cleanups (MH)
- *
- * 19.Aug.94: changed request_irq() parameter (MH)
- *
- * 20.July.94: removed cleanup bugs, removed a 16K-mem-probe-bug (MH)
- *
- * 19.July.94: lotsa cleanups .. (MH)
- *
- * 17.July.94: some patches ... verified to run with 1.1.29 (MH)
- *
- * 4.July.94: patches for Linux 1.1.24 (MH)
- *
- * 26.March.94: patches for Linux 1.0 and iomem-auto-probe (MH)
- *
- * 30.Sep.93: Added nop-chain .. driver now runs with only one Xmit-Buff,
- * too (MH)
- *
- * < 30.Sep.93: first versions
- */
-
-static int debuglevel; /* debug-printk 0: off 1: a few 2: more */
-static int automatic_resume; /* experimental .. better should be zero */
-static int rfdadd; /* rfdadd=1 may be better for 8K MEM cards */
-static int fifo = 0x8; /* don't change */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/bitops.h>
-#include <asm/io.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-
-#include "ni52.h"
-
-#define DRV_NAME "ni52"
-
-#define DEBUG /* debug on */
-#define SYSBUSVAL 1 /* 8 Bit */
-
-#define ni_attn586() { outb(0, dev->base_addr + NI52_ATTENTION); }
-#define ni_reset586() { outb(0, dev->base_addr + NI52_RESET); }
-#define ni_disint() { outb(0, dev->base_addr + NI52_INTDIS); }
-#define ni_enaint() { outb(0, dev->base_addr + NI52_INTENA); }
-
-#define make32(ptr16) ((void __iomem *)(p->memtop + (short) (ptr16)))
-#define make24(ptr32) ((char __iomem *)(ptr32)) - p->base
-#define make16(ptr32) ((unsigned short) ((char __iomem *)(ptr32)\
- - p->memtop))
-
-/******************* how to calculate the buffers *****************************
-
- * IMPORTANT NOTE: if you configure only one NUM_XMIT_BUFFS, the driver works
- * --------------- in a different (more stable?) mode. Only in this mode it's
- * possible to configure the driver with 'NO_NOPCOMMANDS'
-
-sizeof(scp)=12; sizeof(scb)=16; sizeof(iscp)=8;
-sizeof(scp)+sizeof(iscp)+sizeof(scb) = 36 = INIT
-sizeof(rfd) = 24; sizeof(rbd) = 12;
-sizeof(tbd) = 8; sizeof(transmit_cmd) = 16;
-sizeof(nop_cmd) = 8;
-
- * if you don't know the driver, better do not change these values: */
-
-#define RECV_BUFF_SIZE 1524 /* slightly oversized */
-#define XMIT_BUFF_SIZE 1524 /* slightly oversized */
-#define NUM_XMIT_BUFFS 1 /* config for both, 8K and 16K shmem */
-#define NUM_RECV_BUFFS_8 4 /* config for 8K shared mem */
-#define NUM_RECV_BUFFS_16 9 /* config for 16K shared mem */
-#define NO_NOPCOMMANDS /* only possible with NUM_XMIT_BUFFS=1 */
-
-/**************************************************************************/
-
-
-#define NI52_TOTAL_SIZE 16
-#define NI52_ADDR0 0x02
-#define NI52_ADDR1 0x07
-#define NI52_ADDR2 0x01
-
-static int ni52_probe1(struct net_device *dev, int ioaddr);
-static irqreturn_t ni52_interrupt(int irq, void *dev_id);
-static int ni52_open(struct net_device *dev);
-static int ni52_close(struct net_device *dev);
-static netdev_tx_t ni52_send_packet(struct sk_buff *, struct net_device *);
-static struct net_device_stats *ni52_get_stats(struct net_device *dev);
-static void set_multicast_list(struct net_device *dev);
-static void ni52_timeout(struct net_device *dev);
-
-/* helper-functions */
-static int init586(struct net_device *dev);
-static int check586(struct net_device *dev, unsigned size);
-static void alloc586(struct net_device *dev);
-static void startrecv586(struct net_device *dev);
-static void __iomem *alloc_rfa(struct net_device *dev, void __iomem *ptr);
-static void ni52_rcv_int(struct net_device *dev);
-static void ni52_xmt_int(struct net_device *dev);
-static void ni52_rnr_int(struct net_device *dev);
-
-struct priv {
- char __iomem *base;
- char __iomem *mapped;
- char __iomem *memtop;
- spinlock_t spinlock;
- int reset;
- struct rfd_struct __iomem *rfd_last, *rfd_top, *rfd_first;
- struct scp_struct __iomem *scp;
- struct iscp_struct __iomem *iscp;
- struct scb_struct __iomem *scb;
- struct tbd_struct __iomem *xmit_buffs[NUM_XMIT_BUFFS];
-#if (NUM_XMIT_BUFFS == 1)
- struct transmit_cmd_struct __iomem *xmit_cmds[2];
- struct nop_cmd_struct __iomem *nop_cmds[2];
-#else
- struct transmit_cmd_struct __iomem *xmit_cmds[NUM_XMIT_BUFFS];
- struct nop_cmd_struct __iomem *nop_cmds[NUM_XMIT_BUFFS];
-#endif
- int nop_point, num_recv_buffs;
- char __iomem *xmit_cbuffs[NUM_XMIT_BUFFS];
- int xmit_count, xmit_last;
-};
-
-/* wait for command with timeout: */
-static void wait_for_scb_cmd(struct net_device *dev)
-{
- struct priv *p = netdev_priv(dev);
- int i;
- for (i = 0; i < 16384; i++) {
- if (readb(&p->scb->cmd_cuc) == 0)
- break;
- udelay(4);
- if (i == 16383) {
- printk(KERN_ERR "%s: scb_cmd timed out: %04x,%04x .. disabling i82586!!\n",
- dev->name, readb(&p->scb->cmd_cuc), readb(&p->scb->cus));
- if (!p->reset) {
- p->reset = 1;
- ni_reset586();
- }
- }
- }
-}
-
-static void wait_for_scb_cmd_ruc(struct net_device *dev)
-{
- struct priv *p = netdev_priv(dev);
- int i;
- for (i = 0; i < 16384; i++) {
- if (readb(&p->scb->cmd_ruc) == 0)
- break;
- udelay(4);
- if (i == 16383) {
- printk(KERN_ERR "%s: scb_cmd (ruc) timed out: %04x,%04x .. disabling i82586!!\n",
- dev->name, readb(&p->scb->cmd_ruc),
- readb(&p->scb->rus));
- if (!p->reset) {
- p->reset = 1;
- ni_reset586();
- }
- }
- }
-}
-
-static void wait_for_stat_compl(void __iomem *p)
-{
- struct nop_cmd_struct __iomem *addr = p;
- int i;
- for (i = 0; i < 32767; i++) {
- if (readw(&((addr)->cmd_status)) & STAT_COMPL)
- break;
- udelay(32);
- }
-}
-
-/**********************************************
- * close device
- */
-static int ni52_close(struct net_device *dev)
-{
- free_irq(dev->irq, dev);
- ni_reset586(); /* the hard way to stop the receiver */
- netif_stop_queue(dev);
- return 0;
-}
-
-/**********************************************
- * open device
- */
-static int ni52_open(struct net_device *dev)
-{
- int ret;
-
- ni_disint();
- alloc586(dev);
- init586(dev);
- startrecv586(dev);
- ni_enaint();
-
- ret = request_irq(dev->irq, ni52_interrupt, 0, dev->name, dev);
- if (ret) {
- ni_reset586();
- return ret;
- }
- netif_start_queue(dev);
- return 0; /* most done by init */
-}
-
-static int check_iscp(struct net_device *dev, void __iomem *addr)
-{
- struct iscp_struct __iomem *iscp = addr;
- struct priv *p = netdev_priv(dev);
- memset_io(iscp, 0, sizeof(struct iscp_struct));
-
- writel(make24(iscp), &p->scp->iscp);
- writeb(1, &iscp->busy);
-
- ni_reset586();
- ni_attn586();
- mdelay(32); /* wait a while... */
- /* i82586 clears 'busy' after successful init */
- if (readb(&iscp->busy))
- return 0;
- return 1;
-}
-
-/**********************************************
- * Check to see if there's an 82586 out there.
- */
-static int check586(struct net_device *dev, unsigned size)
-{
- struct priv *p = netdev_priv(dev);
- int i;
-
- p->mapped = ioremap(dev->mem_start, size);
- if (!p->mapped)
- return 0;
-
- p->base = p->mapped + size - 0x01000000;
- p->memtop = p->mapped + size;
- p->scp = (struct scp_struct __iomem *)(p->base + SCP_DEFAULT_ADDRESS);
- p->scb = (struct scb_struct __iomem *) p->mapped;
- p->iscp = (struct iscp_struct __iomem *)p->scp - 1;
- memset_io(p->scp, 0, sizeof(struct scp_struct));
- for (i = 0; i < sizeof(struct scp_struct); i++)
- /* memory was writeable? */
- if (readb((char __iomem *)p->scp + i))
- goto Enodev;
- writeb(SYSBUSVAL, &p->scp->sysbus); /* 1 = 8Bit-Bus, 0 = 16 Bit */
- if (readb(&p->scp->sysbus) != SYSBUSVAL)
- goto Enodev;
-
- if (!check_iscp(dev, p->mapped))
- goto Enodev;
- if (!check_iscp(dev, p->iscp))
- goto Enodev;
- return 1;
-Enodev:
- iounmap(p->mapped);
- return 0;
-}
-
-/******************************************************************
- * set iscp at the right place, called by ni52_probe1 and open586.
- */
-static void alloc586(struct net_device *dev)
-{
- struct priv *p = netdev_priv(dev);
-
- ni_reset586();
- mdelay(32);
-
- memset_io(p->iscp, 0, sizeof(struct iscp_struct));
- memset_io(p->scp , 0, sizeof(struct scp_struct));
-
- writel(make24(p->iscp), &p->scp->iscp);
- writeb(SYSBUSVAL, &p->scp->sysbus);
- writew(make16(p->scb), &p->iscp->scb_offset);
-
- writeb(1, &p->iscp->busy);
- ni_reset586();
- ni_attn586();
-
- mdelay(32);
-
- if (readb(&p->iscp->busy))
- printk(KERN_ERR "%s: Init-Problems (alloc).\n", dev->name);
-
- p->reset = 0;
-
- memset_io(p->scb, 0, sizeof(struct scb_struct));
-}
-
-/* set: io,irq,memstart,memend or set it when calling insmod */
-static int irq = 9;
-static int io = 0x300;
-static long memstart; /* e.g 0xd0000 */
-static long memend; /* e.g 0xd4000 */
-
-/**********************************************
- * probe the ni5210-card
- */
-struct net_device * __init ni52_probe(int unit)
-{
- struct net_device *dev = alloc_etherdev(sizeof(struct priv));
- static const int ports[] = {0x300, 0x280, 0x360, 0x320, 0x340, 0};
- const int *port;
- struct priv *p;
- int err = 0;
-
- if (!dev)
- return ERR_PTR(-ENOMEM);
-
- p = netdev_priv(dev);
-
- if (unit >= 0) {
- sprintf(dev->name, "eth%d", unit);
- netdev_boot_setup_check(dev);
- io = dev->base_addr;
- irq = dev->irq;
- memstart = dev->mem_start;
- memend = dev->mem_end;
- }
-
- if (io > 0x1ff) { /* Check a single specified location. */
- err = ni52_probe1(dev, io);
- } else if (io > 0) { /* Don't probe at all. */
- err = -ENXIO;
- } else {
- for (port = ports; *port && ni52_probe1(dev, *port) ; port++)
- ;
- if (*port)
- goto got_it;
-#ifdef FULL_IO_PROBE
- for (io = 0x200; io < 0x400 && ni52_probe1(dev, io); io += 8)
- ;
- if (io < 0x400)
- goto got_it;
-#endif
- err = -ENODEV;
- }
- if (err)
- goto out;
-got_it:
- err = register_netdev(dev);
- if (err)
- goto out1;
- return dev;
-out1:
- iounmap(p->mapped);
- release_region(dev->base_addr, NI52_TOTAL_SIZE);
-out:
- free_netdev(dev);
- return ERR_PTR(err);
-}
-
-static const struct net_device_ops ni52_netdev_ops = {
- .ndo_open = ni52_open,
- .ndo_stop = ni52_close,
- .ndo_get_stats = ni52_get_stats,
- .ndo_tx_timeout = ni52_timeout,
- .ndo_start_xmit = ni52_send_packet,
- .ndo_set_multicast_list = set_multicast_list,
- .ndo_change_mtu = eth_change_mtu,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-static int __init ni52_probe1(struct net_device *dev, int ioaddr)
-{
- int i, size, retval;
- struct priv *priv = netdev_priv(dev);
-
- dev->base_addr = ioaddr;
- dev->irq = irq;
- dev->mem_start = memstart;
- dev->mem_end = memend;
-
- spin_lock_init(&priv->spinlock);
-
- if (!request_region(ioaddr, NI52_TOTAL_SIZE, DRV_NAME))
- return -EBUSY;
-
- if (!(inb(ioaddr+NI52_MAGIC1) == NI52_MAGICVAL1) ||
- !(inb(ioaddr+NI52_MAGIC2) == NI52_MAGICVAL2)) {
- retval = -ENODEV;
- goto out;
- }
-
- for (i = 0; i < ETH_ALEN; i++)
- dev->dev_addr[i] = inb(dev->base_addr+i);
-
- if (dev->dev_addr[0] != NI52_ADDR0 || dev->dev_addr[1] != NI52_ADDR1 ||
- dev->dev_addr[2] != NI52_ADDR2) {
- retval = -ENODEV;
- goto out;
- }
-
- printk(KERN_INFO "%s: NI5210 found at %#3lx, ",
- dev->name, dev->base_addr);
-
- /*
- * check (or search) IO-Memory, 8K and 16K
- */
-#ifdef MODULE
- size = dev->mem_end - dev->mem_start;
- if (size != 0x2000 && size != 0x4000) {
- printk("\n");
- printk(KERN_ERR "%s: Invalid memory size %d. Allowed is 0x2000 or 0x4000 bytes.\n", dev->name, size);
- retval = -ENODEV;
- goto out;
- }
- if (!check586(dev, size)) {
- printk(KERN_ERR "?memcheck, Can't find memory at 0x%lx with size %d!\n", dev->mem_start, size);
- retval = -ENODEV;
- goto out;
- }
-#else
- if (dev->mem_start != 0) {
- /* no auto-mem-probe */
- size = 0x4000; /* check for 16K mem */
- if (!check586(dev, size)) {
- size = 0x2000; /* check for 8K mem */
- if (!check586(dev, size)) {
- printk(KERN_ERR "?memprobe, Can't find memory at 0x%lx!\n", dev->mem_start);
- retval = -ENODEV;
- goto out;
- }
- }
- } else {
- static const unsigned long memaddrs[] = {
- 0xc8000, 0xca000, 0xcc000, 0xce000, 0xd0000, 0xd2000,
- 0xd4000, 0xd6000, 0xd8000, 0xda000, 0xdc000, 0
- };
- for (i = 0;; i++) {
- if (!memaddrs[i]) {
- printk(KERN_ERR "?memprobe, Can't find io-memory!\n");
- retval = -ENODEV;
- goto out;
- }
- dev->mem_start = memaddrs[i];
- size = 0x2000; /* check for 8K mem */
- if (check586(dev, size))
- /* 8K-check */
- break;
- size = 0x4000; /* check for 16K mem */
- if (check586(dev, size))
- /* 16K-check */
- break;
- }
- }
- /* set mem_end showed by 'ifconfig' */
- dev->mem_end = dev->mem_start + size;
-#endif
-
- alloc586(dev);
-
- /* set number of receive-buffs according to memsize */
- if (size == 0x2000)
- priv->num_recv_buffs = NUM_RECV_BUFFS_8;
- else
- priv->num_recv_buffs = NUM_RECV_BUFFS_16;
-
- printk(KERN_DEBUG "Memaddr: 0x%lx, Memsize: %d, ",
- dev->mem_start, size);
-
- if (dev->irq < 2) {
- unsigned long irq_mask;
-
- irq_mask = probe_irq_on();
- ni_reset586();
- ni_attn586();
-
- mdelay(20);
- dev->irq = probe_irq_off(irq_mask);
- if (!dev->irq) {
- printk("?autoirq, Failed to detect IRQ line!\n");
- retval = -EAGAIN;
- iounmap(priv->mapped);
- goto out;
- }
- printk("IRQ %d (autodetected).\n", dev->irq);
- } else {
- if (dev->irq == 2)
- dev->irq = 9;
- printk("IRQ %d (assigned and not checked!).\n", dev->irq);
- }
-
- dev->netdev_ops = &ni52_netdev_ops;
- dev->watchdog_timeo = HZ/20;
-
- return 0;
-out:
- release_region(ioaddr, NI52_TOTAL_SIZE);
- return retval;
-}
-
-/**********************************************
- * init the chip (ni52-interrupt should be disabled?!)
- * needs a correct 'allocated' memory
- */
-
-static int init586(struct net_device *dev)
-{
- void __iomem *ptr;
- int i, result = 0;
- struct priv *p = netdev_priv(dev);
- struct configure_cmd_struct __iomem *cfg_cmd;
- struct iasetup_cmd_struct __iomem *ias_cmd;
- struct tdr_cmd_struct __iomem *tdr_cmd;
- struct mcsetup_cmd_struct __iomem *mc_cmd;
- struct netdev_hw_addr *ha;
- int num_addrs = netdev_mc_count(dev);
-
- ptr = p->scb + 1;
-
- cfg_cmd = ptr; /* configure-command */
- writew(0, &cfg_cmd->cmd_status);
- writew(CMD_CONFIGURE | CMD_LAST, &cfg_cmd->cmd_cmd);
- writew(0xFFFF, &cfg_cmd->cmd_link);
-
- /* number of cfg bytes */
- writeb(0x0a, &cfg_cmd->byte_cnt);
- /* fifo-limit (8=tx:32/rx:64) */
- writeb(fifo, &cfg_cmd->fifo);
- /* hold or discard bad recv frames (bit 7) */
- writeb(0x40, &cfg_cmd->sav_bf);
- /* addr_len |!src_insert |pre-len |loopback */
- writeb(0x2e, &cfg_cmd->adr_len);
- writeb(0x00, &cfg_cmd->priority);
- writeb(0x60, &cfg_cmd->ifs);
- writeb(0x00, &cfg_cmd->time_low);
- writeb(0xf2, &cfg_cmd->time_high);
- writeb(0x00, &cfg_cmd->promisc);
- if (dev->flags & IFF_ALLMULTI) {
- int len = ((char __iomem *)p->iscp - (char __iomem *)ptr - 8) / 6;
- if (num_addrs > len) {
- printk(KERN_ERR "%s: switching to promisc. mode\n",
- dev->name);
- writeb(0x01, &cfg_cmd->promisc);
- }
- }
- if (dev->flags & IFF_PROMISC)
- writeb(0x01, &cfg_cmd->promisc);
- writeb(0x00, &cfg_cmd->carr_coll);
- writew(make16(cfg_cmd), &p->scb->cbl_offset);
- writeb(0, &p->scb->cmd_ruc);
-
- writeb(CUC_START, &p->scb->cmd_cuc); /* cmd.-unit start */
- ni_attn586();
-
- wait_for_stat_compl(cfg_cmd);
-
- if ((readw(&cfg_cmd->cmd_status) & (STAT_OK|STAT_COMPL)) !=
- (STAT_COMPL|STAT_OK)) {
- printk(KERN_ERR "%s: configure command failed: %x\n",
- dev->name, readw(&cfg_cmd->cmd_status));
- return 1;
- }
-
- /*
- * individual address setup
- */
-
- ias_cmd = ptr;
-
- writew(0, &ias_cmd->cmd_status);
- writew(CMD_IASETUP | CMD_LAST, &ias_cmd->cmd_cmd);
- writew(0xffff, &ias_cmd->cmd_link);
-
- memcpy_toio(&ias_cmd->iaddr, (char *)dev->dev_addr, ETH_ALEN);
-
- writew(make16(ias_cmd), &p->scb->cbl_offset);
-
- writeb(CUC_START, &p->scb->cmd_cuc); /* cmd.-unit start */
- ni_attn586();
-
- wait_for_stat_compl(ias_cmd);
-
- if ((readw(&ias_cmd->cmd_status) & (STAT_OK|STAT_COMPL)) !=
- (STAT_OK|STAT_COMPL)) {
- printk(KERN_ERR "%s (ni52): individual address setup command failed: %04x\n", dev->name, readw(&ias_cmd->cmd_status));
- return 1;
- }
-
- /*
- * TDR, wire check .. e.g. no resistor e.t.c
- */
-
- tdr_cmd = ptr;
-
- writew(0, &tdr_cmd->cmd_status);
- writew(CMD_TDR | CMD_LAST, &tdr_cmd->cmd_cmd);
- writew(0xffff, &tdr_cmd->cmd_link);
- writew(0, &tdr_cmd->status);
-
- writew(make16(tdr_cmd), &p->scb->cbl_offset);
- writeb(CUC_START, &p->scb->cmd_cuc); /* cmd.-unit start */
- ni_attn586();
-
- wait_for_stat_compl(tdr_cmd);
-
- if (!(readw(&tdr_cmd->cmd_status) & STAT_COMPL))
- printk(KERN_ERR "%s: Problems while running the TDR.\n",
- dev->name);
- else {
- udelay(16);
- result = readw(&tdr_cmd->status);
- writeb(readb(&p->scb->cus) & STAT_MASK, &p->scb->cmd_cuc);
- ni_attn586(); /* ack the interrupts */
-
- if (result & TDR_LNK_OK)
- ;
- else if (result & TDR_XCVR_PRB)
- printk(KERN_ERR "%s: TDR: Transceiver problem. Check the cable(s)!\n",
- dev->name);
- else if (result & TDR_ET_OPN)
- printk(KERN_ERR "%s: TDR: No correct termination %d clocks away.\n",
- dev->name, result & TDR_TIMEMASK);
- else if (result & TDR_ET_SRT) {
- /* time == 0 -> strange :-) */
- if (result & TDR_TIMEMASK)
- printk(KERN_ERR "%s: TDR: Detected a short circuit %d clocks away.\n",
- dev->name, result & TDR_TIMEMASK);
- } else
- printk(KERN_ERR "%s: TDR: Unknown status %04x\n",
- dev->name, result);
- }
-
- /*
- * Multicast setup
- */
- if (num_addrs && !(dev->flags & IFF_PROMISC)) {
- mc_cmd = ptr;
- writew(0, &mc_cmd->cmd_status);
- writew(CMD_MCSETUP | CMD_LAST, &mc_cmd->cmd_cmd);
- writew(0xffff, &mc_cmd->cmd_link);
- writew(num_addrs * 6, &mc_cmd->mc_cnt);
-
- i = 0;
- netdev_for_each_mc_addr(ha, dev)
- memcpy_toio(mc_cmd->mc_list[i++], ha->addr, 6);
-
- writew(make16(mc_cmd), &p->scb->cbl_offset);
- writeb(CUC_START, &p->scb->cmd_cuc);
- ni_attn586();
-
- wait_for_stat_compl(mc_cmd);
-
- if ((readw(&mc_cmd->cmd_status) & (STAT_COMPL|STAT_OK))
- != (STAT_COMPL|STAT_OK))
- printk(KERN_ERR "%s: Can't apply multicast-address-list.\n", dev->name);
- }
-
- /*
- * alloc nop/xmit-cmds
- */
-#if (NUM_XMIT_BUFFS == 1)
- for (i = 0; i < 2; i++) {
- p->nop_cmds[i] = ptr;
- writew(CMD_NOP, &p->nop_cmds[i]->cmd_cmd);
- writew(0, &p->nop_cmds[i]->cmd_status);
- writew(make16(p->nop_cmds[i]), &p->nop_cmds[i]->cmd_link);
- ptr = ptr + sizeof(struct nop_cmd_struct);
- }
-#else
- for (i = 0; i < NUM_XMIT_BUFFS; i++) {
- p->nop_cmds[i] = ptr;
- writew(CMD_NOP, &p->nop_cmds[i]->cmd_cmd);
- writew(0, &p->nop_cmds[i]->cmd_status);
- writew(make16(p->nop_cmds[i]), &p->nop_cmds[i]->cmd_link);
- ptr = ptr + sizeof(struct nop_cmd_struct);
- }
-#endif
-
- ptr = alloc_rfa(dev, ptr); /* init receive-frame-area */
-
- /*
- * alloc xmit-buffs / init xmit_cmds
- */
- for (i = 0; i < NUM_XMIT_BUFFS; i++) {
- /* Transmit cmd/buff 0 */
- p->xmit_cmds[i] = ptr;
- ptr = ptr + sizeof(struct transmit_cmd_struct);
- p->xmit_cbuffs[i] = ptr; /* char-buffs */
- ptr = ptr + XMIT_BUFF_SIZE;
- p->xmit_buffs[i] = ptr; /* TBD */
- ptr = ptr + sizeof(struct tbd_struct);
- if ((void __iomem *)ptr > (void __iomem *)p->iscp) {
- printk(KERN_ERR "%s: not enough shared-mem for your configuration!\n",
- dev->name);
- return 1;
- }
- memset_io(p->xmit_cmds[i], 0,
- sizeof(struct transmit_cmd_struct));
- memset_io(p->xmit_buffs[i], 0,
- sizeof(struct tbd_struct));
- writew(make16(p->nop_cmds[(i+1)%NUM_XMIT_BUFFS]),
- &p->xmit_cmds[i]->cmd_link);
- writew(STAT_COMPL, &p->xmit_cmds[i]->cmd_status);
- writew(CMD_XMIT|CMD_INT, &p->xmit_cmds[i]->cmd_cmd);
- writew(make16(p->xmit_buffs[i]), &p->xmit_cmds[i]->tbd_offset);
- writew(0xffff, &p->xmit_buffs[i]->next);
- writel(make24(p->xmit_cbuffs[i]), &p->xmit_buffs[i]->buffer);
- }
-
- p->xmit_count = 0;
- p->xmit_last = 0;
-#ifndef NO_NOPCOMMANDS
- p->nop_point = 0;
-#endif
-
- /*
- * 'start transmitter'
- */
-#ifndef NO_NOPCOMMANDS
- writew(make16(p->nop_cmds[0]), &p->scb->cbl_offset);
- writeb(CUC_START, &p->scb->cmd_cuc);
- ni_attn586();
- wait_for_scb_cmd(dev);
-#else
- writew(make16(p->xmit_cmds[0]), &p->xmit_cmds[0]->cmd_link);
- writew(CMD_XMIT | CMD_SUSPEND | CMD_INT, &p->xmit_cmds[0]->cmd_cmd);
-#endif
-
- /*
- * ack. interrupts
- */
- writeb(readb(&p->scb->cus) & STAT_MASK, &p->scb->cmd_cuc);
- ni_attn586();
- udelay(16);
-
- ni_enaint();
-
- return 0;
-}
-
-/******************************************************
- * This is a helper routine for ni52_rnr_int() and init586().
- * It sets up the Receive Frame Area (RFA).
- */
-
-static void __iomem *alloc_rfa(struct net_device *dev, void __iomem *ptr)
-{
- struct rfd_struct __iomem *rfd = ptr;
- struct rbd_struct __iomem *rbd;
- int i;
- struct priv *p = netdev_priv(dev);
-
- memset_io(rfd, 0,
- sizeof(struct rfd_struct) * (p->num_recv_buffs + rfdadd));
- p->rfd_first = rfd;
-
- for (i = 0; i < (p->num_recv_buffs + rfdadd); i++) {
- writew(make16(rfd + (i+1) % (p->num_recv_buffs+rfdadd)),
- &rfd[i].next);
- writew(0xffff, &rfd[i].rbd_offset);
- }
- /* RU suspend */
- writeb(RFD_SUSP, &rfd[p->num_recv_buffs-1+rfdadd].last);
-
- ptr = rfd + (p->num_recv_buffs + rfdadd);
-
- rbd = ptr;
- ptr = rbd + p->num_recv_buffs;
-
- /* clr descriptors */
- memset_io(rbd, 0, sizeof(struct rbd_struct) * (p->num_recv_buffs));
-
- for (i = 0; i < p->num_recv_buffs; i++) {
- writew(make16(rbd + (i+1) % p->num_recv_buffs), &rbd[i].next);
- writew(RECV_BUFF_SIZE, &rbd[i].size);
- writel(make24(ptr), &rbd[i].buffer);
- ptr = ptr + RECV_BUFF_SIZE;
- }
- p->rfd_top = p->rfd_first;
- p->rfd_last = p->rfd_first + (p->num_recv_buffs - 1 + rfdadd);
-
- writew(make16(p->rfd_first), &p->scb->rfa_offset);
- writew(make16(rbd), &p->rfd_first->rbd_offset);
-
- return ptr;
-}
-
-
-/**************************************************
- * Interrupt Handler ...
- */
-
-static irqreturn_t ni52_interrupt(int irq, void *dev_id)
-{
- struct net_device *dev = dev_id;
- unsigned int stat;
- int cnt = 0;
- struct priv *p;
-
- p = netdev_priv(dev);
-
- if (debuglevel > 1)
- printk("I");
-
- spin_lock(&p->spinlock);
-
- wait_for_scb_cmd(dev); /* wait for last command */
-
- while ((stat = readb(&p->scb->cus) & STAT_MASK)) {
- writeb(stat, &p->scb->cmd_cuc);
- ni_attn586();
-
- if (stat & STAT_FR) /* received a frame */
- ni52_rcv_int(dev);
-
- if (stat & STAT_RNR) { /* RU went 'not ready' */
- printk("(R)");
- if (readb(&p->scb->rus) & RU_SUSPEND) {
- /* special case: RU_SUSPEND */
- wait_for_scb_cmd(dev);
- writeb(RUC_RESUME, &p->scb->cmd_ruc);
- ni_attn586();
- wait_for_scb_cmd_ruc(dev);
- } else {
- printk(KERN_ERR "%s: Receiver-Unit went 'NOT READY': %04x/%02x.\n",
- dev->name, stat, readb(&p->scb->rus));
- ni52_rnr_int(dev);
- }
- }
-
- /* Command with I-bit set complete */
- if (stat & STAT_CX)
- ni52_xmt_int(dev);
-
-#ifndef NO_NOPCOMMANDS
- if (stat & STAT_CNA) { /* CU went 'not ready' */
- if (netif_running(dev))
- printk(KERN_ERR "%s: oops! CU has left active state. stat: %04x/%02x.\n",
- dev->name, stat, readb(&p->scb->cus));
- }
-#endif
-
- if (debuglevel > 1)
- printk("%d", cnt++);
-
- /* Wait for ack. (ni52_xmt_int can be faster than ack!!) */
- wait_for_scb_cmd(dev);
- if (readb(&p->scb->cmd_cuc)) { /* timed out? */
- printk(KERN_ERR "%s: Acknowledge timed out.\n",
- dev->name);
- ni_disint();
- break;
- }
- }
- spin_unlock(&p->spinlock);
-
- if (debuglevel > 1)
- printk("i");
- return IRQ_HANDLED;
-}
-
-/*******************************************************
- * receive-interrupt
- */
-
-static void ni52_rcv_int(struct net_device *dev)
-{
- int status, cnt = 0;
- unsigned short totlen;
- struct sk_buff *skb;
- struct rbd_struct __iomem *rbd;
- struct priv *p = netdev_priv(dev);
-
- if (debuglevel > 0)
- printk("R");
-
- for (; (status = readb(&p->rfd_top->stat_high)) & RFD_COMPL;) {
- rbd = make32(readw(&p->rfd_top->rbd_offset));
- if (status & RFD_OK) { /* frame received without error? */
- totlen = readw(&rbd->status);
- if (totlen & RBD_LAST) {
- /* the first and the last buffer? */
- totlen &= RBD_MASK; /* length of this frame */
- writew(0x00, &rbd->status);
- skb = (struct sk_buff *)dev_alloc_skb(totlen+2);
- if (skb != NULL) {
- skb_reserve(skb, 2);
- skb_put(skb, totlen);
- memcpy_fromio(skb->data, p->base + readl(&rbd->buffer), totlen);
- skb->protocol = eth_type_trans(skb, dev);
- netif_rx(skb);
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += totlen;
- } else
- dev->stats.rx_dropped++;
- } else {
- int rstat;
- /* free all RBD's until RBD_LAST is set */
- totlen = 0;
- while (!((rstat = readw(&rbd->status)) & RBD_LAST)) {
- totlen += rstat & RBD_MASK;
- if (!rstat) {
- printk(KERN_ERR "%s: Whoops .. no end mark in RBD list\n", dev->name);
- break;
- }
- writew(0, &rbd->status);
- rbd = make32(readw(&rbd->next));
- }
- totlen += rstat & RBD_MASK;
- writew(0, &rbd->status);
- printk(KERN_ERR "%s: received oversized frame! length: %d\n",
- dev->name, totlen);
- dev->stats.rx_dropped++;
- }
- } else {/* frame !(ok), only with 'save-bad-frames' */
- printk(KERN_ERR "%s: oops! rfd-error-status: %04x\n",
- dev->name, status);
- dev->stats.rx_errors++;
- }
- writeb(0, &p->rfd_top->stat_high);
- writeb(RFD_SUSP, &p->rfd_top->last); /* maybe exchange by RFD_LAST */
- writew(0xffff, &p->rfd_top->rbd_offset);
- writeb(0, &p->rfd_last->last); /* delete RFD_SUSP */
- p->rfd_last = p->rfd_top;
- p->rfd_top = make32(readw(&p->rfd_top->next)); /* step to next RFD */
- writew(make16(p->rfd_top), &p->scb->rfa_offset);
-
- if (debuglevel > 0)
- printk("%d", cnt++);
- }
-
- if (automatic_resume) {
- wait_for_scb_cmd(dev);
- writeb(RUC_RESUME, &p->scb->cmd_ruc);
- ni_attn586();
- wait_for_scb_cmd_ruc(dev);
- }
-
-#ifdef WAIT_4_BUSY
- {
- int i;
- for (i = 0; i < 1024; i++) {
- if (p->rfd_top->status)
- break;
- udelay(16);
- if (i == 1023)
- printk(KERN_ERR "%s: RU hasn't fetched next RFD (not busy/complete)\n", dev->name);
- }
- }
-#endif
- if (debuglevel > 0)
- printk("r");
-}
-
-/**********************************************************
- * handle 'Receiver went not ready'.
- */
-
-static void ni52_rnr_int(struct net_device *dev)
-{
- struct priv *p = netdev_priv(dev);
-
- dev->stats.rx_errors++;
-
- wait_for_scb_cmd(dev); /* wait for the last cmd, WAIT_4_FULLSTAT?? */
- writeb(RUC_ABORT, &p->scb->cmd_ruc); /* usually the RU is in the 'no resource'-state .. abort it now. */
- ni_attn586();
- wait_for_scb_cmd_ruc(dev); /* wait for accept cmd. */
-
- alloc_rfa(dev, p->rfd_first);
- /* maybe add a check here, before restarting the RU */
- startrecv586(dev); /* restart RU */
-
- printk(KERN_ERR "%s: Receive-Unit restarted. Status: %04x\n",
- dev->name, readb(&p->scb->rus));
-
-}
-
-/**********************************************************
- * handle xmit - interrupt
- */
-
-static void ni52_xmt_int(struct net_device *dev)
-{
- int status;
- struct priv *p = netdev_priv(dev);
-
- if (debuglevel > 0)
- printk("X");
-
- status = readw(&p->xmit_cmds[p->xmit_last]->cmd_status);
- if (!(status & STAT_COMPL))
- printk(KERN_ERR "%s: strange .. xmit-int without a 'COMPLETE'\n", dev->name);
-
- if (status & STAT_OK) {
- dev->stats.tx_packets++;
- dev->stats.collisions += (status & TCMD_MAXCOLLMASK);
- } else {
- dev->stats.tx_errors++;
- if (status & TCMD_LATECOLL) {
- printk(KERN_ERR "%s: late collision detected.\n",
- dev->name);
- dev->stats.collisions++;
- } else if (status & TCMD_NOCARRIER) {
- dev->stats.tx_carrier_errors++;
- printk(KERN_ERR "%s: no carrier detected.\n",
- dev->name);
- } else if (status & TCMD_LOSTCTS)
- printk(KERN_ERR "%s: loss of CTS detected.\n",
- dev->name);
- else if (status & TCMD_UNDERRUN) {
- dev->stats.tx_fifo_errors++;
- printk(KERN_ERR "%s: DMA underrun detected.\n",
- dev->name);
- } else if (status & TCMD_MAXCOLL) {
- printk(KERN_ERR "%s: Max. collisions exceeded.\n",
- dev->name);
- dev->stats.collisions += 16;
- }
- }
-#if (NUM_XMIT_BUFFS > 1)
- if ((++p->xmit_last) == NUM_XMIT_BUFFS)
- p->xmit_last = 0;
-#endif
- netif_wake_queue(dev);
-}
-
-/***********************************************************
- * (re)start the receiver
- */
-
-static void startrecv586(struct net_device *dev)
-{
- struct priv *p = netdev_priv(dev);
-
- wait_for_scb_cmd(dev);
- wait_for_scb_cmd_ruc(dev);
- writew(make16(p->rfd_first), &p->scb->rfa_offset);
- writeb(RUC_START, &p->scb->cmd_ruc);
- ni_attn586(); /* start cmd. */
- wait_for_scb_cmd_ruc(dev);
- /* wait for accept cmd. (no timeout!!) */
-}
-
-static void ni52_timeout(struct net_device *dev)
-{
- struct priv *p = netdev_priv(dev);
-#ifndef NO_NOPCOMMANDS
- if (readb(&p->scb->cus) & CU_ACTIVE) { /* COMMAND-UNIT active? */
- netif_wake_queue(dev);
-#ifdef DEBUG
- printk(KERN_ERR "%s: strange ... timeout with CU active?!?\n",
- dev->name);
- printk(KERN_ERR "%s: X0: %04x N0: %04x N1: %04x %d\n",
- dev->name, (int)p->xmit_cmds[0]->cmd_status,
- readw(&p->nop_cmds[0]->cmd_status),
- readw(&p->nop_cmds[1]->cmd_status),
- p->nop_point);
-#endif
- writeb(CUC_ABORT, &p->scb->cmd_cuc);
- ni_attn586();
- wait_for_scb_cmd(dev);
- writew(make16(p->nop_cmds[p->nop_point]), &p->scb->cbl_offset);
- writeb(CUC_START, &p->scb->cmd_cuc);
- ni_attn586();
- wait_for_scb_cmd(dev);
- dev->trans_start = jiffies; /* prevent tx timeout */
- return 0;
- }
-#endif
- {
-#ifdef DEBUG
- printk(KERN_ERR "%s: xmitter timed out, try to restart! stat: %02x\n",
- dev->name, readb(&p->scb->cus));
- printk(KERN_ERR "%s: command-stats: %04x %04x\n",
- dev->name,
- readw(&p->xmit_cmds[0]->cmd_status),
- readw(&p->xmit_cmds[1]->cmd_status));
- printk(KERN_ERR "%s: check, whether you set the right interrupt number!\n",
- dev->name);
-#endif
- ni52_close(dev);
- ni52_open(dev);
- }
- dev->trans_start = jiffies; /* prevent tx timeout */
-}
-
-/******************************************************
- * send frame
- */
-
-static netdev_tx_t ni52_send_packet(struct sk_buff *skb,
- struct net_device *dev)
-{
- int len, i;
-#ifndef NO_NOPCOMMANDS
- int next_nop;
-#endif
- struct priv *p = netdev_priv(dev);
-
- if (skb->len > XMIT_BUFF_SIZE) {
- printk(KERN_ERR "%s: Sorry, max. framelength is %d bytes. The length of your frame is %d bytes.\n", dev->name, XMIT_BUFF_SIZE, skb->len);
- return NETDEV_TX_OK;
- }
-
- netif_stop_queue(dev);
-
- memcpy_toio(p->xmit_cbuffs[p->xmit_count], skb->data, skb->len);
- len = skb->len;
- if (len < ETH_ZLEN) {
- len = ETH_ZLEN;
- memset_io(p->xmit_cbuffs[p->xmit_count]+skb->len, 0,
- len - skb->len);
- }
-
-#if (NUM_XMIT_BUFFS == 1)
-# ifdef NO_NOPCOMMANDS
-
-#ifdef DEBUG
- if (readb(&p->scb->cus) & CU_ACTIVE) {
- printk(KERN_ERR "%s: Hmmm .. CU is still running and we wanna send a new packet.\n", dev->name);
- printk(KERN_ERR "%s: stat: %04x %04x\n",
- dev->name, readb(&p->scb->cus),
- readw(&p->xmit_cmds[0]->cmd_status));
- }
-#endif
- writew(TBD_LAST | len, &p->xmit_buffs[0]->size);
- for (i = 0; i < 16; i++) {
- writew(0, &p->xmit_cmds[0]->cmd_status);
- wait_for_scb_cmd(dev);
- if ((readb(&p->scb->cus) & CU_STATUS) == CU_SUSPEND)
- writeb(CUC_RESUME, &p->scb->cmd_cuc);
- else {
- writew(make16(p->xmit_cmds[0]), &p->scb->cbl_offset);
- writeb(CUC_START, &p->scb->cmd_cuc);
- }
- ni_attn586();
- if (!i)
- dev_kfree_skb(skb);
- wait_for_scb_cmd(dev);
- /* test it, because CU sometimes doesn't start immediately */
- if (readb(&p->scb->cus) & CU_ACTIVE)
- break;
- if (readw(&p->xmit_cmds[0]->cmd_status))
- break;
- if (i == 15)
- printk(KERN_WARNING "%s: Can't start transmit-command.\n", dev->name);
- }
-# else
- next_nop = (p->nop_point + 1) & 0x1;
- writew(TBD_LAST | len, &p->xmit_buffs[0]->size);
- writew(make16(p->nop_cmds[next_nop]), &p->xmit_cmds[0]->cmd_link);
- writew(make16(p->nop_cmds[next_nop]),
- &p->nop_cmds[next_nop]->cmd_link);
- writew(0, &p->xmit_cmds[0]->cmd_status);
- writew(0, &p->nop_cmds[next_nop]->cmd_status);
-
- writew(make16(p->xmit_cmds[0]), &p->nop_cmds[p->nop_point]->cmd_link);
- p->nop_point = next_nop;
- dev_kfree_skb(skb);
-# endif
-#else
- writew(TBD_LAST | len, &p->xmit_buffs[p->xmit_count]->size);
- next_nop = p->xmit_count + 1
- if (next_nop == NUM_XMIT_BUFFS)
- next_nop = 0;
- writew(0, &p->xmit_cmds[p->xmit_count]->cmd_status);
- /* linkpointer of xmit-command already points to next nop cmd */
- writew(make16(p->nop_cmds[next_nop]),
- &p->nop_cmds[next_nop]->cmd_link);
- writew(0, &p->nop_cmds[next_nop]->cmd_status);
- writew(make16(p->xmit_cmds[p->xmit_count]),
- &p->nop_cmds[p->xmit_count]->cmd_link);
- p->xmit_count = next_nop;
- {
- unsigned long flags;
- spin_lock_irqsave(&p->spinlock);
- if (p->xmit_count != p->xmit_last)
- netif_wake_queue(dev);
- spin_unlock_irqrestore(&p->spinlock);
- }
- dev_kfree_skb(skb);
-#endif
- return NETDEV_TX_OK;
-}
-
-/*******************************************
- * Someone wanna have the statistics
- */
-
-static struct net_device_stats *ni52_get_stats(struct net_device *dev)
-{
- struct priv *p = netdev_priv(dev);
- unsigned short crc, aln, rsc, ovrn;
-
- /* Get error-statistics from the ni82586 */
- crc = readw(&p->scb->crc_errs);
- writew(0, &p->scb->crc_errs);
- aln = readw(&p->scb->aln_errs);
- writew(0, &p->scb->aln_errs);
- rsc = readw(&p->scb->rsc_errs);
- writew(0, &p->scb->rsc_errs);
- ovrn = readw(&p->scb->ovrn_errs);
- writew(0, &p->scb->ovrn_errs);
-
- dev->stats.rx_crc_errors += crc;
- dev->stats.rx_fifo_errors += ovrn;
- dev->stats.rx_frame_errors += aln;
- dev->stats.rx_dropped += rsc;
-
- return &dev->stats;
-}
-
-/********************************************************
- * Set MC list ..
- */
-
-static void set_multicast_list(struct net_device *dev)
-{
- netif_stop_queue(dev);
- ni_disint();
- alloc586(dev);
- init586(dev);
- startrecv586(dev);
- ni_enaint();
- netif_wake_queue(dev);
-}
-
-#ifdef MODULE
-static struct net_device *dev_ni52;
-
-module_param(io, int, 0);
-module_param(irq, int, 0);
-module_param(memstart, long, 0);
-module_param(memend, long, 0);
-MODULE_PARM_DESC(io, "NI5210 I/O base address,required");
-MODULE_PARM_DESC(irq, "NI5210 IRQ number,required");
-MODULE_PARM_DESC(memstart, "NI5210 memory base address,required");
-MODULE_PARM_DESC(memend, "NI5210 memory end address,required");
-
-int __init init_module(void)
-{
- if (io <= 0x0 || !memend || !memstart || irq < 2) {
- printk(KERN_ERR "ni52: Autoprobing not allowed for modules.\n");
- printk(KERN_ERR "ni52: Set symbols 'io' 'irq' 'memstart' and 'memend'\n");
- return -ENODEV;
- }
- dev_ni52 = ni52_probe(-1);
- if (IS_ERR(dev_ni52))
- return PTR_ERR(dev_ni52);
- return 0;
-}
-
-void __exit cleanup_module(void)
-{
- struct priv *p = netdev_priv(dev_ni52);
- unregister_netdev(dev_ni52);
- iounmap(p->mapped);
- release_region(dev_ni52->base_addr, NI52_TOTAL_SIZE);
- free_netdev(dev_ni52);
-}
-#endif /* MODULE */
-
-MODULE_LICENSE("GPL");
+++ /dev/null
-/*
- * Intel i82586 Ethernet definitions
- *
- * This is an extension to the Linux operating system, and is covered by the
- * same GNU General Public License that covers that work.
- *
- * copyrights (c) 1994 by Michael Hipp (hippm@informatik.uni-tuebingen.de)
- *
- * I have done a look in the following sources:
- * crynwr-packet-driver by Russ Nelson
- * Garret A. Wollman's i82586-driver for BSD
- */
-
-
-#define NI52_RESET 0 /* writing to this address, resets the i82586 */
-#define NI52_ATTENTION 1 /* channel attention, kick the 586 */
-#define NI52_TENA 3 /* 2-5 possibly wrong, Xmit enable */
-#define NI52_TDIS 2 /* Xmit disable */
-#define NI52_INTENA 5 /* Interrupt enable */
-#define NI52_INTDIS 4 /* Interrupt disable */
-#define NI52_MAGIC1 6 /* dunno exact function */
-#define NI52_MAGIC2 7 /* dunno exact function */
-
-#define NI52_MAGICVAL1 0x00 /* magic-values for ni5210 card */
-#define NI52_MAGICVAL2 0x55
-
-/*
- * where to find the System Configuration Pointer (SCP)
- */
-#define SCP_DEFAULT_ADDRESS 0xfffff4
-
-
-/*
- * System Configuration Pointer Struct
- */
-
-struct scp_struct
-{
- u16 zero_dum0; /* has to be zero */
- u8 sysbus; /* 0=16Bit,1=8Bit */
- u8 zero_dum1; /* has to be zero for 586 */
- u16 zero_dum2;
- u16 zero_dum3;
- u32 iscp; /* pointer to the iscp-block */
-};
-
-
-/*
- * Intermediate System Configuration Pointer (ISCP)
- */
-struct iscp_struct
-{
- u8 busy; /* 586 clears after successful init */
- u8 zero_dummy; /* has to be zero */
- u16 scb_offset; /* pointeroffset to the scb_base */
- u32 scb_base; /* base-address of all 16-bit offsets */
-};
-
-/*
- * System Control Block (SCB)
- */
-struct scb_struct
-{
- u8 rus;
- u8 cus;
- u8 cmd_ruc; /* command word: RU part */
- u8 cmd_cuc; /* command word: CU part & ACK */
- u16 cbl_offset; /* pointeroffset, command block list */
- u16 rfa_offset; /* pointeroffset, receive frame area */
- u16 crc_errs; /* CRC-Error counter */
- u16 aln_errs; /* alignmenterror counter */
- u16 rsc_errs; /* Resourceerror counter */
- u16 ovrn_errs; /* OVerrunerror counter */
-};
-
-/*
- * possible command values for the command word
- */
-#define RUC_MASK 0x0070 /* mask for RU commands */
-#define RUC_NOP 0x0000 /* NOP-command */
-#define RUC_START 0x0010 /* start RU */
-#define RUC_RESUME 0x0020 /* resume RU after suspend */
-#define RUC_SUSPEND 0x0030 /* suspend RU */
-#define RUC_ABORT 0x0040 /* abort receiver operation immediately */
-
-#define CUC_MASK 0x07 /* mask for CU command */
-#define CUC_NOP 0x00 /* NOP-command */
-#define CUC_START 0x01 /* start execution of 1. cmd on the CBL */
-#define CUC_RESUME 0x02 /* resume after suspend */
-#define CUC_SUSPEND 0x03 /* Suspend CU */
-#define CUC_ABORT 0x04 /* abort command operation immediately */
-
-#define ACK_MASK 0xf0 /* mask for ACK command */
-#define ACK_CX 0x80 /* acknowledges STAT_CX */
-#define ACK_FR 0x40 /* ack. STAT_FR */
-#define ACK_CNA 0x20 /* ack. STAT_CNA */
-#define ACK_RNR 0x10 /* ack. STAT_RNR */
-
-/*
- * possible status values for the status word
- */
-#define STAT_MASK 0xf0 /* mask for cause of interrupt */
-#define STAT_CX 0x80 /* CU finished cmd with its I bit set */
-#define STAT_FR 0x40 /* RU finished receiving a frame */
-#define STAT_CNA 0x20 /* CU left active state */
-#define STAT_RNR 0x10 /* RU left ready state */
-
-#define CU_STATUS 0x7 /* CU status, 0=idle */
-#define CU_SUSPEND 0x1 /* CU is suspended */
-#define CU_ACTIVE 0x2 /* CU is active */
-
-#define RU_STATUS 0x70 /* RU status, 0=idle */
-#define RU_SUSPEND 0x10 /* RU suspended */
-#define RU_NOSPACE 0x20 /* RU no resources */
-#define RU_READY 0x40 /* RU is ready */
-
-/*
- * Receive Frame Descriptor (RFD)
- */
-struct rfd_struct
-{
- u8 stat_low; /* status word */
- u8 stat_high; /* status word */
- u8 rfd_sf; /* 82596 mode only */
- u8 last; /* Bit15,Last Frame on List / Bit14,suspend */
- u16 next; /* linkoffset to next RFD */
- u16 rbd_offset; /* pointeroffset to RBD-buffer */
- u8 dest[6]; /* ethernet-address, destination */
- u8 source[6]; /* ethernet-address, source */
- u16 length; /* 802.3 frame-length */
- u16 zero_dummy; /* dummy */
-};
-
-#define RFD_LAST 0x80 /* last: last rfd in the list */
-#define RFD_SUSP 0x40 /* last: suspend RU after */
-#define RFD_COMPL 0x80
-#define RFD_OK 0x20
-#define RFD_BUSY 0x40
-#define RFD_ERR_LEN 0x10 /* Length error (if enabled length-checking */
-#define RFD_ERR_CRC 0x08 /* CRC error */
-#define RFD_ERR_ALGN 0x04 /* Alignment error */
-#define RFD_ERR_RNR 0x02 /* status: receiver out of resources */
-#define RFD_ERR_OVR 0x01 /* DMA Overrun! */
-
-#define RFD_ERR_FTS 0x0080 /* Frame to short */
-#define RFD_ERR_NEOP 0x0040 /* No EOP flag (for bitstuffing only) */
-#define RFD_ERR_TRUN 0x0020 /* (82596 only/SF mode) indicates truncated frame */
-#define RFD_MATCHADD 0x0002 /* status: Destinationaddress !matches IA (only 82596) */
-#define RFD_COLLDET 0x0001 /* Detected collision during reception */
-
-/*
- * Receive Buffer Descriptor (RBD)
- */
-struct rbd_struct
-{
- u16 status; /* status word,number of used bytes in buff */
- u16 next; /* pointeroffset to next RBD */
- u32 buffer; /* receive buffer address pointer */
- u16 size; /* size of this buffer */
- u16 zero_dummy; /* dummy */
-};
-
-#define RBD_LAST 0x8000 /* last buffer */
-#define RBD_USED 0x4000 /* this buffer has data */
-#define RBD_MASK 0x3fff /* size-mask for length */
-
-/*
- * Statusvalues for Commands/RFD
- */
-#define STAT_COMPL 0x8000 /* status: frame/command is complete */
-#define STAT_BUSY 0x4000 /* status: frame/command is busy */
-#define STAT_OK 0x2000 /* status: frame/command is ok */
-
-/*
- * Action-Commands
- */
-#define CMD_NOP 0x0000 /* NOP */
-#define CMD_IASETUP 0x0001 /* initial address setup command */
-#define CMD_CONFIGURE 0x0002 /* configure command */
-#define CMD_MCSETUP 0x0003 /* MC setup command */
-#define CMD_XMIT 0x0004 /* transmit command */
-#define CMD_TDR 0x0005 /* time domain reflectometer (TDR) command */
-#define CMD_DUMP 0x0006 /* dump command */
-#define CMD_DIAGNOSE 0x0007 /* diagnose command */
-
-/*
- * Action command bits
- */
-#define CMD_LAST 0x8000 /* indicates last command in the CBL */
-#define CMD_SUSPEND 0x4000 /* suspend CU after this CB */
-#define CMD_INT 0x2000 /* generate interrupt after execution */
-
-/*
- * NOP - command
- */
-struct nop_cmd_struct
-{
- u16 cmd_status; /* status of this command */
- u16 cmd_cmd; /* the command itself (+bits) */
- u16 cmd_link; /* offsetpointer to next command */
-};
-
-/*
- * IA Setup command
- */
-struct iasetup_cmd_struct
-{
- u16 cmd_status;
- u16 cmd_cmd;
- u16 cmd_link;
- u8 iaddr[6];
-};
-
-/*
- * Configure command
- */
-struct configure_cmd_struct
-{
- u16 cmd_status;
- u16 cmd_cmd;
- u16 cmd_link;
- u8 byte_cnt; /* size of the config-cmd */
- u8 fifo; /* fifo/recv monitor */
- u8 sav_bf; /* save bad frames (bit7=1)*/
- u8 adr_len; /* adr_len(0-2),al_loc(3),pream(4-5),loopbak(6-7)*/
- u8 priority; /* lin_prio(0-2),exp_prio(4-6),bof_metd(7) */
- u8 ifs; /* inter frame spacing */
- u8 time_low; /* slot time low */
- u8 time_high; /* slot time high(0-2) and max. retries(4-7) */
- u8 promisc; /* promisc-mode(0) , et al (1-7) */
- u8 carr_coll; /* carrier(0-3)/collision(4-7) stuff */
- u8 fram_len; /* minimal frame len */
- u8 dummy; /* dummy */
-};
-
-/*
- * Multicast Setup command
- */
-struct mcsetup_cmd_struct
-{
- u16 cmd_status;
- u16 cmd_cmd;
- u16 cmd_link;
- u16 mc_cnt; /* number of bytes in the MC-List */
- u8 mc_list[0][6]; /* pointer to 6 bytes entries */
-};
-
-/*
- * DUMP command
- */
-struct dump_cmd_struct
-{
- u16 cmd_status;
- u16 cmd_cmd;
- u16 cmd_link;
- u16 dump_offset; /* pointeroffset to DUMP space */
-};
-
-/*
- * transmit command
- */
-struct transmit_cmd_struct
-{
- u16 cmd_status;
- u16 cmd_cmd;
- u16 cmd_link;
- u16 tbd_offset; /* pointeroffset to TBD */
- u8 dest[6]; /* destination address of the frame */
- u16 length; /* user defined: 802.3 length / Ether type */
-};
-
-#define TCMD_ERRMASK 0x0fa0
-#define TCMD_MAXCOLLMASK 0x000f
-#define TCMD_MAXCOLL 0x0020
-#define TCMD_HEARTBEAT 0x0040
-#define TCMD_DEFERRED 0x0080
-#define TCMD_UNDERRUN 0x0100
-#define TCMD_LOSTCTS 0x0200
-#define TCMD_NOCARRIER 0x0400
-#define TCMD_LATECOLL 0x0800
-
-struct tdr_cmd_struct
-{
- u16 cmd_status;
- u16 cmd_cmd;
- u16 cmd_link;
- u16 status;
-};
-
-#define TDR_LNK_OK 0x8000 /* No link problem identified */
-#define TDR_XCVR_PRB 0x4000 /* indicates a transceiver problem */
-#define TDR_ET_OPN 0x2000 /* open, no correct termination */
-#define TDR_ET_SRT 0x1000 /* TDR detected a short circuit */
-#define TDR_TIMEMASK 0x07ff /* mask for the time field */
-
-/*
- * Transmit Buffer Descriptor (TBD)
- */
-struct tbd_struct
-{
- u16 size; /* size + EOF-Flag(15) */
- u16 next; /* pointeroffset to next TBD */
- u32 buffer; /* pointer to buffer */
-};
-
-#define TBD_LAST 0x8000 /* EOF-Flag, indicates last buffer in list */
-
-
-
-
+++ /dev/null
-/*
- * sni_82596.c -- driver for intel 82596 ethernet controller, as
- * used in older SNI RM machines
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/bitops.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-
-#define SNI_82596_DRIVER_VERSION "SNI RM 82596 driver - Revision: 0.01"
-
-static const char sni_82596_string[] = "snirm_82596";
-
-#define DMA_ALLOC dma_alloc_coherent
-#define DMA_FREE dma_free_coherent
-#define DMA_WBACK(priv, addr, len) do { } while (0)
-#define DMA_INV(priv, addr, len) do { } while (0)
-#define DMA_WBACK_INV(priv, addr, len) do { } while (0)
-
-#define SYSBUS 0x00004400
-
-/* big endian CPU, 82596 little endian */
-#define SWAP32(x) cpu_to_le32((u32)(x))
-#define SWAP16(x) cpu_to_le16((u16)(x))
-
-#define OPT_MPU_16BIT 0x01
-
-#include "lib82596.c"
-
-MODULE_AUTHOR("Thomas Bogendoerfer");
-MODULE_DESCRIPTION("i82596 driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:snirm_82596");
-module_param(i596_debug, int, 0);
-MODULE_PARM_DESC(i596_debug, "82596 debug mask");
-
-static inline void ca(struct net_device *dev)
-{
- struct i596_private *lp = netdev_priv(dev);
-
- writel(0, lp->ca);
-}
-
-
-static void mpu_port(struct net_device *dev, int c, dma_addr_t x)
-{
- struct i596_private *lp = netdev_priv(dev);
-
- u32 v = (u32) (c) | (u32) (x);
-
- if (lp->options & OPT_MPU_16BIT) {
- writew(v & 0xffff, lp->mpu_port);
- wmb(); /* order writes to MPU port */
- udelay(1);
- writew(v >> 16, lp->mpu_port);
- } else {
- writel(v, lp->mpu_port);
- wmb(); /* order writes to MPU port */
- udelay(1);
- writel(v, lp->mpu_port);
- }
-}
-
-
-static int __devinit sni_82596_probe(struct platform_device *dev)
-{
- struct net_device *netdevice;
- struct i596_private *lp;
- struct resource *res, *ca, *idprom, *options;
- int retval = -ENOMEM;
- void __iomem *mpu_addr;
- void __iomem *ca_addr;
- u8 __iomem *eth_addr;
-
- res = platform_get_resource(dev, IORESOURCE_MEM, 0);
- ca = platform_get_resource(dev, IORESOURCE_MEM, 1);
- options = platform_get_resource(dev, 0, 0);
- idprom = platform_get_resource(dev, IORESOURCE_MEM, 2);
- if (!res || !ca || !options || !idprom)
- return -ENODEV;
- mpu_addr = ioremap_nocache(res->start, 4);
- if (!mpu_addr)
- return -ENOMEM;
- ca_addr = ioremap_nocache(ca->start, 4);
- if (!ca_addr)
- goto probe_failed_free_mpu;
-
- printk(KERN_INFO "Found i82596 at 0x%x\n", res->start);
-
- netdevice = alloc_etherdev(sizeof(struct i596_private));
- if (!netdevice)
- goto probe_failed_free_ca;
-
- SET_NETDEV_DEV(netdevice, &dev->dev);
- platform_set_drvdata (dev, netdevice);
-
- netdevice->base_addr = res->start;
- netdevice->irq = platform_get_irq(dev, 0);
-
- eth_addr = ioremap_nocache(idprom->start, 0x10);
- if (!eth_addr)
- goto probe_failed;
-
- /* someone seems to like messed up stuff */
- netdevice->dev_addr[0] = readb(eth_addr + 0x0b);
- netdevice->dev_addr[1] = readb(eth_addr + 0x0a);
- netdevice->dev_addr[2] = readb(eth_addr + 0x09);
- netdevice->dev_addr[3] = readb(eth_addr + 0x08);
- netdevice->dev_addr[4] = readb(eth_addr + 0x07);
- netdevice->dev_addr[5] = readb(eth_addr + 0x06);
- iounmap(eth_addr);
-
- if (!netdevice->irq) {
- printk(KERN_ERR "%s: IRQ not found for i82596 at 0x%lx\n",
- __FILE__, netdevice->base_addr);
- goto probe_failed;
- }
-
- lp = netdev_priv(netdevice);
- lp->options = options->flags & IORESOURCE_BITS;
- lp->ca = ca_addr;
- lp->mpu_port = mpu_addr;
-
- retval = i82596_probe(netdevice);
- if (retval == 0)
- return 0;
-
-probe_failed:
- free_netdev(netdevice);
-probe_failed_free_ca:
- iounmap(ca_addr);
-probe_failed_free_mpu:
- iounmap(mpu_addr);
- return retval;
-}
-
-static int __devexit sni_82596_driver_remove(struct platform_device *pdev)
-{
- struct net_device *dev = platform_get_drvdata(pdev);
- struct i596_private *lp = netdev_priv(dev);
-
- unregister_netdev(dev);
- DMA_FREE(dev->dev.parent, sizeof(struct i596_private),
- lp->dma, lp->dma_addr);
- iounmap(lp->ca);
- iounmap(lp->mpu_port);
- free_netdev (dev);
- return 0;
-}
-
-static struct platform_driver sni_82596_driver = {
- .probe = sni_82596_probe,
- .remove = __devexit_p(sni_82596_driver_remove),
- .driver = {
- .name = sni_82596_string,
- .owner = THIS_MODULE,
- },
-};
-
-static int __devinit sni_82596_init(void)
-{
- printk(KERN_INFO SNI_82596_DRIVER_VERSION "\n");
- return platform_driver_register(&sni_82596_driver);
-}
-
-
-static void __exit sni_82596_exit(void)
-{
- platform_driver_unregister(&sni_82596_driver);
-}
-
-module_init(sni_82596_init);
-module_exit(sni_82596_exit);
+++ /dev/null
-/*
- * Sun3 i82586 Ethernet driver
- *
- * Cloned from ni52.c for the Sun3 by Sam Creasey (sammy@sammy.net)
- *
- * Original copyright follows:
- * --------------------------
- *
- * net-3-driver for the NI5210 card (i82586 Ethernet chip)
- *
- * This is an extension to the Linux operating system, and is covered by the
- * same Gnu Public License that covers that work.
- *
- * Alphacode 0.82 (96/09/29) for Linux 2.0.0 (or later)
- * Copyrights (c) 1994,1995,1996 by M.Hipp (hippm@informatik.uni-tuebingen.de)
- * --------------------------
- *
- * Consult ni52.c for further notes from the original driver.
- *
- * This incarnation currently supports the OBIO version of the i82586 chip
- * used in certain sun3 models. It should be fairly doable to expand this
- * to support VME if I should every acquire such a board.
- *
- */
-
-static int debuglevel = 0; /* debug-printk 0: off 1: a few 2: more */
-static int automatic_resume = 0; /* experimental .. better should be zero */
-static int rfdadd = 0; /* rfdadd=1 may be better for 8K MEM cards */
-static int fifo=0x8; /* don't change */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/bitops.h>
-#include <asm/io.h>
-#include <asm/idprom.h>
-#include <asm/machines.h>
-#include <asm/sun3mmu.h>
-#include <asm/dvma.h>
-#include <asm/byteorder.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-
-#include "sun3_82586.h"
-
-#define DRV_NAME "sun3_82586"
-
-#define DEBUG /* debug on */
-#define SYSBUSVAL 0 /* 16 Bit */
-#define SUN3_82586_TOTAL_SIZE PAGE_SIZE
-
-#define sun3_attn586() {*(volatile unsigned char *)(dev->base_addr) |= IEOB_ATTEN; *(volatile unsigned char *)(dev->base_addr) &= ~IEOB_ATTEN;}
-#define sun3_reset586() {*(volatile unsigned char *)(dev->base_addr) = 0; udelay(100); *(volatile unsigned char *)(dev->base_addr) = IEOB_NORSET;}
-#define sun3_disint() {*(volatile unsigned char *)(dev->base_addr) &= ~IEOB_IENAB;}
-#define sun3_enaint() {*(volatile unsigned char *)(dev->base_addr) |= IEOB_IENAB;}
-#define sun3_active() {*(volatile unsigned char *)(dev->base_addr) |= (IEOB_IENAB|IEOB_ONAIR|IEOB_NORSET);}
-
-#define make32(ptr16) (p->memtop + (swab16((unsigned short) (ptr16))) )
-#define make24(ptr32) (char *)swab32(( ((unsigned long) (ptr32)) - p->base))
-#define make16(ptr32) (swab16((unsigned short) ((unsigned long)(ptr32) - (unsigned long) p->memtop )))
-
-/******************* how to calculate the buffers *****************************
-
- * IMPORTANT NOTE: if you configure only one NUM_XMIT_BUFFS, the driver works
- * --------------- in a different (more stable?) mode. Only in this mode it's
- * possible to configure the driver with 'NO_NOPCOMMANDS'
-
-sizeof(scp)=12; sizeof(scb)=16; sizeof(iscp)=8;
-sizeof(scp)+sizeof(iscp)+sizeof(scb) = 36 = INIT
-sizeof(rfd) = 24; sizeof(rbd) = 12;
-sizeof(tbd) = 8; sizeof(transmit_cmd) = 16;
-sizeof(nop_cmd) = 8;
-
- * if you don't know the driver, better do not change these values: */
-
-#define RECV_BUFF_SIZE 1536 /* slightly oversized */
-#define XMIT_BUFF_SIZE 1536 /* slightly oversized */
-#define NUM_XMIT_BUFFS 1 /* config for 32K shmem */
-#define NUM_RECV_BUFFS_8 4 /* config for 32K shared mem */
-#define NUM_RECV_BUFFS_16 9 /* config for 32K shared mem */
-#define NUM_RECV_BUFFS_32 16 /* config for 32K shared mem */
-#define NO_NOPCOMMANDS /* only possible with NUM_XMIT_BUFFS=1 */
-
-/**************************************************************************/
-
-/* different DELAYs */
-#define DELAY(x) mdelay(32 * x);
-#define DELAY_16(); { udelay(16); }
-#define DELAY_18(); { udelay(4); }
-
-/* wait for command with timeout: */
-#define WAIT_4_SCB_CMD() \
-{ int i; \
- for(i=0;i<16384;i++) { \
- if(!p->scb->cmd_cuc) break; \
- DELAY_18(); \
- if(i == 16383) { \
- printk("%s: scb_cmd timed out: %04x,%04x .. disabling i82586!!\n",dev->name,p->scb->cmd_cuc,p->scb->cus); \
- if(!p->reseted) { p->reseted = 1; sun3_reset586(); } } } }
-
-#define WAIT_4_SCB_CMD_RUC() { int i; \
- for(i=0;i<16384;i++) { \
- if(!p->scb->cmd_ruc) break; \
- DELAY_18(); \
- if(i == 16383) { \
- printk("%s: scb_cmd (ruc) timed out: %04x,%04x .. disabling i82586!!\n",dev->name,p->scb->cmd_ruc,p->scb->rus); \
- if(!p->reseted) { p->reseted = 1; sun3_reset586(); } } } }
-
-#define WAIT_4_STAT_COMPL(addr) { int i; \
- for(i=0;i<32767;i++) { \
- if(swab16((addr)->cmd_status) & STAT_COMPL) break; \
- DELAY_16(); DELAY_16(); } }
-
-static int sun3_82586_probe1(struct net_device *dev,int ioaddr);
-static irqreturn_t sun3_82586_interrupt(int irq,void *dev_id);
-static int sun3_82586_open(struct net_device *dev);
-static int sun3_82586_close(struct net_device *dev);
-static int sun3_82586_send_packet(struct sk_buff *,struct net_device *);
-static struct net_device_stats *sun3_82586_get_stats(struct net_device *dev);
-static void set_multicast_list(struct net_device *dev);
-static void sun3_82586_timeout(struct net_device *dev);
-#if 0
-static void sun3_82586_dump(struct net_device *,void *);
-#endif
-
-/* helper-functions */
-static int init586(struct net_device *dev);
-static int check586(struct net_device *dev,char *where,unsigned size);
-static void alloc586(struct net_device *dev);
-static void startrecv586(struct net_device *dev);
-static void *alloc_rfa(struct net_device *dev,void *ptr);
-static void sun3_82586_rcv_int(struct net_device *dev);
-static void sun3_82586_xmt_int(struct net_device *dev);
-static void sun3_82586_rnr_int(struct net_device *dev);
-
-struct priv
-{
- unsigned long base;
- char *memtop;
- long int lock;
- int reseted;
- volatile struct rfd_struct *rfd_last,*rfd_top,*rfd_first;
- volatile struct scp_struct *scp; /* volatile is important */
- volatile struct iscp_struct *iscp; /* volatile is important */
- volatile struct scb_struct *scb; /* volatile is important */
- volatile struct tbd_struct *xmit_buffs[NUM_XMIT_BUFFS];
- volatile struct transmit_cmd_struct *xmit_cmds[NUM_XMIT_BUFFS];
-#if (NUM_XMIT_BUFFS == 1)
- volatile struct nop_cmd_struct *nop_cmds[2];
-#else
- volatile struct nop_cmd_struct *nop_cmds[NUM_XMIT_BUFFS];
-#endif
- volatile int nop_point,num_recv_buffs;
- volatile char *xmit_cbuffs[NUM_XMIT_BUFFS];
- volatile int xmit_count,xmit_last;
-};
-
-/**********************************************
- * close device
- */
-static int sun3_82586_close(struct net_device *dev)
-{
- free_irq(dev->irq, dev);
-
- sun3_reset586(); /* the hard way to stop the receiver */
-
- netif_stop_queue(dev);
-
- return 0;
-}
-
-/**********************************************
- * open device
- */
-static int sun3_82586_open(struct net_device *dev)
-{
- int ret;
-
- sun3_disint();
- alloc586(dev);
- init586(dev);
- startrecv586(dev);
- sun3_enaint();
-
- ret = request_irq(dev->irq, sun3_82586_interrupt,0,dev->name,dev);
- if (ret)
- {
- sun3_reset586();
- return ret;
- }
-
- netif_start_queue(dev);
-
- return 0; /* most done by init */
-}
-
-/**********************************************
- * Check to see if there's an 82586 out there.
- */
-static int check586(struct net_device *dev,char *where,unsigned size)
-{
- struct priv pb;
- struct priv *p = &pb;
- char *iscp_addr;
- int i;
-
- p->base = (unsigned long) dvma_btov(0);
- p->memtop = (char *)dvma_btov((unsigned long)where);
- p->scp = (struct scp_struct *)(p->base + SCP_DEFAULT_ADDRESS);
- memset((char *)p->scp,0, sizeof(struct scp_struct));
- for(i=0;i<sizeof(struct scp_struct);i++) /* memory was writeable? */
- if(((char *)p->scp)[i])
- return 0;
- p->scp->sysbus = SYSBUSVAL; /* 1 = 8Bit-Bus, 0 = 16 Bit */
- if(p->scp->sysbus != SYSBUSVAL)
- return 0;
-
- iscp_addr = (char *)dvma_btov((unsigned long)where);
-
- p->iscp = (struct iscp_struct *) iscp_addr;
- memset((char *)p->iscp,0, sizeof(struct iscp_struct));
-
- p->scp->iscp = make24(p->iscp);
- p->iscp->busy = 1;
-
- sun3_reset586();
- sun3_attn586();
- DELAY(1); /* wait a while... */
-
- if(p->iscp->busy) /* i82586 clears 'busy' after successful init */
- return 0;
-
- return 1;
-}
-
-/******************************************************************
- * set iscp at the right place, called by sun3_82586_probe1 and open586.
- */
-static void alloc586(struct net_device *dev)
-{
- struct priv *p = netdev_priv(dev);
-
- sun3_reset586();
- DELAY(1);
-
- p->scp = (struct scp_struct *) (p->base + SCP_DEFAULT_ADDRESS);
- p->iscp = (struct iscp_struct *) dvma_btov(dev->mem_start);
- p->scb = (struct scb_struct *) ((char *)p->iscp + sizeof(struct iscp_struct));
-
- memset((char *) p->iscp,0,sizeof(struct iscp_struct));
- memset((char *) p->scp ,0,sizeof(struct scp_struct));
-
- p->scp->iscp = make24(p->iscp);
- p->scp->sysbus = SYSBUSVAL;
- p->iscp->scb_offset = make16(p->scb);
- p->iscp->scb_base = make24(dvma_btov(dev->mem_start));
-
- p->iscp->busy = 1;
- sun3_reset586();
- sun3_attn586();
-
- DELAY(1);
-
- if(p->iscp->busy)
- printk("%s: Init-Problems (alloc).\n",dev->name);
-
- p->reseted = 0;
-
- memset((char *)p->scb,0,sizeof(struct scb_struct));
-}
-
-struct net_device * __init sun3_82586_probe(int unit)
-{
- struct net_device *dev;
- unsigned long ioaddr;
- static int found = 0;
- int err = -ENOMEM;
-
- /* check that this machine has an onboard 82586 */
- switch(idprom->id_machtype) {
- case SM_SUN3|SM_3_160:
- case SM_SUN3|SM_3_260:
- /* these machines have 82586 */
- break;
-
- default:
- return ERR_PTR(-ENODEV);
- }
-
- if (found)
- return ERR_PTR(-ENODEV);
-
- ioaddr = (unsigned long)ioremap(IE_OBIO, SUN3_82586_TOTAL_SIZE);
- if (!ioaddr)
- return ERR_PTR(-ENOMEM);
- found = 1;
-
- dev = alloc_etherdev(sizeof(struct priv));
- if (!dev)
- goto out;
- if (unit >= 0) {
- sprintf(dev->name, "eth%d", unit);
- netdev_boot_setup_check(dev);
- }
-
- dev->irq = IE_IRQ;
- dev->base_addr = ioaddr;
- err = sun3_82586_probe1(dev, ioaddr);
- if (err)
- goto out1;
- err = register_netdev(dev);
- if (err)
- goto out2;
- return dev;
-
-out2:
- release_region(ioaddr, SUN3_82586_TOTAL_SIZE);
-out1:
- free_netdev(dev);
-out:
- iounmap((void __iomem *)ioaddr);
- return ERR_PTR(err);
-}
-
-static const struct net_device_ops sun3_82586_netdev_ops = {
- .ndo_open = sun3_82586_open,
- .ndo_stop = sun3_82586_close,
- .ndo_start_xmit = sun3_82586_send_packet,
- .ndo_set_multicast_list = set_multicast_list,
- .ndo_tx_timeout = sun3_82586_timeout,
- .ndo_get_stats = sun3_82586_get_stats,
- .ndo_validate_addr = eth_validate_addr,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_change_mtu = eth_change_mtu,
-};
-
-static int __init sun3_82586_probe1(struct net_device *dev,int ioaddr)
-{
- int i, size, retval;
-
- if (!request_region(ioaddr, SUN3_82586_TOTAL_SIZE, DRV_NAME))
- return -EBUSY;
-
- /* copy in the ethernet address from the prom */
- for(i = 0; i < 6 ; i++)
- dev->dev_addr[i] = idprom->id_ethaddr[i];
-
- printk("%s: SUN3 Intel 82586 found at %lx, ",dev->name,dev->base_addr);
-
- /*
- * check (or search) IO-Memory, 32K
- */
- size = 0x8000;
-
- dev->mem_start = (unsigned long)dvma_malloc_align(0x8000, 0x1000);
- dev->mem_end = dev->mem_start + size;
-
- if(size != 0x2000 && size != 0x4000 && size != 0x8000) {
- printk("\n%s: Illegal memory size %d. Allowed is 0x2000 or 0x4000 or 0x8000 bytes.\n",dev->name,size);
- retval = -ENODEV;
- goto out;
- }
- if(!check586(dev,(char *) dev->mem_start,size)) {
- printk("?memcheck, Can't find memory at 0x%lx with size %d!\n",dev->mem_start,size);
- retval = -ENODEV;
- goto out;
- }
-
- ((struct priv *)netdev_priv(dev))->memtop =
- (char *)dvma_btov(dev->mem_start);
- ((struct priv *)netdev_priv(dev))->base = (unsigned long) dvma_btov(0);
- alloc586(dev);
-
- /* set number of receive-buffs according to memsize */
- if(size == 0x2000)
- ((struct priv *)netdev_priv(dev))->num_recv_buffs =
- NUM_RECV_BUFFS_8;
- else if(size == 0x4000)
- ((struct priv *)netdev_priv(dev))->num_recv_buffs =
- NUM_RECV_BUFFS_16;
- else
- ((struct priv *)netdev_priv(dev))->num_recv_buffs =
- NUM_RECV_BUFFS_32;
-
- printk("Memaddr: 0x%lx, Memsize: %d, IRQ %d\n",dev->mem_start,size, dev->irq);
-
- dev->netdev_ops = &sun3_82586_netdev_ops;
- dev->watchdog_timeo = HZ/20;
-
- dev->if_port = 0;
- return 0;
-out:
- release_region(ioaddr, SUN3_82586_TOTAL_SIZE);
- return retval;
-}
-
-
-static int init586(struct net_device *dev)
-{
- void *ptr;
- int i,result=0;
- struct priv *p = netdev_priv(dev);
- volatile struct configure_cmd_struct *cfg_cmd;
- volatile struct iasetup_cmd_struct *ias_cmd;
- volatile struct tdr_cmd_struct *tdr_cmd;
- volatile struct mcsetup_cmd_struct *mc_cmd;
- struct netdev_hw_addr *ha;
- int num_addrs=netdev_mc_count(dev);
-
- ptr = (void *) ((char *)p->scb + sizeof(struct scb_struct));
-
- cfg_cmd = (struct configure_cmd_struct *)ptr; /* configure-command */
- cfg_cmd->cmd_status = 0;
- cfg_cmd->cmd_cmd = swab16(CMD_CONFIGURE | CMD_LAST);
- cfg_cmd->cmd_link = 0xffff;
-
- cfg_cmd->byte_cnt = 0x0a; /* number of cfg bytes */
- cfg_cmd->fifo = fifo; /* fifo-limit (8=tx:32/rx:64) */
- cfg_cmd->sav_bf = 0x40; /* hold or discard bad recv frames (bit 7) */
- cfg_cmd->adr_len = 0x2e; /* addr_len |!src_insert |pre-len |loopback */
- cfg_cmd->priority = 0x00;
- cfg_cmd->ifs = 0x60;
- cfg_cmd->time_low = 0x00;
- cfg_cmd->time_high = 0xf2;
- cfg_cmd->promisc = 0;
- if(dev->flags & IFF_ALLMULTI) {
- int len = ((char *) p->iscp - (char *) ptr - 8) / 6;
- if(num_addrs > len) {
- printk("%s: switching to promisc. mode\n",dev->name);
- cfg_cmd->promisc = 1;
- }
- }
- if(dev->flags&IFF_PROMISC)
- cfg_cmd->promisc = 1;
- cfg_cmd->carr_coll = 0x00;
-
- p->scb->cbl_offset = make16(cfg_cmd);
- p->scb->cmd_ruc = 0;
-
- p->scb->cmd_cuc = CUC_START; /* cmd.-unit start */
- sun3_attn586();
-
- WAIT_4_STAT_COMPL(cfg_cmd);
-
- if((swab16(cfg_cmd->cmd_status) & (STAT_OK|STAT_COMPL)) != (STAT_COMPL|STAT_OK))
- {
- printk("%s: configure command failed: %x\n",dev->name,swab16(cfg_cmd->cmd_status));
- return 1;
- }
-
- /*
- * individual address setup
- */
-
- ias_cmd = (struct iasetup_cmd_struct *)ptr;
-
- ias_cmd->cmd_status = 0;
- ias_cmd->cmd_cmd = swab16(CMD_IASETUP | CMD_LAST);
- ias_cmd->cmd_link = 0xffff;
-
- memcpy((char *)&ias_cmd->iaddr,(char *) dev->dev_addr,ETH_ALEN);
-
- p->scb->cbl_offset = make16(ias_cmd);
-
- p->scb->cmd_cuc = CUC_START; /* cmd.-unit start */
- sun3_attn586();
-
- WAIT_4_STAT_COMPL(ias_cmd);
-
- if((swab16(ias_cmd->cmd_status) & (STAT_OK|STAT_COMPL)) != (STAT_OK|STAT_COMPL)) {
- printk("%s (82586): individual address setup command failed: %04x\n",dev->name,swab16(ias_cmd->cmd_status));
- return 1;
- }
-
- /*
- * TDR, wire check .. e.g. no resistor e.t.c
- */
-
- tdr_cmd = (struct tdr_cmd_struct *)ptr;
-
- tdr_cmd->cmd_status = 0;
- tdr_cmd->cmd_cmd = swab16(CMD_TDR | CMD_LAST);
- tdr_cmd->cmd_link = 0xffff;
- tdr_cmd->status = 0;
-
- p->scb->cbl_offset = make16(tdr_cmd);
- p->scb->cmd_cuc = CUC_START; /* cmd.-unit start */
- sun3_attn586();
-
- WAIT_4_STAT_COMPL(tdr_cmd);
-
- if(!(swab16(tdr_cmd->cmd_status) & STAT_COMPL))
- {
- printk("%s: Problems while running the TDR.\n",dev->name);
- }
- else
- {
- DELAY_16(); /* wait for result */
- result = swab16(tdr_cmd->status);
-
- p->scb->cmd_cuc = p->scb->cus & STAT_MASK;
- sun3_attn586(); /* ack the interrupts */
-
- if(result & TDR_LNK_OK)
- ;
- else if(result & TDR_XCVR_PRB)
- printk("%s: TDR: Transceiver problem. Check the cable(s)!\n",dev->name);
- else if(result & TDR_ET_OPN)
- printk("%s: TDR: No correct termination %d clocks away.\n",dev->name,result & TDR_TIMEMASK);
- else if(result & TDR_ET_SRT)
- {
- if (result & TDR_TIMEMASK) /* time == 0 -> strange :-) */
- printk("%s: TDR: Detected a short circuit %d clocks away.\n",dev->name,result & TDR_TIMEMASK);
- }
- else
- printk("%s: TDR: Unknown status %04x\n",dev->name,result);
- }
-
- /*
- * Multicast setup
- */
- if(num_addrs && !(dev->flags & IFF_PROMISC) )
- {
- mc_cmd = (struct mcsetup_cmd_struct *) ptr;
- mc_cmd->cmd_status = 0;
- mc_cmd->cmd_cmd = swab16(CMD_MCSETUP | CMD_LAST);
- mc_cmd->cmd_link = 0xffff;
- mc_cmd->mc_cnt = swab16(num_addrs * 6);
-
- i = 0;
- netdev_for_each_mc_addr(ha, dev)
- memcpy((char *) mc_cmd->mc_list[i++],
- ha->addr, ETH_ALEN);
-
- p->scb->cbl_offset = make16(mc_cmd);
- p->scb->cmd_cuc = CUC_START;
- sun3_attn586();
-
- WAIT_4_STAT_COMPL(mc_cmd);
-
- if( (swab16(mc_cmd->cmd_status) & (STAT_COMPL|STAT_OK)) != (STAT_COMPL|STAT_OK) )
- printk("%s: Can't apply multicast-address-list.\n",dev->name);
- }
-
- /*
- * alloc nop/xmit-cmds
- */
-#if (NUM_XMIT_BUFFS == 1)
- for(i=0;i<2;i++)
- {
- p->nop_cmds[i] = (struct nop_cmd_struct *)ptr;
- p->nop_cmds[i]->cmd_cmd = swab16(CMD_NOP);
- p->nop_cmds[i]->cmd_status = 0;
- p->nop_cmds[i]->cmd_link = make16((p->nop_cmds[i]));
- ptr = (char *) ptr + sizeof(struct nop_cmd_struct);
- }
-#else
- for(i=0;i<NUM_XMIT_BUFFS;i++)
- {
- p->nop_cmds[i] = (struct nop_cmd_struct *)ptr;
- p->nop_cmds[i]->cmd_cmd = swab16(CMD_NOP);
- p->nop_cmds[i]->cmd_status = 0;
- p->nop_cmds[i]->cmd_link = make16((p->nop_cmds[i]));
- ptr = (char *) ptr + sizeof(struct nop_cmd_struct);
- }
-#endif
-
- ptr = alloc_rfa(dev,(void *)ptr); /* init receive-frame-area */
-
- /*
- * alloc xmit-buffs / init xmit_cmds
- */
- for(i=0;i<NUM_XMIT_BUFFS;i++)
- {
- p->xmit_cmds[i] = (struct transmit_cmd_struct *)ptr; /*transmit cmd/buff 0*/
- ptr = (char *) ptr + sizeof(struct transmit_cmd_struct);
- p->xmit_cbuffs[i] = (char *)ptr; /* char-buffs */
- ptr = (char *) ptr + XMIT_BUFF_SIZE;
- p->xmit_buffs[i] = (struct tbd_struct *)ptr; /* TBD */
- ptr = (char *) ptr + sizeof(struct tbd_struct);
- if((void *)ptr > (void *)dev->mem_end)
- {
- printk("%s: not enough shared-mem for your configuration!\n",dev->name);
- return 1;
- }
- memset((char *)(p->xmit_cmds[i]) ,0, sizeof(struct transmit_cmd_struct));
- memset((char *)(p->xmit_buffs[i]),0, sizeof(struct tbd_struct));
- p->xmit_cmds[i]->cmd_link = make16(p->nop_cmds[(i+1)%NUM_XMIT_BUFFS]);
- p->xmit_cmds[i]->cmd_status = swab16(STAT_COMPL);
- p->xmit_cmds[i]->cmd_cmd = swab16(CMD_XMIT | CMD_INT);
- p->xmit_cmds[i]->tbd_offset = make16((p->xmit_buffs[i]));
- p->xmit_buffs[i]->next = 0xffff;
- p->xmit_buffs[i]->buffer = make24((p->xmit_cbuffs[i]));
- }
-
- p->xmit_count = 0;
- p->xmit_last = 0;
-#ifndef NO_NOPCOMMANDS
- p->nop_point = 0;
-#endif
-
- /*
- * 'start transmitter'
- */
-#ifndef NO_NOPCOMMANDS
- p->scb->cbl_offset = make16(p->nop_cmds[0]);
- p->scb->cmd_cuc = CUC_START;
- sun3_attn586();
- WAIT_4_SCB_CMD();
-#else
- p->xmit_cmds[0]->cmd_link = make16(p->xmit_cmds[0]);
- p->xmit_cmds[0]->cmd_cmd = swab16(CMD_XMIT | CMD_SUSPEND | CMD_INT);
-#endif
-
- /*
- * ack. interrupts
- */
- p->scb->cmd_cuc = p->scb->cus & STAT_MASK;
- sun3_attn586();
- DELAY_16();
-
- sun3_enaint();
- sun3_active();
-
- return 0;
-}
-
-/******************************************************
- * This is a helper routine for sun3_82586_rnr_int() and init586().
- * It sets up the Receive Frame Area (RFA).
- */
-
-static void *alloc_rfa(struct net_device *dev,void *ptr)
-{
- volatile struct rfd_struct *rfd = (struct rfd_struct *)ptr;
- volatile struct rbd_struct *rbd;
- int i;
- struct priv *p = netdev_priv(dev);
-
- memset((char *) rfd,0,sizeof(struct rfd_struct)*(p->num_recv_buffs+rfdadd));
- p->rfd_first = rfd;
-
- for(i = 0; i < (p->num_recv_buffs+rfdadd); i++) {
- rfd[i].next = make16(rfd + (i+1) % (p->num_recv_buffs+rfdadd) );
- rfd[i].rbd_offset = 0xffff;
- }
- rfd[p->num_recv_buffs-1+rfdadd].last = RFD_SUSP; /* RU suspend */
-
- ptr = (void *) (rfd + (p->num_recv_buffs + rfdadd) );
-
- rbd = (struct rbd_struct *) ptr;
- ptr = (void *) (rbd + p->num_recv_buffs);
-
- /* clr descriptors */
- memset((char *) rbd,0,sizeof(struct rbd_struct)*(p->num_recv_buffs));
-
- for(i=0;i<p->num_recv_buffs;i++)
- {
- rbd[i].next = make16((rbd + (i+1) % p->num_recv_buffs));
- rbd[i].size = swab16(RECV_BUFF_SIZE);
- rbd[i].buffer = make24(ptr);
- ptr = (char *) ptr + RECV_BUFF_SIZE;
- }
-
- p->rfd_top = p->rfd_first;
- p->rfd_last = p->rfd_first + (p->num_recv_buffs - 1 + rfdadd);
-
- p->scb->rfa_offset = make16(p->rfd_first);
- p->rfd_first->rbd_offset = make16(rbd);
-
- return ptr;
-}
-
-
-/**************************************************
- * Interrupt Handler ...
- */
-
-static irqreturn_t sun3_82586_interrupt(int irq,void *dev_id)
-{
- struct net_device *dev = dev_id;
- unsigned short stat;
- int cnt=0;
- struct priv *p;
-
- if (!dev) {
- printk ("sun3_82586-interrupt: irq %d for unknown device.\n",irq);
- return IRQ_NONE;
- }
- p = netdev_priv(dev);
-
- if(debuglevel > 1)
- printk("I");
-
- WAIT_4_SCB_CMD(); /* wait for last command */
-
- while((stat=p->scb->cus & STAT_MASK))
- {
- p->scb->cmd_cuc = stat;
- sun3_attn586();
-
- if(stat & STAT_FR) /* received a frame */
- sun3_82586_rcv_int(dev);
-
- if(stat & STAT_RNR) /* RU went 'not ready' */
- {
- printk("(R)");
- if(p->scb->rus & RU_SUSPEND) /* special case: RU_SUSPEND */
- {
- WAIT_4_SCB_CMD();
- p->scb->cmd_ruc = RUC_RESUME;
- sun3_attn586();
- WAIT_4_SCB_CMD_RUC();
- }
- else
- {
- printk("%s: Receiver-Unit went 'NOT READY': %04x/%02x.\n",dev->name,(int) stat,(int) p->scb->rus);
- sun3_82586_rnr_int(dev);
- }
- }
-
- if(stat & STAT_CX) /* command with I-bit set complete */
- sun3_82586_xmt_int(dev);
-
-#ifndef NO_NOPCOMMANDS
- if(stat & STAT_CNA) /* CU went 'not ready' */
- {
- if(netif_running(dev))
- printk("%s: oops! CU has left active state. stat: %04x/%02x.\n",dev->name,(int) stat,(int) p->scb->cus);
- }
-#endif
-
- if(debuglevel > 1)
- printk("%d",cnt++);
-
- WAIT_4_SCB_CMD(); /* wait for ack. (sun3_82586_xmt_int can be faster than ack!!) */
- if(p->scb->cmd_cuc) /* timed out? */
- {
- printk("%s: Acknowledge timed out.\n",dev->name);
- sun3_disint();
- break;
- }
- }
-
- if(debuglevel > 1)
- printk("i");
- return IRQ_HANDLED;
-}
-
-/*******************************************************
- * receive-interrupt
- */
-
-static void sun3_82586_rcv_int(struct net_device *dev)
-{
- int status,cnt=0;
- unsigned short totlen;
- struct sk_buff *skb;
- struct rbd_struct *rbd;
- struct priv *p = netdev_priv(dev);
-
- if(debuglevel > 0)
- printk("R");
-
- for(;(status = p->rfd_top->stat_high) & RFD_COMPL;)
- {
- rbd = (struct rbd_struct *) make32(p->rfd_top->rbd_offset);
-
- if(status & RFD_OK) /* frame received without error? */
- {
- if( (totlen = swab16(rbd->status)) & RBD_LAST) /* the first and the last buffer? */
- {
- totlen &= RBD_MASK; /* length of this frame */
- rbd->status = 0;
- skb = (struct sk_buff *) dev_alloc_skb(totlen+2);
- if(skb != NULL)
- {
- skb_reserve(skb,2);
- skb_put(skb,totlen);
- skb_copy_to_linear_data(skb,(char *) p->base+swab32((unsigned long) rbd->buffer),totlen);
- skb->protocol=eth_type_trans(skb,dev);
- netif_rx(skb);
- dev->stats.rx_packets++;
- }
- else
- dev->stats.rx_dropped++;
- }
- else
- {
- int rstat;
- /* free all RBD's until RBD_LAST is set */
- totlen = 0;
- while(!((rstat=swab16(rbd->status)) & RBD_LAST))
- {
- totlen += rstat & RBD_MASK;
- if(!rstat)
- {
- printk("%s: Whoops .. no end mark in RBD list\n",dev->name);
- break;
- }
- rbd->status = 0;
- rbd = (struct rbd_struct *) make32(rbd->next);
- }
- totlen += rstat & RBD_MASK;
- rbd->status = 0;
- printk("%s: received oversized frame! length: %d\n",dev->name,totlen);
- dev->stats.rx_dropped++;
- }
- }
- else /* frame !(ok), only with 'save-bad-frames' */
- {
- printk("%s: oops! rfd-error-status: %04x\n",dev->name,status);
- dev->stats.rx_errors++;
- }
- p->rfd_top->stat_high = 0;
- p->rfd_top->last = RFD_SUSP; /* maybe exchange by RFD_LAST */
- p->rfd_top->rbd_offset = 0xffff;
- p->rfd_last->last = 0; /* delete RFD_SUSP */
- p->rfd_last = p->rfd_top;
- p->rfd_top = (struct rfd_struct *) make32(p->rfd_top->next); /* step to next RFD */
- p->scb->rfa_offset = make16(p->rfd_top);
-
- if(debuglevel > 0)
- printk("%d",cnt++);
- }
-
- if(automatic_resume)
- {
- WAIT_4_SCB_CMD();
- p->scb->cmd_ruc = RUC_RESUME;
- sun3_attn586();
- WAIT_4_SCB_CMD_RUC();
- }
-
-#ifdef WAIT_4_BUSY
- {
- int i;
- for(i=0;i<1024;i++)
- {
- if(p->rfd_top->status)
- break;
- DELAY_16();
- if(i == 1023)
- printk("%s: RU hasn't fetched next RFD (not busy/complete)\n",dev->name);
- }
- }
-#endif
-
-#if 0
- if(!at_least_one)
- {
- int i;
- volatile struct rfd_struct *rfds=p->rfd_top;
- volatile struct rbd_struct *rbds;
- printk("%s: received a FC intr. without having a frame: %04x %d\n",dev->name,status,old_at_least);
- for(i=0;i< (p->num_recv_buffs+4);i++)
- {
- rbds = (struct rbd_struct *) make32(rfds->rbd_offset);
- printk("%04x:%04x ",rfds->status,rbds->status);
- rfds = (struct rfd_struct *) make32(rfds->next);
- }
- printk("\nerrs: %04x %04x stat: %04x\n",(int)p->scb->rsc_errs,(int)p->scb->ovrn_errs,(int)p->scb->status);
- printk("\nerrs: %04x %04x rus: %02x, cus: %02x\n",(int)p->scb->rsc_errs,(int)p->scb->ovrn_errs,(int)p->scb->rus,(int)p->scb->cus);
- }
- old_at_least = at_least_one;
-#endif
-
- if(debuglevel > 0)
- printk("r");
-}
-
-/**********************************************************
- * handle 'Receiver went not ready'.
- */
-
-static void sun3_82586_rnr_int(struct net_device *dev)
-{
- struct priv *p = netdev_priv(dev);
-
- dev->stats.rx_errors++;
-
- WAIT_4_SCB_CMD(); /* wait for the last cmd, WAIT_4_FULLSTAT?? */
- p->scb->cmd_ruc = RUC_ABORT; /* usually the RU is in the 'no resource'-state .. abort it now. */
- sun3_attn586();
- WAIT_4_SCB_CMD_RUC(); /* wait for accept cmd. */
-
- alloc_rfa(dev,(char *)p->rfd_first);
-/* maybe add a check here, before restarting the RU */
- startrecv586(dev); /* restart RU */
-
- printk("%s: Receive-Unit restarted. Status: %04x\n",dev->name,p->scb->rus);
-
-}
-
-/**********************************************************
- * handle xmit - interrupt
- */
-
-static void sun3_82586_xmt_int(struct net_device *dev)
-{
- int status;
- struct priv *p = netdev_priv(dev);
-
- if(debuglevel > 0)
- printk("X");
-
- status = swab16(p->xmit_cmds[p->xmit_last]->cmd_status);
- if(!(status & STAT_COMPL))
- printk("%s: strange .. xmit-int without a 'COMPLETE'\n",dev->name);
-
- if(status & STAT_OK)
- {
- dev->stats.tx_packets++;
- dev->stats.collisions += (status & TCMD_MAXCOLLMASK);
- }
- else
- {
- dev->stats.tx_errors++;
- if(status & TCMD_LATECOLL) {
- printk("%s: late collision detected.\n",dev->name);
- dev->stats.collisions++;
- }
- else if(status & TCMD_NOCARRIER) {
- dev->stats.tx_carrier_errors++;
- printk("%s: no carrier detected.\n",dev->name);
- }
- else if(status & TCMD_LOSTCTS)
- printk("%s: loss of CTS detected.\n",dev->name);
- else if(status & TCMD_UNDERRUN) {
- dev->stats.tx_fifo_errors++;
- printk("%s: DMA underrun detected.\n",dev->name);
- }
- else if(status & TCMD_MAXCOLL) {
- printk("%s: Max. collisions exceeded.\n",dev->name);
- dev->stats.collisions += 16;
- }
- }
-
-#if (NUM_XMIT_BUFFS > 1)
- if( (++p->xmit_last) == NUM_XMIT_BUFFS)
- p->xmit_last = 0;
-#endif
- netif_wake_queue(dev);
-}
-
-/***********************************************************
- * (re)start the receiver
- */
-
-static void startrecv586(struct net_device *dev)
-{
- struct priv *p = netdev_priv(dev);
-
- WAIT_4_SCB_CMD();
- WAIT_4_SCB_CMD_RUC();
- p->scb->rfa_offset = make16(p->rfd_first);
- p->scb->cmd_ruc = RUC_START;
- sun3_attn586(); /* start cmd. */
- WAIT_4_SCB_CMD_RUC(); /* wait for accept cmd. (no timeout!!) */
-}
-
-static void sun3_82586_timeout(struct net_device *dev)
-{
- struct priv *p = netdev_priv(dev);
-#ifndef NO_NOPCOMMANDS
- if(p->scb->cus & CU_ACTIVE) /* COMMAND-UNIT active? */
- {
- netif_wake_queue(dev);
-#ifdef DEBUG
- printk("%s: strange ... timeout with CU active?!?\n",dev->name);
- printk("%s: X0: %04x N0: %04x N1: %04x %d\n",dev->name,(int)swab16(p->xmit_cmds[0]->cmd_status),(int)swab16(p->nop_cmds[0]->cmd_status),(int)swab16(p->nop_cmds[1]->cmd_status),(int)p->nop_point);
-#endif
- p->scb->cmd_cuc = CUC_ABORT;
- sun3_attn586();
- WAIT_4_SCB_CMD();
- p->scb->cbl_offset = make16(p->nop_cmds[p->nop_point]);
- p->scb->cmd_cuc = CUC_START;
- sun3_attn586();
- WAIT_4_SCB_CMD();
- dev->trans_start = jiffies; /* prevent tx timeout */
- return 0;
- }
-#endif
- {
-#ifdef DEBUG
- printk("%s: xmitter timed out, try to restart! stat: %02x\n",dev->name,p->scb->cus);
- printk("%s: command-stats: %04x %04x\n",dev->name,swab16(p->xmit_cmds[0]->cmd_status),swab16(p->xmit_cmds[1]->cmd_status));
- printk("%s: check, whether you set the right interrupt number!\n",dev->name);
-#endif
- sun3_82586_close(dev);
- sun3_82586_open(dev);
- }
- dev->trans_start = jiffies; /* prevent tx timeout */
-}
-
-/******************************************************
- * send frame
- */
-
-static int sun3_82586_send_packet(struct sk_buff *skb, struct net_device *dev)
-{
- int len,i;
-#ifndef NO_NOPCOMMANDS
- int next_nop;
-#endif
- struct priv *p = netdev_priv(dev);
-
- if(skb->len > XMIT_BUFF_SIZE)
- {
- printk("%s: Sorry, max. framelength is %d bytes. The length of your frame is %d bytes.\n",dev->name,XMIT_BUFF_SIZE,skb->len);
- return NETDEV_TX_OK;
- }
-
- netif_stop_queue(dev);
-
-#if(NUM_XMIT_BUFFS > 1)
- if(test_and_set_bit(0,(void *) &p->lock)) {
- printk("%s: Queue was locked\n",dev->name);
- return NETDEV_TX_BUSY;
- }
- else
-#endif
- {
- len = skb->len;
- if (len < ETH_ZLEN) {
- memset((void *)p->xmit_cbuffs[p->xmit_count], 0,
- ETH_ZLEN);
- len = ETH_ZLEN;
- }
- skb_copy_from_linear_data(skb, (void *)p->xmit_cbuffs[p->xmit_count], skb->len);
-
-#if (NUM_XMIT_BUFFS == 1)
-# ifdef NO_NOPCOMMANDS
-
-#ifdef DEBUG
- if(p->scb->cus & CU_ACTIVE)
- {
- printk("%s: Hmmm .. CU is still running and we wanna send a new packet.\n",dev->name);
- printk("%s: stat: %04x %04x\n",dev->name,p->scb->cus,swab16(p->xmit_cmds[0]->cmd_status));
- }
-#endif
-
- p->xmit_buffs[0]->size = swab16(TBD_LAST | len);
- for(i=0;i<16;i++)
- {
- p->xmit_cmds[0]->cmd_status = 0;
- WAIT_4_SCB_CMD();
- if( (p->scb->cus & CU_STATUS) == CU_SUSPEND)
- p->scb->cmd_cuc = CUC_RESUME;
- else
- {
- p->scb->cbl_offset = make16(p->xmit_cmds[0]);
- p->scb->cmd_cuc = CUC_START;
- }
-
- sun3_attn586();
- if(!i)
- dev_kfree_skb(skb);
- WAIT_4_SCB_CMD();
- if( (p->scb->cus & CU_ACTIVE)) /* test it, because CU sometimes doesn't start immediately */
- break;
- if(p->xmit_cmds[0]->cmd_status)
- break;
- if(i==15)
- printk("%s: Can't start transmit-command.\n",dev->name);
- }
-# else
- next_nop = (p->nop_point + 1) & 0x1;
- p->xmit_buffs[0]->size = swab16(TBD_LAST | len);
-
- p->xmit_cmds[0]->cmd_link = p->nop_cmds[next_nop]->cmd_link
- = make16((p->nop_cmds[next_nop]));
- p->xmit_cmds[0]->cmd_status = p->nop_cmds[next_nop]->cmd_status = 0;
-
- p->nop_cmds[p->nop_point]->cmd_link = make16((p->xmit_cmds[0]));
- p->nop_point = next_nop;
- dev_kfree_skb(skb);
-# endif
-#else
- p->xmit_buffs[p->xmit_count]->size = swab16(TBD_LAST | len);
- if( (next_nop = p->xmit_count + 1) == NUM_XMIT_BUFFS )
- next_nop = 0;
-
- p->xmit_cmds[p->xmit_count]->cmd_status = 0;
- /* linkpointer of xmit-command already points to next nop cmd */
- p->nop_cmds[next_nop]->cmd_link = make16((p->nop_cmds[next_nop]));
- p->nop_cmds[next_nop]->cmd_status = 0;
-
- p->nop_cmds[p->xmit_count]->cmd_link = make16((p->xmit_cmds[p->xmit_count]));
- p->xmit_count = next_nop;
-
- {
- unsigned long flags;
- local_irq_save(flags);
- if(p->xmit_count != p->xmit_last)
- netif_wake_queue(dev);
- p->lock = 0;
- local_irq_restore(flags);
- }
- dev_kfree_skb(skb);
-#endif
- }
- return NETDEV_TX_OK;
-}
-
-/*******************************************
- * Someone wanna have the statistics
- */
-
-static struct net_device_stats *sun3_82586_get_stats(struct net_device *dev)
-{
- struct priv *p = netdev_priv(dev);
- unsigned short crc,aln,rsc,ovrn;
-
- crc = swab16(p->scb->crc_errs); /* get error-statistic from the ni82586 */
- p->scb->crc_errs = 0;
- aln = swab16(p->scb->aln_errs);
- p->scb->aln_errs = 0;
- rsc = swab16(p->scb->rsc_errs);
- p->scb->rsc_errs = 0;
- ovrn = swab16(p->scb->ovrn_errs);
- p->scb->ovrn_errs = 0;
-
- dev->stats.rx_crc_errors += crc;
- dev->stats.rx_fifo_errors += ovrn;
- dev->stats.rx_frame_errors += aln;
- dev->stats.rx_dropped += rsc;
-
- return &dev->stats;
-}
-
-/********************************************************
- * Set MC list ..
- */
-
-static void set_multicast_list(struct net_device *dev)
-{
- netif_stop_queue(dev);
- sun3_disint();
- alloc586(dev);
- init586(dev);
- startrecv586(dev);
- sun3_enaint();
- netif_wake_queue(dev);
-}
-
-#ifdef MODULE
-#error This code is not currently supported as a module
-static struct net_device *dev_sun3_82586;
-
-int init_module(void)
-{
- dev_sun3_82586 = sun3_82586_probe(-1);
- if (IS_ERR(dev_sun3_82586))
- return PTR_ERR(dev_sun3_82586);
- return 0;
-}
-
-void cleanup_module(void)
-{
- unsigned long ioaddr = dev_sun3_82586->base_addr;
- unregister_netdev(dev_sun3_82586);
- release_region(ioaddr, SUN3_82586_TOTAL_SIZE);
- iounmap((void *)ioaddr);
- free_netdev(dev_sun3_82586);
-}
-#endif /* MODULE */
-
-#if 0
-/*
- * DUMP .. we expect a not running CMD unit and enough space
- */
-void sun3_82586_dump(struct net_device *dev,void *ptr)
-{
- struct priv *p = netdev_priv(dev);
- struct dump_cmd_struct *dump_cmd = (struct dump_cmd_struct *) ptr;
- int i;
-
- p->scb->cmd_cuc = CUC_ABORT;
- sun3_attn586();
- WAIT_4_SCB_CMD();
- WAIT_4_SCB_CMD_RUC();
-
- dump_cmd->cmd_status = 0;
- dump_cmd->cmd_cmd = CMD_DUMP | CMD_LAST;
- dump_cmd->dump_offset = make16((dump_cmd + 1));
- dump_cmd->cmd_link = 0xffff;
-
- p->scb->cbl_offset = make16(dump_cmd);
- p->scb->cmd_cuc = CUC_START;
- sun3_attn586();
- WAIT_4_STAT_COMPL(dump_cmd);
-
- if( (dump_cmd->cmd_status & (STAT_COMPL|STAT_OK)) != (STAT_COMPL|STAT_OK) )
- printk("%s: Can't get dump information.\n",dev->name);
-
- for(i=0;i<170;i++) {
- printk("%02x ",(int) ((unsigned char *) (dump_cmd + 1))[i]);
- if(i % 24 == 23)
- printk("\n");
- }
- printk("\n");
-}
-#endif
-
-MODULE_LICENSE("GPL");
+++ /dev/null
-/*
- * Intel i82586 Ethernet definitions
- *
- * This is an extension to the Linux operating system, and is covered by the
- * same Gnu Public License that covers that work.
- *
- * copyrights (c) 1994 by Michael Hipp (hippm@informatik.uni-tuebingen.de)
- *
- * I have done a look in the following sources:
- * crynwr-packet-driver by Russ Nelson
- * Garret A. Wollman's i82586-driver for BSD
- */
-
-/*
- * Cloned from ni52.h, copyright as above.
- *
- * Modified for Sun3 OBIO i82586 by Sam Creasey (sammy@sammy.net)
- */
-
-
-/* defines for the obio chip (not vme) */
-#define IEOB_NORSET 0x80 /* don't reset the board */
-#define IEOB_ONAIR 0x40 /* put us on the air */
-#define IEOB_ATTEN 0x20 /* attention! */
-#define IEOB_IENAB 0x10 /* interrupt enable */
-#define IEOB_XXXXX 0x08 /* free bit */
-#define IEOB_XCVRL2 0x04 /* level 2 transceiver? */
-#define IEOB_BUSERR 0x02 /* bus error */
-#define IEOB_INT 0x01 /* interrupt */
-
-/* where the obio one lives */
-#define IE_OBIO 0xc0000
-#define IE_IRQ 3
-
-/*
- * where to find the System Configuration Pointer (SCP)
- */
-#define SCP_DEFAULT_ADDRESS 0xfffff4
-
-
-/*
- * System Configuration Pointer Struct
- */
-
-struct scp_struct
-{
- unsigned short zero_dum0; /* has to be zero */
- unsigned char sysbus; /* 0=16Bit,1=8Bit */
- unsigned char zero_dum1; /* has to be zero for 586 */
- unsigned short zero_dum2;
- unsigned short zero_dum3;
- char *iscp; /* pointer to the iscp-block */
-};
-
-
-/*
- * Intermediate System Configuration Pointer (ISCP)
- */
-struct iscp_struct
-{
- unsigned char busy; /* 586 clears after successful init */
- unsigned char zero_dummy; /* has to be zero */
- unsigned short scb_offset; /* pointeroffset to the scb_base */
- char *scb_base; /* base-address of all 16-bit offsets */
-};
-
-/*
- * System Control Block (SCB)
- */
-struct scb_struct
-{
- unsigned char rus;
- unsigned char cus;
- unsigned char cmd_ruc; /* command word: RU part */
- unsigned char cmd_cuc; /* command word: CU part & ACK */
- unsigned short cbl_offset; /* pointeroffset, command block list */
- unsigned short rfa_offset; /* pointeroffset, receive frame area */
- unsigned short crc_errs; /* CRC-Error counter */
- unsigned short aln_errs; /* allignmenterror counter */
- unsigned short rsc_errs; /* Resourceerror counter */
- unsigned short ovrn_errs; /* OVerrunerror counter */
-};
-
-/*
- * possible command values for the command word
- */
-#define RUC_MASK 0x0070 /* mask for RU commands */
-#define RUC_NOP 0x0000 /* NOP-command */
-#define RUC_START 0x0010 /* start RU */
-#define RUC_RESUME 0x0020 /* resume RU after suspend */
-#define RUC_SUSPEND 0x0030 /* suspend RU */
-#define RUC_ABORT 0x0040 /* abort receiver operation immediately */
-
-#define CUC_MASK 0x07 /* mask for CU command */
-#define CUC_NOP 0x00 /* NOP-command */
-#define CUC_START 0x01 /* start execution of 1. cmd on the CBL */
-#define CUC_RESUME 0x02 /* resume after suspend */
-#define CUC_SUSPEND 0x03 /* Suspend CU */
-#define CUC_ABORT 0x04 /* abort command operation immediately */
-
-#define ACK_MASK 0xf0 /* mask for ACK command */
-#define ACK_CX 0x80 /* acknowledges STAT_CX */
-#define ACK_FR 0x40 /* ack. STAT_FR */
-#define ACK_CNA 0x20 /* ack. STAT_CNA */
-#define ACK_RNR 0x10 /* ack. STAT_RNR */
-
-/*
- * possible status values for the status word
- */
-#define STAT_MASK 0xf0 /* mask for cause of interrupt */
-#define STAT_CX 0x80 /* CU finished cmd with its I bit set */
-#define STAT_FR 0x40 /* RU finished receiving a frame */
-#define STAT_CNA 0x20 /* CU left active state */
-#define STAT_RNR 0x10 /* RU left ready state */
-
-#define CU_STATUS 0x7 /* CU status, 0=idle */
-#define CU_SUSPEND 0x1 /* CU is suspended */
-#define CU_ACTIVE 0x2 /* CU is active */
-
-#define RU_STATUS 0x70 /* RU status, 0=idle */
-#define RU_SUSPEND 0x10 /* RU suspended */
-#define RU_NOSPACE 0x20 /* RU no resources */
-#define RU_READY 0x40 /* RU is ready */
-
-/*
- * Receive Frame Descriptor (RFD)
- */
-struct rfd_struct
-{
- unsigned char stat_low; /* status word */
- unsigned char stat_high; /* status word */
- unsigned char rfd_sf; /* 82596 mode only */
- unsigned char last; /* Bit15,Last Frame on List / Bit14,suspend */
- unsigned short next; /* linkoffset to next RFD */
- unsigned short rbd_offset; /* pointeroffset to RBD-buffer */
- unsigned char dest[6]; /* ethernet-address, destination */
- unsigned char source[6]; /* ethernet-address, source */
- unsigned short length; /* 802.3 frame-length */
- unsigned short zero_dummy; /* dummy */
-};
-
-#define RFD_LAST 0x80 /* last: last rfd in the list */
-#define RFD_SUSP 0x40 /* last: suspend RU after */
-#define RFD_COMPL 0x80
-#define RFD_OK 0x20
-#define RFD_BUSY 0x40
-#define RFD_ERR_LEN 0x10 /* Length error (if enabled length-checking */
-#define RFD_ERR_CRC 0x08 /* CRC error */
-#define RFD_ERR_ALGN 0x04 /* Alignment error */
-#define RFD_ERR_RNR 0x02 /* status: receiver out of resources */
-#define RFD_ERR_OVR 0x01 /* DMA Overrun! */
-
-#define RFD_ERR_FTS 0x0080 /* Frame to short */
-#define RFD_ERR_NEOP 0x0040 /* No EOP flag (for bitstuffing only) */
-#define RFD_ERR_TRUN 0x0020 /* (82596 only/SF mode) indicates truncated frame */
-#define RFD_MATCHADD 0x0002 /* status: Destinationaddress !matches IA (only 82596) */
-#define RFD_COLLDET 0x0001 /* Detected collision during reception */
-
-/*
- * Receive Buffer Descriptor (RBD)
- */
-struct rbd_struct
-{
- unsigned short status; /* status word,number of used bytes in buff */
- unsigned short next; /* pointeroffset to next RBD */
- char *buffer; /* receive buffer address pointer */
- unsigned short size; /* size of this buffer */
- unsigned short zero_dummy; /* dummy */
-};
-
-#define RBD_LAST 0x8000 /* last buffer */
-#define RBD_USED 0x4000 /* this buffer has data */
-#define RBD_MASK 0x3fff /* size-mask for length */
-
-/*
- * Statusvalues for Commands/RFD
- */
-#define STAT_COMPL 0x8000 /* status: frame/command is complete */
-#define STAT_BUSY 0x4000 /* status: frame/command is busy */
-#define STAT_OK 0x2000 /* status: frame/command is ok */
-
-/*
- * Action-Commands
- */
-#define CMD_NOP 0x0000 /* NOP */
-#define CMD_IASETUP 0x0001 /* initial address setup command */
-#define CMD_CONFIGURE 0x0002 /* configure command */
-#define CMD_MCSETUP 0x0003 /* MC setup command */
-#define CMD_XMIT 0x0004 /* transmit command */
-#define CMD_TDR 0x0005 /* time domain reflectometer (TDR) command */
-#define CMD_DUMP 0x0006 /* dump command */
-#define CMD_DIAGNOSE 0x0007 /* diagnose command */
-
-/*
- * Action command bits
- */
-#define CMD_LAST 0x8000 /* indicates last command in the CBL */
-#define CMD_SUSPEND 0x4000 /* suspend CU after this CB */
-#define CMD_INT 0x2000 /* generate interrupt after execution */
-
-/*
- * NOP - command
- */
-struct nop_cmd_struct
-{
- unsigned short cmd_status; /* status of this command */
- unsigned short cmd_cmd; /* the command itself (+bits) */
- unsigned short cmd_link; /* offsetpointer to next command */
-};
-
-/*
- * IA Setup command
- */
-struct iasetup_cmd_struct
-{
- unsigned short cmd_status;
- unsigned short cmd_cmd;
- unsigned short cmd_link;
- unsigned char iaddr[6];
-};
-
-/*
- * Configure command
- */
-struct configure_cmd_struct
-{
- unsigned short cmd_status;
- unsigned short cmd_cmd;
- unsigned short cmd_link;
- unsigned char byte_cnt; /* size of the config-cmd */
- unsigned char fifo; /* fifo/recv monitor */
- unsigned char sav_bf; /* save bad frames (bit7=1)*/
- unsigned char adr_len; /* adr_len(0-2),al_loc(3),pream(4-5),loopbak(6-7)*/
- unsigned char priority; /* lin_prio(0-2),exp_prio(4-6),bof_metd(7) */
- unsigned char ifs; /* inter frame spacing */
- unsigned char time_low; /* slot time low */
- unsigned char time_high; /* slot time high(0-2) and max. retries(4-7) */
- unsigned char promisc; /* promisc-mode(0) , et al (1-7) */
- unsigned char carr_coll; /* carrier(0-3)/collision(4-7) stuff */
- unsigned char fram_len; /* minimal frame len */
- unsigned char dummy; /* dummy */
-};
-
-/*
- * Multicast Setup command
- */
-struct mcsetup_cmd_struct
-{
- unsigned short cmd_status;
- unsigned short cmd_cmd;
- unsigned short cmd_link;
- unsigned short mc_cnt; /* number of bytes in the MC-List */
- unsigned char mc_list[0][6]; /* pointer to 6 bytes entries */
-};
-
-/*
- * DUMP command
- */
-struct dump_cmd_struct
-{
- unsigned short cmd_status;
- unsigned short cmd_cmd;
- unsigned short cmd_link;
- unsigned short dump_offset; /* pointeroffset to DUMP space */
-};
-
-/*
- * transmit command
- */
-struct transmit_cmd_struct
-{
- unsigned short cmd_status;
- unsigned short cmd_cmd;
- unsigned short cmd_link;
- unsigned short tbd_offset; /* pointeroffset to TBD */
- unsigned char dest[6]; /* destination address of the frame */
- unsigned short length; /* user defined: 802.3 length / Ether type */
-};
-
-#define TCMD_ERRMASK 0x0fa0
-#define TCMD_MAXCOLLMASK 0x000f
-#define TCMD_MAXCOLL 0x0020
-#define TCMD_HEARTBEAT 0x0040
-#define TCMD_DEFERRED 0x0080
-#define TCMD_UNDERRUN 0x0100
-#define TCMD_LOSTCTS 0x0200
-#define TCMD_NOCARRIER 0x0400
-#define TCMD_LATECOLL 0x0800
-
-struct tdr_cmd_struct
-{
- unsigned short cmd_status;
- unsigned short cmd_cmd;
- unsigned short cmd_link;
- unsigned short status;
-};
-
-#define TDR_LNK_OK 0x8000 /* No link problem identified */
-#define TDR_XCVR_PRB 0x4000 /* indicates a transceiver problem */
-#define TDR_ET_OPN 0x2000 /* open, no correct termination */
-#define TDR_ET_SRT 0x1000 /* TDR detected a short circuit */
-#define TDR_TIMEMASK 0x07ff /* mask for the time field */
-
-/*
- * Transmit Buffer Descriptor (TBD)
- */
-struct tbd_struct
-{
- unsigned short size; /* size + EOF-Flag(15) */
- unsigned short next; /* pointeroffset to next TBD */
- char *buffer; /* pointer to buffer */
-};
-
-#define TBD_LAST 0x8000 /* EOF-Flag, indicates last buffer in list */
-
-
-
-
+++ /dev/null
-/* znet.c: An Zenith Z-Note ethernet driver for linux. */
-
-/*
- Written by Donald Becker.
-
- The author may be reached as becker@scyld.com.
- This driver is based on the Linux skeleton driver. The copyright of the
- skeleton driver is held by the United States Government, as represented
- by DIRNSA, and it is released under the GPL.
-
- Thanks to Mike Hollick for alpha testing and suggestions.
-
- References:
- The Crynwr packet driver.
-
- "82593 CSMA/CD Core LAN Controller" Intel datasheet, 1992
- Intel Microcommunications Databook, Vol. 1, 1990.
- As usual with Intel, the documentation is incomplete and inaccurate.
- I had to read the Crynwr packet driver to figure out how to actually
- use the i82593, and guess at what register bits matched the loosely
- related i82586.
-
- Theory of Operation
-
- The i82593 used in the Zenith Z-Note series operates using two(!) slave
- DMA channels, one interrupt, and one 8-bit I/O port.
-
- While there several ways to configure '593 DMA system, I chose the one
- that seemed commensurate with the highest system performance in the face
- of moderate interrupt latency: Both DMA channels are configured as
- recirculating ring buffers, with one channel (#0) dedicated to Rx and
- the other channel (#1) to Tx and configuration. (Note that this is
- different than the Crynwr driver, where the Tx DMA channel is initialized
- before each operation. That approach simplifies operation and Tx error
- recovery, but requires additional I/O in normal operation and precludes
- transmit buffer chaining.)
-
- Both rings are set to 8192 bytes using {TX,RX}_RING_SIZE. This provides
- a reasonable ring size for Rx, while simplifying DMA buffer allocation --
- DMA buffers must not cross a 128K boundary. (In truth the size selection
- was influenced by my lack of '593 documentation. I thus was constrained
- to use the Crynwr '593 initialization table, which sets the Rx ring size
- to 8K.)
-
- Despite my usual low opinion about Intel-designed parts, I must admit
- that the bulk data handling of the i82593 is a good design for
- an integrated system, like a laptop, where using two slave DMA channels
- doesn't pose a problem. I still take issue with using only a single I/O
- port. In the same controlled environment there are essentially no
- limitations on I/O space, and using multiple locations would eliminate
- the need for multiple operations when looking at status registers,
- setting the Rx ring boundary, or switching to promiscuous mode.
-
- I also question Zenith's selection of the '593: one of the advertised
- advantages of earlier Intel parts was that if you figured out the magic
- initialization incantation you could use the same part on many different
- network types. Zenith's use of the "FriendlyNet" (sic) connector rather
- than an on-board transceiver leads me to believe that they were planning
- to take advantage of this. But, uhmmm, the '593 omits all but ethernet
- functionality from the serial subsystem.
- */
-
-/* 10/2002
-
- o Resurected for Linux 2.5+ by Marc Zyngier <maz@wild-wind.fr.eu.org> :
-
- - Removed strange DMA snooping in znet_sent_packet, which lead to
- TX buffer corruption on my laptop.
- - Use init_etherdev stuff.
- - Use kmalloc-ed DMA buffers.
- - Use as few global variables as possible.
- - Use proper resources management.
- - Use wireless/i82593.h as much as possible (structure, constants)
- - Compiles as module or build-in.
- - Now survives unplugging/replugging cable.
-
- Some code was taken from wavelan_cs.
-
- Tested on a vintage Zenith Z-Note 433Lnp+. Probably broken on
- anything else. Testers (and detailed bug reports) are welcome :-).
-
- o TODO :
-
- - Properly handle multicast
- - Understand why some traffic patterns add a 1s latency...
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/if_arp.h>
-#include <linux/bitops.h>
-
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-
-#include <linux/i82593.h>
-
-static char version[] __initdata = "znet.c:v1.02 9/23/94 becker@scyld.com\n";
-
-#ifndef ZNET_DEBUG
-#define ZNET_DEBUG 1
-#endif
-static unsigned int znet_debug = ZNET_DEBUG;
-module_param (znet_debug, int, 0);
-MODULE_PARM_DESC (znet_debug, "ZNet debug level");
-MODULE_LICENSE("GPL");
-
-/* The DMA modes we need aren't in <dma.h>. */
-#define DMA_RX_MODE 0x14 /* Auto init, I/O to mem, ++, demand. */
-#define DMA_TX_MODE 0x18 /* Auto init, Mem to I/O, ++, demand. */
-#define dma_page_eq(ptr1, ptr2) ((long)(ptr1)>>17 == (long)(ptr2)>>17)
-#define RX_BUF_SIZE 8192
-#define TX_BUF_SIZE 8192
-#define DMA_BUF_SIZE (RX_BUF_SIZE + 16) /* 8k + 16 bytes for trailers */
-
-#define TX_TIMEOUT (HZ/10)
-
-struct znet_private {
- int rx_dma, tx_dma;
- spinlock_t lock;
- short sia_base, sia_size, io_size;
- struct i82593_conf_block i593_init;
- /* The starting, current, and end pointers for the packet buffers. */
- ushort *rx_start, *rx_cur, *rx_end;
- ushort *tx_start, *tx_cur, *tx_end;
- ushort tx_buf_len; /* Tx buffer length, in words. */
-};
-
-/* Only one can be built-in;-> */
-static struct net_device *znet_dev;
-
-struct netidblk {
- char magic[8]; /* The magic number (string) "NETIDBLK" */
- unsigned char netid[8]; /* The physical station address */
- char nettype, globalopt;
- char vendor[8]; /* The machine vendor and product name. */
- char product[8];
- char irq1, irq2; /* Interrupts, only one is currently used. */
- char dma1, dma2;
- short dma_mem_misc[8]; /* DMA buffer locations (unused in Linux). */
- short iobase1, iosize1;
- short iobase2, iosize2; /* Second iobase unused. */
- char driver_options; /* Misc. bits */
- char pad;
-};
-
-static int znet_open(struct net_device *dev);
-static netdev_tx_t znet_send_packet(struct sk_buff *skb,
- struct net_device *dev);
-static irqreturn_t znet_interrupt(int irq, void *dev_id);
-static void znet_rx(struct net_device *dev);
-static int znet_close(struct net_device *dev);
-static void hardware_init(struct net_device *dev);
-static void update_stop_hit(short ioaddr, unsigned short rx_stop_offset);
-static void znet_tx_timeout (struct net_device *dev);
-
-/* Request needed resources */
-static int znet_request_resources (struct net_device *dev)
-{
- struct znet_private *znet = netdev_priv(dev);
-
- if (request_irq (dev->irq, znet_interrupt, 0, "ZNet", dev))
- goto failed;
- if (request_dma (znet->rx_dma, "ZNet rx"))
- goto free_irq;
- if (request_dma (znet->tx_dma, "ZNet tx"))
- goto free_rx_dma;
- if (!request_region (znet->sia_base, znet->sia_size, "ZNet SIA"))
- goto free_tx_dma;
- if (!request_region (dev->base_addr, znet->io_size, "ZNet I/O"))
- goto free_sia;
-
- return 0; /* Happy ! */
-
- free_sia:
- release_region (znet->sia_base, znet->sia_size);
- free_tx_dma:
- free_dma (znet->tx_dma);
- free_rx_dma:
- free_dma (znet->rx_dma);
- free_irq:
- free_irq (dev->irq, dev);
- failed:
- return -1;
-}
-
-static void znet_release_resources (struct net_device *dev)
-{
- struct znet_private *znet = netdev_priv(dev);
-
- release_region (znet->sia_base, znet->sia_size);
- release_region (dev->base_addr, znet->io_size);
- free_dma (znet->tx_dma);
- free_dma (znet->rx_dma);
- free_irq (dev->irq, dev);
-}
-
-/* Keep the magical SIA stuff in a single function... */
-static void znet_transceiver_power (struct net_device *dev, int on)
-{
- struct znet_private *znet = netdev_priv(dev);
- unsigned char v;
-
- /* Turn on/off the 82501 SIA, using zenith-specific magic. */
- /* Select LAN control register */
- outb(0x10, znet->sia_base);
-
- if (on)
- v = inb(znet->sia_base + 1) | 0x84;
- else
- v = inb(znet->sia_base + 1) & ~0x84;
-
- outb(v, znet->sia_base+1); /* Turn on/off LAN power (bit 2). */
-}
-
-/* Init the i82593, with current promisc/mcast configuration.
- Also used from hardware_init. */
-static void znet_set_multicast_list (struct net_device *dev)
-{
- struct znet_private *znet = netdev_priv(dev);
- short ioaddr = dev->base_addr;
- struct i82593_conf_block *cfblk = &znet->i593_init;
-
- memset(cfblk, 0x00, sizeof(struct i82593_conf_block));
-
- /* The configuration block. What an undocumented nightmare.
- The first set of values are those suggested (without explanation)
- for ethernet in the Intel 82586 databook. The rest appear to be
- completely undocumented, except for cryptic notes in the Crynwr
- packet driver. This driver uses the Crynwr values verbatim. */
-
- /* maz : Rewritten to take advantage of the wanvelan includes.
- At least we have names, not just blind values */
-
- /* Byte 0 */
- cfblk->fifo_limit = 10; /* = 16 B rx and 80 B tx fifo thresholds */
- cfblk->forgnesi = 0; /* 0=82C501, 1=AMD7992B compatibility */
- cfblk->fifo_32 = 1;
- cfblk->d6mod = 0; /* Run in i82593 advanced mode */
- cfblk->throttle_enb = 1;
-
- /* Byte 1 */
- cfblk->throttle = 8; /* Continuous w/interrupts, 128-clock DMA. */
- cfblk->cntrxint = 0; /* enable continuous mode receive interrupts */
- cfblk->contin = 1; /* enable continuous mode */
-
- /* Byte 2 */
- cfblk->addr_len = ETH_ALEN;
- cfblk->acloc = 1; /* Disable source addr insertion by i82593 */
- cfblk->preamb_len = 2; /* 8 bytes preamble */
- cfblk->loopback = 0; /* Loopback off */
-
- /* Byte 3 */
- cfblk->lin_prio = 0; /* Default priorities & backoff methods. */
- cfblk->tbofstop = 0;
- cfblk->exp_prio = 0;
- cfblk->bof_met = 0;
-
- /* Byte 4 */
- cfblk->ifrm_spc = 6; /* 96 bit times interframe spacing */
-
- /* Byte 5 */
- cfblk->slottim_low = 0; /* 512 bit times slot time (low) */
-
- /* Byte 6 */
- cfblk->slottim_hi = 2; /* 512 bit times slot time (high) */
- cfblk->max_retr = 15; /* 15 collisions retries */
-
- /* Byte 7 */
- cfblk->prmisc = ((dev->flags & IFF_PROMISC) ? 1 : 0); /* Promiscuous mode */
- cfblk->bc_dis = 0; /* Enable broadcast reception */
- cfblk->crs_1 = 0; /* Don't transmit without carrier sense */
- cfblk->nocrc_ins = 0; /* i82593 generates CRC */
- cfblk->crc_1632 = 0; /* 32-bit Autodin-II CRC */
- cfblk->crs_cdt = 0; /* CD not to be interpreted as CS */
-
- /* Byte 8 */
- cfblk->cs_filter = 0; /* CS is recognized immediately */
- cfblk->crs_src = 0; /* External carrier sense */
- cfblk->cd_filter = 0; /* CD is recognized immediately */
-
- /* Byte 9 */
- cfblk->min_fr_len = ETH_ZLEN >> 2; /* Minimum frame length */
-
- /* Byte A */
- cfblk->lng_typ = 1; /* Type/length checks OFF */
- cfblk->lng_fld = 1; /* Disable 802.3 length field check */
- cfblk->rxcrc_xf = 1; /* Don't transfer CRC to memory */
- cfblk->artx = 1; /* Disable automatic retransmission */
- cfblk->sarec = 1; /* Disable source addr trig of CD */
- cfblk->tx_jabber = 0; /* Disable jabber jam sequence */
- cfblk->hash_1 = 1; /* Use bits 0-5 in mc address hash */
- cfblk->lbpkpol = 0; /* Loopback pin active high */
-
- /* Byte B */
- cfblk->fdx = 0; /* Disable full duplex operation */
-
- /* Byte C */
- cfblk->dummy_6 = 0x3f; /* all ones, Default multicast addresses & backoff. */
- cfblk->mult_ia = 0; /* No multiple individual addresses */
- cfblk->dis_bof = 0; /* Disable the backoff algorithm ?! */
-
- /* Byte D */
- cfblk->dummy_1 = 1; /* set to 1 */
- cfblk->tx_ifs_retrig = 3; /* Hmm... Disabled */
- cfblk->mc_all = (!netdev_mc_empty(dev) ||
- (dev->flags & IFF_ALLMULTI)); /* multicast all mode */
- cfblk->rcv_mon = 0; /* Monitor mode disabled */
- cfblk->frag_acpt = 0; /* Do not accept fragments */
- cfblk->tstrttrs = 0; /* No start transmission threshold */
-
- /* Byte E */
- cfblk->fretx = 1; /* FIFO automatic retransmission */
- cfblk->runt_eop = 0; /* drop "runt" packets */
- cfblk->hw_sw_pin = 0; /* ?? */
- cfblk->big_endn = 0; /* Big Endian ? no... */
- cfblk->syncrqs = 1; /* Synchronous DRQ deassertion... */
- cfblk->sttlen = 1; /* 6 byte status registers */
- cfblk->rx_eop = 0; /* Signal EOP on packet reception */
- cfblk->tx_eop = 0; /* Signal EOP on packet transmission */
-
- /* Byte F */
- cfblk->rbuf_size = RX_BUF_SIZE >> 12; /* Set receive buffer size */
- cfblk->rcvstop = 1; /* Enable Receive Stop Register */
-
- if (znet_debug > 2) {
- int i;
- unsigned char *c;
-
- for (i = 0, c = (char *) cfblk; i < sizeof (*cfblk); i++)
- printk ("%02X ", c[i]);
- printk ("\n");
- }
-
- *znet->tx_cur++ = sizeof(struct i82593_conf_block);
- memcpy(znet->tx_cur, cfblk, sizeof(struct i82593_conf_block));
- znet->tx_cur += sizeof(struct i82593_conf_block)/2;
- outb(OP0_CONFIGURE | CR0_CHNL, ioaddr);
-
- /* XXX FIXME maz : Add multicast addresses here, so having a
- * multicast address configured isn't equal to IFF_ALLMULTI */
-}
-
-static const struct net_device_ops znet_netdev_ops = {
- .ndo_open = znet_open,
- .ndo_stop = znet_close,
- .ndo_start_xmit = znet_send_packet,
- .ndo_set_multicast_list = znet_set_multicast_list,
- .ndo_tx_timeout = znet_tx_timeout,
- .ndo_change_mtu = eth_change_mtu,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-/* The Z-Note probe is pretty easy. The NETIDBLK exists in the safe-to-probe
- BIOS area. We just scan for the signature, and pull the vital parameters
- out of the structure. */
-
-static int __init znet_probe (void)
-{
- int i;
- struct netidblk *netinfo;
- struct znet_private *znet;
- struct net_device *dev;
- char *p;
- int err = -ENOMEM;
-
- /* This code scans the region 0xf0000 to 0xfffff for a "NETIDBLK". */
- for(p = (char *)phys_to_virt(0xf0000); p < (char *)phys_to_virt(0x100000); p++)
- if (*p == 'N' && strncmp(p, "NETIDBLK", 8) == 0)
- break;
-
- if (p >= (char *)phys_to_virt(0x100000)) {
- if (znet_debug > 1)
- printk(KERN_INFO "No Z-Note ethernet adaptor found.\n");
- return -ENODEV;
- }
-
- dev = alloc_etherdev(sizeof(struct znet_private));
- if (!dev)
- return -ENOMEM;
-
- znet = netdev_priv(dev);
-
- netinfo = (struct netidblk *)p;
- dev->base_addr = netinfo->iobase1;
- dev->irq = netinfo->irq1;
-
- /* The station address is in the "netidblk" at 0x0f0000. */
- for (i = 0; i < 6; i++)
- dev->dev_addr[i] = netinfo->netid[i];
-
- printk(KERN_INFO "%s: ZNET at %#3lx, %pM"
- ", using IRQ %d DMA %d and %d.\n",
- dev->name, dev->base_addr, dev->dev_addr,
- dev->irq, netinfo->dma1, netinfo->dma2);
-
- if (znet_debug > 1) {
- printk(KERN_INFO "%s: vendor '%16.16s' IRQ1 %d IRQ2 %d DMA1 %d DMA2 %d.\n",
- dev->name, netinfo->vendor,
- netinfo->irq1, netinfo->irq2,
- netinfo->dma1, netinfo->dma2);
- printk(KERN_INFO "%s: iobase1 %#x size %d iobase2 %#x size %d net type %2.2x.\n",
- dev->name, netinfo->iobase1, netinfo->iosize1,
- netinfo->iobase2, netinfo->iosize2, netinfo->nettype);
- }
-
- if (znet_debug > 0)
- printk(KERN_INFO "%s", version);
-
- znet->rx_dma = netinfo->dma1;
- znet->tx_dma = netinfo->dma2;
- spin_lock_init(&znet->lock);
- znet->sia_base = 0xe6; /* Magic address for the 82501 SIA */
- znet->sia_size = 2;
- /* maz: Despite the '593 being advertised above as using a
- * single 8bits I/O port, this driver does many 16bits
- * access. So set io_size accordingly */
- znet->io_size = 2;
-
- if (!(znet->rx_start = kmalloc (DMA_BUF_SIZE, GFP_KERNEL | GFP_DMA)))
- goto free_dev;
- if (!(znet->tx_start = kmalloc (DMA_BUF_SIZE, GFP_KERNEL | GFP_DMA)))
- goto free_rx;
-
- if (!dma_page_eq (znet->rx_start, znet->rx_start + (RX_BUF_SIZE/2-1)) ||
- !dma_page_eq (znet->tx_start, znet->tx_start + (TX_BUF_SIZE/2-1))) {
- printk (KERN_WARNING "tx/rx crossing DMA frontiers, giving up\n");
- goto free_tx;
- }
-
- znet->rx_end = znet->rx_start + RX_BUF_SIZE/2;
- znet->tx_buf_len = TX_BUF_SIZE/2;
- znet->tx_end = znet->tx_start + znet->tx_buf_len;
-
- /* The ZNET-specific entries in the device structure. */
- dev->netdev_ops = &znet_netdev_ops;
- dev->watchdog_timeo = TX_TIMEOUT;
- err = register_netdev(dev);
- if (err)
- goto free_tx;
- znet_dev = dev;
- return 0;
-
- free_tx:
- kfree(znet->tx_start);
- free_rx:
- kfree(znet->rx_start);
- free_dev:
- free_netdev(dev);
- return err;
-}
-
-
-static int znet_open(struct net_device *dev)
-{
- int ioaddr = dev->base_addr;
-
- if (znet_debug > 2)
- printk(KERN_DEBUG "%s: znet_open() called.\n", dev->name);
-
- /* These should never fail. You can't add devices to a sealed box! */
- if (znet_request_resources (dev)) {
- printk(KERN_WARNING "%s: Not opened -- resource busy?!?\n", dev->name);
- return -EBUSY;
- }
-
- znet_transceiver_power (dev, 1);
-
- /* According to the Crynwr driver we should wait 50 msec. for the
- LAN clock to stabilize. My experiments indicates that the '593 can
- be initialized immediately. The delay is probably needed for the
- DC-to-DC converter to come up to full voltage, and for the oscillator
- to be spot-on at 20Mhz before transmitting.
- Until this proves to be a problem we rely on the higher layers for the
- delay and save allocating a timer entry. */
-
- /* maz : Well, I'm getting every time the following message
- * without the delay on a 486@33. This machine is much too
- * fast... :-) So maybe the Crynwr driver wasn't wrong after
- * all, even if the message is completly harmless on my
- * setup. */
- mdelay (50);
-
- /* This follows the packet driver's lead, and checks for success. */
- if (inb(ioaddr) != 0x10 && inb(ioaddr) != 0x00)
- printk(KERN_WARNING "%s: Problem turning on the transceiver power.\n",
- dev->name);
-
- hardware_init(dev);
- netif_start_queue (dev);
-
- return 0;
-}
-
-
-static void znet_tx_timeout (struct net_device *dev)
-{
- int ioaddr = dev->base_addr;
- ushort event, tx_status, rx_offset, state;
-
- outb (CR0_STATUS_0, ioaddr);
- event = inb (ioaddr);
- outb (CR0_STATUS_1, ioaddr);
- tx_status = inw (ioaddr);
- outb (CR0_STATUS_2, ioaddr);
- rx_offset = inw (ioaddr);
- outb (CR0_STATUS_3, ioaddr);
- state = inb (ioaddr);
- printk (KERN_WARNING "%s: transmit timed out, status %02x %04x %04x %02x,"
- " resetting.\n", dev->name, event, tx_status, rx_offset, state);
- if (tx_status == TX_LOST_CRS)
- printk (KERN_WARNING "%s: Tx carrier error, check transceiver cable.\n",
- dev->name);
- outb (OP0_RESET, ioaddr);
- hardware_init (dev);
- netif_wake_queue (dev);
-}
-
-static netdev_tx_t znet_send_packet(struct sk_buff *skb, struct net_device *dev)
-{
- int ioaddr = dev->base_addr;
- struct znet_private *znet = netdev_priv(dev);
- unsigned long flags;
- short length = skb->len;
-
- if (znet_debug > 4)
- printk(KERN_DEBUG "%s: ZNet_send_packet.\n", dev->name);
-
- if (length < ETH_ZLEN) {
- if (skb_padto(skb, ETH_ZLEN))
- return NETDEV_TX_OK;
- length = ETH_ZLEN;
- }
-
- netif_stop_queue (dev);
-
- /* Check that the part hasn't reset itself, probably from suspend. */
- outb(CR0_STATUS_0, ioaddr);
- if (inw(ioaddr) == 0x0010 &&
- inw(ioaddr) == 0x0000 &&
- inw(ioaddr) == 0x0010) {
- if (znet_debug > 1)
- printk (KERN_WARNING "%s : waking up\n", dev->name);
- hardware_init(dev);
- znet_transceiver_power (dev, 1);
- }
-
- if (1) {
- unsigned char *buf = (void *)skb->data;
- ushort *tx_link = znet->tx_cur - 1;
- ushort rnd_len = (length + 1)>>1;
-
- dev->stats.tx_bytes+=length;
-
- if (znet->tx_cur >= znet->tx_end)
- znet->tx_cur = znet->tx_start;
- *znet->tx_cur++ = length;
- if (znet->tx_cur + rnd_len + 1 > znet->tx_end) {
- int semi_cnt = (znet->tx_end - znet->tx_cur)<<1; /* Cvrt to byte cnt. */
- memcpy(znet->tx_cur, buf, semi_cnt);
- rnd_len -= semi_cnt>>1;
- memcpy(znet->tx_start, buf + semi_cnt, length - semi_cnt);
- znet->tx_cur = znet->tx_start + rnd_len;
- } else {
- memcpy(znet->tx_cur, buf, skb->len);
- znet->tx_cur += rnd_len;
- }
- *znet->tx_cur++ = 0;
-
- spin_lock_irqsave(&znet->lock, flags);
- {
- *tx_link = OP0_TRANSMIT | CR0_CHNL;
- /* Is this always safe to do? */
- outb(OP0_TRANSMIT | CR0_CHNL, ioaddr);
- }
- spin_unlock_irqrestore (&znet->lock, flags);
-
- netif_start_queue (dev);
-
- if (znet_debug > 4)
- printk(KERN_DEBUG "%s: Transmitter queued, length %d.\n", dev->name, length);
- }
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
-}
-
-/* The ZNET interrupt handler. */
-static irqreturn_t znet_interrupt(int irq, void *dev_id)
-{
- struct net_device *dev = dev_id;
- struct znet_private *znet = netdev_priv(dev);
- int ioaddr;
- int boguscnt = 20;
- int handled = 0;
-
- spin_lock (&znet->lock);
-
- ioaddr = dev->base_addr;
-
- outb(CR0_STATUS_0, ioaddr);
- do {
- ushort status = inb(ioaddr);
- if (znet_debug > 5) {
- ushort result, rx_ptr, running;
- outb(CR0_STATUS_1, ioaddr);
- result = inw(ioaddr);
- outb(CR0_STATUS_2, ioaddr);
- rx_ptr = inw(ioaddr);
- outb(CR0_STATUS_3, ioaddr);
- running = inb(ioaddr);
- printk(KERN_DEBUG "%s: interrupt, status %02x, %04x %04x %02x serial %d.\n",
- dev->name, status, result, rx_ptr, running, boguscnt);
- }
- if ((status & SR0_INTERRUPT) == 0)
- break;
-
- handled = 1;
-
- if ((status & SR0_EVENT_MASK) == SR0_TRANSMIT_DONE ||
- (status & SR0_EVENT_MASK) == SR0_RETRANSMIT_DONE ||
- (status & SR0_EVENT_MASK) == SR0_TRANSMIT_NO_CRC_DONE) {
- int tx_status;
- outb(CR0_STATUS_1, ioaddr);
- tx_status = inw(ioaddr);
- /* It's undocumented, but tx_status seems to match the i82586. */
- if (tx_status & TX_OK) {
- dev->stats.tx_packets++;
- dev->stats.collisions += tx_status & TX_NCOL_MASK;
- } else {
- if (tx_status & (TX_LOST_CTS | TX_LOST_CRS))
- dev->stats.tx_carrier_errors++;
- if (tx_status & TX_UND_RUN)
- dev->stats.tx_fifo_errors++;
- if (!(tx_status & TX_HRT_BEAT))
- dev->stats.tx_heartbeat_errors++;
- if (tx_status & TX_MAX_COL)
- dev->stats.tx_aborted_errors++;
- /* ...and the catch-all. */
- if ((tx_status | (TX_LOST_CRS | TX_LOST_CTS | TX_UND_RUN | TX_HRT_BEAT | TX_MAX_COL)) != (TX_LOST_CRS | TX_LOST_CTS | TX_UND_RUN | TX_HRT_BEAT | TX_MAX_COL))
- dev->stats.tx_errors++;
-
- /* Transceiver may be stuck if cable
- * was removed while emitting a
- * packet. Flip it off, then on to
- * reset it. This is very empirical,
- * but it seems to work. */
-
- znet_transceiver_power (dev, 0);
- znet_transceiver_power (dev, 1);
- }
- netif_wake_queue (dev);
- }
-
- if ((status & SR0_RECEPTION) ||
- (status & SR0_EVENT_MASK) == SR0_STOP_REG_HIT) {
- znet_rx(dev);
- }
- /* Clear the interrupts we've handled. */
- outb(CR0_INT_ACK, ioaddr);
- } while (boguscnt--);
-
- spin_unlock (&znet->lock);
-
- return IRQ_RETVAL(handled);
-}
-
-static void znet_rx(struct net_device *dev)
-{
- struct znet_private *znet = netdev_priv(dev);
- int ioaddr = dev->base_addr;
- int boguscount = 1;
- short next_frame_end_offset = 0; /* Offset of next frame start. */
- short *cur_frame_end;
- short cur_frame_end_offset;
-
- outb(CR0_STATUS_2, ioaddr);
- cur_frame_end_offset = inw(ioaddr);
-
- if (cur_frame_end_offset == znet->rx_cur - znet->rx_start) {
- printk(KERN_WARNING "%s: Interrupted, but nothing to receive, offset %03x.\n",
- dev->name, cur_frame_end_offset);
- return;
- }
-
- /* Use same method as the Crynwr driver: construct a forward list in
- the same area of the backwards links we now have. This allows us to
- pass packets to the upper layers in the order they were received --
- important for fast-path sequential operations. */
- while (znet->rx_start + cur_frame_end_offset != znet->rx_cur &&
- ++boguscount < 5) {
- unsigned short hi_cnt, lo_cnt, hi_status, lo_status;
- int count, status;
-
- if (cur_frame_end_offset < 4) {
- /* Oh no, we have a special case: the frame trailer wraps around
- the end of the ring buffer. We've saved space at the end of
- the ring buffer for just this problem. */
- memcpy(znet->rx_end, znet->rx_start, 8);
- cur_frame_end_offset += (RX_BUF_SIZE/2);
- }
- cur_frame_end = znet->rx_start + cur_frame_end_offset - 4;
-
- lo_status = *cur_frame_end++;
- hi_status = *cur_frame_end++;
- status = ((hi_status & 0xff) << 8) + (lo_status & 0xff);
- lo_cnt = *cur_frame_end++;
- hi_cnt = *cur_frame_end++;
- count = ((hi_cnt & 0xff) << 8) + (lo_cnt & 0xff);
-
- if (znet_debug > 5)
- printk(KERN_DEBUG "Constructing trailer at location %03x, %04x %04x %04x %04x"
- " count %#x status %04x.\n",
- cur_frame_end_offset<<1, lo_status, hi_status, lo_cnt, hi_cnt,
- count, status);
- cur_frame_end[-4] = status;
- cur_frame_end[-3] = next_frame_end_offset;
- cur_frame_end[-2] = count;
- next_frame_end_offset = cur_frame_end_offset;
- cur_frame_end_offset -= ((count + 1)>>1) + 3;
- if (cur_frame_end_offset < 0)
- cur_frame_end_offset += RX_BUF_SIZE/2;
- }
-
- /* Now step forward through the list. */
- do {
- ushort *this_rfp_ptr = znet->rx_start + next_frame_end_offset;
- int status = this_rfp_ptr[-4];
- int pkt_len = this_rfp_ptr[-2];
-
- if (znet_debug > 5)
- printk(KERN_DEBUG "Looking at trailer ending at %04x status %04x length %03x"
- " next %04x.\n", next_frame_end_offset<<1, status, pkt_len,
- this_rfp_ptr[-3]<<1);
- /* Once again we must assume that the i82586 docs apply. */
- if ( ! (status & RX_RCV_OK)) { /* There was an error. */
- dev->stats.rx_errors++;
- if (status & RX_CRC_ERR) dev->stats.rx_crc_errors++;
- if (status & RX_ALG_ERR) dev->stats.rx_frame_errors++;
-#if 0
- if (status & 0x0200) dev->stats.rx_over_errors++; /* Wrong. */
- if (status & 0x0100) dev->stats.rx_fifo_errors++;
-#else
- /* maz : Wild guess... */
- if (status & RX_OVRRUN) dev->stats.rx_over_errors++;
-#endif
- if (status & RX_SRT_FRM) dev->stats.rx_length_errors++;
- } else if (pkt_len > 1536) {
- dev->stats.rx_length_errors++;
- } else {
- /* Malloc up new buffer. */
- struct sk_buff *skb;
-
- skb = dev_alloc_skb(pkt_len);
- if (skb == NULL) {
- if (znet_debug)
- printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
- dev->stats.rx_dropped++;
- break;
- }
-
- if (&znet->rx_cur[(pkt_len+1)>>1] > znet->rx_end) {
- int semi_cnt = (znet->rx_end - znet->rx_cur)<<1;
- memcpy(skb_put(skb,semi_cnt), znet->rx_cur, semi_cnt);
- memcpy(skb_put(skb,pkt_len-semi_cnt), znet->rx_start,
- pkt_len - semi_cnt);
- } else {
- memcpy(skb_put(skb,pkt_len), znet->rx_cur, pkt_len);
- if (znet_debug > 6) {
- unsigned int *packet = (unsigned int *) skb->data;
- printk(KERN_DEBUG "Packet data is %08x %08x %08x %08x.\n", packet[0],
- packet[1], packet[2], packet[3]);
- }
- }
- skb->protocol=eth_type_trans(skb,dev);
- netif_rx(skb);
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += pkt_len;
- }
- znet->rx_cur = this_rfp_ptr;
- if (znet->rx_cur >= znet->rx_end)
- znet->rx_cur -= RX_BUF_SIZE/2;
- update_stop_hit(ioaddr, (znet->rx_cur - znet->rx_start)<<1);
- next_frame_end_offset = this_rfp_ptr[-3];
- if (next_frame_end_offset == 0) /* Read all the frames? */
- break; /* Done for now */
- this_rfp_ptr = znet->rx_start + next_frame_end_offset;
- } while (--boguscount);
-
- /* If any worth-while packets have been received, dev_rint()
- has done a mark_bh(INET_BH) for us and will work on them
- when we get to the bottom-half routine. */
-}
-
-/* The inverse routine to znet_open(). */
-static int znet_close(struct net_device *dev)
-{
- int ioaddr = dev->base_addr;
-
- netif_stop_queue (dev);
-
- outb(OP0_RESET, ioaddr); /* CMD0_RESET */
-
- if (znet_debug > 1)
- printk(KERN_DEBUG "%s: Shutting down ethercard.\n", dev->name);
- /* Turn off transceiver power. */
- znet_transceiver_power (dev, 0);
-
- znet_release_resources (dev);
-
- return 0;
-}
-
-static void show_dma(struct net_device *dev)
-{
- short ioaddr = dev->base_addr;
- unsigned char stat = inb (ioaddr);
- struct znet_private *znet = netdev_priv(dev);
- unsigned long flags;
- short dma_port = ((znet->tx_dma&3)<<2) + IO_DMA2_BASE;
- unsigned addr = inb(dma_port);
- short residue;
-
- addr |= inb(dma_port) << 8;
- residue = get_dma_residue(znet->tx_dma);
-
- if (znet_debug > 1) {
- flags=claim_dma_lock();
- printk(KERN_DEBUG "Stat:%02x Addr: %04x cnt:%3x\n",
- stat, addr<<1, residue);
- release_dma_lock(flags);
- }
-}
-
-/* Initialize the hardware. We have to do this when the board is open()ed
- or when we come out of suspend mode. */
-static void hardware_init(struct net_device *dev)
-{
- unsigned long flags;
- short ioaddr = dev->base_addr;
- struct znet_private *znet = netdev_priv(dev);
-
- znet->rx_cur = znet->rx_start;
- znet->tx_cur = znet->tx_start;
-
- /* Reset the chip, and start it up. */
- outb(OP0_RESET, ioaddr);
-
- flags=claim_dma_lock();
- disable_dma(znet->rx_dma); /* reset by an interrupting task. */
- clear_dma_ff(znet->rx_dma);
- set_dma_mode(znet->rx_dma, DMA_RX_MODE);
- set_dma_addr(znet->rx_dma, (unsigned int) znet->rx_start);
- set_dma_count(znet->rx_dma, RX_BUF_SIZE);
- enable_dma(znet->rx_dma);
- /* Now set up the Tx channel. */
- disable_dma(znet->tx_dma);
- clear_dma_ff(znet->tx_dma);
- set_dma_mode(znet->tx_dma, DMA_TX_MODE);
- set_dma_addr(znet->tx_dma, (unsigned int) znet->tx_start);
- set_dma_count(znet->tx_dma, znet->tx_buf_len<<1);
- enable_dma(znet->tx_dma);
- release_dma_lock(flags);
-
- if (znet_debug > 1)
- printk(KERN_DEBUG "%s: Initializing the i82593, rx buf %p tx buf %p\n",
- dev->name, znet->rx_start,znet->tx_start);
- /* Do an empty configure command, just like the Crynwr driver. This
- resets to chip to its default values. */
- *znet->tx_cur++ = 0;
- *znet->tx_cur++ = 0;
- show_dma(dev);
- outb(OP0_CONFIGURE | CR0_CHNL, ioaddr);
-
- znet_set_multicast_list (dev);
-
- *znet->tx_cur++ = 6;
- memcpy(znet->tx_cur, dev->dev_addr, 6);
- znet->tx_cur += 3;
- show_dma(dev);
- outb(OP0_IA_SETUP | CR0_CHNL, ioaddr);
- show_dma(dev);
-
- update_stop_hit(ioaddr, 8192);
- if (znet_debug > 1) printk(KERN_DEBUG "enabling Rx.\n");
- outb(OP0_RCV_ENABLE, ioaddr);
- netif_start_queue (dev);
-}
-
-static void update_stop_hit(short ioaddr, unsigned short rx_stop_offset)
-{
- outb(OP0_SWIT_TO_PORT_1 | CR0_CHNL, ioaddr);
- if (znet_debug > 5)
- printk(KERN_DEBUG "Updating stop hit with value %02x.\n",
- (rx_stop_offset >> 6) | CR1_STOP_REG_UPDATE);
- outb((rx_stop_offset >> 6) | CR1_STOP_REG_UPDATE, ioaddr);
- outb(OP1_SWIT_TO_PORT_0, ioaddr);
-}
-
-static __exit void znet_cleanup (void)
-{
- if (znet_dev) {
- struct znet_private *znet = netdev_priv(znet_dev);
-
- unregister_netdev (znet_dev);
- kfree (znet->rx_start);
- kfree (znet->tx_start);
- free_netdev (znet_dev);
- }
-}
-
-module_init (znet_probe);
-module_exit (znet_cleanup);