xref: /minix3/sys/arch/i386/stand/lib/netif/3c90xb.c (revision 58a2b0008e28f606a7f7f5faaeaba4faac57a1ea)
1 /* $NetBSD: 3c90xb.c,v 1.14 2008/12/14 18:46:33 christos Exp $ */
2 
3 /*
4  * Copyright (c) 1999
5  * 	Matthias Drochner.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions, and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <sys/types.h>
30 #include <machine/pio.h>
31 
32 struct mbuf; /* XXX */
33 typedef int bus_dmamap_t; /* XXX */
34 #include <dev/ic/elink3reg.h>
35 #include <dev/ic/elinkxlreg.h>
36 
37 #include <lib/libsa/stand.h>
38 
39 #include <libi386.h>
40 #include <pcivar.h>
41 
42 #if defined(_STANDALONE) && !defined(SUPPORT_NO_NETBSD)
43 #include <lib/libkern/libkern.h>
44 #include <bootinfo.h>
45 #endif
46 
47 #include "etherdrv.h"
48 
49 #define RECVBUF_SIZE 1600 /* struct ex_upd + packet */
50 
51 #ifdef _STANDALONE
52 
53 static pcihdl_t mytag;
54 static char recvbuf[RECVBUF_SIZE];
55 #define RECVBUF_PHYS vtophys(recvbuf)
56 #define RECVBUF_VIRT ((void *)recvbuf)
57 static struct ex_dpd sndbuf;
58 #define SNDBUF_PHYS vtophys(&sndbuf)
59 #define SNDBUF_VIRT ((void *)&sndbuf)
60 
61 #else /* !standalone, userspace testing environment */
62 
63 #define	PCI_MODE1_ENABLE	0x80000000UL
64 #define PCIBUSNO 1
65 #define PCIDEVNO 4
66 static pcihdl_t mytag = PCI_MODE1_ENABLE | (PCIBUSNO << 16) | (PCIDEVNO << 11);
67 
68 extern void *mapmem(int, int);
69 void *dmamem; /* virtual */
70 #define DMABASE 0x3ffd800
71 #define DMASIZE 10240
72 #define RECVBUF_PHYS DMABASE
73 #define RECVBUF_VIRT dmamem
74 #define SNDBUF_PHYS (DMABASE + RECVBUF_SIZE)
75 #define SNDBUF_VIRT ((void *)(((char *)dmamem) + RECVBUF_SIZE))
76 
77 #endif /* _STANDALONE */
78 
79 
80 #define CSR_READ_1(reg) inb(iobase + (reg))
81 #define CSR_READ_2(reg) inw(iobase + (reg))
82 #define CSR_READ_4(reg) inl(iobase + (reg))
83 #define CSR_WRITE_1(reg, val) outb(iobase + (reg), val)
84 #define CSR_WRITE_2(reg, val) outw(iobase + (reg), val)
85 #define CSR_WRITE_4(reg, val) outl(iobase + (reg), val)
86 
87 #undef GO_WINDOW
88 #define GO_WINDOW(x) CSR_WRITE_2(ELINK_COMMAND, WINDOW_SELECT | x)
89 
90 static int iobase;
91 static u_char myethaddr[6];
92 unsigned ether_medium;
93 
94 static struct {
95 	int did;
96 	int mii;
97 } excards[] = {
98 	{0x9005, 0}, /* 3c900b Combo */
99 	{0x9055, 1}, /* 3c905b TP */
100 	{0x9058, 0}, /* 3c905b Combo */
101 	{-1}
102 }, *excard;
103 
104 static struct mtabentry {
105 	int address_cfg; /* configured connector */
106 	int config_bit; /* connector present */
107 	char *name;
108 } mediatab[] = { /* indexed by media type - etherdrv.h */
109 	{ELINKMEDIA_10BASE_2, ELINK_PCI_BNC, "BNC"},
110 	{ELINKMEDIA_10BASE_T, ELINK_PCI_10BASE_T, "UTP"},
111 	{ELINKMEDIA_AUI, ELINK_PCI_AUI, "AUI"},
112 	{ELINKMEDIA_MII, ELINK_PCI_100BASE_MII, "MII"},
113 	{ELINKMEDIA_100BASE_TX, ELINK_PCI_100BASE_TX, "100TX"},
114 };
115 
116 #if defined(_STANDALONE) && !defined(SUPPORT_NO_NETBSD)
117 static struct btinfo_netif bi_netif;
118 #endif
119 
120 #define ex_waitcmd() \
121 	do { \
122 		while (CSR_READ_2(ELINK_STATUS) & COMMAND_IN_PROGRESS) \
123 			continue; \
124 	} while (0)
125 
126 void ex_reset(void);
127 uint16_t ex_read_eeprom(int);
128 static int ex_eeprom_busy(void);
129 void ex_init(void);
130 void ex_set_media(void);
131 
132 void
ex_reset(void)133 ex_reset(void)
134 {
135 	CSR_WRITE_2(ELINK_COMMAND, GLOBAL_RESET);
136 	delay(100000);
137 	ex_waitcmd();
138 }
139 
140 /*
141  * Read EEPROM data.
142  * XXX what to do if EEPROM doesn't unbusy?
143  */
144 uint16_t
ex_read_eeprom(int offset)145 ex_read_eeprom(int offset)
146 {
147 	uint16_t data = 0;
148 
149 	GO_WINDOW(0);
150 	if (ex_eeprom_busy())
151 		goto out;
152 	CSR_WRITE_1(ELINK_W0_EEPROM_COMMAND, READ_EEPROM | (offset & 0x3f));
153 	if (ex_eeprom_busy())
154 		goto out;
155 	data = CSR_READ_2(ELINK_W0_EEPROM_DATA);
156 out:
157 	return data;
158 }
159 
160 static int
ex_eeprom_busy(void)161 ex_eeprom_busy(void)
162 {
163 	int i = 100;
164 
165 	while (i--) {
166 		if (!(CSR_READ_2(ELINK_W0_EEPROM_COMMAND) & EEPROM_BUSY))
167 			return 0;
168 		delay(100);
169 	}
170 	printf("\nex: eeprom stays busy.\n");
171 	return 1;
172 }
173 
174 /*
175  * Bring device up.
176  */
177 void
ex_init(void)178 ex_init(void)
179 {
180 	int i;
181 
182 	ex_waitcmd();
183 	EtherStop();
184 
185 	/*
186 	 * Set the station address and clear the station mask. The latter
187 	 * is needed for 90x cards, 0 is the default for 90xB cards.
188 	 */
189 	GO_WINDOW(2);
190 	for (i = 0; i < 6; i++) {
191 		CSR_WRITE_1(ELINK_W2_ADDR_0 + i,
192 		    myethaddr[i]);
193 		CSR_WRITE_1(ELINK_W2_RECVMASK_0 + i, 0);
194 	}
195 
196 	GO_WINDOW(3);
197 
198 	CSR_WRITE_2(ELINK_COMMAND, RX_RESET);
199 	ex_waitcmd();
200 	CSR_WRITE_2(ELINK_COMMAND, TX_RESET);
201 	ex_waitcmd();
202 
203 	CSR_WRITE_2(ELINK_COMMAND, SET_INTR_MASK | 0); /* disable */
204 	CSR_WRITE_2(ELINK_COMMAND, ACK_INTR | 0xff);
205 
206 	ex_set_media();
207 
208 	CSR_WRITE_2(ELINK_COMMAND, SET_RX_FILTER | FIL_INDIVIDUAL | FIL_BRDCST);
209 
210 	CSR_WRITE_4(ELINK_DNLISTPTR, 0);
211 	CSR_WRITE_2(ELINK_COMMAND, TX_ENABLE);
212 
213 	CSR_WRITE_4(ELINK_UPLISTPTR, RECVBUF_PHYS);
214 	CSR_WRITE_2(ELINK_COMMAND, RX_ENABLE);
215 	CSR_WRITE_2(ELINK_COMMAND, ELINK_UPUNSTALL);
216 
217 	GO_WINDOW(1);
218 }
219 
220 void
ex_set_media(void)221 ex_set_media(void)
222 {
223 	int config0, config1;
224 
225 	CSR_WRITE_2(ELINK_W3_MAC_CONTROL, 0);
226 
227 	if (ether_medium == ETHERMEDIUM_MII)
228 		goto setcfg;
229 
230 	GO_WINDOW(4);
231 	CSR_WRITE_2(ELINK_W4_MEDIA_TYPE, 0);
232 	CSR_WRITE_2(ELINK_COMMAND, STOP_TRANSCEIVER);
233 	delay(800);
234 
235 	switch (ether_medium) {
236 	case ETHERMEDIUM_UTP:
237 		CSR_WRITE_2(ELINK_W4_MEDIA_TYPE,
238 			    JABBER_GUARD_ENABLE | LINKBEAT_ENABLE);
239 		break;
240 	case ETHERMEDIUM_BNC:
241 		CSR_WRITE_2(ELINK_COMMAND, START_TRANSCEIVER);
242 		delay(800);
243 		break;
244 	case ETHERMEDIUM_AUI:
245 		CSR_WRITE_2(ELINK_W4_MEDIA_TYPE, SQE_ENABLE);
246 		delay(800);
247 		break;
248 	case ETHERMEDIUM_100TX:
249 		CSR_WRITE_2(ELINK_W4_MEDIA_TYPE, LINKBEAT_ENABLE);
250 		break;
251 	}
252 
253 setcfg:
254 	GO_WINDOW(3);
255 
256 	config0 = CSR_READ_2(ELINK_W3_INTERNAL_CONFIG);
257 	config1 = CSR_READ_2(ELINK_W3_INTERNAL_CONFIG + 2);
258 
259 	config1 = config1 & ~CONFIG_MEDIAMASK;
260 	config1 |= (mediatab[ether_medium].address_cfg
261 		    << CONFIG_MEDIAMASK_SHIFT);
262 
263 	CSR_WRITE_2(ELINK_W3_INTERNAL_CONFIG, config0);
264 	CSR_WRITE_2(ELINK_W3_INTERNAL_CONFIG + 2, config1);
265 }
266 
267 static void
ex_probemedia(void)268 ex_probemedia(void)
269 {
270 	int i, j;
271 	struct mtabentry *m;
272 
273 	/* test for presence of connectors */
274 	GO_WINDOW(3);
275 	i = CSR_READ_1(ELINK_W3_RESET_OPTIONS);
276 	j = (CSR_READ_2(ELINK_W3_INTERNAL_CONFIG + 2) & CONFIG_MEDIAMASK)
277 		>> CONFIG_MEDIAMASK_SHIFT;
278 	GO_WINDOW(0);
279 
280 	for (ether_medium = 0, m = mediatab;
281 	     ether_medium < sizeof(mediatab) / sizeof(mediatab[0]);
282 	     ether_medium++, m++) {
283 		if (j == m->address_cfg) {
284 			if (!(i & m->config_bit)) {
285 				printf("%s not present\n", m->name);
286 				goto bad;
287 			}
288 			printf("using %s\n", m->name);
289 			return;
290 		}
291 	}
292 	printf("unknown connector\n");
293 bad:
294 	ether_medium = -1;
295 }
296 
297 int
EtherInit(unsigned char * myadr)298 EtherInit(unsigned char *myadr)
299 {
300 	uint32_t pcicsr;
301 	uint16_t val;
302 	volatile struct ex_upd *upd;
303 #ifndef _STANDALONE
304 	uint32_t id;
305 #endif
306 
307 	if (pcicheck()) {
308 		printf("pcicheck failed\n");
309 		return 0;
310 	}
311 #ifndef _STANDALONE
312 	pcicfgread(&mytag, 0, &id);
313 #endif
314 	for (excard = &excards[0]; excard->did != -1; excard++) {
315 #ifdef _STANDALONE
316 		if (pcifinddev(0x10b7, excard->did, &mytag) == 0)
317 			goto found;
318 #else
319 		if (id == (0x10b7 | (excard->did << 16)))
320 			goto found;
321 #endif
322 	}
323 	printf("no ex\n");
324 	return 0;
325 
326 found:
327 	pcicfgread(&mytag, 0x10, &iobase);
328 	iobase &= ~3;
329 
330 #ifndef _STANDALONE
331 	dmamem = mapmem(DMABASE, DMASIZE);
332 	if (!dmamem)
333 		return 0;
334 #endif
335 
336 	/* enable bus mastering in PCI command register */
337 	if (pcicfgread(&mytag, 0x04, (int *)&pcicsr)
338 	    || pcicfgwrite(&mytag, 0x04, pcicsr | 4)) {
339 		printf("cannot enable DMA\n");
340 		return 0;
341 	}
342 
343 	ex_reset();
344 
345 	if (excard->mii)
346 		ether_medium = ETHERMEDIUM_MII;
347 	else {
348 		ex_probemedia();
349 		if (ether_medium < 0)
350 			return 0;
351 	}
352 
353 	val = ex_read_eeprom(EEPROM_OEM_ADDR0);
354 	myethaddr[0] = val >> 8;
355 	myethaddr[1] = val & 0xff;
356 	val = ex_read_eeprom(EEPROM_OEM_ADDR1);
357 	myethaddr[2] = val >> 8;
358 	myethaddr[3] = val & 0xff;
359 	val = ex_read_eeprom(EEPROM_OEM_ADDR2);
360 	myethaddr[4] = val >> 8;
361 	myethaddr[5] = val & 0xff;
362 	memcpy(myadr, myethaddr, 6);
363 
364 	upd = RECVBUF_VIRT;
365 	upd->upd_nextptr = RECVBUF_PHYS;
366 	upd->upd_pktstatus = 1500;
367 	upd->upd_frags[0].fr_addr = RECVBUF_PHYS + 100;
368 	upd->upd_frags[0].fr_len = 1500 | EX_FR_LAST;
369 
370 	ex_init();
371 
372 #if defined(_STANDALONE) && !defined(SUPPORT_NO_NETBSD)
373 	strncpy(bi_netif.ifname, "ex", sizeof(bi_netif.ifname));
374 	bi_netif.bus = BI_BUS_PCI;
375 	bi_netif.addr.tag = mytag;
376 
377 	BI_ADD(&bi_netif, BTINFO_NETIF, sizeof(bi_netif));
378 #endif
379 
380 	return 1;
381 }
382 
383 void
EtherStop(void)384 EtherStop(void)
385 {
386 	/*
387 	 * Issue software reset
388 	 */
389 	CSR_WRITE_2(ELINK_COMMAND, RX_DISABLE);
390 	CSR_WRITE_2(ELINK_COMMAND, TX_DISABLE);
391         CSR_WRITE_2(ELINK_COMMAND, STOP_TRANSCEIVER);
392 	CSR_WRITE_2(ELINK_COMMAND, INTR_LATCH);
393 }
394 
395 int
EtherSend(char * pkt,int len)396 EtherSend(char *pkt, int len)
397 {
398 	volatile struct ex_dpd *dpd;
399 	int i;
400 
401 	dpd = SNDBUF_VIRT;
402 
403 	dpd->dpd_nextptr = 0;
404 	dpd->dpd_fsh = len;
405 #ifdef _STANDALONE
406 	dpd->dpd_frags[0].fr_addr = vtophys(pkt);
407 #else
408 	memcpy(SNDBUF_VIRT + 100, pkt, len);
409 	dpd->dpd_frags[0].fr_addr = SNDBUF_PHYS + 100;
410 #endif
411 	dpd->dpd_frags[0].fr_len = len | EX_FR_LAST;
412 
413 	CSR_WRITE_4(ELINK_DNLISTPTR, SNDBUF_PHYS);
414 	CSR_WRITE_2(ELINK_COMMAND, ELINK_DNUNSTALL);
415 
416 	i = 10000;
417 	while (!(dpd->dpd_fsh & 0x00010000)) {
418 		if (--i < 0) {
419 			printf("3c90xb: send timeout\n");
420 			return -1;
421 		}
422 		delay(1);
423 	}
424 
425 	return len;
426 }
427 
428 int
EtherReceive(char * pkt,int maxlen)429 EtherReceive(char *pkt, int maxlen)
430 {
431 	volatile struct ex_upd *upd;
432 	int len;
433 
434 	upd = RECVBUF_VIRT;
435 
436 	if (!(upd->upd_pktstatus & ~EX_UPD_PKTLENMASK))
437 		return 0;
438 
439 	len = upd->upd_pktstatus & EX_UPD_PKTLENMASK;
440 	if (len > maxlen)
441 		len = 0;
442 	else
443 		memcpy(pkt, RECVBUF_VIRT + 100, len);
444 
445 	upd->upd_pktstatus = 1500;
446 	CSR_WRITE_2(ELINK_COMMAND, ELINK_UPUNSTALL);
447 
448 	return len;
449 }
450