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