Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 5 Apr 2008 23:35:54 GMT
From:      Sam Leffler <sam@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 139438 for review
Message-ID:  <200804052335.m35NZseK074914@repoman.freebsd.org>

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

Change 139438 by sam@sam_ebb on 2008/04/05 23:35:37

	Checkpoint major overhaul now that we're back to sta operation
	(open and w/ wpa):
	o move if_alloc up to simplify work
	o cleanup iwi_detach; still need to eliminate it's use in iwi_attach
	o move firmware get into vap create so we don't need to drop the
	  softc lock in iwi_init
	o add task bounces for iwi_notification_intr calls back into net80211
	  to eliminate LOR's
	o rewrite iwi_newstate to use split state machine handling mechanism
	  and inline expand routines that just toss requests to the task queue
	  to make logic more explicit
	o eliminate bogus call to ieee80211_node_authorize; this was wrong
	  for WPA and should never be done by the driver
	o tighten up some code (Andrew, you really like blank lines, eh? :))
	o move check of IFF_DRV_RUNNING on firmware error to the task queue
	  to avoid inconsistent state
	o make iwi_raw_xmit just discard frames; there's no way to send raw
	  802.11 frames with this device and trying to cause the firmware
	  to barf
	o eliminate "wait until pending iwi_cmds are completed" logic in
	  iwi_ioctl; we are now called from the 802.11 layer and there should
	  never be cmds pending if we have done the right work wrt the cmd
	  queues, firmware state, and taskqueue
	o block/unblock task queues instead of trying to drain them; this
	  fixes various races in the handling of reset I believe
	o display symbolic names for fw states in debug msgs
	o never never touch IFF_UP
	o expand iwi_queue_cmd to pass an opaque argument through so the
	  state machine changes can be directly mimic the 802.11 layer requests
	o add IWI_AUTH so we can explicitly track the state machine

Affected files ...

.. //depot/projects/vap/sys/dev/iwi/if_iwi.c#17 edit
.. //depot/projects/vap/sys/dev/iwi/if_iwivar.h#11 edit

Differences ...

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

@@ -91,6 +91,14 @@
 #define DPRINTFN(n, x)	do { if (iwi_debug >= (n)) printf x; } while (0)
 int iwi_debug = 0;
 SYSCTL_INT(_debug, OID_AUTO, iwi, CTLFLAG_RW, &iwi_debug, 0, "iwi debug level");
+
+static const char *iwi_fw_states[] = {
+	"IDLE", 		/* IWI_FW_IDLE */
+	"LOADING",		/* IWI_FW_LOADING */
+	"ASSOCIATING",		/* IWI_FW_ASSOCIATING */
+	"DISASSOCIATING",	/* IWI_FW_DISASSOCIATING */
+	"SCANNING",		/* IWI_FW_SCANNING */
+};
 #else
 #define DPRINTF(x)
 #define DPRINTFN(n, x)
@@ -144,11 +152,15 @@
 static void	iwi_media_status(struct ifnet *, struct ifmediareq *);
 static int	iwi_newstate(struct ieee80211vap *, enum ieee80211_state, int);
 static void	iwi_wme_init(struct iwi_softc *);
-static int	iwi_wme_setparams(struct iwi_softc *);
+static int	iwi_wme_setparams(struct iwi_softc *, struct ieee80211com *);
 static int	iwi_wme_update(struct ieee80211com *);
 static uint16_t	iwi_read_prom_word(struct iwi_softc *, uint8_t);
 static void	iwi_frame_intr(struct iwi_softc *, struct iwi_rx_data *, int,
 		    struct iwi_frame *);
+static void	iwi_bmiss(void *, int);
+static void	iwi_authsuccess(void *, int);
+static void	iwi_assocsuccess(void *, int);
+static void	iwi_assocfailed(void *, int);
 static void	iwi_notification_intr(struct iwi_softc *, struct iwi_notif *);
 static void	iwi_rx_intr(struct iwi_softc *);
 static void	iwi_tx_intr(struct iwi_softc *, struct iwi_tx_ring *);
@@ -159,6 +171,7 @@
 		    struct ieee80211_node *, int);
 static int	iwi_raw_xmit(struct ieee80211_node *, struct mbuf *,
 		    const struct ieee80211_bpf_params *);
+static void	iwi_start_locked(struct ifnet *);
 static void	iwi_start(struct ifnet *);
 static void	iwi_watchdog(void *);
 static int	iwi_ioctl(struct ifnet *, u_long, caddr_t);
@@ -167,8 +180,8 @@
 static int	iwi_load_ucode(struct iwi_softc *, const struct iwi_fw *);
 static int	iwi_load_firmware(struct iwi_softc *, const struct iwi_fw *);
 static void	iwi_release_fw_dma(struct iwi_softc *sc);
