xref: /plan9/sys/src/9/pc/ethervt6105m.c (revision 5b79763299e9ee505816eaec895aa7ccdd6561ca)
1 /*
2  * VIA VT6105M Fast Ethernet Controller (Rhine III).
3  * To do:
4  *	reorganise initialisation/shutdown/reset
5  *	adjust Tx FIFO threshold on underflow - untested
6  *	why does the link status never cause an interrupt?
7  *	use the lproc as a periodic timer for stalls, etc.
8  *	take non-HW stuff out of descriptor for 64-bit
9  *	cleanliness
10  *	why does the receive buffer alloc have a +3?
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 	Tqw		= 0x0A,			/* Transmit Queue Wake */
30 	Isr		= 0x0C,			/* Interrupt Status */
31 	Imr		= 0x0E,			/* Interrupt Mask */
32 	Mcfilt0		= 0x10,			/* Multicast Filter 0 */
33 	Mcfilt1		= 0x14,			/* Multicast Filter 1 */
34 	Rxdaddr		= 0x18,			/* Current Rd Address */
35 	Txdaddr		= 0x1C,			/* Current Td Address */
36 	Phyadr		= 0x6C,			/* Phy Address */
37 	Miisr		= 0x6D,			/* MII Status */
38 	Bcr0		= 0x6E,			/* Bus Control */
39 	Bcr1		= 0x6F,
40 	Miicr		= 0x70,			/* MII Control */
41 	Miiadr		= 0x71,			/* MII Address */
42 	Miidata		= 0x72,			/* MII Data */
43 	Eecsr		= 0x74,			/* EEPROM Control and Status */
44 	CfgA		= 0x78,			/* Chip Configuration A */
45 	CfgB		= 0x79,
46 	CfgC		= 0x7A,
47 	CfgD		= 0x7B,
48 	Cr0		= 0x80,			/* Miscellaneous Control */
49 	Cr1		= 0x81,
50 	Pmcc		= 0x82,			/* Power Mgmt Capability Control */
51 	Stickhw		= 0x83,			/* Sticky Hardware Control */
52 	Misr		= 0x84,			/* MII Interrupt Control */
53 	Mimr		= 0x85,			/* MII Interrupt Mask */
54 	Wolcrclr	= 0xA4,
55 	Wolcgclr	= 0xA7,
56 	Pwrcsrclr	= 0xAC,
57 };
58 
59 enum {						/* Rcr */
60 	Sep		= 0x01,			/* Accept Error Packets */
61 	Ar		= 0x02,			/* Accept Small Packets */
62 	Am		= 0x04,			/* Accept Multicast */
63 	Ab		= 0x08,			/* Accept Broadcast */
64 	Prom		= 0x10,			/* Accept Physical Address Packets */
65 	RrftMASK	= 0xE0,			/* Receive FIFO Threshold */
66 	RrftSHIFT	= 5,
67 	Rrft64		= 0<<RrftSHIFT,
68 	Rrft32		= 1<<RrftSHIFT,
69 	Rrft128		= 2<<RrftSHIFT,
70 	Rrft256		= 3<<RrftSHIFT,
71 	Rrft512		= 4<<RrftSHIFT,
72 	Rrft768		= 5<<RrftSHIFT,
73 	Rrft1024	= 6<<RrftSHIFT,
74 	RrftSAF		= 7<<RrftSHIFT,
75 };
76 
77 enum {						/* Tcr */
78 	Lb0		= 0x02,			/* Loopback Mode */
79 	Lb1		= 0x04,
80 	Ofset		= 0x08,			/* Select Back-off Priority */
81 	RtsfMASK	= 0xE0,			/* Transmit FIFO Threshold */
82 	RtsfSHIFT	= 5,
83 	Rtsf128		= 0<<RtsfSHIFT,
84 	Rtsf256		= 1<<RtsfSHIFT,
85 	Rtsf512		= 2<<RtsfSHIFT,
86 	Rtsf1024	= 3<<RtsfSHIFT,
87 	RtsfSAF		= 7<<RtsfSHIFT,
88 };
89 
90 enum {						/* Cr */
91 	Init		= 0x0001,		/* INIT Process Begin */
92 	Strt		= 0x0002,		/* Start NIC */
93 	Stop		= 0x0004,		/* Stop NIC */
94 	Rxon		= 0x0008,		/* Turn on Receive Process */
95 	Txon		= 0x0010,		/* Turn on Transmit Process */
96 	Tdmd		= 0x0020,		/* Transmit Poll Demand */
97 	Rdmd		= 0x0040,		/* Receive Poll Demand */
98 	Eren		= 0x0100,		/* Early Receive Enable */
99 	Fdx		= 0x0400,		/* Set MAC to Full Duplex */
100 	Dpoll		= 0x0800,		/* Disable Td/Rd Auto Polling */
101 	Tdmd1		= 0x2000,		/* Transmit Poll Demand 1 */
102 	Rdmd1		= 0x4000,		/* Receive Poll Demand 1 */
103 	Sfrst		= 0x8000,		/* Software Reset */
104 };
105 
106 enum {						/* Isr/Imr */
107 	Prx		= 0x0001,		/* Packet Received OK */
108 	Ptx		= 0x0002,		/* Packet Transmitted OK */
109 	Rxe		= 0x0004,		/* Receive Error */
110 	Txe		= 0x0008,		/* Transmit Error */
111 	Tu		= 0x0010,		/* Transmit Buffer Underflow */
112 	Ru		= 0x0020,		/* Receive Buffer Link Error */
113 	Be		= 0x0040,		/* PCI Bus Error */
114 	Cnt		= 0x0080,		/* Counter Overflow */
115 	Eri		= 0x0100,		/* Early Receive Interrupt */
116 	Udfi		= 0x0200,		/* Tx FIFO Underflow */
117 	Ovfi		= 0x0400,		/* Receive FIFO Overflow */
118 	Pktrace		= 0x0800,		/* Hmmm... */
119 	Norbf		= 0x1000,		/* No Receive Buffers */
120 	Abti		= 0x2000,		/* Transmission Abort */
121 	Srci		= 0x4000,		/* Port State Change */
122 	Geni		= 0x8000,		/* General Purpose Interrupt */
123 };
124 
125 enum {						/* Phyadr */
126 	PhyadMASK	= 0x1F,			/* PHY Address */
127 	PhyadSHIFT	= 0,
128 	Mfdc		= 0x20,			/* Accelerate MDC Speed */
129 	Mpo0		= 0x40,			/* MII Polling Timer Interval */
130 	Mpo1		= 0x80,
131 };
132 
133 enum {						/* Bcr0 */
134 	DmaMASK		= 0x07,			/* DMA Length */
135 	DmaSHIFT	= 0,
136 	Dma32		= 0<<DmaSHIFT,
137 	Dma64		= 1<<DmaSHIFT,
138 	Dma128		= 2<<DmaSHIFT,
139 	Dma256		= 3<<DmaSHIFT,
140 	Dma512		= 4<<DmaSHIFT,
141 	Dma1024		= 5<<DmaSHIFT,
142 	DmaSAF		= 7<<DmaSHIFT,
143 	CrftMASK	= 0x38,			/* Rx FIFO Threshold */
144 	CrftSHIFT	= 3,
145 	Crft64		= 1<<CrftSHIFT,
146 	Crft128		= 2<<CrftSHIFT,
147 	Crft256		= 3<<CrftSHIFT,
148 	Crft512		= 4<<CrftSHIFT,
149 	Crft1024	= 5<<CrftSHIFT,
150 	CrftSAF		= 7<<CrftSHIFT,
151 	Extled		= 0x40,			/* Extra LED Support Control */
152 	Med2		= 0x80,			/* Medium Select Control */
153 };
154 
155 enum {						/* Bcr1 */
156 	PotMASK		= 0x07,			/* Polling Timer Interval */
157 	PotSHIFT	= 0,
158 	CtftMASK	= 0x38,			/* Tx FIFO Threshold */
159 	CtftSHIFT	= 3,
160 	Ctft64		= 1<<CtftSHIFT,
161 	Ctft128		= 2<<CtftSHIFT,
162 	Ctft256		= 3<<CtftSHIFT,
163 	Ctft512		= 4<<CtftSHIFT,
164 	Ctft1024	= 5<<CtftSHIFT,
165 	CtftSAF		= 7<<CtftSHIFT,
166 };
167 
168 enum {						/* Miicr */
169 	Mdc		= 0x01,			/* Clock */
170 	Mdi		= 0x02,			/* Data In */
171 	Mdo		= 0x04,			/* Data Out */
172 	Mout		= 0x08,			/* Output Enable */
173 	Mdpm		= 0x10,			/* Direct Program Mode Enable */
174 	Wcmd		= 0x20,			/* Write Enable */
175 	Rcmd		= 0x40,			/* Read Enable */
176 	Mauto		= 0x80,			/* Auto Polling Enable */
177 };
178 
179 enum {						/* Miiadr */
180 	MadMASK		= 0x1F,			/* MII Port Address */
181 	MadSHIFT	= 0,
182 	Mdone		= 0x20,			/* Accelerate MDC Speed */
183 	Msrcen		= 0x40,			/* MII Polling Timer Interval */
184 	Midle		= 0x80,
185 };
186 
187 enum {						/* Eecsr */
188 	Edo		= 0x01,			/* Data Out */
189 	Edi		= 0x02,			/* Data In */
190 	Eck		= 0x04,			/* Clock */
191 	Ecs		= 0x08,			/* Chip Select */
192 	Dpm		= 0x10,			/* Direct Program Mode Enable */
193 	Autold		= 0x20,			/* Dynamic Reload */
194 	Embp		= 0x40,			/* Embedded Program Enable */
195 	Eepr		= 0x80,			/* Programmed */
196 };
197 
198 /*
199  * Ring descriptor. The space allocated for each
200  * of these will be rounded up to a cache-line boundary.
201  * The first 4 elements are known to the hardware.
202  */
203 typedef struct Ds Ds;
204 typedef struct Ds {
205 	u32int	status;
206 	u32int	control;
207 	u32int	addr;
208 	u32int	branch;
209 
210 	Block*	bp;
211 	Ds*	next;
212 	Ds*	prev;
213 } Ds;
214 
215 enum {						/* Rx Ds status */
216 	Rerr		= 0x00000001,		/* Buff|Rxserr|Fov|Fae|Crc */
217 	Crc		= 0x00000002,		/* CRC Error */
218 	Fae		= 0x00000004,		/* Frame Alignment Error */
219 	Fov		= 0x00000008,		/* FIFO Overflow */
220 	Long		= 0x00000010,		/* A Long Packet */
221 	Runt		= 0x00000020,		/* A Runt Packet */
222 	Rxserr		= 0x00000040,		/* System Error */
223 	Buff		= 0x00000080,		/* Buffer Underflow Error */
224 	Rxedp		= 0x00000100,		/* End of Packet Buffer */
225 	Rxstp		= 0x00000200,		/* Packet Start */
226 	Chn		= 0x00000400,		/* Chain Buffer */
227 	Phy		= 0x00000800,		/* Physical Address Packet */
228 	Bar		= 0x00001000,		/* Broadcast Packet */
229 	Mar		= 0x00002000,		/* Multicast Packet */
230 	Rxok		= 0x00008000,		/* Packet Received OK */
231 	LengthMASK	= 0x07FF0000,		/* Received Packet Length */
232 	LengthSHIFT	= 16,
233 
234 	Own		= 0x80000000,		/* Descriptor Owned by NIC */
235 };
236 
237 enum {						/* Rx Ds control */
238 	RbsizeMASK	= 0x000007FF,		/* Receive Buffer Size */
239 	RbsizeSHIFT	= 0,
240 	Tag		= 0x00010000,		/* Receive a Tagged Packet */
241 	Udpkt		= 0x00020000,		/* Receive a UDP Packet */
242 	Tcpkt		= 0x00040000,		/* Receive a TCP Packet */
243 	Ipkt		= 0x00080000,		/* Receive an IP Packet */
244 	Tuok		= 0x00100000,		/* TCP/UDP Checksum OK */
245 	Ipok		= 0x00200000,		/* IP Checksum OK */
246 	Snaptag		= 0x00400000,		/* Snap Packet + 802.1q Tag */
247 	Rxlerr		= 0x00800000,		/* Receive Length Check Error */
248 	IpktMASK	= 0xff000000,		/* Interesting Packet */
249 	IpktSHIFT	= 24,
250 };
251 
252 enum {						/* Tx Ds status */
253 	NcrMASK		= 0x0000000F,		/* Collision Retry Count */
254 	NcrSHIFT	= 0,
255 	Cols		= 0x00000010,		/* Experienced Collisions */
256 	Cdh		= 0x00000080,		/* CD Heartbeat */
257 	Abt		= 0x00000100,		/* Aborted after Excessive Collisions */
258 	Owc		= 0x00000200,		/* Out of Window Collision */
259 	Crs		= 0x00000400,		/* Carrier Sense Lost */
260 	Udf		= 0x00000800,		/* FIFO Underflow */
261 	Tbuff		= 0x00001000,		/* Invalid Td */
262 	Txserr		= 0x00002000,		/* System Error */
263 	Terr		= 0x00008000,		/* Excessive Collisions */
264 };
265 
266 enum {						/* Tx Ds control */
267 	TbsMASK		= 0x000007FF,		/* Tx Buffer Size */
268 	TbsSHIFT	= 0,
269 	Chain		= 0x00008000,		/* Chain Buffer */
270 	Crcdisable	= 0x00010000,		/* Disable CRC generation */
271 	Stp		= 0x00200000,		/* Start of Packet */
272 	Edp		= 0x00400000,		/* End of Packet */
273 	Ic		= 0x00800000,		/* Interrupt Control */
274 };
275 
276 enum {						/* Tx Ds branch */
277 	Tdctl		= 0x00000001,		/* No Interrupt Generated */
278 };
279 
280 enum {
281 	Nrd		= 196,
282 	Ntd		= 64,
283 	Crcsz		= 4,
284 	Bslop		= 48,
285 	Rdbsz		= ETHERMAXTU+Crcsz+Bslop,
286 	Maxus		= 1000000,  /* Soekris 5501s take a while to reset */
287 
288 	Nrxstats	= 8,
289 	Ntxstats	= 9,
290 };
291 
292 typedef struct Ctlr Ctlr;
293 typedef struct Ctlr {
294 	int	port;
295 	Pcidev*	pcidev;
296 	Ctlr*	next;
297 	int	active;
298 	int	id;
299 	uchar	par[Eaddrlen];
300 
301 	QLock	alock;				/* attach */
302 	void*	alloc;				/* descriptors, etc. */
303 	int	cls;				/* alignment */
304 	int	nrd;
305 	int	ntd;
306 
307 	Ds*	rd;
308 	Ds*	rdh;
309 
310 	Lock	tlock;
311 	Ds*	td;
312 	Ds*	tdh;
313 	Ds*	tdt;
314 	int	tdused;
315 
316 	Lock	clock;				/*  */
317 	int	cr;
318 	int	imr;
319 	int	tft;				/* Tx threshold */
320 
321 	Mii*	mii;
322 	Rendez	lrendez;
323 	int	lwakeup;
324 
325 	uint	rxstats[Nrxstats];		/* statistics */
326 	uint	txstats[Ntxstats];
327 	ulong	totalt;
328 	uint	intr;
329 	uint	lintr;
330 	uint	lsleep;
331 	uint	rintr;
332 	uint	tintr;
333 	uint	txdw;
334 	int	tdumax;
335 
336 	uint	abt;
337 	uint	tbuff;
338 	uint	udf;
339 
340 	uint	abti;
341 	uint	udfi;
342 	uint	tu;
343 
344 	uint	tuok;
345 	uint	ipok;
346 } Ctlr;
347 
348 static Ctlr* vt6105Mctlrhead;
349 static Ctlr* vt6105Mctlrtail;
350 
351 #define csr8r(c, r)	(inb((c)->port+(r)))
352 #define csr16r(c, r)	(ins((c)->port+(r)))
353 #define csr32r(c, r)	(inl((c)->port+(r)))
354 #define csr8w(c, r, b)	(outb((c)->port+(r), (int)(b)))
355 #define csr16w(c, r, w)	(outs((c)->port+(r), (ushort)(w)))
356 #define csr32w(c, r, w)	(outl((c)->port+(r), (ulong)(w)))
357 
358 static Lock vt6105Mrblock;			/* receive Block freelist */
359 static Block* vt6105Mrbpool;
360 static uint vt6105Mrbpoolsz;
361 
362 typedef struct Regs Regs;
363 typedef struct Regs {
364 	char*	name;
365 	int	offset;
366 	int	size;
367 } Regs;
368 
369 static Regs regs[] = {
370 //	"Par0",		Par0,	1,
371 //	"Par1",		Par0+1,	1,
372 //	"Par2",		Par0+2,	1,
373 //	"Par3",		Par0+3,	1,
374 //	"Par4",		Par0+4,	1,
375 //	"Par5",		Par0+5,	1,
376 	"Rcr",		Rcr,	1,
377 	"Tcr",		Tcr,	1,
378 	"Cr0",		Cr,	1,
379 	"Cr1",		Cr+1,	1,
380 	"Isr0",		Isr,	1,
381 	"Isr1",		Isr+1,	1,
382 	"Imr0",		Imr,	1,
383 	"Imr1",		Imr+1,	1,
384 //	"Mcfilt0",	Mcfilt0,4,
385 //	"Mcfilt1",	Mcfilt1,4,
386 //	"Rxdaddr",	Rxdaddr,4,
387 //	"Txdaddr",	Txdaddr,4,
388 	"Phyadr",	Phyadr,	1,
389 	"Miisr",	Miisr,	1,
390 	"Bcr0",		Bcr0,	1,
391 	"Bcr1",		Bcr1,	1,
392 	"Miicr",	Miicr,	1,
393 	"Miiadr",	Miiadr,	1,
394 //	"Miidata",	Miidata,2,
395 	"Eecsr",	Eecsr,	1,
396 	"CfgA",		CfgA,	1,
397 	"CfgB",		CfgB,	1,
398 	"CfgC",		CfgC,	1,
399 	"CfgD",		CfgD,	1,
400 	"Cr0",		Cr0,	1,
401 	"Cr1",		Cr1,	1,
402 	"Pmcc",		Pmcc,	1,
403 	"Stickhw",	Stickhw,1,
404 	"Misr",		Misr,	1,
405 	"Mimr",		Mimr,	1,
406 	nil,
407 };
408 
409 static char* rxstats[Nrxstats] = {
410 	"Receiver Error",
411 	"CRC Error",
412 	"Frame Alignment Error",
413 	"FIFO Overflow",
414 	"Long Packet",
415 	"Runt Packet",
416 	"System Error",
417 	"Buffer Underflow Error",
418 };
419 static char* txstats[Ntxstats] = {
420 	"Aborted after Excessive Collisions",
421 	"Out of Window Collision Seen",
422 	"Carrier Sense Lost",
423 	"FIFO Underflow",
424 	"Invalid Td",
425 	"System Error",
426 	nil,
427 	"Excessive Collisions",
428 };
429 
430 static long
vt6105Mifstat(Ether * edev,void * a,long n,ulong offset)431 vt6105Mifstat(Ether* edev, void* a, long n, ulong offset)
432 {
433 	int i, r;
434 	Ctlr *ctlr;
435 	char *alloc, *e, *p;
436 
437 	ctlr = edev->ctlr;
438 
439 	alloc = malloc(READSTR);
440 	p = alloc;
441 	if(p == nil)
442 		error(Enomem);
443 	e = p + READSTR;
444 	for(i = 0; i < Nrxstats; i++){
445 		p = seprint(p, e, "%s: %ud\n", rxstats[i], ctlr->rxstats[i]);
446 	}
447 	for(i = 0; i < Ntxstats; i++){
448 		if(txstats[i] == nil)
449 			continue;
450 		p = seprint(p, e, "%s: %ud\n", txstats[i], ctlr->txstats[i]);
451 	}
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);
461 
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);
468 
469 	p = seprint(p, e, "tuok: %ud\n", ctlr->tuok);
470 	p = seprint(p, e, "ipok: %ud\n", ctlr->ipok);
471 
472 	p = seprint(p, e, "rbpoolsz: %ud\n", vt6105Mrbpoolsz);
473 	p = seprint(p, e, "totalt: %uld\n", ctlr->totalt);
474 
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));
478 	}
479 
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);
487 		}
488 		seprint(p, e, "\n");
489 	}
490 
491 	n = readstr(offset, a, n, alloc);
492 	free(alloc);
493 
494 	return n;
495 }
496 
497 static void
vt6105Mpromiscuous(void * arg,int on)498 vt6105Mpromiscuous(void* arg, int on)
499 {
500 	int rcr;
501 	Ctlr *ctlr;
502 	Ether *edev;
503 
504 	edev = arg;
505 	ctlr = edev->ctlr;
506 	rcr = csr8r(ctlr, Rcr);
507 	if(on)
508 		rcr |= Prom;
509 	else
510 		rcr &= ~Prom;
511 	csr8w(ctlr, Rcr, rcr);
512 }
513 
514 static void
vt6105Mmulticast(void * arg,uchar * addr,int on)515 vt6105Mmulticast(void* arg, uchar* addr, int on)
516 {
517 	/*
518 	 * For now Am is set in Rcr.
519 	 * Will need to interlock with promiscuous
520 	 * when this gets filled in.
521 	 */
522 	USED(arg, addr, on);
523 }
524 
525 static int
vt6105Mwakeup(void * v)526 vt6105Mwakeup(void* v)
527 {
528 	return *((int*)v) != 0;
529 }
530 
531 static void
vt6105Mimr(Ctlr * ctlr,int imr)532 vt6105Mimr(Ctlr* ctlr, int imr)
533 {
534 	ilock(&ctlr->clock);
535 	ctlr->imr |= imr;
536 	csr16w(ctlr, Imr, ctlr->imr);
537 	iunlock(&ctlr->clock);
538 }
539 
540 static void
vt6105Mlproc(void * arg)541 vt6105Mlproc(void* arg)
542 {
543 	Ctlr *ctlr;
544 	Ether *edev;
545 	MiiPhy *phy;
546 
547 	edev = arg;
548 	ctlr = edev->ctlr;
549 	for(;;){
550 		if(ctlr->mii == nil || ctlr->mii->curphy == nil)
551 			break;
552 		if(miistatus(ctlr->mii) < 0)
553 			goto enable;
554 
555 		phy = ctlr->mii->curphy;
556 		ilock(&ctlr->clock);
557 		csr16w(ctlr, Cr, ctlr->cr & ~(Txon|Rxon));
558 		if(phy->fd)
559 			ctlr->cr |= Fdx;
560 		else
561 			ctlr->cr &= ~Fdx;
562 		csr16w(ctlr, Cr, ctlr->cr);
563 		iunlock(&ctlr->clock);
564 enable:
565 		ctlr->lwakeup = 0;
566 		vt6105Mimr(ctlr, Srci);
567 
568 		ctlr->lsleep++;
569 		sleep(&ctlr->lrendez, vt6105Mwakeup, &ctlr->lwakeup);
570 
571 	}
572 	pexit("vt6105Mlproc: done", 1);
573 }
574 
575 static void
vt6105Mrbfree(Block * bp)576 vt6105Mrbfree(Block* bp)
577 {
578 	bp->rp = bp->lim - (Rdbsz+3);
579 	bp->wp = bp->rp;
580  	bp->flag &= ~(Bipck | Budpck | Btcpck | Bpktck);
581 
582 	ilock(&vt6105Mrblock);
583 	bp->next = vt6105Mrbpool;
584 	vt6105Mrbpool = bp;
585 	iunlock(&vt6105Mrblock);
586 }
587 
588 static Block*
vt6105Mrballoc(void)589 vt6105Mrballoc(void)
590 {
591 	Block *bp;
592 
593 	ilock(&vt6105Mrblock);
594 	if((bp = vt6105Mrbpool) != nil){
595 		vt6105Mrbpool = bp->next;
596 		bp->next = nil;
597 		_xinc(&bp->ref);	/* prevent bp from being freed */
598 	}
599 	iunlock(&vt6105Mrblock);
600 
601 	if(bp == nil && (bp = iallocb(Rdbsz+3)) != nil){
602 		bp->free = vt6105Mrbfree;
603 		vt6105Mrbpoolsz++;
604 	}
605 	return bp;
606 }
607 
608 static void
vt6105Mattach(Ether * edev)609 vt6105Mattach(Ether* edev)
610 {
611 	Ctlr *ctlr;
612 //	MiiPhy *phy;
613 	uchar *alloc;
614 	Ds *ds, *prev;
615 	int dsz, i, timeo;
616 	char name[KNAMELEN];
617 
618 	ctlr = edev->ctlr;
619 	qlock(&ctlr->alock);
620 	if(ctlr->alloc != nil){
621 		qunlock(&ctlr->alock);
622 		return;
623 	}
624 
625 	/*
626 	 * Descriptor space.
627 	 * Receive descriptors should all be aligned on a 4-byte boundary,
628 	 * but try to do cache-line alignment.
629 	 */
630 	ctlr->nrd = Nrd;
631 	ctlr->ntd = Ntd;
632 	dsz = ROUNDUP(sizeof(Ds), ctlr->cls);
633 	alloc = mallocalign((ctlr->nrd+ctlr->ntd)*dsz, dsz, 0, 0);
634 	if(alloc == nil){
635 		qunlock(&ctlr->alock);
636 		error(Enomem);
637 	}
638 	ctlr->alloc = alloc;
639 
640 	ctlr->rd = (Ds*)alloc;
641 
642 	if(waserror()){
643 		ds = ctlr->rd;
644 		for(i = 0; i < ctlr->nrd; i++){
645 			if(ds->bp != nil){
646 				freeb(ds->bp);
647 				ds->bp = nil;
648 			}
649 			if((ds = ds->next) == nil)
650 				break;
651 		}
652 		free(ctlr->alloc);
653 		ctlr->alloc = nil;
654 		qunlock(&ctlr->alock);
655 		nexterror();
656 	}
657 
658 	prev = (Ds*)(alloc + (ctlr->nrd-1)*dsz);
659 	for(i = 0; i < ctlr->nrd; i++){
660 		ds = (Ds*)alloc;
661 		alloc += dsz;
662 
663 		ds->control = Ipkt|Tcpkt|Udpkt|Rdbsz;
664 		ds->branch = PCIWADDR(alloc);
665 
666 		ds->bp = vt6105Mrballoc();
667 		if(ds->bp == nil)
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);
671 
672 		ds->next = (Ds*)alloc;
673 		ds->prev = prev;
674 		prev = ds;
675 
676 		ds->status = Own;
677 	}
678 	prev->branch = 0;
679 	prev->next = ctlr->rd;
680 	prev->status = 0;
681 	ctlr->rdh = ctlr->rd;
682 
683 	ctlr->td = (Ds*)alloc;
684 	prev = (Ds*)(alloc + (ctlr->ntd-1)*dsz);
685 	for(i = 0; i < ctlr->ntd; i++){
686 		ds = (Ds*)alloc;
687 		alloc += dsz;
688 
689 		ds->next = (Ds*)alloc;
690 		ds->prev = prev;
691 		prev = ds;
692 	}
693 	prev->next = ctlr->td;
694 	ctlr->tdh = ctlr->tdt = ctlr->td;
695 	ctlr->tdused = 0;
696 
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;
700 
701 	ilock(&ctlr->clock);
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);
708 
709 	/*
710 	 * Wait for link to be ready.
711 	 */
712 	for(timeo = 0; timeo < 350; timeo++){
713 		if(miistatus(ctlr->mii) == 0)
714 			break;
715 		tsleep(&up->sleep, return0, 0, 10);
716 	}
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);
720 
721 	ilock(&ctlr->clock);
722 	ctlr->cr |= Txon|Rxon;
723 	csr16w(ctlr, Cr, ctlr->cr);
724 	iunlock(&ctlr->clock);
725 
726 	snprint(name, KNAMELEN, "#l%dlproc", edev->ctlrno);
727 	kproc(name, vt6105Mlproc, edev);
728 
729 	qunlock(&ctlr->alock);
730 	poperror();
731 }
732 
733 static void
vt6105Mtransmit(Ether * edev)734 vt6105Mtransmit(Ether* edev)
735 {
736 	Block *bp;
737 	Ctlr *ctlr;
738 	Ds *ds, *next;
739 	int control, i, size, tdused, timeo;
740 	long t;
741 
742 	ctlr = edev->ctlr;
743 
744 	ilock(&ctlr->tlock);
745 	t = lcycles();
746 
747 	/*
748 	 * Free any completed packets
749 	 */
750 	ds = ctlr->tdh;
751 	for(tdused = ctlr->tdused; tdused > 0; tdused--){
752 		/*
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
756 		 * play fair.
757 		 * To do: adjust Tx FIFO threshold on underflow.
758 		 */
759 		if(ds->status & (Abt|Tbuff|Udf)){
760 			if(ds->status & Abt)
761 				ctlr->abt++;
762 			if(ds->status & Tbuff)
763 				ctlr->tbuff++;
764 			if(ds->status & Udf)
765 				ctlr->udf++;
766 			for(timeo = 0; timeo < 1000; timeo++){
767 				if(!(csr16r(ctlr, Cr) & Txon))
768 					break;
769 				microdelay(1);
770 			}
771 			ds->status = Own;
772 			csr32w(ctlr, Txdaddr, PCIWADDR(ds));
773 		}
774 
775 		if(ds->status & Own)
776 			break;
777 		ds->addr = 0;
778 		ds->branch = 0;
779 
780 		if(ds->bp != nil){
781 			freeb(ds->bp);
782 			ds->bp = nil;
783 		}
784 		for(i = 0; i < Ntxstats-1; i++){
785 			if(ds->status & (1<<i))
786 				ctlr->txstats[i]++;
787 		}
788 		ctlr->txstats[i] += (ds->status & NcrMASK)>>NcrSHIFT;
789 
790 		ds = ds->next;
791 	}
792 	ctlr->tdh = ds;
793 
794 	/*
795 	 * Try to fill the ring back up.
796 	 */
797 	ds = ctlr->tdt;
798 	while(tdused < ctlr->ntd-2){
799 		if((bp = qget(edev->oq)) == nil)
800 			break;
801 		tdused++;
802 
803 		size = BLEN(bp);
804 
805 		next = ds->next;
806 		ds->branch = PCIWADDR(ds->next)|Tdctl;
807 
808 		ds->bp = bp;
809 		ds->addr = PCIWADDR(bp->rp);
810 		control = Edp|Stp|((size<<TbsSHIFT) & TbsMASK);
811 
812 		ds->control = control;
813 		if(tdused >= ctlr->ntd-2){
814 			ctlr->txdw++;
815 			ds->branch &= ~Tdctl;
816 		}
817 		coherence();
818 		ds->status = Own;
819 
820 		ds = next;
821 	}
822 	ctlr->tdt = ds;
823 	ctlr->tdused = tdused;
824 	if(ctlr->tdused){
825 		csr16w(ctlr, Cr, Tdmd|ctlr->cr);
826 		if(tdused > ctlr->tdumax)
827 			ctlr->tdumax = tdused;
828 	}
829 
830 	ctlr->totalt += lcycles() - t;
831 	iunlock(&ctlr->tlock);
832 }
833 
834 static void
vt6105Mreceive(Ether * edev)835 vt6105Mreceive(Ether* edev)
836 {
837 	Ds *ds;
838 	Block *bp;
839 	Ctlr *ctlr;
840 	int i, len;
841 
842 	ctlr = edev->ctlr;
843 
844 	ds = ctlr->rdh;
845 	while(!(ds->status & Own) && ds->status != 0){
846 		/*
847 		 * Can Long packets be received OK?
848 		 * What happens to the Rxok bit?
849 		 */
850 		if(ds->status & Rerr){
851 			for(i = 0; i < Nrxstats; i++){
852 				if(ds->status & (1<<i))
853 					ctlr->rxstats[i]++;
854 			}
855 		}
856 		else if(bp = vt6105Mrballoc()){
857 			if(ds->control & Tuok){
858 				ds->bp->flag |= Btcpck|Budpck;
859 				ctlr->tuok++;
860 			}
861 			if(ds->control & Ipok){
862 				ds->bp->flag |= Bipck;
863 				ctlr->ipok++;
864 			}
865 			len = ((ds->status & LengthMASK)>>LengthSHIFT)-4;
866 			ds->bp->wp = ds->bp->rp+len;
867 			etheriq(edev, ds->bp, 1);
868 			bp->rp = (uchar*)ROUNDUP((ulong)bp->rp, 4);
869 			ds->addr = PCIWADDR(bp->rp);
870 			ds->bp = bp;
871 		}
872 		ds->control = Ipkt|Tcpkt|Udpkt|Rdbsz;
873 		ds->branch = 0;
874 		ds->status = 0;
875 
876 		ds->prev->branch = PCIWADDR(ds);
877 		coherence();
878 		ds->prev->status = Own;
879 
880 		ds = ds->next;
881 	}
882 	ctlr->rdh = ds;
883 
884 	csr16w(ctlr, Cr, ctlr->cr);
885 }
886 
887 static void
vt6105Minterrupt(Ureg *,void * arg)888 vt6105Minterrupt(Ureg*, void* arg)
889 {
890 	Ctlr *ctlr;
891 	Ether *edev;
892 	int imr, isr, r, timeo;
893 	long t;
894 
895 	edev = arg;
896 	ctlr = edev->ctlr;
897 
898 	ilock(&ctlr->clock);
899 	t = lcycles();
900 
901 	csr16w(ctlr, Imr, 0);
902 	imr = ctlr->imr;
903 	ctlr->intr++;
904 	for(;;){
905 		if((isr = csr16r(ctlr, Isr)) != 0)
906 			csr16w(ctlr, Isr, isr);
907 		if((isr & ctlr->imr) == 0)
908 			break;
909 
910 		if(isr & Srci){
911 			imr &= ~Srci;
912 			ctlr->lwakeup = isr & Srci;
913 			wakeup(&ctlr->lrendez);
914 			isr &= ~Srci;
915 			ctlr->lintr++;
916 		}
917 		if(isr & (Norbf|Pktrace|Ovfi|Ru|Rxe|Prx)){
918 			vt6105Mreceive(edev);
919 			isr &= ~(Norbf|Pktrace|Ovfi|Ru|Rxe|Prx);
920 			ctlr->rintr++;
921 		}
922 		if(isr & (Abti|Udfi|Tu|Txe|Ptx)){
923 			if(isr & (Abti|Udfi|Tu)){
924 				if(isr & Abti)
925 					ctlr->abti++;
926 				if(isr & Udfi)
927 					ctlr->udfi++;
928 				if(isr & Tu)
929 					ctlr->tu++;
930 				for(timeo = 0; timeo < 1000; timeo++){
931 					if(!(csr16r(ctlr, Cr) & Txon))
932 						break;
933 					microdelay(1);
934 				}
935 
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);
940 				}
941 			}
942 
943 
944 			ctlr->totalt += lcycles() - t;
945 			vt6105Mtransmit(edev);
946 			t = lcycles();
947 			isr &= ~(Abti|Udfi|Tu|Txe|Ptx);
948 			ctlr->tintr++;
949 		}
950 		if(isr)
951 			panic("vt6105M: isr %4.4uX\n", isr);
952 	}
953 	ctlr->imr = imr;
954 	csr16w(ctlr, Imr, ctlr->imr);
955 
956 	ctlr->totalt += lcycles() - t;
957 	iunlock(&ctlr->clock);
958 }
959 
960 static int
vt6105Mmiimicmd(Mii * mii,int pa,int ra,int cmd,int data)961 vt6105Mmiimicmd(Mii* mii, int pa, int ra, int cmd, int data)
962 {
963 	Ctlr *ctlr;
964 	int r, timeo;
965 
966 	ctlr = mii->ctlr;
967 
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);
973 	if(cmd == Wcmd)
974 		csr16w(ctlr, Miidata, data);
975 	csr8w(ctlr, Miicr, cmd);
976 
977 	for(timeo = 0; timeo < Maxus; timeo++){
978 		if(!(csr8r(ctlr, Miicr) & cmd))
979 			break;
980 		microdelay(1);
981 	}
982 	if(timeo >= Maxus)
983 		return -1;
984 
985 	if(cmd == Wcmd)
986 		return 0;
987 	return csr16r(ctlr, Miidata);
988 }
989 
990 static int
vt6105Mmiimir(Mii * mii,int pa,int ra)991 vt6105Mmiimir(Mii* mii, int pa, int ra)
992 {
993 	return vt6105Mmiimicmd(mii, pa, ra, Rcmd, 0);
994 }
995 
996 static int
vt6105Mmiimiw(Mii * mii,int pa,int ra,int data)997 vt6105Mmiimiw(Mii* mii, int pa, int ra, int data)
998 {
999 	return vt6105Mmiimicmd(mii, pa, ra, Wcmd, data);
1000 }
1001 
1002 static int
vt6105Mdetach(Ctlr * ctlr)1003 vt6105Mdetach(Ctlr* ctlr)
1004 {
1005 	int revid, timeo;
1006 
1007 	/*
1008 	 * Reset power management registers.
1009 	 */
1010 	revid = pcicfgr8(ctlr->pcidev, PciRID);
1011 	if(revid >= 0x40){
1012 		/* Set power state D0. */
1013 		csr8w(ctlr, Stickhw, csr8r(ctlr, Stickhw) & 0xFC);
1014 
1015 		/* Disable force PME-enable. */
1016 		csr8w(ctlr, Wolcgclr, 0x80);
1017 
1018 		/* Clear WOL config and status bits. */
1019 		csr8w(ctlr, Wolcrclr, 0xFF);
1020 		csr8w(ctlr, Pwrcsrclr, 0xFF);
1021 	}
1022 
1023 	/*
1024 	 * Soft reset the controller.
1025 	 */
1026 	csr16w(ctlr, Cr, Stop);
1027 	csr16w(ctlr, Cr, Stop|Sfrst);
1028 	for(timeo = 0; timeo < Maxus; timeo++){
1029 		if(!(csr16r(ctlr, Cr) & Sfrst))
1030 			break;
1031 		microdelay(1);
1032 	}
1033 	if(timeo >= Maxus)
1034 		return -1;
1035 
1036 	return 0;
1037 }
1038 
1039 static void
vt6105Mshutdown(Ether * ether)1040 vt6105Mshutdown(Ether *ether)
1041 {
1042 	Ctlr *ctlr = ether->ctlr;
1043 
1044 	vt6105Mdetach(ctlr);
1045 }
1046 
1047 static int
vt6105Mreset(Ctlr * ctlr)1048 vt6105Mreset(Ctlr* ctlr)
1049 {
1050 	MiiPhy *phy;
1051 	int i, r, timeo;
1052 
1053 	if(vt6105Mdetach(ctlr) < 0)
1054 		return -1;
1055 
1056 	/*
1057 	 * Load the MAC address into the PAR[01]
1058 	 * registers.
1059 	 */
1060 	r = csr8r(ctlr, Eecsr);
1061 	csr8w(ctlr, Eecsr, Autold|r);
1062 	for(timeo = 0; timeo < Maxus; timeo++){
1063 		if(!(csr8r(ctlr, Cr) & Autold))
1064 			break;
1065 		microdelay(1);
1066 	}
1067 	if(timeo >= Maxus)
1068 		return -1;
1069 
1070 	for(i = 0; i < Eaddrlen; i++)
1071 		ctlr->par[i] = csr8r(ctlr, Par0+i);
1072 
1073 	/*
1074 	 * Configure DMA and Rx/Tx thresholds.
1075 	 * If the Rx/Tx threshold bits in Bcr[01] are 0 then
1076 	 * the thresholds are determined by Rcr/Tcr.
1077 	 */
1078 	r = csr8r(ctlr, Bcr0) & ~(CrftMASK|DmaMASK);
1079 	csr8w(ctlr, Bcr0, r|Crft128|DmaSAF);
1080 	r = csr8r(ctlr, Bcr1) & ~CtftMASK;
1081 	csr8w(ctlr, Bcr1, r|ctlr->tft);
1082 
1083 	r = csr8r(ctlr, Rcr) & ~(RrftMASK|Prom|Ar|Sep);
1084 	csr8w(ctlr, Rcr, r|Ab|Am);
1085 	csr32w(ctlr, Mcfilt0, ~0UL);	/* accept all multicast */
1086 	csr32w(ctlr, Mcfilt1, ~0UL);
1087 
1088 	r = csr8r(ctlr, Tcr) & ~(RtsfMASK|Ofset|Lb1|Lb0);
1089 	csr8w(ctlr, Tcr, r);
1090 
1091 	/*
1092 	 * Link management.
1093 	 */
1094 	if((ctlr->mii = malloc(sizeof(Mii))) == nil)
1095 		return -1;
1096 	ctlr->mii->mir = vt6105Mmiimir;
1097 	ctlr->mii->miw = vt6105Mmiimiw;
1098 	ctlr->mii->ctlr = ctlr;
1099 
1100 	if(mii(ctlr->mii, ~0) == 0 || (phy = ctlr->mii->curphy) == nil){
1101 		free(ctlr->mii);
1102 		ctlr->mii = nil;
1103 		return -1;
1104 	}
1105 //	print("oui %X phyno %d\n", phy->oui, phy->phyno);
1106 	USED(phy);
1107 
1108 	if(miistatus(ctlr->mii) < 0){
1109 //		miireset(ctlr->mii);
1110 		miiane(ctlr->mii, ~0, ~0, ~0);
1111 	}
1112 
1113 	return 0;
1114 }
1115 
1116 static void
vt6105Mpci(void)1117 vt6105Mpci(void)
1118 {
1119 	Pcidev *p;
1120 	Ctlr *ctlr;
1121 	int cls, port;
1122 
1123 	p = nil;
1124 	while(p = pcimatch(p, 0, 0)){
1125 		if(p->ccrb != Pcibcnet || p->ccru != Pciscether)
1126 			continue;
1127 
1128 		switch((p->did<<16)|p->vid){
1129 		default:
1130 			continue;
1131 		case (0x3053<<16)|0x1106:	/* Rhine III-M vt6105M */
1132 			break;
1133 		}
1134 
1135 		port = p->mem[0].bar & ~0x01;
1136 		if(ioalloc(port, p->mem[0].size, 0, "vt6105M") < 0){
1137 			print("vt6105M: port 0x%uX in use\n", port);
1138 			continue;
1139 		}
1140 		ctlr = malloc(sizeof(Ctlr));
1141 		if(ctlr == nil) {
1142 			iofree(port);
1143 			error(Enomem);
1144 		}
1145 		ctlr->port = port;
1146 		ctlr->pcidev = p;
1147 		ctlr->id = (p->did<<16)|p->vid;
1148 		if((cls = pcicfgr8(p, PciCLS)) == 0 || cls == 0xFF)
1149 			cls = 0x10;
1150 		ctlr->cls = cls*4;
1151 		if(ctlr->cls < sizeof(Ds)){
1152 			print("vt6105M: cls %d < sizeof(Ds)\n", ctlr->cls);
1153 			iofree(port);
1154 			free(ctlr);
1155 			continue;
1156 		}
1157 		ctlr->tft = CtftSAF;
1158 
1159 		if(vt6105Mreset(ctlr)){
1160 			iofree(port);
1161 			free(ctlr);
1162 			continue;
1163 		}
1164 		pcisetbme(p);
1165 
1166 		if(vt6105Mctlrhead != nil)
1167 			vt6105Mctlrtail->next = ctlr;
1168 		else
1169 			vt6105Mctlrhead = ctlr;
1170 		vt6105Mctlrtail = ctlr;
1171 	}
1172 }
1173 
1174 static int
vt6105Mpnp(Ether * edev)1175 vt6105Mpnp(Ether* edev)
1176 {
1177 	Ctlr *ctlr;
1178 
1179 	if(vt6105Mctlrhead == nil)
1180 		vt6105Mpci();
1181 
1182 	/*
1183 	 * Any adapter matches if no edev->port is supplied,
1184 	 * otherwise the ports must match.
1185 	 */
1186 	for(ctlr = vt6105Mctlrhead; ctlr != nil; ctlr = ctlr->next){
1187 		if(ctlr->active)
1188 			continue;
1189 		if(edev->port == 0 || edev->port == ctlr->port){
1190 			ctlr->active = 1;
1191 			break;
1192 		}
1193 	}
1194 	if(ctlr == nil)
1195 		return -1;
1196 
1197 	edev->ctlr = ctlr;
1198 	edev->port = ctlr->port;
1199 	edev->irq = ctlr->pcidev->intl;
1200 	edev->tbdf = ctlr->pcidev->tbdf;
1201 	/*
1202 	 * Set to 1000Mb/s to fool the bsz calculation.  We need
1203 	 * something better, though.
1204 	 */
1205 	edev->mbps = 1000;
1206 	memmove(edev->ea, ctlr->par, Eaddrlen);
1207 
1208 	/*
1209 	 * Linkage to the generic ethernet driver.
1210 	 */
1211 	edev->attach = vt6105Mattach;
1212 	edev->transmit = vt6105Mtransmit;
1213 	edev->interrupt = vt6105Minterrupt;
1214 	edev->ifstat = vt6105Mifstat;
1215 	edev->shutdown = vt6105Mshutdown;
1216 	edev->ctl = nil;
1217 
1218 	edev->arg = edev;
1219 	edev->promiscuous = vt6105Mpromiscuous;
1220 	edev->multicast = vt6105Mmulticast;
1221 
1222 	edev->maxmtu = ETHERMAXTU+Bslop;
1223 
1224 	return 0;
1225 }
1226 
1227 void
ethervt6105mlink(void)1228 ethervt6105mlink(void)
1229 {
1230 	addethercard("vt6105M", vt6105Mpnp);
1231 }
1232