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