Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 9 Jun 2007 20:01:07 GMT
From:      Andrew Thompson <thompsa@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 121291 for review
Message-ID:  <200706092001.l59K17Xq021397@repoman.freebsd.org>

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

Change 121291 by thompsa@thompsa_heff on 2007/06/09 20:00:59

	Track the firmware state. Some actions take several commands (assoc)
	or persist after the firmware acks the command (scan). If other
	commands get interleaved then the firmware will die.

Affected files ...

.. //depot/projects/wifi/sys/dev/iwi/if_iwi.c#46 edit
.. //depot/projects/wifi/sys/dev/iwi/if_iwivar.h#20 edit

Differences ...

==== //depot/projects/wifi/sys/dev/iwi/if_iwi.c#46 (text+ko) ====

@@ -978,7 +978,7 @@
 		    (sc->flags & IWI_FLAG_FW_INITED))
 			iwi_disassoc(ic);
 		if (ic->ic_state == IEEE80211_S_SCAN &&
-		    (sc->flags & IWI_FLAG_SCANNING))
+		    (sc->fw_state == IWI_FW_SCANNING))
 			ieee80211_cancel_scan(ic);
 		break;
 	case IEEE80211_S_ASSOC:
@@ -1389,7 +1389,7 @@
 		    ieee80211_ieee2mhz(chan->nchan, 0), chan->nchan));
 
 		/* Reset the timer, the scan is still going */
-		sc->sc_scan_timer = 3;
+		sc->sc_state_timer = 3;
 		break;
 
 	case IWI_NOTIF_TYPE_SCAN_COMPLETE:
@@ -1398,8 +1398,7 @@
 		DPRINTFN(2, ("Scan completed (%u, %u)\n", scan->nchan,
 		    scan->status));
 
-		sc->sc_scan_timer = 0;
-		sc->flags &= ~IWI_FLAG_SCANNING;
+		IWI_STATE_END(sc, IWI_FW_SCANNING);
 
 		if (scan->status == IWI_SCAN_COMPLETED)
 			ieee80211_scan_next(ic);
@@ -1419,6 +1418,7 @@
 		case IWI_AUTH_FAIL:
 			DPRINTFN(2, ("Authentication failed\n"));
 			sc->flags &= ~IWI_FLAG_ASSOCIATED;
+			IWI_STATE_END(sc, IWI_FW_ASSOCIATING);
 			/* XXX */
 			break;
 
@@ -1430,6 +1430,7 @@
 		case IWI_AUTH_SEQ1_FAIL:
 			DPRINTFN(2, ("Initial authentication handshake failed; "
 				"you probably need shared key\n"));
+			IWI_STATE_END(sc, IWI_FW_ASSOCIATING);
 			/* XXX retry shared key when in auto */
 			break;
 
@@ -1450,6 +1451,7 @@
 		case IWI_ASSOC_SUCCESS:
 			DPRINTFN(2, ("Association succeeded\n"));
 			sc->flags |= IWI_FLAG_ASSOCIATED;
+			IWI_STATE_END(sc, IWI_FW_ASSOCIATING);
 			iwi_checkforqos(sc,
 			    (const struct ieee80211_frame *)(assoc+1),
 			    le16toh(notif->len) - sizeof(*assoc));
@@ -1457,15 +1459,18 @@
 			break;
 
 		case IWI_ASSOC_INIT:
-			switch (ic->ic_state) {
-				case IEEE80211_S_ASSOC:
+			switch (sc->fw_state) {
+				case IWI_FW_ASSOCIATING:
 					DPRINTFN(2, ("Association failed\n"));
+					IWI_STATE_END(sc, IWI_FW_ASSOCIATING);
 					ieee80211_new_state(ic,
 					    IEEE80211_S_SCAN, -1);
 					break;
 
-				case IEEE80211_S_RUN:
-					DPRINTFN(2, ("Disassociated\n"));
+				case IWI_FW_DISASSOCIATING:
+					DPRINTFN(2, ("Dissassociated\n"));
+					IWI_STATE_END(sc,
+					    IWI_FW_DISASSOCIATING);
 					break;
 			}
 			sc->flags &= ~IWI_FLAG_ASSOCIATED;
@@ -1620,6 +1625,7 @@
 			taskqueue_enqueue(sc->sc_tq, &sc->sc_restarttask);
 
 		sc->flags &= ~IWI_FLAG_BUSY;
+		sc->sc_busy_timer = 0;
 		wakeup(sc);
 	}
 
@@ -1633,6 +1639,7 @@
 
 	if (r & IWI_INTR_CMD_DONE) {
 		sc->flags &= ~IWI_FLAG_BUSY;
+		sc->sc_busy_timer = 0;
 		wakeup(sc);
 	}
 
@@ -1672,6 +1679,7 @@
 		return EAGAIN;
 	}
 	sc->flags |= IWI_FLAG_BUSY;
+	sc->sc_busy_timer = 2;
 
 	desc = &sc->cmdq.desc[sc->cmdq.cur];
 
