2 * VIA VT6105M Fast Ethernet Controller (Rhine III).
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
13 * why does the receive buffer alloc have a +3?
16 #include "../port/lib.h"
21 #include "../port/error.h"
22 #include "../port/netif.h"
23 #include "../port/etherif.h"
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 */
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 */
51 Cr0 = 0x80, /* Miscellaneous Control */
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 */
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 */
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,
81 Lb0 = 0x02, /* Loopback Mode */
83 Ofset = 0x08, /* Select Back-off Priority */
84 RtsfMASK = 0xE0, /* Transmit FIFO Threshold */
86 Rtsf128 = 0<<RtsfSHIFT,
87 Rtsf256 = 1<<RtsfSHIFT,
88 Rtsf512 = 2<<RtsfSHIFT,
89 Rtsf1024 = 3<<RtsfSHIFT,
90 RtsfSAF = 7<<RtsfSHIFT,
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 */
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 */
129 PhyadMASK = 0x1F, /* PHY Address */
131 Mfdc = 0x20, /* Accelerate MDC Speed */
132 Mpo0 = 0x40, /* MII Polling Timer Interval */
137 DmaMASK = 0x07, /* DMA Length */
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 */
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 */
159 PotMASK = 0x07, /* Polling Timer Interval */
161 CtftMASK = 0x38, /* Tx FIFO Threshold */
163 Ctft64 = 1<<CtftSHIFT,
164 Ctft128 = 2<<CtftSHIFT,
165 Ctft256 = 3<<CtftSHIFT,
166 Ctft512 = 4<<CtftSHIFT,
167 Ctft1024 = 5<<CtftSHIFT,
168 CtftSAF = 7<<CtftSHIFT,
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 */
183 MadMASK = 0x1F, /* MII Port Address */
185 Mdone = 0x20, /* Accelerate MDC Speed */
186 Msrcen = 0x40, /* MII Polling Timer Interval */
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 */
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.
206 typedef struct Ds Ds;
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 */
237 Own = 0x80000000, /* Descriptor Owned by NIC */
240 enum { /* Rx Ds control */
241 RbsizeMASK = 0x000007FF, /* Receive Buffer Size */
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 */
255 enum { /* Tx Ds status */
256 NcrMASK = 0x0000000F, /* Collision Retry Count */
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 */
269 enum { /* Tx Ds control */
270 TbsMASK = 0x000007FF, /* Tx Buffer Size */
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 */
279 enum { /* Tx Ds branch */
280 Tdctl = 0x00000001, /* No Interrupt Generated */
288 Rdbsz = ETHERMAXTU+Crcsz+Bslop,
296 typedef struct Ctlr Ctlr;
297 typedef struct Ctlr {
305 QLock alock; /* attach */
306 void* alloc; /* descriptors, etc. */
307 int cls; /* alignment */
323 int tft; /* Tx threshold */
329 uint rxstats[Nrxstats]; /* statistics */
330 uint txstats[Ntxstats];
352 static Ctlr* vt6105Mctlrhead;
353 static Ctlr* vt6105Mctlrtail;
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)))
362 static Lock vt6105Mrblock; /* receive Block freelist */
363 static Block* vt6105Mrbpool;
364 static uint vt6105Mrbpoolsz;
366 typedef struct Regs Regs;
367 typedef struct Regs {
373 static Regs regs[] = {
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,
388 // "Mcfilt0", Mcfilt0,4,
389 // "Mcfilt1", Mcfilt1,4,
390 // "Rxdaddr", Rxdaddr,4,
391 // "Txdaddr", Txdaddr,4,
398 // "Miidata", Miidata,2,
407 "Stickhw", Stickhw,1,
413 static char* rxstats[Nrxstats] = {
416 "Frame Alignment Error",
421 "Buffer Underflow Error",
423 static char* txstats[Ntxstats] = {
424 "Aborted after Excessive Collisions",
425 "Out of Window Collision Seen",
426 "Carrier Sense Lost",
431 "Excessive Collisions",
435 vt6105Mifstat(Ether* edev, void* a, long n, ulong offset)
443 p = alloc = smalloc(READSTR);
445 for(i = 0; i < Nrxstats; i++){
446 p = seprint(p, e, "%s: %ud\n", rxstats[i], ctlr->rxstats[i]);
448 for(i = 0; i < Ntxstats; i++){
449 if(txstats[i] == nil)
451 p = seprint(p, e, "%s: %ud\n", txstats[i], ctlr->txstats[i]);
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);
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);
470 p = seprint(p, e, "tuok: %ud\n", ctlr->tuok);
471 p = seprint(p, e, "ipok: %ud\n", ctlr->ipok);
473 p = seprint(p, e, "rbpoolsz: %ud\n", vt6105Mrbpoolsz);
474 p = seprint(p, e, "totalt: %uld\n", ctlr->totalt);
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));
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);
492 n = readstr(offset, a, n, alloc);
499 vt6105Mpromiscuous(void* arg, int on)
507 rcr = csr8r(ctlr, Rcr);
512 csr8w(ctlr, Rcr, rcr);
516 vt6105Mmulticast(void* arg, uchar* addr, int on)
519 * For now Am is set in Rcr.
520 * Will need to interlock with promiscuous
521 * when this gets filled in.
527 vt6105Mwakeup(void* v)
529 return *((int*)v) != 0;
533 vt6105Mimr(Ctlr* ctlr, int imr)
537 csr16w(ctlr, Imr, ctlr->imr);
538 iunlock(&ctlr->clock);
542 vt6105Mlproc(void* arg)
553 if(ctlr->mii == nil || ctlr->mii->curphy == nil)
555 if(miistatus(ctlr->mii) < 0)
558 phy = ctlr->mii->curphy;
560 csr16w(ctlr, Cr, ctlr->cr & ~(Txon|Rxon));
565 csr16w(ctlr, Cr, ctlr->cr);
566 iunlock(&ctlr->clock);
569 vt6105Mimr(ctlr, Srci);
572 sleep(&ctlr->lrendez, vt6105Mwakeup, &ctlr->lwakeup);
575 pexit("vt6105Mlproc: done", 1);
579 vt6105Mrbfree(Block* bp)
581 bp->rp = bp->lim - (Rdbsz+3);
583 bp->flag &= ~(Bipck | Budpck | Btcpck | Bpktck);
585 ilock(&vt6105Mrblock);
586 bp->next = vt6105Mrbpool;
588 iunlock(&vt6105Mrblock);
596 ilock(&vt6105Mrblock);
597 if((bp = vt6105Mrbpool) != nil){
598 vt6105Mrbpool = bp->next;
601 iunlock(&vt6105Mrblock);
603 if(bp == nil && (bp = iallocb(Rdbsz+3)) != nil){
604 bp->free = vt6105Mrbfree;
611 vt6105Mattach(Ether* edev)
621 if(ctlr->alloc != nil){
622 qunlock(&ctlr->alock);
628 * Receive descriptors should all be aligned on a 4-byte boundary,
629 * but try to do cache-line alignment.
633 dsz = ROUNDUP(sizeof(Ds), ctlr->cls);
634 alloc = mallocalign((ctlr->nrd+ctlr->ntd)*dsz, dsz, 0, 0);
636 qunlock(&ctlr->alock);
641 ctlr->rd = (Ds*)alloc;
645 for(i = 0; i < ctlr->nrd; i++){
650 if((ds = ds->next) == nil)
655 qunlock(&ctlr->alock);
659 prev = (Ds*)(alloc + (ctlr->nrd-1)*dsz);
660 for(i = 0; i < ctlr->nrd; i++){
664 ds->control = Ipkt|Tcpkt|Udpkt|Rdbsz;
665 ds->branch = PCIWADDR(alloc);
667 ds->bp = vt6105Mrballoc();
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);
673 ds->next = (Ds*)alloc;
680 prev->next = ctlr->rd;
682 ctlr->rdh = ctlr->rd;
684 ctlr->td = (Ds*)alloc;
685 prev = (Ds*)(alloc + (ctlr->ntd-1)*dsz);
686 for(i = 0; i < ctlr->ntd; i++){
690 ds->next = (Ds*)alloc;
694 prev->next = ctlr->td;
695 ctlr->tdh = ctlr->tdt = ctlr->td;
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;
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);
711 * Wait for link to be ready.
713 for(timeo = 0; timeo < 350; timeo++){
714 if(miistatus(ctlr->mii) == 0)
716 tsleep(&up->sleep, return0, 0, 10);
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);
723 ctlr->cr |= Txon|Rxon;
724 csr16w(ctlr, Cr, ctlr->cr);
725 iunlock(&ctlr->clock);
727 snprint(name, KNAMELEN, "#l%dlproc", edev->ctlrno);
728 kproc(name, vt6105Mlproc, edev);
730 qunlock(&ctlr->alock);
735 vt6105Mtransmit(Ether* edev)
740 int control, i, size, tdused, timeo;
749 * Free any completed packets
752 for(tdused = ctlr->tdused; tdused > 0; tdused--){
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
758 * To do: adjust Tx FIFO threshold on underflow.
760 if(ds->status & (Abt|Tbuff|Udf)){
763 if(ds->status & Tbuff)
767 for(timeo = 0; timeo < 1000; timeo++){
768 if(!(csr16r(ctlr, Cr) & Txon))
773 csr32w(ctlr, Txdaddr, PCIWADDR(ds));
785 for(i = 0; i < Ntxstats-1; i++){
786 if(ds->status & (1<<i))
789 ctlr->txstats[i] += (ds->status & NcrMASK)>>NcrSHIFT;
796 * Try to fill the ring back up.
799 while(tdused < ctlr->ntd-2){
800 if((bp = qget(edev->oq)) == nil)
807 ds->branch = PCIWADDR(ds->next)|Tdctl;
810 ds->addr = PCIWADDR(bp->rp);
811 control = Edp|Stp|((size<<TbsSHIFT) & TbsMASK);
813 ds->control = control;
814 if(tdused >= ctlr->ntd-2){
816 ds->branch &= ~Tdctl;
824 ctlr->tdused = tdused;
826 csr16w(ctlr, Cr, Tdmd|ctlr->cr);
827 if(tdused > ctlr->tdumax)
828 ctlr->tdumax = tdused;
831 ctlr->totalt += lcycles() - t;
832 iunlock(&ctlr->tlock);
836 vt6105Mreceive(Ether* edev)
846 while(!(ds->status & Own) && ds->status != 0){
848 * Can Long packets be received OK?
849 * What happens to the Rxok bit?
851 if(ds->status & Rerr){
852 for(i = 0; i < Nrxstats; i++){
853 if(ds->status & (1<<i))
857 else if(bp = vt6105Mrballoc()){
858 if(ds->control & Tuok){
859 ds->bp->flag |= Btcpck|Budpck;
862 if(ds->control & Ipok){
863 ds->bp->flag |= Bipck;
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);
873 ds->control = Ipkt|Tcpkt|Udpkt|Rdbsz;
877 ds->prev->branch = PCIWADDR(ds);
879 ds->prev->status = Own;
885 csr16w(ctlr, Cr, ctlr->cr);
889 vt6105Minterrupt(Ureg*, void* arg)
893 int imr, isr, r, timeo;
902 csr16w(ctlr, Imr, 0);
906 if((isr = csr16r(ctlr, Isr)) != 0)
907 csr16w(ctlr, Isr, isr);
908 if((isr & ctlr->imr) == 0)
913 ctlr->lwakeup = isr & Srci;
914 wakeup(&ctlr->lrendez);
918 if(isr & (Norbf|Pktrace|Ovfi|Ru|Rxe|Prx)){
919 vt6105Mreceive(edev);
920 isr &= ~(Norbf|Pktrace|Ovfi|Ru|Rxe|Prx);
923 if(isr & (Abti|Udfi|Tu|Txe|Ptx)){
924 if(isr & (Abti|Udfi|Tu)){
931 for(timeo = 0; timeo < 1000; timeo++){
932 if(!(csr16r(ctlr, Cr) & Txon))
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);
945 ctlr->totalt += lcycles() - t;
946 vt6105Mtransmit(edev);
948 isr &= ~(Abti|Udfi|Tu|Txe|Ptx);
952 panic("vt6105M: isr %4.4uX", isr);
955 csr16w(ctlr, Imr, ctlr->imr);
957 ctlr->totalt += lcycles() - t;
958 iunlock(&ctlr->clock);
962 vt6105Mmiimicmd(Mii* mii, int pa, int ra, int cmd, int data)
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);
975 csr16w(ctlr, Miidata, data);
976 csr8w(ctlr, Miicr, cmd);
978 for(timeo = 0; timeo < 10000; timeo++){
979 if(!(csr8r(ctlr, Miicr) & cmd))
988 return csr16r(ctlr, Miidata);
992 vt6105Mmiimir(Mii* mii, int pa, int ra)
994 return vt6105Mmiimicmd(mii, pa, ra, Rcmd, 0);
998 vt6105Mmiimiw(Mii* mii, int pa, int ra, int data)
1000 return vt6105Mmiimicmd(mii, pa, ra, Wcmd, data);
1004 vt6105Mdetach(Ctlr* ctlr)
1009 * Reset power management registers.
1011 revid = pcicfgr8(ctlr->pcidev, PciRID);
1013 /* Set power state D0. */
1014 csr8w(ctlr, Stickhw, csr8r(ctlr, Stickhw) & 0xFC);
1016 /* Disable force PME-enable. */
1017 csr8w(ctlr, Wolcgclr, 0x80);
1019 /* Clear WOL config and status bits. */
1020 csr8w(ctlr, Wolcrclr, 0xFF);
1021 csr8w(ctlr, Pwrcsrclr, 0xFF);
1025 * Soft reset the controller.
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))
1042 vt6105Mreset(Ctlr* ctlr)
1047 if(vt6105Mdetach(ctlr) < 0)
1051 * Load the MAC address into the PAR[01]
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))
1065 for(i = 0; i < Eaddrlen; i++)
1066 ctlr->par[i] = csr8r(ctlr, Par0+i);
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.
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);
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);
1083 r = csr8r(ctlr, Tcr) & ~(RtsfMASK|Ofset|Lb1|Lb0);
1084 csr8w(ctlr, Tcr, r);
1089 if((ctlr->mii = malloc(sizeof(Mii))) == nil)
1091 ctlr->mii->mir = vt6105Mmiimir;
1092 ctlr->mii->miw = vt6105Mmiimiw;
1093 ctlr->mii->ctlr = ctlr;
1095 if(mii(ctlr->mii, ~0) == 0 || (phy = ctlr->mii->curphy) == nil){
1100 // print("oui %X phyno %d\n", phy->oui, phy->phyno);
1103 if(miistatus(ctlr->mii) < 0){
1104 // miireset(ctlr->mii);
1105 miiane(ctlr->mii, ~0, ~0, ~0);
1119 while(p = pcimatch(p, 0, 0)){
1120 if(p->ccrb != Pcibcnet || p->ccru != Pciscether)
1123 switch((p->did<<16)|p->vid){
1126 case (0x3053<<16)|0x1106: /* Rhine III-M vt6105M */
1130 port = p->mem[0].bar & ~0x01;
1131 if(ioalloc(port, p->mem[0].size, 0, "vt6105M") < 0){
1132 print("vt6105M: port 0x%uX in use\n", port);
1135 ctlr = malloc(sizeof(Ctlr));
1137 print("vt6105M: can't allocate memory\n");
1144 ctlr->id = (p->did<<16)|p->vid;
1145 if((cls = pcicfgr8(p, PciCLS)) == 0 || cls == 0xFF)
1148 ctlr->tft = CtftSAF;
1150 if(vt6105Mreset(ctlr)){
1157 if(vt6105Mctlrhead != nil)
1158 vt6105Mctlrtail->next = ctlr;
1160 vt6105Mctlrhead = ctlr;
1161 vt6105Mctlrtail = ctlr;
1166 vt6105Mpnp(Ether* edev)
1170 if(vt6105Mctlrhead == nil)
1174 * Any adapter matches if no edev->port is supplied,
1175 * otherwise the ports must match.
1177 for(ctlr = vt6105Mctlrhead; ctlr != nil; ctlr = ctlr->next){
1180 if(edev->port == 0 || edev->port == ctlr->port){
1189 edev->port = ctlr->port;
1190 edev->irq = ctlr->pcidev->intl;
1191 edev->tbdf = ctlr->pcidev->tbdf;
1193 * Set to 1000Mb/s to fool the bsz calculation. We need
1194 * something better, though.
1197 memmove(edev->ea, ctlr->par, Eaddrlen);
1200 * Linkage to the generic ethernet driver.
1202 edev->attach = vt6105Mattach;
1203 edev->transmit = vt6105Mtransmit;
1204 edev->ifstat = vt6105Mifstat;
1208 edev->promiscuous = vt6105Mpromiscuous;
1209 edev->multicast = vt6105Mmulticast;
1211 edev->maxmtu = ETHERMAXTU+Bslop;
1213 intrenable(edev->irq, vt6105Minterrupt, edev, edev->tbdf, edev->name);
1219 ethervt6105mlink(void)
1221 addethercard("vt6105M", vt6105Mpnp);