From 22ffe4fa3c224cccb0684eb316590444c7b04845 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Tue, 22 Sep 1992 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 1992-09-22 --- pc/clock.c | 12 + pc/devether.c | 652 +++++-------------------------------------------- pc/ether509.c | 422 ++++++++++++++++++++++++++++++++ pc/fns.h | 4 + pc/io.h | 94 +++++++ pc/l.s | 4 +- port/devscc.c | 14 +- port/portfns.h | 2 +- ss/main.c | 4 +- 9 files changed, 608 insertions(+), 600 deletions(-) create mode 100644 pc/ether509.c diff --git a/pc/clock.c b/pc/clock.c index 5b219121cbbd6f67e4ca5706a8389f2e3a65a6a0..3bd8d793c730b31629be93f5d6059f33e9d1f07b 100644 --- a/pc/clock.c +++ b/pc/clock.c @@ -20,6 +20,7 @@ enum * output a square wave whose * period is the counter period */ + Latch0= 0x06, Freq= 1193182, /* Real clock frequency */ }; @@ -40,6 +41,8 @@ delay(int l) void clockinit(void) { + ulong dc; /* change in counter */ + /* * set vector for clock interrupts */ @@ -51,6 +54,15 @@ clockinit(void) outb(Tmode, Load0square); outb(T0cntr, (Freq/HZ)); /* low byte */ outb(T0cntr, (Freq/HZ)>>8); /* high byte */ + + /* + * measure cpu speed to make delay() system + * independent + */ + delay(100); + outb(Tmode, Latch0); + dc = inb(T0cntr); + dc |= inb(T0cntr)<<8; } void diff --git a/pc/devether.c b/pc/devether.c index 03dbe7a3acfc2495b3d53ac25e0fced772bd2670..8e839f2bdb32ca113ca935eeb9dcffb7feb0d148 100644 --- a/pc/devether.c +++ b/pc/devether.c @@ -7,113 +7,33 @@ #include "io.h" #include "devtab.h" -typedef struct Hw Hw; -typedef struct Buffer Buffer; -typedef struct Type Type; -typedef struct Ctlr Ctlr; - -struct Hw { - int (*reset)(Ctlr*); - void (*init)(Ctlr*); - void (*mode)(Ctlr*, int); - void (*online)(Ctlr*, int); - void (*receive)(Ctlr*); - void (*transmit)(Ctlr*); - void (*intr)(Ureg*); - void (*tweek)(Ctlr*); - int addr; /* interface address */ - uchar *ram; /* interface shared memory address */ - int bt16; /* true if a 16 bit interface */ - int lvl; /* interrupt level */ - int size; - uchar tstart; - uchar pstart; - uchar pstop; +/* + * Half-arsed attempt at a general top-level + * ethernet driver. Needs work: + * handle multiple controllers + * much tidying + * set ethernet address + */ +extern EtherHw ether509; +extern EtherHw ether80x3; + +static EtherHw *etherhw[] = { + ðer509, + ðer80x3, + 0 }; -static Hw wd8013; enum { - Nctlr = 1, /* even one of these is too many */ - NType = 9, /* types/interface */ - - Nrb = 16, /* software receive buffers */ - Ntb = 4, /* software transmit buffers */ + Nctlr = 1, }; +static struct EtherCtlr ctlr[Nctlr]; + #define NEXT(x, l) (((x)+1)%(l)) #define OFFSETOF(t, m) ((unsigned)&(((t*)0)->m)) #define HOWMANY(x, y) (((x)+((y)-1))/(y)) #define ROUNDUP(x, y) (HOWMANY((x), (y))*(y)) -struct Buffer { - uchar owner; - uchar busy; - ushort len; - uchar pkt[sizeof(Etherpkt)]; -}; - -enum { - Host = 0, /* buffer owned by host */ - Interface = 1, /* buffer owned by interface */ -}; - -/* - * one per ethernet packet type - */ -struct Type { - QLock; - Netprot; /* stat info */ - int type; /* ethernet type */ - int prom; /* promiscuous mode */ - Queue *q; - int inuse; - Ctlr *ctlr; -}; - -/* - * per ethernet - */ -struct Ctlr { - QLock; - - Hw *hw; - int present; - - ushort nrb; /* number of software receive buffers */ - ushort ntb; /* number of software transmit buffers */ - Buffer *rb; /* software receive buffers */ - Buffer *tb; /* software transmit buffers */ - - 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 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 */ - - Type type[NType]; - uchar prom; /* true if promiscuous mode */ - uchar kproc; /* true if kproc started */ - char name[NAMELEN]; /* name of kproc */ - Network net; - - 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 */ -}; -static Ctlr ctlr[Nctlr]; - Chan* etherattach(char *spec) { @@ -189,7 +109,7 @@ etherwstat(Chan *c, char *dp) static int isobuf(void *arg) { - Ctlr *cp = arg; + EtherCtlr *cp = arg; return cp->tb[cp->th].owner == Host; } @@ -197,17 +117,17 @@ isobuf(void *arg) static void etheroput(Queue *q, Block *bp) { - Ctlr *cp; - int len, n; - Type *tp; + EtherCtlr *cp; + EtherType *tp; Etherpkt *p; - Buffer *tb; + EtherBuf *tb; + int len, n; Block *nbp; if(bp->type == M_CTL){ tp = q->ptr; if(streamparse("connect", bp)) - tp->type = strtol((char *)bp->rptr, 0, 0); + tp->type = strtol((char*)bp->rptr, 0, 0); else if(streamparse("promiscuous", bp)) { tp->prom = 1; (*tp->ctlr->hw->mode)(tp->ctlr, 1); @@ -216,7 +136,7 @@ etheroput(Queue *q, Block *bp) return; } - cp = ((Type *)q->ptr)->ctlr; + cp = ((EtherType*)q->ptr)->ctlr; /* * give packet a local address, return upstream if destined for @@ -224,7 +144,7 @@ etheroput(Queue *q, Block *bp) */ if(BLEN(bp) < ETHERHDRSIZE && (bp = pullup(bp, ETHERHDRSIZE)) == 0) return; - p = (Etherpkt *)bp->rptr; + p = (Etherpkt*)bp->rptr; memmove(p->s, cp->ea, sizeof(cp->ea)); if(memcmp(cp->ea, p->d, sizeof(cp->ea)) == 0){ len = blen(bp); @@ -308,8 +228,8 @@ etheroput(Queue *q, Block *bp) static void etherstopen(Queue *q, Stream *s) { - Ctlr *cp = &ctlr[0]; - Type *tp; + EtherCtlr *cp = &ctlr[0]; + EtherType *tp; tp = &cp->type[s->id]; qlock(tp); @@ -330,9 +250,9 @@ etherstopen(Queue *q, Stream *s) static void etherstclose(Queue *q) { - Type *tp; + EtherType *tp; - tp = (Type *)(q->ptr); + tp = (EtherType*)(q->ptr); if(tp->prom) (*tp->ctlr->hw->mode)(tp->ctlr, 0); qlock(tp); @@ -356,8 +276,8 @@ static Qinfo info = { static int clonecon(Chan *c) { - Ctlr *cp = &ctlr[0]; - Type *tp; + EtherCtlr *cp = &ctlr[0]; + EtherType *tp; USED(c); for(tp = cp->type; tp < &cp->type[NType]; tp++){ @@ -378,7 +298,7 @@ clonecon(Chan *c) static void statsfill(Chan *c, char *p, int n) { - Ctlr *cp = &ctlr[0]; + EtherCtlr *cp = &ctlr[0]; char buf[256]; USED(c); @@ -393,7 +313,7 @@ static void typefill(Chan *c, char *p, int n) { char buf[16]; - Type *tp; + EtherType *tp; tp = &ctlr[0].type[STREAMID(c->qid.path)]; sprint(buf, "%d", tp->type); @@ -401,11 +321,11 @@ typefill(Chan *c, char *p, int n) } static void -etherup(Ctlr *cp, void *data, int len) +etherup(EtherCtlr *cp, void *data, int len) { Etherpkt *p; int t; - Type *tp; + EtherType *tp; Block *bp; p = data; @@ -448,7 +368,7 @@ etherup(Ctlr *cp, void *data, int len) static int isinput(void *arg) { - Ctlr *cp = arg; + EtherCtlr *cp = arg; return cp->lbq.first || cp->rb[cp->ri].owner == Host; } @@ -456,20 +376,22 @@ isinput(void *arg) static void etherkproc(void *arg) { - Ctlr *cp = arg; - Buffer *rb; + EtherCtlr *cp = arg; + EtherBuf *rb; Block *bp; if(waserror()){ print("%s noted\n", cp->name); - (*cp->hw->init)(cp); + if(cp->hw->init) + (*cp->hw->init)(cp); cp->kproc = 0; nexterror(); } cp->kproc = 1; for(;;){ tsleep(&cp->rr, isinput, cp, 500); - (*cp->hw->tweek)(cp); + if(cp->hw->tweak) + (*cp->hw->tweak)(cp); /* * process any internal loopback packets @@ -493,19 +415,33 @@ etherkproc(void *arg) } } +static void +etherintr(Ureg *ur) +{ + EtherCtlr *cp = &ctlr[0]; + + USED(ur); + (*cp->hw->intr)(cp); +} + void etherreset(void) { + EtherCtlr *cp; + EtherHw **hw; int i; - Ctlr *cp; cp = &ctlr[0]; - cp->hw = &wd8013; - if((*cp->hw->reset)(cp) < 0){ - cp->present = 0; - return; + for(hw = etherhw; *hw; hw++){ + cp->hw = *hw; + if((*cp->hw->reset)(cp) == 0){ + cp->present = 1; + setvec(Int0vec + cp->hw->irq, etherintr); + break; + } } - cp->present = 1; + if(cp->present == 0) + return; memset(cp->ba, 0xFF, sizeof(cp->ba)); @@ -528,7 +464,7 @@ void etherinit(void) { int ctlrno = 0; - Ctlr *cp = &ctlr[ctlrno]; + EtherCtlr *cp = &ctlr[ctlrno]; int i; if(cp->present == 0) @@ -554,465 +490,3 @@ etherinit(void) kproc(cp->name, etherkproc, cp); } } - -typedef struct { - uchar msr; /* 83C584 bus interface */ - uchar icr; - uchar iar; - uchar bio; - uchar irr; - uchar laar; - uchar ijr; - uchar gp2; - uchar lan[6]; - uchar id; - uchar cksum; - - union { /* DP8390/83C690 LAN controller */ - struct { /* Page0, read */ - uchar cr; - uchar clda0; - uchar clda1; - uchar bnry; - uchar tsr; - uchar ncr; - uchar fifo; - uchar isr; - uchar crda0; - uchar crda1; - uchar pad0x0A; - uchar pad0x0B; - uchar rsr; - uchar cntr0; - uchar cntr1; - uchar cntr2; - } r; - struct { /* Page0, write */ - uchar cr; - uchar pstart; - uchar pstop; - uchar bnry; - uchar tpsr; - uchar tbcr0; - uchar tbcr1; - uchar isr; - uchar rsar0; - uchar rsar1; - uchar rbcr0; - uchar rbcr1; - uchar rcr; - uchar tcr; - uchar dcr; - uchar imr; - } w; - struct { /* Page1, read/write */ - uchar cr; - uchar par[6]; - uchar curr; - uchar mar[8]; - }; - struct { /* Page2, read */ - uchar cr; - uchar pstart; - uchar pstop; - uchar dummy1[1]; - uchar tstart; - uchar next; - uchar block; - uchar enh; - uchar dummy2[4]; - uchar rcon; - uchar tcon; - uchar dcon; - uchar intmask; - } r2; - struct { /* Page2, write */ - uchar cr; - uchar trincrl; - uchar trincrh; - uchar dummy1[2]; - uchar next; - uchar block; - uchar enh; - } w2; - }; -} Wd8013; - -enum { - MENB = 0x40, /* memory enable */ - - /* bit definitions for laar */ - ZeroWS16 = (1<<5), /* zero wait states for 16-bit ops */ - L16EN = (1<<6), /* enable 16-bit LAN operation */ - M16EN = (1<<7), /* enable 16-bit memory access */ - - /* bit defintitions for DP8390/83C690 cr */ - Page0 = (0<<6), - Page1 = (1<<6), - Page2 = (2<<6), - RD2 = (4<<3), - TXP = (1<<2), - STA = (1<<1), - STP = (1<<0), -}; - -#define IN(hw, m) inb((hw)->addr+OFFSETOF(Wd8013, m)) -#define OUT(hw, m, x) outb((hw)->addr+OFFSETOF(Wd8013, m), (x)) - -typedef struct { - uchar status; - uchar next; - uchar len0; - uchar len1; - uchar data[256-4]; -} Ring; - -static void -wd8013dumpregs(Hw *hw) -{ - print("msr=#%2.2ux\n", IN(hw, msr)); - print("icr=#%2.2ux\n", IN(hw, icr)); - print("iar=#%2.2ux\n", IN(hw, iar)); - print("bio=#%2.2ux\n", IN(hw, bio)); - print("irr=#%2.2ux\n", IN(hw, irr)); - print("laar=#%2.2ux\n", IN(hw, laar)); - print("ijr=#%2.2ux\n", IN(hw, ijr)); - print("gp2=#%2.2ux\n", IN(hw, gp2)); - print("lan0=#%2.2ux\n", IN(hw, lan[0])); - print("lan1=#%2.2ux\n", IN(hw, lan[1])); - print("lan2=#%2.2ux\n", IN(hw, lan[2])); - print("lan3=#%2.2ux\n", IN(hw, lan[3])); - print("lan4=#%2.2ux\n", IN(hw, lan[4])); - print("lan5=#%2.2ux\n", IN(hw, lan[5])); - print("id=#%2.2ux\n", IN(hw, id)); -} - -/* mapping from configuration bits to interrupt level */ -int intrmap[] = -{ - 9, 3, 5, 7, 10, 11, 15, 4, -}; - -/* - * get configuration parameters, enable memory - */ -static int -wd8013reset(Ctlr *cp) -{ - Hw *hw = cp->hw; - int i; - uchar msr, icr, laar, irr; - ulong ram; - - /* find the ineterface */ - SET(msr, icr, irr, laar); - for(hw->addr = 0x200; hw->addr < 0x400; hw->addr += 0x20){ - msr = IN(hw, msr); - icr = IN(hw, icr); - irr = IN(hw, irr); - laar = IN(hw, laar); - if((msr&0x80) || (icr&0xf0) || irr == 0xff || laar == 0xff) - continue; /* nothing there */ - - /* ethernet address */ - for(i = 0; i < sizeof(cp->ea); i++) - cp->ea[i] = IN(hw, lan[i]); - - /* look for an elite ether address */ - if(cp->ea[0] == 0x00 && cp->ea[1] == 0x00 && cp->ea[2] == 0xC0) - break; - } - if(hw->addr >= 0x400) - return -1; - - if(cp->rb == 0){ - cp->rb = xspanalloc(sizeof(Buffer)*Nrb, BY2PG, 0); - cp->nrb = Nrb; - cp->tb = xspanalloc(sizeof(Buffer)*Ntb, BY2PG, 0); - cp->ntb = Ntb; - } - - /* 16 bit operation? */ - hw->bt16 = icr & 0x1; - - /* address of interface RAM */ - ram = KZERO | ((msr & 0x3f) << 13); - if(hw->bt16) - ram |= (laar & 0x3f)<<19; - else - ram |= 0x80000; - hw->ram = (uchar*)ram; - - /* interrupt level */ - hw->lvl = intrmap[((irr>>5) & 0x3) | (icr & 0x4)]; - - /* ram size */ - if(icr&(1<<3)) - hw->size = 32*1024; - else - hw->size = 8*1024; - if(hw->bt16) - hw->size <<= 1; - hw->pstart = HOWMANY(sizeof(Etherpkt), 256); - hw->pstop = HOWMANY(hw->size, 256); - -print("elite at %lux width %d addr %lux size %d lvl %d\n", hw->addr, hw->bt16?16:8, - hw->ram, hw->size, hw->lvl);/**/ - - /* enable interface RAM, set interface width */ - OUT(hw, msr, MENB|msr); - if(hw->bt16) - OUT(hw, laar, laar|L16EN|M16EN|ZeroWS16); - - (*hw->init)(cp); - setvec(Int0vec + hw->lvl, hw->intr); - return 0; -} - -static void -dp8390rinit(Ctlr *cp) -{ - Hw *hw = cp->hw; - - OUT(hw, w.cr, Page0|RD2|STP); - OUT(hw, w.bnry, hw->pstart); - OUT(hw, w.cr, Page1|RD2|STP); - OUT(hw, curr, hw->pstart+1); - OUT(hw, w.cr, Page0|RD2|STA); -} - -/* - * we leave the chip idling on internal loopback - * and pointing to Page0. - */ -static void -dp8390init(Ctlr *cp) -{ - Hw *hw = cp->hw; - int i; - - OUT(hw, w.cr, Page0|RD2|STP); - if(hw->bt16) - OUT(hw, w.dcr, (1<<0)|(3<<5)); /* 16 bit interface, 12 byte DMA burst */ - else - OUT(hw, w.dcr, 0x48); /* FT1|LS */ - OUT(hw, w.rbcr0, 0); - OUT(hw, w.rbcr1, 0); - if(cp->prom) - OUT(hw, w.rcr, 0x14); /* PRO|AB */ - else - OUT(hw, w.rcr, 0x04); /* AB */ - OUT(hw, w.tcr, 0x20); /* LB0 */ - - OUT(hw, w.bnry, hw->pstart); - OUT(hw, w.pstart, hw->pstart); - OUT(hw, w.pstop, hw->pstop); - OUT(hw, w.isr, 0xFF); - OUT(hw, w.imr, 0x1F); /* OVWE|TXEE|RXEE|PTXE|PRXE */ - - OUT(hw, w.cr, Page1|RD2|STP); - for(i = 0; i < sizeof(cp->ea); i++) - OUT(hw, par[i], cp->ea[i]); - OUT(hw, curr, hw->pstart+1); - - OUT(hw, w.cr, Page0|RD2|STA); - OUT(hw, w.tpsr, 0); -} - -void -wd8013mode(Ctlr *cp, int on) -{ - qlock(cp); - if(on){ - cp->prom++; - if(cp->prom == 1) - OUT(cp->hw, w.rcr, 0x14);/* PRO|AB */ - } - else { - cp->prom--; - if(cp->prom == 0) - OUT(cp->hw, w.rcr, 0x04);/* AB */ - } - qunlock(cp); -} - -static void -wd8013online(Ctlr *cp, int on) -{ - USED(on); - OUT(cp->hw, w.tcr, 0); -} - -static void -wd8013tweek(Ctlr *cp) -{ - uchar msr; - Hw *hw = cp->hw; - int s; - - s = splhi(); - msr = IN(hw, msr); - if((msr & MENB) == 0){ - /* board has reset itself, start again */ - delay(100); - - (*hw->reset)(cp); - etherinit(); - - wakeup(&cp->tr); - wakeup(&cp->rr); - } - splx(s); -} - -/* - * 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. - * - * we peek at the DMA registers and, if they are changing, wait. - */ -void -waitfordma(Hw *hw) -{ - uchar a,b,c; - - for(;;delay(10)){ - a = IN(hw, r.clda0); - b = IN(hw, r.clda0); - if(a != b) - continue; - c = IN(hw, r.clda0); - if(c != b) - continue; - break; - } -} - -static void -wd8013receive(Ctlr *cp) -{ - Hw *hw = cp->hw; - Buffer *rb; - uchar bnry, curr, next; - Ring *p; - int i, len; - - bnry = IN(hw, r.bnry); - next = bnry+1; - if(next >= hw->pstop) - next = hw->pstart; - for(i = 0; ; i++){ - OUT(hw, w.cr, Page1|RD2|STA); - curr = IN(hw, curr); - OUT(hw, w.cr, Page0|RD2|STA); - if(next == curr) - break; - if(strcmp(machtype, "NCRD.0") == 0) - waitfordma(hw); - cp->inpackets++; - p = &((Ring*)hw->ram)[next]; - len = ((p->len1<<8)|p->len0)-4; - if(p->next < hw->pstart || p->next >= hw->pstop || len < 60){ - /*print("%d/%d : #%2.2ux #%2.2ux #%2.2ux #%2.2ux\n", next, len, - p->status, p->next, p->len0, p->len1);/**/ - dp8390rinit(cp); - break; - } - rb = &cp->rb[cp->ri]; - if(rb->owner == Interface){ - rb->len = len; - if((p->data+len) >= (hw->ram+hw->size)){ - len = (hw->ram+hw->size) - p->data; - memmove(rb->pkt+len, - &((Ring*)hw->ram)[hw->pstart], - (p->data+rb->len) - (hw->ram+hw->size)); - } - memmove(rb->pkt, p->data, len); - rb->owner = Host; - cp->ri = NEXT(cp->ri, cp->nrb); - } - p->status = 0; - next = p->next; - bnry = next-1; - if(bnry < hw->pstart) - bnry = hw->pstop-1; - OUT(hw, w.bnry, bnry); - } -} - -static void -wd8013transmit(Ctlr *cp) -{ - Hw *hw; - Buffer *tb; - int s; - - s = splhi(); - hw = cp->hw; - tb = &cp->tb[cp->ti]; - if(tb->busy == 0 && tb->owner == Interface){ - memmove(hw->ram, tb->pkt, tb->len); - OUT(hw, w.tbcr0, tb->len & 0xFF); - OUT(hw, w.tbcr1, (tb->len>>8) & 0xFF); - OUT(hw, w.cr, Page0|RD2|TXP|STA); - tb->busy = 1; - } - splx(s); -} - -static void -wd8013intr(Ureg *ur) -{ - Ctlr *cp = &ctlr[0]; - Hw *hw = cp->hw; - Buffer *tb; - uchar isr; - - USED(ur); - while(isr = IN(hw, r.isr)){ - OUT(hw, w.isr, isr); - /* - * we have received packets. - */ - if(isr & (0x04|0x01)){ /* Rxe|Prx - packet received */ - (*cp->hw->receive)(cp); - wakeup(&cp->rr); - } - if(isr & 0x10) /* Ovw - overwrite warning */ - cp->overflows++; - if(isr & 0x08) /* Txe - transmit error */ - cp->oerrs++; - if(isr & 0x04){ /* Rxe - receive error */ - cp->frames += IN(hw, r.cntr0); - cp->crcs += IN(hw, r.cntr1); - cp->buffs += IN(hw, r.cntr2); - } - if(isr & 0x02) /* Ptx - packet transmitted */ - cp->outpackets++; - /* - * a packet completed transmission, successfully or - * not. start transmission on the next buffered packet, - * and wake the output routine. - */ - if(isr & (0x08|0x02)){ - tb = &cp->tb[cp->ti]; - tb->owner = Host; - tb->busy = 0; - cp->ti = NEXT(cp->ti, cp->ntb); - (*cp->hw->transmit)(cp); - wakeup(&cp->tr); - } - } -} - -static Hw wd8013 = -{ - wd8013reset, - dp8390init, - wd8013mode, - wd8013online, - wd8013receive, - wd8013transmit, - wd8013intr, - wd8013tweek, -}; diff --git a/pc/ether509.c b/pc/ether509.c new file mode 100644 index 0000000000000000000000000000000000000000..f4db22f66eae3da3424075b3268547cbbd12bfc0 --- /dev/null +++ b/pc/ether509.c @@ -0,0 +1,422 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "../port/error.h" +#include "io.h" +#include "devtab.h" + +#define NEXT(x, l) (((x)+1)%(l)) +#define OFFSETOF(t, m) ((unsigned)&(((t*)0)->m)) +#define HOWMANY(x, y) (((x)+((y)-1))/(y)) +#define ROUNDUP(x, y) (HOWMANY((x), (y))*(y)) + +enum { + Nrb = 16, /* software receive buffers */ + Ntb = 4, /* software transmit buffers */ +}; + +enum { + IDport = 0x0100, /* anywhere between 0x0100 and 0x01F0 */ + + /* Commands */ + SelectWindow = 0x01, /* SelectWindow command */ + StartCoax = 0x02, /* Start Coaxial Transceiver */ + RxDisable = 0x03, /* RX Disable */ + RxEnable = 0x04, /* RX Enable */ + RxDiscard = 0x08, /* RX Discard Top Packet */ + TxEnable = 0x09, /* TX Enable */ + TxDisable = 0x0A, /* TX Disable */ + AckIntr = 0x0D, /* Acknowledge Interrupt */ + SetIntrMask = 0x0E, /* Set Interrupt Mask */ + SetReadZeroMask = 0x0F, /* Set Read Zero Mask */ + SetRxFilter = 0x10, /* Set RX Filter */ + SetTxAvailable = 0x12, /* Set TX Available Threshold */ + + /* RX Filter Command Bits */ + MyEtherAddr = 0x01, /* Individual address */ + Multicast = 0x02, /* Group (multicast) addresses */ + Broadcast = 0x04, /* Broadcast address */ + Promiscuous = 0x08, /* All addresses (promiscuous mode */ + + /* Window Register Offsets */ + Command = 0x0E, /* all windows */ + Status = 0x0E, + + EEPROMdata = 0x0C, /* window 0 */ + EEPROMcmd = 0x0A, + ResourceConfig = 0x08, + ConfigControl = 0x04, + + TxFreeBytes = 0x0C, /* window 1 */ + TxStatus = 0x0B, + RxStatus = 0x08, + Fifo = 0x00, + + /* Status/Interrupt Bits */ + Latch = 0x0001, /* Interrupt Latch */ + TxComplete = 0x0004, /* TX Complete */ + TxAvailable = 0x0008, /* TX Available */ + RxComplete = 0x0010, /* RX Complete */ + AllIntr = 0x00FE, /* All Interrupt Bits */ + CmdInProgress = 0x1000, /* Command In Progress */ + + /* RxStatus Bits */ + RxByteMask = 0x07FF, /* RX Bytes (0-1514) */ + RxErrMask = 0x3800, /* Type of Error: */ + RxErrOverrun = 0x0000, /* Overrrun */ + RxErrOversize = 0x0800, /* Oversize Packet (>1514) */ + RxErrDribble = 0x1000, /* Dribble Bit(s) */ + RxErrRunt = 0x1800, /* Runt Packet */ + RxErrFraming = 0x2000, /* Alignment (Framing) */ + RxErrCRC = 0x2800, /* CRC */ + RxError = 0x4000, /* Error */ + RxEmpty = 0x8000, /* Incomplete or FIFO empty */ +}; + +#define COMMAND(hw, cmd, a) outs(hw->addr+Command, ((cmd)<<11)|(a)) + +/* + * get configuration parameters + */ +static int +reset(EtherCtlr *cp) +{ + EtherHw *hw = cp->hw; + int i, ea; + ushort acr; + uchar al; + + cp->rb = xspanalloc(sizeof(EtherBuf)*Nrb, BY2PG, 0); + cp->nrb = Nrb; + cp->tb = xspanalloc(sizeof(EtherBuf)*Ntb, BY2PG, 0); + cp->ntb = Ntb; + + /* + * Do the little configuration dance. We only look + * at the first board that responds, if we ever have more + * than one we'll need to modify this sequence. + * + * 2. Write two 0 bytes then the ID sequence to the IDport. + */ + outb(IDport, 0); + outb(IDport, 0); + outb(IDport, 0xc0); + delay(100) + outb(IDport, 0); + outb(IDport, 0); + for(al = 0xFF, i = 0; i < 255; i++){ + outb(IDport, al); + if(al & 0x80){ + al <<= 1; + al ^= 0xCF; + } + else + al <<= 1; + } + + /* + * 3. Read the Product ID from the EEPROM. + * This is done by writing the IDPort with 0x83 (0x80 + * is the 'read EEPROM command, 0x03 is the offset of + * the Product ID field in the EEPROM). + * The data comes back 1 bit at a time. + * We seem to need a delay here between reading the bits. + * + * If the ID doesn't match the 3C509 ID code, the adapter + * probably isn't there, so barf. + */ + outb(IDport, 0x83); + for(acr = 0, i = 0; i < 16; i++){ + delay(5); + acr <<= 1; + acr |= inb(IDport) & 0x01; + } + if((acr & 0xF0FF) != 0x9050) + return -1; + + /* + * 3. Read the Address Configuration from the EEPROM. + * The Address Configuration field is at offset 0x08 in the EEPROM). + * 6. Activate the adapter by writing the Activate command + * (0xFF). + */ + outb(IDport, 0x88); + for(acr = 0, i = 0; i < 16; i++){ + delay(20); + acr <<= 1; + acr |= inb(IDport) & 0x01; + } + outb(IDport, 0xFF); + + /* + * 8. Now we can talk to the adapter's I/O base addresses. + * We get the I/O base address from the acr just read. + * + * Enable the adapter. + */ + hw->addr = (acr & 0x1F)*0x10 + 0x200; + outb(hw->addr+ConfigControl, 0x01); + + /* + * Read the IRQ from the Resource Configuration Register + * and the ethernet address from the EEPROM. + * The EEPROM command is 8bits, the lower 6 bits being + * the address offset. + */ + hw->irq = (ins(hw->addr+ResourceConfig)>>12) & 0x0F; + for(ea = 0, i = 0; i < 3; i++, ea += 2){ + while(ins(hw->addr+EEPROMcmd) & 0x8000) + ; + outs(hw->addr+EEPROMcmd, (2<<6)|i); + while(ins(hw->addr+EEPROMcmd) & 0x8000) + ; + acr = ins(hw->addr+EEPROMdata); + cp->ea[ea] = (acr>>8) & 0xFF; + cp->ea[ea+1] = acr & 0xFF; + } + + /* + * Finished with window 0. Now set the ethernet address + * in window 2. + * Commands have the format 'CCCCCAAAAAAAAAAA' where C + * is a bit in the command and A is a bit in the argument. + */ + COMMAND(hw, SelectWindow, 2); + for(i = 0; i < 6; i++) + outb(hw->addr+i, cp->ea[i]); + + /* + * Finished with window 2. + * Set window 1 for normal operation. + */ + COMMAND(hw, SelectWindow, 1); + + /* + * If we have a 10BASE2 transceiver, start the DC-DC + * converter. Wait > 800 microseconds. + */ + if(((acr>>14) & 0x03) == 0x03){ + COMMAND(hw, StartCoax, 0); + delay(1); + } + + print("3C509 I/O addr %lux irq %d:", hw->addr, hw->irq); + for(i = 0; i < sizeof(cp->ea); i++) + print(" %2.2ux", cp->ea[i]); + print("\n"); + + return 0; +} + +static void +mode(EtherCtlr *cp, int on) +{ + EtherHw *hw = cp->hw; + + qlock(cp); + if(on){ + cp->prom++; + if(cp->prom == 1) + COMMAND(hw, SetRxFilter, Promiscuous|Broadcast|MyEtherAddr); + } + else{ + cp->prom--; + if(cp->prom == 0) + COMMAND(hw, SetRxFilter, Broadcast|MyEtherAddr); + } + qunlock(cp); +} + +static void +online(EtherCtlr *cp, int on) +{ + EtherHw *hw = cp->hw; + + USED(on); /* BUG */ + /* + * Set the receiver packet filter for our own and + * and broadcast addresses, set the interrupt masks + * for all interrupts, and enable the receiver and transmitter. + * The only interrupt we should see under normal conditions + * is the receiver interrupt. If the transmit FIFO fills up, + * we will also see TxAvailable interrupts. + */ + COMMAND(hw, SetRxFilter, Broadcast|MyEtherAddr); + COMMAND(hw, SetReadZeroMask, AllIntr|Latch); + COMMAND(hw, SetIntrMask, AllIntr|Latch); + COMMAND(hw, RxEnable, 0); + COMMAND(hw, TxEnable, 0); +} + + +static int +getdiag(EtherHw *hw) +{ + int bytes; + + COMMAND(hw, SelectWindow, 4); + bytes = ins(hw->addr+0x04); + COMMAND(hw, SelectWindow, 1); + return bytes & 0xFFFF; +} + +static void +receive(EtherCtlr *cp) +{ + EtherHw *hw = cp->hw; + ushort status; + EtherBuf *rb; + int len; + + while(((status = ins(hw->addr+RxStatus)) & RxEmpty) == 0){ + + /* + * If we had an error, log it and continue + * without updating the ring. + */ + if(status & RxError){ + print("error #%ux, #%ux\n", status, getdiag(hw)); + switch(status & RxErrMask){ + + case RxErrOverrun: /* Overrrun */ + cp->overflows++; + break; + + case RxErrOversize: /* Oversize Packet (>1514) */ + case RxErrRunt: /* Runt Packet */ + cp->buffs++; + break; + case RxErrFraming: /* Alignment (Framing) */ + cp->frames++; + break; + + case RxErrCRC: /* CRC */ + cp->crcs++; + break; + } + } + else { + /* + * We have a packet. Read it into the next + * free ring buffer, if any. + * The CRC is already stripped off. + */ + rb = &cp->rb[cp->ri]; + if(rb->owner == Interface){ + len = (status & RxByteMask); + rb->len = len; + + /* + * Must read len bytes padded to a + * doubleword. We can pick them out 16-bits + * at a time (can try 32-bits at a time + * later). + insl(hw->addr+Fifo, rb->pkt, HOWMANY(len, 4)); + */ + inss(hw->addr+Fifo, rb->pkt, HOWMANY(len, 2)); + + /* + * Update the ring. + */ + rb->owner = Host; + cp->ri = NEXT(cp->ri, cp->nrb); + } + } + /* + * Discard the packet as we're done with it. + * Wait for discard to complete. + */ + COMMAND(hw, RxDiscard, 0); + while(ins(hw->addr+Status) & CmdInProgress) + ; + } +} + +static void +transmit(EtherCtlr *cp) +{ + EtherHw *hw = cp->hw; + EtherBuf *tb; + int s; + ushort len; + + s = splhi(); + for(tb = &cp->tb[cp->ti]; tb->owner == Interface; tb = &cp->tb[cp->ti]){ + + /* + * If there's no room in the FIFO for this packet, + * set up an interrupt for when space becomes available. + */ + if(tb->len > ins(hw->addr+TxFreeBytes)){ + COMMAND(hw, SetTxAvailable, tb->len); + break; + } + + /* + * There's room, copy the packet to the FIFO and free + * the buffer back to the host. + * Output packet muat be a multiple of 4 in length. + */ + len = ROUNDUP(tb->len, 4)/2; + outs(hw->addr+Fifo, tb->len); + outs(hw->addr+Fifo, 0); + outss(hw->addr+Fifo, tb->pkt, len); + tb->owner = Host; + cp->ti = NEXT(cp->ti, cp->ntb); + } + splx(s); +} + +static void +interrupt(EtherCtlr *cp) +{ + EtherHw *hw = cp->hw; + ushort status; + + status = ins(hw->addr+Status); + + if(status & RxComplete){ + (*cp->hw->receive)(cp); + wakeup(&cp->rr); + status &= ~RxComplete; + } + + if(status & TxComplete){ + /* + * Needs work here. + */ + print("txstat %ux\n", inb(hw->addr+TxStatus)); + } + + if(status & TxAvailable){ + (*cp->hw->transmit)(cp); + wakeup(&cp->tr); + status &= ~TxAvailable; + } + + /* + * Panic if there are any interrupt bits on we haven't + * dealt with other than Latch. + */ + if(status & AllIntr) + panic("ether509 interrupt: #%lux, #%ux\n", status, getdiag(hw)); + + /* + * Acknowledge the interrupt. + */ + COMMAND(hw, AckIntr, Latch); +} + +EtherHw ether509 = { + reset, + 0, /* init */ + mode, + online, + receive, + transmit, + interrupt, + 0, /* tweak */ + 0, /* I/O base address */ +}; diff --git a/pc/fns.h b/pc/fns.h index 6a667074ebc8c2492e272b585d6b108fce1b1003..cb9678a7e3b8fa664fa7b94510759a0811c6808a 100644 --- a/pc/fns.h +++ b/pc/fns.h @@ -31,7 +31,9 @@ void i8042reset(void); void ident(void); void idle(void); int inb(int); +ushort ins(int); void inss(int, void*, int); +void insl(int, void*, int); void kbdinit(void); void mathinit(void); void mmuinit(void); @@ -42,7 +44,9 @@ void mouseaccelerate(int); void mouseres(int); void mousespeed(int); void outb(int, int); +void outs(int, ushort); void outss(int, void*, int); +void outsl(int, void*, int); void pmubuzz(int, int); int pmucpuspeed(int); void pmulights(int); diff --git a/pc/io.h b/pc/io.h index 16fafa80fcfde8564b2b71b21421fd60d039cb52..d653db0721f9134902e604d072e26f9d71cd7390 100644 --- a/pc/io.h +++ b/pc/io.h @@ -24,3 +24,97 @@ enum Syscallvec= 64, }; + +typedef struct EtherHw EtherHw; +typedef struct EtherBuf EtherBuf; +typedef struct EtherType EtherType; +typedef struct EtherCtlr EtherCtlr; + +struct EtherHw { + int (*reset)(EtherCtlr*); + void (*init)(EtherCtlr*); + void (*mode)(EtherCtlr*, int); + void (*online)(EtherCtlr*, int); + void (*receive)(EtherCtlr*); + void (*transmit)(EtherCtlr*); + void (*intr)(EtherCtlr*); + void (*tweak)(EtherCtlr*); + int addr; /* interface address */ + uchar *ram; /* interface shared memory address */ + int bt16; /* true if a 16 bit interface */ + int irq; /* interrupt level */ + int size; + uchar tstart; + uchar pstart; + uchar pstop; +}; + +struct EtherBuf { + uchar owner; + uchar busy; + ushort len; + uchar pkt[sizeof(Etherpkt)]; +}; + +enum { + Host = 0, /* buffer owned by host */ + Interface = 1, /* buffer owned by interface */ + + NType = 9, /* types/interface */ +}; + +/* + * one per ethernet packet type + */ +struct EtherType { + QLock; + Netprot; /* stat info */ + int type; /* ethernet type */ + int prom; /* promiscuous mode */ + Queue *q; + int inuse; + EtherCtlr *ctlr; +}; + +/* + * per ethernet + */ +struct EtherCtlr { + QLock; + + EtherHw *hw; + int present; + + ushort nrb; /* number of software receive buffers */ + ushort ntb; /* number of software transmit buffers */ + EtherBuf *rb; /* software receive buffers */ + EtherBuf *tb; /* software transmit buffers */ + + 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 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 */ + + EtherType type[NType]; + uchar prom; /* true if promiscuous mode */ + uchar kproc; /* true if kproc started */ + char name[NAMELEN]; /* name of kproc */ + Network net; + + 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 */ +}; diff --git a/pc/l.s b/pc/l.s index 61a55c1471a5218d8981b1c2b9e497cbea020eeb..d2bf38e15ee9960166757e8bef1f9b96ca0fe125 100644 --- a/pc/l.s +++ b/pc/l.s @@ -226,7 +226,7 @@ TEXT ins(SB), $0 MOVL p+0(FP), DX XORL AX, AX - INL + OP16; INL RET @@ -258,7 +258,7 @@ TEXT insl(SB),$0 TEXT outs(SB), $0 MOVL p+0(FP), DX MOVL s+4(FP), AX - OUTL + OP16; OUTL RET /* diff --git a/port/devscc.c b/port/devscc.c index ae6a8db1edfe611ff3859db0bd853816f15b9aaf..49e08fc34aa639e61fe4111f36b5491c53c4cf2b 100644 --- a/port/devscc.c +++ b/port/devscc.c @@ -271,7 +271,7 @@ sccbreak(SCC *sp, int ms) * transmit and receive enabled, interrupts disabled. */ static void -sccsetup0(SCC *sp) +sccsetup0(SCC *sp, int brsource) { memset(sp->sticky, 0, sizeof(sp->sticky)); @@ -284,9 +284,11 @@ sccsetup0(SCC *sp) sccsetbaud(sp, 9600); sp->sticky[4] = Rx1stop | X16; sccwrreg(sp, 4, 0); - sp->sticky[11] = TxClockBR | RxClockBR | TRxCOutBR | TRxCOI; + sp->sticky[11] = TxClockBR | RxClockBR | TRxCOutBR /*| TRxCOI*/; sccwrreg(sp, 11, 0); - sp->sticky[14] = BREna | BRSource; + sp->sticky[14] = BREna; + if(brsource) + sp->sticky[14] |= BRSource; sccwrreg(sp, 14, 0); /* @@ -299,7 +301,7 @@ sccsetup0(SCC *sp) } void -sccsetup(void *addr, ulong freq) +sccsetup(void *addr, ulong freq, int brsource) { SCCdev *dev; SCC *sp; @@ -314,13 +316,13 @@ sccsetup(void *addr, ulong freq) sp->ptr = &dev->ptra; sp->data = &dev->dataa; sp->freq = freq; - sccsetup0(sp); + sccsetup0(sp, brsource); sp = xalloc(sizeof(SCC)); scc[nscc+1] = sp; sp->ptr = &dev->ptrb; sp->data = &dev->datab; sp->freq = freq; - sccsetup0(sp); + sccsetup0(sp, brsource); nscc += 2; } diff --git a/port/portfns.h b/port/portfns.h index 3e41dbe897c8f53fb108593ec38f36a2d77d4af1..a106cce2abb10a3b7f6210910da70c841989e502 100644 --- a/port/portfns.h +++ b/port/portfns.h @@ -192,7 +192,7 @@ Proc* runproc(void); void savefpregs(FPsave*); void sccclock(void); void sccintr(void); -void sccsetup(void*, ulong); +void sccsetup(void*, ulong, int); void sccspecial(int, IOQ*, IOQ*, int); void sched(void); void schedinit(void); diff --git a/ss/main.c b/ss/main.c index 84c78b7d93c439be98d1e8b317be408a885c54b3..f7d199de183d844910a373504cf5acdd079cfe34 100644 --- a/ss/main.c +++ b/ss/main.c @@ -115,9 +115,9 @@ ioinit(void) /* tell scc driver its addresses */ k = kmappa(KMDUART, PTEIO|PTENOCACHE); - sccsetup((void*)(k->va), KMFREQ); + sccsetup((void*)(k->va), KMFREQ, 1); k = kmappa(EIADUART, PTEIO|PTENOCACHE); - sccsetup((void*)(k->va), EIAFREQ); + sccsetup((void*)(k->va), EIAFREQ, 1); /* scc port 0 is the keyboard */ sccspecial(0, 0, &kbdq, 2400);