| plan 9 kernel history: overview | file list | diff list |
1993/0906/carrera/devether.c (diff list | history)
| 1993/0905/sys/src/9/carrera/devether.c:16,24 – 1993/0906/sys/src/9/carrera/devether.c:16,34 (short | long | prev | next) | ||
| 1993/0904 | #define SONICADDR ((Sonic*)Sonicbase) | |
| 1993/0903 | ||
| 1993/0904 | #define RD(rn) (delay(1), *(ulong*)((ulong)&SONICADDR->rn^4)) | |
| 1993/0905 |
| |
| 1993/0906 | #define WR(rn, v) (delay(1), *(ulong*)((ulong)&SONICADDR->rn^4) = (v)) #define ISquad(s) if((ulong)s & 0x7) panic("sonic: Quad alignment"); | |
| 1993/0903 | ||
| 1993/0906 | typedef struct Pbuf Pbuf; struct Pbuf { uchar d[6]; uchar s[6]; uchar type[2]; uchar data[1500]; uchar crc[4]; }; | |
| 1993/0904 | typedef struct { ulong cr; /* command */ | |
| 1993/0905/sys/src/9/carrera/devether.c:32,38 – 1993/0906/sys/src/9/carrera/devether.c:42,51 | ||
| 1993/0904 | ulong pad0x08[5]; /* */ ulong urda; /* upper receive descriptor address */ ulong crda; /* current receive descriptor address */ | |
| 1993/0906 | ulong crba0; /* DO NOT WRITE THESE */ ulong crba1; ulong rbwc0; ulong rbwc1; | |
| 1993/0904 | ulong eobc; /* end of buffer word count */ ulong urra; /* upper receive resource address */ ulong rsa; /* resource start address */ | |
| 1993/0905/sys/src/9/carrera/devether.c:111,116 – 1993/0906/sys/src/9/carrera/devether.c:124,132 | ||
| 1993/0904 | Hbl = 0x2000, /* CD heartbeat lost */ Br = 0x4000, /* bus retry occurred */ AllIntr = 0x7771, /* all of the above */ | |
| 1993/0906 | Rxbuf = sizeof(Pbuf)+4, Txbuf = sizeof(Pbuf), | |
| 1993/0903 | }; | |
| 1993/0904 | /* | |
| 1993/0905/sys/src/9/carrera/devether.c:118,131 – 1993/0906/sys/src/9/carrera/devether.c:134,147 | ||
| 1993/0904 | */ typedef struct { | |
| 1993/0906 | 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; | |
| 1993/0904 | } RXrsc; | |
| 1993/0903 | /* | |
| 1993/0905/sys/src/9/carrera/devether.c:133,152 – 1993/0906/sys/src/9/carrera/devether.c:149,169 | ||
| 1993/0903 | */ typedef struct { | |
| 1993/0904 |
| |
| 1993/0906 | 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 */ | |
| 1993/0904 | } RXpkt; | |
| 1993/0903 | ||
| 1993/0904 | /* | |
| 1993/0905/sys/src/9/carrera/devether.c:154,175 – 1993/0906/sys/src/9/carrera/devether.c:171,192 | ||
| 1993/0904 | */ typedef struct { | |
| 1993/0906 | 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 */ | |
| 1993/0904 | } TXpkt; enum{ | |
| 1993/0905/sys/src/9/carrera/devether.c:186,201 – 1993/0906/sys/src/9/carrera/devether.c:203,219 | ||
| 1993/0904 | */ | |
| 1993/0905 | typedef struct { | |
| 1993/0904 |
| |
| 1993/0906 | 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 */ | |
| 1993/0904 | } Cam; typedef struct Ether Ether; | |
| 1993/0905/sys/src/9/carrera/devether.c:204,211 – 1993/0906/sys/src/9/carrera/devether.c:222,227 | ||
| 1993/0903 | uchar ea[6]; | |
| 1993/0904 | uchar ba[6]; | |
| 1993/0903 | ||
| 1993/0904 |
| |
| 1993/0903 |
| |
| 1993/0904 | int th; /* first transmit buffer owned by host */ | |
| 1993/0905/sys/src/9/carrera/devether.c:214,226 – 1993/0906/sys/src/9/carrera/devether.c:230,243 | ||
| 1993/0904 | int rh; /* first receive buffer owned by host */ int ri; /* first receive buffer owned by interface */ | |
| 1993/0906 | RXrsc *rra; /* receive resource area */ RXpkt *rda; /* receive descriptor area */ TXpkt *tda; /* transmit descriptor area */ Cam *cda; /* CAM descriptor area */ | |
| 1993/0904 | ||
| 1993/0906 | uchar *rb[Nrb]; /* receive buffer area */ uchar *tb[Ntb]; /* transmit buffer area */ | |
| 1993/0903 | Netif; | |
| 1993/0904 | }; | |
| 1993/0903 | ||
| 1993/0905/sys/src/9/carrera/devether.c:231,251 – 1993/0906/sys/src/9/carrera/devether.c:248,276 | ||
| 1993/0904 | #define LS16(addr) (PADDR(addr) & 0xFFFF) #define MS16(addr) ((PADDR(addr)>>16) & 0xFFFF) | |
| 1993/0906 | void sonicswap(void*, int); | |
| 1993/0903 | static void | |
| 1993/0906 | wus(ushort *a, ushort v) { a[0] = v; a[-1] = v; } static void | |
| 1993/0904 | reset(Ether *ctlr) | |
| 1993/0903 | { | |
| 1993/0904 | int i; | |
| 1993/0906 | ushort lolen, hilen, loadr, hiadr; | |
| 1993/0903 | ||
| 1993/0904 | /* * Reset the SONIC, toggle the Rst bit. * Set the data config register for synchronous termination * and 32-bit data-path width. | |
| 1993/0906 | * Setup the descriptor and buffer area. | |
| 1993/0904 | */ WR(cr, Rst); | |
| 1993/0905 | WR(dcr, 0x2423); /* 5-19 Carrera manual */ | |
| 1993/0904 |
| |
| 1993/0903 | ||
| 1993/0904 | /* * Initialise the receive resource area (RRA) and | |
| 1993/0905/sys/src/9/carrera/devether.c:254,276 – 1993/0906/sys/src/9/carrera/devether.c:279,312 | ||
| 1993/0904 | * 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; | |
| 1993/0906 | * thus the size of the receive buffers must be sizeof(Pbuf)+4. | |
| 1993/0904 | * Set up the receive descriptors as a ring. */ | |
| 1993/0906 | lolen = (Rxbuf/2) & 0xFFFF; hilen = ((Rxbuf/2)>>16) & 0xFFFF; | |
| 1993/0905 | for(i = 0; i < Nrb; i++) { | |
| 1993/0904 |
| |
| 1993/0906 | wus(&ctlr->rra[i].wc0, lolen); wus(&ctlr->rra[i].wc1, hilen); | |
| 1993/0903 | ||
| 1993/0904 |
| |
| 1993/0906 | ctlr->rda[i].link = LS16(&ctlr->rda[NEXT(i, Nrb)]); | |
| 1993/0904 | ctlr->rda[i].owner = Interface; | |
| 1993/0903 | ||
| 1993/0904 |
| |
| 1993/0906 | 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); | |
| 1993/0904 | } | |
| 1993/0903 | ||
| 1993/0906 | /* * Check the important resources are QUAD aligned */ | |
| 1993/0905 | ISquad(ctlr->rra); ISquad(ctlr->rda); | |
| 1993/0904 | /* * Terminate the receive descriptor ring | |
| 1993/0905/sys/src/9/carrera/devether.c:280,287 – 1993/0906/sys/src/9/carrera/devether.c:316,322 | ||
| 1993/0903 | ||
| 1993/0904 | WR(crda, LS16(ctlr->rda)); WR(urda, MS16(ctlr->rda)); | |
| 1993/0905 |
| |
| 1993/0906 | WR(eobc, Rxbuf/2 - 2); | |
| 1993/0903 | ||
| 1993/0904 | /* * Load the SONIC registers to describe the RRA. | |
| 1993/0905/sys/src/9/carrera/devether.c:289,296 – 1993/0906/sys/src/9/carrera/devether.c:324,329 | ||
| 1993/0904 | * 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. | |
| 1993/0905/sys/src/9/carrera/devether.c:298,307 – 1993/0906/sys/src/9/carrera/devether.c:331,336 | ||
| 1993/0904 | WR(rea, LS16(&ctlr->rra[Nrb])); WR(rwp, LS16(&ctlr->rra[Nrb+1])); | |
| 1993/0903 | ||
| 1993/0904 |
| |
| 1993/0905/sys/src/9/carrera/devether.c:339,356 – 1993/0906/sys/src/9/carrera/devether.c:368,393 | ||
| 1993/0904 | * broadcast is defined by the SONIC as all 1s. * * Load the SONIC registers to describe the CDA. | |
| 1993/0906 | 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; | |
| 1993/0904 |
| |
| 1993/0906 | WR(cdp, LS16(ctlr->cda)); | |
| 1993/0904 | WR(cdc, 1); | |
| 1993/0906 | /* * End the reset * Load the Resource Descriptors and Cam contents */ WR(cr, 0); WR(cr, Rrra); while(RD(cr) & Rrra) ; | |
| 1993/0904 | WR(cr, Lcam); while(RD(cr) & Lcam) ; | |
| 1993/0905/sys/src/9/carrera/devether.c:366,408 – 1993/0906/sys/src/9/carrera/devether.c:403,444 | ||
| 1993/0903 | } void | |
| 1993/0905 |
| |
| 1993/0906 | sonicpkt(Ether *ctlr, RXpkt *r, Pbuf *p) | |
| 1993/0905 | { | |
| 1993/0906 | 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); } | |
| 1993/0905 | } void | |
| 1993/0903 | etherintr(void) { | |
| 1993/0904 |
| |
| 1993/0906 | Ether *c; | |
| 1993/0904 | ulong status; TXpkt *txpkt; RXpkt *rxpkt; | |
| 1993/0903 | ||
| 1993/0904 |
| |
| 1993/0906 | c = ether[0]; | |
| 1993/0903 | ||
| 1993/0904 | for(;;) { status = RD(isr) & AllIntr; if(status == 0) break; | |
| 1993/0905 |
| |
| 1993/0904 | WR(isr, status); | |
| 1993/0905/sys/src/9/carrera/devether.c:410,416 – 1993/0906/sys/src/9/carrera/devether.c:446,452 | ||
| 1993/0904 | * Transmission complete, for good or bad. */ if(status & (Txdn|Txer)){ | |
| 1993/0906 | txpkt = &c->tda[c->ti]; | |
| 1993/0904 | while(txpkt->status != Host){ if(txpkt->status == Interface){ WR(ctda, LS16(txpkt)); | |
| 1993/0905/sys/src/9/carrera/devether.c:419,429 – 1993/0906/sys/src/9/carrera/devether.c:455,465 | ||
| 1993/0904 | } if((txpkt->status & Ptx) == 0) | |
| 1993/0906 | c->oerrs++; | |
| 1993/0904 | txpkt->status = Host; | |
| 1993/0906 | c->ti = NEXT(c->ti, Ntb); txpkt = &c->tda[c->ti]; | |
| 1993/0904 | } status &= ~(Txdn|Txer); | |
| 1993/0903 | } | |
| 1993/0905/sys/src/9/carrera/devether.c:434,471 – 1993/0906/sys/src/9/carrera/devether.c:470,493 | ||
| 1993/0904 | /* * A packet arrived or we ran out of descriptors. */ | |
| 1993/0905 |
| |
| 1993/0906 | rxpkt = &c->rda[c->rh]; | |
| 1993/0904 | while(rxpkt->owner == Host){ | |
| 1993/0906 | c->inpackets++; | |
| 1993/0904 | /* * If the packet was received OK, pass it up, * otherwise log the error. | |
| 1993/0903 |
| |
| 1993/0906 | if(rxpkt->status & Prx) sonicpkt(c, rxpkt, (Pbuf*)c->rb[c->rh]); | |
| 1993/0904 | else if(rxpkt->status & Fae) | |
| 1993/0906 | c->frames++; | |
| 1993/0904 | else if(rxpkt->status & Crc) | |
| 1993/0906 | c->crcs++; | |
| 1993/0904 | else | |
| 1993/0906 | c->buffs++; | |
| 1993/0904 | /* * Finished with this packet, it becomes the | |
| 1993/0905/sys/src/9/carrera/devether.c:475,484 – 1993/0906/sys/src/9/carrera/devether.c:497,506 | ||
| 1993/0904 | */ rxpkt->link |= Eol; rxpkt->owner = Interface; | |
| 1993/0906 | c->rda[PREV(c->rh, Nrb)].link &= ~Eol; c->rh = NEXT(c->rh, Nrb); | |
| 1993/0904 |
| |
| 1993/0906 | rxpkt = &c->rda[c->rh]; | |
| 1993/0903 | } | |
| 1993/0904 | status &= ~(Pktrx|Rde); | |
| 1993/0903 | ||
| 1993/0905/sys/src/9/carrera/devether.c:494,509 – 1993/0906/sys/src/9/carrera/devether.c:516,531 | ||
| 1993/0904 | * Warnings that something is afoot. */ if(status & Hbl){ | |
| 1993/0905 |
| |
| 1993/0906 | print("sonic: cd heartbeat lost\n"); | |
| 1993/0904 | status &= ~Hbl; | |
| 1993/0903 | } | |
| 1993/0904 | if(status & Br){ | |
| 1993/0905 |
| |
| 1993/0906 | print("sonic: bus retry occurred\n"); | |
| 1993/0904 | status &= ~Br; } if(status & AllIntr) | |
| 1993/0905 |
| |
| 1993/0906 | print("sonic #%lux\n", status); | |
| 1993/0903 | } } | |
| 1993/0905/sys/src/9/carrera/devether.c:524,529 – 1993/0906/sys/src/9/carrera/devether.c:546,592 | ||
| 1993/0904 | WR(rcr, reg&~Pro); | |
| 1993/0903 | } | |
| 1993/0906 | static void initbufs(Ether *c) { int i; uchar *mem; mem = xspanalloc(64*1024, BY2PG, 0); mem = CACHELINE(uchar, mem); /* * Descriptors must be built in uncached space */ 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); /* * DMA buffers are cache coherent - but we must not straddle * a cache line */ 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); } for(i = 0; i < Ntb; i++) { c->tb[i] = UNCACHED(uchar, mem); mem += sizeof(Pbuf); mem = QUAD(uchar, mem); } } | |
| 1993/0903 | void etherreset(void) { | |
| 1993/0905/sys/src/9/carrera/devether.c:535,546 – 1993/0906/sys/src/9/carrera/devether.c:598,608 | ||
| 1993/0904 | * Set the physical ethernet address and * prime the interrupt handler. */ | |
| 1993/0905 |
| |
| 1993/0906 | if(ether[0] == 0) { ctlr = malloc(sizeof(Ether)); ether[0] = ctlr; initbufs(ctlr); | |
| 1993/0905 | enetaddr(ether[0]->ea); | |
| 1993/0903 | } | |
| 1993/0904 | ctlr = ether[0]; | |
| 1993/0905/sys/src/9/carrera/devether.c:559,570 – 1993/0906/sys/src/9/carrera/devether.c:621,626 | ||
| 1993/0903 | } void | |
| 1993/0905 |
| |
| 1993/0903 | etherinit(void) { } | |
| 1993/0905/sys/src/9/carrera/devether.c:578,584 – 1993/0906/sys/src/9/carrera/devether.c:634,639 | ||
| 1993/0905 | enable = 1; WR(cr, Rxen); } | |
| 1993/0903 | return devattach('l', spec); } | |
| 1993/0905/sys/src/9/carrera/devether.c:629,642 – 1993/0906/sys/src/9/carrera/devether.c:684,695 | ||
| 1993/0903 | long etherwrite(Chan *c, void *buf, long n, ulong offset) { | |
| 1993/0904 |
| |
| 1993/0906 | Pbuf *p; | |
| 1993/0904 | TXpkt *txpkt; Ether *ctlr = ether[0]; | |
| 1993/0903 | USED(offset); | |
| 1993/0905 |
| |
| 1993/0903 | if(n > ETHERMAXTU) error(Ebadarg); | |
| 1993/0905/sys/src/9/carrera/devether.c:651,657 – 1993/0906/sys/src/9/carrera/devether.c:704,710 | ||
| 1993/0905 | if(!isoutbuf(ctlr)) | |
| 1993/0903 | print("ether transmitter jammed\n"); | |
| 1993/0904 | else { | |
| 1993/0906 | p =(Pbuf*)ctlr->tb[ctlr->th]; | |
| 1993/0903 | memmove(p->d, buf, n); if(n < 60) { memset(p->d+n, 0, 60-n); | |
| 1993/0905/sys/src/9/carrera/devether.c:658,663 – 1993/0906/sys/src/9/carrera/devether.c:711,717 | ||
| 1993/0903 | n = 60; } | |
| 1993/0904 | memmove(p->s, ctlr->ea, sizeof(ctlr->ea)); | |
| 1993/0906 | sonicswap(p, n); | |
| 1993/0904 | txpkt = &ctlr->tda[ctlr->th]; txpkt->size = n; | |
| 1993/0905/sys/src/9/carrera/devether.c:671,678 – 1993/0906/sys/src/9/carrera/devether.c:725,730 | ||
| 1993/0903 | } | |
| 1993/0904 | qunlock(&ctlr->tlock); | |
| 1993/0905 |
| |
| 1993/0903 | return n; } | |
| 1993/0905/sys/src/9/carrera/devether.c:692,695 – 1993/0906/sys/src/9/carrera/devether.c:744,766 | ||
| 1993/0903 | etherwstat(Chan *c, char *dp) { | |
| 1993/0904 | netifwstat(ether[0], c, dp); | |
| 1993/0906 | } #define swiz(s) (s<<24)|((s>>8)&0xff00)|((s<<8)&0xff0000)|(s>>24) 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; } | |
| 1993/0903 | } | |