diff options
author | oleg <oleg@FreeBSD.org> | 2006-08-24 14:41:16 +0000 |
---|---|---|
committer | oleg <oleg@FreeBSD.org> | 2006-08-24 14:41:16 +0000 |
commit | 6a84fb6ac0714a5581271822053eb301f43e76e2 (patch) | |
tree | 0b02fc5c4e61afeb79be4846fce6bb19ce41b5b7 /sys/dev/bge | |
parent | 9db068b977aea7bd4da4bed4946186746814284a (diff) | |
download | FreeBSD-src-6a84fb6ac0714a5581271822053eb301f43e76e2.zip FreeBSD-src-6a84fb6ac0714a5581271822053eb301f43e76e2.tar.gz |
Properly lock ifmedia callbacks. This should prevent concurrent access to PHY.
Following issues should be resolved:
- random watchdog timeouts (caused by concurrent phy access)
- some link state issues
- non working TX if media type was set explicitly
PR: kern/98738
Approved by: glebius (mentor)
MFC after: 2 weeks
Diffstat (limited to 'sys/dev/bge')
-rw-r--r-- | sys/dev/bge/if_bge.c | 29 |
1 files changed, 24 insertions, 5 deletions
diff --git a/sys/dev/bge/if_bge.c b/sys/dev/bge/if_bge.c index 5931a35..0d00770 100644 --- a/sys/dev/bge/if_bge.c +++ b/sys/dev/bge/if_bge.c @@ -341,6 +341,7 @@ static void bge_init(void *); static void bge_stop(struct bge_softc *); static void bge_watchdog(struct ifnet *); static void bge_shutdown(device_t); +static int bge_ifmedia_upd_locked(struct ifnet *); static int bge_ifmedia_upd(struct ifnet *); static void bge_ifmedia_sts(struct ifnet *, struct ifmediareq *); @@ -3206,7 +3207,7 @@ bge_init_locked(struct bge_softc *sc) CSR_WRITE_4(sc, BGE_MBX_IRQ0_LO, 0); } - bge_ifmedia_upd(ifp); + bge_ifmedia_upd_locked(ifp); ifp->if_drv_flags |= IFF_DRV_RUNNING; ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; @@ -3230,11 +3231,25 @@ bge_init(void *xsc) static int bge_ifmedia_upd(struct ifnet *ifp) { - struct bge_softc *sc; + struct bge_softc *sc = ifp->if_softc; + int res; + + BGE_LOCK(sc); + res = bge_ifmedia_upd_locked(ifp); + BGE_UNLOCK(sc); + + return (res); +} + +static int +bge_ifmedia_upd_locked(struct ifnet *ifp) +{ + struct bge_softc *sc = ifp->if_softc; struct mii_data *mii; struct ifmedia *ifm; - sc = ifp->if_softc; + BGE_LOCK_ASSERT(sc); + ifm = &sc->bge_ifmedia; /* If this is a 1000baseX NIC, enable the TBI port. */ @@ -3296,10 +3311,10 @@ bge_ifmedia_upd(struct ifnet *ifp) static void bge_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) { - struct bge_softc *sc; + struct bge_softc *sc = ifp->if_softc; struct mii_data *mii; - sc = ifp->if_softc; + BGE_LOCK(sc); if (sc->bge_flags & BGE_FLAG_TBI) { ifmr->ifm_status = IFM_AVALID; @@ -3309,6 +3324,7 @@ bge_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) ifmr->ifm_status |= IFM_ACTIVE; else { ifmr->ifm_active |= IFM_NONE; + BGE_UNLOCK(sc); return; } ifmr->ifm_active |= IFM_1000_SX; @@ -3316,6 +3332,7 @@ bge_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) ifmr->ifm_active |= IFM_HDX; else ifmr->ifm_active |= IFM_FDX; + BGE_UNLOCK(sc); return; } @@ -3323,6 +3340,8 @@ bge_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) mii_pollstat(mii); ifmr->ifm_active = mii->mii_media_active; ifmr->ifm_status = mii->mii_media_status; + + BGE_UNLOCK(sc); } static int |