if_we_isa.c revision 1.1.4.2 1 /* $NetBSD: if_we_isa.c,v 1.1.4.2 2001/04/09 01:56:42 nathanw Exp $ */
2
3 /*-
4 * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9 * NASA Ames Research Center.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the NetBSD
22 * Foundation, Inc. and its contributors.
23 * 4. Neither the name of The NetBSD Foundation nor the names of its
24 * contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40 /*
41 * Device driver for National Semiconductor DS8390/WD83C690 based ethernet
42 * adapters.
43 *
44 * Copyright (c) 1994, 1995 Charles M. Hannum. All rights reserved.
45 *
46 * Copyright (C) 1993, David Greenman. This software may be used, modified,
47 * copied, distributed, and sold, in both source and binary form provided that
48 * the above copyright and these terms are retained. Under no circumstances is
49 * the author responsible for the proper functioning of this software, nor does
50 * the author assume any responsibility for damages incurred with its use.
51 */
52
53 /*
54 * Device driver for the Western Digital/SMC 8003 and 8013 series,
55 * and the SMC Elite Ultra (8216).
56 */
57
58 #include "opt_inet.h"
59 #include "opt_ns.h"
60 #include "bpfilter.h"
61 #include "rnd.h"
62
63 #include <sys/param.h>
64 #include <sys/systm.h>
65 #include <sys/device.h>
66 #include <sys/socket.h>
67 #include <sys/mbuf.h>
68 #include <sys/syslog.h>
69
70 #include <net/if.h>
71 #include <net/if_dl.h>
72 #include <net/if_types.h>
73 #include <net/if_media.h>
74
75 #include <net/if_ether.h>
76
77 #ifdef INET
78 #include <netinet/in.h>
79 #include <netinet/in_systm.h>
80 #include <netinet/in_var.h>
81 #include <netinet/ip.h>
82 #include <netinet/if_inarp.h>
83 #endif
84
85 #ifdef NS
86 #include <netns/ns.h>
87 #include <netns/ns_if.h>
88 #endif
89
90 #if NBPFILTER > 0
91 #include <net/bpf.h>
92 #include <net/bpfdesc.h>
93 #endif
94
95 #include <machine/bus.h>
96 #include <machine/bswap.h>
97 #include <machine/intr.h>
98
99 #include <dev/isa/isareg.h>
100 #include <dev/isa/isavar.h>
101
102 #include <dev/ic/dp8390reg.h>
103 #include <dev/ic/dp8390var.h>
104 #include <dev/ic/wereg.h>
105 #include <dev/ic/wevar.h>
106
107 #ifndef __BUS_SPACE_HAS_STREAM_METHODS
108 #define bus_space_read_region_stream_2 bus_space_read_region_2
109 #define bus_space_write_stream_2 bus_space_write_2
110 #define bus_space_write_region_stream_2 bus_space_write_region_2
111 #endif
112
113 int we_isa_probe __P((struct device *, struct cfdata *, void *));
114 void we_isa_attach __P((struct device *, struct device *, void *));
115
116 struct cfattach we_isa_ca = {
117 sizeof(struct we_softc), we_isa_probe, we_isa_attach
118 };
119
120 extern struct cfdriver we_cd;
121
122 static const char *we_params __P((bus_space_tag_t, bus_space_handle_t,
123 u_int8_t *, bus_size_t *, int *, int *));
124
125 static const int we_584_irq[] = {
126 9, 3, 5, 7, 10, 11, 15, 4,
127 };
128 #define NWE_584_IRQ (sizeof(we_584_irq) / sizeof(we_584_irq[0]))
129
130 static const int we_790_irq[] = {
131 IRQUNK, 9, 3, 5, 7, 10, 11, 15,
132 };
133 #define NWE_790_IRQ (sizeof(we_790_irq) / sizeof(we_790_irq[0]))
134
135 /*
136 * Delay needed when switching 16-bit access to shared memory.
137 */
138 #define WE_DELAY(wsc) delay(3)
139
140 /*
141 * Enable card RAM, and 16-bit access.
142 */
143 #define WE_MEM_ENABLE(wsc) \
144 do { \
145 if ((wsc)->sc_16bitp) \
146 bus_space_write_1((wsc)->sc_asict, (wsc)->sc_asich, \
147 WE_LAAR, (wsc)->sc_laar_proto | WE_LAAR_M16EN); \
148 bus_space_write_1((wsc)->sc_asict, (wsc)->sc_asich, \
149 WE_MSR, wsc->sc_msr_proto | WE_MSR_MENB); \
150 WE_DELAY((wsc)); \
151 } while (0)
152
153 /*
154 * Disable card RAM, and 16-bit access.
155 */
156 #define WE_MEM_DISABLE(wsc) \
157 do { \
158 bus_space_write_1((wsc)->sc_asict, (wsc)->sc_asich, \
159 WE_MSR, (wsc)->sc_msr_proto); \
160 if ((wsc)->sc_16bitp) \
161 bus_space_write_1((wsc)->sc_asict, (wsc)->sc_asich, \
162 WE_LAAR, (wsc)->sc_laar_proto); \
163 WE_DELAY((wsc)); \
164 } while (0)
165
166 int
167 we_isa_probe(parent, cf, aux)
168 struct device *parent;
169 struct cfdata *cf;
170 void *aux;
171 {
172 struct isa_attach_args *ia = aux;
173 bus_space_tag_t asict, memt;
174 bus_space_handle_t asich, memh;
175 bus_size_t memsize;
176 int asich_valid, memh_valid;
177 int i, is790, rv = 0;
178 u_int8_t x, type;
179
180 asict = ia->ia_iot;
181 memt = ia->ia_memt;
182
183 asich_valid = memh_valid = 0;
184
185 /* Disallow wildcarded i/o addresses. */
186 if (ia->ia_iobase == ISACF_PORT_DEFAULT)
187 return (0);
188
189 /* Disallow wildcarded mem address. */
190 if (ia->ia_maddr == ISACF_IOMEM_DEFAULT)
191 return (0);
192
193 /* Attempt to map the device. */
194 if (bus_space_map(asict, ia->ia_iobase, WE_NPORTS, 0, &asich))
195 goto out;
196 asich_valid = 1;
197
198 #ifdef TOSH_ETHER
199 bus_space_write_1(asict, asich, WE_MSR, WE_MSR_POW);
200 #endif
201
202 /*
203 * Attempt to do a checksum over the station address PROM.
204 * If it fails, it's probably not a WD/SMC board. There is
205 * a problem with this, though. Some clone WD8003E boards
206 * (e.g. Danpex) won't pass the checksum. In this case,
207 * the checksum byte always seems to be 0.
208 */
209 for (x = 0, i = 0; i < 8; i++)
210 x += bus_space_read_1(asict, asich, WE_PROM + i);
211
212 if (x != WE_ROM_CHECKSUM_TOTAL) {
213 /* Make sure it's an 8003E clone... */
214 if (bus_space_read_1(asict, asich, WE_CARD_ID) !=
215 WE_TYPE_WD8003E)
216 goto out;
217
218 /* Check the checksum byte. */
219 if (bus_space_read_1(asict, asich, WE_PROM + 7) != 0)
220 goto out;
221 }
222
223 /*
224 * Reset the card to force it into a known state.
225 */
226 #ifdef TOSH_ETHER
227 bus_space_write_1(asict, asich, WE_MSR, WE_MSR_RST | WE_MSR_POW);
228 #else
229 bus_space_write_1(asict, asich, WE_MSR, WE_MSR_RST);
230 #endif
231 delay(100);
232
233 bus_space_write_1(asict, asich, WE_MSR,
234 bus_space_read_1(asict, asich, WE_MSR) & ~WE_MSR_RST);
235
236 /* Wait in case the card is reading it's EEPROM. */
237 delay(5000);
238
239 /*
240 * Get parameters.
241 */
242 if (we_params(asict, asich, &type, &memsize, NULL, &is790) == NULL)
243 goto out;
244
245 /* Allow user to override probed value. */
246 if (ia->ia_msize)
247 memsize = ia->ia_msize;
248
249 /* Attempt to map the memory space. */
250 if (bus_space_map(memt, ia->ia_maddr, memsize, 0, &memh))
251 goto out;
252 memh_valid = 1;
253
254 /*
255 * If possible, get the assigned interrupt number from the card
256 * and use it.
257 */
258 if (is790) {
259 u_int8_t hwr;
260
261 /* Assemble together the encoded interrupt number. */
262 hwr = bus_space_read_1(asict, asich, WE790_HWR);
263 bus_space_write_1(asict, asich, WE790_HWR,
264 hwr | WE790_HWR_SWH);
265
266 x = bus_space_read_1(asict, asich, WE790_GCR);
267 i = ((x & WE790_GCR_IR2) >> 4) |
268 ((x & (WE790_GCR_IR1|WE790_GCR_IR0)) >> 2);
269 bus_space_write_1(asict, asich, WE790_HWR,
270 hwr & ~WE790_HWR_SWH);
271
272 if (ia->ia_irq != IRQUNK && ia->ia_irq != we_790_irq[i])
273 printf("%s%d: overriding IRQ %d to %d\n",
274 we_cd.cd_name, cf->cf_unit, ia->ia_irq,
275 we_790_irq[i]);
276 ia->ia_irq = we_790_irq[i];
277 } else if (type & WE_SOFTCONFIG) {
278 /* Assemble together the encoded interrupt number. */
279 i = (bus_space_read_1(asict, asich, WE_ICR) & WE_ICR_IR2) |
280 ((bus_space_read_1(asict, asich, WE_IRR) &
281 (WE_IRR_IR0 | WE_IRR_IR1)) >> 5);
282
283 if (ia->ia_irq != IRQUNK && ia->ia_irq != we_584_irq[i])
284 printf("%s%d: overriding IRQ %d to %d\n",
285 we_cd.cd_name, cf->cf_unit, ia->ia_irq,
286 we_584_irq[i]);
287 ia->ia_irq = we_584_irq[i];
288 }
289
290 /* So, we say we've found it! */
291 ia->ia_iosize = WE_NPORTS;
292 ia->ia_msize = memsize;
293 rv = 1;
294
295 out:
296 if (asich_valid)
297 bus_space_unmap(asict, asich, WE_NPORTS);
298 if (memh_valid)
299 bus_space_unmap(memt, memh, memsize);
300 return (rv);
301 }
302
303 void
304 we_isa_attach(parent, self, aux)
305 struct device *parent, *self;
306 void *aux;
307 {
308 struct we_softc *wsc = (struct we_softc *)self;
309 struct dp8390_softc *sc = &wsc->sc_dp8390;
310 struct isa_attach_args *ia = aux;
311 bus_space_tag_t nict, asict, memt;
312 bus_space_handle_t nich, asich, memh;
313 const char *typestr;
314
315 printf("\n");
316
317 nict = asict = ia->ia_iot;
318 memt = ia->ia_memt;
319
320 /* Map the device. */
321 if (bus_space_map(asict, ia->ia_iobase, WE_NPORTS, 0, &asich)) {
322 printf("%s: can't map nic i/o space\n",
323 sc->sc_dev.dv_xname);
324 return;
325 }
326
327 if (bus_space_subregion(asict, asich, WE_NIC_OFFSET, WE_NIC_NPORTS,
328 &nich)) {
329 printf("%s: can't subregion i/o space\n",
330 sc->sc_dev.dv_xname);
331 return;
332 }
333
334 typestr = we_params(asict, asich, &wsc->sc_type, NULL,
335 &wsc->sc_16bitp, &sc->is790);
336 if (typestr == NULL) {
337 printf("%s: where did the card go?\n", sc->sc_dev.dv_xname);
338 return;
339 }
340
341 /*
342 * Map memory space. Note we use the size that might have
343 * been overridden by the user.
344 */
345 if (bus_space_map(memt, ia->ia_maddr, ia->ia_msize, 0, &memh)) {
346 printf("%s: can't map shared memory\n",
347 sc->sc_dev.dv_xname);
348 return;
349 }
350
351 wsc->sc_asict = asict;
352 wsc->sc_asich = asich;
353
354 sc->sc_regt = nict;
355 sc->sc_regh = nich;
356
357 sc->sc_buft = memt;
358 sc->sc_bufh = memh;
359
360 wsc->sc_maddr = ia->ia_maddr;
361 sc->mem_size = ia->ia_msize;
362
363 /* Interface is always enabled. */
364 sc->sc_enabled = 1;
365
366 if (we_config(self, wsc, typestr))
367 return;
368
369 /*
370 * Enable the configured interrupt.
371 */
372 if (sc->is790)
373 bus_space_write_1(asict, asich, WE790_ICR,
374 bus_space_read_1(asict, asich, WE790_ICR) |
375 WE790_ICR_EIL);
376 else if (wsc->sc_type & WE_SOFTCONFIG)
377 bus_space_write_1(asict, asich, WE_IRR,
378 bus_space_read_1(asict, asich, WE_IRR) | WE_IRR_IEN);
379 else if (ia->ia_irq == IRQUNK) {
380 printf("%s: can't wildcard IRQ on a %s\n",
381 sc->sc_dev.dv_xname, typestr);
382 return;
383 }
384
385 /* Establish interrupt handler. */
386 wsc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE,
387 IPL_NET, dp8390_intr, sc);
388 if (wsc->sc_ih == NULL)
389 printf("%s: can't establish interrupt\n", sc->sc_dev.dv_xname);
390 }
391
392 static const char *
393 we_params(asict, asich, typep, memsizep, is16bitp, is790p)
394 bus_space_tag_t asict;
395 bus_space_handle_t asich;
396 u_int8_t *typep;
397 bus_size_t *memsizep;
398 int *is16bitp, *is790p;
399 {
400 const char *typestr;
401 bus_size_t memsize;
402 int is16bit, is790;
403 u_int8_t type;
404
405 memsize = 8192;
406 is16bit = is790 = 0;
407
408 type = bus_space_read_1(asict, asich, WE_CARD_ID);
409 switch (type) {
410 case WE_TYPE_WD8003S:
411 typestr = "WD8003S";
412 break;
413 case WE_TYPE_WD8003E:
414 typestr = "WD8003E";
415 break;
416 case WE_TYPE_WD8003EB:
417 typestr = "WD8003EB";
418 break;
419 case WE_TYPE_WD8003W:
420 typestr = "WD8003W";
421 break;
422 case WE_TYPE_WD8013EBT:
423 typestr = "WD8013EBT";
424 memsize = 16384;
425 is16bit = 1;
426 break;
427 case WE_TYPE_WD8013W:
428 typestr = "WD8013W";
429 memsize = 16384;
430 is16bit = 1;
431 break;
432 case WE_TYPE_WD8013EP: /* also WD8003EP */
433 if (bus_space_read_1(asict, asich, WE_ICR) & WE_ICR_16BIT) {
434 is16bit = 1;
435 memsize = 16384;
436 typestr = "WD8013EP";
437 } else
438 typestr = "WD8003EP";
439 break;
440 case WE_TYPE_WD8013WC:
441 typestr = "WD8013WC";
442 memsize = 16384;
443 is16bit = 1;
444 break;
445 case WE_TYPE_WD8013EBP:
446 typestr = "WD8013EBP";
447 memsize = 16384;
448 is16bit = 1;
449 break;
450 case WE_TYPE_WD8013EPC:
451 typestr = "WD8013EPC";
452 memsize = 16384;
453 is16bit = 1;
454 break;
455 case WE_TYPE_SMC8216C:
456 case WE_TYPE_SMC8216T:
457 {
458 u_int8_t hwr;
459
460 typestr = (type == WE_TYPE_SMC8216C) ?
461 "SMC8216/SMC8216C" : "SMC8216T";
462
463 hwr = bus_space_read_1(asict, asich, WE790_HWR);
464 bus_space_write_1(asict, asich, WE790_HWR,
465 hwr | WE790_HWR_SWH);
466 switch (bus_space_read_1(asict, asich, WE790_RAR) &
467 WE790_RAR_SZ64) {
468 case WE790_RAR_SZ64:
469 memsize = 65536;
470 break;
471 case WE790_RAR_SZ32:
472 memsize = 32768;
473 break;
474 case WE790_RAR_SZ16:
475 memsize = 16384;
476 break;
477 case WE790_RAR_SZ8:
478 /* 8216 has 16K shared mem -- 8416 has 8K */
479 typestr = (type == WE_TYPE_SMC8216C) ?
480 "SMC8416C/SMC8416BT" : "SMC8416T";
481 memsize = 8192;
482 break;
483 }
484 bus_space_write_1(asict, asich, WE790_HWR, hwr);
485
486 is16bit = 1;
487 is790 = 1;
488 break;
489 }
490 #ifdef TOSH_ETHER
491 case WE_TYPE_TOSHIBA1:
492 typestr = "Toshiba1";
493 memsize = 32768;
494 is16bit = 1;
495 break;
496 case WE_TYPE_TOSHIBA4:
497 typestr = "Toshiba4";
498 memsize = 32768;
499 is16bit = 1;
500 break;
501 #endif
502 default:
503 /* Not one we recognize. */
504 return (NULL);
505 }
506
507 /*
508 * Make some adjustments to initial values depending on what is
509 * found in the ICR.
510 */
511 if (is16bit && (type != WE_TYPE_WD8013EBT) &&
512 #ifdef TOSH_ETHER
513 (type != WE_TYPE_TOSHIBA1 && type != WE_TYPE_TOSHIBA4) &&
514 #endif
515 (bus_space_read_1(asict, asich, WE_ICR) & WE_ICR_16BIT) == 0) {
516 is16bit = 0;
517 memsize = 8192;
518 }
519
520 #ifdef WE_DEBUG
521 {
522 int i;
523
524 printf("we_params: type = 0x%x, typestr = %s, is16bit = %d, "
525 "memsize = %d\n", type, typestr, is16bit, memsize);
526 for (i = 0; i < 8; i++)
527 printf(" %d -> 0x%x\n", i,
528 bus_space_read_1(asict, asich, i));
529 }
530 #endif
531
532 if (typep != NULL)
533 *typep = type;
534 if (memsizep != NULL)
535 *memsizep = memsize;
536 if (is16bitp != NULL)
537 *is16bitp = is16bit;
538 if (is790p != NULL)
539 *is790p = is790;
540 return (typestr);
541 }
542