From owner-p4-projects@FreeBSD.ORG Sat Apr 5 23:35:55 2008 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 6BB6E1065675; Sat, 5 Apr 2008 23:35:55 +0000 (UTC) Delivered-To: perforce@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 2CE4F106566B for ; Sat, 5 Apr 2008 23:35:55 +0000 (UTC) (envelope-from sam@freebsd.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id 1031A8FC0C for ; Sat, 5 Apr 2008 23:35:55 +0000 (UTC) (envelope-from sam@freebsd.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.1/8.14.1) with ESMTP id m35NZtX9074916 for ; Sat, 5 Apr 2008 23:35:55 GMT (envelope-from sam@freebsd.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.1/8.14.1/Submit) id m35NZseK074914 for perforce@freebsd.org; Sat, 5 Apr 2008 23:35:54 GMT (envelope-from sam@freebsd.org) Date: Sat, 5 Apr 2008 23:35:54 GMT Message-Id: <200804052335.m35NZseK074914@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to sam@freebsd.org using -f From: Sam Leffler To: Perforce Change Reviews Cc: Subject: PERFORCE change 139438 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 05 Apr 2008 23:35:55 -0000 http://perforce.freebsd.org/chv.cgi?CH=139438 Change 139438 by sam@sam_ebb on 2008/04/05 23:35:37 Checkpoint major overhaul now that we're back to sta operation (open and w/ wpa): o move if_alloc up to simplify work o cleanup iwi_detach; still need to eliminate it's use in iwi_attach o move firmware get into vap create so we don't need to drop the softc lock in iwi_init o add task bounces for iwi_notification_intr calls back into net80211 to eliminate LOR's o rewrite iwi_newstate to use split state machine handling mechanism and inline expand routines that just toss requests to the task queue to make logic more explicit o eliminate bogus call to ieee80211_node_authorize; this was wrong for WPA and should never be done by the driver o tighten up some code (Andrew, you really like blank lines, eh? :)) o move check of IFF_DRV_RUNNING on firmware error to the task queue to avoid inconsistent state o make iwi_raw_xmit just discard frames; there's no way to send raw 802.11 frames with this device and trying to cause the firmware to barf o eliminate "wait until pending iwi_cmds are completed" logic in iwi_ioctl; we are now called from the 802.11 layer and there should never be cmds pending if we have done the right work wrt the cmd queues, firmware state, and taskqueue o block/unblock task queues instead of trying to drain them; this fixes various races in the handling of reset I believe o display symbolic names for fw states in debug msgs o never never touch IFF_UP o expand iwi_queue_cmd to pass an opaque argument through so the state machine changes can be directly mimic the 802.11 layer requests o add IWI_AUTH so we can explicitly track the state machine Affected files ... .. //depot/projects/vap/sys/dev/iwi/if_iwi.c#17 edit .. //depot/projects/vap/sys/dev/iwi/if_iwivar.h#11 edit Differences ... ==== //depot/projects/vap/sys/dev/iwi/if_iwi.c#17 (text+ko) ==== @@ -91,6 +91,14 @@ #define DPRINTFN(n, x) do { if (iwi_debug >= (n)) printf x; } while (0) int iwi_debug = 0; SYSCTL_INT(_debug, OID_AUTO, iwi, CTLFLAG_RW, &iwi_debug, 0, "iwi debug level"); + +static const char *iwi_fw_states[] = { + "IDLE", /* IWI_FW_IDLE */ + "LOADING", /* IWI_FW_LOADING */ + "ASSOCIATING", /* IWI_FW_ASSOCIATING */ + "DISASSOCIATING", /* IWI_FW_DISASSOCIATING */ + "SCANNING", /* IWI_FW_SCANNING */ +}; #else #define DPRINTF(x) #define DPRINTFN(n, x) @@ -144,11 +152,15 @@ static void iwi_media_status(struct ifnet *, struct ifmediareq *); static int iwi_newstate(struct ieee80211vap *, enum ieee80211_state, int); static void iwi_wme_init(struct iwi_softc *); -static int iwi_wme_setparams(struct iwi_softc *); +static int iwi_wme_setparams(struct iwi_softc *, struct ieee80211com *); static int iwi_wme_update(struct ieee80211com *); static uint16_t iwi_read_prom_word(struct iwi_softc *, uint8_t); static void iwi_frame_intr(struct iwi_softc *, struct iwi_rx_data *, int, struct iwi_frame *); +static void iwi_bmiss(void *, int); +static void iwi_authsuccess(void *, int); +static void iwi_assocsuccess(void *, int); +static void iwi_assocfailed(void *, int); static void iwi_notification_intr(struct iwi_softc *, struct iwi_notif *); static void iwi_rx_intr(struct iwi_softc *); static void iwi_tx_intr(struct iwi_softc *, struct iwi_tx_ring *); @@ -159,6 +171,7 @@ struct ieee80211_node *, int); static int iwi_raw_xmit(struct ieee80211_node *, struct mbuf *, const struct ieee80211_bpf_params *); +static void iwi_start_locked(struct ifnet *); static void iwi_start(struct ifnet *); static void iwi_watchdog(void *); static int iwi_ioctl(struct ifnet *, u_long, caddr_t); @@ -167,8 +180,8 @@ static int iwi_load_ucode(struct iwi_softc *, const struct iwi_fw *); static int iwi_load_firmware(struct iwi_softc *, const struct iwi_fw *); static void iwi_release_fw_dma(struct iwi_softc *sc); -static int iwi_config(struct iwi_softc *); -static int iwi_get_firmware(struct iwi_softc *); +static int iwi_config(struct iwi_softc *, struct ieee80211vap *); +static int iwi_get_firmware(struct iwi_softc *, enum ieee80211_opmode); static void iwi_put_firmware(struct iwi_softc *); static int iwi_scanchan(struct iwi_softc *, unsigned long, int); static void iwi_scan_start(struct ieee80211com *); @@ -180,15 +193,14 @@ static void iwi_scan_allchan(struct ieee80211com *, unsigned long maxdwell); #endif static void iwi_scan_mindwell(struct ieee80211_scan_state *); -static void iwi_assoc(struct ieee80211vap *); -static void iwi_disassoc(struct ieee80211vap *); static void iwi_ops(void *, int); -static int iwi_queue_cmd(struct iwi_softc *, int); +static int iwi_queue_cmd(struct iwi_softc *, int, int); static int iwi_auth_and_assoc(struct iwi_softc *, struct ieee80211vap *); static int iwi_disassociate(struct iwi_softc *, int quiet); static void iwi_init(void *); -static void iwi_init_locked(void *, int); -static void iwi_stop(void *); +static int iwi_init_fw_dma(struct iwi_softc *, int); +static void iwi_stop_locked(void *); +static void iwi_stop(struct iwi_softc *); static void iwi_restart(void *, int); static int iwi_getrfkill(struct iwi_softc *); static void iwi_radio_on(void *, int); @@ -270,6 +282,13 @@ sc->sc_dev = dev; + ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); + if (ifp == NULL) { + device_printf(dev, "can not if_alloc()\n"); + return ENXIO; + } + ic = ifp->if_l2com; + IWI_LOCK_INIT(sc); IWI_CMD_LOCK_INIT(sc); @@ -352,12 +371,7 @@ iwi_wme_init(sc); - ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); - if (ifp == NULL) { - device_printf(dev, "can not if_alloc()\n"); - goto fail; - } - ic = ifp->if_l2com; + TASK_INIT(&sc->sc_bmiss_task, 0, iwi_bmiss, ic); ifp->if_softc = sc; if_initname(ifp, device_get_name(dev), device_get_unit(dev)); @@ -446,8 +460,9 @@ ieee80211_announce(ic); return 0; - -fail: iwi_detach(dev); +fail: + /* XXX fix */ + iwi_detach(dev); return ENXIO; } @@ -457,17 +472,16 @@ struct iwi_softc *sc = device_get_softc(dev); struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; - IWI_LOCK_DECL; + + iwi_stop(sc); + + bpfdetach(ifp); + ieee80211_ifdetach(ic); - if (ifp != NULL) { - IWI_LOCK(sc); - iwi_stop(sc); - IWI_UNLOCK(sc); - bpfdetach(ifp); - ieee80211_ifdetach(ic); - } + /* NB: do early to drain any pending tasks */ + taskqueue_free(sc->sc_tq); + taskqueue_free(sc->sc_tq2); - callout_drain(&sc->sc_wdtimer); iwi_put_firmware(sc); iwi_release_fw_dma(sc); @@ -478,26 +492,18 @@ iwi_free_tx_ring(sc, &sc->txq[3]); iwi_free_rx_ring(sc, &sc->rxq); - if (sc->irq != NULL) { - bus_teardown_intr(dev, sc->irq, sc->sc_ih); - bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq); - } + bus_teardown_intr(dev, sc->irq, sc->sc_ih); + bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq); - if (sc->mem != NULL) - bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem); + bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem); - if (ifp != NULL) - if_free(ifp); - - taskqueue_free(sc->sc_tq); - taskqueue_free(sc->sc_tq2); - - if (sc->sc_unr != NULL) - delete_unrhdr(sc->sc_unr); + delete_unrhdr(sc->sc_unr); IWI_LOCK_DESTROY(sc); IWI_CMD_LOCK_DESTROY(sc); + if_free(ifp); + return 0; } @@ -507,11 +513,29 @@ const uint8_t bssid[IEEE80211_ADDR_LEN], const uint8_t mac[IEEE80211_ADDR_LEN]) { + struct ifnet *ifp = ic->ic_ifp; + struct iwi_softc *sc = ifp->if_softc; struct iwi_vap *ivp; struct ieee80211vap *vap; + int i; if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */ return NULL; + /* + * Get firmware image (and possibly dma memory) on mode change. + */ + if (iwi_get_firmware(sc, opmode)) + return NULL; + /* allocate DMA memory for mapping firmware image */ + i = sc->fw_fw.size; + if (sc->fw_boot.size > i) + i = sc->fw_boot.size; + /* XXX do we dma the ucode as well ? */ + if (sc->fw_uc.size > i) + i = sc->fw_uc.size; + if (iwi_init_fw_dma(sc, i)) + return NULL; + ivp = (struct iwi_vap *) malloc(sizeof(struct iwi_vap), M_80211_VAP, M_NOWAIT | M_ZERO); if (ivp == NULL) @@ -523,6 +547,10 @@ ivp->iwi_newstate = vap->iv_newstate; vap->iv_newstate = iwi_newstate; + TASK_INIT(&ivp->iwi_authsuccess_task, 0, iwi_authsuccess, vap); + TASK_INIT(&ivp->iwi_assocsuccess_task, 0, iwi_assocsuccess, vap); + TASK_INIT(&ivp->iwi_assocfailed_task, 0, iwi_assocfailed, vap); + /* complete setup */ ieee80211_vap_attach(vap, ieee80211_media_change, iwi_media_status); ic->ic_opmode = opmode; @@ -840,11 +868,8 @@ iwi_shutdown(device_t dev) { struct iwi_softc *sc = device_get_softc(dev); - IWI_LOCK_DECL; - IWI_LOCK(sc); iwi_stop(sc); - IWI_UNLOCK(sc); iwi_put_firmware(sc); /* ??? XXX */ return 0; @@ -854,11 +879,8 @@ iwi_suspend(device_t dev) { struct iwi_softc *sc = device_get_softc(dev); - IWI_LOCK_DECL; - IWI_LOCK(sc); iwi_stop(sc); - IWI_UNLOCK(sc); return 0; } @@ -962,19 +984,36 @@ struct ieee80211com *ic = vap->iv_ic; struct ifnet *ifp = ic->ic_ifp; struct iwi_softc *sc = ifp->if_softc; - int error = 0; + IWI_LOCK_DECL; DPRINTF(("%s: %s -> %s flags 0x%x\n", __func__, ieee80211_state_name[vap->iv_state], ieee80211_state_name[nstate], sc->flags)); - /* XXX state change race with taskqueue */ switch (nstate) { + case IEEE80211_S_INIT: + IWI_LOCK(sc); + /* + * NB: don't try to do this if iwi_stop_master has + * shutdown the firmware and disabled interrupts. + */ + if (vap->iv_state == IEEE80211_S_RUN && + (sc->flags & IWI_FLAG_FW_INITED)) + iwi_queue_cmd(sc, IWI_DISASSOC, 0); + IWI_UNLOCK(sc); + break; + case IEEE80211_S_SCAN: + iwi_queue_cmd(sc, IWI_CONFIG, 0); + return EINPROGRESS; case IEEE80211_S_AUTH: - iwi_assoc(vap); - break; + /* The firmware will fail if we are already associated */ + if (sc->flags & IWI_FLAG_ASSOCIATED) + iwi_queue_cmd(sc, IWI_DISASSOC, 0); + iwi_queue_cmd(sc, IWI_AUTH, arg); + return EINPROGRESS; case IEEE80211_S_RUN: - if (vap->iv_opmode == IEEE80211_M_IBSS) { + if (vap->iv_opmode == IEEE80211_M_IBSS && + vap->iv_state == IEEE80211_S_SCAN) { /* * XXX when joining an ibss network we are called * with a SCAN -> RUN transition on scan complete. @@ -983,35 +1022,27 @@ * AUTH -> RUN transition and we want to do nothing. * This is all totally bogus and needs to be redone. */ - if (vap->iv_state == IEEE80211_S_SCAN) - iwi_assoc(vap); - } + iwi_queue_cmd(sc, IWI_ASSOC, 0); + return EINPROGRESS; + } break; - case IEEE80211_S_INIT: - /* - * NB: don't try to do this if iwi_stop_master has - * shutdown the firmware and disabled interrupts. - */ - if (vap->iv_state == IEEE80211_S_RUN && - (sc->flags & IWI_FLAG_FW_INITED)) - iwi_disassoc(vap); - if (vap->iv_state == IEEE80211_S_SCAN && - (sc->fw_state == IWI_FW_SCANNING)) - ieee80211_cancel_scan(vap); - break; case IEEE80211_S_ASSOC: /* - * If we are not transitioning from AUTH the resend the - * association request. + * If we are transitioning from AUTH then just wait + * for the ASSOC status to come back from the firmware. + * Otherwise we need to issue the association request. */ - if (vap->iv_state != IEEE80211_S_AUTH) - iwi_assoc(vap); - break; + if (vap->iv_state == IEEE80211_S_AUTH) + break; + /* The firmware will fail if we are already associated */ + if (sc->flags & IWI_FLAG_ASSOCIATED) + iwi_queue_cmd(sc, IWI_DISASSOC, 0); + iwi_queue_cmd(sc, IWI_ASSOC, arg); + return EINPROGRESS; default: break; } - return (error != 0) ? error : ivp->iwi_newstate(vap, nstate, arg); - + return ivp->iwi_newstate(vap, nstate, arg); } /* @@ -1062,10 +1093,8 @@ } static int -iwi_wme_setparams(struct iwi_softc *sc) +iwi_wme_setparams(struct iwi_softc *sc, struct ieee80211com *ic) { - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; const struct wmeParams *wmep; int ac; @@ -1098,7 +1127,7 @@ * will get sent down to the adapter as part of the * work iwi_auth_and_assoc does. */ - return (iwi_queue_cmd(sc, IWI_SET_WME)); + return iwi_queue_cmd(sc, IWI_SET_WME, 0); } static int @@ -1367,7 +1396,42 @@ #undef SUBTYPE } +/* + * Task queue callbacks for iwi_notification_intr used to avoid LOR's. + */ +static void +iwi_bmiss(void *arg, int npending) +{ + struct ieee80211com *ic = arg; + + ieee80211_beacon_miss(ic); +} + +static void +iwi_authsuccess(void *arg, int npending) +{ + struct ieee80211vap *vap = arg; + + ieee80211_new_state(vap, IEEE80211_S_ASSOC, -1); +} + static void +iwi_assocsuccess(void *arg, int npending) +{ + struct ieee80211vap *vap = arg; + + ieee80211_new_state(vap, IEEE80211_S_RUN, -1); +} + +static void +iwi_assocfailed(void *arg, int npending) +{ + struct ieee80211vap *vap = arg; + + ieee80211_new_state(vap, IEEE80211_S_SCAN, -1); +} + +static void iwi_notification_intr(struct iwi_softc *sc, struct iwi_notif *notif) { struct ifnet *ifp = sc->sc_ifp; @@ -1398,54 +1462,49 @@ IWI_STATE_END(sc, IWI_FW_SCANNING); - if (scan->status == IWI_SCAN_COMPLETED) + if (scan->status == IWI_SCAN_COMPLETED) { + /* NB: don't need to defer, net80211 does it for us */ ieee80211_scan_next(vap); - + } break; case IWI_NOTIF_TYPE_AUTHENTICATION: auth = (struct iwi_notif_authentication *)(notif + 1); - switch (auth->state) { case IWI_AUTH_SUCCESS: DPRINTFN(2, ("Authentication succeeeded\n")); - ieee80211_node_authorize(vap->iv_bss); - ieee80211_new_state(vap, IEEE80211_S_ASSOC, -1); + taskqueue_enqueue(taskqueue_swi, + &IWI_VAP(vap)->iwi_authsuccess_task); break; - case IWI_AUTH_FAIL: DPRINTFN(2, ("Authentication failed\n")); sc->flags &= ~IWI_FLAG_ASSOCIATED; IWI_STATE_END(sc, IWI_FW_ASSOCIATING); /* XXX */ break; - case IWI_AUTH_SENT_1: case IWI_AUTH_RECV_2: case IWI_AUTH_SEQ1_PASS: break; - case IWI_AUTH_SEQ1_FAIL: DPRINTFN(2, ("Initial authentication handshake failed; " "you probably need shared key\n")); IWI_STATE_END(sc, IWI_FW_ASSOCIATING); /* XXX retry shared key when in auto */ break; - default: device_printf(sc->sc_dev, "unknown authentication state %u\n", auth->state); + break; } break; case IWI_NOTIF_TYPE_ASSOCIATION: assoc = (struct iwi_notif_association *)(notif + 1); - switch (assoc->state) { case IWI_AUTH_SUCCESS: /* re-association, do nothing */ break; - case IWI_ASSOC_SUCCESS: DPRINTFN(2, ("Association succeeded\n")); sc->flags |= IWI_FLAG_ASSOCIATED; @@ -1453,30 +1512,30 @@ iwi_checkforqos(vap, (const struct ieee80211_frame *)(assoc+1), le16toh(notif->len) - sizeof(*assoc)); - ieee80211_new_state(vap, IEEE80211_S_RUN, -1); + taskqueue_enqueue(taskqueue_swi, + &IWI_VAP(vap)->iwi_assocsuccess_task); break; - case IWI_ASSOC_INIT: switch (sc->fw_state) { - case IWI_FW_ASSOCIATING: - DPRINTFN(2, ("Association failed\n")); - IWI_STATE_END(sc, IWI_FW_ASSOCIATING); - ieee80211_new_state(vap, - IEEE80211_S_SCAN, -1); - break; + case IWI_FW_ASSOCIATING: + DPRINTFN(2, ("Association failed\n")); + IWI_STATE_END(sc, IWI_FW_ASSOCIATING); + taskqueue_enqueue(taskqueue_swi, + &IWI_VAP(vap)->iwi_assocfailed_task); + break; - case IWI_FW_DISASSOCIATING: - DPRINTFN(2, ("Dissassociated\n")); - IWI_STATE_END(sc, - IWI_FW_DISASSOCIATING); - break; + case IWI_FW_DISASSOCIATING: + DPRINTFN(2, ("Dissassociated\n")); + IWI_STATE_END(sc, + IWI_FW_DISASSOCIATING); + break; } sc->flags &= ~IWI_FLAG_ASSOCIATED; break; - default: device_printf(sc->sc_dev, "unknown association state %u\n", assoc->state); + break; } break; @@ -1499,7 +1558,8 @@ DPRINTF(("Beacon miss: %u >= %u\n", le32toh(beacon->number), vap->iv_bmissthreshold)); - ieee80211_beacon_miss(ic); + taskqueue_enqueue(taskqueue_swi, + &sc->sc_bmiss_task); } } break; @@ -1513,6 +1573,7 @@ default: DPRINTF(("unknown notification type %u flags 0x%x len %u\n", notif->type, notif->flags, le16toh(notif->len))); + break; } } @@ -1595,7 +1656,7 @@ if (sc->sc_softled) iwi_led_event(sc, IWI_LED_TX); - iwi_start(ifp); + iwi_start_locked(ifp); } static void @@ -1617,9 +1678,7 @@ if (r & IWI_INTR_FATAL_ERROR) { device_printf(sc->sc_dev, "firmware error\n"); - /* don't restart if the interface isn't up */ - if (sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING) - taskqueue_enqueue(sc->sc_tq2, &sc->sc_restarttask); + taskqueue_enqueue(sc->sc_tq2, &sc->sc_restarttask); sc->flags &= ~IWI_FLAG_BUSY; sc->sc_busy_timer = 0; @@ -1884,60 +1943,24 @@ iwi_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, const struct ieee80211_bpf_params *params) { - struct ieee80211com *ic = ni->ni_ic; - struct ifnet *ifp = ic->ic_ifp; - struct iwi_softc *sc = ifp->if_softc; - int ac; - IWI_LOCK_DECL; - - IWI_LOCK(sc); - - /* prevent management frames from being sent if we're not ready */ - if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { - IWI_UNLOCK(sc); - m_freem(m); - ieee80211_free_node(ni); - return ENETDOWN; - } - ac = M_WME_GETAC(m); - if (sc->txq[ac].queued > IWI_TX_RING_COUNT - 8) { - ifp->if_drv_flags |= IFF_DRV_OACTIVE; - IWI_UNLOCK(sc); - m_freem(m); - ieee80211_free_node(ni); - return ENOBUFS; /* XXX */ - } - - BPF_MTAP(ifp, m); - - /* XXX honor params */ - if (iwi_tx_start(ifp, m, ni, ac) != 0) { - ieee80211_free_node(ni); - ifp->if_oerrors++; - IWI_UNLOCK(sc); - return EIO; - } - - IWI_UNLOCK(sc); - + /* no support; just discard */ + m_freem(m); + ieee80211_free_node(ni); return 0; } static void -iwi_start(struct ifnet *ifp) +iwi_start_locked(struct ifnet *ifp) { struct iwi_softc *sc = ifp->if_softc; struct mbuf *m; struct ieee80211_node *ni; int ac; - IWI_LOCK_DECL; - IWI_LOCK(sc); + IWI_LOCK_ASSERT(sc); - if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { - IWI_UNLOCK(sc); + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) return; - } for (;;) { IFQ_DRV_DEQUEUE(&ifp->if_snd, m); @@ -1970,7 +1993,16 @@ sc->sc_tx_timer = 5; } +} + +static void +iwi_start(struct ifnet *ifp) +{ + struct iwi_softc *sc = ifp->if_softc; + IWI_LOCK_DECL; + IWI_LOCK(sc); + iwi_start_locked(ifp); IWI_UNLOCK(sc); } @@ -2032,22 +2064,12 @@ struct ieee80211com *ic = ifp->if_l2com; struct ifreq *ifr = (struct ifreq *) data; int error = 0; - IWI_LOCK_DECL; - IWI_LOCK(sc); - - /* - * wait until pending iwi_cmd() are completed, to avoid races - * that could cause problems. - */ - while (sc->flags & IWI_FLAG_BUSY) - msleep(sc, &sc->sc_mtx, 0, "iwiioctl", hz); - switch (cmd) { case SIOCSIFFLAGS: if (ifp->if_flags & IFF_UP) { if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) - iwi_init_locked(sc, 0); + iwi_init(sc); } else { if (ifp->if_drv_flags & IFF_DRV_RUNNING) iwi_stop(sc); @@ -2067,10 +2089,8 @@ break; default: error = ether_ioctl(ifp, cmd, data); + break; } - - IWI_UNLOCK(sc); - return error; } @@ -2204,31 +2224,26 @@ * the boot firmware as "master". */ static int -iwi_get_firmware(struct iwi_softc *sc) +iwi_get_firmware(struct iwi_softc *sc, enum ieee80211_opmode opmode) { - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; const struct iwi_firmware_hdr *hdr; const struct firmware *fp; /* invalidate cached firmware on mode change */ - if (sc->fw_mode != ic->ic_opmode) + if (sc->fw_mode != opmode) iwi_put_firmware(sc); - switch (ic->ic_opmode) { + switch (opmode) { case IEEE80211_M_STA: iwi_getfw(&sc->fw_fw, "iwi_bss", &sc->fw_uc, "iwi_ucode_bss"); break; - case IEEE80211_M_IBSS: iwi_getfw(&sc->fw_fw, "iwi_ibss", &sc->fw_uc, "iwi_ucode_ibss"); break; - case IEEE80211_M_MONITOR: iwi_getfw(&sc->fw_fw, "iwi_monitor", &sc->fw_uc, "iwi_ucode_monitor"); break; - default: break; } @@ -2308,7 +2323,7 @@ sc->fw_boot.size, sc->fw_uc.size, sc->fw_fw.size); #endif - sc->fw_mode = ic->ic_opmode; + sc->fw_mode = opmode; return 0; bad: iwi_put_firmware(sc); @@ -2421,6 +2436,7 @@ int ntries, error; IWI_LOCK_ASSERT(sc); + /* copy firmware image to DMA memory */ memcpy(sc->fw_virtaddr, fw->data, fw->size); @@ -2551,16 +2567,16 @@ } static int -iwi_config(struct iwi_softc *sc) +iwi_config(struct iwi_softc *sc, struct ieee80211vap *vap) { struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); struct iwi_configuration config; struct iwi_rateset rs; struct iwi_txpower power; uint32_t data; int error, i; + IWI_LOCK_ASSERT(sc); IEEE80211_ADDR_COPY(vap->iv_myaddr, IF_LLADDR(ifp)); @@ -2924,13 +2940,13 @@ if ((vap->iv_flags & IEEE80211_F_WME) && ni->ni_ies.wme_ie != NULL) { /* NB: don't treat WME setup as failure */ - if (iwi_wme_setparams(sc) == 0 && iwi_wme_setie(sc) == 0) + if (iwi_wme_setparams(sc, ic) == 0 && iwi_wme_setie(sc) == 0) assoc->policy |= htole16(IWI_POLICY_WME); /* XXX complain on failure? */ } - if (vap->iv_appie_assocreq != NULL) { - struct ieee80211_appie *ie = vap->iv_appie_assocreq; + if (vap->iv_appie_wpa != NULL) { + struct ieee80211_appie *ie = vap->iv_appie_wpa; DPRINTF(("Setting optional IE (len=%u)\n", ie->ie_len)); error = iwi_cmd(sc, IWI_CMD_SET_OPTIE, ie->ie_data, ie->ie_len); @@ -3030,17 +3046,6 @@ return iwi_cmd(sc, IWI_CMD_ASSOCIATE, assoc, sizeof *assoc); } -static void -iwi_init(void *priv) -{ - struct iwi_softc *sc = priv; - IWI_LOCK_DECL; - - IWI_LOCK(sc); - iwi_init_locked(sc, 0); - IWI_UNLOCK(sc); -} - /* * release dma resources for the firmware */ @@ -3102,7 +3107,7 @@ } static void -iwi_init_locked(void *priv, int force) +iwi_init(void *priv) { struct iwi_softc *sc = priv; struct ifnet *ifp = sc->sc_ifp; @@ -3111,45 +3116,30 @@ int i; IWI_LOCK_DECL; - IWI_LOCK_ASSERT(sc); + IWI_LOCK(sc); + if (sc->fw_state == IWI_FW_LOADING) { + IWI_UNLOCK(sc); device_printf(sc->sc_dev, "%s: already loading\n", __func__); return; /* XXX: condvar? */ } - iwi_stop(sc); + iwi_stop_locked(sc); + IWI_STATE_BEGIN(sc, IWI_FW_LOADING); + taskqueue_unblock(sc->sc_tq); + taskqueue_unblock(sc->sc_tq2); + if (iwi_reset(sc) != 0) { device_printf(sc->sc_dev, "could not reset adapter\n"); goto fail; } - - IWI_UNLOCK(sc); - if (iwi_get_firmware(sc)) { - IWI_LOCK(sc); - goto fail; - } - - /* allocate DMA memory for mapping firmware image */ - i = sc->fw_fw.size; - if (sc->fw_boot.size > i) - i = sc->fw_boot.size; - /* XXX do we dma the ucode as well ? */ - if (sc->fw_uc.size > i) - i = sc->fw_uc.size; - if (iwi_init_fw_dma(sc, i)) { - IWI_LOCK(sc); - goto fail; - } - IWI_LOCK(sc); - if (iwi_load_firmware(sc, &sc->fw_boot) != 0) { device_printf(sc->sc_dev, "could not load boot firmware %s\n", sc->fw_boot.name); goto fail; } - if (iwi_load_ucode(sc, &sc->fw_uc) != 0) { device_printf(sc->sc_dev, "could not load microcode %s\n", sc->fw_uc.name); @@ -3192,39 +3182,40 @@ } sc->flags |= IWI_FLAG_FW_INITED; - if (iwi_config(sc) != 0) { - device_printf(sc->sc_dev, "device configuration failed\n"); - goto fail; - } - callout_reset(&sc->sc_wdtimer, hz, iwi_watchdog, sc); ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; ifp->if_drv_flags |= IFF_DRV_RUNNING; + IWI_STATE_END(sc, IWI_FW_LOADING); + + IWI_UNLOCK(sc); + ieee80211_start_all(ic); /* start all vap's */ - - IWI_STATE_END(sc, IWI_FW_LOADING); return; - -fail: ifp->if_flags &= ~IFF_UP; +fail: IWI_STATE_END(sc, IWI_FW_LOADING); - iwi_stop(sc); - iwi_put_firmware(sc); + iwi_stop_locked(sc); + IWI_UNLOCK(sc); } static void -iwi_stop(void *priv) +iwi_stop_locked(void *priv) { struct iwi_softc *sc = priv; struct ifnet *ifp = sc->sc_ifp; IWI_LOCK_ASSERT(sc); + + ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); + + taskqueue_block(sc->sc_tq); + taskqueue_block(sc->sc_tq2); if (sc->sc_softled) { callout_stop(&sc->sc_ledtimer); sc->sc_blinking = 0; } + callout_stop(&sc->sc_wdtimer); - callout_stop(&sc->sc_wdtimer); iwi_stop_master(sc); CSR_WRITE_4(sc, IWI_CSR_RST, IWI_RST_SOFT_RESET); @@ -3237,8 +3228,6 @@ iwi_reset_tx_ring(sc, &sc->txq[3]); iwi_reset_rx_ring(sc, &sc->rxq); - ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); - memset(sc->sc_cmd, 0, sizeof(sc->sc_cmd)); sc->sc_tx_timer = 0; sc->sc_rfkill_timer = 0; @@ -3250,13 +3239,25 @@ } static void +iwi_stop(struct iwi_softc *sc) +{ + IWI_LOCK_DECL; + + IWI_LOCK(sc); + iwi_stop_locked(sc); + IWI_UNLOCK(sc); +} + +static void iwi_restart(void *arg, int npending) { struct iwi_softc *sc = arg; IWI_LOCK_DECL; IWI_LOCK(sc); - iwi_init_locked(sc, 1); /* NB: force state machine */ + /* XXX not right */ + if (sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING) + iwi_init(sc); IWI_UNLOCK(sc); } @@ -3276,6 +3277,7 @@ struct iwi_softc *sc = arg; device_printf(sc->sc_dev, "radio turned on\n"); + iwi_init(sc); } @@ -3286,8 +3288,9 @@ IWI_LOCK_DECL; device_printf(sc->sc_dev, "radio turned off\n"); + IWI_LOCK(sc); - iwi_stop(sc); + iwi_stop_locked(sc); sc->sc_rfkill_timer = 2; IWI_UNLOCK(sc); } @@ -3535,14 +3538,14 @@ } static void -iwi_ops(void *arg, int npending) +iwi_ops(void *arg0, int npending) { - struct iwi_softc *sc = arg; + struct iwi_softc *sc = arg0; struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); IWI_LOCK_DECL; - int cmd; + int cmd, arg; again: IWI_CMD_LOCK(sc); @@ -3552,6 +3555,7 @@ IWI_CMD_UNLOCK(sc); return; } + arg = sc->sc_cmd[sc->sc_cmd_cur]; sc->sc_cmd[sc->sc_cmd_cur] = 0; /* free the slot */ sc->sc_cmd_cur = (sc->sc_cmd_cur + 1) % IWI_CMD_MAXOPS; >>> TRUNCATED FOR MAIL (1000 lines) <<<