i825xx: Move the Intel 82586/82593/82596 based drivers

Move the drivers that use the i82586/i82593/i82596 chipsets into
drivers/net/ethernet/i825xx/ and make the necessary Kconfig and
Makefile changes.  There were 4 3Com drivers which were initially
moved into 3com/, which now reside in i825xx since they all used
the i82586 chip.

CC: Philip Blundell <philb@gnu.org>
CC: Russell King <linux@arm.linux.org.uk>
CC: <aris@cathedrallabs.org>
CC: Donald Becker <becker@scyld.com>
CC: Chris Beauregard <cpbeaure@undergrad.math.uwaterloo.ca>
CC: Richard Procter <rnp@paradise.net.nz>
CC: Andries Brouwer <aeb@cwi.nl>
CC: "M.Hipp" <hippm@informatik.uni-tuebingen.de>
CC: Richard Hirst <richard@sleepie.demon.co.uk>
CC: Sam Creasey <sammy@oh.verio.com>
CC: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
This commit is contained in:
Jeff Kirsher
2011-07-13 15:38:08 -07:00
parent ae150435b5
commit 1159788592
31 changed files with 208 additions and 194 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,292 @@
/*****************************************************************
*
* defines for 3Com Etherlink Plus adapter
*
*****************************************************************/
#define ELP_DMA 6
#define ELP_RX_PCBS 4
#define ELP_MAX_CARDS 4
/*
* I/O register offsets
*/
#define PORT_COMMAND 0x00 /* read/write, 8-bit */
#define PORT_STATUS 0x02 /* read only, 8-bit */
#define PORT_AUXDMA 0x02 /* write only, 8-bit */
#define PORT_DATA 0x04 /* read/write, 16-bit */
#define PORT_CONTROL 0x06 /* read/write, 8-bit */
#define ELP_IO_EXTENT 0x10 /* size of used IO registers */
/*
* host control registers bits
*/
#define ATTN 0x80 /* attention */
#define FLSH 0x40 /* flush data register */
#define DMAE 0x20 /* DMA enable */
#define DIR 0x10 /* direction */
#define TCEN 0x08 /* terminal count interrupt enable */
#define CMDE 0x04 /* command register interrupt enable */
#define HSF2 0x02 /* host status flag 2 */
#define HSF1 0x01 /* host status flag 1 */
/*
* combinations of HSF flags used for PCB transmission
*/
#define HSF_PCB_ACK HSF1
#define HSF_PCB_NAK HSF2
#define HSF_PCB_END (HSF2|HSF1)
#define HSF_PCB_MASK (HSF2|HSF1)
/*
* host status register bits
*/
#define HRDY 0x80 /* data register ready */
#define HCRE 0x40 /* command register empty */
#define ACRF 0x20 /* adapter command register full */
/* #define DIR 0x10 direction - same as in control register */
#define DONE 0x08 /* DMA done */
#define ASF3 0x04 /* adapter status flag 3 */
#define ASF2 0x02 /* adapter status flag 2 */
#define ASF1 0x01 /* adapter status flag 1 */
/*
* combinations of ASF flags used for PCB reception
*/
#define ASF_PCB_ACK ASF1
#define ASF_PCB_NAK ASF2
#define ASF_PCB_END (ASF2|ASF1)
#define ASF_PCB_MASK (ASF2|ASF1)
/*
* host aux DMA register bits
*/
#define DMA_BRST 0x01 /* DMA burst */
/*
* maximum amount of data allowed in a PCB
*/
#define MAX_PCB_DATA 62
/*****************************************************************
*
* timeout value
* this is a rough value used for loops to stop them from
* locking up the whole machine in the case of failure or
* error conditions
*
*****************************************************************/
#define TIMEOUT 300
/*****************************************************************
*
* PCB commands
*
*****************************************************************/
enum {
/*
* host PCB commands
*/
CMD_CONFIGURE_ADAPTER_MEMORY = 0x01,
CMD_CONFIGURE_82586 = 0x02,
CMD_STATION_ADDRESS = 0x03,
CMD_DMA_DOWNLOAD = 0x04,
CMD_DMA_UPLOAD = 0x05,
CMD_PIO_DOWNLOAD = 0x06,
CMD_PIO_UPLOAD = 0x07,
CMD_RECEIVE_PACKET = 0x08,
CMD_TRANSMIT_PACKET = 0x09,
CMD_NETWORK_STATISTICS = 0x0a,
CMD_LOAD_MULTICAST_LIST = 0x0b,
CMD_CLEAR_PROGRAM = 0x0c,
CMD_DOWNLOAD_PROGRAM = 0x0d,
CMD_EXECUTE_PROGRAM = 0x0e,
CMD_SELF_TEST = 0x0f,
CMD_SET_STATION_ADDRESS = 0x10,
CMD_ADAPTER_INFO = 0x11,
NUM_TRANSMIT_CMDS,
/*
* adapter PCB commands
*/
CMD_CONFIGURE_ADAPTER_RESPONSE = 0x31,
CMD_CONFIGURE_82586_RESPONSE = 0x32,
CMD_ADDRESS_RESPONSE = 0x33,
CMD_DOWNLOAD_DATA_REQUEST = 0x34,
CMD_UPLOAD_DATA_REQUEST = 0x35,
CMD_RECEIVE_PACKET_COMPLETE = 0x38,
CMD_TRANSMIT_PACKET_COMPLETE = 0x39,
CMD_NETWORK_STATISTICS_RESPONSE = 0x3a,
CMD_LOAD_MULTICAST_RESPONSE = 0x3b,
CMD_CLEAR_PROGRAM_RESPONSE = 0x3c,
CMD_DOWNLOAD_PROGRAM_RESPONSE = 0x3d,
CMD_EXECUTE_RESPONSE = 0x3e,
CMD_SELF_TEST_RESPONSE = 0x3f,
CMD_SET_ADDRESS_RESPONSE = 0x40,
CMD_ADAPTER_INFO_RESPONSE = 0x41
};
/* Definitions for the PCB data structure */
/* Data units */
typedef unsigned char byte;
typedef unsigned short int word;
typedef unsigned long int dword;
/* Data structures */
struct Memconf {
word cmd_q,
rcv_q,
mcast,
frame,
rcv_b,
progs;
};
struct Rcv_pkt {
word buf_ofs,
buf_seg,
buf_len,
timeout;
};
struct Xmit_pkt {
word buf_ofs,
buf_seg,
pkt_len;
};
struct Rcv_resp {
word buf_ofs,
buf_seg,
buf_len,
pkt_len,
timeout,
status;
dword timetag;
};
struct Xmit_resp {
word buf_ofs,
buf_seg,
c_stat,
status;
};
struct Netstat {
dword tot_recv,
tot_xmit;
word err_CRC,
err_align,
err_res,
err_ovrrun;
};
struct Selftest {
word error;
union {
word ROM_cksum;
struct {
word ofs, seg;
} RAM;
word i82586;
} failure;
};
struct Info {
byte minor_vers,
major_vers;
word ROM_cksum,
RAM_sz,
free_ofs,
free_seg;
};
struct Memdump {
word size,
off,
seg;
};
/*
Primary Command Block. The most important data structure. All communication
between the host and the adapter is done with these. (Except for the actual
Ethernet data, which has different packaging.)
*/
typedef struct {
byte command;
byte length;
union {
struct Memconf memconf;
word configure;
struct Rcv_pkt rcv_pkt;
struct Xmit_pkt xmit_pkt;
byte multicast[10][6];
byte eth_addr[6];
byte failed;
struct Rcv_resp rcv_resp;
struct Xmit_resp xmit_resp;
struct Netstat netstat;
struct Selftest selftest;
struct Info info;
struct Memdump memdump;
byte raw[62];
} data;
} pcb_struct;
/* These defines for 'configure' */
#define RECV_STATION 0x00
#define RECV_BROAD 0x01
#define RECV_MULTI 0x02
#define RECV_PROMISC 0x04
#define NO_LOOPBACK 0x00
#define INT_LOOPBACK 0x08
#define EXT_LOOPBACK 0x10
/*****************************************************************
*
* structure to hold context information for adapter
*
*****************************************************************/
#define DMA_BUFFER_SIZE 1600
#define BACKLOG_SIZE 4
typedef struct {
volatile short got[NUM_TRANSMIT_CMDS]; /* flags for
command completion */
pcb_struct tx_pcb; /* PCB for foreground sending */
pcb_struct rx_pcb; /* PCB for foreground receiving */
pcb_struct itx_pcb; /* PCB for background sending */
pcb_struct irx_pcb; /* PCB for background receiving */
void *dma_buffer;
struct {
unsigned int length[BACKLOG_SIZE];
unsigned int in;
unsigned int out;
} rx_backlog;
struct {
unsigned int direction;
unsigned int length;
struct sk_buff *skb;
void *target;
unsigned long start_time;
} current_dma;
/* flags */
unsigned long send_pcb_semaphore;
unsigned long dmaing;
unsigned long busy;
unsigned int rx_active; /* number of receive PCBs */
volatile unsigned char hcr_val; /* what we think the HCR contains */
spinlock_t lock; /* Interrupt v tx lock */
} elp_device;

View File

