Subject: kern/3574: if_ie malfunctions on 3Com cards if more than one configured
To: None <gnats-bugs@gnats.netbsd.org>
From: None <rkboni@concentric.net>
List: netbsd-bugs
Date: 05/04/1997 23:10:29
>Number: 3574
>Category: kern
>Synopsis: with both ie0 and ie1 in kern config, 3C507 cards break
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: kern-bug-people (Kernel Bug People)
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Sun May 4 20:20:01 1997
>Last-Modified:
>Originator: Rafal Boni
>Organization:
Huh? Whazzat?
>Release: April 20'th, 1997, but is present in all newer verions
>Environment:
System: NetBSD doppelganger 1.2D NetBSD 1.2D (DOPPELGANGER) #0: Sun May 4 17:32:40 EDT 1997 rafal@doppelganger:/usr/NetBSD/src/sys/arch/i386/compile/DOPPELGANGER i386
ISA i486 machine with one or more 3C507 cards.
>Description:
The 3C507, like the 3c509, needs a Magick Sequence of bits to be sent
to a Magick Port to enable all cards on a bus. The driver is not
careful about only doing so once per bus, hence setting cards that
have already been initialized back into unconfigured states.
>How-To-Repeat:
Build kernel with both ie0 and ie1, boot on a ISA-bus machine with
a 3C507 on the bus. Watch kernel freeze during/after autoconf.
>Fix:
This code is stolen almost directly from the if_ep ISA frontend.
Index: if_ie.c
===================================================================
RCS file: /cvs/root/netbsd/src/sys/dev/isa/if_ie.c,v
retrieving revision 1.1.1.1
diff -c -2 -r1.1.1.1 if_ie.c
*** if_ie.c 1997/04/19 21:32:45 1.1.1.1
--- if_ie.c 1997/05/05 02:27:23
***************
*** 223,226 ****
--- 223,241 ----
/*
+ * This keeps track of which ISAs have been through an ie probe sequence.
+ * A simple static variable isn't enough, since it's conceivable that
+ * a system might have more than one ISA bus.
+ *
+ * The "er_bus" member is the unit number of the parent ISA bus, e.g. "0"
+ * for "isa0".
+ */
+ struct ie_isa_done_probe {
+ LIST_ENTRY(ie_isa_done_probe) er_link;
+ int er_bus;
+ };
+ static LIST_HEAD(, ie_isa_done_probe) ie_isa_all_probes;
+ static int ie_isa_probes_initialized;
+
+ /*
* Ethernet status, per interface.
*/
***************
*** 314,318 ****
void ieattach __P((struct device *, struct device *, void *));
int sl_probe __P((struct ie_softc *, struct isa_attach_args *));
! int el_probe __P((struct ie_softc *, struct isa_attach_args *));
int ee16_probe __P((struct ie_softc *, struct isa_attach_args *));
int check_ie_present __P((struct ie_softc *, caddr_t, u_int));
--- 329,333 ----
void ieattach __P((struct device *, struct device *, void *));
int sl_probe __P((struct ie_softc *, struct isa_attach_args *));
! int el_probe __P((struct ie_softc *, struct isa_attach_args *, int));
int ee16_probe __P((struct ie_softc *, struct isa_attach_args *));
int check_ie_present __P((struct ie_softc *, caddr_t, u_int));
***************
*** 389,396 ****
struct ie_softc *sc = match;
struct isa_attach_args *ia = aux;
if (sl_probe(sc, ia))
return 1;
! if (el_probe(sc, ia))
return 1;
if (ee16_probe(sc, ia))
--- 404,439 ----
struct ie_softc *sc = match;
struct isa_attach_args *ia = aux;
+ int bus = parent->dv_unit;
+ struct ie_isa_done_probe *er;
+ int bus_probed = 0;
+
+ if (ie_isa_probes_initialized == 0) {
+ LIST_INIT(&ie_isa_all_probes);
+ ie_isa_probes_initialized = 1;
+ }
+
+ /*
+ * Check if we're already probed this bus, for the benefit of the
+ * 3Com cards.
+ */
+ for (er = ie_isa_all_probes.lh_first; er != NULL;
+ er = er->er_link.le_next)
+ if (er->er_bus == parent->dv_unit)
+ bus_probed = 1;
+
+ /*
+ * Mark this bus so we know if we've probed it next time through
+ */
+ er = (struct ie_isa_done_probe *)
+ malloc(sizeof(struct ie_isa_done_probe), M_DEVBUF, M_NOWAIT);
+ if (er == NULL)
+ panic("ie_probe: can't allocate state storage");
+
+ er->er_bus = bus;
+ LIST_INSERT_HEAD(&ie_isa_all_probes, er, er_link);
if (sl_probe(sc, ia))
return 1;
! if (el_probe(sc, ia, bus_probed))
return 1;
if (ee16_probe(sc, ia))
***************
*** 467,473 ****
int
! el_probe(sc, ia)
struct ie_softc *sc;
struct isa_attach_args *ia;
{
bus_space_tag_t iot = ia->ia_iot;
--- 510,517 ----
int
! el_probe(sc, ia, bus_probed)
struct ie_softc *sc;
struct isa_attach_args *ia;
+ int bus_probed;
{
bus_space_tag_t iot = ia->ia_iot;
***************
*** 483,502 ****
sc->chan_attn = el_chan_attn;
! /*
! * Map the Etherlink ID port for the probe sequence.
! */
! if (bus_space_map(iot, ELINK_ID_PORT, 1, 0, &ioh)) {
! printf("3c507 probe: can't map Etherlink ID port\n");
! return 0;
! }
! /*
! * Reset and put card in CONFIG state without changing address.
! * XXX Indirect brokenness here!
! */
! elink_reset(iot, ioh, sc->sc_dev.dv_parent->dv_unit);
! elink_idseq(iot, ioh, ELINK_507_POLY);
! elink_idseq(iot, ioh, ELINK_507_POLY);
! outb(ELINK_ID_PORT, 0xff);
/* Check for 3COM signature before proceeding. */
--- 527,548 ----
sc->chan_attn = el_chan_attn;
! if (!bus_probed) {
! /*
! * Map the Etherlink ID port for the probe sequence.
! */
! if (bus_space_map(iot, ELINK_ID_PORT, 1, 0, &ioh)) {
! printf("3c507 probe: can't map Etherlink ID port\n");
! return 0;
! }
! /*
! * Reset and put card in CONFIG state without changing address.
! * XXX Indirect brokenness here!
! */
! elink_reset(iot, ioh, sc->sc_dev.dv_parent->dv_unit);
! elink_idseq(iot, ioh, ELINK_507_POLY);
! elink_idseq(iot, ioh, ELINK_507_POLY);
! outb(ELINK_ID_PORT, 0xff);
! }
/* Check for 3COM signature before proceeding. */
***************
*** 514,520 ****
/* Go to RUN state. */
! outb(ELINK_ID_PORT, 0x00);
! elink_idseq(iot, ioh, ELINK_507_POLY);
! outb(ELINK_ID_PORT, 0x00);
/* Set bank 2 for version info and read BCD version byte. */
--- 560,568 ----
/* Go to RUN state. */
! if (!bus_probed) {
! outb(ELINK_ID_PORT, 0x00);
! elink_idseq(iot, ioh, ELINK_507_POLY);
! outb(ELINK_ID_PORT, 0x00);
! }
/* Set bank 2 for version info and read BCD version byte. */
***************
*** 579,583 ****
out:
! bus_space_unmap(iot, ioh, 1);
return rval;
}
--- 627,632 ----
out:
! if (!bus_probed)
! bus_space_unmap(iot, ioh, 1);
return rval;
}
>Audit-Trail:
>Unformatted: