]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/ethervt6102.c
kernel: massive pci code rewrite
[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/pci.h"
19 #include "../port/error.h"
20 #include "../port/netif.h"
21 #include "../port/etherif.h"
22 #include "../port/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 = smalloc(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-l, "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         while(waserror())
444                 ;
445         for(;;){
446                 if(ctlr->mii == nil || ctlr->mii->curphy == nil)
447                         break;
448                 if(miistatus(ctlr->mii) < 0)
449                         goto enable;
450
451                 phy = ctlr->mii->curphy;
452                 ilock(&ctlr->clock);
453                 if(phy->fd)
454                         ctlr->cr |= Fdx;
455                 else
456                         ctlr->cr &= ~Fdx;
457                 csr16w(ctlr, Cr, ctlr->cr);
458                 iunlock(&ctlr->clock);
459 enable:
460                 ctlr->lwakeup = 0;
461                 vt6102imr(ctlr, Srci);
462
463                 ctlr->lsleep++;
464                 sleep(&ctlr->lrendez, vt6102wakeup, &ctlr->lwakeup);
465
466         }
467         pexit("vt6102lproc: done", 1);
468 }
469
470 static void
471 vt6102attach(Ether* edev)
472 {
473         int dsz, i;
474         Ctlr *ctlr;
475         Ds *ds, *prev;
476         uchar *alloc, *bounce;
477         char name[KNAMELEN];
478
479         ctlr = edev->ctlr;
480         qlock(&ctlr->alock);
481         if(ctlr->alloc != nil){
482                 qunlock(&ctlr->alock);
483                 return;
484         }
485
486         /*
487          * Descriptor and bounce-buffer space.
488          * Must all be aligned on a 4-byte boundary,
489          * but try to align on cache-lines.
490          */
491         ctlr->nrd = Nrd;
492         ctlr->ntd = Ntd;
493         dsz = ROUNDUP(sizeof(Ds), ctlr->cls);
494         alloc = mallocalign((ctlr->nrd+ctlr->ntd)*dsz + ctlr->ntd*Txcopy, dsz, 0, 0);
495         if(alloc == nil){
496                 qunlock(&ctlr->alock);
497                 error(Enomem);
498         }
499         ctlr->alloc = alloc;
500
501         ctlr->rd = (Ds*)alloc;
502
503         if(waserror()){
504                 ds = ctlr->rd;
505                 for(i = 0; i < ctlr->nrd; i++){
506                         if(ds->bp != nil){
507                                 freeb(ds->bp);
508                                 ds->bp = nil;
509                         }
510                         if((ds = ds->next) == nil)
511                                 break;
512                 }
513                 free(ctlr->alloc);
514                 ctlr->alloc = nil;
515                 qunlock(&ctlr->alock);
516                 nexterror();
517         }
518
519         prev = ctlr->rd + ctlr->nrd-1;
520         for(i = 0; i < ctlr->nrd; i++){
521                 ds = (Ds*)alloc;
522                 alloc += dsz;
523
524                 ds->control = Rdbsz;
525                 ds->branch = PCIWADDR(alloc);
526
527                 ds->bp = iallocb(Rdbsz+3);
528                 if(ds->bp == nil)
529                         error("vt6102: can't allocate receive ring\n");
530                 ds->bp->rp = (uchar*)ROUNDUP((ulong)ds->bp->rp, 4);
531                 ds->addr = PCIWADDR(ds->bp->rp);
532
533                 ds->next = (Ds*)alloc;
534                 ds->prev = prev;
535                 prev = ds;
536
537                 ds->status = Own;
538         }
539         prev->branch = 0;
540         prev->next = ctlr->rd;
541         prev->status = 0;
542         ctlr->rdh = ctlr->rd;
543
544         ctlr->td = (Ds*)alloc;
545         prev = ctlr->td + ctlr->ntd-1;
546         bounce = alloc + ctlr->ntd*dsz;
547         for(i = 0; i < ctlr->ntd; i++){
548                 ds = (Ds*)alloc;
549                 alloc += dsz;
550
551                 ds->bounce = bounce;
552                 bounce += Txcopy;
553                 ds->next = (Ds*)alloc;
554                 ds->prev = prev;
555                 prev = ds;
556         }
557         prev->next = ctlr->td;
558         ctlr->tdh = ctlr->tdt = ctlr->td;
559         ctlr->tdused = 0;
560
561         ctlr->cr = Dpoll|Rdmd|Txon|Rxon|Strt;
562         /*Srci|Abti|Norbf|Pktrace|Ovfi|Udfi|Be|Ru|Tu|Txe|Rxe|Ptx|Prx*/
563         ctlr->imr = Abti|Norbf|Pktrace|Ovfi|Udfi|Be|Ru|Tu|Txe|Rxe|Ptx|Prx;
564
565         ilock(&ctlr->clock);
566         csr32w(ctlr, Rxdaddr, PCIWADDR(ctlr->rd));
567         csr32w(ctlr, Txdaddr, PCIWADDR(ctlr->td));
568         csr16w(ctlr, Isr, ~0);
569         csr16w(ctlr, Imr, ctlr->imr);
570         csr16w(ctlr, Cr, ctlr->cr);
571         iunlock(&ctlr->clock);
572
573         snprint(name, KNAMELEN, "#l%dlproc", edev->ctlrno);
574         kproc(name, vt6102lproc, edev);
575
576         qunlock(&ctlr->alock);
577         poperror();
578 }
579
580 static void
581 vt6102transmit(Ether* edev)
582 {
583         Block *bp;
584         Ctlr *ctlr;
585         Ds *ds, *next;
586         int control, i, o, prefix, size, tdused, timeo;
587
588         ctlr = edev->ctlr;
589
590         ilock(&ctlr->tlock);
591
592         /*
593          * Free any completed packets
594          */
595         ds = ctlr->tdh;
596         for(tdused = ctlr->tdused; tdused > 0; tdused--){
597                 /*
598                  * For some errors the chip will turn the Tx engine
599                  * off. Wait for that to happen.
600                  * Could reset and re-init the chip here if it doesn't
601                  * play fair.
602                  * To do: adjust Tx FIFO threshold on underflow.
603                  */
604                 if(ds->status & (Abt|Tbuff|Udf)){
605                         for(timeo = 0; timeo < 1000; timeo++){
606                                 if(!(csr16r(ctlr, Cr) & Txon))
607                                         break;
608                                 microdelay(1);
609                         }
610                         ds->status = Own;
611                         csr32w(ctlr, Txdaddr, PCIWADDR(ds));
612                 }
613
614                 if(ds->status & Own)
615                         break;
616                 ds->addr = 0;
617                 ds->branch = 0;
618
619                 if(ds->bp != nil){
620                         freeb(ds->bp);
621                         ds->bp = nil;
622                 }
623                 for(i = 0; i < Ntxstats-1; i++){
624                         if(ds->status & (1<<i))
625                                 ctlr->txstats[i]++;
626                 }
627                 ctlr->txstats[i] += (ds->status & NcrMASK)>>NcrSHIFT;
628
629                 ds = ds->next;
630         }
631         ctlr->tdh = ds;
632
633         /*
634          * Try to fill the ring back up.
635          */
636         ds = ctlr->tdt;
637         while(tdused < ctlr->ntd-2){
638                 if((bp = qget(edev->oq)) == nil)
639                         break;
640                 tdused++;
641
642                 size = BLEN(bp);
643                 prefix = 0;
644
645                 if(o = (((int)bp->rp) & 0x03)){
646                         prefix = Txcopy-o;
647                         if(prefix > size)
648                                 prefix = size;
649                         memmove(ds->bounce, bp->rp, prefix);
650                         ds->addr = PCIWADDR(ds->bounce);
651                         bp->rp += prefix;
652                         size -= prefix;
653                 }
654
655                 next = ds->next;
656                 ds->branch = PCIWADDR(ds->next);
657
658                 if(size){
659                         if(prefix){
660                                 next->bp = bp;
661                                 next->addr = PCIWADDR(bp->rp);
662                                 next->branch = PCIWADDR(next->next);
663                                 next->control = Edp|Chain|((size<<TbsSHIFT) & TbsMASK);
664
665                                 control = Stp|Chain|((prefix<<TbsSHIFT) & TbsMASK);
666
667                                 next = next->next;
668                                 tdused++;
669                                 ctlr->tsplit++;
670                         }
671                         else{
672                                 ds->bp = bp;
673                                 ds->addr = PCIWADDR(bp->rp);
674                                 control = Edp|Stp|((size<<TbsSHIFT) & TbsMASK);
675                                 ctlr->taligned++;
676                         }
677                 }
678                 else{
679                         freeb(bp);
680                         control = Edp|Stp|((prefix<<TbsSHIFT) & TbsMASK);
681                         ctlr->tcopied++;
682                 }
683
684                 ds->control = control;
685                 if(tdused >= ctlr->ntd-2){
686                         ds->control |= Ic;
687                         ctlr->txdw++;
688                 }
689                 coherence();
690                 ds->status = Own;
691
692                 ds = next;
693         }
694         ctlr->tdt = ds;
695         ctlr->tdused = tdused;
696         if(ctlr->tdused)
697                 csr16w(ctlr, Cr, Tdmd|ctlr->cr);
698
699         iunlock(&ctlr->tlock);
700 }
701
702 static void
703 vt6102receive(Ether* edev)
704 {
705         Ds *ds;
706         Block *bp;
707         Ctlr *ctlr;
708         int i, len;
709
710         ctlr = edev->ctlr;
711
712         ds = ctlr->rdh;
713         while(!(ds->status & Own) && ds->status != 0){
714                 if(ds->status & Rerr){
715                         for(i = 0; i < Nrxstats; i++){
716                                 if(ds->status & (1<<i))
717                                         ctlr->rxstats[i]++;
718                         }
719                 }
720                 else if(bp = iallocb(Rdbsz+3)){
721                         len = ((ds->status & LengthMASK)>>LengthSHIFT)-4;
722                         ds->bp->wp = ds->bp->rp+len;
723                         etheriq(edev, ds->bp);
724                         bp->rp = (uchar*)ROUNDUP((ulong)bp->rp, 4);
725                         ds->addr = PCIWADDR(bp->rp);
726                         ds->bp = bp;
727                 }
728                 ds->control = Rdbsz;
729                 ds->branch = 0;
730                 ds->status = 0;
731
732                 ds->prev->branch = PCIWADDR(ds);
733                 coherence();
734                 ds->prev->status = Own;
735
736                 ds = ds->next;
737         }
738         ctlr->rdh = ds;
739
740         csr16w(ctlr, Cr, ctlr->cr);
741 }
742
743 static void
744 vt6102interrupt(Ureg*, void* arg)
745 {
746         Ctlr *ctlr;
747         Ether *edev;
748         int imr, isr, r, timeo;
749
750         edev = arg;
751         ctlr = edev->ctlr;
752
753         ilock(&ctlr->clock);
754         csr16w(ctlr, Imr, 0);
755         imr = ctlr->imr;
756         ctlr->intr++;
757         for(;;){
758                 if((isr = csr16r(ctlr, Isr)) != 0)
759                         csr16w(ctlr, Isr, isr);
760                 if((isr & ctlr->imr) == 0)
761                         break;
762                         
763                 if(isr & Srci){
764                         imr &= ~Srci;
765                         ctlr->lwakeup = isr & Srci;
766                         wakeup(&ctlr->lrendez);
767                         isr &= ~Srci;
768                         ctlr->lintr++;
769                 }
770                 if(isr & (Norbf|Pktrace|Ovfi|Ru|Rxe|Prx)){
771                         vt6102receive(edev);
772                         isr &= ~(Norbf|Pktrace|Ovfi|Ru|Rxe|Prx);
773                         ctlr->rintr++;
774                 }
775                 if(isr & (Abti|Udfi|Tu|Txe|Ptx)){
776                         if(isr & (Abti|Udfi|Tu)){
777                                 for(timeo = 0; timeo < 1000; timeo++){
778                                         if(!(csr16r(ctlr, Cr) & Txon))
779                                                 break;
780                                         microdelay(1);
781                                 }
782
783                                 if((isr & Udfi) && ctlr->tft < CtftSAF){
784                                         ctlr->tft += 1<<CtftSHIFT;
785                                         r = csr8r(ctlr, Bcr1) & ~CtftMASK;
786                                         csr8w(ctlr, Bcr1, r|ctlr->tft);
787                                 }
788                         }
789                         vt6102transmit(edev);
790                         isr &= ~(Abti|Udfi|Tu|Txe|Ptx);
791                         ctlr->tintr++;
792                 }
793                 if(isr)
794                         panic("vt6102: isr %4.4uX", isr);
795         }
796         ctlr->imr = imr;
797         csr16w(ctlr, Imr, ctlr->imr);
798         iunlock(&ctlr->clock);
799 }
800
801 static int
802 vt6102miimicmd(Mii* mii, int pa, int ra, int cmd, int data)
803 {
804         Ctlr *ctlr;
805         int r, timeo;
806
807         ctlr = mii->ctlr;
808
809         csr8w(ctlr, Miicr, 0);
810         r = csr8r(ctlr, Phyadr);
811         csr8w(ctlr, Phyadr, (r & ~PhyadMASK)|pa);
812         csr8w(ctlr, Phyadr, pa);
813         csr8w(ctlr, Miiadr, ra);
814         if(cmd == Wcmd)
815                 csr16w(ctlr, Miidata, data);
816         csr8w(ctlr, Miicr, cmd);
817
818         for(timeo = 0; timeo < 10000; timeo++){
819                 if(!(csr8r(ctlr, Miicr) & cmd))
820                         break;
821                 microdelay(1);
822         }
823         if(timeo >= 10000)
824                 return -1;
825
826         if(cmd == Wcmd)
827                 return 0;
828         return csr16r(ctlr, Miidata);
829 }
830
831 static int
832 vt6102miimir(Mii* mii, int pa, int ra)
833 {
834         return vt6102miimicmd(mii, pa, ra, Rcmd, 0);
835 }
836
837 static int
838 vt6102miimiw(Mii* mii, int pa, int ra, int data)
839 {
840         return vt6102miimicmd(mii, pa, ra, Wcmd, data);
841 }
842
843 static int
844 vt6102detach(Ctlr* ctlr)
845 {
846         int revid, timeo;
847
848         /*
849          * Reset power management registers.
850          */
851         revid = pcicfgr8(ctlr->pcidev, PciRID);
852         if(revid >= 0x40){
853                 /* Set power state D0. */
854                 csr8w(ctlr, Stickhw, csr8r(ctlr, Stickhw) & 0xFC);
855
856                 /* Disable force PME-enable. */
857                 csr8w(ctlr, Wolcgclr, 0x80);
858
859                 /* Clear WOL config and status bits. */
860                 csr8w(ctlr, Wolcrclr, 0xFF);
861                 csr8w(ctlr, Pwrcsrclr, 0xFF);
862         }
863
864         /*
865          * Soft reset the controller.
866          */
867         csr16w(ctlr, Cr, Stop);
868         csr16w(ctlr, Cr, Stop|Sfrst);
869         for(timeo = 0; timeo < 10000; timeo++){
870                 if(!(csr16r(ctlr, Cr) & Sfrst))
871                         break;
872                 microdelay(1);
873         }
874         if(timeo >= 1000)
875                 return -1;
876
877         return 0;
878 }
879
880 static int
881 vt6102reset(Ctlr* ctlr)
882 {
883         MiiPhy *phy;
884         int i, r, timeo;
885
886         if(vt6102detach(ctlr) < 0)
887                 return -1;
888
889         /*
890          * Load the MAC address into the PAR[01]
891          * registers.
892          */
893         r = csr8r(ctlr, Eecsr);
894         csr8w(ctlr, Eecsr, Autold|r);
895         for(timeo = 0; timeo < 100; timeo++){
896                 if(!(csr8r(ctlr, Cr) & Autold))
897                         break;
898                 microdelay(1);
899         }
900         if(timeo >= 100)
901                 return -1;
902
903         for(i = 0; i < Eaddrlen; i++)
904                 ctlr->par[i] = csr8r(ctlr, Par0+i);
905
906         /*
907          * Configure DMA and Rx/Tx thresholds.
908          * If the Rx/Tx threshold bits in Bcr[01] are 0 then
909          * the thresholds are determined by Rcr/Tcr.
910          */
911         r = csr8r(ctlr, Bcr0) & ~(CrftMASK|DmaMASK);
912         csr8w(ctlr, Bcr0, r|Crft64|Dma64);
913         r = csr8r(ctlr, Bcr1) & ~CtftMASK;
914         csr8w(ctlr, Bcr1, r|ctlr->tft);
915
916         r = csr8r(ctlr, Rcr) & ~(RrftMASK|Prom|Ar|Sep);
917         csr8w(ctlr, Rcr, r|Ab|Am);
918         csr32w(ctlr, Mcfilt0, ~0UL);    /* accept all multicast */
919         csr32w(ctlr, Mcfilt1, ~0UL);
920
921         r = csr8r(ctlr, Tcr) & ~(RtsfMASK|Ofset|Lb1|Lb0);
922         csr8w(ctlr, Tcr, r);
923
924         /*
925          * Link management.
926          */
927         if((ctlr->mii = malloc(sizeof(Mii))) == nil)
928                 return -1;
929         ctlr->mii->mir = vt6102miimir;
930         ctlr->mii->miw = vt6102miimiw;
931         ctlr->mii->ctlr = ctlr;
932
933         if(mii(ctlr->mii, ~0) == 0 || (phy = ctlr->mii->curphy) == nil){
934                 free(ctlr->mii);
935                 ctlr->mii = nil;
936                 return -1;
937         }
938         // print("oui %X phyno %d\n", phy->oui, phy->phyno);
939         USED(phy);
940
941         //miiane(ctlr->mii, ~0, ~0, ~0);
942
943         return 0;
944 }
945
946 static void
947 vt6102pci(void)
948 {
949         Pcidev *p;
950         Ctlr *ctlr;
951         int port;
952
953         p = nil;
954         while(p = pcimatch(p, 0, 0)){
955                 if(p->ccrb != Pcibcnet || p->ccru != Pciscether)
956                         continue;
957
958                 switch((p->did<<16)|p->vid){
959                 default:
960                         continue;
961                 case (0x3065<<16)|0x1106:       /* Rhine II */
962                 case (0x3106<<16)|0x1106:       /* Rhine III */
963                         break;
964                 }
965
966                 port = p->mem[0].bar & ~3;
967                 if(ioalloc(port, p->mem[0].size, 0, "vt6102") < 0){
968                         print("vt6102: port 0x%uX in use\n", port);
969                         continue;
970                 }
971                 ctlr = malloc(sizeof(Ctlr));
972                 if(ctlr == nil){
973                         print("vt6102: can't allocate memory\n");
974                         iofree(port);
975                         continue;
976                 }
977                 ctlr->port = port;
978                 ctlr->pcidev = p;
979                 pcienable(p);
980                 ctlr->id = (p->did<<16)|p->vid;
981                 ctlr->cls = p->cls*4;
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->ifstat = vt6102ifstat;
1035         edev->ctl = nil;
1036
1037         edev->arg = edev;
1038         edev->promiscuous = vt6102promiscuous;
1039         edev->multicast = vt6102multicast;
1040
1041         intrenable(edev->irq, vt6102interrupt, edev, edev->tbdf, edev->name);
1042
1043         return 0;
1044 }
1045
1046 void
1047 ethervt6102link(void)
1048 {
1049         addethercard("vt6102", vt6102pnp);
1050         addethercard("rhine", vt6102pnp);
1051 }