Files
2024-02-19 00:25:04 -05:00

1054 lines
35 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* 3c503.c: A general NS8390 ethernet driver for linux. */
/*
Copyright (C) 1992 Donald Becker
This is alpha test code. No general redistribution is permitted.
This driver should work with the 3Com Etherlink II 3c503 and
(hardwiring the ne2000 variable) the NE1000, NE2000, and NE2000 clones.
The Author may be reached as becker@super.org or
C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
*/
#include <linux/config.h>
#ifdef EI8390
/*
Braindamage remaining:
I mostly do full dispatching on cards now, but you might still have to edit
file until all of the probe code is working. Ideally you could have a
subset of the possible cards configured into the kernel and probed for
at boot time.
We should be able to support multiple, diverse boards
simultaneousely. Pass us 'kmem' at boot time like the drivers in
chr_drv and I'll finish doing the minor bits to put all of the statics
into a structure allocated per-board. Mostly that means putting a few
global statics into an allocated struct, and doing a gensym to get a
new name "ei8390<0-9>".
When everything is working right, I should make it possible to have a
compile-time configuration of a single ethercard type, and not include
the general code.
Sources:
The National Semiconductor LAN Databook, and 3Com databooks, both companies
provided information readily. The NE* info came from the Clarkson 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; buy
a NE2000 _clone_ from someone beside Novell.
*/
#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>
/* If you are having flakey problems put this back in _before_ <io.h>. */
/* #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"
#include "3c503reg.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")
static unsigned short inline inw( unsigned short port )
{ unsigned short _v;
__asm__ volatile ("inw %1,%0"
:"=a" (_v):"d" ((unsigned short) port));
return _v;
}
static void inline outw( unsigned short value, unsigned short port )
{ __asm__ volatile ("outw %0,%1" ::"a" ((unsigned short) value),
"d" ((unsigned short) port));
}
#define EI_NAME "eth_if"
#define SM_TSTART_PG (ei_status.tx_start_page)
#define SM_RSTART_PG (ei_status.rx_start_page)
#define SM_RSTOP_PG (ei_status.stop_page)
#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 NEEI_NAME "NE2000" /* Unused for now. */
/* These are for the ne1000 and are untested */
#define NE1SM_TSTART_PG 0x20 /* First page of TX buffer */
#define NE1SM_RSTART_PG 0x26 /* Starting page of RX ring */
#define NE1SM_RSTOP_PG 0x40 /* Last page +1 of RX ring */
#define NESM_TSTART_PG 0x40 /* First page of TX buffer */
#define NESM_RSTART_PG 0x46 /* Starting page of RX ring */
#define NESM_RSTOP_PG 0x80 /* Last page +1 of RX ring */
#define EL2EI_NAME "3c503" /* Unused for now. */
#define EN_CMD (e8390_base)
#define E8390_BASE (e8390_base)
/* use 0 for production, 1 for devel., >2 for debug */
#ifdef EI_DEBUG
static int ei_debug = EI_DEBUG;
#else
static int ei_debug = 2;
#endif
static int e8390_base;
static struct device *eifdev; /* Only for consistency checking. */
static int etherlink2 = 0, ne2000 = 0, ne1000 = 0;
static struct { /* These 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 word16:1; /* We have the 16-bit (vs 8-bit) version of the card. */
int in_interrupt;
int overruns; /* Rx overruns. */
void (*reset_8390)(struct device *);
void (*block_output)(struct device *, int, const unsigned char *);
int (*block_input)(struct device *, int, char *, int);
int tx_start_page, rx_start_page, stop_page;
int current_page; /* Read pointer in buffer */
int thin_bit; /* Value to write to the 3c503 E33G_CNTRL */
} ei_status = { "eth_if", 0, 0, 0, 0, 0, 0,
NULL, NULL, NULL, 0, 0, 0, 0, ECNTRL_THIN};
/* 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;
/* 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. */
static void NS8390_init(struct device *dev);
static void NS8390_start();
static void NS8390_trigger_send(unsigned int length);
static int el2probe(int ioaddr, unsigned char station_addr[ETHER_ADDR_LEN]);
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);
static int el2_block_input(struct device *dev, int count, char *buf,
int ring_offset);
static int neprobe(int ioaddr, unsigned char station_addr[ETHER_ADDR_LEN]);
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, int count,
const unsigned char *buf);
static void ne_init_card(struct device *dev);
static 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; /* We should have a better error return. */
}
if (etherlink2) {
outb_p(ei_status.thin_bit, E33G_CNTRL);
} else {
ei_reset_8390(dev);
}
NS8390_init(dev);
if (etherlink2) {
/* Set ASIC copy of rx's first and last+1 buffer pages */
/* This must be the same as in the 8390. */
outb_p(EL2SM_RSTART_PG+1, E33G_STARTPG);
outb_p(EL2SM_RSTOP_PG, E33G_STOPPG);
}
NS8390_start();
ei_status.txing = 0;
ei_status.in_interrupt = 0;
ei_status.open = 1;
if (etherlink2)
outb(EGACFR_NORM, E33G_GACFR); /* Enable RAM (redundent?) */
return (0);
}
int
ei_start_xmit(struct sk_buff *skb, struct device *dev)
{
if ( ! ei_status.exists)
return 0; /* We should have a better error return. */
cli();
if (ei_status.txing) { /* Follow the 8003 driver and do timeouts. */
if (jiffies - dev->trans_start < 30) {
sti();
return 1;
}
printk (EI_NAME ": transmit timed out with tx status %#2x.\n",
inb(E8390_BASE+EN0_TSR));
ei_reset_8390(dev);
}
sti();
/* 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); */
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;
ei_status.txing = 1;
ei_send_packet(skb, dev);
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. */
/* 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);
/* Change to page 0 and read the intr status reg. */
outb_p(E8390_NODMA+E8390_PAGE0, EN_CMD);
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;
}
/* !!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);
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;
}
/* This is stuffed into the dev struct to be called by dev.c:dev_tint(). */
static void
ei_send_packet(struct sk_buff *skb, struct device *dev)
{
int length = skb->len;
if (length) {
if (etherlink2)
outb(EGACFR_NORM, E33G_GACFR); /* Enable RAM (redundent?) */
ei_block_output(dev, length, (void*)(skb+1));
NS8390_trigger_send(ETHER_MIN_LEN < length ? length : ETHER_MIN_LEN);
tx_packets++;
}
}
/* We have finished a transmit: check for errors and then put the next
packet in the tx buffer. */
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) {
if (dev_tint(NULL, dev) == 0)
ei_status.txing = 0;
} else { /* Bogus! Transmit error */
tx_errors++;
}
}
/* 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 state = 2;
int num_rx_pages = ei_status.stop_page-ei_status.rx_start_page;
while (state != 1 && ++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) {
static int last_rx_bogosity = -1;
printk(EI_NAME": bogus packet header, status=%#2x nxpg=%#2x sz=%#x (at %#2x)\n",
rx_frame.status, rx_frame.next, rx_frame.count, this_frame);
if (rx_packets != last_rx_bogosity
&& ei_status.rx_start_page <= rx_frame.status
&& rx_frame.status < ei_status.stop_page) {
/* Maybe we can continue without stopping... */
ei_status.current_page = rx_frame.status;
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);
state = 0;
continue;
} else {
/* Oh no Mr Bill! Last ditch error recovery. */
printk(EI_NAME": multiple sequential lossage, resetting at #%d..",
rx_packets);
ei_reset_8390(dev);
NS8390_init(dev);
NS8390_start(dev);
printk("restarting.\n");
return;
}
}
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->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));
state = dev_rint((void *)skb, size, IN_SKBUFF, dev);
} else if (ei_debug) {
printk("Couldn't allocate a sk_buff of size %d.\n", sksize);
state = 0;
break;
}
if (state < 0) continue; /* Redo packet, dev_rint() screwed up */
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++;
state = 0;
}
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 (state != 1 && ++boguscount < 20)
state = dev_rint(NULL, 0, 0, dev);
outb_p(ENISR_RX+ENISR_RX_ERR, 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 boguscount = 0;
printk (EI_NAME ": receiver overrun\n");
/* We should already be stopped and in page0. Remove after testing. */
outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, EN_CMD);
#ifdef notdef
/* The we.c driver does this. Is it to speed up a reset? */
{ unsigned char dummy;
dummy = inb_p( RBCR0 );
dummy = inb_p( RBCR1 );
}
#endif
/* Acknowledge the RX Interrupt. Maybe we should also do RXOVERRUN? */
if (inb_p(E8390_BASE+EN0_ISR) & ENISR_RX )
outb_p(ENISR_RX, E8390_BASE+EN0_ISR);
/* Wait for reset in case the NIX is doing a tx or rx. */
while ((inb_p(E8390_BASE+EN0_ISR) & ENISR_RESET) == 0 )
if (++boguscount > 150000) {
printk(EI_NAME": reset did not complete at ei_rx_overrun.\n");
NS8390_init(dev);
return;
};
/* We should clear out at least one received packet here. */
outb_p(ENISR_RESET, E8390_BASE+EN0_ISR); /* Ack Reset Intr. */
/* 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. */
outb_p(E8390_RXCONFIG, E8390_BASE + EN0_RXCR); /* rx on, */
}
void
ethif_init(struct device *dev)
{
int i;
eifdev = dev; /* Store for debugging. */
e8390_base = dev->base_addr;
if (el2probe(dev->base_addr, dev->dev_addr)) {
ei_status.exists = 1;
etherlink2 = 1;
ei_status.tx_start_page = EL2SM_TSTART_PG;
ei_status.rx_start_page = EL2SM_RSTART_PG;
ei_status.stop_page = EL2SM_RSTOP_PG;
ei_status.reset_8390 = &el2_reset_8390;
ei_status.block_input = &el2_block_input;
ei_status.block_output = &el2_block_output;
el2_init_card(dev);
} else if (neprobe(dev->base_addr, dev->dev_addr)) {
ei_status.exists = 1;
if (ne1000) {
ne2000 = 0;
ei_status.word16 = 0;
ei_status.tx_start_page = NE1SM_TSTART_PG;
ei_status.rx_start_page = NE1SM_RSTART_PG;
ei_status.stop_page = NE1SM_RSTOP_PG;
} else {
ne2000 = 1;
ei_status.word16 = 1;
ei_status.tx_start_page = NESM_TSTART_PG;
ei_status.rx_start_page = NESM_RSTART_PG;
ei_status.stop_page = NESM_RSTOP_PG;
}
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);
} else {
/* What should I do here? Erase dev->open? That crashes the kernel. */
dev->open = &ei_open;
printk("No ethernet device found found.\n");
return;
}
/* 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 = &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;
}
/* This page of functions should be 8390 generic */
/* Follow National Semi's recommendations for initializing the "NIC". */
static void NS8390_init(struct device *dev)
{
int i;
int endcfg = ei_status.word16 ? (0x48 | ENDCFG_WTS) : 0x48;
/* Follow National Semi's recommendations for initing the DP83902. */
outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, EN_CMD); /* 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(SM_TSTART_PG, E8390_BASE + EN0_TPSR);
outb_p(SM_RSTART_PG, E8390_BASE + EN0_STARTPG);
outb_p(SM_RSTOP_PG-1, E8390_BASE + EN0_BOUNDARY); /* 3c503 says 0x3f,NS0x26*/
ei_status.current_page = SM_RSTART_PG; /* assert boundary+1 */
outb_p(SM_RSTOP_PG, 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. */
outb_p(E8390_NODMA + E8390_PAGE1 + E8390_STOP, EN_CMD); /* 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(SM_RSTART_PG, E8390_BASE + EN1_CURPAG);
outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, EN_CMD);
return;
}
/* Start the NIC: 8390 insns to turn on the xmit, rx, and irqs. */
static void
NS8390_start()
{
outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, EN_CMD);
outb_p(0xff, E8390_BASE + EN0_ISR);
outb_p(ENISR_ALL, E8390_BASE + EN0_IMR);
outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, EN_CMD);
outb_p(E8390_TXCONFIG, E8390_BASE + EN0_TXCR); /* xmit on. */
/* 3c503 TechMan says this should only be done 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(unsigned int length)
{
struct device *dev = eifdev;
/* Set everything up again, just to be certain. */
if (etherlink2)
outb_p(0x00, E33G_CNTRL);
outb_p(E8390_NODMA+E8390_PAGE0, EN_CMD);
if (inb_p(EN_CMD) & E8390_TRANS) {
printk(EI_NAME": NS8390_send_packet() called with the transmitter still busy.\n");
/* This might be a good place to bump a counter and recover. */
return;
}
cli();
outb_p(length & 0xff, E8390_BASE + EN0_TCNTLO);
outb_p(length >> 8, E8390_BASE + EN0_TCNTHI);
outb_p(SM_TSTART_PG, E8390_BASE + EN0_TPSR);
outb_p(E8390_NODMA+E8390_TRANS+E8390_START, EN_CMD);
outb_p(ENISR_RDC, E8390_BASE + EN0_ISR);
sti();
return;
}
/* Probe for the Etherlink II card at I/O port base IOADDR,
returning non-zero on sucess. */
static int
el2probe(int ioaddr, unsigned char station_addr[ETHER_ADDR_LEN])
{
int i, found;
/* We check for a 3C503 board by checking the first three octets
of its ethernet address. */
printk("3c503 probe at %#3x:", ioaddr);
outb_p(ECNTRL_RESET, ioaddr + 0x406); /* Reset it... */
outb_p(0, ioaddr + 0x406);
/* Map the station addr PROM into the lower I/O ports. */
outb(ECNTRL_SAPROM, 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(0, ioaddr + 0x406);
found =( station_addr[0] == 0x02
&& station_addr[1] == 0x60
&& station_addr[2] == 0x8c);
printk(" 3C503 %sfound.\n", found ? "":"not ");
return found;
}
/* These functions are somewhat Clarkson packet driver-like. */
/* Right now this is only called when we have a transmit timeout. */
static void
el2_reset_8390(struct device *dev)
{
/* Reset the board. */
outb_p(ECNTRL_RESET | ei_status.thin_bit, E33G_CNTRL);
outb(EGACFR_NORM, E33G_GACFR); /* Enable RAM and irqs */
outb_p(ei_status.thin_bit, E33G_CNTRL);
ei_status.txing = 0;
/* Doing a 'NS8390_init(dev)' here wouldn't hurt... */
}
/* Initialize the card and fill in STATION_ADDR with the station address.
The 3c503 maps the SA PROM into its lower I/O port bank. */
static void
el2_init_card(struct device *dev)
{
int i, mem_jumpers;
int pirq;
/* Unmap the station PROM and turn on the thinnet connector. */
outb(ei_status.thin_bit, E33G_CNTRL);
/* 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, E8390_BASE + EN0_IMR);
outb_p(EGACFR_IRQOFF, E33G_GACFR);
/* Probe for, turn on and clear the board's shared memory. */
mem_jumpers = inb(E33G_ROMBASE);
if (mem_jumpers & 0xf0 == 0) {
dev->mem_start = 0;
printk(EI_NAME": no shared memory mapped\n");
} else {
int *mem_base;
dev->mem_start = ((mem_jumpers & 0xc0) ? 0xD8000 : 0xC8000) +
((mem_jumpers & 0xA0) ? 0x4000 : 0);
mem_base = (int *)dev->mem_start;
printk(EI_NAME": shared memory at %#6X\n", mem_base);
/* Check the card's memory. */
for (i = 0; i < (SM_RSTOP_PG - SM_TSTART_PG)*256/sizeof(mem_base[0]);
i++) {
mem_base[i] = 0xAA425542;
if (mem_base[i] != 0xAA425542) {
printk(EI_NAME": memory failure or memory address conflict.\n");
dev->mem_start = 0;
break;
}
mem_base[i] = 0;
}
/* 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 = i * sizeof(mem_base[0]);
dev->rmem_start = (SM_RSTART_PG - SM_TSTART_PG) * 256;
}
pirq = (dev->irq == 9 ? 2 : dev->irq);
if (pirq > 5 || pirq < 2) {
printk(EI_NAME": configured interrupt number %d out of range.\n",
dev->irq);
return; /* Return failure someday */
} else if (irqaction (dev->irq, &ei_sigaction)) {
printk (EI_NAME ": Unable to get IRQ%d.\n", dev->irq);
return; /* Return failure someday */
} else {
/* We could look for other free interrupts here, or something... */
}
outb_p((0x04 << pirq), E33G_IDCFR); /* Set the interrupt line. */
outb_p(8, E33G_NBURST); /* Set burst size to 8 */
outb_p(0x21, E33G_DMAAH); /* Set up transmit bfr in DMA addr */
outb_p(0x00, E33G_DMAAL);
return; /* Return success */
}
/* 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)
{
int i; /* Buffer index */
int boguscount = 0; /* timeout counter */
if (dev->mem_start) { /* Shared memory transfer */
outb(EGACFR_NORM, E33G_GACFR); /* Enable RAM */
memcpy((char *)dev->mem_start, buf, count);
return;
}
/* Set up then start the internal memory transfer to SM_TSTART_PG */
outb(0x00, E33G_DMAAL);
outb(SM_TSTART_PG, 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 checking the status bit. */
for(i = 0; i < count; i++) {
while (inb(E33G_STATUS) & ESTAT_DPRDY == 0)
if (++boguscount > 150000) {
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;
/* Maybe enable shared memory just be to be safe... nahh.*/
if (dev->mem_start) { /* Use the shared memory. */
if (ring_offset + count >= end_of_ring) {
/* We must wrap the input move. */
int semi_count = end_of_ring - ring_offset;
memcpy(buf, (char *)dev->mem_start + ring_offset, semi_count);
buf += semi_count, count -= semi_count;
ring_offset = dev->rmem_start;
}
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++) {
while (inb(E33G_STATUS) & ESTAT_DPRDY == 0)
if (++boguscount > 150000) {
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;
}
}
/* Routines for the NE2000. */
#define NE_BASE (e8390_base)
#define NE_DATAPORT 0x10 /* NE2000 Port Window. */
#define NE_RESET 0x1f /* Issue a read for reset */
#define longpause()\
do { int start_time = jiffies; while(jiffies-start_time < 18) ;\
} while(0)
/* Probe for the NE1000 and NE2000. NE2000-like boards have 0x57,0x57 in
bytes 0x0e,0x0f of the SAPROM. I'm not certain yet what to do about
the NE1000! */
/* Also initialize the card and fill in STATION_ADDR with the station address.
The on-board data is stored where other cards have shared memory,
32 bytes starting at remote DMA address 0. */
static int neprobe(int ioaddr, unsigned char station_addr[ETHER_ADDR_LEN])
{
int i;
unsigned char ne_board_data[32];
int found, cmdreg;
printk("NE2000 probing 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);*/
outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, ioaddr);
outb_p(0x49, ioaddr + EN0_DCFG); /* Set word-wide for probe. */
/* 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, E8390_BASE + EN0_ISR);
/* Set to monitor and loopback mode. */
outb_p(E8390_RXOFF, E8390_BASE + EN0_RXCR); /* 0x20 */
outb_p(E8390_TXOFF, E8390_BASE + EN0_TXCR); /* 0x02 */
/* Double count 0x20 words, the SA PROM is only byte wide. */
outb_p(2*sizeof(ne_board_data), ioaddr + EN0_RCNTLO);
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(ne_board_data); i++) {
ne_board_data[i] = inb_p(ioaddr + NE_DATAPORT);
if (i < ETHER_ADDR_LEN && station_addr) {
printk(" %#2.2x", ne_board_data[i]);
station_addr[i] = ne_board_data[i];
}
}
found = ne_board_data[14] == 0x57 && ne_board_data[15] == 0x57;
printk(" %sfound.\n", found ? "" : "not ");
return found;
}
static void
ne_reset_8390(struct device *dev)
{
int tmp = inb_p(NE_BASE + NE_RESET);
ei_status.txing = 0;
longpause(); /* We should wait a few jiffies... */
outb_p(tmp, NE_BASE + NE_RESET);
}
/* Block input and output, based on the Clarkson packet driver.
The NE2000 doesn't have shared memory on the board -- put the packet
out through the ASIC FIFO. This is probably very slow. */
static int
ne_block_input(struct device *dev, int count, char *buf, int ring_offset)
{
outb_p(E8390_PAGE0+E8390_START, EN_CMD);
outb_p(count & 0xff, E8390_BASE + EN0_RCNTLO);
outb_p(count >> 8, E8390_BASE + EN0_RCNTHI);
outb_p(ring_offset & 0xff, E8390_BASE + EN0_RSARLO);
outb_p(ring_offset >> 8, E8390_BASE + EN0_RSARHI);
outb_p(E8390_RREAD+E8390_START, EN_CMD);
if (!ne1000) {
port_read(E8390_BASE + NE_DATAPORT,buf,count>>1);
if (count & 0x01)
buf[count-1] = inb(E8390_BASE + NE_DATAPORT);
} else {
int i;
/* Input the bytes with a slow 8-bit loop. Tune this someday. */
for(i = 0; i < count; i++) {
buf[i] = inb_p(E8390_BASE + NE_DATAPORT);
}
}
return ring_offset + count;
}
/* Issues to be resolved for the NE1000: we don't need to round the byte
count up, and the dummy read only needs (count+1), not (count+2). */
static void
ne_block_output(struct device *dev, int count, const unsigned char *buf)
{
int i;
int boguscount = 0, tries = 0;
/* Round the count up. This is for word writes on the NE2000, but do
we need to do it? What effect will an odd byte count have on the
8390? */
if (count & 0x01)
count++;
restart:
boguscount = 0;
/* We should already be in page 0, but to be safe... */
outb_p(E8390_PAGE0+E8390_START, EN_CMD);
/* This following dummy-read-first sequence is suggested by
NatSemi to avoid a bug in the 8390. */
outb_p((count+2) & 0xff, NE_BASE + EN0_RCNTLO);
outb_p((count+2) >> 8, NE_BASE + EN0_RCNTHI);
outb_p(0xfe, NE_BASE + EN0_RSARLO);
outb_p(ei_status.tx_start_page-1, NE_BASE + EN0_RSARHI);
outb_p(E8390_RREAD+E8390_START, EN_CMD);
/* Make certain that the dummy read has occured -- strange bugs can
occur otherwise. */
while (inb_p(NE_BASE + EN0_RSARLO) != 0x00)
if (++boguscount > 10) {
printk(EI_NAME": Failed to write packet (addrlo=%#2x).\n",
inb_p(NE_BASE + EN0_RSARLO));
if (++tries < 3)
goto restart; /* 8390 burped? */
return; /* Splat... drop the packet..should reset? */
}
outb_p(E8390_RWRITE+E8390_START, EN_CMD);
if (ne1000) {
/* Output the bytes with a slow 8-bit loop. This actually is almost
as fast as possible, but it does tie up the processor. */
for(i = 0; i < count; i++)
outb_p(buf[i], NE_BASE + NE_DATAPORT);
} else /* NE2000 */
/* Use the 'rep' sequence for the NE2000. */
port_write(E8390_BASE + NE_DATAPORT, buf, count>>1);
while (inb_p(EN0_ISR) & ENISR_RDC == 0) /* DMA done? */
if (++boguscount > 15000) {
printk(EI_NAME": Timed out doing ne_block_output(%d).\n", count);
return;
}
/* This is for the ALPHA version only, remove for later releases. */
if (ei_debug > 0) { /* DMA termination address check... */
int low = inb_p(NE_BASE + EN0_RSARLO);
int high = inb_p(NE_BASE + EN0_RSARHI);
int addr = (high << 8) + low;
if ((ei_status.tx_start_page << 8) + count != addr)
printk(EI_NAME": TX Transfer address mismatch, %#4.4x vs. %#4.4x.\n",
(ei_status.tx_start_page << 8) + count, addr);
}
return;
}
/* This function resets the ethercard if something screws up. */
static void
ne_init_card(struct device *dev)
{
NS8390_init(dev);
/* Snarf the interrupt. We could share or wait until open(), but... */
{ int irqval = irqaction (dev->irq, &ei_sigaction);
if (irqval)
printk (EI_NAME": unable to get IRQ%d, error=%d.\n", dev->irq, irqval);
}
return;
}
/*
* Local variables:
* compile-command: "gcc -DKERNEL -Wall -O6 -fomit-frame-pointer -DEI_DEBUG=3 -I/usr/linux-master/net/tcp -c -o 3c503.o 3c503.c"
* version-control: t
* kept-new-versions: 5
* End:
*/
#endif /* EI8390 */