xref: /inferno-os/os/boot/pc/etherelnk3x.c (revision 8a8c2d742b51525f66c2210e3c8a251de10022ff)
1 /*
2  * Etherlink III and Fast EtherLink adapters.
3  * To do:
4  *	autoSelect;
5  *	busmaster channel;
6  *	PCMCIA;
7  *	PCI latency timer and master enable;
8  *	errata list.
9  *
10  * Product ID:
11  *	9150 ISA	3C509[B]
12  *	9050 ISA	3C509[B]-TP
13  *	9450 ISA	3C509[B]-COMBO
14  *	9550 ISA	3C509[B]-TPO
15  *
16  *	9350 EISA	3C579
17  *	9250 EISA	3C579-TP
18  *
19  *	5920 EISA	3C592-[TP|COMBO|TPO]
20  *	5970 EISA	3C597-TX	Fast Etherlink 10BASE-T/100BASE-TX
21  *	5971 EISA	3C597-T4	Fast Etherlink 10BASE-T/100BASE-T4
22  *	5972 EISA	3C597-MII	Fast Etherlink 10BASE-T/MII
23  *
24  *	5900 PCI	3C590-[TP|COMBO|TPO]
25  *	5950 PCI	3C595-TX	Fast Etherlink Shared 10BASE-T/100BASE-TX
26  *	5951 PCI	3C595-T4	Fast Etherlink Shared 10BASE-T/100BASE-T4
27  *	5952 PCI	3C595-MII	Fast Etherlink 10BASE-T/MII
28  *
29  *	9058 PCMCIA	3C589[B]-[TP|COMBO]
30  *
31  *	627C MCA	3C529
32  *	627D MCA	3C529-TP
33  */
34 #include "u.h"
35 #include "lib.h"
36 #include "mem.h"
37 #include "dat.h"
38 #include "fns.h"
39 #include "io.h"
40 
41 #include "etherif.h"
42 
43 enum {
44 	IDport			= 0x0110,	/* anywhere between 0x0100 and 0x01F0 */
45 };
46 
47 enum {						/* all windows */
48 	Command			= 0x000E,
49 	IntStatus		= 0x000E,
50 };
51 
52 enum {						/* Commands */
53 	GlobalReset		= 0x0000,
54 	SelectRegisterWindow	= 0x0001,
55 	EnableDcConverter	= 0x0002,
56 	RxDisable		= 0x0003,
57 	RxEnable		= 0x0004,
58 	RxReset			= 0x0005,
59 	TxDone			= 0x0007,
60 	RxDiscard		= 0x0008,
61 	TxEnable		= 0x0009,
62 	TxDisable		= 0x000A,
63 	TxReset			= 0x000B,
64 	RequestInterrupt	= 0x000C,
65 	AcknowledgeInterrupt	= 0x000D,
66 	SetInterruptEnable	= 0x000E,
67 	SetIndicationEnable	= 0x000F,	/* SetReadZeroMask */
68 	SetRxFilter		= 0x0010,
69 	SetRxEarlyThresh	= 0x0011,
70 	SetTxAvailableThresh	= 0x0012,
71 	SetTxStartThresh	= 0x0013,
72 	StartDma		= 0x0014,	/* initiate busmaster operation */
73 	StatisticsEnable	= 0x0015,
74 	StatisticsDisable	= 0x0016,
75 	DisableDcConverter	= 0x0017,
76 	SetTxReclaimThresh	= 0x0018,	/* PIO-only adapters */
77 	PowerUp			= 0x001B,	/* not all adapters */
78 	PowerDownFull		= 0x001C,	/* not all adapters */
79 	PowerAuto		= 0x001D,	/* not all adapters */
80 };
81 
82 enum {						/* (Global|Rx|Tx)Reset command bits */
83 	tpAuiReset		= 0x0001,	/* 10BaseT and AUI transceivers */
84 	endecReset		= 0x0002,	/* internal Ethernet encoder/decoder */
85 	networkReset		= 0x0004,	/* network interface logic */
86 	fifoReset		= 0x0008,	/* FIFO control logic */
87 	aismReset		= 0x0010,	/* autoinitialise state-machine logic */
88 	hostReset		= 0x0020,	/* bus interface logic */
89 	dmaReset		= 0x0040,	/* bus master logic */
90 	vcoReset		= 0x0080,	/* on-board 10Mbps VCO */
91 
92 	resetMask		= 0x00FF,
93 };
94 
95 enum {						/* SetRxFilter command bits */
96 	receiveIndividual	= 0x0001,	/* match station address */
97 	receiveMulticast	= 0x0002,
98 	receiveBroadcast	= 0x0004,
99 	receiveAllFrames	= 0x0008,	/* promiscuous */
100 };
101 
102 enum {						/* StartDma command bits */
103 	Upload			= 0x0000,	/* transfer data from adapter to memory */
104 	Download		= 0x0001,	/* transfer data from memory to adapter */
105 };
106 
107 enum {						/* IntStatus bits */
108 	interruptLatch		= 0x0001,
109 	hostError		= 0x0002,	/* Adapter Failure */
110 	txComplete		= 0x0004,
111 	txAvailable		= 0x0008,
112 	rxComplete		= 0x0010,
113 	rxEarly			= 0x0020,
114 	intRequested		= 0x0040,
115 	updateStats		= 0x0080,
116 	transferInt		= 0x0100,	/* Bus Master Transfer Complete */
117 	busMasterInProgress	= 0x0800,
118 	commandInProgress	= 0x1000,
119 
120 	interruptMask		= 0x01FE,
121 };
122 
123 #define COMMAND(port, cmd, a)	outs((port)+Command, ((cmd)<<11)|(a))
124 #define STATUS(port)		ins((port)+IntStatus)
125 
126 enum {						/* Window 0 - setup */
127 	Wsetup			= 0x0000,
128 						/* registers */
129 	ManufacturerID		= 0x0000,	/* 3C5[08]*, 3C59[27] */
130 	ProductID		= 0x0002,	/* 3C5[08]*, 3C59[27] */
131 	ConfigControl		= 0x0004,	/* 3C5[08]*, 3C59[27] */
132 	AddressConfig		= 0x0006,	/* 3C5[08]*, 3C59[27] */
133 	ResourceConfig		= 0x0008,	/* 3C5[08]*, 3C59[27] */
134 	EepromCommand		= 0x000A,
135 	EepromData		= 0x000C,
136 						/* AddressConfig Bits */
137 	autoSelect9		= 0x0080,
138 	xcvrMask9		= 0xC000,
139 						/* ConfigControl bits */
140 	Ena			= 0x0001,
141 						/* EepromCommand bits */
142 	EepromReadRegister	= 0x0080,
143 	EepromBusy		= 0x8000,
144 };
145 
146 #define EEPROMCMD(port, cmd, a)	outs((port)+EepromCommand, (cmd)|(a))
147 #define EEPROMBUSY(port)	(ins((port)+EepromCommand) & EepromBusy)
148 #define EEPROMDATA(port)	ins((port)+EepromData)
149 
150 enum {						/* Window 1 - operating set */
151 	Wop			= 0x0001,
152 						/* registers */
153 	Fifo			= 0x0000,
154 	RxError			= 0x0004,	/* 3C59[0257] only */
155 	RxStatus		= 0x0008,
156 	Timer			= 0x000A,
157 	TxStatus		= 0x000B,
158 	TxFree			= 0x000C,
159 						/* RxError bits */
160 	rxOverrun		= 0x0001,
161 	runtFrame		= 0x0002,
162 	alignmentError		= 0x0004,	/* Framing */
163 	crcError		= 0x0008,
164 	oversizedFrame		= 0x0010,
165 	dribbleBits		= 0x0080,
166 						/* RxStatus bits */
167 	rxBytes			= 0x1FFF,	/* 3C59[0257] mask */
168 	rxBytes9		= 0x07FF,	/* 3C5[078]9 mask */
169 	rxError9		= 0x3800,	/* 3C5[078]9 error mask */
170 	rxOverrun9		= 0x0000,
171 	oversizedFrame9		= 0x0800,
172 	dribbleBits9		= 0x1000,
173 	runtFrame9		= 0x1800,
174 	alignmentError9		= 0x2000,	/* Framing */
175 	crcError9		= 0x2800,
176 	rxError			= 0x4000,
177 	rxIncomplete		= 0x8000,
178 						/* TxStatus Bits */
179 	txStatusOverflow	= 0x0004,
180 	maxCollisions		= 0x0008,
181 	txUnderrun		= 0x0010,
182 	txJabber		= 0x0020,
183 	interruptRequested	= 0x0040,
184 	txStatusComplete	= 0x0080,
185 };
186 
187 enum {						/* Window 2 - station address */
188 	Wstation		= 0x0002,
189 };
190 
191 enum {						/* Window 3 - FIFO management */
192 	Wfifo			= 0x0003,
193 						/* registers */
194 	InternalConfig		= 0x0000,	/* 3C509B, 3C589, 3C59[0257] */
195 	OtherInt		= 0x0004,	/* 3C59[0257] */
196 	RomControl		= 0x0006,	/* 3C509B, 3C59[27] */
197 	MacControl		= 0x0006,	/* 3C59[0257] */
198 	ResetOptions		= 0x0008,	/* 3C59[0257] */
199 	RxFree			= 0x000A,
200 						/* InternalConfig bits */
201 	disableBadSsdDetect	= 0x00000100,
202 	ramLocation		= 0x00000200,	/* 0 external, 1 internal */
203 	ramPartition5to3	= 0x00000000,
204 	ramPartition3to1	= 0x00010000,
205 	ramPartition1to1	= 0x00020000,
206 	ramPartition3to5	= 0x00030000,
207 	ramPartitionMask	= 0x00030000,
208 	xcvr10BaseT		= 0x00000000,
209 	xcvrAui			= 0x00100000,	/* 10BASE5 */
210 	xcvr10Base2		= 0x00300000,
211 	xcvr100BaseTX		= 0x00400000,
212 	xcvr100BaseFX		= 0x00500000,
213 	xcvrMii			= 0x00600000,
214 	xcvrMask		= 0x00700000,
215 	autoSelect		= 0x01000000,
216 						/* MacControl bits */
217 	deferExtendEnable	= 0x0001,
218 	deferTimerSelect	= 0x001E,	/* mask */
219 	fullDuplexEnable	= 0x0020,
220 	allowLargePackets	= 0x0040,
221 						/* ResetOptions bits */
222 	baseT4Available		= 0x0001,
223 	baseTXAvailable		= 0x0002,
224 	baseFXAvailable		= 0x0004,
225 	base10TAvailable	= 0x0008,
226 	coaxAvailable		= 0x0010,
227 	auiAvailable		= 0x0020,
228 	miiConnector		= 0x0040,
229 };
230 
231 enum {						/* Window 4 - diagnostic */
232 	Wdiagnostic		= 0x0004,
233 						/* registers */
234 	VcoDiagnostic		= 0x0002,
235 	FifoDiagnostic		= 0x0004,
236 	NetworkDiagnostic	= 0x0006,
237 	PhysicalMgmt		= 0x0008,
238 	MediaStatus		= 0x000A,
239 	BadSSD			= 0x000C,
240 						/* FifoDiagnostic bits */
241 	txOverrun		= 0x0400,
242 	rxUnderrun		= 0x2000,
243 	receiving		= 0x8000,
244 						/* MediaStatus bits */
245 	dataRate100		= 0x0002,
246 	crcStripDisable		= 0x0004,
247 	enableSqeStats		= 0x0008,
248 	collisionDetect		= 0x0010,
249 	carrierSense		= 0x0020,
250 	jabberGuardEnable	= 0x0040,
251 	linkBeatEnable		= 0x0080,
252 	jabberDetect		= 0x0200,
253 	polarityReversed	= 0x0400,
254 	linkBeatDetect		= 0x0800,
255 	txInProg		= 0x1000,
256 	dcConverterEnabled	= 0x4000,
257 	auiDisable		= 0x8000,
258 };
259 
260 enum {						/* Window 5 - internal state */
261 	Wstate			= 0x0005,
262 						/* registers */
263 	TxStartThresh		= 0x0000,
264 	TxAvalableThresh	= 0x0002,
265 	RxEarlyThresh		= 0x0006,
266 	RxFilter		= 0x0008,
267 	InterruptEnable		= 0x000A,
268 	IndicationEnable	= 0x000C,
269 };
270 
271 enum {						/* Window 6 - statistics */
272 	Wstatistics		= 0x0006,
273 						/* registers */
274 	CarrierLost		= 0x0000,
275 	SqeErrors		= 0x0001,
276 	MultipleColls		= 0x0002,
277 	SingleCollFrames	= 0x0003,
278 	LateCollisions		= 0x0004,
279 	RxOverruns		= 0x0005,
280 	FramesXmittedOk		= 0x0006,
281 	FramesRcvdOk		= 0x0007,
282 	FramesDeferred		= 0x0008,
283 	UpperFramesOk		= 0x0009,
284 	BytesRcvdOk		= 0x000A,
285 	BytesXmittedOk		= 0x000C,
286 };
287 
288 enum {						/* Window 7 - bus master operations */
289 	Wmaster			= 0x0007,
290 						/* registers */
291 	MasterAddress		= 0x0000,
292 	MasterLen		= 0x0006,
293 	MasterStatus		= 0x000C,
294 						/* MasterStatus bits */
295 	masterAbort		= 0x0001,
296 	targetAbort		= 0x0002,
297 	targetRetry		= 0x0004,
298 	targetDisc		= 0x0008,
299 	masterDownload		= 0x1000,
300 	masterUpload		= 0x4000,
301 	masterInProgress	= 0x8000,
302 
303 	masterMask		= 0xD00F,
304 };
305 
306 typedef struct {
307 	int	txthreshold;
308 } Ctlr;
309 
310 static void
attach(Ether * ether)311 attach(Ether* ether)
312 {
313 	int port, x;
314 
315 	port = ether->port;
316 
317 	/*
318 	 * Set the receiver packet filter for this and broadcast addresses,
319 	 * set the interrupt masks for all interrupts, enable the receiver
320 	 * and transmitter.
321 	 */
322 	x = receiveBroadcast|receiveIndividual;
323 	COMMAND(port, SetRxFilter, x);
324 
325 	x = interruptMask|interruptLatch;
326 	COMMAND(port, SetIndicationEnable, x);
327 	COMMAND(port, SetInterruptEnable, x);
328 
329 	COMMAND(port, RxEnable, 0);
330 	COMMAND(port, TxEnable, 0);
331 }
332 
333 static void
transmit(Ether * ether)334 transmit(Ether* ether)
335 {
336 	int port, len;
337 	RingBuf *tb;
338 
339 	/*
340 	 * Attempt to top-up the transmit FIFO. If there's room simply
341 	 * stuff in the packet length (unpadded to a dword boundary), the
342 	 * packet data (padded) and remove the packet from the queue.
343 	 * If there's no room post an interrupt for when there is.
344 	 * This routine is called both from the top level and from interrupt
345 	 * level.
346 	 */
347 	port = ether->port;
348 	for(tb = &ether->tb[ether->ti]; tb->owner == Interface; tb = &ether->tb[ether->ti]){
349 		len = ROUNDUP(tb->len, 4);
350 		if(len+4 <= ins(port+TxFree)){
351 			outl(port+Fifo, tb->len);
352 			outsl(port+Fifo, tb->pkt, len/4);
353 			tb->owner = Host;
354 			ether->ti = NEXT(ether->ti, ether->ntb);
355 		}
356 		else{
357 			COMMAND(port, SetTxAvailableThresh, len);
358 			break;
359 		}
360 	}
361 }
362 
363 static void
receive(Ether * ether)364 receive(Ether* ether)
365 {
366 	int len, port, rxstatus;
367 	RingBuf *rb;
368 
369 	port = ether->port;
370 
371 	while(((rxstatus = ins(port+RxStatus)) & rxIncomplete) == 0){
372 		/*
373 		 * If there was an error, throw it away and continue.
374 		 * The 3C5[078]9 has the error info in the status register
375 		 * and the 3C59[0257] implement a separate RxError register.
376 		 */
377 		if((rxstatus & rxError) == 0){
378 			/*
379 			 * Packet received. Read it into the next free
380 			 * ring buffer, if any. Must read len bytes padded
381 			 * to a doubleword, can be picked out 32-bits at
382 			 * a time. The CRC is already stripped off.
383 			 */
384 			rb = &ether->rb[ether->ri];
385 			if(rb->owner == Interface){
386 				len = (rxstatus & rxBytes9);
387 				rb->len = len;
388 				insl(port+Fifo, rb->pkt, HOWMANY(len, 4));
389 
390 				rb->owner = Host;
391 				ether->ri = NEXT(ether->ri, ether->nrb);
392 			}
393 		}
394 
395 		/*
396 		 * All done, discard the packet.
397 		 */
398 		COMMAND(port, RxDiscard, 0);
399 		while(STATUS(port) & commandInProgress)
400 			;
401 	}
402 }
403 
404 static void
statistics(Ether * ether)405 statistics(Ether* ether)
406 {
407 	int i, port, w;
408 
409 	port = ether->port;
410 	w = (STATUS(port)>>13) & 0x07;
411 	COMMAND(port, SelectRegisterWindow, Wop);
412 	COMMAND(port, SelectRegisterWindow, Wstatistics);
413 
414 	for(i = 0; i < 0x0A; i++)
415 		inb(port+i);
416 	ins(port+BytesRcvdOk);
417 	ins(port+BytesXmittedOk);
418 
419 	COMMAND(port, SelectRegisterWindow, w);
420 }
421 
422 static void
interrupt(Ureg *,void * arg)423 interrupt(Ureg*, void* arg)
424 {
425 	Ether *ether;
426 	int port, status, txstatus, w, x;
427 	Ctlr *ctlr;
428 
429 	ether = arg;
430 	port = ether->port;
431 	ctlr = ether->ctlr;
432 
433 	w = (STATUS(port)>>13) & 0x07;
434 	COMMAND(port, SelectRegisterWindow, Wop);
435 
436 	for(;;){
437 		/*
438 		 * Clear the interrupt latch.
439 		 * It's possible to receive a packet and for another
440 		 * to become complete before exiting the interrupt
441 		 * handler so this must be done first to ensure another
442 		 * interrupt will occur.
443 		 */
444 		COMMAND(port, AcknowledgeInterrupt, interruptLatch);
445 		status = STATUS(port);
446 		if((status & interruptMask) == 0)
447 			break;
448 
449 		if(status & hostError){
450 			/*
451 			 * Adapter failure, try to find out why, reset if
452 			 * necessary. What happens if Tx is active and a reset
453 			 * occurs, need to retransmit? This probably isn't right.
454 			 */
455 			COMMAND(port, SelectRegisterWindow, Wdiagnostic);
456 			x = ins(port+FifoDiagnostic);
457 			COMMAND(port, SelectRegisterWindow, Wop);
458 			print("elnk3#%d: status 0x%uX, diag 0x%uX\n",
459 			    ether->ctlrno, status, x);
460 
461 			if(x & txOverrun){
462 				COMMAND(port, TxReset, 0);
463 				COMMAND(port, TxEnable, 0);
464 			}
465 
466 			if(x & rxUnderrun){
467 				/*
468 				 * This shouldn't happen...
469 				 * Need to restart any busmastering?
470 				 */
471 				COMMAND(port, RxReset, 0);
472 				while(STATUS(port) & commandInProgress)
473 					;
474 				COMMAND(port, RxEnable, 0);
475 			}
476 
477 			status &= ~hostError;
478 		}
479 
480 		if(status & (transferInt|rxComplete)){
481 			receive(ether);
482 			status &= ~(transferInt|rxComplete);
483 		}
484 
485 		if(status & txComplete){
486 			/*
487 			 * Pop the TxStatus stack, accumulating errors.
488 			 * Adjust the TX start threshold if there was an underrun.
489 			 * If there was a Jabber or Underrun error, reset
490 			 * the transmitter.
491 			 * For all conditions enable the transmitter.
492 			 */
493 			txstatus = 0;
494 			do{
495 				if(x = inb(port+TxStatus))
496 					outb(port+TxStatus, 0);
497 				txstatus |= x;
498 			}while(STATUS(port) & txComplete);
499 
500 			if(txstatus & txUnderrun){
501 				COMMAND(port, SelectRegisterWindow, Wdiagnostic);
502 				while(ins(port+MediaStatus) & txInProg)
503 					;
504 				COMMAND(port, SelectRegisterWindow, Wop);
505 				if(ctlr->txthreshold < ETHERMAXTU)
506 					ctlr->txthreshold += ETHERMINTU;
507 			}
508 
509 			if(txstatus & (txJabber|txUnderrun)){
510 				COMMAND(port, TxReset, 0);
511 				while(STATUS(port) & commandInProgress)
512 					;
513 				COMMAND(port, SetTxStartThresh, ctlr->txthreshold);
514 			}
515 			COMMAND(port, TxEnable, 0);
516 			status &= ~txComplete;
517 			status |= txAvailable;
518 		}
519 
520 		if(status & txAvailable){
521 			COMMAND(port, AcknowledgeInterrupt, txAvailable);
522 			transmit(ether);
523 			status &= ~txAvailable;
524 		}
525 
526 		if(status & updateStats){
527 			statistics(ether);
528 			status &= ~updateStats;
529 		}
530 
531 		/*
532 		 * Panic if there are any interrupts not dealt with.
533 		 */
534 		if(status & interruptMask)
535 			panic("elnk3#%d: interrupt mask 0x%uX\n", ether->ctlrno, status);
536 	}
537 
538 	COMMAND(port, SelectRegisterWindow, w);
539 }
540 
541 typedef struct Adapter {
542 	int	port;
543 	int	irq;
544 	int	tbdf;
545 } Adapter;
546 static Block* adapter;
547 
548 static void
tcmadapter(int port,int irq,int tbdf)549 tcmadapter(int port, int irq, int tbdf)
550 {
551 	Block *bp;
552 	Adapter *ap;
553 
554 	bp = allocb(sizeof(Adapter));
555 	ap = (Adapter*)bp->rp;
556 	ap->port = port;
557 	ap->irq = irq;
558 	ap->tbdf = tbdf;
559 
560 	bp->next = adapter;
561 	adapter = bp;
562 }
563 
564 /*
565  * Write two 0 bytes to identify the IDport and then reset the
566  * ID sequence. Then send the ID sequence to the card to get
567  * the card into command state.
568  */
569 static void
idseq(void)570 idseq(void)
571 {
572 	int i;
573 	uchar al;
574 	static int reset, untag;
575 
576 	/*
577 	 * One time only:
578 	 *	reset any adapters listening
579 	 */
580 	if(reset == 0){
581 		outb(IDport, 0);
582 		outb(IDport, 0);
583 		outb(IDport, 0xC0);
584 		delay(20);
585 		reset = 1;
586 	}
587 
588 	outb(IDport, 0);
589 	outb(IDport, 0);
590 	for(al = 0xFF, i = 0; i < 255; i++){
591 		outb(IDport, al);
592 		if(al & 0x80){
593 			al <<= 1;
594 			al ^= 0xCF;
595 		}
596 		else
597 			al <<= 1;
598 	}
599 
600 	/*
601 	 * One time only:
602 	 *	write ID sequence to get the attention of all adapters;
603 	 *	untag all adapters.
604 	 * If we do a global reset here on all adapters we'll confuse any
605 	 * ISA cards configured for EISA mode.
606 	 */
607 	if(untag == 0){
608 		outb(IDport, 0xD0);
609 		untag = 1;
610 	}
611 }
612 
613 static ulong
activate(void)614 activate(void)
615 {
616 	int i;
617 	ushort x, acr;
618 
619 	/*
620 	 * Do the little configuration dance:
621 	 *
622 	 * 2. write the ID sequence to get to command state.
623 	 */
624 	idseq();
625 
626 	/*
627 	 * 3. Read the Manufacturer ID from the EEPROM.
628 	 *    This is done by writing the IDPort with 0x87 (0x80
629 	 *    is the 'read EEPROM' command, 0x07 is the offset of
630 	 *    the Manufacturer ID field in the EEPROM).
631 	 *    The data comes back 1 bit at a time.
632 	 *    We seem to need a delay here between reading the bits.
633 	 *
634 	 * If the ID doesn't match, there are no more adapters.
635 	 */
636 	outb(IDport, 0x87);
637 	delay(20);
638 	for(x = 0, i = 0; i < 16; i++){
639 		delay(20);
640 		x <<= 1;
641 		x |= inb(IDport) & 0x01;
642 	}
643 	if(x != 0x6D50)
644 		return 0;
645 
646 	/*
647 	 * 3. Read the Address Configuration from the EEPROM.
648 	 *    The Address Configuration field is at offset 0x08 in the EEPROM).
649 	 */
650 	outb(IDport, 0x88);
651 	for(acr = 0, i = 0; i < 16; i++){
652 		delay(20);
653 		acr <<= 1;
654 		acr |= inb(IDport) & 0x01;
655 	}
656 
657 	return (acr & 0x1F)*0x10 + 0x200;
658 }
659 
660 #ifdef notjustpcmcia
661 static void
tcm509isa(void)662 tcm509isa(void)
663 {
664 	int irq, port;
665 
666 	/*
667 	 * Attempt to activate all adapters. If adapter is set for
668 	 * EISA mode (0x3F0), tag it and ignore. Otherwise, activate
669 	 * it fully.
670 	 */
671 	while(port = activate()){
672 		/*
673 		 * 6. Tag the adapter so it won't respond in future.
674 		 */
675 		outb(IDport, 0xD1);
676 		if(port == 0x3F0)
677 			continue;
678 
679 		/*
680 		 * 6. Activate the adapter by writing the Activate command
681 		 *    (0xFF).
682 		 */
683 		outb(IDport, 0xFF);
684 		delay(20);
685 
686 		/*
687 		 * 8. Can now talk to the adapter's I/O base addresses.
688 		 *    Use the I/O base address from the acr just read.
689 		 *
690 		 *    Enable the adapter and clear out any lingering status
691 		 *    and interrupts.
692 		 */
693 		while(STATUS(port) & commandInProgress)
694 			;
695 		COMMAND(port, SelectRegisterWindow, Wsetup);
696 		outs(port+ConfigControl, Ena);
697 
698 		COMMAND(port, TxReset, 0);
699 		COMMAND(port, RxReset, 0);
700 		COMMAND(port, AcknowledgeInterrupt, 0xFF);
701 
702 		irq = (ins(port+ResourceConfig)>>12) & 0x0F;
703 		tcmadapter(port, irq, BUSUNKNOWN);
704 	}
705 }
706 
707 static void
tcm5XXeisa(void)708 tcm5XXeisa(void)
709 {
710 	ushort x;
711 	int irq, port, slot;
712 
713 	/*
714 	 * Check if this is an EISA machine.
715 	 * If not, nothing to do.
716 	 */
717 	if(strncmp((char*)(KZERO|0xFFFD9), "EISA", 4))
718 		return;
719 
720 	/*
721 	 * Continue through the EISA slots looking for a match on both
722 	 * 3COM as the manufacturer and 3C579-* or 3C59[27]-* as the product.
723 	 * If an adapter is found, select window 0, enable it and clear
724 	 * out any lingering status and interrupts.
725 	 */
726 	for(slot = 1; slot < MaxEISA; slot++){
727 		port = slot*0x1000;
728 		if(ins(port+0xC80+ManufacturerID) != 0x6D50)
729 			continue;
730 		x = ins(port+0xC80+ProductID);
731 		if((x & 0xF0FF) != 0x9050 && (x & 0xFF00) != 0x5900)
732 			continue;
733 
734 		COMMAND(port, SelectRegisterWindow, Wsetup);
735 		outs(port+ConfigControl, Ena);
736 
737 		COMMAND(port, TxReset, 0);
738 		COMMAND(port, RxReset, 0);
739 		COMMAND(port, AcknowledgeInterrupt, 0xFF);
740 
741 		irq = (ins(port+ResourceConfig)>>12) & 0x0F;
742 		tcmadapter(port, irq, BUSUNKNOWN);
743 	}
744 }
745 
746 static void
tcm59Xpci(void)747 tcm59Xpci(void)
748 {
749 	Pcidev *p;
750 	int irq, port;
751 
752 	p = nil;
753 	while(p = pcimatch(p, 0x10B7, 0)){
754 		port = p->mem[0].bar & ~0x01;
755 		irq = p->intl;
756 		COMMAND(port, GlobalReset, 0);
757 		while(STATUS(port) & commandInProgress)
758 			;
759 
760 		tcmadapter(port, irq, p->tbdf);
761 	}
762 }
763 #endif /* notjustpcmcia */
764 
765 static char* tcmpcmcia[] = {
766 	"3C589",			/* 3COM 589[ABCD] */
767 	"3C562",			/* 3COM 562 */
768 	"589E",				/* 3COM Megahertz 589E */
769 	nil,
770 };
771 
772 static int
tcm5XXpcmcia(Ether * ether)773 tcm5XXpcmcia(Ether* ether)
774 {
775 	int i;
776 
777 	for(i = 0; tcmpcmcia[i] != nil; i++){
778 		if(!cistrcmp(ether->type, tcmpcmcia[i]))
779 			return ether->port;
780 	}
781 
782 	return 0;
783 }
784 
785 static int
autoselect(int port,int rxstatus9)786 autoselect(int port, int rxstatus9)
787 {
788 	int media, x;
789 
790 	/*
791 	 * Pathetic attempt at automatic media selection.
792 	 * Really just to get the Fast Etherlink 10BASE-T/100BASE-TX
793 	 * cards operational.
794 	 */
795 	media = auiAvailable|coaxAvailable|base10TAvailable;
796 	if(rxstatus9 == 0){
797 		COMMAND(port, SelectRegisterWindow, Wfifo);
798 		media = ins(port+ResetOptions);
799 	}
800 
801 	if(media & miiConnector)
802 		return xcvrMii;
803 
804 	if(media & baseTXAvailable){
805 		/*
806 		 * Must have InternalConfig register.
807 		 */
808 		COMMAND(port, SelectRegisterWindow, Wfifo);
809 		x = inl(port+InternalConfig) & ~xcvrMask;
810 		x |= xcvr100BaseTX;
811 		outl(port+InternalConfig, x);
812 		COMMAND(port, TxReset, 0);
813 		while(STATUS(port) & commandInProgress)
814 			;
815 		COMMAND(port, RxReset, 0);
816 		while(STATUS(port) & commandInProgress)
817 			;
818 
819 		COMMAND(port, SelectRegisterWindow, Wdiagnostic);
820 		x = ins(port+MediaStatus) & ~(dcConverterEnabled|jabberGuardEnable);
821 		outs(port+MediaStatus, linkBeatEnable|x);
822 		delay(10);
823 
824 { int i, v;
825   for(i = 0; i < 10000; i++){
826 	v = ins(port+MediaStatus);
827 	if(v & linkBeatDetect){
828 		print("count %d v %uX\n", i, v);
829 		return xcvr100BaseTX;
830 	}
831 	delay(1);
832   }
833 print("count %d v %uX\n", i, ins(port+MediaStatus));
834 }
835 		if(ins(port+MediaStatus) & linkBeatDetect)
836 			return xcvr100BaseTX;
837 		outs(port+MediaStatus, x);
838 	}
839 
840 	if(media & base10TAvailable){
841 		if(rxstatus9 == 0){
842 			COMMAND(port, SelectRegisterWindow, Wfifo);
843 			x = inl(port+InternalConfig) & ~xcvrMask;
844 			x |= xcvr10BaseT;
845 			outl(port+InternalConfig, x);
846 		}
847 		else{
848 			COMMAND(port, SelectRegisterWindow, Wsetup);
849 			x = ins(port+AddressConfig) & ~xcvrMask9;
850 			x |= (xcvr10BaseT>>20)<<14;
851 			outs(port+AddressConfig, x);
852 		}
853 		COMMAND(port, TxReset, 0);
854 		while(STATUS(port) & commandInProgress)
855 			;
856 		COMMAND(port, RxReset, 0);
857 		while(STATUS(port) & commandInProgress)
858 			;
859 
860 		COMMAND(port, SelectRegisterWindow, Wdiagnostic);
861 		x = ins(port+MediaStatus) & ~dcConverterEnabled;
862 		outs(port+MediaStatus, linkBeatEnable|jabberGuardEnable|x);
863 		delay(10);
864 
865 		if(ins(port+MediaStatus) & linkBeatDetect)
866 			return xcvr10BaseT;
867 		outs(port+MediaStatus, x);
868 	}
869 
870 	/*
871 	 * Botch.
872 	 */
873 	return autoSelect;
874 }
875 
876 static int
eepromdata(int port,int offset)877 eepromdata(int port, int offset)
878 {
879 	COMMAND(port, SelectRegisterWindow, Wsetup);
880 	while(EEPROMBUSY(port))
881 		;
882 	EEPROMCMD(port, EepromReadRegister, offset);
883 	while(EEPROMBUSY(port))
884 		;
885 	return EEPROMDATA(port);
886 }
887 
888 int
elnk3reset(Ether * ether)889 elnk3reset(Ether* ether)
890 {
891 	int did, i, port, rxstatus9, x, xcvr;
892 	Block *bp, **bpp;
893 	Adapter *ap;
894 	uchar ea[Eaddrlen];
895 	Ctlr *ctlr;
896 #ifdef notjustpcmcia
897 	static int scandone;
898 
899 	/*
900 	 * Scan for adapter on PCI, EISA and finally
901 	 * using the little ISA configuration dance.
902 	 */
903 	if(scandone == 0){
904 		tcm59Xpci();
905 		tcm5XXeisa();
906 		tcm509isa();
907 		scandone = 1;
908 	}
909 #endif /* notjustpcmcia */
910 
911 	/*
912 	 * Any adapter matches if no ether->port is supplied,
913 	 * otherwise the ports must match.
914 	 */
915 	port = 0;
916 	bpp = &adapter;
917 	for(bp = *bpp; bp; bp = bp->next){
918 		ap = (Adapter*)bp->rp;
919 		if(ether->port == 0 || ether->port == ap->port){
920 			port = ap->port;
921 			ether->irq = ap->irq;
922 			ether->tbdf = ap->tbdf;
923 			*bpp = bp->next;
924 			freeb(bp);
925 			break;
926 		}
927 		bpp = &bp->next;
928 	}
929 	if(port == 0 && (port = tcm5XXpcmcia(ether)) == 0)
930 		return -1;
931 
932 	/*
933 	 * Read the DeviceID from the EEPROM, it's at offset 0x03,
934 	 * and do something depending on capabilities.
935 	 */
936 	switch(did = eepromdata(port, 0x03)){
937 
938 	case 0x9000:
939 	case 0x9001:
940 	case 0x9050:
941 	case 0x9051:
942 		if(BUSTYPE(ether->tbdf) != BusPCI)
943 			goto buggery;
944 		goto vortex;
945 
946 	case 0x5900:
947 	case 0x5920:
948 	case 0x5950:
949 	case 0x5951:
950 	case 0x5952:
951 	case 0x5970:
952 	case 0x5971:
953 	case 0x5972:
954 	vortex:
955 		COMMAND(port, SelectRegisterWindow, Wfifo);
956 		xcvr = inl(port+InternalConfig) & (autoSelect|xcvrMask);
957 		rxstatus9 = 0;
958 		break;
959 
960 	buggery:
961 	default:
962 		COMMAND(port, SelectRegisterWindow, Wsetup);
963 		x = ins(port+AddressConfig);
964 		xcvr = ((x & xcvrMask9)>>14)<<20;
965 		if(x & autoSelect9)
966 			xcvr |= autoSelect;
967 		rxstatus9 = 1;
968 		break;
969 	}
970 	USED(did);
971 
972 	/*
973 	 * Check if the adapter's station address is to be overridden.
974 	 * If not, read it from the EEPROM and set in ether->ea prior to loading the
975 	 * station address in Wstation. The EEPROM returns 16-bits at a time.
976 	 */
977 	memset(ea, 0, Eaddrlen);
978 	if(memcmp(ea, ether->ea, Eaddrlen) == 0){
979 		for(i = 0; i < Eaddrlen/2; i++){
980 			x = eepromdata(port, i);
981 			ether->ea[2*i] = x>>8;
982 			ether->ea[2*i+1] = x;
983 		}
984 	}
985 
986 	COMMAND(port, SelectRegisterWindow, Wstation);
987 	for(i = 0; i < Eaddrlen; i++)
988 		outb(port+i, ether->ea[i]);
989 
990 	/*
991 	 * Enable the transceiver if necessary.
992 	 */
993 	if(xcvr & autoSelect)
994 		xcvr = autoselect(port, rxstatus9);
995 	switch(xcvr){
996 
997 	case xcvrMii:
998 		break;
999 
1000 	case xcvr100BaseTX:
1001 	case xcvr100BaseFX:
1002 		COMMAND(port, SelectRegisterWindow, Wfifo);
1003 		x = inl(port+InternalConfig) & ~ramPartitionMask;
1004 		outl(port+InternalConfig, x|ramPartition1to1);
1005 
1006 		COMMAND(port, SelectRegisterWindow, Wdiagnostic);
1007 		x = ins(port+MediaStatus) & ~(dcConverterEnabled|jabberGuardEnable);
1008 		x |= linkBeatEnable;
1009 		outs(port+MediaStatus, x);
1010 		break;
1011 
1012 	case xcvr10BaseT:
1013 		/*
1014 		 * Enable Link Beat and Jabber to start the
1015 		 * transceiver.
1016 		 */
1017 		COMMAND(port, SelectRegisterWindow, Wdiagnostic);
1018 		x = ins(port+MediaStatus) & ~dcConverterEnabled;
1019 		x |= linkBeatEnable|jabberGuardEnable;
1020 		outs(port+MediaStatus, x);
1021 		break;
1022 
1023 	case xcvr10Base2:
1024 		COMMAND(port, SelectRegisterWindow, Wdiagnostic);
1025 		x = ins(port+MediaStatus) & ~(linkBeatEnable|jabberGuardEnable);
1026 		outs(port+MediaStatus, x);
1027 
1028 		/*
1029 		 * Start the DC-DC converter.
1030 		 * Wait > 800 microseconds.
1031 		 */
1032 		COMMAND(port, EnableDcConverter, 0);
1033 		delay(1);
1034 		break;
1035 	}
1036 
1037 	/*
1038 	 * Wop is the normal operating register set.
1039 	 * The 3C59[0257] adapters allow access to more than one register window
1040 	 * at a time, but there are situations where switching still needs to be
1041 	 * done, so just do it.
1042 	 * Clear out any lingering Tx status.
1043 	 */
1044 	COMMAND(port, SelectRegisterWindow, Wop);
1045 	while(inb(port+TxStatus))
1046 		outb(port+TxStatus, 0);
1047 
1048 	/*
1049 	 * Allocate a controller structure and start
1050 	 * to initialise it.
1051 	 */
1052 	ether->ctlr = malloc(sizeof(Ctlr));
1053 	ctlr = ether->ctlr;
1054 	memset(ctlr, 0, sizeof(Ctlr));
1055 
1056 	/*
1057 	 * Set a base TxStartThresh which will be incremented
1058 	 * if any txUnderrun errors occur and ensure no RxEarly
1059 	 * interrupts happen.
1060 	 */
1061 	ctlr->txthreshold = ETHERMINTU;
1062 	COMMAND(port, SetTxStartThresh, ETHERMINTU);
1063 	COMMAND(port, SetRxEarlyThresh, ETHERMAXTU);
1064 
1065 	/*
1066 	 * Set up the software configuration.
1067 	 */
1068 	ether->port = port;
1069 	ether->attach = attach;
1070 	ether->transmit = transmit;
1071 	ether->interrupt = interrupt;
1072 
1073 	return 0;
1074 }
1075