From cbb79dc19652758ed1a538e203666352c4791861 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:09:32 -0500 Subject: [PATCH] Import 1.1.22 --- Makefile | 2 +- config.in | 64 ++- drivers/block/hd.c | 2 + drivers/char/console.c | 55 ++- drivers/net/3c505.c | 941 ++++++++++++++++++++++++++++++++++++++++ drivers/net/3c505.h | 124 ++++++ drivers/net/3c509.c | 4 +- drivers/net/ac32000.c | 275 ++++++++++++ drivers/net/depca.c | 461 +++++++++++--------- drivers/net/depca.h | 20 + drivers/net/e2100.c | 341 +++++++++++++++ drivers/net/loopback.c | 2 +- drivers/net/znote.c | 947 +++++++++++++++++++++++++++++++++++++++++ drivers/scsi/scsi.c | 1 + include/linux/if_arp.h | 1 + include/linux/route.h | 15 +- mm/memory.c | 9 + modules/NET_MODULES | 2 +- net/inet/af_inet.c | 2 +- net/inet/icmp.c | 4 +- net/inet/ip.c | 4 +- net/inet/ipx.c | 38 +- net/inet/route.c | 22 +- net/inet/route.h | 5 +- net/inet/sock.h | 1 + net/inet/tcp.c | 59 ++- 26 files changed, 3123 insertions(+), 278 deletions(-) create mode 100644 drivers/net/3c505.c create mode 100644 drivers/net/3c505.h create mode 100644 drivers/net/ac32000.c create mode 100644 drivers/net/e2100.c create mode 100644 drivers/net/znote.c diff --git a/Makefile b/Makefile index d884c14786b0..1e9fd91825f9 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 1 PATCHLEVEL = 1 -SUBLEVEL = 21 +SUBLEVEL = 22 all: Version zImage diff --git a/config.in b/config.in index d0ea821496ea..b90ab874a796 100644 --- a/config.in +++ b/config.in @@ -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 diff --git a/drivers/block/hd.c b/drivers/block/hd.c index 7dabb9e9b9ea..abe91d0cd1d2 100644 --- a/drivers/block/hd.c +++ b/drivers/block/hd.c @@ -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; } diff --git a/drivers/char/console.c b/drivers/char/console.c index 532e54169901..4c43aee99430 100644 --- a/drivers/char/console.c +++ b/drivers/char/console.c @@ -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); diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c new file mode 100644 index 000000000000..02eb824d32fe --- /dev/null +++ b/drivers/net/3c505.c @@ -0,0 +1,941 @@ +/* + * 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, + * Linux 3C509 driver by: + * Donald Becker, + * 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, + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef port_read +#include "iow.h" +#endif + +#include +#include +#include + +#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; +} + diff --git a/drivers/net/3c505.h b/drivers/net/3c505.h new file mode 100644 index 000000000000..727f03b88a95 --- /dev/null +++ b/drivers/net/3c505.h @@ -0,0 +1,124 @@ +/***************************************************************** + * + * 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 +}; + diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index 1385fddf5576..f4d03f08cb07 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -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; diff --git a/drivers/net/ac32000.c b/drivers/net/ac32000.c new file mode 100644 index 000000000000..1e22eb2a4ce6 --- /dev/null +++ b/drivers/net/ac32000.c @@ -0,0 +1,275 @@ +/* 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 +#include +#include +#include +#include +#include +#include + +#include +#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: + */ diff --git a/drivers/net/depca.c b/drivers/net/depca.c index 24351b727742..986f82a9e872 100644 --- a/drivers/net/depca.c +++ b/drivers/net/depca.c @@ -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 @@ -59,14 +61,15 @@ the filter bit positions correctly. Hash filtering is not yet implemented in the current driver set. - The original DEPCA card requires that the ethernet ROM address counter + The original DEPCA card requires that the ethernet ROM address counter 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 + 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 + 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 #include @@ -148,7 +157,6 @@ static char *version = "depca.c:v0.35 3/8/94 davies@wanton.lkg.dec.com\n"; #include #include -#include "iow.h" /* left in for pl13/14 compatibility... */ #include #include #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,96 +315,26 @@ 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); } } else if (base_addr > 0) { /* Don't probe at all. */ - status = -ENXIO; + 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) { @@ -436,11 +382,16 @@ depca_probe1(struct device *dev, short ioaddr) } } - if (*name != (char)NULL) { /* found a DEPCA device */ + if (*name != (char)NULL) { /* found a DEPCA device */ 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)); } @@ -481,27 +432,32 @@ depca_probe1(struct device *dev, short ioaddr) } /* - ** Determine the base address for the DEPCA RAM from the NI-CSR - ** and make up a DEPCA-specific-data structure. + ** Determine the base address for the DEPCA RAM from the NI-CSR + ** and make up a DEPCA-specific-data structure. */ 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. + ** Enable the shadow RAM. */ - nicsr |= SHE; - PUT_NICSR(nicsr, DEPCA_NICSR); + if (strstr(name,"DEPCA")==(char *)NULL) { + nicsr |= SHE; + 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; @@ -644,7 +598,7 @@ depca_probe1(struct device *dev, short ioaddr) dev->mem_start = 0; /* Fill in the generic field of the device structure. */ - ether_setup(dev); + ether_setup(dev); } } 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,54 +888,52 @@ 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) + if (dev->interrupt) printk("%s: Re-entering the interrupt handler.\n", dev->name); - dev->interrupt = MASK_INTERRUPTS; + dev->interrupt = MASK_INTERRUPTS; - /* mask the DEPCA board interrupts and turn on the LED */ - GET_NICSR(nicsr, DEPCA_NICSR); - nicsr |= (IM|LED); - PUT_NICSR(nicsr, DEPCA_NICSR); + /* mask the DEPCA board interrupts and turn on the LED */ + nicsr = inb(DEPCA_NICSR); + nicsr |= (IM|LED); + outb(nicsr, DEPCA_NICSR); - outw(CSR0, DEPCA_ADDR); - csr0 = inw(DEPCA_DATA); + outw(CSR0, DEPCA_ADDR); + csr0 = inw(DEPCA_DATA); - /* Acknowledge all of the current interrupt sources ASAP. */ - outw(csr0 & ~(INEA|TDMD|STOP|STRT|INIT), DEPCA_DATA); + /* Acknowledge all of the current interrupt sources ASAP. */ + outw(csr0 & ~(INEA|TDMD|STOP|STRT|INIT), DEPCA_DATA); - if (depca_debug > 5) + if (depca_debug > 5) printk("%s: interrupt csr0=%#2.2x new csr=%#2.2x.\n", dev->name, csr0, inw(DEPCA_DATA)); - if (csr0 & RINT) /* Rx interrupt (packet arrived) */ + if (csr0 & RINT) /* Rx interrupt (packet arrived) */ depca_rx(dev); - if (csr0 & TINT) /* Tx interrupt (packet sent) */ + if (csr0 & TINT) /* Tx interrupt (packet sent) */ depca_tx(dev); - /* Clear the interrupts we've handled. */ - outw(CSR0, DEPCA_ADDR); - outw(BABL|CERR|MISS|MERR|RINT|TINT|IDON|INEA, DEPCA_DATA); + /* Clear the interrupts we've handled. */ + outw(CSR0, DEPCA_ADDR); + outw(BABL|CERR|MISS|MERR|RINT|TINT|IDON|INEA, DEPCA_DATA); - if (depca_debug > 4) { - printk("%s: exiting interrupt, csr%d=%#4.4x.\n", - dev->name, inw(DEPCA_ADDR), - inw(DEPCA_DATA)); - } + if (depca_debug > 4) { + printk("%s: exiting interrupt, csr%d=%#4.4x.\n", + dev->name, inw(DEPCA_ADDR), + inw(DEPCA_DATA)); + } - /* Unmask the DEPCA board interrupts and turn off the LED */ - nicsr = (nicsr & ~IM & ~LED); - PUT_NICSR(nicsr, DEPCA_NICSR); + /* Unmask the DEPCA board interrupts and turn off the LED */ + nicsr = (nicsr & ~IM & ~LED); + outb(nicsr, DEPCA_NICSR); + dev->interrupt = UNMASK_INTERRUPTS; + } - 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 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. diff --git a/drivers/net/depca.h b/drivers/net/depca.h index 531211836dc2..a3a30a8aa9cf 100644 --- a/drivers/net/depca.h +++ b/drivers/net/depca.h @@ -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 */ diff --git a/drivers/net/e2100.c b/drivers/net/e2100.c new file mode 100644 index 000000000000..b8927d3ad4ae --- /dev/null +++ b/drivers/net/e2100.c @@ -0,0 +1,341 @@ +/* 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 +#include +#include +#include +#include +#include +#include +#ifndef PRE_PL13 +#include /* Delete if your kernel doesn't have it. */ +#endif + +#include +#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: + */ diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index f95a7cede16f..20908d605896 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -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"); diff --git a/drivers/net/znote.c b/drivers/net/znote.c new file mode 100644 index 000000000000..9586693a5a2e --- /dev/null +++ b/drivers/net/znote.c @@ -0,0 +1,947 @@ +/* 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#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 . */ +#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: + */ diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 724155152881..93b01764314d 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -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 */ diff --git a/include/linux/if_arp.h b/include/linux/if_arp.h index ffe9d3e86458..c62fdcebae5e 100644 --- a/include/linux/if_arp.h +++ b/include/linux/if_arp.h @@ -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 */ diff --git a/include/linux/route.h b/include/linux/route.h index 2fc76e89ab97..454917a0cfcc 100644 --- a/include/linux/route.h +++ b/include/linux/route.h @@ -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 */ diff --git a/mm/memory.c b/mm/memory.c index 711917f61909..ab511b9610f0 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -45,6 +45,8 @@ #include #include #include +#include +#include /* * 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; diff --git a/modules/NET_MODULES b/modules/NET_MODULES index d8e7ca0ea1bd..d7da20136414 100644 --- a/modules/NET_MODULES +++ b/modules/NET_MODULES @@ -1 +1 @@ -3c509.o de600.o 3c501.o plip.o +3c509.o de600.o de620.o 3c501.o plip.o diff --git a/net/inet/af_inet.c b/net/inet/af_inet.c index e52587de515f..f6062c5dabb0 100644 --- a/net/inet/af_inet.c +++ b/net/inet/af_inet.c @@ -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 */ diff --git a/net/inet/icmp.c b/net/inet/icmp.c index db42b6154d44..46caae53256a 100644 --- a/net/inet/icmp.c +++ b/net/inet/icmp.c @@ -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: diff --git a/net/inet/ip.c b/net/inet/ip.c index 61f0acf49523..7c6222b3a49b 100644 --- a/net/inet/ip.c +++ b/net/inet/ip.c @@ -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 /* diff --git a/net/inet/ipx.c b/net/inet/ipx.c index 1f450f878bfd..9de5d3eec8f7 100644 --- a/net/inet/ipx.c +++ b/net/inet/ipx.c @@ -26,6 +26,7 @@ * identification, support for local net 0 and * multiple datalinks * Revision 0.26: Device drop kills IPX routes via it. (needed for modules) + * Revision 0.27: Autobind * * * @@ -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 sipx_family != AF_IPX) diff --git a/net/inet/route.c b/net/inet/route.c index 617295d5076d..4ea8dfb09c74 100644 --- a/net/inet/route.c +++ b/net/inet/route.c @@ -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 #include -#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 @@ -3523,11 +3544,16 @@ static int tcp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len) t1->urg_ptr = 0; 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,17 +3965,18 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, return(0); } - if (th->fin && tcp_fin(skb, sk, th, saddr, dev)) { - kfree_skb(skb, FREE_READ); - release_sock(sk); - return(0); - } if (tcp_data(skb, sk, saddr, len)) { kfree_skb(skb, FREE_READ); release_sock(sk); return(0); } + + if (th->fin && tcp_fin(skb, sk, th, saddr, dev)) { + kfree_skb(skb, FREE_READ); + release_sock(sk); + return(0); + } release_sock(sk); return(0); -- 2.39.5