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