From owner-p4-projects@FreeBSD.ORG Sat Jun 9 20:01:08 2007 Return-Path: X-Original-To: p4-projects@freebsd.org Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id B9D6216A468; Sat, 9 Jun 2007 20:01:07 +0000 (UTC) X-Original-To: perforce@freebsd.org Delivered-To: perforce@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 628F516A41F for ; Sat, 9 Jun 2007 20:01:07 +0000 (UTC) (envelope-from thompsa@freebsd.org) Received: from repoman.freebsd.org (repoman.freebsd.org [69.147.83.41]) by mx1.freebsd.org (Postfix) with ESMTP id 536F913C48A for ; Sat, 9 Jun 2007 20:01:07 +0000 (UTC) (envelope-from thompsa@freebsd.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.13.8/8.13.8) with ESMTP id l59K17pP021420 for ; Sat, 9 Jun 2007 20:01:07 GMT (envelope-from thompsa@freebsd.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.13.8/8.13.8/Submit) id l59K17Xq021397 for perforce@freebsd.org; Sat, 9 Jun 2007 20:01:07 GMT (envelope-from thompsa@freebsd.org) Date: Sat, 9 Jun 2007 20:01:07 GMT Message-Id: <200706092001.l59K17Xq021397@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to thompsa@freebsd.org using -f From: Andrew Thompson To: Perforce Change Reviews Cc: Subject: PERFORCE change 121291 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 09 Jun 2007 20:01:08 -0000 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.