]> git.karo-electronics.de Git - mv-sheeva.git/commitdiff
Merge branch 'for-davem' of git://git.kernel.org/pub/scm/linux/kernel/git/linville...
authorDavid S. Miller <davem@davemloft.net>
Fri, 8 Oct 2010 20:51:11 +0000 (13:51 -0700)
committerDavid S. Miller <davem@davemloft.net>
Fri, 8 Oct 2010 20:51:11 +0000 (13:51 -0700)
146 files changed:
Documentation/feature-removal-schedule.txt
MAINTAINERS
arch/arm/mach-omap2/board-zoom-peripherals.c
drivers/net/wireless/ath/ar9170/usb.c
drivers/net/wireless/ath/ath.h
drivers/net/wireless/ath/ath5k/base.c
drivers/net/wireless/ath/ath5k/base.h
drivers/net/wireless/ath/ath5k/debug.c
drivers/net/wireless/ath/ath5k/reset.c
drivers/net/wireless/ath/ath9k/ani.c
drivers/net/wireless/ath/ath9k/ani.h
drivers/net/wireless/ath/ath9k/ar5008_phy.c
drivers/net/wireless/ath/ath9k/ar9002_calib.c
drivers/net/wireless/ath/ath9k/ar9002_hw.c
drivers/net/wireless/ath/ath9k/ar9002_phy.c
drivers/net/wireless/ath/ath9k/ar9003_calib.c
drivers/net/wireless/ath/ath9k/ar9003_hw.c
drivers/net/wireless/ath/ath9k/ar9003_phy.c
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/calib.c
drivers/net/wireless/ath/ath9k/calib.h
drivers/net/wireless/ath/ath9k/debug.c
drivers/net/wireless/ath/ath9k/debug.h
drivers/net/wireless/ath/ath9k/eeprom_4k.c
drivers/net/wireless/ath/ath9k/htc_drv_init.c
drivers/net/wireless/ath/ath9k/htc_drv_main.c
drivers/net/wireless/ath/ath9k/hw-ops.h
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/ath9k/hw.h
drivers/net/wireless/ath/ath9k/init.c
drivers/net/wireless/ath/ath9k/mac.c
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/ath/carl9170/carl9170.h
drivers/net/wireless/ath/carl9170/cmd.h
drivers/net/wireless/ath/carl9170/fw.c
drivers/net/wireless/ath/carl9170/fwcmd.h
drivers/net/wireless/ath/carl9170/fwdesc.h
drivers/net/wireless/ath/carl9170/hw.h
drivers/net/wireless/ath/carl9170/main.c
drivers/net/wireless/ath/carl9170/phy.h
drivers/net/wireless/ath/carl9170/version.h
drivers/net/wireless/b43/b43.h
drivers/net/wireless/b43/phy_common.c
drivers/net/wireless/b43/phy_n.c
drivers/net/wireless/ipw2x00/ipw2200.c
drivers/net/wireless/iwlwifi/iwl-1000.c
drivers/net/wireless/iwlwifi/iwl-3945.c
drivers/net/wireless/iwlwifi/iwl-4965.c
drivers/net/wireless/iwlwifi/iwl-5000.c
drivers/net/wireless/iwlwifi/iwl-6000.c
drivers/net/wireless/iwlwifi/iwl-agn-calib.c
drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c
drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c
drivers/net/wireless/iwlwifi/iwl-agn-ict.c
drivers/net/wireless/iwlwifi/iwl-agn-lib.c
drivers/net/wireless/iwlwifi/iwl-agn-rs.c
drivers/net/wireless/iwlwifi/iwl-agn-rx.c
drivers/net/wireless/iwlwifi/iwl-agn-tt.c
drivers/net/wireless/iwlwifi/iwl-agn-tx.c
drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
drivers/net/wireless/iwlwifi/iwl-agn.c
drivers/net/wireless/iwlwifi/iwl-agn.h
drivers/net/wireless/iwlwifi/iwl-commands.h
drivers/net/wireless/iwlwifi/iwl-core.c
drivers/net/wireless/iwlwifi/iwl-core.h
drivers/net/wireless/iwlwifi/iwl-csr.h
drivers/net/wireless/iwlwifi/iwl-debugfs.c
drivers/net/wireless/iwlwifi/iwl-dev.h
drivers/net/wireless/iwlwifi/iwl-eeprom.c
drivers/net/wireless/iwlwifi/iwl-led.c
drivers/net/wireless/iwlwifi/iwl-power.c
drivers/net/wireless/iwlwifi/iwl-scan.c
drivers/net/wireless/iwlwifi/iwl3945-base.c
drivers/net/wireless/iwmc3200wifi/cfg80211.c
drivers/net/wireless/libertas/cfg.c
drivers/net/wireless/p54/p54usb.c
drivers/net/wireless/rndis_wlan.c
drivers/net/wireless/rt2x00/rt2500usb.c
drivers/net/wireless/rt2x00/rt2800.h
drivers/net/wireless/rt2x00/rt2800lib.c
drivers/net/wireless/rt2x00/rt2800lib.h
drivers/net/wireless/rt2x00/rt2800pci.c
drivers/net/wireless/rt2x00/rt2x00.h
drivers/net/wireless/rt2x00/rt2x00config.c
drivers/net/wireless/rt2x00/rt2x00dev.c
drivers/net/wireless/rt2x00/rt2x00ht.c
drivers/net/wireless/rt2x00/rt2x00mac.c
drivers/net/wireless/rt2x00/rt61pci.c
drivers/net/wireless/rt2x00/rt73usb.c
drivers/net/wireless/rtl818x/rtl8180_dev.c
drivers/net/wireless/wl12xx/wl1271.h
drivers/net/wireless/wl12xx/wl1271_acx.c
drivers/net/wireless/wl12xx/wl1271_acx.h
drivers/net/wireless/wl12xx/wl1271_boot.c
drivers/net/wireless/wl12xx/wl1271_cmd.c
drivers/net/wireless/wl12xx/wl1271_cmd.h
drivers/net/wireless/wl12xx/wl1271_conf.h
drivers/net/wireless/wl12xx/wl1271_event.c
drivers/net/wireless/wl12xx/wl1271_init.c
drivers/net/wireless/wl12xx/wl1271_main.c
drivers/net/wireless/wl12xx/wl1271_ps.c
drivers/net/wireless/wl12xx/wl1271_ps.h
drivers/net/wireless/wl12xx/wl1271_rx.c
drivers/net/wireless/wl12xx/wl1271_scan.c
drivers/net/wireless/wl12xx/wl1271_scan.h
drivers/net/wireless/wl12xx/wl1271_sdio.c
drivers/net/wireless/wl12xx/wl1271_spi.c
drivers/net/wireless/wl12xx/wl1271_testmode.c
drivers/net/wireless/wl12xx/wl1271_tx.c
drivers/net/wireless/wl12xx/wl1271_tx.h
include/linux/nl80211.h
include/linux/wl12xx.h
include/net/cfg80211.h
include/net/genetlink.h
include/net/mac80211.h
net/mac80211/agg-rx.c
net/mac80211/agg-tx.c
net/mac80211/cfg.c
net/mac80211/debugfs_sta.c
net/mac80211/ht.c
net/mac80211/ibss.c
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/key.c
net/mac80211/key.h
net/mac80211/main.c
net/mac80211/mlme.c
net/mac80211/pm.c
net/mac80211/rx.c
net/mac80211/scan.c
net/mac80211/sta_info.c
net/mac80211/sta_info.h
net/mac80211/status.c
net/mac80211/tx.c
net/mac80211/util.c
net/netlink/genetlink.c
net/wireless/core.c
net/wireless/core.h
net/wireless/ibss.c
net/wireless/mlme.c
net/wireless/nl80211.c
net/wireless/scan.c
net/wireless/sme.c
net/wireless/util.c
net/wireless/wext-compat.c

index 842aa9de84a603298f74f9f4b8c036e0104001cf..f45638962858191209b4662693124789a2613de1 100644 (file)
@@ -564,3 +564,12 @@ Who:       FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
 
 ----------------------------
 
+What:  iwlwifi disable_hw_scan module parameters
+When:  2.6.40
+Why:   Hareware scan is the prefer method for iwlwifi devices for
+       scanning operation. Remove software scan support for all the
+       iwlwifi devices.
+
+Who:   Wey-Yi Guy <wey-yi.w.guy@intel.com>
+
+----------------------------
index e967aadddfc6eb851e79d8fe0e2d78aade12c6d8..296c3d7cdb501918de08fa1f72825b6147489967 100644 (file)
@@ -6457,7 +6457,7 @@ WL1271 WIRELESS DRIVER
 M:     Luciano Coelho <luciano.coelho@nokia.com>
 L:     linux-wireless@vger.kernel.org
 W:     http://wireless.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/luca/wl12xx.git
 S:     Maintained
 F:     drivers/net/wireless/wl12xx/wl1271*
 F:     include/linux/wl12xx.h
index 6aa0728fa15dcd5ec301cf4a379080861c60bfe9..189a6d1600b208ef448ea210139d2d3faa056e29 100644 (file)
@@ -213,7 +213,7 @@ static struct omap2_hsmmc_info mmc[] __initdata = {
        {
                .name           = "wl1271",
                .mmc            = 3,
-               .wires          = 4,
+               .caps           = MMC_CAP_4_BIT_DATA,
                .gpio_wp        = -EINVAL,
                .gpio_cd        = -EINVAL,
                .nonremovable   = true,
index a93dc18a45c3fc9e0911197f7292948518741927..5dbb5361fd516808fccc79bc9c2dbd2fc22c5963 100644 (file)
@@ -54,8 +54,6 @@ MODULE_AUTHOR("Christian Lamparter <chunkeey@web.de>");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Atheros AR9170 802.11n USB wireless");
 MODULE_FIRMWARE("ar9170.fw");
-MODULE_FIRMWARE("ar9170-1.fw");
-MODULE_FIRMWARE("ar9170-2.fw");
 
 enum ar9170_requirements {
        AR9170_REQ_FW1_ONLY = 1,
index dd236c3b52f6218755b2197845f987a487d87a43..cee0191704f513251d083cfdc9a0b78198d5e0c3 100644 (file)
@@ -35,7 +35,6 @@ static const u8 ath_bcast_mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
 
 struct ath_ani {
        bool caldone;
-       int16_t noise_floor;
        unsigned int longcal_timer;
        unsigned int shortcal_timer;
        unsigned int resetcal_timer;
@@ -103,14 +102,12 @@ enum ath_cipher {
  * @read: Register read
  * @write: Register write
  * @enable_write_buffer: Enable multiple register writes
- * @disable_write_buffer: Disable multiple register writes
- * @write_flush: Flush buffered register writes
+ * @write_flush: flush buffered register writes and disable buffering
  */
 struct ath_ops {
        unsigned int (*read)(void *, u32 reg_offset);
        void (*write)(void *, u32 val, u32 reg_offset);
        void (*enable_write_buffer)(void *);
-       void (*disable_write_buffer)(void *);
        void (*write_flush) (void *);
 };
 
index 94cc3354f3a6fef8f7d3fda8fd4540de57772793..dad726585637146a62b282f6facce9636cfab57b 100644 (file)
@@ -52,6 +52,7 @@
 #include <linux/ethtool.h>
 #include <linux/uaccess.h>
 #include <linux/slab.h>
+#include <linux/etherdevice.h>
 
 #include <net/ieee80211_radiotap.h>
 
@@ -509,8 +510,71 @@ ath5k_setcurmode(struct ath5k_softc *sc, unsigned int mode)
        }
 }
 
+struct ath_vif_iter_data {
+       const u8        *hw_macaddr;
+       u8              mask[ETH_ALEN];
+       u8              active_mac[ETH_ALEN]; /* first active MAC */
+       bool            need_set_hw_addr;
+       bool            found_active;
+       bool            any_assoc;
+};
+
+static void ath_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
+{
+       struct ath_vif_iter_data *iter_data = data;
+       int i;
+
+       if (iter_data->hw_macaddr)
+               for (i = 0; i < ETH_ALEN; i++)
+                       iter_data->mask[i] &=
+                               ~(iter_data->hw_macaddr[i] ^ mac[i]);
+
+       if (!iter_data->found_active) {
+               iter_data->found_active = true;
+               memcpy(iter_data->active_mac, mac, ETH_ALEN);
+       }
+
+       if (iter_data->need_set_hw_addr && iter_data->hw_macaddr)
+               if (compare_ether_addr(iter_data->hw_macaddr, mac) == 0)
+                       iter_data->need_set_hw_addr = false;
+
+       if (!iter_data->any_assoc) {
+               struct ath5k_vif *avf = (void *)vif->drv_priv;
+               if (avf->assoc)
+                       iter_data->any_assoc = true;
+       }
+}
+
+void ath5k_update_bssid_mask(struct ath5k_softc *sc, struct ieee80211_vif *vif)
+{
+       struct ath_common *common = ath5k_hw_common(sc->ah);
+       struct ath_vif_iter_data iter_data;
+
+       /*
+        * Use the hardware MAC address as reference, the hardware uses it
+        * together with the BSSID mask when matching addresses.
+        */
+       iter_data.hw_macaddr = common->macaddr;
+       memset(&iter_data.mask, 0xff, ETH_ALEN);
+       iter_data.found_active = false;
+       iter_data.need_set_hw_addr = true;
+
+       if (vif)
+               ath_vif_iter(&iter_data, vif->addr, vif);
+
+       /* Get list of all active MAC addresses */
+       ieee80211_iterate_active_interfaces_atomic(sc->hw, ath_vif_iter,
+                                                  &iter_data);
+       memcpy(sc->bssidmask, iter_data.mask, ETH_ALEN);
+
+       if (iter_data.need_set_hw_addr && iter_data.found_active)
+               ath5k_hw_set_lladdr(sc->ah, iter_data.active_mac);
+
+       ath5k_hw_set_bssid_mask(sc->ah, sc->bssidmask);
+}
+
 static void
-ath5k_mode_setup(struct ath5k_softc *sc)
+ath5k_mode_setup(struct ath5k_softc *sc, struct ieee80211_vif *vif)
 {
        struct ath5k_hw *ah = sc->ah;
        u32 rfilt;
@@ -520,7 +584,7 @@ ath5k_mode_setup(struct ath5k_softc *sc)
        ath5k_hw_set_rx_filter(ah, rfilt);
 
        if (ath5k_hw_hasbssidmask(ah))
-               ath5k_hw_set_bssid_mask(ah, sc->bssidmask);
+               ath5k_update_bssid_mask(sc, vif);
 
        /* configure operational mode */
        ath5k_hw_set_opmode(ah, sc->opmode);
@@ -698,13 +762,13 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf,
                flags |= AR5K_TXDESC_RTSENA;
                cts_rate = ieee80211_get_rts_cts_rate(sc->hw, info)->hw_value;
                duration = le16_to_cpu(ieee80211_rts_duration(sc->hw,
-                       sc->vif, pktlen, info));
+                       info->control.vif, pktlen, info));
        }
        if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
                flags |= AR5K_TXDESC_CTSENA;
                cts_rate = ieee80211_get_rts_cts_rate(sc->hw, info)->hw_value;
                duration = le16_to_cpu(ieee80211_ctstoself_duration(sc->hw,
-                       sc->vif, pktlen, info));
+                       info->control.vif, pktlen, info));
        }
        ret = ah->ah_setup_tx_desc(ah, ds, pktlen,
                ieee80211_get_hdrlen_from_skb(skb), padsize,
@@ -806,10 +870,13 @@ ath5k_desc_alloc(struct ath5k_softc *sc, struct pci_dev *pdev)
                list_add_tail(&bf->list, &sc->txbuf);
        }
 
-       /* beacon buffer */
-       bf->desc = ds;
-       bf->daddr = da;
-       sc->bbuf = bf;
+       /* beacon buffers */
+       INIT_LIST_HEAD(&sc->bcbuf);
+       for (i = 0; i < ATH_BCBUF; i++, bf++, ds++, da += sizeof(*ds)) {
+               bf->desc = ds;
+               bf->daddr = da;
+               list_add_tail(&bf->list, &sc->bcbuf);
+       }
 
        return 0;
 err_free:
@@ -824,11 +891,12 @@ ath5k_desc_free(struct ath5k_softc *sc, struct pci_dev *pdev)
 {
        struct ath5k_buf *bf;
 
-       ath5k_txbuf_free_skb(sc, sc->bbuf);
        list_for_each_entry(bf, &sc->txbuf, list)
                ath5k_txbuf_free_skb(sc, bf);
        list_for_each_entry(bf, &sc->rxbuf, list)
                ath5k_rxbuf_free_skb(sc, bf);
+       list_for_each_entry(bf, &sc->bcbuf, list)
+               ath5k_txbuf_free_skb(sc, bf);
 
        /* Free memory associated with all descriptors */
        pci_free_consistent(pdev, sc->desc_len, sc->desc, sc->desc_daddr);
@@ -837,7 +905,6 @@ ath5k_desc_free(struct ath5k_softc *sc, struct pci_dev *pdev)
 
        kfree(sc->bufptr);
        sc->bufptr = NULL;
-       sc->bbuf = NULL;
 }
 
 
@@ -1083,7 +1150,7 @@ ath5k_rx_start(struct ath5k_softc *sc)
        spin_unlock_bh(&sc->rxbuflock);
 
        ath5k_hw_start_rx_dma(ah);      /* enable recv descriptors */
-       ath5k_mode_setup(sc);           /* set filters, etc. */
+       ath5k_mode_setup(sc, NULL);             /* set filters, etc. */
        ath5k_hw_start_rx_pcu(ah);      /* re-enable PCU/DMA engine */
 
        return 0;
@@ -1366,6 +1433,7 @@ static bool
 ath5k_receive_frame_ok(struct ath5k_softc *sc, struct ath5k_rx_status *rs)
 {
        sc->stats.rx_all_count++;
+       sc->stats.rx_bytes_count += rs->rs_datalen;
 
        if (unlikely(rs->rs_status)) {
                if (rs->rs_status & AR5K_RXERR_CRC)
@@ -1544,6 +1612,7 @@ ath5k_tx_frame_completed(struct ath5k_softc *sc, struct sk_buff *skb,
        int i;
 
        sc->stats.tx_all_count++;
+       sc->stats.tx_bytes_count += skb->len;
        info = IEEE80211_SKB_CB(skb);
 
        ieee80211_tx_info_clear_status(info);
@@ -1642,7 +1711,7 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq)
                }
        }
        spin_unlock(&txq->lock);
-       if (txq->txq_len < ATH5K_TXQ_LEN_LOW)
+       if (txq->txq_len < ATH5K_TXQ_LEN_LOW && txq->qnum < 4)
                ieee80211_wake_queue(sc->hw, txq->qnum);
 }
 
@@ -1750,6 +1819,7 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
        int ret;
        struct ath5k_softc *sc = hw->priv;
+       struct ath5k_vif *avf = (void *)vif->drv_priv;
        struct sk_buff *skb;
 
        if (WARN_ON(!vif)) {
@@ -1766,11 +1836,11 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 
        ath5k_debug_dump_skb(sc, skb, "BC  ", 1);
 
-       ath5k_txbuf_free_skb(sc, sc->bbuf);
-       sc->bbuf->skb = skb;
-       ret = ath5k_beacon_setup(sc, sc->bbuf);
+       ath5k_txbuf_free_skb(sc, avf->bbuf);
+       avf->bbuf->skb = skb;
+       ret = ath5k_beacon_setup(sc, avf->bbuf);
        if (ret)
-               sc->bbuf->skb = NULL;
+               avf->bbuf->skb = NULL;
 out:
        return ret;
 }
@@ -1786,16 +1856,14 @@ out:
 static void
 ath5k_beacon_send(struct ath5k_softc *sc)
 {
-       struct ath5k_buf *bf = sc->bbuf;
        struct ath5k_hw *ah = sc->ah;
+       struct ieee80211_vif *vif;
+       struct ath5k_vif *avf;
+       struct ath5k_buf *bf;
        struct sk_buff *skb;
 
        ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, "in beacon_send\n");
 
-       if (unlikely(bf->skb == NULL || sc->opmode == NL80211_IFTYPE_STATION)) {
-               ATH5K_WARN(sc, "bf=%p bf_skb=%p\n", bf, bf ? bf->skb : NULL);
-               return;
-       }
        /*
         * Check if the previous beacon has gone out.  If
         * not, don't don't try to post another: skip this
@@ -1824,6 +1892,28 @@ ath5k_beacon_send(struct ath5k_softc *sc)
                sc->bmisscount = 0;
        }
 
+       if (sc->opmode == NL80211_IFTYPE_AP && sc->num_ap_vifs > 1) {
+               u64 tsf = ath5k_hw_get_tsf64(ah);
+               u32 tsftu = TSF_TO_TU(tsf);
+               int slot = ((tsftu % sc->bintval) * ATH_BCBUF) / sc->bintval;
+               vif = sc->bslot[(slot + 1) % ATH_BCBUF];
+               ATH5K_DBG(sc, ATH5K_DEBUG_BEACON,
+                       "tsf %llx tsftu %x intval %u slot %u vif %p\n",
+                       (unsigned long long)tsf, tsftu, sc->bintval, slot, vif);
+       } else /* only one interface */
+               vif = sc->bslot[0];
+
+       if (!vif)
+               return;
+
+       avf = (void *)vif->drv_priv;
+       bf = avf->bbuf;
+       if (unlikely(bf->skb == NULL || sc->opmode == NL80211_IFTYPE_STATION ||
+                       sc->opmode == NL80211_IFTYPE_MONITOR)) {
+               ATH5K_WARN(sc, "bf=%p bf_skb=%p\n", bf, bf ? bf->skb : NULL);
+               return;
+       }
+
        /*
         * Stop any current dma and put the new frame on the queue.
         * This should never fail since we check above that no frames
@@ -1836,17 +1926,17 @@ ath5k_beacon_send(struct ath5k_softc *sc)
 
        /* refresh the beacon for AP mode */
        if (sc->opmode == NL80211_IFTYPE_AP)
-               ath5k_beacon_update(sc->hw, sc->vif);
+               ath5k_beacon_update(sc->hw, vif);
 
        ath5k_hw_set_txdp(ah, sc->bhalq, bf->daddr);
        ath5k_hw_start_tx_dma(ah, sc->bhalq);
        ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "TXDP[%u] = %llx (%p)\n",
                sc->bhalq, (unsigned long long)bf->daddr, bf->desc);
 
-       skb = ieee80211_get_buffered_bc(sc->hw, sc->vif);
+       skb = ieee80211_get_buffered_bc(sc->hw, vif);
        while (skb) {
                ath5k_tx_queue(sc->hw, skb, sc->cabq);
-               skb = ieee80211_get_buffered_bc(sc->hw, sc->vif);
+               skb = ieee80211_get_buffered_bc(sc->hw, vif);
        }
 
        sc->bsent++;
@@ -1876,6 +1966,12 @@ ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf)
        u64 hw_tsf;
 
        intval = sc->bintval & AR5K_BEACON_PERIOD;
+       if (sc->opmode == NL80211_IFTYPE_AP && sc->num_ap_vifs > 1) {
+               intval /= ATH_BCBUF;    /* staggered multi-bss beacons */
+               if (intval < 15)
+                       ATH5K_WARN(sc, "intval %u is too low, min 15\n",
+                                  intval);
+       }
        if (WARN_ON(!intval))
                return;
 
@@ -2323,6 +2419,10 @@ ath5k_init(struct ath5k_softc *sc)
                ath_hw_keyreset(common, (u16) i);
 
        ath5k_hw_set_ack_bitrate_high(ah, true);
+
+       for (i = 0; i < ARRAY_SIZE(sc->bslot); i++)
+               sc->bslot[i] = NULL;
+
        ret = 0;
 done:
        mmiowb();
@@ -2382,7 +2482,6 @@ ath5k_stop_hw(struct ath5k_softc *sc)
                ATH5K_DBG(sc, ATH5K_DEBUG_RESET,
                                "putting device to sleep\n");
        }
-       ath5k_txbuf_free_skb(sc, sc->bbuf);
 
        mmiowb();
        mutex_unlock(&sc->lock);
@@ -2587,9 +2686,9 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
        }
 
        SET_IEEE80211_PERM_ADDR(hw, mac);
+       memcpy(&sc->lladdr, mac, ETH_ALEN);
        /* All MAC address bits matter for ACKs */
-       memcpy(sc->bssidmask, ath_bcast_mac, ETH_ALEN);
-       ath5k_hw_set_bssid_mask(sc->ah, sc->bssidmask);
+       ath5k_update_bssid_mask(sc, NULL);
 
        regulatory->current_rd = ah->ah_capabilities.cap_eeprom.ee_regdomain;
        ret = ath_regd_init(regulatory, hw->wiphy, ath5k_reg_notifier);
@@ -2687,31 +2786,91 @@ static int ath5k_add_interface(struct ieee80211_hw *hw,
 {
        struct ath5k_softc *sc = hw->priv;
        int ret;
+       struct ath5k_hw *ah = sc->ah;
+       struct ath5k_vif *avf = (void *)vif->drv_priv;
 
        mutex_lock(&sc->lock);
-       if (sc->vif) {
-               ret = 0;
+
+       if ((vif->type == NL80211_IFTYPE_AP ||
+            vif->type == NL80211_IFTYPE_ADHOC)
+           && (sc->num_ap_vifs + sc->num_adhoc_vifs) >= ATH_BCBUF) {
+               ret = -ELNRNG;
                goto end;
        }
 
-       sc->vif = vif;
+       /* Don't allow other interfaces if one ad-hoc is configured.
+        * TODO: Fix the problems with ad-hoc and multiple other interfaces.
+        * We would need to operate the HW in ad-hoc mode to allow TSF updates
+        * for the IBSS, but this breaks with additional AP or STA interfaces
+        * at the moment. */
+       if (sc->num_adhoc_vifs ||
+           (sc->nvifs && vif->type == NL80211_IFTYPE_ADHOC)) {
+               ATH5K_ERR(sc, "Only one single ad-hoc interface is allowed.\n");
+               ret = -ELNRNG;
+               goto end;
+       }
 
        switch (vif->type) {
        case NL80211_IFTYPE_AP:
        case NL80211_IFTYPE_STATION:
        case NL80211_IFTYPE_ADHOC:
        case NL80211_IFTYPE_MESH_POINT:
-               sc->opmode = vif->type;
+               avf->opmode = vif->type;
                break;
        default:
                ret = -EOPNOTSUPP;
                goto end;
        }
 
-       ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "add interface mode %d\n", sc->opmode);
+       sc->nvifs++;
+       ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "add interface mode %d\n", avf->opmode);
 
+       /* Assign the vap/adhoc to a beacon xmit slot. */
+       if ((avf->opmode == NL80211_IFTYPE_AP) ||
+           (avf->opmode == NL80211_IFTYPE_ADHOC)) {
+               int slot;
+
+               WARN_ON(list_empty(&sc->bcbuf));
+               avf->bbuf = list_first_entry(&sc->bcbuf, struct ath5k_buf,
+                                            list);
+               list_del(&avf->bbuf->list);
+
+               avf->bslot = 0;
+               for (slot = 0; slot < ATH_BCBUF; slot++) {
+                       if (!sc->bslot[slot]) {
+                               avf->bslot = slot;
+                               break;
+                       }
+               }
+               BUG_ON(sc->bslot[avf->bslot] != NULL);
+               sc->bslot[avf->bslot] = vif;
+               if (avf->opmode == NL80211_IFTYPE_AP)
+                       sc->num_ap_vifs++;
+               else
+                       sc->num_adhoc_vifs++;
+       }
+
+       /* Set combined mode - when APs are configured, operate in AP mode.
+        * Otherwise use the mode of the new interface. This can currently
+        * only deal with combinations of APs and STAs. Only one ad-hoc
+        * interfaces is allowed above.
+        */
+       if (sc->num_ap_vifs)
+               sc->opmode = NL80211_IFTYPE_AP;
+       else
+               sc->opmode = vif->type;
+
+       ath5k_hw_set_opmode(ah, sc->opmode);
+
+       /* Any MAC address is fine, all others are included through the
+        * filter.
+        */
+       memcpy(&sc->lladdr, vif->addr, ETH_ALEN);
        ath5k_hw_set_lladdr(sc->ah, vif->addr);
-       ath5k_mode_setup(sc);
+
+       memcpy(&avf->lladdr, vif->addr, ETH_ALEN);
+
+       ath5k_mode_setup(sc, vif);
 
        ret = 0;
 end:
@@ -2724,15 +2883,29 @@ ath5k_remove_interface(struct ieee80211_hw *hw,
                        struct ieee80211_vif *vif)
 {
        struct ath5k_softc *sc = hw->priv;
-       u8 mac[ETH_ALEN] = {};
+       struct ath5k_vif *avf = (void *)vif->drv_priv;
+       unsigned int i;
 
        mutex_lock(&sc->lock);
-       if (sc->vif != vif)
-               goto end;
+       sc->nvifs--;
+
+       if (avf->bbuf) {
+               ath5k_txbuf_free_skb(sc, avf->bbuf);
+               list_add_tail(&avf->bbuf->list, &sc->bcbuf);
+               for (i = 0; i < ATH_BCBUF; i++) {
+                       if (sc->bslot[i] == vif) {
+                               sc->bslot[i] = NULL;
+                               break;
+                       }
+               }
+               avf->bbuf = NULL;
+       }
+       if (avf->opmode == NL80211_IFTYPE_AP)
+               sc->num_ap_vifs--;
+       else if (avf->opmode == NL80211_IFTYPE_ADHOC)
+               sc->num_adhoc_vifs--;
 
-       ath5k_hw_set_lladdr(sc->ah, mac);
-       sc->vif = NULL;
-end:
+       ath5k_update_bssid_mask(sc, NULL);
        mutex_unlock(&sc->lock);
 }
 
@@ -2815,6 +2988,19 @@ static u64 ath5k_prepare_multicast(struct ieee80211_hw *hw,
        return ((u64)(mfilt[1]) << 32) | mfilt[0];
 }
 
+static bool ath_any_vif_assoc(struct ath5k_softc *sc)
+{
+       struct ath_vif_iter_data iter_data;
+       iter_data.hw_macaddr = NULL;
+       iter_data.any_assoc = false;
+       iter_data.need_set_hw_addr = false;
+       iter_data.found_active = true;
+
+       ieee80211_iterate_active_interfaces_atomic(sc->hw, ath_vif_iter,
+                                                  &iter_data);
+       return iter_data.any_assoc;
+}
+
 #define SUPPORTED_FIF_FLAGS \
        FIF_PROMISC_IN_BSS |  FIF_ALLMULTI | FIF_FCSFAIL | \
        FIF_PLCPFAIL | FIF_CONTROL | FIF_OTHER_BSS | \
@@ -2885,7 +3071,7 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw,
 
        /* FIF_BCN_PRBRESP_PROMISC really means to enable beacons
        * and probes for any BSSID */
-       if (*new_flags & FIF_BCN_PRBRESP_PROMISC)
+       if ((*new_flags & FIF_BCN_PRBRESP_PROMISC) || (sc->nvifs > 1))
                rfilt |= AR5K_RX_FILTER_BEACON;
 
        /* FIF_CONTROL doc says that if FIF_PROMISC_IN_BSS is not
@@ -3070,14 +3256,13 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw,
                                    struct ieee80211_bss_conf *bss_conf,
                                    u32 changes)
 {
+       struct ath5k_vif *avf = (void *)vif->drv_priv;
        struct ath5k_softc *sc = hw->priv;
        struct ath5k_hw *ah = sc->ah;
        struct ath_common *common = ath5k_hw_common(ah);
        unsigned long flags;
 
        mutex_lock(&sc->lock);
-       if (WARN_ON(sc->vif != vif))
-               goto unlock;
 
        if (changes & BSS_CHANGED_BSSID) {
                /* Cache for later use during resets */
@@ -3091,7 +3276,12 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw,
                sc->bintval = bss_conf->beacon_int;
 
        if (changes & BSS_CHANGED_ASSOC) {
-               sc->assoc = bss_conf->assoc;
+               avf->assoc = bss_conf->assoc;
+               if (bss_conf->assoc)
+                       sc->assoc = bss_conf->assoc;
+               else
+                       sc->assoc = ath_any_vif_assoc(sc);
+
                if (sc->opmode == NL80211_IFTYPE_STATION)
                        set_beacon_filter(hw, sc->assoc);
                ath5k_hw_set_ledstate(sc->ah, sc->assoc ?
@@ -3119,7 +3309,6 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw,
                       BSS_CHANGED_BEACON_INT))
                ath5k_beacon_config(sc);
 
- unlock:
        mutex_unlock(&sc->lock);
 }
 
@@ -3394,6 +3583,8 @@ ath5k_pci_probe(struct pci_dev *pdev,
                hw->max_rate_tries = 11;
        }
 
+       hw->vif_data_size = sizeof(struct ath5k_vif);
+
        /* Finish private driver data initialization */
        ret = ath5k_attach(pdev, hw);
        if (ret)
index 7f9d0d3018e81a2b40b026808bf6373516e0d002..9a79773cdc2a43f59ccbddf2a53f51172e06d8a6 100644 (file)
@@ -58,8 +58,7 @@
 
 #define        ATH_RXBUF       40              /* number of RX buffers */
 #define        ATH_TXBUF       200             /* number of TX buffers */
-#define ATH_BCBUF      1               /* number of beacon buffers */
-
+#define ATH_BCBUF      4               /* number of beacon buffers */
 #define ATH5K_TXQ_LEN_MAX      (ATH_TXBUF / 4)         /* bufs per queue */
 #define ATH5K_TXQ_LEN_LOW      (ATH5K_TXQ_LEN_MAX / 2) /* low mark */
 
@@ -122,6 +121,13 @@ struct ath5k_statistics {
        /* frame errors */
        unsigned int rx_all_count;      /* all RX frames, including errors */
        unsigned int tx_all_count;      /* all TX frames, including errors */
+       unsigned int rx_bytes_count;    /* all RX bytes, including errored pks
+                                        * and the MAC headers for each packet
+                                        */
+       unsigned int tx_bytes_count;    /* all TX bytes, including errored pkts
+                                        * and the MAC headers and padding for
+                                        * each packet.
+                                        */
        unsigned int rxerr_crc;
        unsigned int rxerr_phy;
        unsigned int rxerr_phy_code[32];
@@ -152,6 +158,14 @@ struct ath5k_statistics {
 #define ATH_CHAN_MAX   (14+14+14+252+20)
 #endif
 
+struct ath5k_vif {
+       bool                    assoc; /* are we associated or not */
+       enum nl80211_iftype     opmode;
+       int                     bslot;
+       struct ath5k_buf        *bbuf; /* beacon buffer */
+       u8                      lladdr[ETH_ALEN];
+};
+
 /* Software Carrier, keeps track of the driver state
  * associated with an instance of a device */
 struct ath5k_softc {
@@ -188,10 +202,11 @@ struct ath5k_softc {
        unsigned int            curmode;        /* current phy mode */
        struct ieee80211_channel *curchan;      /* current h/w channel */
 
-       struct ieee80211_vif *vif;
+       u16                     nvifs;
 
        enum ath5k_int          imask;          /* interrupt mask copy */
 
+       u8                      lladdr[ETH_ALEN];
        u8                      bssidmask[ETH_ALEN];
 
        unsigned int            led_pin,        /* GPIO pin for driving LED */
@@ -219,7 +234,10 @@ struct ath5k_softc {
 
        spinlock_t              block;          /* protects beacon */
        struct tasklet_struct   beacontq;       /* beacon intr tasklet */
-       struct ath5k_buf        *bbuf;          /* beacon buffer */
+       struct list_head        bcbuf;          /* beacon buffer */
+       struct ieee80211_vif    *bslot[ATH_BCBUF];
+       u16                     num_ap_vifs;
+       u16                     num_adhoc_vifs;
        unsigned int            bhalq,          /* SW q for outgoing beacons */
                                bmisscount,     /* missed beacon transmits */
                                bintval,        /* beacon interval in TU */
index 0f06e849031400405673c37b07835e95165a3af2..c2d549f871f936075ed64587690273c5717edd10 100644 (file)
@@ -587,6 +587,8 @@ static ssize_t read_file_frameerrors(struct file *file, char __user *user_buf,
                                st->rxerr_jumbo*100/st->rx_all_count : 0);
        len += snprintf(buf+len, sizeof(buf)-len, "[RX all\t%d]\n",
                        st->rx_all_count);
+       len += snprintf(buf+len, sizeof(buf)-len, "RX-all-bytes\t%d\n",
+                       st->rx_bytes_count);
 
        len += snprintf(buf+len, sizeof(buf)-len,
                        "\nTX\n---------------------\n");
@@ -604,6 +606,8 @@ static ssize_t read_file_frameerrors(struct file *file, char __user *user_buf,
                                st->txerr_filt*100/st->tx_all_count : 0);
        len += snprintf(buf+len, sizeof(buf)-len, "[TX all\t%d]\n",
                        st->tx_all_count);
+       len += snprintf(buf+len, sizeof(buf)-len, "TX-all-bytes\t%d\n",
+                       st->tx_bytes_count);
 
        if (len > sizeof(buf))
                len = sizeof(buf);
index 58912cd762d9808c199f78fbdb6ab97f5261e03f..5b179d01f97db16c64bddc97fc0ade0005bf57ee 100644 (file)
@@ -167,7 +167,7 @@ static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah,
                 * ieee80211_duration() for a brief description of
                 * what rate we should choose to TX ACKs. */
                tx_time = le16_to_cpu(ieee80211_generic_frame_duration(sc->hw,
-                                                       sc->vif, 10, rate));
+                                                       NULL, 10, rate));
 
                ath5k_hw_reg_write(ah, tx_time, reg);
 
@@ -1060,7 +1060,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
                 * XXX: rethink this after new mode changes to
                 * mac80211 are integrated */
                if (ah->ah_version == AR5K_AR5212 &&
-                       ah->ah_sc->vif != NULL)
+                       ah->ah_sc->nvifs)
                        ath5k_hw_write_rate_duration(ah, mode);
 
                /*
index 0496f965314fa8417ba79d30d161a221e16ad630..f2a907b4acb80dfc178829de9e16e467939ba2a8 100644 (file)
@@ -103,31 +103,9 @@ static const struct ani_cck_level_entry cck_level_table[] = {
 #define ATH9K_ANI_CCK_DEF_LEVEL \
        2 /* default level - matches the INI settings */
 
-/* Private to ani.c */
-static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah)
-{
-       ath9k_hw_private_ops(ah)->ani_lower_immunity(ah);
-}
-
-int ath9k_hw_get_ani_channel_idx(struct ath_hw *ah,
-                                struct ath9k_channel *chan)
+static bool use_new_ani(struct ath_hw *ah)
 {
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(ah->ani); i++) {
-               if (ah->ani[i].c &&
-                   ah->ani[i].c->channel == chan->channel)
-                       return i;
-               if (ah->ani[i].c == NULL) {
-                       ah->ani[i].c = chan;
-                       return i;
-               }
-       }
-
-       ath_print(ath9k_hw_common(ah), ATH_DBG_ANI,
-                 "No more channel states left. Using channel 0\n");
-
-       return 0;
+       return AR_SREV_9300_20_OR_LATER(ah) || modparam_force_new_ani;
 }
 
 static void ath9k_hw_update_mibstats(struct ath_hw *ah,
@@ -140,82 +118,34 @@ static void ath9k_hw_update_mibstats(struct ath_hw *ah,
        stats->beacons += REG_READ(ah, AR_BEACON_CNT);
 }
 
-static void ath9k_ani_restart_old(struct ath_hw *ah)
+static void ath9k_ani_restart(struct ath_hw *ah)
 {
        struct ar5416AniState *aniState;
        struct ath_common *common = ath9k_hw_common(ah);
+       u32 ofdm_base = 0, cck_base = 0;
 
        if (!DO_ANI(ah))
                return;
 
-       aniState = ah->curani;
+       aniState = &ah->curchan->ani;
        aniState->listenTime = 0;
 
-       if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) {
-               aniState->ofdmPhyErrBase = 0;
-               ath_print(common, ATH_DBG_ANI,
-                         "OFDM Trigger is too high for hw counters\n");
-       } else {
-               aniState->ofdmPhyErrBase =
-                       AR_PHY_COUNTMAX - aniState->ofdmTrigHigh;
+       if (!use_new_ani(ah)) {
+               ofdm_base = AR_PHY_COUNTMAX - ah->config.ofdm_trig_high;
+               cck_base = AR_PHY_COUNTMAX - ah->config.cck_trig_high;
        }
-       if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) {
-               aniState->cckPhyErrBase = 0;
-               ath_print(common, ATH_DBG_ANI,
-                         "CCK Trigger is too high for hw counters\n");
-       } else {
-               aniState->cckPhyErrBase =
-                       AR_PHY_COUNTMAX - aniState->cckTrigHigh;
-       }
-       ath_print(common, ATH_DBG_ANI,
-                 "Writing ofdmbase=%u   cckbase=%u\n",
-                 aniState->ofdmPhyErrBase,
-                 aniState->cckPhyErrBase);
-
-       ENABLE_REGWRITE_BUFFER(ah);
-
-       REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase);
-       REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase);
-       REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
-       REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
-
-       REGWRITE_BUFFER_FLUSH(ah);
-       DISABLE_REGWRITE_BUFFER(ah);
-
-       ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
-
-       aniState->ofdmPhyErrCount = 0;
-       aniState->cckPhyErrCount = 0;
-}
-
-static void ath9k_ani_restart_new(struct ath_hw *ah)
-{
-       struct ar5416AniState *aniState;
-       struct ath_common *common = ath9k_hw_common(ah);
-
-       if (!DO_ANI(ah))
-               return;
-
-       aniState = ah->curani;
-       aniState->listenTime = 0;
-
-       aniState->ofdmPhyErrBase = 0;
-       aniState->cckPhyErrBase = 0;
 
        ath_print(common, ATH_DBG_ANI,
-                 "Writing ofdmbase=%08x   cckbase=%08x\n",
-                 aniState->ofdmPhyErrBase,
-                 aniState->cckPhyErrBase);
+                 "Writing ofdmbase=%u   cckbase=%u\n", ofdm_base, cck_base);
 
        ENABLE_REGWRITE_BUFFER(ah);
 
-       REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase);
-       REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase);
+       REG_WRITE(ah, AR_PHY_ERR_1, ofdm_base);
+       REG_WRITE(ah, AR_PHY_ERR_2, cck_base);
        REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
        REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
 
        REGWRITE_BUFFER_FLUSH(ah);
-       DISABLE_REGWRITE_BUFFER(ah);
 
        ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
 
@@ -229,10 +159,7 @@ static void ath9k_hw_ani_ofdm_err_trigger_old(struct ath_hw *ah)
        struct ar5416AniState *aniState;
        int32_t rssi;
 
-       if (!DO_ANI(ah))
-               return;
-
-       aniState = ah->curani;
+       aniState = &ah->curchan->ani;
 
        if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
                if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
@@ -301,10 +228,7 @@ static void ath9k_hw_ani_cck_err_trigger_old(struct ath_hw *ah)
        struct ar5416AniState *aniState;
        int32_t rssi;
 
-       if (!DO_ANI(ah))
-               return;
-
-       aniState = ah->curani;
+       aniState = &ah->curchan->ani;
        if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
                if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
                                         aniState->noiseImmunityLevel + 1)) {
@@ -336,7 +260,7 @@ static void ath9k_hw_ani_cck_err_trigger_old(struct ath_hw *ah)
 /* Adjust the OFDM Noise Immunity Level */
 static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel)
 {
-       struct ar5416AniState *aniState = ah->curani;
+       struct ar5416AniState *aniState = &ah->curchan->ani;
        struct ath_common *common = ath9k_hw_common(ah);
        const struct ani_ofdm_level_entry *entry_ofdm;
        const struct ani_cck_level_entry *entry_cck;
@@ -381,14 +305,19 @@ static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel)
        }
 }
 
-static void ath9k_hw_ani_ofdm_err_trigger_new(struct ath_hw *ah)
+static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah)
 {
        struct ar5416AniState *aniState;
 
        if (!DO_ANI(ah))
                return;
 
-       aniState = ah->curani;
+       if (!use_new_ani(ah)) {
+               ath9k_hw_ani_ofdm_err_trigger_old(ah);
+               return;
+       }
+
+       aniState = &ah->curchan->ani;
 
        if (aniState->ofdmNoiseImmunityLevel < ATH9K_ANI_OFDM_MAX_LEVEL)
                ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel + 1);
@@ -399,7 +328,7 @@ static void ath9k_hw_ani_ofdm_err_trigger_new(struct ath_hw *ah)
  */
 static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel)
 {
-       struct ar5416AniState *aniState = ah->curani;
+       struct ar5416AniState *aniState = &ah->curchan->ani;
        struct ath_common *common = ath9k_hw_common(ah);
        const struct ani_ofdm_level_entry *entry_ofdm;
        const struct ani_cck_level_entry *entry_cck;
@@ -438,14 +367,19 @@ static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel)
                                     entry_cck->mrc_cck_on);
 }
 
-static void ath9k_hw_ani_cck_err_trigger_new(struct ath_hw *ah)
+static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah)
 {
        struct ar5416AniState *aniState;
 
        if (!DO_ANI(ah))
                return;
 
-       aniState = ah->curani;
+       if (!use_new_ani(ah)) {
+               ath9k_hw_ani_cck_err_trigger_old(ah);
+               return;
+       }
+
+       aniState = &ah->curchan->ani;
 
        if (aniState->cckNoiseImmunityLevel < ATH9K_ANI_CCK_MAX_LEVEL)
                ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel + 1);
@@ -456,7 +390,7 @@ static void ath9k_hw_ani_lower_immunity_old(struct ath_hw *ah)
        struct ar5416AniState *aniState;
        int32_t rssi;
 
-       aniState = ah->curani;
+       aniState = &ah->curchan->ani;
 
        if (ah->opmode == NL80211_IFTYPE_AP) {
                if (aniState->firstepLevel > 0) {
@@ -508,11 +442,16 @@ static void ath9k_hw_ani_lower_immunity_old(struct ath_hw *ah)
  * only lower either OFDM or CCK errors per turn
  * we lower the other one next time
  */
-static void ath9k_hw_ani_lower_immunity_new(struct ath_hw *ah)
+static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah)
 {
        struct ar5416AniState *aniState;
 
-       aniState = ah->curani;
+       aniState = &ah->curchan->ani;
+
+       if (!use_new_ani(ah)) {
+               ath9k_hw_ani_lower_immunity_old(ah);
+               return;
+       }
 
        /* lower OFDM noise immunity */
        if (aniState->ofdmNoiseImmunityLevel > 0 &&
@@ -544,52 +483,20 @@ static u8 ath9k_hw_chan_2_clockrate_mhz(struct ath_hw *ah)
        if (conf_is_ht40(conf))
                return clockrate * 2;
 
-       return clockrate * 2;
+       return clockrate;
 }
 
 static int32_t ath9k_hw_ani_get_listen_time(struct ath_hw *ah)
 {
-       struct ar5416AniState *aniState;
-       struct ath_common *common = ath9k_hw_common(ah);
-       u32 txFrameCount, rxFrameCount, cycleCount;
-       int32_t listenTime;
-
-       txFrameCount = REG_READ(ah, AR_TFCNT);
-       rxFrameCount = REG_READ(ah, AR_RFCNT);
-       cycleCount = REG_READ(ah, AR_CCCNT);
-
-       aniState = ah->curani;
-       if (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount) {
-               listenTime = 0;
-               ah->stats.ast_ani_lzero++;
-               ath_print(common, ATH_DBG_ANI,
-                         "1st call: aniState->cycleCount=%d\n",
-                         aniState->cycleCount);
-       } else {
-               int32_t ccdelta = cycleCount - aniState->cycleCount;
-               int32_t rfdelta = rxFrameCount - aniState->rxFrameCount;
-               int32_t tfdelta = txFrameCount - aniState->txFrameCount;
-               int32_t clock_rate;
+       int32_t listen_time;
+       int32_t clock_rate;
 
-               /*
-                * convert HW counter values to ms using mode
-                * specifix clock rate
-                */
-               clock_rate = ath9k_hw_chan_2_clockrate_mhz(ah) * 1000;;
+       ath9k_hw_update_cycle_counters(ah);
+       clock_rate = ath9k_hw_chan_2_clockrate_mhz(ah) * 1000;
+       listen_time = ah->listen_time / clock_rate;
+       ah->listen_time = 0;
 
-               listenTime = (ccdelta - rfdelta - tfdelta) / clock_rate;
-
-               ath_print(common, ATH_DBG_ANI,
-                         "cyclecount=%d, rfcount=%d, "
-                         "tfcount=%d, listenTime=%d CLOCK_RATE=%d\n",
-                         ccdelta, rfdelta, tfdelta, listenTime, clock_rate);
-       }
-
-       aniState->cycleCount = cycleCount;
-       aniState->txFrameCount = txFrameCount;
-       aniState->rxFrameCount = rxFrameCount;
-
-       return listenTime;
+       return listen_time;
 }
 
 static void ath9k_ani_reset_old(struct ath_hw *ah, bool is_scanning)
@@ -597,16 +504,13 @@ static void ath9k_ani_reset_old(struct ath_hw *ah, bool is_scanning)
        struct ar5416AniState *aniState;
        struct ath9k_channel *chan = ah->curchan;
        struct ath_common *common = ath9k_hw_common(ah);
-       int index;
 
        if (!DO_ANI(ah))
                return;
 
-       index = ath9k_hw_get_ani_channel_idx(ah, chan);
-       aniState = &ah->ani[index];
-       ah->curani = aniState;
+       aniState = &ah->curchan->ani;
 
-       if (DO_ANI(ah) && ah->opmode != NL80211_IFTYPE_STATION
+       if (ah->opmode != NL80211_IFTYPE_STATION
            && ah->opmode != NL80211_IFTYPE_ADHOC) {
                ath_print(common, ATH_DBG_ANI,
                          "Reset ANI state opmode %u\n", ah->opmode);
@@ -635,17 +539,7 @@ static void ath9k_ani_reset_old(struct ath_hw *ah, bool is_scanning)
                ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) |
                                     ATH9K_RX_FILTER_PHYERR);
 
-               if (ah->opmode == NL80211_IFTYPE_AP) {
-                       ah->curani->ofdmTrigHigh =
-                               ah->config.ofdm_trig_high;
-                       ah->curani->ofdmTrigLow =
-                               ah->config.ofdm_trig_low;
-                       ah->curani->cckTrigHigh =
-                               ah->config.cck_trig_high;
-                       ah->curani->cckTrigLow =
-                               ah->config.cck_trig_low;
-               }
-               ath9k_ani_restart_old(ah);
+               ath9k_ani_restart(ah);
                return;
        }
 
@@ -667,7 +561,7 @@ static void ath9k_ani_reset_old(struct ath_hw *ah, bool is_scanning)
 
        ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) &
                             ~ATH9K_RX_FILTER_PHYERR);
-       ath9k_ani_restart_old(ah);
+       ath9k_ani_restart(ah);
 
        ENABLE_REGWRITE_BUFFER(ah);
 
@@ -675,7 +569,6 @@ static void ath9k_ani_reset_old(struct ath_hw *ah, bool is_scanning)
        REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
 
        REGWRITE_BUFFER_FLUSH(ah);
-       DISABLE_REGWRITE_BUFFER(ah);
 }
 
 /*
@@ -683,15 +576,18 @@ static void ath9k_ani_reset_old(struct ath_hw *ah, bool is_scanning)
  * This routine should be called for every hardware reset and for
  * every channel change.
  */
-static void ath9k_ani_reset_new(struct ath_hw *ah, bool is_scanning)
+void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning)
 {
-       struct ar5416AniState *aniState = ah->curani;
+       struct ar5416AniState *aniState = &ah->curchan->ani;
        struct ath9k_channel *chan = ah->curchan;
        struct ath_common *common = ath9k_hw_common(ah);
 
        if (!DO_ANI(ah))
                return;
 
+       if (!use_new_ani(ah))
+               return ath9k_ani_reset_old(ah, is_scanning);
+
        BUG_ON(aniState == NULL);
        ah->stats.ast_ani_reset++;
 
@@ -761,7 +657,7 @@ static void ath9k_ani_reset_new(struct ath_hw *ah, bool is_scanning)
         * enable phy counters if hw supports or if not, enable phy
         * interrupts (so we can count each one)
         */
-       ath9k_ani_restart_new(ah);
+       ath9k_ani_restart(ah);
 
        ENABLE_REGWRITE_BUFFER(ah);
 
@@ -769,30 +665,30 @@ static void ath9k_ani_reset_new(struct ath_hw *ah, bool is_scanning)
        REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
 
        REGWRITE_BUFFER_FLUSH(ah);
-       DISABLE_REGWRITE_BUFFER(ah);
 }
 
-static void ath9k_hw_ani_monitor_old(struct ath_hw *ah,
-                                    struct ath9k_channel *chan)
+static void ath9k_hw_ani_read_counters(struct ath_hw *ah)
 {
-       struct ar5416AniState *aniState;
        struct ath_common *common = ath9k_hw_common(ah);
-       int32_t listenTime;
-       u32 phyCnt1, phyCnt2;
+       struct ar5416AniState *aniState = &ah->curchan->ani;
+       u32 ofdm_base = 0;
+       u32 cck_base = 0;
        u32 ofdmPhyErrCnt, cckPhyErrCnt;
-
-       if (!DO_ANI(ah))
-               return;
-
-       aniState = ah->curani;
+       u32 phyCnt1, phyCnt2;
+       int32_t listenTime;
 
        listenTime = ath9k_hw_ani_get_listen_time(ah);
        if (listenTime < 0) {
                ah->stats.ast_ani_lneg++;
-               ath9k_ani_restart_old(ah);
+               ath9k_ani_restart(ah);
                return;
        }
 
+       if (!use_new_ani(ah)) {
+               ofdm_base = AR_PHY_COUNTMAX - ah->config.ofdm_trig_high;
+               cck_base = AR_PHY_COUNTMAX - ah->config.cck_trig_high;
+       }
+
        aniState->listenTime += listenTime;
 
        ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
@@ -800,145 +696,54 @@ static void ath9k_hw_ani_monitor_old(struct ath_hw *ah,
        phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
        phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
 
-       if (phyCnt1 < aniState->ofdmPhyErrBase ||
-           phyCnt2 < aniState->cckPhyErrBase) {
-               if (phyCnt1 < aniState->ofdmPhyErrBase) {
+       if (use_new_ani(ah) && (phyCnt1 < ofdm_base || phyCnt2 < cck_base)) {
+               if (phyCnt1 < ofdm_base) {
                        ath_print(common, ATH_DBG_ANI,
                                  "phyCnt1 0x%x, resetting "
                                  "counter value to 0x%x\n",
-                                 phyCnt1,
-                                 aniState->ofdmPhyErrBase);
-                       REG_WRITE(ah, AR_PHY_ERR_1,
-                                 aniState->ofdmPhyErrBase);
+                                 phyCnt1, ofdm_base);
+                       REG_WRITE(ah, AR_PHY_ERR_1, ofdm_base);
                        REG_WRITE(ah, AR_PHY_ERR_MASK_1,
                                  AR_PHY_ERR_OFDM_TIMING);
                }
-               if (phyCnt2 < aniState->cckPhyErrBase) {
+               if (phyCnt2 < cck_base) {
                        ath_print(common, ATH_DBG_ANI,
                                  "phyCnt2 0x%x, resetting "
                                  "counter value to 0x%x\n",
-                                 phyCnt2,
-                                 aniState->cckPhyErrBase);
-                       REG_WRITE(ah, AR_PHY_ERR_2,
-                                 aniState->cckPhyErrBase);
+                                 phyCnt2, cck_base);
+                       REG_WRITE(ah, AR_PHY_ERR_2, cck_base);
                        REG_WRITE(ah, AR_PHY_ERR_MASK_2,
                                  AR_PHY_ERR_CCK_TIMING);
                }
                return;
        }
 
-       ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
+       ofdmPhyErrCnt = phyCnt1 - ofdm_base;
        ah->stats.ast_ani_ofdmerrs +=
                ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
        aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
 
-       cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
+       cckPhyErrCnt = phyCnt2 - cck_base;
        ah->stats.ast_ani_cckerrs +=
                cckPhyErrCnt - aniState->cckPhyErrCount;
        aniState->cckPhyErrCount = cckPhyErrCnt;
 
-       if (aniState->listenTime > 5 * ah->aniperiod) {
-               if (aniState->ofdmPhyErrCount <= aniState->listenTime *
-                   aniState->ofdmTrigLow / 1000 &&
-                   aniState->cckPhyErrCount <= aniState->listenTime *
-                   aniState->cckTrigLow / 1000)
-                       ath9k_hw_ani_lower_immunity(ah);
-               ath9k_ani_restart_old(ah);
-       } else if (aniState->listenTime > ah->aniperiod) {
-               if (aniState->ofdmPhyErrCount > aniState->listenTime *
-                   aniState->ofdmTrigHigh / 1000) {
-                       ath9k_hw_ani_ofdm_err_trigger_old(ah);
-                       ath9k_ani_restart_old(ah);
-               } else if (aniState->cckPhyErrCount >
-                          aniState->listenTime * aniState->cckTrigHigh /
-                          1000) {
-                       ath9k_hw_ani_cck_err_trigger_old(ah);
-                       ath9k_ani_restart_old(ah);
-               }
-       }
 }
 
-static void ath9k_hw_ani_monitor_new(struct ath_hw *ah,
-                                    struct ath9k_channel *chan)
+void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan)
 {
        struct ar5416AniState *aniState;
        struct ath_common *common = ath9k_hw_common(ah);
-       int32_t listenTime;
-       u32 phyCnt1, phyCnt2;
-       u32 ofdmPhyErrCnt, cckPhyErrCnt;
        u32 ofdmPhyErrRate, cckPhyErrRate;
 
        if (!DO_ANI(ah))
                return;
 
-       aniState = ah->curani;
+       aniState = &ah->curchan->ani;
        if (WARN_ON(!aniState))
                return;
 
-       listenTime = ath9k_hw_ani_get_listen_time(ah);
-       if (listenTime <= 0) {
-               ah->stats.ast_ani_lneg++;
-               /* restart ANI period if listenTime is invalid */
-               ath_print(common, ATH_DBG_ANI,
-                         "listenTime=%d - on new ani monitor\n",
-                         listenTime);
-               ath9k_ani_restart_new(ah);
-               return;
-       }
-
-       aniState->listenTime += listenTime;
-
-       ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
-
-       phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
-       phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
-
-       if (phyCnt1 < aniState->ofdmPhyErrBase ||
-           phyCnt2 < aniState->cckPhyErrBase) {
-               if (phyCnt1 < aniState->ofdmPhyErrBase) {
-                       ath_print(common, ATH_DBG_ANI,
-                                 "phyCnt1 0x%x, resetting "
-                                 "counter value to 0x%x\n",
-                                 phyCnt1,
-                                 aniState->ofdmPhyErrBase);
-                       REG_WRITE(ah, AR_PHY_ERR_1,
-                                 aniState->ofdmPhyErrBase);
-                       REG_WRITE(ah, AR_PHY_ERR_MASK_1,
-                                 AR_PHY_ERR_OFDM_TIMING);
-               }
-               if (phyCnt2 < aniState->cckPhyErrBase) {
-                       ath_print(common, ATH_DBG_ANI,
-                                 "phyCnt2 0x%x, resetting "
-                                 "counter value to 0x%x\n",
-                                 phyCnt2,
-                                 aniState->cckPhyErrBase);
-                       REG_WRITE(ah, AR_PHY_ERR_2,
-                                 aniState->cckPhyErrBase);
-                       REG_WRITE(ah, AR_PHY_ERR_MASK_2,
-                                 AR_PHY_ERR_CCK_TIMING);
-               }
-               return;
-       }
-
-       ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
-       ah->stats.ast_ani_ofdmerrs +=
-               ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
-       aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
-
-       cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
-       ah->stats.ast_ani_cckerrs +=
-               cckPhyErrCnt - aniState->cckPhyErrCount;
-       aniState->cckPhyErrCount = cckPhyErrCnt;
-
-       ath_print(common, ATH_DBG_ANI,
-                 "Errors: OFDM=0x%08x-0x%08x=%d   "
-                 "CCK=0x%08x-0x%08x=%d\n",
-                 phyCnt1,
-                 aniState->ofdmPhyErrBase,
-                 ofdmPhyErrCnt,
-                 phyCnt2,
-                 aniState->cckPhyErrBase,
-                 cckPhyErrCnt);
+       ath9k_hw_ani_read_counters(ah);
 
        ofdmPhyErrRate = aniState->ofdmPhyErrCount * 1000 /
                         aniState->listenTime;
@@ -948,61 +753,34 @@ static void ath9k_hw_ani_monitor_new(struct ath_hw *ah,
        ath_print(common, ATH_DBG_ANI,
                  "listenTime=%d OFDM:%d errs=%d/s CCK:%d "
                  "errs=%d/s ofdm_turn=%d\n",
-                 listenTime, aniState->ofdmNoiseImmunityLevel,
+                 aniState->listenTime,
+                 aniState->ofdmNoiseImmunityLevel,
                  ofdmPhyErrRate, aniState->cckNoiseImmunityLevel,
                  cckPhyErrRate, aniState->ofdmsTurn);
 
        if (aniState->listenTime > 5 * ah->aniperiod) {
-               if (ofdmPhyErrRate <= aniState->ofdmTrigLow &&
-                   cckPhyErrRate <= aniState->cckTrigLow) {
-                       ath_print(common, ATH_DBG_ANI,
-                                 "1. listenTime=%d OFDM:%d errs=%d/s(<%d)  "
-                                 "CCK:%d errs=%d/s(<%d) -> "
-                                 "ath9k_hw_ani_lower_immunity()\n",
-                                 aniState->listenTime,
-                                 aniState->ofdmNoiseImmunityLevel,
-                                 ofdmPhyErrRate,
-                                 aniState->ofdmTrigLow,
-                                 aniState->cckNoiseImmunityLevel,
-                                 cckPhyErrRate,
-                                 aniState->cckTrigLow);
+               if (ofdmPhyErrRate <= ah->config.ofdm_trig_low &&
+                   cckPhyErrRate <= ah->config.cck_trig_low) {
                        ath9k_hw_ani_lower_immunity(ah);
                        aniState->ofdmsTurn = !aniState->ofdmsTurn;
                }
-               ath_print(common, ATH_DBG_ANI,
-                         "1 listenTime=%d ofdm=%d/s cck=%d/s - "
-                         "calling ath9k_ani_restart_new()\n",
-                         aniState->listenTime, ofdmPhyErrRate, cckPhyErrRate);
-               ath9k_ani_restart_new(ah);
+               ath9k_ani_restart(ah);
        } else if (aniState->listenTime > ah->aniperiod) {
                /* check to see if need to raise immunity */
-               if (ofdmPhyErrRate > aniState->ofdmTrigHigh &&
-                   (cckPhyErrRate <= aniState->cckTrigHigh ||
+               if (ofdmPhyErrRate > ah->config.ofdm_trig_high &&
+                   (cckPhyErrRate <= ah->config.cck_trig_high ||
                     aniState->ofdmsTurn)) {
-                       ath_print(common, ATH_DBG_ANI,
-                                 "2 listenTime=%d OFDM:%d errs=%d/s(>%d) -> "
-                                 "ath9k_hw_ani_ofdm_err_trigger_new()\n",
-                                 aniState->listenTime,
-                                 aniState->ofdmNoiseImmunityLevel,
-                                 ofdmPhyErrRate,
-                                 aniState->ofdmTrigHigh);
-                       ath9k_hw_ani_ofdm_err_trigger_new(ah);
-                       ath9k_ani_restart_new(ah);
+                       ath9k_hw_ani_ofdm_err_trigger(ah);
+                       ath9k_ani_restart(ah);
                        aniState->ofdmsTurn = false;
-               } else if (cckPhyErrRate > aniState->cckTrigHigh) {
-                       ath_print(common, ATH_DBG_ANI,
-                                "3 listenTime=%d CCK:%d errs=%d/s(>%d) -> "
-                                "ath9k_hw_ani_cck_err_trigger_new()\n",
-                                aniState->listenTime,
-                                aniState->cckNoiseImmunityLevel,
-                                cckPhyErrRate,
-                                aniState->cckTrigHigh);
-                       ath9k_hw_ani_cck_err_trigger_new(ah);
-                       ath9k_ani_restart_new(ah);
+               } else if (cckPhyErrRate > ah->config.cck_trig_high) {
+                       ath9k_hw_ani_cck_err_trigger(ah);
+                       ath9k_ani_restart(ah);
                        aniState->ofdmsTurn = true;
                }
        }
 }
+EXPORT_SYMBOL(ath9k_hw_ani_monitor);
 
 void ath9k_enable_mib_counters(struct ath_hw *ah)
 {
@@ -1023,7 +801,6 @@ void ath9k_enable_mib_counters(struct ath_hw *ah)
        REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
 
        REGWRITE_BUFFER_FLUSH(ah);
-       DISABLE_REGWRITE_BUFFER(ah);
 }
 
 /* Freeze the MIB counters, get the stats and then clear them */
@@ -1041,107 +818,52 @@ void ath9k_hw_disable_mib_counters(struct ath_hw *ah)
 }
 EXPORT_SYMBOL(ath9k_hw_disable_mib_counters);
 
-u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah,
-                                 u32 *rxc_pcnt,
-                                 u32 *rxf_pcnt,
-                                 u32 *txf_pcnt)
+void ath9k_hw_update_cycle_counters(struct ath_hw *ah)
 {
-       struct ath_common *common = ath9k_hw_common(ah);
-       static u32 cycles, rx_clear, rx_frame, tx_frame;
-       u32 good = 1;
+       struct ath_cycle_counters cc;
+       bool clear;
 
-       u32 rc = REG_READ(ah, AR_RCCNT);
-       u32 rf = REG_READ(ah, AR_RFCNT);
-       u32 tf = REG_READ(ah, AR_TFCNT);
-       u32 cc = REG_READ(ah, AR_CCCNT);
+       memcpy(&cc, &ah->cc, sizeof(cc));
 
-       if (cycles == 0 || cycles > cc) {
-               ath_print(common, ATH_DBG_ANI,
-                         "cycle counter wrap. ExtBusy = 0\n");
-               good = 0;
-       } else {
-               u32 cc_d = cc - cycles;
-               u32 rc_d = rc - rx_clear;
-               u32 rf_d = rf - rx_frame;
-               u32 tf_d = tf - tx_frame;
-
-               if (cc_d != 0) {
-                       *rxc_pcnt = rc_d * 100 / cc_d;
-                       *rxf_pcnt = rf_d * 100 / cc_d;
-                       *txf_pcnt = tf_d * 100 / cc_d;
-               } else {
-                       good = 0;
-               }
-       }
+       /* freeze counters */
+       REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC);
 
-       cycles = cc;
-       rx_frame = rf;
-       rx_clear = rc;
-       tx_frame = tf;
+       ah->cc.cycles = REG_READ(ah, AR_CCCNT);
+       if (ah->cc.cycles < cc.cycles) {
+               clear = true;
+               goto skip;
+       }
 
-       return good;
-}
+       ah->cc.rx_clear = REG_READ(ah, AR_RCCNT);
+       ah->cc.rx_frame = REG_READ(ah, AR_RFCNT);
+       ah->cc.tx_frame = REG_READ(ah, AR_TFCNT);
 
-/*
- * Process a MIB interrupt.  We may potentially be invoked because
- * any of the MIB counters overflow/trigger so don't assume we're
- * here because a PHY error counter triggered.
- */
-static void ath9k_hw_proc_mib_event_old(struct ath_hw *ah)
-{
-       u32 phyCnt1, phyCnt2;
+       /* prevent wraparound */
+       if (ah->cc.cycles & BIT(31))
+               clear = true;
 
-       /* Reset these counters regardless */
-       REG_WRITE(ah, AR_FILT_OFDM, 0);
-       REG_WRITE(ah, AR_FILT_CCK, 0);
-       if (!(REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING))
-               REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR);
+#define CC_DELTA(_field, _reg) ah->cc_delta._field += ah->cc._field - cc._field
+       CC_DELTA(cycles, AR_CCCNT);
+       CC_DELTA(rx_frame, AR_RFCNT);
+       CC_DELTA(rx_clear, AR_RCCNT);
+       CC_DELTA(tx_frame, AR_TFCNT);
+#undef CC_DELTA
 
-       /* Clear the mib counters and save them in the stats */
-       ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
+       ah->listen_time += (ah->cc.cycles - cc.cycles) -
+                ((ah->cc.rx_frame - cc.rx_frame) +
+                 (ah->cc.tx_frame - cc.tx_frame));
 
-       if (!DO_ANI(ah)) {
-               /*
-                * We must always clear the interrupt cause by
-                * resetting the phy error regs.
-                */
-               REG_WRITE(ah, AR_PHY_ERR_1, 0);
-               REG_WRITE(ah, AR_PHY_ERR_2, 0);
-               return;
+skip:
+       if (clear) {
+               REG_WRITE(ah, AR_CCCNT, 0);
+               REG_WRITE(ah, AR_RFCNT, 0);
+               REG_WRITE(ah, AR_RCCNT, 0);
+               REG_WRITE(ah, AR_TFCNT, 0);
+               memset(&ah->cc, 0, sizeof(ah->cc));
        }
 
-       /* NB: these are not reset-on-read */
-       phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
-       phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
-       if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) ||
-           ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) {
-               struct ar5416AniState *aniState = ah->curani;
-               u32 ofdmPhyErrCnt, cckPhyErrCnt;
-
-               /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */
-               ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
-               ah->stats.ast_ani_ofdmerrs +=
-                       ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
-               aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
-
-               cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
-               ah->stats.ast_ani_cckerrs +=
-                       cckPhyErrCnt - aniState->cckPhyErrCount;
-               aniState->cckPhyErrCount = cckPhyErrCnt;
-
-               /*
-                * NB: figure out which counter triggered.  If both
-                * trigger we'll only deal with one as the processing
-                * clobbers the error counter so the trigger threshold
-                * check will never be true.
-                */
-               if (aniState->ofdmPhyErrCount > aniState->ofdmTrigHigh)
-                       ath9k_hw_ani_ofdm_err_trigger_new(ah);
-               if (aniState->cckPhyErrCount > aniState->cckTrigHigh)
-                       ath9k_hw_ani_cck_err_trigger_old(ah);
-               /* NB: always restart to insure the h/w counters are reset */
-               ath9k_ani_restart_old(ah);
-       }
+       /* unfreeze counters */
+       REG_WRITE(ah, AR_MIBC, 0);
 }
 
 /*
@@ -1149,7 +871,7 @@ static void ath9k_hw_proc_mib_event_old(struct ath_hw *ah)
  * any of the MIB counters overflow/trigger so don't assume we're
  * here because a PHY error counter triggered.
  */
-static void ath9k_hw_proc_mib_event_new(struct ath_hw *ah)
+void ath9k_hw_proc_mib_event(struct ath_hw *ah)
 {
        u32 phyCnt1, phyCnt2;
 
@@ -1175,12 +897,17 @@ static void ath9k_hw_proc_mib_event_new(struct ath_hw *ah)
        /* NB: these are not reset-on-read */
        phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
        phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
-
-       /* NB: always restart to insure the h/w counters are reset */
        if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) ||
-           ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK))
-               ath9k_ani_restart_new(ah);
+           ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) {
+
+               if (!use_new_ani(ah))
+                       ath9k_hw_ani_read_counters(ah);
+
+               /* NB: always restart to insure the h/w counters are reset */
+               ath9k_ani_restart(ah);
+       }
 }
+EXPORT_SYMBOL(ath9k_hw_proc_mib_event);
 
 void ath9k_hw_ani_setup(struct ath_hw *ah)
 {
@@ -1206,61 +933,58 @@ void ath9k_hw_ani_init(struct ath_hw *ah)
 
        ath_print(common, ATH_DBG_ANI, "Initialize ANI\n");
 
-       memset(ah->ani, 0, sizeof(ah->ani));
-       for (i = 0; i < ARRAY_SIZE(ah->ani); i++) {
-               if (AR_SREV_9300_20_OR_LATER(ah) || modparam_force_new_ani) {
-                       ah->ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH_NEW;
-                       ah->ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW_NEW;
+       if (use_new_ani(ah)) {
+               ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH_NEW;
+               ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW_NEW;
 
-                       ah->ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH_NEW;
-                       ah->ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW_NEW;
+               ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH_NEW;
+               ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW_NEW;
+       } else {
+               ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH_OLD;
+               ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW_OLD;
 
-                       ah->ani[i].spurImmunityLevel =
-                               ATH9K_ANI_SPUR_IMMUNE_LVL_NEW;
+               ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH_OLD;
+               ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW_OLD;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(ah->channels); i++) {
+               struct ath9k_channel *chan = &ah->channels[i];
+               struct ar5416AniState *ani = &chan->ani;
 
-                       ah->ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL_NEW;
+               if (use_new_ani(ah)) {
+                       ani->spurImmunityLevel =
+                               ATH9K_ANI_SPUR_IMMUNE_LVL_NEW;
 
-                       ah->ani[i].ofdmPhyErrBase = 0;
-                       ah->ani[i].cckPhyErrBase = 0;
+                       ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL_NEW;
 
                        if (AR_SREV_9300_20_OR_LATER(ah))
-                               ah->ani[i].mrcCCKOff =
+                               ani->mrcCCKOff =
                                        !ATH9K_ANI_ENABLE_MRC_CCK;
                        else
-                               ah->ani[i].mrcCCKOff = true;
+                               ani->mrcCCKOff = true;
 
-                       ah->ani[i].ofdmsTurn = true;
+                       ani->ofdmsTurn = true;
                } else {
-                       ah->ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH_OLD;
-                       ah->ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW_OLD;
-
-                       ah->ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH_OLD;
-                       ah->ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW_OLD;
-
-                       ah->ani[i].spurImmunityLevel =
+                       ani->spurImmunityLevel =
                                ATH9K_ANI_SPUR_IMMUNE_LVL_OLD;
-                       ah->ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL_OLD;
+                       ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL_OLD;
 
-                       ah->ani[i].ofdmPhyErrBase =
-                               AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH_OLD;
-                       ah->ani[i].cckPhyErrBase =
-                               AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH_OLD;
-                       ah->ani[i].cckWeakSigThreshold =
+                       ani->cckWeakSigThreshold =
                                ATH9K_ANI_CCK_WEAK_SIG_THR;
                }
 
-               ah->ani[i].rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH;
-               ah->ani[i].rssiThrLow = ATH9K_ANI_RSSI_THR_LOW;
-               ah->ani[i].ofdmWeakSigDetectOff =
+               ani->rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH;
+               ani->rssiThrLow = ATH9K_ANI_RSSI_THR_LOW;
+               ani->ofdmWeakSigDetectOff =
                        !ATH9K_ANI_USE_OFDM_WEAK_SIG;
-               ah->ani[i].cckNoiseImmunityLevel = ATH9K_ANI_CCK_DEF_LEVEL;
+               ani->cckNoiseImmunityLevel = ATH9K_ANI_CCK_DEF_LEVEL;
        }
 
        /*
         * since we expect some ongoing maintenance on the tables, let's sanity
         * check here default level should not modify INI setting.
         */
-       if (AR_SREV_9300_20_OR_LATER(ah) || modparam_force_new_ani) {
+       if (use_new_ani(ah)) {
                const struct ani_ofdm_level_entry *entry_ofdm;
                const struct ani_cck_level_entry *entry_cck;
 
@@ -1274,50 +998,9 @@ void ath9k_hw_ani_init(struct ath_hw *ah)
                ah->config.ani_poll_interval = ATH9K_ANI_POLLINTERVAL_OLD;
        }
 
-       ath_print(common, ATH_DBG_ANI,
-                 "Setting OfdmErrBase = 0x%08x\n",
-                 ah->ani[0].ofdmPhyErrBase);
-       ath_print(common, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n",
-                 ah->ani[0].cckPhyErrBase);
-
-       ENABLE_REGWRITE_BUFFER(ah);
-
-       REG_WRITE(ah, AR_PHY_ERR_1, ah->ani[0].ofdmPhyErrBase);
-       REG_WRITE(ah, AR_PHY_ERR_2, ah->ani[0].cckPhyErrBase);
-
-       REGWRITE_BUFFER_FLUSH(ah);
-       DISABLE_REGWRITE_BUFFER(ah);
-
-       ath9k_enable_mib_counters(ah);
-
        if (ah->config.enable_ani)
                ah->proc_phyerr |= HAL_PROCESS_ANI;
-}
-
-void ath9k_hw_attach_ani_ops_old(struct ath_hw *ah)
-{
-       struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
-       struct ath_hw_ops *ops = ath9k_hw_ops(ah);
 
-       priv_ops->ani_reset = ath9k_ani_reset_old;
-       priv_ops->ani_lower_immunity = ath9k_hw_ani_lower_immunity_old;
-
-       ops->ani_proc_mib_event = ath9k_hw_proc_mib_event_old;
-       ops->ani_monitor = ath9k_hw_ani_monitor_old;
-
-       ath_print(ath9k_hw_common(ah), ATH_DBG_ANY, "Using ANI v1\n");
-}
-
-void ath9k_hw_attach_ani_ops_new(struct ath_hw *ah)
-{
-       struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
-       struct ath_hw_ops *ops = ath9k_hw_ops(ah);
-
-       priv_ops->ani_reset = ath9k_ani_reset_new;
-       priv_ops->ani_lower_immunity = ath9k_hw_ani_lower_immunity_new;
-
-       ops->ani_proc_mib_event = ath9k_hw_proc_mib_event_new;
-       ops->ani_monitor = ath9k_hw_ani_monitor_new;
-
-       ath_print(ath9k_hw_common(ah), ATH_DBG_ANY, "Using ANI v2\n");
+       ath9k_ani_restart(ah);
+       ath9k_enable_mib_counters(ah);
 }
index f4d0a4d48b37b18ec3e3f0f828f6b30743d19147..98cfd8154c71d5b90a9a0dd44c05c09446f97b1a 100644 (file)
@@ -19,7 +19,7 @@
 
 #define HAL_PROCESS_ANI           0x00000001
 
-#define DO_ANI(ah) (((ah)->proc_phyerr & HAL_PROCESS_ANI))
+#define DO_ANI(ah) (((ah)->proc_phyerr & HAL_PROCESS_ANI) && ah->curchan)
 
 #define BEACON_RSSI(ahp) (ahp->stats.avgbrssi)
 
@@ -93,6 +93,13 @@ struct ath9k_mib_stats {
        u32 beacons;
 };
 
+struct ath_cycle_counters {
+       u32 cycles;
+       u32 rx_frame;
+       u32 rx_clear;
+       u32 tx_frame;
+};
+
 /* INI default values for ANI registers */
 struct ath9k_ani_default {
        u16 m1ThreshLow;
@@ -123,20 +130,11 @@ struct ar5416AniState {
        u8 ofdmWeakSigDetectOff;
        u8 cckWeakSigThreshold;
        u32 listenTime;
-       u32 ofdmTrigHigh;
-       u32 ofdmTrigLow;
-       int32_t cckTrigHigh;
-       int32_t cckTrigLow;
        int32_t rssiThrLow;
        int32_t rssiThrHigh;
        u32 noiseFloor;
-       u32 txFrameCount;
-       u32 rxFrameCount;
-       u32 cycleCount;
        u32 ofdmPhyErrCount;
        u32 cckPhyErrCount;
-       u32 ofdmPhyErrBase;
-       u32 cckPhyErrBase;
        int16_t pktRssi[2];
        int16_t ofdmErrRssi[2];
        int16_t cckErrRssi[2];
@@ -166,8 +164,7 @@ struct ar5416Stats {
 
 void ath9k_enable_mib_counters(struct ath_hw *ah);
 void ath9k_hw_disable_mib_counters(struct ath_hw *ah);
-u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah, u32 *rxc_pcnt,
-                                 u32 *rxf_pcnt, u32 *txf_pcnt);
+void ath9k_hw_update_cycle_counters(struct ath_hw *ah);
 void ath9k_hw_ani_setup(struct ath_hw *ah);
 void ath9k_hw_ani_init(struct ath_hw *ah);
 int ath9k_hw_get_ani_channel_idx(struct ath_hw *ah,
index 525671f52b451ba010f0ba98e0550e7479e6a4b2..ea9f4497f58c79bd491d84181a605e7b251f4b91 100644 (file)
@@ -613,14 +613,11 @@ static void ar5008_hw_init_chain_masks(struct ath_hw *ah)
        rx_chainmask = ah->rxchainmask;
        tx_chainmask = ah->txchainmask;
 
-       ENABLE_REGWRITE_BUFFER(ah);
 
        switch (rx_chainmask) {
        case 0x5:
-               DISABLE_REGWRITE_BUFFER(ah);
                REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP,
                            AR_PHY_SWAP_ALT_CHAIN);
-               ENABLE_REGWRITE_BUFFER(ah);
        case 0x3:
                if (ah->hw_version.macVersion == AR_SREV_REVISION_5416_10) {
                        REG_WRITE(ah, AR_PHY_RX_CHAINMASK, 0x7);
@@ -630,17 +627,18 @@ static void ar5008_hw_init_chain_masks(struct ath_hw *ah)
        case 0x1:
        case 0x2:
        case 0x7:
+               ENABLE_REGWRITE_BUFFER(ah);
                REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask);
                REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask);
                break;
        default:
+               ENABLE_REGWRITE_BUFFER(ah);
                break;
        }
 
        REG_WRITE(ah, AR_SELFGEN_MASK, tx_chainmask);
 
        REGWRITE_BUFFER_FLUSH(ah);
-       DISABLE_REGWRITE_BUFFER(ah);
 
        if (tx_chainmask == 0x5) {
                REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP,
@@ -726,7 +724,6 @@ static void ar5008_hw_set_channel_regs(struct ath_hw *ah,
        REG_WRITE(ah, AR_CST, 0xF << AR_CST_TIMEOUT_LIMIT_S);
 
        REGWRITE_BUFFER_FLUSH(ah);
-       DISABLE_REGWRITE_BUFFER(ah);
 }
 
 
@@ -818,7 +815,6 @@ static int ar5008_hw_process_ini(struct ath_hw *ah,
        }
 
        REGWRITE_BUFFER_FLUSH(ah);
-       DISABLE_REGWRITE_BUFFER(ah);
 
        if (AR_SREV_9280(ah) || AR_SREV_9287_11_OR_LATER(ah))
                REG_WRITE_ARRAY(&ah->iniModesRxGain, modesIndex, regWrites);
@@ -849,7 +845,6 @@ static int ar5008_hw_process_ini(struct ath_hw *ah,
        }
 
        REGWRITE_BUFFER_FLUSH(ah);
-       DISABLE_REGWRITE_BUFFER(ah);
 
        if (AR_SREV_9271(ah)) {
                if (ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE) == 1)
@@ -1053,7 +1048,7 @@ static bool ar5008_hw_ani_control_old(struct ath_hw *ah,
                                      enum ath9k_ani_cmd cmd,
                                      int param)
 {
-       struct ar5416AniState *aniState = ah->curani;
+       struct ar5416AniState *aniState = &ah->curchan->ani;
        struct ath_common *common = ath9k_hw_common(ah);
 
        switch (cmd & ah->ani_function) {
@@ -1225,8 +1220,7 @@ static bool ar5008_hw_ani_control_old(struct ath_hw *ah,
                  aniState->firstepLevel,
                  aniState->listenTime);
        ath_print(common, ATH_DBG_ANI,
-               "cycleCount=%d, ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n",
-               aniState->cycleCount,
+               "ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n",
                aniState->ofdmPhyErrCount,
                aniState->cckPhyErrCount);
 
@@ -1237,9 +1231,9 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah,
                                      enum ath9k_ani_cmd cmd,
                                      int param)
 {
-       struct ar5416AniState *aniState = ah->curani;
        struct ath_common *common = ath9k_hw_common(ah);
        struct ath9k_channel *chan = ah->curchan;
+       struct ar5416AniState *aniState = &chan->ani;
        s32 value, value2;
 
        switch (cmd & ah->ani_function) {
@@ -1478,15 +1472,13 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah,
 
        ath_print(common, ATH_DBG_ANI,
                  "ANI parameters: SI=%d, ofdmWS=%s FS=%d "
-                 "MRCcck=%s listenTime=%d CC=%d listen=%d "
+                 "MRCcck=%s listenTime=%d "
                  "ofdmErrs=%d cckErrs=%d\n",
                  aniState->spurImmunityLevel,
                  !aniState->ofdmWeakSigDetectOff ? "on" : "off",
                  aniState->firstepLevel,
                  !aniState->mrcCCKOff ? "on" : "off",
                  aniState->listenTime,
-                 aniState->cycleCount,
-                 aniState->listenTime,
                  aniState->ofdmPhyErrCount,
                  aniState->cckPhyErrCount);
        return true;
@@ -1526,16 +1518,12 @@ static void ar5008_hw_do_getnf(struct ath_hw *ah,
  */
 static void ar5008_hw_ani_cache_ini_regs(struct ath_hw *ah)
 {
-       struct ar5416AniState *aniState;
        struct ath_common *common = ath9k_hw_common(ah);
        struct ath9k_channel *chan = ah->curchan;
+       struct ar5416AniState *aniState = &chan->ani;
        struct ath9k_ani_default *iniDef;
-       int index;
        u32 val;
 
-       index = ath9k_hw_get_ani_channel_idx(ah, chan);
-       aniState = &ah->ani[index];
-       ah->curani = aniState;
        iniDef = &aniState->iniDef;
 
        ath_print(common, ATH_DBG_ANI,
@@ -1579,8 +1567,6 @@ static void ar5008_hw_ani_cache_ini_regs(struct ath_hw *ah)
        aniState->firstepLevel = ATH9K_ANI_FIRSTEP_LVL_NEW;
        aniState->ofdmWeakSigDetectOff = !ATH9K_ANI_USE_OFDM_WEAK_SIG;
        aniState->mrcCCKOff = true; /* not available on pre AR9003 */
-
-       aniState->cycleCount = 0;
 }
 
 static void ar5008_hw_set_nf_limits(struct ath_hw *ah)
index d7d1d55362e6059c82398d6f893c611b7b6edac8..15f62cd0cc38a239ceac760e55eff1c9d4c1db92 100644 (file)
 
 #define AR9285_CLCAL_REDO_THRESH    1
 
+enum ar9002_cal_types {
+       ADC_GAIN_CAL = BIT(0),
+       ADC_DC_CAL = BIT(1),
+       IQ_MISMATCH_CAL = BIT(2),
+};
+
+
 static void ar9002_hw_setup_calibration(struct ath_hw *ah,
                                        struct ath9k_cal_list *currCal)
 {
@@ -45,13 +52,6 @@ static void ar9002_hw_setup_calibration(struct ath_hw *ah,
                ath_print(common, ATH_DBG_CALIBRATE,
                          "starting ADC DC Calibration\n");
                break;
-       case ADC_DC_INIT_CAL:
-               REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_INIT);
-               ath_print(common, ATH_DBG_CALIBRATE,
-                         "starting Init ADC DC Calibration\n");
-               break;
-       case TEMP_COMP_CAL:
-               break; /* Not supported */
        }
 
        REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0),
@@ -96,25 +96,6 @@ static bool ar9002_hw_per_calibration(struct ath_hw *ah,
        return iscaldone;
 }
 
-/* Assumes you are talking about the currently configured channel */
-static bool ar9002_hw_iscal_supported(struct ath_hw *ah,
-                                     enum ath9k_cal_types calType)
-{
-       struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
-
-       switch (calType & ah->supp_cals) {
-       case IQ_MISMATCH_CAL: /* Both 2 GHz and 5 GHz support OFDM */
-               return true;
-       case ADC_GAIN_CAL:
-       case ADC_DC_CAL:
-               if (!(conf->channel->band == IEEE80211_BAND_2GHZ &&
-                     conf_is_ht20(conf)))
-                       return true;
-               break;
-       }
-       return false;
-}
-
 static void ar9002_hw_iqcal_collect(struct ath_hw *ah)
 {
        int i;
@@ -541,7 +522,6 @@ static void ar9271_hw_pa_cal(struct ath_hw *ah, bool is_reset)
                REG_WRITE(ah, regList[i][0], regList[i][1]);
 
        REGWRITE_BUFFER_FLUSH(ah);
-       DISABLE_REGWRITE_BUFFER(ah);
 }
 
 static inline void ar9285_hw_pa_cal(struct ath_hw *ah, bool is_reset)
@@ -877,24 +857,28 @@ static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
 
        /* Enable IQ, ADC Gain and ADC DC offset CALs */
        if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) {
-               if (ar9002_hw_iscal_supported(ah, ADC_GAIN_CAL)) {
+               ah->supp_cals = IQ_MISMATCH_CAL;
+
+               if (AR_SREV_9160_10_OR_LATER(ah) &&
+                   !(IS_CHAN_2GHZ(chan) && IS_CHAN_HT20(chan))) {
+                       ah->supp_cals |= ADC_GAIN_CAL | ADC_DC_CAL;
+
+
                        INIT_CAL(&ah->adcgain_caldata);
                        INSERT_CAL(ah, &ah->adcgain_caldata);
                        ath_print(common, ATH_DBG_CALIBRATE,
                                  "enabling ADC Gain Calibration.\n");
-               }
-               if (ar9002_hw_iscal_supported(ah, ADC_DC_CAL)) {
+
                        INIT_CAL(&ah->adcdc_caldata);
                        INSERT_CAL(ah, &ah->adcdc_caldata);
                        ath_print(common, ATH_DBG_CALIBRATE,
                                  "enabling ADC DC Calibration.\n");
                }
-               if (ar9002_hw_iscal_supported(ah, IQ_MISMATCH_CAL)) {
-                       INIT_CAL(&ah->iq_caldata);
-                       INSERT_CAL(ah, &ah->iq_caldata);
-                       ath_print(common, ATH_DBG_CALIBRATE,
-                                 "enabling IQ Calibration.\n");
-               }
+
+               INIT_CAL(&ah->iq_caldata);
+               INSERT_CAL(ah, &ah->iq_caldata);
+               ath_print(common, ATH_DBG_CALIBRATE,
+                         "enabling IQ Calibration.\n");
 
                ah->cal_list_curr = ah->cal_list;
 
@@ -950,13 +934,6 @@ static const struct ath9k_percal_data adc_dc_cal_single_sample = {
        ar9002_hw_adc_dccal_collect,
        ar9002_hw_adc_dccal_calibrate
 };
-static const struct ath9k_percal_data adc_init_dc_cal = {
-       ADC_DC_INIT_CAL,
-       MIN_CAL_SAMPLES,
-       INIT_LOG_COUNT,
-       ar9002_hw_adc_dccal_collect,
-       ar9002_hw_adc_dccal_calibrate
-};
 
 static void ar9002_hw_init_cal_settings(struct ath_hw *ah)
 {
@@ -973,16 +950,12 @@ static void ar9002_hw_init_cal_settings(struct ath_hw *ah)
                                &adc_gain_cal_single_sample;
                        ah->adcdc_caldata.calData =
                                &adc_dc_cal_single_sample;
-                       ah->adcdc_calinitdata.calData =
-                               &adc_init_dc_cal;
                } else {
                        ah->iq_caldata.calData = &iq_cal_multi_sample;
                        ah->adcgain_caldata.calData =
                                &adc_gain_cal_multi_sample;
                        ah->adcdc_caldata.calData =
                                &adc_dc_cal_multi_sample;
-                       ah->adcdc_calinitdata.calData =
-                               &adc_init_dc_cal;
                }
                ah->supp_cals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL;
        }
@@ -996,7 +969,6 @@ void ar9002_hw_attach_calib_ops(struct ath_hw *ah)
        priv_ops->init_cal_settings = ar9002_hw_init_cal_settings;
        priv_ops->init_cal = ar9002_hw_init_cal;
        priv_ops->setup_calibration = ar9002_hw_setup_calibration;
-       priv_ops->iscal_supported = ar9002_hw_iscal_supported;
 
        ops->calibrate = ar9002_hw_calibrate;
 }
index fde45082a13b168b88ed25d887c374627f5bfa87..a0471f2e1c7a0e8cadb92adb09aa06d3b0b7a1ef 100644 (file)
@@ -371,7 +371,6 @@ static void ar9002_hw_configpcipowersave(struct ath_hw *ah,
                        REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
 
                        REGWRITE_BUFFER_FLUSH(ah);
-                       DISABLE_REGWRITE_BUFFER(ah);
                }
 
                udelay(1000);
@@ -468,7 +467,6 @@ static int ar9002_hw_get_radiorev(struct ath_hw *ah)
                REG_WRITE(ah, AR_PHY(0x20), 0x00010000);
 
        REGWRITE_BUFFER_FLUSH(ah);
-       DISABLE_REGWRITE_BUFFER(ah);
 
        val = (REG_READ(ah, AR_PHY(256)) >> 24) & 0xff;
        val = ((val & 0xf0) >> 4) | ((val & 0x0f) << 4);
@@ -574,11 +572,6 @@ void ar9002_hw_attach_ops(struct ath_hw *ah)
 
        ar9002_hw_attach_calib_ops(ah);
        ar9002_hw_attach_mac_ops(ah);
-
-       if (modparam_force_new_ani)
-               ath9k_hw_attach_ani_ops_new(ah);
-       else
-               ath9k_hw_attach_ani_ops_old(ah);
 }
 
 void ar9002_hw_load_ani_reg(struct ath_hw *ah, struct ath9k_channel *chan)
@@ -627,6 +620,4 @@ void ar9002_hw_load_ani_reg(struct ath_hw *ah, struct ath9k_channel *chan)
        }
 
        REGWRITE_BUFFER_FLUSH(ah);
-       DISABLE_REGWRITE_BUFFER(ah);
-
 }
index cd56c86927056038c77906705ea2ae4309437c87..c00cdc67b55ba5291f9ebc758d342f7dfb3184a1 100644 (file)
@@ -415,7 +415,6 @@ static void ar9002_hw_spur_mitigate(struct ath_hw *ah,
        REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask);
 
        REGWRITE_BUFFER_FLUSH(ah);
-       DISABLE_REGWRITE_BUFFER(ah);
 }
 
 static void ar9002_olc_init(struct ath_hw *ah)
index 4674ea8c9c99497add7587ff30c6f94c7f7f6ef1..9e6edffe0bd125544bce11b4d1dbcea470173add 100644 (file)
 #include "hw-ops.h"
 #include "ar9003_phy.h"
 
+enum ar9003_cal_types {
+       IQ_MISMATCH_CAL = BIT(0),
+       TEMP_COMP_CAL = BIT(1),
+};
+
 static void ar9003_hw_setup_calibration(struct ath_hw *ah,
                                        struct ath9k_cal_list *currCal)
 {
@@ -50,11 +55,6 @@ static void ar9003_hw_setup_calibration(struct ath_hw *ah,
                ath_print(common, ATH_DBG_CALIBRATE,
                          "starting Temperature Compensation Calibration\n");
                break;
-       case ADC_DC_INIT_CAL:
-       case ADC_GAIN_CAL:
-       case ADC_DC_CAL:
-               /* Not yet */
-               break;
        }
 }
 
@@ -314,27 +314,6 @@ static const struct ath9k_percal_data iq_cal_single_sample = {
 static void ar9003_hw_init_cal_settings(struct ath_hw *ah)
 {
        ah->iq_caldata.calData = &iq_cal_single_sample;
-       ah->supp_cals = IQ_MISMATCH_CAL;
-}
-
-static bool ar9003_hw_iscal_supported(struct ath_hw *ah,
-                                     enum ath9k_cal_types calType)
-{
-       switch (calType & ah->supp_cals) {
-       case IQ_MISMATCH_CAL:
-               /*
-                * XXX: Run IQ Mismatch for non-CCK only
-                * Note that CHANNEL_B is never set though.
-                */
-               return true;
-       case ADC_GAIN_CAL:
-       case ADC_DC_CAL:
-               return false;
-       case TEMP_COMP_CAL:
-               return true;
-       }
-
-       return false;
 }
 
 /*
@@ -773,15 +752,16 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
 
        /* Initialize list pointers */
        ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL;
+       ah->supp_cals = IQ_MISMATCH_CAL;
 
-       if (ar9003_hw_iscal_supported(ah, IQ_MISMATCH_CAL)) {
+       if (ah->supp_cals & IQ_MISMATCH_CAL) {
                INIT_CAL(&ah->iq_caldata);
                INSERT_CAL(ah, &ah->iq_caldata);
                ath_print(common, ATH_DBG_CALIBRATE,
                          "enabling IQ Calibration.\n");
        }
 
-       if (ar9003_hw_iscal_supported(ah, TEMP_COMP_CAL)) {
+       if (ah->supp_cals & TEMP_COMP_CAL) {
                INIT_CAL(&ah->tempCompCalData);
                INSERT_CAL(ah, &ah->tempCompCalData);
                ath_print(common, ATH_DBG_CALIBRATE,
@@ -808,7 +788,6 @@ void ar9003_hw_attach_calib_ops(struct ath_hw *ah)
        priv_ops->init_cal_settings = ar9003_hw_init_cal_settings;
        priv_ops->init_cal = ar9003_hw_init_cal;
        priv_ops->setup_calibration = ar9003_hw_setup_calibration;
-       priv_ops->iscal_supported = ar9003_hw_iscal_supported;
 
        ops->calibrate = ar9003_hw_calibrate;
 }
index 064168909108005531e90e9ea657f51a43866794..02c970819f794015a693cd7a7fda1bc391cd0d0f 100644 (file)
@@ -333,6 +333,4 @@ void ar9003_hw_attach_ops(struct ath_hw *ah)
        ar9003_hw_attach_phy_ops(ah);
        ar9003_hw_attach_calib_ops(ah);
        ar9003_hw_attach_mac_ops(ah);
-
-       ath9k_hw_attach_ani_ops_new(ah);
 }
index a491854fa38aa7173c5b976c54da6551f4f96aa9..efb05599b84c52c55dff8d28d86227e170dd4575 100644 (file)
@@ -747,9 +747,9 @@ static void ar9003_hw_set_diversity(struct ath_hw *ah, bool value)
 static bool ar9003_hw_ani_control(struct ath_hw *ah,
                                  enum ath9k_ani_cmd cmd, int param)
 {
-       struct ar5416AniState *aniState = ah->curani;
        struct ath_common *common = ath9k_hw_common(ah);
        struct ath9k_channel *chan = ah->curchan;
+       struct ar5416AniState *aniState = &chan->ani;
        s32 value, value2;
 
        switch (cmd & ah->ani_function) {
@@ -1005,15 +1005,13 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah,
 
        ath_print(common, ATH_DBG_ANI,
                  "ANI parameters: SI=%d, ofdmWS=%s FS=%d "
-                 "MRCcck=%s listenTime=%d CC=%d listen=%d "
+                 "MRCcck=%s listenTime=%d "
                  "ofdmErrs=%d cckErrs=%d\n",
                  aniState->spurImmunityLevel,
                  !aniState->ofdmWeakSigDetectOff ? "on" : "off",
                  aniState->firstepLevel,
                  !aniState->mrcCCKOff ? "on" : "off",
                  aniState->listenTime,
-                 aniState->cycleCount,
-                 aniState->listenTime,
                  aniState->ofdmPhyErrCount,
                  aniState->cckPhyErrCount);
        return true;
@@ -1067,12 +1065,9 @@ static void ar9003_hw_ani_cache_ini_regs(struct ath_hw *ah)
        struct ath_common *common = ath9k_hw_common(ah);
        struct ath9k_channel *chan = ah->curchan;
        struct ath9k_ani_default *iniDef;
-       int index;
        u32 val;
 
-       index = ath9k_hw_get_ani_channel_idx(ah, chan);
-       aniState = &ah->ani[index];
-       ah->curani = aniState;
+       aniState = &ah->curchan->ani;
        iniDef = &aniState->iniDef;
 
        ath_print(common, ATH_DBG_ANI,
@@ -1116,8 +1111,6 @@ static void ar9003_hw_ani_cache_ini_regs(struct ath_hw *ah)
        aniState->firstepLevel = ATH9K_ANI_FIRSTEP_LVL_NEW;
        aniState->ofdmWeakSigDetectOff = !ATH9K_ANI_USE_OFDM_WEAK_SIG;
        aniState->mrcCCKOff = !ATH9K_ANI_ENABLE_MRC_CCK;
-
-       aniState->cycleCount = 0;
 }
 
 void ar9003_hw_attach_phy_ops(struct ath_hw *ah)
@@ -1232,7 +1225,7 @@ void ar9003_hw_bb_watchdog_read(struct ath_hw *ah)
 void ar9003_hw_bb_watchdog_dbg_info(struct ath_hw *ah)
 {
        struct ath_common *common = ath9k_hw_common(ah);
-       u32 rxc_pcnt = 0, rxf_pcnt = 0, txf_pcnt = 0, status;
+       u32 status;
 
        if (likely(!(common->debug_mask & ATH_DBG_RESET)))
                return;
@@ -1261,11 +1254,13 @@ void ar9003_hw_bb_watchdog_dbg_info(struct ath_hw *ah)
                  "** BB mode: BB_gen_controls=0x%08x **\n",
                  REG_READ(ah, AR_PHY_GEN_CTRL));
 
-       if (ath9k_hw_GetMibCycleCountsPct(ah, &rxc_pcnt, &rxf_pcnt, &txf_pcnt))
+       ath9k_hw_update_cycle_counters(ah);
+#define PCT(_field) (ah->cc_delta._field * 100 / ah->cc_delta.cycles)
+       if (ah->cc_delta.cycles)
                ath_print(common, ATH_DBG_RESET,
                          "** BB busy times: rx_clear=%d%%, "
                          "rx_frame=%d%%, tx_frame=%d%% **\n",
-                         rxc_pcnt, rxf_pcnt, txf_pcnt);
+                         PCT(rx_clear), PCT(rx_frame), PCT(tx_frame));
 
        ath_print(common, ATH_DBG_RESET,
                  "==== BB update: done ====\n\n");
index 9f8e542ef47e20713c372b7f07866e5876b238ee..de2b18ee7f771eba0f66d5fb880266d5c1f1e2be 100644 (file)
@@ -241,7 +241,6 @@ struct ath_buf {
        dma_addr_t bf_daddr;            /* physical addr of desc */
        dma_addr_t bf_buf_addr;         /* physical addr of data buffer */
        bool bf_stale;
-       bool bf_isnullfunc;
        bool bf_tx_aborted;
        u16 bf_flags;
        struct ath_buf_state bf_state;
@@ -349,7 +348,6 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
                      u16 tid, u16 *ssn);
 void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
 void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
-void ath9k_enable_ps(struct ath_softc *sc);
 
 /********/
 /* VIFs */
@@ -573,8 +571,6 @@ struct ath_ant_comb {
 #define PS_WAIT_FOR_PSPOLL_DATA   BIT(2)
 #define PS_WAIT_FOR_TX_ACK        BIT(3)
 #define PS_BEACON_SYNC            BIT(4)
-#define PS_NULLFUNC_COMPLETED     BIT(5)
-#define PS_ENABLED                BIT(6)
 
 struct ath_wiphy;
 struct ath_rate_table;
index 67ee5d735cc12a30b5f642c0d0860531a4242ed1..6d509484b5f6144babfc5646412bc0f8d7edaef9 100644 (file)
@@ -186,7 +186,7 @@ bool ath9k_hw_reset_calvalid(struct ath_hw *ah)
                return true;
        }
 
-       if (!ath9k_hw_iscal_supported(ah, currCal->calData->calType))
+       if (!(ah->supp_cals & currCal->calData->calType))
                return true;
 
        ath_print(common, ATH_DBG_CALIBRATE,
@@ -300,7 +300,6 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
                }
        }
        REGWRITE_BUFFER_FLUSH(ah);
-       DISABLE_REGWRITE_BUFFER(ah);
 }
 
 
@@ -346,34 +345,34 @@ bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan)
        struct ieee80211_channel *c = chan->chan;
        struct ath9k_hw_cal_data *caldata = ah->caldata;
 
-       if (!caldata)
-               return false;
-
        chan->channelFlags &= (~CHANNEL_CW_INT);
        if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) {
                ath_print(common, ATH_DBG_CALIBRATE,
                          "NF did not complete in calibration window\n");
-               nf = 0;
-               caldata->rawNoiseFloor = nf;
                return false;
-       } else {
-               ath9k_hw_do_getnf(ah, nfarray);
-               ath9k_hw_nf_sanitize(ah, nfarray);
-               nf = nfarray[0];
-               if (ath9k_hw_get_nf_thresh(ah, c->band, &nfThresh)
-                   && nf > nfThresh) {
-                       ath_print(common, ATH_DBG_CALIBRATE,
-                                 "noise floor failed detected; "
-                                 "detected %d, threshold %d\n",
-                                 nf, nfThresh);
-                       chan->channelFlags |= CHANNEL_CW_INT;
-               }
+       }
+
+       ath9k_hw_do_getnf(ah, nfarray);
+       ath9k_hw_nf_sanitize(ah, nfarray);
+       nf = nfarray[0];
+       if (ath9k_hw_get_nf_thresh(ah, c->band, &nfThresh)
+           && nf > nfThresh) {
+               ath_print(common, ATH_DBG_CALIBRATE,
+                         "noise floor failed detected; "
+                         "detected %d, threshold %d\n",
+                         nf, nfThresh);
+               chan->channelFlags |= CHANNEL_CW_INT;
+       }
+
+       if (!caldata) {
+               chan->noisefloor = nf;
+               return false;
        }
 
        h = caldata->nfCalHist;
        caldata->nfcal_pending = false;
        ath9k_hw_update_nfcal_hist_buffer(ah, caldata, nfarray);
-       caldata->rawNoiseFloor = h[0].privNF;
+       chan->noisefloor = h[0].privNF;
        return true;
 }
 
@@ -401,10 +400,10 @@ void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah,
 
 s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan)
 {
-       if (!ah->caldata || !ah->caldata->rawNoiseFloor)
+       if (!ah->curchan || !ah->curchan->noisefloor)
                return ath9k_hw_get_default_nf(ah, chan);
 
-       return ah->caldata->rawNoiseFloor;
+       return ah->curchan->noisefloor;
 }
 EXPORT_SYMBOL(ath9k_hw_getchan_noise);
 
index 5b053a6260b27f4c9021c0cd27d84b75e24cda48..b8973eb8d858bb3414c41bea41e01970aeb28a62 100644 (file)
@@ -58,14 +58,6 @@ struct ar5416IniArray {
                }                                                       \
        } while (0)
 
-enum ath9k_cal_types {
-       ADC_DC_INIT_CAL = 0x1,
-       ADC_GAIN_CAL = 0x2,
-       ADC_DC_CAL = 0x4,
-       IQ_MISMATCH_CAL = 0x8,
-       TEMP_COMP_CAL = 0x10,
-};
-
 enum ath9k_cal_state {
        CAL_INACTIVE,
        CAL_WAITING,
@@ -80,7 +72,7 @@ enum ath9k_cal_state {
 #define PER_MAX_LOG_COUNT  10
 
 struct ath9k_percal_data {
-       enum ath9k_cal_types calType;
+       u32 calType;
        u32 calNumSamples;
        u32 calCountMax;
        void (*calCollect) (struct ath_hw *);
index d65a896a421d6881fad42117dd7c4a127f22a98c..74a4570dc87f35c066e7299be7c1d0323a5002b4 100644 (file)
@@ -488,6 +488,8 @@ static ssize_t read_file_wiphy(struct file *file, char __user *user_buf,
                               size_t count, loff_t *ppos)
 {
        struct ath_softc *sc = file->private_data;
+       struct ath_wiphy *aphy = sc->pri_wiphy;
+       struct ieee80211_channel *chan = aphy->hw->conf.channel;
        char buf[512];
        unsigned int len = 0;
        int i;
@@ -498,7 +500,8 @@ static ssize_t read_file_wiphy(struct file *file, char __user *user_buf,
                        "primary: %s (%s chan=%d ht=%d)\n",
                        wiphy_name(sc->pri_wiphy->hw->wiphy),
                        ath_wiphy_state_str(sc->pri_wiphy->state),
-                       sc->pri_wiphy->chan_idx, sc->pri_wiphy->chan_is_ht);
+                       ieee80211_frequency_to_channel(chan->center_freq),
+                       aphy->chan_is_ht);
 
        put_unaligned_le32(REG_READ_D(sc->sc_ah, AR_STA_ID0), addr);
        put_unaligned_le16(REG_READ_D(sc->sc_ah, AR_STA_ID1) & 0xffff, addr + 4);
@@ -545,11 +548,13 @@ static ssize_t read_file_wiphy(struct file *file, char __user *user_buf,
                struct ath_wiphy *aphy = sc->sec_wiphy[i];
                if (aphy == NULL)
                        continue;
+               chan = aphy->hw->conf.channel;
                len += snprintf(buf + len, sizeof(buf) - len,
-                               "secondary: %s (%s chan=%d ht=%d)\n",
-                               wiphy_name(aphy->hw->wiphy),
-                               ath_wiphy_state_str(aphy->state),
-                               aphy->chan_idx, aphy->chan_is_ht);
+                       "secondary: %s (%s chan=%d ht=%d)\n",
+                       wiphy_name(aphy->hw->wiphy),
+                       ath_wiphy_state_str(aphy->state),
+                       ieee80211_frequency_to_channel(chan->center_freq),
+                       aphy->chan_is_ht);
        }
        if (len > sizeof(buf))
                len = sizeof(buf);
@@ -696,6 +701,8 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
        PR("DESC CFG Error:  ", desc_cfg_err);
        PR("DATA Underrun:   ", data_underrun);
        PR("DELIM Underrun:  ", delim_underrun);
+       PR("TX-Pkts-All:     ", tx_pkts_all);
+       PR("TX-Bytes-All:    ", tx_bytes_all);
 
        if (len > size)
                len = size;
@@ -709,6 +716,9 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
 void ath_debug_stat_tx(struct ath_softc *sc, struct ath_txq *txq,
                       struct ath_buf *bf, struct ath_tx_status *ts)
 {
+       TX_STAT_INC(txq->axq_qnum, tx_pkts_all);
+       sc->debug.stats.txstats[txq->axq_qnum].tx_bytes_all += bf->bf_mpdu->len;
+
        if (bf_isampdu(bf)) {
                if (bf_isxretried(bf))
                        TX_STAT_INC(txq->axq_qnum, a_xretries);
@@ -803,6 +813,13 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf,
        PHY_ERR("HT-LENGTH", ATH9K_PHYERR_HT_LENGTH_ILLEGAL);
        PHY_ERR("HT-RATE", ATH9K_PHYERR_HT_RATE_ILLEGAL);
 
+       len += snprintf(buf + len, size - len,
+                       "%18s : %10u\n", "RX-Pkts-All",
+                       sc->debug.stats.rxstats.rx_pkts_all);
+       len += snprintf(buf + len, size - len,
+                       "%18s : %10u\n", "RX-Bytes-All",
+                       sc->debug.stats.rxstats.rx_bytes_all);
+
        if (len > size)
                len = size;
 
@@ -821,6 +838,9 @@ void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs)
 
        u32 phyerr;
 
+       RX_STAT_INC(rx_pkts_all);
+       sc->debug.stats.rxstats.rx_bytes_all += rs->rs_datalen;
+
        if (rs->rs_status & ATH9K_RXERR_CRC)
                RX_STAT_INC(crc_err);
        if (rs->rs_status & ATH9K_RXERR_DECRYPT)
index 5d21704e87fff40c078382e1010f4b1fc529efcf..822b6f3f23c573467b62a563b2258d372128da1d 100644 (file)
@@ -89,6 +89,10 @@ struct ath_rc_stats {
 
 /**
  * struct ath_tx_stats - Statistics about TX
+ * @tx_pkts_all:  No. of total frames transmitted, including ones that
+       may have had errors.
+ * @tx_bytes_all:  No. of total bytes transmitted, including ones that
+       may have had errors.
  * @queued: Total MPDUs (non-aggr) queued
  * @completed: Total MPDUs (non-aggr) completed
  * @a_aggr: Total no. of aggregates queued
@@ -107,6 +111,8 @@ struct ath_rc_stats {
  * @delim_urn: TX delimiter underrun errors
  */
 struct ath_tx_stats {
+       u32 tx_pkts_all;
+       u32 tx_bytes_all;
        u32 queued;
        u32 completed;
        u32 a_aggr;
@@ -124,6 +130,10 @@ struct ath_tx_stats {
 
 /**
  * struct ath_rx_stats - RX Statistics
+ * @rx_pkts_all:  No. of total frames received, including ones that
+       may have had errors.
+ * @rx_bytes_all:  No. of total bytes received, including ones that
+       may have had errors.
  * @crc_err: No. of frames with incorrect CRC value
  * @decrypt_crc_err: No. of frames whose CRC check failed after
        decryption process completed
@@ -136,6 +146,8 @@ struct ath_tx_stats {
  * @phy_err_stats: Individual PHY error statistics
  */
 struct ath_rx_stats {
+       u32 rx_pkts_all;
+       u32 rx_bytes_all;
        u32 crc_err;
        u32 decrypt_crc_err;
        u32 phy_err;
index d6eed1f02e84c13fa6981814a66b1f5198e63bf4..4fa4d8e28c64236ffa5d7547ad5d5234565658bc 100644 (file)
@@ -179,6 +179,9 @@ static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah,
        struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k;
        struct modal_eep_4k_header *pModal = &eep->modalHeader;
        struct base_eep_header_4k *pBase = &eep->baseEepHeader;
+       u16 ver_minor;
+
+       ver_minor = pBase->version & AR5416_EEP_VER_MINOR_MASK;
 
        switch (param) {
        case EEP_NFTHRESH_2:
@@ -204,7 +207,7 @@ static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah,
        case EEP_DB_2:
                return pModal->db1_1;
        case EEP_MINOR_REV:
-               return pBase->version & AR5416_EEP_VER_MINOR_MASK;
+               return ver_minor;
        case EEP_TX_MASK:
                return pBase->txMask;
        case EEP_RX_MASK:
@@ -217,6 +220,11 @@ static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah,
                return pModal->version;
        case EEP_ANT_DIV_CTL1:
                return pModal->antdiv_ctl1;
+       case EEP_TXGAIN_TYPE:
+               if (ver_minor >= AR5416_EEP_MINOR_VER_19)
+                       return pBase->txGainType;
+               else
+                       return AR5416_EEP_TXGAIN_ORIGINAL;
        default:
                return 0;
        }
@@ -500,7 +508,6 @@ static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah,
                        }
 
                        REGWRITE_BUFFER_FLUSH(ah);
-                       DISABLE_REGWRITE_BUFFER(ah);
                }
        }
 
@@ -832,7 +839,6 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah,
        }
 
        REGWRITE_BUFFER_FLUSH(ah);
-       DISABLE_REGWRITE_BUFFER(ah);
 }
 
 static void ath9k_hw_4k_set_addac(struct ath_hw *ah,
index b100db2766cfc106d0b4f92312873cac2fd22d63..bbb54bc28a44d277ccc274e10feee6195794c610 100644 (file)
@@ -380,15 +380,6 @@ static void ath9k_enable_regwrite_buffer(void *hw_priv)
        atomic_inc(&priv->wmi->mwrite_cnt);
 }
 
-static void ath9k_disable_regwrite_buffer(void *hw_priv)
-{
-       struct ath_hw *ah = (struct ath_hw *) hw_priv;
-       struct ath_common *common = ath9k_hw_common(ah);
-       struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
-
-       atomic_dec(&priv->wmi->mwrite_cnt);
-}
-
 static void ath9k_regwrite_flush(void *hw_priv)
 {
        struct ath_hw *ah = (struct ath_hw *) hw_priv;
@@ -397,6 +388,8 @@ static void ath9k_regwrite_flush(void *hw_priv)
        u32 rsp_status;
        int r;
 
+       atomic_dec(&priv->wmi->mwrite_cnt);
+
        mutex_lock(&priv->wmi->multi_write_mutex);
 
        if (priv->wmi->multi_write_idx) {
@@ -420,7 +413,6 @@ static const struct ath_ops ath9k_common_ops = {
        .read = ath9k_regread,
        .write = ath9k_regwrite,
        .enable_write_buffer = ath9k_enable_regwrite_buffer,
-       .disable_write_buffer = ath9k_disable_regwrite_buffer,
        .write_flush = ath9k_regwrite_flush,
 };
 
index 5124d04b240b5d09eb21ad35f2122905dda55afc..f12591f5d02aa4e7bb792ee944b6932355f9e1e2 100644 (file)
@@ -760,23 +760,12 @@ void ath9k_ani_work(struct work_struct *work)
                        ath9k_hw_ani_monitor(ah, ah->curchan);
 
                /* Perform calibration if necessary */
-               if (longcal || shortcal) {
+               if (longcal || shortcal)
                        common->ani.caldone =
                                ath9k_hw_calibrate(ah, ah->curchan,
                                                   common->rx_chainmask,
                                                   longcal);
 
-                       if (longcal)
-                               common->ani.noise_floor =
-                                       ath9k_hw_getchan_noise(ah, ah->curchan);
-
-                       ath_print(common, ATH_DBG_ANI,
-                                 " calibrate chan %u/%x nf: %d\n",
-                                 ah->curchan->channel,
-                                 ah->curchan->channelFlags,
-                                 common->ani.noise_floor);
-               }
-
                ath9k_htc_ps_restore(priv);
        }
 
index ffecbadaea4a592450da48c3e849b9bdd1961b07..0a4ad348b6997d90594201b0d8a3aaadc3c11bca 100644 (file)
@@ -128,17 +128,6 @@ static inline void ath9k_hw_set11n_virtualmorefrag(struct ath_hw *ah, void *ds,
        ath9k_hw_ops(ah)->set11n_virtualmorefrag(ah, ds, vmf);
 }
 
-static inline void ath9k_hw_procmibevent(struct ath_hw *ah)
-{
-       ath9k_hw_ops(ah)->ani_proc_mib_event(ah);
-}
-
-static inline void ath9k_hw_ani_monitor(struct ath_hw *ah,
-                                       struct ath9k_channel *chan)
-{
-       ath9k_hw_ops(ah)->ani_monitor(ah, chan);
-}
-
 /* Private hardware call ops */
 
 /* PHY ops */
@@ -276,15 +265,4 @@ static inline void ath9k_hw_setup_calibration(struct ath_hw *ah,
        ath9k_hw_private_ops(ah)->setup_calibration(ah, currCal);
 }
 
-static inline bool ath9k_hw_iscal_supported(struct ath_hw *ah,
-                                           enum ath9k_cal_types calType)
-{
-       return ath9k_hw_private_ops(ah)->iscal_supported(ah, calType);
-}
-
-static inline void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning)
-{
-       ath9k_hw_private_ops(ah)->ani_reset(ah, is_scanning);
-}
-
 #endif /* ATH9K_HW_OPS_H */
index 25ed65ac992c66069d23ec83f30c69ea73726f38..05e9935ef1602326e9beb1d5bff776ad4c2983ba 100644 (file)
@@ -299,7 +299,6 @@ static void ath9k_hw_disablepcie(struct ath_hw *ah)
        REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
 
        REGWRITE_BUFFER_FLUSH(ah);
-       DISABLE_REGWRITE_BUFFER(ah);
 }
 
 /* This should work for all families including legacy */
@@ -371,10 +370,6 @@ static void ath9k_hw_init_config(struct ath_hw *ah)
        ah->config.pcie_clock_req = 0;
        ah->config.pcie_waen = 0;
        ah->config.analog_shiftreg = 1;
-       ah->config.ofdm_trig_low = 200;
-       ah->config.ofdm_trig_high = 500;
-       ah->config.cck_trig_high = 200;
-       ah->config.cck_trig_low = 100;
        ah->config.enable_ani = true;
 
        for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
@@ -676,7 +671,6 @@ static void ath9k_hw_init_qos(struct ath_hw *ah)
        REG_WRITE(ah, AR_TXOP_12_15, 0xFFFFFFFF);
 
        REGWRITE_BUFFER_FLUSH(ah);
-       DISABLE_REGWRITE_BUFFER(ah);
 }
 
 static void ath9k_hw_init_pll(struct ath_hw *ah,
@@ -741,7 +735,6 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah,
        }
 
        REGWRITE_BUFFER_FLUSH(ah);
-       DISABLE_REGWRITE_BUFFER(ah);
 
        if (AR_SREV_9300_20_OR_LATER(ah)) {
                REG_WRITE(ah, AR_INTR_PRIO_ASYNC_ENABLE, 0);
@@ -885,7 +878,6 @@ static inline void ath9k_hw_set_dma(struct ath_hw *ah)
        REG_WRITE(ah, AR_TXCFG, regval | AR_TXCFG_DMASZ_128B);
 
        REGWRITE_BUFFER_FLUSH(ah);
-       DISABLE_REGWRITE_BUFFER(ah);
 
        /*
         * Restore TX Trigger Level to its pre-reset value.
@@ -933,7 +925,6 @@ static inline void ath9k_hw_set_dma(struct ath_hw *ah)
        }
 
        REGWRITE_BUFFER_FLUSH(ah);
-       DISABLE_REGWRITE_BUFFER(ah);
 
        if (AR_SREV_9300_20_OR_LATER(ah))
                ath9k_hw_reset_txstatus_ring(ah);
@@ -1031,7 +1022,6 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type)
        REG_WRITE(ah, AR_RTC_RC, rst_flags);
 
        REGWRITE_BUFFER_FLUSH(ah);
-       DISABLE_REGWRITE_BUFFER(ah);
 
        udelay(50);
 
@@ -1070,7 +1060,6 @@ static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah)
        udelay(2);
 
        REGWRITE_BUFFER_FLUSH(ah);
-       DISABLE_REGWRITE_BUFFER(ah);
 
        if (!AR_SREV_9300_20_OR_LATER(ah))
                udelay(2);
@@ -1239,7 +1228,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
                return -EIO;
 
-       if (curchan && !ah->chip_fullsleep && ah->caldata)
+       if (curchan && !ah->chip_fullsleep)
                ath9k_hw_getnf(ah, curchan);
 
        ah->caldata = caldata;
@@ -1374,7 +1363,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        REG_WRITE(ah, AR_RSSI_THR, INIT_RSSI_THR);
 
        REGWRITE_BUFFER_FLUSH(ah);
-       DISABLE_REGWRITE_BUFFER(ah);
 
        r = ath9k_hw_rf_set_freq(ah, chan);
        if (r)
@@ -1386,7 +1374,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
                REG_WRITE(ah, AR_DQCUMASK(i), 1 << i);
 
        REGWRITE_BUFFER_FLUSH(ah);
-       DISABLE_REGWRITE_BUFFER(ah);
 
        ah->intr_txqs = 0;
        for (i = 0; i < ah->caps.total_queues; i++)
@@ -1434,7 +1421,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        REG_WRITE(ah, AR_CFG_LED, saveLedState | AR_CFG_SCLK_32KHZ);
 
        REGWRITE_BUFFER_FLUSH(ah);
-       DISABLE_REGWRITE_BUFFER(ah);
 
        /*
         * For big endian systems turn on swapping for descriptors
@@ -1684,7 +1670,6 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period)
        REG_WRITE(ah, AR_NDP_PERIOD, TU_TO_USEC(beacon_period));
 
        REGWRITE_BUFFER_FLUSH(ah);
-       DISABLE_REGWRITE_BUFFER(ah);
 
        beacon_period &= ~ATH9K_BEACON_ENA;
        if (beacon_period & ATH9K_BEACON_RESET_TSF) {
@@ -1712,7 +1697,6 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
                  TU_TO_USEC(bs->bs_intval & ATH9K_BEACON_PERIOD));
 
        REGWRITE_BUFFER_FLUSH(ah);
-       DISABLE_REGWRITE_BUFFER(ah);
 
        REG_RMW_FIELD(ah, AR_RSSI_THR,
                      AR_RSSI_THR_BM_THR, bs->bs_bmissthreshold);
@@ -1758,7 +1742,6 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
        REG_WRITE(ah, AR_DTIM_PERIOD, TU_TO_USEC(dtimperiod));
 
        REGWRITE_BUFFER_FLUSH(ah);
-       DISABLE_REGWRITE_BUFFER(ah);
 
        REG_SET_BIT(ah, AR_TIMER_MODE,
                    AR_TBTT_TIMER_EN | AR_TIM_TIMER_EN |
@@ -2176,7 +2159,6 @@ void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits)
                          REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_ZLFDMA);
 
        REGWRITE_BUFFER_FLUSH(ah);
-       DISABLE_REGWRITE_BUFFER(ah);
 }
 EXPORT_SYMBOL(ath9k_hw_setrxfilter);
 
index df47f792cf4ed3835d2f4f3715f386e184ce4827..87627dd634635ea5f116471940f5d3edac0eff4f 100644 (file)
 
 #define ENABLE_REGWRITE_BUFFER(_ah)                                    \
        do {                                                            \
-               if (AR_SREV_9271(_ah))                                  \
+               if (ath9k_hw_common(_ah)->ops->enable_write_buffer)     \
                        ath9k_hw_common(_ah)->ops->enable_write_buffer((_ah)); \
        } while (0)
 
-#define DISABLE_REGWRITE_BUFFER(_ah)                                   \
-       do {                                                            \
-               if (AR_SREV_9271(_ah))                                  \
-                       ath9k_hw_common(_ah)->ops->disable_write_buffer((_ah)); \
-       } while (0)
-
 #define REGWRITE_BUFFER_FLUSH(_ah)                                     \
        do {                                                            \
-               if (AR_SREV_9271(_ah))                                  \
+               if (ath9k_hw_common(_ah)->ops->write_flush)             \
                        ath9k_hw_common(_ah)->ops->write_flush((_ah));  \
        } while (0)
 
@@ -342,7 +336,6 @@ struct ath9k_hw_cal_data {
        int32_t CalValid;
        int8_t iCoff;
        int8_t qCoff;
-       int16_t rawNoiseFloor;
        bool paprd_done;
        bool nfcal_pending;
        bool nfcal_interference;
@@ -353,9 +346,11 @@ struct ath9k_hw_cal_data {
 
 struct ath9k_channel {
        struct ieee80211_channel *chan;
+       struct ar5416AniState ani;
        u16 channel;
        u32 channelFlags;
        u32 chanmode;
+       s16 noisefloor;
 };
 
 #define IS_CHAN_G(_c) ((((_c)->channelFlags & (CHANNEL_G)) == CHANNEL_G) || \
@@ -514,14 +509,6 @@ struct ath_hw_antcomb_conf {
  * @setup_calibration: set up calibration
  * @iscal_supported: used to query if a type of calibration is supported
  *
- * @ani_reset: reset ANI parameters to default values
- * @ani_lower_immunity: lower the noise immunity level. The level controls
- *     the power-based packet detection on hardware. If a power jump is
- *     detected the adapter takes it as an indication that a packet has
- *     arrived. The level ranges from 0-5. Each level corresponds to a
- *     few dB more of noise immunity. If you have a strong time-varying
- *     interference that is causing false detections (OFDM timing errors or
- *     CCK timing errors) the level can be increased.
  * @ani_cache_ini_regs: cache the values for ANI from the initial
  *     register settings through the register initialization.
  */
@@ -535,8 +522,6 @@ struct ath_hw_private_ops {
        bool (*macversion_supported)(u32 macversion);
        void (*setup_calibration)(struct ath_hw *ah,
                                  struct ath9k_cal_list *currCal);
-       bool (*iscal_supported)(struct ath_hw *ah,
-                               enum ath9k_cal_types calType);
 
        /* PHY ops */
        int (*rf_set_freq)(struct ath_hw *ah,
@@ -568,8 +553,6 @@ struct ath_hw_private_ops {
        void (*do_getnf)(struct ath_hw *ah, int16_t nfarray[NUM_NF_READINGS]);
 
        /* ANI */
-       void (*ani_reset)(struct ath_hw *ah, bool is_scanning);
-       void (*ani_lower_immunity)(struct ath_hw *ah);
        void (*ani_cache_ini_regs)(struct ath_hw *ah);
 };
 
@@ -581,11 +564,6 @@ struct ath_hw_private_ops {
  *
  * @config_pci_powersave:
  * @calibrate: periodic calibration for NF, ANI, IQ, ADC gain, ADC-DC
- *
- * @ani_proc_mib_event: process MIB events, this would happen upon specific ANI
- *     thresholds being reached or having overflowed.
- * @ani_monitor: called periodically by the core driver to collect
- *     MIB stats and adjust ANI if specific thresholds have been reached.
  */
 struct ath_hw_ops {
        void (*config_pci_powersave)(struct ath_hw *ah,
@@ -626,9 +604,6 @@ struct ath_hw_ops {
                                     u32 burstDuration);
        void (*set11n_virtualmorefrag)(struct ath_hw *ah, void *ds,
                                       u32 vmf);
-
-       void (*ani_proc_mib_event)(struct ath_hw *ah);
-       void (*ani_monitor)(struct ath_hw *ah, struct ath9k_channel *chan);
 };
 
 struct ath_nf_limits {
@@ -689,10 +664,9 @@ struct ath_hw {
        u32 atim_window;
 
        /* Calibration */
-       enum ath9k_cal_types supp_cals;
+       u32 supp_cals;
        struct ath9k_cal_list iq_caldata;
        struct ath9k_cal_list adcgain_caldata;
-       struct ath9k_cal_list adcdc_calinitdata;
        struct ath9k_cal_list adcdc_caldata;
        struct ath9k_cal_list tempCompCalData;
        struct ath9k_cal_list *cal_list;
@@ -761,13 +735,13 @@ struct ath_hw {
        /* ANI */
        u32 proc_phyerr;
        u32 aniperiod;
-       struct ar5416AniState *curani;
-       struct ar5416AniState ani[255];
        int totalSizeDesired[5];
        int coarse_high[5];
        int coarse_low[5];
        int firpwr[5];
        enum ath9k_ani_cmd ani_function;
+       struct ath_cycle_counters cc, cc_delta;
+       int32_t listen_time;
 
        /* Bluetooth coexistance */
        struct ath_btcoex_hw btcoex_hw;
@@ -988,8 +962,9 @@ void ar9002_hw_load_ani_reg(struct ath_hw *ah, struct ath9k_channel *chan);
  * older families (AR5008, AR9001, AR9002) by using modparam_force_new_ani.
  */
 extern int modparam_force_new_ani;
-void ath9k_hw_attach_ani_ops_old(struct ath_hw *ah);
-void ath9k_hw_attach_ani_ops_new(struct ath_hw *ah);
+void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning);
+void ath9k_hw_proc_mib_event(struct ath_hw *ah);
+void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan);
 
 #define ATH_PCIE_CAP_LINK_CTRL 0x70
 #define ATH_PCIE_CAP_LINK_L0S  1
index de3393867e37fe04702db58fbd68abfd1ebb1d2a..d76003c06fe4dc1a53be4b82a9010213a1bcf7ad 100644 (file)
@@ -56,7 +56,7 @@ MODULE_PARM_DESC(blink, "Enable LED blink on activity");
  * on 5 MHz steps, we support the channels which we know
  * we have calibration data for all cards though to make
  * this static */
-static struct ieee80211_channel ath9k_2ghz_chantable[] = {
+static const struct ieee80211_channel ath9k_2ghz_chantable[] = {
        CHAN2G(2412, 0), /* Channel 1 */
        CHAN2G(2417, 1), /* Channel 2 */
        CHAN2G(2422, 2), /* Channel 3 */
@@ -77,7 +77,7 @@ static struct ieee80211_channel ath9k_2ghz_chantable[] = {
  * on 5 MHz steps, we support the channels which we know
  * we have calibration data for all cards though to make
  * this static */
-static struct ieee80211_channel ath9k_5ghz_chantable[] = {
+static const struct ieee80211_channel ath9k_5ghz_chantable[] = {
        /* _We_ call this UNII 1 */
        CHAN5G(5180, 14), /* Channel 36 */
        CHAN5G(5200, 15), /* Channel 40 */
@@ -477,10 +477,17 @@ err:
        return -EIO;
 }
 
-static void ath9k_init_channels_rates(struct ath_softc *sc)
+static int ath9k_init_channels_rates(struct ath_softc *sc)
 {
+       void *channels;
+
        if (test_bit(ATH9K_MODE_11G, sc->sc_ah->caps.wireless_modes)) {
-               sc->sbands[IEEE80211_BAND_2GHZ].channels = ath9k_2ghz_chantable;
+               channels = kmemdup(ath9k_2ghz_chantable,
+                       sizeof(ath9k_2ghz_chantable), GFP_KERNEL);
+               if (!channels)
+                   return -ENOMEM;
+
+               sc->sbands[IEEE80211_BAND_2GHZ].channels = channels;
                sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ;
                sc->sbands[IEEE80211_BAND_2GHZ].n_channels =
                        ARRAY_SIZE(ath9k_2ghz_chantable);
@@ -490,7 +497,15 @@ static void ath9k_init_channels_rates(struct ath_softc *sc)
        }
 
        if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) {
-               sc->sbands[IEEE80211_BAND_5GHZ].channels = ath9k_5ghz_chantable;
+               channels = kmemdup(ath9k_5ghz_chantable,
+                       sizeof(ath9k_5ghz_chantable), GFP_KERNEL);
+               if (!channels) {
+                       if (sc->sbands[IEEE80211_BAND_2GHZ].channels)
+                               kfree(sc->sbands[IEEE80211_BAND_2GHZ].channels);
+                       return -ENOMEM;
+               }
+
+               sc->sbands[IEEE80211_BAND_5GHZ].channels = channels;
                sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ;
                sc->sbands[IEEE80211_BAND_5GHZ].n_channels =
                        ARRAY_SIZE(ath9k_5ghz_chantable);
@@ -499,6 +514,7 @@ static void ath9k_init_channels_rates(struct ath_softc *sc)
                sc->sbands[IEEE80211_BAND_5GHZ].n_bitrates =
                        ARRAY_SIZE(ath9k_legacy_rates) - 4;
        }
+       return 0;
 }
 
 static void ath9k_init_misc(struct ath_softc *sc)
@@ -506,7 +522,6 @@ static void ath9k_init_misc(struct ath_softc *sc)
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        int i = 0;
 
-       common->ani.noise_floor = ATH_DEFAULT_NOISE_FLOOR;
        setup_timer(&common->ani.timer, ath_ani_calibrate, (unsigned long)sc);
 
        sc->config.txpowlimit = ATH_TXPOWER_MAX;
@@ -595,8 +610,11 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
        if (ret)
                goto err_btcoex;
 
+       ret = ath9k_init_channels_rates(sc);
+       if (ret)
+               goto err_btcoex;
+
        ath9k_init_crypto(sc);
-       ath9k_init_channels_rates(sc);
        ath9k_init_misc(sc);
 
        return 0;
@@ -639,6 +657,7 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
 
        hw->wiphy->interface_modes =
                BIT(NL80211_IFTYPE_AP) |
+               BIT(NL80211_IFTYPE_WDS) |
                BIT(NL80211_IFTYPE_STATION) |
                BIT(NL80211_IFTYPE_ADHOC) |
                BIT(NL80211_IFTYPE_MESH_POINT);
@@ -756,6 +775,12 @@ static void ath9k_deinit_softc(struct ath_softc *sc)
 {
        int i = 0;
 
+       if (sc->sbands[IEEE80211_BAND_2GHZ].channels)
+               kfree(sc->sbands[IEEE80211_BAND_2GHZ].channels);
+
+       if (sc->sbands[IEEE80211_BAND_5GHZ].channels)
+               kfree(sc->sbands[IEEE80211_BAND_5GHZ].channels);
+
         if ((sc->btcoex.no_stomp_timer) &&
            sc->sc_ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE)
                ath_gen_timer_free(sc->sc_ah, sc->btcoex.no_stomp_timer);
index 3efda8a8a3c1e66e1b0ed71a7a5bbad2a936bb28..8c13479b17cd9d418f7d7f496b01dbf7445ba202 100644 (file)
@@ -40,7 +40,6 @@ static void ath9k_hw_set_txq_interrupts(struct ath_hw *ah,
        REG_WRITE(ah, AR_IMR_S2, ah->imrs2_reg);
 
        REGWRITE_BUFFER_FLUSH(ah);
-       DISABLE_REGWRITE_BUFFER(ah);
 }
 
 u32 ath9k_hw_gettxbuf(struct ath_hw *ah, u32 q)
@@ -492,8 +491,6 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
        REG_WRITE(ah, AR_DMISC(q),
                  AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x2);
 
-       REGWRITE_BUFFER_FLUSH(ah);
-
        if (qi->tqi_cbrPeriod) {
                REG_WRITE(ah, AR_QCBRCFG(q),
                          SM(qi->tqi_cbrPeriod, AR_Q_CBRCFG_INTERVAL) |
@@ -509,8 +506,6 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
                          AR_Q_RDYTIMECFG_EN);
        }
 
-       REGWRITE_BUFFER_FLUSH(ah);
-
        REG_WRITE(ah, AR_DCHNTIME(q),
                  SM(qi->tqi_burstTime, AR_D_CHNTIME_DUR) |
                  (qi->tqi_burstTime ? AR_D_CHNTIME_EN : 0));
@@ -530,7 +525,6 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
        }
 
        REGWRITE_BUFFER_FLUSH(ah);
-       DISABLE_REGWRITE_BUFFER(ah);
 
        if (qi->tqi_qflags & TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE) {
                REG_WRITE(ah, AR_DMISC(q),
@@ -553,7 +547,6 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
                          | AR_D_MISC_POST_FR_BKOFF_DIS);
 
                REGWRITE_BUFFER_FLUSH(ah);
-               DISABLE_REGWRITE_BUFFER(ah);
 
                /*
                 * cwmin and cwmax should be 0 for beacon queue
@@ -585,7 +578,6 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
                             AR_D_MISC_ARB_LOCKOUT_CNTRL_S));
 
                REGWRITE_BUFFER_FLUSH(ah);
-               DISABLE_REGWRITE_BUFFER(ah);
 
                break;
        case ATH9K_TX_QUEUE_PSPOLL:
index a133878826360d6856117b5ddad6935b5af1ba99..74c2dc8a8b8ac4978a5381ecad40ba1f6c275aed 100644 (file)
@@ -459,16 +459,6 @@ void ath_ani_calibrate(unsigned long data)
                                                   ah->curchan,
                                                   common->rx_chainmask,
                                                   longcal);
-
-                       if (longcal)
-                               common->ani.noise_floor = ath9k_hw_getchan_noise(ah,
-                                                                    ah->curchan);
-
-                       ath_print(common, ATH_DBG_ANI,
-                                 " calibrate chan %u/%x nf: %d\n",
-                                 ah->curchan->channel,
-                                 ah->curchan->channelFlags,
-                                 common->ani.noise_floor);
                }
        }
 
@@ -723,7 +713,7 @@ irqreturn_t ath_isr(int irq, void *dev)
                 * it will clear whatever condition caused
                 * the interrupt.
                 */
-               ath9k_hw_procmibevent(ah);
+               ath9k_hw_proc_mib_event(ah);
                ath9k_hw_set_interrupts(ah, ah->imask);
        }
 
@@ -1384,6 +1374,9 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
        case NL80211_IFTYPE_STATION:
                ic_opmode = NL80211_IFTYPE_STATION;
                break;
+       case NL80211_IFTYPE_WDS:
+               ic_opmode = NL80211_IFTYPE_WDS;
+               break;
        case NL80211_IFTYPE_ADHOC:
        case NL80211_IFTYPE_AP:
        case NL80211_IFTYPE_MESH_POINT:
@@ -1491,7 +1484,7 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
        mutex_unlock(&sc->mutex);
 }
 
-void ath9k_enable_ps(struct ath_softc *sc)
+static void ath9k_enable_ps(struct ath_softc *sc)
 {
        struct ath_hw *ah = sc->sc_ah;
 
@@ -1505,13 +1498,32 @@ void ath9k_enable_ps(struct ath_softc *sc)
        }
 }
 
+static void ath9k_disable_ps(struct ath_softc *sc)
+{
+       struct ath_hw *ah = sc->sc_ah;
+
+       sc->ps_enabled = false;
+       ath9k_hw_setpower(ah, ATH9K_PM_AWAKE);
+       if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
+               ath9k_hw_setrxabort(ah, 0);
+               sc->ps_flags &= ~(PS_WAIT_FOR_BEACON |
+                                 PS_WAIT_FOR_CAB |
+                                 PS_WAIT_FOR_PSPOLL_DATA |
+                                 PS_WAIT_FOR_TX_ACK);
+               if (ah->imask & ATH9K_INT_TIM_TIMER) {
+                       ah->imask &= ~ATH9K_INT_TIM_TIMER;
+                       ath9k_hw_set_interrupts(ah, ah->imask);
+               }
+       }
+
+}
+
 static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
 {
        struct ath_wiphy *aphy = hw->priv;
        struct ath_softc *sc = aphy->sc;
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ieee80211_conf *conf = &hw->conf;
-       struct ath_hw *ah = sc->sc_ah;
        bool disable_radio;
 
        mutex_lock(&sc->mutex);
@@ -1558,35 +1570,10 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
        if (changed & IEEE80211_CONF_CHANGE_PS) {
                unsigned long flags;
                spin_lock_irqsave(&sc->sc_pm_lock, flags);
-               if (conf->flags & IEEE80211_CONF_PS) {
-                       sc->ps_flags |= PS_ENABLED;
-                       /*
-                        * At this point we know hardware has received an ACK
-                        * of a previously sent null data frame.
-                        */
-                       if ((sc->ps_flags & PS_NULLFUNC_COMPLETED)) {
-                               sc->ps_flags &= ~PS_NULLFUNC_COMPLETED;
-                               ath9k_enable_ps(sc);
-                        }
-               } else {
-                       sc->ps_enabled = false;
-                       sc->ps_flags &= ~(PS_ENABLED |
-                                         PS_NULLFUNC_COMPLETED);
-                       ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
-                       if (!(ah->caps.hw_caps &
-                             ATH9K_HW_CAP_AUTOSLEEP)) {
-                               ath9k_hw_setrxabort(sc->sc_ah, 0);
-                               sc->ps_flags &= ~(PS_WAIT_FOR_BEACON |
-                                                 PS_WAIT_FOR_CAB |
-                                                 PS_WAIT_FOR_PSPOLL_DATA |
-                                                 PS_WAIT_FOR_TX_ACK);
-                               if (ah->imask & ATH9K_INT_TIM_TIMER) {
-                                       ah->imask &= ~ATH9K_INT_TIM_TIMER;
-                                       ath9k_hw_set_interrupts(sc->sc_ah,
-                                                       ah->imask);
-                               }
-                       }
-               }
+               if (conf->flags & IEEE80211_CONF_PS)
+                       ath9k_enable_ps(sc);
+               else
+                       ath9k_disable_ps(sc);
                spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
        }
 
@@ -2004,15 +1991,32 @@ static int ath9k_get_survey(struct ieee80211_hw *hw, int idx,
        struct ath_wiphy *aphy = hw->priv;
        struct ath_softc *sc = aphy->sc;
        struct ath_hw *ah = sc->sc_ah;
-       struct ath_common *common = ath9k_hw_common(ah);
-       struct ieee80211_conf *conf = &hw->conf;
+       struct ieee80211_supported_band *sband;
+       struct ath9k_channel *chan;
+
+       sband = hw->wiphy->bands[IEEE80211_BAND_2GHZ];
+       if (sband && idx >= sband->n_channels) {
+               idx -= sband->n_channels;
+               sband = NULL;
+       }
+
+       if (!sband)
+               sband = hw->wiphy->bands[IEEE80211_BAND_5GHZ];
 
-        if (idx != 0)
-               return -ENOENT;
+       if (!sband || idx >= sband->n_channels)
+           return -ENOENT;
 
-       survey->channel = conf->channel;
-       survey->filled = SURVEY_INFO_NOISE_DBM;
-       survey->noise = common->ani.noise_floor;
+       survey->channel = &sband->channels[idx];
+       chan = &ah->channels[survey->channel->hw_value];
+       survey->filled = 0;
+
+       if (chan == ah->curchan)
+               survey->filled |= SURVEY_INFO_IN_USE;
+
+       if (chan->noisefloor) {
+               survey->filled |= SURVEY_INFO_NOISE_DBM;
+               survey->noise = chan->noisefloor;
+       }
 
        return 0;
 }
index f7da6b20a92574c9eec02ba6672df834f69319d7..aa447770eb2b606ed2ccffed3880b993f9cc3200 100644 (file)
@@ -1648,13 +1648,6 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
 
        bf->bf_buf_addr = bf->bf_dmacontext;
 
-       /* tag if this is a nullfunc frame to enable PS when AP acks it */
-       if (ieee80211_is_nullfunc(fc) && ieee80211_has_pm(fc)) {
-               bf->bf_isnullfunc = true;
-               sc->ps_flags &= ~PS_NULLFUNC_COMPLETED;
-       } else
-               bf->bf_isnullfunc = false;
-
        bf->bf_tx_aborted = false;
 
        return 0;
@@ -2081,18 +2074,6 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
                        break;
                }
 
-               /*
-                * We now know the nullfunc frame has been ACKed so we
-                * can disable RX.
-                */
-               if (bf->bf_isnullfunc &&
-                   (ts.ts_status & ATH9K_TX_ACKED)) {
-                       if ((sc->ps_flags & PS_ENABLED))
-                               ath9k_enable_ps(sc);
-                       else
-                               sc->ps_flags |= PS_NULLFUNC_COMPLETED;
-               }
-
                /*
                 * Remove ath_buf's of the same transmit unit from txq,
                 * however leave the last descriptor back as the holding
@@ -2236,17 +2217,6 @@ void ath_tx_edma_tasklet(struct ath_softc *sc)
 
                txok = !(txs.ts_status & ATH9K_TXERR_MASK);
 
-               /*
-                * Make sure null func frame is acked before configuring
-                * hw into ps mode.
-                */
-               if (bf->bf_isnullfunc && txok) {
-                       if ((sc->ps_flags & PS_ENABLED))
-                               ath9k_enable_ps(sc);
-                       else
-                               sc->ps_flags |= PS_NULLFUNC_COMPLETED;
-               }
-
                if (!bf_isampdu(bf)) {
                        if (txs.ts_status & ATH9K_TXERR_XRETRY)
                                bf->bf_state.bf_type |= BUF_XRETRY;
index 20f2a77e54d261419bcfb1bfe6ff43fde2bd4c37..6cf0c9ef47aa4e7ae005abc034edca2fb40d30e6 100644 (file)
@@ -279,6 +279,7 @@ struct ar9170 {
                unsigned int beacon_max_len;
                bool rx_stream;
                bool tx_stream;
+               bool rx_filter;
                unsigned int mem_blocks;
                unsigned int mem_block_size;
                unsigned int rx_size;
@@ -314,6 +315,7 @@ struct ar9170 {
        u64 cur_mc_hash;
        u32 cur_filter;
        unsigned int filter_state;
+       unsigned int rx_filter_caps;
        bool sniffer_enabled;
 
        /* MAC */
index 0fc83d2336fdcc602e546b6839391a6b4bbe7a2a..f78728c38294e07c6098853e8fb902f3c24d9bb7 100644 (file)
@@ -59,6 +59,16 @@ static inline int carl9170_flush_cab(struct ar9170 *ar,
        return carl9170_bcn_ctrl(ar, vif_id, CARL9170_BCN_CTRL_DRAIN, 0, 0);
 }
 
+static inline int carl9170_rx_filter(struct ar9170 *ar,
+                                    const unsigned int _rx_filter)
+{
+       __le32 rx_filter = cpu_to_le32(_rx_filter);
+
+       return carl9170_exec_cmd(ar, CARL9170_CMD_RX_FILTER,
+                               sizeof(rx_filter), (u8 *)&rx_filter,
+                               0, NULL);
+}
+
 struct carl9170_cmd *carl9170_cmd_buf(struct ar9170 *ar,
        const enum carl9170_cmd_oids cmd, const unsigned int len);
 
index 36615462b87a0c5cfc772ca1c82f85ff17e3b95e..ae6c006bbc56c03bd76f0e1cc56c46a927db1db9 100644 (file)
@@ -257,6 +257,13 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len)
        if (SUPP(CARL9170FW_USB_UP_STREAM))
                ar->fw.rx_stream = true;
 
+       if (SUPP(CARL9170FW_RX_FILTER)) {
+               ar->fw.rx_filter = true;
+               ar->rx_filter_caps = FIF_FCSFAIL | FIF_PLCPFAIL |
+                       FIF_CONTROL | FIF_PSPOLL | FIF_OTHER_BSS |
+                       FIF_PROMISC_IN_BSS;
+       }
+
        ar->fw.vif_num = otus_desc->vif_num;
        ar->fw.cmd_bufs = otus_desc->cmd_bufs;
        ar->fw.address = le32_to_cpu(otus_desc->fw_address);
index d4a4e1dbef0695d1d9c3acd72a9df29485d42f1b..d552166db5059149cd8e653fb2e1154dfba85173 100644 (file)
@@ -53,6 +53,7 @@ enum carl9170_cmd_oids {
        CARL9170_CMD_REBOOT             = 0x04,
        CARL9170_CMD_BCN_CTRL           = 0x05,
        CARL9170_CMD_READ_TSF           = 0x06,
+       CARL9170_CMD_RX_FILTER          = 0x07,
 
        /* CAM */
        CARL9170_CMD_EKEY               = 0x10,
@@ -153,6 +154,20 @@ struct carl9170_psm {
 } __packed;
 #define CARL9170_PSM_SIZE              4
 
+struct carl9170_rx_filter_cmd {
+       __le32          rx_filter;
+} __packed;
+#define CARL9170_RX_FILTER_CMD_SIZE    4
+
+#define CARL9170_RX_FILTER_BAD         0x01
+#define CARL9170_RX_FILTER_OTHER_RA    0x02
+#define CARL9170_RX_FILTER_DECRY_FAIL  0x04
+#define CARL9170_RX_FILTER_CTL_OTHER   0x08
+#define CARL9170_RX_FILTER_CTL_PSPOLL  0x10
+#define CARL9170_RX_FILTER_CTL_BACKR   0x20
+#define CARL9170_RX_FILTER_MGMT                0x40
+#define CARL9170_RX_FILTER_DATA                0x80
+
 struct carl9170_bcn_ctrl_cmd {
        __le32          vif_id;
        __le32          mode;
@@ -188,6 +203,7 @@ struct carl9170_cmd {
                struct carl9170_rf_init         rf_init;
                struct carl9170_psm             psm;
                struct carl9170_bcn_ctrl_cmd    bcn_ctrl;
+               struct carl9170_rx_filter_cmd   rx_filter;
                u8 data[CARL9170_MAX_CMD_PAYLOAD_LEN];
        } __packed;
 } __packed;
index 7cd811708fe5b18d9911aa35d126f787edd52a37..71f3821f60581d721bd203cea46ed31245e26679 100644 (file)
@@ -66,6 +66,9 @@ enum carl9170fw_feature_list {
        /* Firmware PSM support | CARL9170_CMD_PSM */
        CARL9170FW_PSM,
 
+       /* Firmware RX filter | CARL9170_CMD_RX_FILTER */
+       CARL9170FW_RX_FILTER,
+
        /* KEEP LAST */
        __CARL9170FW_FEATURE_NUM
 };
@@ -142,7 +145,7 @@ struct carl9170fw_fix_desc {
        (sizeof(struct carl9170fw_fix_desc))
 
 #define CARL9170FW_DBG_DESC_MIN_VER                    1
-#define CARL9170FW_DBG_DESC_CUR_VER                    2
+#define CARL9170FW_DBG_DESC_CUR_VER                    3
 struct carl9170fw_dbg_desc {
        struct carl9170fw_desc_head head;
 
@@ -150,6 +153,7 @@ struct carl9170fw_dbg_desc {
        __le32 counter_addr;
        __le32 rx_total_addr;
        __le32 rx_overrun_addr;
+       __le32 rx_filter;
 
        /* Put your debugging definitions here */
 } __packed;
index b1292ac5b7033f4704d96bc691226ce4ebfe4efb..2f471b3f05afdec737ab6e1d293ac40bb7c0db5c 100644 (file)
@@ -731,6 +731,9 @@ struct ar9170_stream {
 #define SET_VAL(reg, value, newvalue)                                  \
        (value = ((value) & ~reg) | (((newvalue) << reg##_S) & reg))
 
+#define SET_CONSTVAL(reg, newvalue)                                    \
+       (((newvalue) << reg##_S) & reg)
+
 #define MOD_VAL(reg, value, newvalue)                                  \
        (((value) & ~reg) | (((newvalue) << reg##_S) & reg))
 #endif /* __CARL9170_SHARED_HW_H */
index 84bd38e9961cb62d84a7d25f314c5b72713186eb..3cc99f3f7ab5728af8eeb40c759f954a319671b7 100644 (file)
@@ -380,6 +380,13 @@ static int carl9170_op_start(struct ieee80211_hw *hw)
        if (err)
                goto out;
 
+       if (ar->fw.rx_filter) {
+               err = carl9170_rx_filter(ar, CARL9170_RX_FILTER_OTHER_RA |
+                       CARL9170_RX_FILTER_CTL_OTHER | CARL9170_RX_FILTER_BAD);
+               if (err)
+                       goto out;
+       }
+
        err = carl9170_write_reg(ar, AR9170_MAC_REG_DMA_TRIGGER,
                                 AR9170_DMA_TRIGGER_RXQ);
        if (err)
@@ -840,8 +847,7 @@ static void carl9170_op_configure_filter(struct ieee80211_hw *hw,
        struct ar9170 *ar = hw->priv;
 
        /* mask supported flags */
-       *new_flags &= FIF_ALLMULTI | FIF_FCSFAIL | FIF_PLCPFAIL |
-                     FIF_OTHER_BSS | FIF_PROMISC_IN_BSS;
+       *new_flags &= FIF_ALLMULTI | ar->rx_filter_caps;
 
        if (!IS_ACCEPTING_CMD(ar))
                return;
@@ -867,6 +873,26 @@ static void carl9170_op_configure_filter(struct ieee80211_hw *hw,
                WARN_ON(carl9170_set_operating_mode(ar));
        }
 
+       if (ar->fw.rx_filter && changed_flags & ar->rx_filter_caps) {
+               u32 rx_filter = 0;
+
+               if (!(*new_flags & (FIF_FCSFAIL | FIF_PLCPFAIL)))
+                       rx_filter |= CARL9170_RX_FILTER_BAD;
+
+               if (!(*new_flags & FIF_CONTROL))
+                       rx_filter |= CARL9170_RX_FILTER_CTL_OTHER;
+
+               if (!(*new_flags & FIF_PSPOLL))
+                       rx_filter |= CARL9170_RX_FILTER_CTL_PSPOLL;
+
+               if (!(*new_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS))) {
+                       rx_filter |= CARL9170_RX_FILTER_OTHER_RA;
+                       rx_filter |= CARL9170_RX_FILTER_DECRY_FAIL;
+               }
+
+               WARN_ON(carl9170_rx_filter(ar, rx_filter));
+       }
+
        mutex_unlock(&ar->mutex);
 }
 
index 53c18d34ffccb6ba1e4aab146feecea372e9f97e..02c34eb4ebdec5fe64eb0730e24e89393c8f800f 100644 (file)
 #define                AR9170_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV    0x2000
 #define                AR9170_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV_S  13
 
-#define        AR9170_PHY_REG_GAIN_2GHZ_CHAIN_2        (AR9170_PHY_REG_BASE + 0x2a0c)
 #define        AR9170_PHY_REG_GAIN_2GHZ                (AR9170_PHY_REG_BASE + 0x0a0c)
+#define        AR9170_PHY_REG_GAIN_2GHZ_CHAIN_2        (AR9170_PHY_REG_BASE + 0x2a0c)
 #define                AR9170_PHY_GAIN_2GHZ_RXTX_MARGIN        0x00fc0000
 #define                AR9170_PHY_GAIN_2GHZ_RXTX_MARGIN_S      18
 #define                AR9170_PHY_GAIN_2GHZ_BSW_MARGIN         0x00003c00
 #define                AR9170_PHY_CH2_EXT_MINCCA_PWR           0xff800000
 #define                AR9170_PHY_CH2_EXT_MINCCA_PWR_S         23
 
-#define        REDUCE_CHAIN_0 0x00000050
-#define        REDUCE_CHAIN_1 0x00000051
-
 #endif /* __CARL9170_SHARED_PHY_H */
index 0e917f80eab4656951eb325239e6290f711c60bc..ff53f078a0b5eaff1080bd7e27840940ae1cc0d1 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef __CARL9170_SHARED_VERSION_H
 #define __CARL9170_SHARED_VERSION_H
 #define CARL9170FW_VERSION_YEAR 10
-#define CARL9170FW_VERSION_MONTH 8
-#define CARL9170FW_VERSION_DAY 30
-#define CARL9170FW_VERSION_GIT "1.8.8.1"
+#define CARL9170FW_VERSION_MONTH 9
+#define CARL9170FW_VERSION_DAY 28
+#define CARL9170FW_VERSION_GIT "1.8.8.3"
 #endif /* __CARL9170_SHARED_VERSION_H */
index 8674a99356af644349a17f0e221ce5a22d27b0aa..72821c456b02fcf480525846ffce55e185486c73 100644 (file)
@@ -186,7 +186,8 @@ enum {
 #define B43_SHM_SH_PHYTXNOI            0x006E  /* PHY noise directly after TX (lower 8bit only) */
 #define B43_SHM_SH_RFRXSP1             0x0072  /* RF RX SP Register 1 */
 #define B43_SHM_SH_CHAN                        0x00A0  /* Current channel (low 8bit only) */
-#define  B43_SHM_SH_CHAN_5GHZ          0x0100  /* Bit set, if 5Ghz channel */
+#define  B43_SHM_SH_CHAN_5GHZ          0x0100  /* Bit set, if 5 Ghz channel */
+#define  B43_SHM_SH_CHAN_40MHZ         0x0200  /* Bit set, if 40 Mhz channel width */
 #define B43_SHM_SH_BCMCFIFOID          0x0108  /* Last posted cookie to the bcast/mcast FIFO */
 /* TSSI information */
 #define B43_SHM_SH_TSSI_CCK            0x0058  /* TSSI for last 4 CCK frames (32bit) */
index 8f7d7eff2d803a79649e4a340f15a6d806089adb..7b2ea67814574152009f654c60c7a60771d7d189 100644 (file)
@@ -294,8 +294,10 @@ int b43_switch_channel(struct b43_wldev *dev, unsigned int new_channel)
         */
        channelcookie = new_channel;
        if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ)
-               channelcookie |= 0x100;
-       //FIXME set 40Mhz flag if required
+               channelcookie |= B43_SHM_SH_CHAN_5GHZ;
+       /* FIXME: set 40Mhz flag if required */
+       if (0)
+               channelcookie |= B43_SHM_SH_CHAN_40MHZ;
        savedcookie = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_CHAN);
        b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_CHAN, channelcookie);
 
index 2466c0a52e5d12f548528673f39337b2b1de11eb..f575e757caeb549ba71ed5a61ab28a63080eac41 100644 (file)
@@ -73,7 +73,6 @@ static void b43_nphy_rf_control_override(struct b43_wldev *dev, u16 field,
                                                u16 value, u8 core, bool off);
 static void b43_nphy_rf_control_intc_override(struct b43_wldev *dev, u8 field,
                                                u16 value, u8 core);
-static int nphy_channel_switch(struct b43_wldev *dev, unsigned int channel);
 
 static inline bool b43_empty_chanspec(struct b43_chanspec *chanspec)
 {
@@ -223,7 +222,7 @@ static void b43_radio_init2055_post(struct b43_wldev *dev)
        if (i)
                b43err(dev->wl, "radio post init timeout\n");
        b43_radio_mask(dev, B2055_CAL_LPOCTL, 0xFF7F);
-       nphy_channel_switch(dev, dev->phy.channel);
+       b43_switch_channel(dev, dev->phy.channel);
        b43_radio_write(dev, B2055_C1_RX_BB_LPF, 0x9);
        b43_radio_write(dev, B2055_C2_RX_BB_LPF, 0x9);
        b43_radio_write(dev, B2055_C1_RX_BB_MIDACHP, 0x83);
@@ -3351,12 +3350,6 @@ static void b43_nphy_chanspec_setup(struct b43_wldev *dev,
 
        b43_chantab_phy_upload(dev, e);
 
-       tmp = chanspec.channel;
-       if (chanspec.b_freq == 1)
-               tmp |= 0x0100;
-       if (chanspec.b_width == 3)
-               tmp |= 0x0200;
-       b43_shm_write16(dev, B43_SHM_SHARED, 0xA0, tmp);
 
        if (nphy->radio_chanspec.channel == 14) {
                b43_nphy_classifier(dev, 2, 0);
@@ -3438,18 +3431,6 @@ static int b43_nphy_set_chanspec(struct b43_wldev *dev,
        return 0;
 }
 
-/* Tune the hardware to a new channel */
-static int nphy_channel_switch(struct b43_wldev *dev, unsigned int channel)
-{
-       struct b43_phy_n *nphy = dev->phy.n;
-
-       struct b43_chanspec chanspec;
-       chanspec = nphy->radio_chanspec;
-       chanspec.channel = channel;
-
-       return b43_nphy_set_chanspec(dev, chanspec);
-}
-
 static int b43_nphy_op_allocate(struct b43_wldev *dev)
 {
        struct b43_phy_n *nphy;
@@ -3570,7 +3551,7 @@ static void b43_nphy_op_software_rfkill(struct b43_wldev *dev,
        } else {
                if (dev->phy.rev >= 3) {
                        b43_radio_init2056(dev);
-                       b43_nphy_set_chanspec(dev, nphy->radio_chanspec);
+                       b43_switch_channel(dev, dev->phy.channel);
                } else {
                        b43_radio_init2055(dev);
                }
@@ -3586,6 +3567,9 @@ static void b43_nphy_op_switch_analog(struct b43_wldev *dev, bool on)
 static int b43_nphy_op_switch_channel(struct b43_wldev *dev,
                                      unsigned int new_channel)
 {
+       struct b43_phy_n *nphy = dev->phy.n;
+       struct b43_chanspec chanspec;
+
        if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
                if ((new_channel < 1) || (new_channel > 14))
                        return -EINVAL;
@@ -3594,7 +3578,10 @@ static int b43_nphy_op_switch_channel(struct b43_wldev *dev,
                        return -EINVAL;
        }
 
-       return nphy_channel_switch(dev, new_channel);
+       chanspec = nphy->radio_chanspec;
+       chanspec.channel = new_channel;
+
+       return b43_nphy_set_chanspec(dev, chanspec);
 }
 
 static unsigned int b43_nphy_op_get_default_chan(struct b43_wldev *dev)
index 0f2508384c751c35422e598f1c561e1db2372d43..8d6ed5f6f46f4a423e31943dc70b70fd3727569f 100644 (file)
@@ -11470,6 +11470,10 @@ static int ipw_net_init(struct net_device *dev)
                bg_band->channels = kcalloc(geo->bg_channels,
                                            sizeof(struct ieee80211_channel),
                                            GFP_KERNEL);
+               if (!bg_band->channels) {
+                       rc = -ENOMEM;
+                       goto out;
+               }
                /* translate geo->bg to bg_band.channels */
                for (i = 0; i < geo->bg_channels; i++) {
                        bg_band->channels[i].band = IEEE80211_BAND_2GHZ;
@@ -11505,6 +11509,10 @@ static int ipw_net_init(struct net_device *dev)
                a_band->channels = kcalloc(geo->a_channels,
                                           sizeof(struct ieee80211_channel),
                                           GFP_KERNEL);
+               if (!a_band->channels) {
+                       rc = -ENOMEM;
+                       goto out;
+               }
                /* translate geo->bg to a_band.channels */
                for (i = 0; i < geo->a_channels; i++) {
                        a_band->channels[i].band = IEEE80211_BAND_2GHZ;
index 56ef4ed0db476a7c6560d5b4d7f297e21cfbb5ac..134f54541330c8d58a117d7a43d0a6f9408ab642 100644 (file)
 
 /* Highest firmware API version supported */
 #define IWL1000_UCODE_API_MAX 3
+#define IWL100_UCODE_API_MAX 5
 
 /* Lowest firmware API version supported */
 #define IWL1000_UCODE_API_MIN 1
+#define IWL100_UCODE_API_MIN 5
 
 #define IWL1000_FW_PRE "iwlwifi-1000-"
 #define _IWL1000_MODULE_FIRMWARE(api) IWL1000_FW_PRE #api ".ucode"
 #define IWL1000_MODULE_FIRMWARE(api) _IWL1000_MODULE_FIRMWARE(api)
 
+#define IWL100_FW_PRE "iwlwifi-100-"
+#define _IWL100_MODULE_FIRMWARE(api) IWL100_FW_PRE #api ".ucode"
+#define IWL100_MODULE_FIRMWARE(api) _IWL100_MODULE_FIRMWARE(api)
+
 
 /*
  * For 1000, use advance thermal throttling critical temperature threshold,
@@ -120,13 +126,13 @@ static int iwl1000_hw_set_hw_params(struct iwl_priv *priv)
 {
        if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES &&
            priv->cfg->mod_params->num_of_queues <= IWLAGN_NUM_QUEUES)
-               priv->cfg->num_of_queues =
+               priv->cfg->base_params->num_of_queues =
                        priv->cfg->mod_params->num_of_queues;
 
-       priv->hw_params.max_txq_num = priv->cfg->num_of_queues;
+       priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues;
        priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM;
        priv->hw_params.scd_bc_tbls_size =
-                       priv->cfg->num_of_queues *
+                       priv->cfg->base_params->num_of_queues *
                        sizeof(struct iwlagn_scd_bc_tbl);
        priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
        priv->hw_params.max_stations = IWLAGN_STATION_COUNT;
@@ -244,29 +250,16 @@ static const struct iwl_ops iwl1000_ops = {
        .led = &iwlagn_led_ops,
 };
 
-struct iwl_cfg iwl1000_bgn_cfg = {
-       .name = "Intel(R) Centrino(R) Wireless-N 1000 BGN",
-       .fw_name_pre = IWL1000_FW_PRE,
-       .ucode_api_max = IWL1000_UCODE_API_MAX,
-       .ucode_api_min = IWL1000_UCODE_API_MIN,
-       .sku = IWL_SKU_G|IWL_SKU_N,
-       .ops = &iwl1000_ops,
-       .eeprom_size = OTP_LOW_IMAGE_SIZE,
-       .eeprom_ver = EEPROM_1000_EEPROM_VERSION,
-       .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION,
+static struct iwl_base_params iwl1000_base_params = {
        .num_of_queues = IWLAGN_NUM_QUEUES,
        .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
-       .mod_params = &iwlagn_mod_params,
-       .valid_tx_ant = ANT_A,
-       .valid_rx_ant = ANT_AB,
+       .eeprom_size = OTP_LOW_IMAGE_SIZE,
        .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
        .set_l0s = true,
        .use_bsm = false,
        .max_ll_items = OTP_MAX_LL_ITEMS_1000,
        .shadow_ram_support = false,
-       .ht_greenfield_support = true,
        .led_compensation = 51,
-       .use_rts_for_aggregation = true, /* use rts/cts protection */
        .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
        .support_ct_kill_exit = true,
        .plcp_delta_threshold = IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF,
@@ -277,6 +270,26 @@ struct iwl_cfg iwl1000_bgn_cfg = {
        .sensitivity_calib_by_driver = true,
        .chain_noise_calib_by_driver = true,
 };
+static struct iwl_ht_params iwl1000_ht_params = {
+       .ht_greenfield_support = true,
+       .use_rts_for_aggregation = true, /* use rts/cts protection */
+};
+
+struct iwl_cfg iwl1000_bgn_cfg = {
+       .name = "Intel(R) Centrino(R) Wireless-N 1000 BGN",
+       .fw_name_pre = IWL1000_FW_PRE,
+       .ucode_api_max = IWL1000_UCODE_API_MAX,
+       .ucode_api_min = IWL1000_UCODE_API_MIN,
+       .sku = IWL_SKU_G|IWL_SKU_N,
+       .valid_tx_ant = ANT_A,
+       .valid_rx_ant = ANT_AB,
+       .eeprom_ver = EEPROM_1000_EEPROM_VERSION,
+       .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION,
+       .ops = &iwl1000_ops,
+       .mod_params = &iwlagn_mod_params,
+       .base_params = &iwl1000_base_params,
+       .ht_params = &iwl1000_ht_params,
+};
 
 struct iwl_cfg iwl1000_bg_cfg = {
        .name = "Intel(R) Centrino(R) Wireless-N 1000 BG",
@@ -284,30 +297,45 @@ struct iwl_cfg iwl1000_bg_cfg = {
        .ucode_api_max = IWL1000_UCODE_API_MAX,
        .ucode_api_min = IWL1000_UCODE_API_MIN,
        .sku = IWL_SKU_G,
+       .valid_tx_ant = ANT_A,
+       .valid_rx_ant = ANT_AB,
+       .eeprom_ver = EEPROM_1000_EEPROM_VERSION,
+       .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION,
        .ops = &iwl1000_ops,
-       .eeprom_size = OTP_LOW_IMAGE_SIZE,
+       .mod_params = &iwlagn_mod_params,
+       .base_params = &iwl1000_base_params,
+};
+
+struct iwl_cfg iwl100_bgn_cfg = {
+       .name = "Intel(R) 100 Series 1x1 BGN",
+       .fw_name_pre = IWL100_FW_PRE,
+       .ucode_api_max = IWL100_UCODE_API_MAX,
+       .ucode_api_min = IWL100_UCODE_API_MIN,
+       .sku = IWL_SKU_G|IWL_SKU_N,
+       .valid_tx_ant = ANT_A,
+       .valid_rx_ant = ANT_A,
        .eeprom_ver = EEPROM_1000_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION,
-       .num_of_queues = IWLAGN_NUM_QUEUES,
-       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+       .ops = &iwl1000_ops,
        .mod_params = &iwlagn_mod_params,
+       .base_params = &iwl1000_base_params,
+       .ht_params = &iwl1000_ht_params,
+};
+
+struct iwl_cfg iwl100_bg_cfg = {
+       .name = "Intel(R) 100 Series 1x1 BG",
+       .fw_name_pre = IWL100_FW_PRE,
+       .ucode_api_max = IWL100_UCODE_API_MAX,
+       .ucode_api_min = IWL100_UCODE_API_MIN,
+       .sku = IWL_SKU_G,
        .valid_tx_ant = ANT_A,
-       .valid_rx_ant = ANT_AB,
-       .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
-       .set_l0s = true,
-       .use_bsm = false,
-       .max_ll_items = OTP_MAX_LL_ITEMS_1000,
-       .shadow_ram_support = false,
-       .led_compensation = 51,
-       .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
-       .support_ct_kill_exit = true,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF,
-       .chain_noise_scale = 1000,
-       .monitor_recover_period = IWL_DEF_MONITORING_PERIOD,
-       .max_event_log_size = 128,
-       .ucode_tracing = true,
-       .sensitivity_calib_by_driver = true,
-       .chain_noise_calib_by_driver = true,
+       .valid_rx_ant = ANT_A,
+       .eeprom_ver = EEPROM_1000_EEPROM_VERSION,
+       .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION,
+       .ops = &iwl1000_ops,
+       .mod_params = &iwlagn_mod_params,
+       .base_params = &iwl1000_base_params,
 };
 
 MODULE_FIRMWARE(IWL1000_MODULE_FIRMWARE(IWL1000_UCODE_API_MAX));
+MODULE_FIRMWARE(IWL100_MODULE_FIRMWARE(IWL100_UCODE_API_MAX));
index 5d09686c33895c89c7cb8d91124cc6f539cd2c80..cfdff5487e3c2d3e239de2f3199a33175011d774 100644 (file)
@@ -406,7 +406,7 @@ static bool iwl3945_good_plcp_health(struct iwl_priv *priv,
        unsigned int plcp_msec;
        unsigned long plcp_received_jiffies;
 
-       if (priv->cfg->plcp_delta_threshold ==
+       if (priv->cfg->base_params->plcp_delta_threshold ==
            IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE) {
                IWL_DEBUG_RADIO(priv, "plcp_err check disabled\n");
                return rc;
@@ -432,7 +432,7 @@ static bool iwl3945_good_plcp_health(struct iwl_priv *priv,
 
                if ((combined_plcp_delta > 0) &&
                        ((combined_plcp_delta * 100) / plcp_msec) >
-                       priv->cfg->plcp_delta_threshold) {
+                       priv->cfg->base_params->plcp_delta_threshold) {
                        /*
                         * if plcp_err exceed the threshold, the following
                         * data is printed in csv format:
@@ -444,7 +444,7 @@ static bool iwl3945_good_plcp_health(struct iwl_priv *priv,
                         */
                        IWL_DEBUG_RADIO(priv, "plcp_err exceeded %u, "
                                "%u, %d, %u mSecs\n",
-                               priv->cfg->plcp_delta_threshold,
+                               priv->cfg->base_params->plcp_delta_threshold,
                                le32_to_cpu(current_stat.rx.ofdm.plcp_err),
                                combined_plcp_delta, plcp_msec);
                        /*
@@ -2421,7 +2421,7 @@ int iwl3945_hw_set_hw_params(struct iwl_priv *priv)
        }
 
        /* Assign number of Usable TX queues */
-       priv->hw_params.max_txq_num = priv->cfg->num_of_queues;
+       priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues;
 
        priv->hw_params.tfd_size = sizeof(struct iwl3945_tfd);
        priv->hw_params.rx_page_order = get_order(IWL_RX_BUF_SIZE_3K);
@@ -2722,22 +2722,12 @@ static const struct iwl_ops iwl3945_ops = {
        .led = &iwl3945_led_ops,
 };
 
-static struct iwl_cfg iwl3945_bg_cfg = {
-       .name = "3945BG",
-       .fw_name_pre = IWL3945_FW_PRE,
-       .ucode_api_max = IWL3945_UCODE_API_MAX,
-       .ucode_api_min = IWL3945_UCODE_API_MIN,
-       .sku = IWL_SKU_G,
+static struct iwl_base_params iwl3945_base_params = {
        .eeprom_size = IWL3945_EEPROM_IMG_SIZE,
-       .eeprom_ver = EEPROM_3945_EEPROM_VERSION,
-       .ops = &iwl3945_ops,
-       .num_of_queues = IWL39_NUM_QUEUES,
-       .mod_params = &iwl3945_mod_params,
        .pll_cfg_val = CSR39_ANA_PLL_CFG_VAL,
        .set_l0s = false,
        .use_bsm = true,
        .use_isr_legacy = true,
-       .ht_greenfield_support = false,
        .led_compensation = 64,
        .broken_powersave = true,
        .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
@@ -2746,25 +2736,28 @@ static struct iwl_cfg iwl3945_bg_cfg = {
        .tx_power_by_driver = true,
 };
 
+static struct iwl_cfg iwl3945_bg_cfg = {
+       .name = "3945BG",
+       .fw_name_pre = IWL3945_FW_PRE,
+       .ucode_api_max = IWL3945_UCODE_API_MAX,
+       .ucode_api_min = IWL3945_UCODE_API_MIN,
+       .sku = IWL_SKU_G,
+       .eeprom_ver = EEPROM_3945_EEPROM_VERSION,
+       .ops = &iwl3945_ops,
+       .mod_params = &iwl3945_mod_params,
+       .base_params = &iwl3945_base_params,
+};
+
 static struct iwl_cfg iwl3945_abg_cfg = {
        .name = "3945ABG",
        .fw_name_pre = IWL3945_FW_PRE,
        .ucode_api_max = IWL3945_UCODE_API_MAX,
        .ucode_api_min = IWL3945_UCODE_API_MIN,
        .sku = IWL_SKU_A|IWL_SKU_G,
-       .eeprom_size = IWL3945_EEPROM_IMG_SIZE,
        .eeprom_ver = EEPROM_3945_EEPROM_VERSION,
        .ops = &iwl3945_ops,
-       .num_of_queues = IWL39_NUM_QUEUES,
        .mod_params = &iwl3945_mod_params,
-       .use_isr_legacy = true,
-       .ht_greenfield_support = false,
-       .led_compensation = 64,
-       .broken_powersave = true,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
-       .monitor_recover_period = IWL_DEF_MONITORING_PERIOD,
-       .max_event_log_size = 512,
-       .tx_power_by_driver = true,
+       .base_params = &iwl3945_base_params,
 };
 
 DEFINE_PCI_DEVICE_TABLE(iwl3945_hw_card_ids) = {
index 943a9c7bfa7fdeeb71fce24dba5cee3734a68946..834c2f9c15d748b61b85174a11fce20b7838ac48 100644 (file)
@@ -647,13 +647,13 @@ static int iwl4965_hw_set_hw_params(struct iwl_priv *priv)
 {
        if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES &&
            priv->cfg->mod_params->num_of_queues <= IWL49_NUM_QUEUES)
-               priv->cfg->num_of_queues =
+               priv->cfg->base_params->num_of_queues =
                        priv->cfg->mod_params->num_of_queues;
 
-       priv->hw_params.max_txq_num = priv->cfg->num_of_queues;
+       priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues;
        priv->hw_params.dma_chnl_num = FH49_TCSR_CHNL_NUM;
        priv->hw_params.scd_bc_tbls_size =
-                       priv->cfg->num_of_queues *
+                       priv->cfg->base_params->num_of_queues *
                        sizeof(struct iwl4965_scd_bc_tbl);
        priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
        priv->hw_params.max_stations = IWL4965_STATION_COUNT;
@@ -1724,13 +1724,13 @@ static int iwl4965_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
                                   u16 ssn_idx, u8 tx_fifo)
 {
        if ((IWL49_FIRST_AMPDU_QUEUE > txq_id) ||
-           (IWL49_FIRST_AMPDU_QUEUE + priv->cfg->num_of_ampdu_queues
-            <= txq_id)) {
+           (IWL49_FIRST_AMPDU_QUEUE +
+               priv->cfg->base_params->num_of_ampdu_queues <= txq_id)) {
                IWL_WARN(priv,
                        "queue number out of range: %d, must be %d to %d\n",
                        txq_id, IWL49_FIRST_AMPDU_QUEUE,
                        IWL49_FIRST_AMPDU_QUEUE +
-                       priv->cfg->num_of_ampdu_queues - 1);
+                       priv->cfg->base_params->num_of_ampdu_queues - 1);
                return -EINVAL;
        }
 
@@ -1792,13 +1792,13 @@ static int iwl4965_txq_agg_enable(struct iwl_priv *priv, int txq_id,
        int ret;
 
        if ((IWL49_FIRST_AMPDU_QUEUE > txq_id) ||
-           (IWL49_FIRST_AMPDU_QUEUE + priv->cfg->num_of_ampdu_queues
-            <= txq_id)) {
+           (IWL49_FIRST_AMPDU_QUEUE +
+               priv->cfg->base_params->num_of_ampdu_queues <= txq_id)) {
                IWL_WARN(priv,
                        "queue number out of range: %d, must be %d to %d\n",
                        txq_id, IWL49_FIRST_AMPDU_QUEUE,
                        IWL49_FIRST_AMPDU_QUEUE +
-                       priv->cfg->num_of_ampdu_queues - 1);
+                       priv->cfg->base_params->num_of_ampdu_queues - 1);
                return -EINVAL;
        }
 
@@ -2302,26 +2302,14 @@ static const struct iwl_ops iwl4965_ops = {
        .led = &iwlagn_led_ops,
 };
 
-struct iwl_cfg iwl4965_agn_cfg = {
-       .name = "Intel(R) Wireless WiFi Link 4965AGN",
-       .fw_name_pre = IWL4965_FW_PRE,
-       .ucode_api_max = IWL4965_UCODE_API_MAX,
-       .ucode_api_min = IWL4965_UCODE_API_MIN,
-       .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
+static struct iwl_base_params iwl4965_base_params = {
        .eeprom_size = IWL4965_EEPROM_IMG_SIZE,
-       .eeprom_ver = EEPROM_4965_EEPROM_VERSION,
-       .eeprom_calib_ver = EEPROM_4965_TX_POWER_VERSION,
-       .ops = &iwl4965_ops,
        .num_of_queues = IWL49_NUM_QUEUES,
        .num_of_ampdu_queues = IWL49_NUM_AMPDU_QUEUES,
-       .mod_params = &iwlagn_mod_params,
-       .valid_tx_ant = ANT_AB,
-       .valid_rx_ant = ANT_ABC,
        .pll_cfg_val = 0,
        .set_l0s = true,
        .use_bsm = true,
        .use_isr_legacy = true,
-       .ht_greenfield_support = false,
        .broken_powersave = true,
        .led_compensation = 61,
        .chain_noise_num_beacons = IWL4965_CAL_NUM_BEACONS,
@@ -2333,6 +2321,21 @@ struct iwl_cfg iwl4965_agn_cfg = {
        .ucode_tracing = true,
        .sensitivity_calib_by_driver = true,
        .chain_noise_calib_by_driver = true,
+};
+
+struct iwl_cfg iwl4965_agn_cfg = {
+       .name = "Intel(R) Wireless WiFi Link 4965AGN",
+       .fw_name_pre = IWL4965_FW_PRE,
+       .ucode_api_max = IWL4965_UCODE_API_MAX,
+       .ucode_api_min = IWL4965_UCODE_API_MIN,
+       .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
+       .valid_tx_ant = ANT_AB,
+       .valid_rx_ant = ANT_ABC,
+       .eeprom_ver = EEPROM_4965_EEPROM_VERSION,
+       .eeprom_calib_ver = EEPROM_4965_TX_POWER_VERSION,
+       .ops = &iwl4965_ops,
+       .mod_params = &iwlagn_mod_params,
+       .base_params = &iwl4965_base_params,
        /*
         * Force use of chains B and C for scan RX on 5 GHz band
         * because the device has off-channel reception on chain A.
index 21b4b23368e6e7129820f3d55427cee01059c534..1b25ad63b5c1adb7a1f52589a8a54199954db7ef 100644 (file)
@@ -170,13 +170,13 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
 {
        if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES &&
            priv->cfg->mod_params->num_of_queues <= IWLAGN_NUM_QUEUES)
-               priv->cfg->num_of_queues =
+               priv->cfg->base_params->num_of_queues =
                        priv->cfg->mod_params->num_of_queues;
 
-       priv->hw_params.max_txq_num = priv->cfg->num_of_queues;
+       priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues;
        priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM;
        priv->hw_params.scd_bc_tbls_size =
-                       priv->cfg->num_of_queues *
+                       priv->cfg->base_params->num_of_queues *
                        sizeof(struct iwlagn_scd_bc_tbl);
        priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
        priv->hw_params.max_stations = IWLAGN_STATION_COUNT;
@@ -217,13 +217,13 @@ static int iwl5150_hw_set_hw_params(struct iwl_priv *priv)
 {
        if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES &&
            priv->cfg->mod_params->num_of_queues <= IWLAGN_NUM_QUEUES)
-               priv->cfg->num_of_queues =
+               priv->cfg->base_params->num_of_queues =
                        priv->cfg->mod_params->num_of_queues;
 
-       priv->hw_params.max_txq_num = priv->cfg->num_of_queues;
+       priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues;
        priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM;
        priv->hw_params.scd_bc_tbls_size =
-                       priv->cfg->num_of_queues *
+                       priv->cfg->base_params->num_of_queues *
                        sizeof(struct iwlagn_scd_bc_tbl);
        priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
        priv->hw_params.max_stations = IWLAGN_STATION_COUNT;
@@ -504,27 +504,14 @@ static const struct iwl_ops iwl5150_ops = {
        .led = &iwlagn_led_ops,
 };
 
-struct iwl_cfg iwl5300_agn_cfg = {
-       .name = "Intel(R) Ultimate N WiFi Link 5300 AGN",
-       .fw_name_pre = IWL5000_FW_PRE,
-       .ucode_api_max = IWL5000_UCODE_API_MAX,
-       .ucode_api_min = IWL5000_UCODE_API_MIN,
-       .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
-       .ops = &iwl5000_ops,
+static struct iwl_base_params iwl5000_base_params = {
        .eeprom_size = IWLAGN_EEPROM_IMG_SIZE,
-       .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
-       .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
        .num_of_queues = IWLAGN_NUM_QUEUES,
        .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
-       .mod_params = &iwlagn_mod_params,
-       .valid_tx_ant = ANT_ABC,
-       .valid_rx_ant = ANT_ABC,
        .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
        .set_l0s = true,
        .use_bsm = false,
-       .ht_greenfield_support = true,
        .led_compensation = 51,
-       .use_rts_for_aggregation = true, /* use rts/cts protection */
        .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
        .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
        .chain_noise_scale = 1000,
@@ -534,6 +521,26 @@ struct iwl_cfg iwl5300_agn_cfg = {
        .sensitivity_calib_by_driver = true,
        .chain_noise_calib_by_driver = true,
 };
+static struct iwl_ht_params iwl5000_ht_params = {
+       .ht_greenfield_support = true,
+       .use_rts_for_aggregation = true, /* use rts/cts protection */
+};
+
+struct iwl_cfg iwl5300_agn_cfg = {
+       .name = "Intel(R) Ultimate N WiFi Link 5300 AGN",
+       .fw_name_pre = IWL5000_FW_PRE,
+       .ucode_api_max = IWL5000_UCODE_API_MAX,
+       .ucode_api_min = IWL5000_UCODE_API_MIN,
+       .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
+       .valid_tx_ant = ANT_ABC,
+       .valid_rx_ant = ANT_ABC,
+       .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
+       .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
+       .ops = &iwl5000_ops,
+       .mod_params = &iwlagn_mod_params,
+       .base_params = &iwl5000_base_params,
+       .ht_params = &iwl5000_ht_params,
+};
 
 struct iwl_cfg iwl5100_bgn_cfg = {
        .name = "Intel(R) WiFi Link 5100 BGN",
@@ -541,29 +548,14 @@ struct iwl_cfg iwl5100_bgn_cfg = {
        .ucode_api_max = IWL5000_UCODE_API_MAX,
        .ucode_api_min = IWL5000_UCODE_API_MIN,
        .sku = IWL_SKU_G|IWL_SKU_N,
-       .ops = &iwl5000_ops,
-       .eeprom_size = IWLAGN_EEPROM_IMG_SIZE,
+       .valid_tx_ant = ANT_B,
+       .valid_rx_ant = ANT_AB,
        .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
-       .num_of_queues = IWLAGN_NUM_QUEUES,
-       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+       .ops = &iwl5000_ops,
        .mod_params = &iwlagn_mod_params,
-       .valid_tx_ant = ANT_B,
-       .valid_rx_ant = ANT_AB,
-       .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
-       .set_l0s = true,
-       .use_bsm = false,
-       .ht_greenfield_support = true,
-       .led_compensation = 51,
-       .use_rts_for_aggregation = true, /* use rts/cts protection */
-       .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
-       .chain_noise_scale = 1000,
-       .monitor_recover_period = IWL_LONG_MONITORING_PERIOD,
-       .max_event_log_size = 512,
-       .ucode_tracing = true,
-       .sensitivity_calib_by_driver = true,
-       .chain_noise_calib_by_driver = true,
+       .base_params = &iwl5000_base_params,
+       .ht_params = &iwl5000_ht_params,
 };
 
 struct iwl_cfg iwl5100_abg_cfg = {
@@ -572,27 +564,13 @@ struct iwl_cfg iwl5100_abg_cfg = {
        .ucode_api_max = IWL5000_UCODE_API_MAX,
        .ucode_api_min = IWL5000_UCODE_API_MIN,
        .sku = IWL_SKU_A|IWL_SKU_G,
-       .ops = &iwl5000_ops,
-       .eeprom_size = IWLAGN_EEPROM_IMG_SIZE,
+       .valid_tx_ant = ANT_B,
+       .valid_rx_ant = ANT_AB,
        .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
-       .num_of_queues = IWLAGN_NUM_QUEUES,
-       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+       .ops = &iwl5000_ops,
        .mod_params = &iwlagn_mod_params,
-       .valid_tx_ant = ANT_B,
-       .valid_rx_ant = ANT_AB,
-       .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
-       .set_l0s = true,
-       .use_bsm = false,
-       .led_compensation = 51,
-       .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
-       .chain_noise_scale = 1000,
-       .monitor_recover_period = IWL_LONG_MONITORING_PERIOD,
-       .max_event_log_size = 512,
-       .ucode_tracing = true,
-       .sensitivity_calib_by_driver = true,
-       .chain_noise_calib_by_driver = true,
+       .base_params = &iwl5000_base_params,
 };
 
 struct iwl_cfg iwl5100_agn_cfg = {
@@ -601,29 +579,14 @@ struct iwl_cfg iwl5100_agn_cfg = {
        .ucode_api_max = IWL5000_UCODE_API_MAX,
        .ucode_api_min = IWL5000_UCODE_API_MIN,
        .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
-       .ops = &iwl5000_ops,
-       .eeprom_size = IWLAGN_EEPROM_IMG_SIZE,
+       .valid_tx_ant = ANT_B,
+       .valid_rx_ant = ANT_AB,
        .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
-       .num_of_queues = IWLAGN_NUM_QUEUES,
-       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+       .ops = &iwl5000_ops,
        .mod_params = &iwlagn_mod_params,
-       .valid_tx_ant = ANT_B,
-       .valid_rx_ant = ANT_AB,
-       .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
-       .set_l0s = true,
-       .use_bsm = false,
-       .ht_greenfield_support = true,
-       .led_compensation = 51,
-       .use_rts_for_aggregation = true, /* use rts/cts protection */
-       .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
-       .chain_noise_scale = 1000,
-       .monitor_recover_period = IWL_LONG_MONITORING_PERIOD,
-       .max_event_log_size = 512,
-       .ucode_tracing = true,
-       .sensitivity_calib_by_driver = true,
-       .chain_noise_calib_by_driver = true,
+       .base_params = &iwl5000_base_params,
+       .ht_params = &iwl5000_ht_params,
 };
 
 struct iwl_cfg iwl5350_agn_cfg = {
@@ -632,29 +595,14 @@ struct iwl_cfg iwl5350_agn_cfg = {
        .ucode_api_max = IWL5000_UCODE_API_MAX,
        .ucode_api_min = IWL5000_UCODE_API_MIN,
        .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
-       .ops = &iwl5000_ops,
-       .eeprom_size = IWLAGN_EEPROM_IMG_SIZE,
+       .valid_tx_ant = ANT_ABC,
+       .valid_rx_ant = ANT_ABC,
        .eeprom_ver = EEPROM_5050_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,
-       .num_of_queues = IWLAGN_NUM_QUEUES,
-       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+       .ops = &iwl5000_ops,
        .mod_params = &iwlagn_mod_params,
-       .valid_tx_ant = ANT_ABC,
-       .valid_rx_ant = ANT_ABC,
-       .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
-       .set_l0s = true,
-       .use_bsm = false,
-       .ht_greenfield_support = true,
-       .led_compensation = 51,
-       .use_rts_for_aggregation = true, /* use rts/cts protection */
-       .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
-       .chain_noise_scale = 1000,
-       .monitor_recover_period = IWL_LONG_MONITORING_PERIOD,
-       .max_event_log_size = 512,
-       .ucode_tracing = true,
-       .sensitivity_calib_by_driver = true,
-       .chain_noise_calib_by_driver = true,
+       .base_params = &iwl5000_base_params,
+       .ht_params = &iwl5000_ht_params,
 };
 
 struct iwl_cfg iwl5150_agn_cfg = {
@@ -663,29 +611,14 @@ struct iwl_cfg iwl5150_agn_cfg = {
        .ucode_api_max = IWL5150_UCODE_API_MAX,
        .ucode_api_min = IWL5150_UCODE_API_MIN,
        .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
-       .ops = &iwl5150_ops,
-       .eeprom_size = IWLAGN_EEPROM_IMG_SIZE,
+       .valid_tx_ant = ANT_A,
+       .valid_rx_ant = ANT_AB,
        .eeprom_ver = EEPROM_5050_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,
-       .num_of_queues = IWLAGN_NUM_QUEUES,
-       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+       .ops = &iwl5150_ops,
        .mod_params = &iwlagn_mod_params,
-       .valid_tx_ant = ANT_A,
-       .valid_rx_ant = ANT_AB,
-       .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
-       .set_l0s = true,
-       .use_bsm = false,
-       .ht_greenfield_support = true,
-       .led_compensation = 51,
-       .use_rts_for_aggregation = true, /* use rts/cts protection */
-       .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
-       .chain_noise_scale = 1000,
-       .monitor_recover_period = IWL_LONG_MONITORING_PERIOD,
-       .max_event_log_size = 512,
-       .ucode_tracing = true,
-       .sensitivity_calib_by_driver = true,
-       .chain_noise_calib_by_driver = true,
+       .base_params = &iwl5000_base_params,
+       .ht_params = &iwl5000_ht_params,
        .need_dc_calib = true,
 };
 
@@ -695,27 +628,13 @@ struct iwl_cfg iwl5150_abg_cfg = {
        .ucode_api_max = IWL5150_UCODE_API_MAX,
        .ucode_api_min = IWL5150_UCODE_API_MIN,
        .sku = IWL_SKU_A|IWL_SKU_G,
-       .ops = &iwl5150_ops,
-       .eeprom_size = IWLAGN_EEPROM_IMG_SIZE,
+       .valid_tx_ant = ANT_A,
+       .valid_rx_ant = ANT_AB,
        .eeprom_ver = EEPROM_5050_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,
-       .num_of_queues = IWLAGN_NUM_QUEUES,
-       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+       .ops = &iwl5150_ops,
        .mod_params = &iwlagn_mod_params,
-       .valid_tx_ant = ANT_A,
-       .valid_rx_ant = ANT_AB,
-       .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
-       .set_l0s = true,
-       .use_bsm = false,
-       .led_compensation = 51,
-       .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
-       .chain_noise_scale = 1000,
-       .monitor_recover_period = IWL_LONG_MONITORING_PERIOD,
-       .max_event_log_size = 512,
-       .ucode_tracing = true,
-       .sensitivity_calib_by_driver = true,
-       .chain_noise_calib_by_driver = true,
+       .base_params = &iwl5000_base_params,
        .need_dc_calib = true,
 };
 
index 9f43f2770c96897e39fed5118abdf311af5731bb..6261aec5ebdc143eb8510ad484bb757e53b4ea44 100644 (file)
 
 /* Highest firmware API version supported */
 #define IWL6000_UCODE_API_MAX 4
-#define IWL6050_UCODE_API_MAX 4
+#define IWL6050_UCODE_API_MAX 5
 #define IWL6000G2_UCODE_API_MAX 5
+#define IWL130_UCODE_API_MAX 5
 
 /* Lowest firmware API version supported */
 #define IWL6000_UCODE_API_MIN 4
 #define IWL6050_UCODE_API_MIN 4
 #define IWL6000G2_UCODE_API_MIN 4
+#define IWL130_UCODE_API_MIN 5
 
 #define IWL6000_FW_PRE "iwlwifi-6000-"
 #define _IWL6000_MODULE_FIRMWARE(api) IWL6000_FW_PRE #api ".ucode"
@@ -75,6 +77,9 @@
 #define _IWL6000G2B_MODULE_FIRMWARE(api) IWL6000G2B_FW_PRE #api ".ucode"
 #define IWL6000G2B_MODULE_FIRMWARE(api) _IWL6000G2B_MODULE_FIRMWARE(api)
 
+#define IWL130_FW_PRE "iwlwifi-130-"
+#define _IWL130_MODULE_FIRMWARE(api) IWL130_FW_PRE #api ".ucode"
+#define IWL130_MODULE_FIRMWARE(api) _IWL130_MODULE_FIRMWARE(api)
 
 static void iwl6000_set_ct_threshold(struct iwl_priv *priv)
 {
@@ -83,15 +88,24 @@ static void iwl6000_set_ct_threshold(struct iwl_priv *priv)
        priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD;
 }
 
-/* Indicate calibration version to uCode. */
-static void iwl6000_set_calib_version(struct iwl_priv *priv)
+static void iwl6050_additional_nic_config(struct iwl_priv *priv)
 {
-       if (priv->cfg->need_dc_calib &&
-           (priv->cfg->ops->lib->eeprom_ops.calib_version(priv) >= 6))
+       /* Indicate calibration version to uCode. */
+       if (priv->cfg->ops->lib->eeprom_ops.calib_version(priv) >= 6)
                iwl_set_bit(priv, CSR_GP_DRIVER_REG,
                                CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6);
 }
 
+static void iwl6050g2_additional_nic_config(struct iwl_priv *priv)
+{
+       /* Indicate calibration version to uCode. */
+       if (priv->cfg->ops->lib->eeprom_ops.calib_version(priv) >= 6)
+               iwl_set_bit(priv, CSR_GP_DRIVER_REG,
+                               CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6);
+       iwl_set_bit(priv, CSR_GP_DRIVER_REG,
+                   CSR_GP_DRIVER_REG_BIT_6050_1x2);
+}
+
 /* NIC configuration for 6000 series */
 static void iwl6000_nic_config(struct iwl_priv *priv)
 {
@@ -117,9 +131,11 @@ static void iwl6000_nic_config(struct iwl_priv *priv)
                iwl_write32(priv, CSR_GP_DRIVER_REG,
                             CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA);
        }
-       /* else do nothing, uCode configured */
-       if (priv->cfg->ops->lib->temp_ops.set_calib_version)
-               priv->cfg->ops->lib->temp_ops.set_calib_version(priv);
+       /* do additional nic configuration if needed */
+       if (priv->cfg->ops->nic &&
+               priv->cfg->ops->nic->additional_nic_config) {
+                       priv->cfg->ops->nic->additional_nic_config(priv);
+       }
 }
 
 static struct iwl_sensitivity_ranges iwl6000_sensitivity = {
@@ -151,13 +167,13 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv)
 {
        if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES &&
            priv->cfg->mod_params->num_of_queues <= IWLAGN_NUM_QUEUES)
-               priv->cfg->num_of_queues =
+               priv->cfg->base_params->num_of_queues =
                        priv->cfg->mod_params->num_of_queues;
 
-       priv->hw_params.max_txq_num = priv->cfg->num_of_queues;
+       priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues;
        priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM;
        priv->hw_params.scd_bc_tbls_size =
-                       priv->cfg->num_of_queues *
+                       priv->cfg->base_params->num_of_queues *
                        sizeof(struct iwlagn_scd_bc_tbl);
        priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
        priv->hw_params.max_stations = IWLAGN_STATION_COUNT;
@@ -188,7 +204,7 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv)
                BIT(IWL_CALIB_TX_IQ)            |
                BIT(IWL_CALIB_BASE_BAND);
        if (priv->cfg->need_dc_calib)
-               priv->hw_params.calib_init_cfg |= BIT(IWL_CALIB_DC);
+               priv->hw_params.calib_rt_cfg |= BIT(IWL_CALIB_CFG_DC_IDX);
 
        priv->hw_params.beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS;
 
@@ -320,7 +336,6 @@ static struct iwl_lib_ops iwl6000_lib = {
        .temp_ops = {
                .temperature = iwlagn_temperature,
                .set_ct_kill = iwl6000_set_ct_threshold,
-               .set_calib_version = iwl6000_set_calib_version,
         },
        .manage_ibss_station = iwlagn_manage_ibss_station,
        .update_bcast_stations = iwl_update_bcast_stations,
@@ -396,7 +411,6 @@ static struct iwl_lib_ops iwl6000g2b_lib = {
        .temp_ops = {
                .temperature = iwlagn_temperature,
                .set_ct_kill = iwl6000_set_ct_threshold,
-               .set_calib_version = iwl6000_set_calib_version,
         },
        .manage_ibss_station = iwlagn_manage_ibss_station,
        .update_bcast_stations = iwl_update_bcast_stations,
@@ -419,6 +433,14 @@ static struct iwl_lib_ops iwl6000g2b_lib = {
        }
 };
 
+static struct iwl_nic_ops iwl6050_nic_ops = {
+       .additional_nic_config = &iwl6050_additional_nic_config,
+};
+
+static struct iwl_nic_ops iwl6050g2_nic_ops = {
+       .additional_nic_config = &iwl6050g2_additional_nic_config,
+};
+
 static const struct iwl_ops iwl6000_ops = {
        .lib = &iwl6000_lib,
        .hcmd = &iwlagn_hcmd,
@@ -426,6 +448,22 @@ static const struct iwl_ops iwl6000_ops = {
        .led = &iwlagn_led_ops,
 };
 
+static const struct iwl_ops iwl6050_ops = {
+       .lib = &iwl6000_lib,
+       .hcmd = &iwlagn_hcmd,
+       .utils = &iwlagn_hcmd_utils,
+       .led = &iwlagn_led_ops,
+       .nic = &iwl6050_nic_ops,
+};
+
+static const struct iwl_ops iwl6050g2_ops = {
+       .lib = &iwl6000_lib,
+       .hcmd = &iwlagn_hcmd,
+       .utils = &iwlagn_hcmd_utils,
+       .led = &iwlagn_led_ops,
+       .nic = &iwl6050g2_nic_ops,
+};
+
 static const struct iwl_ops iwl6000g2b_ops = {
        .lib = &iwl6000g2b_lib,
        .hcmd = &iwlagn_bt_hcmd,
@@ -433,30 +471,16 @@ static const struct iwl_ops iwl6000g2b_ops = {
        .led = &iwlagn_led_ops,
 };
 
-struct iwl_cfg iwl6000g2a_2agn_cfg = {
-       .name = "6000 Series 2x2 AGN Gen2a",
-       .fw_name_pre = IWL6000G2A_FW_PRE,
-       .ucode_api_max = IWL6000G2_UCODE_API_MAX,
-       .ucode_api_min = IWL6000G2_UCODE_API_MIN,
-       .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
-       .ops = &iwl6000_ops,
+static struct iwl_base_params iwl6000_base_params = {
        .eeprom_size = OTP_LOW_IMAGE_SIZE,
-       .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
-       .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
        .num_of_queues = IWLAGN_NUM_QUEUES,
        .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
-       .mod_params = &iwlagn_mod_params,
-       .valid_tx_ant = ANT_AB,
-       .valid_rx_ant = ANT_AB,
        .pll_cfg_val = 0,
        .set_l0s = true,
        .use_bsm = false,
-       .pa_type = IWL_PA_SYSTEM,
        .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
        .shadow_ram_support = true,
-       .ht_greenfield_support = true,
        .led_compensation = 51,
-       .use_rts_for_aggregation = true, /* use rts/cts protection */
        .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
        .supports_idle = true,
        .adv_thermal_throttle = true,
@@ -468,29 +492,16 @@ struct iwl_cfg iwl6000g2a_2agn_cfg = {
        .ucode_tracing = true,
        .sensitivity_calib_by_driver = true,
        .chain_noise_calib_by_driver = true,
-       .need_dc_calib = true,
 };
 
-struct iwl_cfg iwl6000g2a_2abg_cfg = {
-       .name = "6000 Series 2x2 ABG Gen2a",
-       .fw_name_pre = IWL6000G2A_FW_PRE,
-       .ucode_api_max = IWL6000G2_UCODE_API_MAX,
-       .ucode_api_min = IWL6000G2_UCODE_API_MIN,
-       .sku = IWL_SKU_A|IWL_SKU_G,
-       .ops = &iwl6000_ops,
+static struct iwl_base_params iwl6050_base_params = {
        .eeprom_size = OTP_LOW_IMAGE_SIZE,
-       .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
-       .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
        .num_of_queues = IWLAGN_NUM_QUEUES,
        .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
-       .mod_params = &iwlagn_mod_params,
-       .valid_tx_ant = ANT_AB,
-       .valid_rx_ant = ANT_AB,
        .pll_cfg_val = 0,
        .set_l0s = true,
        .use_bsm = false,
-       .pa_type = IWL_PA_SYSTEM,
-       .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+       .max_ll_items = OTP_MAX_LL_ITEMS_6x50,
        .shadow_ram_support = true,
        .led_compensation = 51,
        .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
@@ -498,11 +509,57 @@ struct iwl_cfg iwl6000g2a_2abg_cfg = {
        .adv_thermal_throttle = true,
        .support_ct_kill_exit = true,
        .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
-       .chain_noise_scale = 1000,
+       .chain_noise_scale = 1500,
        .monitor_recover_period = IWL_DEF_MONITORING_PERIOD,
-       .max_event_log_size = 512,
+       .max_event_log_size = 1024,
+       .ucode_tracing = true,
        .sensitivity_calib_by_driver = true,
        .chain_noise_calib_by_driver = true,
+};
+
+static struct iwl_ht_params iwl6000_ht_params = {
+       .ht_greenfield_support = true,
+       .use_rts_for_aggregation = true, /* use rts/cts protection */
+};
+
+static struct iwl_bt_params iwl6000_bt_params = {
+       .bt_statistics = true,
+       /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
+       .advanced_bt_coexist = true,
+       .bt_init_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_NONE,
+       .bt_prio_boost = IWLAGN_BT_PRIO_BOOST_DEFAULT,
+};
+
+struct iwl_cfg iwl6000g2a_2agn_cfg = {
+       .name = "6000 Series 2x2 AGN Gen2a",
+       .fw_name_pre = IWL6000G2A_FW_PRE,
+       .ucode_api_max = IWL6000G2_UCODE_API_MAX,
+       .ucode_api_min = IWL6000G2_UCODE_API_MIN,
+       .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
+       .valid_tx_ant = ANT_AB,
+       .valid_rx_ant = ANT_AB,
+       .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
+       .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
+       .ops = &iwl6000_ops,
+       .mod_params = &iwlagn_mod_params,
+       .base_params = &iwl6000_base_params,
+       .ht_params = &iwl6000_ht_params,
+       .need_dc_calib = true,
+};
+
+struct iwl_cfg iwl6000g2a_2abg_cfg = {
+       .name = "6000 Series 2x2 ABG Gen2a",
+       .fw_name_pre = IWL6000G2A_FW_PRE,
+       .ucode_api_max = IWL6000G2_UCODE_API_MAX,
+       .ucode_api_min = IWL6000G2_UCODE_API_MIN,
+       .sku = IWL_SKU_A|IWL_SKU_G,
+       .valid_tx_ant = ANT_AB,
+       .valid_rx_ant = ANT_AB,
+       .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
+       .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
+       .ops = &iwl6000_ops,
+       .mod_params = &iwlagn_mod_params,
+       .base_params = &iwl6000_base_params,
        .need_dc_calib = true,
 };
 
@@ -512,32 +569,13 @@ struct iwl_cfg iwl6000g2a_2bg_cfg = {
        .ucode_api_max = IWL6000G2_UCODE_API_MAX,
        .ucode_api_min = IWL6000G2_UCODE_API_MIN,
        .sku = IWL_SKU_G,
-       .ops = &iwl6000_ops,
-       .eeprom_size = OTP_LOW_IMAGE_SIZE,
+       .valid_tx_ant = ANT_AB,
+       .valid_rx_ant = ANT_AB,
        .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
-       .num_of_queues = IWLAGN_NUM_QUEUES,
-       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+       .ops = &iwl6000_ops,
        .mod_params = &iwlagn_mod_params,
-       .valid_tx_ant = ANT_AB,
-       .valid_rx_ant = ANT_AB,
-       .pll_cfg_val = 0,
-       .set_l0s = true,
-       .use_bsm = false,
-       .pa_type = IWL_PA_SYSTEM,
-       .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
-       .shadow_ram_support = true,
-       .led_compensation = 51,
-       .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
-       .supports_idle = true,
-       .adv_thermal_throttle = true,
-       .support_ct_kill_exit = true,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
-       .chain_noise_scale = 1000,
-       .monitor_recover_period = IWL_DEF_MONITORING_PERIOD,
-       .max_event_log_size = 512,
-       .sensitivity_calib_by_driver = true,
-       .chain_noise_calib_by_driver = true,
+       .base_params = &iwl6000_base_params,
        .need_dc_calib = true,
 };
 
@@ -547,41 +585,18 @@ struct iwl_cfg iwl6000g2b_2agn_cfg = {
        .ucode_api_max = IWL6000G2_UCODE_API_MAX,
        .ucode_api_min = IWL6000G2_UCODE_API_MIN,
        .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
-       .ops = &iwl6000g2b_ops,
-       .eeprom_size = OTP_LOW_IMAGE_SIZE,
+       .valid_tx_ant = ANT_AB,
+       .valid_rx_ant = ANT_AB,
        .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
-       .num_of_queues = IWLAGN_NUM_QUEUES,
-       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+       .ops = &iwl6000g2b_ops,
        .mod_params = &iwlagn_mod_params,
-       .valid_tx_ant = ANT_AB,
-       .valid_rx_ant = ANT_AB,
-       .pll_cfg_val = 0,
-       .set_l0s = true,
-       .use_bsm = false,
-       .pa_type = IWL_PA_SYSTEM,
-       .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
-       .shadow_ram_support = true,
-       .ht_greenfield_support = true,
-       .led_compensation = 51,
-       .use_rts_for_aggregation = true, /* use rts/cts protection */
-       .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
-       .supports_idle = true,
-       .adv_thermal_throttle = true,
-       .support_ct_kill_exit = true,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE,
-       .chain_noise_scale = 1000,
-       .monitor_recover_period = IWL_LONG_MONITORING_PERIOD,
-       .max_event_log_size = 512,
-       .sensitivity_calib_by_driver = true,
-       .chain_noise_calib_by_driver = true,
+       .base_params = &iwl6000_base_params,
+       .bt_params = &iwl6000_bt_params,
+       .ht_params = &iwl6000_ht_params,
        .need_dc_calib = true,
-       .bt_statistics = true,
        /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
        .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A,
-       .advanced_bt_coexist = true,
-       .bt_init_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_NONE,
-       .bt_prio_boost = IWLAGN_BT_PRIO_BOOST_DEFAULT,
 };
 
 struct iwl_cfg iwl6000g2b_2abg_cfg = {
@@ -590,39 +605,17 @@ struct iwl_cfg iwl6000g2b_2abg_cfg = {
        .ucode_api_max = IWL6000G2_UCODE_API_MAX,
        .ucode_api_min = IWL6000G2_UCODE_API_MIN,
        .sku = IWL_SKU_A|IWL_SKU_G,
-       .ops = &iwl6000g2b_ops,
-       .eeprom_size = OTP_LOW_IMAGE_SIZE,
+       .valid_tx_ant = ANT_AB,
+       .valid_rx_ant = ANT_AB,
        .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
-       .num_of_queues = IWLAGN_NUM_QUEUES,
-       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+       .ops = &iwl6000g2b_ops,
        .mod_params = &iwlagn_mod_params,
-       .valid_tx_ant = ANT_AB,
-       .valid_rx_ant = ANT_AB,
-       .pll_cfg_val = 0,
-       .set_l0s = true,
-       .use_bsm = false,
-       .pa_type = IWL_PA_SYSTEM,
-       .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
-       .shadow_ram_support = true,
-       .led_compensation = 51,
-       .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
-       .supports_idle = true,
-       .adv_thermal_throttle = true,
-       .support_ct_kill_exit = true,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE,
-       .chain_noise_scale = 1000,
-       .monitor_recover_period = IWL_LONG_MONITORING_PERIOD,
-       .max_event_log_size = 512,
-       .sensitivity_calib_by_driver = true,
-       .chain_noise_calib_by_driver = true,
+       .base_params = &iwl6000_base_params,
+       .bt_params = &iwl6000_bt_params,
        .need_dc_calib = true,
-       .bt_statistics = true,
        /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
        .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A,
-       .advanced_bt_coexist = true,
-       .bt_init_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_NONE,
-       .bt_prio_boost = IWLAGN_BT_PRIO_BOOST_DEFAULT,
 };
 
 struct iwl_cfg iwl6000g2b_2bgn_cfg = {
@@ -631,41 +624,18 @@ struct iwl_cfg iwl6000g2b_2bgn_cfg = {
        .ucode_api_max = IWL6000G2_UCODE_API_MAX,
        .ucode_api_min = IWL6000G2_UCODE_API_MIN,
        .sku = IWL_SKU_G|IWL_SKU_N,
-       .ops = &iwl6000g2b_ops,
-       .eeprom_size = OTP_LOW_IMAGE_SIZE,
+       .valid_tx_ant = ANT_AB,
+       .valid_rx_ant = ANT_AB,
        .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
-       .num_of_queues = IWLAGN_NUM_QUEUES,
-       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+       .ops = &iwl6000g2b_ops,
        .mod_params = &iwlagn_mod_params,
-       .valid_tx_ant = ANT_AB,
-       .valid_rx_ant = ANT_AB,
-       .pll_cfg_val = 0,
-       .set_l0s = true,
-       .use_bsm = false,
-       .pa_type = IWL_PA_SYSTEM,
-       .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
-       .shadow_ram_support = true,
-       .ht_greenfield_support = true,
-       .led_compensation = 51,
-       .use_rts_for_aggregation = true, /* use rts/cts protection */
-       .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
-       .supports_idle = true,
-       .adv_thermal_throttle = true,
-       .support_ct_kill_exit = true,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE,
-       .chain_noise_scale = 1000,
-       .monitor_recover_period = IWL_LONG_MONITORING_PERIOD,
-       .max_event_log_size = 512,
-       .sensitivity_calib_by_driver = true,
-       .chain_noise_calib_by_driver = true,
+       .base_params = &iwl6000_base_params,
+       .bt_params = &iwl6000_bt_params,
+       .ht_params = &iwl6000_ht_params,
        .need_dc_calib = true,
-       .bt_statistics = true,
        /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
        .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A,
-       .advanced_bt_coexist = true,
-       .bt_init_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_NONE,
-       .bt_prio_boost = IWLAGN_BT_PRIO_BOOST_DEFAULT,
 };
 
 struct iwl_cfg iwl6000g2b_2bg_cfg = {
@@ -674,39 +644,17 @@ struct iwl_cfg iwl6000g2b_2bg_cfg = {
        .ucode_api_max = IWL6000G2_UCODE_API_MAX,
        .ucode_api_min = IWL6000G2_UCODE_API_MIN,
        .sku = IWL_SKU_G,
-       .ops = &iwl6000g2b_ops,
-       .eeprom_size = OTP_LOW_IMAGE_SIZE,
+       .valid_tx_ant = ANT_AB,
+       .valid_rx_ant = ANT_AB,
        .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
-       .num_of_queues = IWLAGN_NUM_QUEUES,
-       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+       .ops = &iwl6000g2b_ops,
        .mod_params = &iwlagn_mod_params,
-       .valid_tx_ant = ANT_AB,
-       .valid_rx_ant = ANT_AB,
-       .pll_cfg_val = 0,
-       .set_l0s = true,
-       .use_bsm = false,
-       .pa_type = IWL_PA_SYSTEM,
-       .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
-       .shadow_ram_support = true,
-       .led_compensation = 51,
-       .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
-       .supports_idle = true,
-       .adv_thermal_throttle = true,
-       .support_ct_kill_exit = true,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE,
-       .chain_noise_scale = 1000,
-       .monitor_recover_period = IWL_LONG_MONITORING_PERIOD,
-       .max_event_log_size = 512,
-       .sensitivity_calib_by_driver = true,
-       .chain_noise_calib_by_driver = true,
+       .base_params = &iwl6000_base_params,
+       .bt_params = &iwl6000_bt_params,
        .need_dc_calib = true,
-       .bt_statistics = true,
        /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
        .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A,
-       .advanced_bt_coexist = true,
-       .bt_init_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_NONE,
-       .bt_prio_boost = IWLAGN_BT_PRIO_BOOST_DEFAULT,
 };
 
 struct iwl_cfg iwl6000g2b_bgn_cfg = {
@@ -715,41 +663,18 @@ struct iwl_cfg iwl6000g2b_bgn_cfg = {
        .ucode_api_max = IWL6000G2_UCODE_API_MAX,
        .ucode_api_min = IWL6000G2_UCODE_API_MIN,
        .sku = IWL_SKU_G|IWL_SKU_N,
-       .ops = &iwl6000g2b_ops,
-       .eeprom_size = OTP_LOW_IMAGE_SIZE,
+       .valid_tx_ant = ANT_A,
+       .valid_rx_ant = ANT_AB,
        .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
-       .num_of_queues = IWLAGN_NUM_QUEUES,
-       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+       .ops = &iwl6000g2b_ops,
        .mod_params = &iwlagn_mod_params,
-       .valid_tx_ant = ANT_A,
-       .valid_rx_ant = ANT_AB,
-       .pll_cfg_val = 0,
-       .set_l0s = true,
-       .use_bsm = false,
-       .pa_type = IWL_PA_SYSTEM,
-       .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
-       .shadow_ram_support = true,
-       .ht_greenfield_support = true,
-       .led_compensation = 51,
-       .use_rts_for_aggregation = true, /* use rts/cts protection */
-       .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
-       .supports_idle = true,
-       .adv_thermal_throttle = true,
-       .support_ct_kill_exit = true,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE,
-       .chain_noise_scale = 1000,
-       .monitor_recover_period = IWL_LONG_MONITORING_PERIOD,
-       .max_event_log_size = 512,
-       .sensitivity_calib_by_driver = true,
-       .chain_noise_calib_by_driver = true,
+       .base_params = &iwl6000_base_params,
+       .bt_params = &iwl6000_bt_params,
+       .ht_params = &iwl6000_ht_params,
        .need_dc_calib = true,
-       .bt_statistics = true,
        /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
        .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A,
-       .advanced_bt_coexist = true,
-       .bt_init_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_NONE,
-       .bt_prio_boost = IWLAGN_BT_PRIO_BOOST_DEFAULT,
 };
 
 struct iwl_cfg iwl6000g2b_bg_cfg = {
@@ -758,39 +683,17 @@ struct iwl_cfg iwl6000g2b_bg_cfg = {
        .ucode_api_max = IWL6000G2_UCODE_API_MAX,
        .ucode_api_min = IWL6000G2_UCODE_API_MIN,
        .sku = IWL_SKU_G,
-       .ops = &iwl6000g2b_ops,
-       .eeprom_size = OTP_LOW_IMAGE_SIZE,
+       .valid_tx_ant = ANT_A,
+       .valid_rx_ant = ANT_AB,
        .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
-       .num_of_queues = IWLAGN_NUM_QUEUES,
-       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+       .ops = &iwl6000g2b_ops,
        .mod_params = &iwlagn_mod_params,
-       .valid_tx_ant = ANT_A,
-       .valid_rx_ant = ANT_AB,
-       .pll_cfg_val = 0,
-       .set_l0s = true,
-       .use_bsm = false,
-       .pa_type = IWL_PA_SYSTEM,
-       .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
-       .shadow_ram_support = true,
-       .led_compensation = 51,
-       .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
-       .supports_idle = true,
-       .adv_thermal_throttle = true,
-       .support_ct_kill_exit = true,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE,
-       .chain_noise_scale = 1000,
-       .monitor_recover_period = IWL_LONG_MONITORING_PERIOD,
-       .max_event_log_size = 512,
-       .sensitivity_calib_by_driver = true,
-       .chain_noise_calib_by_driver = true,
+       .base_params = &iwl6000_base_params,
+       .bt_params = &iwl6000_bt_params,
        .need_dc_calib = true,
-       .bt_statistics = true,
        /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
        .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A,
-       .advanced_bt_coexist = true,
-       .bt_init_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_NONE,
-       .bt_prio_boost = IWLAGN_BT_PRIO_BOOST_DEFAULT,
 };
 
 /*
@@ -802,35 +705,15 @@ struct iwl_cfg iwl6000i_2agn_cfg = {
        .ucode_api_max = IWL6000_UCODE_API_MAX,
        .ucode_api_min = IWL6000_UCODE_API_MIN,
        .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
-       .ops = &iwl6000_ops,
-       .eeprom_size = OTP_LOW_IMAGE_SIZE,
+       .valid_tx_ant = ANT_BC,
+       .valid_rx_ant = ANT_BC,
        .eeprom_ver = EEPROM_6000_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION,
-       .num_of_queues = IWLAGN_NUM_QUEUES,
-       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+       .ops = &iwl6000_ops,
        .mod_params = &iwlagn_mod_params,
-       .valid_tx_ant = ANT_BC,
-       .valid_rx_ant = ANT_BC,
-       .pll_cfg_val = 0,
-       .set_l0s = true,
-       .use_bsm = false,
+       .base_params = &iwl6000_base_params,
+       .ht_params = &iwl6000_ht_params,
        .pa_type = IWL_PA_INTERNAL,
-       .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
-       .shadow_ram_support = true,
-       .ht_greenfield_support = true,
-       .led_compensation = 51,
-       .use_rts_for_aggregation = true, /* use rts/cts protection */
-       .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
-       .supports_idle = true,
-       .adv_thermal_throttle = true,
-       .support_ct_kill_exit = true,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
-       .chain_noise_scale = 1000,
-       .monitor_recover_period = IWL_DEF_MONITORING_PERIOD,
-       .max_event_log_size = 1024,
-       .ucode_tracing = true,
-       .sensitivity_calib_by_driver = true,
-       .chain_noise_calib_by_driver = true,
 };
 
 struct iwl_cfg iwl6000i_2abg_cfg = {
@@ -839,33 +722,14 @@ struct iwl_cfg iwl6000i_2abg_cfg = {
        .ucode_api_max = IWL6000_UCODE_API_MAX,
        .ucode_api_min = IWL6000_UCODE_API_MIN,
        .sku = IWL_SKU_A|IWL_SKU_G,
-       .ops = &iwl6000_ops,
-       .eeprom_size = OTP_LOW_IMAGE_SIZE,
+       .valid_tx_ant = ANT_BC,
+       .valid_rx_ant = ANT_BC,
        .eeprom_ver = EEPROM_6000_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION,
-       .num_of_queues = IWLAGN_NUM_QUEUES,
-       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+       .ops = &iwl6000_ops,
        .mod_params = &iwlagn_mod_params,
-       .valid_tx_ant = ANT_BC,
-       .valid_rx_ant = ANT_BC,
-       .pll_cfg_val = 0,
-       .set_l0s = true,
-       .use_bsm = false,
+       .base_params = &iwl6000_base_params,
        .pa_type = IWL_PA_INTERNAL,
-       .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
-       .shadow_ram_support = true,
-       .led_compensation = 51,
-       .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
-       .supports_idle = true,
-       .adv_thermal_throttle = true,
-       .support_ct_kill_exit = true,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
-       .chain_noise_scale = 1000,
-       .monitor_recover_period = IWL_DEF_MONITORING_PERIOD,
-       .max_event_log_size = 1024,
-       .ucode_tracing = true,
-       .sensitivity_calib_by_driver = true,
-       .chain_noise_calib_by_driver = true,
 };
 
 struct iwl_cfg iwl6000i_2bg_cfg = {
@@ -874,33 +738,14 @@ struct iwl_cfg iwl6000i_2bg_cfg = {
        .ucode_api_max = IWL6000_UCODE_API_MAX,
        .ucode_api_min = IWL6000_UCODE_API_MIN,
        .sku = IWL_SKU_G,
-       .ops = &iwl6000_ops,
-       .eeprom_size = OTP_LOW_IMAGE_SIZE,
+       .valid_tx_ant = ANT_BC,
+       .valid_rx_ant = ANT_BC,
        .eeprom_ver = EEPROM_6000_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION,
-       .num_of_queues = IWLAGN_NUM_QUEUES,
-       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+       .ops = &iwl6000_ops,
        .mod_params = &iwlagn_mod_params,
-       .valid_tx_ant = ANT_BC,
-       .valid_rx_ant = ANT_BC,
-       .pll_cfg_val = 0,
-       .set_l0s = true,
-       .use_bsm = false,
+       .base_params = &iwl6000_base_params,
        .pa_type = IWL_PA_INTERNAL,
-       .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
-       .shadow_ram_support = true,
-       .led_compensation = 51,
-       .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
-       .supports_idle = true,
-       .adv_thermal_throttle = true,
-       .support_ct_kill_exit = true,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
-       .chain_noise_scale = 1000,
-       .monitor_recover_period = IWL_DEF_MONITORING_PERIOD,
-       .max_event_log_size = 1024,
-       .ucode_tracing = true,
-       .sensitivity_calib_by_driver = true,
-       .chain_noise_calib_by_driver = true,
 };
 
 struct iwl_cfg iwl6050_2agn_cfg = {
@@ -909,35 +754,14 @@ struct iwl_cfg iwl6050_2agn_cfg = {
        .ucode_api_max = IWL6050_UCODE_API_MAX,
        .ucode_api_min = IWL6050_UCODE_API_MIN,
        .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
+       .valid_tx_ant = ANT_AB,
+       .valid_rx_ant = ANT_AB,
        .ops = &iwl6000_ops,
-       .eeprom_size = OTP_LOW_IMAGE_SIZE,
        .eeprom_ver = EEPROM_6050_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_6050_TX_POWER_VERSION,
-       .num_of_queues = IWLAGN_NUM_QUEUES,
-       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
        .mod_params = &iwlagn_mod_params,
-       .valid_tx_ant = ANT_AB,
-       .valid_rx_ant = ANT_AB,
-       .pll_cfg_val = 0,
-       .set_l0s = true,
-       .use_bsm = false,
-       .pa_type = IWL_PA_SYSTEM,
-       .max_ll_items = OTP_MAX_LL_ITEMS_6x50,
-       .shadow_ram_support = true,
-       .ht_greenfield_support = true,
-       .led_compensation = 51,
-       .use_rts_for_aggregation = true, /* use rts/cts protection */
-       .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
-       .supports_idle = true,
-       .adv_thermal_throttle = true,
-       .support_ct_kill_exit = true,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
-       .chain_noise_scale = 1500,
-       .monitor_recover_period = IWL_DEF_MONITORING_PERIOD,
-       .max_event_log_size = 1024,
-       .ucode_tracing = true,
-       .sensitivity_calib_by_driver = true,
-       .chain_noise_calib_by_driver = true,
+       .base_params = &iwl6050_base_params,
+       .ht_params = &iwl6000_ht_params,
        .need_dc_calib = true,
 };
 
@@ -947,35 +771,14 @@ struct iwl_cfg iwl6050g2_bgn_cfg = {
        .ucode_api_max = IWL6050_UCODE_API_MAX,
        .ucode_api_min = IWL6050_UCODE_API_MIN,
        .sku = IWL_SKU_G|IWL_SKU_N,
-       .ops = &iwl6000_ops,
-       .eeprom_size = OTP_LOW_IMAGE_SIZE,
+       .valid_tx_ant = ANT_A,
+       .valid_rx_ant = ANT_AB,
        .eeprom_ver = EEPROM_6050G2_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_6050G2_TX_POWER_VERSION,
-       .num_of_queues = IWLAGN_NUM_QUEUES,
-       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+       .ops = &iwl6050g2_ops,
        .mod_params = &iwlagn_mod_params,
-       .valid_tx_ant = ANT_A,
-       .valid_rx_ant = ANT_AB,
-       .pll_cfg_val = 0,
-       .set_l0s = true,
-       .use_bsm = false,
-       .pa_type = IWL_PA_SYSTEM,
-       .max_ll_items = OTP_MAX_LL_ITEMS_6x50,
-       .shadow_ram_support = true,
-       .ht_greenfield_support = true,
-       .led_compensation = 51,
-       .use_rts_for_aggregation = true, /* use rts/cts protection */
-       .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
-       .supports_idle = true,
-       .adv_thermal_throttle = true,
-       .support_ct_kill_exit = true,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
-       .chain_noise_scale = 1500,
-       .monitor_recover_period = IWL_DEF_MONITORING_PERIOD,
-       .max_event_log_size = 1024,
-       .ucode_tracing = true,
-       .sensitivity_calib_by_driver = true,
-       .chain_noise_calib_by_driver = true,
+       .base_params = &iwl6050_base_params,
+       .ht_params = &iwl6000_ht_params,
        .need_dc_calib = true,
 };
 
@@ -985,33 +788,13 @@ struct iwl_cfg iwl6050_2abg_cfg = {
        .ucode_api_max = IWL6050_UCODE_API_MAX,
        .ucode_api_min = IWL6050_UCODE_API_MIN,
        .sku = IWL_SKU_A|IWL_SKU_G,
-       .ops = &iwl6000_ops,
-       .eeprom_size = OTP_LOW_IMAGE_SIZE,
+       .valid_tx_ant = ANT_AB,
+       .valid_rx_ant = ANT_AB,
        .eeprom_ver = EEPROM_6050_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_6050_TX_POWER_VERSION,
-       .num_of_queues = IWLAGN_NUM_QUEUES,
-       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+       .ops = &iwl6050_ops,
        .mod_params = &iwlagn_mod_params,
-       .valid_tx_ant = ANT_AB,
-       .valid_rx_ant = ANT_AB,
-       .pll_cfg_val = 0,
-       .set_l0s = true,
-       .use_bsm = false,
-       .pa_type = IWL_PA_SYSTEM,
-       .max_ll_items = OTP_MAX_LL_ITEMS_6x50,
-       .shadow_ram_support = true,
-       .led_compensation = 51,
-       .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
-       .supports_idle = true,
-       .adv_thermal_throttle = true,
-       .support_ct_kill_exit = true,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
-       .chain_noise_scale = 1500,
-       .monitor_recover_period = IWL_DEF_MONITORING_PERIOD,
-       .max_event_log_size = 1024,
-       .ucode_tracing = true,
-       .sensitivity_calib_by_driver = true,
-       .chain_noise_calib_by_driver = true,
+       .base_params = &iwl6050_base_params,
        .need_dc_calib = true,
 };
 
@@ -1021,38 +804,58 @@ struct iwl_cfg iwl6000_3agn_cfg = {
        .ucode_api_max = IWL6000_UCODE_API_MAX,
        .ucode_api_min = IWL6000_UCODE_API_MIN,
        .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
-       .ops = &iwl6000_ops,
-       .eeprom_size = OTP_LOW_IMAGE_SIZE,
+       .valid_tx_ant = ANT_ABC,
+       .valid_rx_ant = ANT_ABC,
        .eeprom_ver = EEPROM_6000_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION,
-       .num_of_queues = IWLAGN_NUM_QUEUES,
-       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+       .ops = &iwl6000_ops,
        .mod_params = &iwlagn_mod_params,
-       .valid_tx_ant = ANT_ABC,
-       .valid_rx_ant = ANT_ABC,
-       .pll_cfg_val = 0,
-       .set_l0s = true,
-       .use_bsm = false,
-       .pa_type = IWL_PA_SYSTEM,
-       .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
-       .shadow_ram_support = true,
-       .ht_greenfield_support = true,
-       .led_compensation = 51,
-       .use_rts_for_aggregation = true, /* use rts/cts protection */
-       .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
-       .supports_idle = true,
-       .adv_thermal_throttle = true,
-       .support_ct_kill_exit = true,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
-       .chain_noise_scale = 1000,
-       .monitor_recover_period = IWL_DEF_MONITORING_PERIOD,
-       .max_event_log_size = 1024,
-       .ucode_tracing = true,
-       .sensitivity_calib_by_driver = true,
-       .chain_noise_calib_by_driver = true,
+       .base_params = &iwl6000_base_params,
+       .ht_params = &iwl6000_ht_params,
+       .need_dc_calib = true,
+};
+
+struct iwl_cfg iwl130_bgn_cfg = {
+       .name = "Intel(R) 130 Series 1x1 BGN",
+       .fw_name_pre = IWL6000G2B_FW_PRE,
+       .ucode_api_max = IWL130_UCODE_API_MAX,
+       .ucode_api_min = IWL130_UCODE_API_MIN,
+       .sku = IWL_SKU_G|IWL_SKU_N,
+       .valid_tx_ant = ANT_A,
+       .valid_rx_ant = ANT_A,
+       .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
+       .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
+       .ops = &iwl6000g2b_ops,
+       .mod_params = &iwlagn_mod_params,
+       .base_params = &iwl6000_base_params,
+       .bt_params = &iwl6000_bt_params,
+       .ht_params = &iwl6000_ht_params,
+       .need_dc_calib = true,
+       /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
+       .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A,
+};
+
+struct iwl_cfg iwl130_bg_cfg = {
+       .name = "Intel(R) 130 Series 1x2 BG",
+       .fw_name_pre = IWL6000G2B_FW_PRE,
+       .ucode_api_max = IWL130_UCODE_API_MAX,
+       .ucode_api_min = IWL130_UCODE_API_MIN,
+       .sku = IWL_SKU_G,
+       .valid_tx_ant = ANT_A,
+       .valid_rx_ant = ANT_A,
+       .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
+       .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
+       .ops = &iwl6000g2b_ops,
+       .mod_params = &iwlagn_mod_params,
+       .base_params = &iwl6000_base_params,
+       .bt_params = &iwl6000_bt_params,
+       .need_dc_calib = true,
+       /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
+       .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A,
 };
 
 MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX));
 MODULE_FIRMWARE(IWL6050_MODULE_FIRMWARE(IWL6050_UCODE_API_MAX));
 MODULE_FIRMWARE(IWL6000G2A_MODULE_FIRMWARE(IWL6000G2_UCODE_API_MAX));
 MODULE_FIRMWARE(IWL6000G2B_MODULE_FIRMWARE(IWL6000G2_UCODE_API_MAX));
+MODULE_FIRMWARE(IWL130_MODULE_FIRMWARE(IWL130_UCODE_API_MAX));
index 84ad62958535ed455ac4d32e2b5501efb9e5d6da..4c5ab783737f8623cb239da1e1c3f37a7680ca4c 100644 (file)
@@ -631,7 +631,8 @@ void iwl_sensitivity_calibration(struct iwl_priv *priv, void *resp)
        }
 
        spin_lock_irqsave(&priv->lock, flags);
-       if (priv->cfg->bt_statistics) {
+       if (priv->cfg->bt_params &&
+           priv->cfg->bt_params->bt_statistics) {
                rx_info = &(((struct iwl_bt_notif_statistics *)resp)->
                              rx.general.common);
                ofdm = &(((struct iwl_bt_notif_statistics *)resp)->rx.ofdm);
@@ -786,7 +787,8 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp)
        }
 
        spin_lock_irqsave(&priv->lock, flags);
-       if (priv->cfg->bt_statistics) {
+       if (priv->cfg->bt_params &&
+           priv->cfg->bt_params->bt_statistics) {
                rx_info = &(((struct iwl_bt_notif_statistics *)stat_resp)->
                              rx.general.common);
        } else {
@@ -801,7 +803,8 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp)
 
        rxon_band24 = !!(ctx->staging.flags & RXON_FLG_BAND_24G_MSK);
        rxon_chnum = le16_to_cpu(ctx->staging.channel);
-       if (priv->cfg->bt_statistics) {
+       if (priv->cfg->bt_params &&
+           priv->cfg->bt_params->bt_statistics) {
                stat_band24 = !!(((struct iwl_bt_notif_statistics *)
                                 stat_resp)->flag &
                                 STATISTICS_REPLY_FLG_BAND_24G_MSK);
@@ -861,16 +864,17 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp)
        /* If this is the "chain_noise_num_beacons", determine:
         * 1)  Disconnected antennas (using signal strengths)
         * 2)  Differential gain (using silence noise) to balance receivers */
-       if (data->beacon_count != priv->cfg->chain_noise_num_beacons)
+       if (data->beacon_count !=
+               priv->cfg->base_params->chain_noise_num_beacons)
                return;
 
        /* Analyze signal for disconnected antenna */
-       average_sig[0] =
-               (data->chain_signal_a) / priv->cfg->chain_noise_num_beacons;
-       average_sig[1] =
-               (data->chain_signal_b) / priv->cfg->chain_noise_num_beacons;
-       average_sig[2] =
-               (data->chain_signal_c) / priv->cfg->chain_noise_num_beacons;
+       average_sig[0] = data->chain_signal_a /
+                        priv->cfg->base_params->chain_noise_num_beacons;
+       average_sig[1] = data->chain_signal_b /
+                        priv->cfg->base_params->chain_noise_num_beacons;
+       average_sig[2] = data->chain_signal_c /
+                        priv->cfg->base_params->chain_noise_num_beacons;
 
        if (average_sig[0] >= average_sig[1]) {
                max_average_sig = average_sig[0];
@@ -920,7 +924,9 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp)
         * To be safe, simply mask out any chains that we know
         * are not on the device.
         */
-       if (priv->cfg->advanced_bt_coexist && priv->bt_full_concurrent) {
+       if (priv->cfg->bt_params &&
+           priv->cfg->bt_params->advanced_bt_coexist &&
+           priv->bt_full_concurrent) {
                /* operated as 1x1 in full concurrency mode */
                active_chains &= first_antenna(priv->hw_params.valid_rx_ant);
        } else
@@ -967,12 +973,12 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp)
                        active_chains);
 
        /* Analyze noise for rx balance */
-       average_noise[0] =
-               ((data->chain_noise_a) / priv->cfg->chain_noise_num_beacons);
-       average_noise[1] =
-               ((data->chain_noise_b) / priv->cfg->chain_noise_num_beacons);
-       average_noise[2] =
-               ((data->chain_noise_c) / priv->cfg->chain_noise_num_beacons);
+       average_noise[0] = data->chain_noise_a /
+                          priv->cfg->base_params->chain_noise_num_beacons;
+       average_noise[1] = data->chain_noise_b /
+                          priv->cfg->base_params->chain_noise_num_beacons;
+       average_noise[2] = data->chain_noise_c /
+                          priv->cfg->base_params->chain_noise_num_beacons;
 
        for (i = 0; i < NUM_RX_CHAINS; i++) {
                if (!(data->disconn_array[i]) &&
index 5391b4627397741d90bcd8b31ce3e5aa676ebb3b..a358d4334a1a356f6cecbe2407359c8829792350 100644 (file)
@@ -39,7 +39,8 @@ static int iwl_statistics_flag(struct iwl_priv *priv, char *buf, int bufsz)
        int p = 0;
        u32 flag;
 
-       if (priv->cfg->bt_statistics)
+       if (priv->cfg->bt_params &&
+           priv->cfg->bt_params->bt_statistics)
                flag = le32_to_cpu(priv->_agn.statistics_bt.flag);
        else
                flag = le32_to_cpu(priv->_agn.statistics.flag);
@@ -88,7 +89,8 @@ ssize_t iwl_ucode_rx_stats_read(struct file *file, char __user *user_buf,
         * the last statistics notification from uCode
         * might not reflect the current uCode activity
         */
-       if (priv->cfg->bt_statistics) {
+       if (priv->cfg->bt_params &&
+           priv->cfg->bt_params->bt_statistics) {
                ofdm = &priv->_agn.statistics_bt.rx.ofdm;
                cck = &priv->_agn.statistics_bt.rx.cck;
                general = &priv->_agn.statistics_bt.rx.general.common;
@@ -534,7 +536,8 @@ ssize_t iwl_ucode_tx_stats_read(struct file *file,
          * the last statistics notification from uCode
          * might not reflect the current uCode activity
          */
-       if (priv->cfg->bt_statistics) {
+       if (priv->cfg->bt_params &&
+           priv->cfg->bt_params->bt_statistics) {
                tx = &priv->_agn.statistics_bt.tx;
                accum_tx = &priv->_agn.accum_statistics_bt.tx;
                delta_tx = &priv->_agn.delta_statistics_bt.tx;
@@ -734,7 +737,8 @@ ssize_t iwl_ucode_general_stats_read(struct file *file, char __user *user_buf,
          * the last statistics notification from uCode
          * might not reflect the current uCode activity
          */
-       if (priv->cfg->bt_statistics) {
+       if (priv->cfg->bt_params &&
+           priv->cfg->bt_params->bt_statistics) {
                general = &priv->_agn.statistics_bt.general.common;
                dbg = &priv->_agn.statistics_bt.general.common.dbg;
                div = &priv->_agn.statistics_bt.general.common.div;
index d86902b83630d3163f45bb07b224634fa14d2817..9ca6c91eaae61384a9bc9edb0ea46dc03f0c7b4e 100644 (file)
@@ -137,7 +137,7 @@ static void iwlagn_gain_computation(struct iwl_priv *priv,
                        continue;
                }
 
-               delta_g = (priv->cfg->chain_noise_scale *
+               delta_g = (priv->cfg->base_params->chain_noise_scale *
                        ((s32)average_noise[default_chain] -
                        (s32)average_noise[i])) / 1500;
 
@@ -222,7 +222,8 @@ static void iwlagn_tx_cmd_protection(struct iwl_priv *priv,
                return;
        }
 
-       if (priv->cfg->use_rts_for_aggregation &&
+       if (priv->cfg->ht_params &&
+           priv->cfg->ht_params->use_rts_for_aggregation &&
            info->flags & IEEE80211_TX_CTL_AMPDU) {
                *tx_flags |= TX_CMD_FLG_PROT_REQUIRE_MSK;
                return;
index c92b2c0cbd9130ee1ba35a1ac160dfd5f0baa0ca..a5dbfea1bfade7da2f53e04c3f9c2c36a681a808 100644 (file)
@@ -59,7 +59,7 @@ void iwl_free_isr_ict(struct iwl_priv *priv)
 int iwl_alloc_isr_ict(struct iwl_priv *priv)
 {
 
-       if (priv->cfg->use_isr_legacy)
+       if (priv->cfg->base_params->use_isr_legacy)
                return 0;
        /* allocate shrared data table */
        priv->_agn.ict_tbl_vir =
index 299fd9d596041ed2bc0758393148b1ddf7a2efea..f5445d575fec64f785f0506ee15675e77dce877d 100644 (file)
@@ -40,7 +40,7 @@
 #include "iwl-agn.h"
 #include "iwl-sta.h"
 
-static inline u32 iwlagn_get_scd_ssn(struct iwl5000_tx_resp *tx_resp)
+static inline u32 iwlagn_get_scd_ssn(struct iwlagn_tx_resp *tx_resp)
 {
        return le32_to_cpup((__le32 *)&tx_resp->status +
                            tx_resp->frame_count) & MAX_SN;
@@ -172,7 +172,7 @@ static void iwlagn_count_agg_tx_err_status(struct iwl_priv *priv, u16 status)
 
 static void iwlagn_set_tx_status(struct iwl_priv *priv,
                                 struct ieee80211_tx_info *info,
-                                struct iwl5000_tx_resp *tx_resp,
+                                struct iwlagn_tx_resp *tx_resp,
                                 int txq_id, bool is_agg)
 {
        u16  status = le16_to_cpu(tx_resp->status.status);
@@ -223,7 +223,7 @@ const char *iwl_get_agg_tx_fail_reason(u16 status)
 
 static int iwlagn_tx_status_reply_tx(struct iwl_priv *priv,
                                      struct iwl_ht_agg *agg,
-                                     struct iwl5000_tx_resp *tx_resp,
+                                     struct iwlagn_tx_resp *tx_resp,
                                      int txq_id, u16 start_idx)
 {
        u16 status;
@@ -390,7 +390,7 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv,
        int index = SEQ_TO_INDEX(sequence);
        struct iwl_tx_queue *txq = &priv->txq[txq_id];
        struct ieee80211_tx_info *info;
-       struct iwl5000_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
+       struct iwlagn_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
        u32  status = le16_to_cpu(tx_resp->status.status);
        int tid;
        int sta_id;
@@ -408,8 +408,10 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv,
        info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb);
        memset(&info->status, 0, sizeof(info->status));
 
-       tid = (tx_resp->ra_tid & IWL50_TX_RES_TID_MSK) >> IWL50_TX_RES_TID_POS;
-       sta_id = (tx_resp->ra_tid & IWL50_TX_RES_RA_MSK) >> IWL50_TX_RES_RA_POS;
+       tid = (tx_resp->ra_tid & IWLAGN_TX_RES_TID_MSK) >>
+               IWLAGN_TX_RES_TID_POS;
+       sta_id = (tx_resp->ra_tid & IWLAGN_TX_RES_RA_MSK) >>
+               IWLAGN_TX_RES_RA_POS;
 
        spin_lock_irqsave(&priv->sta_lock, flags);
        if (txq->sched_retry) {
@@ -422,7 +424,8 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv,
                 * notification again.
                 */
                if (tx_resp->bt_kill_count && tx_resp->frame_count == 1 &&
-                   priv->cfg->advanced_bt_coexist) {
+                   priv->cfg->bt_params &&
+                   priv->cfg->bt_params->advanced_bt_coexist) {
                        IWL_WARN(priv, "receive reply tx with bt_kill\n");
                }
                iwlagn_tx_status_reply_tx(priv, agg, tx_resp, txq_id, index);
@@ -490,7 +493,7 @@ int iwlagn_hw_valid_rtc_data_addr(u32 addr)
 
 int iwlagn_send_tx_power(struct iwl_priv *priv)
 {
-       struct iwl5000_tx_power_dbm_cmd tx_power_cmd;
+       struct iwlagn_tx_power_dbm_cmd tx_power_cmd;
        u8 tx_ant_cfg_cmd;
 
        /* half dBm need to multiply */
@@ -511,8 +514,8 @@ int iwlagn_send_tx_power(struct iwl_priv *priv)
                 */
                tx_power_cmd.global_lmt = priv->tx_power_lmt_in_half_dbm;
        }
-       tx_power_cmd.flags = IWL50_TX_POWER_NO_CLOSED;
-       tx_power_cmd.srv_chan_lmt = IWL50_TX_POWER_AUTO;
+       tx_power_cmd.flags = IWLAGN_TX_POWER_NO_CLOSED;
+       tx_power_cmd.srv_chan_lmt = IWLAGN_TX_POWER_AUTO;
 
        if (IWL_UCODE_API(priv->ucode_ver) == 1)
                tx_ant_cfg_cmd = REPLY_TX_POWER_DBM_CMD_V1;
@@ -589,7 +592,7 @@ const u8 *iwlagn_eeprom_query_addr(const struct iwl_priv *priv,
                                           size_t offset)
 {
        u32 address = eeprom_indirect_address(priv, offset);
-       BUG_ON(address >= priv->cfg->eeprom_size);
+       BUG_ON(address >= priv->cfg->base_params->eeprom_size);
        return &priv->eeprom[address];
 }
 
@@ -637,7 +640,7 @@ int iwlagn_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
        const u32 rfdnlog = RX_QUEUE_SIZE_LOG; /* 256 RBDs */
        u32 rb_timeout = 0; /* FIXME: RX_RB_TIMEOUT for all devices? */
 
-       if (!priv->cfg->use_isr_legacy)
+       if (!priv->cfg->base_params->use_isr_legacy)
                rb_timeout = RX_RB_TIMEOUT;
 
        if (priv->cfg->mod_params->amsdu_size_8K)
@@ -1424,7 +1427,8 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
                 * Internal scans are passive, so we can indiscriminately set
                 * the BT ignore flag on 2.4 GHz since it applies to TX only.
                 */
-               if (priv->cfg->advanced_bt_coexist)
+               if (priv->cfg->bt_params &&
+                   priv->cfg->bt_params->advanced_bt_coexist)
                        scan->tx_cmd.tx_flags |= TX_CMD_FLG_IGNORE_BT;
                scan->good_CRC_th = IWL_GOOD_CRC_TH_DISABLED;
                break;
@@ -1463,10 +1467,12 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
        if (priv->cfg->scan_tx_antennas[band])
                scan_tx_antennas = priv->cfg->scan_tx_antennas[band];
 
-       if (priv->cfg->advanced_bt_coexist && priv->bt_full_concurrent) {
+       if (priv->cfg->bt_params &&
+           priv->cfg->bt_params->advanced_bt_coexist &&
+           priv->bt_full_concurrent) {
                /* operated as 1x1 in full concurrency mode */
-               scan_tx_antennas =
-                       first_antenna(priv->cfg->scan_tx_antennas[band]);
+               scan_tx_antennas = first_antenna(
+                       priv->cfg->scan_tx_antennas[band]);
        }
 
        priv->scan_tx_ant[band] = iwl_toggle_tx_ant(priv, priv->scan_tx_ant[band],
@@ -1487,7 +1493,9 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
 
                rx_ant = first_antenna(active_chains);
        }
-       if (priv->cfg->advanced_bt_coexist && priv->bt_full_concurrent) {
+       if (priv->cfg->bt_params &&
+           priv->cfg->bt_params->advanced_bt_coexist &&
+           priv->bt_full_concurrent) {
                /* operated as 1x1 in full concurrency mode */
                rx_ant = first_antenna(rx_ant);
        }
@@ -1777,7 +1785,10 @@ void iwlagn_send_advance_bt_config(struct iwl_priv *priv)
        BUILD_BUG_ON(sizeof(iwlagn_def_3w_lookup) !=
                        sizeof(bt_cmd.bt3_lookup_table));
 
-       bt_cmd.prio_boost = priv->cfg->bt_prio_boost;
+       if (priv->cfg->bt_params)
+               bt_cmd.prio_boost = priv->cfg->bt_params->bt_prio_boost;
+       else
+               bt_cmd.prio_boost = 0;
        bt_cmd.kill_ack_mask = priv->kill_ack_mask;
        bt_cmd.kill_cts_mask = priv->kill_cts_mask;
        bt_cmd.valid = priv->bt_valid;
index 57629fba3a7ddbb17fd013ac7623b283a6d0d57a..f865685fd5f547b53dd2acc0103445839c3f4a56 100644 (file)
@@ -2939,11 +2939,14 @@ static void rs_fill_link_cmd(struct iwl_priv *priv,
         * overwrite if needed, pass aggregation time limit
         * to uCode in uSec
         */
-       if (priv && priv->cfg->agg_time_limit &&
-           priv->cfg->agg_time_limit >= LINK_QUAL_AGG_TIME_LIMIT_MIN &&
-           priv->cfg->agg_time_limit <= LINK_QUAL_AGG_TIME_LIMIT_MAX)
+       if (priv && priv->cfg->bt_params &&
+           priv->cfg->bt_params->agg_time_limit &&
+           priv->cfg->bt_params->agg_time_limit >=
+               LINK_QUAL_AGG_TIME_LIMIT_MIN &&
+           priv->cfg->bt_params->agg_time_limit <=
+                LINK_QUAL_AGG_TIME_LIMIT_MAX)
                lq_cmd->agg_params.agg_time_limit =
-                       cpu_to_le16(priv->cfg->agg_time_limit);
+                       cpu_to_le16(priv->cfg->bt_params->agg_time_limit);
 }
 
 static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
index 9490eced1198ad178f6191389156565ceca9cbd1..1e08eb455474877824e4148dba3fe25980f68c66 100644 (file)
@@ -73,7 +73,8 @@ static void iwl_rx_calc_noise(struct iwl_priv *priv)
        int bcn_silence_a, bcn_silence_b, bcn_silence_c;
        int last_rx_noise;
 
-       if (priv->cfg->bt_statistics)
+       if (priv->cfg->bt_params &&
+           priv->cfg->bt_params->bt_statistics)
                rx_info = &(priv->_agn.statistics_bt.rx.general.common);
        else
                rx_info = &(priv->_agn.statistics.rx.general);
@@ -124,7 +125,8 @@ static void iwl_accumulative_statistics(struct iwl_priv *priv,
        struct statistics_general_common *general, *accum_general;
        struct statistics_tx *tx, *accum_tx;
 
-       if (priv->cfg->bt_statistics) {
+       if (priv->cfg->bt_params &&
+           priv->cfg->bt_params->bt_statistics) {
                prev_stats = (__le32 *)&priv->_agn.statistics_bt;
                accum_stats = (u32 *)&priv->_agn.accum_statistics_bt;
                size = sizeof(struct iwl_bt_notif_statistics);
@@ -183,7 +185,7 @@ bool iwl_good_plcp_health(struct iwl_priv *priv,
        unsigned int plcp_msec;
        unsigned long plcp_received_jiffies;
 
-       if (priv->cfg->plcp_delta_threshold ==
+       if (priv->cfg->base_params->plcp_delta_threshold ==
            IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE) {
                IWL_DEBUG_RADIO(priv, "plcp_err check disabled\n");
                return rc;
@@ -205,7 +207,8 @@ bool iwl_good_plcp_health(struct iwl_priv *priv,
                struct statistics_rx_phy *ofdm;
                struct statistics_rx_ht_phy *ofdm_ht;
 
-               if (priv->cfg->bt_statistics) {
+               if (priv->cfg->bt_params &&
+                   priv->cfg->bt_params->bt_statistics) {
                        ofdm = &pkt->u.stats_bt.rx.ofdm;
                        ofdm_ht = &pkt->u.stats_bt.rx.ofdm_ht;
                        combined_plcp_delta =
@@ -229,7 +232,7 @@ bool iwl_good_plcp_health(struct iwl_priv *priv,
 
                if ((combined_plcp_delta > 0) &&
                    ((combined_plcp_delta * 100) / plcp_msec) >
-                       priv->cfg->plcp_delta_threshold) {
+                       priv->cfg->base_params->plcp_delta_threshold) {
                        /*
                         * if plcp_err exceed the threshold,
                         * the following data is printed in csv format:
@@ -242,13 +245,13 @@ bool iwl_good_plcp_health(struct iwl_priv *priv,
                         *    plcp_msec
                         */
                        IWL_DEBUG_RADIO(priv, "plcp_err exceeded %u, "
-                                   "%u, %u, %u, %u, %d, %u mSecs\n",
-                                   priv->cfg->plcp_delta_threshold,
-                                   le32_to_cpu(ofdm->plcp_err),
-                                   le32_to_cpu(ofdm->plcp_err),
-                                   le32_to_cpu(ofdm_ht->plcp_err),
-                                   le32_to_cpu(ofdm_ht->plcp_err),
-                                   combined_plcp_delta, plcp_msec);
+                               "%u, %u, %u, %u, %d, %u mSecs\n",
+                               priv->cfg->base_params->plcp_delta_threshold,
+                               le32_to_cpu(ofdm->plcp_err),
+                               le32_to_cpu(ofdm->plcp_err),
+                               le32_to_cpu(ofdm_ht->plcp_err),
+                               le32_to_cpu(ofdm_ht->plcp_err),
+                               combined_plcp_delta, plcp_msec);
 
                        rc = false;
                }
@@ -262,7 +265,8 @@ void iwl_rx_statistics(struct iwl_priv *priv,
        int change;
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
 
-       if (priv->cfg->bt_statistics) {
+       if (priv->cfg->bt_params &&
+           priv->cfg->bt_params->bt_statistics) {
                IWL_DEBUG_RX(priv,
                             "Statistics notification received (%d vs %d).\n",
                             (int)sizeof(struct iwl_bt_notif_statistics),
@@ -300,7 +304,8 @@ void iwl_rx_statistics(struct iwl_priv *priv,
 
        iwl_recover_from_statistics(priv, pkt);
 
-       if (priv->cfg->bt_statistics)
+       if (priv->cfg->bt_params &&
+           priv->cfg->bt_params->bt_statistics)
                memcpy(&priv->_agn.statistics_bt, &pkt->u.stats_bt,
                        sizeof(priv->_agn.statistics_bt));
        else
index 07b2c6cadf5103a21b26b221b4e147085cbe64be..0c6c4d96970673bbf280cf4705d0802dd7637768 100644 (file)
@@ -114,7 +114,7 @@ static bool iwl_within_ct_kill_margin(struct iwl_priv *priv)
        s32 temp = priv->temperature; /* degrees CELSIUS except specified */
        bool within_margin = false;
 
-       if (priv->cfg->temperature_kelvin)
+       if (priv->cfg->base_params->temperature_kelvin)
                temp = KELVIN_TO_CELSIUS(priv->temperature);
 
        if (!priv->thermal_throttle.advanced_tt)
@@ -591,7 +591,7 @@ static void iwl_bg_tt_work(struct work_struct *work)
        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
-       if (priv->cfg->temperature_kelvin)
+       if (priv->cfg->base_params->temperature_kelvin)
                temp = KELVIN_TO_CELSIUS(priv->temperature);
 
        if (!priv->thermal_throttle.advanced_tt)
@@ -640,7 +640,7 @@ void iwl_tt_initialize(struct iwl_priv *priv)
        INIT_WORK(&priv->ct_enter, iwl_bg_ct_enter);
        INIT_WORK(&priv->ct_exit, iwl_bg_ct_exit);
 
-       if (priv->cfg->adv_thermal_throttle) {
+       if (priv->cfg->base_params->adv_thermal_throttle) {
                IWL_DEBUG_POWER(priv, "Advanced Thermal Throttling\n");
                tt->restriction = kzalloc(sizeof(struct iwl_tt_restriction) *
                                         IWL_TI_STATE_MAX, GFP_KERNEL);
index 5950184d98606a4f997bc5b027b5ddd21b6db7f8..77753b72f23680b36677fad7fc271d2e0cd52017 100644 (file)
@@ -224,13 +224,13 @@ int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id,
        int ret;
 
        if ((IWLAGN_FIRST_AMPDU_QUEUE > txq_id) ||
-           (IWLAGN_FIRST_AMPDU_QUEUE + priv->cfg->num_of_ampdu_queues
-            <= txq_id)) {
+           (IWLAGN_FIRST_AMPDU_QUEUE +
+               priv->cfg->base_params->num_of_ampdu_queues <= txq_id)) {
                IWL_WARN(priv,
                        "queue number out of range: %d, must be %d to %d\n",
                        txq_id, IWLAGN_FIRST_AMPDU_QUEUE,
                        IWLAGN_FIRST_AMPDU_QUEUE +
-                       priv->cfg->num_of_ampdu_queues - 1);
+                       priv->cfg->base_params->num_of_ampdu_queues - 1);
                return -EINVAL;
        }
 
@@ -286,13 +286,13 @@ int iwlagn_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
                           u16 ssn_idx, u8 tx_fifo)
 {
        if ((IWLAGN_FIRST_AMPDU_QUEUE > txq_id) ||
-           (IWLAGN_FIRST_AMPDU_QUEUE + priv->cfg->num_of_ampdu_queues
-            <= txq_id)) {
+           (IWLAGN_FIRST_AMPDU_QUEUE +
+               priv->cfg->base_params->num_of_ampdu_queues <= txq_id)) {
                IWL_ERR(priv,
                        "queue number out of range: %d, must be %d to %d\n",
                        txq_id, IWLAGN_FIRST_AMPDU_QUEUE,
                        IWLAGN_FIRST_AMPDU_QUEUE +
-                       priv->cfg->num_of_ampdu_queues - 1);
+                       priv->cfg->base_params->num_of_ampdu_queues - 1);
                return -EINVAL;
        }
 
@@ -350,7 +350,8 @@ static void iwlagn_tx_cmd_build_basic(struct iwl_priv *priv,
        if (ieee80211_is_back_req(fc))
                tx_flags |= TX_CMD_FLG_ACK_MSK | TX_CMD_FLG_IMM_BA_RSP_MASK;
        else if (info->band == IEEE80211_BAND_2GHZ &&
-                priv->cfg->advanced_bt_coexist &&
+                priv->cfg->bt_params &&
+                priv->cfg->bt_params->advanced_bt_coexist &&
                 (ieee80211_is_auth(fc) || ieee80211_is_assoc_req(fc) ||
                 ieee80211_is_reassoc_req(fc) ||
                 skb->protocol == cpu_to_be16(ETH_P_PAE)))
@@ -444,7 +445,9 @@ static void iwlagn_tx_cmd_build_rate(struct iwl_priv *priv,
                rate_flags |= RATE_MCS_CCK_MSK;
 
        /* Set up antennas */
-        if (priv->cfg->advanced_bt_coexist && priv->bt_full_concurrent) {
+        if (priv->cfg->bt_params &&
+            priv->cfg->bt_params->advanced_bt_coexist &&
+            priv->bt_full_concurrent) {
                /* operated as 1x1 in full concurrency mode */
                priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant,
                                first_antenna(priv->hw_params.valid_tx_ant));
index 8bfb0495a76b2e17b8a1a4a23aeac05230144f16..e1dd76267dca2fdcc08d4c40ace5118d2e0310e6 100644 (file)
@@ -307,7 +307,8 @@ void iwlagn_init_alive_start(struct iwl_priv *priv)
                goto restart;
        }
 
-       if (priv->cfg->advanced_bt_coexist) {
+       if (priv->cfg->bt_params &&
+           priv->cfg->bt_params->advanced_bt_coexist) {
                /*
                 * Tell uCode we are ready to perform calibration
                 * need to perform this before any calibration
@@ -330,7 +331,7 @@ static int iwlagn_send_wimax_coex(struct iwl_priv *priv)
 {
        struct iwl_wimax_coex_cmd coex_cmd;
 
-       if (priv->cfg->support_wimax_coexist) {
+       if (priv->cfg->base_params->support_wimax_coexist) {
                /* UnMask wake up src at associated sleep */
                coex_cmd.flags = COEX_FLAGS_ASSOC_WA_UNMASK_MSK;
 
index 646864a26eaf5277e6c0d0909c8079d8c23e14cb..a6dce616ee3c8ecd523ad241a23dac0e64430611 100644 (file)
@@ -2256,13 +2256,15 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
        if (pieces.init_evtlog_size)
                priv->_agn.init_evtlog_size = (pieces.init_evtlog_size - 16)/12;
        else
-               priv->_agn.init_evtlog_size = priv->cfg->max_event_log_size;
+               priv->_agn.init_evtlog_size =
+                       priv->cfg->base_params->max_event_log_size;
        priv->_agn.init_errlog_ptr = pieces.init_errlog_ptr;
        priv->_agn.inst_evtlog_ptr = pieces.inst_evtlog_ptr;
        if (pieces.inst_evtlog_size)
                priv->_agn.inst_evtlog_size = (pieces.inst_evtlog_size - 16)/12;
        else
-               priv->_agn.inst_evtlog_size = priv->cfg->max_event_log_size;
+               priv->_agn.inst_evtlog_size =
+                       priv->cfg->base_params->max_event_log_size;
        priv->_agn.inst_errlog_ptr = pieces.inst_errlog_ptr;
 
        if (ucode_capa.pan) {
@@ -2732,7 +2734,7 @@ static void iwl_rf_kill_ct_config(struct iwl_priv *priv)
        spin_unlock_irqrestore(&priv->lock, flags);
        priv->thermal_throttle.ct_kill_toggle = false;
 
-       if (priv->cfg->support_ct_kill_exit) {
+       if (priv->cfg->base_params->support_ct_kill_exit) {
                adv_cmd.critical_temperature_enter =
                        cpu_to_le32(priv->hw_params.ct_kill_threshold);
                adv_cmd.critical_temperature_exit =
@@ -2765,6 +2767,23 @@ static void iwl_rf_kill_ct_config(struct iwl_priv *priv)
        }
 }
 
+static int iwlagn_send_calib_cfg_rt(struct iwl_priv *priv, u32 cfg)
+{
+       struct iwl_calib_cfg_cmd calib_cfg_cmd;
+       struct iwl_host_cmd cmd = {
+               .id = CALIBRATION_CFG_CMD,
+               .len = sizeof(struct iwl_calib_cfg_cmd),
+               .data = &calib_cfg_cmd,
+       };
+
+       memset(&calib_cfg_cmd, 0, sizeof(calib_cfg_cmd));
+       calib_cfg_cmd.ucd_calib_cfg.once.is_enable = IWL_CALIB_INIT_CFG_ALL;
+       calib_cfg_cmd.ucd_calib_cfg.once.start = cpu_to_le32(cfg);
+
+       return iwl_send_cmd(priv, &cmd);
+}
+
+
 /**
  * iwl_alive_start - called after REPLY_ALIVE notification received
  *                   from protocol/runtime uCode (initialization uCode's
@@ -2801,6 +2820,10 @@ static void iwl_alive_start(struct iwl_priv *priv)
                goto restart;
        }
 
+       if (priv->hw_params.calib_rt_cfg)
+               iwlagn_send_calib_cfg_rt(priv, priv->hw_params.calib_rt_cfg);
+
+
        /* After the ALIVE response, we can send host commands to the uCode */
        set_bit(STATUS_ALIVE, &priv->status);
 
@@ -2808,13 +2831,15 @@ static void iwl_alive_start(struct iwl_priv *priv)
                /* Enable timer to monitor the driver queues */
                mod_timer(&priv->monitor_recover,
                        jiffies +
-                       msecs_to_jiffies(priv->cfg->monitor_recover_period));
+                       msecs_to_jiffies(
+                         priv->cfg->base_params->monitor_recover_period));
        }
 
        if (iwl_is_rfkill(priv))
                return;
 
-       if (priv->cfg->advanced_bt_coexist) {
+       if (priv->cfg->bt_params &&
+           priv->cfg->bt_params->advanced_bt_coexist) {
                /* Configure Bluetooth device coexistence support */
                priv->bt_valid = IWLAGN_BT_ALL_VALID_MSK;
                priv->kill_ack_mask = IWLAGN_BT_KILL_ACK_MASK_DEFAULT;
@@ -2854,7 +2879,8 @@ static void iwl_alive_start(struct iwl_priv *priv)
                        priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
        }
 
-       if (!priv->cfg->advanced_bt_coexist) {
+       if (priv->cfg->bt_params &&
+           !priv->cfg->bt_params->advanced_bt_coexist) {
                /* Configure Bluetooth device coexistence support */
                priv->cfg->ops->hcmd->send_bt_config(priv);
        }
@@ -2907,7 +2933,11 @@ static void __iwl_down(struct iwl_priv *priv)
 
        /* reset BT coex data */
        priv->bt_status = 0;
-       priv->bt_traffic_load = priv->cfg->bt_init_traffic_load;
+       if (priv->cfg->bt_params)
+               priv->bt_traffic_load =
+                        priv->cfg->bt_params->bt_init_traffic_load;
+       else
+               priv->bt_traffic_load = 0;
        priv->bt_sco_active = false;
        priv->bt_full_concurrent = false;
        priv->bt_ci_compliance = 0;
@@ -3201,7 +3231,8 @@ static void iwl_bg_run_time_calib_work(struct work_struct *work)
        }
 
        if (priv->start_calib) {
-               if (priv->cfg->bt_statistics) {
+               if (priv->cfg->bt_params &&
+                   priv->cfg->bt_params->bt_statistics) {
                        iwl_chain_noise_calibration(priv,
                                        (void *)&priv->_agn.statistics_bt);
                        iwl_sensitivity_calibration(priv,
@@ -3400,7 +3431,7 @@ static int iwl_mac_setup_register(struct iwl_priv *priv,
                    IEEE80211_HW_NEED_DTIM_PERIOD |
                    IEEE80211_HW_SPECTRUM_MGMT;
 
-       if (!priv->cfg->broken_powersave)
+       if (!priv->cfg->base_params->broken_powersave)
                hw->flags |= IEEE80211_HW_SUPPORTS_PS |
                             IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
 
@@ -3725,7 +3756,8 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
                }
                if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                        ret = 0;
-               if (priv->cfg->use_rts_for_aggregation) {
+               if (priv->cfg->ht_params &&
+                   priv->cfg->ht_params->use_rts_for_aggregation) {
                        struct iwl_station_priv *sta_priv =
                                (void *) sta->drv_priv;
                        /*
@@ -3739,7 +3771,8 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
                }
                break;
        case IEEE80211_AMPDU_TX_OPERATIONAL:
-               if (priv->cfg->use_rts_for_aggregation) {
+               if (priv->cfg->ht_params &&
+                   priv->cfg->ht_params->use_rts_for_aggregation) {
                        struct iwl_station_priv *sta_priv =
                                (void *) sta->drv_priv;
 
@@ -4057,7 +4090,7 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
                        priv->cfg->ops->lib->recover_from_tx_stall;
        }
 
-       if (!priv->cfg->use_isr_legacy)
+       if (!priv->cfg->base_params->use_isr_legacy)
                tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
                        iwl_irq_tasklet, (unsigned long)priv);
        else
@@ -4142,7 +4175,8 @@ static int iwl_init_drv(struct iwl_priv *priv)
        iwl_init_scan_params(priv);
 
        /* init bt coex */
-       if (priv->cfg->advanced_bt_coexist) {
+       if (priv->cfg->bt_params &&
+           priv->cfg->bt_params->advanced_bt_coexist) {
                priv->kill_ack_mask = IWLAGN_BT_KILL_ACK_MASK_DEFAULT;
                priv->kill_cts_mask = IWLAGN_BT_KILL_CTS_MASK_DEFAULT;
                priv->bt_valid = IWLAGN_BT_ALL_VALID_MSK;
@@ -4273,9 +4307,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        /* Disabling hardware scan means that mac80211 will perform scans
         * "the hard way", rather than using device's scan. */
        if (cfg->mod_params->disable_hw_scan) {
-               if (iwl_debug_level & IWL_DL_INFO)
-                       dev_printk(KERN_DEBUG, &(pdev->dev),
-                                  "Disabling hw_scan\n");
+               dev_printk(KERN_DEBUG, &(pdev->dev),
+                       "sw scan support is deprecated\n");
                iwl_hw_ops.hw_scan = NULL;
        }
 
@@ -4788,6 +4821,22 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
        {IWL_PCI_DEVICE(0x0083, 0x1326, iwl1000_bg_cfg)},
        {IWL_PCI_DEVICE(0x0084, 0x1216, iwl1000_bg_cfg)},
        {IWL_PCI_DEVICE(0x0084, 0x1316, iwl1000_bg_cfg)},
+
+/* 100 Series WiFi */
+       {IWL_PCI_DEVICE(0x08AE, 0x1005, iwl100_bgn_cfg)},
+       {IWL_PCI_DEVICE(0x08AF, 0x1015, iwl100_bgn_cfg)},
+       {IWL_PCI_DEVICE(0x08AE, 0x1025, iwl100_bgn_cfg)},
+       {IWL_PCI_DEVICE(0x08AE, 0x1007, iwl100_bg_cfg)},
+       {IWL_PCI_DEVICE(0x08AE, 0x1017, iwl100_bg_cfg)},
+
+/* 130 Series WiFi */
+       {IWL_PCI_DEVICE(0x0896, 0x5005, iwl130_bgn_cfg)},
+       {IWL_PCI_DEVICE(0x0896, 0x5007, iwl130_bg_cfg)},
+       {IWL_PCI_DEVICE(0x0897, 0x5015, iwl130_bgn_cfg)},
+       {IWL_PCI_DEVICE(0x0897, 0x5017, iwl130_bg_cfg)},
+       {IWL_PCI_DEVICE(0x0896, 0x5025, iwl130_bgn_cfg)},
+       {IWL_PCI_DEVICE(0x0896, 0x5027, iwl130_bg_cfg)},
+
 #endif /* CONFIG_IWL5000 */
 
        {0}
@@ -4876,7 +4925,8 @@ module_param_named(fw_restart, iwlagn_mod_params.restart_fw, int, S_IRUGO);
 MODULE_PARM_DESC(fw_restart, "restart firmware in case of error");
 module_param_named(
        disable_hw_scan, iwlagn_mod_params.disable_hw_scan, int, S_IRUGO);
-MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)");
+MODULE_PARM_DESC(disable_hw_scan,
+                "disable hardware scanning (default 0) (deprecated)");
 
 module_param_named(ucode_alternative, iwlagn_wanted_ucode_alternative, int,
                   S_IRUGO);
index a372184ac2105b4761d71514abdcd5076d7839ff..eb3812a358623d1f7a6957f3ef908ecae10582a3 100644 (file)
@@ -92,6 +92,10 @@ extern struct iwl_cfg iwl6050_2abg_cfg;
 extern struct iwl_cfg iwl6050g2_bgn_cfg;
 extern struct iwl_cfg iwl1000_bgn_cfg;
 extern struct iwl_cfg iwl1000_bg_cfg;
+extern struct iwl_cfg iwl100_bgn_cfg;
+extern struct iwl_cfg iwl100_bg_cfg;
+extern struct iwl_cfg iwl130_bgn_cfg;
+extern struct iwl_cfg iwl130_bg_cfg;
 
 extern struct iwl_mod_params iwlagn_mod_params;
 extern struct iwl_hcmd_ops iwlagn_hcmd;
index 27e250c8d4b5540ae6704701d922ef6455331081..fe652568fec7547535e7d8d7d1a226c9bf5025ea 100644 (file)
@@ -420,12 +420,12 @@ struct iwl4965_tx_power_db {
 
 /**
  * Command REPLY_TX_POWER_DBM_CMD = 0x98
- * struct iwl5000_tx_power_dbm_cmd
+ * struct iwlagn_tx_power_dbm_cmd
  */
-#define IWL50_TX_POWER_AUTO 0x7f
-#define IWL50_TX_POWER_NO_CLOSED (0x1 << 6)
+#define IWLAGN_TX_POWER_AUTO 0x7f
+#define IWLAGN_TX_POWER_NO_CLOSED (0x1 << 6)
 
-struct iwl5000_tx_power_dbm_cmd {
+struct iwlagn_tx_power_dbm_cmd {
        s8 global_lmt; /*in half-dBm (e.g. 30 = 15 dBm) */
        u8 flags;
        s8 srv_chan_lmt; /*in half-dBm (e.g. 30 = 15 dBm) */
@@ -1042,7 +1042,7 @@ struct iwl4965_keyinfo {
        u8 key[16];             /* 16-byte unicast decryption key */
 } __packed;
 
-/* 5000 */
+/* agn */
 struct iwl_keyinfo {
        __le16 key_flags;
        u8 tkip_rx_tsc_byte2;   /* TSC[2] for key mix ph1 detection */
@@ -1168,7 +1168,7 @@ struct iwl4965_addsta_cmd {
        __le16 reserved2;
 } __packed;
 
-/* 5000 */
+/* agn */
 struct iwl_addsta_cmd {
        u8 mode;                /* 1: modify existing, 0: add new station */
        u8 reserved[3];
@@ -1959,12 +1959,12 @@ struct iwl4965_tx_resp {
 #define IWL50_TX_RES_INV_RATE_INDEX_MSK        0x80
 
 /* refer to ra_tid */
-#define IWL50_TX_RES_TID_POS   0
-#define IWL50_TX_RES_TID_MSK   0x0f
-#define IWL50_TX_RES_RA_POS    4
-#define IWL50_TX_RES_RA_MSK    0xf0
+#define IWLAGN_TX_RES_TID_POS  0
+#define IWLAGN_TX_RES_TID_MSK  0x0f
+#define IWLAGN_TX_RES_RA_POS   4
+#define IWLAGN_TX_RES_RA_MSK   0xf0
 
-struct iwl5000_tx_resp {
+struct iwlagn_tx_resp {
        u8 frame_count;         /* 1 no aggregation, >1 aggregation */
        u8 bt_kill_count;       /* # blocked by bluetooth (unused for agg) */
        u8 failure_rts;         /* # failures due to unsuccessful RTS */
@@ -3800,6 +3800,21 @@ enum {
 
 #define IWL_CALIB_INIT_CFG_ALL cpu_to_le32(0xffffffff)
 
+/* This enum defines the bitmap of various calibrations to enable in both
+ * init ucode and runtime ucode through CALIBRATION_CFG_CMD.
+ */
+enum iwl_ucode_calib_cfg {
+       IWL_CALIB_CFG_RX_BB_IDX,
+       IWL_CALIB_CFG_DC_IDX,
+       IWL_CALIB_CFG_TX_IQ_IDX,
+       IWL_CALIB_CFG_RX_IQ_IDX,
+       IWL_CALIB_CFG_NOISE_IDX,
+       IWL_CALIB_CFG_CRYSTAL_IDX,
+       IWL_CALIB_CFG_TEMPERATURE_IDX,
+       IWL_CALIB_CFG_PAPD_IDX,
+};
+
+
 struct iwl_calib_cfg_elmnt_s {
        __le32 is_enable;
        __le32 start;
index 5c568933ce48f521e24ef868b70f6e7c74d47c7b..516c55ae38aad4ea10bf957283d6d5a6a98234ae 100644 (file)
@@ -232,7 +232,8 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv,
 
        ht_info->ht_supported = true;
 
-       if (priv->cfg->ht_greenfield_support)
+       if (priv->cfg->ht_params &&
+           priv->cfg->ht_params->ht_greenfield_support)
                ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD;
        ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
        max_bit_rate = MAX_BIT_RATE_20_MHZ;
@@ -247,11 +248,11 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv,
                ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU;
 
        ht_info->ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF;
-       if (priv->cfg->ampdu_factor)
-               ht_info->ampdu_factor = priv->cfg->ampdu_factor;
+       if (priv->cfg->bt_params && priv->cfg->bt_params->ampdu_factor)
+               ht_info->ampdu_factor = priv->cfg->bt_params->ampdu_factor;
        ht_info->ampdu_density = CFG_HT_MPDU_DENSITY_DEF;
-       if (priv->cfg->ampdu_density)
-               ht_info->ampdu_density = priv->cfg->ampdu_density;
+       if (priv->cfg->bt_params && priv->cfg->bt_params->ampdu_density)
+               ht_info->ampdu_density = priv->cfg->bt_params->ampdu_density;
 
        ht_info->mcs.rx_mask[0] = 0xFF;
        if (rx_chains_num >= 2)
@@ -850,8 +851,10 @@ EXPORT_SYMBOL(iwl_set_rxon_ht);
  */
 static int iwl_get_active_rx_chain_count(struct iwl_priv *priv)
 {
-       if (priv->cfg->advanced_bt_coexist && (priv->bt_full_concurrent ||
-           priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)) {
+       if (priv->cfg->bt_params &&
+           priv->cfg->bt_params->advanced_bt_coexist &&
+           (priv->bt_full_concurrent ||
+            priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)) {
                /*
                 * only use chain 'A' in bt high traffic load or
                 * full concurrency mode
@@ -919,8 +922,10 @@ void iwl_set_rxon_chain(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
        else
                active_chains = priv->hw_params.valid_rx_ant;
 
-       if (priv->cfg->advanced_bt_coexist && (priv->bt_full_concurrent ||
-           priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)) {
+       if (priv->cfg->bt_params &&
+           priv->cfg->bt_params->advanced_bt_coexist &&
+           (priv->bt_full_concurrent ||
+            priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)) {
                /*
                 * only use chain 'A' in bt high traffic load or
                 * full concurrency mode
@@ -1362,7 +1367,7 @@ int iwl_apm_init(struct iwl_priv *priv)
         * If not (unlikely), enable L0S, so there is at least some
         *    power savings, even without L1.
         */
-       if (priv->cfg->set_l0s) {
+       if (priv->cfg->base_params->set_l0s) {
                lctl = iwl_pcie_link_ctl(priv);
                if ((lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN) ==
                                        PCI_CFG_LINK_CTRL_VAL_L1_EN) {
@@ -1379,8 +1384,9 @@ int iwl_apm_init(struct iwl_priv *priv)
        }
 
        /* Configure analog phase-lock-loop before activating to D0A */
-       if (priv->cfg->pll_cfg_val)
-               iwl_set_bit(priv, CSR_ANA_PLL_CFG, priv->cfg->pll_cfg_val);
+       if (priv->cfg->base_params->pll_cfg_val)
+               iwl_set_bit(priv, CSR_ANA_PLL_CFG,
+                           priv->cfg->base_params->pll_cfg_val);
 
        /*
         * Set "initialization complete" bit to move adapter from
@@ -1411,7 +1417,7 @@ int iwl_apm_init(struct iwl_priv *priv)
         * do not disable clocks.  This preserves any hardware bits already
         * set by default in "CLK_CTRL_REG" after reset.
         */
-       if (priv->cfg->use_bsm)
+       if (priv->cfg->base_params->use_bsm)
                iwl_write_prph(priv, APMG_CLK_EN_REG,
                        APMG_CLK_VAL_DMA_CLK_RQT | APMG_CLK_VAL_BSM_CLK_RQT);
        else
@@ -2003,7 +2009,8 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 
        mutex_lock(&priv->mutex);
 
-       if (WARN_ON(!iwl_is_ready_rf(priv))) {
+       if (!iwl_is_ready_rf(priv)) {
+               IWL_WARN(priv, "Try to add interface when device not ready\n");
                err = -EINVAL;
                goto out;
        }
@@ -2053,7 +2060,8 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
                goto out_err;
        }
 
-       if (priv->cfg->advanced_bt_coexist &&
+       if (priv->cfg->bt_params &&
+           priv->cfg->bt_params->advanced_bt_coexist &&
            vif->type == NL80211_IFTYPE_ADHOC) {
                /*
                 * pretend to have high BT traffic as long as we
@@ -2316,7 +2324,8 @@ int iwl_alloc_txq_mem(struct iwl_priv *priv)
 {
        if (!priv->txq)
                priv->txq = kzalloc(
-                       sizeof(struct iwl_tx_queue) * priv->cfg->num_of_queues,
+                       sizeof(struct iwl_tx_queue) *
+                               priv->cfg->base_params->num_of_queues,
                        GFP_KERNEL);
        if (!priv->txq) {
                IWL_ERR(priv, "Not enough memory for txq\n");
@@ -2736,11 +2745,6 @@ int iwl_force_reset(struct iwl_priv *priv, int mode, bool external)
        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return -EINVAL;
 
-       if (test_bit(STATUS_SCANNING, &priv->status)) {
-               IWL_DEBUG_INFO(priv, "scan in progress.\n");
-               return -EINVAL;
-       }
-
        if (mode >= IWL_MAX_FORCE_RESET) {
                IWL_DEBUG_INFO(priv, "invalid reset request.\n");
                return -EINVAL;
@@ -2827,33 +2831,34 @@ static int iwl_check_stuck_queue(struct iwl_priv *priv, int cnt)
        txq = &priv->txq[cnt];
        q = &txq->q;
        /* queue is empty, skip */
-       if (q->read_ptr != q->write_ptr) {
-               if (q->read_ptr == q->last_read_ptr) {
-                       /* a queue has not been read from last time */
-                       if (q->repeat_same_read_ptr > MAX_REPEAT) {
-                               IWL_ERR(priv,
-                                       "queue %d stuck %d time. Fw reload.\n",
-                                       q->id, q->repeat_same_read_ptr);
-                               q->repeat_same_read_ptr = 0;
-                               iwl_force_reset(priv, IWL_FW_RESET, false);
-                       } else {
-                               q->repeat_same_read_ptr++;
-                               IWL_DEBUG_RADIO(priv,
-                                               "queue %d, not read %d time\n",
-                                               q->id,
-                                               q->repeat_same_read_ptr);
-                               if (!priv->cfg->advanced_bt_coexist) {
-                                       mod_timer(&priv->monitor_recover,
-                                               jiffies + msecs_to_jiffies(
-                                               IWL_ONE_HUNDRED_MSECS));
-                                       return 1;
-                               }
-                       }
-                       return 0;
-               } else {
-                       q->last_read_ptr = q->read_ptr;
+       if (q->read_ptr == q->write_ptr)
+               return 0;
+
+       if (q->read_ptr == q->last_read_ptr) {
+               /* a queue has not been read from last time */
+               if (q->repeat_same_read_ptr > MAX_REPEAT) {
+                       IWL_ERR(priv,
+                               "queue %d stuck %d time. Fw reload.\n",
+                               q->id, q->repeat_same_read_ptr);
                        q->repeat_same_read_ptr = 0;
+                       iwl_force_reset(priv, IWL_FW_RESET, false);
+               } else {
+                       q->repeat_same_read_ptr++;
+                       IWL_DEBUG_RADIO(priv,
+                                       "queue %d, not read %d time\n",
+                                       q->id,
+                                       q->repeat_same_read_ptr);
+                       if (priv->cfg->bt_params &&
+                           !priv->cfg->bt_params->advanced_bt_coexist) {
+                               mod_timer(&priv->monitor_recover,
+                                       jiffies + msecs_to_jiffies(
+                                       IWL_ONE_HUNDRED_MSECS));
+                               return 1;
+                       }
                }
+       } else {
+               q->last_read_ptr = q->read_ptr;
+               q->repeat_same_read_ptr = 0;
        }
        return 0;
 }
@@ -2880,13 +2885,13 @@ void iwl_bg_monitor_recover(unsigned long data)
                                return;
                }
        }
-       if (priv->cfg->monitor_recover_period) {
+       if (priv->cfg->base_params->monitor_recover_period) {
                /*
                 * Reschedule the timer to occur in
-                * priv->cfg->monitor_recover_period
+                * priv->cfg->base_params->monitor_recover_period
                 */
                mod_timer(&priv->monitor_recover, jiffies + msecs_to_jiffies(
-                         priv->cfg->monitor_recover_period));
+                         priv->cfg->base_params->monitor_recover_period));
        }
 }
 EXPORT_SYMBOL(iwl_bg_monitor_recover);
index f0302bfe85f55c46eee85bcbafc48c93270a8c7d..6228b1c2ec966487f71a2df350d83db74a4d04ea 100644 (file)
@@ -137,7 +137,6 @@ struct iwl_debugfs_ops {
 struct iwl_temp_ops {
        void (*temperature)(struct iwl_priv *priv);
        void (*set_ct_kill)(struct iwl_priv *priv);
-       void (*set_calib_version)(struct iwl_priv *priv);
 };
 
 struct iwl_tt_ops {
@@ -233,11 +232,17 @@ struct iwl_led_ops {
        int (*off)(struct iwl_priv *priv);
 };
 
+/* NIC specific ops */
+struct iwl_nic_ops {
+       void (*additional_nic_config)(struct iwl_priv *priv);
+};
+
 struct iwl_ops {
        const struct iwl_lib_ops *lib;
        const struct iwl_hcmd_ops *hcmd;
        const struct iwl_hcmd_utils_ops *utils;
        const struct iwl_led_ops *led;
+       const struct iwl_nic_ops *nic;
 };
 
 struct iwl_mod_params {
@@ -250,20 +255,12 @@ struct iwl_mod_params {
        int restart_fw;         /* def: 1 = restart firmware */
 };
 
-/**
- * struct iwl_cfg
- * @fw_name_pre: Firmware filename prefix. The api version and extension
- *     (.ucode) will be added to filename before loading from disk. The
- *     filename is constructed as fw_name_pre<api>.ucode.
- * @ucode_api_max: Highest version of uCode API supported by driver.
- * @ucode_api_min: Lowest version of uCode API supported by driver.
- * @pa_type: used by 6000 series only to identify the type of Power Amplifier
+/*
  * @max_ll_items: max number of OTP blocks
  * @shadow_ram_support: shadow support for OTP memory
  * @led_compensation: compensate on the led on/off time per HW according
  *     to the deviation to achieve the desired led frequency.
  *     The detail algorithm is described in iwl-led.c
- * @use_rts_for_aggregation: use rts/cts protection for HT traffic
  * @chain_noise_num_beacons: number of beacons used to compute chain noise
  * @adv_thermal_throttle: support advance thermal throttle
  * @support_ct_kill_exit: support ct kill exit condition
@@ -281,15 +278,73 @@ struct iwl_mod_params {
  *     sensitivity calibration operation
  * @chain_noise_calib_by_driver: driver has the capability to perform
  *     chain noise calibration operation
- * @scan_antennas: available antenna for scan operation
+*/
+struct iwl_base_params {
+       int eeprom_size;
+       int num_of_queues;      /* def: HW dependent */
+       int num_of_ampdu_queues;/* def: HW dependent */
+       /* for iwl_apm_init() */
+       u32 pll_cfg_val;
+       bool set_l0s;
+       bool use_bsm;
+
+       bool use_isr_legacy;
+       const u16 max_ll_items;
+       const bool shadow_ram_support;
+       u16 led_compensation;
+       const bool broken_powersave;
+       int chain_noise_num_beacons;
+       const bool supports_idle;
+       bool adv_thermal_throttle;
+       bool support_ct_kill_exit;
+       const bool support_wimax_coexist;
+       u8 plcp_delta_threshold;
+       s32 chain_noise_scale;
+       /* timer period for monitor the driver queues */
+       u32 monitor_recover_period;
+       bool temperature_kelvin;
+       u32 max_event_log_size;
+       const bool tx_power_by_driver;
+       const bool ucode_tracing;
+       const bool sensitivity_calib_by_driver;
+       const bool chain_noise_calib_by_driver;
+};
+/*
  * @advanced_bt_coexist: support advanced bt coexist
  * @bt_init_traffic_load: specify initial bt traffic load
  * @bt_prio_boost: default bt priority boost value
- * @need_dc_calib: need to perform init dc calibration
  * @bt_statistics: use BT version of statistics notification
  * @agg_time_limit: maximum number of uSec in aggregation
  * @ampdu_factor: Maximum A-MPDU length factor
  * @ampdu_density: Minimum A-MPDU spacing
+*/
+struct iwl_bt_params {
+       bool advanced_bt_coexist;
+       u8 bt_init_traffic_load;
+       u8 bt_prio_boost;
+       const bool bt_statistics;
+       u16 agg_time_limit;
+       u8 ampdu_factor;
+       u8 ampdu_density;
+};
+/*
+ * @use_rts_for_aggregation: use rts/cts protection for HT traffic
+*/
+struct iwl_ht_params {
+       const bool ht_greenfield_support; /* if used set to true */
+       bool use_rts_for_aggregation;
+};
+
+/**
+ * struct iwl_cfg
+ * @fw_name_pre: Firmware filename prefix. The api version and extension
+ *     (.ucode) will be added to filename before loading from disk. The
+ *     filename is constructed as fw_name_pre<api>.ucode.
+ * @ucode_api_max: Highest version of uCode API supported by driver.
+ * @ucode_api_min: Lowest version of uCode API supported by driver.
+ * @pa_type: used by 6000 series only to identify the type of Power Amplifier
+ * @need_dc_calib: need to perform init dc calibration
+ * @scan_antennas: available antenna for scan operation
  *
  * We enable the driver to be backward compatible wrt API version. The
  * driver specifies which APIs it supports (with @ucode_api_max being the
@@ -300,9 +355,9 @@ struct iwl_mod_params {
  *
  * For example,
  * if (IWL_UCODE_API(priv->ucode_ver) >= 2) {
- *     Driver interacts with Firmware API version >= 2.
+ *     Driver interacts with Firmware API version >= 2.
  * } else {
- *     Driver interacts with Firmware API version 1.
+ *     Driver interacts with Firmware API version 1.
  * }
  *
  * The ideal usage of this infrastructure is to treat a new ucode API
@@ -313,59 +368,28 @@ struct iwl_mod_params {
  *
  */
 struct iwl_cfg {
+       /* params specific to an individual device within a device family */
        const char *name;
        const char *fw_name_pre;
        const unsigned int ucode_api_max;
        const unsigned int ucode_api_min;
+       u8   valid_tx_ant;
+       u8   valid_rx_ant;
        unsigned int sku;
-       int eeprom_size;
        u16  eeprom_ver;
        u16  eeprom_calib_ver;
-       int num_of_queues;      /* def: HW dependent */
-       int num_of_ampdu_queues;/* def: HW dependent */
        const struct iwl_ops *ops;
+       /* module based parameters which can be set from modprobe cmd */
        const struct iwl_mod_params *mod_params;
-       u8   valid_tx_ant;
-       u8   valid_rx_ant;
-
-       /* for iwl_apm_init() */
-       u32 pll_cfg_val;
-       bool set_l0s;
-       bool use_bsm;
-
-       bool use_isr_legacy;
-       enum iwl_pa_type pa_type;
-       const u16 max_ll_items;
-       const bool shadow_ram_support;
-       const bool ht_greenfield_support;
-       u16 led_compensation;
-       const bool broken_powersave;
-       bool use_rts_for_aggregation;
-       int chain_noise_num_beacons;
-       const bool supports_idle;
-       bool adv_thermal_throttle;
-       bool support_ct_kill_exit;
-       const bool support_wimax_coexist;
-       u8 plcp_delta_threshold;
-       s32 chain_noise_scale;
-       /* timer period for monitor the driver queues */
-       u32 monitor_recover_period;
-       bool temperature_kelvin;
-       u32 max_event_log_size;
-       const bool tx_power_by_driver;
-       const bool ucode_tracing;
-       const bool sensitivity_calib_by_driver;
-       const bool chain_noise_calib_by_driver;
+       /* params not likely to change within a device family */
+       struct iwl_base_params *base_params;
+       /* params likely to change within a device family */
+       struct iwl_ht_params *ht_params;
+       struct iwl_bt_params *bt_params;
+       enum iwl_pa_type pa_type;         /* if used set to IWL_PA_SYSTEM */
+       const bool need_dc_calib;         /* if used set to true */
        u8 scan_rx_antennas[IEEE80211_NUM_BANDS];
        u8 scan_tx_antennas[IEEE80211_NUM_BANDS];
-       bool advanced_bt_coexist;
-       u8 bt_init_traffic_load;
-       u8 bt_prio_boost;
-       const bool need_dc_calib;
-       const bool bt_statistics;
-       u16 agg_time_limit;
-       u8 ampdu_factor;
-       u8 ampdu_density;
 };
 
 /***************************
index ecf98e7ac4edac798b90bc3db4116ff1a7b923dc..2aa15ab13892541fab426e0dac361e2d3b279adb 100644 (file)
 #define CSR_GP_DRIVER_REG_BIT_RADIO_SKU_3x3_HYB            (0x00000000)
 #define CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_HYB            (0x00000001)
 #define CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA            (0x00000002)
-#define CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6   (0x00000004)
+#define CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6       (0x00000004)
+#define CSR_GP_DRIVER_REG_BIT_6050_1x2             (0x00000008)
 
 /* GIO Chicken Bits (PCI Express bus link power management) */
 #define CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX  (0x00800000)
index 265ad01a443f9adb887fe7c606098e5bf94f8ecd..fc340311ea0a81cc89ccf56387168bfc441b0600 100644 (file)
@@ -356,7 +356,7 @@ static ssize_t iwl_dbgfs_nvm_read(struct file *file,
        const u8 *ptr;
        char *buf;
        u16 eeprom_ver;
-       size_t eeprom_len = priv->cfg->eeprom_size;
+       size_t eeprom_len = priv->cfg->base_params->eeprom_size;
        buf_size = 4 * eeprom_len + 256;
 
        if (eeprom_len % 16) {
@@ -872,7 +872,7 @@ static ssize_t iwl_dbgfs_traffic_log_read(struct file *file,
        struct iwl_rx_queue *rxq = &priv->rxq;
        char *buf;
        int bufsz = ((IWL_TRAFFIC_ENTRIES * IWL_TRAFFIC_ENTRY_SIZE * 64) * 2) +
-               (priv->cfg->num_of_queues * 32 * 8) + 400;
+               (priv->cfg->base_params->num_of_queues * 32 * 8) + 400;
        const u8 *ptr;
        ssize_t ret;
 
@@ -971,7 +971,8 @@ static ssize_t iwl_dbgfs_tx_queue_read(struct file *file,
        int pos = 0;
        int cnt;
        int ret;
-       const size_t bufsz = sizeof(char) * 64 * priv->cfg->num_of_queues;
+       const size_t bufsz = sizeof(char) * 64 *
+                               priv->cfg->base_params->num_of_queues;
 
        if (!priv->txq) {
                IWL_ERR(priv, "txq not ready\n");
@@ -1415,7 +1416,7 @@ static ssize_t iwl_dbgfs_plcp_delta_read(struct file *file,
        const size_t bufsz = sizeof(buf);
 
        pos += scnprintf(buf + pos, bufsz - pos, "%u\n",
-                       priv->cfg->plcp_delta_threshold);
+                       priv->cfg->base_params->plcp_delta_threshold);
 
        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 }
@@ -1437,10 +1438,10 @@ static ssize_t iwl_dbgfs_plcp_delta_write(struct file *file,
                return -EINVAL;
        if ((plcp < IWL_MAX_PLCP_ERR_THRESHOLD_MIN) ||
                (plcp > IWL_MAX_PLCP_ERR_THRESHOLD_MAX))
-               priv->cfg->plcp_delta_threshold =
+               priv->cfg->base_params->plcp_delta_threshold =
                        IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE;
        else
-               priv->cfg->plcp_delta_threshold = plcp;
+               priv->cfg->base_params->plcp_delta_threshold = plcp;
        return count;
 }
 
@@ -1550,13 +1551,14 @@ static ssize_t iwl_dbgfs_monitor_period_write(struct file *file,
        if (sscanf(buf, "%d", &period) != 1)
                return -EINVAL;
        if (period < 0 || period > IWL_MAX_MONITORING_PERIOD)
-               priv->cfg->monitor_recover_period = IWL_DEF_MONITORING_PERIOD;
+               priv->cfg->base_params->monitor_recover_period =
+                       IWL_DEF_MONITORING_PERIOD;
        else
-               priv->cfg->monitor_recover_period = period;
+               priv->cfg->base_params->monitor_recover_period = period;
 
-       if (priv->cfg->monitor_recover_period)
+       if (priv->cfg->base_params->monitor_recover_period)
                mod_timer(&priv->monitor_recover, jiffies + msecs_to_jiffies(
-                         priv->cfg->monitor_recover_period));
+                         priv->cfg->base_params->monitor_recover_period));
        else
                del_timer_sync(&priv->monitor_recover);
        return count;
@@ -1614,9 +1616,14 @@ static ssize_t iwl_dbgfs_protection_mode_read(struct file *file,
        char buf[40];
        const size_t bufsz = sizeof(buf);
 
-       pos += scnprintf(buf + pos, bufsz - pos, "use %s for aggregation\n",
-                        (priv->cfg->use_rts_for_aggregation) ? "rts/cts" :
-                        "cts-to-self");
+       if (priv->cfg->ht_params)
+               pos += scnprintf(buf + pos, bufsz - pos,
+                        "use %s for aggregation\n",
+                        (priv->cfg->ht_params->use_rts_for_aggregation) ?
+                               "rts/cts" : "cts-to-self");
+       else
+               pos += scnprintf(buf + pos, bufsz - pos, "N/A");
+
        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 }
 
@@ -1629,6 +1636,9 @@ static ssize_t iwl_dbgfs_protection_mode_write(struct file *file,
        int buf_size;
        int rts;
 
+       if (!priv->cfg->ht_params)
+               return -EINVAL;
+
        memset(buf, 0, sizeof(buf));
        buf_size = min(count, sizeof(buf) -  1);
        if (copy_from_user(buf, user_buf, buf_size))
@@ -1636,9 +1646,9 @@ static ssize_t iwl_dbgfs_protection_mode_write(struct file *file,
        if (sscanf(buf, "%d", &rts) != 1)
                return -EINVAL;
        if (rts)
-               priv->cfg->use_rts_for_aggregation = true;
+               priv->cfg->ht_params->use_rts_for_aggregation = true;
        else
-               priv->cfg->use_rts_for_aggregation = false;
+               priv->cfg->ht_params->use_rts_for_aggregation = false;
        return count;
 }
 
@@ -1716,7 +1726,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
        DEBUGFS_ADD_FILE(interrupt, dir_data, S_IWUSR | S_IRUSR);
        DEBUGFS_ADD_FILE(qos, dir_data, S_IRUSR);
        DEBUGFS_ADD_FILE(led, dir_data, S_IRUSR);
-       if (!priv->cfg->broken_powersave) {
+       if (!priv->cfg->base_params->broken_powersave) {
                DEBUGFS_ADD_FILE(sleep_level_override, dir_data,
                                 S_IWUSR | S_IRUSR);
                DEBUGFS_ADD_FILE(current_sleep_command, dir_data, S_IRUSR);
@@ -1743,27 +1753,27 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
                DEBUGFS_ADD_FILE(txfifo_flush, dir_debug, S_IWUSR);
        DEBUGFS_ADD_FILE(protection_mode, dir_debug, S_IWUSR | S_IRUSR);
 
-       if (priv->cfg->sensitivity_calib_by_driver)
+       if (priv->cfg->base_params->sensitivity_calib_by_driver)
                DEBUGFS_ADD_FILE(sensitivity, dir_debug, S_IRUSR);
-       if (priv->cfg->chain_noise_calib_by_driver)
+       if (priv->cfg->base_params->chain_noise_calib_by_driver)
                DEBUGFS_ADD_FILE(chain_noise, dir_debug, S_IRUSR);
-       if (priv->cfg->ucode_tracing)
+       if (priv->cfg->base_params->ucode_tracing)
                DEBUGFS_ADD_FILE(ucode_tracing, dir_debug, S_IWUSR | S_IRUSR);
-       if (priv->cfg->bt_statistics)
+       if (priv->cfg->bt_params && priv->cfg->bt_params->bt_statistics)
                DEBUGFS_ADD_FILE(ucode_bt_stats, dir_debug, S_IRUSR);
        DEBUGFS_ADD_FILE(reply_tx_error, dir_debug, S_IRUSR);
        DEBUGFS_ADD_FILE(rxon_flags, dir_debug, S_IWUSR);
        DEBUGFS_ADD_FILE(rxon_filter_flags, dir_debug, S_IWUSR);
        DEBUGFS_ADD_FILE(monitor_period, dir_debug, S_IWUSR);
-       if (priv->cfg->advanced_bt_coexist)
+       if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist)
                DEBUGFS_ADD_FILE(bt_traffic, dir_debug, S_IRUSR);
-       if (priv->cfg->sensitivity_calib_by_driver)
+       if (priv->cfg->base_params->sensitivity_calib_by_driver)
                DEBUGFS_ADD_BOOL(disable_sensitivity, dir_rf,
                                 &priv->disable_sens_cal);
-       if (priv->cfg->chain_noise_calib_by_driver)
+       if (priv->cfg->base_params->chain_noise_calib_by_driver)
                DEBUGFS_ADD_BOOL(disable_chain_noise, dir_rf,
                                 &priv->disable_chain_noise_cal);
-       if (priv->cfg->tx_power_by_driver)
+       if (priv->cfg->base_params->tx_power_by_driver)
                DEBUGFS_ADD_BOOL(disable_tx_power, dir_rf,
                                &priv->disable_tx_power_cal);
        return 0;
index 74d25bcbfcb27e7532c9facc8e05600760bc4593..90a37a94c69876c034ba168437fb764912445ef3 100644 (file)
@@ -684,6 +684,7 @@ struct iwl_sensitivity_ranges {
  * @ct_kill_threshold: temperature threshold
  * @beacon_time_tsf_bits: number of valid tsf bits for beacon time
  * @calib_init_cfg: setup initial calibrations for the hw
+ * @calib_rt_cfg: setup runtime calibrations for the hw
  * @struct iwl_sensitivity_ranges: range of sensitivity values
  */
 struct iwl_hw_params {
@@ -710,6 +711,7 @@ struct iwl_hw_params {
                                    /* for 1000, 6000 series and up */
        u16 beacon_time_tsf_bits;
        u32 calib_init_cfg;
+       u32 calib_rt_cfg;
        const struct iwl_sensitivity_ranges *sens;
 };
 
index a45d02e555cfffbcd3d174deb5dbdc4352ff6bef..88f4a80d4733bafff85a1894db1a7d690f62ea2f 100644 (file)
@@ -332,7 +332,7 @@ EXPORT_SYMBOL(iwlcore_eeprom_release_semaphore);
 
 const u8 *iwlcore_eeprom_query_addr(const struct iwl_priv *priv, size_t offset)
 {
-       BUG_ON(offset >= priv->cfg->eeprom_size);
+       BUG_ON(offset >= priv->cfg->base_params->eeprom_size);
        return &priv->eeprom[offset];
 }
 EXPORT_SYMBOL(iwlcore_eeprom_query_addr);
@@ -364,7 +364,7 @@ static int iwl_init_otp_access(struct iwl_priv *priv)
                 * CSR auto clock gate disable bit -
                 * this is only applicable for HW with OTP shadow RAM
                 */
-               if (priv->cfg->shadow_ram_support)
+               if (priv->cfg->base_params->shadow_ram_support)
                        iwl_set_bit(priv, CSR_DBG_LINK_PWR_MGMT_REG,
                                CSR_RESET_LINK_PWR_MGMT_DISABLED);
        }
@@ -484,7 +484,7 @@ static int iwl_find_otp_image(struct iwl_priv *priv,
                }
                /* more in the link list, continue */
                usedblocks++;
-       } while (usedblocks <= priv->cfg->max_ll_items);
+       } while (usedblocks <= priv->cfg->base_params->max_ll_items);
 
        /* OTP has no valid blocks */
        IWL_DEBUG_INFO(priv, "OTP has no valid blocks\n");
@@ -512,8 +512,8 @@ int iwl_eeprom_init(struct iwl_priv *priv)
        if (priv->nvm_device_type == -ENOENT)
                return -ENOENT;
        /* allocate eeprom */
-       IWL_DEBUG_INFO(priv, "NVM size = %d\n", priv->cfg->eeprom_size);
-       sz = priv->cfg->eeprom_size;
+       sz = priv->cfg->base_params->eeprom_size;
+       IWL_DEBUG_INFO(priv, "NVM size = %d\n", sz);
        priv->eeprom = kzalloc(sz, GFP_KERNEL);
        if (!priv->eeprom) {
                ret = -ENOMEM;
@@ -554,7 +554,7 @@ int iwl_eeprom_init(struct iwl_priv *priv)
                             CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK |
                             CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK);
                /* traversing the linked list if no shadow ram supported */
-               if (!priv->cfg->shadow_ram_support) {
+               if (!priv->cfg->base_params->shadow_ram_support) {
                        if (iwl_find_otp_image(priv, &validblockaddr)) {
                                ret = -ENOENT;
                                goto done;
index db5bfcb036ca274a2f1183e4f5e7ff963568998d..86c2b6fed0c6beeeb920ccc4adfb54dd5e0b990f 100644 (file)
@@ -108,13 +108,13 @@ static int iwl_led_pattern(struct iwl_priv *priv, unsigned int idx)
        BUG_ON(idx > IWL_MAX_BLINK_TBL);
 
        IWL_DEBUG_LED(priv, "Led blink time compensation= %u\n",
-                       priv->cfg->led_compensation);
+                       priv->cfg->base_params->led_compensation);
        led_cmd.on =
                iwl_blink_compensation(priv, blink_tbl[idx].on_time,
-                                       priv->cfg->led_compensation);
+                               priv->cfg->base_params->led_compensation);
        led_cmd.off =
                iwl_blink_compensation(priv, blink_tbl[idx].off_time,
-                                       priv->cfg->led_compensation);
+                               priv->cfg->base_params->led_compensation);
 
        return priv->cfg->ops->led->cmd(priv, &led_cmd);
 }
index 63c0ab46261faa105a7a20419b1d7cab899d2dc8..49d7788937a9eccc80891c703ea4220c1a98f100 100644 (file)
@@ -278,9 +278,9 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force)
 
        dtimper = priv->hw->conf.ps_dtim_period ?: 1;
 
-       if (priv->cfg->broken_powersave)
+       if (priv->cfg->base_params->broken_powersave)
                iwl_power_sleep_cam_cmd(priv, &cmd);
-       else if (priv->cfg->supports_idle &&
+       else if (priv->cfg->base_params->supports_idle &&
                 priv->hw->conf.flags & IEEE80211_CONF_IDLE)
                iwl_static_sleep_cmd(priv, &cmd, IWL_POWER_INDEX_5, 20);
        else if (priv->cfg->ops->lib->tt_ops.lower_power_detection &&
index c54c20023e7c256bc9a82784561bafa0d05b186c..eaae49ee0c60a1e36e564911bf4bf507fe5053b0 100644 (file)
@@ -259,7 +259,8 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv,
        queue_work(priv->workqueue, &priv->scan_completed);
 
        if (priv->iw_mode != NL80211_IFTYPE_ADHOC &&
-           priv->cfg->advanced_bt_coexist &&
+           priv->cfg->bt_params &&
+           priv->cfg->bt_params->advanced_bt_coexist &&
            priv->bt_status != scan_notif->bt_status) {
                if (scan_notif->bt_status) {
                        /* BT on */
index 116777122a798b2b700f8aa86cce11112a956a9f..43db5f38e3e6cc2cd8a23bdd9dcae21f23d0ea2c 100644 (file)
@@ -1581,16 +1581,16 @@ int iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
        num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32)));
        next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32)));
 
-       if (capacity > priv->cfg->max_event_log_size) {
+       if (capacity > priv->cfg->base_params->max_event_log_size) {
                IWL_ERR(priv, "Log capacity %d is bogus, limit to %d entries\n",
-                       capacity, priv->cfg->max_event_log_size);
-               capacity = priv->cfg->max_event_log_size;
+                       capacity, priv->cfg->base_params->max_event_log_size);
+               capacity = priv->cfg->base_params->max_event_log_size;
        }
 
-       if (next_entry > priv->cfg->max_event_log_size) {
+       if (next_entry > priv->cfg->base_params->max_event_log_size) {
                IWL_ERR(priv, "Log write index %d is bogus, limit to %d\n",
-                       next_entry, priv->cfg->max_event_log_size);
-               next_entry = priv->cfg->max_event_log_size;
+                       next_entry, priv->cfg->base_params->max_event_log_size);
+               next_entry = priv->cfg->base_params->max_event_log_size;
        }
 
        size = num_wraps ? capacity : next_entry;
@@ -2519,7 +2519,8 @@ static void iwl3945_alive_start(struct iwl_priv *priv)
                /* Enable timer to monitor the driver queues */
                mod_timer(&priv->monitor_recover,
                        jiffies +
-                       msecs_to_jiffies(priv->cfg->monitor_recover_period));
+                       msecs_to_jiffies(
+                         priv->cfg->base_params->monitor_recover_period));
        }
 
        if (iwl_is_rfkill(priv))
@@ -3881,7 +3882,7 @@ static int iwl3945_setup_mac(struct iwl_priv *priv)
        hw->flags = IEEE80211_HW_SIGNAL_DBM |
                    IEEE80211_HW_SPECTRUM_MGMT;
 
-       if (!priv->cfg->broken_powersave)
+       if (!priv->cfg->base_params->broken_powersave)
                hw->flags |= IEEE80211_HW_SUPPORTS_PS |
                             IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
 
@@ -3966,7 +3967,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
         * "the hard way", rather than using device's scan.
         */
        if (iwl3945_mod_params.disable_hw_scan) {
-               IWL_DEBUG_INFO(priv, "Disabling hw_scan\n");
+               IWL_ERR(priv, "sw scan support is deprecated\n");
                iwl3945_hw_ops.hw_scan = NULL;
        }
 
@@ -4291,7 +4292,8 @@ MODULE_PARM_DESC(debug, "debug output mask");
 #endif
 module_param_named(disable_hw_scan, iwl3945_mod_params.disable_hw_scan,
                   int, S_IRUGO);
-MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)");
+MODULE_PARM_DESC(disable_hw_scan,
+                "disable hardware scanning (default 0) (deprecated)");
 module_param_named(fw_restart3945, iwl3945_mod_params.restart_fw, int, S_IRUGO);
 MODULE_PARM_DESC(fw_restart3945, "restart firmware in case of error");
 
index 60619678f4ec1cb39c94dd5b97c3977082c168f3..c6c0eff9b5ed33f32c51223629ddc1e2cf118d71 100644 (file)
@@ -161,7 +161,7 @@ static int iwm_key_init(struct iwm_key *key, u8 key_index,
 }
 
 static int iwm_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
-                               u8 key_index, const u8 *mac_addr,
+                               u8 key_index, bool pairwise, const u8 *mac_addr,
                                struct key_params *params)
 {
        struct iwm_priv *iwm = ndev_to_iwm(ndev);
@@ -181,7 +181,8 @@ static int iwm_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
 }
 
 static int iwm_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
-                               u8 key_index, const u8 *mac_addr, void *cookie,
+                               u8 key_index, bool pairwise, const u8 *mac_addr,
+                               void *cookie,
                                void (*callback)(void *cookie,
                                                 struct key_params*))
 {
@@ -206,7 +207,7 @@ static int iwm_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
 
 
 static int iwm_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
-                               u8 key_index, const u8 *mac_addr)
+                               u8 key_index, bool pairwise, const u8 *mac_addr)
 {
        struct iwm_priv *iwm = ndev_to_iwm(ndev);
        struct iwm_key *key = &iwm->keys[key_index];
index 1bbdb14f7d760a9309ac2fafc98b862e1dd0b990..5046a00050348cc03fa4d10a566144449542bf36 100644 (file)
@@ -1440,7 +1440,7 @@ static int lbs_cfg_set_default_key(struct wiphy *wiphy,
 
 
 static int lbs_cfg_add_key(struct wiphy *wiphy, struct net_device *netdev,
-                          u8 idx, const u8 *mac_addr,
+                          u8 idx, bool pairwise, const u8 *mac_addr,
                           struct key_params *params)
 {
        struct lbs_private *priv = wiphy_priv(wiphy);
@@ -1500,7 +1500,7 @@ static int lbs_cfg_add_key(struct wiphy *wiphy, struct net_device *netdev,
 
 
 static int lbs_cfg_del_key(struct wiphy *wiphy, struct net_device *netdev,
-                          u8 key_index, const u8 *mac_addr)
+                          u8 key_index, bool pairwise, const u8 *mac_addr)
 {
 
        lbs_deb_enter(LBS_DEB_CFG80211);
index 063248b350692f13b6948e63722e28b4b634434d..d5bc21e5a02c7520d6599ad5822eafe85b267823 100644 (file)
@@ -33,8 +33,17 @@ MODULE_ALIAS("prism54usb");
 MODULE_FIRMWARE("isl3886usb");
 MODULE_FIRMWARE("isl3887usb");
 
+/*
+ * Note:
+ *
+ * Always update our wiki's device list (located at:
+ * http://wireless.kernel.org/en/users/Drivers/p54/devices ),
+ * whenever you add a new device.
+ */
+
 static struct usb_device_id p54u_table[] __devinitdata = {
        /* Version 1 devices (pci chip + net2280) */
+       {USB_DEVICE(0x045e, 0x00c2)},   /* Microsoft MN-710 */
        {USB_DEVICE(0x0506, 0x0a11)},   /* 3COM 3CRWE254G72 */
        {USB_DEVICE(0x06b9, 0x0120)},   /* Thomson SpeedTouch 120g */
        {USB_DEVICE(0x0707, 0xee06)},   /* SMC 2862W-G */
@@ -47,7 +56,9 @@ static struct usb_device_id p54u_table[] __devinitdata = {
        {USB_DEVICE(0x0846, 0x4220)},   /* Netgear WG111 */
        {USB_DEVICE(0x09aa, 0x1000)},   /* Spinnaker Proto board */
        {USB_DEVICE(0x0cde, 0x0006)},   /* Medion 40900, Roper Europe */
+       {USB_DEVICE(0x107b, 0x55f2)},   /* Gateway WGU-210 (Gemtek) */
        {USB_DEVICE(0x124a, 0x4023)},   /* Shuttle PN15, Airvast WM168g, IOGear GWU513 */
+       {USB_DEVICE(0x1630, 0x0005)},   /* 2Wire 802.11g USB (v1) / Z-Com */
        {USB_DEVICE(0x1915, 0x2234)},   /* Linksys WUSB54G OEM */
        {USB_DEVICE(0x1915, 0x2235)},   /* Linksys WUSB54G Portable OEM */
        {USB_DEVICE(0x2001, 0x3701)},   /* DLink DWL-G120 Spinnaker */
@@ -60,6 +71,7 @@ static struct usb_device_id p54u_table[] __devinitdata = {
        {USB_DEVICE(0x050d, 0x7050)},   /* Belkin F5D7050 ver 1000 */
        {USB_DEVICE(0x0572, 0x2000)},   /* Cohiba Proto board */
        {USB_DEVICE(0x0572, 0x2002)},   /* Cohiba Proto board */
+       {USB_DEVICE(0x06a9, 0x000e)},   /* Westell 802.11g USB (A90-211WG-01) */
        {USB_DEVICE(0x06b9, 0x0121)},   /* Thomson SpeedTouch 121g */
        {USB_DEVICE(0x0707, 0xee13)},   /* SMC 2862W-G version 2 */
        {USB_DEVICE(0x083a, 0x4521)},   /* Siemens Gigaset USB Adapter 54 version 2 */
@@ -80,6 +92,7 @@ static struct usb_device_id p54u_table[] __devinitdata = {
        {USB_DEVICE(0x13B1, 0x000C)},   /* Linksys WUSB54AG */
        {USB_DEVICE(0x1413, 0x5400)},   /* Telsey 802.11g USB2.0 Adapter */
        {USB_DEVICE(0x1435, 0x0427)},   /* Inventel UR054G */
+       {USB_DEVICE(0x1668, 0x1050)},   /* Actiontec 802UIG-1 */
        {USB_DEVICE(0x2001, 0x3704)},   /* DLink DWL-G122 rev A2 */
        {USB_DEVICE(0x413c, 0x5513)},   /* Dell WLA3310 USB Wireless Adapter */
        {USB_DEVICE(0x413c, 0x8102)},   /* Spinnaker DUT */
index 719573bbbf81fce6e21560465702cbff814847f4..71b5971da5970b2300c29a185c9836f394f227af 100644 (file)
@@ -540,11 +540,11 @@ static int rndis_set_channel(struct wiphy *wiphy, struct net_device *dev,
        struct ieee80211_channel *chan, enum nl80211_channel_type channel_type);
 
 static int rndis_add_key(struct wiphy *wiphy, struct net_device *netdev,
-                                       u8 key_index, const u8 *mac_addr,
-                                       struct key_params *params);
+                        u8 key_index, bool pairwise, const u8 *mac_addr,
+                        struct key_params *params);
 
 static int rndis_del_key(struct wiphy *wiphy, struct net_device *netdev,
-                                       u8 key_index, const u8 *mac_addr);
+                        u8 key_index, bool pairwise, const u8 *mac_addr);
 
 static int rndis_set_default_key(struct wiphy *wiphy, struct net_device *netdev,
                                                                u8 key_index);
@@ -2308,8 +2308,8 @@ static int rndis_set_channel(struct wiphy *wiphy, struct net_device *netdev,
 }
 
 static int rndis_add_key(struct wiphy *wiphy, struct net_device *netdev,
-                                       u8 key_index, const u8 *mac_addr,
-                                       struct key_params *params)
+                        u8 key_index, bool pairwise, const u8 *mac_addr,
+                        struct key_params *params)
 {
        struct rndis_wlan_private *priv = wiphy_priv(wiphy);
        struct usbnet *usbdev = priv->usbdev;
@@ -2344,7 +2344,7 @@ static int rndis_add_key(struct wiphy *wiphy, struct net_device *netdev,
 }
 
 static int rndis_del_key(struct wiphy *wiphy, struct net_device *netdev,
-                                       u8 key_index, const u8 *mac_addr)
+                        u8 key_index, bool pairwise, const u8 *mac_addr)
 {
        struct rndis_wlan_private *priv = wiphy_priv(wiphy);
        struct usbnet *usbdev = priv->usbdev;
index 6e94356265b38335dbc8742b0b5d360740724324..93e44c7f3a749ac5962fb4c6079ee7e8f0493163 100644 (file)
@@ -1674,10 +1674,15 @@ static int rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
 
        /*
         * Initialize all hw fields.
+        *
+        * Don't set IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING unless we are
+        * capable of sending the buffered frames out after the DTIM
+        * transmission using rt2x00lib_beacondone. This will send out
+        * multicast and broadcast traffic immediately instead of buffering it
+        * infinitly and thus dropping it after some time.
         */
        rt2x00dev->hw->flags =
            IEEE80211_HW_RX_INCLUDES_FCS |
-           IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
            IEEE80211_HW_SIGNAL_DBM |
            IEEE80211_HW_SUPPORTS_PS |
            IEEE80211_HW_PS_NULLFUNC_STACK;
index 2edc7742a7e906f3ab7673813d30b3759282e9dc..eb8b6cab992516fa8bdf58d2feabcf44950585f3 100644 (file)
@@ -1,5 +1,6 @@
 /*
-       Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
+       Copyright (C) 2004 - 2010 Ivo van Doorn <IvDoorn@gmail.com>
+       Copyright (C) 2010 Willow Garage <http://www.willowgarage.com>
        Copyright (C) 2009 Alban Browaeys <prahal@yahoo.com>
        Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org>
        Copyright (C) 2009 Luis Correia <luis.f.correia@gmail.com>
 
 /*
  * TBTT_SYNC_CFG:
+ * BCN_AIFSN: Beacon AIFSN after TBTT interrupt in slots
+ * BCN_CWMIN: Beacon CWMin after TBTT interrupt in slots
  */
 #define TBTT_SYNC_CFG                  0x1118
+#define TBTT_SYNC_CFG_TBTT_ADJUST      FIELD32(0x000000ff)
+#define TBTT_SYNC_CFG_BCN_EXP_WIN      FIELD32(0x0000ff00)
+#define TBTT_SYNC_CFG_BCN_AIFSN                FIELD32(0x000f0000)
+#define TBTT_SYNC_CFG_BCN_CWMIN                FIELD32(0x00f00000)
 
 /*
  * TSF_TIMER_DW0: Local lsb TSF timer, read-only
 #define INT_TIMER_EN_GP_TIMER          FIELD32(0x00000002)
 
 /*
- * CH_IDLE_STA: channel idle time
+ * CH_IDLE_STA: channel idle time (in us)
  */
 #define CH_IDLE_STA                    0x1130
 
 /*
- * CH_BUSY_STA: channel busy time
+ * CH_BUSY_STA: channel busy time on primary channel (in us)
  */
 #define CH_BUSY_STA                    0x1134
 
+/*
+ * CH_BUSY_STA_SEC: channel busy time on secondary channel in HT40 mode (in us)
+ */
+#define CH_BUSY_STA_SEC                        0x1138
+
 /*
  * MAC_STATUS_CFG:
  * BBP_RF_BUSY: When set to 0, BBP and RF are stable.
  * PID_TYPE: The PID latched from the PID field in the TXWI, can be used
  *           to match a frame with its tx result (even though the PID is
  *           only 4 bits wide).
+ * PID_QUEUE: Part of PID_TYPE, this is the queue index number (0-3)
+ * PID_ENTRY: Part of PID_TYPE, this is the queue entry index number (1-3)
+ *            This identification number is calculated by ((idx % 3) + 1).
  * TX_SUCCESS: Indicates tx success (1) or failure (0)
  * TX_AGGRE: Indicates if the frame was part of an aggregate (1) or not (0)
  * TX_ACK_REQUIRED: Indicates if the frame needed to get ack'ed (1) or not (0)
 #define TX_STA_FIFO                    0x1718
 #define TX_STA_FIFO_VALID              FIELD32(0x00000001)
 #define TX_STA_FIFO_PID_TYPE           FIELD32(0x0000001e)
+#define TX_STA_FIFO_PID_QUEUE          FIELD32(0x00000006)
+#define TX_STA_FIFO_PID_ENTRY          FIELD32(0x00000018)
 #define TX_STA_FIFO_TX_SUCCESS         FIELD32(0x00000020)
 #define TX_STA_FIFO_TX_AGGRE           FIELD32(0x00000040)
 #define TX_STA_FIFO_TX_ACK_REQUIRED    FIELD32(0x00000080)
 
 /*
  * Security key table memory.
+ *
+ * The pairwise key table shares some memory with the beacon frame
+ * buffers 6 and 7. That basically means that when beacon 6 & 7
+ * are used we should only use the reduced pairwise key table which
+ * has a maximum of 222 entries.
+ *
+ * ---------------------------------------------
+ * |0x4000 | Pairwise Key   | Reduced Pairwise |
+ * |       | Table          | Key Table        |
+ * |       | Size: 256 * 32 | Size: 222 * 32   |
+ * |0x5BC0 |                |-------------------
+ * |       |                | Beacon 6         |
+ * |0x5DC0 |                |-------------------
+ * |       |                | Beacon 7         |
+ * |0x5FC0 |                |-------------------
+ * |0x5FFF |                |
+ * --------------------------
+ *
  * MAC_WCID_BASE: 8-bytes (use only 6 bytes) * 256 entry
  * PAIRWISE_KEY_TABLE_BASE: 32-byte * 256 entry
  * MAC_IVEIV_TABLE_BASE: 8-byte * 256-entry
@@ -1584,7 +1619,8 @@ struct mac_iveiv_entry {
  * 2. Extract memory from FCE table for BCN 4~5
  * 3. Extract memory from Pair-wise key table for BCN 6~7
  *    It occupied those memory of wcid 238~253 for BCN 6
- *    and wcid 222~237 for BCN 7
+ *    and wcid 222~237 for BCN 7 (see Security key table memory
+ *    for more info).
  *
  * IMPORTANT NOTE: Not sure why legacy driver does this,
  * but HW_BEACON_BASE7 is 0x0200 bytes below HW_BEACON_BASE6.
@@ -1963,10 +1999,17 @@ struct mac_iveiv_entry {
  * FRAG: 1 To inform TKIP engine this is a fragment.
  * MIMO_PS: The remote peer is in dynamic MIMO-PS mode
  * TX_OP: 0:HT TXOP rule , 1:PIFS TX ,2:Backoff, 3:sifs
- * BW: Channel bandwidth 20MHz or 40 MHz
+ * BW: Channel bandwidth 0:20MHz, 1:40 MHz (for legacy rates this will
+ *     duplicate the frame to both channels).
  * STBC: 1: STBC support MCS =0-7, 2,3 : RESERVED
  * AMPDU: 1: this frame is eligible for AMPDU aggregation, the hw will
- *        aggregate consecutive frames with the same RA and QoS TID.
+ *        aggregate consecutive frames with the same RA and QoS TID. If
+ *        a frame A with the same RA and QoS TID but AMPDU=0 is queued
+ *        directly after a frame B with AMPDU=1, frame A might still
+ *        get aggregated into the AMPDU started by frame B. So, setting
+ *        AMPDU to 0 does _not_ necessarily mean the frame is sent as
+ *        MPDU, it can still end up in an AMPDU if the previous frame
+ *        was tagged as AMPDU.
  */
 #define TXWI_W0_FRAG                   FIELD32(0x00000001)
 #define TXWI_W0_MIMO_PS                        FIELD32(0x00000002)
@@ -1993,6 +2036,10 @@ struct mac_iveiv_entry {
  *           frame was processed. If multiple frames are aggregated together
  *           (AMPDU==1) the reported tx status will always contain the packet
  *           id of the first frame. 0: Don't report tx status for this frame.
+ * PACKETID_QUEUE: Part of PACKETID, This is the queue index (0-3)
+ * PACKETID_ENTRY: Part of PACKETID, THis is the queue entry index (1-3)
+ *                 This identification number is calculated by ((idx % 3) + 1).
+ *                The (+1) is required to prevent PACKETID to become 0.
  */
 #define TXWI_W1_ACK                    FIELD32(0x00000001)
 #define TXWI_W1_NSEQ                   FIELD32(0x00000002)
@@ -2000,6 +2047,8 @@ struct mac_iveiv_entry {
 #define TXWI_W1_WIRELESS_CLI_ID                FIELD32(0x0000ff00)
 #define TXWI_W1_MPDU_TOTAL_BYTE_COUNT  FIELD32(0x0fff0000)
 #define TXWI_W1_PACKETID               FIELD32(0xf0000000)
+#define TXWI_W1_PACKETID_QUEUE         FIELD32(0x30000000)
+#define TXWI_W1_PACKETID_ENTRY         FIELD32(0xc0000000)
 
 /*
  * Word2
index 3bb67492d754897e663f532fc0986fcded430209..10aefc4fb0ccef1266547b2c5a419767ef660869 100644 (file)
@@ -483,7 +483,8 @@ void rt2800_write_tx_data(struct queue_entry *entry,
                           txdesc->key_idx : 0xff);
        rt2x00_set_field32(&word, TXWI_W1_MPDU_TOTAL_BYTE_COUNT,
                           txdesc->length);
-       rt2x00_set_field32(&word, TXWI_W1_PACKETID, txdesc->qid + 1);
+       rt2x00_set_field32(&word, TXWI_W1_PACKETID_QUEUE, txdesc->qid);
+       rt2x00_set_field32(&word, TXWI_W1_PACKETID_ENTRY, (entry->entry_idx % 3) + 1);
        rt2x00_desc_write(txwi, 1, word);
 
        /*
@@ -630,15 +631,90 @@ static bool rt2800_txdone_entry_check(struct queue_entry *entry, u32 reg)
        return true;
 }
 
+void rt2800_txdone_entry(struct queue_entry *entry, u32 status)
+{
+       struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+       struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
+       struct txdone_entry_desc txdesc;
+       u32 word;
+       u16 mcs, real_mcs;
+       int aggr, ampdu;
+       __le32 *txwi;
+
+       /*
+        * Obtain the status about this packet.
+        */
+       txdesc.flags = 0;
+       txwi = rt2800_drv_get_txwi(entry);
+       rt2x00_desc_read(txwi, 0, &word);
+
+       mcs = rt2x00_get_field32(word, TXWI_W0_MCS);
+       ampdu = rt2x00_get_field32(word, TXWI_W0_AMPDU);
+
+       real_mcs = rt2x00_get_field32(status, TX_STA_FIFO_MCS);
+       aggr = rt2x00_get_field32(status, TX_STA_FIFO_TX_AGGRE);
+
+       /*
+        * If a frame was meant to be sent as a single non-aggregated MPDU
+        * but ended up in an aggregate the used tx rate doesn't correlate
+        * with the one specified in the TXWI as the whole aggregate is sent
+        * with the same rate.
+        *
+        * For example: two frames are sent to rt2x00, the first one sets
+        * AMPDU=1 and requests MCS7 whereas the second frame sets AMDPU=0
+        * and requests MCS15. If the hw aggregates both frames into one
+        * AMDPU the tx status for both frames will contain MCS7 although
+        * the frame was sent successfully.
+        *
+        * Hence, replace the requested rate with the real tx rate to not
+        * confuse the rate control algortihm by providing clearly wrong
+        * data.
+        */
+       if (aggr == 1 && ampdu == 0 && real_mcs != mcs) {
+               skbdesc->tx_rate_idx = real_mcs;
+               mcs = real_mcs;
+       }
+
+       /*
+        * Ralink has a retry mechanism using a global fallback
+        * table. We setup this fallback table to try the immediate
+        * lower rate for all rates. In the TX_STA_FIFO, the MCS field
+        * always contains the MCS used for the last transmission, be
+        * it successful or not.
+        */
+       if (rt2x00_get_field32(status, TX_STA_FIFO_TX_SUCCESS)) {
+               /*
+                * Transmission succeeded. The number of retries is
+                * mcs - real_mcs
+                */
+               __set_bit(TXDONE_SUCCESS, &txdesc.flags);
+               txdesc.retry = ((mcs > real_mcs) ? mcs - real_mcs : 0);
+       } else {
+               /*
+                * Transmission failed. The number of retries is
+                * always 7 in this case (for a total number of 8
+                * frames sent).
+                */
+               __set_bit(TXDONE_FAILURE, &txdesc.flags);
+               txdesc.retry = rt2x00dev->long_retry;
+       }
+
+       /*
+        * the frame was retried at least once
+        * -> hw used fallback rates
+        */
+       if (txdesc.retry)
+               __set_bit(TXDONE_FALLBACK, &txdesc.flags);
+
+       rt2x00lib_txdone(entry, &txdesc);
+}
+EXPORT_SYMBOL_GPL(rt2800_txdone_entry);
+
 void rt2800_txdone(struct rt2x00_dev *rt2x00dev)
 {
        struct data_queue *queue;
        struct queue_entry *entry;
-       __le32 *txwi;
-       struct txdone_entry_desc txdesc;
-       u32 word;
        u32 reg;
-       u16 mcs, real_mcs;
        u8 pid;
        int i;
 
@@ -660,7 +736,7 @@ void rt2800_txdone(struct rt2x00_dev *rt2x00dev)
                 * Skip this entry when it contains an invalid
                 * queue identication number.
                 */
-               pid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE) - 1;
+               pid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_QUEUE);
                if (pid >= QID_RX)
                        continue;
 
@@ -673,7 +749,6 @@ void rt2800_txdone(struct rt2x00_dev *rt2x00dev)
                 * order. We first check that the queue is not empty.
                 */
                entry = NULL;
-               txwi = NULL;
                while (!rt2x00queue_empty(queue)) {
                        entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
                        if (rt2800_txdone_entry_check(entry, reg))
@@ -683,48 +758,7 @@ void rt2800_txdone(struct rt2x00_dev *rt2x00dev)
                if (!entry || rt2x00queue_empty(queue))
                        break;
 
-
-               /*
-                * Obtain the status about this packet.
-                */
-               txdesc.flags = 0;
-               txwi = rt2800_drv_get_txwi(entry);
-               rt2x00_desc_read(txwi, 0, &word);
-               mcs = rt2x00_get_field32(word, TXWI_W0_MCS);
-               real_mcs = rt2x00_get_field32(reg, TX_STA_FIFO_MCS);
-
-               /*
-                * Ralink has a retry mechanism using a global fallback
-                * table. We setup this fallback table to try the immediate
-                * lower rate for all rates. In the TX_STA_FIFO, the MCS field
-                * always contains the MCS used for the last transmission, be
-                * it successful or not.
-                */
-               if (rt2x00_get_field32(reg, TX_STA_FIFO_TX_SUCCESS)) {
-                       /*
-                        * Transmission succeeded. The number of retries is
-                        * mcs - real_mcs
-                        */
-                       __set_bit(TXDONE_SUCCESS, &txdesc.flags);
-                       txdesc.retry = ((mcs > real_mcs) ? mcs - real_mcs : 0);
-               } else {
-                       /*
-                        * Transmission failed. The number of retries is
-                        * always 7 in this case (for a total number of 8
-                        * frames sent).
-                        */
-                       __set_bit(TXDONE_FAILURE, &txdesc.flags);
-                       txdesc.retry = rt2x00dev->long_retry;
-               }
-
-               /*
-                * the frame was retried at least once
-                * -> hw used fallback rates
-                */
-               if (txdesc.retry)
-                       __set_bit(TXDONE_FALLBACK, &txdesc.flags);
-
-               rt2x00lib_txdone(entry, &txdesc);
+               rt2800_txdone_entry(entry, reg);
        }
 }
 EXPORT_SYMBOL_GPL(rt2800_txdone);
@@ -1031,8 +1065,12 @@ int rt2800_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
                 * 1 pairwise key is possible per AID, this means that the AID
                 * equals our hw_key_idx. Make sure the WCID starts _after_ the
                 * last possible shared key entry.
+                *
+                * Since parts of the pairwise key table might be shared with
+                * the beacon frame buffers 6 & 7 we should only write into the
+                * first 222 entries.
                 */
-               if (crypto->aid > (256 - 32))
+               if (crypto->aid > (222 - 32))
                        return -ENOSPC;
 
                key->hw_key_idx = 32 + crypto->aid;
@@ -1159,6 +1197,102 @@ void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf,
 }
 EXPORT_SYMBOL_GPL(rt2800_config_intf);
 
+static void rt2800_config_ht_opmode(struct rt2x00_dev *rt2x00dev,
+                                   struct rt2x00lib_erp *erp)
+{
+       bool any_sta_nongf = !!(erp->ht_opmode &
+                               IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
+       u8 protection = erp->ht_opmode & IEEE80211_HT_OP_MODE_PROTECTION;
+       u8 mm20_mode, mm40_mode, gf20_mode, gf40_mode;
+       u16 mm20_rate, mm40_rate, gf20_rate, gf40_rate;
+       u32 reg;
+
+       /* default protection rate for HT20: OFDM 24M */
+       mm20_rate = gf20_rate = 0x4004;
+
+       /* default protection rate for HT40: duplicate OFDM 24M */
+       mm40_rate = gf40_rate = 0x4084;
+
+       switch (protection) {
+       case IEEE80211_HT_OP_MODE_PROTECTION_NONE:
+               /*
+                * All STAs in this BSS are HT20/40 but there might be
+                * STAs not supporting greenfield mode.
+                * => Disable protection for HT transmissions.
+                */
+               mm20_mode = mm40_mode = gf20_mode = gf40_mode = 0;
+
+               break;
+       case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ:
+               /*
+                * All STAs in this BSS are HT20 or HT20/40 but there
+                * might be STAs not supporting greenfield mode.
+                * => Protect all HT40 transmissions.
+                */
+               mm20_mode = gf20_mode = 0;
+               mm40_mode = gf40_mode = 2;
+
+               break;
+       case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER:
+               /*
+                * Nonmember protection:
+                * According to 802.11n we _should_ protect all
+                * HT transmissions (but we don't have to).
+                *
+                * But if cts_protection is enabled we _shall_ protect
+                * all HT transmissions using a CCK rate.
+                *
+                * And if any station is non GF we _shall_ protect
+                * GF transmissions.
+                *
+                * We decide to protect everything
+                * -> fall through to mixed mode.
+                */
+       case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED:
+               /*
+                * Legacy STAs are present
+                * => Protect all HT transmissions.
+                */
+               mm20_mode = mm40_mode = gf20_mode = gf40_mode = 2;
+
+               /*
+                * If erp protection is needed we have to protect HT
+                * transmissions with CCK 11M long preamble.
+                */
+               if (erp->cts_protection) {
+                       /* don't duplicate RTS/CTS in CCK mode */
+                       mm20_rate = mm40_rate = 0x0003;
+                       gf20_rate = gf40_rate = 0x0003;
+               }
+               break;
+       };
+
+       /* check for STAs not supporting greenfield mode */
+       if (any_sta_nongf)
+               gf20_mode = gf40_mode = 2;
+
+       /* Update HT protection config */
+       rt2800_register_read(rt2x00dev, MM20_PROT_CFG, &reg);
+       rt2x00_set_field32(&reg, MM20_PROT_CFG_PROTECT_RATE, mm20_rate);
+       rt2x00_set_field32(&reg, MM20_PROT_CFG_PROTECT_CTRL, mm20_mode);
+       rt2800_register_write(rt2x00dev, MM20_PROT_CFG, reg);
+
+       rt2800_register_read(rt2x00dev, MM40_PROT_CFG, &reg);
+       rt2x00_set_field32(&reg, MM40_PROT_CFG_PROTECT_RATE, mm40_rate);
+       rt2x00_set_field32(&reg, MM40_PROT_CFG_PROTECT_CTRL, mm40_mode);
+       rt2800_register_write(rt2x00dev, MM40_PROT_CFG, reg);
+
+       rt2800_register_read(rt2x00dev, GF20_PROT_CFG, &reg);
+       rt2x00_set_field32(&reg, GF20_PROT_CFG_PROTECT_RATE, gf20_rate);
+       rt2x00_set_field32(&reg, GF20_PROT_CFG_PROTECT_CTRL, gf20_mode);
+       rt2800_register_write(rt2x00dev, GF20_PROT_CFG, reg);
+
+       rt2800_register_read(rt2x00dev, GF40_PROT_CFG, &reg);
+       rt2x00_set_field32(&reg, GF40_PROT_CFG_PROTECT_RATE, gf40_rate);
+       rt2x00_set_field32(&reg, GF40_PROT_CFG_PROTECT_CTRL, gf40_mode);
+       rt2800_register_write(rt2x00dev, GF40_PROT_CFG, reg);
+}
+
 void rt2800_config_erp(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_erp *erp,
                       u32 changed)
 {
@@ -1203,6 +1337,9 @@ void rt2800_config_erp(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_erp *erp,
                                   erp->beacon_int * 16);
                rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
        }
+
+       if (changed & BSS_CHANGED_HT)
+               rt2800_config_ht_opmode(rt2x00dev, erp);
 }
 EXPORT_SYMBOL_GPL(rt2800_config_erp);
 
@@ -1907,8 +2044,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
 
        rt2800_register_read(rt2x00dev, MM40_PROT_CFG, &reg);
        rt2x00_set_field32(&reg, MM40_PROT_CFG_PROTECT_RATE, 0x4084);
-       rt2x00_set_field32(&reg, MM40_PROT_CFG_PROTECT_CTRL,
-                          !rt2x00_is_usb(rt2x00dev));
+       rt2x00_set_field32(&reg, MM40_PROT_CFG_PROTECT_CTRL, 0);
        rt2x00_set_field32(&reg, MM40_PROT_CFG_PROTECT_NAV, 1);
        rt2x00_set_field32(&reg, MM40_PROT_CFG_TX_OP_ALLOW_CCK, 1);
        rt2x00_set_field32(&reg, MM40_PROT_CFG_TX_OP_ALLOW_OFDM, 1);
@@ -3056,11 +3192,20 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
         * Initialize all hw fields.
         */
        rt2x00dev->hw->flags =
-           IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
            IEEE80211_HW_SIGNAL_DBM |
            IEEE80211_HW_SUPPORTS_PS |
            IEEE80211_HW_PS_NULLFUNC_STACK |
            IEEE80211_HW_AMPDU_AGGREGATION;
+       /*
+        * Don't set IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING for USB devices
+        * unless we are capable of sending the buffered frames out after the
+        * DTIM transmission using rt2x00lib_beacondone. This will send out
+        * multicast and broadcast traffic immediately instead of buffering it
+        * infinitly and thus dropping it after some time.
+        */
+       if (!rt2x00_is_usb(rt2x00dev))
+               rt2x00dev->hw->flags |=
+                       IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
 
        SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
        SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
@@ -3071,12 +3216,13 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
         * As rt2800 has a global fallback table we cannot specify
         * more then one tx rate per frame but since the hw will
         * try several rates (based on the fallback table) we should
-        * still initialize max_rates to the maximum number of rates
+        * initialize max_report_rates to the maximum number of rates
         * we are going to try. Otherwise mac80211 will truncate our
         * reported tx rates and the rc algortihm will end up with
         * incorrect data.
         */
-       rt2x00dev->hw->max_rates = 7;
+       rt2x00dev->hw->max_rates = 1;
+       rt2x00dev->hw->max_report_rates = 7;
        rt2x00dev->hw->max_rate_tries = 1;
 
        rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom);
@@ -3333,8 +3479,12 @@ int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
        switch (action) {
        case IEEE80211_AMPDU_RX_START:
        case IEEE80211_AMPDU_RX_STOP:
-               /* we don't support RX aggregation yet */
-               ret = -ENOTSUPP;
+               /*
+                * The hw itself takes care of setting up BlockAck mechanisms.
+                * So, we only have to allow mac80211 to nagotiate a BlockAck
+                * agreement. Once that is done, the hw will BlockAck incoming
+                * AMPDUs without further setup.
+                */
                break;
        case IEEE80211_AMPDU_TX_START:
                ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
index 600c5eb25c41914029a778ec63b95e135d5a143a..81cbc92e7857ed040c6bf123897a5f908857c819 100644 (file)
@@ -153,6 +153,7 @@ void rt2800_write_tx_data(struct queue_entry *entry,
 void rt2800_process_rxwi(struct queue_entry *entry, struct rxdone_entry_desc *txdesc);
 
 void rt2800_txdone(struct rt2x00_dev *rt2x00dev);
+void rt2800_txdone_entry(struct queue_entry *entry, u32 status);
 
 void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc);
 
index 005ee153e0ccf244296ca60f5d02ef1ec32951d5..85a134cd62bfdade64d2a448c5e0b742af60bfe2 100644 (file)
@@ -241,6 +241,7 @@ static void rt2800pci_clear_entry(struct queue_entry *entry)
 {
        struct queue_entry_priv_pci *entry_priv = entry->priv_data;
        struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
+       struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
        u32 word;
 
        if (entry->queue->qid == QID_RX) {
@@ -251,6 +252,13 @@ static void rt2800pci_clear_entry(struct queue_entry *entry)
                rt2x00_desc_read(entry_priv->desc, 1, &word);
                rt2x00_set_field32(&word, RXD_W1_DMA_DONE, 0);
                rt2x00_desc_write(entry_priv->desc, 1, word);
+
+               /*
+                * Set RX IDX in register to inform hardware that we have
+                * handled this entry and it is available for reuse again.
+                */
+               rt2800_register_write(rt2x00dev, RX_CRX_IDX,
+                                     entry->entry_idx);
        } else {
                rt2x00_desc_read(entry_priv->desc, 1, &word);
                rt2x00_set_field32(&word, TXD_W1_DMA_DONE, 1);
@@ -599,7 +607,6 @@ static void rt2800pci_kill_tx_queue(struct data_queue *queue)
 static void rt2800pci_fill_rxdone(struct queue_entry *entry,
                                  struct rxdone_entry_desc *rxdesc)
 {
-       struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
        struct queue_entry_priv_pci *entry_priv = entry->priv_data;
        __le32 *rxd = entry_priv->desc;
        u32 word;
@@ -641,12 +648,6 @@ static void rt2800pci_fill_rxdone(struct queue_entry *entry,
         * Process the RXWI structure that is at the start of the buffer.
         */
        rt2800_process_rxwi(entry, rxdesc);
-
-       /*
-        * Set RX IDX in register to inform hardware that we have handled
-        * this entry and it is available for reuse again.
-        */
-       rt2800_register_write(rt2x00dev, RX_CRX_IDX, entry->entry_idx);
 }
 
 /*
@@ -660,6 +661,63 @@ static void rt2800pci_wakeup(struct rt2x00_dev *rt2x00dev)
        rt2800_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS);
 }
 
+static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev)
+{
+       struct data_queue *queue;
+       struct queue_entry *entry;
+       u32 status;
+       u8 qid;
+
+       while (!kfifo_is_empty(&rt2x00dev->txstatus_fifo)) {
+               /* Now remove the tx status from the FIFO */
+               if (kfifo_out(&rt2x00dev->txstatus_fifo, &status,
+                             sizeof(status)) != sizeof(status)) {
+                       WARN_ON(1);
+                       break;
+               }
+
+               qid = rt2x00_get_field32(status, TX_STA_FIFO_PID_TYPE) - 1;
+               if (qid >= QID_RX) {
+                       /*
+                        * Unknown queue, this shouldn't happen. Just drop
+                        * this tx status.
+                        */
+                       WARNING(rt2x00dev, "Got TX status report with "
+                                          "unexpected pid %u, dropping", qid);
+                       break;
+               }
+
+               queue = rt2x00queue_get_queue(rt2x00dev, qid);
+               if (unlikely(queue == NULL)) {
+                       /*
+                        * The queue is NULL, this shouldn't happen. Stop
+                        * processing here and drop the tx status
+                        */
+                       WARNING(rt2x00dev, "Got TX status for an unavailable "
+                                          "queue %u, dropping", qid);
+                       break;
+               }
+
+               if (rt2x00queue_empty(queue)) {
+                       /*
+                        * The queue is empty. Stop processing here
+                        * and drop the tx status.
+                        */
+                       WARNING(rt2x00dev, "Got TX status for an empty "
+                                          "queue %u, dropping", qid);
+                       break;
+               }
+
+               entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
+               rt2800_txdone_entry(entry, status);
+       }
+}
+
+static void rt2800pci_txstatus_tasklet(unsigned long data)
+{
+       rt2800pci_txdone((struct rt2x00_dev *)data);
+}
+
 static irqreturn_t rt2800pci_interrupt_thread(int irq, void *dev_instance)
 {
        struct rt2x00_dev *rt2x00dev = dev_instance;
@@ -684,13 +742,7 @@ static irqreturn_t rt2800pci_interrupt_thread(int irq, void *dev_instance)
                rt2x00pci_rxdone(rt2x00dev);
 
        /*
-        * 4 - Tx done interrupt.
-        */
-       if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS))
-               rt2800_txdone(rt2x00dev);
-
-       /*
-        * 5 - Auto wakeup interrupt.
+        * 4 - Auto wakeup interrupt.
         */
        if (rt2x00_get_field32(reg, INT_SOURCE_CSR_AUTO_WAKEUP))
                rt2800pci_wakeup(rt2x00dev);
@@ -702,10 +754,58 @@ static irqreturn_t rt2800pci_interrupt_thread(int irq, void *dev_instance)
        return IRQ_HANDLED;
 }
 
+static void rt2800pci_txstatus_interrupt(struct rt2x00_dev *rt2x00dev)
+{
+       u32 status;
+       int i;
+
+       /*
+        * The TX_FIFO_STATUS interrupt needs special care. We should
+        * read TX_STA_FIFO but we should do it immediately as otherwise
+        * the register can overflow and we would lose status reports.
+        *
+        * Hence, read the TX_STA_FIFO register and copy all tx status
+        * reports into a kernel FIFO which is handled in the txstatus
+        * tasklet. We use a tasklet to process the tx status reports
+        * because we can schedule the tasklet multiple times (when the
+        * interrupt fires again during tx status processing).
+        *
+        * Furthermore we don't disable the TX_FIFO_STATUS
+        * interrupt here but leave it enabled so that the TX_STA_FIFO
+        * can also be read while the interrupt thread gets executed.
+        *
+        * Since we have only one producer and one consumer we don't
+        * need to lock the kfifo.
+        */
+       for (i = 0; i < TX_ENTRIES; i++) {
+               rt2800_register_read(rt2x00dev, TX_STA_FIFO, &status);
+
+               if (!rt2x00_get_field32(status, TX_STA_FIFO_VALID))
+                       break;
+
+               if (kfifo_is_full(&rt2x00dev->txstatus_fifo)) {
+                       WARNING(rt2x00dev, "TX status FIFO overrun,"
+                               " drop tx status report.\n");
+                       break;
+               }
+
+               if (kfifo_in(&rt2x00dev->txstatus_fifo, &status,
+                            sizeof(status)) != sizeof(status)) {
+                       WARNING(rt2x00dev, "TX status FIFO overrun,"
+                               "drop tx status report.\n");
+                       break;
+               }
+       }
+
+       /* Schedule the tasklet for processing the tx status. */
+       tasklet_schedule(&rt2x00dev->txstatus_tasklet);
+}
+
 static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance)
 {
        struct rt2x00_dev *rt2x00dev = dev_instance;
        u32 reg;
+       irqreturn_t ret = IRQ_HANDLED;
 
        /* Read status and ACK all interrupts */
        rt2800_register_read(rt2x00dev, INT_SOURCE_CSR, &reg);
@@ -717,15 +817,38 @@ static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance)
        if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
                return IRQ_HANDLED;
 
-       /* Store irqvalue for use in the interrupt thread. */
-       rt2x00dev->irqvalue[0] = reg;
+       if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS))
+               rt2800pci_txstatus_interrupt(rt2x00dev);
 
-       /* Disable interrupts, will be enabled again in the interrupt thread. */
-       rt2x00dev->ops->lib->set_device_state(rt2x00dev,
-                                             STATE_RADIO_IRQ_OFF_ISR);
+       if (rt2x00_get_field32(reg, INT_SOURCE_CSR_PRE_TBTT) ||
+           rt2x00_get_field32(reg, INT_SOURCE_CSR_TBTT) ||
+           rt2x00_get_field32(reg, INT_SOURCE_CSR_RX_DONE) ||
+           rt2x00_get_field32(reg, INT_SOURCE_CSR_AUTO_WAKEUP)) {
+               /*
+                * All other interrupts are handled in the interrupt thread.
+                * Store irqvalue for use in the interrupt thread.
+                */
+               rt2x00dev->irqvalue[0] = reg;
+
+               /*
+                * Disable interrupts, will be enabled again in the
+                * interrupt thread.
+               */
+               rt2x00dev->ops->lib->set_device_state(rt2x00dev,
+                                                     STATE_RADIO_IRQ_OFF_ISR);
+
+               /*
+                * Leave the TX_FIFO_STATUS interrupt enabled to not lose any
+                * tx status reports.
+                */
+               rt2800_register_read(rt2x00dev, INT_MASK_CSR, &reg);
+               rt2x00_set_field32(&reg, INT_MASK_CSR_TX_FIFO_STATUS, 1);
+               rt2800_register_write(rt2x00dev, INT_MASK_CSR, reg);
 
+               ret = IRQ_WAKE_THREAD;
+       }
 
-       return IRQ_WAKE_THREAD;
+       return ret;
 }
 
 /*
@@ -788,6 +911,7 @@ static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev)
                __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags);
        __set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags);
        __set_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags);
+       __set_bit(DRIVER_REQUIRE_TXSTATUS_FIFO, &rt2x00dev->flags);
        if (!modparam_nohwcrypt)
                __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags);
        __set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags);
@@ -837,6 +961,7 @@ static const struct rt2800_ops rt2800pci_rt2800_ops = {
 static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = {
        .irq_handler            = rt2800pci_interrupt,
        .irq_handler_thread     = rt2800pci_interrupt_thread,
+       .txstatus_tasklet       = rt2800pci_txstatus_tasklet,
        .probe_hw               = rt2800pci_probe_hw,
        .get_firmware_name      = rt2800pci_get_firmware_name,
        .check_firmware         = rt2800_check_firmware,
index 7832a5996a8c94b53d38ae70922025081f43e0c0..75ac6624bf9e3914d9e571d03526cf5ea19cd4eb 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/mutex.h>
 #include <linux/etherdevice.h>
 #include <linux/input-polldev.h>
+#include <linux/kfifo.h>
 
 #include <net/mac80211.h>
 
@@ -457,6 +458,7 @@ struct rt2x00lib_erp {
        short eifs;
 
        u16 beacon_int;
+       u16 ht_opmode;
 };
 
 /*
@@ -521,6 +523,11 @@ struct rt2x00lib_ops {
         */
        irq_handler_t irq_handler_thread;
 
+       /*
+        * TX status tasklet handler.
+        */
+       void (*txstatus_tasklet) (unsigned long data);
+
        /*
         * Device init handlers.
         */
@@ -651,6 +658,7 @@ enum rt2x00_flags {
        DRIVER_REQUIRE_DMA,
        DRIVER_REQUIRE_COPY_IV,
        DRIVER_REQUIRE_L2PAD,
+       DRIVER_REQUIRE_TXSTATUS_FIFO,
 
        /*
         * Driver features
@@ -884,6 +892,16 @@ struct rt2x00_dev {
         * and interrupt thread routine.
         */
        u32 irqvalue[2];
+
+       /*
+        * FIFO for storing tx status reports between isr and tasklet.
+        */
+       struct kfifo txstatus_fifo;
+
+       /*
+        * Tasklet for processing tx status reports (rt2800pci).
+        */
+       struct tasklet_struct txstatus_tasklet;
 };
 
 /*
index 4c7ff765a8bf5f2ba80dbcd992d6d6327ad7de19..54ffb5aeb34e4b808f1a94bcf8e6de7463883893 100644 (file)
@@ -103,6 +103,9 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev,
        /* Update global beacon interval time, this is needed for PS support */
        rt2x00dev->beacon_int = bss_conf->beacon_int;
 
+       if (changed & BSS_CHANGED_HT)
+               erp.ht_opmode = bss_conf->ht_operation_mode;
+
        rt2x00dev->ops->lib->config_erp(rt2x00dev, &erp, changed);
 }
 
index 053fdd3bd7206c56836a7aa73aed12e155edd026..6f442b02b83ed0282c41b1ee2710d52f967ad43d 100644 (file)
@@ -812,6 +812,30 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev)
        else if (test_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags))
                rt2x00dev->hw->extra_tx_headroom += RT2X00_ALIGN_SIZE;
 
+       /*
+        * Allocate tx status FIFO for driver use.
+        */
+       if (test_bit(DRIVER_REQUIRE_TXSTATUS_FIFO, &rt2x00dev->flags) &&
+           rt2x00dev->ops->lib->txstatus_tasklet) {
+               /*
+                * Allocate txstatus fifo and tasklet, we use a size of 512
+                * for the kfifo which is big enough to store 512/4=128 tx
+                * status reports. In the worst case (tx status for all tx
+                * queues gets reported before we've got a chance to handle
+                * them) 24*4=384 tx status reports need to be cached.
+                */
+               status = kfifo_alloc(&rt2x00dev->txstatus_fifo, 512,
+                                    GFP_KERNEL);
+               if (status)
+                       return status;
+
+               /* tasklet for processing the tx status reports. */
+               tasklet_init(&rt2x00dev->txstatus_tasklet,
+                            rt2x00dev->ops->lib->txstatus_tasklet,
+                            (unsigned long)rt2x00dev);
+
+       }
+
        /*
         * Register HW.
         */
@@ -909,10 +933,8 @@ int rt2x00lib_start(struct rt2x00_dev *rt2x00dev)
 
        /* Enable the radio */
        retval = rt2x00lib_enable_radio(rt2x00dev);
-       if (retval) {
-               rt2x00queue_uninitialize(rt2x00dev);
+       if (retval)
                return retval;
-       }
 
        set_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags);
 
@@ -1027,6 +1049,16 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev)
        cancel_work_sync(&rt2x00dev->rxdone_work);
        cancel_work_sync(&rt2x00dev->txdone_work);
 
+       /*
+        * Free the tx status fifo.
+        */
+       kfifo_free(&rt2x00dev->txstatus_fifo);
+
+       /*
+        * Kill the tx status tasklet.
+        */
+       tasklet_kill(&rt2x00dev->txstatus_tasklet);
+
        /*
         * Uninitialize device.
         */
index ad3c7ff4837b5bc96fb4efc6e74d69aa84fefe0c..c637bcaec5f8d6ef37320950f5bf9964f4bde675 100644 (file)
@@ -60,9 +60,10 @@ void rt2x00ht_create_tx_descriptor(struct queue_entry *entry,
                 * when using more then one tx stream (>MCS7).
                 */
                if (tx_info->control.sta && txdesc->mcs > 7 &&
-                   (tx_info->control.sta->ht_cap.cap &
-                    (WLAN_HT_CAP_SM_PS_DYNAMIC <<
-                     IEEE80211_HT_CAP_SM_PS_SHIFT)))
+                   ((tx_info->control.sta->ht_cap.cap &
+                     IEEE80211_HT_CAP_SM_PS) >>
+                    IEEE80211_HT_CAP_SM_PS_SHIFT) ==
+                   WLAN_HT_CAP_SM_PS_DYNAMIC)
                        __set_bit(ENTRY_TXD_HT_MIMO_PS, &txdesc->flags);
        } else {
                txdesc->mcs = rt2x00_get_rate_mcs(hwrate->mcs);
@@ -72,9 +73,11 @@ void rt2x00ht_create_tx_descriptor(struct queue_entry *entry,
 
 
        /*
-        * Convert flags
+        * This frame is eligible for an AMPDU, however, don't aggregate
+        * frames that are intended to probe a specific tx rate.
         */
-       if (tx_info->flags & IEEE80211_TX_CTL_AMPDU)
+       if (tx_info->flags & IEEE80211_TX_CTL_AMPDU &&
+           !(tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE))
                __set_bit(ENTRY_TXD_HT_AMPDU, &txdesc->flags);
 
        /*
@@ -84,7 +87,13 @@ void rt2x00ht_create_tx_descriptor(struct queue_entry *entry,
                txdesc->rate_mode = RATE_MODE_HT_MIX;
        if (txrate->flags & IEEE80211_TX_RC_GREEN_FIELD)
                txdesc->rate_mode = RATE_MODE_HT_GREENFIELD;
-       if (txrate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+
+       /*
+        * Set 40Mhz mode if necessary (for legacy rates this will
+        * duplicate the frame to both channels).
+        */
+       if (txrate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH ||
+           txrate->flags & IEEE80211_TX_RC_DUP_DATA)
                __set_bit(ENTRY_TXD_HT_BW_40, &txdesc->flags);
        if (txrate->flags & IEEE80211_TX_RC_SHORT_GI)
                __set_bit(ENTRY_TXD_HT_SHORT_GI, &txdesc->flags);
index 7862a840984a8a0229cdc1a4c716fd5f41bdc81d..c3c206a97d54c608da497256a7fcadd44293d9df 100644 (file)
@@ -671,7 +671,7 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
         */
        if (changes & (BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_ERP_PREAMBLE |
                       BSS_CHANGED_ERP_SLOT | BSS_CHANGED_BASIC_RATES |
-                      BSS_CHANGED_BEACON_INT))
+                      BSS_CHANGED_BEACON_INT | BSS_CHANGED_HT))
                rt2x00lib_config_erp(rt2x00dev, intf, bss_conf, changes);
 }
 EXPORT_SYMBOL_GPL(rt2x00mac_bss_info_changed);
index 97b3935f615bfd4388a80cec84ff8bda850c220a..af548c87f1084a6d641430bfd5fbf84bef52b8a0 100644 (file)
@@ -2630,12 +2630,13 @@ static int rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
         * As rt61 has a global fallback table we cannot specify
         * more then one tx rate per frame but since the hw will
         * try several rates (based on the fallback table) we should
-        * still initialize max_rates to the maximum number of rates
+        * initialize max_report_rates to the maximum number of rates
         * we are going to try. Otherwise mac80211 will truncate our
         * reported tx rates and the rc algortihm will end up with
         * incorrect data.
         */
-       rt2x00dev->hw->max_rates = 7;
+       rt2x00dev->hw->max_rates = 1;
+       rt2x00dev->hw->max_report_rates = 7;
        rt2x00dev->hw->max_rate_tries = 1;
 
        /*
index e22f01c1818e141a5802b29b14a4f15e13d71b78..9be8089317e4b1a6ffe7921f9d46bae9336b7cc7 100644 (file)
@@ -2063,9 +2063,14 @@ static int rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
 
        /*
         * Initialize all hw fields.
+        *
+        * Don't set IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING unless we are
+        * capable of sending the buffered frames out after the DTIM
+        * transmission using rt2x00lib_beacondone. This will send out
+        * multicast and broadcast traffic immediately instead of buffering it
+        * infinitly and thus dropping it after some time.
         */
        rt2x00dev->hw->flags =
-           IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
            IEEE80211_HW_SIGNAL_DBM |
            IEEE80211_HW_SUPPORTS_PS |
            IEEE80211_HW_PS_NULLFUNC_STACK;
@@ -2365,6 +2370,7 @@ static struct usb_device_id rt73usb_device_table[] = {
        { USB_DEVICE(0x0411, 0x00f4), USB_DEVICE_DATA(&rt73usb_ops) },
        { USB_DEVICE(0x0411, 0x0116), USB_DEVICE_DATA(&rt73usb_ops) },
        { USB_DEVICE(0x0411, 0x0119), USB_DEVICE_DATA(&rt73usb_ops) },
+       { USB_DEVICE(0x0411, 0x0137), USB_DEVICE_DATA(&rt73usb_ops) },
        /* CEIVA */
        { USB_DEVICE(0x178d, 0x02be), USB_DEVICE_DATA(&rt73usb_ops) },
        /* CNet */
index 05c6badbe201a892eb57a431ebdffd5d1630efcf..707c688da618f7728d988dccbccb8b78ea52ab22 100644 (file)
@@ -99,66 +99,19 @@ void rtl8180_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data)
        }
 }
 
-static void rtl8180_handle_tx(struct ieee80211_hw *dev)
+static void rtl8180_handle_rx(struct ieee80211_hw *dev)
 {
        struct rtl8180_priv *priv = dev->priv;
-       struct rtl8180_tx_ring *ring;
-       int prio;
-
-       spin_lock(&priv->lock);
-
-       for (prio = 3; prio >= 0; prio--) {
-               ring = &priv->tx_ring[prio];
-
-               while (skb_queue_len(&ring->queue)) {
-                       struct rtl8180_tx_desc *entry = &ring->desc[ring->idx];
-                       struct sk_buff *skb;
-                       struct ieee80211_tx_info *info;
-                       u32 flags = le32_to_cpu(entry->flags);
-
-                       if (flags & RTL818X_TX_DESC_FLAG_OWN)
-                               break;
-
-                       ring->idx = (ring->idx + 1) % ring->entries;
-                       skb = __skb_dequeue(&ring->queue);
-                       pci_unmap_single(priv->pdev, le32_to_cpu(entry->tx_buf),
-                                        skb->len, PCI_DMA_TODEVICE);
-
-                       info = IEEE80211_SKB_CB(skb);
-                       ieee80211_tx_info_clear_status(info);
-
-                       if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) &&
-                           (flags & RTL818X_TX_DESC_FLAG_TX_OK))
-                               info->flags |= IEEE80211_TX_STAT_ACK;
-
-                       info->status.rates[0].count = (flags & 0xFF) + 1;
-                       info->status.rates[1].idx = -1;
-
-                       ieee80211_tx_status(dev, skb);
-                       if (ring->entries - skb_queue_len(&ring->queue) == 2)
-                               ieee80211_wake_queue(dev, prio);
-               }
-       }
-
-       spin_unlock(&priv->lock);
-}
-
-static int rtl8180_poll(struct ieee80211_hw *dev, int budget)
-{
-       struct rtl8180_priv *priv = dev->priv;
-       unsigned int count = 0;
+       unsigned int count = 32;
        u8 signal, agc, sq;
 
-       /* handle pending Tx queue cleanup */
-       rtl8180_handle_tx(dev);
-
-       while (count++ < budget) {
+       while (count--) {
                struct rtl8180_rx_desc *entry = &priv->rx_ring[priv->rx_idx];
                struct sk_buff *skb = priv->rx_buf[priv->rx_idx];
                u32 flags = le32_to_cpu(entry->flags);
 
                if (flags & RTL818X_RX_DESC_FLAG_OWN)
-                       break;
+                       return;
 
                if (unlikely(flags & (RTL818X_RX_DESC_FLAG_DMA_FAIL |
                                      RTL818X_RX_DESC_FLAG_FOF |
@@ -198,7 +151,7 @@ static int rtl8180_poll(struct ieee80211_hw *dev, int budget)
                                rx_status.flag |= RX_FLAG_FAILED_FCS_CRC;
 
                        memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status));
-                       ieee80211_rx(dev, skb);
+                       ieee80211_rx_irqsafe(dev, skb);
 
                        skb = new_skb;
                        priv->rx_buf[priv->rx_idx] = skb;
@@ -215,16 +168,41 @@ static int rtl8180_poll(struct ieee80211_hw *dev, int budget)
                        entry->flags |= cpu_to_le32(RTL818X_RX_DESC_FLAG_EOR);
                priv->rx_idx = (priv->rx_idx + 1) % 32;
        }
+}
+
+static void rtl8180_handle_tx(struct ieee80211_hw *dev, unsigned int prio)
+{
+       struct rtl8180_priv *priv = dev->priv;
+       struct rtl8180_tx_ring *ring = &priv->tx_ring[prio];
 
-       if (count < budget) {
-               /* disable polling */
-               ieee80211_napi_complete(dev);
+       while (skb_queue_len(&ring->queue)) {
+               struct rtl8180_tx_desc *entry = &ring->desc[ring->idx];
+               struct sk_buff *skb;
+               struct ieee80211_tx_info *info;
+               u32 flags = le32_to_cpu(entry->flags);
 
-               /* enable interrupts */
-               rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0xFFFF);
-       }
+               if (flags & RTL818X_TX_DESC_FLAG_OWN)
+                       return;
+
+               ring->idx = (ring->idx + 1) % ring->entries;
+               skb = __skb_dequeue(&ring->queue);
+               pci_unmap_single(priv->pdev, le32_to_cpu(entry->tx_buf),
+                                skb->len, PCI_DMA_TODEVICE);
+
+               info = IEEE80211_SKB_CB(skb);
+               ieee80211_tx_info_clear_status(info);
+
+               if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) &&
+                   (flags & RTL818X_TX_DESC_FLAG_TX_OK))
+                       info->flags |= IEEE80211_TX_STAT_ACK;
+
+               info->status.rates[0].count = (flags & 0xFF) + 1;
+               info->status.rates[1].idx = -1;
 
-       return count;
+               ieee80211_tx_status_irqsafe(dev, skb);
+               if (ring->entries - skb_queue_len(&ring->queue) == 2)
+                       ieee80211_wake_queue(dev, prio);
+       }
 }
 
 static irqreturn_t rtl8180_interrupt(int irq, void *dev_id)
@@ -233,17 +211,31 @@ static irqreturn_t rtl8180_interrupt(int irq, void *dev_id)
        struct rtl8180_priv *priv = dev->priv;
        u16 reg;
 
+       spin_lock(&priv->lock);
        reg = rtl818x_ioread16(priv, &priv->map->INT_STATUS);
-       if (unlikely(reg == 0xFFFF))
+       if (unlikely(reg == 0xFFFF)) {
+               spin_unlock(&priv->lock);
                return IRQ_HANDLED;
+       }
 
        rtl818x_iowrite16(priv, &priv->map->INT_STATUS, reg);
 
-       /* disable interrupts */
-       rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0);
+       if (reg & (RTL818X_INT_TXB_OK | RTL818X_INT_TXB_ERR))
+               rtl8180_handle_tx(dev, 3);
+
+       if (reg & (RTL818X_INT_TXH_OK | RTL818X_INT_TXH_ERR))
+               rtl8180_handle_tx(dev, 2);
+
+       if (reg & (RTL818X_INT_TXN_OK | RTL818X_INT_TXN_ERR))
+               rtl8180_handle_tx(dev, 1);
 
-       /* enable polling */
-       ieee80211_napi_schedule(dev);
+       if (reg & (RTL818X_INT_TXL_OK | RTL818X_INT_TXL_ERR))
+               rtl8180_handle_tx(dev, 0);
+
+       if (reg & (RTL818X_INT_RX_OK | RTL818X_INT_RX_ERR))
+               rtl8180_handle_rx(dev);
+
+       spin_unlock(&priv->lock);
 
        return IRQ_HANDLED;
 }
@@ -255,6 +247,7 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
        struct rtl8180_priv *priv = dev->priv;
        struct rtl8180_tx_ring *ring;
        struct rtl8180_tx_desc *entry;
+       unsigned long flags;
        unsigned int idx, prio;
        dma_addr_t mapping;
        u32 tx_flags;
@@ -301,7 +294,7 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
                        plcp_len |= 1 << 15;
        }
 
-       spin_lock(&priv->lock);
+       spin_lock_irqsave(&priv->lock, flags);
 
        if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
                if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
@@ -325,7 +318,7 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
        if (ring->entries - skb_queue_len(&ring->queue) < 2)
                ieee80211_stop_queue(dev, prio);
 
-       spin_unlock(&priv->lock);
+       spin_unlock_irqrestore(&priv->lock, flags);
 
        rtl818x_iowrite8(priv, &priv->map->TX_DMA_POLLING, (1 << (prio + 4)));
 
@@ -871,7 +864,6 @@ static const struct ieee80211_ops rtl8180_ops = {
        .prepare_multicast      = rtl8180_prepare_multicast,
        .configure_filter       = rtl8180_configure_filter,
        .get_tsf                = rtl8180_get_tsf,
-       .napi_poll              = rtl8180_poll,
 };
 
 static void rtl8180_eeprom_register_read(struct eeprom_93cx6 *eeprom)
@@ -1003,8 +995,6 @@ static int __devinit rtl8180_probe(struct pci_dev *pdev,
        dev->queues = 1;
        dev->max_signal = 65;
 
-       dev->napi_weight = 64;
-
        reg = rtl818x_ioread32(priv, &priv->map->TX_CONF);
        reg &= RTL818X_TX_CONF_HWVER_MASK;
        switch (reg) {
index 4134f4495b95313c14552cae60cf00723291ec5b..8a4cd763e5a24c49080a97a0100f994e1f4993d0 100644 (file)
@@ -117,10 +117,7 @@ enum {
 #define WL1271_TX_SECURITY_LO16(s) ((u16)((s) & 0xffff))
 #define WL1271_TX_SECURITY_HI32(s) ((u32)(((s) >> 16) & 0xffffffff))
 
-/*
- * Enable/disable 802.11a support for WL1273
- */
-#undef WL1271_80211A_ENABLED
+#define WL1271_CIPHER_SUITE_GEM 0x00147201
 
 #define WL1271_BUSY_WORD_CNT 1
 #define WL1271_BUSY_WORD_LEN (WL1271_BUSY_WORD_CNT * sizeof(u32))
@@ -133,6 +130,8 @@ enum {
 
 #define ACX_TX_DESCRIPTORS         32
 
+#define WL1271_AGGR_BUFFER_SIZE (4 * PAGE_SIZE)
+
 enum wl1271_state {
        WL1271_STATE_OFF,
        WL1271_STATE_ON,
@@ -301,6 +300,7 @@ struct wl1271_rx_mem_pool_addr {
 struct wl1271_scan {
        struct cfg80211_scan_request *req;
        bool *scanned_ch;
+       bool failed;
        u8 state;
        u8 ssid[IW_ESSID_MAX_SIZE+1];
        size_t ssid_len;
@@ -350,6 +350,7 @@ struct wl1271 {
 #define WL1271_FLAG_IDLE              (10)
 #define WL1271_FLAG_IDLE_REQUESTED    (11)
 #define WL1271_FLAG_PSPOLL_FAILURE    (12)
+#define WL1271_FLAG_STA_STATE_SENT    (13)
        unsigned long flags;
 
        struct wl1271_partition_set part;
@@ -362,6 +363,7 @@ struct wl1271 {
        u8 *fw;
        size_t fw_len;
        struct wl1271_nvs_file *nvs;
+       size_t nvs_len;
 
        s8 hw_pg_ver;
 
@@ -408,9 +410,15 @@ struct wl1271 {
        /* Rx memory pool address */
        struct wl1271_rx_mem_pool_addr rx_mem_pool_addr;
 
+       /* Intermediate buffer, used for packet aggregation */
+       u8 *aggr_buf;
+
        /* The target interrupt mask */
        struct work_struct irq_work;
 
+       /* Hardware recovery work */
+       struct work_struct recovery_work;
+
        /* The mbox event mask */
        u32 event_mask;
 
@@ -419,6 +427,7 @@ struct wl1271 {
 
        /* Are we currently scanning */
        struct wl1271_scan scan;
+       struct delayed_work scan_complete_work;
 
        /* Our association ID */
        u16 aid;
@@ -475,6 +484,8 @@ struct wl1271 {
 
        bool sg_enabled;
 
+       bool enable_11a;
+
        struct list_head list;
 
        /* Most recently reported noise in dBm */
@@ -498,14 +509,4 @@ int wl1271_plt_stop(struct wl1271 *wl);
 #define WL1271_PRE_POWER_ON_SLEEP 20 /* in miliseconds */
 #define WL1271_POWER_ON_SLEEP 200 /* in miliseconds */
 
-static inline bool wl1271_11a_enabled(void)
-{
-       /* FIXME: this could be determined based on the NVS-INI file */
-#ifdef WL1271_80211A_ENABLED
-       return true;
-#else
-       return false;
-#endif
-}
-
 #endif
index f03ad088db8b3eb7535e9e29de8b19dd08a0928d..6189934052629d61b528ba771d30f94865e51f6f 100644 (file)
@@ -86,40 +86,6 @@ out:
        return ret;
 }
 
-int wl1271_acx_fw_version(struct wl1271 *wl, char *buf, size_t len)
-{
-       struct acx_revision *rev;
-       int ret;
-
-       wl1271_debug(DEBUG_ACX, "acx fw rev");
-
-       rev = kzalloc(sizeof(*rev), GFP_KERNEL);
-       if (!rev) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       ret = wl1271_cmd_interrogate(wl, ACX_FW_REV, rev, sizeof(*rev));
-       if (ret < 0) {
-               wl1271_warning("ACX_FW_REV interrogate failed");
-               goto out;
-       }
-
-       /* be careful with the buffer sizes */
-       strncpy(buf, rev->fw_version, min(len, sizeof(rev->fw_version)));
-
-       /*
-        * if the firmware version string is exactly
-        * sizeof(rev->fw_version) long or fw_len is less than
-        * sizeof(rev->fw_version) it won't be null terminated
-        */
-       buf[min(len, sizeof(rev->fw_version)) - 1] = '\0';
-
-out:
-       kfree(rev);
-       return ret;
-}
-
 int wl1271_acx_tx_power(struct wl1271 *wl, int power)
 {
        struct acx_current_tx_power *acx;
index 4235bc56f750eb4b40b036952cd246dc2e67db6c..ebb341d36e8c01a88f2fe423908c2a0994e6be1d 100644 (file)
@@ -100,35 +100,6 @@ struct acx_error_counter {
        __le32 seq_num_miss;
 } __packed;
 
-struct acx_revision {
-       struct acx_header header;
-
-       /*
-        * The WiLink firmware version, an ASCII string x.x.x.x,
-        * that uniquely identifies the current firmware.
-        * The left most digit is incremented each time a
-        * significant change is made to the firmware, such as
-        * code redesign or new platform support.
-        * The second digit is incremented when major enhancements
-        * are added or major fixes are made.
-        * The third digit is incremented for each GA release.
-        * The fourth digit is incremented for each build.
-        * The first two digits identify a firmware release version,
-        * in other words, a unique set of features.
-        * The first three digits identify a GA release.
-        */
-       char fw_version[20];
-
-       /*
-        * This 4 byte field specifies the WiLink hardware version.
-        * bits 0  - 15: Reserved.
-        * bits 16 - 23: Version ID - The WiLink version ID
-        *              (1 = first spin, 2 = second spin, and so on).
-        * bits 24 - 31: Chip ID - The WiLink chip ID.
-        */
-       __le32 hw_version;
-} __packed;
-
 enum wl1271_psm_mode {
        /* Active mode */
        WL1271_PSM_CAM = 0,
@@ -1060,7 +1031,6 @@ enum {
        ACX_PEER_HT_CAP             = 0x0057,
        ACX_HT_BSS_OPERATION        = 0x0058,
        ACX_COEX_ACTIVITY           = 0x0059,
-       ACX_SET_SMART_REFLEX_DEBUG  = 0x005A,
        ACX_SET_DCO_ITRIM_PARAMS    = 0x0061,
        DOT11_RX_MSDU_LIFE_TIME     = 0x1004,
        DOT11_CUR_TX_PWR            = 0x100D,
@@ -1077,7 +1047,6 @@ enum {
 
 int wl1271_acx_wake_up_conditions(struct wl1271 *wl);
 int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth);
-int wl1271_acx_fw_version(struct wl1271 *wl, char *buf, size_t len);
 int wl1271_acx_tx_power(struct wl1271 *wl, int power);
 int wl1271_acx_feature_cfg(struct wl1271 *wl);
 int wl1271_acx_mem_map(struct wl1271 *wl,
index e5a7f042645f0a8dc8d7e76c9c3371c66d67ac81..b910212420985cd3ecf28dfa18dd3584b03b1cb7 100644 (file)
@@ -225,6 +225,28 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
        if (wl->nvs == NULL)
                return -ENODEV;
 
+       /*
+        * FIXME: the LEGACY NVS image support (NVS's missing the 5GHz band
+        * configurations) can be removed when those NVS files stop floating
+        * around.
+        */
+       if (wl->nvs_len == sizeof(struct wl1271_nvs_file) ||
+           wl->nvs_len == WL1271_INI_LEGACY_NVS_FILE_SIZE) {
+               if (wl->nvs->general_params.dual_mode_select)
+                       wl->enable_11a = true;
+       }
+
+       if (wl->nvs_len != sizeof(struct wl1271_nvs_file) &&
+           (wl->nvs_len != WL1271_INI_LEGACY_NVS_FILE_SIZE ||
+            wl->enable_11a)) {
+               wl1271_error("nvs size is not as expected: %zu != %zu",
+                            wl->nvs_len, sizeof(struct wl1271_nvs_file));
+               kfree(wl->nvs);
+               wl->nvs = NULL;
+               wl->nvs_len = 0;
+               return -EILSEQ;
+       }
+
        /* only the first part of the NVS needs to be uploaded */
        nvs_len = sizeof(wl->nvs->nvs);
        nvs_ptr = (u8 *)wl->nvs->nvs;
@@ -251,8 +273,10 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
                burst_len = nvs_ptr[0];
                dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8));
 
-               /* FIXME: Due to our new wl1271_translate_reg_addr function,
-                  we need to add the REGISTER_BASE to the destination */
+               /*
+                * Due to our new wl1271_translate_reg_addr function,
+                * we need to add the REGISTER_BASE to the destination
+                */
                dest_addr += REGISTERS_BASE;
 
                /* We move our pointer to the data */
@@ -280,8 +304,6 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
                        ALIGN(nvs_ptr - (u8 *)wl->nvs->nvs + 7, 4);
        nvs_len -= nvs_ptr - (u8 *)wl->nvs->nvs;
 
-       /* FIXME: The driver sets the partition here, but this is not needed,
-          since it sets to the same one as currently in use */
        /* Now we must set the partition correctly */
        wl1271_set_partition(wl, &part_table[PART_WORK]);
 
@@ -291,9 +313,6 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
                return -ENOMEM;
 
        /* And finally we upload the NVS tables */
-       /* FIXME: In wl1271, we upload everything at once.
-          No endianness handling needed here?! The ref driver doesn't do
-          anything about it at this point */
        wl1271_write(wl, CMD_MBOX_ADDRESS, nvs_aligned, nvs_len, false);
 
        kfree(nvs_aligned);
@@ -491,10 +510,7 @@ int wl1271_boot(struct wl1271 *wl)
 
        wl1271_debug(DEBUG_BOOT, "pause1 0x%x", pause);
 
-       pause &= ~(WU_COUNTER_PAUSE_VAL); /* FIXME: This should probably be
-                                          * WU_COUNTER_PAUSE_VAL instead of
-                                          * 0x3ff (magic number ).  How does
-                                          * this work?! */
+       pause &= ~(WU_COUNTER_PAUSE_VAL);
        pause |= WU_COUNTER_PAUSE_VAL;
        wl1271_write32(wl, WU_COUNTER_PAUSE, pause);
 
@@ -548,7 +564,6 @@ int wl1271_boot(struct wl1271 *wl)
        if (ret < 0)
                goto out;
 
-       /* FIXME: Need to check whether this is really what we want */
        wl1271_write32(wl, ACX_REG_INTERRUPT_MASK,
                       WL1271_ACX_ALL_EVENTS_VECTOR);
 
index ce503ddd5a41e8504d894cd5516973d078af8769..5d3e8485ea4e51dfca8757ec116cfb8f63736fdf 100644 (file)
@@ -94,6 +94,7 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
        status = le16_to_cpu(cmd->status);
        if (status != CMD_STATUS_SUCCESS) {
                wl1271_error("command execute failure %d", status);
+               ieee80211_queue_work(wl->hw, &wl->recovery_work);
                ret = -EIO;
        }
 
@@ -107,6 +108,8 @@ out:
 int wl1271_cmd_general_parms(struct wl1271 *wl)
 {
        struct wl1271_general_parms_cmd *gen_parms;
+       struct wl1271_ini_general_params *gp = &wl->nvs->general_params;
+       bool answer = false;
        int ret;
 
        if (!wl->nvs)
@@ -118,13 +121,24 @@ int wl1271_cmd_general_parms(struct wl1271 *wl)
 
        gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM;
 
-       memcpy(&gen_parms->general_params, &wl->nvs->general_params,
-              sizeof(struct wl1271_ini_general_params));
+       memcpy(&gen_parms->general_params, gp, sizeof(*gp));
 
-       ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), 0);
-       if (ret < 0)
+       if (gp->tx_bip_fem_auto_detect)
+               answer = true;
+
+       ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer);
+       if (ret < 0) {
                wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed");
+               goto out;
+       }
+
+       gp->tx_bip_fem_manufacturer =
+               gen_parms->general_params.tx_bip_fem_manufacturer;
+
+       wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n",
+                    answer ? "auto" : "manual", gp->tx_bip_fem_manufacturer);
 
+out:
        kfree(gen_parms);
        return ret;
 }
@@ -170,6 +184,39 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl)
        return ret;
 }
 
+int wl1271_cmd_ext_radio_parms(struct wl1271 *wl)
+{
+       struct wl1271_ext_radio_parms_cmd *ext_radio_parms;
+       struct conf_rf_settings *rf = &wl->conf.rf;
+       int ret;
+
+       if (!wl->nvs)
+               return -ENODEV;
+
+       ext_radio_parms = kzalloc(sizeof(*ext_radio_parms), GFP_KERNEL);
+       if (!ext_radio_parms)
+               return -ENOMEM;
+
+       ext_radio_parms->test.id = TEST_CMD_INI_FILE_RF_EXTENDED_PARAM;
+
+       memcpy(ext_radio_parms->tx_per_channel_power_compensation_2,
+              rf->tx_per_channel_power_compensation_2,
+              CONF_TX_PWR_COMPENSATION_LEN_2);
+       memcpy(ext_radio_parms->tx_per_channel_power_compensation_5,
+              rf->tx_per_channel_power_compensation_5,
+              CONF_TX_PWR_COMPENSATION_LEN_5);
+
+       wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_EXT_RADIO_PARAM: ",
+                   ext_radio_parms, sizeof(*ext_radio_parms));
+
+       ret = wl1271_cmd_test(wl, ext_radio_parms, sizeof(*ext_radio_parms), 0);
+       if (ret < 0)
+               wl1271_warning("TEST_CMD_INI_FILE_RF_EXTENDED_PARAM failed");
+
+       kfree(ext_radio_parms);
+       return ret;
+}
+
 /*
  * Poll the mailbox event field until any of the bits in the mask is set or a
  * timeout occurs (WL1271_EVENT_TIMEOUT in msecs)
@@ -182,8 +229,10 @@ static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask)
        timeout = jiffies + msecs_to_jiffies(WL1271_EVENT_TIMEOUT);
 
        do {
-               if (time_after(jiffies, timeout))
+               if (time_after(jiffies, timeout)) {
+                       ieee80211_queue_work(wl->hw, &wl->recovery_work);
                        return -ETIMEDOUT;
+               }
 
                msleep(1);
 
@@ -390,18 +439,11 @@ out:
        return ret;
 }
 
-int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, bool send)
+int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, u32 rates, bool send)
 {
        struct wl1271_cmd_ps_params *ps_params = NULL;
        int ret = 0;
 
-       /* FIXME: this should be in ps.c */
-       ret = wl1271_acx_wake_up_conditions(wl);
-       if (ret < 0) {
-               wl1271_error("couldn't set wake up conditions");
-               goto out;
-       }
-
        wl1271_debug(DEBUG_CMD, "cmd set ps mode");
 
        ps_params = kzalloc(sizeof(*ps_params), GFP_KERNEL);
@@ -412,9 +454,9 @@ int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, bool send)
 
        ps_params->ps_mode = ps_mode;
        ps_params->send_null_data = send;
-       ps_params->retries = 5;
-       ps_params->hang_over_period = 1;
-       ps_params->null_data_rate = cpu_to_le32(wl->basic_rate_set);
+       ps_params->retries = wl->conf.conn.psm_entry_nullfunc_retries;
+       ps_params->hang_over_period = wl->conf.conn.psm_entry_hangover_period;
+       ps_params->null_data_rate = cpu_to_le32(rates);
 
        ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params,
                              sizeof(*ps_params), 0);
@@ -428,41 +470,6 @@ out:
        return ret;
 }
 
-int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer,
-                          size_t len)
-{
-       struct cmd_read_write_memory *cmd;
-       int ret = 0;
-
-       wl1271_debug(DEBUG_CMD, "cmd read memory");
-
-       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
-       if (!cmd) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       WARN_ON(len > MAX_READ_SIZE);
-       len = min_t(size_t, len, MAX_READ_SIZE);
-
-       cmd->addr = cpu_to_le32(addr);
-       cmd->size = cpu_to_le32(len);
-
-       ret = wl1271_cmd_send(wl, CMD_READ_MEMORY, cmd, sizeof(*cmd),
-                             sizeof(*cmd));
-       if (ret < 0) {
-               wl1271_error("read memory command failed: %d", ret);
-               goto out;
-       }
-
-       /* the read command got in */
-       memcpy(answer, cmd->value, len);
-
-out:
-       kfree(cmd);
-       return ret;
-}
-
 int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id,
                            void *buf, size_t buf_len, int index, u32 rates)
 {
@@ -523,7 +530,7 @@ int wl1271_cmd_build_null_data(struct wl1271 *wl)
        }
 
        ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, ptr, size, 0,
-                                     WL1271_RATE_AUTOMATIC);
+                                     wl->basic_rate);
 
 out:
        dev_kfree_skb(skb);
@@ -546,7 +553,7 @@ int wl1271_cmd_build_klv_null_data(struct wl1271 *wl)
        ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV,
                                      skb->data, skb->len,
                                      CMD_TEMPL_KLV_IDX_NULL_DATA,
-                                     WL1271_RATE_AUTOMATIC);
+                                     wl->basic_rate);
 
 out:
        dev_kfree_skb(skb);
@@ -623,7 +630,7 @@ int wl1271_build_qos_null_data(struct wl1271 *wl)
 
        return wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, &template,
                                       sizeof(template), 0,
-                                      WL1271_RATE_AUTOMATIC);
+                                      wl->basic_rate);
 }
 
 int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id)
@@ -746,3 +753,31 @@ out_free:
 out:
        return ret;
 }
+
+int wl1271_cmd_set_sta_state(struct wl1271 *wl)
+{
+       struct wl1271_cmd_set_sta_state *cmd;
+       int ret = 0;
+
+       wl1271_debug(DEBUG_CMD, "cmd set sta state");
+
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (!cmd) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       cmd->state = WL1271_CMD_STA_STATE_CONNECTED;
+
+       ret = wl1271_cmd_send(wl, CMD_SET_STA_STATE, cmd, sizeof(*cmd), 0);
+       if (ret < 0) {
+               wl1271_error("failed to send set STA state command");
+               goto out_free;
+       }
+
+out_free:
+       kfree(cmd);
+
+out:
+       return ret;
+}
index af577ee8eb0257c4585c86518f776b98d380e387..a0caf4fc37b1a4936917b3287442e72d1fa5fdd8 100644 (file)
@@ -33,12 +33,13 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
                    size_t res_len);
 int wl1271_cmd_general_parms(struct wl1271 *wl);
 int wl1271_cmd_radio_parms(struct wl1271 *wl);
+int wl1271_cmd_ext_radio_parms(struct wl1271 *wl);
 int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type);
 int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer);
 int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len);
 int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len);
 int wl1271_cmd_data_path(struct wl1271 *wl, bool enable);
-int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, bool send);
+int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, u32 rates, bool send);
 int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer,
                           size_t len);
 int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id,
@@ -55,6 +56,7 @@ int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
                       u8 key_size, const u8 *key, const u8 *addr,
                       u32 tx_seq_32, u16 tx_seq_16);
 int wl1271_cmd_disconnect(struct wl1271 *wl);
+int wl1271_cmd_set_sta_state(struct wl1271 *wl);
 
 enum wl1271_commands {
        CMD_INTERROGATE     = 1,    /*use this to read information elements*/
@@ -160,41 +162,6 @@ enum {
        MAX_COMMAND_STATUS              = 0xff
 };
 
-
-/*
- * CMD_READ_MEMORY
- *
- * The host issues this command to read the WiLink device memory/registers.
- *
- * Note: The Base Band address has special handling (16 bits registers and
- * addresses). For more information, see the hardware specification.
- */
-/*
- * CMD_WRITE_MEMORY
- *
- * The host issues this command to write the WiLink device memory/registers.
- *
- * The Base Band address has special handling (16 bits registers and
- * addresses). For more information, see the hardware specification.
- */
-#define MAX_READ_SIZE 256
-
-struct cmd_read_write_memory {
-       struct wl1271_cmd_header header;
-
-       /* The address of the memory to read from or write to.*/
-       __le32 addr;
-
-       /* The amount of data in bytes to read from or write to the WiLink
-        * device.*/
-       __le32 size;
-
-       /* The actual value read from or written to the Wilink. The source
-          of this field is the Host in WRITE command or the Wilink in READ
-          command. */
-       u8 value[MAX_READ_SIZE];
-} __packed;
-
 #define CMDMBOX_HEADER_LEN 4
 #define CMDMBOX_INFO_ELEM_HEADER_LEN 4
 
@@ -313,7 +280,7 @@ enum wl1271_cmd_key_type {
        KEY_WEP  = 1,
        KEY_TKIP = 2,
        KEY_AES  = 3,
-       KEY_GEM  = 4
+       KEY_GEM  = 4,
 };
 
 /* FIXME: Add description for key-types */
@@ -358,13 +325,14 @@ enum wl1271_channel_tune_bands {
        WL1271_CHANNEL_TUNE_BAND_4_9
 };
 
-#define WL1271_PD_REFERENCE_POINT_BAND_B_G 0
+#define WL1271_PD_REFERENCE_POINT_BAND_B_G  0
 
-#define TEST_CMD_P2G_CAL                   0x02
-#define TEST_CMD_CHANNEL_TUNE              0x0d
-#define TEST_CMD_UPDATE_PD_REFERENCE_POINT 0x1d
-#define TEST_CMD_INI_FILE_RADIO_PARAM      0x19
-#define TEST_CMD_INI_FILE_GENERAL_PARAM    0x1E
+#define TEST_CMD_P2G_CAL                    0x02
+#define TEST_CMD_CHANNEL_TUNE               0x0d
+#define TEST_CMD_UPDATE_PD_REFERENCE_POINT  0x1d
+#define TEST_CMD_INI_FILE_RADIO_PARAM       0x19
+#define TEST_CMD_INI_FILE_GENERAL_PARAM     0x1E
+#define TEST_CMD_INI_FILE_RF_EXTENDED_PARAM 0x26
 
 struct wl1271_general_parms_cmd {
        struct wl1271_cmd_header header;
@@ -397,6 +365,16 @@ struct wl1271_radio_parms_cmd {
        u8 padding3[2];
 } __packed;
 
+struct wl1271_ext_radio_parms_cmd {
+       struct wl1271_cmd_header header;
+
+       struct wl1271_cmd_test_header test;
+
+       u8 tx_per_channel_power_compensation_2[CONF_TX_PWR_COMPENSATION_LEN_2];
+       u8 tx_per_channel_power_compensation_5[CONF_TX_PWR_COMPENSATION_LEN_5];
+       u8 padding[3];
+} __packed;
+
 struct wl1271_cmd_cal_channel_tune {
        struct wl1271_cmd_header header;
 
@@ -469,4 +447,13 @@ struct wl1271_cmd_disconnect {
        u8  padding;
 } __packed;
 
+#define WL1271_CMD_STA_STATE_CONNECTED  1
+
+struct wl1271_cmd_set_sta_state {
+       struct wl1271_cmd_header header;
+
+       u8 state;
+       u8 padding[3];
+} __packed;
+
 #endif /* __WL1271_CMD_H__ */
index 0435ffda8f7340b14cbe9dfcee73f492a80c6b3e..5f78a6cb14334b55f5e195d3df838d80ec3c7649 100644 (file)
@@ -595,7 +595,7 @@ struct conf_tx_ac_category {
        u16 tx_op_limit;
 };
 
-#define CONF_TX_MAX_TID_COUNT 7
+#define CONF_TX_MAX_TID_COUNT 8
 
 enum {
        CONF_CHANNEL_TYPE_DCF = 0,   /* DC/LEGACY*/
@@ -911,6 +911,22 @@ struct conf_conn_settings {
         */
        u8 psm_entry_retries;
 
+       /*
+        * Specifies the maximum number of times to try transmit the PSM entry
+        * null-func frame for each PSM entry attempt
+        *
+        * Range 0 - 255
+        */
+       u8 psm_entry_nullfunc_retries;
+
+       /*
+        * Specifies the time to linger in active mode after successfully
+        * transmitting the PSM entry null-func frame.
+        *
+        * Range 0 - 255 TU's
+        */
+       u8 psm_entry_hangover_period;
+
        /*
         *
         * Specifies the interval of the connection keep-alive null-func
@@ -1016,6 +1032,64 @@ struct conf_roam_trigger_settings {
        u8 avg_weight_snr_data;
 };
 
+struct conf_scan_settings {
+       /*
+        * The minimum time to wait on each channel for active scans
+        *
+        * Range: 0 - 65536 tu
+        */
+       u16 min_dwell_time_active;
+
+       /*
+        * The maximum time to wait on each channel for active scans
+        *
+        * Range: 0 - 65536 tu
+        */
+       u16 max_dwell_time_active;
+
+       /*
+        * The maximum time to wait on each channel for passive scans
+        *
+        * Range: 0 - 65536 tu
+        */
+       u16 min_dwell_time_passive;
+
+       /*
+        * The maximum time to wait on each channel for passive scans
+        *
+        * Range: 0 - 65536 tu
+        */
+       u16 max_dwell_time_passive;
+
+       /*
+        * Number of probe requests to transmit on each active scan channel
+        *
+        * Range: u8
+        */
+       u16 num_probe_reqs;
+
+};
+
+/* these are number of channels on the band divided by two, rounded up */
+#define CONF_TX_PWR_COMPENSATION_LEN_2 7
+#define CONF_TX_PWR_COMPENSATION_LEN_5 18
+
+struct conf_rf_settings {
+       /*
+        * Per channel power compensation for 2.4GHz
+        *
+        * Range: s8
+        */
+       u8 tx_per_channel_power_compensation_2[CONF_TX_PWR_COMPENSATION_LEN_2];
+
+       /*
+        * Per channel power compensation for 5GHz
+        *
+        * Range: s8
+        */
+       u8 tx_per_channel_power_compensation_5[CONF_TX_PWR_COMPENSATION_LEN_5];
+};
+
 struct conf_drv_settings {
        struct conf_sg_settings sg;
        struct conf_rx_settings rx;
@@ -1024,6 +1098,8 @@ struct conf_drv_settings {
        struct conf_itrim_settings itrim;
        struct conf_pm_config_settings pm_config;
        struct conf_roam_trigger_settings roam_trigger;
+       struct conf_scan_settings scan;
+       struct conf_rf_settings rf;
 };
 
 #endif
index 25ce2cd5e3f3fa406f1d7fb3aa574da9d5113631..7b3f503829631018630ca21e9faa67f840db10c8 100644 (file)
@@ -41,6 +41,9 @@ void wl1271_pspoll_work(struct work_struct *work)
 
        mutex_lock(&wl->mutex);
 
+       if (unlikely(wl->state == WL1271_STATE_OFF))
+               goto out;
+
        if (!test_and_clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags))
                goto out;
 
@@ -52,7 +55,7 @@ void wl1271_pspoll_work(struct work_struct *work)
         * delivery failure occurred, and no-one changed state since, so
         * we should go back to powersave.
         */
-       wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, true);
+       wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, wl->basic_rate, true);
 
 out:
        mutex_unlock(&wl->mutex);
@@ -70,7 +73,8 @@ static void wl1271_event_pspoll_delivery_fail(struct wl1271 *wl)
 
        /* force active mode receive data from the AP */
        if (test_bit(WL1271_FLAG_PSM, &wl->flags)) {
-               ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE, true);
+               ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
+                                        wl->basic_rate, true);
                if (ret < 0)
                        return;
                set_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
@@ -91,6 +95,7 @@ static int wl1271_event_ps_report(struct wl1271 *wl,
                                  bool *beacon_loss)
 {
        int ret = 0;
+       u32 total_retries = wl->conf.conn.psm_entry_retries;
 
        wl1271_debug(DEBUG_EVENT, "ps_status: 0x%x", mbox->ps_status);
 
@@ -104,10 +109,10 @@ static int wl1271_event_ps_report(struct wl1271 *wl,
                        break;
                }
 
-               if (wl->psm_entry_retry < wl->conf.conn.psm_entry_retries) {
+               if (wl->psm_entry_retry < total_retries) {
                        wl->psm_entry_retry++;
                        ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
-                                                true);
+                                                wl->basic_rate, true);
                } else {
                        wl1271_info("No ack to nullfunc from AP.");
                        wl->psm_entry_retry = 0;
@@ -143,7 +148,7 @@ static int wl1271_event_ps_report(struct wl1271 *wl,
                /* make sure the firmware goes to active mode - the frame to
                   be sent next will indicate to the AP, that we are active. */
                ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
-                                        false);
+                                        wl->basic_rate, false);
                break;
        case EVENT_EXIT_POWER_SAVE_SUCCESS:
        default:
index 4447af1557f5c2af3d95ff7576118e543b8e0ea1..8044bba70ee789b377e1183cef516cd34d36d02b 100644 (file)
@@ -53,6 +53,7 @@ static int wl1271_init_hwenc_config(struct wl1271 *wl)
 int wl1271_init_templates_config(struct wl1271 *wl)
 {
        int ret, i;
+       size_t size;
 
        /* send empty templates for fw memory reservation */
        ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL,
@@ -61,14 +62,12 @@ int wl1271_init_templates_config(struct wl1271 *wl)
        if (ret < 0)
                return ret;
 
-       if (wl1271_11a_enabled()) {
-               size_t size = sizeof(struct wl12xx_probe_req_template);
-               ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5,
-                                             NULL, size, 0,
-                                             WL1271_RATE_AUTOMATIC);
-               if (ret < 0)
-                       return ret;
-       }
+       size = sizeof(struct wl12xx_probe_req_template);
+       ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5,
+                                     NULL, size, 0,
+                                     WL1271_RATE_AUTOMATIC);
+       if (ret < 0)
+               return ret;
 
        ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, NULL,
                                      sizeof(struct wl12xx_null_data_template),
@@ -223,6 +222,10 @@ int wl1271_hw_init(struct wl1271 *wl)
        if (ret < 0)
                return ret;
 
+       ret = wl1271_cmd_ext_radio_parms(wl);
+       if (ret < 0)
+               return ret;
+
        /* Template settings */
        ret = wl1271_init_templates_config(wl);
        if (ret < 0)
@@ -291,8 +294,16 @@ int wl1271_hw_init(struct wl1271 *wl)
        if (ret < 0)
                goto out_free_memmap;
 
-       /* Default TID configuration */
+       /* Default TID/AC configuration */
+       BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
        for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
+               conf_ac = &wl->conf.tx.ac_conf[i];
+               ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
+                                       conf_ac->cw_max, conf_ac->aifsn,
+                                       conf_ac->tx_op_limit);
+               if (ret < 0)
+                       goto out_free_memmap;
+
                conf_tid = &wl->conf.tx.tid_conf[i];
                ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
                                         conf_tid->channel_type,
@@ -305,16 +316,6 @@ int wl1271_hw_init(struct wl1271 *wl)
                        goto out_free_memmap;
        }
 
-       /* Default AC configuration */
-       for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
-               conf_ac = &wl->conf.tx.ac_conf[i];
-               ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
-                                       conf_ac->cw_max, conf_ac->aifsn,
-                                       conf_ac->tx_op_limit);
-               if (ret < 0)
-                       goto out_free_memmap;
-       }
-
        /* Configure TX rate classes */
        ret = wl1271_acx_rate_policies(wl);
        if (ret < 0)
index 776cd7c4114806936650ef3f8edde5b2037df66c..48a4b9961ae6e1bea44a4985bca56e46bdf1ee32 100644 (file)
@@ -124,28 +124,28 @@ static struct conf_drv_settings default_conf = {
                },
                .ac_conf_count               = 4,
                .ac_conf                     = {
-                       [0] = {
+                       [CONF_TX_AC_BE] = {
                                .ac          = CONF_TX_AC_BE,
                                .cw_min      = 15,
                                .cw_max      = 63,
                                .aifsn       = 3,
                                .tx_op_limit = 0,
                        },
-                       [1] = {
+                       [CONF_TX_AC_BK] = {
                                .ac          = CONF_TX_AC_BK,
                                .cw_min      = 15,
                                .cw_max      = 63,
                                .aifsn       = 7,
                                .tx_op_limit = 0,
                        },
-                       [2] = {
+                       [CONF_TX_AC_VI] = {
                                .ac          = CONF_TX_AC_VI,
                                .cw_min      = 15,
                                .cw_max      = 63,
                                .aifsn       = CONF_TX_AIFS_PIFS,
                                .tx_op_limit = 3008,
                        },
-                       [3] = {
+                       [CONF_TX_AC_VO] = {
                                .ac          = CONF_TX_AC_VO,
                                .cw_min      = 15,
                                .cw_max      = 63,
@@ -153,64 +153,40 @@ static struct conf_drv_settings default_conf = {
                                .tx_op_limit = 1504,
                        },
                },
-               .tid_conf_count = 7,
+               .tid_conf_count = 4,
                .tid_conf = {
-                       [0] = {
-                               .queue_id    = 0,
-                               .channel_type = CONF_CHANNEL_TYPE_DCF,
-                               .tsid        = CONF_TX_AC_BE,
-                               .ps_scheme   = CONF_PS_SCHEME_LEGACY,
-                               .ack_policy  = CONF_ACK_POLICY_LEGACY,
-                               .apsd_conf   = {0, 0},
-                       },
-                       [1] = {
-                               .queue_id    = 1,
-                               .channel_type = CONF_CHANNEL_TYPE_DCF,
+                       [CONF_TX_AC_BE] = {
+                               .queue_id    = CONF_TX_AC_BE,
+                               .channel_type = CONF_CHANNEL_TYPE_EDCF,
                                .tsid        = CONF_TX_AC_BE,
                                .ps_scheme   = CONF_PS_SCHEME_LEGACY,
                                .ack_policy  = CONF_ACK_POLICY_LEGACY,
                                .apsd_conf   = {0, 0},
                        },
-                       [2] = {
-                               .queue_id    = 2,
-                               .channel_type = CONF_CHANNEL_TYPE_DCF,
-                               .tsid        = CONF_TX_AC_BE,
+                       [CONF_TX_AC_BK] = {
+                               .queue_id    = CONF_TX_AC_BK,
+                               .channel_type = CONF_CHANNEL_TYPE_EDCF,
+                               .tsid        = CONF_TX_AC_BK,
                                .ps_scheme   = CONF_PS_SCHEME_LEGACY,
                                .ack_policy  = CONF_ACK_POLICY_LEGACY,
                                .apsd_conf   = {0, 0},
                        },
-                       [3] = {
-                               .queue_id    = 3,
-                               .channel_type = CONF_CHANNEL_TYPE_DCF,
-                               .tsid        = CONF_TX_AC_BE,
-                               .ps_scheme   = CONF_PS_SCHEME_LEGACY,
-                               .ack_policy  = CONF_ACK_POLICY_LEGACY,
-                               .apsd_conf   = {0, 0},
-                       },
-                       [4] = {
-                               .queue_id    = 4,
-                               .channel_type = CONF_CHANNEL_TYPE_DCF,
-                               .tsid        = CONF_TX_AC_BE,
+                       [CONF_TX_AC_VI] = {
+                               .queue_id    = CONF_TX_AC_VI,
+                               .channel_type = CONF_CHANNEL_TYPE_EDCF,
+                               .tsid        = CONF_TX_AC_VI,
                                .ps_scheme   = CONF_PS_SCHEME_LEGACY,
                                .ack_policy  = CONF_ACK_POLICY_LEGACY,
                                .apsd_conf   = {0, 0},
                        },
-                       [5] = {
-                               .queue_id    = 5,
-                               .channel_type = CONF_CHANNEL_TYPE_DCF,
-                               .tsid        = CONF_TX_AC_BE,
+                       [CONF_TX_AC_VO] = {
+                               .queue_id    = CONF_TX_AC_VO,
+                               .channel_type = CONF_CHANNEL_TYPE_EDCF,
+                               .tsid        = CONF_TX_AC_VO,
                                .ps_scheme   = CONF_PS_SCHEME_LEGACY,
                                .ack_policy  = CONF_ACK_POLICY_LEGACY,
                                .apsd_conf   = {0, 0},
                        },
-                       [6] = {
-                               .queue_id    = 6,
-                               .channel_type = CONF_CHANNEL_TYPE_DCF,
-                               .tsid        = CONF_TX_AC_BE,
-                               .ps_scheme   = CONF_PS_SCHEME_LEGACY,
-                               .ack_policy  = CONF_ACK_POLICY_LEGACY,
-                               .apsd_conf   = {0, 0},
-                       }
                },
                .frag_threshold              = IEEE80211_MAX_FRAG_THRESHOLD,
                .tx_compl_timeout            = 700,
@@ -238,7 +214,9 @@ static struct conf_drv_settings default_conf = {
                .ps_poll_recovery_period     = 700,
                .bet_enable                  = CONF_BET_MODE_ENABLE,
                .bet_max_consecutive         = 10,
-               .psm_entry_retries           = 3,
+               .psm_entry_retries           = 5,
+               .psm_entry_nullfunc_retries  = 3,
+               .psm_entry_hangover_period   = 1,
                .keep_alive_interval         = 55000,
                .max_listen_interval         = 20,
        },
@@ -251,15 +229,34 @@ static struct conf_drv_settings default_conf = {
                .host_fast_wakeup_support = false
        },
        .roam_trigger = {
-               /* FIXME: due to firmware bug, must use value 1 for now */
                .trigger_pacing               = 1,
                .avg_weight_rssi_beacon       = 20,
                .avg_weight_rssi_data         = 10,
                .avg_weight_snr_beacon        = 20,
                .avg_weight_snr_data          = 10
-       }
+       },
+       .scan = {
+               .min_dwell_time_active        = 7500,
+               .max_dwell_time_active        = 30000,
+               .min_dwell_time_passive       = 30000,
+               .max_dwell_time_passive       = 60000,
+               .num_probe_reqs               = 2,
+       },
+       .rf = {
+               .tx_per_channel_power_compensation_2 = {
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               },
+               .tx_per_channel_power_compensation_5 = {
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               },
+       },
 };
 
+static void __wl1271_op_remove_interface(struct wl1271 *wl);
+
+
 static void wl1271_device_release(struct device *dev)
 {
 
@@ -277,6 +274,67 @@ static struct platform_device wl1271_device = {
 
 static LIST_HEAD(wl_list);
 
+static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
+                            void *arg)
+{
+       struct net_device *dev = arg;
+       struct wireless_dev *wdev;
+       struct wiphy *wiphy;
+       struct ieee80211_hw *hw;
+       struct wl1271 *wl;
+       struct wl1271 *wl_temp;
+       int ret = 0;
+
+       /* Check that this notification is for us. */
+       if (what != NETDEV_CHANGE)
+               return NOTIFY_DONE;
+
+       wdev = dev->ieee80211_ptr;
+       if (wdev == NULL)
+               return NOTIFY_DONE;
+
+       wiphy = wdev->wiphy;
+       if (wiphy == NULL)
+               return NOTIFY_DONE;
+
+       hw = wiphy_priv(wiphy);
+       if (hw == NULL)
+               return NOTIFY_DONE;
+
+       wl_temp = hw->priv;
+       list_for_each_entry(wl, &wl_list, list) {
+               if (wl == wl_temp)
+                       break;
+       }
+       if (wl != wl_temp)
+               return NOTIFY_DONE;
+
+       mutex_lock(&wl->mutex);
+
+       if (wl->state == WL1271_STATE_OFF)
+               goto out;
+
+       if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
+               goto out;
+
+       ret = wl1271_ps_elp_wakeup(wl, false);
+       if (ret < 0)
+               goto out;
+
+       if ((dev->operstate == IF_OPER_UP) &&
+           !test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags)) {
+               wl1271_cmd_set_sta_state(wl);
+               wl1271_info("Association completed.");
+       }
+
+       wl1271_ps_elp_sleep(wl);
+
+out:
+       mutex_unlock(&wl->mutex);
+
+       return NOTIFY_OK;
+}
+
 static void wl1271_conf_init(struct wl1271 *wl)
 {
 
@@ -309,6 +367,10 @@ static int wl1271_plt_init(struct wl1271 *wl)
        if (ret < 0)
                return ret;
 
+       ret = wl1271_cmd_ext_radio_parms(wl);
+       if (ret < 0)
+               return ret;
+
        ret = wl1271_init_templates_config(wl);
        if (ret < 0)
                return ret;
@@ -346,8 +408,16 @@ static int wl1271_plt_init(struct wl1271 *wl)
        if (ret < 0)
                goto out_free_memmap;
 
-       /* Default TID configuration */
+       /* Default TID/AC configuration */
+       BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
        for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
+               conf_ac = &wl->conf.tx.ac_conf[i];
+               ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
+                                       conf_ac->cw_max, conf_ac->aifsn,
+                                       conf_ac->tx_op_limit);
+               if (ret < 0)
+                       goto out_free_memmap;
+
                conf_tid = &wl->conf.tx.tid_conf[i];
                ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
                                         conf_tid->channel_type,
@@ -360,16 +430,6 @@ static int wl1271_plt_init(struct wl1271 *wl)
                        goto out_free_memmap;
        }
 
-       /* Default AC configuration */
-       for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
-               conf_ac = &wl->conf.tx.ac_conf[i];
-               ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
-                                       conf_ac->cw_max, conf_ac->aifsn,
-                                       conf_ac->tx_op_limit);
-               if (ret < 0)
-                       goto out_free_memmap;
-       }
-
        /* Enable data path */
        ret = wl1271_cmd_data_path(wl, 1);
        if (ret < 0)
@@ -562,20 +622,6 @@ static int wl1271_fetch_nvs(struct wl1271 *wl)
                return ret;
        }
 
-       /*
-        * FIXME: the LEGACY NVS image support (NVS's missing the 5GHz band
-        * configurations) can be removed when those NVS files stop floating
-        * around.
-        */
-       if (fw->size != sizeof(struct wl1271_nvs_file) &&
-           (fw->size != WL1271_INI_LEGACY_NVS_FILE_SIZE ||
-            wl1271_11a_enabled())) {
-               wl1271_error("nvs size is not as expected: %zu != %zu",
-                            fw->size, sizeof(struct wl1271_nvs_file));
-               ret = -EILSEQ;
-               goto out;
-       }
-
        wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL);
 
        if (!wl->nvs) {
@@ -584,12 +630,37 @@ static int wl1271_fetch_nvs(struct wl1271 *wl)
                goto out;
        }
 
+       wl->nvs_len = fw->size;
+
 out:
        release_firmware(fw);
 
        return ret;
 }
 
+static void wl1271_recovery_work(struct work_struct *work)
+{
+       struct wl1271 *wl =
+               container_of(work, struct wl1271, recovery_work);
+
+       mutex_lock(&wl->mutex);
+
+       if (wl->state != WL1271_STATE_ON)
+               goto out;
+
+       wl1271_info("Hardware recovery in progress.");
+
+       if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
+               ieee80211_connection_loss(wl->vif);
+
+       /* reboot the chipset */
+       __wl1271_op_remove_interface(wl);
+       ieee80211_restart_hw(wl->hw);
+
+out:
+       mutex_unlock(&wl->mutex);
+}
+
 static void wl1271_fw_wakeup(struct wl1271 *wl)
 {
        u32 elp_reg;
@@ -610,8 +681,6 @@ static int wl1271_setup(struct wl1271 *wl)
                return -ENOMEM;
        }
 
-       INIT_WORK(&wl->irq_work, wl1271_irq_work);
-       INIT_WORK(&wl->tx_work, wl1271_tx_work);
        return 0;
 }
 
@@ -768,10 +837,12 @@ int wl1271_plt_stop(struct wl1271 *wl)
 out:
        mutex_unlock(&wl->mutex);
 
+       cancel_work_sync(&wl->irq_work);
+       cancel_work_sync(&wl->recovery_work);
+
        return ret;
 }
 
-
 static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
        struct wl1271 *wl = hw->priv;
@@ -814,6 +885,10 @@ static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
        return NETDEV_TX_OK;
 }
 
+static struct notifier_block wl1271_dev_notifier = {
+       .notifier_call = wl1271_dev_notify,
+};
+
 static int wl1271_op_start(struct ieee80211_hw *hw)
 {
        wl1271_debug(DEBUG_MAC80211, "mac80211 start");
@@ -930,13 +1005,10 @@ out:
        return ret;
 }
 
-static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
-                                      struct ieee80211_vif *vif)
+static void __wl1271_op_remove_interface(struct wl1271 *wl)
 {
-       struct wl1271 *wl = hw->priv;
        int i;
 
-       mutex_lock(&wl->mutex);
        wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
 
        wl1271_info("down");
@@ -950,10 +1022,10 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
                ieee80211_enable_dyn_ps(wl->vif);
 
        if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
-               ieee80211_scan_completed(wl->hw, true);
                wl->scan.state = WL1271_SCAN_STATE_IDLE;
                kfree(wl->scan.scanned_ch);
                wl->scan.scanned_ch = NULL;
+               ieee80211_scan_completed(wl->hw, true);
        }
 
        wl->state = WL1271_STATE_OFF;
@@ -962,9 +1034,11 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
 
        mutex_unlock(&wl->mutex);
 
+       cancel_delayed_work_sync(&wl->scan_complete_work);
        cancel_work_sync(&wl->irq_work);
        cancel_work_sync(&wl->tx_work);
        cancel_delayed_work_sync(&wl->pspoll_work);
+       cancel_delayed_work_sync(&wl->elp_work);
 
        mutex_lock(&wl->mutex);
 
@@ -1006,8 +1080,19 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
        wl->tx_res_if = NULL;
        kfree(wl->target_mem_map);
        wl->target_mem_map = NULL;
+}
+
+static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
+                                      struct ieee80211_vif *vif)
+{
+       struct wl1271 *wl = hw->priv;
 
+       mutex_lock(&wl->mutex);
+       WARN_ON(wl->vif != vif);
+       __wl1271_op_remove_interface(wl);
        mutex_unlock(&wl->mutex);
+
+       cancel_work_sync(&wl->recovery_work);
 }
 
 static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
@@ -1289,7 +1374,7 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
                if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
                        wl1271_debug(DEBUG_PSM, "psm enabled");
                        ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
-                                                true);
+                                                wl->basic_rate, true);
                }
        } else if (!(conf->flags & IEEE80211_CONF_PS) &&
                   test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
@@ -1299,7 +1384,7 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
 
                if (test_bit(WL1271_FLAG_PSM, &wl->flags))
                        ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
-                                                true);
+                                                wl->basic_rate, true);
        }
 
        if (conf->power_level != wl->power_level) {
@@ -1476,6 +1561,11 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
                tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
                break;
+       case WL1271_CIPHER_SUITE_GEM:
+               key_type = KEY_GEM;
+               tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
+               tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
+               break;
        default:
                wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
 
@@ -1559,10 +1649,7 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
        if (ret < 0)
                goto out;
 
-       if (wl1271_11a_enabled())
-               ret = wl1271_scan(hw->priv, ssid, len, req);
-       else
-               ret = wl1271_scan(hw->priv, ssid, len, req);
+       ret = wl1271_scan(hw->priv, ssid, len, req);
 
        wl1271_ps_elp_sleep(wl);
 
@@ -1777,12 +1864,15 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
                        if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
                            !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
                                mode = STATION_POWER_SAVE_MODE;
-                               ret = wl1271_ps_set_mode(wl, mode, true);
+                               ret = wl1271_ps_set_mode(wl, mode,
+                                                        wl->basic_rate,
+                                                        true);
                                if (ret < 0)
                                        goto out_sleep;
                        }
                } else {
                        /* use defaults when not associated */
+                       clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
                        clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
                        wl->aid = 0;
 
@@ -1994,21 +2084,24 @@ static struct ieee80211_rate wl1271_rates[] = {
          .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
 };
 
-/* can't be const, mac80211 writes to this */
+/*
+ * Can't be const, mac80211 writes to this. The order of the channels here
+ * is designed to improve scanning.
+ */
 static struct ieee80211_channel wl1271_channels[] = {
        { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
-       { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
-       { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
-       { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
        { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
-       { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
-       { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
-       { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
        { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
-       { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
-       { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
-       { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
        { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
+       { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
+       { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
+       { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
+       { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
+       { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
+       { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
+       { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
+       { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
+       { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
 };
 
 /* mapping to indexes for wl1271_rates */
@@ -2077,49 +2170,52 @@ static struct ieee80211_rate wl1271_rates_5ghz[] = {
          .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
 };
 
-/* 5 GHz band channels for WL1273 */
+/*
+ * 5 GHz band channels for WL1273 - can't be const, mac80211 writes to this.
+ * The order of the channels here is designed to improve scanning.
+ */
 static struct ieee80211_channel wl1271_channels_5ghz[] = {
        { .hw_value = 183, .center_freq = 4915},
-       { .hw_value = 184, .center_freq = 4920},
-       { .hw_value = 185, .center_freq = 4925},
-       { .hw_value = 187, .center_freq = 4935},
        { .hw_value = 188, .center_freq = 4940},
-       { .hw_value = 189, .center_freq = 4945},
-       { .hw_value = 192, .center_freq = 4960},
-       { .hw_value = 196, .center_freq = 4980},
-       { .hw_value = 7, .center_freq = 5035},
        { .hw_value = 8, .center_freq = 5040},
-       { .hw_value = 9, .center_freq = 5045},
-       { .hw_value = 11, .center_freq = 5055},
-       { .hw_value = 12, .center_freq = 5060},
-       { .hw_value = 16, .center_freq = 5080},
        { .hw_value = 34, .center_freq = 5170},
-       { .hw_value = 36, .center_freq = 5180},
-       { .hw_value = 38, .center_freq = 5190},
-       { .hw_value = 40, .center_freq = 5200},
-       { .hw_value = 42, .center_freq = 5210},
        { .hw_value = 44, .center_freq = 5220},
-       { .hw_value = 46, .center_freq = 5230},
-       { .hw_value = 48, .center_freq = 5240},
-       { .hw_value = 52, .center_freq = 5260},
-       { .hw_value = 56, .center_freq = 5280},
        { .hw_value = 60, .center_freq = 5300},
-       { .hw_value = 64, .center_freq = 5320},
-       { .hw_value = 100, .center_freq = 5500},
-       { .hw_value = 104, .center_freq = 5520},
-       { .hw_value = 108, .center_freq = 5540},
        { .hw_value = 112, .center_freq = 5560},
-       { .hw_value = 116, .center_freq = 5580},
-       { .hw_value = 120, .center_freq = 5600},
-       { .hw_value = 124, .center_freq = 5620},
-       { .hw_value = 128, .center_freq = 5640},
        { .hw_value = 132, .center_freq = 5660},
+       { .hw_value = 157, .center_freq = 5785},
+       { .hw_value = 184, .center_freq = 4920},
+       { .hw_value = 189, .center_freq = 4945},
+       { .hw_value = 9, .center_freq = 5045},
+       { .hw_value = 36, .center_freq = 5180},
+       { .hw_value = 46, .center_freq = 5230},
+       { .hw_value = 64, .center_freq = 5320},
+       { .hw_value = 116, .center_freq = 5580},
        { .hw_value = 136, .center_freq = 5680},
+       { .hw_value = 192, .center_freq = 4960},
+       { .hw_value = 11, .center_freq = 5055},
+       { .hw_value = 38, .center_freq = 5190},
+       { .hw_value = 48, .center_freq = 5240},
+       { .hw_value = 100, .center_freq = 5500},
+       { .hw_value = 120, .center_freq = 5600},
        { .hw_value = 140, .center_freq = 5700},
+       { .hw_value = 185, .center_freq = 4925},
+       { .hw_value = 196, .center_freq = 4980},
+       { .hw_value = 12, .center_freq = 5060},
+       { .hw_value = 40, .center_freq = 5200},
+       { .hw_value = 52, .center_freq = 5260},
+       { .hw_value = 104, .center_freq = 5520},
+       { .hw_value = 124, .center_freq = 5620},
        { .hw_value = 149, .center_freq = 5745},
-       { .hw_value = 153, .center_freq = 5765},
-       { .hw_value = 157, .center_freq = 5785},
        { .hw_value = 161, .center_freq = 5805},
+       { .hw_value = 187, .center_freq = 4935},
+       { .hw_value = 7, .center_freq = 5035},
+       { .hw_value = 16, .center_freq = 5080},
+       { .hw_value = 42, .center_freq = 5210},
+       { .hw_value = 56, .center_freq = 5280},
+       { .hw_value = 108, .center_freq = 5540},
+       { .hw_value = 128, .center_freq = 5640},
+       { .hw_value = 153, .center_freq = 5765},
        { .hw_value = 165, .center_freq = 5825},
 };
 
@@ -2212,8 +2308,7 @@ static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
        struct wl1271 *wl = dev_get_drvdata(dev);
        ssize_t len;
 
-       /* FIXME: what's the maximum length of buf? page size?*/
-       len = 500;
+       len = PAGE_SIZE;
 
        mutex_lock(&wl->mutex);
        len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
@@ -2274,8 +2369,7 @@ static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
        struct wl1271 *wl = dev_get_drvdata(dev);
        ssize_t len;
 
-       /* FIXME: what's the maximum length of buf? page size?*/
-       len = 500;
+       len = PAGE_SIZE;
 
        mutex_lock(&wl->mutex);
        if (wl->hw_pg_ver >= 0)
@@ -2307,6 +2401,8 @@ int wl1271_register_hw(struct wl1271 *wl)
 
        wl->mac80211_registered = true;
 
+       register_netdevice_notifier(&wl1271_dev_notifier);
+
        wl1271_notice("loaded");
 
        return 0;
@@ -2315,6 +2411,7 @@ EXPORT_SYMBOL_GPL(wl1271_register_hw);
 
 void wl1271_unregister_hw(struct wl1271 *wl)
 {
+       unregister_netdevice_notifier(&wl1271_dev_notifier);
        ieee80211_unregister_hw(wl->hw);
        wl->mac80211_registered = false;
 
@@ -2323,6 +2420,14 @@ EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
 
 int wl1271_init_ieee80211(struct wl1271 *wl)
 {
+       static const u32 cipher_suites[] = {
+               WLAN_CIPHER_SUITE_WEP40,
+               WLAN_CIPHER_SUITE_WEP104,
+               WLAN_CIPHER_SUITE_TKIP,
+               WLAN_CIPHER_SUITE_CCMP,
+               WL1271_CIPHER_SUITE_GEM,
+       };
+
        /* The tx descriptor buffer and the TKIP space. */
        wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
                sizeof(struct wl1271_tx_hw_descr);
@@ -2340,13 +2445,14 @@ int wl1271_init_ieee80211(struct wl1271 *wl)
                IEEE80211_HW_CONNECTION_MONITOR |
                IEEE80211_HW_SUPPORTS_CQM_RSSI;
 
+       wl->hw->wiphy->cipher_suites = cipher_suites;
+       wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
+
        wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
                BIT(NL80211_IFTYPE_ADHOC);
        wl->hw->wiphy->max_scan_ssids = 1;
        wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
-
-       if (wl1271_11a_enabled())
-               wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
+       wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
 
        wl->hw->queues = 4;
        wl->hw->max_rates = 1;
@@ -2365,6 +2471,7 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
        struct platform_device *plat_dev = NULL;
        struct wl1271 *wl;
        int i, ret;
+       unsigned int order;
 
        hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
        if (!hw) {
@@ -2392,6 +2499,10 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
 
        INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
        INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
+       INIT_WORK(&wl->irq_work, wl1271_irq_work);
+       INIT_WORK(&wl->tx_work, wl1271_tx_work);
+       INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
+       INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
        wl->channel = WL1271_DEFAULT_CHANNEL;
        wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
        wl->default_key = 0;
@@ -2423,11 +2534,18 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
 
        wl1271_debugfs_init(wl);
 
+       order = get_order(WL1271_AGGR_BUFFER_SIZE);
+       wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
+       if (!wl->aggr_buf) {
+               ret = -ENOMEM;
+               goto err_hw;
+       }
+
        /* Register platform device */
        ret = platform_device_register(wl->plat_dev);
        if (ret) {
                wl1271_error("couldn't register platform device");
-               goto err_hw;
+               goto err_aggr;
        }
        dev_set_drvdata(&wl->plat_dev->dev, wl);
 
@@ -2453,6 +2571,9 @@ err_bt_coex_state:
 err_platform:
        platform_device_unregister(wl->plat_dev);
 
+err_aggr:
+       free_pages((unsigned long)wl->aggr_buf, order);
+
 err_hw:
        wl1271_debugfs_exit(wl);
        kfree(plat_dev);
@@ -2469,6 +2590,8 @@ EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
 int wl1271_free_hw(struct wl1271 *wl)
 {
        platform_device_unregister(wl->plat_dev);
+       free_pages((unsigned long)wl->aggr_buf,
+                       get_order(WL1271_AGGR_BUFFER_SIZE));
        kfree(wl->plat_dev);
 
        wl1271_debugfs_exit(wl);
index a5e60e0403e5ad90f2b35f6900dbfa71aafe52ea..e3c332e2f97c06646174e6661241f723e546b561 100644 (file)
@@ -39,6 +39,9 @@ void wl1271_elp_work(struct work_struct *work)
 
        mutex_lock(&wl->mutex);
 
+       if (unlikely(wl->state == WL1271_STATE_OFF))
+               goto out;
+
        if (test_bit(WL1271_FLAG_IN_ELP, &wl->flags) ||
            (!test_bit(WL1271_FLAG_PSM, &wl->flags) &&
             !test_bit(WL1271_FLAG_IDLE, &wl->flags)))
@@ -61,7 +64,7 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl)
            test_bit(WL1271_FLAG_IDLE, &wl->flags)) {
                cancel_delayed_work(&wl->elp_work);
                ieee80211_queue_delayed_work(wl->hw, &wl->elp_work,
-                                       msecs_to_jiffies(ELP_ENTRY_DELAY));
+                                            msecs_to_jiffies(ELP_ENTRY_DELAY));
        }
 }
 
@@ -96,6 +99,7 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake)
                        &compl, msecs_to_jiffies(WL1271_WAKEUP_TIMEOUT));
                if (ret == 0) {
                        wl1271_error("ELP wakeup timeout!");
+                       ieee80211_queue_work(wl->hw, &wl->recovery_work);
                        ret = -ETIMEDOUT;
                        goto err;
                } else if (ret < 0) {
@@ -121,7 +125,7 @@ out:
 }
 
 int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode,
-                      bool send)
+                      u32 rates, bool send)
 {
        int ret;
 
@@ -129,7 +133,14 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode,
        case STATION_POWER_SAVE_MODE:
                wl1271_debug(DEBUG_PSM, "entering psm");
 
-               ret = wl1271_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE, send);
+               ret = wl1271_acx_wake_up_conditions(wl);
+               if (ret < 0) {
+                       wl1271_error("couldn't set wake up conditions");
+                       return ret;
+               }
+
+               ret = wl1271_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE,
+                                        rates, send);
                if (ret < 0)
                        return ret;
 
@@ -152,7 +163,8 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode,
                if (ret < 0)
                        return ret;
 
-               ret = wl1271_cmd_ps_mode(wl, STATION_ACTIVE_MODE, send);
+               ret = wl1271_cmd_ps_mode(wl, STATION_ACTIVE_MODE,
+                                        rates, send);
                if (ret < 0)
                        return ret;
 
index 940276f517a40bef3d649cc0522f5d989b9ba43f..6ba7b032736f260aa5c418b1c32710b025c70496 100644 (file)
@@ -28,7 +28,7 @@
 #include "wl1271_acx.h"
 
 int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode,
-                      bool send);
+                      u32 rates, bool send);
 void wl1271_ps_elp_sleep(struct wl1271 *wl);
 int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake);
 void wl1271_elp_work(struct work_struct *work);
index 94da5dd7723c14ef70f4bfe531c508941b48603b..bea133b6e4893e2d61cbeff1e4d1f31d1faa42c4 100644 (file)
@@ -74,7 +74,7 @@ static void wl1271_rx_status(struct wl1271 *wl,
        }
 }
 
-static void wl1271_rx_handle_data(struct wl1271 *wl, u32 length)
+static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length)
 {
        struct wl1271_rx_descriptor *desc;
        struct sk_buff *skb;
@@ -87,16 +87,16 @@ static void wl1271_rx_handle_data(struct wl1271 *wl, u32 length)
         * workaround this by not retrieving them at all.
         */
        if (unlikely(wl->state == WL1271_STATE_PLT))
-               return;
+               return -EINVAL;
 
        skb = __dev_alloc_skb(length, GFP_KERNEL);
        if (!skb) {
                wl1271_error("Couldn't allocate RX frame");
-               return;
+               return -ENOMEM;
        }
 
        buf = skb_put(skb, length);
-       wl1271_read(wl, WL1271_SLV_MEM_DATA, buf, length, true);
+       memcpy(buf, data, length);
 
        /* the data read starts with the descriptor */
        desc = (struct wl1271_rx_descriptor *) buf;
@@ -116,6 +116,8 @@ static void wl1271_rx_handle_data(struct wl1271 *wl, u32 length)
        skb_trim(skb, skb->len - desc->pad_len);
 
        ieee80211_rx_ni(wl->hw, skb);
+
+       return 0;
 }
 
 void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status)
@@ -124,31 +126,60 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status)
        u32 buf_size;
        u32 fw_rx_counter  = status->fw_rx_counter & NUM_RX_PKT_DESC_MOD_MASK;
        u32 drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK;
+       u32 rx_counter;
        u32 mem_block;
+       u32 pkt_length;
+       u32 pkt_offset;
 
        while (drv_rx_counter != fw_rx_counter) {
-               mem_block = wl1271_rx_get_mem_block(status, drv_rx_counter);
-               buf_size = wl1271_rx_get_buf_size(status, drv_rx_counter);
+               buf_size = 0;
+               rx_counter = drv_rx_counter;
+               while (rx_counter != fw_rx_counter) {
+                       pkt_length = wl1271_rx_get_buf_size(status, rx_counter);
+                       if (buf_size + pkt_length > WL1271_AGGR_BUFFER_SIZE)
+                               break;
+                       buf_size += pkt_length;
+                       rx_counter++;
+                       rx_counter &= NUM_RX_PKT_DESC_MOD_MASK;
+               }
 
                if (buf_size == 0) {
                        wl1271_warning("received empty data");
                        break;
                }
 
+               /*
+                * Choose the block we want to read
+                * For aggregated packets, only the first memory block should
+                * be retrieved. The FW takes care of the rest.
+                */
+               mem_block = wl1271_rx_get_mem_block(status, drv_rx_counter);
                wl->rx_mem_pool_addr.addr = (mem_block << 8) +
                        le32_to_cpu(wl_mem_map->packet_memory_pool_start);
                wl->rx_mem_pool_addr.addr_extra =
                        wl->rx_mem_pool_addr.addr + 4;
-
-               /* Choose the block we want to read */
                wl1271_write(wl, WL1271_SLV_REG_DATA, &wl->rx_mem_pool_addr,
-                            sizeof(wl->rx_mem_pool_addr), false);
-
-               wl1271_rx_handle_data(wl, buf_size);
-
-               wl->rx_counter++;
-               drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK;
+                               sizeof(wl->rx_mem_pool_addr), false);
+
+               /* Read all available packets at once */
+               wl1271_read(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf,
+                               buf_size, true);
+
+               /* Split data into separate packets */
+               pkt_offset = 0;
+               while (pkt_offset < buf_size) {
+                       pkt_length = wl1271_rx_get_buf_size(status,
+                                       drv_rx_counter);
+                       if (wl1271_rx_handle_data(wl,
+                                       wl->aggr_buf + pkt_offset,
+                                       pkt_length) < 0)
+                               break;
+                       wl->rx_counter++;
+                       drv_rx_counter++;
+                       drv_rx_counter &= NUM_RX_PKT_DESC_MOD_MASK;
+                       pkt_offset += pkt_length;
+               }
        }
-
-       wl1271_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter);
+       wl1271_write32(wl, RX_DRIVER_COUNTER_ADDRESS,
+                       cpu_to_le32(wl->rx_counter));
 }
index e4950c8e396e38a57c553c81875ab51b2aa04d43..909bb47995b6907ee8afad05c3acf37500043d4a 100644 (file)
 #include "wl1271_scan.h"
 #include "wl1271_acx.h"
 
+void wl1271_scan_complete_work(struct work_struct *work)
+{
+       struct delayed_work *dwork;
+       struct wl1271 *wl;
+
+       dwork = container_of(work, struct delayed_work, work);
+       wl = container_of(dwork, struct wl1271, scan_complete_work);
+
+       wl1271_debug(DEBUG_SCAN, "Scanning complete");
+
+       mutex_lock(&wl->mutex);
+
+       if (wl->scan.state == WL1271_SCAN_STATE_IDLE) {
+               mutex_unlock(&wl->mutex);
+               return;
+       }
+
+       wl->scan.state = WL1271_SCAN_STATE_IDLE;
+       kfree(wl->scan.scanned_ch);
+       wl->scan.scanned_ch = NULL;
+       mutex_unlock(&wl->mutex);
+
+       ieee80211_scan_completed(wl->hw, false);
+
+       if (wl->scan.failed) {
+               wl1271_info("Scan completed due to error.");
+               ieee80211_queue_work(wl->hw, &wl->recovery_work);
+       }
+}
+
+
 static int wl1271_get_scan_channels(struct wl1271 *wl,
                                    struct cfg80211_scan_request *req,
                                    struct basic_scan_channel_params *channels,
                                    enum ieee80211_band band, bool passive)
 {
+       struct conf_scan_settings *c = &wl->conf.scan;
        int i, j;
        u32 flags;
 
@@ -60,10 +92,17 @@ static int wl1271_get_scan_channels(struct wl1271 *wl,
                        wl1271_debug(DEBUG_SCAN, "beacon_found %d",
                                     req->channels[i]->beacon_found);
 
-                       channels[j].min_duration =
-                               cpu_to_le32(WL1271_SCAN_CHAN_MIN_DURATION);
-                       channels[j].max_duration =
-                               cpu_to_le32(WL1271_SCAN_CHAN_MAX_DURATION);
+                       if (!passive) {
+                               channels[j].min_duration =
+                                       cpu_to_le32(c->min_dwell_time_active);
+                               channels[j].max_duration =
+                                       cpu_to_le32(c->max_dwell_time_active);
+                       } else {
+                               channels[j].min_duration =
+                                       cpu_to_le32(c->min_dwell_time_passive);
+                               channels[j].max_duration =
+                                       cpu_to_le32(c->max_dwell_time_passive);
+                       }
                        channels[j].early_termination = 0;
                        channels[j].tx_power_att = req->channels[i]->max_power;
                        channels[j].channel = req->channels[i]->hw_value;
@@ -100,8 +139,11 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band,
 
        /* We always use high priority scans */
        scan_options = WL1271_SCAN_OPT_PRIORITY_HIGH;
-       if(passive)
+
+       /* No SSIDs means that we have a forced passive scan */
+       if (passive || wl->scan.req->n_ssids == 0)
                scan_options |= WL1271_SCAN_OPT_PASSIVE;
+
        cmd->params.scan_options = cpu_to_le16(scan_options);
 
        cmd->params.n_ch = wl1271_get_scan_channels(wl, wl->scan.req,
@@ -117,7 +159,7 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band,
        cmd->params.rx_filter_options =
                cpu_to_le32(CFG_RX_PRSP_EN | CFG_RX_MGMT_EN | CFG_RX_BCN_EN);
 
-       cmd->params.n_probe_reqs = WL1271_SCAN_PROBE_REQS;
+       cmd->params.n_probe_reqs = wl->conf.scan.num_probe_reqs;
        cmd->params.tx_rate = cpu_to_le32(basic_rate);
        cmd->params.tid_trigger = 0;
        cmd->params.scan_tag = WL1271_SCAN_DEFAULT_TAG;
@@ -165,7 +207,7 @@ out:
 
 void wl1271_scan_stm(struct wl1271 *wl)
 {
-       int ret;
+       int ret = 0;
 
        switch (wl->scan.state) {
        case WL1271_SCAN_STATE_IDLE:
@@ -185,7 +227,7 @@ void wl1271_scan_stm(struct wl1271 *wl)
                ret = wl1271_scan_send(wl, IEEE80211_BAND_2GHZ, true,
                                       wl->conf.tx.basic_rate);
                if (ret == WL1271_NOTHING_TO_SCAN) {
-                       if (wl1271_11a_enabled())
+                       if (wl->enable_11a)
                                wl->scan.state = WL1271_SCAN_STATE_5GHZ_ACTIVE;
                        else
                                wl->scan.state = WL1271_SCAN_STATE_DONE;
@@ -215,18 +257,22 @@ void wl1271_scan_stm(struct wl1271 *wl)
                break;
 
        case WL1271_SCAN_STATE_DONE:
-               ieee80211_scan_completed(wl->hw, false);
-
-               kfree(wl->scan.scanned_ch);
-               wl->scan.scanned_ch = NULL;
-
-               wl->scan.state = WL1271_SCAN_STATE_IDLE;
+               wl->scan.failed = false;
+               cancel_delayed_work(&wl->scan_complete_work);
+               ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work,
+                                            msecs_to_jiffies(0));
                break;
 
        default:
                wl1271_error("invalid scan state");
                break;
        }
+
+       if (ret < 0) {
+               cancel_delayed_work(&wl->scan_complete_work);
+               ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work,
+                                            msecs_to_jiffies(0));
+       }
 }
 
 int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
@@ -249,6 +295,11 @@ int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
        wl->scan.scanned_ch = kcalloc(req->n_channels,
                                      sizeof(*wl->scan.scanned_ch),
                                      GFP_KERNEL);
+       /* we assume failure so that timeout scenarios are handled correctly */
+       wl->scan.failed = true;
+       ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work,
+                                    msecs_to_jiffies(WL1271_SCAN_TIMEOUT));
+
        wl1271_scan_stm(wl);
 
        return 0;
index f1815700f5f9da97464cba2f727920fd45d8f219..6d57127b5e6be10b438d73f51faacf49e86c75b0 100644 (file)
@@ -32,6 +32,7 @@ int wl1271_scan_build_probe_req(struct wl1271 *wl,
                                const u8 *ssid, size_t ssid_len,
                                const u8 *ie, size_t ie_len, u8 band);
 void wl1271_scan_stm(struct wl1271 *wl);
+void wl1271_scan_complete_work(struct work_struct *work);
 
 #define WL1271_SCAN_MAX_CHANNELS       24
 #define WL1271_SCAN_DEFAULT_TAG        1
@@ -39,11 +40,10 @@ void wl1271_scan_stm(struct wl1271 *wl);
 #define WL1271_SCAN_OPT_ACTIVE         0
 #define WL1271_SCAN_OPT_PASSIVE               1
 #define WL1271_SCAN_OPT_PRIORITY_HIGH  4
-#define WL1271_SCAN_CHAN_MIN_DURATION  30000  /* TU */
-#define WL1271_SCAN_CHAN_MAX_DURATION  60000  /* TU */
 #define WL1271_SCAN_BAND_2_4_GHZ 0
 #define WL1271_SCAN_BAND_5_GHZ 1
-#define WL1271_SCAN_PROBE_REQS 3
+
+#define WL1271_SCAN_TIMEOUT    10000 /* msec */
 
 enum {
        WL1271_SCAN_STATE_IDLE,
index f2f04663627c2b43fb80b42c249748e4721ed30d..4c250d7dc3fa436d53d9c73362622d188f4d965d 100644 (file)
@@ -274,9 +274,8 @@ static void __devexit wl1271_remove(struct sdio_func *func)
 {
        struct wl1271 *wl = sdio_get_drvdata(func);
 
-       free_irq(wl->irq, wl);
-
        wl1271_unregister_hw(wl);
+       free_irq(wl->irq, wl);
        wl1271_free_hw(wl);
 }
 
index ced0a9e2c7e14c02faa5d89b917222b2d89bf573..ef801680773f623017d7e4e514d5a827daa85d98 100644 (file)
                ((WL1271_BUSY_WORD_LEN - 4) / sizeof(u32))
 #define HW_ACCESS_WSPI_INIT_CMD_MASK  0
 
+/* HW limitation: maximum possible chunk size is 4095 bytes */
+#define WSPI_MAX_CHUNK_SIZE    4092
+
+#define WSPI_MAX_NUM_OF_CHUNKS (WL1271_AGGR_BUFFER_SIZE / WSPI_MAX_CHUNK_SIZE)
+
 static inline struct spi_device *wl_to_spi(struct wl1271 *wl)
 {
        return wl->if_priv;
@@ -202,90 +207,117 @@ static int wl1271_spi_read_busy(struct wl1271 *wl)
 static void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf,
                                size_t len, bool fixed)
 {
-       struct spi_transfer t[3];
+       struct spi_transfer t[2];
        struct spi_message m;
        u32 *busy_buf;
        u32 *cmd;
+       u32 chunk_len;
 
-       cmd = &wl->buffer_cmd;
-       busy_buf = wl->buffer_busyword;
+       while (len > 0) {
+               chunk_len = min((size_t)WSPI_MAX_CHUNK_SIZE, len);
 
-       *cmd = 0;
-       *cmd |= WSPI_CMD_READ;
-       *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH;
-       *cmd |= addr & WSPI_CMD_BYTE_ADDR;
+               cmd = &wl->buffer_cmd;
+               busy_buf = wl->buffer_busyword;
 
-       if (fixed)
-               *cmd |= WSPI_CMD_FIXED;
+               *cmd = 0;
+               *cmd |= WSPI_CMD_READ;
+               *cmd |= (chunk_len << WSPI_CMD_BYTE_LENGTH_OFFSET) &
+                       WSPI_CMD_BYTE_LENGTH;
+               *cmd |= addr & WSPI_CMD_BYTE_ADDR;
 
-       spi_message_init(&m);
-       memset(t, 0, sizeof(t));
+               if (fixed)
+                       *cmd |= WSPI_CMD_FIXED;
 
-       t[0].tx_buf = cmd;
-       t[0].len = 4;
-       t[0].cs_change = true;
-       spi_message_add_tail(&t[0], &m);
+               spi_message_init(&m);
+               memset(t, 0, sizeof(t));
 
-       /* Busy and non busy words read */
-       t[1].rx_buf = busy_buf;
-       t[1].len = WL1271_BUSY_WORD_LEN;
-       t[1].cs_change = true;
-       spi_message_add_tail(&t[1], &m);
+               t[0].tx_buf = cmd;
+               t[0].len = 4;
+               t[0].cs_change = true;
+               spi_message_add_tail(&t[0], &m);
 
-       spi_sync(wl_to_spi(wl), &m);
+               /* Busy and non busy words read */
+               t[1].rx_buf = busy_buf;
+               t[1].len = WL1271_BUSY_WORD_LEN;
+               t[1].cs_change = true;
+               spi_message_add_tail(&t[1], &m);
 
-       if (!(busy_buf[WL1271_BUSY_WORD_CNT - 1] & 0x1) &&
-           wl1271_spi_read_busy(wl)) {
-               memset(buf, 0, len);
-               return;
-       }
+               spi_sync(wl_to_spi(wl), &m);
 
-       spi_message_init(&m);
-       memset(t, 0, sizeof(t));
+               if (!(busy_buf[WL1271_BUSY_WORD_CNT - 1] & 0x1) &&
+                   wl1271_spi_read_busy(wl)) {
+                       memset(buf, 0, chunk_len);
+                       return;
+               }
 
-       t[0].rx_buf = buf;
-       t[0].len = len;
-       t[0].cs_change = true;
-       spi_message_add_tail(&t[0], &m);
+               spi_message_init(&m);
+               memset(t, 0, sizeof(t));
 
-       spi_sync(wl_to_spi(wl), &m);
+               t[0].rx_buf = buf;
+               t[0].len = chunk_len;
+               t[0].cs_change = true;
+               spi_message_add_tail(&t[0], &m);
+
+               spi_sync(wl_to_spi(wl), &m);
+
+               wl1271_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd));
+               wl1271_dump(DEBUG_SPI, "spi_read buf <- ", buf, chunk_len);
 
-       wl1271_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd));
-       wl1271_dump(DEBUG_SPI, "spi_read buf <- ", buf, len);
+               if (!fixed)
+                       addr += chunk_len;
+               buf += chunk_len;
+               len -= chunk_len;
+       }
 }
 
 static void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf,
                          size_t len, bool fixed)
 {
-       struct spi_transfer t[2];
+       struct spi_transfer t[2 * WSPI_MAX_NUM_OF_CHUNKS];
        struct spi_message m;
+       u32 commands[WSPI_MAX_NUM_OF_CHUNKS];
        u32 *cmd;
+       u32 chunk_len;
+       int i;
 
-       cmd = &wl->buffer_cmd;
-
-       *cmd = 0;
-       *cmd |= WSPI_CMD_WRITE;
-       *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH;
-       *cmd |= addr & WSPI_CMD_BYTE_ADDR;
-
-       if (fixed)
-               *cmd |= WSPI_CMD_FIXED;
+       WARN_ON(len > WL1271_AGGR_BUFFER_SIZE);
 
        spi_message_init(&m);
        memset(t, 0, sizeof(t));
 
-       t[0].tx_buf = cmd;
-       t[0].len = sizeof(*cmd);
-       spi_message_add_tail(&t[0], &m);
+       cmd = &commands[0];
+       i = 0;
+       while (len > 0) {
+               chunk_len = min((size_t)WSPI_MAX_CHUNK_SIZE, len);
 
-       t[1].tx_buf = buf;
-       t[1].len = len;
-       spi_message_add_tail(&t[1], &m);
+               *cmd = 0;
+               *cmd |= WSPI_CMD_WRITE;
+               *cmd |= (chunk_len << WSPI_CMD_BYTE_LENGTH_OFFSET) &
+                       WSPI_CMD_BYTE_LENGTH;
+               *cmd |= addr & WSPI_CMD_BYTE_ADDR;
 
-       spi_sync(wl_to_spi(wl), &m);
+               if (fixed)
+                       *cmd |= WSPI_CMD_FIXED;
 
-       wl1271_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd));
-       wl1271_dump(DEBUG_SPI, "spi_write buf -> ", buf, len);
+               t[i].tx_buf = cmd;
+               t[i].len = sizeof(*cmd);
+               spi_message_add_tail(&t[i++], &m);
+
+               t[i].tx_buf = buf;
+               t[i].len = chunk_len;
+               spi_message_add_tail(&t[i++], &m);
+
+               wl1271_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd));
+               wl1271_dump(DEBUG_SPI, "spi_write buf -> ", buf, chunk_len);
+
+               if (!fixed)
+                       addr += chunk_len;
+               buf += chunk_len;
+               len -= chunk_len;
+               cmd++;
+       }
+
+       spi_sync(wl_to_spi(wl), &m);
 }
 
 static irqreturn_t wl1271_irq(int irq, void *cookie)
@@ -416,9 +448,8 @@ static int __devexit wl1271_remove(struct spi_device *spi)
 {
        struct wl1271 *wl = dev_get_drvdata(&spi->dev);
 
-       free_irq(wl->irq, wl);
-
        wl1271_unregister_hw(wl);
+       free_irq(wl->irq, wl);
        wl1271_free_hw(wl);
 
        return 0;
index 6e0952f79e9a79e942a4ed3182ab6f419cba07c6..a3aa84386c88b3aef93cbfe4210e796797738974 100644 (file)
@@ -199,19 +199,6 @@ static int wl1271_tm_cmd_nvs_push(struct wl1271 *wl, struct nlattr *tb[])
        buf = nla_data(tb[WL1271_TM_ATTR_DATA]);
        len = nla_len(tb[WL1271_TM_ATTR_DATA]);
 
-       /*
-        * FIXME: the LEGACY NVS image support (NVS's missing the 5GHz band
-        * configurations) can be removed when those NVS files stop floating
-        * around.
-        */
-       if (len != sizeof(struct wl1271_nvs_file) &&
-           (len != WL1271_INI_LEGACY_NVS_FILE_SIZE ||
-            wl1271_11a_enabled())) {
-               wl1271_error("nvs size is not as expected: %zu != %zu",
-                            len, sizeof(struct wl1271_nvs_file));
-               return -EMSGSIZE;
-       }
-
        mutex_lock(&wl->mutex);
 
        kfree(wl->nvs);
@@ -224,6 +211,7 @@ static int wl1271_tm_cmd_nvs_push(struct wl1271 *wl, struct nlattr *tb[])
        }
 
        memcpy(wl->nvs, buf, len);
+       wl->nvs_len = len;
 
        wl1271_debug(DEBUG_TESTMODE, "testmode pushed nvs");
 
index dc0b46c93c4b52aec49441dc518613cf6f762343..e3dc13c4d01ad0b572267526efae5f666b5bf757 100644 (file)
@@ -43,13 +43,17 @@ static int wl1271_tx_id(struct wl1271 *wl, struct sk_buff *skb)
        return -EBUSY;
 }
 
-static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra)
+static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
+                               u32 buf_offset)
 {
        struct wl1271_tx_hw_descr *desc;
        u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra;
        u32 total_blocks;
        int id, ret = -EBUSY;
 
+       if (buf_offset + total_len > WL1271_AGGR_BUFFER_SIZE)
+               return -EBUSY;
+
        /* allocate free identifier for the packet */
        id = wl1271_tx_id(wl, skb);
        if (id < 0)
@@ -82,7 +86,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra)
        return ret;
 }
 
-static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
+static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
                              u32 extra, struct ieee80211_tx_info *control)
 {
        struct timespec ts;
@@ -110,9 +114,9 @@ static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
        /* configure the tx attributes */
        tx_attr = wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER;
 
-       /* queue */
+       /* queue (we use same identifiers for tid's and ac's */
        ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
-       desc->tid = wl1271_tx_ac_to_tid(ac);
+       desc->tid = ac;
 
        desc->aid = TX_HW_DEFAULT_AID;
        desc->reserved = 0;
@@ -133,59 +137,17 @@ static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
        desc->tx_attr = cpu_to_le16(tx_attr);
 
        wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d", pad);
-       return 0;
-}
-
-static int wl1271_tx_send_packet(struct wl1271 *wl, struct sk_buff *skb,
-                                struct ieee80211_tx_info *control)
-{
-
-       struct wl1271_tx_hw_descr *desc;
-       int len;
-
-       /* FIXME: This is a workaround for getting non-aligned packets.
-          This happens at least with EAPOL packets from the user space.
-          Our DMA requires packets to be aligned on a 4-byte boundary.
-       */
-       if (unlikely((long)skb->data & 0x03)) {
-               int offset = (4 - (long)skb->data) & 0x03;
-               wl1271_debug(DEBUG_TX, "skb offset %d", offset);
-
-               /* check whether the current skb can be used */
-               if (!skb_cloned(skb) && (skb_tailroom(skb) >= offset)) {
-                       unsigned char *src = skb->data;
-
-                       /* align the buffer on a 4-byte boundary */
-                       skb_reserve(skb, offset);
-                       memmove(skb->data, src, skb->len);
-               } else {
-                       wl1271_info("No handler, fixme!");
-                       return -EINVAL;
-               }
-       }
-
-       len = WL1271_TX_ALIGN(skb->len);
-
-       /* perform a fixed address block write with the packet */
-       wl1271_write(wl, WL1271_SLV_MEM_DATA, skb->data, len, true);
-
-       /* write packet new counter into the write access register */
-       wl->tx_packets_count++;
-
-       desc = (struct wl1271_tx_hw_descr *) skb->data;
-       wl1271_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u (%u words)",
-                    desc->id, skb, len, desc->length);
-
-       return 0;
 }
 
 /* caller must hold wl->mutex */
-static int wl1271_tx_frame(struct wl1271 *wl, struct sk_buff *skb)
+static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb,
+                                                       u32 buf_offset)
 {
        struct ieee80211_tx_info *info;
        u32 extra = 0;
        int ret = 0;
        u8 idx;
+       u32 total_len;
 
        if (!skb)
                return -EINVAL;
@@ -208,19 +170,22 @@ static int wl1271_tx_frame(struct wl1271 *wl, struct sk_buff *skb)
                }
        }
 
-       ret = wl1271_tx_allocate(wl, skb, extra);
+       ret = wl1271_tx_allocate(wl, skb, extra, buf_offset);
        if (ret < 0)
                return ret;
 
-       ret = wl1271_tx_fill_hdr(wl, skb, extra, info);
-       if (ret < 0)
-               return ret;
+       wl1271_tx_fill_hdr(wl, skb, extra, info);
 
-       ret = wl1271_tx_send_packet(wl, skb, info);
-       if (ret < 0)
-               return ret;
+       /*
+        * The length of each packet is stored in terms of words. Thus, we must
+        * pad the skb data to make sure its length is aligned.
+        * The number of padding bytes is computed and set in wl1271_tx_fill_hdr
+        */
+       total_len = WL1271_TX_ALIGN(skb->len);
+       memcpy(wl->aggr_buf + buf_offset, skb->data, skb->len);
+       memset(wl->aggr_buf + buf_offset + skb->len, 0, total_len - skb->len);
 
-       return ret;
+       return total_len;
 }
 
 u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set)
@@ -245,7 +210,7 @@ void wl1271_tx_work(struct work_struct *work)
        struct sk_buff *skb;
        bool woken_up = false;
        u32 sta_rates = 0;
-       u32 prev_tx_packets_count;
+       u32 buf_offset;
        int ret;
 
        /* check if the rates supported by the AP have changed */
@@ -262,14 +227,15 @@ void wl1271_tx_work(struct work_struct *work)
        if (unlikely(wl->state == WL1271_STATE_OFF))
                goto out;
 
-       prev_tx_packets_count = wl->tx_packets_count;
-
        /* if rates have changed, re-configure the rate policy */
        if (unlikely(sta_rates)) {
                wl->rate_set = wl1271_tx_enabled_rates_get(wl, sta_rates);
                wl1271_acx_rate_policies(wl);
        }
 
+       /* Prepare the transfer buffer, by aggregating all
+        * available packets */
+       buf_offset = 0;
        while ((skb = skb_dequeue(&wl->tx_queue))) {
                if (!woken_up) {
                        ret = wl1271_ps_elp_wakeup(wl, false);
@@ -278,21 +244,30 @@ void wl1271_tx_work(struct work_struct *work)
                        woken_up = true;
                }
 
-               ret = wl1271_tx_frame(wl, skb);
+               ret = wl1271_prepare_tx_frame(wl, skb, buf_offset);
                if (ret == -EBUSY) {
-                       /* firmware buffer is full, lets stop transmitting. */
+                       /*
+                        * Either the firmware buffer is full, or the
+                        * aggregation buffer is.
+                        * Queue back last skb, and stop aggregating.
+                        */
                        skb_queue_head(&wl->tx_queue, skb);
                        goto out_ack;
                } else if (ret < 0) {
                        dev_kfree_skb(skb);
                        goto out_ack;
                }
+               buf_offset += ret;
+               wl->tx_packets_count++;
        }
 
 out_ack:
-       /* interrupt the firmware with the new packets */
-       if (prev_tx_packets_count != wl->tx_packets_count)
+       if (buf_offset) {
+               wl1271_write(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf,
+                               buf_offset, true);
+               /* interrupt the firmware with the new packets */
                wl1271_write32(wl, WL1271_HOST_WR_ACCESS, wl->tx_packets_count);
+       }
 
 out:
        if (woken_up)
@@ -422,8 +397,6 @@ void wl1271_tx_reset(struct wl1271 *wl)
        struct sk_buff *skb;
 
        /* TX failure */
-/*     control->flags = 0; FIXME */
-
        while ((skb = skb_dequeue(&wl->tx_queue))) {
                wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb);
                ieee80211_tx_status(wl->hw, skb);
index 48bf92621c03390f9d6e40efa51f79674c766108..d12a129ad11cc79716e46ef771112c7429faa3c6 100644 (file)
@@ -139,23 +139,6 @@ static inline int wl1271_tx_get_queue(int queue)
        }
 }
 
-/* wl1271 tx descriptor needs the tid and we need to convert it from ac */
-static inline int wl1271_tx_ac_to_tid(int ac)
-{
-       switch (ac) {
-       case 0:
-               return 0;
-       case 1:
-               return 2;
-       case 2:
-               return 4;
-       case 3:
-               return 6;
-       default:
-               return 0;
-       }
-}
-
 void wl1271_tx_work(struct work_struct *work);
 void wl1271_tx_complete(struct wl1271 *wl);
 void wl1271_tx_reset(struct wl1271 *wl);
index f0518b0278a927b0998659daf1aed1c5e7793bc6..c08709fe36fc93f842cb4a6e0149741e0f6efaa6 100644 (file)
  *     channel for the specified amount of time. This can be used to do
  *     off-channel operations like transmit a Public Action frame and wait for
  *     a response while being associated to an AP on another channel.
- *     %NL80211_ATTR_WIPHY or %NL80211_ATTR_IFINDEX is used to specify which
- *     radio is used. %NL80211_ATTR_WIPHY_FREQ is used to specify the
+ *     %NL80211_ATTR_IFINDEX is used to specify which interface (and thus
+ *     radio) is used. %NL80211_ATTR_WIPHY_FREQ is used to specify the
  *     frequency for the operation and %NL80211_ATTR_WIPHY_CHANNEL_TYPE may be
  *     optionally used to specify additional channel parameters.
  *     %NL80211_ATTR_DURATION is used to specify the duration in milliseconds
  *     of any other interfaces, and other interfaces will again take
  *     precedence when they are used.
  *
+ * @NL80211_CMD_SET_WDS_PEER: Set the MAC address of the peer on a WDS interface.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -489,6 +491,7 @@ enum nl80211_commands {
        NL80211_CMD_NOTIFY_CQM,
 
        NL80211_CMD_SET_CHANNEL,
+       NL80211_CMD_SET_WDS_PEER,
 
        /* add new commands above here */
 
@@ -798,6 +801,9 @@ enum nl80211_commands {
  *      This is used in association with @NL80211_ATTR_WIPHY_TX_POWER_SETTING
  *      for non-automatic settings.
  *
+ * @NL80211_ATTR_SUPPORT_IBSS_RSN: The device supports IBSS RSN, which mostly
+ *     means support for per-station GTKs.
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -965,6 +971,8 @@ enum nl80211_attrs {
        NL80211_ATTR_CONTROL_PORT_ETHERTYPE,
        NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT,
 
+       NL80211_ATTR_SUPPORT_IBSS_RSN,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
@@ -1129,6 +1137,8 @@ enum nl80211_rate_info {
  * @NL80211_STA_INFO_RX_PACKETS: total received packet (u32, from this station)
  * @NL80211_STA_INFO_TX_PACKETS: total transmitted packets (u32, to this
  *     station)
+ * @NL80211_STA_INFO_TX_RETRIES: total retries (u32, to this station)
+ * @NL80211_STA_INFO_TX_FAILED: total failed packets (u32, to this station)
  */
 enum nl80211_sta_info {
        __NL80211_STA_INFO_INVALID,
@@ -1142,6 +1152,8 @@ enum nl80211_sta_info {
        NL80211_STA_INFO_TX_BITRATE,
        NL80211_STA_INFO_RX_PACKETS,
        NL80211_STA_INFO_TX_PACKETS,
+       NL80211_STA_INFO_TX_RETRIES,
+       NL80211_STA_INFO_TX_FAILED,
 
        /* keep last */
        __NL80211_STA_INFO_AFTER_LAST,
@@ -1400,6 +1412,7 @@ enum nl80211_reg_rule_flags {
  * @__NL80211_SURVEY_INFO_INVALID: attribute number 0 is reserved
  * @NL80211_SURVEY_INFO_FREQUENCY: center frequency of channel
  * @NL80211_SURVEY_INFO_NOISE: noise level of channel (u8, dBm)
+ * @NL80211_SURVEY_INFO_IN_USE: channel is currently being used
  * @NL80211_SURVEY_INFO_MAX: highest survey info attribute number
  *     currently defined
  * @__NL80211_SURVEY_INFO_AFTER_LAST: internal use
@@ -1408,6 +1421,7 @@ enum nl80211_survey_info {
        __NL80211_SURVEY_INFO_INVALID,
        NL80211_SURVEY_INFO_FREQUENCY,
        NL80211_SURVEY_INFO_NOISE,
+       NL80211_SURVEY_INFO_IN_USE,
 
        /* keep last */
        __NL80211_SURVEY_INFO_AFTER_LAST,
@@ -1654,11 +1668,14 @@ enum nl80211_auth_type {
  * @NL80211_KEYTYPE_GROUP: Group (broadcast/multicast) key
  * @NL80211_KEYTYPE_PAIRWISE: Pairwise (unicast/individual) key
  * @NL80211_KEYTYPE_PEERKEY: PeerKey (DLS)
+ * @NUM_NL80211_KEYTYPES: number of defined key types
  */
 enum nl80211_key_type {
        NL80211_KEYTYPE_GROUP,
        NL80211_KEYTYPE_PAIRWISE,
        NL80211_KEYTYPE_PEERKEY,
+
+       NUM_NL80211_KEYTYPES
 };
 
 /**
@@ -1689,6 +1706,9 @@ enum nl80211_wpa_versions {
  *     CCMP keys, each six bytes in little endian
  * @NL80211_KEY_DEFAULT: flag indicating default key
  * @NL80211_KEY_DEFAULT_MGMT: flag indicating default management key
+ * @NL80211_KEY_TYPE: the key type from enum nl80211_key_type, if not
+ *     specified the default depends on whether a MAC address was
+ *     given with the command using the key or not (u32)
  * @__NL80211_KEY_AFTER_LAST: internal
  * @NL80211_KEY_MAX: highest key attribute
  */
@@ -1700,6 +1720,7 @@ enum nl80211_key_attributes {
        NL80211_KEY_SEQ,
        NL80211_KEY_DEFAULT,
        NL80211_KEY_DEFAULT_MGMT,
+       NL80211_KEY_TYPE,
 
        /* keep last */
        __NL80211_KEY_AFTER_LAST,
index 95deae3968f4b5f24bb40a6b53b1dc9fbbc928cf..4f902e1908aaa191095c2f90741f96679b4b3113 100644 (file)
@@ -32,7 +32,20 @@ struct wl12xx_platform_data {
        int board_ref_clock;
 };
 
+#ifdef CONFIG_WL12XX_PLATFORM_DATA
+
 int wl12xx_set_platform_data(const struct wl12xx_platform_data *data);
+
+#else
+
+static inline
+int wl12xx_set_platform_data(const struct wl12xx_platform_data *data)
+{
+       return -ENOSYS;
+}
+
+#endif
+
 const struct wl12xx_platform_data *wl12xx_get_platform_data(void);
 
 #endif
index a0613ff62c97b3e6811f15f28b5950e8b3644e0d..0778d04b3bbe48ae52eabef6027cbbb3f0bec556 100644 (file)
@@ -293,12 +293,14 @@ struct key_params {
  * enum survey_info_flags - survey information flags
  *
  * @SURVEY_INFO_NOISE_DBM: noise (in dBm) was filled in
+ * @SURVEY_INFO_IN_USE: channel is currently being used
  *
  * Used by the driver to indicate which info in &struct survey_info
  * it has filled in during the get_survey().
  */
 enum survey_info_flags {
        SURVEY_INFO_NOISE_DBM = 1<<0,
+       SURVEY_INFO_IN_USE = 1<<1,
 };
 
 /**
@@ -399,6 +401,8 @@ struct station_parameters {
  *  (tx_bitrate, tx_bitrate_flags and tx_bitrate_mcs)
  * @STATION_INFO_RX_PACKETS: @rx_packets filled
  * @STATION_INFO_TX_PACKETS: @tx_packets filled
+ * @STATION_INFO_TX_RETRIES: @tx_retries filled
+ * @STATION_INFO_TX_FAILED: @tx_failed filled
  */
 enum station_info_flags {
        STATION_INFO_INACTIVE_TIME      = 1<<0,
@@ -411,6 +415,8 @@ enum station_info_flags {
        STATION_INFO_TX_BITRATE         = 1<<7,
        STATION_INFO_RX_PACKETS         = 1<<8,
        STATION_INFO_TX_PACKETS         = 1<<9,
+       STATION_INFO_TX_RETRIES         = 1<<10,
+       STATION_INFO_TX_FAILED          = 1<<11,
 };
 
 /**
@@ -460,6 +466,8 @@ struct rate_info {
  * @txrate: current unicast bitrate to this station
  * @rx_packets: packets received from this station
  * @tx_packets: packets transmitted to this station
+ * @tx_retries: cumulative retry counts
+ * @tx_failed: number of failed transmissions (retries exceeded, no ACK)
  * @generation: generation number for nl80211 dumps.
  *     This number should increase every time the list of stations
  *     changes, i.e. when a station is added or removed, so that
@@ -477,6 +485,8 @@ struct station_info {
        struct rate_info txrate;
        u32 rx_packets;
        u32 tx_packets;
+       u32 tx_retries;
+       u32 tx_failed;
 
        int generation;
 };
@@ -1128,13 +1138,14 @@ struct cfg80211_ops {
                                       struct vif_params *params);
 
        int     (*add_key)(struct wiphy *wiphy, struct net_device *netdev,
-                          u8 key_index, const u8 *mac_addr,
+                          u8 key_index, bool pairwise, const u8 *mac_addr,
                           struct key_params *params);
        int     (*get_key)(struct wiphy *wiphy, struct net_device *netdev,
-                          u8 key_index, const u8 *mac_addr, void *cookie,
+                          u8 key_index, bool pairwise, const u8 *mac_addr,
+                          void *cookie,
                           void (*callback)(void *cookie, struct key_params*));
        int     (*del_key)(struct wiphy *wiphy, struct net_device *netdev,
-                          u8 key_index, const u8 *mac_addr);
+                          u8 key_index, bool pairwise, const u8 *mac_addr);
        int     (*set_default_key)(struct wiphy *wiphy,
                                   struct net_device *netdev,
                                   u8 key_index);
@@ -1218,7 +1229,7 @@ struct cfg80211_ops {
        int     (*get_tx_power)(struct wiphy *wiphy, int *dbm);
 
        int     (*set_wds_peer)(struct wiphy *wiphy, struct net_device *dev,
-                               u8 *addr);
+                               const u8 *addr);
 
        void    (*rfkill_poll)(struct wiphy *wiphy);
 
@@ -1302,6 +1313,7 @@ struct cfg80211_ops {
  * @WIPHY_FLAG_CONTROL_PORT_PROTOCOL: This device supports setting the
  *     control port protocol ethertype. The device also honours the
  *     control_port_no_encrypt flag.
+ * @WIPHY_FLAG_IBSS_RSN: The device supports IBSS RSN.
  */
 enum wiphy_flags {
        WIPHY_FLAG_CUSTOM_REGULATORY            = BIT(0),
@@ -1312,6 +1324,7 @@ enum wiphy_flags {
        WIPHY_FLAG_4ADDR_AP                     = BIT(5),
        WIPHY_FLAG_4ADDR_STATION                = BIT(6),
        WIPHY_FLAG_CONTROL_PORT_PROTOCOL        = BIT(7),
+       WIPHY_FLAG_IBSS_RSN                     = BIT(7),
 };
 
 struct mac_address {
@@ -2551,8 +2564,6 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev,
                              enum nl80211_cqm_rssi_threshold_event rssi_event,
                              gfp_t gfp);
 
-#ifdef __KERNEL__
-
 /* Logging, debugging and troubleshooting/diagnostic helpers. */
 
 /* wiphy_printk helpers, similar to dev_printk */
@@ -2599,6 +2610,4 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev,
 #define wiphy_WARN(wiphy, format, args...)                     \
        WARN(1, "wiphy: %s\n" format, wiphy_name(wiphy), ##args);
 
-#endif
-
 #endif /* __NET_CFG80211_H */
index f7dcd2c7041266fadc9794efc50136c44c36d4f4..8a64b811a39aba9278a258396f268aa35a422e22 100644 (file)
@@ -20,6 +20,9 @@ struct genl_multicast_group {
        u32                     id;
 };
 
+struct genl_ops;
+struct genl_info;
+
 /**
  * struct genl_family - generic netlink family
  * @id: protocol family idenfitier
@@ -29,6 +32,10 @@ struct genl_multicast_group {
  * @maxattr: maximum number of attributes supported
  * @netnsok: set to true if the family can handle network
  *     namespaces and should be presented in all of them
+ * @pre_doit: called before an operation's doit callback, it may
+ *     do additional, common, filtering and return an error
+ * @post_doit: called after an operation's doit callback, it may
+ *     undo operations done by pre_doit, for example release locks
  * @attrbuf: buffer to store parsed attributes
  * @ops_list: list of all assigned operations
  * @family_list: family list
@@ -41,6 +48,12 @@ struct genl_family {
        unsigned int            version;
        unsigned int            maxattr;
        bool                    netnsok;
+       int                     (*pre_doit)(struct genl_ops *ops,
+                                           struct sk_buff *skb,
+                                           struct genl_info *info);
+       void                    (*post_doit)(struct genl_ops *ops,
+                                            struct sk_buff *skb,
+                                            struct genl_info *info);
        struct nlattr **        attrbuf;        /* private */
        struct list_head        ops_list;       /* private */
        struct list_head        family_list;    /* private */
@@ -55,6 +68,8 @@ struct genl_family {
  * @genlhdr: generic netlink message header
  * @userhdr: user specific header
  * @attrs: netlink attributes
+ * @_net: network namespace
+ * @user_ptr: user pointers
  */
 struct genl_info {
        u32                     snd_seq;
@@ -66,6 +81,7 @@ struct genl_info {
 #ifdef CONFIG_NET_NS
        struct net *            _net;
 #endif
+       void *                  user_ptr[2];
 };
 
 static inline struct net *genl_info_net(struct genl_info *info)
@@ -81,6 +97,7 @@ static inline void genl_info_net_set(struct genl_info *info, struct net *net)
 /**
  * struct genl_ops - generic netlink operations
  * @cmd: command identifier
+ * @internal_flags: flags used by the family
  * @flags: flags
  * @policy: attribute validation policy
  * @doit: standard command callback
@@ -90,6 +107,7 @@ static inline void genl_info_net_set(struct genl_info *info, struct net *net)
  */
 struct genl_ops {
        u8                      cmd;
+       u8                      internal_flags;
        unsigned int            flags;
        const struct nla_policy *policy;
        int                    (*doit)(struct sk_buff *skb,
index fe8b9dae4dee425c9f6df1245b7a1fbdef24842b..33aa2e39147b12baff9542729c70af6675898e01 100644 (file)
@@ -1041,6 +1041,13 @@ enum ieee80211_tkip_key_type {
  * @IEEE80211_HW_NEED_DTIM_PERIOD:
  *     This device needs to know the DTIM period for the BSS before
  *     associating.
+ *
+ * @IEEE80211_HW_SUPPORTS_PER_STA_GTK: The device's crypto engine supports
+ *     per-station GTKs as used by IBSS RSN or during fast transition. If
+ *     the device doesn't support per-station GTKs, but can be asked not
+ *     to decrypt group addressed frames, then IBSS RSN support is still
+ *     possible but software crypto will be used. Advertise the wiphy flag
+ *     only in that case.
  */
 enum ieee80211_hw_flags {
        IEEE80211_HW_HAS_RATE_CONTROL                   = 1<<0,
@@ -1064,6 +1071,7 @@ enum ieee80211_hw_flags {
        IEEE80211_HW_REPORTS_TX_ACK_STATUS              = 1<<18,
        IEEE80211_HW_CONNECTION_MONITOR                 = 1<<19,
        IEEE80211_HW_SUPPORTS_CQM_RSSI                  = 1<<20,
+       IEEE80211_HW_SUPPORTS_PER_STA_GTK               = 1<<21,
 };
 
 /**
@@ -1109,7 +1117,10 @@ enum ieee80211_hw_flags {
  * @sta_data_size: size (in bytes) of the drv_priv data area
  *     within &struct ieee80211_sta.
  *
- * @max_rates: maximum number of alternate rate retry stages
+ * @max_rates: maximum number of alternate rate retry stages the hw
+ *     can handle.
+ * @max_report_rates: maximum number of alternate rate retry stages
+ *     the hw can report back.
  * @max_rate_tries: maximum number of tries for each stage
  *
  * @napi_weight: weight used for NAPI polling.  You must specify an
@@ -1131,6 +1142,7 @@ struct ieee80211_hw {
        u16 max_listen_interval;
        s8 max_signal;
        u8 max_rates;
+       u8 max_report_rates;
        u8 max_rate_tries;
 };
 
@@ -2578,6 +2590,22 @@ void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success);
 void ieee80211_request_smps(struct ieee80211_vif *vif,
                            enum ieee80211_smps_mode smps_mode);
 
+/**
+ * ieee80211_key_removed - disable hw acceleration for key
+ * @key_conf: The key hw acceleration should be disabled for
+ *
+ * This allows drivers to indicate that the given key has been
+ * removed from hardware acceleration, due to a new key that
+ * was added. Don't use this if the key can continue to be used
+ * for TX, if the key restriction is on RX only it is permitted
+ * to keep the key for TX only and not call this function.
+ *
+ * Due to locking constraints, it may only be called during
+ * @set_key. This function must be allowed to sleep, and the
+ * key it tries to disable may still be used until it returns.
+ */
+void ieee80211_key_removed(struct ieee80211_key_conf *key_conf);
+
 /* Rate control API */
 
 /**
index 58eab9e8e4eedaaaef445cfc082546c1af1c1328..720b7a84af590f0660d4862c717113daaf0c65af 100644 (file)
@@ -56,7 +56,7 @@ static void ieee80211_free_tid_rx(struct rcu_head *h)
 }
 
 void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
-                                    u16 initiator, u16 reason)
+                                    u16 initiator, u16 reason, bool tx)
 {
        struct ieee80211_local *local = sta->local;
        struct tid_ampdu_rx *tid_rx;
@@ -81,7 +81,7 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
                                "aggregation for tid %d\n", tid);
 
        /* check if this is a self generated aggregation halt */
-       if (initiator == WLAN_BACK_RECIPIENT)
+       if (initiator == WLAN_BACK_RECIPIENT && tx)
                ieee80211_send_delba(sta->sdata, sta->sta.addr,
                                     tid, 0, reason);
 
@@ -92,10 +92,10 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
 }
 
 void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
-                                   u16 initiator, u16 reason)
+                                   u16 initiator, u16 reason, bool tx)
 {
        mutex_lock(&sta->ampdu_mlme.mtx);
-       ___ieee80211_stop_rx_ba_session(sta, tid, initiator, reason);
+       ___ieee80211_stop_rx_ba_session(sta, tid, initiator, reason, tx);
        mutex_unlock(&sta->ampdu_mlme.mtx);
 }
 
index c893f236acea771076b5572b42c82162c3684913..d4679b265ba88698298a403dac25392b61dc04e7 100644 (file)
@@ -145,7 +145,8 @@ static void kfree_tid_tx(struct rcu_head *rcu_head)
 }
 
 int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
-                                   enum ieee80211_back_parties initiator)
+                                   enum ieee80211_back_parties initiator,
+                                   bool tx)
 {
        struct ieee80211_local *local = sta->local;
        struct tid_ampdu_tx *tid_tx = sta->ampdu_mlme.tid_tx[tid];
@@ -175,6 +176,8 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
 
        set_bit(HT_AGG_STATE_STOPPING, &tid_tx->state);
 
+       del_timer_sync(&tid_tx->addba_resp_timer);
+
        /*
         * After this packets are no longer handed right through
         * to the driver but are put onto tid_tx->pending instead,
@@ -183,6 +186,7 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
        clear_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state);
 
        tid_tx->stop_initiator = initiator;
+       tid_tx->tx_stop = tx;
 
        ret = drv_ampdu_action(local, sta->sdata,
                               IEEE80211_AMPDU_TX_STOP,
@@ -575,13 +579,14 @@ void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_vif *vif,
 EXPORT_SYMBOL(ieee80211_start_tx_ba_cb_irqsafe);
 
 int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
-                                  enum ieee80211_back_parties initiator)
+                                  enum ieee80211_back_parties initiator,
+                                  bool tx)
 {
        int ret;
 
        mutex_lock(&sta->ampdu_mlme.mtx);
 
-       ret = ___ieee80211_stop_tx_ba_session(sta, tid, initiator);
+       ret = ___ieee80211_stop_tx_ba_session(sta, tid, initiator, tx);
 
        mutex_unlock(&sta->ampdu_mlme.mtx);
 
@@ -670,7 +675,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid)
                goto unlock_sta;
        }
 
-       if (tid_tx->stop_initiator == WLAN_BACK_INITIATOR)
+       if (tid_tx->stop_initiator == WLAN_BACK_INITIATOR && tid_tx->tx_stop)
                ieee80211_send_delba(sta->sdata, ra, tid,
                        WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE);
 
@@ -770,7 +775,8 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
 
                sta->ampdu_mlme.addba_req_num[tid] = 0;
        } else {
-               ___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR);
+               ___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR,
+                                               true);
        }
 
  out:
index c981604b71e6d78fa1d13d7ec4d8d03976396819..ecf9b7166ed151f044755534fe4b071c9ad382c5 100644 (file)
@@ -68,14 +68,42 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
                 params && params->use_4addr >= 0)
                sdata->u.mgd.use_4addr = params->use_4addr;
 
-       if (sdata->vif.type == NL80211_IFTYPE_MONITOR && flags)
-               sdata->u.mntr_flags = *flags;
+       if (sdata->vif.type == NL80211_IFTYPE_MONITOR && flags) {
+               struct ieee80211_local *local = sdata->local;
+
+               if (ieee80211_sdata_running(sdata)) {
+                       /*
+                        * Prohibit MONITOR_FLAG_COOK_FRAMES to be
+                        * changed while the interface is up.
+                        * Else we would need to add a lot of cruft
+                        * to update everything:
+                        *      cooked_mntrs, monitor and all fif_* counters
+                        *      reconfigure hardware
+                        */
+                       if ((*flags & MONITOR_FLAG_COOK_FRAMES) !=
+                           (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES))
+                               return -EBUSY;
+
+                       ieee80211_adjust_monitor_flags(sdata, -1);
+                       sdata->u.mntr_flags = *flags;
+                       ieee80211_adjust_monitor_flags(sdata, 1);
+
+                       ieee80211_configure_filter(local);
+               } else {
+                       /*
+                        * Because the interface is down, ieee80211_do_stop
+                        * and ieee80211_do_open take care of "everything"
+                        * mentioned in the comment above.
+                        */
+                       sdata->u.mntr_flags = *flags;
+               }
+       }
 
        return 0;
 }
 
 static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
-                            u8 key_idx, const u8 *mac_addr,
+                            u8 key_idx, bool pairwise, const u8 *mac_addr,
                             struct key_params *params)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
@@ -103,6 +131,9 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
        if (IS_ERR(key))
                return PTR_ERR(key);
 
+       if (pairwise)
+               key->conf.flags |= IEEE80211_KEY_FLAG_PAIRWISE;
+
        mutex_lock(&sdata->local->sta_mtx);
 
        if (mac_addr) {
@@ -125,7 +156,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
 }
 
 static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
-                            u8 key_idx, const u8 *mac_addr)
+                            u8 key_idx, bool pairwise, const u8 *mac_addr)
 {
        struct ieee80211_sub_if_data *sdata;
        struct sta_info *sta;
@@ -142,10 +173,17 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
                if (!sta)
                        goto out_unlock;
 
-               if (sta->key) {
-                       ieee80211_key_free(sdata->local, sta->key);
-                       WARN_ON(sta->key);
-                       ret = 0;
+               if (pairwise) {
+                       if (sta->ptk) {
+                               ieee80211_key_free(sdata->local, sta->ptk);
+                               ret = 0;
+                       }
+               } else {
+                       if (sta->gtk[key_idx]) {
+                               ieee80211_key_free(sdata->local,
+                                                  sta->gtk[key_idx]);
+                               ret = 0;
+                       }
                }
 
                goto out_unlock;
@@ -167,7 +205,8 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
 }
 
 static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
-                            u8 key_idx, const u8 *mac_addr, void *cookie,
+                            u8 key_idx, bool pairwise, const u8 *mac_addr,
+                            void *cookie,
                             void (*callback)(void *cookie,
                                              struct key_params *params))
 {
@@ -175,7 +214,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
        struct sta_info *sta = NULL;
        u8 seq[6] = {0};
        struct key_params params;
-       struct ieee80211_key *key;
+       struct ieee80211_key *key = NULL;
        u32 iv32;
        u16 iv16;
        int err = -ENOENT;
@@ -189,7 +228,10 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
                if (!sta)
                        goto out;
 
-               key = sta->key;
+               if (pairwise)
+                       key = sta->ptk;
+               else if (key_idx < NUM_DEFAULT_KEYS)
+                       key = sta->gtk[key_idx];
        } else
                key = sdata->keys[key_idx];
 
@@ -285,6 +327,8 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
                        STATION_INFO_TX_BYTES |
                        STATION_INFO_RX_PACKETS |
                        STATION_INFO_TX_PACKETS |
+                       STATION_INFO_TX_RETRIES |
+                       STATION_INFO_TX_FAILED |
                        STATION_INFO_TX_BITRATE;
 
        sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx);
@@ -292,6 +336,8 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
        sinfo->tx_bytes = sta->tx_bytes;
        sinfo->rx_packets = sta->rx_packets;
        sinfo->tx_packets = sta->tx_packets;
+       sinfo->tx_retries = sta->tx_retry_count;
+       sinfo->tx_failed = sta->tx_retry_failed;
 
        if ((sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) ||
            (sta->local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)) {
@@ -1317,7 +1363,7 @@ static int ieee80211_get_tx_power(struct wiphy *wiphy, int *dbm)
 }
 
 static int ieee80211_set_wds_peer(struct wiphy *wiphy, struct net_device *dev,
-                                 u8 *addr)
+                                 const u8 *addr)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
@@ -1366,7 +1412,7 @@ int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata,
        if (!sdata->u.mgd.associated ||
            sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT) {
                mutex_lock(&sdata->local->iflist_mtx);
-               ieee80211_recalc_smps(sdata->local, sdata);
+               ieee80211_recalc_smps(sdata->local);
                mutex_unlock(&sdata->local->iflist_mtx);
                return 0;
        }
@@ -1521,7 +1567,11 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
 
        switch (sdata->vif.type) {
        case NL80211_IFTYPE_ADHOC:
-               if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC)
+       case NL80211_IFTYPE_AP:
+       case NL80211_IFTYPE_AP_VLAN:
+       case NL80211_IFTYPE_P2P_GO:
+               if (!ieee80211_is_action(mgmt->frame_control) ||
+                   mgmt->u.action.category == WLAN_CATEGORY_PUBLIC)
                        break;
                rcu_read_lock();
                sta = sta_info_get(sdata, mgmt->da);
@@ -1530,6 +1580,7 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
                        return -ENOLINK;
                break;
        case NL80211_IFTYPE_STATION:
+       case NL80211_IFTYPE_P2P_CLIENT:
                break;
        default:
                return -EOPNOTSUPP;
index 6b7ff9fb4604fd98a907e840f5b65cb638ee142f..50c40ea3cb4de949eabc8b02b0c6cd77753e1d94 100644 (file)
@@ -196,7 +196,8 @@ static ssize_t sta_agg_status_write(struct file *file, const char __user *userbu
                else
                        ret = ieee80211_stop_tx_ba_session(&sta->sta, tid);
        } else {
-               __ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_RECIPIENT, 3);
+               __ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_RECIPIENT,
+                                              3, true);
                ret = 0;
        }
 
index 11f74f5f7b2f837a3e6159736296478fb3125b8e..4214bb6e12fc501cf55749dda1574e3fcd4696eb 100644 (file)
@@ -101,16 +101,16 @@ void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband,
                ht_cap->mcs.rx_mask[32/8] |= 1;
 }
 
-void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta)
+void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, bool tx)
 {
        int i;
 
        cancel_work_sync(&sta->ampdu_mlme.work);
 
        for (i = 0; i <  STA_TID_NUM; i++) {
-               __ieee80211_stop_tx_ba_session(sta, i, WLAN_BACK_INITIATOR);
+               __ieee80211_stop_tx_ba_session(sta, i, WLAN_BACK_INITIATOR, tx);
                __ieee80211_stop_rx_ba_session(sta, i, WLAN_BACK_RECIPIENT,
-                                              WLAN_REASON_QSTA_LEAVE_QBSS);
+                                              WLAN_REASON_QSTA_LEAVE_QBSS, tx);
        }
 }
 
@@ -135,7 +135,7 @@ void ieee80211_ba_session_work(struct work_struct *work)
                if (test_and_clear_bit(tid, sta->ampdu_mlme.tid_rx_timer_expired))
                        ___ieee80211_stop_rx_ba_session(
                                sta, tid, WLAN_BACK_RECIPIENT,
-                               WLAN_REASON_QSTA_TIMEOUT);
+                               WLAN_REASON_QSTA_TIMEOUT, true);
 
                tid_tx = sta->ampdu_mlme.tid_tx[tid];
                if (!tid_tx)
@@ -146,7 +146,8 @@ void ieee80211_ba_session_work(struct work_struct *work)
                else if (test_and_clear_bit(HT_AGG_STATE_WANT_STOP,
                                            &tid_tx->state))
                        ___ieee80211_stop_tx_ba_session(sta, tid,
-                                                       WLAN_BACK_INITIATOR);
+                                                       WLAN_BACK_INITIATOR,
+                                                       true);
        }
        mutex_unlock(&sta->ampdu_mlme.mtx);
 }
@@ -214,9 +215,11 @@ void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
 #endif /* CONFIG_MAC80211_HT_DEBUG */
 
        if (initiator == WLAN_BACK_INITIATOR)
-               __ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_INITIATOR, 0);
+               __ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_INITIATOR, 0,
+                                              true);
        else
-               __ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_RECIPIENT);
+               __ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_RECIPIENT,
+                                              true);
 }
 
 int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata,
index 1a3aae54f0cf88a44d9fa819fd94d1518978d8fd..ff60c022f51de8b4d2f7dd2e910aa6912a4e780c 100644 (file)
@@ -173,6 +173,19 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
                memcpy(skb_put(skb, ifibss->ie_len),
                       ifibss->ie, ifibss->ie_len);
 
+       if (local->hw.queues >= 4) {
+               pos = skb_put(skb, 9);
+               *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+               *pos++ = 7; /* len */
+               *pos++ = 0x00; /* Microsoft OUI 00:50:F2 */
+               *pos++ = 0x50;
+               *pos++ = 0xf2;
+               *pos++ = 2; /* WME */
+               *pos++ = 0; /* WME info */
+               *pos++ = 1; /* WME ver */
+               *pos++ = 0; /* U-APSD no in use */
+       }
+
        rcu_assign_pointer(ifibss->presp, skb);
 
        sdata->vif.bss_conf.beacon_int = beacon_int;
@@ -266,37 +279,45 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
        if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
                return;
 
-       if (sdata->vif.type == NL80211_IFTYPE_ADHOC && elems->supp_rates &&
+       if (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
            memcmp(mgmt->bssid, sdata->u.ibss.bssid, ETH_ALEN) == 0) {
-               supp_rates = ieee80211_sta_get_rates(local, elems, band);
 
                rcu_read_lock();
-
                sta = sta_info_get(sdata, mgmt->sa);
-               if (sta) {
-                       u32 prev_rates;
 
-                       prev_rates = sta->sta.supp_rates[band];
-                       /* make sure mandatory rates are always added */
-                       sta->sta.supp_rates[band] = supp_rates |
-                               ieee80211_mandatory_rates(local, band);
+               if (elems->supp_rates) {
+                       supp_rates = ieee80211_sta_get_rates(local, elems,
+                                                            band);
+                       if (sta) {
+                               u32 prev_rates;
 
-                       if (sta->sta.supp_rates[band] != prev_rates) {
+                               prev_rates = sta->sta.supp_rates[band];
+                               /* make sure mandatory rates are always added */
+                               sta->sta.supp_rates[band] = supp_rates |
+                                       ieee80211_mandatory_rates(local, band);
+
+                               if (sta->sta.supp_rates[band] != prev_rates) {
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
-                               printk(KERN_DEBUG "%s: updated supp_rates set "
-                                   "for %pM based on beacon/probe_response "
-                                   "(0x%x -> 0x%x)\n",
-                                   sdata->name, sta->sta.addr,
-                                   prev_rates, sta->sta.supp_rates[band]);
+                                       printk(KERN_DEBUG
+                                               "%s: updated supp_rates set "
+                                               "for %pM based on beacon"
+                                               "/probe_resp (0x%x -> 0x%x)\n",
+                                               sdata->name, sta->sta.addr,
+                                               prev_rates,
+                                               sta->sta.supp_rates[band]);
 #endif
-                               rate_control_rate_init(sta);
-                       }
-                       rcu_read_unlock();
-               } else {
-                       rcu_read_unlock();
-                       ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa,
-                                              supp_rates, GFP_KERNEL);
+                                       rate_control_rate_init(sta);
+                               }
+                       } else
+                               sta = ieee80211_ibss_add_sta(sdata, mgmt->bssid,
+                                               mgmt->sa, supp_rates,
+                                               GFP_ATOMIC);
                }
+
+               if (sta && elems->wmm_info)
+                       set_sta_flags(sta, WLAN_STA_WME);
+
+               rcu_read_unlock();
        }
 
        bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems,
index 945fbf29719dd3f47eb658daebec405f159d16ba..f0610fa4fbe078efce627592e4dad49015362ce6 100644 (file)
@@ -369,6 +369,7 @@ struct ieee80211_if_managed {
 
        unsigned int flags;
 
+       bool beacon_crc_valid;
        u32 beacon_crc;
 
        enum {
@@ -548,8 +549,6 @@ struct ieee80211_sub_if_data {
        struct ieee80211_fragment_entry fragments[IEEE80211_FRAGMENT_MAX];
        unsigned int fragment_next;
 
-#define NUM_DEFAULT_KEYS 4
-#define NUM_DEFAULT_MGMT_KEYS 2
        struct ieee80211_key *keys[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS];
        struct ieee80211_key *default_key;
        struct ieee80211_key *default_mgmt_key;
@@ -1132,6 +1131,8 @@ void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata);
 void ieee80211_remove_interfaces(struct ieee80211_local *local);
 u32 __ieee80211_recalc_idle(struct ieee80211_local *local);
 void ieee80211_recalc_idle(struct ieee80211_local *local);
+void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata,
+                                   const int offset);
 
 static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata)
 {
@@ -1172,10 +1173,10 @@ int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata,
 void ieee80211_request_smps_work(struct work_struct *work);
 
 void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
-                                    u16 initiator, u16 reason);
+                                    u16 initiator, u16 reason, bool stop);
 void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
-                                   u16 initiator, u16 reason);
-void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta);
+                                   u16 initiator, u16 reason, bool stop);
+void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, bool tx);
 void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
                             struct sta_info *sta,
                             struct ieee80211_mgmt *mgmt, size_t len);
@@ -1189,9 +1190,11 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
                                     size_t len);
 
 int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
-                                  enum ieee80211_back_parties initiator);
+                                  enum ieee80211_back_parties initiator,
+                                  bool tx);
 int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
-                                   enum ieee80211_back_parties initiator);
+                                   enum ieee80211_back_parties initiator,
+                                   bool tx);
 void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid);
 void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid);
 void ieee80211_ba_session_work(struct work_struct *work);
@@ -1294,8 +1297,7 @@ u32 ieee80211_sta_get_rates(struct ieee80211_local *local,
                            enum ieee80211_band band);
 int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata,
                             enum ieee80211_smps_mode smps_mode);
-void ieee80211_recalc_smps(struct ieee80211_local *local,
-                          struct ieee80211_sub_if_data *forsdata);
+void ieee80211_recalc_smps(struct ieee80211_local *local);
 
 size_t ieee80211_ie_split(const u8 *ies, size_t ielen,
                          const u8 *ids, int n_ids, size_t offset);
index 66785739dad378fe5bdd10904d8c59586951d131..e99d1b60557cb0f932ec570acb08b11f26738ed9 100644 (file)
@@ -24,6 +24,7 @@
 #include "led.h"
 #include "driver-ops.h"
 #include "wme.h"
+#include "rate.h"
 
 /**
  * DOC: Interface list locking
@@ -148,6 +149,26 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata,
        return 0;
 }
 
+void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata,
+                                   const int offset)
+{
+       struct ieee80211_local *local = sdata->local;
+       u32 flags = sdata->u.mntr_flags;
+
+#define ADJUST(_f, _s) do {                                    \
+       if (flags & MONITOR_FLAG_##_f)                          \
+               local->fif_##_s += offset;                      \
+       } while (0)
+
+       ADJUST(FCSFAIL, fcsfail);
+       ADJUST(PLCPFAIL, plcpfail);
+       ADJUST(CONTROL, control);
+       ADJUST(CONTROL, pspoll);
+       ADJUST(OTHER_BSS, other_bss);
+
+#undef ADJUST
+}
+
 /*
  * NOTE: Be very careful when changing this function, it must NOT return
  * an error on interface type changes that have been pre-checked, so most
@@ -240,17 +261,7 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
                        hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR;
                }
 
-               if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL)
-                       local->fif_fcsfail++;
-               if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL)
-                       local->fif_plcpfail++;
-               if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL) {
-                       local->fif_control++;
-                       local->fif_pspoll++;
-               }
-               if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
-                       local->fif_other_bss++;
-
+               ieee80211_adjust_monitor_flags(sdata, 1);
                ieee80211_configure_filter(local);
 
                netif_carrier_on(dev);
@@ -301,6 +312,8 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
                        /* STA has been freed */
                        goto err_del_interface;
                }
+
+               rate_control_rate_init(sta);
        }
 
        /*
@@ -477,17 +490,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
                        hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR;
                }
 
-               if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL)
-                       local->fif_fcsfail--;
-               if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL)
-                       local->fif_plcpfail--;
-               if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL) {
-                       local->fif_pspoll--;
-                       local->fif_control--;
-               }
-               if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
-                       local->fif_other_bss--;
-
+               ieee80211_adjust_monitor_flags(sdata, -1);
                ieee80211_configure_filter(local);
                break;
        case NL80211_IFTYPE_MESH_POINT:
@@ -793,7 +796,8 @@ static void ieee80211_iface_work(struct work_struct *work)
 
                                __ieee80211_stop_rx_ba_session(
                                        sta, tid, WLAN_BACK_RECIPIENT,
-                                       WLAN_REASON_QSTA_REQUIRE_SETUP);
+                                       WLAN_REASON_QSTA_REQUIRE_SETUP,
+                                       true);
                        }
                        mutex_unlock(&local->sta_mtx);
                } else switch (sdata->vif.type) {
index 6a63d1abd14dab5117778bf524c630d19cfaf01e..ccd676b2f5999b6779e02903b853e838c8836612 100644 (file)
@@ -68,15 +68,21 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
 
        might_sleep();
 
-       if (!key->local->ops->set_key) {
-               ret = -EOPNOTSUPP;
+       if (!key->local->ops->set_key)
                goto out_unsupported;
-       }
 
        assert_key_lock(key->local);
 
        sta = get_sta_for_key(key);
 
+       /*
+        * If this is a per-STA GTK, check if it
+        * is supported; if not, return.
+        */
+       if (sta && !(key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE) &&
+           !(key->local->hw.flags & IEEE80211_HW_SUPPORTS_PER_STA_GTK))
+               goto out_unsupported;
+
        sdata = key->sdata;
        if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
                sdata = container_of(sdata->bss,
@@ -85,31 +91,28 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
 
        ret = drv_set_key(key->local, SET_KEY, sdata, sta, &key->conf);
 
-       if (!ret)
+       if (!ret) {
                key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE;
+               return 0;
+       }
 
-       if (ret && ret != -ENOSPC && ret != -EOPNOTSUPP)
+       if (ret != -ENOSPC && ret != -EOPNOTSUPP)
                wiphy_err(key->local->hw.wiphy,
                          "failed to set key (%d, %pM) to hardware (%d)\n",
                          key->conf.keyidx, sta ? sta->addr : bcast_addr, ret);
 
-out_unsupported:
-       if (ret) {
-               switch (key->conf.cipher) {
-               case WLAN_CIPHER_SUITE_WEP40:
-               case WLAN_CIPHER_SUITE_WEP104:
-               case WLAN_CIPHER_SUITE_TKIP:
-               case WLAN_CIPHER_SUITE_CCMP:
-               case WLAN_CIPHER_SUITE_AES_CMAC:
-                       /* all of these we can do in software */
-                       ret = 0;
-                       break;
-               default:
-                       ret = -EINVAL;
-               }
+ out_unsupported:
+       switch (key->conf.cipher) {
+       case WLAN_CIPHER_SUITE_WEP40:
+       case WLAN_CIPHER_SUITE_WEP104:
+       case WLAN_CIPHER_SUITE_TKIP:
+       case WLAN_CIPHER_SUITE_CCMP:
+       case WLAN_CIPHER_SUITE_AES_CMAC:
+               /* all of these we can do in software */
+               return 0;
+       default:
+               return -EINVAL;
        }
-
-       return ret;
 }
 
 static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
@@ -147,6 +150,26 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
        key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
 }
 
+void ieee80211_key_removed(struct ieee80211_key_conf *key_conf)
+{
+       struct ieee80211_key *key;
+
+       key = container_of(key_conf, struct ieee80211_key, conf);
+
+       might_sleep();
+       assert_key_lock(key->local);
+
+       key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
+
+       /*
+        * Flush TX path to avoid attempts to use this key
+        * after this function returns. Until then, drivers
+        * must be prepared to handle the key.
+        */
+       synchronize_rcu();
+}
+EXPORT_SYMBOL_GPL(ieee80211_key_removed);
+
 static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata,
                                        int idx)
 {
@@ -202,6 +225,7 @@ void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata,
 
 static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
                                    struct sta_info *sta,
+                                   bool pairwise,
                                    struct ieee80211_key *old,
                                    struct ieee80211_key *new)
 {
@@ -210,8 +234,14 @@ static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
        if (new)
                list_add(&new->list, &sdata->key_list);
 
-       if (sta) {
-               rcu_assign_pointer(sta->key, new);
+       if (sta && pairwise) {
+               rcu_assign_pointer(sta->ptk, new);
+       } else if (sta) {
+               if (old)
+                       idx = old->conf.keyidx;
+               else
+                       idx = new->conf.keyidx;
+               rcu_assign_pointer(sta->gtk[idx], new);
        } else {
                WARN_ON(new && old && new->conf.keyidx != old->conf.keyidx);
 
@@ -355,6 +385,7 @@ int ieee80211_key_link(struct ieee80211_key *key,
 {
        struct ieee80211_key *old_key;
        int idx, ret;
+       bool pairwise = key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE;
 
        BUG_ON(!sdata);
        BUG_ON(!key);
@@ -371,13 +402,6 @@ int ieee80211_key_link(struct ieee80211_key *key,
                 */
                if (test_sta_flags(sta, WLAN_STA_WME))
                        key->conf.flags |= IEEE80211_KEY_FLAG_WMM_STA;
-
-               /*
-                * This key is for a specific sta interface,
-                * inform the driver that it should try to store
-                * this key as pairwise key.
-                */
-               key->conf.flags |= IEEE80211_KEY_FLAG_PAIRWISE;
        } else {
                if (sdata->vif.type == NL80211_IFTYPE_STATION) {
                        struct sta_info *ap;
@@ -399,12 +423,14 @@ int ieee80211_key_link(struct ieee80211_key *key,
 
        mutex_lock(&sdata->local->key_mtx);
 
-       if (sta)
-               old_key = sta->key;
+       if (sta && pairwise)
+               old_key = sta->ptk;
+       else if (sta)
+               old_key = sta->gtk[idx];
        else
                old_key = sdata->keys[idx];
 
-       __ieee80211_key_replace(sdata, sta, old_key, key);
+       __ieee80211_key_replace(sdata, sta, pairwise, old_key, key);
        __ieee80211_key_destroy(old_key);
 
        ieee80211_debugfs_key_add(key);
@@ -423,7 +449,8 @@ static void __ieee80211_key_free(struct ieee80211_key *key)
         */
        if (key->sdata)
                __ieee80211_key_replace(key->sdata, key->sta,
-                                       key, NULL);
+                               key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
+                               key, NULL);
        __ieee80211_key_destroy(key);
 }
 
index cb9a4a65cc68fae008b1ea79a0c0ff84d9651cb8..0db1c0f5f697fefd06b58766ec01d287a6cec95f 100644 (file)
@@ -16,6 +16,9 @@
 #include <linux/rcupdate.h>
 #include <net/mac80211.h>
 
+#define NUM_DEFAULT_KEYS 4
+#define NUM_DEFAULT_MGMT_KEYS 2
+
 #define WEP_IV_LEN             4
 #define WEP_ICV_LEN            4
 #define ALG_TKIP_KEY_LEN       32
index db341a99c7c7d995ac66964e721df5b984973c1f..eb0f5997767610f6466032adfb7a529b5ad80aa3 100644 (file)
@@ -201,6 +201,8 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
                sdata->vif.bss_conf.bssid = sdata->u.ibss.bssid;
        else if (sdata->vif.type == NL80211_IFTYPE_AP)
                sdata->vif.bss_conf.bssid = sdata->vif.addr;
+       else if (sdata->vif.type == NL80211_IFTYPE_WDS)
+               sdata->vif.bss_conf.bssid = NULL;
        else if (ieee80211_vif_is_mesh(&sdata->vif)) {
                sdata->vif.bss_conf.bssid = zero;
        } else {
@@ -211,6 +213,7 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
        switch (sdata->vif.type) {
        case NL80211_IFTYPE_AP:
        case NL80211_IFTYPE_ADHOC:
+       case NL80211_IFTYPE_WDS:
        case NL80211_IFTYPE_MESH_POINT:
                break;
        default:
@@ -295,7 +298,16 @@ static void ieee80211_restart_work(struct work_struct *work)
        struct ieee80211_local *local =
                container_of(work, struct ieee80211_local, restart_work);
 
+       /* wait for scan work complete */
+       flush_workqueue(local->workqueue);
+
+       mutex_lock(&local->mtx);
+       WARN(test_bit(SCAN_HW_SCANNING, &local->scanning),
+               "%s called with hardware scan in progress\n", __func__);
+       mutex_unlock(&local->mtx);
+
        rtnl_lock();
+       ieee80211_scan_cancel(local);
        ieee80211_reconfig(local);
        rtnl_unlock();
 }
@@ -306,15 +318,6 @@ void ieee80211_restart_hw(struct ieee80211_hw *hw)
 
        trace_api_restart_hw(local);
 
-       /* wait for scan work complete */
-       flush_workqueue(local->workqueue);
-
-       WARN(test_bit(SCAN_HW_SCANNING, &local->scanning),
-               "%s called with hardware scan in progress\n", __func__);
-
-       if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning)))
-               ieee80211_scan_cancel(local);
-
        /* use this reason, ieee80211_reconfig will unblock it */
        ieee80211_stop_queues_by_reason(hw,
                IEEE80211_QUEUE_STOP_REASON_SUSPEND);
@@ -329,7 +332,7 @@ static void ieee80211_recalc_smps_work(struct work_struct *work)
                container_of(work, struct ieee80211_local, recalc_smps);
 
        mutex_lock(&local->iflist_mtx);
-       ieee80211_recalc_smps(local, NULL);
+       ieee80211_recalc_smps(local);
        mutex_unlock(&local->iflist_mtx);
 }
 
@@ -533,6 +536,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
        /* set up some defaults */
        local->hw.queues = 1;
        local->hw.max_rates = 1;
+       local->hw.max_report_rates = 0;
        local->hw.conf.long_frame_max_tx_count = wiphy->retry_long;
        local->hw.conf.short_frame_max_tx_count = wiphy->retry_short;
        local->user_power_level = -1;
@@ -608,6 +612,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
                WLAN_CIPHER_SUITE_AES_CMAC
        };
 
+       if (hw->max_report_rates == 0)
+               hw->max_report_rates = hw->max_rates;
+
        /*
         * generic code guarantees at least one band,
         * set this very early because much code assumes
index 77913a15f5374e68494c2087a206479f0feb63be..5695c94c49aac10f074da18868263d5d1b9a58d3 100644 (file)
@@ -913,7 +913,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
 
        mutex_lock(&local->iflist_mtx);
        ieee80211_recalc_ps(local, -1);
-       ieee80211_recalc_smps(local, sdata);
+       ieee80211_recalc_smps(local);
        mutex_unlock(&local->iflist_mtx);
 
        netif_tx_start_all_queues(sdata->dev);
@@ -921,7 +921,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
 }
 
 static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
-                                  bool remove_sta)
+                                  bool remove_sta, bool tx)
 {
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct ieee80211_local *local = sdata->local;
@@ -960,7 +960,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
        sta = sta_info_get(sdata, bssid);
        if (sta) {
                set_sta_flags(sta, WLAN_STA_BLOCK_BA);
-               ieee80211_sta_tear_down_BA_sessions(sta);
+               ieee80211_sta_tear_down_BA_sessions(sta, tx);
        }
        mutex_unlock(&local->sta_mtx);
 
@@ -1124,7 +1124,7 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata)
 
        printk(KERN_DEBUG "Connection to AP %pM lost.\n", bssid);
 
-       ieee80211_set_disassoc(sdata, true);
+       ieee80211_set_disassoc(sdata, true, true);
        mutex_unlock(&ifmgd->mtx);
 
        mutex_lock(&local->mtx);
@@ -1197,7 +1197,7 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
        printk(KERN_DEBUG "%s: deauthenticated from %pM (Reason: %u)\n",
                        sdata->name, bssid, reason_code);
 
-       ieee80211_set_disassoc(sdata, true);
+       ieee80211_set_disassoc(sdata, true, false);
        mutex_lock(&sdata->local->mtx);
        ieee80211_recalc_idle(sdata->local);
        mutex_unlock(&sdata->local->mtx);
@@ -1229,7 +1229,7 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
        printk(KERN_DEBUG "%s: disassociated from %pM (Reason: %u)\n",
                        sdata->name, mgmt->sa, reason_code);
 
-       ieee80211_set_disassoc(sdata, true);
+       ieee80211_set_disassoc(sdata, true, false);
        mutex_lock(&sdata->local->mtx);
        ieee80211_recalc_idle(sdata->local);
        mutex_unlock(&sdata->local->mtx);
@@ -1291,7 +1291,7 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk,
 
        rates = 0;
        basic_rates = 0;
-       sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+       sband = local->hw.wiphy->bands[wk->chan->band];
 
        for (i = 0; i < elems.supp_rates_len; i++) {
                int rate = (elems.supp_rates[i] & 0x7f) * 5;
@@ -1327,11 +1327,11 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk,
                }
        }
 
-       sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
+       sta->sta.supp_rates[wk->chan->band] = rates;
        sdata->vif.bss_conf.basic_rates = basic_rates;
 
        /* cf. IEEE 802.11 9.2.12 */
-       if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ &&
+       if (wk->chan->band == IEEE80211_BAND_2GHZ &&
            have_higher_than_11mbit)
                sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE;
        else
@@ -1639,7 +1639,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
                directed_tim = ieee80211_check_tim(elems.tim, elems.tim_len,
                                                   ifmgd->aid);
 
-       if (ncrc != ifmgd->beacon_crc) {
+       if (ncrc != ifmgd->beacon_crc || !ifmgd->beacon_crc_valid) {
                ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems,
                                      true);
 
@@ -1670,9 +1670,10 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
                }
        }
 
-       if (ncrc == ifmgd->beacon_crc)
+       if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid)
                return;
        ifmgd->beacon_crc = ncrc;
+       ifmgd->beacon_crc_valid = true;
 
        if (elems.erp_info && elems.erp_info_len >= 1) {
                erp_valid = true;
@@ -1879,7 +1880,7 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
                        printk(KERN_DEBUG "No probe response from AP %pM"
                                " after %dms, disconnecting.\n",
                                bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ);
-                       ieee80211_set_disassoc(sdata, true);
+                       ieee80211_set_disassoc(sdata, true, true);
                        mutex_unlock(&ifmgd->mtx);
                        mutex_lock(&local->mtx);
                        ieee80211_recalc_idle(local);
@@ -2203,7 +2204,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
                }
 
                /* Trying to reassociate - clear previous association state */
-               ieee80211_set_disassoc(sdata, true);
+               ieee80211_set_disassoc(sdata, true, false);
        }
        mutex_unlock(&ifmgd->mtx);
 
@@ -2214,6 +2215,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
        ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N;
        ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED;
 
+       ifmgd->beacon_crc_valid = false;
+
        for (i = 0; i < req->crypto.n_ciphers_pairwise; i++)
                if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 ||
                    req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP ||
@@ -2315,7 +2318,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
 
        memcpy(bssid, req->bss->bssid, ETH_ALEN);
        if (ifmgd->associated == req->bss) {
-               ieee80211_set_disassoc(sdata, false);
+               ieee80211_set_disassoc(sdata, false, true);
                mutex_unlock(&ifmgd->mtx);
                assoc_bss = true;
        } else {
@@ -2398,7 +2401,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
               sdata->name, req->bss->bssid, req->reason_code);
 
        memcpy(bssid, req->bss->bssid, ETH_ALEN);
-       ieee80211_set_disassoc(sdata, false);
+       ieee80211_set_disassoc(sdata, false, true);
 
        mutex_unlock(&ifmgd->mtx);
 
index ce671dfd238c115281608e9fdb96b3ac3ce433fd..e37355193ed185679aa88b23a1a88789bec09678 100644 (file)
@@ -12,8 +12,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw)
        struct ieee80211_sub_if_data *sdata;
        struct sta_info *sta;
 
-       if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning)))
-               ieee80211_scan_cancel(local);
+       ieee80211_scan_cancel(local);
 
        ieee80211_stop_queues_by_reason(hw,
                        IEEE80211_QUEUE_STOP_REASON_SUSPEND);
@@ -46,7 +45,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw)
        list_for_each_entry(sta, &local->sta_list, list) {
                if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) {
                        set_sta_flags(sta, WLAN_STA_BLOCK_BA);
-                       ieee80211_sta_tear_down_BA_sessions(sta);
+                       ieee80211_sta_tear_down_BA_sessions(sta, true);
                }
 
                if (sta->uploaded) {
index 0b0e83ebe3d5b9dd589500b1e5e84693f12e4cdb..b67221def5844fa50edd3b246227c80bb95b463e 100644 (file)
@@ -819,6 +819,7 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
        if (unlikely((ieee80211_is_data(hdr->frame_control) ||
                      ieee80211_is_pspoll(hdr->frame_control)) &&
                     rx->sdata->vif.type != NL80211_IFTYPE_ADHOC &&
+                    rx->sdata->vif.type != NL80211_IFTYPE_WDS &&
                     (!rx->sta || !test_sta_flags(rx->sta, WLAN_STA_ASSOC)))) {
                if ((!ieee80211_has_fromds(hdr->frame_control) &&
                     !ieee80211_has_tods(hdr->frame_control) &&
@@ -845,7 +846,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
        int keyidx;
        int hdrlen;
        ieee80211_rx_result result = RX_DROP_UNUSABLE;
-       struct ieee80211_key *stakey = NULL;
+       struct ieee80211_key *sta_ptk = NULL;
        int mmie_keyidx = -1;
        __le16 fc;
 
@@ -887,15 +888,15 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
        rx->key = NULL;
 
        if (rx->sta)
-               stakey = rcu_dereference(rx->sta->key);
+               sta_ptk = rcu_dereference(rx->sta->ptk);
 
        fc = hdr->frame_control;
 
        if (!ieee80211_has_protected(fc))
                mmie_keyidx = ieee80211_get_mmie_keyidx(rx->skb);
 
-       if (!is_multicast_ether_addr(hdr->addr1) && stakey) {
-               rx->key = stakey;
+       if (!is_multicast_ether_addr(hdr->addr1) && sta_ptk) {
+               rx->key = sta_ptk;
                if ((status->flag & RX_FLAG_DECRYPTED) &&
                    (status->flag & RX_FLAG_IV_STRIPPED))
                        return RX_CONTINUE;
@@ -911,7 +912,10 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
                if (mmie_keyidx < NUM_DEFAULT_KEYS ||
                    mmie_keyidx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS)
                        return RX_DROP_MONITOR; /* unexpected BIP keyidx */
-               rx->key = rcu_dereference(rx->sdata->keys[mmie_keyidx]);
+               if (rx->sta)
+                       rx->key = rcu_dereference(rx->sta->gtk[mmie_keyidx]);
+               if (!rx->key)
+                       rx->key = rcu_dereference(rx->sdata->keys[mmie_keyidx]);
        } else if (!ieee80211_has_protected(fc)) {
                /*
                 * The frame was not protected, so skip decryption. However, we
@@ -954,17 +958,25 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
                skb_copy_bits(rx->skb, hdrlen + 3, &keyid, 1);
                keyidx = keyid >> 6;
 
-               rx->key = rcu_dereference(rx->sdata->keys[keyidx]);
+               /* check per-station GTK first, if multicast packet */
+               if (is_multicast_ether_addr(hdr->addr1) && rx->sta)
+                       rx->key = rcu_dereference(rx->sta->gtk[keyidx]);
 
-               /*
-                * RSNA-protected unicast frames should always be sent with
-                * pairwise or station-to-station keys, but for WEP we allow
-                * using a key index as well.
-                */
-               if (rx->key && rx->key->conf.cipher != WLAN_CIPHER_SUITE_WEP40 &&
-                   rx->key->conf.cipher != WLAN_CIPHER_SUITE_WEP104 &&
-                   !is_multicast_ether_addr(hdr->addr1))
-                       rx->key = NULL;
+               /* if not found, try default key */
+               if (!rx->key) {
+                       rx->key = rcu_dereference(rx->sdata->keys[keyidx]);
+
+                       /*
+                        * RSNA-protected unicast frames should always be
+                        * sent with pairwise or station-to-station keys,
+                        * but for WEP we allow using a key index as well.
+                        */
+                       if (rx->key &&
+                           rx->key->conf.cipher != WLAN_CIPHER_SUITE_WEP40 &&
+                           rx->key->conf.cipher != WLAN_CIPHER_SUITE_WEP104 &&
+                           !is_multicast_ether_addr(hdr->addr1))
+                               rx->key = NULL;
+               }
        }
 
        if (rx->key) {
index 5171a95816312466afc085fe26ebcd871fa4c9ce..fb274db77e3cc73a1b1d9f537966ffc0a8a0cd14 100644 (file)
@@ -249,12 +249,12 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local)
        return true;
 }
 
-static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
+static bool __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted,
+                                      bool was_hw_scan)
 {
        struct ieee80211_local *local = hw_to_local(hw);
-       bool was_hw_scan;
 
-       mutex_lock(&local->mtx);
+       lockdep_assert_held(&local->mtx);
 
        /*
         * It's ok to abort a not-yet-running scan (that
@@ -265,17 +265,13 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
        if (WARN_ON(!local->scanning && !aborted))
                aborted = true;
 
-       if (WARN_ON(!local->scan_req)) {
-               mutex_unlock(&local->mtx);
-               return;
-       }
+       if (WARN_ON(!local->scan_req))
+               return false;
 
-       was_hw_scan = test_bit(SCAN_HW_SCANNING, &local->scanning);
        if (was_hw_scan && !aborted && ieee80211_prep_hw_scan(local)) {
-               ieee80211_queue_delayed_work(&local->hw,
-                                            &local->scan_work, 0);
-               mutex_unlock(&local->mtx);
-               return;
+               int rc = drv_hw_scan(local, local->scan_sdata, local->hw_scan_req);
+               if (rc == 0)
+                       return false;
        }
 
        kfree(local->hw_scan_req);
@@ -289,23 +285,25 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
        local->scanning = 0;
        local->scan_channel = NULL;
 
-       /* we only have to protect scan_req and hw/sw scan */
-       mutex_unlock(&local->mtx);
-
-       ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
-       if (was_hw_scan)
-               goto done;
-
-       ieee80211_configure_filter(local);
+       return true;
+}
 
-       drv_sw_scan_complete(local);
+static void __ieee80211_scan_completed_finish(struct ieee80211_hw *hw,
+                                             bool was_hw_scan)
+{
+       struct ieee80211_local *local = hw_to_local(hw);
 
-       ieee80211_offchannel_return(local, true);
+       ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
+       if (!was_hw_scan) {
+               ieee80211_configure_filter(local);
+               drv_sw_scan_complete(local);
+               ieee80211_offchannel_return(local, true);
+       }
 
- done:
        mutex_lock(&local->mtx);
        ieee80211_recalc_idle(local);
        mutex_unlock(&local->mtx);
+
        ieee80211_mlme_notify_scan_completed(local);
        ieee80211_ibss_notify_scan_completed(local);
        ieee80211_mesh_notify_scan_completed(local);
@@ -366,6 +364,8 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_local *local = sdata->local;
        int rc;
 
+       lockdep_assert_held(&local->mtx);
+
        if (local->scan_req)
                return -EBUSY;
 
@@ -447,8 +447,8 @@ ieee80211_scan_get_channel_time(struct ieee80211_channel *chan)
        return IEEE80211_PROBE_DELAY + IEEE80211_CHANNEL_TIME;
 }
 
-static int ieee80211_scan_state_decision(struct ieee80211_local *local,
-                                        unsigned long *next_delay)
+static void ieee80211_scan_state_decision(struct ieee80211_local *local,
+                                         unsigned long *next_delay)
 {
        bool associated = false;
        bool tx_empty = true;
@@ -458,12 +458,6 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local,
        struct ieee80211_sub_if_data *sdata;
        struct ieee80211_channel *next_chan;
 
-       /* if no more bands/channels left, complete scan and advance to the idle state */
-       if (local->scan_channel_idx >= local->scan_req->n_channels) {
-               __ieee80211_scan_completed(&local->hw, false);
-               return 1;
-       }
-
        /*
         * check if at least one STA interface is associated,
         * check if at least one STA interface has pending tx frames
@@ -535,7 +529,6 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local,
        }
 
        *next_delay = 0;
-       return 0;
 }
 
 static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *local,
@@ -651,28 +644,17 @@ void ieee80211_scan_work(struct work_struct *work)
                container_of(work, struct ieee80211_local, scan_work.work);
        struct ieee80211_sub_if_data *sdata = local->scan_sdata;
        unsigned long next_delay = 0;
+       bool aborted, hw_scan, finish;
 
-       if (test_and_clear_bit(SCAN_COMPLETED, &local->scanning)) {
-               bool aborted;
+       mutex_lock(&local->mtx);
 
+       if (test_and_clear_bit(SCAN_COMPLETED, &local->scanning)) {
                aborted = test_and_clear_bit(SCAN_ABORTED, &local->scanning);
-               __ieee80211_scan_completed(&local->hw, aborted);
-               return;
-       }
-
-       mutex_lock(&local->mtx);
-       if (!sdata || !local->scan_req) {
-               mutex_unlock(&local->mtx);
-               return;
+               goto out_complete;
        }
 
-       if (local->hw_scan_req) {
-               int rc = drv_hw_scan(local, sdata, local->hw_scan_req);
-               mutex_unlock(&local->mtx);
-               if (rc)
-                       __ieee80211_scan_completed(&local->hw, true);
-               return;
-       }
+       if (!sdata || !local->scan_req)
+               goto out;
 
        if (local->scan_req && !local->scanning) {
                struct cfg80211_scan_request *req = local->scan_req;
@@ -682,21 +664,21 @@ void ieee80211_scan_work(struct work_struct *work)
                local->scan_sdata = NULL;
 
                rc = __ieee80211_start_scan(sdata, req);
-               mutex_unlock(&local->mtx);
-
-               if (rc)
-                       __ieee80211_scan_completed(&local->hw, true);
-               return;
+               if (rc) {
+                       /* need to complete scan in cfg80211 */
+                       local->scan_req = req;
+                       aborted = true;
+                       goto out_complete;
+               } else
+                       goto out;
        }
 
-       mutex_unlock(&local->mtx);
-
        /*
         * Avoid re-scheduling when the sdata is going away.
         */
        if (!ieee80211_sdata_running(sdata)) {
-               __ieee80211_scan_completed(&local->hw, true);
-               return;
+               aborted = true;
+               goto out_complete;
        }
 
        /*
@@ -706,8 +688,12 @@ void ieee80211_scan_work(struct work_struct *work)
        do {
                switch (local->next_scan_state) {
                case SCAN_DECISION:
-                       if (ieee80211_scan_state_decision(local, &next_delay))
-                               return;
+                       /* if no more bands/channels left, complete scan */
+                       if (local->scan_channel_idx >= local->scan_req->n_channels) {
+                               aborted = false;
+                               goto out_complete;
+                       }
+                       ieee80211_scan_state_decision(local, &next_delay);
                        break;
                case SCAN_SET_CHANNEL:
                        ieee80211_scan_state_set_channel(local, &next_delay);
@@ -725,6 +711,19 @@ void ieee80211_scan_work(struct work_struct *work)
        } while (next_delay == 0);
 
        ieee80211_queue_delayed_work(&local->hw, &local->scan_work, next_delay);
+       mutex_unlock(&local->mtx);
+       return;
+
+out_complete:
+       hw_scan = test_bit(SCAN_HW_SCANNING, &local->scanning);
+       finish = __ieee80211_scan_completed(&local->hw, aborted, hw_scan);
+       mutex_unlock(&local->mtx);
+       if (finish)
+               __ieee80211_scan_completed_finish(&local->hw, hw_scan);
+       return;
+
+out:
+       mutex_unlock(&local->mtx);
 }
 
 int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
@@ -786,21 +785,40 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata,
        return ret;
 }
 
+/*
+ * Only call this function when a scan can't be queued -- under RTNL.
+ */
 void ieee80211_scan_cancel(struct ieee80211_local *local)
 {
        bool abortscan;
-
-       cancel_delayed_work_sync(&local->scan_work);
+       bool finish = false;
 
        /*
-        * Only call this function when a scan can't be
-        * queued -- mostly at suspend under RTNL.
+        * We are only canceling software scan, or deferred scan that was not
+        * yet really started (see __ieee80211_start_scan ).
+        *
+        * Regarding hardware scan:
+        * - we can not call  __ieee80211_scan_completed() as when
+        *   SCAN_HW_SCANNING bit is set this function change
+        *   local->hw_scan_req to operate on 5G band, what race with
+        *   driver which can use local->hw_scan_req
+        *
+        * - we can not cancel scan_work since driver can schedule it
+        *   by ieee80211_scan_completed(..., true) to finish scan
+        *
+        * Hence low lever driver is responsible for canceling HW scan.
         */
+
        mutex_lock(&local->mtx);
-       abortscan = test_bit(SCAN_SW_SCANNING, &local->scanning) ||
-                   (!local->scanning && local->scan_req);
+       abortscan = local->scan_req && !test_bit(SCAN_HW_SCANNING, &local->scanning);
+       if (abortscan)
+               finish = __ieee80211_scan_completed(&local->hw, true, false);
        mutex_unlock(&local->mtx);
 
-       if (abortscan)
-               __ieee80211_scan_completed(&local->hw, true);
+       if (abortscan) {
+               /* The scan is canceled, but stop work from being pending */
+               cancel_delayed_work_sync(&local->scan_work);
+       }
+       if (finish)
+               __ieee80211_scan_completed_finish(&local->hw, false);
 }
index ca2cba9cea8792594c5789f1eb3b3fb3e8e4f2e3..6d8f897d87636c8422b23ec9447c27dbb0937096 100644 (file)
@@ -616,7 +616,7 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
        struct ieee80211_sub_if_data *sdata;
        struct sk_buff *skb;
        unsigned long flags;
-       int ret;
+       int ret, i;
 
        might_sleep();
 
@@ -633,7 +633,7 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
         * will be sufficient.
         */
        set_sta_flags(sta, WLAN_STA_BLOCK_BA);
-       ieee80211_sta_tear_down_BA_sessions(sta);
+       ieee80211_sta_tear_down_BA_sessions(sta, true);
 
        spin_lock_irqsave(&local->sta_lock, flags);
        ret = sta_info_hash_del(local, sta);
@@ -644,10 +644,10 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
        if (ret)
                return ret;
 
-       if (sta->key) {
-               ieee80211_key_free(local, sta->key);
-               WARN_ON(sta->key);
-       }
+       for (i = 0; i < NUM_DEFAULT_KEYS; i++)
+               ieee80211_key_free(local, sta->gtk[i]);
+       if (sta->ptk)
+               ieee80211_key_free(local, sta->ptk);
 
        sta->dead = true;
 
index 810c5ce98316549a581d537aebb492a2f5e0065d..9265acadef32d862c11889c2d96575147fcec972 100644 (file)
@@ -79,6 +79,7 @@ enum ieee80211_sta_info_flags {
  * @dialog_token: dialog token for aggregation session
  * @state: session state (see above)
  * @stop_initiator: initiator of a session stop
+ * @tx_stop: TX DelBA frame when stopping
  *
  * This structure is protected by RCU and the per-station
  * spinlock. Assignments to the array holding it must hold
@@ -95,6 +96,7 @@ struct tid_ampdu_tx {
        unsigned long state;
        u8 dialog_token;
        u8 stop_initiator;
+       bool tx_stop;
 };
 
 /**
@@ -197,7 +199,8 @@ enum plink_state {
  * @hnext: hash table linked list pointer
  * @local: pointer to the global information
  * @sdata: virtual interface this station belongs to
- * @key: peer key negotiated with this station, if any
+ * @ptk: peer key negotiated with this station, if any
+ * @gtk: group keys negotiated with this station, if any
  * @rate_ctrl: rate control algorithm reference
  * @rate_ctrl_priv: rate control private per-STA pointer
  * @last_tx_rate: rate used for last transmit, to report to userspace as
@@ -252,7 +255,8 @@ struct sta_info {
        struct sta_info *hnext;
        struct ieee80211_local *local;
        struct ieee80211_sub_if_data *sdata;
-       struct ieee80211_key *key;
+       struct ieee80211_key *gtk[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS];
+       struct ieee80211_key *ptk;
        struct rate_control_ref *rate_ctrl;
        void *rate_ctrl_priv;
        spinlock_t lock;
index dd85006c4fe86350704c2ffaef04bf29be95b671..3153c19893b81ebe1309290b41491010cd296999 100644 (file)
@@ -176,7 +176,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
 
        for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
                /* the HW cannot have attempted that rate */
-               if (i >= hw->max_rates) {
+               if (i >= hw->max_report_rates) {
                        info->status.rates[i].idx = -1;
                        info->status.rates[i].count = 0;
                } else if (info->status.rates[i].idx >= 0) {
@@ -377,7 +377,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
                                skb2 = skb_clone(skb, GFP_ATOMIC);
                                if (skb2) {
                                        skb2->dev = prev_dev;
-                                       netif_receive_skb(skb2);
+                                       netif_rx(skb2);
                                }
                        }
 
@@ -386,7 +386,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
        }
        if (prev_dev) {
                skb->dev = prev_dev;
-               netif_receive_skb(skb);
+               netif_rx(skb);
                skb = NULL;
        }
        rcu_read_unlock();
index e1733dcb58a73025ba609b2a9919524ec2dd51c0..96c594309506432b897b4ab8c749aed4cb3c1349 100644 (file)
@@ -273,6 +273,9 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
                 */
                return TX_DROP;
 
+       if (tx->sdata->vif.type == NL80211_IFTYPE_WDS)
+               return TX_CONTINUE;
+
        if (tx->sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
                return TX_CONTINUE;
 
@@ -529,7 +532,7 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
 
        if (unlikely(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT))
                tx->key = NULL;
-       else if (tx->sta && (key = rcu_dereference(tx->sta->key)))
+       else if (tx->sta && (key = rcu_dereference(tx->sta->ptk)))
                tx->key = key;
        else if (ieee80211_is_mgmt(hdr->frame_control) &&
                 is_multicast_ether_addr(hdr->addr1) &&
index aba025d748e92cd8bdfa7e4c7347a4ea7e8ea18e..0b6fc92bc0d7520bbb9050c2850acaa5da71a1ff 100644 (file)
@@ -1221,7 +1221,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                mutex_lock(&local->sta_mtx);
 
                list_for_each_entry(sta, &local->sta_list, list) {
-                       ieee80211_sta_tear_down_BA_sessions(sta);
+                       ieee80211_sta_tear_down_BA_sessions(sta, true);
                        clear_sta_flags(sta, WLAN_STA_BLOCK_BA);
                }
 
@@ -1297,16 +1297,12 @@ static int check_mgd_smps(struct ieee80211_if_managed *ifmgd,
 }
 
 /* must hold iflist_mtx */
-void ieee80211_recalc_smps(struct ieee80211_local *local,
-                          struct ieee80211_sub_if_data *forsdata)
+void ieee80211_recalc_smps(struct ieee80211_local *local)
 {
        struct ieee80211_sub_if_data *sdata;
        enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_OFF;
        int count = 0;
 
-       if (forsdata)
-               lockdep_assert_held(&forsdata->u.mgd.mtx);
-
        lockdep_assert_held(&local->iflist_mtx);
 
        /*
@@ -1324,18 +1320,8 @@ void ieee80211_recalc_smps(struct ieee80211_local *local,
                        continue;
                if (sdata->vif.type != NL80211_IFTYPE_STATION)
                        goto set;
-               if (sdata != forsdata) {
-                       /*
-                        * This nested is ok -- we are holding the iflist_mtx
-                        * so can't get here twice or so. But it's required
-                        * since normally we acquire it first and then the
-                        * iflist_mtx.
-                        */
-                       mutex_lock_nested(&sdata->u.mgd.mtx, SINGLE_DEPTH_NESTING);
-                       count += check_mgd_smps(&sdata->u.mgd, &smps_mode);
-                       mutex_unlock(&sdata->u.mgd.mtx);
-               } else
-                       count += check_mgd_smps(&sdata->u.mgd, &smps_mode);
+
+               count += check_mgd_smps(&sdata->u.mgd, &smps_mode);
 
                if (count > 1) {
                        smps_mode = IEEE80211_SMPS_OFF;
index 26ed3e8587c20f13a22c7aa2e2abf91dedf3d62a..1781d99145e2d2594fc961e1a2fc9307aad957a5 100644 (file)
@@ -547,8 +547,20 @@ static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
        info.userhdr = nlmsg_data(nlh) + GENL_HDRLEN;
        info.attrs = family->attrbuf;
        genl_info_net_set(&info, net);
+       memset(&info.user_ptr, 0, sizeof(info.user_ptr));
 
-       return ops->doit(skb, &info);
+       if (family->pre_doit) {
+               err = family->pre_doit(ops, skb, &info);
+               if (err)
+                       return err;
+       }
+
+       err = ops->doit(skb, &info);
+
+       if (family->post_doit)
+               family->post_doit(ops, skb, &info);
+
+       return err;
 }
 
 static void genl_rcv(struct sk_buff *skb)
index 9c21ebf9780ea21ff22c9326da29a423061d088b..1684ad91763ced2f059e944d46b39d4729939f4d 100644 (file)
@@ -178,26 +178,10 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
                        char *newname)
 {
        struct cfg80211_registered_device *rdev2;
-       int wiphy_idx, taken = -1, result, digits;
+       int result;
 
        assert_cfg80211_lock();
 
-       /* prohibit calling the thing phy%d when %d is not its number */
-       sscanf(newname, PHY_NAME "%d%n", &wiphy_idx, &taken);
-       if (taken == strlen(newname) && wiphy_idx != rdev->wiphy_idx) {
-               /* count number of places needed to print wiphy_idx */
-               digits = 1;
-               while (wiphy_idx /= 10)
-                       digits++;
-               /*
-                * deny the name if it is phy<idx> where <idx> is printed
-                * without leading zeroes. taken == strlen(newname) here
-                */
-               if (taken == strlen(PHY_NAME) + digits)
-                       return -EINVAL;
-       }
-
-
        /* Ignore nop renames */
        if (strcmp(newname, dev_name(&rdev->wiphy.dev)) == 0)
                return 0;
@@ -205,7 +189,7 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
        /* Ensure another device does not already have this name. */
        list_for_each_entry(rdev2, &cfg80211_rdev_list, list)
                if (strcmp(newname, dev_name(&rdev2->wiphy.dev)) == 0)
-                       return -EINVAL;
+                       return -EEXIST;
 
        result = device_rename(&rdev->wiphy.dev, newname);
        if (result)
@@ -320,9 +304,11 @@ static void cfg80211_event_work(struct work_struct *work)
 struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
 {
        static int wiphy_counter;
-
-       struct cfg80211_registered_device *rdev;
+       int i;
+       struct cfg80211_registered_device *rdev, *rdev2;
        int alloc_size;
+       char nname[IFNAMSIZ + 1];
+       bool found = false;
 
        WARN_ON(ops->add_key && (!ops->del_key || !ops->set_default_key));
        WARN_ON(ops->auth && (!ops->assoc || !ops->deauth || !ops->disassoc));
@@ -346,16 +332,36 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
 
        if (unlikely(!wiphy_idx_valid(rdev->wiphy_idx))) {
                wiphy_counter--;
+               goto too_many_devs;
+       }
+
+       /* 64k wiphy devices is enough for anyone! */
+       for (i = 0; i < 0xFFFF; i++) {
+               found = false;
+               snprintf(nname, sizeof(nname)-1, PHY_NAME "%d", i);
+               nname[sizeof(nname)-1] = 0;
+               list_for_each_entry(rdev2, &cfg80211_rdev_list, list)
+                       if (strcmp(nname, dev_name(&rdev2->wiphy.dev)) == 0) {
+                               found = true;
+                               break;
+                       }
+
+               if (!found)
+                       break;
+       }
+
+       if (unlikely(found)) {
+too_many_devs:
                mutex_unlock(&cfg80211_mutex);
-               /* ugh, wrapped! */
+               /* ugh, too many devices already! */
                kfree(rdev);
                return NULL;
        }
 
-       mutex_unlock(&cfg80211_mutex);
-
        /* give it a proper name */
-       dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx);
+       dev_set_name(&rdev->wiphy.dev, "%s", nname);
+
+       mutex_unlock(&cfg80211_mutex);
 
        mutex_init(&rdev->mtx);
        mutex_init(&rdev->devlist_mtx);
index 5d89310b35878f20f9210f76d8c826d3e6f5d5cd..6583cca0e2ee52a8bec5403cb2a77d59e945d983 100644 (file)
@@ -375,7 +375,7 @@ bool cfg80211_sme_failed_reassoc(struct wireless_dev *wdev);
 /* internal helpers */
 int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
                                   struct key_params *params, int key_idx,
-                                  const u8 *mac_addr);
+                                  bool pairwise, const u8 *mac_addr);
 void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
                             size_t ie_len, u16 reason, bool from_ap);
 void cfg80211_sme_scan_done(struct net_device *dev);
index 8cb6e08373b989b7cb880315afff64221d33810f..f33fbb79437c3280b980447c9f36cd8c99436dc7 100644 (file)
@@ -160,7 +160,7 @@ static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext)
         */
        if (rdev->ops->del_key)
                for (i = 0; i < 6; i++)
-                       rdev->ops->del_key(wdev->wiphy, dev, i, NULL);
+                       rdev->ops->del_key(wdev->wiphy, dev, i, false, NULL);
 
        if (wdev->current_bss) {
                cfg80211_unhold_bss(wdev->current_bss);
index 46f3711608960b7ba42d6675219530b2c9886e2d..caf11a4275073c7fc7ba0f47937adf67da41384a 100644 (file)
@@ -876,21 +876,53 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
 
        if (ieee80211_is_action(mgmt->frame_control) &&
            mgmt->u.action.category != WLAN_CATEGORY_PUBLIC) {
-               /* Verify that we are associated with the destination AP */
+               int err = 0;
+
                wdev_lock(wdev);
 
-               if (!wdev->current_bss ||
-                   memcmp(wdev->current_bss->pub.bssid, mgmt->bssid,
-                          ETH_ALEN) != 0 ||
-                   ((wdev->iftype == NL80211_IFTYPE_STATION ||
-                     wdev->iftype == NL80211_IFTYPE_P2P_CLIENT) &&
-                    memcmp(wdev->current_bss->pub.bssid, mgmt->da,
-                           ETH_ALEN) != 0)) {
-                       wdev_unlock(wdev);
-                       return -ENOTCONN;
-               }
+               switch (wdev->iftype) {
+               case NL80211_IFTYPE_ADHOC:
+               case NL80211_IFTYPE_STATION:
+               case NL80211_IFTYPE_P2P_CLIENT:
+                       if (!wdev->current_bss) {
+                               err = -ENOTCONN;
+                               break;
+                       }
+
+                       if (memcmp(wdev->current_bss->pub.bssid,
+                                  mgmt->bssid, ETH_ALEN)) {
+                               err = -ENOTCONN;
+                               break;
+                       }
+
+                       /*
+                        * check for IBSS DA must be done by driver as
+                        * cfg80211 doesn't track the stations
+                        */
+                       if (wdev->iftype == NL80211_IFTYPE_ADHOC)
+                               break;
 
+                       /* for station, check that DA is the AP */
+                       if (memcmp(wdev->current_bss->pub.bssid,
+                                  mgmt->da, ETH_ALEN)) {
+                               err = -ENOTCONN;
+                               break;
+                       }
+                       break;
+               case NL80211_IFTYPE_AP:
+               case NL80211_IFTYPE_P2P_GO:
+               case NL80211_IFTYPE_AP_VLAN:
+                       if (memcmp(mgmt->bssid, dev->dev_addr, ETH_ALEN))
+                               err = -EINVAL;
+                       break;
+               default:
+                       err = -EOPNOTSUPP;
+                       break;
+               }
                wdev_unlock(wdev);
+
+               if (err)
+                       return err;
        }
 
        if (memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0)
index 9c84825803ceb13de075a1e763e0c72fd4217b66..882dc921103ba91d29b630a703752b7d3a322ed2 100644 (file)
 #include "nl80211.h"
 #include "reg.h"
 
+static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb,
+                           struct genl_info *info);
+static void nl80211_post_doit(struct genl_ops *ops, struct sk_buff *skb,
+                             struct genl_info *info);
+
 /* the netlink family */
 static struct genl_family nl80211_fam = {
        .id = GENL_ID_GENERATE, /* don't bother with a hardcoded ID */
@@ -31,6 +36,8 @@ static struct genl_family nl80211_fam = {
        .version = 1,           /* no particular meaning now */
        .maxattr = NL80211_ATTR_MAX,
        .netnsok = true,
+       .pre_doit = nl80211_pre_doit,
+       .post_doit = nl80211_post_doit,
 };
 
 /* internal helper: get rdev and dev */
@@ -86,6 +93,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
        [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 },
        [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG },
        [NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 },
+       [NL80211_ATTR_KEY_TYPE] = { .type = NLA_U32 },
 
        [NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 },
        [NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 },
@@ -161,7 +169,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
        [NL80211_ATTR_FRAME_TYPE] = { .type = NLA_U16 },
 };
 
-/* policy for the attributes */
+/* policy for the key attributes */
 static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = {
        [NL80211_KEY_DATA] = { .type = NLA_BINARY, .len = WLAN_MAX_KEY_LEN },
        [NL80211_KEY_IDX] = { .type = NLA_U8 },
@@ -169,6 +177,7 @@ static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = {
        [NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 },
        [NL80211_KEY_DEFAULT] = { .type = NLA_FLAG },
        [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG },
+       [NL80211_KEY_TYPE] = { .type = NLA_U32 },
 };
 
 /* ifidx get helper */
@@ -191,6 +200,47 @@ static int nl80211_get_ifidx(struct netlink_callback *cb)
        return res;
 }
 
+static int nl80211_prepare_netdev_dump(struct sk_buff *skb,
+                                      struct netlink_callback *cb,
+                                      struct cfg80211_registered_device **rdev,
+                                      struct net_device **dev)
+{
+       int ifidx = cb->args[0];
+       int err;
+
+       if (!ifidx)
+               ifidx = nl80211_get_ifidx(cb);
+       if (ifidx < 0)
+               return ifidx;
+
+       cb->args[0] = ifidx;
+
+       rtnl_lock();
+
+       *dev = __dev_get_by_index(sock_net(skb->sk), ifidx);
+       if (!*dev) {
+               err = -ENODEV;
+               goto out_rtnl;
+       }
+
+       *rdev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx);
+       if (IS_ERR(dev)) {
+               err = PTR_ERR(dev);
+               goto out_rtnl;
+       }
+
+       return 0;
+ out_rtnl:
+       rtnl_unlock();
+       return err;
+}
+
+static void nl80211_finish_netdev_dump(struct cfg80211_registered_device *rdev)
+{
+       cfg80211_unlock_rdev(rdev);
+       rtnl_unlock();
+}
+
 /* IE validation */
 static bool is_valid_ie_attr(const struct nlattr *attr)
 {
@@ -258,6 +308,7 @@ static int nl80211_msg_put_channel(struct sk_buff *msg,
 struct key_parse {
        struct key_params p;
        int idx;
+       int type;
        bool def, defmgmt;
 };
 
@@ -288,6 +339,12 @@ static int nl80211_parse_key_new(struct nlattr *key, struct key_parse *k)
        if (tb[NL80211_KEY_CIPHER])
                k->p.cipher = nla_get_u32(tb[NL80211_KEY_CIPHER]);
 
+       if (tb[NL80211_KEY_TYPE]) {
+               k->type = nla_get_u32(tb[NL80211_KEY_TYPE]);
+               if (k->type < 0 || k->type >= NUM_NL80211_KEYTYPES)
+                       return -EINVAL;
+       }
+
        return 0;
 }
 
@@ -312,6 +369,12 @@ static int nl80211_parse_key_old(struct genl_info *info, struct key_parse *k)
        k->def = !!info->attrs[NL80211_ATTR_KEY_DEFAULT];
        k->defmgmt = !!info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT];
 
+       if (info->attrs[NL80211_ATTR_KEY_TYPE]) {
+               k->type = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]);
+               if (k->type < 0 || k->type >= NUM_NL80211_KEYTYPES)
+                       return -EINVAL;
+       }
+
        return 0;
 }
 
@@ -321,6 +384,7 @@ static int nl80211_parse_key(struct genl_info *info, struct key_parse *k)
 
        memset(k, 0, sizeof(*k));
        k->idx = -1;
+       k->type = -1;
 
        if (info->attrs[NL80211_ATTR_KEY])
                err = nl80211_parse_key_new(info->attrs[NL80211_ATTR_KEY], k);
@@ -385,7 +449,7 @@ nl80211_parse_connkeys(struct cfg80211_registered_device *rdev,
                } else if (parse.defmgmt)
                        goto error;
                err = cfg80211_validate_key_settings(rdev, &parse.p,
-                                                    parse.idx, NULL);
+                                                    parse.idx, false, NULL);
                if (err)
                        goto error;
                result->params[parse.idx].cipher = parse.p.cipher;
@@ -404,9 +468,6 @@ static int nl80211_key_allowed(struct wireless_dev *wdev)
 {
        ASSERT_WDEV_LOCK(wdev);
 
-       if (!netif_running(wdev->netdev))
-               return -ENETDOWN;
-
        switch (wdev->iftype) {
        case NL80211_IFTYPE_AP:
        case NL80211_IFTYPE_AP_VLAN:
@@ -471,6 +532,9 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
        NLA_PUT_U16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN,
                    dev->wiphy.max_scan_ie_len);
 
+       if (dev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)
+               NLA_PUT_FLAG(msg, NL80211_ATTR_SUPPORT_IBSS_RSN);
+
        NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES,
                sizeof(u32) * dev->wiphy.n_cipher_suites,
                dev->wiphy.cipher_suites);
@@ -603,6 +667,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
                NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS);
        }
        CMD(set_channel, SET_CHANNEL);
+       CMD(set_wds_peer, SET_WDS_PEER);
 
 #undef CMD
 
@@ -703,28 +768,18 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
 static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info)
 {
        struct sk_buff *msg;
-       struct cfg80211_registered_device *dev;
-
-       dev = cfg80211_get_dev_from_info(info);
-       if (IS_ERR(dev))
-               return PTR_ERR(dev);
+       struct cfg80211_registered_device *dev = info->user_ptr[0];
 
        msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
        if (!msg)
-               goto out_err;
-
-       if (nl80211_send_wiphy(msg, info->snd_pid, info->snd_seq, 0, dev) < 0)
-               goto out_free;
+               return -ENOMEM;
 
-       cfg80211_unlock_rdev(dev);
+       if (nl80211_send_wiphy(msg, info->snd_pid, info->snd_seq, 0, dev) < 0) {
+               nlmsg_free(msg);
+               return -ENOBUFS;
+       }
 
        return genlmsg_reply(msg, info);
-
- out_free:
-       nlmsg_free(msg);
- out_err:
-       cfg80211_unlock_rdev(dev);
-       return -ENOBUFS;
 }
 
 static const struct nla_policy txq_params_policy[NL80211_TXQ_ATTR_MAX + 1] = {
@@ -813,24 +868,36 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
 
 static int nl80211_set_channel(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
-       struct net_device *netdev;
-       int result;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *netdev = info->user_ptr[1];
 
-       rtnl_lock();
+       return __nl80211_set_channel(rdev, netdev->ieee80211_ptr, info);
+}
 
-       result = get_rdev_dev_by_info_ifindex(info, &rdev, &netdev);
-       if (result)
-               goto unlock;
+static int nl80211_set_wds_peer(struct sk_buff *skb, struct genl_info *info)
+{
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       const u8 *bssid;
 
-       result = __nl80211_set_channel(rdev, netdev->ieee80211_ptr, info);
+       if (!info->attrs[NL80211_ATTR_MAC])
+               return -EINVAL;
 
- unlock:
-       rtnl_unlock();
+       if (netif_running(dev))
+               return -EBUSY;
 
-       return result;
+       if (!rdev->ops->set_wds_peer)
+               return -EOPNOTSUPP;
+
+       if (wdev->iftype != NL80211_IFTYPE_WDS)
+               return -EOPNOTSUPP;
+
+       bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
+       return rdev->ops->set_wds_peer(wdev->wiphy, dev, bssid);
 }
 
+
 static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
 {
        struct cfg80211_registered_device *rdev;
@@ -843,8 +910,6 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
        u32 frag_threshold = 0, rts_threshold = 0;
        u8 coverage_class = 0;
 
-       rtnl_lock();
-
        /*
         * Try to find the wiphy and netdev. Normally this
         * function shouldn't need the netdev, but this is
@@ -871,8 +936,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
                rdev = __cfg80211_rdev_from_info(info);
                if (IS_ERR(rdev)) {
                        mutex_unlock(&cfg80211_mutex);
-                       result = PTR_ERR(rdev);
-                       goto unlock;
+                       return PTR_ERR(rdev);
                }
                wdev = NULL;
                netdev = NULL;
@@ -1054,8 +1118,6 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
        mutex_unlock(&rdev->mtx);
        if (netdev)
                dev_put(netdev);
- unlock:
-       rtnl_unlock();
        return result;
 }
 
@@ -1135,33 +1197,20 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *
 static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info)
 {
        struct sk_buff *msg;
-       struct cfg80211_registered_device *dev;
-       struct net_device *netdev;
-       int err;
-
-       err = get_rdev_dev_by_info_ifindex(info, &dev, &netdev);
-       if (err)
-               return err;
+       struct cfg80211_registered_device *dev = info->user_ptr[0];
+       struct net_device *netdev = info->user_ptr[1];
 
        msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
        if (!msg)
-               goto out_err;
+               return -ENOMEM;
 
        if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0,
-                              dev, netdev) < 0)
-               goto out_free;
-
-       dev_put(netdev);
-       cfg80211_unlock_rdev(dev);
+                              dev, netdev) < 0) {
+               nlmsg_free(msg);
+               return -ENOBUFS;
+       }
 
        return genlmsg_reply(msg, info);
-
- out_free:
-       nlmsg_free(msg);
- out_err:
-       dev_put(netdev);
-       cfg80211_unlock_rdev(dev);
-       return -ENOBUFS;
 }
 
 static const struct nla_policy mntr_flags_policy[NL80211_MNTR_FLAG_MAX + 1] = {
@@ -1221,39 +1270,29 @@ static int nl80211_valid_4addr(struct cfg80211_registered_device *rdev,
 
 static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
        struct vif_params params;
        int err;
        enum nl80211_iftype otype, ntype;
-       struct net_device *dev;
+       struct net_device *dev = info->user_ptr[1];
        u32 _flags, *flags = NULL;
        bool change = false;
 
        memset(&params, 0, sizeof(params));
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto unlock_rtnl;
-
        otype = ntype = dev->ieee80211_ptr->iftype;
 
        if (info->attrs[NL80211_ATTR_IFTYPE]) {
                ntype = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
                if (otype != ntype)
                        change = true;
-               if (ntype > NL80211_IFTYPE_MAX) {
-                       err = -EINVAL;
-                       goto unlock;
-               }
+               if (ntype > NL80211_IFTYPE_MAX)
+                       return -EINVAL;
        }
 
        if (info->attrs[NL80211_ATTR_MESH_ID]) {
-               if (ntype != NL80211_IFTYPE_MESH_POINT) {
-                       err = -EINVAL;
-                       goto unlock;
-               }
+               if (ntype != NL80211_IFTYPE_MESH_POINT)
+                       return -EINVAL;
                params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]);
                params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
                change = true;
@@ -1264,20 +1303,18 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
                change = true;
                err = nl80211_valid_4addr(rdev, dev, params.use_4addr, ntype);
                if (err)
-                       goto unlock;
+                       return err;
        } else {
                params.use_4addr = -1;
        }
 
        if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) {
-               if (ntype != NL80211_IFTYPE_MONITOR) {
-                       err = -EINVAL;
-                       goto unlock;
-               }
+               if (ntype != NL80211_IFTYPE_MONITOR)
+                       return -EINVAL;
                err = parse_monitor_flags(info->attrs[NL80211_ATTR_MNTR_FLAGS],
                                          &_flags);
                if (err)
-                       goto unlock;
+                       return err;
 
                flags = &_flags;
                change = true;
@@ -1291,17 +1328,12 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
        if (!err && params.use_4addr != -1)
                dev->ieee80211_ptr->use_4addr = params.use_4addr;
 
- unlock:
-       dev_put(dev);
-       cfg80211_unlock_rdev(rdev);
- unlock_rtnl:
-       rtnl_unlock();
        return err;
 }
 
 static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
        struct vif_params params;
        int err;
        enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
@@ -1318,19 +1350,9 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
                        return -EINVAL;
        }
 
-       rtnl_lock();
-
-       rdev = cfg80211_get_dev_from_info(info);
-       if (IS_ERR(rdev)) {
-               err = PTR_ERR(rdev);
-               goto unlock_rtnl;
-       }
-
        if (!rdev->ops->add_virtual_intf ||
-           !(rdev->wiphy.interface_modes & (1 << type))) {
-               err = -EOPNOTSUPP;
-               goto unlock;
-       }
+           !(rdev->wiphy.interface_modes & (1 << type)))
+               return -EOPNOTSUPP;
 
        if (type == NL80211_IFTYPE_MESH_POINT &&
            info->attrs[NL80211_ATTR_MESH_ID]) {
@@ -1342,7 +1364,7 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
                params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
                err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type);
                if (err)
-                       goto unlock;
+                       return err;
        }
 
        err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
@@ -1352,38 +1374,18 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
                nla_data(info->attrs[NL80211_ATTR_IFNAME]),
                type, err ? NULL : &flags, &params);
 
- unlock:
-       cfg80211_unlock_rdev(rdev);
- unlock_rtnl:
-       rtnl_unlock();
        return err;
 }
 
 static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
-       int err;
-       struct net_device *dev;
-
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto unlock_rtnl;
-
-       if (!rdev->ops->del_virtual_intf) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
 
-       err = rdev->ops->del_virtual_intf(&rdev->wiphy, dev);
+       if (!rdev->ops->del_virtual_intf)
+               return -EOPNOTSUPP;
 
- out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
- unlock_rtnl:
-       rtnl_unlock();
-       return err;
+       return rdev->ops->del_virtual_intf(&rdev->wiphy, dev);
 }
 
 struct get_key_cookie {
@@ -1436,11 +1438,12 @@ static void get_key_callback(void *c, struct key_params *params)
 
 static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
        int err;
-       struct net_device *dev;
+       struct net_device *dev = info->user_ptr[1];
        u8 key_idx = 0;
-       u8 *mac_addr = NULL;
+       const u8 *mac_addr = NULL;
+       bool pairwise;
        struct get_key_cookie cookie = {
                .error = 0,
        };
@@ -1456,30 +1459,28 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
        if (info->attrs[NL80211_ATTR_MAC])
                mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto unlock_rtnl;
-
-       if (!rdev->ops->get_key) {
-               err = -EOPNOTSUPP;
-               goto out;
+       pairwise = !!mac_addr;
+       if (info->attrs[NL80211_ATTR_KEY_TYPE]) {
+               u32 kt = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]);
+               if (kt >= NUM_NL80211_KEYTYPES)
+                       return -EINVAL;
+               if (kt != NL80211_KEYTYPE_GROUP &&
+                   kt != NL80211_KEYTYPE_PAIRWISE)
+                       return -EINVAL;
+               pairwise = kt == NL80211_KEYTYPE_PAIRWISE;
        }
 
+       if (!rdev->ops->get_key)
+               return -EOPNOTSUPP;
+
        msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
-       if (!msg) {
-               err = -ENOMEM;
-               goto out;
-       }
+       if (!msg)
+               return -ENOMEM;
 
        hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
                             NL80211_CMD_NEW_KEY);
-
-       if (IS_ERR(hdr)) {
-               err = PTR_ERR(hdr);
-               goto free_msg;
-       }
+       if (IS_ERR(hdr))
+               return PTR_ERR(hdr);
 
        cookie.msg = msg;
        cookie.idx = key_idx;
@@ -1489,8 +1490,12 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
        if (mac_addr)
                NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr);
 
-       err = rdev->ops->get_key(&rdev->wiphy, dev, key_idx, mac_addr,
-                               &cookie, get_key_callback);
+       if (pairwise && mac_addr &&
+           !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
+               return -ENOENT;
+
+       err = rdev->ops->get_key(&rdev->wiphy, dev, key_idx, pairwise,
+                                mac_addr, &cookie, get_key_callback);
 
        if (err)
                goto free_msg;
@@ -1499,28 +1504,21 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
                goto nla_put_failure;
 
        genlmsg_end(msg, hdr);
-       err = genlmsg_reply(msg, info);
-       goto out;
+       return genlmsg_reply(msg, info);
 
  nla_put_failure:
        err = -ENOBUFS;
  free_msg:
        nlmsg_free(msg);
- out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
- unlock_rtnl:
-       rtnl_unlock();
-
        return err;
 }
 
 static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
        struct key_parse key;
        int err;
-       struct net_device *dev;
+       struct net_device *dev = info->user_ptr[1];
        int (*func)(struct wiphy *wiphy, struct net_device *netdev,
                    u8 key_index);
 
@@ -1535,21 +1533,13 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
        if (!key.def && !key.defmgmt)
                return -EINVAL;
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto unlock_rtnl;
-
        if (key.def)
                func = rdev->ops->set_default_key;
        else
                func = rdev->ops->set_default_mgmt_key;
 
-       if (!func) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
+       if (!func)
+               return -EOPNOTSUPP;
 
        wdev_lock(dev->ieee80211_ptr);
        err = nl80211_key_allowed(dev->ieee80211_ptr);
@@ -1566,23 +1556,16 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
 #endif
        wdev_unlock(dev->ieee80211_ptr);
 
- out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
-
- unlock_rtnl:
-       rtnl_unlock();
-
        return err;
 }
 
 static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
        int err;
-       struct net_device *dev;
+       struct net_device *dev = info->user_ptr[1];
        struct key_parse key;
-       u8 *mac_addr = NULL;
+       const u8 *mac_addr = NULL;
 
        err = nl80211_parse_key(info, &key);
        if (err)
@@ -1594,43 +1577,42 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
        if (info->attrs[NL80211_ATTR_MAC])
                mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
 
-       rtnl_lock();
+       if (key.type == -1) {
+               if (mac_addr)
+                       key.type = NL80211_KEYTYPE_PAIRWISE;
+               else
+                       key.type = NL80211_KEYTYPE_GROUP;
+       }
 
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto unlock_rtnl;
+       /* for now */
+       if (key.type != NL80211_KEYTYPE_PAIRWISE &&
+           key.type != NL80211_KEYTYPE_GROUP)
+               return -EINVAL;
 
-       if (!rdev->ops->add_key) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
+       if (!rdev->ops->add_key)
+               return -EOPNOTSUPP;
 
-       if (cfg80211_validate_key_settings(rdev, &key.p, key.idx, mac_addr)) {
-               err = -EINVAL;
-               goto out;
-       }
+       if (cfg80211_validate_key_settings(rdev, &key.p, key.idx,
+                                          key.type == NL80211_KEYTYPE_PAIRWISE,
+                                          mac_addr))
+               return -EINVAL;
 
        wdev_lock(dev->ieee80211_ptr);
        err = nl80211_key_allowed(dev->ieee80211_ptr);
        if (!err)
                err = rdev->ops->add_key(&rdev->wiphy, dev, key.idx,
+                                        key.type == NL80211_KEYTYPE_PAIRWISE,
                                         mac_addr, &key.p);
        wdev_unlock(dev->ieee80211_ptr);
 
- out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
- unlock_rtnl:
-       rtnl_unlock();
-
        return err;
 }
 
 static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
        int err;
-       struct net_device *dev;
+       struct net_device *dev = info->user_ptr[1];
        u8 *mac_addr = NULL;
        struct key_parse key;
 
@@ -1641,21 +1623,32 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
        if (info->attrs[NL80211_ATTR_MAC])
                mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
 
-       rtnl_lock();
+       if (key.type == -1) {
+               if (mac_addr)
+                       key.type = NL80211_KEYTYPE_PAIRWISE;
+               else
+                       key.type = NL80211_KEYTYPE_GROUP;
+       }
 
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto unlock_rtnl;
+       /* for now */
+       if (key.type != NL80211_KEYTYPE_PAIRWISE &&
+           key.type != NL80211_KEYTYPE_GROUP)
+               return -EINVAL;
 
-       if (!rdev->ops->del_key) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
+       if (!rdev->ops->del_key)
+               return -EOPNOTSUPP;
 
        wdev_lock(dev->ieee80211_ptr);
        err = nl80211_key_allowed(dev->ieee80211_ptr);
+
+       if (key.type == NL80211_KEYTYPE_PAIRWISE && mac_addr &&
+           !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
+               err = -ENOENT;
+
        if (!err)
-               err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx, mac_addr);
+               err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx,
+                                        key.type == NL80211_KEYTYPE_PAIRWISE,
+                                        mac_addr);
 
 #ifdef CONFIG_CFG80211_WEXT
        if (!err) {
@@ -1667,13 +1660,6 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
 #endif
        wdev_unlock(dev->ieee80211_ptr);
 
- out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
-
- unlock_rtnl:
-       rtnl_unlock();
-
        return err;
 }
 
@@ -1681,36 +1667,25 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
 {
         int (*call)(struct wiphy *wiphy, struct net_device *dev,
                    struct beacon_parameters *info);
-       struct cfg80211_registered_device *rdev;
-       int err;
-       struct net_device *dev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
        struct beacon_parameters params;
        int haveinfo = 0;
 
        if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL]))
                return -EINVAL;
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto unlock_rtnl;
-
        if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
-           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
+               return -EOPNOTSUPP;
 
        switch (info->genlhdr->cmd) {
        case NL80211_CMD_NEW_BEACON:
                /* these are required for NEW_BEACON */
                if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] ||
                    !info->attrs[NL80211_ATTR_DTIM_PERIOD] ||
-                   !info->attrs[NL80211_ATTR_BEACON_HEAD]) {
-                       err = -EINVAL;
-                       goto out;
-               }
+                   !info->attrs[NL80211_ATTR_BEACON_HEAD])
+                       return -EINVAL;
 
                call = rdev->ops->add_beacon;
                break;
@@ -1719,14 +1694,11 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
                break;
        default:
                WARN_ON(1);
-               err = -EOPNOTSUPP;
-               goto out;
+               return -EOPNOTSUPP;
        }
 
-       if (!call) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
+       if (!call)
+               return -EOPNOTSUPP;
 
        memset(&params, 0, sizeof(params));
 
@@ -1756,53 +1728,25 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
                haveinfo = 1;
        }
 
-       if (!haveinfo) {
-               err = -EINVAL;
-               goto out;
-       }
-
-       err = call(&rdev->wiphy, dev, &params);
-
- out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
- unlock_rtnl:
-       rtnl_unlock();
+       if (!haveinfo)
+               return -EINVAL;
 
-       return err;
+       return call(&rdev->wiphy, dev, &params);
 }
 
 static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
-       int err;
-       struct net_device *dev;
-
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto unlock_rtnl;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
 
-       if (!rdev->ops->del_beacon) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
+       if (!rdev->ops->del_beacon)
+               return -EOPNOTSUPP;
 
        if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
-           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-       err = rdev->ops->del_beacon(&rdev->wiphy, dev);
-
- out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
- unlock_rtnl:
-       rtnl_unlock();
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
+               return -EOPNOTSUPP;
 
-       return err;
+       return rdev->ops->del_beacon(&rdev->wiphy, dev);
 }
 
 static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = {
@@ -1923,6 +1867,12 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq,
        if (sinfo->filled & STATION_INFO_TX_PACKETS)
                NLA_PUT_U32(msg, NL80211_STA_INFO_TX_PACKETS,
                            sinfo->tx_packets);
+       if (sinfo->filled & STATION_INFO_TX_RETRIES)
+               NLA_PUT_U32(msg, NL80211_STA_INFO_TX_RETRIES,
+                           sinfo->tx_retries);
+       if (sinfo->filled & STATION_INFO_TX_FAILED)
+               NLA_PUT_U32(msg, NL80211_STA_INFO_TX_FAILED,
+                           sinfo->tx_failed);
        nla_nest_end(msg, sinfoattr);
 
        return genlmsg_end(msg, hdr);
@@ -1939,28 +1889,12 @@ static int nl80211_dump_station(struct sk_buff *skb,
        struct cfg80211_registered_device *dev;
        struct net_device *netdev;
        u8 mac_addr[ETH_ALEN];
-       int ifidx = cb->args[0];
        int sta_idx = cb->args[1];
        int err;
 
-       if (!ifidx)
-               ifidx = nl80211_get_ifidx(cb);
-       if (ifidx < 0)
-               return ifidx;
-
-       rtnl_lock();
-
-       netdev = __dev_get_by_index(sock_net(skb->sk), ifidx);
-       if (!netdev) {
-               err = -ENODEV;
-               goto out_rtnl;
-       }
-
-       dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx);
-       if (IS_ERR(dev)) {
-               err = PTR_ERR(dev);
-               goto out_rtnl;
-       }
+       err = nl80211_prepare_netdev_dump(skb, cb, &dev, &netdev);
+       if (err)
+               return err;
 
        if (!dev->ops->dump_station) {
                err = -EOPNOTSUPP;
@@ -1990,21 +1924,19 @@ static int nl80211_dump_station(struct sk_buff *skb,
        cb->args[1] = sta_idx;
        err = skb->len;
  out_err:
-       cfg80211_unlock_rdev(dev);
- out_rtnl:
-       rtnl_unlock();
+       nl80211_finish_netdev_dump(dev);
 
        return err;
 }
 
 static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
-       int err;
-       struct net_device *dev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
        struct station_info sinfo;
        struct sk_buff *msg;
        u8 *mac_addr = NULL;
+       int err;
 
        memset(&sinfo, 0, sizeof(sinfo));
 
@@ -2013,41 +1945,24 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
 
        mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto out_rtnl;
-
-       if (!rdev->ops->get_station) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
+       if (!rdev->ops->get_station)
+               return -EOPNOTSUPP;
 
        err = rdev->ops->get_station(&rdev->wiphy, dev, mac_addr, &sinfo);
        if (err)
-               goto out;
+               return err;
 
        msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
        if (!msg)
-               goto out;
+               return -ENOMEM;
 
        if (nl80211_send_station(msg, info->snd_pid, info->snd_seq, 0,
-                                dev, mac_addr, &sinfo) < 0)
-               goto out_free;
-
-       err = genlmsg_reply(msg, info);
-       goto out;
-
- out_free:
-       nlmsg_free(msg);
- out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
- out_rtnl:
-       rtnl_unlock();
+                                dev, mac_addr, &sinfo) < 0) {
+               nlmsg_free(msg);
+               return -ENOBUFS;
+       }
 
-       return err;
+       return genlmsg_reply(msg, info);
 }
 
 /*
@@ -2077,9 +1992,9 @@ static int get_vlan(struct genl_info *info,
 
 static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
        int err;
-       struct net_device *dev;
+       struct net_device *dev = info->user_ptr[1];
        struct station_parameters params;
        u8 *mac_addr = NULL;
 
@@ -2117,12 +2032,6 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
                params.plink_action =
                    nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto out_rtnl;
-
        err = get_vlan(info, rdev, &params.vlan);
        if (err)
                goto out;
@@ -2184,19 +2093,15 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
  out:
        if (params.vlan)
                dev_put(params.vlan);
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
- out_rtnl:
-       rtnl_unlock();
 
        return err;
 }
 
 static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
        int err;
-       struct net_device *dev;
+       struct net_device *dev = info->user_ptr[1];
        struct station_parameters params;
        u8 *mac_addr = NULL;
 
@@ -2233,18 +2138,10 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
        if (parse_station_flags(info, &params))
                return -EINVAL;
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto out_rtnl;
-
        if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
            dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
-           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) {
-               err = -EINVAL;
-               goto out;
-       }
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
+               return -EINVAL;
 
        err = get_vlan(info, rdev, &params.vlan);
        if (err)
@@ -2258,62 +2155,33 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
                goto out;
        }
 
-       if (!netif_running(dev)) {
-               err = -ENETDOWN;
-               goto out;
-       }
-
        err = rdev->ops->add_station(&rdev->wiphy, dev, mac_addr, &params);
 
  out:
        if (params.vlan)
                dev_put(params.vlan);
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
- out_rtnl:
-       rtnl_unlock();
-
        return err;
 }
 
 static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
-       int err;
-       struct net_device *dev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
        u8 *mac_addr = NULL;
 
        if (info->attrs[NL80211_ATTR_MAC])
                mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto out_rtnl;
-
        if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
            dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
            dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT &&
-           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) {
-               err = -EINVAL;
-               goto out;
-       }
-
-       if (!rdev->ops->del_station) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       err = rdev->ops->del_station(&rdev->wiphy, dev, mac_addr);
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
+               return -EINVAL;
 
- out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
- out_rtnl:
-       rtnl_unlock();
+       if (!rdev->ops->del_station)
+               return -EOPNOTSUPP;
 
-       return err;
+       return rdev->ops->del_station(&rdev->wiphy, dev, mac_addr);
 }
 
 static int nl80211_send_mpath(struct sk_buff *msg, u32 pid, u32 seq,
@@ -2376,28 +2244,12 @@ static int nl80211_dump_mpath(struct sk_buff *skb,
        struct net_device *netdev;
        u8 dst[ETH_ALEN];
        u8 next_hop[ETH_ALEN];
-       int ifidx = cb->args[0];
        int path_idx = cb->args[1];
        int err;
 
-       if (!ifidx)
-               ifidx = nl80211_get_ifidx(cb);
-       if (ifidx < 0)
-               return ifidx;
-
-       rtnl_lock();
-
-       netdev = __dev_get_by_index(sock_net(skb->sk), ifidx);
-       if (!netdev) {
-               err = -ENODEV;
-               goto out_rtnl;
-       }
-
-       dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx);
-       if (IS_ERR(dev)) {
-               err = PTR_ERR(dev);
-               goto out_rtnl;
-       }
+       err = nl80211_prepare_netdev_dump(skb, cb, &dev, &netdev);
+       if (err)
+               return err;
 
        if (!dev->ops->dump_mpath) {
                err = -EOPNOTSUPP;
@@ -2431,18 +2283,15 @@ static int nl80211_dump_mpath(struct sk_buff *skb,
        cb->args[1] = path_idx;
        err = skb->len;
  out_err:
-       cfg80211_unlock_rdev(dev);
- out_rtnl:
-       rtnl_unlock();
-
+       nl80211_finish_netdev_dump(dev);
        return err;
 }
 
 static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
        int err;
-       struct net_device *dev;
+       struct net_device *dev = info->user_ptr[1];
        struct mpath_info pinfo;
        struct sk_buff *msg;
        u8 *dst = NULL;
@@ -2455,53 +2304,33 @@ static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info)
 
        dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto out_rtnl;
-
-       if (!rdev->ops->get_mpath) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
+       if (!rdev->ops->get_mpath)
+               return -EOPNOTSUPP;
 
-       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
+       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
+               return -EOPNOTSUPP;
 
        err = rdev->ops->get_mpath(&rdev->wiphy, dev, dst, next_hop, &pinfo);
        if (err)
-               goto out;
+               return err;
 
        msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
        if (!msg)
-               goto out;
+               return -ENOMEM;
 
        if (nl80211_send_mpath(msg, info->snd_pid, info->snd_seq, 0,
-                                dev, dst, next_hop, &pinfo) < 0)
-               goto out_free;
-
-       err = genlmsg_reply(msg, info);
-       goto out;
-
- out_free:
-       nlmsg_free(msg);
- out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
- out_rtnl:
-       rtnl_unlock();
+                                dev, dst, next_hop, &pinfo) < 0) {
+               nlmsg_free(msg);
+               return -ENOBUFS;
+       }
 
-       return err;
+       return genlmsg_reply(msg, info);
 }
 
 static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
-       int err;
-       struct net_device *dev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
        u8 *dst = NULL;
        u8 *next_hop = NULL;
 
@@ -2514,42 +2343,19 @@ static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info)
        dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
        next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]);
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto out_rtnl;
-
-       if (!rdev->ops->change_mpath) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       if (!netif_running(dev)) {
-               err = -ENETDOWN;
-               goto out;
-       }
-
-       err = rdev->ops->change_mpath(&rdev->wiphy, dev, dst, next_hop);
+       if (!rdev->ops->change_mpath)
+               return -EOPNOTSUPP;
 
- out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
- out_rtnl:
-       rtnl_unlock();
+       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
+               return -EOPNOTSUPP;
 
-       return err;
+       return rdev->ops->change_mpath(&rdev->wiphy, dev, dst, next_hop);
 }
+
 static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
-       int err;
-       struct net_device *dev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
        u8 *dst = NULL;
        u8 *next_hop = NULL;
 
@@ -2562,75 +2368,34 @@ static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info)
        dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
        next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]);
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto out_rtnl;
-
-       if (!rdev->ops->add_mpath) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       if (!netif_running(dev)) {
-               err = -ENETDOWN;
-               goto out;
-       }
-
-       err = rdev->ops->add_mpath(&rdev->wiphy, dev, dst, next_hop);
+       if (!rdev->ops->add_mpath)
+               return -EOPNOTSUPP;
 
- out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
- out_rtnl:
-       rtnl_unlock();
+       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
+               return -EOPNOTSUPP;
 
-       return err;
+       return rdev->ops->add_mpath(&rdev->wiphy, dev, dst, next_hop);
 }
 
 static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
-       int err;
-       struct net_device *dev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
        u8 *dst = NULL;
 
        if (info->attrs[NL80211_ATTR_MAC])
                dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto out_rtnl;
-
-       if (!rdev->ops->del_mpath) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       err = rdev->ops->del_mpath(&rdev->wiphy, dev, dst);
-
- out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
- out_rtnl:
-       rtnl_unlock();
+       if (!rdev->ops->del_mpath)
+               return -EOPNOTSUPP;
 
-       return err;
+       return rdev->ops->del_mpath(&rdev->wiphy, dev, dst);
 }
 
 static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
-       int err;
-       struct net_device *dev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
        struct bss_parameters params;
 
        memset(&params, 0, sizeof(params));
@@ -2658,32 +2423,14 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
        if (info->attrs[NL80211_ATTR_AP_ISOLATE])
                params.ap_isolate = !!nla_get_u8(info->attrs[NL80211_ATTR_AP_ISOLATE]);
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto out_rtnl;
-
-       if (!rdev->ops->change_bss) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
+       if (!rdev->ops->change_bss)
+               return -EOPNOTSUPP;
 
        if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
-           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       err = rdev->ops->change_bss(&rdev->wiphy, dev, &params);
-
- out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
- out_rtnl:
-       rtnl_unlock();
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
+               return -EOPNOTSUPP;
 
-       return err;
+       return rdev->ops->change_bss(&rdev->wiphy, dev, &params);
 }
 
 static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = {
@@ -2762,37 +2509,26 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
 static int nl80211_get_mesh_params(struct sk_buff *skb,
        struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
        struct mesh_config cur_params;
        int err;
-       struct net_device *dev;
+       struct net_device *dev = info->user_ptr[1];
        void *hdr;
        struct nlattr *pinfoattr;
        struct sk_buff *msg;
 
-       rtnl_lock();
-
-       /* Look up our device */
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto out_rtnl;
-
-       if (!rdev->ops->get_mesh_params) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
+       if (!rdev->ops->get_mesh_params)
+               return -EOPNOTSUPP;
 
        /* Get the mesh params */
        err = rdev->ops->get_mesh_params(&rdev->wiphy, dev, &cur_params);
        if (err)
-               goto out;
+               return err;
 
        /* Draw up a netlink message to send back */
        msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
-       if (!msg) {
-               err = -ENOBUFS;
-               goto out;
-       }
+       if (!msg)
+               return -ENOMEM;
        hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
                             NL80211_CMD_GET_MESH_PARAMS);
        if (!hdr)
@@ -2831,21 +2567,12 @@ static int nl80211_get_mesh_params(struct sk_buff *skb,
                        cur_params.dot11MeshHWMPRootMode);
        nla_nest_end(msg, pinfoattr);
        genlmsg_end(msg, hdr);
-       err = genlmsg_reply(msg, info);
-       goto out;
+       return genlmsg_reply(msg, info);
 
  nla_put_failure:
        genlmsg_cancel(msg, hdr);
        nlmsg_free(msg);
-       err = -EMSGSIZE;
- out:
-       /* Cleanup */
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
- out_rtnl:
-       rtnl_unlock();
-
-       return err;
+       return -ENOBUFS;
 }
 
 #define FILL_IN_MESH_PARAM_IF_SET(table, cfg, param, mask, attr_num, nla_fn) \
@@ -2875,10 +2602,9 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A
 
 static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info)
 {
-       int err;
        u32 mask;
-       struct cfg80211_registered_device *rdev;
-       struct net_device *dev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
        struct mesh_config cfg;
        struct nlattr *tb[NL80211_MESHCONF_ATTR_MAX + 1];
        struct nlattr *parent_attr;
@@ -2890,16 +2616,8 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info)
                        parent_attr, nl80211_meshconf_params_policy))
                return -EINVAL;
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto out_rtnl;
-
-       if (!rdev->ops->set_mesh_params) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
+       if (!rdev->ops->set_mesh_params)
+               return -EOPNOTSUPP;
 
        /* This makes sure that there aren't more than 32 mesh config
         * parameters (otherwise our bitfield scheme would not work.) */
@@ -2945,16 +2663,7 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info)
                        nla_get_u8);
 
        /* Apply changes */
-       err = rdev->ops->set_mesh_params(&rdev->wiphy, dev, &cfg, mask);
-
- out:
-       /* cleanup */
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
- out_rtnl:
-       rtnl_unlock();
-
-       return err;
+       return rdev->ops->set_mesh_params(&rdev->wiphy, dev, &cfg, mask);
 }
 
 #undef FILL_IN_MESH_PARAM_IF_SET
@@ -3137,8 +2846,8 @@ static int validate_scan_freqs(struct nlattr *freqs)
 
 static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
-       struct net_device *dev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
        struct cfg80211_scan_request *request;
        struct cfg80211_ssid *ssid;
        struct ieee80211_channel *channel;
@@ -3151,36 +2860,19 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
        if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
                return -EINVAL;
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto out_rtnl;
-
        wiphy = &rdev->wiphy;
 
-       if (!rdev->ops->scan) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       if (!netif_running(dev)) {
-               err = -ENETDOWN;
-               goto out;
-       }
+       if (!rdev->ops->scan)
+               return -EOPNOTSUPP;
 
-       if (rdev->scan_req) {
-               err = -EBUSY;
-               goto out;
-       }
+       if (rdev->scan_req)
+               return -EBUSY;
 
        if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
                n_channels = validate_scan_freqs(
                                info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]);
-               if (!n_channels) {
-                       err = -EINVAL;
-                       goto out;
-               }
+               if (!n_channels)
+                       return -EINVAL;
        } else {
                n_channels = 0;
 
@@ -3193,29 +2885,23 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
                nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp)
                        n_ssids++;
 
-       if (n_ssids > wiphy->max_scan_ssids) {
-               err = -EINVAL;
-               goto out;
-       }
+       if (n_ssids > wiphy->max_scan_ssids)
+               return -EINVAL;
 
        if (info->attrs[NL80211_ATTR_IE])
                ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
        else
                ie_len = 0;
 
-       if (ie_len > wiphy->max_scan_ie_len) {
-               err = -EINVAL;
-               goto out;
-       }
+       if (ie_len > wiphy->max_scan_ie_len)
+               return -EINVAL;
 
        request = kzalloc(sizeof(*request)
                        + sizeof(*ssid) * n_ssids
                        + sizeof(channel) * n_channels
                        + ie_len, GFP_KERNEL);
-       if (!request) {
-               err = -ENOMEM;
-               goto out;
-       }
+       if (!request)
+               return -ENOMEM;
 
        if (n_ssids)
                request->ssids = (void *)&request->channels[n_channels];
@@ -3303,18 +2989,11 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
        if (!err) {
                nl80211_send_scan_start(rdev, dev);
                dev_hold(dev);
-       }
-
+       } else {
  out_free:
-       if (err) {
                rdev->scan_req = NULL;
                kfree(request);
        }
- out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
- out_rtnl:
-       rtnl_unlock();
 
        return err;
 }
@@ -3411,25 +3090,12 @@ static int nl80211_dump_scan(struct sk_buff *skb,
        struct net_device *dev;
        struct cfg80211_internal_bss *scan;
        struct wireless_dev *wdev;
-       int ifidx = cb->args[0];
        int start = cb->args[1], idx = 0;
        int err;
 
-       if (!ifidx)
-               ifidx = nl80211_get_ifidx(cb);
-       if (ifidx < 0)
-               return ifidx;
-       cb->args[0] = ifidx;
-
-       dev = dev_get_by_index(sock_net(skb->sk), ifidx);
-       if (!dev)
-               return -ENODEV;
-
-       rdev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx);
-       if (IS_ERR(rdev)) {
-               err = PTR_ERR(rdev);
-               goto out_put_netdev;
-       }
+       err = nl80211_prepare_netdev_dump(skb, cb, &rdev, &dev);
+       if (err)
+               return err;
 
        wdev = dev->ieee80211_ptr;
 
@@ -3445,21 +3111,17 @@ static int nl80211_dump_scan(struct sk_buff *skb,
                                cb->nlh->nlmsg_seq, NLM_F_MULTI,
                                rdev, wdev, scan) < 0) {
                        idx--;
-                       goto out;
+                       break;
                }
        }
 
- out:
        spin_unlock_bh(&rdev->bss_lock);
        wdev_unlock(wdev);
 
        cb->args[1] = idx;
-       err = skb->len;
-       cfg80211_unlock_rdev(rdev);
- out_put_netdev:
-       dev_put(dev);
+       nl80211_finish_netdev_dump(rdev);
 
-       return err;
+       return skb->len;
 }
 
 static int nl80211_send_survey(struct sk_buff *msg, u32 pid, u32 seq,
@@ -3489,6 +3151,8 @@ static int nl80211_send_survey(struct sk_buff *msg, u32 pid, u32 seq,
        if (survey->filled & SURVEY_INFO_NOISE_DBM)
                NLA_PUT_U8(msg, NL80211_SURVEY_INFO_NOISE,
                            survey->noise);
+       if (survey->filled & SURVEY_INFO_IN_USE)
+               NLA_PUT_FLAG(msg, NL80211_SURVEY_INFO_IN_USE);
 
        nla_nest_end(msg, infoattr);
 
@@ -3505,29 +3169,12 @@ static int nl80211_dump_survey(struct sk_buff *skb,
        struct survey_info survey;
        struct cfg80211_registered_device *dev;
        struct net_device *netdev;
-       int ifidx = cb->args[0];
        int survey_idx = cb->args[1];
        int res;
 
-       if (!ifidx)
-               ifidx = nl80211_get_ifidx(cb);
-       if (ifidx < 0)
-               return ifidx;
-       cb->args[0] = ifidx;
-
-       rtnl_lock();
-
-       netdev = __dev_get_by_index(sock_net(skb->sk), ifidx);
-       if (!netdev) {
-               res = -ENODEV;
-               goto out_rtnl;
-       }
-
-       dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx);
-       if (IS_ERR(dev)) {
-               res = PTR_ERR(dev);
-               goto out_rtnl;
-       }
+       res = nl80211_prepare_netdev_dump(skb, cb, &dev, &netdev);
+       if (res)
+               return res;
 
        if (!dev->ops->dump_survey) {
                res = -EOPNOTSUPP;
@@ -3555,10 +3202,7 @@ static int nl80211_dump_survey(struct sk_buff *skb,
        cb->args[1] = survey_idx;
        res = skb->len;
  out_err:
-       cfg80211_unlock_rdev(dev);
- out_rtnl:
-       rtnl_unlock();
-
+       nl80211_finish_netdev_dump(dev);
        return res;
 }
 
@@ -3591,8 +3235,8 @@ static bool nl80211_valid_cipher_suite(u32 cipher)
 
 static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
-       struct net_device *dev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
        struct ieee80211_channel *chan;
        const u8 *bssid, *ssid, *ie = NULL;
        int err, ssid_len, ie_len = 0;
@@ -3620,6 +3264,8 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
                return err;
 
        if (key.idx >= 0) {
+               if (key.type != -1 && key.type != NL80211_KEYTYPE_GROUP)
+                       return -EINVAL;
                if (!key.p.key || !key.p.key_len)
                        return -EINVAL;
                if ((key.p.cipher != WLAN_CIPHER_SUITE_WEP40 ||
@@ -3634,12 +3280,6 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
                key.p.key = NULL;
        }
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto unlock_rtnl;
-
        if (key.idx >= 0) {
                int i;
                bool ok = false;
@@ -3649,35 +3289,22 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
                                break;
                        }
                }
-               if (!ok) {
-                       err = -EINVAL;
-                       goto out;
-               }
+               if (!ok)
+                       return -EINVAL;
        }
 
-       if (!rdev->ops->auth) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
+       if (!rdev->ops->auth)
+               return -EOPNOTSUPP;
 
        if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
-           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       if (!netif_running(dev)) {
-               err = -ENETDOWN;
-               goto out;
-       }
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
+               return -EOPNOTSUPP;
 
        bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
        chan = ieee80211_get_channel(&rdev->wiphy,
                nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
-       if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) {
-               err = -EINVAL;
-               goto out;
-       }
+       if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED))
+               return -EINVAL;
 
        ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
        ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
@@ -3688,24 +3315,15 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
        }
 
        auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]);
-       if (!nl80211_valid_auth_type(auth_type)) {
-               err = -EINVAL;
-               goto out;
-       }
+       if (!nl80211_valid_auth_type(auth_type))
+               return -EINVAL;
 
        local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
 
-       err = cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
-                                ssid, ssid_len, ie, ie_len,
-                                key.p.key, key.p.key_len, key.idx,
-                                local_state_change);
-
-out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
-unlock_rtnl:
-       rtnl_unlock();
-       return err;
+       return cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
+                                 ssid, ssid_len, ie, ie_len,
+                                 key.p.key, key.p.key_len, key.idx,
+                                 local_state_change);
 }
 
 static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
@@ -3789,8 +3407,8 @@ static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
 
 static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
-       struct net_device *dev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
        struct cfg80211_crypto_settings crypto;
        struct ieee80211_channel *chan;
        const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL;
@@ -3805,36 +3423,19 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
            !info->attrs[NL80211_ATTR_WIPHY_FREQ])
                return -EINVAL;
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto unlock_rtnl;
-
-       if (!rdev->ops->assoc) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
+       if (!rdev->ops->assoc)
+               return -EOPNOTSUPP;
 
        if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
-           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       if (!netif_running(dev)) {
-               err = -ENETDOWN;
-               goto out;
-       }
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
+               return -EOPNOTSUPP;
 
        bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
 
        chan = ieee80211_get_channel(&rdev->wiphy,
                nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
-       if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) {
-               err = -EINVAL;
-               goto out;
-       }
+       if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED))
+               return -EINVAL;
 
        ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
        ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
@@ -3849,10 +3450,8 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
                        nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]);
                if (mfp == NL80211_MFP_REQUIRED)
                        use_mfp = true;
-               else if (mfp != NL80211_MFP_NO) {
-                       err = -EINVAL;
-                       goto out;
-               }
+               else if (mfp != NL80211_MFP_NO)
+                       return -EINVAL;
        }
 
        if (info->attrs[NL80211_ATTR_PREV_BSSID])
@@ -3864,20 +3463,15 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
                                          ssid, ssid_len, ie, ie_len, use_mfp,
                                          &crypto);
 
-out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
-unlock_rtnl:
-       rtnl_unlock();
        return err;
 }
 
 static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
-       struct net_device *dev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
        const u8 *ie = NULL, *bssid;
-       int err, ie_len = 0;
+       int ie_len = 0;
        u16 reason_code;
        bool local_state_change;
 
@@ -3890,35 +3484,19 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info)
        if (!info->attrs[NL80211_ATTR_REASON_CODE])
                return -EINVAL;
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto unlock_rtnl;
-
-       if (!rdev->ops->deauth) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
+       if (!rdev->ops->deauth)
+               return -EOPNOTSUPP;
 
        if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
-           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       if (!netif_running(dev)) {
-               err = -ENETDOWN;
-               goto out;
-       }
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
+               return -EOPNOTSUPP;
 
        bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
 
        reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
        if (reason_code == 0) {
                /* Reason Code 0 is reserved */
-               err = -EINVAL;
-               goto out;
+               return -EINVAL;
        }
 
        if (info->attrs[NL80211_ATTR_IE]) {
@@ -3928,23 +3506,16 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info)
 
        local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
 
-       err = cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason_code,
-                                  local_state_change);
-
-out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
-unlock_rtnl:
-       rtnl_unlock();
-       return err;
+       return cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason_code,
+                                   local_state_change);
 }
 
 static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
-       struct net_device *dev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
        const u8 *ie = NULL, *bssid;
-       int err, ie_len = 0;
+       int ie_len = 0;
        u16 reason_code;
        bool local_state_change;
 
@@ -3957,35 +3528,19 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
        if (!info->attrs[NL80211_ATTR_REASON_CODE])
                return -EINVAL;
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto unlock_rtnl;
-
-       if (!rdev->ops->disassoc) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
+       if (!rdev->ops->disassoc)
+               return -EOPNOTSUPP;
 
        if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
-           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       if (!netif_running(dev)) {
-               err = -ENETDOWN;
-               goto out;
-       }
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
+               return -EOPNOTSUPP;
 
        bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
 
        reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
        if (reason_code == 0) {
                /* Reason Code 0 is reserved */
-               err = -EINVAL;
-               goto out;
+               return -EINVAL;
        }
 
        if (info->attrs[NL80211_ATTR_IE]) {
@@ -3995,21 +3550,14 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
 
        local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
 
-       err = cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason_code,
-                                    local_state_change);
-
-out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
-unlock_rtnl:
-       rtnl_unlock();
-       return err;
+       return cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason_code,
+                                     local_state_change);
 }
 
 static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
-       struct net_device *dev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
        struct cfg80211_ibss_params ibss;
        struct wiphy *wiphy;
        struct cfg80211_cached_keys *connkeys = NULL;
@@ -4034,26 +3582,11 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
                        return -EINVAL;
        }
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto unlock_rtnl;
-
-       if (!rdev->ops->join_ibss) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
+       if (!rdev->ops->join_ibss)
+               return -EOPNOTSUPP;
 
-       if (!netif_running(dev)) {
-               err = -ENETDOWN;
-               goto out;
-       }
+       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC)
+               return -EOPNOTSUPP;
 
        wiphy = &rdev->wiphy;
 
@@ -4071,24 +3604,12 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
                nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
        if (!ibss.channel ||
            ibss.channel->flags & IEEE80211_CHAN_NO_IBSS ||
-           ibss.channel->flags & IEEE80211_CHAN_DISABLED) {
-               err = -EINVAL;
-               goto out;
-       }
+           ibss.channel->flags & IEEE80211_CHAN_DISABLED)
+               return -EINVAL;
 
        ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED];
        ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
 
-       if (ibss.privacy && info->attrs[NL80211_ATTR_KEYS]) {
-               connkeys = nl80211_parse_connkeys(rdev,
-                                       info->attrs[NL80211_ATTR_KEYS]);
-               if (IS_ERR(connkeys)) {
-                       err = PTR_ERR(connkeys);
-                       connkeys = NULL;
-                       goto out;
-               }
-       }
-
        if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) {
                u8 *rates =
                        nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
@@ -4098,10 +3619,8 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
                        wiphy->bands[ibss.channel->band];
                int i, j;
 
-               if (n_rates == 0) {
-                       err = -EINVAL;
-                       goto out;
-               }
+               if (n_rates == 0)
+                       return -EINVAL;
 
                for (i = 0; i < n_rates; i++) {
                        int rate = (rates[i] & 0x7f) * 5;
@@ -4114,60 +3633,36 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
                                        break;
                                }
                        }
-                       if (!found) {
-                               err = -EINVAL;
-                               goto out;
-                       }
+                       if (!found)
+                               return -EINVAL;
                }
        }
 
-       err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys);
+       if (ibss.privacy && info->attrs[NL80211_ATTR_KEYS]) {
+               connkeys = nl80211_parse_connkeys(rdev,
+                                       info->attrs[NL80211_ATTR_KEYS]);
+               if (IS_ERR(connkeys))
+                       return PTR_ERR(connkeys);
+       }
 
-out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
-unlock_rtnl:
+       err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys);
        if (err)
                kfree(connkeys);
-       rtnl_unlock();
        return err;
 }
 
 static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
-       struct net_device *dev;
-       int err;
-
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto unlock_rtnl;
-
-       if (!rdev->ops->leave_ibss) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
 
-       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       if (!netif_running(dev)) {
-               err = -ENETDOWN;
-               goto out;
-       }
+       if (!rdev->ops->leave_ibss)
+               return -EOPNOTSUPP;
 
-       err = cfg80211_leave_ibss(rdev, dev, false);
+       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC)
+               return -EOPNOTSUPP;
 
-out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
-unlock_rtnl:
-       rtnl_unlock();
-       return err;
+       return cfg80211_leave_ibss(rdev, dev, false);
 }
 
 #ifdef CONFIG_NL80211_TESTMODE
@@ -4177,20 +3672,12 @@ static struct genl_multicast_group nl80211_testmode_mcgrp = {
 
 static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
        int err;
 
        if (!info->attrs[NL80211_ATTR_TESTDATA])
                return -EINVAL;
 
-       rtnl_lock();
-
-       rdev = cfg80211_get_dev_from_info(info);
-       if (IS_ERR(rdev)) {
-               err = PTR_ERR(rdev);
-               goto unlock_rtnl;
-       }
-
        err = -EOPNOTSUPP;
        if (rdev->ops->testmode_cmd) {
                rdev->testmode_info = info;
@@ -4200,10 +3687,6 @@ static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info)
                rdev->testmode_info = NULL;
        }
 
-       cfg80211_unlock_rdev(rdev);
-
- unlock_rtnl:
-       rtnl_unlock();
        return err;
 }
 
@@ -4294,8 +3777,8 @@ EXPORT_SYMBOL(cfg80211_testmode_event);
 
 static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
-       struct net_device *dev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
        struct cfg80211_connect_params connect;
        struct wiphy *wiphy;
        struct cfg80211_cached_keys *connkeys = NULL;
@@ -4324,22 +3807,10 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
                                      NL80211_MAX_NR_CIPHER_SUITES);
        if (err)
                return err;
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto unlock_rtnl;
 
        if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
-           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       if (!netif_running(dev)) {
-               err = -ENETDOWN;
-               goto out;
-       }
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
+               return -EOPNOTSUPP;
 
        wiphy = &rdev->wiphy;
 
@@ -4358,39 +3829,27 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
                        ieee80211_get_channel(wiphy,
                            nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
                if (!connect.channel ||
-                   connect.channel->flags & IEEE80211_CHAN_DISABLED) {
-                       err = -EINVAL;
-                       goto out;
-               }
+                   connect.channel->flags & IEEE80211_CHAN_DISABLED)
+                       return -EINVAL;
        }
 
        if (connect.privacy && info->attrs[NL80211_ATTR_KEYS]) {
                connkeys = nl80211_parse_connkeys(rdev,
                                        info->attrs[NL80211_ATTR_KEYS]);
-               if (IS_ERR(connkeys)) {
-                       err = PTR_ERR(connkeys);
-                       connkeys = NULL;
-                       goto out;
-               }
+               if (IS_ERR(connkeys))
+                       return PTR_ERR(connkeys);
        }
 
        err = cfg80211_connect(rdev, dev, &connect, connkeys);
-
-out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
-unlock_rtnl:
        if (err)
                kfree(connkeys);
-       rtnl_unlock();
        return err;
 }
 
 static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
-       struct net_device *dev;
-       int err;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
        u16 reason;
 
        if (!info->attrs[NL80211_ATTR_REASON_CODE])
@@ -4401,36 +3860,16 @@ static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info)
        if (reason == 0)
                return -EINVAL;
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto unlock_rtnl;
-
        if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
-           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       if (!netif_running(dev)) {
-               err = -ENETDOWN;
-               goto out;
-       }
-
-       err = cfg80211_disconnect(rdev, dev, reason, true);
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
+               return -EOPNOTSUPP;
 
-out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
-unlock_rtnl:
-       rtnl_unlock();
-       return err;
+       return cfg80211_disconnect(rdev, dev, reason, true);
 }
 
 static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
        struct net *net;
        int err;
        u32 pid;
@@ -4440,43 +3879,26 @@ static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info)
 
        pid = nla_get_u32(info->attrs[NL80211_ATTR_PID]);
 
-       rtnl_lock();
-
-       rdev = cfg80211_get_dev_from_info(info);
-       if (IS_ERR(rdev)) {
-               err = PTR_ERR(rdev);
-               goto out_rtnl;
-       }
-
        net = get_net_ns_by_pid(pid);
-       if (IS_ERR(net)) {
-               err = PTR_ERR(net);
-               goto out;
-       }
+       if (IS_ERR(net))
+               return PTR_ERR(net);
 
        err = 0;
 
        /* check if anything to do */
-       if (net_eq(wiphy_net(&rdev->wiphy), net))
-               goto out_put_net;
+       if (!net_eq(wiphy_net(&rdev->wiphy), net))
+               err = cfg80211_switch_netns(rdev, net);
 
-       err = cfg80211_switch_netns(rdev, net);
- out_put_net:
        put_net(net);
- out:
-       cfg80211_unlock_rdev(rdev);
- out_rtnl:
-       rtnl_unlock();
        return err;
 }
 
 static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
        int (*rdev_ops)(struct wiphy *wiphy, struct net_device *dev,
                        struct cfg80211_pmksa *pmksa) = NULL;
-       int err;
-       struct net_device *dev;
+       struct net_device *dev = info->user_ptr[1];
        struct cfg80211_pmksa pmksa;
 
        memset(&pmksa, 0, sizeof(struct cfg80211_pmksa));
@@ -4487,20 +3909,12 @@ static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info)
        if (!info->attrs[NL80211_ATTR_PMKID])
                return -EINVAL;
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto out_rtnl;
-
        pmksa.pmkid = nla_data(info->attrs[NL80211_ATTR_PMKID]);
        pmksa.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
 
        if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
-           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
+               return -EOPNOTSUPP;
 
        switch (info->genlhdr->cmd) {
        case NL80211_CMD_SET_PMKSA:
@@ -4514,62 +3928,32 @@ static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info)
                break;
        }
 
-       if (!rdev_ops) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       err = rdev_ops(&rdev->wiphy, dev, &pmksa);
-
- out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
- out_rtnl:
-       rtnl_unlock();
-
-       return err;
+       if (!rdev_ops)
+               return -EOPNOTSUPP;
+
+       return rdev_ops(&rdev->wiphy, dev, &pmksa);
 }
 
 static int nl80211_flush_pmksa(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
-       int err;
-       struct net_device *dev;
-
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto out_rtnl;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
 
        if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
-           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       if (!rdev->ops->flush_pmksa) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       err = rdev->ops->flush_pmksa(&rdev->wiphy, dev);
-
- out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
- out_rtnl:
-       rtnl_unlock();
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
+               return -EOPNOTSUPP;
 
-       return err;
+       if (!rdev->ops->flush_pmksa)
+               return -EOPNOTSUPP;
 
+       return rdev->ops->flush_pmksa(&rdev->wiphy, dev);
 }
 
 static int nl80211_remain_on_channel(struct sk_buff *skb,
                                     struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
-       struct net_device *dev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
        struct ieee80211_channel *chan;
        struct sk_buff *msg;
        void *hdr;
@@ -4591,21 +3975,8 @@ static int nl80211_remain_on_channel(struct sk_buff *skb,
        if (!duration || !msecs_to_jiffies(duration) || duration > 5000)
                return -EINVAL;
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto unlock_rtnl;
-
-       if (!rdev->ops->remain_on_channel) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       if (!netif_running(dev)) {
-               err = -ENETDOWN;
-               goto out;
-       }
+       if (!rdev->ops->remain_on_channel)
+               return -EOPNOTSUPP;
 
        if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
                channel_type = nla_get_u32(
@@ -4613,24 +3984,18 @@ static int nl80211_remain_on_channel(struct sk_buff *skb,
                if (channel_type != NL80211_CHAN_NO_HT &&
                    channel_type != NL80211_CHAN_HT20 &&
                    channel_type != NL80211_CHAN_HT40PLUS &&
-                   channel_type != NL80211_CHAN_HT40MINUS) {
-                       err = -EINVAL;
-                       goto out;
-               }
+                   channel_type != NL80211_CHAN_HT40MINUS)
+                       return -EINVAL;
        }
 
        freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
        chan = rdev_freq_to_chan(rdev, freq, channel_type);
-       if (chan == NULL) {
-               err = -EINVAL;
-               goto out;
-       }
+       if (chan == NULL)
+               return -EINVAL;
 
        msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
-       if (!msg) {
-               err = -ENOMEM;
-               goto out;
-       }
+       if (!msg)
+               return -ENOMEM;
 
        hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
                             NL80211_CMD_REMAIN_ON_CHANNEL);
@@ -4649,58 +4014,32 @@ static int nl80211_remain_on_channel(struct sk_buff *skb,
        NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie);
 
        genlmsg_end(msg, hdr);
-       err = genlmsg_reply(msg, info);
-       goto out;
+
+       return genlmsg_reply(msg, info);
 
  nla_put_failure:
        err = -ENOBUFS;
  free_msg:
        nlmsg_free(msg);
- out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
- unlock_rtnl:
-       rtnl_unlock();
        return err;
 }
 
 static int nl80211_cancel_remain_on_channel(struct sk_buff *skb,
                                            struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
-       struct net_device *dev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
        u64 cookie;
-       int err;
 
        if (!info->attrs[NL80211_ATTR_COOKIE])
                return -EINVAL;
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto unlock_rtnl;
-
-       if (!rdev->ops->cancel_remain_on_channel) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       if (!netif_running(dev)) {
-               err = -ENETDOWN;
-               goto out;
-       }
+       if (!rdev->ops->cancel_remain_on_channel)
+               return -EOPNOTSUPP;
 
        cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);
 
-       err = rdev->ops->cancel_remain_on_channel(&rdev->wiphy, dev, cookie);
-
- out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
- unlock_rtnl:
-       rtnl_unlock();
-       return err;
+       return rdev->ops->cancel_remain_on_channel(&rdev->wiphy, dev, cookie);
 }
 
 static u32 rateset_to_mask(struct ieee80211_supported_band *sband,
@@ -4736,26 +4075,18 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
                                       struct genl_info *info)
 {
        struct nlattr *tb[NL80211_TXRATE_MAX + 1];
-       struct cfg80211_registered_device *rdev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
        struct cfg80211_bitrate_mask mask;
-       int err, rem, i;
-       struct net_device *dev;
+       int rem, i;
+       struct net_device *dev = info->user_ptr[1];
        struct nlattr *tx_rates;
        struct ieee80211_supported_band *sband;
 
        if (info->attrs[NL80211_ATTR_TX_RATES] == NULL)
                return -EINVAL;
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto unlock_rtnl;
-
-       if (!rdev->ops->set_bitrate_mask) {
-               err = -EOPNOTSUPP;
-               goto unlock;
-       }
+       if (!rdev->ops->set_bitrate_mask)
+               return -EOPNOTSUPP;
 
        memset(&mask, 0, sizeof(mask));
        /* Default to all rates enabled */
@@ -4772,15 +4103,11 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
        nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem)
        {
                enum ieee80211_band band = nla_type(tx_rates);
-               if (band < 0 || band >= IEEE80211_NUM_BANDS) {
-                       err = -EINVAL;
-                       goto unlock;
-               }
+               if (band < 0 || band >= IEEE80211_NUM_BANDS)
+                       return -EINVAL;
                sband = rdev->wiphy.bands[band];
-               if (sband == NULL) {
-                       err = -EINVAL;
-                       goto unlock;
-               }
+               if (sband == NULL)
+                       return -EINVAL;
                nla_parse(tb, NL80211_TXRATE_MAX, nla_data(tx_rates),
                          nla_len(tx_rates), nl80211_txattr_policy);
                if (tb[NL80211_TXRATE_LEGACY]) {
@@ -4788,29 +4115,19 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
                                sband,
                                nla_data(tb[NL80211_TXRATE_LEGACY]),
                                nla_len(tb[NL80211_TXRATE_LEGACY]));
-                       if (mask.control[band].legacy == 0) {
-                               err = -EINVAL;
-                               goto unlock;
-                       }
+                       if (mask.control[band].legacy == 0)
+                               return -EINVAL;
                }
        }
 
-       err = rdev->ops->set_bitrate_mask(&rdev->wiphy, dev, NULL, &mask);
-
- unlock:
-       dev_put(dev);
-       cfg80211_unlock_rdev(rdev);
- unlock_rtnl:
-       rtnl_unlock();
-       return err;
+       return rdev->ops->set_bitrate_mask(&rdev->wiphy, dev, NULL, &mask);
 }
 
 static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
-       struct net_device *dev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
        u16 frame_type = IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION;
-       int err;
 
        if (!info->attrs[NL80211_ATTR_FRAME_MATCH])
                return -EINVAL;
@@ -4818,41 +4135,28 @@ static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info)
        if (info->attrs[NL80211_ATTR_FRAME_TYPE])
                frame_type = nla_get_u16(info->attrs[NL80211_ATTR_FRAME_TYPE]);
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto unlock_rtnl;
-
        if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
            dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC &&
-           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT &&
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
+               return -EOPNOTSUPP;
 
        /* not much point in registering if we can't reply */
-       if (!rdev->ops->mgmt_tx) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
+       if (!rdev->ops->mgmt_tx)
+               return -EOPNOTSUPP;
 
-       err = cfg80211_mlme_register_mgmt(dev->ieee80211_ptr, info->snd_pid,
+       return cfg80211_mlme_register_mgmt(dev->ieee80211_ptr, info->snd_pid,
                        frame_type,
                        nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]),
                        nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH]));
- out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
- unlock_rtnl:
-       rtnl_unlock();
-       return err;
 }
 
 static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
-       struct net_device *dev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
        struct ieee80211_channel *chan;
        enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
        bool channel_type_valid = false;
@@ -4866,28 +4170,16 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
            !info->attrs[NL80211_ATTR_WIPHY_FREQ])
                return -EINVAL;
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto unlock_rtnl;
-
-       if (!rdev->ops->mgmt_tx) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
+       if (!rdev->ops->mgmt_tx)
+               return -EOPNOTSUPP;
 
        if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
            dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC &&
-           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       if (!netif_running(dev)) {
-               err = -ENETDOWN;
-               goto out;
-       }
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT &&
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
+               return -EOPNOTSUPP;
 
        if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
                channel_type = nla_get_u32(
@@ -4895,25 +4187,19 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
                if (channel_type != NL80211_CHAN_NO_HT &&
                    channel_type != NL80211_CHAN_HT20 &&
                    channel_type != NL80211_CHAN_HT40PLUS &&
-                   channel_type != NL80211_CHAN_HT40MINUS) {
-                       err = -EINVAL;
-                       goto out;
-               }
+                   channel_type != NL80211_CHAN_HT40MINUS)
+                       return -EINVAL;
                channel_type_valid = true;
        }
 
        freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
        chan = rdev_freq_to_chan(rdev, freq, channel_type);
-       if (chan == NULL) {
-               err = -EINVAL;
-               goto out;
-       }
+       if (chan == NULL)
+               return -EINVAL;
 
        msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
-       if (!msg) {
-               err = -ENOMEM;
-               goto out;
-       }
+       if (!msg)
+               return -ENOMEM;
 
        hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
                             NL80211_CMD_FRAME);
@@ -4933,110 +4219,72 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
        NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie);
 
        genlmsg_end(msg, hdr);
-       err = genlmsg_reply(msg, info);
-       goto out;
+       return genlmsg_reply(msg, info);
 
  nla_put_failure:
        err = -ENOBUFS;
  free_msg:
        nlmsg_free(msg);
- out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
-unlock_rtnl:
-       rtnl_unlock();
        return err;
 }
 
 static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
        struct wireless_dev *wdev;
-       struct net_device *dev;
+       struct net_device *dev = info->user_ptr[1];
        u8 ps_state;
        bool state;
        int err;
 
-       if (!info->attrs[NL80211_ATTR_PS_STATE]) {
-               err = -EINVAL;
-               goto out;
-       }
+       if (!info->attrs[NL80211_ATTR_PS_STATE])
+               return -EINVAL;
 
        ps_state = nla_get_u32(info->attrs[NL80211_ATTR_PS_STATE]);
 
-       if (ps_state != NL80211_PS_DISABLED && ps_state != NL80211_PS_ENABLED) {
-               err = -EINVAL;
-               goto out;
-       }
-
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto unlock_rtnl;
+       if (ps_state != NL80211_PS_DISABLED && ps_state != NL80211_PS_ENABLED)
+               return -EINVAL;
 
        wdev = dev->ieee80211_ptr;
 
-       if (!rdev->ops->set_power_mgmt) {
-               err = -EOPNOTSUPP;
-               goto unlock_rdev;
-       }
+       if (!rdev->ops->set_power_mgmt)
+               return -EOPNOTSUPP;
 
        state = (ps_state == NL80211_PS_ENABLED) ? true : false;
 
        if (state == wdev->ps)
-               goto unlock_rdev;
-
-       wdev->ps = state;
-
-       if (rdev->ops->set_power_mgmt(wdev->wiphy, dev, wdev->ps,
-                                     wdev->ps_timeout))
-               /* assume this means it's off */
-               wdev->ps = false;
-
-unlock_rdev:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
-unlock_rtnl:
-       rtnl_unlock();
+               return 0;
 
-out:
+       err = rdev->ops->set_power_mgmt(wdev->wiphy, dev, state,
+                                       wdev->ps_timeout);
+       if (!err)
+               wdev->ps = state;
        return err;
 }
 
 static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
        enum nl80211_ps_state ps_state;
        struct wireless_dev *wdev;
-       struct net_device *dev;
+       struct net_device *dev = info->user_ptr[1];
        struct sk_buff *msg;
        void *hdr;
        int err;
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto unlock_rtnl;
-
        wdev = dev->ieee80211_ptr;
 
-       if (!rdev->ops->set_power_mgmt) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
+       if (!rdev->ops->set_power_mgmt)
+               return -EOPNOTSUPP;
 
        msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
-       if (!msg) {
-               err = -ENOMEM;
-               goto out;
-       }
+       if (!msg)
+               return -ENOMEM;
 
        hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
                             NL80211_CMD_GET_POWER_SAVE);
        if (!hdr) {
-               err = -ENOMEM;
+               err = -ENOBUFS;
                goto free_msg;
        }
 
@@ -5048,22 +4296,12 @@ static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info)
        NLA_PUT_U32(msg, NL80211_ATTR_PS_STATE, ps_state);
 
        genlmsg_end(msg, hdr);
-       err = genlmsg_reply(msg, info);
-       goto out;
+       return genlmsg_reply(msg, info);
 
-nla_put_failure:
+ nla_put_failure:
        err = -ENOBUFS;
-
-free_msg:
+ free_msg:
        nlmsg_free(msg);
-
-out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
-
-unlock_rtnl:
-       rtnl_unlock();
-
        return err;
 }
 
@@ -5077,42 +4315,24 @@ nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] __read_mostly = {
 static int nl80211_set_cqm_rssi(struct genl_info *info,
                                s32 threshold, u32 hysteresis)
 {
-       struct cfg80211_registered_device *rdev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
        struct wireless_dev *wdev;
-       struct net_device *dev;
-       int err;
+       struct net_device *dev = info->user_ptr[1];
 
        if (threshold > 0)
                return -EINVAL;
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto unlock_rdev;
-
        wdev = dev->ieee80211_ptr;
 
-       if (!rdev->ops->set_cqm_rssi_config) {
-               err = -EOPNOTSUPP;
-               goto unlock_rdev;
-       }
+       if (!rdev->ops->set_cqm_rssi_config)
+               return -EOPNOTSUPP;
 
        if (wdev->iftype != NL80211_IFTYPE_STATION &&
-           wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) {
-               err = -EOPNOTSUPP;
-               goto unlock_rdev;
-       }
-
-       err = rdev->ops->set_cqm_rssi_config(wdev->wiphy, dev,
-                                            threshold, hysteresis);
-
-unlock_rdev:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
-       rtnl_unlock();
+           wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
+               return -EOPNOTSUPP;
 
-       return err;
+       return rdev->ops->set_cqm_rssi_config(wdev->wiphy, dev,
+                                             threshold, hysteresis);
 }
 
 static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info)
@@ -5146,6 +4366,65 @@ out:
        return err;
 }
 
+#define NL80211_FLAG_NEED_WIPHY                0x01
+#define NL80211_FLAG_NEED_NETDEV       0x02
+#define NL80211_FLAG_NEED_RTNL         0x04
+#define NL80211_FLAG_CHECK_NETDEV_UP   0x08
+#define NL80211_FLAG_NEED_NETDEV_UP    (NL80211_FLAG_NEED_NETDEV |\
+                                        NL80211_FLAG_CHECK_NETDEV_UP)
+
+static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb,
+                           struct genl_info *info)
+{
+       struct cfg80211_registered_device *rdev;
+       struct net_device *dev;
+       int err;
+       bool rtnl = ops->internal_flags & NL80211_FLAG_NEED_RTNL;
+
+       if (rtnl)
+               rtnl_lock();
+
+       if (ops->internal_flags & NL80211_FLAG_NEED_WIPHY) {
+               rdev = cfg80211_get_dev_from_info(info);
+               if (IS_ERR(rdev)) {
+                       if (rtnl)
+                               rtnl_unlock();
+                       return PTR_ERR(rdev);
+               }
+               info->user_ptr[0] = rdev;
+       } else if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV) {
+               err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
+               if (err) {
+                       if (rtnl)
+                               rtnl_unlock();
+                       return err;
+               }
+               if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP &&
+                   !netif_running(dev)) {
+                       cfg80211_unlock_rdev(rdev);
+                       dev_put(dev);
+                       if (rtnl)
+                               rtnl_unlock();
+                       return -ENETDOWN;
+               }
+               info->user_ptr[0] = rdev;
+               info->user_ptr[1] = dev;
+       }
+
+       return 0;
+}
+
+static void nl80211_post_doit(struct genl_ops *ops, struct sk_buff *skb,
+                             struct genl_info *info)
+{
+       if (info->user_ptr[0])
+               cfg80211_unlock_rdev(info->user_ptr[0]);
+       if (info->user_ptr[1])
+               dev_put(info->user_ptr[1]);
+       if (ops->internal_flags & NL80211_FLAG_NEED_RTNL)
+               rtnl_unlock();
+}
+
 static struct genl_ops nl80211_ops[] = {
        {
                .cmd = NL80211_CMD_GET_WIPHY,
@@ -5153,12 +4432,14 @@ static struct genl_ops nl80211_ops[] = {
                .dumpit = nl80211_dump_wiphy,
                .policy = nl80211_policy,
                /* can be retrieved by unprivileged users */
+               .internal_flags = NL80211_FLAG_NEED_WIPHY,
        },
        {
                .cmd = NL80211_CMD_SET_WIPHY,
                .doit = nl80211_set_wiphy,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_GET_INTERFACE,
@@ -5166,90 +4447,119 @@ static struct genl_ops nl80211_ops[] = {
                .dumpit = nl80211_dump_interface,
                .policy = nl80211_policy,
                /* can be retrieved by unprivileged users */
+               .internal_flags = NL80211_FLAG_NEED_NETDEV,
        },
        {
                .cmd = NL80211_CMD_SET_INTERFACE,
                .doit = nl80211_set_interface,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_NEW_INTERFACE,
                .doit = nl80211_new_interface,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_WIPHY |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_DEL_INTERFACE,
                .doit = nl80211_del_interface,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_GET_KEY,
                .doit = nl80211_get_key,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_SET_KEY,
                .doit = nl80211_set_key,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_NEW_KEY,
                .doit = nl80211_new_key,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_DEL_KEY,
                .doit = nl80211_del_key,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_SET_BEACON,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
                .doit = nl80211_addset_beacon,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_NEW_BEACON,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
                .doit = nl80211_addset_beacon,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_DEL_BEACON,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
                .doit = nl80211_del_beacon,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_GET_STATION,
                .doit = nl80211_get_station,
                .dumpit = nl80211_dump_station,
                .policy = nl80211_policy,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_SET_STATION,
                .doit = nl80211_set_station,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_NEW_STATION,
                .doit = nl80211_new_station,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_DEL_STATION,
                .doit = nl80211_del_station,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_GET_MPATH,
@@ -5257,30 +4567,40 @@ static struct genl_ops nl80211_ops[] = {
                .dumpit = nl80211_dump_mpath,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_SET_MPATH,
                .doit = nl80211_set_mpath,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_NEW_MPATH,
                .doit = nl80211_new_mpath,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_DEL_MPATH,
                .doit = nl80211_del_mpath,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_SET_BSS,
                .doit = nl80211_set_bss,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_GET_REG,
@@ -5305,18 +4625,24 @@ static struct genl_ops nl80211_ops[] = {
                .doit = nl80211_get_mesh_params,
                .policy = nl80211_policy,
                /* can be retrieved by unprivileged users */
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_SET_MESH_PARAMS,
                .doit = nl80211_set_mesh_params,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_TRIGGER_SCAN,
                .doit = nl80211_trigger_scan,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_GET_SCAN,
@@ -5328,36 +4654,48 @@ static struct genl_ops nl80211_ops[] = {
                .doit = nl80211_authenticate,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_ASSOCIATE,
                .doit = nl80211_associate,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_DEAUTHENTICATE,
                .doit = nl80211_deauthenticate,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_DISASSOCIATE,
                .doit = nl80211_disassociate,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_JOIN_IBSS,
                .doit = nl80211_join_ibss,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_LEAVE_IBSS,
                .doit = nl80211_leave_ibss,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
        },
 #ifdef CONFIG_NL80211_TESTMODE
        {
@@ -5365,6 +4703,8 @@ static struct genl_ops nl80211_ops[] = {
                .doit = nl80211_testmode_do,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_WIPHY |
+                                 NL80211_FLAG_NEED_RTNL,
        },
 #endif
        {
@@ -5372,18 +4712,24 @@ static struct genl_ops nl80211_ops[] = {
                .doit = nl80211_connect,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_DISCONNECT,
                .doit = nl80211_disconnect,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_SET_WIPHY_NETNS,
                .doit = nl80211_wiphy_netns,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_WIPHY |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_GET_SURVEY,
@@ -5395,72 +4741,104 @@ static struct genl_ops nl80211_ops[] = {
                .doit = nl80211_setdel_pmksa,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_DEL_PMKSA,
                .doit = nl80211_setdel_pmksa,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_FLUSH_PMKSA,
                .doit = nl80211_flush_pmksa,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_REMAIN_ON_CHANNEL,
                .doit = nl80211_remain_on_channel,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
                .doit = nl80211_cancel_remain_on_channel,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_SET_TX_BITRATE_MASK,
                .doit = nl80211_set_tx_bitrate_mask,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_REGISTER_FRAME,
                .doit = nl80211_register_mgmt,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_FRAME,
                .doit = nl80211_tx_mgmt,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_SET_POWER_SAVE,
                .doit = nl80211_set_power_save,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_GET_POWER_SAVE,
                .doit = nl80211_get_power_save,
                .policy = nl80211_policy,
                /* can be retrieved by unprivileged users */
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_SET_CQM,
                .doit = nl80211_set_cqm,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_SET_CHANNEL,
                .doit = nl80211_set_channel,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
+       },
+       {
+               .cmd = NL80211_CMD_SET_WDS_PEER,
+               .doit = nl80211_set_wds_peer,
+               .policy = nl80211_policy,
+               .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
        },
 };
 
index 5ca8c7180141d8dc9bc43d607eb26395cd0268bf..503ebb86ba1836f5d2c8709c75bae5eff83c5de6 100644 (file)
@@ -650,14 +650,14 @@ void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub)
        bss = container_of(pub, struct cfg80211_internal_bss, pub);
 
        spin_lock_bh(&dev->bss_lock);
+       if (!list_empty(&bss->list)) {
+               list_del_init(&bss->list);
+               dev->bss_generation++;
+               rb_erase(&bss->rbn, &dev->bss_tree);
 
-       list_del(&bss->list);
-       dev->bss_generation++;
-       rb_erase(&bss->rbn, &dev->bss_tree);
-
+               kref_put(&bss->ref, bss_release);
+       }
        spin_unlock_bh(&dev->bss_lock);
-
-       kref_put(&bss->ref, bss_release);
 }
 EXPORT_SYMBOL(cfg80211_unlink_bss);
 
index f161b9844542a2adcfa82dfc83fcd23068a4ee46..e17b0bee6bdc7b8e0b6d74a401ea9df3bdf7e977 100644 (file)
@@ -698,7 +698,7 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
         */
        if (rdev->ops->del_key)
                for (i = 0; i < 6; i++)
-                       rdev->ops->del_key(wdev->wiphy, dev, i, NULL);
+                       rdev->ops->del_key(wdev->wiphy, dev, i, false, NULL);
 
 #ifdef CONFIG_CFG80211_WEXT
        memset(&wrqu, 0, sizeof(wrqu));
index fb5448f7d55af55b8ee8220ef813880993d0b069..76120aeda57d3ed311c338cb7e54196000cc937d 100644 (file)
@@ -144,19 +144,25 @@ void ieee80211_set_bitrate_flags(struct wiphy *wiphy)
 
 int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
                                   struct key_params *params, int key_idx,
-                                  const u8 *mac_addr)
+                                  bool pairwise, const u8 *mac_addr)
 {
        int i;
 
        if (key_idx > 5)
                return -EINVAL;
 
+       if (!pairwise && mac_addr && !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
+               return -EINVAL;
+
+       if (pairwise && !mac_addr)
+               return -EINVAL;
+
        /*
         * Disallow pairwise keys with non-zero index unless it's WEP
         * (because current deployments use pairwise WEP keys with
         * non-zero indizes but 802.11i clearly specifies to use zero)
         */
-       if (mac_addr && key_idx &&
+       if (pairwise && key_idx &&
            params->cipher != WLAN_CIPHER_SUITE_WEP40 &&
            params->cipher != WLAN_CIPHER_SUITE_WEP104)
                return -EINVAL;
@@ -677,7 +683,7 @@ void cfg80211_upload_connect_keys(struct wireless_dev *wdev)
        for (i = 0; i < 6; i++) {
                if (!wdev->connect_keys->params[i].cipher)
                        continue;
-               if (rdev->ops->add_key(wdev->wiphy, dev, i, NULL,
+               if (rdev->ops->add_key(wdev->wiphy, dev, i, false, NULL,
                                        &wdev->connect_keys->params[i])) {
                        printk(KERN_ERR "%s: failed to set key %d\n",
                                dev->name, i);
index 7e5c3a45f811d1a951ebee2486cfd8ffa70e5482..6002265289c6267ce182531865c8e4f6db3d947e 100644 (file)
@@ -432,14 +432,17 @@ int cfg80211_wext_giwretry(struct net_device *dev,
 EXPORT_SYMBOL_GPL(cfg80211_wext_giwretry);
 
 static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
-                                    struct net_device *dev, const u8 *addr,
-                                    bool remove, bool tx_key, int idx,
-                                    struct key_params *params)
+                                    struct net_device *dev, bool pairwise,
+                                    const u8 *addr, bool remove, bool tx_key,
+                                    int idx, struct key_params *params)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        int err, i;
        bool rejoin = false;
 
+       if (pairwise && !addr)
+               return -EINVAL;
+
        if (!wdev->wext.keys) {
                wdev->wext.keys = kzalloc(sizeof(*wdev->wext.keys),
                                              GFP_KERNEL);
@@ -478,7 +481,13 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
                                __cfg80211_leave_ibss(rdev, wdev->netdev, true);
                                rejoin = true;
                        }
-                       err = rdev->ops->del_key(&rdev->wiphy, dev, idx, addr);
+
+                       if (!pairwise && addr &&
+                           !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
+                               err = -ENOENT;
+                       else
+                               err = rdev->ops->del_key(&rdev->wiphy, dev, idx,
+                                                        pairwise, addr);
                }
                wdev->wext.connect.privacy = false;
                /*
@@ -507,12 +516,13 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
        if (addr)
                tx_key = false;
 
-       if (cfg80211_validate_key_settings(rdev, params, idx, addr))
+       if (cfg80211_validate_key_settings(rdev, params, idx, pairwise, addr))
                return -EINVAL;
 
        err = 0;
        if (wdev->current_bss)
-               err = rdev->ops->add_key(&rdev->wiphy, dev, idx, addr, params);
+               err = rdev->ops->add_key(&rdev->wiphy, dev, idx,
+                                        pairwise, addr, params);
        if (err)
                return err;
 
@@ -563,17 +573,17 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
 }
 
 static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
-                                  struct net_device *dev, const u8 *addr,
-                                  bool remove, bool tx_key, int idx,
-                                  struct key_params *params)
+                                  struct net_device *dev, bool pairwise,
+                                  const u8 *addr, bool remove, bool tx_key,
+                                  int idx, struct key_params *params)
 {
        int err;
 
        /* devlist mutex needed for possible IBSS re-join */
        mutex_lock(&rdev->devlist_mtx);
        wdev_lock(dev->ieee80211_ptr);
-       err = __cfg80211_set_encryption(rdev, dev, addr, remove,
-                                       tx_key, idx, params);
+       err = __cfg80211_set_encryption(rdev, dev, pairwise, addr,
+                                       remove, tx_key, idx, params);
        wdev_unlock(dev->ieee80211_ptr);
        mutex_unlock(&rdev->devlist_mtx);
 
@@ -635,7 +645,7 @@ int cfg80211_wext_siwencode(struct net_device *dev,
        else if (!remove)
                return -EINVAL;
 
-       return cfg80211_set_encryption(rdev, dev, NULL, remove,
+       return cfg80211_set_encryption(rdev, dev, false, NULL, remove,
                                       wdev->wext.default_key == -1,
                                       idx, &params);
 }
@@ -725,7 +735,9 @@ int cfg80211_wext_siwencodeext(struct net_device *dev,
        }
 
        return cfg80211_set_encryption(
-                       rdev, dev, addr, remove,
+                       rdev, dev,
+                       !(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY),
+                       addr, remove,
                        ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY,
                        idx, &params);
 }