From 2251c00bc9d6d7aeb1b29d0bd929fbf925a26011 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Wed, 10 Dec 1997 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 1997-12-10 --- carrera/dat.h | 14 +- carrera/devether.c | 1051 +++++++++++++----------------------------- carrera/etherif.h | 48 ++ carrera/ethersonic.c | 727 +++++++++++++++++++++++++++++ carrera/fns.h | 1 + carrera/io.h | 8 +- carrera/main.c | 28 +- port/chan.c | 79 ++-- 8 files changed, 1187 insertions(+), 769 deletions(-) create mode 100644 carrera/etherif.h create mode 100644 carrera/ethersonic.c diff --git a/carrera/dat.h b/carrera/dat.h index 706c4b3d6582ab2262261f1a6a8dc1688800922d..87a62071936d18b13af46e0f9b8f390c47a661ff 100644 --- a/carrera/dat.h +++ b/carrera/dat.h @@ -153,11 +153,23 @@ struct short exiting; }active; +/* + * a parsed plan9.ini line + */ +#define ISAOPTLEN 16 +#define NISAOPT 8 + struct ISAConf { char type[NAMELEN]; ulong port; ulong irq; - int dma; + ulong dma; + ulong mem; + ulong size; + ulong freq; + + int nopt; + char opt[NISAOPT][ISAOPTLEN]; }; extern KMap kpte[]; diff --git a/carrera/devether.c b/carrera/devether.c index 79e23907f0da879eb7a6f5e0000273e634e1782c..7eb844acb577cb186641f56553754da52e8e1985 100644 --- a/carrera/devether.c +++ b/carrera/devether.c @@ -1,819 +1,372 @@ -#include "u.h" -#include "../port/lib.h" -#include "mem.h" -#include "dat.h" -#include "fns.h" -#include "io.h" -#include "../port/error.h" -#include "../port/netif.h" - -/* - * National Semiconductor DP83932 - * Systems-Oriented Network Interface Controller - * (SONIC) - */ - -#define SONICADDR ((Sonic*)Sonicbase) - -#define RD(rn) (delay(0), *(ulong*)((ulong)&SONICADDR->rn^4)) -#define WR(rn, v) (delay(0), *(ulong*)((ulong)&SONICADDR->rn^4) = (v)) -#define ISquad(s) if((ulong)s & 0x7) panic("sonic: Quad alignment"); - -typedef struct Pbuf Pbuf; -struct Pbuf +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "ureg.h" +#include "../port/error.h" +#include "../port/netif.h" + +#include "etherif.h" + +static Ether *etherxx[MaxEther]; + +Chan* +etherattach(char* spec) { - uchar d[6]; - uchar s[6]; - uchar type[2]; - uchar data[1500]; - uchar crc[4]; -}; + ulong ctlrno; + char *p; + Chan *chan; -typedef struct -{ - ulong cr; /* command */ - ulong dcr; /* data configuration */ - ulong rcr; /* receive control */ - ulong tcr; /* transmit control */ - ulong imr; /* interrupt mask */ - ulong isr; /* interrupt status */ - ulong utda; /* upper transmit descriptor address */ - ulong ctda; /* current transmit descriptor address */ - ulong pad0x08[5]; /* */ - ulong urda; /* upper receive descriptor address */ - ulong crda; /* current receive descriptor address */ - ulong crba0; /* DO NOT WRITE THESE */ - ulong crba1; - ulong rbwc0; - ulong rbwc1; - ulong eobc; /* end of buffer word count */ - ulong urra; /* upper receive resource address */ - ulong rsa; /* resource start address */ - ulong rea; /* resource end address */ - ulong rrp; /* resource read pointer */ - ulong rwp; /* resource write pointer */ - ulong pad0x19[8]; /* */ - ulong cep; /* CAM entry pointer */ - ulong cap2; /* CAM address port 2 */ - ulong cap1; /* CAM address port 1 */ - ulong cap0; /* CAM address port 0 */ - ulong ce; /* CAM enable */ - ulong cdp; /* CAM descriptor pointer */ - ulong cdc; /* CAM descriptor count */ - ulong sr; /* silicon revision */ - ulong wt0; /* watchdog timer 0 */ - ulong wt1; /* watchdog timer 1 */ - ulong rsc; /* receive sequence counter */ - ulong crct; /* CRC error tally */ - ulong faet; /* FAE tally */ - ulong mpt; /* missed packet tally */ - ulong mdt; /* maximum deferral timer */ - ulong pad0x30[15]; /* */ - ulong dcr2; /* data configuration 2 */ -} Sonic; - -enum -{ - Nrb = 16, /* receive buffers */ - Ntb = 8, /* transmit buffers */ -}; + ctlrno = 0; + if(spec && *spec){ + ctlrno = strtoul(spec, &p, 0); + if((ctlrno == 0 && p == spec) || *p || (ctlrno >= MaxEther)) + error(Ebadarg); + } + if(etherxx[ctlrno] == 0) + error(Enodev); + + chan = devattach('l', spec); + chan->dev = ctlrno; + if(etherxx[ctlrno]->dev && etherxx[ctlrno]->dev->attach) + etherxx[ctlrno]->dev->attach(etherxx[ctlrno]); + return chan; +} -enum +static int +etherwalk(Chan* chan, char* name) { - Htx = 0x0001, /* halt transmission */ - Txp = 0x0002, /* transmit packet(s) */ - Rxdis = 0x0004, /* receiver disable */ - Rxen = 0x0008, /* receiver enable */ - Stp = 0x0010, /* stop timer */ - St = 0x0020, /* start timer */ - Rst = 0x0080, /* software reset */ - Rrra = 0x0100, /* read RRA */ - Lcam = 0x0200, /* load CAM */ - - Dw32 = 0x0020, /* data width select */ - Sterm = 0x0400, /* synchronous termination */ - Lbr = 0x4000, /* latched bus retry */ - Efm = 0x0010, /* Empty fill mode */ - W14tf = 0x0003, /* 14 Word transmit fifo */ - - Prx = 0x0001, /* packet received ok */ - Fae = 0x0004, /* frame alignment error */ - Crc = 0x0008, /* CRC error */ - Lpkt = 0x0040, /* last packet in rba */ - Bc = 0x0080, /* broadcast packet received */ - Pro = 0x1000, /* physical promiscuous mode */ - Brd = 0x2000, /* accept broadcast packets */ - Rnt = 0x4000, /* accept runt packets */ - Err = 0x8000, /* accept packets with errors */ - - Ptx = 0x0001, /* packet transmitted ok */ - Pintr = 0x8000, /* programmable interrupt */ - - Rfo = 0x0001, /* receive fifo overrun */ - MpTally = 0x0002, /* missed packet tally counter rollover */ - FaeTally= 0x0004, /* frame alignment error tally counter rollover */ - CrcTally= 0x0008, /* Crc tally counter rollover */ - Rbae = 0x0010, /* receive buffer area exceeded */ - Rbe = 0x0020, /* receive buffer exhausted */ - Rde = 0x0040, /* receive descriptors exhausted */ - Txer = 0x0100, /* transmit error */ - Txdn = 0x0200, /* transmission done */ - Pktrx = 0x0400, /* packet received */ - Pint = 0x0800, /* programmed interrupt */ - Lcd = 0x1000, /* load CAM done */ - Hbl = 0x2000, /* CD heartbeat lost */ - Br = 0x4000, /* bus retry occurred */ - AllIntr = 0x7771, /* all of the above */ - - Rxbuf = sizeof(Pbuf)+4, - Txbuf = sizeof(Pbuf), -}; + return netifwalk(etherxx[chan->dev], chan, name); +} -/* - * Receive Resource Descriptor. - */ -typedef struct -{ - ushort pad1; - ushort ptr1; /* buffer pointer in the RRA */ - ushort pad2; - ushort ptr0; - ushort pad3; - ushort wc1; /* buffer word count in the RRA */ - ushort pad4; - ushort wc0; -} RXrsc; - -/* - * Receive Packet Descriptor. - */ -typedef struct -{ - ushort pad0; - ushort count; /* packet byte count */ - ushort pad1; - ushort status; /* receive status */ - ushort pad2; - ushort ptr1; /* buffer pointer */ - ushort pad3; - ushort ptr0; - ushort pad4; - ushort link; /* descriptor link and EOL */ - ushort pad5; - ushort seqno; /* */ - ulong pad6; - ushort pad7; - ushort owner; /* in use */ -} RXpkt; - -/* - * Transmit Packet Descriptor. - */ -typedef struct +static void +etherstat(Chan* chan, char* dp) { - ushort pad1; - ushort config; /* */ - ushort pad0; - ushort status; /* transmit status */ - ushort pad3; - ushort count; /* fragment count */ - ushort pad2; - ushort size; /* byte count of entire packet */ - ushort pad5; - ushort ptr1; - ushort pad4; - ushort ptr0; /* packet pointer */ - ushort pad7; - ushort link; /* descriptor link */ - ushort pad6; - ushort fsize; /* fragment size */ -} TXpkt; - -enum{ - Eol = 1, /* end of list bit in descriptor link */ - Host = 0, /* descriptor belongs to host */ - Interface = -1, /* descriptor belongs to interface */ - - Nether = 1, - Ntypes = 8, -}; + netifstat(etherxx[chan->dev], chan, dp); +} -/* - * CAM Descriptor - */ -typedef struct -{ - ushort pad0; - ushort cap0; /* CAM address port 0 */ - ushort pad1; - ushort cep; /* CAM entry pointer */ - ushort pad2; - ushort cap2; /* CAM address port 2 */ - ushort pad3; - ushort cap1; /* CAM address port 1 */ - ulong pad4; - ushort pad5; - ushort ce; /* CAM enable */ -} Cam; - -typedef struct Ether Ether; -struct Ether +static Chan* +etheropen(Chan* chan, int omode) { - uchar ea[6]; - uchar ba[6]; - - QLock tlock; /* lock for grabbing transmitter queue */ - Rendez tr; /* wait here for free xmit buffer */ - int th; /* first transmit buffer owned by host */ - int ti; /* first transmit buffer owned by interface */ - - int rh; /* first receive buffer owned by host */ - int ri; /* first receive buffer owned by interface */ - - RXrsc *rra; /* receive resource area */ - RXpkt *rda; /* receive descriptor area */ - TXpkt *tda; /* transmit descriptor area */ - Cam *cda; /* CAM descriptor area */ - - uchar *rb[Nrb]; /* receive buffer area */ - uchar *tb[Ntb]; /* transmit buffer area */ - - Netif; -}; - -static Ether *ether[Nether]; - -#define NEXT(x, l) (((x)+1)%(l)) -#define PREV(x, l) (((x) == 0) ? (l)-1: (x)-1) -#define LS16(addr) (PADDR(addr) & 0xFFFF) -#define MS16(addr) ((PADDR(addr)>>16) & 0xFFFF) - -static void sonicswap(void*, int); + return netifopen(etherxx[chan->dev], chan, omode); +} static void -wus(ushort *a, ushort v) +ethercreate(Chan*, char*, int, ulong) { - a[0] = v; - a[-1] = v; } static void -reset(Ether *ctlr) +etherclose(Chan* chan) { - int i; - ushort lolen, hilen, loadr, hiadr; - - /* - * Reset the SONIC, toggle the Rst bit. - * Set the data config register for synchronous termination - * and 32-bit data-path width. - * Setup the descriptor and buffer area. - */ - WR(cr, Rst); - WR(dcr, 0x2423); /* 5-19 Carrera manual */ - WR(cr, 0); - - /* - * Initialise the receive resource area (RRA) and - * the receive descriptor area (RDA). - * - * We use a simple scheme of one packet per descriptor. - * We achieve this by setting the EOBC register to be - * 2 (16-bit words) less than the buffer size; - * thus the size of the receive buffers must be sizeof(Pbuf)+4. - * Set up the receive descriptors as a ring. - */ - - lolen = (Rxbuf/2) & 0xFFFF; - hilen = ((Rxbuf/2)>>16) & 0xFFFF; - - for(i = 0; i < Nrb; i++) { - wus(&ctlr->rra[i].wc0, lolen); - wus(&ctlr->rra[i].wc1, hilen); - - ctlr->rda[i].link = LS16(&ctlr->rda[NEXT(i, Nrb)]); - ctlr->rda[i].owner = Interface; - - loadr = LS16(ctlr->rb[i]); - wus(&ctlr->rra[i].ptr0, loadr); - wus(&ctlr->rda[i].ptr0, loadr); - - hiadr = MS16(ctlr->rb[i]); - wus(&ctlr->rra[i].ptr1, hiadr); - wus(&ctlr->rda[i].ptr1, hiadr); - } - - /* - * Check the important resources are QUAD aligned - */ - ISquad(ctlr->rra); - ISquad(ctlr->rda); - - /* - * Terminate the receive descriptor ring - * and load the SONIC registers to describe the RDA. - */ - ctlr->rda[Nrb-1].link |= Eol; - - WR(crda, LS16(ctlr->rda)); - WR(urda, MS16(ctlr->rda)); - WR(eobc, Rxbuf/2 - 2); + netifclose(etherxx[chan->dev], chan); +} - /* - * Load the SONIC registers to describe the RRA. - * We set the rwp to beyond the area delimited by rsa and - * rea. This means that since we've already allocated all - * the buffers, we'll never get a 'receive buffer area - * exhausted' interrupt and the rrp will just wrap round. - */ - WR(urra, MS16(&ctlr->rra[0])); - WR(rsa, LS16(&ctlr->rra[0])); - WR(rrp, LS16(&ctlr->rra[0])); - WR(rea, LS16(&ctlr->rra[Nrb])); - WR(rwp, LS16(&ctlr->rra[Nrb+1])); +static long +etherread(Chan* chan, void* buf, long n, ulong offset) +{ + Ether *ether; - /* - * Initialise the transmit descriptor area (TDA). - * Each descriptor describes one packet, we make no use - * of having the packet in multiple fragments. - * The descriptors are linked in a ring; overlapping transmission - * with buffer queueing will cause some packets to - * go out back-to-back. - * - * Load the SONIC registers to describe the TDA. - */ - for(i = 0; i < Ntb; i++){ - ctlr->tda[i].status = Host; - ctlr->tda[i].config = 0; - ctlr->tda[i].count = 1; - ctlr->tda[i].ptr0 = LS16(ctlr->tb[i]); - ctlr->tda[i].ptr1 = MS16(ctlr->tb[i]); - ctlr->tda[i].link = LS16(&ctlr->tda[NEXT(i, Ntb)]); + ether = etherxx[chan->dev]; + if((chan->qid.path & CHDIR) == 0 && ether->dev && ether->dev->ifstat){ + /* + * With some controllers it is necessary to reach + * into the chip to extract statistics. + */ + if(NETTYPE(chan->qid.path) == Nifstatqid) + return ether->dev->ifstat(ether, buf, n, offset); + else if(NETTYPE(chan->qid.path) == Nstatqid) + ether->dev->ifstat(ether, buf, 0, offset); } - WR(ctda, LS16(&ctlr->tda[0])); - WR(utda, MS16(&ctlr->tda[0])); - - /* - * Initialise the software receive and transmit - * ring indexes. - */ - ctlr->rh = 0; - ctlr->ri = 0; - ctlr->th = 0; - ctlr->ti = 0; - - /* - * Initialise the CAM descriptor area (CDA). - * We only have one ethernet address to load, - * broadcast is defined by the SONIC as all 1s. - * - * Load the SONIC registers to describe the CDA. - */ - ctlr->cda->cep = 0; - ctlr->cda->cap0 = (ctlr->ea[1]<<8)|ctlr->ea[0]; - ctlr->cda->cap1 = (ctlr->ea[3]<<8)|ctlr->ea[2]; - ctlr->cda->cap2 = (ctlr->ea[5]<<8)|ctlr->ea[4]; - ctlr->cda->ce = 1; - - WR(cdp, LS16(ctlr->cda)); - WR(cdc, 1); - - /* - * Load the Resource Descriptors and Cam contents - */ - WR(cr, Rrra); - while(RD(cr) & Rrra) - ; - - WR(cr, Lcam); - while(RD(cr) & Lcam) - ; - - /* - * Configure the receive control, transmit control - * and interrupt-mask registers. - * The SONIC is now initialised, but not enabled. - */ - WR(rcr, Brd); - WR(tcr, 0); - WR(imr, AllIntr); + return netifread(ether, chan, buf, n, offset); } -static void -sonicpkt(Ether *ctlr, RXpkt *r, Pbuf *p) +static Block* +etherbread(Chan* chan, long n, ulong offset) { - int len; - ushort type; - Netfile *f, **fp, **ep; - - /* - * Sonic delivers CRC as part of the packet count - */ - len = (r->count & 0xFFFF)-4; - - sonicswap(p, len); - - type = (p->type[0]<<8) | p->type[1]; - ep = &ctlr->f[Ntypes]; - for(fp = ctlr->f; fp < ep; fp++) { - f = *fp; - if(f && (f->type == type || f->type < 0)) - qproduce(f->in, p->d, len); - } + return netifbread(etherxx[chan->dev], chan, n, offset); } -static int -isoutbuf(void *arg) +static void +etherremove(Chan*) { - Ether *ctlr = arg; - - return ctlr->tda[ctlr->th].status == Host; } -void -etherintr(void) +static void +etherwstat(Chan* chan, char* dp) { - Ether *c; - ushort *s; - ulong status; - TXpkt *txpkt; - RXpkt *rxpkt; - - c = ether[0]; - - for(;;) { - status = RD(isr) & AllIntr; - if(status == 0) - break; - - /* - * Warnings that something is atoe. - */ - if(status & Hbl){ - WR(isr, Hbl); - status &= ~Hbl; - print("sonic: cd heartbeat lost\n"); - } - if(status & Br){ -WR(cr, Rst); - print("sonic: bus retry occurred\n"); -(*(void(*)(void))0xA001C020)(); - status &= ~Br; - } - - /* - * Transmission complete, for good or bad. - */ - if(status & (Txdn|Txer)) { - txpkt = &c->tda[c->ti]; - while(txpkt->status != Host){ - if(txpkt->status == Interface){ - WR(ctda, LS16(txpkt)); - WR(cr, Txp); - break; - } - - if((txpkt->status & Ptx) == 0) - c->oerrs++; - - txpkt->status = Host; - c->ti = NEXT(c->ti, Ntb); - txpkt = &c->tda[c->ti]; - } - WR(isr, status & (Txdn|Txer)); - status &= ~(Txdn|Txer); - if(isoutbuf(c)) - wakeup(&c->tr); - } - - if((status & (Pktrx|Rde)) == 0) - goto noinput; - - /* - * A packet arrived or we ran out of descriptors. - */ - rxpkt = &c->rda[c->rh]; - while(rxpkt->owner == Host){ - c->inpackets++; - - /* - * If the packet was received OK, pass it up, - * otherwise log the error. - */ - if(rxpkt->status & Prx) - sonicpkt(c, rxpkt, (Pbuf*)c->rb[c->rh]); - else - if(rxpkt->status & Fae) - c->frames++; - else - if(rxpkt->status & Crc) - c->crcs++; - else - c->buffs++; - - rxpkt->status = 0; - /* - * Finished with this packet, it becomes the - * last free packet in the ring, so give it Eol, - * and take the Eol bit off the previous packet. - * Move the ring index on. - */ - wus(&rxpkt->link, rxpkt->link|Eol); - rxpkt->owner = Interface; - s = &c->rda[PREV(c->rh, Nrb)].link; - wus(s, *s & ~Eol); - c->rh = NEXT(c->rh, Nrb); - - rxpkt = &c->rda[c->rh]; - } - WR(isr, status & (Pktrx|Rde)); - status &= ~(Pktrx|Rde); - - noinput: - /* - * We get a 'load CAM done' interrupt - * after initialisation. Ignore it. - */ - if(status & Lcd) { - WR(isr, Lcd); - status &= ~Lcd; - } - - if(status & AllIntr) { - WR(isr, status); - print("sonic #%lux\n", status); - } - } + netifwstat(etherxx[chan->dev], chan, dp); } -/* - * turn promiscuous mode on/off - */ static void -promiscuous(void *arg, int on) +etherrtrace(Netfile* f, Etherpkt* pkt, int len) { - ushort reg; - - USED(arg); + int i, n; + Block *bp; - reg = RD(rcr); - if(on) - WR(rcr, reg|Pro); + if(qwindow(f->in) <= 0) + return; + if(len > 64) + n = 64; else - WR(rcr, reg&~Pro); + n = len; + bp = iallocb(n); + if(bp == 0) + return; + memmove(bp->wp, pkt->d, n); + i = TK2MS(MACHP(0)->ticks); + bp->wp[58] = len>>8; + bp->wp[59] = len; + bp->wp[60] = i>>24; + bp->wp[61] = i>>16; + bp->wp[62] = i>>8; + bp->wp[63] = i; + bp->wp += 64; + qpass(f->in, bp); } -static void -initbufs(Ether *c) +Block* +etheriq(Ether* ether, Block* bp, int freebp) { - int i; - uchar *mem, *base; - - /* Put the ethernet buffers in the same place - * as the bootrom - */ - mem = (void*)(KZERO|0x2000); - base = mem; - mem = CACHELINE(uchar, mem); + Etherpkt *pkt; + ushort type; + int len; + Netfile **ep, *f, **fp, *fx; + Block *xbp; + + ether->inpackets++; + + pkt = (Etherpkt*)bp->rp; + len = BLEN(bp); + type = (pkt->type[0]<<8)|pkt->type[1]; + fx = 0; + ep = ðer->f[Ntypes]; + + /* check for valid multcast addresses */ + if((pkt->d[0] & 1) && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) && ether->prom == 0){ + if(!activemulti(ether, pkt->d, sizeof(pkt->d))){ + if(freebp){ + freeb(bp); + bp = 0; + } + return bp; + } + } /* - * Descriptors must be built in uncached space + * Multiplex the packet to all the connections which want it. + * If the packet is not to be used subsequently (freebp != 0), + * attempt to simply pass it into one of the connections, thereby + * saving a copy of the data (usual case hopefully). */ - c->rra = UNCACHED(RXrsc, mem); - mem = QUAD(uchar, mem+Nrb*sizeof(RXrsc)); - - c->rda = UNCACHED(RXpkt, mem); - mem = QUAD(uchar, mem+Nrb*sizeof(RXpkt)); - - c->tda = UNCACHED(TXpkt, mem); - mem = QUAD(uchar, mem+Ntb*sizeof(TXpkt)); - - c->cda = UNCACHED(Cam, mem); + for(fp = ether->f; fp < ep; fp++){ + if((f = *fp) && (f->type == type || f->type < 0)){ + if(f->type > -2){ + if(freebp && fx == 0) + fx = f; + else if(xbp = iallocb(len)){ + memmove(xbp->wp, pkt, len); + xbp->wp += len; + qpass(f->in, xbp); + } + else + ether->soverflows++; + } + else + etherrtrace(f, pkt, len); + } + } - mem = CACHELINE(uchar, mem+sizeof(Cam)); - for(i = 0; i < Nrb; i++) { - c->rb[i] = UNCACHED(uchar, mem); - mem += sizeof(Pbuf)+4; - mem = QUAD(uchar, mem); + if(fx){ + qpass(fx->in, bp); + return 0; } - for(i = 0; i < Ntb; i++) { - c->tb[i] = UNCACHED(uchar, mem); - mem += sizeof(Pbuf); - mem = QUAD(uchar, mem); + if(freebp){ + freeb(bp); + return 0; } - if(mem >= base+64*1024) - panic("sonic init"); + + return bp; } -static void -etherreset(void) +static int +etheroq(Ether* ether, Block* bp) { - Ether *ctlr; + int len, loopback, s; + Etherpkt *pkt; + + ether->outpackets++; /* - * Map the device registers and allocate - * memory for the receive/transmit rings. - * Set the physical ethernet address and - * prime the interrupt handler. + * Check if the packet has to be placed back onto the input queue, + * i.e. if it's a loopback or broadcast packet or the interface is + * in promiscuous mode. + * If it's a loopback packet indicate to etheriq that the data isn't + * needed and return, etheriq will pass-on or free the block. */ - if(ether[0] == 0) { - ctlr = malloc(sizeof(Ether)); - ether[0] = ctlr; - initbufs(ctlr); - enetaddr(ether[0]->ea); + pkt = (Etherpkt*)bp->rp; + len = BLEN(bp); + loopback = (memcmp(pkt->d, ether->addr, sizeof(pkt->d)) == 0); + if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom){ + s = splhi(); + etheriq(ether, bp, loopback); + splx(s); } - ctlr = ether[0]; - - reset(ctlr); - - memset(ctlr->ba, 0xFF, sizeof(ctlr->ba)); - - /* general network interface structure */ - netifinit(ether[0], "ether0", Ntypes, 32*1024); - ether[0]->alen = 6; - memmove(ether[0]->addr, ether[0]->ea, 6); - memmove(ether[0]->bcast, ctlr->ba, 6); - ether[0]->promiscuous = promiscuous; - ether[0]->arg = ether[0]; -} -static Chan* -etherattach(char *spec) -{ - static int enable; - - if(enable == 0) { - enable = 1; - WR(cr, Rxen); + if(!loopback){ + if(ether->dev && ether->dev->transmit){ + qbwrite(ether->oq, bp); + ether->dev->transmit(ether); + } + else{ + freeb(bp); + return 0; + } } - if(*spec && strcmp(spec, "0") != 0) - error(Eio); - return devattach('l', spec); -} -static int -etherwalk(Chan *c, char *name) -{ - return netifwalk(ether[0], c, name); -} - -static Chan* -etheropen(Chan *c, int omode) -{ - return netifopen(ether[0], c, omode); -} - -static void -ethercreate(Chan *c, char *name, int omode, ulong perm) -{ - USED(c, name, omode, perm); -} - -static void -etherclose(Chan *c) -{ - netifclose(ether[0], c); + return len; } -long -etherread(Chan *c, void *buf, long n, ulong offset) +static long +etherwrite(Chan* chan, void* buf, long n, ulong) { - return netifread(ether[0], c, buf, n, offset); -} + Ether *ether; + Block *bp; -static int -etherloop(Etherpkt *p, long n) -{ - int s, different; - ushort t; - Netfile *f, **fp; - Ether *ctlr = ether[0]; + ether = etherxx[chan->dev]; + if(NETTYPE(chan->qid.path) != Ndataqid) + return netifwrite(ether, chan, buf, n); - different = memcmp(p->d, ctlr->ea, sizeof(ctlr->ea)); - if(different && memcmp(p->d, ctlr->bcast, sizeof(p->d))) - return 0; + if(n > ETHERMAXTU) + error(Etoobig); + if(n < ETHERMINTU) + error(Etoosmall); - s = splhi(); - t = (p->type[0]<<8) | p->type[1]; - for(fp = ctlr->f; fp < &ctlr->f[Ntypes]; fp++) { - f = *fp; - if(f == 0) - continue; - if(f->type == t || f->type < 0) - switch(qproduce(f->in, p->d, n)){ - case -1: - print("etherloop overflow\n"); - break; - case -2: - print("etherloop memory\n"); - break; - } + bp = allocb(n); + if(waserror()){ + freeb(bp); + nexterror(); } - splx(s); - return !different; + memmove(bp->rp, buf, n); + memmove(bp->rp+Eaddrlen, ether->addr, Eaddrlen); + poperror(); + bp->wp += n; + + return etheroq(ether, bp); } static long -etherwrite(Chan *c, void *buf, long n, ulong offset) +etherbwrite(Chan* chan, Block* bp, ulong) { - Pbuf *p; - ushort *s; - TXpkt *txpkt; - Ether *ctlr = ether[0]; - - USED(offset); - - /* etherif.c handles structure */ - if(NETTYPE(c->qid.path) != Ndataqid) - return netifwrite(ether[0], c, buf, n); - - if(n > ETHERMAXTU) - error(Ebadarg); - - p = buf; - memmove(p->s, ctlr->ea, sizeof(ctlr->ea)); - - /* we handle data */ - if(etherloop(buf, n)) + Ether *ether; + long n; + + n = BLEN(bp); + ether = etherxx[chan->dev]; + if(NETTYPE(chan->qid.path) != Ndataqid){ + n = netifwrite(ether, chan, bp->rp, n); + freeb(bp); return n; - - qlock(&ctlr->tlock); - ctlr->outpackets++; - if(waserror()) { - qunlock(&ctlr->tlock); - nexterror(); } - tsleep(&ctlr->tr, isoutbuf, ctlr, 10000); - - if(!isoutbuf(ctlr)) - print("ether transmitter jammed cr #%lux\n", RD(cr)); - else { - p = (Pbuf*)ctlr->tb[ctlr->th]; - memmove(p->d, buf, n); - if(n < 60) { - memset(p->d+n, 0, 60-n); - n = 60; - } - sonicswap(p, n); - - txpkt = &ctlr->tda[ctlr->th]; - txpkt->size = n; - txpkt->fsize = n; - wus(&txpkt->link, txpkt->link|Eol); - txpkt->status = Interface; - s = &ctlr->tda[PREV(ctlr->th, Ntb)].link; - wus(s, *s & ~Eol); - - ctlr->th = NEXT(ctlr->th, Ntb); - WR(cr, Txp); + if(n > ETHERMAXTU){ + freeb(bp); + error(Ebadarg); + } + if(n < ETHERMINTU){ + freeb(bp); + error(Etoosmall); } - poperror(); - qunlock(&ctlr->tlock); - - return n; -} -static void -etherremove(Chan *c) -{ - USED(c); + return etheroq(ether, bp); } -static void -etherstat(Chan *c, char *dp) +void +etherreset(void) { - netifstat(ether[0], c, dp); -} + Ether *ether; + int i, n, ctlrno; + char name[NAMELEN], buf[128]; + + for(ether = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++){ + if(ether == 0) + ether = malloc(sizeof(Ether)); + memset(ether, 0, sizeof(Ether)); + ether->ctlrno = ctlrno; + ether->tbdf = BUSUNKNOWN; + ether->mbps = 10; + if(isaconfig("ether", ctlrno, ether) == 0) + continue; + for(n = 0; endev[n]; n++){ + if(cistrcmp(endev[n]->name, ether->type)) + continue; + ether->dev = endev[n]; + for(i = 0; i < ether->nopt; i++){ + if(strncmp(ether->opt[i], "ea=", 3)) + continue; + if(parseether(ether->addr, ðer->opt[i][3]) == -1) + memset(ether->addr, 0, Eaddrlen); + } + if(endev[n]->reset(ether)) + break; -static void -etherwstat(Chan *c, char *dp) -{ - netifwstat(ether[0], c, dp); -} + /* + * IRQ2 doesn't really exist, it's used to gang the interrupt + * controllers together. A device set to IRQ2 will appear on + * the second interrupt controller as IRQ9. + */ + if(ether->irq == 2) + ether->irq = 9; + intrenable(VectorPIC+ether->irq, ether->interrupt, ether, ether->tbdf); + + i = sprint(buf, "#l%d: %s: %dMbps port 0x%luX", + ctlrno, ether->type, ether->mbps, ether->port); + if(ether->irq) + i += sprint(buf+i, " irq %d", ether->irq); + if(ether->mem) + i += sprint(buf+i, " addr 0x%luX", PADDR(ether->mem)); + if(ether->size) + i += sprint(buf+i, " size 0x%luX", ether->size); + i += sprint(buf+i, ": %2.2uX%2.2uX%2.2uX%2.2uX%2.2uX%2.2uX", + ether->addr[0], ether->addr[1], ether->addr[2], + ether->addr[3], ether->addr[4], ether->addr[5]); + sprint(buf+i, "\n"); + print(buf); + + snprint(name, sizeof(name), "ether%d", ctlrno); + if(ether->mbps == 100){ + netifinit(ether, name, Ntypes, 256*1024); + if(ether->oq == 0) + ether->oq = qopen(256*1024, 1, 0, 0); + } + else{ + netifinit(ether, name, Ntypes, 32*1024); + if(ether->oq == 0) + ether->oq = qopen(64*1024, 1, 0, 0); + } + if(ether->oq == 0) + panic("etherreset %s", name); -#define swiz(s) (s<<24)|((s>>8)&0xff00)|((s<<8)&0xff0000)|(s>>24) + ether->alen = Eaddrlen; + memset(ether->bcast, 0xFF, Eaddrlen); + ether->arg = ether; + ether->promiscuous = ether->dev->promiscuous; + ether->multicast = ether->dev->multicast; -static void -sonicswap(void *a, int n) -{ - ulong *p, t0, t1; - - n = ((n+8)/8)*8; - p = a; - while(n) { - t0 = p[0]; - t1 = p[1]; - p[0] = swiz(t1); - p[1] = swiz(t0); - p += 2; - n -= 8; + etherxx[ctlrno] = ether; + ether = 0; + break; + } } + if(ether) + free(ether); } int -parseether(uchar *to, char *from) +parseether(uchar* to, char* from) { char nip[4]; char *p; @@ -835,6 +388,26 @@ parseether(uchar *to, char *from) return 0; } +#define POLY 0xedb88320 + +/* really slow 32 bit crc for ethers */ +ulong +ethercrc(uchar* p, int len) +{ + int i, j; + ulong crc, b; + + crc = 0xffffffff; + for(i = 0; i < len; i++){ + b = *p++; + for(j = 0; j < 8; j++){ + crc = (crc>>1) ^ (((crc^b) & 1) ? POLY : 0); + b >>= 1; + } + } + return crc; +} + Dev etherdevtab = { 'l', "ether", @@ -849,9 +422,9 @@ Dev etherdevtab = { ethercreate, etherclose, etherread, - devbread, + etherbread, etherwrite, - devbwrite, + etherbwrite, etherremove, etherwstat, }; diff --git a/carrera/etherif.h b/carrera/etherif.h new file mode 100644 index 0000000000000000000000000000000000000000..447e587a2869dc4fd7e09a4b73fe7c9e2499d1ea --- /dev/null +++ b/carrera/etherif.h @@ -0,0 +1,48 @@ +enum { + MaxEther = 1, + Ntypes = 8, +}; + +typedef struct Ether Ether; +typedef struct Endev Endev; + +struct Ether { + ISAConf; /* hardware info */ + int ctlrno; + int tbdf; /* type+busno+devno+funcno */ + int mbps; /* Mbps */ + + Netif; + + Endev* dev; + void *ctlr; + Queue* oq; +}; + +struct Endev { + char* name; + + int (*reset)(Ether*); + void (*attach)(Ether*); + void (*transmit)(Ether*); + void (*interrupt)(Ureg*, void*); + long (*ifstat)(Ether*, void*, long, ulong); + void (*promiscuous)(void*, int); + void (*multicast)(void*, uchar*, int); + + int vid; + int did; +}; + +/* + * devether.c + */ +extern Block* etheriq(Ether*, Block*, int); +extern ulong ethercrc(uchar*, int); + +extern Endev* endev[]; + +#define NEXT(x, l) (((x)+1)%(l)) +#define PREV(x, l) (((x) == 0) ? (l)-1: (x)-1) +#define HOWMANY(x, y) (((x)+((y)-1))/(y)) +#define ROUNDUP(x, y) (HOWMANY((x), (y))*(y)) diff --git a/carrera/ethersonic.c b/carrera/ethersonic.c new file mode 100644 index 0000000000000000000000000000000000000000..7988d798d8f41ebd9e40ba8562bbc9d832f20a6b --- /dev/null +++ b/carrera/ethersonic.c @@ -0,0 +1,727 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "../port/error.h" +#include "../port/netif.h" + +#include "etherif.h" + +/* + * National Semiconductor DP83932 + * Systems-Oriented Network Interface Controller + * (SONIC) + */ + +#define SONICADDR ((Sonic*)Sonicbase) + +#define RD(rn) (delay(0), *(ulong*)((ulong)&SONICADDR->rn^4)) +#define WR(rn, v) (delay(0), *(ulong*)((ulong)&SONICADDR->rn^4) = (v)) +#define ISquad(s) if((ulong)s & 0x7) panic("sonic: Quad alignment"); + +typedef struct Pbuf Pbuf; +struct Pbuf +{ + uchar d[6]; + uchar s[6]; + uchar type[2]; + uchar data[1500]; + uchar crc[4]; +}; + +typedef struct +{ + ulong cr; /* command */ + ulong dcr; /* data configuration */ + ulong rcr; /* receive control */ + ulong tcr; /* transmit control */ + ulong imr; /* interrupt mask */ + ulong isr; /* interrupt status */ + ulong utda; /* upper transmit descriptor address */ + ulong ctda; /* current transmit descriptor address */ + ulong pad0x08[5]; /* */ + ulong urda; /* upper receive descriptor address */ + ulong crda; /* current receive descriptor address */ + ulong crba0; /* DO NOT WRITE THESE */ + ulong crba1; + ulong rbwc0; + ulong rbwc1; + ulong eobc; /* end of buffer word count */ + ulong urra; /* upper receive resource address */ + ulong rsa; /* resource start address */ + ulong rea; /* resource end address */ + ulong rrp; /* resource read pointer */ + ulong rwp; /* resource write pointer */ + ulong pad0x19[8]; /* */ + ulong cep; /* CAM entry pointer */ + ulong cap2; /* CAM address port 2 */ + ulong cap1; /* CAM address port 1 */ + ulong cap0; /* CAM address port 0 */ + ulong ce; /* CAM enable */ + ulong cdp; /* CAM descriptor pointer */ + ulong cdc; /* CAM descriptor count */ + ulong sr; /* silicon revision */ + ulong wt0; /* watchdog timer 0 */ + ulong wt1; /* watchdog timer 1 */ + ulong rsc; /* receive sequence counter */ + ulong crct; /* CRC error tally */ + ulong faet; /* FAE tally */ + ulong mpt; /* missed packet tally */ + ulong mdt; /* maximum deferral timer */ + ulong pad0x30[15]; /* */ + ulong dcr2; /* data configuration 2 */ +} Sonic; + +enum +{ + Nrb = 16, /* receive buffers */ + Ntb = 8, /* transmit buffers */ +}; + +enum +{ + Htx = 0x0001, /* halt transmission */ + Txp = 0x0002, /* transmit packet(s) */ + Rxdis = 0x0004, /* receiver disable */ + Rxen = 0x0008, /* receiver enable */ + Stp = 0x0010, /* stop timer */ + St = 0x0020, /* start timer */ + Rst = 0x0080, /* software reset */ + Rrra = 0x0100, /* read RRA */ + Lcam = 0x0200, /* load CAM */ + + Dw32 = 0x0020, /* data width select */ + Sterm = 0x0400, /* synchronous termination */ + Lbr = 0x4000, /* latched bus retry */ + Efm = 0x0010, /* Empty fill mode */ + W14tf = 0x0003, /* 14 Word transmit fifo */ + + Prx = 0x0001, /* packet received ok */ + Fae = 0x0004, /* frame alignment error */ + Crc = 0x0008, /* CRC error */ + Lpkt = 0x0040, /* last packet in rba */ + Bc = 0x0080, /* broadcast packet received */ + Pro = 0x1000, /* physical promiscuous mode */ + Brd = 0x2000, /* accept broadcast packets */ + Rnt = 0x4000, /* accept runt packets */ + Err = 0x8000, /* accept packets with errors */ + + Ptx = 0x0001, /* packet transmitted ok */ + Pintr = 0x8000, /* programmable interrupt */ + + Rfo = 0x0001, /* receive fifo overrun */ + MpTally = 0x0002, /* missed packet tally counter rollover */ + FaeTally= 0x0004, /* frame alignment error tally counter rollover */ + CrcTally= 0x0008, /* Crc tally counter rollover */ + Rbae = 0x0010, /* receive buffer area exceeded */ + Rbe = 0x0020, /* receive buffer exhausted */ + Rde = 0x0040, /* receive descriptors exhausted */ + Txer = 0x0100, /* transmit error */ + Txdn = 0x0200, /* transmission done */ + Pktrx = 0x0400, /* packet received */ + Pint = 0x0800, /* programmed interrupt */ + Lcd = 0x1000, /* load CAM done */ + Hbl = 0x2000, /* CD heartbeat lost */ + Br = 0x4000, /* bus retry occurred */ + AllIntr = 0x7771, /* all of the above */ + + Rxbuf = sizeof(Pbuf)+4, + Txbuf = sizeof(Pbuf), +}; + +/* + * Receive Resource Descriptor. + */ +typedef struct +{ + ushort pad1; + ushort ptr1; /* buffer pointer in the RRA */ + ushort pad2; + ushort ptr0; + ushort pad3; + ushort wc1; /* buffer word count in the RRA */ + ushort pad4; + ushort wc0; +} RXrsc; + +/* + * Receive Packet Descriptor. + */ +typedef struct +{ + ushort pad0; + ushort count; /* packet byte count */ + ushort pad1; + ushort status; /* receive status */ + ushort pad2; + ushort ptr1; /* buffer pointer */ + ushort pad3; + ushort ptr0; + ushort pad4; + ushort link; /* descriptor link and EOL */ + ushort pad5; + ushort seqno; /* */ + ulong pad6; + ushort pad7; + ushort owner; /* in use */ +} RXpkt; + +/* + * Transmit Packet Descriptor. + */ +typedef struct +{ + ushort pad1; + ushort config; /* */ + ushort pad0; + ushort status; /* transmit status */ + ushort pad3; + ushort count; /* fragment count */ + ushort pad2; + ushort size; /* byte count of entire packet */ + ushort pad5; + ushort ptr1; + ushort pad4; + ushort ptr0; /* packet pointer */ + ushort pad7; + ushort link; /* descriptor link */ + ushort pad6; + ushort fsize; /* fragment size */ +} TXpkt; + +enum{ + Eol = 1, /* end of list bit in descriptor link */ + Host = 0, /* descriptor belongs to host */ + Interface = -1, /* descriptor belongs to interface */ +}; + +/* + * CAM Descriptor + */ +typedef struct +{ + ushort pad0; + ushort cap0; /* CAM address port 0 */ + ushort pad1; + ushort cep; /* CAM entry pointer */ + ushort pad2; + ushort cap2; /* CAM address port 2 */ + ushort pad3; + ushort cap1; /* CAM address port 1 */ + ulong pad4; + ushort pad5; + ushort ce; /* CAM enable */ +} Cam; + +typedef struct Ctlr { + Lock lock; + + Lock tlock; + int th; /* first transmit buffer owned by host */ + int ti; /* first transmit buffer owned by interface */ + int ntq; + + int rh; /* first receive buffer owned by host */ + int ri; /* first receive buffer owned by interface */ + + RXrsc* rra; /* receive resource area */ + RXpkt* rda; /* receive descriptor area */ + TXpkt* tda; /* transmit descriptor area */ + Cam* cda; /* CAM descriptor area */ + + ulong* rb[Nrb]; /* receive buffer area */ + ulong* tb[Ntb]; /* transmit buffer area */ +} Ctlr; + +static Ether* etherxx; + +#define LS16(addr) (PADDR(addr) & 0xFFFF) +#define MS16(addr) ((PADDR(addr)>>16) & 0xFFFF) + +static void +attach(Ether* ether) +{ + Ctlr *ctlr; + + ctlr = ether->ctlr; + + ilock(&ctlr->lock); + if(!(RD(cr) & Rxen)) + WR(cr, Rxen); + iunlock(&ctlr->lock); +} + +static void +promiscuous(void* arg, int on) +{ + Ctlr *ctlr; + ushort rcr; + + ctlr = ((Ether*)arg)->ctlr; + + ilock(&ctlr->lock); + rcr = RD(rcr); + if(on) + rcr |= Pro; + else + rcr &= ~Pro; + WR(rcr, rcr); + iunlock(&ctlr->lock); +} + +static void +wus(ushort* a, ushort v) +{ + a[0] = v; + a[-1] = v; +} + +static void +swizzle(uchar* to, ulong *from, int nbytes) +{ + ulong *l, l0, l1; + uchar *p; + + p = to; + l = from; + for(nbytes = ROUNDUP(nbytes, 8); nbytes; nbytes -= 8){ + l1 = *l++; + l0 = *l++; + p[0] = l0; + p[1] = l0>>8; + p[2] = l0>>16; + p[3] = l0>>24; + p[4] = l1; + p[5] = l1>>8; + p[6] = l1>>16; + p[7] = l1>>24; + p += 8; + } +} + +static void +swozzle(ulong* to, uchar *from, int nbytes) +{ + ulong *l; + uchar *p; + + l = to; + p = from; + for(nbytes = ROUNDUP(nbytes, 8); nbytes; nbytes -= 8){ + *l++ = (p[7]<<24)|(p[6]<<16)|(p[5]<<8)|p[4]; + *l++ = (p[3]<<24)|(p[2]<<16)|(p[1]<<8)|p[0]; + p += 8; + } +} + +static void +txstart(Ether* ether) +{ + Ctlr *ctlr; + Block *bp; + ushort *s; + TXpkt *txpkt; + int len; + + ctlr = ether->ctlr; + txpkt = &ctlr->tda[ctlr->th]; + while(txpkt->status == Host){ + bp = qget(ether->oq); + if(bp == nil) + break; + + len = BLEN(bp); + swozzle(ctlr->tb[ctlr->th], bp->rp, len); + + txpkt->size = len; + txpkt->fsize = len; + wus(&txpkt->link, txpkt->link|Eol); + txpkt->status = Interface; + s = &ctlr->tda[PREV(ctlr->th, Ntb)].link; + wus(s, *s & ~Eol); + + ctlr->th = NEXT(ctlr->th, Ntb); + txpkt = &ctlr->tda[ctlr->th]; + WR(cr, Txp); + + freeb(bp); + } +} + +void +etherintr(void) +{ + Ether *ether; + Ctlr *ctlr; + ushort *s; + ulong status; + TXpkt *txpkt; + RXpkt *rxpkt; + int len; + Block *bp; + + ether = etherxx; + ctlr = ether->ctlr; + + for(status = (RD(isr) & AllIntr); status; status = (RD(isr) & AllIntr)){ + /* + * Warnings that something is atoe. + */ + if(status & Hbl){ + WR(isr, Hbl); + status &= ~Hbl; + print("sonic: cd heartbeat lost\n"); + } + if(status & Br){ + WR(cr, Rst); + print("sonic: bus retry occurred\n"); + (*(void(*)(void))0xA001C020)(); + status &= ~Br; + } + + /* + * Transmission complete, for good or bad. + */ + if(status & (Txdn|Txer)){ + txpkt = &ctlr->tda[ctlr->ti]; + while(txpkt->status != Host){ + if(txpkt->status == Interface){ + WR(ctda, LS16(txpkt)); + WR(cr, Txp); + break; + } + + if((txpkt->status & Ptx) == 0) + ether->oerrs++; + + txpkt->status = Host; + ctlr->ti = NEXT(ctlr->ti, Ntb); + txpkt = &ctlr->tda[ctlr->ti]; + } + WR(isr, status & (Txdn|Txer)); + status &= ~(Txdn|Txer); + + lock(&ctlr->tlock); + txstart(ether); + unlock(&ctlr->tlock); + } + + if((status & (Pktrx|Rde)) == 0) + goto noinput; + + /* + * A packet arrived or we ran out of descriptors. + */ + rxpkt = &ctlr->rda[ctlr->rh]; + while(rxpkt->owner == Host){ + ether->inpackets++; + + /* + * If the packet was received OK, pass it up, + * otherwise log the error. + */ + if(rxpkt->status & Prx){ + /* + * Sonic delivers CRC as part of the packet count. + */ + len = (rxpkt->count & 0xFFFF)-4; + if(bp = iallocb(ROUNDUP(len, 8))){ + swizzle(bp->rp, ctlr->rb[ctlr->rh], len); + bp->wp += len; + etheriq(ether, bp, 1); + } + } + else if(rxpkt->status & Fae) + ether->frames++; + else if(rxpkt->status & Crc) + ether->crcs++; + else + ether->buffs++; + rxpkt->status = 0; + + /* + * Finished with this packet, it becomes the + * last free packet in the ring, so give it Eol, + * and take the Eol bit off the previous packet. + * Move the ring index on. + */ + wus(&rxpkt->link, rxpkt->link|Eol); + rxpkt->owner = Interface; + s = &ctlr->rda[PREV(ctlr->rh, Nrb)].link; + wus(s, *s & ~Eol); + ctlr->rh = NEXT(ctlr->rh, Nrb); + + rxpkt = &ctlr->rda[ctlr->rh]; + } + WR(isr, status & (Pktrx|Rde)); + status &= ~(Pktrx|Rde); + + noinput: + /* + * We get a 'load CAM done' interrupt + * after initialisation. Ignore it. + */ + if(status & Lcd) { + WR(isr, Lcd); + status &= ~Lcd; + } + + if(status & AllIntr) { + WR(isr, status); + print("sonic #%lux\n", status); + } + } +} + +static void +transmit(Ether* ether) +{ + Ctlr *ctlr; + + ctlr = ether->ctlr; + ilock(&ctlr->tlock); + txstart(ether); + iunlock(&ctlr->tlock); +} + +static void +reset(Ether* ether) +{ + Ctlr *ctlr; + int i; + ushort lolen, hilen, loadr, hiadr; + + ctlr = ether->ctlr; + + /* + * Reset the SONIC, toggle the Rst bit. + * Set the data config register for synchronous termination + * and 32-bit data-path width. + * Setup the descriptor and buffer area. + */ + WR(cr, Rst); + WR(dcr, 0x2423); /* 5-19 Carrera manual */ + WR(cr, 0); + + /* + * Initialise the receive resource area (RRA) and + * the receive descriptor area (RDA). + * + * We use a simple scheme of one packet per descriptor. + * We achieve this by setting the EOBC register to be + * 2 (16-bit words) less than the buffer size; + * thus the size of the receive buffers must be sizeof(Pbuf)+4. + * Set up the receive descriptors as a ring. + */ + + lolen = (Rxbuf/2) & 0xFFFF; + hilen = ((Rxbuf/2)>>16) & 0xFFFF; + + for(i = 0; i < Nrb; i++) { + wus(&ctlr->rra[i].wc0, lolen); + wus(&ctlr->rra[i].wc1, hilen); + + ctlr->rda[i].link = LS16(&ctlr->rda[NEXT(i, Nrb)]); + ctlr->rda[i].owner = Interface; + + loadr = LS16(ctlr->rb[i]); + wus(&ctlr->rra[i].ptr0, loadr); + wus(&ctlr->rda[i].ptr0, loadr); + + hiadr = MS16(ctlr->rb[i]); + wus(&ctlr->rra[i].ptr1, hiadr); + wus(&ctlr->rda[i].ptr1, hiadr); + } + + /* + * Check the important resources are QUAD aligned + */ + ISquad(ctlr->rra); + ISquad(ctlr->rda); + + /* + * Terminate the receive descriptor ring + * and load the SONIC registers to describe the RDA. + */ + ctlr->rda[Nrb-1].link |= Eol; + + WR(crda, LS16(ctlr->rda)); + WR(urda, MS16(ctlr->rda)); + WR(eobc, Rxbuf/2 - 2); + + /* + * Load the SONIC registers to describe the RRA. + * We set the rwp to beyond the area delimited by rsa and + * rea. This means that since we've already allocated all + * the buffers, we'll never get a 'receive buffer area + * exhausted' interrupt and the rrp will just wrap round. + */ + WR(urra, MS16(&ctlr->rra[0])); + WR(rsa, LS16(&ctlr->rra[0])); + WR(rrp, LS16(&ctlr->rra[0])); + WR(rea, LS16(&ctlr->rra[Nrb])); + WR(rwp, LS16(&ctlr->rra[Nrb+1])); + + /* + * Initialise the transmit descriptor area (TDA). + * Each descriptor describes one packet, we make no use + * of having the packet in multiple fragments. + * The descriptors are linked in a ring; overlapping transmission + * with buffer queueing will cause some packets to + * go out back-to-back. + * + * Load the SONIC registers to describe the TDA. + */ + for(i = 0; i < Ntb; i++){ + ctlr->tda[i].status = Host; + ctlr->tda[i].config = 0; + ctlr->tda[i].count = 1; + ctlr->tda[i].ptr0 = LS16(ctlr->tb[i]); + ctlr->tda[i].ptr1 = MS16(ctlr->tb[i]); + ctlr->tda[i].link = LS16(&ctlr->tda[NEXT(i, Ntb)]); + } + + WR(ctda, LS16(&ctlr->tda[0])); + WR(utda, MS16(&ctlr->tda[0])); + + /* + * Initialise the software receive and transmit + * ring indexes. + */ + ctlr->rh = 0; + ctlr->ri = 0; + ctlr->th = 0; + ctlr->ti = 0; + + /* + * Initialise the CAM descriptor area (CDA). + * We only have one ethernet address to load, + * broadcast is defined by the SONIC as all 1s. + * + * Load the SONIC registers to describe the CDA. + */ + ctlr->cda->cep = 0; + ctlr->cda->cap0 = (ether->addr[1]<<8)|ether->addr[0]; + ctlr->cda->cap1 = (ether->addr[3]<<8)|ether->addr[2]; + ctlr->cda->cap2 = (ether->addr[5]<<8)|ether->addr[4]; + ctlr->cda->ce = 1; + + WR(cdp, LS16(ctlr->cda)); + WR(cdc, 1); + + /* + * Load the Resource Descriptors and Cam contents + */ + WR(cr, Rrra); + while(RD(cr) & Rrra) + ; + + WR(cr, Lcam); + while(RD(cr) & Lcam) + ; + + /* + * Configure the receive control, transmit control + * and interrupt-mask registers. + * The SONIC is now initialised, but not enabled. + */ + WR(rcr, Brd); + WR(tcr, 0); + WR(imr, AllIntr); +} + +static void +initbufs(Ctlr* ctlr) +{ + int i; + uchar *mem, *base; + + /* Put the ethernet buffers in the same place + * as the bootrom + */ + mem = (void*)(KZERO|0x2000); + base = mem; + mem = CACHELINE(uchar, mem); + + /* + * Descriptors must be built in uncached space + */ + ctlr->rra = UNCACHED(RXrsc, mem); + mem = QUAD(uchar, mem+Nrb*sizeof(RXrsc)); + + ctlr->rda = UNCACHED(RXpkt, mem); + mem = QUAD(uchar, mem+Nrb*sizeof(RXpkt)); + + ctlr->tda = UNCACHED(TXpkt, mem); + mem = QUAD(uchar, mem+Ntb*sizeof(TXpkt)); + + ctlr->cda = UNCACHED(Cam, mem); + + mem = CACHELINE(uchar, mem+sizeof(Cam)); + for(i = 0; i < Nrb; i++) { + ctlr->rb[i] = UNCACHED(ulong, mem); + mem += sizeof(Pbuf)+4; + mem = QUAD(uchar, mem); + } + for(i = 0; i < Ntb; i++) { + ctlr->tb[i] = UNCACHED(ulong, mem); + mem += sizeof(Pbuf); + mem = QUAD(uchar, mem); + } + if(mem >= base+64*1024) + panic("sonic init"); +} + +static int +sonicreset(Ether* ether) +{ + Ctlr *ctlr; + + if(ether->ctlrno != 0) + return 1; + + /* + * Map the device registers and allocate + * memory for the receive/transmit rings. + * Set the physical ethernet address and + * prime the interrupt handler. + */ + ether->ctlr = malloc(sizeof(Ctlr)); + ctlr = ether->ctlr; + ether->port = Sonicbase; + + initbufs(ctlr); + enetaddr(ether->addr); + + reset(ether); + + /* + * Hack: etherintr is called directly from trap with no arguments. + * There can only be one sonic, so keep a note of the generic ether + * struct. + */ + etherxx = ether; + + return 0; +} + +static Endev sonicdev = { + "sonic", + + sonicreset, + attach, + transmit, + nil, /* interrupt - etherintr called directly from trap */ + nil, /* ifstat */ + promiscuous, + nil, /* multicast */ + + 0, 0, /* vid, did */ +}; + +Endev* endev[] = { + &sonicdev, + nil, +}; diff --git a/carrera/fns.h b/carrera/fns.h index 4c0a815db8a4f6d904ad9420a06015efe32c203f..2efa5fa9cbe2f31bd888655c5604f6e29075e2c8 100644 --- a/carrera/fns.h +++ b/carrera/fns.h @@ -3,6 +3,7 @@ void addclock0link(void (*)(void)); void arginit(void); int busprobe(ulong); +int cistrcmp(char*, char*); void cleancache(void); void clearmmucache(void); void clock(Ureg*); diff --git a/carrera/io.h b/carrera/io.h index 0f3c03a5f424496f5a61fd52208e4fbca6089ca7..93d1036880dbce510ea15c470b6634f6f5169fc8 100644 --- a/carrera/io.h +++ b/carrera/io.h @@ -62,7 +62,7 @@ enum Floppyint = (1<<1), Parallelint = (1<<0), Intenareg = 0xE0200004, /* Device interrupt enable */ - Intcause = 0xE0200007, /* Decice interrupt cause register */ + Intcause = 0xE0200007, /* Device interrupt cause register */ Promvirt = 0xE1000000, /* From ARCS chipset */ Promphys = 0x1FC00000, /* MIPs processors */ @@ -125,3 +125,9 @@ enum extern int int0mask; /* interrupts enabled for first 8259 */ extern int int1mask; /* interrupts enabled for second 8259 */ + +/* + * All motherboard and ISA interrupts are enabled by default. + */ +#define intrenable(a, b, c, d) +#define BUSUNKNOWN (-1) diff --git a/carrera/main.c b/carrera/main.c index f0aca329830e99427cd328c59791ab6565329117..a0cc26f416c7a8a048f580e02a18b173c2cfd3a5 100644 --- a/carrera/main.c +++ b/carrera/main.c @@ -482,16 +482,42 @@ buzz(int f, int d) USED(d); } +int +cistrcmp(char *a, char *b) +{ + int ac, bc; + + for(;;){ + ac = *a++; + bc = *b++; + + if(ac >= 'A' && ac <= 'Z') + ac = 'a' + (ac - 'A'); + if(bc >= 'A' && bc <= 'Z') + bc = 'a' + (bc - 'A'); + ac -= bc; + if(ac) + return ac; + if(bc == 0) + break; + } + return 0; +} + /* * dummy routine for interoperability with pc's */ int isaconfig(char *class, int ctlrno, ISAConf *isa) { - if(strcmp(class, "audio") == 0 && ctlrno == 0){ + if(cistrcmp(class, "audio") == 0 && ctlrno == 0){ strcpy(isa->type, "sb16"); return 1; } + if(cistrcmp(class, "ether") == 0 && ctlrno == 0){ + strcpy(isa->type, "sonic"); + return 1; + } return 0; } diff --git a/port/chan.c b/port/chan.c index 0d14f79b1dd21486c9ee778352fd9c6cd69c0b9a..44dec72bbc3739385c125fb604385973b4352a3e 100644 --- a/port/chan.c +++ b/port/chan.c @@ -104,28 +104,58 @@ newchan(void) return c; } -int -okchan1(Chan *c) +void +okchan1(Chan *c, char *msg, int n) { - if(c->type > 64) - return 0; - if((ulong)(c->next) & 3) - return 0; - if((ulong)(c->link) & 3) - return 0; - if((ulong)(c->path) & 3) - return 0; - if((ulong)(c->mnt) & 3) - return 0; - if((ulong)(c->xmnt) & 3) - return 0; - if((ulong)(c->mcp) & 3) - return 0; - if((ulong)(c->mchan) & 3) - return 0; - if((ulong)(c->session) & 3) - return 0; - return 1; + int i, bad; + + bad = 0; + if(c->type > 64){ + print("bad type %d\n", c->type); + bad = 1; + } + if((ulong)(c->next) & 3){ + print("bad next %.8lux\n", c->next); + bad = 1; + } + if((ulong)(c->link) & 3){ + print("bad link %.8lux\n", c->link); + bad = 1; + } + if((ulong)(c->path) & 3){ + print("bad path %.8lux\n", c->path); + bad = 1; + } + if((ulong)(c->mnt) & 3){ + print("bad mnt %.8lux\n", c->mnt); + bad = 1; + } + if((ulong)(c->xmnt) & 3){ + print("bad xmnt %.8lux\n", c->xmnt); + bad = 1; + } + if((ulong)(c->mcp) & 3){ + print("bad mcp %.8lux\n", c->mcp); + bad = 1; + } + if((ulong)(c->mchan) & 3){ + print("bad mchan %.8lux\n", c->mchan); + bad = 1; + } + if((ulong)(c->session) & 3){ + print("bad session %.8lux\n", c->session); + bad = 1; + } + if(!bad) + return; + + print("okchan: %s (%d=#%.8lux)\n", msg, n, n); + for(i=0; i<16; i++){ + print("%d=%.8lux\n", i, ((ulong*)c)[i]); + if((i&7) == 7) + print("\n"); + } + for(;;); } void @@ -134,14 +164,9 @@ okchan(char *msg, int n) int s; Chan *c; - return; s = splhi(); for(c = chanalloc.list; c; c = c->link) - if(!okchan1(c)){ - spllo(); - print("okchan: %s (%d=#%.8lux)\n", msg, n, n); - panic("okchan"); - } + okchan1(c, msg, n); splx(s); }