| plan 9 kernel history: overview | file list | diff list |
1995/0520/carrera/devether.c (diff list | history)
| 1995/0520/sys/src/9/carrera/devether.c:1,836 – 1997/0327/sys/src/9/carrera/devether.c:1,854 (short | long | prev | next) | ||
| 1993/0903 | #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" /* | |
| 1993/0904 | * National Semiconductor DP83932 * Systems-Oriented Network Interface Controller * (SONIC) | |
| 1993/0903 | */ | |
| 1993/0904 | #define SONICADDR ((Sonic*)Sonicbase) | |
| 1993/0903 | ||
| 1993/1219 | #define RD(rn) (delay(0), *(ulong*)((ulong)&SONICADDR->rn^4)) #define WR(rn, v) (delay(0), *(ulong*)((ulong)&SONICADDR->rn^4) = (v)) | |
| 1993/0906 | #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 */ 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 */ | |
| 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 */ 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; | |
| 1993/0903 | enum { | |
| 1993/1218 | Nrb = 16, /* receive buffers */ | |
| 1993/1217 | Ntb = 8, /* transmit buffers */ | |
| 1993/0904 | }; | |
| 1993/0903 | ||
| 1993/0904 | 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 */ | |
| 1993/0903 | ||
| 1993/0904 | 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 */ | |
| 1993/0903 | ||
| 1993/0904 | 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 */ | |
| 1993/0903 | ||
| 1993/0904 | Ptx = 0x0001, /* packet transmitted ok */ Pintr = 0x8000, /* programmable interrupt */ | |
| 1993/0903 | ||
| 1993/0904 | 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 */ | |
| 1993/0906 | Rxbuf = sizeof(Pbuf)+4, Txbuf = sizeof(Pbuf), | |
| 1993/0903 | }; | |
| 1993/0904 | /* * Receive Resource Descriptor. */ 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/0904 | * Receive Packet Descriptor. | |
| 1993/0903 | */ typedef struct { | |
| 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 | /* * Transmit Packet Descriptor. */ 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{ Eol = 1, /* end of list bit in descriptor link */ Host = 0, /* descriptor belongs to host */ Interface = -1, /* descriptor belongs to interface */ Nether = 1, | |
| 1993/0905 | Ntypes = 8, | |
| 1993/0904 | }; /* * CAM Descriptor */ | |
| 1993/0905 | typedef struct { | |
| 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/0903 | struct Ether { uchar ea[6]; | |
| 1993/0904 | uchar ba[6]; | |
| 1993/0903 | QLock tlock; /* lock for grabbing transmitter queue */ Rendez tr; /* wait here for free xmit buffer */ | |
| 1993/0904 | int th; /* first transmit buffer owned by host */ int ti; /* first transmit buffer owned by interface */ | |
| 1993/0903 | ||
| 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/0904 |
| |
| 1997/0327 | static Ether *ether[Nether]; | |
| 1993/0903 | ||
| 1993/0904 | #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) | |
| 1993/0906 |
| |
| 1997/0327 | static void sonicswap(void*, int); | |
| 1993/0906 | ||
| 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 */ | |
| 1994/0107 | WR(cr, 0); | |
| 1993/0903 | ||
| 1993/0904 | /* * 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; | |
| 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/0906 | wus(&ctlr->rra[i].wc0, lolen); wus(&ctlr->rra[i].wc1, hilen); | |
| 1993/0903 | ||
| 1993/0906 | ctlr->rda[i].link = LS16(&ctlr->rda[NEXT(i, Nrb)]); | |
| 1993/0904 | ctlr->rda[i].owner = Interface; | |
| 1993/0903 | ||
| 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 * and load the SONIC registers to describe the RDA. | |
| 1993/0903 | */ | |
| 1993/0904 | ctlr->rda[Nrb-1].link |= Eol; | |
| 1993/0903 | ||
| 1993/0904 | WR(crda, LS16(ctlr->rda)); WR(urda, MS16(ctlr->rda)); | |
| 1993/0906 | WR(eobc, Rxbuf/2 - 2); | |
| 1993/0903 | ||
| 1993/0904 | /* * 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])); | |
| 1993/0903 | ||
| 1993/0904 | /* * 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. */ | |
| 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 | /* * Load the Resource Descriptors and Cam contents */ WR(cr, Rrra); while(RD(cr) & Rrra) ; | |
| 1993/0904 | 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. */ | |
| 1994/0107 | WR(rcr, Brd); | |
| 1993/0904 | WR(tcr, 0); WR(imr, AllIntr); | |
| 1993/0903 | } | |
| 1997/0327 | static void | |
| 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 | } | |
| 1993/1212 | static int isoutbuf(void *arg) { Ether *ctlr = arg; return ctlr->tda[ctlr->th].status == Host; } | |
| 1993/0905 | void | |
| 1993/0903 | etherintr(void) { | |
| 1993/0906 | Ether *c; | |
| 1994/0107 | ushort *s; | |
| 1993/0904 | ulong status; TXpkt *txpkt; RXpkt *rxpkt; | |
| 1993/0903 | ||
| 1993/0906 | c = ether[0]; | |
| 1993/0903 | ||
| 1993/0904 | for(;;) { status = RD(isr) & AllIntr; if(status == 0) break; | |
| 1994/0107 | /* * 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; } | |
| 1993/0904 | /* * Transmission complete, for good or bad. */ | |
| 1993/1219 | 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)); WR(cr, Txp); break; } 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 | } | |
| 1994/0107 | WR(isr, status & (Txdn|Txer)); | |
| 1993/0904 | status &= ~(Txdn|Txer); | |
| 1993/1212 | if(isoutbuf(c)) wakeup(&c->tr); | |
| 1993/0903 | } | |
| 1993/0904 | if((status & (Pktrx|Rde)) == 0) goto noinput; /* * A packet arrived or we ran out of descriptors. */ | |
| 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/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 | ||
| 1994/0107 | rxpkt->status = 0; | |
| 1993/0904 | /* * 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. */ | |
| 1994/0107 | wus(&rxpkt->link, rxpkt->link|Eol); | |
| 1993/0904 | rxpkt->owner = Interface; | |
| 1994/0107 | s = &c->rda[PREV(c->rh, Nrb)].link; wus(s, *s & ~Eol); | |
| 1993/0906 | c->rh = NEXT(c->rh, Nrb); | |
| 1993/0904 | ||
| 1993/0906 | rxpkt = &c->rda[c->rh]; | |
| 1993/0903 | } | |
| 1994/0107 | WR(isr, status & (Pktrx|Rde)); | |
| 1993/0904 | status &= ~(Pktrx|Rde); | |
| 1993/0903 | ||
| 1993/0904 | noinput: | |
| 1993/0903 | /* | |
| 1993/0904 | * We get a 'load CAM done' interrupt * after initialisation. Ignore it. | |
| 1993/0903 | */ | |
| 1994/0107 | if(status & Lcd) { WR(isr, Lcd); | |
| 1993/0904 | status &= ~Lcd; | |
| 1993/0903 | } | |
| 1993/0904 | ||
| 1994/0107 | if(status & AllIntr) { WR(isr, status); | |
| 1993/0906 | print("sonic #%lux\n", status); | |
| 1994/0107 | } | |
| 1993/0903 | } } /* * turn promiscuous mode on/off */ static void promiscuous(void *arg, int on) { | |
| 1993/0904 | ushort reg; | |
| 1993/0903 | USED(arg); | |
| 1993/0904 | reg = RD(rcr); | |
| 1993/0903 | if(on) | |
| 1993/0904 | WR(rcr, reg|Pro); | |
| 1993/0903 | else | |
| 1993/0904 | WR(rcr, reg&~Pro); | |
| 1993/0903 | } | |
| 1993/0906 | static void initbufs(Ether *c) { int i; | |
| 1993/1217 | uchar *mem, *base; | |
| 1993/0906 | ||
| 1994/0524 | /* Put the ethernet buffers in the same place * as the bootrom */ mem = (void*)(KZERO|0x2000); | |
| 1993/1217 | base = mem; | |
| 1993/0906 | 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); 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/1217 | if(mem >= base+64*1024) panic("sonic init"); | |
| 1993/0906 | } | |
| 1993/0903 |
| |
| 1997/0327 | static void | |
| 1993/0903 | etherreset(void) { | |
| 1993/0904 | Ether *ctlr; | |
| 1993/0903 | ||
| 1993/0904 | /* * Map the device registers and allocate * memory for the receive/transmit rings. * Set the physical ethernet address and * prime the interrupt handler. */ | |
| 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/0903 | ||
| 1993/0904 | reset(ctlr); | |
| 1993/0903 | ||
| 1993/0904 | memset(ctlr->ba, 0xFF, sizeof(ctlr->ba)); | |
| 1993/0903 | /* general network interface structure */ | |
| 1993/0904 |
| |
| 1997/0327 | netifinit(ether[0], "ether0", Ntypes, 32*1024); | |
| 1993/0904 | 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]; | |
| 1993/0903 | } | |
| 1997/0327 | static Chan* | |
| 1993/0903 | etherattach(char *spec) { | |
| 1993/0905 | static int enable; if(enable == 0) { enable = 1; WR(cr, Rxen); } | |
| 1995/0520 | if(*spec && strcmp(spec, "0") != 0) error(Eio); | |
| 1993/0903 | return devattach('l', spec); } | |
| 1997/0327 | static int | |
| 1993/0903 | etherwalk(Chan *c, char *name) { | |
| 1993/0904 | return netifwalk(ether[0], c, name); | |
| 1993/0903 | } | |
| 1997/0327 | static Chan* | |
| 1993/0903 | etheropen(Chan *c, int omode) { | |
| 1993/0904 | return netifopen(ether[0], c, omode); | |
| 1993/0903 | } | |
| 1997/0327 | static void | |
| 1993/0903 | ethercreate(Chan *c, char *name, int omode, ulong perm) { USED(c, name, omode, perm); } | |
| 1997/0327 | static void | |
| 1993/0903 | etherclose(Chan *c) { | |
| 1993/0904 | netifclose(ether[0], c); | |
| 1993/0903 | } long etherread(Chan *c, void *buf, long n, ulong offset) { | |
| 1993/0904 | return netifread(ether[0], c, buf, n, offset); | |
| 1993/0903 | } | |
| 1995/0108 |
| |
| 1993/0903 | static int | |
| 1993/1202 | etherloop(Etherpkt *p, long n) { int s, different; ushort t; Netfile *f, **fp; | |
| 1995/0114 | Ether *ctlr = ether[0]; | |
| 1993/1202 | ||
| 1995/0114 | different = memcmp(p->d, ctlr->ea, sizeof(ctlr->ea)); if(different && memcmp(p->d, ctlr->bcast, sizeof(p->d))) | |
| 1993/1202 | return 0; s = splhi(); t = (p->type[0]<<8) | p->type[1]; | |
| 1995/0114 | for(fp = ctlr->f; fp < &ctlr->f[Ntypes]; fp++) { | |
| 1993/1202 | 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; } } splx(s); return !different; } | |
| 1993/0903 |
| |
| 1997/0327 | static long | |
| 1993/0903 | etherwrite(Chan *c, void *buf, long n, ulong offset) { | |
| 1993/0906 | Pbuf *p; | |
| 1994/0107 | ushort *s; | |
| 1993/0904 | TXpkt *txpkt; Ether *ctlr = ether[0]; | |
| 1993/0903 | USED(offset); /* etherif.c handles structure */ if(NETTYPE(c->qid.path) != Ndataqid) | |
| 1993/0904 | return netifwrite(ether[0], c, buf, n); | |
| 1993/0903 | ||
| 1993/1212 | if(n > ETHERMAXTU) error(Ebadarg); | |
| 1995/0114 | p = buf; memmove(p->s, ctlr->ea, sizeof(ctlr->ea)); | |
| 1993/0903 | /* we handle data */ | |
| 1993/1202 | if(etherloop(buf, n)) return n; | |
| 1993/0904 | qlock(&ctlr->tlock); | |
| 1994/0107 | ctlr->outpackets++; | |
| 1993/0918 | if(waserror()) { qunlock(&ctlr->tlock); nexterror(); } | |
| 1993/1212 | tsleep(&ctlr->tr, isoutbuf, ctlr, 10000); | |
| 1993/0905 | ||
| 1993/1212 | if(!isoutbuf(ctlr)) print("ether transmitter jammed cr #%lux\n", RD(cr)); | |
| 1993/0904 | else { | |
| 1993/1212 | p = (Pbuf*)ctlr->tb[ctlr->th]; | |
| 1993/0903 | memmove(p->d, buf, n); if(n < 60) { memset(p->d+n, 0, 60-n); n = 60; } | |
| 1993/0906 | sonicswap(p, n); | |
| 1993/0904 | txpkt = &ctlr->tda[ctlr->th]; txpkt->size = n; txpkt->fsize = n; | |
| 1994/0107 | wus(&txpkt->link, txpkt->link|Eol); | |
| 1993/0904 | txpkt->status = Interface; | |
| 1994/0107 | s = &ctlr->tda[PREV(ctlr->th, Ntb)].link; wus(s, *s & ~Eol); | |
| 1993/0904 | ctlr->th = NEXT(ctlr->th, Ntb); WR(cr, Txp); | |
| 1993/0903 | } | |
| 1993/0918 | poperror(); | |
| 1993/0904 | qunlock(&ctlr->tlock); | |
| 1993/0905 | ||
| 1993/0903 | return n; | |
| 1995/0108 | } | |
| 1993/0903 |
| |
| 1997/0327 | static void | |
| 1993/0903 | etherremove(Chan *c) { USED(c); } | |
| 1997/0327 | static void | |
| 1993/0903 | etherstat(Chan *c, char *dp) { | |
| 1993/0904 | netifstat(ether[0], c, dp); | |
| 1993/0903 | } | |
| 1997/0327 | static void | |
| 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) | |
| 1997/0327 | static void | |
| 1993/0906 | 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 | } | |
| 1997/0327 | int parseether(uchar *to, char *from) { char nip[4]; char *p; int i; p = from; for(i = 0; i < 6; i++){ if(*p == 0) return -1; nip[0] = *p++; if(*p == 0) return -1; nip[1] = *p++; nip[2] = 0; to[i] = strtoul(nip, 0, 16); if(*p == ':') p++; } return 0; } Dev etherdevtab = { etherreset, devinit, etherattach, devclone, etherwalk, etherstat, etheropen, ethercreate, etherclose, etherread, devbread, etherwrite, devbwrite, etherremove, etherwstat, }; | |