@@ -0,0 +1,939 @@
/* 3c507.c: An EtherLink16 device driver for Linux. */
/*
Written 1993,1994 by Donald Becker.
Copyright 1993 United States Government as represented by the
Director, National Security Agency.
This software may be used and distributed according to the terms
of the GNU General Public License, incorporated herein by reference.
The author may be reached as becker@scyld.com, or C/O
Scyld Computing Corporation
410 Severn Ave., Suite 210
Annapolis MD 21403
Thanks go to jennings@Montrouge.SMR.slb.com ( Patrick Jennings)
and jrs@world.std.com (Rick Sladkey) for testing and bugfixes.
Mark Salazar <leslie@access.digex.net> made the changes for cards with
only 16K packet buffers.
Things remaining to do:
Verify that the tx and rx buffers don't have fencepost errors.
Move the theory of operation and memory map documentation.
The statistics need to be updated correctly.
*/
#define DRV_NAME "3c507"
#define DRV_VERSION "1.10a"
#define DRV_RELDATE "11/17/2001"
static const char version[] =
DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " Donald Becker (becker@scyld.com)\n";
/*
Sources:
This driver wouldn't have been written with the availability of the
Crynwr driver source code. It provided a known-working implementation
that filled in the gaping holes of the Intel documentation. Three cheers
for Russ Nelson.
Intel Microcommunications Databook, Vol. 1, 1990. It provides just enough
info that the casual reader might think that it documents the i82586 :-<.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/in.h>
#include <linux/string.h>
#include <linux/spinlock.h>
#include <linux/ethtool.h>
#include <linux/errno.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/if_ether.h>
#include <linux/skbuff.h>
#include <linux/init.h>
#include <linux/bitops.h>
#include <asm/dma.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/uaccess.h>
/* use 0 for production, 1 for verification, 2..7 for debug */
#ifndef NET_DEBUG
#define NET_DEBUG 1
#endif
static unsigned int net_debug = NET_DEBUG;
#define debug net_debug
/*
Details of the i82586.
You'll really need the databook to understand the details of this part,
but the outline is that the i82586 has two separate processing units.
Both are started from a list of three configuration tables, of which only
the last, the System Control Block (SCB), is used after reset-time. The SCB
has the following fields:
Status word
Command word
Tx/Command block addr.
Rx block addr.
The command word accepts the following controls for the Tx and Rx units:
*/
#define CUC_START 0x0100
#define CUC_RESUME 0x0200
#define CUC_SUSPEND 0x0300
#define RX_START 0x0010
#define RX_RESUME 0x0020
#define RX_SUSPEND 0x0030
/* The Rx unit uses a list of frame descriptors and a list of data buffer
descriptors. We use full-sized (1518 byte) data buffers, so there is
a one-to-one pairing of frame descriptors to buffer descriptors.
The Tx ("command") unit executes a list of commands that look like:
Status word Written by the 82586 when the command is done.
Command word Command in lower 3 bits, post-command action in upper 3
Link word The address of the next command.
Parameters (as needed).
Some definitions related to the Command Word are:
*/
#define CMD_EOL 0x8000 /* The last command of the list, stop. */
#define CMD_SUSP 0x4000 /* Suspend after doing cmd. */
#define CMD_INTR 0x2000 /* Interrupt after doing cmd. */
enum commands {
CmdNOp = 0, CmdSASetup = 1, CmdConfigure = 2, CmdMulticastList = 3,
CmdTx = 4, CmdTDR = 5, CmdDump = 6, CmdDiagnose = 7};
/* Information that need to be kept for each board. */
struct net_local {
int last_restart;
ushort rx_head;
ushort rx_tail;
ushort tx_head;
ushort tx_cmd_link;
ushort tx_reap;
ushort tx_pkts_in_ring;
spinlock_t lock;
void __iomem *base;
};
/*
Details of the EtherLink16 Implementation
The 3c507 is a generic shared-memory i82586 implementation.
The host can map 16K, 32K, 48K, or 64K of the 64K memory into
0x0[CD][08]0000, or all 64K into 0xF[02468]0000.
*/
/* Offsets from the base I/O address. */
#define SA_DATA 0 /* Station address data, or 3Com signature. */
#define MISC_CTRL 6 /* Switch the SA_DATA banks, and bus config bits. */
#define RESET_IRQ 10 /* Reset the latched IRQ line. */
#define SIGNAL_CA 11 /* Frob the 82586 Channel Attention line. */
#define ROM_CONFIG 13
#define MEM_CONFIG 14
#define IRQ_CONFIG 15
#define EL16_IO_EXTENT 16
/* The ID port is used at boot-time to locate the ethercard. */
#define ID_PORT 0x100
/* Offsets to registers in the mailbox (SCB). */
#define iSCB_STATUS 0x8
#define iSCB_CMD 0xA
#define iSCB_CBL 0xC /* Command BLock offset. */
#define iSCB_RFA 0xE /* Rx Frame Area offset. */
/* Since the 3c507 maps the shared memory window so that the last byte is
at 82586 address FFFF, the first byte is at 82586 address 0, 16K, 32K, or
48K corresponding to window sizes of 64K, 48K, 32K and 16K respectively.
We can account for this be setting the 'SBC Base' entry in the ISCP table
below for all the 16 bit offset addresses, and also adding the 'SCB Base'
value to all 24 bit physical addresses (in the SCP table and the TX and RX
Buffer Descriptors).
-Mark
*/
#define SCB_BASE ((unsigned)64*1024 - (dev->mem_end - dev->mem_start))
/*
What follows in 'init_words[]' is the "program" that is downloaded to the
82586 memory. It's mostly tables and command blocks, and starts at the
reset address 0xfffff6. This is designed to be similar to the EtherExpress,
thus the unusual location of the SCB at 0x0008.
Even with the additional "don't care" values, doing it this way takes less
program space than initializing the individual tables, and I feel it's much
cleaner.
The databook is particularly useless for the first two structures, I had
to use the Crynwr driver as an example.
The memory setup is as follows:
*/
#define CONFIG_CMD 0x0018
#define SET_SA_CMD 0x0024
#define SA_OFFSET 0x002A
#define IDLELOOP 0x30
#define TDR_CMD 0x38
#define TDR_TIME 0x3C
#define DUMP_CMD 0x40
#define DIAG_CMD 0x48
#define SET_MC_CMD 0x4E
#define DUMP_DATA 0x56 /* A 170 byte buffer for dump and Set-MC into. */
#define TX_BUF_START 0x0100
#define NUM_TX_BUFS 5
#define TX_BUF_SIZE (1518+14+20+16) /* packet+header+TBD */
#define RX_BUF_START 0x2000
#define RX_BUF_SIZE (1518+14+18) /* packet+header+RBD */
#define RX_BUF_END (dev->mem_end - dev->mem_start)
#define TX_TIMEOUT (HZ/20)
/*
That's it: only 86 bytes to set up the beast, including every extra
command available. The 170 byte buffer at DUMP_DATA is shared between the
Dump command (called only by the diagnostic program) and the SetMulticastList
command.
To complete the memory setup you only have to write the station address at
SA_OFFSET and create the Tx & Rx buffer lists.
The Tx command chain and buffer list is setup as follows:
A Tx command table, with the data buffer pointing to...
A Tx data buffer descriptor. The packet is in a single buffer, rather than
chaining together several smaller buffers.
A NoOp command, which initially points to itself,
And the packet data.
A transmit is done by filling in the Tx command table and data buffer,
re-writing the NoOp command, and finally changing the offset of the last
command to point to the current Tx command. When the Tx command is finished,
it jumps to the NoOp, when it loops until the next Tx command changes the
"link offset" in the NoOp. This way the 82586 never has to go through the
slow restart sequence.
The Rx buffer list is set up in the obvious ring structure. We have enough
memory (and low enough interrupt latency) that we can avoid the complicated
Rx buffer linked lists by alway associating a full-size Rx data buffer with
each Rx data frame.
I current use four transmit buffers starting at TX_BUF_START (0x0100), and
use the rest of memory, from RX_BUF_START to RX_BUF_END, for Rx buffers.
*/
static unsigned short init_words[] = {
/* System Configuration Pointer (SCP). */
0x0000, /* Set bus size to 16 bits. */
0,0, /* pad words. */
0x0000,0x0000, /* ISCP phys addr, set in init_82586_mem(). */
/* Intermediate System Configuration Pointer (ISCP). */
0x0001, /* Status word that's cleared when init is done. */
0x0008,0,0, /* SCB offset, (skip, skip) */
/* System Control Block (SCB). */
0,0xf000|RX_START|CUC_START, /* SCB status and cmd. */
CONFIG_CMD, /* Command list pointer, points to Configure. */
RX_BUF_START, /* Rx block list. */
0,0,0,0, /* Error count: CRC, align, buffer, overrun. */
/* 0x0018: Configure command. Change to put MAC data with packet. */
0, CmdConfigure, /* Status, command. */
SET_SA_CMD, /* Next command is Set Station Addr. */
0x0804, /* "4" bytes of config data, 8 byte FIFO. */
0x2e40, /* Magic values, including MAC data location. */
0, /* Unused pad word. */
/* 0x0024: Setup station address command. */
0, CmdSASetup,
SET_MC_CMD, /* Next command. */
0xaa00,0xb000,0x0bad, /* Station address (to be filled in) */
/* 0x0030: NOP, looping back to itself. Point to first Tx buffer to Tx. */
0, CmdNOp, IDLELOOP, 0 /* pad */,
/* 0x0038: A unused Time-Domain Reflectometer command. */
0, CmdTDR, IDLELOOP, 0,
/* 0x0040: An unused Dump State command. */
0, CmdDump, IDLELOOP, DUMP_DATA,
/* 0x0048: An unused Diagnose command. */
0, CmdDiagnose, IDLELOOP,
/* 0x004E: An empty set-multicast-list command. */
0, CmdMulticastList, IDLELOOP, 0,
};
/* Index to functions, as function prototypes. */
static int el16_probe1(struct net_device *dev, int ioaddr);
static int el16_open(struct net_device *dev);
static netdev_tx_t el16_send_packet(struct sk_buff *skb,
struct net_device *dev);
static irqreturn_t el16_interrupt(int irq, void *dev_id);
static void el16_rx(struct net_device *dev);
static int el16_close(struct net_device *dev);
static void el16_tx_timeout (struct net_device *dev);
static void hardware_send_packet(struct net_device *dev, void *buf, short length, short pad);
static void init_82586_mem(struct net_device *dev);
static const struct ethtool_ops netdev_ethtool_ops;
static void init_rx_bufs(struct net_device *);
static int io = 0x300;
static int irq;
static int mem_start;
/* Check for a network adaptor of this type, and return '0' iff one exists.
If dev->base_addr == 0, probe all likely locations.
If dev->base_addr == 1, always return failure.
If dev->base_addr == 2, (detachable devices only) allocate space for the
device and return success.
*/
struct net_device * __init el16_probe(int unit)
{
struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
static const unsigned ports[] = { 0x300, 0x320, 0x340, 0x280, 0};
const unsigned *port;
int err = -ENODEV;
if (!dev)
return ERR_PTR(-ENODEV);
if (unit >= 0) {
sprintf(dev->name, "eth%d", unit);
netdev_boot_setup_check(dev);
io = dev->base_addr;
irq = dev->irq;
mem_start = dev->mem_start & 15;
}
if (io > 0x1ff) /* Check a single specified location. */
err = el16_probe1(dev, io);
else if (io != 0)
err = -ENXIO; /* Don't probe at all. */
else {
for (port = ports; *port; port++) {
err = el16_probe1(dev, *port);
if (!err)
break;
}
}
if (err)
goto out;
err = register_netdev(dev);
if (err)
goto out1;
return dev;
out1:
free_irq(dev->irq, dev);
iounmap(((struct net_local *)netdev_priv(dev))->base);
release_region(dev->base_addr, EL16_IO_EXTENT);
out:
free_netdev(dev);
return ERR_PTR(err);
}
static const struct net_device_ops netdev_ops = {
.ndo_open = el16_open,
.ndo_stop = el16_close,
.ndo_start_xmit = el16_send_packet,
.ndo_tx_timeout = el16_tx_timeout,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
};
static int __init el16_probe1(struct net_device *dev, int ioaddr)
{
static unsigned char init_ID_done;
int i, irq, irqval, retval;
struct net_local *lp;
if (init_ID_done == 0) {
ushort lrs_state = 0xff;
/* Send the ID sequence to the ID_PORT to enable the board(s). */
outb(0x00, ID_PORT);
for(i = 0; i < 255; i++) {
outb(lrs_state, ID_PORT);
lrs_state <<= 1;
if (lrs_state & 0x100)
lrs_state ^= 0xe7;
}
outb(0x00, ID_PORT);
init_ID_done = 1;
}
if (!request_region(ioaddr, EL16_IO_EXTENT, DRV_NAME))
return -ENODEV;
if ((inb(ioaddr) != '*') || (inb(ioaddr + 1) != '3') ||
(inb(ioaddr + 2) != 'C') || (inb(ioaddr + 3) != 'O')) {
retval = -ENODEV;
goto out;
}
pr_info("%s: 3c507 at %#x,", dev->name, ioaddr);
/* We should make a few more checks here, like the first three octets of
the S.A. for the manufacturer's code. */
irq = inb(ioaddr + IRQ_CONFIG) & 0x0f;
irqval = request_irq(irq, el16_interrupt, 0, DRV_NAME, dev);
if (irqval) {
pr_cont("\n");
pr_err("3c507: unable to get IRQ %d (irqval=%d).\n", irq, irqval);
retval = -EAGAIN;
goto out;
}
/* We've committed to using the board, and can start filling in *dev. */
dev->base_addr = ioaddr;
outb(0x01, ioaddr + MISC_CTRL);
for (i = 0; i < 6; i++)
dev->dev_addr[i] = inb(ioaddr + i);
pr_cont(" %pM", dev->dev_addr);
if (mem_start)
net_debug = mem_start & 7;
#ifdef MEM_BASE
dev->mem_start = MEM_BASE;
dev->mem_end = dev->mem_start + 0x10000;
#else
{
int base;
int size;
char mem_config = inb(ioaddr + MEM_CONFIG);
if (mem_config & 0x20) {
size = 64*1024;
base = 0xf00000 + (mem_config & 0x08 ? 0x080000
: ((mem_config & 3) << 17));
} else {
size = ((mem_config & 3) + 1) << 14;
base = 0x0c0000 + ( (mem_config & 0x18) << 12);
}
dev->mem_start = base;
dev->mem_end = base + size;
}
#endif
dev->if_port = (inb(ioaddr + ROM_CONFIG) & 0x80) ? 1 : 0;
dev->irq = inb(ioaddr + IRQ_CONFIG) & 0x0f;
pr_cont(", IRQ %d, %sternal xcvr, memory %#lx-%#lx.\n", dev->irq,
dev->if_port ? "ex" : "in", dev->mem_start, dev->mem_end-1);
if (net_debug)
pr_debug("%s", version);
lp = netdev_priv(dev);
spin_lock_init(&lp->lock);
lp->base = ioremap(dev->mem_start, RX_BUF_END);
if (!lp->base) {
pr_err("3c507: unable to remap memory\n");
retval = -EAGAIN;
goto out1;
}
dev->netdev_ops = &netdev_ops;
dev->watchdog_timeo = TX_TIMEOUT;
dev->ethtool_ops = &netdev_ethtool_ops;
dev->flags &= ~IFF_MULTICAST; /* Multicast doesn't work */
return 0;
out1:
free_irq(dev->irq, dev);
out:
release_region(ioaddr, EL16_IO_EXTENT);
return retval;
}
static int el16_open(struct net_device *dev)
{
/* Initialize the 82586 memory and start it. */
init_82586_mem(dev);
netif_start_queue(dev);
return 0;
}
static void el16_tx_timeout (struct net_device *dev)
{
struct net_local *lp = netdev_priv(dev);
int ioaddr = dev->base_addr;
void __iomem *shmem = lp->base;
if (net_debug > 1)
pr_debug("%s: transmit timed out, %s? ", dev->name,
readw(shmem + iSCB_STATUS) & 0x8000 ? "IRQ conflict" :
"network cable problem");
/* Try to restart the adaptor. */
if (lp->last_restart == dev->stats.tx_packets) {
if (net_debug > 1)
pr_cont("Resetting board.\n");
/* Completely reset the adaptor. */
init_82586_mem (dev);
lp->tx_pkts_in_ring = 0;
} else {
/* Issue the channel attention signal and hope it "gets better". */
if (net_debug > 1)
pr_cont("Kicking board.\n");
writew(0xf000 | CUC_START | RX_START, shmem + iSCB_CMD);
outb (0, ioaddr + SIGNAL_CA); /* Issue channel-attn. */
lp->last_restart = dev->stats.tx_packets;
}
dev->trans_start = jiffies; /* prevent tx timeout */
netif_wake_queue (dev);
}
static netdev_tx_t el16_send_packet (struct sk_buff *skb,
struct net_device *dev)
{
struct net_local *lp = netdev_priv(dev);
int ioaddr = dev->base_addr;
unsigned long flags;
short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
unsigned char *buf = skb->data;
netif_stop_queue (dev);
spin_lock_irqsave (&lp->lock, flags);
dev->stats.tx_bytes += length;
/* Disable the 82586's input to the interrupt line. */
outb (0x80, ioaddr + MISC_CTRL);
hardware_send_packet (dev, buf, skb->len, length - skb->len);
/* Enable the 82586 interrupt input. */
outb (0x84, ioaddr + MISC_CTRL);
spin_unlock_irqrestore (&lp->lock, flags);
dev_kfree_skb (skb);
/* You might need to clean up and record Tx statistics here. */
return NETDEV_TX_OK;
}
/* The typical workload of the driver:
Handle the network interface interrupts. */
static irqreturn_t el16_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct net_local *lp;
int ioaddr, status, boguscount = 0;
ushort ack_cmd = 0;
void __iomem *shmem;
if (dev == NULL) {
pr_err("net_interrupt(): irq %d for unknown device.\n", irq);
return IRQ_NONE;
}
ioaddr = dev->base_addr;
lp = netdev_priv(dev);
shmem = lp->base;
spin_lock(&lp->lock);
status = readw(shmem+iSCB_STATUS);
if (net_debug > 4) {
pr_debug("%s: 3c507 interrupt, status %4.4x.\n", dev->name, status);
}
/* Disable the 82586's input to the interrupt line. */
outb(0x80, ioaddr + MISC_CTRL);
/* Reap the Tx packet buffers. */
while (lp->tx_pkts_in_ring) {
unsigned short tx_status = readw(shmem+lp->tx_reap);
if (!(tx_status & 0x8000)) {
if (net_debug > 5)
pr_debug("Tx command incomplete (%#x).\n", lp->tx_reap);
break;
}
/* Tx unsuccessful or some interesting status bit set. */
if (!(tx_status & 0x2000) || (tx_status & 0x0f3f)) {
dev->stats.tx_errors++;
if (tx_status & 0x0600) dev->stats.tx_carrier_errors++;
if (tx_status & 0x0100) dev->stats.tx_fifo_errors++;
if (!(tx_status & 0x0040)) dev->stats.tx_heartbeat_errors++;
if (tx_status & 0x0020) dev->stats.tx_aborted_errors++;
dev->stats.collisions += tx_status & 0xf;
}
dev->stats.tx_packets++;
if (net_debug > 5)
pr_debug("Reaped %x, Tx status %04x.\n" , lp->tx_reap, tx_status);
lp->tx_reap += TX_BUF_SIZE;
if (lp->tx_reap > RX_BUF_START - TX_BUF_SIZE)
lp->tx_reap = TX_BUF_START;
lp->tx_pkts_in_ring--;
/* There is always more space in the Tx ring buffer now. */
netif_wake_queue(dev);
if (++boguscount > 10)
break;
}
if (status & 0x4000) { /* Packet received. */
if (net_debug > 5)
pr_debug("Received packet, rx_head %04x.\n", lp->rx_head);
el16_rx(dev);
}
/* Acknowledge the interrupt sources. */
ack_cmd = status & 0xf000;
if ((status & 0x0700) != 0x0200 && netif_running(dev)) {
if (net_debug)
pr_debug("%s: Command unit stopped, status %04x, restarting.\n",
dev->name, status);
/* If this ever occurs we should really re-write the idle loop, reset
the Tx list, and do a complete restart of the command unit.
For now we rely on the Tx timeout if the resume doesn't work. */
ack_cmd |= CUC_RESUME;
}
if ((status & 0x0070) != 0x0040 && netif_running(dev)) {
/* The Rx unit is not ready, it must be hung. Restart the receiver by
initializing the rx buffers, and issuing an Rx start command. */
if (net_debug)
pr_debug("%s: Rx unit stopped, status %04x, restarting.\n",
dev->name, status);
init_rx_bufs(dev);
writew(RX_BUF_START,shmem+iSCB_RFA);
ack_cmd |= RX_START;
}
writew(ack_cmd,shmem+iSCB_CMD);
outb(0, ioaddr + SIGNAL_CA); /* Issue channel-attn. */
/* Clear the latched interrupt. */
outb(0, ioaddr + RESET_IRQ);
/* Enable the 82586's interrupt input. */
outb(0x84, ioaddr + MISC_CTRL);
spin_unlock(&lp->lock);
return IRQ_HANDLED;
}
static int el16_close(struct net_device *dev)
{
struct net_local *lp = netdev_priv(dev);
int ioaddr = dev->base_addr;
void __iomem *shmem = lp->base;
netif_stop_queue(dev);
/* Flush the Tx and disable Rx. */
writew(RX_SUSPEND | CUC_SUSPEND,shmem+iSCB_CMD);
outb(0, ioaddr + SIGNAL_CA);
/* Disable the 82586's input to the interrupt line. */
outb(0x80, ioaddr + MISC_CTRL);
/* We always physically use the IRQ line, so we don't do free_irq(). */
/* Update the statistics here. */
return 0;
}
/* Initialize the Rx-block list. */
static void init_rx_bufs(struct net_device *dev)
{
struct net_local *lp = netdev_priv(dev);
void __iomem *write_ptr;
unsigned short SCB_base = SCB_BASE;
int cur_rxbuf = lp->rx_head = RX_BUF_START;
/* Initialize each Rx frame + data buffer. */
do { /* While there is room for one more. */
write_ptr = lp->base + cur_rxbuf;
writew(0x0000,write_ptr); /* Status */
writew(0x0000,write_ptr+=2); /* Command */
writew(cur_rxbuf + RX_BUF_SIZE,write_ptr+=2); /* Link */
writew(cur_rxbuf + 22,write_ptr+=2); /* Buffer offset */
writew(0x0000,write_ptr+=2); /* Pad for dest addr. */
writew(0x0000,write_ptr+=2);
writew(0x0000,write_ptr+=2);
writew(0x0000,write_ptr+=2); /* Pad for source addr. */
writew(0x0000,write_ptr+=2);
writew(0x0000,write_ptr+=2);
writew(0x0000,write_ptr+=2); /* Pad for protocol. */
writew(0x0000,write_ptr+=2); /* Buffer: Actual count */
writew(-1,write_ptr+=2); /* Buffer: Next (none). */
writew(cur_rxbuf + 0x20 + SCB_base,write_ptr+=2);/* Buffer: Address low */
writew(0x0000,write_ptr+=2);
/* Finally, the number of bytes in the buffer. */
writew(0x8000 + RX_BUF_SIZE-0x20,write_ptr+=2);
lp->rx_tail = cur_rxbuf;
cur_rxbuf += RX_BUF_SIZE;
} while (cur_rxbuf <= RX_BUF_END - RX_BUF_SIZE);
/* Terminate the list by setting the EOL bit, and wrap the pointer to make
the list a ring. */
write_ptr = lp->base + lp->rx_tail + 2;
writew(0xC000,write_ptr); /* Command, mark as last. */
writew(lp->rx_head,write_ptr+2); /* Link */
}
static void init_82586_mem(struct net_device *dev)
{
struct net_local *lp = netdev_priv(dev);
short ioaddr = dev->base_addr;
void __iomem *shmem = lp->base;
/* Enable loopback to protect the wire while starting up,
and hold the 586 in reset during the memory initialization. */
outb(0x20, ioaddr + MISC_CTRL);
/* Fix the ISCP address and base. */
init_words[3] = SCB_BASE;
init_words[7] = SCB_BASE;
/* Write the words at 0xfff6 (address-aliased to 0xfffff6). */
memcpy_toio(lp->base + RX_BUF_END - 10, init_words, 10);
/* Write the words at 0x0000. */
memcpy_toio(lp->base, init_words + 5, sizeof(init_words) - 10);
/* Fill in the station address. */
memcpy_toio(lp->base+SA_OFFSET, dev->dev_addr, ETH_ALEN);
/* The Tx-block list is written as needed. We just set up the values. */
lp->tx_cmd_link = IDLELOOP + 4;
lp->tx_head = lp->tx_reap = TX_BUF_START;
init_rx_bufs(dev);
/* Start the 586 by releasing the reset line, but leave loopback. */
outb(0xA0, ioaddr + MISC_CTRL);
/* This was time consuming to track down: you need to give two channel
attention signals to reliably start up the i82586. */
outb(0, ioaddr + SIGNAL_CA);
{
int boguscnt = 50;
while (readw(shmem+iSCB_STATUS) == 0)
if (--boguscnt == 0) {
pr_warning("%s: i82586 initialization timed out with status %04x, cmd %04x.\n",
dev->name, readw(shmem+iSCB_STATUS), readw(shmem+iSCB_CMD));
break;
}
/* Issue channel-attn -- the 82586 won't start. */
outb(0, ioaddr + SIGNAL_CA);
}
/* Disable loopback and enable interrupts. */
outb(0x84, ioaddr + MISC_CTRL);
if (net_debug > 4)
pr_debug("%s: Initialized 82586, status %04x.\n", dev->name,
readw(shmem+iSCB_STATUS));
}
static void hardware_send_packet(struct net_device *dev, void *buf, short length, short pad)
{
struct net_local *lp = netdev_priv(dev);
short ioaddr = dev->base_addr;
ushort tx_block = lp->tx_head;
void __iomem *write_ptr = lp->base + tx_block;
static char padding[ETH_ZLEN];
/* Set the write pointer to the Tx block, and put out the header. */
writew(0x0000,write_ptr); /* Tx status */
writew(CMD_INTR|CmdTx,write_ptr+=2); /* Tx command */
writew(tx_block+16,write_ptr+=2); /* Next command is a NoOp. */
writew(tx_block+8,write_ptr+=2); /* Data Buffer offset. */
/* Output the data buffer descriptor. */
writew((pad + length) | 0x8000,write_ptr+=2); /* Byte count parameter. */
writew(-1,write_ptr+=2); /* No next data buffer. */
writew(tx_block+22+SCB_BASE,write_ptr+=2); /* Buffer follows the NoOp command. */
writew(0x0000,write_ptr+=2); /* Buffer address high bits (always zero). */
/* Output the Loop-back NoOp command. */
writew(0x0000,write_ptr+=2); /* Tx status */
writew(CmdNOp,write_ptr+=2); /* Tx command */
writew(tx_block+16,write_ptr+=2); /* Next is myself. */
/* Output the packet at the write pointer. */
memcpy_toio(write_ptr+2, buf, length);
if (pad)
memcpy_toio(write_ptr+length+2, padding, pad);
/* Set the old command link pointing to this send packet. */
writew(tx_block,lp->base + lp->tx_cmd_link);
lp->tx_cmd_link = tx_block + 20;
/* Set the next free tx region. */
lp->tx_head = tx_block + TX_BUF_SIZE;
if (lp->tx_head > RX_BUF_START - TX_BUF_SIZE)
lp->tx_head = TX_BUF_START;
if (net_debug > 4) {
pr_debug("%s: 3c507 @%x send length = %d, tx_block %3x, next %3x.\n",
dev->name, ioaddr, length, tx_block, lp->tx_head);
}
/* Grimly block further packets if there has been insufficient reaping. */
if (++lp->tx_pkts_in_ring < NUM_TX_BUFS)
netif_wake_queue(dev);
}
static void el16_rx(struct net_device *dev)
{
struct net_local *lp = netdev_priv(dev);
void __iomem *shmem = lp->base;
ushort rx_head = lp->rx_head;
ushort rx_tail = lp->rx_tail;
ushort boguscount = 10;
short frame_status;
while ((frame_status = readw(shmem+rx_head)) < 0) { /* Command complete */
void __iomem *read_frame = lp->base + rx_head;
ushort rfd_cmd = readw(read_frame+2);
ushort next_rx_frame = readw(read_frame+4);
ushort data_buffer_addr = readw(read_frame+6);
void __iomem *data_frame = lp->base + data_buffer_addr;
ushort pkt_len = readw(data_frame);
if (rfd_cmd != 0 || data_buffer_addr != rx_head + 22 ||
(pkt_len & 0xC000) != 0xC000) {
pr_err("%s: Rx frame at %#x corrupted, "
"status %04x cmd %04x next %04x "
"data-buf @%04x %04x.\n",
dev->name, rx_head, frame_status, rfd_cmd,
next_rx_frame, data_buffer_addr, pkt_len);
} else if ((frame_status & 0x2000) == 0) {
/* Frame Rxed, but with error. */
dev->stats.rx_errors++;
if (frame_status & 0x0800) dev->stats.rx_crc_errors++;
if (frame_status & 0x0400) dev->stats.rx_frame_errors++;
if (frame_status & 0x0200) dev->stats.rx_fifo_errors++;
if (frame_status & 0x0100) dev->stats.rx_over_errors++;
if (frame_status & 0x0080) dev->stats.rx_length_errors++;
} else {
/* Malloc up new buffer. */
struct sk_buff *skb;
pkt_len &= 0x3fff;
skb = dev_alloc_skb(pkt_len+2);
if (skb == NULL) {
pr_err("%s: Memory squeeze, dropping packet.\n",
dev->name);
dev->stats.rx_dropped++;
break;
}
skb_reserve(skb,2);
/* 'skb->data' points to the start of sk_buff data area. */
memcpy_fromio(skb_put(skb,pkt_len), data_frame + 10, pkt_len);
skb->protocol=eth_type_trans(skb,dev);
netif_rx(skb);
dev->stats.rx_packets++;
dev->stats.rx_bytes += pkt_len;
}
/* Clear the status word and set End-of-List on the rx frame. */
writew(0,read_frame);
writew(0xC000,read_frame+2);
/* Clear the end-of-list on the prev. RFD. */
writew(0x0000,lp->base + rx_tail + 2);
rx_tail = rx_head;
rx_head = next_rx_frame;
if (--boguscount == 0)
break;
}
lp->rx_head = rx_head;
lp->rx_tail = rx_tail;
}
static void netdev_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
strcpy(info->driver, DRV_NAME);
strcpy(info->version, DRV_VERSION);
sprintf(info->bus_info, "ISA 0x%lx", dev->base_addr);
}
static u32 netdev_get_msglevel(struct net_device *dev)
{
return debug;
}
static void netdev_set_msglevel(struct net_device *dev, u32 level)
{
debug = level;
}
static const struct ethtool_ops netdev_ethtool_ops = {
.get_drvinfo = netdev_get_drvinfo,
.get_msglevel = netdev_get_msglevel,
.set_msglevel = netdev_set_msglevel,
};
#ifdef MODULE
static struct net_device *dev_3c507;
module_param(io, int, 0);
module_param(irq, int, 0);
MODULE_PARM_DESC(io, "EtherLink16 I/O base address");
MODULE_PARM_DESC(irq, "(ignored)");
int __init init_module(void)
{
if (io == 0)
pr_notice("3c507: You should not use auto-probing with insmod!\n");
dev_3c507 = el16_probe(-1);
return IS_ERR(dev_3c507) ? PTR_ERR(dev_3c507) : 0;
}
void __exit
cleanup_module(void)
{
struct net_device *dev = dev_3c507;
unregister_netdev(dev);
free_irq(dev->irq, dev);
iounmap(((struct net_local *)netdev_priv(dev))->base);
release_region(dev->base_addr, EL16_IO_EXTENT);
free_netdev(dev);
}
#endif /* MODULE */
MODULE_LICENSE("GPL");

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,355 @@
#ifndef _3c523_INCLUDE_
#define _3c523_INCLUDE_
/*
This is basically a hacked version of ni52.h, for the 3c523
Etherlink/MC.
*/
/*
* Intel i82586 Ethernet definitions
*
* This is an extension to the Linux operating system, and is covered by the
* same GNU General Public License that covers that work.
*
* Copyright 1995 by Chris Beauregard (cpbeaure@undergrad.math.uwaterloo.ca)
*
* See 3c523.c for details.
*
* $Header: /home/chrisb/linux-1.2.13-3c523/drivers/net/RCS/3c523.h,v 1.6 1996/01/20 05:09:00 chrisb Exp chrisb $
*/
/*
* where to find the System Configuration Pointer (SCP)
*/
#define SCP_DEFAULT_ADDRESS 0xfffff4
/*
* System Configuration Pointer Struct
*/
struct scp_struct
{
unsigned short zero_dum0; /* has to be zero */
unsigned char sysbus; /* 0=16Bit,1=8Bit */
unsigned char zero_dum1; /* has to be zero for 586 */
unsigned short zero_dum2;
unsigned short zero_dum3;
char *iscp; /* pointer to the iscp-block */
};
/*
* Intermediate System Configuration Pointer (ISCP)
*/
struct iscp_struct
{
unsigned char busy; /* 586 clears after successful init */
unsigned char zero_dummy; /* hast to be zero */
unsigned short scb_offset; /* pointeroffset to the scb_base */
char *scb_base; /* base-address of all 16-bit offsets */
};
/*
* System Control Block (SCB)
*/
struct scb_struct
{
unsigned short status; /* status word */
unsigned short cmd; /* command word */
unsigned short cbl_offset; /* pointeroffset, command block list */
unsigned short rfa_offset; /* pointeroffset, receive frame area */
unsigned short crc_errs; /* CRC-Error counter */
unsigned short aln_errs; /* alignmenterror counter */
unsigned short rsc_errs; /* Resourceerror counter */
unsigned short ovrn_errs; /* OVerrunerror counter */
};
/*
* possible command values for the command word
*/
#define RUC_MASK 0x0070 /* mask for RU commands */
#define RUC_NOP 0x0000 /* NOP-command */
#define RUC_START 0x0010 /* start RU */
#define RUC_RESUME 0x0020 /* resume RU after suspend */
#define RUC_SUSPEND 0x0030 /* suspend RU */
#define RUC_ABORT 0x0040 /* abort receiver operation immediately */
#define CUC_MASK 0x0700 /* mask for CU command */
#define CUC_NOP 0x0000 /* NOP-command */
#define CUC_START 0x0100 /* start execution of 1. cmd on the CBL */
#define CUC_RESUME 0x0200 /* resume after suspend */
#define CUC_SUSPEND 0x0300 /* Suspend CU */
#define CUC_ABORT 0x0400 /* abort command operation immediately */
#define ACK_MASK 0xf000 /* mask for ACK command */
#define ACK_CX 0x8000 /* acknowledges STAT_CX */
#define ACK_FR 0x4000 /* ack. STAT_FR */
#define ACK_CNA 0x2000 /* ack. STAT_CNA */
#define ACK_RNR 0x1000 /* ack. STAT_RNR */
/*
* possible status values for the status word
*/
#define STAT_MASK 0xf000 /* mask for cause of interrupt */
#define STAT_CX 0x8000 /* CU finished cmd with its I bit set */
#define STAT_FR 0x4000 /* RU finished receiving a frame */
#define STAT_CNA 0x2000 /* CU left active state */
#define STAT_RNR 0x1000 /* RU left ready state */
#define CU_STATUS 0x700 /* CU status, 0=idle */
#define CU_SUSPEND 0x100 /* CU is suspended */
#define CU_ACTIVE 0x200 /* CU is active */
#define RU_STATUS 0x70 /* RU status, 0=idle */
#define RU_SUSPEND 0x10 /* RU suspended */
#define RU_NOSPACE 0x20 /* RU no resources */
#define RU_READY 0x40 /* RU is ready */
/*
* Receive Frame Descriptor (RFD)
*/
struct rfd_struct
{
unsigned short status; /* status word */
unsigned short last; /* Bit15,Last Frame on List / Bit14,suspend */
unsigned short next; /* linkoffset to next RFD */
unsigned short rbd_offset; /* pointeroffset to RBD-buffer */
unsigned char dest[6]; /* ethernet-address, destination */
unsigned char source[6]; /* ethernet-address, source */
unsigned short length; /* 802.3 frame-length */
unsigned short zero_dummy; /* dummy */
};
#define RFD_LAST 0x8000 /* last: last rfd in the list */
#define RFD_SUSP 0x4000 /* last: suspend RU after */
#define RFD_ERRMASK 0x0fe1 /* status: errormask */
#define RFD_MATCHADD 0x0002 /* status: Destinationaddress !matches IA */
#define RFD_RNR 0x0200 /* status: receiver out of resources */
/*
* Receive Buffer Descriptor (RBD)
*/
struct rbd_struct
{
unsigned short status; /* status word,number of used bytes in buff */
unsigned short next; /* pointeroffset to next RBD */
char *buffer; /* receive buffer address pointer */
unsigned short size; /* size of this buffer */
unsigned short zero_dummy; /* dummy */
};
#define RBD_LAST 0x8000 /* last buffer */
#define RBD_USED 0x4000 /* this buffer has data */
#define RBD_MASK 0x3fff /* size-mask for length */
/*
* Statusvalues for Commands/RFD
*/
#define STAT_COMPL 0x8000 /* status: frame/command is complete */
#define STAT_BUSY 0x4000 /* status: frame/command is busy */
#define STAT_OK 0x2000 /* status: frame/command is ok */
/*
* Action-Commands
*/
#define CMD_NOP 0x0000 /* NOP */
#define CMD_IASETUP 0x0001 /* initial address setup command */
#define CMD_CONFIGURE 0x0002 /* configure command */
#define CMD_MCSETUP 0x0003 /* MC setup command */
#define CMD_XMIT 0x0004 /* transmit command */
#define CMD_TDR 0x0005 /* time domain reflectometer (TDR) command */
#define CMD_DUMP 0x0006 /* dump command */
#define CMD_DIAGNOSE 0x0007 /* diagnose command */
/*
* Action command bits
*/
#define CMD_LAST 0x8000 /* indicates last command in the CBL */
#define CMD_SUSPEND 0x4000 /* suspend CU after this CB */
#define CMD_INT 0x2000 /* generate interrupt after execution */
/*
* NOP - command
*/
struct nop_cmd_struct
{
unsigned short cmd_status; /* status of this command */
unsigned short cmd_cmd; /* the command itself (+bits) */
unsigned short cmd_link; /* offsetpointer to next command */
};
/*
* IA Setup command
*/
struct iasetup_cmd_struct
{
unsigned short cmd_status;
unsigned short cmd_cmd;
unsigned short cmd_link;
unsigned char iaddr[6];
};
/*
* Configure command
*/
struct configure_cmd_struct
{
unsigned short cmd_status;
unsigned short cmd_cmd;
unsigned short cmd_link;
unsigned char byte_cnt; /* size of the config-cmd */
unsigned char fifo; /* fifo/recv monitor */
unsigned char sav_bf; /* save bad frames (bit7=1)*/
unsigned char adr_len; /* adr_len(0-2),al_loc(3),pream(4-5),loopbak(6-7)*/
unsigned char priority; /* lin_prio(0-2),exp_prio(4-6),bof_metd(7) */
unsigned char ifs; /* inter frame spacing */
unsigned char time_low; /* slot time low */
unsigned char time_high; /* slot time high(0-2) and max. retries(4-7) */
unsigned char promisc; /* promisc-mode(0) , et al (1-7) */
unsigned char carr_coll; /* carrier(0-3)/collision(4-7) stuff */
unsigned char fram_len; /* minimal frame len */
unsigned char dummy; /* dummy */
};
/*
* Multicast Setup command
*/
struct mcsetup_cmd_struct
{
unsigned short cmd_status;
unsigned short cmd_cmd;
unsigned short cmd_link;
unsigned short mc_cnt; /* number of bytes in the MC-List */
unsigned char mc_list[0][6]; /* pointer to 6 bytes entries */
};
/*
* transmit command
*/
struct transmit_cmd_struct
{
unsigned short cmd_status;
unsigned short cmd_cmd;
unsigned short cmd_link;
unsigned short tbd_offset; /* pointeroffset to TBD */
unsigned char dest[6]; /* destination address of the frame */
unsigned short length; /* user defined: 802.3 length / Ether type */
};
#define TCMD_ERRMASK 0x0fa0
#define TCMD_MAXCOLLMASK 0x000f
#define TCMD_MAXCOLL 0x0020
#define TCMD_HEARTBEAT 0x0040
#define TCMD_DEFERRED 0x0080
#define TCMD_UNDERRUN 0x0100
#define TCMD_LOSTCTS 0x0200
#define TCMD_NOCARRIER 0x0400
#define TCMD_LATECOLL 0x0800
struct tdr_cmd_struct
{
unsigned short cmd_status;
unsigned short cmd_cmd;
unsigned short cmd_link;
unsigned short status;
};
#define TDR_LNK_OK 0x8000 /* No link problem identified */
#define TDR_XCVR_PRB 0x4000 /* indicates a transceiver problem */
#define TDR_ET_OPN 0x2000 /* open, no correct termination */
#define TDR_ET_SRT 0x1000 /* TDR detected a short circuit */
#define TDR_TIMEMASK 0x07ff /* mask for the time field */
/*
* Transmit Buffer Descriptor (TBD)
*/
struct tbd_struct
{
unsigned short size; /* size + EOF-Flag(15) */
unsigned short next; /* pointeroffset to next TBD */
char *buffer; /* pointer to buffer */
};
#define TBD_LAST 0x8000 /* EOF-Flag, indicates last buffer in list */
/*************************************************************************/
/*
Verbatim from the Crynwyr stuff:
The 3c523 responds with adapter code 0x6042 at slot
registers xxx0 and xxx1. The setup register is at xxx2 and
contains the following bits:
0: card enable
2,1: csr address select
00 = 0300
01 = 1300
10 = 2300
11 = 3300
4,3: shared memory address select
00 = 0c0000
01 = 0c8000
10 = 0d0000
11 = 0d8000
5: set to disable on-board thinnet
7,6: (read-only) shows selected irq
00 = 12
01 = 7
10 = 3
11 = 9
The interrupt-select register is at xxx3 and uses one bit per irq.
0: int 12
1: int 7
2: int 3
3: int 9
Again, the documentation stresses that the setup register
should never be written. The interrupt-select register may be
written with the value corresponding to bits 7.6 in
the setup register to insure corret setup.
*/
/* Offsets from the base I/O address. */
#define ELMC_SA 0 /* first 6 bytes are IEEE network address */
#define ELMC_CTRL 6 /* control & status register */
#define ELMC_REVISION 7 /* revision register, first 4 bits only */
#define ELMC_IO_EXTENT 8
/* these are the bit selects for the port register 2 */
#define ELMC_STATUS_ENABLED 0x01
#define ELMC_STATUS_CSR_SELECT 0x06
#define ELMC_STATUS_MEMORY_SELECT 0x18
#define ELMC_STATUS_DISABLE_THIN 0x20
#define ELMC_STATUS_IRQ_SELECT 0xc0
/* this is the card id used in the detection code. You might recognize
it from @6042.adf */
#define ELMC_MCA_ID 0x6042
/*
The following define the bits for the control & status register
The bank select registers can be used if more than 16K of memory is
on the card. For some stupid reason, bank 3 is the one for the
bottom 16K, and the card defaults to bank 0. So we have to set the
bank to 3 before the card will even think of operating. To get bank
3, set BS0 and BS1 to high (of course...)
*/
#define ELMC_CTRL_BS0 0x01 /* RW bank select */
#define ELMC_CTRL_BS1 0x02 /* RW bank select */
#define ELMC_CTRL_INTE 0x04 /* RW interrupt enable, assert high */
#define ELMC_CTRL_INT 0x08 /* R interrupt active, assert high */
/*#define ELMC_CTRL_* 0x10*/ /* reserved */
#define ELMC_CTRL_LBK 0x20 /* RW loopback enable, assert high */
#define ELMC_CTRL_CA 0x40 /* RW channel attention, assert high */
#define ELMC_CTRL_RST 0x80 /* RW 82586 reset, assert low */
/* some handy compound bits */
/* normal operation should have bank 3 and RST high, ints enabled */
#define ELMC_NORMAL (ELMC_CTRL_INTE|ELMC_CTRL_RST|0x3)
#endif /* _3c523_INCLUDE_ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,81 @@
/*
* 3COM "EtherLink MC/32" Descriptions
*/
/*
* Registers
*/
#define HOST_CMD 0
#define HOST_CMD_START_RX (1<<3)
#define HOST_CMD_SUSPND_RX (3<<3)
#define HOST_CMD_RESTRT_RX (5<<3)
#define HOST_CMD_SUSPND_TX 3
#define HOST_CMD_RESTRT_TX 5
#define HOST_STATUS 2
#define HOST_STATUS_CRR (1<<6)
#define HOST_STATUS_CWR (1<<5)
#define HOST_CTRL 6
#define HOST_CTRL_ATTN (1<<7)
#define HOST_CTRL_RESET (1<<6)
#define HOST_CTRL_INTE (1<<2)
#define HOST_RAMPAGE 8
#define HALTED 0
#define RUNNING 1
struct mc32_mailbox
{
u16 mbox;
u16 data[1];
} __packed;
struct skb_header
{
u8 status;
u8 control;
u16 next; /* Do not change! */
u16 length;
u32 data;
} __packed;
struct mc32_stats
{
/* RX Errors */
u32 rx_crc_errors;
u32 rx_alignment_errors;
u32 rx_overrun_errors;
u32 rx_tooshort_errors;
u32 rx_toolong_errors;
u32 rx_outofresource_errors;
u32 rx_discarded; /* via card pattern match filter */
/* TX Errors */
u32 tx_max_collisions;
u32 tx_carrier_errors;
u32 tx_underrun_errors;
u32 tx_cts_errors;
u32 tx_timeout_errors;
/* various cruft */
u32 dataA[6];
u16 dataB[5];
u32 dataC[14];
} __packed;
#define STATUS_MASK 0x0F
#define COMPLETED (1<<7)
#define COMPLETED_OK (1<<6)
#define BUFFER_BUSY (1<<5)
#define CONTROL_EOP (1<<7) /* End Of Packet */
#define CONTROL_EOL (1<<6) /* End of List */
#define MCA_MC32_ID 0x0041 /* Our MCA ident */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,182 @@
#
# Intel 82596/82593/82596 network device configuration
#
config NET_VENDOR_I825XX
bool "Intel (82586/82593/82596) devices"
depends on NET_VENDOR_INTEL && (ISA || ISA_DMA_API || ARM || \
ARCH_ACORN || MCA || MCA_LEGACY || SNI_RM || SUN3 || \
GSC || BVME6000 || MVME16x || EXPERIMENTAL)
---help---
If you have a network (Ethernet) card belonging to this class, say Y
and read the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
Note that the answer to this question does not directly affect the
kernel: saying N will just cause the configurator to skip all
the questions about these devices. If you say Y, you will be asked for
your specific card in the following questions.
if NET_VENDOR_I825XX
config ELPLUS
tristate "3c505 \"EtherLink Plus\" support"
depends on ISA && ISA_DMA_API
---help---
Information about this network (Ethernet) card can be found in
<file:Documentation/networking/3c505.txt>. If you have a card of
this type, say Y and read the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
To compile this driver as a module, choose M here. The module
will be called 3c505.
config EL16
tristate "3c507 \"EtherLink 16\" support (EXPERIMENTAL)"
depends on ISA && EXPERIMENTAL
---help---
If you have a network (Ethernet) card of this type, say Y and read
the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
To compile this driver as a module, choose M here. The module
will be called 3c507.
config ELMC
tristate "3c523 \"EtherLink/MC\" support"
depends on MCA_LEGACY
---help---
If you have a network (Ethernet) card of this type, say Y and read
the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
To compile this driver as a module, choose M here. The module
will be called 3c523.
config ELMC_II
tristate "3c527 \"EtherLink/MC 32\" support (EXPERIMENTAL)"
depends on MCA && MCA_LEGACY
---help---
If you have a network (Ethernet) card of this type, say Y and read
the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
To compile this driver as a module, choose M here. The module
will be called 3c527.
config ARM_ETHER1
tristate "Acorn Ether1 support"
depends on ARM && ARCH_ACORN
---help---
If you have an Acorn system with one of these (AKA25) network cards,
you should say Y to this option if you wish to use it with Linux.
config APRICOT
tristate "Apricot Xen-II on board Ethernet"
depends on ISA
---help---
If you have a network (Ethernet) controller of this type, say Y and
read the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
To compile this driver as a module, choose M here. The module
will be called apricot.
config BVME6000_NET
tristate "BVME6000 Ethernet support"
depends on BVME6000MVME16x
---help---
This is the driver for the Ethernet interface on BVME4000 and
BVME6000 VME boards. Say Y here to include the driver for this chip
in your kernel.
To compile this driver as a module, choose M here.
config EEXPRESS
tristate "EtherExpress 16 support"
depends on ISA
---help---
If you have an EtherExpress16 network (Ethernet) card, say Y and
read the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>. Note that the Intel
EtherExpress16 card used to be regarded as a very poor choice
because the driver was very unreliable. We now have a new driver
that should do better.
To compile this driver as a module, choose M here. The module
will be called eexpress.
config EEXPRESS_PRO
tristate "EtherExpressPro support/EtherExpress 10 (i82595) support"
depends on ISA
---help---
If you have a network (Ethernet) card of this type, say Y. This
driver supports Intel i82595{FX,TX} based boards. Note however
that the EtherExpress PRO/100 Ethernet card has its own separate
driver. Please read the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
To compile this driver as a module, choose M here. The module
will be called eepro.
config LASI_82596
tristate "Lasi ethernet"
depends on GSC
---help---
Say Y here to support the builtin Intel 82596 ethernet controller
found in Hewlett-Packard PA-RISC machines with 10Mbit ethernet.
config LP486E
tristate "LP486E on board Ethernet"
depends on ISA
---help---
Say Y here to support the 82596-based on-board Ethernet controller
for the Panther motherboard, which is one of the two shipped in the
Intel Professional Workstation.
config MVME16x_NET
tristate "MVME16x Ethernet support"
depends on MVME16x
---help---
This is the driver for the Ethernet interface on the Motorola
MVME162, 166, 167, 172 and 177 boards. Say Y here to include the
driver for this chip in your kernel.
To compile this driver as a module, choose M here.
config NI52
tristate "NI5210 support"
depends on ISA
---help---
If you have a network (Ethernet) card of this type, say Y and read
the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
To compile this driver as a module, choose M here. The module
will be called ni52.
config SNI_82596
tristate "SNI RM ethernet"
depends on SNI_RM
---help---
Say Y here to support the on-board Intel 82596 ethernet controller
built into SNI RM machines.
config SUN3_82586
bool "Sun3 on-board Intel 82586 support"
depends on SUN3
---help---
This driver enables support for the on-board Intel 82586 based
Ethernet adapter found on Sun 3/1xx and 3/2xx motherboards. Note
that this driver does not support 82586-based adapters on additional
VME boards.
config ZNET
tristate "Zenith Z-Note support (EXPERIMENTAL)"
depends on EXPERIMENTAL && ISA_DMA_API
---help---
The Zenith Z-Note notebook computer has a built-in network
(Ethernet) card, and this is the Linux driver for it. Note that the
IBM Thinkpad 300 is compatible with the Z-Note and is also supported
by this driver. Read the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
endif # NET_VENDOR_I825XX

