[haiku-commits] haiku: hrev52730 - src/add-ons/kernel/drivers/network/wlan/iprowifi4965/dev/iwn

  • From: waddlesplash <waddlesplash@xxxxxxxxx>
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Tue, 8 Jan 2019 21:00:32 -0500 (EST)

hrev52730 adds 2 changesets to branch 'master'
old head: 24e7aa421750a7403332a47827cd739fe5a0f0e1
new head: 4e5a521c2adf5efa14b277e53ddfaf0fa0ea61a5
overview: 
https://git.haiku-os.org/haiku/log/?qt=range&q=4e5a521c2adf+%5E24e7aa421750

----------------------------------------------------------------------------

27632129b22f: freebsd_network: Implement taskqueue_drain_all.
  
  Required by FreeBSD 12's iprowifi4965.

4e5a521c2adf: iprowifi4965: Upgrade to FreeBSD 12.
  
  Tested on a ThinkPad T61.

                              [ Augustin Cavalier <waddlesplash@xxxxxxxxx> ]

----------------------------------------------------------------------------

10 files changed, 533 insertions(+), 479 deletions(-)
src/add-ons/kernel/drivers/network/wlan/Jamfile  |   4 +-
.../network/wlan/iprowifi4965/dev/iwn/if_iwn.c   | 916 +++++++++----------
.../wlan/iprowifi4965/dev/iwn/if_iwn_chip_cfg.h  |   2 +-
.../wlan/iprowifi4965/dev/iwn/if_iwn_debug.h     |   4 +-
.../wlan/iprowifi4965/dev/iwn/if_iwn_devid.h     |   2 +-
.../wlan/iprowifi4965/dev/iwn/if_iwn_ioctl.h     |   2 +-
.../wlan/iprowifi4965/dev/iwn/if_iwnreg.h        |  40 +-
.../wlan/iprowifi4965/dev/iwn/if_iwnvar.h        |  19 +-
.../freebsd_network/compat/sys/taskqueue.h       |   1 +
src/libs/compat/freebsd_network/taskqueue.c      |  22 +

############################################################################

Commit:      27632129b22f7b7a8dd67be4dea489ba25abf792
URL:         https://git.haiku-os.org/haiku/commit/?id=27632129b22f
Author:      Augustin Cavalier <waddlesplash@xxxxxxxxx>
Date:        Wed Jan  9 01:52:06 2019 UTC

freebsd_network: Implement taskqueue_drain_all.

Required by FreeBSD 12's iprowifi4965.

----------------------------------------------------------------------------

diff --git a/src/libs/compat/freebsd_network/compat/sys/taskqueue.h 
b/src/libs/compat/freebsd_network/compat/sys/taskqueue.h
index 2767b321c7..f8d5c7363e 100644
--- a/src/libs/compat/freebsd_network/compat/sys/taskqueue.h
+++ b/src/libs/compat/freebsd_network/compat/sys/taskqueue.h
@@ -32,6 +32,7 @@ void taskqueue_free(struct taskqueue *tq);
 void taskqueue_drain(struct taskqueue *tq, struct task *task);
 void taskqueue_drain_timeout(struct taskqueue *queue,
        struct timeout_task *timeout_task);
+void taskqueue_drain_all(struct taskqueue *tq);
 void taskqueue_block(struct taskqueue *queue);
 void taskqueue_unblock(struct taskqueue *queue);
 int taskqueue_enqueue(struct taskqueue *tq, struct task *task);
diff --git a/src/libs/compat/freebsd_network/taskqueue.c 
b/src/libs/compat/freebsd_network/taskqueue.c
index 33826a8ad4..01dfdb918e 100644
--- a/src/libs/compat/freebsd_network/taskqueue.c
+++ b/src/libs/compat/freebsd_network/taskqueue.c
@@ -293,6 +293,28 @@ taskqueue_drain_timeout(struct taskqueue *queue,
 }
 
 
+static void
+taskqueue_task_nop_fn(void* context, int pending)
+{
+}
+
+
+void
+taskqueue_drain_all(struct taskqueue *taskQueue)
+{
+       struct task t_barrier;
+
+       if (taskQueue == NULL) {
+               printf("taskqueue_drain_all called with NULL taskqueue\n");
+               return;
+       }
+
+       TASK_INIT(&t_barrier, USHRT_MAX, taskqueue_task_nop_fn, &t_barrier);
+       taskqueue_enqueue(taskQueue, &t_barrier);
+       taskqueue_drain(taskQueue, &t_barrier);
+}
+
+
 static void
 taskqueue_enqueue_locked(struct taskqueue *taskQueue, struct task *task,
        cpu_status status)

############################################################################

Revision:    hrev52730
Commit:      4e5a521c2adf5efa14b277e53ddfaf0fa0ea61a5
URL:         https://git.haiku-os.org/haiku/commit/?id=4e5a521c2adf
Author:      Augustin Cavalier <waddlesplash@xxxxxxxxx>
Date:        Wed Jan  9 01:54:21 2019 UTC

iprowifi4965: Upgrade to FreeBSD 12.

Tested on a ThinkPad T61.

----------------------------------------------------------------------------

diff --git a/src/add-ons/kernel/drivers/network/wlan/Jamfile 
b/src/add-ons/kernel/drivers/network/wlan/Jamfile
index d29532544e..5478113968 100644
--- a/src/add-ons/kernel/drivers/network/wlan/Jamfile
+++ b/src/add-ons/kernel/drivers/network/wlan/Jamfile
@@ -1,11 +1,9 @@
 SubDir HAIKU_TOP src add-ons kernel drivers network wlan ;
 
 # FreeBSD 11.1 drivers
-SubInclude HAIKU_TOP src add-ons kernel drivers network wlan atheroswifi ;
 SubInclude HAIKU_TOP src add-ons kernel drivers network wlan broadcom43xx ;
 SubInclude HAIKU_TOP src add-ons kernel drivers network wlan iprowifi2100 ;
 SubInclude HAIKU_TOP src add-ons kernel drivers network wlan iprowifi3945 ;
-SubInclude HAIKU_TOP src add-ons kernel drivers network wlan iprowifi4965 ;
 SubInclude HAIKU_TOP src add-ons kernel drivers network wlan marvell88w8335 ;
 SubInclude HAIKU_TOP src add-ons kernel drivers network wlan marvell88w8363 ;
 SubInclude HAIKU_TOP src add-ons kernel drivers network wlan ralinkwifi ;
@@ -16,5 +14,7 @@ SubInclude HAIKU_TOP src add-ons kernel drivers network wlan 
wavelanwifi ;
 SubInclude HAIKU_TOP src add-ons kernel drivers network wlan iprowifi2200 ;
 
 # FreeBSD 12 drivers
+SubInclude HAIKU_TOP src add-ons kernel drivers network wlan atheroswifi ;
 SubInclude HAIKU_TOP src add-ons kernel drivers network wlan aironetwifi ;
 SubInclude HAIKU_TOP src add-ons kernel drivers network wlan idualwifi7260 ;
+SubInclude HAIKU_TOP src add-ons kernel drivers network wlan iprowifi4965 ;
diff --git 
a/src/add-ons/kernel/drivers/network/wlan/iprowifi4965/dev/iwn/if_iwn.c 
b/src/add-ons/kernel/drivers/network/wlan/iprowifi4965/dev/iwn/if_iwn.c
index 54576cba13..62adfb428c 100644
--- a/src/add-ons/kernel/drivers/network/wlan/iprowifi4965/dev/iwn/if_iwn.c
+++ b/src/add-ons/kernel/drivers/network/wlan/iprowifi4965/dev/iwn/if_iwn.c
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: releng/12.0/sys/dev/iwn/if_iwn.c 338949 2018-09-26 
17:12:30Z imp $");
 
 #include <sys/param.h>
 #include <sys/sockio.h>
@@ -193,16 +193,13 @@ static void       iwn_newassoc(struct ieee80211_node *, 
int);
 static int     iwn_media_change(struct ifnet *);
 static int     iwn_newstate(struct ieee80211vap *, enum ieee80211_state, int);
 static void    iwn_calib_timeout(void *);
-static void    iwn_rx_phy(struct iwn_softc *, struct iwn_rx_desc *,
-                   struct iwn_rx_data *);
+static void    iwn_rx_phy(struct iwn_softc *, struct iwn_rx_desc *);
 static void    iwn_rx_done(struct iwn_softc *, struct iwn_rx_desc *,
                    struct iwn_rx_data *);
