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