-static int	iwi_config(struct iwi_softc *);
-static int	iwi_get_firmware(struct iwi_softc *);
+static int	iwi_config(struct iwi_softc *, struct ieee80211vap *);
+static int	iwi_get_firmware(struct iwi_softc *, enum ieee80211_opmode);
 static void	iwi_put_firmware(struct iwi_softc *);
 static int	iwi_scanchan(struct iwi_softc *, unsigned long, int);
 static void	iwi_scan_start(struct ieee80211com *);
@@ -180,15 +193,14 @@
 static void	iwi_scan_allchan(struct ieee80211com *, unsigned long maxdwell);
 #endif
 static void	iwi_scan_mindwell(struct ieee80211_scan_state *);
-static void     iwi_assoc(struct ieee80211vap *);
-static void     iwi_disassoc(struct ieee80211vap *);
 static void	iwi_ops(void *, int);
-static int	iwi_queue_cmd(struct iwi_softc *, int);
+static int	iwi_queue_cmd(struct iwi_softc *, int, int);
 static int	iwi_auth_and_assoc(struct iwi_softc *, struct ieee80211vap *);
 static int	iwi_disassociate(struct iwi_softc *, int quiet);
 static void	iwi_init(void *);
-static void	iwi_init_locked(void *, int);
-static void	iwi_stop(void *);
+static int	iwi_init_fw_dma(struct iwi_softc *, int);
+static void	iwi_stop_locked(void *);
+static void	iwi_stop(struct iwi_softc *);
 static void	iwi_restart(void *, int);
 static int	iwi_getrfkill(struct iwi_softc *);
 static void	iwi_radio_on(void *, int);
@@ -270,6 +282,13 @@
 
 	sc->sc_dev = dev;
 
+	ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211);
+	if (ifp == NULL) {
+		device_printf(dev, "can not if_alloc()\n");
+		return ENXIO;
+	}
+	ic = ifp->if_l2com;
+
 	IWI_LOCK_INIT(sc);
 	IWI_CMD_LOCK_INIT(sc);
 
@@ -352,12 +371,7 @@
 
 	iwi_wme_init(sc);
 
-	ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211);
-	if (ifp == NULL) {
-		device_printf(dev, "can not if_alloc()\n");
-		goto fail;
-	}
-	ic = ifp->if_l2com;
+	TASK_INIT(&sc->sc_bmiss_task, 0, iwi_bmiss, ic);
 
 	ifp->if_softc = sc;
 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
@@ -446,8 +460,9 @@
 		ieee80211_announce(ic);
 
 	return 0;
-
-fail:	iwi_detach(dev);
+fail:
+	/* XXX fix */
+	iwi_detach(dev);
 	return ENXIO;
 }
 
@@ -457,17 +472,16 @@
 	struct iwi_softc *sc = device_get_softc(dev);
 	struct ifnet *ifp = sc->sc_ifp;
 	struct ieee80211com *ic = ifp->if_l2com;
-	IWI_LOCK_DECL;
+
+	iwi_stop(sc);
+
+	bpfdetach(ifp);
+	ieee80211_ifdetach(ic);
 
-	if (ifp != NULL) {
-		IWI_LOCK(sc);
-		iwi_stop(sc);
-		IWI_UNLOCK(sc);
-		bpfdetach(ifp);
-		ieee80211_ifdetach(ic);
-	}
+	/* NB: do early to drain any pending tasks */
+	taskqueue_free(sc->sc_tq);
+	taskqueue_free(sc->sc_tq2);
 
-	callout_drain(&sc->sc_wdtimer);
 	iwi_put_firmware(sc);
 	iwi_release_fw_dma(sc);
 
@@ -478,26 +492,18 @@
 	iwi_free_tx_ring(sc, &sc->txq[3]);
 	iwi_free_rx_ring(sc, &sc->rxq);
 
-	if (sc->irq != NULL) {
-		bus_teardown_intr(dev, sc->irq, sc->sc_ih);
-		bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq);
-	}
+	bus_teardown_intr(dev, sc->irq, sc->sc_ih);
+	bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq);
 
-	if (sc->mem != NULL)
-		bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem);
+	bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem);
 
-	if (ifp != NULL)
-		if_free(ifp);
-
-	taskqueue_free(sc->sc_tq);
-	taskqueue_free(sc->sc_tq2);
-
-	if (sc->sc_unr != NULL)
-		delete_unrhdr(sc->sc_unr);
+	delete_unrhdr(sc->sc_unr);
 
 	IWI_LOCK_DESTROY(sc);
 	IWI_CMD_LOCK_DESTROY(sc);
 
+	if_free(ifp);
+
 	return 0;
 }
 