View File

@@ -0,0 +1,20 @@
#
# Makefile for the Intel 82586/82593/82596 chipset device drivers.
#
obj-$(CONFIG_ARM_ETHER1) += ether1.o
obj-$(CONFIG_EEXPRESS) += eexpress.o
obj-$(CONFIG_EEXPRESS_PRO) += eepro.o
obj-$(CONFIG_ELPLUS) += 3c505.o
obj-$(CONFIG_EL16) += 3c507.o
obj-$(CONFIG_ELMC) += 3c523.o
obj-$(CONFIG_ELMC_II) += 3c527.o
obj-$(CONFIG_LP486E) += lp486e.o
obj-$(CONFIG_NI52) += ni52.o
obj-$(CONFIG_SUN3_82586) += sun3_82586.o
obj-$(CONFIG_ZNET) += znet.o
obj-$(CONFIG_APRICOT) += 82596.o
obj-$(CONFIG_LASI_82596) += lasi_82596.o
obj-$(CONFIG_SNI_82596) += sni_82596.o
obj-$(CONFIG_MVME16x_NET) += 82596.o
obj-$(CONFIG_BVME6000_NET) += 82596.o

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,179 @@
/*
* eexpress.h: Intel EtherExpress16 defines
*/
/*
* EtherExpress card register addresses
* as offsets from the base IO region (dev->base_addr)
*/
#define DATAPORT 0x0000
#define WRITE_PTR 0x0002
#define READ_PTR 0x0004
#define SIGNAL_CA 0x0006
#define SET_IRQ 0x0007
#define SM_PTR 0x0008
#define MEM_Dec 0x000a
#define MEM_Ctrl 0x000b
#define MEM_Page_Ctrl 0x000c
#define Config 0x000d
#define EEPROM_Ctrl 0x000e
#define ID_PORT 0x000f
#define MEM_ECtrl 0x000f
/*
* card register defines
*/
/* SET_IRQ */
#define SIRQ_en 0x08
#define SIRQ_dis 0x00
/* EEPROM_Ctrl */
#define EC_Clk 0x01
#define EC_CS 0x02
#define EC_Wr 0x04
#define EC_Rd 0x08
#define ASIC_RST 0x40
#define i586_RST 0x80
#define eeprom_delay() { udelay(40); }
/*
* i82586 Memory Configuration
*/
/* (System Configuration Pointer) System start up block, read after 586_RST */
#define SCP_START 0xfff6
/* Intermediate System Configuration Pointer */
#define ISCP_START 0x0000
/* System Command Block */
#define SCB_START 0x0008
/* Start of buffer region. Everything before this is used for control
* structures and the CU configuration program. The memory layout is
* determined in eexp_hw_probe(), once we know how much memory is
* available on the card.
*/
#define TX_BUF_START 0x0100
#define TX_BUF_SIZE ((24+ETH_FRAME_LEN+31)&~0x1f)
#define RX_BUF_SIZE ((32+ETH_FRAME_LEN+31)&~0x1f)
/*
* SCB defines
*/
/* these functions take the SCB status word and test the relevant status bit */
#define SCB_complete(s) (((s) & 0x8000) != 0)
#define SCB_rxdframe(s) (((s) & 0x4000) != 0)
#define SCB_CUdead(s) (((s) & 0x2000) != 0)
#define SCB_RUdead(s) (((s) & 0x1000) != 0)
#define SCB_ack(s) ((s) & 0xf000)
/* Command unit status: 0=idle, 1=suspended, 2=active */
#define SCB_CUstat(s) (((s)&0x0300)>>8)
/* Receive unit status: 0=idle, 1=suspended, 2=out of resources, 4=ready */
#define SCB_RUstat(s) (((s)&0x0070)>>4)
/* SCB commands */
#define SCB_CUnop 0x0000
#define SCB_CUstart 0x0100
#define SCB_CUresume 0x0200
#define SCB_CUsuspend 0x0300
#define SCB_CUabort 0x0400
#define SCB_resetchip 0x0080
#define SCB_RUnop 0x0000
#define SCB_RUstart 0x0010
#define SCB_RUresume 0x0020
#define SCB_RUsuspend 0x0030
#define SCB_RUabort 0x0040
/*
* Command block defines
*/
#define Stat_Done(s) (((s) & 0x8000) != 0)
#define Stat_Busy(s) (((s) & 0x4000) != 0)
#define Stat_OK(s) (((s) & 0x2000) != 0)
#define Stat_Abort(s) (((s) & 0x1000) != 0)
#define Stat_STFail (((s) & 0x0800) != 0)
#define Stat_TNoCar(s) (((s) & 0x0400) != 0)
#define Stat_TNoCTS(s) (((s) & 0x0200) != 0)
#define Stat_TNoDMA(s) (((s) & 0x0100) != 0)
#define Stat_TDefer(s) (((s) & 0x0080) != 0)
#define Stat_TColl(s) (((s) & 0x0040) != 0)
#define Stat_TXColl(s) (((s) & 0x0020) != 0)
#define Stat_NoColl(s) ((s) & 0x000f)
/* Cmd_END will end AFTER the command if this is the first
* command block after an SCB_CUstart, but BEFORE the command
* for all subsequent commands. Best strategy is to place
* Cmd_INT on the last command in the sequence, followed by a
* dummy Cmd_Nop with Cmd_END after this.
*/
#define Cmd_END 0x8000
#define Cmd_SUS 0x4000
#define Cmd_INT 0x2000
#define Cmd_Nop 0x0000
#define Cmd_SetAddr 0x0001
#define Cmd_Config 0x0002
#define Cmd_MCast 0x0003
#define Cmd_Xmit 0x0004
#define Cmd_TDR 0x0005
#define Cmd_Dump 0x0006
#define Cmd_Diag 0x0007
/*
* Frame Descriptor (Receive block) defines
*/
#define FD_Done(s) (((s) & 0x8000) != 0)
#define FD_Busy(s) (((s) & 0x4000) != 0)
#define FD_OK(s) (((s) & 0x2000) != 0)
#define FD_CRC(s) (((s) & 0x0800) != 0)
#define FD_Align(s) (((s) & 0x0400) != 0)
#define FD_Resrc(s) (((s) & 0x0200) != 0)
#define FD_DMA(s) (((s) & 0x0100) != 0)
#define FD_Short(s) (((s) & 0x0080) != 0)
#define FD_NoEOF(s) (((s) & 0x0040) != 0)
struct rfd_header {
volatile unsigned long flags;
volatile unsigned short link;
volatile unsigned short rbd_offset;
volatile unsigned short dstaddr1;
volatile unsigned short dstaddr2;
volatile unsigned short dstaddr3;
volatile unsigned short srcaddr1;
volatile unsigned short srcaddr2;
volatile unsigned short srcaddr3;
volatile unsigned short length;
/* This is actually a Receive Buffer Descriptor. The way we
* arrange memory means that an RBD always follows the RFD that
* points to it, so they might as well be in the same structure.
*/
volatile unsigned short actual_count;
volatile unsigned short next_rbd;
volatile unsigned short buf_addr1;
volatile unsigned short buf_addr2;
volatile unsigned short size;
};
/* Returned data from the Time Domain Reflectometer */
#define TDR_LINKOK (1<<15)
#define TDR_XCVRPROBLEM (1<<14)
#define TDR_OPEN (1<<13)
#define TDR_SHORT (1<<12)
#define TDR_TIME 0x7ff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,280 @@
/*
* linux/drivers/acorn/net/ether1.h
*
* Copyright (C) 1996 Russell King
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Network driver for Acorn Ether1 cards.
*/
#ifndef _LINUX_ether1_H
#define _LINUX_ether1_H
#ifdef __ETHER1_C
/* use 0 for production, 1 for verification, >2 for debug */
#ifndef NET_DEBUG
#define NET_DEBUG 0
#endif
#define priv(dev) ((struct ether1_priv *)netdev_priv(dev))
/* Page register */
#define REG_PAGE (priv(dev)->base + 0x0000)
/* Control register */
#define REG_CONTROL (priv(dev)->base + 0x0004)
#define CTRL_RST 0x01
#define CTRL_LOOPBACK 0x02
#define CTRL_CA 0x04
#define CTRL_ACK 0x08
#define ETHER1_RAM (priv(dev)->base + 0x2000)
/* HW address */
#define IDPROM_ADDRESS (priv(dev)->base + 0x0024)
struct ether1_priv {
void __iomem *base;
unsigned int tx_link;
unsigned int tx_head;
volatile unsigned int tx_tail;
volatile unsigned int rx_head;
volatile unsigned int rx_tail;
unsigned char bus_type;
unsigned char resetting;
unsigned char initialising : 1;
unsigned char restart : 1;
};
#define I82586_NULL (-1)
typedef struct { /* tdr */
unsigned short tdr_status;
unsigned short tdr_command;
unsigned short tdr_link;
unsigned short tdr_result;
#define TDR_TIME (0x7ff)
#define TDR_SHORT (1 << 12)
#define TDR_OPEN (1 << 13)
#define TDR_XCVRPROB (1 << 14)
#define TDR_LNKOK (1 << 15)
} tdr_t;
typedef struct { /* transmit */
unsigned short tx_status;
unsigned short tx_command;
unsigned short tx_link;
unsigned short tx_tbdoffset;
} tx_t;
typedef struct { /* tbd */
unsigned short tbd_opts;
#define TBD_CNT (0x3fff)
#define TBD_EOL (1 << 15)
unsigned short tbd_link;
unsigned short tbd_bufl;
unsigned short tbd_bufh;
} tbd_t;
typedef struct { /* rfd */
unsigned short rfd_status;
#define RFD_NOEOF (1 << 6)
#define RFD_FRAMESHORT (1 << 7)
#define RFD_DMAOVRN (1 << 8)
#define RFD_NORESOURCES (1 << 9)
#define RFD_ALIGNERROR (1 << 10)
#define RFD_CRCERROR (1 << 11)
#define RFD_OK (1 << 13)
#define RFD_FDCONSUMED (1 << 14)
#define RFD_COMPLETE (1 << 15)
unsigned short rfd_command;
#define RFD_CMDSUSPEND (1 << 14)
#define RFD_CMDEL (1 << 15)
unsigned short rfd_link;
unsigned short rfd_rbdoffset;
unsigned char rfd_dest[6];
unsigned char rfd_src[6];
unsigned short rfd_len;
} rfd_t;
typedef struct { /* rbd */
unsigned short rbd_status;
#define RBD_ACNT (0x3fff)
#define RBD_ACNTVALID (1 << 14)
#define RBD_EOF (1 << 15)
unsigned short rbd_link;
unsigned short rbd_bufl;
unsigned short rbd_bufh;
unsigned short rbd_len;
} rbd_t;
typedef struct { /* nop */
unsigned short nop_status;
unsigned short nop_command;
unsigned short nop_link;
} nop_t;
typedef struct { /* set multicast */
unsigned short mc_status;
unsigned short mc_command;
unsigned short mc_link;
unsigned short mc_cnt;
unsigned char mc_addrs[1][6];
} mc_t;
typedef struct { /* set address */
unsigned short sa_status;
unsigned short sa_command;
unsigned short sa_link;
unsigned char sa_addr[6];
} sa_t;
typedef struct { /* config command */
unsigned short cfg_status;
unsigned short cfg_command;
unsigned short cfg_link;
unsigned char cfg_bytecnt; /* size foll data: 4 - 12 */
unsigned char cfg_fifolim; /* FIFO threshold */
unsigned char cfg_byte8;
#define CFG8_SRDY (1 << 6)
#define CFG8_SAVEBADF (1 << 7)
unsigned char cfg_byte9;
#define CFG9_ADDRLEN(x) (x)
#define CFG9_ADDRLENBUF (1 << 3)
#define CFG9_PREAMB2 (0 << 4)
#define CFG9_PREAMB4 (1 << 4)
#define CFG9_PREAMB8 (2 << 4)
#define CFG9_PREAMB16 (3 << 4)
#define CFG9_ILOOPBACK (1 << 6)
#define CFG9_ELOOPBACK (1 << 7)
unsigned char cfg_byte10;
#define CFG10_LINPRI(x) (x)
#define CFG10_ACR(x) (x << 4)
#define CFG10_BOFMET (1 << 7)
unsigned char cfg_ifs;
unsigned char cfg_slotl;
unsigned char cfg_byte13;
#define CFG13_SLOTH(x) (x)
#define CFG13_RETRY(x) (x << 4)
unsigned char cfg_byte14;
#define CFG14_PROMISC (1 << 0)
#define CFG14_DISBRD (1 << 1)
#define CFG14_MANCH (1 << 2)
#define CFG14_TNCRS (1 << 3)
#define CFG14_NOCRC (1 << 4)
#define CFG14_CRC16 (1 << 5)
#define CFG14_BTSTF (1 << 6)
#define CFG14_FLGPAD (1 << 7)
unsigned char cfg_byte15;
#define CFG15_CSTF(x) (x)
#define CFG15_ICSS (1 << 3)
#define CFG15_CDTF(x) (x << 4)
#define CFG15_ICDS (1 << 7)
unsigned short cfg_minfrmlen;
} cfg_t;
typedef struct { /* scb */
unsigned short scb_status; /* status of 82586 */
#define SCB_STRXMASK (7 << 4) /* Receive unit status */
#define SCB_STRXIDLE (0 << 4) /* Idle */
#define SCB_STRXSUSP (1 << 4) /* Suspended */
#define SCB_STRXNRES (2 << 4) /* No resources */
#define SCB_STRXRDY (4 << 4) /* Ready */
#define SCB_STCUMASK (7 << 8) /* Command unit status */
#define SCB_STCUIDLE (0 << 8) /* Idle */
#define SCB_STCUSUSP (1 << 8) /* Suspended */
#define SCB_STCUACTV (2 << 8) /* Active */
#define SCB_STRNR (1 << 12) /* Receive unit not ready */
#define SCB_STCNA (1 << 13) /* Command unit not ready */
#define SCB_STFR (1 << 14) /* Frame received */
#define SCB_STCX (1 << 15) /* Command completed */
unsigned short scb_command; /* Next command */
#define SCB_CMDRXSTART (1 << 4) /* Start (at rfa_offset) */
#define SCB_CMDRXRESUME (2 << 4) /* Resume reception */
#define SCB_CMDRXSUSPEND (3 << 4) /* Suspend reception */
#define SCB_CMDRXABORT (4 << 4) /* Abort reception */
#define SCB_CMDCUCSTART (1 << 8) /* Start (at cbl_offset) */
#define SCB_CMDCUCRESUME (2 << 8) /* Resume execution */
#define SCB_CMDCUCSUSPEND (3 << 8) /* Suspend execution */
#define SCB_CMDCUCABORT (4 << 8) /* Abort execution */
#define SCB_CMDACKRNR (1 << 12) /* Ack RU not ready */
#define SCB_CMDACKCNA (1 << 13) /* Ack CU not ready */
#define SCB_CMDACKFR (1 << 14) /* Ack Frame received */
#define SCB_CMDACKCX (1 << 15) /* Ack Command complete */
unsigned short scb_cbl_offset; /* Offset of first command unit */
unsigned short scb_rfa_offset; /* Offset of first receive frame area */
unsigned short scb_crc_errors; /* Properly aligned frame with CRC error*/
unsigned short scb_aln_errors; /* Misaligned frames */
unsigned short scb_rsc_errors; /* Frames lost due to no space */
unsigned short scb_ovn_errors; /* Frames lost due to slow bus */
} scb_t;
typedef struct { /* iscp */
unsigned short iscp_busy; /* set by CPU before CA */
unsigned short iscp_offset; /* offset of SCB */
unsigned short iscp_basel; /* base of SCB */
unsigned short iscp_baseh;
} iscp_t;
/* this address must be 0xfff6 */
typedef struct { /* scp */
unsigned short scp_sysbus; /* bus size */
#define SCP_SY_16BBUS 0x00
#define SCP_SY_8BBUS 0x01
unsigned short scp_junk[2]; /* junk */
unsigned short scp_iscpl; /* lower 16 bits of iscp */
unsigned short scp_iscph; /* upper 16 bits of iscp */
} scp_t;
/* commands */
#define CMD_NOP 0
#define CMD_SETADDRESS 1
#define CMD_CONFIG 2
#define CMD_SETMULTICAST 3
#define CMD_TX 4
#define CMD_TDR 5
#define CMD_DUMP 6
#define CMD_DIAGNOSE 7
#define CMD_MASK 7
#define CMD_INTR (1 << 13)
#define CMD_SUSP (1 << 14)
#define CMD_EOL (1 << 15)
#define STAT_COLLISIONS (15)
#define STAT_COLLEXCESSIVE (1 << 5)
#define STAT_COLLAFTERTX (1 << 6)
#define STAT_TXDEFERRED (1 << 7)
#define STAT_TXSLOWDMA (1 << 8)
#define STAT_TXLOSTCTS (1 << 9)
#define STAT_NOCARRIER (1 << 10)
#define STAT_FAIL (1 << 11)
#define STAT_ABORTED (1 << 12)
#define STAT_OK (1 << 13)
#define STAT_BUSY (1 << 14)
#define STAT_COMPLETE (1 << 15)
#endif
#endif
/*
* Ether1 card definitions:
*
* FAST accesses:
* +0 Page register
* 16 pages
* +4 Control
* '1' = reset
* '2' = loopback
* '4' = CA
* '8' = int ack
*
* RAM at address + 0x2000
* Pod. Prod id = 3
* Words after ID block [base + 8 words]
* +0 pcb issue (0x0c and 0xf3 invalid)
* +1 - +6 eth hw address
*/

