unstack - fix ipcvecs
[minix.git] / sys / arch / i386 / stand / lib / netif / 3c90xb.c
blob602d0ab1f86f0b41416f56669eed3d2561c3f643
1 /* $NetBSD: 3c90xb.c,v 1.14 2008/12/14 18:46:33 christos Exp $ */
3 /*
4 * Copyright (c) 1999
5 * Matthias Drochner. All rights reserved.
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.
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.
29 #include <sys/types.h>
30 #include <machine/pio.h>
32 struct mbuf; /* XXX */
33 typedef int bus_dmamap_t; /* XXX */
34 #include <dev/ic/elink3reg.h>
35 #include <dev/ic/elinkxlreg.h>
37 #include <lib/libsa/stand.h>
39 #include <libi386.h>
40 #include <pcivar.h>
42 #if defined(_STANDALONE) && !defined(SUPPORT_NO_NETBSD)
43 #include <lib/libkern/libkern.h>
44 #include <bootinfo.h>
45 #endif
47 #include "etherdrv.h"
49 #define RECVBUF_SIZE 1600 /* struct ex_upd + packet */
51 #ifdef _STANDALONE
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)
61 #else /* !standalone, userspace testing environment */
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);
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))
77 #endif /* _STANDALONE */
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)
87 #undef GO_WINDOW
88 #define GO_WINDOW(x) CSR_WRITE_2(ELINK_COMMAND, WINDOW_SELECT | x)
90 static int iobase;
91 static u_char myethaddr[6];
92 unsigned ether_medium;
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;
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"},
116 #if defined(_STANDALONE) && !defined(SUPPORT_NO_NETBSD)
117 static struct btinfo_netif bi_netif;
118 #endif
120 #define ex_waitcmd() \
121 do { \
122 while (CSR_READ_2(ELINK_STATUS) & COMMAND_IN_PROGRESS) \
123 continue; \
124 } while (0)
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);
132 void
133 ex_reset(void)
135 CSR_WRITE_2(ELINK_COMMAND, GLOBAL_RESET);
136 delay(100000);
137 ex_waitcmd();
141 * Read EEPROM data.
142 * XXX what to do if EEPROM doesn't unbusy?
144 uint16_t
145 ex_read_eeprom(int offset)
147 uint16_t data = 0;
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;
160 static int
161 ex_eeprom_busy(void)
163 int i = 100;
165 while (i--) {
166 if (!(CSR_READ_2(ELINK_W0_EEPROM_COMMAND) & EEPROM_BUSY))
167 return 0;
168 delay(100);
170 printf("\nex: eeprom stays busy.\n");
171 return 1;
175 * Bring device up.
177 void
178 ex_init(void)
180 int i;
182 ex_waitcmd();
183 EtherStop();
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.
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);
196 GO_WINDOW(3);
198 CSR_WRITE_2(ELINK_COMMAND, RX_RESET);
199 ex_waitcmd();
200 CSR_WRITE_2(ELINK_COMMAND, TX_RESET);
201 ex_waitcmd();
203 CSR_WRITE_2(ELINK_COMMAND, SET_INTR_MASK | 0); /* disable */
204 CSR_WRITE_2(ELINK_COMMAND, ACK_INTR | 0xff);
206 ex_set_media();
208 CSR_WRITE_2(ELINK_COMMAND, SET_RX_FILTER | FIL_INDIVIDUAL | FIL_BRDCST);
210 CSR_WRITE_4(ELINK_DNLISTPTR, 0);
211 CSR_WRITE_2(ELINK_COMMAND, TX_ENABLE);
213 CSR_WRITE_4(ELINK_UPLISTPTR, RECVBUF_PHYS);
214 CSR_WRITE_2(ELINK_COMMAND, RX_ENABLE);
215 CSR_WRITE_2(ELINK_COMMAND, ELINK_UPUNSTALL);
217 GO_WINDOW(1);
220 void
221 ex_set_media(void)
223 int config0, config1;
225 CSR_WRITE_2(ELINK_W3_MAC_CONTROL, 0);
227 if (ether_medium == ETHERMEDIUM_MII)
228 goto setcfg;
230 GO_WINDOW(4);
231 CSR_WRITE_2(ELINK_W4_MEDIA_TYPE, 0);
232 CSR_WRITE_2(ELINK_COMMAND, STOP_TRANSCEIVER);
233 delay(800);
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;
253 setcfg:
254 GO_WINDOW(3);
256 config0 = CSR_READ_2(ELINK_W3_INTERNAL_CONFIG);
257 config1 = CSR_READ_2(ELINK_W3_INTERNAL_CONFIG + 2);
259 config1 = config1 & ~CONFIG_MEDIAMASK;
260 config1 |= (mediatab[ether_medium].address_cfg
261 << CONFIG_MEDIAMASK_SHIFT);
263 CSR_WRITE_2(ELINK_W3_INTERNAL_CONFIG, config0);
264 CSR_WRITE_2(ELINK_W3_INTERNAL_CONFIG + 2, config1);
267 static void
268 ex_probemedia(void)
270 int i, j;
271 struct mtabentry *m;
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);
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;
288 printf("using %s\n", m->name);
289 return;
292 printf("unknown connector\n");
293 bad:
294 ether_medium = -1;
298 EtherInit(unsigned char *myadr)
300 uint32_t pcicsr;
301 uint16_t val;
302 volatile struct ex_upd *upd;
303 #ifndef _STANDALONE
304 uint32_t id;
305 #endif
307 if (pcicheck()) {
308 printf("pcicheck failed\n");
309 return 0;
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
323 printf("no ex\n");
324 return 0;
326 found:
327 pcicfgread(&mytag, 0x10, &iobase);
328 iobase &= ~3;
330 #ifndef _STANDALONE
331 dmamem = mapmem(DMABASE, DMASIZE);
332 if (!dmamem)
333 return 0;
334 #endif
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;
343 ex_reset();
345 if (excard->mii)
346 ether_medium = ETHERMEDIUM_MII;
347 else {
348 ex_probemedia();
349 if (ether_medium < 0)
350 return 0;
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);
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;
370 ex_init();
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;
377 BI_ADD(&bi_netif, BTINFO_NETIF, sizeof(bi_netif));
378 #endif
380 return 1;
383 void
384 EtherStop(void)
387 * Issue software reset
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);
396 EtherSend(char *pkt, int len)
398 volatile struct ex_dpd *dpd;
399 int i;
401 dpd = SNDBUF_VIRT;
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;
413 CSR_WRITE_4(ELINK_DNLISTPTR, SNDBUF_PHYS);
414 CSR_WRITE_2(ELINK_COMMAND, ELINK_DNUNSTALL);
416 i = 10000;
417 while (!(dpd->dpd_fsh & 0x00010000)) {
418 if (--i < 0) {
419 printf("3c90xb: send timeout\n");
420 return -1;
422 delay(1);
425 return len;
429 EtherReceive(char *pkt, int maxlen)
431 volatile struct ex_upd *upd;
432 int len;
434 upd = RECVBUF_VIRT;
436 if (!(upd->upd_pktstatus & ~EX_UPD_PKTLENMASK))
437 return 0;
439 len = upd->upd_pktstatus & EX_UPD_PKTLENMASK;
440 if (len > maxlen)
441 len = 0;
442 else
443 memcpy(pkt, RECVBUF_VIRT + 100, len);
445 upd->upd_pktstatus = 1500;
446 CSR_WRITE_2(ELINK_COMMAND, ELINK_UPUNSTALL);
448 return len;