]> 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/pci.h"
22 #include "../port/error.h"
23 #include "../port/netif.h"
24 #include "../port/etherif.h"
25 #include "../port/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         while(waserror())
551                 ;
552         for(;;){
553                 if(ctlr->mii == nil || ctlr->mii->curphy == nil)
554                         break;
555                 if(miistatus(ctlr->mii) < 0)
556                         goto enable;
557
558                 phy = ctlr->mii->curphy;
559                 ilock(&ctlr->clock);
560                 csr16w(ctlr, Cr, ctlr->cr & ~(Txon|Rxon));
561                 if(phy->fd)
562                         ctlr->cr |= Fdx;
563                 else
564                         ctlr->cr &= ~Fdx;
565                 csr16w(ctlr, Cr, ctlr->cr);
566                 iunlock(&ctlr->clock);
567 enable:
568                 ctlr->lwakeup = 0;
569                 vt6105Mimr(ctlr, Srci);
570
571                 ctlr->lsleep++;
572                 sleep(&ctlr->lrendez, vt6105Mwakeup, &ctlr->lwakeup);
573
574         }
575         pexit("vt6105Mlproc: done", 1);
576 }
577
578 static void
579 vt6105Mrbfree(Block* bp)
580 {
581         bp->rp = bp->lim - (Rdbsz+3);
582         bp->wp = bp->rp;
583         bp->flag &= ~(Bipck | Budpck | Btcpck | Bpktck);
584
585         ilock(&vt6105Mrblock);
586         bp->next = vt6105Mrbpool;
587         vt6105Mrbpool = bp;
588         iunlock(&vt6105Mrblock);
589 }
590
591 static Block*
592 vt6105Mrballoc(void)
593 {
594         Block *bp;
595
596         ilock(&vt6105Mrblock);
597         if((bp = vt6105Mrbpool) != nil){
598                 vt6105Mrbpool = bp->next;
599                 bp->next = nil;
600         }
601         iunlock(&vt6105Mrblock);
602
603         if(bp == nil && (bp = iallocb(Rdbsz+3)) != nil){
604                 bp->free = vt6105Mrbfree;
605                 vt6105Mrbpoolsz++;
606         }
607         return bp;
608 }
609
610 static void
611 vt6105Mattach(Ether* edev)
612 {
613         Ctlr *ctlr;
614         uchar *alloc;
615         Ds *ds, *prev;
616         int dsz, i, timeo;
617         char name[KNAMELEN];
618
619         ctlr = edev->ctlr;
620         qlock(&ctlr->alock);
621         if(ctlr->alloc != nil){
622                 qunlock(&ctlr->alock);
623                 return;
624         }
625
626         /*
627          * Descriptor space.
628          * Receive descriptors should all be aligned on a 4-byte boundary,
629          * but try to do cache-line alignment.
630          */
631         ctlr->nrd = Nrd;
632         ctlr->ntd = Ntd;
633         dsz = ROUNDUP(sizeof(Ds), ctlr->cls);
634         alloc = mallocalign((ctlr->nrd+ctlr->ntd)*dsz, dsz, 0, 0);
635         if(alloc == nil){
636                 qunlock(&ctlr->alock);
637                 error(Enomem);
638         }
639         ctlr->alloc = alloc;
640
641         ctlr->rd = (Ds*)alloc;
642
643         if(waserror()){
644                 ds = ctlr->rd;
645                 for(i = 0; i < ctlr->nrd; i++){
646                         if(ds->bp != nil){
647                                 freeb(ds->bp);
648                                 ds->bp = nil;
649                         }
650                         if((ds = ds->next) == nil)
651                                 break;
652                 }
653                 free(ctlr->alloc);
654                 ctlr->alloc = nil;
655                 qunlock(&ctlr->alock);
656                 nexterror();
657         }
658
659         prev = (Ds*)(alloc + (ctlr->nrd-1)*dsz);
660         for(i = 0; i < ctlr->nrd; i++){
661                 ds = (Ds*)alloc;
662                 alloc += dsz;
663
664                 ds->control = Ipkt|Tcpkt|Udpkt|Rdbsz;
665                 ds->branch = PCIWADDR(alloc);
666
667                 ds->bp = vt6105Mrballoc();
668                 if(ds->bp == nil)
669                         error("vt6105M: can't allocate receive ring\n");
670                 ds->bp->rp = (uchar*)ROUNDUP((ulong)ds->bp->rp, 4);
671                 ds->addr = PCIWADDR(ds->bp->rp);
672
673                 ds->next = (Ds*)alloc;
674                 ds->prev = prev;
675                 prev = ds;
676
677                 ds->status = Own;
678         }
679         prev->branch = 0;
680         prev->next = ctlr->rd;
681         prev->status = 0;
682         ctlr->rdh = ctlr->rd;
683
684         ctlr->td = (Ds*)alloc;
685         prev = (Ds*)(alloc + (ctlr->ntd-1)*dsz);
686         for(i = 0; i < ctlr->ntd; i++){
687                 ds = (Ds*)alloc;
688                 alloc += dsz;
689
690                 ds->next = (Ds*)alloc;
691                 ds->prev = prev;
692                 prev = ds;
693         }
694         prev->next = ctlr->td;
695         ctlr->tdh = ctlr->tdt = ctlr->td;
696         ctlr->tdused = 0;
697
698         ctlr->cr = Dpoll|Rdmd/*|Txon|Rxon*/|Strt;
699         /*Srci|Abti|Norbf|Pktrace|Ovfi|Udfi|Be|Ru|Tu|Txe|Rxe|Ptx|Prx*/
700         ctlr->imr = Abti|Norbf|Pktrace|Ovfi|Udfi|Be|Ru|Tu|Txe|Rxe|Ptx|Prx;
701
702         ilock(&ctlr->clock);
703         csr32w(ctlr, Rxdaddr, PCIWADDR(ctlr->rd));
704         csr32w(ctlr, Txdaddr, PCIWADDR(ctlr->td));
705         csr16w(ctlr, Isr, ~0);
706         csr16w(ctlr, Imr, ctlr->imr);
707         csr16w(ctlr, Cr, ctlr->cr);
708         iunlock(&ctlr->clock);
709
710         /*
711          * Wait for link to be ready.
712          */
713         for(timeo = 0; timeo < 350; timeo++){
714                 if(miistatus(ctlr->mii) == 0)
715                         break;
716                 tsleep(&up->sleep, return0, 0, 10);
717         }
718 //      phy = ctlr->mii->curphy;
719 //      print("%s: speed %d fd %d link %d rfc %d tfc %d\n",
720 //              edev->name, phy->speed, phy->fd, phy->link, phy->rfc, phy->tfc);
721
722         ilock(&ctlr->clock);
723         ctlr->cr |= Txon|Rxon;
724         csr16w(ctlr, Cr, ctlr->cr);
725         iunlock(&ctlr->clock);
726
727         snprint(name, KNAMELEN, "#l%dlproc", edev->ctlrno);
728         kproc(name, vt6105Mlproc, edev);
729
730         qunlock(&ctlr->alock);
731         poperror();
732 }
733
734 static void
735 vt6105Mtransmit(Ether* edev)
736 {
737         Block *bp;
738         Ctlr *ctlr;
739         Ds *ds, *next;
740         int control, i, size, tdused, timeo;
741         long t;
742
743         ctlr = edev->ctlr;
744
745         ilock(&ctlr->tlock);
746         t = lcycles();
747
748         /*
749          * Free any completed packets
750          */
751         ds = ctlr->tdh;
752         for(tdused = ctlr->tdused; tdused > 0; tdused--){
753                 /*
754                  * For some errors the chip will turn the Tx engine
755                  * off. Wait for that to happen.
756                  * Could reset and re-init the chip here if it doesn't
757                  * play fair.
758                  * To do: adjust Tx FIFO threshold on underflow.
759                  */
760                 if(ds->status & (Abt|Tbuff|Udf)){
761                         if(ds->status & Abt)
762                                 ctlr->abt++;
763                         if(ds->status & Tbuff)
764                                 ctlr->tbuff++;
765                         if(ds->status & Udf)
766                                 ctlr->udf++;
767                         for(timeo = 0; timeo < 1000; timeo++){
768                                 if(!(csr16r(ctlr, Cr) & Txon))
769                                         break;
770                                 microdelay(1);
771                         }
772                         ds->status = Own;
773                         csr32w(ctlr, Txdaddr, PCIWADDR(ds));
774                 }
775
776                 if(ds->status & Own)
777                         break;
778                 ds->addr = 0;
779                 ds->branch = 0;
780
781                 if(ds->bp != nil){
782                         freeb(ds->bp);
783                         ds->bp = nil;
784                 }
785                 for(i = 0; i < Ntxstats-1; i++){
786                         if(ds->status & (1<<i))
787                                 ctlr->txstats[i]++;
788                 }
789                 ctlr->txstats[i] += (ds->status & NcrMASK)>>NcrSHIFT;
790
791                 ds = ds->next;
792         }
793         ctlr->tdh = ds;
794
795         /*
796          * Try to fill the ring back up.
797          */
798         ds = ctlr->tdt;
799         while(tdused < ctlr->ntd-2){
800                 if((bp = qget(edev->oq)) == nil)
801                         break;
802                 tdused++;
803
804                 size = BLEN(bp);
805
806                 next = ds->next;
807                 ds->branch = PCIWADDR(ds->next)|Tdctl;
808
809                 ds->bp = bp;
810                 ds->addr = PCIWADDR(bp->rp);
811                 control = Edp|Stp|((size<<TbsSHIFT) & TbsMASK);
812
813                 ds->control = control;
814                 if(tdused >= ctlr->ntd-2){
815                         ctlr->txdw++;
816                         ds->branch &= ~Tdctl;
817                 }
818                 coherence();
819                 ds->status = Own;
820
821                 ds = next;
822         }
823         ctlr->tdt = ds;
824         ctlr->tdused = tdused;
825         if(ctlr->tdused){
826                 csr16w(ctlr, Cr, Tdmd|ctlr->cr);
827                 if(tdused > ctlr->tdumax)
828                         ctlr->tdumax = tdused;
829         }
830
831         ctlr->totalt += lcycles() - t;
832         iunlock(&ctlr->tlock);
833 }
834
835 static void
836 vt6105Mreceive(Ether* edev)
837 {
838         Ds *ds;
839         Block *bp;
840         Ctlr *ctlr;
841         int i, len;
842
843         ctlr = edev->ctlr;
844
845         ds = ctlr->rdh;
846         while(!(ds->status & Own) && ds->status != 0){
847                 /*
848                  * Can Long packets be received OK?
849                  * What happens to the Rxok bit?
850                  */
851                 if(ds->status & Rerr){
852                         for(i = 0; i < Nrxstats; i++){
853                                 if(ds->status & (1<<i))
854                                         ctlr->rxstats[i]++;
855                         }
856                 }
857                 else if(bp = vt6105Mrballoc()){
858                         if(ds->control & Tuok){
859                                 ds->bp->flag |= Btcpck|Budpck;
860                                 ctlr->tuok++;
861                         }
862                         if(ds->control & Ipok){
863                                 ds->bp->flag |= Bipck;
864                                 ctlr->ipok++;
865                         }
866                         len = ((ds->status & LengthMASK)>>LengthSHIFT)-4;
867                         ds->bp->wp = ds->bp->rp+len;
868                         etheriq(edev, ds->bp);
869                         bp->rp = (uchar*)ROUNDUP((ulong)bp->rp, 4);
870                         ds->addr = PCIWADDR(bp->rp);
871                         ds->bp = bp;
872                 }
873                 ds->control = Ipkt|Tcpkt|Udpkt|Rdbsz;
874                 ds->branch = 0;
875                 ds->status = 0;
876
877                 ds->prev->branch = PCIWADDR(ds);
878                 coherence();
879                 ds->prev->status = Own;
880
881                 ds = ds->next;
882         }
883         ctlr->rdh = ds;
884
885         csr16w(ctlr, Cr, ctlr->cr);
886 }
887
888 static void
889 vt6105Minterrupt(Ureg*, void* arg)
890 {
891         Ctlr *ctlr;
892         Ether *edev;
893         int imr, isr, r, timeo;
894         long t;
895
896         edev = arg;
897         ctlr = edev->ctlr;
898
899         ilock(&ctlr->clock);
900         t = lcycles();
901
902         csr16w(ctlr, Imr, 0);
903         imr = ctlr->imr;
904         ctlr->intr++;
905         for(;;){
906                 if((isr = csr16r(ctlr, Isr)) != 0)
907                         csr16w(ctlr, Isr, isr);
908                 if((isr & ctlr->imr) == 0)
909                         break;
910                         
911                 if(isr & Srci){
912                         imr &= ~Srci;
913                         ctlr->lwakeup = isr & Srci;
914                         wakeup(&ctlr->lrendez);
915                         isr &= ~Srci;
916                         ctlr->lintr++;
917                 }
918                 if(isr & (Norbf|Pktrace|Ovfi|Ru|Rxe|Prx)){
919                         vt6105Mreceive(edev);
920                         isr &= ~(Norbf|Pktrace|Ovfi|Ru|Rxe|Prx);
921                         ctlr->rintr++;
922                 }
923                 if(isr & (Abti|Udfi|Tu|Txe|Ptx)){
924                         if(isr & (Abti|Udfi|Tu)){
925                                 if(isr & Abti)
926                                         ctlr->abti++;
927                                 if(isr & Udfi)
928                                         ctlr->udfi++;
929                                 if(isr & Tu)
930                                         ctlr->tu++;
931                                 for(timeo = 0; timeo < 1000; timeo++){
932                                         if(!(csr16r(ctlr, Cr) & Txon))
933                                                 break;
934                                         microdelay(1);
935                                 }
936
937                                 if((isr & Udfi) && ctlr->tft < CtftSAF){
938                                         ctlr->tft += 1<<CtftSHIFT;
939                                         r = csr8r(ctlr, Bcr1) & ~CtftMASK;
940                                         csr8w(ctlr, Bcr1, r|ctlr->tft);
941                                 }
942                         }
943                         
944                         
945                         ctlr->totalt += lcycles() - t;
946                         vt6105Mtransmit(edev);
947                         t = lcycles();
948                         isr &= ~(Abti|Udfi|Tu|Txe|Ptx);
949                         ctlr->tintr++;
950                 }
951                 if(isr)
952                         panic("vt6105M: isr %4.4uX", isr);
953         }
954         ctlr->imr = imr;
955         csr16w(ctlr, Imr, ctlr->imr);
956         
957         ctlr->totalt += lcycles() - t;
958         iunlock(&ctlr->clock);
959 }
960
961 static int
962 vt6105Mmiimicmd(Mii* mii, int pa, int ra, int cmd, int data)
963 {
964         Ctlr *ctlr;
965         int r, timeo;
966
967         ctlr = mii->ctlr;
968
969         csr8w(ctlr, Miicr, 0);
970         r = csr8r(ctlr, Phyadr);
971         csr8w(ctlr, Phyadr, (r & ~PhyadMASK)|pa);
972         csr8w(ctlr, Phyadr, pa);
973         csr8w(ctlr, Miiadr, ra);
974         if(cmd == Wcmd)
975                 csr16w(ctlr, Miidata, data);
976         csr8w(ctlr, Miicr, cmd);
977
978         for(timeo = 0; timeo < 10000; timeo++){
979                 if(!(csr8r(ctlr, Miicr) & cmd))
980                         break;
981                 microdelay(1);
982         }
983         if(timeo >= 10000)
984                 return -1;
985
986         if(cmd == Wcmd)
987                 return 0;
988         return csr16r(ctlr, Miidata);
989 }
990
991 static int
992 vt6105Mmiimir(Mii* mii, int pa, int ra)
993 {
994         return vt6105Mmiimicmd(mii, pa, ra, Rcmd, 0);
995 }
996
997 static int
998 vt6105Mmiimiw(Mii* mii, int pa, int ra, int data)
999 {
1000         return vt6105Mmiimicmd(mii, pa, ra, Wcmd, data);
1001 }
1002
1003 static int
1004 vt6105Mdetach(Ctlr* ctlr)
1005 {
1006         int revid, timeo;
1007
1008         /*
1009          * Reset power management registers.
1010          */
1011         revid = pcicfgr8(ctlr->pcidev, PciRID);
1012         if(revid >= 0x40){
1013                 /* Set power state D0. */
1014                 csr8w(ctlr, Stickhw, csr8r(ctlr, Stickhw) & 0xFC);
1015
1016                 /* Disable force PME-enable. */
1017                 csr8w(ctlr, Wolcgclr, 0x80);
1018
1019                 /* Clear WOL config and status bits. */
1020                 csr8w(ctlr, Wolcrclr, 0xFF);
1021                 csr8w(ctlr, Pwrcsrclr, 0xFF);
1022         }
1023
1024         /*
1025          * Soft reset the controller.
1026          */
1027         csr16w(ctlr, Cr, Stop);
1028         csr16w(ctlr, Cr, Stop|Sfrst);
1029         /* limit used to be 10000, but that wasn't enough for our Soekris 5501s */
1030         for(timeo = 0; timeo < 100000; timeo++){
1031                 if(!(csr16r(ctlr, Cr) & Sfrst))
1032                         break;
1033                 microdelay(1);
1034         }
1035         if(timeo >= 100000)
1036                 return -1;
1037
1038         return 0;
1039 }
1040
1041 static int
1042 vt6105Mreset(Ctlr* ctlr)
1043 {
1044         MiiPhy *phy;
1045         int i, r, timeo;
1046
1047         if(vt6105Mdetach(ctlr) < 0)
1048                 return -1;
1049
1050         /*
1051          * Load the MAC address into the PAR[01]
1052          * registers.
1053          */
1054         r = csr8r(ctlr, Eecsr);
1055         csr8w(ctlr, Eecsr, Autold|r);
1056         /* limit used to be 100, but that wasn't enough for our Soekris 5501s */
1057         for(timeo = 0; timeo < 100000; timeo++){
1058                 if(!(csr8r(ctlr, Cr) & Autold))
1059                         break;
1060                 microdelay(1);
1061         }
1062         if(timeo >= 100000)
1063                 return -1;
1064
1065         for(i = 0; i < Eaddrlen; i++)
1066                 ctlr->par[i] = csr8r(ctlr, Par0+i);
1067
1068         /*
1069          * Configure DMA and Rx/Tx thresholds.
1070          * If the Rx/Tx threshold bits in Bcr[01] are 0 then
1071          * the thresholds are determined by Rcr/Tcr.
1072          */
1073         r = csr8r(ctlr, Bcr0) & ~(CrftMASK|DmaMASK);
1074         csr8w(ctlr, Bcr0, r|Crft128|DmaSAF);
1075         r = csr8r(ctlr, Bcr1) & ~CtftMASK;
1076         csr8w(ctlr, Bcr1, r|ctlr->tft);
1077
1078         r = csr8r(ctlr, Rcr) & ~(RrftMASK|Prom|Ar|Sep);
1079         csr8w(ctlr, Rcr, r|Ab|Am);
1080         csr32w(ctlr, Mcfilt0, ~0UL);    /* accept all multicast */
1081         csr32w(ctlr, Mcfilt1, ~0UL);
1082
1083         r = csr8r(ctlr, Tcr) & ~(RtsfMASK|Ofset|Lb1|Lb0);
1084         csr8w(ctlr, Tcr, r);
1085
1086         /*
1087          * Link management.
1088          */
1089         if((ctlr->mii = malloc(sizeof(Mii))) == nil)
1090                 return -1;
1091         ctlr->mii->mir = vt6105Mmiimir;
1092         ctlr->mii->miw = vt6105Mmiimiw;
1093         ctlr->mii->ctlr = ctlr;
1094
1095         if(mii(ctlr->mii, ~0) == 0 || (phy = ctlr->mii->curphy) == nil){
1096                 free(ctlr->mii);
1097                 ctlr->mii = nil;
1098                 return -1;
1099         }
1100 //      print("oui %X phyno %d\n", phy->oui, phy->phyno);
1101         USED(phy);
1102
1103         if(miistatus(ctlr->mii) < 0){
1104 //              miireset(ctlr->mii);
1105                 miiane(ctlr->mii, ~0, ~0, ~0);
1106         }
1107
1108         return 0;
1109 }
1110
1111 static void
1112 vt6105Mpci(void)
1113 {
1114         Pcidev *p;
1115         Ctlr *ctlr;
1116         int port;
1117
1118         p = nil;
1119         while(p = pcimatch(p, 0, 0)){
1120                 if(p->ccrb != Pcibcnet || p->ccru != Pciscether)
1121                         continue;
1122
1123                 switch((p->did<<16)|p->vid){
1124                 default:
1125                         continue;
1126                 case (0x3053<<16)|0x1106:       /* Rhine III-M vt6105M */
1127                         break;
1128                 }
1129
1130                 port = p->mem[0].bar & ~3;
1131                 if(ioalloc(port, p->mem[0].size, 0, "vt6105M") < 0){
1132                         print("vt6105M: port 0x%uX in use\n", port);
1133                         continue;
1134                 }
1135                 ctlr = malloc(sizeof(Ctlr));
1136                 if(ctlr == nil){
1137                         print("vt6105M: can't allocate memory\n");
1138                         iofree(port);
1139                         continue;
1140                 }
1141                 ctlr->port = port;
1142                 ctlr->pcidev = p;
1143                 pcienable(p);
1144                 ctlr->id = (p->did<<16)|p->vid;
1145                 ctlr->cls = p->cls*4;
1146                 ctlr->tft = CtftSAF;
1147
1148                 if(vt6105Mreset(ctlr)){
1149                         iofree(port);
1150                         free(ctlr);
1151                         continue;
1152                 }
1153                 pcisetbme(p);
1154
1155                 if(vt6105Mctlrhead != nil)
1156                         vt6105Mctlrtail->next = ctlr;
1157                 else
1158                         vt6105Mctlrhead = ctlr;
1159                 vt6105Mctlrtail = ctlr;
1160         }
1161 }
1162
1163 static int
1164 vt6105Mpnp(Ether* edev)
1165 {
1166         Ctlr *ctlr;
1167
1168         if(vt6105Mctlrhead == nil)
1169                 vt6105Mpci();
1170
1171         /*
1172          * Any adapter matches if no edev->port is supplied,
1173          * otherwise the ports must match.
1174          */
1175         for(ctlr = vt6105Mctlrhead; ctlr != nil; ctlr = ctlr->next){
1176                 if(ctlr->active)
1177                         continue;
1178                 if(edev->port == 0 || edev->port == ctlr->port){
1179                         ctlr->active = 1;
1180                         break;
1181                 }
1182         }
1183         if(ctlr == nil)
1184                 return -1;
1185
1186         edev->ctlr = ctlr;
1187         edev->port = ctlr->port;
1188         edev->irq = ctlr->pcidev->intl;
1189         edev->tbdf = ctlr->pcidev->tbdf;
1190         /*
1191          * Set to 1000Mb/s to fool the bsz calculation.  We need 
1192          * something better, though.
1193          */
1194         edev->mbps = 1000;
1195         memmove(edev->ea, ctlr->par, Eaddrlen);
1196
1197         /*
1198          * Linkage to the generic ethernet driver.
1199          */
1200         edev->attach = vt6105Mattach;
1201         edev->transmit = vt6105Mtransmit;
1202         edev->ifstat = vt6105Mifstat;
1203         edev->ctl = nil;
1204
1205         edev->arg = edev;
1206         edev->promiscuous = vt6105Mpromiscuous;
1207         edev->multicast = vt6105Mmulticast;
1208
1209         edev->maxmtu = ETHERMAXTU+Bslop;
1210
1211         intrenable(edev->irq, vt6105Minterrupt, edev, edev->tbdf, edev->name);
1212
1213         return 0;
1214 }
1215
1216 void
1217 ethervt6105mlink(void)
1218 {
1219         addethercard("vt6105M", vt6105Mpnp);
1220 }