View File

@@ -0,0 +1,238 @@
/* lasi_82596.c -- driver for the intel 82596 ethernet controller, as
munged into HPPA boxen .
This driver is based upon 82596.c, original credits are below...
but there were too many hoops which HP wants jumped through to
keep this code in there in a sane manner.
3 primary sources of the mess --
1) hppa needs *lots* of cacheline flushing to keep this kind of
MMIO running.
2) The 82596 needs to see all of its pointers as their physical
address. Thus virt_to_bus/bus_to_virt are *everywhere*.
3) The implementation HP is using seems to be significantly pickier
about when and how the command and RX units are started. some
command ordering was changed.
Examination of the mach driver leads one to believe that there
might be a saner way to pull this off... anyone who feels like a
full rewrite can be my guest.
Split 02/13/2000 Sam Creasey (sammy@oh.verio.com)
02/01/2000 Initial modifications for parisc by Helge Deller (deller@gmx.de)
03/02/2000 changes for better/correct(?) cache-flushing (deller)
*/
/* 82596.c: A generic 82596 ethernet driver for linux. */
/*
Based on Apricot.c
Written 1994 by Mark Evans.
This driver is for the Apricot 82596 bus-master interface
Modularised 12/94 Mark Evans
Modified to support the 82596 ethernet chips on 680x0 VME boards.
by Richard Hirst <richard@sleepie.demon.co.uk>
Renamed to be 82596.c
980825: Changed to receive directly in to sk_buffs which are
allocated at open() time. Eliminates copy on incoming frames
(small ones are still copied). Shared data now held in a
non-cached page, so we can run on 68060 in copyback mode.
TBD:
* look at deferring rx frames rather than discarding (as per tulip)
* handle tx ring full as per tulip
* performance test to tune rx_copybreak
Most of my modifications relate to the braindead big-endian
implementation by Intel. When the i596 is operating in
'big-endian' mode, it thinks a 32 bit value of 0x12345678
should be stored as 0x56781234. This is a real pain, when
you have linked lists which are shared by the 680x0 and the
i596.
Driver skeleton
Written 1993 by Donald Becker.
Copyright 1993 United States Government as represented by the Director,
National Security Agency. This software may only be used and distributed
according to the terms of the GNU General Public License as modified by SRC,
incorporated herein by reference.
The author may be reached as becker@scyld.com, or C/O
Scyld Computing Corporation, 410 Severn Ave., Suite 210, Annapolis MD 21403
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/ptrace.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/bitops.h>
#include <linux/dma-mapping.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/pdc.h>
#include <asm/parisc-device.h>
#define LASI_82596_DRIVER_VERSION "LASI 82596 driver - Revision: 1.30"
#define PA_I82596_RESET 0 /* Offsets relative to LASI-LAN-Addr.*/
#define PA_CPU_PORT_L_ACCESS 4
#define PA_CHANNEL_ATTENTION 8
#define OPT_SWAP_PORT 0x0001 /* Need to wordswp on the MPU port */
#define DMA_ALLOC dma_alloc_noncoherent
#define DMA_FREE dma_free_noncoherent
#define DMA_WBACK(ndev, addr, len) \
do { dma_cache_sync((ndev)->dev.parent, (void *)addr, len, DMA_TO_DEVICE); } while (0)
#define DMA_INV(ndev, addr, len) \
do { dma_cache_sync((ndev)->dev.parent, (void *)addr, len, DMA_FROM_DEVICE); } while (0)
#define DMA_WBACK_INV(ndev, addr, len) \
do { dma_cache_sync((ndev)->dev.parent, (void *)addr, len, DMA_BIDIRECTIONAL); } while (0)
#define SYSBUS 0x0000006c;
/* big endian CPU, 82596 "big" endian mode */
#define SWAP32(x) (((u32)(x)<<16) | ((((u32)(x)))>>16))
#define SWAP16(x) (x)
#include "lib82596.c"
MODULE_AUTHOR("Richard Hirst");
MODULE_DESCRIPTION("i82596 driver");
MODULE_LICENSE("GPL");
module_param(i596_debug, int, 0);
MODULE_PARM_DESC(i596_debug, "lasi_82596 debug mask");
static inline void ca(struct net_device *dev)
{
gsc_writel(0, dev->base_addr + PA_CHANNEL_ATTENTION);
}
static void mpu_port(struct net_device *dev, int c, dma_addr_t x)
{
struct i596_private *lp = netdev_priv(dev);
u32 v = (u32) (c) | (u32) (x);
u16 a, b;
if (lp->options & OPT_SWAP_PORT) {
a = v >> 16;
b = v & 0xffff;
} else {
a = v & 0xffff;
b = v >> 16;
}
gsc_writel(a, dev->base_addr + PA_CPU_PORT_L_ACCESS);
udelay(1);
gsc_writel(b, dev->base_addr + PA_CPU_PORT_L_ACCESS);
}
#define LAN_PROM_ADDR 0xF0810000
static int __devinit
lan_init_chip(struct parisc_device *dev)
{
struct net_device *netdevice;
struct i596_private *lp;
int retval;
int i;
if (!dev->irq) {
printk(KERN_ERR "%s: IRQ not found for i82596 at 0x%lx\n",
__FILE__, (unsigned long)dev->hpa.start);
return -ENODEV;
}
printk(KERN_INFO "Found i82596 at 0x%lx, IRQ %d\n",
(unsigned long)dev->hpa.start, dev->irq);
netdevice = alloc_etherdev(sizeof(struct i596_private));
if (!netdevice)
return -ENOMEM;
SET_NETDEV_DEV(netdevice, &dev->dev);
parisc_set_drvdata (dev, netdevice);
netdevice->base_addr = dev->hpa.start;
netdevice->irq = dev->irq;
if (pdc_lan_station_id(netdevice->dev_addr, netdevice->base_addr)) {
for (i = 0; i < 6; i++) {
netdevice->dev_addr[i] = gsc_readb(LAN_PROM_ADDR + i);
}
printk(KERN_INFO
"%s: MAC of HP700 LAN read from EEPROM\n", __FILE__);
}
lp = netdev_priv(netdevice);
lp->options = dev->id.sversion == 0x72 ? OPT_SWAP_PORT : 0;
retval = i82596_probe(netdevice);
if (retval) {
free_netdev(netdevice);
return -ENODEV;
}
return retval;
}
static int __devexit lan_remove_chip (struct parisc_device *pdev)
{
struct net_device *dev = parisc_get_drvdata(pdev);
struct i596_private *lp = netdev_priv(dev);
unregister_netdev (dev);
DMA_FREE(&pdev->dev, sizeof(struct i596_private),
(void *)lp->dma, lp->dma_addr);
free_netdev (dev);
return 0;
}
static struct parisc_device_id lan_tbl[] = {
{ HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0008a },
{ HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00072 },
{ 0, }
};
MODULE_DEVICE_TABLE(parisc, lan_tbl);
static struct parisc_driver lan_driver = {
.name = "lasi_82596",
.id_table = lan_tbl,
.probe = lan_init_chip,
.remove = __devexit_p(lan_remove_chip),
};
static int __devinit lasi_82596_init(void)
{
printk(KERN_INFO LASI_82596_DRIVER_VERSION "\n");
return register_parisc_driver(&lan_driver);
}
module_init(lasi_82596_init);
static void __exit lasi_82596_exit(void)
{
unregister_parisc_driver(&lan_driver);
}
module_exit(lasi_82596_exit);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,310 @@
/*
* Intel i82586 Ethernet definitions
*
* This is an extension to the Linux operating system, and is covered by the
* same GNU General Public License that covers that work.
*
* copyrights (c) 1994 by Michael Hipp (hippm@informatik.uni-tuebingen.de)
*
* I have done a look in the following sources:
* crynwr-packet-driver by Russ Nelson
* Garret A. Wollman's i82586-driver for BSD
*/
#define NI52_RESET 0 /* writing to this address, resets the i82586 */
#define NI52_ATTENTION 1 /* channel attention, kick the 586 */
#define NI52_TENA 3 /* 2-5 possibly wrong, Xmit enable */
#define NI52_TDIS 2 /* Xmit disable */
#define NI52_INTENA 5 /* Interrupt enable */
#define NI52_INTDIS 4 /* Interrupt disable */
#define NI52_MAGIC1 6 /* dunno exact function */
#define NI52_MAGIC2 7 /* dunno exact function */
#define NI52_MAGICVAL1 0x00 /* magic-values for ni5210 card */
#define NI52_MAGICVAL2 0x55
/*
* where to find the System Configuration Pointer (SCP)
*/
#define SCP_DEFAULT_ADDRESS 0xfffff4
/*
* System Configuration Pointer Struct
*/
struct scp_struct
{
u16 zero_dum0; /* has to be zero */
u8 sysbus; /* 0=16Bit,1=8Bit */
u8 zero_dum1; /* has to be zero for 586 */
u16 zero_dum2;
u16 zero_dum3;
u32 iscp; /* pointer to the iscp-block */
};
/*
* Intermediate System Configuration Pointer (ISCP)
*/
struct iscp_struct
{
u8 busy; /* 586 clears after successful init */
u8 zero_dummy; /* has to be zero */
u16 scb_offset; /* pointeroffset to the scb_base */
u32 scb_base; /* base-address of all 16-bit offsets */
};
/*
* System Control Block (SCB)
*/
struct scb_struct
{
u8 rus;
u8 cus;
u8 cmd_ruc; /* command word: RU part */
u8 cmd_cuc; /* command word: CU part & ACK */
u16 cbl_offset; /* pointeroffset, command block list */
u16 rfa_offset; /* pointeroffset, receive frame area */
u16 crc_errs; /* CRC-Error counter */
u16 aln_errs; /* alignmenterror counter */
u16 rsc_errs; /* Resourceerror counter */
u16 ovrn_errs; /* OVerrunerror counter */
};
/*
* possible command values for the command word
*/
#define RUC_MASK 0x0070 /* mask for RU commands */
#define RUC_NOP 0x0000 /* NOP-command */
#define RUC_START 0x0010 /* start RU */
#define RUC_RESUME 0x0020 /* resume RU after suspend */
#define RUC_SUSPEND 0x0030 /* suspend RU */
#define RUC_ABORT 0x0040 /* abort receiver operation immediately */
#define CUC_MASK 0x07 /* mask for CU command */
#define CUC_NOP 0x00 /* NOP-command */
#define CUC_START 0x01 /* start execution of 1. cmd on the CBL */
#define CUC_RESUME 0x02 /* resume after suspend */
#define CUC_SUSPEND 0x03 /* Suspend CU */
#define CUC_ABORT 0x04 /* abort command operation immediately */
#define ACK_MASK 0xf0 /* mask for ACK command */
#define ACK_CX 0x80 /* acknowledges STAT_CX */
#define ACK_FR 0x40 /* ack. STAT_FR */
#define ACK_CNA 0x20 /* ack. STAT_CNA */
#define ACK_RNR 0x10 /* ack. STAT_RNR */
/*
* possible status values for the status word
*/
#define STAT_MASK 0xf0 /* mask for cause of interrupt */
#define STAT_CX 0x80 /* CU finished cmd with its I bit set */
#define STAT_FR 0x40 /* RU finished receiving a frame */
#define STAT_CNA 0x20 /* CU left active state */
#define STAT_RNR 0x10 /* RU left ready state */
#define CU_STATUS 0x7 /* CU status, 0=idle */
#define CU_SUSPEND 0x1 /* CU is suspended */
#define CU_ACTIVE 0x2 /* CU is active */
#define RU_STATUS 0x70 /* RU status, 0=idle */
#define RU_SUSPEND 0x10 /* RU suspended */
#define RU_NOSPACE 0x20 /* RU no resources */
#define RU_READY 0x40 /* RU is ready */
/*
* Receive Frame Descriptor (RFD)
*/
struct rfd_struct
{
u8 stat_low; /* status word */
u8 stat_high; /* status word */
u8 rfd_sf; /* 82596 mode only */
u8 last; /* Bit15,Last Frame on List / Bit14,suspend */
u16 next; /* linkoffset to next RFD */
u16 rbd_offset; /* pointeroffset to RBD-buffer */
u8 dest[6]; /* ethernet-address, destination */
u8 source[6]; /* ethernet-address, source */
u16 length; /* 802.3 frame-length */
u16 zero_dummy; /* dummy */
};
#define RFD_LAST 0x80 /* last: last rfd in the list */
#define RFD_SUSP 0x40 /* last: suspend RU after */
#define RFD_COMPL 0x80
#define RFD_OK 0x20
#define RFD_BUSY 0x40
#define RFD_ERR_LEN 0x10 /* Length error (if enabled length-checking */
#define RFD_ERR_CRC 0x08 /* CRC error */
#define RFD_ERR_ALGN 0x04 /* Alignment error */
#define RFD_ERR_RNR 0x02 /* status: receiver out of resources */
#define RFD_ERR_OVR 0x01 /* DMA Overrun! */
#define RFD_ERR_FTS 0x0080 /* Frame to short */
#define RFD_ERR_NEOP 0x0040 /* No EOP flag (for bitstuffing only) */
#define RFD_ERR_TRUN 0x0020 /* (82596 only/SF mode) indicates truncated frame */
#define RFD_MATCHADD 0x0002 /* status: Destinationaddress !matches IA (only 82596) */
#define RFD_COLLDET 0x0001 /* Detected collision during reception */
/*
* Receive Buffer Descriptor (RBD)
*/
struct rbd_struct
{
u16 status; /* status word,number of used bytes in buff */
u16 next; /* pointeroffset to next RBD */
u32 buffer; /* receive buffer address pointer */
u16 size; /* size of this buffer */
u16 zero_dummy; /* dummy */
};
#define RBD_LAST 0x8000 /* last buffer */
#define RBD_USED 0x4000 /* this buffer has data */
#define RBD_MASK 0x3fff /* size-mask for length */
/*
* Statusvalues for Commands/RFD
*/
#define STAT_COMPL 0x8000 /* status: frame/command is complete */
#define STAT_BUSY 0x4000 /* status: frame/command is busy */
#define STAT_OK 0x2000 /* status: frame/command is ok */
/*
* Action-Commands
*/
#define CMD_NOP 0x0000 /* NOP */
#define CMD_IASETUP 0x0001 /* initial address setup command */
#define CMD_CONFIGURE 0x0002 /* configure command */
#define CMD_MCSETUP 0x0003 /* MC setup command */
#define CMD_XMIT 0x0004 /* transmit command */
#define CMD_TDR 0x0005 /* time domain reflectometer (TDR) command */
#define CMD_DUMP 0x0006 /* dump command */
#define CMD_DIAGNOSE 0x0007 /* diagnose command */
/*
* Action command bits
*/
#define CMD_LAST 0x8000 /* indicates last command in the CBL */
#define CMD_SUSPEND 0x4000 /* suspend CU after this CB */
#define CMD_INT 0x2000 /* generate interrupt after execution */
/*
* NOP - command
*/
struct nop_cmd_struct
{
u16 cmd_status; /* status of this command */
u16 cmd_cmd; /* the command itself (+bits) */
u16 cmd_link; /* offsetpointer to next command */
};
/*
* IA Setup command
*/
struct iasetup_cmd_struct
{
u16 cmd_status;
u16 cmd_cmd;
u16 cmd_link;
u8 iaddr[6];
};
/*
* Configure command
*/
struct configure_cmd_struct
{
u16 cmd_status;
u16 cmd_cmd;
u16 cmd_link;
u8 byte_cnt; /* size of the config-cmd */
u8 fifo; /* fifo/recv monitor */
u8 sav_bf; /* save bad frames (bit7=1)*/
u8 adr_len; /* adr_len(0-2),al_loc(3),pream(4-5),loopbak(6-7)*/
u8 priority; /* lin_prio(0-2),exp_prio(4-6),bof_metd(7) */
u8 ifs; /* inter frame spacing */
u8 time_low; /* slot time low */
u8 time_high; /* slot time high(0-2) and max. retries(4-7) */
u8 promisc; /* promisc-mode(0) , et al (1-7) */
u8 carr_coll; /* carrier(0-3)/collision(4-7) stuff */
u8 fram_len; /* minimal frame len */
u8 dummy; /* dummy */
};
/*
* Multicast Setup command
*/
struct mcsetup_cmd_struct
{
u16 cmd_status;
u16 cmd_cmd;
u16 cmd_link;
u16 mc_cnt; /* number of bytes in the MC-List */
u8 mc_list[0][6]; /* pointer to 6 bytes entries */
};
/*
* DUMP command
*/
struct dump_cmd_struct
{
u16 cmd_status;
u16 cmd_cmd;
u16 cmd_link;
u16 dump_offset; /* pointeroffset to DUMP space */
};
/*
* transmit command
*/
struct transmit_cmd_struct
{
u16 cmd_status;
u16 cmd_cmd;
u16 cmd_link;
u16 tbd_offset; /* pointeroffset to TBD */
u8 dest[6]; /* destination address of the frame */
u16 length; /* user defined: 802.3 length / Ether type */
};
#define TCMD_ERRMASK 0x0fa0
#define TCMD_MAXCOLLMASK 0x000f
#define TCMD_MAXCOLL 0x0020
#define TCMD_HEARTBEAT 0x0040
#define TCMD_DEFERRED 0x0080
#define TCMD_UNDERRUN 0x0100
#define TCMD_LOSTCTS 0x0200
#define TCMD_NOCARRIER 0x0400
#define TCMD_LATECOLL 0x0800
struct tdr_cmd_struct
{
u16 cmd_status;
u16 cmd_cmd;
u16 cmd_link;
u16 status;
};
#define TDR_LNK_OK 0x8000 /* No link problem identified */
#define TDR_XCVR_PRB 0x4000 /* indicates a transceiver problem */
#define TDR_ET_OPN 0x2000 /* open, no correct termination */
#define TDR_ET_SRT 0x1000 /* TDR detected a short circuit */
#define TDR_TIMEMASK 0x07ff /* mask for the time field */
/*
* Transmit Buffer Descriptor (TBD)
*/
struct tbd_struct
{
u16 size; /* size + EOF-Flag(15) */
u16 next; /* pointeroffset to next TBD */
u32 buffer; /* pointer to buffer */
};
#define TBD_LAST 0x8000 /* EOF-Flag, indicates last buffer in list */

