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