summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoradrian <adrian@FreeBSD.org>2014-05-05 08:12:21 +0000
committeradrian <adrian@FreeBSD.org>2014-05-05 08:12:21 +0000
commit7870802b3f95989eb00c58eaa73f940a9198307f (patch)
tree78d8875feb2b27f3fa4a503a99e364fca1582ec8
parent7568a6fe4cb15d64f21b16acd889641c76ff8268 (diff)
downloadFreeBSD-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.c36
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);
}
/*
OpenPOWER on IntegriCloud