From a10c2ddd6cbfc8c9f4d97ef189cc6d18fba74838 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Fri, 12 Feb 1993 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 1993-02-12 --- pc/devether.c | 81 +++++---- pc/ether.h | 112 +++++++----- pc/ether2000.c | 73 ++++---- pc/ether503.c | 346 +++++++++++++++++++++++++++++++++--- pc/ether509.c | 149 ++++++++-------- pc/ether8003.c | 142 ++++++++------- pc/ether8390.c | 468 ++++++++++++++++++++++++++++--------------------- pc/l.s | 28 +++ power/trap.c | 2 + 9 files changed, 926 insertions(+), 475 deletions(-) diff --git a/pc/devether.c b/pc/devether.c index c8b6ba2d85fcf11f9869ab3b5e358cb2a0262848..e972e4d3fe5234587fd0743d74a76f89299045fa 100644 --- a/pc/devether.c +++ b/pc/devether.c @@ -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; diff --git a/pc/ether.h b/pc/ether.h index a98b61aa52d49cf262aea6d5f0f5701848bb5034..9ad2545d7575a9c6baea655b9c8cb4809d4cd7c5 100644 --- a/pc/ether.h +++ b/pc/ether.h @@ -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 */ diff --git a/pc/ether2000.c b/pc/ether2000.c index e357b3d3f2e4be7fb3ede3c00fe4fc919b789e8f..a87820139ef241453f2608da49495c796a8e4dd1 100644 --- a/pc/ether2000.c +++ b/pc/ether2000.c @@ -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 */ }; diff --git a/pc/ether503.c b/pc/ether503.c index f518bfdee9bf366c421161ca46908cfeeb99279b..396060705225894b5fc949e04f15514482f756a7 100644 --- a/pc/ether503.c +++ b/pc/ether503.c @@ -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 */ }; diff --git a/pc/ether509.c b/pc/ether509.c index 7b33b09ccf27242b28a826eb89462861b7b38830..f959b71e9df3ec1ccbbf18f352cba1de12df0151 100644 --- a/pc/ether509.c +++ b/pc/ether509.c @@ -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 */ }; diff --git a/pc/ether8003.c b/pc/ether8003.c index c74d2ad784fd4a6b7722ef6cb4990f9e362b34a1..b3e91b42af8a402ef67a0585eaa2efe18161b072 100644 --- a/pc/ether8003.c +++ b/pc/ether8003.c @@ -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 */ }; diff --git a/pc/ether8390.c b/pc/ether8390.c index 065edea0166be23e4c146e93b2d03118d05f0b64..073e86eb064ca819796b19ed765aeeab57dedd93 100644 --- a/pc/ether8390.c +++ b/pc/ether8390.c @@ -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); } diff --git a/pc/l.s b/pc/l.s index 751a69b2a3f1ffda3160c23fe8610462a4b6e66d..48bb6b7ed75f04798a44640ab90ab32959a6887b 100644 --- a/pc/l.s +++ b/pc/l.s @@ -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 diff --git a/power/trap.c b/power/trap.c index dc0a34372b6226a77b13122f390ff7168db7db32..ebf6523a17e0c48a1678c7413711d1fc711b9039 100644 --- a/power/trap.c +++ b/power/trap.c @@ -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)) {