- Encapsulate the EEPROM reading code into ep_read_eeprom(), and use

the correct "read eeprom" opcode on the RoadRunner (which has a larger
  EEPROM, and thus needs a different opcode to make room for the larger
  offsets).
- Reset and enable the MII before probing for PHYs, and reset and enable
  the MII in epinit().
- Be more conservative when resetting the interface after a transmit error.

Based on PR #8331, from Ryoji KATO.

Closer on 3c574, probably will work fine with the 3CCFEM556BI (which
won't have an older rev TDK Semi PHY, and which was tested by the author
of the PR).
This commit is contained in:
thorpej 1999-10-11 17:48:20 +00:00
parent 7871f8c56d
commit 5082673b91

View File

@ -1,4 +1,4 @@
/* $NetBSD: elink3.c,v 1.58 1999/05/18 23:52:55 thorpej Exp $ */
/* $NetBSD: elink3.c,v 1.59 1999/10/11 17:48:20 thorpej Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -213,6 +213,7 @@ struct mbuf *epget __P((struct ep_softc *, int));
void epmbuffill __P((void *));
void epmbufempty __P((struct ep_softc *));
void epsetfilter __P((struct ep_softc *));
void ep_roadrunner_mii_enable __P((struct ep_softc *));
void epsetmedia __P((struct ep_softc *));
/* ifmedia callbacks */
@ -233,6 +234,7 @@ void ep_mii_sync __P((struct ep_softc *));
void ep_mii_sendbits __P((struct ep_softc *, u_int32_t, int));
static int epbusyeeprom __P((struct ep_softc *));
u_int16_t ep_read_eeprom __P((struct ep_softc *, u_int16_t));
static inline void ep_reset_cmd __P((struct ep_softc *sc,
u_int cmd, u_int arg));
static inline void ep_finish_reset __P((bus_space_tag_t, bus_space_handle_t));
@ -353,17 +355,10 @@ epconfig(sc, chipset, enaddr)
if (enaddr == NULL) {
/*
* Read the station address from the eeprom
* Read the station address from the eeprom.
*/
for (i = 0; i < 3; i++) {
u_int16_t x;
if (epbusyeeprom(sc))
return; /* XXX why is eeprom busy? */
bus_space_write_2(iot, ioh, ELINK_W0_EEPROM_COMMAND,
READ_EEPROM | i);
if (epbusyeeprom(sc))
return; /* XXX why is eeprom busy? */
x = bus_space_read_2(iot, ioh, ELINK_W0_EEPROM_DATA);
u_int16_t x = ep_read_eeprom(sc, i);
myla[(i << 1)] = x >> 8;
myla[(i << 1) + 1] = x;
}
@ -459,8 +454,14 @@ epconfig(sc, chipset, enaddr)
* Now, determine which media we have.
*/
switch (sc->ep_chipset) {
case ELINK_CHIPSET_BOOMERANG:
case ELINK_CHIPSET_ROADRUNNER:
if (sc->ep_flags & ELINK_FLAGS_MII) {
ep_roadrunner_mii_enable(sc);
GO_WINDOW(0);
}
/* FALLTHROUGH */
case ELINK_CHIPSET_BOOMERANG:
/*
* If the device has MII, probe it. We won't be using
* any `native' media in this case, only PHYs. If
@ -591,13 +592,7 @@ ep_509_probemedia(sc)
/*
* Get the default media from the EEPROM.
*/
if (epbusyeeprom(sc))
return; /* XXX why is eeprom busy? */
bus_space_write_2(iot, ioh, ELINK_W0_EEPROM_COMMAND,
READ_EEPROM | EEPROM_ADDR_CFG);
if (epbusyeeprom(sc))
return; /* XXX why is eeprom busy? */
port = bus_space_read_2(iot, ioh, ELINK_W0_EEPROM_DATA) >> 14;
port = ep_read_eeprom(sc, EEPROM_ADDR_CFG) >> 14;
#define PRINT(s) printf("%s%s", sep, s); sep = ", "
@ -796,6 +791,11 @@ epinit(sc)
bus_space_write_2(iot, ioh, ELINK_W1_RUNNER_WRCTL, 0);
bus_space_write_2(iot, ioh, ELINK_W1_RUNNER_RDCTL, 0);
if (sc->ep_flags & ELINK_FLAGS_MII) {
ep_roadrunner_mii_enable(sc);
GO_WINDOW(1);
}
}
/* Enable interrupts. */
@ -864,6 +864,30 @@ ep_media_change(ifp)
return (0);
}
/*
* Reset and enable the MII on the RoadRunner.
*/
void
ep_roadrunner_mii_enable(sc)
struct ep_softc *sc;
{
bus_space_tag_t iot = sc->sc_iot;
bus_space_handle_t ioh = sc->sc_ioh;
GO_WINDOW(3);
bus_space_write_2(iot, ioh, ELINK_W3_RESET_OPTIONS,
ELINK_PCI_100BASE_MII|ELINK_RUNNER_ENABLE_MII);
delay(1000);
bus_space_write_2(iot, ioh, ELINK_W3_RESET_OPTIONS,
ELINK_PCI_100BASE_MII|ELINK_RUNNER_MII_RESET|
ELINK_RUNNER_ENABLE_MII);
ep_reset_cmd(sc, ELINK_COMMAND, TX_RESET);
ep_reset_cmd(sc, ELINK_COMMAND, RX_RESET);
delay(1000);
bus_space_write_2(iot, ioh, ELINK_W3_RESET_OPTIONS,
ELINK_PCI_100BASE_MII|ELINK_RUNNER_ENABLE_MII);
}
/*
* Set the card to use the specified media.
*/
@ -891,6 +915,7 @@ epsetmedia(sc)
GO_WINDOW(3);
#if 0
if (sc->ep_chipset == ELINK_CHIPSET_ROADRUNNER) {
int resopt;
@ -899,6 +924,7 @@ epsetmedia(sc)
bus_space_write_2(iot, ioh,
ELINK_W3_RESET_OPTIONS, resopt|ELINK_RUNNER_ENABLE_MII);
}
#endif
config0 = (u_int)bus_space_read_2(iot, ioh,
ELINK_W3_INTERNAL_CONFIG);
@ -1312,7 +1338,11 @@ eptxstat(sc)
if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG)
printf("%s: jabber (%x)\n",
sc->sc_dev.dv_xname, i);
#if 1
ep_reset_cmd(sc, ELINK_COMMAND, TX_RESET);
#else
epreset(sc);
#endif
} else if (i & TXS_UNDERRUN) {
++sc->sc_ethercom.ec_if.if_oerrors;
if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG)
@ -1323,7 +1353,11 @@ eptxstat(sc)
sc->tx_start_thresh = min(ETHER_MAX_LEN,
sc->tx_start_thresh + 20);
sc->tx_succ_ok = 0;
#if 1
ep_reset_cmd(sc, ELINK_COMMAND, TX_RESET);
#else
epreset(sc);
#endif
} else if (i & TXS_MAX_COLLISION) {
++sc->sc_ethercom.ec_if.if_collisions;
bus_space_write_2(iot, ioh, ELINK_COMMAND, TX_ENABLE);
@ -1404,7 +1438,11 @@ epintr(arg)
if (status & S_CARD_FAILURE) {
printf("%s: adapter failure (%x)\n",
sc->sc_dev.dv_xname, status);
#if 1
epinit(sc);
#else
epreset(sc);
#endif
return (1);
}
if (status & S_TX_COMPLETE) {
@ -1953,6 +1991,31 @@ epbusyeeprom(sc)
return (0);
}
u_int16_t
ep_read_eeprom(sc, offset)
struct ep_softc *sc;
u_int16_t offset;
{
u_int16_t readcmd;
/*
* RoadRunner has a larger EEPROM, so a different read command
* is required.
*/
if (sc->ep_chipset == ELINK_CHIPSET_ROADRUNNER)
readcmd = READ_EEPROM_RR;
else
readcmd = READ_EEPROM;
if (epbusyeeprom(sc))
return (0); /* XXX why is eeprom busy? */
bus_space_write_2(sc->sc_iot, sc->sc_ioh, ELINK_W0_EEPROM_COMMAND,
readcmd | offset);
if (epbusyeeprom(sc))
return (0); /* XXX why is eeprom busy? */
return (bus_space_read_2(sc->sc_iot, sc->sc_ioh, ELINK_W0_EEPROM_DATA));
}
void
epmbuffill(v)
void *v;