1 /* $NetBSD: if_we_isa.c,v 1.19 2008/03/12 14:31:11 cube Exp $ */
4 * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
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.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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.
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
34 * Device driver for National Semiconductor DS8390/WD83C690 based ethernet
37 * Copyright (c) 1994, 1995 Charles M. Hannum. All rights reserved.
39 * Copyright (C) 1993, David Greenman. This software may be used, modified,
40 * copied, distributed, and sold, in both source and binary form provided that
41 * the above copyright and these terms are retained. Under no circumstances is
42 * the author responsible for the proper functioning of this software, nor does
43 * the author assume any responsibility for damages incurred with its use.
47 * Device driver for the Western Digital/SMC 8003 and 8013 series,
48 * and the SMC Elite Ultra (8216).
51 #include <sys/cdefs.h>
52 __KERNEL_RCSID(0, "$NetBSD: if_we_isa.c,v 1.19 2008/03/12 14:31:11 cube Exp $");
54 #include <sys/param.h>
55 #include <sys/systm.h>
56 #include <sys/device.h>
57 #include <sys/socket.h>
59 #include <sys/syslog.h>
62 #include <net/if_dl.h>
63 #include <net/if_types.h>
64 #include <net/if_media.h>
66 #include <net/if_ether.h>
69 #include <sys/bswap.h>
72 #include <dev/isa/isareg.h>
73 #include <dev/isa/isavar.h>
75 #include <dev/ic/dp8390reg.h>
76 #include <dev/ic/dp8390var.h>
77 #include <dev/ic/wereg.h>
78 #include <dev/ic/wevar.h>
80 #ifndef __BUS_SPACE_HAS_STREAM_METHODS
81 #define bus_space_read_region_stream_2 bus_space_read_region_2
82 #define bus_space_write_stream_2 bus_space_write_2
83 #define bus_space_write_region_stream_2 bus_space_write_region_2
86 int we_isa_probe(device_t
, cfdata_t
, void *);
87 void we_isa_attach(device_t
, device_t
, void *);
89 CFATTACH_DECL_NEW(we_isa
, sizeof(struct we_softc
),
90 we_isa_probe
, we_isa_attach
, NULL
, NULL
);
92 extern struct cfdriver we_cd
;
94 static const char *we_params(bus_space_tag_t
, bus_space_handle_t
,
95 u_int8_t
*, bus_size_t
*, u_int8_t
*, int *);
97 static const int we_584_irq
[] = {
98 9, 3, 5, 7, 10, 11, 15, 4,
100 #define NWE_584_IRQ (sizeof(we_584_irq) / sizeof(we_584_irq[0]))
102 static const int we_790_irq
[] = {
103 ISA_UNKNOWN_IRQ
, 9, 3, 5, 7, 10, 11, 15,
105 #define NWE_790_IRQ (sizeof(we_790_irq) / sizeof(we_790_irq[0]))
108 * Delay needed when switching 16-bit access to shared memory.
110 #define WE_DELAY(wsc) delay(3)
113 * Enable card RAM, and 16-bit access.
115 #define WE_MEM_ENABLE(wsc) \
117 if ((wsc)->sc_16bitp) \
118 bus_space_write_1((wsc)->sc_asict, (wsc)->sc_asich, \
119 WE_LAAR, (wsc)->sc_laar_proto | WE_LAAR_M16EN); \
120 bus_space_write_1((wsc)->sc_asict, (wsc)->sc_asich, \
121 WE_MSR, wsc->sc_msr_proto | WE_MSR_MENB); \
126 * Disable card RAM, and 16-bit access.
128 #define WE_MEM_DISABLE(wsc) \
130 bus_space_write_1((wsc)->sc_asict, (wsc)->sc_asich, \
131 WE_MSR, (wsc)->sc_msr_proto); \
132 if ((wsc)->sc_16bitp) \
133 bus_space_write_1((wsc)->sc_asict, (wsc)->sc_asich, \
134 WE_LAAR, (wsc)->sc_laar_proto); \
139 we_isa_probe(device_t parent
, cfdata_t cf
, void *aux
)
141 struct isa_attach_args
*ia
= aux
;
142 bus_space_tag_t asict
, memt
;
143 bus_space_handle_t asich
, memh
;
145 int asich_valid
, memh_valid
;
146 int i
, is790
, rv
= 0;
152 asich_valid
= memh_valid
= 0;
156 if (ia
->ia_niomem
< 1)
161 if (ISA_DIRECT_CONFIG(ia
))
164 /* Disallow wildcarded i/o addresses. */
165 if (ia
->ia_io
[0].ir_addr
== ISA_UNKNOWN_PORT
)
168 /* Disallow wildcarded mem address. */
169 if (ia
->ia_iomem
[0].ir_addr
== ISA_UNKNOWN_IOMEM
)
172 /* Attempt to map the device. */
173 if (bus_space_map(asict
, ia
->ia_io
[0].ir_addr
, WE_NPORTS
, 0, &asich
))
178 bus_space_write_1(asict
, asich
, WE_MSR
, WE_MSR_POW
);
182 * Attempt to do a checksum over the station address PROM.
183 * If it fails, it's probably not a WD/SMC board. There is
184 * a problem with this, though. Some clone WD8003E boards
185 * (e.g. Danpex) won't pass the checksum. In this case,
186 * the checksum byte always seems to be 0.
188 for (x
= 0, i
= 0; i
< 8; i
++)
189 x
+= bus_space_read_1(asict
, asich
, WE_PROM
+ i
);
191 if (x
!= WE_ROM_CHECKSUM_TOTAL
) {
192 /* Make sure it's an 8003E clone... */
193 if (bus_space_read_1(asict
, asich
, WE_CARD_ID
) !=
197 /* Check the checksum byte. */
198 if (bus_space_read_1(asict
, asich
, WE_PROM
+ 7) != 0)
203 * Reset the card to force it into a known state.
206 bus_space_write_1(asict
, asich
, WE_MSR
, WE_MSR_RST
| WE_MSR_POW
);
208 bus_space_write_1(asict
, asich
, WE_MSR
, WE_MSR_RST
);
212 bus_space_write_1(asict
, asich
, WE_MSR
,
213 bus_space_read_1(asict
, asich
, WE_MSR
) & ~WE_MSR_RST
);
215 /* Wait in case the card is reading it's EEPROM. */
221 if (we_params(asict
, asich
, &type
, &memsize
, NULL
, &is790
) == NULL
)
224 /* Allow user to override probed value. */
225 if (ia
->ia_iomem
[0].ir_size
)
226 memsize
= ia
->ia_iomem
[0].ir_size
;
228 /* Attempt to map the memory space. */
229 if (bus_space_map(memt
, ia
->ia_iomem
[0].ir_addr
, memsize
, 0, &memh
))
234 * If possible, get the assigned interrupt number from the card
240 /* Assemble together the encoded interrupt number. */
241 hwr
= bus_space_read_1(asict
, asich
, WE790_HWR
);
242 bus_space_write_1(asict
, asich
, WE790_HWR
,
243 hwr
| WE790_HWR_SWH
);
245 x
= bus_space_read_1(asict
, asich
, WE790_GCR
);
246 i
= ((x
& WE790_GCR_IR2
) >> 4) |
247 ((x
& (WE790_GCR_IR1
|WE790_GCR_IR0
)) >> 2);
248 bus_space_write_1(asict
, asich
, WE790_HWR
,
249 hwr
& ~WE790_HWR_SWH
);
251 if (ia
->ia_irq
[0].ir_irq
!= ISA_UNKNOWN_IRQ
&&
252 ia
->ia_irq
[0].ir_irq
!= we_790_irq
[i
])
253 aprint_error("%s%d: overriding configured "
254 "IRQ %d to %d\n", we_cd
.cd_name
, cf
->cf_unit
,
255 ia
->ia_irq
[0].ir_irq
, we_790_irq
[i
]);
256 ia
->ia_irq
[0].ir_irq
= we_790_irq
[i
];
257 } else if (type
& WE_SOFTCONFIG
) {
258 /* Assemble together the encoded interrupt number. */
259 i
= (bus_space_read_1(asict
, asich
, WE_ICR
) & WE_ICR_IR2
) |
260 ((bus_space_read_1(asict
, asich
, WE_IRR
) &
261 (WE_IRR_IR0
| WE_IRR_IR1
)) >> 5);
263 if (ia
->ia_irq
[0].ir_irq
!= ISA_UNKNOWN_IRQ
&&
264 ia
->ia_irq
[0].ir_irq
!= we_584_irq
[i
])
265 aprint_error("%s%d: overriding configured "
266 "IRQ %d to %d\n", we_cd
.cd_name
, cf
->cf_unit
,
267 ia
->ia_irq
[0].ir_irq
, we_584_irq
[i
]);
268 ia
->ia_irq
[0].ir_irq
= we_584_irq
[i
];
271 /* So, we say we've found it! */
273 ia
->ia_io
[0].ir_size
= WE_NPORTS
;
276 ia
->ia_iomem
[0].ir_size
= memsize
;
286 bus_space_unmap(asict
, asich
, WE_NPORTS
);
288 bus_space_unmap(memt
, memh
, memsize
);
293 we_isa_attach(device_t parent
, device_t self
, void *aux
)
295 struct we_softc
*wsc
= device_private(self
);
296 struct dp8390_softc
*sc
= &wsc
->sc_dp8390
;
297 struct isa_attach_args
*ia
= aux
;
298 bus_space_tag_t nict
, asict
, memt
;
299 bus_space_handle_t nich
, asich
, memh
;
305 nict
= asict
= ia
->ia_iot
;
308 /* Map the device. */
309 if (bus_space_map(asict
, ia
->ia_io
[0].ir_addr
, WE_NPORTS
, 0, &asich
)) {
310 aprint_error_dev(self
, "can't map nic i/o space\n");
314 if (bus_space_subregion(asict
, asich
, WE_NIC_OFFSET
, WE_NIC_NPORTS
,
316 aprint_error_dev(self
, "can't subregion i/o space\n");
320 typestr
= we_params(asict
, asich
, &wsc
->sc_type
, NULL
,
321 &wsc
->sc_flags
, &sc
->is790
);
322 if (typestr
== NULL
) {
323 aprint_error_dev(self
, "where did the card go?\n");
328 * Map memory space. Note we use the size that might have
329 * been overridden by the user.
331 if (bus_space_map(memt
, ia
->ia_iomem
[0].ir_addr
,
332 ia
->ia_iomem
[0].ir_size
, 0, &memh
)) {
333 aprint_error_dev(self
, "can't map shared memory\n");
337 wsc
->sc_asict
= asict
;
338 wsc
->sc_asich
= asich
;
346 wsc
->sc_maddr
= ia
->ia_iomem
[0].ir_addr
;
347 sc
->mem_size
= ia
->ia_iomem
[0].ir_size
;
349 /* Interface is always enabled. */
352 if (we_config(self
, wsc
, typestr
))
356 * Enable the configured interrupt.
359 bus_space_write_1(asict
, asich
, WE790_ICR
,
360 bus_space_read_1(asict
, asich
, WE790_ICR
) |
362 else if (wsc
->sc_type
& WE_SOFTCONFIG
)
363 bus_space_write_1(asict
, asich
, WE_IRR
,
364 bus_space_read_1(asict
, asich
, WE_IRR
) | WE_IRR_IEN
);
365 else if (ia
->ia_irq
[0].ir_irq
== ISA_UNKNOWN_IRQ
) {
366 aprint_error_dev(self
, "can't wildcard IRQ on a %s\n",
371 /* Establish interrupt handler. */
372 wsc
->sc_ih
= isa_intr_establish(ia
->ia_ic
, ia
->ia_irq
[0].ir_irq
,
373 IST_EDGE
, IPL_NET
, dp8390_intr
, sc
);
374 if (wsc
->sc_ih
== NULL
)
375 aprint_error_dev(self
, "can't establish interrupt\n");
379 we_params(bus_space_tag_t asict
, bus_space_handle_t asich
, u_int8_t
*typep
,
380 bus_size_t
*memsizep
, u_int8_t
*flagp
, int *is790p
)
390 type
= bus_space_read_1(asict
, asich
, WE_CARD_ID
);
392 case WE_TYPE_WD8003S
:
395 case WE_TYPE_WD8003E
:
398 case WE_TYPE_WD8003EB
:
399 typestr
= "WD8003EB";
401 case WE_TYPE_WD8003W
:
404 case WE_TYPE_WD8013EBT
:
405 typestr
= "WD8013EBT";
409 case WE_TYPE_WD8013W
:
414 case WE_TYPE_WD8013EP
: /* also WD8003EP */
415 if (bus_space_read_1(asict
, asich
, WE_ICR
) & WE_ICR_16BIT
) {
418 typestr
= "WD8013EP";
420 typestr
= "WD8003EP";
422 case WE_TYPE_WD8013WC
:
423 typestr
= "WD8013WC";
427 case WE_TYPE_WD8013EBP
:
428 typestr
= "WD8013EBP";
432 case WE_TYPE_WD8013EPC
:
433 typestr
= "WD8013EPC";
437 case WE_TYPE_SMC8216C
:
438 case WE_TYPE_SMC8216T
:
442 typestr
= (type
== WE_TYPE_SMC8216C
) ?
443 "SMC8216/SMC8216C" : "SMC8216T";
445 hwr
= bus_space_read_1(asict
, asich
, WE790_HWR
);
446 bus_space_write_1(asict
, asich
, WE790_HWR
,
447 hwr
| WE790_HWR_SWH
);
448 switch (bus_space_read_1(asict
, asich
, WE790_RAR
) &
460 /* 8216 has 16K shared mem -- 8416 has 8K */
461 typestr
= (type
== WE_TYPE_SMC8216C
) ?
462 "SMC8416C/SMC8416BT" : "SMC8416T";
466 bus_space_write_1(asict
, asich
, WE790_HWR
, hwr
);
473 case WE_TYPE_TOSHIBA1
:
474 typestr
= "Toshiba1";
478 case WE_TYPE_TOSHIBA4
:
479 typestr
= "Toshiba4";
485 /* Not one we recognize. */
490 * Make some adjustments to initial values depending on what is
493 if (is16bit
&& (type
!= WE_TYPE_WD8013EBT
) &&
495 (type
!= WE_TYPE_TOSHIBA1
&& type
!= WE_TYPE_TOSHIBA4
) &&
497 (bus_space_read_1(asict
, asich
, WE_ICR
) & WE_ICR_16BIT
) == 0) {
506 printf("we_params: type = 0x%x, typestr = %s, is16bit = %d, "
507 "memsize = %ld\n", type
, typestr
, is16bit
, (u_long
)memsize
);
508 for (i
= 0; i
< 8; i
++)
509 printf(" %d -> 0x%x\n", i
,
510 bus_space_read_1(asict
, asich
, i
));
516 if (memsizep
!= NULL
)
518 if (flagp
!= NULL
&& is16bit
)
519 *flagp
|= WE_16BIT_ENABLE
;