diff options
Diffstat (limited to 'sys')
31 files changed, 1135 insertions, 2229 deletions
diff --git a/sys/dev/if_ndis/if_ndis.c b/sys/dev/if_ndis/if_ndis.c index dfff9e8..8f5054b 100644 --- a/sys/dev/if_ndis/if_ndis.c +++ b/sys/dev/if_ndis/if_ndis.c @@ -50,7 +50,6 @@ __FBSDID("$FreeBSD$"); #include <sys/proc.h> #include <sys/sysctl.h> #include <sys/kthread.h> -#include <sys/taskqueue.h> #include <net/if.h> @@ -173,7 +172,7 @@ static int ndis_newstate (struct ieee80211vap *, enum ieee80211_state, int); static int ndis_nettype_chan (uint32_t); static int ndis_nettype_mode (uint32_t); -static void ndis_scan (void *, int); +static void ndis_scan (void *); static void ndis_scan_results (struct ndis_softc *); static void ndis_scan_start (struct ieee80211com *); static void ndis_scan_end (struct ieee80211com *); @@ -184,8 +183,6 @@ static void ndis_init (void *); static void ndis_stop (struct ndis_softc *); static int ndis_ifmedia_upd (struct ifnet *); static void ndis_ifmedia_sts (struct ifnet *, struct ifmediareq *); -static void ndis_auth (void *, int); -static void ndis_assoc (void *, int); static int ndis_get_assoc (struct ndis_softc *, ndis_wlan_bssid_ex **); static int ndis_probe_offload (struct ndis_softc *); static int ndis_set_offload (struct ndis_softc *); @@ -741,13 +738,7 @@ ndis_attach(dev) uint32_t arg; int r; - sc->ndis_tq = taskqueue_create("nids_taskq", M_NOWAIT | M_ZERO, - taskqueue_thread_enqueue, &sc->ndis_tq); - taskqueue_start_threads(&sc->ndis_tq, 1, PI_NET, "%s taskq", - device_get_nameunit(dev)); - TASK_INIT(&sc->ndis_scantask, 0, ndis_scan, sc); - TASK_INIT(&sc->ndis_authtask, 0, ndis_auth, sc); - TASK_INIT(&sc->ndis_assoctask, 0, ndis_assoc, sc); + callout_init(&sc->ndis_scan_callout, CALLOUT_MPSAFE); ifp->if_ioctl = ndis_ioctl_80211; ic->ic_ifp = ifp; @@ -1054,12 +1045,6 @@ ndis_detach(dev) } else NDIS_UNLOCK(sc); - if (sc->ndis_80211) { - taskqueue_drain(sc->ndis_tq, &sc->ndis_scantask); - taskqueue_drain(sc->ndis_tq, &sc->ndis_authtask); - taskqueue_drain(sc->ndis_tq, &sc->ndis_assoctask); - } - if (sc->ndis_tickitem != NULL) IoFreeWorkItem(sc->ndis_tickitem); if (sc->ndis_startitem != NULL) @@ -1121,8 +1106,6 @@ ndis_detach(dev) if (sc->ndis_iftype == PCIBus) bus_dma_tag_destroy(sc->ndis_parent_tag); - if (sc->ndis_80211) - taskqueue_free(sc->ndis_tq); return(0); } @@ -2419,30 +2402,6 @@ ndis_setstate_80211(sc) } static void -ndis_auth(void *arg, int npending) -{ - struct ndis_softc *sc = arg; - struct ifnet *ifp = sc->ifp; - struct ieee80211com *ic = ifp->if_l2com; - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); - - vap->iv_state = IEEE80211_S_AUTH; - ndis_auth_and_assoc(sc, vap); -} - -static void -ndis_assoc(void *arg, int npending) -{ - struct ndis_softc *sc = arg; - struct ifnet *ifp = sc->ifp; - struct ieee80211com *ic = ifp->if_l2com; - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); - - vap->iv_state = IEEE80211_S_ASSOC; - ndis_auth_and_assoc(sc, vap); -} - -static void ndis_auth_and_assoc(sc, vap) struct ndis_softc *sc; struct ieee80211vap *vap; @@ -2656,9 +2615,6 @@ ndis_auth_and_assoc(sc, vap) if (rval) device_printf (sc->ndis_dev, "set ssid failed: %d\n", rval); - if (vap->iv_state == IEEE80211_S_AUTH) - ieee80211_new_state(vap, IEEE80211_S_ASSOC, 0); - return; } @@ -3304,13 +3260,18 @@ ndis_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) return nvp->newstate(vap, nstate, arg); case IEEE80211_S_ASSOC: if (ostate != IEEE80211_S_AUTH) { - taskqueue_enqueue(sc->ndis_tq, &sc->ndis_assoctask); - return EINPROGRESS; + IEEE80211_UNLOCK(ic); + ndis_auth_and_assoc(sc, vap); + IEEE80211_LOCK(ic); } break; case IEEE80211_S_AUTH: - taskqueue_enqueue(sc->ndis_tq, &sc->ndis_authtask); - return EINPROGRESS; + IEEE80211_UNLOCK(ic); + ndis_auth_and_assoc(sc, vap); + if (vap->iv_state == IEEE80211_S_AUTH) /* XXX */ + ieee80211_new_state(vap, IEEE80211_S_ASSOC, 0); + IEEE80211_LOCK(ic); + break; default: break; } @@ -3318,54 +3279,18 @@ ndis_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) } static void -ndis_scan(void *arg, int npending) +ndis_scan(void *arg) { struct ndis_softc *sc = arg; struct ieee80211com *ic; struct ieee80211vap *vap; - struct ieee80211_scan_state *ss; - ndis_80211_ssid ssid; - int error, len; ic = sc->ifp->if_l2com; - ss = ic->ic_scan; vap = TAILQ_FIRST(&ic->ic_vaps); - if (!NDIS_INITIALIZED(sc)) { - DPRINTF(("%s: scan aborted\n", __func__)); - ieee80211_cancel_scan(vap); - return; - } - - len = sizeof(ssid); - bzero((char *)&ssid, len); - if (ss->ss_nssid == 0) - ssid.ns_ssidlen = 1; - else { - /* Perform a directed scan */ - ssid.ns_ssidlen = ss->ss_ssid[0].len; - bcopy(ss->ss_ssid[0].ssid, ssid.ns_ssid, ssid.ns_ssidlen); - } - - error = ndis_set_info(sc, OID_802_11_SSID, &ssid, &len); - if (error) - DPRINTF(("%s: set ESSID failed\n", __func__)); - - len = 0; - error = ndis_set_info(sc, OID_802_11_BSSID_LIST_SCAN, - NULL, &len); - if (error) { - DPRINTF(("%s: scan command failed\n", __func__)); - ieee80211_cancel_scan(vap); - return; - } - - pause("ssidscan", hz * 3); - if (!NDIS_INITIALIZED(sc)) - /* The interface was downed while we were sleeping */ - return; - + NDIS_LOCK(sc); ndis_scan_results(sc); + NDIS_UNLOCK(sc); ieee80211_scan_done(vap); } @@ -3496,8 +3421,48 @@ ndis_scan_start(struct ieee80211com *ic) { struct ifnet *ifp = ic->ic_ifp; struct ndis_softc *sc = ifp->if_softc; + struct ieee80211vap *vap; + struct ieee80211_scan_state *ss; + ndis_80211_ssid ssid; + int error, len; + + ss = ic->ic_scan; + vap = TAILQ_FIRST(&ic->ic_vaps); + + NDIS_LOCK(sc); + if (!NDIS_INITIALIZED(sc)) { + DPRINTF(("%s: scan aborted\n", __func__)); + NDIS_UNLOCK(sc); + ieee80211_cancel_scan(vap); + return; + } - taskqueue_enqueue(sc->ndis_tq, &sc->ndis_scantask); + len = sizeof(ssid); + bzero((char *)&ssid, len); + if (ss->ss_nssid == 0) + ssid.ns_ssidlen = 1; + else { + /* Perform a directed scan */ + ssid.ns_ssidlen = ss->ss_ssid[0].len; + bcopy(ss->ss_ssid[0].ssid, ssid.ns_ssid, ssid.ns_ssidlen); + } + + error = ndis_set_info(sc, OID_802_11_SSID, &ssid, &len); + if (error) + DPRINTF(("%s: set ESSID failed\n", __func__)); + + len = 0; + error = ndis_set_info(sc, OID_802_11_BSSID_LIST_SCAN, + NULL, &len); + if (error) { + DPRINTF(("%s: scan command failed\n", __func__)); + NDIS_UNLOCK(sc); + ieee80211_cancel_scan(vap); + return; + } + NDIS_UNLOCK(sc); + /* Set a timer to collect the results */ + callout_reset(&sc->ndis_scan_callout, hz * 3, ndis_scan, sc); } static void diff --git a/sys/dev/if_ndis/if_ndisvar.h b/sys/dev/if_ndis/if_ndisvar.h index 6db48a6..fc7ae4c 100644 --- a/sys/dev/if_ndis/if_ndisvar.h +++ b/sys/dev/if_ndis/if_ndisvar.h @@ -180,6 +180,7 @@ struct ndis_softc { ndis_miniport_block *ndis_block; ndis_miniport_characteristics *ndis_chars; interface_type ndis_type; + struct callout ndis_scan_callout; struct callout ndis_stat_callout; int ndis_maxpkts; ndis_oid *ndis_oids; @@ -219,10 +220,6 @@ struct ndis_softc { struct ifqueue ndis_rxqueue; kspin_lock ndis_rxlock; - struct taskqueue *ndis_tq; /* private task queue */ - struct task ndis_scantask; - struct task ndis_authtask; - struct task ndis_assoctask; int (*ndis_newstate)(struct ieee80211com *, enum ieee80211_state, int); int ndis_tx_timer; diff --git a/sys/dev/ipw/if_ipw.c b/sys/dev/ipw/if_ipw.c index 5463f0a..9d67724 100644 --- a/sys/dev/ipw/if_ipw.c +++ b/sys/dev/ipw/if_ipw.c @@ -118,10 +118,6 @@ static void ipw_media_status(struct ifnet *, struct ifmediareq *); static int ipw_newstate(struct ieee80211vap *, enum ieee80211_state, int); static uint16_t ipw_read_prom_word(struct ipw_softc *, uint8_t); static void ipw_rx_cmd_intr(struct ipw_softc *, struct ipw_soft_buf *); -static void ipw_assocsuccess(void *, int); -static void ipw_assocfailed(void *, int); -static void ipw_scandone(void *, int); -static void ipw_bmiss(void *, int); static void ipw_rx_newstate_intr(struct ipw_softc *, struct ipw_soft_buf *); static void ipw_rx_data_intr(struct ipw_softc *, struct ipw_status *, struct ipw_soft_bd *, struct ipw_soft_buf *); @@ -147,8 +143,8 @@ static int ipw_reset(struct ipw_softc *); static int ipw_load_ucode(struct ipw_softc *, const char *, int); static int ipw_load_firmware(struct ipw_softc *, const char *, int); static int ipw_config(struct ipw_softc *); -static void ipw_assoc_task(void *, int); -static void ipw_disassoc_task(void *, int); +static void ipw_assoc(struct ieee80211com *, struct ieee80211vap *); +static void ipw_disassoc(struct ieee80211com *, struct ieee80211vap *); static void ipw_init_task(void *, int); static void ipw_init(void *); static void ipw_init_locked(struct ipw_softc *); @@ -166,7 +162,6 @@ static void ipw_read_mem_1(struct ipw_softc *, bus_size_t, uint8_t *, #endif static void ipw_write_mem_1(struct ipw_softc *, bus_size_t, const uint8_t *, bus_size_t); -static void ipw_scan_task(void *, int); static int ipw_scan(struct ipw_softc *); static void ipw_scan_start(struct ieee80211com *); static void ipw_scan_end(struct ieee80211com *); @@ -239,8 +234,6 @@ ipw_attach(device_t dev) MTX_DEF | MTX_RECURSE); TASK_INIT(&sc->sc_init_task, 0, ipw_init_task, sc); - TASK_INIT(&sc->sc_scan_task, 0, ipw_scan_task, sc); - TASK_INIT(&sc->sc_bmiss_task, 0, ipw_bmiss, sc); callout_init_mtx(&sc->sc_wdtimer, &sc->sc_mtx, 0); if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { @@ -417,9 +410,7 @@ ipw_detach(device_t dev) ieee80211_ifdetach(ic); callout_drain(&sc->sc_wdtimer); - taskqueue_drain(taskqueue_swi, &sc->sc_init_task); - taskqueue_drain(taskqueue_swi, &sc->sc_scan_task); - taskqueue_drain(taskqueue_swi, &sc->sc_bmiss_task); + ieee80211_draintask(ic, &sc->sc_init_task); ipw_release(sc); @@ -511,12 +502,6 @@ ipw_vap_create(struct ieee80211com *ic, return NULL; vap = &ivp->vap; - TASK_INIT(&ivp->assoc_task, 0, ipw_assoc_task, vap); - TASK_INIT(&ivp->disassoc_task, 0, ipw_disassoc_task, vap); - TASK_INIT(&ivp->assoc_success_task, 0, ipw_assocsuccess, vap); - TASK_INIT(&ivp->assoc_failed_task, 0, ipw_assocfailed, vap); - TASK_INIT(&ivp->scandone_task, 0, ipw_scandone, vap); - ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac); /* override with driver methods */ ivp->newstate = vap->iv_newstate; @@ -894,11 +879,15 @@ ipw_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) struct ieee80211com *ic = vap->iv_ic; struct ifnet *ifp = ic->ic_ifp; struct ipw_softc *sc = ifp->if_softc; + enum ieee80211_state ostate; DPRINTF(("%s: %s -> %s flags 0x%x\n", __func__, ieee80211_state_name[vap->iv_state], ieee80211_state_name[nstate], sc->flags)); + ostate = vap->iv_state; + IEEE80211_UNLOCK(ic); + switch (nstate) { case IEEE80211_S_RUN: if (ic->ic_opmode == IEEE80211_M_IBSS) { @@ -910,39 +899,33 @@ ipw_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) * 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) { - taskqueue_enqueue(taskqueue_swi, - &IPW_VAP(vap)->assoc_task); - return EINPROGRESS; - } + if (ostate == IEEE80211_S_SCAN) + ipw_assoc(ic, vap); } break; case IEEE80211_S_INIT: if (sc->flags & IPW_FLAG_ASSOCIATED) - taskqueue_enqueue(taskqueue_swi, - &IPW_VAP(vap)->disassoc_task); + ipw_disassoc(ic, vap); break; case IEEE80211_S_AUTH: - taskqueue_enqueue(taskqueue_swi, &IPW_VAP(vap)->assoc_task); - return EINPROGRESS; + ipw_assoc(ic, vap); + break; case IEEE80211_S_ASSOC: /* * If we are not transitioning from AUTH the resend the * association request. */ - if (vap->iv_state != IEEE80211_S_AUTH) { - taskqueue_enqueue(taskqueue_swi, - &IPW_VAP(vap)->assoc_task); - return EINPROGRESS; - } + if (ostate != IEEE80211_S_AUTH) + ipw_assoc(ic, vap); break; default: break; } + IEEE80211_LOCK(ic); return ivp->newstate(vap, nstate, arg); } @@ -1020,38 +1003,6 @@ ipw_rx_cmd_intr(struct ipw_softc *sc, struct ipw_soft_buf *sbuf) } static void -ipw_assocsuccess(void *arg, int npending) -{ - struct ieee80211vap *vap = arg; - - ieee80211_new_state(vap, IEEE80211_S_RUN, -1); -} - -static void -ipw_assocfailed(void *arg, int npending) -{ - struct ieee80211vap *vap = arg; - - ieee80211_new_state(vap, IEEE80211_S_SCAN, -1); -} - -static void -ipw_scandone(void *arg, int npending) -{ - struct ieee80211vap *vap = arg; - - ieee80211_scan_done(vap); -} - -static void -ipw_bmiss(void *arg, int npending) -{ - struct ieee80211com *ic = arg; - - ieee80211_beacon_miss(ic); -} - -static void ipw_rx_newstate_intr(struct ipw_softc *sc, struct ipw_soft_buf *sbuf) { #define IEEESTATE(vap) ieee80211_state_name[vap->iv_state] @@ -1076,8 +1027,7 @@ ipw_rx_newstate_intr(struct ipw_softc *sc, struct ipw_soft_buf *sbuf) } sc->flags &= ~IPW_FLAG_ASSOCIATING; sc->flags |= IPW_FLAG_ASSOCIATED; - taskqueue_enqueue(taskqueue_swi, - &IPW_VAP(vap)->assoc_success_task); + ieee80211_new_state(vap, IEEE80211_S_RUN, -1); break; case IPW_STATE_SCANNING: @@ -1091,7 +1041,7 @@ ipw_rx_newstate_intr(struct ipw_softc *sc, struct ipw_soft_buf *sbuf) */ if (sc->flags & IPW_FLAG_ASSOCIATED) { /* XXX probably need to issue disassoc to fw */ - taskqueue_enqueue(taskqueue_swi, &sc->sc_bmiss_task); + ieee80211_beacon_miss(ic); } break; @@ -1110,8 +1060,7 @@ ipw_rx_newstate_intr(struct ipw_softc *sc, struct ipw_soft_buf *sbuf) break; } if (sc->flags & IPW_FLAG_SCANNING) { - taskqueue_enqueue(taskqueue_swi, - &IPW_VAP(vap)->scandone_task); + ieee80211_scan_done(vap); sc->flags &= ~IPW_FLAG_SCANNING; sc->sc_scan_timer = 0; } @@ -1122,8 +1071,7 @@ ipw_rx_newstate_intr(struct ipw_softc *sc, struct ipw_soft_buf *sbuf) IEEESTATE(vap), sc->flags)); sc->flags &= ~(IPW_FLAG_ASSOCIATING | IPW_FLAG_ASSOCIATED); if (vap->iv_state == IEEE80211_S_RUN) - taskqueue_enqueue(taskqueue_swi, - &IPW_VAP(vap)->assoc_failed_task); + ieee80211_new_state(vap, IEEE80211_S_SCAN, -1); break; case IPW_STATE_DISABLED: @@ -1432,6 +1380,16 @@ ipw_tx_intr(struct ipw_softc *sc) } static void +ipw_fatal_error_intr(struct ipw_softc *sc) +{ + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + + device_printf(sc->sc_dev, "firmware error\n"); + ieee80211_runtask(ic, &sc->sc_init_task); +} + +static void ipw_intr(void *arg) { struct ipw_softc *sc = arg; @@ -1440,10 +1398,9 @@ ipw_intr(void *arg) IPW_LOCK(sc); - if ((r = CSR_READ_4(sc, IPW_CSR_INTR)) == 0 || r == 0xffffffff) { - IPW_UNLOCK(sc); - return; - } + r = CSR_READ_4(sc, IPW_CSR_INTR); + if (r == 0 || r == 0xffffffff) + goto done; /* disable interrupts */ CSR_WRITE_4(sc, IPW_CSR_INTR_MASK, 0); @@ -1452,9 +1409,8 @@ ipw_intr(void *arg) CSR_WRITE_4(sc, IPW_CSR_INTR, r); if (r & (IPW_INTR_FATAL_ERROR | IPW_INTR_PARITY_ERROR)) { - device_printf(sc->sc_dev, "firmware error\n"); - taskqueue_enqueue(taskqueue_swi, &sc->sc_init_task); - r = 0; /* don't process more interrupts */ + ipw_fatal_error_intr(sc); + goto done; } if (r & IPW_INTR_FW_INIT_DONE) @@ -1468,7 +1424,7 @@ ipw_intr(void *arg) /* re-enable interrupts */ CSR_WRITE_4(sc, IPW_CSR_INTR_MASK, IPW_INTR_MASK); - +done: IPW_UNLOCK(sc); } @@ -2181,20 +2137,6 @@ ipw_setscanopts(struct ipw_softc *sc, uint32_t chanmask, uint32_t flags) return ipw_cmd(sc, IPW_CMD_SET_SCAN_OPTIONS, &opts, sizeof(opts)); } -/* - * Handler for sc_scan_task. This is a simple wrapper around ipw_scan(). - */ -static void -ipw_scan_task(void *context, int pending) -{ - struct ipw_softc *sc = context; - IPW_LOCK_DECL; - - IPW_LOCK(sc); - ipw_scan(sc); - IPW_UNLOCK(sc); -} - static int ipw_scan(struct ipw_softc *sc) { @@ -2258,11 +2200,9 @@ ipw_setchannel(struct ipw_softc *sc, struct ieee80211_channel *chan) } static void -ipw_assoc_task(void *context, int pending) +ipw_assoc(struct ieee80211com *ic, struct ieee80211vap *vap) { - struct ieee80211vap *vap = context; struct ifnet *ifp = vap->iv_ic->ic_ifp; - struct ieee80211com *ic = ifp->if_l2com; struct ipw_softc *sc = ifp->if_softc; struct ieee80211_node *ni = vap->iv_bss; struct ipw_security security; @@ -2353,9 +2293,8 @@ done: } static void -ipw_disassoc_task(void *context, int pending) +ipw_disassoc(struct ieee80211com *ic, struct ieee80211vap *vap) { - struct ieee80211vap *vap = context; struct ifnet *ifp = vap->iv_ic->ic_ifp; struct ieee80211_node *ni = vap->iv_bss; struct ipw_softc *sc = ifp->if_softc; @@ -2729,8 +2668,7 @@ ipw_scan_start(struct ieee80211com *ic) IPW_LOCK_DECL; IPW_LOCK(sc); - if (!(sc->flags & IPW_FLAG_SCANNING)) - taskqueue_enqueue(taskqueue_swi, &sc->sc_scan_task); + ipw_scan(sc); IPW_UNLOCK(sc); } diff --git a/sys/dev/ipw/if_ipwvar.h b/sys/dev/ipw/if_ipwvar.h index de35019..24fb8e8 100644 --- a/sys/dev/ipw/if_ipwvar.h +++ b/sys/dev/ipw/if_ipwvar.h @@ -78,11 +78,6 @@ struct ipw_tx_radiotap_header { struct ipw_vap { struct ieee80211vap vap; - struct task assoc_task; - struct task disassoc_task; - struct task assoc_success_task; - struct task assoc_failed_task; - struct task scandone_task; int (*newstate)(struct ieee80211vap *, enum ieee80211_state, int); @@ -95,9 +90,6 @@ struct ipw_softc { struct mtx sc_mtx; struct task sc_init_task; - struct task sc_scan_task; - struct task sc_chan_task; - struct task sc_bmiss_task; struct callout sc_wdtimer; /* watchdog timer */ uint32_t flags; diff --git a/sys/dev/iwi/if_iwi.c b/sys/dev/iwi/if_iwi.c index 83ab3e5..6957f9b 100644 --- a/sys/dev/iwi/if_iwi.c +++ b/sys/dev/iwi/if_iwi.c @@ -158,9 +158,6 @@ 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_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 *); @@ -186,16 +183,11 @@ 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 *); static void iwi_scan_end(struct ieee80211com *); -static void iwi_scanabort(void *, int); static void iwi_set_channel(struct ieee80211com *); static void iwi_scan_curchan(struct ieee80211_scan_state *, unsigned long maxdwell); -#if 0 -static void iwi_scan_allchan(struct ieee80211com *, unsigned long maxdwell); -#endif static void iwi_scan_mindwell(struct ieee80211_scan_state *); -static void iwi_ops(void *, int); -static int iwi_queue_cmd(struct iwi_softc *, int, unsigned long); static int iwi_auth_and_assoc(struct iwi_softc *, struct ieee80211vap *); +static void iwi_disassoc(void *, int); static int iwi_disassociate(struct iwi_softc *, int quiet); static void iwi_init_locked(struct iwi_softc *); static void iwi_init(void *); @@ -292,24 +284,14 @@ iwi_attach(device_t dev) ic = ifp->if_l2com; IWI_LOCK_INIT(sc); - IWI_CMD_LOCK_INIT(sc); sc->sc_unr = new_unrhdr(1, IWI_MAX_IBSSNODE-1, &sc->sc_mtx); - sc->sc_tq = taskqueue_create("iwi_taskq", M_NOWAIT | M_ZERO, - taskqueue_thread_enqueue, &sc->sc_tq); - taskqueue_start_threads(&sc->sc_tq, 1, PI_NET, "%s taskq", - device_get_nameunit(dev)); - sc->sc_tq2 = taskqueue_create("iwi_taskq2", M_NOWAIT | M_ZERO, - taskqueue_thread_enqueue, &sc->sc_tq2); - taskqueue_start_threads(&sc->sc_tq2, 1, PI_NET, "%s taskq2", - device_get_nameunit(dev)); - TASK_INIT(&sc->sc_radiontask, 0, iwi_radio_on, sc); TASK_INIT(&sc->sc_radiofftask, 0, iwi_radio_off, sc); TASK_INIT(&sc->sc_restarttask, 0, iwi_restart, sc); - TASK_INIT(&sc->sc_opstask, 0, iwi_ops, sc); - TASK_INIT(&sc->sc_scanaborttask, 0, iwi_scanabort, sc); + TASK_INIT(&sc->sc_disassoctask, 0, iwi_disassoc, sc); + callout_init_mtx(&sc->sc_wdtimer, &sc->sc_mtx, 0); callout_init_mtx(&sc->sc_rftimer, &sc->sc_mtx, 0); @@ -483,8 +465,10 @@ iwi_detach(device_t dev) ieee80211_ifdetach(ic); /* NB: do early to drain any pending tasks */ - taskqueue_free(sc->sc_tq); - taskqueue_free(sc->sc_tq2); + ieee80211_draintask(ic, &sc->sc_radiontask); + ieee80211_draintask(ic, &sc->sc_radiofftask); + ieee80211_draintask(ic, &sc->sc_restarttask); + ieee80211_draintask(ic, &sc->sc_disassoctask); iwi_put_firmware(sc); iwi_release_fw_dma(sc); @@ -504,7 +488,6 @@ iwi_detach(device_t dev) delete_unrhdr(sc->sc_unr); IWI_LOCK_DESTROY(sc); - IWI_CMD_LOCK_DESTROY(sc); if_free(ifp); @@ -552,10 +535,6 @@ iwi_vap_create(struct ieee80211com *ic, 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; @@ -987,21 +966,21 @@ iwi_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) ieee80211_state_name[vap->iv_state], ieee80211_state_name[nstate], sc->flags)); + IEEE80211_UNLOCK(ic); + IWI_LOCK(sc); 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, 1); - IWI_UNLOCK(sc); + iwi_disassociate(sc, 0); break; case IEEE80211_S_AUTH: - iwi_queue_cmd(sc, IWI_AUTH, arg); - return EINPROGRESS; + iwi_auth_and_assoc(sc, vap); + break; case IEEE80211_S_RUN: if (vap->iv_opmode == IEEE80211_M_IBSS && vap->iv_state == IEEE80211_S_SCAN) { @@ -1013,8 +992,7 @@ iwi_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) * AUTH -> RUN transition and we want to do nothing. * This is all totally bogus and needs to be redone. */ - iwi_queue_cmd(sc, IWI_ASSOC, 0); - return EINPROGRESS; + iwi_auth_and_assoc(sc, vap); } break; case IEEE80211_S_ASSOC: @@ -1025,11 +1003,13 @@ iwi_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) */ if (vap->iv_state == IEEE80211_S_AUTH) break; - iwi_queue_cmd(sc, IWI_ASSOC, arg); - return EINPROGRESS; + iwi_auth_and_assoc(sc, vap); + break; default: break; } + IWI_UNLOCK(sc); + IEEE80211_LOCK(ic); return ivp->iwi_newstate(vap, nstate, arg); } @@ -1106,6 +1086,7 @@ static int iwi_wme_update(struct ieee80211com *ic) { struct iwi_softc *sc = ic->ic_ifp->if_softc; + struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); /* * We may be called to update the WME parameters in @@ -1115,7 +1096,9 @@ iwi_wme_update(struct ieee80211com *ic) * 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, 0); + if (vap->iv_state == IEEE80211_S_RUN) + (void) iwi_wme_setparams(sc, ic); + return (0); } static int @@ -1389,30 +1372,6 @@ iwi_checkforqos(struct ieee80211vap *vap, */ 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; @@ -1454,8 +1413,7 @@ iwi_notification_intr(struct iwi_softc *sc, struct iwi_notif *notif) switch (auth->state) { case IWI_AUTH_SUCCESS: DPRINTFN(2, ("Authentication succeeeded\n")); - taskqueue_enqueue(taskqueue_swi, - &IWI_VAP(vap)->iwi_authsuccess_task); + ieee80211_new_state(vap, IEEE80211_S_ASSOC, -1); break; case IWI_AUTH_FAIL: /* @@ -1472,8 +1430,7 @@ iwi_notification_intr(struct iwi_softc *sc, struct iwi_notif *notif) DPRINTFN(2, ("Deauthenticated\n")); vap->iv_stats.is_rx_deauth++; } - taskqueue_enqueue(taskqueue_swi, - &IWI_VAP(vap)->iwi_assocfailed_task); + ieee80211_new_state(vap, IEEE80211_S_SCAN, -1); break; case IWI_AUTH_SENT_1: case IWI_AUTH_RECV_2: @@ -1506,8 +1463,7 @@ iwi_notification_intr(struct iwi_softc *sc, struct iwi_notif *notif) iwi_checkforqos(vap, (const struct ieee80211_frame *)(assoc+1), le16toh(notif->len) - sizeof(*assoc)); - taskqueue_enqueue(taskqueue_swi, - &IWI_VAP(vap)->iwi_assocsuccess_task); + ieee80211_new_state(vap, IEEE80211_S_RUN, -1); break; case IWI_ASSOC_INIT: sc->flags &= ~IWI_FLAG_ASSOCIATED; @@ -1515,16 +1471,14 @@ iwi_notification_intr(struct iwi_softc *sc, struct iwi_notif *notif) 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); + ieee80211_new_state(vap, IEEE80211_S_SCAN, -1); break; case IWI_FW_DISASSOCIATING: DPRINTFN(2, ("Dissassociated\n")); IWI_STATE_END(sc, IWI_FW_DISASSOCIATING); vap->iv_stats.is_rx_disassoc++; - taskqueue_enqueue(taskqueue_swi, - &IWI_VAP(vap)->iwi_assocfailed_task); + ieee80211_new_state(vap, IEEE80211_S_SCAN, -1); break; } break; @@ -1563,7 +1517,7 @@ iwi_notification_intr(struct iwi_softc *sc, struct iwi_notif *notif) * to disassociate and then on completion we'll * kick the state machine to scan. */ - iwi_queue_cmd(sc, IWI_DISASSOC, 1); + ieee80211_runtask(ic, &sc->sc_disassoctask); } } break; @@ -1664,6 +1618,29 @@ iwi_tx_intr(struct iwi_softc *sc, struct iwi_tx_ring *txq) } static void +iwi_fatal_error_intr(struct iwi_softc *sc) +{ + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + + device_printf(sc->sc_dev, "firmware error\n"); + ieee80211_runtask(ic, &sc->sc_restarttask); + + sc->flags &= ~IWI_FLAG_BUSY; + sc->sc_busy_timer = 0; + wakeup(sc); +} + +static void +iwi_radio_off_intr(struct iwi_softc *sc) +{ + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + + ieee80211_runtask(ic, &sc->sc_radiofftask); +} + +static void iwi_intr(void *arg) { struct iwi_softc *sc = arg; @@ -1681,12 +1658,8 @@ iwi_intr(void *arg) CSR_WRITE_4(sc, IWI_CSR_INTR, r); if (r & IWI_INTR_FATAL_ERROR) { - device_printf(sc->sc_dev, "firmware error\n"); - taskqueue_enqueue(sc->sc_tq2, &sc->sc_restarttask); - - sc->flags &= ~IWI_FLAG_BUSY; - sc->sc_busy_timer = 0; - wakeup(sc); + iwi_fatal_error_intr(sc); + goto done; } if (r & IWI_INTR_FW_INITED) { @@ -1695,7 +1668,7 @@ iwi_intr(void *arg) } if (r & IWI_INTR_RADIO_OFF) - taskqueue_enqueue(sc->sc_tq, &sc->sc_radiofftask); + iwi_radio_off_intr(sc); if (r & IWI_INTR_CMD_DONE) { sc->flags &= ~IWI_FLAG_BUSY; @@ -1722,7 +1695,7 @@ iwi_intr(void *arg) /* XXX rate-limit */ device_printf(sc->sc_dev, "parity error\n"); } - +done: IWI_UNLOCK(sc); } @@ -2008,6 +1981,7 @@ iwi_watchdog(void *arg) { struct iwi_softc *sc = arg; struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; IWI_LOCK_ASSERT(sc); @@ -2015,25 +1989,25 @@ iwi_watchdog(void *arg) if (--sc->sc_tx_timer == 0) { if_printf(ifp, "device timeout\n"); ifp->if_oerrors++; - taskqueue_enqueue(sc->sc_tq2, &sc->sc_restarttask); + ieee80211_runtask(ic, &sc->sc_restarttask); } } 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_tq2, &sc->sc_restarttask); if (sc->fw_state == IWI_FW_SCANNING) { struct ieee80211com *ic = ifp->if_l2com; ieee80211_cancel_scan(TAILQ_FIRST(&ic->ic_vaps)); } + ieee80211_runtask(ic, &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_tq2, &sc->sc_restarttask); + ieee80211_runtask(ic, &sc->sc_restarttask); } } callout_reset(&sc->sc_wdtimer, hz, iwi_watchdog, sc); @@ -2665,7 +2639,7 @@ scan_band(const struct ieee80211_channel *c) * Start a scan on the current channel or all channels. */ static int -iwi_scanchan(struct iwi_softc *sc, unsigned long maxdwell, int mode) +iwi_scanchan(struct iwi_softc *sc, unsigned long maxdwell, int allchan) { struct ieee80211com *ic; struct ieee80211_channel *chan; @@ -2712,7 +2686,7 @@ iwi_scanchan(struct iwi_softc *sc, unsigned long maxdwell, int mode) return (error); } - if (mode == IWI_SCAN_ALLCHAN) { + if (allchan) { int i, next, band, b, bstart; /* * Convert scan list to run-length encoded channel list @@ -2781,20 +2755,6 @@ iwi_scanchan(struct iwi_softc *sc, unsigned long maxdwell, int mode) return (iwi_cmd(sc, IWI_CMD_SCAN_EXT, &scan, sizeof scan)); } -static void -iwi_scanabort(void *arg, int npending) -{ - struct iwi_softc *sc = arg; - IWI_LOCK_DECL; - - IWI_LOCK(sc); - sc->flags &= ~IWI_FLAG_CHANNEL_SCAN; - /* NB: make sure we're still scanning */ - if (sc->fw_state == IWI_FW_SCANNING) - iwi_cmd(sc, IWI_CMD_ABORT_SCAN, NULL, 0); - IWI_UNLOCK(sc); -} - static int iwi_set_sensitivity(struct iwi_softc *sc, int8_t rssi_dbm) { @@ -2986,6 +2946,17 @@ done: return (error); } +static void +iwi_disassoc(void *arg, int pending) +{ + struct iwi_softc *sc = arg; + IWI_LOCK_DECL; + + IWI_LOCK(sc); + iwi_disassociate(sc, 0); + IWI_UNLOCK(sc); +} + static int iwi_disassociate(struct iwi_softc *sc, int quiet) { @@ -3086,9 +3057,6 @@ iwi_init_locked(struct iwi_softc *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; @@ -3183,8 +3151,6 @@ iwi_stop_locked(void *priv) 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; @@ -3204,7 +3170,6 @@ iwi_stop_locked(void *priv) iwi_reset_tx_ring(sc, &sc->txq[3]); iwi_reset_rx_ring(sc, &sc->rxq); - memset(sc->sc_cmd, 0, sizeof(sc->sc_cmd)); sc->sc_tx_timer = 0; sc->sc_state_timer = 0; sc->sc_busy_timer = 0; @@ -3266,8 +3231,10 @@ iwi_rfkill_poll(void *arg) * it is enabled so we must poll for the latter. */ if (!iwi_getrfkill(sc)) { - taskqueue_unblock(sc->sc_tq); - taskqueue_enqueue(sc->sc_tq, &sc->sc_radiontask); + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + + ieee80211_runtask(ic, &sc->sc_radiontask); return; } callout_reset(&sc->sc_rftimer, 2*hz, iwi_rfkill_poll, sc); @@ -3533,114 +3500,9 @@ iwi_ledattach(struct iwi_softc *sc) } static void -iwi_ops(void *arg0, int npending) -{ - static const char *opnames[] = { - [IWI_CMD_FREE] = "FREE", - [IWI_SCAN_START] = "SCAN_START", - [IWI_SET_CHANNEL] = "SET_CHANNEL", - [IWI_AUTH] = "AUTH", - [IWI_ASSOC] = "ASSOC", - [IWI_DISASSOC] = "DISASSOC", - [IWI_SCAN_CURCHAN] = "SCAN_CURCHAN", - [IWI_SCAN_ALLCHAN] = "SCAN_ALLCHAN", - [IWI_SET_WME] = "SET_WME", - }; - 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; - unsigned long arg; - -again: - IWI_CMD_LOCK(sc); - cmd = sc->sc_cmd[sc->sc_cmd_cur]; - if (cmd == IWI_CMD_FREE) { - /* No more commands to process */ - IWI_CMD_UNLOCK(sc); - return; - } - arg = sc->sc_arg[sc->sc_cmd_cur]; - sc->sc_cmd[sc->sc_cmd_cur] = IWI_CMD_FREE; /* free the slot */ - sc->sc_cmd_cur = (sc->sc_cmd_cur + 1) % IWI_CMD_MAXOPS; - IWI_CMD_UNLOCK(sc); - - IWI_LOCK(sc); - while (sc->fw_state != IWI_FW_IDLE || (sc->flags & IWI_FLAG_BUSY)) { - msleep(sc, &sc->sc_mtx, 0, "iwicmd", hz/10); - } - - if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { - IWI_UNLOCK(sc); - return; - } - - DPRINTF(("%s: %s arg %lu\n", __func__, opnames[cmd], arg)); - switch (cmd) { - case IWI_AUTH: - case IWI_ASSOC: - if (cmd == IWI_AUTH) - vap->iv_state = IEEE80211_S_AUTH; - else - vap->iv_state = IEEE80211_S_ASSOC; - iwi_auth_and_assoc(sc, vap); - /* NB: completion done in iwi_notification_intr */ - break; - case IWI_DISASSOC: - iwi_disassociate(sc, 0); - break; - case IWI_SET_WME: - if (vap->iv_state == IEEE80211_S_RUN) - (void) iwi_wme_setparams(sc, ic); - break; - case IWI_SCAN_START: - sc->flags |= IWI_FLAG_CHANNEL_SCAN; - break; - case IWI_SCAN_CURCHAN: - case IWI_SCAN_ALLCHAN: - if (!(sc->flags & IWI_FLAG_CHANNEL_SCAN)) { - DPRINTF(("%s: ic_scan_curchan while not scanning\n", - __func__)); - goto done; - } - if (iwi_scanchan(sc, arg, cmd)) - ieee80211_cancel_scan(vap); - break; - } -done: - IWI_UNLOCK(sc); - - /* Take another pass */ - goto again; -} - -static int -iwi_queue_cmd(struct iwi_softc *sc, int cmd, unsigned long arg) -{ - IWI_CMD_LOCK(sc); - if (sc->sc_cmd[sc->sc_cmd_next] != 0) { - IWI_CMD_UNLOCK(sc); - DPRINTF(("%s: command %d dropped\n", __func__, cmd)); - return (EBUSY); - } - - sc->sc_cmd[sc->sc_cmd_next] = cmd; - sc->sc_arg[sc->sc_cmd_next] = arg; - sc->sc_cmd_next = (sc->sc_cmd_next + 1) % IWI_CMD_MAXOPS; - taskqueue_enqueue(sc->sc_tq, &sc->sc_opstask); - IWI_CMD_UNLOCK(sc); - return (0); -} - -static void iwi_scan_start(struct ieee80211com *ic) { - struct ifnet *ifp = ic->ic_ifp; - struct iwi_softc *sc = ifp->if_softc; - - iwi_queue_cmd(sc, IWI_SCAN_START, 0); + /* ignore */ } static void @@ -3658,20 +3520,13 @@ iwi_scan_curchan(struct ieee80211_scan_state *ss, unsigned long maxdwell) struct ieee80211vap *vap = ss->ss_vap; struct ifnet *ifp = vap->iv_ic->ic_ifp; struct iwi_softc *sc = ifp->if_softc; + IWI_LOCK_DECL; - iwi_queue_cmd(sc, IWI_SCAN_CURCHAN, maxdwell); -} - -#if 0 -static void -iwi_scan_allchan(struct ieee80211com *ic, unsigned long maxdwell) -{ - struct ifnet *ifp = ic->ic_ifp; - struct iwi_softc *sc = ifp->if_softc; - - iwi_queue_cmd(sc, IWI_SCAN_ALLCHAN, maxdwell); + IWI_LOCK(sc); + if (iwi_scanchan(sc, maxdwell, 0)) + ieee80211_cancel_scan(vap); + IWI_UNLOCK(sc); } -#endif static void iwi_scan_mindwell(struct ieee80211_scan_state *ss) @@ -3684,6 +3539,12 @@ iwi_scan_end(struct ieee80211com *ic) { struct ifnet *ifp = ic->ic_ifp; struct iwi_softc *sc = ifp->if_softc; + IWI_LOCK_DECL; - taskqueue_enqueue(sc->sc_tq2, &sc->sc_scanaborttask); + IWI_LOCK(sc); + sc->flags &= ~IWI_FLAG_CHANNEL_SCAN; + /* NB: make sure we're still scanning */ + if (sc->fw_state == IWI_FW_SCANNING) + iwi_cmd(sc, IWI_CMD_ABORT_SCAN, NULL, 0); + IWI_UNLOCK(sc); } diff --git a/sys/dev/iwi/if_iwivar.h b/sys/dev/iwi/if_iwivar.h index abc6f9c..25db9cf 100644 --- a/sys/dev/iwi/if_iwivar.h +++ b/sys/dev/iwi/if_iwivar.h @@ -116,9 +116,6 @@ struct iwi_fw { struct iwi_vap { struct ieee80211vap iwi_vap; - struct task iwi_authsuccess_task; - struct task iwi_assocsuccess_task; - struct task iwi_assocfailed_task; int (*iwi_newstate)(struct ieee80211vap *, enum ieee80211_state, int); @@ -131,12 +128,8 @@ struct iwi_softc { device_t sc_dev; struct mtx sc_mtx; - struct mtx sc_cmdlock; - char sc_cmdname[12]; /* e.g. "iwi0_cmd" */ uint8_t sc_mcast[IEEE80211_ADDR_LEN]; struct unrhdr *sc_unr; - struct taskqueue *sc_tq; /* private task queue */ - struct taskqueue *sc_tq2; /* reset task queue */ uint32_t flags; #define IWI_FLAG_FW_INITED (1 << 0) @@ -195,9 +188,8 @@ struct iwi_softc { struct task sc_radiontask; /* radio on processing */ struct task sc_radiofftask; /* radio off processing */ - struct task sc_scanaborttask; /* cancel active scan */ struct task sc_restarttask; /* restart adapter processing */ - struct task sc_opstask; /* scan / auth processing */ + struct task sc_disassoctask; unsigned int sc_softled : 1, /* enable LED gpio status */ sc_ledstate: 1, /* LED on/off state */ @@ -219,21 +211,6 @@ struct iwi_softc { int sc_state_timer; /* firmware state timer */ int sc_busy_timer; /* firmware cmd timer */ -#define IWI_CMD_MAXOPS 10 - int sc_cmd[IWI_CMD_MAXOPS]; - unsigned long sc_arg[IWI_CMD_MAXOPS]; - int sc_cmd_cur; /* current queued scan task */ - int sc_cmd_next; /* last queued scan task */ -#define IWI_CMD_FREE 0 /* for marking slots unused */ -#define IWI_SCAN_START 1 -#define IWI_SET_CHANNEL 2 -#define IWI_AUTH 3 -#define IWI_ASSOC 4 -#define IWI_DISASSOC 5 -#define IWI_SCAN_CURCHAN 6 -#define IWI_SCAN_ALLCHAN 7 -#define IWI_SET_WME 8 - struct iwi_rx_radiotap_header sc_rxtap; int sc_rxtap_len; @@ -277,11 +254,3 @@ struct iwi_softc { if (!__waslocked) \ mtx_unlock(&(sc)->sc_mtx); \ } while (0) -#define IWI_CMD_LOCK_INIT(sc) do { \ - snprintf((sc)->sc_cmdname, sizeof((sc)->sc_cmdname), "%s_cmd", \ - device_get_nameunit((sc)->sc_dev)); \ - mtx_init(&(sc)->sc_cmdlock, (sc)->sc_cmdname, NULL, MTX_DEF); \ -} while (0) -#define IWI_CMD_LOCK_DESTROY(sc) mtx_destroy(&(sc)->sc_cmdlock) -#define IWI_CMD_LOCK(sc) mtx_lock(&(sc)->sc_cmdlock) -#define IWI_CMD_UNLOCK(sc) mtx_unlock(&(sc)->sc_cmdlock) diff --git a/sys/dev/iwn/if_iwn.c b/sys/dev/iwn/if_iwn.c index 2928c0f..f32bdaa 100644 --- a/sys/dev/iwn/if_iwn.c +++ b/sys/dev/iwn/if_iwn.c @@ -129,7 +129,6 @@ void iwn_rx_intr(struct iwn_softc *, struct iwn_rx_desc *, void iwn_rx_statistics(struct iwn_softc *, struct iwn_rx_desc *); void iwn_tx_intr(struct iwn_softc *, struct iwn_rx_desc *); void iwn_cmd_intr(struct iwn_softc *, struct iwn_rx_desc *); -static void iwn_bmiss(void *, int); void iwn_notif_intr(struct iwn_softc *); void iwn_intr(void *); void iwn_read_eeprom(struct iwn_softc *, @@ -166,8 +165,8 @@ void iwn_compute_differential_gain(struct iwn_softc *, void iwn_tune_sensitivity(struct iwn_softc *, const struct iwn_rx_stats *); int iwn_send_sensitivity(struct iwn_softc *); -int iwn_auth(struct iwn_softc *); -int iwn_run(struct iwn_softc *); +int iwn_auth(struct iwn_softc *, struct ieee80211vap *); +int iwn_run(struct iwn_softc *, struct ieee80211vap *); int iwn_scan(struct iwn_softc *); int iwn_config(struct iwn_softc *); void iwn_post_alive(struct iwn_softc *); @@ -183,8 +182,9 @@ static void iwn_scan_end(struct ieee80211com *); static void iwn_set_channel(struct ieee80211com *); static void iwn_scan_curchan(struct ieee80211_scan_state *, unsigned long); static void iwn_scan_mindwell(struct ieee80211_scan_state *); -static void iwn_ops(void *, int); -static int iwn_queue_cmd( struct iwn_softc *, int, int, int); +static void iwn_hwreset(void *, int); +static void iwn_radioon(void *, int); +static void iwn_radiooff(void *, int); static void iwn_bpfattach(struct iwn_softc *); static void iwn_sysctlattach(struct iwn_softc *); @@ -213,7 +213,6 @@ enum { printf(fmt, __VA_ARGS__); \ } while (0) -static const char *iwn_ops_str(int); static const char *iwn_intr_str(uint8_t); #else #define DPRINTF(sc, m, fmt, ...) do { (void) sc; } while (0) @@ -296,20 +295,10 @@ iwn_attach(device_t dev) } IWN_LOCK_INIT(sc); - IWN_CMD_LOCK_INIT(sc); callout_init_mtx(&sc->sc_timer_to, &sc->sc_mtx, 0); - - /* - * Create the taskqueues used by the driver. Primarily - * sc_tq handles most the task - */ - sc->sc_tq = taskqueue_create("iwn_taskq", M_NOWAIT | M_ZERO, - taskqueue_thread_enqueue, &sc->sc_tq); - taskqueue_start_threads(&sc->sc_tq, 1, PI_NET, "%s taskq", - device_get_nameunit(dev)); - - TASK_INIT(&sc->sc_ops_task, 0, iwn_ops, sc ); - TASK_INIT(&sc->sc_bmiss_task, 0, iwn_bmiss, sc); + TASK_INIT(&sc->sc_reinit_task, 0, iwn_hwreset, sc ); + TASK_INIT(&sc->sc_radioon_task, 0, iwn_radioon, sc ); + TASK_INIT(&sc->sc_radiooff_task, 0, iwn_radiooff, sc ); /* * Put adapter into a known state. @@ -475,6 +464,10 @@ iwn_cleanup(device_t dev) struct ieee80211com *ic = ifp->if_l2com; int i; + ieee80211_draintask(ic, &sc->sc_reinit_task); + ieee80211_draintask(ic, &sc->sc_radioon_task); + ieee80211_draintask(ic, &sc->sc_radiooff_task); + if (ifp != NULL) { iwn_stop(sc); callout_drain(&sc->sc_timer_to); @@ -499,8 +492,6 @@ iwn_cleanup(device_t dev) bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem); if (ifp != NULL) if_free(ifp); - taskqueue_free(sc->sc_tq); - IWN_CMD_LOCK_DESTROY(sc); IWN_LOCK_DESTROY(sc); return 0; } @@ -983,20 +974,13 @@ iwn_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) ieee80211_state_name[vap->iv_state], ieee80211_state_name[nstate]); + IEEE80211_UNLOCK(ic); IWN_LOCK(sc); callout_stop(&sc->sc_timer_to); - IWN_UNLOCK(sc); - /* - * Some state transitions require issuing a configure request - * to the adapter. This must be done in a blocking context - * so we toss control to the task q thread where the state - * change will be finished after the command completes. - */ if (nstate == IEEE80211_S_AUTH && vap->iv_state != IEEE80211_S_AUTH) { /* !AUTH -> AUTH requires adapter config */ - error = iwn_queue_cmd(sc, IWN_AUTH, arg, IWN_QUEUE_NORMAL); - return (error != 0 ? error : EINPROGRESS); + error = iwn_auth(sc, vap); } if (nstate == IEEE80211_S_RUN && vap->iv_state != IEEE80211_S_RUN) { /* @@ -1004,8 +988,7 @@ iwn_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) * which is done with a firmware cmd. We also defer * starting the timers until that work is done. */ - error = iwn_queue_cmd(sc, IWN_RUN, arg, IWN_QUEUE_NORMAL); - return (error != 0 ? error : EINPROGRESS); + error = iwn_run(sc, vap); } if (nstate == IEEE80211_S_RUN) { /* @@ -1013,6 +996,8 @@ iwn_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) */ iwn_calib_reset(sc); } + IWN_UNLOCK(sc); + IEEE80211_LOCK(ic); return ivp->iv_newstate(vap, nstate, arg); } @@ -1657,15 +1642,6 @@ iwn_cmd_intr(struct iwn_softc *sc, struct iwn_rx_desc *desc) wakeup(&ring->cmd[desc->idx]); } -static void -iwn_bmiss(void *arg, int npending) -{ - struct iwn_softc *sc = arg; - struct ieee80211com *ic = sc->sc_ifp->if_l2com; - - ieee80211_beacon_miss(ic); -} - void iwn_notif_intr(struct iwn_softc *sc) { @@ -1726,8 +1702,7 @@ iwn_notif_intr(struct iwn_softc *sc) if (vap->iv_state == IEEE80211_S_RUN && misses > 5) (void) iwn_init_sensitivity(sc); if (misses >= vap->iv_bmissthreshold) - taskqueue_enqueue(taskqueue_swi, - &sc->sc_bmiss_task); + ieee80211_beacon_miss(ic); break; } case IWN_UC_READY: { @@ -1780,7 +1755,7 @@ iwn_notif_intr(struct iwn_softc *sc) "scan finished nchan=%d status=%d chan=%d\n", scan->nchan, scan->status, scan->chan); - iwn_queue_cmd(sc, IWN_SCAN_NEXT, 0, IWN_QUEUE_NORMAL); + ieee80211_scan_next(vap); break; } } @@ -1792,6 +1767,36 @@ iwn_notif_intr(struct iwn_softc *sc) IWN_WRITE(sc, IWN_RX_WIDX, hw & ~7); } +static void +iwn_rftoggle_intr(struct iwn_softc *sc) +{ + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + uint32_t tmp = IWN_READ(sc, IWN_GPIO_CTL); + + IWN_LOCK_ASSERT(sc); + + device_printf(sc->sc_dev, "RF switch: radio %s\n", + (tmp & IWN_GPIO_RF_ENABLED) ? "enabled" : "disabled"); + if (tmp & IWN_GPIO_RF_ENABLED) + ieee80211_runtask(ic, &sc->sc_radioon_task); + else + ieee80211_runtask(ic, &sc->sc_radiooff_task); +} + +static void +iwn_error_intr(struct iwn_softc *sc, uint32_t r1, uint32_t r2) +{ + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + + IWN_LOCK_ASSERT(sc); + + device_printf(sc->sc_dev, "error, INTR=%b STATUS=0x%x\n", + r1, IWN_INTR_BITS, r2); + ieee80211_runtask(ic, &sc->sc_reinit_task); +} + void iwn_intr(void *arg) { @@ -1820,21 +1825,12 @@ iwn_intr(void *arg) DPRINTF(sc, IWN_DEBUG_INTR, "interrupt reg1=%x reg2=%x\n", r1, r2); - if (r1 & IWN_RF_TOGGLED) { - uint32_t tmp = IWN_READ(sc, IWN_GPIO_CTL); - device_printf(sc->sc_dev, "RF switch: radio %s\n", - (tmp & IWN_GPIO_RF_ENABLED) ? "enabled" : "disabled"); - if (tmp & IWN_GPIO_RF_ENABLED) - iwn_queue_cmd(sc, IWN_RADIO_ENABLE, 0, IWN_QUEUE_CLEAR); - else - iwn_queue_cmd(sc, IWN_RADIO_DISABLE, 0, IWN_QUEUE_CLEAR); - } + if (r1 & IWN_RF_TOGGLED) + iwn_rftoggle_intr(sc); if (r1 & IWN_CT_REACHED) device_printf(sc->sc_dev, "critical temperature reached!\n"); if (r1 & (IWN_SW_ERROR | IWN_HW_ERROR)) { - device_printf(sc->sc_dev, "error, INTR=%b STATUS=0x%x\n", - r1, IWN_INTR_BITS, r2); - iwn_queue_cmd(sc, IWN_REINIT, 0, IWN_QUEUE_CLEAR); + iwn_error_intr(sc, r1, r2); goto done; } if ((r1 & (IWN_RX_INTR | IWN_SW_RX_INTR)) || (r2 & IWN_RX_STATUS_INTR)) @@ -2361,9 +2357,10 @@ iwn_watchdog(struct iwn_softc *sc) { if (sc->sc_tx_timer > 0 && --sc->sc_tx_timer == 0) { struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; if_printf(ifp, "device timeout\n"); - iwn_queue_cmd(sc, IWN_REINIT, 0, IWN_QUEUE_CLEAR); + ieee80211_runtask(ic, &sc->sc_reinit_task); } } @@ -3446,11 +3443,10 @@ iwn_send_sensitivity(struct iwn_softc *sc) } int -iwn_auth(struct iwn_softc *sc) +iwn_auth(struct iwn_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); /*XXX*/ struct ieee80211_node *ni = vap->iv_bss; struct iwn_node_info node; int error; @@ -3539,12 +3535,11 @@ iwn_auth(struct iwn_softc *sc) * Configure the adapter for associated state. */ int -iwn_run(struct iwn_softc *sc) +iwn_run(struct iwn_softc *sc, struct ieee80211vap *vap) { #define MS(v,x) (((v) & x) >> x##_S) struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); /*XXX*/ struct ieee80211_node *ni = vap->iv_bss; struct iwn_node_info node; int error, maxrxampdu, ampdudensity; @@ -4270,9 +4265,6 @@ iwn_stop_locked(struct iwn_softc *sc) IWN_WRITE(sc, IWN_INTR, 0xffffffff); IWN_WRITE(sc, IWN_INTR_STATUS, 0xffffffff); - /* Clear any commands left in the taskq command buffer */ - memset(sc->sc_cmd, 0, sizeof(sc->sc_cmd)); - /* reset all Tx rings */ for (i = 0; i < IWN_NTXQUEUES; i++) iwn_reset_tx_ring(sc, &sc->txq[i]); @@ -4308,7 +4300,10 @@ iwn_scan_start(struct ieee80211com *ic) struct ifnet *ifp = ic->ic_ifp; struct iwn_softc *sc = ifp->if_softc; - iwn_queue_cmd(sc, IWN_SCAN_START, 0, IWN_QUEUE_NORMAL); + IWN_LOCK(sc); + /* make the link LED blink while we're scanning */ + iwn_set_led(sc, IWN_LED_LINK, 20, 2); + IWN_UNLOCK(sc); } /* @@ -4317,10 +4312,7 @@ iwn_scan_start(struct ieee80211com *ic) static void iwn_scan_end(struct ieee80211com *ic) { - struct ifnet *ifp = ic->ic_ifp; - struct iwn_softc *sc = ifp->if_softc; - - iwn_queue_cmd(sc, IWN_SCAN_STOP, 0, IWN_QUEUE_NORMAL); + /* ignore */ } /* @@ -4331,15 +4323,29 @@ iwn_set_channel(struct ieee80211com *ic) { struct ifnet *ifp = ic->ic_ifp; struct iwn_softc *sc = ifp->if_softc; + struct ieee80211vap *vap; const struct ieee80211_channel *c = ic->ic_curchan; + int error; + + vap = TAILQ_FIRST(&ic->ic_vaps); /* XXX */ + IWN_LOCK(sc); if (c != sc->sc_curchan) { sc->sc_rxtap.wr_chan_freq = htole16(c->ic_freq); sc->sc_rxtap.wr_chan_flags = htole16(c->ic_flags); sc->sc_txtap.wt_chan_freq = htole16(c->ic_freq); sc->sc_txtap.wt_chan_flags = htole16(c->ic_flags); - iwn_queue_cmd(sc, IWN_SET_CHAN, 0, IWN_QUEUE_NORMAL); + + error = iwn_config(sc); + if (error != 0) { + DPRINTF(sc, IWN_DEBUG_STATE, + "%s: set chan failed, cancel scan\n", + __func__); + //XXX Handle failed scan correctly + ieee80211_cancel_scan(vap); + } } + IWN_UNLOCK(sc); } /* @@ -4350,8 +4356,13 @@ iwn_scan_curchan(struct ieee80211_scan_state *ss, unsigned long maxdwell) { struct ieee80211vap *vap = ss->ss_vap; struct iwn_softc *sc = vap->iv_ic->ic_ifp->if_softc; + int error; - iwn_queue_cmd(sc, IWN_SCAN_CURCHAN, 0, IWN_QUEUE_NORMAL); + IWN_LOCK(sc); + error = iwn_scan(sc); + IWN_UNLOCK(sc); + if (error != 0) + ieee80211_cancel_scan(vap); } /* @@ -4365,149 +4376,36 @@ iwn_scan_mindwell(struct ieee80211_scan_state *ss) /* NB: don't try to abort scan; wait for firmware to finish */ } -/* - * Carry out work in the taskq context. - */ static void -iwn_ops(void *arg0, int pending) +iwn_hwreset(void *arg0, int pending) { struct iwn_softc *sc = arg0; struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; - struct ieee80211vap *vap; - int cmd, arg, error; - enum ieee80211_state nstate; - for (;;) { - IWN_CMD_LOCK(sc); - cmd = sc->sc_cmd[sc->sc_cmd_cur]; - if (cmd == 0) { - /* No more commands to process */ - IWN_CMD_UNLOCK(sc); - return; - } - if ((sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 && - cmd != IWN_RADIO_ENABLE ) { - IWN_CMD_UNLOCK(sc); - return; - } - arg = sc->sc_cmd_arg[sc->sc_cmd_cur]; - sc->sc_cmd[sc->sc_cmd_cur] = 0; /* free the slot */ - sc->sc_cmd_cur = (sc->sc_cmd_cur + 1) % IWN_CMD_MAXOPS; - IWN_CMD_UNLOCK(sc); - - IWN_LOCK(sc); /* NB: sync debug printfs on smp */ - DPRINTF(sc, IWN_DEBUG_OPS, "%s: %s (cmd 0x%x)\n", - __func__, iwn_ops_str(cmd), cmd); - - vap = TAILQ_FIRST(&ic->ic_vaps); /* XXX */ - switch (cmd) { - case IWN_SCAN_START: - /* make the link LED blink while we're scanning */ - iwn_set_led(sc, IWN_LED_LINK, 20, 2); - break; - case IWN_SCAN_STOP: - break; - case IWN_SCAN_NEXT: - ieee80211_scan_next(vap); - break; - case IWN_SCAN_CURCHAN: - error = iwn_scan(sc); - if (error != 0) { - IWN_UNLOCK(sc); - ieee80211_cancel_scan(vap); - IWN_LOCK(sc); - return; - } - break; - case IWN_SET_CHAN: - error = iwn_config(sc); - if (error != 0) { - DPRINTF(sc, IWN_DEBUG_STATE, - "%s: set chan failed, cancel scan\n", - __func__); - IWN_UNLOCK(sc); - //XXX Handle failed scan correctly - ieee80211_cancel_scan(vap); - return; - } - break; - case IWN_AUTH: - case IWN_RUN: - if (cmd == IWN_AUTH) { - error = iwn_auth(sc); - nstate = IEEE80211_S_AUTH; - } else { - error = iwn_run(sc); - nstate = IEEE80211_S_RUN; - } - if (error == 0) { - IWN_UNLOCK(sc); - IEEE80211_LOCK(ic); - IWN_VAP(vap)->iv_newstate(vap, nstate, arg); - if (vap->iv_newstate_cb != NULL) - vap->iv_newstate_cb(vap, nstate, arg); - IEEE80211_UNLOCK(ic); - IWN_LOCK(sc); - } else { - device_printf(sc->sc_dev, - "%s: %s state change failed, error %d\n", - __func__, ieee80211_state_name[nstate], - error); - } - break; - case IWN_REINIT: - IWN_UNLOCK(sc); - iwn_init(sc); - IWN_LOCK(sc); - ieee80211_notify_radio(ic, 1); - break; - case IWN_RADIO_ENABLE: - KASSERT(sc->fw_fp != NULL, - ("Fware Not Loaded, can't load from tq")); - IWN_UNLOCK(sc); - iwn_init(sc); - IWN_LOCK(sc); - break; - case IWN_RADIO_DISABLE: - ieee80211_notify_radio(ic, 0); - iwn_stop_locked(sc); - break; - } - IWN_UNLOCK(sc); - } + iwn_init(sc); + ieee80211_notify_radio(ic, 1); } -/* - * Queue a command for execution in the taskq thread. - * This is needed as the net80211 callbacks do not allow - * sleeping, since we need to sleep to confirm commands have - * been processed by the firmware, we must defer execution to - * a sleep enabled thread. - */ -static int -iwn_queue_cmd(struct iwn_softc *sc, int cmd, int arg, int clear) +static void +iwn_radioon(void *arg0, int pending) { - IWN_CMD_LOCK(sc); - if (clear) { - sc->sc_cmd[0] = cmd; - sc->sc_cmd_arg[0] = arg; - sc->sc_cmd_cur = 0; - sc->sc_cmd_next = 1; - } else { - if (sc->sc_cmd[sc->sc_cmd_next] != 0) { - IWN_CMD_UNLOCK(sc); - DPRINTF(sc, IWN_DEBUG_ANY, "%s: command %d dropped\n", - __func__, cmd); - return EBUSY; - } - sc->sc_cmd[sc->sc_cmd_next] = cmd; - sc->sc_cmd_arg[sc->sc_cmd_next] = arg; - sc->sc_cmd_next = (sc->sc_cmd_next + 1) % IWN_CMD_MAXOPS; - } - taskqueue_enqueue(sc->sc_tq, &sc->sc_ops_task); - IWN_CMD_UNLOCK(sc); - return 0; + struct iwn_softc *sc = arg0; + + iwn_init(sc); +} + +static void +iwn_radiooff(void *arg0, int pending) +{ + struct iwn_softc *sc = arg0; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + + IWN_LOCK(sc); + ieee80211_notify_radio(ic, 0); + iwn_stop_locked(sc); + IWN_UNLOCK(sc); } static void @@ -4542,24 +4440,6 @@ iwn_sysctlattach(struct iwn_softc *sc) #ifdef IWN_DEBUG static const char * -iwn_ops_str(int cmd) -{ - switch (cmd) { - case IWN_SCAN_START: return "SCAN_START"; - case IWN_SCAN_CURCHAN: return "SCAN_CURCHAN"; - case IWN_SCAN_STOP: return "SCAN_STOP"; - case IWN_SET_CHAN: return "SET_CHAN"; - case IWN_AUTH: return "AUTH"; - case IWN_SCAN_NEXT: return "SCAN_NEXT"; - case IWN_RUN: return "RUN"; - case IWN_RADIO_ENABLE: return "RADIO_ENABLE"; - case IWN_RADIO_DISABLE: return "RADIO_DISABLE"; - case IWN_REINIT: return "REINIT"; - } - return "UNKNOWN COMMAND"; -} - -static const char * iwn_intr_str(uint8_t cmd) { switch (cmd) { diff --git a/sys/dev/iwn/if_iwnvar.h b/sys/dev/iwn/if_iwnvar.h index 4620342..d956525 100644 --- a/sys/dev/iwn/if_iwnvar.h +++ b/sys/dev/iwn/if_iwnvar.h @@ -180,33 +180,10 @@ struct iwn_softc { void *sc_ih; bus_size_t sc_sz; - /* command queue related variables */ -#define IWN_SCAN_START (1<<0) -#define IWN_SCAN_CURCHAN (1<<1) -#define IWN_SCAN_STOP (1<<2) -#define IWN_SET_CHAN (1<<3) -#define IWN_AUTH (1<<4) -#define IWN_SCAN_NEXT (1<<5) -#define IWN_RUN (1<<6) -#define IWN_RADIO_ENABLE (1<<7) -#define IWN_RADIO_DISABLE (1<<8) -#define IWN_REINIT (1<<9) -#define IWN_CMD_MAXOPS 10 - /* command queuing request type */ -#define IWN_QUEUE_NORMAL 0 -#define IWN_QUEUE_CLEAR 1 - int sc_cmd[IWN_CMD_MAXOPS]; - int sc_cmd_arg[IWN_CMD_MAXOPS]; - int sc_cmd_cur; /* current queued scan task */ - int sc_cmd_next; /* last queued scan task */ - struct mtx sc_cmdlock; - - /* Task queues used to control the driver */ - struct taskqueue *sc_tq; /* Main command task queue */ - /* Tasks used by the driver */ - struct task sc_ops_task; /* deferred ops */ - struct task sc_bmiss_task; /* beacon miss */ + struct task sc_reinit_task; + struct task sc_radioon_task; + struct task sc_radiooff_task; /* Thermal calibration */ int calib_cnt; @@ -234,9 +211,3 @@ struct iwn_softc { #define IWN_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->sc_mtx, MA_OWNED) #define IWN_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) #define IWN_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_mtx) -#define IWN_CMD_LOCK_INIT(_sc) \ - mtx_init(&(_sc)->sc_cmdlock, device_get_nameunit((_sc)->sc_dev), \ - NULL, MTX_DEF); -#define IWN_CMD_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_cmdlock) -#define IWN_CMD_LOCK(_sc) mtx_lock(&(_sc)->sc_cmdlock) -#define IWN_CMD_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_cmdlock) diff --git a/sys/dev/usb/wlan/if_rum.c b/sys/dev/usb/wlan/if_rum.c index 856ed38..0c3012e 100644 --- a/sys/dev/usb/wlan/if_rum.c +++ b/sys/dev/usb/wlan/if_rum.c @@ -26,22 +26,58 @@ __FBSDID("$FreeBSD$"); * http://www.ralinktech.com.tw/ */ -#include "usbdevs.h" -#include <dev/usb/usb.h> -#include <dev/usb/usb_mfunc.h> -#include <dev/usb/usb_error.h> +#include <sys/param.h> +#include <sys/sockio.h> +#include <sys/sysctl.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/mbuf.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/module.h> +#include <sys/bus.h> +#include <sys/endian.h> +#include <sys/kdb.h> + +#include <machine/bus.h> +#include <machine/resource.h> +#include <sys/rman.h> + +#include <net/bpf.h> +#include <net/if.h> +#include <net/if_arp.h> +#include <net/ethernet.h> +#include <net/if_dl.h> +#include <net/if_media.h> +#include <net/if_types.h> + +#ifdef INET +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/in_var.h> +#include <netinet/if_ether.h> +#include <netinet/ip.h> +#endif + +#include <net80211/ieee80211_var.h> +#include <net80211/ieee80211_regdomain.h> +#include <net80211/ieee80211_radiotap.h> +#include <net80211/ieee80211_amrr.h> #define USB_DEBUG_VAR rum_debug +#include <dev/usb/usb.h> +#include <dev/usb/usb_error.h> #include <dev/usb/usb_core.h> #include <dev/usb/usb_lookup.h> -#include <dev/usb/usb_process.h> #include <dev/usb/usb_debug.h> #include <dev/usb/usb_request.h> #include <dev/usb/usb_busdma.h> #include <dev/usb/usb_util.h> +#include "usbdevs.h" -#include <dev/usb/wlan/usb_wlan.h> #include <dev/usb/wlan/if_rumreg.h> #include <dev/usb/wlan/if_rumvar.h> #include <dev/usb/wlan/if_rumfw.h> @@ -116,16 +152,6 @@ static device_detach_t rum_detach; static usb2_callback_t rum_bulk_read_callback; static usb2_callback_t rum_bulk_write_callback; -static usb2_proc_callback_t rum_command_wrapper; -static usb2_proc_callback_t rum_attach_post; -static usb2_proc_callback_t rum_task; -static usb2_proc_callback_t rum_scantask; -static usb2_proc_callback_t rum_promisctask; -static usb2_proc_callback_t rum_amrr_task; -static usb2_proc_callback_t rum_init_task; -static usb2_proc_callback_t rum_stop_task; -static usb2_proc_callback_t rum_flush_task; - static usb2_error_t rum_do_request(struct rum_softc *sc, struct usb2_device_request *req, void *data); static struct ieee80211vap *rum_vap_create(struct ieee80211com *, @@ -174,10 +200,13 @@ static void rum_update_slot(struct ifnet *); static void rum_set_bssid(struct rum_softc *, const uint8_t *); static void rum_set_macaddr(struct rum_softc *, const uint8_t *); static void rum_update_promisc(struct ifnet *); +static void rum_setpromisc(struct rum_softc *); static const char *rum_get_rf(int); static void rum_read_eeprom(struct rum_softc *); static int rum_bbp_init(struct rum_softc *); +static void rum_init_locked(struct rum_softc *); static void rum_init(void *); +static void rum_stop(struct rum_softc *); static void rum_load_microcode(struct rum_softc *, const uint8_t *, size_t); static int rum_prepare_beacon(struct rum_softc *, @@ -194,10 +223,8 @@ static int rum_get_rssi(struct rum_softc *, uint8_t); static void rum_amrr_start(struct rum_softc *, struct ieee80211_node *); static void rum_amrr_timeout(void *); +static void rum_amrr_task(void *, int); static int rum_pause(struct rum_softc *, int); -static void rum_queue_command(struct rum_softc *, - usb2_proc_callback_t *, struct usb2_proc_msg *, - struct usb2_proc_msg *); static const struct { uint32_t reg; @@ -398,8 +425,11 @@ rum_attach(device_t self) { struct usb2_attach_arg *uaa = device_get_ivars(self); struct rum_softc *sc = device_get_softc(self); - uint8_t iface_index; - int error; + struct ieee80211com *ic; + struct ifnet *ifp; + uint8_t iface_index, bands; + uint32_t tmp; + int error, ntries; device_set_usb2_desc(self); sc->sc_udev = uaa->device; @@ -408,8 +438,6 @@ rum_attach(device_t self) mtx_init(&sc->sc_mtx, device_get_nameunit(self), MTX_NETWORK_LOCK, MTX_DEF); - cv_init(&sc->sc_cmd_cv, "wtxdone"); - iface_index = RT2573_IFACE_INDEX; error = usb2_transfer_setup(uaa->device, &iface_index, sc->sc_xfer, rum_config, RUM_N_TRANSFER, sc, &sc->sc_mtx); @@ -418,37 +446,8 @@ rum_attach(device_t self) "err=%s\n", usb2_errstr(error)); goto detach; } - error = usb2_proc_create(&sc->sc_tq, &sc->sc_mtx, - device_get_nameunit(self), USB_PRI_MED); - if (error) { - device_printf(self, "could not setup config thread!\n"); - goto detach; - } - /* fork rest of the attach code */ RUM_LOCK(sc); - rum_queue_command(sc, rum_attach_post, - &sc->sc_synctask[0].hdr, - &sc->sc_synctask[1].hdr); - RUM_UNLOCK(sc); - return (0); - -detach: - rum_detach(self); - return (ENXIO); /* failure */ -} - -static void -rum_attach_post(struct usb2_proc_msg *pm) -{ - struct rum_task *task = (struct rum_task *)pm; - struct rum_softc *sc = task->sc; - struct ifnet *ifp; - struct ieee80211com *ic; - unsigned int ntries; - uint32_t tmp; - uint8_t bands; - /* retrieve RT2573 rev. no */ for (ntries = 0; ntries < 100; ntries++) { if ((tmp = rum_read(sc, RT2573_MAC_CSR0)) != 0) @@ -458,7 +457,8 @@ rum_attach_post(struct usb2_proc_msg *pm) } if (ntries == 100) { device_printf(sc->sc_dev, "timeout waiting for chip to settle\n"); - return; + RUM_UNLOCK(sc); + goto detach; } /* retrieve MAC address and various other things from EEPROM */ @@ -468,18 +468,12 @@ rum_attach_post(struct usb2_proc_msg *pm) tmp, rum_get_rf(sc->rf_rev)); rum_load_microcode(sc, rt2573_ucode, sizeof(rt2573_ucode)); - - /* XXX Async attach race */ - if (usb2_proc_is_gone(&sc->sc_tq)) - return; - RUM_UNLOCK(sc); ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); if (ifp == NULL) { device_printf(sc->sc_dev, "can not if_alloc()\n"); - RUM_LOCK(sc); - return; + goto detach; } ic = ifp->if_l2com; @@ -542,7 +536,11 @@ rum_attach_post(struct usb2_proc_msg *pm) if (bootverbose) ieee80211_announce(ic); - RUM_LOCK(sc); + return (0); + +detach: + rum_detach(self); + return (ENXIO); /* failure */ } static int @@ -552,12 +550,8 @@ rum_detach(device_t self) struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic; - /* wait for any post attach or other command to complete */ - usb2_proc_drain(&sc->sc_tq); - /* stop all USB transfers */ usb2_transfer_unsetup(sc->sc_xfer, RUM_N_TRANSFER); - usb2_proc_free(&sc->sc_tq); /* free TX list, if any */ RUM_LOCK(sc); @@ -570,7 +564,6 @@ rum_detach(device_t self) ieee80211_ifdetach(ic); if_free(ifp); } - cv_destroy(&sc->sc_cmd_cv); mtx_destroy(&sc->sc_mtx); return (0); @@ -584,7 +577,7 @@ rum_do_request(struct rum_softc *sc, int ntries = 10; while (ntries--) { - err = usb2_do_request_proc(sc->sc_udev, &sc->sc_tq, + err = usb2_do_request_flags(sc->sc_udev, &sc->sc_mtx, req, data, 0, NULL, 250 /* ms */); if (err == 0) break; @@ -622,8 +615,8 @@ rum_vap_create(struct ieee80211com *ic, rvp->newstate = vap->iv_newstate; vap->iv_newstate = rum_newstate; - rvp->sc = sc; usb2_callout_init_mtx(&rvp->amrr_ch, &sc->sc_mtx, 0); + TASK_INIT(&rvp->amrr_task, 0, rum_amrr_task, rvp); ieee80211_amrr_init(&rvp->amrr, vap, IEEE80211_AMRR_MIN_SUCCESS_THRESHOLD, IEEE80211_AMRR_MAX_SUCCESS_THRESHOLD, @@ -636,25 +629,13 @@ rum_vap_create(struct ieee80211com *ic, } static void -rum_flush_task(struct usb2_proc_msg *pm) -{ - /* Nothing to do */ -} - -static void rum_vap_delete(struct ieee80211vap *vap) { struct rum_vap *rvp = RUM_VAP(vap); - struct rum_softc *sc = rvp->sc; - - RUM_LOCK(sc); - /* wait for any pending tasks to complete */ - rum_queue_command(sc, rum_flush_task, - &sc->sc_synctask[0].hdr, - &sc->sc_synctask[1].hdr); - RUM_UNLOCK(sc); + struct ieee80211com *ic = vap->iv_ic; usb2_callout_drain(&rvp->amrr_ch); + ieee80211_draintask(ic, &rvp->amrr_task); ieee80211_amrr_cleanup(&rvp->amrr); ieee80211_vap_detach(vap); free(rvp, M_80211_VAP); @@ -724,23 +705,27 @@ rum_unsetup_tx_list(struct rum_softc *sc) } } -static void -rum_task(struct usb2_proc_msg *pm) +static int +rum_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) { - struct rum_task *task = (struct rum_task *)pm; - struct rum_softc *sc = task->sc; - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); struct rum_vap *rvp = RUM_VAP(vap); + struct ieee80211com *ic = vap->iv_ic; + struct rum_softc *sc = ic->ic_ifp->if_softc; const struct ieee80211_txparam *tp; enum ieee80211_state ostate; struct ieee80211_node *ni; uint32_t tmp; ostate = vap->iv_state; + DPRINTF("%s -> %s\n", + ieee80211_state_name[ostate], + ieee80211_state_name[nstate]); - switch (sc->sc_state) { + IEEE80211_UNLOCK(ic); + RUM_LOCK(sc); + usb2_callout_stop(&rvp->amrr_ch); + + switch (nstate) { case IEEE80211_S_INIT: if (ostate == IEEE80211_S_RUN) { /* abort TSF synchronization */ @@ -776,45 +761,9 @@ rum_task(struct usb2_proc_msg *pm) default: break; } - RUM_UNLOCK(sc); IEEE80211_LOCK(ic); - rvp->newstate(vap, sc->sc_state, sc->sc_arg); - if (vap->iv_newstate_cb != NULL) - vap->iv_newstate_cb(vap, sc->sc_state, sc->sc_arg); - IEEE80211_UNLOCK(ic); - RUM_LOCK(sc); -} - -static int -rum_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) -{ - struct rum_vap *rvp = RUM_VAP(vap); - struct ieee80211com *ic = vap->iv_ic; - struct rum_softc *sc = ic->ic_ifp->if_softc; - - DPRINTF("%s -> %s\n", - ieee80211_state_name[vap->iv_state], - ieee80211_state_name[nstate]); - - RUM_LOCK(sc); - usb2_callout_stop(&rvp->amrr_ch); - - /* do it in a process context */ - sc->sc_state = nstate; - sc->sc_arg = arg; - RUM_UNLOCK(sc); - - if (nstate == IEEE80211_S_INIT) { - rvp->newstate(vap, nstate, arg); - return 0; - } else { - RUM_LOCK(sc); - rum_queue_command(sc, rum_task, &sc->sc_task[0].hdr, - &sc->sc_task[1].hdr); - RUM_UNLOCK(sc); - return EINPROGRESS; - } + return (rvp->newstate(vap, nstate, arg)); } static void @@ -828,10 +777,6 @@ rum_bulk_write_callback(struct usb2_xfer *xfer) struct mbuf *m; unsigned int len; - /* wakeup waiting command, if any */ - if (sc->sc_last_task != NULL) - cv_signal(&sc->sc_cmd_cv); - switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: DPRINTFN(11, "transfer complete, %d bytes\n", xfer->actlen); @@ -847,10 +792,6 @@ rum_bulk_write_callback(struct usb2_xfer *xfer) /* FALLTHROUGH */ case USB_ST_SETUP: tr_setup: - /* wait for command to complete, if any */ - if (sc->sc_last_task != NULL) - break; - data = STAILQ_FIRST(&sc->tx_q); if (data) { STAILQ_REMOVE_HEAD(&sc->tx_q, next); @@ -1377,20 +1318,13 @@ rum_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) RUM_LOCK(sc); if (ifp->if_flags & IFF_UP) { if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { - rum_queue_command(sc, rum_init_task, - &sc->sc_synctask[0].hdr, - &sc->sc_synctask[1].hdr); + rum_init_locked(sc); startall = 1; } else - rum_queue_command(sc, rum_promisctask, - &sc->sc_promisctask[0].hdr, - &sc->sc_promisctask[1].hdr); + rum_setpromisc(sc); } else { - if (ifp->if_drv_flags & IFF_DRV_RUNNING) { - rum_queue_command(sc, rum_stop_task, - &sc->sc_synctask[0].hdr, - &sc->sc_synctask[1].hdr); - } + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + rum_stop(sc); } RUM_UNLOCK(sc); if (startall) @@ -1844,10 +1778,8 @@ rum_set_macaddr(struct rum_softc *sc, const uint8_t *addr) } static void -rum_promisctask(struct usb2_proc_msg *pm) +rum_setpromisc(struct rum_softc *sc) { - struct rum_task *task = (struct rum_task *)pm; - struct rum_softc *sc = task->sc; struct ifnet *ifp = sc->sc_ifp; uint32_t tmp; @@ -1872,9 +1804,7 @@ rum_update_promisc(struct ifnet *ifp) return; RUM_LOCK(sc); - rum_queue_command(sc, rum_promisctask, - &sc->sc_promisctask[0].hdr, - &sc->sc_promisctask[1].hdr); + rum_setpromisc(sc); RUM_UNLOCK(sc); } @@ -2008,11 +1938,9 @@ rum_bbp_init(struct rum_softc *sc) } static void -rum_init_task(struct usb2_proc_msg *pm) +rum_init_locked(struct rum_softc *sc) { #define N(a) (sizeof (a) / sizeof ((a)[0])) - struct rum_task *task = (struct rum_task *)pm; - struct rum_softc *sc = task->sc; struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; uint32_t tmp; @@ -2021,7 +1949,7 @@ rum_init_task(struct usb2_proc_msg *pm) RUM_LOCK_ASSERT(sc, MA_OWNED); - rum_stop_task(pm); + rum_stop(sc); /* initialize MAC registers to default values */ for (i = 0; i < N(rum_def_mac); i++) @@ -2086,7 +2014,7 @@ rum_init_task(struct usb2_proc_msg *pm) usb2_transfer_start(sc->sc_xfer[RUM_BULK_RD]); return; -fail: rum_stop_task(pm); +fail: rum_stop(sc); #undef N } @@ -2098,9 +2026,7 @@ rum_init(void *priv) struct ieee80211com *ic = ifp->if_l2com; RUM_LOCK(sc); - rum_queue_command(sc, rum_init_task, - &sc->sc_synctask[0].hdr, - &sc->sc_synctask[1].hdr); + rum_init_locked(sc); RUM_UNLOCK(sc); if (ifp->if_drv_flags & IFF_DRV_RUNNING) @@ -2108,10 +2034,8 @@ rum_init(void *priv) } static void -rum_stop_task(struct usb2_proc_msg *pm) +rum_stop(struct rum_softc *sc) { - struct rum_task *task = (struct rum_task *)pm; - struct rum_softc *sc = task->sc; struct ifnet *ifp = sc->sc_ifp; uint32_t tmp; @@ -2271,24 +2195,24 @@ static void rum_amrr_timeout(void *arg) { struct rum_vap *rvp = arg; - struct rum_softc *sc = rvp->sc; + struct ieee80211vap *vap = &rvp->vap; + struct ieee80211com *ic = vap->iv_ic; - rum_queue_command(sc, rum_amrr_task, - &rvp->amrr_task[0].hdr, &rvp->amrr_task[1].hdr); + ieee80211_runtask(ic, &rvp->amrr_task); } static void -rum_amrr_task(struct usb2_proc_msg *pm) +rum_amrr_task(void *arg, int pending) { - struct rum_task *task = (struct rum_task *)pm; - struct rum_softc *sc = task->sc; - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); - struct rum_vap *rvp = RUM_VAP(vap); + struct rum_vap *rvp = arg; + struct ieee80211vap *vap = &rvp->vap; + struct ieee80211com *ic = vap->iv_ic; + struct ifnet *ifp = ic->ic_ifp; + struct rum_softc *sc = ifp->if_softc; struct ieee80211_node *ni = vap->iv_bss; int ok, fail; + RUM_LOCK(sc); /* read and clear statistic registers (STA_CSR0 to STA_CSR10) */ rum_read_multi(sc, RT2573_STA_CSR0, sc->sta, sizeof(sc->sta)); @@ -2303,6 +2227,7 @@ rum_amrr_task(struct usb2_proc_msg *pm) ifp->if_oerrors += fail; /* count TX retry-fail as Tx errors */ usb2_callout_reset(&rvp->amrr_ch, hz, rum_amrr_timeout, rvp); + RUM_UNLOCK(sc); } /* ARGUSED */ @@ -2327,13 +2252,15 @@ rum_newassoc(struct ieee80211_node *ni, int isnew) static void rum_scan_start(struct ieee80211com *ic) { - struct rum_softc *sc = ic->ic_ifp->if_softc; + struct ifnet *ifp = ic->ic_ifp; + struct rum_softc *sc = ifp->if_softc; + uint32_t tmp; RUM_LOCK(sc); - /* do it in a process context */ - sc->sc_scan_action = RUM_SCAN_START; - rum_queue_command(sc, rum_scantask, - &sc->sc_scantask[0].hdr, &sc->sc_scantask[1].hdr); + /* abort TSF synchronization */ + tmp = rum_read(sc, RT2573_TXRX_CSR9); + rum_write(sc, RT2573_TXRX_CSR9, tmp & ~0x00ffffff); + rum_set_bssid(sc, ifp->if_broadcastaddr); RUM_UNLOCK(sc); } @@ -2344,10 +2271,8 @@ rum_scan_end(struct ieee80211com *ic) struct rum_softc *sc = ic->ic_ifp->if_softc; RUM_LOCK(sc); - /* do it in a process context */ - sc->sc_scan_action = RUM_SCAN_END; - rum_queue_command(sc, rum_scantask, - &sc->sc_scantask[0].hdr, &sc->sc_scantask[1].hdr); + rum_enable_tsf_sync(sc); + rum_set_bssid(sc, sc->sc_bssid); RUM_UNLOCK(sc); } @@ -2358,43 +2283,10 @@ rum_set_channel(struct ieee80211com *ic) struct rum_softc *sc = ic->ic_ifp->if_softc; RUM_LOCK(sc); - /* do it in a process context */ - sc->sc_scan_action = RUM_SET_CHANNEL; - rum_queue_command(sc, rum_scantask, - &sc->sc_scantask[0].hdr, &sc->sc_scantask[1].hdr); + rum_set_chan(sc, ic->ic_curchan); RUM_UNLOCK(sc); } -static void -rum_scantask(struct usb2_proc_msg *pm) -{ - struct rum_task *task = (struct rum_task *)pm; - struct rum_softc *sc = task->sc; - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; - uint32_t tmp; - - RUM_LOCK_ASSERT(sc, MA_OWNED); - - switch (sc->sc_scan_action) { - case RUM_SCAN_START: - /* abort TSF synchronization */ - tmp = rum_read(sc, RT2573_TXRX_CSR9); - rum_write(sc, RT2573_TXRX_CSR9, tmp & ~0x00ffffff); - rum_set_bssid(sc, ifp->if_broadcastaddr); - break; - - case RUM_SET_CHANNEL: - rum_set_chan(sc, ic->ic_curchan); - break; - - default: /* RUM_SCAN_END */ - rum_enable_tsf_sync(sc); - rum_set_bssid(sc, sc->sc_bssid); - break; - } -} - static int rum_get_rssi(struct rum_softc *sc, uint8_t raw) { @@ -2445,72 +2337,11 @@ rum_get_rssi(struct rum_softc *sc, uint8_t raw) static int rum_pause(struct rum_softc *sc, int timeout) { - if (usb2_proc_is_gone(&sc->sc_tq)) - return (1); usb2_pause_mtx(&sc->sc_mtx, timeout); return (0); } -static void -rum_command_wrapper(struct usb2_proc_msg *pm) -{ - struct rum_task *task = (struct rum_task *)pm; - struct rum_softc *sc = task->sc; - struct ifnet *ifp; - - /* wait for pending transfer, if any */ - while (usb2_transfer_pending(sc->sc_xfer[RUM_BULK_WR])) - cv_wait(&sc->sc_cmd_cv, &sc->sc_mtx); - - /* make sure any hardware buffers are emptied */ - rum_pause(sc, hz / 1000); - - /* execute task */ - task->func(pm); - - /* check if this is the last task executed */ - if (sc->sc_last_task == task) { - sc->sc_last_task = NULL; - ifp = sc->sc_ifp; - /* re-start TX, if any */ - if ((ifp != NULL) && (ifp->if_drv_flags & IFF_DRV_RUNNING)) - usb2_transfer_start(sc->sc_xfer[RUM_BULK_WR]); - } -} - -static void -rum_queue_command(struct rum_softc *sc, usb2_proc_callback_t *fn, - struct usb2_proc_msg *t0, struct usb2_proc_msg *t1) -{ - struct rum_task *task; - - RUM_LOCK_ASSERT(sc, MA_OWNED); - - /* - * NOTE: The task cannot get executed before we drop the - * "sc_mtx" mutex. It is safe to update fields in the message - * structure after that the message got queued. - */ - task = (struct rum_task *) - usb2_proc_msignal(&sc->sc_tq, t0, t1); - - /* Setup callback and softc pointers */ - task->hdr.pm_callback = rum_command_wrapper; - task->func = fn; - task->sc = sc; - - /* Make sure that any TX operation will stop */ - sc->sc_last_task = task; - - /* - * Init, stop and flush must be synchronous! - */ - if ((fn == rum_init_task) || (fn == rum_stop_task) || - (fn == rum_flush_task)) - usb2_proc_mwait(&sc->sc_tq, t0, t1); -} - static device_method_t rum_methods[] = { /* Device interface */ DEVMETHOD(device_probe, rum_match), diff --git a/sys/dev/usb/wlan/if_rumvar.h b/sys/dev/usb/wlan/if_rumvar.h index d6b8137..2ba4007 100644 --- a/sys/dev/usb/wlan/if_rumvar.h +++ b/sys/dev/usb/wlan/if_rumvar.h @@ -54,12 +54,6 @@ struct rum_tx_radiotap_header { struct rum_softc; -struct rum_task { - struct usb2_proc_msg hdr; - usb2_proc_callback_t *func; - struct rum_softc *sc; -}; - struct rum_tx_data { STAILQ_ENTRY(rum_tx_data) next; struct rum_softc *sc; @@ -78,11 +72,10 @@ struct rum_node { struct rum_vap { struct ieee80211vap vap; - struct rum_softc *sc; struct ieee80211_beacon_offsets bo; struct ieee80211_amrr amrr; struct usb2_callout amrr_ch; - struct rum_task amrr_task[2]; + struct task amrr_task; int (*newstate)(struct ieee80211vap *, enum ieee80211_state, int); @@ -99,32 +92,18 @@ struct rum_softc { struct ifnet *sc_ifp; device_t sc_dev; struct usb2_device *sc_udev; - struct usb2_process sc_tq; struct usb2_xfer *sc_xfer[RUM_N_TRANSFER]; - struct rum_task *sc_last_task; uint8_t rf_rev; uint8_t rffreq; - enum ieee80211_state sc_state; - int sc_arg; - struct rum_task sc_synctask[2]; - struct rum_task sc_task[2]; - struct rum_task sc_promisctask[2]; - struct rum_task sc_scantask[2]; - int sc_scan_action; -#define RUM_SCAN_START 0 -#define RUM_SCAN_END 1 -#define RUM_SET_CHANNEL 2 - struct rum_tx_data tx_data[RUM_TX_LIST_COUNT]; rum_txdhead tx_q; rum_txdhead tx_free; int tx_nfree; struct rum_rx_desc sc_rx_desc; - struct cv sc_cmd_cv; struct mtx sc_mtx; uint32_t sta[6]; diff --git a/sys/dev/usb/wlan/if_uath.c b/sys/dev/usb/wlan/if_uath.c index eb1c31c..8e65770 100644 --- a/sys/dev/usb/wlan/if_uath.c +++ b/sys/dev/usb/wlan/if_uath.c @@ -1602,6 +1602,7 @@ uath_tx_start(struct uath_softc *sc, struct mbuf *m0, struct ieee80211_node *ni, { struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; + struct ieee80211vap *vap = ni->ni_vap; struct uath_chunk *chunk; struct uath_tx_desc *desc; const struct ieee80211_frame *wh; @@ -1677,9 +1678,9 @@ uath_tx_start(struct uath_softc *sc, struct mbuf *m0, struct ieee80211_node *ni, m_freem(m0); return (EIO); } - if (sc->sc_state == IEEE80211_S_AUTH || - sc->sc_state == IEEE80211_S_ASSOC || - sc->sc_state == IEEE80211_S_RUN) + if (vap->iv_state == IEEE80211_S_AUTH || + vap->iv_state == IEEE80211_S_ASSOC || + vap->iv_state == IEEE80211_S_RUN) desc->connid = htobe32(UATH_ID_BSS); else desc->connid = htobe32(UATH_ID_INVALID); @@ -2061,11 +2062,10 @@ uath_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) "%s: %s -> %s\n", __func__, ieee80211_state_name[vap->iv_state], ieee80211_state_name[nstate]); + IEEE80211_UNLOCK(ic); UATH_LOCK(sc); - callout_stop(&sc->stat_ch); callout_stop(&sc->watchdog_ch); - sc->sc_state = nstate; switch (nstate) { case IEEE80211_S_INIT: @@ -2139,14 +2139,8 @@ uath_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) break; } UATH_UNLOCK(sc); - IEEE80211_LOCK(ic); - uvp->newstate(vap, nstate, arg); - if (vap->iv_newstate_cb != NULL) - vap->iv_newstate_cb(vap, nstate, arg); - IEEE80211_UNLOCK(ic); - - return (0); + return (uvp->newstate(vap, nstate, arg)); } static int diff --git a/sys/dev/usb/wlan/if_uathvar.h b/sys/dev/usb/wlan/if_uathvar.h index 2717399..2757ad4 100644 --- a/sys/dev/usb/wlan/if_uathvar.h +++ b/sys/dev/usb/wlan/if_uathvar.h @@ -183,7 +183,6 @@ struct uath_softc { struct uath_stat sc_stat; int (*sc_newstate)(struct ieee80211com *, enum ieee80211_state, int); - enum ieee80211_state sc_state; struct usb2_xfer *sc_xfer[UATH_N_XFERS]; struct uath_cmd sc_cmd[UATH_CMD_LIST_COUNT]; diff --git a/sys/dev/usb/wlan/if_ural.c b/sys/dev/usb/wlan/if_ural.c index b865a41..523cc61 100644 --- a/sys/dev/usb/wlan/if_ural.c +++ b/sys/dev/usb/wlan/if_ural.c @@ -28,22 +28,59 @@ __FBSDID("$FreeBSD$"); * http://www.ralinktech.com/ */ -#include "usbdevs.h" -#include <dev/usb/usb.h> -#include <dev/usb/usb_mfunc.h> -#include <dev/usb/usb_error.h> +#include <sys/param.h> +#include <sys/sockio.h> +#include <sys/sysctl.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/mbuf.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/module.h> +#include <sys/bus.h> +#include <sys/endian.h> +#include <sys/kdb.h> + +#include <machine/bus.h> +#include <machine/resource.h> +#include <sys/rman.h> + +#include <net/bpf.h> +#include <net/if.h> +#include <net/if_arp.h> +#include <net/ethernet.h> +#include <net/if_dl.h> +#include <net/if_media.h> +#include <net/if_types.h> + +#ifdef INET +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/in_var.h> +#include <netinet/if_ether.h> +#include <netinet/ip.h> +#endif + +#include <net80211/ieee80211_var.h> +#include <net80211/ieee80211_regdomain.h> +#include <net80211/ieee80211_radiotap.h> +#include <net80211/ieee80211_amrr.h> #define USB_DEBUG_VAR ural_debug +#include <dev/usb/usb.h> +#include <dev/usb/usb_error.h> #include <dev/usb/usb_core.h> #include <dev/usb/usb_lookup.h> -#include <dev/usb/usb_process.h> #include <dev/usb/usb_debug.h> #include <dev/usb/usb_request.h> #include <dev/usb/usb_busdma.h> #include <dev/usb/usb_util.h> +#include "usbdevs.h" + -#include <dev/usb/wlan/usb_wlan.h> #include <dev/usb/wlan/if_uralreg.h> #include <dev/usb/wlan/if_uralvar.h> @@ -95,16 +132,6 @@ static const struct usb2_device_id ural_devs[] = { static usb2_callback_t ural_bulk_read_callback; static usb2_callback_t ural_bulk_write_callback; -static usb2_proc_callback_t ural_command_wrapper; -static usb2_proc_callback_t ural_attach_post; -static usb2_proc_callback_t ural_task; -static usb2_proc_callback_t ural_scantask; -static usb2_proc_callback_t ural_promisctask; -static usb2_proc_callback_t ural_amrr_task; -static usb2_proc_callback_t ural_init_task; -static usb2_proc_callback_t ural_stop_task; -static usb2_proc_callback_t ural_flush_task; - static usb2_error_t ural_do_request(struct ural_softc *sc, struct usb2_device_request *req, void *data); static struct ieee80211vap *ural_vap_create(struct ieee80211com *, @@ -156,21 +183,22 @@ static void ural_set_basicrates(struct ural_softc *, static void ural_set_bssid(struct ural_softc *, const uint8_t *); static void ural_set_macaddr(struct ural_softc *, uint8_t *); static void ural_update_promisc(struct ifnet *); +static void ural_setpromisc(struct ural_softc *); static const char *ural_get_rf(int); static void ural_read_eeprom(struct ural_softc *); static int ural_bbp_init(struct ural_softc *); static void ural_set_txantenna(struct ural_softc *, int); static void ural_set_rxantenna(struct ural_softc *, int); +static void ural_init_locked(struct ural_softc *); static void ural_init(void *); +static void ural_stop(struct ural_softc *); static int ural_raw_xmit(struct ieee80211_node *, struct mbuf *, const struct ieee80211_bpf_params *); static void ural_amrr_start(struct ural_softc *, struct ieee80211_node *); static void ural_amrr_timeout(void *); +static void ural_amrr_task(void *, int); static int ural_pause(struct ural_softc *sc, int timeout); -static void ural_queue_command(struct ural_softc *, - usb2_proc_callback_t *, struct usb2_proc_msg *, - struct usb2_proc_msg *); /* * Default values for MAC registers; values taken from the reference driver. @@ -400,8 +428,10 @@ ural_attach(device_t self) { struct usb2_attach_arg *uaa = device_get_ivars(self); struct ural_softc *sc = device_get_softc(self); + struct ifnet *ifp; + struct ieee80211com *ic; + uint8_t iface_index, bands; int error; - uint8_t iface_index; device_set_usb2_desc(self); sc->sc_udev = uaa->device; @@ -410,8 +440,6 @@ ural_attach(device_t self) mtx_init(&sc->sc_mtx, device_get_nameunit(self), MTX_NETWORK_LOCK, MTX_DEF); - cv_init(&sc->sc_cmd_cv, "wtxdone"); - iface_index = RAL_IFACE_INDEX; error = usb2_transfer_setup(uaa->device, &iface_index, sc->sc_xfer, ural_config, @@ -421,55 +449,22 @@ ural_attach(device_t self) "err=%s\n", usb2_errstr(error)); goto detach; } - error = usb2_proc_create(&sc->sc_tq, &sc->sc_mtx, - device_get_nameunit(self), USB_PRI_MED); - if (error) { - device_printf(self, "could not setup config thread!\n"); - goto detach; - } - /* fork rest of the attach code */ RAL_LOCK(sc); - ural_queue_command(sc, ural_attach_post, - &sc->sc_synctask[0].hdr, - &sc->sc_synctask[1].hdr); - RAL_UNLOCK(sc); - return (0); - -detach: - ural_detach(self); - return (ENXIO); /* failure */ -} - -static void -ural_attach_post(struct usb2_proc_msg *pm) -{ - struct ural_task *task = (struct ural_task *)pm; - struct ural_softc *sc = task->sc; - struct ifnet *ifp; - struct ieee80211com *ic; - uint8_t bands; - /* retrieve RT2570 rev. no */ sc->asic_rev = ural_read(sc, RAL_MAC_CSR0); /* retrieve MAC address and various other things from EEPROM */ ural_read_eeprom(sc); - - /* XXX Async attach race */ - if (usb2_proc_is_gone(&sc->sc_tq)) - return; - RAL_UNLOCK(sc); - device_printf(sc->sc_dev, "MAC/BBP RT2570 (rev 0x%02x), RF %s\n", + device_printf(self, "MAC/BBP RT2570 (rev 0x%02x), RF %s\n", sc->asic_rev, ural_get_rf(sc->rf_rev)); ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); if (ifp == NULL) { device_printf(sc->sc_dev, "can not if_alloc()\n"); - RAL_LOCK(sc); - return; + goto detach; } ic = ifp->if_l2com; @@ -532,7 +527,11 @@ ural_attach_post(struct usb2_proc_msg *pm) if (bootverbose) ieee80211_announce(ic); - RAL_LOCK(sc); + return (0); + +detach: + ural_detach(self); + return (ENXIO); /* failure */ } static int @@ -542,12 +541,8 @@ ural_detach(device_t self) struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic; - /* wait for any post attach or other command to complete */ - usb2_proc_drain(&sc->sc_tq); - /* stop all USB transfers */ usb2_transfer_unsetup(sc->sc_xfer, URAL_N_TRANSFER); - usb2_proc_free(&sc->sc_tq); /* free TX list, if any */ RAL_LOCK(sc); @@ -560,7 +555,6 @@ ural_detach(device_t self) ieee80211_ifdetach(ic); if_free(ifp); } - cv_destroy(&sc->sc_cmd_cv); mtx_destroy(&sc->sc_mtx); return (0); @@ -574,7 +568,7 @@ ural_do_request(struct ural_softc *sc, int ntries = 10; while (ntries--) { - err = usb2_do_request_proc(sc->sc_udev, &sc->sc_tq, + err = usb2_do_request_flags(sc->sc_udev, &sc->sc_mtx, req, data, 0, NULL, 250 /* ms */); if (err == 0) break; @@ -612,8 +606,8 @@ ural_vap_create(struct ieee80211com *ic, uvp->newstate = vap->iv_newstate; vap->iv_newstate = ural_newstate; - uvp->sc = sc; usb2_callout_init_mtx(&uvp->amrr_ch, &sc->sc_mtx, 0); + TASK_INIT(&uvp->amrr_task, 0, ural_amrr_task, uvp); ieee80211_amrr_init(&uvp->amrr, vap, IEEE80211_AMRR_MIN_SUCCESS_THRESHOLD, IEEE80211_AMRR_MAX_SUCCESS_THRESHOLD, @@ -626,25 +620,13 @@ ural_vap_create(struct ieee80211com *ic, } static void -ural_flush_task(struct usb2_proc_msg *pm) -{ - /* nothing to do */ -} - -static void ural_vap_delete(struct ieee80211vap *vap) { struct ural_vap *uvp = URAL_VAP(vap); - struct ural_softc *sc = uvp->sc; - - RAL_LOCK(sc); - /* wait for any pending tasks to complete */ - ural_queue_command(sc, ural_flush_task, - &sc->sc_synctask[0].hdr, - &sc->sc_synctask[1].hdr); - RAL_UNLOCK(sc); + struct ieee80211com *ic = vap->iv_ic; usb2_callout_drain(&uvp->amrr_ch); + ieee80211_draintask(ic, &uvp->amrr_task); ieee80211_amrr_cleanup(&uvp->amrr); ieee80211_vap_detach(vap); free(uvp, M_80211_VAP); @@ -714,25 +696,27 @@ ural_unsetup_tx_list(struct ural_softc *sc) } } -static void -ural_task(struct usb2_proc_msg *pm) +static int +ural_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) { - struct ural_task *task = (struct ural_task *)pm; - struct ural_softc *sc = task->sc; - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); struct ural_vap *uvp = URAL_VAP(vap); + struct ieee80211com *ic = vap->iv_ic; + struct ural_softc *sc = ic->ic_ifp->if_softc; const struct ieee80211_txparam *tp; - enum ieee80211_state ostate; struct ieee80211_node *ni; struct mbuf *m; - ostate = vap->iv_state; + DPRINTF("%s -> %s\n", + ieee80211_state_name[vap->iv_state], + ieee80211_state_name[nstate]); + + IEEE80211_UNLOCK(ic); + RAL_LOCK(sc); + usb2_callout_stop(&uvp->amrr_ch); - switch (sc->sc_state) { + switch (nstate) { case IEEE80211_S_INIT: - if (ostate == IEEE80211_S_RUN) { + if (vap->iv_state == IEEE80211_S_RUN) { /* abort TSF synchronization */ ural_write(sc, RAL_TXRX_CSR19, 0); @@ -758,13 +742,17 @@ ural_task(struct usb2_proc_msg *pm) if (m == NULL) { device_printf(sc->sc_dev, "could not allocate beacon\n"); - return; + RAL_UNLOCK(sc); + IEEE80211_LOCK(ic); + return (-1); } ieee80211_ref_node(ni); if (ural_tx_bcn(sc, m, ni) != 0) { device_printf(sc->sc_dev, "could not send beacon\n"); - return; + RAL_UNLOCK(sc); + IEEE80211_LOCK(ic); + return (-1); } } @@ -784,75 +772,9 @@ ural_task(struct usb2_proc_msg *pm) default: break; } - RAL_UNLOCK(sc); IEEE80211_LOCK(ic); - uvp->newstate(vap, sc->sc_state, sc->sc_arg); - if (vap->iv_newstate_cb != NULL) - vap->iv_newstate_cb(vap, sc->sc_state, sc->sc_arg); - IEEE80211_UNLOCK(ic); - RAL_LOCK(sc); -} - -static void -ural_scantask(struct usb2_proc_msg *pm) -{ - struct ural_task *task = (struct ural_task *)pm; - struct ural_softc *sc = task->sc; - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; - - RAL_LOCK_ASSERT(sc, MA_OWNED); - - switch (sc->sc_scan_action) { - case URAL_SCAN_START: - /* abort TSF synchronization */ - DPRINTF("starting scan\n"); - ural_write(sc, RAL_TXRX_CSR19, 0); - ural_set_bssid(sc, ifp->if_broadcastaddr); - break; - - case URAL_SET_CHANNEL: - ural_set_chan(sc, ic->ic_curchan); - break; - - default: /* URAL_SCAN_END */ - DPRINTF("stopping scan\n"); - ural_enable_tsf_sync(sc); - ural_set_bssid(sc, sc->sc_bssid); - break; - } -} - -static int -ural_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) -{ - struct ural_vap *uvp = URAL_VAP(vap); - struct ieee80211com *ic = vap->iv_ic; - struct ural_softc *sc = ic->ic_ifp->if_softc; - - DPRINTF("%s -> %s\n", - ieee80211_state_name[vap->iv_state], - ieee80211_state_name[nstate]); - - RAL_LOCK(sc); - usb2_callout_stop(&uvp->amrr_ch); - - /* do it in a process context */ - sc->sc_state = nstate; - sc->sc_arg = arg; - RAL_UNLOCK(sc); - - if (nstate == IEEE80211_S_INIT) { - uvp->newstate(vap, nstate, arg); - return 0; - } else { - RAL_LOCK(sc); - ural_queue_command(sc, ural_task, &sc->sc_task[0].hdr, - &sc->sc_task[1].hdr); - RAL_UNLOCK(sc); - return EINPROGRESS; - } + return (uvp->newstate(vap, nstate, arg)); } @@ -867,10 +789,6 @@ ural_bulk_write_callback(struct usb2_xfer *xfer) struct mbuf *m; unsigned int len; - /* wakeup waiting command, if any */ - if (sc->sc_last_task != NULL) - cv_signal(&sc->sc_cmd_cv); - switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: DPRINTFN(11, "transfer complete, %d bytes\n", xfer->actlen); @@ -886,10 +804,6 @@ ural_bulk_write_callback(struct usb2_xfer *xfer) /* FALLTHROUGH */ case USB_ST_SETUP: tr_setup: - /* wait for command to complete, if any */ - if (sc->sc_last_task != NULL) - break; - data = STAILQ_FIRST(&sc->tx_q); if (data) { STAILQ_REMOVE_HEAD(&sc->tx_q, next); @@ -1458,20 +1372,13 @@ ural_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) RAL_LOCK(sc); if (ifp->if_flags & IFF_UP) { if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { - ural_queue_command(sc, ural_init_task, - &sc->sc_synctask[0].hdr, - &sc->sc_synctask[1].hdr); + ural_init_locked(sc); startall = 1; } else - ural_queue_command(sc, ural_promisctask, - &sc->sc_promisctask[0].hdr, - &sc->sc_promisctask[1].hdr); + ural_setpromisc(sc); } else { - if (ifp->if_drv_flags & IFF_DRV_RUNNING) { - ural_queue_command(sc, ural_stop_task, - &sc->sc_synctask[0].hdr, - &sc->sc_synctask[1].hdr); - } + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + ural_stop(sc); } RAL_UNLOCK(sc); if (startall) @@ -1699,15 +1606,13 @@ ural_newassoc(struct ieee80211_node *ni, int isnew) static void ural_scan_start(struct ieee80211com *ic) { - struct ural_softc *sc = ic->ic_ifp->if_softc; + struct ifnet *ifp = ic->ic_ifp; + struct ural_softc *sc = ifp->if_softc; RAL_LOCK(sc); - /* do it in a process context */ - sc->sc_scan_action = URAL_SCAN_START; - ural_queue_command(sc, ural_scantask, - &sc->sc_scantask[0].hdr, &sc->sc_scantask[1].hdr); + ural_write(sc, RAL_TXRX_CSR19, 0); + ural_set_bssid(sc, ifp->if_broadcastaddr); RAL_UNLOCK(sc); - } static void @@ -1716,10 +1621,8 @@ ural_scan_end(struct ieee80211com *ic) struct ural_softc *sc = ic->ic_ifp->if_softc; RAL_LOCK(sc); - /* do it in a process context */ - sc->sc_scan_action = URAL_SCAN_END; - ural_queue_command(sc, ural_scantask, - &sc->sc_scantask[0].hdr, &sc->sc_scantask[1].hdr); + ural_enable_tsf_sync(sc); + ural_set_bssid(sc, sc->sc_bssid); RAL_UNLOCK(sc); } @@ -1730,10 +1633,7 @@ ural_set_channel(struct ieee80211com *ic) struct ural_softc *sc = ic->ic_ifp->if_softc; RAL_LOCK(sc); - /* do it in a process context */ - sc->sc_scan_action = URAL_SET_CHANNEL; - ural_queue_command(sc, ural_scantask, - &sc->sc_scantask[0].hdr, &sc->sc_scantask[1].hdr); + ural_set_chan(sc, ic->ic_curchan); RAL_UNLOCK(sc); } @@ -1994,10 +1894,8 @@ ural_set_macaddr(struct ural_softc *sc, uint8_t *addr) } static void -ural_promisctask(struct usb2_proc_msg *pm) +ural_setpromisc(struct ural_softc *sc) { - struct ural_task *task = (struct ural_task *)pm; - struct ural_softc *sc = task->sc; struct ifnet *ifp = sc->sc_ifp; uint32_t tmp; @@ -2022,9 +1920,7 @@ ural_update_promisc(struct ifnet *ifp) return; RAL_LOCK(sc); - ural_queue_command(sc, ural_promisctask, - &sc->sc_promisctask[0].hdr, - &sc->sc_promisctask[1].hdr); + ural_setpromisc(sc); RAL_UNLOCK(sc); } @@ -2152,11 +2048,9 @@ ural_set_rxantenna(struct ural_softc *sc, int antenna) } static void -ural_init_task(struct usb2_proc_msg *pm) +ural_init_locked(struct ural_softc *sc) { #define N(a) (sizeof (a) / sizeof ((a)[0])) - struct ural_task *task = (struct ural_task *)pm; - struct ural_softc *sc = task->sc; struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; uint16_t tmp; @@ -2167,7 +2061,7 @@ ural_init_task(struct usb2_proc_msg *pm) ural_set_testmode(sc); ural_write(sc, 0x308, 0x00f0); /* XXX magic */ - ural_stop_task(pm); + ural_stop(sc); /* initialize MAC registers to default values */ for (i = 0; i < N(ural_def_mac); i++) @@ -2229,7 +2123,7 @@ ural_init_task(struct usb2_proc_msg *pm) usb2_transfer_start(sc->sc_xfer[URAL_BULK_RD]); return; -fail: ural_stop_task(pm); +fail: ural_stop(sc); #undef N } @@ -2241,9 +2135,7 @@ ural_init(void *priv) struct ieee80211com *ic = ifp->if_l2com; RAL_LOCK(sc); - ural_queue_command(sc, ural_init_task, - &sc->sc_synctask[0].hdr, - &sc->sc_synctask[1].hdr); + ural_init_locked(sc); RAL_UNLOCK(sc); if (ifp->if_drv_flags & IFF_DRV_RUNNING) @@ -2251,10 +2143,8 @@ ural_init(void *priv) } static void -ural_stop_task(struct usb2_proc_msg *pm) +ural_stop(struct ural_softc *sc) { - struct ural_task *task = (struct ural_task *)pm; - struct ural_softc *sc = task->sc; struct ifnet *ifp = sc->sc_ifp; RAL_LOCK_ASSERT(sc, MA_OWNED); @@ -2350,24 +2240,24 @@ static void ural_amrr_timeout(void *arg) { struct ural_vap *uvp = arg; - struct ural_softc *sc = uvp->sc; + struct ieee80211vap *vap = &uvp->vap; + struct ieee80211com *ic = vap->iv_ic; - ural_queue_command(sc, ural_amrr_task, - &uvp->amrr_task[0].hdr, &uvp->amrr_task[1].hdr); + ieee80211_runtask(ic, &uvp->amrr_task); } static void -ural_amrr_task(struct usb2_proc_msg *pm) +ural_amrr_task(void *arg, int pending) { - struct ural_task *task = (struct ural_task *)pm; - struct ural_softc *sc = task->sc; - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); - struct ural_vap *uvp = URAL_VAP(vap); + struct ural_vap *uvp = arg; + struct ieee80211vap *vap = &uvp->vap; + struct ieee80211com *ic = vap->iv_ic; + struct ifnet *ifp = ic->ic_ifp; + struct ural_softc *sc = ifp->if_softc; struct ieee80211_node *ni = vap->iv_bss; int ok, fail; + RAL_LOCK(sc); /* read and clear statistic registers (STA_CSR0 to STA_CSR10) */ ural_read_multi(sc, RAL_STA_CSR0, sc->sta, sizeof(sc->sta)); @@ -2382,73 +2272,13 @@ ural_amrr_task(struct usb2_proc_msg *pm) ifp->if_oerrors += fail; /* count TX retry-fail as Tx errors */ usb2_callout_reset(&uvp->amrr_ch, hz, ural_amrr_timeout, uvp); + RAL_UNLOCK(sc); } static int ural_pause(struct ural_softc *sc, int timeout) { - if (usb2_proc_is_gone(&sc->sc_tq)) - return (1); usb2_pause_mtx(&sc->sc_mtx, timeout); return (0); } - -static void -ural_command_wrapper(struct usb2_proc_msg *pm) -{ - struct ural_task *task = (struct ural_task *)pm; - struct ural_softc *sc = task->sc; - struct ifnet *ifp; - - /* wait for pending transfer, if any */ - while (usb2_transfer_pending(sc->sc_xfer[URAL_BULK_WR])) - cv_wait(&sc->sc_cmd_cv, &sc->sc_mtx); - - /* make sure any hardware FIFOs are emptied */ - ural_pause(sc, hz / 1000); - - /* execute task */ - task->func(pm); - - /* check if this is the last task executed */ - if (sc->sc_last_task == task) { - sc->sc_last_task = NULL; - ifp = sc->sc_ifp; - /* re-start TX, if any */ - if ((ifp != NULL) && (ifp->if_drv_flags & IFF_DRV_RUNNING)) - usb2_transfer_start(sc->sc_xfer[URAL_BULK_WR]); - } -} - -static void -ural_queue_command(struct ural_softc *sc, usb2_proc_callback_t *fn, - struct usb2_proc_msg *t0, struct usb2_proc_msg *t1) -{ - struct ural_task *task; - - RAL_LOCK_ASSERT(sc, MA_OWNED); - - /* - * NOTE: The task cannot get executed before we drop the - * "sc_mtx" mutex. It is safe to update fields in the message - * structure after that the message got queued. - */ - task = (struct ural_task *) - usb2_proc_msignal(&sc->sc_tq, t0, t1); - - /* Setup callback and softc pointers */ - task->hdr.pm_callback = ural_command_wrapper; - task->func = fn; - task->sc = sc; - - /* Make sure that any TX operation will stop */ - sc->sc_last_task = task; - - /* - * Init, stop and flush must be synchronous! - */ - if ((fn == ural_init_task) || (fn == ural_stop_task) || - (fn == ural_stop_task)) - usb2_proc_mwait(&sc->sc_tq, t0, t1); -} diff --git a/sys/dev/usb/wlan/if_uralvar.h b/sys/dev/usb/wlan/if_uralvar.h index 13a3df8..5149f6b 100644 --- a/sys/dev/usb/wlan/if_uralvar.h +++ b/sys/dev/usb/wlan/if_uralvar.h @@ -59,12 +59,6 @@ struct ural_tx_radiotap_header { struct ural_softc; -struct ural_task { - struct usb2_proc_msg hdr; - usb2_proc_callback_t *func; - struct ural_softc *sc; -}; - struct ural_tx_data { STAILQ_ENTRY(ural_tx_data) next; struct ural_softc *sc; @@ -83,11 +77,10 @@ struct ural_node { struct ural_vap { struct ieee80211vap vap; - struct ural_softc *sc; struct ieee80211_beacon_offsets bo; struct ieee80211_amrr amrr; struct usb2_callout amrr_ch; - struct ural_task amrr_task[2]; + struct task amrr_task; int (*newstate)(struct ieee80211vap *, enum ieee80211_state, int); @@ -104,21 +97,11 @@ struct ural_softc { struct ifnet *sc_ifp; device_t sc_dev; struct usb2_device *sc_udev; - struct usb2_process sc_tq; uint32_t asic_rev; uint8_t rf_rev; struct usb2_xfer *sc_xfer[URAL_N_TRANSFER]; - struct ural_task *sc_last_task; - - enum ieee80211_state sc_state; - int sc_arg; - int sc_scan_action; /* should be an enum */ - struct ural_task sc_synctask[2]; - struct ural_task sc_task[2]; - struct ural_task sc_promisctask[2]; - struct ural_task sc_scantask[2]; struct ural_tx_data tx_data[RAL_TX_LIST_COUNT]; ural_txdhead tx_q; @@ -127,7 +110,6 @@ struct ural_softc { struct ural_rx_desc sc_rx_desc; struct mtx sc_mtx; - struct cv sc_cmd_cv; uint16_t sta[11]; uint32_t rf_regs[4]; diff --git a/sys/dev/usb/wlan/if_zyd.c b/sys/dev/usb/wlan/if_zyd.c index 6858d55..c386ea8 100644 --- a/sys/dev/usb/wlan/if_zyd.c +++ b/sys/dev/usb/wlan/if_zyd.c @@ -26,20 +26,56 @@ __FBSDID("$FreeBSD$"); * ZyDAS ZD1211/ZD1211B USB WLAN driver. */ -#include "usbdevs.h" +#include <sys/param.h> +#include <sys/sockio.h> +#include <sys/sysctl.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/mbuf.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/module.h> +#include <sys/bus.h> +#include <sys/endian.h> +#include <sys/kdb.h> + +#include <machine/bus.h> +#include <machine/resource.h> +#include <sys/rman.h> + +#include <net/bpf.h> +#include <net/if.h> +#include <net/if_arp.h> +#include <net/ethernet.h> +#include <net/if_dl.h> +#include <net/if_media.h> +#include <net/if_types.h> + +#ifdef INET +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/in_var.h> +#include <netinet/if_ether.h> +#include <netinet/ip.h> +#endif + +#include <net80211/ieee80211_var.h> +#include <net80211/ieee80211_regdomain.h> +#include <net80211/ieee80211_radiotap.h> +#include <net80211/ieee80211_amrr.h> + #include <dev/usb/usb.h> -#include <dev/usb/usb_mfunc.h> #include <dev/usb/usb_error.h> - #include <dev/usb/usb_core.h> #include <dev/usb/usb_lookup.h> -#include <dev/usb/usb_process.h> #include <dev/usb/usb_debug.h> #include <dev/usb/usb_request.h> #include <dev/usb/usb_busdma.h> #include <dev/usb/usb_util.h> +#include "usbdevs.h" -#include <dev/usb/wlan/usb_wlan.h> #include <dev/usb/wlan/if_zydreg.h> #include <dev/usb/wlan/if_zydfw.h> @@ -74,7 +110,7 @@ enum { #endif #define zyd_do_request(sc,req,data) \ - usb2_do_request_proc((sc)->sc_udev, &(sc)->sc_tq, req, data, 0, NULL, 5000) + usb2_do_request_flags((sc)->sc_udev, &(sc)->sc_mtx, req, data, 0, NULL, 5000) static device_probe_t zyd_match; static device_attach_t zyd_attach; @@ -85,14 +121,6 @@ static usb2_callback_t zyd_intr_write_callback; static usb2_callback_t zyd_bulk_read_callback; static usb2_callback_t zyd_bulk_write_callback; -static usb2_proc_callback_t zyd_attach_post; -static usb2_proc_callback_t zyd_task; -static usb2_proc_callback_t zyd_scantask; -static usb2_proc_callback_t zyd_multitask; -static usb2_proc_callback_t zyd_init_task; -static usb2_proc_callback_t zyd_stop_task; -static usb2_proc_callback_t zyd_flush_task; - static struct ieee80211vap *zyd_vap_create(struct ieee80211com *, const char name[IFNAMSIZ], int unit, int opmode, int flags, const uint8_t bssid[IEEE80211_ADDR_LEN], @@ -137,7 +165,9 @@ static void zyd_start(struct ifnet *); static int zyd_raw_xmit(struct ieee80211_node *, struct mbuf *, const struct ieee80211_bpf_params *); static int zyd_ioctl(struct ifnet *, u_long, caddr_t); +static void zyd_init_locked(struct zyd_softc *); static void zyd_init(void *); +static void zyd_stop(struct zyd_softc *); static int zyd_loadfirmware(struct zyd_softc *); static void zyd_newassoc(struct ieee80211_node *, int); static void zyd_scan_start(struct ieee80211com *); @@ -166,8 +196,6 @@ static int zyd_maxim_set_channel(struct zyd_rf *, uint8_t); static int zyd_maxim2_init(struct zyd_rf *); static int zyd_maxim2_switch_radio(struct zyd_rf *, int); static int zyd_maxim2_set_channel(struct zyd_rf *, uint8_t); -static void zyd_queue_command(struct zyd_softc *, usb2_proc_callback_t *, - struct usb2_proc_msg *, struct usb2_proc_msg *); static const struct zyd_phy_pair zyd_def_phy[] = ZYD_DEF_PHY; static const struct zyd_phy_pair zyd_def_phyB[] = ZYD_DEF_PHYB; @@ -307,8 +335,10 @@ zyd_attach(device_t dev) { struct usb2_attach_arg *uaa = device_get_ivars(dev); struct zyd_softc *sc = device_get_softc(dev); + struct ifnet *ifp; + struct ieee80211com *ic; + uint8_t iface_index, bands; int error; - uint8_t iface_index; if (uaa->info.bcdDevice < 0x4330) { device_printf(dev, "device version mismatch: 0x%X " @@ -324,7 +354,6 @@ zyd_attach(device_t dev) mtx_init(&sc->sc_mtx, device_get_nameunit(sc->sc_dev), MTX_NETWORK_LOCK, MTX_DEF); - cv_init(&sc->sc_cmd_cv, "wtxdone"); STAILQ_INIT(&sc->sc_rqh); iface_index = ZYD_IFACE_INDEX; @@ -336,52 +365,19 @@ zyd_attach(device_t dev) "err=%s\n", usb2_errstr(error)); goto detach; } - error = usb2_proc_create(&sc->sc_tq, &sc->sc_mtx, - device_get_nameunit(dev), USB_PRI_MED); - if (error) { - device_printf(dev, "could not setup config thread!\n"); - goto detach; - } - /* fork rest of the attach code */ ZYD_LOCK(sc); - zyd_queue_command(sc, zyd_attach_post, - &sc->sc_synctask[0].hdr, - &sc->sc_synctask[1].hdr); - ZYD_UNLOCK(sc); - return (0); - -detach: - zyd_detach(dev); - return (ENXIO); /* failure */ -} - -static void -zyd_attach_post(struct usb2_proc_msg *pm) -{ - struct zyd_task *task = (struct zyd_task *)pm; - struct zyd_softc *sc = task->sc; - struct ifnet *ifp; - struct ieee80211com *ic; - int error; - uint8_t bands; - if ((error = zyd_get_macaddr(sc)) != 0) { device_printf(sc->sc_dev, "could not read EEPROM\n"); - return; + ZYD_UNLOCK(sc); + goto detach; } - - /* XXX Async attach race */ - if (usb2_proc_is_gone(&sc->sc_tq)) - return; - ZYD_UNLOCK(sc); ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); if (ifp == NULL) { device_printf(sc->sc_dev, "can not if_alloc()\n"); - ZYD_LOCK(sc); - return; + goto detach; } ifp->if_softc = sc; if_initname(ifp, "zyd", device_get_unit(sc->sc_dev)); @@ -437,7 +433,11 @@ zyd_attach_post(struct usb2_proc_msg *pm) if (bootverbose) ieee80211_announce(ic); - ZYD_LOCK(sc); + return (0); + +detach: + zyd_detach(dev); + return (ENXIO); /* failure */ } static int @@ -447,12 +447,8 @@ zyd_detach(device_t dev) struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic; - /* wait for any post attach or other command to complete */ - usb2_proc_drain(&sc->sc_tq); - /* stop all USB transfers */ usb2_transfer_unsetup(sc->sc_xfer, ZYD_N_TRANSFER); - usb2_proc_free(&sc->sc_tq); /* free TX list, if any */ zyd_unsetup_tx_list(sc); @@ -463,7 +459,6 @@ zyd_detach(device_t dev) ieee80211_ifdetach(ic); if_free(ifp); } - cv_destroy(&sc->sc_cmd_cv); mtx_destroy(&sc->sc_mtx); return (0); @@ -475,7 +470,6 @@ zyd_vap_create(struct ieee80211com *ic, const uint8_t bssid[IEEE80211_ADDR_LEN], const uint8_t mac[IEEE80211_ADDR_LEN]) { - struct zyd_softc *sc = ic->ic_ifp->if_softc; struct zyd_vap *zvp; struct ieee80211vap *vap; @@ -494,7 +488,6 @@ zyd_vap_create(struct ieee80211com *ic, zvp->newstate = vap->iv_newstate; vap->iv_newstate = zyd_newstate; - zvp->sc = sc; ieee80211_amrr_init(&zvp->amrr, vap, IEEE80211_AMRR_MIN_SUCCESS_THRESHOLD, IEEE80211_AMRR_MAX_SUCCESS_THRESHOLD, @@ -508,23 +501,9 @@ zyd_vap_create(struct ieee80211com *ic, } static void -zyd_flush_task(struct usb2_proc_msg *_pm) -{ - /* nothing to do */ -} - -static void zyd_vap_delete(struct ieee80211vap *vap) { struct zyd_vap *zvp = ZYD_VAP(vap); - struct zyd_softc *sc = zvp->sc; - - ZYD_LOCK(sc); - /* wait for any pending tasks to complete */ - zyd_queue_command(sc, zyd_flush_task, - &sc->sc_synctask[0].hdr, - &sc->sc_synctask[1].hdr); - ZYD_UNLOCK(sc); ieee80211_amrr_cleanup(&zvp->amrr); ieee80211_vap_detach(vap); @@ -606,34 +585,38 @@ zyd_node_alloc(struct ieee80211vap *vap __unused, return (zn != NULL) ? (&zn->ni) : (NULL); } -static void -zyd_task(struct usb2_proc_msg *pm) +static int +zyd_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) { - struct zyd_task *task = (struct zyd_task *)pm; - struct zyd_softc *sc = task->sc; - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); - struct ieee80211_node *ni = vap->iv_bss; struct zyd_vap *zvp = ZYD_VAP(vap); + struct ieee80211com *ic = vap->iv_ic; + struct zyd_softc *sc = ic->ic_ifp->if_softc; + struct ieee80211_node *ni; int error; - switch (sc->sc_state) { + DPRINTF(sc, ZYD_DEBUG_STATE, "%s: %s -> %s\n", __func__, + ieee80211_state_name[vap->iv_state], + ieee80211_state_name[nstate]); + + IEEE80211_UNLOCK(ic); + ZYD_LOCK(sc); + switch (nstate) { case IEEE80211_S_AUTH: zyd_set_chan(sc, ic->ic_curchan); break; case IEEE80211_S_RUN: + ni = vap->iv_bss; if (vap->iv_opmode == IEEE80211_M_MONITOR) break; /* turn link LED on */ error = zyd_set_led(sc, ZYD_LED1, 1); if (error != 0) - goto fail; - + break; + /* make data LED blink upon Tx */ zyd_write32_m(sc, sc->sc_fwbase + ZYD_FW_LINK_STATUS, 1); - + IEEE80211_ADDR_COPY(sc->sc_bssid, ni->ni_bssid); zyd_set_bssid(sc, sc->sc_bssid); break; @@ -643,40 +626,7 @@ zyd_task(struct usb2_proc_msg *pm) fail: ZYD_UNLOCK(sc); IEEE80211_LOCK(ic); - zvp->newstate(vap, sc->sc_state, sc->sc_arg); - if (vap->iv_newstate_cb != NULL) - vap->iv_newstate_cb(vap, sc->sc_state, sc->sc_arg); - IEEE80211_UNLOCK(ic); - ZYD_LOCK(sc); -} - -static int -zyd_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) -{ - struct zyd_vap *zvp = ZYD_VAP(vap); - struct ieee80211com *ic = vap->iv_ic; - struct zyd_softc *sc = ic->ic_ifp->if_softc; - - DPRINTF(sc, ZYD_DEBUG_STATE, "%s: %s -> %s\n", __func__, - ieee80211_state_name[vap->iv_state], - ieee80211_state_name[nstate]); - - ZYD_LOCK(sc); - /* do it in a process context */ - sc->sc_state = nstate; - sc->sc_arg = arg; - ZYD_UNLOCK(sc); - - if (nstate == IEEE80211_S_INIT) { - zvp->newstate(vap, nstate, arg); - return (0); - } else { - ZYD_LOCK(sc); - zyd_queue_command(sc, zyd_task, &sc->sc_task[0].hdr, - &sc->sc_task[1].hdr); - ZYD_UNLOCK(sc); - return (EINPROGRESS); - } + return (zvp->newstate(vap, nstate, arg)); } /* @@ -845,9 +795,6 @@ zyd_cmd(struct zyd_softc *sc, uint16_t code, const void *idata, int ilen, if (ilen > sizeof(cmd.data)) return (EINVAL); - if (usb2_proc_is_gone(&sc->sc_tq)) - return (ENXIO); - cmd.code = htole16(code); bcopy(idata, cmd.data, ilen); DPRINTF(sc, ZYD_DEBUG_CMD, "sending cmd %p = %*D\n", @@ -2012,15 +1959,6 @@ fail: } static void -zyd_multitask(struct usb2_proc_msg *pm) -{ - struct zyd_task *task = (struct zyd_task *)pm; - struct zyd_softc *sc = task->sc; - - zyd_set_multi(sc); -} - -static void zyd_set_multi(struct zyd_softc *sc) { int error; @@ -2073,8 +2011,7 @@ zyd_update_mcast(struct ifnet *ifp) return; ZYD_LOCK(sc); - zyd_queue_command(sc, zyd_multitask, - &sc->sc_mcasttask[0].hdr, &sc->sc_mcasttask[1].hdr); + zyd_set_multi(sc); ZYD_UNLOCK(sc); } @@ -2502,10 +2439,6 @@ zyd_bulk_write_callback(struct usb2_xfer *xfer) struct zyd_tx_data *data; struct mbuf *m; - /* wakeup any waiting command, if any */ - if (sc->sc_last_task != NULL) - cv_signal(&sc->sc_cmd_cv); - switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: DPRINTF(sc, ZYD_DEBUG_ANY, "transfer complete, %u bytes\n", @@ -2522,10 +2455,6 @@ zyd_bulk_write_callback(struct usb2_xfer *xfer) /* FALLTHROUGH */ case USB_ST_SETUP: tr_setup: - /* wait for command to complete, if any */ - if (sc->sc_last_task != NULL) - break; - data = STAILQ_FIRST(&sc->tx_q); if (data) { STAILQ_REMOVE_HEAD(&sc->tx_q, next); @@ -2757,22 +2686,14 @@ zyd_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) case SIOCSIFFLAGS: ZYD_LOCK(sc); if (ifp->if_flags & IFF_UP) { - if (ifp->if_drv_flags & IFF_DRV_RUNNING) { - zyd_queue_command(sc, zyd_multitask, - &sc->sc_mcasttask[0].hdr, - &sc->sc_mcasttask[1].hdr); - } else { - zyd_queue_command(sc, zyd_init_task, - &sc->sc_synctask[0].hdr, - &sc->sc_synctask[1].hdr); + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { + zyd_init_locked(sc); startall = 1; - } + } else + zyd_set_multi(sc); } else { - if (ifp->if_drv_flags & IFF_DRV_RUNNING) { - zyd_queue_command(sc, zyd_stop_task, - &sc->sc_synctask[0].hdr, - &sc->sc_synctask[1].hdr); - } + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + zyd_stop(sc); } ZYD_UNLOCK(sc); if (startall) @@ -2792,10 +2713,8 @@ zyd_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) } static void -zyd_init_task(struct usb2_proc_msg *pm) +zyd_init_locked(struct zyd_softc *sc) { - struct zyd_task *task = (struct zyd_task *)pm; - struct zyd_softc *sc = task->sc; struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; struct usb2_config_descriptor *cd; @@ -2850,7 +2769,7 @@ zyd_init_task(struct usb2_proc_msg *pm) } if (ifp->if_drv_flags & IFF_DRV_RUNNING) - zyd_stop_task(pm); + zyd_stop(sc); DPRINTF(sc, ZYD_DEBUG_INIT, "setting MAC address to %6D\n", IF_LLADDR(ifp), ":"); @@ -2898,7 +2817,7 @@ zyd_init_task(struct usb2_proc_msg *pm) return; -fail: zyd_stop_task(pm); +fail: zyd_stop(sc); return; } @@ -2910,9 +2829,7 @@ zyd_init(void *priv) struct ieee80211com *ic = ifp->if_l2com; ZYD_LOCK(sc); - zyd_queue_command(sc, zyd_init_task, - &sc->sc_synctask[0].hdr, - &sc->sc_synctask[1].hdr); + zyd_init_locked(sc); ZYD_UNLOCK(sc); if (ifp->if_drv_flags & IFF_DRV_RUNNING) @@ -2920,10 +2837,8 @@ zyd_init(void *priv) } static void -zyd_stop_task(struct usb2_proc_msg *pm) +zyd_stop(struct zyd_softc *sc) { - struct zyd_task *task = (struct zyd_task *)pm; - struct zyd_softc *sc = task->sc; struct ifnet *ifp = sc->sc_ifp; int error; @@ -3029,13 +2944,12 @@ zyd_newassoc(struct ieee80211_node *ni, int isnew) static void zyd_scan_start(struct ieee80211com *ic) { - struct zyd_softc *sc = ic->ic_ifp->if_softc; + struct ifnet *ifp = ic->ic_ifp; + struct zyd_softc *sc = ifp->if_softc; ZYD_LOCK(sc); - /* do it in a process context */ - sc->sc_scan_action = ZYD_SCAN_START; - zyd_queue_command(sc, zyd_scantask, - &sc->sc_scantask[0].hdr, &sc->sc_scantask[1].hdr); + /* want broadcast address while scanning */ + zyd_set_bssid(sc, ifp->if_broadcastaddr); ZYD_UNLOCK(sc); } @@ -3045,10 +2959,8 @@ zyd_scan_end(struct ieee80211com *ic) struct zyd_softc *sc = ic->ic_ifp->if_softc; ZYD_LOCK(sc); - /* do it in a process context */ - sc->sc_scan_action = ZYD_SCAN_END; - zyd_queue_command(sc, zyd_scantask, - &sc->sc_scantask[0].hdr, &sc->sc_scantask[1].hdr); + /* restore previous bssid */ + zyd_set_bssid(sc, sc->sc_bssid); ZYD_UNLOCK(sc); } @@ -3058,105 +2970,16 @@ zyd_set_channel(struct ieee80211com *ic) struct zyd_softc *sc = ic->ic_ifp->if_softc; ZYD_LOCK(sc); - /* do it in a process context */ - sc->sc_scan_action = ZYD_SET_CHANNEL; - zyd_queue_command(sc, zyd_scantask, - &sc->sc_scantask[0].hdr, &sc->sc_scantask[1].hdr); + zyd_set_chan(sc, ic->ic_curchan); ZYD_UNLOCK(sc); } -static void -zyd_scantask(struct usb2_proc_msg *pm) -{ - struct zyd_task *task = (struct zyd_task *)pm; - struct zyd_softc *sc = task->sc; - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; - - ZYD_LOCK_ASSERT(sc, MA_OWNED); - - switch (sc->sc_scan_action) { - case ZYD_SCAN_START: - /* want broadcast address while scanning */ - zyd_set_bssid(sc, ifp->if_broadcastaddr); - break; - - case ZYD_SET_CHANNEL: - zyd_set_chan(sc, ic->ic_curchan); - break; - - default: /* ZYD_SCAN_END */ - /* restore previous bssid */ - zyd_set_bssid(sc, sc->sc_bssid); - break; - } -} - -static void -zyd_command_wrapper(struct usb2_proc_msg *pm) -{ - struct zyd_task *task = (struct zyd_task *)pm; - struct zyd_softc *sc = task->sc; - struct ifnet *ifp; - - /* wait for pending transfer, if any */ - while (usb2_transfer_pending(sc->sc_xfer[ZYD_BULK_WR])) - cv_wait(&sc->sc_cmd_cv, &sc->sc_mtx); - - /* make sure any hardware FIFOs are emptied */ - usb2_pause_mtx(&sc->sc_mtx, hz / 1000); - - /* execute task */ - task->func(pm); - - /* check if this is the last task executed */ - if (sc->sc_last_task == task) { - sc->sc_last_task = NULL; - ifp = sc->sc_ifp; - /* re-start TX, if any */ - if ((ifp != NULL) && (ifp->if_drv_flags & IFF_DRV_RUNNING)) - usb2_transfer_start(sc->sc_xfer[ZYD_BULK_WR]); - } -} - -static void -zyd_queue_command(struct zyd_softc *sc, usb2_proc_callback_t *fn, - struct usb2_proc_msg *t0, struct usb2_proc_msg *t1) -{ - struct zyd_task *task; - - ZYD_LOCK_ASSERT(sc, MA_OWNED); - - /* - * NOTE: The task cannot get executed before we drop the - * "sc_mtx" mutex. It is safe to update fields in the message - * structure after that the message got queued. - */ - task = (struct zyd_task *) - usb2_proc_msignal(&sc->sc_tq, t0, t1); - - /* Setup callback and softc pointers */ - task->hdr.pm_callback = zyd_command_wrapper; - task->func = fn; - task->sc = sc; - - /* Make sure that any TX operation will stop */ - sc->sc_last_task = task; - - /* - * Init and stop must be synchronous! - */ - if ((fn == zyd_init_task) || (fn == zyd_stop_task) || - (fn == zyd_flush_task)) - usb2_proc_mwait(&sc->sc_tq, t0, t1); -} - static device_method_t zyd_methods[] = { /* Device interface */ DEVMETHOD(device_probe, zyd_match), DEVMETHOD(device_attach, zyd_attach), DEVMETHOD(device_detach, zyd_detach), - + { 0, 0 } }; diff --git a/sys/dev/usb/wlan/if_zydreg.h b/sys/dev/usb/wlan/if_zydreg.h index fabed61..cd60593 100644 --- a/sys/dev/usb/wlan/if_zydreg.h +++ b/sys/dev/usb/wlan/if_zydreg.h @@ -1163,12 +1163,6 @@ struct zyd_mac_pair { uint32_t val; }; -struct zyd_task { - struct usb2_proc_msg hdr; - usb2_proc_callback_t *func; - struct zyd_softc *sc; -}; - struct zyd_tx_data { STAILQ_ENTRY(zyd_tx_data) next; struct zyd_softc *sc; @@ -1248,7 +1242,6 @@ struct zyd_vap { struct ieee80211vap vap; int (*newstate)(struct ieee80211vap *, enum ieee80211_state, int); - struct zyd_softc *sc; struct ieee80211_amrr amrr; }; #define ZYD_VAP(vap) ((struct zyd_vap *)(vap)) @@ -1265,27 +1258,14 @@ struct zyd_softc { struct ifnet *sc_ifp; device_t sc_dev; struct usb2_device *sc_udev; - struct usb2_process sc_tq; struct usb2_xfer *sc_xfer[ZYD_N_TRANSFER]; - struct zyd_task *sc_last_task; - enum ieee80211_state sc_state; - int sc_arg; int sc_flags; #define ZYD_FLAG_FWLOADED (1 << 0) #define ZYD_FLAG_INITONCE (1 << 1) #define ZYD_FLAG_INITDONE (1 << 2) - struct zyd_task sc_synctask[2]; - struct zyd_task sc_mcasttask[2]; - struct zyd_task sc_scantask[2]; - int sc_scan_action; -#define ZYD_SCAN_START 0 -#define ZYD_SCAN_END 1 -#define ZYD_SET_CHANNEL 2 - struct zyd_task sc_task[2]; - struct zyd_rf sc_rf; STAILQ_HEAD(, zyd_rq) sc_rtx; @@ -1317,7 +1297,6 @@ struct zyd_softc { uint8_t sc_ofdm54_cal[14]; struct mtx sc_mtx; - struct cv sc_cmd_cv; struct zyd_tx_data tx_data[ZYD_TX_LIST_CNT]; zyd_txdhead tx_q; zyd_txdhead tx_free; diff --git a/sys/dev/usb/wlan/usb_wlan.h b/sys/dev/usb/wlan/usb_wlan.h deleted file mode 100644 index aa0f1c4..0000000 --- a/sys/dev/usb/wlan/usb_wlan.h +++ /dev/null @@ -1,56 +0,0 @@ -/* $FreeBSD$ */ -/*- - * Copyright (c) 2008 Hans Petter Selasky. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef _USB2_WLAN_H_ -#define _USB2_WLAN_H_ - -#include <sys/param.h> -#include <sys/sockio.h> -#include <sys/mbuf.h> -#include <sys/kernel.h> -#include <sys/socket.h> - -#include <net/bpf.h> -#include <net/if.h> -#include <net/if_arp.h> -#include <net/ethernet.h> -#include <net/if_dl.h> -#include <net/if_media.h> -#include <net/if_types.h> -#include <net/if_clone.h> - -#include <net80211/ieee80211_var.h> -#include <net80211/ieee80211_radiotap.h> -#include <net80211/ieee80211_amrr.h> -#include <net80211/ieee80211_regdomain.h> - -#include <netinet/in.h> -#include <netinet/in_systm.h> -#include <netinet/in_var.h> -#include <netinet/ip.h> -#include <netinet/if_ether.h> - -#endif /* _USB2_WLAN_H_ */ diff --git a/sys/dev/wi/if_wi.c b/sys/dev/wi/if_wi.c index a4a74e4..3dce847 100644 --- a/sys/dev/wi/if_wi.c +++ b/sys/dev/wi/if_wi.c @@ -78,7 +78,6 @@ __FBSDID("$FreeBSD$"); #include <sys/random.h> #include <sys/syslog.h> #include <sys/sysctl.h> -#include <sys/taskqueue.h> #include <machine/bus.h> #include <machine/resource.h> @@ -134,10 +133,6 @@ static void wi_rx_intr(struct wi_softc *); static void wi_tx_intr(struct wi_softc *); static void wi_tx_ex_intr(struct wi_softc *); -static void wi_status_connected(void *, int); -static void wi_status_disconnected(void *, int); -static void wi_status_oor(void *, int); -static void wi_status_assoc_failed(void *, int); static void wi_info_intr(struct wi_softc *); static int wi_write_txrate(struct wi_softc *, struct ieee80211vap *); @@ -451,7 +446,6 @@ wi_attach(device_t dev) } sc->sc_portnum = WI_DEFAULT_PORT; - TASK_INIT(&sc->sc_oor_task, 0, wi_status_oor, ic); ieee80211_ifattach(ic, macaddr); ic->ic_raw_xmit = wi_raw_xmit; @@ -574,10 +568,6 @@ wi_vap_create(struct ieee80211com *ic, break; } - TASK_INIT(&wvp->wv_connected_task, 0, wi_status_connected, vap); - TASK_INIT(&wvp->wv_disconnected_task, 0, wi_status_disconnected, vap); - TASK_INIT(&wvp->wv_assoc_failed_task, 0, wi_status_assoc_failed, vap); - /* complete setup */ ieee80211_vap_attach(vap, ieee80211_media_change, wi_media_status); ic->ic_opmode = opmode; @@ -902,7 +892,7 @@ wi_newstate_sta(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) * notification we get on association. */ vap->iv_state = nstate; - return EINPROGRESS; + return (0); } return WI_VAP(vap)->wv_newstate(vap, nstate, arg); } @@ -1512,55 +1502,12 @@ wi_tx_intr(struct wi_softc *sc) } } -static void -wi_status_connected(void *arg, int pending) -{ - struct ieee80211vap *vap = arg; - struct ieee80211com *ic = vap->iv_ic; - - IEEE80211_LOCK(ic); - vap->iv_bss->ni_associd = 1 | 0xc000; /* NB: anything will do */ - WI_VAP(vap)->wv_newstate(vap, IEEE80211_S_RUN, 0); - if (vap->iv_newstate_cb != NULL) - vap->iv_newstate_cb(vap, IEEE80211_S_RUN, 0); - IEEE80211_UNLOCK(ic); -} - -static void -wi_status_disconnected(void *arg, int pending) -{ - struct ieee80211vap *vap = arg; - - if (vap->iv_state == IEEE80211_S_RUN) { - vap->iv_bss->ni_associd = 0; - vap->iv_stats.is_rx_deauth++; - ieee80211_new_state(vap, IEEE80211_S_SCAN, 0); - } -} - -static void -wi_status_oor(void *arg, int pending) -{ - struct ieee80211com *ic = arg; - - ieee80211_beacon_miss(ic); -} - -static void -wi_status_assoc_failed(void *arg, int pending) -{ - struct ieee80211vap *vap = arg; - - ieee80211_new_state(vap, IEEE80211_S_SCAN, IEEE80211_SCAN_FAIL_TIMEOUT); -} - static __noinline void wi_info_intr(struct wi_softc *sc) { struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); - struct wi_vap *wvp = WI_VAP(vap); int i, fid, len, off; u_int16_t ltbuf[2]; u_int16_t stat; @@ -1580,22 +1527,29 @@ wi_info_intr(struct wi_softc *sc) break; /* fall thru... */ case WI_INFO_LINK_STAT_AP_CHG: - taskqueue_enqueue(taskqueue_swi, &wvp->wv_connected_task); + IEEE80211_LOCK(ic); + vap->iv_bss->ni_associd = 1 | 0xc000; /* NB: anything will do */ + ieee80211_new_state(vap, IEEE80211_S_RUN, 0); + IEEE80211_UNLOCK(ic); break; case WI_INFO_LINK_STAT_AP_INR: break; case WI_INFO_LINK_STAT_DISCONNECTED: /* we dropped off the net; e.g. due to deauth/disassoc */ - taskqueue_enqueue(taskqueue_swi, &wvp->wv_disconnected_task); + IEEE80211_LOCK(ic); + vap->iv_bss->ni_associd = 0; + vap->iv_stats.is_rx_deauth++; + ieee80211_new_state(vap, IEEE80211_S_SCAN, 0); + IEEE80211_UNLOCK(ic); break; case WI_INFO_LINK_STAT_AP_OOR: /* XXX does this need to be per-vap? */ - taskqueue_enqueue(taskqueue_swi, &sc->sc_oor_task); + ieee80211_beacon_miss(ic); break; case WI_INFO_LINK_STAT_ASSOC_FAILED: if (vap->iv_opmode == IEEE80211_M_STA) - taskqueue_enqueue(taskqueue_swi, - &wvp->wv_assoc_failed_task); + ieee80211_new_state(vap, IEEE80211_S_SCAN, + IEEE80211_SCAN_FAIL_TIMEOUT); break; } break; diff --git a/sys/dev/wi/if_wivar.h b/sys/dev/wi/if_wivar.h index a66c74b..fdcedd8 100644 --- a/sys/dev/wi/if_wivar.h +++ b/sys/dev/wi/if_wivar.h @@ -59,9 +59,6 @@ struct wi_vap { struct ieee80211vap wv_vap; struct ieee80211_beacon_offsets wv_bo; - struct task wv_connected_task; - struct task wv_disconnected_task; - struct task wv_assoc_failed_task; void (*wv_recv_mgmt)(struct ieee80211_node *, struct mbuf *, int, int, int, u_int32_t); @@ -75,7 +72,6 @@ struct wi_softc { device_t sc_dev; struct mtx sc_mtx; struct callout sc_watchdog; - struct task sc_oor_task; int sc_unit; int wi_gone; int sc_enabled; diff --git a/sys/dev/wpi/if_wpi.c b/sys/dev/wpi/if_wpi.c index 1e980aa..0ab8680 100644 --- a/sys/dev/wpi/if_wpi.c +++ b/sys/dev/wpi/if_wpi.c @@ -192,12 +192,9 @@ static void wpi_rx_intr(struct wpi_softc *, struct wpi_rx_desc *, struct wpi_rx_data *); static void wpi_tx_intr(struct wpi_softc *, struct wpi_rx_desc *); static void wpi_cmd_intr(struct wpi_softc *, struct wpi_rx_desc *); -static void wpi_bmiss(void *, int); static void wpi_notif_intr(struct wpi_softc *); static void wpi_intr(void *); -static void wpi_ops(void *, int); static uint8_t wpi_plcp_signal(int); -static int wpi_queue_cmd(struct wpi_softc *, int, int, int); static void wpi_watchdog(void *); static int wpi_tx_data(struct wpi_softc *, struct mbuf *, struct ieee80211_node *, int); @@ -230,6 +227,8 @@ static int wpi_config(struct wpi_softc *); static void wpi_stop_master(struct wpi_softc *); static int wpi_power_up(struct wpi_softc *); static int wpi_reset(struct wpi_softc *); +static void wpi_hwreset(void *, int); +static void wpi_rfreset(void *, int); static void wpi_hw_config(struct wpi_softc *); static void wpi_init(void *); static void wpi_init_locked(struct wpi_softc *, int); @@ -514,21 +513,11 @@ wpi_attach(device_t dev) } } - /* - * Create the taskqueues used by the driver. Primarily - * sc_tq handles most the task - */ - sc->sc_tq = taskqueue_create("wpi_taskq", M_NOWAIT | M_ZERO, - taskqueue_thread_enqueue, &sc->sc_tq); - taskqueue_start_threads(&sc->sc_tq, 1, PI_NET, "%s taskq", - device_get_nameunit(dev)); - /* Create the tasks that can be queued */ - TASK_INIT(&sc->sc_opstask, 0, wpi_ops, sc); - TASK_INIT(&sc->sc_bmiss_task, 0, wpi_bmiss, sc); + TASK_INIT(&sc->sc_restarttask, 0, wpi_hwreset, sc); + TASK_INIT(&sc->sc_radiotask, 0, wpi_rfreset, sc); WPI_LOCK_INIT(sc); - WPI_CMD_LOCK_INIT(sc); callout_init_mtx(&sc->calib_to, &sc->sc_mtx, 0); callout_init_mtx(&sc->watchdog_to, &sc->sc_mtx, 0); @@ -732,6 +721,9 @@ wpi_detach(device_t dev) struct ieee80211com *ic = ifp->if_l2com; int ac; + ieee80211_draintask(ic, &sc->sc_restarttask); + ieee80211_draintask(ic, &sc->sc_radiotask); + if (ifp != NULL) { wpi_stop(sc); callout_drain(&sc->watchdog_to); @@ -769,10 +761,7 @@ wpi_detach(device_t dev) if (ifp != NULL) if_free(ifp); - taskqueue_free(sc->sc_tq); - WPI_LOCK_DESTROY(sc); - WPI_CMD_LOCK_DESTROY(sc); return 0; } @@ -1280,21 +1269,32 @@ wpi_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) ieee80211_state_name[vap->iv_state], ieee80211_state_name[nstate], sc->flags)); + IEEE80211_UNLOCK(ic); + WPI_LOCK(sc); if (nstate == IEEE80211_S_AUTH) { - /* Delay the auth transition until we can update the firmware */ - error = wpi_queue_cmd(sc, WPI_AUTH, arg, WPI_QUEUE_NORMAL); - return (error != 0 ? error : EINPROGRESS); + /* The node must be registered in the firmware before auth */ + error = wpi_auth(sc, vap); + if (error != 0) { + device_printf(sc->sc_dev, + "%s: could not move to auth state, error %d\n", + __func__, error); + } } if (nstate == IEEE80211_S_RUN && vap->iv_state != IEEE80211_S_RUN) { - /* set the association id first */ - error = wpi_queue_cmd(sc, WPI_RUN, arg, WPI_QUEUE_NORMAL); - return (error != 0 ? error : EINPROGRESS); + error = wpi_run(sc, vap); + if (error != 0) { + device_printf(sc->sc_dev, + "%s: could not move to run state, error %d\n", + __func__, error); + } } if (nstate == IEEE80211_S_RUN) { /* RUN -> RUN transition; just restart the timers */ wpi_calib_timeout(sc); /* XXX split out rate control timer */ } + WPI_UNLOCK(sc); + IEEE80211_LOCK(ic); return wvp->newstate(vap, nstate, arg); } @@ -1642,15 +1642,6 @@ wpi_cmd_intr(struct wpi_softc *sc, struct wpi_rx_desc *desc) } static void -wpi_bmiss(void *arg, int npending) -{ - struct wpi_softc *sc = arg; - struct ieee80211com *ic = sc->sc_ifp->if_l2com; - - ieee80211_beacon_miss(ic); -} - -static void wpi_notif_intr(struct wpi_softc *sc) { struct ifnet *ifp = sc->sc_ifp; @@ -1759,8 +1750,7 @@ wpi_notif_intr(struct wpi_softc *sc) DPRINTF(("Beacon miss: %u >= %u\n", le32toh(beacon->consecutive), vap->iv_bmissthreshold)); - taskqueue_enqueue(taskqueue_swi, - &sc->sc_bmiss_task); + ieee80211_beacon_miss(ic); } break; } @@ -1794,10 +1784,13 @@ wpi_intr(void *arg) WPI_WRITE(sc, WPI_INTR, r); if (r & (WPI_SW_ERROR | WPI_HW_ERROR)) { + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + device_printf(sc->sc_dev, "fatal firmware error\n"); DPRINTFN(6,("(%s)\n", (r & WPI_SW_ERROR) ? "(Software Error)" : "(Hardware Error)")); - wpi_queue_cmd(sc, WPI_RESTART, 0, WPI_QUEUE_CLEAR); + ieee80211_runtask(ic, &sc->sc_restarttask); sc->flags &= ~WPI_FLAG_BUSY; WPI_UNLOCK(sc); return; @@ -3030,8 +3023,7 @@ wpi_rfkill_resume(struct wpi_softc *sc) if (vap != NULL) { if ((ic->ic_flags & IEEE80211_F_SCAN) == 0) { if (vap->iv_opmode != IEEE80211_M_MONITOR) { - taskqueue_enqueue(taskqueue_swi, - &sc->sc_bmiss_task); + ieee80211_beacon_miss(ic); wpi_set_led(sc, WPI_LED_LINK, 0, 1); } else wpi_set_led(sc, WPI_LED_LINK, 5, 5); @@ -3189,12 +3181,6 @@ wpi_stop_locked(struct wpi_softc *sc) WPI_WRITE(sc, WPI_INTR_STATUS, 0xff); WPI_WRITE(sc, WPI_INTR_STATUS, 0x00070000); - /* Clear any commands left in the command buffer */ - memset(sc->sc_cmd, 0, sizeof(sc->sc_cmd)); - memset(sc->sc_cmd_arg, 0, sizeof(sc->sc_cmd_arg)); - sc->sc_cmd_cur = 0; - sc->sc_cmd_next = 0; - wpi_mem_lock(sc); wpi_mem_write(sc, WPI_MEM_MODE, 0); wpi_mem_unlock(sc); @@ -3538,7 +3524,9 @@ wpi_scan_start(struct ieee80211com *ic) struct ifnet *ifp = ic->ic_ifp; struct wpi_softc *sc = ifp->if_softc; - wpi_queue_cmd(sc, WPI_SCAN_START, 0, WPI_QUEUE_NORMAL); + WPI_LOCK(sc); + wpi_set_led(sc, WPI_LED_LINK, 20, 2); + WPI_UNLOCK(sc); } /** @@ -3549,10 +3537,7 @@ wpi_scan_start(struct ieee80211com *ic) static void wpi_scan_end(struct ieee80211com *ic) { - struct ifnet *ifp = ic->ic_ifp; - struct wpi_softc *sc = ifp->if_softc; - - wpi_queue_cmd(sc, WPI_SCAN_STOP, 0, WPI_QUEUE_NORMAL); + /* XXX ignore */ } /** @@ -3564,13 +3549,18 @@ wpi_set_channel(struct ieee80211com *ic) { struct ifnet *ifp = ic->ic_ifp; struct wpi_softc *sc = ifp->if_softc; + int error; /* * Only need to set the channel in Monitor mode. AP scanning and auth * are already taken care of by their respective firmware commands. */ - if (ic->ic_opmode == IEEE80211_M_MONITOR) - wpi_queue_cmd(sc, WPI_SET_CHAN, 0, WPI_QUEUE_NORMAL); + if (ic->ic_opmode == IEEE80211_M_MONITOR) { + error = wpi_config(sc); + if (error != 0) + device_printf(sc->sc_dev, + "error %d settting channel\n", error); + } } /** @@ -3585,7 +3575,10 @@ wpi_scan_curchan(struct ieee80211_scan_state *ss, unsigned long maxdwell) struct ifnet *ifp = vap->iv_ic->ic_ifp; struct wpi_softc *sc = ifp->if_softc; - wpi_queue_cmd(sc, WPI_SCAN_CURCHAN, 0, WPI_QUEUE_NORMAL); + WPI_LOCK(sc); + if (wpi_scan(sc)) + ieee80211_cancel_scan(vap); + WPI_UNLOCK(sc); } /** @@ -3600,152 +3593,24 @@ wpi_scan_mindwell(struct ieee80211_scan_state *ss) /* NB: don't try to abort scan; wait for firmware to finish */ } -/** - * The ops function is called to perform some actual work. - * because we can't sleep from any of the ic callbacks, we queue an - * op task with wpi_queue_cmd and have the taskqueue process that task. - * The task that gets cued is a op task, which ends up calling this function. - */ static void -wpi_ops(void *arg0, int pending) +wpi_hwreset(void *arg, int pending) { - struct wpi_softc *sc = arg0; - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; - int cmd, arg, error; - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); - -again: - WPI_CMD_LOCK(sc); - cmd = sc->sc_cmd[sc->sc_cmd_cur]; - arg = sc->sc_cmd_arg[sc->sc_cmd_cur]; + struct wpi_softc *sc = arg; - if (cmd == 0) { - /* No more commands to process */ - WPI_CMD_UNLOCK(sc); - return; - } - sc->sc_cmd[sc->sc_cmd_cur] = 0; /* free the slot */ - sc->sc_cmd_arg[sc->sc_cmd_cur] = 0; /* free the slot */ - sc->sc_cmd_cur = (sc->sc_cmd_cur + 1) % WPI_CMD_MAXOPS; - WPI_CMD_UNLOCK(sc); WPI_LOCK(sc); - - DPRINTFN(WPI_DEBUG_OPS,("wpi_ops: command: %d\n", cmd)); - - switch (cmd) { - case WPI_RESTART: - wpi_init_locked(sc, 0); - WPI_UNLOCK(sc); - return; - - case WPI_RF_RESTART: - wpi_rfkill_resume(sc); - WPI_UNLOCK(sc); - return; - } - - if (!(sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING)) { - WPI_UNLOCK(sc); - return; - } - - switch (cmd) { - case WPI_SCAN_START: - /* make the link LED blink while we're scanning */ - wpi_set_led(sc, WPI_LED_LINK, 20, 2); - sc->flags |= WPI_FLAG_SCANNING; - break; - - case WPI_SCAN_STOP: - sc->flags &= ~WPI_FLAG_SCANNING; - break; - - case WPI_SCAN_CURCHAN: - if (wpi_scan(sc)) - ieee80211_cancel_scan(vap); - break; - - case WPI_SET_CHAN: - error = wpi_config(sc); - if (error != 0) - device_printf(sc->sc_dev, - "error %d settting channel\n", error); - break; - - case WPI_AUTH: - /* The node must be registered in the firmware before auth */ - error = wpi_auth(sc, vap); - WPI_UNLOCK(sc); - if (error != 0) { - device_printf(sc->sc_dev, - "%s: could not move to auth state, error %d\n", - __func__, error); - return; - } - IEEE80211_LOCK(ic); - WPI_VAP(vap)->newstate(vap, IEEE80211_S_AUTH, arg); - if (vap->iv_newstate_cb != NULL) - vap->iv_newstate_cb(vap, IEEE80211_S_AUTH, arg); - IEEE80211_UNLOCK(ic); - goto again; - - case WPI_RUN: - error = wpi_run(sc, vap); - WPI_UNLOCK(sc); - if (error != 0) { - device_printf(sc->sc_dev, - "%s: could not move to run state, error %d\n", - __func__, error); - return; - } - IEEE80211_LOCK(ic); - WPI_VAP(vap)->newstate(vap, IEEE80211_S_RUN, arg); - if (vap->iv_newstate_cb != NULL) - vap->iv_newstate_cb(vap, IEEE80211_S_RUN, arg); - IEEE80211_UNLOCK(ic); - goto again; - } + wpi_init_locked(sc, 0); WPI_UNLOCK(sc); - - /* Take another pass */ - goto again; } -/** - * queue a command for later execution in a different thread. - * This is needed as the net80211 callbacks do not allow - * sleeping, since we need to sleep to confirm commands have - * been processed by the firmware, we must defer execution to - * a sleep enabled thread. - */ -static int -wpi_queue_cmd(struct wpi_softc *sc, int cmd, int arg, int flush) +static void +wpi_rfreset(void *arg, int pending) { - WPI_CMD_LOCK(sc); - - if (flush) { - memset(sc->sc_cmd, 0, sizeof (sc->sc_cmd)); - memset(sc->sc_cmd_arg, 0, sizeof (sc->sc_cmd_arg)); - sc->sc_cmd_cur = 0; - sc->sc_cmd_next = 0; - } - - if (sc->sc_cmd[sc->sc_cmd_next] != 0) { - WPI_CMD_UNLOCK(sc); - DPRINTF(("%s: command %d dropped\n", __func__, cmd)); - return (EBUSY); - } - - sc->sc_cmd[sc->sc_cmd_next] = cmd; - sc->sc_cmd_arg[sc->sc_cmd_next] = arg; - sc->sc_cmd_next = (sc->sc_cmd_next + 1) % WPI_CMD_MAXOPS; - - taskqueue_enqueue(sc->sc_tq, &sc->sc_opstask); - - WPI_CMD_UNLOCK(sc); + struct wpi_softc *sc = arg; - return 0; + WPI_LOCK(sc); + wpi_rfkill_resume(sc); + WPI_UNLOCK(sc); } /* @@ -3775,6 +3640,7 @@ wpi_watchdog(void *arg) { struct wpi_softc *sc = arg; struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; uint32_t tmp; DPRINTFN(WPI_DEBUG_WATCHDOG,("Watchdog: tick\n")); @@ -3790,7 +3656,7 @@ wpi_watchdog(void *arg) } device_printf(sc->sc_dev, "Hardware Switch Enabled\n"); - wpi_queue_cmd(sc, WPI_RF_RESTART, 0, WPI_QUEUE_CLEAR); + ieee80211_runtask(ic, &sc->sc_radiotask); return; } @@ -3798,17 +3664,15 @@ wpi_watchdog(void *arg) if (--sc->sc_tx_timer == 0) { device_printf(sc->sc_dev,"device timeout\n"); ifp->if_oerrors++; - wpi_queue_cmd(sc, WPI_RESTART, 0, WPI_QUEUE_CLEAR); + ieee80211_runtask(ic, &sc->sc_restarttask); } } if (sc->sc_scan_timer > 0) { - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); if (--sc->sc_scan_timer == 0 && vap != NULL) { device_printf(sc->sc_dev,"scan timeout\n"); ieee80211_cancel_scan(vap); - wpi_queue_cmd(sc, WPI_RESTART, 0, WPI_QUEUE_CLEAR); + ieee80211_runtask(ic, &sc->sc_restarttask); } } diff --git a/sys/dev/wpi/if_wpivar.h b/sys/dev/wpi/if_wpivar.h index a447fd3..36da3b1 100644 --- a/sys/dev/wpi/if_wpivar.h +++ b/sys/dev/wpi/if_wpivar.h @@ -144,9 +144,8 @@ struct wpi_softc { */ uint32_t flags; #define WPI_FLAG_HW_RADIO_OFF (1 << 0) -#define WPI_FLAG_SCANNING (1 << 1) -#define WPI_FLAG_BUSY (1 << 2) -#define WPI_FLAG_AUTH (1 << 3) +#define WPI_FLAG_BUSY (1 << 1) +#define WPI_FLAG_AUTH (1 << 2) /* shared area */ struct wpi_dma_info shared_dma; @@ -193,36 +192,9 @@ struct wpi_softc { /* firmware DMA transfer */ struct wpi_dma_info fw_dma; - /* command queue related variables */ -#define WPI_SCAN_START (1<<0) -#define WPI_SCAN_CURCHAN (1<<1) -#define WPI_SCAN_STOP (1<<2) -#define WPI_SET_CHAN (1<<3) -#define WPI_AUTH (1<<4) -#define WPI_RUN (1<<5) -#define WPI_SCAN_NEXT (1<<6) -#define WPI_RESTART (1<<7) -#define WPI_RF_RESTART (1<<8) -#define WPI_CMD_MAXOPS 10 - /* command queuing request type */ -#define WPI_QUEUE_NORMAL 0 -#define WPI_QUEUE_CLEAR 1 - int sc_cmd[WPI_CMD_MAXOPS]; - int sc_cmd_arg[WPI_CMD_MAXOPS]; - int sc_cmd_cur; /* current queued scan task */ - int sc_cmd_next; /* last queued scan task */ - struct mtx sc_cmdlock; - - /* Task queues used to control the driver */ - struct taskqueue *sc_tq; /* Main command task queue */ - struct taskqueue *sc_tq2; /* firmware reset task queue */ - /* Tasks used by the driver */ - struct task sc_radioontask; /* enable rf transmitter task*/ - struct task sc_radioofftask;/* disable rf transmitter task*/ - struct task sc_opstask; /* operation handling task */ struct task sc_restarttask; /* reset firmware task */ - struct task sc_bmiss_task; /* beacon miss */ + struct task sc_radiotask; /* reset rf task */ /* Eeprom info */ uint8_t cap; @@ -239,10 +211,3 @@ struct wpi_softc { #define WPI_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) #define WPI_LOCK_ASSERT(sc) mtx_assert(&(sc)->sc_mtx, MA_OWNED) #define WPI_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_mtx) - -#define WPI_CMD_LOCK_INIT(_sc) \ - mtx_init(&(_sc)->sc_cmdlock, device_get_nameunit((_sc)->sc_dev), \ - NULL, MTX_DEF) -#define WPI_CMD_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_cmdlock) -#define WPI_CMD_LOCK(_sc) mtx_lock(&(_sc)->sc_cmdlock) -#define WPI_CMD_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_cmdlock) diff --git a/sys/net80211/ieee80211.c b/sys/net80211/ieee80211.c index eb40f61..2e75965 100644 --- a/sys/net80211/ieee80211.c +++ b/sys/net80211/ieee80211.c @@ -33,7 +33,7 @@ __FBSDID("$FreeBSD$"); #include "opt_wlan.h" #include <sys/param.h> -#include <sys/systm.h> +#include <sys/systm.h> #include <sys/kernel.h> #include <sys/socket.h> @@ -251,6 +251,12 @@ ieee80211_ifattach(struct ieee80211com *ic, IEEE80211_LOCK_INIT(ic, ifp->if_xname); TAILQ_INIT(&ic->ic_vaps); + + /* Create a taskqueue for all state changes */ + ic->ic_tq = taskqueue_create("ic_taskq", M_WAITOK | M_ZERO, + taskqueue_thread_enqueue, &ic->ic_tq); + taskqueue_start_threads(&ic->ic_tq, 1, PI_NET, "%s taskq", + ifp->if_xname); /* * Fill in 802.11 available channel set, mark all * available channels as active, and pick a default @@ -325,6 +331,7 @@ ieee80211_ifdetach(struct ieee80211com *ic) ieee80211_node_detach(ic); ifmedia_removeall(&ic->ic_media); + taskqueue_free(ic->ic_tq); IEEE80211_LOCK_DESTROY(ic); if_detach(ifp); } @@ -554,7 +561,17 @@ ieee80211_vap_detach(struct ieee80211vap *vap) * while we cleanup internal state but that is hard. */ ieee80211_stop_locked(vap); + IEEE80211_UNLOCK(ic); + + /* + * Flush any deferred vap tasks. + * NB: must be before ether_ifdetach() and removal from ic_vaps list + */ + ieee80211_draintask(ic, &vap->iv_nstate_task); + ieee80211_draintask(ic, &vap->iv_swbmiss_task); + IEEE80211_LOCK(ic); + KASSERT(vap->iv_state == IEEE80211_S_INIT , ("vap still running")); TAILQ_REMOVE(&ic->ic_vaps, vap, iv_next); ieee80211_syncflag_locked(ic, IEEE80211_F_WME); #ifdef IEEE80211_SUPPORT_SUPERG @@ -627,9 +644,9 @@ ieee80211_syncifflag_locked(struct ieee80211com *ic, int flag) /* XXX should we return 1/0 and let caller do this? */ if (ifp->if_drv_flags & IFF_DRV_RUNNING) { if (flag == IFF_PROMISC) - ic->ic_update_promisc(ifp); + ieee80211_runtask(ic, &ic->ic_promisc_task); else if (flag == IFF_ALLMULTI) - ic->ic_update_mcast(ifp); + ieee80211_runtask(ic, &ic->ic_mcast_task); } } } diff --git a/sys/net80211/ieee80211_freebsd.h b/sys/net80211/ieee80211_freebsd.h index 2e0075e..3ed9ece 100644 --- a/sys/net80211/ieee80211_freebsd.h +++ b/sys/net80211/ieee80211_freebsd.h @@ -32,6 +32,7 @@ #include <sys/lock.h> #include <sys/mutex.h> #include <sys/rwlock.h> +#include <sys/taskqueue.h> /* * Common state locking definitions. diff --git a/sys/net80211/ieee80211_ioctl.c b/sys/net80211/ieee80211_ioctl.c index b28dffa..d40680a 100644 --- a/sys/net80211/ieee80211_ioctl.c +++ b/sys/net80211/ieee80211_ioctl.c @@ -42,7 +42,6 @@ __FBSDID("$FreeBSD$"); #include <sys/socket.h> #include <sys/sockio.h> #include <sys/systm.h> -#include <sys/taskqueue.h> #include <net/if.h> #include <net/if_dl.h> @@ -3196,8 +3195,7 @@ ieee80211_ioctl_updatemulti(struct ieee80211com *ic) (void) if_addmulti(parent, ifma->ifma_addr, NULL); } parent->if_ioctl = ioctl; - - ic->ic_update_mcast(ic->ic_ifp); + ieee80211_runtask(ic, &ic->ic_mcast_task); IEEE80211_UNLOCK(ic); } diff --git a/sys/net80211/ieee80211_node.c b/sys/net80211/ieee80211_node.c index 2f39eb8..483af2d 100644 --- a/sys/net80211/ieee80211_node.c +++ b/sys/net80211/ieee80211_node.c @@ -629,16 +629,18 @@ ieee80211_sync_curchan(struct ieee80211com *ic) ic->ic_curchan = c; ic->ic_curmode = ieee80211_chan2mode(ic->ic_curchan); ic->ic_rt = ieee80211_get_ratetable(ic->ic_curchan); + IEEE80211_UNLOCK(ic); ic->ic_set_channel(ic); + IEEE80211_LOCK(ic); } } /* - * Change the current channel. The request channel may be + * Setup the current channel. The request channel may be * promoted if other vap's are operating with HT20/HT40. */ void -ieee80211_setcurchan(struct ieee80211com *ic, struct ieee80211_channel *c) +ieee80211_setupcurchan(struct ieee80211com *ic, struct ieee80211_channel *c) { if (ic->ic_htcaps & IEEE80211_HTC_HT) { int flags = gethtadjustflags(ic); @@ -654,7 +656,17 @@ ieee80211_setcurchan(struct ieee80211com *ic, struct ieee80211_channel *c) ic->ic_bsschan = ic->ic_curchan = c; ic->ic_curmode = ieee80211_chan2mode(ic->ic_curchan); ic->ic_rt = ieee80211_get_ratetable(ic->ic_curchan); - ic->ic_set_channel(ic); +} + +/* + * Change the current channel. The channel change is guaranteed to have + * happened before the next state change. + */ +void +ieee80211_setcurchan(struct ieee80211com *ic, struct ieee80211_channel *c) +{ + ieee80211_setupcurchan(ic, c); + ieee80211_runtask(ic, &ic->ic_chan_task); } /* diff --git a/sys/net80211/ieee80211_node.h b/sys/net80211/ieee80211_node.h index 9e9d254..47f705f 100644 --- a/sys/net80211/ieee80211_node.h +++ b/sys/net80211/ieee80211_node.h @@ -286,6 +286,8 @@ void ieee80211_node_set_chan(struct ieee80211_node *, void ieee80211_create_ibss(struct ieee80211vap*, struct ieee80211_channel *); void ieee80211_reset_bss(struct ieee80211vap *); void ieee80211_sync_curchan(struct ieee80211com *); +void ieee80211_setupcurchan(struct ieee80211com *, + struct ieee80211_channel *); void ieee80211_setcurchan(struct ieee80211com *, struct ieee80211_channel *); int ieee80211_ibss_merge(struct ieee80211_node *); struct ieee80211_scan_entry; diff --git a/sys/net80211/ieee80211_proto.c b/sys/net80211/ieee80211_proto.c index 572580f..98888d8 100644 --- a/sys/net80211/ieee80211_proto.c +++ b/sys/net80211/ieee80211_proto.c @@ -37,7 +37,6 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/kernel.h> #include <sys/systm.h> -#include <sys/taskqueue.h> #include <sys/socket.h> #include <sys/sockio.h> @@ -96,7 +95,13 @@ const char *ieee80211_wme_acnames[] = { "WME_UPSD", }; +static void beacon_miss(void *, int); +static void beacon_swmiss(void *, int); static void parent_updown(void *, int); +static void update_mcast(void *, int); +static void update_promisc(void *, int); +static void update_channel(void *, int); +static void ieee80211_newstate_cb(void *, int); static int ieee80211_new_state_locked(struct ieee80211vap *, enum ieee80211_state, int); @@ -131,6 +136,10 @@ ieee80211_proto_attach(struct ieee80211com *ic) ic->ic_protmode = IEEE80211_PROT_CTSONLY; TASK_INIT(&ic->ic_parent_task, 0, parent_updown, ifp); + TASK_INIT(&ic->ic_mcast_task, 0, update_mcast, ic); + TASK_INIT(&ic->ic_promisc_task, 0, update_promisc, ic); + TASK_INIT(&ic->ic_chan_task, 0, update_channel, ic); + TASK_INIT(&ic->ic_bmiss_task, 0, beacon_miss, ic); ic->ic_wme.wme_hipri_switch_hysteresis = AGGRESSIVE_MODE_SWITCH_HYSTERESIS; @@ -176,6 +185,8 @@ ieee80211_proto_vattach(struct ieee80211vap *vap) vap->iv_bmiss_max = IEEE80211_BMISS_MAX; callout_init(&vap->iv_swbmiss, CALLOUT_MPSAFE); callout_init(&vap->iv_mgtsend, CALLOUT_MPSAFE); + TASK_INIT(&vap->iv_nstate_task, 0, ieee80211_newstate_cb, vap); + TASK_INIT(&vap->iv_swbmiss_task, 0, beacon_swmiss, vap); /* * Install default tx rate handling: no fixed rate, lowest * supported rate for mgmt and multicast frames. Default @@ -1072,6 +1083,32 @@ parent_updown(void *arg, int npending) parent->if_ioctl(parent, SIOCSIFFLAGS, NULL); } +static void +update_mcast(void *arg, int npending) +{ + struct ieee80211com *ic = arg; + struct ifnet *parent = ic->ic_ifp; + + ic->ic_update_mcast(parent); +} + +static void +update_promisc(void *arg, int npending) +{ + struct ieee80211com *ic = arg; + struct ifnet *parent = ic->ic_ifp; + + ic->ic_update_promisc(parent); +} + +static void +update_channel(void *arg, int npending) +{ + struct ieee80211com *ic = arg; + + ic->ic_set_channel(ic); +} + /* * Block until the parent is in a known state. This is * used after any operations that dispatch a task (e.g. @@ -1080,7 +1117,13 @@ parent_updown(void *arg, int npending) void ieee80211_waitfor_parent(struct ieee80211com *ic) { - taskqueue_drain(taskqueue_thread, &ic->ic_parent_task); + taskqueue_block(ic->ic_tq); + ieee80211_draintask(ic, &ic->ic_parent_task); + ieee80211_draintask(ic, &ic->ic_mcast_task); + ieee80211_draintask(ic, &ic->ic_promisc_task); + ieee80211_draintask(ic, &ic->ic_chan_task); + ieee80211_draintask(ic, &ic->ic_bmiss_task); + taskqueue_unblock(ic->ic_tq); } /* @@ -1121,7 +1164,7 @@ ieee80211_start_locked(struct ieee80211vap *vap) IEEE80211_MSG_STATE | IEEE80211_MSG_DEBUG, "%s: up parent %s\n", __func__, parent->if_xname); parent->if_flags |= IFF_UP; - taskqueue_enqueue(taskqueue_thread, &ic->ic_parent_task); + ieee80211_runtask(ic, &ic->ic_parent_task); return; } } @@ -1156,8 +1199,7 @@ ieee80211_start_locked(struct ieee80211vap *vap) * preempted if the station is locked to a particular * channel. */ - /* XXX needed? */ - ieee80211_new_state_locked(vap, IEEE80211_S_INIT, 0); + vap->iv_flags_ext |= IEEE80211_FEXT_REINIT; if (vap->iv_opmode == IEEE80211_M_MONITOR || vap->iv_opmode == IEEE80211_M_WDS) ieee80211_new_state_locked(vap, @@ -1240,7 +1282,7 @@ ieee80211_stop_locked(struct ieee80211vap *vap) IEEE80211_MSG_STATE | IEEE80211_MSG_DEBUG, "down parent %s\n", parent->if_xname); parent->if_flags &= ~IFF_UP; - taskqueue_enqueue(taskqueue_thread, &ic->ic_parent_task); + ieee80211_runtask(ic, &ic->ic_parent_task); } } } @@ -1319,10 +1361,20 @@ ieee80211_resume_all(struct ieee80211com *ic) void ieee80211_beacon_miss(struct ieee80211com *ic) { + IEEE80211_LOCK(ic); + if ((ic->ic_flags & IEEE80211_F_SCAN) == 0) { + /* Process in a taskq, the handler may reenter the driver */ + ieee80211_runtask(ic, &ic->ic_bmiss_task); + } + IEEE80211_UNLOCK(ic); +} + +static void +beacon_miss(void *arg, int npending) +{ + struct ieee80211com *ic = arg; struct ieee80211vap *vap; - if (ic->ic_flags & IEEE80211_F_SCAN) - return; /* XXX locking */ TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { /* @@ -1337,6 +1389,18 @@ ieee80211_beacon_miss(struct ieee80211com *ic) } } +static void +beacon_swmiss(void *arg, int npending) +{ + struct ieee80211vap *vap = arg; + + if (vap->iv_state != IEEE80211_S_RUN) + return; + + /* XXX Call multiple times if npending > zero? */ + vap->iv_bmiss(vap); +} + /* * Software beacon miss handling. Check if any beacons * were received in the last period. If not post a @@ -1366,7 +1430,7 @@ ieee80211_swbmiss(void *arg) vap->iv_swbmiss_count = 0; } else if (vap->iv_swbmiss_count == 0) { if (vap->iv_bmiss != NULL) - vap->iv_bmiss(vap); + ieee80211_runtask(ic, &vap->iv_swbmiss_task); if (vap->iv_bmiss_count == 0) /* don't re-arm timer */ return; } else @@ -1463,7 +1527,6 @@ ieee80211_cac_completeswitch(struct ieee80211vap *vap0) * and mark them as waiting for a scan to complete. These vaps * will be brought up when the scan completes and the scanning vap * reaches RUN state by wakeupwaiting. - * XXX if we do this in threads we can use sleep/wakeup. */ static void markwaiting(struct ieee80211vap *vap0) @@ -1473,10 +1536,16 @@ markwaiting(struct ieee80211vap *vap0) IEEE80211_LOCK_ASSERT(ic); + /* + * A vap list entry can not disappear since we are running on the + * taskqueue and a vap destroy will queue and drain another state + * change task. + */ TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { if (vap == vap0) continue; if (vap->iv_state != IEEE80211_S_INIT) { + /* NB: iv_newstate may drop the lock */ vap->iv_newstate(vap, IEEE80211_S_INIT, 0); vap->iv_flags_ext |= IEEE80211_FEXT_SCANWAIT; } @@ -1487,6 +1556,7 @@ markwaiting(struct ieee80211vap *vap0) * Wakeup all vap's waiting for a scan to complete. This is the * companion to markwaiting (above) and is used to coordinate * multiple vaps scanning. + * This is called from the state taskqueue. */ static void wakeupwaiting(struct ieee80211vap *vap0) @@ -1496,12 +1566,18 @@ wakeupwaiting(struct ieee80211vap *vap0) IEEE80211_LOCK_ASSERT(ic); + /* + * A vap list entry can not disappear since we are running on the + * taskqueue and a vap destroy will queue and drain another state + * change task. + */ TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { if (vap == vap0) continue; if (vap->iv_flags_ext & IEEE80211_FEXT_SCANWAIT) { vap->iv_flags_ext &= ~IEEE80211_FEXT_SCANWAIT; /* NB: sta's cannot go INIT->RUN */ + /* NB: iv_newstate may drop the lock */ vap->iv_newstate(vap, vap->iv_opmode == IEEE80211_M_STA ? IEEE80211_S_SCAN : IEEE80211_S_RUN, 0); @@ -1513,15 +1589,63 @@ wakeupwaiting(struct ieee80211vap *vap0) * Handle post state change work common to all operating modes. */ static void -ieee80211_newstate_cb(struct ieee80211vap *vap, - enum ieee80211_state nstate, int arg) +ieee80211_newstate_cb(void *xvap, int npending) { + struct ieee80211vap *vap = xvap; struct ieee80211com *ic = vap->iv_ic; + enum ieee80211_state nstate, ostate; + int arg, rc; - IEEE80211_LOCK_ASSERT(ic); + IEEE80211_LOCK(ic); + nstate = vap->iv_nstate; + arg = vap->iv_nstate_arg; + if (vap->iv_flags_ext & IEEE80211_FEXT_REINIT) { + /* + * We have been requested to drop back to the INIT before + * proceeding to the new state. + */ + IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, + "%s: %s -> %s arg %d\n", __func__, + ieee80211_state_name[vap->iv_state], + ieee80211_state_name[IEEE80211_S_INIT], arg); + vap->iv_newstate(vap, IEEE80211_S_INIT, arg); + vap->iv_flags_ext &= ~IEEE80211_FEXT_REINIT; + } + + ostate = vap->iv_state; + if (nstate == IEEE80211_S_SCAN && ostate != IEEE80211_S_INIT) { + /* + * SCAN was forced; e.g. on beacon miss. Force other running + * vap's to INIT state and mark them as waiting for the scan to + * complete. This insures they don't interfere with our + * scanning. Since we are single threaded the vaps can not + * transition again while we are executing. + * + * XXX not always right, assumes ap follows sta + */ + markwaiting(vap); + } IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, - "%s: %s arg %d\n", __func__, ieee80211_state_name[nstate], arg); + "%s: %s -> %s arg %d\n", __func__, + ieee80211_state_name[ostate], ieee80211_state_name[nstate], arg); + + rc = vap->iv_newstate(vap, nstate, arg); + vap->iv_flags_ext &= ~IEEE80211_FEXT_STATEWAIT; + if (rc != 0) { + /* State transition failed */ + KASSERT(rc != EINPROGRESS, ("iv_newstate was deferred")); + KASSERT(nstate != IEEE80211_S_INIT, + ("INIT state change failed")); + IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, + "%s: %s returned error %d\n", __func__, + ieee80211_state_name[nstate], rc); + goto done; + } + + /* No actual transition, skip post processing */ + if (ostate == nstate) + goto done; if (nstate == IEEE80211_S_RUN) { /* @@ -1549,7 +1673,8 @@ ieee80211_newstate_cb(struct ieee80211vap *vap, /* XXX NB: cast for altq */ ieee80211_flush_ifq((struct ifqueue *)&ic->ic_ifp->if_snd, vap); } - vap->iv_newstate_cb = NULL; +done: + IEEE80211_UNLOCK(ic); } /* @@ -1586,10 +1711,32 @@ ieee80211_new_state_locked(struct ieee80211vap *vap, struct ieee80211com *ic = vap->iv_ic; struct ieee80211vap *vp; enum ieee80211_state ostate; - int nrunning, nscanning, rc; + int nrunning, nscanning; IEEE80211_LOCK_ASSERT(ic); + if (vap->iv_flags_ext & IEEE80211_FEXT_STATEWAIT) { + if (vap->iv_nstate == IEEE80211_S_INIT) { + /* + * XXX The vap is being stopped, do no allow any other + * state changes until this is completed. + */ + return -1; + } +#if 0 + /* Warn if the previous state hasn't completed. */ + IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, + "%s: pending %s -> %s transition lost\n", __func__, + ieee80211_state_name[vap->iv_state], + ieee80211_state_name[vap->iv_nstate]); +#else + /* XXX temporarily enable to identify issues */ + if_printf(vap->iv_ifp, "%s: pending %s -> %s transition lost\n", + __func__, ieee80211_state_name[vap->iv_state], + ieee80211_state_name[vap->iv_nstate]); +#endif + } + nrunning = nscanning = 0; /* XXX can track this state instead of calculating */ TAILQ_FOREACH(vp, &ic->ic_vaps, iv_next) { @@ -1625,8 +1772,7 @@ ieee80211_new_state_locked(struct ieee80211vap *vap, __func__, ieee80211_state_name[ostate], ieee80211_state_name[nstate]); vap->iv_flags_ext |= IEEE80211_FEXT_SCANWAIT; - rc = 0; - goto done; + return 0; } if (nrunning) { /* @@ -1650,16 +1796,6 @@ ieee80211_new_state_locked(struct ieee80211vap *vap, } #endif } - } else { - /* - * SCAN was forced; e.g. on beacon miss. Force - * other running vap's to INIT state and mark - * them as waiting for the scan to complete. This - * insures they don't interfere with our scanning. - * - * XXX not always right, assumes ap follows sta - */ - markwaiting(vap); } break; case IEEE80211_S_RUN: @@ -1676,8 +1812,7 @@ ieee80211_new_state_locked(struct ieee80211vap *vap, ieee80211_state_name[ostate], ieee80211_state_name[nstate]); vap->iv_flags_ext |= IEEE80211_FEXT_SCANWAIT; - rc = 0; - goto done; + return 0; } if (vap->iv_opmode == IEEE80211_M_HOSTAP && IEEE80211_IS_CHAN_DFS(ic->ic_bsschan) && @@ -1706,20 +1841,12 @@ ieee80211_new_state_locked(struct ieee80211vap *vap, default: break; } - /* XXX on transition RUN->CAC do we need to set nstate = iv_state? */ - if (ostate != nstate) { - /* - * Arrange for work to happen after state change completes. - * If this happens asynchronously the caller must arrange - * for the com lock to be held. - */ - vap->iv_newstate_cb = ieee80211_newstate_cb; - } - rc = vap->iv_newstate(vap, nstate, arg); - if (rc == 0 && vap->iv_newstate_cb != NULL) - vap->iv_newstate_cb(vap, nstate, arg); -done: - return rc; + /* defer the state change to a thread */ + vap->iv_nstate = nstate; + vap->iv_nstate_arg = arg; + vap->iv_flags_ext |= IEEE80211_FEXT_STATEWAIT; + ieee80211_runtask(ic, &vap->iv_nstate_task); + return EINPROGRESS; } int diff --git a/sys/net80211/ieee80211_scan.c b/sys/net80211/ieee80211_scan.c index 7ce2d31..c1f4a13 100644 --- a/sys/net80211/ieee80211_scan.c +++ b/sys/net80211/ieee80211_scan.c @@ -33,7 +33,9 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> +#include <sys/proc.h> #include <sys/kernel.h> +#include <sys/condvar.h> #include <sys/socket.h> @@ -52,10 +54,12 @@ struct scan_state { #define ISCAN_MINDWELL 0x0001 /* min dwell time reached */ #define ISCAN_DISCARD 0x0002 /* discard rx'd frames */ #define ISCAN_CANCEL 0x0004 /* cancel current scan */ -#define ISCAN_START 0x0008 /* 1st time through next_scan */ +#define ISCAN_ABORT 0x0008 /* end the scan immediately */ unsigned long ss_chanmindwell; /* min dwell on curchan */ unsigned long ss_scanend; /* time scan must stop */ u_int ss_duration; /* duration for next scan */ + struct task ss_scan_task; /* scan execution */ + struct cv ss_scan_cv; /* scan signal */ struct callout ss_scan_timer; /* scan timer */ }; #define SCAN_PRIVATE(ss) ((struct scan_state *) ss) @@ -88,10 +92,10 @@ struct scan_state { #define ROAM_RATE_QUARTER_DEFAULT 2*3 /* quarter-width 11a/g bss */ #define ROAM_MCS_11N_DEFAULT (1 | IEEE80211_RATE_MCS) /* 11n bss */ -static void scan_restart_pwrsav(void *); static void scan_curchan(struct ieee80211_scan_state *, unsigned long); static void scan_mindwell(struct ieee80211_scan_state *); -static void scan_next(void *); +static void scan_signal(void *); +static void scan_task(void *, int); MALLOC_DEFINE(M_80211_SCAN, "80211scan", "802.11 scan state"); @@ -107,7 +111,10 @@ ieee80211_scan_attach(struct ieee80211com *ic) return; } callout_init_mtx(&ss->ss_scan_timer, IEEE80211_LOCK_OBJ(ic), 0); + cv_init(&ss->ss_scan_cv, "scan"); + TASK_INIT(&ss->ss_scan_task, 0, scan_task, ss); ic->ic_scan = &ss->base; + ss->base.ss_ic = ic; ic->ic_scan_curchan = scan_curchan; ic->ic_scan_mindwell = scan_mindwell; @@ -119,12 +126,17 @@ ieee80211_scan_detach(struct ieee80211com *ic) struct ieee80211_scan_state *ss = ic->ic_scan; if (ss != NULL) { - callout_drain(&SCAN_PRIVATE(ss)->ss_scan_timer); + IEEE80211_LOCK(ic); + SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_ABORT; + scan_signal(ss); + IEEE80211_UNLOCK(ic); + ieee80211_draintask(ic, &SCAN_PRIVATE(ss)->ss_scan_task); + KASSERT((ic->ic_flags & IEEE80211_F_SCAN) == 0, + ("scan still running")); if (ss->ss_ops != NULL) { ss->ss_ops->scan_detach(ss); ss->ss_ops = NULL; } - ic->ic_flags &= ~IEEE80211_F_SCAN; ic->ic_scan = NULL; free(SCAN_PRIVATE(ss), M_80211_SCAN); } @@ -174,9 +186,8 @@ ieee80211_scan_vdetach(struct ieee80211vap *vap) ss = ic->ic_scan; if (ss != NULL && ss->ss_vap == vap) { if (ic->ic_flags & IEEE80211_F_SCAN) { - /* XXX callout_drain */ - callout_stop(&SCAN_PRIVATE(ss)->ss_scan_timer); - ic->ic_flags &= ~IEEE80211_F_SCAN; + SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_ABORT; + scan_signal(ss); } if (ss->ss_ops != NULL) { ss->ss_ops->scan_detach(ss); @@ -293,15 +304,6 @@ scan_update_locked(struct ieee80211vap *vap, } } -static void -change_channel(struct ieee80211com *ic, - struct ieee80211_channel *chan) -{ - ic->ic_curchan = chan; - ic->ic_rt = ieee80211_get_ratetable(chan); - ic->ic_set_channel(ic); -} - static char channel_type(const struct ieee80211_channel *c) { @@ -325,7 +327,7 @@ channel_type(const struct ieee80211_channel *c) void ieee80211_scan_dump_channels(const struct ieee80211_scan_state *ss) { - struct ieee80211com *ic = ss->ss_vap->iv_ic; + struct ieee80211com *ic = ss->ss_ic; const char *sep; int i; @@ -352,76 +354,6 @@ scan_dump(struct ieee80211_scan_state *ss) } #endif /* IEEE80211_DEBUG */ -/* - * Enable station power save mode and start/restart the scanning thread. - */ -static void -scan_restart_pwrsav(void *arg) -{ - struct scan_state *ss = (struct scan_state *) arg; - struct ieee80211vap *vap = ss->base.ss_vap; - struct ieee80211com *ic = vap->iv_ic; - int ticksdelay; - - ieee80211_sta_pwrsave(vap, 1); - /* - * Use an initial 1ms delay so the null - * data frame has a chance to go out. - * XXX 1ms is a lot, better to trigger scan - * on tx complete. - */ - ticksdelay = msecs_to_ticks(1); - if (ticksdelay < 1) - ticksdelay = 1; - ic->ic_scan_start(ic); /* notify driver */ - ss->ss_scanend = ticks + ticksdelay + ss->ss_duration; - ss->ss_iflags |= ISCAN_START; - callout_reset(&ss->ss_scan_timer, ticksdelay, scan_next, ss); -} - -/* - * Start/restart scanning. If we're operating in station mode - * and associated notify the ap we're going into power save mode - * and schedule a callback to initiate the work (where there's a - * better context for doing the work). Otherwise, start the scan - * directly. - */ -static int -scan_restart(struct scan_state *ss, u_int duration) -{ - struct ieee80211vap *vap = ss->base.ss_vap; - struct ieee80211com *ic = vap->iv_ic; - int defer = 0; - - if (ss->base.ss_next == ss->base.ss_last) { - IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, - "%s: no channels to scan\n", __func__); - return 0; - } - if (vap->iv_opmode == IEEE80211_M_STA && - vap->iv_state == IEEE80211_S_RUN) { - if ((vap->iv_bss->ni_flags & IEEE80211_NODE_PWR_MGT) == 0) { - /* - * Initiate power save before going off-channel. - * Note that we cannot do this directly because - * of locking issues; instead we defer it to a - * tasklet. - */ - ss->ss_duration = duration; - defer = 1; - } - } - - if (!defer) { - ic->ic_scan_start(ic); /* notify driver */ - ss->ss_scanend = ticks + duration; - ss->ss_iflags |= ISCAN_START; - callout_reset(&ss->ss_scan_timer, 0, scan_next, ss); - } else - scan_restart_pwrsav(ss); - return 1; -} - static void copy_ssid(struct ieee80211vap *vap, struct ieee80211_scan_state *ss, int nssid, const struct ieee80211_scan_ssid ssids[]) @@ -485,16 +417,18 @@ start_scan_locked(const struct ieee80211_scanner *scan, /* NB: flush frames rx'd before 1st channel change */ SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_DISCARD; + SCAN_PRIVATE(ss)->ss_duration = duration; ss->ss_next = 0; ss->ss_mindwell = mindwell; ss->ss_maxdwell = maxdwell; + /* NB: scan_start must be before the scan runtask */ ss->ss_ops->scan_start(ss, vap); #ifdef IEEE80211_DEBUG if (ieee80211_msg_scan(vap)) scan_dump(ss); #endif /* IEEE80211_DEBUG */ - if (scan_restart(SCAN_PRIVATE(ss), duration)) - ic->ic_flags |= IEEE80211_F_SCAN; + ic->ic_flags |= IEEE80211_F_SCAN; + ieee80211_runtask(ic, &SCAN_PRIVATE(ss)->ss_scan_task); } } else { IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, @@ -716,11 +650,11 @@ ieee80211_bg_scan(struct ieee80211vap *vap, int flags) } /* NB: flush frames rx'd before 1st channel change */ SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_DISCARD; + SCAN_PRIVATE(ss)->ss_duration = duration; ss->ss_maxdwell = duration; - if (scan_restart(SCAN_PRIVATE(ss), duration)) { - ic->ic_flags |= IEEE80211_F_SCAN; - ic->ic_flags_ext |= IEEE80211_FEXT_BGSCAN; - } + ic->ic_flags |= IEEE80211_F_SCAN; + ic->ic_flags_ext |= IEEE80211_FEXT_BGSCAN; + ieee80211_runtask(ic, &SCAN_PRIVATE(ss)->ss_scan_task); } else { /* XXX msg+stat */ } @@ -756,9 +690,8 @@ ieee80211_cancel_scan(struct ieee80211vap *vap) /* clear bg scan NOPICK and mark cancel request */ ss->ss_flags &= ~IEEE80211_SCAN_NOPICK; SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_CANCEL; - /* force it to fire asap */ - callout_reset(&SCAN_PRIVATE(ss)->ss_scan_timer, - 0, scan_next, ss); + /* wake up the scan task */ + scan_signal(ss); } IEEE80211_UNLOCK(ic); } @@ -783,9 +716,8 @@ ieee80211_cancel_anyscan(struct ieee80211vap *vap) /* clear bg scan NOPICK and mark cancel request */ ss->ss_flags &= ~IEEE80211_SCAN_NOPICK; SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_CANCEL; - /* force it to fire asap */ - callout_reset(&SCAN_PRIVATE(ss)->ss_scan_timer, - 0, scan_next, ss); + /* wake up the scan task */ + scan_signal(ss); } IEEE80211_UNLOCK(ic); } @@ -800,7 +732,10 @@ ieee80211_scan_next(struct ieee80211vap *vap) struct ieee80211com *ic = vap->iv_ic; struct ieee80211_scan_state *ss = ic->ic_scan; - callout_reset(&SCAN_PRIVATE(ss)->ss_scan_timer, 0, scan_next, ss); + /* wake up the scan task */ + IEEE80211_LOCK(ic); + scan_signal(ss); + IEEE80211_UNLOCK(ic); } /* @@ -816,7 +751,7 @@ ieee80211_scan_done(struct ieee80211vap *vap) IEEE80211_LOCK(ic); ss = ic->ic_scan; ss->ss_next = ss->ss_last; /* all channels are complete */ - scan_next(ss); + scan_signal(ss); IEEE80211_UNLOCK(ic); } @@ -866,12 +801,22 @@ scan_curchan(struct ieee80211_scan_state *ss, unsigned long maxdwell) { struct ieee80211vap *vap = ss->ss_vap; - IEEE80211_LOCK_ASSERT(vap->iv_ic); - + IEEE80211_LOCK(vap->iv_ic); if (ss->ss_flags & IEEE80211_SCAN_ACTIVE) ieee80211_probe_curchan(vap, 0); callout_reset(&SCAN_PRIVATE(ss)->ss_scan_timer, - maxdwell, scan_next, ss); + maxdwell, scan_signal, ss); + IEEE80211_UNLOCK(vap->iv_ic); +} + +static void +scan_signal(void *arg) +{ + struct ieee80211_scan_state *ss = (struct ieee80211_scan_state *) arg; + + IEEE80211_LOCK_ASSERT(ss->ss_ic); + + cv_signal(&SCAN_PRIVATE(ss)->ss_scan_cv); } /* @@ -881,35 +826,67 @@ scan_curchan(struct ieee80211_scan_state *ss, unsigned long maxdwell) static void scan_mindwell(struct ieee80211_scan_state *ss) { - callout_reset(&SCAN_PRIVATE(ss)->ss_scan_timer, 0, scan_next, ss); + struct ieee80211com *ic = ss->ss_ic; + + IEEE80211_LOCK(ic); + scan_signal(ss); + IEEE80211_UNLOCK(ic); } -/* - * Switch to the next channel marked for scanning. - */ static void -scan_next(void *arg) +scan_task(void *arg, int pending) { -#define ISCAN_REP (ISCAN_MINDWELL | ISCAN_START | ISCAN_DISCARD) +#define ISCAN_REP (ISCAN_MINDWELL | ISCAN_DISCARD) struct ieee80211_scan_state *ss = (struct ieee80211_scan_state *) arg; struct ieee80211vap *vap = ss->ss_vap; - struct ieee80211com *ic = vap->iv_ic; + struct ieee80211com *ic = ss->ss_ic; struct ieee80211_channel *chan; unsigned long maxdwell, scanend; - int scandone; + int scandone = 0; - IEEE80211_LOCK_ASSERT(ic); + IEEE80211_LOCK(ic); + if (vap == NULL || (ic->ic_flags & IEEE80211_F_SCAN) == 0 || + (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_ABORT)) { + /* Cancelled before we started */ + goto done; + } + + if (ss->ss_next == ss->ss_last) { + IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, + "%s: no channels to scan\n", __func__); + goto done; + } + + if (vap->iv_opmode == IEEE80211_M_STA && + vap->iv_state == IEEE80211_S_RUN) { + if ((vap->iv_bss->ni_flags & IEEE80211_NODE_PWR_MGT) == 0) { + /* Enable station power save mode */ + ieee80211_sta_pwrsave(vap, 1); + /* + * Use an 1ms delay so the null data frame has a chance + * to go out. + * XXX Should use M_TXCB mechanism to eliminate this. + */ + cv_timedwait(&SCAN_PRIVATE(ss)->ss_scan_cv, + IEEE80211_LOCK_OBJ(ic), hz / 1000); + if (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_ABORT) + goto done; + } + } + + scanend = ticks + SCAN_PRIVATE(ss)->ss_duration; + IEEE80211_UNLOCK(ic); + ic->ic_scan_start(ic); /* notify driver */ + IEEE80211_LOCK(ic); + + for (;;) { + scandone = (ss->ss_next >= ss->ss_last) || + (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL) != 0; + if (scandone || (ss->ss_flags & IEEE80211_SCAN_GOTPICK) || + (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_ABORT) || + time_after(ticks + ss->ss_mindwell, scanend)) + break; - if ((ic->ic_flags & IEEE80211_F_SCAN) == 0) - return; -again: - scandone = (ss->ss_next >= ss->ss_last) || - (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL) != 0; - scanend = SCAN_PRIVATE(ss)->ss_scanend; - if (!scandone && - (ss->ss_flags & IEEE80211_SCAN_GOTPICK) == 0 && - ((SCAN_PRIVATE(ss)->ss_iflags & ISCAN_START) || - time_before(ticks + ss->ss_mindwell, scanend))) { chan = ss->ss_chans[ss->ss_next++]; /* @@ -934,7 +911,15 @@ again: /* * Potentially change channel and phy mode. */ - change_channel(ic, chan); + ic->ic_curchan = chan; + ic->ic_rt = ieee80211_get_ratetable(chan); + IEEE80211_UNLOCK(ic); + /* + * Perform the channel change and scan unlocked so the driver + * may sleep. Once set_channel returns the hardware has + * completed the channel change. + */ + ic->ic_set_channel(ic); /* * Scan curchan. Drivers for "intelligent hardware" @@ -942,93 +927,115 @@ again: * the work. Otherwise we manage the work outselves; * sending a probe request (as needed), and arming the * timeout to switch channels after maxdwell ticks. + * + * scan_curchan should only pause for the time required to + * prepare/initiate the hardware for the scan (if at all), the + * below condvar is used to sleep for the channels dwell time + * and allows it to be signalled for abort. */ ic->ic_scan_curchan(ss, maxdwell); + IEEE80211_LOCK(ic); SCAN_PRIVATE(ss)->ss_chanmindwell = ticks + ss->ss_mindwell; /* clear mindwell lock and initial channel change flush */ SCAN_PRIVATE(ss)->ss_iflags &= ~ISCAN_REP; - } else { - ic->ic_scan_end(ic); /* notify driver */ - /* - * Record scan complete time. Note that we also do - * this when canceled so any background scan will - * not be restarted for a while. - */ - if (scandone) - ic->ic_lastscan = ticks; - /* return to the bss channel */ - if (ic->ic_bsschan != IEEE80211_CHAN_ANYC && - ic->ic_curchan != ic->ic_bsschan) - ieee80211_setcurchan(ic, ic->ic_bsschan); - /* clear internal flags and any indication of a pick */ - SCAN_PRIVATE(ss)->ss_iflags &= ~ISCAN_REP; - ss->ss_flags &= ~IEEE80211_SCAN_GOTPICK; - /* - * If not canceled and scan completed, do post-processing. - * If the callback function returns 0, then it wants to - * continue/restart scanning. Unfortunately we needed to - * notify the driver to end the scan above to avoid having - * rx frames alter the scan candidate list. - */ - if ((SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL) == 0 && - !ss->ss_ops->scan_end(ss, vap) && - (ss->ss_flags & IEEE80211_SCAN_ONCE) == 0 && - time_before(ticks + ss->ss_mindwell, scanend)) { - IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, - "%s: done, restart " - "[ticks %u, dwell min %lu scanend %lu]\n", - __func__, - ticks, ss->ss_mindwell, scanend); - ss->ss_next = 0; /* reset to begining */ - if (ss->ss_flags & IEEE80211_SCAN_ACTIVE) - vap->iv_stats.is_scan_active++; - else - vap->iv_stats.is_scan_passive++; + if ((SCAN_PRIVATE(ss)->ss_iflags & (ISCAN_CANCEL|ISCAN_ABORT))) + continue; - ss->ss_ops->scan_restart(ss, vap); /* XXX? */ - ic->ic_scan_start(ic); /* notify driver */ - goto again; - } else { - /* past here, scandone is ``true'' if not in bg mode */ - if ((ss->ss_flags & IEEE80211_SCAN_BGSCAN) == 0) - scandone = 1; + /* Wait to be signalled to scan the next channel */ + cv_wait(&SCAN_PRIVATE(ss)->ss_scan_cv, IEEE80211_LOCK_OBJ(ic)); + } + if (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_ABORT) + goto done; - IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, - "%s: %s, " - "[ticks %u, dwell min %lu scanend %lu]\n", - __func__, scandone ? "done" : "stopped", - ticks, ss->ss_mindwell, scanend); + IEEE80211_UNLOCK(ic); + ic->ic_scan_end(ic); /* notify driver */ + IEEE80211_LOCK(ic); - /* - * Clear the SCAN bit first in case frames are - * pending on the station power save queue. If - * we defer this then the dispatch of the frames - * may generate a request to cancel scanning. - */ - ic->ic_flags &= ~IEEE80211_F_SCAN; - /* - * Drop out of power save mode when a scan has - * completed. If this scan was prematurely terminated - * because it is a background scan then don't notify - * the ap; we'll either return to scanning after we - * receive the beacon frame or we'll drop out of power - * save mode because the beacon indicates we have frames - * waiting for us. - */ - if (scandone) { - ieee80211_sta_pwrsave(vap, 0); - if (ss->ss_next >= ss->ss_last) { - ieee80211_notify_scan_done(vap); - ic->ic_flags_ext &= ~IEEE80211_FEXT_BGSCAN; - } - } - SCAN_PRIVATE(ss)->ss_iflags &= ~ISCAN_CANCEL; - ss->ss_flags &= - ~(IEEE80211_SCAN_ONCE | IEEE80211_SCAN_PICK1ST); + /* + * Record scan complete time. Note that we also do + * this when canceled so any background scan will + * not be restarted for a while. + */ + if (scandone) + ic->ic_lastscan = ticks; + /* return to the bss channel */ + if (ic->ic_bsschan != IEEE80211_CHAN_ANYC && + ic->ic_curchan != ic->ic_bsschan) { + ieee80211_setupcurchan(ic, ic->ic_bsschan); + IEEE80211_UNLOCK(ic); + ic->ic_set_channel(ic); + IEEE80211_LOCK(ic); + } + /* clear internal flags and any indication of a pick */ + SCAN_PRIVATE(ss)->ss_iflags &= ~ISCAN_REP; + ss->ss_flags &= ~IEEE80211_SCAN_GOTPICK; + + /* + * If not canceled and scan completed, do post-processing. + * If the callback function returns 0, then it wants to + * continue/restart scanning. Unfortunately we needed to + * notify the driver to end the scan above to avoid having + * rx frames alter the scan candidate list. + */ + if ((SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL) == 0 && + !ss->ss_ops->scan_end(ss, vap) && + (ss->ss_flags & IEEE80211_SCAN_ONCE) == 0 && + time_before(ticks + ss->ss_mindwell, scanend)) { + IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, + "%s: done, restart " + "[ticks %u, dwell min %lu scanend %lu]\n", + __func__, + ticks, ss->ss_mindwell, scanend); + ss->ss_next = 0; /* reset to begining */ + if (ss->ss_flags & IEEE80211_SCAN_ACTIVE) + vap->iv_stats.is_scan_active++; + else + vap->iv_stats.is_scan_passive++; + + ss->ss_ops->scan_restart(ss, vap); /* XXX? */ + ieee80211_runtask(ic, &SCAN_PRIVATE(ss)->ss_scan_task); + IEEE80211_UNLOCK(ic); + return; + } + + /* past here, scandone is ``true'' if not in bg mode */ + if ((ss->ss_flags & IEEE80211_SCAN_BGSCAN) == 0) + scandone = 1; + + IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, + "%s: %s, [ticks %u, dwell min %lu scanend %lu]\n", + __func__, scandone ? "done" : "stopped", + ticks, ss->ss_mindwell, scanend); + + /* + * Clear the SCAN bit first in case frames are + * pending on the station power save queue. If + * we defer this then the dispatch of the frames + * may generate a request to cancel scanning. + */ +done: + ic->ic_flags &= ~IEEE80211_F_SCAN; + /* + * Drop out of power save mode when a scan has + * completed. If this scan was prematurely terminated + * because it is a background scan then don't notify + * the ap; we'll either return to scanning after we + * receive the beacon frame or we'll drop out of power + * save mode because the beacon indicates we have frames + * waiting for us. + */ + if (scandone) { + ieee80211_sta_pwrsave(vap, 0); + if (ss->ss_next >= ss->ss_last) { + ieee80211_notify_scan_done(vap); + ic->ic_flags_ext &= ~IEEE80211_FEXT_BGSCAN; } } + SCAN_PRIVATE(ss)->ss_iflags &= ~(ISCAN_CANCEL|ISCAN_ABORT); + ss->ss_flags &= ~(IEEE80211_SCAN_ONCE | IEEE80211_SCAN_PICK1ST); + IEEE80211_UNLOCK(ic); #undef ISCAN_REP } diff --git a/sys/net80211/ieee80211_scan.h b/sys/net80211/ieee80211_scan.h index 78e5fe4..edba660 100644 --- a/sys/net80211/ieee80211_scan.h +++ b/sys/net80211/ieee80211_scan.h @@ -90,6 +90,7 @@ struct ieee80211_scan_ssid { */ struct ieee80211_scan_state { struct ieee80211vap *ss_vap; + struct ieee80211com *ss_ic; const struct ieee80211_scanner *ss_ops; /* policy hookup, see below */ void *ss_priv; /* scanner private state */ uint16_t ss_flags; diff --git a/sys/net80211/ieee80211_scan_sta.c b/sys/net80211/ieee80211_scan_sta.c index 607c36d..cef3db4 100644 --- a/sys/net80211/ieee80211_scan_sta.c +++ b/sys/net80211/ieee80211_scan_sta.c @@ -32,10 +32,10 @@ __FBSDID("$FreeBSD$"); #include "opt_wlan.h" #include <sys/param.h> -#include <sys/systm.h> +#include <sys/systm.h> #include <sys/kernel.h> #include <sys/module.h> - + #include <sys/socket.h> #include <net/if.h> @@ -1640,7 +1640,7 @@ ap_force_promisc(struct ieee80211com *ic) IEEE80211_LOCK(ic); /* set interface into promiscuous mode */ ifp->if_flags |= IFF_PROMISC; - ic->ic_update_promisc(ifp); + ieee80211_runtask(ic, &ic->ic_promisc_task); IEEE80211_UNLOCK(ic); } diff --git a/sys/net80211/ieee80211_var.h b/sys/net80211/ieee80211_var.h index 55204f8..6c4ee74 100644 --- a/sys/net80211/ieee80211_var.h +++ b/sys/net80211/ieee80211_var.h @@ -126,7 +126,12 @@ struct ieee80211com { enum ieee80211_opmode ic_opmode; /* operation mode */ struct ifmedia ic_media; /* interface media config */ struct callout ic_inact; /* inactivity processing */ + struct taskqueue *ic_tq; /* deferred state thread */ struct task ic_parent_task; /* deferred parent processing */ + struct task ic_promisc_task;/* deferred promisc update */ + struct task ic_mcast_task; /* deferred mcast update */ + struct task ic_chan_task; /* deferred channel change */ + struct task ic_bmiss_task; /* deferred beacon miss hndlr */ uint32_t ic_flags; /* state flags */ uint32_t ic_flags_ext; /* extended state flags */ @@ -325,8 +330,10 @@ struct ieee80211vap { uint32_t iv_htcaps; /* HT capabilities */ enum ieee80211_opmode iv_opmode; /* operation mode */ enum ieee80211_state iv_state; /* state machine state */ - void (*iv_newstate_cb)(struct ieee80211vap *, - enum ieee80211_state, int); + enum ieee80211_state iv_nstate; /* pending state */ + int iv_nstate_arg; /* pending state arg */ + struct task iv_nstate_task; /* deferred state processing */ + struct task iv_swbmiss_task;/* deferred iv_bmiss call */ struct callout iv_mgtsend; /* mgmt frame response timer */ /* inactivity timer settings */ int iv_inact_init; /* setting for new station */ @@ -519,6 +526,8 @@ MALLOC_DECLARE(M_80211_VAP); #define IEEE80211_FEXT_SWBMISS 0x00000400 /* CONF: do bmiss in s/w */ #define IEEE80211_FEXT_DFS 0x00000800 /* CONF: DFS enabled */ #define IEEE80211_FEXT_DOTD 0x00001000 /* CONF: 11d enabled */ +#define IEEE80211_FEXT_STATEWAIT 0x00002000 /* STATUS: awaiting state chg */ +#define IEEE80211_FEXT_REINIT 0x00004000 /* STATUS: INIT state first */ /* NB: immutable: should be set only when creating a vap */ #define IEEE80211_FEXT_WDSLEGACY 0x00010000 /* CONF: legacy WDS operation */ #define IEEE80211_FEXT_PROBECHAN 0x00020000 /* CONF: probe passive channel*/ @@ -536,9 +545,10 @@ MALLOC_DECLARE(M_80211_VAP); #define IEEE80211_FEXT_BITS \ "\20\1NONHT_PR\2INACT\3SCANWAIT\4BGSCAN\5WPS\6TSN\7SCANREQ\10RESUME" \ - "\0114ADDR\12NONEPR_PR\13SWBMISS\14DFS\15DOTD\22WDSLEGACY\23PROBECHAN" \ - "\24HT\25AMDPU_TX\26AMPDU_TX\27AMSDU_TX\30AMSDU_RX\31USEHT40\32PUREN" \ - "\33SHORTGI20\34SHORTGI40\35HTCOMPAT\36RIFS" + "\0114ADDR\12NONEPR_PR\13SWBMISS\14DFS\15DOTD\16STATEWAIT\17REINIT" \ + "\22WDSLEGACY\23PROBECHAN\24HT\25AMDPU_TX\26AMPDU_TX\27AMSDU_TX" \ + "\30AMSDU_RX\31USEHT40\32PUREN\33SHORTGI20\34SHORTGI40\35HTCOMPAT" \ + "\36RIFS" #define IEEE80211_FVEN_BITS "\20" @@ -633,6 +643,24 @@ struct ieee80211_channel *ieee80211_find_channel_byieee(struct ieee80211com *, int ieee80211_setmode(struct ieee80211com *, enum ieee80211_phymode); enum ieee80211_phymode ieee80211_chan2mode(const struct ieee80211_channel *); +/* + * Enqueue a task on the state thread. + */ +static __inline void +ieee80211_runtask(struct ieee80211com *ic, struct task *task) +{ + taskqueue_enqueue(ic->ic_tq, task); +} + +/* + * Wait for a queued task to complete. + */ +static __inline void +ieee80211_draintask(struct ieee80211com *ic, struct task *task) +{ + taskqueue_drain(ic->ic_tq, task); +} + /* * Key update synchronization methods. XXX should not be visible. */ |