]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/etherelnk3.c
bcm, bcm64: add support for device tree parameter passing
[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                 pcienable(p);
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->ifstat = ifstat;
2128
2129         ether->promiscuous = promiscuous;
2130         ether->multicast = multicast;
2131         ether->shutdown = shutdown;
2132         ether->arg = ether;
2133
2134         intrenable(ether->irq, interrupt, ether, ether->tbdf, ether->name);
2135
2136         return 0;
2137 }
2138
2139 void
2140 etherelnk3link(void)
2141 {
2142         addethercard("elnk3", etherelnk3reset);
2143         addethercard("3C509", etherelnk3reset);
2144         addethercard("3C575", etherelnk3reset);
2145 }