|
|
1.1 ! root 1: #include "u.h" ! 2: #include "lib.h" ! 3: #include "mem.h" ! 4: #include "dat.h" ! 5: #include "fns.h" ! 6: #include "io.h" ! 7: ! 8: #include "ether.h" ! 9: ! 10: enum { ! 11: IDport = 0x0110, /* anywhere between 0x0100 and 0x01F0 */ ! 12: /* CommandRs */ ! 13: GlobalReset = 0x00, /* Global Reset */ ! 14: SelectWindow = 0x01, /* SelectWindow command */ ! 15: StartCoax = 0x02, /* Start Coaxial Transceiver */ ! 16: RxDisable = 0x03, /* RX Disable */ ! 17: RxEnable = 0x04, /* RX Enable */ ! 18: RxReset = 0x05, /* RX Reset */ ! 19: RxDiscard = 0x08, /* RX Discard Top Packet */ ! 20: TxEnable = 0x09, /* TX Enable */ ! 21: TxDisable = 0x0A, /* TX Disable */ ! 22: TxReset = 0x0B, /* TX Reset */ ! 23: AckIntr = 0x0D, /* Acknowledge Interrupt */ ! 24: SetIntrMask = 0x0E, /* Set Interrupt Mask */ ! 25: SetReadZeroMask = 0x0F, /* Set Read Zero Mask */ ! 26: SetRxFilter = 0x10, /* Set RX Filter */ ! 27: SetTxAvailable = 0x12, /* Set TX Available Threshold */ ! 28: ! 29: /* RX Filter CommandR Bits */ ! 30: MyEtherAddr = 0x01, /* Individual address */ ! 31: Multicast = 0x02, /* Group (multicast) addresses */ ! 32: Broadcast = 0x04, /* Broadcast address */ ! 33: Promiscuous = 0x08, /* All addresses (promiscuous mode */ ! 34: ! 35: /* Window Register Offsets */ ! 36: CommandR = 0x0E, /* all windows */ ! 37: Status = 0x0E, ! 38: ! 39: ManufacturerID = 0x00, /* window 0 */ ! 40: ProductID = 0x02, ! 41: ConfigControl = 0x04, ! 42: AddressConfig = 0x06, ! 43: ResourceConfig = 0x08, ! 44: EEPROMcmd = 0x0A, ! 45: EEPROMdata = 0x0C, ! 46: ! 47: /* AddressConfig Bits */ ! 48: XcvrTypeMask = 0xC000, /* Transceiver Type Select */ ! 49: Xcvr10BaseT = 0x0000, ! 50: XcvrAUI = 0x4000, ! 51: XcvrBNC = 0xC000, ! 52: ! 53: /* ConfigControl */ ! 54: Rst = 0x04, /* Reset Adapter */ ! 55: Ena = 0x01, /* Enable Adapter */ ! 56: ! 57: TxFreeBytes = 0x0C, /* window 1 */ ! 58: TxStatus = 0x0B, ! 59: Timer = 0x0A, ! 60: RxStatus = 0x08, ! 61: Fifo = 0x00, ! 62: ! 63: /* Status/Interrupt Bits */ ! 64: Latch = 0x0001, /* Interrupt Latch */ ! 65: Failure = 0x0002, /* Adapter Failure */ ! 66: TxComplete = 0x0004, /* TX Complete */ ! 67: TxAvailable = 0x0008, /* TX Available */ ! 68: RxComplete = 0x0010, /* RX Complete */ ! 69: AllIntr = 0x00FE, /* All Interrupt Bits */ ! 70: CmdInProgress = 0x1000, /* CommandR In Progress */ ! 71: ! 72: /* TxStatus Bits */ ! 73: TxJabber = 0x20, /* Jabber Error */ ! 74: TxUnderrun = 0x10, /* Underrun */ ! 75: TxMaxColl = 0x08, /* Maximum Collisions */ ! 76: ! 77: /* RxStatus Bits */ ! 78: RxByteMask = 0x07FF, /* RX Bytes (0-1514) */ ! 79: RxErrMask = 0x3800, /* Type of Error: */ ! 80: RxErrOverrun = 0x0000, /* Overrrun */ ! 81: RxErrOversize = 0x0800, /* Oversize Packet (>1514) */ ! 82: RxErrDribble = 0x1000, /* Dribble Bit(s) */ ! 83: RxErrRunt = 0x1800, /* Runt Packet */ ! 84: RxErrFraming = 0x2000, /* Alignment (Framing) */ ! 85: RxErrCRC = 0x2800, /* CRC */ ! 86: RxError = 0x4000, /* Error */ ! 87: RxEmpty = 0x8000, /* Incomplete or FIFO empty */ ! 88: ! 89: FIFOdiag = 0x04, /* window 4 */ ! 90: MediaStatus = 0x0A, ! 91: ! 92: /* FIFOdiag bits */ ! 93: TxOverrun = 0x0400, /* TX Overrrun */ ! 94: RxOverrun = 0x0800, /* RX Overrun */ ! 95: RxStatusOverrun = 0x1000, /* RX Status Overrun */ ! 96: RxUnderrun = 0x2000, /* RX Underrun */ ! 97: RxReceiving = 0x8000, /* RX Receiving */ ! 98: ! 99: /* MediaStatus bits */ ! 100: JabberEna = 0x0040, /* Jabber Enabled (writeable) */ ! 101: LinkBeatEna = 0x0080, /* Link Beat Enabled (writeable) */ ! 102: }; ! 103: ! 104: #define COMMAND(port, cmd, a) outs(port+CommandR, ((cmd)<<11)|(a)) ! 105: ! 106: static void ! 107: attach(Ctlr *ctlr) ! 108: { ! 109: ulong port; ! 110: ! 111: port = ctlr->card.port; ! 112: /* ! 113: * Set the receiver packet filter for our own and ! 114: * and broadcast addresses, set the interrupt masks ! 115: * for all interrupts, and enable the receiver and transmitter. ! 116: * The only interrupt we should see under normal conditions ! 117: * is the receiver interrupt. If the transmit FIFO fills up, ! 118: * we will also see TxAvailable interrupts. ! 119: */ ! 120: COMMAND(port, SetRxFilter, Broadcast|MyEtherAddr); ! 121: COMMAND(port, SetReadZeroMask, AllIntr|Latch); ! 122: COMMAND(port, SetIntrMask, AllIntr|Latch); ! 123: COMMAND(port, RxEnable, 0); ! 124: COMMAND(port, TxEnable, 0); ! 125: } ! 126: ! 127: static void ! 128: receive(Ctlr *ctlr) ! 129: { ! 130: ushort status; ! 131: RingBuf *rb; ! 132: int len; ! 133: ulong port; ! 134: ! 135: port = ctlr->card.port; ! 136: while(((status = ins(port+RxStatus)) & RxEmpty) == 0){ ! 137: /* ! 138: * If we had an error, log it and continue ! 139: * without updating the ring. ! 140: */ ! 141: if(status & RxError){ ! 142: switch(status & RxErrMask){ ! 143: ! 144: case RxErrOverrun: /* Overrrun */ ! 145: case RxErrOversize: /* Oversize Packet (>1514) */ ! 146: case RxErrRunt: /* Runt Packet */ ! 147: case RxErrFraming: /* Alignment (Framing) */ ! 148: ctlr->frames++; ! 149: break; ! 150: ! 151: case RxErrCRC: /* CRC */ ! 152: ctlr->crcs++; ! 153: break; ! 154: } ! 155: } ! 156: else { ! 157: /* ! 158: * We have a packet. Read it into the next ! 159: * free ring buffer, if any. ! 160: * The CRC is already stripped off. ! 161: */ ! 162: rb = &ctlr->rb[ctlr->ri]; ! 163: if(rb->owner == Interface){ ! 164: len = (status & RxByteMask); ! 165: rb->len = len; ! 166: ! 167: /* ! 168: * Must read len bytes padded to a ! 169: * doubleword. We can pick them out 32-bits ! 170: * at a time . ! 171: */ ! 172: insl(port+Fifo, rb->pkt, HOWMANY(len, 4)); ! 173: ! 174: /* ! 175: * Update the ring. ! 176: */ ! 177: rb->owner = Host; ! 178: ctlr->ri = NEXT(ctlr->ri, ctlr->nrb); ! 179: } ! 180: } ! 181: ! 182: /* ! 183: * Discard the packet as we're done with it. ! 184: * Wait for discard to complete. ! 185: */ ! 186: COMMAND(port, RxDiscard, 0); ! 187: while(ins(port+Status) & CmdInProgress) ! 188: ; ! 189: } ! 190: } ! 191: ! 192: static void ! 193: transmit(Ctlr *ctlr) ! 194: { ! 195: RingBuf *tb; ! 196: ushort len; ! 197: ulong port; ! 198: ! 199: port = ctlr->card.port; ! 200: for(tb = &ctlr->tb[ctlr->ti]; tb->owner == Interface; tb = &ctlr->tb[ctlr->ti]){ ! 201: /* ! 202: * If there's no room in the FIFO for this packet, ! 203: * set up an interrupt for when space becomes available. ! 204: * Output packet must be a multiple of 4 in length and ! 205: * we need 4 bytes for the preamble. ! 206: */ ! 207: len = ROUNDUP(tb->len, 4); ! 208: if(len+4 > ins(port+TxFreeBytes)){ ! 209: COMMAND(port, SetTxAvailable, len); ! 210: break; ! 211: } ! 212: ! 213: /* ! 214: * There's room, copy the packet to the FIFO and free ! 215: * the buffer back to the host. ! 216: */ ! 217: outs(port+Fifo, tb->len); ! 218: outs(port+Fifo, 0); ! 219: outsl(port+Fifo, tb->pkt, len/4); ! 220: tb->owner = Host; ! 221: ctlr->ti = NEXT(ctlr->ti, ctlr->ntb); ! 222: } ! 223: } ! 224: ! 225: static ushort ! 226: getdiag(Ctlr *ctlr) ! 227: { ! 228: ushort bytes; ! 229: ulong port; ! 230: ! 231: port = ctlr->card.port; ! 232: COMMAND(port, SelectWindow, 4); ! 233: bytes = ins(port+FIFOdiag); ! 234: COMMAND(port, SelectWindow, 1); ! 235: return bytes & 0xFFFF; ! 236: } ! 237: ! 238: static void ! 239: interrupt(Ureg*, Ctlr *ctlr) ! 240: { ! 241: ushort status, diag; ! 242: uchar txstatus, x; ! 243: ulong port; ! 244: ! 245: port = ctlr->card.port; ! 246: status = ins(port+Status); ! 247: ! 248: if(status & Failure){ ! 249: /* ! 250: * Adapter failure, try to find out why. ! 251: * Reset if necessary. ! 252: * What happens if Tx is active and we reset, ! 253: * need to retransmit? ! 254: * This probably isn't right. ! 255: */ ! 256: diag = getdiag(ctlr); ! 257: print("ether%d: status #%ux, diag #%ux\n", ctlr->ctlrno, status, diag); ! 258: ! 259: if(diag & TxOverrun){ ! 260: COMMAND(port, TxReset, 0); ! 261: COMMAND(port, TxEnable, 0); ! 262: } ! 263: ! 264: if(diag & RxUnderrun){ ! 265: COMMAND(port, RxReset, 0); ! 266: attach(ctlr); ! 267: } ! 268: ! 269: if(diag & TxOverrun) ! 270: transmit(ctlr); ! 271: ! 272: return; ! 273: } ! 274: ! 275: if(status & RxComplete){ ! 276: receive(ctlr); ! 277: status &= ~RxComplete; ! 278: } ! 279: ! 280: if(status & TxComplete){ ! 281: /* ! 282: * Pop the TX Status stack, accumulating errors. ! 283: * If there was a Jabber or Underrun error, reset ! 284: * the transmitter. For all conditions enable ! 285: * the transmitter. ! 286: */ ! 287: txstatus = 0; ! 288: do{ ! 289: if(x = inb(port+TxStatus)) ! 290: outb(port+TxStatus, 0); ! 291: txstatus |= x; ! 292: }while(ins(port+Status) & TxComplete); ! 293: ! 294: if(txstatus & (TxJabber|TxUnderrun)) ! 295: COMMAND(port, TxReset, 0); ! 296: COMMAND(port, TxEnable, 0); ! 297: ctlr->oerrs++; ! 298: } ! 299: ! 300: if(status & (TxAvailable|TxComplete)){ ! 301: /* ! 302: * Reset the Tx FIFO threshold. ! 303: */ ! 304: if(status & TxAvailable) ! 305: COMMAND(port, AckIntr, TxAvailable); ! 306: transmit(ctlr); ! 307: status &= ~(TxAvailable|TxComplete); ! 308: } ! 309: ! 310: /* ! 311: * Panic if there are any interrupt bits on we haven't ! 312: * dealt with other than Latch. ! 313: * Otherwise, acknowledge the interrupt. ! 314: */ ! 315: if(status & AllIntr) ! 316: panic("ether%d interrupt: #%lux, #%ux\n", ! 317: ctlr->ctlrno, status, getdiag(ctlr)); ! 318: ! 319: COMMAND(port, AckIntr, Latch); ! 320: } ! 321: ! 322: typedef struct Adapter Adapter; ! 323: struct Adapter { ! 324: Adapter *next; ! 325: ulong port; ! 326: }; ! 327: static Adapter *adapter; ! 328: ! 329: /* ! 330: * Write two 0 bytes to identify the IDport and then reset the ! 331: * ID sequence. Then send the ID sequence to the card to get ! 332: * the card into command state. ! 333: */ ! 334: static void ! 335: idseq(void) ! 336: { ! 337: int i; ! 338: uchar al; ! 339: ! 340: outb(IDport, 0); ! 341: outb(IDport, 0); ! 342: for(al = 0xFF, i = 0; i < 255; i++){ ! 343: outb(IDport, al); ! 344: if(al & 0x80){ ! 345: al <<= 1; ! 346: al ^= 0xCF; ! 347: } ! 348: else ! 349: al <<= 1; ! 350: } ! 351: } ! 352: ! 353: static ulong ! 354: activate(int tag) ! 355: { ! 356: int i; ! 357: ushort x, acr; ! 358: ulong port; ! 359: ! 360: /* ! 361: * Do the little configuration dance: ! 362: * ! 363: * 2. write the ID sequence to get to command state. ! 364: */ ! 365: idseq(); ! 366: ! 367: /* ! 368: * 3. Read the Manufacturer ID from the EEPROM. ! 369: * This is done by writing the IDPort with 0x87 (0x80 ! 370: * is the 'read EEPROM' command, 0x07 is the offset of ! 371: * the Manufacturer ID field in the EEPROM). ! 372: * The data comes back 1 bit at a time. ! 373: * We seem to need a delay here between reading the bits. ! 374: * ! 375: * If the ID doesn't match, there are no more adapters. ! 376: */ ! 377: outb(IDport, 0x87); ! 378: for(x = 0, i = 0; i < 16; i++){ ! 379: delay(5); ! 380: x <<= 1; ! 381: x |= inb(IDport) & 0x01; ! 382: } ! 383: if(x != 0x6D50) ! 384: return 0; ! 385: ! 386: /* ! 387: * 3. Read the Address Configuration from the EEPROM. ! 388: * The Address Configuration field is at offset 0x08 in the EEPROM). ! 389: */ ! 390: outb(IDport, 0x88); ! 391: for(acr = 0, i = 0; i < 16; i++){ ! 392: delay(20); ! 393: acr <<= 1; ! 394: acr |= inb(IDport) & 0x01; ! 395: } ! 396: port = (acr & 0x1F)*0x10 + 0x200; ! 397: ! 398: if(tag){ ! 399: /* ! 400: * 6. Tag the adapter so it won't respond in future. ! 401: * 6. Activate the adapter by writing the Activate command ! 402: * (0xFF). ! 403: */ ! 404: outb(IDport, 0xD1); ! 405: outb(IDport, 0xFF); ! 406: ! 407: /* ! 408: * 8. Now we can talk to the adapter's I/O base addresses. ! 409: * We get the I/O base address from the acr just read. ! 410: * ! 411: * Enable the adapter. ! 412: */ ! 413: outs(port+ConfigControl, Ena); ! 414: } ! 415: ! 416: return port; ! 417: } ! 418: ! 419: static ulong ! 420: tcm509(ISAConf *isa) ! 421: { ! 422: static int untag; ! 423: ulong port; ! 424: Adapter *ap; ! 425: ! 426: /* ! 427: * One time only: ! 428: * write ID sequence to get the attention of all adapters; ! 429: * untag all adapters. ! 430: * If we do a global reset here on all adapters we'll confuse any ! 431: * ISA cards configured for EISA mode. ! 432: */ ! 433: if(untag == 0){ ! 434: idseq(); ! 435: outb(IDport, 0xD0); ! 436: untag = 1; ! 437: } ! 438: ! 439: /* ! 440: * Attempt to activate adapters until one matches our ! 441: * address criteria. If adapter is set for EISA mode, ! 442: * tag it and ignore. Otherwise, reset the adapter and ! 443: * activate it fully. ! 444: */ ! 445: while(port = activate(0)){ ! 446: if(port == 0x3F0){ ! 447: outb(IDport, 0xD1); ! 448: continue; ! 449: } ! 450: outb(IDport, 0xC0); ! 451: delay(2); ! 452: if(activate(1) != port) ! 453: print("tcm509: activate\n"); ! 454: ! 455: if(isa->port == 0 || isa->port == port) ! 456: return port; ! 457: ! 458: ap = ialloc(sizeof(Adapter), 0); ! 459: ap->port = port; ! 460: ap->next = adapter; ! 461: adapter = ap; ! 462: } ! 463: ! 464: return 0; ! 465: } ! 466: ! 467: static ulong ! 468: tcm579(ISAConf *isa) ! 469: { ! 470: static int slot = 1; ! 471: ushort x; ! 472: ulong port; ! 473: Adapter *ap; ! 474: ! 475: /* ! 476: * First time through, check if this is an EISA machine. ! 477: * If not, nothing to do. ! 478: */ ! 479: if(slot == 1 && strncmp((char*)(KZERO|0xFFFD9), "EISA", 4)) ! 480: return 0; ! 481: ! 482: /* ! 483: * Continue through the EISA slots looking for a match on both ! 484: * 3COM as the manufacturer and 3C579 or 3C579-TP as the product. ! 485: * If we find an adapter, select window 0, enable it and clear ! 486: * out any lingering status and interrupts. ! 487: * Trying to do a GlobalReset here to re-init the card (as in the ! 488: * 509 code) doesn't seem to work. ! 489: */ ! 490: while(slot < MaxEISA){ ! 491: port = slot++*0x1000; ! 492: if(ins(port+EISAconfig+ManufacturerID) != 0x6D50) ! 493: continue; ! 494: x = ins(port+EISAconfig+ProductID); ! 495: if((x & 0xF0FF) != 0x9050/* || (x != 0x9350 && x != 0x9250)*/) ! 496: continue; ! 497: ! 498: COMMAND(port, SelectWindow, 0); ! 499: outs(port+ConfigControl, Ena); ! 500: ! 501: COMMAND(port, TxReset, 0); ! 502: COMMAND(port, RxReset, 0); ! 503: COMMAND(port, AckIntr, 0xFF); ! 504: ! 505: if(isa->port == 0 || isa->port == port) ! 506: return port; ! 507: ! 508: ap = ialloc(sizeof(Adapter), 0); ! 509: ap->port = port; ! 510: ap->next = adapter; ! 511: adapter = ap; ! 512: } ! 513: ! 514: return 0; ! 515: } ! 516: ! 517: static ulong ! 518: tcm589(ISAConf*) ! 519: { ! 520: return 0; ! 521: } ! 522: ! 523: /* ! 524: * Get configuration parameters. ! 525: */ ! 526: int ! 527: tcm509reset(Ctlr *ctlr) ! 528: { ! 529: int i, eax; ! 530: uchar ea[Eaddrlen]; ! 531: ushort x, acr; ! 532: ulong port; ! 533: Adapter *ap, **app; ! 534: ! 535: /* ! 536: * Any adapter matches if no port is supplied, ! 537: * otherwise the ports must match. ! 538: * See if we've already found an adapter that fits ! 539: * the bill. ! 540: * If no match then try for an EISA card, an ISA card ! 541: * and finally for a PCMCIA card. ! 542: */ ! 543: port = 0; ! 544: for(app = &adapter, ap = *app; ap; app = &ap->next, ap = ap->next){ ! 545: if(ctlr->card.port == 0 || ctlr->card.port == ap->port){ ! 546: port = ap->port; ! 547: *app = ap->next; ! 548: /*free(ap);lost*/ ! 549: break; ! 550: } ! 551: } ! 552: if(port == 0) ! 553: port = tcm579(&ctlr->card); ! 554: if(port == 0) ! 555: port = tcm509(&ctlr->card); ! 556: if(port == 0) ! 557: port = tcm589(&ctlr->card); ! 558: if(port == 0) ! 559: return -1; ! 560: ! 561: /* ! 562: * Read the IRQ from the Resource Configuration Register, ! 563: * the ethernet address from the EEPROM, and the address configuration. ! 564: * The EEPROM command is 8 bits, the lower 6 bits being ! 565: * the address offset. ! 566: */ ! 567: ctlr->card.irq = (ins(port+ResourceConfig)>>12) & 0x0F; ! 568: for(eax = 0, i = 0; i < 3; i++, eax += 2){ ! 569: while(ins(port+EEPROMcmd) & 0x8000) ! 570: ; ! 571: outs(port+EEPROMcmd, (2<<6)|i); ! 572: while(ins(port+EEPROMcmd) & 0x8000) ! 573: ; ! 574: x = ins(port+EEPROMdata); ! 575: ea[eax] = (x>>8) & 0xFF; ! 576: ea[eax+1] = x & 0xFF; ! 577: } ! 578: acr = ins(port+AddressConfig); ! 579: ! 580: /* ! 581: * Finished with window 0. Now set the ethernet address ! 582: * in window 2. ! 583: * CommandRs have the format 'CCCCCAAAAAAAAAAA' where C ! 584: * is a bit in the command and A is a bit in the argument. ! 585: */ ! 586: if((ctlr->card.ea[0]|ctlr->card.ea[1]|ctlr->card.ea[2]|ctlr->card.ea[3]|ctlr->card.ea[4]|ctlr->card.ea[5]) == 0) ! 587: memmove(ctlr->card.ea, ea, Eaddrlen); ! 588: COMMAND(port, SelectWindow, 2); ! 589: for(i = 0; i < Eaddrlen; i++) ! 590: outb(port+i, ctlr->card.ea[i]); ! 591: ! 592: /* ! 593: * Enable the transceiver if necessary. ! 594: */ ! 595: switch(acr & XcvrTypeMask){ ! 596: ! 597: case Xcvr10BaseT: ! 598: /* ! 599: * Enable Link Beat and Jabber to start the ! 600: * transceiver. ! 601: */ ! 602: COMMAND(port, SelectWindow, 4); ! 603: outb(port+MediaStatus, LinkBeatEna|JabberEna); ! 604: break; ! 605: ! 606: case XcvrBNC: ! 607: /* ! 608: * Start the DC-DC converter. ! 609: * Wait > 800 microseconds. ! 610: */ ! 611: COMMAND(port, StartCoax, 0); ! 612: delay(1); ! 613: break; ! 614: } ! 615: ! 616: /* ! 617: * Set window 1 for normal operation. ! 618: * Clear out any lingering Tx status. ! 619: */ ! 620: COMMAND(port, SelectWindow, 1); ! 621: while(inb(port+TxStatus)) ! 622: outb(port+TxStatus, 0); ! 623: ! 624: ctlr->card.port = port; ! 625: ! 626: /* ! 627: * Set up the software configuration. ! 628: */ ! 629: ctlr->card.reset = tcm509reset; ! 630: ctlr->card.attach = attach; ! 631: ctlr->card.transmit = transmit; ! 632: ctlr->card.intr = interrupt; ! 633: ctlr->card.bit16 = 1; ! 634: ! 635: return 0; ! 636: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.