]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/ethervt6105m.c
kernel: move common ethermii to port/
[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 #include "../port/etherif.h"
24 #include "../port/ethermii.h"
25
26 enum {
27         Par0            = 0x00,                 /* Ethernet Address */
28         Rcr             = 0x06,                 /* Receive Configuration */
29         Tcr             = 0x07,                 /* Transmit Configuration */
30         Cr              = 0x08,                 /* Control */
31         Tqw             = 0x0A,                 /* Transmit Queue Wake */
32         Isr             = 0x0C,                 /* Interrupt Status */
33         Imr             = 0x0E,                 /* Interrupt Mask */
34         Mcfilt0         = 0x10,                 /* Multicast Filter 0 */
35         Mcfilt1         = 0x14,                 /* Multicast Filter 1 */
36         Rxdaddr         = 0x18,                 /* Current Rd Address */
37         Txdaddr         = 0x1C,                 /* Current Td Address */
38         Phyadr          = 0x6C,                 /* Phy Address */
39         Miisr           = 0x6D,                 /* MII Status */
40         Bcr0            = 0x6E,                 /* Bus Control */
41         Bcr1            = 0x6F,
42         Miicr           = 0x70,                 /* MII Control */
43         Miiadr          = 0x71,                 /* MII Address */
44         Miidata         = 0x72,                 /* MII Data */
45         Eecsr           = 0x74,                 /* EEPROM Control and Status */
46         CfgA            = 0x78,                 /* Chip Configuration A */
47         CfgB            = 0x79,
48         CfgC            = 0x7A,
49         CfgD            = 0x7B,
50         Cr0             = 0x80,                 /* Miscellaneous Control */
51         Cr1             = 0x81,
52         Pmcc            = 0x82,                 /* Power Mgmt Capability Control */
53         Stickhw         = 0x83,                 /* Sticky Hardware Control */
54         Misr            = 0x84,                 /* MII Interrupt Control */
55         Mimr            = 0x85,                 /* MII Interrupt Mask */
56         Wolcrclr        = 0xA4,
57         Wolcgclr        = 0xA7,
58         Pwrcsrclr       = 0xAC,
59 };
60
61 enum {                                          /* Rcr */
62         Sep             = 0x01,                 /* Accept Error Packets */
63         Ar              = 0x02,                 /* Accept Small Packets */
64         Am              = 0x04,                 /* Accept Multicast */
65         Ab              = 0x08,                 /* Accept Broadcast */
66         Prom            = 0x10,                 /* Accept Physical Address Packets */
67         RrftMASK        = 0xE0,                 /* Receive FIFO Threshold */
68         RrftSHIFT       = 5,
69         Rrft64          = 0<<RrftSHIFT,
70         Rrft32          = 1<<RrftSHIFT,
71         Rrft128         = 2<<RrftSHIFT,
72         Rrft256         = 3<<RrftSHIFT,
73         Rrft512         = 4<<RrftSHIFT,
74         Rrft768         = 5<<RrftSHIFT,
75         Rrft1024        = 6<<RrftSHIFT,
76         RrftSAF         = 7<<RrftSHIFT,
77 };
78
79 enum {                                          /* Tcr */
80         Lb0             = 0x02,                 /* Loopback Mode */
81         Lb1             = 0x04,
82         Ofset           = 0x08,                 /* Select Back-off Priority */
83         RtsfMASK        = 0xE0,                 /* Transmit FIFO Threshold */
84         RtsfSHIFT       = 5,
85         Rtsf128         = 0<<RtsfSHIFT,
86         Rtsf256         = 1<<RtsfSHIFT,
87         Rtsf512         = 2<<RtsfSHIFT,
88         Rtsf1024        = 3<<RtsfSHIFT,
89         RtsfSAF         = 7<<RtsfSHIFT,
90 };
91
92 enum {                                          /* Cr */
93         Init            = 0x0001,               /* INIT Process Begin */
94         Strt            = 0x0002,               /* Start NIC */
95         Stop            = 0x0004,               /* Stop NIC */
96         Rxon            = 0x0008,               /* Turn on Receive Process */
97         Txon            = 0x0010,               /* Turn on Transmit Process */
98         Tdmd            = 0x0020,               /* Transmit Poll Demand */
99         Rdmd            = 0x0040,               /* Receive Poll Demand */
100         Eren            = 0x0100,               /* Early Receive Enable */
101         Fdx             = 0x0400,               /* Set MAC to Full Duplex */
102         Dpoll           = 0x0800,               /* Disable Td/Rd Auto Polling */
103         Tdmd1           = 0x2000,               /* Transmit Poll Demand 1 */
104         Rdmd1           = 0x4000,               /* Receive Poll Demand 1 */
105         Sfrst           = 0x8000,               /* Software Reset */
106 };
107
108 enum {                                          /* Isr/Imr */
109         Prx             = 0x0001,               /* Packet Received OK */
110         Ptx             = 0x0002,               /* Packet Transmitted OK */
111         Rxe             = 0x0004,               /* Receive Error */
112         Txe             = 0x0008,               /* Transmit Error */
113         Tu              = 0x0010,               /* Transmit Buffer Underflow */
114         Ru              = 0x0020,               /* Receive Buffer Link Error */
115         Be              = 0x0040,               /* PCI Bus Error */
116         Cnt             = 0x0080,               /* Counter Overflow */
117         Eri             = 0x0100,               /* Early Receive Interrupt */
118         Udfi            = 0x0200,               /* Tx FIFO Underflow */
119         Ovfi            = 0x0400,               /* Receive FIFO Overflow */
120         Pktrace         = 0x0800,               /* Hmmm... */
121         Norbf           = 0x1000,               /* No Receive Buffers */
122         Abti            = 0x2000,               /* Transmission Abort */
123         Srci            = 0x4000,               /* Port State Change */
124         Geni            = 0x8000,               /* General Purpose Interrupt */
125 };
126
127 enum {                                          /* Phyadr */
128         PhyadMASK       = 0x1F,                 /* PHY Address */
129         PhyadSHIFT      = 0,
130         Mfdc            = 0x20,                 /* Accelerate MDC Speed */
131         Mpo0            = 0x40,                 /* MII Polling Timer Interval */
132         Mpo1            = 0x80,
133 };
134
135 enum {                                          /* Bcr0 */
136         DmaMASK         = 0x07,                 /* DMA Length */
137         DmaSHIFT        = 0,
138         Dma32           = 0<<DmaSHIFT,
139         Dma64           = 1<<DmaSHIFT,
140         Dma128          = 2<<DmaSHIFT,
141         Dma256          = 3<<DmaSHIFT,
142         Dma512          = 4<<DmaSHIFT,
143         Dma1024         = 5<<DmaSHIFT,
144         DmaSAF          = 7<<DmaSHIFT,
145         CrftMASK        = 0x38,                 /* Rx FIFO Threshold */
146         CrftSHIFT       = 3,
147         Crft64          = 1<<CrftSHIFT,
148         Crft128         = 2<<CrftSHIFT,
149         Crft256         = 3<<CrftSHIFT,
150         Crft512         = 4<<CrftSHIFT,
151         Crft1024        = 5<<CrftSHIFT,
152         CrftSAF         = 7<<CrftSHIFT,
153         Extled          = 0x40,                 /* Extra LED Support Control */
154         Med2            = 0x80,                 /* Medium Select Control */
155 };
156
157 enum {                                          /* Bcr1 */
158         PotMASK         = 0x07,                 /* Polling Timer Interval */
159         PotSHIFT        = 0,
160         CtftMASK        = 0x38,                 /* Tx FIFO Threshold */
161         CtftSHIFT       = 3,
162         Ctft64          = 1<<CtftSHIFT,
163         Ctft128         = 2<<CtftSHIFT,
164         Ctft256         = 3<<CtftSHIFT,
165         Ctft512         = 4<<CtftSHIFT,
166         Ctft1024        = 5<<CtftSHIFT,
167         CtftSAF         = 7<<CtftSHIFT,
168 };
169
170 enum {                                          /* Miicr */
171         Mdc             = 0x01,                 /* Clock */
172         Mdi             = 0x02,                 /* Data In */
173         Mdo             = 0x04,                 /* Data Out */
174         Mout            = 0x08,                 /* Output Enable */
175         Mdpm            = 0x10,                 /* Direct Program Mode Enable */
176         Wcmd            = 0x20,                 /* Write Enable */
177         Rcmd            = 0x40,                 /* Read Enable */
178         Mauto           = 0x80,                 /* Auto Polling Enable */
179 };
180
181 enum {                                          /* Miiadr */
182         MadMASK         = 0x1F,                 /* MII Port Address */
183         MadSHIFT        = 0,
184         Mdone           = 0x20,                 /* Accelerate MDC Speed */
185         Msrcen          = 0x40,                 /* MII Polling Timer Interval */
186         Midle           = 0x80,
187 };
188
189 enum {                                          /* Eecsr */
190         Edo             = 0x01,                 /* Data Out */
191         Edi             = 0x02,                 /* Data In */
192         Eck             = 0x04,                 /* Clock */
193         Ecs             = 0x08,                 /* Chip Select */
194         Dpm             = 0x10,                 /* Direct Program Mode Enable */
195         Autold          = 0x20,                 /* Dynamic Reload */
196         Embp            = 0x40,                 /* Embedded Program Enable */
197         Eepr            = 0x80,                 /* Programmed */
198 };
199
200 /*
201  * Ring descriptor. The space allocated for each
202  * of these will be rounded up to a cache-line boundary.
203  * The first 4 elements are known to the hardware.
204  */
205 typedef struct Ds Ds;
206 typedef struct Ds {
207         u32int  status;
208         u32int  control;
209         u32int  addr;
210         u32int  branch;
211
212         Block*  bp;
213         Ds*     next;
214         Ds*     prev;
215 } Ds;
216
217 enum {                                          /* Rx Ds status */
218         Rerr            = 0x00000001,           /* Buff|Rxserr|Fov|Fae|Crc */
219         Crc             = 0x00000002,           /* CRC Error */
220         Fae             = 0x00000004,           /* Frame Alignment Error */
221         Fov             = 0x00000008,           /* FIFO Overflow */
222         Long            = 0x00000010,           /* A Long Packet */
223         Runt            = 0x00000020,           /* A Runt Packet */
224         Rxserr          = 0x00000040,           /* System Error */
225         Buff            = 0x00000080,           /* Buffer Underflow Error */
226         Rxedp           = 0x00000100,           /* End of Packet Buffer */
227         Rxstp           = 0x00000200,           /* Packet Start */
228         Chn             = 0x00000400,           /* Chain Buffer */
229         Phy             = 0x00000800,           /* Physical Address Packet */
230         Bar             = 0x00001000,           /* Broadcast Packet */
231         Mar             = 0x00002000,           /* Multicast Packet */
232         Rxok            = 0x00008000,           /* Packet Received OK */
233         LengthMASK      = 0x07FF0000,           /* Received Packet Length */
234         LengthSHIFT     = 16,
235
236         Own             = 0x80000000,           /* Descriptor Owned by NIC */
237 };
238
239 enum {                                          /* Rx Ds control */
240         RbsizeMASK      = 0x000007FF,           /* Receive Buffer Size */
241         RbsizeSHIFT     = 0,
242         Tag             = 0x00010000,           /* Receive a Tagged Packet */
243         Udpkt           = 0x00020000,           /* Receive a UDP Packet */
244         Tcpkt           = 0x00040000,           /* Receive a TCP Packet */
245         Ipkt            = 0x00080000,           /* Receive an IP Packet */
246         Tuok            = 0x00100000,           /* TCP/UDP Checksum OK */
247         Ipok            = 0x00200000,           /* IP Checksum OK */
248         Snaptag         = 0x00400000,           /* Snap Packet + 802.1q Tag */
249         Rxlerr          = 0x00800000,           /* Receive Length Check Error */
250         IpktMASK        = 0xff000000,           /* Interesting Packet */
251         IpktSHIFT       = 24,
252 };
253
254 enum {                                          /* Tx Ds status */
255         NcrMASK         = 0x0000000F,           /* Collision Retry Count */
256         NcrSHIFT        = 0,
257         Cols            = 0x00000010,           /* Experienced Collisions */
258         Cdh             = 0x00000080,           /* CD Heartbeat */
259         Abt             = 0x00000100,           /* Aborted after Excessive Collisions */
260         Owc             = 0x00000200,           /* Out of Window Collision */
261         Crs             = 0x00000400,           /* Carrier Sense Lost */
262         Udf             = 0x00000800,           /* FIFO Underflow */
263         Tbuff           = 0x00001000,           /* Invalid Td */
264         Txserr          = 0x00002000,           /* System Error */
265         Terr            = 0x00008000,           /* Excessive Collisions */
266 };
267
268 enum {                                          /* Tx Ds control */
269         TbsMASK         = 0x000007FF,           /* Tx Buffer Size */
270         TbsSHIFT        = 0,
271         Chain           = 0x00008000,           /* Chain Buffer */
272         Crcdisable      = 0x00010000,           /* Disable CRC generation */
273         Stp             = 0x00200000,           /* Start of Packet */
274         Edp             = 0x00400000,           /* End of Packet */
275         Ic              = 0x00800000,           /* Interrupt Control */
276 };
277
278 enum {                                          /* Tx Ds branch */
279         Tdctl           = 0x00000001,           /* No Interrupt Generated */
280 };
281
282 enum {
283         Nrd             = 196,
284         Ntd             = 128,
285         Crcsz           = 4,
286         Bslop           = 48,
287         Rdbsz           = ETHERMAXTU+Crcsz+Bslop,
288
289         Nrxstats        = 8,
290         Ntxstats        = 9,
291
292         Txcopy          = 128,
293 };
294
295 typedef struct Ctlr Ctlr;
296 typedef struct Ctlr {
297         int     port;
298         Pcidev* pcidev;
299         Ctlr*   next;
300         int     active;
301         int     id;
302         uchar   par[Eaddrlen];
303
304         QLock   alock;                          /* attach */
305         void*   alloc;                          /* descriptors, etc. */
306         int     cls;                            /* alignment */
307         int     nrd;
308         int     ntd;
309
310         Ds*     rd;
311         Ds*     rdh;
312
313         Lock    tlock;
314         Ds*     td;
315         Ds*     tdh;
316         Ds*     tdt;
317         int     tdused;
318
319         Lock    clock;                          /*  */
320         int     cr;
321         int     imr;
322         int     tft;                            /* Tx threshold */
323
324         Mii*    mii;
325         Rendez  lrendez;
326         int     lwakeup;
327
328         uint    rxstats[Nrxstats];              /* statistics */
329         uint    txstats[Ntxstats];
330         ulong   totalt;
331         uint    intr;
332         uint    lintr;                  
333         uint    lsleep;
334         uint    rintr;
335         uint    tintr;
336         uint    txdw;
337         int     tdumax;
338
339         uint    abt;
340         uint    tbuff;
341         uint    udf;
342
343         uint    abti;
344         uint    udfi;
345         uint    tu;
346
347         uint    tuok;
348         uint    ipok;
349 } Ctlr;
350
351 static Ctlr* vt6105Mctlrhead;
352 static Ctlr* vt6105Mctlrtail;
353
354 #define csr8r(c, r)     (inb((c)->port+(r)))
355 #define csr16r(c, r)    (ins((c)->port+(r)))
356 #define csr32r(c, r)    (inl((c)->port+(r)))
357 #define csr8w(c, r, b)  (outb((c)->port+(r), (int)(b)))
358 #define csr16w(c, r, w) (outs((c)->port+(r), (ushort)(w)))
359 #define csr32w(c, r, w) (outl((c)->port+(r), (ulong)(w)))
360
361 static Lock vt6105Mrblock;                      /* receive Block freelist */
362 static Block* vt6105Mrbpool;
363 static uint vt6105Mrbpoolsz;
364
365 typedef struct Regs Regs;
366 typedef struct Regs {
367         char*   name;
368         int     offset;
369         int     size;
370 } Regs;
371
372 static Regs regs[] = {
373 //      "Par0",         Par0,   1,
374 //      "Par1",         Par0+1, 1,
375 //      "Par2",         Par0+2, 1,
376 //      "Par3",         Par0+3, 1,
377 //      "Par4",         Par0+4, 1,
378 //      "Par5",         Par0+5, 1,
379         "Rcr",          Rcr,    1,
380         "Tcr",          Tcr,    1,
381         "Cr0",          Cr,     1,
382         "Cr1",          Cr+1,   1,
383         "Isr0",         Isr,    1,
384         "Isr1",         Isr+1,  1,
385         "Imr0",         Imr,    1,
386         "Imr1",         Imr+1,  1,
387 //      "Mcfilt0",      Mcfilt0,4,
388 //      "Mcfilt1",      Mcfilt1,4,
389 //      "Rxdaddr",      Rxdaddr,4,
390 //      "Txdaddr",      Txdaddr,4,
391         "Phyadr",       Phyadr, 1,
392         "Miisr",        Miisr,  1,
393         "Bcr0",         Bcr0,   1,
394         "Bcr1",         Bcr1,   1,
395         "Miicr",        Miicr,  1,
396         "Miiadr",       Miiadr, 1,
397 //      "Miidata",      Miidata,2,
398         "Eecsr",        Eecsr,  1,
399         "CfgA",         CfgA,   1,
400         "CfgB",         CfgB,   1,
401         "CfgC",         CfgC,   1,
402         "CfgD",         CfgD,   1,
403         "Cr0",          Cr0,    1,
404         "Cr1",          Cr1,    1,
405         "Pmcc",         Pmcc,   1,
406         "Stickhw",      Stickhw,1,
407         "Misr",         Misr,   1,
408         "Mimr",         Mimr,   1,
409         nil,
410 };
411
412 static char* rxstats[Nrxstats] = {
413         "Receiver Error",
414         "CRC Error",
415         "Frame Alignment Error",
416         "FIFO Overflow",
417         "Long Packet",
418         "Runt Packet",
419         "System Error",
420         "Buffer Underflow Error",
421 };
422 static char* txstats[Ntxstats] = {
423         "Aborted after Excessive Collisions",
424         "Out of Window Collision Seen",
425         "Carrier Sense Lost",
426         "FIFO Underflow",
427         "Invalid Td",
428         "System Error",
429         nil,
430         "Excessive Collisions",
431 };
432
433 static long
434 vt6105Mifstat(Ether* edev, void* a, long n, ulong offset)
435 {
436         int i, r;
437         Ctlr *ctlr;
438         char *alloc, *e, *p;
439
440         ctlr = edev->ctlr;
441         
442         p = alloc = smalloc(READSTR);
443         e = p + READSTR;
444         for(i = 0; i < Nrxstats; i++){
445                 p = seprint(p, e, "%s: %ud\n", rxstats[i], ctlr->rxstats[i]);
446         }
447         for(i = 0; i < Ntxstats; i++){
448                 if(txstats[i] == nil)
449                         continue;
450                 p = seprint(p, e, "%s: %ud\n", txstats[i], ctlr->txstats[i]);
451         }
452         p = seprint(p, e, "cls: %ud\n", ctlr->cls);
453         p = seprint(p, e, "intr: %ud\n", ctlr->intr);
454         p = seprint(p, e, "lintr: %ud\n", ctlr->lintr);
455         p = seprint(p, e, "lsleep: %ud\n", ctlr->lsleep);
456         p = seprint(p, e, "rintr: %ud\n", ctlr->rintr);
457         p = seprint(p, e, "tintr: %ud\n", ctlr->tintr);
458         p = seprint(p, e, "txdw: %ud\n", ctlr->txdw);
459         p = seprint(p, e, "tdumax: %ud\n", ctlr->tdumax);
460         p = seprint(p, e, "tft: %ud\n", ctlr->tft);
461
462         p = seprint(p, e, "abt: %ud\n", ctlr->abt);
463         p = seprint(p, e, "tbuff: %ud\n", ctlr->tbuff);
464         p = seprint(p, e, "udf: %ud\n", ctlr->udf);
465         p = seprint(p, e, "abti: %ud\n", ctlr->abti);
466         p = seprint(p, e, "udfi: %ud\n", ctlr->udfi);
467         p = seprint(p, e, "tu: %ud\n", ctlr->tu);
468
469         p = seprint(p, e, "tuok: %ud\n", ctlr->tuok);
470         p = seprint(p, e, "ipok: %ud\n", ctlr->ipok);
471
472         p = seprint(p, e, "rbpoolsz: %ud\n", vt6105Mrbpoolsz);
473         p = seprint(p, e, "totalt: %uld\n", ctlr->totalt);
474
475         for(i = 0; regs[i].name != nil; i++){
476                 p = seprint(p, e, "%s: %2.2x\n",
477                         regs[i].name,  csr8r(ctlr, regs[i].offset));
478         }
479
480         if(ctlr->mii != nil && ctlr->mii->curphy != nil){
481                 p = seprint(p, e, "phy:   ");
482                 for(i = 0; i < NMiiPhyr; i++){
483                         if(i && ((i & 0x07) == 0))
484                                 p = seprint(p, e, "\n       ");
485                         r = miimir(ctlr->mii, i);
486                         p = seprint(p, e, " %4.4uX", r);
487                 }
488                 seprint(p, e, "\n");
489         }
490
491         n = readstr(offset, a, n, alloc);
492         free(alloc);
493
494         return n;
495 }
496
497 static void
498 vt6105Mpromiscuous(void* arg, int on)
499 {
500         int rcr;
501         Ctlr *ctlr;
502         Ether *edev;
503
504         edev = arg;
505         ctlr = edev->ctlr;
506         rcr = csr8r(ctlr, Rcr);
507         if(on)
508                 rcr |= Prom;
509         else
510                 rcr &= ~Prom;
511         csr8w(ctlr, Rcr, rcr);
512 }
513
514 static void
515 vt6105Mmulticast(void* arg, uchar* addr, int on)
516 {
517         /*
518          * For now Am is set in Rcr.
519          * Will need to interlock with promiscuous
520          * when this gets filled in.
521          */
522         USED(arg, addr, on);
523 }
524
525 static int
526 vt6105Mwakeup(void* v)
527 {
528         return *((int*)v) != 0;
529 }
530
531 static void
532 vt6105Mimr(Ctlr* ctlr, int imr)
533 {
534         ilock(&ctlr->clock);
535         ctlr->imr |= imr;
536         csr16w(ctlr, Imr, ctlr->imr);
537         iunlock(&ctlr->clock);
538 }
539
540 static void
541 vt6105Mlproc(void* arg)
542 {
543         Ctlr *ctlr;
544         Ether *edev;
545         MiiPhy *phy;
546
547         edev = arg;
548         ctlr = edev->ctlr;
549         while(waserror())
550                 ;
551         for(;;){
552                 if(ctlr->mii == nil || ctlr->mii->curphy == nil)
553                         break;
554                 if(miistatus(ctlr->mii) < 0)
555                         goto enable;
556
557                 phy = ctlr->mii->curphy;
558                 ilock(&ctlr->clock);
559                 csr16w(ctlr, Cr, ctlr->cr & ~(Txon|Rxon));
560                 if(phy->fd)
561                         ctlr->cr |= Fdx;
562                 else
563                         ctlr->cr &= ~Fdx;
564                 csr16w(ctlr, Cr, ctlr->cr);
565                 iunlock(&ctlr->clock);
566 enable:
567                 ctlr->lwakeup = 0;
568                 vt6105Mimr(ctlr, Srci);
569
570                 ctlr->lsleep++;
571                 sleep(&ctlr->lrendez, vt6105Mwakeup, &ctlr->lwakeup);
572
573         }
574         pexit("vt6105Mlproc: done", 1);
575 }
576
577 static void
578 vt6105Mrbfree(Block* bp)
579 {
580         bp->rp = bp->lim - (Rdbsz+3);
581         bp->wp = bp->rp;
582         bp->flag &= ~(Bipck | Budpck | Btcpck | Bpktck);
583
584         ilock(&vt6105Mrblock);
585         bp->next = vt6105Mrbpool;
586         vt6105Mrbpool = bp;
587         iunlock(&vt6105Mrblock);
588 }
589
590 static Block*
591 vt6105Mrballoc(void)
592 {
593         Block *bp;
594
595         ilock(&vt6105Mrblock);
596         if((bp = vt6105Mrbpool) != nil){
597                 vt6105Mrbpool = bp->next;
598                 bp->next = nil;
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);
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         /* limit used to be 10000, but that wasn't enough for our Soekris 5501s */
1029         for(timeo = 0; timeo < 100000; timeo++){
1030                 if(!(csr16r(ctlr, Cr) & Sfrst))
1031                         break;
1032                 microdelay(1);
1033         }
1034         if(timeo >= 100000)
1035                 return -1;
1036
1037         return 0;
1038 }
1039
1040 static int
1041 vt6105Mreset(Ctlr* ctlr)
1042 {
1043         MiiPhy *phy;
1044         int i, r, timeo;
1045
1046         if(vt6105Mdetach(ctlr) < 0)
1047                 return -1;
1048
1049         /*
1050          * Load the MAC address into the PAR[01]
1051          * registers.
1052          */
1053         r = csr8r(ctlr, Eecsr);
1054         csr8w(ctlr, Eecsr, Autold|r);
1055         /* limit used to be 100, but that wasn't enough for our Soekris 5501s */
1056         for(timeo = 0; timeo < 100000; timeo++){
1057                 if(!(csr8r(ctlr, Cr) & Autold))
1058                         break;
1059                 microdelay(1);
1060         }
1061         if(timeo >= 100000)
1062                 return -1;
1063
1064         for(i = 0; i < Eaddrlen; i++)
1065                 ctlr->par[i] = csr8r(ctlr, Par0+i);
1066
1067         /*
1068          * Configure DMA and Rx/Tx thresholds.
1069          * If the Rx/Tx threshold bits in Bcr[01] are 0 then
1070          * the thresholds are determined by Rcr/Tcr.
1071          */
1072         r = csr8r(ctlr, Bcr0) & ~(CrftMASK|DmaMASK);
1073         csr8w(ctlr, Bcr0, r|Crft128|DmaSAF);
1074         r = csr8r(ctlr, Bcr1) & ~CtftMASK;
1075         csr8w(ctlr, Bcr1, r|ctlr->tft);
1076
1077         r = csr8r(ctlr, Rcr) & ~(RrftMASK|Prom|Ar|Sep);
1078         csr8w(ctlr, Rcr, r|Ab|Am);
1079         csr32w(ctlr, Mcfilt0, ~0UL);    /* accept all multicast */
1080         csr32w(ctlr, Mcfilt1, ~0UL);
1081
1082         r = csr8r(ctlr, Tcr) & ~(RtsfMASK|Ofset|Lb1|Lb0);
1083         csr8w(ctlr, Tcr, r);
1084
1085         /*
1086          * Link management.
1087          */
1088         if((ctlr->mii = malloc(sizeof(Mii))) == nil)
1089                 return -1;
1090         ctlr->mii->mir = vt6105Mmiimir;
1091         ctlr->mii->miw = vt6105Mmiimiw;
1092         ctlr->mii->ctlr = ctlr;
1093
1094         if(mii(ctlr->mii, ~0) == 0 || (phy = ctlr->mii->curphy) == nil){
1095                 free(ctlr->mii);
1096                 ctlr->mii = nil;
1097                 return -1;
1098         }
1099 //      print("oui %X phyno %d\n", phy->oui, phy->phyno);
1100         USED(phy);
1101
1102         if(miistatus(ctlr->mii) < 0){
1103 //              miireset(ctlr->mii);
1104                 miiane(ctlr->mii, ~0, ~0, ~0);
1105         }
1106
1107         return 0;
1108 }
1109
1110 static void
1111 vt6105Mpci(void)
1112 {
1113         Pcidev *p;
1114         Ctlr *ctlr;
1115         int cls, port;
1116
1117         p = nil;
1118         while(p = pcimatch(p, 0, 0)){
1119                 if(p->ccrb != Pcibcnet || p->ccru != Pciscether)
1120                         continue;
1121
1122                 switch((p->did<<16)|p->vid){
1123                 default:
1124                         continue;
1125                 case (0x3053<<16)|0x1106:       /* Rhine III-M vt6105M */
1126                         break;
1127                 }
1128
1129                 port = p->mem[0].bar & ~0x01;
1130                 if(ioalloc(port, p->mem[0].size, 0, "vt6105M") < 0){
1131                         print("vt6105M: port 0x%uX in use\n", port);
1132                         continue;
1133                 }
1134                 ctlr = malloc(sizeof(Ctlr));
1135                 if(ctlr == nil){
1136                         print("vt6105M: can't allocate memory\n");
1137                         iofree(port);
1138                         continue;
1139                 }
1140                 ctlr->port = port;
1141                 ctlr->pcidev = p;
1142                 pcienable(p);
1143                 ctlr->id = (p->did<<16)|p->vid;
1144                 if((cls = pcicfgr8(p, PciCLS)) == 0 || cls == 0xFF)
1145                         cls = 0x10;
1146                 ctlr->cls = cls*4;
1147                 ctlr->tft = CtftSAF;
1148
1149                 if(vt6105Mreset(ctlr)){
1150                         iofree(port);
1151                         free(ctlr);
1152                         continue;
1153                 }
1154                 pcisetbme(p);
1155
1156                 if(vt6105Mctlrhead != nil)
1157                         vt6105Mctlrtail->next = ctlr;
1158                 else
1159                         vt6105Mctlrhead = ctlr;
1160                 vt6105Mctlrtail = ctlr;
1161         }
1162 }
1163
1164 static int
1165 vt6105Mpnp(Ether* edev)
1166 {
1167         Ctlr *ctlr;
1168
1169         if(vt6105Mctlrhead == nil)
1170                 vt6105Mpci();
1171
1172         /*
1173          * Any adapter matches if no edev->port is supplied,
1174          * otherwise the ports must match.
1175          */
1176         for(ctlr = vt6105Mctlrhead; ctlr != nil; ctlr = ctlr->next){
1177                 if(ctlr->active)
1178                         continue;
1179                 if(edev->port == 0 || edev->port == ctlr->port){
1180                         ctlr->active = 1;
1181                         break;
1182                 }
1183         }
1184         if(ctlr == nil)
1185                 return -1;
1186
1187         edev->ctlr = ctlr;
1188         edev->port = ctlr->port;
1189         edev->irq = ctlr->pcidev->intl;
1190         edev->tbdf = ctlr->pcidev->tbdf;
1191         /*
1192          * Set to 1000Mb/s to fool the bsz calculation.  We need 
1193          * something better, though.
1194          */
1195         edev->mbps = 1000;
1196         memmove(edev->ea, ctlr->par, Eaddrlen);
1197
1198         /*
1199          * Linkage to the generic ethernet driver.
1200          */
1201         edev->attach = vt6105Mattach;
1202         edev->transmit = vt6105Mtransmit;
1203         edev->ifstat = vt6105Mifstat;
1204         edev->ctl = nil;
1205
1206         edev->arg = edev;
1207         edev->promiscuous = vt6105Mpromiscuous;
1208         edev->multicast = vt6105Mmulticast;
1209
1210         edev->maxmtu = ETHERMAXTU+Bslop;
1211
1212         intrenable(edev->irq, vt6105Minterrupt, edev, edev->tbdf, edev->name);
1213
1214         return 0;
1215 }
1216
1217 void
1218 ethervt6105mlink(void)
1219 {
1220         addethercard("vt6105M", vt6105Mpnp);
1221 }