FreeBSD Bugzilla – Attachment 153977 Details for
Bug 197143
[wpi] [patch]: sync with iwn / OpenBSD wpi
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Bugfixes2.diff
patch-wpi3.1.diff (text/plain), 93.00 KB, created by
Andriy Voskoboinyk
on 2015-03-07 22:29:08 UTC
(
hide
)
Description:
Bugfixes2.diff
Filename:
MIME Type:
Creator:
Andriy Voskoboinyk
Created:
2015-03-07 22:29:08 UTC
Size:
93.00 KB
patch
obsolete
>Index: sys/dev/wpi/if_wpi.c >=================================================================== >--- sys/dev/wpi/if_wpi.c (revision 278764) >+++ sys/dev/wpi/if_wpi.c (working copy) >@@ -76,6 +76,7 @@ > #include <sys/linker.h> > #include <sys/firmware.h> > >+#include <machine/atomic.h> > #include <machine/bus.h> > #include <machine/resource.h> > #include <sys/rman.h> >@@ -130,6 +131,7 @@ > static int wpi_attach(device_t); > static void wpi_radiotap_attach(struct wpi_softc *); > static void wpi_sysctlattach(struct wpi_softc *); >+static void wpi_init_beacon(struct wpi_vap *); > static struct ieee80211vap *wpi_vap_create(struct ieee80211com *, > const char [IFNAMSIZ], int, enum ieee80211_opmode, int, > const uint8_t [IEEE80211_ADDR_LEN], >@@ -169,6 +171,7 @@ > struct ieee80211_regdomain *, int, > struct ieee80211_channel[]); > static int wpi_read_eeprom_group(struct wpi_softc *, int); >+static int wpi_add_node_entry_adhoc(struct wpi_softc *); > static void wpi_node_free(struct ieee80211_node *); > static struct ieee80211_node *wpi_node_alloc(struct ieee80211vap *, > const uint8_t mac[IEEE80211_ADDR_LEN]); >@@ -182,9 +185,12 @@ > static void wpi_cmd_done(struct wpi_softc *, struct wpi_rx_desc *); > static void wpi_notif_intr(struct wpi_softc *); > static void wpi_wakeup_intr(struct wpi_softc *); >+#ifdef WPI_DEBUG >+static void wpi_debug_registers(struct wpi_softc *); >+#endif > static void wpi_fatal_intr(struct wpi_softc *); > static void wpi_intr(void *); >-static int wpi_cmd2(struct wpi_softc *, struct wpi_buf *); >+static int wpi_cmd2(struct wpi_softc *, struct wpi_buf *, int); > static int wpi_tx_data(struct wpi_softc *, struct mbuf *, > struct ieee80211_node *); > static int wpi_tx_data_raw(struct wpi_softc *, struct mbuf *, >@@ -193,7 +199,7 @@ > static int wpi_raw_xmit(struct ieee80211_node *, struct mbuf *, > const struct ieee80211_bpf_params *); > static void wpi_start(struct ifnet *); >-static void wpi_start_locked(struct ifnet *); >+static void wpi_start_task(void *, int); > static void wpi_watchdog_rfkill(void *); > static void wpi_watchdog(void *); > static int wpi_ioctl(struct ifnet *, u_long, caddr_t); >@@ -224,11 +230,20 @@ > struct ieee80211_channel *); > static int wpi_scan(struct wpi_softc *, struct ieee80211_channel *); > static int wpi_auth(struct wpi_softc *, struct ieee80211vap *); >+static int wpi_config_beacon(struct wpi_vap *); >+static int wpi_setup_beacon(struct wpi_softc *, struct ieee80211_node *); > static void wpi_update_beacon(struct ieee80211vap *, int); >-static int wpi_setup_beacon(struct wpi_softc *, struct ieee80211_node *); >+static void wpi_newassoc(struct ieee80211_node *, int); > static int wpi_run(struct wpi_softc *, struct ieee80211vap *); >-static int wpi_key_alloc(struct ieee80211vap *, struct ieee80211_key *, >- ieee80211_keyix *, ieee80211_keyix *); >+static int wpi_load_key(struct ieee80211_node *, >+ const struct ieee80211_key *); >+static void wpi_load_key_cb(void *, struct ieee80211_node *); >+static int wpi_set_global_keys(struct ieee80211_node *); >+static int wpi_del_key(struct ieee80211_node *, >+ const struct ieee80211_key *); >+static void wpi_del_key_cb(void *, struct ieee80211_node *); >+static int wpi_process_key(struct ieee80211vap *, >+ const struct ieee80211_key *, int); > static int wpi_key_set(struct ieee80211vap *, > const struct ieee80211_key *, > const uint8_t mac[IEEE80211_ADDR_LEN]); >@@ -248,7 +263,6 @@ > static void wpi_hw_stop(struct wpi_softc *); > static void wpi_radio_on(void *, int); > static void wpi_radio_off(void *, int); >-static void wpi_init_locked(struct wpi_softc *); > static void wpi_init(void *); > static void wpi_stop_locked(struct wpi_softc *); > static void wpi_stop(struct wpi_softc *); >@@ -307,13 +321,16 @@ > struct wpi_softc *sc = (struct wpi_softc *)device_get_softc(dev); > struct ieee80211com *ic; > struct ifnet *ifp; >- int i, error, rid, supportsa = 1; >+ int i, error, rid; >+#ifdef WPI_DEBUG >+ int supportsa = 1; > const struct wpi_ident *ident; >+#endif > uint8_t macaddr[IEEE80211_ADDR_LEN]; > > sc->sc_dev = dev; > >-#ifdef WPI_DEBUG >+#ifdef WPI_DEBUG > error = resource_int_value(device_get_name(sc->sc_dev), > device_get_unit(sc->sc_dev), "debug", &(sc->sc_debug)); > if (error != 0) >@@ -339,6 +356,7 @@ > * this is one such card. A 0x0 in the subdevice table indicates > * the entire subdevice range is to be ignored. > */ >+#ifdef WPI_DEBUG > for (ident = wpi_ident_table; ident->name != NULL; ident++) { > if (ident->subdevice && > pci_get_subdevice(dev) == ident->subdevice) { >@@ -346,6 +364,7 @@ > break; > } > } >+#endif > > /* Clear device-specific "PCI retry timeout" register (41h). */ > pci_write_config(dev, 0x41, 0, 1); >@@ -358,8 +377,7 @@ > RF_ACTIVE); > if (sc->mem == NULL) { > device_printf(dev, "can't map mem space\n"); >- error = ENOMEM; >- return error; >+ return ENOMEM; > } > sc->sc_st = rman_get_bustag(sc->mem); > sc->sc_sh = rman_get_bushandle(sc->mem); >@@ -378,9 +396,11 @@ > } > > WPI_LOCK_INIT(sc); >+ WPI_RXON_LOCK_INIT(sc); >+ WPI_TX_LOCK_INIT(sc); >+ WPI_NT_LOCK_INIT(sc); >+ WPI_TXQ_LOCK_INIT(sc); > >- sc->sc_unr = new_unrhdr(WPI_ID_IBSS_MIN, WPI_ID_IBSS_MAX, &sc->sc_mtx); >- > /* Allocate DMA memory for firmware transfers. */ > if ((error = wpi_alloc_fwmem(sc)) != 0) { > device_printf(dev, >@@ -430,6 +450,7 @@ > ic->ic_caps = > IEEE80211_C_STA /* station mode supported */ > | IEEE80211_C_IBSS /* IBSS mode supported */ >+ | IEEE80211_C_HOSTAP /* Host access point mode */ > | IEEE80211_C_MONITOR /* monitor mode supported */ > | IEEE80211_C_AHDEMO /* adhoc demo mode */ > | IEEE80211_C_BGSCAN /* capable of bg scanning */ >@@ -437,9 +458,6 @@ > | IEEE80211_C_SHSLOT /* short slot time supported */ > | IEEE80211_C_WPA /* 802.11i */ > | IEEE80211_C_SHPREAMBLE /* short preamble supported */ >-#if 0 >- | IEEE80211_C_HOSTAP /* Host access point mode */ >-#endif > | IEEE80211_C_WME /* 802.11e */ > | IEEE80211_C_PMGT /* Station-side power mgmt */ > ; >@@ -447,8 +465,6 @@ > ic->ic_cryptocaps = > IEEE80211_CRYPTO_AES_CCM; > >- ic->ic_flags |= IEEE80211_F_DATAPAD; >- > /* > * Read in the eeprom and also setup the channels for > * net80211. We don't set the rates as net80211 does this for us >@@ -457,20 +473,21 @@ > device_printf(dev, "could not read EEPROM, error %d\n", > error); > goto fail; >- } >+ } > >-#ifdef WPI_DEBUG >+#ifdef WPI_DEBUG > if (bootverbose) { >- device_printf(sc->sc_dev, "Regulatory Domain: %.4s\n", sc->domain); >- device_printf(sc->sc_dev, "Hardware Type: %c\n", >- sc->type > 1 ? 'B': '?'); >- device_printf(sc->sc_dev, "Hardware Revision: %c\n", >- ((le16toh(sc->rev) & 0xf0) == 0xd0) ? 'D': '?'); >- device_printf(sc->sc_dev, "SKU %s support 802.11a\n", >- supportsa ? "does" : "does not"); >+ device_printf(sc->sc_dev, "Regulatory Domain: %.4s\n", >+ sc->domain); >+ device_printf(sc->sc_dev, "Hardware Type: %c\n", >+ sc->type > 1 ? 'B': '?'); >+ device_printf(sc->sc_dev, "Hardware Revision: %c\n", >+ ((sc->rev & 0xf0) == 0xd0) ? 'D': '?'); >+ device_printf(sc->sc_dev, "SKU %s support 802.11a\n", >+ supportsa ? "does" : "does not"); > >- /* XXX hw_config uses the PCIDEV for the Hardware rev. Must check >- what sc->rev really represents - benjsc 20070615 */ >+ /* XXX hw_config uses the PCIDEV for the Hardware rev. Must >+ check what sc->rev really represents - benjsc 20070615 */ > } > #endif > >@@ -494,6 +511,7 @@ > ic->ic_wme.wme_update = wpi_updateedca; > ic->ic_update_promisc = wpi_update_promisc; > ic->ic_update_mcast = wpi_update_mcast; >+ ic->ic_newassoc = wpi_newassoc; > ic->ic_scan_start = wpi_scan_start; > ic->ic_scan_end = wpi_scan_end; > ic->ic_set_channel = wpi_set_channel; >@@ -504,12 +522,13 @@ > > wpi_radiotap_attach(sc); > >- callout_init_mtx(&sc->calib_to, &sc->sc_mtx, 0); >+ callout_init_mtx(&sc->calib_to, &sc->rxon_mtx, 0); > callout_init_mtx(&sc->watchdog_to, &sc->sc_mtx, 0); > callout_init_mtx(&sc->watchdog_rfkill, &sc->sc_mtx, 0); > TASK_INIT(&sc->sc_reinittask, 0, wpi_hw_reset, sc); > TASK_INIT(&sc->sc_radiooff_task, 0, wpi_radio_off, sc); > TASK_INIT(&sc->sc_radioon_task, 0, wpi_radio_on, sc); >+ TASK_INIT(&sc->sc_start_task, 0, wpi_start_task, sc); > > wpi_sysctlattach(sc); > >@@ -560,7 +579,7 @@ > static void > wpi_sysctlattach(struct wpi_softc *sc) > { >-#ifdef WPI_DEBUG >+#ifdef WPI_DEBUG > struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev); > struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev); > >@@ -570,6 +589,23 @@ > #endif > } > >+static void >+wpi_init_beacon(struct wpi_vap *wvp) >+{ >+ struct wpi_buf *bcn = &wvp->wv_bcbuf; >+ struct wpi_cmd_beacon *cmd = (struct wpi_cmd_beacon *)&bcn->data; >+ >+ cmd->id = WPI_ID_BROADCAST; >+ cmd->ofdm_mask = 0xff; >+ cmd->cck_mask = 0x0f; >+ cmd->lifetime = htole32(WPI_LIFETIME_INFINITE); >+ cmd->flags = htole32(WPI_TX_AUTO_SEQ | WPI_TX_INSERT_TSTAMP); >+ >+ bcn->code = WPI_CMD_SET_BEACON; >+ bcn->ac = WPI_CMD_QUEUE_NUM; >+ bcn->size = sizeof(struct wpi_cmd_beacon); >+} >+ > static struct ieee80211vap * > wpi_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, > enum ieee80211_opmode opmode, int flags, >@@ -577,7 +613,6 @@ > const uint8_t mac[IEEE80211_ADDR_LEN]) > { > struct wpi_vap *wvp; >- struct wpi_buf *bcn; > struct ieee80211vap *vap; > > if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */ >@@ -587,23 +622,27 @@ > M_80211_VAP, M_NOWAIT | M_ZERO); > if (wvp == NULL) > return NULL; >- vap = &wvp->vap; >+ vap = &wvp->wv_vap; > ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac); > >- bcn = &wvp->wv_bcbuf; >- bcn->data = NULL; >+ if (opmode == IEEE80211_M_IBSS || opmode == IEEE80211_M_HOSTAP) { >+ WPI_VAP_LOCK_INIT(wvp); >+ wpi_init_beacon(wvp); >+ } > > /* Override with driver methods. */ >- wvp->newstate = vap->iv_newstate; >- vap->iv_key_alloc = wpi_key_alloc; > vap->iv_key_set = wpi_key_set; > vap->iv_key_delete = wpi_key_delete; >+ wvp->wv_newstate = vap->iv_newstate; > vap->iv_newstate = wpi_newstate; > vap->iv_update_beacon = wpi_update_beacon; >+ vap->iv_max_aid = WPI_ID_IBSS_MAX - WPI_ID_IBSS_MIN + 1; > > ieee80211_ratectl_init(vap); > /* Complete setup. */ >- ieee80211_vap_attach(vap, ieee80211_media_change, ieee80211_media_status); >+ ieee80211_vap_attach(vap, ieee80211_media_change, >+ ieee80211_media_status); >+ > ic->ic_opmode = opmode; > return vap; > } >@@ -613,12 +652,18 @@ > { > struct wpi_vap *wvp = WPI_VAP(vap); > struct wpi_buf *bcn = &wvp->wv_bcbuf; >+ enum ieee80211_opmode opmode = vap->iv_opmode; > > ieee80211_ratectl_deinit(vap); > ieee80211_vap_detach(vap); > >- if (bcn->data != NULL) >- free(bcn->data, M_DEVBUF); >+ if (opmode == IEEE80211_M_IBSS || opmode == IEEE80211_M_HOSTAP) { >+ if (bcn->m != NULL) >+ m_freem(bcn->m); >+ >+ WPI_VAP_LOCK_DESTROY(wvp); >+ } >+ > free(wvp, M_80211_VAP); > } > >@@ -637,6 +682,8 @@ > > ieee80211_draintask(ic, &sc->sc_reinittask); > ieee80211_draintask(ic, &sc->sc_radiooff_task); >+ ieee80211_draintask(ic, &sc->sc_radioon_task); >+ ieee80211_draintask(ic, &sc->sc_start_task); > > wpi_stop(sc); > >@@ -673,9 +720,11 @@ > if (ifp != NULL) > if_free(ifp); > >- delete_unrhdr(sc->sc_unr); >- > DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); >+ WPI_TXQ_LOCK_DESTROY(sc); >+ WPI_NT_LOCK_DESTROY(sc); >+ WPI_TX_LOCK_DESTROY(sc); >+ WPI_RXON_LOCK_DESTROY(sc); > WPI_LOCK_DESTROY(sc); > return 0; > } >@@ -726,7 +775,7 @@ > /* Spin until we actually get the lock. */ > for (ntries = 0; ntries < 1000; ntries++) { > if ((WPI_READ(sc, WPI_GP_CNTRL) & >- (WPI_GP_CNTRL_MAC_ACCESS_ENA | WPI_GP_CNTRL_SLEEP)) == >+ (WPI_GP_CNTRL_MAC_ACCESS_ENA | WPI_GP_CNTRL_SLEEP)) == > WPI_GP_CNTRL_MAC_ACCESS_ENA) > return 0; > DELAY(10); >@@ -958,16 +1007,16 @@ > } > > /* Create RX buffer DMA tag. */ >- error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, >+ error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, > BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, > MJUMPAGESIZE, 1, MJUMPAGESIZE, BUS_DMA_NOWAIT, NULL, NULL, > &ring->data_dmat); >- if (error != 0) { >- device_printf(sc->sc_dev, >+ if (error != 0) { >+ device_printf(sc->sc_dev, > "%s: could not create RX buf DMA tag, error %d\n", > __func__, error); >- goto fail; >- } >+ goto fail; >+ } > > /* > * Allocate and map RX buffers. >@@ -1024,6 +1073,10 @@ > wpi_update_rx_ring(struct wpi_softc *sc) > { > struct wpi_rx_ring *ring = &sc->rxq; >+ if (ring->update != 0) { >+ /* Wait for INT_WAKEUP event. */ >+ return; >+ } > > if (WPI_READ(sc, WPI_UCODE_GP1) & WPI_UCODE_GP1_MAC_SLEEP) { > DPRINTF(sc, WPI_DEBUG_PWRSAVE, "%s: wakeup request\n", >@@ -1051,12 +1104,6 @@ > break; > DELAY(10); > } >-#ifdef WPI_DEBUG >- if (ntries == 1000) { >- device_printf(sc->sc_dev, >- "timeout resetting Rx ring\n"); >- } >-#endif > wpi_nic_unlock(sc); > } > >@@ -1126,10 +1173,11 @@ > /* > * We only use rings 0 through 4 (4 EDCA + cmd) so there is no need > * to allocate commands space for other rings. >- * XXX Do we really need to allocate descriptors for other rings? > */ >- if (qid > 4) >+ if (qid > WPI_CMD_QUEUE_NUM) { >+ DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); > return 0; >+ } > > size = WPI_TX_RING_COUNT * sizeof (struct wpi_tx_cmd); > error = wpi_dma_contig_alloc(sc, &ring->cmd_dma, (void **)&ring->cmd, >@@ -1180,6 +1228,11 @@ > static void > wpi_update_tx_ring(struct wpi_softc *sc, struct wpi_tx_ring *ring) > { >+ if (ring->update != 0) { >+ /* Wait for INT_WAKEUP event. */ >+ return; >+ } >+ > if (WPI_READ(sc, WPI_UCODE_GP1) & WPI_UCODE_GP1_MAC_SLEEP) { > DPRINTF(sc, WPI_DEBUG_PWRSAVE, "%s (%d): requesting wakeup\n", > __func__, ring->qid); >@@ -1195,6 +1248,8 @@ > { > int i; > >+ WPI_TXQ_LOCK(sc); >+ > DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); > > for (i = 0; i < WPI_TX_RING_COUNT; i++) { >@@ -1212,10 +1267,11 @@ > memset(ring->desc, 0, ring->desc_dma.size); > bus_dmamap_sync(ring->desc_dma.tag, ring->desc_dma.map, > BUS_DMASYNC_PREWRITE); >- sc->qfullmsk &= ~(1 << ring->qid); >- ring->queued = 0; >+ atomic_clear_32(&sc->qfullmsk, 1 << ring->qid); >+ atomic_store_rel_32(&ring->queued, 0); > ring->cur = 0; > ring->update = 0; >+ WPI_TXQ_UNLOCK(sc); > } > > static void >@@ -1284,8 +1340,9 @@ > WPI_CHK(wpi_read_prom_data(sc, WPI_EEPROM_TYPE, &sc->type, > sizeof(sc->type))); > >- DPRINTF(sc, WPI_DEBUG_EEPROM, "cap=%x rev=%x type=%x\n", sc->cap, le16toh(sc->rev), >- sc->type); >+ sc->rev = le16toh(sc->rev); >+ DPRINTF(sc, WPI_DEBUG_EEPROM, "cap=%x rev=%x type=%x\n", sc->cap, >+ sc->rev, sc->type); > > /* Read the regulatory domain (4 ASCII characters.) */ > WPI_CHK(wpi_read_prom_data(sc, WPI_EEPROM_DOMAIN, sc->domain, >@@ -1331,6 +1388,10 @@ > nflags |= IEEE80211_CHAN_NOADHOC; > } > >+ /* XXX HOSTAP uses WPI_MODE_IBSS */ >+ if (nflags & IEEE80211_CHAN_NOADHOC) >+ nflags |= IEEE80211_CHAN_NOHOSTAP; >+ > return nflags; > } > >@@ -1347,7 +1408,7 @@ > > for (i = 0; i < band->nchan; i++) { > if (!(channels[i].flags & WPI_EEPROM_CHAN_VALID)) { >- DPRINTF(sc, WPI_DEBUG_HW, >+ DPRINTF(sc, WPI_DEBUG_EEPROM, > "Channel Not Valid: %d, band %d\n", > band->chan[i],n); > continue; >@@ -1362,7 +1423,9 @@ > c->ic_maxpower = 2*c->ic_maxregpower; > > if (n == 0) { /* 2GHz band */ >- c->ic_freq = ieee80211_ieee2mhz(chan, IEEE80211_CHAN_G); >+ c->ic_freq = ieee80211_ieee2mhz(chan, >+ IEEE80211_CHAN_G); >+ > /* G =>'s B is supported */ > c->ic_flags = IEEE80211_CHAN_B | nflags; > c = &ic->ic_channels[ic->ic_nchans++]; >@@ -1369,7 +1432,9 @@ > c[0] = c[-1]; > c->ic_flags = IEEE80211_CHAN_G | nflags; > } else { /* 5GHz band */ >- c->ic_freq = ieee80211_ieee2mhz(chan, IEEE80211_CHAN_A); >+ c->ic_freq = ieee80211_ieee2mhz(chan, >+ IEEE80211_CHAN_A); >+ > c->ic_flags = IEEE80211_CHAN_A | nflags; > } > >@@ -1494,6 +1559,50 @@ > return 0; > } > >+static int >+wpi_add_node_entry_adhoc(struct wpi_softc *sc) >+{ >+ int newid = WPI_ID_IBSS_MIN; >+ >+ for (; newid <= WPI_ID_IBSS_MAX; newid++) { >+ if ((sc->nodesmsk & (1 << newid)) == 0) { >+ sc->nodesmsk |= 1 << newid; >+ return newid; >+ } >+ } >+ >+ return WPI_ID_UNDEFINED; >+} >+ >+static __inline int >+wpi_add_node_entry_sta(struct wpi_softc *sc) >+{ >+ sc->nodesmsk |= 1 << WPI_ID_BSS; >+ >+ return WPI_ID_BSS; >+} >+ >+static __inline int >+wpi_check_node_entry(struct wpi_softc *sc, uint8_t id) >+{ >+ if (id == WPI_ID_UNDEFINED) >+ return 0; >+ >+ return (sc->nodesmsk >> id) & 1; >+} >+ >+static __inline void >+wpi_clear_node_table(struct wpi_softc *sc) >+{ >+ sc->nodesmsk = 0; >+} >+ >+static __inline void >+wpi_del_node_entry(struct wpi_softc *sc, uint8_t id) >+{ >+ sc->nodesmsk &= ~(1 << id); >+} >+ > static struct ieee80211_node * > wpi_node_alloc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN]) > { >@@ -1515,15 +1624,15 @@ > { > struct ieee80211com *ic = ni->ni_ic; > struct wpi_softc *sc = ic->ic_ifp->if_softc; >- struct wpi_node *wn = (struct wpi_node *)ni; >+ struct wpi_node *wn = WPI_NODE(ni); > >- if (wn->id >= WPI_ID_IBSS_MIN && wn->id <= WPI_ID_IBSS_MAX) { >- free_unr(sc->sc_unr, wn->id); >- >- WPI_LOCK(sc); >- if (sc->rxon.filter & htole32(WPI_FILTER_BSS)) >+ if (wn->id != WPI_ID_UNDEFINED) { >+ WPI_NT_LOCK(sc); >+ if (wpi_check_node_entry(sc, wn->id)) { >+ wpi_del_node_entry(sc, wn->id); > wpi_del_node(sc, ni); >- WPI_UNLOCK(sc); >+ } >+ WPI_NT_UNLOCK(sc); > } > > sc->sc_node_free(ni); >@@ -1547,13 +1656,11 @@ > ieee80211_state_name[vap->iv_state], > ieee80211_state_name[nstate]); > >- IEEE80211_UNLOCK(ic); >- WPI_LOCK(sc); > switch (nstate) { > case IEEE80211_S_SCAN: >- if ((vap->iv_opmode == IEEE80211_M_IBSS || >- vap->iv_opmode == IEEE80211_M_AHDEMO) && >- (sc->rxon.filter & htole32(WPI_FILTER_BSS))) { >+ WPI_RXON_LOCK(sc); >+ if (sc->rxon.filter & htole32(WPI_FILTER_BSS) && >+ vap->iv_opmode != IEEE80211_M_STA) { > sc->rxon.filter &= ~htole32(WPI_FILTER_BSS); > if ((error = wpi_send_rxon(sc, 0, 1)) != 0) { > device_printf(sc->sc_dev, >@@ -1560,6 +1667,7 @@ > "%s: could not send RXON\n", __func__); > } > } >+ WPI_RXON_UNLOCK(sc); > break; > > case IEEE80211_S_ASSOC: >@@ -1584,7 +1692,9 @@ > * RUN -> RUN transition; Just restart the timers. > */ > if (vap->iv_state == IEEE80211_S_RUN) { >+ WPI_RXON_LOCK(sc); > wpi_calib_timeout(sc); >+ WPI_RXON_UNLOCK(sc); > break; > } > >@@ -1602,8 +1712,6 @@ > default: > break; > } >- WPI_UNLOCK(sc); >- IEEE80211_LOCK(ic); > if (error != 0) { > DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END_ERR, __func__); > return error; >@@ -1611,7 +1719,7 @@ > > DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); > >- return wvp->newstate(vap, nstate, arg); >+ return wvp->wv_newstate(vap, nstate, arg); > } > > static void >@@ -1618,11 +1726,8 @@ > wpi_calib_timeout(void *arg) > { > struct wpi_softc *sc = arg; >- struct ifnet *ifp = sc->sc_ifp; >- struct ieee80211com *ic = ifp->if_l2com; >- struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); > >- if (vap->iv_state != IEEE80211_S_RUN) >+ if (!(sc->rxon.filter & htole32(WPI_FILTER_BSS))) > return; > > wpi_power_calibration(sc); >@@ -1678,7 +1783,6 @@ > struct wpi_rx_data *data) > { > struct ifnet *ifp = sc->sc_ifp; >- const struct ieee80211_cipher *cip = NULL; > struct ieee80211com *ic = ifp->if_l2com; > struct wpi_rx_ring *ring = &sc->rxq; > struct wpi_rx_stat *stat; >@@ -1766,16 +1870,9 @@ > > /* Grab a reference to the source node. */ > wh = mtod(m, struct ieee80211_frame *); >- ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh); > >- if (ni != NULL) >- cip = ni->ni_ucastkey.wk_cipher; > if ((wh->i_fc[1] & IEEE80211_FC1_PROTECTED) && >- !IEEE80211_IS_MULTICAST(wh->i_addr1) && >- cip != NULL && cip->ic_cipher == IEEE80211_CIPHER_AES_CCM) { >- if ((flags & WPI_RX_CIPHER_MASK) != WPI_RX_CIPHER_CCMP) >- goto fail2; >- >+ (flags & WPI_RX_CIPHER_MASK) == WPI_RX_CIPHER_CCMP) { > /* Check whether decryption was successful or not. */ > if ((flags & WPI_RX_DECRYPT_MASK) != WPI_RX_DECRYPT_OK) { > DPRINTF(sc, WPI_DEBUG_RECV, >@@ -1785,6 +1882,8 @@ > m->m_flags |= M_WEP; > } > >+ ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh); >+ > if (ieee80211_radiotap_active(ic)) { > struct wpi_rx_radiotap_header *tap = &sc->sc_rxtap; > >@@ -1791,8 +1890,8 @@ > tap->wr_flags = 0; > if (head->flags & htole16(WPI_STAT_FLAG_SHPREAMBLE)) > tap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; >- tap->wr_dbm_antsignal = (int8_t)(stat->rssi - WPI_RSSI_OFFSET); >- tap->wr_dbm_antnoise = (int8_t)le16toh(stat->noise); >+ tap->wr_dbm_antsignal = (int8_t)(stat->rssi + WPI_RSSI_OFFSET); >+ tap->wr_dbm_antnoise = WPI_RSSI_OFFSET; > tap->wr_tsft = tail->tstamp; > tap->wr_antenna = (le16toh(head->flags) >> 4) & 0xf; > tap->wr_rate = plcp2rate(head->plcp); >@@ -1802,18 +1901,17 @@ > > /* Send the frame to the 802.11 layer. */ > if (ni != NULL) { >- (void)ieee80211_input(ni, m, stat->rssi, -WPI_RSSI_OFFSET); >+ (void)ieee80211_input(ni, m, stat->rssi, WPI_RSSI_OFFSET); > /* Node is no longer needed. */ > ieee80211_free_node(ni); > } else >- (void)ieee80211_input_all(ic, m, stat->rssi, -WPI_RSSI_OFFSET); >+ (void)ieee80211_input_all(ic, m, stat->rssi, WPI_RSSI_OFFSET); > > WPI_LOCK(sc); > > return; > >-fail2: ieee80211_free_node(ni); >- m_freem(m); >+fail2: m_freem(m); > > fail1: if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); > } >@@ -1835,10 +1933,12 @@ > struct mbuf *m; > struct ieee80211_node *ni; > struct ieee80211vap *vap; >- int ackfailcnt = stat->ackfailcnt; >- int status = le32toh(stat->status); >+ struct ieee80211com *ic; >+ uint32_t queued, status = le32toh(stat->status); >+ int ackfailcnt = stat->ackfailcnt / 2; /* wpi_mrr_setup() */ > > KASSERT(data->ni != NULL, ("no node")); >+ KASSERT(data->m != NULL, ("no mbuf")); > > DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); > >@@ -1853,11 +1953,14 @@ > m = data->m, data->m = NULL; > ni = data->ni, data->ni = NULL; > vap = ni->ni_vap; >+ ic = vap->iv_ic; > >+ queued = atomic_fetchadd_32(&ring->queued, -1); >+ atomic_store_rel_32(&sc->sc_tx_timer, 0); >+ > /* > * Update rate control statistics for the node. > */ >- WPI_UNLOCK(sc); > if ((status & 0xff) != 1) { > if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); > ieee80211_ratectl_tx_complete(vap, ni, >@@ -1869,17 +1972,28 @@ > } > > ieee80211_tx_complete(ni, m, (status & 0xff) != 1); >- WPI_LOCK(sc); > >- sc->sc_tx_timer = 0; >- if (--ring->queued < WPI_TX_RING_LOMARK) { >- sc->qfullmsk &= ~(1 << ring->qid); >- if (sc->qfullmsk == 0 && >- (ifp->if_drv_flags & IFF_DRV_OACTIVE)) { >+ IF_LOCK(&ifp->if_snd); >+ if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) && >+ queued <= WPI_TX_RING_LOMARK) { >+ IF_UNLOCK(&ifp->if_snd); >+ >+ if (atomic_load_acq_32(&sc->qfullmsk) != 0) { >+ WPI_TXQ_LOCK(sc); >+ queued = atomic_load_acq_32(&ring->queued); >+ if (queued < WPI_TX_RING_LOMARK) >+ atomic_clear_32(&sc->qfullmsk, 1 << ring->qid); >+ WPI_TXQ_UNLOCK(sc); >+ } >+ >+ if (atomic_load_acq_32(&sc->qfullmsk) == 0) { >+ IF_LOCK(&ifp->if_snd); > ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; >- wpi_start_locked(ifp); >+ IF_UNLOCK(&ifp->if_snd); >+ ieee80211_runtask(ic, &sc->sc_start_task); > } >- } >+ } else >+ IF_UNLOCK(&ifp->if_snd); > > DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); > } >@@ -1891,15 +2005,15 @@ > static void > wpi_cmd_done(struct wpi_softc *sc, struct wpi_rx_desc *desc) > { >- struct wpi_tx_ring *ring = &sc->txq[4]; >+ struct wpi_tx_ring *ring = &sc->txq[WPI_CMD_QUEUE_NUM]; > struct wpi_tx_data *data; > >- DPRINTF(sc, WPI_DEBUG_CMD, "cmd notification qid=%x idx=%d flags=%x " >- "type=%s len=%d\n", desc->qid, desc->idx, >+ DPRINTF(sc, WPI_DEBUG_CMD, "cmd notification qid %x idx %d flags %x " >+ "type %s len %d\n", desc->qid, desc->idx, > desc->flags, wpi_cmd_str(desc->type), > le32toh(desc->len)); > >- if ((desc->qid & 7) != 4) >+ if ((desc->qid & WPI_RX_DESC_QID_MSK) != WPI_CMD_QUEUE_NUM) > return; /* Not a command ack. */ > > data = &ring->data[desc->idx]; >@@ -1913,7 +2027,6 @@ > data->m = NULL; > } > >- sc->flags &= ~WPI_FLAG_BUSY; > wakeup(&ring->cmd[desc->idx]); > } > >@@ -1928,6 +2041,7 @@ > bus_dmamap_sync(sc->shared_dma.tag, sc->shared_dma.map, > BUS_DMASYNC_POSTREAD); > >+ /* This field may be corrupted when DIAGNOSTIC option is used. */ > hw = le32toh(sc->shared->next); > hw = (hw == 0) ? WPI_RX_RING_COUNT - 1 : hw - 1; > >@@ -1946,13 +2060,21 @@ > __func__, sc->rxq.cur, desc->qid, desc->idx, desc->flags, > desc->type, wpi_cmd_str(desc->type), le32toh(desc->len)); > >- if (!(desc->qid & 0x80)) /* Reply to a command. */ >+ if (!(desc->qid & WPI_UNSOLICITED_RX_NOTIF)) { >+ /* Reply to a command. */ > wpi_cmd_done(sc, desc); >+ } > > switch (desc->type) { > case WPI_RX_DONE: > /* An 802.11 frame has been received. */ > wpi_rx_done(sc, desc, data); >+ >+ if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { >+ /* wpi_stop() was called. */ >+ return; >+ } >+ > break; > > case WPI_TX_DONE: >@@ -1980,13 +2102,10 @@ > le32toh(miss->total)); > > if (vap->iv_state == IEEE80211_S_RUN && >- (ic->ic_flags & IEEE80211_S_SCAN) == 0) { >- if (misses >= vap->iv_bmissthreshold) { >- WPI_UNLOCK(sc); >- ieee80211_beacon_miss(ic); >- WPI_LOCK(sc); >- } >- } >+ (ic->ic_flags & IEEE80211_F_SCAN) == 0 && >+ misses >= vap->iv_bmissthreshold) >+ ieee80211_beacon_miss(ic); >+ > break; > } > case WPI_UC_READY: >@@ -2013,8 +2132,8 @@ > } > case WPI_STATE_CHANGED: > { >- bus_dmamap_sync(sc->rxq.data_dmat, data->map, >- BUS_DMASYNC_POSTREAD); >+ bus_dmamap_sync(sc->rxq.data_dmat, data->map, >+ BUS_DMASYNC_POSTREAD); > > uint32_t *status = (uint32_t *)(desc + 1); > >@@ -2022,6 +2141,9 @@ > le32toh(*status)); > > if (le32toh(*status) & 1) { >+ WPI_NT_LOCK(sc); >+ wpi_clear_node_table(sc); >+ WPI_NT_UNLOCK(sc); > ieee80211_runtask(ic, &sc->sc_radiooff_task); > return; > } >@@ -2051,10 +2173,8 @@ > "scan finished nchan=%d status=%d chan=%d\n", > scan->nchan, scan->status, scan->chan); > #endif >- sc->sc_scan_timer = 0; >- WPI_UNLOCK(sc); >+ atomic_store_rel_32(&sc->sc_scan_timer, 0); > ieee80211_scan_next(vap); >- WPI_LOCK(sc); > break; > } > } >@@ -2068,7 +2188,7 @@ > * Process an INT_WAKEUP interrupt raised when the microcontroller wakes up > * from power-down sleep mode. > */ >-static void >+static void > wpi_wakeup_intr(struct wpi_softc *sc) > { > int qid; >@@ -2077,23 +2197,108 @@ > "%s: ucode wakeup from power-down sleep\n", __func__); > > /* Wakeup RX and TX rings. */ >- if (sc->rxq.update) { >+ if (sc->rxq.update != 0) { > sc->rxq.update = 0; > wpi_update_rx_ring(sc); > } >- for (qid = 0; qid < WPI_NTXQUEUES; qid++) { >+ >+ WPI_TXQ_LOCK(sc); >+ for (qid = 0; qid < WPI_DRV_NTXQUEUES; qid++) { > struct wpi_tx_ring *ring = &sc->txq[qid]; > >- if (ring->update) { >+ if (ring->update != 0) { > ring->update = 0; > wpi_update_tx_ring(sc, ring); > } > } >+ WPI_TXQ_UNLOCK(sc); > > WPI_CLRBITS(sc, WPI_GP_CNTRL, WPI_GP_CNTRL_MAC_ACCESS_REQ); > } > > /* >+ * This function prints firmware registers >+ */ >+#ifdef WPI_DEBUG >+static void >+wpi_debug_registers(struct wpi_softc *sc) >+{ >+#define COUNTOF(array) (sizeof(array) / sizeof(array[0])) >+ int i; >+ static const uint32_t csr_tbl[] = { >+ WPI_HW_IF_CONFIG, >+ WPI_INT, >+ WPI_INT_MASK, >+ WPI_FH_INT, >+ WPI_GPIO_IN, >+ WPI_RESET, >+ WPI_GP_CNTRL, >+ WPI_EEPROM, >+ WPI_EEPROM_GP, >+ WPI_GIO, >+ WPI_UCODE_GP1, >+ WPI_UCODE_GP2, >+ WPI_GIO_CHICKEN, >+ WPI_ANA_PLL, >+ WPI_DBG_HPET_MEM, >+ }; >+ static const uint32_t prph_tbl[] = { >+ WPI_APMG_CLK_CTRL, >+ WPI_APMG_PS, >+ WPI_APMG_PCI_STT, >+ WPI_APMG_RFKILL, >+ }; >+ /* Undocumented */ >+ static const uint32_t prph2_tbl[] = { >+ 0x302c, >+ 0x3044, >+ 0x3048, >+ 0x3050, >+ 0x3054, >+ 0x3080, >+ 0x3084, >+ }; >+ >+ DPRINTF(sc, WPI_DEBUG_REGISTER,"%s","\n"); >+ >+ for (i = 0; i < COUNTOF(csr_tbl); i++) { >+ DPRINTF(sc, WPI_DEBUG_REGISTER, " %-18s: 0x%08x ", >+ wpi_get_csr_string(csr_tbl[i]), WPI_READ(sc, csr_tbl[i])); >+ >+ if ((i + 1) % 2 == 0) >+ DPRINTF(sc, WPI_DEBUG_REGISTER, "\n"); >+ } >+ DPRINTF(sc, WPI_DEBUG_REGISTER, "\n\n"); >+ >+ if (wpi_nic_lock(sc) == 0) { >+ for (i = 0; i < COUNTOF(prph_tbl); i++) { >+ DPRINTF(sc, WPI_DEBUG_REGISTER, " %-18s: 0x%08x ", >+ wpi_get_prph_string(prph_tbl[i]), >+ wpi_prph_read(sc, prph_tbl[i])); >+ >+ if ((i + 1) % 2 == 0) >+ DPRINTF(sc, WPI_DEBUG_REGISTER, "\n"); >+ } >+ DPRINTF(sc, WPI_DEBUG_REGISTER, "\n"); >+ >+ for (i = 0; i < COUNTOF(prph2_tbl); i++) { >+ DPRINTF(sc, WPI_DEBUG_REGISTER, " 0x%04x: 0x%08x ", >+ prph2_tbl[i], wpi_prph_read(sc, prph2_tbl[i])); >+ >+ if ((i + 1) % 3 == 0) >+ DPRINTF(sc, WPI_DEBUG_REGISTER, "\n"); >+ } >+ DPRINTF(sc, WPI_DEBUG_REGISTER, "\n\n"); >+ wpi_nic_unlock(sc); >+ } else { >+ DPRINTF(sc, WPI_DEBUG_REGISTER, >+ "Cannot access internal registers.\n"); >+ } >+#undef COUNTOF >+} >+#endif >+ >+/* > * Dump the error log of the firmware when a firmware panic occurs. Although > * we can't debug the firmware because it is neither open source nor free, it > * can help us to identify certain classes of problems. >@@ -2112,12 +2317,12 @@ > WPI_FW_DATA_BASE + WPI_FW_DATA_MAXSZ) { > printf("%s: bad firmware error log address 0x%08x\n", __func__, > sc->errptr); >- return; >- } >+ return; >+ } > if (wpi_nic_lock(sc) != 0) { > printf("%s: could not read firmware error log\n", __func__); >- return; >- } >+ return; >+ } > /* Read number of entries in the log. */ > count = wpi_mem_read(sc, sc->errptr); > if (count == 0 || count * sizeof (dump) > WPI_FW_DATA_MAXSZ) { >@@ -2150,11 +2355,13 @@ > wpi_nic_unlock(sc); > /* Dump driver status (TX and RX rings) while we're here. */ > printf("driver status:\n"); >- for (i = 0; i < WPI_NTXQUEUES; i++) { >+ WPI_TXQ_LOCK(sc); >+ for (i = 0; i < WPI_DRV_NTXQUEUES; i++) { > struct wpi_tx_ring *ring = &sc->txq[i]; > printf(" tx ring %2d: qid=%-2d cur=%-3d queued=%-3d\n", > i, ring->qid, ring->cur, ring->queued); > } >+ WPI_TXQ_UNLOCK(sc); > printf(" rx ring: cur=%d\n", sc->rxq.cur); > } > >@@ -2172,10 +2379,8 @@ > > r1 = WPI_READ(sc, WPI_INT); > >- if (r1 == 0xffffffff || (r1 & 0xfffffff0) == 0xa5a5a5a0) { >- WPI_UNLOCK(sc); >- return; /* Hardware gone! */ >- } >+ if (r1 == 0xffffffff || (r1 & 0xfffffff0) == 0xa5a5a5a0) >+ goto end; /* Hardware gone! */ > > r2 = WPI_READ(sc, WPI_FH_INT); > >@@ -2193,14 +2398,15 @@ > struct ieee80211com *ic = ifp->if_l2com; > > device_printf(sc->sc_dev, "fatal firmware error\n"); >+#ifdef WPI_DEBUG >+ wpi_debug_registers(sc); >+#endif > wpi_fatal_intr(sc); > DPRINTF(sc, WPI_DEBUG_HW, > "(%s)\n", (r1 & WPI_INT_SW_ERR) ? "(Software Error)" : > "(Hardware Error)"); > ieee80211_runtask(ic, &sc->sc_reinittask); >- sc->flags &= ~WPI_FLAG_BUSY; >- WPI_UNLOCK(sc); >- return; >+ goto end; > } > > if ((r1 & (WPI_INT_FH_RX | WPI_INT_SW_RX)) || >@@ -2218,14 +2424,12 @@ > if (ifp->if_flags & IFF_UP) > WPI_WRITE(sc, WPI_INT_MASK, WPI_INT_MASK_DEF); > >- WPI_UNLOCK(sc); >+end: WPI_UNLOCK(sc); > } > > static int >-wpi_cmd2(struct wpi_softc *sc, struct wpi_buf *buf) >+wpi_cmd2(struct wpi_softc *sc, struct wpi_buf *buf, int count) > { >- struct ifnet *ifp = sc->sc_ifp; >- struct ieee80211com *ic = ifp->if_l2com; > struct ieee80211_frame *wh; > struct wpi_tx_cmd *cmd; > struct wpi_tx_data *data; >@@ -2233,20 +2437,36 @@ > struct wpi_tx_ring *ring; > struct mbuf *m1; > bus_dma_segment_t *seg, segs[WPI_MAX_SCATTER]; >- int error, i, hdrspace, nsegs, totlen; >+ int error, i, hdrlen, nsegs, totlen, pad; > >- WPI_LOCK_ASSERT(sc); >+ WPI_TXQ_LOCK(sc); > > DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); > >+ if (atomic_load_acq_32(&sc->txq_active) == 0) { >+ error = ENETDOWN; >+ goto fail; >+ } >+ > wh = mtod(buf->m, struct ieee80211_frame *); >- hdrspace = ieee80211_anyhdrspace(ic, wh); >+ hdrlen = ieee80211_anyhdrsize(wh); > totlen = buf->m->m_pkthdr.len; > >+ if (hdrlen & 3) { >+ /* First segment length must be a multiple of 4. */ >+ pad = 4 - (hdrlen & 3); >+ } else >+ pad = 0; >+ > ring = &sc->txq[buf->ac]; > desc = &ring->desc[ring->cur]; > data = &ring->data[ring->cur]; > >+ if (atomic_load_acq_32(&ring->queued) > WPI_TX_RING_HIMARK) { >+ error = ENOMEM; >+ goto fail; >+ } >+ > /* Prepare TX firmware command. */ > cmd = &ring->cmd[ring->cur]; > cmd->code = buf->code; >@@ -2257,8 +2477,8 @@ > memcpy(cmd->data, buf->data, buf->size); > > /* Save and trim IEEE802.11 header. */ >- memcpy((uint8_t *)(cmd->data + buf->size), wh, hdrspace); >- m_adj(buf->m, hdrspace); >+ memcpy((uint8_t *)(cmd->data + buf->size), wh, hdrlen); >+ m_adj(buf->m, hdrlen); > > error = bus_dmamap_load_mbuf_sg(ring->data_dmat, data->map, buf->m, > segs, &nsegs, BUS_DMA_NOWAIT); >@@ -2265,17 +2485,16 @@ > if (error != 0 && error != EFBIG) { > device_printf(sc->sc_dev, > "%s: can't map mbuf (error %d)\n", __func__, error); >- m_freem(buf->m); >- return error; >+ goto fail; > } > if (error != 0) { > /* Too many DMA segments, linearize mbuf. */ >- m1 = m_collapse(buf->m, M_NOWAIT, WPI_MAX_SCATTER); >+ m1 = m_collapse(buf->m, M_NOWAIT, WPI_MAX_SCATTER - 1); > if (m1 == NULL) { > device_printf(sc->sc_dev, > "%s: could not defrag mbuf\n", __func__); >- m_freem(buf->m); >- return ENOBUFS; >+ error = ENOBUFS; >+ goto fail; > } > buf->m = m1; > >@@ -2283,9 +2502,9 @@ > buf->m, segs, &nsegs, BUS_DMA_NOWAIT); > if (error != 0) { > device_printf(sc->sc_dev, >- "%s: can't map mbuf (error %d)\n", __func__, error); >- m_freem(buf->m); >- return error; >+ "%s: can't map mbuf (error %d)\n", __func__, >+ error); >+ goto fail; > } > } > >@@ -2296,10 +2515,11 @@ > __func__, ring->qid, ring->cur, totlen, nsegs); > > /* Fill TX descriptor. */ >- desc->nsegs = WPI_PAD32(totlen) << 4 | (1 + nsegs); >+ desc->nsegs = WPI_PAD32(totlen + pad) << 4 | (1 + nsegs); >+ > /* First DMA segment is used by the TX command. */ > desc->segs[0].addr = htole32(data->cmd_paddr); >- desc->segs[0].len = htole32(4 + buf->size + hdrspace); >+ desc->segs[0].len = htole32(4 + buf->size + hdrlen + pad); > /* Other DMA segments are for data payload. */ > seg = &segs[0]; > for (i = 1; i <= nsegs; i++) { >@@ -2318,13 +2538,29 @@ > ring->cur = (ring->cur + 1) % WPI_TX_RING_COUNT; > wpi_update_tx_ring(sc, ring); > >- /* Mark TX ring as full if we reach a certain threshold. */ >- if (++ring->queued > WPI_TX_RING_HIMARK) >- sc->qfullmsk |= 1 << ring->qid; >+ if (ring->qid < WPI_CMD_QUEUE_NUM) { >+ int diff = WPI_TX_RING_HIMARK - count; > >+ /* Mark TX ring as full if we reach a certain threshold. */ >+ if (atomic_fetchadd_32(&ring->queued, count) > diff) >+ atomic_set_32(&sc->qfullmsk, 1 << ring->qid); >+ >+ atomic_store_rel_32(&sc->sc_tx_timer, 5); >+ } >+ >+ WPI_TXQ_UNLOCK(sc); >+ > DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); > > return 0; >+ >+fail: WPI_TXQ_UNLOCK(sc); >+ >+ m_freem(buf->m); >+ >+ DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END_ERR, __func__); >+ >+ return error; > } > > /* >@@ -2336,19 +2572,18 @@ > const struct ieee80211_txparam *tp; > struct ieee80211vap *vap = ni->ni_vap; > struct ieee80211com *ic = ni->ni_ic; >- struct wpi_node *wn = (void *)ni; >+ struct wpi_node *wn = WPI_NODE(ni); > struct ieee80211_channel *chan; > struct ieee80211_frame *wh; > struct ieee80211_key *k = NULL; >- struct wpi_cmd_data tx; > struct wpi_buf tx_data; >+ struct wpi_cmd_data *tx = (struct wpi_cmd_data *)&tx_data.data; > uint32_t flags; > uint16_t qos; > uint8_t tid, type; >- int ac, error, rate, ismcast, hdrlen, totlen; >+ int ac, error, swcrypt, rate, ismcast, totlen; > > wh = mtod(m, struct ieee80211_frame *); >- hdrlen = ieee80211_anyhdrsize(wh); > type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; > ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); > >@@ -2359,7 +2594,7 @@ > } else { > qos = 0; > tid = 0; >- } >+ } > ac = M_WME_GETAC(m); > > chan = (ni->ni_chan != IEEE80211_CHAN_ANYC) ? >@@ -2389,15 +2624,17 @@ > error = ENOBUFS; > goto fail; > } >+ swcrypt = k->wk_flags & IEEE80211_KEY_SWCRYPT; >+ > /* 802.11 header may have moved. */ > wh = mtod(m, struct ieee80211_frame *); > } >- totlen = m->m_pkthdr.len - (hdrlen & 3); >+ totlen = m->m_pkthdr.len; > > if (ieee80211_radiotap_active_vap(vap)) { > struct wpi_tx_radiotap_header *tap = &sc->sc_txtap; > >- tap->wt_flags = IEEE80211_RADIOTAP_F_DATAPAD; >+ tap->wt_flags = 0; > tap->wt_rate = rate; > if (k != NULL) > tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP; >@@ -2433,7 +2670,7 @@ > flags |= WPI_TX_FULL_TXOP; > } > >- memset(&tx, 0, sizeof (struct wpi_cmd_data)); >+ memset(tx, 0, sizeof (struct wpi_cmd_data)); > if (type == IEEE80211_FC0_TYPE_MGT) { > uint8_t subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; > >@@ -2442,26 +2679,14 @@ > flags |= WPI_TX_INSERT_TSTAMP; > if (subtype == IEEE80211_FC0_SUBTYPE_ASSOC_REQ || > subtype == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) >- tx.timeout = htole16(3); >+ tx->timeout = htole16(3); > else >- tx.timeout = htole16(2); >+ tx->timeout = htole16(2); > } > > if (ismcast || type != IEEE80211_FC0_TYPE_DATA) >- tx.id = WPI_ID_BROADCAST; >+ tx->id = WPI_ID_BROADCAST; > else { >- if (wn->id == WPI_ID_UNDEFINED && >- (vap->iv_opmode == IEEE80211_M_IBSS || >- vap->iv_opmode == IEEE80211_M_AHDEMO)) { >- error = wpi_add_ibss_node(sc, ni); >- if (error != 0) { >- device_printf(sc->sc_dev, >- "%s: could not add IBSS node, error %d\n", >- __func__, error); >- goto fail; >- } >- } >- > if (wn->id == WPI_ID_UNDEFINED) { > device_printf(sc->sc_dev, > "%s: undefined node id\n", __func__); >@@ -2469,36 +2694,41 @@ > goto fail; > } > >- tx.id = wn->id; >+ tx->id = wn->id; > } > > if (type != IEEE80211_FC0_TYPE_MGT) >- tx.data_ntries = tp->maxretry; >+ tx->data_ntries = tp->maxretry; > >- tx.len = htole16(totlen); >- tx.flags = htole32(flags); >- tx.plcp = rate2plcp(rate); >- tx.tid = tid; >- tx.lifetime = htole32(WPI_LIFETIME_INFINITE); >- tx.ofdm_mask = 0xff; >- tx.cck_mask = 0x0f; >- tx.rts_ntries = 7; >+ if (k != NULL && !swcrypt) { >+ switch (k->wk_cipher->ic_cipher) { >+ case IEEE80211_CIPHER_AES_CCM: >+ tx->security = WPI_CIPHER_CCMP; >+ break; > >- if (k != NULL && k->wk_cipher->ic_cipher == IEEE80211_CIPHER_AES_CCM) { >- if (!(k->wk_flags & IEEE80211_KEY_SWCRYPT)) { >- tx.security = WPI_CIPHER_CCMP; >- memcpy(tx.key, k->wk_key, k->wk_keylen); >+ default: >+ break; > } >+ >+ memcpy(tx->key, k->wk_key, k->wk_keylen); > } > >- tx_data.data = &tx; >+ tx->len = htole16(totlen); >+ tx->flags = htole32(flags); >+ tx->plcp = rate2plcp(rate); >+ tx->tid = tid; >+ tx->lifetime = htole32(WPI_LIFETIME_INFINITE); >+ tx->ofdm_mask = 0xff; >+ tx->cck_mask = 0x0f; >+ tx->rts_ntries = 7; >+ > tx_data.ni = ni; > tx_data.m = m; >- tx_data.size = sizeof(tx); >+ tx_data.size = sizeof(struct wpi_cmd_data); > tx_data.code = WPI_CMD_TX_DATA; > tx_data.ac = ac; > >- return wpi_cmd2(sc, &tx_data); >+ return wpi_cmd2(sc, &tx_data, 1); > > fail: m_freem(m); > return error; >@@ -2505,21 +2735,20 @@ > } > > static int >-wpi_tx_data_raw(struct wpi_softc *sc, struct mbuf *m, struct ieee80211_node *ni, >- const struct ieee80211_bpf_params *params) >+wpi_tx_data_raw(struct wpi_softc *sc, struct mbuf *m, >+ struct ieee80211_node *ni, const struct ieee80211_bpf_params *params) > { > struct ieee80211vap *vap = ni->ni_vap; >+ struct ieee80211_key *k = NULL; > struct ieee80211_frame *wh; >- struct wpi_cmd_data tx; > struct wpi_buf tx_data; >+ struct wpi_cmd_data *tx = (struct wpi_cmd_data *)&tx_data.data; > uint32_t flags; > uint8_t type; >- int ac, rate, hdrlen, totlen; >+ int ac, swcrypt, rate, totlen; > > wh = mtod(m, struct ieee80211_frame *); >- hdrlen = ieee80211_anyhdrsize(wh); > type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; >- totlen = m->m_pkthdr.len - (hdrlen & 3); > > ac = params->ibp_pri & 3; > >@@ -2536,18 +2765,33 @@ > if (flags & (WPI_TX_NEED_RTS | WPI_TX_NEED_CTS)) > flags |= WPI_TX_FULL_TXOP; > >+ /* Encrypt the frame if need be. */ >+ if (params->ibp_flags & IEEE80211_BPF_CRYPTO) { >+ /* Retrieve key for TX. */ >+ k = ieee80211_crypto_encap(ni, m); >+ if (k == NULL) { >+ m_freem(m); >+ return ENOBUFS; >+ } >+ swcrypt = k->wk_flags & IEEE80211_KEY_SWCRYPT; >+ >+ /* 802.11 header may have moved. */ >+ wh = mtod(m, struct ieee80211_frame *); >+ } >+ totlen = m->m_pkthdr.len; >+ > if (ieee80211_radiotap_active_vap(vap)) { > struct wpi_tx_radiotap_header *tap = &sc->sc_txtap; > > tap->wt_flags = 0; > tap->wt_rate = rate; >- if (params->ibp_flags & IEEE80211_BPF_DATAPAD) >- tap->wt_flags |= IEEE80211_RADIOTAP_F_DATAPAD; >+ if (params->ibp_flags & IEEE80211_BPF_CRYPTO) >+ tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP; > > ieee80211_radiotap_tx(vap, m); > } > >- memset(&tx, 0, sizeof (struct wpi_cmd_data)); >+ memset(tx, 0, sizeof (struct wpi_cmd_data)); > if (type == IEEE80211_FC0_TYPE_MGT) { > uint8_t subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; > >@@ -2556,27 +2800,39 @@ > flags |= WPI_TX_INSERT_TSTAMP; > if (subtype == IEEE80211_FC0_SUBTYPE_ASSOC_REQ || > subtype == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) >- tx.timeout = htole16(3); >+ tx->timeout = htole16(3); > else >- tx.timeout = htole16(2); >+ tx->timeout = htole16(2); > } > >- tx.len = htole16(totlen); >- tx.flags = htole32(flags); >- tx.plcp = rate2plcp(rate); >- tx.id = WPI_ID_BROADCAST; >- tx.lifetime = htole32(WPI_LIFETIME_INFINITE); >- tx.rts_ntries = params->ibp_try1; >- tx.data_ntries = params->ibp_try0; >+ if (k != NULL && !swcrypt) { >+ switch (k->wk_cipher->ic_cipher) { >+ case IEEE80211_CIPHER_AES_CCM: >+ tx->security = WPI_CIPHER_CCMP; >+ break; > >- tx_data.data = &tx; >+ default: >+ break; >+ } >+ >+ memcpy(tx->key, k->wk_key, k->wk_keylen); >+ } >+ >+ tx->len = htole16(totlen); >+ tx->flags = htole32(flags); >+ tx->plcp = rate2plcp(rate); >+ tx->id = WPI_ID_BROADCAST; >+ tx->lifetime = htole32(WPI_LIFETIME_INFINITE); >+ tx->rts_ntries = params->ibp_try1; >+ tx->data_ntries = params->ibp_try0; >+ > tx_data.ni = ni; > tx_data.m = m; >- tx_data.size = sizeof(tx); >+ tx_data.size = sizeof(struct wpi_cmd_data); > tx_data.code = WPI_CMD_TX_DATA; > tx_data.ac = ac; > >- return wpi_cmd2(sc, &tx_data); >+ return wpi_cmd2(sc, &tx_data, 1); > } > > static int >@@ -2596,7 +2852,7 @@ > return ENETDOWN; > } > >- WPI_LOCK(sc); >+ WPI_TX_LOCK(sc); > if (params == NULL) { > /* > * Legacy path; interpret frame contents to decide >@@ -2610,7 +2866,7 @@ > */ > error = wpi_tx_data_raw(sc, m, ni, params); > } >- WPI_UNLOCK(sc); >+ WPI_TX_UNLOCK(sc); > > if (error != 0) { > /* NB: m is reclaimed on tx failure */ >@@ -2622,8 +2878,6 @@ > return error; > } > >- sc->sc_tx_timer = 5; >- > DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); > > return 0; >@@ -2636,30 +2890,25 @@ > wpi_start(struct ifnet *ifp) > { > struct wpi_softc *sc = ifp->if_softc; >- >- WPI_LOCK(sc); >- wpi_start_locked(ifp); >- WPI_UNLOCK(sc); >-} >- >-static void >-wpi_start_locked(struct ifnet *ifp) >-{ >- struct wpi_softc *sc = ifp->if_softc; > struct ieee80211_node *ni; > struct mbuf *m; > >- WPI_LOCK_ASSERT(sc); >- > DPRINTF(sc, WPI_DEBUG_XMIT, "%s: called\n", __func__); > >+ IF_LOCK(&ifp->if_snd); > if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || >- (ifp->if_drv_flags & IFF_DRV_OACTIVE)) >+ (ifp->if_drv_flags & IFF_DRV_OACTIVE)) { >+ IF_UNLOCK(&ifp->if_snd); > return; >+ } >+ IF_UNLOCK(&ifp->if_snd); > >+ WPI_TX_LOCK(sc); > for (;;) { >- if (sc->qfullmsk != 0) { >+ if (atomic_load_acq_32(&sc->qfullmsk) != 0) { >+ IF_LOCK(&ifp->if_snd); > ifp->if_drv_flags |= IFF_DRV_OACTIVE; >+ IF_UNLOCK(&ifp->if_snd); > break; > } > IFQ_DRV_DEQUEUE(&ifp->if_snd, m); >@@ -2667,18 +2916,25 @@ > break; > ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; > if (wpi_tx_data(sc, m, ni) != 0) { >- WPI_UNLOCK(sc); > ieee80211_free_node(ni); >- WPI_LOCK(sc); > if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); >- } else >- sc->sc_tx_timer = 5; >+ } > } >+ WPI_TX_UNLOCK(sc); > > DPRINTF(sc, WPI_DEBUG_XMIT, "%s: done\n", __func__); > } > > static void >+wpi_start_task(void *arg0, int pending) >+{ >+ struct wpi_softc *sc = arg0; >+ struct ifnet *ifp = sc->sc_ifp; >+ >+ wpi_start(ifp); >+} >+ >+static void > wpi_watchdog_rfkill(void *arg) > { > struct wpi_softc *sc = arg; >@@ -2706,11 +2962,15 @@ > struct wpi_softc *sc = arg; > struct ifnet *ifp = sc->sc_ifp; > struct ieee80211com *ic = ifp->if_l2com; >+ int32_t tmp; > > DPRINTF(sc, WPI_DEBUG_WATCHDOG, "Watchdog: tick\n"); > >- if (sc->sc_tx_timer > 0) { >- if (--sc->sc_tx_timer == 0) { >+ tmp = atomic_load_acq_32(&sc->sc_tx_timer); >+ if (tmp > 0) { >+ tmp -= 1; >+ atomic_cmpset_rel_32(&sc->sc_tx_timer, tmp + 1, tmp); >+ if (tmp == 0) { > if_printf(ifp, "device timeout\n"); > if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); > ieee80211_runtask(ic, &sc->sc_reinittask); >@@ -2717,9 +2977,12 @@ > } > } > >- if (sc->sc_scan_timer > 0) { >+ tmp = atomic_load_acq_32(&sc->sc_scan_timer); >+ if (tmp > 0) { > struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); >- if (--sc->sc_scan_timer == 0 && vap != NULL) { >+ tmp -= 1; >+ atomic_cmpset_rel_32(&sc->sc_scan_timer, tmp + 1, tmp); >+ if (tmp == 0 && vap != NULL) { > if_printf(ifp, "scan timeout\n"); > ieee80211_cancel_scan(vap); > ieee80211_runtask(ic, &sc->sc_reinittask); >@@ -2726,7 +2989,7 @@ > } > } > >- if (ifp->if_drv_flags & IFF_DRV_RUNNING) >+ if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) > callout_reset(&sc->watchdog_to, hz, wpi_watchdog, sc); > } > >@@ -2737,7 +3000,7 @@ > struct ieee80211com *ic = ifp->if_l2com; > struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); > struct ifreq *ifr = (struct ifreq *) data; >- int error = 0, startall = 0, stop = 0; >+ int error = 0; > > switch (cmd) { > case SIOCGIFADDR: >@@ -2744,23 +3007,14 @@ > error = ether_ioctl(ifp, cmd, data); > break; > case SIOCSIFFLAGS: >- WPI_LOCK(sc); > if (ifp->if_flags & IFF_UP) { >- if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { >- wpi_init_locked(sc); >- if (WPI_READ(sc, WPI_GP_CNTRL) & >- WPI_GP_CNTRL_RFKILL) >- startall = 1; >- else >- stop = 1; >- } >- } else if (ifp->if_drv_flags & IFF_DRV_RUNNING) >- wpi_stop_locked(sc); >- WPI_UNLOCK(sc); >- if (startall) >- ieee80211_start_all(ic); >- else if (vap != NULL && stop) >- ieee80211_stop(vap); >+ wpi_init(sc); >+ >+ if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 && >+ vap != NULL) >+ ieee80211_stop(vap); >+ } else if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) >+ wpi_stop(sc); > break; > case SIOCGIFMEDIA: > error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd); >@@ -2779,7 +3033,7 @@ > wpi_cmd(struct wpi_softc *sc, int code, const void *buf, size_t size, > int async) > { >- struct wpi_tx_ring *ring = &sc->txq[4]; >+ struct wpi_tx_ring *ring = &sc->txq[WPI_CMD_QUEUE_NUM]; > struct wpi_tx_desc *desc; > struct wpi_tx_data *data; > struct wpi_tx_cmd *cmd; >@@ -2787,21 +3041,18 @@ > bus_addr_t paddr; > int totlen, error; > >+ WPI_TXQ_LOCK(sc); >+ > DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); > >- if (async == 0) >- WPI_LOCK_ASSERT(sc); >+ if (atomic_load_acq_32(&sc->txq_active) == 0) { >+ error = 0; >+ goto fail; >+ } > >- DPRINTF(sc, WPI_DEBUG_CMD, "wpi_cmd %s size %zu async %d\n", >- wpi_cmd_str(code), size, async); >+ DPRINTF(sc, WPI_DEBUG_CMD, "%s: cmd %s size %zu async %d\n", >+ __func__, wpi_cmd_str(code), size, async); > >- if (sc->flags & WPI_FLAG_BUSY) { >- device_printf(sc->sc_dev, "%s: cmd %d not sent, busy\n", >- __func__, code); >- return EAGAIN; >- } >- sc->flags |= WPI_FLAG_BUSY; >- > desc = &ring->desc[ring->cur]; > data = &ring->data[ring->cur]; > totlen = 4 + size; >@@ -2808,17 +3059,21 @@ > > if (size > sizeof cmd->data) { > /* Command is too large to fit in a descriptor. */ >- if (totlen > MCLBYTES) >- return EINVAL; >+ if (totlen > MCLBYTES) { >+ error = EINVAL; >+ goto fail; >+ } > m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUMPAGESIZE); >- if (m == NULL) >- return ENOMEM; >+ if (m == NULL) { >+ error = ENOMEM; >+ goto fail; >+ } > cmd = mtod(m, struct wpi_tx_cmd *); > error = bus_dmamap_load(ring->data_dmat, data->map, cmd, > totlen, wpi_dma_map_addr, &paddr, BUS_DMA_NOWAIT); > if (error != 0) { > m_freem(m); >- return error; >+ goto fail; > } > data->m = m; > } else { >@@ -2850,14 +3105,20 @@ > ring->cur = (ring->cur + 1) % WPI_TX_RING_COUNT; > wpi_update_tx_ring(sc, ring); > >+ WPI_TXQ_UNLOCK(sc); >+ > DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); > >- if (async) { >- sc->flags &= ~WPI_FLAG_BUSY; >+ if (async) > return 0; >- } > >- return msleep(cmd, &sc->sc_mtx, PCATCH, "wpicmd", hz); >+ return mtx_sleep(cmd, &sc->sc_mtx, PCATCH, "wpicmd", hz); >+ >+fail: WPI_TXQ_UNLOCK(sc); >+ >+ DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END_ERR, __func__); >+ >+ return error; > } > > /* >@@ -2917,8 +3178,11 @@ > wpi_add_node(struct wpi_softc *sc, struct ieee80211_node *ni) > { > struct ieee80211com *ic = ni->ni_ic; >- struct wpi_node *wn = (void *)ni; >+ struct ieee80211vap *vap = ni->ni_vap; >+ struct wpi_vap *wvp = WPI_VAP(vap); >+ struct wpi_node *wn = WPI_NODE(ni); > struct wpi_node_info node; >+ int error; > > DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); > >@@ -2926,7 +3190,7 @@ > return EINVAL; > > memset(&node, 0, sizeof node); >- IEEE80211_ADDR_COPY(node.macaddr, ni->ni_bssid); >+ IEEE80211_ADDR_COPY(node.macaddr, ni->ni_macaddr); > node.id = wn->id; > node.plcp = (ic->ic_curmode == IEEE80211_MODE_11A) ? > wpi_ridx_to_plcp[WPI_RIDX_OFDM6] : wpi_ridx_to_plcp[WPI_RIDX_CCK1]; >@@ -2933,7 +3197,27 @@ > node.action = htole32(WPI_ACTION_SET_RATE); > node.antenna = WPI_ANTENNA_BOTH; > >- return wpi_cmd(sc, WPI_CMD_ADD_NODE, &node, sizeof node, 1); >+ DPRINTF(sc, WPI_DEBUG_NODE, "%s: adding node %d (%s)\n", __func__, >+ wn->id, ether_sprintf(ni->ni_macaddr)); >+ >+ error = wpi_cmd(sc, WPI_CMD_ADD_NODE, &node, sizeof node, 1); >+ if (error != 0) { >+ device_printf(sc->sc_dev, >+ "%s: wpi_cmd() call failed with error code %d\n", __func__, >+ error); >+ return error; >+ } >+ >+ if (atomic_load_acq_32(&wvp->wv_gtk) != 0) { >+ error = wpi_set_global_keys(ni); >+ if (error != 0) { >+ device_printf(sc->sc_dev, >+ "%s: error while setting global keys\n", __func__); >+ return ENXIO; >+ } >+ } >+ >+ return 0; > } > > /* >@@ -2956,13 +3240,35 @@ > node.action = htole32(WPI_ACTION_SET_RATE); > node.antenna = WPI_ANTENNA_BOTH; > >+ DPRINTF(sc, WPI_DEBUG_NODE, "%s: adding broadcast node\n", __func__); >+ > return wpi_cmd(sc, WPI_CMD_ADD_NODE, &node, sizeof node, async); > } > > static int >+wpi_add_sta_node(struct wpi_softc *sc, struct ieee80211_node *ni) >+{ >+ struct wpi_node *wn = WPI_NODE(ni); >+ int error; >+ >+ DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); >+ >+ wn->id = wpi_add_node_entry_sta(sc); >+ >+ if ((error = wpi_add_node(sc, ni)) != 0) { >+ wpi_del_node_entry(sc, wn->id); >+ wn->id = WPI_ID_UNDEFINED; >+ return error; >+ } >+ >+ return 0; >+} >+ >+static int > wpi_add_ibss_node(struct wpi_softc *sc, struct ieee80211_node *ni) > { >- struct wpi_node *wn = (void *)ni; >+ struct wpi_node *wn = WPI_NODE(ni); >+ int error; > > DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); > >@@ -2969,33 +3275,38 @@ > if (wn->id != WPI_ID_UNDEFINED) > return EINVAL; > >- wn->id = alloc_unrl(sc->sc_unr); >+ if ((wn->id = wpi_add_node_entry_adhoc(sc)) == WPI_ID_UNDEFINED) { >+ device_printf(sc->sc_dev, "%s: h/w table is full\n", __func__); >+ return ENOMEM; >+ } > >- if (wn->id == (uint8_t)-1) >- return ENOBUFS; >+ if ((error = wpi_add_node(sc, ni)) != 0) { >+ wpi_del_node_entry(sc, wn->id); >+ wn->id = WPI_ID_UNDEFINED; >+ return error; >+ } > >- return wpi_add_node(sc, ni); >+ return 0; > } > > static void > wpi_del_node(struct wpi_softc *sc, struct ieee80211_node *ni) > { >- struct wpi_node *wn = (void *)ni; >+ struct wpi_node *wn = WPI_NODE(ni); > struct wpi_cmd_del_node node; > int error; > >+ KASSERT(wn->id != WPI_ID_UNDEFINED, ("undefined node id passed")); >+ > DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); > >- if (wn->id == WPI_ID_UNDEFINED) { >- device_printf(sc->sc_dev, "%s: undefined node id passed\n", >- __func__); >- return; >- } >- > memset(&node, 0, sizeof node); >- IEEE80211_ADDR_COPY(node.macaddr, ni->ni_bssid); >+ IEEE80211_ADDR_COPY(node.macaddr, ni->ni_macaddr); > node.count = 1; > >+ DPRINTF(sc, WPI_DEBUG_NODE, "%s: deleting node %d (%s)\n", __func__, >+ wn->id, ether_sprintf(ni->ni_macaddr)); >+ > error = wpi_cmd(sc, WPI_CMD_DEL_NODE, &node, sizeof node, 1); > if (error != 0) { > device_printf(sc->sc_dev, >@@ -3031,11 +3342,7 @@ > cmd.ac[aci].cwmin, cmd.ac[aci].cwmax, > cmd.ac[aci].txoplimit); > } >- IEEE80211_UNLOCK(ic); >- WPI_LOCK(sc); > error = wpi_cmd(sc, WPI_CMD_EDCA_PARAMS, &cmd, sizeof cmd, 1); >- WPI_UNLOCK(sc); >- IEEE80211_LOCK(ic); > > DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); > >@@ -3047,9 +3354,13 @@ > wpi_set_promisc(struct wpi_softc *sc) > { > struct ifnet *ifp = sc->sc_ifp; >+ struct ieee80211com *ic = ifp->if_l2com; >+ struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); > uint32_t promisc_filter; > >- promisc_filter = WPI_FILTER_PROMISC | WPI_FILTER_CTL; >+ promisc_filter = WPI_FILTER_CTL; >+ if (vap != NULL && vap->iv_opmode != IEEE80211_M_HOSTAP) >+ promisc_filter |= WPI_FILTER_PROMISC; > > if (ifp->if_flags & IFF_PROMISC) > sc->rxon.filter |= htole32(promisc_filter); >@@ -3062,14 +3373,14 @@ > { > struct wpi_softc *sc = ifp->if_softc; > >+ WPI_RXON_LOCK(sc); > wpi_set_promisc(sc); > >- WPI_LOCK(sc); > if (wpi_send_rxon(sc, 1, 1) != 0) { > device_printf(sc->sc_dev, "%s: could not send RXON\n", > __func__); > } >- WPI_UNLOCK(sc); >+ WPI_RXON_UNLOCK(sc); > } > > static void >@@ -3159,8 +3470,7 @@ > static int > wpi_set_txpower(struct wpi_softc *sc, int async) > { >- struct ifnet *ifp = sc->sc_ifp; >- struct ieee80211com *ic = ifp->if_l2com; >+ struct ieee80211com *ic = sc->sc_ifp->if_l2com; > struct ieee80211_channel *ch; > struct wpi_power_group *group; > struct wpi_cmd_txpower cmd; >@@ -3214,15 +3524,14 @@ > struct ieee80211_channel *c, int ridx) > { > /* Fixed-point arithmetic division using a n-bit fractional part. */ >-#define fdivround(a, b, n) \ >+#define fdivround(a, b, n) \ > ((((1 << n) * (a)) / (b) + (1 << n) / 2) / (1 << n)) > > /* Linear interpolation. */ >-#define interpolate(x, x1, y1, x2, y2, n) \ >+#define interpolate(x, x1, y1, x2, y2, n) \ > ((y1) + fdivround(((x) - (x1)) * ((y2) - (y1)), (x2) - (x1), n)) > >- struct ifnet *ifp = sc->sc_ifp; >- struct ieee80211com *ic = ifp->if_l2com; >+ struct ieee80211com *ic = sc->sc_ifp->if_l2com; > struct wpi_power_sample *sample; > int pwr, idx; > u_int chan; >@@ -3335,18 +3644,18 @@ > return wpi_cmd(sc, WPI_CMD_SET_POWER_MODE, &cmd, sizeof cmd, async); > } > >-static int >+static int > wpi_send_btcoex(struct wpi_softc *sc) > { > struct wpi_bluetooth cmd; > >- memset(&cmd, 0, sizeof cmd); >- cmd.flags = WPI_BT_COEX_MODE_4WIRE; >- cmd.lead_time = WPI_BT_LEAD_TIME_DEF; >- cmd.max_kill = WPI_BT_MAX_KILL_DEF; >+ memset(&cmd, 0, sizeof cmd); >+ cmd.flags = WPI_BT_COEX_MODE_4WIRE; >+ cmd.lead_time = WPI_BT_LEAD_TIME_DEF; >+ cmd.max_kill = WPI_BT_MAX_KILL_DEF; > DPRINTF(sc, WPI_DEBUG_RESET, "%s: configuring bluetooth coexistence\n", > __func__); >- return wpi_cmd(sc, WPI_CMD_BT_COEX, &cmd, sizeof(cmd), 0); >+ return wpi_cmd(sc, WPI_CMD_BT_COEX, &cmd, sizeof(cmd), 0); > } > > static int >@@ -3354,6 +3663,9 @@ > { > int error; > >+ if (async) >+ WPI_RXON_LOCK_ASSERT(sc); >+ > if (assoc && (sc->rxon.filter & htole32(WPI_FILTER_BSS))) { > struct wpi_assoc rxon_assoc; > >@@ -3365,24 +3677,28 @@ > > error = wpi_cmd(sc, WPI_CMD_RXON_ASSOC, &rxon_assoc, > sizeof (struct wpi_assoc), async); >+ if (error != 0) { >+ device_printf(sc->sc_dev, >+ "RXON_ASSOC command failed, error %d\n", error); >+ return error; >+ } > } else { >+ if (async) >+ WPI_NT_LOCK(sc); >+ > error = wpi_cmd(sc, WPI_CMD_RXON, &sc->rxon, > sizeof (struct wpi_rxon), async); >- } >- if (error != 0) { >- device_printf(sc->sc_dev, "RXON command failed, error %d\n", >- error); >- return error; >- } >+ if (error != 0) { >+ device_printf(sc->sc_dev, >+ "RXON command failed, error %d\n", error); >+ return error; >+ } > >- /* Configuration has changed, set Tx power accordingly. */ >- if ((error = wpi_set_txpower(sc, async)) != 0) { >- device_printf(sc->sc_dev, >- "%s: could not set TX power, error %d\n", __func__, error); >- return error; >- } >+ wpi_clear_node_table(sc); > >- if (!(sc->rxon.filter & htole32(WPI_FILTER_BSS))) { >+ if (async) >+ WPI_NT_UNLOCK(sc); >+ > /* Add broadcast node. */ > error = wpi_add_broadcast_node(sc, async); > if (error != 0) { >@@ -3392,6 +3708,13 @@ > } > } > >+ /* Configuration has changed, set Tx power accordingly. */ >+ if ((error = wpi_set_txpower(sc, async)) != 0) { >+ device_printf(sc->sc_dev, >+ "%s: could not set TX power, error %d\n", __func__, error); >+ return error; >+ } >+ > return 0; > } > >@@ -3404,6 +3727,7 @@ > { > struct ifnet *ifp = sc->sc_ifp; > struct ieee80211com *ic = ifp->if_l2com; >+ struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); > uint32_t flags; > int error; > >@@ -3425,7 +3749,7 @@ > > /* Configure adapter. */ > memset(&sc->rxon, 0, sizeof (struct wpi_rxon)); >- IEEE80211_ADDR_COPY(sc->rxon.myaddr, IF_LLADDR(ifp)); >+ IEEE80211_ADDR_COPY(sc->rxon.myaddr, vap->iv_myaddr); > > /* Set default channel. */ > sc->rxon.chan = ieee80211_chan2ieee(ic, ic->ic_curchan); >@@ -3442,9 +3766,13 @@ > sc->rxon.mode = WPI_MODE_IBSS; > sc->rxon.filter |= WPI_FILTER_BEACON; > break; >- /* XXX workaround for passive channels selection */ >+ case IEEE80211_M_HOSTAP: >+ /* XXX workaround for beaconing */ >+ sc->rxon.mode = WPI_MODE_IBSS; >+ sc->rxon.filter |= WPI_FILTER_ASSOC | WPI_FILTER_PROMISC; >+ break; > case IEEE80211_M_AHDEMO: >- case IEEE80211_M_HOSTAP: >+ /* XXX workaround for passive channels selection */ > sc->rxon.mode = WPI_MODE_HOSTAP; > break; > case IEEE80211_M_MONITOR: >@@ -3451,7 +3779,8 @@ > sc->rxon.mode = WPI_MODE_MONITOR; > break; > default: >- device_printf(sc->sc_dev, "unknown opmode %d\n", ic->ic_opmode); >+ device_printf(sc->sc_dev, "unknown opmode %d\n", >+ ic->ic_opmode); > return EINVAL; > } > sc->rxon.filter = htole32(sc->rxon.filter); >@@ -3510,14 +3839,12 @@ > wpi_limit_dwell(struct wpi_softc *sc, uint16_t dwell_time) > { > struct ieee80211com *ic = sc->sc_ifp->if_l2com; >- struct ieee80211vap *vap = NULL; >+ struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); > int bintval = 0; > > /* bintval is in TU (1.024mS) */ >- if (! TAILQ_EMPTY(&ic->ic_vaps)) { >- vap = TAILQ_FIRST(&ic->ic_vaps); >+ if (vap != NULL) > bintval = vap->iv_bss->ni_intval; >- } > > /* > * If it's non-zero, we should calculate the minimum of >@@ -3559,6 +3886,7 @@ > struct ifnet *ifp = sc->sc_ifp; > struct ieee80211com *ic = ifp->if_l2com; > struct ieee80211_scan_state *ss = ic->ic_scan; >+ struct ieee80211vap *vap = ss->ss_vap; > struct wpi_scan_hdr *hdr; > struct wpi_cmd_data *tx; > struct wpi_scan_essid *essids; >@@ -3575,9 +3903,12 @@ > * We are absolutely not allowed to send a scan command when another > * scan command is pending. > */ >- if (sc->sc_scan_timer) { >+ if (atomic_cmpset_acq_32(&sc->sc_scan_timer, 0, 5) == 0) { > device_printf(sc->sc_dev, "%s: called whilst scanning!\n", > __func__); >+ >+ DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END_ERR, __func__); >+ > return (EAGAIN); > } > >@@ -3586,7 +3917,8 @@ > device_printf(sc->sc_dev, > "%s: could not allocate buffer for scan command\n", > __func__); >- return ENOMEM; >+ error = ENOMEM; >+ goto fail; > } > hdr = (struct wpi_scan_hdr *)buf; > >@@ -3645,7 +3977,7 @@ > IEEE80211_FC0_SUBTYPE_PROBE_REQ; > wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; > IEEE80211_ADDR_COPY(wh->i_addr1, ifp->if_broadcastaddr); >- IEEE80211_ADDR_COPY(wh->i_addr2, IF_LLADDR(ifp)); >+ IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); > IEEE80211_ADDR_COPY(wh->i_addr3, ifp->if_broadcastaddr); > *(uint16_t *)&wh->i_dur[0] = 0; /* filled by h/w */ > *(uint16_t *)&wh->i_seq[0] = 0; /* filled by h/w */ >@@ -3698,7 +4030,7 @@ > chan->rf_gain = 0x28; > > DPRINTF(sc, WPI_DEBUG_SCAN, "Scanning %u Passive: %d\n", >- chan->chan, IEEE80211_IS_CHAN_PASSIVE(c)); >+ chan->chan, IEEE80211_IS_CHAN_PASSIVE(c)); > > hdr->nchan++; > chan++; >@@ -3711,10 +4043,17 @@ > error = wpi_cmd(sc, WPI_CMD_SCAN, buf, buflen, 1); > free(buf, M_DEVBUF); > >- sc->sc_scan_timer = 5; >+ if (error != 0) >+ goto fail; > > DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); > >+ return 0; >+ >+fail: atomic_store_rel_32(&sc->sc_scan_timer, 0); >+ >+ DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END_ERR, __func__); >+ > return error; > } > >@@ -3728,6 +4067,7 @@ > DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); > > /* Update adapter configuration. */ >+ WPI_RXON_LOCK(sc); > sc->rxon.associd = 0; > sc->rxon.filter &= ~htole32(WPI_FILTER_BSS); > IEEE80211_ADDR_COPY(sc->rxon.bssid, ni->ni_bssid); >@@ -3759,6 +4099,7 @@ > device_printf(sc->sc_dev, "%s: could not send RXON\n", > __func__); > } >+ WPI_RXON_UNLOCK(sc); > > DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); > >@@ -3766,17 +4107,65 @@ > } > > static int >+wpi_config_beacon(struct wpi_vap *wvp) >+{ >+ struct ieee80211com *ic = wvp->wv_vap.iv_ic; >+ struct ieee80211_beacon_offsets *bo = &wvp->wv_boff; >+ struct wpi_buf *bcn = &wvp->wv_bcbuf; >+ struct wpi_softc *sc = ic->ic_ifp->if_softc; >+ struct wpi_cmd_beacon *cmd = (struct wpi_cmd_beacon *)&bcn->data; >+ struct ieee80211_tim_ie *tie; >+ struct mbuf *m; >+ uint8_t *ptr; >+ int error; >+ >+ DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); >+ >+ WPI_VAP_LOCK_ASSERT(wvp); >+ >+ cmd->len = htole16(bcn->m->m_pkthdr.len); >+ cmd->plcp = (ic->ic_curmode == IEEE80211_MODE_11A) ? >+ wpi_ridx_to_plcp[WPI_RIDX_OFDM6] : wpi_ridx_to_plcp[WPI_RIDX_CCK1]; >+ >+ /* XXX seems to be unused */ >+ if (*(bo->bo_tim) == IEEE80211_ELEMID_TIM) { >+ tie = (struct ieee80211_tim_ie *) bo->bo_tim; >+ ptr = mtod(bcn->m, uint8_t *); >+ >+ cmd->tim = htole16(bo->bo_tim - ptr); >+ cmd->timsz = tie->tim_len; >+ } >+ >+ /* Necessary for recursion in ieee80211_beacon_update(). */ >+ m = bcn->m; >+ bcn->m = m_dup(m, M_NOWAIT); >+ if (bcn->m == NULL) { >+ device_printf(sc->sc_dev, >+ "%s: could not copy beacon frame\n", __func__); >+ error = ENOMEM; >+ goto end; >+ } >+ >+ if ((error = wpi_cmd2(sc, bcn, 1)) != 0) { >+ device_printf(sc->sc_dev, >+ "%s: could not update beacon frame, error %d", __func__, >+ error); >+ } >+ >+ /* Restore mbuf. */ >+end: bcn->m = m; >+ >+ return error; >+} >+ >+static int > wpi_setup_beacon(struct wpi_softc *sc, struct ieee80211_node *ni) > { >- struct ifnet *ifp = sc->sc_ifp; >- struct ieee80211com *ic = ifp->if_l2com; >- struct ieee80211vap *vap = ni->ni_vap; >- struct wpi_vap *wvp = WPI_VAP(vap); >+ struct wpi_vap *wvp = WPI_VAP(ni->ni_vap); > struct wpi_buf *bcn = &wvp->wv_bcbuf; >- struct ieee80211_beacon_offsets bo; >- struct wpi_cmd_beacon *cmd; >+ struct ieee80211_beacon_offsets *bo = &wvp->wv_boff; > struct mbuf *m; >- int totlen; >+ int error; > > DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); > >@@ -3783,64 +4172,86 @@ > if (ni->ni_chan == IEEE80211_CHAN_ANYC) > return EINVAL; > >- m = ieee80211_beacon_alloc(ni, &bo); >+ m = ieee80211_beacon_alloc(ni, bo); > if (m == NULL) { > device_printf(sc->sc_dev, > "%s: could not allocate beacon frame\n", __func__); > return ENOMEM; > } >- totlen = m->m_pkthdr.len; > >- if (bcn->data == NULL) { >- cmd = malloc(sizeof(struct wpi_cmd_beacon), M_DEVBUF, >- M_NOWAIT | M_ZERO); >+ WPI_VAP_LOCK(wvp); >+ if (bcn->m != NULL) >+ m_freem(bcn->m); > >- if (cmd == NULL) { >+ bcn->m = m; >+ >+ error = wpi_config_beacon(wvp); >+ WPI_VAP_UNLOCK(wvp); >+ >+ return error; >+} >+ >+static void >+wpi_update_beacon(struct ieee80211vap *vap, int item) >+{ >+ struct wpi_softc *sc = vap->iv_ic->ic_ifp->if_softc; >+ struct wpi_vap *wvp = WPI_VAP(vap); >+ struct wpi_buf *bcn = &wvp->wv_bcbuf; >+ struct ieee80211_beacon_offsets *bo = &wvp->wv_boff; >+ struct ieee80211_node *ni = vap->iv_bss; >+ int mcast = 0; >+ >+ DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); >+ >+ WPI_VAP_LOCK(wvp); >+ if (bcn->m == NULL) { >+ bcn->m = ieee80211_beacon_alloc(ni, bo); >+ if (bcn->m == NULL) { > device_printf(sc->sc_dev, >- "could not allocate buffer for beacon command\n"); >- m_freem(m); >- return ENOMEM; >+ "%s: could not allocate beacon frame\n", __func__); >+ WPI_VAP_UNLOCK(wvp); >+ >+ DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END_ERR, >+ __func__); >+ >+ return; > } >+ } >+ WPI_VAP_UNLOCK(wvp); > >- cmd->id = WPI_ID_BROADCAST; >- cmd->ofdm_mask = 0xff; >- cmd->cck_mask = 0x0f; >- cmd->lifetime = htole32(WPI_LIFETIME_INFINITE); >- cmd->flags = htole32(WPI_TX_AUTO_SEQ | WPI_TX_INSERT_TSTAMP); >+ if (item == IEEE80211_BEACON_TIM) >+ mcast = 1; /* TODO */ > >- bcn->data = cmd; >- bcn->ni = NULL; >- bcn->code = WPI_CMD_SET_BEACON; >- bcn->ac = 4; >- bcn->size = sizeof(struct wpi_cmd_beacon); >- } else >- cmd = bcn->data; >+ setbit(bo->bo_flags, item); >+ ieee80211_beacon_update(ni, bo, bcn->m, mcast); > >- cmd->len = htole16(totlen); >- cmd->plcp = (ic->ic_curmode == IEEE80211_MODE_11A) ? >- wpi_ridx_to_plcp[WPI_RIDX_OFDM6] : wpi_ridx_to_plcp[WPI_RIDX_CCK1]; >+ WPI_VAP_LOCK(wvp); >+ wpi_config_beacon(wvp); >+ WPI_VAP_UNLOCK(wvp); > >- /* NB: m will be freed in wpi_cmd_done() */ >- bcn->m = m; >- >- return wpi_cmd2(sc, bcn); >+ DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); > } > > static void >-wpi_update_beacon(struct ieee80211vap *vap, int item) >+wpi_newassoc(struct ieee80211_node *ni, int isnew) > { >- struct ieee80211_node *ni = vap->iv_bss; >- struct ifnet *ifp = vap->iv_ifp; >- struct wpi_softc *sc = ifp->if_softc; >+ struct ieee80211vap *vap = ni->ni_vap; >+ struct wpi_softc *sc = ni->ni_ic->ic_ifp->if_softc; >+ struct wpi_node *wn = WPI_NODE(ni); > int error; > >- WPI_LOCK(sc); >- if ((error = wpi_setup_beacon(sc, ni)) != 0) { >- device_printf(sc->sc_dev, >- "%s: could not update beacon frame, error %d", __func__, >- error); >+ WPI_NT_LOCK(sc); >+ >+ DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); >+ >+ if (vap->iv_opmode != IEEE80211_M_STA && wn->id == WPI_ID_UNDEFINED) { >+ if ((error = wpi_add_ibss_node(sc, ni)) != 0) { >+ device_printf(sc->sc_dev, >+ "%s: could not add IBSS node, error %d\n", >+ __func__, error); >+ } > } >- WPI_UNLOCK(sc); >+ WPI_NT_UNLOCK(sc); > } > > static int >@@ -3872,6 +4283,7 @@ > } > > /* Update adapter configuration. */ >+ WPI_RXON_LOCK(sc); > IEEE80211_ADDR_COPY(sc->rxon.bssid, ni->ni_bssid); > sc->rxon.associd = htole16(IEEE80211_NODE_AID(ni)); > sc->rxon.chan = ieee80211_chan2ieee(ic, ni->ni_chan); >@@ -3897,8 +4309,6 @@ > } > sc->rxon.filter |= htole32(WPI_FILTER_BSS); > >- /* XXX put somewhere HC_QOS_SUPPORT_ASSOC + HC_IBSS_START */ >- > DPRINTF(sc, WPI_DEBUG_STATE, "rxon chan %d flags %x\n", > sc->rxon.chan, sc->rxon.flags); > >@@ -3908,7 +4318,13 @@ > return error; > } > >- if (vap->iv_opmode == IEEE80211_M_IBSS) { >+ /* Start periodic calibration timer. */ >+ callout_reset(&sc->calib_to, 60*hz, wpi_calib_timeout, sc); >+ >+ WPI_RXON_UNLOCK(sc); >+ >+ if (vap->iv_opmode == IEEE80211_M_IBSS || >+ vap->iv_opmode == IEEE80211_M_HOSTAP) { > if ((error = wpi_setup_beacon(sc, ni)) != 0) { > device_printf(sc->sc_dev, > "%s: could not setup beacon, error %d\n", __func__, >@@ -3919,8 +4335,10 @@ > > if (vap->iv_opmode == IEEE80211_M_STA) { > /* Add BSS node. */ >- ((struct wpi_node *)ni)->id = WPI_ID_BSS; >- if ((error = wpi_add_node(sc, ni)) != 0) { >+ WPI_NT_LOCK(sc); >+ error = wpi_add_sta_node(sc, ni); >+ WPI_NT_UNLOCK(sc); >+ if (error != 0) { > device_printf(sc->sc_dev, > "%s: could not add BSS node, error %d\n", __func__, > error); >@@ -3931,11 +4349,9 @@ > /* Link LED always on while associated. */ > wpi_set_led(sc, WPI_LED_LINK, 0, 1); > >- /* Start periodic calibration timer. */ >- callout_reset(&sc->calib_to, 60*hz, wpi_calib_timeout, sc); >- > /* Enable power-saving mode if requested by user. */ >- if (vap->iv_flags & IEEE80211_F_PMGTON) >+ if ((vap->iv_flags & IEEE80211_F_PMGTON) && >+ vap->iv_opmode != IEEE80211_M_IBSS) > (void)wpi_set_pslevel(sc, 0, 3, 1); > else > (void)wpi_set_pslevel(sc, 0, 0, 1); >@@ -3946,39 +4362,12 @@ > } > > static int >-wpi_key_alloc(struct ieee80211vap *vap, struct ieee80211_key *k, >- ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix) >+wpi_load_key(struct ieee80211_node *ni, const struct ieee80211_key *k) > { >- struct ifnet *ifp = vap->iv_ifp; >- struct wpi_softc *sc = ifp->if_softc; >- >- if (!(&vap->iv_nw_keys[0] <= k && >- k < &vap->iv_nw_keys[IEEE80211_WEP_NKID])) { >- if (k->wk_flags & IEEE80211_KEY_GROUP) { >- /* should not happen */ >- DPRINTF(sc, WPI_DEBUG_KEY, "%s: bogus group key\n", >- __func__); >- return 0; >- } >- *keyix = 0; /* NB: use key index 0 for ucast key */ >- } else { >- *keyix = *rxkeyix = k - vap->iv_nw_keys; >- >- if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_AES_CCM) >- k->wk_flags |= IEEE80211_KEY_SWCRYPT; >- } >- return 1; >-} >- >-static int >-wpi_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k, >- const uint8_t mac[IEEE80211_ADDR_LEN]) >-{ > const struct ieee80211_cipher *cip = k->wk_cipher; >- struct ieee80211com *ic = vap->iv_ic; >- struct ieee80211_node *ni = vap->iv_bss; >- struct wpi_softc *sc = ic->ic_ifp->if_softc; >- struct wpi_node *wn = (void *)ni; >+ struct ieee80211vap *vap = ni->ni_vap; >+ struct wpi_softc *sc = ni->ni_ic->ic_ifp->if_softc; >+ struct wpi_node *wn = WPI_NODE(ni); > struct wpi_node_info node; > uint16_t kflags; > int error; >@@ -3985,21 +4374,23 @@ > > DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); > >+ if (wpi_check_node_entry(sc, wn->id) == 0) { >+ device_printf(sc->sc_dev, "%s: node does not exist\n", >+ __func__); >+ return 0; >+ } >+ > switch (cip->ic_cipher) { > case IEEE80211_CIPHER_AES_CCM: >- if (k->wk_flags & IEEE80211_KEY_GROUP) >- return 1; >- > kflags = WPI_KFLAG_CCMP; > break; >+ > default: >- /* null_key_set() */ >- return 1; >+ device_printf(sc->sc_dev, "%s: unknown cipher %d\n", __func__, >+ cip->ic_cipher); >+ return 0; > } > >- if (wn->id == WPI_ID_UNDEFINED) >- return 0; >- > kflags |= WPI_KFLAG_KID(k->wk_keyix); > if (k->wk_flags & IEEE80211_KEY_GROUP) > kflags |= WPI_KFLAG_MULTICAST; >@@ -4010,55 +4401,225 @@ > node.flags = WPI_FLAG_KEY_SET; > node.kflags = htole16(kflags); > memcpy(node.key, k->wk_key, k->wk_keylen); >+again: >+ DPRINTF(sc, WPI_DEBUG_KEY, >+ "%s: setting %s key id %d for node %d (%s)\n", __func__, >+ (kflags & WPI_KFLAG_MULTICAST) ? "group" : "ucast", k->wk_keyix, >+ node.id, ether_sprintf(ni->ni_macaddr)); > >- DPRINTF(sc, WPI_DEBUG_KEY, "set key id=%d for node %d\n", k->wk_keyix, >- node.id); >- > error = wpi_cmd(sc, WPI_CMD_ADD_NODE, &node, sizeof node, 1); > if (error != 0) { > device_printf(sc->sc_dev, "can't update node info, error %d\n", > error); >- return 0; >+ return !error; > } > >+ if (!(kflags & WPI_KFLAG_MULTICAST) && &vap->iv_nw_keys[0] <= k && >+ k < &vap->iv_nw_keys[IEEE80211_WEP_NKID]) { >+ kflags |= WPI_KFLAG_MULTICAST; >+ node.kflags = htole16(kflags); >+ >+ goto again; >+ } >+ > return 1; > } > >+static void >+wpi_load_key_cb(void *arg, struct ieee80211_node *ni) >+{ >+ const struct ieee80211_key *k = arg; >+ struct ieee80211vap *vap = ni->ni_vap; >+ struct wpi_softc *sc = ni->ni_ic->ic_ifp->if_softc; >+ struct wpi_node *wn = WPI_NODE(ni); >+ int error; >+ >+ if (vap->iv_bss == ni && wn->id == WPI_ID_UNDEFINED) >+ return; >+ >+ WPI_NT_LOCK(sc); >+ error = wpi_load_key(ni, k); >+ WPI_NT_UNLOCK(sc); >+ >+ if (error == 0) { >+ device_printf(sc->sc_dev, "%s: error while setting key\n", >+ __func__); >+ } >+} >+ > static int >-wpi_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k) >+wpi_set_global_keys(struct ieee80211_node *ni) > { >- const struct ieee80211_cipher *cip = k->wk_cipher; >- struct ieee80211com *ic = vap->iv_ic; >- struct ieee80211_node *ni = vap->iv_bss; >- struct wpi_softc *sc = ic->ic_ifp->if_softc; >- struct wpi_node *wn = (void *)ni; >+ struct ieee80211vap *vap = ni->ni_vap; >+ struct ieee80211_key *wk = &vap->iv_nw_keys[0]; >+ int error = 1; >+ >+ for (; wk < &vap->iv_nw_keys[IEEE80211_WEP_NKID] && error; wk++) >+ if (wk->wk_keyix != IEEE80211_KEYIX_NONE) >+ error = wpi_load_key(ni, wk); >+ >+ return !error; >+} >+ >+static int >+wpi_del_key(struct ieee80211_node *ni, const struct ieee80211_key *k) >+{ >+ struct ieee80211vap *vap = ni->ni_vap; >+ struct wpi_softc *sc = ni->ni_ic->ic_ifp->if_softc; >+ struct wpi_node *wn = WPI_NODE(ni); > struct wpi_node_info node; >+ uint16_t kflags; >+ int error; > > DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); > >- switch (cip->ic_cipher) { >- case IEEE80211_CIPHER_AES_CCM: >- break; >- default: >- /* null_key_delete() */ >- return 1; >+ if (wpi_check_node_entry(sc, wn->id) == 0) { >+ DPRINTF(sc, WPI_DEBUG_KEY, "%s: node was removed\n", __func__); >+ return 1; /* Nothing to do. */ > } > >- if (vap->iv_state != IEEE80211_S_RUN || >- (k->wk_flags & IEEE80211_KEY_GROUP)) >- return 1; /* Nothing to do. */ >+ kflags = WPI_KFLAG_KID(k->wk_keyix); >+ if (k->wk_flags & IEEE80211_KEY_GROUP) >+ kflags |= WPI_KFLAG_MULTICAST; > > memset(&node, 0, sizeof node); > node.id = wn->id; > node.control = WPI_NODE_UPDATE; > node.flags = WPI_FLAG_KEY_SET; >+ node.kflags = htole16(kflags); >+again: >+ DPRINTF(sc, WPI_DEBUG_KEY, "%s: deleting %s key %d for node %d (%s)\n", >+ __func__, (kflags & WPI_KFLAG_MULTICAST) ? "group" : "ucast", >+ k->wk_keyix, node.id, ether_sprintf(ni->ni_macaddr)); > >- DPRINTF(sc, WPI_DEBUG_KEY, "delete keys for node %d\n", node.id); >- (void)wpi_cmd(sc, WPI_CMD_ADD_NODE, &node, sizeof node, 1); >+ error = wpi_cmd(sc, WPI_CMD_ADD_NODE, &node, sizeof node, 1); >+ if (error != 0) { >+ device_printf(sc->sc_dev, "can't update node info, error %d\n", >+ error); >+ return !error; >+ } > >+ if (!(kflags & WPI_KFLAG_MULTICAST) && &vap->iv_nw_keys[0] <= k && >+ k < &vap->iv_nw_keys[IEEE80211_WEP_NKID]) { >+ kflags |= WPI_KFLAG_MULTICAST; >+ node.kflags = htole16(kflags); >+ >+ goto again; >+ } >+ > return 1; > } > >+static void >+wpi_del_key_cb(void *arg, struct ieee80211_node *ni) >+{ >+ const struct ieee80211_key *k = arg; >+ struct ieee80211vap *vap = ni->ni_vap; >+ struct wpi_softc *sc = ni->ni_ic->ic_ifp->if_softc; >+ struct wpi_node *wn = WPI_NODE(ni); >+ int error; >+ >+ if (vap->iv_bss == ni && wn->id == WPI_ID_UNDEFINED) >+ return; >+ >+ WPI_NT_LOCK(sc); >+ error = wpi_del_key(ni, k); >+ WPI_NT_UNLOCK(sc); >+ >+ if (error == 0) { >+ device_printf(sc->sc_dev, "%s: error while deleting key\n", >+ __func__); >+ } >+} >+ >+static int >+wpi_process_key(struct ieee80211vap *vap, const struct ieee80211_key *k, >+ int set) >+{ >+ struct ieee80211com *ic = vap->iv_ic; >+ struct wpi_softc *sc = ic->ic_ifp->if_softc; >+ struct wpi_vap *wvp = WPI_VAP(vap); >+ struct ieee80211_node *ni; >+ int error, ni_ref = 0; >+ >+ DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); >+ >+ if (k->wk_flags & IEEE80211_KEY_SWCRYPT) { >+ /* Not for us. */ >+ return 1; >+ } >+ >+ if (!(k->wk_flags & IEEE80211_KEY_RECV)) { >+ /* XMIT keys are handled in wpi_tx_data(). */ >+ return 1; >+ } >+ >+ /* Handle group keys. */ >+ if (&vap->iv_nw_keys[0] <= k && >+ k < &vap->iv_nw_keys[IEEE80211_WEP_NKID]) { >+ if (set) { >+ atomic_set_acq_32(&wvp->wv_gtk, >+ WPI_VAP_KEY(k->wk_keyix)); >+ } else { >+ atomic_clear_acq_32(&wvp->wv_gtk, >+ WPI_VAP_KEY(k->wk_keyix)); >+ } >+ >+ if (vap->iv_state == IEEE80211_S_RUN) { >+ ieee80211_iterate_nodes(&ic->ic_sta, >+ set ? wpi_load_key_cb : wpi_del_key_cb, (void *)k); >+ } >+ >+ return 1; >+ } >+ >+ switch (vap->iv_opmode) { >+ case IEEE80211_M_STA: >+ ni = vap->iv_bss; >+ break; >+ >+ case IEEE80211_M_IBSS: >+ case IEEE80211_M_AHDEMO: >+ case IEEE80211_M_HOSTAP: >+ ni = ieee80211_find_vap_node(&ic->ic_sta, vap, k->wk_macaddr); >+ if (ni == NULL) >+ return 0; /* should not happen */ >+ >+ ni_ref = 1; >+ break; >+ >+ default: >+ device_printf(sc->sc_dev, "%s: unknown opmode %d\n", __func__, >+ vap->iv_opmode); >+ return 0; >+ } >+ >+ WPI_NT_LOCK(sc); >+ if (set) >+ error = wpi_load_key(ni, k); >+ else >+ error = wpi_del_key(ni, k); >+ WPI_NT_UNLOCK(sc); >+ >+ if (ni_ref) >+ ieee80211_node_decref(ni); >+ >+ return error; >+} >+ >+static int >+wpi_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k, >+ const uint8_t mac[IEEE80211_ADDR_LEN]) >+{ >+ return wpi_process_key(vap, k, 1); >+} >+ >+static int >+wpi_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k) >+{ >+ return wpi_process_key(vap, k, 0); >+} >+ > /* > * This function is called after the runtime firmware notifies us of its > * readiness (called in a process context). >@@ -4093,11 +4654,11 @@ > if (ntries == 1000) { > device_printf(sc->sc_dev, > "timeout waiting for thermal sensor calibration\n"); >- return ETIMEDOUT; >- } >+ return ETIMEDOUT; >+ } > >- DPRINTF(sc, WPI_DEBUG_TEMP, "temperature %d\n", sc->temp); >- return 0; >+ DPRINTF(sc, WPI_DEBUG_TEMP, "temperature %d\n", sc->temp); >+ return 0; > } > > /* >@@ -4192,7 +4753,7 @@ > WPI_WRITE(sc, WPI_RESET, 0); > > /* Wait at most one second for first alive notification. */ >- if ((error = msleep(sc, &sc->sc_mtx, PCATCH, "wpiinit", hz)) != 0) { >+ if ((error = mtx_sleep(sc, &sc->sc_mtx, PCATCH, "wpiinit", hz)) != 0) { > device_printf(sc->sc_dev, > "%s: timeout waiting for adapter to initialize, error %d\n", > __func__, error); >@@ -4297,8 +4858,8 @@ > > DPRINTF(sc, WPI_DEBUG_FIRMWARE, > "Firmware Version: Major %d, Minor %d, Driver %d, \n" >- "runtime (text: %u, data: %u) init (text: %u, data %u) boot (text %u)\n", >- hdr->major, hdr->minor, le32toh(hdr->driver), >+ "runtime (text: %u, data: %u) init (text: %u, data %u) " >+ "boot (text %u)\n", hdr->major, hdr->minor, le32toh(hdr->driver), > fw->main.textsz, fw->main.datasz, > fw->init.textsz, fw->init.datasz, fw->boot.textsz); > >@@ -4362,6 +4923,10 @@ > /* Set FH wait threshold to max (HW bug under stress workaround). */ > WPI_SETBITS(sc, WPI_DBG_HPET_MEM, 0xffff0000); > >+ /* Cleanup. */ >+ wpi_prph_write(sc, WPI_APMG_CLK_DIS, 0x00000400); >+ wpi_prph_clrbits(sc, WPI_APMG_PS, 0x00000E00); >+ > /* Retrieve PCIe Active State Power Management (ASPM). */ > reg = pci_read_config(sc->sc_dev, sc->sc_cap_off + 0x10, 1); > /* Workaround for HW instability in PCIe L0->L0s->L1 transition. */ >@@ -4384,8 +4949,6 @@ > DELAY(20); > /* Disable L1-Active. */ > wpi_prph_setbits(sc, WPI_APMG_PCI_STT, WPI_APMG_PCI_STT_L1A_DIS); >- /* ??? */ >- wpi_prph_clrbits(sc, WPI_APMG_PS, 0x00000E00); > wpi_nic_unlock(sc); > > return 0; >@@ -4408,7 +4971,8 @@ > return; > DELAY(10); > } >- device_printf(sc->sc_dev, "%s: timeout waiting for master\n", __func__); >+ device_printf(sc->sc_dev, "%s: timeout waiting for master\n", >+ __func__); > } > > static void >@@ -4440,7 +5004,7 @@ > if (sc->cap == 0x80) > WPI_SETBITS(sc, WPI_HW_IF_CONFIG, WPI_HW_IF_CONFIG_SKU_MRC); > >- if ((le16toh(sc->rev) & 0xf0) == 0xd0) >+ if ((sc->rev & 0xf0) == 0xd0) > WPI_SETBITS(sc, WPI_HW_IF_CONFIG, WPI_HW_IF_CONFIG_REV_D); > else > WPI_CLRBITS(sc, WPI_HW_IF_CONFIG, WPI_HW_IF_CONFIG_REV_D); >@@ -4551,7 +5115,7 @@ > return error; > } > /* Wait at most one second for firmware alive notification. */ >- if ((error = msleep(sc, &sc->sc_mtx, PCATCH, "wpiinit", hz)) != 0) { >+ if ((error = mtx_sleep(sc, &sc->sc_mtx, PCATCH, "wpiinit", hz)) != 0) { > device_printf(sc->sc_dev, > "%s: timeout waiting for adapter to initialize, error %d\n", > __func__, error); >@@ -4655,18 +5219,25 @@ > if (vap != NULL) > ieee80211_stop(vap); > >+ WPI_LOCK(sc); > callout_reset(&sc->watchdog_rfkill, hz, wpi_watchdog_rfkill, sc); >+ WPI_UNLOCK(sc); > } > > static void >-wpi_init_locked(struct wpi_softc *sc) >+wpi_init(void *arg) > { >+ struct wpi_softc *sc = arg; > struct ifnet *ifp = sc->sc_ifp; >+ struct ieee80211com *ic = ifp->if_l2com; > int error; > >+ WPI_LOCK(sc); >+ > DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); > >- WPI_LOCK_ASSERT(sc); >+ if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) >+ goto end; > > /* Check that the radio is not disabled by hardware switch. */ > if (!(WPI_READ(sc, WPI_GP_CNTRL) & WPI_GP_CNTRL_RFKILL)) { >@@ -4674,7 +5245,7 @@ > "RF switch: radio disabled (%s)\n", __func__); > callout_reset(&sc->watchdog_rfkill, hz, wpi_watchdog_rfkill, > sc); >- return; >+ goto end; > } > > /* Read firmware images from the filesystem. */ >@@ -4695,6 +5266,8 @@ > goto fail; > } > >+ atomic_store_rel_32(&sc->txq_active, 1); >+ > /* Configure adapter now that it is ready. */ > if ((error = wpi_config(sc)) != 0) { > device_printf(sc->sc_dev, >@@ -4703,32 +5276,24 @@ > goto fail; > } > >+ IF_LOCK(&ifp->if_snd); > ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; > ifp->if_drv_flags |= IFF_DRV_RUNNING; >+ IF_UNLOCK(&ifp->if_snd); > > callout_reset(&sc->watchdog_to, hz, wpi_watchdog, sc); > >+ WPI_UNLOCK(sc); >+ >+ ieee80211_start_all(ic); >+ > DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); > > return; > > fail: wpi_stop_locked(sc); >- DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END_ERR, __func__); >-} >- >-static void >-wpi_init(void *arg) >-{ >- struct wpi_softc *sc = arg; >- struct ifnet *ifp = sc->sc_ifp; >- struct ieee80211com *ic = ifp->if_l2com; >- >- WPI_LOCK(sc); >- wpi_init_locked(sc); >+end: DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END_ERR, __func__); > WPI_UNLOCK(sc); >- >- if (ifp->if_drv_flags & IFF_DRV_RUNNING) >- ieee80211_start_all(ic); > } > > static void >@@ -4738,11 +5303,19 @@ > > WPI_LOCK_ASSERT(sc); > >- sc->sc_scan_timer = 0; >- sc->sc_tx_timer = 0; >+ atomic_store_rel_32(&sc->txq_active, 0); >+ atomic_store_rel_32(&sc->sc_scan_timer, 0); >+ atomic_store_rel_32(&sc->sc_tx_timer, 0); >+ > callout_stop(&sc->watchdog_to); >+ >+ WPI_RXON_LOCK(sc); > callout_stop(&sc->calib_to); >+ WPI_RXON_UNLOCK(sc); >+ >+ IF_LOCK(&ifp->if_snd); > ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); >+ IF_UNLOCK(&ifp->if_snd); > > /* Power OFF hardware. */ > wpi_hw_stop(sc); >@@ -4762,12 +5335,9 @@ > static void > wpi_scan_start(struct ieee80211com *ic) > { >- struct ifnet *ifp = ic->ic_ifp; >- struct wpi_softc *sc = ifp->if_softc; >+ struct wpi_softc *sc = ic->ic_ifp->if_softc; > >- WPI_LOCK(sc); > wpi_set_led(sc, WPI_LED_LINK, 20, 2); >- WPI_UNLOCK(sc); > } > > /* >@@ -4780,11 +5350,8 @@ > struct wpi_softc *sc = ifp->if_softc; > struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); > >- if (vap->iv_state == IEEE80211_S_RUN) { >- WPI_LOCK(sc); >+ if (vap->iv_state == IEEE80211_S_RUN) > wpi_set_led(sc, WPI_LED_LINK, 0, 1); >- WPI_UNLOCK(sc); >- } > } > > /** >@@ -4804,8 +5371,11 @@ > WPI_LOCK(sc); > sc->sc_rxtap.wr_chan_freq = htole16(c->ic_freq); > sc->sc_rxtap.wr_chan_flags = htole16(c->ic_flags); >+ WPI_UNLOCK(sc); >+ WPI_TX_LOCK(sc); > sc->sc_txtap.wt_chan_freq = htole16(c->ic_freq); > sc->sc_txtap.wt_chan_flags = htole16(c->ic_flags); >+ WPI_TX_UNLOCK(sc); > > /* > * Only need to set the channel in Monitor mode. AP scanning and auth >@@ -4812,6 +5382,7 @@ > * are already taken care of by their respective firmware commands. > */ > if (ic->ic_opmode == IEEE80211_M_MONITOR) { >+ WPI_RXON_LOCK(sc); > sc->rxon.chan = ieee80211_chan2ieee(ic, c); > if (IEEE80211_IS_CHAN_2GHZ(c)) { > sc->rxon.flags |= htole32(WPI_RXON_AUTO | >@@ -4820,12 +5391,12 @@ > sc->rxon.flags &= ~htole32(WPI_RXON_AUTO | > WPI_RXON_24GHZ); > } >- if ((error = wpi_send_rxon(sc, 0, 0)) != 0) >+ if ((error = wpi_send_rxon(sc, 0, 1)) != 0) > device_printf(sc->sc_dev, >- "%s: error %d settting channel\n", __func__, >+ "%s: error %d setting channel\n", __func__, > error); >+ WPI_RXON_UNLOCK(sc); > } >- WPI_UNLOCK(sc); > } > > /** >@@ -4838,15 +5409,15 @@ > { > struct ieee80211vap *vap = ss->ss_vap; > struct ieee80211com *ic = vap->iv_ic; >- struct ifnet *ifp = ic->ic_ifp; >- struct wpi_softc *sc = ifp->if_softc; >- int error; >+ struct wpi_softc *sc = ic->ic_ifp->if_softc; >+ uint8_t curchan; > >- if (sc->rxon.chan != ieee80211_chan2ieee(ic, ic->ic_curchan)) { >- WPI_LOCK(sc); >- error = wpi_scan(sc, ic->ic_curchan); >- WPI_UNLOCK(sc); >- if (error != 0) >+ WPI_RXON_LOCK(sc); >+ curchan = sc->rxon.chan; >+ WPI_RXON_UNLOCK(sc); >+ >+ if (curchan != ieee80211_chan2ieee(ic, ic->ic_curchan)) { >+ if (wpi_scan(sc, ic->ic_curchan) != 0) > ieee80211_cancel_scan(vap); > } else { > /* Send probe request when associated. */ >Index: sys/dev/wpi/if_wpi_debug.h >=================================================================== >--- sys/dev/wpi/if_wpi_debug.h (revision 278764) >+++ sys/dev/wpi/if_wpi_debug.h (working copy) >@@ -39,8 +39,10 @@ > WPI_DEBUG_TRACE = 0x00002000, /* Print begin and start driver function */ > WPI_DEBUG_PWRSAVE = 0x00004000, /* Power save operations */ > WPI_DEBUG_EEPROM = 0x00008000, /* EEPROM info */ >- WPI_DEBUG_KEY = 0x00010000, /* node key management */ >- WPI_DEBUG_EDCA = 0x00020000, /* WME info */ >+ WPI_DEBUG_NODE = 0x00010000, /* node addition/removal */ >+ WPI_DEBUG_KEY = 0x00020000, /* node key management */ >+ WPI_DEBUG_EDCA = 0x00040000, /* WME info */ >+ WPI_DEBUG_REGISTER = 0x00080000, /* print chipset register */ > WPI_DEBUG_ANY = 0xffffffff > }; > >@@ -54,36 +56,38 @@ > #define TRACE_STR_END "->%s: end\n" > #define TRACE_STR_END_ERR "->%s: end in error\n" > >+#define WPI_DESC(x) case x: return #x >+ > static const char *wpi_cmd_str(int cmd) > { > switch (cmd) { >- /* Notifications */ >- case WPI_UC_READY: return "UC_READY"; >- case WPI_RX_DONE: return "RX_DONE"; >- case WPI_START_SCAN: return "START_SCAN"; >- case WPI_SCAN_RESULTS: return "SCAN_RESULTS"; >- case WPI_STOP_SCAN: return "STOP_SCAN"; >- case WPI_BEACON_SENT: return "BEACON_SENT"; >- case WPI_RX_STATISTICS: return "RX_STATS"; >- case WPI_BEACON_STATISTICS: return "BEACON_STATS"; >- case WPI_STATE_CHANGED: return "STATE_CHANGED"; >- case WPI_BEACON_MISSED: return "BEACON_MISSED"; >+ /* Notifications. */ >+ WPI_DESC(WPI_UC_READY); >+ WPI_DESC(WPI_RX_DONE); >+ WPI_DESC(WPI_START_SCAN); >+ WPI_DESC(WPI_SCAN_RESULTS); >+ WPI_DESC(WPI_STOP_SCAN); >+ WPI_DESC(WPI_BEACON_SENT); >+ WPI_DESC(WPI_RX_STATISTICS); >+ WPI_DESC(WPI_BEACON_STATISTICS); >+ WPI_DESC(WPI_STATE_CHANGED); >+ WPI_DESC(WPI_BEACON_MISSED); > >- /* Command notifications */ >- case WPI_CMD_RXON: return "WPI_CMD_RXON"; >- case WPI_CMD_RXON_ASSOC: return "WPI_CMD_RXON_ASSOC"; >- case WPI_CMD_EDCA_PARAMS: return "WPI_CMD_EDCA_PARAMS"; >- case WPI_CMD_TIMING: return "WPI_CMD_TIMING"; >- case WPI_CMD_ADD_NODE: return "WPI_CMD_ADD_NODE"; >- case WPI_CMD_DEL_NODE: return "WPI_CMD_DEL_NODE"; >- case WPI_CMD_TX_DATA: return "WPI_CMD_TX_DATA"; >- case WPI_CMD_MRR_SETUP: return "WPI_CMD_MRR_SETUP"; >- case WPI_CMD_SET_LED: return "WPI_CMD_SET_LED"; >- case WPI_CMD_SET_POWER_MODE: return "WPI_CMD_SET_POWER_MODE"; >- case WPI_CMD_SCAN: return "WPI_CMD_SCAN"; >- case WPI_CMD_SET_BEACON: return "WPI_CMD_SET_BEACON"; >- case WPI_CMD_TXPOWER: return "WPI_CMD_TXPOWER"; >- case WPI_CMD_BT_COEX: return "WPI_CMD_BT_COEX"; >+ /* Command notifications. */ >+ WPI_DESC(WPI_CMD_RXON); >+ WPI_DESC(WPI_CMD_RXON_ASSOC); >+ WPI_DESC(WPI_CMD_EDCA_PARAMS); >+ WPI_DESC(WPI_CMD_TIMING); >+ WPI_DESC(WPI_CMD_ADD_NODE); >+ WPI_DESC(WPI_CMD_DEL_NODE); >+ WPI_DESC(WPI_CMD_TX_DATA); >+ WPI_DESC(WPI_CMD_MRR_SETUP); >+ WPI_DESC(WPI_CMD_SET_LED); >+ WPI_DESC(WPI_CMD_SET_POWER_MODE); >+ WPI_DESC(WPI_CMD_SCAN); >+ WPI_DESC(WPI_CMD_SET_BEACON); >+ WPI_DESC(WPI_CMD_TXPOWER); >+ WPI_DESC(WPI_CMD_BT_COEX); > > default: > KASSERT(1, ("Unknown Command: %d\n", cmd)); >@@ -91,6 +95,46 @@ > } > } > >+/* >+ * Translate CSR code to string >+ */ >+static const char *wpi_get_csr_string(int csr) >+{ >+ switch (csr) { >+ WPI_DESC(WPI_HW_IF_CONFIG); >+ WPI_DESC(WPI_INT); >+ WPI_DESC(WPI_INT_MASK); >+ WPI_DESC(WPI_FH_INT); >+ WPI_DESC(WPI_GPIO_IN); >+ WPI_DESC(WPI_RESET); >+ WPI_DESC(WPI_GP_CNTRL); >+ WPI_DESC(WPI_EEPROM); >+ WPI_DESC(WPI_EEPROM_GP); >+ WPI_DESC(WPI_GIO); >+ WPI_DESC(WPI_UCODE_GP1); >+ WPI_DESC(WPI_UCODE_GP2); >+ WPI_DESC(WPI_GIO_CHICKEN); >+ WPI_DESC(WPI_ANA_PLL); >+ WPI_DESC(WPI_DBG_HPET_MEM); >+ default: >+ KASSERT(1, ("Unknown CSR: %d\n", csr)); >+ return "UNKNOWN CSR"; >+ } >+} >+ >+static const char *wpi_get_prph_string(int prph) >+{ >+ switch (prph) { >+ WPI_DESC(WPI_APMG_CLK_CTRL); >+ WPI_DESC(WPI_APMG_PS); >+ WPI_DESC(WPI_APMG_PCI_STT); >+ WPI_DESC(WPI_APMG_RFKILL); >+ default: >+ KASSERT(1, ("Unknown register: %d\n", prph)); >+ return "UNKNOWN PRPH"; >+ } >+} >+ > #else > #define DPRINTF(sc, m, ...) do { (void) sc; } while (0) > #endif >Index: sys/dev/wpi/if_wpireg.h >=================================================================== >--- sys/dev/wpi/if_wpireg.h (revision 278764) >+++ sys/dev/wpi/if_wpireg.h (working copy) >@@ -24,10 +24,13 @@ > #define WPI_RX_RING_COUNT (1 << WPI_RX_RING_COUNT_LOG) > > #define WPI_NTXQUEUES 8 >+#define WPI_DRV_NTXQUEUES 5 >+#define WPI_CMD_QUEUE_NUM 4 >+ > #define WPI_NDMACHNLS 6 > > /* Maximum scatter/gather. */ >-#define WPI_MAX_SCATTER 4 >+#define WPI_MAX_SCATTER 4 > > /* > * Rings must be aligned on a 16K boundary. >@@ -94,6 +97,7 @@ > #define WPI_ALM_SCHED_TXF5MF 0x2e20 > #define WPI_ALM_SCHED_SBYPASS_MODE1 0x2e2c > #define WPI_ALM_SCHED_SBYPASS_MODE2 0x2e30 >+#define WPI_APMG_CLK_CTRL 0x3000 > #define WPI_APMG_CLK_EN 0x3004 > #define WPI_APMG_CLK_DIS 0x3008 > #define WPI_APMG_PS 0x300c >@@ -221,7 +225,7 @@ > #define WPI_APMG_PCI_STT_L1A_DIS (1 << 11) > > struct wpi_shared { >- uint32_t txbase[8]; >+ uint32_t txbase[WPI_NTXQUEUES]; > uint32_t next; > uint32_t reserved[2]; > } __packed; >@@ -268,6 +272,9 @@ > uint8_t qid; > } __packed; > >+#define WPI_RX_DESC_QID_MSK 0x07 >+#define WPI_UNSOLICITED_RX_NOTIF 0x80 >+ > struct wpi_rx_stat { > uint8_t len; > #define WPI_STAT_MAXLEN 20 >@@ -274,7 +281,7 @@ > > uint8_t id; > uint8_t rssi; /* received signal strength */ >-#define WPI_RSSI_OFFSET 95 >+#define WPI_RSSI_OFFSET -95 > > uint8_t agc; /* access gain control */ > uint16_t signal; >@@ -368,6 +375,7 @@ > #define WPI_FILTER_NODECRYPT (1 << 3) > #define WPI_FILTER_BSS (1 << 5) > #define WPI_FILTER_BEACON (1 << 6) >+#define WPI_FILTER_ASSOC (1 << 7) /* Accept associaton requests. */ > > uint8_t chan; > uint16_t reserved5; >@@ -465,7 +473,7 @@ > uint16_t lnext; > uint32_t flags; > #define WPI_TX_NEED_RTS (1 << 1) >-#define WPI_TX_NEED_CTS (1 << 2) >+#define WPI_TX_NEED_CTS (1 << 2) > #define WPI_TX_NEED_ACK (1 << 3) > #define WPI_TX_FULL_TXOP (1 << 7) > #define WPI_TX_BT_DISABLE (1 << 12) /* bluetooth coexistence */ >@@ -515,10 +523,10 @@ > > /* Structure for notification WPI_BEACON_MISSED. */ > struct wpi_beacon_missed { >- uint32_t consecutive; >- uint32_t total; >- uint32_t expected; >- uint32_t received; >+ uint32_t consecutive; >+ uint32_t total; >+ uint32_t expected; >+ uint32_t received; > } __packed; > > >Index: sys/dev/wpi/if_wpivar.h >=================================================================== >--- sys/dev/wpi/if_wpivar.h (revision 278764) >+++ sys/dev/wpi/if_wpivar.h (working copy) >@@ -52,7 +52,7 @@ > > struct wpi_dma_info { > bus_dma_tag_t tag; >- bus_dmamap_t map; >+ bus_dmamap_t map; > bus_addr_t paddr; > caddr_t vaddr; > bus_size_t size; >@@ -73,7 +73,7 @@ > struct wpi_tx_data data[WPI_TX_RING_COUNT]; > bus_dma_tag_t data_dmat; > int qid; >- int queued; >+ volatile uint32_t queued; > int cur; > int update; > }; >@@ -96,6 +96,7 @@ > struct ieee80211_node ni; /* must be the first */ > uint8_t id; > }; >+#define WPI_NODE(ni) ((struct wpi_node *)(ni)) > > struct wpi_power_sample { > uint8_t index; >@@ -111,7 +112,7 @@ > }; > > struct wpi_buf { >- void *data; >+ uint8_t data[56]; /* sizeof(struct wpi_cmd_beacon) */ > struct ieee80211_node *ni; > struct mbuf *m; > size_t size; >@@ -120,14 +121,28 @@ > }; > > struct wpi_vap { >- struct ieee80211vap vap; >- struct wpi_buf wv_bcbuf; >+ struct ieee80211vap wv_vap; > >- int (*newstate)(struct ieee80211vap *, >- enum ieee80211_state, int); >+ struct wpi_buf wv_bcbuf; >+ struct ieee80211_beacon_offsets wv_boff; >+ struct mtx wv_mtx; >+ >+ volatile uint32_t wv_gtk; >+#define WPI_VAP_KEY(kid) (1 << kid) >+ >+ int (*wv_newstate)(struct ieee80211vap *, >+ enum ieee80211_state, int); > }; > #define WPI_VAP(vap) ((struct wpi_vap *)(vap)) > >+#define WPI_VAP_LOCK_INIT(_wvp) \ >+ mtx_init(&(_wvp)->wv_mtx, "lock for wv_bcbuf/wv_boff structures", \ >+ NULL, MTX_DEF) >+#define WPI_VAP_LOCK(_wvp) mtx_lock(&(_wvp)->wv_mtx) >+#define WPI_VAP_UNLOCK(_wvp) mtx_unlock(&(_wvp)->wv_mtx) >+#define WPI_VAP_LOCK_ASSERT(_wvp) mtx_assert(&(_wvp)->wv_mtx, MA_OWNED) >+#define WPI_VAP_LOCK_DESTROY(_wvp) mtx_destroy(&(_wvp)->wv_mtx) >+ > struct wpi_fw_part { > const uint8_t *text; > uint32_t textsz; >@@ -150,19 +165,16 @@ > int sc_debug; > > struct mtx sc_mtx; >- struct unrhdr *sc_unr; >+ struct mtx tx_mtx; > >- /* Flags indicating the current state the driver >- * expects the hardware to be in >- */ >- uint32_t flags; >-#define WPI_FLAG_BUSY (1 << 0) >- > /* Shared area. */ > struct wpi_dma_info shared_dma; > struct wpi_shared *shared; > > struct wpi_tx_ring txq[WPI_NTXQUEUES]; >+ struct mtx txq_mtx; >+ volatile uint32_t txq_active; >+ > struct wpi_rx_ring rxq; > > /* TX Thermal Callibration. */ >@@ -183,21 +195,27 @@ > bus_space_handle_t sc_sh; > void *sc_ih; > bus_size_t sc_sz; >- int sc_cap_off; /* PCIe Capabilities. */ >+ int sc_cap_off; /* PCIe Capabilities. */ > > struct wpi_rxon rxon; >+ struct mtx rxon_mtx; >+ > int temp; >- uint32_t qfullmsk; > >- int sc_tx_timer; >- int sc_scan_timer; >+ volatile uint32_t qfullmsk; > >+ uint32_t nodesmsk; >+ struct mtx nt_mtx; >+ >+ volatile int32_t sc_tx_timer; >+ volatile int32_t sc_scan_timer; >+ > void (*sc_node_free)(struct ieee80211_node *); > void (*sc_scan_curchan)(struct ieee80211_scan_state *, > unsigned long); > >- struct wpi_rx_radiotap_header sc_rxtap; >- struct wpi_tx_radiotap_header sc_txtap; >+ struct wpi_rx_radiotap_header sc_rxtap; >+ struct wpi_tx_radiotap_header sc_txtap; > > /* Firmware image. */ > const struct firmware *fw_fp; >@@ -209,6 +227,7 @@ > struct task sc_reinittask; > struct task sc_radiooff_task; > struct task sc_radioon_task; >+ struct task sc_start_task; > > /* Eeprom info. */ > uint8_t cap; >@@ -221,10 +240,38 @@ > char domain[4]; /* Regulatory domain. */ > }; > >+/* WPI_LOCK > WPI_RXON_LOCK / WPI_TX_LOCK > WPI_NT_LOCK > WPI_TXQ_LOCK */ >+ > #define WPI_LOCK_INIT(_sc) \ > mtx_init(&(_sc)->sc_mtx, device_get_nameunit((_sc)->sc_dev), \ >- MTX_NETWORK_LOCK, MTX_DEF) >+ MTX_NETWORK_LOCK, MTX_DEF) > #define WPI_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) > #define WPI_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) >-#define WPI_LOCK_ASSERT(sc) mtx_assert(&(sc)->sc_mtx, MA_OWNED) >+#define WPI_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->sc_mtx, MA_OWNED) > #define WPI_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_mtx) >+ >+#define WPI_RXON_LOCK_INIT(_sc) \ >+ mtx_init(&(_sc)->rxon_mtx, "lock for wpi_rxon structure", NULL, MTX_DEF) >+#define WPI_RXON_LOCK(_sc) mtx_lock(&(_sc)->rxon_mtx) >+#define WPI_RXON_UNLOCK(_sc) mtx_unlock(&(_sc)->rxon_mtx) >+#define WPI_RXON_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->rxon_mtx, MA_OWNED) >+#define WPI_RXON_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->rxon_mtx) >+ >+#define WPI_TX_LOCK_INIT(_sc) \ >+ mtx_init(&(_sc)->tx_mtx, "tx path lock", \ >+ NULL, MTX_DEF) >+#define WPI_TX_LOCK(_sc) mtx_lock(&(_sc)->tx_mtx) >+#define WPI_TX_UNLOCK(_sc) mtx_unlock(&(_sc)->tx_mtx) >+#define WPI_TX_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->tx_mtx) >+ >+#define WPI_NT_LOCK_INIT(_sc) \ >+ mtx_init(&(_sc)->nt_mtx, "node table lock", NULL, MTX_DEF) >+#define WPI_NT_LOCK(_sc) mtx_lock(&(_sc)->nt_mtx) >+#define WPI_NT_UNLOCK(_sc) mtx_unlock(&(_sc)->nt_mtx) >+#define WPI_NT_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->nt_mtx) >+ >+#define WPI_TXQ_LOCK_INIT(_sc) \ >+ mtx_init(&(_sc)->txq_mtx, "txq/cmdq lock", NULL, MTX_DEF) >+#define WPI_TXQ_LOCK(_sc) mtx_lock(&(_sc)->txq_mtx) >+#define WPI_TXQ_UNLOCK(_sc) mtx_unlock(&(_sc)->txq_mtx) >+#define WPI_TXQ_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->txq_mtx)
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 197143
:
152282
|
152662
|
152977
|
153911
| 153977 |
153983
|
153985
|
153999
|
154000
|
154002
|
154006
|
154007
|
154009
|
154010
|
154011
|
154013
|
154015
|
154016
|
154017
|
154019
|
154020
|
154021
|
154022
|
154024
|
154026
|
154030
|
154032
|
154033
|
154328
|
154329
|
154330
|
154332
|
154334
|
154335
|
154336
|
154337
|
154338
|
154340
|
154341
|
154343
|
154346
|
154347
|
154348
|
154349
|
154350
|
154351
|
154352
|
154353
|
154354
|
154355
|
154356
|
154357
|
154358
|
154359
|
154360
|
154361
|
154362
|
154363
|
154364
|
154365
|
154366
|
154368
|
154369
|
154370
|
154371
|
154372
|
154373
|
154374
|
154375
|
154378
|
154379
|
154380
|
154381
|
154382
|
154383
|
154384
|
155332
|
155333
|
156164
|
156165
|
156166
|
156167
|
156168
|
156169
|
156170
|
156171
|
156172
|
156173
|
156174
|
156175
|
156176
|
156177
|
156178
|
156179
|
156180
|
156181
|
156182
|
156183
|
156184
|
156185
|
156186
|
156187
|
156188
|
156189
|
156190
|
156191
|
156192
|
156193
|
156194
|
156195