@@ -507,11 +513,29 @@
 	const uint8_t bssid[IEEE80211_ADDR_LEN],
 	const uint8_t mac[IEEE80211_ADDR_LEN])
 {
+	struct ifnet *ifp = ic->ic_ifp;
+	struct iwi_softc *sc = ifp->if_softc;
 	struct iwi_vap *ivp;
 	struct ieee80211vap *vap;
+	int i;
 
 	if (!TAILQ_EMPTY(&ic->ic_vaps))		/* only one at a time */
 		return NULL;
+	/*
+	 * Get firmware image (and possibly dma memory) on mode change.
+	 */
+	if (iwi_get_firmware(sc, opmode))
+		return NULL;
+	/* allocate DMA memory for mapping firmware image */
+	i = sc->fw_fw.size;
+	if (sc->fw_boot.size > i)
+		i = sc->fw_boot.size;
+	/* XXX do we dma the ucode as well ? */
+	if (sc->fw_uc.size > i)
+		i = sc->fw_uc.size;
+	if (iwi_init_fw_dma(sc, i))
+		return NULL;
+
 	ivp = (struct iwi_vap *) malloc(sizeof(struct iwi_vap),
 	    M_80211_VAP, M_NOWAIT | M_ZERO);
 	if (ivp == NULL)
@@ -523,6 +547,10 @@
 	ivp->iwi_newstate = vap->iv_newstate;
 	vap->iv_newstate = iwi_newstate;
 
+	TASK_INIT(&ivp->iwi_authsuccess_task, 0, iwi_authsuccess, vap);
+	TASK_INIT(&ivp->iwi_assocsuccess_task, 0, iwi_assocsuccess, vap);
+	TASK_INIT(&ivp->iwi_assocfailed_task, 0, iwi_assocfailed, vap);
+
 	/* complete setup */
 	ieee80211_vap_attach(vap, ieee80211_media_change, iwi_media_status);
 	ic->ic_opmode = opmode;
@@ -840,11 +868,8 @@
 iwi_shutdown(device_t dev)
 {
 	struct iwi_softc *sc = device_get_softc(dev);
-	IWI_LOCK_DECL;
 
-	IWI_LOCK(sc);
 	iwi_stop(sc);
-	IWI_UNLOCK(sc);
 	iwi_put_firmware(sc);		/* ??? XXX */
 
 	return 0;
@@ -854,11 +879,8 @@
 iwi_suspend(device_t dev)
 {
 	struct iwi_softc *sc = device_get_softc(dev);
-	IWI_LOCK_DECL;
 
-	IWI_LOCK(sc);
 	iwi_stop(sc);
-	IWI_UNLOCK(sc);
 
 	return 0;
 }
@@ -962,19 +984,36 @@
 	struct ieee80211com *ic = vap->iv_ic;
 	struct ifnet *ifp = ic->ic_ifp;
 	struct iwi_softc *sc = ifp->if_softc;
-	int error = 0;
+	IWI_LOCK_DECL;
 
 	DPRINTF(("%s: %s -> %s flags 0x%x\n", __func__,
 		ieee80211_state_name[vap->iv_state],
 		ieee80211_state_name[nstate], sc->flags));
 
-	/* XXX state change race with taskqueue */
 	switch (nstate) {
+	case IEEE80211_S_INIT:
+		IWI_LOCK(sc);
+		/*
+		 * NB: don't try to do this if iwi_stop_master has
+		 *     shutdown the firmware and disabled interrupts.
+		 */
+		if (vap->iv_state == IEEE80211_S_RUN &&
+		    (sc->flags & IWI_FLAG_FW_INITED))
+			iwi_queue_cmd(sc, IWI_DISASSOC, 0);
+		IWI_UNLOCK(sc);
+		break;
+	case IEEE80211_S_SCAN:
+		iwi_queue_cmd(sc, IWI_CONFIG, 0);
+		return EINPROGRESS;
 	case IEEE80211_S_AUTH:
-		iwi_assoc(vap);
-		break;
+		/* The firmware will fail if we are already associated */
+		if (sc->flags & IWI_FLAG_ASSOCIATED)
+			iwi_queue_cmd(sc, IWI_DISASSOC, 0);
+		iwi_queue_cmd(sc, IWI_AUTH, arg);
+		return EINPROGRESS;
 	case IEEE80211_S_RUN:
-		if (vap->iv_opmode == IEEE80211_M_IBSS) {
+		if (vap->iv_opmode == IEEE80211_M_IBSS &&
+		    vap->iv_state == IEEE80211_S_SCAN) {
 			/*
 			 * XXX when joining an ibss network we are called
 			 * with a SCAN -> RUN transition on scan complete.
@@ -983,35 +1022,27 @@
 			 * AUTH -> RUN transition and we want to do nothing.
 			 * This is all totally bogus and needs to be redone.
 			 */
-			if (vap->iv_state == IEEE80211_S_SCAN)
-				iwi_assoc(vap);
-		} 
+			iwi_queue_cmd(sc, IWI_ASSOC, 0);
+			return EINPROGRESS;
+		}
 		break;
-	case IEEE80211_S_INIT:
-		/*
-		 * NB: don't try to do this if iwi_stop_master has
-		 *     shutdown the firmware and disabled interrupts.
-		 */
-		if (vap->iv_state == IEEE80211_S_RUN &&
-		    (sc->flags & IWI_FLAG_FW_INITED))
-			iwi_disassoc(vap);
-		if (vap->iv_state == IEEE80211_S_SCAN &&
-		    (sc->fw_state == IWI_FW_SCANNING))
-			ieee80211_cancel_scan(vap);
-		break;
 	case IEEE80211_S_ASSOC:
 		/*
-		 * If we are not transitioning from AUTH the resend the
-		 * association request.
+		 * If we are transitioning from AUTH then just wait
+		 * for the ASSOC status to come back from the firmware.
+		 * Otherwise we need to issue the association request.
 		 */
-		if (vap->iv_state != IEEE80211_S_AUTH)
-			iwi_assoc(vap);
-		break;
+		if (vap->iv_state == IEEE80211_S_AUTH)
+			break;
+		/* The firmware will fail if we are already associated */
+		if (sc->flags & IWI_FLAG_ASSOCIATED)
+			iwi_queue_cmd(sc, IWI_DISASSOC, 0);
+		iwi_queue_cmd(sc, IWI_ASSOC, arg);
+		return EINPROGRESS;
 	default:
 		break;
 	}
-	return (error != 0) ? error : ivp->iwi_newstate(vap, nstate, arg);
-
+	return ivp->iwi_newstate(vap, nstate, arg);
 }
 
 /*
@@ -1062,10 +1093,8 @@
 }
 
 static int
-iwi_wme_setparams(struct iwi_softc *sc)
+iwi_wme_setparams(struct iwi_softc *sc, struct ieee80211com *ic)
 {
-	struct ifnet *ifp = sc->sc_ifp;
-	struct ieee80211com *ic = ifp->if_l2com;
 	const struct wmeParams *wmep;
 	int ac;
 
@@ -1098,7 +1127,7 @@
 	 * will get sent down to the adapter as part of the
 	 * work iwi_auth_and_assoc does.
 	 */
-	return (iwi_queue_cmd(sc, IWI_SET_WME));
+	return iwi_queue_cmd(sc, IWI_SET_WME, 0);
 }
 
 static int