View File

@@ -0,0 +1,186 @@
/*
* sni_82596.c -- driver for intel 82596 ethernet controller, as
* used in older SNI RM machines
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/bitops.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/irq.h>
#define SNI_82596_DRIVER_VERSION "SNI RM 82596 driver - Revision: 0.01"
static const char sni_82596_string[] = "snirm_82596";
#define DMA_ALLOC dma_alloc_coherent
#define DMA_FREE dma_free_coherent
#define DMA_WBACK(priv, addr, len) do { } while (0)
#define DMA_INV(priv, addr, len) do { } while (0)
#define DMA_WBACK_INV(priv, addr, len) do { } while (0)
#define SYSBUS 0x00004400
/* big endian CPU, 82596 little endian */
#define SWAP32(x) cpu_to_le32((u32)(x))
#define SWAP16(x) cpu_to_le16((u16)(x))
#define OPT_MPU_16BIT 0x01
#include "lib82596.c"
MODULE_AUTHOR("Thomas Bogendoerfer");
MODULE_DESCRIPTION("i82596 driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:snirm_82596");
module_param(i596_debug, int, 0);
MODULE_PARM_DESC(i596_debug, "82596 debug mask");
static inline void ca(struct net_device *dev)
{
struct i596_private *lp = netdev_priv(dev);
writel(0, lp->ca);
}
static void mpu_port(struct net_device *dev, int c, dma_addr_t x)
{
struct i596_private *lp = netdev_priv(dev);
u32 v = (u32) (c) | (u32) (x);
if (lp->options & OPT_MPU_16BIT) {
writew(v & 0xffff, lp->mpu_port);
wmb(); /* order writes to MPU port */
udelay(1);
writew(v >> 16, lp->mpu_port);
} else {
writel(v, lp->mpu_port);
wmb(); /* order writes to MPU port */
udelay(1);
writel(v, lp->mpu_port);
}
}
static int __devinit sni_82596_probe(struct platform_device *dev)
{
struct net_device *netdevice;
struct i596_private *lp;
struct resource *res, *ca, *idprom, *options;
int retval = -ENOMEM;
void __iomem *mpu_addr;
void __iomem *ca_addr;
u8 __iomem *eth_addr;
res = platform_get_resource(dev, IORESOURCE_MEM, 0);
ca = platform_get_resource(dev, IORESOURCE_MEM, 1);
options = platform_get_resource(dev, 0, 0);
idprom = platform_get_resource(dev, IORESOURCE_MEM, 2);
if (!res || !ca || !options || !idprom)
return -ENODEV;
mpu_addr = ioremap_nocache(res->start, 4);
if (!mpu_addr)
return -ENOMEM;
ca_addr = ioremap_nocache(ca->start, 4);
if (!ca_addr)
goto probe_failed_free_mpu;
printk(KERN_INFO "Found i82596 at 0x%x\n", res->start);
netdevice = alloc_etherdev(sizeof(struct i596_private));
if (!netdevice)
goto probe_failed_free_ca;
SET_NETDEV_DEV(netdevice, &dev->dev);
platform_set_drvdata (dev, netdevice);
netdevice->base_addr = res->start;
netdevice->irq = platform_get_irq(dev, 0);
eth_addr = ioremap_nocache(idprom->start, 0x10);
if (!eth_addr)
goto probe_failed;
/* someone seems to like messed up stuff */
netdevice->dev_addr[0] = readb(eth_addr + 0x0b);
netdevice->dev_addr[1] = readb(eth_addr + 0x0a);
netdevice->dev_addr[2] = readb(eth_addr + 0x09);
netdevice->dev_addr[3] = readb(eth_addr + 0x08);
netdevice->dev_addr[4] = readb(eth_addr + 0x07);
netdevice->dev_addr[5] = readb(eth_addr + 0x06);
iounmap(eth_addr);
if (!netdevice->irq) {
printk(KERN_ERR "%s: IRQ not found for i82596 at 0x%lx\n",
__FILE__, netdevice->base_addr);
goto probe_failed;
}
lp = netdev_priv(netdevice);
lp->options = options->flags & IORESOURCE_BITS;
lp->ca = ca_addr;
lp->mpu_port = mpu_addr;
retval = i82596_probe(netdevice);
if (retval == 0)
return 0;
probe_failed:
free_netdev(netdevice);
probe_failed_free_ca:
iounmap(ca_addr);
probe_failed_free_mpu:
iounmap(mpu_addr);
return retval;
}
static int __devexit sni_82596_driver_remove(struct platform_device *pdev)
{
struct net_device *dev = platform_get_drvdata(pdev);
struct i596_private *lp = netdev_priv(dev);
unregister_netdev(dev);
DMA_FREE(dev->dev.parent, sizeof(struct i596_private),
lp->dma, lp->dma_addr);
iounmap(lp->ca);
iounmap(lp->mpu_port);
free_netdev (dev);
return 0;
}
static struct platform_driver sni_82596_driver = {
.probe = sni_82596_probe,
.remove = __devexit_p(sni_82596_driver_remove),
.driver = {
.name = sni_82596_string,
.owner = THIS_MODULE,
},
};
static int __devinit sni_82596_init(void)
{
printk(KERN_INFO SNI_82596_DRIVER_VERSION "\n");
return platform_driver_register(&sni_82596_driver);
}
static void __exit sni_82596_exit(void)
{
platform_driver_unregister(&sni_82596_driver);
}
module_init(sni_82596_init);
module_exit(sni_82596_exit);

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,318 @@
/*
* Intel i82586 Ethernet definitions
*
* This is an extension to the Linux operating system, and is covered by the
* same Gnu Public License that covers that work.
*
* copyrights (c) 1994 by Michael Hipp (hippm@informatik.uni-tuebingen.de)
*
* I have done a look in the following sources:
* crynwr-packet-driver by Russ Nelson
* Garret A. Wollman's i82586-driver for BSD
*/
/*
* Cloned from ni52.h, copyright as above.
*
* Modified for Sun3 OBIO i82586 by Sam Creasey (sammy@sammy.net)
*/
/* defines for the obio chip (not vme) */
#define IEOB_NORSET 0x80 /* don't reset the board */
#define IEOB_ONAIR 0x40 /* put us on the air */
#define IEOB_ATTEN 0x20 /* attention! */
#define IEOB_IENAB 0x10 /* interrupt enable */
#define IEOB_XXXXX 0x08 /* free bit */
#define IEOB_XCVRL2 0x04 /* level 2 transceiver? */
#define IEOB_BUSERR 0x02 /* bus error */
#define IEOB_INT 0x01 /* interrupt */
/* where the obio one lives */
#define IE_OBIO 0xc0000
#define IE_IRQ 3
/*
* where to find the System Configuration Pointer (SCP)
*/
#define SCP_DEFAULT_ADDRESS 0xfffff4
/*
* System Configuration Pointer Struct
*/
struct scp_struct
{
unsigned short zero_dum0; /* has to be zero */
unsigned char sysbus; /* 0=16Bit,1=8Bit */
unsigned char zero_dum1; /* has to be zero for 586 */
unsigned short zero_dum2;
unsigned short zero_dum3;
char *iscp; /* pointer to the iscp-block */
};
/*
* Intermediate System Configuration Pointer (ISCP)
*/
struct iscp_struct
{
unsigned char busy; /* 586 clears after successful init */
unsigned char zero_dummy; /* has to be zero */
unsigned short scb_offset; /* pointeroffset to the scb_base */
char *scb_base; /* base-address of all 16-bit offsets */
};
/*
* System Control Block (SCB)
*/
struct scb_struct
{
unsigned char rus;
unsigned char cus;
unsigned char cmd_ruc; /* command word: RU part */
unsigned char cmd_cuc; /* command word: CU part & ACK */
unsigned short cbl_offset; /* pointeroffset, command block list */
unsigned short rfa_offset; /* pointeroffset, receive frame area */
unsigned short crc_errs; /* CRC-Error counter */
unsigned short aln_errs; /* allignmenterror counter */
unsigned short rsc_errs; /* Resourceerror counter */
unsigned short ovrn_errs; /* OVerrunerror counter */
};
/*
* possible command values for the command word
*/
#define RUC_MASK 0x0070 /* mask for RU commands */
#define RUC_NOP 0x0000 /* NOP-command */
#define RUC_START 0x0010 /* start RU */
#define RUC_RESUME 0x0020 /* resume RU after suspend */
#define RUC_SUSPEND 0x0030 /* suspend RU */
#define RUC_ABORT 0x0040 /* abort receiver operation immediately */
#define CUC_MASK 0x07 /* mask for CU command */
#define CUC_NOP 0x00 /* NOP-command */
#define CUC_START 0x01 /* start execution of 1. cmd on the CBL */
#define CUC_RESUME 0x02 /* resume after suspend */
#define CUC_SUSPEND 0x03 /* Suspend CU */
#define CUC_ABORT 0x04 /* abort command operation immediately */
#define ACK_MASK 0xf0 /* mask for ACK command */
#define ACK_CX 0x80 /* acknowledges STAT_CX */
#define ACK_FR 0x40 /* ack. STAT_FR */
#define ACK_CNA 0x20 /* ack. STAT_CNA */
#define ACK_RNR 0x10 /* ack. STAT_RNR */
/*
* possible status values for the status word
*/
#define STAT_MASK 0xf0 /* mask for cause of interrupt */
#define STAT_CX 0x80 /* CU finished cmd with its I bit set */
#define STAT_FR 0x40 /* RU finished receiving a frame */
#define STAT_CNA 0x20 /* CU left active state */
#define STAT_RNR 0x10 /* RU left ready state */
#define CU_STATUS 0x7 /* CU status, 0=idle */
#define CU_SUSPEND 0x1 /* CU is suspended */
#define CU_ACTIVE 0x2 /* CU is active */
#define RU_STATUS 0x70 /* RU status, 0=idle */
#define RU_SUSPEND 0x10 /* RU suspended */
#define RU_NOSPACE 0x20 /* RU no resources */
#define RU_READY 0x40 /* RU is ready */
/*
* Receive Frame Descriptor (RFD)
*/
struct rfd_struct
{
unsigned char stat_low; /* status word */
unsigned char stat_high; /* status word */
unsigned char rfd_sf; /* 82596 mode only */
unsigned char last; /* Bit15,Last Frame on List / Bit14,suspend */
unsigned short next; /* linkoffset to next RFD */
unsigned short rbd_offset; /* pointeroffset to RBD-buffer */
unsigned char dest[6]; /* ethernet-address, destination */
unsigned char source[6]; /* ethernet-address, source */
unsigned short length; /* 802.3 frame-length */
unsigned short zero_dummy; /* dummy */
};
#define RFD_LAST 0x80 /* last: last rfd in the list */
#define RFD_SUSP 0x40 /* last: suspend RU after */
#define RFD_COMPL 0x80
#define RFD_OK 0x20
#define RFD_BUSY 0x40
#define RFD_ERR_LEN 0x10 /* Length error (if enabled length-checking */
#define RFD_ERR_CRC 0x08 /* CRC error */
#define RFD_ERR_ALGN 0x04 /* Alignment error */
#define RFD_ERR_RNR 0x02 /* status: receiver out of resources */
#define RFD_ERR_OVR 0x01 /* DMA Overrun! */
#define RFD_ERR_FTS 0x0080 /* Frame to short */
#define RFD_ERR_NEOP 0x0040 /* No EOP flag (for bitstuffing only) */
#define RFD_ERR_TRUN 0x0020 /* (82596 only/SF mode) indicates truncated frame */
#define RFD_MATCHADD 0x0002 /* status: Destinationaddress !matches IA (only 82596) */
#define RFD_COLLDET 0x0001 /* Detected collision during reception */
/*
* Receive Buffer Descriptor (RBD)
*/
struct rbd_struct
{
unsigned short status; /* status word,number of used bytes in buff */
unsigned short next; /* pointeroffset to next RBD */
char *buffer; /* receive buffer address pointer */
unsigned short size; /* size of this buffer */
unsigned short zero_dummy; /* dummy */
};
#define RBD_LAST 0x8000 /* last buffer */
#define RBD_USED 0x4000 /* this buffer has data */
#define RBD_MASK 0x3fff /* size-mask for length */
/*
* Statusvalues for Commands/RFD
*/
#define STAT_COMPL 0x8000 /* status: frame/command is complete */
#define STAT_BUSY 0x4000 /* status: frame/command is busy */
#define STAT_OK 0x2000 /* status: frame/command is ok */
/*
* Action-Commands
*/
#define CMD_NOP 0x0000 /* NOP */
#define CMD_IASETUP 0x0001 /* initial address setup command */
#define CMD_CONFIGURE 0x0002 /* configure command */
#define CMD_MCSETUP 0x0003 /* MC setup command */
#define CMD_XMIT 0x0004 /* transmit command */
#define CMD_TDR 0x0005 /* time domain reflectometer (TDR) command */
#define CMD_DUMP 0x0006 /* dump command */
#define CMD_DIAGNOSE 0x0007 /* diagnose command */
/*
* Action command bits
*/
#define CMD_LAST 0x8000 /* indicates last command in the CBL */
#define CMD_SUSPEND 0x4000 /* suspend CU after this CB */
#define CMD_INT 0x2000 /* generate interrupt after execution */
/*
* NOP - command
*/
struct nop_cmd_struct
{
unsigned short cmd_status; /* status of this command */
unsigned short cmd_cmd; /* the command itself (+bits) */
unsigned short cmd_link; /* offsetpointer to next command */
};
/*
* IA Setup command
*/
struct iasetup_cmd_struct
{
unsigned short cmd_status;
unsigned short cmd_cmd;
unsigned short cmd_link;
unsigned char iaddr[6];
};
/*
* Configure command
*/
struct configure_cmd_struct
{
unsigned short cmd_status;
unsigned short cmd_cmd;
unsigned short cmd_link;
unsigned char byte_cnt; /* size of the config-cmd */
unsigned char fifo; /* fifo/recv monitor */
unsigned char sav_bf; /* save bad frames (bit7=1)*/
unsigned char adr_len; /* adr_len(0-2),al_loc(3),pream(4-5),loopbak(6-7)*/
unsigned char priority; /* lin_prio(0-2),exp_prio(4-6),bof_metd(7) */
unsigned char ifs; /* inter frame spacing */
unsigned char time_low; /* slot time low */
unsigned char time_high; /* slot time high(0-2) and max. retries(4-7) */
unsigned char promisc; /* promisc-mode(0) , et al (1-7) */
unsigned char carr_coll; /* carrier(0-3)/collision(4-7) stuff */
unsigned char fram_len; /* minimal frame len */
unsigned char dummy; /* dummy */
};
/*
* Multicast Setup command
*/
struct mcsetup_cmd_struct
{
unsigned short cmd_status;
unsigned short cmd_cmd;
unsigned short cmd_link;
unsigned short mc_cnt; /* number of bytes in the MC-List */
unsigned char mc_list[0][6]; /* pointer to 6 bytes entries */
};
/*
* DUMP command
*/
struct dump_cmd_struct
{
unsigned short cmd_status;
unsigned short cmd_cmd;
unsigned short cmd_link;
unsigned short dump_offset; /* pointeroffset to DUMP space */
};
/*
* transmit command
*/
struct transmit_cmd_struct
{
unsigned short cmd_status;
unsigned short cmd_cmd;
unsigned short cmd_link;
unsigned short tbd_offset; /* pointeroffset to TBD */
unsigned char dest[6]; /* destination address of the frame */
unsigned short length; /* user defined: 802.3 length / Ether type */
};
#define TCMD_ERRMASK 0x0fa0
#define TCMD_MAXCOLLMASK 0x000f
#define TCMD_MAXCOLL 0x0020
#define TCMD_HEARTBEAT 0x0040
#define TCMD_DEFERRED 0x0080
#define TCMD_UNDERRUN 0x0100
#define TCMD_LOSTCTS 0x0200
#define TCMD_NOCARRIER 0x0400
#define TCMD_LATECOLL 0x0800
struct tdr_cmd_struct
{
unsigned short cmd_status;
unsigned short cmd_cmd;
unsigned short cmd_link;
unsigned short status;
};
#define TDR_LNK_OK 0x8000 /* No link problem identified */
#define TDR_XCVR_PRB 0x4000 /* indicates a transceiver problem */
#define TDR_ET_OPN 0x2000 /* open, no correct termination */
#define TDR_ET_SRT 0x1000 /* TDR detected a short circuit */
#define TDR_TIMEMASK 0x07ff /* mask for the time field */
/*
* Transmit Buffer Descriptor (TBD)
*/
struct tbd_struct
{
unsigned short size; /* size + EOF-Flag(15) */
unsigned short next; /* pointeroffset to next TBD */
char *buffer; /* pointer to buffer */
};
#define TBD_LAST 0x8000 /* EOF-Flag, indicates last buffer in list */

