]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/etherelnk3.c
pc, pc64: more conservative pcirouting
[plan9front.git] / sys / src / 9 / pc / etherelnk3.c
1 /*
2  * Etherlink III, Fast EtherLink and Fast EtherLink XL adapters.
3  * To do:
4  *      check robustness in the face of errors (e.g. busmaster & rxUnderrun);
5  *      RxEarly and busmaster;
6  *      autoSelect;
7  *      PCI latency timer and master enable;
8  *      errata list;
9  *      rewrite all initialisation.
10  */
11 #include "u.h"
12 #include "../port/lib.h"
13 #include "mem.h"
14 #include "dat.h"
15 #include "fns.h"
16 #include "io.h"
17 #include "../port/error.h"
18 #include "../port/netif.h"
19
20 #include "etherif.h"
21
22 #define XCVRDEBUG               if(0)print
23
24 enum {
25         IDport                  = 0x0110,       /* anywhere between 0x0100 and 0x01F0 */
26 };
27
28 enum {                                          /* all windows */
29         CommandR                = 0x000E,
30         IntStatusR              = 0x000E,
31 };
32
33 enum {                                          /* Commands */
34         GlobalReset             = 0x0000,
35         SelectRegisterWindow    = 0x0001,
36         EnableDcConverter       = 0x0002,
37         RxDisable               = 0x0003,
38         RxEnable                = 0x0004,
39         RxReset                 = 0x0005,
40         Stall                   = 0x0006,       /* 3C90x */
41         TxDone                  = 0x0007,
42         RxDiscard               = 0x0008,
43         TxEnable                = 0x0009,
44         TxDisable               = 0x000A,
45         TxReset                 = 0x000B,
46         RequestInterrupt        = 0x000C,
47         AcknowledgeInterrupt    = 0x000D,
48         SetInterruptEnable      = 0x000E,
49         SetIndicationEnable     = 0x000F,       /* SetReadZeroMask */
50         SetRxFilter             = 0x0010,
51         SetRxEarlyThresh        = 0x0011,
52         SetTxAvailableThresh    = 0x0012,
53         SetTxStartThresh        = 0x0013,
54         StartDma                = 0x0014,       /* initiate busmaster operation */
55         StatisticsEnable        = 0x0015,
56         StatisticsDisable       = 0x0016,
57         DisableDcConverter      = 0x0017,
58         SetTxReclaimThresh      = 0x0018,       /* PIO-only adapters */
59         PowerUp                 = 0x001B,       /* not all adapters */
60         PowerDownFull           = 0x001C,       /* not all adapters */
61         PowerAuto               = 0x001D,       /* not all adapters */
62 };
63
64 enum {                                          /* (Global|Rx|Tx)Reset command bits */
65         tpAuiReset              = 0x0001,       /* 10BaseT and AUI transceivers */
66         endecReset              = 0x0002,       /* internal Ethernet encoder/decoder */
67         networkReset            = 0x0004,       /* network interface logic */
68         fifoReset               = 0x0008,       /* FIFO control logic */
69         aismReset               = 0x0010,       /* autoinitialise state-machine logic */
70         hostReset               = 0x0020,       /* bus interface logic */
71         dmaReset                = 0x0040,       /* bus master logic */
72         vcoReset                = 0x0080,       /* on-board 10Mbps VCO */
73         updnReset               = 0x0100,       /* upload/download (Rx/TX) logic */
74
75         resetMask               = 0x01FF,
76 };
77
78 enum {                                          /* Stall command bits */
79         upStall                 = 0x0000,
80         upUnStall               = 0x0001,
81         dnStall                 = 0x0002,
82         dnUnStall               = 0x0003,
83 };
84
85 enum {                                          /* SetRxFilter command bits */
86         receiveIndividual       = 0x0001,       /* match station address */
87         receiveMulticast        = 0x0002,
88         receiveBroadcast        = 0x0004,
89         receiveAllFrames        = 0x0008,       /* promiscuous */
90 };
91
92 enum {                                          /* StartDma command bits */
93         Upload                  = 0x0000,       /* transfer data from adapter to memory */
94         Download                = 0x0001,       /* transfer data from memory to adapter */
95 };
96
97 enum {                                          /* IntStatus bits */
98         interruptLatch          = 0x0001,
99         hostError               = 0x0002,       /* Adapter Failure */
100         txComplete              = 0x0004,
101         txAvailable             = 0x0008,
102         rxComplete              = 0x0010,
103         rxEarly                 = 0x0020,
104         intRequested            = 0x0040,
105         updateStats             = 0x0080,
106         transferInt             = 0x0100,       /* Bus Master Transfer Complete */
107         dnComplete              = 0x0200,
108         upComplete              = 0x0400,
109         busMasterInProgress     = 0x0800,
110         commandInProgress       = 0x1000,
111
112         interruptMask           = 0x07FE,
113 };
114
115 #define COMMAND(port, cmd, a)   outs((port)+CommandR, ((cmd)<<11)|(a))
116 #define STATUS(port)            ins((port)+IntStatusR)
117
118 enum {                                          /* Window 0 - setup */
119         Wsetup                  = 0x0000,
120                                                 /* registers */
121         ManufacturerID          = 0x0000,       /* 3C5[08]*, 3C59[27] */
122         ProductID               = 0x0002,       /* 3C5[08]*, 3C59[27] */
123         ConfigControl           = 0x0004,       /* 3C5[08]*, 3C59[27] */
124         AddressConfig           = 0x0006,       /* 3C5[08]*, 3C59[27] */
125         ResourceConfig          = 0x0008,       /* 3C5[08]*, 3C59[27] */
126         EepromCommand           = 0x000A,
127         EepromData              = 0x000C,
128                                                 /* AddressConfig Bits */
129         autoSelect9             = 0x0080,
130         xcvrMask9               = 0xC000,
131                                                 /* ConfigControl bits */
132         Ena                     = 0x0001,
133         base10TAvailable9       = 0x0200,
134         coaxAvailable9          = 0x1000,
135         auiAvailable9           = 0x2000,
136                                                 /* EepromCommand bits */
137         EepromReadRegister      = 0x0080,
138         EepromReadOffRegister   = 0x00B0,
139         EepromRead8bRegister    = 0x0230,
140         EepromBusy              = 0x8000,
141 };
142
143 #define EEPROMCMD(port, cmd, a) outs((port)+EepromCommand, (cmd)|(a))
144 #define EEPROMBUSY(port)        (ins((port)+EepromCommand) & EepromBusy)
145 #define EEPROMDATA(port)        ins((port)+EepromData)
146
147 enum {                                          /* Window 1 - operating set */
148         Wop                     = 0x0001,
149                                                 /* registers */
150         Fifo                    = 0x0000,
151         RxError                 = 0x0004,       /* 3C59[0257] only */
152         RxStatus                = 0x0008,
153         TIMER                   = 0x000A,
154         TxStatus                = 0x000B,
155         TxFree                  = 0x000C,
156                                                 /* RxError bits */
157         rxOverrun               = 0x0001,
158         runtFrame               = 0x0002,
159         alignmentError          = 0x0004,       /* Framing */
160         crcError                = 0x0008,
161         oversizedFrame          = 0x0010,
162         dribbleBits             = 0x0080,
163                                                 /* RxStatus bits */
164         rxBytes                 = 0x1FFF,       /* 3C59[0257] mask */
165         rxBytes9                = 0x07FF,       /* 3C5[078]9 mask */
166         rxError9                = 0x3800,       /* 3C5[078]9 error mask */
167         rxOverrun9              = 0x0000,
168         oversizedFrame9         = 0x0800,
169         dribbleBits9            = 0x1000,
170         runtFrame9              = 0x1800,
171         alignmentError9         = 0x2000,       /* Framing */
172         crcError9               = 0x2800,
173         rxError                 = 0x4000,
174         rxIncomplete            = 0x8000,
175                                                 /* TxStatus Bits */
176         txStatusOverflow        = 0x0004,
177         maxCollisions           = 0x0008,
178         txUnderrun              = 0x0010,
179         txJabber                = 0x0020,
180         interruptRequested      = 0x0040,
181         txStatusComplete        = 0x0080,
182 };
183
184 enum {                                          /* Window 2 - station address */
185         Wstation                = 0x0002,
186
187         ResetOp905B             = 0x000C,
188 };
189
190 enum {                                          /* Window 3 - FIFO management */
191         Wfifo                   = 0x0003,
192                                                 /* registers */
193         InternalConfig          = 0x0000,       /* 3C509B, 3C589, 3C59[0257] */
194         OtherInt                = 0x0004,       /* 3C59[0257] */
195         RomControl              = 0x0006,       /* 3C509B, 3C59[27] */
196         MacControl              = 0x0006,       /* 3C59[0257] */
197         ResetOptions            = 0x0008,       /* 3C59[0257] */
198         MediaOptions            = 0x0008,       /* 3C905B */
199         RxFree                  = 0x000A,
200                                                 /* InternalConfig bits */
201         disableBadSsdDetect     = 0x00000100,
202         ramLocation             = 0x00000200,   /* 0 external, 1 internal */
203         ramPartition5to3        = 0x00000000,
204         ramPartition3to1        = 0x00010000,
205         ramPartition1to1        = 0x00020000,
206         ramPartition3to5        = 0x00030000,
207         ramPartitionMask        = 0x00030000,
208         xcvr10BaseT             = 0x00000000,
209         xcvrAui                 = 0x00100000,   /* 10BASE5 */
210         xcvr10Base2             = 0x00300000,
211         xcvr100BaseTX           = 0x00400000,
212         xcvr100BaseFX           = 0x00500000,
213         xcvrMii                 = 0x00600000,
214         xcvrMask                = 0x00700000,
215         autoSelect              = 0x01000000,
216                                                 /* MacControl bits */
217         deferExtendEnable       = 0x0001,
218         deferTIMERSelect        = 0x001E,       /* mask */
219         fullDuplexEnable        = 0x0020,
220         allowLargePackets       = 0x0040,
221         extendAfterCollision    = 0x0080,       /* 3C90xB */
222         flowControlEnable       = 0x0100,       /* 3C90xB */
223         vltEnable               = 0x0200,       /* 3C90xB */
224                                                 /* ResetOptions bits */
225         baseT4Available         = 0x0001,
226         baseTXAvailable         = 0x0002,
227         baseFXAvailable         = 0x0004,
228         base10TAvailable        = 0x0008,
229         coaxAvailable           = 0x0010,
230         auiAvailable            = 0x0020,
231         miiConnector            = 0x0040,
232 };
233
234 enum {                                          /* Window 4 - diagnostic */
235         Wdiagnostic             = 0x0004,
236                                                 /* registers */
237         VcoDiagnostic           = 0x0002,
238         FifoDiagnostic          = 0x0004,
239         NetworkDiagnostic       = 0x0006,
240         PhysicalMgmt            = 0x0008,
241         MediaStatus             = 0x000A,
242         BadSSD                  = 0x000C,
243         UpperBytesOk            = 0x000D,
244                                                 /* FifoDiagnostic bits */
245         txOverrun               = 0x0400,
246         rxUnderrun              = 0x2000,
247         receiving               = 0x8000,
248                                                 /* PhysicalMgmt bits */
249         mgmtClk                 = 0x0001,
250         mgmtData                = 0x0002,
251         mgmtDir                 = 0x0004,
252         cat5LinkTestDefeat      = 0x8000,
253                                                 /* MediaStatus bits */
254         dataRate100             = 0x0002,
255         crcStripDisable         = 0x0004,
256         enableSqeStats          = 0x0008,
257         collisionDetect         = 0x0010,
258         carrierSense            = 0x0020,
259         jabberGuardEnable       = 0x0040,
260         linkBeatEnable          = 0x0080,
261         jabberDetect            = 0x0200,
262         polarityReversed        = 0x0400,
263         linkBeatDetect          = 0x0800,
264         txInProg                = 0x1000,
265         dcConverterEnabled      = 0x4000,
266         auiDisable              = 0x8000,       /* 10BaseT transceiver selected */
267 };
268
269 enum {                                          /* Window 5 - internal state */
270         Wstate                  = 0x0005,
271                                                 /* registers */
272         TxStartThresh           = 0x0000,
273         TxAvailableThresh       = 0x0002,
274         RxEarlyThresh           = 0x0006,
275         RxFilter                = 0x0008,
276         InterruptEnable         = 0x000A,
277         IndicationEnable        = 0x000C,
278 };
279
280 enum {                                          /* Window 6 - statistics */
281         Wstatistics             = 0x0006,
282                                                 /* registers */
283         CarrierLost             = 0x0000,
284         SqeErrors               = 0x0001,
285         MultipleColls           = 0x0002,
286         SingleCollFrames        = 0x0003,
287         LateCollisions          = 0x0004,
288         RxOverruns              = 0x0005,
289         FramesXmittedOk         = 0x0006,
290         FramesRcvdOk            = 0x0007,
291         FramesDeferred          = 0x0008,
292         UpperFramesOk           = 0x0009,
293         BytesRcvdOk             = 0x000A,
294         BytesXmittedOk          = 0x000C,
295 };
296
297 enum {                                          /* Window 7 - bus master operations */
298         Wmaster                 = 0x0007,
299                                                 /* registers */
300         MasterAddress           = 0x0000,
301         MasterLen               = 0x0006,
302         MasterStatus            = 0x000C,
303                                                 /* MasterStatus bits */
304         masterAbort             = 0x0001,
305         targetAbort             = 0x0002,
306         targetRetry             = 0x0004,
307         targetDisc              = 0x0008,
308         masterDownload          = 0x1000,
309         masterUpload            = 0x4000,
310         masterInProgress        = 0x8000,
311
312         masterMask              = 0xD00F,
313 };
314
315 enum {                                          /* 3C90x extended register set */
316         TIMER905                = 0x001A,       /* 8-bits */
317         TxStatus905             = 0x001B,       /* 8-bits */
318         PktStatus               = 0x0020,       /* 32-bits */
319         DnListPtr               = 0x0024,       /* 32-bits, 8-byte aligned */
320         FragAddr                = 0x0028,       /* 32-bits */
321         FragLen                 = 0x002C,       /* 16-bits */
322         ListOffset              = 0x002E,       /* 8-bits */
323         TxFreeThresh            = 0x002F,       /* 8-bits */
324         UpPktStatus             = 0x0030,       /* 32-bits */
325         FreeTIMER               = 0x0034,       /* 16-bits */
326         UpListPtr               = 0x0038,       /* 32-bits, 8-byte aligned */
327
328                                                 /* PktStatus bits */
329         fragLast                = 0x00000001,
330         dnCmplReq               = 0x00000002,
331         dnStalled               = 0x00000004,
332         upCompleteX             = 0x00000008,
333         dnCompleteX             = 0x00000010,
334         upRxEarlyEnable         = 0x00000020,
335         armCountdown            = 0x00000040,
336         dnInProg                = 0x00000080,
337         counterSpeed            = 0x00000010,   /* 0 3.2uS, 1 320nS */
338         countdownMode           = 0x00000020,
339                                                 /* UpPktStatus bits (dpd->control) */
340         upPktLenMask            = 0x00001FFF,
341         upStalled               = 0x00002000,
342         upError                 = 0x00004000,
343         upPktComplete           = 0x00008000,
344         upOverrun               = 0x00010000,   /* RxError<<16 */
345         upRuntFrame             = 0x00020000,
346         upAlignmentError        = 0x00040000,
347         upCRCError              = 0x00080000,
348         upOversizedFrame        = 0x00100000,
349         upDribbleBits           = 0x00800000,
350         upOverflow              = 0x01000000,
351
352         dnIndicate              = 0x80000000,   /* FrameStartHeader (dpd->control) */
353
354         updnLastFrag            = 0x80000000,   /* (dpd->len) */
355
356         Nup                     = 32,
357         Ndn                     = 64,
358 };
359
360 /*
361  * Up/Dn Packet Descriptors.
362  * The hardware info (np, control, addr, len) must be 8-byte aligned
363  * and this structure size must be a multiple of 8.
364  */
365 typedef struct Pd Pd;
366 typedef struct Pd {
367         ulong   np;                     /* next pointer */
368         ulong   control;                /* FSH or UpPktStatus */
369         ulong   addr;
370         ulong   len;
371
372         Pd*     next;
373         Block*  bp;
374 } Pd;
375
376 typedef struct Ctlr Ctlr;
377 typedef struct Ctlr {
378         int     port;
379         Pcidev* pcidev;
380         int     irq;
381         Ctlr*   next;
382         int     active;
383         int     did;
384
385         Lock    wlock;                  /* window access */
386
387         int     attached;
388         int     busmaster;
389         Block*  rbp;                    /* receive buffer */
390
391         Block*  txbp;                   /* FIFO -based transmission */
392         int     txthreshold;
393         int     txbusy;
394
395         int     nup;                    /* full-busmaster -based reception */
396         void*   upbase;
397         Pd*     upr;
398         Pd*     uphead;
399
400         int     ndn;                    /* full-busmaster -based transmission */
401         void*   dnbase;
402         Pd*     dnr;
403         Pd*     dnhead;
404         Pd*     dntail;
405         int     dnq;
406
407         long    interrupts;             /* statistics */
408         long    bogusinterrupts;
409         long    timer[2];
410         long    stats[BytesRcvdOk+3];
411
412         int     upqmax;
413         int     upqmaxhw;
414         ulong   upinterrupts;
415         ulong   upqueued;
416         ulong   upstalls;
417         int     dnqmax;
418         int     dnqmaxhw;
419         ulong   dninterrupts;
420         ulong   dnqueued;
421
422         int     xcvr;                   /* transceiver type */
423         int     eepromcmd;              /* EEPROM read command */
424         int     rxstatus9;              /* old-style RxStatus register */
425         int     rxearly;                /* RxEarlyThreshold */
426         int     ts;                     /* threshold shift */
427         int     upenabled;
428         int     dnenabled;
429         ulong   cbfnpa;                 /* CardBus functions */
430         ulong*  cbfn;
431 } Ctlr;
432
433 static Ctlr* ctlrhead;
434 static Ctlr* ctlrtail;
435
436 static void
437 init905(Ctlr* ctlr)
438 {
439         Block *bp;
440         Pd *pd, *prev;
441
442         /*
443          * Create rings for the receive and transmit sides.
444          * Take care with alignment:
445          *      make sure ring base is 8-byte aligned;
446          *      make sure each entry is 8-byte aligned.
447          */
448         ctlr->upbase = malloc((ctlr->nup+1)*sizeof(Pd));
449         if(ctlr->upbase == nil)
450                 panic("etherlnk3: can't allocate upr");
451         ctlr->upr = (Pd*)ROUNDUP((ulong)ctlr->upbase, 8);
452
453         prev = ctlr->upr;
454         for(pd = &ctlr->upr[ctlr->nup-1]; pd >= ctlr->upr; pd--){
455                 pd->np = PADDR(&prev->np);
456                 pd->control = 0;
457                 bp = iallocb(sizeof(Etherpkt));
458                 if(bp == nil)
459                         panic("etherlnk3: iallocb: out of memory");
460                 pd->addr = PADDR(bp->rp);
461                 pd->len = updnLastFrag|sizeof(Etherpkt);
462
463                 pd->next = prev;
464                 prev = pd;
465                 pd->bp = bp;
466         }
467         ctlr->uphead = ctlr->upr;
468
469         ctlr->dnbase = malloc((ctlr->ndn+1)*sizeof(Pd));
470         if(ctlr->dnbase == nil)
471                 panic("etherlnk3: can't allocate dnr");
472         ctlr->dnr = (Pd*)ROUNDUP((ulong)ctlr->dnbase, 8);
473
474         prev = ctlr->dnr;
475         for(pd = &ctlr->dnr[ctlr->ndn-1]; pd >= ctlr->dnr; pd--){
476                 pd->next = prev;
477                 prev = pd;
478         }
479         ctlr->dnhead = ctlr->dnr;
480         ctlr->dntail = ctlr->dnr;
481         ctlr->dnq = 0;
482 }
483
484 static Block*
485 rbpalloc(Block* (*f)(int))
486 {
487         Block *bp;
488         ulong addr;
489
490         /*
491          * The receive buffers must be on a 32-byte
492          * boundary for EISA busmastering.
493          */
494         if(bp = f(ROUNDUP(sizeof(Etherpkt), 4) + 31)){
495                 addr = (ulong)bp->base;
496                 addr = ROUNDUP(addr, 32);
497                 bp->rp = (uchar*)addr;
498         }
499
500         return bp;
501 }
502
503 static uchar*
504 startdma(Ether* ether, ulong address)
505 {
506         int port, status, w;
507         uchar *wp;
508
509         port = ether->port;
510
511         w = (STATUS(port)>>13) & 0x07;
512         COMMAND(port, SelectRegisterWindow, Wmaster);
513
514         wp = KADDR(inl(port+MasterAddress));
515         status = ins(port+MasterStatus);
516         if(status & (masterInProgress|targetAbort|masterAbort))
517                 print("#l%d: BM status 0x%uX\n", ether->ctlrno, status);
518         outs(port+MasterStatus, masterMask);
519         outl(port+MasterAddress, address);
520         outs(port+MasterLen, sizeof(Etherpkt));
521         COMMAND(port, StartDma, Upload);
522
523         COMMAND(port, SelectRegisterWindow, w);
524         return wp;
525 }
526
527 static void
528 promiscuous(void* arg, int on)
529 {
530         int filter, port;
531         Ether *ether;
532
533         ether = (Ether*)arg;
534         port = ether->port;
535
536         filter = receiveBroadcast|receiveIndividual;
537         if(ether->nmaddr)
538                 filter |= receiveMulticast;
539         if(on)
540                 filter |= receiveAllFrames;
541         COMMAND(port, SetRxFilter, filter);
542 }
543
544 static void
545 multicast(void* arg, uchar *addr, int on)
546 {
547         int filter, port;
548         Ether *ether;
549
550         USED(addr, on);
551
552         ether = (Ether*)arg;
553         port = ether->port;
554
555         filter = receiveBroadcast|receiveIndividual;
556         if(ether->nmaddr)
557                 filter |= receiveMulticast;
558         if(ether->prom)
559                 filter |= receiveAllFrames;
560         COMMAND(port, SetRxFilter, filter);
561 }
562
563 /* On the 575B and C, interrupts need to be acknowledged in CardBus memory space */
564 static void
565 intrackcb(ulong *cbfn)
566 {
567         cbfn[1] = 0x8000;
568 }
569
570 static void
571 attach(Ether* ether)
572 {
573         int port, x;
574         Ctlr *ctlr;
575
576         ctlr = ether->ctlr;
577         ilock(&ctlr->wlock);
578         if(ctlr->attached){
579                 iunlock(&ctlr->wlock);
580                 return;
581         }
582
583         port = ether->port;
584
585         /*
586          * Set the receiver packet filter for this and broadcast addresses,
587          * set the interrupt masks for all interrupts, enable the receiver
588          * and transmitter.
589          */
590         promiscuous(ether, ether->prom);
591
592         x = interruptMask;
593         if(ctlr->busmaster == 1)
594                 x &= ~(rxEarly|rxComplete);
595         else{
596                 if(ctlr->dnenabled)
597                         x &= ~transferInt;
598                 if(ctlr->upenabled)
599                         x &= ~(rxEarly|rxComplete);
600         }
601         COMMAND(port, SetIndicationEnable, x);
602         COMMAND(port, SetInterruptEnable, x);
603         COMMAND(port, RxEnable, 0);
604         COMMAND(port, TxEnable, 0);
605
606         /*
607          * If this is a CardBus card, acknowledge any interrupts.
608          */
609         if(ctlr->cbfn != nil)
610                 intrackcb(ctlr->cbfn);
611                 
612         /*
613          * Prime the busmaster channel for receiving directly into a
614          * receive packet buffer if necessary.
615          */
616         if(ctlr->busmaster == 1)
617                 startdma(ether, PADDR(ctlr->rbp->rp));
618         else{
619                 if(ctlr->upenabled)
620                         outl(port+UpListPtr, PADDR(&ctlr->uphead->np));
621         }
622
623         ctlr->attached = 1;
624         iunlock(&ctlr->wlock);
625 }
626
627 static void
628 statistics(Ether* ether)
629 {
630         int port, i, u, w;
631         Ctlr *ctlr;
632
633         port = ether->port;
634         ctlr = ether->ctlr;
635
636         /*
637          * 3C59[27] require a read between a PIO write and
638          * reading a statistics register.
639          */
640         w = (STATUS(port)>>13) & 0x07;
641         COMMAND(port, SelectRegisterWindow, Wstatistics);
642         STATUS(port);
643
644         for(i = 0; i < UpperFramesOk; i++)
645                 ctlr->stats[i] += inb(port+i) & 0xFF;
646         u = inb(port+UpperFramesOk) & 0xFF;
647         ctlr->stats[FramesXmittedOk] += (u & 0x30)<<4;
648         ctlr->stats[FramesRcvdOk] += (u & 0x03)<<8;
649         ctlr->stats[BytesRcvdOk] += ins(port+BytesRcvdOk) & 0xFFFF;
650         ctlr->stats[BytesRcvdOk+1] += ins(port+BytesXmittedOk) & 0xFFFF;
651
652         switch(ctlr->xcvr){
653
654         case xcvrMii:
655         case xcvr100BaseTX:
656         case xcvr100BaseFX:
657                 COMMAND(port, SelectRegisterWindow, Wdiagnostic);
658                 STATUS(port);
659                 ctlr->stats[BytesRcvdOk+2] += inb(port+BadSSD);
660                 break;
661         }
662
663         COMMAND(port, SelectRegisterWindow, w);
664 }
665
666 static void
667 txstart(Ether* ether)
668 {
669         int port, len;
670         Ctlr *ctlr;
671         Block *bp;
672
673         port = ether->port;
674         ctlr = ether->ctlr;
675
676         /*
677          * Attempt to top-up the transmit FIFO. If there's room simply
678          * stuff in the packet length (unpadded to a dword boundary), the
679          * packet data (padded) and remove the packet from the queue.
680          * If there's no room post an interrupt for when there is.
681          * This routine is called both from the top level and from interrupt
682          * level and expects to be called with ctlr->wlock already locked
683          * and the correct register window (Wop) in place.
684          */
685         for(;;){
686                 if(ctlr->txbp){
687                         bp = ctlr->txbp;
688                         ctlr->txbp = 0;
689                 }
690                 else{
691                         bp = qget(ether->oq);
692                         if(bp == nil)
693                                 break;
694                 }
695
696                 len = ROUNDUP(BLEN(bp), 4);
697                 if(len+4 <= ins(port+TxFree)){
698                         outl(port+Fifo, BLEN(bp));
699                         outsl(port+Fifo, bp->rp, len/4);
700
701                         freeb(bp);
702
703                         ether->outpackets++;
704                 }
705                 else{
706                         ctlr->txbp = bp;
707                         if(ctlr->txbusy == 0){
708                                 ctlr->txbusy = 1;
709                                 COMMAND(port, SetTxAvailableThresh, len>>ctlr->ts);
710                         }
711                         break;
712                 }
713         }
714 }
715
716 static void
717 txstart905(Ether* ether)
718 {
719         Ctlr *ctlr;
720         int port, stalled, timeo;
721         Block *bp;
722         Pd *pd;
723
724         ctlr = ether->ctlr;
725         port = ether->port;
726
727         /*
728          * Free any completed packets.
729          */
730         pd = ctlr->dntail;
731         while(ctlr->dnq){
732                 if(PADDR(&pd->np) == inl(port+DnListPtr))
733                         break;
734                 if(pd->bp){
735                         freeb(pd->bp);
736                         pd->bp = nil;
737                 }
738                 ctlr->dnq--;
739                 pd = pd->next;
740         }
741         ctlr->dntail = pd;
742
743         stalled = 0;
744         while(ctlr->dnq < (ctlr->ndn-1)){
745                 bp = qget(ether->oq);
746                 if(bp == nil)
747                         break;
748
749                 pd = ctlr->dnhead->next;
750                 pd->np = 0;
751                 pd->control = dnIndicate|BLEN(bp);
752                 pd->addr = PADDR(bp->rp);
753                 pd->len = updnLastFrag|BLEN(bp);
754                 pd->bp = bp;
755
756                 if(stalled == 0 && ctlr->dnq && inl(port+DnListPtr)){
757                         COMMAND(port, Stall, dnStall);
758                         for(timeo = 100; (STATUS(port) & commandInProgress) && timeo; timeo--)
759                                 ;
760                         if(timeo == 0)
761                                 print("#l%d: dnstall %d\n", ether->ctlrno, timeo);
762                         stalled = 1;
763                 }
764
765                 coherence();
766                 ctlr->dnhead->np = PADDR(&pd->np);
767                 ctlr->dnhead->control &= ~dnIndicate;
768                 ctlr->dnhead = pd;
769                 if(ctlr->dnq == 0)
770                         ctlr->dntail = pd;
771                 ctlr->dnq++;
772
773                 ctlr->dnqueued++;
774         }
775
776         if(ctlr->dnq > ctlr->dnqmax)
777                 ctlr->dnqmax = ctlr->dnq;
778
779         /*
780          * If the adapter is not currently processing anything
781          * and there is something on the queue, start it processing.
782          */
783         if(inl(port+DnListPtr) == 0 && ctlr->dnq)
784                 outl(port+DnListPtr, PADDR(&ctlr->dnhead->np));
785         if(stalled)
786                 COMMAND(port, Stall, dnUnStall);
787 }
788
789 static void
790 transmit(Ether* ether)
791 {
792         Ctlr *ctlr;
793         int port, w;
794
795         port = ether->port;
796         ctlr = ether->ctlr;
797
798         ilock(&ctlr->wlock);
799         if(ctlr->dnenabled)
800                 txstart905(ether);
801         else{
802                 w = (STATUS(port)>>13) & 0x07;
803                 COMMAND(port, SelectRegisterWindow, Wop);
804                 txstart(ether);
805                 COMMAND(port, SelectRegisterWindow, w);
806         }
807         iunlock(&ctlr->wlock);
808 }
809
810 static void
811 receive905(Ether* ether)
812 {
813         Ctlr *ctlr;
814         int len, port, q;
815         Pd *pd;
816         Block *bp;
817
818         ctlr = ether->ctlr;
819         port = ether->port;
820
821         if(inl(port+UpPktStatus) & upStalled)
822                 ctlr->upstalls++;
823         q = 0;
824         for(pd = ctlr->uphead; pd->control & upPktComplete; pd = pd->next){
825                 if(pd->control & upError){
826                         if(pd->control & upOverrun)
827                                 ether->overflows++;
828                         if(pd->control & (upOversizedFrame|upRuntFrame))
829                                 ether->buffs++;
830                         if(pd->control & upAlignmentError)
831                                 ether->frames++;
832                         if(pd->control & upCRCError)
833                                 ether->crcs++;
834                 }
835                 else if(bp = iallocb(sizeof(Etherpkt)+4)){
836                         len = pd->control & rxBytes;
837                         pd->bp->wp = pd->bp->rp+len;
838                         etheriq(ether, pd->bp, 1);
839                         pd->bp = bp;
840                         pd->addr = PADDR(bp->rp);
841                         coherence();
842                 }
843
844                 pd->control = 0;
845                 COMMAND(port, Stall, upUnStall);
846
847                 q++;
848         }
849         ctlr->uphead = pd;
850
851         ctlr->upqueued += q;
852         if(q > ctlr->upqmax)
853                 ctlr->upqmax = q;
854 }
855
856 static void
857 receive(Ether* ether)
858 {
859         int len, port, rxerror, rxstatus;
860         Ctlr *ctlr;
861         Block *bp;
862
863         port = ether->port;
864         ctlr = ether->ctlr;
865
866         while(((rxstatus = ins(port+RxStatus)) & rxIncomplete) == 0){
867                 if(ctlr->busmaster == 1 && (STATUS(port) & busMasterInProgress))
868                         break;
869
870                 /*
871                  * If there was an error, log it and continue.
872                  * Unfortunately the 3C5[078]9 has the error info in the status register
873                  * and the 3C59[0257] implement a separate RxError register.
874                  */
875                 if(rxstatus & rxError){
876                         if(ctlr->rxstatus9){
877                                 switch(rxstatus & rxError9){
878
879                                 case rxOverrun9:
880                                         ether->overflows++;
881                                         break;
882
883                                 case oversizedFrame9:
884                                 case runtFrame9:
885                                         ether->buffs++;
886                                         break;
887
888                                 case alignmentError9:
889                                         ether->frames++;
890                                         break;
891
892                                 case crcError9:
893                                         ether->crcs++;
894                                         break;
895
896                                 }
897                         }
898                         else{
899                                 rxerror = inb(port+RxError);
900                                 if(rxerror & rxOverrun)
901                                         ether->overflows++;
902                                 if(rxerror & (oversizedFrame|runtFrame))
903                                         ether->buffs++;
904                                 if(rxerror & alignmentError)
905                                         ether->frames++;
906                                 if(rxerror & crcError)
907                                         ether->crcs++;
908                         }
909                 }
910
911                 /*
912                  * If there was an error or a new receive buffer can't be
913                  * allocated, discard the packet and go on to the next.
914                  */
915                 if((rxstatus & rxError) || (bp = rbpalloc(iallocb)) == 0){
916                         COMMAND(port, RxDiscard, 0);
917                         while(STATUS(port) & commandInProgress)
918                                 ;
919
920                         if(ctlr->busmaster == 1)
921                                 startdma(ether, PADDR(ctlr->rbp->rp));
922
923                         continue;
924                 }
925
926                 /*
927                  * A valid receive packet awaits:
928                  *      if using PIO, read it into the buffer;
929                  *      discard the packet from the FIFO;
930                  *      if using busmastering, start a new transfer for
931                  *        the next packet and as a side-effect get the
932                  *        end-pointer of the one just received;
933                  *      pass the packet on to whoever wants it.
934                  */
935                 if(ctlr->busmaster == 0 || ctlr->busmaster == 2){
936                         len = (rxstatus & rxBytes9);
937                         ctlr->rbp->wp = ctlr->rbp->rp + len;
938                         insl(port+Fifo, ctlr->rbp->rp, HOWMANY(len, 4));
939                 }
940
941                 COMMAND(port, RxDiscard, 0);
942                 while(STATUS(port) & commandInProgress)
943                         ;
944
945                 if(ctlr->busmaster == 1)
946                         ctlr->rbp->wp = startdma(ether, PADDR(bp->rp));
947
948                 etheriq(ether, ctlr->rbp, 1);
949                 ctlr->rbp = bp;
950         }
951 }
952
953 static int
954 ejectable(int did)
955 {
956         switch (did) {
957         case 0x5157:
958                 return 1;
959
960         default:
961                 return 0;
962         }
963 }
964
965 static void
966 interrupt(Ureg*, void* arg)
967 {
968         Ether *ether;
969         int port, status, s, txstatus, w, x;
970         Ctlr *ctlr;
971
972         ether = arg;
973         port = ether->port;
974         ctlr = ether->ctlr;
975
976         ilock(&ctlr->wlock);
977         status = STATUS(port);
978         if(!(status & (interruptMask|interruptLatch))){
979                 ctlr->bogusinterrupts++;
980                 iunlock(&ctlr->wlock);
981                 return;
982         }
983         w = (status>>13) & 0x07;
984         COMMAND(port, SelectRegisterWindow, Wop);
985
986         ctlr->interrupts++;
987         if(ctlr->busmaster == 2)
988                 ctlr->timer[0] += inb(port+TIMER905) & 0xFF;
989         else
990                 ctlr->timer[0] += inb(port+TIMER) & 0xFF;
991
992         do{
993                 if(status & hostError){
994                         /*
995                          * Adapter failure, try to find out why, reset if
996                          * necessary. What happens if Tx is active and a reset
997                          * occurs, need to retransmit? This probably isn't right.
998                          */
999                         COMMAND(port, SelectRegisterWindow, Wdiagnostic);
1000                         x = ins(port+FifoDiagnostic);
1001                         COMMAND(port, SelectRegisterWindow, Wop);
1002         
1003                         if (status == 0xFFFF && x == 0xFFFF && ejectable(ctlr->did)) {
1004                                 print("#l%d: Card ejected?\n", ether->ctlrno);
1005                                 iunlock(&ctlr->wlock);
1006                                 return;
1007                         }
1008
1009                         print("#l%d: status 0x%uX, diag 0x%uX\n",
1010                             ether->ctlrno, status, x);
1011
1012                         if(x & txOverrun){
1013                                 if(ctlr->busmaster == 0)
1014                                         COMMAND(port, TxReset, 0);
1015                                 else
1016                                         COMMAND(port, TxReset, (updnReset|dmaReset));
1017                                 COMMAND(port, TxEnable, 0);
1018                         }
1019
1020                         if(x & rxUnderrun){
1021                                 /*
1022                                  * This shouldn't happen...
1023                                  * Reset the receiver and restore the filter and RxEarly
1024                                  * threshold before re-enabling.
1025                                  * Need to restart any busmastering?
1026                                  */
1027                                 COMMAND(port, SelectRegisterWindow, Wstate);
1028                                 s = (port+RxFilter) & 0x000F;
1029                                 COMMAND(port, SelectRegisterWindow, Wop);
1030                                 COMMAND(port, RxReset, 0);
1031                                 while(STATUS(port) & commandInProgress)
1032                                         ;
1033                                 COMMAND(port, SetRxFilter, s);
1034                                 COMMAND(port, SetRxEarlyThresh, ctlr->rxearly>>ctlr->ts);
1035                                 COMMAND(port, RxEnable, 0);
1036                         }
1037
1038                         status &= ~hostError;
1039                 }
1040
1041                 if(status & (transferInt|rxComplete)){
1042                         receive(ether);
1043                         status &= ~(transferInt|rxComplete);
1044                 }
1045
1046                 if(status & (upComplete)){
1047                         COMMAND(port, AcknowledgeInterrupt, upComplete);
1048                         receive905(ether);
1049                         status &= ~upComplete;
1050                         ctlr->upinterrupts++;
1051                 }
1052
1053                 if(status & txComplete){
1054                         /*
1055                          * Pop the TxStatus stack, accumulating errors.
1056                          * Adjust the TX start threshold if there was an underrun.
1057                          * If there was a Jabber or Underrun error, reset
1058                          * the transmitter, taking care not to reset the dma logic
1059                          * as a busmaster receive may be in progress.
1060                          * For all conditions enable the transmitter.
1061                          */
1062                         if(ctlr->busmaster == 2)
1063                                 txstatus = port+TxStatus905;
1064                         else
1065                                 txstatus = port+TxStatus;
1066                         s = 0;
1067                         do{
1068                                 if(x = inb(txstatus))
1069                                         outb(txstatus, 0);
1070                                 s |= x;
1071                         }while(STATUS(port) & txComplete);
1072
1073                         if(s & txUnderrun){
1074                                 if(ctlr->dnenabled){
1075                                         while(inl(port+PktStatus) & dnInProg)
1076                                                 ;
1077                                 }
1078                                 COMMAND(port, SelectRegisterWindow, Wdiagnostic);
1079                                 while(ins(port+MediaStatus) & txInProg)
1080                                         ;
1081                                 COMMAND(port, SelectRegisterWindow, Wop);
1082                                 if(ctlr->txthreshold < ETHERMAXTU)
1083                                         ctlr->txthreshold += ETHERMINTU;
1084                         }
1085
1086                         /*
1087                          * According to the manual, maxCollisions does not require
1088                          * a TxReset, merely a TxEnable. However, evidence points to
1089                          * it being necessary on the 3C905. The jury is still out.
1090                          * On busy or badly configured networks maxCollisions can
1091                          * happen frequently enough for messages to be annoying so
1092                          * keep quiet about them by popular request.
1093                          */
1094                         if(s & (txJabber|txUnderrun|maxCollisions)){
1095                                 if(ctlr->busmaster == 0)
1096                                         COMMAND(port, TxReset, 0);
1097                                 else
1098                                         COMMAND(port, TxReset, (updnReset|dmaReset));
1099                                 while(STATUS(port) & commandInProgress)
1100                                         ;
1101                                 COMMAND(port, SetTxStartThresh, ctlr->txthreshold>>ctlr->ts);
1102                                 if(ctlr->busmaster == 2)
1103                                         outl(port+TxFreeThresh, HOWMANY(ETHERMAXTU, 256));
1104                                 if(ctlr->dnenabled)
1105                                         status |= dnComplete;
1106                         }
1107
1108                         if(s & ~(txStatusComplete|maxCollisions))
1109                                 print("#l%d: txstatus 0x%uX, threshold %d\n",
1110                                         ether->ctlrno, s, ctlr->txthreshold);
1111                         COMMAND(port, TxEnable, 0);
1112                         ether->oerrs++;
1113                         status &= ~txComplete;
1114                         status |= txAvailable;
1115                 }
1116
1117                 if(status & txAvailable){
1118                         COMMAND(port, AcknowledgeInterrupt, txAvailable);
1119                         ctlr->txbusy = 0;
1120                         txstart(ether);
1121                         status &= ~txAvailable;
1122                 }
1123
1124                 if(status & dnComplete){
1125                         COMMAND(port, AcknowledgeInterrupt, dnComplete);
1126                         txstart905(ether);
1127                         status &= ~dnComplete;
1128                         ctlr->dninterrupts++;
1129                 }
1130
1131                 if(status & updateStats){
1132                         statistics(ether);
1133                         status &= ~updateStats;
1134                 }
1135
1136                 /*
1137                  * Currently, this shouldn't happen.
1138                  */
1139                 if(status & rxEarly){
1140                         COMMAND(port, AcknowledgeInterrupt, rxEarly);
1141                         status &= ~rxEarly;
1142                 }
1143
1144                 /*
1145                  * Panic if there are any interrupts not dealt with.
1146                  */
1147                 if(status & interruptMask)
1148                         panic("#l%d: interrupt mask 0x%uX", ether->ctlrno, status);
1149
1150                 COMMAND(port, AcknowledgeInterrupt, interruptLatch);
1151                 if(ctlr->cbfn != nil)
1152                         intrackcb(ctlr->cbfn);
1153
1154         }while((status = STATUS(port)) & (interruptMask|interruptLatch));
1155
1156         if(ctlr->busmaster == 2)
1157                 ctlr->timer[1] += inb(port+TIMER905) & 0xFF;
1158         else
1159                 ctlr->timer[1] += inb(port+TIMER) & 0xFF;
1160
1161         COMMAND(port, SelectRegisterWindow, w);
1162         iunlock(&ctlr->wlock);
1163 }
1164
1165 static long
1166 ifstat(Ether* ether, void* a, long n, ulong offset)
1167 {
1168         char *p;
1169         int len;
1170         Ctlr *ctlr;
1171
1172         if(n == 0)
1173                 return 0;
1174
1175         ctlr = ether->ctlr;
1176
1177         ilock(&ctlr->wlock);
1178         statistics(ether);
1179         iunlock(&ctlr->wlock);
1180
1181         p = smalloc(READSTR);
1182         len = snprint(p, READSTR, "interrupts: %lud\n", ctlr->interrupts);
1183         len += snprint(p+len, READSTR-len, "bogusinterrupts: %lud\n", ctlr->bogusinterrupts);
1184         len += snprint(p+len, READSTR-len, "timer: %lud %lud\n",
1185                 ctlr->timer[0], ctlr->timer[1]);
1186         len += snprint(p+len, READSTR-len, "carrierlost: %lud\n",
1187                 ctlr->stats[CarrierLost]);
1188         len += snprint(p+len, READSTR-len, "sqeerrors: %lud\n",
1189                 ctlr->stats[SqeErrors]);
1190         len += snprint(p+len, READSTR-len, "multiplecolls: %lud\n",
1191                 ctlr->stats[MultipleColls]);
1192         len += snprint(p+len, READSTR-len, "singlecollframes: %lud\n",
1193                 ctlr->stats[SingleCollFrames]);
1194         len += snprint(p+len, READSTR-len, "latecollisions: %lud\n",
1195                 ctlr->stats[LateCollisions]);
1196         len += snprint(p+len, READSTR-len, "rxoverruns: %lud\n",
1197                 ctlr->stats[RxOverruns]);
1198         len += snprint(p+len, READSTR-len, "framesxmittedok: %lud\n",
1199                 ctlr->stats[FramesXmittedOk]);
1200         len += snprint(p+len, READSTR-len, "framesrcvdok: %lud\n",
1201                 ctlr->stats[FramesRcvdOk]);
1202         len += snprint(p+len, READSTR-len, "framesdeferred: %lud\n",
1203                 ctlr->stats[FramesDeferred]);
1204         len += snprint(p+len, READSTR-len, "bytesrcvdok: %lud\n",
1205                 ctlr->stats[BytesRcvdOk]);
1206         len += snprint(p+len, READSTR-len, "bytesxmittedok: %lud\n",
1207                 ctlr->stats[BytesRcvdOk+1]);
1208
1209         if(ctlr->upenabled){
1210                 if(ctlr->upqmax > ctlr->upqmaxhw)
1211                         ctlr->upqmaxhw = ctlr->upqmax;
1212                 len += snprint(p+len, READSTR-len, "up: q %lud i %lud m %d h %d s %lud\n",
1213                         ctlr->upqueued, ctlr->upinterrupts,
1214                         ctlr->upqmax, ctlr->upqmaxhw, ctlr->upstalls);
1215                 ctlr->upqmax = 0;
1216         }
1217         if(ctlr->dnenabled){
1218                 if(ctlr->dnqmax > ctlr->dnqmaxhw)
1219                         ctlr->dnqmaxhw = ctlr->dnqmax;
1220                 len += snprint(p+len, READSTR-len, "dn: q %lud i %lud m %d h %d\n",
1221                         ctlr->dnqueued, ctlr->dninterrupts, ctlr->dnqmax, ctlr->dnqmaxhw);
1222                 ctlr->dnqmax = 0;
1223         }
1224
1225         snprint(p+len, READSTR-len, "badssd: %lud\n", ctlr->stats[BytesRcvdOk+2]);
1226
1227         n = readstr(offset, a, n, p);
1228         free(p);
1229
1230         return n;
1231 }
1232
1233 static void
1234 txrxreset(int port)
1235 {
1236         COMMAND(port, TxReset, 0);
1237         while(STATUS(port) & commandInProgress)
1238                 ;
1239         COMMAND(port, RxReset, 0);
1240         while(STATUS(port) & commandInProgress)
1241                 ;
1242 }
1243
1244 static Ctlr*
1245 tcmadapter(int port, int irq, Pcidev* pcidev)
1246 {
1247         Ctlr *ctlr;
1248
1249         ctlr = malloc(sizeof(Ctlr));
1250         if(ctlr == nil){
1251                 print("etherelnk3: can't allocate memory\n");
1252                 return nil;
1253         }
1254         ctlr->port = port;
1255         ctlr->irq = irq;
1256         ctlr->pcidev = pcidev;
1257         ctlr->eepromcmd = EepromReadRegister;
1258
1259         if(ctlrhead != nil)
1260                 ctlrtail->next = ctlr;
1261         else
1262                 ctlrhead = ctlr;
1263         ctlrtail = ctlr;
1264
1265         return ctlr;
1266 }
1267
1268 /*
1269  * Write two 0 bytes to identify the IDport and then reset the
1270  * ID sequence. Then send the ID sequence to the card to get
1271  * the card into command state.
1272  */
1273 static void
1274 idseq(void)
1275 {
1276         int i;
1277         uchar al;
1278         static int reset, untag;
1279
1280         /*
1281          * One time only:
1282          *      reset any adapters listening
1283          */
1284         if(reset == 0){
1285                 outb(IDport, 0);
1286                 outb(IDport, 0);
1287                 outb(IDport, 0xC0);
1288                 delay(20);
1289                 reset = 1;
1290         }
1291
1292         outb(IDport, 0);
1293         outb(IDport, 0);
1294         for(al = 0xFF, i = 0; i < 255; i++){
1295                 outb(IDport, al);
1296                 if(al & 0x80){
1297                         al <<= 1;
1298                         al ^= 0xCF;
1299                 }
1300                 else
1301                         al <<= 1;
1302         }
1303
1304         /*
1305          * One time only:
1306          *      write ID sequence to get the attention of all adapters;
1307          *      untag all adapters.
1308          * If a global reset is done here on all adapters it will confuse
1309          * any ISA cards configured for EISA mode.
1310          */
1311         if(untag == 0){
1312                 outb(IDport, 0xD0);
1313                 untag = 1;
1314         }
1315 }
1316
1317 static ulong
1318 activate(void)
1319 {
1320         int i;
1321         ushort x, acr;
1322
1323         /*
1324          * Do the little configuration dance:
1325          *
1326          * 2. write the ID sequence to get to command state.
1327          */
1328         idseq();
1329
1330         /*
1331          * 3. Read the Manufacturer ID from the EEPROM.
1332          *    This is done by writing the IDPort with 0x87 (0x80
1333          *    is the 'read EEPROM' command, 0x07 is the offset of
1334          *    the Manufacturer ID field in the EEPROM).
1335          *    The data comes back 1 bit at a time.
1336          *    A delay seems necessary between reading the bits.
1337          *
1338          * If the ID doesn't match, there are no more adapters.
1339          */
1340         outb(IDport, 0x87);
1341         delay(20);
1342         for(x = 0, i = 0; i < 16; i++){
1343                 delay(20);
1344                 x <<= 1;
1345                 x |= inb(IDport) & 0x01;
1346         }
1347         if(x != 0x6D50)
1348                 return 0;
1349
1350         /*
1351          * 3. Read the Address Configuration from the EEPROM.
1352          *    The Address Configuration field is at offset 0x08 in the EEPROM).
1353          */
1354         outb(IDport, 0x88);
1355         for(acr = 0, i = 0; i < 16; i++){
1356                 delay(20);
1357                 acr <<= 1;
1358                 acr |= inb(IDport) & 0x01;
1359         }
1360
1361         return (acr & 0x1F)*0x10 + 0x200;
1362 }
1363
1364 static void
1365 tcm509isa(void)
1366 {
1367         int irq, port;
1368
1369         /*
1370          * Attempt to activate all adapters. If adapter is set for
1371          * EISA mode (0x3F0), tag it and ignore. Otherwise, activate
1372          * it fully.
1373          */
1374         while(port = activate()){
1375                 if(ioalloc(port, 0x10, 0, "tcm509isa") < 0){
1376                         print("tcm509isa: port 0x%uX in use\n", port);
1377                         continue;
1378                 }
1379
1380                 /*
1381                  * 6. Tag the adapter so it won't respond in future.
1382                  */
1383                 outb(IDport, 0xD1);
1384                 if(port == 0x3F0){
1385                         iofree(port);
1386                         continue;
1387                 }
1388
1389                 /*
1390                  * 6. Activate the adapter by writing the Activate command
1391                  *    (0xFF).
1392                  */
1393                 outb(IDport, 0xFF);
1394                 delay(20);
1395
1396                 /*
1397                  * 8. Can now talk to the adapter's I/O base addresses.
1398                  *    Use the I/O base address from the acr just read.
1399                  *
1400                  *    Enable the adapter and clear out any lingering status
1401                  *    and interrupts.
1402                  */
1403                 while(STATUS(port) & commandInProgress)
1404                         ;
1405                 COMMAND(port, SelectRegisterWindow, Wsetup);
1406                 outs(port+ConfigControl, Ena);
1407
1408                 txrxreset(port);
1409                 COMMAND(port, AcknowledgeInterrupt, 0xFF);
1410
1411                 irq = (ins(port+ResourceConfig)>>12) & 0x0F;
1412                 tcmadapter(port, irq, nil);
1413         }
1414 }
1415
1416 static void
1417 tcm5XXeisa(void)
1418 {
1419         ushort x;
1420         int irq, port, slot;
1421
1422         /*
1423          * Check if this is an EISA machine.
1424          * If not, nothing to do.
1425          */
1426         if(strncmp((char*)KADDR(0xFFFD9), "EISA", 4))
1427                 return;
1428
1429         /*
1430          * Continue through the EISA slots looking for a match on both
1431          * 3COM as the manufacturer and 3C579-* or 3C59[27]-* as the product.
1432          * If an adapter is found, select window 0, enable it and clear
1433          * out any lingering status and interrupts.
1434          */
1435         for(slot = 1; slot < MaxEISA; slot++){
1436                 port = slot*0x1000;
1437                 if(ioalloc(port, 0x1000, 0, "tcm5XXeisa") < 0){
1438                         print("tcm5XXeisa: port 0x%uX in use\n", port);
1439                         continue;
1440                 }
1441                 if(ins(port+0xC80+ManufacturerID) != 0x6D50){
1442                         iofree(port);
1443                         continue;
1444                 }
1445                 x = ins(port+0xC80+ProductID);
1446                 if((x & 0xF0FF) != 0x9050 && (x & 0xFF00) != 0x5900){
1447                         iofree(port);
1448                         continue;
1449                 }
1450
1451                 COMMAND(port, SelectRegisterWindow, Wsetup);
1452                 outs(port+ConfigControl, Ena);
1453
1454                 txrxreset(port);
1455                 COMMAND(port, AcknowledgeInterrupt, 0xFF);
1456
1457                 irq = (ins(port+ResourceConfig)>>12) & 0x0F;
1458                 tcmadapter(port, irq, nil);
1459         }
1460 }
1461
1462 static void
1463 tcm59Xpci(void)
1464 {
1465         Pcidev *p;
1466         Ctlr *ctlr;
1467         int irq, port;
1468
1469         p = nil;
1470         while(p = pcimatch(p, 0x10B7, 0)){
1471                 if(p->ccrb != 0x02 || p->ccru != 0)
1472                         continue;
1473                 /*
1474                  * Not prepared to deal with memory-mapped
1475                  * devices yet.
1476                  */
1477                 if(!(p->mem[0].bar & 0x01))
1478                         continue;
1479                 port = p->mem[0].bar & ~0x01;
1480                 if((port = ioalloc((port == 0)? -1: port,  p->mem[0].size, 
1481                                           0, "tcm59Xpci")) < 0){
1482                         print("tcm59Xpci: port 0x%uX in use\n", port);
1483                         continue;
1484                 }
1485                 irq = p->intl;
1486
1487                 txrxreset(port);
1488                 COMMAND(port, AcknowledgeInterrupt, 0xFF);
1489
1490                 ctlr = tcmadapter(port, irq, p);
1491                 if(ctlr == nil)
1492                         continue;
1493                 switch(p->did){
1494                 default:
1495                         break;
1496                 case 0x5157:
1497                         ctlr->eepromcmd = EepromRead8bRegister;
1498                         ctlr->cbfnpa = p->mem[2].bar&~0x0F;
1499                         ctlr->cbfn = vmap(p->mem[2].bar&~0x0F, p->mem[2].size);
1500                         break;
1501                 case 0x6056:
1502                         ctlr->eepromcmd = EepromReadOffRegister;
1503                         ctlr->cbfnpa = p->mem[2].bar&~0x0F;
1504                         ctlr->cbfn = vmap(p->mem[2].bar&~0x0F, p->mem[2].size);
1505                         break;
1506                 }
1507                 pcisetbme(p);
1508         }
1509 }
1510
1511 static char* tcmpcmcia[] = {
1512         "3C589",                        /* 3COM 589[ABCD] */
1513         "3C562",                        /* 3COM 562 */
1514         "589E",                         /* 3COM Megahertz 589E */
1515         nil,
1516 };
1517
1518 static Ctlr*
1519 tcm5XXpcmcia(Ether* ether)
1520 {
1521         int i;
1522         Ctlr *ctlr;
1523
1524         if(ether->type == nil)
1525                 return nil;
1526
1527         for(i = 0; tcmpcmcia[i] != nil; i++){
1528                 if(cistrcmp(ether->type, tcmpcmcia[i]))
1529                         continue;
1530                 if(ctlr = tcmadapter(ether->port, ether->irq, nil))
1531                         ctlr->active = 1;
1532                 return ctlr;
1533         }
1534
1535         return nil;
1536 }
1537
1538 static void
1539 setxcvr(Ctlr* ctlr, int xcvr)
1540 {
1541         int port, x;
1542
1543         port = ctlr->port;
1544         if(ctlr->rxstatus9){
1545                 COMMAND(port, SelectRegisterWindow, Wsetup);
1546                 x = ins(port+AddressConfig) & ~xcvrMask9;
1547                 x |= (xcvr>>20)<<14;
1548                 outs(port+AddressConfig, x);
1549         }
1550         else{
1551                 COMMAND(port, SelectRegisterWindow, Wfifo);
1552                 x = inl(port+InternalConfig) & ~xcvrMask;
1553                 x |= xcvr;
1554                 outl(port+InternalConfig, x);
1555         }
1556
1557         txrxreset(port);
1558 }
1559
1560 static void
1561 setfullduplex(int port)
1562 {
1563         int x;
1564
1565         COMMAND(port, SelectRegisterWindow, Wfifo);
1566         x = ins(port+MacControl);
1567         outs(port+MacControl, fullDuplexEnable|x);
1568
1569         txrxreset(port);
1570 }
1571
1572 static int
1573 miimdi(int port, int n)
1574 {
1575         int data, i;
1576
1577         /*
1578          * Read n bits from the MII Management Register.
1579          */
1580         data = 0;
1581         for(i = n-1; i >= 0; i--){
1582                 if(ins(port) & mgmtData)
1583                         data |= (1<<i);
1584                 microdelay(1);
1585                 outs(port, mgmtClk);
1586                 microdelay(1);
1587                 outs(port, 0);
1588                 microdelay(1);
1589         }
1590
1591         return data;
1592 }
1593
1594 static void
1595 miimdo(int port, int bits, int n)
1596 {
1597         int i, mdo;
1598
1599         /*
1600          * Write n bits to the MII Management Register.
1601          */
1602         for(i = n-1; i >= 0; i--){
1603                 if(bits & (1<<i))
1604                         mdo = mgmtDir|mgmtData;
1605                 else
1606                         mdo = mgmtDir;
1607                 outs(port, mdo);
1608                 microdelay(1);
1609                 outs(port, mdo|mgmtClk);
1610                 microdelay(1);
1611                 outs(port, mdo);
1612                 microdelay(1);
1613         }
1614 }
1615
1616 static int
1617 miir(int port, int phyad, int regad)
1618 {
1619         int data, w;
1620
1621         w = (STATUS(port)>>13) & 0x07;
1622         COMMAND(port, SelectRegisterWindow, Wdiagnostic);
1623         port += PhysicalMgmt;
1624
1625         /*
1626          * Preamble;
1627          * ST+OP+PHYAD+REGAD;
1628          * TA + 16 data bits.
1629          */
1630         miimdo(port, 0xFFFFFFFF, 32);
1631         miimdo(port, 0x1800|(phyad<<5)|regad, 14);
1632         data = miimdi(port, 18);
1633
1634         port -= PhysicalMgmt;
1635         COMMAND(port, SelectRegisterWindow, w);
1636
1637         if(data & 0x10000)
1638                 return -1;
1639
1640         return data & 0xFFFF;
1641 }
1642
1643 static int
1644 scanphy(int port)
1645 {
1646         int i, x;
1647
1648         for(i = 0; i < 32; i++){
1649                 if((x = miir(port, i, 2)) == -1 || x == 0)
1650                         continue;
1651                 x <<= 6;
1652                 x |= miir(port, i, 3)>>10;
1653                 XCVRDEBUG("phy%d: oui %uX reg1 %uX\n", i, x, miir(port, i, 1));
1654                 USED(x);
1655
1656                 return i;
1657         }
1658         return 24;
1659 }
1660
1661 static struct {
1662         char *name;
1663         int avail;
1664         int xcvr;
1665 } media[] = {
1666         "10BaseT",      base10TAvailable,       xcvr10BaseT,
1667         "10Base2",      coaxAvailable,          xcvr10Base2,
1668         "100BaseTX",    baseTXAvailable,        xcvr100BaseTX,
1669         "100BaseFX",    baseFXAvailable,        xcvr100BaseFX,
1670         "aui",          auiAvailable,           xcvrAui,
1671         "mii",          miiConnector,           xcvrMii
1672 };
1673
1674 static int
1675 autoselect(Ctlr* ctlr)
1676 {
1677         int media, port, x;
1678
1679         /*
1680          * Pathetic attempt at automatic media selection.
1681          * Really just to get the Fast Etherlink 10BASE-T/100BASE-TX
1682          * cards operational.
1683          * It's a bonus if it works for anything else.
1684          */
1685         port = ctlr->port;
1686         if(ctlr->rxstatus9){
1687                 COMMAND(port, SelectRegisterWindow, Wsetup);
1688                 x = ins(port+ConfigControl);
1689                 media = 0;
1690                 if(x & base10TAvailable9)
1691                         media |= base10TAvailable;
1692                 if(x & coaxAvailable9)
1693                         media |= coaxAvailable;
1694                 if(x & auiAvailable9)
1695                         media |= auiAvailable;
1696         }
1697         else{
1698                 COMMAND(port, SelectRegisterWindow, Wfifo);
1699                 media = ins(port+ResetOptions);
1700         }
1701         XCVRDEBUG("autoselect: media %uX\n", media);
1702
1703         if(media & miiConnector)
1704                 return xcvrMii;
1705
1706         COMMAND(port, SelectRegisterWindow, Wdiagnostic);
1707         XCVRDEBUG("autoselect: media status %uX\n", ins(port+MediaStatus));
1708
1709         if(media & baseTXAvailable){
1710                 /*
1711                  * Must have InternalConfig register.
1712                  */
1713                 setxcvr(ctlr, xcvr100BaseTX);
1714
1715                 COMMAND(port, SelectRegisterWindow, Wdiagnostic);
1716                 x = ins(port+MediaStatus) & ~(dcConverterEnabled|jabberGuardEnable);
1717                 outs(port+MediaStatus, linkBeatEnable|x);
1718                 delay(10);
1719
1720                 if(ins(port+MediaStatus) & linkBeatDetect)
1721                         return xcvr100BaseTX;
1722                 outs(port+MediaStatus, x);
1723         }
1724
1725         if(media & base10TAvailable){
1726                 setxcvr(ctlr, xcvr10BaseT);
1727
1728                 COMMAND(port, SelectRegisterWindow, Wdiagnostic);
1729                 x = ins(port+MediaStatus) & ~dcConverterEnabled;
1730                 outs(port+MediaStatus, linkBeatEnable|jabberGuardEnable|x);
1731                 delay(100);
1732
1733                 XCVRDEBUG("autoselect: 10BaseT media status %uX\n", ins(port+MediaStatus));
1734                 if(ins(port+MediaStatus) & linkBeatDetect)
1735                         return xcvr10BaseT;
1736                 outs(port+MediaStatus, x);
1737         }
1738
1739         /*
1740          * Botch.
1741          */
1742         return autoSelect;
1743 }
1744
1745 static int
1746 eepromdata(Ctlr* ctlr, int offset)
1747 {
1748         int port;
1749
1750         port = ctlr->port;
1751
1752         COMMAND(port, SelectRegisterWindow, Wsetup);
1753         while(EEPROMBUSY(port))
1754                 ;
1755         EEPROMCMD(port, ctlr->eepromcmd, offset);
1756         while(EEPROMBUSY(port))
1757                 ;
1758         return EEPROMDATA(port);
1759 }
1760
1761 static void
1762 resetctlr(Ctlr *ctlr)
1763 {
1764         int x, port = ctlr->port;
1765
1766         txrxreset(port);
1767         x = ins(port+ResetOp905B);
1768         XCVRDEBUG("905[BC] reset ops 0x%uX\n", x);
1769         x &= ~0x4010;
1770         if(ctlr->did == 0x5157){
1771                 x |= 0x0010;                    /* Invert LED */
1772                 outs(port+ResetOp905B, x);
1773         }
1774         if(ctlr->did == 0x6056){
1775                 x |= 0x4000;
1776                 outs(port+ResetOp905B, x);
1777
1778                 COMMAND(port, SelectRegisterWindow, Wsetup);
1779                 outs(port, 0x0800);
1780         }
1781 }
1782
1783 static void
1784 shutdown(Ether *ether)
1785 {
1786 print("etherelnk3 shutting down\n");
1787         resetctlr(ether->ctlr);
1788 }
1789
1790 int
1791 etherelnk3reset(Ether* ether)
1792 {
1793         char *p;
1794         Ctlr *ctlr;
1795         uchar ea[Eaddrlen];
1796         static int scandone;
1797         int anar, anlpar, i, j, phyaddr, phystat, port, timeo, x;
1798
1799         /*
1800          * Scan for adapter on PCI, EISA and finally
1801          * using the little ISA configuration dance.
1802          */
1803         if(scandone == 0){
1804                 tcm59Xpci();
1805                 tcm5XXeisa();
1806                 tcm509isa();
1807                 scandone = 1;
1808         }
1809
1810         /*
1811          * Any adapter matches if no ether->port is supplied,
1812          * otherwise the ports must match.
1813          */
1814         for(ctlr = ctlrhead; ctlr != nil; ctlr = ctlr->next){
1815                 if(ctlr->active)
1816                         continue;
1817                 if(ether->port == 0 || ether->port == ctlr->port){
1818                         ctlr->active = 1;
1819                         break;
1820                 }
1821         }
1822         if(ctlr == nil && (ctlr = tcm5XXpcmcia(ether)) == 0)
1823                 return -1;
1824
1825         ether->ctlr = ctlr;
1826         port = ctlr->port;
1827         ether->port = port;
1828         ether->irq = ctlr->irq;
1829         if(ctlr->pcidev != nil)
1830                 ether->tbdf = ctlr->pcidev->tbdf;
1831         else
1832                 ether->tbdf = BUSUNKNOWN;
1833
1834         /*
1835          * Read the DeviceID from the EEPROM, it's at offset 0x03,
1836          * and do something depending on capabilities.
1837          */
1838         switch(ctlr->did = eepromdata(ctlr, 0x03)){
1839         case 0x5157:            /* 3C575 Cyclone */
1840         case 0x6056:
1841                 /*FALLTHROUGH*/
1842         case 0x4500:            /* 3C450 HomePNA Tornado */
1843         case 0x7646:            /* 3CSOHO100-TX */
1844         case 0x9055:            /* 3C905B-TX */
1845         case 0x9200:            /* 3C905C-TX */
1846         case 0x9201:            /* 3C920 */
1847         case 0x9805:            /* 3C9805: 3C980-TX Python-T 10/100baseTX */
1848                 /*FALLTHROUGH*/
1849         case 0x9000:            /* 3C900-TPO */
1850         case 0x9001:            /* 3C900-COMBO */
1851         case 0x9005:            /* 3C900B-COMBO */
1852         case 0x9050:            /* 3C905-TX */
1853         case 0x9051:            /* 3C905-T4 */
1854                 if(BUSTYPE(ether->tbdf) != BusPCI)
1855                         goto buggery;
1856                 ctlr->busmaster = 2;
1857                 goto vortex;
1858         case 0x5900:            /* 3C590-[TP|COMBO|TPO] */
1859         case 0x5920:            /* 3C592-[TP|COMBO|TPO] */
1860         case 0x5950:            /* 3C595-TX */
1861         case 0x5951:            /* 3C595-T4 */
1862         case 0x5952:            /* 3C595-MII */
1863         case 0x5970:            /* 3C597-TX */
1864         case 0x5971:            /* 3C597-T4 */
1865         case 0x5972:            /* 3C597-MII */
1866                 ctlr->busmaster = 1;
1867         vortex:
1868                 COMMAND(port, SelectRegisterWindow, Wfifo);
1869                 ctlr->xcvr = inl(port+InternalConfig) & (autoSelect|xcvrMask);
1870                 ctlr->rxearly = 8188;
1871                 ctlr->rxstatus9 = 0;
1872                 break;
1873         buggery:
1874         default:
1875                 ctlr->busmaster = 0;
1876                 COMMAND(port, SelectRegisterWindow, Wsetup);
1877                 x = ins(port+AddressConfig);
1878                 ctlr->xcvr = ((x & xcvrMask9)>>14)<<20;
1879                 if(x & autoSelect9)
1880                         ctlr->xcvr |= autoSelect;
1881                 ctlr->rxearly = 2044;
1882                 ctlr->rxstatus9 = 1;
1883                 break;
1884         }
1885         if(ctlr->rxearly >= 2048)
1886                 ctlr->ts = 2;
1887
1888         /*
1889          * Check if the adapter's station address is to be overridden.
1890          * If not, read it from the EEPROM and set in ether->ea prior to
1891          * loading the station address in Wstation.
1892          * The EEPROM returns 16-bits at a time.
1893          */
1894         memset(ea, 0, Eaddrlen);
1895         if(memcmp(ea, ether->ea, Eaddrlen) == 0){
1896                 for(i = 0; i < Eaddrlen/2; i++){
1897                         x = eepromdata(ctlr, i);
1898                         ether->ea[2*i] = x>>8;
1899                         ether->ea[2*i+1] = x;
1900                 }
1901         }
1902
1903         COMMAND(port, SelectRegisterWindow, Wstation);
1904         for(i = 0; i < Eaddrlen; i++)
1905                 outb(port+i, ether->ea[i]);
1906
1907         /*
1908          * Enable the transceiver if necessary and determine whether
1909          * busmastering can be used. Due to bugs in the first revision
1910          * of the 3C59[05], don't use busmastering at 10Mbps.
1911          */
1912         XCVRDEBUG("reset: xcvr %uX\n", ctlr->xcvr);
1913
1914         /*
1915          * Allow user to specify desired media in plan9.ini
1916          */
1917         for(i = 0; i < ether->nopt; i++){
1918                 if(cistrncmp(ether->opt[i], "media=", 6) != 0)
1919                         continue;
1920                 p = ether->opt[i]+6;
1921                 for(j = 0; j < nelem(media); j++)
1922                         if(cistrcmp(p, media[j].name) == 0)
1923                                 ctlr->xcvr = media[j].xcvr;
1924         }
1925         
1926         /*
1927          * forgive me, but i am weak
1928          */
1929         switch(ctlr->did){
1930         default:
1931                 if(ctlr->xcvr & autoSelect)
1932                         ctlr->xcvr = autoselect(ctlr);
1933                 break;
1934         case 0x5157:
1935         case 0x6056:
1936         case 0x4500:
1937         case 0x7646:
1938         case 0x9055:
1939         case 0x9200:
1940         case 0x9201:
1941         case 0x9805:
1942                 ctlr->xcvr = xcvrMii;
1943                 resetctlr(ctlr);
1944                 break;
1945         }
1946         XCVRDEBUG("xcvr selected: %uX, did 0x%uX\n", ctlr->xcvr, ctlr->did);
1947
1948         switch(ctlr->xcvr){
1949         case xcvrMii:
1950                 /*
1951                  * Quick hack.
1952                  */
1953                 if(ctlr->did == 0x5157)
1954                         phyaddr = 0;
1955                 else if(ctlr->did == 0x6056)
1956                         phyaddr = scanphy(port);
1957                 else
1958                         phyaddr = 24;
1959                 for(i = 0; i < 7; i++)
1960                         XCVRDEBUG(" %2.2uX", miir(port, phyaddr, i));
1961                         XCVRDEBUG("\n");
1962
1963                 for(timeo = 0; timeo < 30; timeo++){
1964                         phystat = miir(port, phyaddr, 0x01);
1965                         if(phystat & 0x20)
1966                                 break;
1967                         XCVRDEBUG(" %2.2uX", phystat);
1968                         delay(100);
1969                 }
1970                 XCVRDEBUG(" %2.2uX", miir(port, phyaddr, 0x01));
1971                 XCVRDEBUG("\n");
1972
1973                 anar = miir(port, phyaddr, 0x04);
1974                 anlpar = miir(port, phyaddr, 0x05) & 0x03E0;
1975                 anar &= anlpar;
1976                 miir(port, phyaddr, 0x00);
1977                 XCVRDEBUG("mii an: %uX anlp: %uX r0:%uX r1:%uX\n",
1978                         anar, anlpar, miir(port, phyaddr, 0x00),
1979                         miir(port, phyaddr, 0x01));
1980                 for(i = 0; i < ether->nopt; i++){
1981                         if(cistrcmp(ether->opt[i], "fullduplex") == 0)
1982                                 anar |= 0x0100;
1983                         else if(cistrcmp(ether->opt[i], "100BASE-TXFD") == 0)
1984                                 anar |= 0x0100;
1985                         else if(cistrcmp(ether->opt[i], "force100") == 0)
1986                                 anar |= 0x0080;
1987                 }
1988                 XCVRDEBUG("mii anar: %uX\n", anar);
1989                 if(anar & 0x0100){              /* 100BASE-TXFD */
1990                         ether->mbps = 100;
1991                         setfullduplex(port);
1992                 }
1993                 else if(anar & 0x0200){         /* 100BASE-T4 */
1994                         /* nothing to do */
1995                 }
1996                 else if(anar & 0x0080)          /* 100BASE-TX */
1997                         ether->mbps = 100;
1998                 else if(anar & 0x0040)          /* 10BASE-TFD */
1999                         setfullduplex(port);
2000                 else{                           /* 10BASE-T */
2001                         /* nothing to do */
2002                 }
2003                 break;
2004         case xcvr100BaseTX:
2005         case xcvr100BaseFX:
2006                 COMMAND(port, SelectRegisterWindow, Wfifo);
2007                 x = inl(port+InternalConfig) & ~ramPartitionMask;
2008                 outl(port+InternalConfig, x|ramPartition1to1);
2009
2010                 COMMAND(port, SelectRegisterWindow, Wdiagnostic);
2011                 x = ins(port+MediaStatus) & ~(dcConverterEnabled|jabberGuardEnable);
2012                 x |= linkBeatEnable;
2013                 outs(port+MediaStatus, x);
2014
2015                 if(x & dataRate100)
2016                         ether->mbps = 100;
2017                 break;
2018         case xcvr10BaseT:
2019                 /*
2020                  * Enable Link Beat and Jabber to start the
2021                  * transceiver.
2022                  */
2023                 COMMAND(port, SelectRegisterWindow, Wdiagnostic);
2024                 x = ins(port+MediaStatus) & ~dcConverterEnabled;
2025                 x |= linkBeatEnable|jabberGuardEnable;
2026                 outs(port+MediaStatus, x);
2027
2028                 if((ctlr->did & 0xFF00) == 0x5900)
2029                         ctlr->busmaster = 0;
2030                 break;
2031         case xcvr10Base2:
2032                 COMMAND(port, SelectRegisterWindow, Wdiagnostic);
2033                 x = ins(port+MediaStatus) & ~(linkBeatEnable|jabberGuardEnable);
2034                 outs(port+MediaStatus, x);
2035
2036                 /*
2037                  * Start the DC-DC converter.
2038                  * Wait > 800 microseconds.
2039                  */
2040                 COMMAND(port, EnableDcConverter, 0);
2041                 delay(1);
2042                 break;
2043         }
2044
2045         /*
2046          * Wop is the normal operating register set.
2047          * The 3C59[0257] adapters allow access to more than one register window
2048          * at a time, but there are situations where switching still needs to be
2049          * done, so just do it.
2050          * Clear out any lingering Tx status.
2051          */
2052         COMMAND(port, SelectRegisterWindow, Wop);
2053         if(ctlr->busmaster == 2)
2054                 x = port+TxStatus905;
2055         else
2056                 x = port+TxStatus;
2057         while(inb(x))
2058                 outb(x, 0);
2059
2060         /*
2061          * Clear out the
2062          * adapter statistics, clear the statistics logged into ctlr
2063          * and enable statistics collection.
2064          */
2065         ilock(&ctlr->wlock);
2066         statistics(ether);
2067         memset(ctlr->stats, 0, sizeof(ctlr->stats));
2068
2069         COMMAND(port, StatisticsEnable, 0);
2070
2071         /*
2072          * Allocate any receive buffers.
2073          */
2074         switch(ctlr->busmaster){
2075         case 2:
2076                 ctlr->dnenabled = 1;
2077
2078                 /*
2079                  * 10MUpldBug.
2080                  * Disabling is too severe, can use receive busmastering at
2081                  * 100Mbps OK, but how to tell which rate is actually being used -
2082                  * the 3c905 always seems to have dataRate100 set?
2083                  * Believe the bug doesn't apply if upRxEarlyEnable is set
2084                  * and the threshold is set such that uploads won't start
2085                  * until the whole packet has been received.
2086                  */
2087                 ctlr->upenabled = 1;
2088                 x = eepromdata(ctlr, 0x0F);
2089                 if(!(x & 0x01))
2090                         outl(port+PktStatus, upRxEarlyEnable);
2091
2092                 if(ctlr->upenabled || ctlr->dnenabled){
2093                         ctlr->nup = Nup;
2094                         ctlr->ndn = Ndn;
2095                         init905(ctlr);
2096                 }
2097                 else {
2098                         ctlr->rbp = rbpalloc(iallocb);
2099                         if(ctlr->rbp == nil)
2100                                 panic("etherlnk3: iallocb: out of memory");
2101                 }
2102                 outl(port+TxFreeThresh, HOWMANY(ETHERMAXTU, 256));
2103                 break;
2104         default:
2105                 ctlr->rbp = rbpalloc(iallocb);
2106                 if(ctlr->rbp == nil)
2107                         panic("etherlnk3: iallocb: out of memory");
2108                 break;
2109         }
2110
2111         /*
2112          * Set a base TxStartThresh which will be incremented
2113          * if any txUnderrun errors occur and ensure no RxEarly
2114          * interrupts happen.
2115          */
2116         ctlr->txthreshold = ETHERMAXTU/2;
2117         COMMAND(port, SetTxStartThresh, ctlr->txthreshold>>ctlr->ts);
2118         COMMAND(port, SetRxEarlyThresh, ctlr->rxearly>>ctlr->ts);
2119
2120         iunlock(&ctlr->wlock);
2121
2122         /*
2123          * Linkage to the generic ethernet driver.
2124          */
2125         ether->attach = attach;
2126         ether->transmit = transmit;
2127         ether->interrupt = interrupt;
2128         ether->ifstat = ifstat;
2129
2130         ether->promiscuous = promiscuous;
2131         ether->multicast = multicast;
2132         ether->shutdown = shutdown;
2133         ether->arg = ether;
2134
2135         return 0;
2136 }
2137
2138 void
2139 etherelnk3link(void)
2140 {
2141         addethercard("elnk3", etherelnk3reset);
2142         addethercard("3C509", etherelnk3reset);
2143         addethercard("3C575", etherelnk3reset);
2144 }