FreeBSD/Linux Kernel Cross Reference
sys/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 alloc = malloc(READSTR);
444 p = alloc;
445 e = p + READSTR;
446 for(i = 0; i < Nrxstats; i++){
447 p = seprint(p, e, "%s: %ud\n", rxstats[i], ctlr->rxstats[i]);
448 }
449 for(i = 0; i < Ntxstats; i++){
450 if(txstats[i] == nil)
451 continue;
452 p = seprint(p, e, "%s: %ud\n", txstats[i], ctlr->txstats[i]);
453 }
454 p = seprint(p, e, "cls: %ud\n", ctlr->cls);
455 p = seprint(p, e, "intr: %ud\n", ctlr->intr);
456 p = seprint(p, e, "lintr: %ud\n", ctlr->lintr);
457 p = seprint(p, e, "lsleep: %ud\n", ctlr->lsleep);
458 p = seprint(p, e, "rintr: %ud\n", ctlr->rintr);
459 p = seprint(p, e, "tintr: %ud\n", ctlr->tintr);
460 p = seprint(p, e, "txdw: %ud\n", ctlr->txdw);
461 p = seprint(p, e, "tdumax: %ud\n", ctlr->tdumax);
462 p = seprint(p, e, "tft: %ud\n", ctlr->tft);
463
464 p = seprint(p, e, "abt: %ud\n", ctlr->abt);
465 p = seprint(p, e, "tbuff: %ud\n", ctlr->tbuff);
466 p = seprint(p, e, "udf: %ud\n", ctlr->udf);
467 p = seprint(p, e, "abti: %ud\n", ctlr->abti);
468 p = seprint(p, e, "udfi: %ud\n", ctlr->udfi);
469 p = seprint(p, e, "tu: %ud\n", ctlr->tu);
470
471 p = seprint(p, e, "tuok: %ud\n", ctlr->tuok);
472 p = seprint(p, e, "ipok: %ud\n", ctlr->ipok);
473
474 p = seprint(p, e, "rbpoolsz: %ud\n", vt6105Mrbpoolsz);
475 p = seprint(p, e, "totalt: %uld\n", ctlr->totalt);
476
477 for(i = 0; regs[i].name != nil; i++){
478 p = seprint(p, e, "%s: %2.2x\n",
479 regs[i].name, csr8r(ctlr, regs[i].offset));
480 }
481
482 if(ctlr->mii != nil && ctlr->mii->curphy != nil){
483 p = seprint(p, e, "phy: ");
484 for(i = 0; i < NMiiPhyr; i++){
485 if(i && ((i & 0x07) == 0))
486 p = seprint(p, e, "\n ");
487 r = miimir(ctlr->mii, i);
488 p = seprint(p, e, " %4.4uX", r);
489 }
490 seprint(p, e, "\n");
491 }
492
493 n = readstr(offset, a, n, alloc);
494 free(alloc);
495
496 return n;
497 }
498
499 static void
500 vt6105Mpromiscuous(void* arg, int on)
501 {
502 int rcr;
503 Ctlr *ctlr;
504 Ether *edev;
505
506 edev = arg;
507 ctlr = edev->ctlr;
508 rcr = csr8r(ctlr, Rcr);
509 if(on)
510 rcr |= Prom;
511 else
512 rcr &= ~Prom;
513 csr8w(ctlr, Rcr, rcr);
514 }
515
516 static void
517 vt6105Mmulticast(void* arg, uchar* addr, int on)
518 {
519 /*
520 * For now Am is set in Rcr.
521 * Will need to interlock with promiscuous
522 * when this gets filled in.
523 */
524 USED(arg, addr, on);
525 }
526
527 static int
528 vt6105Mwakeup(void* v)
529 {
530 return *((int*)v) != 0;
531 }
532
533 static void
534 vt6105Mimr(Ctlr* ctlr, int imr)
535 {
536 ilock(&ctlr->clock);
537 ctlr->imr |= imr;
538 csr16w(ctlr, Imr, ctlr->imr);
539 iunlock(&ctlr->clock);
540 }
541
542 static void
543 vt6105Mlproc(void* arg)
544 {
545 Ctlr *ctlr;
546 Ether *edev;
547 MiiPhy *phy;
548
549 edev = arg;
550 ctlr = edev->ctlr;
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
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 // MiiPhy *phy;
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 return;
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, 1);
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\n", 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 for(timeo = 0; timeo < 10000; timeo++){
1030 if(!(csr16r(ctlr, Cr) & Sfrst))
1031 break;
1032 microdelay(1);
1033 }
1034 if(timeo >= 1000)
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 for(timeo = 0; timeo < 100; timeo++){
1056 if(!(csr8r(ctlr, Cr) & Autold))
1057 break;
1058 microdelay(1);
1059 }
1060 if(timeo >= 100)
1061 return -1;
1062
1063 for(i = 0; i < Eaddrlen; i++)
1064 ctlr->par[i] = csr8r(ctlr, Par0+i);
1065
1066 /*
1067 * Configure DMA and Rx/Tx thresholds.
1068 * If the Rx/Tx threshold bits in Bcr[01] are 0 then
1069 * the thresholds are determined by Rcr/Tcr.
1070 */
1071 r = csr8r(ctlr, Bcr0) & ~(CrftMASK|DmaMASK);
1072 csr8w(ctlr, Bcr0, r|Crft128|DmaSAF);
1073 r = csr8r(ctlr, Bcr1) & ~CtftMASK;
1074 csr8w(ctlr, Bcr1, r|ctlr->tft);
1075
1076 r = csr8r(ctlr, Rcr) & ~(RrftMASK|Prom|Ar|Sep);
1077 csr8w(ctlr, Rcr, r|Ab|Am);
1078 csr32w(ctlr, Mcfilt0, ~0UL); /* accept all multicast */
1079 csr32w(ctlr, Mcfilt1, ~0UL);
1080
1081 r = csr8r(ctlr, Tcr) & ~(RtsfMASK|Ofset|Lb1|Lb0);
1082 csr8w(ctlr, Tcr, r);
1083
1084 /*
1085 * Link management.
1086 */
1087 if((ctlr->mii = malloc(sizeof(Mii))) == nil)
1088 return -1;
1089 ctlr->mii->mir = vt6105Mmiimir;
1090 ctlr->mii->miw = vt6105Mmiimiw;
1091 ctlr->mii->ctlr = ctlr;
1092
1093 if(mii(ctlr->mii, ~0) == 0 || (phy = ctlr->mii->curphy) == nil){
1094 free(ctlr->mii);
1095 ctlr->mii = nil;
1096 return -1;
1097 }
1098 // print("oui %X phyno %d\n", phy->oui, phy->phyno);
1099 USED(phy);
1100
1101 if(miistatus(ctlr->mii) < 0){
1102 // miireset(ctlr->mii);
1103 miiane(ctlr->mii, ~0, ~0, ~0);
1104 }
1105
1106 return 0;
1107 }
1108
1109 static void
1110 vt6105Mpci(void)
1111 {
1112 Pcidev *p;
1113 Ctlr *ctlr;
1114 int cls, port;
1115
1116 p = nil;
1117 while(p = pcimatch(p, 0, 0)){
1118 if(p->ccrb != Pcibcnet || p->ccru != Pciscether)
1119 continue;
1120
1121 switch((p->did<<16)|p->vid){
1122 default:
1123 continue;
1124 case (0x3053<<16)|0x1106: /* Rhine III-M vt6105M */
1125 break;
1126 }
1127
1128 port = p->mem[0].bar & ~0x01;
1129 if(ioalloc(port, p->mem[0].size, 0, "vt6105M") < 0){
1130 print("vt6105M: port 0x%uX in use\n", port);
1131 continue;
1132 }
1133 ctlr = malloc(sizeof(Ctlr));
1134 ctlr->port = port;
1135 ctlr->pcidev = p;
1136 ctlr->id = (p->did<<16)|p->vid;
1137 if((cls = pcicfgr8(p, PciCLS)) == 0 || cls == 0xFF)
1138 cls = 0x10;
1139 ctlr->cls = cls*4;
1140 if(ctlr->cls < sizeof(Ds)){
1141 print("vt6105M: cls %d < sizeof(Ds)\n", ctlr->cls);
1142 iofree(port);
1143 free(ctlr);
1144 continue;
1145 }
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->interrupt = vt6105Minterrupt;
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 return 0;
1213 }
1214
1215 void
1216 ethervt6105mlink(void)
1217 {
1218 addethercard("vt6105M", vt6105Mpnp);
1219 }
Cache object: 5fa5cc5760269d4ecfcf6ffc1b25b9f3
|