M pc/devether.c => pc/devether.c +51 -30
@@ 15,20 15,20 @@
* handle multiple controllers
* much tidying
* set ethernet address
+ * need a ctl file passed down to card drivers
+ * so we can set options.
*/
-extern Board ether8003;
-extern Board ether503;
-extern Board ether2000;
-extern Board ether509;
+extern Card ether8003, ether503, ether2000;
+extern Card ether509;
/*
- * The ordering here is important for those boards
- * using the DP8390 (WD8003, 3COM503 and NE2000) as
- * attempting to determine if a board is a NE2000
+ * The ordering here is important for those cards
+ * using the DP8390 (WD8003, 3Com503 and NE2000) as
+ * attempting to determine if a card is a NE2000
* cannot be done passively, so it must be last to
* prevent scrogging one of the others.
*/
-static Board *boards[] = {
+static Card *cards[] = {
ðer8003,
ðer503,
ðer2000,
@@ 41,7 41,7 @@ enum {
NCtlr = 1,
};
-static struct Ctlr *softctlr[NCtlr];
+/*static */struct Ctlr *softctlr[NCtlr];
static int nctlr;
Chan*
@@ 123,7 123,7 @@ etheroput(Queue *q, Block *bp)
Type *type;
Etherpkt *pkt;
RingBuf *ring;
- int len, n;
+ int len, n, s;
Block *nbp;
type = q->ptr;
@@ 141,7 141,7 @@ etheroput(Queue *q, Block *bp)
type->prom = 1;
ctlr->prom++;
if(ctlr->prom == 1)
- (*ctlr->board->mode)(ctlr, 1);
+ (*ctlr->card.mode)(ctlr, 1);
}
qunlock(ctlr);
freeb(bp);
@@ 179,8 179,8 @@ etheroput(Queue *q, Block *bp)
*/
qlock(&ctlr->tlock);
if(waserror()){
- freeb(bp);
qunlock(&ctlr->tlock);
+ freeb(bp);
nexterror();
}
@@ 188,7 188,15 @@ etheroput(Queue *q, Block *bp)
* Wait till we get an output buffer.
* should try to restart.
*/
- sleep(&ctlr->tr, isobuf, ctlr);
+ if(isobuf(ctlr) == 0){
+ tsleep(&ctlr->tr, isobuf, ctlr, 3*1000);
+ if(isobuf(ctlr) == 0){
+ qunlock(&ctlr->tlock);
+ freeb(bp);
+ poperror();
+ return;
+ }
+ }
ring = &ctlr->tb[ctlr->th];
@@ 217,14 225,15 @@ etheroput(Queue *q, Block *bp)
* Set up the transmit buffer and
* start the transmission.
*/
- ctlr->outpackets++;
+ s = splhi();
ring->len = len;
ring->owner = Interface;
ctlr->th = NEXT(ctlr->th, ctlr->ntb);
- (*ctlr->board->transmit)(ctlr);
+ (*ctlr->card.transmit)(ctlr);
+ splx(s);
- freeb(bp);
qunlock(&ctlr->tlock);
+ freeb(bp);
poperror();
}
@@ 267,7 276,7 @@ etherstclose(Queue *q)
qlock(ctlr);
ctlr->prom--;
if(ctlr->prom == 0)
- (*ctlr->board->mode)(ctlr, 0);
+ (*ctlr->card.mode)(ctlr, 0);
qunlock(ctlr);
}
if(type->type == -1){
@@ 407,8 416,8 @@ etherkproc(void *arg)
if(waserror()){
print("%s noted\n", ctlr->name);
/* fix
- if(ctlr->board->reset)
- (*ctlr->board->reset)(ctlr);
+ if(ctlr->card.reset)
+ (*ctlr->card.reset)(ctlr);
*/
ctlr->kproc = 0;
nexterror();
@@ 416,8 425,8 @@ etherkproc(void *arg)
for(;;){
tsleep(&ctlr->rr, isinput, ctlr, 500);
- if(ctlr->board->watch)
- (*ctlr->board->watch)(ctlr);
+ if(ctlr->card.watch)
+ (*ctlr->card.watch)(ctlr);
/*
* Process any internal loopback packets.
@@ 460,22 469,25 @@ etherintr(Ureg *ur)
Ctlr *ctlr = softctlr[0];
USED(ur);
- (*ctlr->board->intr)(ctlr);
+ (*ctlr->card.intr)(ctlr);
}
void
etherreset(void)
{
Ctlr *ctlr;
- Board **board;
+ Card **card;
int i;
+ if(nctlr >= NCtlr)
+ return;
if(softctlr[nctlr] == 0)
softctlr[nctlr] = xalloc(sizeof(Ctlr));
ctlr = softctlr[nctlr];
- for(board = boards; *board; board++){
- ctlr->board = *board;
- if((*ctlr->board->reset)(ctlr) == 0){
+ for(card = cards; *card; card++){
+ memset(ctlr, 0, sizeof(Ctlr));
+ ctlr->card = **card;
+ if((*ctlr->card.reset)(ctlr) == 0){
ctlr->present = 1;
/*
@@ 483,14 495,23 @@ etherreset(void)
* controllers together. A device set to IRQ2 will appear on
* the second interrupt controller as IRQ9.
*/
- if(ctlr->board->irq == 2)
- ctlr->board->irq = 9;
- setvec(Int0vec + ctlr->board->irq, etherintr);
+ if(ctlr->card.irq == 2)
+ ctlr->card.irq = 9;
+ setvec(Int0vec + ctlr->card.irq, etherintr);
break;
}
}
if(ctlr->present == 0)
return;
+
+ print("ether%d: %s: I/O addr %lux width %d addr %lux size %d irq %d:",
+ nctlr, ctlr->card.id,
+ ctlr->card.io, ctlr->card.bit16 ? 16: 8, ctlr->card.ramstart,
+ ctlr->card.ramstop-ctlr->card.ramstart, ctlr->card.irq);
+ for(i = 0; i < sizeof(ctlr->ea); i++)
+ print(" %2.2ux", ctlr->ea[i]);
+ print("\n");
+
nctlr++;
if(ctlr->nrb == 0)
@@ 551,7 572,7 @@ etherattach(char *spec)
* Enable the interface
* and start the kproc.
*/
- (*ctlr->board->attach)(ctlr);
+ (*ctlr->card.attach)(ctlr);
if(ctlr->kproc == 0){
sprint(ctlr->name, "ether%dkproc", ctlrno);
ctlr->kproc = 1;
M pc/ether.h => pc/ether.h +69 -43
@@ 1,7 1,7 @@
/*
* All the goo for PC ethernet cards.
*/
-typedef struct Board Board;
+typedef struct Card Card;
typedef struct RingBuf RingBuf;
typedef struct Type Type;
typedef struct Ctlr Ctlr;
@@ 9,27 9,34 @@ typedef struct Ctlr Ctlr;
/*
* Hardware interface.
*/
-struct Board {
+struct Card {
+ char id[NAMELEN]; /* type of card */
+
int (*reset)(Ctlr*);
void (*init)(Ctlr*);
void (*attach)(Ctlr*);
void (*mode)(Ctlr*, int);
+ void *(*read)(Ctlr*, void*, ulong, ulong);
+ void *(*write)(Ctlr*, ulong, void*, ulong);
+
void (*receive)(Ctlr*);
void (*transmit)(Ctlr*);
void (*intr)(Ctlr*);
void (*watch)(Ctlr*);
+ void (*overflow)(Ctlr*);
- ulong io; /* interface I/O base address */
+ ulong io; /* card I/O base address */
uchar irq; /* interrupt level */
uchar bit16; /* true if a 16 bit interface */
- uchar ram; /* true if interface has shared memory */
- ulong ramstart; /* interface shared memory address start */
- ulong ramstop; /* interface shared memory address end */
+ uchar ram; /* true if card has shared memory */
+ ulong ramstart; /* card shared memory address start */
+ ulong ramstop; /* card shared memory address end */
ulong dp8390; /* I/O address of 8390 (if any) */
ulong data; /* I/O data port if no shared memory */
+ uchar nxtpkt; /* software bndry */
uchar tstart; /* 8390 ring addresses */
uchar pstart;
uchar pstop;
@@ 40,17 47,17 @@ struct Board {
*/
struct RingBuf {
uchar owner;
- uchar busy;
+ uchar busy; /* unused */
ushort len;
uchar pkt[sizeof(Etherpkt)];
};
enum {
- Host = 0, /* buffer owned by host */
- Interface = 1, /* buffer owned by interface */
+ Host = 0, /* buffer owned by host */
+ Interface = 1, /* buffer owned by card */
- Nrb = 16, /* default number of receive buffers */
- Ntb = 4, /* default number of transmit buffers */
+ Nrb = 16, /* default number of receive buffers */
+ Ntb = 4, /* default number of transmit buffers */
};
/*
@@ 58,19 65,19 @@ enum {
*/
struct Type {
QLock;
- Netprot; /* stat info */
- int type; /* ethernet type */
- int prom; /* promiscuous mode */
+ Netprot; /* stat info */
+ int type; /* ethernet type */
+ int prom; /* promiscuous mode */
Queue *q;
int inuse;
Ctlr *ctlr;
- Rendez cr; /* rendezvous for close */
- Type *clist; /* close list */
+ Rendez cr; /* rendezvous for close */
+ Type *clist; /* close list */
};
enum {
- NType = 9, /* types/interface */
+ NType = 9, /* types/card */
};
/*
@@ 79,44 86,46 @@ enum {
struct Ctlr {
QLock;
- Board *board;
+ Card card; /* hardware info */
int present;
+ int debug;
- ushort nrb; /* number of software receive buffers */
- ushort ntb; /* number of software transmit buffers */
- RingBuf *rb; /* software receive buffers */
- RingBuf *tb; /* software transmit buffers */
+ ushort nrb; /* number of software receive buffers */
+ ushort ntb; /* number of software transmit buffers */
+ RingBuf *rb; /* software receive buffers */
+ RingBuf *tb; /* software transmit buffers */
- uchar ea[6]; /* ethernet address */
- uchar ba[6]; /* broadcast address */
+ uchar ea[6]; /* ethernet address */
+ uchar ba[6]; /* broadcast address */
- Rendez rr; /* rendezvous for a receive buffer */
- ushort rh; /* first receive buffer belonging to host */
- ushort ri; /* first receive buffer belonging to interface */
+ Rendez rr; /* rendezvous for a receive buffer */
+ ushort rh; /* first receive buffer belonging to host */
+ ushort ri; /* first receive buffer belonging to card */
- Rendez tr; /* rendezvous for a transmit buffer */
- QLock tlock; /* semaphore on th */
- ushort th; /* first transmit buffer belonging to host */
- ushort ti; /* first transmit buffer belonging to interface */
+ Rendez tr; /* rendezvous for a transmit buffer */
+ QLock tlock; /* semaphore on th */
+ ushort th; /* first transmit buffer belonging to host */
+ ushort ti; /* first transmit buffer belonging to card */
+ int tbusy; /* transmitter is busy */
Type type[NType];
- int all; /* number of channels listening to all packets */
- Type *clist; /* channels waiting to close */
- Lock clock; /* lock for clist */
- int prom; /* number of promiscuous channels */
- int kproc; /* true if kproc started */
- char name[NAMELEN]; /* name of kproc */
+ int all; /* number of channels listening to all packets */
+ Type *clist; /* channels waiting to close */
+ Lock clock; /* lock for clist */
+ int prom; /* number of promiscuous channels */
+ int kproc; /* true if kproc started */
+ char name[NAMELEN]; /* name of kproc */
Network net;
- Queue lbq; /* software loopback packet queue */
+ Queue lbq; /* software loopback packet queue */
int inpackets;
int outpackets;
- int crcs; /* input crc errors */
- int oerrs; /* output errors */
- int frames; /* framing errors */
- int overflows; /* packet overflows */
- int buffs; /* buffering errors */
+ int crcs; /* input crc errors */
+ int oerrs; /* output errors */
+ int frames; /* framing errors */
+ int overflows; /* packet overflows */
+ int buffs; /* buffering errors */
};
#define NEXT(x, l) (((x)+1)%(l))
@@ 133,9 142,26 @@ extern void dp8390attach(Ctlr*);
extern void dp8390mode(Ctlr*, int);
extern void dp8390setea(Ctlr*);
extern void *dp8390read(Ctlr*, void*, ulong, ulong);
+extern void *dp8390write(Ctlr*, ulong, void*, ulong);
extern void dp8390receive(Ctlr*);
extern void dp8390transmit(Ctlr*);
extern void dp8390intr(Ctlr*);
+extern void dp8390watch(Ctlr*);
+extern void dp8390overflow(Ctlr*);
+
+extern void dp8390debug(Ctlr*);
+
+/*
+ * The DP8390 needs some time between successive
+ * chip selects, so we need special I/O routines.
+ * See l.s.
+ * These routines only need to be used for accessing
+ * the chip registers. Data I/O, either through
+ * remote DMA or shared memory, can use the normal
+ * routines.
+ */
+extern int dp8390inb(ulong);
+extern void dp8390outb(ulong, uchar);
enum {
Dp8390BufSz = 256, /* hardware ring buffer size */
M pc/ether2000.c => pc/ether2000.c +36 -37
@@ 15,9 15,9 @@
* laptop. The manual says NE2000 compatible.
* The interface appears to be pretty well described in the National
* Semiconductor Local Area Network Databook (1992) as one of the
- * AT evaluation boards.
+ * AT evaluation cards.
*
- * The NE2000 is really just a DP8390 plus a data port
+ * The NE2000 is really just a DP83901 plus a data port
* and a reset port.
*/
enum {
@@ 28,7 28,6 @@ enum {
static int
reset(Ctlr *ctlr)
{
- Board *board = ctlr->board;
ushort buf[16];
int i;
@@ 36,12 35,12 @@ reset(Ctlr *ctlr)
* We look for boards.
* We look for boards to make us barf.
*/
- for(board->io = 0x300; board->io < 0x380; board->io += 0x20){
+ for(ctlr->card.io = 0x300; ctlr->card.io < 0x380; ctlr->card.io += 0x20){
/*
* Reset the board. This is done by doing a read
* followed by a write to the Reset address.
*/
- outb(board->io+Reset, inb(board->io+Reset));
+ outb(ctlr->card.io+Reset, inb(ctlr->card.io+Reset));
/*
* Init the (possible) chip, then use the (possible)
@@ 52,17 51,16 @@ reset(Ctlr *ctlr)
* enough, there are other ethernet boards which could
* match.
*/
- board->dp8390 = board->io;
- board->data = board->io+Data;
+ ctlr->card.dp8390 = ctlr->card.io;
+ ctlr->card.data = ctlr->card.io+Data;
dp8390reset(ctlr);
memset(buf, 0, sizeof(buf));
dp8390read(ctlr, buf, 0, sizeof(buf));
- if(buf[0x0E] == 0x57 && buf[0x0F] == 0x57)
+ if((buf[0x0E] & 0xFF) == 0x57 && (buf[0x0F] & 0xFF) == 0x57)
break;
}
- if(board->io >= 0x380)
+ if(ctlr->card.io >= 0x380)
return -1;
-
/*
* Stupid machine. We asked for shorts, we got shorts,
* although the PROM is a byte array.
@@ 72,37 70,38 @@ reset(Ctlr *ctlr)
ctlr->ea[i] = buf[i];
dp8390setea(ctlr);
- print("NE2000 I/O addr %lux width %d addr %lux size %d irq %d:",
- board->io, board->bit16 ? 16: 8, board->ramstart,
- board->ramstop-board->ramstart, board->irq);
- for(i = 0; i < sizeof(ctlr->ea); i++)
- print(" %2.2ux", ctlr->ea[i]);
- print("\n");
-
return 0;
}
-Board ether2000 = {
- reset,
- 0, /* init */
- dp8390attach,
- dp8390mode,
- dp8390receive,
- dp8390transmit,
- dp8390intr,
- 0, /* watch */
+Card ether2000 = {
+ "NE2000", /* ident */
+
+ reset, /* reset */
+ 0, /* init */
+ dp8390attach, /* attach */
+ dp8390mode, /* mode */
+
+ dp8390read, /* read */
+ dp8390write, /* write */
+
+ dp8390receive, /* receive */
+ dp8390transmit, /* transmit */
+ dp8390intr, /* interrupt */
+ dp8390watch, /* watch */
+ dp8390overflow, /* overflow */
- 0x300, /* addr */
- 2, /* irq */
- 1, /* bit16 */
+ 0x300, /* addr */
+ 2, /* irq */
+ 1, /* bit16 */
- 0, /* ram */
- 0x4000, /* ramstart */
- 0x4000+16*1024, /* ramstop */
+ 0, /* ram */
+ 0x4000, /* ramstart */
+ 0x4000+16*1024, /* ramstop */
- 0x300, /* dp8390 */
- 0x300+Data, /* data */
- 0x4000/Dp8390BufSz, /* tstart */
- 0x4600/Dp8390BufSz, /* pstart */
- 0x8000/Dp8390BufSz, /* pstop */
+ 0x300, /* dp8390 */
+ 0x300+Data, /* data */
+ 0, /* software bndry */
+ 0x4000/Dp8390BufSz, /* tstart */
+ 0x4600/Dp8390BufSz, /* pstart */
+ 0x8000/Dp8390BufSz, /* pstop */
};
M pc/ether503.c => pc/ether503.c +321 -25
@@ 9,35 9,331 @@
#include "ether.h"
+/*
+ * 3Com 503 (EtherLink II).
+ * This driver doesn't work under load, the card gets blasted by
+ * overwrite-warning interrupts and eventually just hangs. Always clearing
+ * the Ovw bit in the DP8390 Isr along with the Rxe and Prx bits stops
+ * the overwrite-warning interrupts, but the card eventually hangs anyway.
+ * I really don't understand why this card doesn't work,
+ * there is plenty of evidence that other systems manage to use it.
+ * The only good thing about this driver is that both shared
+ * memory and polled I/O work (given the above restraints), although
+ * the polled I/O should be tuned.
+ */
+enum { /* Gate Array Registers */
+ Pstr = 0x400, /* Page Start Register */
+ Pspr = 0x401, /* Page Stop Register */
+ Dqtr = 0x402, /* Drq Timer Register */
+ Bcfr = 0x403, /* Base Configuration Register */
+ Pcfr = 0x404, /* EPROM Configuration Register */
+ Gacfr = 0x405, /* GA Configuration Register */
+ Ctrl = 0x406, /* Control Register */
+ Streg = 0x407, /* Status Register */
+ Idcfr = 0x408, /* Interrupt/DMA Configuration Register */
+ Damsb = 0x409, /* DMA Address Register MSB */
+ Dalsb = 0x40A, /* DMA Address Register LSB */
+ Vptr2 = 0x40B, /* Vector Pointer Register 2 */
+ Vptr1 = 0x40C, /* Vector Pointer Register 1 */
+ Vptr0 = 0x40D, /* Vector Pointer Register 0 */
+ Rfmsb = 0x40E, /* Register File Access MSB */
+ Rflsb = 0x40F, /* Register File Access LSB */
+};
+
+enum { /* Pcfr */
+ C8xxx = 0x10, /* memory address 0xC8000 */
+ CCxxx = 0x20, /* memory address 0xCC000 */
+ D8xxx = 0x40, /* memory address 0xD8000 */
+ DCxxx = 0x80, /* memory address 0xDC000 */
+};
+
+enum { /* Gacfr */
+ Mbs0 = 0x01, /* memory bank select 0 */
+ Mbs1 = 0x02, /* memory bank select 1 */
+ Mbs2 = 0x04, /* memory bank select 2 */
+ Rsel = 0x08, /* RAM select */
+ Test = 0x10, /* test */
+ Ows = 0x20, /* 0 wait state */
+ Tcm = 0x40, /* terminal count mask */
+ Nim = 0x80, /* MIC interrupt mask */
+};
+
+enum { /* Ctrl */
+ Rst = 0x01, /* software reset */
+ Xsel = 0x02, /* transceiver select (BNC = 1, AUI = 0) */
+ Ealo = 0x04, /* ethernet address low */
+ Eahi = 0x08, /* ethernet address high */
+ Share = 0x10, /* interrupt share */
+ Dbsel = 0x20, /* double buffer select */
+ Ddir = 0x40, /* DMA direction */
+ Start = 0x80, /* DMA start */
+};
+
+enum { /* Streg */
+ Rev0 = 0x01, /* gate array revision bit 0 */
+ Rev1 = 0x02, /* gate array revision bit 1 */
+ Rev2 = 0x04, /* gate array revision bit 2 */
+ Dip = 0x08, /* DMA in progress */
+ Dtc = 0x10, /* DMA terminal count */
+ Oflw = 0x20, /* overflow */
+ Uflw = 0x40, /* underflow */
+ Dprdy = 0x80, /* data port ready */
+};
+
+enum { /* Idcfr */
+ Drq1 = 0x01, /* DMA request 1 */
+ Drq2 = 0x02, /* DMA request 2 */
+ Drq3 = 0x04, /* DMA request 3 */
+ Irq2 = 0x10, /* interrupt request 2 */
+ Irq3 = 0x20, /* interrupt request 3 */
+ Irq4 = 0x40, /* interrupt request 4 */
+ Irq5 = 0x80, /* interrupt request 5 */
+};
+
+enum {
+ RamOffset = 0x2000, /* where the card sees the shared memory */
+};
+
+typedef struct {
+ ulong io; /* I/O base address */
+ uchar irq; /* interrupt level */
+ uchar bnc; /* use BNC connector */
+} Table;
+
+/*
+ * The only configuration info we can get from the card is the
+ * I/O base address and the shared-memory address. So let's make
+ * a little hard-wired configuration table.
+ */
+static Table table[] = {
+ { 0x300, Irq2, 0, }, /* external transceiver */
+ { 0x310, Irq3, 0, },
+ { 0x330, Irq4, 0, },
+ { 0x350, Irq5, 0, },
+
+ { 0x250, Irq2, 1, }, /* BNC */
+ { 0x280, Irq3, 1, },
+ { 0x2A0, Irq4, 1, },
+ { 0x2E0, Irq5, 1, },
+
+ { 0 },
+};
+
static int
reset(Ctlr *ctlr)
{
- USED(ctlr);
+ Table *tp;
+ int i;
+ uchar cfr;
+
+ /*
+ * The Gate Array Ctrl register bits <3,2> determine what is
+ * mapped at the I/O base address. The options are the DP8390,
+ * PROM bytes 0-15 or PROM bytes 16-31.
+ * At power-on, the I/O base address contains PROM bytes 16-31.
+ */
+ for(tp = table; ctlr->card.io = tp->io; tp++){
+ /*
+ * Toggle the software reset bit, this should initialise the
+ * Ctrl register to 0x0A (Eahi|Xsel).
+ * Hopefully there is no other card at the gate-array address.
+ */
+ outb(ctlr->card.io+Ctrl, Rst);
+ delay(1);
+ outb(ctlr->card.io+Ctrl, 0);
+ if(inb(ctlr->card.io+Ctrl) == (Eahi|Xsel))
+ break;
+ }
+ if(ctlr->card.io == 0)
+ return -1;
+
+ /*
+ * Map PROM bytes 0-15 to the I/O base address
+ * and read the ethernet address.
+ * When done, map the DP8390 at the I/O base address
+ * and set the transceiver type and irq.
+ */
+ outb(ctlr->card.io+Ctrl, Ealo|Xsel);
+ for(i = 0; i < sizeof(ctlr->ea); i++)
+ ctlr->ea[i] = inb(ctlr->card.io+i);
+
+ outb(ctlr->card.io+Gacfr, Nim|Tcm);
+
+ outb(ctlr->card.io+Ctrl, 0|tp->bnc);
+ outb(ctlr->card.io+Idcfr, tp->irq);
+
+ if(tp->irq == Irq2)
+ ctlr->card.irq = 2;
+ else if(tp->irq == Irq3)
+ ctlr->card.irq = 3;
+ else if(tp->irq == Irq4)
+ ctlr->card.irq = 4;
+ else if(tp->irq == Irq5)
+ ctlr->card.irq = 5;
+ else
+ return -1;
- return -1;
+ /*
+ * Try to configure the shared memory.
+ * Assume this is an 8K card.
+ */
+ ctlr->card.ram = 1;
+ cfr = inb(ctlr->card.io+Pcfr);
+ if(cfr & C8xxx)
+ ctlr->card.ramstart = KZERO|0xC8000;
+ else if(cfr & CCxxx)
+ ctlr->card.ramstart = KZERO|0xCC000;
+ else if(cfr & D8xxx)
+ ctlr->card.ramstart = KZERO|0xD8000;
+ else if(cfr & DCxxx)
+ ctlr->card.ramstart = KZERO|0xDC000;
+ else
+ ctlr->card.ram = 0;
+
+ ctlr->card.ramstop = ctlr->card.ramstart + 8*1024;
+
+ /*
+ * Finish initialising the gate-array.
+ * The Pstr and Pspr registers must be the same as those
+ * given to the DP8390.
+ * Gacfr is set to enable shared memory and block DMA
+ * interrupts.
+ */
+ outb(ctlr->card.io+Pstr, ctlr->card.pstart);
+ outb(ctlr->card.io+Pspr, ctlr->card.pstop);
+
+ outb(ctlr->card.io+Dqtr, 8);
+ outb(ctlr->card.io+Damsb, ctlr->card.tstart);
+ outb(ctlr->card.io+Dalsb, 0);
+
+ outb(ctlr->card.io+Vptr2, 0xFF);
+ outb(ctlr->card.io+Vptr1, 0xFF);
+ outb(ctlr->card.io+Vptr0, 0x00);
+
+ /*
+ * Finally, init the 8390, set the ethernet address
+ * and turn on the shared memory if any.
+ */
+ ctlr->card.dp8390 = ctlr->card.io;
+ dp8390reset(ctlr);
+ dp8390setea(ctlr);
+
+ if(ctlr->card.ram)
+ outb(ctlr->card.io+Gacfr, Tcm|Rsel|Mbs0);
+ else
+ outb(ctlr->card.io+Gacfr, Tcm);
+
+ return 0;
+}
+
+static void*
+read(Ctlr *ctlr, void *to, ulong from, ulong len)
+{
+ uchar *addr, ctrl;
+
+ /*
+ * If the interface has shared memory, just do a memmove.
+ * In this case, 'from' is an index into the shared memory.
+ * Due to 'hardware considerations', the memory is seen by
+ * the adapter at RamOffset, so we have to adjust.
+ */
+ if(ctlr->card.ram)
+ return memmove(to, (void*)(ctlr->card.ramstart+from-RamOffset), len);
+
+ /*
+ * Polled I/O. This should be tuned.
+ * Set up the dma registers and pump the fifo.
+ */
+ outb(ctlr->card.io+Dalsb, from & 0xFF);
+ outb(ctlr->card.io+Damsb, (from>>8) & 0xFF);
+ ctrl = inb(ctlr->card.io+Ctrl);
+ outb(ctlr->card.io+Ctrl, Start|ctrl);
+ addr = to;
+ while(len){
+ /*
+ * The fifo is 8 bytes deep, we have to wait
+ * until it's ready before stuffing it.
+ * The fifo is in its default configuration,
+ * so we can do word accesses.
+ */
+ while((inb(ctlr->card.io+Streg) & Dprdy) == 0)
+ ;
+ if(len >= 8){
+ inss(ctlr->card.io+Rfmsb, addr, 4);
+ addr += 8;
+ len -= 8;
+ }
+ else{
+ insb(ctlr->card.io+Rfmsb, addr, len);
+ break;
+ }
+ }
+ outb(ctlr->card.io+Ctrl, ctrl);
+ return to;
}
-Board ether503 = {
- reset,
- 0, /* init */
- 0, /* attach */
- 0, /* mode */
- 0, /* receive */
- 0, /* transmit */
- 0, /* interrupt */
- 0, /* watch */
-
- 0, /* addr */
- 0, /* irq */
- 0, /* bit16 */
-
- 0, /* ram */
- 0, /* ramstart */
- 0, /* ramstop */
-
- 0, /* dp8390 */
- 0, /* data */
- 0, /* tstart */
- 0, /* pstart */
- 0, /* pstop */
+static void*
+write(Ctlr *ctlr, ulong to, void *from, ulong len)
+{
+ uchar *addr, ctrl;
+
+ /*
+ * See the comments in 'read()' above.
+ */
+ if(ctlr->card.ram)
+ return memmove((void*)(ctlr->card.ramstart+to-RamOffset), from, len);
+
+ outb(ctlr->card.io+Dalsb, to & 0xFF);
+ outb(ctlr->card.io+Damsb, (to>>8) & 0xFF);
+ ctrl = inb(ctlr->card.io+Ctrl);
+ outb(ctlr->card.io+Ctrl, Start|Ddir|ctrl);
+ addr = from;
+ while(len){
+ while((inb(ctlr->card.io+Streg) & Dprdy) == 0)
+ ;
+ if(len >= 8){
+ outss(ctlr->card.io+Rfmsb, addr, 4);
+ addr += 8;
+ len -= 8;
+ }
+ else{
+ outsb(ctlr->card.io+Rfmsb, addr, len);
+ break;
+ }
+ }
+ outb(ctlr->card.io+Ctrl, ctrl);
+ return (void*)to;
+}
+
+Card ether503 = {
+ "3Com503", /* ident */
+
+ reset, /* reset */
+ 0, /* init */
+ dp8390attach, /* attach */
+ dp8390mode, /* mode */
+
+ read, /* read */
+ write, /* write */
+
+ dp8390receive, /* receive */
+ dp8390transmit, /* transmit */
+ dp8390intr, /* interrupt */
+ dp8390watch, /* watch */
+ dp8390overflow, /* overflow */
+
+ 0, /* io */
+ 0, /* irq */
+ 0, /* bit16 */
+
+ 0, /* ram */
+ 0, /* ramstart */
+ 0, /* ramstop */
+
+ 0, /* dp8390 */
+ 0, /* data */
+ 0, /* software bndry */
+ RamOffset/Dp8390BufSz, /* tstart */
+ (RamOffset+0x600)/Dp8390BufSz, /* pstart */
+ (RamOffset+8*1024)/Dp8390BufSz, /* pstop */
};
M pc/ether509.c => pc/ether509.c +70 -79
@@ 84,7 84,7 @@ enum {
RxReceiving = 0x8000, /* RX Receiving */
};
-#define COMMAND(board, cmd, a) outs(board->io+Command, ((cmd)<<11)|(a))
+#define COMMAND(ctlr, cmd, a) outs(ctlr->card.io+Command, ((cmd)<<11)|(a))
/*
* Write two 0 bytes to identify the IDport and then reset the
@@ 116,13 116,12 @@ idseq(void)
static int
reset(Ctlr *ctlr)
{
- Board *board = ctlr->board;
int i, ea;
ushort x, acr;
/*
* Do the little configuration dance. We only look
- * at the first board that responds, if we ever have more
+ * at the first card that responds, if we ever have more
* than one we'll need to modify this sequence.
*
* 2. get to command state, reset, then return to command state
@@ 172,8 171,8 @@ reset(Ctlr *ctlr)
*
* Enable the adapter.
*/
- board->io = (acr & 0x1F)*0x10 + 0x200;
- outb(board->io+ConfigControl, 0x01);
+ ctlr->card.io = (acr & 0x1F)*0x10 + 0x200;
+ outb(ctlr->card.io+ConfigControl, 0x01);
/*
* Read the IRQ from the Resource Configuration Register
@@ 181,14 180,14 @@ reset(Ctlr *ctlr)
* The EEPROM command is 8bits, the lower 6 bits being
* the address offset.
*/
- board->irq = (ins(board->io+ResourceConfig)>>12) & 0x0F;
+ ctlr->card.irq = (ins(ctlr->card.io+ResourceConfig)>>12) & 0x0F;
for(ea = 0, i = 0; i < 3; i++, ea += 2){
- while(ins(board->io+EEPROMcmd) & 0x8000)
+ while(ins(ctlr->card.io+EEPROMcmd) & 0x8000)
;
- outs(board->io+EEPROMcmd, (2<<6)|i);
- while(ins(board->io+EEPROMcmd) & 0x8000)
+ outs(ctlr->card.io+EEPROMcmd, (2<<6)|i);
+ while(ins(ctlr->card.io+EEPROMcmd) & 0x8000)
;
- x = ins(board->io+EEPROMdata);
+ x = ins(ctlr->card.io+EEPROMdata);
ctlr->ea[ea] = (x>>8) & 0xFF;
ctlr->ea[ea+1] = x & 0xFF;
}
@@ 199,38 198,31 @@ reset(Ctlr *ctlr)
* Commands have the format 'CCCCCAAAAAAAAAAA' where C
* is a bit in the command and A is a bit in the argument.
*/
- COMMAND(board, SelectWindow, 2);
+ COMMAND(ctlr, SelectWindow, 2);
for(i = 0; i < 6; i++)
- outb(board->io+i, ctlr->ea[i]);
+ outb(ctlr->card.io+i, ctlr->ea[i]);
/*
* Finished with window 2.
* Set window 1 for normal operation.
*/
- COMMAND(board, SelectWindow, 1);
+ COMMAND(ctlr, SelectWindow, 1);
/*
* If we have a 10BASE2 transceiver, start the DC-DC
* converter. Wait > 800 microseconds.
*/
if(((acr>>14) & 0x03) == 0x03){
- COMMAND(board, StartCoax, 0);
+ COMMAND(ctlr, StartCoax, 0);
delay(1);
}
- print("3C509 I/O addr %lux irq %d:", board->io, board->irq);
- for(i = 0; i < sizeof(ctlr->ea); i++)
- print(" %2.2ux", ctlr->ea[i]);
- print("\n");
-
return 0;
}
static void
attach(Ctlr *ctlr)
{
- Board *board = ctlr->board;
-
/*
* Set the receiver packet filter for our own and
* and broadcast addresses, set the interrupt masks
@@ 239,44 231,30 @@ attach(Ctlr *ctlr)
* is the receiver interrupt. If the transmit FIFO fills up,
* we will also see TxAvailable interrupts.
*/
- COMMAND(board, SetRxFilter, Broadcast|MyEtherAddr);
- COMMAND(board, SetReadZeroMask, AllIntr|Latch);
- COMMAND(board, SetIntrMask, AllIntr|Latch);
- COMMAND(board, RxEnable, 0);
- COMMAND(board, TxEnable, 0);
+ COMMAND(ctlr, SetRxFilter, Broadcast|MyEtherAddr);
+ COMMAND(ctlr, SetReadZeroMask, AllIntr|Latch);
+ COMMAND(ctlr, SetIntrMask, AllIntr|Latch);
+ COMMAND(ctlr, RxEnable, 0);
+ COMMAND(ctlr, TxEnable, 0);
}
static void
mode(Ctlr *ctlr, int on)
{
- Board *board = ctlr->board;
-
if(on)
- COMMAND(board, SetRxFilter, Promiscuous|Broadcast|MyEtherAddr);
+ COMMAND(ctlr, SetRxFilter, Promiscuous|Broadcast|MyEtherAddr);
else
- COMMAND(board, SetRxFilter, Broadcast|MyEtherAddr);
-}
-
-static int
-getdiag(Board *board)
-{
- int bytes;
-
- COMMAND(board, SelectWindow, 4);
- bytes = ins(board->io+FIFOdiag);
- COMMAND(board, SelectWindow, 1);
- return bytes & 0xFFFF;
+ COMMAND(ctlr, SetRxFilter, Broadcast|MyEtherAddr);
}
static void
receive(Ctlr *ctlr)
{
- Board *board = ctlr->board;
ushort status;
RingBuf *rb;
int len;
- while(((status = ins(board->io+RxStatus)) & RxEmpty) == 0){
+ while(((status = ins(ctlr->card.io+RxStatus)) & RxEmpty) == 0){
/*
* If we had an error, log it and continue
* without updating the ring.
@@ 317,9 295,9 @@ receive(Ctlr *ctlr)
* doubleword. We can pick them out 16-bits
* at a time (can try 32-bits at a time
* later).
- insl(board->io+Fifo, rb->pkt, HOWMANY(len, 4));
+ insl(ctlr->card.io+Fifo, rb->pkt, HOWMANY(len, 4));
*/
- inss(board->io+Fifo, rb->pkt, HOWMANY(len, 2));
+ inss(ctlr->card.io+Fifo, rb->pkt, HOWMANY(len, 2));
/*
* Update the ring.
@@ 333,8 311,8 @@ receive(Ctlr *ctlr)
* Discard the packet as we're done with it.
* Wait for discard to complete.
*/
- COMMAND(board, RxDiscard, 0);
- while(ins(board->io+Status) & CmdInProgress)
+ COMMAND(ctlr, RxDiscard, 0);
+ while(ins(ctlr->card.io+Status) & CmdInProgress)
;
}
}
@@ 342,12 320,9 @@ receive(Ctlr *ctlr)
static void
transmit(Ctlr *ctlr)
{
- Board *board = ctlr->board;
RingBuf *tb;
- int s;
ushort len;
- s = splhi();
for(tb = &ctlr->tb[ctlr->ti]; tb->owner == Interface; tb = &ctlr->tb[ctlr->ti]){
/*
* If there's no room in the FIFO for this packet,
@@ 356,8 331,8 @@ transmit(Ctlr *ctlr)
* we need 4 bytes for the preamble.
*/
len = ROUNDUP(tb->len, 4);
- if(len > ins(board->io+TxFreeBytes)+4){
- COMMAND(board, SetTxAvailable, len);
+ if(len > ins(ctlr->card.io+TxFreeBytes)+4){
+ COMMAND(ctlr, SetTxAvailable, len);
break;
}
@@ 365,23 340,32 @@ transmit(Ctlr *ctlr)
* There's room, copy the packet to the FIFO and free
* the buffer back to the host.
*/
- outs(board->io+Fifo, tb->len);
- outs(board->io+Fifo, 0);
- outss(board->io+Fifo, tb->pkt, len/2);
+ outs(ctlr->card.io+Fifo, tb->len);
+ outs(ctlr->card.io+Fifo, 0);
+ outss(ctlr->card.io+Fifo, tb->pkt, len/2);
tb->owner = Host;
ctlr->ti = NEXT(ctlr->ti, ctlr->ntb);
}
- splx(s);
+}
+
+static ushort
+getdiag(Ctlr *ctlr)
+{
+ ushort bytes;
+
+ COMMAND(ctlr, SelectWindow, 4);
+ bytes = ins(ctlr->card.io+FIFOdiag);
+ COMMAND(ctlr, SelectWindow, 1);
+ return bytes & 0xFFFF;
}
static void
interrupt(Ctlr *ctlr)
{
- Board *board = ctlr->board;
ushort status, diag;
uchar txstatus, x;
- status = ins(board->io+Status);
+ status = ins(ctlr->card.io+Status);
if(status & Failure){
/*
@@ 391,16 375,16 @@ interrupt(Ctlr *ctlr)
* need to retransmit?
* This probably isn't right.
*/
- diag = getdiag(board);
+ diag = getdiag(ctlr);
print("ether509: status #%ux, diag #%ux\n", status, diag);
if(diag & TxOverrun){
- COMMAND(board, TxReset, 0);
- COMMAND(board, TxEnable, 0);
+ COMMAND(ctlr, TxReset, 0);
+ COMMAND(ctlr, TxEnable, 0);
}
if(diag & RxUnderrun){
- COMMAND(board, RxReset, 0);
+ COMMAND(ctlr, RxReset, 0);
attach(ctlr);
}
@@ 425,14 409,14 @@ interrupt(Ctlr *ctlr)
*/
txstatus = 0;
do{
- if(x = inb(board->io+TxStatus))
- outb(board->io+TxStatus, 0);
+ if(x = inb(ctlr->card.io+TxStatus))
+ outb(ctlr->card.io+TxStatus, 0);
txstatus |= x;
- }while(ins(board->io+Status) & TxComplete);
+ }while(ins(ctlr->card.io+Status) & TxComplete);
if(txstatus & (TxJabber|TxUnderrun))
- COMMAND(board, TxReset, 0);
- COMMAND(board, TxEnable, 0);
+ COMMAND(ctlr, TxReset, 0);
+ COMMAND(ctlr, TxEnable, 0);
ctlr->oerrs++;
}
@@ 441,7 425,7 @@ interrupt(Ctlr *ctlr)
* Reset the Tx FIFO threshold.
*/
if(status & TxAvailable)
- COMMAND(board, AckIntr, TxAvailable);
+ COMMAND(ctlr, AckIntr, TxAvailable);
transmit(ctlr);
wakeup(&ctlr->tr);
status &= ~(TxAvailable|TxComplete);
@@ 453,18 437,25 @@ interrupt(Ctlr *ctlr)
* Otherwise, acknowledge the interrupt.
*/
if(status & AllIntr)
- panic("ether509 interrupt: #%lux, #%ux\n", status, getdiag(board));
+ panic("ether509 interrupt: #%lux, #%ux\n", status, getdiag(ctlr));
- COMMAND(board, AckIntr, Latch);
+ COMMAND(ctlr, AckIntr, Latch);
}
-Board ether509 = {
- reset,
- 0, /* init */
- attach,
- mode,
- 0, /* receive */
- transmit,
- interrupt,
- 0, /* watch */
+Card ether509 = {
+ "3Com509", /* ident */
+
+ reset, /* reset */
+ 0, /* init */
+ attach, /* attach */
+ mode, /* mode */
+
+ 0, /* read */
+ 0, /* write */
+
+ 0, /* receive */
+ transmit, /* transmit */
+ interrupt, /* interrupt */
+ 0, /* watch */
+ 0, /* overflow */
};
M pc/ether8003.c => pc/ether8003.c +80 -62
@@ 19,7 19,7 @@ enum { /* 83C584 Bus Interface Controller */
Ijr = 0x06, /* Initialisation Jumpers */
Gp2 = 0x07, /* General Purpose Data Register */
Lar = 0x08, /* LAN Address Registers */
- Id = 0x0E, /* Board ID byte */
+ Id = 0x0E, /* Card ID byte */
Cksum = 0x0F, /* Checksum */
};
@@ 47,7 47,6 @@ static int intrmap[] = {
static int
reset(Ctlr *ctlr)
{
- Board *board = ctlr->board;
int i;
uchar msr, icr, laar, irr, sum;
@@ 56,18 55,18 @@ reset(Ctlr *ctlr)
* and validate the checksum - the sum of all 8 bytes
* should be 0xFF.
*/
- for(board->io = 0x200; board->io < 0x400; board->io += 0x20){
+ for(ctlr->card.io = 0x200; ctlr->card.io < 0x400; ctlr->card.io += 0x20){
sum = 0;
for(i = 0; i < sizeof(ctlr->ea); i++){
- ctlr->ea[i] = inb(board->io+Lar+i);
+ ctlr->ea[i] = inb(ctlr->card.io+Lar+i);
sum += ctlr->ea[i];
}
- sum += inb(board->io+Id);
- sum += inb(board->io+Cksum);
+ sum += inb(ctlr->card.io+Id);
+ sum += inb(ctlr->card.io+Cksum);
if(sum == 0xFF)
break;
}
- if(board->io >= 0x400)
+ if(ctlr->card.io >= 0x400)
return -1;
/*
@@ 75,10 74,10 @@ reset(Ctlr *ctlr)
* Be careful to preserve the Msr address bits,
* they don't get reloaded from the EEPROM on reset.
*/
- msr = inb(board->io+Msr);
- outb(board->io+Msr, Rst|msr);
+ msr = inb(ctlr->card.io+Msr);
+ outb(ctlr->card.io+Msr, Rst|msr);
delay(1);
- outb(board->io+Msr, msr);
+ outb(ctlr->card.io+Msr, msr);
delay(2);
/*
@@ 90,60 89,53 @@ reset(Ctlr *ctlr)
* 8003EBT, 8003S, 8003SH or 8003WT, we don't care), in which
* case the default irq gets used.
*/
- msr = inb(board->io+Msr);
- icr = inb(board->io+Icr);
- laar = inb(board->io+Laar);
- irr = inb(board->io+Irr);
+ msr = inb(ctlr->card.io+Msr);
+ icr = inb(ctlr->card.io+Icr);
+ laar = inb(ctlr->card.io+Laar);
+ irr = inb(ctlr->card.io+Irr);
if(icr != ctlr->ea[1] || irr != ctlr->ea[4] || laar != ctlr->ea[5])
- board->irq = intrmap[((irr>>5) & 0x3)|(icr & 0x4)];
+ ctlr->card.irq = intrmap[((irr>>5) & 0x3)|(icr & 0x4)];
else {
- msr = (((ulong)board->ramstart)>>13) & 0x3F;
+ msr = (((ulong)ctlr->card.ramstart)>>13) & 0x3F;
icr = laar = 0;
- board->watch = 0;
+ ctlr->card.watch = 0;
}
/*
* Set up the bus-size, RAM address and RAM size
* from the info in the configuration registers.
*/
- board->bit16 = icr & 0x1;
+ ctlr->card.bit16 = icr & 0x1;
- board->ram = 1;
- board->ramstart = KZERO|((msr & 0x3F)<<13);
- if(board->bit16)
- board->ramstart |= (laar & 0x1F)<<19;
+ ctlr->card.ram = 1;
+ ctlr->card.ramstart = KZERO|((msr & 0x3F)<<13);
+ if(ctlr->card.bit16)
+ ctlr->card.ramstart |= (laar & 0x1F)<<19;
else
- board->ramstart |= 0x80000;
+ ctlr->card.ramstart |= 0x80000;
if(icr & (1<<3))
- board->ramstop = 32*1024;
+ ctlr->card.ramstop = 32*1024;
else
- board->ramstop = 8*1024;
- if(board->bit16)
- board->ramstop <<= 1;
- board->ramstop += board->ramstart;
+ ctlr->card.ramstop = 8*1024;
+ if(ctlr->card.bit16)
+ ctlr->card.ramstop <<= 1;
+ ctlr->card.ramstop += ctlr->card.ramstart;
/*
* Set the DP8390 ring addresses.
*/
- board->dp8390 = board->io+0x10;
- board->pstart = HOWMANY(sizeof(Etherpkt), Dp8390BufSz);
- board->pstop = HOWMANY(board->ramstop-board->ramstart, Dp8390BufSz);
- board->tstart = 0;
-
- print("WD8003 I/O addr %lux width %d addr %lux size %d irq %d:",
- board->io, board->bit16 ? 16: 8, board->ramstart,
- board->ramstop-board->ramstart, board->irq);
- for(i = 0; i < sizeof(ctlr->ea); i++)
- print(" %2.2ux", ctlr->ea[i]);
- print("\n");
+ ctlr->card.dp8390 = ctlr->card.io+0x10;
+ ctlr->card.pstart = HOWMANY(sizeof(Etherpkt), Dp8390BufSz);
+ ctlr->card.pstop = HOWMANY(ctlr->card.ramstop-ctlr->card.ramstart, Dp8390BufSz);
+ ctlr->card.tstart = 0;
/*
* Enable interface RAM, set interface width.
*/
- outb(board->io+Msr, Menb|msr);
- if(board->bit16)
- outb(board->io+Laar, laar|L16en|M16en|ZeroWS16);
+ outb(ctlr->card.io+Msr, Menb|msr);
+ if(ctlr->card.bit16)
+ outb(ctlr->card.io+Laar, laar|L16en|M16en|ZeroWS16);
/*
* Finally, init the 8390 and set the
@@ 155,17 147,36 @@ reset(Ctlr *ctlr)
return 0;
}
+static void*
+read(Ctlr *ctlr, void *to, ulong from, ulong len)
+{
+ /*
+ * In this case, 'from' is an index into the shared memory.
+ */
+ memmove(to, (void*)(ctlr->card.ramstart+from), len);
+ return to;
+}
+
+static void*
+write(Ctlr *ctlr, ulong to, void *from, ulong len)
+{
+ /*
+ * In this case, 'to' is an index into the shared memory.
+ */
+ memmove((void*)(ctlr->card.ramstart+to), from, len);
+ return (void*)to;
+}
+
static void
watch(Ctlr *ctlr)
{
- Board *board = ctlr->board;
uchar msr;
int s;
s = splhi();
- msr = inb(board->io+Msr);
+ msr = inb(ctlr->card.io+Msr);
/*
- * If the board has reset itself,
+ * If the card has reset itself,
* start again.
*/
if((msr & Menb) == 0){
@@ 184,21 195,28 @@ watch(Ctlr *ctlr)
* Defaults are set for the dumb 8003E
* which can't be autoconfigured.
*/
-Board ether8003 = {
- reset,
- 0, /* init */
- dp8390attach,
- dp8390mode,
- dp8390receive,
- dp8390transmit,
- dp8390intr,
- watch,
-
- 0x280, /* io */
- 3, /* irq */
- 0, /* bit16 */
-
- 1, /* ram */
- 0xD0000, /* ramstart */
- 0xD0000+8*1024, /* ramstop */
+Card ether8003 = {
+ "WD8003", /* ident */
+
+ reset, /* reset */
+ 0, /* init */
+ dp8390attach, /* attach */
+ dp8390mode, /* mode */
+
+ read, /* read */
+ write, /* write */
+
+ dp8390receive, /* receive */
+ dp8390transmit, /* transmit */
+ dp8390intr, /* interrupt */
+ watch, /* watch */
+ 0, /* overflow */
+
+ 0x280, /* io */
+ 3, /* irq */
+ 0, /* bit16 */
+
+ 1, /* ram */
+ 0xD0000, /* ramstart */
+ 0xD0000+8*1024, /* ramstop */
};
M pc/ether8390.c => pc/ether8390.c +269 -199
@@ 24,9 24,11 @@ enum {
RDMAwrite = (2<<3), /* remote DMA write */
RDMAsend = (3<<3), /* remote DMA send packet */
RDMAabort = (4<<3), /* abort/complete remote DMA */
- Page0 = (0x00<<6), /* page select */
- Page1 = (0x01<<6),
- Page2 = (0x02<<6),
+ Ps0 = 0x40, /* page select */
+ Ps1 = 0x80, /* page select */
+ Page0 = 0x00,
+ Page1 = Ps0,
+ Page2 = Ps1,
};
enum { /* Page 0, read */
@@ 38,7 40,7 @@ enum { /* Page 0, read */
Fifo = 0x06, /* FIFO */
Isr = 0x07, /* interrupt status register (R/W) */
Crda0 = 0x08, /* current remote DMA address 0 */
- Crda1 = 0x08, /* current remote DMA address 1 */
+ Crda1 = 0x09, /* current remote DMA address 1 */
Rsr = 0x0C, /* receive status register */
Cntr0 = 0x0D, /* frame alignment errors */
Cntr1 = 0x0E, /* CRC errors */
@@ 144,15 146,9 @@ typedef struct {
uchar len1;
} Hdr;
-typedef struct {
- Hdr;
- uchar data[Dp8390BufSz-sizeof(Hdr)];
-} Buf;
-
static void
dp8390disable(Ctlr *ctlr)
{
- Board *board = ctlr->board;
int timo;
/*
@@ 163,54 159,63 @@ dp8390disable(Ctlr *ctlr)
* chip there if this is called when probing for a device
* at boot.
*/
- outb(board->dp8390+Cr, Page0|RDMAabort|Stp);
- for(timo = 10000; (inb(board->dp8390+Isr) & Rst) == 0 && timo; timo--)
+ dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Stp);
+ dp8390outb(ctlr->card.dp8390+Rbcr0, 0);
+ dp8390outb(ctlr->card.dp8390+Rbcr1, 0);
+ for(timo = 10000; (dp8390inb(ctlr->card.dp8390+Isr) & Rst) == 0 && timo; timo--)
;
}
+static void
+dp8390ring(Ctlr *ctlr)
+{
+ dp8390outb(ctlr->card.dp8390+Pstart, ctlr->card.pstart);
+ dp8390outb(ctlr->card.dp8390+Pstop, ctlr->card.pstop);
+ dp8390outb(ctlr->card.dp8390+Bnry, ctlr->card.pstop-1);
+
+ dp8390outb(ctlr->card.dp8390+Cr, Page1|RDMAabort|Stp);
+ dp8390outb(ctlr->card.dp8390+Curr, ctlr->card.pstart);
+ dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Stp);
+
+ ctlr->card.nxtpkt = ctlr->card.pstart;
+}
+
void
dp8390reset(Ctlr *ctlr)
{
- Board *board = ctlr->board;
-
/*
* This is the initialisation procedure described
- * as 'mandatory' in the datasheet.
+ * as 'mandatory' in the datasheet, with references
+ * to the 3Com503 technical reference manual.
*/
dp8390disable(ctlr);
- if(board->bit16)
- outb(board->dp8390+Dcr, Ft4|Ls|Wts);
+ if(ctlr->card.bit16)
+ dp8390outb(ctlr->card.dp8390+Dcr, Ft4|Ls|Wts);
else
- outb(board->dp8390+Dcr, Ft4|Ls);
-
- outb(board->dp8390+Rbcr0, 0);
- outb(board->dp8390+Rbcr1, 0);
-
- outb(board->dp8390+Rcr, Ab);
- outb(board->dp8390+Tcr, Lb);
+ dp8390outb(ctlr->card.dp8390+Dcr, Ft4|Ls);
- outb(board->dp8390+Bnry, board->pstart);
- outb(board->dp8390+Pstart, board->pstart);
- outb(board->dp8390+Pstop, board->pstop);
+ dp8390outb(ctlr->card.dp8390+Rbcr0, 0);
+ dp8390outb(ctlr->card.dp8390+Rbcr1, 0);
- outb(board->dp8390+Isr, 0xFF);
- outb(board->dp8390+Imr, Ovwe|Txee|Rxee|Ptxe|Prxe);
-
- outb(board->dp8390+Cr, Page1|RDMAabort|Stp);
+ dp8390outb(ctlr->card.dp8390+Tcr, 0);
+ dp8390outb(ctlr->card.dp8390+Rcr, Mon);
/*
- * Can't initialise ethernet address as we may
- * not know it yet.
+ * Init the ring hardware and software ring pointers.
+ * Can't initialise ethernet address as we may not know
+ * it yet.
*/
- outb(board->dp8390+Curr, board->pstart+1);
+ dp8390ring(ctlr);
+ dp8390outb(ctlr->card.dp8390+Tpsr, ctlr->card.tstart);
+
+ dp8390outb(ctlr->card.dp8390+Isr, 0xFF);
+ dp8390outb(ctlr->card.dp8390+Imr, Cnte|Ovwe|Txee|Rxee|Ptxe|Prxe);
/*
* Leave the chip initialised,
* but in internal loopback mode.
*/
- outb(board->dp8390+Cr, Page0|RDMAabort|Sta);
-
- outb(board->dp8390+Tpsr, board->tstart);
+ dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Sta);
}
void
@@ 218,25 223,27 @@ dp8390attach(Ctlr *ctlr)
{
/*
* Enable the chip for transmit/receive.
- * The init routine leaves the chip in internal
- * loopback.
+ * The init routine leaves the chip in monitor
+ * mode.
*/
- outb(ctlr->board->dp8390+Tcr, 0);
+ dp8390outb(ctlr->card.dp8390+Rcr, Ab);
}
void
dp8390mode(Ctlr *ctlr, int on)
{
+ /*
+ * Set/reset promiscuous mode.
+ */
if(on)
- outb(ctlr->board->dp8390+Rcr, Pro|Ab);
+ dp8390outb(ctlr->card.dp8390+Rcr, Pro|Ab);
else
- outb(ctlr->board->dp8390+Rcr, Ab);
+ dp8390outb(ctlr->card.dp8390+Rcr, Ab);
}
void
dp8390setea(Ctlr *ctlr)
{
- Board *board = ctlr->board;
uchar cr;
int i;
@@ 247,58 254,47 @@ dp8390setea(Ctlr *ctlr)
* addresses as we never set the multicast
* enable.
*/
- cr = inb(board->dp8390+Cr);
- outb(board->dp8390+Cr, Page1|(~Page0 & cr));
+ cr = dp8390inb(ctlr->card.dp8390+Cr) & ~Txp;
+ dp8390outb(ctlr->card.dp8390+Cr, Page1|(~(Ps1|Ps0) & cr));
for(i = 0; i < sizeof(ctlr->ea); i++)
- outb(board->dp8390+Par0+i, ctlr->ea[i]);
- outb(board->dp8390+Cr, cr);
+ dp8390outb(ctlr->card.dp8390+Par0+i, ctlr->ea[i]);
+ dp8390outb(ctlr->card.dp8390+Cr, cr);
}
void*
dp8390read(Ctlr *ctlr, void *to, ulong from, ulong len)
{
- Board *board = ctlr->board;
uchar cr;
int timo;
/*
- * If the interface has shared memory, just
- * do a memmove.
- * In this case, 'from' is an index into the shared memory.
- */
- if(board->ram){
- memmove(to, (void*)(board->ramstart+from), len);
- return to;
- }
-
- /*
- * Read some data at offset 'from' in the board's memory
+ * Read some data at offset 'from' in the card's memory
* using the DP8390 remote DMA facility, and place it at
* 'to' in main memory, via the I/O data port.
*/
- cr = inb(board->dp8390+Cr);
- outb(board->dp8390+Cr, Page0|RDMAabort|Sta);
- outb(board->dp8390+Isr, Rdc);
+ cr = dp8390inb(ctlr->card.dp8390+Cr) & ~Txp;
+ dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Sta);
+ dp8390outb(ctlr->card.dp8390+Isr, Rdc);
/*
* Set up the remote DMA address and count.
*/
- if(board->bit16)
+ if(ctlr->card.bit16)
len = ROUNDUP(len, 2);
- outb(board->dp8390+Rbcr0, len & 0xFF);
- outb(board->dp8390+Rbcr1, (len>>8) & 0xFF);
- outb(board->dp8390+Rsar0, from & 0xFF);
- outb(board->dp8390+Rsar1, (from>>8) & 0xFF);
+ dp8390outb(ctlr->card.dp8390+Rbcr0, len & 0xFF);
+ dp8390outb(ctlr->card.dp8390+Rbcr1, (len>>8) & 0xFF);
+ dp8390outb(ctlr->card.dp8390+Rsar0, from & 0xFF);
+ dp8390outb(ctlr->card.dp8390+Rsar1, (from>>8) & 0xFF);
/*
* Start the remote DMA read and suck the data
* out of the I/O port.
*/
- outb(board->dp8390+Cr, Page0|RDMAread|Sta);
- if(board->bit16)
- inss(board->data, to, len/2);
+ dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAread|Sta);
+ if(ctlr->card.bit16)
+ inss(ctlr->card.data, to, len/2);
else
- insb(board->data, to, len);
+ insb(ctlr->card.data, to, len);
/*
* Wait for the remote DMA to complete. The timeout
@@ 307,99 303,105 @@ dp8390read(Ctlr *ctlr, void *to, ulong from, ulong len)
* to the miracles of the bus, we could get this far
* and still be talking to a slot full of nothing.
*/
- for(timo = 10000; (inb(board->dp8390+Isr) & Rdc) == 0 && timo; timo--)
+ for(timo = 10000; (dp8390inb(ctlr->card.dp8390+Isr) & Rdc) == 0 && timo; timo--)
;
- outb(board->dp8390+Isr, Rdc);
- outb(board->dp8390+Cr, cr);
+ dp8390outb(ctlr->card.dp8390+Isr, Rdc);
+ dp8390outb(ctlr->card.dp8390+Cr, cr);
return to;
}
void*
dp8390write(Ctlr *ctlr, ulong to, void *from, ulong len)
{
- Board *board = ctlr->board;
uchar cr;
+ ulong crda;
/*
- * If the interface has shared memory, just
- * do a memmove.
- * In this case, 'to' is an index into the shared memory.
- */
- if(board->ram){
- memmove((void*)(board->ramstart+to), from, len);
- return (void*)to;
- }
-
- /*
- * Write some data to offset 'to' in the board's memory
+ * Write some data to offset 'to' in the card's memory
* using the DP8390 remote DMA facility, reading it at
* 'from' in main memory, via the I/O data port.
*/
- cr = inb(board->dp8390+Cr);
- outb(board->dp8390+Cr, Page0|RDMAabort|Sta);
- outb(board->dp8390+Isr, Rdc);
+ cr = dp8390inb(ctlr->card.dp8390+Cr) & ~Txp;
+ dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Sta);
+ dp8390outb(ctlr->card.dp8390+Isr, Rdc);
+
+ if(ctlr->card.bit16)
+ len = ROUNDUP(len, 2);
/*
* Set up the remote DMA address and count.
- * This is straight from the datasheet, hence
- * the initial write to Rbcr0 and Cr.
+ * This is straight from the DP8390[12D] datasheet, hence
+ * the initial set up for read.
*/
- outb(board->dp8390+Rbcr0, 0xFF);
- outb(board->dp8390+Cr, Page0|RDMAread|Sta);
+ crda = to-1-ctlr->card.bit16;
+ dp8390outb(ctlr->card.dp8390+Rbcr0, (len+1+ctlr->card.bit16) & 0xFF);
+ dp8390outb(ctlr->card.dp8390+Rbcr1, ((len+1+ctlr->card.bit16)>>8) & 0xFF);
+ dp8390outb(ctlr->card.dp8390+Rsar0, crda & 0xFF);
+ dp8390outb(ctlr->card.dp8390+Rsar1, (crda>>8) & 0xFF);
+ dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAread|Sta);
+
+ for(;;){
+ crda = dp8390inb(ctlr->card.dp8390+Crda0);
+ crda |= dp8390inb(ctlr->card.dp8390+Crda1)<<8;
+ if(crda == to){
+ /*
+ * Start the remote DMA write and make sure
+ * the registers are correct.
+ */
+ dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAwrite|Sta);
- if(board->bit16)
- len = ROUNDUP(len, 2);
- outb(board->dp8390+Rbcr0, len & 0xFF);
- outb(board->dp8390+Rbcr1, (len>>8) & 0xFF);
- outb(board->dp8390+Rsar0, to & 0xFF);
- outb(board->dp8390+Rsar1, (to>>8) & 0xFF);
+ crda = dp8390inb(ctlr->card.dp8390+Crda0);
+ crda |= dp8390inb(ctlr->card.dp8390+Crda1)<<8;
+ if(crda != to)
+ panic("crda write %d to %d\n", crda, to);
+
+ break;
+ }
+ }
/*
- * Start the remote DMA write and pump the data
- * into the I/O port.
+ * Pump the data into the I/O port.
*/
- outb(board->dp8390+Cr, Page0|RDMAwrite|Sta);
- if(board->bit16)
- outss(board->data, from, len/2);
+ if(ctlr->card.bit16)
+ outss(ctlr->card.data, from, len/2);
else
- outsb(board->data, from, len);
+ outsb(ctlr->card.data, from, len);
/*
* Wait for the remote DMA to finish. We'll need
* a timeout here if this ever gets called before
* we know there really is a chip there.
*/
- while((inb(board->dp8390+Isr) & Rdc) == 0)
+ while((dp8390inb(ctlr->card.dp8390+Isr) & Rdc) == 0)
;
- outb(board->dp8390+Isr, Rdc);
- outb(board->dp8390+Cr, cr);
+ dp8390outb(ctlr->card.dp8390+Isr, Rdc);
+ dp8390outb(ctlr->card.dp8390+Cr, cr);
return (void*)to;
}
+static uchar
+getcurr(Ctlr *ctlr)
+{
+ uchar cr, curr;
+
+ cr = dp8390inb(ctlr->card.dp8390+Cr) & ~Txp;
+ dp8390outb(ctlr->card.dp8390+Cr, Page1|(~(Ps1|Ps0) & cr));
+ curr = dp8390inb(ctlr->card.dp8390+Curr);
+ dp8390outb(ctlr->card.dp8390+Cr, cr);
+ return curr;
+}
+
void
dp8390receive(Ctlr *ctlr)
{
- Board *board = ctlr->board;
RingBuf *ring;
- uchar bnry, curr, next;
+ uchar curr, len1, *pkt;
Hdr hdr;
- ulong data;
- int i, len;
-
- bnry = inb(board->dp8390+Bnry);
- next = bnry+1;
- if(next >= board->pstop)
- next = board->pstart;
-
- for(i = 0; ; i++){
- outb(board->dp8390+Cr, Page1|RDMAabort|Sta);
- curr = inb(board->dp8390+Curr);
- outb(board->dp8390+Cr, Page0|RDMAabort|Sta);
- if(next == curr)
- break;
+ ulong data, len;
+ for(curr = getcurr(ctlr); ctlr->card.nxtpkt != curr; curr = getcurr(ctlr)){
/*
* Hack to keep away from the card's memory while it is receiving
* a packet. This is only a problem on the NCR 3170 Safari.
@@ 411,11 413,11 @@ dp8390receive(Ctlr *ctlr)
uchar a, b, c;
for(;;delay(10)){
- a = inb(board->dp8390+Clda0);
- b = inb(board->dp8390+Clda0);
+ a = dp8390inb(ctlr->card.dp8390+Clda0);
+ b = dp8390inb(ctlr->card.dp8390+Clda0);
if(a != b)
continue;
- c = inb(board->dp8390+Clda0);
+ c = dp8390inb(ctlr->card.dp8390+Clda0);
if(c != b)
continue;
break;
@@ 424,63 426,139 @@ dp8390receive(Ctlr *ctlr)
ctlr->inpackets++;
- data = next*Dp8390BufSz;
- dp8390read(ctlr, &hdr, data, sizeof(Hdr));
- len = ((hdr.len1<<8)|hdr.len0)-4;
+ data = ctlr->card.nxtpkt*Dp8390BufSz;
+ (*ctlr->card.read)(ctlr, &hdr, data, sizeof(Hdr));
/*
- * Chip is badly scrogged, reinitialise it.
- * dp8390reset() calls the disable function.
- * There's no need to reload the ethernet
- * address.
- *
- * Untested.
+ * Don't believe the upper byte count, work it
+ * out from the software next-page pointer and
+ * the current next-page pointer.
+ */
+ if(hdr.next > ctlr->card.nxtpkt)
+ len1 = hdr.next - ctlr->card.nxtpkt - 1;
+ else
+ len1 = (ctlr->card.pstop-ctlr->card.nxtpkt) + (hdr.next-ctlr->card.pstart) - 1;
+ if(hdr.len0 > (Dp8390BufSz-sizeof(Hdr)))
+ len1--;
+
+ len = ((len1<<8)|hdr.len0)-4;
+
+ /*
+ * Chip is badly scrogged, reinitialise the ring.
*/
- if(hdr.next < board->pstart || hdr.next >= board->pstop || len < 60){
-print("scrogged\n");
- dp8390reset(ctlr);
- dp8390attach(ctlr);
+ if(hdr.next < ctlr->card.pstart || hdr.next >= ctlr->card.pstop
+ || len < 60 || len > sizeof(Etherpkt)){
+ print("H#%2.2ux#%2.2ux#%2.2ux#%2.2ux,%d|",
+ hdr.status, hdr.next, hdr.len0, hdr.len1, len);
+ dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Stp);
+ dp8390ring(ctlr);
+ dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Sta);
return;
}
+ /*
+ * If it's a good packet and we have a place to put it,
+ * read it in to the software ring.
+ * If the packet wraps round the hardware ring, read it
+ * in two pieces.
+ */
ring = &ctlr->rb[ctlr->ri];
- if(ring->owner == Interface){
- ring->len = len;
+ if((hdr.status & (Fo|Fae|Crce|Prxok)) == Prxok && ring->owner == Interface){
+ pkt = ring->pkt;
data += sizeof(Hdr);
- if((data+len) >= board->pstop*Dp8390BufSz){
- len = board->pstop*Dp8390BufSz - data;
- dp8390read(ctlr, ring->pkt+len, board->pstart*Dp8390BufSz,
- (data+ring->len) - board->pstop*Dp8390BufSz);
+ ring->len = len;
+
+ if((data+len) >= ctlr->card.pstop*Dp8390BufSz){
+ ulong count = ctlr->card.pstop*Dp8390BufSz - data;
+
+ (*ctlr->card.read)(ctlr, pkt, data, count);
+ pkt += count;
+ data = ctlr->card.pstart*Dp8390BufSz;
+ len -= count;
}
- dp8390read(ctlr, ring->pkt, data, len);
+ if(len)
+ (*ctlr->card.read)(ctlr, pkt, data, len);
+
ring->owner = Host;
ctlr->ri = NEXT(ctlr->ri, ctlr->nrb);
}
- next = hdr.next;
- bnry = next-1;
- if(bnry < board->pstart)
- bnry = board->pstop-1;
- outb(board->dp8390+Bnry, bnry);
+ /*
+ * Finished woth this packet, update the
+ * hardware and software ring pointers.
+ */
+ ctlr->card.nxtpkt = hdr.next;
+
+ hdr.next--;
+ if(hdr.next < ctlr->card.pstart)
+ hdr.next = ctlr->card.pstop-1;
+ dp8390outb(ctlr->card.dp8390+Bnry, hdr.next);
}
}
+/*
+ * Initiate a transmission. Must be called splhi().
+ */
void
dp8390transmit(Ctlr *ctlr)
{
- Board *board;
RingBuf *ring;
+
+ ring = &ctlr->tb[ctlr->ti];
+ if(ctlr->tbusy == 0 && ring->owner == Interface){
+ (*ctlr->card.write)(ctlr, ctlr->card.tstart*Dp8390BufSz, ring->pkt, ring->len);
+ dp8390outb(ctlr->card.dp8390+Tbcr0, ring->len & 0xFF);
+ dp8390outb(ctlr->card.dp8390+Tbcr1, (ring->len>>8) & 0xFF);
+ dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Txp|Sta);
+ ctlr->tbusy = 1;
+ }
+}
+
+void
+dp8390overflow(Ctlr *ctlr)
+{
+ uchar txp;
+ int resend;
+
+ /*
+ * The following procedure is taken from the DP8390[12D] datasheet,
+ * it seems pretty adamant that this is what has to be done.
+ */
+ txp = dp8390inb(ctlr->card.dp8390+Cr) & Txp;
+ dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Stp);
+ delay(2);
+ dp8390outb(ctlr->card.dp8390+Rbcr0, 0);
+ dp8390outb(ctlr->card.dp8390+Rbcr1, 0);
+
+ resend = 0;
+ if(txp && (dp8390inb(ctlr->card.dp8390+Isr) & (Txe|Ptx)) == 0)
+ resend = 1;
+
+ dp8390outb(ctlr->card.dp8390+Tcr, Lb);
+ dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Sta);
+ (*ctlr->card.receive)(ctlr);
+ dp8390outb(ctlr->card.dp8390+Isr, Ovw);
+ wakeup(&ctlr->rr);
+ dp8390outb(ctlr->card.dp8390+Tcr, 0);
+
+ if(resend)
+ dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Txp|Sta);
+}
+
+void
+dp8390watch(Ctlr *ctlr)
+{
int s;
+ /*
+ * Stub watchdog routine.
+ * Whine if a transmit takes too long.
+ */
s = splhi();
- board = ctlr->board;
- ring = &ctlr->tb[ctlr->ti];
- if(ring->busy == 0 && ring->owner == Interface){
- dp8390write(ctlr, board->tstart*Dp8390BufSz, ring->pkt, ring->len);
- outb(board->dp8390+Tbcr0, ring->len & 0xFF);
- outb(board->dp8390+Tbcr1, (ring->len>>8) & 0xFF);
- outb(board->dp8390+Cr, Page0|RDMAabort|Txp|Sta);
- ring->busy = 1;
+ if(ctlr->tbusy){
+ ctlr->tbusy++;
+ if(ctlr->tbusy > 1 && ctlr->debug)
+ print("TB%d|", ctlr->tbusy);
}
splx(s);
}
@@ 488,37 566,21 @@ dp8390transmit(Ctlr *ctlr)
void
dp8390intr(Ctlr *ctlr)
{
- Board *board = ctlr->board;
RingBuf *ring;
- uchar isr;
+ uchar isr, r;
/*
* While there is something of interest,
* clear all the interrupts and process.
*/
- while(isr = inb(board->dp8390+Isr)){
- outb(board->dp8390+Isr, isr);
+ dp8390outb(ctlr->card.dp8390+Imr, 0x00);
+ while(isr = dp8390inb(ctlr->card.dp8390+Isr)){
if(isr & Ovw){
- /*
- * Need to do some work here:
- * stop the chip;
- * clear out the ring;
- * re-enable the chip.
- * The procedure to put the chip back on
- * an active network is to first put it
- * into internal loopback mode, enable it,
- * then take it out of loopback.
- *
- * Untested.
- */
+ if(ctlr->card.overflow)
+ (*ctlr->card.overflow)(ctlr);
+ dp8390outb(ctlr->card.dp8390+Isr, Ovw);
ctlr->overflows++;
-
- dp8390disable(ctlr);
- (*ctlr->board->receive)(ctlr);
- outb(board->dp8390+Tcr, Lb);
- outb(board->dp8390+Cr, Page0|RDMAabort|Sta);
- dp8390attach(ctlr);
}
/*
@@ 527,35 589,43 @@ dp8390intr(Ctlr *ctlr)
* wakeup the kproc.
*/
if(isr & (Rxe|Prx)){
- (*ctlr->board->receive)(ctlr);
+ (*ctlr->card.receive)(ctlr);
+ dp8390outb(ctlr->card.dp8390+Isr, Rxe|Prx);
wakeup(&ctlr->rr);
}
/*
- * Log errors and successful transmissions.
- */
- if(isr & Txe)
- ctlr->oerrs++;
- if(isr & Rxe){
- ctlr->frames += inb(board->dp8390+Cntr0);
- ctlr->crcs += inb(board->dp8390+Cntr1);
- ctlr->buffs += inb(board->dp8390+Cntr2);
- }
- if(isr & Ptx)
- ctlr->outpackets++;
-
- /*
* A packet completed transmission, successfully or
* not. Start transmission on the next buffered packet,
* and wake the output routine.
*/
if(isr & (Txe|Ptx)){
+ r = dp8390inb(ctlr->card.dp8390+Tsr);
+ if(isr & Txe){
+ if((r & (Cdh|Fu|Crs|Abt)) && ctlr->debug)
+ print("Tsr#%2.2ux|", r);
+ ctlr->oerrs++;
+ }
+
+ dp8390outb(ctlr->card.dp8390+Isr, Txe|Ptx);
+
+ if(isr & Ptx)
+ ctlr->outpackets++;
+
ring = &ctlr->tb[ctlr->ti];
ring->owner = Host;
- ring->busy = 0;
+ ctlr->tbusy = 0;
ctlr->ti = NEXT(ctlr->ti, ctlr->ntb);
- (*ctlr->board->transmit)(ctlr);
+ (*ctlr->card.transmit)(ctlr);
wakeup(&ctlr->tr);
}
+
+ if(isr & Cnt){
+ ctlr->frames += dp8390inb(ctlr->card.dp8390+Cntr0);
+ ctlr->crcs += dp8390inb(ctlr->card.dp8390+Cntr1);
+ ctlr->buffs += dp8390inb(ctlr->card.dp8390+Cntr2);
+ dp8390outb(ctlr->card.dp8390+Isr, Cnt);
+ }
}
+ dp8390outb(ctlr->card.dp8390+Imr, Cnte|Ovwe|Txee|Rxee|Ptxe|Prxe);
}
M pc/l.s => pc/l.s +28 -0
@@ 766,3 766,31 @@ l20:
MOVB BX,-1(DI)(CX*1)
LOOP l20
RET
+
+/*
+ * The DP8390 ethernet chip needs some time between
+ * successive chip selects, so we force a jump into
+ * the instruction stream to break the pipeline.
+ */
+TEXT dp8390inb(SB), $0
+ MOVL p+0(FP),DX
+ XORL AX,AX /* CF = 0 */
+ INB
+
+ JCC _dp8390inb0 /* always true */
+ MOVL AX,AX
+
+_dp8390inb0:
+ RET
+
+TEXT dp8390outb(SB), $0
+ MOVL p+0(FP),DX
+ MOVL b+4(FP),AX
+ OUTB
+
+ CLC /* CF = 0 */
+ JCC _dp8390outb0 /* always true */
+ MOVL AX,AX
+
+_dp8390outb0:
+ RET
M power/trap.c => power/trap.c +2 -0
@@ 286,8 286,10 @@ intr(Ureg *ur)
cause &= ~INTR5;
}
if(limit == 0) {
+ LEDON(LED5);
print("intr: unable to identify and clear level5\n");
cause &= ~INTR5;
+ LEDOFF(LED5);
}
if(cause & (INTR2|INTR4)) {