@@ -1367,7 +1396,42 @@
 #undef SUBTYPE
 }
 
+/*
+ * Task queue callbacks for iwi_notification_intr used to avoid LOR's.
+ */
+static void
+iwi_bmiss(void *arg, int npending)
+{
+	struct ieee80211com *ic = arg;
+
+	ieee80211_beacon_miss(ic);
+}
+
+static void
+iwi_authsuccess(void *arg, int npending)
+{
+	struct ieee80211vap *vap = arg;
+
+	ieee80211_new_state(vap, IEEE80211_S_ASSOC, -1);
+}
+
 static void
+iwi_assocsuccess(void *arg, int npending)
+{
+	struct ieee80211vap *vap = arg;
+
+	ieee80211_new_state(vap, IEEE80211_S_RUN, -1);
+}
+
+static void
+iwi_assocfailed(void *arg, int npending)
+{
+	struct ieee80211vap *vap = arg;
+
+	ieee80211_new_state(vap, IEEE80211_S_SCAN, -1);
+}
+
+static void
 iwi_notification_intr(struct iwi_softc *sc, struct iwi_notif *notif)
 {
 	struct ifnet *ifp = sc->sc_ifp;
@@ -1398,54 +1462,49 @@
 
 		IWI_STATE_END(sc, IWI_FW_SCANNING);
 
-		if (scan->status == IWI_SCAN_COMPLETED)
+		if (scan->status == IWI_SCAN_COMPLETED) {
+			/* NB: don't need to defer, net80211 does it for us */
 			ieee80211_scan_next(vap);
-
+		}
 		break;
 
 	case IWI_NOTIF_TYPE_AUTHENTICATION:
 		auth = (struct iwi_notif_authentication *)(notif + 1);
-
 		switch (auth->state) {
 		case IWI_AUTH_SUCCESS:
 			DPRINTFN(2, ("Authentication succeeeded\n"));
-			ieee80211_node_authorize(vap->iv_bss);
-			ieee80211_new_state(vap, IEEE80211_S_ASSOC, -1);
+			taskqueue_enqueue(taskqueue_swi,
+			    &IWI_VAP(vap)->iwi_authsuccess_task);
 			break;
-
 		case IWI_AUTH_FAIL:
 			DPRINTFN(2, ("Authentication failed\n"));
 			sc->flags &= ~IWI_FLAG_ASSOCIATED;
 			IWI_STATE_END(sc, IWI_FW_ASSOCIATING);
 			/* XXX */
 			break;
-
 		case IWI_AUTH_SENT_1:
 		case IWI_AUTH_RECV_2:
 		case IWI_AUTH_SEQ1_PASS:
 			break;
-
 		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;
-
 		default:
 			device_printf(sc->sc_dev,
 			    "unknown authentication state %u\n", auth->state);
+			break;
 		}
 		break;
 
 	case IWI_NOTIF_TYPE_ASSOCIATION:
 		assoc = (struct iwi_notif_association *)(notif + 1);
-
 		switch (assoc->state) {
 		case IWI_AUTH_SUCCESS:
 			/* re-association, do nothing */
 			break;
-
 		case IWI_ASSOC_SUCCESS:
 			DPRINTFN(2, ("Association succeeded\n"));
 			sc->flags |= IWI_FLAG_ASSOCIATED;
@@ -1453,30 +1512,30 @@
 			iwi_checkforqos(vap,
 			    (const struct ieee80211_frame *)(assoc+1),
 			    le16toh(notif->len) - sizeof(*assoc));
-			ieee80211_new_state(vap, IEEE80211_S_RUN, -1);
+			taskqueue_enqueue(taskqueue_swi,
+			    &IWI_VAP(vap)->iwi_assocsuccess_task);
 			break;
-
 		case IWI_ASSOC_INIT:
 			switch (sc->fw_state) {
-				case IWI_FW_ASSOCIATING:
-					DPRINTFN(2, ("Association failed\n"));
-					IWI_STATE_END(sc, IWI_FW_ASSOCIATING);
-					ieee80211_new_state(vap,
-					    IEEE80211_S_SCAN, -1);
-					break;
+			case IWI_FW_ASSOCIATING:
+				DPRINTFN(2, ("Association failed\n"));
+				IWI_STATE_END(sc, IWI_FW_ASSOCIATING);
+				taskqueue_enqueue(taskqueue_swi,
+				    &IWI_VAP(vap)->iwi_assocfailed_task);
+				break;
 
-				case IWI_FW_DISASSOCIATING:
-					DPRINTFN(2, ("Dissassociated\n"));
-					IWI_STATE_END(sc,
-					    IWI_FW_DISASSOCIATING);
-					break;
+			case IWI_FW_DISASSOCIATING:
+				DPRINTFN(2, ("Dissassociated\n"));
+				IWI_STATE_END(sc,
+				    IWI_FW_DISASSOCIATING);
+				break;
 			}
 			sc->flags &= ~IWI_FLAG_ASSOCIATED;
 			break;
-
 		default:
 			device_printf(sc->sc_dev,
 			    "unknown association state %u\n", assoc->state);
+			break;
 		}
 		break;
 
@@ -1499,7 +1558,8 @@
 				DPRINTF(("Beacon miss: %u >= %u\n",
 				    le32toh(beacon->number),
 				    vap->iv_bmissthreshold));
-				ieee80211_beacon_miss(ic);
+				taskqueue_enqueue(taskqueue_swi,
+				    &sc->sc_bmiss_task);
 			}
 		}
 		break;
@@ -1513,6 +1573,7 @@
 	default:
 		DPRINTF(("unknown notification type %u flags 0x%x len %u\n",
 		    notif->type, notif->flags, le16toh(notif->len)));
+		break;
 	}
 }
 
@@ -1595,7 +1656,7 @@
 	if (sc->sc_softled)
 		iwi_led_event(sc, IWI_LED_TX);
 
-	iwi_start(ifp);
+	iwi_start_locked(ifp);
 }
 
 static void
@@ -1617,9 +1678,7 @@
 
 	if (r & IWI_INTR_FATAL_ERROR) {
 		device_printf(sc->sc_dev, "firmware error\n");
-		/* don't restart if the interface isn't up */
-		if (sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING)
-			taskqueue_enqueue(sc->sc_tq2, &sc->sc_restarttask);
+		taskqueue_enqueue(sc->sc_tq2, &sc->sc_restarttask);
 
 		sc->flags &= ~IWI_FLAG_BUSY;
 		sc->sc_busy_timer = 0;
@@ -1884,60 +1943,24 @@
 iwi_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
 	const struct ieee80211_bpf_params *params)
 {
-	struct ieee80211com *ic = ni->ni_ic;
-	struct ifnet *ifp = ic->ic_ifp;
-	struct iwi_softc *sc = ifp->if_softc;
-	int ac;
-	IWI_LOCK_DECL;
-
-	IWI_LOCK(sc);
-
-	/* prevent management frames from being sent if we're not ready */
-	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
-		IWI_UNLOCK(sc);
-		m_freem(m);
-		ieee80211_free_node(ni);
-		return ENETDOWN;
-	}
-	ac = M_WME_GETAC(m);
-	if (sc->txq[ac].queued > IWI_TX_RING_COUNT - 8) {
-		ifp->if_drv_flags |= IFF_DRV_OACTIVE;
-		IWI_UNLOCK(sc);
-		m_freem(m);
-		ieee80211_free_node(ni);
-		return ENOBUFS;		/* XXX */
-	}
-
-	BPF_MTAP(ifp, m);
-
-	/* XXX honor params */
-	if (iwi_tx_start(ifp, m, ni, ac) != 0) {
-		ieee80211_free_node(ni);
-		ifp->if_oerrors++;
-		IWI_UNLOCK(sc);
-		return EIO;
-	}
-
-	IWI_UNLOCK(sc);
-
+	/* no support; just discard */
+	m_freem(m);
+	ieee80211_free_node(ni);
 	return 0;
 }
 
 static void
-iwi_start(struct ifnet *ifp)
+iwi_start_locked(struct ifnet *ifp)
 {
 	struct iwi_softc *sc = ifp->if_softc;
 	struct mbuf *m;
 	struct ieee80211_node *ni;
 	int ac;
-	IWI_LOCK_DECL;
 
-	IWI_LOCK(sc);
+	IWI_LOCK_ASSERT(sc);
 
-	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
-		IWI_UNLOCK(sc);
+	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
 		return;
-	}
 
 	for (;;) {
 		IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
@@ -1970,7 +1993,16 @@
 
 		sc->sc_tx_timer = 5;
 	}
+}
+
+static void
+iwi_start(struct ifnet *ifp)
+{
+	struct iwi_softc *sc = ifp->if_softc;
+	IWI_LOCK_DECL;
 
+	IWI_LOCK(sc);
+	iwi_start_locked(ifp);
 	IWI_UNLOCK(sc);
 }
 
@@ -2032,22 +2064,12 @@
 	struct ieee80211com *ic = ifp->if_l2com;
 	struct ifreq *ifr = (struct ifreq *) data;
 	int error = 0;
-	IWI_LOCK_DECL;
 
-	IWI_LOCK(sc);
-
-	/*
-	 * wait until pending iwi_cmd() are completed, to avoid races
-	 * that could cause problems.
-	 */
-	while (sc->flags & IWI_FLAG_BUSY)
-		msleep(sc, &sc->sc_mtx, 0, "iwiioctl", hz);
-
 	switch (cmd) {
 	case SIOCSIFFLAGS:
 		if (ifp->if_flags & IFF_UP) {
 			if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
-				iwi_init_locked(sc, 0);
+				iwi_init(sc);
 		} else {
 			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
 				iwi_stop(sc);
@@ -2067,10 +2089,8 @@
 		break;
 	default:
 		error = ether_ioctl(ifp, cmd, data);
+		break;
 	}
-
-	IWI_UNLOCK(sc);
-
 	return error;
 }
 
@@ -2204,31 +2224,26 @@
  * the boot firmware as "master".
  */
 static int
-iwi_get_firmware(struct iwi_softc *sc)
+iwi_get_firmware(struct iwi_softc *sc, enum ieee80211_opmode opmode)
 {
-	struct ifnet *ifp = sc->sc_ifp;
-	struct ieee80211com *ic = ifp->if_l2com;
 	const struct iwi_firmware_hdr *hdr;
 	const struct firmware *fp;
 
 	/* invalidate cached firmware on mode change */
-	if (sc->fw_mode != ic->ic_opmode)
+	if (sc->fw_mode != opmode)
 		iwi_put_firmware(sc);
 
-	switch (ic->ic_opmode) {
+	switch (opmode) {
 	case IEEE80211_M_STA:
 		iwi_getfw(&sc->fw_fw, "iwi_bss", &sc->fw_uc, "iwi_ucode_bss");
 		break;
-
 	case IEEE80211_M_IBSS:
 		iwi_getfw(&sc->fw_fw, "iwi_ibss", &sc->fw_uc, "iwi_ucode_ibss");
 		break;
-
 	case IEEE80211_M_MONITOR:
 		iwi_getfw(&sc->fw_fw, "iwi_monitor",
 			  &sc->fw_uc, "iwi_ucode_monitor");
 		break;
-
 	default:
 		break;
 	}
@@ -2308,7 +2323,7 @@
 		sc->fw_boot.size, sc->fw_uc.size, sc->fw_fw.size);
 #endif
 
-	sc->fw_mode = ic->ic_opmode;
+	sc->fw_mode = opmode;
 	return 0;
 bad:
 	iwi_put_firmware(sc);
@@ -2421,6 +2436,7 @@
 	int ntries, error;
 
 	IWI_LOCK_ASSERT(sc);
+
 	/* copy firmware image to DMA memory */
 	memcpy(sc->fw_virtaddr, fw->data, fw->size);
 
@@ -2551,16 +2567,16 @@
 }
 
 static int
