From owner-p4-projects@FreeBSD.ORG Fri Sep 28 21:46:09 2007 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id C7C1D16A469; Fri, 28 Sep 2007 21:46:08 +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 868C916A421 for ; Fri, 28 Sep 2007 21:46:08 +0000 (UTC) (envelope-from thompsa@freebsd.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id 6B46813C45B for ; Fri, 28 Sep 2007 21:46:08 +0000 (UTC) (envelope-from thompsa@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 l8SLk8Bd057316 for ; Fri, 28 Sep 2007 21:46:08 GMT (envelope-from thompsa@freebsd.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.1/8.14.1/Submit) id l8SLk8e1057313 for perforce@freebsd.org; Fri, 28 Sep 2007 21:46:08 GMT (envelope-from thompsa@freebsd.org) Date: Fri, 28 Sep 2007 21:46:08 GMT Message-Id: <200709282146.l8SLk8e1057313@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to thompsa@freebsd.org using -f From: Andrew Thompson To: Perforce Change Reviews Cc: Subject: PERFORCE change 126945 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: Fri, 28 Sep 2007 21:46:09 -0000 http://perforce.freebsd.org/chv.cgi?CH=126945 Change 126945 by thompsa@thompsa_heff on 2007/09/28 21:45:44 Drop in a reduced set of changes to HEAD which seem to work quite well. Affected files ... .. //depot/projects/wifi/sys/dev/ipw/if_ipw.c#26 edit .. //depot/projects/wifi/sys/dev/ipw/if_ipwreg.h#6 edit .. //depot/projects/wifi/sys/dev/ipw/if_ipwvar.h#8 edit Differences ... ==== //depot/projects/wifi/sys/dev/ipw/if_ipw.c#26 (text+ko) ==== @@ -1,3 +1,5 @@ +/* $FreeBSD: src/sys/dev/ipw/if_ipw.c,v 1.30 2007/09/05 21:31:31 sam Exp $ */ + /*- * Copyright (c) 2004-2006 * Damien Bergamini . All rights reserved. @@ -81,7 +83,7 @@ #ifdef IPW_DEBUG #define DPRINTF(x) do { if (ipw_debug > 0) printf x; } while (0) #define DPRINTFN(n, x) do { if (ipw_debug >= (n)) printf x; } while (0) -int ipw_debug = 40; +int ipw_debug = 3; SYSCTL_INT(_debug, OID_AUTO, ipw, CTLFLAG_RW, &ipw_debug, 0, "ipw debug level"); #else #define DPRINTF(x) @@ -109,49 +111,37 @@ static int ipw_media_change(struct ifnet *); static void ipw_media_status(struct ifnet *, struct ifmediareq *); static int ipw_newstate(struct ieee80211com *, enum ieee80211_state, int); -static void ipw_rx_cmd_intr(struct ipw_softc *, struct ipw_soft_buf *); -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 *, +static uint16_t ipw_read_prom_word(struct ipw_softc *, uint8_t); +static void ipw_command_intr(struct ipw_softc *, struct ipw_soft_buf *); +static void ipw_newstate_intr(struct ipw_softc *, struct ipw_soft_buf *); +static void ipw_data_intr(struct ipw_softc *, struct ipw_status *, struct ipw_soft_bd *, struct ipw_soft_buf *); static void ipw_rx_intr(struct ipw_softc *); static void ipw_release_sbd(struct ipw_softc *, struct ipw_soft_bd *); static void ipw_tx_intr(struct ipw_softc *); -static const char *ipw_cmdname(int); static void ipw_intr(void *); static void ipw_dma_map_addr(void *, bus_dma_segment_t *, int, int); -static int ipw_cmd(struct ipw_softc *, uint32_t, const void *, uint32_t); +static const char * ipw_cmdname(int); +static int ipw_cmd(struct ipw_softc *, uint32_t, void *, uint32_t); static int ipw_tx_start(struct ifnet *, struct mbuf *, struct ieee80211_node *); -static void ipw_start_locked(struct ifnet *); static void ipw_start(struct ifnet *); -static void ipw_watchdog(void *); +static void ipw_watchdog(struct ifnet *); static int ipw_ioctl(struct ifnet *, u_long, caddr_t); static void ipw_stop_master(struct ipw_softc *); -static int ipw_reset(struct ipw_softc *); static int ipw_enable(struct ipw_softc *); static int ipw_disable(struct ipw_softc *); +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 void ipw_assoc_task(void *, int); +static int ipw_auth_and_assoc(struct ipw_softc *); static int ipw_config(struct ipw_softc *); -static void ipw_restart(void *, int); -static int ipw_scan(struct ipw_softc *); -static void ipw_assoc_lost(void *, int); -static void ipw_assoc(struct ieee80211com *); -static void ipw_disassoc(struct ieee80211com *); -static int ipw_auth_and_assoc(struct ipw_softc *); -static int ipw_disassociate(struct ipw_softc *); -static void ipw_ops(void *, int); +static void ipw_init_task(void *, int); static void ipw_init(void *); -static void ipw_init_locked(struct ipw_softc *, int); -static void ipw_stop_locked(struct ipw_softc *); static void ipw_stop(void *); static int ipw_sysctl_stats(SYSCTL_HANDLER_ARGS); -static int ipw_getrfkill(struct ipw_softc *); -static void ipw_radio_on(void *, int); -static void ipw_radio_off(void *, int); static int ipw_sysctl_radio(SYSCTL_HANDLER_ARGS); -static int ipw_get_firmware(struct ipw_softc *); -static void ipw_put_firmware(struct ipw_softc *); -static int ipw_load_ucode(struct ipw_softc *, const struct ipw_fw *); -static int ipw_load_firmware(struct ipw_softc *, const struct ipw_fw *); static uint32_t ipw_read_table1(struct ipw_softc *, uint32_t); static void ipw_write_table1(struct ipw_softc *, uint32_t, uint32_t); #if 0 @@ -162,8 +152,8 @@ #endif static void ipw_write_mem_1(struct ipw_softc *, bus_size_t, const uint8_t *, bus_size_t); -static uint16_t ipw_read_prom_word(struct ipw_softc *, uint8_t); -static void ipw_sysctlattach(struct ipw_softc *); +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 *); static void ipw_set_channel(struct ieee80211com *); @@ -232,25 +222,10 @@ mtx_init(&sc->sc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, MTX_DEF | MTX_RECURSE); - IPW_CMD_LOCK_INIT(sc); -#if __FreeBSD_version >= 700000 - sc->sc_tq = taskqueue_create("ipw_taskq", M_NOWAIT, - taskqueue_thread_enqueue, &sc->sc_tq); - taskqueue_start_threads(&sc->sc_tq, 1, PI_NET, "%s taskq", - device_get_nameunit(dev)); -#else - sc->sc_tq = taskqueue_create("ipw_taskq", M_NOWAIT, - taskqueue_thread_enqueue, &sc->sc_tq, &sc->sc_tqproc); - taskqueue_start_threads(&sc->sc_tq, 1, PI_NET, "%s taskq", - device_get_nameunit(dev)); -#endif - TASK_INIT(&sc->sc_radiontask, 0, ipw_radio_on, sc); - TASK_INIT(&sc->sc_radiofftask, 0, ipw_radio_off, sc); - TASK_INIT(&sc->sc_assoclosttask,0, ipw_assoc_lost, sc); - TASK_INIT(&sc->sc_restarttask, 0, ipw_restart, sc); - TASK_INIT(&sc->sc_opstask, 0, ipw_ops, sc); - callout_init_mtx(&sc->sc_wdtimer, &sc->sc_mtx, 0); + 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_assoc_task, 0, ipw_assoc_task, sc); if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { device_printf(dev, "chip is in D%d power mode " @@ -304,6 +279,7 @@ ifp->if_init = ipw_init; ifp->if_ioctl = ipw_ioctl; ifp->if_start = ipw_start; + ifp->if_watchdog = ipw_watchdog; IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN; IFQ_SET_READY(&ifp->if_snd); @@ -314,12 +290,11 @@ ic->ic_state = IEEE80211_S_INIT; /* set device capabilities */ - ic->ic_caps = IEEE80211_C_IBSS /* IBSS mode supported */ - | IEEE80211_C_MONITOR /* monitor mode supported */ - | IEEE80211_C_PMGT /* power save supported */ - | IEEE80211_C_SHPREAMBLE /* short preamble supported */ - | IEEE80211_C_WPA /* 802.11i supported */ - ; + ic->ic_caps = + IEEE80211_C_IBSS | /* IBSS mode supported */ + IEEE80211_C_MONITOR | /* monitor mode supported */ + IEEE80211_C_TXPMGT | /* tx power management */ + IEEE80211_C_SHPREAMBLE; /* short preamble supported */ /* read MAC address from EEPROM */ val = ipw_read_prom_word(sc, IPW_EEPROM_MAC + 0); @@ -335,7 +310,6 @@ /* set supported .11b channels (read from EEPROM) */ if ((val = ipw_read_prom_word(sc, IPW_EEPROM_CHANNEL_LIST)) == 0) val = 0x7ff; /* default to channels 1-11 */ - sc->chanmask = val; val <<= 1; for (i = 1; i < 16; i++) { if (val & (1 << i)) { @@ -345,11 +319,10 @@ c->ic_ieee = i; } } - DPRINTF(("%s: added %d channels\n", __func__, ic->ic_nchans)); /* check support for radio transmitter switch in EEPROM */ if (!(ipw_read_prom_word(sc, IPW_EEPROM_RADIO) & 8)) - sc->flags |= IPW_FLAG_HAS_RFSWITCH; + sc->flags |= IPW_FLAG_HAS_RADIO_SWITCH; ieee80211_ifattach(ic); /* override state transition machine */ @@ -364,7 +337,7 @@ ic->ic_scan_mindwell = ipw_scan_mindwell; bpfattach2(ifp, DLT_IEEE802_11_RADIO, - sizeof (struct ieee80211_frame) + sizeof (sc->sc_txtap), + sizeof (struct ieee80211_frame) + sizeof (sc->sc_txtap), &sc->sc_drvbpf); sc->sc_rxtap_len = sizeof sc->sc_rxtap; @@ -375,7 +348,25 @@ sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len); sc->sc_txtap.wt_ihdr.it_present = htole32(IPW_TX_RADIOTAP_PRESENT); - ipw_sysctlattach(sc); + /* + * Add a few sysctl knobs. + */ + sc->dwelltime = 100; + + SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), + SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "radio", + CTLTYPE_INT | CTLFLAG_RD, sc, 0, ipw_sysctl_radio, "I", + "radio transmitter switch state (0=off, 1=on)"); + + SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), + SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "stats", + CTLTYPE_OPAQUE | CTLFLAG_RD, sc, 0, ipw_sysctl_stats, "S", + "statistics"); + + SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), + SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "dwell", + CTLFLAG_RW, &sc->dwelltime, 0, + "channel dwell time (ms) for AP/station scanning"); /* * Hook our interrupt after all initialization is complete. @@ -404,8 +395,6 @@ struct ifnet *ifp = ic->ic_ifp; ipw_stop(sc); - callout_drain(&sc->sc_wdtimer); - ipw_put_firmware(sc); if (ifp != NULL) { bpfdetach(ifp); @@ -425,10 +414,12 @@ if (ifp != NULL) if_free(ifp); - taskqueue_free(sc->sc_tq); + if (sc->sc_firmware != NULL) { + firmware_put(sc->sc_firmware, FIRMWARE_UNLOAD); + sc->sc_firmware = NULL; + } mtx_destroy(&sc->sc_mtx); - IPW_CMD_LOCK_DESTROY(sc); return 0; } @@ -726,7 +717,6 @@ struct ipw_softc *sc = device_get_softc(dev); ipw_stop(sc); - ipw_put_firmware(sc); /* ??? XXX */ return 0; } @@ -746,19 +736,18 @@ { struct ipw_softc *sc = device_get_softc(dev); struct ifnet *ifp = sc->sc_ic.ic_ifp; - IPW_LOCK_DECL; - IPW_LOCK(sc); + mtx_lock(&sc->sc_mtx); pci_write_config(dev, 0x41, 0, 1); if (ifp->if_flags & IFF_UP) { - ipw_init_locked(sc, 0); + ifp->if_init(ifp->if_softc); if (ifp->if_drv_flags & IFF_DRV_RUNNING) - ipw_start_locked(ifp); + ifp->if_start(ifp); } - IPW_UNLOCK(sc); + mtx_unlock(&sc->sc_mtx); return 0; } @@ -768,30 +757,20 @@ { struct ipw_softc *sc = ifp->if_softc; int error; - IPW_LOCK_DECL; + + mtx_lock(&sc->sc_mtx); - IPW_LOCK(sc); error = ieee80211_media_change(ifp); - if (error == ENETRESET) { - if ((ifp->if_flags & IFF_UP) && - (ifp->if_drv_flags & IFF_DRV_RUNNING)) - ipw_init_locked(sc, 0); - error = 0; + if (error != ENETRESET) { + mtx_unlock(&sc->sc_mtx); + return error; } - IPW_UNLOCK(sc); + + if ((ifp->if_flags & IFF_UP) && (ifp->if_drv_flags & IFF_DRV_RUNNING)) + ipw_init(sc); - return error; -} + mtx_unlock(&sc->sc_mtx); -static int -ipw_cvtrate(int ipwrate) -{ - switch (ipwrate) { - case IPW_RATE_DS1: return 2; - case IPW_RATE_DS2: return 4; - case IPW_RATE_DS5: return 11; - case IPW_RATE_DS11: return 22; - } return 0; } @@ -802,9 +781,20 @@ static void ipw_media_status(struct ifnet *ifp, struct ifmediareq *imr) { +#define N(a) (sizeof (a) / sizeof (a[0])) struct ipw_softc *sc = ifp->if_softc; struct ieee80211com *ic = &sc->sc_ic; - int rate; + static const struct { + uint32_t val; + int rate; + } rates[] = { + { IPW_RATE_DS1, 2 }, + { IPW_RATE_DS2, 4 }, + { IPW_RATE_DS5, 11 }, + { IPW_RATE_DS11, 22 }, + }; + uint32_t val; + int rate, i; imr->ifm_status = IFM_AVALID; imr->ifm_active = IFM_IEEE80211; @@ -812,13 +802,33 @@ imr->ifm_status |= IFM_ACTIVE; /* read current transmission rate from adapter */ - rate = ipw_cvtrate(ipw_read_table1(sc, IPW_INFO_CURRENT_TX_RATE) & 0xf); + val = ipw_read_table1(sc, IPW_INFO_CURRENT_TX_RATE) & 0xf; + + /* convert ipw rate to 802.11 rate */ + for (i = 0; i < N(rates) && rates[i].val != val; i++); + rate = (i < N(rates)) ? rates[i].rate : 0; + + imr->ifm_active |= IFM_IEEE80211_11B; imr->ifm_active |= ieee80211_rate2media(ic, rate, IEEE80211_MODE_11B); + switch (ic->ic_opmode) { + case IEEE80211_M_STA: + break; - if (ic->ic_opmode == IEEE80211_M_IBSS) + case IEEE80211_M_IBSS: imr->ifm_active |= IFM_IEEE80211_IBSS; - else if (ic->ic_opmode == IEEE80211_M_MONITOR) + break; + + case IEEE80211_M_MONITOR: imr->ifm_active |= IFM_IEEE80211_MONITOR; + break; + + case IEEE80211_M_AHDEMO: + case IEEE80211_M_HOSTAP: + case IEEE80211_M_WDS: + /* should not get there */ + break; + } +#undef N } static int @@ -826,56 +836,129 @@ { struct ifnet *ifp = ic->ic_ifp; struct ipw_softc *sc = ifp->if_softc; +#if 0 + struct ieee80211_node *ni; + uint32_t len, error; +#endif DPRINTF(("%s: %s -> %s flags 0x%x\n", __func__, ieee80211_state_name[ic->ic_state], ieee80211_state_name[nstate], sc->flags)); switch (nstate) { - case IEEE80211_S_AUTH: - ipw_assoc(ic); - break; + case IEEE80211_S_RUN: +#if 0 + ni = ic->ic_bss; + DELAY(200); /* firmware needs a short delay here */ + + len = IEEE80211_ADDR_LEN; + ipw_read_table2(sc, IPW_INFO_CURRENT_BSSID, ni->ni_bssid, &len); + IEEE80211_ADDR_COPY(ni->ni_macaddr, ni->ni_bssid); + + if (ic->ic_opmode != IEEE80211_M_HOSTAP) { + len = IEEE80211_NWID_LEN; + error = ipw_read_table2(sc, IPW_INFO_CURRENT_SSID, + ni->ni_essid, &len); - case IEEE80211_S_RUN: - if (ic->ic_opmode == IEEE80211_M_IBSS) { - /* - * XXX when joining an ibss network we are called - * with a SCAN -> RUN transition on scan complete. - * Use that to call ipw_auth_and_assoc. On completing - * the join we are then called again with an - * AUTH -> RUN transition and we want to do nothing. - * This is all totally bogus and needs to be redone. - */ - if (ic->ic_state == IEEE80211_S_SCAN) - ipw_assoc(ic); + if (error == 0) { + ni->ni_esslen = len; +#ifdef IPW_DEBUG + if (ipw_debug > 0) { + printf("Associated to "); + ieee80211_print_essid(ni->ni_essid, + ni->ni_esslen); + printf("\n"); + } +#endif + } } - /* XXX way wrong */ - return sc->sc_newstate(ic, nstate, - IEEE80211_FC0_SUBTYPE_ASSOC_RESP); +#endif + return (*sc->sc_newstate)(ic, nstate, arg); + + case IEEE80211_S_INIT: + case IEEE80211_S_SCAN: + return sc->sc_newstate(ic, nstate, arg); + + case IEEE80211_S_AUTH: + taskqueue_enqueue_fast(taskqueue_fast, &sc->sc_assoc_task); break; case IEEE80211_S_ASSOC: - break; - - case IEEE80211_S_INIT: /* - * NB: don't try to do this if ipw_stop_master has - * shutdown the firmware and disabled interrupts. + * If we are not transitioning from AUTH the resend the + * association request. */ - if (ic->ic_state == IEEE80211_S_RUN && - (sc->flags & IPW_FLAG_FW_INITED)) - ipw_disassoc(ic); - default: + if (ic->ic_state != IEEE80211_S_AUTH) + taskqueue_enqueue_fast(taskqueue_fast, + &sc->sc_assoc_task); break; default: break; } - return sc->sc_newstate(ic, nstate, arg); + + ic->ic_state = nstate; + + return 0; +} + +/* + * Read 16 bits at address 'addr' from the serial EEPROM. + */ +static uint16_t +ipw_read_prom_word(struct ipw_softc *sc, uint8_t addr) +{ + uint32_t tmp; + uint16_t val; + int n; + + /* clock C once before the first command */ + IPW_EEPROM_CTL(sc, 0); + IPW_EEPROM_CTL(sc, IPW_EEPROM_S); + IPW_EEPROM_CTL(sc, IPW_EEPROM_S | IPW_EEPROM_C); + IPW_EEPROM_CTL(sc, IPW_EEPROM_S); + + /* write start bit (1) */ + IPW_EEPROM_CTL(sc, IPW_EEPROM_S | IPW_EEPROM_D); + IPW_EEPROM_CTL(sc, IPW_EEPROM_S | IPW_EEPROM_D | IPW_EEPROM_C); + + /* write READ opcode (10) */ + IPW_EEPROM_CTL(sc, IPW_EEPROM_S | IPW_EEPROM_D); + IPW_EEPROM_CTL(sc, IPW_EEPROM_S | IPW_EEPROM_D | IPW_EEPROM_C); + IPW_EEPROM_CTL(sc, IPW_EEPROM_S); + IPW_EEPROM_CTL(sc, IPW_EEPROM_S | IPW_EEPROM_C); + + /* write address A7-A0 */ + for (n = 7; n >= 0; n--) { + IPW_EEPROM_CTL(sc, IPW_EEPROM_S | + (((addr >> n) & 1) << IPW_EEPROM_SHIFT_D)); + IPW_EEPROM_CTL(sc, IPW_EEPROM_S | + (((addr >> n) & 1) << IPW_EEPROM_SHIFT_D) | IPW_EEPROM_C); + } + + IPW_EEPROM_CTL(sc, IPW_EEPROM_S); + + /* read data Q15-Q0 */ + val = 0; + for (n = 15; n >= 0; n--) { + IPW_EEPROM_CTL(sc, IPW_EEPROM_S | IPW_EEPROM_C); + IPW_EEPROM_CTL(sc, IPW_EEPROM_S); + tmp = MEM_READ_4(sc, IPW_MEM_EEPROM_CTL); + val |= ((tmp & IPW_EEPROM_Q) >> IPW_EEPROM_SHIFT_Q) << n; + } + + IPW_EEPROM_CTL(sc, 0); + + /* clear Chip Select and clock C */ + IPW_EEPROM_CTL(sc, IPW_EEPROM_S); + IPW_EEPROM_CTL(sc, 0); + IPW_EEPROM_CTL(sc, IPW_EEPROM_C); + + return le16toh(val); } static void -ipw_rx_cmd_intr(struct ipw_softc *sc, struct ipw_soft_buf *sbuf) +ipw_command_intr(struct ipw_softc *sc, struct ipw_soft_buf *sbuf) { struct ipw_cmd *cmd; @@ -883,16 +966,17 @@ cmd = mtod(sbuf->m, struct ipw_cmd *); - DPRINTFN(9, ("%s(%s subtype %u seq %u len %u status %u)\n", - __func__, ipw_cmdname(le32toh(cmd->type)), le32toh(cmd->subtype), - le32toh(cmd->seq), le32toh(cmd->len), le32toh(cmd->status))); + DPRINTFN(4, ("cmd ack'ed %s(%u, %u, %u, %u, %u)\n", + ipw_cmdname(le32toh(cmd->type)), le32toh(cmd->type), + le32toh(cmd->subtype), le32toh(cmd->seq), le32toh(cmd->len), + le32toh(cmd->status))); sc->flags &= ~IPW_FLAG_BUSY; - wakeup_one(&sc->cmd); + wakeup(sc); } static void -ipw_rx_newstate_intr(struct ipw_softc *sc, struct ipw_soft_buf *sbuf) +ipw_newstate_intr(struct ipw_softc *sc, struct ipw_soft_buf *sbuf) { #define IEEESTATE(ic) ieee80211_state_name[ic->ic_state] struct ieee80211com *ic = &sc->sc_ic; @@ -903,26 +987,20 @@ state = le32toh(*mtod(sbuf->m, uint32_t *)); switch (state) { - case IPW_STATE_INITIALIZED: - case IPW_STATE_DISABLED: - break; - case IPW_STATE_ASSOCIATED: DPRINTFN(2, ("Association succeeded (%s flags 0x%x)\n", IEEESTATE(ic), sc->flags)); + if (sc->flags & IPW_FLAG_SCANNING) { + ieee80211_cancel_scan(ic); + sc->flags &= ~IPW_FLAG_SCANNING; + } sc->flags |= IPW_FLAG_ASSOCIATED; - IPW_STATE_END(sc, IPW_FW_ASSOCIATING); - /* XXX suppress state change in case the fw auto-associates */ - if (ic->ic_state != IEEE80211_S_ASSOC) { - DPRINTF(("Unexpected association (state %u)\n", - ic->ic_state)); - } else - ieee80211_new_state(ic, IEEE80211_S_RUN, -1); + ieee80211_new_state(ic, IEEE80211_S_RUN, -1); break; case IPW_STATE_SCANNING: DPRINTFN(3, ("Scanning (%s flags 0x%x)\n", - IEEESTATE(ic), sc->flags)); + IEEESTATE(ic), sc->flags)); /* * NB: Check driver state for association on assoc * loss as the firmware will immediately start to @@ -931,32 +1009,14 @@ */ if (sc->flags & IPW_FLAG_ASSOCIATED) ieee80211_beacon_miss(ic); - - sc->sc_state_timer = 3; /* fw is still alive */ break; case IPW_STATE_SCAN_COMPLETE: DPRINTFN(3, ("Scan complete (%s flags 0x%x)\n", - IEEESTATE(ic), sc->flags)); - /* - * XXX For some reason scan requests generate scan - * started + scan done events before any traffic is - * received (e.g. probe response frames). We work - * around this by marking the HACK flag and skipping - * the first scan complete event. This works ok - * because the adapter scans only 2.4G channels so - * doing an extra pass doesn't take long. - if (sc->flags & IPW_FLAG_HACK) { - sc->flags &= ~IPW_FLAG_HACK; - break; - } - */ - - /* Only update the scan module if we were actaully scanning */ - if (sc->fw_state == IPW_FW_SCANNING) { + IEEESTATE(ic), sc->flags)); + if (sc->flags & IPW_FLAG_SCANNING) { + ieee80211_scan_done(ic); sc->flags &= ~IPW_FLAG_SCANNING; - IPW_STATE_END(sc, IPW_FW_SCANNING); - ieee80211_scan_done(ic); } break; @@ -964,16 +1024,24 @@ DPRINTFN(2, ("Association lost (%s flags 0x%x)\n", IEEESTATE(ic), sc->flags)); sc->flags &= ~IPW_FLAG_ASSOCIATED; - taskqueue_enqueue(sc->sc_tq, &sc->sc_assoclosttask); + if (ic->ic_state == IEEE80211_S_RUN) + ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); + break; + + case IPW_STATE_DISABLED: + DPRINTFN(2, ("Firmware disabled (%s flags 0x%x)\n", + IEEESTATE(ic), sc->flags)); break; - case IPW_STATE_RADIO_OFF: + case IPW_STATE_RADIO_DISABLED: DPRINTFN(2, ("Radio off (%s flags 0x%x)\n", IEEESTATE(ic), sc->flags)); - taskqueue_enqueue(sc->sc_tq, &sc->sc_radiofftask); + ic->ic_ifp->if_flags &= ~IFF_UP; + ipw_stop(sc); break; + default: - DPRINTFN(2, ("%s: state %u %s flags 0x%x\n", + DPRINTFN(2, ("%s: unhandled state %u %s flags 0x%x\n", __func__, state, IEEESTATE(ic), sc->flags)); break; } @@ -998,7 +1066,6 @@ /* * XXX: Hack to set the current channel to the value advertised in beacons or * probe responses. Only used during AP detection. - * XXX value comes from DSPARMS ie which is wrong for off-channel rx's */ static void ipw_fix_channel(struct ipw_softc *sc, struct mbuf *m) @@ -1025,11 +1092,12 @@ frm += 12; /* skip tstamp, bintval and capinfo fields */ while (frm < efrm) { - if (*frm == IEEE80211_ELEMID_DSPARMS + if (*frm == IEEE80211_ELEMID_DSPARMS) #if IEEE80211_CHAN_MAX < 255 - && frm[2] <= IEEE80211_CHAN_MAX + if (frm[2] <= IEEE80211_CHAN_MAX) #endif - ) { + { + DPRINTF(("Fixing channel to %d\n", frm[2])); c = ieee80211_find_channel(ic, ieee80211_ieee2mhz(frm[2], 0), IEEE80211_CHAN_B); @@ -1043,7 +1111,7 @@ } static void -ipw_rx_data_intr(struct ipw_softc *sc, struct ipw_status *status, +ipw_data_intr(struct ipw_softc *sc, struct ipw_status *status, struct ipw_soft_bd *sbd, struct ipw_soft_buf *sbuf) { struct ieee80211com *ic = &sc->sc_ic; @@ -1052,25 +1120,15 @@ struct ieee80211_frame *wh; struct ieee80211_node *ni; bus_addr_t physaddr; - int error, framelen; - IPW_LOCK_DECL; - - framelen = le32toh(status->len); - if (framelen < IEEE80211_MIN_LEN || framelen > MCLBYTES) { - /* - * XXX >MCLBYTES is bogus as it means the h/w dma'd - * out of bounds; need to figure out how to limit - * frame size in the firmware - */ - /* XXX stat */ - DPRINTF(("drop rx frame len=%u rssi=%u\n", - framelen, status->rssi)); - return; - } + int error; DPRINTFN(5, ("received frame len=%u, rssi=%u\n", le32toh(status->len), status->rssi)); + if (le32toh(status->len) < sizeof (struct ieee80211_frame_min) || + le32toh(status->len) > MCLBYTES) + return; + /* * Try to allocate a new mbuf for this ring element and load it before * processing the current mbuf. If the ring element cannot be loaded, @@ -1116,21 +1174,22 @@ m->m_pkthdr.rcvif = ifp; m->m_pkthdr.len = m->m_len = le32toh(status->len); - /* XXX */ - if (sc->flags & IPW_FLAG_SCANNING) - ipw_fix_channel(sc, m); - - if (sc->sc_drvbpf != NULL) { + if (bpf_peers_present(sc->sc_drvbpf)) { struct ipw_rx_radiotap_header *tap = &sc->sc_rxtap; tap->wr_flags = 0; - tap->wr_antsignal = status->rssi + IPW_RSSI_TO_DBM; + tap->wr_antsignal = status->rssi; + tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq); + tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags); bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_rxtap_len, m); } + if (ic->ic_state == IEEE80211_S_SCAN) + ipw_fix_channel(sc, m); + wh = mtod(m, struct ieee80211_frame *); - IPW_UNLOCK(sc); + mtx_unlock(&sc->sc_mtx); ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh); /* send the frame to the 802.11 layer */ @@ -1138,7 +1197,7 @@ /* node is no longer needed */ ieee80211_free_node(ni); - IPW_LOCK(sc); + mtx_lock(&sc->sc_mtx); bus_dmamap_sync(sc->rbd_dmat, sc->rbd_map, BUS_DMASYNC_PREWRITE); } @@ -1166,16 +1225,16 @@ switch (le16toh(status->code) & 0xf) { case IPW_STATUS_CODE_COMMAND: - ipw_rx_cmd_intr(sc, sbuf); + ipw_command_intr(sc, sbuf); break; case IPW_STATUS_CODE_NEWSTATE: - ipw_rx_newstate_intr(sc, sbuf); + ipw_newstate_intr(sc, sbuf); break; case IPW_STATUS_CODE_DATA_802_3: case IPW_STATUS_CODE_DATA_802_11: - ipw_rx_data_intr(sc, status, sbd, sbuf); + ipw_data_intr(sc, status, sbd, sbuf); break; case IPW_STATUS_CODE_NOTIFICATION: @@ -1191,8 +1250,12 @@ default: device_printf(sc->sc_dev, "unexpected status code %u\n", le16toh(status->code)); - break; } + + /* firmware was killed, stop processing received frames */ + if (!(sc->flags & IPW_FLAG_FW_INITED)) + return; + sbd->bd->flags = 0; } @@ -1230,8 +1293,12 @@ bus_dmamap_unload(sc->txbuf_dmat, sbuf->map); SLIST_INSERT_HEAD(&sc->free_sbuf, sbuf, next); + if (sbuf->m->m_flags & M_TXCB) + ieee80211_process_callback(sbuf->ni, sbuf->m, 0/*XXX*/); m_freem(sbuf->m); ieee80211_free_node(sbuf->ni); + + sc->sc_tx_timer = 0; break; } @@ -1263,10 +1330,8 @@ /* remember what the firmware has processed */ sc->txold = (r == 0) ? IPW_NTBD - 1 : r - 1; - sc->sc_tx_timer = 0; ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; - - ipw_start_locked(ifp); + ipw_start(ifp); } static void @@ -1276,39 +1341,36 @@ uint32_t r; mtx_lock(&sc->sc_mtx); - r = CSR_READ_4(sc, IPW_CSR_INTR); - if (r != 0 && r != 0xffffffff) { - /* acknowledge all interrupts */ - CSR_WRITE_4(sc, IPW_CSR_INTR, r); + + if ((r = CSR_READ_4(sc, IPW_CSR_INTR)) == 0 || r == 0xffffffff) { + mtx_unlock(&sc->sc_mtx); + return; + } + + /* disable interrupts */ + CSR_WRITE_4(sc, IPW_CSR_INTR_MASK, 0); - DPRINTFN(9, ("%s: 0x%x\n", __func__, r)); + /* acknowledge all interrupts */ + CSR_WRITE_4(sc, IPW_CSR_INTR, r); - if (r & IPW_INTR_FATAL_ERROR) { - device_printf(sc->sc_dev, "firmware error\n"); - taskqueue_enqueue(sc->sc_tq, &sc->sc_restarttask); - r = 0; /* NB: don't do anything else */ - } - if (r & IPW_INTR_FW_INIT_DONE) { - wakeup_one(sc); - r &= ~IPW_INTR_FW_INIT_DONE; - } - if (r & IPW_INTR_RX_TRANSFER) { - ipw_rx_intr(sc); - r &= ~IPW_INTR_RX_TRANSFER; - } - if (r & IPW_INTR_TX_TRANSFER) { - ipw_tx_intr(sc); - r &= ~IPW_INTR_TX_TRANSFER; - } - if (r & IPW_INTR_PARITY_ERROR) { - /* XXX rate limit */ - device_printf(sc->sc_dev, "parity error\n"); - r &= ~IPW_INTR_PARITY_ERROR; - } - if (r != 0) - device_printf(sc->sc_dev, - "%s: 0x%x unserviced\n", __func__, r); + if (r & (IPW_INTR_FATAL_ERROR | IPW_INTR_PARITY_ERROR)) { + device_printf(sc->sc_dev, "firmware error\n"); + taskqueue_enqueue_fast(taskqueue_fast, &sc->sc_init_task); + r = 0; /* don't process more interrupts */ } + + if (r & IPW_INTR_FW_INIT_DONE) + wakeup(sc); + + if (r & IPW_INTR_RX_TRANSFER) + ipw_rx_intr(sc); + + if (r & IPW_INTR_TX_TRANSFER) + ipw_tx_intr(sc); + + /* re-enable interrupts */ + CSR_WRITE_4(sc, IPW_CSR_INTR_MASK, IPW_INTR_MASK); + mtx_unlock(&sc->sc_mtx); } @@ -1335,7 +1397,6 @@ { IPW_CMD_BROADCAST_SCAN, "BROADCAST_SCAN" }, { IPW_CMD_DISABLE, "DISABLE" }, { IPW_CMD_DISABLE_PHY, "DISABLE_PHY" }, - { IPW_CMD_DISASSOCIATE, "DISASSOCIATE" }, { IPW_CMD_ENABLE, "ENABLE" }, { IPW_CMD_PREPARE_POWER_DOWN, "PREPARE_POWER_DOWN" }, { IPW_CMD_SET_BASIC_TX_RATES, "SET_BASIC_TX_RATES" }, @@ -1345,17 +1406,13 @@ { IPW_CMD_SET_DESIRED_BSSID, "SET_DESIRED_BSSID" }, { IPW_CMD_SET_ESSID, "SET_ESSID" }, { IPW_CMD_SET_FRAG_THRESHOLD, "SET_FRAG_THRESHOLD" }, - { IPW_CMD_SET_LONG_RETRY, "SET_LONG_RETRY" }, { IPW_CMD_SET_MAC_ADDRESS, "SET_MAC_ADDRESS" }, { IPW_CMD_SET_MANDATORY_BSSID, "SET_MANDATORY_BSSID" }, { IPW_CMD_SET_MODE, "SET_MODE" }, - { IPW_CMD_SET_MSDU_TX_RATES, "SET_MSDU_TX_RATES" }, { IPW_CMD_SET_POWER_MODE, "SET_POWER_MODE" }, { IPW_CMD_SET_RTS_THRESHOLD, "SET_RTS_THRESHOLD" }, - { IPW_CMD_SET_SCAN_DWELL_TIME, "SET_SCAN_DWELL_TIME" }, { IPW_CMD_SET_SCAN_OPTIONS, "SET_SCAN_OPTIONS" }, - { IPW_CMD_SET_SECURITY_INFO, "SET_SECURITY_INFO" }, - { IPW_CMD_SET_SHORT_RETRY, "SET_SHORT_RETRY" }, + { IPW_CMD_SET_SECURITY_INFORMATION, "SET_SECURITY_INFO" }, { IPW_CMD_SET_TX_POWER_INDEX, "SET_TX_POWER_INDEX" }, { IPW_CMD_SET_TX_RATES, "SET_TX_RATES" }, { IPW_CMD_SET_WEP_FLAGS, "SET_WEP_FLAGS" }, @@ -1379,15 +1436,18 @@ * Send a command to the firmware and wait for the acknowledgement. */ static int -ipw_cmd(struct ipw_softc *sc, uint32_t cmd, const void *data, uint32_t len) +ipw_cmd(struct ipw_softc *sc, uint32_t type, void *data, uint32_t len) { struct ipw_soft_bd *sbd; bus_addr_t physaddr; int error; + if (mtx_recursed(&sc->sc_mtx)) + device_printf(sc->sc_dev, "OMG, msleeping on a recursed mtx\n"); + if (sc->flags & IPW_FLAG_BUSY) { device_printf(sc->sc_dev, "%s: %s not sent, busy\n", - __func__, ipw_cmdname(cmd)); + __func__, ipw_cmdname(type)); return EAGAIN; } sc->flags |= IPW_FLAG_BUSY; @@ -1397,13 +1457,12 @@ error = bus_dmamap_load(sc->cmd_dmat, sc->cmd_map, &sc->cmd, sizeof (struct ipw_cmd), ipw_dma_map_addr, &physaddr, 0); if (error != 0) { - device_printf(sc->sc_dev, - "%s: %s not sent, could not map memory (error %u)\n", - __func__, ipw_cmdname(cmd), error); + device_printf(sc->sc_dev, "could not map command DMA memory\n"); + sc->flags &= ~IPW_FLAG_BUSY; return error; } - sc->cmd.type = htole32(cmd); + sc->cmd.type = htole32(type); sc->cmd.subtype = 0; sc->cmd.len = htole32(len); sc->cmd.seq = 0; @@ -1420,7 +1479,7 @@ bus_dmamap_sync(sc->tbd_dmat, sc->tbd_map, BUS_DMASYNC_PREWRITE); DPRINTFN(4, ("sending %s(%u, %u, %u, %u)\n", - ipw_cmdname(cmd), cmd, 0, 0, len)); + ipw_cmdname(type), type, 0, 0, len)); /* kick firmware */ sc->txfree--; @@ -1428,13 +1487,14 @@ CSR_WRITE_4(sc, IPW_CSR_TX_WRITE, sc->txcur); /* wait at most one second for command to complete */ - error = msleep(&sc->cmd, &sc->sc_mtx, 0, "ipwcmd", hz); + error = msleep(sc, &sc->sc_mtx, 0, "ipwcmd", hz); if (error != 0) { device_printf(sc->sc_dev, "%s: %s failed, timeout (error %u)\n", - __func__, ipw_cmdname(cmd), error); - return error; + __func__, ipw_cmdname(type), error); + sc->flags &= ~IPW_FLAG_BUSY; + return (error); } - return 0; + return (0); } static int @@ -1450,15 +1510,11 @@ struct mbuf *mnew; bus_dma_segment_t segs[IPW_MAX_NSEG]; bus_addr_t physaddr; - int nsegs, error, i, iswep, hdrlen, ismcast; + int nsegs, error, i; wh = mtod(m0, struct ieee80211_frame *); - /* NB: only data frames use this path */ - iswep = wh->i_fc[1] & IEEE80211_FC1_WEP; - hdrlen = ieee80211_hdrsize(wh); - ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); - if (iswep) { + if (wh->i_fc[1] & IEEE80211_FC1_WEP) { k = ieee80211_crypto_encap(ic, ni, m0); if (k == NULL) { m_freem(m0); @@ -1469,10 +1525,12 @@ wh = mtod(m0, struct ieee80211_frame *); } - if (sc->sc_drvbpf != NULL) { + if (bpf_peers_present(sc->sc_drvbpf)) { struct ipw_tx_radiotap_header *tap = &sc->sc_txtap; tap->wt_flags = 0; + tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq); >>> TRUNCATED FOR MAIL (1000 lines) <<<