diff options
author | marius <marius@FreeBSD.org> | 2007-01-20 10:47:16 +0000 |
---|---|---|
committer | marius <marius@FreeBSD.org> | 2007-01-20 10:47:16 +0000 |
commit | a31f50a3fbb019e8bef333536641691ebce78066 (patch) | |
tree | 8606f79689e4024c144fa70d49e3b09decc1d48d /sys/dev/le | |
parent | 613c7e2883fd4fbbdd40df85bdb9b599815510bf (diff) | |
download | FreeBSD-src-a31f50a3fbb019e8bef333536641691ebce78066.zip FreeBSD-src-a31f50a3fbb019e8bef333536641691ebce78066.tar.gz |
For setting the port PCnet chips must be powered down or stopped and
unlike documented may not take effect without an initialization. So
don't invoke (*sc_mediachange) directly in lance_mediachange() but
go through lance_init_locked(). It's suboptimal to impose this for
all chips but given that besides the affected PCI bus front-end the
only other front-end which supports media selection is and likely
ever will be the 'ledma' front-end I see not enough reason to break
the in-driver API for this (though one could argue both ways here).
Diffstat (limited to 'sys/dev/le')
-rw-r--r-- | sys/dev/le/lance.c | 22 |
1 files changed, 15 insertions, 7 deletions
diff --git a/sys/dev/le/lance.c b/sys/dev/le/lance.c index 3257637..68673a9 100644 --- a/sys/dev/le/lance.c +++ b/sys/dev/le/lance.c @@ -299,6 +299,10 @@ lance_init_locked(struct lance_softc *sc) /* Set the correct byte swapping mode, etc. */ (*sc->sc_wrcsr)(sc, LE_CSR3, sc->sc_conf3); + /* Set the current media. This may require the chip to be stopped. */ + if (sc->sc_mediachange) + (void)(*sc->sc_mediachange)(sc); + /* * Update our private copy of the Ethernet address. * We NEED the copy so we can ensure its alignment! @@ -322,10 +326,6 @@ lance_init_locked(struct lance_softc *sc) if ((*sc->sc_rdcsr)(sc, LE_CSR0) & LE_C0_IDON) break; - /* Set the current media. */ - if (sc->sc_mediachange) - (void)(*sc->sc_mediachange)(sc); - if ((*sc->sc_rdcsr)(sc, LE_CSR0) & LE_C0_IDON) { /* Start the LANCE. */ (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA | LE_C0_STRT); @@ -460,13 +460,21 @@ static int lance_mediachange(struct ifnet *ifp) { struct lance_softc *sc = ifp->if_softc; - int error; if (sc->sc_mediachange) { + /* + * For setting the port in LE_CSR15 the PCnet chips must + * be powered down or stopped and unlike documented may + * not take effect without an initialization. So don't + * invoke (*sc_mediachange) directly here but go through + * lance_init_locked(). + */ LE_LOCK(sc); - error = (*sc->sc_mediachange)(sc); + lance_stop(sc); + lance_init_locked(sc); + if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) + (*sc->sc_start_locked)(sc); LE_UNLOCK(sc); - return (error); } return (0); } |