add directory net

This commit is contained in:
gohigh
2024-02-19 00:25:04 -05:00
parent a778c607a4
commit 9ad4ff3d15
95 changed files with 15535 additions and 0 deletions

5
net/tcpip/README.hostcvt Normal file
View File

@@ -0,0 +1,5 @@
This is a copy of hostcvt compiled for linux. It helps to convert
from /etc/hosts to named configuration files.
It may not be used to make money, so I don't think you can charge to
redistribute this.

7
net/tcpip/README.inetd Normal file
View File

@@ -0,0 +1,7 @@
inetd.tar.Z has the following files in it
inetd (put in /usr/etc/inet)
inetd.8 (put in /usr/man/man8)
inetd-diffs
The diffs only include changes to the *.[ch] files. You will need to
edit the makefile to recompile inetd.

13
net/tcpip/README.named Normal file
View File

@@ -0,0 +1,13 @@
named-bin.tar.Z consists of the following files:
named (put in /usr/etc/inet)
named-xfer (put in /usr/etc/int)
nsquery (put in /usr/bin or /usr/etc/inet)
nslookup (put in /usr/bin or /usr/etc/inet)
named.8 (put in /usr/man/man8)
nslookup.1 (put in /usr/man/man1)
named-diffs
nslkp.diffs
The diff files only include changes to the *.[ch] files. You
will need to edit the makefiles yourself and you may need to include
the file res/res_debug.c.

View File

@@ -0,0 +1,3 @@
This is the third tcp patch to 0.98pl5. All three go in without any problem.
This one fixes raw sockets and a few other minor problems.

View File

@@ -0,0 +1,6 @@
This patch was made against pl4 + tcp diffs I sent to Linus. You may need
to apply some of them by hand.
Ross Biro bir7@leland.stanford.edu
Member League for Programming Freedom (LPF)
mail lpf@uunet.uu.net for information

View File

@@ -0,0 +1,7 @@
This diff fixes some problems with the first diff, and corrects a few
error returns. Hopefully some of the problems with accept, connect,
and shutdown should have vanished. Again these are not really against
pl5 but against pl4 + some of the pl5 diffs + patch1. You may need to
do these by hand also.

View File

@@ -0,0 +1,3 @@
This is the same BUGGY version of telnetd that was in earlier
releases. It has been recompiled to use a newer library and to
work with .98pl5. We still need a new version.

View File

@@ -0,0 +1,11 @@
From: "pb@cs" <100136.3530@compuserve.com>
To: <arl@cs.hut.fi>
Subject: new depca-0.7 for pl13
Date: 26 Sep 93 18:31:24 EDT
Find enclosed depca-0.7. This version patches against the limux99pl13
kernel sources and shoud go where the other depca-driver went (I think
somewhere in Linux/BETA/depca). From the older versions there only the
0.5 version is worth keeping, because it patches against pl10 and 11.
Gruss PB

BIN
net/tcpip/depca-0.7.tar.z Normal file

Binary file not shown.

347
net/tcpip/ether-995/3c503.c Normal file
View File

@@ -0,0 +1,347 @@
/* 3c503.c: A shared-memory NS8390 ethernet driver for linux. */
/*
Written 1992,1993 by Donald Becker. This is alpha test code.
This is a extension to the Linux operating system, and is covered by
same Gnu Public License that covers that work.
This driver should work with the 3c503 and 3c503/16. It must be used
in shared memory mode.
The Author may be reached as becker@super.org or
C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
*/
static char *version = "3c503.c:v0.30 1/30/93 Donald Becker (becker@super.org)\n";
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <asm/io.h>
#include <asm/system.h>
#include "dev.h"
#include "8390.h"
#include "3c503reg.h"
extern void NS8390_init(struct device *dev, int startp);
extern int ei_debug;
extern struct sigaction ei_sigaction;
extern struct ei_device ei_status;
int etherlink2 = 0;
int el2autoprobe(int ioaddr, struct device *dev);
int el2probe(int ioaddr, struct device *dev);
static void el2_reset_8390(struct device *dev);
static void el2_init_card(struct device *dev);
static void el2_block_output(struct device *dev, int count,
const unsigned char *buf, const start_page);
static int el2_block_input(struct device *dev, int count, char *buf,
int ring_offset);
int
el2autoprobe(int ioaddr, struct device *dev)
{
int *addr, addrs[] = { 0xddfff, 0xd9fff, 0xcdfff, 0xc9fff, 0};
int ports[] = {0, 0x300, 0x310, 0x330, 0x350, 0x250, 0x280, 0x2a0, 0x2e0, 0};
/* Non-autoprobe case first: */
if (ioaddr > 0)
return el2probe(ioaddr, dev);
/* We check for a memory-mapped 3c503 board by looking at the
end of boot PROM space (works even if a PROM isn't there). */
for (addr = addrs; *addr; addr++) {
unsigned int base_bits = *(unsigned char *)*addr, i;
/* Find first set bit. */
for(i = 8; i; i--, base_bits >>= 1)
if (base_bits & 0x1)
break;
if (base_bits == 1 && el2probe(ports[i], dev))
return dev->base_addr;
}
#ifdef notdef
/* If it's not memory mapped, we don't care to find it. I haven't
tested the non-memory-mapped code. */
/* It's not memory mapped -- try all of the locations that aren't
obviously empty. */
{ int *port;
for (port = &ports[1]; *port; port++)
if (inb_p(*port) != 0xff && el2probe(*port, dev))
return dev->base_addr = *port;
}
#endif
return 0;
}
/* Probe for the Etherlink II card at I/O port base IOADDR,
returning non-zero on sucess. If found, set the station
address and memory parameters in DEVICE. */
int
el2probe(int ioaddr, struct device *dev)
{
int i, found, mem_jumpers;
unsigned char *station_addr = dev->dev_addr;
/* We verify that it's a 3C503 board by checking the first three octets
of its ethernet address. */
printk("3c503 probe at %#3x:", ioaddr);
outb_p(ECNTRL_RESET|ECNTRL_THIN, ioaddr + 0x406); /* Reset it... */
outb_p(ECNTRL_THIN, ioaddr + 0x406);
/* Map the station addr PROM into the lower I/O ports. */
outb(ECNTRL_SAPROM|ECNTRL_THIN, ioaddr + 0x406);
for (i = 0; i < ETHER_ADDR_LEN; i++) {
printk(" %2.2X", (station_addr[i] = inb(ioaddr + i)));
}
/* Map the 8390 back into the window. */
outb(ECNTRL_THIN, ioaddr + 0x406);
found =( station_addr[0] == 0x02
&& station_addr[1] == 0x60
&& station_addr[2] == 0x8c);
if (! found) {
printk(" 3C503 not found.\n");
return 0;
}
dev->base_addr = ioaddr;
/* Probe for, turn on and clear the board's shared memory. */
mem_jumpers = inb(ioaddr + 0x404); /* E33G_ROMBASE */
if (ei_debug > 2) printk(" memory jumpers %2.2x ", mem_jumpers);
outb(EGACFR_IRQOFF, ioaddr + 0x405); /* Enable RAM */
if ((mem_jumpers & 0xf0) == 0) {
dev->mem_start = 0;
if (ei_debug > 1) printk(" no shared memory ");
} else {
dev->mem_start = ((mem_jumpers & 0xc0) ? 0xD8000 : 0xC8000) +
((mem_jumpers & 0xA0) ? 0x4000 : 0);
#define EL2_MEMSIZE (EL2SM_STOP_PG - EL2SM_START_PG)*256
#ifdef EL2MEMTEST
{ /* Check the card's memory. */
int *mem_base = (int *)dev->mem_start;
int memtest_value = 0xbbadf00d;
mem_base[0] = 0xba5eba5e;
for (i = 1; i < EL2_MEMSIZE/sizeof(mem_base[0]); i++) {
mem_base[i] = memtest_value;
if (mem_base[0] != 0xba5eba5e
|| mem_base[i] != memtest_value) {
printk(" memory failure or memory address conflict.\n");
dev->mem_start = 0;
break;
}
memtest_value += 0x55555555;
mem_base[i] = 0;
}
}
#endif /* EL2MEMTEST */
/* Divide the on-board memory into a single maximum-sized transmit
(double-sized for ping-pong transmit) buffer at the base, and
use the rest as a receive ring. */
dev->mem_end = dev->rmem_end = dev->mem_start + EL2_MEMSIZE;
dev->rmem_start = TX_PAGES*256 + dev->mem_start;
}
if (ei_debug > 2)
printk("\n3c503: memory params start=%#5x rstart=%#5x end=%#5x rend=%#5x.\n",
dev->mem_start, dev->rmem_start, dev->mem_end, dev->rmem_end);
/* Finish setting the board's parameters. */
etherlink2 = 1;
ei_status.tx_start_page = EL2SM_START_PG;
ei_status.rx_start_page = EL2SM_START_PG + TX_PAGES;
ei_status.stop_page = EL2SM_STOP_PG;
ei_status.reset_8390 = &el2_reset_8390;
ei_status.block_input = &el2_block_input;
ei_status.block_output = &el2_block_output;
/* This should be probed for (or set via an ioctl()) at run-time someday. */
#if defined(EI8390_THICK) || defined(EL2_AUI)
ei_status.thin_bit = 0;
#else
ei_status.thin_bit = ECNTRL_THIN;
#endif
if (dev->irq < 2) {
int irqlist[] = {5, 2, 3, 4, 0};
int *irqp = irqlist;
do {
if (irqaction (dev->irq = *irqp, &ei_sigaction) == 0) {
break;
}
} while (*++irqp);
if (*irqp == 0) {
printk("\n3c503: Unable to find an free IRQ line.\n");
return 0;
}
} else {
if (dev->irq == 2)
dev->irq = 9;
else if (dev->irq > 5 && dev->irq != 9) {
printk("\n3c503: configured interrupt number %d out of range.\n",
dev->irq);
return 0;
}
if (irqaction (dev->irq, &ei_sigaction)) {
printk ("\n3c503: Unable to get IRQ%d.\n", dev->irq);
return 0;
}
}
el2_init_card(dev);
if (dev->mem_start)
printk("3c503 found, memory at %#6x, IRQ %d\n",
dev->mem_start, dev->irq);
else
printk(" 3c503 found, no shared memory, IRQ %d\n", dev->irq);
if (ei_debug > 2)
printk(version);
return ioaddr;
}
/* This is called whenever we have a unrecoverable failure:
transmit timeout
Bad ring buffer packet header
*/
static void
el2_reset_8390(struct device *dev)
{
if (ei_debug > 1) printk("3c503: Resetting the board...");
outb_p(ECNTRL_RESET|ECNTRL_THIN, E33G_CNTRL);
ei_status.txing = 0;
outb_p(ei_status.thin_bit, E33G_CNTRL);
el2_init_card(dev);
if (ei_debug > 1) printk("done\n");
}
/* Initialize the 3c503 GA registers after a reset. */
static void
el2_init_card(struct device *dev)
{
/* Unmap the station PROM and select the DIX or BNC connector. */
outb_p(ei_status.thin_bit, E33G_CNTRL);
/* Set ASIC copy of rx's first and last+1 buffer pages */
/* These must be the same as in the 8390. */
outb(ei_status.rx_start_page, E33G_STARTPG);
outb(ei_status.stop_page, E33G_STOPPG);
/* Point the vector pointer registers somewhere ?harmless?. */
outb(0xff, E33G_VP2); /* Point at the ROM restart location 0xffff0 */
outb(0xff, E33G_VP1);
outb(0x00, E33G_VP0);
/* Turn off all interrupts until we're opened. */
outb_p(0x00, dev->base_addr + EN0_IMR);
outb_p(EGACFR_IRQOFF, E33G_GACFR);
/* Set the interrupt line. */
outb_p((0x04 << (dev->irq == 9 ? 2 : dev->irq)), E33G_IDCFR);
outb_p(8, E33G_DRQCNT); /* Set burst size to 8 */
outb_p(0x20, E33G_DMAAH); /* Put a valid addr in the GA DMA */
outb_p(0x00, E33G_DMAAL);
return; /* We always succeed */
}
/* Either use the shared memory (if enabled on the board) or put the packet
out through the ASIC FIFO. The latter is probably much slower. */
static void
el2_block_output(struct device *dev, int count,
const unsigned char *buf, const start_page)
{
int i; /* Buffer index */
int boguscount = 0; /* timeout counter */
if (dev->mem_start) { /* Shared memory transfer */
void *dest_addr = (void *)(dev->mem_start +
((start_page - ei_status.tx_start_page) << 8));
outb(EGACFR_NORM, E33G_GACFR); /* Enable RAM */
memcpy(dest_addr, buf, count);
if (ei_debug > 2 && memcmp(dest_addr, buf, count))
printk("3c503: send_packet() bad memory copy @ %#5x.\n",
dest_addr);
else if (ei_debug > 4)
printk("3c503: send_packet() good memory copy @ %#5x.\n",
dest_addr);
return;
}
/* Set up then start the internal memory transfer to Tx Start Page */
outb(0x00, E33G_DMAAL);
outb(start_page, E33G_DMAAH);
outb(ei_status.thin_bit | ECNTRL_OUTPUT | ECNTRL_START, E33G_CNTRL);
/* This is the byte copy loop: it should probably be tuned for
for speed once everything is working. I think it is possible
to output 8 bytes between each check of the status bit. */
for(i = 0; i < count; i++) {
if (count % 8 == 7)
while ((inb(E33G_STATUS) & ESTAT_DPRDY) == 0)
if (++boguscount > 32) {
printk(EI_NAME": fifo blocked in el2_block_output.\n");
return;
}
outb(buf[i], E33G_FIFOH);
}
outb(ei_status.thin_bit, E33G_CNTRL);
return;
}
/* Returns the new ring pointer. */
static int
el2_block_input(struct device *dev, int count, char *buf, int ring_offset)
{
int boguscount = 0;
int end_of_ring = dev->rmem_end;
ring_offset -= (EL2SM_START_PG<<8);
/* Maybe enable shared memory just be to be safe... nahh.*/
if (dev->mem_start) { /* Use the shared memory. */
if (dev->mem_start + ring_offset + count > end_of_ring) {
/* We must wrap the input move. */
int semi_count = end_of_ring - (dev->mem_start + ring_offset);
if (ei_debug > 4)
printk("3c503: block_input() @ %#5x+%x=%5x.\n",
dev->mem_start, ring_offset,
(char *)dev->mem_start + ring_offset);
memcpy(buf, (char *)dev->mem_start + ring_offset, semi_count);
count -= semi_count;
memcpy(buf + semi_count, (char *)dev->rmem_start, count);
return dev->rmem_start + count;
}
if (ei_debug > 4)
printk("3c503: block_input() @ %#5x+%x=%5x.\n",
dev->mem_start, ring_offset,
(char *)dev->mem_start + ring_offset);
memcpy(buf, (char *)dev->mem_start + ring_offset, count);
return ring_offset + count;
} else { /* No shared memory, use the fifo. */
int i;
outb(ring_offset & 0xff, E33G_DMAAL);
outb((ring_offset >> 8) & 0xff, E33G_DMAAH);
outb(ei_status.thin_bit | ECNTRL_INPUT | ECNTRL_START, E33G_CNTRL);
/* This is the byte copy loop: it should probably be tuned for
for speed once everything is working. */
for(i = 0; i < count; i++) {
if (count % 8 == 7)
while ((inb(E33G_STATUS) & ESTAT_DPRDY) == 0)
if (++boguscount > 32) {
printk(EI_NAME": fifo blocked in el2_block_input().\n");
return 0;
}
buf[i] = inb(E33G_FIFOH);
}
outb(ei_status.thin_bit, E33G_CNTRL);
ring_offset += count;
if (ring_offset >= end_of_ring)
ring_offset = dev->rmem_start + ring_offset - end_of_ring;
return ring_offset;
}
}
/*
* Local variables:
* compile-command: "gcc -DKERNEL -Wall -O6 -fomit-frame-pointer -I/usr/src/linux/net/tcp -c 3c503.c"
* version-control: t
* kept-new-versions: 5
* End:
*/

View File

@@ -0,0 +1,59 @@
/* Definitions for the 3Com 3c503 Etherlink 2. */
/* This file is part of Donald Becker's 8390 drivers.
This file is distributed under the Linux GPL.
Some of these names and comments are from the Crynwr packet drivers. */
#define EL2H (dev->base_addr + 0x400)
#define EL2L (dev->base_addr)
/* Shared memory management parameters */
#define EL2SM_START_PG (0x20) /* First page of TX buffer */
#define EL2SM_STOP_PG (0x40) /* Last page +1 of RX ring */
/* 3Com 3c503 ASIC registers */
#define E33G_STARTPG (EL2H+0) /* Start page, must match EN0_STARTPG */
#define E33G_STOPPG (EL2H+1) /* Stop page, must match EN0_STOPPG */
#define E33G_DRQCNT (EL2H+2) /* DMA burst count */
#define E33G_IOBASE (EL2H+3) /* Read of I/O base jumpers. */
/* (non-useful, but it also appears at the end of EPROM space) */
#define E33G_ROMBASE (EL2H+4) /* Read of memory base jumpers. */
#define E33G_GACFR (EL2H+5) /* Config/setup bits for the ASIC GA */
#define E33G_CNTRL (EL2H+6) /* Board's main control register */
#define E33G_STATUS (EL2H+7) /* Status on completions. */
#define E33G_IDCFR (EL2H+8) /* Interrupt/DMA config register */
/* (Which IRQ to assert, DMA chan to use) */
#define E33G_DMAAH (EL2H+9) /* High byte of DMA address reg */
#define E33G_DMAAL (EL2H+10) /* Low byte of DMA address reg */
/* "Vector pointer" - if this address matches a read, the EPROM (rather than
shared RAM) is mapped into memory space. */
#define E33G_VP2 (EL2H+11)
#define E33G_VP1 (EL2H+12)
#define E33G_VP0 (EL2H+13)
#define E33G_FIFOH (EL2H+14) /* FIFO for programmed I/O moves */
#define E33G_FIFOL (EL2H+15) /* ... low byte of above. */
/* Bits in E33G_CNTRL register: */
#define ECNTRL_RESET (0x01) /* Software reset of the ASIC and 8390 */
#define ECNTRL_THIN (0x02) /* Onboard thin-net xcvr enable */
#define ECNTRL_SAPROM (0x04) /* Map the station address prom */
#define ECNTRL_DBLBFR (0x20) /* FIFO configuration bit */
#define ECNTRL_OUTPUT (0x40) /* PC-to-3C503 direction if 1 */
#define ECNTRL_INPUT (0x00) /* 3C503-to-PC direction if 0 */
#define ECNTRL_START (0x80) /* Start the DMA logic */
/* Bits in E33G_STATUS register: */
#define ESTAT_DPRDY (0x80) /* Data port (of FIFO) ready */
#define ESTAT_UFLW (0x40) /* Tried to read FIFO when it was empty */
#define ESTAT_OFLW (0x20) /* Tried to write FIFO when it was full */
#define ESTAT_DTC (0x10) /* Terminal Count from PC bus DMA logic */
#define ESTAT_DIP (0x08) /* DMA In Progress */
/* Bits in E33G_GACFR register: */
#define EGACFR_NORM (0x49) /* Enable 8K shared mem, no DMA TC int */
#define EGACFR_IRQOFF (0xc9) /* Above, and disable 8390 IRQ line */
/* End of 3C503 parameter definitions */

731
net/tcpip/ether-995/8390.c Normal file
View File

@@ -0,0 +1,731 @@
/* 8390.c: A general NS8390 ethernet driver core for linux. */
/*
Written 1992,1993 by Donald Becker. This is alpha test code.
This is a extension to the Linux operating system, and is covered by
same Gnu Public License that covers that work.
This driver should work with many 8390-based ethernet adaptors.
The Author may be reached as becker@super.org or
C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
*/
static char *version =
"8390.c:v0.43 2/12/93 for 0.99.5+ Donald Becker (becker@super.org)\n";
#include <linux/config.h>
#if !defined(EL2) && !defined(NE2000) && !defined(WD80x3) && !defined(HPLAN)
/* They don't know what they want -- give it all to them! */
#define EL2
#define NE2000
#define WD80x3
#define HPLAN
#endif
/*
Braindamage remaining:
Ethernet devices should use a chr_drv device interface, with ioctl()s to
configure the card, bring the interface up or down, allow access to
statistics, and maybe read() and write() access to raw packets.
This won't be done until after Linux 1.00.
This driver should support multiple, diverse boards simultaneousely.
This won't be done until after Linux 1.00.
Sources:
The National Semiconductor LAN Databook, and 3Com databooks, both companies
provided information readily. The NE* info came from the Crynwr packet
driver, and figuring out that the those boards are similar to the NatSemi
evaluation board described in AN-729. Thanks NS, no thanks to Novell/Eagle.
Cabletron provided only info I had already gotten from other sources -- hiss.
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/tty.h>
#include <linux/types.h>
#include <linux/ptrace.h>
#include <linux/string.h>
#include <asm/system.h>
#include <asm/segment.h>
#include <asm/io.h>
#include <errno.h>
#include <linux/fcntl.h>
#include <netinet/in.h>
#include <linux/interrupt.h>
#include "dev.h"
#include "eth.h"
#include "timer.h"
#include "ip.h"
#include "tcp.h"
#include "sock.h"
#include "arp.h"
#include "8390.h"
#define ei_reset_8390 (ei_status.reset_8390)
#define ei_block_output (ei_status.block_output)
#define ei_block_input (ei_status.block_input)
#define EN_CMD (e8390_base)
#define E8390_BASE (e8390_base)
/* use 0 for production, 1 for verification, >2 for debug */
#ifdef EI_DEBUG
int ei_debug = EI_DEBUG;
#else
int ei_debug = 2;
#endif
static int e8390_base;
static struct device *eifdev; /* For single-board consistency checking. */
extern int etherlink2;
struct ei_device ei_status = { EI_NAME, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
/* The statistics, perhaps these should be in the above structure. */
static int tx_packets = 0;
static int rx_packets = 0;
static int tx_errors = 0;
static int soft_rx_errors = 0;
static int soft_rx_err_bits = 0;
static int missed_packets = 0;
static int rx_overrun_packets = 0;
/* Max number of packets received at one Intr. */
/*static int high_water_mark = 0;*/
/* Index to functions. */
/* Put in the device structure. */
static int ei_open(struct device *dev);
static void ei_send_packet(struct sk_buff *skb, struct device *dev);
/* Dispatch from interrupts. */
static void ei_interrupt(int reg_ptr);
static void ei_tx_intr(struct device *dev);
static void ei_receive(struct device *dev);
static void ei_rx_overrun(struct device *dev);
/* Routines generic to NS8390-based boards. */
void NS8390_init(struct device *dev, int startp);
static void NS8390_trigger_send(struct device *dev, unsigned int length,
int start_page);
extern int el2autoprobe(int ioaddr, struct device *dev);
extern int el2probe(int ioaddr, struct device *dev);
extern int neprobe(int ioaddr, struct device *dev);
extern int wdprobe(int ioaddr, struct device *dev);
extern int hpprobe(int ioaddr, struct device *dev);
struct sigaction ei_sigaction = { ei_interrupt, 0, 0, NULL, };
/* Open/initialize the board. This routine goes all-out, setting everything
up anew at each open, even though many of these registers should only
need to be set once at boot.
*/
static int
ei_open(struct device *dev)
{
if ( ! ei_status.exists) {
printk(EI_NAME ": Opening a non-existent physical device\n");
return 1; /* ENXIO would be more accurate. */
}
NS8390_init(dev, 1);
/* The old local flags... */
ei_status.txing = 0;
ei_status.in_interrupt = 0;
ei_status.open = 1;
/* ... are now global. */
dev->tbusy = 0;
dev->interrupt = 0;
dev->start = 1;
return 0;
}
static int
ei_start_xmit(struct sk_buff *skb, struct device *dev)
{
if ( ! ei_status.exists)
return 0; /* We should be able to do ENODEV, but nooo. */
if (ei_status.txing) { /* Do timeouts, just like the 8003 driver. */
int txsr = inb(E8390_BASE+EN0_TSR);
int tickssofar = jiffies - dev->trans_start;
if (tickssofar < 5 || (tickssofar < 15 && ! (txsr & ENTSR_PTX))) {
return 1;
}
printk(EI_NAME": transmit timed out, TX status %#2x, ISR %#2x.\n",
txsr, inb(E8390_BASE+EN0_ISR));
/* It's possible to check for an IRQ conflict here.
I may have to do that someday. */
if ((txsr & ~0x02) == ENTSR_PTX) /* Strip an undefined bit. */
printk(EI_NAME": Possible IRQ conflict?\n");
else
printk(EI_NAME": Possible network cable problem?\n");
/* It futile, but try to restart it anyway. */
ei_reset_8390(dev);
NS8390_init(dev, 1);
}
/* This is new: it means some higher layer thinks we've missed an
tx-done interrupt. Caution: dev_tint() handles the cli()/sti()
itself. */
if (skb == NULL) {
#ifdef pre_995
/* Alternative is ei_tx_intr(dev); */
ei_status.txing = 1;
if (dev_tint(NULL, dev) == 0)
ei_status.txing = 0;
#else
dev_tint(dev);
#endif
return 0;
}
/* Fill in the ethernet header. */
if (!skb->arp && dev->rebuild_header(skb+1, dev)) {
skb->dev = dev;
arp_queue (skb);
return 0;
}
dev->trans_start = jiffies;
cli();
#ifdef PINGPONG
ei_tx_intr(dev);
#endif
ei_send_packet(skb, dev);
sti();
if (skb->free)
kfree_skb (skb, FREE_WRITE);
return 0;
}
/* The typical workload of the driver:
Handle the ether interface interrupts. */
static void
ei_interrupt(int reg_ptr)
{
int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2);
struct device *dev;
int interrupts, boguscount = 0;
/* We do the same thing as the 8013 driver, but this is mostly bogus. */
for (dev = dev_base; dev != NULL; dev = dev->next) {
if (dev->irq == irq) break;
}
dev->interrupt = 1;
ei_status.in_interrupt++;
sti(); /* Allow other interrupts. */
#ifdef notneeded
/* If we a getting a reset-complete interrupt the 8390 might not be
mapped in for the 3c503. */
if (etherlink2)
outb_p(ei_status.thin_bit, E33G_CNTRL),
outb_p(0x00, E33G_STATUS);
#endif
/* Change to page 0 and read the intr status reg. */
outb_p(E8390_NODMA+E8390_PAGE0, EN_CMD);
if (ei_debug > 3)
printk(EI_NAME": interrupt(isr=%#2.2x).\n",
inb_p(E8390_BASE + EN0_ISR));
if (ei_status.in_interrupt > 1)
printk(EI_NAME ": Reentering the interrupt driver!\n");
if (dev == NULL) {
printk (EI_NAME ": irq %d for unknown device\n", irq);
ei_status.in_interrupt--;
return;
} else if (ei_debug > 0 && eifdev != dev) {
printk (EI_NAME": device mismatch on irq %d.\n", irq);
dev = eifdev;
}
/* !!Assumption!! -- we stay in page 0. Don't break this. */
while ((interrupts = inb_p(E8390_BASE + EN0_ISR)) != 0
&& ++boguscount < 20) {
/* The reset interrupt is the most important... */
if (interrupts & ENISR_RDC) {
outb_p(ENISR_RDC, E8390_BASE + EN0_ISR); /* Ack intr. */
}
if (interrupts & ENISR_OVER) {
ei_status.overruns++;
ei_rx_overrun(dev);
} else if (interrupts & (ENISR_RX+ENISR_RX_ERR)) {
/* Got a good (?) packet. */
ei_receive(dev);
}
/* Push the next to-transmit packet through. */
if (interrupts & ENISR_TX) {
ei_tx_intr(dev);
} else if (interrupts & ENISR_COUNTERS) {
/* Gotta read the counter to clear the irq, even if we
don't care about their values. */
inb_p(E8390_BASE + EN0_COUNTER0);
inb_p(E8390_BASE + EN0_COUNTER1);
missed_packets += inb_p(E8390_BASE + EN0_COUNTER2);
outb_p(ENISR_COUNTERS, E8390_BASE + EN0_ISR); /* Ack intr. */
outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START, EN_CMD);
}
/* Ignore the transmit errs and reset intr for now. */
if (interrupts & ENISR_TX_ERR) {
outb_p(ENISR_TX_ERR, E8390_BASE + EN0_ISR); /* Ack intr. */
}
outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START, EN_CMD);
}
if (interrupts && ei_debug) {
printk(EI_NAME ": unknown interrupt %#2x\n", interrupts);
outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, EN_CMD);
outb_p(0xff, E8390_BASE + EN0_ISR); /* Ack. all intrs. */
}
ei_status.in_interrupt--;
return;
}
#ifdef PINGPONG
static int lasttx = 0;
#endif
/* This is stuffed into the dev struct to be called by dev.c:dev_tint().
Evenually this should be replaced by the block_output() routines. */
static void
ei_send_packet(struct sk_buff *skb, struct device *dev)
{
int length = skb->len;
int send_length = ETHER_MIN_LEN < length ? length : ETHER_MIN_LEN;
if (length <= 0)
return;
#ifdef PINGPONG
if (ei_status.tx1 == 0) { /* First buffer empty */
ei_block_output(dev, length, (void*)(skb+1),
ei_status.tx_start_page);
ei_status.tx1 = send_length;
} else if (ei_status.tx2 == 0) { /* Second buffer empty */
ei_block_output(dev, length, (void*)(skb+1),
ei_status.tx_start_page+6);
ei_status.tx2 = send_length;
} else {
printk("%s: Internal error, no transmit buffer space tx1=%d tx2=%d lasttx=%d.\n",
ei_status.name, ei_status.tx1, ei_status.tx2, lasttx);
}
ei_status.txqueue++;
/* The following should be merged with ei_tx_intr(). */
if (lasttx = 0) {
if (ei_status.tx1 > 0) {
NS8390_trigger_send(dev, ei_status.tx1,
ei_status.tx_start_page + 6),
ei_status.tx1 = -1,
lasttx = 1;
} else if (ei_status.tx2 > 0) {
NS8390_trigger_send(dev, ei_status.tx2,
ei_status.tx_start_page + 6),
ei_status.tx2 = -1,
lasttx = 2;
}
}
#else
ei_block_output(dev, length, (void*)(skb+1), ei_status.tx_start_page);
NS8390_trigger_send(dev, send_length, ei_status.tx_start_page);
#endif
return;
}
/* We have finished a transmit: check for errors and then trigger the next
packet to be sent. */
static void
ei_tx_intr(struct device *dev)
{
int status = inb(E8390_BASE + EN0_TSR);
outb_p(ENISR_TX, E8390_BASE + EN0_ISR); /* Ack intr. */
if ((status & ENTSR_PTX) == 0)
tx_errors++;
else
tx_packets++;
#ifdef PINGPONG
ei_status.txqueue--;
if (ei_status.tx1 < 0) {
uif (lasttx != 1)
printk("%s: bogus last_tx_buffer %d, tx1=%d.\n",
ei_status.name, lasttx, ei_status.tx1);
ei_status.tx1 = 0;
lasttx = 0;
if (ei_status.tx2 > 0) {
NS8390_trigger_send(dev, ei_status.tx2,
ei_status.tx_start_page + 6),
ei_status.tx2 = -1,
lasttx = 2;
}
} else if (ei_status.tx2 < 0) {
if (lasttx != 2)
printk("%s: bogus last_tx_buffer %d, tx2=%d.\n",
ei_status.name, lasttx, ei_status.tx2);
ei_status.tx2 = 0;
lasttx = 0;
if (ei_status.tx1 > 0) {
NS8390_trigger_send(dev, ei_status.tx1,
ei_status.tx_start_page),
ei_status.tx1 = -1;
lasttx = 1;
}
} /*else
printk(EI_NAME": unexpected TX interrupt.\n");*/
while ((ei_status.tx1 == 0) || (ei_status.tx2 == 0)) {
dev->tbusy = 0;
dev_tint(dev);
if (dev->tbusy)
return;
else if (lasttx == 0) {
if (ei_status.tx1 == 0 || ei_status.tx2 != 0)
printk(EI_NAME": Unexpected tx buffer busy tx1=%d tx2=%d.\n",
ei_status.tx1, ei_status.tx2);
NS8390_trigger_send(dev, ei_status.tx1,
ei_status.tx_start_page),
ei_status.tx1 = -1;
lasttx = 1;
}
}
#else
ei_status.txing = 0;
dev->tbusy = 0;
#ifdef pre_995
dev_tint(NULL, dev)
#else
mark_bh (INET_BH);
#endif
#endif
}
/* We have a good packet(s), get it/them out of the buffers. */
static void
ei_receive(struct device *dev)
{
int rxing_page, this_frame, next_frame, current_offset;
int boguscount = 0;
struct e8390_pkt_hdr rx_frame;
int num_rx_pages = ei_status.stop_page-ei_status.rx_start_page;
while (++boguscount < 10) {
int size;
cli();
outb_p(E8390_NODMA+E8390_PAGE1, EN_CMD); /* Get the rec. page. */
rxing_page = inb_p(E8390_BASE+EN1_CURPAG);/* (Incoming packet pointer).*/
outb_p(E8390_NODMA+E8390_PAGE0, EN_CMD);
sti();
/* Remove one frame from the ring. Boundary is alway a page behind. */
this_frame = inb_p(E8390_BASE + EN0_BOUNDARY) + 1;
if (this_frame >= ei_status.stop_page)
this_frame = ei_status.rx_start_page;
/* Someday we'll omit the previous step, iff we never get this message.*/
if (ei_debug > 0 && this_frame != ei_status.current_page)
printk(EI_NAME": mismatched read page pointers %2x vs %2x.\n",
this_frame, ei_status.current_page);
if (this_frame == rxing_page) /* Read all the frames? */
break; /* Done for now */
current_offset = this_frame << 8;
ei_block_input(dev, sizeof(rx_frame), (void *)&rx_frame,
current_offset);
size = rx_frame.count - sizeof(rx_frame);
next_frame = this_frame + 1 + ((size+4)>>8);
/* Check for bogosity warned by 3c503 book: the status byte is never
written. This happened a lot during testing! This code should be
cleaned up someday, and the printk()s should be PRINTK()s. */
if ( rx_frame.next != next_frame
&& rx_frame.next != next_frame + 1
&& rx_frame.next != next_frame - num_rx_pages
&& rx_frame.next != next_frame + 1 - num_rx_pages) {
#ifndef EI_DEBUG
ei_status.current_page = rxing_page;
outb(ei_status.current_page-1, E8390_BASE+EN0_BOUNDARY);
continue;
#else
static int last_rx_bogosity = -1;
printk(EI_NAME": bogus packet header, status=%#2x nxpg=%#2x sz=%#x (at %#4x)\n",
rx_frame.status, rx_frame.next, rx_frame.count, current_offset);
if (rx_packets != last_rx_bogosity) {
/* Maybe we can avoid resetting the chip... empty the packet ring. */
ei_status.current_page = rxing_page;
printk(EI_NAME": setting next frame to %#2x (nxt=%#2x, rx_frm.nx=%#2x rx_frm.stat=%#2x).\n",
ei_status.current_page, next_frame,
rx_frame.next, rx_frame.status);
last_rx_bogosity = rx_packets;
outb(ei_status.current_page-1, E8390_BASE+EN0_BOUNDARY);
continue;
} else {
/* Oh no Mr Bill! Last ditch error recovery. */
printk(EI_NAME": multiple sequential lossage, resetting at packet #%d.",
rx_packets);
sti();
ei_reset_8390(dev);
NS8390_init(dev, 1);
printk("restarting.\n");
return;
}
#endif /* EI8390_NOCHECK */
}
if ((size < 32 || size > 1535) && ei_debug)
printk(EI_NAME": bogus packet size, status=%#2x nxpg=%#2x size=%#x\n",
rx_frame.status, rx_frame.next, rx_frame.count);
if ((rx_frame.status & 0x0F) == ENRSR_RXOK) {
int sksize = sizeof(struct sk_buff) + size;
struct sk_buff *skb;
skb = kmalloc(sksize, GFP_ATOMIC);
if (skb != NULL) {
skb->lock = 0;
skb->mem_len = sksize;
skb->mem_addr = skb;
/* 'skb+1' points to the start of sk_buff data area. */
ei_block_input(dev, size, (void *)(skb+1),
current_offset + sizeof(rx_frame));
if(dev_rint((void *)skb, size, IN_SKBUFF, dev)) {
printk(EI_NAME": receive buffers full.\n");
break;
}
} else if (ei_debug) {
printk(EI_NAME": Couldn't allocate a sk_buff of size %d.\n", sksize);
break;
}
rx_packets++;
} else {
if (ei_debug)
printk(EI_NAME": bogus packet, status=%#2x nxpg=%#2x size=%d\n",
rx_frame.status, rx_frame.next, rx_frame.count);
soft_rx_err_bits |= rx_frame.status,
soft_rx_errors++;
}
next_frame = rx_frame.next;
/* This should never happen, it's here for debugging. */
if (next_frame >= ei_status.stop_page) {
printk(EI_NAME": next frame inconsistency, %#2x..", next_frame);
next_frame = ei_status.rx_start_page;
}
ei_status.current_page += 1 + ((size+4)>>8);
#ifdef notdef
if (ei_status.current_page > ei_status.stop_page)
ei_status.current_page -= ei_status.stop_page-ei_status.rx_start_page;
if (ei_status.current_page != next_frame) {
printk(EI_NAME": inconsistency in next_frame %#2x!=%#2x.\n",
this_frame, next_frame);
/* Assume this packet frame is scrogged by the NIC, use magic to
skip to the next frame. Actually we should stop and restart.*/
next_frame = size > 1535 ? rx_frame.status : rx_frame.next;
ei_status.current_page = next_frame;
break;
}
#endif
ei_status.current_page = next_frame;
outb(next_frame-1, E8390_BASE+EN0_BOUNDARY);
}
/* Tell the upper levels we're done. */
while (dev_rint(NULL, 0, 0, dev) == 1
&& ++boguscount < 20)
;
/* Bug alert! Reset ENISR_OVER to avoid spurious overruns! */
outb_p(ENISR_RX+ENISR_RX_ERR+ENISR_OVER, E8390_BASE+EN0_ISR); /* Ack intr. */
return;
}
/* We have a receiver overrun: we have to kick the 8390 to get it started
again. Overruns are detected on a per-256byte-page basis. */
static void
ei_rx_overrun(struct device *dev)
{
int reset_start_time = jiffies;
/* We should already be stopped and in page0. Remove after testing. */
outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, EN_CMD);
if (ei_debug)
printk(EI_NAME ": Receiver overrun.\n");
/* The we.c driver does dummy = inb_p( RBCR[01] ); at this point.
It might mean something -- magic to speed up a reset? A 8390 bug?*/
/* Wait for reset in case the NIC is doing a tx or rx. This could take up to
1.5msec, but we have no way of timing something in that range. The 'jiffies'
are just a sanity check. */
while ((inb_p(E8390_BASE+EN0_ISR) & ENISR_RESET) == 0)
if (jiffies - reset_start_time > 1) {
printk(EI_NAME": reset did not complete at ei_rx_overrun.\n");
NS8390_init(dev, 1);
return;
};
{
int old_rx_packets = rx_packets;
/* Remove packets right away. */
ei_receive(dev);
rx_overrun_packets += (rx_packets - old_rx_packets);
}
outb_p(0xff, E8390_BASE+EN0_ISR);
/* Generic 8390 insns to start up again, same as in open_8390(). */
outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START, EN_CMD);
outb_p(E8390_TXCONFIG, E8390_BASE + EN0_TXCR); /* xmit on. */
#ifdef notneeded
outb_p(E8390_RXCONFIG, E8390_BASE + EN0_RXCR); /* rx on, */
#endif
}
int
ethif_init(struct device *dev)
{
int i;
eifdev = dev; /* Store for debugging. */
if (ei_debug > 3)
printk(version);
if (1
#ifdef WD80x3
&& ! wdprobe(dev->base_addr, dev)
#endif
#ifdef EL2
&& ! el2autoprobe(dev->base_addr, dev)
#endif
#ifdef NE2000
&& ! neprobe(dev->base_addr, dev)
#endif
#ifdef HPLAN
&& ! hpprobe(dev->base_addr, dev)
#endif
&& 1 ) {
dev->open = &ei_open;
printk("No ethernet device found.\n");
ei_status.exists = 0;
return 1; /* ENODEV or EAGAIN would be more accurate. */
}
e8390_base = dev->base_addr;
/* Initialize the rest of the device structure. Many of these could
be in Space.c. */
for (i = 0; i < DEV_NUMBUFFS; i++)
dev->buffs[i] = NULL;
ei_status.exists = 1;
dev->hard_header = eth_hard_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->send_packet = &ei_send_packet;
dev->open = &ei_open;
dev->hard_start_xmit = &ei_start_xmit;
dev->type = ETHER_TYPE;
dev->hard_header_len = sizeof (struct enet_header);
dev->mtu = 1500; /* eth_mtu */
dev->addr_len = ETHER_ADDR_LEN;
for (i = 0; i < dev->addr_len; i++) {
dev->broadcast[i]=0xff;
}
return 0;
}
/* This page of functions should be 8390 generic */
/* Follow National Semi's recommendations for initializing the "NIC". */
void NS8390_init(struct device *dev, int startp)
{
int i;
int endcfg = ei_status.word16 ? (0x48 | ENDCFG_WTS) : 0x48;
int e8390_base = dev->base_addr;
/* Follow National Semi's recommendations for initing the DP83902. */
outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base); /* 0x21 */
outb_p(endcfg, e8390_base + EN0_DCFG); /* 0x48 or 0x49 */
/* Clear the remote byte count registers. */
outb_p(0x00, e8390_base + EN0_RCNTLO);
outb_p(0x00, e8390_base + EN0_RCNTHI);
/* Set to monitor and loopback mode -- this is vital!. */
outb_p(E8390_RXOFF, e8390_base + EN0_RXCR); /* 0x20 */
outb_p(E8390_TXOFF, e8390_base + EN0_TXCR); /* 0x02 */
/* Set the transmit page and receive ring. */
outb_p(ei_status.tx_start_page, e8390_base + EN0_TPSR);
ei_status.tx1 = ei_status.tx2 = 0;
outb_p(ei_status.rx_start_page, e8390_base + EN0_STARTPG);
outb_p(ei_status.stop_page-1, e8390_base + EN0_BOUNDARY); /* 3c503 says 0x3f,NS0x26*/
ei_status.current_page = ei_status.rx_start_page; /* assert boundary+1 */
outb_p(ei_status.stop_page, e8390_base + EN0_STOPPG);
/* Clear the pending interrupts and mask. */
outb_p(0xFF, e8390_base + EN0_ISR);
outb_p(0x00, e8390_base + EN0_IMR);
/* Copy the station address into the DS8390 registers,
and set the multicast hash bitmap to receive all multicasts. */
cli();
outb_p(E8390_NODMA + E8390_PAGE1 + E8390_STOP, e8390_base); /* 0x61 */
for(i = 0; i < 6; i++) {
outb_p(dev->dev_addr[i], e8390_base + EN1_PHYS + i);
}
for(i = 0; i < 8; i++)
outb_p(0xff, e8390_base + EN1_MULT + i);
outb_p(ei_status.rx_start_page, e8390_base + EN1_CURPAG);
outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base);
sti();
if (startp) {
outb_p(0xff, e8390_base + EN0_ISR);
outb_p(ENISR_ALL, e8390_base + EN0_IMR);
outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base);
outb_p(E8390_TXCONFIG, e8390_base + EN0_TXCR); /* xmit on. */
/* 3c503 TechMan says rxconfig only after the NIC is started. */
outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR); /* rx on, */
}
return;
}
/* Trigger a transmit start, assuming the length is valid. */
static void NS8390_trigger_send(struct device *dev, unsigned int length,
int start_page)
{
int e8390_base = dev->base_addr;
ei_status.txing = 1;
dev->tbusy = 1;
outb_p(E8390_NODMA+E8390_PAGE0, e8390_base);
if (inb_p(EN_CMD) & E8390_TRANS) {
printk(EI_NAME": trigger_send() called with the transmitter busy.\n");
return;
}
outb_p(length & 0xff, e8390_base + EN0_TCNTLO);
outb_p(length >> 8, e8390_base + EN0_TCNTHI);
outb_p(start_page, e8390_base + EN0_TPSR);
outb_p(E8390_NODMA+E8390_TRANS+E8390_START, e8390_base);
outb_p(ENISR_RDC, e8390_base + EN0_ISR);
return;
}
/*
* Local variables:
* compile-command: "gcc -DKERNEL -Wall -O6 -fomit-frame-pointer -DPINGPONG -I/usr/src/linux/net/tcp -c 8390.c"
* version-control: t
* kept-new-versions: 5
* End:
*/

129
net/tcpip/ether-995/8390.h Normal file
View File

@@ -0,0 +1,129 @@
/* Generic NS8390 register definitions. */
/* This file is part of Donald Becker's 8390 drivers.
This file is distributed under the Linux GPL.
Some of these names and comments are from the Crynwr packet drivers. */
#ifndef e8390_h
#define e8390_h
#ifndef EI_NAME
#define EI_NAME "eth_if"
#endif
/*#define PINGPONG*/
#ifdef PINGPONG
#define TX_PAGES 12
#else
#define TX_PAGES 6
#endif
#define ETHER_ADDR_LEN 6
/* From auto_irq.c */
extern void autoirq_setup(int waittime);
extern int autoirq_report(int waittime);
/* Most of these entries should be in 'struct device' (or most
things in there should be here!) */
struct ei_device { /* These should be stored per-board */
char *name;
int exists:1; /* perhaps in dev->private. */
int open:1;
int word16:1; /* We have the 16-bit (vs 8-bit) version of the card. */
void (*reset_8390)(struct device *);
void (*block_output)(struct device *, int, const unsigned char *, int);
int (*block_input)(struct device *, int, char *, int);
unsigned char tx_start_page, rx_start_page, stop_page;
unsigned char current_page; /* Read pointer in buffer */
unsigned char thin_bit; /* Value to write to the 3c503 E33G_CNTRL */
unsigned char txing; /* Transmit Active, don't confuse the upper levels. */
unsigned char txqueue; /* Tx Packet buffer queue length. */
unsigned char in_interrupt;
short tx1, tx2; /* Packet lengths for ping-pong tx. */
int overruns; /* Rx overruns. */
};
/* Some generic ethernet register configurations. */
#define E8390_TX_IRQ_MASK 0xa /* For register EN0_ISR */
#define E8390_RX_IRQ_MASK 0x5
#define E8390_RXCONFIG 0x4 /* EN0_RXCR: broadcasts, no multicast,errors */
#define E8390_RXOFF 0x20 /* EN0_RXCR: Accept no packets */
#define E8390_TXCONFIG 0x00 /* EN0_TXCR: Normal transmit mode */
#define E8390_TXOFF 0x02 /* EN0_TXCR: Transmitter off */
/* Register accessed at EN_CMD, the 8390 base addr. */
#define E8390_STOP 0x01 /* Stop and reset the chip */
#define E8390_START 0x02 /* Start the chip, clear reset */
#define E8390_TRANS 0x04 /* Transmit a frame */
#define E8390_RREAD 0x08 /* Remote read */
#define E8390_RWRITE 0x10 /* Remote write */
#define E8390_NODMA 0x20 /* Remote DMA */
#define E8390_PAGE0 0x00 /* Select page chip registers */
#define E8390_PAGE1 0x40 /* using the two high-order bits */
#define E8390_PAGE2 0x80 /* Page 3 is invalid. */
/* Page 0 register offsets. */
#define EN0_CLDALO 0x01 /* Low byte of current local dma addr RD */
#define EN0_STARTPG 0x01 /* Starting page of ring bfr WR */
#define EN0_CLDAHI 0x02 /* High byte of current local dma addr RD */
#define EN0_STOPPG 0x02 /* Ending page +1 of ring bfr WR */
#define EN0_BOUNDARY 0x03 /* Boundary page of ring bfr RD WR */
#define EN0_TSR 0x04 /* Transmit status reg RD */
#define EN0_TPSR 0x04 /* Transmit starting page WR */
#define EN0_NCR 0x05 /* Number of collision reg RD */
#define EN0_TCNTLO 0x05 /* Low byte of tx byte count WR */
#define EN0_FIFO 0x06 /* FIFO RD */
#define EN0_TCNTHI 0x06 /* High byte of tx byte count WR */
#define EN0_ISR 0x07 /* Interrupt status reg RD WR */
#define EN0_CRDALO 0x08 /* low byte of current remote dma address RD */
#define EN0_RSARLO 0x08 /* Remote start address reg 0 */
#define EN0_CRDAHI 0x09 /* high byte, current remote dma address RD */
#define EN0_RSARHI 0x09 /* Remote start address reg 1 */
#define EN0_RCNTLO 0x0a /* Remote byte count reg WR */
#define EN0_RCNTHI 0x0b /* Remote byte count reg WR */
#define EN0_RSR 0x0c /* rx status reg RD */
#define EN0_RXCR 0x0c /* RX configuration reg WR */
#define EN0_TXCR 0x0d /* TX configuration reg WR */
#define EN0_COUNTER0 0x0d /* Rcv alignment error counter RD */
#define EN0_DCFG 0x0e /* Data configuration reg WR */
#define EN0_COUNTER1 0x0e /* Rcv CRC error counter RD */
#define EN0_IMR 0x0f /* Interrupt mask reg WR */
#define EN0_COUNTER2 0x0f /* Rcv missed frame error counter RD */
/* Bits in EN0_ISR - Interrupt status register */
#define ENISR_RX 0x01 /* Receiver, no error */
#define ENISR_TX 0x02 /* Transmitter, no error */
#define ENISR_RX_ERR 0x04 /* Receiver, with error */
#define ENISR_TX_ERR 0x08 /* Transmitter, with error */
#define ENISR_OVER 0x10 /* Receiver overwrote the ring */
#define ENISR_COUNTERS 0x20 /* Counters need emptying */
#define ENISR_RDC 0x40 /* remote dma complete */
#define ENISR_RESET 0x80 /* Reset completed */
#define ENISR_ALL 0x3f /* Interrupts we will enable */
/* Bits in EN0_DCFG - Data config register */
#define ENDCFG_WTS 0x01 /* word transfer mode selection */
/* Page 1 register offsets. */
#define EN1_PHYS 0x01 /* This board's physical enet addr RD WR */
#define EN1_CURPAG 0x07 /* Current memory page RD WR */
#define EN1_MULT 0x08 /* Multicast filter mask array (8 bytes) RD WR */
/* Bits in received packet status byte and EN0_RSR*/
#define ENRSR_RXOK 0x01 /* Received a good packet */
#define ENRSR_CRC 0x02 /* CRC error */
#define ENRSR_FAE 0x04 /* frame alignment error */
#define ENRSR_FO 0x08 /* FIFO overrun */
#define ENRSR_MPA 0x10 /* missed pkt */
#define ENRSR_PHY 0x20 /* physical/multicase address */
#define ENRSR_DIS 0x40 /* receiver disable. set in monitor mode */
#define ENRSR_DEF 0x80 /* deferring */
/* Transmitted packet status, EN0_TSR. */
#define ENTSR_PTX 0x01 /* Packet transmitted without error */
/* The per-packet-header format. */
struct e8390_pkt_hdr {
unsigned char status; /* status */
unsigned char next; /* pointer to next packet. */
unsigned short count; /* header + packet lenght in bytes */
};
#endif /* e8390_h */

View File

@@ -0,0 +1,45 @@
Fri Feb 12 15:45:13 1993 Donald J. Becker (becker at metropolis)
* 8390.c: Commented out 'high_water_mark', since it's
never set and results in an 'unused variable' warning.
* hp.c: Deleted the 'int i;' from hp_block_output() --
it's unused now that port_write_b() is used instead
of an explicit loop.
Thu Feb 11 16:04:27 1993 Donald J. Becker (becker at metropolis)
* ne.c: Added explicit support for D-Link ethercards.
Sat Jan 30 03:16:30 1993 Donald J. Becker (becker at metropolis)
* hp.c: Changed the 8-bit output and input loops to use
port_{read,write?_b() instead. Assigned dev->irq before
sigaction() is call to avoid the 3c503 problem (below).
* 3c503.c: Fixed a wild I/O port write in the probe code that had
been added to mask interrupts during probes. Also assigned dev->irq
before sigaction() is called to correctly handle that spurious
first interrupt.
* wd.c: Changed the IRQ from the unreliable autoIRQ to reading the
configuation register. I also go a report that it still works
with the 8003
Fri Jan 29 11:29:10 1993 Donald J. Becker (becker at metropolis)
* 3c503: Added EL2_AUI as an alias for EI8390_THICK, and rewrote
the IRQ selection code. It now does assigns the first free IRQ
from the list { 5 2/9 3 4 }.
* GNUmakefile: Changed the default name from "eth_if" to "eth0" to
be compatible. Also changed the name of EI8390_THICK to EL2_AUI.
* 8390.c: Omitted incrementing ei_debug during a rx_overrun.
* ne.c: I put the a ctron check inside of #ifdef EI_8BIT
so that 8-bit Cabletron card are recognized.
Thanks to Eric Wallace, wallace@chezmoto.ai.mit.edu.

View File

@@ -0,0 +1,36 @@
# This file must be named 'GNUmakefile'. When it has that name it
# loaded in preference to the regular 'Makefile' (which it include
# right here) so this has the effect of appending lines to the Makefile.
include Makefile
# Add a few files to tcpip.a.
newobjs = 8390.o 3c503.o ne.o wd.o hp.o auto_irq.o
OBJS := $(OBJS) $(newobjs)
tcpip.a: $(newobjs)
# Set the address and IRQ here. The ne.c and 3c503 driver will autoprobe
# if you set the address or IRQ to zero, so we do that by default.
#
# Add -DEI_NAME="eth0" if you want to be exactly compatible with the default
# driver. This will only work if you don't use the distributed 'we' driver!
#
ether_options := -DEI_NAME=\"eth0\" -DEI8390=0 -DEI8390_IRQ=0
Space.o: Space.c GNUmakefile
$(CC) $(CPPFLAGS) $(CFLAGS) $(ether_options) -c Space.c -o $@
# Change this to define the set of ethercards your kernel will support.
8390.o: 8390.c GNUmakefile
$(CC) $(CPPFLAGS) $(CFLAGS) -DNE2000 -DWD80x3 -DHPLAN -DEL2 -c 8390.c -o $@
# Change this to -DEI_8BIT if you have an 8-bit ethercard (NE1000, E10xx).
ne.o: ne.c GNUmakefile
$(CC) $(CPPFLAGS) $(CFLAGS) -UEI_8BIT -c ne.c -o $@
# Change this to -DEL2_AUI if you use the AUI port.
3c503.o: 3c503.c 3c503reg.h GNUmakefile
$(CC) $(CPPFLAGS) $(CFLAGS) -UEL2_AUI -c 3c503.c -o $@
# Change this to -DSHMEM=0xd0000 if you have an old non-EEPROM wd8003
wd.o: wd.c GNUmakefile
$(CC) $(CPPFLAGS) $(CFLAGS) -UWD_SHMEM -c wd.c -o $@

View File

@@ -0,0 +1,82 @@
Installation Directions:
EMail me (becker@super.org) telling me which version you have gotten.
I need to know how many people have tried, succeeded and
failed before this is released as part of the official Linux.
Use Linux 0.99.2 or later. Make certain you can make a working kernel
_before_ you install the ethercard driver.
Put the all of the files into linux/net/tcp/. You'll need all of the
files in this directory.
GNUmakefile 8390.c 8390.h auto_irq.c Space.c wd.c ne.c 3c503.[ch] and hp.c.
Space.c is the only tricky one -- it overwrites the old Space.c.
Stock versions of Space.c leave the "we" driver enabled and will not work.
Change the GNUmakefile to reflect your configuration. Use the guide at
the end of these instructions and in the README file.
Make and install your new kernel.
To actually use this driver you must get the TCP/IP package and edit
your /usr/etc/inet/rc.net file to config whatever you named your
ethernet device. (You can edit the GNUmakefile to use something
besides the "eth0" name. Note that the default name has changed to
the now-standard "eth0" from the old "eth_if"!)
If you try to 'config' an interface that doesn't exist your kernel
will report "invalid ioctl()" for anthing that tries to use the card.
Note that the ethercard devices aren't (yet) real '/dev/eth_if' devices --
they only exist in the socket namespace and thus you don't need to
'mknode' them.
________________
Important defines
For Space.c
#define EI8390 0 /* The base address of your ethercard. */
#define EI8390_IRQ 0 /* and the interrupt you want to use. */
/* '0' means autoconfigure */
For 8390.c
#define EI_DEBUG 2 /* Use '0' for no messages. */
#define EL2 /* For the 3c503 driver. */
#define NE2000 /* For the NE1000/NE2000/Ctron driver. */
#define WD80x3 /* For the WD8003/WD8013 driver. */
#define HPLAN /* For the HP27xxx driver. */
For the individual drivers
#undef EI_8BIT /* Define for ne.c iff you have an 8 bit card. */
#undef EL2_AUI /* Define to use the 3c503 AUI/DIX transceiver. */
EI8390 Define (probably in autoconf.h or config.site.h) this to the base
address of your ethernet card.
EI8390_IRQ Define (probably in autoconf.h or config.site.h) this to the
IRQ line of your ethernet card. Most drivers convert a IRQ2 to an
IRQ9 for you, so don't be surprised.
EI_DEBUG Set to the desired numeric debugging level. Use 3 or
greater when actively debugging a problem, '1' for a
casual interest in what's going on, and '0' for normal
use. (Most of the debugging stuff has been taken out recently,
so this won't have much effect.)
EI_PINGPONG
Not included or broken the alpha version. Define this if you want
ping-pong transmit buffers.
EI_8BIT
If you are using the ne.c driver and have an 8-bit card (NE1000 or
E1xxx Cabletron) you must define this. It's not needed for the other
drivers, and I hope to find a way to clean this up in the future.
EL2_AUI
Define for this if you are using the 3c503 and use the AUI/DIX
connector rather than the built-in thin-net transceiver.
WD_SHMEM
Define this to override the shared memory address used by the
WD driver. This should only be necessary for old, jumpered '8003's.
If you have a Cabletron ethercard you might want to look at ne.c:neprobe()
for info on how to enable more packet buffer space.
ETHERLINK1_IRQ
ETHERLINK1 Define these to the base address and IRQ of a 3c501 (NOT 3c503)
card. Refer to net/tcp/Space.c.

101
net/tcpip/ether-995/README Normal file
View File

@@ -0,0 +1,101 @@
This is the current version of the 8390 ethercard driver.
The ether-994 drivers are for 0.99.4 and earlier.
The ether-995 drivers are for 0.99.5.
You should consult the list below for the specific #define for your
ethercard. If you don't have one specific #define the driver will
probe for all supported ethercard types.
Source Header #define to get Supported cards
8390.c 8390.h EI8390 (generic, needed for all)
3c503.c 3c503reg.h EL2 3c503, 3c503/16
ne.c NE2000 NE1000, NE2000, NatSemi, Cabletron
wd.c wd.h WD80x3 WD8003, WD8013, SMC elite
hp.c HPLAN HP LAN adaptors
Notes on each file
INSTALL
The installation directions -- "read this first, uhmmm, second".
GNUmakefile
The 'GNUmakefile' name is "magic". You just put it into the directory
and it is loaded instead of the regular Makefile (which it thenincludes).
Most people should never need to edit the Makefile, just the GNUmakefile.
3c503.c
o You'll need to '#define EI8390_THICK' or EL2_AUI if you are using the AUI port
instead of the thinnet connector. Russ Nelson <nelson@crynwr.com> sent me an
run-time method of selecting between the two, but I haven't put it in yet.
This _may_ generate a spurious error message when transmitting the first
packet, I haven't yet tracked down this bug report.
o If you want to check the shared memory, #define EL2MEMTEST. I don't think
the memory check is worth the effort -- it's missed obvious problems.
o You must jumper the board to use shared memory -- I don't test the
non-shared-memory mode and it's probably broken.
o Thanks to Chance Reschke at USRA <creschke@usra.edu> for providing the
3c503 and anonymous FTP space.
ne.c
o You'll need to #define EI_8BIT if you are using an 8-bit ethercard
such as the NE1000 or Cabletron E10xx. I might someday make a run-time
selection between the NE1000 and NE2000 (right now it screws up the
non-default bus-width) but I don't know how to distinguish the Cabletron
ethercards. I'm hoping to find a general way to identify the board's bus
width, but don't hold your breath.
wd.c
o Thanks to Russ Nelson (nelson@crynwr.com) for loaning me a WD8013.
o The 8013 doesn't work if it's probed by some other driver first: keep
it first in the probe list.
I could reset the board before looking at it to fix the probe problem, but
this involves an outb() which may disturb non-WD8013 devices.
o You _must_ run this board with shared memory enabled. Don't set the
jumper to the no-shared-memory setting.
o The driver now reads the EEPROM setting, so you can use the EEPROM
settings! And there is a new Linux 'wdsetup' program that replaces
MS-DOS 'EZSETUP'!
o You machine may fail to do a soft reboot if the packet buffer shared memory
is mapped in -- the machine might think its a boot PROM (since it
intentionally shares the same memory space as the optional on-board
boot PROM). "Live with it" for now.
o If the packet buffer memory is mapped into a cacheable region it won't work!
It's really easy to this with the map-it-anywhere EEPROM. Check your BIOS
setup.
o If you have an old non-EEPROM wd8003 and need to change the shared memory
address from the default 0xd0000 set WD_SHMEM to the desired address.
hp.c
o This has only been tested with a 27245A, 27247A, and 27250. It doesn't yet
work with the new 27247B!
o Thanks to Chance Reschke at USRA <creschke@usra.edu> for loaning me the
27247A ethercard.
BUGS
The "bogus packet header" is a bug in the 8390. I drop all of
the packets in the ring (usually just one) when this happens.
If you get this more than just occasionally please report it to me.
I don't yet distinguish between the problems with IRQ conflicts and
problems with the ethernet cable not being connected. If you get
a "transmit timed out" message check both! Your ethercard
probably will NOT work without proper termination.
A small number of people report continuous "RX transfer address mismatch"
errors with the NE2000. This is a bug in the 8390, and the reason
most designers use shared memory or design their own packet buffer access
circuitry rather than use what's provided by the 8390. An occasional
"mismatch" message (say, once a week) won't impact performance.
I've fixed most of the spurious "receiver overrun" messages. It
was a bug in the 8390 -- the overrun flag is sometimes set
when the boundary pointer is written. If you still get
isolated overrun errors please send me email.
The 3c501 driver isn't complete. This card is severely brain-damaged
anyway -- you won't notice the performance difference between working
and non-working versions anyway. If this source code is here, it is
only provided for a few people that wanted to write code for their 3c501
cards. Don't send me email about it unless it's a bug fix.

134
net/tcpip/ether-995/Space.c Normal file
View File

@@ -0,0 +1,134 @@
/* Space.c */
/* Holds initial configuration information for devices. */
#include "dev.h"
#include <linux/stddef.h>
#include <linux/config.h>
#define NEXT_DEV NULL
#ifdef ETHERLINK1
extern int etherlink_init(struct device *);
#ifndef ETHERLINK1_IRQ
#define ETHERLINK1_IRQ 9
#endif
static struct device el_dev = {
"if3c501",
0, 0, 0, 0, /* memory rx_end, rx_start, end, start are autoconfiged. */
ETHERLINK1, ETHERLINK1_IRQ, /* base i/o address, irq. */
0,0,0,0,0,
NEXT_DEV,
etherlink_init, 0, {NULL}, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, {0,}, {0,}, 0
};
#undef NEXT_DEV
#define NEXT_DEV (&el_dev)
#endif /* ETHERLINK1 */
#if defined(EI8390) || defined(EL2) || defined(NE2000) \
|| defined(WD80x3) || defined(HPLAN)
extern int ethif_init(struct device *);
#ifndef EI8390_IRQ
#define EI8390_IRQ 0
#endif
static struct device ei8390_dev = {
#ifdef EI_NAME
EI_NAME,
#else
"eth_if",
#endif
0, 0, 0, 0, /* memory rx_end, rx_start, end, start are autoconfiged. */
EI8390, EI8390_IRQ, 0,0,0,0,0, /* base i/o address, irq, and flags. */
NEXT_DEV,
ethif_init, 0, {NULL}, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, 0, 0, 0, {0,}, {0,}, 0
};
#undef NEXT_DEV
#define NEXT_DEV (&ei8390_dev)
#endif /* The EI8390 drivers. */
#ifdef WD8003
extern int wd8003_init(struct device *);
static struct device wd8003_dev =
{
"eth0",
0xd2000, /* recv memory end. */
0xd0600, /* recv memory start. */
0xd2000, /* memory end. */
0xd0000, /* memory start. */
0x280, /* base i/o address. */
5, /* irq */
0,0,0,0,0, /* flags */
NEXT_DEV,
wd8003_init,
/* wd8003_init should set up the rest. */
0, /* trans start. */
{NULL}, /* buffs */
NULL, /* backlog */
NULL, /* open */
NULL, /* stop */
NULL, /* hard_start_xmit */
NULL, /* hard_header */
NULL, /* add arp */
NULL, /* queue xmit */
NULL, /* rebuild header */
NULL, /* type_trans */
NULL, /* send_packet */
NULL, /* private */
0, /* type. */
0, /* hard_header_len */
0, /* mtu */
{0,}, /* broadcast address */
{0,}, /* device address */
0 /* addr len */
};
#undef NEXT_DEV
#define NEXT_DEV (&wd8003_dev)
#endif /* WD8003 */
extern int loopback_init(struct device *dev);
static struct device loopback_dev =
{
"loopback",
-1, /* recv memory end. */
0x0, /* recv memory start. */
-1, /* memory end. */
0, /* memory start. */
0, /* base i/o address. */
0, /* irq */
0,0,1,0,0, /* flags */
NEXT_DEV, /* next device */
loopback_init,
/* loopback_init should set up the rest. */
0, /* trans start. */
{NULL}, /* buffs */
NULL, /* backlog */
NULL, /* open */
NULL, /* stop */
NULL, /* hard_start_xmit */
NULL, /* hard_header */
NULL, /* add arp */
NULL, /* queue xmit */
NULL, /* rebuild header */
NULL, /* type_trans */
NULL, /* send_packet */
NULL, /* private */
0, /* type. */
0, /* hard_header_len */
0, /* mtu */
{0,}, /* broadcast address */
{0,}, /* device address */
0 /* addr len */
};
#undef NEXT_DEV
#define NEXT_DEV (error no next device &loopback_dev)
struct device *dev_base = &loopback_dev;

View File

@@ -0,0 +1,100 @@
/* auto_irq.c: Auto-configure IRQ lines for linux. */
/*
Written 1993 by Donald Becker. This is alpha test code.
The Author may be reached as becker@super.org or
C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
This code is a general-purpose IRQ line detector for devices with
jumpered IRQ lines. If you can make the device raise an IRQ (and
that IRQ line isn't already being used), these routines will tell
you what IRQ line it's using -- perfect for those oh-so-cool boot-time
device probes!
To use this, first call autoirq_setup(timeout). TIMEOUT is how many
'jiffies' (1/18 sec.) to detect other devices that have active IRQ lines,
and can usually be zero at boot.
Next, set up your device to trigger an interrupt.
Finally call autoirq_report(TIMEOUT) to find out which IRQ line was
most recently active. The TIMEOUT should usually be zero, but may
be set to the number of jiffies to wait for an active IRQ.
The idea of using the setup timeout to filter out bogus IRQs came from
the serial driver.
*/
#ifdef version
static char *version="auto_irq.c:v0.01 1993 Donald Becker (becker@super.org)";
#endif
/*#include <linux/config.h>*/
/*#include <linux/kernel.h>*/
#include <linux/sched.h>
#include <asm/bitops.h>
#include <asm/io.h>
/*#include <asm/system.h>*/
static volatile int irq_number; /* The latest irq number we actually found. */
static volatile int irq_bitmap; /* The irqs we actually found. */
static int irq_handled; /* The irq lines we have a handler on. */
static void autoirq_probe(int irq)
{
irq_number = irq;
set_bit(irq, (void *)&irq_bitmap);
/*irq_bitmap |= 1 << irq;*/
return;
}
struct sigaction autoirq_sigaction = { autoirq_probe, 0, SA_INTERRUPT, NULL};
void autoirq_setup(int waittime)
{
int i, mask;
int timeout = jiffies+waittime;
irq_number = 0;
irq_bitmap = 0;
irq_handled = 0;
for (i = 0; i < 16; i++) {
if (!irqaction(i, &autoirq_sigaction))
set_bit(i, (void *)&irq_handled); /* irq_handled |= 1 << i;*/
}
/* Hang out at least <waittime> jiffies waiting for bogus IRQ hits. */
while (timeout >= jiffies)
;
for (i = 0, mask = 0x01; i < 16; i++, mask <<= 1) {
if (irq_bitmap & irq_handled & mask) {
irq_handled &= ~mask;
printk(" Spurious interrupt on IRQ %d\n", i);
free_irq(i);
}
}
}
int autoirq_report(int waittime)
{
int i;
int timeout = jiffies+waittime;
/* Hang out at least <waittime> jiffies waiting for the IRQ. */
while (timeout >= jiffies)
if (irq_number)
break;
/* Retract the irq handlers that we installed. */
for (i = 0; i < 16; i++) {
if (test_bit(i, (void *)&irq_handled))
free_irq(i);
}
return irq_number;
}
/*
* Local variables:
* compile-command: "gcc -DKERNEL -Wall -O6 -fomit-frame-pointer -I/usr/src/linux/net/tcp -c auto_irq.c"
* version-control: t
* kept-new-versions: 5
* End:
*/

303
net/tcpip/ether-995/hp.c Normal file
View File

@@ -0,0 +1,303 @@
/* hp.c: A HP LAN ethernet driver for linux. */
/*
Written 1993 by Donald Becker. This is alpha test code.
This is a extension to the Linux operating system, and is covered by
same Gnu Public License that covers that work.
This is a driver for the HP LAN adaptors.
The Author may be reached as becker@super.org or
C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
*/
static char *version = "hp.c:v0.43 2/12/93 Donald Becker (becker@super.org)\n";
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <asm/io.h>
#include <asm/system.h>
#include "dev.h"
#include "8390.h"
/* These should be in <asm/io.h> someday, borrowed from blk_drv/hd.c. */
#define port_read(port,buf,nr) \
__asm__("cld;rep;insw"::"d" (port),"D" (buf),"c" (nr):"cx","di")
#define port_write(port,buf,nr) \
__asm__("cld;rep;outsw"::"d" (port),"S" (buf),"c" (nr):"cx","si")
#define port_read_b(port,buf,nr) \
__asm__("cld;rep;insb"::"d" (port),"D" (buf),"c" (nr):"cx","di")
#define port_write_b(port,buf,nr) \
__asm__("cld;rep;outsb"::"d" (port),"S" (buf),"c" (nr):"cx","si")
#define HP_DATAPORT 0x0c /* "Remote DMA" data port. */
#define HP_ID 0x07
#define HP_CONFIGURE 0x08 /* Configuration register. */
#define HP_RUN 0x01 /* 1 == Run, 0 == reset. */
#define HP_IRQ 0x0E /* Mask for software-configured IRQ line. */
#define HP_DATAON 0x10 /* Turn on dataport */
#define NIC_OFFSET 0x10 /* Offset the 8390 registers. */
#define HP_START_PG 0x00 /* First page of TX buffer */
#define HP_8BSTOP_PG 0x80 /* Last page +1 of RX ring */
#define HP_16BSTOP_PG 0xFF /* Last page +1 of RX ring */
extern void NS8390_init(struct device *dev, int startp);
extern int ei_debug;
extern struct sigaction ei_sigaction;
extern struct ei_device ei_status;
int hpprobe(int ioaddr, struct device *dev);
int hpprobe1(int ioaddr, struct device *dev);
static void hp_reset_8390(struct device *dev);
static int hp_block_input(struct device *dev, int count,
char *buf, int ring_offset);
static void hp_block_output(struct device *dev, int count,
const unsigned char *buf, const start_page);
static void hp_init_card(struct device *dev);
/* Probe for an HP LAN adaptor.
Also initialize the card and fill in STATION_ADDR with the station
address. */
int hpprobe(int ioaddr, struct device *dev)
{
int *port, ports[] = {0x300, 0x320, 0x340, 0x280, 0x2C0, 0x200, 0x240, 0};
if (ioaddr > 0x100)
return hpprobe1(ioaddr, dev);
for (port = &ports[0]; *port; port++)
if (inb_p(*port) != 0xff && hpprobe1(*port, dev))
return dev->base_addr;
return 0;
}
int hpprobe1(int ioaddr, struct device *dev)
{
int i;
unsigned char *station_addr = dev->dev_addr;
unsigned char SA_prom[6];
int tmp;
int hplan;
printk("HP-LAN ethercard probe at %#3x:", ioaddr);
tmp = inb_p(ioaddr);
if (tmp == 0xFF) {
printk(" not found (nothing there).\n");
return 0;
}
for(i = 0; i < sizeof(SA_prom); i++) {
SA_prom[i] = inb(ioaddr + i);
if (i < ETHER_ADDR_LEN && station_addr) {
printk(" %2.2x", SA_prom[i]);
station_addr[i] = SA_prom[i];
}
}
hplan = (SA_prom[0] == 0x08 && SA_prom[1] == 0x00 && SA_prom[2] == 0x09);
if (hplan == 0) {
printk(" not found (invalid station address prefix).\n");
return 0;
}
ei_status.tx_start_page = HP_START_PG;
ei_status.rx_start_page = HP_START_PG + TX_PAGES;
/* Set up the rest of the parameters. */
if ((tmp = inb_p(HP_ID)) & 0x80) {
ei_status.name = "HP27247";
ei_status.word16 = 1;
ei_status.stop_page = HP_16BSTOP_PG; /* Safe for now */
} else {
ei_status.name = "HP27250";
ei_status.word16 = 0;
ei_status.stop_page = HP_8BSTOP_PG; /* Safe for now */
}
/* Set the base address to point to the NIC! */
dev->base_addr = ioaddr + NIC_OFFSET;
if (dev->irq == 2)
dev->irq = 9;
/* Snarf the interrupt now. There's no point in waiting since we cannot
share and the board will usually be enabled. */
if (dev->irq < 2) {
int irq_16list[] = { 11, 10, 5, 3, 4, 7, 9, 0};
int irq_8list[] = { 7, 5, 3, 4, 9, 0};
int *irq = ei_status.word16 ? irq_16list : irq_8list;
for (; *irq; irq++) {
if (irqaction(dev->irq = *irq, &ei_sigaction) == 0)
break;
}
if (*irq == 0) {
printk (" unable to get an IRQ.\n");
return 0;
}
}
printk(" %s found, using IRQ %d.\n", ei_status.name, dev->irq);
if (ei_debug > 1)
printk(version);
ei_status.reset_8390 = &hp_reset_8390;
ei_status.block_input = &hp_block_input;
ei_status.block_output = &hp_block_output;
hp_init_card(dev);
return dev->base_addr;
}
static void
hp_reset_8390(struct device *dev)
{
int hp_base = dev->base_addr - NIC_OFFSET;
int saved_config = inb_p(hp_base + HP_CONFIGURE);
int reset_start_time = jiffies;
if (ei_debug > 1) printk("resetting the 8390 time=%d...", jiffies);
outb_p(0x00, hp_base + HP_CONFIGURE);
ei_status.txing = 0;
sti();
/* We shouldn't use the boguscount for timing, but this hasn't been
checked yet, and you could hang your machine if jiffies break... */
{
int boguscount = 150000;
while(jiffies - reset_start_time < 2)
if (boguscount-- < 0) {
printk("jiffy failure (t=%d)...", jiffies);
break;
}
}
outb_p(saved_config, hp_base + HP_CONFIGURE);
while ((inb_p(hp_base+NIC_OFFSET+EN0_ISR) & ENISR_RESET) == 0)
if (jiffies - reset_start_time > 2) {
printk(EI_NAME": hp_reset_8390() did not complete.\n");
return;
}
if (ei_debug > 1) printk("8390 reset done.", jiffies);
}
/* Block input and output, similar to the Crynwr packet driver. If you
porting to a new ethercard look at the packet driver source for hints.
The HP LAN doesn't use shared memory -- we put the packet
out through the "remote DMA" dataport. */
static int
hp_block_input(struct device *dev, int count, char *buf, int ring_offset)
{
int nic_base = dev->base_addr;
int saved_config = inb_p(nic_base - NIC_OFFSET + HP_CONFIGURE);
int xfer_count = count;
outb_p(saved_config | HP_DATAON, nic_base - NIC_OFFSET + HP_CONFIGURE);
outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base);
outb_p(count & 0xff, nic_base + EN0_RCNTLO);
outb_p(count >> 8, nic_base + EN0_RCNTHI);
outb_p(ring_offset & 0xff, nic_base + EN0_RSARLO);
outb_p(ring_offset >> 8, nic_base + EN0_RSARHI);
outb_p(E8390_RREAD+E8390_START, nic_base);
if (ei_status.word16) {
port_read(nic_base - NIC_OFFSET + HP_DATAPORT,buf,count>>1);
if (count & 0x01)
buf[count-1] = inb(nic_base - NIC_OFFSET + HP_DATAPORT), xfer_count++;
} else {
port_read_b(nic_base - NIC_OFFSET + HP_DATAPORT, buf, count);
}
/* This is for the ALPHA version only, remove for later releases. */
if (ei_debug > 0) { /* DMA termination address check... */
int high = inb_p(nic_base + EN0_RSARHI);
int low = inb_p(nic_base + EN0_RSARLO);
int addr = (high << 8) + low;
/* Check only the lower 8 bits so we can ignore ring wrap. */
if (((ring_offset + xfer_count) & 0xff) != (addr & 0xff))
printk(EI_NAME": RX transfer address mismatch, %#4.4x vs. %#4.4x (actual).\n",
ring_offset + xfer_count, addr);
}
outb_p(saved_config & (~HP_DATAON), nic_base - NIC_OFFSET + HP_CONFIGURE);
return ring_offset + count;
}
static void
hp_block_output(struct device *dev, int count,
const unsigned char *buf, const start_page)
{
int nic_base = dev->base_addr;
int saved_config = inb_p(nic_base - NIC_OFFSET + HP_CONFIGURE);
outb_p(saved_config | HP_DATAON, nic_base - NIC_OFFSET + HP_CONFIGURE);
/* Round the count up for word writes. Do we need to do this?
What effect will an odd byte count have on the 8390?
I should check someday. */
if (ei_status.word16 && (count & 0x01))
count++;
/* We should already be in page 0, but to be safe... */
outb_p(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base);
#ifdef ei8390_bug
/* Handle the read-before-write bug the same way as the
Crynwr packet driver -- the NatSemi method doesn't work. */
outb_p(0x42, nic_base + EN0_RCNTLO);
outb_p(0, nic_base + EN0_RCNTHI);
outb_p(0xff, nic_base + EN0_RSARLO);
outb_p(0x00, nic_base + EN0_RSARHI);
outb_p(E8390_RREAD+E8390_START, EN_CMD);
/* Make certain that the dummy read has occured. */
inb_p(0x61);
inb_p(0x61);
#endif
outb_p(count & 0xff, nic_base + EN0_RCNTLO);
outb_p(count >> 8, nic_base + EN0_RCNTHI);
outb_p(0x00, nic_base + EN0_RSARLO);
outb_p(start_page, nic_base + EN0_RSARHI);
outb_p(E8390_RWRITE+E8390_START, nic_base);
if (ei_status.word16) {
/* Use the 'rep' sequence for 16 bit boards. */
port_write(nic_base - NIC_OFFSET + HP_DATAPORT, buf, count>>1);
} else {
port_write_b(nic_base - NIC_OFFSET + HP_DATAPORT, buf, count);
}
/* DON'T check for 'inb_p(EN0_ISR) & ENISR_RDC' here -- it's broken! */
/* This is for the ALPHA version only, remove for later releases. */
if (ei_debug > 0) { /* DMA termination address check... */
int high = inb_p(nic_base + EN0_RSARHI);
int low = inb_p(nic_base + EN0_RSARLO);
int addr = (high << 8) + low;
if ((start_page << 8) + count != addr)
printk(EI_NAME": TX Transfer address mismatch, %#4.4x vs. %#4.4x.\n",
(start_page << 8) + count, addr);
}
outb_p(saved_config & (~HP_DATAON), nic_base - NIC_OFFSET + HP_CONFIGURE);
return;
}
/* This function resets the ethercard if something screws up. */
static void
hp_init_card(struct device *dev)
{
int irq = dev->irq;
/* default is IRQ5 0 1 2 3 4 5 6 7 8 9 10 11 */
static char irqval[16] = { 0, 0, 4, 6, 8,10, 0,14, 0, 4, 2,12,0,0,0,0};
NS8390_init(dev, 0);
outb_p(irqval[irq&0x0f] | HP_RUN,
dev->base_addr - NIC_OFFSET + HP_CONFIGURE);
return;
}
/*
* Local variables:
* compile-command: "gcc -DKERNEL -Wall -O6 -fomit-frame-pointer -I/usr/src/linux/net/tcp -c hp.c"
* version-control: t
* kept-new-versions: 5
* End:
*/

379
net/tcpip/ether-995/ne.c Normal file
View File

@@ -0,0 +1,379 @@
/* ne.c: A general non-shared-memory NS8390 ethernet driver for linux. */
/*
Written 1992,1993 by Donald Becker. This is alpha test code.
This is a extension to the Linux operating system, and is covered by
same Gnu Public License that covers that work.
This driver should work with many 8390-based ethernet boards. Currently
it support the NE1000, NE2000 (and clones), and some Cabletron products.
8-bit ethercard support is enabled with #define EI_8BIT
The Author may be reached as becker@super.org or
C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
*/
/* Routines for the NatSemi-based designs (NE[12]000). */
static char *version =
"ne.c:v0.50 2/19/93 Donald Becker (becker@super.org)\n";
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <asm/io.h>
#include <asm/system.h>
#include "dev.h"
#include "8390.h"
/* These should be in <asm/io.h> someday, borrowed from blk_drv/hd.c. */
#define port_read(port,buf,nr) \
__asm__("cld;rep;insw"::"d" (port),"D" (buf),"c" (nr):"cx","di")
#define port_write(port,buf,nr) \
__asm__("cld;rep;outsw"::"d" (port),"S" (buf),"c" (nr):"cx","si")
#define port_read_b(port,buf,nr) \
__asm__("cld;rep;insb"::"d" (port),"D" (buf),"c" (nr):"cx","di")
#define port_write_b(port,buf,nr) \
__asm__("cld;rep;outsb"::"d" (port),"S" (buf),"c" (nr):"cx","si")
#define EN_CMD (dev->base_addr)
#define NE_BASE (dev->base_addr)
#define NE_DATAPORT 0x10 /* NatSemi-defined port window offset. */
#define NE_RESET 0x1f /* Issue a read to reset, a write to clear. */
#define NE1SM_START_PG 0x20 /* First page of TX buffer */
#define NE1SM_STOP_PG 0x40 /* Last page +1 of RX ring */
#define NESM_START_PG 0x40 /* First page of TX buffer */
#define NESM_STOP_PG 0x80 /* Last page +1 of RX ring */
extern void NS8390_init(struct device *dev, int startp);
extern int ei_debug;
extern struct sigaction ei_sigaction;
extern struct ei_device ei_status;
int neprobe(int ioaddr, struct device *dev);
static int neprobe1(int ioaddr, struct device *dev);
static void ne_reset_8390(struct device *dev);
static int ne_block_input(struct device *dev, int count,
char *buf, int ring_offset);
static void ne_block_output(struct device *dev, const int count,
const unsigned char *buf, const int start_page);
static void ne_init_card(struct device *dev);
/* Probe for the NE1000 and NE2000. NEx000-like boards have 0x57,0x57 in
bytes 0x0e,0x0f of the SAPROM, but if we read by 16 bit words the NE1000
appears to have 0x00, 0x42. */
/* Also initialize the card and fill in STATION_ADDR with the station
address. The station address (and other data) is stored in the
packet buffer memory space, 32 bytes starting at remote DMA address 0. */
int neprobe(int ioaddr, struct device *dev)
{
int *port, ports[] = {0x300, 0x320, 0x340, 0x360, 0};
if (ioaddr > 0x100)
return neprobe1(ioaddr, dev);
for (port = &ports[0]; *port; port++)
if (inb_p(*port) != 0xff && neprobe1(*port, dev))
return dev->base_addr = *port;
return 0;
}
static int neprobe1(int ioaddr, struct device *dev)
{
int i;
unsigned char *station_addr = dev->dev_addr;
unsigned char SA_prom[32];
int cmdreg;
int ne2000 = 0, ne1000 = 0, ctron = 0, dlink = 0;
printk("8390 ethercard probe at %#3x:", ioaddr);
cmdreg = inb_p(ioaddr);
if (cmdreg == 0xFF) {
printk(" not found (%#2.2x).\n", cmdreg);
return 0;
}
/* Ooops, we must first initialize registers -- we can't just read the PROM
address right away. (Learned the hard way.) */
/* NS8390_init(eifdev, 0);*/
outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, ioaddr);
#ifdef EI_8BIT
outb_p(0x48, ioaddr + EN0_DCFG); /* Set byte-wide for probe. */
#else
outb_p(0x49, ioaddr + EN0_DCFG); /* Set word-wide for probe. */
#endif
/* Even though we'll set them soon, we must clear them! */
outb_p(0x00, ioaddr + EN0_RCNTLO);
outb_p(0x00, ioaddr + EN0_RCNTHI);
outb_p(0x00, ioaddr + EN0_IMR); /* Mask completion irq. */
outb_p(0xFF, ioaddr + EN0_ISR);
/* Set to monitor and loopback mode. */
outb_p(E8390_RXOFF, ioaddr + EN0_RXCR); /* 0x20 */
outb_p(E8390_TXOFF, ioaddr + EN0_TXCR); /* 0x02 */
#ifdef EI_8BIT
outb_p(sizeof(SA_prom), ioaddr + EN0_RCNTLO);
#else
/* Double count 0x20 words, the SA PROM is only byte wide. */
outb_p(2*sizeof(SA_prom), ioaddr + EN0_RCNTLO);
#endif
outb_p(0x00, ioaddr + EN0_RCNTHI);
outb_p(0x00, ioaddr + EN0_RSARLO); /* DMA starting at 0x0000. */
outb_p(0x00, ioaddr + EN0_RSARHI);
outb_p(E8390_RREAD+E8390_START, ioaddr);
for(i = 0; i < sizeof(SA_prom); i++) {
SA_prom[i] = inb_p(ioaddr + NE_DATAPORT);
if (i < ETHER_ADDR_LEN && station_addr) {
printk(" %2.2x", SA_prom[i]);
station_addr[i] = SA_prom[i];
}
}
#ifdef EI_8BIT
ne1000 = (SA_prom[14] == 0x57 && SA_prom[15] == 0x57);
ctron = (SA_prom[0] == 0x00 && SA_prom[1] == 0x00 && SA_prom[2] == 0x1d);
dlink = (SA_prom[0] == 0x00 && SA_prom[1] == 0xDE && SA_prom[2] == 0x01);
#else
ne2000 = (SA_prom[14] == 0x57 && SA_prom[15] == 0x57);
ne1000 = (SA_prom[14] == 0x00 && SA_prom[15] == 0x42);
ctron = (SA_prom[0] == 0x00 && SA_prom[1] == 0x00 && SA_prom[2] == 0x1d);
dlink = (SA_prom[0] == 0x00 && SA_prom[1] == 0xDE && SA_prom[2] == 0x01);
#endif
/* Set up the rest of the parameters. */
if (ne1000 || dlink) {
ei_status.name = ne1000 ? "NE1000" : "D-Link";
ei_status.word16 = 0;
ei_status.tx_start_page = NE1SM_START_PG;
ei_status.rx_start_page = NE1SM_START_PG + TX_PAGES;
ei_status.stop_page = NE1SM_STOP_PG;
} else if (ne2000) {
ei_status.name = "NE2000";
ei_status.word16 = 1;
ei_status.tx_start_page = NESM_START_PG;
ei_status.rx_start_page = NESM_START_PG + TX_PAGES;
ei_status.stop_page = NESM_STOP_PG;
} else if (ctron) {
/* You'll have to set these yourself, but this info might be useful.
Cabletron packet buffer locations:
E1010 starts at 0x100 and ends at 0x2000.
E1010-x starts at 0x100 and ends at 0x8000. ("-x" means "more memory")
E2010 starts at 0x100 and ends at 0x4000.
E2010-x starts at 0x100 and ends at 0xffff. */
ei_status.name = "Cabletron";
#ifdef EI_8BIT
ei_status.word16 = 0;
#else
ei_status.word16 = 1;
#endif
ei_status.tx_start_page = 0x01;
ei_status.rx_start_page = 0x01 + TX_PAGES;
#ifndef CTRON_MEMSIZE
#define CTRON_MEMSIZE 0x20 /* Extra safe... */
#endif
ei_status.stop_page = CTRON_MEMSIZE;
} else {
printk(" not found.\n");
return 0;
}
dev->base_addr = ioaddr;
if (dev->irq < 2) {
int nic_base = dev->base_addr;
autoirq_setup(0);
outb_p(0x50, nic_base + EN0_IMR); /* Enable one interrupt. */
outb_p(0x00, nic_base + EN0_RCNTLO);
outb_p(0x00, nic_base + EN0_RCNTHI);
outb_p(E8390_RREAD+E8390_START, nic_base); /* Trigger it... */
outb_p(0x00, nic_base + EN0_IMR); /* Mask it again. */
dev->irq = autoirq_report(0);
if (ei_debug > 2)
printk(" autoirq is %d", dev->irq);
} else if (dev->irq == 2)
/* Fixup for users that don't know that IRQ 2 is really IRQ 9,
or don't know which one to set. */
dev->irq = 9;
/* Snarf the interrupt now. There's no point in waiting since we cannot
share and the board will usually be enabled. */
{ int irqval = irqaction (dev->irq, &ei_sigaction);
if (irqval) {
printk (" unable to get IRQ %d (irqval=%d).\n", dev->irq, irqval);
return 0;
}
}
printk(" %s found, using IRQ %d.\n", ei_status.name, dev->irq);
if (ei_debug > 1)
printk(version);
ei_status.reset_8390 = &ne_reset_8390;
ei_status.block_input = &ne_block_input;
ei_status.block_output = &ne_block_output;
ne_init_card(dev);
return dev->base_addr;
}
static void
ne_reset_8390(struct device *dev)
{
int tmp = inb_p(NE_BASE + NE_RESET);
int reset_start_time = jiffies;
if (ei_debug > 1) printk("resetting the 8390 t=%d...", jiffies);
ei_status.txing = 0;
sti();
/* We shouldn't use the boguscount for timing, but this hasn't been
checked yet, and you could hang your machine if jiffies break... */
{
int boguscount = 150000;
while(jiffies - reset_start_time < 2)
if (boguscount-- < 0) {
printk("jiffy failure (t=%d)...", jiffies);
outb_p(tmp, NE_BASE + NE_RESET);
return;
}
}
outb_p(tmp, NE_BASE + NE_RESET);
while ((inb_p(NE_BASE+EN0_ISR) & ENISR_RESET) == 0)
if (jiffies - reset_start_time > 2) {
printk(EI_NAME": ne_reset_8390() did not complete.\n");
break;
}
}
/* Block input and output, similar to the Crynwr packet driver. If you
porting to a new ethercard look at the packet driver source for hints.
The NEx000 doesn't share it on-board packet memory -- you have to put
the packet out through the "remote DMA" dataport using outb. */
static int
ne_block_input(struct device *dev, int count, char *buf, int ring_offset)
{
int xfer_count = count;
int nic_base = NE_BASE;
outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, EN_CMD);
outb_p(count & 0xff, nic_base + EN0_RCNTLO);
outb_p(count >> 8, nic_base + EN0_RCNTHI);
outb_p(ring_offset & 0xff, nic_base + EN0_RSARLO);
outb_p(ring_offset >> 8, nic_base + EN0_RSARHI);
outb_p(E8390_RREAD+E8390_START, EN_CMD);
if (ei_status.word16) {
port_read(NE_BASE + NE_DATAPORT,buf,count>>1);
if (count & 0x01)
buf[count-1] = inb(NE_BASE + NE_DATAPORT), xfer_count++;
} else {
port_read_b(NE_BASE + NE_DATAPORT, buf, count);
}
/* This was for the ALPHA version only, but enough people have
encountering problems that it is still here. */
if (ei_debug > 0) { /* DMA termination address check... */
int addr, tries = 10;
do {
/* DON'T check for 'inb_p(EN0_ISR) & ENISR_RDC' here
-- it's broken! Check the "DMA" address instead. */
int high = inb_p(nic_base + EN0_RSARHI);
int low = inb_p(nic_base + EN0_RSARLO);
addr = (high << 8) + low;
if (((ring_offset + xfer_count) & 0xff) == low)
return ring_offset + count;
} while (--tries > 0);
printk(EI_NAME": RX transfer address mismatch, %#4.4x (should be) vs. %#4.4x (actual).\n",
ring_offset + xfer_count, addr);
}
return ring_offset + count;
}
static void
ne_block_output(struct device *dev, int count,
const unsigned char *buf, const int start_page)
{
int retries = 0;
int nic_base = NE_BASE;
/* Round the count up for word writes. Do we need to do this?
What effect will an odd byte count have on the 8390?
I should check someday. */
if (ei_status.word16 && (count & 0x01))
count++;
/* We should already be in page 0, but to be safe... */
outb_p(E8390_PAGE0+E8390_START+E8390_NODMA, EN_CMD);
retry:
#if defined(rw_bugfix)
/* Handle the read-before-write bug the same way as the
Crynwr packet driver -- the NatSemi method doesn't work.
Actually this doesn't aways work either, but if you have
problems with your NEx000 this is better than nothing! */
outb_p(0x42, nic_base + EN0_RCNTLO);
outb_p(0x00, nic_base + EN0_RCNTHI);
outb_p(0x42, nic_base + EN0_RSARLO);
outb_p(0x00, nic_base + EN0_RSARHI);
outb_p(E8390_RREAD+E8390_START, EN_CMD);
/* Make certain that the dummy read has occured. */
SLOW_DOWN_IO;
SLOW_DOWN_IO;
SLOW_DOWN_IO;
#endif /* rw_bugfix */
/* Now the normal output. */
outb_p(count & 0xff, nic_base + EN0_RCNTLO);
outb_p(count >> 8, nic_base + EN0_RCNTHI);
outb_p(0x00, nic_base + EN0_RSARLO);
outb_p(start_page, nic_base + EN0_RSARHI);
outb_p(E8390_RWRITE+E8390_START, EN_CMD);
if (ei_status.word16) {
port_write(NE_BASE + NE_DATAPORT, buf, count>>1);
} else {
port_write_b(NE_BASE + NE_DATAPORT, buf, count);
}
/* This was for the ALPHA version only, but enough people have
encountering problems that it is still here. */
if (ei_debug > 0) { /* DMA termination address check... */
int addr, tries = 10;
do {
/* DON'T check for 'inb_p(EN0_ISR) & ENISR_RDC' here
-- it's broken! Check the "DMA" address instead. */
int high = inb_p(nic_base + EN0_RSARHI);
int low = inb_p(nic_base + EN0_RSARLO);
addr = (high << 8) + low;
if ((start_page << 8) + count == addr)
return;
} while (--tries > 0);
printk(EI_NAME": Packet buffer transfer address mismatch on TX, %#4.4x vs. %#4.4x.\n",
(start_page << 8) + count, addr);
if (retries++ == 0)
goto retry;
}
return;
}
/* This function resets the ethercard if something screws up. */
static void
ne_init_card(struct device *dev)
{
NS8390_init(dev, 0);
return;
}
/*
* Local variables:
* compile-command: "gcc -DKERNEL -Wall -O6 -fomit-frame-pointer -I/usr/src/linux/net/tcp -c ne.c"
* version-control: t
* kept-new-versions: 5
* End:
*/

334
net/tcpip/ether-995/wd.c Normal file
View File

@@ -0,0 +1,334 @@
/* wd.c: A WD80x3 ethernet driver for linux. */
/*
Written 1993 by Donald Becker. This is alpha test code.
This is a extension to the Linux operating system, and is covered by
same Gnu Public License that covers that work.
This is a driver for the WD8003 and WD8013 ethercards.
The Author may be reached as becker@super.org or
C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
Thanks to Russ Nelson (nelson@crnwyr.com) for loaning me a WD8013.
*/
static char *version =
"wd.c:v0.30 1/30/93 Donald Becker (becker@super.org)\n";
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <asm/io.h>
#include <asm/system.h>
#include <memory.h>
#include "dev.h"
#include "8390.h"
extern void NS8390_init(struct device *dev, int startp);
extern int ei_debug;
extern struct sigaction ei_sigaction;
extern struct ei_device ei_status;
int wdprobe(int ioaddr, struct device *dev);
int wdprobe1(int ioaddr, struct device *dev);
static void wd_reset_8390(struct device *dev);
static int wd_block_input(struct device *dev, int count,
char *buf, int ring_offset);
static void wd_block_output(struct device *dev, int count,
const unsigned char *buf, const start_page);
static int wd_close_card(struct device *dev);
#define WD_START_PG 0x00 /* First page of TX buffer */
#define WD03_STOP_PG 0x20 /* Last page +1 of RX ring */
#define WD13_STOP_PG 0x40 /* Last page +1 of RX ring */
#define WD_CMDREG 0 /* Offset to ASIC command register. */
#define WD_RESET 0x80 /* Board reset, in WD_CMDREG. */
#define WD_MEMENB 0x40 /* Enable the shared memory. */
#define WD_CMDREG5 5 /* Offset to 16-bit-only ASIC register 5. */
#define ISA16 0x80 /* Enable 16 bit access from the ISA bus. */
#define NIC16 0x40 /* Enable 16 bit access from the 8390. */
#define WD_NIC_OFFSET 16 /* Offset to the 8390 NIC from the base_addr. */
/* Probe for the WD8003 and WD8013. These cards have the station
address PROM at I/O ports <base>+8 to <base>+13, with a checksum
following. The routine also initializes the card and fills the
station address field. */
int wdprobe(int ioaddr, struct device *dev)
{
int *port, ports[] = {0x300, 0x280, 0};
if (ioaddr > 0x100)
return wdprobe1(ioaddr, dev);
for (port = &ports[0]; *port; port++)
if (inb(*port) != 0xff && wdprobe1(*port, dev))
return *port;
return 0;
}
int wdprobe1(int ioaddr, struct device *dev)
{
int i;
unsigned char *station_addr = dev->dev_addr;
int checksum = 0;
int bits16 = 0;
#if defined(EI_DEBUG) && EI_DEBUG > 2
printk("WD80x3 ethercard at %#3x:", ioaddr);
for (i = 0; i < 16; i++) {
printk(" %2.2X", inb(ioaddr+i));
}
printk("\n");
printk("WD80x3 ethercard at %#3x:", ioaddr+i);
for (;i < 33; i++) {
printk(" %2.2X", inb(ioaddr+i));
}
printk("\n");
#endif
printk("WD80x3 ethercard probe at %#3x:", ioaddr);
for (i = 0; i < 8; i++) {
int inval = inb(ioaddr + 8 + i);
checksum += inval;
if (i < 6)
printk(" %2.2X", (station_addr[i] = inval));
}
if ((checksum & 0xff) != 0xFF) {
printk(" not found (%#2.2x).\n", checksum);
return 0;
}
ei_status.name = "WD8003";
ei_status.word16 = 0;
/* This method of checking for a 16-bit board is borrowed from the
we.c driver. A simpler method is just to look in ASIC reg. 0x03.
I'm comparing the two method in alpha test to make certain they
return the same result. */
#ifndef FORCE_8BIT /* Same define as we.c. */
/* check for 16 bit board - it doesn't have register 0/8 aliasing */
for (i = 0; i < 8; i++) {
int tmp;
if( inb(ioaddr+8+i) != inb(ioaddr+i) ){
tmp = inb(ioaddr+1); /* fiddle with 16bit bit */
outb( tmp ^ 0x01, ioaddr+1 ); /* attempt to clear 16bit bit */
if ((tmp & 0x01) == (inb( ioaddr+1) & 0x01)) {
int asic_reg5 = inb(ioaddr+WD_CMDREG5);
bits16 = 1; /* use word mode of operation */
/* Magic to set ASIC to word-wide mode. */
outb( ISA16 | NIC16 | (asic_reg5&0x1f), ioaddr+WD_CMDREG5);
outb(tmp, ioaddr+1);
ei_status.name = "WD8013";
ei_status.word16 = 1;
break; /* We have a 16bit board here! */
}
outb(tmp, ioaddr+1);
}
}
#else
bits8 = 1;
#endif /* FORCE_8BIT */
#ifndef final_version
if ((inb(ioaddr+1) & 0x01) != (ei_status.word16 & 0x01))
printk("\nWD80x3: Bus width conflict, %d (probe) != %d (reg report).\n",
ei_status.word16 ? 16:8, (inb(ioaddr+1) & 0x01) ? 16 : 8);
#endif
#if defined(WD_SHMEM) && WD_SHMEM > 0x80000
/* Allow an override for alpha testing. */
dev->mem_start = WD_SHMEM;
#else
if (dev->mem_start == 0) {
dev->mem_start = ((inb(ioaddr)&0x3f) << 13) +
(ei_status.word16 ? (inb(ioaddr+WD_CMDREG5)&0x1f)<<19 : 0x80000);
printk(" address %#x,", dev->mem_start);
}
#endif
/* The 8390 isn't at the base address -- the ASIC regs are there! */
dev->base_addr = ioaddr+WD_NIC_OFFSET;
ei_status.tx_start_page = WD_START_PG;
ei_status.rx_start_page = WD_START_PG + TX_PAGES;
ei_status.stop_page = ei_status.word16 ? WD13_STOP_PG : WD03_STOP_PG;
dev->rmem_start = dev->mem_start + TX_PAGES*256;
dev->mem_end = dev->rmem_end
= dev->mem_start + (ei_status.stop_page - WD_START_PG)*256;
#if defined(EI_DEBUG) && EI_DEBUG > 3
memset((void*)dev->mem_start, 0x42052465,
(ei_status.stop_page - WD_START_PG)*256);
#endif
if (dev->irq < 2) {
int irqmap[] = {9,3,5,7,10,11,15,4};
dev->irq = irqmap[((inb(ioaddr+4) >> 5) & 0x03)
+ (inb(ioaddr+1) & 0x04)];
} else if (dev->irq == 2)
/* Fixup for users that don't know that IRQ 2 is really IRQ 9,
or don't know which one to set. */
dev->irq = 9;
/* Snarf the interrupt now. There's no point in waiting since we cannot
share and the board will usually be enabled. */
{ int irqval = irqaction (dev->irq, &ei_sigaction);
if (irqval) {
printk (" unable to get IRQ %d (irqval=%d).\n", dev->irq, irqval);
return 0;
}
}
printk(" %s found, using IRQ %d.\n", ei_status.name, dev->irq);
if (ei_debug > 1)
printk(version);
if (ei_debug > 2)
printk("%s: Address read from register is %#x, setting address %#x\n",
ei_status.name,
((inb(ioaddr+WD_CMDREG5)&0x1f)<<19) + ((inb(ioaddr)&0x3f) << 13),
dev->mem_start);
/* Map in the shared memory. This is a little risky, since using
the stuff the user supplied is probably a bad idea. */
outb((((dev->mem_start>>13) & 0x3f)|WD_MEMENB), ioaddr); /* WD_CMDREG */
if (ei_status.word16)
outb( ISA16 | NIC16 | ((dev->mem_start>>19) & 0x1f), ioaddr+WD_CMDREG5);
ei_status.reset_8390 = &wd_reset_8390;
ei_status.block_input = &wd_block_input;
ei_status.block_output = &wd_block_output;
dev->stop = &wd_close_card;
NS8390_init(dev, 0);
return dev->base_addr;
}
static void
wd_reset_8390(struct device *dev)
{
int wd_cmd_port = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
int reset_start_time = jiffies;
outb(WD_RESET, wd_cmd_port);
if (ei_debug > 1) printk("resetting the WD80x3 t=%d...", jiffies);
ei_status.txing = 0;
sti();
/* We shouldn't use the boguscount for timing, but this hasn't been
checked yet, and you could hang your machine if jiffies break... */
{
int boguscount = 150000;
while(jiffies - reset_start_time < 2)
if (boguscount-- < 0) {
printk("jiffy failure (t=%d)...", jiffies);
break;
}
}
outb(0x00, wd_cmd_port);
while ((inb(dev->base_addr+EN0_ISR) & ENISR_RESET) == 0)
if (jiffies - reset_start_time > 2) {
printk(EI_NAME": wd_reset_8390() did not complete.\n");
break;
}
#if defined(EI_DEBUG) && EI_DEBUG > 2
{
int i;
printk("WD80x3 ethercard at %#3x:", wd_cmd_port);
for (i = 0; i < 16; i++) {
printk(" %2.2X", inb(wd_cmd_port+i));
}
printk("\nWD80x3 ethercard at %#3x:", wd_cmd_port);
for (;i < 33; i++) {
printk(" %2.2X", inb(wd_cmd_port+i));
}
printk("\n");
}
#endif
/* Set up the ASIC registers, just in case something changed them. */
outb((((dev->mem_start>>13) & 0x3f)|WD_MEMENB), wd_cmd_port); /* WD_CMDREG */
if (ei_status.word16)
outb( ISA16 | NIC16 | ((dev->mem_start>>19) & 0x1f), wd_cmd_port+WD_CMDREG5);
}
/* Block input and output are easy on shared memory ethercards, and trivial
on the Western digital card where there is no choice of how to do it. */
static int
wd_block_input(struct device *dev, int count, char *buf, int ring_offset)
{
void *xfer_start = (void *)(dev->mem_start + ring_offset - (WD_START_PG<<8));
#ifdef mapout
int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
int mem_val = inb(wd_cmdreg);
/* Map in the shared memory. */
outb(mem_val|WD_MEMENB, wd_cmdreg);
#endif
if (xfer_start + count > (void*) dev->rmem_end) {
/* We must wrap the input move. */
int semi_count = (void*)dev->rmem_end - xfer_start;
memcpy(buf, xfer_start, semi_count);
count -= semi_count;
memcpy(buf + semi_count, (char *)dev->rmem_start, count);
return dev->rmem_start + count;
}
memcpy(buf, xfer_start, count);
if (ei_debug > 4) {
unsigned short *board = xfer_start;
printk("wd8013: wd_block_input(cnt=%d offset=%3x addr=%#x) = %2x %2x %2x...\n",
count, ring_offset, xfer_start, board[-1], board[0], board[1]);
}
#ifdef mapout
outb(mem_val & ~WD_MEMENB, wd_cmdreg); /* WD_CMDREG: Map out the shared memory. */
#endif
return ring_offset + count;
}
/* This could only be outputting to the transmit buffer. The
ping-pong transmit setup doesn't work with this yet. */
static void
wd_block_output(struct device *dev, int count, const unsigned char *buf, int start_page)
{
unsigned char *shmem = (void *)dev->mem_start + ((start_page - WD_START_PG)<<8);
#ifdef mapout
int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
int mem_val = inb(wd_cmdreg);
/* Map in the shared memory. */
outb(mem_val|WD_MEMENB, wd_cmdreg);
#endif
memcpy(shmem, buf, count);
if (ei_debug > 4)
printk("wd8013: wd_block_output(addr=%#x cnt=%d) -> %2x=%2x %2x=%2x %d...\n",
shmem, count, shmem[23], buf[23], shmem[24], buf[24], memcmp(shmem,buf,count));
#ifdef mapout
outb(mem_val & ~WD_MEMENB, wd_cmdreg); /* WD_CMDREG: Map out the shared memory. */
#endif
}
/* This function resets the ethercard if something screws up. */
static int
wd_close_card(struct device *dev)
{
if (ei_debug > 1)
printk("%s: shutting down ethercard.\n", ei_status.name);
NS8390_init(dev, 0);
/* Turn off the shared memory. */
outb((((dev->mem_start>>13) & 0x3f)),
dev->base_addr-WD_NIC_OFFSET); /* WD_CMDREG */
return 0;
}
/*
* Local variables:
* compile-command: "gcc -DKERNEL -Wall -O6 -fomit-frame-pointer -I/usr/src/linux/net/tcp -c wd.c"
* version-control: t
* kept-new-versions: 5
* End:
*/

BIN
net/tcpip/ftp-rl.taz Normal file

Binary file not shown.

BIN
net/tcpip/ftpd-dik.taz Normal file

Binary file not shown.

View File

@@ -0,0 +1 @@
stammt von super.org:/pub/linux

368
net/tcpip/ne2000/3c501.c Normal file
View File

@@ -0,0 +1,368 @@
/* 3c501.c: A 3Com 3c501 ethernet driver for linux. */
#include <linux/config.h>
#ifdef ETHERLINK1
/*
Copyright (C) 1992 Donald Becker
This is alpha test code. No general redistribution is permitted.
This is a device driver for the 3Com Etherlink 3c501.
Do not purchase this card, even as a joke. It's performance is horrible,
and it breaks in many ways.
The Author may be reached as becker@super.org or
C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
*/
/*
Braindamage remaining:
The 3c501 board.
*/
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/tty.h>
#include <linux/types.h>
#include <linux/ptrace.h>
#include <linux/string.h>
#include <asm/system.h>
#include <asm/segment.h>
/* This should be checked for necessity after testing. */
#define REALLY_SLOW_IO
#include <asm/io.h>
#include <errno.h>
#include <linux/fcntl.h>
#include <netinet/in.h>
#include "dev.h"
#include "eth.h"
#include "timer.h"
#include "ip.h"
#include "tcp.h"
#include "sock.h"
#include "arp.h"
/* These should be in <asm/io.h> someday, borrowed from blk_drv/hd.c. */
#define port_read_b(port,buf,nr) \
__asm__("cld;rep;insb"::"d" (port),"D" (buf),"c" (nr):"cx","di")
#define port_write_b(port,buf,nr) \
__asm__("cld;rep;outsb"::"d" (port),"S" (buf),"c" (nr):"cx","si")
#define DEBUG 10 /* use 0 for production, 1 for devel., >2 for debug */
/* Index to functions. */
static void el_interrupt(int reg_ptr);
static void el_send_packet(struct sk_buff *skb, struct device *dev);
static void el_receive(struct device *dev);
#define EL_NAME "EtherLink 3c501"
static int el_debug = DEBUG; /* Anything above 5 is wordy death! */
static int el_base;
static struct device *eldev; /* Only for consistency checking. */
/* We could put everything in a struct to be malloc()ed per-board, but
who would want more than one 3c501?. */
static struct { /* This should be stored per-board */
char *name;
int exists:1; /* perhaps in dev->private. */
int open:1;
int txing:1; /* Transmit Active, don't confuse the 8390 */
int in_interrupt:4;
int overruns, rx_errors, tx_errors;
} el_status = { "Etherlink I", 0, 0, 0, 0, 0, 0, 0 };
static int collisions; /* Tx collisions this packet */
static int tx_pkt_length; /* To reset GP after each collision. */
static int runt_packets = 0; /* # of runt packets picked up so far. */
/* static int rx_missed = 0; * # of packets we missed. */
static struct sigaction el_sigaction = { el_interrupt, 0, 0, NULL, };
#define RX_STATUS (el_base + 0x06)
#define TX_STATUS (el_base + 0x07)
#define GP_LOW (el_base + 0x08)
#define GP_HIGH (el_base + 0x09)
#define RX_LOW (el_base + 0x0A)
#define RX_HIGH (el_base + 0x0B)
#define SAPROM (el_base + 0x0C)
#define AX_STATUS (el_base + 0x0E)
#define DATAPORT (el_base + 0x0F)
#define TX_RDY 0x08 /* In TX_STATUS */
/* Writes to the ax command register. */
#define AX_OFF 0x40 /* Irq off, buffer access on */
#define AX_SYS 0x41 /* Load the buffer */
#define AX_XMIT 0x45 /* Transmit a packet */
#define AX_RX 0x49 /* Receive a packet */
#define AX_LOOP 0x4D /* Loopback */
/* Normal receive mode written to RX_STATUS. We must intr on short packets
to avoid bogus rx lockups. */
#define RX_NORM 0xA8
/* TX_STATUS register. */
#define TX_COLLISION 0x02
/* Open/initialize the board. */
static int
el_open(struct device *dev)
{
if ( ! el_status.exists) {
printk(EL_NAME ": Opening a non-existent physical device\n");
return 1; /* We should have a better error return. */
}
if (el_debug > 2)
printk(EL_NAME ": Doing el_open(%s)...",
dev == eldev ? dev->name : " on unknown dev");
el_status.txing = 0;
el_status.in_interrupt = 0;
outb_p(AX_LOOP, AX_STATUS); /* Aux control, irq and loopback enabled */
outb_p(0x00, RX_LOW); /* Set rx packet area to 0. */
outb_p(RX_NORM, RX_STATUS); /* Set Rx commands. */
outb_p(AX_RX, AX_STATUS); /* Aux control, irq and receive enabled */
el_status.open = 1;
if (el_debug > 2)
printk("finished el_open().\n");
return (0);
}
int
el_start_xmit(struct sk_buff *skb, struct device *dev)
{
int axsr;
if ( ! el_status.exists)
return 0; /* We should have a better error return. */
if (el_debug > 2)
printk(EL_NAME": Doing el_start_xmit(<sk_buff%x>,%s).\n", skb,
dev == eldev ? "EtherLink" : "unknown dev");
cli();
if (el_debug > 4) printk(EL_NAME": interrupts suspended...");
axsr = inb_p(AX_STATUS);
if (el_status.txing || axsr & 0x01) {
if (jiffies - dev->trans_start < 30) {
sti();
if (el_debug > 2)
printk(EL_NAME": transmit deferred, no timeout.\n");
return 1;
}
printk (EL_NAME ": transmit timed out with tx status %#2x.\n",
inb(TX_STATUS));
}
if (el_debug > 4) printk("doing sti()...");
sti();
if (el_debug > 4) printk("filling in hdr...");
/* This is new: it means some higher layer thinks we've missed an
tx-done interrupt. */
if (skb == NULL) {
/* Alternative is ei_tx_intr(dev); */
el_status.txing = 1;
if (dev_tint(NULL, dev) == 0)
el_status.txing = 0;
return 0;
}
/* Fill in the ethernet header. */
if (!skb->arp && dev->rebuild_header(skb+1, dev)) {
skb->dev = dev;
arp_queue (skb);
if (el_debug > 1)
printk(" Exiting from xmit_start() via rebuild header?\n");
return 0;
}
dev->trans_start = jiffies;
el_status.txing = 1;
outb_p(0x0A, TX_STATUS); /* tx irq on done, collision */
el_send_packet(skb, dev);
if (skb->free)
kfree_skb (skb, FREE_WRITE);
if (el_debug > 3)
printk(EL_NAME": Returning from el_start_xmit().\n");
return 0;
}
/* The typical workload of the driver:
Handle the ether interface interrupts. */
static void
el_interrupt(int reg_ptr)
{
int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2);
int axsr; /* Aux. status reg. */
int txsr; /* Tx. status reg. */
int rxsr; /* Rx. status reg. */
if (eldev->irq != irq) {
printk (EL_NAME ": irq %d for unknown device\n", irq);
return;
}
el_status.in_interrupt++;
sti(); /* Turn interrupts back on. */
axsr = inb_p(AX_STATUS);
txsr = inb_p(TX_STATUS);
rxsr = inb_p(RX_STATUS);
if (el_debug > 1)
printk(EL_NAME": in el_interrupt(), axsr=%#2x, txsr=%#2x, rxsr=%#2x.\n",
axsr, txsr, rxsr);
if (el_status.in_interrupt > 1) {
/* We should probably return here -- the 3c501 glitches the
interrupt line when you write to the rx or tx command register. */
printk(EL_NAME ": Reentering the interrupt driver!\n");
}
if (rxsr & 0x08)
runt_packets++; /* Just reading rxstatus fixes this. */
else if (rxsr & 0x20)
el_receive(eldev);
else if (txsr & TX_COLLISION) {
if (++collisions > 16) {
printk(EL_NAME": Transmit failed 16 times, ethernet jammed?\n");
/* Turn receiving back on. */
el_status.txing = 0;
outb_p(0x00, RX_LOW);
outb_p(AX_RX, AX_STATUS);
} else { /* Retrigger xmit. */
int gp_start = 0x800 - tx_pkt_length;
outb_p(gp_start, GP_LOW);
outb_p(gp_start>>8, GP_HIGH);
outb_p(AX_XMIT, AX_STATUS);
}
} else if (txsr & TX_RDY) {
if (dev_tint(NULL, eldev) == 0)
el_status.txing = 0; /* We could turn off the tx... */
}
el_status.in_interrupt--;
return;
}
/* This is stuffed into the dev struct to be called by dev.c:dev_tint(). */
static void
el_send_packet(struct sk_buff *skb, struct device *dev)
{
tx_pkt_length = skb->len;
collisions = 0;
if (el_debug > 3) printk(" el_send_packet(%d)...", tx_pkt_length);
/* Should we check for tiny (or huge) lengths here? */
if (tx_pkt_length) {
int gp_start = 0x800 - tx_pkt_length;
unsigned char *buf = (void *)(skb+1);
outb_p(AX_OFF, AX_STATUS); /* irq disabled, rx off */
outb_p(gp_start, GP_LOW);
outb_p(gp_start>>8, GP_HIGH);
/* After testing use port_write(), defined above. */
for (; gp_start < 0x800; gp_start++)
outb_p(*buf++, DATAPORT);
outb_p(AX_XMIT, AX_STATUS); /* Trigger xmit. */
}
}
/* We have a good packet; well, not really "good", just mostly not broken.
We must check everything to see if it is good. */
static void
el_receive(struct device *dev)
{
int state = 0, sksize, length;
struct sk_buff *skb;
if (el_debug > 2)
printk("in el_receive...");
/* Painfully read it out of the local memory. */
outb_p(AX_SYS, AX_STATUS);
length = inb_p(RX_LOW) + (inb_p(RX_HIGH)<<8);
if ((length < 60 || length > 1535)) {
if (el_debug)
printk(EL_NAME": bogus packet, length=%d\n", length);
/* We should reset to receive... */
return;
}
sksize = sizeof(struct sk_buff) + length;
skb = kmalloc(sksize, GFP_ATOMIC);
outb_p(0x00, GP_LOW);
outb_p(0x00, GP_HIGH);
if (skb != NULL) {
unsigned char *buf = (void *)(skb+1);
skb->mem_len = sksize;
skb->mem_addr = skb;
/* After testing use port_read(), defined above. */
while (length-- > 0)
*buf++ = inb_p(DATAPORT);
state = dev_rint((void *)skb, length, IN_SKBUFF, dev);
} else if (el_debug) {
printk("Couldn't allocate a sk_buff of size %d.\n", sksize);
}
dev_rint(NULL, 0,0, dev); /* Inform upper level */
if (el_debug > 2)
printk("done.\n");
return;
}
void
etherlink_init(struct device *dev)
{
int i;
eldev = dev; /* Store for debugging. */
el_base = dev->base_addr;
printk("3c501 probe at %#3.3x: ", el_base);
outb(0x00, GP_HIGH);
for (i = 0; i < 6; i++) {
outb(i, GP_LOW); /* Set station address prom addr */
dev->dev_addr[i] = inb(SAPROM); /* Read Station address prom */
printk(" %2.2x", dev->dev_addr[i]);
}
/* Check the first three octets of the S.A. for 3Com's code. */
if (dev->dev_addr[0] != 0x02 || dev->dev_addr[1] != 0x60
|| dev->dev_addr[2] != 0x8c) {
printk(" Etherlink not found.\n", dev->base_addr);
el_status.exists = 0;
return;
}
el_status.exists = 1;
printk(" Etherlink found.\n");
/* Initialize the rest of the device structure. Most of these should
be in Space.c. */
for (i = 0; i < DEV_NUMBUFFS; i++)
dev->buffs[i] = NULL;
dev->hard_header = eth_hard_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->send_packet = &el_send_packet;
dev->open = &el_open;
dev->hard_start_xmit = &el_start_xmit;
dev->type = ETHER_TYPE;
dev->hard_header_len = sizeof (struct enet_header);
dev->mtu = 1500; /* eth_mtu */
dev->addr_len = ETHER_ADDR_LEN;
for (i = 0; i < dev->addr_len; i++) {
dev->broadcast[i]=0xff;
}
/* Turn off interrupts. */
/* Snarf the assigned interrupt. */
{ int irqval = irqaction (dev->irq, &el_sigaction);
if (irqval) {
printk (" unable to get IRQ%d, error=%d.\n", dev->irq, irqval);
return; /* Return failure someday */
}
}
outb(0x8C, 0x0e); /* setup Aux. control reg. */
return;
}
#endif /* ETHERLINK1 */
/*
* Local variables:
* compile-command: "gcc -DKERNEL -Wall -O6 -fomit-frame-pointer -DMAX_16M -I/usr/linux-master/net/tcp -c -o 3c501.o 3c501.c"
* End:
*/

1053
net/tcpip/ne2000/3c503.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,55 @@
/* Definitions for the Etherlink 2. */
#include "8390.h"
#define EL2H (dev->base_addr + 0x400)
#define EL2L (dev->base_addr)
/* 3Com 3c503 ASIC registers */
#define E33G_STARTPG (EL2H+0) /* Start page, must match EN0_STARTPG */
#define E33G_STOPPG (EL2H+1) /* Stop page, must match EN0_STOPPG */
#define E33G_NBURST (EL2H+2) /* Size of DMA burst before relinquishing bus */
#define E33G_IOBASE (EL2H+3) /* Bit coded: where I/O regs are jumpered. */
/* (Which you have to know already to read it) */
#define E33G_ROMBASE (EL2H+4) /* Bit coded: Where/whether EEPROM&DPRAM exist */
#define E33G_GACFR (EL2H+5) /* Config/setup bits for the ASIC GA */
#define E33G_CNTRL (EL2H+6) /* Board's main control register */
#define E33G_STATUS (EL2H+7) /* Status on completions. */
#define E33G_IDCFR (EL2H+8) /* Interrupt/DMA config register */
/* (Which IRQ to assert, DMA chan to use) */
#define E33G_DMAAH (EL2H+9) /* High byte of DMA address reg */
#define E33G_DMAAL (EL2H+10) /* Low byte of DMA address reg */
#define E33G_VP2 (EL2H+11) /* Vector pointer - for clearing RAM select */
#define E33G_VP1 (EL2H+12) /* on a system reset, to re-enable EPROM. */
#define E33G_VP0 (EL2H+13) /* 3Com says set this to Ctrl-Alt-Del handler */
#define E33G_FIFOH (EL2H+14) /* FIFO for programmed I/O data moves ... */
#define E33G_FIFOL (EL2H+15) /* .. low byte of above. */
/* Bits in E33G_CNTRL register: */
#define ECNTRL_RESET (0x01) /* Software reset of the ASIC and 8390 */
#define ECNTRL_THIN (0x02) /* Onboard thin-net xcvr enable */
#define ECNTRL_SAPROM (0x04) /* Map the station address prom */
#define ECNTRL_DBLBFR (0x20) /* FIFO configuration bit */
#define ECNTRL_OUTPUT (0x40) /* PC-to-3C503 direction if 1 */
#define ECNTRL_INPUT (0x00) /* 3C503-to-PC direction if 0 */
#define ECNTRL_START (0x80) /* Start the DMA logic */
/* Bits in E33G_STATUS register: */
#define ESTAT_DPRDY (0x80) /* Data port (of FIFO) ready */
#define ESTAT_UFLW (0x40) /* Tried to read FIFO when it was empty */
#define ESTAT_OFLW (0x20) /* Tried to write FIFO when it was full */
#define ESTAT_DTC (0x10) /* Terminal Count from PC bus DMA logic */
#define ESTAT_DIP (0x08) /* DMA In Progress */
/* Bits in E33G_GACFR register: */
#define EGACFR_NORM (0x49) /* Enable 8K shared mem, no DMA TC int */
#define EGACFR_IRQOFF (0xc9) /* Above, and disable 8390 IRQ line */
/* Shared memory management parameters */
#define EL2SM_TSTART_PG (0x20) /* First page of TX buffer */
#define EL2SM_RSTART_PG (0x26) /* Starting page of RX ring */
#define EL2SM_RSTOP_PG (0x40) /* Last page +1 of RX ring */
/* End of 3C503 parameter definitions */

90
net/tcpip/ne2000/8390.h Normal file
View File

@@ -0,0 +1,90 @@
/* Generic NS8390 register definitions. */
/* This file was originally written for the 3c503 driver, but should be
usable for most 8390-based network boards.
Some of these names are from the clarkson packet drivers. */
/* Some generic ethernet register configurations. */
#define E8390_TX_IRQ_MASK 0xa /* For register EN0_ISR */
#define E8390_RX_IRQ_MASK 0x5
#define E8390_RXCONFIG 0x4 /* EN0_RXCR: broadcasts, no multicast,errors */
#define E8390_RXOFF 0x20 /* EN0_RXCR: Accept no packets */
#define E8390_TXCONFIG 0x00 /* EN0_TXCR: Normal transmit mode */
#define E8390_TXOFF 0x02 /* EN0_TXCR: Transmitter off */
/* Register accessed at EN_CMD, the 8390 base addr. */
#define E8390_STOP 0x01 /* Stop the chip, software reset */
#define E8390_START 0x02 /* Start the chip after stopping */
#define E8390_TRANS 0x04 /* Transmit a frame */
#define E8390_RREAD 0x08 /* Remote read */
#define E8390_RWRITE 0x10 /* Remote write */
#define E8390_NODMA 0x20 /* No remote DMA used on this card */
#define E8390_PAGE0 0x00 /* Select page chip registers */
#define E8390_PAGE1 0x40 /* using the two high-order bits */
#define E8390_PAGE2 0x80 /* Page 3 is invalid. */
/* Page 0 register offsets. */
#define EN0_CLDALO 0x01 /* Low byte of current local dma addr RD */
#define EN0_STARTPG 0x01 /* Starting page of ring bfr WR */
#define EN0_CLDAHI 0x02 /* High byte of current local dma addr RD */
#define EN0_STOPPG 0x02 /* Ending page +1 of ring bfr WR */
#define EN0_BOUNDARY 0x03 /* Boundary page of ring bfr RD WR */
#define EN0_TSR 0x04 /* Transmit status reg RD */
#define EN0_TPSR 0x04 /* Transmit starting page WR */
#define EN0_NCR 0x05 /* Number of collision reg RD */
#define EN0_TCNTLO 0x05 /* Low byte of tx byte count WR */
#define EN0_FIFO 0x06 /* FIFO RD */
#define EN0_TCNTHI 0x06 /* High byte of tx byte count WR */
#define EN0_ISR 0x07 /* Interrupt status reg RD WR */
#define EN0_CRDALO 0x08 /* low byte of current remote dma address RD */
#define EN0_RSARLO 0x08 /* Remote start address reg 0 */
#define EN0_CRDAHI 0x09 /* high byte, current remote dma address RD */
#define EN0_RSARHI 0x09 /* Remote start address reg 1 */
#define EN0_RCNTLO 0x0a /* Remote byte count reg WR */
#define EN0_RCNTHI 0x0b /* Remote byte count reg WR */
#define EN0_RSR 0x0c /* rx status reg RD */
#define EN0_RXCR 0x0c /* RX configuration reg WR */
#define EN0_TXCR 0x0d /* TX configuration reg WR */
#define EN0_COUNTER0 0x0d /* Rcv alignment error counter RD */
#define EN0_DCFG 0x0e /* Data configuration reg WR */
#define EN0_COUNTER1 0x0e /* Rcv CRC error counter RD */
#define EN0_IMR 0x0f /* Interrupt mask reg WR */
#define EN0_COUNTER2 0x0f /* Rcv missed frame error counter RD */
/* Bits in EN0_ISR - Interrupt status register */
#define ENISR_RX 0x01 /* Receiver, no error */
#define ENISR_TX 0x02 /* Transmitter, no error */
#define ENISR_RX_ERR 0x04 /* Receiver, with error */
#define ENISR_TX_ERR 0x08 /* Transmitter, with error */
#define ENISR_OVER 0x10 /* Receiver overwrote the ring */
#define ENISR_COUNTERS 0x20 /* Counters need emptying */
#define ENISR_RDC 0x40 /* remote dma complete */
#define ENISR_RESET 0x80 /* Reset completed */
#define ENISR_ALL 0x3f /* Interrupts we will enable */
/* Bits in EN0_DCFG - Data config register */
#define ENDCFG_WTS 0x01 /* word transfer mode selection */
/* Page 1 register offsets. */
#define EN1_PHYS 0x01 /* This board's physical enet addr RD WR */
#define EN1_CURPAG 0x07 /* Current memory page RD WR */
#define EN1_MULT 0x08 /* Multicast filter mask array (8 bytes) RD WR */
/* Bits in received packet status byte and EN0_RSR*/
#define ENRSR_RXOK 0x01 /* Received a good packet */
#define ENRSR_CRC 0x02 /* CRC error */
#define ENRSR_FAE 0x04 /* frame alignment error */
#define ENRSR_FO 0x08 /* FIFO overrun */
#define ENRSR_MPA 0x10 /* missed pkt */
#define ENRSR_PHY 0x20 /* physical/multicase address */
#define ENRSR_DIS 0x40 /* receiver disable. set in monitor mode */
#define ENRSR_DEF 0x80 /* deferring */
/* Transmitted packet status, EN0_TSR. */
#define ENTSR_PTX 0x01 /* Packet transmitted without error */
/* The per-packet-header format. */
struct e8390_pkt_hdr {
unsigned char status; /* status */
unsigned char next; /* pointer to next packet. */
unsigned short count; /* header + packet lenght in bytes */
};

86
net/tcpip/ne2000/README Normal file
View File

@@ -0,0 +1,86 @@
Directory: ~ftp/pub/linux/
WARNING -- read the bugs section at the end of this file before getting
the ethernet board driver!!!
Files:
README This file, updated Tuesday Nov. 24, 1992 18:34.
3c501.c The 3c501 ethernet driver source
3c503.c The 3c503, 3c503/16, NE1000 and NE2000 ethernet driver source.
3c503reg.h Definitions specific to the 3c503
8390.h Generic definitions for the NS8390 chip.
Space.c Added the table entries for the new ethernet drivers.
This file is modified from the 0.98.4 release.
Image A pre-built Linux 0.98.4 kernel with MathEmu, no SCSI, mount
patch, serial patch, CapsLck mapped to Cntrl, and the
3c503 and NE2000 ethernet drivers. This kernel usually has
massive ethernet debugging turned on (debugging the kernel
and setting ei_debug = 0 and el_debug = 0 will turn it off)
and this version may not really work. Also the address and
IRQ settings are hard-coded for most ethercards. Making your
own kernel is usually a much better choice.
linux-0.98.3-E If it exists, the last Image file that worked OK.
Directions:
You might want to rename "3c503.c" to "ne2000.c".
Put the files (3c503.c, 3c503reg.h, 8390.h, and Space.c) into linux/net/tcp/.
Space.c is the only tricky one -- it overwrites the old Space.c, and
you'll need to edit it to add your IRQ and base address.
Next add 3c503.o to to linux/net/tcp/Makefile
tcpip.o: ... 3c503.o
Edit linux/include/linux/config.h and/or config.site.h and insert the following
(see below for other details).
#undef CONFIG_DISTRIBUTION /* Use config.site.h instead. */
#define EI8390 0x300 /* Then these should be in config.site.h */
#define EI8390IRQ 5 /* Not used yet, edit Space.c instead. */
#define EI_DEBUG 2
Make and install your new kernel.
To actually use this driver you must get the TCP/IP package and edit
your /usr/etc/inet/rc.net file to config device "eth_if" instead of
"eth0" (the WD8003).
BUGS
None know right now. I haven't tested the NS8390 overrun code -- it
worked OK the last time I had other bugs to trigger it, but I've
changed it since.
Two errors in some versions of the 8390/83901/83902 may not
be handled correctly: the first is a bug where the RX status bytes
is missing from the header -- I try to recover first rather than
resetting the chip (which I do afterwards).
The second is the 8390 problem with writes to the ethercard
RAM: the first write may be corrupted if you don't do a read
first -- I've never seen this corruption happen, but it may
just be masked by higher level protocols.
I have put in the read-first code, but it's a frequent
source of problems... The timing is really tricky.
The 3c501 driver isn't complete. This card severely brain-damaged
anyway -- you won't notice the performance diffence when it does work.
Please send me email if you do try out the drivers, even if you don't
encounter bugs.
Important defines
EI_DEBUG Set to the desired numeric debugging level. Use 3 or
greater when actively debugging a problem, '1' for a
casual interest in what's going on, and '0' for normal
use. (Most of the debugging stuff has been taken out recently,
so this won't have much effect.)
EI8390 Define (probably in config.site.h) this to the base address
of your ethernet card. You will also have to set the base
address and irq in net/tcp/Space.c.
ETHERLINK1 Define this to the base address of a 3c501 card. You will
also have to set the base address and irq in net/tcp/Space.c.

113
net/tcpip/ne2000/Space.c Normal file
View File

@@ -0,0 +1,113 @@
/* Space.c */
/* Holds initial configuration information for devices. */
#include "dev.h"
#include <linux/stddef.h>
#include <linux/config.h>
#ifdef ETHERLINK1
extern void etherlink_init(struct device *);
static struct device el_dev = {
"if3c501",
0, 0, 0, 0, /* memory rx_end, rx_start, end, start are autoconfiged. */
ETHERLINK1, 9, 0,0,0,0,0, /* base i/o address, irq, and flags. */
NULL, etherlink_init, 0, {NULL}, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, {0,}, {0,}, 0
};
#endif
#ifdef EI8390
extern void ethif_init(struct device *);
static struct device el3c503_dev = {
"eth_if",
0, 0, 0, 0, /* memory rx_end, rx_start, end, start are autoconfiged. */
0x300, 5, 0,0,0,0,0, /* base i/o address, irq, and flags. */
#ifdef ETHERLINK1
&el_dev,
#else
NULL,
#endif
ethif_init, 0, {NULL}, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, 0, 0, 0, {0,}, {0,}, 0
};
#endif
extern void wd8003_init(struct device *);
static struct device wd8003_dev =
{
"eth0",
0xd2000, /* recv memory end. */
0xd0600, /* recv memory start. */
0xd2000, /* memory end. */
0xd0000, /* memory start. */
0x280, /* base i/o address. */
5, /* irq */
0,0,0,0,0, /* flags */
#ifdef EI8390
&el3c503_dev, /* next device */
#elif defined(ETHERLINK1)
&el_dev, /* next device */
#else
NULL, /* next device */
#endif
wd8003_init,
/* wd8003_init should set up the rest. */
0, /* trans start. */
{NULL}, /* buffs */
NULL, /* backlog */
NULL, /* open */
NULL, /* stop */
NULL, /* hard_start_xmit */
NULL, /* hard_header */
NULL, /* add arp */
NULL, /* queue xmit */
NULL, /* rebuild header */
NULL, /* type_trans */
NULL, /* send_packet */
NULL, /* private */
0, /* type. */
0, /* hard_header_len */
0, /* mtu */
{0,}, /* broadcast address */
{0,}, /* device address */
0 /* addr len */
};
extern void loopback_init(struct device *dev);
static struct device loopback_dev =
{
"loopback",
-1, /* recv memory end. */
0x0, /* recv memory start. */
-1, /* memory end. */
0, /* memory start. */
0, /* base i/o address. */
0, /* irq */
0,0,1,0,0, /* flags */
&wd8003_dev, /* next device */
loopback_init,
/* loopback_init should set up the rest. */
0, /* trans start. */
{NULL}, /* buffs */
NULL, /* backlog */
NULL, /* open */
NULL, /* stop */
NULL, /* hard_start_xmit */
NULL, /* hard_header */
NULL, /* add arp */
NULL, /* queue xmit */
NULL, /* rebuild header */
NULL, /* type_trans */
NULL, /* send_packet */
NULL, /* private */
0, /* type. */
0, /* hard_header_len */
0, /* mtu */
{0,}, /* broadcast address */
{0,}, /* device address */
0 /* addr len */
};
struct device *dev_base = &loopback_dev;

13
net/tcpip/net-0.1.README Normal file
View File

@@ -0,0 +1,13 @@
README for net-src-0.1.tar.Z and net-bin-0.1.tar.Z
Included are ftp, ftpd, telnet, telnetd, inetd, named, nslookup and ping.
These are libc-4.1 versions of various net programs, both
source and binaries. They are from bsd-net2 with very minimal
changes. The telnet port is based on the one from Pete Chown.
Yes, this telnet/telnetd really works. I think. This is only
a pre-release. Let me know if there are any problems.
Rick Sladkey
jrs@world.std.com

98
net/tcpip/net-0.2.README Normal file
View File

@@ -0,0 +1,98 @@
This is a compliation of some net sources, mostly from bsd-net2. I
have made an effort to get the programs to compile with few or no
changes except for a new Makefile. This resulted in a bsd include
directory and a bsd library. Take a look at them to see what types of
things are required to get BSD sources to compile correctly without
changes. Some of the tricks are pretty ugly. Please don't laugh...
Everything should compile straight with the libc-4.2 libraries. Just
type "make" in this directory. You may have to do some surgery on
libbsd/libbsd.a to get things to compile with libc-4.1.
Notes
=====
bsd: The directory "bsd" contains include files that, for the most
part, just overload include files of the same name from /usr/include.
It provides some BSD things like "union wait" and others.
libbsd: The libbsd.a archive is a small library of some functions that
are not in our libc as well as some emulation support functions
referenced in the bsd header files. Notably, it includes a
half-decent transparent sgtty emulation package.
inetd: Works. Only pathname changes.
ftp: Works. No changes.
ftpd: I find that ls with ftpd doesn't work very often. It reports
"Transport endpoint already connected" 9 times out of 10. I think
this is a bug in the kernel which will be fixed in a subsequent
release. There was a memory allocation bug in the original source,
look for "#ifdef linux". Also, the shadow password stuff is not
compiled in as I haven't had a chance to mess with that.
telnet: Works but see the man page for info about the .telnetrc file
and other new options. This is a really nice telnet with rlogin
emulation and lots of other stuff not present in older telnets. The
original Linux port of telnet/telnetd was done by Pete Chown.
telnetd: Several people have reported that the 0.1 telnetd sometimes
disconnected before getting to the login prompt. The 0.2 version
omits the vhangup stuff which might have been causing the problem.
Also fixed is the problem with /etc/wtmp not being updated correctly
on logout. It was trying to use /var/adm/wtmp.
finger: Works. One minor change for POSIX timezone handling.
fingerd: Works, no changes.
ping: Works, no changes. Must be suid to root.
named: Works. A few changes for pathnames and net device
configuration stuff.
nslookup: Works, but it's fussier than older nslookups about named
being setup correctly. Note the -I option is needed for flex -- that
was a tough one to find. No changes.
named-xfer: Not tested.
rcp: Works. Must be suid to root.
rsh: Works. Must be suid to root.
rshd: Works.
rlogin: Works OK but needs more testing. This one depends pretty heavily
on the sgtty emulation in libbsd which is not complete yet. There is
an odd timing bug with select and termio settings. Look for "sleep(1)"
to see what I mean. Must be suid to root.
rlogind: Works with the URGENT stuff commented out. There was a nasty
bug with shared libraries because environ was redefined.
talk: Works. This is the new byte-order independent talk, not the old
talk that, e.g., native SunOS uses. The old one wouldn't work with
them anyway. Not the fault of Linux. Includes a one line patch for a
bug in our curses and another for a bug in the original source dealing
with select.
ntalkd: Works. No changes.
tftp: Works. No changes.
tftpd: Works. No changes.
Sample Entries for inetd.conf
=============================
telnet stream tcp nowait root /usr/etc/inet/telnetd telnetd
ntalk dgram udp wait root /usr/etc/inet/ntalkd ntalkd
ftp stream tcp nowait root /usr/etc/inet/ftpd ftpd -l
finger stream tcp nowait root /usr/etc/inet/fingerd finger
shell stream tcp nowait root /usr/etc/inet/rshd rshd
login stream tcp nowait root /usr/etc/inet/rlogind rlogind
tftp dgram udp wait root /usr/etc/inet/tftpd tftpd
Rick Sladkey
jrs@world.std.com

View File

@@ -0,0 +1,377 @@
/* 3c503.c: A shared-memory NS8390 ethernet driver for linux. */
/*
Written 1992,1993 by Donald Becker. This is alpha test code.
This is a extension to the Linux operating system, and is covered by
same Gnu Public License that covers that work.
This driver should work with the 3c503 and 3c503/16. It must be used
in shared memory mode.
The Author may be reached as becker@super.org or
C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
*/
static char *version = "3c503.c:v0.67 3/8/93 Donald Becker (becker@super.org)\n";
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <asm/io.h>
#include <asm/system.h>
#include "dev.h"
#include "8390.h"
#include "3c503reg.h"
extern void NS8390_init(struct device *dev, int startp);
extern int ei_debug;
extern struct sigaction ei_sigaction;
int el2autoprobe(int ioaddr, struct device *dev);
int el2probe(int ioaddr, struct device *dev);
static void el2_reset_8390(struct device *dev);
static void el2_init_card(struct device *dev);
static void el2_block_output(struct device *dev, int count,
const unsigned char *buf, const start_page);
static int el2_block_input(struct device *dev, int count, char *buf,
int ring_offset);
int
el2autoprobe(int ioaddr, struct device *dev)
{
int *addr, addrs[] = { 0xddffe, 0xd9ffe, 0xcdffe, 0xc9ffe, 0};
int ports[] = {0x300,0x310,0x330,0x350,0x250,0x280,0x2a0,0x2e0,0};
/* Non-autoprobe case first: */
if (ioaddr > 0)
return el2probe(ioaddr, dev);
/* We check for a memory-mapped 3c503 board by looking at the
port location bitmap at the end of the jumpered boot PROM space.
This works even if a PROM isn't there. */
for (addr = addrs; *addr; addr++) {
int i;
unsigned int base_bits = *(unsigned char *)*addr;
/* Find first set bit. */
for(i = 7; i >= 0; i--, base_bits >>= 1)
if (base_bits & 0x1)
break;
if (base_bits == 1 && el2probe(ports[i], dev))
return dev->base_addr;
}
#ifndef ignore_nonshared_memory
/* It's not memory mapped, bummer. Try all of the locations
that aren't obviously empty. */
{ int i;
for (i = 0; i < 8; i++)
if (inb_p(ports[i] + 0x403) == (0x80 >> i) /* Preliminary check */
&& el2probe(ports[i], dev))
return dev->base_addr;
}
#endif /* probe_nonshared_memory */
return 0;
}
/* Probe for the Etherlink II card at I/O port base IOADDR,
returning non-zero on sucess. If found, set the station
address and memory parameters in DEVICE. */
int
el2probe(int ioaddr, struct device *dev)
{
int i, iobase_reg, membase_reg, saved_406;
unsigned char *station_addr = dev->dev_addr;
/* We verify that it's a 3C503 board by checking the first three octets
of its ethernet address. */
printk("3c503 probe at %#3x:", ioaddr);
iobase_reg = inb(ioaddr+0x403);
membase_reg = inb(ioaddr+0x404);
/* Verify ASIC register that should be 0 or have a single bit set. */
if ( (iobase_reg & (iobase_reg - 1))
|| (membase_reg & (membase_reg - 1))) {
printk(" not found.\n");
return 0;
}
saved_406 = inb_p(ioaddr + 0x406);
outb_p(ECNTRL_RESET|ECNTRL_THIN, ioaddr + 0x406); /* Reset it... */
outb_p(ECNTRL_THIN, ioaddr + 0x406);
/* Map the station addr PROM into the lower I/O ports. */
outb(ECNTRL_SAPROM|ECNTRL_THIN, ioaddr + 0x406);
for (i = 0; i < ETHER_ADDR_LEN; i++) {
printk(" %2.2X", (station_addr[i] = inb(ioaddr + i)));
}
if ( station_addr[0] != 0x02
|| station_addr[1] != 0x60
|| station_addr[2] != 0x8c) {
printk(" 3C503 not found.\n");
/* Restore the register we frobbed. */
outb_p(saved_406, ioaddr + 0x406);
return 0;
}
/* Map the 8390 back into the window. */
outb(ECNTRL_THIN, ioaddr + 0x406);
dev->base_addr = ioaddr;
/* Probe for, turn on and clear the board's shared memory. */
if (ei_debug > 2) printk(" memory jumpers %2.2x ", membase_reg);
outb(EGACFR_NORM, ioaddr + 0x405); /* Enable RAM */
if ((membase_reg & 0xf0) == 0) {
dev->mem_start = 0;
} else {
dev->mem_start = ((membase_reg & 0xc0) ? 0xD8000 : 0xC8000) +
((membase_reg & 0xA0) ? 0x4000 : 0);
#define EL2_MEMSIZE (EL2SM_STOP_PG - EL2SM_START_PG)*256
#ifdef EL2MEMTEST
/* This has never found an error, but someone might care. */
{ /* Check the card's memory. */
int *mem_base = (int *)dev->mem_start;
int memtest_value = 0xbbadf00d;
mem_base[0] = 0xba5eba5e;
for (i = 1; i < EL2_MEMSIZE/sizeof(mem_base[0]); i++) {
mem_base[i] = memtest_value;
if (mem_base[0] != 0xba5eba5e
|| mem_base[i] != memtest_value) {
printk(" memory failure or memory address conflict.\n");
dev->mem_start = 0;
break;
}
memtest_value += 0x55555555;
mem_base[i] = 0;
}
}
#endif /* EL2MEMTEST */
/* Divide the on-board memory into a single maximum-sized transmit
(double-sized for ping-pong transmit) buffer at the base, and
use the rest as a receive ring. */
dev->mem_end = dev->rmem_end = dev->mem_start + EL2_MEMSIZE;
dev->rmem_start = TX_PAGES*256 + dev->mem_start;
}
if (ei_debug > 2)
printk("\n3c503: memory params start=%#5x rstart=%#5x end=%#5x rend=%#5x.\n",
dev->mem_start, dev->rmem_start, dev->mem_end, dev->rmem_end);
/* Finish setting the board's parameters. */
ei_status.name = "3C503";
ei_status.tx_start_page = EL2SM_START_PG;
ei_status.rx_start_page = EL2SM_START_PG + TX_PAGES;
ei_status.stop_page = EL2SM_STOP_PG;
ei_status.reset_8390 = &el2_reset_8390;
ei_status.block_input = &el2_block_input;
ei_status.block_output = &el2_block_output;
/* This should be probed for (or set via an ioctl()) at run-time someday. */
#if defined(EI8390_THICK) || defined(EL2_AUI)
ei_status.thin_bit = 0;
#else
ei_status.thin_bit = ECNTRL_THIN;
#endif
if (dev->irq < 2) {
int irqlist[] = {5, 9, 3, 4, 0};
int *irqp = irqlist;
do {
if (request_irq (dev->irq = *irqp, NULL) != -EBUSY) {
/* Twinkle the interrupt, and check if it's seen. */
autoirq_setup(0);
outb_p((0x04 << (dev->irq == 9 ? 2 : dev->irq)), E33G_IDCFR);
outb_p(0x00, E33G_IDCFR);
if (dev->irq == autoirq_report(0) /* It's a good IRQ line! */
&& request_irq (dev->irq, &ei_interrupt) == 0) {
printk(" got IRQ %d", dev->irq);
break;
} else
printk(" IRQ%d bad..", dev->irq);
}
} while (*++irqp);
if (*irqp == 0) {
printk(" unable to find an free IRQ line.\n");
return 0;
}
} else {
if (dev->irq == 2)
dev->irq = 9;
else if (dev->irq > 5 && dev->irq != 9) {
printk("\n3c503: configured interrupt number %d out of range.\n",
dev->irq);
return 0;
}
if (request_irq(dev->irq, &ei_interrupt)) {
printk (" unable to get IRQ%d.\n", dev->irq);
return 0;
}
}
dev->start = 0;
el2_init_card(dev);
if (dev->mem_start)
printk("\n%s: %s using IRQ %d with shared memory at %#6x-%#6x,\n",
dev->name, ei_status.name, dev->irq,
dev->mem_start, dev->mem_end-1);
else
printk("\n%s: %s using IRQ %d with programmed I/O.\n",
dev->name, ei_status.name, dev->irq);
if (ei_debug > 1)
printk(version);
return ioaddr;
}
/* This is called whenever we have a unrecoverable failure:
transmit timeout
Bad ring buffer packet header
*/
static void
el2_reset_8390(struct device *dev)
{
if (ei_debug > 1) {
printk("%s: Resetting the 3c503 board...", dev->name);
printk("%#x=%#02x %#x=%#02x %#x=%#02x...", E33G_IDCFR, inb(E33G_IDCFR),
E33G_CNTRL, inb(E33G_CNTRL), E33G_GACFR, inb(E33G_GACFR));
}
outb_p(ECNTRL_RESET|ECNTRL_THIN, E33G_CNTRL);
ei_status.txing = 0;
outb_p(ei_status.thin_bit, E33G_CNTRL);
el2_init_card(dev);
if (ei_debug > 1) printk("done\n");
}
/* Initialize the 3c503 GA registers after a reset. */
static void
el2_init_card(struct device *dev)
{
/* Unmap the station PROM and select the DIX or BNC connector. */
outb_p(ei_status.thin_bit, E33G_CNTRL);
/* Set ASIC copy of rx's first and last+1 buffer pages */
/* These must be the same as in the 8390. */
outb(ei_status.rx_start_page, E33G_STARTPG);
outb(ei_status.stop_page, E33G_STOPPG);
/* Point the vector pointer registers somewhere ?harmless?. */
outb(0xff, E33G_VP2); /* Point at the ROM restart location 0xffff0 */
outb(0xff, E33G_VP1);
outb(0x00, E33G_VP0);
/* Turn off all interrupts until we're opened. */
outb_p(0x00, dev->base_addr + EN0_IMR);
/* Enable IRQs iff started. */
outb(EGACFR_NORM, E33G_GACFR);
/* Set the interrupt line. */
outb_p((0x04 << (dev->irq == 9 ? 2 : dev->irq)), E33G_IDCFR);
outb_p(8, E33G_DRQCNT); /* Set burst size to 8 */
outb_p(0x20, E33G_DMAAH); /* Put a valid addr in the GA DMA */
outb_p(0x00, E33G_DMAAL);
return; /* We always succeed */
}
/* Either use the shared memory (if enabled on the board) or put the packet
out through the ASIC FIFO. The latter is probably much slower. */
static void
el2_block_output(struct device *dev, int count,
const unsigned char *buf, const start_page)
{
int i; /* Buffer index */
int boguscount = 0; /* timeout counter */
/* This should really be set with during an open(). */
outb(EGACFR_NORM, E33G_GACFR); /* Enable RAM and interrupts. */
if (dev->mem_start) { /* Shared memory transfer */
void *dest_addr = (void *)(dev->mem_start +
((start_page - ei_status.tx_start_page) << 8));
memcpy(dest_addr, buf, count);
if (ei_debug > 2 && memcmp(dest_addr, buf, count))
printk("%s: 3c503 send_packet() bad memory copy @ %#5x.\n",
dev->name, dest_addr);
else if (ei_debug > 4)
printk("%s: 3c503 send_packet() good memory copy @ %#5x.\n",
dev->name, dest_addr);
return;
}
/* No shared memory, put the packet out the slow way. */
/* Set up then start the internal memory transfer to Tx Start Page */
outb(0x00, E33G_DMAAL);
outb_p(start_page, E33G_DMAAH);
outb_p(ei_status.thin_bit | ECNTRL_OUTPUT | ECNTRL_START, E33G_CNTRL);
/* This is the byte copy loop: it should probably be tuned for
for speed once everything is working. I think it is possible
to output 8 bytes between each check of the status bit. */
for(i = 0; i < count; i++) {
if (i % 8 == 0)
while ((inb(E33G_STATUS) & ESTAT_DPRDY) == 0)
if (++boguscount > (i<<3) + 32) {
printk("%s: FIFO blocked in el2_block_output (at %d of %d, bc=%d).\n",
dev->name, i, count, boguscount);
return;
}
outb(buf[i], E33G_FIFOH);
}
outb(ei_status.thin_bit, E33G_CNTRL);
return;
}
/* Returns the new ring pointer. */
static int
el2_block_input(struct device *dev, int count, char *buf, int ring_offset)
{
int boguscount = 0;
int end_of_ring = dev->rmem_end;
unsigned int i;
/* Maybe enable shared memory just be to be safe... nahh.*/
if (dev->mem_start) { /* Use the shared memory. */
ring_offset -= (EL2SM_START_PG<<8);
if (dev->mem_start + ring_offset + count > end_of_ring) {
/* We must wrap the input move. */
int semi_count = end_of_ring - (dev->mem_start + ring_offset);
if (ei_debug > 4)
printk("%s: 3c503 block_input() @ %#5x+%x=%5x.\n",
dev->name, dev->mem_start, ring_offset,
(char *)dev->mem_start + ring_offset);
memcpy(buf, (char *)dev->mem_start + ring_offset, semi_count);
count -= semi_count;
memcpy(buf + semi_count, (char *)dev->rmem_start, count);
return dev->rmem_start + count;
}
if (ei_debug > 4)
printk("%s: 3c503 block_input() @ %#5x+%x=%5x.\n",
dev->name, dev->mem_start, ring_offset,
(char *)dev->mem_start + ring_offset);
memcpy(buf, (char *)dev->mem_start + ring_offset, count);
return ring_offset + count;
}
/* No shared memory, use programmed I/O. */
outb(ring_offset & 0xff, E33G_DMAAL);
outb_p((ring_offset >> 8) & 0xff, E33G_DMAAH);
outb_p(ei_status.thin_bit | ECNTRL_INPUT | ECNTRL_START, E33G_CNTRL);
/* This is the byte copy loop: it should probably be tuned for
for speed once everything is working. */
for(i = 0; i < count; i++) {
if (i % 8 == 0)
while ((inb(E33G_STATUS) & ESTAT_DPRDY) == 0)
if (++boguscount > (i<<3) + 32) {
printk("%s: FIFO blocked in el2_block_input() (at %d of %d, bc=%d).\n",
dev->name, i, count, boguscount);
boguscount = 0;
break;
}
buf[i] = inb_p(E33G_FIFOH);
}
outb(ei_status.thin_bit, E33G_CNTRL);
return 0;
}
/*
* Local variables:
* compile-command: "gcc -DKERNEL -Wall -O6 -fomit-frame-pointer -I/usr/src/linux/net/tcp -c 3c503.c"
* version-control: t
* kept-new-versions: 5
* End:
*/

View File

@@ -0,0 +1,59 @@
/* Definitions for the 3Com 3c503 Etherlink 2. */
/* This file is part of Donald Becker's 8390 drivers.
This file is distributed under the Linux GPL.
Some of these names and comments are from the Crynwr packet drivers. */
#define EL2H (dev->base_addr + 0x400)
#define EL2L (dev->base_addr)
/* Shared memory management parameters */
#define EL2SM_START_PG (0x20) /* First page of TX buffer */
#define EL2SM_STOP_PG (0x40) /* Last page +1 of RX ring */
/* 3Com 3c503 ASIC registers */
#define E33G_STARTPG (EL2H+0) /* Start page, must match EN0_STARTPG */
#define E33G_STOPPG (EL2H+1) /* Stop page, must match EN0_STOPPG */
#define E33G_DRQCNT (EL2H+2) /* DMA burst count */
#define E33G_IOBASE (EL2H+3) /* Read of I/O base jumpers. */
/* (non-useful, but it also appears at the end of EPROM space) */
#define E33G_ROMBASE (EL2H+4) /* Read of memory base jumpers. */
#define E33G_GACFR (EL2H+5) /* Config/setup bits for the ASIC GA */
#define E33G_CNTRL (EL2H+6) /* Board's main control register */
#define E33G_STATUS (EL2H+7) /* Status on completions. */
#define E33G_IDCFR (EL2H+8) /* Interrupt/DMA config register */
/* (Which IRQ to assert, DMA chan to use) */
#define E33G_DMAAH (EL2H+9) /* High byte of DMA address reg */
#define E33G_DMAAL (EL2H+10) /* Low byte of DMA address reg */
/* "Vector pointer" - if this address matches a read, the EPROM (rather than
shared RAM) is mapped into memory space. */
#define E33G_VP2 (EL2H+11)
#define E33G_VP1 (EL2H+12)
#define E33G_VP0 (EL2H+13)
#define E33G_FIFOH (EL2H+14) /* FIFO for programmed I/O moves */
#define E33G_FIFOL (EL2H+15) /* ... low byte of above. */
/* Bits in E33G_CNTRL register: */
#define ECNTRL_RESET (0x01) /* Software reset of the ASIC and 8390 */
#define ECNTRL_THIN (0x02) /* Onboard thin-net xcvr enable */
#define ECNTRL_SAPROM (0x04) /* Map the station address prom */
#define ECNTRL_DBLBFR (0x20) /* FIFO configuration bit */
#define ECNTRL_OUTPUT (0x40) /* PC-to-3C503 direction if 1 */
#define ECNTRL_INPUT (0x00) /* 3C503-to-PC direction if 0 */
#define ECNTRL_START (0x80) /* Start the DMA logic */
/* Bits in E33G_STATUS register: */
#define ESTAT_DPRDY (0x80) /* Data port (of FIFO) ready */
#define ESTAT_UFLW (0x40) /* Tried to read FIFO when it was empty */
#define ESTAT_OFLW (0x20) /* Tried to write FIFO when it was full */
#define ESTAT_DTC (0x10) /* Terminal Count from PC bus DMA logic */
#define ESTAT_DIP (0x08) /* DMA In Progress */
/* Bits in E33G_GACFR register: */
#define EGACFR_NORM (0x49) /* Enable 8K shared mem, no DMA TC int */
#define EGACFR_IRQOFF (0xc9) /* Above, and disable 8390 IRQ line */
/* End of 3C503 parameter definitions */

View File

@@ -0,0 +1,689 @@
/* 8390.c: A general NS8390 ethernet driver core for linux. */
/*
Written 1992,1993 by Donald Becker. This is alpha test code.
This is a extension to the Linux operating system, and is covered by
same Gnu Public License that covers that work.
This driver should work with many 8390-based ethernet adaptors.
The Author may be reached as becker@super.org or
C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
*/
static char *version =
"8390.c:v0.68 3/9/93 for 0.99.6 Donald Becker (becker@super.org)\n";
#include <linux/config.h>
#if !defined(EL2) && !defined(NE2000) && !defined(WD80x3) && !defined(HPLAN)
/* They don't know what they want -- give it all to them! */
#define EL2
#define NE2000
#define WD80x3
#define HPLAN
#endif
/*
Braindamage remaining:
Ethernet devices should use a chr_drv device interface, with ioctl()s to
configure the card, bring the interface up or down, allow access to
statistics, and maybe read() and write() access to raw packets.
This won't be done until after Linux 1.00.
This driver should support multiple, diverse boards simultaneousely.
This won't be done until after Linux 1.00.
Sources:
The National Semiconductor LAN Databook, and the 3Com 3c503 databook.
The NE* programming info came from the Crynwr packet driver, and figuring
out that the those boards are similar to the NatSemi evaluation board
described in AN-729. Thanks NS, no thanks to Novell/Eagle.
Cabletron provided only info I had already gotten from other sources -- hiss.
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/tty.h>
#include <linux/types.h>
#include <linux/ptrace.h>
#include <linux/string.h>
#include <asm/system.h>
#include <asm/segment.h>
#include <asm/io.h>
#include <errno.h>
#include <linux/fcntl.h>
#include <netinet/in.h>
#include <linux/interrupt.h>
#include "dev.h"
#include "eth.h"
#include "timer.h"
#include "ip.h"
#include "tcp.h"
#include "sock.h"
#include "arp.h"
#include "8390.h"
#define ei_reset_8390 (ei_local->reset_8390)
#define ei_block_output (ei_local->block_output)
#define ei_block_input (ei_local->block_input)
/* use 0 for production, 1 for verification, >2 for debug */
#ifdef EI_DEBUG
int ei_debug = EI_DEBUG;
#else
int ei_debug = 2;
#endif
struct device *irq2dev_map[16] = {0,0,0, /* zeroed...*/};
#ifdef PINGPONG
static int lasttx = 0;
#endif
/* Max number of packets received at one Intr. */
/*static int high_water_mark = 0;*/
/* Index to functions. */
/* Put in the device structure. */
static int ei_open(struct device *dev);
/* Dispatch from interrupts. */
void ei_interrupt(int reg_ptr);
static void ei_tx_intr(struct device *dev);
static void ei_receive(struct device *dev);
static void ei_rx_overrun(struct device *dev);
int ethdev_init(struct device *dev);
/* Routines generic to NS8390-based boards. */
void NS8390_init(struct device *dev, int startp);
static void NS8390_trigger_send(struct device *dev, unsigned int length,
int start_page);
extern int el2autoprobe(int ioaddr, struct device *dev);
extern int el2probe(int ioaddr, struct device *dev);
extern int neprobe(int ioaddr, struct device *dev);
extern int wdprobe(int ioaddr, struct device *dev);
extern int hpprobe(int ioaddr, struct device *dev);
struct sigaction ei_sigaction = { ei_interrupt, 0, 0, NULL, };
/* Open/initialize the board. This routine goes all-out, setting everything
up anew at each open, even though many of these registers should only
need to be set once at boot.
*/
static int
ei_open(struct device *dev)
{
struct ei_device *ei_local = dev->private;
if ( ! ei_local) {
printk("%s: Opening a non-existent physical device\n", dev->name);
return 1; /* ENXIO would be more accurate. */
}
irq2dev_map[dev->irq] = dev;
NS8390_init(dev, 1);
ei_local->tx1 = ei_local->tx2 = 0;
/* The old local flags... */
ei_local->txing = 0;
/* ... are now global. */
dev->tbusy = 0;
dev->interrupt = 0;
dev->start = 1;
return 0;
}
static int
ei_start_xmit(struct sk_buff *skb, struct device *dev)
{
int e8390_base = dev->base_addr;
struct ei_device *ei_local = dev->private;
if (dev->tbusy) { /* Do timeouts, just like the 8003 driver. */
int txsr = inb(e8390_base+EN0_TSR), isr;
int tickssofar = jiffies - dev->trans_start;
if (tickssofar < 5 || (tickssofar < 15 && ! (txsr & ENTSR_PTX))) {
return 1;
}
isr = inb(e8390_base+EN0_ISR);
printk("%s: transmit timed out, TX status %#2x, ISR %#2x.\n",
dev->name, txsr, isr);
/* It's possible to check for an IRQ conflict here.
I may have to do that someday. */
if (isr)
printk("%s: Possible IRQ conflict on IRQ%d?", dev->name, dev->irq);
else
printk("%s: Possible network cable problem?\n", dev->name);
/* It futile, but try to restart it anyway. */
ei_reset_8390(dev);
NS8390_init(dev, 1);
printk("\n");
}
/* This is new: it means some higher layer thinks we've missed an
tx-done interrupt. Caution: dev_tint() handles the cli()/sti()
itself. */
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;
}
#ifdef PINGPONG
{
int length = skb->len;
int output_page;
int send_length = ETHER_MIN_LEN < length ? length : ETHER_MIN_LEN;
if (length <= 0)
return 0;
/* Turn off interrupts so that we can put the packet out safely. */
outb(0x00, e8390_base + EN0_IMR);
if (ei_local->tx1 == 0) {
output_page = ei_local->tx_start_page;
ei_local->tx1 = send_length;
if (ei_debug && ei_local->tx2 > 0)
printk("%s: idle transmitter tx2=%d, lasttx=%d, txing=%d.\n",
dev->name, ei_local->tx2, lasttx, ei_local->txing);
} else if (ei_local->tx2 == 0) {
output_page = ei_local->tx_start_page + 6;
ei_local->tx2 = send_length;
if (ei_debug && ei_local->tx1 > 0)
printk("%s: idle transmitter, tx1=%d, lasttx=%d, txing=%d.\n",
dev->name, ei_local->tx1, lasttx, ei_local->txing);
} else {
/* We can get to here if we get an rx interrupt and queued
a tx packet just before masking 8390 irqs above. */
if (ei_debug > 2)
printk("%s: No packet buffer space for ping-pong use.\n",
dev->name);
outb_p(ENISR_ALL, e8390_base + EN0_IMR);
return 1;
}
dev->trans_start = jiffies;
ei_block_output(dev, length, (void*)(skb+1), output_page);
if (! ei_local->txing) {
NS8390_trigger_send(dev, send_length, output_page);
if (output_page == ei_local->tx_start_page)
ei_local->tx1 = -1, lasttx = -1;
else
ei_local->tx2 = -1, lasttx = -2;
ei_local->txing = 1;
} else
ei_local->txqueue++;
if (ei_local->tx1 && ei_local->tx2)
dev->tbusy = 1;
/* Turn 8390 interrupts back on. */
outb_p(ENISR_ALL, e8390_base + EN0_IMR);
}
#else
{
int length = skb->len;
int send_length = ETHER_MIN_LEN < length ? length : ETHER_MIN_LEN;
if (length <= 0)
return 0;
dev->trans_start = jiffies;
/* Turn off interrupts so that we can put the packet out safely. */
outb(0x00, e8390_base + EN0_IMR);
ei_block_output(dev, length, (void*)(skb+1), ei_local->tx_start_page);
NS8390_trigger_send(dev, send_length, ei_local->tx_start_page);
dev->tbusy = 1;
/* Turn 8390 interrupts back on. */
outb_p(ENISR_ALL, e8390_base + EN0_IMR);
}
#endif /* PINGPONG */
if (skb->free)
kfree_skb (skb, FREE_WRITE);
return 0;
}
/* The typical workload of the driver:
Handle the ether interface interrupts. */
void
ei_interrupt(int reg_ptr)
{
int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2);
struct device *dev = irq2dev_map[irq];
int e8390_base;
int interrupts, boguscount = 0;
if (dev == NULL) {
printk ("net_interrupt(): irq %d for unknown device.\n", irq);
return;
}
dev->interrupt = 1;
sti(); /* Allow other interrupts. */
e8390_base = dev->base_addr;
/* Change to page 0 and read the intr status reg. */
outb_p(E8390_NODMA+E8390_PAGE0, e8390_base + E8390_CMD);
if (ei_debug > 3)
printk("%s: interrupt(isr=%#2.2x).\n", dev->name,
inb_p(e8390_base + EN0_ISR));
/* !!Assumption!! -- we stay in page 0. Don't break this. */
while ((interrupts = inb_p(e8390_base + EN0_ISR)) != 0
&& ++boguscount < 20) {
if (interrupts & ENISR_RDC) {
/* Ack meaningless DMA complete. */
outb_p(ENISR_RDC, e8390_base + EN0_ISR);
}
if (interrupts & ENISR_OVER) {
ei_rx_overrun(dev);
} else if (interrupts & (ENISR_RX+ENISR_RX_ERR)) {
/* Got a good (?) packet. */
ei_receive(dev);
}
/* Push the next to-transmit packet through. */
if (interrupts & ENISR_TX) {
ei_tx_intr(dev);
} else if (interrupts & ENISR_COUNTERS) {
struct ei_device *ei_local = dev->private;
ei_local->soft_rx_errors += inb_p(e8390_base + EN0_COUNTER0);
ei_local->soft_rx_errors += inb_p(e8390_base + EN0_COUNTER1);
ei_local->missed_packets += inb_p(e8390_base + EN0_COUNTER2);
outb_p(ENISR_COUNTERS, e8390_base + EN0_ISR); /* Ack intr. */
}
/* Ignore the transmit errs and reset intr for now. */
if (interrupts & ENISR_TX_ERR) {
outb_p(ENISR_TX_ERR, e8390_base + EN0_ISR); /* Ack intr. */
}
outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base + E8390_CMD);
}
if (interrupts && ei_debug) {
printk("%s: unknown interrupt %#2x\n", dev->name, interrupts);
outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base + E8390_CMD);
outb_p(0xff, e8390_base + EN0_ISR); /* Ack. all intrs. */
}
dev->interrupt = 0;
return;
}
/* We have finished a transmit: check for errors and then trigger the next
packet to be sent. */
static void
ei_tx_intr(struct device *dev)
{
int e8390_base = dev->base_addr;
int status = inb(e8390_base + EN0_TSR);
struct ei_device *ei_local = dev->private;
outb_p(ENISR_TX, e8390_base + EN0_ISR); /* Ack intr. */
if ((status & ENTSR_PTX) == 0)
ei_local->tx_errors++;
else
ei_local->tx_packets++;
#ifdef PINGPONG
ei_local->txqueue--;
if (ei_local->tx1 < 0) {
if (lasttx != 1 && lasttx != -1)
printk("%s: bogus last_tx_buffer %d, tx1=%d.\n",
ei_local->name, lasttx, ei_local->tx1);
ei_local->tx1 = 0;
dev->tbusy = 0;
if (ei_local->tx2 > 0) {
NS8390_trigger_send(dev, ei_local->tx2, ei_local->tx_start_page + 6);
ei_local->txing = 1;
ei_local->tx2 = -1,
lasttx = 2;
} else
lasttx = 20, ei_local->txing = 0;
} else if (ei_local->tx2 < 0) {
if (lasttx != 2 && lasttx != -2)
printk("%s: bogus last_tx_buffer %d, tx2=%d.\n",
ei_local->name, lasttx, ei_local->tx2);
ei_local->tx2 = 0;
dev->tbusy = 0;
if (ei_local->tx1 > 0) {
NS8390_trigger_send(dev, ei_local->tx1, ei_local->tx_start_page);
ei_local->txing = 1;
ei_local->tx1 = -1;
lasttx = 1;
} else
lasttx = 10, ei_local->txing = 0;
} else
printk("%s: unexpected TX-done interrupt, lasttx=%d.\n",
dev->name, lasttx);
#else
ei_local->txing = 0;
dev->tbusy = 0;
#endif
mark_bh (INET_BH);
}
/* We have a good packet(s), get it/them out of the buffers. */
static void
ei_receive(struct device *dev)
{
int e8390_base = dev->base_addr;
struct ei_device *ei_local = dev->private;
int rxing_page, this_frame, next_frame, current_offset;
int boguscount = 0;
struct e8390_pkt_hdr rx_frame;
int num_rx_pages = ei_local->stop_page-ei_local->rx_start_page;
while (++boguscount < 10) {
int size;
/* Get the rx page (incoming packet pointer). */
outb_p(E8390_NODMA+E8390_PAGE1, e8390_base + E8390_CMD);
rxing_page = inb_p(e8390_base + EN1_CURPAG);
outb_p(E8390_NODMA+E8390_PAGE0, e8390_base + E8390_CMD);
/* Remove one frame from the ring. Boundary is alway a page behind. */
this_frame = inb_p(e8390_base + EN0_BOUNDARY) + 1;
if (this_frame >= ei_local->stop_page)
this_frame = ei_local->rx_start_page;
/* Someday we'll omit the previous step, iff we never get this message.*/
if (ei_debug > 0 && this_frame != ei_local->current_page)
printk("%s: mismatched read page pointers %2x vs %2x.\n",
dev->name, this_frame, ei_local->current_page);
if (this_frame == rxing_page) /* Read all the frames? */
break; /* Done for now */
current_offset = this_frame << 8;
ei_block_input(dev, sizeof(rx_frame), (void *)&rx_frame,
current_offset);
size = rx_frame.count - sizeof(rx_frame);
next_frame = this_frame + 1 + ((size+4)>>8);
/* Check for bogosity warned by 3c503 book: the status byte is never
written. This happened a lot during testing! This code should be
cleaned up someday, and the printk()s should be PRINTK()s. */
if ( rx_frame.next != next_frame
&& rx_frame.next != next_frame + 1
&& rx_frame.next != next_frame - num_rx_pages
&& rx_frame.next != next_frame + 1 - num_rx_pages) {
#ifndef EI_DEBUG
ei_local->current_page = rxing_page;
outb(ei_local->current_page-1, e8390_base+EN0_BOUNDARY);
continue;
#else
static int last_rx_bogosity = -1;
printk("%s: bogus packet header, status=%#2x nxpg=%#2x sz=%#x (at %#4x)\n",
dev->name, rx_frame.status, rx_frame.next, rx_frame.count,
current_offset);
if (rx_packets != last_rx_bogosity) {
/* Maybe we can avoid resetting the chip... empty the packet ring. */
ei_local->current_page = rxing_page;
printk("%s: setting next frame to %#2x (nxt=%#2x, rx_frm.nx=%#2x rx_frm.stat=%#2x).\n",
dev->name, ei_local->current_page, next_frame,
rx_frame.next, rx_frame.status);
last_rx_bogosity = rx_packets;
outb(ei_local->current_page-1, e8390_base+EN0_BOUNDARY);
continue;
} else {
/* Oh no Mr Bill! Last ditch error recovery. */
printk("%s: recovery failed, resetting at packet #%d..",
dev->name, rx_packets);
sti();
ei_reset_8390(dev);
NS8390_init(dev, 1);
printk("restarting.\n");
return;
}
#endif /* EI8390_NOCHECK */
}
if ((size < 32 || size > 1535) && ei_debug)
printk("%s: bogus packet size, status=%#2x nxpg=%#2x size=%#x\n",
dev->name, rx_frame.status, rx_frame.next, rx_frame.count);
if ((rx_frame.status & 0x0F) == ENRSR_RXOK) {
int sksize = sizeof(struct sk_buff) + size;
struct sk_buff *skb;
skb = kmalloc(sksize, GFP_ATOMIC);
if (skb != NULL) {
skb->lock = 0;
skb->mem_len = sksize;
skb->mem_addr = skb;
/* 'skb+1' points to the start of sk_buff data area. */
ei_block_input(dev, size, (void *)(skb+1),
current_offset + sizeof(rx_frame));
if (dev_rint((void *)skb, size, IN_SKBUFF, dev)) {
printk("%s: receive buffers full.\n", dev->name);
break;
}
} else if (ei_debug) {
printk("%s: Couldn't allocate a sk_buff of size %d.\n",
dev->name, sksize);
break;
}
ei_local->rx_packets++;
} else {
if (ei_debug)
printk("%s: bogus packet, status=%#2x nxpg=%#2x size=%d\n",
dev->name, rx_frame.status, rx_frame.next, rx_frame.count);
ei_local->soft_rx_err_bits |= rx_frame.status,
ei_local->soft_rx_errors++;
}
next_frame = rx_frame.next;
/* This should never happen, it's here for debugging. */
if (next_frame >= ei_local->stop_page) {
printk("%s: next frame inconsistency, %#2x..", dev->name, next_frame);
next_frame = ei_local->rx_start_page;
}
ei_local->current_page += 1 + ((size+4)>>8);
ei_local->current_page = next_frame;
outb(next_frame-1, e8390_base+EN0_BOUNDARY);
}
/* 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. */
/* Bug alert! Reset ENISR_OVER to avoid spurious overruns! */
outb_p(ENISR_RX+ENISR_RX_ERR+ENISR_OVER, e8390_base+EN0_ISR);
return;
}
/* We have a receiver overrun: we have to kick the 8390 to get it started
again.*/
static void
ei_rx_overrun(struct device *dev)
{
int e8390_base = dev->base_addr;
int reset_start_time = jiffies;
struct ei_device *ei_local = dev->private;
/* We should already be stopped and in page0. Remove after testing. */
outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD);
if (ei_debug)
printk("%s: Receiver overrun.\n", dev->name);
ei_local->rx_overruns++;
/* The we.c driver does dummy = inb_p( RBCR[01] ); at this point.
It might mean something -- magic to speed up a reset? A 8390 bug?*/
/* Wait for reset in case the NIC is doing a tx or rx. This could take up to
1.5msec, but we have no way of timing something in that range. The 'jiffies'
are just a sanity check. */
while ((inb_p(e8390_base+EN0_ISR) & ENISR_RESET) == 0)
if (jiffies - reset_start_time > 1) {
printk("%s: reset did not complete at ei_rx_overrun.\n",
dev->name);
NS8390_init(dev, 1);
return;
};
{
int old_rx_packets = ei_local->rx_packets;
/* Remove packets right away. */
ei_receive(dev);
ei_local->rx_overrun_packets +=
(ei_local->rx_packets - old_rx_packets);
}
outb_p(0xff, e8390_base+EN0_ISR);
/* Generic 8390 insns to start up again, same as in open_8390(). */
outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START, e8390_base + E8390_CMD);
outb_p(E8390_TXCONFIG, e8390_base + EN0_TXCR); /* xmit on. */
}
int
ethif_init(struct device *dev)
{
if (ei_debug > 1)
printk(version);
/* The open call may be overridden by the card-specific code. */
dev->open = &ei_open;
/* Make up a ei_local structure. */
dev->private = kmalloc(sizeof(struct ei_device), GFP_KERNEL);
memset(dev->private, 0, sizeof(struct ei_device));
if (1
#ifdef WD80x3
&& ! wdprobe(dev->base_addr, dev)
#endif
#ifdef EL2
&& ! el2autoprobe(dev->base_addr, dev)
#endif
#ifdef NE2000
&& ! neprobe(dev->base_addr, dev)
#endif
#ifdef HPLAN
&& ! hpprobe(dev->base_addr, dev)
#endif
&& 1 ) {
printk("No ethernet device found.\n");
kfree(dev->private);
dev->private = NULL;
return 1; /* ENODEV or EAGAIN would be more accurate. */
}
return ethdev_init(dev);
}
/* Initialize the rest of the device structure. */
int
ethdev_init(struct device *dev)
{
int i;
for (i = 0; i < DEV_NUMBUFFS; i++)
dev->buffs[i] = NULL;
dev->hard_header = eth_hard_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;
if (dev->private == NULL) {
dev->private = kmalloc(sizeof(struct ei_device), GFP_KERNEL);
memset(dev->private, 0, sizeof(struct ei_device));
}
dev->send_packet = 0;
dev->hard_start_xmit = &ei_start_xmit;
dev->type = ETHER_TYPE;
dev->hard_header_len = sizeof (struct enet_header);
dev->mtu = 1500; /* eth_mtu */
dev->addr_len = ETHER_ADDR_LEN;
for (i = 0; i < dev->addr_len; i++) {
dev->broadcast[i]=0xff;
}
return 0;
}
/* This page of functions should be 8390 generic */
/* Follow National Semi's recommendations for initializing the "NIC". */
void NS8390_init(struct device *dev, int startp)
{
int e8390_base = dev->base_addr;
struct ei_device *ei_local = dev->private;
int i;
int endcfg = ei_local->word16 ? (0x48 | ENDCFG_WTS) : 0x48;
/* Follow National Semi's recommendations for initing the DP83902. */
outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base); /* 0x21 */
outb_p(endcfg, e8390_base + EN0_DCFG); /* 0x48 or 0x49 */
/* Clear the remote byte count registers. */
outb_p(0x00, e8390_base + EN0_RCNTLO);
outb_p(0x00, e8390_base + EN0_RCNTHI);
/* Set to monitor and loopback mode -- this is vital!. */
outb_p(E8390_RXOFF, e8390_base + EN0_RXCR); /* 0x20 */
outb_p(E8390_TXOFF, e8390_base + EN0_TXCR); /* 0x02 */
/* Set the transmit page and receive ring. */
outb_p(ei_local->tx_start_page, e8390_base + EN0_TPSR);
ei_local->tx1 = ei_local->tx2 = 0;
outb_p(ei_local->rx_start_page, e8390_base + EN0_STARTPG);
outb_p(ei_local->stop_page-1, e8390_base + EN0_BOUNDARY); /* 3c503 says 0x3f,NS0x26*/
ei_local->current_page = ei_local->rx_start_page; /* assert boundary+1 */
outb_p(ei_local->stop_page, e8390_base + EN0_STOPPG);
/* Clear the pending interrupts and mask. */
outb_p(0xFF, e8390_base + EN0_ISR);
outb_p(0x00, e8390_base + EN0_IMR);
/* Copy the station address into the DS8390 registers,
and set the multicast hash bitmap to receive all multicasts. */
cli();
outb_p(E8390_NODMA + E8390_PAGE1 + E8390_STOP, e8390_base); /* 0x61 */
for(i = 0; i < 6; i++) {
outb_p(dev->dev_addr[i], e8390_base + EN1_PHYS + i);
}
for(i = 0; i < 8; i++)
outb_p(0xff, e8390_base + EN1_MULT + i);
outb_p(ei_local->rx_start_page, e8390_base + EN1_CURPAG);
outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base);
sti();
if (startp) {
outb_p(0xff, e8390_base + EN0_ISR);
outb_p(ENISR_ALL, e8390_base + EN0_IMR);
outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base);
outb_p(E8390_TXCONFIG, e8390_base + EN0_TXCR); /* xmit on. */
/* 3c503 TechMan says rxconfig only after the NIC is started. */
outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR); /* rx on, */
}
return;
}
/* Trigger a transmit start, assuming the length is valid. */
static void NS8390_trigger_send(struct device *dev, unsigned int length,
int start_page)
{
int e8390_base = dev->base_addr;
ei_status.txing = 1;
outb_p(E8390_NODMA+E8390_PAGE0, e8390_base);
if (inb_p(e8390_base) & E8390_TRANS) {
printk("%s: trigger_send() called with the transmitter busy.\n",
dev->name);
return;
}
outb_p(length & 0xff, e8390_base + EN0_TCNTLO);
outb_p(length >> 8, e8390_base + EN0_TCNTHI);
outb_p(start_page, e8390_base + EN0_TPSR);
outb_p(E8390_NODMA+E8390_TRANS+E8390_START, e8390_base);
return;
}
/*
* Local variables:
* compile-command: "gcc -DKERNEL -Wall -O6 -fomit-frame-pointer -DPINGPONG -I/usr/src/linux/net/tcp -c 8390.c"
* version-control: t
* kept-new-versions: 5
* End:
*/

View File

@@ -0,0 +1,148 @@
/* Generic NS8390 register definitions. */
/* This file is part of Donald Becker's 8390 drivers.
This file is distributed under the Linux GPL.
Some of these names and comments are from the Crynwr packet drivers. */
#ifndef e8390_h
#define e8390_h
#define PINGPONG
#ifdef PINGPONG
#define TX_PAGES 12
#else
#define TX_PAGES 6
#endif
#define ETHER_ADDR_LEN 6
/* From 8390.c */
void ei_interrupt(int reg_ptr);
/* From auto_irq.c */
extern void autoirq_setup(int waittime);
extern int autoirq_report(int waittime);
/* Most of these entries should be in 'struct device' (or most of the
things in there should be here!) */
/* You have one of these per-board */
struct ei_device {
char *name;
int open:1;
int word16:1; /* We have the 16-bit (vs 8-bit) version of the card. */
int txing:1; /* Transmit Active */
void (*reset_8390)(struct device *);
void (*block_output)(struct device *, int, const unsigned char *, int);
int (*block_input)(struct device *, int, char *, int);
unsigned char tx_start_page, rx_start_page, stop_page;
unsigned char current_page; /* Read pointer in buffer */
unsigned char thin_bit; /* Value to write to the 3c503 E33G_CNTRL */
unsigned char txqueue; /* Tx Packet buffer queue length. */
unsigned char in_interrupt;
short tx1, tx2; /* Packet lengths for ping-pong tx. */
/* The statistics: */
int tx_packets;
int tx_errors;
int rx_packets;
int soft_rx_errors;
int soft_rx_err_bits;
int missed_packets;
int rx_overruns;
int rx_overrun_packets;
};
#define ei_status (*(struct ei_device *)(dev->private))
/* Some generic ethernet register configurations. */
#define E8390_TX_IRQ_MASK 0xa /* For register EN0_ISR */
#define E8390_RX_IRQ_MASK 0x5
#define E8390_RXCONFIG 0x4 /* EN0_RXCR: broadcasts, no multicast,errors */
#define E8390_RXOFF 0x20 /* EN0_RXCR: Accept no packets */
#define E8390_TXCONFIG 0x00 /* EN0_TXCR: Normal transmit mode */
#define E8390_TXOFF 0x02 /* EN0_TXCR: Transmitter off */
/* Register accessed at EN_CMD, the 8390 base addr. */
#define E8390_STOP 0x01 /* Stop and reset the chip */
#define E8390_START 0x02 /* Start the chip, clear reset */
#define E8390_TRANS 0x04 /* Transmit a frame */
#define E8390_RREAD 0x08 /* Remote read */
#define E8390_RWRITE 0x10 /* Remote write */
#define E8390_NODMA 0x20 /* Remote DMA */
#define E8390_PAGE0 0x00 /* Select page chip registers */
#define E8390_PAGE1 0x40 /* using the two high-order bits */
#define E8390_PAGE2 0x80 /* Page 3 is invalid. */
#define E8390_CMD 0x00 /* The command register (for all pages) */
/* Page 0 register offsets. */
#define EN0_CLDALO 0x01 /* Low byte of current local dma addr RD */
#define EN0_STARTPG 0x01 /* Starting page of ring bfr WR */
#define EN0_CLDAHI 0x02 /* High byte of current local dma addr RD */
#define EN0_STOPPG 0x02 /* Ending page +1 of ring bfr WR */
#define EN0_BOUNDARY 0x03 /* Boundary page of ring bfr RD WR */
#define EN0_TSR 0x04 /* Transmit status reg RD */
#define EN0_TPSR 0x04 /* Transmit starting page WR */
#define EN0_NCR 0x05 /* Number of collision reg RD */
#define EN0_TCNTLO 0x05 /* Low byte of tx byte count WR */
#define EN0_FIFO 0x06 /* FIFO RD */
#define EN0_TCNTHI 0x06 /* High byte of tx byte count WR */
#define EN0_ISR 0x07 /* Interrupt status reg RD WR */
#define EN0_CRDALO 0x08 /* low byte of current remote dma address RD */
#define EN0_RSARLO 0x08 /* Remote start address reg 0 */
#define EN0_CRDAHI 0x09 /* high byte, current remote dma address RD */
#define EN0_RSARHI 0x09 /* Remote start address reg 1 */
#define EN0_RCNTLO 0x0a /* Remote byte count reg WR */
#define EN0_RCNTHI 0x0b /* Remote byte count reg WR */
#define EN0_RSR 0x0c /* rx status reg RD */
#define EN0_RXCR 0x0c /* RX configuration reg WR */
#define EN0_TXCR 0x0d /* TX configuration reg WR */
#define EN0_COUNTER0 0x0d /* Rcv alignment error counter RD */
#define EN0_DCFG 0x0e /* Data configuration reg WR */
#define EN0_COUNTER1 0x0e /* Rcv CRC error counter RD */
#define EN0_IMR 0x0f /* Interrupt mask reg WR */
#define EN0_COUNTER2 0x0f /* Rcv missed frame error counter RD */
/* Bits in EN0_ISR - Interrupt status register */
#define ENISR_RX 0x01 /* Receiver, no error */
#define ENISR_TX 0x02 /* Transmitter, no error */
#define ENISR_RX_ERR 0x04 /* Receiver, with error */
#define ENISR_TX_ERR 0x08 /* Transmitter, with error */
#define ENISR_OVER 0x10 /* Receiver overwrote the ring */
#define ENISR_COUNTERS 0x20 /* Counters need emptying */
#define ENISR_RDC 0x40 /* remote dma complete */
#define ENISR_RESET 0x80 /* Reset completed */
#define ENISR_ALL 0x3f /* Interrupts we will enable */
/* Bits in EN0_DCFG - Data config register */
#define ENDCFG_WTS 0x01 /* word transfer mode selection */
/* Page 1 register offsets. */
#define EN1_PHYS 0x01 /* This board's physical enet addr RD WR */
#define EN1_CURPAG 0x07 /* Current memory page RD WR */
#define EN1_MULT 0x08 /* Multicast filter mask array (8 bytes) RD WR */
/* Bits in received packet status byte and EN0_RSR*/
#define ENRSR_RXOK 0x01 /* Received a good packet */
#define ENRSR_CRC 0x02 /* CRC error */
#define ENRSR_FAE 0x04 /* frame alignment error */
#define ENRSR_FO 0x08 /* FIFO overrun */
#define ENRSR_MPA 0x10 /* missed pkt */
#define ENRSR_PHY 0x20 /* physical/multicase address */
#define ENRSR_DIS 0x40 /* receiver disable. set in monitor mode */
#define ENRSR_DEF 0x80 /* deferring */
/* Transmitted packet status, EN0_TSR. */
#define ENTSR_PTX 0x01 /* Packet transmitted without error */
/* The other bits in the TX status register mean:
0x02 The transmit wasn't deferred.
0x04 The transmit collided at least once.
0x08 The transmit collided 16 times, and was deferred.
0x10 The carrier sense was lost (from the ethernet transceiver)
0x20 A "FIFO underrun" (internal error) occured during transmit.
0x40 The collision detect "heartbeat" signal was lost.
0x80 There was an out-of-window collision.
*/
/* The per-packet-header format. */
struct e8390_pkt_hdr {
unsigned char status; /* status */
unsigned char next; /* pointer to next packet. */
unsigned short count; /* header + packet lenght in bytes */
};
#endif /* e8390_h */

View File

@@ -0,0 +1,44 @@
Subject: Enhanced Ethercard driver available for alpha test.
My "8390" Linux ethercard drivers are now available from usra.edu and
super.org in ~ftp/pub/linux/ethercards/*. They'll be at tsx-11 and
sunsite RSN.
These drivers support all common 8390-based ethernet boards. Currently
"common" is defined as:
3Com Products:
* 3Com 3c503 Board loaned by Chance Reschke, USRA.edu (thanks!)
3Com 3c503/16 and excellent documentation provided by 3Com.
Clones-n-things
NE1000 Novell and Eagle are useless for documentation,
* NE2000 but copied the designs directly from NatSemi;->.
* Alta Combo(NE2000 clone)
Aritsoft LANtastic AE-2 (NE2000 clone w/ extra memory)
D-Link Ethernet II
Cabletron products:
E1010 No ID PROM and sketchy info from Ctron means you'll
E1010-x have to compile-in information about your board.
E2010
E2010-x
WD/SMC products
WD8003
* WD8013 Board loaned by Russ Nelson, Crynwr Software. Thanks!
* I've seen it work myself!
There is support for the following boards, but since I've only been
able to borrow a thinnet of an HP ethercard I haven't been able to test it:
HP LAN adaptors
** HP27245
** HP27247
** HP27250
Thanks are due to the dozens of alpha testers, and special thanks to Chance Reschke <@usra.edu> and Russ Nelson <@crynwr.com> for loaning me ethercards.

View File

@@ -0,0 +1,33 @@
# This file must be named 'GNUmakefile'. When it has that name it
# loaded in preference to the regular 'Makefile' (which it include
# right here) so this has the effect of appending lines to the Makefile.
include Makefile
# Add a few files to tcpip.a.
newobjs = 8390.o 3c503.o ne.o wd.o hp.o auto_irq.o
OBJS := $(OBJS) $(newobjs)
tcpip.a: $(newobjs)
# Set the address and IRQ here. The ne.c and 3c503 driver will autoprobe
# if you set the address or IRQ to zero, so we do that by default.
#
# Add -DEI_NAME="eth0" if you want to be exactly compatible with the default
# driver. This will only work if you don't use the distributed 'we' driver!
#
ether_options := -DEI_NAME=\"eth0\" -DEI8390=0 -DEI8390_IRQ=0
Space.o: Space.c GNUmakefile
$(CC) $(CPPFLAGS) $(CFLAGS) $(ether_options) -c Space.c -o $@
# Change this to define the set of ethercards your kernel will support.
8390.o: 8390.c GNUmakefile
$(CC) $(CPPFLAGS) $(CFLAGS) -DNE2000 -DWD80x3 -DHPLAN -DEL2 -c 8390.c -o $@
# Change this to -DEL2_AUI if you use the AUI port.
3c503.o: 3c503.c 3c503reg.h GNUmakefile
$(CC) $(CPPFLAGS) $(CFLAGS) -UEL2_AUI -c 3c503.c -o $@
# Change this to -DSHMEM=0xd0000 and -DFORCE_8BIT if you have an old
# (non-EEPROM) wd8003.
wd.o: wd.c GNUmakefile
$(CC) $(CPPFLAGS) $(CFLAGS) -UWD_SHMEM -UFORCE_8BIT -c wd.c -o $@

View File

@@ -0,0 +1,14 @@
This is a new version of the ethercard drivers.
The new features are:
PING-PONG transmit! This can almost double the transmit rate in some
cases. 1MB/sec is now possible!!!
The 'ne' driver autoselects between the NE1000 and NE2000 modes.
There is a less-intrusive 3c503 probe.
The 3c503 can now be used in non-shared-memory mode.
The HP-LAN non-autoIRQ mode should now work.
The WD driver should now work with some older WD8003 cards, but this
is untested.

View File

@@ -0,0 +1,110 @@
/* auto_irq.c: Auto-configure IRQ lines for linux. */
/*
Written 1993 by Donald Becker. This is alpha test code.
The Author may be reached as becker@super.org or
C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
This code is a general-purpose IRQ line detector for devices with
jumpered IRQ lines. If you can make the device raise an IRQ (and
that IRQ line isn't already being used), these routines will tell
you what IRQ line it's using -- perfect for those oh-so-cool boot-time
device probes!
To use this, first call autoirq_setup(timeout). TIMEOUT is how many
'jiffies' (1/18 sec.) to detect other devices that have active IRQ lines,
and can usually be zero at boot. 'autoirq_setup()' returns the bit
vector of nominally-available IRQ lines (lines may be physically in-use,
but not yet registered to a device).
Next, set up your device to trigger an interrupt.
Finally call autoirq_report(TIMEOUT) to find out which IRQ line was
most recently active. The TIMEOUT should usually be zero, but may
be set to the number of jiffies to wait for a slow device to raise an IRQ.
The idea of using the setup timeout to filter out bogus IRQs came from
the serial driver.
*/
#ifdef version
static char *version="auto_irq.c:v0.01 1993 Donald Becker (becker@super.org)";
#endif
/*#include <linux/config.h>*/
/*#include <linux/kernel.h>*/
#include <linux/sched.h>
#include <asm/bitops.h>
#include <asm/io.h>
/*#include <asm/system.h>*/
int irqs_busy = 0x01; /* The set of fixed IRQs always enabled */
int irqs_used = 0x01; /* The set of fixed IRQs sometimes enabled. */
int irqs_reserved = 0x00; /* An advisory "reserved" table. */
int irqs_shared = 0x00; /* IRQ lines "shared" among conforming cards.*/
static volatile int irq_number; /* The latest irq number we actually found. */
static volatile int irq_bitmap; /* The irqs we actually found. */
static int irq_handled; /* The irq lines we have a handler on. */
static void autoirq_probe(int irq)
{
irq_number = irq;
set_bit(irq, (void *)&irq_bitmap); /* irq_bitmap |= 1 << irq; */
return;
}
struct sigaction autoirq_sigaction = { autoirq_probe, 0, SA_INTERRUPT, NULL};
int autoirq_setup(int waittime)
{
int i, mask;
int timeout = jiffies+waittime;
irq_number = 0;
irq_bitmap = 0;
irq_handled = 0;
for (i = 0; i < 16; i++) {
if (!irqaction(i, &autoirq_sigaction))
set_bit(i, (void *)&irq_handled); /* irq_handled |= 1 << i;*/
}
/* Update our USED lists. */
irqs_used |= ~irq_handled;
/* Hang out at least <waittime> jiffies waiting for bogus IRQ hits. */
while (timeout >= jiffies)
;
for (i = 0, mask = 0x01; i < 16; i++, mask <<= 1) {
if (irq_bitmap & irq_handled & mask) {
irq_handled &= ~mask;
printk(" Spurious interrupt on IRQ %d\n", i);
free_irq(i);
}
}
return irq_handled;
}
int autoirq_report(int waittime)
{
int i;
int timeout = jiffies+waittime;
/* Hang out at least <waittime> jiffies waiting for the IRQ. */
while (timeout >= jiffies)
if (irq_number)
break;
/* Retract the irq handlers that we installed. */
for (i = 0; i < 16; i++) {
if (test_bit(i, (void *)&irq_handled))
free_irq(i);
}
return irq_number;
}
/*
* Local variables:
* compile-command: "gcc -DKERNEL -Wall -O6 -fomit-frame-pointer -I/usr/src/linux/net/tcp -c auto_irq.c"
* version-control: t
* kept-new-versions: 5
* End:
*/

View File

@@ -0,0 +1,319 @@
/* hp.c: A HP LAN ethernet driver for linux. */
/*
Written 1993 by Donald Becker. This is alpha test code.
This is a extension to the Linux operating system, and is covered by
same Gnu Public License that covers that work.
This is a driver for the HP LAN adaptors.
The Author may be reached as becker@super.org or
C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
*/
static char *version = "hp.c:v0.67 3/8/93 Donald Becker (becker@super.org)\n";
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <asm/io.h>
#include <asm/system.h>
#include "dev.h"
#include "8390.h"
/* These should be in <asm/io.h> someday, borrowed from blk_drv/hd.c. */
#define port_read(port,buf,nr) \
__asm__("cld;rep;insw"::"d" (port),"D" (buf),"c" (nr):"cx","di")
#define port_write(port,buf,nr) \
__asm__("cld;rep;outsw"::"d" (port),"S" (buf),"c" (nr):"cx","si")
#define port_read_b(port,buf,nr) \
__asm__("cld;rep;insb"::"d" (port),"D" (buf),"c" (nr):"cx","di")
#define port_write_b(port,buf,nr) \
__asm__("cld;rep;outsb"::"d" (port),"S" (buf),"c" (nr):"cx","si")
#define HP_DATAPORT 0x0c /* "Remote DMA" data port. */
#define HP_ID 0x07
#define HP_CONFIGURE 0x08 /* Configuration register. */
#define HP_RUN 0x01 /* 1 == Run, 0 == reset. */
#define HP_IRQ 0x0E /* Mask for software-configured IRQ line. */
#define HP_DATAON 0x10 /* Turn on dataport */
#define NIC_OFFSET 0x10 /* Offset the 8390 registers. */
#define HP_START_PG 0x00 /* First page of TX buffer */
#define HP_8BSTOP_PG 0x80 /* Last page +1 of RX ring */
#define HP_16BSTOP_PG 0xFF /* Last page +1 of RX ring */
extern void NS8390_init(struct device *dev, int startp);
extern int ei_debug;
extern struct sigaction ei_sigaction;
int hpprobe(int ioaddr, struct device *dev);
int hpprobe1(int ioaddr, struct device *dev);
static void hp_reset_8390(struct device *dev);
static int hp_block_input(struct device *dev, int count,
char *buf, int ring_offset);
static void hp_block_output(struct device *dev, int count,
const unsigned char *buf, const start_page);
static void hp_init_card(struct device *dev);
/* The map from IRQ number to HP_CONFIGURE register setting. */
/* My default is IRQ5 0 1 2 3 4 5 6 7 8 9 10 11 */
static char irqmap[16] = { 0, 0, 4, 6, 8,10, 0,14, 0, 4, 2,12,0,0,0,0};
/* Probe for an HP LAN adaptor.
Also initialize the card and fill in STATION_ADDR with the station
address. */
int hpprobe(int ioaddr, struct device *dev)
{
int *port, ports[] = {0x300, 0x320, 0x340, 0x280, 0x2C0, 0x200, 0x240, 0};
if (ioaddr > 0x100)
return hpprobe1(ioaddr, dev);
for (port = &ports[0]; *port; port++)
if (inb_p(*port) != 0xff && hpprobe1(*port, dev))
return dev->base_addr;
return 0;
}
int hpprobe1(int ioaddr, struct device *dev)
{
int i;
unsigned char *station_addr = dev->dev_addr;
unsigned char SA_prom[6];
int tmp;
int hplan;
printk("HP-LAN ethercard probe at %#3x:", ioaddr);
tmp = inb_p(ioaddr);
if (tmp == 0xFF) {
printk(" not found (nothing there).\n");
return 0;
}
for(i = 0; i < sizeof(SA_prom); i++) {
SA_prom[i] = inb(ioaddr + i);
if (i < ETHER_ADDR_LEN && station_addr) {
printk(" %2.2x", SA_prom[i]);
station_addr[i] = SA_prom[i];
}
}
hplan = (SA_prom[0] == 0x08 && SA_prom[1] == 0x00 && SA_prom[2] == 0x09);
if (hplan == 0) {
printk(" not found (invalid station address prefix).\n");
return 0;
}
ei_status.tx_start_page = HP_START_PG;
ei_status.rx_start_page = HP_START_PG + TX_PAGES;
/* Set up the rest of the parameters. */
if ((tmp = inb_p(HP_ID)) & 0x80) {
ei_status.name = "HP27247";
ei_status.word16 = 1;
ei_status.stop_page = HP_16BSTOP_PG; /* Safe for now */
} else {
ei_status.name = "HP27250";
ei_status.word16 = 0;
ei_status.stop_page = HP_8BSTOP_PG; /* Safe for now */
}
/* Set the base address to point to the NIC! */
dev->base_addr = ioaddr + NIC_OFFSET;
/* Snarf the interrupt now. There's no point in waiting since we cannot
share and the board will usually be enabled. */
if (dev->irq < 2) {
int irq_16list[] = { 11, 10, 5, 3, 4, 7, 9, 0};
int irq_8list[] = { 7, 5, 3, 4, 9, 0};
int *irqp = ei_status.word16 ? irq_16list : irq_8list;
do {
if (request_irq (dev->irq = *irqp, NULL) != -EBUSY) {
autoirq_setup(0);
/* Twinkle the interrupt, and check if it's seen. */
outb_p(irqmap[dev->irq] | HP_RUN, ioaddr + HP_CONFIGURE);
outb_p( 0x00 | HP_RUN, ioaddr + HP_CONFIGURE);
if (dev->irq == autoirq_report(0) /* It's a good IRQ line! */
&& request_irq (dev->irq, &ei_interrupt) == 0) {
printk(" got IRQ %d", dev->irq);
break;
} else
printk(" IRQ%d busy..", dev->irq);
}
} while (*++irqp);
if (*irqp == 0) {
printk(" unable to find an free IRQ line.\n");
return 0;
}
} 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;
}
}
printk("\n%s: %s using IRQ %d.\n", dev->name, ei_status.name, dev->irq);
if (ei_debug > 1)
printk(version);
ei_status.reset_8390 = &hp_reset_8390;
ei_status.block_input = &hp_block_input;
ei_status.block_output = &hp_block_output;
hp_init_card(dev);
return dev->base_addr;
}
static void
hp_reset_8390(struct device *dev)
{
int hp_base = dev->base_addr - NIC_OFFSET;
int saved_config = inb_p(hp_base + HP_CONFIGURE);
int reset_start_time = jiffies;
if (ei_debug > 1) printk("resetting the 8390 time=%d...", jiffies);
outb_p(0x00, hp_base + HP_CONFIGURE);
ei_status.txing = 0;
sti();
/* We shouldn't use the boguscount for timing, but this hasn't been
checked yet, and you could hang your machine if jiffies break... */
{
int boguscount = 150000;
while(jiffies - reset_start_time < 2)
if (boguscount-- < 0) {
printk("jiffy failure (t=%d)...", jiffies);
break;
}
}
outb_p(saved_config, hp_base + HP_CONFIGURE);
while ((inb_p(hp_base+NIC_OFFSET+EN0_ISR) & ENISR_RESET) == 0)
if (jiffies - reset_start_time > 2) {
printk("%s: hp_reset_8390() did not complete.\n", dev->name);
return;
}
if (ei_debug > 1) printk("8390 reset done.", jiffies);
}
/* Block input and output, similar to the Crynwr packet driver. If you
porting to a new ethercard look at the packet driver source for hints.
The HP LAN doesn't use shared memory -- we put the packet
out through the "remote DMA" dataport. */
static int
hp_block_input(struct device *dev, int count, char *buf, int ring_offset)
{
int nic_base = dev->base_addr;
int saved_config = inb_p(nic_base - NIC_OFFSET + HP_CONFIGURE);
int xfer_count = count;
outb_p(saved_config | HP_DATAON, nic_base - NIC_OFFSET + HP_CONFIGURE);
outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base);
outb_p(count & 0xff, nic_base + EN0_RCNTLO);
outb_p(count >> 8, nic_base + EN0_RCNTHI);
outb_p(ring_offset & 0xff, nic_base + EN0_RSARLO);
outb_p(ring_offset >> 8, nic_base + EN0_RSARHI);
outb_p(E8390_RREAD+E8390_START, nic_base);
if (ei_status.word16) {
port_read(nic_base - NIC_OFFSET + HP_DATAPORT,buf,count>>1);
if (count & 0x01)
buf[count-1] = inb(nic_base - NIC_OFFSET + HP_DATAPORT), xfer_count++;
} else {
port_read_b(nic_base - NIC_OFFSET + HP_DATAPORT, buf, count);
}
/* This is for the ALPHA version only, remove for later releases. */
if (ei_debug > 0) { /* DMA termination address check... */
int high = inb_p(nic_base + EN0_RSARHI);
int low = inb_p(nic_base + EN0_RSARLO);
int addr = (high << 8) + low;
/* Check only the lower 8 bits so we can ignore ring wrap. */
if (((ring_offset + xfer_count) & 0xff) != (addr & 0xff))
printk("%s: RX transfer address mismatch, %#4.4x vs. %#4.4x (actual).\n",
dev->name, ring_offset + xfer_count, addr);
}
outb_p(saved_config & (~HP_DATAON), nic_base - NIC_OFFSET + HP_CONFIGURE);
return ring_offset + count;
}
static void
hp_block_output(struct device *dev, int count,
const unsigned char *buf, const start_page)
{
int nic_base = dev->base_addr;
int saved_config = inb_p(nic_base - NIC_OFFSET + HP_CONFIGURE);
outb_p(saved_config | HP_DATAON, nic_base - NIC_OFFSET + HP_CONFIGURE);
/* Round the count up for word writes. Do we need to do this?
What effect will an odd byte count have on the 8390?
I should check someday. */
if (ei_status.word16 && (count & 0x01))
count++;
/* We should already be in page 0, but to be safe... */
outb_p(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base);
#ifdef ei8390_bug
/* Handle the read-before-write bug the same way as the
Crynwr packet driver -- the NatSemi method doesn't work. */
outb_p(0x42, nic_base + EN0_RCNTLO);
outb_p(0, nic_base + EN0_RCNTHI);
outb_p(0xff, nic_base + EN0_RSARLO);
outb_p(0x00, nic_base + EN0_RSARHI);
outb_p(E8390_RREAD+E8390_START, EN_CMD);
/* Make certain that the dummy read has occured. */
inb_p(0x61);
inb_p(0x61);
#endif
outb_p(count & 0xff, nic_base + EN0_RCNTLO);
outb_p(count >> 8, nic_base + EN0_RCNTHI);
outb_p(0x00, nic_base + EN0_RSARLO);
outb_p(start_page, nic_base + EN0_RSARHI);
outb_p(E8390_RWRITE+E8390_START, nic_base);
if (ei_status.word16) {
/* Use the 'rep' sequence for 16 bit boards. */
port_write(nic_base - NIC_OFFSET + HP_DATAPORT, buf, count>>1);
} else {
port_write_b(nic_base - NIC_OFFSET + HP_DATAPORT, buf, count);
}
/* DON'T check for 'inb_p(EN0_ISR) & ENISR_RDC' here -- it's broken! */
/* This is for the ALPHA version only, remove for later releases. */
if (ei_debug > 0) { /* DMA termination address check... */
int high = inb_p(nic_base + EN0_RSARHI);
int low = inb_p(nic_base + EN0_RSARLO);
int addr = (high << 8) + low;
if ((start_page << 8) + count != addr)
printk("%s: TX Transfer address mismatch, %#4.4x vs. %#4.4x.\n",
dev->name, (start_page << 8) + count, addr);
}
outb_p(saved_config & (~HP_DATAON), nic_base - NIC_OFFSET + HP_CONFIGURE);
return;
}
/* This function resets the ethercard if something screws up. */
static void
hp_init_card(struct device *dev)
{
int irq = dev->irq;
NS8390_init(dev, 0);
outb_p(irqmap[irq&0x0f] | HP_RUN,
dev->base_addr - NIC_OFFSET + HP_CONFIGURE);
return;
}
/*
* Local variables:
* compile-command: "gcc -DKERNEL -Wall -O6 -fomit-frame-pointer -I/usr/src/linux/net/tcp -c hp.c"
* version-control: t
* kept-new-versions: 5
* End:
*/

View File

@@ -0,0 +1,379 @@
/* ne.c: A general non-shared-memory NS8390 ethernet driver for linux. */
/*
Written 1992,1993 by Donald Becker. This is alpha test code.
This is a extension to the Linux operating system, and is covered by
same Gnu Public License that covers that work.
This driver should work with many 8390-based ethernet boards. Currently
it support the NE1000, NE2000 (and clones), and some Cabletron products.
8-bit ethercard support is enabled with #define EI_8BIT
The Author may be reached as becker@super.org or
C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
*/
/* Routines for the NatSemi-based designs (NE[12]000). */
static char *version =
"ne.c:v0.50 2/19/93 Donald Becker (becker@super.org)\n";
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <asm/io.h>
#include <asm/system.h>
#include "dev.h"
#include "8390.h"
/* These should be in <asm/io.h> someday, borrowed from blk_drv/hd.c. */
#define port_read(port,buf,nr) \
__asm__("cld;rep;insw"::"d" (port),"D" (buf),"c" (nr):"cx","di")
#define port_write(port,buf,nr) \
__asm__("cld;rep;outsw"::"d" (port),"S" (buf),"c" (nr):"cx","si")
#define port_read_b(port,buf,nr) \
__asm__("cld;rep;insb"::"d" (port),"D" (buf),"c" (nr):"cx","di")
#define port_write_b(port,buf,nr) \
__asm__("cld;rep;outsb"::"d" (port),"S" (buf),"c" (nr):"cx","si")
#define EN_CMD (dev->base_addr)
#define NE_BASE (dev->base_addr)
#define NE_DATAPORT 0x10 /* NatSemi-defined port window offset. */
#define NE_RESET 0x1f /* Issue a read to reset, a write to clear. */
#define NE1SM_START_PG 0x20 /* First page of TX buffer */
#define NE1SM_STOP_PG 0x40 /* Last page +1 of RX ring */
#define NESM_START_PG 0x40 /* First page of TX buffer */
#define NESM_STOP_PG 0x80 /* Last page +1 of RX ring */
extern void NS8390_init(struct device *dev, int startp);
extern int ei_debug;
extern struct sigaction ei_sigaction;
int neprobe(int ioaddr, struct device *dev);
static int neprobe1(int ioaddr, struct device *dev, int verbose);
static void ne_reset_8390(struct device *dev);
static int ne_block_input(struct device *dev, int count,
char *buf, int ring_offset);
static void ne_block_output(struct device *dev, const int count,
const unsigned char *buf, const int start_page);
/* Probe for various non-shared-memory ethercards.
NEx000-clone boards have a Station Address PROM (SAPROM) in the packet
buffer memory space. NE2000 clones have 0x57,0x57 in bytes 0x0e,0x0f of
the SAPROM, while other supposed NE2000 clones must be detected by their
SA prefix.
Reading the SAPROM from a word-wide card with the 8390 set in byte-wide
mode results in doubled values, which can be detected and compansated for.
The probe is also responsible for initializing the card and filling
in the 'dev' and 'ei_status' structures.
We use the minimum memory size for some ethercard product lines, iff we can't
distinguish models. You can increase the packet buffer size by setting
PACKETBUF_MEMSIZE. Reported Cabletron packet buffer locations are:
E1010 starts at 0x100 and ends at 0x2000.
E1010-x starts at 0x100 and ends at 0x8000. ("-x" means "more memory")
E2010 starts at 0x100 and ends at 0x4000.
E2010-x starts at 0x100 and ends at 0xffff. */
int neprobe(int ioaddr, struct device *dev)
{
int *port, ports[] = {0x300, 0x280, 0x320, 0x340, 0x360, 0};
if (ioaddr > 0x100)
return neprobe1(ioaddr, dev, 1);
for (port = &ports[0]; *port; port++)
if (inb_p(*port) != 0xff && neprobe1(*port, dev, 0))
return dev->base_addr = *port;
return 0;
}
static int neprobe1(int ioaddr, struct device *dev, int verbose)
{
int i;
unsigned char SA_prom[32];
int wordlength = 2;
int neX000, ctron, dlink;
if ( inb_p(ioaddr) == 0xFF) {
if (verbose) printk("8390 ethercard probe at %#3x failed.\n", ioaddr);
return 0;
}
printk("8390 ethercard probe at %#3x:", ioaddr);
/* Read the 16 bytes of station address prom, returning 1 for
an eight-bit interface and 2 for a 16-bit interface.
We must first initialize registers, similar to NS8390_init(eifdev, 0).
We can't reliably read the SAPROM address without this.
(I learned the hard way!). */
{
struct {char value, offset; } program_seq[] = {
{E8390_NODMA+E8390_PAGE0+E8390_STOP, EN_CMD}, /* Select page 0 */
{0x48, EN0_DCFG}, /* Set byte-wide (0x48) access. */
{0x00, EN0_RCNTLO}, /* Clear the count regs. */
{0x00, EN0_RCNTHI},
{0x00, EN0_IMR}, /* Mask completion irq. */
{0xFF, EN0_ISR},
{E8390_RXOFF, EN0_RXCR}, /* 0x20 Set to monitor */
{E8390_TXOFF, EN0_TXCR}, /* 0x02 and loopback mode. */
{32, EN0_RCNTLO},
{0x00, EN0_RCNTHI},
{0x00, EN0_RSARLO}, /* DMA starting at 0x0000. */
{0x00, EN0_RSARHI},
{E8390_RREAD+E8390_START, EN_CMD},
};
for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++)
outb_p(program_seq[i].value, ioaddr + program_seq[i].offset);
}
for(i = 0; i < 32 /*sizeof(SA_prom)*/; i+=2) {
SA_prom[i] = inb_p(ioaddr + NE_DATAPORT);
SA_prom[i+1] = inb_p(ioaddr + NE_DATAPORT);
if (SA_prom[i] != SA_prom[i+1])
wordlength = 1;
}
if (wordlength == 2) {
/* We must set the 8390 for word mode, AND RESET IT. */
int tmp;
outb_p(0x49, ioaddr + EN0_DCFG);
tmp = inb_p(NE_BASE + NE_RESET);
ei_status.word16 = 1;
outb(tmp, NE_BASE + NE_RESET);
/* Un-double the SA_prom values. */
for (i = 0; i < 16; i++)
SA_prom[i] = SA_prom[i+i];
} else
ei_status.word16 = 0;
#if defined(show_all_SAPROM)
/* If your ethercard isn't detected define this to see the SA_PROM. */
for(i = 0; i < sizeof(SA_prom); i++)
printk(" %2.2x", SA_prom[i]);
#else
for(i = 0; i < ETHER_ADDR_LEN; i++) {
dev->dev_addr[i] = SA_prom[i];
printk(" %2.2x", SA_prom[i]);
}
#endif
neX000 = (SA_prom[14] == 0x57 && SA_prom[15] == 0x57);
ctron = (SA_prom[0] == 0x00 && SA_prom[1] == 0x00 && SA_prom[2] == 0x1d);
dlink = (SA_prom[0] == 0x00 && SA_prom[1] == 0xDE && SA_prom[2] == 0x01);
/* Set up the rest of the parameters. */
if (neX000 && wordlength == 2) {
ei_status.name = "NE2000";
ei_status.tx_start_page = NESM_START_PG;
ei_status.stop_page = NESM_STOP_PG;
} else if (neX000 || dlink) {
ei_status.name = neX000 ? "NE1000" : "D-Link";
ei_status.tx_start_page = NE1SM_START_PG;
ei_status.stop_page = NE1SM_STOP_PG;
} else if (ctron) {
ei_status.name = "Cabletron";
ei_status.tx_start_page = 0x01;
ei_status.stop_page = (wordlength == 2) ? 0x40 : 0x20;
} else {
printk(" not found.\n");
return 0;
}
ei_status.rx_start_page = ei_status.tx_start_page + TX_PAGES;
#ifdef PACKETBUF_MEMSIZE
/* Allow the packet buffer size to be overridden by know-it-alls. */
ei_status.stop_page = ei_status.tx_start_page + PACKETBUF_MEMSIZE;
#endif
dev->base_addr = ioaddr;
if (dev->irq < 2) {
int nic_base = dev->base_addr;
autoirq_setup(0);
outb_p(0x50, nic_base + EN0_IMR); /* Enable one interrupt. */
outb_p(0x00, nic_base + EN0_RCNTLO);
outb_p(0x00, nic_base + EN0_RCNTHI);
outb_p(E8390_RREAD+E8390_START, nic_base); /* Trigger it... */
outb_p(0x00, nic_base + EN0_IMR); /* Mask it again. */
dev->irq = autoirq_report(0);
if (ei_debug > 2)
printk(" autoirq is %d", dev->irq);
} else if (dev->irq == 2)
/* Fixup for users that don't know that IRQ 2 is really IRQ 9,
or don't know which one to set. */
dev->irq = 9;
/* Snarf the interrupt now. There's no point in waiting since we cannot
share and the board will usually be enabled. */
{ int irqval = irqaction (dev->irq, &ei_sigaction);
if (irqval) {
printk (" unable to get IRQ %d (irqval=%d).\n", dev->irq, irqval);
return 0;
}
}
printk("\n%s: %s found, using IRQ %d.\n",
dev->name, ei_status.name, dev->irq);
if (ei_debug > 1)
printk(version);
ei_status.reset_8390 = &ne_reset_8390;
ei_status.block_input = &ne_block_input;
ei_status.block_output = &ne_block_output;
NS8390_init(dev, 0);
return dev->base_addr;
}
static void
ne_reset_8390(struct device *dev)
{
int tmp = inb_p(NE_BASE + NE_RESET);
int reset_start_time = jiffies;
if (ei_debug > 1) printk("resetting the 8390 t=%d...", jiffies);
ei_status.txing = 0;
sti();
/* We shouldn't use the boguscount for timing, but this hasn't been
checked yet, and you could hang your machine if jiffies break... */
{
int boguscount = 150000;
while(jiffies - reset_start_time < 2)
if (boguscount-- < 0) {
printk("jiffy failure (t=%d)...", jiffies);
outb_p(tmp, NE_BASE + NE_RESET);
return;
}
}
outb_p(tmp, NE_BASE + NE_RESET);
while ((inb_p(NE_BASE+EN0_ISR) & ENISR_RESET) == 0)
if (jiffies - reset_start_time > 2) {
printk("%s: ne_reset_8390() did not complete.\n", dev->name);
break;
}
}
/* Block input and output, similar to the Crynwr packet driver. If you
porting to a new ethercard look at the packet driver source for hints.
The NEx000 doesn't share it on-board packet memory -- you have to put
the packet out through the "remote DMA" dataport using outb. */
static int
ne_block_input(struct device *dev, int count, char *buf, int ring_offset)
{
int xfer_count = count;
int nic_base = NE_BASE;
outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, EN_CMD);
outb_p(count & 0xff, nic_base + EN0_RCNTLO);
outb_p(count >> 8, nic_base + EN0_RCNTHI);
outb_p(ring_offset & 0xff, nic_base + EN0_RSARLO);
outb_p(ring_offset >> 8, nic_base + EN0_RSARHI);
outb_p(E8390_RREAD+E8390_START, EN_CMD);
if (ei_status.word16) {
port_read(NE_BASE + NE_DATAPORT,buf,count>>1);
if (count & 0x01)
buf[count-1] = inb(NE_BASE + NE_DATAPORT), xfer_count++;
} else {
port_read_b(NE_BASE + NE_DATAPORT, buf, count);
}
/* This was for the ALPHA version only, but enough people have
encountering problems that it is still here. */
if (ei_debug > 0) { /* DMA termination address check... */
int addr, tries = 10;
do {
/* DON'T check for 'inb_p(EN0_ISR) & ENISR_RDC' here
-- it's broken! Check the "DMA" address instead. */
int high = inb_p(nic_base + EN0_RSARHI);
int low = inb_p(nic_base + EN0_RSARLO);
addr = (high << 8) + low;
if (((ring_offset + xfer_count) & 0xff) == low)
return ring_offset + count;
} while (--tries > 0);
printk("%s: RX transfer address mismatch, %#4.4x (should be) vs. %#4.4x (actual).\n",
dev->name, ring_offset + xfer_count, addr);
}
return ring_offset + count;
}
static void
ne_block_output(struct device *dev, int count,
const unsigned char *buf, const int start_page)
{
int retries = 0;
int nic_base = NE_BASE;
/* Round the count up for word writes. Do we need to do this?
What effect will an odd byte count have on the 8390?
I should check someday. */
if (ei_status.word16 && (count & 0x01))
count++;
/* We should already be in page 0, but to be safe... */
outb_p(E8390_PAGE0+E8390_START+E8390_NODMA, EN_CMD);
retry:
#if defined(rw_bugfix)
/* Handle the read-before-write bug the same way as the
Crynwr packet driver -- the NatSemi method doesn't work.
Actually this doesn't aways work either, but if you have
problems with your NEx000 this is better than nothing! */
outb_p(0x42, nic_base + EN0_RCNTLO);
outb_p(0x00, nic_base + EN0_RCNTHI);
outb_p(0x42, nic_base + EN0_RSARLO);
outb_p(0x00, nic_base + EN0_RSARHI);
outb_p(E8390_RREAD+E8390_START, EN_CMD);
/* Make certain that the dummy read has occured. */
SLOW_DOWN_IO;
SLOW_DOWN_IO;
SLOW_DOWN_IO;
#endif /* rw_bugfix */
/* Now the normal output. */
outb_p(count & 0xff, nic_base + EN0_RCNTLO);
outb_p(count >> 8, nic_base + EN0_RCNTHI);
outb_p(0x00, nic_base + EN0_RSARLO);
outb_p(start_page, nic_base + EN0_RSARHI);
outb_p(E8390_RWRITE+E8390_START, EN_CMD);
if (ei_status.word16) {
port_write(NE_BASE + NE_DATAPORT, buf, count>>1);
} else {
port_write_b(NE_BASE + NE_DATAPORT, buf, count);
}
/* This was for the ALPHA version only, but enough people have
encountering problems that it is still here. */
if (ei_debug > 0) { /* DMA termination address check... */
int addr, tries = 10;
do {
/* DON'T check for 'inb_p(EN0_ISR) & ENISR_RDC' here
-- it's broken! Check the "DMA" address instead. */
int high = inb_p(nic_base + EN0_RSARHI);
int low = inb_p(nic_base + EN0_RSARLO);
addr = (high << 8) + low;
if ((start_page << 8) + count == addr)
return;
} while (--tries > 0);
printk("%s: Packet buffer transfer address mismatch on TX, %#4.4x vs. %#4.4x.\n",
dev->name, (start_page << 8) + count, addr);
if (retries++ == 0)
goto retry;
}
return;
}
/*
* Local variables:
* compile-command: "gcc -DKERNEL -Wall -O6 -fomit-frame-pointer -I/usr/src/linux/net/tcp -c ne.c"
* version-control: t
* kept-new-versions: 5
* End:
*/

View File

@@ -0,0 +1,334 @@
/* wd.c: A WD80x3 ethernet driver for linux. */
/*
Written 1993 by Donald Becker. This is alpha test code.
This is a extension to the Linux operating system, and is covered by
same Gnu Public License that covers that work.
This is a driver for the WD8003 and WD8013 ethercards.
The Author may be reached as becker@super.org or
C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
Thanks to Russ Nelson (nelson@crnwyr.com) for loaning me a WD8013.
*/
static char *version =
"wd.c:v0.66 3/7/93 Donald Becker (becker@super.org)\n";
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <asm/io.h>
#include <asm/system.h>
#include <memory.h>
#include "dev.h"
#include "8390.h"
extern void NS8390_init(struct device *dev, int startp);
extern int ei_debug;
extern struct sigaction ei_sigaction;
int wdprobe(int ioaddr, struct device *dev);
int wdprobe1(int ioaddr, struct device *dev);
static void wd_reset_8390(struct device *dev);
static int wd_block_input(struct device *dev, int count,
char *buf, int ring_offset);
static void wd_block_output(struct device *dev, int count,
const unsigned char *buf, const start_page);
static int wd_close_card(struct device *dev);
#define WD_START_PG 0x00 /* First page of TX buffer */
#define WD03_STOP_PG 0x20 /* Last page +1 of RX ring */
#define WD13_STOP_PG 0x40 /* Last page +1 of RX ring */
#define WD_CMDREG 0 /* Offset to ASIC command register. */
#define WD_RESET 0x80 /* Board reset, in WD_CMDREG. */
#define WD_MEMENB 0x40 /* Enable the shared memory. */
#define WD_CMDREG5 5 /* Offset to 16-bit-only ASIC register 5. */
#define ISA16 0x80 /* Enable 16 bit access from the ISA bus. */
#define NIC16 0x40 /* Enable 16 bit access from the 8390. */
#define WD_NIC_OFFSET 16 /* Offset to the 8390 NIC from the base_addr. */
/* Probe for the WD8003 and WD8013. These cards have the station
address PROM at I/O ports <base>+8 to <base>+13, with a checksum
following. The routine also initializes the card and fills the
station address field. */
int wdprobe(int ioaddr, struct device *dev)
{
int *port, ports[] = {0x300, 0x280, 0};
if (ioaddr > 0x100)
return wdprobe1(ioaddr, dev);
for (port = &ports[0]; *port; port++)
if (inb(*port) != 0xff && wdprobe1(*port, dev))
return *port;
return 0;
}
int wdprobe1(int ioaddr, struct device *dev)
{
int i;
unsigned char *station_addr = dev->dev_addr;
int checksum = 0;
int ancient = 0; /* An old card without config registers. */
#if defined(EI_DEBUG) && EI_DEBUG > 2
printk("WD80x3 ethercard at %#3x:", ioaddr);
for (i = 0; i < 16; i++) {
printk(" %2.2X", inb(ioaddr+i));
}
printk("\n");
printk("WD80x3 ethercard at %#3x:", ioaddr+i);
for (;i < 33; i++) {
printk(" %2.2X", inb(ioaddr+i));
}
printk("\n");
#endif
printk("WD80x3 ethercard probe at %#3x:", ioaddr);
for (i = 0; i < 8; i++) {
int inval = inb(ioaddr + 8 + i);
checksum += inval;
if (i < 6)
printk(" %2.2X", (station_addr[i] = inval));
}
if ((checksum & 0xff) != 0xFF) {
printk(" not found (%#2.2x).\n", checksum);
return 0;
}
ei_status.name = "WD8003";
ei_status.word16 = 0;
/* This method of checking for a 16-bit board is borrowed from the
we.c driver. A simpler method is just to look in ASIC reg. 0x03.
I'm comparing the two method in alpha test to make certain they
return the same result. */
#ifndef FORCE_8BIT /* Same define as we.c. */
/* check for 16 bit board - it doesn't have register 0/8 aliasing */
for (i = 0; i < 8; i++)
if (inb(ioaddr+i) != inb(ioaddr+8+i))
break;
if (i != 8) {
int tmp = inb(ioaddr+1); /* fiddle with 16bit bit */
outb( tmp ^ 0x01, ioaddr+1 ); /* attempt to clear 16bit bit */
if (((inb( ioaddr+1) & 0x01) == 0x01) /* A 16 bit card */
&& (tmp & 0x01) == 0x01 ) { /* In a 16 slot. */
int asic_reg5 = inb(ioaddr+WD_CMDREG5);
/* Magic to set ASIC to word-wide mode. */
outb( ISA16 | NIC16 | (asic_reg5&0x1f), ioaddr+WD_CMDREG5);
outb(tmp, ioaddr+1);
ei_status.name = "WD8013";
ei_status.word16 = 1; /* We have a 16bit board here! */
}
outb(tmp, ioaddr+1); /* Restore original reg1 value. */
} else
ancient = 1;
#endif /* not FORCE_8BIT */
#ifndef final_version
if ( !ancient && (inb(ioaddr+1) & 0x01) != (ei_status.word16 & 0x01))
printk("\nWD80?3: Bus width conflict, %d (probe) != %d (reg report).",
ei_status.word16 ? 16:8, (inb(ioaddr+1) & 0x01) ? 16 : 8);
#endif
#if defined(WD_SHMEM) && WD_SHMEM > 0x80000
/* Allow an override. */
dev->mem_start = WD_SHMEM;
#else
if (dev->mem_start == 0) {
dev->mem_start = ((inb(ioaddr)&0x3f) << 13) +
(ei_status.word16 ? (inb(ioaddr+WD_CMDREG5)&0x1f)<<19 : 0x80000);
if (dev->mem_start < 0xc0000) /* Sanity and old 8003 check */
dev->mem_start = 0xd0000;
}
#endif
/* The 8390 isn't at the base address -- the ASIC regs are there! */
dev->base_addr = ioaddr+WD_NIC_OFFSET;
ei_status.tx_start_page = WD_START_PG;
ei_status.rx_start_page = WD_START_PG + TX_PAGES;
ei_status.stop_page = ei_status.word16 ? WD13_STOP_PG : WD03_STOP_PG;
dev->rmem_start = dev->mem_start + TX_PAGES*256;
dev->mem_end = dev->rmem_end
= dev->mem_start + (ei_status.stop_page - WD_START_PG)*256;
#if defined(EI_DEBUG) && EI_DEBUG > 3
memset((void*)dev->mem_start, 0x42052465,
(ei_status.stop_page - WD_START_PG)*256);
#endif
if (dev->irq < 2) {
int irqmap[] = {9,3,5,7,10,11,15,4};
dev->irq = irqmap[((inb(ioaddr+4) >> 5) & 0x03)
+ (inb(ioaddr+1) & 0x04)];
} else if (dev->irq == 2)
/* Fixup for users that don't know that IRQ 2 is really IRQ 9,
or don't know which one to set. */
dev->irq = 9;
/* Snarf the interrupt now. There's no point in waiting since we cannot
share and the board will usually be enabled. */
{ int irqval = irqaction (dev->irq, &ei_sigaction);
if (irqval) {
printk (" unable to get IRQ %d (irqval=%d).\n", dev->irq, irqval);
return 0;
}
}
printk("\n%s: %s using IRQ %d with shared memory at %#x-%#x.\n",
dev->name, ei_status.name, dev->irq, dev->mem_start, dev->mem_end-1);
if (ei_debug > 1)
printk(version);
if (ei_debug > 2)
printk("%s: Address read from register is %#x, setting address %#x\n",
ei_status.name,
((inb(ioaddr+WD_CMDREG5)&0x1f)<<19) + ((inb(ioaddr)&0x3f) << 13),
dev->mem_start);
/* Map in the shared memory. This is a little risky, since using
the stuff the user supplied is probably a bad idea. */
outb((((dev->mem_start>>13) & 0x3f)|WD_MEMENB), ioaddr); /* WD_CMDREG */
if (ei_status.word16)
outb( ISA16 | NIC16 | ((dev->mem_start>>19) & 0x1f), ioaddr+WD_CMDREG5);
ei_status.reset_8390 = &wd_reset_8390;
ei_status.block_input = &wd_block_input;
ei_status.block_output = &wd_block_output;
dev->stop = &wd_close_card;
NS8390_init(dev, 0);
return dev->base_addr;
}
static void
wd_reset_8390(struct device *dev)
{
int wd_cmd_port = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
int reset_start_time = jiffies;
outb(WD_RESET, wd_cmd_port);
if (ei_debug > 1) printk("resetting the WD80x3 t=%d...", jiffies);
ei_status.txing = 0;
sti();
/* We shouldn't use the boguscount for timing, but this hasn't been
checked yet, and you could hang your machine if jiffies break... */
{
int boguscount = 150000;
while(jiffies - reset_start_time < 2)
if (boguscount-- < 0) {
printk("jiffy failure (t=%d)...", jiffies);
break;
}
}
outb(0x00, wd_cmd_port);
while ((inb(dev->base_addr+EN0_ISR) & ENISR_RESET) == 0)
if (jiffies - reset_start_time > 2) {
printk("%s: wd_reset_8390() did not complete.\n", dev->name);
break;
}
#if defined(EI_DEBUG) && EI_DEBUG > 2
{
int i;
printk("WD80x3 ethercard at %#3x:", wd_cmd_port);
for (i = 0; i < 16; i++) {
printk(" %2.2X", inb(wd_cmd_port+i));
}
printk("\nWD80x3 ethercard at %#3x:", wd_cmd_port);
for (;i < 33; i++) {
printk(" %2.2X", inb(wd_cmd_port+i));
}
printk("\n");
}
#endif
/* Set up the ASIC registers, just in case something changed them. */
outb((((dev->mem_start>>13) & 0x3f)|WD_MEMENB), wd_cmd_port); /* WD_CMDREG */
if (ei_status.word16)
outb( ISA16 | NIC16 | ((dev->mem_start>>19) & 0x1f), wd_cmd_port+WD_CMDREG5);
}
/* Block input and output are easy on shared memory ethercards, and trivial
on the Western digital card where there is no choice of how to do it. */
static int
wd_block_input(struct device *dev, int count, char *buf, int ring_offset)
{
void *xfer_start = (void *)(dev->mem_start + ring_offset - (WD_START_PG<<8));
#ifdef mapout
int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
int mem_val = inb(wd_cmdreg);
/* Map in the shared memory. */
outb(mem_val|WD_MEMENB, wd_cmdreg);
#endif
if (xfer_start + count > (void*) dev->rmem_end) {
/* We must wrap the input move. */
int semi_count = (void*)dev->rmem_end - xfer_start;
memcpy(buf, xfer_start, semi_count);
count -= semi_count;
memcpy(buf + semi_count, (char *)dev->rmem_start, count);
return dev->rmem_start + count;
}
memcpy(buf, xfer_start, count);
if (ei_debug > 4) {
unsigned short *board = xfer_start;
printk("%s: wd8013 block_input(cnt=%d offset=%3x addr=%#x) = %2x %2x %2x...\n",
dev->name, count, ring_offset, xfer_start,
board[-1], board[0], board[1]);
}
#ifdef mapout
outb(mem_val & ~WD_MEMENB, wd_cmdreg); /* WD_CMDREG: Map out the shared memory. */
#endif
return ring_offset + count;
}
/* This could only be outputting to the transmit buffer. The
ping-pong transmit setup doesn't work with this yet. */
static void
wd_block_output(struct device *dev, int count, const unsigned char *buf, int start_page)
{
unsigned char *shmem = (void *)dev->mem_start + ((start_page - WD_START_PG)<<8);
#ifdef mapout
int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
int mem_val = inb(wd_cmdreg);
/* Map in the shared memory. */
outb(mem_val|WD_MEMENB, wd_cmdreg);
#endif
memcpy(shmem, buf, count);
if (ei_debug > 4)
printk("%s: wd80*3 block_output(addr=%#x cnt=%d) -> %2x=%2x %2x=%2x %d...\n",
shmem, count, shmem[23], buf[23], shmem[24], buf[24], memcmp(shmem,buf,count));
#ifdef mapout
outb(mem_val & ~WD_MEMENB, wd_cmdreg); /* WD_CMDREG: Map out the shared memory. */
#endif
}
/* This function resets the ethercard if something screws up. */
static int
wd_close_card(struct device *dev)
{
if (ei_debug > 1)
printk("%s: Shutting down ethercard.\n", dev->name);
NS8390_init(dev, 0);
/* Turn off the shared memory. */
outb((((dev->mem_start>>13) & 0x3f)),
dev->base_addr-WD_NIC_OFFSET); /* WD_CMDREG */
return 0;
}
/*
* Local variables:
* compile-command: "gcc -DKERNEL -Wall -O6 -fomit-frame-pointer -I/usr/src/linux/net/tcp -c wd.c"
* version-control: t
* kept-new-versions: 5
* End:
*/

BIN
net/tcpip/newether.taz Normal file

Binary file not shown.

340
net/tcpip/newether/3c503.c Normal file
View File

@@ -0,0 +1,340 @@
/* 3c503.c: A shared-memory NS8390 ethernet driver for linux. */
/*
Written 1992,1993 by Donald Becker. This is alpha test code.
This is a extension to the Linux operating system, and is covered by
same Gnu Public License that covers that work.
This driver should work with the 3c503 and 3c503/16. It must be used
in shared memory mode.
The Author may be reached as becker@super.org or
C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
*/
static char *version = "3c503.c:v0.28 1/28/93 Donald Becker (becker@super.org)\n";
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <asm/io.h>
#include <asm/system.h>
#include "dev.h"
#include "8390.h"
#include "3c503reg.h"
#define EL2AUTOPROBE
extern void NS8390_init(struct device *dev, int startp);
extern int ei_debug;
extern struct sigaction ei_sigaction;
extern struct ei_device ei_status;
int etherlink2 = 0;
int el2autoprobe(int ioaddr, struct device *dev);
int el2probe(int ioaddr, struct device *dev);
static void el2_reset_8390(struct device *dev);
static void el2_init_card(struct device *dev);
static void el2_block_output(struct device *dev, int count,
const unsigned char *buf, const start_page);
static int el2_block_input(struct device *dev, int count, char *buf,
int ring_offset);
int
el2autoprobe(int ioaddr, struct device *dev)
{
int *addr, addrs[] = { 0xddfff, 0xd9fff, 0xcdfff, 0xc9fff, 0};
int ports[] = {0, 0x300, 0x310, 0x330, 0x350, 0x250, 0x280, 0x2a0, 0x2e0, 0};
/* Non-autoprobe case first: */
if (ioaddr > 0)
if (el2probe(ioaddr, dev))
return dev->base_addr = ioaddr;
else
return 0;
/* We check for a memory-mapped 3c503 board by looking at the
end of boot PROM space (works even if a PROM isn't there). */
for (addr = addrs; *addr; addr++) {
unsigned int base_bits = *(unsigned char *)*addr, i;
/* Find first set bit. */
for(i = 8; i; i--, base_bits >>= 1)
if (base_bits & 0x1)
break;
if (base_bits == 1 && el2probe(ports[i], dev))
return dev->base_addr = ports[i];
}
#ifdef notdef
/* If it's not memory mapped, we don't care to find it. I haven't
tested the non-memory-mapped code. */
/* It's not memory mapped -- try all of the locations that aren't
obviously empty. */
{ int *port;
for (port = &ports[1]; *port; port++)
if (inb_p(*port) != 0xff && el2probe(*port, dev))
return dev->base_addr = *port;
}
#endif
return 0;
}
/* Probe for the Etherlink II card at I/O port base IOADDR,
returning non-zero on sucess. If found, set the station
address and memory parameters in DEVICE. */
int
el2probe(int ioaddr, struct device *dev)
{
int i, found, mem_jumpers;
unsigned char *station_addr = dev->dev_addr;
/* We verify that it's a 3C503 board by checking the first three octets
of its ethernet address. */
printk("3c503 probe at %#3x:", ioaddr);
outb_p(ECNTRL_RESET|ECNTRL_THIN, ioaddr + 0x406); /* Reset it... */
outb_p(ECNTRL_THIN, ioaddr + 0x406);
/* Map the station addr PROM into the lower I/O ports. */
outb(ECNTRL_SAPROM|ECNTRL_THIN, ioaddr + 0x406);
for (i = 0; i < ETHER_ADDR_LEN; i++) {
printk(" %2.2X", (station_addr[i] = inb(ioaddr + i)));
}
/* Map the 8390 back into the window. */
outb(ECNTRL_THIN, ioaddr + 0x406);
found =( station_addr[0] == 0x02
&& station_addr[1] == 0x60
&& station_addr[2] == 0x8c);
if (! found) {
printk(" 3C503 not found.\n");
return 0;
}
/* Probe for, turn on and clear the board's shared memory. */
mem_jumpers = inb(ioaddr + 0x404); /* E33G_ROMBASE */
if (ei_debug > 2) printk(" memory jumpers %2.2x ", mem_jumpers);
outb(EGACFR_IRQOFF, E33G_GACFR); /* Enable RAM */
if ((mem_jumpers & 0xf0) == 0) {
dev->mem_start = 0;
if (ei_debug > 1) printk(" no shared memory ");
} else {
dev->mem_start = ((mem_jumpers & 0xc0) ? 0xD8000 : 0xC8000) +
((mem_jumpers & 0xA0) ? 0x4000 : 0);
#define EL2_MEMSIZE (EL2SM_STOP_PG - EL2SM_START_PG)*256
#ifdef EL2MEMTEST
{ /* Check the card's memory. */
int *mem_base = (int *)dev->mem_start;
int memtest_value = 0xbbadf00d;
mem_base[0] = 0xba5eba5e;
for (i = 1; i < EL2_MEMSIZE/sizeof(mem_base[0]); i++) {
mem_base[i] = memtest_value;
if (mem_base[0] != 0xba5eba5e
|| mem_base[i] != memtest_value) {
printk(" memory failure or memory address conflict.\n");
dev->mem_start = 0;
break;
}
memtest_value += 0x55555555;
mem_base[i] = 0;
}
}
#endif /* EL2MEMTEST */
/* Divide the on-board memory into a single maximum-sized transmit
(double-sized for ping-pong transmit) buffer at the base, and
use the rest as a receive ring. */
dev->mem_end = dev->rmem_end = dev->mem_start + EL2_MEMSIZE;
dev->rmem_start = TX_PAGES*256 + dev->mem_start;
}
if (ei_debug > 2)
printk("\n3c503: memory params start=%#5x rstart=%#5x end=%#5x rend=%#5x.\n",
dev->mem_start, dev->rmem_start, dev->mem_end, dev->rmem_end);
/* Finish setting the board's parameters. */
etherlink2 = 1;
ei_status.tx_start_page = EL2SM_START_PG;
ei_status.rx_start_page = EL2SM_START_PG + TX_PAGES;
ei_status.stop_page = EL2SM_STOP_PG;
ei_status.reset_8390 = &el2_reset_8390;
ei_status.block_input = &el2_block_input;
ei_status.block_output = &el2_block_output;
/* This should be probed for (or set via an ioctl()) at run-time someday. */
#ifdef EI8390_THICK
ei_status.thin_bit = 0;
#else
ei_status.thin_bit = ECNTRL_THIN;
#endif
if (dev->irq <= 0)
dev->irq = 5; /* Autoprobe guess... */
if (dev->irq == 2)
dev->irq = 9;
else if (dev->irq != 9 && (dev->irq > 5 || dev->irq < 3)) {
printk("\n3c503: configured interrupt number %d out of range.\n",
dev->irq);
return 0;
}
if (irqaction (dev->irq, &ei_sigaction)) {
printk ("\n3c503: Unable to get IRQ%d.\n", dev->irq);
/* We could look for other free interrupts here, or something... */
return 0;
}
el2_init_card(dev);
if (dev->mem_start)
printk("3c503 found, memory at %#6x, IRQ %d\n",
dev->mem_start, dev->irq);
else
printk(" 3c503 found, no shared memory, IRQ %d\n", dev->irq);
if (ei_debug > 2)
printk(version);
return ioaddr;
}
/* This is called whenever we have a unrecoverable failure:
transmit timeout
Bad ring buffer packet header
*/
static void
el2_reset_8390(struct device *dev)
{
if (ei_debug > 1) printk("3c503: Resetting the board...");
outb_p(ECNTRL_RESET|ECNTRL_THIN, E33G_CNTRL);
ei_status.txing = 0;
outb_p(ei_status.thin_bit, E33G_CNTRL);
el2_init_card(dev);
if (ei_debug > 1) printk("done\n");
}
/* Initialize the 3c503 GA registers after a reset. */
static void
el2_init_card(struct device *dev)
{
/* Unmap the station PROM and select the DIX or BNC connector. */
outb_p(ei_status.thin_bit, E33G_CNTRL);
/* Set ASIC copy of rx's first and last+1 buffer pages */
/* These must be the same as in the 8390. */
outb(ei_status.rx_start_page, E33G_STARTPG);
outb(ei_status.stop_page, E33G_STOPPG);
/* Point the vector pointer registers somewhere ?harmless?. */
outb(0xff, E33G_VP2); /* Point at the ROM restart location 0xffff0 */
outb(0xff, E33G_VP1);
outb(0x00, E33G_VP0);
/* Turn off all interrupts until we're opened. */
outb_p(0x00, dev->base_addr + EN0_IMR);
outb_p(EGACFR_IRQOFF, E33G_GACFR);
/* Set the interrupt line. */
outb_p((0x04 << (dev->irq == 9 ? 2 : dev->irq)), E33G_IDCFR);
outb_p(8, E33G_DRQCNT); /* Set burst size to 8 */
outb_p(0x20, E33G_DMAAH); /* Put a valid addr in the GA DMA */
outb_p(0x00, E33G_DMAAL);
return; /* We always succeed */
}
/* Either use the shared memory (if enabled on the board) or put the packet
out through the ASIC FIFO. The latter is probably much slower. */
static void
el2_block_output(struct device *dev, int count,
const unsigned char *buf, const start_page)
{
int i; /* Buffer index */
int boguscount = 0; /* timeout counter */
if (dev->mem_start) { /* Shared memory transfer */
void *dest_addr = (void *)(dev->mem_start +
((start_page - ei_status.tx_start_page) << 8));
outb(EGACFR_NORM, E33G_GACFR); /* Enable RAM */
memcpy(dest_addr, buf, count);
if (ei_debug > 2 && memcmp(dest_addr, buf, count))
printk("3c503: send_packet() bad memory copy @ %#5x.\n",
dest_addr);
else if (ei_debug > 4)
printk("3c503: send_packet() good memory copy @ %#5x.\n",
dest_addr);
return;
}
/* Set up then start the internal memory transfer to Tx Start Page */
outb(0x00, E33G_DMAAL);
outb(start_page, E33G_DMAAH);
outb(ei_status.thin_bit | ECNTRL_OUTPUT | ECNTRL_START, E33G_CNTRL);
/* This is the byte copy loop: it should probably be tuned for
for speed once everything is working. I think it is possible
to output 8 bytes between each check of the status bit. */
for(i = 0; i < count; i++) {
if (count % 8 == 7)
while ((inb(E33G_STATUS) & ESTAT_DPRDY) == 0)
if (++boguscount > 32) {
printk(EI_NAME": fifo blocked in el2_block_output.\n");
return;
}
outb(buf[i], E33G_FIFOH);
}
outb(ei_status.thin_bit, E33G_CNTRL);
return;
}
/* Returns the new ring pointer. */
static int
el2_block_input(struct device *dev, int count, char *buf, int ring_offset)
{
int boguscount = 0;
int end_of_ring = dev->rmem_end;
ring_offset -= (EL2SM_START_PG<<8);
/* Maybe enable shared memory just be to be safe... nahh.*/
if (dev->mem_start) { /* Use the shared memory. */
if (dev->mem_start + ring_offset + count > end_of_ring) {
/* We must wrap the input move. */
int semi_count = end_of_ring - (dev->mem_start + ring_offset);
if (ei_debug > 4)
printk("3c503: block_input() @ %#5x+%x=%5x.\n",
dev->mem_start, ring_offset,
(char *)dev->mem_start + ring_offset);
memcpy(buf, (char *)dev->mem_start + ring_offset, semi_count);
count -= semi_count;
memcpy(buf + semi_count, (char *)dev->rmem_start, count);
return dev->rmem_start + count;
}
if (ei_debug > 4)
printk("3c503: block_input() @ %#5x+%x=%5x.\n",
dev->mem_start, ring_offset,
(char *)dev->mem_start + ring_offset);
memcpy(buf, (char *)dev->mem_start + ring_offset, count);
return ring_offset + count;
} else { /* No shared memory, use the fifo. */
int i;
outb(ring_offset & 0xff, E33G_DMAAL);
outb((ring_offset >> 8) & 0xff, E33G_DMAAH);
outb(ei_status.thin_bit | ECNTRL_INPUT | ECNTRL_START, E33G_CNTRL);
/* This is the byte copy loop: it should probably be tuned for
for speed once everything is working. */
for(i = 0; i < count; i++) {
if (count % 8 == 7)
while ((inb(E33G_STATUS) & ESTAT_DPRDY) == 0)
if (++boguscount > 32) {
printk(EI_NAME": fifo blocked in el2_block_input().\n");
return 0;
}
buf[i] = inb(E33G_FIFOH);
}
outb(ei_status.thin_bit, E33G_CNTRL);
ring_offset += count;
if (ring_offset >= end_of_ring)
ring_offset = dev->rmem_start + ring_offset - end_of_ring;
return ring_offset;
}
}
/*
* Local variables:
* compile-command: "gcc -DKERNEL -Wall -O6 -fomit-frame-pointer -I/usr/src/linux/net/tcp -c 3c503.c"
* version-control: t
* kept-new-versions: 5
* End:
*/

View File

@@ -0,0 +1,59 @@
/* Definitions for the 3Com 3c503 Etherlink 2. */
/* This file is part of Donald Becker's 8390 drivers.
This file is distributed under the Linux GPL.
Some of these names and comments are from the Crynwr packet drivers. */
#define EL2H (dev->base_addr + 0x400)
#define EL2L (dev->base_addr)
/* Shared memory management parameters */
#define EL2SM_START_PG (0x20) /* First page of TX buffer */
#define EL2SM_STOP_PG (0x40) /* Last page +1 of RX ring */
/* 3Com 3c503 ASIC registers */
#define E33G_STARTPG (EL2H+0) /* Start page, must match EN0_STARTPG */
#define E33G_STOPPG (EL2H+1) /* Stop page, must match EN0_STOPPG */
#define E33G_DRQCNT (EL2H+2) /* DMA burst count */
#define E33G_IOBASE (EL2H+3) /* Read of I/O base jumpers. */
/* (non-useful, but it also appears at the end of EPROM space) */
#define E33G_ROMBASE (EL2H+4) /* Read of memory base jumpers. */
#define E33G_GACFR (EL2H+5) /* Config/setup bits for the ASIC GA */
#define E33G_CNTRL (EL2H+6) /* Board's main control register */
#define E33G_STATUS (EL2H+7) /* Status on completions. */
#define E33G_IDCFR (EL2H+8) /* Interrupt/DMA config register */
/* (Which IRQ to assert, DMA chan to use) */
#define E33G_DMAAH (EL2H+9) /* High byte of DMA address reg */
#define E33G_DMAAL (EL2H+10) /* Low byte of DMA address reg */
/* "Vector pointer" - if this address matches a read, the EPROM (rather than
shared RAM) is mapped into memory space. */
#define E33G_VP2 (EL2H+11)
#define E33G_VP1 (EL2H+12)
#define E33G_VP0 (EL2H+13)
#define E33G_FIFOH (EL2H+14) /* FIFO for programmed I/O moves */
#define E33G_FIFOL (EL2H+15) /* ... low byte of above. */
/* Bits in E33G_CNTRL register: */
#define ECNTRL_RESET (0x01) /* Software reset of the ASIC and 8390 */
#define ECNTRL_THIN (0x02) /* Onboard thin-net xcvr enable */
#define ECNTRL_SAPROM (0x04) /* Map the station address prom */
#define ECNTRL_DBLBFR (0x20) /* FIFO configuration bit */
#define ECNTRL_OUTPUT (0x40) /* PC-to-3C503 direction if 1 */
#define ECNTRL_INPUT (0x00) /* 3C503-to-PC direction if 0 */
#define ECNTRL_START (0x80) /* Start the DMA logic */
/* Bits in E33G_STATUS register: */
#define ESTAT_DPRDY (0x80) /* Data port (of FIFO) ready */
#define ESTAT_UFLW (0x40) /* Tried to read FIFO when it was empty */
#define ESTAT_OFLW (0x20) /* Tried to write FIFO when it was full */
#define ESTAT_DTC (0x10) /* Terminal Count from PC bus DMA logic */
#define ESTAT_DIP (0x08) /* DMA In Progress */
/* Bits in E33G_GACFR register: */
#define EGACFR_NORM (0x49) /* Enable 8K shared mem, no DMA TC int */
#define EGACFR_IRQOFF (0xc9) /* Above, and disable 8390 IRQ line */
/* End of 3C503 parameter definitions */

712
net/tcpip/newether/8390.c Normal file
View File

@@ -0,0 +1,712 @@
/* 8390.c: A general NS8390 ethernet driver core for linux. */
/*
Written 1992,1993 by Donald Becker. This is alpha test code.
This is a extension to the Linux operating system, and is covered by
same Gnu Public License that covers that work.
This driver should work with many 8390-based ethernet adaptors.
The Author may be reached as becker@super.org or
C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
*/
static char *version =
"8390.c:v0.27 1/27/93 Donald Becker (becker@super.org)\n";
#include <linux/config.h>
#if !defined(EL2) && !defined(NE2000) && !defined(WD80x3) && !defined(HPLAN)
/* They don't know what they want -- give it all to them! */
#define EL2
#define NE2000
#define WD80x3
#define HPLAN
#endif
/*
Braindamage remaining:
Ethernet devices should use a chr_drv device interface, with ioctl()s to
configure the card, bring the interface up or down, allow access to
statistics, and maybe read() and write() access to raw packets.
This won't be done until after Linux 1.00.
This driver should support multiple, diverse boards simultaneousely.
This won't be done until after Linux 1.00.
Sources:
The National Semiconductor LAN Databook, and 3Com databooks, both companies
provided information readily. The NE* info came from the Crynwr packet
driver, and figuring out that the those boards are similar to the NatSemi
evaluation board described in AN-729. Thanks NS, no thanks to Novell/Eagle.
Cabletron provided only info I had already gotten from other sources -- hiss.
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/tty.h>
#include <linux/types.h>
#include <linux/ptrace.h>
#include <linux/string.h>
#include <asm/system.h>
#include <asm/segment.h>
#include <asm/io.h>
#include <errno.h>
#include <linux/fcntl.h>
#include <netinet/in.h>
#include "dev.h"
#include "eth.h"
#include "timer.h"
#include "ip.h"
#include "tcp.h"
#include "sock.h"
#include "arp.h"
#include "8390.h"
#define ei_reset_8390 (ei_status.reset_8390)
#define ei_block_output (ei_status.block_output)
#define ei_block_input (ei_status.block_input)
#define EN_CMD (e8390_base)
#define E8390_BASE (e8390_base)
/* use 0 for production, 1 for verification, >2 for debug */
#ifdef EI_DEBUG
int ei_debug = EI_DEBUG;
#else
int ei_debug = 2;
#endif
static int e8390_base;
static struct device *eifdev; /* For single-board consistency checking. */
extern int etherlink2;
struct ei_device ei_status = { EI_NAME, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
/* The statistics, perhaps these should be in the above structure. */
static int tx_packets = 0;
static int rx_packets = 0;
static int tx_errors = 0;
static int soft_rx_errors = 0;
static int soft_rx_err_bits = 0;
static int missed_packets = 0;
/* Index to functions. */
/* Put in the device structure. */
static int ei_open(struct device *dev);
static void ei_send_packet(struct sk_buff *skb, struct device *dev);
/* Dispatch from interrupts. */
static void ei_interrupt(int reg_ptr);
static void ei_tx_intr(struct device *dev);
static void ei_receive(struct device *dev);
static void ei_rx_overrun(struct device *dev);
/* Routines generic to NS8390-based boards. */
void NS8390_init(struct device *dev, int startp);
static void NS8390_trigger_send(struct device *dev, unsigned int length,
int start_page);
extern int el2autoprobe(int ioaddr, struct device *dev);
extern int el2probe(int ioaddr, struct device *dev);
extern int neprobe(int ioaddr, struct device *dev);
extern int wdprobe(int ioaddr, struct device *dev);
extern int hpprobe(int ioaddr, struct device *dev);
struct sigaction ei_sigaction = { ei_interrupt, 0, 0, NULL, };
/* Open/initialize the board. This routine goes all-out, setting everything
up anew at each open, even though many of these registers should only
need to be set once at boot.
*/
static int
ei_open(struct device *dev)
{
if ( ! ei_status.exists) {
printk(EI_NAME ": Opening a non-existent physical device\n");
return 1; /* ENXIO would be more accurate. */
}
NS8390_init(dev, 1);
ei_status.txing = 0;
ei_status.in_interrupt = 0;
ei_status.open = 1;
return 0;
}
static int
ei_start_xmit(struct sk_buff *skb, struct device *dev)
{
if ( ! ei_status.exists)
return 0; /* We should be able to do ENODEV, but nooo. */
if (ei_status.txing) { /* Do timeouts, just like the 8003 driver. */
int txsr = inb(E8390_BASE+EN0_TSR);
int tickssofar = jiffies - dev->trans_start;
if (tickssofar < 5 || (tickssofar < 15 && ! (txsr & ENTSR_PTX))) {
return 1;
}
printk(EI_NAME": transmit timed out, TX status %#2x, ISR %#2x.\n",
txsr, inb(E8390_BASE+EN0_ISR));
/* It's possible to check for an IRQ conflict here.
I may have to do that someday. */
if ((txsr & ~0x02) == ENTSR_PTX) /* Strip an undefined bit. */
printk(EI_NAME": Possible IRQ conflict?\n");
else
printk(EI_NAME": Possible network cable problem?\n");
/* It futile, but try to restart it anyway. */
ei_reset_8390(dev);
NS8390_init(dev, 1);
}
/* This is new: it means some higher layer thinks we've missed an
tx-done interrupt. Caution: dev_tint() handles the cli()/sti()
itself. */
if (skb == NULL) {
/* Alternative is ei_tx_intr(dev); */
ei_status.txing = 1;
if (dev_tint(NULL, dev) == 0)
ei_status.txing = 0;
return 0;
}
/* Fill in the ethernet header. */
if (!skb->arp && dev->rebuild_header(skb+1, dev)) {
skb->dev = dev;
arp_queue (skb);
return 0;
}
dev->trans_start = jiffies;
cli();
ei_status.txing = 1;
#ifdef PINGPONG
ei_tx_intr(dev);
#endif
ei_send_packet(skb, dev);
sti();
if (skb->free)
#ifdef notdef /* 0.98.5 and beyond use kfree_skb(). */
free_skb (skb, FREE_WRITE);
#else
kfree_skb (skb, FREE_WRITE);
#endif
return 0;
}
/* The typical workload of the driver:
Handle the ether interface interrupts. */
static void
ei_interrupt(int reg_ptr)
{
int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2);
struct device *dev;
int interrupts, boguscount = 0;
/* We do the same thing as the 8013 driver, but this is mostly bogus. */
for (dev = dev_base; dev != NULL; dev = dev->next) {
if (dev->irq == irq) break;
}
ei_status.in_interrupt++;
sti(); /* Allow other interrupts. */
#ifdef notneeded
/* If we a getting a reset-complete interrupt the 8390 might not be
mapped in for the 3c503. */
if (etherlink2)
outb_p(ei_status.thin_bit, E33G_CNTRL),
outb_p(0x00, E33G_STATUS);
#endif
/* Change to page 0 and read the intr status reg. */
outb_p(E8390_NODMA+E8390_PAGE0, EN_CMD);
if (ei_debug > 3)
printk(EI_NAME": interrupt(isr=%#2.2x).\n",
inb_p(E8390_BASE + EN0_ISR));
if (ei_status.in_interrupt > 1)
printk(EI_NAME ": Reentering the interrupt driver!\n");
if (dev == NULL) {
printk (EI_NAME ": irq %d for unknown device\n", irq);
ei_status.in_interrupt--;
return;
} else if (ei_debug > 0 && eifdev != dev) {
printk (EI_NAME": device mismatch on irq %d.\n", irq);
dev = eifdev;
}
/* !!Assumption!! -- we stay in page 0. Don't break this. */
while ((interrupts = inb_p(E8390_BASE + EN0_ISR)) != 0
&& ++boguscount < 20) {
/* The reset interrupt is the most important... */
if (interrupts & ENISR_RDC) {
outb_p(ENISR_RDC, E8390_BASE + EN0_ISR); /* Ack intr. */
}
if (interrupts & ENISR_OVER) {
ei_status.overruns++;
ei_rx_overrun(dev);
} else if (interrupts & (ENISR_RX+ENISR_RX_ERR)) {
/* Got a good (?) packet. */
ei_receive(dev);
}
/* Push the next to-transmit packet through. */
if (interrupts & ENISR_TX) {
ei_tx_intr(dev);
} else if (interrupts & ENISR_COUNTERS) {
/* Gotta read the counter to clear the irq, even if we
don't care about their values. */
inb_p(E8390_BASE + EN0_COUNTER0);
inb_p(E8390_BASE + EN0_COUNTER1);
missed_packets += inb_p(E8390_BASE + EN0_COUNTER2);
outb_p(ENISR_COUNTERS, E8390_BASE + EN0_ISR); /* Ack intr. */
outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START, EN_CMD);
}
/* Ignore the transmit errs and reset intr for now. */
if (interrupts & ENISR_TX_ERR) {
outb_p(ENISR_TX_ERR, E8390_BASE + EN0_ISR); /* Ack intr. */
}
outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START, EN_CMD);
}
if (interrupts && ei_debug) {
printk(EI_NAME ": unknown interrupt %#2x\n", interrupts);
outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, EN_CMD);
outb_p(0xff, E8390_BASE + EN0_ISR); /* Ack. all intrs. */
}
ei_status.in_interrupt--;
return;
}
#ifdef PINGPONG
static int lasttx = 0;
#endif
/* This is stuffed into the dev struct to be called by dev.c:dev_tint().
Evenually this should be replaced by the block_output() routines. */
static void
ei_send_packet(struct sk_buff *skb, struct device *dev)
{
int length = skb->len;
int send_length = ETHER_MIN_LEN < length ? length : ETHER_MIN_LEN;
if (length <= 0)
return;
#ifdef PINGPONG
if (ei_status.tx1 == 0) { /* First buffer empty */
ei_block_output(dev, length, (void*)(skb+1),
ei_status.tx_start_page);
ei_status.tx1 = send_length;
} else if (ei_status.tx2 == 0) { /* Second buffer empty */
ei_block_output(dev, length, (void*)(skb+1),
ei_status.tx_start_page+6);
ei_status.tx2 = send_length;
} else {
printk("%s: Internal error, no transmit buffer space tx1=%d tx2=%d lasttx=%d.\n",
ei_status.name, ei_status.tx1, ei_status.tx2, lasttx);
}
ei_status.txqueue++;
/* The following should be merged with ei_tx_intr(). */
if (lasttx = 0) {
if (ei_status.tx1 > 0) {
NS8390_trigger_send(dev, ei_status.tx1,
ei_status.tx_start_page + 6),
ei_status.tx1 = -1,
lasttx = 1;
} else if (ei_status.tx2 > 0) {
NS8390_trigger_send(dev, ei_status.tx2,
ei_status.tx_start_page + 6),
ei_status.tx2 = -1,
lasttx = 2;
}
}
#else
ei_block_output(dev, length, (void*)(skb+1), ei_status.tx_start_page);
NS8390_trigger_send(dev, send_length, ei_status.tx_start_page);
#endif
return;
}
/* We have finished a transmit: check for errors and then trigger the next
packet to be sent. */
static void
ei_tx_intr(struct device *dev)
{
int status = inb(E8390_BASE + EN0_TSR);
outb_p(ENISR_TX, E8390_BASE + EN0_ISR); /* Ack intr. */
if ((status & ENTSR_PTX) == 0)
tx_errors++;
else
tx_packets++;
#ifdef PINGPONG
{
ei_status.txqueue--;
if (ei_status.tx1 < 0) {
if (lasttx != 1)
printk("%s: bogus last_tx_buffer %d, tx1=%d.\n",
ei_status.name, lasttx, ei_status.tx1);
ei_status.tx1 = 0;
lasttx = 0;
if (ei_status.tx2 > 0) {
NS8390_trigger_send(dev, ei_status.tx2,
ei_status.tx_start_page + 6),
ei_status.tx2 = -1,
lasttx = 2;
}
} else if (ei_status.tx2 < 0) {
if (lasttx != 2)
printk("%s: bogus last_tx_buffer %d, tx2=%d.\n",
ei_status.name, lasttx, ei_status.tx2);
ei_status.tx2 = 0;
lasttx = 0;
if (ei_status.tx1 > 0) {
NS8390_trigger_send(dev, ei_status.tx1,
ei_status.tx_start_page),
ei_status.tx1 = -1;
lasttx = 1;
}
} /*else
printk(EI_NAME": unexpected TX interrupt.\n");*/
while ((ei_status.tx1 == 0) || (ei_status.tx2 == 0))
if (dev_tint(NULL, dev) == 0) {
ei_status.txing = 0;
return;
} else if (lasttx == 0) {
if (ei_status.tx1 == 0 || ei_status.tx2 != 0)
printk(EI_NAME": Unexpected tx buffer busy tx1=%d tx2=%d.\n",
ei_status.tx1, ei_status.tx2);
NS8390_trigger_send(dev, ei_status.tx1,
ei_status.tx_start_page),
ei_status.tx1 = -1;
lasttx = 1;
}
}
#else
if (dev_tint(NULL, dev) == 0)
ei_status.txing = 0;
#endif
}
/* We have a good packet(s), get it/them out of the buffers. */
static void
ei_receive(struct device *dev)
{
int rxing_page, this_frame, next_frame, current_offset;
int boguscount = 0;
struct e8390_pkt_hdr rx_frame;
int num_rx_pages = ei_status.stop_page-ei_status.rx_start_page;
while (++boguscount < 10) {
int size;
cli();
outb_p(E8390_NODMA+E8390_PAGE1, EN_CMD); /* Get the rec. page. */
rxing_page = inb_p(E8390_BASE+EN1_CURPAG);/* (Incoming packet pointer).*/
outb_p(E8390_NODMA+E8390_PAGE0, EN_CMD);
sti();
/* Remove one frame from the ring. Boundary is alway a page behind. */
this_frame = inb_p(E8390_BASE + EN0_BOUNDARY) + 1;
if (this_frame >= ei_status.stop_page)
this_frame = ei_status.rx_start_page;
/* Someday we'll omit the previous step, iff we never get this message.*/
if (ei_debug > 0 && this_frame != ei_status.current_page)
printk(EI_NAME": mismatched read page pointers %2x vs %2x.\n",
this_frame, ei_status.current_page);
if (this_frame == rxing_page) /* Read all the frames? */
break; /* Done for now */
current_offset = this_frame << 8;
ei_block_input(dev, sizeof(rx_frame), (void *)&rx_frame,
current_offset);
size = rx_frame.count - sizeof(rx_frame);
next_frame = this_frame + 1 + ((size+4)>>8);
/* Check for bogosity warned by 3c503 book: the status byte is never
written. This happened a lot during testing! This code should be
cleaned up someday, and the printk()s should be PRINTK()s. */
if ( rx_frame.next != next_frame
&& rx_frame.next != next_frame + 1
&& rx_frame.next != next_frame - num_rx_pages
&& rx_frame.next != next_frame + 1 - num_rx_pages) {
#ifndef EI_DEBUG
ei_status.current_page = rxing_page;
outb(ei_status.current_page-1, E8390_BASE+EN0_BOUNDARY);
continue;
#else
static int last_rx_bogosity = -1;
printk(EI_NAME": bogus packet header, status=%#2x nxpg=%#2x sz=%#x (at %#4x)\n",
rx_frame.status, rx_frame.next, rx_frame.count, current_offset);
if (rx_packets != last_rx_bogosity) {
/* Maybe we can avoid resetting the chip... empty the packet ring. */
ei_status.current_page = rxing_page;
printk(EI_NAME": setting next frame to %#2x (nxt=%#2x, rx_frm.nx=%#2x rx_frm.stat=%#2x).\n",
ei_status.current_page, next_frame,
rx_frame.next, rx_frame.status);
last_rx_bogosity = rx_packets;
outb(ei_status.current_page-1, E8390_BASE+EN0_BOUNDARY);
continue;
} else {
/* Oh no Mr Bill! Last ditch error recovery. */
printk(EI_NAME": multiple sequential lossage, resetting at packet #%d.",
rx_packets);
sti();
ei_reset_8390(dev);
NS8390_init(dev, 1);
printk("restarting.\n");
return;
}
#endif /* EI8390_NOCHECK */
}
if ((size < 32 || size > 1535) && ei_debug)
printk(EI_NAME": bogus big packet, status=%#2x nxpg=%#2x size=%#x\n",
rx_frame.status, rx_frame.next, rx_frame.count);
if ((rx_frame.status & 0x0F) == ENRSR_RXOK) {
int sksize = sizeof(struct sk_buff) + size;
struct sk_buff *skb;
skb = kmalloc(sksize, GFP_ATOMIC);
if (skb != NULL) {
skb->lock = 0;
skb->mem_len = sksize;
skb->mem_addr = skb;
/* 'skb+1' points to the start of sk_buff data area. */
ei_block_input(dev, size, (void *)(skb+1),
current_offset + sizeof(rx_frame));
if(dev_rint((void *)skb, size, IN_SKBUFF, dev)) {
printk(EI_NAME": receive buffers full.\n");
break;
}
} else if (ei_debug) {
printk(EI_NAME": Couldn't allocate a sk_buff of size %d.\n", sksize);
break;
}
rx_packets++;
} else {
if (ei_debug)
printk(EI_NAME": bogus packet, status=%#2x nxpg=%#2x size=%d\n",
rx_frame.status, rx_frame.next, rx_frame.count);
soft_rx_err_bits |= rx_frame.status,
soft_rx_errors++;
}
next_frame = rx_frame.next;
/* This should never happen, it's here for debugging. */
if (next_frame >= ei_status.stop_page) {
printk(EI_NAME": next frame inconsistency, %#2x..", next_frame);
next_frame = ei_status.rx_start_page;
}
ei_status.current_page += 1 + ((size+4)>>8);
#ifdef notdef
if (ei_status.current_page > ei_status.stop_page)
ei_status.current_page -= ei_status.stop_page-ei_status.rx_start_page;
if (ei_status.current_page != next_frame) {
printk(EI_NAME": inconsistency in next_frame %#2x!=%#2x.\n",
this_frame, next_frame);
/* Assume this packet frame is scrogged by the NIC, use magic to
skip to the next frame. Actually we should stop and restart.*/
next_frame = size > 1535 ? rx_frame.status : rx_frame.next;
ei_status.current_page = next_frame;
break;
}
#endif
ei_status.current_page = next_frame;
outb(next_frame-1, E8390_BASE+EN0_BOUNDARY);
}
/* Tell the upper levels we're done. */
while (dev_rint(NULL, 0, 0, dev) == 1
&& ++boguscount < 20)
;
/* Bug alert! Reset ENISR_OVER to avoid spurious overruns! */
outb_p(ENISR_RX+ENISR_RX_ERR+ENISR_OVER, E8390_BASE+EN0_ISR); /* Ack intr. */
return;
}
/* We have a receiver overrun: we have to kick the 8390 to get it started
again. Overruns are detected on a per-256byte-page basis. */
static void
ei_rx_overrun(struct device *dev)
{
int reset_start_time = jiffies;
/* We should already be stopped and in page0. Remove after testing. */
outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, EN_CMD);
if (ei_debug)
printk(EI_NAME ": Receiver overrun.\n");
/* The we.c driver does dummy = inb_p( RBCR[01] ); at this point.
It might mean something -- magic to speed up a reset? A 8390 bug?*/
/* Wait for reset in case the NIC is doing a tx or rx. This could take up to
1.5msec, but we have no way of timing something in that range. The 'jiffies'
are just a sanity check. */
while ((inb_p(E8390_BASE+EN0_ISR) & ENISR_RESET) == 0)
if (jiffies - reset_start_time > 1) {
printk(EI_NAME": reset did not complete at ei_rx_overrun.\n");
NS8390_init(dev, 1);
return;
};
/* Remove packets right away. */
ei_debug += 5;
ei_receive(dev);
ei_debug -= 5;
outb_p(0xff, E8390_BASE+EN0_ISR);
/* Generic 8390 insns to start up again, same as in open_8390(). */
outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START, EN_CMD);
outb_p(E8390_TXCONFIG, E8390_BASE + EN0_TXCR); /* xmit on. */
#ifdef notneeded
outb_p(E8390_RXCONFIG, E8390_BASE + EN0_RXCR); /* rx on, */
#endif
}
int
ethif_init(struct device *dev)
{
int i;
eifdev = dev; /* Store for debugging. */
if (ei_debug > 3)
printk(version);
if (1
#ifdef WD80x3
&& ! wdprobe(dev->base_addr, dev)
#endif
#ifdef EL2
&& ! el2autoprobe(dev->base_addr, dev)
#endif
#ifdef NE2000
&& ! neprobe(dev->base_addr, dev)
#endif
#ifdef HPLAN
&& ! hpprobe(dev->base_addr, dev)
#endif
&& 1 ) {
dev->open = &ei_open;
printk("No ethernet device found.\n");
ei_status.exists = 0;
return 1; /* ENODEV or EAGAIN would be more accurate. */
}
e8390_base = dev->base_addr;
/* Initialize the rest of the device structure. Many of these could
be in Space.c. */
for (i = 0; i < DEV_NUMBUFFS; i++)
dev->buffs[i] = NULL;
ei_status.exists = 1;
dev->hard_header = eth_hard_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->send_packet = &ei_send_packet;
dev->open = &ei_open;
dev->hard_start_xmit = &ei_start_xmit;
dev->type = ETHER_TYPE;
dev->hard_header_len = sizeof (struct enet_header);
dev->mtu = 1500; /* eth_mtu */
dev->addr_len = ETHER_ADDR_LEN;
for (i = 0; i < dev->addr_len; i++) {
dev->broadcast[i]=0xff;
}
return 0;
}
/* This page of functions should be 8390 generic */
/* Follow National Semi's recommendations for initializing the "NIC". */
void NS8390_init(struct device *dev, int startp)
{
int i;
int endcfg = ei_status.word16 ? (0x48 | ENDCFG_WTS) : 0x48;
int e8390_base = dev->base_addr;
/* Follow National Semi's recommendations for initing the DP83902. */
outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base); /* 0x21 */
outb_p(endcfg, e8390_base + EN0_DCFG); /* 0x48 or 0x49 */
/* Clear the remote byte count registers. */
outb_p(0x00, e8390_base + EN0_RCNTLO);
outb_p(0x00, e8390_base + EN0_RCNTHI);
/* Set to monitor and loopback mode -- this is vital!. */
outb_p(E8390_RXOFF, e8390_base + EN0_RXCR); /* 0x20 */
outb_p(E8390_TXOFF, e8390_base + EN0_TXCR); /* 0x02 */
/* Set the transmit page and receive ring. */
outb_p(ei_status.tx_start_page, e8390_base + EN0_TPSR);
ei_status.tx1 = ei_status.tx2 = 0;
outb_p(ei_status.rx_start_page, e8390_base + EN0_STARTPG);
outb_p(ei_status.stop_page-1, e8390_base + EN0_BOUNDARY); /* 3c503 says 0x3f,NS0x26*/
ei_status.current_page = ei_status.rx_start_page; /* assert boundary+1 */
outb_p(ei_status.stop_page, e8390_base + EN0_STOPPG);
/* Clear the pending interrupts and mask. */
outb_p(0xFF, e8390_base + EN0_ISR);
outb_p(0x00, e8390_base + EN0_IMR);
/* Copy the station address into the DS8390 registers,
and set the multicast hash bitmap to receive all multicasts. */
cli();
outb_p(E8390_NODMA + E8390_PAGE1 + E8390_STOP, e8390_base); /* 0x61 */
for(i = 0; i < 6; i++) {
outb_p(dev->dev_addr[i], e8390_base + EN1_PHYS + i);
}
for(i = 0; i < 8; i++)
outb_p(0xff, e8390_base + EN1_MULT + i);
outb_p(ei_status.rx_start_page, e8390_base + EN1_CURPAG);
outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base);
sti();
if (startp) {
outb_p(0xff, e8390_base + EN0_ISR);
outb_p(ENISR_ALL, e8390_base + EN0_IMR);
outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base);
outb_p(E8390_TXCONFIG, e8390_base + EN0_TXCR); /* xmit on. */
/* 3c503 TechMan says rxconfig only after the NIC is started. */
outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR); /* rx on, */
}
return;
}
/* Trigger a transmit start, assuming the length is valid. */
static void NS8390_trigger_send(struct device *dev, unsigned int length,
int start_page)
{
int e8390_base = dev->base_addr;
outb_p(E8390_NODMA+E8390_PAGE0, e8390_base);
if (inb_p(EN_CMD) & E8390_TRANS) {
printk(EI_NAME": trigger_send() called with the transmitter busy.\n");
return;
}
outb_p(length & 0xff, e8390_base + EN0_TCNTLO);
outb_p(length >> 8, e8390_base + EN0_TCNTHI);
outb_p(start_page, e8390_base + EN0_TPSR);
outb_p(E8390_NODMA+E8390_TRANS+E8390_START, e8390_base);
outb_p(ENISR_RDC, e8390_base + EN0_ISR);
return;
}
/*
* Local variables:
* compile-command: "gcc -DKERNEL -Wall -O6 -fomit-frame-pointer -DPINGPONG -I/usr/src/linux/net/tcp -c 8390.c"
* version-control: t
* kept-new-versions: 5
* End:
*/

129
net/tcpip/newether/8390.h Normal file
View File

@@ -0,0 +1,129 @@
/* Generic NS8390 register definitions. */
/* This file is part of Donald Becker's 8390 drivers.
This file is distributed under the Linux GPL.
Some of these names and comments are from the Crynwr packet drivers. */
#ifndef e8390_h
#define e8390_h
#ifndef EI_NAME
#define EI_NAME "eth_if"
#endif
/*#define PINGPONG*/
#ifdef PINGPONG
#define TX_PAGES 12
#else
#define TX_PAGES 6
#endif
#define ETHER_ADDR_LEN 6
/* From auto_irq.c */
extern void autoirq_setup(int waittime);
extern int autoirq_report(int waittime);
/* Most of these entries should be in 'struct device' (or most
things in there should be here!) */
struct ei_device { /* These should be stored per-board */
char *name;
int exists:1; /* perhaps in dev->private. */
int open:1;
int word16:1; /* We have the 16-bit (vs 8-bit) version of the card. */
void (*reset_8390)(struct device *);
void (*block_output)(struct device *, int, const unsigned char *, int);
int (*block_input)(struct device *, int, char *, int);
unsigned char tx_start_page, rx_start_page, stop_page;
unsigned char current_page; /* Read pointer in buffer */
unsigned char thin_bit; /* Value to write to the 3c503 E33G_CNTRL */
unsigned char txing; /* Transmit Active, don't confuse the upper levels. */
unsigned char txqueue; /* Tx Packet buffer queue length. */
unsigned char in_interrupt;
short tx1, tx2; /* Packet lengths for ping-pong tx. */
int overruns; /* Rx overruns. */
};
/* Some generic ethernet register configurations. */
#define E8390_TX_IRQ_MASK 0xa /* For register EN0_ISR */
#define E8390_RX_IRQ_MASK 0x5
#define E8390_RXCONFIG 0x4 /* EN0_RXCR: broadcasts, no multicast,errors */
#define E8390_RXOFF 0x20 /* EN0_RXCR: Accept no packets */
#define E8390_TXCONFIG 0x00 /* EN0_TXCR: Normal transmit mode */
#define E8390_TXOFF 0x02 /* EN0_TXCR: Transmitter off */
/* Register accessed at EN_CMD, the 8390 base addr. */
#define E8390_STOP 0x01 /* Stop and reset the chip */
#define E8390_START 0x02 /* Start the chip, clear reset */
#define E8390_TRANS 0x04 /* Transmit a frame */
#define E8390_RREAD 0x08 /* Remote read */
#define E8390_RWRITE 0x10 /* Remote write */
#define E8390_NODMA 0x20 /* Remote DMA */
#define E8390_PAGE0 0x00 /* Select page chip registers */
#define E8390_PAGE1 0x40 /* using the two high-order bits */
#define E8390_PAGE2 0x80 /* Page 3 is invalid. */
/* Page 0 register offsets. */
#define EN0_CLDALO 0x01 /* Low byte of current local dma addr RD */
#define EN0_STARTPG 0x01 /* Starting page of ring bfr WR */
#define EN0_CLDAHI 0x02 /* High byte of current local dma addr RD */
#define EN0_STOPPG 0x02 /* Ending page +1 of ring bfr WR */
#define EN0_BOUNDARY 0x03 /* Boundary page of ring bfr RD WR */
#define EN0_TSR 0x04 /* Transmit status reg RD */
#define EN0_TPSR 0x04 /* Transmit starting page WR */
#define EN0_NCR 0x05 /* Number of collision reg RD */
#define EN0_TCNTLO 0x05 /* Low byte of tx byte count WR */
#define EN0_FIFO 0x06 /* FIFO RD */
#define EN0_TCNTHI 0x06 /* High byte of tx byte count WR */
#define EN0_ISR 0x07 /* Interrupt status reg RD WR */
#define EN0_CRDALO 0x08 /* low byte of current remote dma address RD */
#define EN0_RSARLO 0x08 /* Remote start address reg 0 */
#define EN0_CRDAHI 0x09 /* high byte, current remote dma address RD */
#define EN0_RSARHI 0x09 /* Remote start address reg 1 */
#define EN0_RCNTLO 0x0a /* Remote byte count reg WR */
#define EN0_RCNTHI 0x0b /* Remote byte count reg WR */
#define EN0_RSR 0x0c /* rx status reg RD */
#define EN0_RXCR 0x0c /* RX configuration reg WR */
#define EN0_TXCR 0x0d /* TX configuration reg WR */
#define EN0_COUNTER0 0x0d /* Rcv alignment error counter RD */
#define EN0_DCFG 0x0e /* Data configuration reg WR */
#define EN0_COUNTER1 0x0e /* Rcv CRC error counter RD */
#define EN0_IMR 0x0f /* Interrupt mask reg WR */
#define EN0_COUNTER2 0x0f /* Rcv missed frame error counter RD */
/* Bits in EN0_ISR - Interrupt status register */
#define ENISR_RX 0x01 /* Receiver, no error */
#define ENISR_TX 0x02 /* Transmitter, no error */
#define ENISR_RX_ERR 0x04 /* Receiver, with error */
#define ENISR_TX_ERR 0x08 /* Transmitter, with error */
#define ENISR_OVER 0x10 /* Receiver overwrote the ring */
#define ENISR_COUNTERS 0x20 /* Counters need emptying */
#define ENISR_RDC 0x40 /* remote dma complete */
#define ENISR_RESET 0x80 /* Reset completed */
#define ENISR_ALL 0x3f /* Interrupts we will enable */
/* Bits in EN0_DCFG - Data config register */
#define ENDCFG_WTS 0x01 /* word transfer mode selection */
/* Page 1 register offsets. */
#define EN1_PHYS 0x01 /* This board's physical enet addr RD WR */
#define EN1_CURPAG 0x07 /* Current memory page RD WR */
#define EN1_MULT 0x08 /* Multicast filter mask array (8 bytes) RD WR */
/* Bits in received packet status byte and EN0_RSR*/
#define ENRSR_RXOK 0x01 /* Received a good packet */
#define ENRSR_CRC 0x02 /* CRC error */
#define ENRSR_FAE 0x04 /* frame alignment error */
#define ENRSR_FO 0x08 /* FIFO overrun */
#define ENRSR_MPA 0x10 /* missed pkt */
#define ENRSR_PHY 0x20 /* physical/multicase address */
#define ENRSR_DIS 0x40 /* receiver disable. set in monitor mode */
#define ENRSR_DEF 0x80 /* deferring */
/* Transmitted packet status, EN0_TSR. */
#define ENTSR_PTX 0x01 /* Packet transmitted without error */
/* The per-packet-header format. */
struct e8390_pkt_hdr {
unsigned char status; /* status */
unsigned char next; /* pointer to next packet. */
unsigned short count; /* header + packet lenght in bytes */
};
#endif /* e8390_h */

View File

@@ -0,0 +1,27 @@
# This has the effect of appending lines to the Makefile.
include Makefile
# Add a few files to tcpip.a.
newobjs = 8390.o 3c503.o ne.o wd.o hp.o auto_irq.o
OBJS := $(OBJS) $(newobjs)
tcpip.a: $(newobjs)
# Set the address and IRQ here. The ne.c and 3c503 driver will autoprobe
# if you set the address or IRQ to zero, so we do that by default.
#
# Add -DEI_NAME=eth0 if you want to be exactly compatible with the default
# driver. This will only work if you don't use the distributed 'we' driver!
#
Space.o: Space.c GNUmakefile
$(CC) $(CPPFLAGS) $(CFLAGS) -DEI8390=0 -DEI8390_IRQ=0 -c Space.c -o $@
# Change this to define the set of ethercards your kernel will support.
8390.o: 8390.c GNUmakefile
$(CC) $(CPPFLAGS) $(CFLAGS) -DNE2000 -DWD80x3 -DHPLAN -DEL2 -c 8390.c -o $@
# And set any special compile-time options here.
ne.o: ne.c GNUmakefile
$(CC) $(CPPFLAGS) $(CFLAGS) -UEI_8BIT -c ne.c -o $@
3c503.o: 3c503.c 3c503reg.h GNUmakefile
$(CC) $(CPPFLAGS) $(CFLAGS) -UEI8390_THICK -c 3c503.c -o $@

View File

@@ -0,0 +1,77 @@
Installation Directions:
EMail me (becker@super.org) telling me you've gotten the "experimental
drivers". I need to know how many people have tried, succeeded and
failed before this is released as part of the official Linux.
Use Linux 0.99.2 or later. Make certain you can make a working kernel
_before_ you install the ethercard driver.
Put the all of the files into linux/net/tcp/. You'll need
GNUmakefile 8390.c 8390.h Space.c wd.c ne.c 3c503.c 3c503reg.h and hp.c.
Space.c is the only tricky one -- it overwrites the old Space.c.
Stock versions of Space.c leave the "we" driver enabled and will not work.
Change the GNUmakefile to reflect your configuration. Use the guide at
the end of these instructions.
Make and install your new kernel.
To actually use this driver you must get the TCP/IP package and edit
your /usr/etc/inet/rc.net file to config "eth_if" instead of
"eth0" (the WD8003). (Alternately you can edit the GNUmakefile to use the
"eth0" name.)
If you try to 'config' an interface that doesn't exist your kernel
will report "invalid ioctl()" for anthing that tries to use the card.
Note that the ethercard devices aren't (yet) real '/dev/eth_if' devices --
they only exist in the socket namespace and thus you don't need to
'mknode' them.
________________
Important defines
For Space.c
#define EI8390 0x300 /* The base address of your ethercard. */
#define EI8390_IRQ 5 /* and the interrupt you want to use. */
For 8390.c
#define EI_DEBUG 2 /* Use '0' for no messages. */
#define EL2 /* For the 3c503 driver. */
#define NE2000 /* For the NE1000/NE2000/Ctron driver. */
#define WD80x3 /* For the WD8003/WD8013 driver. */
#define HPLAN /* For the HP27xxx driver. */
For the individual drivers
#undef EI_8BIT /* Define for ne.c iff you have an 8 bit card.*/
#undef EI8390_THICK /* Define for 3c503 AUI/DIX transceiver.*/
EI8390 Define (probably in autoconf.h or config.site.h) this to the base
address of your ethernet card.
EI8390_IRQ Define (probably in autoconf.h or config.site.h) this to the
IRQ line of your ethernet card. Most drivers convert a IRQ2 to an
IRQ9 for you, so don't be surprised.
EI_DEBUG Set to the desired numeric debugging level. Use 3 or
greater when actively debugging a problem, '1' for a
casual interest in what's going on, and '0' for normal
use. (Most of the debugging stuff has been taken out recently,
so this won't have much effect.)
EI_PINGPONG
Not included or broken the alpha version. Define this if you want
ping-pong transmit buffers.
EI_8BIT
If you are using the ne.c driver and have an 8-bit card (NE1000 or
E1xxx Cabletron) you must define this. It's not needed for the other
drivers, and I hope to find a way to clean this up in the future.
EI8390_THICK
Define for this if you are using the 3c503 and use the AUI/DIX
connector rather than the built-in thin-net transceiver.
If you have a Cabletron ethercard you might want to look at ne.c:neprobe()
for info on how to enable more packet buffer space.
ETHERLINK1_IRQ
ETHERLINK1 Define these to the base address and IRQ of a 3c501 (NOT 3c503)
card. Refer to net/tcp/Space.c.

80
net/tcpip/newether/README Normal file
View File

@@ -0,0 +1,80 @@
This is the experimental version of the 8390 ethercard driver.
You should consult the list below for the specific #define for your
ethercard. If you don't have one specific #define the driver will
probe for all supported ethercard types.
Source Header #define to get Supported cards
8390.c 8390.h EI8390 (generic, needed for all)
3c503.c 3c503reg.h EL2 3c503, 3c503/16
ne.c NE2000 NE1000, NE2000, NatSemi, Cabletron
wd.c wd.h WD80x3 WD8003, WD8013, SMC elite
hp.c HPLAN HP LAN adaptors
Notes on each package
3c503.c
o You'll need to #define EI8390_THICK if you are using the AUI port instead
of the thinnet connector. Russ Nelson <nelson@crynwr.com> sent me an
run-time method of selecting between the two, but I haven't put it in yet.
This _may_ generate a spurious error message when transmitting the first
packet, I haven't yet tracked down this bug report.
o If you want to check the shared memory, #define EL2MEMTEST. I don't think
the memory check is worth the effort -- it's missed obvious problems.
o You must jumper the board to use shared memory -- I don't test the
non-shared-memory mode and it's probably broken.
o Thanks to Chance Reschke at USRA <creschke@usra.edu> for providing the
3c503 and anonymous FTP space.
ne.c
o You'll need to #define EI_8BIT if you are using an 8-bit ethercard
such as the NE1000 or Cabletron E10xx. I might someday make a run-time
selection between the NE1000 and NE2000 (right now it screws up the
non-default bus-width) but I don't know how to distinguish the Cabletron
ethercards. I'm hoping to find a general way to identify the board's bus
width, but don't hold your breath.
wd.c
o Thanks to Russ Nelson (nelson@crynwr.com) for loaning me a WD8013.
o The 8013 doesn't work if it's probed by some other driver first.
Make it either first in the probe list or the only driver you compile in.
Maybe I should reset the board before looking at it to fix the probe problem.
o You machine may fail to do a soft reboot if the packet buffer shared memory is
mapped in -- the machine might think its a boot PROM (since it intentionally
shares the same memory space as the optional on-board boot PROM).
hp.c
o This has only been tested with a 27245A, 27247A, and 27250. It doesn't yet
work with the new 27247B!
o Thanks to Chance Reschke at USRA <creschke@usra.edu> for loaning me the
27247A ethercard.
BUGS
The "bogus packet header" is a bug in the 8390. I drop all of
the packets in the ring (usually just one) when this happens.
If you get this more than just occasionally please report it to me.
I don't yet distinguish between the problems with IRQ conflicts and
problems with the ethernet cable not being connected. If you get
a "transmit timed out" message check both! Your ethercard
probably will NOT work without proper termination.
A small number of people report continuous "RX transfer address mismatch"
errors with the NE2000. This is a bug in the 8390, and the reason
most designers use shared memory or design their own packet buffer access
circuitry rather than use what's provided by the 8390. An occasional
"mismatch" message (say, once a week) won't impact performance.
I've fixed most of the spurious "receiver overrun" messages. It
was a bug in the 8390 -- the overrun flag is sometimes set
when the boundary pointer is written. If you still get
isolated overrun errors please send me email.
The 3c501 driver isn't complete. This card is severely brain-damaged
anyway -- you won't notice the performance difference between working
and non-working versions anyway. If this source code is here, it is
only provided for a few people that wanted to write code for their 3c501
cards. Don't send me email about it unless it's a bug fix.

134
net/tcpip/newether/Space.c Normal file
View File

@@ -0,0 +1,134 @@
/* Space.c */
/* Holds initial configuration information for devices. */
#include "dev.h"
#include <linux/stddef.h>
#include <linux/config.h>
#define NEXT_DEV NULL
#ifdef ETHERLINK1
extern int etherlink_init(struct device *);
#ifndef ETHERLINK1_IRQ
#define ETHERLINK1_IRQ 9
#endif
static struct device el_dev = {
"if3c501",
0, 0, 0, 0, /* memory rx_end, rx_start, end, start are autoconfiged. */
ETHERLINK1, ETHERLINK1_IRQ, /* base i/o address, irq. */
0,0,0,0,0,
NEXT_DEV,
etherlink_init, 0, {NULL}, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, {0,}, {0,}, 0
};
#undef NEXT_DEV
#define NEXT_DEV (&el_dev)
#endif /* ETHERLINK1 */
#if defined(EI8390) || defined(EL2) || defined(NE2000) \
|| defined(WD80x3) || defined(HPLAN)
extern int ethif_init(struct device *);
#ifndef EI8390_IRQ
#define EI8390_IRQ 0
#endif
static struct device ei8390_dev = {
#ifdef EI_NAME
EI_NAME,
#else
"eth_if",
#endif
0, 0, 0, 0, /* memory rx_end, rx_start, end, start are autoconfiged. */
EI8390, EI8390_IRQ, 0,0,0,0,0, /* base i/o address, irq, and flags. */
NEXT_DEV,
ethif_init, 0, {NULL}, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, 0, 0, 0, {0,}, {0,}, 0
};
#undef NEXT_DEV
#define NEXT_DEV (&ei8390_dev)
#endif /* The EI8390 drivers. */
#ifdef WD8003
extern int wd8003_init(struct device *);
static struct device wd8003_dev =
{
"eth0",
0xd2000, /* recv memory end. */
0xd0600, /* recv memory start. */
0xd2000, /* memory end. */
0xd0000, /* memory start. */
0x280, /* base i/o address. */
5, /* irq */
0,0,0,0,0, /* flags */
NEXT_DEV,
wd8003_init,
/* wd8003_init should set up the rest. */
0, /* trans start. */
{NULL}, /* buffs */
NULL, /* backlog */
NULL, /* open */
NULL, /* stop */
NULL, /* hard_start_xmit */
NULL, /* hard_header */
NULL, /* add arp */
NULL, /* queue xmit */
NULL, /* rebuild header */
NULL, /* type_trans */
NULL, /* send_packet */
NULL, /* private */
0, /* type. */
0, /* hard_header_len */
0, /* mtu */
{0,}, /* broadcast address */
{0,}, /* device address */
0 /* addr len */
};
#undef NEXT_DEV
#define NEXT_DEV (&wd8003_dev)
#endif /* WD8003 */
extern int loopback_init(struct device *dev);
static struct device loopback_dev =
{
"loopback",
-1, /* recv memory end. */
0x0, /* recv memory start. */
-1, /* memory end. */
0, /* memory start. */
0, /* base i/o address. */
0, /* irq */
0,0,1,0,0, /* flags */
NEXT_DEV, /* next device */
loopback_init,
/* loopback_init should set up the rest. */
0, /* trans start. */
{NULL}, /* buffs */
NULL, /* backlog */
NULL, /* open */
NULL, /* stop */
NULL, /* hard_start_xmit */
NULL, /* hard_header */
NULL, /* add arp */
NULL, /* queue xmit */
NULL, /* rebuild header */
NULL, /* type_trans */
NULL, /* send_packet */
NULL, /* private */
0, /* type. */
0, /* hard_header_len */
0, /* mtu */
{0,}, /* broadcast address */
{0,}, /* device address */
0 /* addr len */
};
#undef NEXT_DEV
#define NEXT_DEV (error no next device &loopback_dev)
struct device *dev_base = &loopback_dev;

View File

@@ -0,0 +1,100 @@
/* auto_irq.c: Auto-configure IRQ lines for linux. */
/*
Written 1993 by Donald Becker. This is alpha test code.
The Author may be reached as becker@super.org or
C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
This code is a general-purpose IRQ line detector for devices with
jumpered IRQ lines. If you can make the device raise an IRQ (and
that IRQ line isn't already being used), these routines will tell
you what IRQ line it's using -- perfect for those oh-so-cool boot-time
device probes!
To use this, first call autoirq_setup(timeout). TIMEOUT is how many
'jiffies' (1/18 sec.) to detect other devices that have active IRQ lines,
and can usually be zero at boot.
Next, set up your device to trigger an interrupt.
Finally call autoirq_report(TIMEOUT) to find out which IRQ line was
most recently active. The TIMEOUT should usually be zero, but may
be set to the number of jiffies to wait for an active IRQ.
The idea of using the setup timeout to filter out bogus IRQs came from
the serial driver.
*/
#ifdef version
static char *version="auto_irq.c:v0.01 1993 Donald Becker (becker@super.org)";
#endif
/*#include <linux/config.h>*/
/*#include <linux/kernel.h>*/
#include <linux/sched.h>
#include <asm/bitops.h>
#include <asm/io.h>
/*#include <asm/system.h>*/
static volatile int irq_number; /* The latest irq number we actually found. */
static volatile int irq_bitmap; /* The irqs we actually found. */
static int irq_handled; /* The irq lines we have a handler on. */
static void autoirq_probe(int irq)
{
irq_number = irq;
set_bit(irq, (void *)&irq_bitmap);
/*irq_bitmap |= 1 << irq;*/
return;
}
struct sigaction autoirq_sigaction = { autoirq_probe, 0, SA_INTERRUPT, NULL};
void autoirq_setup(int waittime)
{
int i, mask;
int timeout = jiffies+waittime;
irq_number = 0;
irq_bitmap = 0;
irq_handled = 0;
for (i = 0; i < 16; i++) {
if (!irqaction(i, &autoirq_sigaction))
set_bit(i, (void *)&irq_handled); /* irq_handled |= 1 << i;*/
}
/* Hang out at least <waittime> jiffies waiting for bogus IRQ hits. */
while (timeout >= jiffies)
;
for (i = 0, mask = 0x01; i < 16; i++, mask <<= 1) {
if (irq_bitmap & irq_handled & mask) {
irq_handled &= ~mask;
printk(" Spurious interrupt on IRQ %d\n", i);
free_irq(i);
}
}
}
int autoirq_report(int waittime)
{
int i;
int timeout = jiffies+waittime;
/* Hang out at least <waittime> jiffies waiting for the IRQ. */
while (timeout >= jiffies)
if (irq_number)
break;
/* Retract the irq handlers that we installed. */
for (i = 0; i < 16; i++) {
if (test_bit(i, (void *)&irq_handled))
free_irq(i);
}
return irq_number;
}
/*
* Local variables:
* compile-command: "gcc -DKERNEL -Wall -O6 -fomit-frame-pointer -I/usr/src/linux/net/tcp -c auto_irq.c"
* version-control: t
* kept-new-versions: 5
* End:
*/

312
net/tcpip/newether/hp.c Normal file
View File

@@ -0,0 +1,312 @@
/* hp.c: A HP LAN ethernet driver for linux. */
/*
Written 1993 by Donald Becker. This is alpha test code.
This is a extension to the Linux operating system, and is covered by
same Gnu Public License that covers that work.
This is a driver for the HP LAN adaptors.
The Author may be reached as becker@super.org or
C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
*/
static char *version = "hp.c:v0.28 1/28/93 Donald Becker (becker@super.org)\n";
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <asm/io.h>
#include <asm/system.h>
#include "dev.h"
#include "8390.h"
/* These should be in <asm/io.h> someday, borrowed from blk_drv/hd.c. */
#define port_read(port,buf,nr) \
__asm__("cld;rep;insw"::"d" (port),"D" (buf),"c" (nr):"cx","di")
#define port_write(port,buf,nr) \
__asm__("cld;rep;outsw"::"d" (port),"S" (buf),"c" (nr):"cx","si")
#define port_read_b(port,buf,nr) \
__asm__("cld;rep;insb"::"d" (port),"D" (buf),"c" (nr):"cx","di")
#define port_write_b(port,buf,nr) \
__asm__("cld;rep;outsb"::"d" (port),"S" (buf),"c" (nr):"cx","si")
#define HP_DATAPORT 0x0c /* "Remote DMA" data port. */
#define HP_ID 0x07
#define HP_CONFIGURE 0x08 /* Configuration register. */
#define HP_RUN 0x01 /* 1 == Run, 0 == reset. */
#define HP_IRQ 0x0E /* Mask for software-configured IRQ line. */
#define HP_DATAON 0x10 /* Turn on dataport */
#define NIC_OFFSET 0x10 /* Offset the 8390 registers. */
#define HP_START_PG 0x00 /* First page of TX buffer */
#define HP_8BSTOP_PG 0x80 /* Last page +1 of RX ring */
#define HP_16BSTOP_PG 0xFF /* Last page +1 of RX ring */
extern void NS8390_init(struct device *dev, int startp);
extern int ei_debug;
extern struct sigaction ei_sigaction;
extern struct ei_device ei_status;
int hpprobe(int ioaddr, struct device *dev);
int hpprobe1(int ioaddr, struct device *dev);
static void hp_reset_8390(struct device *dev);
static int hp_block_input(struct device *dev, int count,
char *buf, int ring_offset);
static void hp_block_output(struct device *dev, int count,
const unsigned char *buf, const start_page);
static void hp_init_card(struct device *dev);
/* Probe for an HP LAN adaptor.
Also initialize the card and fill in STATION_ADDR with the station
address. */
int hpprobe(int ioaddr, struct device *dev)
{
int *port, ports[] = {0x300, 0x320, 0x340, 0x280, 0x2C0, 0x200, 0x240, 0};
if (ioaddr > 0x100)
return hpprobe1(ioaddr, dev);
for (port = &ports[0]; *port; port++)
if (inb_p(*port) != 0xff && hpprobe1(*port, dev))
return dev->base_addr;
return 0;
}
int hpprobe1(int ioaddr, struct device *dev)
{
int i;
unsigned char *station_addr = dev->dev_addr;
unsigned char SA_prom[6];
int tmp;
int hplan;
printk("HP-LAN ethercard probe at %#3x:", ioaddr);
tmp = inb_p(ioaddr);
if (tmp == 0xFF) {
printk(" not found (nothing there).\n");
return 0;
}
for(i = 0; i < sizeof(SA_prom); i++) {
SA_prom[i] = inb(ioaddr + i);
if (i < ETHER_ADDR_LEN && station_addr) {
printk(" %2.2x", SA_prom[i]);
station_addr[i] = SA_prom[i];
}
}
hplan = (SA_prom[0] == 0x08 && SA_prom[1] == 0x00 && SA_prom[2] == 0x09);
if (hplan == 0) {
printk(" not found (invalid station address prefix).\n");
return 0;
}
ei_status.tx_start_page = HP_START_PG;
ei_status.rx_start_page = HP_START_PG + TX_PAGES;
/* Set up the rest of the parameters. */
if ((tmp = inb_p(HP_ID)) & 0x80) {
ei_status.name = "HP27247";
ei_status.word16 = 1;
ei_status.stop_page = HP_16BSTOP_PG; /* Safe for now */
} else {
ei_status.name = "HP27250";
ei_status.word16 = 0;
ei_status.stop_page = HP_8BSTOP_PG; /* Safe for now */
}
/* Set the base address to point to the NIC! */
dev->base_addr = ioaddr + NIC_OFFSET;
if (dev->irq == 2)
dev->irq = 9;
/* Snarf the interrupt now. There's no point in waiting since we cannot
share and the board will usually be enabled. */
if (dev->irq < 2) {
int *irq, irq_list[] = { 11, 10, 5, 3, 4, 7, 9, 0};
for (irq = irq_list; *irq; irq++) {
if (irqaction(*irq, &ei_sigaction) == 0)
break;
}
if (*irq == 0) {
printk (" unable to get an IRQ.\n");
return 0;
}
dev->irq = *irq;
}
printk(" %s found, using IRQ %d.\n", ei_status.name, dev->irq);
if (ei_debug > 1)
printk(version);
ei_status.reset_8390 = &hp_reset_8390;
ei_status.block_input = &hp_block_input;
ei_status.block_output = &hp_block_output;
hp_init_card(dev);
return dev->base_addr;
}
static void
hp_reset_8390(struct device *dev)
{
int hp_base = dev->base_addr - NIC_OFFSET;
int saved_config = inb_p(hp_base + HP_CONFIGURE);
int reset_start_time = jiffies;
if (ei_debug > 1) printk("resetting the 8390 time=%d...", jiffies);
outb_p(0x00, hp_base + HP_CONFIGURE);
ei_status.txing = 0;
sti();
/* We shouldn't use the boguscount for timing, but this hasn't been
checked yet, and you could hang your machine if jiffies break... */
{
int boguscount = 150000;
while(jiffies - reset_start_time < 2)
if (boguscount-- < 0) {
printk("jiffy failure (t=%d)...", jiffies);
break;
}
}
outb_p(saved_config, hp_base + HP_CONFIGURE);
while ((inb_p(hp_base+NIC_OFFSET+EN0_ISR) & ENISR_RESET) == 0)
if (jiffies - reset_start_time > 2) {
printk(EI_NAME": hp_reset_8390() did not complete.\n");
return;
}
if (ei_debug > 1) printk("8390 reset done.", jiffies);
}
/* Block input and output, similar to the Crynwr packet driver. If you
porting to a new ethercard look at the packet driver source for hints.
The HP LAN doesn't use shared memory -- we put the packet
out through the "remote DMA" dataport. */
static int
hp_block_input(struct device *dev, int count, char *buf, int ring_offset)
{
int nic_base = dev->base_addr;
int saved_config = inb_p(nic_base - NIC_OFFSET + HP_CONFIGURE);
int xfer_count = count;
outb_p(saved_config | HP_DATAON, nic_base - NIC_OFFSET + HP_CONFIGURE);
outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base);
outb_p(count & 0xff, nic_base + EN0_RCNTLO);
outb_p(count >> 8, nic_base + EN0_RCNTHI);
outb_p(ring_offset & 0xff, nic_base + EN0_RSARLO);
outb_p(ring_offset >> 8, nic_base + EN0_RSARHI);
outb_p(E8390_RREAD+E8390_START, nic_base);
if (ei_status.word16) {
port_read(nic_base - NIC_OFFSET + HP_DATAPORT,buf,count>>1);
if (count & 0x01)
buf[count-1] = inb(nic_base - NIC_OFFSET + HP_DATAPORT), xfer_count++;
} else {
/* Input the bytes with a slow 8-bit loop. Someday change this to:
port_read_b(nic_base - NIC_OFFSET + HP_DATA_PORT,buf, count); */
int i;
for(i = 0; i < count; i++) {
buf[i] = inb_p(nic_base - NIC_OFFSET + HP_DATAPORT);
}
}
/* This is for the ALPHA version only, remove for later releases. */
if (ei_debug > 0) { /* DMA termination address check... */
int high = inb_p(nic_base + EN0_RSARHI);
int low = inb_p(nic_base + EN0_RSARLO);
int addr = (high << 8) + low;
/* Check only the lower 8 bits so we can ignore ring wrap. */
if (((ring_offset + xfer_count) & 0xff) != (addr & 0xff))
printk(EI_NAME": RX transfer address mismatch, %#4.4x vs. %#4.4x (actual).\n",
ring_offset + xfer_count, addr);
}
outb_p(saved_config & (~HP_DATAON), nic_base - NIC_OFFSET + HP_CONFIGURE);
return ring_offset + count;
}
static void
hp_block_output(struct device *dev, int count,
const unsigned char *buf, const start_page)
{
int nic_base = dev->base_addr;
int saved_config = inb_p(nic_base - NIC_OFFSET + HP_CONFIGURE);
int i;
outb_p(saved_config | HP_DATAON, nic_base - NIC_OFFSET + HP_CONFIGURE);
/* Round the count up for word writes. Do we need to do this?
What effect will an odd byte count have on the 8390?
I should check someday. */
if (ei_status.word16 && (count & 0x01))
count++;
/* We should already be in page 0, but to be safe... */
outb_p(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base);
#ifdef notdef
/* Handle the read-before-write bug the same way as the
Crynwr packet driver -- the NatSemi method doesn't work. */
outb_p(0x42, nic_base + EN0_RCNTLO);
outb_p(0, nic_base + EN0_RCNTHI);
outb_p(0xff, nic_base + EN0_RSARLO);
outb_p(0x00, nic_base + EN0_RSARHI);
outb_p(E8390_RREAD+E8390_START, EN_CMD);
/* Make certain that the dummy read has occured. */
inb_p(0x61);
inb_p(0x61);
#endif
outb_p(count & 0xff, nic_base + EN0_RCNTLO);
outb_p(count >> 8, nic_base + EN0_RCNTHI);
outb_p(0x00, nic_base + EN0_RSARLO);
outb_p(start_page, nic_base + EN0_RSARHI);
outb_p(E8390_RWRITE+E8390_START, nic_base);
if (ei_status.word16) {
/* Use the 'rep' sequence for 16 bit boards. */
port_write(nic_base - NIC_OFFSET + HP_DATAPORT, buf, count>>1);
} else {
/* Output the bytes with a slow 8-bit loop. This actually is almost
as fast as possible, but it does tie up the processor. We could
also use a 'rep' sequnce here. */
for(i = 0; i < count; i++)
outb_p(buf[i], nic_base - NIC_OFFSET + HP_DATAPORT);
}
/* DON'T check for 'inb_p(EN0_ISR) & ENISR_RDC' here -- it's broken! */
/* This is for the ALPHA version only, remove for later releases. */
if (ei_debug > 0) { /* DMA termination address check... */
int high = inb_p(nic_base + EN0_RSARHI);
int low = inb_p(nic_base + EN0_RSARLO);
int addr = (high << 8) + low;
if ((start_page << 8) + count != addr)
printk(EI_NAME": TX Transfer address mismatch, %#4.4x vs. %#4.4x.\n",
(start_page << 8) + count, addr);
}
outb_p(saved_config & (~HP_DATAON), nic_base - NIC_OFFSET + HP_CONFIGURE);
return;
}
/* This function resets the ethercard if something screws up. */
static void
hp_init_card(struct device *dev)
{
int irq = dev->irq;
/* default is IRQ5 0 1 2 3 4 5 6 7 8 9 10 11 */
static char irqval[16] = { 0, 0, 4, 6, 8,10, 0,14, 0, 4, 2,12,0,0,0,0};
NS8390_init(dev, 0);
outb_p(irqval[irq&0x0f] | HP_RUN,
dev->base_addr - NIC_OFFSET + HP_CONFIGURE);
return;
}
/*
* Local variables:
* compile-command: "gcc -DKERNEL -Wall -O6 -fomit-frame-pointer -I/usr/src/linux/net/tcp -c hp.c"
* version-control: t
* kept-new-versions: 5
* End:
*/

372
net/tcpip/newether/ne.c Normal file
View File

@@ -0,0 +1,372 @@
/* ne.c: A general non-shared-memory NS8390 ethernet driver for linux. */
/*
Written 1992,1993 by Donald Becker. This is alpha test code.
This is a extension to the Linux operating system, and is covered by
same Gnu Public License that covers that work.
This driver should work with many 8390-based ethernet boards. Currently
it support the NE1000, NE2000 (and clones), and some Cabletron products.
8-bit ethercard support is enabled with #define EI_8BIT
The Author may be reached as becker@super.org or
C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
*/
/* Routines for the NatSemi-based designs (NE[12]000). */
static char *version =
"ne.c:v0.27 1/27/93 Donald Becker (becker@super.org)\n";
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <asm/io.h>
#include <asm/system.h>
#include "dev.h"
#include "8390.h"
/* These should be in <asm/io.h> someday, borrowed from blk_drv/hd.c. */
#define port_read(port,buf,nr) \
__asm__("cld;rep;insw"::"d" (port),"D" (buf),"c" (nr):"cx","di")
#define port_write(port,buf,nr) \
__asm__("cld;rep;outsw"::"d" (port),"S" (buf),"c" (nr):"cx","si")
#define port_read_b(port,buf,nr) \
__asm__("cld;rep;insb"::"d" (port),"D" (buf),"c" (nr):"cx","di")
#define port_write_b(port,buf,nr) \
__asm__("cld;rep;outsb"::"d" (port),"S" (buf),"c" (nr):"cx","si")
#define EN_CMD (dev->base_addr)
#define NE_BASE (dev->base_addr)
#define NE_DATAPORT 0x10 /* NatSemi-defined port window offset. */
#define NE_RESET 0x1f /* Issue a read to reset, a write to clear. */
#define NE1SM_START_PG 0x20 /* First page of TX buffer */
#define NE1SM_STOP_PG 0x40 /* Last page +1 of RX ring */
#define NESM_START_PG 0x40 /* First page of TX buffer */
#define NESM_STOP_PG 0x80 /* Last page +1 of RX ring */
extern void NS8390_init(struct device *dev, int startp);
extern int ei_debug;
extern struct sigaction ei_sigaction;
extern struct ei_device ei_status;
int neprobe(int ioaddr, struct device *dev);
static int neprobe1(int ioaddr, struct device *dev);
static void ne_reset_8390(struct device *dev);
static int ne_block_input(struct device *dev, int count,
char *buf, int ring_offset);
static void ne_block_output(struct device *dev, const int count,
const unsigned char *buf, const int start_page);
static void ne_init_card(struct device *dev);
/* Probe for the NE1000 and NE2000. NEx000-like boards have 0x57,0x57 in
bytes 0x0e,0x0f of the SAPROM, but if we read by 16 bit words the NE1000
appears to have 0x00, 0x42. */
/* Also initialize the card and fill in STATION_ADDR with the station
address. The station address (and other data) is stored in the
packet buffer memory space, 32 bytes starting at remote DMA address 0. */
int neprobe(int ioaddr, struct device *dev)
{
int *port, ports[] = {0x300, 0x320, 0x340, 0x360, 0};
if (ioaddr > 0x100)
return neprobe1(ioaddr, dev);
for (port = &ports[0]; *port; port++)
if (inb_p(*port) != 0xff && neprobe1(*port, dev))
return dev->base_addr = *port;
return 0;
}
static int neprobe1(int ioaddr, struct device *dev)
{
int i;
unsigned char *station_addr = dev->dev_addr;
unsigned char SA_prom[32];
int cmdreg;
int ne2000 = 0, ne1000 = 0, ctron = 0;
printk("8390 ethercard probe at %#3x:", ioaddr);
cmdreg = inb_p(ioaddr);
if (cmdreg == 0xFF) {
printk(" not found (%#2.2x).\n", cmdreg);
return 0;
}
/* Ooops, we must first initialize registers -- we can't just read the PROM
address right away. (Learned the hard way.) */
/* NS8390_init(eifdev, 0);*/
outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, ioaddr);
#ifdef EI_8BIT
outb_p(0x48, ioaddr + EN0_DCFG); /* Set byte-wide for probe. */
#else
outb_p(0x49, ioaddr + EN0_DCFG); /* Set word-wide for probe. */
#endif
/* Even though we'll set them soon, we must clear them! */
outb_p(0x00, ioaddr + EN0_RCNTLO);
outb_p(0x00, ioaddr + EN0_RCNTHI);
outb_p(0x00, ioaddr + EN0_IMR); /* Mask completion irq. */
outb_p(0xFF, ioaddr + EN0_ISR);
/* Set to monitor and loopback mode. */
outb_p(E8390_RXOFF, ioaddr + EN0_RXCR); /* 0x20 */
outb_p(E8390_TXOFF, ioaddr + EN0_TXCR); /* 0x02 */
#ifdef EI_8BIT
outb_p(sizeof(SA_prom), ioaddr + EN0_RCNTLO);
#else
/* Double count 0x20 words, the SA PROM is only byte wide. */
outb_p(2*sizeof(SA_prom), ioaddr + EN0_RCNTLO);
#endif
outb_p(0x00, ioaddr + EN0_RCNTHI);
outb_p(0x00, ioaddr + EN0_RSARLO); /* DMA starting at 0x0000. */
outb_p(0x00, ioaddr + EN0_RSARHI);
outb_p(E8390_RREAD+E8390_START, ioaddr);
for(i = 0; i < sizeof(SA_prom); i++) {
SA_prom[i] = inb_p(ioaddr + NE_DATAPORT);
if (i < ETHER_ADDR_LEN && station_addr) {
printk(" %2.2x", SA_prom[i]);
station_addr[i] = SA_prom[i];
}
}
#ifdef EI_8BIT
ne1000 = (SA_prom[14] == 0x57 && SA_prom[15] == 0x57);
#else
ne2000 = (SA_prom[14] == 0x57 && SA_prom[15] == 0x57);
ne1000 = (SA_prom[14] == 0x00 && SA_prom[15] == 0x42);
ctron = (SA_prom[0] == 0x00 && SA_prom[1] == 0x00 && SA_prom[2] == 0x1d);
#endif
/* Set up the rest of the parameters. */
if (ne1000) {
ei_status.name = "NE1000";
ei_status.word16 = 0;
ei_status.tx_start_page = NE1SM_START_PG;
ei_status.rx_start_page = NE1SM_START_PG + TX_PAGES;
ei_status.stop_page = NE1SM_STOP_PG;
} else if (ne2000) {
ei_status.name = "NE2000";
ei_status.word16 = 1;
ei_status.tx_start_page = NESM_START_PG;
ei_status.rx_start_page = NESM_START_PG + TX_PAGES;
ei_status.stop_page = NESM_STOP_PG;
} else if (ctron) {
/* You'll have to set these yourself, but this info might be useful.
Cabletron packet buffer locations:
E1010 starts at 0x100 and ends at 0x2000.
E1010-x starts at 0x100 and ends at 0x8000. ("-x" means "more memory")
E2010 starts at 0x100 and ends at 0x4000.
E2010-x starts at 0x100 and ends at 0xffff. */
ei_status.name = "Cabletron";
ei_status.word16 = 1;
ei_status.tx_start_page = 0x01;
ei_status.rx_start_page = 0x01 + TX_PAGES;
#ifndef CTRON_MEMSIZE
#define CTRON_MEMSIZE 0x20 /* Extra safe... */
#endif
ei_status.stop_page = CTRON_MEMSIZE;
} else {
printk(" not found.\n");
return 0;
}
dev->base_addr = ioaddr;
if (dev->irq < 2) {
int nic_base = dev->base_addr;
autoirq_setup(0);
outb_p(0x50, nic_base + EN0_IMR); /* Enable one interrupt. */
outb_p(0x00, nic_base + EN0_RCNTLO);
outb_p(0x00, nic_base + EN0_RCNTHI);
outb_p(E8390_RREAD+E8390_START, nic_base); /* Trigger it... */
outb_p(0x00, nic_base + EN0_IMR); /* Mask it again. */
dev->irq = autoirq_report(0);
if (ei_debug > 2)
printk(" autoirq is %d", dev->irq);
} else if (dev->irq == 2)
/* Fixup for users that don't know that IRQ 2 is really IRQ 9,
or don't know which one to set. */
dev->irq = 9;
/* Snarf the interrupt now. There's no point in waiting since we cannot
share and the board will usually be enabled. */
{ int irqval = irqaction (dev->irq, &ei_sigaction);
if (irqval) {
printk (" unable to get IRQ %d (irqval=%d).\n", dev->irq, irqval);
return 0;
}
}
printk(" %s found, using IRQ %d.\n", ei_status.name, dev->irq);
if (ei_debug > 1)
printk(version);
ei_status.reset_8390 = &ne_reset_8390;
ei_status.block_input = &ne_block_input;
ei_status.block_output = &ne_block_output;
ne_init_card(dev);
return dev->base_addr;
}
static void
ne_reset_8390(struct device *dev)
{
int tmp = inb_p(NE_BASE + NE_RESET);
int reset_start_time = jiffies;
if (ei_debug > 1) printk("resetting the 8390 t=%d...", jiffies);
ei_status.txing = 0;
sti();
/* We shouldn't use the boguscount for timing, but this hasn't been
checked yet, and you could hang your machine if jiffies break... */
{
int boguscount = 150000;
while(jiffies - reset_start_time < 2)
if (boguscount-- < 0) {
printk("jiffy failure (t=%d)...", jiffies);
break;
}
}
outb_p(tmp, NE_BASE + NE_RESET);
while ((inb_p(NE_BASE+EN0_ISR) & ENISR_RESET) == 0)
if (jiffies - reset_start_time > 2) {
printk(EI_NAME": ne_reset_8390() did not complete.\n");
break;
}
}
/* Block input and output, similar to the Crynwr packet driver. If you
porting to a new ethercard look at the packet driver source for hints.
The NEx000 doesn't have shared memory on the board -- put the packet
out through the "remote DMA" dataport. */
static int
ne_block_input(struct device *dev, int count, char *buf, int ring_offset)
{
int xfer_count = count;
int nic_base = NE_BASE;
outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, EN_CMD);
outb_p(count & 0xff, nic_base + EN0_RCNTLO);
outb_p(count >> 8, nic_base + EN0_RCNTHI);
outb_p(ring_offset & 0xff, nic_base + EN0_RSARLO);
outb_p(ring_offset >> 8, nic_base + EN0_RSARHI);
outb_p(E8390_RREAD+E8390_START, EN_CMD);
if (ei_status.word16) {
port_read(NE_BASE + NE_DATAPORT,buf,count>>1);
if (count & 0x01)
buf[count-1] = inb(NE_BASE + NE_DATAPORT), xfer_count++;
} else {
/* Input the bytes with a slow 8-bit loop. Someday change this to:
port_read_b(NE_BASE + NE_DATAPORT, buf, count); */
int i;
/* Input the bytes with a slow 8-bit loop. Tune this someday. */
for(i = 0; i < count; i++) {
buf[i] = inb_p(NE_BASE + NE_DATAPORT);
}
}
/* This is for the ALPHA version only, remove for later releases. */
if (ei_debug > 0) { /* DMA termination address check... */
int high = inb_p(nic_base + EN0_RSARHI);
int low = inb_p(nic_base + EN0_RSARLO);
int addr = (high << 8) + low;
/* Check only the lower 8 bits so we can ignore ring wrap. */
if (((ring_offset + xfer_count) & 0xff) != (addr & 0xff))
printk(EI_NAME": RX transfer address mismatch, %#4.4x (should be) vs. %#4.4x (actual).\n",
ring_offset + xfer_count, addr);
}
return ring_offset + count;
}
static void
ne_block_output(struct device *dev, int count,
const unsigned char *buf, const int start_page)
{
int i, retries = 0;
int nic_base = NE_BASE;
/* Round the count up for word writes. Do we need to do this?
What effect will an odd byte count have on the 8390?
I should check someday. */
if (ei_status.word16 && (count & 0x01))
count++;
/* We should already be in page 0, but to be safe... */
outb_p(E8390_PAGE0+E8390_START+E8390_NODMA, EN_CMD);
retry:
#if !defined(no_rw_bugfix) && 0
/* Handle the read-before-write bug the same way as the
Crynwr packet driver -- the NatSemi method doesn't work.
Actually this doesn't aways work either, but if you have
problems with your NEx000 this is better than nothing! */
outb_p(0x42, nic_base + EN0_RCNTLO);
outb_p(0x00, nic_base + EN0_RCNTHI);
outb_p(0x42, nic_base + EN0_RSARLO);
outb_p(0x00, nic_base + EN0_RSARHI);
outb_p(E8390_RREAD+E8390_START, EN_CMD);
/* Make certain that the dummy read has occured. */
SLOW_DOWN_IO;
SLOW_DOWN_IO;
SLOW_DOWN_IO;
#endif /* no_rw_bugfix */
/* Now the normal output. */
outb_p(count & 0xff, nic_base + EN0_RCNTLO);
outb_p(count >> 8, nic_base + EN0_RCNTHI);
outb_p(0x00, nic_base + EN0_RSARLO);
outb_p(start_page, nic_base + EN0_RSARHI);
outb_p(E8390_RWRITE+E8390_START, EN_CMD);
if (ei_status.word16) {
/* Use the 'rep' sequence for 16 bit boards. */
port_write(NE_BASE + NE_DATAPORT, buf, count>>1);
} else {
/* Output the bytes with a slow 8-bit loop. Someday change this to:
port_write_b(NE_BASE + NE_DATAPORT, buf, count); */
/* Output the bytes with a slow 8-bit loop. This actually is almost
as fast as possible, but it does tie up the processor. We could
also use a 'rep' sequnce here. */
for(i = 0; i < count; i++)
outb_p(buf[i], NE_BASE + NE_DATAPORT);
}
/* DON'T check for 'inb_p(EN0_ISR) & ENISR_RDC' here -- it's broken! */
/* This is for the ALPHA version only, remove for later releases. */
if (ei_debug > 0) { /* DMA termination address check... */
int high = inb_p(nic_base + EN0_RSARHI);
int low = inb_p(nic_base + EN0_RSARLO);
int addr = (high << 8) + low;
if ((start_page << 8) + count != addr)
printk(EI_NAME": Packet buffer transfer address mismatch on TX, %#4.4x vs. %#4.4x.\n",
(start_page << 8) + count, addr);
if (retries++ == 0)
goto retry;
}
return;
}
/* This function resets the ethercard if something screws up. */
static void
ne_init_card(struct device *dev)
{
NS8390_init(dev, 0);
return;
}
/*
* Local variables:
* compile-command: "gcc -DKERNEL -Wall -O6 -fomit-frame-pointer -I/usr/src/linux/net/tcp -c ne.c"
* version-control: t
* kept-new-versions: 5
* End:
*/

352
net/tcpip/newether/wd.c Normal file
View File

@@ -0,0 +1,352 @@
/* wd.c: A WD80x3 ethernet driver for linux. */
/*
Written 1993 by Donald Becker. This is alpha test code.
This is a extension to the Linux operating system, and is covered by
same Gnu Public License that covers that work.
This is a driver for the WD8003 and WD8013 ethercards.
The Author may be reached as becker@super.org or
C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
Thanks to Russ Nelson (nelson@crnwyr.com) for loaning me a WD8013.
*/
static char *version =
"wd.c:v0.28a 1/28/93 Donald Becker (becker@super.org)\n";
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <asm/io.h>
#include <asm/system.h>
#include <memory.h>
#include "dev.h"
#include "8390.h"
extern void NS8390_init(struct device *dev, int startp);
extern int ei_debug;
extern struct sigaction ei_sigaction;
extern struct ei_device ei_status;
int wdprobe(int ioaddr, struct device *dev);
int wdprobe1(int ioaddr, struct device *dev);
static void wd_reset_8390(struct device *dev);
static int wd_block_input(struct device *dev, int count,
char *buf, int ring_offset);
static void wd_block_output(struct device *dev, int count,
const unsigned char *buf, const start_page);
static int wd_close_card(struct device *dev);
/* The stop page doesn't use the whole packet buffer RAM for the
16 bit versions. This could be changed for the final version. */
#define WD_START_PG 0x00 /* First page of TX buffer */
#define WD_STOP_PG 0x40 /* Last page +1 of RX ring */
#define WD_CMDREG 0 /* Offset to ASIC command register. */
#define WD_RESET 0x80 /* Board reset, in WD_CMDREG. */
#define WD_MEMENB 0x40 /* Enable the shared memory. */
#define WD_CMDREG5 5 /* Offset to 16-bit-only ASIC register 5. */
#define ISA16 0x80 /* Enable 16 bit access from the ISA bus. */
#define NIC16 0x40 /* Enable 16 bit access from the 8390. */
#define WD_NIC_OFFSET 16 /* Offset to the 8390 NIC from the base_addr. */
/* Probe for the WD8003 and WD8013. These cards have the station
address PROM at I/O ports <base>+8 to <base>+13, with a checksum
following. The routine also initializes the card and fills the
station address field. */
int wdprobe(int ioaddr, struct device *dev)
{
int *port, ports[] = {0x300, 0x280, 0};
if (ioaddr > 0x100)
return wdprobe1(ioaddr, dev);
for (port = &ports[0]; *port; port++)
if (inb_p(*port) != 0xff && wdprobe1(*port, dev))
return dev->base_addr;
return 0;
}
int wdprobe1(int ioaddr, struct device *dev)
{
int i;
unsigned char *station_addr = dev->dev_addr;
int checksum = 0;
int bits16 = 0;
#if defined(EI_DEBUG) && EI_DEBUG > 2
printk("WD80x3 ethercard at %#3x:", ioaddr);
for (i = 0; i < 16; i++) {
printk(" %2.2X", inb(ioaddr+i));
}
printk("\n");
printk("WD80x3 ethercard at %#3x:", ioaddr+i);
for (;i < 33; i++) {
printk(" %2.2X", inb(ioaddr+i));
}
printk("\n");
#endif
printk("WD80x3 ethercard probe at %#3x:", ioaddr);
for (i = 0; i < 8; i++) {
int inval = inb(ioaddr + 8 + i);
checksum += inval;
if (i < 6)
printk(" %2.2X", (station_addr[i] = inval));
}
if ((checksum & 0xff) != 0xFF) {
printk(" not found (%#2.2x).\n", checksum);
return 0;
}
ei_status.name = "WD8003";
ei_status.word16 = 0;
/* This method of checking for a 16-bit board is borrowed from the
we.c driver. A simpler method is just to look in ASIC reg. 0x03.
I'm comparing the two method in alpha test to make certain they
return the same result. */
#ifndef FORCE_8BIT /* Same define as we.c. */
/* check for 16 bit board - it doesn't have register 0/8 aliasing */
for (i = 0; i < 8; i++) {
int tmp;
if( inb_p(ioaddr+8+i) != inb_p(ioaddr+i) ){
tmp = inb_p(ioaddr+1); /* fiddle with 16bit bit */
outb( tmp ^ 0x01, ioaddr+1 ); /* attempt to clear 16bit bit */
if ((tmp & 0x01) == (inb_p( ioaddr+1) & 0x01)) {
int asic_reg5 = inb(ioaddr+WD_CMDREG5);
bits16 = 1; /* use word mode of operation */
/* Magic to set ASIC to word-wide mode. */
outb( ISA16 | NIC16 | (asic_reg5&0x1f), ioaddr+WD_CMDREG5);
outb(tmp, ioaddr+1);
ei_status.name = "WD8013";
ei_status.word16 = 1;
break; /* We have a 16bit board here! */
}
outb(tmp, ioaddr+1);
}
}
#else
bits8 = 1;
#endif /* FORCE_8BIT */
#ifndef final_version
if ((inb(ioaddr+1) & 0x01) != (ei_status.word16 & 0x01))
printk("\nWD80x3: Bus width conflict, %d (probe) != %d (reg report).\n",
ei_status.word16 ? 16:8, (inb(ioaddr+1) & 0x01) ? 16 : 8);
#endif
ei_status.tx_start_page = WD_START_PG;
ei_status.rx_start_page = WD_START_PG + TX_PAGES;
ei_status.stop_page = WD_STOP_PG;
#if defined(WD_SHMEM) && WD_SHMEM > 0x80000
/* Allow an override for alpha testing. */
dev->mem_start = WD_SHMEM;
#else
if (dev->mem_start == 0) {
dev->mem_start = ((inb(ioaddr)&0x3f) << 13) +
(ei_status.word16 ? (inb(ioaddr+WD_CMDREG5)&0x1f)<<19 : 0x80000);
printk(" address %#x,", dev->mem_start);
}
#endif
dev->rmem_start = dev->mem_start + TX_PAGES*256;
dev->mem_end = dev->rmem_end
= dev->mem_start + (WD_STOP_PG - WD_START_PG)*256;
#if defined(EI_DEBUG) && EI_DEBUG > 3
memset((void*)dev->mem_start, 0x42424242, (WD_STOP_PG - WD_START_PG)*256);
#endif
/* The 8390 isn't at the base address -- the ASIC regs are there! */
dev->base_addr = ioaddr+WD_NIC_OFFSET;
if (dev->irq < 2) {
int nic_base = dev->base_addr;
outb(WD_RESET, ioaddr);
autoirq_setup(1);
outb_p((((dev->mem_start>>13) & 0x3f)|WD_MEMENB), ioaddr); /* WD_CMDREG */
if (ei_status.word16)
outb_p( ISA16 | NIC16 | ((dev->mem_start>>19) & 0x1f), ioaddr+WD_CMDREG5);
/* This doesn't reliably generate an interrupt! */
outb_p(0xff, nic_base + EN0_ISR); /* Ack. all intrs. */
outb_p(0x50, nic_base + EN0_IMR); /* Enable "DMA complete" interrupt. */
outb_p(0x00, nic_base + EN0_RCNTLO);
outb_p(0x00, nic_base + EN0_RCNTHI);
outb_p(E8390_RREAD+E8390_START, nic_base); /* Trigger it... */
outb_p(E8390_RWRITE+E8390_START, nic_base); /* Trigger it again... */
dev->irq = autoirq_report(1);
outb_p(0x00, nic_base + EN0_IMR); /* Mask it again. */
if (ei_debug > 2)
printk(" autoIRQ %d", dev->irq);
if (dev->irq == 0) {
printk(" autoIRQ failed, isr=%02x", inb(nic_base + EN0_ISR));
dev->irq = 10;
}
} else if (dev->irq == 2)
/* Fixup for users that don't know that IRQ 2 is really IRQ 9,
or don't know which one to set. */
dev->irq = 9;
/* Snarf the interrupt now. There's no point in waiting since we cannot
share and the board will usually be enabled. */
{ int irqval = irqaction (dev->irq, &ei_sigaction);
if (irqval) {
printk (" unable to get IRQ %d (irqval=%d).\n", dev->irq, irqval);
return 0;
}
}
printk(" %s found, using IRQ %d.\n", ei_status.name, dev->irq);
if (ei_debug > 1)
printk(version);
if (ei_debug > 1)
printk("%s: Address read from register is %#x, setting address %#x\n",
ei_status.name,
((inb(ioaddr+WD_CMDREG5)&0x1f)<<19) + ((inb(ioaddr)&0x3f) << 13),
dev->mem_start);
/* Map in the shared memory. This is a little risky, since using
the stuff the user supplied is probably a bad idea. */
outb_p((((dev->mem_start>>13) & 0x3f)|WD_MEMENB), ioaddr); /* WD_CMDREG */
if (ei_status.word16)
outb_p( ISA16 | NIC16 | ((dev->mem_start>>19) & 0x1f), ioaddr+WD_CMDREG5);
ei_status.reset_8390 = &wd_reset_8390;
ei_status.block_input = &wd_block_input;
ei_status.block_output = &wd_block_output;
dev->stop = &wd_close_card;
NS8390_init(dev, 0);
return dev->base_addr;
}
static void
wd_reset_8390(struct device *dev)
{
int wd_cmd_port = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
int reset_start_time = jiffies;
outb(WD_RESET, wd_cmd_port);
if (ei_debug > 1) printk("resetting the WD80x3 t=%d...", jiffies);
ei_status.txing = 0;
sti();
/* We shouldn't use the boguscount for timing, but this hasn't been
checked yet, and you could hang your machine if jiffies break... */
{
int boguscount = 150000;
while(jiffies - reset_start_time < 2)
if (boguscount-- < 0) {
printk("jiffy failure (t=%d)...", jiffies);
break;
}
}
outb(0x00, wd_cmd_port);
while ((inb_p(dev->base_addr+EN0_ISR) & ENISR_RESET) == 0)
if (jiffies - reset_start_time > 2) {
printk(EI_NAME": wd_reset_8390() did not complete.\n");
break;
}
#if defined(EI_DEBUG) && EI_DEBUG > 2
{
int i;
printk("WD80x3 ethercard at %#3x:", wd_cmd_port);
for (i = 0; i < 16; i++) {
printk(" %2.2X", inb(wd_cmd_port+i));
}
printk("\nWD80x3 ethercard at %#3x:", wd_cmd_port);
for (;i < 33; i++) {
printk(" %2.2X", inb(wd_cmd_port+i));
}
printk("\n");
}
#endif
/* Set up the ASIC registers, just in case something changed them. */
outb_p((((dev->mem_start>>13) & 0x3f)|WD_MEMENB), wd_cmd_port); /* WD_CMDREG */
if (ei_status.word16)
outb_p( ISA16 | NIC16 | ((dev->mem_start>>19) & 0x1f), wd_cmd_port+WD_CMDREG5);
}
/* Block input and output are easy on shared memory ethercards, and trivial
on the Western digital card where there is no choice of how to do it. */
static int
wd_block_input(struct device *dev, int count, char *buf, int ring_offset)
{
void *xfer_start = (void *)(dev->mem_start + ring_offset - (WD_START_PG<<8));
#ifdef mapout
int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
/* Map in the shared memory. */
outb_p((((dev->mem_start>>13) & 0x3f)|WD_MEMENB), wd_cmdreg);
#endif
if (xfer_start + count > (void*) dev->rmem_end) {
/* We must wrap the input move. */
int semi_count = (void*)dev->rmem_end - xfer_start;
memcpy(buf, xfer_start, semi_count);
count -= semi_count;
memcpy(buf + semi_count, (char *)dev->rmem_start, count);
return dev->rmem_start + count;
}
memcpy(buf, xfer_start, count);
if (ei_debug > 4) {
unsigned short *board = xfer_start;
printk("wd8013: wd_block_input(cnt=%d offset=%3x addr=%#x) = %2x %2x %2x...\n",
count, ring_offset, xfer_start, board[-1], board[0], board[1]);
}
#ifdef mapout
outb(0, wd_cmdreg); /* WD_CMDREG: Map out the shared memory. */
#endif
return ring_offset + count;
}
/* This could only be outputting to the transmit buffer. The
ping-pong transmit setup doesn't work with this yet. */
static void
wd_block_output(struct device *dev, int count, const unsigned char *buf, int start_page)
{
unsigned char *shmem = (void *)dev->mem_start + ((start_page - WD_START_PG)<<8);
#ifdef mapout
int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
/* Map in the shared memory. */
outb_p((((dev->mem_start>>13) & 0x3f)|WD_MEMENB), wd_cmdreg);
#endif
memcpy(shmem, buf, count);
if (ei_debug > 4)
printk("wd8013: wd_block_output(addr=%#x cnt=%d) -> %2x=%2x %2x=%2x %d...\n",
shmem, count, shmem[23], buf[23], shmem[24], buf[24], memcmp(shmem,buf,count));
#ifdef mapout
outb(0, wd_cmdreg); /* WD_CMDREG: Map out the shared memory. */
#endif
}
/* This function resets the ethercard if something screws up. */
static int
wd_close_card(struct device *dev)
{
if (ei_debug > 1)
printk("%s: shutting down ethercard.\n", ei_status.name);
NS8390_init(dev, 0);
/* Turn off the shared memory. */
outb_p((((dev->mem_start>>13) & 0x3f)),
dev->base_addr-WD_NIC_OFFSET); /* WD_CMDREG */
return 0;
}
/*
* Local variables:
* compile-command: "gcc -DKERNEL -Wall -O6 -fomit-frame-pointer -I/usr/src/linux/net/tcp -c wd.c"
* version-control: t
* kept-new-versions: 5
* End:
*/

5
net/tcpip/ping.README Normal file
View File

@@ -0,0 +1,5 @@
This is a ping binary for Linux .98pl5 + the 3 tcp patches. It should also
work with any kernel > .98pl5. It needs to be installed suid root.
The source has a message saying it's public domain, but it also claims
to be Copyright by Berkeley with the standard Berkeley license.

116
net/tcpip/tcp5.diff Normal file
View File

@@ -0,0 +1,116 @@
From owner-linux-activists@joker.cs.hut.fi Wed Aug 5 03:51:40 1992
Received: from funet.fi by lazy.qt.IPA.FhG.de with SMTP
(5.61+/IDA-1.2.8/gandalf.2) id AA03065; Wed, 5 Aug 92 03:51:37 +0200
Received: from santra.hut.fi by funet.fi with SMTP (PP) id <02221-0@funet.fi>;
Wed, 5 Aug 1992 04:50:24 +0300
Received: from joker.cs.hut.fi by santra.hut.fi (5.65c/8.0/TeKoLa) id AA17553;
Wed, 5 Aug 1992 04:50:12 +0300
Received: by joker.cs.hut.fi (5.65b/6.8/S-TeKoLa) id AA13438;
Wed, 5 Aug 92 04:49:56 +0259
Received: from sunlight.Stanford.EDU by joker.cs.hut.fi (5.65b/6.8/S-TeKoLa)
id AA13417; Wed, 5 Aug 92 04:49:12 +0300
Received: from elaine12.Stanford.EDU by sunlight.Stanford.EDU (4.1/AIR-1.0)
id AA18390; Tue, 4 Aug 92 18:49:17 PDT
From: bir7@leland.stanford.edu
Message-Id: <9208050149.AA18390@sunlight.Stanford.EDU>
Subject: Re: tcp/ip diffs
Sender: owner-linux-activists@niksula.hut.fi
To: linux-activists@niksula.hut.fi
X-Note1: Remember to put 'X-Mn-Key: normal' to your mail body or header
Date: Tue, 4 Aug 92 18:49:17 PDT
Cc: linux-activists@joker.cs.hut.fi (Linux Activists), arl@cs.hut.fi
In-Reply-To: <9208050130.AA02024@klaava.Helsinki.FI>; from "Linus Torvalds" at Aug 5, 92 4:30 am
X-Mailer: ELM [version 2.3 PL11]
X-Mn-Key: NET
>
> bir7@leland.stanford.edu: "tcp/ip diffs" (Aug 4, 16:44):
> > Here are diffs against .97 (+ profile patches) that are required for
> > all the tcp/ip code. It includes 4 files, one for vhangup, one for
> > the tty's, one for fcntl, and one for the net directory. I would
> > appretiate it if you would include all these diffs in the next
> > release.
>
> Your next message indicated there were problems with the patch, so I
> won't put it in yet. Other than that, I think I'm ready for the tcp/ip
> code.
Some diffs to fix the problem are at the end of the message.
For the net/tcp directory, you should probably get it from nic.funet.fi
Linux/testing/beta/NET, as it's very big.
>
> One thing I've been wondering about: does the tcp/ip code use 386bsd
> code heavily? I've had a few people asking about it, as they don't like
> the USL suit against BSDI. I'd rather be NET/2 free (which the current
> kernel should be), although I personally think the USL suit will fail
> (but it may take some time)
>
All the clients and servers are from BIND. The only kernel
code that is remotely related to anything is the wd8003 driver. I used
the 386bsd driver as an example when I wrote the code. But basically
everything is different. The basic tcp/ip code was written completely
by me. The only thing I've gotten from anyone else is some icmp code
which is probably not from net2, as it has to interface with everything
I did which is not remotely like anything in net2 (Actually I don't know
this since I haven't look at the net2 code, but the way the tcp/ip code
evolved it couldn't be like anything else.)
Everyone Please note at the end of this message are some diffs which must
be applied for unix domain sockets to work (after applying my sock.diff
which screws them up.)
[Ari, Please add them to the ftp site either in the tar file or next to it.]
Ross Biro bir7@leland.stanford.edu
Member League for Programming Freedom (LPF)
mail league@prep.ai.mit.edu for information
ps. I'm using X right now, so the diffs work.
---- important diffs -----
*** ../linux/net/unix.c Tue Aug 4 12:26:38 1992
--- linux/net/unix.c Tue Aug 4 17:30:29 1992
***************
*** 431,441 ****
{
struct socket *clientsock;
PRINTK("unix_proto_accept: socket 0x%x accepted via socket 0x%x\n",
sock, newsock);
- unix_data_ref(UN_DATA(newsock->conn));
/*
* if there aren't any sockets awaiting connection, then wait for
* one, unless nonblocking
*/
--- 431,440 ----
***************
*** 446,456 ****
if (current->signal & ~current->blocked) {
PRINTK("sys_accept: sleep was interrupted\n");
return -ERESTARTSYS;
}
}
- UN_DATA(newsock)->peerupd = UN_DATA(newsock->conn);
/*
* great. finish the connection relative to server and client,
* wake up the client and return the new fd to the server
*/
--- 445,454 ----
***************
*** 459,468 ****
--- 457,470 ----
newsock->conn = clientsock;
clientsock->conn = newsock;
clientsock->state = SS_CONNECTED;
newsock->state = SS_CONNECTED;
wake_up(clientsock->wait);
+
+ unix_data_ref (UN_DATA(newsock->conn));
+ UN_DATA(newsock)->peerupd = UN_DATA(newsock->conn);
+
return 0;
}
/*
* gets the current name or the name of the connected socket.

82
net/tcpip/tcp5.patch Normal file
View File

@@ -0,0 +1,82 @@
From owner-linux-activists@joker.cs.hut.fi Wed Aug 5 19:54:00 1992
Received: from funet.fi by lazy.qt.IPA.FhG.de with SMTP
(5.61+/IDA-1.2.8/gandalf.2) id AA03798; Wed, 5 Aug 92 19:53:55 +0200
Received: from santra.hut.fi by funet.fi with SMTP (PP) id <12734-0@funet.fi>;
Wed, 5 Aug 1992 20:44:54 +0300
Received: from joker.cs.hut.fi by santra.hut.fi (5.65c/8.0/TeKoLa) id AA23193;
Wed, 5 Aug 1992 20:44:44 +0300
Received: by joker.cs.hut.fi (5.65b/6.8/S-TeKoLa) id AA23011;
Wed, 5 Aug 92 20:44:27 +0300
Received: from sunlight.Stanford.EDU by joker.cs.hut.fi (5.65b/6.8/S-TeKoLa)
id AA23002; Wed, 5 Aug 92 20:43:45 +0300
Received: from elaine29.Stanford.EDU by sunlight.Stanford.EDU (4.1/AIR-1.0)
id AA23764; Wed, 5 Aug 92 10:43:45 PDT
From: bir7@leland.stanford.edu
Message-Id: <9208051743.AA23764@sunlight.Stanford.EDU>
Subject: Re: No Problem with tcpip diffs - alpha 5
Sender: owner-linux-activists@niksula.hut.fi
To: linux-activists@niksula.hut.fi
X-Note1: Remember to put 'X-Mn-Key: normal' to your mail body or header
Date: Wed, 5 Aug 92 10:43:45 PDT
Cc: linux-activists@joker.cs.hut.fi (Linux Activists),
torvalds@kruuna.helsinki.fi (Linus Torvalds)
In-Reply-To: <9208051731.AA11359@sparta.com>; from "Robert T. Harris" at Aug 5, 92 1:31 pm
X-Mailer: ELM [version 2.3 PL11]
X-Mn-Key: NET
> When you are wrong - you are wrong - I was wrong - sorry!
>
> I posted a message describing problems with the tcpip alpha 5 release diffs,
> my problem turned out to be trying to patch using the alpha 4 release diffs. I
> left the old alpha release stuff in /usr/src/inet and thought that it had come
> from alpha 5 - I wondered why I had a duplicate set of diffs at /usr/src!
>
Actually I think there may be problems with the diffs (Coming from
me you should expect that.) They may have part of the profiling code in
them. It seems that they are against a stock .97 kernel without the
profiling code, but the "new" kernel had the profiling code in. If
something strange happens, it might be do to that. Now on to the bugs.
First You will only be able to connect via the loopback interface
for 2 reasons.
1) in line 107 of sock.h in the definition of struct sock:
unsigned long retransmits should be long retransmits
(connect sets it to negative to give more time to make the
connection.)
2) ip.c: ip_compute_csum
unsigned short sum = 0;
should be
unsigned long sum = 0;
(around line 604)
shrl $16, %%eax
adcw %%ax, %%bx
adcw $0, %%bx
should be
shrl $16, %%eax
addw %%ax, %%bx <- changed the 'c' to a 'd'
adcw $0, %%bx
And (this one shouldn't matter.)
(around line 622)
lodsb
movb $0,%%al
should be
lodsb
movb $0, %%ah <-- change the 'l' to a 'h'
With this I can connect using other than the loopback interface.
(It's what I get for rushing and only testing it with itself when
I've made some major changes.)
I'm sorry for the inconvenience.
Ross Biro bir7@leland.stanford.edu
Member League for Programming Freedom (LPF)
mail league@prep.ai.mit.edu for information

BIN
net/tcpip/tcp8p1.tar.Z.uue Normal file

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,2 @@
This is the third tcp patch to 0.98pl5. All three go in without any problem.
This one fixes raw sockets and a few other minor problems.

4
net/tcpip/tcpip.README Normal file
View File

@@ -0,0 +1,4 @@
tcpip.tar.Z contains a working config (and source) as well as
services protocols and the install script. Get the Linux TCP/IP
FAQ for more information on how to set things up.

23
net/tcpip/tcpip.iafa Normal file
View File

@@ -0,0 +1,23 @@
Package-Name: tcpip.8.tar.Z
Title: Linux tcpip configuration and support programs
Version: 1.0
Description: configuration program for Inet sockets for Linux
Author: Ross Biro bir7@leland.stanford.edu
Maintained-by: Author
Maintained-at: Check tsx-11.mit.edu and nic.funet.fi
Platforms: Linux .98pl5+(4 meg of ram may be needed.)
Copying-Policy: Copyrighted Liscensed under GPL
Keywords: tcp ip tcp/ip network ethernet sockets internet

BIN
net/tcpip/tcpip.tar.Z.A5 Normal file

Binary file not shown.

BIN
net/tcpip/tcpip.tar.Z.A6 Normal file

Binary file not shown.

BIN
net/tcpip/tcpip.tar.Z.A7 Normal file

Binary file not shown.

Binary file not shown.