M pc/clock.c => pc/clock.c +12 -0
@@ 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
M pc/devether.c => pc/devether.c +63 -589
@@ 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,
-};
A pc/ether509.c => pc/ether509.c +422 -0
@@ 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 */
+};
M pc/fns.h => pc/fns.h +4 -0
@@ 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);
M pc/io.h => pc/io.h +94 -0
@@ 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 */
+};
M pc/l.s => pc/l.s +2 -2
@@ 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
/*
M port/devscc.c => port/devscc.c +8 -6
@@ 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;
}
M port/portfns.h => port/portfns.h +1 -1
@@ 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);
M ss/main.c => ss/main.c +2 -2
@@ 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);