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"
24 #include "../port/ethermii.h"
27 Par0 = 0x00, /* Ethernet Address */
28 Rcr = 0x06, /* Receive Configuration */
29 Tcr = 0x07, /* Transmit Configuration */
30 Cr = 0x08, /* Control */
31 Tqw = 0x0A, /* Transmit Queue Wake */
32 Isr = 0x0C, /* Interrupt Status */
33 Imr = 0x0E, /* Interrupt Mask */
34 Mcfilt0 = 0x10, /* Multicast Filter 0 */
35 Mcfilt1 = 0x14, /* Multicast Filter 1 */
36 Rxdaddr = 0x18, /* Current Rd Address */
37 Txdaddr = 0x1C, /* Current Td Address */
38 Phyadr = 0x6C, /* Phy Address */
39 Miisr = 0x6D, /* MII Status */
40 Bcr0 = 0x6E, /* Bus Control */
42 Miicr = 0x70, /* MII Control */
43 Miiadr = 0x71, /* MII Address */
44 Miidata = 0x72, /* MII Data */
45 Eecsr = 0x74, /* EEPROM Control and Status */
46 CfgA = 0x78, /* Chip Configuration A */
50 Cr0 = 0x80, /* Miscellaneous Control */
52 Pmcc = 0x82, /* Power Mgmt Capability Control */
53 Stickhw = 0x83, /* Sticky Hardware Control */
54 Misr = 0x84, /* MII Interrupt Control */
55 Mimr = 0x85, /* MII Interrupt Mask */
62 Sep = 0x01, /* Accept Error Packets */
63 Ar = 0x02, /* Accept Small Packets */
64 Am = 0x04, /* Accept Multicast */
65 Ab = 0x08, /* Accept Broadcast */
66 Prom = 0x10, /* Accept Physical Address Packets */
67 RrftMASK = 0xE0, /* Receive FIFO Threshold */
69 Rrft64 = 0<<RrftSHIFT,
70 Rrft32 = 1<<RrftSHIFT,
71 Rrft128 = 2<<RrftSHIFT,
72 Rrft256 = 3<<RrftSHIFT,
73 Rrft512 = 4<<RrftSHIFT,
74 Rrft768 = 5<<RrftSHIFT,
75 Rrft1024 = 6<<RrftSHIFT,
76 RrftSAF = 7<<RrftSHIFT,
80 Lb0 = 0x02, /* Loopback Mode */
82 Ofset = 0x08, /* Select Back-off Priority */
83 RtsfMASK = 0xE0, /* Transmit FIFO Threshold */
85 Rtsf128 = 0<<RtsfSHIFT,
86 Rtsf256 = 1<<RtsfSHIFT,
87 Rtsf512 = 2<<RtsfSHIFT,
88 Rtsf1024 = 3<<RtsfSHIFT,
89 RtsfSAF = 7<<RtsfSHIFT,
93 Init = 0x0001, /* INIT Process Begin */
94 Strt = 0x0002, /* Start NIC */
95 Stop = 0x0004, /* Stop NIC */
96 Rxon = 0x0008, /* Turn on Receive Process */
97 Txon = 0x0010, /* Turn on Transmit Process */
98 Tdmd = 0x0020, /* Transmit Poll Demand */
99 Rdmd = 0x0040, /* Receive Poll Demand */
100 Eren = 0x0100, /* Early Receive Enable */
101 Fdx = 0x0400, /* Set MAC to Full Duplex */
102 Dpoll = 0x0800, /* Disable Td/Rd Auto Polling */
103 Tdmd1 = 0x2000, /* Transmit Poll Demand 1 */
104 Rdmd1 = 0x4000, /* Receive Poll Demand 1 */
105 Sfrst = 0x8000, /* Software Reset */
109 Prx = 0x0001, /* Packet Received OK */
110 Ptx = 0x0002, /* Packet Transmitted OK */
111 Rxe = 0x0004, /* Receive Error */
112 Txe = 0x0008, /* Transmit Error */
113 Tu = 0x0010, /* Transmit Buffer Underflow */
114 Ru = 0x0020, /* Receive Buffer Link Error */
115 Be = 0x0040, /* PCI Bus Error */
116 Cnt = 0x0080, /* Counter Overflow */
117 Eri = 0x0100, /* Early Receive Interrupt */
118 Udfi = 0x0200, /* Tx FIFO Underflow */
119 Ovfi = 0x0400, /* Receive FIFO Overflow */
120 Pktrace = 0x0800, /* Hmmm... */
121 Norbf = 0x1000, /* No Receive Buffers */
122 Abti = 0x2000, /* Transmission Abort */
123 Srci = 0x4000, /* Port State Change */
124 Geni = 0x8000, /* General Purpose Interrupt */
128 PhyadMASK = 0x1F, /* PHY Address */
130 Mfdc = 0x20, /* Accelerate MDC Speed */
131 Mpo0 = 0x40, /* MII Polling Timer Interval */
136 DmaMASK = 0x07, /* DMA Length */
140 Dma128 = 2<<DmaSHIFT,
141 Dma256 = 3<<DmaSHIFT,
142 Dma512 = 4<<DmaSHIFT,
143 Dma1024 = 5<<DmaSHIFT,
144 DmaSAF = 7<<DmaSHIFT,
145 CrftMASK = 0x38, /* Rx FIFO Threshold */
147 Crft64 = 1<<CrftSHIFT,
148 Crft128 = 2<<CrftSHIFT,
149 Crft256 = 3<<CrftSHIFT,
150 Crft512 = 4<<CrftSHIFT,
151 Crft1024 = 5<<CrftSHIFT,
152 CrftSAF = 7<<CrftSHIFT,
153 Extled = 0x40, /* Extra LED Support Control */
154 Med2 = 0x80, /* Medium Select Control */
158 PotMASK = 0x07, /* Polling Timer Interval */
160 CtftMASK = 0x38, /* Tx FIFO Threshold */
162 Ctft64 = 1<<CtftSHIFT,
163 Ctft128 = 2<<CtftSHIFT,
164 Ctft256 = 3<<CtftSHIFT,
165 Ctft512 = 4<<CtftSHIFT,
166 Ctft1024 = 5<<CtftSHIFT,
167 CtftSAF = 7<<CtftSHIFT,
171 Mdc = 0x01, /* Clock */
172 Mdi = 0x02, /* Data In */
173 Mdo = 0x04, /* Data Out */
174 Mout = 0x08, /* Output Enable */
175 Mdpm = 0x10, /* Direct Program Mode Enable */
176 Wcmd = 0x20, /* Write Enable */
177 Rcmd = 0x40, /* Read Enable */
178 Mauto = 0x80, /* Auto Polling Enable */
182 MadMASK = 0x1F, /* MII Port Address */
184 Mdone = 0x20, /* Accelerate MDC Speed */
185 Msrcen = 0x40, /* MII Polling Timer Interval */
190 Edo = 0x01, /* Data Out */
191 Edi = 0x02, /* Data In */
192 Eck = 0x04, /* Clock */
193 Ecs = 0x08, /* Chip Select */
194 Dpm = 0x10, /* Direct Program Mode Enable */
195 Autold = 0x20, /* Dynamic Reload */
196 Embp = 0x40, /* Embedded Program Enable */
197 Eepr = 0x80, /* Programmed */
201 * Ring descriptor. The space allocated for each
202 * of these will be rounded up to a cache-line boundary.
203 * The first 4 elements are known to the hardware.
205 typedef struct Ds Ds;
217 enum { /* Rx Ds status */
218 Rerr = 0x00000001, /* Buff|Rxserr|Fov|Fae|Crc */
219 Crc = 0x00000002, /* CRC Error */
220 Fae = 0x00000004, /* Frame Alignment Error */
221 Fov = 0x00000008, /* FIFO Overflow */
222 Long = 0x00000010, /* A Long Packet */
223 Runt = 0x00000020, /* A Runt Packet */
224 Rxserr = 0x00000040, /* System Error */
225 Buff = 0x00000080, /* Buffer Underflow Error */
226 Rxedp = 0x00000100, /* End of Packet Buffer */
227 Rxstp = 0x00000200, /* Packet Start */
228 Chn = 0x00000400, /* Chain Buffer */
229 Phy = 0x00000800, /* Physical Address Packet */
230 Bar = 0x00001000, /* Broadcast Packet */
231 Mar = 0x00002000, /* Multicast Packet */
232 Rxok = 0x00008000, /* Packet Received OK */
233 LengthMASK = 0x07FF0000, /* Received Packet Length */
236 Own = 0x80000000, /* Descriptor Owned by NIC */
239 enum { /* Rx Ds control */
240 RbsizeMASK = 0x000007FF, /* Receive Buffer Size */
242 Tag = 0x00010000, /* Receive a Tagged Packet */
243 Udpkt = 0x00020000, /* Receive a UDP Packet */
244 Tcpkt = 0x00040000, /* Receive a TCP Packet */
245 Ipkt = 0x00080000, /* Receive an IP Packet */
246 Tuok = 0x00100000, /* TCP/UDP Checksum OK */
247 Ipok = 0x00200000, /* IP Checksum OK */
248 Snaptag = 0x00400000, /* Snap Packet + 802.1q Tag */
249 Rxlerr = 0x00800000, /* Receive Length Check Error */
250 IpktMASK = 0xff000000, /* Interesting Packet */
254 enum { /* Tx Ds status */
255 NcrMASK = 0x0000000F, /* Collision Retry Count */
257 Cols = 0x00000010, /* Experienced Collisions */
258 Cdh = 0x00000080, /* CD Heartbeat */
259 Abt = 0x00000100, /* Aborted after Excessive Collisions */
260 Owc = 0x00000200, /* Out of Window Collision */
261 Crs = 0x00000400, /* Carrier Sense Lost */
262 Udf = 0x00000800, /* FIFO Underflow */
263 Tbuff = 0x00001000, /* Invalid Td */
264 Txserr = 0x00002000, /* System Error */
265 Terr = 0x00008000, /* Excessive Collisions */
268 enum { /* Tx Ds control */
269 TbsMASK = 0x000007FF, /* Tx Buffer Size */
271 Chain = 0x00008000, /* Chain Buffer */
272 Crcdisable = 0x00010000, /* Disable CRC generation */
273 Stp = 0x00200000, /* Start of Packet */
274 Edp = 0x00400000, /* End of Packet */
275 Ic = 0x00800000, /* Interrupt Control */
278 enum { /* Tx Ds branch */
279 Tdctl = 0x00000001, /* No Interrupt Generated */
287 Rdbsz = ETHERMAXTU+Crcsz+Bslop,
295 typedef struct Ctlr Ctlr;
296 typedef struct Ctlr {
304 QLock alock; /* attach */
305 void* alloc; /* descriptors, etc. */
306 int cls; /* alignment */
322 int tft; /* Tx threshold */
328 uint rxstats[Nrxstats]; /* statistics */
329 uint txstats[Ntxstats];
351 static Ctlr* vt6105Mctlrhead;
352 static Ctlr* vt6105Mctlrtail;
354 #define csr8r(c, r) (inb((c)->port+(r)))
355 #define csr16r(c, r) (ins((c)->port+(r)))
356 #define csr32r(c, r) (inl((c)->port+(r)))
357 #define csr8w(c, r, b) (outb((c)->port+(r), (int)(b)))
358 #define csr16w(c, r, w) (outs((c)->port+(r), (ushort)(w)))
359 #define csr32w(c, r, w) (outl((c)->port+(r), (ulong)(w)))
361 static Lock vt6105Mrblock; /* receive Block freelist */
362 static Block* vt6105Mrbpool;
363 static uint vt6105Mrbpoolsz;
365 typedef struct Regs Regs;
366 typedef struct Regs {
372 static Regs regs[] = {
374 // "Par1", Par0+1, 1,
375 // "Par2", Par0+2, 1,
376 // "Par3", Par0+3, 1,
377 // "Par4", Par0+4, 1,
378 // "Par5", Par0+5, 1,
387 // "Mcfilt0", Mcfilt0,4,
388 // "Mcfilt1", Mcfilt1,4,
389 // "Rxdaddr", Rxdaddr,4,
390 // "Txdaddr", Txdaddr,4,
397 // "Miidata", Miidata,2,
406 "Stickhw", Stickhw,1,
412 static char* rxstats[Nrxstats] = {
415 "Frame Alignment Error",
420 "Buffer Underflow Error",
422 static char* txstats[Ntxstats] = {
423 "Aborted after Excessive Collisions",
424 "Out of Window Collision Seen",
425 "Carrier Sense Lost",
430 "Excessive Collisions",
434 vt6105Mifstat(Ether* edev, void* a, long n, ulong offset)
442 p = alloc = smalloc(READSTR);
444 for(i = 0; i < Nrxstats; i++){
445 p = seprint(p, e, "%s: %ud\n", rxstats[i], ctlr->rxstats[i]);
447 for(i = 0; i < Ntxstats; i++){
448 if(txstats[i] == nil)
450 p = seprint(p, e, "%s: %ud\n", txstats[i], ctlr->txstats[i]);
452 p = seprint(p, e, "cls: %ud\n", ctlr->cls);
453 p = seprint(p, e, "intr: %ud\n", ctlr->intr);
454 p = seprint(p, e, "lintr: %ud\n", ctlr->lintr);
455 p = seprint(p, e, "lsleep: %ud\n", ctlr->lsleep);
456 p = seprint(p, e, "rintr: %ud\n", ctlr->rintr);
457 p = seprint(p, e, "tintr: %ud\n", ctlr->tintr);
458 p = seprint(p, e, "txdw: %ud\n", ctlr->txdw);
459 p = seprint(p, e, "tdumax: %ud\n", ctlr->tdumax);
460 p = seprint(p, e, "tft: %ud\n", ctlr->tft);
462 p = seprint(p, e, "abt: %ud\n", ctlr->abt);
463 p = seprint(p, e, "tbuff: %ud\n", ctlr->tbuff);
464 p = seprint(p, e, "udf: %ud\n", ctlr->udf);
465 p = seprint(p, e, "abti: %ud\n", ctlr->abti);
466 p = seprint(p, e, "udfi: %ud\n", ctlr->udfi);
467 p = seprint(p, e, "tu: %ud\n", ctlr->tu);
469 p = seprint(p, e, "tuok: %ud\n", ctlr->tuok);
470 p = seprint(p, e, "ipok: %ud\n", ctlr->ipok);
472 p = seprint(p, e, "rbpoolsz: %ud\n", vt6105Mrbpoolsz);
473 p = seprint(p, e, "totalt: %uld\n", ctlr->totalt);
475 for(i = 0; regs[i].name != nil; i++){
476 p = seprint(p, e, "%s: %2.2x\n",
477 regs[i].name, csr8r(ctlr, regs[i].offset));
480 if(ctlr->mii != nil && ctlr->mii->curphy != nil){
481 p = seprint(p, e, "phy: ");
482 for(i = 0; i < NMiiPhyr; i++){
483 if(i && ((i & 0x07) == 0))
484 p = seprint(p, e, "\n ");
485 r = miimir(ctlr->mii, i);
486 p = seprint(p, e, " %4.4uX", r);
491 n = readstr(offset, a, n, alloc);
498 vt6105Mpromiscuous(void* arg, int on)
506 rcr = csr8r(ctlr, Rcr);
511 csr8w(ctlr, Rcr, rcr);
515 vt6105Mmulticast(void* arg, uchar* addr, int on)
518 * For now Am is set in Rcr.
519 * Will need to interlock with promiscuous
520 * when this gets filled in.
526 vt6105Mwakeup(void* v)
528 return *((int*)v) != 0;
532 vt6105Mimr(Ctlr* ctlr, int imr)
536 csr16w(ctlr, Imr, ctlr->imr);
537 iunlock(&ctlr->clock);
541 vt6105Mlproc(void* arg)
552 if(ctlr->mii == nil || ctlr->mii->curphy == nil)
554 if(miistatus(ctlr->mii) < 0)
557 phy = ctlr->mii->curphy;
559 csr16w(ctlr, Cr, ctlr->cr & ~(Txon|Rxon));
564 csr16w(ctlr, Cr, ctlr->cr);
565 iunlock(&ctlr->clock);
568 vt6105Mimr(ctlr, Srci);
571 sleep(&ctlr->lrendez, vt6105Mwakeup, &ctlr->lwakeup);
574 pexit("vt6105Mlproc: done", 1);
578 vt6105Mrbfree(Block* bp)
580 bp->rp = bp->lim - (Rdbsz+3);
582 bp->flag &= ~(Bipck | Budpck | Btcpck | Bpktck);
584 ilock(&vt6105Mrblock);
585 bp->next = vt6105Mrbpool;
587 iunlock(&vt6105Mrblock);
595 ilock(&vt6105Mrblock);
596 if((bp = vt6105Mrbpool) != nil){
597 vt6105Mrbpool = bp->next;
600 iunlock(&vt6105Mrblock);
602 if(bp == nil && (bp = iallocb(Rdbsz+3)) != nil){
603 bp->free = vt6105Mrbfree;
610 vt6105Mattach(Ether* edev)
620 if(ctlr->alloc != nil){
621 qunlock(&ctlr->alock);
627 * Receive descriptors should all be aligned on a 4-byte boundary,
628 * but try to do cache-line alignment.
632 dsz = ROUNDUP(sizeof(Ds), ctlr->cls);
633 alloc = mallocalign((ctlr->nrd+ctlr->ntd)*dsz, dsz, 0, 0);
635 qunlock(&ctlr->alock);
640 ctlr->rd = (Ds*)alloc;
644 for(i = 0; i < ctlr->nrd; i++){
649 if((ds = ds->next) == nil)
654 qunlock(&ctlr->alock);
658 prev = (Ds*)(alloc + (ctlr->nrd-1)*dsz);
659 for(i = 0; i < ctlr->nrd; i++){
663 ds->control = Ipkt|Tcpkt|Udpkt|Rdbsz;
664 ds->branch = PCIWADDR(alloc);
666 ds->bp = vt6105Mrballoc();
668 error("vt6105M: can't allocate receive ring\n");
669 ds->bp->rp = (uchar*)ROUNDUP((ulong)ds->bp->rp, 4);
670 ds->addr = PCIWADDR(ds->bp->rp);
672 ds->next = (Ds*)alloc;
679 prev->next = ctlr->rd;
681 ctlr->rdh = ctlr->rd;
683 ctlr->td = (Ds*)alloc;
684 prev = (Ds*)(alloc + (ctlr->ntd-1)*dsz);
685 for(i = 0; i < ctlr->ntd; i++){
689 ds->next = (Ds*)alloc;
693 prev->next = ctlr->td;
694 ctlr->tdh = ctlr->tdt = ctlr->td;
697 ctlr->cr = Dpoll|Rdmd/*|Txon|Rxon*/|Strt;
698 /*Srci|Abti|Norbf|Pktrace|Ovfi|Udfi|Be|Ru|Tu|Txe|Rxe|Ptx|Prx*/
699 ctlr->imr = Abti|Norbf|Pktrace|Ovfi|Udfi|Be|Ru|Tu|Txe|Rxe|Ptx|Prx;
702 csr32w(ctlr, Rxdaddr, PCIWADDR(ctlr->rd));
703 csr32w(ctlr, Txdaddr, PCIWADDR(ctlr->td));
704 csr16w(ctlr, Isr, ~0);
705 csr16w(ctlr, Imr, ctlr->imr);
706 csr16w(ctlr, Cr, ctlr->cr);
707 iunlock(&ctlr->clock);
710 * Wait for link to be ready.
712 for(timeo = 0; timeo < 350; timeo++){
713 if(miistatus(ctlr->mii) == 0)
715 tsleep(&up->sleep, return0, 0, 10);
717 // phy = ctlr->mii->curphy;
718 // print("%s: speed %d fd %d link %d rfc %d tfc %d\n",
719 // edev->name, phy->speed, phy->fd, phy->link, phy->rfc, phy->tfc);
722 ctlr->cr |= Txon|Rxon;
723 csr16w(ctlr, Cr, ctlr->cr);
724 iunlock(&ctlr->clock);
726 snprint(name, KNAMELEN, "#l%dlproc", edev->ctlrno);
727 kproc(name, vt6105Mlproc, edev);
729 qunlock(&ctlr->alock);
734 vt6105Mtransmit(Ether* edev)
739 int control, i, size, tdused, timeo;
748 * Free any completed packets
751 for(tdused = ctlr->tdused; tdused > 0; tdused--){
753 * For some errors the chip will turn the Tx engine
754 * off. Wait for that to happen.
755 * Could reset and re-init the chip here if it doesn't
757 * To do: adjust Tx FIFO threshold on underflow.
759 if(ds->status & (Abt|Tbuff|Udf)){
762 if(ds->status & Tbuff)
766 for(timeo = 0; timeo < 1000; timeo++){
767 if(!(csr16r(ctlr, Cr) & Txon))
772 csr32w(ctlr, Txdaddr, PCIWADDR(ds));
784 for(i = 0; i < Ntxstats-1; i++){
785 if(ds->status & (1<<i))
788 ctlr->txstats[i] += (ds->status & NcrMASK)>>NcrSHIFT;
795 * Try to fill the ring back up.
798 while(tdused < ctlr->ntd-2){
799 if((bp = qget(edev->oq)) == nil)
806 ds->branch = PCIWADDR(ds->next)|Tdctl;
809 ds->addr = PCIWADDR(bp->rp);
810 control = Edp|Stp|((size<<TbsSHIFT) & TbsMASK);
812 ds->control = control;
813 if(tdused >= ctlr->ntd-2){
815 ds->branch &= ~Tdctl;
823 ctlr->tdused = tdused;
825 csr16w(ctlr, Cr, Tdmd|ctlr->cr);
826 if(tdused > ctlr->tdumax)
827 ctlr->tdumax = tdused;
830 ctlr->totalt += lcycles() - t;
831 iunlock(&ctlr->tlock);
835 vt6105Mreceive(Ether* edev)
845 while(!(ds->status & Own) && ds->status != 0){
847 * Can Long packets be received OK?
848 * What happens to the Rxok bit?
850 if(ds->status & Rerr){
851 for(i = 0; i < Nrxstats; i++){
852 if(ds->status & (1<<i))
856 else if(bp = vt6105Mrballoc()){
857 if(ds->control & Tuok){
858 ds->bp->flag |= Btcpck|Budpck;
861 if(ds->control & Ipok){
862 ds->bp->flag |= Bipck;
865 len = ((ds->status & LengthMASK)>>LengthSHIFT)-4;
866 ds->bp->wp = ds->bp->rp+len;
867 etheriq(edev, ds->bp);
868 bp->rp = (uchar*)ROUNDUP((ulong)bp->rp, 4);
869 ds->addr = PCIWADDR(bp->rp);
872 ds->control = Ipkt|Tcpkt|Udpkt|Rdbsz;
876 ds->prev->branch = PCIWADDR(ds);
878 ds->prev->status = Own;
884 csr16w(ctlr, Cr, ctlr->cr);
888 vt6105Minterrupt(Ureg*, void* arg)
892 int imr, isr, r, timeo;
901 csr16w(ctlr, Imr, 0);
905 if((isr = csr16r(ctlr, Isr)) != 0)
906 csr16w(ctlr, Isr, isr);
907 if((isr & ctlr->imr) == 0)
912 ctlr->lwakeup = isr & Srci;
913 wakeup(&ctlr->lrendez);
917 if(isr & (Norbf|Pktrace|Ovfi|Ru|Rxe|Prx)){
918 vt6105Mreceive(edev);
919 isr &= ~(Norbf|Pktrace|Ovfi|Ru|Rxe|Prx);
922 if(isr & (Abti|Udfi|Tu|Txe|Ptx)){
923 if(isr & (Abti|Udfi|Tu)){
930 for(timeo = 0; timeo < 1000; timeo++){
931 if(!(csr16r(ctlr, Cr) & Txon))
936 if((isr & Udfi) && ctlr->tft < CtftSAF){
937 ctlr->tft += 1<<CtftSHIFT;
938 r = csr8r(ctlr, Bcr1) & ~CtftMASK;
939 csr8w(ctlr, Bcr1, r|ctlr->tft);
944 ctlr->totalt += lcycles() - t;
945 vt6105Mtransmit(edev);
947 isr &= ~(Abti|Udfi|Tu|Txe|Ptx);
951 panic("vt6105M: isr %4.4uX", isr);
954 csr16w(ctlr, Imr, ctlr->imr);
956 ctlr->totalt += lcycles() - t;
957 iunlock(&ctlr->clock);
961 vt6105Mmiimicmd(Mii* mii, int pa, int ra, int cmd, int data)
968 csr8w(ctlr, Miicr, 0);
969 r = csr8r(ctlr, Phyadr);
970 csr8w(ctlr, Phyadr, (r & ~PhyadMASK)|pa);
971 csr8w(ctlr, Phyadr, pa);
972 csr8w(ctlr, Miiadr, ra);
974 csr16w(ctlr, Miidata, data);
975 csr8w(ctlr, Miicr, cmd);
977 for(timeo = 0; timeo < 10000; timeo++){
978 if(!(csr8r(ctlr, Miicr) & cmd))
987 return csr16r(ctlr, Miidata);
991 vt6105Mmiimir(Mii* mii, int pa, int ra)
993 return vt6105Mmiimicmd(mii, pa, ra, Rcmd, 0);
997 vt6105Mmiimiw(Mii* mii, int pa, int ra, int data)
999 return vt6105Mmiimicmd(mii, pa, ra, Wcmd, data);
1003 vt6105Mdetach(Ctlr* ctlr)
1008 * Reset power management registers.
1010 revid = pcicfgr8(ctlr->pcidev, PciRID);
1012 /* Set power state D0. */
1013 csr8w(ctlr, Stickhw, csr8r(ctlr, Stickhw) & 0xFC);
1015 /* Disable force PME-enable. */
1016 csr8w(ctlr, Wolcgclr, 0x80);
1018 /* Clear WOL config and status bits. */
1019 csr8w(ctlr, Wolcrclr, 0xFF);
1020 csr8w(ctlr, Pwrcsrclr, 0xFF);
1024 * Soft reset the controller.
1026 csr16w(ctlr, Cr, Stop);
1027 csr16w(ctlr, Cr, Stop|Sfrst);
1028 /* limit used to be 10000, but that wasn't enough for our Soekris 5501s */
1029 for(timeo = 0; timeo < 100000; timeo++){
1030 if(!(csr16r(ctlr, Cr) & Sfrst))
1041 vt6105Mreset(Ctlr* ctlr)
1046 if(vt6105Mdetach(ctlr) < 0)
1050 * Load the MAC address into the PAR[01]
1053 r = csr8r(ctlr, Eecsr);
1054 csr8w(ctlr, Eecsr, Autold|r);
1055 /* limit used to be 100, but that wasn't enough for our Soekris 5501s */
1056 for(timeo = 0; timeo < 100000; timeo++){
1057 if(!(csr8r(ctlr, Cr) & Autold))
1064 for(i = 0; i < Eaddrlen; i++)
1065 ctlr->par[i] = csr8r(ctlr, Par0+i);
1068 * Configure DMA and Rx/Tx thresholds.
1069 * If the Rx/Tx threshold bits in Bcr[01] are 0 then
1070 * the thresholds are determined by Rcr/Tcr.
1072 r = csr8r(ctlr, Bcr0) & ~(CrftMASK|DmaMASK);
1073 csr8w(ctlr, Bcr0, r|Crft128|DmaSAF);
1074 r = csr8r(ctlr, Bcr1) & ~CtftMASK;
1075 csr8w(ctlr, Bcr1, r|ctlr->tft);
1077 r = csr8r(ctlr, Rcr) & ~(RrftMASK|Prom|Ar|Sep);
1078 csr8w(ctlr, Rcr, r|Ab|Am);
1079 csr32w(ctlr, Mcfilt0, ~0UL); /* accept all multicast */
1080 csr32w(ctlr, Mcfilt1, ~0UL);
1082 r = csr8r(ctlr, Tcr) & ~(RtsfMASK|Ofset|Lb1|Lb0);
1083 csr8w(ctlr, Tcr, r);
1088 if((ctlr->mii = malloc(sizeof(Mii))) == nil)
1090 ctlr->mii->mir = vt6105Mmiimir;
1091 ctlr->mii->miw = vt6105Mmiimiw;
1092 ctlr->mii->ctlr = ctlr;
1094 if(mii(ctlr->mii, ~0) == 0 || (phy = ctlr->mii->curphy) == nil){
1099 // print("oui %X phyno %d\n", phy->oui, phy->phyno);
1102 if(miistatus(ctlr->mii) < 0){
1103 // miireset(ctlr->mii);
1104 miiane(ctlr->mii, ~0, ~0, ~0);
1118 while(p = pcimatch(p, 0, 0)){
1119 if(p->ccrb != Pcibcnet || p->ccru != Pciscether)
1122 switch((p->did<<16)|p->vid){
1125 case (0x3053<<16)|0x1106: /* Rhine III-M vt6105M */
1129 port = p->mem[0].bar & ~0x01;
1130 if(ioalloc(port, p->mem[0].size, 0, "vt6105M") < 0){
1131 print("vt6105M: port 0x%uX in use\n", port);
1134 ctlr = malloc(sizeof(Ctlr));
1136 print("vt6105M: can't allocate memory\n");
1143 ctlr->id = (p->did<<16)|p->vid;
1144 if((cls = pcicfgr8(p, PciCLS)) == 0 || cls == 0xFF)
1147 ctlr->tft = CtftSAF;
1149 if(vt6105Mreset(ctlr)){
1156 if(vt6105Mctlrhead != nil)
1157 vt6105Mctlrtail->next = ctlr;
1159 vt6105Mctlrhead = ctlr;
1160 vt6105Mctlrtail = ctlr;
1165 vt6105Mpnp(Ether* edev)
1169 if(vt6105Mctlrhead == nil)
1173 * Any adapter matches if no edev->port is supplied,
1174 * otherwise the ports must match.
1176 for(ctlr = vt6105Mctlrhead; ctlr != nil; ctlr = ctlr->next){
1179 if(edev->port == 0 || edev->port == ctlr->port){
1188 edev->port = ctlr->port;
1189 edev->irq = ctlr->pcidev->intl;
1190 edev->tbdf = ctlr->pcidev->tbdf;
1192 * Set to 1000Mb/s to fool the bsz calculation. We need
1193 * something better, though.
1196 memmove(edev->ea, ctlr->par, Eaddrlen);
1199 * Linkage to the generic ethernet driver.
1201 edev->attach = vt6105Mattach;
1202 edev->transmit = vt6105Mtransmit;
1203 edev->ifstat = vt6105Mifstat;
1207 edev->promiscuous = vt6105Mpromiscuous;
1208 edev->multicast = vt6105Mmulticast;
1210 edev->maxmtu = ETHERMAXTU+Bslop;
1212 intrenable(edev->irq, vt6105Minterrupt, edev, edev->tbdf, edev->name);
1218 ethervt6105mlink(void)
1220 addethercard("vt6105M", vt6105Mpnp);