PERFORCE change 123164 for review
Andrew Thompson
thompsa at FreeBSD.org
Mon Jul 9 01:35:00 UTC 2007
http://perforce.freebsd.org/chv.cgi?CH=123164
Change 123164 by thompsa at 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.
*/
More information about the p4-projects
mailing list