Commit cbb79dc1 authored by Linus Torvalds's avatar Linus Torvalds

Import 1.1.22

parent 466add5a
VERSION = 1
PATCHLEVEL = 1
SUBLEVEL = 21
SUBLEVEL = 22
all: Version zImage
......
......@@ -70,10 +70,10 @@ comment 'Network device support'
bool 'Network device support?' CONFIG_NETDEVICES y
if [ "$CONFIG_NETDEVICES" = "n" ]; then
comment 'Skipping ethercard configuration options...'
comment 'Skipping network driver configuration options...'
else
bool 'Dummy net driver support' CONFIG_DUMMY y
bool 'Dummy net driver support' CONFIG_DUMMY n
bool 'SLIP (serial line) support' CONFIG_SLIP n
if [ "$CONFIG_SLIP" = "y" ]; then
bool ' CSLIP compressed headers' SL_COMPRESSED y
......@@ -81,29 +81,49 @@ if [ "$CONFIG_SLIP" = "y" ]; then
fi
bool 'PPP (point-to-point) support' CONFIG_PPP n
bool 'Load balancing support (experimental)' CONFIG_SLAVE_BALANCING n
bool 'Do you want to be offered ALPHA test drivers' CONFIG_NET_ALPHA n
bool 'Western Digital/SMC cards' CONFIG_NET_VENDOR_SMC n
if [ "$CONFIG_NET_VENDOR_SMC" = "y" ]; then
bool 'WD80*3 support' CONFIG_WD80x3 n
bool 'SMC Ultra support' CONFIG_ULTRA n
fi
bool '3COM cards' CONFIG_NET_VENDOR_3COM y
if [ "$CONFIG_NET_VENDOR_3COM" = "y" ]; then
bool '3c501 support' CONFIG_EL1 n
bool '3c503 support' CONFIG_EL2 n
if [ "$CONFIG_NET_ALPHA" = "y" ]; then
bool '3c505 support' CONFIG_ELPLUS n
bool '3c507 support' CONFIG_EL16 n
fi
bool '3c509/3c579 support' CONFIG_EL3 y
fi
bool 'Other ISA cards' CONFIG_NET_ISA n
if [ "$CONFIG_NET_ISA" = "y" ]; then
bool 'AT1500 and NE2100 (LANCE and PCnet-ISA) support' CONFIG_LANCE y
bool 'Cabletron E21xx support (not recommended)' CONFIG_E2100 n
bool 'DEPCA support' CONFIG_DEPCA n
if [ "$CONFIG_NET_ALPHA" = "y" ]; then
bool 'EtherExpress support' CONFIG_EEXPRESS n
fi
bool 'HP PCLAN support' CONFIG_HPLAN n
bool 'NE2000/NE1000 support' CONFIG_NE2000 n
fi
bool 'PLIP (parallel port) support' CONFIG_PLIP n
bool 'NE2000/NE1000 support' CONFIG_NE2000 n
bool 'WD80*3 support' CONFIG_WD80x3 n
bool 'SMC Ultra support' CONFIG_ULTRA n
bool '3c501 support' CONFIG_EL1 n
bool '3c503 support' CONFIG_EL2 n
#bool '3c505 support' CONFIG_ELPLUS n
#bool '3c507 support' CONFIG_EL16 n
bool '3c509/3c579 support' CONFIG_EL3 y
bool 'HP PCLAN support' CONFIG_HPLAN n
bool 'AT1500 and NE2100 (LANCE and PCnet-ISA) support' CONFIG_LANCE n
bool 'AT1700 support' CONFIG_AT1700 n
#bool 'Zenith Z-Note support' CONFIG_ZNET n
#bool 'EtherExpress support' CONFIG_EEXPRESS n
#bool 'Apricot Xen-II on board ethernet' CONFIG_APRICOT n
bool 'DEPCA support' CONFIG_DEPCA n
bool 'EISA and on board controllers' CONFIG_NET_EISA n
if [ "$CONFIG_NET_ALPHA" = "y" ]; then
bool 'Ansel Communications EISA 3200 support' CONFIG_AC3200 n
bool 'AT1700 support' CONFIG_AT1700 n
fi
bool 'Apricot Xen-II on board ethernet' CONFIG_APRICOT n
#bool 'NI52EE support' CONFIG_NI52 n
#bool 'NI65EE support' CONFIG_NI65 n
#bool 'Ansel Communications EISA 3200 support' CONFIG_AC3200 n
#bool 'Cabletron E21xx support (not recommended)' CONFIG_E2100 n
bool 'D-Link DE600 pocket adaptor support' CONFIG_DE600 n
bool 'D-Link DE620 pocket adaptor support' CONFIG_DE620 n
bool 'AT-LAN-TEC/RealTek pocket adaptor support' CONFIG_ATP n
bool 'Pocket and portable adaptors' CONFIG_NET_POCKET n
if [ "$CONFIG_NET_POCKET" = "y" ]; then
bool 'D-Link DE600 pocket adaptor support' CONFIG_DE600 n
bool 'D-Link DE620 pocket adaptor support' CONFIG_DE620 n
bool 'AT-LAN-TEC/RealTek pocket adaptor support' CONFIG_ATP n
bool 'Zenith Z-Note support' CONFIG_ZNET n
fi
fi
fi
......
......@@ -655,8 +655,10 @@ static void hd_geninit(void)
hd_info[drive].ctl = *(8+BIOS);
hd_info[drive].lzone = *(unsigned short *) (12+BIOS);
hd_info[drive].sect = *(14+BIOS);
#ifdef does_not_work_for_everybody_with_scsi_but_helps_ibm_vp
if (hd_info[drive].cyl && NR_HD == drive)
NR_HD++;
#endif
BIOS += 16;
}
......
......@@ -133,6 +133,8 @@ static struct {
/* mode flags */
unsigned long vc_charset : 1; /* Character set G0 / G1 */
unsigned long vc_s_charset : 1; /* Saved character set */
unsigned long vc_disp_ctrl : 1; /* Display chars < 32? */
unsigned long vc_toggle_meta : 1; /* Toggle high bit? */
unsigned long vc_decscnm : 1; /* Screen Mode */
unsigned long vc_decom : 1; /* Origin Mode */
unsigned long vc_decawm : 1; /* Autowrap Mode */
......@@ -185,6 +187,8 @@ static int console_blanked = 0;
#define video_mem_start (vc_cons[currcons].vc_video_mem_start)
#define video_mem_end (vc_cons[currcons].vc_video_mem_end)
#define video_erase_char (vc_cons[currcons].vc_video_erase_char)
#define disp_ctrl (vc_cons[currcons].vc_disp_ctrl)
#define toggle_meta (vc_cons[currcons].vc_toggle_meta)
#define decscnm (vc_cons[currcons].vc_decscnm)
#define decom (vc_cons[currcons].vc_decom)
#define decawm (vc_cons[currcons].vc_decawm)
......@@ -682,6 +686,33 @@ static void csi_m(int currcons)
case 7:
reverse = 1;
break;
case 10: /* ANSI X3.64-1979 (SCO-ish?)
* Select primary font, don't display
* control chars if defined, don't set
* bit 8 on output.
*/
translate = (charset == 0
? G0_charset
: G1_charset);
disp_ctrl = 0;
toggle_meta = 0;
break;
case 11: /* ANSI X3.64-1979 (SCO-ish?)
* Select first alternate font, let's
* chars < 32 be displayed as ROM chars.
*/
translate = NULL_TRANS;
disp_ctrl = 1;
toggle_meta = 0;
break;
case 12: /* ANSI X3.64-1979 (SCO-ish?)
* Select second alternate font, toggle
* high bit before displaying as ROM char.
*/
translate = NULL_TRANS;
disp_ctrl = 1;
toggle_meta = 1;
break;
case 21:
case 22:
intensity = 1;
......@@ -695,8 +726,21 @@ static void csi_m(int currcons)
case 27:
reverse = 0;
break;
case 39:
case 38: /* ANSI X3.64-1979 (SCO-ish?)
* Enables underscore, white foreground
* with white underscore (Linux - use
* default foreground).
*/
color = (def_color & 0x0f) | background;
underline = 1;
break;
case 39: /* ANSI X3.64-1979 (SCO-ish?)
* Disable underline option.
* Reset colour to default? It did this
* before...
*/
color = (def_color & 0x0f) | background;
underline = 0;
break;
case 49:
color = (def_color & 0xf0) | foreground;
......@@ -957,6 +1001,9 @@ static void reset_terminal(int currcons, int do_clear)
charset = 0;
need_wrap = 0;
disp_ctrl = 0;
toggle_meta = 0;
decscnm = 0;
decom = 0;
decawm = 1;
......@@ -1026,7 +1073,11 @@ static int con_write(struct tty_struct * tty, int from_user,
while (!tty->stopped && count) {
c = from_user ? get_fs_byte(buf) : *buf;
buf++; n++; count--;
if (vc_state == ESnormal && translate[c]) {
if (vc_state == ESnormal
&& (c >= 32 || (disp_ctrl && (c&0x7f) != 27))
&& (toggle_meta ? translate[c|0x80] : translate[c])) {
if (toggle_meta)
c |= 0x80;
if (need_wrap) {
cr(currcons);
lf(currcons);
......
/*
* Linux ethernet device driver for the 3Com Etherlink Plus (3C505)
* By Craig Southeren
*
* 3c505.c This module implements an interface to the 3Com
* Etherlink Plus (3c505) ethernet card. Linux device
* driver interface reverse engineered from the Linux 3C509
* device drivers. Vital 3C505 information gleaned from
* the Crynwr packet driver
*
* Version: @(#)3c505.c 0.1 23/09/93
*
* Authors: Linux 3c505 device driver by:
* Craig Southeren, <geoffw@extro.ucc.su.oz.au>
* Linux 3C509 driver by:
* Donald Becker, <becker@super.org>
* Crynwr packet driver by
* Krishnan Gopalan and Gregg Stefancik,
* Clemson Univesity Engineering Computer Operations.
* Portions of the code have been adapted from the 3c505
* driver for NCSA Telnet by Bruce Orchard and later
* modified by Warren Van Houten and krus@diku.dk.
* 3C505 technical information provided by
* Terry Murphy, of 3Com Network Adapter Division
* Special thanks to Juha Laiho, <jlaiho@ichaos.nullnet.fi>
*
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/interrupt.h>
#include <linux/ptrace.h>
#include <linux/errno.h>
#include <linux/in.h>
#include <asm/io.h>
#ifndef port_read
#include "iow.h"
#endif
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include "3c505.h"
#ifdef ELP_DEBUG
static int elp_debug = ELP_DEBUG;
#else
static int elp_debug = 0;
#endif
/*
* 0 = no messages
* 1 = messages when high level commands performed
* 2 = messages when low level commands performed
* 3 = messages when interrupts received
*/
#define ELP_VERSION "0.1.0"
extern struct device *irq2dev_map[16];
/*****************************************************************
*
* useful macros
*
*****************************************************************/
#define INB(port) inb((unsigned short)port)
#define OUTB(val,port) outb((unsigned char)val,(unsigned short)port);
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
/*****************************************************************
*
* PCB structure
*
*****************************************************************/
typedef struct {
unsigned char command; /* PCB command code */
unsigned char length; /* PCB data length */
unsigned char data[MAX_PCB_DATA]; /* PCB data */
} pcb_struct;
/*****************************************************************
*
* structure to hold context information for adapter
*
*****************************************************************/
typedef struct {
int io_addr; /* base I/O address */
short got_configure; /* set to TRUE when configure response received */
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 */
struct enet_statistics stats;
} elp_device;
/*****************************************************************
*
* useful functions for accessing the adapter
*
*****************************************************************/
/*
* use this routine when accessing the ASF bits as they are
* changed asynchronously by the adapter
*/
/* get adapter PCB status */
#define GET_ASF() (get_status(adapter)&ASF_PCB_MASK)
#define GET_STATUS() (get_status(adapter))
static int get_status (elp_device * adapter)
{
register int stat1;
do {
stat1 = INB(adapter->io_addr+PORT_STATUS);
} while (stat1 != INB(adapter->io_addr+PORT_STATUS));
return stat1;
}
#define SET_HSF(hsf) (set_hsf(adapter,hsf))
static void set_hsf (elp_device * adapter, int hsf)
{
cli();
OUTB((INB(adapter->io_addr+PORT_CONTROL)&(~HSF_PCB_MASK))|hsf, adapter->io_addr+PORT_CONTROL);
sti();
}
#define WAIT_HCRE(toval) (wait_hcre(adapter,toval))
static int wait_hcre(elp_device * adapter, int toval)
{
int timeout = jiffies + toval;
while(((INB(adapter->io_addr+PORT_STATUS)&STATUS_HCRE)==0) &&
(jiffies <= timeout))
;
if (jiffies > timeout) {
printk("elp0: timeout waiting for HCRE\n");
return FALSE;
}
return TRUE;
}
/*****************************************************************
*
* send_pcb
* Send a PCB to the adapter.
*
* output byte to command reg --<--+
* wait until HCRE is non zero |
* loop until all bytes sent -->--+
* set HSF1 and HSF2 to 1
* output pcb length
* wait until ASF give ACK or NAK
* set HSF1 and HSF2 to 0
*
*****************************************************************/
static int send_pcb(elp_device * adapter, pcb_struct * pcb)
{
int i;
int cont;
int retry = 0;
int timeout;
while (1) {
cont = 1;
/*
* load each byte into the command register and
* wait for the HCRE bit to indicate the adapter
* had read the byte
*/
SET_HSF(0);
OUTB(pcb->command, (adapter->io_addr)+PORT_COMMAND);
cont = WAIT_HCRE(5);
/* SET_HSF(0); */
if (cont) {
OUTB(pcb->length, (adapter->io_addr)+PORT_COMMAND);
cont = WAIT_HCRE(2);
}
for (i = 0; cont && (i < pcb->length); i++) {
OUTB(pcb->data[i], (adapter->io_addr)+PORT_COMMAND);
cont = WAIT_HCRE(2);
}
/* set the host status bits to indicate end of PCB */
/* send the total packet length as well */
/* wait for the adapter to indicate that it has read the PCB */
if (cont) {
SET_HSF(HSF_PCB_END);
OUTB(2+pcb->length, adapter->io_addr+PORT_COMMAND);
timeout = jiffies + 6;
while (jiffies < timeout) {
i = GET_ASF();
if ((i == ASF_PCB_ACK) ||
(i == ASF_PCB_NAK))
break;
}
if (i == ASF_PCB_ACK) {
SET_HSF(0);
return TRUE;
} else if (i = ASF_PCB_NAK) {
SET_HSF(0);
printk("elp0: PCB send was NAKed\n");
{
int to = jiffies + 5;
while (jiffies < to)
;
}
}
}
if (elp_debug >= 6)
printk("elp0: NAK/timeout on send PCB\n");
if ((retry++ & 7) == 0)
printk("elp0: retry #%i on send PCB\n", retry);
}
}
/*****************************************************************
*
* receive_pcb
* Read a PCB to the adapter
*
* wait for ACRF to be non-zero ---<---+
* input a byte |
* if ASF1 and ASF2 were not both one |
* before byte was read, loop --->---+
* set HSF1 and HSF2 for ack
*
*****************************************************************/
static int receive_pcb(elp_device * adapter, pcb_struct * pcb)
{
int i;
int total_length;
int stat;
/* get the command code */
while (((stat = GET_STATUS())&STATUS_ACRF) == 0)
;
SET_HSF(0);
pcb->command = INB(adapter->io_addr+PORT_COMMAND);
if ((stat & ASF_PCB_MASK) != ASF_PCB_END) {
/* read the data length */
while (((stat = GET_STATUS())&STATUS_ACRF) == 0)
;
pcb->length = INB(adapter->io_addr+PORT_COMMAND);
if ((stat & ASF_PCB_MASK) != ASF_PCB_END) {
/* read the data */
i = 0;
do {
while (((stat = GET_STATUS())&STATUS_ACRF) == 0)
;
pcb->data[i++] = INB(adapter->io_addr+PORT_COMMAND);
} while ((stat & ASF_PCB_MASK) != ASF_PCB_END);
/* woops, the last "data" byte was really the length! */
total_length = pcb->data[--i];
/* safety check total length vs data length */
if (total_length != (pcb->length + 2)) {
if (elp_debug >= 6)
printk("elp0: mangled PCB received\n");
SET_HSF(HSF_PCB_NAK);
return FALSE;
}
SET_HSF(HSF_PCB_ACK);
return TRUE;
}
}
SET_HSF(HSF_PCB_NAK);
return FALSE;
}
static void adapter_hard_reset(elp_device * adapter)
{
int timeout;
/*
* take FLSH and ATTN high
*/
OUTB(CONTROL_ATTN|CONTROL_FLSH, adapter->io_addr+PORT_CONTROL);
/*
* wait for a little bit
*/
for (timeout = jiffies + 20; jiffies <= timeout; )
;
/*
* now take them low
*/
OUTB(0, adapter->io_addr+PORT_CONTROL);
/*
* wait for a little bit
*/
for (timeout = jiffies + 20; jiffies <= timeout; )
;
/*
* now hang around until the board gets it's act together
*/
for (timeout = jiffies + (100 * 15); jiffies <= timeout; )
if (GET_ASF() != ASF_PCB_END)
break;
}
static void adapter_reset(elp_device * adapter)
{
int timeout;
cli();
OUTB(CONTROL_ATTN|INB(adapter->io_addr+PORT_CONTROL), adapter->io_addr+PORT_CONTROL);
sti();
/*
* wait for a little bit
*/
for (timeout = jiffies + 20; jiffies <= timeout; )
;
cli();
OUTB(INB(adapter->io_addr+PORT_CONTROL)&~(CONTROL_ATTN), adapter->io_addr+PORT_CONTROL);
sti();
}
/******************************************************
*
* queue a receive command on the adapter so we will get an
* interrupt when a packet is received.
*
******************************************************/
static int start_receive(elp_device * adapter, pcb_struct * tx_pcb)
{
if (elp_debug > 3)
printk("elp0: restarting receiver\n");
tx_pcb->command = CMD_RECEIVE_PACKET;
tx_pcb->length = 8;
tx_pcb->data[4] = 1600 & 0xff;
tx_pcb->data[5] = 1600 >> 8;
tx_pcb->data[6] = 0; /* set timeout to zero */
tx_pcb->data[7] = 0;
return send_pcb(adapter, tx_pcb);
}
/******************************************************
*
* extract a packet from the adapter
* this routine is only called from within the interrupt
* service routine, so no cli/sti calls are needed
* note that the length is always assumed to be even
*
******************************************************/
static void receive_packet(struct device * dev,
elp_device * adapter,
int len)
{
register int i;
unsigned short * ptr;
short d;
/*
* allocate a buffer to put the packet into.
*/
struct sk_buff *skb;
skb = alloc_skb(len+3, GFP_ATOMIC);
/*
* make sure the data register is going the right way
*/
OUTB(INB(adapter->io_addr+PORT_CONTROL)|CONTROL_DIR, adapter->io_addr+PORT_CONTROL);
/*
* if buffer could not be allocated, swallow it
*/
if (skb == NULL) {
for (i = 0; i < (len/2); i++) {
while ((INB(adapter->io_addr+PORT_STATUS)&STATUS_HRDY) == 0)
;
d = inw(adapter->io_addr+PORT_DATA);
}
adapter->stats.rx_dropped++;
} else {
/*
* now read the data from the adapter
*/
ptr = (unsigned short *)(skb->data);
for (i = 0; i < (len/2); i++) {
while ((INB(adapter->io_addr+PORT_STATUS)&STATUS_HRDY) == 0) {
;
}
*ptr = inw(adapter->io_addr+PORT_DATA);
ptr++;
}
/*
* the magic routine "dev_rint" passes the packet up the
* protocol chain. If it returns 0, we can assume the packet was
* swallowed up. If not, then we are responsible for freeing memory
*/
if (dev_rint((unsigned char *)skb, len, IN_SKBUFF, dev) != 0) {
printk("%s: receive buffers full.\n", dev->name);
kfree_skb(skb, FREE_READ);
}
}
OUTB(INB(adapter->io_addr+PORT_CONTROL)&(~CONTROL_DIR), adapter->io_addr+PORT_CONTROL);
}
/******************************************************
*
* interrupt handler
*
******************************************************/
static void elp_interrupt(int reg_ptr)
{
int len;
int dlen;
int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2);
struct device *dev;
elp_device * adapter;
if (irq < 0 || irq > 15) {
printk ("elp0: illegal IRQ number found in interrupt routine (%i)\n", irq);
return;
}
if (irq != 0xc) {
printk ("elp0: warning - interrupt routine has incorrect IRQ of %i\n", irq);
return;
}
dev = irq2dev_map[irq];
adapter = (elp_device *) dev->priv;
if (dev == NULL) {
printk ("elp_interrupt(): irq %d for unknown device.\n", irq);
return;
}
if (dev->interrupt)
if (elp_debug >= 3)
printk("%s: Re-entering the interrupt handler.\n", dev->name);
dev->interrupt = 1;
/*
* allow interrupts (we need timers!)
*/
sti();
/*
* receive a PCB from the adapter
*/
while ((INB(adapter->io_addr+PORT_STATUS)&STATUS_ACRF) != 0) {
if (receive_pcb(adapter, &adapter->irx_pcb)) {
switch (adapter->irx_pcb.command) {
/*
* 82586 configured correctly
*/
case CMD_CONFIGURE_82586_RESPONSE:
adapter->got_configure = 1;
if (elp_debug >= 3)
printk("%s: interrupt - configure response received\n", dev->name);
break;
/*
* received a packet
*/
case CMD_RECEIVE_PACKET_COMPLETE:
len = adapter->irx_pcb.data[6] + (adapter->irx_pcb.data[7] << 8);
dlen = adapter->irx_pcb.data[4] + (adapter->irx_pcb.data[5] << 8);
if (adapter->irx_pcb.data[8] != 0) {
printk("%s: interrupt - packet not received correctly\n", dev->name);
} else {
if (elp_debug >= 3)
printk("%s: interrupt - packet received of length %i (%i)\n", dev->name, len, dlen);
receive_packet(dev, adapter, dlen);
if (elp_debug >= 3)
printk("%s: packet received\n", dev->name);
adapter->stats.rx_packets++;
}
if (dev->start && !start_receive(adapter, &adapter->itx_pcb))
if (elp_debug >= 2)
printk("%s: interrupt - failed to send receive start PCB\n", dev->name);
if (elp_debug >= 3)
printk("%s: receive procedure complete\n", dev->name);
break;
/*
* sent a packet
*/
case CMD_TRANSMIT_PACKET_COMPLETE:
if (elp_debug >= 3)
printk("%s: interrupt - packet sent\n", dev->name);
if (adapter->irx_pcb.data[4] != 0)
if (elp_debug >= 2)
printk("%s: interrupt - error sending packet %4.4x\n", dev->name,
adapter->irx_pcb.data[4] + (adapter->irx_pcb.data[5] << 8));
dev->tbusy = 0;
mark_bh(INET_BH);
adapter->stats.tx_packets++;
break;
/*
* some unknown PCB
*/
default:
printk("%s: unknown PCB received - %2.2x\n", dev->name, adapter->irx_pcb.command);
break;
}
} else
printk("%s: failed to read PCB on interrupt\n", dev->name);
}
/*
* indicate no longer in interrupt routine
*/
dev->interrupt = 0;
}
/******************************************************
*
* open the board
*
******************************************************/
static int elp_open (struct device *dev)
{
elp_device * adapter = (elp_device *) dev->priv;
if (elp_debug >= 1)
printk("%s: request to open device\n", dev->name);
/*
* make sure we actually found the device
*/
if (adapter == NULL) {
printk("%s: Opening a non-existent physical device\n", dev->name);
return -EAGAIN;
}
/*
* interrupt routine not entered
*/
dev->interrupt = 0;
/*
* transmitter not busy
*/
dev->tbusy = 0;
/*
* install our interrupt service routine
*/
if (request_irq(dev->irq, &elp_interrupt))
return -EAGAIN;
/*
* make sure we can find the device header given the interrupt number
*/
irq2dev_map[dev->irq] = dev;
/*
* enable interrupts on the board
*/
OUTB(CONTROL_CMDE, adapter->io_addr+PORT_CONTROL);
/*
* device is now offically open!
*/
dev->start = 1;
/*
* configure adapter to receive broadcast messages and wait for response
*/
if (elp_debug >= 2)
printk("%s: sending 82586 configure command\n", dev->name);
adapter->tx_pcb.command = CMD_CONFIGURE_82586;
adapter->tx_pcb.data[0] = 1;
adapter->tx_pcb.data[1] = 0;
adapter->tx_pcb.length = 2;
adapter->got_configure = 0;
if (!send_pcb(adapter, &adapter->tx_pcb))
printk("%s: couldn't send 82586 configure command\n", dev->name);
else
while (adapter->got_configure == 0)
;
/*
* queue a receive command to start things rolling
*/
if (!start_receive(adapter, &adapter->tx_pcb))
printk("%s: start receive command failed \n", dev->name);
if (elp_debug >= 2)
printk("%s: start receive command sent\n", dev->name);
return 0; /* Always succeed */
}
/******************************************************
*
* close the board
*
******************************************************/
static int elp_close (struct device *dev)
{
elp_device * adapter = (elp_device *) dev->priv;
if (elp_debug >= 1)
printk("%s: request to close device\n", dev->name);
/*
* disable interrupts on the board
*/
OUTB(0x00, adapter->io_addr+PORT_CONTROL);
/*
* flag transmitter as busy (i.e. not available)
*/
dev->tbusy = 1;
/*
* indicate device is closed
*/
dev->start = 0;
/*
* release the IRQ
*/
free_irq(dev->irq);
/*
* and we no longer have to map irq to dev either
*/
irq2dev_map[dev->irq] = 0;
return 0;
}
/******************************************************
*
* send a packet to the adapter
*
******************************************************/
static int send_packet (elp_device * adapter, unsigned char * ptr, int len)
{
int i;
/*
* make sure the length is even and no shorter than 60 bytes
*/
unsigned int nlen = (((len < 60) ? 60 : len) + 1) & (~1);
/*
* send the adapter a transmit packet command. Ignore segment and offset
* and make sure the length is even
*/
adapter->tx_pcb.command = CMD_TRANSMIT_PACKET;
adapter->tx_pcb.length = 6;
adapter->tx_pcb.data[4] = nlen & 0xff;
adapter->tx_pcb.data[5] = nlen >> 8;
if (!send_pcb(adapter, &adapter->tx_pcb))
return FALSE;
/*
* make sure the data register is going the right way
*/
cli();
OUTB(INB(adapter->io_addr+PORT_CONTROL)&(~CONTROL_DIR), adapter->io_addr+PORT_CONTROL);
sti();
/*
* write data to the adapter
*/
for (i = 0; i < (nlen/2);i++) {
while ((INB(adapter->io_addr+PORT_STATUS)&STATUS_HRDY) == 0)
;
outw(*(short *)ptr, adapter->io_addr+PORT_DATA);
ptr +=2;
}
return TRUE;
}
/******************************************************
*
* start the transmitter
* return 0 if sent OK, else return 1
*
******************************************************/
static int elp_start_xmit(struct sk_buff *skb, struct device *dev)
{
elp_device * adapter = (elp_device *) dev->priv;
/*
* not sure what this does, but the 3c609 driver does it, so...
*/
if (skb == NULL) {
dev_tint(dev);
return 0;
}
/*
* if we ended up with a munged length, don't send it
*/
if (skb->len <= 0)
return 0;
if (elp_debug >= 1)
printk("%s: request to send packet of length %i\n", dev->name, skb->len);
/*
* if the transmitter is still busy, we have a transmit timeout...
*/
if (dev->tbusy) {
int tickssofar = jiffies - dev->trans_start;
if (tickssofar < 500)
return 1;
printk("%s: transmit timed out, resetting adapter\n", dev->name);
if ((INB(adapter->io_addr+PORT_STATUS)&STATUS_ACRF) != 0)
printk("%s: hmmm...seemed to have missed an interrupt!\n", dev->name);
adapter_reset(adapter);
dev->trans_start = jiffies;
dev->tbusy = 0;
}
/*
* send the packet at (void *)(skb+1) for skb->len
*/
if (!send_packet(adapter, (unsigned char *)(skb->data), skb->len)) {
printk("%s: send packet PCB failed\n", dev->name);
return 1;
}
if (elp_debug >= 2)
printk("%s: packet of length %i sent\n", dev->name, skb->len);
/*
* start the transmit timeout
*/
dev->trans_start = jiffies;
/*
* the transmitter is now busy
*/
dev->tbusy = 1;
/*
* if we have been asked to free the buffer, do so
*/
dev_kfree_skb(skb, FREE_WRITE);
return 0;
}
/******************************************************
*
* return statistics on the board
*
******************************************************/
static struct enet_statistics * elp_get_stats(struct device *dev)
{
if (elp_debug >= 1)
printk("%s: request for stats\n", dev->name);
elp_device * adapter = (elp_device *) dev->priv;
return &adapter->stats;
}
/******************************************************
*
* initialise Etherlink Pus board
*
******************************************************/
static void elp_init(struct device *dev)
{
int i;
elp_device * adapter;
/*
* NULL out buffer pointers
*/
for (i = 0; i < DEV_NUMBUFFS; i++)
dev->buffs[i] = NULL;
/*
* set ptrs to various functions
*/
dev->open = elp_open; /* local */
dev->stop = elp_close; /* local */
dev->get_stats = elp_get_stats; /* local */
dev->hard_start_xmit = elp_start_xmit; /* local */
dev->hard_header = eth_header; /* eth.c */
dev->add_arp = eth_add_arp; /* eth.c */
dev->rebuild_header = eth_rebuild_header; /* eth.c */
dev->type_trans = eth_type_trans; /* eth.c */
dev->queue_xmit = dev_queue_xmit; /* dev.c */
/*
* setup ptr to adapter specific information
*/
adapter = (elp_device *)(dev->priv = kmalloc(sizeof(elp_device), GFP_KERNEL));
adapter->io_addr = dev->base_addr;
memset(&(adapter->stats), 0, sizeof(struct enet_statistics));
/*
* Ethernet information
*/
dev->type = ARPHRD_ETHER;
dev->hard_header_len = ETH_HLEN;
dev->mtu = 1500; /* eth_mtu */
dev->addr_len = ETH_ALEN;
for (i = 0; i < dev->addr_len; i++)
dev->broadcast[i] = 0xff;
/*
* New-style flags.
*/
dev->flags = IFF_BROADCAST;
dev->family = AF_INET;
dev->pa_addr = 0;
dev->pa_brdaddr = 0;
dev->pa_mask = 0;
dev->pa_alen = sizeof(unsigned long);
/*
* memory information
*/
dev->mem_start = dev->mem_end = dev->rmem_end = dev->mem_start = 0;
}
/******************************************************
*
* probe for an Etherlink Plus board at the specified address
* by attempting to get the ethernet address.
*
******************************************************/
int elp_probe(struct device *dev)
{
elp_device adapter;
int i;
/*
* setup adapter structure
*/
adapter.io_addr = dev->base_addr;
printk ("%s: probing for 3c505...", dev->name);
/*
* get the adapter's undivided attention (if it's there!)
*/
adapter_hard_reset(&adapter);
/*
* use ethernet address command to probe for board in polled mode
*/
adapter.tx_pcb.command = CMD_STATION_ADDRESS;
adapter.tx_pcb.length = 0;
if (!send_pcb (&adapter, &adapter.tx_pcb) ||
!receive_pcb(&adapter, &adapter.rx_pcb) ||
(adapter.rx_pcb.command != CMD_ADDRESS_RESPONSE) ||
(adapter.rx_pcb.length != 6)) {
printk("not found\n");
return -ENODEV;
}
for (i = 0; i < 6; i++)
dev->dev_addr[i] = adapter.rx_pcb.data[i];
printk("found at port 0x%x, address = %s\n", dev->base_addr, eth_print(dev->dev_addr));
elp_init(dev);
return 0;
}
/*****************************************************************
*
* defines for 3Com Etherlink Plus adapter
*
*****************************************************************/
/*
* I/O register offsets
*/
#define PORT_COMMAND 0x00 /* read/write */
#define PORT_STATUS 0x02 /* read only */
#define PORT_AUXDMA 0x02 /* write only */
#define PORT_DATA 0x04 /* read/write */
#define PORT_CONTROL 0x06 /* read/write */
/*
* host control registers bits
*/
#define CONTROL_ATTN 0x80 /* attention */
#define CONTROL_FLSH 0x40 /* flush data register */
#define CONTROL_DMAE 0x20 /* DMA enable */
#define CONTROL_DIR 0x10 /* direction */
#define CONTROL_TCEN 0x08 /* terminal count interrupt enable */
#define CONTROL_CMDE 0x04 /* command register interrupt enable */
#define CONTROL_HSF2 0x02 /* host status flag 2 */
#define CONTROL_HSF1 0x01 /* host status flag 1 */
/*
* combinations of HSF flags used for PCB transmission
*/
#define HSF_PCB_ACK (CONTROL_HSF1)
#define HSF_PCB_NAK (CONTROL_HSF2)
#define HSF_PCB_END (CONTROL_HSF2|CONTROL_HSF1)
#define HSF_PCB_MASK (CONTROL_HSF2|CONTROL_HSF1)
/*
* host status register bits
*/
#define STATUS_HRDY 0x80 /* data register ready */
#define STATUS_HCRE 0x40 /* command register empty */
#define STATUS_ACRF 0x20 /* adapter command register full */
#define STATUS_DIR 0x10 /* direction */
#define STATUS_DONE 0x08 /* DMA done */
#define STATUS_ASF3 0x04 /* adapter status flag 3 */
#define STATUS_ASF2 0x02 /* adapter status flag 2 */
#define STATUS_ASF1 0x01 /* adapter status flag 1 */
/*
* combinations of ASF flags used for PCB reception
*/
#define ASF_PCB_ACK (STATUS_ASF1)
#define ASF_PCB_NAK (STATUS_ASF2)
#define ASF_PCB_END (STATUS_ASF2|STATUS_ASF1)
#define ASF_PCB_MASK (STATUS_ASF2|STATUS_ASF1)
/*
* host aux DMA register bits
*/
#define AUXDMA_BRST 0x01 /* DMA burst */
/*
* maximum amount of data 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 10000
/*****************************************************************
*
* 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,
/*
* 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
};
......@@ -94,7 +94,9 @@ int el3_probe(struct device *dev)
/* First check for a board on the EISA bus. */
if (EISA_bus) {
for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) {
static int eisa_addr;
for (ioaddr=0x1000 ; ioaddr < 0x9000; ioaddr += 0x1000) {
eisa_addr = ioaddr;
/* Check the standard EISA ID register for an encoded '3Com'. */
if (inw(ioaddr + 0xC80) != 0x6d50)
continue;
......
/* ac3200.c: A driver for the Ansel Communications EISA ethernet adaptor. */
/*
Written 1993, 1994 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 Public License as modified by SRC,
incorporated herein by reference.
The author may be reached as becker@cesdis.gsfc.nasa.gov, or
C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
This is driver for the Ansel Communications Model 3200 EISA Ethernet LAN
Adapter. The programming information is from the users manual, as related
by glee@ardnassak.math.clemson.edu.
*/
static char *version =
"ac3200.c:v0.03 2/6/94 Donald Becker (becker@super.org)\n";
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <asm/system.h>
#include <asm/io.h>
#include <linux/netdevice.h>
#include "8390.h"
/* Offsets from the base address. */
#define AC_NIC_BASE 0x00
#define AC_SA_PROM 0x16 /* The station address PROM. */
#define AC_ADDR0 0x00 /* Prefix station address values. */
#define AC_ADDR1 0x40 /* !!!!These are just guesses!!!! */
#define AC_ADDR2 0x90
#define AC_ID_PORT 0xC80
#define AC_EISA_ID 0x0110d305
#define AC_RESET_PORT 0xC84
#define AC_RESET 0x00
#define AC_ENABLE 0x01
#define AC_CONFIG 0xC90 /* The configuration port. */
/* Decoding of the configuration register. */
static unsigned char config2irqmap[8] = {15, 12, 11, 10, 9, 7, 5, 3};
static int addrmap[8] =
{0xFF0000, 0xFE0000, 0xFD0000, 0xFFF0000, 0xFFE0000, 0xFFC0000, 0xD0000, 0 };
static char *port_name[4] = { "10baseT", "invalid", "AUI", "10base2"};
#define config2irq(configval) config2irqmap[((configval) >> 3) & 7]
#define config2mem(configval) addrmap[(configval) & 7]
#define config2name(configval) port_name[((configval) >> 6) & 3]
/* First and last 8390 pages. */
#define AC_START_PG 0x00 /* First page of 8390 TX buffer */
#define AC_STOP_PG 0x80 /* Last page +1 of the 8390 RX ring */
int ac3200_probe(struct device *dev);
static int ac_probe1(int ioaddr, struct device *dev);
static int ac_open(struct device *dev);
static void ac_reset_8390(struct device *dev);
static int ac_block_input(struct device *dev, int count,
char *buf, int ring_offset);
static void ac_block_output(struct device *dev, const int count,
const unsigned char *buf, const int start_page);
static int ac_close_card(struct device *dev);
/* Probe for the AC3200.
The AC3200 can be identified by either the EISA configuration registers,
or the unique value in the station address PROM.
*/
int ac3200_probe(struct device *dev)
{
unsigned short ioaddr = dev->base_addr;
if (ioaddr > 0x1ff) /* Check a single specified location. */
return ac_probe1(ioaddr, dev);
else if (ioaddr > 0) /* Don't probe at all. */
return ENXIO;
/* If you have a pre-pl15 machine you should delete this line. */
if ( ! EISA_bus)
return ENXIO;
for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000)
if (ac_probe1(ioaddr, dev) == 0)
return 0;
return ENODEV;
}
static int ac_probe1(int ioaddr, struct device *dev)
{
int i;
#ifndef final_version
printk("AC3200 ethercard probe at %#3x:", ioaddr);
for(i = 0; i < 6; i++)
printk(" %02x", inb(ioaddr + AC_SA_PROM + i));
#endif
/* !!!!The values of AC_ADDRn (see above) should be corrected when we
find out the correct station address prefix!!!! */
if (inb(ioaddr + AC_SA_PROM + 0) != AC_ADDR0
|| inb(ioaddr + AC_SA_PROM + 1) != AC_ADDR1
|| inb(ioaddr + AC_SA_PROM + 2) != AC_ADDR2 ) {
#ifndef final_version
printk(" not found (invalid prefix).\n");
#endif
return ENODEV;
}
/* The correct probe method is to check the EISA ID. */
for (i = 0; i < 4; i++)
if (inl(ioaddr + AC_ID_PORT) != AC_EISA_ID) {
printk("EISA ID mismatch, %8x vs %8x.\n",
inl(ioaddr + AC_EISA_ID), AC_EISA_ID);
return ENODEV;
}
for(i = 0; i < ETHER_ADDR_LEN; i++)
dev->dev_addr[i] = inb(ioaddr + AC_SA_PROM + i);
#ifndef final_version
printk("\nAC3200 ethercard configuration register is %#02x,"
" EISA ID %02x %02x %02x %02x.\n", inb(ioaddr + AC_CONFIG),
inb(ioaddr + AC_ID_PORT + 0), inb(ioaddr + AC_ID_PORT + 1),
inb(ioaddr + AC_ID_PORT + 2), inb(ioaddr + AC_ID_PORT + 3));
#endif
/* Assign and snarf the interrupt now. */
if (dev->irq == 0)
dev->irq = config2irq(inb(ioaddr + AC_CONFIG));
else if (dev->irq == 2)
dev->irq = 9;
if (irqaction (dev->irq, &ei_sigaction)) {
printk (" unable to get IRQ %d.\n", dev->irq);
return 0;
}
dev->base_addr = ioaddr;
#ifdef notyet
if (dev->mem_start) { /* Override the value from the board. */
for (i = 0; i < 7; i++)
if (addrmap[i] == dev->mem_start)
break;
if (i >= 7)
i = 0;
outb((inb(ioaddr + AC_CONFIG) & ~7) | i, ioaddr + AC_CONFIG);
}
#endif
dev->if_port = inb(ioaddr + AC_CONFIG) >> 6;
dev->mem_start = config2mem(inb(ioaddr + AC_CONFIG));
dev->rmem_start = dev->mem_start + TX_PAGES*256;
dev->mem_end = dev->rmem_end = dev->mem_start
+ (AC_STOP_PG - AC_START_PG)*256;
ethdev_init(dev);
ei_status.name = "AC3200";
ei_status.tx_start_page = AC_START_PG;
ei_status.rx_start_page = AC_START_PG + TX_PAGES;
ei_status.stop_page = AC_STOP_PG;
ei_status.word16 = 1;
printk("\n%s: AC3200 at %#x, IRQ %d, %s port, shared memory at %#x-%#x.\n",
dev->name, ioaddr, dev->irq, port_name[dev->if_port],
dev->mem_start, dev->mem_end-1);
if (ei_debug > 0)
printk(version);
ei_status.reset_8390 = &ac_reset_8390;
ei_status.block_input = &ac_block_input;
ei_status.block_output = &ac_block_output;
dev->open = &ac_open;
dev->stop = &ac_close_card;
NS8390_init(dev, 0);
return 0;
}
static int ac_open(struct device *dev)
{
#ifdef notyet
/* Someday we may enable the IRQ and shared memory here. */
int ioaddr = dev->base_addr;
if (irqaction(dev->irq, &ei_sigaction))
return -EAGAIN;
#endif
return ei_open(dev);
}
static void ac_reset_8390(struct device *dev)
{
ushort ioaddr = dev->base_addr;
outb(AC_RESET, ioaddr + AC_RESET_PORT);
if (ei_debug > 1) printk("resetting AC3200, t=%d...", jiffies);
ei_status.txing = 0;
outb(AC_ENABLE, ioaddr + AC_RESET_PORT);
if (ei_debug > 1) printk("reset done\n");
return;
}
/* Block input and output are easy on shared memory ethercards, the only
complication is when the ring buffer wraps. */
static int ac_block_input(struct device *dev, int count, char *buf,
int ring_offset)
{
long xfer_start = dev->mem_start + ring_offset - (AC_START_PG<<8);
if (xfer_start + count > dev->rmem_end) {
/* We must wrap the input move. */
int semi_count = dev->rmem_end - xfer_start;
memcpy(buf, (char*)xfer_start, semi_count);
count -= semi_count;
memcpy(buf + semi_count, (char *)dev->rmem_start, count);
return dev->rmem_start + count;
}
memcpy(buf, (char*)xfer_start, count);
return ring_offset + count;
}
static void ac_block_output(struct device *dev, int count,
const unsigned char *buf, int start_page)
{
long shmem = dev->mem_start + ((start_page - AC_START_PG)<<8);
memcpy((unsigned char *)shmem, buf, count);
}
static int ac_close_card(struct device *dev)
{
dev->start = 0;
dev->tbusy = 1;
if (ei_debug > 1)
printk("%s: Shutting down ethercard.\n", dev->name);
#ifdef notyet
/* We should someday disable shared memory and interrupts. */
outb(0x00, ioaddr + 6); /* Disable interrupts. */
free_irq(dev->irq);
irq2dev_map[dev->irq] = 0;
#endif
NS8390_init(dev, 0);
return 0;
}
/*
* Local variables:
* compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c ac3200.c"
* version-control: t
* kept-new-versions: 5
* tab-width: 4
* End:
*/
......@@ -21,15 +21,17 @@
DE201 Turbo
DE202 Turbo (TP BNC)
DE210
DE422 (EISA)
The driver has been tested on DE100, DE200 and DE202 cards in a
relatively busy network.
relatively busy network. The DE422 has been tested a little.
This driver will not work for the DE203, DE204 and DE205 series of
cards, since they have a new custom ASIC in place of the AMD LANCE chip.
This driver will NOT work for the DE203, DE204 and DE205 series of
cards, since they have a new custom ASIC in place of the AMD LANCE
chip.
The author may be reached as davies@wanton.lkg.dec.com or
Digital Equipment Corporation, 146 Main Street, Maynard MA 01754.
Digital Equipment Corporation, 550 King Street, Littleton MA 01460.
=========================================================================
The driver was based on the 'lance.c' driver from Donald Becker which is
......@@ -63,10 +65,11 @@
be enabled to count and has an 8 bit NICSR. The ROM counter enabling is
only done when a 0x08 is read as the first address octet (to minimise
the chances of writing over some other hardware's I/O register). The
size of the NICSR is tested by a word read: if both bytes are the same,
the register is 8 bits wide. Also, there is a maximum of only 48kB
network RAM for this card. My thanks to Torbjorn Lindh for help
debugging all this (and holding my feet to the fire until I got it
NICSR accesses have been changed to byte accesses for all the cards
supported by this driver, since there is only one useful bit in the MSB
(remote boot timeout) and it is not used. Also, there is a maximum of
only 48kB network RAM for this card. My thanks to Torbjorn Lindh for
help debugging all this (and holding my feet to the fire until I got it
right).
The DE200 series boards have on-board 64kB RAM for use as a shared
......@@ -74,22 +77,26 @@
mode which has not been implemented in this driver (only the 32kB and
64kB modes are supported [16kB/48kB for the original DEPCA]).
At the most only 2 DEPCA cards can be supported because there is only
provision for two I/O base addresses on the cards (0x300 and 0x200). The
base address is 'autoprobed' by looking for the self test PROM and
detecting the card name. The shared memory base address is decoded by
'autoprobing' the Ethernet PROM address information. The second DEPCA is
detected and information placed in the base_addr variable of the next
device structure (which is created if necessary), thus enabling
ethif_probe initialization for the device.
At the most only 2 DEPCA cards can be supported on the ISA bus because
there is only provision for two I/O base addresses on each card (0x300
and 0x200). The I/O address is detected by searching for a byte sequence
in the Ethernet station address PROM at the expected I/O address for the
Ethernet PROM. The shared memory base address is 'autoprobed' by
looking for the self test PROM and detecting the card name. When a
second DEPCA is detected, information is placed in the base_addr
variable of the next device structure (which is created if necessary),
thus enabling ethif_probe initialization for the device. More than 2
EISA cards can be supported, but care will be needed assigning the
shared memory to ensure that each slot has the correct IRQ, I/O address
and shared memory address assigned.
************************************************************************
NOTE: If you are using two DEPCAs, it is important that you assign the
base memory addresses correctly. The driver autoprobes I/O 0x300 then
0x200. The base memory address for the first device must be less than
that of the second so that the auto probe will correctly assign the I/O
and memory addresses on the same card. I can't think of a way to do
NOTE: If you are using two ISA DEPCAs, it is important that you assign
the base memory addresses correctly. The driver autoprobes I/O 0x300
then 0x200. The base memory address for the first device must be less
than that of the second so that the auto probe will correctly assign the
I/O and memory addresses on the same card. I can't think of a way to do
this unambiguously at the moment, since there is nothing on the cards to
tie I/O and memory information together.
......@@ -126,12 +133,14 @@
Add jabber packet fix from murf@perftech.com
and becker@super.org
0.34 7-mar-94 Fix DEPCA max network memory RAM & NICSR access.
0.35 8-mar-94 Added DE201 recognition.
0.35 8-mar-94 Added DE201 recognition. Tidied up.
0.351 30-apr-94 Added EISA support. Added DE422 recognition.
0.36 16-may-94 DE422 fix released.
=========================================================================
*/
static char *version = "depca.c:v0.35 3/8/94 davies@wanton.lkg.dec.com\n";
static char *version = "depca.c:v0.36 5/16/94 davies@wanton.lkg.dec.com\n";
#include <stdarg.h>
#include <linux/config.h>
......@@ -148,7 +157,6 @@ static char *version = "depca.c:v0.35 3/8/94 davies@wanton.lkg.dec.com\n";
#include <asm/dma.h>
#include <linux/netdevice.h>
#include "iow.h" /* left in for pl13/14 compatibility... */
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include "depca.h"
......@@ -159,11 +167,6 @@ int depca_debug = DEPCA_DEBUG;
int depca_debug = 1;
#endif
#ifndef DEPCA_IRQ
/*#define DEPCA_IRQ {5,9,10,11,15,0}*/
#define DEPCA_IRQ 5
#endif
#ifndef PROBE_LENGTH
#define PROBE_LENGTH 32
#endif
......@@ -173,7 +176,10 @@ int depca_debug = 1;
#endif
#ifndef DEPCA_SIGNATURE
#define DEPCA_SIGNATURE {"DEPCA","DE100","DE200","DE201","DE202","DE210",""}
#define DEPCA_SIGNATURE {"DEPCA","DE100",\
"DE200","DE201","DE202","DE210",\
"DE422",\
""}
#define DEPCA_NAME_LENGTH 8
#endif
......@@ -195,6 +201,14 @@ static short mem_chkd = 0; /* holds which base addrs have been */
#define MAX_NUM_DEPCAS 2
#endif
#ifndef DEPCA_EISA_IO_PORTS
#define DEPCA_EISA_IO_PORTS 0x0c00 /* I/O port base address, slot 0 */
#endif
#ifndef MAX_EISA_SLOTS
#define MAX_EISA_SLOTS 8
#endif
/*
** Set the number of Tx and Rx buffers.
*/
......@@ -230,8 +244,8 @@ struct depca_tx_head {
short misc; /* Errors and TDR info */
};
struct depca_ring_info {
};
#define LA_MASK 0x0000ffff /* LANCE address mask for mapping network RAM
to LANCE memory address space */
/*
** The Lance initialization block, described in databook, in common memory.
......@@ -249,6 +263,7 @@ struct depca_private {
struct depca_rx_head *rx_ring; /* Pointer to start of RX descriptor ring */
struct depca_tx_head *tx_ring; /* Pointer to start of TX descriptor ring */
struct depca_init init_block;/* Initialization block */
long bus_offset; /* (E)ISA bus address offset vs LANCE */
long dma_buffs; /* Start address of Rx and Tx buffers. */
int cur_rx, cur_tx; /* The next free ring entry */
int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */
......@@ -287,8 +302,10 @@ static int DevicePresent(short ioaddr);
#ifdef HAVE_MULTICAST
static void SetMulticastFilter(int num_addrs, char *addrs, char *multicast_table);
#endif
static struct device *isa_probe(struct device *dev);
static struct device *eisa_probe(struct device *dev);
static struct device *alloc_device(struct device *dev, int ioaddr);
static int depca_na;
static int num_depcas = 0, num_eth = 0;;
/*
......@@ -298,32 +315,16 @@ static int num_depcas = 0, num_eth = 0;;
outw(CSR0, DEPCA_ADDR);\
outw(STOP, DEPCA_DATA)
#define GET_NICSR(a,b) \
if (depca_na) { \
(a) = inw((b)); \
} else { \
(a) = inb((b)); \
}
#define PUT_NICSR(a,b) \
if (depca_na) { \
outw((a), (b)); \
} else { \
outb((a), (b)); \
}
int depca_probe(struct device *dev)
{
int *port, ports[] = DEPCA_IO_PORTS;
int base_addr = dev->base_addr;
int status;
struct device *eth0 = (struct device *) NULL;
int status = -ENODEV;
struct device *eth0;
if (base_addr > 0x1ff) { /* Check a single specified location. */
status = -ENODEV;
if (DevicePresent(base_addr) == 0) { /* Is DEPCA really here? */
status = depca_probe1(dev, base_addr);
}
......@@ -331,63 +332,9 @@ int depca_probe(struct device *dev)
status = -ENXIO;
} else { /* First probe for the DEPCA test */
/* pattern in ROM */
for (status = -ENODEV, port = &ports[0];
*port && (num_depcas < MAX_NUM_DEPCAS); port++) {
int ioaddr = *port;
#ifdef HAVE_PORTRESERVE
if (check_region(ioaddr, DEPCA_TOTAL_SIZE))
continue;
#endif
if (DevicePresent(ioaddr) == 0) {
if (num_depcas > 0) { /* only gets here in autoprobe */
/*
** Check the device structures for an end of list or unused device
*/
while (dev->next != (struct device *)NULL) {
if (dev->next->base_addr == 0xffe0) break;
dev = dev->next; /* walk through eth device list */
num_eth++; /* increment eth device number */
}
/*
** If no more device structures, malloc one up. If memory could
** not be allocated, print an error message.
**
*/
if (dev->next == (struct device *)NULL) {
dev->next = (struct device *)kmalloc(sizeof(struct device) + 8,
GFP_KERNEL);
} else {
printk("eth%d: Device not initialised, insufficient memory\n",
num_eth);
}
/*
** If the memory was allocated, point to the new memory area
** and initialize it (name, I/O address, next device (NULL) and
** initialisation probe routine).
*/
if ((dev->next != (struct device *)NULL) &&
(num_eth > 0) && (num_eth < 9999)) {
dev = dev->next; /* point to the new device */
dev->name = (char *)(dev + sizeof(struct device));
sprintf(dev->name,"eth%d", num_eth); /* New device name */
dev->base_addr = ioaddr; /* assign the io address */
dev->next = (struct device *)NULL; /* mark the end of list */
dev->init = &depca_probe;/* initialisation routine */
}
} else {
eth0 = dev; /* remember the first device */
status = depca_probe1(dev, ioaddr);
}
num_depcas++;
num_eth++;
}
}
if (eth0) dev = eth0; /* restore the first device */
eth0=isa_probe(dev);
eth0=eisa_probe(eth0);
if (dev->priv) status=0;
}
if (status) dev->base_addr = base_addr;
......@@ -406,14 +353,13 @@ depca_probe1(struct device *dev, short ioaddr)
/*
** Stop the DEPCA. Enable the DBR ROM and the ethernet ROM address counter
** (for the really old DEPCAs). Disable interrupts and remote boot.
** Stop the DEPCA. Enable the DBR ROM. Disable interrupts and remote boot.
*/
STOP_DEPCA;
GET_NICSR(nicsr, DEPCA_NICSR);
nicsr = ((nicsr & ~SHE & ~RBE & ~IEN) | AAC | IM);
PUT_NICSR(nicsr, DEPCA_NICSR);
nicsr = inb(DEPCA_NICSR);
nicsr = ((nicsr & ~SHE & ~RBE & ~IEN) | IM);
outb(nicsr, DEPCA_NICSR);
if (inw(DEPCA_DATA) == STOP) {
......@@ -440,7 +386,12 @@ depca_probe1(struct device *dev, short ioaddr)
mem_start = mem_base[i];
dev->base_addr = ioaddr;
printk("%s: DEPCA at %#3x is a %s, ", dev->name, ioaddr, name);
if ((ioaddr&0x0fff)==DEPCA_EISA_IO_PORTS) {/* EISA slot address */
printk("%s: %s at %#3x (EISA slot %d)",
dev->name, name, ioaddr, ((ioaddr>>12)&0x0f));
} else { /* ISA port address */
printk("%s: %s at %#3x", dev->name, name, ioaddr);
}
/* There is a 32 byte station address PROM at DEPCA_PROM address.
The first six bytes are the station address. They can be read
......@@ -457,7 +408,7 @@ depca_probe1(struct device *dev, short ioaddr)
j = 0;
}
printk("ethernet address ");
printk(", h/w address ");
for (i = 0; i < ETH_ALEN - 1; i++) { /* get the ethernet address */
printk("%2.2x:", dev->dev_addr[i] = inb(DEPCA_PROM + j));
}
......@@ -488,20 +439,25 @@ depca_probe1(struct device *dev, short ioaddr)
if (nicsr & BUF) {
offset = 0x8000; /* 32kbyte RAM offset*/
nicsr &= ~BS; /* DEPCA RAM in top 32k */
printk(",\n with %dkB RAM", netRAM-(offset >> 10));
printk(",\n has %dkB RAM", netRAM - 32);
} else if ((nicsr & _128KB) && (netRAM!=48)) {
offset = 0x0000;
printk(",\n has 128kB RAM");
} else {
offset = 0x0000; /* 64k/48k bytes RAM */
printk(",\n with %dkB RAM", netRAM);
printk(",\n has %dkB RAM", netRAM);
}
mem_start += offset;
printk(" starting at 0x%.5lx", mem_start);
mem_start += offset; /* (E)ISA start address */
printk(" at 0x%.5lx", mem_start);
/*
** Enable the shadow RAM.
*/
if (strstr(name,"DEPCA")==(char *)NULL) {
nicsr |= SHE;
PUT_NICSR(nicsr, DEPCA_NICSR);
outb(nicsr, DEPCA_NICSR);
}
/*
** Calculate the ring size based on the available RAM
......@@ -551,12 +507,15 @@ depca_probe1(struct device *dev, short ioaddr)
lp->tx_ring = (struct depca_tx_head *)mem_start;
mem_start += (sizeof(struct depca_tx_head) * j);
lp->dma_buffs = mem_start & 0x00ffffff;
lp->bus_offset = mem_start & 0x00ff0000;
mem_start &= LA_MASK; /* LANCE re-mapped start address */
lp->dma_buffs = mem_start;
mem_start += (PKT_BUF_SZ * j);
/* (mem_start now points to the start of the Tx buffers) */
/* Initialise the data structures */
/* Initialise the data structures wrt CPU */
memset(lp->rx_ring, 0, sizeof(struct depca_rx_head)*j);
memset(lp->tx_ring, 0, sizeof(struct depca_tx_head)*j);
......@@ -592,16 +551,11 @@ depca_probe1(struct device *dev, short ioaddr)
*/
LoadCSRs(dev);
/*
** Store the NICSR width for this DEPCA
*/
lp->depca_na = depca_na;
/*
** Enable DEPCA board interrupts for autoprobing
*/
nicsr = ((nicsr & ~IM)|IEN);
PUT_NICSR(nicsr, DEPCA_NICSR);
outb(nicsr, DEPCA_NICSR);
/* The DMA channel may be passed in on this parameter. */
dev->dma = 0;
......@@ -616,13 +570,13 @@ depca_probe1(struct device *dev, short ioaddr)
dev->irq = autoirq_report(1);
if (dev->irq) {
printk(" and probed IRQ%d.\n", dev->irq);
printk(" and uses IRQ%d.\n", dev->irq);
} else {
printk(". Failed to detect IRQ line.\n");
printk(" and failed to detect IRQ line.\n");
status = -EAGAIN;
}
} else {
printk(". Assigned IRQ%d.\n", dev->irq);
printk(" and assigned IRQ%d.\n", dev->irq);
}
} else {
status = -ENXIO;
......@@ -670,9 +624,8 @@ depca_open(struct device *dev)
/*
** Stop the DEPCA & get the board status information.
*/
depca_na=lp->depca_na;
STOP_DEPCA;
GET_NICSR(nicsr, DEPCA_NICSR);
nicsr = inb(DEPCA_NICSR);
/*
** Re-initialize the DEPCA...
......@@ -723,7 +676,7 @@ depca_open(struct device *dev)
** Enable DEPCA board interrupts
*/
nicsr = ((nicsr & ~IM & ~LED)|SHE|IEN);
PUT_NICSR(nicsr, DEPCA_NICSR);
outb(nicsr, DEPCA_NICSR);
outw(CSR0,DEPCA_ADDR);
dev->tbusy = 0;
......@@ -734,8 +687,7 @@ depca_open(struct device *dev)
if (depca_debug > 1){
printk("CSR0: 0x%4.4x\n",inw(DEPCA_DATA));
GET_NICSR(nicsr, DEPCA_NICSR);
printk("nicsr: 0x%4.4x\n",nicsr);
printk("nicsr: 0x%02x\n",inb(DEPCA_NICSR));
}
return 0; /* Always succeed */
......@@ -767,8 +719,8 @@ depca_init_ring(struct device *dev)
for (i = 0; i < 4; i++) {
lp->init_block.filter[i] = 0x0000;
}
lp->init_block.rx_ring = (unsigned long)lp->rx_ring | lp->rlen;
lp->init_block.tx_ring = (unsigned long)lp->tx_ring | lp->rlen;
lp->init_block.rx_ring = ((unsigned long)lp->rx_ring & LA_MASK) | lp->rlen;
lp->init_block.tx_ring = ((unsigned long)lp->tx_ring & LA_MASK) | lp->rlen;
lp->init_block.mode = 0x0000; /* Enable the Tx and Rx */
}
......@@ -789,10 +741,10 @@ depca_start_xmit(struct sk_buff *skb, struct device *dev)
if (tickssofar < 10) {
status = -1;
} else {
STOP_DEPCA;
printk("%s: transmit timed out, status %4.4x, resetting.\n",
printk("%s: transmit timed out, status %04x, resetting.\n",
dev->name, inw(DEPCA_DATA));
STOP_DEPCA;
depca_init_ring(dev);
LoadCSRs(dev);
InitRestartDepca(dev);
......@@ -835,7 +787,8 @@ depca_start_xmit(struct sk_buff *skb, struct device *dev)
char *p = (char *) skb->data;
entry &= lp->rmask; /* Ring around buffer number. */
buf = (unsigned char *)(lp->tx_ring[entry].base & 0x00ffffff);
buf = (unsigned char *)((lp->tx_ring[entry].base+lp->bus_offset) &
0x00ffffff);
/* Wait for a full ring to free up */
while (lp->tx_ring[entry].base < 0);
......@@ -870,7 +823,8 @@ depca_start_xmit(struct sk_buff *skb, struct device *dev)
/* Get new buffer pointer */
entry = lp->cur_tx++;
entry &= lp->rmask; /* Ring around buffer number. */
buf = (unsigned char *)(lp->tx_ring[entry].base & 0x00ffffff);
buf = (unsigned char *)((lp->tx_ring[entry].base+lp->bus_offset) &
0x00ffffff);
/* Wait for a full ring to free up */
while (lp->tx_ring[entry].base < 0);
......@@ -898,7 +852,8 @@ depca_start_xmit(struct sk_buff *skb, struct device *dev)
if (depca_debug > 4) {
unsigned char *pkt =
(unsigned char *)(lp->tx_ring[entry].base & 0x00ffffff);
(unsigned char *)((lp->tx_ring[entry].base+lp->bus_offset) &
0x00ffffff);
printk("%s: tx ring[%d], %#lx, sk_buf %#lx len %d.\n",
dev->name, entry, (unsigned long) &lp->tx_ring[entry],
......@@ -933,12 +888,9 @@ depca_interrupt(int reg_ptr)
if (dev == NULL) {
printk ("depca_interrupt(): irq %d for unknown device.\n", irq);
return;
} else {
lp = (struct depca_private *)dev->priv;
ioaddr = dev->base_addr;
depca_na = lp->depca_na;
}
if (dev->interrupt)
printk("%s: Re-entering the interrupt handler.\n", dev->name);
......@@ -946,9 +898,9 @@ depca_interrupt(int reg_ptr)
dev->interrupt = MASK_INTERRUPTS;
/* mask the DEPCA board interrupts and turn on the LED */
GET_NICSR(nicsr, DEPCA_NICSR);
nicsr = inb(DEPCA_NICSR);
nicsr |= (IM|LED);
PUT_NICSR(nicsr, DEPCA_NICSR);
outb(nicsr, DEPCA_NICSR);
outw(CSR0, DEPCA_ADDR);
csr0 = inw(DEPCA_DATA);
......@@ -978,9 +930,10 @@ depca_interrupt(int reg_ptr)
/* Unmask the DEPCA board interrupts and turn off the LED */
nicsr = (nicsr & ~IM & ~LED);
PUT_NICSR(nicsr, DEPCA_NICSR);
outb(nicsr, DEPCA_NICSR);
dev->interrupt = UNMASK_INTERRUPTS;
}
return;
}
......@@ -1036,7 +989,8 @@ depca_rx(struct device *dev)
skb->len = pkt_len;
skb->dev = dev;
memcpy(skb->data,
(unsigned char *)(lp->rx_ring[entry].base & 0x00ffffff),
(unsigned char *)((lp->rx_ring[entry].base+lp->bus_offset) &
0x00ffffff),
pkt_len);
/*
** Notify the upper protocol layers that there is another
......@@ -1146,9 +1100,11 @@ static void LoadCSRs(struct device *dev)
int ioaddr = dev->base_addr;
outw(CSR1, DEPCA_ADDR); /* initialisation block address LSW */
outw((unsigned short)(unsigned long)&lp->init_block, DEPCA_DATA);
outw((unsigned short)((unsigned long)(&lp->init_block) & LA_MASK),
DEPCA_DATA);
outw(CSR2, DEPCA_ADDR); /* initialisation block address MSW */
outw((unsigned short)((unsigned long)&lp->init_block >> 16), DEPCA_DATA);
outw((unsigned short)(((unsigned long)(&lp->init_block) & LA_MASK) >> 16),
DEPCA_DATA);
outw(CSR3, DEPCA_ADDR); /* ALE control */
outw(ACON, DEPCA_DATA);
outw(CSR0, DEPCA_ADDR); /* point back to CSR0 */
......@@ -1273,6 +1229,118 @@ static void SetMulticastFilter(int num_addrs, char *addrs, char *multicast_table
#endif /* HAVE_MULTICAST */
/*
** ISA bus I/O device probe
*/
static struct device *isa_probe(dev)
struct device *dev;
{
int *port, ports[] = DEPCA_IO_PORTS;
int status;
for (status = -ENODEV, port = &ports[0];
*port && (num_depcas < MAX_NUM_DEPCAS); port++) {
int ioaddr = *port;
#ifdef HAVE_PORTRESERVE
if (check_region(ioaddr, DEPCA_TOTAL_SIZE))
continue;
#endif
if (DevicePresent(ioaddr) == 0) {
if (num_depcas > 0) { /* only gets here in autoprobe */
dev = alloc_device(dev, ioaddr);
} else {
if ((status = depca_probe1(dev, ioaddr)) == 0) {
num_depcas++;
}
}
num_eth++;
}
}
return dev;
}
/*
** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually
** the motherboard.
*/
static struct device *eisa_probe(dev)
struct device *dev;
{
int i, ioaddr = DEPCA_EISA_IO_PORTS;
int status;
ioaddr+=0x1000; /* get the first slot address */
for (status = -ENODEV, i=1; i<MAX_EISA_SLOTS; i++, ioaddr+=0x1000) {
#ifdef HAVE_PORTRESERVE
if (check_region(ioaddr, DEPCA_TOTAL_SIZE))
continue;
#endif
if (DevicePresent(ioaddr) == 0) {
if (num_depcas > 0) { /* only gets here in autoprobe */
dev = alloc_device(dev, ioaddr);
} else {
if ((status = depca_probe1(dev, ioaddr)) == 0) {
num_depcas++;
}
}
num_eth++;
}
}
return dev;
}
/*
** Allocate the device by pointing to the next available space in the
** device structure. Should one not be available, it is created.
*/
static struct device *alloc_device(dev, ioaddr)
struct device *dev;
int ioaddr;
{
/*
** Check the device structures for an end of list or unused device
*/
while (dev->next != (struct device *)NULL) {
if (dev->next->base_addr == 0xffe0) break;
dev = dev->next; /* walk through eth device list */
num_eth++; /* increment eth device number */
}
/*
** If no more device structures, malloc one up. If memory could
** not be allocated, print an error message.
*/
if (dev->next == (struct device *)NULL) {
dev->next = (struct device *)kmalloc(sizeof(struct device) + 8,
GFP_KERNEL);
if (dev->next == (struct device *)NULL) {
printk("eth%d: Device not initialised, insufficient memory\n",
num_eth);
}
}
/*
** If the memory was allocated, point to the new memory area
** and initialize it (name, I/O address, next device (NULL) and
** initialisation probe routine).
*/
if ((dev->next != (struct device *)NULL) &&
(num_eth > 0) && (num_eth < 9999)) {
dev = dev->next; /* point to the new device */
dev->name = (char *)(dev + sizeof(struct device));
sprintf(dev->name,"eth%d", num_eth);/* New device name */
dev->base_addr = ioaddr; /* assign the io address */
dev->next = (struct device *)NULL; /* mark the end of list */
dev->init = &depca_probe; /* initialisation routine */
num_depcas++;
}
return dev;
}
/*
** Look for a particular board name in the on-board Remote Diagnostics
** and Boot (RDB) ROM. This will also give us a clue to the network RAM
......@@ -1315,9 +1383,7 @@ static char *DepcaSignature(unsigned long mem_addr)
** messing around with some other hardware, but it assumes that this DEPCA
** card initialized itself correctly. It also assumes that all past and
** future DEPCA/EtherWORKS cards will have ethernet addresses beginning with
** a 0x08. The choice of byte or word addressing is made here based on whether
** word read of the NICSR returns two identical lower and upper bytes: if so
** the register is 8 bits wide.
** a 0x08.
*/
static int DevicePresent(short ioaddr)
......@@ -1325,7 +1391,6 @@ static int DevicePresent(short ioaddr)
static short fp=1,sigLength=0;
static char devSig[] = PROBE_SEQUENCE;
char data;
unsigned char LSB,MSB;
int i, j, nicsr, status = 0;
static char asc2hex(char value);
......@@ -1336,27 +1401,13 @@ static int DevicePresent(short ioaddr)
data = inb(DEPCA_PROM); /* clear counter */
data = inb(DEPCA_PROM); /* read data */
/*
** Determine whether a byte or word access should be made on the NICSR.
** Since the I/O 'functions' are actually in-line code, the choice not to use
** pointers to functions vs. just set a conditional, is made for us. This code
** assumes that the NICSR has an asymmetric bit pattern already in it.
*/
nicsr = inw(DEPCA_NICSR);
LSB = nicsr & 0xff;
MSB = (((unsigned) nicsr) >> 8) & 0xff;
if (MSB == LSB) {
depca_na = 0; /* byte accesses */
} else {
depca_na = 1; /* word accesses */
}
/*
** Enable counter
*/
if (data == 0x08) {
nicsr = inb(DEPCA_NICSR);
nicsr |= AAC;
PUT_NICSR(nicsr, DEPCA_NICSR);
outb(nicsr, DEPCA_NICSR);
}
/*
......@@ -1382,7 +1433,7 @@ static int DevicePresent(short ioaddr)
/*
** Search the Ethernet address ROM for the signature. Since the ROM address
** counter can start at an arbitrary point, the search must include the entire
** probe sequence length plus the length of the (signature - 1).
** probe sequence length plus the (length_of_the_signature - 1).
** Stop the search IMMEDIATELY after the signature is found so that the
** PROM address counter is correctly positioned at the start of the
** ethernet address for later read out.
......
......@@ -14,7 +14,9 @@
#define DEPCA_RBI ioaddr+0x02 /* RAM buffer index (2k buffer mode) */
#define DEPCA_DATA ioaddr+0x04 /* LANCE registers' data port */
#define DEPCA_ADDR ioaddr+0x06 /* LANCE registers' address port */
#define DEPCA_HBASE ioaddr+0x08 /* EISA high memory base address reg. */
#define DEPCA_PROM ioaddr+0x0c /* Ethernet address ROM data port */
#define DEPCA_CNFG ioaddr+0x0c /* EISA Configuration port */
#define DEPCA_RBSA ioaddr+0x0e /* RAM buffer starting address (2k buff.) */
/*
......@@ -35,6 +37,7 @@
#define BUF 0x0020 /* BUFfer size (1->32k, 0->64k) */
#define RBE 0x0010 /* Remote Boot Enable (1->net boot) */
#define AAC 0x0008 /* Address ROM Address Counter (1->enable) */
#define _128KB 0x0008 /* 128kB Network RAM (1->enable) */
#define IM 0x0004 /* Interrupt Mask (1->mask) */
#define IEN 0x0002 /* Interrupt tristate ENable (1->enable) */
#define LED 0x0001 /* LED control */
......@@ -119,6 +122,20 @@
#define TMD3_LCAR 0x0800 /* Loss of CARrier */
#define TMD3_RTRY 0x0400 /* ReTRY error */
/*
** EISA configuration Register (CNFG) bit definitions
*/
#define TIMEOUT 0x0100 /* 0:2.5 mins, 1: 30 secs */
#define REMOTE 0x0080 /* Remote Boot Enable -> 1 */
#define IRQ11 0x0040 /* Enable -> 1 */
#define IRQ10 0x0020 /* Enable -> 1 */
#define IRQ9 0x0010 /* Enable -> 1 */
#define IRQ5 0x0008 /* Enable -> 1 */
#define BUFF 0x0004 /* 0: 64kB or 128kB, 1: 32kB */
#define PADR16 0x0002 /* RAM on 64kB boundary */
#define PADR17 0x0001 /* RAM on 128kB boundary */
/*
** Miscellaneous
*/
......@@ -126,3 +143,6 @@
#define MASK_INTERRUPTS 1
#define UNMASK_INTERRUPTS 0
#define EISA_EN 0x0001 /* Enable EISA bus buffers */
#define DEPCA_EISA_ID ioaddr+0x80 /* ID long word for EISA card */
#define DEPCA_EISA_CTRL ioaddr+0x84 /* Control word for EISA card */
/* e2100.c: A Cabletron E2100 series ethernet driver for linux. */
/*
Written 1993 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 Public License,
incorporated herein by reference.
This is a driver for the Cabletron E2100 series ethercards.
The Author may be reached as becker@cesdis.gsfc.nasa.gov, or
C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
The E2100 series ethercard is a fairly generic shared memory 8390
implementation. The only unusual aspect is the way the shared memory
registers are set: first you do an inb() in what is normally the
station address region, and the low four bits of next outb() is used
as the write value for that register. Either someone wasn't too used
to dem bit en bites, or they were trying to obfusicate the programming
interface.
There is an additional complication when setting the window on the packet
buffer. You must first do a read into the packet buffer region with the
low 8 address bits the address setting the page for the start of the packet
buffer window, and then do the above operation. See mem_on() for details.
One bug on the chip is that even a hard reset won't disable the memory
window, usually resulting in a hung machine if mem_off() isn't called.
If this happens, you must power down the machine for about 30 seconds.
*/
static char *version =
"e2100.c:v0.01 11/21/93 Donald Becker (becker@super.org)\n";
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <asm/io.h>
#include <asm/system.h>
#ifndef PRE_PL13
#include <linux/ioport.h> /* Delete if your kernel doesn't have it. */
#endif
#include <linux/netdevice.h>
#include "8390.h"
/* Compatibility definitions for earlier kernel versions. */
#ifndef HAVE_PORTRESERVE
#define check_region(ioaddr, size) 0
#define snarf_region(ioaddr, size); do ; while (0)
#endif
#ifndef HAVE_AUTOIRQ
/* From auto_irq.c, in ioport.h for later versions. */
extern void autoirq_setup(int waittime);
extern int autoirq_report(int waittime);
/* The map from IRQ number (as passed to the interrupt handler) to
'struct device'. */
extern struct device *irq2dev_map[16];
#endif
/* Offsets from the base_addr.
Read from the ASIC register, and the low 3(?) bits of the next outb() address
is used to set the cooresponding register. */
#define E21_NIC_OFFSET 0 /* Offset to the 8390 NIC. */
#define E21_ASIC 0x10
#define E21_MEM_ENABLE 0x10
#define E21_MEM_ON 0x05 /* Enable memory in 16 bit mode. */
#define E21_MEM_ON_8 0x07 /* Enable memory in 8 bit mode. */
#define E21_MEM_BASE 0x11
#define E21_IRQ_LOW 0x12 /* The low three bits of the IRQ number. */
#define E21_IRQ_HIGH 0x14 /* The high IRQ bit, and ... */
#define E21_ALT_IFPORT 0x02 /* Set to use the other (BNC,AUI) port. */
#define E21_BIG_MEM 0x04 /* Use a bigger (64K) buffer (we don't) */
#define E21_SAPROM 0x10 /* Offset to station address data. */
#define ETHERCARD_TOTAL_SIZE 0x20
extern inline void mem_on(short port, volatile char *mem_base,
unsigned char start_page )
{
/* This is a little weird: set the shared memory window by doing a
read. The low address bits specify the starting page. */
mem_base[start_page];
inb(port + E21_MEM_ENABLE);
outb(E21_MEM_ON, port + E21_MEM_ENABLE + E21_MEM_ON);
}
extern inline void mem_off(short port)
{
inb(port + E21_MEM_ENABLE);
outb(0x00, port + E21_MEM_ENABLE);
}
/* In other drivers I put the TX pages first, but the E2100 window circuitry
is designed to have a 4K Tx region last. The windowing circuitry wraps the
window at 0x2fff->0x0000 so that the packets at e.g. 0x2f00 in the RX ring
appear contiguously in the window. */
#define E21_RX_START_PG 0x00 /* First page of RX buffer */
#define E21_RX_STOP_PG 0x30 /* Last page +1 of RX ring */
#define E21_BIG_RX_STOP_PG 0xF0 /* Last page +1 of RX ring */
#define E21_TX_START_PG E21_RX_STOP_PG /* First page of TX buffer */
int e2100_probe(struct device *dev);
int e21_probe1(struct device *dev, int ioaddr);
static int e21_open(struct device *dev);
static void e21_reset_8390(struct device *dev);
static int e21_block_input(struct device *dev, int count,
char *buf, int ring_offset);
static void e21_block_output(struct device *dev, int count,
const unsigned char *buf, const start_page);
static int e21_close(struct device *dev);
/* Probe for the E2100 series ethercards. These cards have an 8390 at the
base address and the station address at both offset 0x10 and 0x18. I read
the station address from offset 0x18 to avoid the dataport of NE2000
ethercards, and look for Ctron's unique ID (first three octets of the
station address).
*/
int e2100_probe(struct device *dev)
{
int *port, ports[] = {0x300, 0x280, 0x380, 0x220, 0};
short base_addr = dev->base_addr;
if (base_addr > 0x1ff) /* Check a single specified location. */
return e21_probe1(dev, base_addr);
else if (base_addr > 0) /* Don't probe at all. */
return ENXIO;
for (port = &ports[0]; *port; port++) {
ushort ioaddr = *port;
if (check_region(ioaddr, ETHERCARD_TOTAL_SIZE))
continue;
if (inb(ioaddr + E21_SAPROM + 0) == 0x00
&& inb(ioaddr + E21_SAPROM + 1) == 0x00
&& inb(ioaddr + E21_SAPROM + 2) == 0x1d
&& e21_probe1(dev, ioaddr) == 0)
return 0;
}
return -ENODEV;
}
int e21_probe1(struct device *dev, int ioaddr)
{
int i, status;
unsigned char *station_addr = dev->dev_addr;
/* We've already checked the station address prefix, now verify by making
certain that there is a 8390 at the expected location. */
outb(E8390_NODMA + E8390_STOP, ioaddr);
SLOW_DOWN_IO;
status = inb(ioaddr);
if (status != 0x21 && status != 0x23)
return -ENODEV;
#ifdef testing_only
printk("%s: E21xx at %#3x (PAXI backwards): ", dev->name, ioaddr);
for (i = 0; i < 16; i++)
printk(" %02X", inb(ioaddr + 0x1f - i));
printk("\n");
#endif
/* Read the station address PROM. */
for (i = 0; i < 6; i++)
station_addr[i] = inb(ioaddr + E21_SAPROM + i);
/* Grab the region so we can find another board if needed . */
snarf_region(ioaddr, ETHERCARD_TOTAL_SIZE);
printk("%s: E21xx at %#3x, ", dev->name, ioaddr);
for (i = 0; i < 6; i++)
printk(" %02X", station_addr[i]);
if (dev->irq < 2) {
int irqlist[] = {15,11,10,12,5,9,3,4}, i;
for (i = 0; i < 8; i++)
if (request_irq (irqlist[i], NULL) != -EBUSY) {
dev->irq = irqlist[i];
break;
}
} else if (dev->irq == 2) /* Fixup bogosity: IRQ2 is really IRQ9 */
dev->irq = 9;
/* Snarf the interrupt now. */
if (irqaction (dev->irq, &ei_sigaction)) {
printk (" unable to get IRQ %d.\n", dev->irq);
return -EBUSY;
}
/* The 8390 is at the base address. */
dev->base_addr = ioaddr;
ethdev_init(dev);
ei_status.name = "E2100";
ei_status.word16 = 1;
ei_status.tx_start_page = E21_TX_START_PG;
ei_status.rx_start_page = E21_RX_START_PG;
ei_status.stop_page = E21_RX_STOP_PG;
/* Check the media port used. The port can be passed in on the
low mem_end bits. */
if (dev->mem_end & 15)
dev->if_port = dev->mem_end & 7;
else {
dev->if_port = 0;
inb_p(ioaddr + E21_IRQ_HIGH); /* Select if_port detect. */
for(i = 0; i < 6; i++)
if (station_addr[i] != inb(ioaddr + E21_SAPROM))
dev->if_port = 1;
}
/* Never map in the E21 shared memory unless you are actively using it.
Also, the shared memory has effective only one setting -- spread all
over the 128K region! */
if (dev->mem_start == 0)
dev->mem_start = 0xd0000;
#ifdef notdef
/* These values are unused. The E2100 has a 2K window into the packet
buffer. The window can be set to start on any page boundary. */
dev->rmem_start = dev->mem_start + TX_PAGES*256;
dev->mem_end = dev->rmem_end = dev->mem_start + 2*1024;
#endif
printk(" IRQ %d, %s interface, memory at %#x-%#x.\n", dev->irq,
dev->if_port ? "secondary" : "primary", dev->mem_start,
dev->mem_start + 2*1024 - 1);
if (ei_debug > 0)
printk(version);
ei_status.reset_8390 = &e21_reset_8390;
ei_status.block_input = &e21_block_input;
ei_status.block_output = &e21_block_output;
dev->open = &e21_open;
dev->stop = &e21_close;
NS8390_init(dev, 0);
return 0;
}
static int
e21_open(struct device *dev)
{
short ioaddr = dev->base_addr;
/* Set the interrupt line and memory base on the hardware. */
inb_p(ioaddr + E21_IRQ_LOW);
outb_p(0, ioaddr + E21_ASIC + (dev->irq & 7));
inb_p(ioaddr + E21_IRQ_HIGH); /* High IRQ bit, and if_port. */
outb_p(0, ioaddr + E21_ASIC + (dev->irq > 7 ? 1:0)
+ (dev->if_port ? E21_ALT_IFPORT : 0));
inb_p(ioaddr + E21_MEM_BASE);
outb_p(0, ioaddr + E21_ASIC + ((dev->mem_start >> 17) & 7));
return ei_open(dev);
}
static void
e21_reset_8390(struct device *dev)
{
short ioaddr = dev->base_addr;
outb(0x01, ioaddr);
if (ei_debug > 1) printk("resetting the E2180x3 t=%d...", jiffies);
ei_status.txing = 0;
/* Set up the ASIC registers, just in case something changed them. */
if (ei_debug > 1) printk("reset done\n");
return;
}
/* Block input and output are easy on shared memory ethercards. The E21xx makes
block_input() especially easy by wrapping the top ring buffer to the bottom
automatically. */
static int
e21_block_input(struct device *dev, int count, char *buf, int ring_offset)
{
short ioaddr = dev->base_addr;
char *shared_mem = (char *)dev->mem_start;
int start_page = (ring_offset>>8);
mem_on(ioaddr, shared_mem, start_page);
/* We'll always get a 4 byte header read first. */
if (count == 4)
((int*)buf)[0] = ((int*)shared_mem)[0];
else
memcpy(buf, shared_mem + (ring_offset & 0xff), count);
/* Turn off memory access: we would need to reprogram the window anyway. */
mem_off(ioaddr);
return 0;
}
static void
e21_block_output(struct device *dev, int count, const unsigned char *buf,
int start_page)
{
short ioaddr = dev->base_addr;
volatile char *shared_mem = (char *)dev->mem_start;
/* Set the shared memory window start by doing a read, with the low address
bits specifing the starting page. */
*(shared_mem + start_page);
mem_on(ioaddr, shared_mem, start_page);
memcpy((char*)shared_mem, buf, count);
mem_off(ioaddr);
}
static int
e21_close(struct device *dev)
{
short ioaddr = dev->base_addr;
if (ei_debug > 1)
printk("%s: Shutting down ethercard.\n", dev->name);
NS8390_init(dev, 0);
mem_off(ioaddr);
return 0;
}
/*
* Local variables:
* compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c e2100.c"
* version-control: t
* tab-width: 4
* kept-new-versions: 5
* End:
*/
......@@ -128,7 +128,7 @@ loopback_init(struct device *dev)
#endif
/* New-style flags. */
dev->flags = IFF_LOOPBACK;
dev->flags = IFF_LOOPBACK|IFF_BROADCAST;
dev->family = AF_INET;
#ifdef CONFIG_INET
dev->pa_addr = in_aton("127.0.0.1");
......
/* znet.c: An Zenith Z-Note ethernet driver for linux. */
static char *version = "znet.c:v0.04 5/10/94 becker@cesdis.gsfc.nasa.gov\n";
/*
Written by Donald Becker.
The author may be reached as becker@cesdis.gsfc.nasa.gov.
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 commesurate with the highest system performance in the face
of moderate interrupt latency: Both DMA channels are configued 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.
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/ptrace.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <asm/system.h>
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/if_arp.h>
#ifndef HAVE_AUTOIRQ
/* From auto_irq.c, in ioport.h for later versions. */
extern void autoirq_setup(int waittime);
extern int autoirq_report(int waittime);
/* The map from IRQ number (as passed to the interrupt handler) to
'struct device'. */
extern struct device *irq2dev_map[16];
#endif
#ifndef HAVE_ALLOC_SKB
#define alloc_skb(size, priority) (struct sk_buff *) kmalloc(size,priority)
#define kfree_skbmem(addr, size) kfree_s(addr,size);
#endif
#ifndef ZNET_DEBUG
#define ZNET_DEBUG 3
#endif
static unsigned int znet_debug = ZNET_DEBUG;
/* 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 DMA_BUF_SIZE 8192
#define RX_BUF_SIZE 8192
#define TX_BUF_SIZE 8192
/* Commands to the i82593 channel 0. */
#define CMD0_CHNL_0 0x00
#define CMD0_CHNL_1 0x10 /* Switch to channel 1. */
#define CMD0_NOP (CMD0_CHNL_0)
#define CMD0_PORT_1 CMD0_CHNL_1
#define CMD1_PORT_0 1
#define CMD0_IA_SETUP 1
#define CMD0_CONFIGURE 2
#define CMD0_MULTICAST_LIST 3
#define CMD0_TRANSMIT 4
#define CMD0_DUMP 6
#define CMD0_DIAGNOSE 7
#define CMD0_Rx_ENABLE 8
#define CMD0_Rx_DISABLE 10
#define CMD0_Rx_STOP 11
#define CMD0_RETRANSMIT 12
#define CMD0_ABORT 13
#define CMD0_RESET 14
#define CMD0_ACK 0x80
#define CMD0_STAT0 (0 << 5)
#define CMD0_STAT1 (1 << 5)
#define CMD0_STAT2 (2 << 5)
#define CMD0_STAT3 (3 << 5)
#define net_local znet_private
struct znet_private {
int rx_dma, tx_dma;
struct enet_statistics stats;
/* 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 lenght, in words. */
};
/* Only one can be built-in;-> */
static struct znet_private zn;
static ushort dma_buffer1[DMA_BUF_SIZE/2];
static ushort dma_buffer2[DMA_BUF_SIZE/2];
static ushort dma_buffer3[DMA_BUF_SIZE/2 + 8];
/* The configuration block. What an undocumented nightmare. The first
set of values are those suggested (without explaination) 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. */
static unsigned char i593_init[] = {
0xAA, /* 0: 16-byte input & 80-byte output FIFO. */
/* threshhold, 96-byte FIFO, 82593 mode. */
0x88, /* 1: Continuous w/interrupts, 128-clock DMA.*/
0x2E, /* 2: 8-byte preamble, NO address insertion, */
/* 6-byte Ethernet address, loopback off.*/
0x00, /* 3: Default priorities & backoff methods. */
0x60, /* 4: 96-bit interframe spacing. */
0x00, /* 5: 512-bit slot time (low-order). */
0xF2, /* 6: Slot time (high-order), 15 COLL retries. */
0x00, /* 7: Promisc-off, broadcast-on, default CRC. */
0x00, /* 8: Default carrier-sense, collision-detect. */
0x40, /* 9: 64-byte minimum frame length. */
0x5F, /* A: Type/length checks OFF, no CRC input,
"jabber" termination, etc. */
0x00, /* B: Full-duplex disabled. */
0x3F, /* C: Default multicast addresses & backoff. */
0x07, /* D: Default IFS retriggering. */
0x31, /* E: Internal retransmit, drop "runt" packets,
synchr. DRQ deassertion, 6 status bytes. */
0x22, /* F: Receive ring-buffer size (8K),
receive-stop register enable. */
};
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;
};
int znet_probe(struct device *dev);
static int znet_open(struct device *dev);
static int znet_send_packet(struct sk_buff *skb, struct device *dev);
static void znet_interrupt(int reg_ptr);
static void znet_rx(struct device *dev);
static int znet_close(struct device *dev);
static struct enet_statistics *net_get_stats(struct device *dev);
static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
static void hardware_init(struct device *dev);
static int do_command(short ioaddr, int command, int length, ushort *buffer);
static int wait_for_done(short ioaddr);
static void update_stop_hit(short ioaddr, unsigned short rx_stop_offset);
#ifdef notdef
static struct sigaction znet_sigaction = { &znet_interrupt, 0, 0, NULL, };
#endif
/* 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. */
int znet_probe(struct device *dev)
{
int i;
struct netidblk *netinfo;
char *p;
/* This code scans the region 0xf0000 to 0xfffff for a "NETIDBLK". */
for(p = (char *)0xf0000; p < (char *)0x100000; p++)
if (*p == 'N' && strncmp(p, "NETIDBLK", 8) == 0)
break;
if (p >= (char *)0x100000) {
if (znet_debug > 1)
printk("No Z-Note ethernet adaptor found.\n");
return ENODEV;
}
netinfo = (struct netidblk *)p;
dev->base_addr = netinfo->iobase1;
dev->irq = netinfo->irq1;
printk("%s: ZNET at %#3x,", dev->name, dev->base_addr);
/* The station address is in the "netidblk" at 0x0f0000. */
for (i = 0; i < 6; i++)
printk(" %2.2x", dev->dev_addr[i] = netinfo->netid[i]);
printk(", using IRQ %d DMA %d and %d.\n", dev->irq, netinfo->dma1,
netinfo->dma2);
if (znet_debug > 1) {
printk("%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("%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(version);
dev->priv = (void *) &zn;
zn.rx_dma = netinfo->dma1;
zn.tx_dma = netinfo->dma2;
/* These should never fail. You can't add devices to a sealed box! */
if (request_irq(dev->irq, &znet_interrupt)
|| request_dma(zn.rx_dma)
|| request_dma(zn.tx_dma)) {
printk("Not opened -- resource busy?!?\n");
return EBUSY;
}
irq2dev_map[dev->irq] = dev;
/* Allocate buffer memory. We can cross a 128K boundary, so we
must be careful about the allocation. It's easiest to waste 8K. */
if (dma_page_eq(dma_buffer1, &dma_buffer1[RX_BUF_SIZE/2-1]))
zn.rx_start = dma_buffer1;
else
zn.rx_start = dma_buffer2;
if (dma_page_eq(dma_buffer3, &dma_buffer3[RX_BUF_SIZE/2-1]))
zn.tx_start = dma_buffer3;
else
zn.tx_start = dma_buffer2;
zn.rx_end = zn.rx_start + RX_BUF_SIZE/2;
zn.tx_buf_len = TX_BUF_SIZE/2;
zn.tx_end = zn.tx_start + zn.tx_buf_len;
/* The ZNET-specific entries in the device structure. */
dev->open = &znet_open;
dev->hard_start_xmit = &znet_send_packet;
dev->stop = &znet_close;
dev->get_stats = net_get_stats;
#ifdef HAVE_MULTICAST
dev->set_multicast_list = &set_multicast_list;
#endif
/* Fill in the generic field of the device structure. */
for (i = 0; i < DEV_NUMBUFFS; i++)
dev->buffs[i] = NULL;
dev->hard_header = eth_header;
dev->add_arp = eth_add_arp;
dev->queue_xmit = dev_queue_xmit;
dev->rebuild_header = eth_rebuild_header;
dev->type_trans = eth_type_trans;
dev->type = ARPHRD_ETHER;
dev->hard_header_len = ETH_HLEN;
dev->mtu = 1500; /* eth_mtu */
dev->addr_len = ETH_ALEN;
for (i = 0; i < ETH_ALEN; i++) {
dev->broadcast[i]=0xff;
}
/* New-style flags. */
dev->flags = IFF_BROADCAST;
dev->family = AF_INET;
dev->pa_addr = 0;
dev->pa_brdaddr = 0;
dev->pa_mask = 0;
dev->pa_alen = sizeof(unsigned long);
return 0;
}
static int znet_open(struct device *dev)
{
int ioaddr = dev->base_addr;
if (znet_debug > 2)
printk("%s: znet_open() called.\n", dev->name);
/* Turn on the 82501 SIA, using zenith-specific magic. */
outb(0x10, 0xe6); /* Select LAN control register */
outb(inb(0xe7) | 0x84, 0xe7); /* Turn on LAN power (bit 2). */
/* 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. */
/* This follows the packet driver's lead, and checks for success. */
if (inb(ioaddr) != 0x10 && inb(ioaddr) != 0x00)
printk("%s: Problem turning on the transceiver power.\n", dev->name);
dev->tbusy = 0;
dev->interrupt = 0;
hardware_init(dev);
dev->start = 1;
return 0;
}
static int znet_send_packet(struct sk_buff *skb, struct device *dev)
{
int ioaddr = dev->base_addr;
if (znet_debug > 4)
printk("%s: ZNet_send_packet(%d).\n", dev->name, dev->tbusy);
/* Transmitter timeout, could be a serious problems. */
if (dev->tbusy) {
ushort event, tx_status, rx_offset, state;
int tickssofar = jiffies - dev->trans_start;
if (tickssofar < 10)
return 1;
outb(CMD0_STAT0, ioaddr); event = inb(ioaddr);
outb(CMD0_STAT1, ioaddr); tx_status = inw(ioaddr);
outb(CMD0_STAT2, ioaddr); rx_offset = inw(ioaddr);
outb(CMD0_STAT3, ioaddr); state = inb(ioaddr);
printk("%s: transmit timed out, status %02x %04x %04x %02x,"
" resetting.\n", dev->name, event, tx_status, rx_offset, state);
if (tx_status == 0x0400)
printk("%s: Tx carrier error, check transceiver cable.\n",
dev->name);
outb(CMD0_RESET, ioaddr);
hardware_init(dev);
}
if (skb == NULL) {
dev_tint(dev);
return 0;
}
/* Fill in the ethernet header. */
if (!skb->arp && dev->rebuild_header(skb+1, dev)) {
skb->dev = dev;
arp_queue (skb);
return 0;
}
/* Check that the part hasn't reset itself, probably from suspend. */
outb(CMD0_STAT0, ioaddr);
if (inw(ioaddr) == 0x0010
&& inw(ioaddr) == 0x0000
&& inw(ioaddr) == 0x0010)
hardware_init(dev);
/* Block a timer-based transmit from overlapping. This could better be
done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
if (set_bit(0, (void*)&dev->tbusy) != 0)
printk("%s: Transmitter access conflict.\n", dev->name);
else {
short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
unsigned char *buf = (void *)(skb+1);
ushort *tx_link = zn.tx_cur - 1;
ushort rnd_len = (length + 1)>>1;
{
short dma_port = ((zn.tx_dma&3)<<2) + IO_DMA2_BASE;
unsigned addr = inb(dma_port);
addr |= inb(dma_port) << 8;
addr <<= 1;
if (((int)zn.tx_cur & 0x1ffff) != addr)
printk("Address mismatch at Tx: %#x vs %#x.\n",
(int)zn.tx_cur & 0xffff, addr);
zn.tx_cur = (ushort *)(((int)zn.tx_cur & 0xfe0000) | addr);
}
if (zn.tx_cur >= zn.tx_end)
zn.tx_cur = zn.tx_start;
*zn.tx_cur++ = length;
if (zn.tx_cur + rnd_len + 1 > zn.tx_end) {
int semi_cnt = (zn.tx_end - zn.tx_cur)<<1; /* Cvrt to byte cnt. */
memcpy(zn.tx_cur, buf, semi_cnt);
rnd_len -= semi_cnt>>1;
memcpy(zn.tx_start, buf + semi_cnt, length - semi_cnt);
zn.tx_cur = zn.tx_start + rnd_len;
} else {
memcpy(zn.tx_cur, buf, skb->len);
zn.tx_cur += rnd_len;
}
*zn.tx_cur++ = 0;
cli(); {
*tx_link = CMD0_TRANSMIT + CMD0_CHNL_1;
/* Is this always safe to do? */
outb(CMD0_TRANSMIT + CMD0_CHNL_1,ioaddr);
} sti();
dev->trans_start = jiffies;
if (znet_debug > 4)
printk("%s: Transmitter queued, length %d.\n", dev->name, length);
}
dev_kfree_skb(skb, FREE_WRITE);
return 0;
}
/* The ZNET interrupt handler. */
static void znet_interrupt(int reg_ptr)
{
int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2);
struct device *dev = irq2dev_map[irq];
int ioaddr;
int boguscnt = 20;
if (dev == NULL) {
printk ("znet_interrupt(): IRQ %d for unknown device.\n", irq);
return;
}
dev->interrupt = 1;
ioaddr = dev->base_addr;
outb(CMD0_STAT0, ioaddr);
do {
ushort status = inb(ioaddr);
if (znet_debug > 5) {
ushort result, rx_ptr, running;
outb(CMD0_STAT1, ioaddr);
result = inw(ioaddr);
outb(CMD0_STAT2, ioaddr);
rx_ptr = inw(ioaddr);
outb(CMD0_STAT3, ioaddr);
running = inb(ioaddr);
printk("%s: interrupt, status %02x, %04x %04x %02x serial %d.\n",
dev->name, status, result, rx_ptr, running, boguscnt);
}
if ((status & 0x80) == 0)
break;
if ((status & 0x0F) == 4) { /* Transmit done. */
struct net_local *lp = (struct net_local *)dev->priv;
int tx_status;
outb(CMD0_STAT1, ioaddr);
tx_status = inw(ioaddr);
/* It's undocumented, but tx_status seems to match the i82586. */
if (tx_status & 0x2000) {
lp->stats.tx_packets++;
lp->stats.collisions += tx_status & 0xf;
} else {
if (tx_status & 0x0600) lp->stats.tx_carrier_errors++;
if (tx_status & 0x0100) lp->stats.tx_fifo_errors++;
if (!(tx_status & 0x0040)) lp->stats.tx_heartbeat_errors++;
if (tx_status & 0x0020) lp->stats.tx_aborted_errors++;
/* ...and the catch-all. */
if (tx_status | 0x0760 != 0x0760)
lp->stats.tx_errors++;
}
dev->tbusy = 0;
mark_bh(INET_BH); /* Inform upper layers. */
}
if ((status & 0x40)
|| (status & 0x0f) == 11) {
znet_rx(dev);
}
/* Clear the interrupts we've handled. */
outb(CMD0_ACK,ioaddr);
} while (boguscnt--);
dev->interrupt = 0;
return;
}
static void znet_rx(struct device *dev)
{
struct net_local *lp = (struct net_local *)dev->priv;
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(CMD0_STAT2, ioaddr);
cur_frame_end_offset = inw(ioaddr);
if (cur_frame_end_offset == zn.rx_cur - zn.rx_start) {
printk("%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 (zn.rx_start + cur_frame_end_offset != zn.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(zn.rx_end, zn.rx_start, 8);
cur_frame_end_offset += (RX_BUF_SIZE/2);
}
cur_frame_end = zn.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("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 = zn.rx_start + next_frame_end_offset;
int status = this_rfp_ptr[-4];
int pkt_len = this_rfp_ptr[-2];
if (znet_debug > 5)
printk("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 & 0x2000)) { /* There was an error. */
lp->stats.rx_errors++;
if (status & 0x0800) lp->stats.rx_crc_errors++;
if (status & 0x0400) lp->stats.rx_frame_errors++;
if (status & 0x0200) lp->stats.rx_over_errors++; /* Wrong. */
if (status & 0x0100) lp->stats.rx_fifo_errors++;
if (status & 0x0080) lp->stats.rx_length_errors++;
} else if (pkt_len > 1536) {
lp->stats.rx_length_errors++;
} else {
/* Malloc up new buffer. */
int sksize = sizeof(struct sk_buff) + pkt_len;
struct sk_buff *skb;
skb = alloc_skb(sksize, GFP_ATOMIC);
if (skb == NULL) {
if (znet_debug)
printk("%s: Memory squeeze, dropping packet.\n", dev->name);
lp->stats.rx_dropped++;
break;
}
skb->mem_len = sksize;
skb->mem_addr = skb;
skb->len = pkt_len;
skb->dev = dev;
if (&zn.rx_cur[(pkt_len+1)>>1] > zn.rx_end) {
int semi_cnt = (zn.rx_end - zn.rx_cur)<<1;
memcpy((unsigned char *) (skb + 1), zn.rx_cur, semi_cnt);
memcpy((unsigned char *) (skb + 1) + semi_cnt, zn.rx_start,
pkt_len - semi_cnt);
} else {
memcpy((unsigned char *) (skb + 1), zn.rx_cur, pkt_len);
if (znet_debug > 6) {
unsigned int *packet = (unsigned int *) (skb + 1);
printk("Packet data is %08x %08x %08x %08x.\n", packet[0],
packet[1], packet[2], packet[3]);
}
}
#ifdef HAVE_NETIF_RX
netif_rx(skb);
#else
skb->lock = 0;
if (dev_rint((unsigned char*)skb, pkt_len, IN_SKBUFF, dev) != 0) {
kfree_s(skb, sksize);
lp->stats.rx_dropped++;
break;
}
#endif
lp->stats.rx_packets++;
}
zn.rx_cur = this_rfp_ptr;
if (zn.rx_cur >= zn.rx_end)
zn.rx_cur -= RX_BUF_SIZE/2;
update_stop_hit(ioaddr, (zn.rx_cur - zn.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 = zn.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. */
return;
}
/* The inverse routine to znet_open(). */
static int znet_close(struct device *dev)
{
int ioaddr = dev->base_addr;
dev->tbusy = 1;
dev->start = 0;
outb(CMD0_RESET, ioaddr); /* CMD0_RESET */
disable_dma(zn.rx_dma);
disable_dma(zn.tx_dma);
free_irq(dev->irq);
if (znet_debug > 1)
printk("%s: Shutting down ethercard.\n", dev->name);
/* Turn off transceiver power. */
outb(0x10, 0xe6); /* Select LAN control register */
outb(inb(0xe7) & ~0x84, 0xe7); /* Turn on LAN power (bit 2). */
return 0;
}
/* Get the current statistics. This may be called with the card open or
closed. */
static struct enet_statistics *net_get_stats(struct device *dev)
{
struct net_local *lp = (struct net_local *)dev->priv;
return &lp->stats;
}
#ifdef HAVE_MULTICAST
/* Set or clear the multicast filter for this adaptor.
num_addrs == -1 Promiscuous mode, receive all packets
num_addrs == 0 Normal mode, clear multicast list
num_addrs > 0 Multicast mode, receive normal and MC packets, and do
best-effort filtering.
As a side effect this routine must also initialize the device parameters.
This is taken advantage of in open().
N.B. that we change i593_init[] in place. This (properly) makes the
mode change persistent, but must be changed if this code is moved to
a multiple adaptor environment.
*/
static void set_multicast_list(struct device *dev, int num_addrs, void *addrs)
{
short ioaddr = dev->base_addr;
if (num_addrs < 0) {
/* Enable promiscuous mode */
i593_init[7] &= ~3; i593_init[7] |= 1;
i593_init[13] &= ~8; i593_init[13] |= 8;
} else if (num_addrs > 0) {
/* Enable accept-all-multicast mode */
i593_init[7] &= ~3; i593_init[7] |= 0;
i593_init[13] &= ~8; i593_init[13] |= 8;
} else { /* Enable normal mode. */
i593_init[7] &= ~3; i593_init[7] |= 0;
i593_init[13] &= ~8; i593_init[13] |= 0;
}
*zn.tx_cur++ = sizeof(i593_init);
memcpy(zn.tx_cur, i593_init, sizeof(i593_init));
zn.tx_cur += sizeof(i593_init)/2;
outb(CMD0_CONFIGURE+CMD0_CHNL_1, ioaddr);
#ifdef not_tested
if (num_addrs > 0) {
int addrs_len = 6*num_addrs;
*zn.tx_cur++ = addrs_len;
memcpy(zn.tx_cur, addrs, addrs_len);
outb(CMD0_MULTICAST_LIST+CMD0_CHNL_1, ioaddr);
zn.tx_cur += addrs_len>>1;
}
#endif
}
#endif
void show_dma(void)
{
short dma_port = ((zn.tx_dma&3)<<2) + IO_DMA2_BASE;
unsigned addr = inb(dma_port);
addr |= inb(dma_port) << 8;
printk("Addr: %04x cnt:%3x...", addr<<1,
get_dma_residue(zn.tx_dma));
}
/* 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 device *dev)
{
short ioaddr = dev->base_addr;
zn.rx_cur = zn.rx_start;
zn.tx_cur = zn.tx_start;
/* Reset the chip, and start it up. */
outb(CMD0_RESET, ioaddr);
cli(); { /* Protect against a DMA flip-flop */
disable_dma(zn.rx_dma); /* reset by an interrupting task. */
clear_dma_ff(zn.rx_dma);
set_dma_mode(zn.rx_dma, DMA_RX_MODE);
set_dma_addr(zn.rx_dma, (unsigned int) zn.rx_start);
set_dma_count(zn.rx_dma, RX_BUF_SIZE);
enable_dma(zn.rx_dma);
/* Now set up the Tx channel. */
disable_dma(zn.tx_dma);
clear_dma_ff(zn.tx_dma);
set_dma_mode(zn.tx_dma, DMA_TX_MODE);
set_dma_addr(zn.tx_dma, (unsigned int) zn.tx_start);
set_dma_count(zn.tx_dma, zn.tx_buf_len<<1);
enable_dma(zn.tx_dma);
} sti();
if (znet_debug > 1)
printk("%s: Initializing the i82593, tx buf %p... ", dev->name,
zn.tx_start);
/* Do an empty configure command, just like the Crynwr driver. This
resets to chip to its default values. */
*zn.tx_cur++ = 0;
*zn.tx_cur++ = 0;
printk("stat:%02x ", inb(ioaddr)); show_dma();
outb(CMD0_CONFIGURE+CMD0_CHNL_1, ioaddr);
*zn.tx_cur++ = sizeof(i593_init);
memcpy(zn.tx_cur, i593_init, sizeof(i593_init));
zn.tx_cur += sizeof(i593_init)/2;
printk("stat:%02x ", inb(ioaddr)); show_dma();
outb(CMD0_CONFIGURE+CMD0_CHNL_1, ioaddr);
*zn.tx_cur++ = 6;
memcpy(zn.tx_cur, dev->dev_addr, 6);
zn.tx_cur += 3;
printk("stat:%02x ", inb(ioaddr)); show_dma();
outb(CMD0_IA_SETUP + CMD0_CHNL_1, ioaddr);
printk("stat:%02x ", inb(ioaddr)); show_dma();
update_stop_hit(ioaddr, 8192);
if (znet_debug > 1) printk("enabling Rx.\n");
outb(CMD0_Rx_ENABLE+CMD0_CHNL_0, ioaddr);
dev->tbusy = 0;
}
#ifdef notdef
foo()
{
/*do_command(ioaddr, CMD0_CONFIGURE+CMD0_CHNL_1, sizeof(i593_init) + 2,
zn.tx_buffer);*/
/*do_command(ioaddr, CMD0_CONFIGURE+CMD0_CHNL_1, 32, zn.tx_buffer);*/
/*outb(CMD0_CONFIGURE+CMD0_CHNL_1, ioaddr);*/
if (znet_debug > 1) printk("Set Address... ");
*zn.tx_cur++ = 6;
memcpy(zn.tx_cur, dev->dev_addr, 6);
zn.tx_cur += 3;
outb(CMD0_IA_SETUP + CMD0_CHNL_1, ioaddr);
{
unsigned stop_time = jiffies + 3;
while (jiffies < stop_time);
}
if (znet_debug > 2) {
short dma_port = ((zn.tx_dma&3)<<2) + IO_DMA2_BASE;
unsigned addr = inb(dma_port);
addr |= inb(dma_port) << 8;
printk("Terminal addr is %04x, cnt. %03x...", addr<<1,
get_dma_residue(zn.tx_dma));
}
*zn.tx_cur++ = 6;
memcpy(zn.tx_cur, dev->dev_addr, 6);
zn.tx_cur += 3;
outb(CMD0_IA_SETUP + CMD0_CHNL_1, ioaddr);
{
unsigned stop_time = jiffies + 2;
while (jiffies < stop_time);
}
if (znet_debug > 2) {
short dma_port = ((zn.tx_dma&3)<<2) + IO_DMA2_BASE;
unsigned addr = inb(dma_port);
addr |= inb(dma_port) << 8;
printk("Terminal addr is %04x, cnt. %03x...", addr<<1,
get_dma_residue(zn.tx_dma));
}
wait_for_done(ioaddr);
if (znet_debug > 1) printk("Set Mode... ");
set_multicast_list(dev, 0, 0);
{
unsigned stop_time = jiffies + 3;
while (jiffies < stop_time);
}
if (znet_debug > 2) {
short dma_port = ((zn.tx_dma&3)<<2) + IO_DMA2_BASE;
unsigned addr = inb(dma_port);
addr |= inb(dma_port) << 8;
printk("Terminal addr is %04x, cnt. %03x...", addr<<1,
get_dma_residue(zn.tx_dma));
}
if (znet_debug > 2) {
int i;
outb(CMD0_DUMP+CMD0_CHNL_0, ioaddr);
printk("Dumping state:");
for (i = 0; i < 16; i++)
printk(" %04x", *zn.rx_cur++);
printk("\n :");
for (;i < 32; i++)
printk(" %04x", *zn.rx_cur++);
printk("\n");
wait_for_done(ioaddr);
}
}
static int do_command(short ioaddr, int command, int length, ushort *buffer)
{
/* This isn't needed, but is here for safety. */
outb(CMD0_NOP+CMD0_STAT3,ioaddr);
if (inb(ioaddr) & 3)
printk("znet: do_command() while the i82593 is busy.\n");
cli();
disable_dma(zn.tx_dma);
clear_dma_ff(zn.tx_dma);
set_dma_mode(zn.tx_dma,DMA_MODE_WRITE);
set_dma_addr(zn.tx_dma,(unsigned int) zn.tx_start);
set_dma_count(zn.tx_dma,length);
sti();
enable_dma(zn.tx_dma);
outb(command, ioaddr);
return 0;
}
/* wait_for_done - this is a blatent rip-off of the wait_for_done routine
** from the Crynwr packet driver. It does not work correctly - doesn't
** acknowledge the interrupts it gets or something. It does determine
** when the command is done, or if there are none executing, though...
** -Mike
*/
static int wait_for_done(short ioaddr)
{
unsigned int stat;
unsigned stop_time = jiffies + 10;
int ticks = 0;
/* check to see if we are busy */
outb(CMD0_NOP+CMD0_STAT3,ioaddr);
stat = inb(ioaddr);
/* check if busy */
if ((stat&3)==0) {
if (znet_debug > 5)
printk("wait_for_done(): Not busy, status %02x.\n", stat);
return 0;
}
while (jiffies < stop_time) {
/* now check */
outb(CMD0_NOP+CMD0_STAT3,ioaddr);
stat = inb(ioaddr);
if ((stat&3)==0) {
if (znet_debug > 5)
printk("Command completed after %d ticks status %02x.\n",
ticks, stat);
outb((CMD0_NOP|CMD0_ACK),ioaddr);
return 0;
}
ticks++;
}
outb(CMD0_ABORT, ioaddr);
if (znet_debug)
printk("wait_for_done: command not ACK'd, status %02x after abort %02x.\n",
stat, inb(ioaddr));
/* should re-initialize here... */
return 1;
}
#endif /* notdef */
static void update_stop_hit(short ioaddr, unsigned short rx_stop_offset)
{
outb(CMD0_PORT_1, ioaddr);
if (znet_debug > 5)
printk("Updating stop hit with value %02x.\n",
(rx_stop_offset >> 6) | 0x80);
outb((rx_stop_offset >> 6) | 0x80, ioaddr);
outb(CMD1_PORT_0, ioaddr);
}
/*
* Local variables:
* compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c znet.c"
* version-control: t
* kept-new-versions: 5
* c-indent-level: 4
* tab-width: 4
* End:
*/
......@@ -142,6 +142,7 @@ static struct blist blacklist[] =
{"MAXTOR","XT-4380S","B3C"}, /* Locks-up when LUN>0 polled. */
{"MAXTOR","MXT-1240S","I1.2"}, /* Locks up when LUN > 0 polled */
{"MAXTOR","XT-4170S","B5A"}, /* Locks-up sometimes when LUN>0 polled. */
{"MAXTOR","XT-8760S","B6B"}, /* Locks-up when LUN > 0 is polled */
{"MAXTOR","XT-8760S","B7B"}, /* guess what? */
{"NEC","CD-ROM DRIVE:841","1.0"}, /* Locks-up when LUN>0 polled. */
{"RODIME","RO3000S","2.33"}, /* Locks up if polled for lun != 0 */
......
......@@ -37,6 +37,7 @@
#define ARPHRD_CSLIP6 259
#define ARPHRD_RSRVD 260 /* Notional KISS type */
#define ARPHRD_ADAPT 264
#define ARPHRD_PPP 512
/* ARP protocol opcodes. */
#define ARPOP_REQUEST 1 /* ARP request */
......
......@@ -22,6 +22,7 @@
/* This structure gets passed by the SIOCADDRTOLD and SIOCDELRTOLD calls. */
struct old_rtentry {
unsigned long rt_genmask;
struct sockaddr rt_dst;
......@@ -44,7 +45,8 @@ struct rtentry {
struct ifnet *rt_ifp;
short rt_metric; /* +1 for binary compatibility! */
char *rt_dev; /* forcing the device at add */
unsigned long rt_mtu; /* per route MTU/Window */
unsigned long rt_mss; /* per route MTU/Window */
unsigned long rt_window; /* Window clamping */
};
......@@ -54,5 +56,14 @@ struct rtentry {
#define RTF_REINSTATE 0x0008 /* re-instate route after tmout */
#define RTF_DYNAMIC 0x0010 /* created dyn. (by redirect) */
#define RTF_MODIFIED 0x0020 /* modified dyn. (by redirect) */
#define RTF_MTU 0x0040 /* specific MSS for this route */
#define RTF_MSS 0x0040 /* specific MSS for this route */
#define RTF_WINDOW 0x0080 /* per route window clamping */
/*
* REMOVE THESE BY 1.2.0 !!!!!!!!!!!!!!!!!
*/
#define RTF_MTU RTF_MSS
#define rt_mtu rt_mss
#endif /* _LINUX_ROUTE_H */
......@@ -45,6 +45,8 @@
#include <linux/types.h>
#include <linux/ptrace.h>
#include <linux/mman.h>
#include <linux/segment.h>
#include <asm/segment.h>
/*
* Define this if things work differently on a i386 and a i486:
......@@ -678,6 +680,13 @@ int verify_area(int type, const void * addr, unsigned long size)
{
struct vm_area_struct * vma;
/* If the current user space is mapped to kernel space (for the
* case where we use a fake user buffer with get_fs/set_fs()) we
* don't expect to find the address in the user vm map.
*/
if (get_fs() == get_ds())
return 0;
for (vma = current->mm->mmap ; ; vma = vma->vm_next) {
if (!vma)
goto bad_area;
......
3c509.o de600.o 3c501.o plip.o
3c509.o de600.o de620.o 3c501.o plip.o
......@@ -839,7 +839,7 @@ static int inet_connect(struct socket *sock, struct sockaddr * uaddr,
int err;
sock->conn = NULL;
if (sock->state == SS_CONNECTING && sk->state == TCP_ESTABLISHED)
if (sock->state == SS_CONNECTING && tcp_connected(sk->state))
{
sock->state = SS_CONNECTED;
/* Connection completing after a connect/EINPROGRESS/select/connect */
......
......@@ -308,7 +308,7 @@ static void icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb,
*/
#ifdef not_a_good_idea
ip_rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_GATEWAY),
ip, 0, icmph->un.gateway, dev,0);
ip, 0, icmph->un.gateway, dev,0, 0);
break;
#endif
case ICMP_REDIR_HOST:
......@@ -324,7 +324,7 @@ static void icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb,
break;
printk("redirect from %08lx\n", source);
ip_rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_HOST | RTF_GATEWAY),
ip, 0, icmph->un.gateway, dev,0);
ip, 0, icmph->un.gateway, dev,0, 0);
break;
case ICMP_REDIR_NETTOS:
case ICMP_REDIR_HOSTTOS:
......
......@@ -1523,8 +1523,8 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
#ifdef CONFIG_IP_FORWARD
ip_forward(skb, dev, is_frag);
#else
printk("Machine %lx tried to use us as a forwarder to %lx but we have forwarding disabled!\n",
iph->saddr,iph->daddr);
/* printk("Machine %lx tried to use us as a forwarder to %lx but we have forwarding disabled!\n",
iph->saddr,iph->daddr);*/
ip_statistics.IpInAddrErrors++;
#endif
/*
......
......@@ -26,6 +26,7 @@
* identification, support for local net 0 and
* multiple datalinks <Greg Page>
* Revision 0.26: Device drop kills IPX routes via it. (needed for modules)
* Revision 0.27: Autobind <Mark Evans>
*
*
*
......@@ -640,18 +641,11 @@ static int ipx_release(struct socket *sock, struct socket *peer)
static unsigned short first_free_socketnum(void)
{
static unsigned short socketNum = 0x4000;
unsigned short startNum, foundNum = 0;
startNum = socketNum;
do {
if (ipx_find_socket(htons(socketNum)) == NULL) {
foundNum = socketNum;
}
socketNum++;
while (ipx_find_socket(htons(socketNum)) != NULL)
if (socketNum > 0x7ffc) socketNum = 0x4000;
} while (!foundNum && (socketNum != startNum));
return htons(foundNum);
return htons(socketNum++);
}
static int ipx_bind(struct socket *sock, struct sockaddr *uaddr,int addr_len)
......@@ -736,9 +730,17 @@ static int ipx_connect(struct socket *sock, struct sockaddr *uaddr,
return(-EINVAL);
addr=(struct sockaddr_ipx *)uaddr;
if(sk->ipx_source_addr.net==0) /* Must bind first - no autobinding in this */
return -EINVAL;
if(sk->ipx_source_addr.net==0)
/* put the autobinding in */
{
struct sockaddr_ipx uaddr;
int ret;
uaddr.sipx_port = 0;
uaddr.sipx_network = 0L;
ret = ipx_bind (sock, (struct sockaddr *)&uaddr, sizeof(struct sockaddr_ipx));
if (ret != 0) return (ret);
}
sk->ipx_dest_addr.net=addr->sipx_network;
sk->ipx_dest_addr.sock=addr->sipx_port;
......@@ -970,6 +972,18 @@ static int ipx_sendto(struct socket *sock, void *ubuf, int len, int noblock,
if(usipx)
{
if(sk->ipx_source_addr.net==0)
/* put the autobinding in */
{
struct sockaddr_ipx uaddr;
int ret;
uaddr.sipx_port = 0;
uaddr.sipx_network = 0L;
ret = ipx_bind (sock, (struct sockaddr *)&uaddr, sizeof(struct sockaddr_ipx));
if (ret != 0) return (ret);
}
if(addr_len <sizeof(*usipx))
return(-EINVAL);
if(usipx->sipx_family != AF_IPX)
......
......@@ -21,6 +21,8 @@
* Alan Cox : Added BSD route gw semantics
* Alan Cox : Super /proc >4K
* Alan Cox : MTU in route table
* Alan Cox : MSS actually. Also added the window
* clamper.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
......@@ -195,7 +197,7 @@ static inline struct device * get_gw_dev(unsigned long gw)
*/
void ip_rt_add(short flags, unsigned long dst, unsigned long mask,
unsigned long gw, struct device *dev, unsigned short mtu)
unsigned long gw, struct device *dev, unsigned short mtu, unsigned long window)
{
struct rtable *r, *rt;
struct rtable **rp;
......@@ -267,12 +269,16 @@ void ip_rt_add(short flags, unsigned long dst, unsigned long mask,
rt->rt_dev = dev;
rt->rt_gateway = gw;
rt->rt_mask = mask;
rt->rt_mtu = dev->mtu;
rt->rt_mss = dev->mtu - HEADER_SIZE;
rt->rt_window = 0; /* Default is no clamping */
/* Are the MSS/Window valid ? */
if(rt->rt_flags & RTF_MTU)
rt->rt_mtu = mtu;
if(rt->rt_flags & RTF_MSS)
rt->rt_mss = mtu;
if(rt->rt_flags & RTF_WINDOW)
rt->rt_window = window;
/*
* What we have to do is loop though this until we have
......@@ -449,7 +455,7 @@ static int rt_new(struct rtentry *r)
* Add the route
*/
ip_rt_add(flags, daddr, mask, gw, dev, r->rt_mtu);
ip_rt_add(flags, daddr, mask, gw, dev, r->rt_mss, r->rt_window);
return 0;
}
......@@ -481,7 +487,7 @@ int rt_get_info(char *buffer, char **start, off_t offset, int length)
int size;
len += sprintf(buffer,
"Iface\tDestination\tGateway \tFlags\tRefCnt\tUse\tMetric\tMask\tMTU\n");
"Iface\tDestination\tGateway \tFlags\tRefCnt\tUse\tMetric\tMask\t\tMTU\tWindow\n");
pos=len;
/*
......@@ -490,10 +496,10 @@ int rt_get_info(char *buffer, char **start, off_t offset, int length)
for (r = rt_base; r != NULL; r = r->rt_next)
{
size = sprintf(buffer+len, "%s\t%08lX\t%08lX\t%02X\t%d\t%lu\t%d\t%08lX\t%d\n",
size = sprintf(buffer+len, "%s\t%08lX\t%08lX\t%02X\t%d\t%lu\t%d\t%08lX\t%d\t%lu\n",
r->rt_dev->name, r->rt_dst, r->rt_gateway,
r->rt_flags, r->rt_refcnt, r->rt_use, r->rt_metric,
r->rt_mask, (int)r->rt_mtu);
r->rt_mask, (int)r->rt_mss, r->rt_window);
len+=size;
pos+=size;
if(pos<offset)
......
......@@ -36,14 +36,15 @@ struct rtable
unsigned char rt_metric;
short rt_refcnt;
unsigned long rt_use;
unsigned short rt_mss, rt_mtu;
unsigned short rt_mss;
unsigned long rt_window;
struct device *rt_dev;
};
extern void ip_rt_flush(struct device *dev);
extern void ip_rt_add(short flags, unsigned long addr, unsigned long mask,
unsigned long gw, struct device *dev, unsigned short);
unsigned long gw, struct device *dev, unsigned short mss, unsigned long window);
extern struct rtable *ip_rt_route(unsigned long daddr, struct options *opt, unsigned long *src_addr);
extern struct rtable *ip_rt_local(unsigned long daddr, struct options *opt, unsigned long *src_addr);
extern int rt_get_info(char * buffer, char **start, off_t offset, int length);
......
......@@ -109,6 +109,7 @@ struct sock {
volatile unsigned short mss; /* current eff. mss - can change */
volatile unsigned short user_mss; /* mss requested by user in ioctl */
volatile unsigned short max_window;
unsigned long window_clamp;
unsigned short num;
volatile unsigned short cong_window;
volatile unsigned short cong_count;
......
......@@ -76,6 +76,9 @@
* Alan Cox : Move to kernel side addressing changes.
* Alan Cox : Beginning work on TCP fastpathing (not yet usable)
* Arnt Gulbrandsen: Turbocharged tcp_check() routine.
* Alan Cox : TCP fast path debugging
* Alan Cox : Window clamping
* Michael Riepe : Bug in tcp_check()
*
*
* To Fix:
......@@ -152,7 +155,7 @@
#include <asm/segment.h>
#include <linux/mm.h>
#define TCP_FASTPATH
#undef TCP_FASTPATH
#define SEQ_TICK 3
unsigned long seq_offset;
......@@ -183,8 +186,6 @@ static __inline__ int min(unsigned int a, unsigned int b)
in order to get the data we are waiting for into the memory limit.
Secondly we bin common duplicate forms at receive time
TODO: add sk->window_clamp to limit windows over the DE600 and AX.25
Better heuristics welcome
*/
......@@ -192,6 +193,8 @@ int tcp_select_window(struct sock *sk)
{
int new_window = sk->prot->rspace(sk);
if(sk->window_clamp)
new_window=min(sk->window_clamp,new_window);
/*
* two things are going on here. First, we don't ever offer a
* window less than min(sk->mss, MAX_WINDOW/2). This is the
......@@ -565,8 +568,7 @@ unsigned short tcp_check(struct tcphdr *th, int len,
adcl $0, %%ebx
movl %%edx, %%ecx
2: andl $28, %%ecx
cmpl $4, %%ecx
jb 4f
je 4f
shrl $2, %%ecx
clc
3: lodsl
......@@ -578,11 +580,13 @@ unsigned short tcp_check(struct tcphdr *th, int len,
je 5f
lodsw
addl %%eax, %%ebx
adcl $0, %%ebx
movw $0, %%ax
5: test $1, %%edx
je 6f
lodsb
addl %%eax, %%ebx
adcl $0, %%ebx
6: movl %%ebx, %%eax
shrl $16, %%eax
addw %%ax, %%bx
......@@ -2024,10 +2028,16 @@ static void tcp_conn_request(struct sock *sk, struct sk_buff *skb,
*/
rt=ip_rt_route(saddr, NULL,NULL);
if(rt!=NULL && (rt->rt_flags&RTF_WINDOW))
sk->window_clamp=rt->rt_window;
else
sk->window_clamp=0;
if (sk->user_mss)
newsk->mtu = sk->user_mss;
else if(rt!=NULL && (rt->rt_flags&RTF_MTU))
newsk->mtu = rt->rt_mtu - HEADER_SIZE;
else if(rt!=NULL && (rt->rt_flags&RTF_MSS))
newsk->mtu = rt->rt_mss - HEADER_SIZE;
else
{
#ifdef CONFIG_INET_SNARL /* Sub Nets ARe Local */
......@@ -2270,6 +2280,7 @@ static void tcp_close(struct sock *sk, int timeout)
sizeof(struct tcphdr),sk->ip_tos,sk->ip_ttl);
if (tmp < 0)
{
sk->write_seq++; /* Very important 8) */
kfree_skb(buff,FREE_WRITE);
/*
......@@ -2481,12 +2492,18 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int
if (sk->retransmits && sk->timeout == TIME_KEEPOPEN)
sk->retransmits = 0;
#if 0
/*
* Not quite clear why the +1 and -1 here, and why not +1 in next line
*/
if (after(ack, sk->sent_seq+1) || before(ack, sk->rcv_ack_seq-1))
#else
if (after(ack, sk->sent_seq) || before(ack, sk->rcv_ack_seq))
#endif
{
if(sk->debug)
printk("Ack ignored %lu %lu\n",ack,sk->sent_seq);
if (after(ack, sk->sent_seq) ||
(sk->state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT))
{
......@@ -2841,6 +2858,7 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int
if (sk->state == TCP_FIN_WAIT1)
{
if (!sk->dead)
sk->state_change(sk);
if (sk->rcv_ack_seq == sk->write_seq)
......@@ -2866,6 +2884,7 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int
if (sk->state == TCP_CLOSING)
{
if (!sk->dead)
sk->state_change(sk);
if (sk->rcv_ack_seq == sk->write_seq)
......@@ -2974,10 +2993,12 @@ static int tcp_data(struct sk_buff *skb, struct sock *sk,
sk->state_change(sk);
return(0);
}
#if 0
/* Discard the frame here - we've already proved its a duplicate */
kfree_skb(skb, FREE_READ);
return(0);
#endif
}
/*
* Now we have to walk the chain, and figure out where this one
......@@ -3524,10 +3545,15 @@ static int tcp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
t1->doff = 6;
/* use 512 or whatever user asked for */
if(rt!=NULL && (rt->rt_flags&RTF_WINDOW))
sk->window_clamp=rt->rt_window;
else
sk->window_clamp=0;
if (sk->user_mss)
sk->mtu = sk->user_mss;
else if(rt!=NULL && rt->rt_flags&RTF_MTU)
sk->mtu = rt->rt_mtu;
else if(rt!=NULL && (rt->rt_flags&RTF_MTU))
sk->mtu = rt->rt_mss;
else
{
#ifdef CONFIG_INET_SNARL
......@@ -3779,7 +3805,7 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
*/
/* Im trusting gcc to optimise this sensibly... might need judicious application of a software mallet */
if(!(sk->shutdown & RCV_SHUTDOWN) && sk->state==TCP_ESTABLISHED && !th->urg && !th->syn && !th->fin && !th->rst && !th->urg)
if(!(sk->shutdown & RCV_SHUTDOWN) && sk->state==TCP_ESTABLISHED && !th->urg && !th->syn && !th->fin && !th->rst)
{
/* Packets in order. Fits window */
if(th->seq == sk->acked_seq+1 && sk->window && tcp_clean_end(sk))
......@@ -3804,7 +3830,7 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
sk->window-=skb->len; /* We know its effect on the window */
else
sk->window=0;
sk->acked_seq = th->ack_seq; /* Easy */
sk->acked_seq = th->seq+skb->len; /* Easy */
skb->acked=1; /* Guaranteed true */
if(!sk->delay_acks || sk->ack_backlog >= sk->max_ack_backlog ||
sk->bytes_rcv > sk->max_unacked)
......@@ -3939,13 +3965,14 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
return(0);
}
if (th->fin && tcp_fin(skb, sk, th, saddr, dev)) {
if (tcp_data(skb, sk, saddr, len)) {
kfree_skb(skb, FREE_READ);
release_sock(sk);
return(0);
}
if (tcp_data(skb, sk, saddr, len)) {
if (th->fin && tcp_fin(skb, sk, th, saddr, dev)) {
kfree_skb(skb, FREE_READ);
release_sock(sk);
return(0);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment