From 17792f45fb0e6b12c8b95342d861fc41e317abc0 Mon Sep 17 00:00:00 2001 From: Marius Strobl Date: Sat, 20 Jan 2007 10:47:16 +0000 Subject: [PATCH] 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). --- sys/dev/le/lance.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/sys/dev/le/lance.c b/sys/dev/le/lance.c index 32576373571..68673a9c5b0 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); }