|
|
1.1 ! root 1: #include "u.h" ! 2: #include "../port/lib.h" ! 3: #include "mem.h" ! 4: #include "dat.h" ! 5: #include "fns.h" ! 6: #include "io.h" ! 7: #include "../port/error.h" ! 8: #include "devtab.h" ! 9: ! 10: enum { ! 11: Ntypes= 9, /* max number of ethernet packet types */ ! 12: Maxrb= 128, /* max buffers in a ring */ ! 13: }; ! 14: #define RSUCC(x) (((x)+1)%l.nrrb) ! 15: #define TSUCC(x) (((x)+1)%l.ntrb) ! 16: ! 17: /* ! 18: * Communication with the lance is via a transmit and receive ring of ! 19: * message descriptors. The Initblock contains pointers to and sizes of ! 20: * these rings. The rings must be in RAM addressible by the lance ! 21: */ ! 22: typedef struct { ! 23: ushort laddr; /* low order piece of address */ ! 24: ushort flags; /* flags and high order piece of address */ ! 25: short size; /* size of buffer */ ! 26: ushort cntflags; /* (rcv)count of bytes in buffer; (xmt) more flags */ ! 27: } Msg; ! 28: ! 29: /* ! 30: * lance memory map ! 31: */ ! 32: struct Lancemem ! 33: { ! 34: /* ! 35: * initialization block ! 36: */ ! 37: ushort mode; /* chip control (see below) */ ! 38: ushort etheraddr[3]; /* the ethernet physical address */ ! 39: ushort multi[4]; /* multicast addresses, 1 bit for each of 64 */ ! 40: ushort rdralow; /* receive buffer ring */ ! 41: ushort rdrahigh; /* (top three bits define size of ring) */ ! 42: ushort tdralow; /* transmit buffer ring */ ! 43: ushort tdrahigh; /* (top three bits define size of ring) */ ! 44: ! 45: /* ! 46: * ring buffers ! 47: * first receive, then transmit ! 48: */ ! 49: Msg rmr[Maxrb]; /* recieve message ring */ ! 50: Msg tmr[Maxrb]; /* transmit message ring */ ! 51: }; ! 52: ! 53: /* ! 54: * Some macros for dealing with lance memory addresses. The lance splits ! 55: * its 24 bit addresses across two 16 bit registers. ! 56: */ ! 57: #define HADDR(a) ((((ulong)(a))>>16)&0xFF) ! 58: #define LADDR(a) (((ulong)a)&0xFFFF) ! 59: ! 60: /* ! 61: * The following functions exist to sidestep a quirk in the SGI IO3 lance ! 62: * interface. In all other processors, the lance's initialization block and ! 63: * descriptor rings look like normal memory. In the SGI IO3, the CPU sees a ! 64: * 6 byte pad twixt all lance memory shorts. Therefore, we use the following ! 65: * macros to compute the address whenever accessing the lance memory to make ! 66: * the code portable. Sic transit gloria. ! 67: */ ! 68: #define LANCEMEM ((Lancemem*)0) ! 69: #define MPs(a) (*(short *)(l.lanceram + l.sep*((ushort*)&a - (ushort*)0))) ! 70: #define MPus(a) (*(ushort *)(l.lanceram + l.sep*((ushort*)&a - (ushort*)0))) ! 71: ! 72: /* ! 73: * one per ethernet packet type ! 74: */ ! 75: typedef struct Ethertype Ethertype; ! 76: struct Ethertype ! 77: { ! 78: QLock; ! 79: Netprot; /* stat info */ ! 80: int type; /* ethernet type */ ! 81: int prom; /* promiscuous mode */ ! 82: Queue *q; ! 83: int inuse; ! 84: Rendez rc; /* rendzvous for close */ ! 85: Ethertype *closeline; /* close list */ ! 86: }; ! 87: ! 88: ! 89: /* ! 90: * lance state ! 91: */ ! 92: typedef struct { ! 93: QLock; ! 94: ! 95: Lance; /* host dependent lance params */ ! 96: int prom; /* number of promiscuous channels */ ! 97: int all; /* number of channels listening to all packets */ ! 98: int wedged; /* the lance is wedged */ ! 99: Network net; ! 100: ! 101: int inited; ! 102: uchar *lmp; /* location of parity test */ ! 103: ! 104: Rendez rr; /* rendezvous for an input buffer */ ! 105: QLock rlock; /* semaphore on tc */ ! 106: ushort rl; /* first rcv Message belonging to Lance */ ! 107: ! 108: Rendez tr; /* rendezvous for an output buffer */ ! 109: QLock tlock; /* semaphore on tc */ ! 110: ushort tc; /* next xmt Message CPU will try for */ ! 111: ! 112: Ethertype *closeline; /* channels waiting to close */ ! 113: Lock closepin; /* lock for closeline */ ! 114: Ethertype e[Ntypes]; ! 115: int debug; ! 116: int kstarted; ! 117: uchar bcast[6]; ! 118: ! 119: Queue self; /* packets turned around at the interface */ ! 120: ! 121: /* sadistics */ ! 122: ! 123: int misses; ! 124: int inpackets; ! 125: int outpackets; ! 126: int crcs; /* input crc errors */ ! 127: int oerrs; /* output erros */ ! 128: int frames; /* framing errors */ ! 129: int overflows; /* packet overflows */ ! 130: int buffs; /* buffering errors */ ! 131: } SoftLance; ! 132: static SoftLance l; ! 133: ! 134: /* ! 135: * mode bits in the lance initialization block ! 136: */ ! 137: #define PROM 0x8000 ! 138: #define INTL 0x40 ! 139: #define DRTY 0x20 ! 140: #define COLL 0x10 ! 141: #define DTCR 0x8 ! 142: #define LOOP 0x4 ! 143: #define DTX 0x2 ! 144: #define DRX 0x1 ! 145: ! 146: /* ! 147: * LANCE CSR0, this is the register we play with most often. We leave ! 148: * this register pointed to by l.rap in normal operation. ! 149: */ ! 150: #define ERR0 0x8000 ! 151: #define BABL 0x4000 ! 152: #define CERR 0x2000 ! 153: #define MISS 0x1000 ! 154: #define MERR 0x800 ! 155: #define RINT 0x400 ! 156: #define TINT 0x200 ! 157: #define IDON 0x100 ! 158: #define INTR 0x80 ! 159: #define INEA 0x40 ! 160: #define RXON 0x20 ! 161: #define TXON 0x10 ! 162: #define TDMD 0x8 ! 163: #define STOP 0x4 ! 164: #define STRT 0x2 ! 165: #define INIT 0x1 ! 166: ! 167: /* ! 168: * flag bits from a buffer descriptor in the rcv/xmt rings ! 169: */ ! 170: #define LANCEOWNER 0x8000 /* 1 means that the buffer can be used by the chip */ ! 171: #define ERR 0x4000 /* error summary, the OR of all error bits */ ! 172: #define FRAM 0x2000 /* CRC error and incoming packet not a multiple of 8 bits */ ! 173: #define OFLO 0x1000 /* (receive) lost some of the packet */ ! 174: #define MORE 0x1000 /* (transmit) more than 1 retry to send the packet */ ! 175: #define CRC 0x800 /* (receive) crc error reading packet */ ! 176: #define ONE 0x800 /* (transmit) one retry to transmit the packet */ ! 177: #define BUF 0x400 /* (receive) out of buffers while reading a packet */ ! 178: #define DEF 0x400 /* (transmit) deffered while transmitting packet */ ! 179: #define STP 0x200 /* start of packet */ ! 180: #define ENP 0x100 /* end of packet */ ! 181: ! 182: /* ! 183: * cntflags bits from a buffer descriptor in the rcv/xmt rings ! 184: */ ! 185: #define BUFF 0x8000 /* buffer error (host screwed up?) */ ! 186: #define UFLO 0x4000 /* underflow from memory */ ! 187: #define LCOL 0x1000 /* late collision (ether too long?) */ ! 188: #define LCAR 0x800 /* loss of carrier (ether broken?) */ ! 189: #define RTRY 0x400 /* couldn't transmit (bad station on ether?) */ ! 190: #define TTDR 0x3FF /* time domain reflectometer */ ! 191: ! 192: /* ! 193: * predeclared ! 194: */ ! 195: static void lancekproc(void *); ! 196: static void lancestart(int); ! 197: static void lanceup(Etherpkt*, int); ! 198: static int lanceclonecon(Chan*); ! 199: static void lancestatsfill(Chan*, char*, int); ! 200: static void lancetypefill(Chan*, char*, int); ! 201: ! 202: /* ! 203: * lance stream module definition ! 204: */ ! 205: static void lanceoput(Queue*, Block*); ! 206: static void lancestopen(Queue*, Stream*); ! 207: static void lancestclose(Queue*); ! 208: static void stagerbuf(void); ! 209: Qinfo lanceinfo = { nullput, lanceoput, lancestopen, lancestclose, "lance" }; ! 210: ! 211: /* ! 212: * open a lance line discipline ! 213: */ ! 214: void ! 215: lancestopen(Queue *q, Stream *s) ! 216: { ! 217: Ethertype *et; ! 218: ! 219: et = &l.e[s->id]; ! 220: RD(q)->ptr = WR(q)->ptr = et; ! 221: et->type = 0; ! 222: et->q = RD(q); ! 223: et->inuse = 1; ! 224: } ! 225: ! 226: /* ! 227: * close lance line discipline ! 228: * ! 229: * the lock is to synchronize changing the ethertype with ! 230: * sending packets up the stream on interrupts. ! 231: */ ! 232: static int ! 233: isclosed(void *x) ! 234: { ! 235: return ((Ethertype *)x)->q == 0; ! 236: } ! 237: ! 238: static void ! 239: lancestclose(Queue *q) ! 240: { ! 241: Ethertype *et; ! 242: ! 243: et = (Ethertype *)(q->ptr); ! 244: if(et->prom){ ! 245: qlock(&l); ! 246: l.prom--; ! 247: if(l.prom == 0) ! 248: lancestart(0); ! 249: qunlock(&l); ! 250: } ! 251: if(et->type == -1){ ! 252: qlock(&l); ! 253: l.all--; ! 254: qunlock(&l); ! 255: } ! 256: ! 257: /* ! 258: * mark as closing and wait for kproc to close us ! 259: */ ! 260: lock(&l.closepin); ! 261: et->closeline = l.closeline; ! 262: l.closeline = et; ! 263: unlock(&l.closepin); ! 264: wakeup(&l.rr); ! 265: sleep(&et->rc, isclosed, et); ! 266: ! 267: et->type = 0; ! 268: et->q = 0; ! 269: et->prom = 0; ! 270: et->inuse = 0; ! 271: netdisown(et); ! 272: } ! 273: ! 274: /* ! 275: * the ``connect'' control message specifyies the type ! 276: */ ! 277: Proc *lanceout; ! 278: static int ! 279: isobuf(void *x) ! 280: { ! 281: Msg *m; ! 282: ! 283: m = x; ! 284: return l.wedged || (MPus(m->flags)&LANCEOWNER) == 0; ! 285: } ! 286: ! 287: static void ! 288: lanceoput(Queue *q, Block *bp) ! 289: { ! 290: int n, len; ! 291: Etherpkt *p; ! 292: Ethertype *e; ! 293: Msg *m; ! 294: Block *nbp; ! 295: ! 296: if(bp->type == M_CTL){ ! 297: e = q->ptr; ! 298: qlock(&l); ! 299: if(streamparse("connect", bp)){ ! 300: if(e->type == -1) ! 301: l.all--; ! 302: e->type = strtol((char *)bp->rptr, 0, 0); ! 303: if(e->type == -1) ! 304: l.all++; ! 305: } else if(streamparse("promiscuous", bp)) { ! 306: e->prom = 1; ! 307: l.prom++; ! 308: if(l.prom == 1) ! 309: lancestart(PROM);/**/ ! 310: } ! 311: qunlock(&l); ! 312: freeb(bp); ! 313: return; ! 314: } ! 315: ! 316: /* ! 317: * give packet a local address, return upstream if destined for ! 318: * this machine. ! 319: */ ! 320: if(BLEN(bp) < ETHERHDRSIZE){ ! 321: bp = pullup(bp, ETHERHDRSIZE); ! 322: if(bp == 0) ! 323: return; ! 324: } ! 325: p = (Etherpkt *)bp->rptr; ! 326: memmove(p->s, l.ea, sizeof(l.ea)); ! 327: if(*p->d == 0xff || l.prom || l.all){ ! 328: len = blen(bp); ! 329: nbp = copyb(bp, len); ! 330: nbp = expandb(nbp, len >= ETHERMINTU ? len : ETHERMINTU); ! 331: if(nbp){ ! 332: nbp->wptr = nbp->rptr+len; ! 333: putq(&l.self, nbp); ! 334: wakeup(&l.rr); ! 335: } ! 336: } else if(*p->d == *l.ea && memcmp(l.ea, p->d, sizeof(l.ea)) == 0){ ! 337: len = blen(bp); ! 338: bp = expandb(bp, len >= ETHERMINTU ? len : ETHERMINTU); ! 339: if(bp){ ! 340: putq(&l.self, bp); ! 341: wakeup(&l.rr); ! 342: } ! 343: return; ! 344: } ! 345: ! 346: if(l.wedged) { ! 347: freeb(bp); ! 348: return; ! 349: } ! 350: ! 351: /* ! 352: * only one transmitter at a time ! 353: */ ! 354: qlock(&l.tlock); ! 355: ! 356: if(l.wedged) { ! 357: qunlock(&l.tlock); ! 358: freeb(bp); ! 359: return; ! 360: } ! 361: ! 362: if(waserror()){ ! 363: qunlock(&l.tlock); ! 364: freeb(bp); ! 365: nexterror(); ! 366: } ! 367: ! 368: /* ! 369: * Wait till we get an output buffer, complain if input ! 370: * or output seems wedged. ! 371: */ ! 372: m = &(LANCEMEM->tmr[l.tc]); ! 373: p = &l.tp[l.tc]; ! 374: while((MPus(m->flags)&LANCEOWNER) != 0) { ! 375: tsleep(&l.tr, isobuf, m, 128); ! 376: if(l.wedged || isobuf(m) == 0){ ! 377: qunlock(&l.tlock); ! 378: freeb(bp); ! 379: poperror(); ! 380: print("lance wedged, dumping block & restarting\n"); ! 381: lancestart(0); ! 382: l.wedged = 0; ! 383: return; ! 384: } ! 385: } ! 386: ! 387: /* ! 388: * copy message into lance RAM ! 389: */ ! 390: len = 0; ! 391: for(nbp = bp; nbp; nbp = nbp->next){ ! 392: if(sizeof(Etherpkt) - len >= (n = BLEN(nbp))){ ! 393: memmove(((uchar *)p)+len, nbp->rptr, n); ! 394: len += n; ! 395: } else ! 396: print("no room damn it\n"); ! 397: if(bp->flags & S_DELIM) ! 398: break; ! 399: } ! 400: ! 401: /* ! 402: * pad the packet (zero the pad) ! 403: */ ! 404: if(len < ETHERMINTU){ ! 405: memset(((char*)p)+len, 0, ETHERMINTU-len); ! 406: len = ETHERMINTU; ! 407: } ! 408: ! 409: /* ! 410: * set up the ring descriptor and hand to lance ! 411: */ ! 412: l.outpackets++; ! 413: MPs(m->size) = -len; ! 414: MPus(m->cntflags) = 0; ! 415: MPus(m->laddr) = LADDR(&l.ltp[l.tc]); ! 416: MPus(m->flags) = LANCEOWNER|STP|ENP|HADDR(&l.ltp[l.tc]); ! 417: l.tc = TSUCC(l.tc); ! 418: *l.rdp = INEA|TDMD; /**/ ! 419: wbflush(); ! 420: qunlock(&l.tlock); ! 421: freeb(bp); ! 422: poperror(); ! 423: } ! 424: ! 425: /* ! 426: * stop the lance and allocate buffers ! 427: */ ! 428: void ! 429: lancereset(void) ! 430: { ! 431: static int already; ! 432: int i; ! 433: ! 434: if(already == 0){ ! 435: already = 1; ! 436: lancesetup(&l); ! 437: ! 438: l.net.name = "ether"; ! 439: l.net.nconv = Ntypes; ! 440: l.net.devp = &lanceinfo; ! 441: l.net.protop = 0; ! 442: l.net.listen = 0; ! 443: l.net.clone = lanceclonecon; ! 444: l.net.ninfo = 2; ! 445: l.net.info[0].name = "stats"; ! 446: l.net.info[0].fill = lancestatsfill; ! 447: l.net.info[1].name = "type"; ! 448: l.net.info[1].fill = lancetypefill; ! 449: for(i = 0; i < Ntypes; i++) ! 450: netadd(&l.net, &l.e[i], i); ! 451: ! 452: memset(l.bcast, 0xff, sizeof l.bcast); ! 453: } ! 454: ! 455: /* ! 456: * stop the lance ! 457: */ ! 458: *l.rap = 0; ! 459: *l.rdp = STOP; ! 460: l.wedged = 1; ! 461: } ! 462: ! 463: /* ! 464: * Initialize and start the lance. This routine can be called only from a process. ! 465: * It may be used to restart a dead lance. ! 466: */ ! 467: static void ! 468: lancestart(int mode) ! 469: { ! 470: int i; ! 471: Lancemem *lm = LANCEMEM; ! 472: Msg *m; ! 473: ! 474: /* ! 475: * wait till both receiver and transmitter are ! 476: * quiescent ! 477: */ ! 478: qlock(&l.tlock); ! 479: qlock(&l.rlock); ! 480: ! 481: lancereset(); ! 482: l.rl = 0; ! 483: l.tc = 0; ! 484: ! 485: /* ! 486: * create the initialization block ! 487: */ ! 488: MPus(lm->mode) = mode; ! 489: ! 490: /* ! 491: * set ether addr from the value in the id prom. ! 492: * the id prom has them in reverse order, the init ! 493: * structure wants them in byte swapped order ! 494: */ ! 495: MPus(lm->etheraddr[0]) = (l.ea[1]<<8) | l.ea[0]; ! 496: MPus(lm->etheraddr[1]) = (l.ea[3]<<8) | l.ea[2]; ! 497: MPus(lm->etheraddr[2]) = (l.ea[5]<<8) | l.ea[4]; ! 498: ! 499: /* ! 500: * ignore multicast addresses ! 501: */ ! 502: MPus(lm->multi[0]) = 0; ! 503: MPus(lm->multi[1]) = 0; ! 504: MPus(lm->multi[2]) = 0; ! 505: MPus(lm->multi[3]) = 0; ! 506: ! 507: /* ! 508: * set up rcv message ring ! 509: */ ! 510: m = lm->rmr; ! 511: for(i = 0; i < l.nrrb; i++, m++){ ! 512: MPs(m->size) = -sizeof(Etherpkt); ! 513: MPus(m->cntflags) = 0; ! 514: MPus(m->laddr) = LADDR(&l.lrp[i]); ! 515: MPus(m->flags) = HADDR(&l.lrp[i]); ! 516: } ! 517: MPus(lm->rdralow) = LADDR(l.lm->rmr); ! 518: MPus(lm->rdrahigh) = (l.lognrrb<<13)|HADDR(l.lm->rmr); ! 519: ! 520: ! 521: /* ! 522: * give the lance all the rcv buffers except one (as a sentinel) ! 523: */ ! 524: m = lm->rmr; ! 525: for(i = 0; i < l.nrrb; i++, m++) ! 526: MPus(m->flags) |= LANCEOWNER; ! 527: ! 528: /* ! 529: * set up xmit message ring ! 530: */ ! 531: m = lm->tmr; ! 532: for(i = 0; i < l.ntrb; i++, m++){ ! 533: MPs(m->size) = 0; ! 534: MPus(m->cntflags) = 0; ! 535: MPus(m->laddr) = LADDR(&l.ltp[i]); ! 536: MPus(m->flags) = HADDR(&l.ltp[i]); ! 537: } ! 538: MPus(lm->tdralow) = LADDR(l.lm->tmr); ! 539: MPus(lm->tdrahigh) = (l.logntrb<<13)|HADDR(l.lm->tmr); ! 540: ! 541: /* ! 542: * point lance to the initialization block ! 543: */ ! 544: *l.rap = 1; ! 545: *l.rdp = LADDR(l.lm); ! 546: wbflush(); ! 547: *l.rap = 2; ! 548: *l.rdp = HADDR(l.lm); ! 549: ! 550: /* ! 551: * The lance byte swaps the ethernet packet unless we tell it not to ! 552: */ ! 553: wbflush(); ! 554: *l.rap = 3; ! 555: *l.rdp = l.busctl; ! 556: ! 557: /* ! 558: * initialize lance, turn on interrupts, turn on transmit and rcv. ! 559: */ ! 560: wbflush(); ! 561: *l.rap = 0; ! 562: *l.rdp = INEA|INIT|STRT; /**/ ! 563: ! 564: /* ! 565: * spin for up to a second waiting for the IDON interrupt ! 566: */ ! 567: for(i = 0; i < 1000; i++){ ! 568: if(l.wedged == 0) ! 569: break; ! 570: delay(1); ! 571: } ! 572: ! 573: /* ! 574: * let in everything else ! 575: */ ! 576: qunlock(&l.rlock); ! 577: qunlock(&l.tlock); ! 578: } ! 579: ! 580: void ! 581: lanceinit(void) ! 582: { ! 583: } ! 584: ! 585: Chan* ! 586: lanceattach(char *spec) ! 587: { ! 588: if(l.kstarted == 0){ ! 589: kproc("lancekproc", lancekproc, 0); ! 590: l.kstarted = 1; ! 591: lancestart(0); ! 592: print("lance ether: %.2x%.2x%.2x%.2x%.2x%.2x\n", ! 593: l.ea[0], l.ea[1], l.ea[2], l.ea[3], l.ea[4], l.ea[5]); ! 594: } ! 595: return devattach('l', spec); ! 596: } ! 597: ! 598: Chan* ! 599: lanceclone(Chan *c, Chan *nc) ! 600: { ! 601: return devclone(c, nc); ! 602: } ! 603: ! 604: int ! 605: lancewalk(Chan *c, char *name) ! 606: { ! 607: return netwalk(c, name, &l.net); ! 608: } ! 609: ! 610: void ! 611: lancestat(Chan *c, char *dp) ! 612: { ! 613: netstat(c, dp, &l.net); ! 614: } ! 615: ! 616: /* ! 617: * Pass open's of anything except the directory to streamopen ! 618: */ ! 619: Chan* ! 620: lanceopen(Chan *c, int omode) ! 621: { ! 622: return netopen(c, omode, &l.net); ! 623: } ! 624: ! 625: void ! 626: lancecreate(Chan *c, char *name, int omode, ulong perm) ! 627: { ! 628: USED(c, name, omode, perm); ! 629: error(Eperm); ! 630: } ! 631: ! 632: void ! 633: lanceclose(Chan *c) ! 634: { ! 635: if(c->stream) ! 636: streamclose(c); ! 637: } ! 638: ! 639: long ! 640: lanceread(Chan *c, void *a, long n, ulong offset) ! 641: { ! 642: return netread(c, a, n, offset, &l.net); ! 643: } ! 644: ! 645: long ! 646: lancewrite(Chan *c, void *a, long n, ulong offset) ! 647: { ! 648: USED(offset); ! 649: return streamwrite(c, a, n, 0); ! 650: } ! 651: ! 652: void ! 653: lanceremove(Chan *c) ! 654: { ! 655: USED(c); ! 656: error(Eperm); ! 657: } ! 658: ! 659: void ! 660: lancewstat(Chan *c, char *dp) ! 661: { ! 662: netwstat(c, dp, &l.net); ! 663: } ! 664: ! 665: /* ! 666: * user level network interface routines ! 667: */ ! 668: static void ! 669: lancestatsfill(Chan *c, char* p, int n) ! 670: { ! 671: char buf[512]; ! 672: ! 673: USED(c); ! 674: sprint(buf, "in: %d\nout: %d\ncrc errs: %d\noverflows: %d\nframe errs: %d\nbuff errs: %d\noerrs: %d\naddr: %.02x:%.02x:%.02x:%.02x:%.02x:%.02x\n", ! 675: l.inpackets, l.outpackets, l.crcs, ! 676: l.overflows, l.frames, l.buffs, l.oerrs, ! 677: l.ea[0], l.ea[1], l.ea[2], l.ea[3], l.ea[4], l.ea[5]); ! 678: strncpy(p, buf, n); ! 679: } ! 680: ! 681: static void ! 682: lancetypefill(Chan *c, char* p, int n) ! 683: { ! 684: char buf[16]; ! 685: Ethertype *e; ! 686: ! 687: e = &l.e[STREAMID(c->qid.path)]; ! 688: sprint(buf, "%d", e->type); ! 689: strncpy(p, buf, n); ! 690: } ! 691: ! 692: static int ! 693: lanceclonecon(Chan *c) ! 694: { ! 695: Ethertype *e; ! 696: ! 697: USED(c); ! 698: for(e = l.e; e < &l.e[Ntypes]; e++){ ! 699: qlock(e); ! 700: if(e->inuse || e->q){ ! 701: qunlock(e); ! 702: continue; ! 703: } ! 704: e->inuse = 1; ! 705: netown(e, u->p->user, 0); ! 706: qunlock(e); ! 707: return e - l.e; ! 708: } ! 709: error(Enodev); ! 710: return -1; /* never reached */ ! 711: } ! 712: ! 713: /* ! 714: * We will: ! 715: * (1) Clear interrupt cause in the lance ! 716: * (2) service all current events ! 717: */ ! 718: void ! 719: lanceintr(void) ! 720: { ! 721: ushort csr; ! 722: ! 723: csr = *l.rdp; ! 724: ! 725: /* ! 726: * turn off the interrupt and any error indicators ! 727: */ ! 728: *l.rdp = IDON|INEA|TINT|RINT|BABL|CERR|MISS|MERR; ! 729: ! 730: /* ! 731: * see if an error occurred ! 732: */ ! 733: if(csr & (BABL|MISS|MERR)){ ! 734: if(l.misses++ < 4) { ! 735: print("lance err #%ux\n", csr); ! 736: } else { ! 737: print("lance stopped\n"); ! 738: l.wedged = 1; ! 739: l.misses = 0; ! 740: lancereset(); ! 741: wakeup(&l.rr); ! 742: wakeup(&l.tr); ! 743: return; ! 744: } ! 745: } ! 746: ! 747: /* ! 748: * initialization done ! 749: */ ! 750: if(csr & IDON) ! 751: l.wedged = 0; ! 752: ! 753: /* ! 754: * the lance turns off if it gets strange output errors ! 755: */ ! 756: if((csr & (TXON|RXON)) != (TXON|RXON)) ! 757: l.wedged = 1; ! 758: ! 759: /* ! 760: * wakeup the input process ! 761: */ ! 762: if(csr & RINT) ! 763: wakeup(&l.rr); ! 764: ! 765: /* ! 766: * wake any process waiting for a transmit buffer ! 767: */ ! 768: if(csr & TINT) ! 769: wakeup(&l.tr); ! 770: } ! 771: ! 772: /* ! 773: * send a packet upstream ! 774: */ ! 775: static void ! 776: lanceup(Etherpkt *p, int len) ! 777: { ! 778: int t; ! 779: Block *bp; ! 780: Ethertype *e; ! 781: ! 782: if(len <= 0) ! 783: return; ! 784: ! 785: t = (p->type[0]<<8) | p->type[1]; ! 786: for(e = &l.e[0]; e < &l.e[Ntypes]; e++){ ! 787: /* ! 788: * check for open, the right type, and flow control ! 789: */ ! 790: if(e->q==0 || (t!=e->type && e->type!=-1) || e->q->next->len>Streamhi) ! 791: continue; ! 792: ! 793: /* ! 794: * only a trace channel gets packets destined for other machines ! 795: */ ! 796: if(e->type!=-1 && p->d[0]!=0xff ! 797: && (*p->d != *l.ea || memcmp(p->d, l.ea, sizeof(p->d))!=0)) ! 798: continue; ! 799: ! 800: if(!waserror()){ ! 801: bp = allocb(len); ! 802: memmove(bp->rptr, (uchar *)p, len); ! 803: bp->wptr += len; ! 804: bp->flags |= S_DELIM; ! 805: PUTNEXT(e->q, bp); ! 806: poperror(); ! 807: } ! 808: } ! 809: } ! 810: ! 811: /* ! 812: * input process, awakened on each interrupt with rcv buffers filled ! 813: */ ! 814: static int ! 815: isinput(void *arg) ! 816: { ! 817: Msg *m = arg; ! 818: ! 819: return ((MPus(m->flags) & LANCEOWNER)==0) || l.wedged || l.self.first ! 820: || l.closeline; ! 821: } ! 822: ! 823: static void ! 824: lancekproc(void *arg) ! 825: { ! 826: Etherpkt *p; ! 827: Ethertype *e; ! 828: int len; ! 829: int t; ! 830: Lancemem *lm = LANCEMEM; ! 831: Msg *m; ! 832: Block *bp; ! 833: ! 834: USED(arg); ! 835: ! 836: while(waserror()) ! 837: print("lancekproc err %s\n", u->error); ! 838: ! 839: for(;;){ ! 840: qlock(&l.rlock); ! 841: while(bp = getq(&l.self)){ ! 842: lanceup((Etherpkt*)bp->rptr, BLEN(bp)); ! 843: freeb(bp); ! 844: } ! 845: m = &(lm->rmr[l.rl]); ! 846: while((MPus(m->flags) & LANCEOWNER)==0){ ! 847: l.inpackets++; ! 848: t = MPus(m->flags); ! 849: if(t & ERR){ ! 850: if(t & FRAM) ! 851: l.frames++; ! 852: if(t & OFLO) ! 853: l.overflows++; ! 854: if(t & CRC) ! 855: l.crcs++; ! 856: if(t & BUFF) ! 857: l.buffs++; ! 858: } else { ! 859: /* ! 860: * stuff packet up each queue that wants it ! 861: */ ! 862: p = &l.rp[l.rl]; ! 863: len = MPus(m->cntflags) - 4; ! 864: lanceup(p, len); ! 865: } ! 866: ! 867: /* ! 868: * stage the next input buffer ! 869: */ ! 870: MPs(m->size) = -sizeof(Etherpkt); ! 871: MPus(m->cntflags) = 0; ! 872: MPus(m->laddr) = LADDR(&l.lrp[l.rl]); ! 873: MPus(m->flags) = LANCEOWNER|HADDR(&l.lrp[l.rl]); ! 874: wbflush(); ! 875: l.rl = RSUCC(l.rl); ! 876: m = &(lm->rmr[l.rl]); ! 877: } ! 878: qunlock(&l.rlock); ! 879: sleep(&l.rr, isinput, m); ! 880: ! 881: /* ! 882: * if the lance is wedged, restart it ! 883: */ ! 884: if(l.wedged){ ! 885: print("lance wedged, restarting\n"); ! 886: lancestart(0); ! 887: } ! 888: ! 889: /* ! 890: * close ethertypes requesting it ! 891: */ ! 892: if(l.closeline){ ! 893: lock(&l.closepin); ! 894: for(e = l.closeline; e; e = e->closeline){ ! 895: e->q = 0; ! 896: wakeup(&e->rc); ! 897: } ! 898: l.closeline = 0; ! 899: unlock(&l.closepin); ! 900: } ! 901: } ! 902: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.