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