Index: sys/dev/stge/if_stge.c =================================================================== --- sys/dev/stge/if_stge.c (revision 226842) +++ sys/dev/stge/if_stge.c (working copy) @@ -156,7 +156,6 @@ static void stge_set_filter(struct stge_softc *); static void stge_set_multi(struct stge_softc *); -static void stge_link_task(void *, int); static void stge_intr(void *); static __inline int stge_tx_error(struct stge_softc *); static void stge_txeof(struct stge_softc *); @@ -175,6 +174,7 @@ static int stge_miibus_writereg(device_t, int, int, int); static void stge_miibus_statchg(device_t); static int stge_mediachange(struct ifnet *); +static int stge_mediachange_locked(struct ifnet *); static void stge_mediastatus(struct ifnet *, struct ifmediareq *); static void stge_dmamap_cb(void *, bus_dma_segment_t *, int, int); @@ -421,18 +421,14 @@ if (reg == STGE_PhyCtrl) { /* XXX allow ip1000phy read STGE_PhyCtrl register. */ - STGE_MII_LOCK(sc); error = CSR_READ_1(sc, STGE_PhyCtrl); - STGE_MII_UNLOCK(sc); return (error); } bzero(&frame, sizeof(frame)); frame.mii_phyaddr = phy; frame.mii_regaddr = reg; - STGE_MII_LOCK(sc); error = stge_mii_readreg(sc, &frame); - STGE_MII_UNLOCK(sc); if (error != 0) { /* Don't show errors for PHY probe request */ @@ -462,9 +458,7 @@ frame.mii_regaddr = reg; frame.mii_data = val; - STGE_MII_LOCK(sc); error = stge_mii_writereg(sc, &frame); - STGE_MII_UNLOCK(sc); if (error != 0) device_printf(sc->sc_dev, "phy write fail\n"); @@ -480,9 +474,62 @@ stge_miibus_statchg(device_t dev) { struct stge_softc *sc; + struct mii_data *mii; + struct ifnet *ifp; + uint32_t v, ac; + int i; sc = device_get_softc(dev); - taskqueue_enqueue(taskqueue_swi, &sc->sc_link_task); + mii = device_get_softc(sc->sc_miibus); + ifp = sc->sc_ifp; + if (mii == NULL || ifp == NULL || + (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) + return; + + sc->sc_link = 0; + if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == + (IFM_ACTIVE | IFM_AVALID)) { + switch (IFM_SUBTYPE(mii->mii_media_active)) { + case IFM_10_T: + case IFM_100_TX: + case IFM_1000_T: + sc->sc_link = 1; + default: + break; + } + } + + if (sc->sc_link == 0) + return; + + sc->sc_MACCtrl = 0; + if (((mii->mii_media_active & IFM_GMASK) & IFM_FDX) != 0) + sc->sc_MACCtrl |= MC_DuplexSelect; + if (((mii->mii_media_active & IFM_GMASK) & IFM_ETH_RXPAUSE) != 0) + sc->sc_MACCtrl |= MC_RxFlowControlEnable; + if (((mii->mii_media_active & IFM_GMASK) & IFM_ETH_TXPAUSE) != 0) + sc->sc_MACCtrl |= MC_TxFlowControlEnable; + /* + * Update STGE_MACCtrl register depending on link status. + * (duplex, flow control etc) + */ + v = ac = CSR_READ_4(sc, STGE_MACCtrl) & MC_MASK; + v &= ~(MC_DuplexSelect|MC_RxFlowControlEnable|MC_TxFlowControlEnable); + v |= sc->sc_MACCtrl; + CSR_WRITE_4(sc, STGE_MACCtrl, v); + if (((ac ^ sc->sc_MACCtrl) & MC_DuplexSelect) != 0) { + /* Duplex setting changed, reset Tx/Rx functions. */ + ac = CSR_READ_4(sc, STGE_AsicCtrl); + ac |= AC_TxReset | AC_RxReset; + CSR_WRITE_4(sc, STGE_AsicCtrl, ac); + for (i = 0; i < STGE_TIMEOUT; i++) { + DELAY(100); + if ((CSR_READ_4(sc, STGE_AsicCtrl) & AC_ResetBusy) == 0) + break; + } + if (i == STGE_TIMEOUT) + device_printf(sc->sc_dev, "reset failed to complete\n"); + } } /* @@ -497,11 +544,17 @@ struct mii_data *mii; sc = ifp->if_softc; + STGE_LOCK(sc); + if ((ifp->if_flags & IFF_UP) == 0) { + STGE_UNLOCK(sc); + return; + } mii = device_get_softc(sc->sc_miibus); mii_pollstat(mii); ifmr->ifm_status = mii->mii_media_status; ifmr->ifm_active = mii->mii_media_active; + STGE_UNLOCK(sc); } /* @@ -513,13 +566,28 @@ stge_mediachange(struct ifnet *ifp) { struct stge_softc *sc; + int error; + + sc = ifp->if_softc; + STGE_LOCK(sc); + error = stge_mediachange_locked(ifp); + STGE_UNLOCK(sc); + + return (error); +} + +static int +stge_mediachange_locked(struct ifnet *ifp) +{ + struct stge_softc *sc; struct mii_data *mii; + struct mii_softc *miisc; sc = ifp->if_softc; mii = device_get_softc(sc->sc_miibus); - mii_mediachg(mii); - - return (0); + LIST_FOREACH(miisc, &mii->mii_phys, mii_list) + mii_phy_reset(miisc); + return (mii_mediachg(mii)); } static int @@ -593,9 +661,7 @@ mtx_init(&sc->sc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, MTX_DEF); - mtx_init(&sc->sc_mii_mtx, "stge_mii_mutex", NULL, MTX_DEF); callout_init_mtx(&sc->sc_tick_ch, &sc->sc_mtx, 0); - TASK_INIT(&sc->sc_link_task, 0, stge_link_task, sc); /* * Map the device. @@ -723,7 +789,6 @@ ifp->if_ioctl = stge_ioctl; ifp->if_start = stge_start; ifp->if_init = stge_init; - ifp->if_mtu = ETHERMTU; ifp->if_snd.ifq_drv_maxlen = STGE_TX_RING_CNT - 1; IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen); IFQ_SET_READY(&ifp->if_snd); @@ -827,7 +892,6 @@ stge_stop(sc); STGE_UNLOCK(sc); callout_drain(&sc->sc_tick_ch); - taskqueue_drain(taskqueue_swi, &sc->sc_link_task); ether_ifdetach(ifp); } @@ -849,7 +913,6 @@ } bus_release_resources(dev, sc->sc_spec, sc->sc_res); - mtx_destroy(&sc->sc_mii_mtx); mtx_destroy(&sc->sc_mtx); return (0); @@ -1510,55 +1573,6 @@ return (error); } -static void -stge_link_task(void *arg, int pending) -{ - struct stge_softc *sc; - struct mii_data *mii; - uint32_t v, ac; - int i; - - sc = (struct stge_softc *)arg; - STGE_LOCK(sc); - - mii = device_get_softc(sc->sc_miibus); - if (mii->mii_media_status & IFM_ACTIVE) { - if (IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) - sc->sc_link = 1; - } else - sc->sc_link = 0; - - sc->sc_MACCtrl = 0; - if (((mii->mii_media_active & IFM_GMASK) & IFM_FDX) != 0) - sc->sc_MACCtrl |= MC_DuplexSelect; - if (((mii->mii_media_active & IFM_GMASK) & IFM_ETH_RXPAUSE) != 0) - sc->sc_MACCtrl |= MC_RxFlowControlEnable; - if (((mii->mii_media_active & IFM_GMASK) & IFM_ETH_TXPAUSE) != 0) - sc->sc_MACCtrl |= MC_TxFlowControlEnable; - /* - * Update STGE_MACCtrl register depending on link status. - * (duplex, flow control etc) - */ - v = ac = CSR_READ_4(sc, STGE_MACCtrl) & MC_MASK; - v &= ~(MC_DuplexSelect|MC_RxFlowControlEnable|MC_TxFlowControlEnable); - v |= sc->sc_MACCtrl; - CSR_WRITE_4(sc, STGE_MACCtrl, v); - if (((ac ^ sc->sc_MACCtrl) & MC_DuplexSelect) != 0) { - /* Duplex setting changed, reset Tx/Rx functions. */ - ac = CSR_READ_4(sc, STGE_AsicCtrl); - ac |= AC_TxReset | AC_RxReset; - CSR_WRITE_4(sc, STGE_AsicCtrl, ac); - for (i = 0; i < STGE_TIMEOUT; i++) { - DELAY(100); - if ((CSR_READ_4(sc, STGE_AsicCtrl) & AC_ResetBusy) == 0) - break; - } - if (i == STGE_TIMEOUT) - device_printf(sc->sc_dev, "reset failed to complete\n"); - } - STGE_UNLOCK(sc); -} - static __inline int stge_tx_error(struct stge_softc *sc) { @@ -2304,13 +2318,7 @@ stge_start_tx(sc); stge_start_rx(sc); - sc->sc_link = 0; /* - * Set the current media. - */ - mii_mediachg(mii); - - /* * Start the one second MII clock. */ callout_reset(&sc->sc_tick_ch, hz, stge_tick, sc); @@ -2321,6 +2329,12 @@ ifp->if_drv_flags |= IFF_DRV_RUNNING; ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + sc->sc_link = 0; + /* + * Set the current media. + */ + stge_mediachange_locked(ifp); + out: if (error != 0) device_printf(sc->sc_dev, "interface not running\n"); Index: sys/dev/stge/if_stgereg.h =================================================================== --- sys/dev/stge/if_stgereg.h (revision 226842) +++ sys/dev/stge/if_stgereg.h (working copy) @@ -662,16 +662,12 @@ int sc_watchdog_timer; int sc_link; - struct task sc_link_task; - struct mtx sc_mii_mtx; /* MII mutex */ struct mtx sc_mtx; }; #define STGE_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) #define STGE_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) #define STGE_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->sc_mtx, MA_OWNED) -#define STGE_MII_LOCK(_sc) mtx_lock(&(_sc)->sc_mii_mtx) -#define STGE_MII_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mii_mtx) #define STGE_MAXERR 5