1 /* $NetBSD: if_ep_isa.c,v 1.43 2008/08/27 05:33:47 christos Exp $ */
4 * Copyright (c) 1996, 1997 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 * Copyright (c) 1997 Jonathan Stone <jonathan@NetBSD.org>
35 * Copyright (c) 1994 Herb Peyerl <hpeyerl@beer.org>
36 * All rights reserved.
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
41 * 1. Redistributions of source code must retain the above copyright
42 * notice, this list of conditions and the following disclaimer.
43 * 2. Redistributions in binary form must reproduce the above copyright
44 * notice, this list of conditions and the following disclaimer in the
45 * documentation and/or other materials provided with the distribution.
46 * 3. All advertising materials mentioning features or use of this software
47 * must display the following acknowledgement:
48 * This product includes software developed by Herb Peyerl.
49 * 4. The name of Herb Peyerl may not be used to endorse or promote products
50 * derived from this software without specific prior written permission.
52 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
53 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
54 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
55 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
56 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
57 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
58 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
59 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
60 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
61 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
64 #include <sys/cdefs.h>
65 __KERNEL_RCSID(0, "$NetBSD: if_ep_isa.c,v 1.43 2008/08/27 05:33:47 christos Exp $");
67 #include <sys/param.h>
68 #include <sys/systm.h>
70 #include <sys/socket.h>
71 #include <sys/ioctl.h>
72 #include <sys/errno.h>
73 #include <sys/syslog.h>
74 #include <sys/select.h>
75 #include <sys/device.h>
76 #include <sys/queue.h>
79 #include <net/if_dl.h>
80 #include <net/if_ether.h>
81 #include <net/if_media.h>
87 #include <dev/mii/miivar.h>
89 #include <dev/ic/elink3var.h>
90 #include <dev/ic/elink3reg.h>
92 #include <dev/isa/isavar.h>
93 #include <dev/isa/elink.h>
95 int ep_isa_probe(device_t
, cfdata_t
, void *);
96 void ep_isa_attach(device_t
, device_t
, void *);
98 CFATTACH_DECL_NEW(ep_isa
, sizeof(struct ep_softc
),
99 ep_isa_probe
, ep_isa_attach
, NULL
, NULL
);
101 static void epaddcard(int, int, int, int);
104 * This keeps track of which ISAs have been through an ep probe sequence.
105 * A simple static variable isn't enough, since it's conceivable that
106 * a system might have more than one ISA bus.
108 * The "er_bus" member is the unit number of the parent ISA bus, e.g. "0"
111 struct ep_isa_done_probe
{
112 LIST_ENTRY(ep_isa_done_probe
) er_link
;
115 static LIST_HEAD(, ep_isa_done_probe
) ep_isa_all_probes
;
116 static int ep_isa_probes_initialized
;
118 #define MAXEPCARDS 20 /* if you have more than 20, you lose */
120 static struct epcard
{
126 } epcards
[MAXEPCARDS
];
130 epaddcard(int bus
, int iobase
, int irq
, int model
)
133 if (nepcards
>= MAXEPCARDS
)
135 epcards
[nepcards
].bus
= bus
;
136 epcards
[nepcards
].iobase
= iobase
;
137 epcards
[nepcards
].irq
= (irq
== 2) ? 9 : irq
;
138 epcards
[nepcards
].model
= model
;
139 epcards
[nepcards
].available
= 1;
144 * 3c509 cards on the ISA bus are probed in ethernet address order.
145 * The probe sequence requires careful orchestration, and we'd like
146 * like to allow the irq and base address to be wildcarded. So, we
147 * probe all the cards the first time epprobe() is called. On subsequent
148 * calls we look for matching cards.
151 ep_isa_probe(device_t parent
, cfdata_t match
, void *aux
)
153 struct isa_attach_args
*ia
= aux
;
154 bus_space_tag_t iot
= ia
->ia_iot
;
155 bus_space_handle_t ioh
;
156 int slot
, iobase
, irq
, i
;
157 u_int16_t vendor
, model
, eeprom_addr_cfg
;
158 struct ep_isa_done_probe
*er
;
159 int bus
= device_unit(parent
);
161 if (ISA_DIRECT_CONFIG(ia
))
164 if (ep_isa_probes_initialized
== 0) {
165 LIST_INIT(&ep_isa_all_probes
);
166 ep_isa_probes_initialized
= 1;
170 * Probe this bus if we haven't done so already.
172 for (er
= ep_isa_all_probes
.lh_first
; er
!= NULL
;
173 er
= er
->er_link
.le_next
)
174 if (er
->er_bus
== device_unit(parent
))
178 * Mark this bus so we don't probe it again.
180 er
= (struct ep_isa_done_probe
*)
181 malloc(sizeof(struct ep_isa_done_probe
), M_DEVBUF
, M_NOWAIT
);
183 panic("ep_isa_probe: can't allocate state storage");
186 LIST_INSERT_HEAD(&ep_isa_all_probes
, er
, er_link
);
189 * Map the Etherlink ID port for the probe sequence.
191 if (bus_space_map(iot
, ELINK_ID_PORT
, 1, 0, &ioh
)) {
192 printf("ep_isa_probe: can't map Etherlink ID port\n");
196 for (slot
= 0; slot
< MAXEPCARDS
; slot
++) {
197 elink_reset(iot
, ioh
, device_unit(parent
));
198 elink_idseq(iot
, ioh
, ELINK_509_POLY
);
200 /* Untag all the adapters so they will talk to us. */
202 bus_space_write_1(iot
, ioh
, 0, TAG_ADAPTER
+ 0);
204 vendor
= bswap16(epreadeeprom(iot
, ioh
, EEPROM_MFG_ID
));
205 if (vendor
!= MFG_ID
)
208 model
= bswap16(epreadeeprom(iot
, ioh
, EEPROM_PROD_ID
));
210 * XXX: Add a new product id to check for other cards
211 * (3c515?) and fix the check in ep_isa_attach.
213 if ((model
& 0xfff0) != PROD_ID_3C509
) {
216 "ep_isa_probe: ignoring model %04x\n", model
);
221 eeprom_addr_cfg
= epreadeeprom(iot
, ioh
, EEPROM_ADDR_CFG
);
222 iobase
= (eeprom_addr_cfg
& 0x1f) * 0x10 + 0x200;
224 irq
= epreadeeprom(iot
, ioh
, EEPROM_RESOURCE_CFG
);
227 /* XXX Should ignore card if non-ISA(EISA) io address? -chb */
230 * Don't attach a 3c509 in PnP mode.
231 * PnP mode was added with the 3C509B.
232 * Check some EEPROM registers to make sure this is really
233 * a 3C509B and test whether it is in PnP mode.
235 if ((model
& 0xfff0) == PROD_ID_3C509
) {
236 u_int16_t cksum
, eepromrev
, eeprom_cap
, eeprom_hi
;
240 * Fetch all the info we need to ascertain whether
241 * the card is PnP capable and in PnP mode.
242 * Skip over PnP cards.
245 /* secondary configurable data checksum */
246 cksum
= epreadeeprom(iot
, ioh
, EEPROM_CHECKSUM_EL3
)
248 for (i
= EEPROM_CONFIG_HIGH
;
249 i
< EEPROM_CHECKSUM_EL3
; i
++) {
250 cksum
^= epreadeeprom(iot
, ioh
, i
);
252 cksum
= (cksum
& 0xFF) ^ ((cksum
>> 8) & 0xFF);
254 eepromrev
= epreadeeprom(iot
, ioh
, EEPROM_SSI
);
255 eeprom_hi
= epreadeeprom(iot
, ioh
, EEPROM_CONFIG_HIGH
);
256 eeprom_cap
= epreadeeprom(iot
, ioh
, EEPROM_CAP
);
259 * Stop card responding to contention in future.
260 * (NB: stops rsponse to all reads from ID port.)
262 bus_space_write_1(iot
, ioh
, 0, TAG_ADAPTER
+ 1);
266 printf("ep_isa_probe: cksum mismatch 0x%02x\n",
270 else if ((eepromrev
& 0xF) < 1) {
271 /* 3C509B is adapter revision level 1. */
273 printf("ep_isa_probe: revision level 0\n");
276 else if (eeprom_cap
!= 0x2083) {
278 printf("ep_isa_probe: capabilities word mismatch0x%03x\n",
279 (int)epreadeeprom(iot
, ioh
, EEPROM_CAP
));
284 * we have a 3c509B with PnP capabilities.
285 * Test partly documented bits which toggle when
288 if ((eeprom_hi
& 0x8) != 0 || ((eeprom_hi
& 0xc) == 0 &&
289 (eeprom_addr_cfg
& 0x80) != 0)) {
290 printf("3COM 3C509B Ethernet card in PnP mode\n");
296 * XXX: this should probably not be done here
297 * because it enables the drq/irq lines from
298 * the board. Perhaps it should be done after
299 * we have checked for irq/drq collisions?
301 * According to the 3COM docs, this does not enable
302 * the irq lines. -chb
304 bus_space_write_1(iot
, ioh
, 0, ACTIVATE_ADAPTER_TO_CONFIG
);
306 epaddcard(bus
, iobase
, irq
, model
);
308 /* XXX should we sort by ethernet address? */
310 bus_space_unmap(iot
, ioh
, 1);
319 for (i
= 0; i
< nepcards
; i
++) {
320 if (epcards
[i
].bus
!= bus
)
322 if (epcards
[i
].available
== 0)
325 if (ia
->ia_io
[0].ir_addr
!= ISA_UNKNOWN_PORT
&&
326 ia
->ia_io
[0].ir_addr
!= epcards
[i
].iobase
)
329 if (ia
->ia_irq
[0].ir_irq
!= ISA_UNKNOWN_IRQ
&&
330 ia
->ia_irq
[0].ir_irq
!= epcards
[i
].irq
)
338 epcards
[i
].available
= 0;
341 ia
->ia_io
[0].ir_addr
= epcards
[i
].iobase
;
342 ia
->ia_io
[0].ir_size
= 0x10;
345 ia
->ia_irq
[0].ir_irq
= epcards
[i
].irq
;
350 ia
->ia_aux
= (void *)epcards
[i
].model
;
355 ep_isa_attach(device_t parent
, device_t self
, void *aux
)
357 struct ep_softc
*sc
= device_private(self
);
358 struct isa_attach_args
*ia
= aux
;
359 bus_space_tag_t iot
= ia
->ia_iot
;
360 bus_space_handle_t ioh
;
364 if (bus_space_map(iot
, ia
->ia_io
[0].ir_addr
, 0x10, 0, &ioh
)) {
365 printf(": can't map i/o space\n");
372 sc
->bustype
= ELINK_BUS_ISA
;
378 chipset
= (int)(long)ia
->ia_aux
;
379 if ((chipset
& 0xfff0) == PROD_ID_3C509
) {
380 printf(": 3Com 3C509 Ethernet\n");
381 epconfig(sc
, ELINK_CHIPSET_3C509
, NULL
);
384 * XXX: Maybe a 3c515, but the check in ep_isa_probe looks
385 * at the moment only for a 3c509.
387 printf(": unknown 3Com Ethernet card: %04x\n", chipset
);
391 sc
->sc_ih
= isa_intr_establish(ia
->ia_ic
, ia
->ia_irq
[0].ir_irq
,
392 IST_EDGE
, IPL_NET
, epintr
, sc
);