xref: /inferno-os/os/boot/pc/ether589.c (revision a60fa48ce2f27a689f276bea9538b5db2b74ff86)
1 /*
2  * 3C589 and 3C562.
3  * To do:
4  *	check xcvr10Base2 still works (is GlobalReset necessary?).
5  */
6 #include "u.h"
7 #include "lib.h"
8 #include "mem.h"
9 #include "dat.h"
10 #include "fns.h"
11 #include "io.h"
12 #include "error.h"
13 
14 #include "etherif.h"
15 
16 enum {						/* all windows */
17 	CommandR		= 0x000E,
18 	IntStatusR		= 0x000E,
19 };
20 
21 enum {						/* Commands */
22 	GlobalReset		= 0x0000,
23 	SelectRegisterWindow	= 0x0001,
24 	RxReset			= 0x0005,
25 	TxReset			= 0x000B,
26 	AcknowledgeInterrupt	= 0x000D,
27 };
28 
29 enum {						/* IntStatus bits */
30 	commandInProgress	= 0x1000,
31 };
32 
33 #define COMMAND(port, cmd, a)	outs((port)+CommandR, ((cmd)<<11)|(a))
34 #define STATUS(port)		ins((port)+IntStatusR)
35 
36 enum {						/* Window 0 - setup */
37 	Wsetup			= 0x0000,
38 						/* registers */
39 	ManufacturerID		= 0x0000,	/* 3C5[08]*, 3C59[27] */
40 	ProductID		= 0x0002,	/* 3C5[08]*, 3C59[27] */
41 	ConfigControl		= 0x0004,	/* 3C5[08]*, 3C59[27] */
42 	AddressConfig		= 0x0006,	/* 3C5[08]*, 3C59[27] */
43 	ResourceConfig		= 0x0008,	/* 3C5[08]*, 3C59[27] */
44 	EepromCommand		= 0x000A,
45 	EepromData		= 0x000C,
46 						/* AddressConfig Bits */
47 	autoSelect9		= 0x0080,
48 	xcvrMask9		= 0xC000,
49 						/* ConfigControl bits */
50 	Ena			= 0x0001,
51 	base10TAvailable9	= 0x0200,
52 	coaxAvailable9		= 0x1000,
53 	auiAvailable9		= 0x2000,
54 						/* EepromCommand bits */
55 	EepromReadRegister	= 0x0080,
56 	EepromBusy		= 0x8000,
57 };
58 
59 enum {						/* Window 1 - operating set */
60 	Wop			= 0x0001,
61 };
62 
63 enum {						/* Window 3 - FIFO management */
64 	Wfifo			= 0x0003,
65 						/* registers */
66 	InternalConfig		= 0x0000,	/* 3C509B, 3C589, 3C59[0257] */
67 						/* InternalConfig bits */
68 	xcvr10BaseT		= 0x00000000,
69 	xcvr10Base2		= 0x00300000,
70 };
71 
72 enum {						/* Window 4 - diagnostic */
73 	Wdiagnostic		= 0x0004,
74 						/* registers */
75 	MediaStatus		= 0x000A,
76 						/* MediaStatus bits */
77 	linkBeatDetect		= 0x0800,
78 };
79 
80 extern int elnk3reset(Ether*);
81 
82 static char *tcmpcmcia[] = {
83 	"3C589",			/* 3COM 589[ABCD] */
84 	"3C562",			/* 3COM 562 */
85 	"589E",				/* 3COM Megahertz 589E */
86 	nil,
87 };
88 
89 static int
90 configASIC(Ether* ether, int port, int xcvr)
91 {
92 	int x;
93 
94 	/* set Window 0 configuration registers */
95 	COMMAND(port, SelectRegisterWindow, Wsetup);
96 	outs(port+ConfigControl, Ena);
97 
98 	/* IRQ must be 3 on 3C589/3C562 */
99 	outs(port + ResourceConfig, 0x3F00);
100 
101 	x = ins(port+AddressConfig) & ~xcvrMask9;
102 	x |= (xcvr>>20)<<14;
103 	outs(port+AddressConfig, x);
104 
105 	COMMAND(port, TxReset, 0);
106 	while(STATUS(port) & commandInProgress)
107 		;
108 	COMMAND(port, RxReset, 0);
109 	while(STATUS(port) & commandInProgress)
110 		;
111 
112 	return elnk3reset(ether);
113 }
114 
115 int
116 ether589reset(Ether* ether)
117 {
118 	int i, t, slot;
119 	char *type;
120 	int port;
121 	enum { WantAny, Want10BT, Want10B2 };
122 	int want;
123 	uchar ea[6];
124 	char *p;
125 
126 	if(ether->irq == 0)
127 		ether->irq = 10;
128 	if(ether->port == 0)
129 		ether->port = 0x240;
130 	port = ether->port;
131 
132 //	if(ioalloc(port, 0x10, 0, "3C589") < 0)
133 //		return -1;
134 
135 	type = nil;
136 	slot = -1;
137 	for(i = 0; tcmpcmcia[i] != nil; i++){
138 		type = tcmpcmcia[i];
139 if(debug) print("try %s...", type);
140 		if((slot = pcmspecial(type, ether)) >= 0)
141 			break;
142 	}
143 	if(slot < 0){
144 if(debug) print("none found\n");
145 //		iofree(port);
146 		return -1;
147 	}
148 
149 	/*
150 	 * Read Ethernet address from card memory
151 	 * on 3C562, but only if the user has not
152 	 * overridden it.
153 	 */
154 	memset(ea, 0, sizeof ea);
155 	if(memcmp(ea, ether->ea, 6) == 0 && strcmp(type, "3C562") == 0) {
156 		if(debug)
157 			print("read 562...");
158 		if(pcmcistuple(slot, 0x88, -1, ea, 6) == 6) {
159 			for(i = 0; i < 6; i += 2){
160 				t = ea[i];
161 				ea[i] = ea[i+1];
162 				ea[i+1] = t;
163 			}
164 			memmove(ether->ea, ea, 6);
165 			if(debug)
166 				print("ea %E", ea);
167 		}
168 	}
169 	/*
170 	 * Allow user to specify desired media in plan9.ini
171 	 */
172 	want = WantAny;
173 	for(i = 0; i < ether->nopt; i++){
174 		if(cistrncmp(ether->opt[i], "media=", 6) != 0)
175 			continue;
176 		p = ether->opt[i]+6;
177 		if(cistrcmp(p, "10base2") == 0)
178 			want = Want10B2;
179 		else if(cistrcmp(p, "10baseT") == 0)
180 			want = Want10BT;
181 	}
182 
183 	/* try configuring as a 10BaseT */
184 	if(want==WantAny || want==Want10BT){
185 		if(configASIC(ether, port, xcvr10BaseT) < 0){
186 			pcmspecialclose(slot);
187 //			iofree(port);
188 			return -1;
189 		}
190 		delay(100);
191 		COMMAND(port, SelectRegisterWindow, Wdiagnostic);
192 		if((ins(port+MediaStatus)&linkBeatDetect) || want==Want10BT){
193 			COMMAND(port, SelectRegisterWindow, Wop);
194 			print("#l%d: xcvr10BaseT %s\n", ether->ctlrno, type);
195 			return 0;
196 		}
197 	}
198 
199 	/* try configuring as a 10base2 */
200 	if(want==WantAny || want==Want10B2){
201 		COMMAND(port, GlobalReset, 0);
202 		if(configASIC(ether, port, xcvr10Base2) < 0){
203 			pcmspecialclose(slot);
204 //			iofree(port);
205 			return -1;
206 		}
207 		print("#l%d: xcvr10Base2 %s\n", ether->ctlrno, type);
208 		return 0;
209 	}
210 	return -1;		/* not reached */
211 }
212