-iwi_config(struct iwi_softc *sc)
+iwi_config(struct iwi_softc *sc, struct ieee80211vap *vap)
 {
 	struct ifnet *ifp = sc->sc_ifp;
 	struct ieee80211com *ic = ifp->if_l2com;
-	struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
 	struct iwi_configuration config;
 	struct iwi_rateset rs;
 	struct iwi_txpower power;
 	uint32_t data;
 	int error, i;
+
 	IWI_LOCK_ASSERT(sc);
 
 	IEEE80211_ADDR_COPY(vap->iv_myaddr, IF_LLADDR(ifp));
@@ -2924,13 +2940,13 @@
 
 	if ((vap->iv_flags & IEEE80211_F_WME) && ni->ni_ies.wme_ie != NULL) {
 		/* NB: don't treat WME setup as failure */
-		if (iwi_wme_setparams(sc) == 0 && iwi_wme_setie(sc) == 0)
+		if (iwi_wme_setparams(sc, ic) == 0 && iwi_wme_setie(sc) == 0)
 			assoc->policy |= htole16(IWI_POLICY_WME);
 		/* XXX complain on failure? */
 	}
 
-	if (vap->iv_appie_assocreq != NULL) {
-		struct ieee80211_appie *ie = vap->iv_appie_assocreq;
+	if (vap->iv_appie_wpa != NULL) {
+		struct ieee80211_appie *ie = vap->iv_appie_wpa;
 
 		DPRINTF(("Setting optional IE (len=%u)\n", ie->ie_len));
 		error = iwi_cmd(sc, IWI_CMD_SET_OPTIE, ie->ie_data, ie->ie_len);
@@ -3030,17 +3046,6 @@
 	return iwi_cmd(sc, IWI_CMD_ASSOCIATE, assoc, sizeof *assoc);
 }
 
-static void
-iwi_init(void *priv)
-{
-	struct iwi_softc *sc = priv;
-	IWI_LOCK_DECL;
-
-	IWI_LOCK(sc);
-	iwi_init_locked(sc, 0);
-	IWI_UNLOCK(sc);
-}
-
 /*
  * release dma resources for the firmware
  */
@@ -3102,7 +3107,7 @@
 }
 
 static void
-iwi_init_locked(void *priv, int force)
+iwi_init(void *priv)
 {
 	struct iwi_softc *sc = priv;
 	struct ifnet *ifp = sc->sc_ifp;
@@ -3111,45 +3116,30 @@
 	int i;
 	IWI_LOCK_DECL;
 
-	IWI_LOCK_ASSERT(sc);
+	IWI_LOCK(sc);
+
 	if (sc->fw_state == IWI_FW_LOADING) {
+		IWI_UNLOCK(sc);
 		device_printf(sc->sc_dev, "%s: already loading\n", __func__);
 		return;		/* XXX: condvar? */
 	}
 
-	iwi_stop(sc);
+	iwi_stop_locked(sc);
+
 	IWI_STATE_BEGIN(sc, IWI_FW_LOADING);
 
+	taskqueue_unblock(sc->sc_tq);
+	taskqueue_unblock(sc->sc_tq2);
+
 	if (iwi_reset(sc) != 0) {
 		device_printf(sc->sc_dev, "could not reset adapter\n");
 		goto fail;
 	}
-
-	IWI_UNLOCK(sc);
-	if (iwi_get_firmware(sc)) {
-		IWI_LOCK(sc);
-		goto fail;
-	}
-
-	/* allocate DMA memory for mapping firmware image */
-	i = sc->fw_fw.size;
-	if (sc->fw_boot.size > i)
-		i = sc->fw_boot.size;
-	/* XXX do we dma the ucode as well ? */
-	if (sc->fw_uc.size > i)
-		i = sc->fw_uc.size;
-	if (iwi_init_fw_dma(sc, i)) {
-		IWI_LOCK(sc);
-		goto fail;
-	}
-	IWI_LOCK(sc);
-
 	if (iwi_load_firmware(sc, &sc->fw_boot) != 0) {
 		device_printf(sc->sc_dev,
 		    "could not load boot firmware %s\n", sc->fw_boot.name);
 		goto fail;
 	}
-
 	if (iwi_load_ucode(sc, &sc->fw_uc) != 0) {
 		device_printf(sc->sc_dev,
 		    "could not load microcode %s\n", sc->fw_uc.name);
@@ -3192,39 +3182,40 @@
 	}
 	sc->flags |= IWI_FLAG_FW_INITED;
 
-	if (iwi_config(sc) != 0) {
-		device_printf(sc->sc_dev, "device configuration failed\n");
-		goto fail;
-	}
-
 	callout_reset(&sc->sc_wdtimer, hz, iwi_watchdog, sc);
 	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
 	ifp->if_drv_flags |= IFF_DRV_RUNNING;
 
+	IWI_STATE_END(sc, IWI_FW_LOADING);
+
+	IWI_UNLOCK(sc);
+
 	ieee80211_start_all(ic);		/* start all vap's */
-
-	IWI_STATE_END(sc, IWI_FW_LOADING);
 	return;
-
-fail:	ifp->if_flags &= ~IFF_UP;
+fail:
 	IWI_STATE_END(sc, IWI_FW_LOADING);
-	iwi_stop(sc);
-	iwi_put_firmware(sc);
+	iwi_stop_locked(sc);
+	IWI_UNLOCK(sc);
 }
 
 static void
-iwi_stop(void *priv)
+iwi_stop_locked(void *priv)
 {
 	struct iwi_softc *sc = priv;
 	struct ifnet *ifp = sc->sc_ifp;
 
 	IWI_LOCK_ASSERT(sc);
+
+	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
+
+	taskqueue_block(sc->sc_tq);
+	taskqueue_block(sc->sc_tq2);
 	if (sc->sc_softled) {
 		callout_stop(&sc->sc_ledtimer);
 		sc->sc_blinking = 0;
 	}
+	callout_stop(&sc->sc_wdtimer);
 
-	callout_stop(&sc->sc_wdtimer);
 	iwi_stop_master(sc);
 
 	CSR_WRITE_4(sc, IWI_CSR_RST, IWI_RST_SOFT_RESET);
@@ -3237,8 +3228,6 @@
 	iwi_reset_tx_ring(sc, &sc->txq[3]);
 	iwi_reset_rx_ring(sc, &sc->rxq);
 
-	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
-
 	memset(sc->sc_cmd, 0, sizeof(sc->sc_cmd));
 	sc->sc_tx_timer = 0;
 	sc->sc_rfkill_timer = 0;
@@ -3250,13 +3239,25 @@
 }
 
 static void
+iwi_stop(struct iwi_softc *sc)
+{
+	IWI_LOCK_DECL;
+
+	IWI_LOCK(sc);
+	iwi_stop_locked(sc);
+	IWI_UNLOCK(sc);
+}
+
+static void
 iwi_restart(void *arg, int npending)
 {
 	struct iwi_softc *sc = arg;
 	IWI_LOCK_DECL;
 
 	IWI_LOCK(sc);
-	iwi_init_locked(sc, 1);		/* NB: force state machine */
+	/* XXX not right */
+	if (sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING)
+		iwi_init(sc);
 	IWI_UNLOCK(sc);
 }
 
@@ -3276,6 +3277,7 @@
 	struct iwi_softc *sc = arg;
 
 	device_printf(sc->sc_dev, "radio turned on\n");
+
 	iwi_init(sc);
 }
 
