]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/ethervt6102.c
perms
[plan9front.git] / sys / src / 9 / pc / ethervt6102.c
1 /*
2  * VIA VT6102 Fast Ethernet Controller (Rhine II).
3  * To do:
4  *      cache-line size alignments - done
5  *      reduce tx interrupts
6  *      use 2 descriptors on tx for alignment - done
7  *      reorganise initialisation/shutdown/reset
8  *      adjust Tx FIFO threshold on underflow - untested
9  *      why does the link status never cause an interrupt?
10  *      use the lproc as a periodic timer for stalls, etc.
11  */
12 #include "u.h"
13 #include "../port/lib.h"
14 #include "mem.h"
15 #include "dat.h"
16 #include "fns.h"
17 #include "io.h"
18 #include "../port/error.h"
19 #include "../port/netif.h"
20
21 #include "etherif.h"
22 #include "ethermii.h"
23
24 enum {
25         Par0            = 0x00,         /* Ethernet Address */
26         Rcr             = 0x06,         /* Receive Configuration */
27         Tcr             = 0x07,         /* Transmit Configuration */
28         Cr              = 0x08,         /* Control */
29         Isr             = 0x0C,         /* Interrupt Status */
30         Imr             = 0x0E,         /* Interrupt Mask */
31         Mcfilt0         = 0x10,         /* Multicast Filter 0 */
32         Mcfilt1         = 0x14,         /* Multicast Filter 1 */
33         Rxdaddr         = 0x18,         /* Current Rx Descriptor Address */
34         Txdaddr         = 0x1C,         /* Current Tx Descriptor Address */
35         Phyadr          = 0x6C,         /* Phy Address */
36         Miisr           = 0x6D,         /* MII Status */
37         Bcr0            = 0x6E,         /* Bus Control */
38         Bcr1            = 0x6F,
39         Miicr           = 0x70,         /* MII Control */
40         Miiadr          = 0x71,         /* MII Address */
41         Miidata         = 0x72,         /* MII Data */
42         Eecsr           = 0x74,         /* EEPROM Control and Status */
43         Stickhw         = 0x83,         /* Sticky Hardware Control */
44         Wolcrclr        = 0xA4,
45         Wolcgclr        = 0xA7,
46         Pwrcsrclr       = 0xAC,
47 };
48
49 enum {                                  /* Rcr */
50         Sep             = 0x01,         /* Accept Error Packets */
51         Ar              = 0x02,         /* Accept Small Packets */
52         Am              = 0x04,         /* Accept Multicast */
53         Ab              = 0x08,         /* Accept Broadcast */
54         Prom            = 0x10,         /* Accept Physical Address Packets */
55         RrftMASK        = 0xE0,         /* Receive FIFO Threshold */
56         RrftSHIFT       = 5,
57         Rrft64          = 0<<RrftSHIFT,
58         Rrft32          = 1<<RrftSHIFT,
59         Rrft128         = 2<<RrftSHIFT,
60         Rrft256         = 3<<RrftSHIFT,
61         Rrft512         = 4<<RrftSHIFT,
62         Rrft768         = 5<<RrftSHIFT,
63         Rrft1024        = 6<<RrftSHIFT,
64         RrftSAF         = 7<<RrftSHIFT,
65 };
66
67 enum {                                  /* Tcr */
68         Lb0             = 0x02,         /* Loopback Mode */
69         Lb1             = 0x04,
70         Ofset           = 0x08,         /* Back-off Priority Selection */
71         RtsfMASK        = 0xE0,         /* Transmit FIFO Threshold */
72         RtsfSHIFT       = 5,
73         Rtsf128         = 0<<RtsfSHIFT,
74         Rtsf256         = 1<<RtsfSHIFT,
75         Rtsf512         = 2<<RtsfSHIFT,
76         Rtsf1024        = 3<<RtsfSHIFT,
77         RtsfSAF         = 7<<RtsfSHIFT,
78 };
79
80 enum {                                  /* Cr */
81         Init            = 0x0001,       /* INIT Process Begin */
82         Strt            = 0x0002,       /* Start NIC */
83         Stop            = 0x0004,       /* Stop NIC */
84         Rxon            = 0x0008,       /* Turn on Receive Process */
85         Txon            = 0x0010,       /* Turn on Transmit Process */
86         Tdmd            = 0x0020,       /* Transmit Poll Demand */
87         Rdmd            = 0x0040,       /* Receive Poll Demand */
88         Eren            = 0x0100,       /* Early Receive Enable */
89         Fdx             = 0x0400,       /* Set MAC to Full Duplex Mode */
90         Dpoll           = 0x0800,       /* Disable Td/Rd Auto Polling */
91         Tdmd1           = 0x2000,       /* Transmit Poll Demand 1 */
92         Rdmd1           = 0x4000,       /* Receive Poll Demand 1 */
93         Sfrst           = 0x8000,       /* Software Reset */
94 };
95
96 enum {                                  /* Isr/Imr */
97         Prx             = 0x0001,       /* Received Packet Successfully */
98         Ptx             = 0x0002,       /* Transmitted Packet Successfully */
99         Rxe             = 0x0004,       /* Receive Error */
100         Txe             = 0x0008,       /* Transmit Error */
101         Tu              = 0x0010,       /* Transmit Buffer Underflow */
102         Ru              = 0x0020,       /* Receive Buffer Link Error */
103         Be              = 0x0040,       /* PCI Bus Error */
104         Cnt             = 0x0080,       /* Counter Overflow */
105         Eri             = 0x0100,       /* Early Receive Interrupt */
106         Udfi            = 0x0200,       /* Tx FIFO Underflow */
107         Ovfi            = 0x0400,       /* Receive FIFO Overflow */
108         Pktrace         = 0x0800,       /* Hmmm... */
109         Norbf           = 0x1000,       /* No Receive Buffers */
110         Abti            = 0x2000,       /* Transmission Abort */
111         Srci            = 0x4000,       /* Port State Change */
112         Geni            = 0x8000,       /* General Purpose Interrupt */
113 };
114
115 enum {                                  /* Phyadr */
116         PhyadMASK       = 0x1F,         /* PHY Address */
117         PhyadSHIFT      = 0,
118         Mfdc            = 0x20,         /* Accelerate MDC Speed */
119         Mpo0            = 0x40,         /* MII Polling Timer Interval */
120         Mpo1            = 0x80,
121 };
122
123 enum {                                  /* Bcr0 */
124         DmaMASK         = 0x07,         /* DMA Length */
125         DmaSHIFT        = 0,
126         Dma32           = 0<<DmaSHIFT,
127         Dma64           = 1<<DmaSHIFT,
128         Dma128          = 2<<DmaSHIFT,
129         Dma256          = 3<<DmaSHIFT,
130         Dma512          = 4<<DmaSHIFT,
131         Dma1024         = 5<<DmaSHIFT,
132         DmaSAF          = 7<<DmaSHIFT,
133         CrftMASK        = 0x38,         /* Rx FIFO Threshold */
134         CrftSHIFT       = 3,
135         Crft64          = 1<<CrftSHIFT,
136         Crft128         = 2<<CrftSHIFT,
137         Crft256         = 3<<CrftSHIFT,
138         Crft512         = 4<<CrftSHIFT,
139         Crft1024        = 5<<CrftSHIFT,
140         CrftSAF         = 7<<CrftSHIFT,
141         Extled          = 0x40,         /* Extra LED Support Control */
142         Med2            = 0x80,         /* Medium Select Control */
143 };
144
145 enum {                                  /* Bcr1 */
146         PotMASK         = 0x07,         /* Polling Timer Interval */
147         PotSHIFT        = 0,
148         CtftMASK        = 0x38,         /* Tx FIFO Threshold */
149         CtftSHIFT       = 3,
150         Ctft64          = 1<<CtftSHIFT,
151         Ctft128         = 2<<CtftSHIFT,
152         Ctft256         = 3<<CtftSHIFT,
153         Ctft512         = 4<<CtftSHIFT,
154         Ctft1024        = 5<<CtftSHIFT,
155         CtftSAF         = 7<<CtftSHIFT,
156 };
157
158 enum {                                  /* Miicr */
159         Mdc             = 0x01,         /* Clock */
160         Mdi             = 0x02,         /* Data In */
161         Mdo             = 0x04,         /* Data Out */
162         Mout            = 0x08,         /* Output Enable */
163         Mdpm            = 0x10,         /* Direct Program Mode Enable */
164         Wcmd            = 0x20,         /* Write Enable */
165         Rcmd            = 0x40,         /* Read Enable */
166         Mauto           = 0x80,         /* Auto Polling Enable */
167 };
168
169 enum {                                  /* Miiadr */
170         MadMASK         = 0x1F,         /* MII Port Address */
171         MadSHIFT        = 0,
172         Mdone           = 0x20,         /* Accelerate MDC Speed */
173         Msrcen          = 0x40,         /* MII Polling Timer Interval */
174         Midle           = 0x80,
175 };
176
177 enum {                                  /* Eecsr */
178         Edo             = 0x01,         /* Data Out */
179         Edi             = 0x02,         /* Data In */
180         Eck             = 0x04,         /* Clock */
181         Ecs             = 0x08,         /* Chip Select */
182         Dpm             = 0x10,         /* Direct Program Mode Enable */
183         Autold          = 0x20,         /* Dynamic Reload */
184         Embp            = 0x40,         /* Embedded Program Enable */
185         Eepr            = 0x80,         /* Programmed */
186 };
187
188 /*
189  * Ring descriptor. The space allocated for each
190  * of these will be rounded up to a cache-line boundary.
191  * The first 4 elements are known to the hardware.
192  */
193 typedef struct Ds Ds;
194 typedef struct Ds {
195         uint    status;
196         uint    control;
197         uint    addr;
198         uint    branch;
199
200         Block*  bp;
201         void*   bounce;
202         Ds*     next;
203         Ds*     prev;
204 } Ds;
205
206 enum {                                  /* Rx Ds status */
207         Rerr            = 0x00000001,   /* Receiver Error */
208         Crc             = 0x00000002,   /* CRC Error */
209         Fae             = 0x00000004,   /* Frame Alignment Error */
210         Fov             = 0x00000008,   /* FIFO Overflow */
211         Long            = 0x00000010,   /* A Long Packet */
212         Runt            = 0x00000020,   /* A Runt Packet */
213         Rxserr          = 0x00000040,   /* System Error */
214         Buff            = 0x00000080,   /* Buffer Underflow Error */
215         Rxedp           = 0x00000100,   /* End of Packet Buffer */
216         Rxstp           = 0x00000200,   /* Packet Start */
217         Chn             = 0x00000400,   /* Chain Buffer */
218         Phy             = 0x00000800,   /* Physical Address Packet */
219         Bar             = 0x00001000,   /* Broadcast Packet */
220         Mar             = 0x00002000,   /* Multicast Packet */
221         Rxok            = 0x00008000,   /* Packet Received Successfully */
222         LengthMASK      = 0x07FF0000,   /* Received Packet Length */
223         LengthSHIFT     = 16,
224
225         Own             = 0x80000000,   /* Descriptor Owned by NIC */
226 };
227
228 enum {                                  /* Tx Ds status */
229         NcrMASK         = 0x0000000F,   /* Collision Retry Count */
230         NcrSHIFT        = 0,
231         Cols            = 0x00000010,   /* Experienced Collisions */
232         Cdh             = 0x00000080,   /* CD Heartbeat */
233         Abt             = 0x00000100,   /* Aborted after Excessive Collisions */
234         Owc             = 0x00000200,   /* Out of Window Collision Seen */
235         Crs             = 0x00000400,   /* Carrier Sense Lost */
236         Udf             = 0x00000800,   /* FIFO Underflow */
237         Tbuff           = 0x00001000,   /* Invalid Td */
238         Txserr          = 0x00002000,   /* System Error */
239         Terr            = 0x00008000,   /* Excessive Collisions */
240 };
241
242 enum {                                  /* Tx Ds control */
243         TbsMASK         = 0x000007FF,   /* Tx Buffer Size */
244         TbsSHIFT        = 0,
245         Chain           = 0x00008000,   /* Chain Buffer */
246         Crcdisable      = 0x00010000,   /* Disable CRC generation */
247         Stp             = 0x00200000,   /* Start of Packet */
248         Edp             = 0x00400000,   /* End of Packet */
249         Ic              = 0x00800000,   /* Assert Interrupt Immediately */
250 };
251
252 enum {
253         Nrd             = 64,
254         Ntd             = 64,
255         Rdbsz           = ROUNDUP(ETHERMAXTU+4, 4),
256
257         Nrxstats        = 8,
258         Ntxstats        = 9,
259
260         Txcopy          = 128,
261 };
262
263 typedef struct Ctlr Ctlr;
264 typedef struct Ctlr {
265         int     port;
266         Pcidev* pcidev;
267         Ctlr*   next;
268         int     active;
269         int     id;
270         uchar   par[Eaddrlen];
271
272         QLock   alock;                  /* attach */
273         void*   alloc;                  /* receive/transmit descriptors */
274         int     cls;                    /* alignment */
275         int     nrd;
276         int     ntd;
277
278         Ds*     rd;
279         Ds*     rdh;
280
281         Lock    tlock;
282         Ds*     td;
283         Ds*     tdh;
284         Ds*     tdt;
285         int     tdused;
286
287         Lock    clock;                  /*  */
288         int     cr;
289         int     imr;
290         int     tft;                    /* Tx threshold */
291
292         Mii*    mii;
293         Rendez  lrendez;
294         int     lwakeup;
295
296         uint    rxstats[Nrxstats];      /* statistics */
297         uint    txstats[Ntxstats];
298         uint    intr;
299         uint    lintr;
300         uint    lsleep;
301         uint    rintr;
302         uint    tintr;
303         uint    taligned;
304         uint    tsplit;
305         uint    tcopied;
306         uint    txdw;
307 } Ctlr;
308
309 static Ctlr* vt6102ctlrhead;
310 static Ctlr* vt6102ctlrtail;
311
312 #define csr8r(c, r)     (inb((c)->port+(r)))
313 #define csr16r(c, r)    (ins((c)->port+(r)))
314 #define csr32r(c, r)    (inl((c)->port+(r)))
315 #define csr8w(c, r, b)  (outb((c)->port+(r), (int)(b)))
316 #define csr16w(c, r, w) (outs((c)->port+(r), (ushort)(w)))
317 #define csr32w(c, r, w) (outl((c)->port+(r), (ulong)(w)))
318
319 static char* rxstats[Nrxstats] = {
320         "Receiver Error",
321         "CRC Error",
322         "Frame Alignment Error",
323         "FIFO Overflow",
324         "Long Packet",
325         "Runt Packet",
326         "System Error",
327         "Buffer Underflow Error",
328 };
329 static char* txstats[Ntxstats] = {
330         "Aborted after Excessive Collisions",
331         "Out of Window Collision Seen",
332         "Carrier Sense Lost",
333         "FIFO Underflow",
334         "Invalid Td",
335         "System Error",
336         nil,
337         "Excessive Collisions",
338 };
339
340 static long
341 vt6102ifstat(Ether* edev, void* a, long n, ulong offset)
342 {
343         char *p;
344         Ctlr *ctlr;
345         int i, l, r;
346
347         ctlr = edev->ctlr;
348
349         p = malloc(READSTR);
350         l = 0;
351         for(i = 0; i < Nrxstats; i++){
352                 l += snprint(p+l, READSTR-l, "%s: %ud\n",
353                         rxstats[i], ctlr->rxstats[i]);
354         }
355         for(i = 0; i < Ntxstats; i++){
356                 if(txstats[i] == nil)
357                         continue;
358                 l += snprint(p+l, READSTR-l, "%s: %ud\n",
359                         txstats[i], ctlr->txstats[i]);
360         }
361         l += snprint(p+l, READSTR-l, "cls: %ud\n", ctlr->cls);
362         l += snprint(p+l, READSTR-l, "intr: %ud\n", ctlr->intr);
363         l += snprint(p+l, READSTR-l, "lintr: %ud\n", ctlr->lintr);
364         l += snprint(p+l, READSTR-l, "lsleep: %ud\n", ctlr->lsleep);
365         l += snprint(p+l, READSTR-l, "rintr: %ud\n", ctlr->rintr);
366         l += snprint(p+l, READSTR-l, "tintr: %ud\n", ctlr->tintr);
367         l += snprint(p+l, READSTR-l, "taligned: %ud\n", ctlr->taligned);
368         l += snprint(p+l, READSTR-l, "tsplit: %ud\n", ctlr->tsplit);
369         l += snprint(p+l, READSTR-l, "tcopied: %ud\n", ctlr->tcopied);
370         l += snprint(p+l, READSTR-l, "txdw: %ud\n", ctlr->txdw);
371         l += snprint(p+l, READSTR-l, "tft: %ud\n", ctlr->tft);
372
373         if(ctlr->mii != nil && ctlr->mii->curphy != nil){
374                 l += snprint(p+l, READSTR, "phy:   ");
375                 for(i = 0; i < NMiiPhyr; i++){
376                         if(i && ((i & 0x07) == 0))
377                                 l += snprint(p+l, READSTR-l, "\n       ");
378                         r = miimir(ctlr->mii, i);
379                         l += snprint(p+l, READSTR-l, " %4.4uX", r);
380                 }
381                 snprint(p+l, READSTR-l, "\n");
382         }
383         snprint(p+l, READSTR-l, "\n");
384
385         n = readstr(offset, a, n, p);
386         free(p);
387
388         return n;
389 }
390
391 static void
392 vt6102promiscuous(void* arg, int on)
393 {
394         int rcr;
395         Ctlr *ctlr;
396         Ether *edev;
397
398         edev = arg;
399         ctlr = edev->ctlr;
400         rcr = csr8r(ctlr, Rcr);
401         if(on)
402                 rcr |= Prom;
403         else
404                 rcr &= ~Prom;
405         csr8w(ctlr, Rcr, rcr);
406 }
407
408 static void
409 vt6102multicast(void* arg, uchar* addr, int on)
410 {
411         /*
412          * For now Am is set in Rcr.
413          * Will need to interlock with promiscuous
414          * when this gets filled in.
415          */
416         USED(arg, addr, on);
417 }
418
419 static int
420 vt6102wakeup(void* v)
421 {
422         return *((int*)v) != 0;
423 }
424
425 static void
426 vt6102imr(Ctlr* ctlr, int imr)
427 {
428         ilock(&ctlr->clock);
429         ctlr->imr |= imr;
430         csr16w(ctlr, Imr, ctlr->imr);
431         iunlock(&ctlr->clock);
432 }
433
434 static void
435 vt6102lproc(void* arg)
436 {
437         Ctlr *ctlr;
438         Ether *edev;
439         MiiPhy *phy;
440
441         edev = arg;
442         ctlr = edev->ctlr;
443         for(;;){
444                 if(ctlr->mii == nil || ctlr->mii->curphy == nil)
445                         break;
446                 if(miistatus(ctlr->mii) < 0)
447                         goto enable;
448
449                 phy = ctlr->mii->curphy;
450                 ilock(&ctlr->clock);
451                 if(phy->fd)
452                         ctlr->cr |= Fdx;
453                 else
454                         ctlr->cr &= ~Fdx;
455                 csr16w(ctlr, Cr, ctlr->cr);
456                 iunlock(&ctlr->clock);
457 enable:
458                 ctlr->lwakeup = 0;
459                 vt6102imr(ctlr, Srci);
460
461                 ctlr->lsleep++;
462                 sleep(&ctlr->lrendez, vt6102wakeup, &ctlr->lwakeup);
463
464         }
465         pexit("vt6102lproc: done", 1);
466 }
467
468 static void
469 vt6102attach(Ether* edev)
470 {
471         int i;
472         Ctlr *ctlr;
473         Ds *ds, *prev;
474         uchar *alloc, *bounce;
475         char name[KNAMELEN];
476
477         ctlr = edev->ctlr;
478         qlock(&ctlr->alock);
479         if(ctlr->alloc != nil){
480                 qunlock(&ctlr->alock);
481                 return;
482         }
483
484         /*
485          * Descriptor and bounce-buffer space.
486          * Must all be aligned on a 4-byte boundary,
487          * but try to align on cache-lines.
488          */
489         ctlr->nrd = Nrd;
490         ctlr->ntd = Ntd;
491         alloc = malloc((ctlr->nrd+ctlr->ntd)*ctlr->cls + ctlr->ntd*Txcopy + ctlr->cls-1);
492         if(alloc == nil){
493                 qunlock(&ctlr->alock);
494                 return;
495         }
496         ctlr->alloc = alloc;
497         alloc = (uchar*)ROUNDUP((ulong)alloc, ctlr->cls);
498
499         ctlr->rd = (Ds*)alloc;
500
501         if(waserror()){
502                 ds = ctlr->rd;
503                 for(i = 0; i < ctlr->nrd; i++){
504                         if(ds->bp != nil){
505                                 freeb(ds->bp);
506                                 ds->bp = nil;
507                         }
508                         if((ds = ds->next) == nil)
509                                 break;
510                 }
511                 free(ctlr->alloc);
512                 ctlr->alloc = nil;
513                 qunlock(&ctlr->alock);
514                 nexterror();
515         }
516
517         prev = ctlr->rd + ctlr->nrd-1;
518         for(i = 0; i < ctlr->nrd; i++){
519                 ds = (Ds*)alloc;
520                 alloc += ctlr->cls;
521
522                 ds->control = Rdbsz;
523                 ds->branch = PCIWADDR(alloc);
524
525                 ds->bp = iallocb(Rdbsz+3);
526                 if(ds->bp == nil)
527                         error("vt6102: can't allocate receive ring\n");
528                 ds->bp->rp = (uchar*)ROUNDUP((ulong)ds->bp->rp, 4);
529                 ds->addr = PCIWADDR(ds->bp->rp);
530
531                 ds->next = (Ds*)alloc;
532                 ds->prev = prev;
533                 prev = ds;
534
535                 ds->status = Own;
536         }
537         prev->branch = 0;
538         prev->next = ctlr->rd;
539         prev->status = 0;
540         ctlr->rdh = ctlr->rd;
541
542         ctlr->td = (Ds*)alloc;
543         prev = ctlr->td + ctlr->ntd-1;
544         bounce = alloc + ctlr->ntd*ctlr->cls;
545         for(i = 0; i < ctlr->ntd; i++){
546                 ds = (Ds*)alloc;
547                 alloc += ctlr->cls;
548
549                 ds->bounce = bounce;
550                 bounce += Txcopy;
551                 ds->next = (Ds*)alloc;
552                 ds->prev = prev;
553                 prev = ds;
554         }
555         prev->next = ctlr->td;
556         ctlr->tdh = ctlr->tdt = ctlr->td;
557         ctlr->tdused = 0;
558
559         ctlr->cr = Dpoll|Rdmd|Txon|Rxon|Strt;
560         /*Srci|Abti|Norbf|Pktrace|Ovfi|Udfi|Be|Ru|Tu|Txe|Rxe|Ptx|Prx*/
561         ctlr->imr = Abti|Norbf|Pktrace|Ovfi|Udfi|Be|Ru|Tu|Txe|Rxe|Ptx|Prx;
562
563         ilock(&ctlr->clock);
564         csr32w(ctlr, Rxdaddr, PCIWADDR(ctlr->rd));
565         csr32w(ctlr, Txdaddr, PCIWADDR(ctlr->td));
566         csr16w(ctlr, Isr, ~0);
567         csr16w(ctlr, Imr, ctlr->imr);
568         csr16w(ctlr, Cr, ctlr->cr);
569         iunlock(&ctlr->clock);
570
571         snprint(name, KNAMELEN, "#l%dlproc", edev->ctlrno);
572         kproc(name, vt6102lproc, edev);
573
574         qunlock(&ctlr->alock);
575         poperror();
576 }
577
578 static void
579 vt6102transmit(Ether* edev)
580 {
581         Block *bp;
582         Ctlr *ctlr;
583         Ds *ds, *next;
584         int control, i, o, prefix, size, tdused, timeo;
585
586         ctlr = edev->ctlr;
587
588         ilock(&ctlr->tlock);
589
590         /*
591          * Free any completed packets
592          */
593         ds = ctlr->tdh;
594         for(tdused = ctlr->tdused; tdused > 0; tdused--){
595                 /*
596                  * For some errors the chip will turn the Tx engine
597                  * off. Wait for that to happen.
598                  * Could reset and re-init the chip here if it doesn't
599                  * play fair.
600                  * To do: adjust Tx FIFO threshold on underflow.
601                  */
602                 if(ds->status & (Abt|Tbuff|Udf)){
603                         for(timeo = 0; timeo < 1000; timeo++){
604                                 if(!(csr16r(ctlr, Cr) & Txon))
605                                         break;
606                                 microdelay(1);
607                         }
608                         ds->status = Own;
609                         csr32w(ctlr, Txdaddr, PCIWADDR(ds));
610                 }
611
612                 if(ds->status & Own)
613                         break;
614                 ds->addr = 0;
615                 ds->branch = 0;
616
617                 if(ds->bp != nil){
618                         freeb(ds->bp);
619                         ds->bp = nil;
620                 }
621                 for(i = 0; i < Ntxstats-1; i++){
622                         if(ds->status & (1<<i))
623                                 ctlr->txstats[i]++;
624                 }
625                 ctlr->txstats[i] += (ds->status & NcrMASK)>>NcrSHIFT;
626
627                 ds = ds->next;
628         }
629         ctlr->tdh = ds;
630
631         /*
632          * Try to fill the ring back up.
633          */
634         ds = ctlr->tdt;
635         while(tdused < ctlr->ntd-2){
636                 if((bp = qget(edev->oq)) == nil)
637                         break;
638                 tdused++;
639
640                 size = BLEN(bp);
641                 prefix = 0;
642
643                 if(o = (((int)bp->rp) & 0x03)){
644                         prefix = Txcopy-o;
645                         if(prefix > size)
646                                 prefix = size;
647                         memmove(ds->bounce, bp->rp, prefix);
648                         ds->addr = PCIWADDR(ds->bounce);
649                         bp->rp += prefix;
650                         size -= prefix;
651                 }
652
653                 next = ds->next;
654                 ds->branch = PCIWADDR(ds->next);
655
656                 if(size){
657                         if(prefix){
658                                 next->bp = bp;
659                                 next->addr = PCIWADDR(bp->rp);
660                                 next->branch = PCIWADDR(next->next);
661                                 next->control = Edp|Chain|((size<<TbsSHIFT) & TbsMASK);
662
663                                 control = Stp|Chain|((prefix<<TbsSHIFT) & TbsMASK);
664
665                                 next = next->next;
666                                 tdused++;
667                                 ctlr->tsplit++;
668                         }
669                         else{
670                                 ds->bp = bp;
671                                 ds->addr = PCIWADDR(bp->rp);
672                                 control = Edp|Stp|((size<<TbsSHIFT) & TbsMASK);
673                                 ctlr->taligned++;
674                         }
675                 }
676                 else{
677                         freeb(bp);
678                         control = Edp|Stp|((prefix<<TbsSHIFT) & TbsMASK);
679                         ctlr->tcopied++;
680                 }
681
682                 ds->control = control;
683                 if(tdused >= ctlr->ntd-2){
684                         ds->control |= Ic;
685                         ctlr->txdw++;
686                 }
687                 coherence();
688                 ds->status = Own;
689
690                 ds = next;
691         }
692         ctlr->tdt = ds;
693         ctlr->tdused = tdused;
694         if(ctlr->tdused)
695                 csr16w(ctlr, Cr, Tdmd|ctlr->cr);
696
697         iunlock(&ctlr->tlock);
698 }
699
700 static void
701 vt6102receive(Ether* edev)
702 {
703         Ds *ds;
704         Block *bp;
705         Ctlr *ctlr;
706         int i, len;
707
708         ctlr = edev->ctlr;
709
710         ds = ctlr->rdh;
711         while(!(ds->status & Own) && ds->status != 0){
712                 if(ds->status & Rerr){
713                         for(i = 0; i < Nrxstats; i++){
714                                 if(ds->status & (1<<i))
715                                         ctlr->rxstats[i]++;
716                         }
717                 }
718                 else if(bp = iallocb(Rdbsz+3)){
719                         len = ((ds->status & LengthMASK)>>LengthSHIFT)-4;
720                         ds->bp->wp = ds->bp->rp+len;
721                         etheriq(edev, ds->bp, 1);
722                         bp->rp = (uchar*)ROUNDUP((ulong)bp->rp, 4);
723                         ds->addr = PCIWADDR(bp->rp);
724                         ds->bp = bp;
725                 }
726                 ds->control = Rdbsz;
727                 ds->branch = 0;
728                 ds->status = 0;
729
730                 ds->prev->branch = PCIWADDR(ds);
731                 coherence();
732                 ds->prev->status = Own;
733
734                 ds = ds->next;
735         }
736         ctlr->rdh = ds;
737
738         csr16w(ctlr, Cr, ctlr->cr);
739 }
740
741 static void
742 vt6102interrupt(Ureg*, void* arg)
743 {
744         Ctlr *ctlr;
745         Ether *edev;
746         int imr, isr, r, timeo;
747
748         edev = arg;
749         ctlr = edev->ctlr;
750
751         ilock(&ctlr->clock);
752         csr16w(ctlr, Imr, 0);
753         imr = ctlr->imr;
754         ctlr->intr++;
755         for(;;){
756                 if((isr = csr16r(ctlr, Isr)) != 0)
757                         csr16w(ctlr, Isr, isr);
758                 if((isr & ctlr->imr) == 0)
759                         break;
760                         
761                 if(isr & Srci){
762                         imr &= ~Srci;
763                         ctlr->lwakeup = isr & Srci;
764                         wakeup(&ctlr->lrendez);
765                         isr &= ~Srci;
766                         ctlr->lintr++;
767                 }
768                 if(isr & (Norbf|Pktrace|Ovfi|Ru|Rxe|Prx)){
769                         vt6102receive(edev);
770                         isr &= ~(Norbf|Pktrace|Ovfi|Ru|Rxe|Prx);
771                         ctlr->rintr++;
772                 }
773                 if(isr & (Abti|Udfi|Tu|Txe|Ptx)){
774                         if(isr & (Abti|Udfi|Tu)){
775                                 for(timeo = 0; timeo < 1000; timeo++){
776                                         if(!(csr16r(ctlr, Cr) & Txon))
777                                                 break;
778                                         microdelay(1);
779                                 }
780
781                                 if((isr & Udfi) && ctlr->tft < CtftSAF){
782                                         ctlr->tft += 1<<CtftSHIFT;
783                                         r = csr8r(ctlr, Bcr1) & ~CtftMASK;
784                                         csr8w(ctlr, Bcr1, r|ctlr->tft);
785                                 }
786                         }
787                         vt6102transmit(edev);
788                         isr &= ~(Abti|Udfi|Tu|Txe|Ptx);
789                         ctlr->tintr++;
790                 }
791                 if(isr)
792                         panic("vt6102: isr %4.4uX\n", isr);
793         }
794         ctlr->imr = imr;
795         csr16w(ctlr, Imr, ctlr->imr);
796         iunlock(&ctlr->clock);
797 }
798
799 static int
800 vt6102miimicmd(Mii* mii, int pa, int ra, int cmd, int data)
801 {
802         Ctlr *ctlr;
803         int r, timeo;
804
805         ctlr = mii->ctlr;
806
807         csr8w(ctlr, Miicr, 0);
808         r = csr8r(ctlr, Phyadr);
809         csr8w(ctlr, Phyadr, (r & ~PhyadMASK)|pa);
810         csr8w(ctlr, Phyadr, pa);
811         csr8w(ctlr, Miiadr, ra);
812         if(cmd == Wcmd)
813                 csr16w(ctlr, Miidata, data);
814         csr8w(ctlr, Miicr, cmd);
815
816         for(timeo = 0; timeo < 10000; timeo++){
817                 if(!(csr8r(ctlr, Miicr) & cmd))
818                         break;
819                 microdelay(1);
820         }
821         if(timeo >= 10000)
822                 return -1;
823
824         if(cmd == Wcmd)
825                 return 0;
826         return csr16r(ctlr, Miidata);
827 }
828
829 static int
830 vt6102miimir(Mii* mii, int pa, int ra)
831 {
832         return vt6102miimicmd(mii, pa, ra, Rcmd, 0);
833 }
834
835 static int
836 vt6102miimiw(Mii* mii, int pa, int ra, int data)
837 {
838         return vt6102miimicmd(mii, pa, ra, Wcmd, data);
839 }
840
841 static int
842 vt6102detach(Ctlr* ctlr)
843 {
844         int revid, timeo;
845
846         /*
847          * Reset power management registers.
848          */
849         revid = pcicfgr8(ctlr->pcidev, PciRID);
850         if(revid >= 0x40){
851                 /* Set power state D0. */
852                 csr8w(ctlr, Stickhw, csr8r(ctlr, Stickhw) & 0xFC);
853
854                 /* Disable force PME-enable. */
855                 csr8w(ctlr, Wolcgclr, 0x80);
856
857                 /* Clear WOL config and status bits. */
858                 csr8w(ctlr, Wolcrclr, 0xFF);
859                 csr8w(ctlr, Pwrcsrclr, 0xFF);
860         }
861
862         /*
863          * Soft reset the controller.
864          */
865         csr16w(ctlr, Cr, Stop);
866         csr16w(ctlr, Cr, Stop|Sfrst);
867         for(timeo = 0; timeo < 10000; timeo++){
868                 if(!(csr16r(ctlr, Cr) & Sfrst))
869                         break;
870                 microdelay(1);
871         }
872         if(timeo >= 1000)
873                 return -1;
874
875         return 0;
876 }
877
878 static int
879 vt6102reset(Ctlr* ctlr)
880 {
881         MiiPhy *phy;
882         int i, r, timeo;
883
884         if(vt6102detach(ctlr) < 0)
885                 return -1;
886
887         /*
888          * Load the MAC address into the PAR[01]
889          * registers.
890          */
891         r = csr8r(ctlr, Eecsr);
892         csr8w(ctlr, Eecsr, Autold|r);
893         for(timeo = 0; timeo < 100; timeo++){
894                 if(!(csr8r(ctlr, Cr) & Autold))
895                         break;
896                 microdelay(1);
897         }
898         if(timeo >= 100)
899                 return -1;
900
901         for(i = 0; i < Eaddrlen; i++)
902                 ctlr->par[i] = csr8r(ctlr, Par0+i);
903
904         /*
905          * Configure DMA and Rx/Tx thresholds.
906          * If the Rx/Tx threshold bits in Bcr[01] are 0 then
907          * the thresholds are determined by Rcr/Tcr.
908          */
909         r = csr8r(ctlr, Bcr0) & ~(CrftMASK|DmaMASK);
910         csr8w(ctlr, Bcr0, r|Crft64|Dma64);
911         r = csr8r(ctlr, Bcr1) & ~CtftMASK;
912         csr8w(ctlr, Bcr1, r|ctlr->tft);
913
914         r = csr8r(ctlr, Rcr) & ~(RrftMASK|Prom|Ar|Sep);
915         csr8w(ctlr, Rcr, r|Ab|Am);
916         csr32w(ctlr, Mcfilt0, ~0UL);    /* accept all multicast */
917         csr32w(ctlr, Mcfilt1, ~0UL);
918
919         r = csr8r(ctlr, Tcr) & ~(RtsfMASK|Ofset|Lb1|Lb0);
920         csr8w(ctlr, Tcr, r);
921
922         /*
923          * Link management.
924          */
925         if((ctlr->mii = malloc(sizeof(Mii))) == nil)
926                 return -1;
927         ctlr->mii->mir = vt6102miimir;
928         ctlr->mii->miw = vt6102miimiw;
929         ctlr->mii->ctlr = ctlr;
930
931         if(mii(ctlr->mii, ~0) == 0 || (phy = ctlr->mii->curphy) == nil){
932                 free(ctlr->mii);
933                 ctlr->mii = nil;
934                 return -1;
935         }
936         // print("oui %X phyno %d\n", phy->oui, phy->phyno);
937         USED(phy);
938
939         //miiane(ctlr->mii, ~0, ~0, ~0);
940
941         return 0;
942 }
943
944 static void
945 vt6102pci(void)
946 {
947         Pcidev *p;
948         Ctlr *ctlr;
949         int cls, port;
950
951         p = nil;
952         while(p = pcimatch(p, 0, 0)){
953                 if(p->ccrb != Pcibcnet || p->ccru != Pciscether)
954                         continue;
955
956                 switch((p->did<<16)|p->vid){
957                 default:
958                         continue;
959                 case (0x3065<<16)|0x1106:       /* Rhine II */
960                 case (0x3106<<16)|0x1106:       /* Rhine III */
961                         break;
962                 }
963
964                 port = p->mem[0].bar & ~0x01;
965                 if(ioalloc(port, p->mem[0].size, 0, "vt6102") < 0){
966                         print("vt6102: port 0x%uX in use\n", port);
967                         continue;
968                 }
969                 ctlr = malloc(sizeof(Ctlr));
970                 ctlr->port = port;
971                 ctlr->pcidev = p;
972                 ctlr->id = (p->did<<16)|p->vid;
973                 if((cls = pcicfgr8(p, PciCLS)) == 0 || cls == 0xFF)
974                         cls = 0x10;
975                 ctlr->cls = cls*4;
976                 if(ctlr->cls < sizeof(Ds)){
977                         print("vt6102: cls %d < sizeof(Ds)\n", ctlr->cls);
978                         iofree(port);
979                         free(ctlr);
980                         continue;
981                 }
982                 ctlr->tft = Ctft64;
983
984                 if(vt6102reset(ctlr)){
985                         iofree(port);
986                         free(ctlr);
987                         continue;
988                 }
989                 pcisetbme(p);
990
991                 if(vt6102ctlrhead != nil)
992                         vt6102ctlrtail->next = ctlr;
993                 else
994                         vt6102ctlrhead = ctlr;
995                 vt6102ctlrtail = ctlr;
996         }
997 }
998
999 static int
1000 vt6102pnp(Ether* edev)
1001 {
1002         Ctlr *ctlr;
1003
1004         if(vt6102ctlrhead == nil)
1005                 vt6102pci();
1006
1007         /*
1008          * Any adapter matches if no edev->port is supplied,
1009          * otherwise the ports must match.
1010          */
1011         for(ctlr = vt6102ctlrhead; ctlr != nil; ctlr = ctlr->next){
1012                 if(ctlr->active)
1013                         continue;
1014                 if(edev->port == 0 || edev->port == ctlr->port){
1015                         ctlr->active = 1;
1016                         break;
1017                 }
1018         }
1019         if(ctlr == nil)
1020                 return -1;
1021
1022         edev->ctlr = ctlr;
1023         edev->port = ctlr->port;
1024         edev->irq = ctlr->pcidev->intl;
1025         edev->tbdf = ctlr->pcidev->tbdf;
1026         edev->mbps = 100;
1027         memmove(edev->ea, ctlr->par, Eaddrlen);
1028
1029         /*
1030          * Linkage to the generic ethernet driver.
1031          */
1032         edev->attach = vt6102attach;
1033         edev->transmit = vt6102transmit;
1034         edev->interrupt = vt6102interrupt;
1035         edev->ifstat = vt6102ifstat;
1036         edev->ctl = nil;
1037
1038         edev->arg = edev;
1039         edev->promiscuous = vt6102promiscuous;
1040         edev->multicast = vt6102multicast;
1041
1042         return 0;
1043 }
1044
1045 void
1046 ethervt6102link(void)
1047 {
1048         addethercard("vt6102", vt6102pnp);
1049         addethercard("rhine", vt6102pnp);
1050 }