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 @@
 				&params, 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