@@ -3286,8 +3288,9 @@
 	IWI_LOCK_DECL;
 
 	device_printf(sc->sc_dev, "radio turned off\n");
+
 	IWI_LOCK(sc);
-	iwi_stop(sc);
+	iwi_stop_locked(sc);
 	sc->sc_rfkill_timer = 2;
 	IWI_UNLOCK(sc);
 }
@@ -3535,14 +3538,14 @@
 }
 
 static void
-iwi_ops(void *arg, int npending)
+iwi_ops(void *arg0, int npending)
 {
-	struct iwi_softc *sc = arg;
+	struct iwi_softc *sc = arg0;
 	struct ifnet *ifp = sc->sc_ifp;
 	struct ieee80211com *ic = ifp->if_l2com;
 	struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
 	IWI_LOCK_DECL;
-	int cmd;
+	int cmd, arg;
 
 again:
 	IWI_CMD_LOCK(sc);
@@ -3552,6 +3555,7 @@
 		IWI_CMD_UNLOCK(sc);
 		return;
 	}
+	arg = sc->sc_cmd[sc->sc_cmd_cur];
 	sc->sc_cmd[sc->sc_cmd_cur] = 0;	/* free the slot */
 	sc->sc_cmd_cur = (sc->sc_cmd_cur + 1) % IWI_CMD_MAXOPS;

>>> TRUNCATED FOR MAIL (1000 lines) <<<



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