Date: Mon, 9 Jul 2007 01:34:59 GMT From: Andrew Thompson <thompsa@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 123164 for review Message-ID: <200707090134.l691Yx5x006406@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=123164 Change 123164 by thompsa@thompsa_heff on 2007/07/09 01:34:18 Use the same method as iwi for avoiding command interleaving where the current state is tracked. Affected files ... .. //depot/projects/wifi/sys/dev/ipw/if_ipw.c#21 edit Differences ... ==== //depot/projects/wifi/sys/dev/ipw/if_ipw.c#21 (text+ko) ==== @@ -133,12 +133,12 @@ static int ipw_config(struct ipw_softc *); static void ipw_restart(void *, int); static int ipw_scan(struct ipw_softc *); -static void ipw_scanstart(void *, int); static void ipw_assoc_lost(void *, int); -static void ipw_assoc(void *, int); +static void ipw_assoc(struct ieee80211com *); +static void ipw_disassoc(struct ieee80211com *); static int ipw_auth_and_assoc(struct ipw_softc *); static int ipw_disassociate(struct ipw_softc *); -static void ipw_down(void *, int); +static void ipw_ops(void *, int); static void ipw_init(void *); static void ipw_init_locked(struct ipw_softc *, int); static void ipw_stop_locked(struct ipw_softc *); @@ -200,21 +200,6 @@ DRIVER_MODULE(ipw, pci, ipw_driver, ipw_devclass, 0, 0); DRIVER_MODULE(ipw, cardbus, ipw_driver, ipw_devclass, 0, 0); -/* - * NB.: This models the only instance of async locking in ipw_init_locked - * and must be kept in sync. - */ -#define IPW_LOCK_DECL int __waslocked = 0 -#define IPW_LOCK(sc) do { \ - if (!(__waslocked = mtx_owned(&(sc)->sc_mtx))) \ - mtx_lock(&sc->sc_mtx); \ -} while (0) -#define IPW_UNLOCK(sc) do { \ - if (!__waslocked) \ - mtx_unlock(&sc->sc_mtx); \ -} while (0) -#define IPW_LOCK_ASSERT(sc) mtx_assert(&(sc)->sc_mtx, MA_OWNED) - static int ipw_probe(device_t dev) { @@ -247,6 +232,7 @@ mtx_init(&sc->sc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, MTX_DEF | MTX_RECURSE); + IPW_CMD_LOCK_INIT(sc); #if __FreeBSD_version >= 700000 sc->sc_tq = taskqueue_create("ipw_taskq", M_NOWAIT, @@ -261,11 +247,9 @@ #endif TASK_INIT(&sc->sc_radiontask, 0, ipw_radio_on, sc); TASK_INIT(&sc->sc_radiofftask, 0, ipw_radio_off, sc); - TASK_INIT(&sc->sc_scanstarttask,0, ipw_scanstart, sc); TASK_INIT(&sc->sc_assoclosttask,0, ipw_assoc_lost, sc); - TASK_INIT(&sc->sc_assoctask, 0, ipw_assoc, sc); - TASK_INIT(&sc->sc_downtask, 0, ipw_down, sc); TASK_INIT(&sc->sc_restarttask, 0, ipw_restart, sc); + TASK_INIT(&sc->sc_opstask, 0, ipw_ops, sc); callout_init_mtx(&sc->sc_wdtimer, &sc->sc_mtx, 0); if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { @@ -351,9 +335,11 @@ /* set supported .11b channels (read from EEPROM) */ if ((val = ipw_read_prom_word(sc, IPW_EEPROM_CHANNEL_LIST)) == 0) val = 0x7ff; /* default to channels 1-11 */ + sc->chanmask = val; val <<= 1; for (i = 1; i < 16; i++) { if (val & (1 << i)) { + printf("adding channel %d\n",i); c = &ic->ic_channels[ic->ic_nchans++]; c->ic_freq = ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ); c->ic_flags = IEEE80211_CHAN_B; @@ -442,6 +428,7 @@ taskqueue_free(sc->sc_tq); mtx_destroy(&sc->sc_mtx); + IPW_CMD_LOCK_DESTROY(sc); return 0; } @@ -846,7 +833,7 @@ switch (nstate) { case IEEE80211_S_AUTH: - taskqueue_enqueue(sc->sc_tq, &sc->sc_assoctask); + ipw_assoc(ic); break; case IEEE80211_S_RUN: @@ -860,7 +847,7 @@ * This is all totally bogus and needs to be redone. */ if (ic->ic_state == IEEE80211_S_SCAN) - taskqueue_enqueue(sc->sc_tq, &sc->sc_assoctask); + ipw_assoc(ic); } /* XXX way wrong */ return sc->sc_newstate(ic, nstate, @@ -877,7 +864,7 @@ */ if (ic->ic_state == IEEE80211_S_RUN && (sc->flags & IPW_FLAG_FW_INITED)) - taskqueue_enqueue(sc->sc_tq, &sc->sc_downtask); + ipw_disassoc(ic); break; default: @@ -923,6 +910,7 @@ DPRINTFN(2, ("Association succeeded (%s flags 0x%x)\n", IEEESTATE(ic), sc->flags)); sc->flags |= IPW_FLAG_ASSOCIATED; + IPW_STATE_END(sc, IPW_FW_ASSOCIATING); /* XXX suppress state change in case the fw auto-associates */ if (ic->ic_state != IEEE80211_S_ASSOC) { DPRINTF(("Unexpected association (state %u)\n", @@ -955,14 +943,19 @@ * the first scan complete event. This works ok * because the adapter scans only 2.4G channels so * doing an extra pass doesn't take long. - */ if (sc->flags & IPW_FLAG_HACK) { sc->flags &= ~IPW_FLAG_HACK; break; } - sc->sc_scan_timer = 0; - sc->flags &= ~IPW_FLAG_SCANNING; - ieee80211_scan_done(ic); + */ + + /* Only update the scan module if we were actaully scanning */ + if (sc->fw_state == IPW_FW_SCANNING) { + sc->sc_scan_timer = 0; + sc->flags &= ~IPW_FLAG_SCANNING; + IPW_STATE_END(sc, IPW_FW_SCANNING); + ieee80211_scan_done(ic); + } break; case IPW_STATE_ASSOCIATION_LOST: @@ -2172,25 +2165,16 @@ static int ipw_scan(struct ipw_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; - const struct ieee80211_channel *c; - uint32_t chanmask, params; - int i, error; + uint32_t params; + int error; DPRINTF(("%s: flags 0x%x\n", __func__, sc->flags)); + IPW_STATE_BEGIN(sc, IPW_FW_SCANNING); - chanmask = 0; - /* XXX just copy ic_chan_scan */ - for (i = 0; i <= IEEE80211_CHAN_MAX; i++) { - c = &ic->ic_channels[i]; - if (!(isset(ic->ic_chan_scan,i) || c == ic->ic_curchan)) - continue; - chanmask |= 1<<(i-1); - } /* NB: IPW_SCAN_DO_NOT_ASSOCIATE does not work (we set it anyway) */ - error = ipw_setscanopts(sc, chanmask, IPW_SCAN_DO_NOT_ASSOCIATE); + error = ipw_setscanopts(sc, sc->chanmask, IPW_SCAN_DO_NOT_ASSOCIATE); if (error != 0) - return error; + goto done; /* * Setup null/bogus ssid so firmware doesn't use any previous @@ -2199,7 +2183,7 @@ */ error = ipw_setssid(sc, NULL, 0); if (error != 0) - return error; + goto done; /* * With 100ms/channel dwell time and a max of 14 channels @@ -2218,34 +2202,16 @@ ¶ms, sizeof(params)); } else error = ipw_enable(sc); +done: if (error != 0) { sc->sc_scan_timer = 0; sc->flags &= ~(IPW_FLAG_SCANNING | IPW_FLAG_HACK); + IPW_STATE_BEGIN(sc, IPW_FW_SCANNING); } - return error; + return (error); } static void -ipw_scanstart(void *arg, int npending) -{ - struct ipw_softc *sc = arg; - struct ieee80211com *ic = &sc->sc_ic; - IPW_LOCK_DECL; - - DPRINTF(("%s: flags 0x%x\n", __func__, sc->flags)); - - IPW_LOCK(sc); - if (sc->flags & IPW_FLAG_SCANNING) { - if (ipw_scan(sc) != 0) { - /* XXX should not happen */ - sc->flags &= ~IPW_FLAG_SCANNING; - ieee80211_new_state(ic, IEEE80211_S_INIT, 0); - } - } - IPW_UNLOCK(sc); -} - -static void ipw_assoc_lost(void *arg, int npending) { struct ipw_softc *sc = arg; @@ -2260,17 +2226,6 @@ IPW_UNLOCK(sc); } -static void -ipw_assoc(void *arg, int npending) -{ - struct ipw_softc *sc = arg; - IPW_LOCK_DECL; - - IPW_LOCK(sc); - ipw_auth_and_assoc(sc); - IPW_UNLOCK(sc); -} - static int ipw_auth_and_assoc(struct ipw_softc *sc) { @@ -2280,9 +2235,12 @@ uint32_t data; int error; + IPW_LOCK_ASSERT(sc); + IPW_STATE_BEGIN(sc, IPW_FW_ASSOCIATING); + error = ipw_disable(sc); if (error != 0) - return error; + goto done; memset(&security, 0, sizeof security); security.authmode = (ni->ni_authmode == IEEE80211_AUTH_SHARED) ? @@ -2292,12 +2250,12 @@ error = ipw_cmd(sc, IPW_CMD_SET_SECURITY_INFO, &security, sizeof security); if (error != 0) - return error; + goto done; if (ic->ic_flags & IEEE80211_F_PRIVACY) { error = ipw_setwepkeys(sc); if (error != 0) - return error; + goto done; if (ic->ic_crypto.cs_def_txkey != IEEE80211_KEYIX_NONE) { data = htole32(ic->ic_crypto.cs_def_txkey); @@ -2306,41 +2264,44 @@ error = ipw_cmd(sc, IPW_CMD_SET_WEP_KEY_INDEX, &data, sizeof data); if (error != 0) - return error; + goto done; } } error = ipw_setssid(sc, ni->ni_essid, ni->ni_esslen); if (error != 0) - return error; + goto done; error = ipw_setbssid(sc, ni->ni_bssid); if (error != 0) - return error; + goto done; data = htole32((ic->ic_flags & IEEE80211_F_PRIVACY) ? IPW_WEPON : 0); DPRINTF(("Setting wep flags to 0x%x\n", le32toh(data))); error = ipw_cmd(sc, IPW_CMD_SET_WEP_FLAGS, &data, sizeof data); if (error != 0) - return error; + goto done; if (ic->ic_opt_ie != NULL) { error = ipw_setwpaie(sc, ic->ic_opt_ie, ic->ic_opt_ie_len); if (error != 0) - return error; + goto done; } if (ic->ic_opmode == IEEE80211_M_IBSS) { error = ipw_setchannel(sc, ni->ni_chan); if (error != 0) - return error; + goto done; } /* lock scan to ap's channel and enable associate */ error = ipw_setscanopts(sc, 1<<(ieee80211_chan2ieee(ic, ni->ni_chan)-1), 0); - if (error != 0) - return error; +done: + if (error != 0) { + IPW_STATE_END(sc, IPW_FW_ASSOCIATING); + return (error); + } return ipw_enable(sc); /* finally, enable adapter */ } @@ -2361,18 +2322,6 @@ } static void -ipw_down(void *arg, int npending) -{ - struct ipw_softc *sc = arg; - IPW_LOCK_DECL; - - IPW_LOCK(sc); - ipw_disassociate(sc); - /* XXX disable? */ - IPW_UNLOCK(sc); -} - -static void ipw_init(void *priv) { struct ipw_softc *sc = priv; @@ -2393,7 +2342,7 @@ DPRINTF(("%s: state %s flags 0x%x\n", __func__, ieee80211_state_name[ic->ic_state], sc->flags)); - if (sc->flags & IPW_FLAG_FW_LOADING) + if (sc->fw_state == IPW_FW_LOADING) return; ipw_stop_locked(sc); @@ -2403,7 +2352,7 @@ goto fail; } - sc->flags |= IPW_FLAG_FW_LOADING; + IPW_STATE_BEGIN(sc, IPW_FW_LOADING); IPW_UNLOCK(sc); /* NB: cannot hold lock while loading firmware */ @@ -2473,12 +2422,12 @@ ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; ifp->if_drv_flags |= IFF_DRV_RUNNING; - sc->flags &= ~IPW_FLAG_FW_LOADING; + IPW_STATE_END(sc, IPW_FW_LOADING); return; fail: ifp->if_flags &= ~IFF_UP; /* XXX */ - sc->flags &= ~IPW_FLAG_FW_LOADING; + IPW_STATE_END(sc, IPW_FW_LOADING); ipw_stop_locked(sc); ipw_put_firmware(sc); } @@ -2795,14 +2744,80 @@ } static void +ipw_ops(void *arg, int npending) +{ + struct ipw_softc *sc = arg; + struct ieee80211com *ic = &sc->sc_ic; + IPW_LOCK_DECL; + int cmd; + +again: + IPW_CMD_LOCK(sc); + cmd = sc->sc_cmd[sc->sc_cmd_cur]; + if (cmd == 0) { + /* No more commands to process */ + IPW_CMD_UNLOCK(sc); + return; + } + sc->sc_cmd[sc->sc_cmd_cur] = 0; /* free the slot */ + sc->sc_cmd_cur = (sc->sc_cmd_cur + 1) % IPW_CMD_MAXOPS; + IPW_CMD_UNLOCK(sc); + + IPW_LOCK(sc); + while (sc->fw_state != IPW_FW_IDLE || (sc->flags & IPW_FLAG_BUSY)) { + msleep(sc, &sc->sc_mtx, 0, "ipwcmd", hz/10); + } + + if (!(sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING)) { + IPW_UNLOCK(sc); + return; + } + + switch (cmd) { + case IPW_ASSOC: + ipw_auth_and_assoc(sc); + break; + case IPW_DISASSOC: + ipw_disassociate(sc); + break; + case IPW_SCAN_START: + if (ipw_scan(sc) != 0) { + /* XXX should not happen */ + ieee80211_new_state(ic, IEEE80211_S_INIT, 0); + } + break; + } + IPW_UNLOCK(sc); + + /* Take another pass */ + goto again; +} + +static int +ipw_queue_cmd(struct ipw_softc *sc, int cmd) +{ + IPW_CMD_LOCK(sc); + if (sc->sc_cmd[sc->sc_cmd_next] != 0) { + IPW_CMD_UNLOCK(sc); + DPRINTF(("%s: command %d dropped\n", __func__, cmd)); + return (EBUSY); + } + + sc->sc_cmd[sc->sc_cmd_next] = cmd; + sc->sc_cmd_next = (sc->sc_cmd_next + 1) % IPW_CMD_MAXOPS; + taskqueue_enqueue(sc->sc_tq, &sc->sc_opstask); + IPW_CMD_UNLOCK(sc); + return (0); +} + +static void ipw_scan_start(struct ieee80211com *ic) { struct ifnet *ifp = ic->ic_ifp; struct ipw_softc *sc = ifp->if_softc; device_printf(sc->sc_dev, "%s\n", __func__); - sc->flags |= IPW_FLAG_SCANNING; - taskqueue_enqueue(sc->sc_tq, &sc->sc_scanstarttask); + ipw_queue_cmd(sc, IPW_SCAN_START); } static void @@ -2838,6 +2853,28 @@ device_printf(sc->sc_dev, "%s\n", __func__); } +static void +ipw_assoc(struct ieee80211com *ic) +{ + struct ifnet *ifp = ic->ic_ifp; + struct ipw_softc *sc = ifp->if_softc; + + /* The firmware will fail if we are already associated */ + if (sc->flags & IPW_FLAG_ASSOCIATED) + ipw_disassoc(ic); + + ipw_queue_cmd(sc, IPW_ASSOC); +} + +static void +ipw_disassoc(struct ieee80211com *ic) +{ + struct ifnet *ifp = ic->ic_ifp; + struct ipw_softc *sc = ifp->if_softc; + + ipw_queue_cmd(sc, IPW_DISASSOC); +} + /* * Read 16 bits at address 'addr' from the serial EEPROM. */
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200707090134.l691Yx5x006406>