diff options
author | adrian <adrian@FreeBSD.org> | 2014-05-05 08:12:21 +0000 |
---|---|---|
committer | adrian <adrian@FreeBSD.org> | 2014-05-05 08:12:21 +0000 |
commit | 7870802b3f95989eb00c58eaa73f940a9198307f (patch) | |
tree | 78d8875feb2b27f3fa4a503a99e364fca1582ec8 | |
parent | 7568a6fe4cb15d64f21b16acd889641c76ff8268 (diff) | |
download | FreeBSD-src-7870802b3f95989eb00c58eaa73f940a9198307f.zip FreeBSD-src-7870802b3f95989eb00c58eaa73f940a9198307f.tar.gz |
Break out the multicast programming into its own hardware specific
call, which assumes the hardware is awake.
Turn ath_update_mcast() into a routine that's only called from the
net80211 layer - and it forces the hardware awake first.
This fixes a LOR from the EDMA RX path which calls ath_mode_init()
with the RX lock held - the driver lock can't also be grabbed.
This path assumes that the ath_mode_init() callers all wake up
the NIC first.
Tested:
* AR9485, STA mode, powersave
-rw-r--r-- | sys/dev/ath/if_ath.c | 36 |
1 files changed, 30 insertions, 6 deletions
diff --git a/sys/dev/ath/if_ath.c b/sys/dev/ath/if_ath.c index ad8b0d9..d8b0a01 100644 --- a/sys/dev/ath/if_ath.c +++ b/sys/dev/ath/if_ath.c @@ -165,6 +165,7 @@ static void ath_bmiss_vap(struct ieee80211vap *); static void ath_bmiss_proc(void *, int); static void ath_key_update_begin(struct ieee80211vap *); static void ath_key_update_end(struct ieee80211vap *); +static void ath_update_mcast_hw(struct ath_softc *); static void ath_update_mcast(struct ifnet *); static void ath_update_promisc(struct ifnet *); static void ath_updateslot(struct ifnet *); @@ -3379,10 +3380,15 @@ ath_update_promisc(struct ifnet *ifp) DPRINTF(sc, ATH_DEBUG_MODE, "%s: RX filter 0x%x\n", __func__, rfilt); } +/* + * Driver-internal mcast update call. + * + * Assumes the hardware is already awake. + */ static void -ath_update_mcast(struct ifnet *ifp) +ath_update_mcast_hw(struct ath_softc *sc) { - struct ath_softc *sc = ifp->if_softc; + struct ifnet *ifp = sc->sc_ifp; u_int32_t mfilt[2]; /* calculate and install multicast filter */ @@ -3410,13 +3416,31 @@ ath_update_mcast(struct ifnet *ifp) if_maddr_runlock(ifp); } else mfilt[0] = mfilt[1] = ~0; + + ath_hal_setmcastfilter(sc->sc_ah, mfilt[0], mfilt[1]); + + DPRINTF(sc, ATH_DEBUG_MODE, "%s: MC filter %08x:%08x\n", + __func__, mfilt[0], mfilt[1]); +} + +/* + * Called from the net80211 layer - force the hardware + * awake before operating. + */ +static void +ath_update_mcast(struct ifnet *ifp) +{ + struct ath_softc *sc = ifp->if_softc; + ATH_LOCK(sc); ath_power_set_power_state(sc, HAL_PM_AWAKE); - ath_hal_setmcastfilter(sc->sc_ah, mfilt[0], mfilt[1]); + ATH_UNLOCK(sc); + + ath_update_mcast_hw(sc); + + ATH_LOCK(sc); ath_power_restore_power_state(sc); ATH_UNLOCK(sc); - DPRINTF(sc, ATH_DEBUG_MODE, "%s: MC filter %08x:%08x\n", - __func__, mfilt[0], mfilt[1]); } void @@ -3444,7 +3468,7 @@ ath_mode_init(struct ath_softc *sc) ath_hal_setmac(ah, IF_LLADDR(ifp)); /* calculate and install multicast filter */ - ath_update_mcast(ifp); + ath_update_mcast_hw(sc); } /* |