|
|
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.