@@ -1992,13 +2000,20 @@
 				sc->sc_rfkill_timer = 2;
 		}
 	}
-	if (sc->sc_scan_timer > 0) {
-		if (--sc->sc_scan_timer == 0) {
-			if (sc->flags & IWI_FLAG_SCANNING) {
-				if_printf(ifp, "scan stuck\n");
+	if (sc->sc_state_timer > 0) {
+		if (--sc->sc_state_timer == 0) {
+			if_printf(ifp, "firmware stuck in state %d, resetting\n",
+			    sc->fw_state);
+			taskqueue_enqueue(sc->sc_tq, &sc->sc_restarttask);
+			if (sc->fw_state == IWI_FW_SCANNING)
 				ieee80211_cancel_scan(&sc->sc_ic);
-				taskqueue_enqueue(sc->sc_tq, &sc->sc_restarttask);
-			}
+			sc->sc_state_timer = 3;
+		}
+	}
+	if (sc->sc_busy_timer > 0) {
+		if (--sc->sc_busy_timer == 0) {
+			if_printf(ifp, "firmware command timeout, resetting\n");
+			taskqueue_enqueue(sc->sc_tq, &sc->sc_restarttask);
 		}
 	}
 
@@ -2696,7 +2711,7 @@
 	int error = 0;
 
 	IWI_LOCK_ASSERT(sc);
-	if (sc->flags & IWI_FLAG_SCANNING) {
+	if (sc->fw_state == IWI_FW_SCANNING) {
 		/*
 		 * This should not happen as we only trigger scan_next after
 		 * completion
@@ -2704,6 +2719,7 @@
 		DPRINTF(("%s: called too early - still scanning\n", __func__));
 		return (EBUSY);
 	}
+	IWI_STATE_BEGIN(sc, IWI_FW_SCANNING);
 
 	ic = &sc->sc_ic;
 	ss = ic->ic_scan;
@@ -2798,8 +2814,6 @@
 		} while (i < IWI_SCAN_CHANNELS);
 	}
 #endif
-	sc->flags |= IWI_FLAG_SCANNING;
-	sc->sc_scan_timer = 3;
 
 	return (iwi_cmd(sc, IWI_CMD_SCAN_EXT, &scan, sizeof scan));
 }
@@ -2830,7 +2844,13 @@
 	IWI_LOCK_DECL;
  
 	IWI_LOCK_ASSERT(sc);
-	
+
+	if (sc->flags & IWI_FLAG_ASSOCIATED) {
+		DPRINTF(("Already associated\n"));
+		return (-1);
+	}
+
+	IWI_STATE_BEGIN(sc, IWI_FW_ASSOCIATING);
 	error = 0;
 	if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
 		memset(&config, 0, sizeof config);
@@ -2967,9 +2987,10 @@
 	    le16toh(assoc->intval)));
 	error = iwi_cmd(sc, IWI_CMD_ASSOCIATE, assoc, sizeof *assoc);
 done:
-	IWI_UNLOCK(sc);
+	if (error)
+		IWI_STATE_END(sc, IWI_FW_ASSOCIATING);
 
-	return (error);	
+	return (error);
 }
 
 static int
@@ -2977,6 +2998,13 @@
 {
 	struct iwi_associate *assoc = &sc->assoc;
 
+	if ((sc->flags & IWI_FLAG_ASSOCIATED) == 0) {
+		DPRINTF(("Not associated\n"));
+		return (-1);
+	}
+
+	IWI_STATE_BEGIN(sc, IWI_FW_DISASSOCIATING);
+
 	if (quiet)
 		assoc->type = IWI_HC_DISASSOC_QUIET;
 	else
@@ -3069,20 +3097,19 @@
 	IWI_LOCK_DECL;
 
 	IWI_LOCK_ASSERT(sc);
-	if (sc->flags & IWI_FLAG_FW_LOADING) {
+	if (sc->fw_state == IWI_FW_LOADING) {
 		device_printf(sc->sc_dev, "%s: already loading\n", __func__);
 		return;		/* XXX: condvar? */
 	}
 
 	iwi_stop(sc);
+	IWI_STATE_BEGIN(sc, IWI_FW_LOADING);
 
 	if (iwi_reset(sc) != 0) {
 		device_printf(sc->sc_dev, "could not reset adapter\n");
 		goto fail;
 	}
 
-	sc->flags |= IWI_FLAG_FW_LOADING;
-
 	IWI_UNLOCK(sc);
 	if (iwi_get_firmware(sc)) {
 		IWI_LOCK(sc);
@@ -3171,11 +3198,11 @@
 	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
 	ifp->if_drv_flags |= IFF_DRV_RUNNING;
 
-	sc->flags &= ~IWI_FLAG_FW_LOADING;
+	IWI_STATE_END(sc, IWI_FW_LOADING);
 	return;
 
 fail:	ifp->if_flags &= ~IFF_UP;
-	sc->flags &= ~IWI_FLAG_FW_LOADING;
+	IWI_STATE_END(sc, IWI_FW_LOADING);
 	iwi_stop(sc);
 	iwi_put_firmware(sc);
 }
@@ -3210,8 +3237,11 @@
 
 	sc->sc_tx_timer = 0;
 	sc->sc_rfkill_timer = 0;
-	sc->sc_scan_timer = 0;
-	sc->flags &= ~(IWI_FLAG_BUSY | IWI_FLAG_SCANNING | IWI_FLAG_ASSOCIATED);
+	sc->sc_state_timer = 0;
+	sc->sc_busy_timer = 0;
+	sc->flags &= ~(IWI_FLAG_BUSY | IWI_FLAG_ASSOCIATED);
+	sc->fw_state = IWI_FW_IDLE;
+	wakeup(sc);
 
 	ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
 }
@@ -3522,10 +3552,13 @@
 	IWI_CMD_UNLOCK(sc);
 
 	IWI_LOCK(sc);
-	while  ((ic->ic_state !=  IEEE80211_S_INIT) && (sc->flags & IWI_FLAG_BUSY)) {
+	while  (sc->fw_state != IWI_FW_IDLE || (sc->flags & IWI_FLAG_BUSY)) {
 		msleep(sc, &sc->sc_mtx, 0, "iwicmd", hz/10);
 	}
 
+	if (!(sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING))
+		goto done;
+
 	switch (cmd) {
 	case IWI_ASSOC:
 		iwi_auth_and_assoc(sc);
@@ -3543,7 +3576,7 @@
 	case IWI_SCAN_END:
 		sc->flags &= ~IWI_FLAG_CHANNEL_SCAN;
 		/* NB: make sure we're still scanning */
-		if (sc->flags & IWI_FLAG_SCANNING)
+		if (sc->fw_state == IWI_FW_SCANNING)
 			iwi_cmd(sc, IWI_CMD_ABORT_SCAN, NULL, 0);
 		break;
 	case IWI_SCAN_CURCHAN:
@@ -3596,7 +3629,7 @@
 {
 	struct ifnet *ifp = ic->ic_ifp;
 	struct iwi_softc *sc = ifp->if_softc;
-	if (!(sc->flags & (IWI_FLAG_SCANNING | IWI_FLAG_CHANNEL_SCAN))) 
+	if (sc->fw_state == IWI_FW_IDLE)
 		iwi_setcurchan(sc, ic->ic_curchan->ic_ieee);
 }
 

==== //depot/projects/wifi/sys/dev/iwi/if_iwivar.h#20 (text+ko) ====

@@ -134,11 +134,15 @@
 
 	uint32_t		flags;
 #define IWI_FLAG_FW_INITED	(1 << 0)
-#define IWI_FLAG_SCANNING	(1 << 1)
-#define	IWI_FLAG_FW_LOADING	(1 << 2)
 #define	IWI_FLAG_BUSY		(1 << 3)	/* busy sending a command */
 #define	IWI_FLAG_ASSOCIATED	(1 << 4)	/* currently associated  */
 #define IWI_FLAG_CHANNEL_SCAN	(1 << 5)
+	uint32_t		fw_state;
+#define IWI_FW_IDLE		0
+#define IWI_FW_LOADING		1
+#define IWI_FW_ASSOCIATING	2
+#define IWI_FW_DISASSOCIATING	3
+#define IWI_FW_SCANNING		4
 	struct iwi_cmd_ring	cmdq;
 	struct iwi_tx_ring	txq[WME_NUM_AC];
 	struct iwi_rx_ring	rxq;
@@ -205,7 +209,8 @@
 
 	int			sc_tx_timer;
 	int			sc_rfkill_timer;/* poll for rfkill change */
-	int			sc_scan_timer;	/* scan request timeout */
+	int			sc_state_timer;	/* firmware state timer */
+	int			sc_busy_timer;	/* firmware cmd timer */
 
 #define IWI_SCAN_START		(1 << 0)
 #define IWI_SET_CHANNEL	        (1 << 1)
@@ -237,6 +242,24 @@
 	int			sc_txtap_len;
 };
 
+#define	IWI_STATE_BEGIN(_sc, _state)	do {			\
+	KASSERT(_sc->fw_state == IWI_FW_IDLE,			\
+	    ("iwi firmware not idle"));				\
+	_sc->fw_state = _state;					\
+	_sc->sc_state_timer = 5;				\
+	DPRINTF(("enter FW state %d\n",	_state));		\
+} while (0)
+
+#define	IWI_STATE_END(_sc, _state)	do {			\
+	if (_sc->fw_state == _state)				\
+		DPRINTF(("exit FW state %d\n", _state));	\
+	 else							\
+		DPRINTF(("expected FW state %d, got %d\n",	\
+			    _state, _sc->fw_state));		\
+	_sc->fw_state = IWI_FW_IDLE;				\
+	wakeup(_sc);						\
+	_sc->sc_state_timer = 0;				\
+} while (0)
 /*
  * NB.: This models the only instance of async locking in iwi_init_locked
  *	and must be kept in sync.



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