1 /* $NetBSD: if_we_isa.c,v 1.8 2002/10/02 03:10:48 thorpej 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 <sys/cdefs.h>
59 __KERNEL_RCSID(0, "$NetBSD: if_we_isa.c,v 1.8 2002/10/02 03:10:48 thorpej Exp $");
60
61 #include <sys/param.h>
62 #include <sys/systm.h>
63 #include <sys/device.h>
64 #include <sys/socket.h>
65 #include <sys/mbuf.h>
66 #include <sys/syslog.h>
67
68 #include <net/if.h>
69 #include <net/if_dl.h>
70 #include <net/if_types.h>
71 #include <net/if_media.h>
72
73 #include <net/if_ether.h>
74
75 #include <machine/bus.h>
76 #include <machine/bswap.h>
77 #include <machine/intr.h>
78
79 #include <dev/isa/isareg.h>
80 #include <dev/isa/isavar.h>
81
82 #include <dev/ic/dp8390reg.h>
83 #include <dev/ic/dp8390var.h>
84 #include <dev/ic/wereg.h>
85 #include <dev/ic/wevar.h>
86
87 #ifndef __BUS_SPACE_HAS_STREAM_METHODS
88 #define bus_space_read_region_stream_2 bus_space_read_region_2
89 #define bus_space_write_stream_2 bus_space_write_2
90 #define bus_space_write_region_stream_2 bus_space_write_region_2
91 #endif
92
93 int we_isa_probe __P((struct device *, struct cfdata *, void *));
94 void we_isa_attach __P((struct device *, struct device *, void *));
95
96 CFATTACH_DECL(we_isa, sizeof(struct we_softc),
97 we_isa_probe, we_isa_attach, NULL, NULL);
98
99 extern struct cfdriver we_cd;
100
101 static const char *we_params __P((bus_space_tag_t, bus_space_handle_t,
102 u_int8_t *, bus_size_t *, int *, int *));
103
104 static const int we_584_irq[] = {
105 9, 3, 5, 7, 10, 11, 15, 4,
106 };
107 #define NWE_584_IRQ (sizeof(we_584_irq) / sizeof(we_584_irq[0]))
108
109 static const int we_790_irq[] = {
110 ISACF_IRQ_DEFAULT, 9, 3, 5, 7, 10, 11, 15,
111 };
112 #define NWE_790_IRQ (sizeof(we_790_irq) / sizeof(we_790_irq[0]))
113
114 /*
115 * Delay needed when switching 16-bit access to shared memory.
116 */
117 #define WE_DELAY(wsc) delay(3)
118
119 /*
120 * Enable card RAM, and 16-bit access.
121 */
122 #define WE_MEM_ENABLE(wsc) \
123 do { \
124 if ((wsc)->sc_16bitp) \
125 bus_space_write_1((wsc)->sc_asict, (wsc)->sc_asich, \
126 WE_LAAR, (wsc)->sc_laar_proto | WE_LAAR_M16EN); \
127 bus_space_write_1((wsc)->sc_asict, (wsc)->sc_asich, \
128 WE_MSR, wsc->sc_msr_proto | WE_MSR_MENB); \
129 WE_DELAY((wsc)); \
130 } while (0)
131
132 /*
133 * Disable card RAM, and 16-bit access.
134 */
135 #define WE_MEM_DISABLE(wsc) \
136 do { \
137 bus_space_write_1((wsc)->sc_asict, (wsc)->sc_asich, \
138 WE_MSR, (wsc)->sc_msr_proto); \
139 if ((wsc)->sc_16bitp) \
140 bus_space_write_1((wsc)->sc_asict, (wsc)->sc_asich, \
141 WE_LAAR, (wsc)->sc_laar_proto); \
142 WE_DELAY((wsc)); \
143 } while (0)
144
145 int
146 we_isa_probe(parent, cf, aux)
147 struct device *parent;
148 struct cfdata *cf;
149 void *aux;
150 {
151 struct isa_attach_args *ia = aux;
152 bus_space_tag_t asict, memt;
153 bus_space_handle_t asich, memh;
154 bus_size_t memsize;
155 int asich_valid, memh_valid;
156 int i, is790, rv = 0;
157 u_int8_t x, type;
158
159 asict = ia->ia_iot;
160 memt = ia->ia_memt;
161
162 asich_valid = memh_valid = 0;
163
164 if (ia->ia_nio < 1)
165 return (0);
166 if (ia->ia_niomem < 1)
167 return (0);
168 if (ia->ia_nirq < 1)
169 return (0);
170
171 if (ISA_DIRECT_CONFIG(ia))
172 return (0);
173
174 /* Disallow wildcarded i/o addresses. */
175 if (ia->ia_io[0].ir_addr == ISACF_PORT_DEFAULT)
176 return (0);
177
178 /* Disallow wildcarded mem address. */
179 if (ia->ia_iomem[0].ir_addr == ISACF_IOMEM_DEFAULT)
180 return (0);
181
182 /* Attempt to map the device. */
183 if (bus_space_map(asict, ia->ia_io[0].ir_addr, WE_NPORTS, 0, &asich))
184 goto out;
185 asich_valid = 1;
186
187 #ifdef TOSH_ETHER
188 bus_space_write_1(asict, asich, WE_MSR, WE_MSR_POW);
189 #endif
190
191 /*
192 * Attempt to do a checksum over the station address PROM.
193 * If it fails, it's probably not a WD/SMC board. There is
194 * a problem with this, though. Some clone WD8003E boards
195 * (e.g. Danpex) won't pass the checksum. In this case,
196 * the checksum byte always seems to be 0.
197 */
198 for (x = 0, i = 0; i < 8; i++)
199 x += bus_space_read_1(asict, asich, WE_PROM + i);
200
201 if (x != WE_ROM_CHECKSUM_TOTAL) {
202 /* Make sure it's an 8003E clone... */
203 if (bus_space_read_1(asict, asich, WE_CARD_ID) !=
204 WE_TYPE_WD8003E)
205 goto out;
206
207 /* Check the checksum byte. */
208 if (bus_space_read_1(asict, asich, WE_PROM + 7) != 0)
209 goto out;
210 }
211
212 /*
213 * Reset the card to force it into a known state.
214 */
215 #ifdef TOSH_ETHER
216 bus_space_write_1(asict, asich, WE_MSR, WE_MSR_RST | WE_MSR_POW);
217 #else
218 bus_space_write_1(asict, asich, WE_MSR, WE_MSR_RST);
219 #endif
220 delay(100);
221
222 bus_space_write_1(asict, asich, WE_MSR,
223 bus_space_read_1(asict, asich, WE_MSR) & ~WE_MSR_RST);
224
225 /* Wait in case the card is reading it's EEPROM. */
226 delay(5000);
227
228 /*
229 * Get parameters.
230 */
231 if (we_params(asict, asich, &type, &memsize, NULL, &is790) == NULL)
232 goto out;
233
234 /* Allow user to override probed value. */
235 if (ia->ia_iomem[0].ir_size)
236 memsize = ia->ia_iomem[0].ir_size;
237
238 /* Attempt to map the memory space. */
239 if (bus_space_map(memt, ia->ia_iomem[0].ir_addr, memsize, 0, &memh))
240 goto out;
241 memh_valid = 1;
242
243 /*
244 * If possible, get the assigned interrupt number from the card
245 * and use it.
246 */
247 if (is790) {
248 u_int8_t hwr;
249
250 /* Assemble together the encoded interrupt number. */
251 hwr = bus_space_read_1(asict, asich, WE790_HWR);
252 bus_space_write_1(asict, asich, WE790_HWR,
253 hwr | WE790_HWR_SWH);
254
255 x = bus_space_read_1(asict, asich, WE790_GCR);
256 i = ((x & WE790_GCR_IR2) >> 4) |
257 ((x & (WE790_GCR_IR1|WE790_GCR_IR0)) >> 2);
258 bus_space_write_1(asict, asich, WE790_HWR,
259 hwr & ~WE790_HWR_SWH);
260
261 if (ia->ia_irq[0].ir_irq != ISACF_IRQ_DEFAULT &&
262 ia->ia_irq[0].ir_irq != we_790_irq[i])
263 printf("%s%d: overriding configured IRQ %d to %d\n",
264 we_cd.cd_name, cf->cf_unit, ia->ia_irq[0].ir_irq,
265 we_790_irq[i]);
266 ia->ia_irq[0].ir_irq = we_790_irq[i];
267 } else if (type & WE_SOFTCONFIG) {
268 /* Assemble together the encoded interrupt number. */
269 i = (bus_space_read_1(asict, asich, WE_ICR) & WE_ICR_IR2) |
270 ((bus_space_read_1(asict, asich, WE_IRR) &
271 (WE_IRR_IR0 | WE_IRR_IR1)) >> 5);
272
273 if (ia->ia_irq[0].ir_irq != ISACF_IRQ_DEFAULT &&
274 ia->ia_irq[0].ir_irq != we_584_irq[i])
275 printf("%s%d: overriding configured IRQ %d to %d\n",
276 we_cd.cd_name, cf->cf_unit, ia->ia_irq[0].ir_irq,
277 we_584_irq[i]);
278 ia->ia_irq[0].ir_irq = we_584_irq[i];
279 }
280
281 /* So, we say we've found it! */
282 ia->ia_nio = 1;
283 ia->ia_io[0].ir_size = WE_NPORTS;
284
285 ia->ia_niomem = 1;
286 ia->ia_iomem[0].ir_size = memsize;
287
288 ia->ia_nirq = 1;
289
290 ia->ia_ndrq = 0;
291
292 rv = 1;
293
294 out:
295 if (asich_valid)
296 bus_space_unmap(asict, asich, WE_NPORTS);
297 if (memh_valid)
298 bus_space_unmap(memt, memh, memsize);
299 return (rv);
300 }
301
302 void
303 we_isa_attach(parent, self, aux)
304 struct device *parent, *self;
305 void *aux;
306 {
307 struct we_softc *wsc = (struct we_softc *)self;
308 struct dp8390_softc *sc = &wsc->sc_dp8390;
309 struct isa_attach_args *ia = aux;
310 bus_space_tag_t nict, asict, memt;
311 bus_space_handle_t nich, asich, memh;
312 const char *typestr;
313
314 printf("\n");
315
316 nict = asict = ia->ia_iot;
317 memt = ia->ia_memt;
318
319 /* Map the device. */
320 if (bus_space_map(asict, ia->ia_io[0].ir_addr, WE_NPORTS, 0, &asich)) {
321 printf("%s: can't map nic i/o space\n",
322 sc->sc_dev.dv_xname);
323 return;
324 }
325
326 if (bus_space_subregion(asict, asich, WE_NIC_OFFSET, WE_NIC_NPORTS,
327 &nich)) {
328 printf("%s: can't subregion i/o space\n",
329 sc->sc_dev.dv_xname);
330 return;
331 }
332
333 typestr = we_params(asict, asich, &wsc->sc_type, NULL,
334 &wsc->sc_16bitp, &sc->is790);
335 if (typestr == NULL) {
336 printf("%s: where did the card go?\n", sc->sc_dev.dv_xname);
337 return;
338 }
339
340 /*
341 * Map memory space. Note we use the size that might have
342 * been overridden by the user.
343 */
344 if (bus_space_map(memt, ia->ia_iomem[0].ir_addr,
345 ia->ia_iomem[0].ir_size, 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_iomem[0].ir_addr;
361 sc->mem_size = ia->ia_iomem[0].ir_size;
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[0].ir_irq == ISACF_IRQ_DEFAULT) {
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[0].ir_irq,
387 IST_EDGE, 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 }
Cache object: 3756a416fd0c593f07d5c5aa2c4e778e
|