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:
1673
drivers/net/ethernet/i825xx/3c505.c
Normal file
1673
drivers/net/ethernet/i825xx/3c505.c
Normal file
File diff suppressed because it is too large
Load Diff
292
drivers/net/ethernet/i825xx/3c505.h
Normal file
292
drivers/net/ethernet/i825xx/3c505.h
Normal 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;
|
939
drivers/net/ethernet/i825xx/3c507.c
Normal file
939
drivers/net/ethernet/i825xx/3c507.c
Normal 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");
|
1312
drivers/net/ethernet/i825xx/3c523.c
Normal file
1312
drivers/net/ethernet/i825xx/3c523.c
Normal file
File diff suppressed because it is too large
Load Diff
355
drivers/net/ethernet/i825xx/3c523.h
Normal file
355
drivers/net/ethernet/i825xx/3c523.h
Normal 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_ */
|
1661
drivers/net/ethernet/i825xx/3c527.c
Normal file
1661
drivers/net/ethernet/i825xx/3c527.c
Normal file
File diff suppressed because it is too large
Load Diff
81
drivers/net/ethernet/i825xx/3c527.h
Normal file
81
drivers/net/ethernet/i825xx/3c527.h
Normal 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 */
|
1632
drivers/net/ethernet/i825xx/82596.c
Normal file
1632
drivers/net/ethernet/i825xx/82596.c
Normal file
File diff suppressed because it is too large
Load Diff
182
drivers/net/ethernet/i825xx/Kconfig
Normal file
182
drivers/net/ethernet/i825xx/Kconfig
Normal 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
|
20
drivers/net/ethernet/i825xx/Makefile
Normal file
20
drivers/net/ethernet/i825xx/Makefile
Normal 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
|
1822
drivers/net/ethernet/i825xx/eepro.c
Normal file
1822
drivers/net/ethernet/i825xx/eepro.c
Normal file
File diff suppressed because it is too large
Load Diff
1720
drivers/net/ethernet/i825xx/eexpress.c
Normal file
1720
drivers/net/ethernet/i825xx/eexpress.c
Normal file
File diff suppressed because it is too large
Load Diff
179
drivers/net/ethernet/i825xx/eexpress.h
Normal file
179
drivers/net/ethernet/i825xx/eexpress.h
Normal 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
|
1094
drivers/net/ethernet/i825xx/ether1.c
Normal file
1094
drivers/net/ethernet/i825xx/ether1.c
Normal file
File diff suppressed because it is too large
Load Diff
280
drivers/net/ethernet/i825xx/ether1.h
Normal file
280
drivers/net/ethernet/i825xx/ether1.h
Normal 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
|
||||
*/
|
238
drivers/net/ethernet/i825xx/lasi_82596.c
Normal file
238
drivers/net/ethernet/i825xx/lasi_82596.c
Normal 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);
|
1412
drivers/net/ethernet/i825xx/lib82596.c
Normal file
1412
drivers/net/ethernet/i825xx/lib82596.c
Normal file
File diff suppressed because it is too large
Load Diff
1339
drivers/net/ethernet/i825xx/lp486e.c
Normal file
1339
drivers/net/ethernet/i825xx/lp486e.c
Normal file
File diff suppressed because it is too large
Load Diff
1346
drivers/net/ethernet/i825xx/ni52.c
Normal file
1346
drivers/net/ethernet/i825xx/ni52.c
Normal file
File diff suppressed because it is too large
Load Diff
310
drivers/net/ethernet/i825xx/ni52.h
Normal file
310
drivers/net/ethernet/i825xx/ni52.h
Normal 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 */
|
||||
|
||||
|
||||
|
||||
|
186
drivers/net/ethernet/i825xx/sni_82596.c
Normal file
186
drivers/net/ethernet/i825xx/sni_82596.c
Normal 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);
|
1213
drivers/net/ethernet/i825xx/sun3_82586.c
Normal file
1213
drivers/net/ethernet/i825xx/sun3_82586.c
Normal file
File diff suppressed because it is too large
Load Diff
318
drivers/net/ethernet/i825xx/sun3_82586.h
Normal file
318
drivers/net/ethernet/i825xx/sun3_82586.h
Normal 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 */
|
||||
|
||||
|
||||
|
||||
|
924
drivers/net/ethernet/i825xx/znet.c
Normal file
924
drivers/net/ethernet/i825xx/znet.c
Normal 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);
|
Reference in New Issue
Block a user