2 * VIA VT6102 Fast Ethernet Controller (Rhine II).
4 * cache-line size alignments - done
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.
13 #include "../port/lib.h"
18 #include "../port/error.h"
19 #include "../port/netif.h"
20 #include "../port/etherif.h"
21 #include "../port/ethermii.h"
24 Par0 = 0x00, /* Ethernet Address */
25 Rcr = 0x06, /* Receive Configuration */
26 Tcr = 0x07, /* Transmit Configuration */
27 Cr = 0x08, /* Control */
28 Isr = 0x0C, /* Interrupt Status */
29 Imr = 0x0E, /* Interrupt Mask */
30 Mcfilt0 = 0x10, /* Multicast Filter 0 */
31 Mcfilt1 = 0x14, /* Multicast Filter 1 */
32 Rxdaddr = 0x18, /* Current Rx Descriptor Address */
33 Txdaddr = 0x1C, /* Current Tx Descriptor Address */
34 Phyadr = 0x6C, /* Phy Address */
35 Miisr = 0x6D, /* MII Status */
36 Bcr0 = 0x6E, /* Bus Control */
38 Miicr = 0x70, /* MII Control */
39 Miiadr = 0x71, /* MII Address */
40 Miidata = 0x72, /* MII Data */
41 Eecsr = 0x74, /* EEPROM Control and Status */
42 Stickhw = 0x83, /* Sticky Hardware Control */
49 Sep = 0x01, /* Accept Error Packets */
50 Ar = 0x02, /* Accept Small Packets */
51 Am = 0x04, /* Accept Multicast */
52 Ab = 0x08, /* Accept Broadcast */
53 Prom = 0x10, /* Accept Physical Address Packets */
54 RrftMASK = 0xE0, /* Receive FIFO Threshold */
56 Rrft64 = 0<<RrftSHIFT,
57 Rrft32 = 1<<RrftSHIFT,
58 Rrft128 = 2<<RrftSHIFT,
59 Rrft256 = 3<<RrftSHIFT,
60 Rrft512 = 4<<RrftSHIFT,
61 Rrft768 = 5<<RrftSHIFT,
62 Rrft1024 = 6<<RrftSHIFT,
63 RrftSAF = 7<<RrftSHIFT,
67 Lb0 = 0x02, /* Loopback Mode */
69 Ofset = 0x08, /* Back-off Priority Selection */
70 RtsfMASK = 0xE0, /* Transmit FIFO Threshold */
72 Rtsf128 = 0<<RtsfSHIFT,
73 Rtsf256 = 1<<RtsfSHIFT,
74 Rtsf512 = 2<<RtsfSHIFT,
75 Rtsf1024 = 3<<RtsfSHIFT,
76 RtsfSAF = 7<<RtsfSHIFT,
80 Init = 0x0001, /* INIT Process Begin */
81 Strt = 0x0002, /* Start NIC */
82 Stop = 0x0004, /* Stop NIC */
83 Rxon = 0x0008, /* Turn on Receive Process */
84 Txon = 0x0010, /* Turn on Transmit Process */
85 Tdmd = 0x0020, /* Transmit Poll Demand */
86 Rdmd = 0x0040, /* Receive Poll Demand */
87 Eren = 0x0100, /* Early Receive Enable */
88 Fdx = 0x0400, /* Set MAC to Full Duplex Mode */
89 Dpoll = 0x0800, /* Disable Td/Rd Auto Polling */
90 Tdmd1 = 0x2000, /* Transmit Poll Demand 1 */
91 Rdmd1 = 0x4000, /* Receive Poll Demand 1 */
92 Sfrst = 0x8000, /* Software Reset */
96 Prx = 0x0001, /* Received Packet Successfully */
97 Ptx = 0x0002, /* Transmitted Packet Successfully */
98 Rxe = 0x0004, /* Receive Error */
99 Txe = 0x0008, /* Transmit Error */
100 Tu = 0x0010, /* Transmit Buffer Underflow */
101 Ru = 0x0020, /* Receive Buffer Link Error */
102 Be = 0x0040, /* PCI Bus Error */
103 Cnt = 0x0080, /* Counter Overflow */
104 Eri = 0x0100, /* Early Receive Interrupt */
105 Udfi = 0x0200, /* Tx FIFO Underflow */
106 Ovfi = 0x0400, /* Receive FIFO Overflow */
107 Pktrace = 0x0800, /* Hmmm... */
108 Norbf = 0x1000, /* No Receive Buffers */
109 Abti = 0x2000, /* Transmission Abort */
110 Srci = 0x4000, /* Port State Change */
111 Geni = 0x8000, /* General Purpose Interrupt */
115 PhyadMASK = 0x1F, /* PHY Address */
117 Mfdc = 0x20, /* Accelerate MDC Speed */
118 Mpo0 = 0x40, /* MII Polling Timer Interval */
123 DmaMASK = 0x07, /* DMA Length */
127 Dma128 = 2<<DmaSHIFT,
128 Dma256 = 3<<DmaSHIFT,
129 Dma512 = 4<<DmaSHIFT,
130 Dma1024 = 5<<DmaSHIFT,
131 DmaSAF = 7<<DmaSHIFT,
132 CrftMASK = 0x38, /* Rx FIFO Threshold */
134 Crft64 = 1<<CrftSHIFT,
135 Crft128 = 2<<CrftSHIFT,
136 Crft256 = 3<<CrftSHIFT,
137 Crft512 = 4<<CrftSHIFT,
138 Crft1024 = 5<<CrftSHIFT,
139 CrftSAF = 7<<CrftSHIFT,
140 Extled = 0x40, /* Extra LED Support Control */
141 Med2 = 0x80, /* Medium Select Control */
145 PotMASK = 0x07, /* Polling Timer Interval */
147 CtftMASK = 0x38, /* Tx FIFO Threshold */
149 Ctft64 = 1<<CtftSHIFT,
150 Ctft128 = 2<<CtftSHIFT,
151 Ctft256 = 3<<CtftSHIFT,
152 Ctft512 = 4<<CtftSHIFT,
153 Ctft1024 = 5<<CtftSHIFT,
154 CtftSAF = 7<<CtftSHIFT,
158 Mdc = 0x01, /* Clock */
159 Mdi = 0x02, /* Data In */
160 Mdo = 0x04, /* Data Out */
161 Mout = 0x08, /* Output Enable */
162 Mdpm = 0x10, /* Direct Program Mode Enable */
163 Wcmd = 0x20, /* Write Enable */
164 Rcmd = 0x40, /* Read Enable */
165 Mauto = 0x80, /* Auto Polling Enable */
169 MadMASK = 0x1F, /* MII Port Address */
171 Mdone = 0x20, /* Accelerate MDC Speed */
172 Msrcen = 0x40, /* MII Polling Timer Interval */
177 Edo = 0x01, /* Data Out */
178 Edi = 0x02, /* Data In */
179 Eck = 0x04, /* Clock */
180 Ecs = 0x08, /* Chip Select */
181 Dpm = 0x10, /* Direct Program Mode Enable */
182 Autold = 0x20, /* Dynamic Reload */
183 Embp = 0x40, /* Embedded Program Enable */
184 Eepr = 0x80, /* Programmed */
188 * Ring descriptor. The space allocated for each
189 * of these will be rounded up to a cache-line boundary.
190 * The first 4 elements are known to the hardware.
192 typedef struct Ds Ds;
205 enum { /* Rx Ds status */
206 Rerr = 0x00000001, /* Receiver Error */
207 Crc = 0x00000002, /* CRC Error */
208 Fae = 0x00000004, /* Frame Alignment Error */
209 Fov = 0x00000008, /* FIFO Overflow */
210 Long = 0x00000010, /* A Long Packet */
211 Runt = 0x00000020, /* A Runt Packet */
212 Rxserr = 0x00000040, /* System Error */
213 Buff = 0x00000080, /* Buffer Underflow Error */
214 Rxedp = 0x00000100, /* End of Packet Buffer */
215 Rxstp = 0x00000200, /* Packet Start */
216 Chn = 0x00000400, /* Chain Buffer */
217 Phy = 0x00000800, /* Physical Address Packet */
218 Bar = 0x00001000, /* Broadcast Packet */
219 Mar = 0x00002000, /* Multicast Packet */
220 Rxok = 0x00008000, /* Packet Received Successfully */
221 LengthMASK = 0x07FF0000, /* Received Packet Length */
224 Own = 0x80000000, /* Descriptor Owned by NIC */
227 enum { /* Tx Ds status */
228 NcrMASK = 0x0000000F, /* Collision Retry Count */
230 Cols = 0x00000010, /* Experienced Collisions */
231 Cdh = 0x00000080, /* CD Heartbeat */
232 Abt = 0x00000100, /* Aborted after Excessive Collisions */
233 Owc = 0x00000200, /* Out of Window Collision Seen */
234 Crs = 0x00000400, /* Carrier Sense Lost */
235 Udf = 0x00000800, /* FIFO Underflow */
236 Tbuff = 0x00001000, /* Invalid Td */
237 Txserr = 0x00002000, /* System Error */
238 Terr = 0x00008000, /* Excessive Collisions */
241 enum { /* Tx Ds control */
242 TbsMASK = 0x000007FF, /* Tx Buffer Size */
244 Chain = 0x00008000, /* Chain Buffer */
245 Crcdisable = 0x00010000, /* Disable CRC generation */
246 Stp = 0x00200000, /* Start of Packet */
247 Edp = 0x00400000, /* End of Packet */
248 Ic = 0x00800000, /* Assert Interrupt Immediately */
254 Rdbsz = ROUNDUP(ETHERMAXTU+4, 4),
262 typedef struct Ctlr Ctlr;
263 typedef struct Ctlr {
271 QLock alock; /* attach */
272 void* alloc; /* receive/transmit descriptors */
273 int cls; /* alignment */
289 int tft; /* Tx threshold */
295 uint rxstats[Nrxstats]; /* statistics */
296 uint txstats[Ntxstats];
308 static Ctlr* vt6102ctlrhead;
309 static Ctlr* vt6102ctlrtail;
311 #define csr8r(c, r) (inb((c)->port+(r)))
312 #define csr16r(c, r) (ins((c)->port+(r)))
313 #define csr32r(c, r) (inl((c)->port+(r)))
314 #define csr8w(c, r, b) (outb((c)->port+(r), (int)(b)))
315 #define csr16w(c, r, w) (outs((c)->port+(r), (ushort)(w)))
316 #define csr32w(c, r, w) (outl((c)->port+(r), (ulong)(w)))
318 static char* rxstats[Nrxstats] = {
321 "Frame Alignment Error",
326 "Buffer Underflow Error",
328 static char* txstats[Ntxstats] = {
329 "Aborted after Excessive Collisions",
330 "Out of Window Collision Seen",
331 "Carrier Sense Lost",
336 "Excessive Collisions",
340 vt6102ifstat(Ether* edev, void* a, long n, ulong offset)
348 p = smalloc(READSTR);
350 for(i = 0; i < Nrxstats; i++){
351 l += snprint(p+l, READSTR-l, "%s: %ud\n",
352 rxstats[i], ctlr->rxstats[i]);
354 for(i = 0; i < Ntxstats; i++){
355 if(txstats[i] == nil)
357 l += snprint(p+l, READSTR-l, "%s: %ud\n",
358 txstats[i], ctlr->txstats[i]);
360 l += snprint(p+l, READSTR-l, "cls: %ud\n", ctlr->cls);
361 l += snprint(p+l, READSTR-l, "intr: %ud\n", ctlr->intr);
362 l += snprint(p+l, READSTR-l, "lintr: %ud\n", ctlr->lintr);
363 l += snprint(p+l, READSTR-l, "lsleep: %ud\n", ctlr->lsleep);
364 l += snprint(p+l, READSTR-l, "rintr: %ud\n", ctlr->rintr);
365 l += snprint(p+l, READSTR-l, "tintr: %ud\n", ctlr->tintr);
366 l += snprint(p+l, READSTR-l, "taligned: %ud\n", ctlr->taligned);
367 l += snprint(p+l, READSTR-l, "tsplit: %ud\n", ctlr->tsplit);
368 l += snprint(p+l, READSTR-l, "tcopied: %ud\n", ctlr->tcopied);
369 l += snprint(p+l, READSTR-l, "txdw: %ud\n", ctlr->txdw);
370 l += snprint(p+l, READSTR-l, "tft: %ud\n", ctlr->tft);
372 if(ctlr->mii != nil && ctlr->mii->curphy != nil){
373 l += snprint(p+l, READSTR-l, "phy: ");
374 for(i = 0; i < NMiiPhyr; i++){
375 if(i && ((i & 0x07) == 0))
376 l += snprint(p+l, READSTR-l, "\n ");
377 r = miimir(ctlr->mii, i);
378 l += snprint(p+l, READSTR-l, " %4.4uX", r);
380 snprint(p+l, READSTR-l, "\n");
382 snprint(p+l, READSTR-l, "\n");
384 n = readstr(offset, a, n, p);
391 vt6102promiscuous(void* arg, int on)
399 rcr = csr8r(ctlr, Rcr);
404 csr8w(ctlr, Rcr, rcr);
408 vt6102multicast(void* arg, uchar* addr, int on)
411 * For now Am is set in Rcr.
412 * Will need to interlock with promiscuous
413 * when this gets filled in.
419 vt6102wakeup(void* v)
421 return *((int*)v) != 0;
425 vt6102imr(Ctlr* ctlr, int imr)
429 csr16w(ctlr, Imr, ctlr->imr);
430 iunlock(&ctlr->clock);
434 vt6102lproc(void* arg)
445 if(ctlr->mii == nil || ctlr->mii->curphy == nil)
447 if(miistatus(ctlr->mii) < 0)
450 phy = ctlr->mii->curphy;
456 csr16w(ctlr, Cr, ctlr->cr);
457 iunlock(&ctlr->clock);
460 vt6102imr(ctlr, Srci);
463 sleep(&ctlr->lrendez, vt6102wakeup, &ctlr->lwakeup);
466 pexit("vt6102lproc: done", 1);
470 vt6102attach(Ether* edev)
475 uchar *alloc, *bounce;
480 if(ctlr->alloc != nil){
481 qunlock(&ctlr->alock);
486 * Descriptor and bounce-buffer space.
487 * Must all be aligned on a 4-byte boundary,
488 * but try to align on cache-lines.
492 dsz = ROUNDUP(sizeof(Ds), ctlr->cls);
493 alloc = mallocalign((ctlr->nrd+ctlr->ntd)*dsz + ctlr->ntd*Txcopy, dsz, 0, 0);
495 qunlock(&ctlr->alock);
500 ctlr->rd = (Ds*)alloc;
504 for(i = 0; i < ctlr->nrd; i++){
509 if((ds = ds->next) == nil)
514 qunlock(&ctlr->alock);
518 prev = ctlr->rd + ctlr->nrd-1;
519 for(i = 0; i < ctlr->nrd; i++){
524 ds->branch = PCIWADDR(alloc);
526 ds->bp = iallocb(Rdbsz+3);
528 error("vt6102: can't allocate receive ring\n");
529 ds->bp->rp = (uchar*)ROUNDUP((ulong)ds->bp->rp, 4);
530 ds->addr = PCIWADDR(ds->bp->rp);
532 ds->next = (Ds*)alloc;
539 prev->next = ctlr->rd;
541 ctlr->rdh = ctlr->rd;
543 ctlr->td = (Ds*)alloc;
544 prev = ctlr->td + ctlr->ntd-1;
545 bounce = alloc + ctlr->ntd*dsz;
546 for(i = 0; i < ctlr->ntd; i++){
552 ds->next = (Ds*)alloc;
556 prev->next = ctlr->td;
557 ctlr->tdh = ctlr->tdt = ctlr->td;
560 ctlr->cr = Dpoll|Rdmd|Txon|Rxon|Strt;
561 /*Srci|Abti|Norbf|Pktrace|Ovfi|Udfi|Be|Ru|Tu|Txe|Rxe|Ptx|Prx*/
562 ctlr->imr = Abti|Norbf|Pktrace|Ovfi|Udfi|Be|Ru|Tu|Txe|Rxe|Ptx|Prx;
565 csr32w(ctlr, Rxdaddr, PCIWADDR(ctlr->rd));
566 csr32w(ctlr, Txdaddr, PCIWADDR(ctlr->td));
567 csr16w(ctlr, Isr, ~0);
568 csr16w(ctlr, Imr, ctlr->imr);
569 csr16w(ctlr, Cr, ctlr->cr);
570 iunlock(&ctlr->clock);
572 snprint(name, KNAMELEN, "#l%dlproc", edev->ctlrno);
573 kproc(name, vt6102lproc, edev);
575 qunlock(&ctlr->alock);
580 vt6102transmit(Ether* edev)
585 int control, i, o, prefix, size, tdused, timeo;
592 * Free any completed packets
595 for(tdused = ctlr->tdused; tdused > 0; tdused--){
597 * For some errors the chip will turn the Tx engine
598 * off. Wait for that to happen.
599 * Could reset and re-init the chip here if it doesn't
601 * To do: adjust Tx FIFO threshold on underflow.
603 if(ds->status & (Abt|Tbuff|Udf)){
604 for(timeo = 0; timeo < 1000; timeo++){
605 if(!(csr16r(ctlr, Cr) & Txon))
610 csr32w(ctlr, Txdaddr, PCIWADDR(ds));
622 for(i = 0; i < Ntxstats-1; i++){
623 if(ds->status & (1<<i))
626 ctlr->txstats[i] += (ds->status & NcrMASK)>>NcrSHIFT;
633 * Try to fill the ring back up.
636 while(tdused < ctlr->ntd-2){
637 if((bp = qget(edev->oq)) == nil)
644 if(o = (((int)bp->rp) & 0x03)){
648 memmove(ds->bounce, bp->rp, prefix);
649 ds->addr = PCIWADDR(ds->bounce);
655 ds->branch = PCIWADDR(ds->next);
660 next->addr = PCIWADDR(bp->rp);
661 next->branch = PCIWADDR(next->next);
662 next->control = Edp|Chain|((size<<TbsSHIFT) & TbsMASK);
664 control = Stp|Chain|((prefix<<TbsSHIFT) & TbsMASK);
672 ds->addr = PCIWADDR(bp->rp);
673 control = Edp|Stp|((size<<TbsSHIFT) & TbsMASK);
679 control = Edp|Stp|((prefix<<TbsSHIFT) & TbsMASK);
683 ds->control = control;
684 if(tdused >= ctlr->ntd-2){
694 ctlr->tdused = tdused;
696 csr16w(ctlr, Cr, Tdmd|ctlr->cr);
698 iunlock(&ctlr->tlock);
702 vt6102receive(Ether* edev)
712 while(!(ds->status & Own) && ds->status != 0){
713 if(ds->status & Rerr){
714 for(i = 0; i < Nrxstats; i++){
715 if(ds->status & (1<<i))
719 else if(bp = iallocb(Rdbsz+3)){
720 len = ((ds->status & LengthMASK)>>LengthSHIFT)-4;
721 ds->bp->wp = ds->bp->rp+len;
722 etheriq(edev, ds->bp);
723 bp->rp = (uchar*)ROUNDUP((ulong)bp->rp, 4);
724 ds->addr = PCIWADDR(bp->rp);
731 ds->prev->branch = PCIWADDR(ds);
733 ds->prev->status = Own;
739 csr16w(ctlr, Cr, ctlr->cr);
743 vt6102interrupt(Ureg*, void* arg)
747 int imr, isr, r, timeo;
753 csr16w(ctlr, Imr, 0);
757 if((isr = csr16r(ctlr, Isr)) != 0)
758 csr16w(ctlr, Isr, isr);
759 if((isr & ctlr->imr) == 0)
764 ctlr->lwakeup = isr & Srci;
765 wakeup(&ctlr->lrendez);
769 if(isr & (Norbf|Pktrace|Ovfi|Ru|Rxe|Prx)){
771 isr &= ~(Norbf|Pktrace|Ovfi|Ru|Rxe|Prx);
774 if(isr & (Abti|Udfi|Tu|Txe|Ptx)){
775 if(isr & (Abti|Udfi|Tu)){
776 for(timeo = 0; timeo < 1000; timeo++){
777 if(!(csr16r(ctlr, Cr) & Txon))
782 if((isr & Udfi) && ctlr->tft < CtftSAF){
783 ctlr->tft += 1<<CtftSHIFT;
784 r = csr8r(ctlr, Bcr1) & ~CtftMASK;
785 csr8w(ctlr, Bcr1, r|ctlr->tft);
788 vt6102transmit(edev);
789 isr &= ~(Abti|Udfi|Tu|Txe|Ptx);
793 panic("vt6102: isr %4.4uX", isr);
796 csr16w(ctlr, Imr, ctlr->imr);
797 iunlock(&ctlr->clock);
801 vt6102miimicmd(Mii* mii, int pa, int ra, int cmd, int data)
808 csr8w(ctlr, Miicr, 0);
809 r = csr8r(ctlr, Phyadr);
810 csr8w(ctlr, Phyadr, (r & ~PhyadMASK)|pa);
811 csr8w(ctlr, Phyadr, pa);
812 csr8w(ctlr, Miiadr, ra);
814 csr16w(ctlr, Miidata, data);
815 csr8w(ctlr, Miicr, cmd);
817 for(timeo = 0; timeo < 10000; timeo++){
818 if(!(csr8r(ctlr, Miicr) & cmd))
827 return csr16r(ctlr, Miidata);
831 vt6102miimir(Mii* mii, int pa, int ra)
833 return vt6102miimicmd(mii, pa, ra, Rcmd, 0);
837 vt6102miimiw(Mii* mii, int pa, int ra, int data)
839 return vt6102miimicmd(mii, pa, ra, Wcmd, data);
843 vt6102detach(Ctlr* ctlr)
848 * Reset power management registers.
850 revid = pcicfgr8(ctlr->pcidev, PciRID);
852 /* Set power state D0. */
853 csr8w(ctlr, Stickhw, csr8r(ctlr, Stickhw) & 0xFC);
855 /* Disable force PME-enable. */
856 csr8w(ctlr, Wolcgclr, 0x80);
858 /* Clear WOL config and status bits. */
859 csr8w(ctlr, Wolcrclr, 0xFF);
860 csr8w(ctlr, Pwrcsrclr, 0xFF);
864 * Soft reset the controller.
866 csr16w(ctlr, Cr, Stop);
867 csr16w(ctlr, Cr, Stop|Sfrst);
868 for(timeo = 0; timeo < 10000; timeo++){
869 if(!(csr16r(ctlr, Cr) & Sfrst))
880 vt6102reset(Ctlr* ctlr)
885 if(vt6102detach(ctlr) < 0)
889 * Load the MAC address into the PAR[01]
892 r = csr8r(ctlr, Eecsr);
893 csr8w(ctlr, Eecsr, Autold|r);
894 for(timeo = 0; timeo < 100; timeo++){
895 if(!(csr8r(ctlr, Cr) & Autold))
902 for(i = 0; i < Eaddrlen; i++)
903 ctlr->par[i] = csr8r(ctlr, Par0+i);
906 * Configure DMA and Rx/Tx thresholds.
907 * If the Rx/Tx threshold bits in Bcr[01] are 0 then
908 * the thresholds are determined by Rcr/Tcr.
910 r = csr8r(ctlr, Bcr0) & ~(CrftMASK|DmaMASK);
911 csr8w(ctlr, Bcr0, r|Crft64|Dma64);
912 r = csr8r(ctlr, Bcr1) & ~CtftMASK;
913 csr8w(ctlr, Bcr1, r|ctlr->tft);
915 r = csr8r(ctlr, Rcr) & ~(RrftMASK|Prom|Ar|Sep);
916 csr8w(ctlr, Rcr, r|Ab|Am);
917 csr32w(ctlr, Mcfilt0, ~0UL); /* accept all multicast */
918 csr32w(ctlr, Mcfilt1, ~0UL);
920 r = csr8r(ctlr, Tcr) & ~(RtsfMASK|Ofset|Lb1|Lb0);
926 if((ctlr->mii = malloc(sizeof(Mii))) == nil)
928 ctlr->mii->mir = vt6102miimir;
929 ctlr->mii->miw = vt6102miimiw;
930 ctlr->mii->ctlr = ctlr;
932 if(mii(ctlr->mii, ~0) == 0 || (phy = ctlr->mii->curphy) == nil){
937 // print("oui %X phyno %d\n", phy->oui, phy->phyno);
940 //miiane(ctlr->mii, ~0, ~0, ~0);
953 while(p = pcimatch(p, 0, 0)){
954 if(p->ccrb != Pcibcnet || p->ccru != Pciscether)
957 switch((p->did<<16)|p->vid){
960 case (0x3065<<16)|0x1106: /* Rhine II */
961 case (0x3106<<16)|0x1106: /* Rhine III */
965 port = p->mem[0].bar & ~0x01;
966 if(ioalloc(port, p->mem[0].size, 0, "vt6102") < 0){
967 print("vt6102: port 0x%uX in use\n", port);
970 ctlr = malloc(sizeof(Ctlr));
972 print("vt6102: can't allocate memory\n");
979 ctlr->id = (p->did<<16)|p->vid;
980 if((cls = pcicfgr8(p, PciCLS)) == 0 || cls == 0xFF)
985 if(vt6102reset(ctlr)){
992 if(vt6102ctlrhead != nil)
993 vt6102ctlrtail->next = ctlr;
995 vt6102ctlrhead = ctlr;
996 vt6102ctlrtail = ctlr;
1001 vt6102pnp(Ether* edev)
1005 if(vt6102ctlrhead == nil)
1009 * Any adapter matches if no edev->port is supplied,
1010 * otherwise the ports must match.
1012 for(ctlr = vt6102ctlrhead; ctlr != nil; ctlr = ctlr->next){
1015 if(edev->port == 0 || edev->port == ctlr->port){
1024 edev->port = ctlr->port;
1025 edev->irq = ctlr->pcidev->intl;
1026 edev->tbdf = ctlr->pcidev->tbdf;
1028 memmove(edev->ea, ctlr->par, Eaddrlen);
1031 * Linkage to the generic ethernet driver.
1033 edev->attach = vt6102attach;
1034 edev->transmit = vt6102transmit;
1035 edev->ifstat = vt6102ifstat;
1039 edev->promiscuous = vt6102promiscuous;
1040 edev->multicast = vt6102multicast;
1042 intrenable(edev->irq, vt6102interrupt, edev, edev->tbdf, edev->name);
1048 ethervt6102link(void)
1050 addethercard("vt6102", vt6102pnp);
1051 addethercard("rhine", vt6102pnp);