View File

@@ -0,0 +1,924 @@
/* znet.c: An Zenith Z-Note ethernet driver for linux. */
/*
Written by Donald Becker.
The author may be reached as becker@scyld.com.
This driver is based on the Linux skeleton driver. The copyright of the
skeleton driver is held by the United States Government, as represented
by DIRNSA, and it is released under the GPL.
Thanks to Mike Hollick for alpha testing and suggestions.
References:
The Crynwr packet driver.
"82593 CSMA/CD Core LAN Controller" Intel datasheet, 1992
Intel Microcommunications Databook, Vol. 1, 1990.
As usual with Intel, the documentation is incomplete and inaccurate.
I had to read the Crynwr packet driver to figure out how to actually
use the i82593, and guess at what register bits matched the loosely
related i82586.
Theory of Operation
The i82593 used in the Zenith Z-Note series operates using two(!) slave
DMA channels, one interrupt, and one 8-bit I/O port.
While there several ways to configure '593 DMA system, I chose the one
that seemed commensurate with the highest system performance in the face
of moderate interrupt latency: Both DMA channels are configured as
recirculating ring buffers, with one channel (#0) dedicated to Rx and
the other channel (#1) to Tx and configuration. (Note that this is
different than the Crynwr driver, where the Tx DMA channel is initialized
before each operation. That approach simplifies operation and Tx error
recovery, but requires additional I/O in normal operation and precludes
transmit buffer chaining.)
Both rings are set to 8192 bytes using {TX,RX}_RING_SIZE. This provides
a reasonable ring size for Rx, while simplifying DMA buffer allocation --
DMA buffers must not cross a 128K boundary. (In truth the size selection
was influenced by my lack of '593 documentation. I thus was constrained
to use the Crynwr '593 initialization table, which sets the Rx ring size
to 8K.)
Despite my usual low opinion about Intel-designed parts, I must admit
that the bulk data handling of the i82593 is a good design for
an integrated system, like a laptop, where using two slave DMA channels
doesn't pose a problem. I still take issue with using only a single I/O
port. In the same controlled environment there are essentially no
limitations on I/O space, and using multiple locations would eliminate
the need for multiple operations when looking at status registers,
setting the Rx ring boundary, or switching to promiscuous mode.
I also question Zenith's selection of the '593: one of the advertised
advantages of earlier Intel parts was that if you figured out the magic
initialization incantation you could use the same part on many different
network types. Zenith's use of the "FriendlyNet" (sic) connector rather
than an on-board transceiver leads me to believe that they were planning
to take advantage of this. But, uhmmm, the '593 omits all but ethernet
functionality from the serial subsystem.
*/
/* 10/2002
o Resurected for Linux 2.5+ by Marc Zyngier <maz@wild-wind.fr.eu.org> :
- Removed strange DMA snooping in znet_sent_packet, which lead to
TX buffer corruption on my laptop.
- Use init_etherdev stuff.
- Use kmalloc-ed DMA buffers.
- Use as few global variables as possible.
- Use proper resources management.
- Use wireless/i82593.h as much as possible (structure, constants)
- Compiles as module or build-in.
- Now survives unplugging/replugging cable.
Some code was taken from wavelan_cs.
Tested on a vintage Zenith Z-Note 433Lnp+. Probably broken on
anything else. Testers (and detailed bug reports) are welcome :-).
o TODO :
- Properly handle multicast
- Understand why some traffic patterns add a 1s latency...
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/if_arp.h>
#include <linux/bitops.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <linux/i82593.h>
static char version[] __initdata = "znet.c:v1.02 9/23/94 becker@scyld.com\n";
#ifndef ZNET_DEBUG
#define ZNET_DEBUG 1
#endif
static unsigned int znet_debug = ZNET_DEBUG;
module_param (znet_debug, int, 0);
MODULE_PARM_DESC (znet_debug, "ZNet debug level");
MODULE_LICENSE("GPL");
/* The DMA modes we need aren't in <dma.h>. */
#define DMA_RX_MODE 0x14 /* Auto init, I/O to mem, ++, demand. */
#define DMA_TX_MODE 0x18 /* Auto init, Mem to I/O, ++, demand. */
#define dma_page_eq(ptr1, ptr2) ((long)(ptr1)>>17 == (long)(ptr2)>>17)
#define RX_BUF_SIZE 8192
#define TX_BUF_SIZE 8192
#define DMA_BUF_SIZE (RX_BUF_SIZE + 16) /* 8k + 16 bytes for trailers */
#define TX_TIMEOUT (HZ/10)
struct znet_private {
int rx_dma, tx_dma;
spinlock_t lock;
short sia_base, sia_size, io_size;
struct i82593_conf_block i593_init;
/* The starting, current, and end pointers for the packet buffers. */
ushort *rx_start, *rx_cur, *rx_end;
ushort *tx_start, *tx_cur, *tx_end;
ushort tx_buf_len; /* Tx buffer length, in words. */
};
/* Only one can be built-in;-> */
static struct net_device *znet_dev;
struct netidblk {
char magic[8]; /* The magic number (string) "NETIDBLK" */
unsigned char netid[8]; /* The physical station address */
char nettype, globalopt;
char vendor[8]; /* The machine vendor and product name. */
char product[8];
char irq1, irq2; /* Interrupts, only one is currently used. */
char dma1, dma2;
short dma_mem_misc[8]; /* DMA buffer locations (unused in Linux). */
short iobase1, iosize1;
short iobase2, iosize2; /* Second iobase unused. */
char driver_options; /* Misc. bits */
char pad;
};
static int znet_open(struct net_device *dev);
static netdev_tx_t znet_send_packet(struct sk_buff *skb,
struct net_device *dev);
static irqreturn_t znet_interrupt(int irq, void *dev_id);
static void znet_rx(struct net_device *dev);
static int znet_close(struct net_device *dev);
static void hardware_init(struct net_device *dev);
static void update_stop_hit(short ioaddr, unsigned short rx_stop_offset);
static void znet_tx_timeout (struct net_device *dev);
/* Request needed resources */
static int znet_request_resources (struct net_device *dev)
{
struct znet_private *znet = netdev_priv(dev);
if (request_irq (dev->irq, znet_interrupt, 0, "ZNet", dev))
goto failed;
if (request_dma (znet->rx_dma, "ZNet rx"))
goto free_irq;
if (request_dma (znet->tx_dma, "ZNet tx"))
goto free_rx_dma;
if (!request_region (znet->sia_base, znet->sia_size, "ZNet SIA"))
goto free_tx_dma;
if (!request_region (dev->base_addr, znet->io_size, "ZNet I/O"))
goto free_sia;
return 0; /* Happy ! */
free_sia:
release_region (znet->sia_base, znet->sia_size);
free_tx_dma:
free_dma (znet->tx_dma);
free_rx_dma:
free_dma (znet->rx_dma);
free_irq:
free_irq (dev->irq, dev);
failed:
return -1;
}
static void znet_release_resources (struct net_device *dev)
{
struct znet_private *znet = netdev_priv(dev);
release_region (znet->sia_base, znet->sia_size);
release_region (dev->base_addr, znet->io_size);
free_dma (znet->tx_dma);
free_dma (znet->rx_dma);
free_irq (dev->irq, dev);
}
/* Keep the magical SIA stuff in a single function... */
static void znet_transceiver_power (struct net_device *dev, int on)
{
struct znet_private *znet = netdev_priv(dev);
unsigned char v;
/* Turn on/off the 82501 SIA, using zenith-specific magic. */
/* Select LAN control register */
outb(0x10, znet->sia_base);
if (on)
v = inb(znet->sia_base + 1) | 0x84;
else
v = inb(znet->sia_base + 1) & ~0x84;
outb(v, znet->sia_base+1); /* Turn on/off LAN power (bit 2). */
}
/* Init the i82593, with current promisc/mcast configuration.
Also used from hardware_init. */
static void znet_set_multicast_list (struct net_device *dev)
{
struct znet_private *znet = netdev_priv(dev);
short ioaddr = dev->base_addr;
struct i82593_conf_block *cfblk = &znet->i593_init;
memset(cfblk, 0x00, sizeof(struct i82593_conf_block));
/* The configuration block. What an undocumented nightmare.
The first set of values are those suggested (without explanation)
for ethernet in the Intel 82586 databook. The rest appear to be
completely undocumented, except for cryptic notes in the Crynwr
packet driver. This driver uses the Crynwr values verbatim. */
/* maz : Rewritten to take advantage of the wanvelan includes.
At least we have names, not just blind values */
/* Byte 0 */
cfblk->fifo_limit = 10; /* = 16 B rx and 80 B tx fifo thresholds */
cfblk->forgnesi = 0; /* 0=82C501, 1=AMD7992B compatibility */
cfblk->fifo_32 = 1;
cfblk->d6mod = 0; /* Run in i82593 advanced mode */
cfblk->throttle_enb = 1;
/* Byte 1 */
cfblk->throttle = 8; /* Continuous w/interrupts, 128-clock DMA. */
cfblk->cntrxint = 0; /* enable continuous mode receive interrupts */
cfblk->contin = 1; /* enable continuous mode */
/* Byte 2 */
cfblk->addr_len = ETH_ALEN;
cfblk->acloc = 1; /* Disable source addr insertion by i82593 */
cfblk->preamb_len = 2; /* 8 bytes preamble */
cfblk->loopback = 0; /* Loopback off */
/* Byte 3 */
cfblk->lin_prio = 0; /* Default priorities & backoff methods. */
cfblk->tbofstop = 0;
cfblk->exp_prio = 0;
cfblk->bof_met = 0;
/* Byte 4 */
cfblk->ifrm_spc = 6; /* 96 bit times interframe spacing */
/* Byte 5 */
cfblk->slottim_low = 0; /* 512 bit times slot time (low) */
/* Byte 6 */
cfblk->slottim_hi = 2; /* 512 bit times slot time (high) */
cfblk->max_retr = 15; /* 15 collisions retries */
/* Byte 7 */
cfblk->prmisc = ((dev->flags & IFF_PROMISC) ? 1 : 0); /* Promiscuous mode */
cfblk->bc_dis = 0; /* Enable broadcast reception */
cfblk->crs_1 = 0; /* Don't transmit without carrier sense */
cfblk->nocrc_ins = 0; /* i82593 generates CRC */
cfblk->crc_1632 = 0; /* 32-bit Autodin-II CRC */
cfblk->crs_cdt = 0; /* CD not to be interpreted as CS */
/* Byte 8 */
cfblk->cs_filter = 0; /* CS is recognized immediately */
cfblk->crs_src = 0; /* External carrier sense */
cfblk->cd_filter = 0; /* CD is recognized immediately */
/* Byte 9 */
cfblk->min_fr_len = ETH_ZLEN >> 2; /* Minimum frame length */
/* Byte A */
cfblk->lng_typ = 1; /* Type/length checks OFF */
cfblk->lng_fld = 1; /* Disable 802.3 length field check */
cfblk->rxcrc_xf = 1; /* Don't transfer CRC to memory */
cfblk->artx = 1; /* Disable automatic retransmission */
cfblk->sarec = 1; /* Disable source addr trig of CD */
cfblk->tx_jabber = 0; /* Disable jabber jam sequence */
cfblk->hash_1 = 1; /* Use bits 0-5 in mc address hash */
cfblk->lbpkpol = 0; /* Loopback pin active high */
/* Byte B */
cfblk->fdx = 0; /* Disable full duplex operation */
/* Byte C */
cfblk->dummy_6 = 0x3f; /* all ones, Default multicast addresses & backoff. */
cfblk->mult_ia = 0; /* No multiple individual addresses */
cfblk->dis_bof = 0; /* Disable the backoff algorithm ?! */
/* Byte D */
cfblk->dummy_1 = 1; /* set to 1 */
cfblk->tx_ifs_retrig = 3; /* Hmm... Disabled */
cfblk->mc_all = (!netdev_mc_empty(dev) ||
(dev->flags & IFF_ALLMULTI)); /* multicast all mode */
cfblk->rcv_mon = 0; /* Monitor mode disabled */
cfblk->frag_acpt = 0; /* Do not accept fragments */
cfblk->tstrttrs = 0; /* No start transmission threshold */
/* Byte E */
cfblk->fretx = 1; /* FIFO automatic retransmission */
cfblk->runt_eop = 0; /* drop "runt" packets */
cfblk->hw_sw_pin = 0; /* ?? */
cfblk->big_endn = 0; /* Big Endian ? no... */
cfblk->syncrqs = 1; /* Synchronous DRQ deassertion... */
cfblk->sttlen = 1; /* 6 byte status registers */
cfblk->rx_eop = 0; /* Signal EOP on packet reception */
cfblk->tx_eop = 0; /* Signal EOP on packet transmission */
/* Byte F */
cfblk->rbuf_size = RX_BUF_SIZE >> 12; /* Set receive buffer size */
cfblk->rcvstop = 1; /* Enable Receive Stop Register */
if (znet_debug > 2) {
int i;
unsigned char *c;
for (i = 0, c = (char *) cfblk; i < sizeof (*cfblk); i++)
printk ("%02X ", c[i]);
printk ("\n");
}
*znet->tx_cur++ = sizeof(struct i82593_conf_block);
memcpy(znet->tx_cur, cfblk, sizeof(struct i82593_conf_block));
znet->tx_cur += sizeof(struct i82593_conf_block)/2;
outb(OP0_CONFIGURE | CR0_CHNL, ioaddr);
/* XXX FIXME maz : Add multicast addresses here, so having a
* multicast address configured isn't equal to IFF_ALLMULTI */
}
static const struct net_device_ops znet_netdev_ops = {
.ndo_open = znet_open,
.ndo_stop = znet_close,
.ndo_start_xmit = znet_send_packet,
.ndo_set_multicast_list = znet_set_multicast_list,
.ndo_tx_timeout = znet_tx_timeout,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
};
/* The Z-Note probe is pretty easy. The NETIDBLK exists in the safe-to-probe
BIOS area. We just scan for the signature, and pull the vital parameters
out of the structure. */
static int __init znet_probe (void)
{
int i;
struct netidblk *netinfo;
struct znet_private *znet;
struct net_device *dev;
char *p;
int err = -ENOMEM;
/* This code scans the region 0xf0000 to 0xfffff for a "NETIDBLK". */
for(p = (char *)phys_to_virt(0xf0000); p < (char *)phys_to_virt(0x100000); p++)
if (*p == 'N' && strncmp(p, "NETIDBLK", 8) == 0)
break;
if (p >= (char *)phys_to_virt(0x100000)) {
if (znet_debug > 1)
printk(KERN_INFO "No Z-Note ethernet adaptor found.\n");
return -ENODEV;
}
dev = alloc_etherdev(sizeof(struct znet_private));
if (!dev)
return -ENOMEM;
znet = netdev_priv(dev);
netinfo = (struct netidblk *)p;
dev->base_addr = netinfo->iobase1;
dev->irq = netinfo->irq1;
/* The station address is in the "netidblk" at 0x0f0000. */
for (i = 0; i < 6; i++)
dev->dev_addr[i] = netinfo->netid[i];
printk(KERN_INFO "%s: ZNET at %#3lx, %pM"
", using IRQ %d DMA %d and %d.\n",
dev->name, dev->base_addr, dev->dev_addr,
dev->irq, netinfo->dma1, netinfo->dma2);
if (znet_debug > 1) {
printk(KERN_INFO "%s: vendor '%16.16s' IRQ1 %d IRQ2 %d DMA1 %d DMA2 %d.\n",
dev->name, netinfo->vendor,
netinfo->irq1, netinfo->irq2,
netinfo->dma1, netinfo->dma2);
printk(KERN_INFO "%s: iobase1 %#x size %d iobase2 %#x size %d net type %2.2x.\n",
dev->name, netinfo->iobase1, netinfo->iosize1,
netinfo->iobase2, netinfo->iosize2, netinfo->nettype);
}
if (znet_debug > 0)
printk(KERN_INFO "%s", version);
znet->rx_dma = netinfo->dma1;
znet->tx_dma = netinfo->dma2;
spin_lock_init(&znet->lock);
znet->sia_base = 0xe6; /* Magic address for the 82501 SIA */
znet->sia_size = 2;
/* maz: Despite the '593 being advertised above as using a
* single 8bits I/O port, this driver does many 16bits
* access. So set io_size accordingly */
znet->io_size = 2;
if (!(znet->rx_start = kmalloc (DMA_BUF_SIZE, GFP_KERNEL | GFP_DMA)))
goto free_dev;
if (!(znet->tx_start = kmalloc (DMA_BUF_SIZE, GFP_KERNEL | GFP_DMA)))
goto free_rx;
if (!dma_page_eq (znet->rx_start, znet->rx_start + (RX_BUF_SIZE/2-1)) ||
!dma_page_eq (znet->tx_start, znet->tx_start + (TX_BUF_SIZE/2-1))) {
printk (KERN_WARNING "tx/rx crossing DMA frontiers, giving up\n");
goto free_tx;
}
znet->rx_end = znet->rx_start + RX_BUF_SIZE/2;
znet->tx_buf_len = TX_BUF_SIZE/2;
znet->tx_end = znet->tx_start + znet->tx_buf_len;
/* The ZNET-specific entries in the device structure. */
dev->netdev_ops = &znet_netdev_ops;
dev->watchdog_timeo = TX_TIMEOUT;
err = register_netdev(dev);
if (err)
goto free_tx;
znet_dev = dev;
return 0;
free_tx:
kfree(znet->tx_start);
free_rx:
kfree(znet->rx_start);
free_dev:
free_netdev(dev);
return err;
}
static int znet_open(struct net_device *dev)
{
int ioaddr = dev->base_addr;
if (znet_debug > 2)
printk(KERN_DEBUG "%s: znet_open() called.\n", dev->name);
/* These should never fail. You can't add devices to a sealed box! */
if (znet_request_resources (dev)) {
printk(KERN_WARNING "%s: Not opened -- resource busy?!?\n", dev->name);
return -EBUSY;
}
znet_transceiver_power (dev, 1);
/* According to the Crynwr driver we should wait 50 msec. for the
LAN clock to stabilize. My experiments indicates that the '593 can
be initialized immediately. The delay is probably needed for the
DC-to-DC converter to come up to full voltage, and for the oscillator
to be spot-on at 20Mhz before transmitting.
Until this proves to be a problem we rely on the higher layers for the
delay and save allocating a timer entry. */
/* maz : Well, I'm getting every time the following message
* without the delay on a 486@33. This machine is much too
* fast... :-) So maybe the Crynwr driver wasn't wrong after
* all, even if the message is completly harmless on my
* setup. */
mdelay (50);
/* This follows the packet driver's lead, and checks for success. */
if (inb(ioaddr) != 0x10 && inb(ioaddr) != 0x00)
printk(KERN_WARNING "%s: Problem turning on the transceiver power.\n",
dev->name);
hardware_init(dev);
netif_start_queue (dev);
return 0;
}
static void znet_tx_timeout (struct net_device *dev)
{
int ioaddr = dev->base_addr;
ushort event, tx_status, rx_offset, state;
outb (CR0_STATUS_0, ioaddr);
event = inb (ioaddr);
outb (CR0_STATUS_1, ioaddr);
tx_status = inw (ioaddr);
outb (CR0_STATUS_2, ioaddr);
rx_offset = inw (ioaddr);
outb (CR0_STATUS_3, ioaddr);
state = inb (ioaddr);
printk (KERN_WARNING "%s: transmit timed out, status %02x %04x %04x %02x,"
" resetting.\n", dev->name, event, tx_status, rx_offset, state);
if (tx_status == TX_LOST_CRS)
printk (KERN_WARNING "%s: Tx carrier error, check transceiver cable.\n",
dev->name);
outb (OP0_RESET, ioaddr);
hardware_init (dev);
netif_wake_queue (dev);
}
static netdev_tx_t znet_send_packet(struct sk_buff *skb, struct net_device *dev)
{
int ioaddr = dev->base_addr;
struct znet_private *znet = netdev_priv(dev);
unsigned long flags;
short length = skb->len;
if (znet_debug > 4)
printk(KERN_DEBUG "%s: ZNet_send_packet.\n", dev->name);
if (length < ETH_ZLEN) {
if (skb_padto(skb, ETH_ZLEN))
return NETDEV_TX_OK;
length = ETH_ZLEN;
}
netif_stop_queue (dev);
/* Check that the part hasn't reset itself, probably from suspend. */
outb(CR0_STATUS_0, ioaddr);
if (inw(ioaddr) == 0x0010 &&
inw(ioaddr) == 0x0000 &&
inw(ioaddr) == 0x0010) {
if (znet_debug > 1)
printk (KERN_WARNING "%s : waking up\n", dev->name);
hardware_init(dev);
znet_transceiver_power (dev, 1);
}
if (1) {
unsigned char *buf = (void *)skb->data;
ushort *tx_link = znet->tx_cur - 1;
ushort rnd_len = (length + 1)>>1;
dev->stats.tx_bytes+=length;
if (znet->tx_cur >= znet->tx_end)
znet->tx_cur = znet->tx_start;
*znet->tx_cur++ = length;
if (znet->tx_cur + rnd_len + 1 > znet->tx_end) {
int semi_cnt = (znet->tx_end - znet->tx_cur)<<1; /* Cvrt to byte cnt. */
memcpy(znet->tx_cur, buf, semi_cnt);
rnd_len -= semi_cnt>>1;
memcpy(znet->tx_start, buf + semi_cnt, length - semi_cnt);
znet->tx_cur = znet->tx_start + rnd_len;
} else {
memcpy(znet->tx_cur, buf, skb->len);
znet->tx_cur += rnd_len;
}
*znet->tx_cur++ = 0;
spin_lock_irqsave(&znet->lock, flags);
{
*tx_link = OP0_TRANSMIT | CR0_CHNL;
/* Is this always safe to do? */
outb(OP0_TRANSMIT | CR0_CHNL, ioaddr);
}
spin_unlock_irqrestore (&znet->lock, flags);
netif_start_queue (dev);
if (znet_debug > 4)
printk(KERN_DEBUG "%s: Transmitter queued, length %d.\n", dev->name, length);
}
dev_kfree_skb(skb);
return NETDEV_TX_OK;
}
/* The ZNET interrupt handler. */
static irqreturn_t znet_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct znet_private *znet = netdev_priv(dev);
int ioaddr;
int boguscnt = 20;
int handled = 0;
spin_lock (&znet->lock);
ioaddr = dev->base_addr;
outb(CR0_STATUS_0, ioaddr);
do {
ushort status = inb(ioaddr);
if (znet_debug > 5) {
ushort result, rx_ptr, running;
outb(CR0_STATUS_1, ioaddr);
result = inw(ioaddr);
outb(CR0_STATUS_2, ioaddr);
rx_ptr = inw(ioaddr);
outb(CR0_STATUS_3, ioaddr);
running = inb(ioaddr);
printk(KERN_DEBUG "%s: interrupt, status %02x, %04x %04x %02x serial %d.\n",
dev->name, status, result, rx_ptr, running, boguscnt);
}
if ((status & SR0_INTERRUPT) == 0)
break;
handled = 1;
if ((status & SR0_EVENT_MASK) == SR0_TRANSMIT_DONE ||
(status & SR0_EVENT_MASK) == SR0_RETRANSMIT_DONE ||
(status & SR0_EVENT_MASK) == SR0_TRANSMIT_NO_CRC_DONE) {
int tx_status;
outb(CR0_STATUS_1, ioaddr);
tx_status = inw(ioaddr);
/* It's undocumented, but tx_status seems to match the i82586. */
if (tx_status & TX_OK) {
dev->stats.tx_packets++;
dev->stats.collisions += tx_status & TX_NCOL_MASK;
} else {
if (tx_status & (TX_LOST_CTS | TX_LOST_CRS))
dev->stats.tx_carrier_errors++;
if (tx_status & TX_UND_RUN)
dev->stats.tx_fifo_errors++;
if (!(tx_status & TX_HRT_BEAT))
dev->stats.tx_heartbeat_errors++;
if (tx_status & TX_MAX_COL)
dev->stats.tx_aborted_errors++;
/* ...and the catch-all. */
if ((tx_status | (TX_LOST_CRS | TX_LOST_CTS | TX_UND_RUN | TX_HRT_BEAT | TX_MAX_COL)) != (TX_LOST_CRS | TX_LOST_CTS | TX_UND_RUN | TX_HRT_BEAT | TX_MAX_COL))
dev->stats.tx_errors++;
/* Transceiver may be stuck if cable
* was removed while emitting a
* packet. Flip it off, then on to
* reset it. This is very empirical,
* but it seems to work. */
znet_transceiver_power (dev, 0);
znet_transceiver_power (dev, 1);
}
netif_wake_queue (dev);
}
if ((status & SR0_RECEPTION) ||
(status & SR0_EVENT_MASK) == SR0_STOP_REG_HIT) {
znet_rx(dev);
}
/* Clear the interrupts we've handled. */
outb(CR0_INT_ACK, ioaddr);
} while (boguscnt--);
spin_unlock (&znet->lock);
return IRQ_RETVAL(handled);
}
static void znet_rx(struct net_device *dev)
{
struct znet_private *znet = netdev_priv(dev);
int ioaddr = dev->base_addr;
int boguscount = 1;
short next_frame_end_offset = 0; /* Offset of next frame start. */
short *cur_frame_end;
short cur_frame_end_offset;
outb(CR0_STATUS_2, ioaddr);
cur_frame_end_offset = inw(ioaddr);
if (cur_frame_end_offset == znet->rx_cur - znet->rx_start) {
printk(KERN_WARNING "%s: Interrupted, but nothing to receive, offset %03x.\n",
dev->name, cur_frame_end_offset);
return;
}
/* Use same method as the Crynwr driver: construct a forward list in
the same area of the backwards links we now have. This allows us to
pass packets to the upper layers in the order they were received --
important for fast-path sequential operations. */
while (znet->rx_start + cur_frame_end_offset != znet->rx_cur &&
++boguscount < 5) {
unsigned short hi_cnt, lo_cnt, hi_status, lo_status;
int count, status;
if (cur_frame_end_offset < 4) {
/* Oh no, we have a special case: the frame trailer wraps around
the end of the ring buffer. We've saved space at the end of
the ring buffer for just this problem. */
memcpy(znet->rx_end, znet->rx_start, 8);
cur_frame_end_offset += (RX_BUF_SIZE/2);
}
cur_frame_end = znet->rx_start + cur_frame_end_offset - 4;
lo_status = *cur_frame_end++;
hi_status = *cur_frame_end++;
status = ((hi_status & 0xff) << 8) + (lo_status & 0xff);
lo_cnt = *cur_frame_end++;
hi_cnt = *cur_frame_end++;
count = ((hi_cnt & 0xff) << 8) + (lo_cnt & 0xff);
if (znet_debug > 5)
printk(KERN_DEBUG "Constructing trailer at location %03x, %04x %04x %04x %04x"
" count %#x status %04x.\n",
cur_frame_end_offset<<1, lo_status, hi_status, lo_cnt, hi_cnt,
count, status);
cur_frame_end[-4] = status;
cur_frame_end[-3] = next_frame_end_offset;
cur_frame_end[-2] = count;
next_frame_end_offset = cur_frame_end_offset;
cur_frame_end_offset -= ((count + 1)>>1) + 3;
if (cur_frame_end_offset < 0)
cur_frame_end_offset += RX_BUF_SIZE/2;
}
/* Now step forward through the list. */
do {
ushort *this_rfp_ptr = znet->rx_start + next_frame_end_offset;
int status = this_rfp_ptr[-4];
int pkt_len = this_rfp_ptr[-2];
if (znet_debug > 5)
printk(KERN_DEBUG "Looking at trailer ending at %04x status %04x length %03x"
" next %04x.\n", next_frame_end_offset<<1, status, pkt_len,
this_rfp_ptr[-3]<<1);
/* Once again we must assume that the i82586 docs apply. */
if ( ! (status & RX_RCV_OK)) { /* There was an error. */
dev->stats.rx_errors++;
if (status & RX_CRC_ERR) dev->stats.rx_crc_errors++;
if (status & RX_ALG_ERR) dev->stats.rx_frame_errors++;
#if 0
if (status & 0x0200) dev->stats.rx_over_errors++; /* Wrong. */
if (status & 0x0100) dev->stats.rx_fifo_errors++;
#else
/* maz : Wild guess... */
if (status & RX_OVRRUN) dev->stats.rx_over_errors++;
#endif
if (status & RX_SRT_FRM) dev->stats.rx_length_errors++;
} else if (pkt_len > 1536) {
dev->stats.rx_length_errors++;
} else {
/* Malloc up new buffer. */
struct sk_buff *skb;
skb = dev_alloc_skb(pkt_len);
if (skb == NULL) {
if (znet_debug)
printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
dev->stats.rx_dropped++;
break;
}
if (&znet->rx_cur[(pkt_len+1)>>1] > znet->rx_end) {
int semi_cnt = (znet->rx_end - znet->rx_cur)<<1;
memcpy(skb_put(skb,semi_cnt), znet->rx_cur, semi_cnt);
memcpy(skb_put(skb,pkt_len-semi_cnt), znet->rx_start,
pkt_len - semi_cnt);
} else {
memcpy(skb_put(skb,pkt_len), znet->rx_cur, pkt_len);
if (znet_debug > 6) {
unsigned int *packet = (unsigned int *) skb->data;
printk(KERN_DEBUG "Packet data is %08x %08x %08x %08x.\n", packet[0],
packet[1], packet[2], packet[3]);
}
}
skb->protocol=eth_type_trans(skb,dev);
netif_rx(skb);
dev->stats.rx_packets++;
dev->stats.rx_bytes += pkt_len;
}
znet->rx_cur = this_rfp_ptr;
if (znet->rx_cur >= znet->rx_end)
znet->rx_cur -= RX_BUF_SIZE/2;
update_stop_hit(ioaddr, (znet->rx_cur - znet->rx_start)<<1);
next_frame_end_offset = this_rfp_ptr[-3];
if (next_frame_end_offset == 0) /* Read all the frames? */
break; /* Done for now */
this_rfp_ptr = znet->rx_start + next_frame_end_offset;
} while (--boguscount);
/* If any worth-while packets have been received, dev_rint()
has done a mark_bh(INET_BH) for us and will work on them
when we get to the bottom-half routine. */
}
/* The inverse routine to znet_open(). */
static int znet_close(struct net_device *dev)
{
int ioaddr = dev->base_addr;
netif_stop_queue (dev);
outb(OP0_RESET, ioaddr); /* CMD0_RESET */
if (znet_debug > 1)
printk(KERN_DEBUG "%s: Shutting down ethercard.\n", dev->name);
/* Turn off transceiver power. */
znet_transceiver_power (dev, 0);
znet_release_resources (dev);
return 0;
}
static void show_dma(struct net_device *dev)
{
short ioaddr = dev->base_addr;
unsigned char stat = inb (ioaddr);
struct znet_private *znet = netdev_priv(dev);
unsigned long flags;
short dma_port = ((znet->tx_dma&3)<<2) + IO_DMA2_BASE;
unsigned addr = inb(dma_port);
short residue;
addr |= inb(dma_port) << 8;
residue = get_dma_residue(znet->tx_dma);
if (znet_debug > 1) {
flags=claim_dma_lock();
printk(KERN_DEBUG "Stat:%02x Addr: %04x cnt:%3x\n",
stat, addr<<1, residue);
release_dma_lock(flags);
}
}
/* Initialize the hardware. We have to do this when the board is open()ed
or when we come out of suspend mode. */
static void hardware_init(struct net_device *dev)
{
unsigned long flags;
short ioaddr = dev->base_addr;
struct znet_private *znet = netdev_priv(dev);
znet->rx_cur = znet->rx_start;
znet->tx_cur = znet->tx_start;
/* Reset the chip, and start it up. */
outb(OP0_RESET, ioaddr);
flags=claim_dma_lock();
disable_dma(znet->rx_dma); /* reset by an interrupting task. */
clear_dma_ff(znet->rx_dma);
set_dma_mode(znet->rx_dma, DMA_RX_MODE);
set_dma_addr(znet->rx_dma, (unsigned int) znet->rx_start);
set_dma_count(znet->rx_dma, RX_BUF_SIZE);
enable_dma(znet->rx_dma);
/* Now set up the Tx channel. */
disable_dma(znet->tx_dma);
clear_dma_ff(znet->tx_dma);
set_dma_mode(znet->tx_dma, DMA_TX_MODE);
set_dma_addr(znet->tx_dma, (unsigned int) znet->tx_start);
set_dma_count(znet->tx_dma, znet->tx_buf_len<<1);
enable_dma(znet->tx_dma);
release_dma_lock(flags);
if (znet_debug > 1)
printk(KERN_DEBUG "%s: Initializing the i82593, rx buf %p tx buf %p\n",
dev->name, znet->rx_start,znet->tx_start);
/* Do an empty configure command, just like the Crynwr driver. This
resets to chip to its default values. */
*znet->tx_cur++ = 0;
*znet->tx_cur++ = 0;
show_dma(dev);
outb(OP0_CONFIGURE | CR0_CHNL, ioaddr);
znet_set_multicast_list (dev);
*znet->tx_cur++ = 6;
memcpy(znet->tx_cur, dev->dev_addr, 6);
znet->tx_cur += 3;
show_dma(dev);
outb(OP0_IA_SETUP | CR0_CHNL, ioaddr);
show_dma(dev);
update_stop_hit(ioaddr, 8192);
if (znet_debug > 1) printk(KERN_DEBUG "enabling Rx.\n");
outb(OP0_RCV_ENABLE, ioaddr);
netif_start_queue (dev);
}
static void update_stop_hit(short ioaddr, unsigned short rx_stop_offset)
{
outb(OP0_SWIT_TO_PORT_1 | CR0_CHNL, ioaddr);
if (znet_debug > 5)
printk(KERN_DEBUG "Updating stop hit with value %02x.\n",
(rx_stop_offset >> 6) | CR1_STOP_REG_UPDATE);
outb((rx_stop_offset >> 6) | CR1_STOP_REG_UPDATE, ioaddr);
outb(OP1_SWIT_TO_PORT_0, ioaddr);
}
static __exit void znet_cleanup (void)
{
if (znet_dev) {
struct znet_private *znet = netdev_priv(znet_dev);
unregister_netdev (znet_dev);
kfree (znet->rx_start);
kfree (znet->tx_start);
free_netdev (znet_dev);
}
}
module_init (znet_probe);
module_exit (znet_cleanup);