-static void    iwn_rx_compressed_ba(struct iwn_softc *, struct iwn_rx_desc *,
-                   struct iwn_rx_data *);
+static void    iwn_rx_compressed_ba(struct iwn_softc *, struct iwn_rx_desc *);
 static void    iwn5000_rx_calib_results(struct iwn_softc *,
-                   struct iwn_rx_desc *, struct iwn_rx_data *);
-static void    iwn_rx_statistics(struct iwn_softc *, struct iwn_rx_desc *,
-                   struct iwn_rx_data *);
+                   struct iwn_rx_desc *);
+static void    iwn_rx_statistics(struct iwn_softc *, struct iwn_rx_desc *);
 static void    iwn4965_tx_done(struct iwn_softc *, struct iwn_rx_desc *,
                    struct iwn_rx_data *);
 static void    iwn5000_tx_done(struct iwn_softc *, struct iwn_rx_desc *,
@@ -214,7 +211,7 @@ static void iwn_ampdu_tx_done(struct iwn_softc *, int, int, 
int, int, int,
 static void    iwn_cmd_done(struct iwn_softc *, struct iwn_rx_desc *);
 static void    iwn_notif_intr(struct iwn_softc *);
 static void    iwn_wakeup_intr(struct iwn_softc *);
-static void    iwn_rftoggle_intr(struct iwn_softc *);
+static void    iwn_rftoggle_task(void *, int);
 static void    iwn_fatal_intr(struct iwn_softc *);
 static void    iwn_intr(void *);
 static void    iwn4965_update_sched(struct iwn_softc *, int, int, uint8_t,
@@ -229,6 +226,8 @@ static int  iwn_tx_data(struct iwn_softc *, struct mbuf *,
 static int     iwn_tx_data_raw(struct iwn_softc *, struct mbuf *,
                    struct ieee80211_node *,
                    const struct ieee80211_bpf_params *params);
+static int     iwn_tx_cmd(struct iwn_softc *, struct mbuf *,
+                   struct ieee80211_node *, struct iwn_tx_ring *);
 static void    iwn_xmit_task(void *arg0, int pending);
 static int     iwn_raw_xmit(struct ieee80211_node *, struct mbuf *,
                    const struct ieee80211_bpf_params *);
@@ -246,15 +245,15 @@ static int        iwn_set_link_quality(struct iwn_softc *,
                    struct ieee80211_node *);
 static int     iwn_add_broadcast_node(struct iwn_softc *, int);
 static int     iwn_updateedca(struct ieee80211com *);
+static void    iwn_set_promisc(struct iwn_softc *);
+static void    iwn_update_promisc(struct ieee80211com *);
 static void    iwn_update_mcast(struct ieee80211com *);
 static void    iwn_set_led(struct iwn_softc *, uint8_t, uint8_t, uint8_t);
 static int     iwn_set_critical_temp(struct iwn_softc *);
 static int     iwn_set_timing(struct iwn_softc *, struct ieee80211_node *);
 static void    iwn4965_power_calibration(struct iwn_softc *, int);
-static int     iwn4965_set_txpower(struct iwn_softc *,
-                   struct ieee80211_channel *, int);
-static int     iwn5000_set_txpower(struct iwn_softc *,
-                   struct ieee80211_channel *, int);
+static int     iwn4965_set_txpower(struct iwn_softc *, int);
+static int     iwn5000_set_txpower(struct iwn_softc *, int);
 static int     iwn4965_get_rssi(struct iwn_softc *, struct iwn_rx_stat *);
 static int     iwn5000_get_rssi(struct iwn_softc *, struct iwn_rx_stat *);
 static int     iwn_get_noise(const struct iwn_rx_general_stats *);
@@ -277,6 +276,10 @@ static int iwn_set_pslevel(struct iwn_softc *, int, int, 
int);
 static int     iwn_send_btcoex(struct iwn_softc *);
 static int     iwn_send_advanced_btcoex(struct iwn_softc *);
 static int     iwn5000_runtime_calib(struct iwn_softc *);
+static int     iwn_check_bss_filter(struct iwn_softc *);
+static int     iwn4965_rxon_assoc(struct iwn_softc *, int);
+static int     iwn5000_rxon_assoc(struct iwn_softc *, int);
+static int     iwn_send_rxon(struct iwn_softc *, int, int);
 static int     iwn_config(struct iwn_softc *);
 static int     iwn_scan(struct iwn_softc *, struct ieee80211vap *,
                    struct ieee80211_scan_state *, struct ieee80211_channel *);
@@ -331,11 +334,9 @@ static int iwn5000_nic_config(struct iwn_softc *);
 static int     iwn_hw_prepare(struct iwn_softc *);
 static int     iwn_hw_init(struct iwn_softc *);
 static void    iwn_hw_stop(struct iwn_softc *);
-static void    iwn_radio_on(void *, int);
-static void    iwn_radio_off(void *, int);
 static void    iwn_panicked(void *, int);
-static void    iwn_init_locked(struct iwn_softc *);
-static void    iwn_init(struct iwn_softc *);
+static int     iwn_init_locked(struct iwn_softc *);
+static int     iwn_init(struct iwn_softc *);
 static void    iwn_stop_locked(struct iwn_softc *);
 static void    iwn_stop(struct iwn_softc *);
 static void    iwn_scan_start(struct ieee80211com *);
@@ -368,7 +369,8 @@ static driver_t iwn_driver = {
 static devclass_t iwn_devclass;
 
 DRIVER_MODULE(iwn, pci, iwn_driver, iwn_devclass, NULL, NULL);
-
+MODULE_PNP_INFO("U16:vendor;U16:device;D:#", pci, iwn, iwn_ident_table,
+    nitems(iwn_ident_table) - 1);
 MODULE_VERSION(iwn, 1);
 
 MODULE_DEPEND(iwn, firmware, 1, 1, 1);
@@ -380,7 +382,7 @@ static d_ioctl_t iwn_cdev_ioctl;
 static d_open_t iwn_cdev_open;
 static d_close_t iwn_cdev_close;
 
-static struct cdevsw  = {
+static struct cdevsw iwn_cdevsw = {
        .d_version = D_VERSION,
        .d_flags = 0,
        .d_open = iwn_cdev_open,
@@ -664,6 +666,7 @@ iwn_attach(device_t dev)
        ic->ic_addba_stop = iwn_ampdu_tx_stop;
        ic->ic_newassoc = iwn_newassoc;
        ic->ic_wme.wme_update = iwn_updateedca;
+       ic->ic_update_promisc = iwn_update_promisc;
        ic->ic_update_mcast = iwn_update_mcast;
        ic->ic_scan_start = iwn_scan_start;
        ic->ic_scan_end = iwn_scan_end;
@@ -678,8 +681,7 @@ iwn_attach(device_t dev)
        callout_init_mtx(&sc->calib_to, &sc->sc_mtx, 0);
        callout_init_mtx(&sc->scan_timeout, &sc->sc_mtx, 0);
        callout_init_mtx(&sc->watchdog_to, &sc->sc_mtx, 0);
-       TASK_INIT(&sc->sc_radioon_task, 0, iwn_radio_on, sc);
-       TASK_INIT(&sc->sc_radiooff_task, 0, iwn_radio_off, sc);
+       TASK_INIT(&sc->sc_rftoggle_task, 0, iwn_rftoggle_task, sc);
        TASK_INIT(&sc->sc_panic_task, 0, iwn_panicked, sc);
        TASK_INIT(&sc->sc_xmit_task, 0, iwn_xmit_task, sc);
 
@@ -717,8 +719,8 @@ iwn_attach(device_t dev)
                ieee80211_announce(ic);
        DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__);
 
-       /* Add debug ioctl right at the end */
 #ifndef __HAIKU__
+       /* Add debug ioctl right at the end */
        sc->sc_cdev = make_dev(&iwn_cdevsw, device_get_unit(dev),
            UID_ROOT, GID_WHEEL, 0600, "%s", device_get_nameunit(dev));
        if (sc->sc_cdev == NULL) {
@@ -1235,6 +1237,7 @@ iwn4965_attach(struct iwn_softc *sc, uint16_t pid)
        ops->set_txpower = iwn4965_set_txpower;
        ops->init_gains = iwn4965_init_gains;
        ops->set_gains = iwn4965_set_gains;
+       ops->rxon_assoc = iwn4965_rxon_assoc;
        ops->add_node = iwn4965_add_node;
        ops->tx_done = iwn4965_tx_done;
        ops->ampdu_tx_start = iwn4965_ampdu_tx_start;
@@ -1279,6 +1282,7 @@ iwn5000_attach(struct iwn_softc *sc, uint16_t pid)
        ops->set_txpower = iwn5000_set_txpower;
        ops->init_gains = iwn5000_init_gains;
        ops->set_gains = iwn5000_set_gains;
+       ops->rxon_assoc = iwn5000_rxon_assoc;
        ops->add_node = iwn5000_add_node;
        ops->tx_done = iwn5000_tx_done;
        ops->ampdu_tx_start = iwn5000_ampdu_tx_start;
@@ -1405,10 +1409,9 @@ iwn_detach(device_t dev)
                iwn_xmit_queue_drain(sc);
                IWN_UNLOCK(sc);
 
-               ieee80211_draintask(&sc->sc_ic, &sc->sc_radioon_task);
-               ieee80211_draintask(&sc->sc_ic, &sc->sc_radiooff_task);
                iwn_stop(sc);
 
+               taskqueue_drain_all(sc->sc_tq);
                taskqueue_free(sc->sc_tq);
 
                callout_drain(&sc->watchdog_to);
@@ -2654,7 +2657,15 @@ iwn_read_eeprom_enhinfo(struct iwn_softc *sc)
 static struct ieee80211_node *
 iwn_node_alloc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN])
 {
-       return malloc(sizeof (struct iwn_node), M_80211_NODE,M_NOWAIT | M_ZERO);
+       struct iwn_node *wn;
+
+       wn = malloc(sizeof (struct iwn_node), M_80211_NODE, M_NOWAIT | M_ZERO);
+       if (wn == NULL)
+               return (NULL);
+
+       wn->id = IWN_ID_UNDEFINED;
+
+       return (&wn->ni);
 }
 
 static __inline int
@@ -2677,6 +2688,26 @@ rate2plcp(int rate)
        return 0;
 }
 
+static __inline uint8_t
+plcp2rate(const uint8_t rate_plcp)
+{
+       switch (rate_plcp) {
+       case 0xd:       return 12;
+       case 0xf:       return 18;
+       case 0x5:       return 24;
+       case 0x7:       return 36;
+       case 0x9:       return 48;
+       case 0xb:       return 72;
+       case 0x1:       return 96;
+       case 0x3:       return 108;
+       case 10:        return 2;
+       case 20:        return 4;
+       case 55:        return 11;
+       case 110:       return 22;
+       default:        return 0;
+       }
+}
+
 static int
 iwn_get_1stream_tx_antmask(struct iwn_softc *sc)
 {
@@ -2948,13 +2979,11 @@ iwn_calib_timeout(void *arg)
  * followed by an MPDU_RX_DONE notification.
  */
 static void
-iwn_rx_phy(struct iwn_softc *sc, struct iwn_rx_desc *desc,
-    struct iwn_rx_data *data)
+iwn_rx_phy(struct iwn_softc *sc, struct iwn_rx_desc *desc)
 {
        struct iwn_rx_stat *stat = (struct iwn_rx_stat *)(desc + 1);
 
        DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: received PHY stats\n", __func__);
-       bus_dmamap_sync(sc->rxq.data_dmat, data->map, BUS_DMASYNC_POSTREAD);
 
        /* Save RX statistics, they will be used on MPDU_RX_DONE. */
        memcpy(&sc->last_rx_stat, stat, sizeof (*stat));
@@ -2972,7 +3001,7 @@ iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc 
*desc,
        struct iwn_ops *ops = &sc->ops;
        struct ieee80211com *ic = &sc->sc_ic;
        struct iwn_rx_ring *ring = &sc->rxq;
-       struct ieee80211_frame *wh;
+       struct ieee80211_frame_min *wh;
        struct ieee80211_node *ni;
        struct mbuf *m, *m1;
        struct iwn_rx_stat *stat;
@@ -2994,8 +3023,6 @@ iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc 
*desc,
        } else
                stat = (struct iwn_rx_stat *)(desc + 1);
 
-       bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_POSTREAD);
-
        if (stat->cfg_phy_len > IWN_STAT_MAXLEN) {
                device_printf(sc->sc_dev,
                    "%s: invalid RX statistic header, len %d\n", __func__,
@@ -3076,9 +3103,9 @@ iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc 
*desc,
        m->m_pkthdr.len = m->m_len = len;
 
        /* Grab a reference to the source node. */
-       wh = mtod(m, struct ieee80211_frame *);
+       wh = mtod(m, struct ieee80211_frame_min *);
        if (len >= sizeof(struct ieee80211_frame_min))
-               ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min 
*)wh);
+               ni = ieee80211_find_rxnode(ic, wh);
        else
                ni = NULL;
        nf = (ni != NULL && ni->ni_vap->iv_state == IEEE80211_S_RUN &&
@@ -3088,6 +3115,7 @@ iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc 
*desc,
 
        if (ieee80211_radiotap_active(ic)) {
                struct iwn_rx_radiotap_header *tap = &sc->sc_rxtap;
+               uint32_t rate = le32toh(stat->rate);
 
                tap->wr_flags = 0;
                if (stat->flags & htole16(IWN_STAT_FLAG_SHPREAMBLE))
@@ -3095,24 +3123,11 @@ iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc 
*desc,
                tap->wr_dbm_antsignal = (int8_t)rssi;
                tap->wr_dbm_antnoise = (int8_t)nf;
                tap->wr_tsft = stat->tstamp;
-               switch (stat->rate) {
-               /* CCK rates. */
-               case  10: tap->wr_rate =   2; break;
-               case  20: tap->wr_rate =   4; break;
-               case  55: tap->wr_rate =  11; break;
-               case 110: tap->wr_rate =  22; break;
-               /* OFDM rates. */
-               case 0xd: tap->wr_rate =  12; break;
-               case 0xf: tap->wr_rate =  18; break;
-               case 0x5: tap->wr_rate =  24; break;
-               case 0x7: tap->wr_rate =  36; break;
-               case 0x9: tap->wr_rate =  48; break;
-               case 0xb: tap->wr_rate =  72; break;
-               case 0x1: tap->wr_rate =  96; break;
-               case 0x3: tap->wr_rate = 108; break;
-               /* Unknown rate: should not happen. */
-               default:  tap->wr_rate =   0;
-               }
+               if (rate & IWN_RFLAG_MCS) {
+                       tap->wr_rate = rate & IWN_RFLAG_RATE_MCS;
+                       tap->wr_rate |= IEEE80211_RATE_MCS;
+               } else
+                       tap->wr_rate = plcp2rate(rate & IWN_RFLAG_RATE);
        }
 
        /*
@@ -3122,7 +3137,7 @@ iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc 
*desc,
        if (sc->sc_beacon_wait) {
                uint8_t type, subtype;
                /* NB: Re-assign wh */
-               wh = mtod(m, struct ieee80211_frame *);
+               wh = mtod(m, struct ieee80211_frame_min *);
                type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
                subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
                /*
@@ -3161,8 +3176,7 @@ iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc 
*desc,
 
 /* Process an incoming Compressed BlockAck. */
 static void
-iwn_rx_compressed_ba(struct iwn_softc *sc, struct iwn_rx_desc *desc,
-    struct iwn_rx_data *data)
+iwn_rx_compressed_ba(struct iwn_softc *sc, struct iwn_rx_desc *desc)
 {
        struct ieee80211_ratectl_tx_status *txs = &sc->sc_txs;
        struct iwn_ops *ops = &sc->ops;
@@ -3181,8 +3195,6 @@ iwn_rx_compressed_ba(struct iwn_softc *sc, struct 
iwn_rx_desc *desc,
 
        DPRINTF(sc, IWN_DEBUG_TRACE | IWN_DEBUG_XMIT, "->%s begin\n", __func__);
 
-       bus_dmamap_sync(sc->rxq.data_dmat, data->map, BUS_DMASYNC_POSTREAD);
-
        qid = le16toh(ba->qid);
        txq = &sc->txq[ba->qid];
        tap = sc->qid2tap[ba->qid];
@@ -3267,8 +3279,7 @@ iwn_rx_compressed_ba(struct iwn_softc *sc, struct 
iwn_rx_desc *desc,
  * firmware on response to a CMD_CALIB_CONFIG command (5000 only).
  */
 static void
-iwn5000_rx_calib_results(struct iwn_softc *sc, struct iwn_rx_desc *desc,
-    struct iwn_rx_data *data)
+iwn5000_rx_calib_results(struct iwn_softc *sc, struct iwn_rx_desc *desc)
 {
        struct iwn_phy_calib *calib = (struct iwn_phy_calib *)(desc + 1);
        int len, idx = -1;
@@ -3277,12 +3288,11 @@ iwn5000_rx_calib_results(struct iwn_softc *sc, struct 
iwn_rx_desc *desc,
 
        /* Runtime firmware should not send such a notification. */
        if (sc->sc_flags & IWN_FLAG_CALIB_DONE){
-               DPRINTF(sc, IWN_DEBUG_TRACE, "->%s received after clib done\n",
-           __func__);
+               DPRINTF(sc, IWN_DEBUG_TRACE,
+                   "->%s received after calib done\n", __func__);
                return;
        }
        len = (le32toh(desc->len) & 0x3fff) - 4;
-       bus_dmamap_sync(sc->rxq.data_dmat, data->map, BUS_DMASYNC_POSTREAD);
 
        switch (calib->code) {
        case IWN5000_PHY_CALIB_DC:
@@ -3391,8 +3401,7 @@ iwn_stats_update(struct iwn_softc *sc, struct 
iwn_calib_state *calib,
  * The latter is sent by the firmware after each received beacon.
  */
 static void
-iwn_rx_statistics(struct iwn_softc *sc, struct iwn_rx_desc *desc,
-    struct iwn_rx_data *data)
+iwn_rx_statistics(struct iwn_softc *sc, struct iwn_rx_desc *desc)
 {
        struct iwn_ops *ops = &sc->ops;
        struct ieee80211com *ic = &sc->sc_ic;
@@ -3412,8 +3421,6 @@ iwn_rx_statistics(struct iwn_softc *sc, struct 
iwn_rx_desc *desc,
                return;
        }
 
-       bus_dmamap_sync(sc->rxq.data_dmat, data->map, BUS_DMASYNC_POSTREAD);
-
        DPRINTF(sc, IWN_DEBUG_CALIBRATE | IWN_DEBUG_STATS,
            "%s: received statistics, cmd %d, len %d\n",
            __func__, desc->type, le16toh(desc->len));
@@ -3501,11 +3508,7 @@ iwn4965_tx_done(struct iwn_softc *sc, struct iwn_rx_desc 
*desc,
     struct iwn_rx_data *data)
 {
        struct iwn4965_tx_stat *stat = (struct iwn4965_tx_stat *)(desc + 1);
-       struct iwn_tx_ring *ring;
-       int qid;
-
-       qid = desc->qid & 0xf;
-       ring = &sc->txq[qid];
+       int qid = desc->qid & IWN_RX_DESC_QID_MSK;
 
        DPRINTF(sc, IWN_DEBUG_XMIT, "%s: "
            "qid %d idx %d RTS retries %d ACK retries %d nkill %d rate %x 
duration %d status %x\n",
@@ -3516,7 +3519,6 @@ iwn4965_tx_done(struct iwn_softc *sc, struct iwn_rx_desc 
*desc,
            stat->rate, le16toh(stat->duration),
            le32toh(stat->status));
 
-       bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_POSTREAD);
        if (qid >= sc->firstaggqueue) {
                iwn_ampdu_tx_done(sc, qid, desc->idx, stat->nframes,
                    stat->rtsfailcnt, stat->ackfailcnt, &stat->status);
@@ -3531,11 +3533,7 @@ iwn5000_tx_done(struct iwn_softc *sc, struct iwn_rx_desc 
*desc,
     struct iwn_rx_data *data)
 {
        struct iwn5000_tx_stat *stat = (struct iwn5000_tx_stat *)(desc + 1);
-       struct iwn_tx_ring *ring;
-       int qid;
-
-       qid = desc->qid & 0xf;
-       ring = &sc->txq[qid];
+       int qid = desc->qid & IWN_RX_DESC_QID_MSK;
 
        DPRINTF(sc, IWN_DEBUG_XMIT, "%s: "
            "qid %d idx %d RTS retries %d ACK retries %d nkill %d rate %x 
duration %d status %x\n",
@@ -3548,10 +3546,9 @@ iwn5000_tx_done(struct iwn_softc *sc, struct iwn_rx_desc 
*desc,
 
 #ifdef notyet
        /* Reset TX scheduler slot. */
-       iwn5000_reset_sched(sc, desc->qid & 0xf, desc->idx);
+       iwn5000_reset_sched(sc, qid, desc->idx);
 #endif
 
-       bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_POSTREAD);
        if (qid >= sc->firstaggqueue) {
                iwn_ampdu_tx_done(sc, qid, desc->idx, stat->nframes,
                    stat->rtsfailcnt, stat->ackfailcnt, &stat->status);
@@ -3569,7 +3566,7 @@ iwn_tx_done(struct iwn_softc *sc, struct iwn_rx_desc 
*desc, int rtsfailcnt,
     int ackfailcnt, uint8_t status)
 {
        struct ieee80211_ratectl_tx_status *txs = &sc->sc_txs;
-       struct iwn_tx_ring *ring = &sc->txq[desc->qid & 0xf];
+       struct iwn_tx_ring *ring = &sc->txq[desc->qid & IWN_RX_DESC_QID_MSK];
        struct iwn_tx_data *data = &ring->data[desc->idx];
        struct mbuf *m;
        struct ieee80211_node *ni;
@@ -3843,16 +3840,16 @@ iwn_notif_intr(struct iwn_softc *sc)
 
                DPRINTF(sc, IWN_DEBUG_RECV,
                    "%s: cur=%d; qid %x idx %d flags %x type %d(%s) len %d\n",
-                   __func__, sc->rxq.cur, desc->qid & 0xf, desc->idx, 
desc->flags,
-                   desc->type, iwn_intr_str(desc->type),
-                   le16toh(desc->len));
+                   __func__, sc->rxq.cur, desc->qid & IWN_RX_DESC_QID_MSK,
+                   desc->idx, desc->flags, desc->type,
+                   iwn_intr_str(desc->type), le16toh(desc->len));
 
                if (!(desc->qid & IWN_UNSOLICITED_RX_NOTIF))    /* Reply to a 
command. */
                        iwn_cmd_done(sc, desc);
 
                switch (desc->type) {
                case IWN_RX_PHY:
-                       iwn_rx_phy(sc, desc, data);
+                       iwn_rx_phy(sc, desc);
                        break;
 
                case IWN_RX_DONE:               /* 4965AGN only. */
@@ -3863,7 +3860,7 @@ iwn_notif_intr(struct iwn_softc *sc)
 
                case IWN_RX_COMPRESSED_BA:
                        /* A Compressed BlockAck has been received. */
-                       iwn_rx_compressed_ba(sc, desc, data);
+                       iwn_rx_compressed_ba(sc, desc);
                        break;
 
                case IWN_TX_DONE:
@@ -3873,7 +3870,7 @@ iwn_notif_intr(struct iwn_softc *sc)
 
                case IWN_RX_STATISTICS:
                case IWN_BEACON_STATISTICS:
-                       iwn_rx_statistics(sc, desc, data);
+                       iwn_rx_statistics(sc, desc);
                        break;
 
                case IWN_BEACON_MISSED:
@@ -3882,8 +3879,6 @@ iwn_notif_intr(struct iwn_softc *sc)
                            (struct iwn_beacon_missed *)(desc + 1);
                        int misses;
 
-                       bus_dmamap_sync(sc->rxq.data_dmat, data->map,
-                           BUS_DMASYNC_POSTREAD);
                        misses = le32toh(miss->consecutive);
 
                        DPRINTF(sc, IWN_DEBUG_STATE,
@@ -3911,8 +3906,6 @@ iwn_notif_intr(struct iwn_softc *sc)
                            (struct iwn_ucode_info *)(desc + 1);
 
                        /* The microcontroller is ready. */
-                       bus_dmamap_sync(sc->rxq.data_dmat, data->map,
-                           BUS_DMASYNC_POSTREAD);
                        DPRINTF(sc, IWN_DEBUG_RESET,
                            "microcode alive notification version=%d.%d "
                            "subtype=%x alive=%x\n", uc->major, uc->minor,
@@ -3931,6 +3924,7 @@ iwn_notif_intr(struct iwn_softc *sc)
                        sc->errptr = le32toh(uc->errptr);
                        break;
                }
+#ifdef IWN_DEBUG
                case IWN_STATE_CHANGED:
                {
                        /*
@@ -3938,33 +3932,24 @@ iwn_notif_intr(struct iwn_softc *sc)
                         * noted. However, we handle this in iwn_intr as we
                         * get both the enable/disble intr.
                         */
-                       bus_dmamap_sync(sc->rxq.data_dmat, data->map,
-                           BUS_DMASYNC_POSTREAD);
-#ifdef IWN_DEBUG
                        uint32_t *status = (uint32_t *)(desc + 1);
                        DPRINTF(sc, IWN_DEBUG_INTR | IWN_DEBUG_STATE,
                            "state changed to %x\n",
                            le32toh(*status));
-#endif
                        break;
                }
                case IWN_START_SCAN:
                {
-                       bus_dmamap_sync(sc->rxq.data_dmat, data->map,
-                           BUS_DMASYNC_POSTREAD);
-#ifdef IWN_DEBUG
                        struct iwn_start_scan *scan =
                            (struct iwn_start_scan *)(desc + 1);
                        DPRINTF(sc, IWN_DEBUG_ANY,
                            "%s: scanning channel %d status %x\n",
                            __func__, scan->chan, le32toh(scan->status));
-#endif
                        break;
                }
+#endif
                case IWN_STOP_SCAN:
                {
-                       bus_dmamap_sync(sc->rxq.data_dmat, data->map,
-                           BUS_DMASYNC_POSTREAD);
 #ifdef IWN_DEBUG
                        struct iwn_stop_scan *scan =
                            (struct iwn_stop_scan *)(desc + 1);
@@ -3980,7 +3965,7 @@ iwn_notif_intr(struct iwn_softc *sc)
                        break;
                }
                case IWN5000_CALIBRATION_RESULT:
-                       iwn5000_rx_calib_results(sc, desc, data);
+                       iwn5000_rx_calib_results(sc, desc);
                        break;
 
                case IWN5000_CALIBRATION_DONE:
@@ -4018,19 +4003,28 @@ iwn_wakeup_intr(struct iwn_softc *sc)
 }
 
 static void
-iwn_rftoggle_intr(struct iwn_softc *sc)
+iwn_rftoggle_task(void *arg, int npending)
 {
+       struct iwn_softc *sc = arg;
        struct ieee80211com *ic = &sc->sc_ic;
-       uint32_t tmp = IWN_READ(sc, IWN_GP_CNTRL);
+       uint32_t tmp;
 
-       IWN_LOCK_ASSERT(sc);
+       IWN_LOCK(sc);
+       tmp = IWN_READ(sc, IWN_GP_CNTRL);
+       IWN_UNLOCK(sc);
 
        device_printf(sc->sc_dev, "RF switch: radio %s\n",
            (tmp & IWN_GP_CNTRL_RFKILL) ? "enabled" : "disabled");
-       if (tmp & IWN_GP_CNTRL_RFKILL)
-               ieee80211_runtask(ic, &sc->sc_radioon_task);
-       else
-               ieee80211_runtask(ic, &sc->sc_radiooff_task);
+       if (!(tmp & IWN_GP_CNTRL_RFKILL)) {
+               ieee80211_suspend_all(ic);
+
+               /* Enable interrupts to get RF toggle notification. */
+               IWN_LOCK(sc);
+               IWN_WRITE(sc, IWN_INT, 0xffffffff);
+               IWN_WRITE(sc, IWN_INT_MASK, sc->int_mask);
+               IWN_UNLOCK(sc);
+       } else
+               ieee80211_resume_all(ic);
 }
 
 /*
@@ -4103,7 +4097,7 @@ iwn_intr(void *arg)
 
        IWN_LOCK(sc);
 
-#if !defined(__HAIKU__)
+#ifndef __HAIKU__
        /* Disable interrupts. */
        IWN_WRITE(sc, IWN_INT_MASK, 0);
 
@@ -4149,7 +4143,7 @@ iwn_intr(void *arg)
                IWN_WRITE(sc, IWN_FH_INT, r2);
 
        if (r1 & IWN_INT_RF_TOGGLED) {
-               iwn_rftoggle_intr(sc);
+               taskqueue_enqueue(sc->sc_tq, &sc->sc_rftoggle_task);
                goto done;
        }
        if (r1 & IWN_INT_CT_REACHED) {
@@ -4375,32 +4369,25 @@ iwn_tx_rate_to_linkq_offset(struct iwn_softc *sc, 
struct ieee80211_node *ni,
 static int
 iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
 {
-       struct iwn_ops *ops = &sc->ops;
-       const struct ieee80211_txparam *tp;
+       const struct ieee80211_txparam *tp = ni->ni_txparms;
        struct ieee80211vap *vap = ni->ni_vap;
        struct ieee80211com *ic = ni->ni_ic;
        struct iwn_node *wn = (void *)ni;
        struct iwn_tx_ring *ring;
-       struct iwn_tx_desc *desc;
-       struct iwn_tx_data *data;
        struct iwn_tx_cmd *cmd;
        struct iwn_cmd_data *tx;
        struct ieee80211_frame *wh;
        struct ieee80211_key *k = NULL;
-       struct mbuf *m1;
        uint32_t flags;
-       uint16_t qos;
-       u_int hdrlen;
-       bus_dma_segment_t *seg, segs[IWN_MAX_SCATTER];
+       uint16_t seqno, qos;
        uint8_t tid, type;
-       int ac, i, totlen, error, pad, nsegs = 0, rate;
+       int ac, totlen, rate;
 
        DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__);
 
        IWN_LOCK_ASSERT(sc);
 
        wh = mtod(m, struct ieee80211_frame *);
-       hdrlen = ieee80211_anyhdrsize(wh);
        type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
 
        /* Select EDCA Access Category and TX ring for this frame. */
@@ -4411,13 +4398,35 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, 
struct ieee80211_node *ni)
                qos = 0;
                tid = 0;
        }
+
+       /* Choose a TX rate index. */
+       if (type == IEEE80211_FC0_TYPE_MGT ||
+           type == IEEE80211_FC0_TYPE_CTL ||
+           (m->m_flags & M_EAPOL) != 0)
+               rate = tp->mgmtrate;
+       else if (IEEE80211_IS_MULTICAST(wh->i_addr1))
+               rate = tp->mcastrate;
+       else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE)
+               rate = tp->ucastrate;
+       else {
+               /* XXX pass pktlen */
+               (void) ieee80211_ratectl_rate(ni, NULL, 0);
+               rate = ni->ni_txrate;
+       }
+
+       /*
+        * XXX TODO: Group addressed frames aren't aggregated and must
+        * go to the normal non-aggregation queue, and have a NONQOS TID
+        * assigned from net80211.
+        */
+
        ac = M_WME_GETAC(m);
+       seqno = ni->ni_txseqs[tid];
        if (m->m_flags & M_AMPDU_MPDU) {
-               uint16_t seqno;
                struct ieee80211_tx_ampdu *tap = &ni->ni_tx_ampdu[ac];
 
                if (!IEEE80211_AMPDU_RUNNING(tap)) {
-                       return EINVAL;
+                       return (EINVAL);
                }
 
                /*
@@ -4428,40 +4437,10 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, 
struct ieee80211_node *ni)
                 * being used!
                 */
                ac = *(int *)tap->txa_private;
-               seqno = ni->ni_txseqs[tid];
                *(uint16_t *)wh->i_seq =
                    htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT);
-               ring = &sc->txq[ac];
-               if ((seqno % 256) != ring->cur) {
-                       device_printf(sc->sc_dev,
-                           "%s: m=%p: seqno (%d) (%d) != ring index (%d) !\n",
-                           __func__,
-                           m,
-                           seqno,
-                           seqno % 256,
-                           ring->cur);
-               }
                ni->ni_txseqs[tid]++;
        }
-       ring = &sc->txq[ac];
-       desc = &ring->desc[ring->cur];
-       data = &ring->data[ring->cur];
-
-       /* Choose a TX rate index. */
-       tp = &vap->iv_txparms[ieee80211_chan2mode(ni->ni_chan)];
-       if (type == IEEE80211_FC0_TYPE_MGT)
-               rate = tp->mgmtrate;
-       else if (IEEE80211_IS_MULTICAST(wh->i_addr1))
-               rate = tp->mcastrate;
-       else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE)
-               rate = tp->ucastrate;
-       else if (m->m_flags & M_EAPOL)
-               rate = tp->mgmtrate;
-       else {
-               /* XXX pass pktlen */
-               (void) ieee80211_ratectl_rate(ni, NULL, 0);
-               rate = ni->ni_txrate;
-       }
 
        /* Encrypt the frame if need be. */
        if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
@@ -4486,17 +4465,6 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct 
ieee80211_node *ni)
                ieee80211_radiotap_tx(vap, m);
        }
 
-       /* Prepare TX firmware command. */
-       cmd = &ring->cmd[ring->cur];
-       cmd->code = IWN_CMD_TX_DATA;
-       cmd->flags = 0;
-       cmd->qid = ring->qid;
-       cmd->idx = ring->cur;
-
-       tx = (struct iwn_cmd_data *)cmd->data;
-       /* NB: No need to clear tx, all fields are reinitialized here. */
-       tx->scratch = 0;        /* clear "scratch" area */
-
        flags = 0;
        if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
                /* Unicast frame, check if an ACK is expected. */
@@ -4539,6 +4507,25 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct 
ieee80211_node *ni)
                }
        }
 
+       ring = &sc->txq[ac];
+       if ((m->m_flags & M_AMPDU_MPDU) != 0 &&
+           (seqno % 256) != ring->cur) {
+               device_printf(sc->sc_dev,
+                   "%s: m=%p: seqno (%d) (%d) != ring index (%d) !\n",
+                   __func__,
+                   m,
+                   seqno,
+                   seqno % 256,
+                   ring->cur);
+       }
+
+       /* Prepare TX firmware command. */
+       cmd = &ring->cmd[ring->cur];
+       tx = (struct iwn_cmd_data *)cmd->data;
+
+       /* NB: No need to clear tx, all fields are reinitialized here. */
+       tx->scratch = 0;        /* clear "scratch" area */
+
        if (IEEE80211_IS_MULTICAST(wh->i_addr1) ||
            type != IEEE80211_FC0_TYPE_DATA)
                tx->id = sc->broadcast_id;
@@ -4559,19 +4546,6 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct 
ieee80211_node *ni)
        } else
                tx->timeout = htole16(0);
 
-       if (hdrlen & 3) {
-               /* First segment length must be a multiple of 4. */
-               flags |= IWN_TX_NEED_PADDING;
-               pad = 4 - (hdrlen & 3);
-       } else
-               pad = 0;
-
-       tx->len = htole16(totlen);
-       tx->tid = tid;
-       tx->rts_ntries = 60;
-       tx->data_ntries = 15;
-       tx->lifetime = htole32(IWN_LIFETIME_INFINITE);
-       tx->rate = iwn_rate_to_plcp(sc, ni, rate);
        if (tx->id == sc->broadcast_id) {
                /* Group or management frame. */
                tx->linkq = 0;
@@ -4580,115 +4554,28 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, 
struct ieee80211_node *ni)
                flags |= IWN_TX_LINKQ;  /* enable MRR */
        }
 
-       /* Set physical address of "scratch area". */
-       tx->loaddr = htole32(IWN_LOADDR(data->scratch_paddr));
-       tx->hiaddr = IWN_HIADDR(data->scratch_paddr);
-
-       /* Copy 802.11 header in TX command. */
-       memcpy((uint8_t *)(tx + 1), wh, hdrlen);
-
-       /* Trim 802.11 header. */
-       m_adj(m, hdrlen);
+       tx->tid = tid;
+       tx->rts_ntries = 60;
+       tx->data_ntries = 15;
+       tx->lifetime = htole32(IWN_LIFETIME_INFINITE);
+       tx->rate = iwn_rate_to_plcp(sc, ni, rate);
        tx->security = 0;
        tx->flags = htole32(flags);
 
-       error = bus_dmamap_load_mbuf_sg(ring->data_dmat, data->map, m, segs,
-           &nsegs, BUS_DMA_NOWAIT);
-       if (error != 0) {
-               if (error != EFBIG) {
-                       device_printf(sc->sc_dev,
-                           "%s: can't map mbuf (error %d)\n", __func__, error);
-                       return error;
-               }
-               /* Too many DMA segments, linearize mbuf. */
-               m1 = m_collapse(m, M_NOWAIT, IWN_MAX_SCATTER - 1);
-               if (m1 == NULL) {
-                       device_printf(sc->sc_dev,
-                           "%s: could not defrag mbuf\n", __func__);
-                       return ENOBUFS;
-               }
-               m = m1;
-
-               error = bus_dmamap_load_mbuf_sg(ring->data_dmat, data->map, m,
-                   segs, &nsegs, BUS_DMA_NOWAIT);
-               if (error != 0) {
-                       device_printf(sc->sc_dev,
-                           "%s: can't map mbuf (error %d)\n", __func__, error);
-                       return error;
-               }
-       }
-
-       data->m = m;
-       data->ni = ni;
-
-       DPRINTF(sc, IWN_DEBUG_XMIT,
-           "%s: qid %d idx %d len %d nsegs %d flags 0x%08x rate 0x%04x plcp 
0x%08x\n",
-           __func__,
-           ring->qid,
-           ring->cur,
-           m->m_pkthdr.len,
-           nsegs,
-           flags,
-           rate,
-           tx->rate);
-
-       /* Fill TX descriptor. */
-       desc->nsegs = 1;
-       if (m->m_len != 0)
-               desc->nsegs += nsegs;
-       /* First DMA segment is used by the TX command. */
-       desc->segs[0].addr = htole32(IWN_LOADDR(data->cmd_paddr));
-       desc->segs[0].len  = htole16(IWN_HIADDR(data->cmd_paddr) |
-           (4 + sizeof (*tx) + hdrlen + pad) << 4);
-       /* Other DMA segments are for data payload. */
-       seg = &segs[0];
-       for (i = 1; i <= nsegs; i++) {
-               desc->segs[i].addr = htole32(IWN_LOADDR(seg->ds_addr));
-               desc->segs[i].len  = htole16(IWN_HIADDR(seg->ds_addr) |
-                   seg->ds_len << 4);
-               seg++;
-       }
-
-       bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_PREWRITE);
-       bus_dmamap_sync(ring->cmd_dma.tag, ring->cmd_dma.map,
-           BUS_DMASYNC_PREWRITE);
-       bus_dmamap_sync(ring->desc_dma.tag, ring->desc_dma.map,
-           BUS_DMASYNC_PREWRITE);
-
-       /* Update TX scheduler. */
-       if (ring->qid >= sc->firstaggqueue)
-               ops->update_sched(sc, ring->qid, ring->cur, tx->id, totlen);
-
-       /* Kick TX ring. */
-       ring->cur = (ring->cur + 1) % IWN_TX_RING_COUNT;
-       IWN_WRITE(sc, IWN_HBUS_TARG_WRPTR, ring->qid << 8 | ring->cur);
-
-       /* Mark TX ring as full if we reach a certain threshold. */
-       if (++ring->queued > IWN_TX_RING_HIMARK)
-               sc->qfullmsk |= 1 << ring->qid;
-
-       DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__);
-
-       return 0;
+       return (iwn_tx_cmd(sc, m, ni, ring));
 }
 
 static int
 iwn_tx_data_raw(struct iwn_softc *sc, struct mbuf *m,
     struct ieee80211_node *ni, const struct ieee80211_bpf_params *params)
 {
-       struct iwn_ops *ops = &sc->ops;
        struct ieee80211vap *vap = ni->ni_vap;
        struct iwn_tx_cmd *cmd;
        struct iwn_cmd_data *tx;
        struct ieee80211_frame *wh;
        struct iwn_tx_ring *ring;
-       struct iwn_tx_desc *desc;
-       struct iwn_tx_data *data;
-       struct mbuf *m1;
-       bus_dma_segment_t *seg, segs[IWN_MAX_SCATTER];
        uint32_t flags;
-       u_int hdrlen;
-       int ac, totlen, error, pad, nsegs = 0, i, rate;
+       int ac, rate;
        uint8_t type;
 
        DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__);
@@ -4696,29 +4583,12 @@ iwn_tx_data_raw(struct iwn_softc *sc, struct mbuf *m,
        IWN_LOCK_ASSERT(sc);
 
        wh = mtod(m, struct ieee80211_frame *);
-       hdrlen = ieee80211_anyhdrsize(wh);
        type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
 
        ac = params->ibp_pri & 3;
 
-       ring = &sc->txq[ac];
-       desc = &ring->desc[ring->cur];
-       data = &ring->data[ring->cur];
-
        /* Choose a TX rate. */
        rate = params->ibp_rate0;
-       totlen = m->m_pkthdr.len;
-
-       /* Prepare TX firmware command. */
-       cmd = &ring->cmd[ring->cur];
-       cmd->code = IWN_CMD_TX_DATA;
-       cmd->flags = 0;
-       cmd->qid = ring->qid;
-       cmd->idx = ring->cur;
-
-       tx = (struct iwn_cmd_data *)cmd->data;
-       /* NB: No need to clear tx, all fields are reinitialized here. */
-       tx->scratch = 0;        /* clear "scratch" area */
 
        flags = 0;
        if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0)
@@ -4739,30 +4609,9 @@ iwn_tx_data_raw(struct iwn_softc *sc, struct mbuf *m,
                } else
                        flags |= IWN_TX_NEED_CTS | IWN_TX_FULL_TXOP;
        }
-       if (type == IEEE80211_FC0_TYPE_MGT) {
-               uint8_t subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
 
-               /* Tell HW to set timestamp in probe responses. */
-               if (subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP)
-                       flags |= IWN_TX_INSERT_TSTAMP;
-
-               if (subtype == IEEE80211_FC0_SUBTYPE_ASSOC_REQ ||
-                   subtype == IEEE80211_FC0_SUBTYPE_REASSOC_REQ)
-                       tx->timeout = htole16(3);
-               else
-                       tx->timeout = htole16(2);
-       } else
-               tx->timeout = htole16(0);
-
-       if (hdrlen & 3) {
-               /* First segment length must be a multiple of 4. */
-               flags |= IWN_TX_NEED_PADDING;
-               pad = 4 - (hdrlen & 3);
-       } else
-               pad = 0;
-
-       if (ieee80211_radiotap_active_vap(vap)) {
-               struct iwn_tx_radiotap_header *tap = &sc->sc_txtap;
+       if (ieee80211_radiotap_active_vap(vap)) {
+               struct iwn_tx_radiotap_header *tap = &sc->sc_txtap;
 
                tap->wt_flags = 0;
                tap->wt_rate = rate;
@@ -4770,28 +4619,90 @@ iwn_tx_data_raw(struct iwn_softc *sc, struct mbuf *m,
                ieee80211_radiotap_tx(vap, m);
        }
 
-       tx->len = htole16(totlen);
+       ring = &sc->txq[ac];
+       cmd = &ring->cmd[ring->cur];
+
+       tx = (struct iwn_cmd_data *)cmd->data;
+       /* NB: No need to clear tx, all fields are reinitialized here. */
+       tx->scratch = 0;        /* clear "scratch" area */
+
+       if (type == IEEE80211_FC0_TYPE_MGT) {
+               uint8_t subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
+
+               /* Tell HW to set timestamp in probe responses. */
+               if (subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP)
+                       flags |= IWN_TX_INSERT_TSTAMP;
+
+               if (subtype == IEEE80211_FC0_SUBTYPE_ASSOC_REQ ||
+                   subtype == IEEE80211_FC0_SUBTYPE_REASSOC_REQ)
+                       tx->timeout = htole16(3);
+               else
+                       tx->timeout = htole16(2);
+       } else
+               tx->timeout = htole16(0);
+
        tx->tid = 0;
        tx->id = sc->broadcast_id;
        tx->rts_ntries = params->ibp_try1;
        tx->data_ntries = params->ibp_try0;
        tx->lifetime = htole32(IWN_LIFETIME_INFINITE);
        tx->rate = iwn_rate_to_plcp(sc, ni, rate);
+       tx->security = 0;
+       tx->flags = htole32(flags);
 
        /* Group or management frame. */
        tx->linkq = 0;
 
+       return (iwn_tx_cmd(sc, m, ni, ring));
+}
+
+static int
+iwn_tx_cmd(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni,
+    struct iwn_tx_ring *ring)
+{
+       struct iwn_ops *ops = &sc->ops;
+       struct iwn_tx_cmd *cmd;
+       struct iwn_cmd_data *tx;
+       struct ieee80211_frame *wh;
+       struct iwn_tx_desc *desc;
+       struct iwn_tx_data *data;
+       bus_dma_segment_t *seg, segs[IWN_MAX_SCATTER];
+       struct mbuf *m1;
+       u_int hdrlen;
+       int totlen, error, pad, nsegs = 0, i;
+
+       wh = mtod(m, struct ieee80211_frame *);
+       hdrlen = ieee80211_anyhdrsize(wh);
+       totlen = m->m_pkthdr.len;
+
+       desc = &ring->desc[ring->cur];
+       data = &ring->data[ring->cur];
+
+       /* Prepare TX firmware command. */
+       cmd = &ring->cmd[ring->cur];
+       cmd->code = IWN_CMD_TX_DATA;
+       cmd->flags = 0;
+       cmd->qid = ring->qid;
+       cmd->idx = ring->cur;
+
+       tx = (struct iwn_cmd_data *)cmd->data;
+       tx->len = htole16(totlen);
+
        /* Set physical address of "scratch area". */
        tx->loaddr = htole32(IWN_LOADDR(data->scratch_paddr));
        tx->hiaddr = IWN_HIADDR(data->scratch_paddr);
+       if (hdrlen & 3) {
+               /* First segment length must be a multiple of 4. */
+               tx->flags |= htole32(IWN_TX_NEED_PADDING);
+               pad = 4 - (hdrlen & 3);
+       } else
+               pad = 0;
 
        /* Copy 802.11 header in TX command. */
        memcpy((uint8_t *)(tx + 1), wh, hdrlen);
 
        /* Trim 802.11 header. */
        m_adj(m, hdrlen);
-       tx->security = 0;
-       tx->flags = htole32(flags);
 
        error = bus_dmamap_load_mbuf_sg(ring->data_dmat, data->map, m, segs,
            &nsegs, BUS_DMA_NOWAIT);
@@ -4813,17 +4724,28 @@ iwn_tx_data_raw(struct iwn_softc *sc, struct mbuf *m,
                error = bus_dmamap_load_mbuf_sg(ring->data_dmat, data->map, m,
                    segs, &nsegs, BUS_DMA_NOWAIT);
                if (error != 0) {
+                       /* XXX fix this */
+                       /*
+                        * NB: Do not return error;
+                        * original mbuf does not exist anymore.
+                        */
                        device_printf(sc->sc_dev,
-                           "%s: can't map mbuf (error %d)\n", __func__, error);
-                       return error;
+                           "%s: can't map mbuf (error %d)\n",
+                           __func__, error);
+                       if_inc_counter(ni->ni_vap->iv_ifp,
+                           IFCOUNTER_OERRORS, 1);
+                       ieee80211_free_node(ni);
+                       m_freem(m);
+                       return 0;
                }
        }
 
        data->m = m;
        data->ni = ni;
 
-       DPRINTF(sc, IWN_DEBUG_XMIT, "%s: qid %d idx %d len %d nsegs %d\n",
-           __func__, ring->qid, ring->cur, m->m_pkthdr.len, nsegs);
+       DPRINTF(sc, IWN_DEBUG_XMIT, "%s: qid %d idx %d len %d nsegs %d "
+           "plcp %d\n",
+           __func__, ring->qid, ring->cur, totlen, nsegs, tx->rate);
 
        /* Fill TX descriptor. */
        desc->nsegs = 1;
@@ -5089,25 +5011,28 @@ static void
 iwn_parent(struct ieee80211com *ic)
 {
        struct iwn_softc *sc = ic->ic_softc;
-       struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
-       int startall = 0, stop = 0;
+       struct ieee80211vap *vap;
+       int error;
 
-       IWN_LOCK(sc);
        if (ic->ic_nrunning > 0) {
-               if (!(sc->sc_flags & IWN_FLAG_RUNNING)) {
-                       iwn_init_locked(sc);
-                       if (IWN_READ(sc, IWN_GP_CNTRL) & IWN_GP_CNTRL_RFKILL)
-                               startall = 1;
-                       else
-                               stop = 1;
+               error = iwn_init(sc);
+
+               switch (error) {
+               case 0:
+                       ieee80211_start_all(ic);
+                       break;
+               case 1:
+                       /* radio is disabled via RFkill switch */
+                       taskqueue_enqueue(sc->sc_tq, &sc->sc_rftoggle_task);
+                       break;
+               default:
+                       vap = TAILQ_FIRST(&ic->ic_vaps);
+                       if (vap != NULL)
+                               ieee80211_stop(vap);
+                       break;
                }
-       } else if (sc->sc_flags & IWN_FLAG_RUNNING)
-               iwn_stop_locked(sc);
-       IWN_UNLOCK(sc);
-       if (startall)
-               ieee80211_start_all(ic);
-       else if (vap != NULL && stop)
-               ieee80211_stop(vap);
+       } else
+               iwn_stop(sc);
 }
 
 /*
@@ -5390,17 +5315,19 @@ iwn_updateedca(struct ieee80211com *ic)
 #define IWN_EXP2(x)    ((1 << (x)) - 1)        /* CWmin = 2^ECWmin - 1 */
        struct iwn_softc *sc = ic->ic_softc;
        struct iwn_edca_params cmd;
+       struct chanAccParams chp;
        int aci;
 
        DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__);
 
+       ieee80211_wme_ic_getparams(ic, &chp);
+
        memset(&cmd, 0, sizeof cmd);
        cmd.flags = htole32(IWN_EDCA_UPDATE);
 
        IEEE80211_LOCK(ic);
        for (aci = 0; aci < WME_NUM_AC; aci++) {
-               const struct wmeParams *ac =
-                   &ic->ic_wme.wme_chanParams.cap_wmeParams[aci];
+               const struct wmeParams *ac = &chp.cap_wmeParams[aci];
                cmd.ac[aci].aifsn = ac->wmep_aifsn;
                cmd.ac[aci].cwmin = htole16(IWN_EXP2(ac->wmep_logcwmin));
                cmd.ac[aci].cwmax = htole16(IWN_EXP2(ac->wmep_logcwmax));
@@ -5419,6 +5346,43 @@ iwn_updateedca(struct ieee80211com *ic)
 #undef IWN_EXP2
 }
 
+static void
+iwn_set_promisc(struct iwn_softc *sc)
+{
+       struct ieee80211com *ic = &sc->sc_ic;
+       uint32_t promisc_filter;
+
+       promisc_filter = IWN_FILTER_CTL | IWN_FILTER_PROMISC;
+       if (ic->ic_promisc > 0 || ic->ic_opmode == IEEE80211_M_MONITOR)
+               sc->rxon->filter |= htole32(promisc_filter);
+       else
+               sc->rxon->filter &= ~htole32(promisc_filter);
+}
+
+static void
+iwn_update_promisc(struct ieee80211com *ic)
+{
+       struct iwn_softc *sc = ic->ic_softc;
+       int error;
+
+       if (ic->ic_opmode == IEEE80211_M_MONITOR)
+               return;         /* nothing to do */
+
+       IWN_LOCK(sc);
+       if (!(sc->sc_flags & IWN_FLAG_RUNNING)) {
+               IWN_UNLOCK(sc);
+               return;
+       }
+
+       iwn_set_promisc(sc);
+       if ((error = iwn_send_rxon(sc, 1, 1)) != 0) {
+               device_printf(sc->sc_dev,
+                   "%s: could not send RXON, error %d\n",
+                   __func__, error);
+       }
+       IWN_UNLOCK(sc);
+}
+
 static void
 iwn_update_mcast(struct ieee80211com *ic)
 {
@@ -5501,7 +5465,6 @@ iwn_set_timing(struct iwn_softc *sc, struct 
ieee80211_node *ni)
 static void
 iwn4965_power_calibration(struct iwn_softc *sc, int temp)
 {
-       struct ieee80211com *ic = &sc->sc_ic;
 
        DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__);
 
@@ -5511,7 +5474,7 @@ iwn4965_power_calibration(struct iwn_softc *sc, int temp)
        if (abs(temp - sc->temp) >= 3) {
                /* Record temperature of last calibration. */
                sc->temp = temp;
-               (void)iwn4965_set_txpower(sc, ic->ic_bsschan, 1);
+               (void)iwn4965_set_txpower(sc, 1);
        }
 }
 
@@ -5521,8 +5484,7 @@ iwn4965_power_calibration(struct iwn_softc *sc, int temp)
  * the current temperature and the current voltage.
  */
 static int
-iwn4965_set_txpower(struct iwn_softc *sc, struct ieee80211_channel *ch,
-    int async)
+iwn4965_set_txpower(struct iwn_softc *sc, int async)
 {
 /* Fixed-point arithmetic division using a n-bit fractional part. */
 #define fdivround(a, b, n)     \
@@ -5537,20 +5499,21 @@ iwn4965_set_txpower(struct iwn_softc *sc, struct 
ieee80211_channel *ch,
        struct iwn4965_eeprom_chan_samples *chans;
        const uint8_t *rf_gain, *dsp_gain;
        int32_t vdiff, tdiff;
-       int i, c, grp, maxpwr;
+       int i, is_chan_5ghz, c, grp, maxpwr;
        uint8_t chan;
 
        sc->rxon = &sc->rx_on[IWN_RXON_BSS_CTX];
        /* Retrieve current channel from last RXON. */
        chan = sc->rxon->chan;
+       is_chan_5ghz = (sc->rxon->flags & htole32(IWN_RXON_24GHZ)) == 0;
        DPRINTF(sc, IWN_DEBUG_RESET, "setting TX power for channel %d\n",
            chan);
 
        memset(&cmd, 0, sizeof cmd);
-       cmd.band = IEEE80211_IS_CHAN_5GHZ(ch) ? 0 : 1;
+       cmd.band = is_chan_5ghz ? 0 : 1;
        cmd.chan = chan;
 
-       if (IEEE80211_IS_CHAN_5GHZ(ch)) {
+       if (is_chan_5ghz) {
                maxpwr   = sc->maxpwr5GHz;
                rf_gain  = iwn4965_rf_gain_5ghz;
                dsp_gain = iwn4965_dsp_gain_5ghz;
@@ -5672,8 +5635,7 @@ iwn4965_set_txpower(struct iwn_softc *sc, struct 
ieee80211_channel *ch,
 }
 
 static int
-iwn5000_set_txpower(struct iwn_softc *sc, struct ieee80211_channel *ch,
-    int async)
+iwn5000_set_txpower(struct iwn_softc *sc, int async)
 {
        struct iwn5000_cmd_txpower cmd;
        int cmdid;
@@ -6529,9 +6491,108 @@ iwn_get_rxon_ht_flags(struct iwn_softc *sc, struct 
ieee80211_channel *c)
 }
 
 static int
-iwn_config(struct iwn_softc *sc)
+iwn_check_bss_filter(struct iwn_softc *sc)
+{
+       return ((sc->rxon->filter & htole32(IWN_FILTER_BSS)) != 0);
+}
+
+static int
+iwn4965_rxon_assoc(struct iwn_softc *sc, int async)
+{
+       struct iwn4965_rxon_assoc cmd;
+       struct iwn_rxon *rxon = sc->rxon;
+
+       cmd.flags = rxon->flags;
+       cmd.filter = rxon->filter;
+       cmd.ofdm_mask = rxon->ofdm_mask;
+       cmd.cck_mask = rxon->cck_mask;
+       cmd.ht_single_mask = rxon->ht_single_mask;
+       cmd.ht_dual_mask = rxon->ht_dual_mask;
+       cmd.rxchain = rxon->rxchain;
+       cmd.reserved = 0;
+
+       return (iwn_cmd(sc, IWN_CMD_RXON_ASSOC, &cmd, sizeof(cmd), async));
+}
+
+static int
+iwn5000_rxon_assoc(struct iwn_softc *sc, int async)
+{
+       struct iwn5000_rxon_assoc cmd;
+       struct iwn_rxon *rxon = sc->rxon;
+
+       cmd.flags = rxon->flags;
+       cmd.filter = rxon->filter;
+       cmd.ofdm_mask = rxon->ofdm_mask;
+       cmd.cck_mask = rxon->cck_mask;
+       cmd.reserved1 = 0;
+       cmd.ht_single_mask = rxon->ht_single_mask;
+       cmd.ht_dual_mask = rxon->ht_dual_mask;
+       cmd.ht_triple_mask = rxon->ht_triple_mask;
+       cmd.reserved2 = 0;
+       cmd.rxchain = rxon->rxchain;
+       cmd.acquisition = rxon->acquisition;
+       cmd.reserved3 = 0;
+
+       return (iwn_cmd(sc, IWN_CMD_RXON_ASSOC, &cmd, sizeof(cmd), async));
+}
+
+static int
+iwn_send_rxon(struct iwn_softc *sc, int assoc, int async)
 {
        struct iwn_ops *ops = &sc->ops;
+       int error;
+
+       IWN_LOCK_ASSERT(sc);
+
+       if (assoc && iwn_check_bss_filter(sc) != 0) {
+               error = ops->rxon_assoc(sc, async);
+               if (error != 0) {
+                       device_printf(sc->sc_dev,
+                           "%s: RXON_ASSOC command failed, error %d\n",
+                           __func__, error);
+                       return (error);
+               }
+       } else {
+               if (sc->sc_is_scanning)
+                       device_printf(sc->sc_dev,
+                           "%s: is_scanning set, before RXON\n",
+                           __func__);
+
+               error = iwn_cmd(sc, IWN_CMD_RXON, sc->rxon, sc->rxonsz, async);
+               if (error != 0) {
+                       device_printf(sc->sc_dev,
+                           "%s: RXON command failed, error %d\n",
+                           __func__, error);
+                       return (error);
+               }
+
+               /*
+                * Reconfiguring RXON clears the firmware nodes table so
+                * we must add the broadcast node again.
+                */
+               if (iwn_check_bss_filter(sc) == 0 &&
+                   (error = iwn_add_broadcast_node(sc, async)) != 0) {
+                       device_printf(sc->sc_dev,
+                           "%s: could not add broadcast node, error %d\n",
+                           __func__, error);
+                       return (error);
+               }
+       }
+
+       /* Configuration has changed, set TX power accordingly. */
+       if ((error = ops->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);
+}
+
+static int
+iwn_config(struct iwn_softc *sc)
+{
        struct ieee80211com *ic = &sc->sc_ic;
        struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
        const uint8_t *macaddr;
@@ -6623,20 +6684,20 @@ iwn_config(struct iwn_softc *sc)
        sc->rxon->flags = htole32(IWN_RXON_TSF | IWN_RXON_CTS_TO_SELF);
        if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
                sc->rxon->flags |= htole32(IWN_RXON_AUTO | IWN_RXON_24GHZ);
+
+       sc->rxon->filter = htole32(IWN_FILTER_MULTICAST);
        switch (ic->ic_opmode) {
        case IEEE80211_M_STA:
                sc->rxon->mode = IWN_MODE_STA;
-               sc->rxon->filter = htole32(IWN_FILTER_MULTICAST);
                break;
        case IEEE80211_M_MONITOR:
                sc->rxon->mode = IWN_MODE_MONITOR;
-               sc->rxon->filter = htole32(IWN_FILTER_MULTICAST |
-                   IWN_FILTER_CTL | IWN_FILTER_PROMISC);
                break;
        default:
                /* Should not get there. */
                break;
        }
+       iwn_set_promisc(sc);
        sc->rxon->cck_mask  = 0x0f;     /* not yet negotiated */
        sc->rxon->ofdm_mask = 0xff;     /* not yet negotiated */
        sc->rxon->ht_single_mask = 0xff;
@@ -6666,26 +6727,8 @@ iwn_config(struct iwn_softc *sc)
        DPRINTF(sc, IWN_DEBUG_RESET,
            "%s: setting configuration; flags=0x%08x\n",
            __func__, le32toh(sc->rxon->flags));
-       if (sc->sc_is_scanning)
-               device_printf(sc->sc_dev,
-                   "%s: is_scanning set, before RXON\n",
-                   __func__);
-       error = iwn_cmd(sc, IWN_CMD_RXON, sc->rxon, sc->rxonsz, 0);
-       if (error != 0) {
-               device_printf(sc->sc_dev, "%s: RXON command failed\n",
-                   __func__);
-               return error;
-       }
-
-       if ((error = iwn_add_broadcast_node(sc, 0)) != 0) {
-               device_printf(sc->sc_dev, "%s: could not add broadcast node\n",
-                   __func__);
-               return error;
-       }
-
-       /* Configuration has changed, set TX power accordingly. */
-       if ((error = ops->set_txpower(sc, ic->ic_curchan, 0)) != 0) {
-               device_printf(sc->sc_dev, "%s: could not set TX power\n",
+       if ((error = iwn_send_rxon(sc, 0, 0)) != 0) {
+               device_printf(sc->sc_dev, "%s: could not send RXON\n",
                    __func__);
                return error;
        }
@@ -7039,7 +7082,6 @@ iwn_scan(struct iwn_softc *sc, struct ieee80211vap *vap,
 static int
 iwn_auth(struct iwn_softc *sc, struct ieee80211vap *vap)
 {
-       struct iwn_ops *ops = &sc->ops;
        struct ieee80211com *ic = &sc->sc_ic;
        struct ieee80211_node *ni = vap->iv_bss;
        int error;
@@ -7075,37 +7117,16 @@ iwn_auth(struct iwn_softc *sc, struct ieee80211vap *vap)
        DPRINTF(sc, IWN_DEBUG_STATE, "rxon chan %d flags %x cck %x ofdm %x\n",
            sc->rxon->chan, sc->rxon->flags, sc->rxon->cck_mask,
            sc->rxon->ofdm_mask);
-       if (sc->sc_is_scanning)
-               device_printf(sc->sc_dev,
-                   "%s: is_scanning set, before RXON\n",
-                   __func__);
-       error = iwn_cmd(sc, IWN_CMD_RXON, sc->rxon, sc->rxonsz, 1);
-       if (error != 0) {
-               device_printf(sc->sc_dev, "%s: RXON command failed, error %d\n",
-                   __func__, error);
-               return error;
-       }
 
-       /* Configuration has changed, set TX power accordingly. */
-       if ((error = ops->set_txpower(sc, ni->ni_chan, 1)) != 0) {
-               device_printf(sc->sc_dev,
-                   "%s: could not set TX power, error %d\n", __func__, error);
-               return error;
-       }
-       /*
-        * Reconfiguring RXON clears the firmware nodes table so we must
-        * add the broadcast node again.
-        */
-       if ((error = iwn_add_broadcast_node(sc, 1)) != 0) {
-               device_printf(sc->sc_dev,
-                   "%s: could not add broadcast node, error %d\n", __func__,
-                   error);
-               return error;
+       if ((error = iwn_send_rxon(sc, 0, 1)) != 0) {
+               device_printf(sc->sc_dev, "%s: could not send RXON\n",
+                   __func__);
+               return (error);
        }
 
        DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__);
 
-       return 0;
+       return (0);
 }
 
 static int
@@ -7158,22 +7179,10 @@ iwn_run(struct iwn_softc *sc, struct ieee80211vap *vap)
        sc->rxon->filter |= htole32(IWN_FILTER_BSS);
        DPRINTF(sc, IWN_DEBUG_STATE, "rxon chan %d flags %x, 
curhtprotmode=%d\n",
            sc->rxon->chan, le32toh(sc->rxon->flags), ic->ic_curhtprotmode);
-       if (sc->sc_is_scanning)
-               device_printf(sc->sc_dev,
-                   "%s: is_scanning set, before RXON\n",
-                   __func__);
-       error = iwn_cmd(sc, IWN_CMD_RXON, sc->rxon, sc->rxonsz, 1);
-       if (error != 0) {
-               device_printf(sc->sc_dev,
-                   "%s: could not update configuration, error %d\n", __func__,
-                   error);
-               return error;
-       }
 
-       /* Configuration has changed, set TX power accordingly. */
-       if ((error = ops->set_txpower(sc, ni->ni_chan, 1)) != 0) {
-               device_printf(sc->sc_dev,
-                   "%s: could not set TX power, error %d\n", __func__, error);
+       if ((error = iwn_send_rxon(sc, 0, 1)) != 0) {
+               device_printf(sc->sc_dev, "%s: could not send RXON\n",
+                   __func__);
                return error;
        }
 
@@ -7257,6 +7266,9 @@ iwn_ampdu_rx_start(struct ieee80211_node *ni, struct 
ieee80211_rx_ampdu *rap,
        tid = MS(le16toh(baparamset), IEEE80211_BAPS_TID);
        ssn = MS(le16toh(baseqctl), IEEE80211_BASEQ_START);
 
+       if (wn->id == IWN_ID_UNDEFINED)
+               return (ENOENT);
+
        memset(&node, 0, sizeof node);
        node.id = wn->id;
        node.control = IWN_NODE_UPDATE;
@@ -7288,6 +7300,9 @@ iwn_ampdu_rx_stop(struct ieee80211_node *ni, struct 
ieee80211_rx_ampdu *rap)
 
        DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__);
 
+       if (wn->id == IWN_ID_UNDEFINED)
+               goto end;
+
        /* XXX: tid as an argument */
        for (tid = 0; tid < WME_NUM_TID; tid++) {
                if (&ni->ni_rx_ampdu[tid] == rap)
@@ -7301,6 +7316,7 @@ iwn_ampdu_rx_stop(struct ieee80211_node *ni, struct 
ieee80211_rx_ampdu *rap)
        node.delba_tid = tid;
        DPRINTF(sc, IWN_DEBUG_RECV, "DELBA RA=%d TID=%d\n", wn->id, tid);
        (void)ops->add_node(sc, &node, 1);
+end:
        sc->sc_ampdu_rx_stop(ni, rap);
 }
 
@@ -7375,6 +7391,9 @@ iwn_ampdu_tx_start(struct ieee80211com *ic, struct 
ieee80211_node *ni,
 
        DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__);
 
+       if (wn->id == IWN_ID_UNDEFINED)
+               return (0);
+
        /* Enable TX for the specified RA/TID. */
        wn->disable_tid &= ~(1 << tid);
        memset(&node, 0, sizeof node);
@@ -7490,10 +7509,10 @@ static void
 iwn5000_ampdu_tx_start(struct iwn_softc *sc, struct ieee80211_node *ni,
     int qid, uint8_t tid, uint16_t ssn)
 {
-       struct iwn_node *wn = (void *)ni;
-
        DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__);
 
+       struct iwn_node *wn = (void *)ni;
+
        /* Stop TX scheduler while we're changing its configuration. */
        iwn_prph_write(sc, IWN5000_SCHED_QUEUE_STATUS(qid),
            IWN5000_TXQ_STATUS_CHGACT);
@@ -8687,41 +8706,6 @@ iwn_hw_stop(struct iwn_softc *sc)
        iwn_apm_stop(sc);
 }
 
-static void
-iwn_radio_on(void *arg0, int pending)
-{
-       struct iwn_softc *sc = arg0;
-       struct ieee80211com *ic = &sc->sc_ic;
-       struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
-
-       DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__);
-
-       if (vap != NULL) {
-               iwn_init(sc);
-               ieee80211_init(vap);
-       }
-}
-
-static void
-iwn_radio_off(void *arg0, int pending)
-{
-       struct iwn_softc *sc = arg0;
-       struct ieee80211com *ic = &sc->sc_ic;
-       struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
-
-       DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__);
-
-       iwn_stop(sc);
-       if (vap != NULL)
-               ieee80211_stop(vap);
-
-       /* Enable interrupts to get RF toggle notification. */
-       IWN_LOCK(sc);
-       IWN_WRITE(sc, IWN_INT, 0xffffffff);
-       IWN_WRITE(sc, IWN_INT_MASK, sc->int_mask);
-       IWN_UNLOCK(sc);
-}
-
 static void
 iwn_panicked(void *arg0, int pending)
 {
@@ -8753,7 +8737,11 @@ iwn_panicked(void *arg0, int pending)
        IWN_LOCK(sc);
 
        iwn_stop_locked(sc);
-       iwn_init_locked(sc);
+       if ((error = iwn_init_locked(sc)) != 0) {
+               device_printf(sc->sc_dev,
+                   "%s: could not init hardware\n", __func__);
+               goto unlock;
+       }
        if (vap->iv_state >= IEEE80211_S_AUTH &&
            (error = iwn_auth(sc, vap)) != 0) {
                device_printf(sc->sc_dev,
@@ -8765,11 +8753,12 @@ iwn_panicked(void *arg0, int pending)
                    "%s: could not move to run state\n", __func__);
        }
 
+unlock:
        IWN_UNLOCK(sc);
 #endif
 }
 
-static void
+static int
 iwn_init_locked(struct iwn_softc *sc)
 {
        int error;
@@ -8778,6 +8767,9 @@ iwn_init_locked(struct iwn_softc *sc)
 
        IWN_LOCK_ASSERT(sc);
 
+       if (sc->sc_flags & IWN_FLAG_RUNNING)
+               goto end;
+
        sc->sc_flags |= IWN_FLAG_RUNNING;
 
        if ((error = iwn_hw_prepare(sc)) != 0) {
@@ -8792,12 +8784,10 @@ iwn_init_locked(struct iwn_softc *sc)
 
        /* Check that the radio is not disabled by hardware switch. */
        if (!(IWN_READ(sc, IWN_GP_CNTRL) & IWN_GP_CNTRL_RFKILL)) {
-               device_printf(sc->sc_dev,
-                   "radio is disabled by hardware switch\n");
-               /* Enable interrupts to get RF toggle notifications. */
-               IWN_WRITE(sc, IWN_INT, 0xffffffff);
-               IWN_WRITE(sc, IWN_INT_MASK, sc->int_mask);
-               return;
+               iwn_stop_locked(sc);
+               DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__);
+
+               return (1);
        }
 
        /* Read firmware images from the filesystem. */
@@ -8828,26 +8818,29 @@ iwn_init_locked(struct iwn_softc *sc)
 
        callout_reset(&sc->watchdog_to, hz, iwn_watchdog, sc);
 
+end:
        DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__);
 
-       return;
+       return (0);
 
 fail:
-       sc->sc_flags &= ~IWN_FLAG_RUNNING;
        iwn_stop_locked(sc);
+
        DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end in error\n",__func__);
+
+       return (-1);
 }
 
-static void
+static int
 iwn_init(struct iwn_softc *sc)
 {
+       int error;
 
        IWN_LOCK(sc);
-       iwn_init_locked(sc);
+       error = iwn_init_locked(sc);
        IWN_UNLOCK(sc);
 
-       if (sc->sc_flags & IWN_FLAG_RUNNING)
-               ieee80211_start_all(&sc->sc_ic);
+       return (error);
 }
 
 static void
@@ -8856,6 +8849,9 @@ iwn_stop_locked(struct iwn_softc *sc)
 
        IWN_LOCK_ASSERT(sc);
 
+       if (!(sc->sc_flags & IWN_FLAG_RUNNING))
+               return;
+
        sc->sc_is_scanning = 0;
        sc->sc_tx_timer = 0;
        callout_stop(&sc->watchdog_to);
diff --git 
a/src/add-ons/kernel/drivers/network/wlan/iprowifi4965/dev/iwn/if_iwn_chip_cfg.h
 
b/src/add-ons/kernel/drivers/network/wlan/iprowifi4965/dev/iwn/if_iwn_chip_cfg.h
index 041238681a..1547fabb22 100644
--- 
a/src/add-ons/kernel/drivers/network/wlan/iprowifi4965/dev/iwn/if_iwn_chip_cfg.h
+++ 
b/src/add-ons/kernel/drivers/network/wlan/iprowifi4965/dev/iwn/if_iwn_chip_cfg.h
@@ -14,7 +14,7 @@
  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  *
- * $FreeBSD$
+ * $FreeBSD: releng/12.0/sys/dev/iwn/if_iwn_chip_cfg.h 335785 2018-06-28 
21:59:45Z eadler $
  */
 
 #ifndef        __IF_IWN_CHIP_CFG_H__
diff --git 
a/src/add-ons/kernel/drivers/network/wlan/iprowifi4965/dev/iwn/if_iwn_debug.h 
b/src/add-ons/kernel/drivers/network/wlan/iprowifi4965/dev/iwn/if_iwn_debug.h
index 2932c7e4ab..06ded6afd5 100644
--- 
a/src/add-ons/kernel/drivers/network/wlan/iprowifi4965/dev/iwn/if_iwn_debug.h
+++ 
b/src/add-ons/kernel/drivers/network/wlan/iprowifi4965/dev/iwn/if_iwn_debug.h
@@ -19,7 +19,7 @@
  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  *
- * $FreeBSD$
+ * $FreeBSD: releng/12.0/sys/dev/iwn/if_iwn_debug.h 315946 2017-03-25 
13:15:43Z avos $
  */
 
 #ifndef        __IF_IWN_DEBUG_H__
@@ -72,6 +72,7 @@ iwn_intr_str(uint8_t cmd)
        case IWN_RX_PHY:                return "RX_PHY";
        case IWN_MPDU_RX_DONE:          return "MPDU_RX_DONE";
        case IWN_RX_DONE:               return "RX_DONE";
+       case IWN_RX_COMPRESSED_BA:      return "RX_COMPRESSED_BA";
 
        /* Command Notifications */
        case IWN_CMD_RXON:              return "IWN_CMD_RXON";
@@ -81,6 +82,7 @@ iwn_intr_str(uint8_t cmd)
        case IWN_CMD_LINK_QUALITY:      return "IWN_CMD_LINK_QUALITY";
        case IWN_CMD_SET_LED:           return "IWN_CMD_SET_LED";
        case IWN5000_CMD_WIMAX_COEX:    return "IWN5000_CMD_WIMAX_COEX";
+       case IWN_TEMP_NOTIFICATION:     return "IWN_TEMP_NOTIFICATION";
        case IWN5000_CMD_CALIB_CONFIG:  return "IWN5000_CMD_CALIB_CONFIG";
        case IWN5000_CMD_CALIB_RESULT:  return "IWN5000_CMD_CALIB_RESULT";
        case IWN5000_CMD_CALIB_COMPLETE: return "IWN5000_CMD_CALIB_COMPLETE";
diff --git 
a/src/add-ons/kernel/drivers/network/wlan/iprowifi4965/dev/iwn/if_iwn_devid.h 
b/src/add-ons/kernel/drivers/network/wlan/iprowifi4965/dev/iwn/if_iwn_devid.h
index 8470038185..f9e0987a03 100644
--- 
a/src/add-ons/kernel/drivers/network/wlan/iprowifi4965/dev/iwn/if_iwn_devid.h
+++ 
b/src/add-ons/kernel/drivers/network/wlan/iprowifi4965/dev/iwn/if_iwn_devid.h
@@ -13,7 +13,7 @@
  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  *
- * $FreeBSD$
+ * $FreeBSD: releng/12.0/sys/dev/iwn/if_iwn_devid.h 335812 2018-06-30 
04:30:08Z eadler $
  */
 
 #ifndef        __IF_IWN_DEVID_H__
diff --git 
a/src/add-ons/kernel/drivers/network/wlan/iprowifi4965/dev/iwn/if_iwn_ioctl.h 
b/src/add-ons/kernel/drivers/network/wlan/iprowifi4965/dev/iwn/if_iwn_ioctl.h
index c289683ed0..89b2f3c582 100644
--- 
a/src/add-ons/kernel/drivers/network/wlan/iprowifi4965/dev/iwn/if_iwn_ioctl.h
+++ 
b/src/add-ons/kernel/drivers/network/wlan/iprowifi4965/dev/iwn/if_iwn_ioctl.h
@@ -13,7 +13,7 @@
  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  *
- * $FreeBSD$
+ * $FreeBSD: releng/12.0/sys/dev/iwn/if_iwn_ioctl.h 287312 2015-08-30 
21:54:33Z adrian $
  */
 #ifndef        __IF_IWN_IOCTL_H__
 #define        __IF_IWN_IOCTL_H__
diff --git 
a/src/add-ons/kernel/drivers/network/wlan/iprowifi4965/dev/iwn/if_iwnreg.h 
b/src/add-ons/kernel/drivers/network/wlan/iprowifi4965/dev/iwn/if_iwnreg.h
index 05ababf392..1a97f6e34f 100644
--- a/src/add-ons/kernel/drivers/network/wlan/iprowifi4965/dev/iwn/if_iwnreg.h
+++ b/src/add-ons/kernel/drivers/network/wlan/iprowifi4965/dev/iwn/if_iwnreg.h
@@ -1,4 +1,4 @@
-/*     $FreeBSD$       */
+/*     $FreeBSD: releng/12.0/sys/dev/iwn/if_iwnreg.h 315958 2017-03-25 
15:57:47Z avos $        */
 /*     $OpenBSD: if_iwnreg.h,v 1.40 2010/05/05 19:41:57 damien Exp $   */
 
 /*-
@@ -617,6 +617,34 @@ struct iwn_rxon {
 #define IWN4965_RXONSZ (sizeof (struct iwn_rxon) - 6)
 #define IWN5000_RXONSZ (sizeof (struct iwn_rxon))
 
+/* Structure for command IWN_CMD_RXON_ASSOC (4965AGN only.) */
+struct iwn4965_rxon_assoc {
+       uint32_t        flags;
+       uint32_t        filter;
+       uint8_t         ofdm_mask;
+       uint8_t         cck_mask;
+       uint8_t         ht_single_mask;
+       uint8_t         ht_dual_mask;
+       uint16_t        rxchain;
+       uint16_t        reserved;
+} __packed;
+
+/* Structure for command IWN_CMD_RXON_ASSOC (5000 Series only.) */
+struct iwn5000_rxon_assoc {
+       uint32_t        flags;
+       uint32_t        filter;
+       uint8_t         ofdm_mask;
+       uint8_t         cck_mask;
+       uint16_t        reserved1;
+       uint8_t         ht_single_mask;
+       uint8_t         ht_dual_mask;
+       uint8_t         ht_triple_mask;
+       uint8_t         reserved2;
+       uint16_t        rxchain;
+       uint16_t        acquisition;
+       uint32_t        reserved3;
+} __packed;
+
 /* Structure for command IWN_CMD_ASSOCIATE. */
 struct iwn_assoc {
        uint32_t        flags;
@@ -662,13 +690,15 @@ struct iwn_node_info {
        uint8_t         macaddr[IEEE80211_ADDR_LEN];
        uint16_t        reserved2;
        uint8_t         id;
-#define IWN_ID_BSS              0
+#define IWN_ID_BSS             0
 #define        IWN_STA_ID              1
 
-#define        IWN_PAN_ID_BCAST                14
+#define        IWN_PAN_ID_BCAST        14
 #define IWN5000_ID_BROADCAST   15
 #define IWN4965_ID_BROADCAST   31
 
+#define IWN_ID_UNDEFINED       (uint8_t)-1
+
        uint8_t         flags;
 #define IWN_FLAG_SET_KEY               (1 << 0)
 #define IWN_FLAG_SET_DISABLE_TID       (1 << 1)
@@ -736,6 +766,10 @@ struct iwn4965_node_info {
        uint32_t        reserved7;
 } __packed;
 
+#define IWN_RFLAG_RATE         0xff
+#define IWN_RFLAG_RATE_MCS     0x1f
+#define IWN_RFLAG_HT40_DUP     0x20
+
 #define IWN_RFLAG_MCS          (1 << 8)
 #define IWN_RFLAG_CCK          (1 << 9)
 #define IWN_RFLAG_GREENFIELD   (1 << 10)
diff --git 
a/src/add-ons/kernel/drivers/network/wlan/iprowifi4965/dev/iwn/if_iwnvar.h 
b/src/add-ons/kernel/drivers/network/wlan/iprowifi4965/dev/iwn/if_iwnvar.h
index 61ce8456dd..e88d523c22 100644
--- a/src/add-ons/kernel/drivers/network/wlan/iprowifi4965/dev/iwn/if_iwnvar.h
+++ b/src/add-ons/kernel/drivers/network/wlan/iprowifi4965/dev/iwn/if_iwnvar.h
@@ -1,4 +1,4 @@
-/*     $FreeBSD$       */
+/*     $FreeBSD: releng/12.0/sys/dev/iwn/if_iwnvar.h 314923 2017-03-08 
22:49:22Z avos $        */
 /*     $OpenBSD: if_iwnvar.h,v 1.18 2010/04/30 16:06:46 damien Exp $   */
 
 /*-
@@ -206,10 +206,10 @@ struct iwn_ops {
                            uint16_t);
        int             (*get_temperature)(struct iwn_softc *);
        int             (*get_rssi)(struct iwn_softc *, struct iwn_rx_stat *);
-       int             (*set_txpower)(struct iwn_softc *,
-                           struct ieee80211_channel *, int);
+       int             (*set_txpower)(struct iwn_softc *, int);
        int             (*init_gains)(struct iwn_softc *);
        int             (*set_gains)(struct iwn_softc *);
+       int             (*rxon_assoc)(struct iwn_softc *, int);
        int             (*add_node)(struct iwn_softc *, struct iwn_node_info *,
                            int);
        void            (*tx_done)(struct iwn_softc *, struct iwn_rx_desc *,
@@ -305,8 +305,7 @@ struct iwn_softc {
        int                     sc_cap_off;     /* PCIe Capabilities. */
 
        /* Tasks used by the driver */
-       struct task             sc_radioon_task;
-       struct task             sc_radiooff_task;
+       struct task             sc_rftoggle_task;
        struct task             sc_panic_task;
        struct task             sc_xmit_task;
 
@@ -405,11 +404,6 @@ struct iwn_softc {
        struct iwn_rx_radiotap_header sc_rxtap;
        struct iwn_tx_radiotap_header sc_txtap;
 
-#if defined(__HAIKU__)
-       uint32_t sc_intr_status_1;
-       uint32_t sc_intr_status_2;
-#endif
-
        /* The power save level originally configured by user */
        int                     desired_pwrsave_level;
 
@@ -431,6 +425,11 @@ struct iwn_softc {
         * frames whilst waiting for beacons.)
         */
        struct mbufq            sc_xmit_queue;
+
+#if defined(__HAIKU__)
+       uint32_t sc_intr_status_1;
+       uint32_t sc_intr_status_2;
+#endif
 };
 
 #define IWN_LOCK_INIT(_sc) \


Other related posts:

  • » [haiku-commits] haiku: hrev52730 - src/add-ons/kernel/drivers/network/wlan/iprowifi4965/dev/iwn - waddlesplash