Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 26 May 2008 19:00:00 GMT
From:      Sam Leffler <sam@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 142310 for review
Message-ID:  <200805261900.m4QJ00Uu080143@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=142310

Change 142310 by sam@sam_ebb on 2008/05/26 18:59:00

	Fix suspend/resume; need to reload the h/w key cache on
	resume as it's clobbered on at least some systems.  For
	station mode we simulate a beacon miss to get the upper
	layers sync'd up; for other configs we must stop+start
	all the vaps so they go through the state machine.
	
	Needs more thought; some of this work likely belongs in
	the 802.11 layer and we may want to revise the key struct
	to hold the mac address passed in with ioctls.

Affected files ...

.. //depot/projects/vap/sys/dev/ath/if_ath.c#74 edit
.. //depot/projects/vap/sys/dev/ath/if_athvar.h#25 edit

Differences ...

==== //depot/projects/vap/sys/dev/ath/if_ath.c#74 (text+ko) ====

@@ -138,6 +138,9 @@
 static void	ath_rxorn_proc(void *, int);
 static void	ath_bmiss_vap(struct ieee80211vap *);
 static void	ath_bmiss_proc(void *, int);
+static int	ath_keyset(struct ath_softc *, const struct ieee80211_key *,
+			const u_int8_t [IEEE80211_ADDR_LEN],
+			struct ieee80211_node *);
 static int	ath_key_alloc(struct ieee80211vap *,
 			const struct ieee80211_key *,
 			ieee80211_keyix *, ieee80211_keyix *);
@@ -1052,29 +1055,100 @@
 ath_suspend(struct ath_softc *sc)
 {
 	struct ifnet *ifp = sc->sc_ifp;
+	struct ieee80211com *ic = ifp->if_l2com;
 
 	DPRINTF(sc, ATH_DEBUG_ANY, "%s: if_flags %x\n",
 		__func__, ifp->if_flags);
 
-	ath_stop(ifp);
+	sc->sc_resume_up = (ifp->if_flags & IFF_UP) != 0;
+	if (ic->ic_opmode == IEEE80211_M_STA)
+		ath_stop(ifp);
+	else
+		ieee80211_stop_all(ic);
+}
+
+static void
+reset_ucastkey(void *arg, struct ieee80211_node *ni)
+{
+	struct ath_softc *sc = arg;
+	struct ieee80211vap *vap = ni->ni_vap;
+	struct ieee80211_key *k;
+
+	if (vap->iv_state != IEEE80211_S_RUN)
+		return;
+	k = &ni->ni_ucastkey;
+	if (k->wk_keyix != IEEE80211_KEYIX_NONE)
+		ath_keyset(sc, k, ni->ni_macaddr, vap->iv_bss);
+}
+
+/*
+ * Reset the key cache since some parts do not reset the
+ * contents on resume.  First we clear all entries, then
+ * re-load keys that the 802.11 layer assumes are setup
+ * in h/w.
+ */
+static void
+ath_reset_keycache(struct ath_softc *sc)
+{
+	struct ifnet *ifp = sc->sc_ifp;
+	struct ieee80211com *ic = ifp->if_l2com;
+	struct ath_hal *ah = sc->sc_ah;
+	struct ieee80211vap *vap;
+	int i;
+
+	for (i = 0; i < sc->sc_keymax; i++)
+		ath_hal_keyreset(ah, i);
+	/*
+	 * Keys in the global key table of each vap.
+	 * NB: used only during resume so not locking
+	 *     the vap list should be safe
+	 */
+	TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
+		if (vap->iv_state != IEEE80211_S_RUN)
+			continue;
+		for (i = 0; i < IEEE80211_WEP_NKID; i++) {
+			const struct ieee80211_key *k = &vap->iv_nw_keys[i];
+			if (k->wk_keyix == IEEE80211_KEYIX_NONE)
+				continue;
+			/* XXX group keys need bcast addr, should be in key */
+			ath_keyset(sc, k, k->wk_flags & IEEE80211_KEY_GROUP ?
+			   ifp->if_broadcastaddr : vap->iv_myaddr, vap->iv_bss);
+		}
+	}
+	/*
+	 * Unicast keys.
+	 */
+	ieee80211_iterate_nodes(&ic->ic_sta, reset_ucastkey, sc);
 }
 
 void
 ath_resume(struct ath_softc *sc)
 {
 	struct ifnet *ifp = sc->sc_ifp;
+	struct ieee80211com *ic = ifp->if_l2com;
+	struct ath_hal *ah = sc->sc_ah;
+	HAL_STATUS status;
 
 	DPRINTF(sc, ATH_DEBUG_ANY, "%s: if_flags %x\n",
 		__func__, ifp->if_flags);
 
-	if (ifp->if_flags & IFF_UP) {
-		ath_init(sc);
-		if (ifp->if_drv_flags & IFF_DRV_RUNNING)
-			ath_start(ifp);
+	/*
+	 * NB: the only reliable way to get the chip out of power
+	 *     down and ready for reload of the keycache appears
+	 *     to be a reset (e.g. just waking the chip doesn't work).
+	 */
+	ath_hal_reset(ah, sc->sc_opmode, &sc->sc_curchan, AH_FALSE, &status);
+	ath_reset_keycache(sc);
+	if (sc->sc_resume_up) {
+		if (ic->ic_opmode == IEEE80211_M_STA) {
+			ath_init(sc);
+			ieee80211_beacon_miss(ic);
+		} else
+			ieee80211_start_all(ic);
 	}
 	if (sc->sc_softled) {
-		ath_hal_gpioCfgOutput(sc->sc_ah, sc->sc_ledpin);
-		ath_hal_gpioset(sc->sc_ah, sc->sc_ledpin, !sc->sc_ledon);
+		ath_hal_gpioCfgOutput(ah, sc->sc_ledpin);
+		ath_hal_gpioset(ah, sc->sc_ledpin, !sc->sc_ledon);
 	}
 }
 

==== //depot/projects/vap/sys/dev/ath/if_athvar.h#25 (text+ko) ====

@@ -245,7 +245,8 @@
 				sc_beacons  : 1,/* beacons running */
 				sc_swbmiss  : 1,/* sta mode using sw bmiss */
 				sc_stagbeacons:1,/* use staggered beacons */
-				sc_wmetkipmic:1;/* can do WME+TKIP MIC */
+				sc_wmetkipmic:1,/* can do WME+TKIP MIC */
+				sc_resume_up: 1;/* on resume, start all vaps */
 	uint32_t		sc_eerd;	/* regdomain from EEPROM */
 	uint32_t		sc_eecc;	/* country code from EEPROM */
 						/* rate tables */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200805261900.m4QJ00Uu080143>